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