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