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