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