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