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