- Add several mbcs and CP 932 functions, fix some existing calls
[wine/hacks.git] / dlls / crtdll / mbstring.c
blob5e1f18783c44b09996d49d301949fde07884128f
1 /*
2 * CRTDLL multi-byte string functions
4 * Copyright 1999 Alexandre Julliard
5 * Copyright 2000 Jon Griffths
7 * NOTES
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.
21 * FIXME
22 * Not currently binary compatable with win32. CRTDLL_mbctype must be
23 * populated correctly and the ismb* functions should reference it.
26 #include "crtdll.h"
28 DEFAULT_DEBUG_CHANNEL(crtdll);
30 UCHAR CRTDLL_mbctype[257];
33 /*********************************************************************
34 * _mbscmp (CRTDLL.??)
36 * Compare two multibyte strings.
38 INT __cdecl CRTDLL__mbscmp( LPCSTR str, LPCSTR cmp )
40 if (CRTDLL__mb_cur_max_dll > 1)
42 UINT strc, cmpc;
43 do {
44 if (!*str)
45 return *cmp ? -1 : 0;
46 if (!*cmp)
47 return 1;
48 strc = CRTDLL__mbsnextc(str);
49 cmpc = CRTDLL__mbsnextc(cmp);
50 if (strc != cmpc)
51 return strc < cmpc ? -1 : 1;
52 str += (strc > 255) ? 2 : 1;
53 cmp += (strc > 255) ? 2 : 1; /* equal, use same increment */
54 } while (1);
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 )
81 if (!len)
82 return 0;
84 if (CRTDLL__mb_cur_max_dll > 1)
86 UINT strc, cmpc;
87 while (len--)
89 if (!*str)
90 return *cmp ? -1 : 0;
91 if (!*cmp)
92 return 1;
93 strc = CRTDLL__mbsnextc(str);
94 cmpc = CRTDLL__mbsnextc(cmp);
95 if (strc != cmpc)
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 )
142 if (!str || num < 1)
143 return NULL;
144 if (CRTDLL__mb_cur_max_dll > 1)
146 while(num--)
147 str = CRTDLL__mbsinc( str );
148 return (LPSTR)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)
163 INT len = 0;
164 while (*str)
166 str += CRTDLL_isleadbyte( *str ) ? 2 : 1;
167 len++;
169 return len;
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 */
181 return strrchr(s,x);
185 /*********************************************************************
186 * mbtowc (CRTDLL.430)
188 INT __cdecl CRTDLL_mbtowc( WCHAR *dst, LPCSTR str, INT n )
190 if (n <= 0) return 0;
191 if (!str) 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 */
194 if (!*str) return 0;
195 if (n >= 2 && CRTDLL_isleadbyte(*str) && str[1]) return 2;
196 return 1;
200 /*********************************************************************
201 * _mbccpy (CRTDLL.??)
203 * Copy one multibyte character to another
205 VOID __cdecl CRTDLL__mbccpy(LPSTR dest, LPSTR src)
207 *dest++ = *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);
269 return 0;
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);
286 return 0;
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)
300 if ( c < 256)
301 return CRTDLL__ismbbkana( c );
302 /* Japanese/Katakana, CP 932 */
303 return (c >= 0x8340 && c <= 0x8396 && c != 0x837f);
305 return 0;
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)
345 while (start < str)
346 start += CRTDLL_isleadbyte ( *str ) ? 2 : 1;
348 if (start == str)
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 )
374 LPSTR ret = str;
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])
383 *str++ = c >> 8;
384 *str++ = c & 0xff;
386 if (str[0])
387 str[0] = '\0'; /* FIXME: OK to shorten? */
389 return ret;
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 )
399 LPSTR ret = str;
401 if (!len)
402 return ret;
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--)
411 *str++ = c >> 8;
412 *str++ = c & 0xff;
414 if (len && str[0])
415 str[0] = '\0'; /* FIXME: OK to shorten? */
417 return ret;
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)
430 INT len = 0;
431 while (*str)
433 str += CRTDLL_isleadbyte ( *str ) ? 2 : 1;
434 len++;
436 return len;
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 )
463 if (!len)
464 return dst;
465 if (CRTDLL__mb_cur_max_dll > 1)
467 LPSTR ret = dst;
468 while (src[0] && src[1] && len--)
470 *dst++ = *src++;
471 *dst++ = *src++;
473 if (len--)
475 *dst++ = *src++; /* Last char or '\0' */
476 while(len--)
477 *dst++ = '\0';
479 return ret;
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)
494 UINT next;
495 while((next = CRTDLL__mbsnextc( str )))
497 if (next == c)
498 return (LPSTR)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 )
514 int ret = 0;
516 if (CRTDLL__mb_cur_max_dll > 1)
518 while(*str && len-- > 0)
520 if (CRTDLL_isleadbyte ( *str ))
522 str++;
523 len--;
525 ret++;
526 str++;
528 return ret;
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)
543 LPSTR res = dst;
544 dst += CRTDLL__mbslen( dst );
545 while (*src && len--)
547 *dst = *src;
548 if (CRTDLL_isleadbyte( *src ))
549 *++dst = *++src;
550 dst++;
551 src++;
553 *dst++ = '\0';
554 return res;
556 return strncat( dst, src, len ); /* ASCII CP */