kernel32: Remove superfluous heap reallocation calls in FormatMessageA/W.
[wine] / dlls / msvcrt / mbcs.c
1 /*
2  * msvcrt.dll mbcs functions
3  *
4  * Copyright 1999 Alexandre Julliard
5  * Copyright 2000 Jon Griffths
6  *
7  * This library is free software; you can redistribute it and/or
8  * modify it under the terms of the GNU Lesser General Public
9  * License as published by the Free Software Foundation; either
10  * version 2.1 of the License, or (at your option) any later version.
11  *
12  * This library is distributed in the hope that it will be useful,
13  * but WITHOUT ANY WARRANTY; without even the implied warranty of
14  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
15  * Lesser General Public License for more details.
16  *
17  * You should have received a copy of the GNU Lesser General Public
18  * License along with this library; if not, write to the Free Software
19  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
20  *
21  * FIXME
22  * Not currently binary compatible with win32. MSVCRT_mbctype must be
23  * populated correctly and the ismb* functions should reference it.
24  */
25
26 #include "msvcrt.h"
27 #include "wine/unicode.h"
28 #include "wine/debug.h"
29
30 WINE_DEFAULT_DEBUG_CHANNEL(msvcrt);
31
32 unsigned char MSVCRT_mbctype[257] = { 0 };
33 static int g_mbcp_is_multibyte = 0;
34
35 int MSVCRT___mb_cur_max = 1;
36
37 /* It seems that the data about valid trail bytes is not available from kernel32
38  * so we have to store is here. The format is the same as for lead bytes in CPINFO */
39 struct cp_extra_info_t
40 {
41     int cp;
42     BYTE TrailBytes[MAX_LEADBYTES];
43 };
44
45 static struct cp_extra_info_t g_cpextrainfo[] =
46 {
47     {932, {0x40, 0x7e, 0x80, 0xfc, 0, 0}},
48     {936, {0x40, 0xfe, 0, 0}},
49     {949, {0x41, 0xfe, 0, 0}},
50     {950, {0x40, 0x7e, 0xa1, 0xfe, 0, 0}},
51     {1361, {0x31, 0x7e, 0x81, 0xfe, 0, 0}},
52     {20932, {1, 255, 0, 0}},  /* seems to give different results on different systems */
53     {0, {1, 255, 0, 0}}       /* match all with FIXME */
54 };
55
56 /* Maps multibyte cp932 punctuation marks to single byte equivalents */
57 static const unsigned char mbctombb_932_punct[] = {
58   0x20,0xa4,0xa1,0x2c,0x2e,0xa5,0x3a,0x3b,0x3f,0x21,0xde,0xdf,0x00,0x00,0x00,0x5e,
59   0x7e,0x5f,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xb0,0x00,0x00,0x2f,0x00,
60   0x00,0x00,0x7c,0x00,0x00,0x60,0x27,0x00,0x22,0x28,0x29,0x00,0x00,0x5b,0x5d,0x7b,
61   0x7d,0x00,0x00,0x00,0x00,0xa2,0xa3,0x00,0x00,0x00,0x00,0x2b,0x2d,0x00,0x00,0x00,
62   0x00,0x3d,0x00,0x3c,0x3e,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x5c,
63   0x24,0x00,0x00,0x25,0x23,0x26,0x2a,0x40};
64
65 /* Maps multibyte cp932 hiragana/katakana to single-byte equivalents */
66 static const unsigned char mbctombb_932_kana[] = {
67   0xa7,0xb1,0xa8,0xb2,0xa9,0xb3,0xaa,0xb4,0xab,0xb5,0xb6,0xb6,0xb7,0xb7,0xb8,0xb8,
68   0xb9,0xb9,0xba,0xba,0xbb,0xbb,0xbc,0xbc,0xbd,0xbd,0xbe,0xbe,0xbf,0xbf,0xc0,0xc0,
69   0xc1,0xc1,0xaf,0xc2,0xc2,0xc3,0xc3,0xc4,0xc4,0xc5,0xc6,0xc7,0xc8,0xc9,0xca,0xca,
70   0xca,0xcb,0xcb,0xcb,0xcc,0xcc,0xcc,0xcd,0xcd,0xcd,0xce,0xce,0xce,0xcf,0xd0,0xd1,
71   0xd2,0xd3,0xac,0xd4,0xad,0xd5,0xae,0xd6,0xd7,0xd8,0xd9,0xda,0xdb,0xdc,0xdc,0xb2,
72   0xb4,0xa6,0xdd,0xb3,0xb6,0xb9};
73
74 static MSVCRT_wchar_t msvcrt_mbc_to_wc(unsigned int ch)
75 {
76   MSVCRT_wchar_t chW;
77   char mbch[2];
78   int n_chars;
79
80   if (ch <= 0xff) {
81     mbch[0] = ch;
82     n_chars = 1;
83   } else {
84     mbch[0] = (ch >> 8) & 0xff;
85     mbch[1] = ch & 0xff;
86     n_chars = 2;
87   }
88   if (!MultiByteToWideChar(get_locale()->locinfo->lc_codepage, 0, mbch, n_chars, &chW, 1))
89   {
90     WARN("MultiByteToWideChar failed on %x\n", ch);
91     return 0;
92   }
93   return chW;
94 }
95
96 static inline MSVCRT_size_t u_strlen( const unsigned char *str )
97 {
98   return strlen( (const char*) str );
99 }
100
101 static inline unsigned char* u_strncat( unsigned char* dst, const unsigned char* src, MSVCRT_size_t len )
102 {
103   return (unsigned char*)strncat( (char*)dst, (const char*)src, len);
104 }
105
106 static inline int u_strcmp( const unsigned char *s1, const unsigned char *s2 )
107 {
108   return strcmp( (const char*)s1, (const char*)s2 );
109 }
110
111 static inline int u_strcasecmp( const unsigned char *s1, const unsigned char *s2 )
112 {
113   return strcasecmp( (const char*)s1, (const char*)s2 );
114 }
115
116 static inline int u_strncmp( const unsigned char *s1, const unsigned char *s2, MSVCRT_size_t len )
117 {
118   return strncmp( (const char*)s1, (const char*)s2, len );
119 }
120
121 static inline int u_strncasecmp( const unsigned char *s1, const unsigned char *s2, MSVCRT_size_t len )
122 {
123   return strncasecmp( (const char*)s1, (const char*)s2, len );
124 }
125
126 static inline unsigned char *u_strchr( const unsigned char *s, unsigned char x )
127 {
128   return (unsigned char*) strchr( (const char*)s, x );
129 }
130
131 static inline unsigned char *u_strrchr( const unsigned char *s, unsigned char x )
132 {
133   return (unsigned char*) strrchr( (const char*)s, x );
134 }
135
136 static inline unsigned char *u_strtok( unsigned char *s, const unsigned char *delim )
137 {
138   return (unsigned char*) strtok( (char*)s, (const char*)delim );
139 }
140
141 static inline unsigned char *u__strset( unsigned char *s, unsigned char c )
142 {
143   return (unsigned char*) _strset( (char*)s, c);
144 }
145
146 static inline unsigned char *u__strnset( unsigned char *s, unsigned char c, MSVCRT_size_t len )
147 {
148   return (unsigned char*) MSVCRT__strnset( (char*)s, c, len );
149 }
150
151 static inline MSVCRT_size_t u_strcspn( const unsigned char *s, const unsigned char *rej )
152 {
153   return strcspn( (const char *)s, (const char*)rej );
154 }
155
156 /*********************************************************************
157  *              __p__mbctype (MSVCRT.@)
158  */
159 unsigned char* CDECL __p__mbctype(void)
160 {
161   return MSVCRT_mbctype;
162 }
163
164 /*********************************************************************
165  *              ___mb_cur_max_func(MSVCRT.@)
166  */
167 int* CDECL MSVCRT____mb_cur_max_func(void)
168 {
169   return &get_locale()->locinfo->mb_cur_max;
170 }
171
172 /*********************************************************************
173  *              _setmbcp (MSVCRT.@)
174  */
175 int CDECL _setmbcp(int cp)
176 {
177   MSVCRT__locale_t locale = get_locale();
178   int newcp;
179   CPINFO cpi;
180   BYTE *bytes;
181   WORD chartypes[256];
182   WORD *curr_type;
183   char bufA[256];
184   WCHAR bufW[256];
185   int charcount;
186   int ret;
187   int i;
188
189   switch (cp)
190   {
191     case _MB_CP_ANSI:
192       newcp = GetACP();
193       break;
194     case _MB_CP_OEM:
195       newcp = GetOEMCP();
196       break;
197     case _MB_CP_LOCALE:
198       newcp = locale->locinfo->lc_codepage;
199       break;
200     case _MB_CP_SBCS:
201       newcp = 20127;   /* ASCII */
202       break;
203     default:
204       newcp = cp;
205       break;
206   }
207
208   if (!GetCPInfo(newcp, &cpi))
209   {
210     WARN("Codepage %d not found\n", newcp);
211     *MSVCRT__errno() = MSVCRT_EINVAL;
212     return -1;
213   }
214
215   /* setup the _mbctype */
216   memset(MSVCRT_mbctype, 0, sizeof(MSVCRT_mbctype));
217
218   bytes = cpi.LeadByte;
219   while (bytes[0] || bytes[1])
220   {
221     for (i = bytes[0]; i <= bytes[1]; i++)
222       MSVCRT_mbctype[i + 1] |= _M1;
223     bytes += 2;
224   }
225
226   if (cpi.MaxCharSize > 1)
227   {
228     /* trail bytes not available through kernel32 but stored in a structure in msvcrt */
229     struct cp_extra_info_t *cpextra = g_cpextrainfo;
230
231     g_mbcp_is_multibyte = 1;
232     while (TRUE)
233     {
234       if (cpextra->cp == 0 || cpextra->cp == newcp)
235       {
236         if (cpextra->cp == 0)
237           FIXME("trail bytes data not available for DBCS codepage %d - assuming all bytes\n", newcp);
238
239         bytes = cpextra->TrailBytes;
240         while (bytes[0] || bytes[1])
241         {
242           for (i = bytes[0]; i <= bytes[1]; i++)
243             MSVCRT_mbctype[i + 1] |= _M2;
244           bytes += 2;
245         }
246         break;
247       }
248       cpextra++;
249     }
250   }
251   else
252     g_mbcp_is_multibyte = 0;
253
254   /* we can't use GetStringTypeA directly because we don't have a locale - only a code page
255    */
256   charcount = 0;
257   for (i = 0; i < 256; i++)
258     if (!(MSVCRT_mbctype[i + 1] & _M1))
259       bufA[charcount++] = i;
260
261   ret = MultiByteToWideChar(newcp, 0, bufA, charcount, bufW, charcount);
262   if (ret != charcount)
263     ERR("MultiByteToWideChar of chars failed for cp %d, ret=%d (exp %d), error=%d\n", newcp, ret, charcount, GetLastError());
264
265   GetStringTypeW(CT_CTYPE1, bufW, charcount, chartypes);
266
267   curr_type = chartypes;
268   for (i = 0; i < 256; i++)
269     if (!(MSVCRT_mbctype[i + 1] & _M1))
270     {
271         if ((*curr_type) & C1_UPPER)
272             MSVCRT_mbctype[i + 1] |= _SBUP;
273         if ((*curr_type) & C1_LOWER)
274             MSVCRT_mbctype[i + 1] |= _SBLOW;
275         curr_type++;
276     }
277
278   if (newcp == 932)   /* CP932 only - set _MP and _MS */
279   {
280     /* On Windows it's possible to calculate the _MP and _MS from CT_CTYPE1
281      * and CT_CTYPE3. But as of Wine 0.9.43 we return wrong values what makes
282      * it hard. As this is set only for codepage 932 we hardcode it what gives
283      * also faster execution.
284      */
285     for (i = 161; i <= 165; i++)
286       MSVCRT_mbctype[i + 1] |= _MP;
287     for (i = 166; i <= 223; i++)
288       MSVCRT_mbctype[i + 1] |= _MS;
289   }
290
291   locale->locinfo->lc_collate_cp = newcp;
292   locale->locinfo->lc_codepage = newcp;
293   TRACE("(%d) -> %d\n", cp, locale->locinfo->lc_codepage);
294   return 0;
295 }
296
297 /*********************************************************************
298  *              _getmbcp (MSVCRT.@)
299  */
300 int CDECL _getmbcp(void)
301 {
302   /* FIXME: get_locale()->mbcinfo->mbcodepage should be used here */
303   return get_locale()->locinfo->lc_codepage;
304 }
305
306 /*********************************************************************
307  *              _mbsnextc(MSVCRT.@)
308  */
309 unsigned int CDECL _mbsnextc(const unsigned char* str)
310 {
311   if(_ismbblead(*str))
312     return *str << 8 | str[1];
313   return *str;
314 }
315
316 /*********************************************************************
317  *              _mbctolower(MSVCRT.@)
318  */
319 unsigned int CDECL _mbctolower(unsigned int c)
320 {
321     if (MSVCRT_isleadbyte(c))
322     {
323       FIXME("Handle MBC chars\n");
324       return c;
325     }
326     return tolower(c); /* ASCII CP or SB char */
327 }
328
329 /*********************************************************************
330  *              _mbctoupper(MSVCRT.@)
331  */
332 unsigned int CDECL _mbctoupper(unsigned int c)
333 {
334     if (MSVCRT_isleadbyte(c))
335     {
336       FIXME("Handle MBC chars\n");
337       return c;
338     }
339     return toupper(c); /* ASCII CP or SB char */
340 }
341
342 /*********************************************************************
343  *              _mbctombb (MSVCRT.@)
344  */
345 unsigned int CDECL _mbctombb(unsigned int c)
346 {
347     unsigned int value;
348
349     if(get_locale()->locinfo->lc_codepage == 932)
350     {
351         if(c >= 0x829f && c <= 0x82f1)    /* Hiragana */
352             return mbctombb_932_kana[c - 0x829f];
353         if(c >= 0x8340 && c <= 0x8396 && c != 0x837f)    /* Katakana */
354             return mbctombb_932_kana[c - 0x8340 - (c >= 0x837f ? 1 : 0)];
355         if(c >= 0x8140 && c <= 0x8197)    /* Punctuation */
356         {
357             value = mbctombb_932_punct[c - 0x8140];
358             return value ? value : c;
359         }
360         if((c >= 0x824f && c <= 0x8258) || /* Fullwidth digits */
361            (c >= 0x8260 && c <= 0x8279))   /* Fullwidth capitals letters */
362             return c - 0x821f;
363         if(c >= 0x8281 && c <= 0x829a)     /* Fullwidth small letters */
364             return c - 0x8220;
365         /* all other cases return c */
366     }
367     return c;
368 }
369
370 /*********************************************************************
371  *              _mbcjistojms(MSVCRT.@)
372  *
373  *              Converts a jis character to sjis.
374  *              Based on description from
375  *              http://www.slayers.ne.jp/~oouchi/code/jistosjis.html
376  */
377 unsigned int CDECL _mbcjistojms(unsigned int c)
378 {
379   /* Conversion takes place only when codepage is 932.
380      In all other cases, c is returned unchanged */
381   if(get_locale()->locinfo->lc_codepage == 932)
382   {
383     if(HIBYTE(c) >= 0x21 && HIBYTE(c) <= 0x7e &&
384        LOBYTE(c) >= 0x21 && LOBYTE(c) <= 0x7e)
385     {
386       if(HIBYTE(c) % 2)
387         c += 0x1f;
388       else
389         c += 0x7d;
390
391       if(LOBYTE(c) > 0x7F)
392         c += 0x1;
393
394       c = (((HIBYTE(c) - 0x21)/2 + 0x81) << 8) | LOBYTE(c);
395
396       if(HIBYTE(c) > 0x9f)
397         c += 0x4000;
398     }
399     else
400       return 0; /* Codepage is 932, but c can't be converted */
401   }
402
403   return c;
404 }
405
406 /*********************************************************************
407  *              _mbsdec(MSVCRT.@)
408  */
409 unsigned char* CDECL _mbsdec(const unsigned char* start, const unsigned char* cur)
410 {
411   if(get_locale()->locinfo->mb_cur_max > 1)
412     return (unsigned char *)(_ismbstrail(start,cur-1) ? cur - 2 : cur -1);
413
414   return (unsigned char *)cur - 1; /* ASCII CP or SB char */
415 }
416
417 /*********************************************************************
418  *              _mbclen(MSVCRT.@)
419  */
420 unsigned int CDECL _mbclen(const unsigned char* str)
421 {
422   return _ismbblead(*str) ? 2 : 1;
423 }
424
425 /*********************************************************************
426  *              _mbsinc(MSVCRT.@)
427  */
428 unsigned char* CDECL _mbsinc(const unsigned char* str)
429 {
430   return (unsigned char *)(str + _mbclen(str));
431 }
432
433 /*********************************************************************
434  *              _mbsninc(MSVCRT.@)
435  */
436 unsigned char* CDECL _mbsninc(const unsigned char* str, MSVCRT_size_t num)
437 {
438   if(!str)
439     return NULL;
440
441   while (num > 0 && *str)
442   {
443     if (_ismbblead(*str))
444     {
445       if (!*(str+1))
446          break;
447       str++;
448     }
449     str++;
450     num--;
451   }
452
453   return (unsigned char*)str;
454 }
455
456 /*********************************************************************
457  *              _mbslen(MSVCRT.@)
458  */
459 MSVCRT_size_t CDECL _mbslen(const unsigned char* str)
460 {
461   MSVCRT_size_t len = 0;
462   while(*str)
463   {
464     if (_ismbblead(*str))
465     {
466       str++;
467       if (!*str)  /* count only full chars */
468         break;
469     }
470     str++;
471     len++;
472   }
473   return len;
474 }
475
476 /*********************************************************************
477  *              _mbccpy(MSVCRT.@)
478  */
479 void CDECL _mbccpy(unsigned char* dest, const unsigned char* src)
480 {
481   *dest = *src;
482   if(_ismbblead(*src))
483     *++dest = *++src; /* MB char */
484 }
485
486 /*********************************************************************
487  *              _mbsncpy(MSVCRT.@)
488  * REMARKS
489  *  The parameter n is the number or characters to copy, not the size of
490  *  the buffer. Use _mbsnbcpy for a function analogical to strncpy
491  */
492 unsigned char* CDECL _mbsncpy(unsigned char* dst, const unsigned char* src, MSVCRT_size_t n)
493 {
494   unsigned char* ret = dst;
495   if(!n)
496     return dst;
497   if (g_mbcp_is_multibyte)
498   {
499     while (*src && n)
500     {
501       n--;
502       if (_ismbblead(*src))
503       {
504         if (!*(src+1))
505         {
506             *dst++ = 0;
507             *dst++ = 0;
508             break;
509         }
510
511         *dst++ = *src++;
512       }
513
514       *dst++ = *src++;
515     }
516   }
517   else
518   {
519     while (n)
520     {
521         n--;
522         if (!(*dst++ = *src++)) break;
523     }
524   }
525   while (n--) *dst++ = 0;
526   return ret;
527 }
528
529 /*********************************************************************
530  *              _mbsnbcpy_s(MSVCRT.@)
531  * REMARKS
532  * Unlike _mbsnbcpy this function does not pad the rest of the dest
533  * string with 0
534  */
535 int CDECL _mbsnbcpy_s(unsigned char* dst, MSVCRT_size_t size, const unsigned char* src, MSVCRT_size_t n)
536 {
537     MSVCRT_size_t pos = 0;
538
539     if(!dst || size == 0)
540         return MSVCRT_EINVAL;
541     if(!src)
542     {
543         dst[0] = '\0';
544         return MSVCRT_EINVAL;
545     }
546     if(!n)
547         return 0;
548
549     if(g_mbcp_is_multibyte)
550     {
551         int is_lead = 0;
552         while (*src && n)
553         {
554             if(pos == size)
555             {
556                 dst[0] = '\0';
557                 return MSVCRT_ERANGE;
558             }
559             is_lead = (!is_lead && _ismbblead(*src));
560             n--;
561             dst[pos++] = *src++;
562         }
563
564         if (is_lead) /* if string ends with a lead, remove it */
565             dst[pos - 1] = 0;
566     }
567     else
568     {
569         while (n)
570         {
571             n--;
572             if(pos == size)
573             {
574                 dst[0] = '\0';
575                 return MSVCRT_ERANGE;
576             }
577
578             if(!(*src)) break;
579             dst[pos++] = *src++;
580         }
581     }
582
583     if(pos < size)
584         dst[pos] = '\0';
585     else
586     {
587         dst[0] = '\0';
588         return MSVCRT_ERANGE;
589     }
590
591     return 0;
592 }
593
594 /*********************************************************************
595  *              _mbsnbcpy(MSVCRT.@)
596  * REMARKS
597  *  Like strncpy this function doesn't enforce the string to be
598  *  NUL-terminated
599  */
600 unsigned char* CDECL _mbsnbcpy(unsigned char* dst, const unsigned char* src, MSVCRT_size_t n)
601 {
602   unsigned char* ret = dst;
603   if(!n)
604     return dst;
605   if(g_mbcp_is_multibyte)
606   {
607     int is_lead = 0;
608     while (*src && n)
609     {
610       is_lead = (!is_lead && _ismbblead(*src));
611       n--;
612       *dst++ = *src++;
613     }
614
615     if (is_lead) /* if string ends with a lead, remove it */
616         *(dst - 1) = 0;
617   }
618   else
619   {
620     while (n)
621     {
622         n--;
623         if (!(*dst++ = *src++)) break;
624     }
625   }
626   while (n--) *dst++ = 0;
627   return ret;
628 }
629
630 /*********************************************************************
631  *              _mbscmp(MSVCRT.@)
632  */
633 int CDECL _mbscmp(const unsigned char* str, const unsigned char* cmp)
634 {
635   if(get_locale()->locinfo->mb_cur_max > 1)
636   {
637     unsigned int strc, cmpc;
638     do {
639       if(!*str)
640         return *cmp ? -1 : 0;
641       if(!*cmp)
642         return 1;
643       strc = _mbsnextc(str);
644       cmpc = _mbsnextc(cmp);
645       if(strc != cmpc)
646         return strc < cmpc ? -1 : 1;
647       str +=(strc > 255) ? 2 : 1;
648       cmp +=(strc > 255) ? 2 : 1; /* equal, use same increment */
649     } while(1);
650   }
651   return u_strcmp(str, cmp); /* ASCII CP */
652 }
653
654 /*********************************************************************
655  *              _mbsicoll(MSVCRT.@)
656  * FIXME: handle locales.
657  */
658 int CDECL _mbsicoll(const unsigned char* str, const unsigned char* cmp)
659 {
660   if(get_locale()->locinfo->mb_cur_max > 1)
661   {
662     unsigned int strc, cmpc;
663     do {
664       if(!*str)
665         return *cmp ? -1 : 0;
666       if(!*cmp)
667         return 1;
668       strc = _mbctolower(_mbsnextc(str));
669       cmpc = _mbctolower(_mbsnextc(cmp));
670       if(strc != cmpc)
671         return strc < cmpc ? -1 : 1;
672       str +=(strc > 255) ? 2 : 1;
673       cmp +=(strc > 255) ? 2 : 1; /* equal, use same increment */
674     } while(1);
675   }
676   return u_strcasecmp(str, cmp); /* ASCII CP */
677 }
678
679 /*********************************************************************
680  *              _mbscoll(MSVCRT.@)
681  * Performs a case-sensitive comparison according to the current code page
682  * RETURN
683  *   _NLSCMPERROR if error
684  * FIXME: handle locales.
685  */
686 int CDECL _mbscoll(const unsigned char* str, const unsigned char* cmp)
687 {
688   if(get_locale()->locinfo->mb_cur_max > 1)
689   {
690     unsigned int strc, cmpc;
691     do {
692       if(!*str)
693         return *cmp ? -1 : 0;
694       if(!*cmp)
695         return 1;
696       strc = _mbsnextc(str);
697       cmpc = _mbsnextc(cmp);
698       if(strc != cmpc)
699         return strc < cmpc ? -1 : 1;
700       str +=(strc > 255) ? 2 : 1;
701       cmp +=(strc > 255) ? 2 : 1; /* equal, use same increment */
702     } while(1);
703   }
704   return u_strcmp(str, cmp); /* ASCII CP */
705 }
706
707
708 /*********************************************************************
709  *              _mbsicmp(MSVCRT.@)
710  */
711 int CDECL _mbsicmp(const unsigned char* str, const unsigned char* cmp)
712 {
713   if(get_locale()->locinfo->mb_cur_max > 1)
714   {
715     unsigned int strc, cmpc;
716     do {
717       if(!*str)
718         return *cmp ? -1 : 0;
719       if(!*cmp)
720         return 1;
721       strc = _mbctolower(_mbsnextc(str));
722       cmpc = _mbctolower(_mbsnextc(cmp));
723       if(strc != cmpc)
724         return strc < cmpc ? -1 : 1;
725       str +=(strc > 255) ? 2 : 1;
726       cmp +=(strc > 255) ? 2 : 1; /* equal, use same increment */
727     } while(1);
728   }
729   return u_strcasecmp(str, cmp); /* ASCII CP */
730 }
731
732 /*********************************************************************
733  *              _mbsncmp(MSVCRT.@)
734  */
735 int CDECL _mbsncmp(const unsigned char* str, const unsigned char* cmp, MSVCRT_size_t len)
736 {
737   if(!len)
738     return 0;
739
740   if(get_locale()->locinfo->mb_cur_max > 1)
741   {
742     unsigned int strc, cmpc;
743     while(len--)
744     {
745       int inc;
746       if(!*str)
747         return *cmp ? -1 : 0;
748       if(!*cmp)
749         return 1;
750       strc = _mbsnextc(str);
751       cmpc = _mbsnextc(cmp);
752       if(strc != cmpc)
753         return strc < cmpc ? -1 : 1;
754       inc=(strc > 255) ? 2 : 1; /* Equal, use same increment */
755       str += inc;
756       cmp += inc;
757     }
758     return 0; /* Matched len chars */
759   }
760   return u_strncmp(str, cmp, len); /* ASCII CP */
761 }
762
763 /*********************************************************************
764  *              _mbsnbcmp(MSVCRT.@)
765  */
766 int CDECL _mbsnbcmp(const unsigned char* str, const unsigned char* cmp, MSVCRT_size_t len)
767 {
768   if (!len)
769     return 0;
770   if(get_locale()->locinfo->mb_cur_max > 1)
771   {
772     unsigned int strc, cmpc;
773     while (len)
774     {
775       int clen;
776       if(!*str)
777         return *cmp ? -1 : 0;
778       if(!*cmp)
779         return 1;
780       if (MSVCRT_isleadbyte(*str))
781       {
782         strc=(len>=2)?_mbsnextc(str):0;
783         clen=2;
784       }
785       else
786       {
787         strc=*str;
788         clen=1;
789       }
790       if (MSVCRT_isleadbyte(*cmp))
791         cmpc=(len>=2)?_mbsnextc(cmp):0;
792       else
793         cmpc=*str;
794       if(strc != cmpc)
795         return strc < cmpc ? -1 : 1;
796       len -= clen;
797       str += clen;
798       cmp += clen;
799     }
800     return 0; /* Matched len chars */
801   }
802   return u_strncmp(str,cmp,len);
803 }
804
805 /*********************************************************************
806  *              _mbsnicmp(MSVCRT.@)
807  *
808  * Compare two multibyte strings case insensitively to 'len' characters.
809  */
810 int CDECL _mbsnicmp(const unsigned char* str, const unsigned char* cmp, MSVCRT_size_t len)
811 {
812   /* FIXME: No tolower() for mb strings yet */
813   if(get_locale()->locinfo->mb_cur_max > 1)
814   {
815     unsigned int strc, cmpc;
816     while(len--)
817     {
818       if(!*str)
819         return *cmp ? -1 : 0;
820       if(!*cmp)
821         return 1;
822       strc = _mbctolower(_mbsnextc(str));
823       cmpc = _mbctolower(_mbsnextc(cmp));
824       if(strc != cmpc)
825         return strc < cmpc ? -1 : 1;
826       str +=(strc > 255) ? 2 : 1;
827       cmp +=(strc > 255) ? 2 : 1; /* Equal, use same increment */
828     }
829     return 0; /* Matched len chars */
830   }
831   return u_strncasecmp(str, cmp, len); /* ASCII CP */
832 }
833
834 /*********************************************************************
835  *              _mbsnbicmp(MSVCRT.@)
836  */
837 int CDECL _mbsnbicmp(const unsigned char* str, const unsigned char* cmp, MSVCRT_size_t len)
838 {
839   if (!len)
840     return 0;
841   if(get_locale()->locinfo->mb_cur_max > 1)
842   {
843     unsigned int strc, cmpc;
844     while (len)
845     {
846       int clen;
847       if(!*str)
848         return *cmp ? -1 : 0;
849       if(!*cmp)
850         return 1;
851       if (MSVCRT_isleadbyte(*str))
852       {
853         strc=(len>=2)?_mbsnextc(str):0;
854         clen=2;
855       }
856       else
857       {
858         strc=*str;
859         clen=1;
860       }
861       if (MSVCRT_isleadbyte(*cmp))
862         cmpc=(len>=2)?_mbsnextc(cmp):0;
863       else
864         cmpc=*str;
865       strc = _mbctolower(strc);
866       cmpc = _mbctolower(cmpc);
867       if(strc != cmpc)
868         return strc < cmpc ? -1 : 1;
869       len -= clen;
870       str += clen;
871       cmp += clen;
872     }
873     return 0; /* Matched len bytes */
874   }
875   return u_strncasecmp(str,cmp,len);
876 }
877
878 /*********************************************************************
879  *              _mbscat (MSVCRT.@)
880  */
881 unsigned char * CDECL _mbscat( unsigned char *dst, const unsigned char *src )
882 {
883     strcat( (char *)dst, (const char *)src );
884     return dst;
885 }
886
887 /*********************************************************************
888  *              _mbscpy (MSVCRT.@)
889  */
890 unsigned char* CDECL _mbscpy( unsigned char *dst, const unsigned char *src )
891 {
892     strcpy( (char *)dst, (const char *)src );
893     return dst;
894 }
895
896 /*********************************************************************
897  *              _mbsstr (MSVCRT.@)
898  */
899 unsigned char * CDECL _mbsstr(const unsigned char *haystack, const unsigned char *needle)
900 {
901     return (unsigned char *)strstr( (const char *)haystack, (const char *)needle );
902 }
903
904 /*********************************************************************
905  *              _mbschr(MSVCRT.@)
906  *
907  * Find a multibyte character in a multibyte string.
908  */
909 unsigned char* CDECL _mbschr(const unsigned char* s, unsigned int x)
910 {
911   if(get_locale()->locinfo->mb_cur_max > 1)
912   {
913     unsigned int c;
914     while (1)
915     {
916       c = _mbsnextc(s);
917       if (c == x)
918         return (unsigned char*)s;
919       if (!c)
920         return NULL;
921       s += c > 255 ? 2 : 1;
922     }
923   }
924   return u_strchr(s, x); /* ASCII CP */
925 }
926
927 /*********************************************************************
928  *              _mbsrchr(MSVCRT.@)
929  */
930 unsigned char* CDECL _mbsrchr(const unsigned char* s, unsigned int x)
931 {
932   if(get_locale()->locinfo->mb_cur_max > 1)
933   {
934     unsigned int c;
935     unsigned char* match=NULL;
936     if(!s)
937       return NULL;
938     while (1) {
939       c = _mbsnextc(s);
940       if (c == x)
941         match=(unsigned char*)s;
942       if (!c)
943         return match;
944       s +=(c > 255) ? 2 : 1;
945     }
946   }
947   return u_strrchr(s, x);
948 }
949
950 /*********************************************************************
951  *              _mbstok(MSVCRT.@)
952  *
953  * Find and extract tokens from strings
954  */
955 unsigned char* CDECL _mbstok(unsigned char *str, const unsigned char *delim)
956 {
957     thread_data_t *data = msvcrt_get_thread_data();
958     unsigned char *ret;
959
960     if(get_locale()->locinfo->mb_cur_max > 1)
961     {
962         unsigned int c;
963
964         if (!str)
965             if (!(str = data->mbstok_next)) return NULL;
966
967         while ((c = _mbsnextc(str)) && _mbschr(delim, c)) {
968             str += c > 255 ? 2 : 1;
969         }
970         if (!*str) return NULL;
971         ret = str++;
972         while ((c = _mbsnextc(str)) && !_mbschr(delim, c)) {
973             str += c > 255 ? 2 : 1;
974         }
975         if (*str) {
976             *str++ = 0;
977             if (c > 255) *str++ = 0;
978         }
979         data->mbstok_next = str;
980         return ret;
981     }
982     return u_strtok(str, delim); /* ASCII CP */
983 }
984
985 /*********************************************************************
986  *              mbtowc(MSVCRT.@)
987  */
988 int CDECL MSVCRT_mbtowc(MSVCRT_wchar_t *dst, const char* str, MSVCRT_size_t n)
989 {
990     /* temp var needed because MultiByteToWideChar wants non NULL destination */
991     MSVCRT_wchar_t tmpdst = '\0';
992
993     if(n <= 0 || !str)
994         return 0;
995     if(!MultiByteToWideChar(CP_ACP, 0, str, n, &tmpdst, 1))
996         return -1;
997     if(dst)
998         *dst = tmpdst;
999     /* return the number of bytes from src that have been used */
1000     if(!*str)
1001         return 0;
1002     if(n >= 2 && MSVCRT_isleadbyte(*str) && str[1])
1003         return 2;
1004     return 1;
1005 }
1006
1007 /*********************************************************************
1008  *              _mbbtombc(MSVCRT.@)
1009  */
1010 unsigned int CDECL _mbbtombc(unsigned int c)
1011 {
1012   if(get_locale()->locinfo->mb_cur_max > 1 &&
1013      ((c >= 0x20 && c <=0x7e) ||(c >= 0xa1 && c <= 0xdf)))
1014   {
1015     /* FIXME: I can't get this function to return anything
1016      * different from what I pass it...
1017      */
1018   }
1019   return c;  /* ASCII CP or no MB char */
1020 }
1021
1022 /*********************************************************************
1023  *              _mbbtype(MSVCRT.@)
1024  */
1025 int CDECL _mbbtype(unsigned char c, int type)
1026 {
1027     if (type == 1)
1028     {
1029         if ((c >= 0x20 && c <= 0x7e) || (c >= 0xa1 && c <= 0xdf))
1030             return _MBC_SINGLE;
1031         else if ((c >= 0x40 && c <= 0x7e) || (c >= 0x80 && c <= 0xfc))
1032             return _MBC_TRAIL;
1033         else
1034             return _MBC_ILLEGAL;
1035     }
1036     else
1037     {
1038         if ((c >= 0x20 && c <= 0x7e) || (c >= 0xa1 && c <= 0xdf))
1039             return _MBC_SINGLE;
1040         else if ((c >= 0x81 && c <= 0x9f) || (c >= 0xe0 && c <= 0xfc))
1041             return _MBC_LEAD;
1042         else
1043             return _MBC_ILLEGAL;
1044     }
1045 }
1046
1047 /*********************************************************************
1048  *              _ismbbkana(MSVCRT.@)
1049  */
1050 int CDECL _ismbbkana(unsigned int c)
1051 {
1052   /* FIXME: use lc_ctype when supported, not lc_all */
1053   if(get_locale()->locinfo->lc_codepage == 932)
1054   {
1055     /* Japanese/Katakana, CP 932 */
1056     return (c >= 0xa1 && c <= 0xdf);
1057   }
1058   return 0;
1059 }
1060
1061 /*********************************************************************
1062  *              _ismbcdigit(MSVCRT.@)
1063  */
1064 int CDECL _ismbcdigit(unsigned int ch)
1065 {
1066     MSVCRT_wchar_t wch = msvcrt_mbc_to_wc( ch );
1067     return (get_char_typeW( wch ) & C1_DIGIT);
1068 }
1069
1070 /*********************************************************************
1071  *              _ismbcgraph(MSVCRT.@)
1072  */
1073 int CDECL _ismbcgraph(unsigned int ch)
1074 {
1075     MSVCRT_wchar_t wch = msvcrt_mbc_to_wc( ch );
1076     return (get_char_typeW( wch ) & (C1_UPPER | C1_LOWER | C1_DIGIT | C1_PUNCT | C1_ALPHA));
1077 }
1078
1079 /*********************************************************************
1080  *              _ismbcalpha (MSVCRT.@)
1081  */
1082 int CDECL _ismbcalpha(unsigned int ch)
1083 {
1084     MSVCRT_wchar_t wch = msvcrt_mbc_to_wc( ch );
1085     return (get_char_typeW( wch ) & C1_ALPHA);
1086 }
1087
1088 /*********************************************************************
1089  *              _ismbclower (MSVCRT.@)
1090  */
1091 int CDECL _ismbclower(unsigned int ch)
1092 {
1093     MSVCRT_wchar_t wch = msvcrt_mbc_to_wc( ch );
1094     return (get_char_typeW( wch ) & C1_UPPER);
1095 }
1096
1097 /*********************************************************************
1098  *              _ismbcupper (MSVCRT.@)
1099  */
1100 int CDECL _ismbcupper(unsigned int ch)
1101 {
1102     MSVCRT_wchar_t wch = msvcrt_mbc_to_wc( ch );
1103     return (get_char_typeW( wch ) & C1_LOWER);
1104 }
1105
1106 /*********************************************************************
1107  *              _ismbcsymbol(MSVCRT.@)
1108  */
1109 int CDECL _ismbcsymbol(unsigned int ch)
1110 {
1111     MSVCRT_wchar_t wch = msvcrt_mbc_to_wc( ch );
1112     WORD ctype;
1113     if (!GetStringTypeW(CT_CTYPE3, &wch, 1, &ctype))
1114     {
1115         WARN("GetStringTypeW failed on %x\n", ch);
1116         return 0;
1117     }
1118     return ((ctype & C3_SYMBOL) != 0);
1119 }
1120
1121 /*********************************************************************
1122  *              _ismbcalnum (MSVCRT.@)
1123  */
1124 int CDECL _ismbcalnum(unsigned int ch)
1125 {
1126     MSVCRT_wchar_t wch = msvcrt_mbc_to_wc( ch );
1127     return (get_char_typeW( wch ) & (C1_ALPHA | C1_DIGIT));
1128 }
1129
1130 /*********************************************************************
1131  *              _ismbcspace (MSVCRT.@)
1132  */
1133 int CDECL _ismbcspace(unsigned int ch)
1134 {
1135     MSVCRT_wchar_t wch = msvcrt_mbc_to_wc( ch );
1136     return (get_char_typeW( wch ) & C1_SPACE);
1137 }
1138
1139 /*********************************************************************
1140  *              _ismbcprint (MSVCRT.@)
1141  */
1142 int CDECL _ismbcprint(unsigned int ch)
1143 {
1144     MSVCRT_wchar_t wch = msvcrt_mbc_to_wc( ch );
1145     return (get_char_typeW( wch ) & (C1_UPPER | C1_LOWER | C1_DIGIT | C1_PUNCT | C1_ALPHA | C1_SPACE));
1146 }
1147
1148 /*********************************************************************
1149  *              _ismbcpunct(MSVCRT.@)
1150  */
1151 int CDECL _ismbcpunct(unsigned int ch)
1152 {
1153     MSVCRT_wchar_t wch = msvcrt_mbc_to_wc( ch );
1154     return (get_char_typeW( wch ) & C1_PUNCT);
1155 }
1156
1157 /*********************************************************************
1158  *              _ismbchira(MSVCRT.@)
1159  */
1160 int CDECL _ismbchira(unsigned int c)
1161 {
1162   /* FIXME: use lc_ctype when supported, not lc_all */
1163   if(get_locale()->locinfo->lc_codepage == 932)
1164   {
1165     /* Japanese/Hiragana, CP 932 */
1166     return (c >= 0x829f && c <= 0x82f1);
1167   }
1168   return 0;
1169 }
1170
1171 /*********************************************************************
1172  *              _ismbckata(MSVCRT.@)
1173  */
1174 int CDECL _ismbckata(unsigned int c)
1175 {
1176   /* FIXME: use lc_ctype when supported, not lc_all */
1177   if(get_locale()->locinfo->lc_codepage == 932)
1178   {
1179     if(c < 256)
1180       return _ismbbkana(c);
1181     /* Japanese/Katakana, CP 932 */
1182     return (c >= 0x8340 && c <= 0x8396 && c != 0x837f);
1183   }
1184   return 0;
1185 }
1186
1187 /*********************************************************************
1188  *              _ismbblead(MSVCRT.@)
1189  */
1190 int CDECL _ismbblead(unsigned int c)
1191 {
1192   return (MSVCRT_mbctype[(c&0xff) + 1] & _M1) != 0;
1193 }
1194
1195
1196 /*********************************************************************
1197  *              _ismbbtrail(MSVCRT.@)
1198  */
1199 int CDECL _ismbbtrail(unsigned int c)
1200 {
1201   return (MSVCRT_mbctype[(c&0xff) + 1] & _M2) != 0;
1202 }
1203
1204 /*********************************************************************
1205  *              _ismbclegal(MSVCRT.@)
1206  */
1207 int CDECL _ismbclegal(unsigned int c)
1208 {
1209     return _ismbblead(HIBYTE(c)) && _ismbbtrail(LOBYTE(c));
1210 }
1211
1212 /*********************************************************************
1213  *              _ismbslead(MSVCRT.@)
1214  */
1215 int CDECL _ismbslead(const unsigned char* start, const unsigned char* str)
1216 {
1217   int lead = 0;
1218
1219   if(!g_mbcp_is_multibyte)
1220     return 0;
1221
1222   /* Lead bytes can also be trail bytes so we need to analyse the string
1223    */
1224   while (start <= str)
1225   {
1226     if (!*start)
1227       return 0;
1228     lead = !lead && _ismbblead(*start);
1229     start++;
1230   }
1231
1232   return lead ? -1 : 0;
1233 }
1234
1235 /*********************************************************************
1236  *              _ismbstrail(MSVCRT.@)
1237  */
1238 int CDECL _ismbstrail(const unsigned char* start, const unsigned char* str)
1239 {
1240   /* Note: this function doesn't check _ismbbtrail */
1241   if ((str > start) && _ismbslead(start, str-1))
1242     return -1;
1243   else
1244     return 0;
1245 }
1246
1247 /*********************************************************************
1248  *              _mbsbtype (MSVCRT.@)
1249  */
1250 int CDECL _mbsbtype(const unsigned char *str, MSVCRT_size_t count)
1251 {
1252   int lead = 0;
1253   const unsigned char *end = str + count;
1254   int mbcp = g_mbcp_is_multibyte;
1255
1256   /* Lead bytes can also be trail bytes so we need to analyse the string.
1257    * Also we must return _MBC_ILLEGAL for chars past the end of the string
1258    */
1259   while (str < end) /* Note: we skip the last byte - will check after the loop */
1260   {
1261     if (!*str)
1262       return _MBC_ILLEGAL;
1263     lead = mbcp && !lead && _ismbblead(*str);
1264     str++;
1265   }
1266
1267   if (lead)
1268     if (_ismbbtrail(*str))
1269       return _MBC_TRAIL;
1270     else
1271       return _MBC_ILLEGAL;
1272   else
1273     if (_ismbblead(*str))
1274       return _MBC_LEAD;
1275     else
1276       return _MBC_SINGLE;
1277 }
1278
1279 /*********************************************************************
1280  *              _mbsset(MSVCRT.@)
1281  */
1282 unsigned char* CDECL _mbsset(unsigned char* str, unsigned int c)
1283 {
1284   unsigned char* ret = str;
1285
1286   if(get_locale()->locinfo->mb_cur_max == 1 || c < 256)
1287     return u__strset(str, c); /* ASCII CP or SB char */
1288
1289   c &= 0xffff; /* Strip high bits */
1290
1291   while(str[0] && str[1])
1292   {
1293     *str++ = c >> 8;
1294     *str++ = c & 0xff;
1295   }
1296   if(str[0])
1297     str[0] = '\0'; /* FIXME: OK to shorten? */
1298
1299   return ret;
1300 }
1301
1302 /*********************************************************************
1303  *              _mbsnbset(MSVCRT.@)
1304  */
1305 unsigned char* CDECL _mbsnbset(unsigned char *str, unsigned int c, MSVCRT_size_t len)
1306 {
1307     unsigned char *ret = str;
1308
1309     if(!len)
1310         return ret;
1311
1312     if(get_locale()->locinfo->mb_cur_max == 1 || c < 256)
1313         return u__strnset(str, c, len); /* ASCII CP or SB char */
1314
1315     c &= 0xffff; /* Strip high bits */
1316
1317     while(str[0] && str[1] && (len > 1))
1318     {
1319         *str++ = c >> 8;
1320         len--;
1321         *str++ = c & 0xff;
1322         len--;
1323     }
1324     if(len && str[0]) {
1325         /* as per msdn pad with a blank character */
1326         str[0] = ' ';
1327     }
1328
1329     return ret;
1330 }
1331
1332 /*********************************************************************
1333  *              _mbsnset(MSVCRT.@)
1334  */
1335 unsigned char* CDECL _mbsnset(unsigned char* str, unsigned int c, MSVCRT_size_t len)
1336 {
1337   unsigned char *ret = str;
1338
1339   if(!len)
1340     return ret;
1341
1342   if(get_locale()->locinfo->mb_cur_max == 1 || c < 256)
1343     return u__strnset(str, c, len); /* ASCII CP or SB char */
1344
1345   c &= 0xffff; /* Strip high bits */
1346
1347   while(str[0] && str[1] && len--)
1348   {
1349     *str++ = c >> 8;
1350     *str++ = c & 0xff;
1351   }
1352   if(len && str[0])
1353     str[0] = '\0'; /* FIXME: OK to shorten? */
1354
1355   return ret;
1356 }
1357
1358 /*********************************************************************
1359  *              _mbsnccnt(MSVCRT.@)
1360  * 'c' is for 'character'.
1361  */
1362 MSVCRT_size_t CDECL _mbsnccnt(const unsigned char* str, MSVCRT_size_t len)
1363 {
1364   MSVCRT_size_t ret;
1365   if(get_locale()->locinfo->mb_cur_max > 1)
1366   {
1367     ret=0;
1368     while(*str && len-- > 0)
1369     {
1370       if(MSVCRT_isleadbyte(*str))
1371       {
1372         if (!len)
1373           break;
1374         len--;
1375         str++;
1376       }
1377       str++;
1378       ret++;
1379     }
1380     return ret;
1381   }
1382   ret=u_strlen(str);
1383   return min(ret, len); /* ASCII CP */
1384 }
1385
1386 /*********************************************************************
1387  *              _mbsnbcnt(MSVCRT.@)
1388  * 'b' is for byte count.
1389  */
1390 MSVCRT_size_t CDECL _mbsnbcnt(const unsigned char* str, MSVCRT_size_t len)
1391 {
1392   MSVCRT_size_t ret;
1393   if(get_locale()->locinfo->mb_cur_max > 1)
1394   {
1395     const unsigned char* xstr = str;
1396     while(*xstr && len-- > 0)
1397     {
1398       if (MSVCRT_isleadbyte(*xstr++))
1399         xstr++;
1400     }
1401     return xstr-str;
1402   }
1403   ret=u_strlen(str);
1404   return min(ret, len); /* ASCII CP */
1405 }
1406
1407 /*********************************************************************
1408  *              _mbsnbcat(MSVCRT.@)
1409  */
1410 unsigned char* CDECL _mbsnbcat(unsigned char* dst, const unsigned char* src, MSVCRT_size_t len)
1411 {
1412     if(get_locale()->locinfo->mb_cur_max > 1)
1413     {
1414         unsigned char *res = dst;
1415         while (*dst) {
1416             if (MSVCRT_isleadbyte(*dst++)) {
1417                 if (*dst) {
1418                     dst++;
1419                 } else {
1420                     /* as per msdn overwrite the lead byte in front of '\0' */
1421                     dst--;
1422                     break;
1423                 }
1424             }
1425         }
1426         while (*src && len--) *dst++ = *src++;
1427         *dst = '\0';
1428         return res;
1429     }
1430     return u_strncat(dst, src, len); /* ASCII CP */
1431 }
1432
1433
1434 /*********************************************************************
1435  *              _mbsncat(MSVCRT.@)
1436  */
1437 unsigned char* CDECL _mbsncat(unsigned char* dst, const unsigned char* src, MSVCRT_size_t len)
1438 {
1439   if(get_locale()->locinfo->mb_cur_max > 1)
1440   {
1441     unsigned char *res = dst;
1442     while (*dst)
1443     {
1444       if (MSVCRT_isleadbyte(*dst++))
1445         dst++;
1446     }
1447     while (*src && len--)
1448     {
1449       *dst++ = *src;
1450       if(MSVCRT_isleadbyte(*src++))
1451         *dst++ = *src++;
1452     }
1453     *dst = '\0';
1454     return res;
1455   }
1456   return u_strncat(dst, src, len); /* ASCII CP */
1457 }
1458
1459
1460 /*********************************************************************
1461  *              _mbslwr(MSVCRT.@)
1462  */
1463 unsigned char* CDECL _mbslwr(unsigned char* s)
1464 {
1465   unsigned char *ret = s;
1466   if (!s)
1467     return NULL;
1468   if (get_locale()->locinfo->mb_cur_max > 1)
1469   {
1470     unsigned int c;
1471     while (*s)
1472     {
1473       c = _mbctolower(_mbsnextc(s));
1474       /* Note that I assume that the size of the character is unchanged */
1475       if (c > 255)
1476       {
1477           *s++=(c>>8);
1478           c=c & 0xff;
1479       }
1480       *s++=c;
1481     }
1482   }
1483   else for ( ; *s; s++) *s = tolower(*s);
1484   return ret;
1485 }
1486
1487
1488 /*********************************************************************
1489  *              _mbsupr(MSVCRT.@)
1490  */
1491 unsigned char* CDECL _mbsupr(unsigned char* s)
1492 {
1493   unsigned char *ret = s;
1494   if (!s)
1495     return NULL;
1496   if (get_locale()->locinfo->mb_cur_max > 1)
1497   {
1498     unsigned int c;
1499     while (*s)
1500     {
1501       c = _mbctoupper(_mbsnextc(s));
1502       /* Note that I assume that the size of the character is unchanged */
1503       if (c > 255)
1504       {
1505           *s++=(c>>8);
1506           c=c & 0xff;
1507       }
1508       *s++=c;
1509     }
1510   }
1511   else for ( ; *s; s++) *s = toupper(*s);
1512   return ret;
1513 }
1514
1515
1516 /*********************************************************************
1517  *              _mbsspn (MSVCRT.@)
1518  */
1519 MSVCRT_size_t CDECL _mbsspn(const unsigned char* string, const unsigned char* set)
1520 {
1521     const unsigned char *p, *q;
1522
1523     for (p = string; *p; p++)
1524     {
1525         if (MSVCRT_isleadbyte(*p))
1526         {
1527             for (q = set; *q; q++)
1528             {
1529                 if (!q[1])
1530                     break;
1531                 if ((*p == *q) &&  (p[1] == q[1]))
1532                     break;
1533                 q++;
1534             }
1535             if (!q[0] || !q[1]) break;
1536         }
1537         else
1538         {
1539             for (q = set; *q; q++)
1540                 if (*p == *q)
1541                     break;
1542             if (!*q) break;
1543         }
1544     }
1545     return p - string;
1546 }
1547
1548 /*********************************************************************
1549  *              _mbsspnp (MSVCRT.@)
1550  */
1551 unsigned char* CDECL _mbsspnp(const unsigned char* string, const unsigned char* set)
1552 {
1553     const unsigned char *p, *q;
1554
1555     for (p = string; *p; p++)
1556     {
1557         if (MSVCRT_isleadbyte(*p))
1558         {
1559             for (q = set; *q; q++)
1560             {
1561                 if (!q[1])
1562                     break;
1563                 if ((*p == *q) &&  (p[1] == q[1]))
1564                     break;
1565                 q++;
1566             }
1567             if (!q[0] || !q[1]) break;
1568         }
1569         else
1570         {
1571             for (q = set; *q; q++)
1572                 if (*p == *q)
1573                     break;
1574             if (!*q) break;
1575         }
1576     }
1577     if (*p == '\0')
1578         return NULL;
1579     return (unsigned char *)p;
1580 }
1581
1582 /*********************************************************************
1583  *              _mbscspn(MSVCRT.@)
1584  */
1585 MSVCRT_size_t CDECL _mbscspn(const unsigned char* str, const unsigned char* cmp)
1586 {
1587   if (get_locale()->locinfo->mb_cur_max > 1)
1588     FIXME("don't handle double character case\n");
1589   return u_strcspn(str, cmp);
1590 }
1591
1592 /*********************************************************************
1593  *              _mbsrev (MSVCRT.@)
1594  */
1595 unsigned char* CDECL _mbsrev(unsigned char* str)
1596 {
1597     int i, len = _mbslen(str);
1598     unsigned char *p, *temp=MSVCRT_malloc(len*2);
1599
1600     if(!temp)
1601         return str;
1602
1603     /* unpack multibyte string to temp buffer */
1604     p=str;
1605     for(i=0; i<len; i++)
1606     {
1607         if (MSVCRT_isleadbyte(*p))
1608         {
1609             temp[i*2]=*p++;
1610             temp[i*2+1]=*p++;
1611         }
1612         else
1613         {
1614             temp[i*2]=*p++;
1615             temp[i*2+1]=0;
1616         }
1617     }
1618
1619     /* repack it in the reverse order */
1620     p=str;
1621     for(i=len-1; i>=0; i--)
1622     {
1623         if(MSVCRT_isleadbyte(temp[i*2]))
1624         {
1625             *p++=temp[i*2];
1626             *p++=temp[i*2+1];
1627         }
1628         else
1629         {
1630             *p++=temp[i*2];
1631         }
1632     }
1633
1634     MSVCRT_free(temp);
1635
1636     return str;
1637 }
1638
1639 /*********************************************************************
1640  *              _mbspbrk (MSVCRT.@)
1641  */
1642 unsigned char* CDECL _mbspbrk(const unsigned char* str, const unsigned char* accept)
1643 {
1644     const unsigned char* p;
1645
1646     while(*str)
1647     {
1648         for(p = accept; *p; p += (MSVCRT_isleadbyte(*p)?2:1) )
1649         {
1650             if (*p == *str)
1651                 if( !MSVCRT_isleadbyte(*p) || ( *(p+1) == *(str+1) ) )
1652                      return (unsigned char*)str;
1653         }
1654         str += (MSVCRT_isleadbyte(*str)?2:1);
1655     }
1656     return NULL;
1657 }
1658
1659
1660 /*
1661  * Functions depending on locale codepage
1662  */
1663
1664 /*********************************************************************
1665  *              mblen(MSVCRT.@)
1666  * REMARKS
1667  *  Unlike most of the multibyte string functions this function uses
1668  *  the locale codepage, not the codepage set by _setmbcp
1669  */
1670 int CDECL MSVCRT_mblen(const char* str, MSVCRT_size_t size)
1671 {
1672   if (str && *str && size)
1673   {
1674     if(get_locale()->locinfo->mb_cur_max == 1)
1675       return 1; /* ASCII CP */
1676
1677     return !MSVCRT_isleadbyte(*str) ? 1 : (size>1 ? 2 : -1);
1678   }
1679   return 0;
1680 }
1681
1682 /*********************************************************************
1683  *              _mbstrlen(MSVCRT.@)
1684  * REMARKS
1685  *  Unlike most of the multibyte string functions this function uses
1686  *  the locale codepage, not the codepage set by _setmbcp
1687  */
1688 MSVCRT_size_t CDECL _mbstrlen(const char* str)
1689 {
1690   if(get_locale()->locinfo->mb_cur_max > 1)
1691   {
1692     MSVCRT_size_t len = 0;
1693     while(*str)
1694     {
1695       /* FIXME: According to the documentation we are supposed to test for
1696        * multi-byte character validity. Whatever that means
1697        */
1698       str += MSVCRT_isleadbyte(*str) ? 2 : 1;
1699       len++;
1700     }
1701     return len;
1702   }
1703   return strlen(str); /* ASCII CP */
1704 }