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