2 * CRTDLL multi-byte string functions
4 * Copyright 1999 Alexandre Julliard
5 * Copyright 2000 Jon Griffths
8 * See msdn.microsoft.com
9 * /library/devprods/vs6/visualc/vccore/_crt__ismbb_routines.htm
10 * For details and CP 932 information.
12 * This code assumes that MB_LEN_MAX is 2 and that [0,0] is an
13 * invalid MB char. If that changes, this will need to too.
15 * CRTDLL reports valid CP 932 multibyte chars when the current
16 * code page is not 932. MSVCRT fixes this bug - we implement
17 * MSVCRT's behaviour, since its correct. However, MSVCRT fails
18 * to set the code page correctly when the locale is changed, so
19 * it must be explicitly set to get matching results.
22 * Not currently binary compatable with win32. CRTDLL_mbctype must be
23 * populated correctly and the ismb* functions should reference it.
28 DEFAULT_DEBUG_CHANNEL(crtdll
);
30 UCHAR CRTDLL_mbctype
[257];
33 /*********************************************************************
36 * Compare two multibyte strings.
38 INT __cdecl
CRTDLL__mbscmp( LPCSTR str
, LPCSTR cmp
)
40 if (CRTDLL__mb_cur_max_dll
> 1)
48 strc
= CRTDLL__mbsnextc(str
);
49 cmpc
= CRTDLL__mbsnextc(cmp
);
51 return strc
< cmpc
? -1 : 1;
52 str
+= (strc
> 255) ? 2 : 1;
53 cmp
+= (strc
> 255) ? 2 : 1; /* equal, use same increment */
56 return strcmp(str
, cmp
); /* ASCII CP */
60 /*********************************************************************
61 * _mbsicmp (CRTDLL.??)
63 * Compare two multibyte strings case insensitively.
65 INT __cdecl
CRTDLL__mbsicmp( LPCSTR str
, LPCSTR cmp
)
67 /* FIXME: No tolower() for mb strings yet */
68 if (CRTDLL__mb_cur_max_dll
> 1)
69 return CRTDLL__mbscmp( str
, cmp
);
70 return strcasecmp( str
, cmp
); /* ASCII CP */
74 /*********************************************************************
75 * _mbsncmp (CRTDLL.??)
77 * Compare two multibyte strings to 'len' characters.
79 INT __cdecl
CRTDLL__mbsncmp( LPCSTR str
, LPCSTR cmp
, UINT len
)
84 if (CRTDLL__mb_cur_max_dll
> 1)
93 strc
= CRTDLL__mbsnextc(str
);
94 cmpc
= CRTDLL__mbsnextc(cmp
);
96 return strc
< cmpc
? -1 : 1;
97 str
+= (strc
> 255) ? 2 : 1;
98 cmp
+= (strc
> 255) ? 2 : 1; /* Equal, use same increment */
100 return 0; /* Matched len chars */
102 return strncmp(str
, cmp
, len
); /* ASCII CP */
106 /*********************************************************************
107 * _mbsnicmp (CRTDLL.??)
109 * Compare two multibyte strings case insensitively to 'len' characters.
111 INT __cdecl
CRTDLL__mbsnicmp( LPCSTR str
, LPCSTR cmp
, UINT len
)
113 /* FIXME: No tolower() for mb strings yet */
114 if (CRTDLL__mb_cur_max_dll
> 1)
115 return CRTDLL__mbsncmp( str
, cmp
, len
);
116 return strncasecmp( str
, cmp
, len
); /* ASCII CP */
120 /*********************************************************************
121 * _mbsinc (CRTDLL.205)
123 * Return the next character of a string.
125 LPSTR __cdecl
CRTDLL__mbsinc( LPCSTR str
)
127 if (CRTDLL__mb_cur_max_dll
> 1 &&
128 CRTDLL_isleadbyte(*str
))
129 return (LPSTR
)str
+ 2; /* MB char */
131 return (LPSTR
)str
+ 1; /* ASCII CP or SB char */
135 /*********************************************************************
136 * _mbsninc (CRTDLL.??)
138 * Return the 'num'th character of a string.
140 LPSTR
CRTDLL__mbsninc( LPCSTR str
, INT num
)
144 if (CRTDLL__mb_cur_max_dll
> 1)
147 str
= CRTDLL__mbsinc( str
);
150 return (LPSTR
)str
+ num
; /* ASCII CP */
154 /*********************************************************************
155 * _mbslen (CRTDLL.206)
157 * Get the length of a string.
159 INT __cdecl
CRTDLL__mbslen( LPCSTR str
)
161 if (CRTDLL__mb_cur_max_dll
> 1)
166 str
+= CRTDLL_isleadbyte( *str
) ? 2 : 1;
171 return strlen( str
); /* ASCII CP */
175 /*********************************************************************
176 * _mbsrchr (CRTDLL.223)
178 LPSTR __cdecl
CRTDLL__mbsrchr(LPCSTR s
,CHAR x
)
180 /* FIXME: handle multibyte strings */
185 /*********************************************************************
186 * mbtowc (CRTDLL.430)
188 INT __cdecl
CRTDLL_mbtowc( WCHAR
*dst
, LPCSTR str
, INT n
)
190 if (n
<= 0) return 0;
192 if (!MultiByteToWideChar( CP_ACP
, 0, str
, n
, dst
, 1 )) return 0;
193 /* return the number of bytes from src that have been used */
195 if (n
>= 2 && CRTDLL_isleadbyte(*str
) && str
[1]) return 2;
200 /*********************************************************************
201 * _mbccpy (CRTDLL.??)
203 * Copy one multibyte character to another
205 VOID __cdecl
CRTDLL__mbccpy(LPSTR dest
, LPSTR src
)
208 if (CRTDLL__mb_cur_max_dll
> 1 && CRTDLL_isleadbyte(*src
))
209 *dest
= *++src
; /* MB char */
213 /*********************************************************************
214 * _mbsdec (CRTDLL.??)
216 * Return the character before 'cur'.
218 LPSTR __cdecl
CRTDLL__mbsdec( LPCSTR start
, LPCSTR cur
)
220 if (CRTDLL__mb_cur_max_dll
> 1)
221 return (LPSTR
)(CRTDLL__ismbstrail(start
,cur
-1) ? cur
- 2 : cur
-1);
223 return (LPSTR
)cur
- 1; /* ASCII CP or SB char */
227 /*********************************************************************
228 * _mbbtombc (CRTDLL.??)
230 * Convert a single byte character to a multi byte character.
232 USHORT __cdecl
CRTDLL__mbbtombc( USHORT c
)
234 if (CRTDLL__mb_cur_max_dll
> 1 &&
235 ((c
>= 0x20 && c
<=0x7e) || (c
>= 0xa1 && c
<= 0xdf)))
237 /* FIXME: I can't get this function to return anything
238 * different to what I pass it...
241 return c
; /* ASCII CP or no MB char */
245 /*********************************************************************
246 * _mbclen (CRTDLL.??)
248 * Get the length of a multibyte character.
250 INT __cdecl
CRTDLL__mbclen( LPCSTR str
)
252 return CRTDLL_isleadbyte( *str
) ? 2 : 1;
256 /*********************************************************************
257 * _ismbbkana (CRTDLL.??)
259 * Is the given single byte character Katakana?
261 INT __cdecl
CRTDLL__ismbbkana( UINT c
)
263 /* FIXME: use lc_ctype when supported, not lc_all */
264 if (__CRTDLL_current_lc_all_cp
== 932)
266 /* Japanese/Katakana, CP 932 */
267 return (c
>= 0xa1 && c
<= 0xdf);
273 /*********************************************************************
274 * _ismbchira (CRTDLL.??)
276 * Is the given character Hiragana?
278 INT __cdecl
CRTDLL__ismbchira( UINT c
)
280 /* FIXME: use lc_ctype when supported, not lc_all */
281 if (__CRTDLL_current_lc_all_cp
== 932)
283 /* Japanese/Hiragana, CP 932 */
284 return (c
>= 0x829f && c
<= 0x82f1);
290 /*********************************************************************
291 * _ismbckata (CRTDLL.??)
293 * Is the given double byte character Katakana?
295 INT __cdecl
CRTDLL__ismbckata( UINT c
)
297 /* FIXME: use lc_ctype when supported, not lc_all */
298 if (__CRTDLL_current_lc_all_cp
== 932)
301 return CRTDLL__ismbbkana( c
);
302 /* Japanese/Katakana, CP 932 */
303 return (c
>= 0x8340 && c
<= 0x8396 && c
!= 0x837f);
309 /*********************************************************************
310 * _ismbblead (CRTDLL.??)
312 * Is the given single byte character a lead byte?
314 INT __cdecl
CRTDLL__ismbblead( UINT c
)
316 /* FIXME: should reference CRTDLL_mbctype */
317 return CRTDLL__mb_cur_max_dll
> 1 && CRTDLL_isleadbyte( c
);
321 /*********************************************************************
322 * _ismbbtrail (CRTDLL.??)
324 * Is the given single byte character a trail byte?
326 INT __cdecl
CRTDLL__ismbbtrail( UINT c
)
328 /* FIXME: should reference CRTDLL_mbctype */
329 return !CRTDLL__ismbblead( c
);
333 /*********************************************************************
334 * _ismbslead (CRTDLL.??)
336 * Is the character pointed to 'str' a lead byte?
338 INT __cdecl
CRTDLL__ismbslead( LPCSTR start
, LPCSTR str
)
340 /* Lead bytes can also be trail bytes if caller messed up
341 * iterating through the string...
343 if (CRTDLL__mb_cur_max_dll
> 1)
346 start
+= CRTDLL_isleadbyte ( *str
) ? 2 : 1;
349 return CRTDLL_isleadbyte( *str
);
351 return 0; /* Must have been a trail, we skipped it */
355 /*********************************************************************
356 * _ismbstrail (CRTDLL.??)
358 * Is the character pointed to 'str' a trail byte?
360 INT __cdecl
CRTDLL__ismbstrail( LPCSTR start
, LPCSTR str
)
362 /* Must not be a lead, and must be preceeded by one */
363 return !CRTDLL__ismbslead( start
, str
) && CRTDLL_isleadbyte(str
[-1]);
367 /*********************************************************************
368 * _mbsset (CRTDLL.??)
370 * Fill a multibyte string with a value.
372 LPSTR __cdecl
CRTDLL__mbsset( LPSTR str
, UINT c
)
376 if (CRTDLL__mb_cur_max_dll
== 1 || c
< 256)
377 return CRTDLL__strset( str
, c
); /* ASCII CP or SB char */
379 c
&= 0xffff; /* Strip high bits */
381 while (str
[0] && str
[1])
387 str
[0] = '\0'; /* FIXME: OK to shorten? */
392 /*********************************************************************
393 * _mbsnset (CRTDLL.??)
395 * Fill a multibyte string with a value up to 'len' characters.
397 LPSTR __cdecl
CRTDLL__mbsnset( LPSTR str
, UINT c
, UINT len
)
404 if (CRTDLL__mb_cur_max_dll
== 1 || c
< 256)
405 return CRTDLL__strnset( str
, c
, len
); /* ASCII CP or SB char */
407 c
&= 0xffff; /* Strip high bits */
409 while (str
[0] && str
[1] && len
--)
415 str
[0] = '\0'; /* FIXME: OK to shorten? */
421 /*********************************************************************
422 * _mbstrlen (CRTDLL.??)
424 * Get the length of a multibyte string.
426 INT __cdecl
CRTDLL__mbstrlen( LPCSTR str
)
428 if (CRTDLL__mb_cur_max_dll
> 1)
433 str
+= CRTDLL_isleadbyte ( *str
) ? 2 : 1;
438 return strlen( str
); /* ASCII CP */
442 /*********************************************************************
443 * _mbsnextc (CRTDLL.??)
445 * Get the next character from a multibyte string.
447 UINT __cdecl
CRTDLL__mbsnextc( LPCSTR str
)
449 if (CRTDLL__mb_cur_max_dll
> 1 && CRTDLL_isleadbyte( *str
))
450 return *str
<< 8 | str
[1];
452 return *str
; /* ASCII CP or SB char */
456 /*********************************************************************
457 * _mbsncpy (CRTDLL.??)
459 * Copy one multibyte string to another up to 'len' characters.
461 LPSTR __cdecl
CRTDLL__mbsncpy( LPSTR dst
, LPCSTR src
, UINT len
)
465 if (CRTDLL__mb_cur_max_dll
> 1)
468 while (src
[0] && src
[1] && len
--)
475 *dst
++ = *src
++; /* Last char or '\0' */
481 return strncpy( dst
, src
, len
); /* ASCII CP */
485 /*********************************************************************
486 * _mbschr (CRTDLL.??)
488 * Find a multibyte character in a multibyte string.
490 LPSTR __cdecl
CRTDLL__mbschr( LPCSTR str
, UINT c
)
492 if (CRTDLL__mb_cur_max_dll
> 1)
495 while((next
= CRTDLL__mbsnextc( str
)))
499 str
+= next
> 255 ? 2 : 1;
501 return c
? NULL
: (LPSTR
)str
;
503 return strchr( str
, c
); /* ASCII CP */
507 /*********************************************************************
508 * _mbsnccnt (CRTDLL.??)
510 * Return the number of mutibyte characters in 'len' bytes of a string.
512 UINT __cdecl
CRTDLL__mbsnccnt( LPCSTR str
, UINT len
)
516 if (CRTDLL__mb_cur_max_dll
> 1)
518 while(*str
&& len
-- > 0)
520 if (CRTDLL_isleadbyte ( *str
))
530 return min( strlen( str
), len
); /* ASCII CP */
534 /*********************************************************************
535 * _mbsncat (CRTDLL.??)
537 * Add 'len' characters from one multibyte string to another.
539 LPSTR __cdecl
CRTDLL__mbsncat( LPSTR dst
, LPCSTR src
, UINT len
)
541 if (CRTDLL__mb_cur_max_dll
> 1)
544 dst
+= CRTDLL__mbslen( dst
);
545 while (*src
&& len
--)
548 if (CRTDLL_isleadbyte( *src
))
556 return strncat( dst
, src
, len
); /* ASCII CP */