dmloader: Don't claim partial success when loading fails.
[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 <stdio.h>
27
28 #include "msvcrt.h"
29 #include "wine/unicode.h"
30 #include "wine/debug.h"
31
32 WINE_DEFAULT_DEBUG_CHANNEL(msvcrt);
33
34 unsigned char MSVCRT_mbctype[257] = { 0 };
35
36 /* It seems that the data about valid trail bytes is not available from kernel32
37  * so we have to store is here. The format is the same as for lead bytes in CPINFO */
38 struct cp_extra_info_t
39 {
40     int cp;
41     BYTE TrailBytes[MAX_LEADBYTES];
42 };
43
44 static struct cp_extra_info_t g_cpextrainfo[] =
45 {
46     {932, {0x40, 0x7e, 0x80, 0xfc, 0, 0}},
47     {936, {0x40, 0xfe, 0, 0}},
48     {949, {0x41, 0xfe, 0, 0}},
49     {950, {0x40, 0x7e, 0xa1, 0xfe, 0, 0}},
50     {1361, {0x31, 0x7e, 0x81, 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 /* Maps multibyte cp932 punctuation marks to single byte equivalents */
56 static const unsigned char mbctombb_932_punct[] = {
57   0x20,0xa4,0xa1,0x2c,0x2e,0xa5,0x3a,0x3b,0x3f,0x21,0xde,0xdf,0x00,0x00,0x00,0x5e,
58   0x7e,0x5f,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xb0,0x00,0x00,0x2f,0x00,
59   0x00,0x00,0x7c,0x00,0x00,0x60,0x27,0x00,0x22,0x28,0x29,0x00,0x00,0x5b,0x5d,0x7b,
60   0x7d,0x00,0x00,0x00,0x00,0xa2,0xa3,0x00,0x00,0x00,0x00,0x2b,0x2d,0x00,0x00,0x00,
61   0x00,0x3d,0x00,0x3c,0x3e,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x5c,
62   0x24,0x00,0x00,0x25,0x23,0x26,0x2a,0x40};
63
64 /* Maps multibyte cp932 hiragana/katakana to single-byte equivalents */
65 static const unsigned char mbctombb_932_kana[] = {
66   0xa7,0xb1,0xa8,0xb2,0xa9,0xb3,0xaa,0xb4,0xab,0xb5,0xb6,0xb6,0xb7,0xb7,0xb8,0xb8,
67   0xb9,0xb9,0xba,0xba,0xbb,0xbb,0xbc,0xbc,0xbd,0xbd,0xbe,0xbe,0xbf,0xbf,0xc0,0xc0,
68   0xc1,0xc1,0xaf,0xc2,0xc2,0xc3,0xc3,0xc4,0xc4,0xc5,0xc6,0xc7,0xc8,0xc9,0xca,0xca,
69   0xca,0xcb,0xcb,0xcb,0xcc,0xcc,0xcc,0xcd,0xcd,0xcd,0xce,0xce,0xce,0xcf,0xd0,0xd1,
70   0xd2,0xd3,0xac,0xd4,0xad,0xd5,0xae,0xd6,0xd7,0xd8,0xd9,0xda,0xdb,0xdc,0xdc,0xb2,
71   0xb4,0xa6,0xdd,0xb3,0xb6,0xb9};
72
73 static MSVCRT_wchar_t msvcrt_mbc_to_wc(unsigned int ch)
74 {
75   MSVCRT_wchar_t chW;
76   char mbch[2];
77   int n_chars;
78
79   if (ch <= 0xff) {
80     mbch[0] = ch;
81     n_chars = 1;
82   } else {
83     mbch[0] = (ch >> 8) & 0xff;
84     mbch[1] = ch & 0xff;
85     n_chars = 2;
86   }
87   if (!MultiByteToWideChar(get_mbcinfo()->mbcodepage, 0, mbch, n_chars, &chW, 1))
88   {
89     WARN("MultiByteToWideChar failed on %x\n", ch);
90     return 0;
91   }
92   return chW;
93 }
94
95 static inline MSVCRT_size_t u_strlen( const unsigned char *str )
96 {
97   return strlen( (const char*) str );
98 }
99
100 static inline unsigned char* u_strncat( unsigned char* dst, const unsigned char* src, MSVCRT_size_t len )
101 {
102   return (unsigned char*)strncat( (char*)dst, (const char*)src, len);
103 }
104
105 static inline int u_strcmp( const unsigned char *s1, const unsigned char *s2 )
106 {
107   return strcmp( (const char*)s1, (const char*)s2 );
108 }
109
110 static inline int u_strcasecmp( const unsigned char *s1, const unsigned char *s2 )
111 {
112   return strcasecmp( (const char*)s1, (const char*)s2 );
113 }
114
115 static inline int u_strncmp( const unsigned char *s1, const unsigned char *s2, MSVCRT_size_t len )
116 {
117   return strncmp( (const char*)s1, (const char*)s2, len );
118 }
119
120 static inline int u_strncasecmp( const unsigned char *s1, const unsigned char *s2, MSVCRT_size_t len )
121 {
122   return strncasecmp( (const char*)s1, (const char*)s2, len );
123 }
124
125 static inline unsigned char *u_strchr( const unsigned char *s, unsigned char x )
126 {
127   return (unsigned char*) strchr( (const char*)s, x );
128 }
129
130 static inline unsigned char *u_strrchr( const unsigned char *s, unsigned char x )
131 {
132   return (unsigned char*) strrchr( (const char*)s, x );
133 }
134
135 static inline unsigned char *u_strtok( unsigned char *s, const unsigned char *delim )
136 {
137   return (unsigned char*) strtok( (char*)s, (const char*)delim );
138 }
139
140 static inline unsigned char *u__strset( unsigned char *s, unsigned char c )
141 {
142   return (unsigned char*) _strset( (char*)s, c);
143 }
144
145 static inline unsigned char *u__strnset( unsigned char *s, unsigned char c, MSVCRT_size_t len )
146 {
147   return (unsigned char*) MSVCRT__strnset( (char*)s, c, len );
148 }
149
150 static inline MSVCRT_size_t u_strcspn( const unsigned char *s, const unsigned char *rej )
151 {
152   return strcspn( (const char *)s, (const char*)rej );
153 }
154
155 /*********************************************************************
156  *              __p__mbctype (MSVCRT.@)
157  */
158 unsigned char* CDECL __p__mbctype(void)
159 {
160   return get_mbcinfo()->mbctype;
161 }
162
163 /*********************************************************************
164  *              ___mb_cur_max_func(MSVCRT.@)
165  */
166 int* CDECL MSVCRT____mb_cur_max_func(void)
167 {
168   return &get_locinfo()->mb_cur_max;
169 }
170
171 /* ___mb_cur_max_l_func - not exported in native msvcrt */
172 int* CDECL ___mb_cur_max_l_func(MSVCRT__locale_t locale)
173 {
174   MSVCRT_pthreadlocinfo locinfo;
175
176   if(!locale)
177     locinfo = get_locinfo();
178   else
179     locinfo = locale->locinfo;
180
181   return &locinfo->mb_cur_max;
182 }
183
184 /*********************************************************************
185  * INTERNAL: _setmbcp_l
186  */
187 int _setmbcp_l(int cp, LCID lcid, MSVCRT_pthreadmbcinfo mbcinfo)
188 {
189   const char format[] = ".%d";
190
191   int newcp;
192   CPINFO cpi;
193   BYTE *bytes;
194   WORD chartypes[256];
195   char bufA[256];
196   WCHAR bufW[256];
197   int charcount;
198   int ret;
199   int i;
200
201   if(!mbcinfo)
202       mbcinfo = get_mbcinfo();
203
204   switch (cp)
205   {
206     case _MB_CP_ANSI:
207       newcp = GetACP();
208       break;
209     case _MB_CP_OEM:
210       newcp = GetOEMCP();
211       break;
212     case _MB_CP_LOCALE:
213       newcp = get_locinfo()->lc_codepage;
214       if(newcp)
215           break;
216       /* fall through (C locale) */
217     case _MB_CP_SBCS:
218       newcp = 20127;   /* ASCII */
219       break;
220     default:
221       newcp = cp;
222       break;
223   }
224
225   if(lcid == -1) {
226     sprintf(bufA, format, newcp);
227     mbcinfo->mblcid = MSVCRT_locale_to_LCID(bufA);
228   } else {
229     mbcinfo->mblcid = lcid;
230   }
231
232   if(mbcinfo->mblcid == -1)
233   {
234     WARN("Can't assign LCID to codepage (%d)\n", mbcinfo->mblcid);
235     mbcinfo->mblcid = 0;
236   }
237
238   if (!GetCPInfo(newcp, &cpi))
239   {
240     WARN("Codepage %d not found\n", newcp);
241     *MSVCRT__errno() = MSVCRT_EINVAL;
242     return -1;
243   }
244
245   /* setup the _mbctype */
246   memset(mbcinfo->mbctype, 0, sizeof(unsigned char[257]));
247   memset(mbcinfo->mbcasemap, 0, sizeof(unsigned char[256]));
248
249   bytes = cpi.LeadByte;
250   while (bytes[0] || bytes[1])
251   {
252     for (i = bytes[0]; i <= bytes[1]; i++)
253       mbcinfo->mbctype[i + 1] |= _M1;
254     bytes += 2;
255   }
256
257   if (cpi.MaxCharSize > 1)
258   {
259     /* trail bytes not available through kernel32 but stored in a structure in msvcrt */
260     struct cp_extra_info_t *cpextra = g_cpextrainfo;
261
262     mbcinfo->ismbcodepage = 1;
263     while (TRUE)
264     {
265       if (cpextra->cp == 0 || cpextra->cp == newcp)
266       {
267         if (cpextra->cp == 0)
268           FIXME("trail bytes data not available for DBCS codepage %d - assuming all bytes\n", newcp);
269
270         bytes = cpextra->TrailBytes;
271         while (bytes[0] || bytes[1])
272         {
273           for (i = bytes[0]; i <= bytes[1]; i++)
274             mbcinfo->mbctype[i + 1] |= _M2;
275           bytes += 2;
276         }
277         break;
278       }
279       cpextra++;
280     }
281   }
282   else
283     mbcinfo->ismbcodepage = 0;
284
285   /* we can't use GetStringTypeA directly because we don't have a locale - only a code page
286    */
287   charcount = 0;
288   for (i = 0; i < 256; i++)
289     if (!(mbcinfo->mbctype[i + 1] & _M1))
290       bufA[charcount++] = i;
291
292   ret = MultiByteToWideChar(newcp, 0, bufA, charcount, bufW, charcount);
293   if (ret != charcount)
294     ERR("MultiByteToWideChar of chars failed for cp %d, ret=%d (exp %d), error=%d\n", newcp, ret, charcount, GetLastError());
295
296   GetStringTypeW(CT_CTYPE1, bufW, charcount, chartypes);
297
298   charcount = 0;
299   for (i = 0; i < 256; i++)
300     if (!(mbcinfo->mbctype[i + 1] & _M1))
301     {
302       if (chartypes[charcount] & C1_UPPER)
303       {
304         mbcinfo->mbctype[i + 1] |= _SBUP;
305         bufW[charcount] = tolowerW(bufW[charcount]);
306       }
307       else if (chartypes[charcount] & C1_LOWER)
308       {
309         mbcinfo->mbctype[i + 1] |= _SBLOW;
310         bufW[charcount] = toupperW(bufW[charcount]);
311       }
312       charcount++;
313     }
314
315   ret = WideCharToMultiByte(newcp, 0, bufW, charcount, bufA, charcount, NULL, NULL);
316   if (ret != charcount)
317     ERR("WideCharToMultiByte failed for cp %d, ret=%d (exp %d), error=%d\n", newcp, ret, charcount, GetLastError());
318
319   charcount = 0;
320   for (i = 0; i < 256; i++)
321   {
322     if(!(mbcinfo->mbctype[i + 1] & _M1))
323     {
324       if(mbcinfo->mbctype[i] & (C1_UPPER|C1_LOWER))
325         mbcinfo->mbcasemap[i] = bufA[charcount];
326       charcount++;
327     }
328   }
329
330   if (newcp == 932)   /* CP932 only - set _MP and _MS */
331   {
332     /* On Windows it's possible to calculate the _MP and _MS from CT_CTYPE1
333      * and CT_CTYPE3. But as of Wine 0.9.43 we return wrong values what makes
334      * it hard. As this is set only for codepage 932 we hardcode it what gives
335      * also faster execution.
336      */
337     for (i = 161; i <= 165; i++)
338       mbcinfo->mbctype[i + 1] |= _MP;
339     for (i = 166; i <= 223; i++)
340       mbcinfo->mbctype[i + 1] |= _MS;
341   }
342
343   mbcinfo->mbcodepage = newcp;
344   if(MSVCRT_locale && mbcinfo == MSVCRT_locale->mbcinfo)
345     memcpy(MSVCRT_mbctype, MSVCRT_locale->mbcinfo->mbctype, sizeof(MSVCRT_mbctype));
346
347   return 0;
348 }
349
350 /*********************************************************************
351  *              _setmbcp (MSVCRT.@)
352  */
353 int CDECL _setmbcp(int cp)
354 {
355     return _setmbcp_l(cp, -1, NULL);
356 }
357
358 /*********************************************************************
359  *              _getmbcp (MSVCRT.@)
360  */
361 int CDECL _getmbcp(void)
362 {
363   return get_mbcinfo()->mbcodepage;
364 }
365
366 /*********************************************************************
367  *              _mbsnextc(MSVCRT.@)
368  */
369 unsigned int CDECL _mbsnextc(const unsigned char* str)
370 {
371   if(_ismbblead(*str))
372     return *str << 8 | str[1];
373   return *str;
374 }
375
376 /*********************************************************************
377  *              _mbctolower(MSVCRT.@)
378  */
379 unsigned int CDECL _mbctolower(unsigned int c)
380 {
381     if (_ismbblead(c))
382     {
383       FIXME("Handle MBC chars\n");
384       return c;
385     }
386     return tolower(c); /* ASCII CP or SB char */
387 }
388
389 /*********************************************************************
390  *              _mbctoupper(MSVCRT.@)
391  */
392 unsigned int CDECL _mbctoupper(unsigned int c)
393 {
394     if (_ismbblead(c))
395     {
396       FIXME("Handle MBC chars\n");
397       return c;
398     }
399     return toupper(c); /* ASCII CP or SB char */
400 }
401
402 /*********************************************************************
403  *              _mbctombb (MSVCRT.@)
404  */
405 unsigned int CDECL _mbctombb(unsigned int c)
406 {
407     unsigned int value;
408
409     if(get_mbcinfo()->mbcodepage == 932)
410     {
411         if(c >= 0x829f && c <= 0x82f1)    /* Hiragana */
412             return mbctombb_932_kana[c - 0x829f];
413         if(c >= 0x8340 && c <= 0x8396 && c != 0x837f)    /* Katakana */
414             return mbctombb_932_kana[c - 0x8340 - (c >= 0x837f ? 1 : 0)];
415         if(c >= 0x8140 && c <= 0x8197)    /* Punctuation */
416         {
417             value = mbctombb_932_punct[c - 0x8140];
418             return value ? value : c;
419         }
420         if((c >= 0x824f && c <= 0x8258) || /* Fullwidth digits */
421            (c >= 0x8260 && c <= 0x8279))   /* Fullwidth capitals letters */
422             return c - 0x821f;
423         if(c >= 0x8281 && c <= 0x829a)     /* Fullwidth small letters */
424             return c - 0x8220;
425         /* all other cases return c */
426     }
427     return c;
428 }
429
430 /*********************************************************************
431  *              _mbcjistojms(MSVCRT.@)
432  *
433  *              Converts a jis character to sjis.
434  *              Based on description from
435  *              http://www.slayers.ne.jp/~oouchi/code/jistosjis.html
436  */
437 unsigned int CDECL _mbcjistojms(unsigned int c)
438 {
439   /* Conversion takes place only when codepage is 932.
440      In all other cases, c is returned unchanged */
441   if(get_mbcinfo()->mbcodepage == 932)
442   {
443     if(HIBYTE(c) >= 0x21 && HIBYTE(c) <= 0x7e &&
444        LOBYTE(c) >= 0x21 && LOBYTE(c) <= 0x7e)
445     {
446       if(HIBYTE(c) % 2)
447         c += 0x1f;
448       else
449         c += 0x7d;
450
451       if(LOBYTE(c) > 0x7F)
452         c += 0x1;
453
454       c = (((HIBYTE(c) - 0x21)/2 + 0x81) << 8) | LOBYTE(c);
455
456       if(HIBYTE(c) > 0x9f)
457         c += 0x4000;
458     }
459     else
460       return 0; /* Codepage is 932, but c can't be converted */
461   }
462
463   return c;
464 }
465
466 /*********************************************************************
467  *              _mbcjmstojis(MSVCRT.@)
468  *
469  *              Converts a sjis character to jis.
470  */
471 unsigned int CDECL _mbcjmstojis(unsigned int c)
472 {
473   /* Conversion takes place only when codepage is 932.
474      In all other cases, c is returned unchanged */
475   if(get_mbcinfo()->mbcodepage == 932)
476   {
477     if(_ismbclegal(c) && HIBYTE(c) < 0xf0)
478     {
479       if(HIBYTE(c) >= 0xe0)
480         c -= 0x4000;
481
482       c = (((HIBYTE(c) - 0x81)*2 + 0x21) << 8) | LOBYTE(c);
483
484       if(LOBYTE(c) > 0x7f)
485         c -= 0x1;
486
487       if(LOBYTE(c) > 0x9d)
488         c += 0x83;
489       else
490         c -= 0x1f;
491     }
492     else
493       return 0; /* Codepage is 932, but c can't be converted */
494   }
495
496   return c;
497 }
498
499 /*********************************************************************
500  *              _mbsdec(MSVCRT.@)
501  */
502 unsigned char* CDECL _mbsdec(const unsigned char* start, const unsigned char* cur)
503 {
504   if(get_mbcinfo()->ismbcodepage)
505     return (unsigned char *)(_ismbstrail(start,cur-1) ? cur - 2 : cur -1);
506
507   return (unsigned char *)cur - 1; /* ASCII CP or SB char */
508 }
509
510 /*********************************************************************
511  *              _mbclen(MSVCRT.@)
512  */
513 unsigned int CDECL _mbclen(const unsigned char* str)
514 {
515   return _ismbblead(*str) ? 2 : 1;
516 }
517
518 /*********************************************************************
519  *              _mbsinc(MSVCRT.@)
520  */
521 unsigned char* CDECL _mbsinc(const unsigned char* str)
522 {
523   return (unsigned char *)(str + _mbclen(str));
524 }
525
526 /*********************************************************************
527  *              _mbsninc(MSVCRT.@)
528  */
529 unsigned char* CDECL _mbsninc(const unsigned char* str, MSVCRT_size_t num)
530 {
531   if(!str)
532     return NULL;
533
534   while (num > 0 && *str)
535   {
536     if (_ismbblead(*str))
537     {
538       if (!*(str+1))
539          break;
540       str++;
541     }
542     str++;
543     num--;
544   }
545
546   return (unsigned char*)str;
547 }
548
549 /*********************************************************************
550  *              _mbslen(MSVCRT.@)
551  */
552 MSVCRT_size_t CDECL _mbslen(const unsigned char* str)
553 {
554   MSVCRT_size_t len = 0;
555   while(*str)
556   {
557     if (_ismbblead(*str))
558     {
559       str++;
560       if (!*str)  /* count only full chars */
561         break;
562     }
563     str++;
564     len++;
565   }
566   return len;
567 }
568
569 /*********************************************************************
570  *              _mbccpy(MSVCRT.@)
571  */
572 void CDECL _mbccpy(unsigned char* dest, const unsigned char* src)
573 {
574   *dest = *src;
575   if(_ismbblead(*src))
576     *++dest = *++src; /* MB char */
577 }
578
579 /*********************************************************************
580  *              _mbsncpy(MSVCRT.@)
581  * REMARKS
582  *  The parameter n is the number or characters to copy, not the size of
583  *  the buffer. Use _mbsnbcpy for a function analogical to strncpy
584  */
585 unsigned char* CDECL _mbsncpy(unsigned char* dst, const unsigned char* src, MSVCRT_size_t n)
586 {
587   unsigned char* ret = dst;
588   if(!n)
589     return dst;
590   if (get_mbcinfo()->ismbcodepage)
591   {
592     while (*src && n)
593     {
594       n--;
595       if (_ismbblead(*src))
596       {
597         if (!*(src+1))
598         {
599             *dst++ = 0;
600             *dst++ = 0;
601             break;
602         }
603
604         *dst++ = *src++;
605       }
606
607       *dst++ = *src++;
608     }
609   }
610   else
611   {
612     while (n)
613     {
614         n--;
615         if (!(*dst++ = *src++)) break;
616     }
617   }
618   while (n--) *dst++ = 0;
619   return ret;
620 }
621
622 /*********************************************************************
623  *              _mbsnbcpy_s(MSVCRT.@)
624  * REMARKS
625  * Unlike _mbsnbcpy this function does not pad the rest of the dest
626  * string with 0
627  */
628 int CDECL _mbsnbcpy_s(unsigned char* dst, MSVCRT_size_t size, const unsigned char* src, MSVCRT_size_t n)
629 {
630     MSVCRT_size_t pos = 0;
631
632     if(!dst || size == 0)
633         return MSVCRT_EINVAL;
634     if(!src)
635     {
636         dst[0] = '\0';
637         return MSVCRT_EINVAL;
638     }
639     if(!n)
640         return 0;
641
642     if(get_mbcinfo()->ismbcodepage)
643     {
644         int is_lead = 0;
645         while (*src && n)
646         {
647             if(pos == size)
648             {
649                 dst[0] = '\0';
650                 return MSVCRT_ERANGE;
651             }
652             is_lead = (!is_lead && _ismbblead(*src));
653             n--;
654             dst[pos++] = *src++;
655         }
656
657         if (is_lead) /* if string ends with a lead, remove it */
658             dst[pos - 1] = 0;
659     }
660     else
661     {
662         while (n)
663         {
664             n--;
665             if(pos == size)
666             {
667                 dst[0] = '\0';
668                 return MSVCRT_ERANGE;
669             }
670
671             if(!(*src)) break;
672             dst[pos++] = *src++;
673         }
674     }
675
676     if(pos < size)
677         dst[pos] = '\0';
678     else
679     {
680         dst[0] = '\0';
681         return MSVCRT_ERANGE;
682     }
683
684     return 0;
685 }
686
687 /*********************************************************************
688  *              _mbsnbcpy(MSVCRT.@)
689  * REMARKS
690  *  Like strncpy this function doesn't enforce the string to be
691  *  NUL-terminated
692  */
693 unsigned char* CDECL _mbsnbcpy(unsigned char* dst, const unsigned char* src, MSVCRT_size_t n)
694 {
695   unsigned char* ret = dst;
696   if(!n)
697     return dst;
698   if(get_mbcinfo()->ismbcodepage)
699   {
700     int is_lead = 0;
701     while (*src && n)
702     {
703       is_lead = (!is_lead && _ismbblead(*src));
704       n--;
705       *dst++ = *src++;
706     }
707
708     if (is_lead) /* if string ends with a lead, remove it */
709         *(dst - 1) = 0;
710   }
711   else
712   {
713     while (n)
714     {
715         n--;
716         if (!(*dst++ = *src++)) break;
717     }
718   }
719   while (n--) *dst++ = 0;
720   return ret;
721 }
722
723 /*********************************************************************
724  *              _mbscmp(MSVCRT.@)
725  */
726 int CDECL _mbscmp(const unsigned char* str, const unsigned char* cmp)
727 {
728   if(get_mbcinfo()->ismbcodepage)
729   {
730     unsigned int strc, cmpc;
731     do {
732       if(!*str)
733         return *cmp ? -1 : 0;
734       if(!*cmp)
735         return 1;
736       strc = _mbsnextc(str);
737       cmpc = _mbsnextc(cmp);
738       if(strc != cmpc)
739         return strc < cmpc ? -1 : 1;
740       str +=(strc > 255) ? 2 : 1;
741       cmp +=(strc > 255) ? 2 : 1; /* equal, use same increment */
742     } while(1);
743   }
744   return u_strcmp(str, cmp); /* ASCII CP */
745 }
746
747 /*********************************************************************
748  *              _mbsicoll(MSVCRT.@)
749  * FIXME: handle locales.
750  */
751 int CDECL _mbsicoll(const unsigned char* str, const unsigned char* cmp)
752 {
753   if(get_mbcinfo()->ismbcodepage)
754   {
755     unsigned int strc, cmpc;
756     do {
757       if(!*str)
758         return *cmp ? -1 : 0;
759       if(!*cmp)
760         return 1;
761       strc = _mbctolower(_mbsnextc(str));
762       cmpc = _mbctolower(_mbsnextc(cmp));
763       if(strc != cmpc)
764         return strc < cmpc ? -1 : 1;
765       str +=(strc > 255) ? 2 : 1;
766       cmp +=(strc > 255) ? 2 : 1; /* equal, use same increment */
767     } while(1);
768   }
769   return u_strcasecmp(str, cmp); /* ASCII CP */
770 }
771
772 /*********************************************************************
773  *              _mbscoll(MSVCRT.@)
774  * Performs a case-sensitive comparison according to the current code page
775  * RETURN
776  *   _NLSCMPERROR if error
777  * FIXME: handle locales.
778  */
779 int CDECL _mbscoll(const unsigned char* str, const unsigned char* cmp)
780 {
781   if(get_mbcinfo()->ismbcodepage)
782   {
783     unsigned int strc, cmpc;
784     do {
785       if(!*str)
786         return *cmp ? -1 : 0;
787       if(!*cmp)
788         return 1;
789       strc = _mbsnextc(str);
790       cmpc = _mbsnextc(cmp);
791       if(strc != cmpc)
792         return strc < cmpc ? -1 : 1;
793       str +=(strc > 255) ? 2 : 1;
794       cmp +=(strc > 255) ? 2 : 1; /* equal, use same increment */
795     } while(1);
796   }
797   return u_strcmp(str, cmp); /* ASCII CP */
798 }
799
800
801 /*********************************************************************
802  *              _mbsicmp(MSVCRT.@)
803  */
804 int CDECL _mbsicmp(const unsigned char* str, const unsigned char* cmp)
805 {
806   if(get_mbcinfo()->ismbcodepage)
807   {
808     unsigned int strc, cmpc;
809     do {
810       if(!*str)
811         return *cmp ? -1 : 0;
812       if(!*cmp)
813         return 1;
814       strc = _mbctolower(_mbsnextc(str));
815       cmpc = _mbctolower(_mbsnextc(cmp));
816       if(strc != cmpc)
817         return strc < cmpc ? -1 : 1;
818       str +=(strc > 255) ? 2 : 1;
819       cmp +=(strc > 255) ? 2 : 1; /* equal, use same increment */
820     } while(1);
821   }
822   return u_strcasecmp(str, cmp); /* ASCII CP */
823 }
824
825 /*********************************************************************
826  *              _mbsncmp(MSVCRT.@)
827  */
828 int CDECL _mbsncmp(const unsigned char* str, const unsigned char* cmp, MSVCRT_size_t len)
829 {
830   if(!len)
831     return 0;
832
833   if(get_mbcinfo()->ismbcodepage)
834   {
835     unsigned int strc, cmpc;
836     while(len--)
837     {
838       int inc;
839       if(!*str)
840         return *cmp ? -1 : 0;
841       if(!*cmp)
842         return 1;
843       strc = _mbsnextc(str);
844       cmpc = _mbsnextc(cmp);
845       if(strc != cmpc)
846         return strc < cmpc ? -1 : 1;
847       inc=(strc > 255) ? 2 : 1; /* Equal, use same increment */
848       str += inc;
849       cmp += inc;
850     }
851     return 0; /* Matched len chars */
852   }
853   return u_strncmp(str, cmp, len); /* ASCII CP */
854 }
855
856 /*********************************************************************
857  *              _mbsnbcmp(MSVCRT.@)
858  */
859 int CDECL _mbsnbcmp(const unsigned char* str, const unsigned char* cmp, MSVCRT_size_t len)
860 {
861   if (!len)
862     return 0;
863   if(get_mbcinfo()->ismbcodepage)
864   {
865     unsigned int strc, cmpc;
866     while (len)
867     {
868       int clen;
869       if(!*str)
870         return *cmp ? -1 : 0;
871       if(!*cmp)
872         return 1;
873       if (_ismbblead(*str))
874       {
875         strc=(len>=2)?_mbsnextc(str):0;
876         clen=2;
877       }
878       else
879       {
880         strc=*str;
881         clen=1;
882       }
883       if (_ismbblead(*cmp))
884         cmpc=(len>=2)?_mbsnextc(cmp):0;
885       else
886         cmpc=*str;
887       if(strc != cmpc)
888         return strc < cmpc ? -1 : 1;
889       len -= clen;
890       str += clen;
891       cmp += clen;
892     }
893     return 0; /* Matched len chars */
894   }
895   return u_strncmp(str,cmp,len);
896 }
897
898 /*********************************************************************
899  *              _mbsnicmp(MSVCRT.@)
900  *
901  * Compare two multibyte strings case insensitively to 'len' characters.
902  */
903 int CDECL _mbsnicmp(const unsigned char* str, const unsigned char* cmp, MSVCRT_size_t len)
904 {
905   /* FIXME: No tolower() for mb strings yet */
906   if(get_mbcinfo()->ismbcodepage)
907   {
908     unsigned int strc, cmpc;
909     while(len--)
910     {
911       if(!*str)
912         return *cmp ? -1 : 0;
913       if(!*cmp)
914         return 1;
915       strc = _mbctolower(_mbsnextc(str));
916       cmpc = _mbctolower(_mbsnextc(cmp));
917       if(strc != cmpc)
918         return strc < cmpc ? -1 : 1;
919       str +=(strc > 255) ? 2 : 1;
920       cmp +=(strc > 255) ? 2 : 1; /* Equal, use same increment */
921     }
922     return 0; /* Matched len chars */
923   }
924   return u_strncasecmp(str, cmp, len); /* ASCII CP */
925 }
926
927 /*********************************************************************
928  *              _mbsnbicmp(MSVCRT.@)
929  */
930 int CDECL _mbsnbicmp(const unsigned char* str, const unsigned char* cmp, MSVCRT_size_t len)
931 {
932   if (!len)
933     return 0;
934   if(get_mbcinfo()->ismbcodepage)
935   {
936     unsigned int strc, cmpc;
937     while (len)
938     {
939       int clen;
940       if(!*str)
941         return *cmp ? -1 : 0;
942       if(!*cmp)
943         return 1;
944       if (_ismbblead(*str))
945       {
946         strc=(len>=2)?_mbsnextc(str):0;
947         clen=2;
948       }
949       else
950       {
951         strc=*str;
952         clen=1;
953       }
954       if (_ismbblead(*cmp))
955         cmpc=(len>=2)?_mbsnextc(cmp):0;
956       else
957         cmpc=*str;
958       strc = _mbctolower(strc);
959       cmpc = _mbctolower(cmpc);
960       if(strc != cmpc)
961         return strc < cmpc ? -1 : 1;
962       len -= clen;
963       str += clen;
964       cmp += clen;
965     }
966     return 0; /* Matched len bytes */
967   }
968   return u_strncasecmp(str,cmp,len);
969 }
970
971 /*********************************************************************
972  *              _mbscat (MSVCRT.@)
973  */
974 unsigned char * CDECL _mbscat( unsigned char *dst, const unsigned char *src )
975 {
976     strcat( (char *)dst, (const char *)src );
977     return dst;
978 }
979
980 /*********************************************************************
981  *              _mbscpy (MSVCRT.@)
982  */
983 unsigned char* CDECL _mbscpy( unsigned char *dst, const unsigned char *src )
984 {
985     strcpy( (char *)dst, (const char *)src );
986     return dst;
987 }
988
989 /*********************************************************************
990  *              _mbsstr (MSVCRT.@)
991  */
992 unsigned char * CDECL _mbsstr(const unsigned char *haystack, const unsigned char *needle)
993 {
994     return (unsigned char *)strstr( (const char *)haystack, (const char *)needle );
995 }
996
997 /*********************************************************************
998  *              _mbschr(MSVCRT.@)
999  *
1000  * Find a multibyte character in a multibyte string.
1001  */
1002 unsigned char* CDECL _mbschr(const unsigned char* s, unsigned int x)
1003 {
1004   if(get_mbcinfo()->ismbcodepage)
1005   {
1006     unsigned int c;
1007     while (1)
1008     {
1009       c = _mbsnextc(s);
1010       if (c == x)
1011         return (unsigned char*)s;
1012       if (!c)
1013         return NULL;
1014       s += c > 255 ? 2 : 1;
1015     }
1016   }
1017   return u_strchr(s, x); /* ASCII CP */
1018 }
1019
1020 /*********************************************************************
1021  *              _mbsrchr(MSVCRT.@)
1022  */
1023 unsigned char* CDECL _mbsrchr(const unsigned char* s, unsigned int x)
1024 {
1025   if(get_mbcinfo()->ismbcodepage)
1026   {
1027     unsigned int c;
1028     unsigned char* match=NULL;
1029     if(!s)
1030       return NULL;
1031     while (1) {
1032       c = _mbsnextc(s);
1033       if (c == x)
1034         match=(unsigned char*)s;
1035       if (!c)
1036         return match;
1037       s +=(c > 255) ? 2 : 1;
1038     }
1039   }
1040   return u_strrchr(s, x);
1041 }
1042
1043 /*********************************************************************
1044  *              _mbstok(MSVCRT.@)
1045  *
1046  * Find and extract tokens from strings
1047  */
1048 unsigned char* CDECL _mbstok(unsigned char *str, const unsigned char *delim)
1049 {
1050     thread_data_t *data = msvcrt_get_thread_data();
1051     unsigned char *ret;
1052
1053     if(get_mbcinfo()->ismbcodepage)
1054     {
1055         unsigned int c;
1056
1057         if (!str)
1058             if (!(str = data->mbstok_next)) return NULL;
1059
1060         while ((c = _mbsnextc(str)) && _mbschr(delim, c)) {
1061             str += c > 255 ? 2 : 1;
1062         }
1063         if (!*str) return NULL;
1064         ret = str++;
1065         while ((c = _mbsnextc(str)) && !_mbschr(delim, c)) {
1066             str += c > 255 ? 2 : 1;
1067         }
1068         if (*str) {
1069             *str++ = 0;
1070             if (c > 255) *str++ = 0;
1071         }
1072         data->mbstok_next = str;
1073         return ret;
1074     }
1075     return u_strtok(str, delim); /* ASCII CP */
1076 }
1077
1078 /*********************************************************************
1079  *              _mbbtombc(MSVCRT.@)
1080  */
1081 unsigned int CDECL _mbbtombc(unsigned int c)
1082 {
1083   if(get_mbcinfo()->ismbcodepage &&
1084      ((c >= 0x20 && c <=0x7e) ||(c >= 0xa1 && c <= 0xdf)))
1085   {
1086     /* FIXME: I can't get this function to return anything
1087      * different from what I pass it...
1088      */
1089   }
1090   return c;  /* ASCII CP or no MB char */
1091 }
1092
1093 /*********************************************************************
1094  *              _mbbtype(MSVCRT.@)
1095  */
1096 int CDECL _mbbtype(unsigned char c, int type)
1097 {
1098     if (type == 1)
1099     {
1100         if ((c >= 0x20 && c <= 0x7e) || (c >= 0xa1 && c <= 0xdf))
1101             return _MBC_SINGLE;
1102         else if ((c >= 0x40 && c <= 0x7e) || (c >= 0x80 && c <= 0xfc))
1103             return _MBC_TRAIL;
1104         else
1105             return _MBC_ILLEGAL;
1106     }
1107     else
1108     {
1109         if ((c >= 0x20 && c <= 0x7e) || (c >= 0xa1 && c <= 0xdf))
1110             return _MBC_SINGLE;
1111         else if ((c >= 0x81 && c <= 0x9f) || (c >= 0xe0 && c <= 0xfc))
1112             return _MBC_LEAD;
1113         else
1114             return _MBC_ILLEGAL;
1115     }
1116 }
1117
1118 /*********************************************************************
1119  *              _ismbbkana(MSVCRT.@)
1120  */
1121 int CDECL _ismbbkana(unsigned int c)
1122 {
1123   /* FIXME: use lc_ctype when supported, not lc_all */
1124   if(get_mbcinfo()->mbcodepage == 932)
1125   {
1126     /* Japanese/Katakana, CP 932 */
1127     return (c >= 0xa1 && c <= 0xdf);
1128   }
1129   return 0;
1130 }
1131
1132 /*********************************************************************
1133  *              _ismbcdigit(MSVCRT.@)
1134  */
1135 int CDECL _ismbcdigit(unsigned int ch)
1136 {
1137     MSVCRT_wchar_t wch = msvcrt_mbc_to_wc( ch );
1138     return (get_char_typeW( wch ) & C1_DIGIT);
1139 }
1140
1141 /*********************************************************************
1142  *              _ismbcgraph(MSVCRT.@)
1143  */
1144 int CDECL _ismbcgraph(unsigned int ch)
1145 {
1146     MSVCRT_wchar_t wch = msvcrt_mbc_to_wc( ch );
1147     return (get_char_typeW( wch ) & (C1_UPPER | C1_LOWER | C1_DIGIT | C1_PUNCT | C1_ALPHA));
1148 }
1149
1150 /*********************************************************************
1151  *              _ismbcalpha (MSVCRT.@)
1152  */
1153 int CDECL _ismbcalpha(unsigned int ch)
1154 {
1155     MSVCRT_wchar_t wch = msvcrt_mbc_to_wc( ch );
1156     return (get_char_typeW( wch ) & C1_ALPHA);
1157 }
1158
1159 /*********************************************************************
1160  *              _ismbclower (MSVCRT.@)
1161  */
1162 int CDECL _ismbclower(unsigned int ch)
1163 {
1164     MSVCRT_wchar_t wch = msvcrt_mbc_to_wc( ch );
1165     return (get_char_typeW( wch ) & C1_UPPER);
1166 }
1167
1168 /*********************************************************************
1169  *              _ismbcupper (MSVCRT.@)
1170  */
1171 int CDECL _ismbcupper(unsigned int ch)
1172 {
1173     MSVCRT_wchar_t wch = msvcrt_mbc_to_wc( ch );
1174     return (get_char_typeW( wch ) & C1_LOWER);
1175 }
1176
1177 /*********************************************************************
1178  *              _ismbcsymbol(MSVCRT.@)
1179  */
1180 int CDECL _ismbcsymbol(unsigned int ch)
1181 {
1182     MSVCRT_wchar_t wch = msvcrt_mbc_to_wc( ch );
1183     WORD ctype;
1184     if (!GetStringTypeW(CT_CTYPE3, &wch, 1, &ctype))
1185     {
1186         WARN("GetStringTypeW failed on %x\n", ch);
1187         return 0;
1188     }
1189     return ((ctype & C3_SYMBOL) != 0);
1190 }
1191
1192 /*********************************************************************
1193  *              _ismbcalnum (MSVCRT.@)
1194  */
1195 int CDECL _ismbcalnum(unsigned int ch)
1196 {
1197     MSVCRT_wchar_t wch = msvcrt_mbc_to_wc( ch );
1198     return (get_char_typeW( wch ) & (C1_ALPHA | C1_DIGIT));
1199 }
1200
1201 /*********************************************************************
1202  *              _ismbcspace (MSVCRT.@)
1203  */
1204 int CDECL _ismbcspace(unsigned int ch)
1205 {
1206     MSVCRT_wchar_t wch = msvcrt_mbc_to_wc( ch );
1207     return (get_char_typeW( wch ) & C1_SPACE);
1208 }
1209
1210 /*********************************************************************
1211  *              _ismbcprint (MSVCRT.@)
1212  */
1213 int CDECL _ismbcprint(unsigned int ch)
1214 {
1215     MSVCRT_wchar_t wch = msvcrt_mbc_to_wc( ch );
1216     return (get_char_typeW( wch ) & (C1_UPPER | C1_LOWER | C1_DIGIT | C1_PUNCT | C1_ALPHA | C1_SPACE));
1217 }
1218
1219 /*********************************************************************
1220  *              _ismbcpunct(MSVCRT.@)
1221  */
1222 int CDECL _ismbcpunct(unsigned int ch)
1223 {
1224     MSVCRT_wchar_t wch = msvcrt_mbc_to_wc( ch );
1225     return (get_char_typeW( wch ) & C1_PUNCT);
1226 }
1227
1228 /*********************************************************************
1229  *              _ismbchira(MSVCRT.@)
1230  */
1231 int CDECL _ismbchira(unsigned int c)
1232 {
1233   /* FIXME: use lc_ctype when supported, not lc_all */
1234   if(get_mbcinfo()->mbcodepage == 932)
1235   {
1236     /* Japanese/Hiragana, CP 932 */
1237     return (c >= 0x829f && c <= 0x82f1);
1238   }
1239   return 0;
1240 }
1241
1242 /*********************************************************************
1243  *              _ismbckata(MSVCRT.@)
1244  */
1245 int CDECL _ismbckata(unsigned int c)
1246 {
1247   /* FIXME: use lc_ctype when supported, not lc_all */
1248   if(get_mbcinfo()->mbcodepage == 932)
1249   {
1250     if(c < 256)
1251       return _ismbbkana(c);
1252     /* Japanese/Katakana, CP 932 */
1253     return (c >= 0x8340 && c <= 0x8396 && c != 0x837f);
1254   }
1255   return 0;
1256 }
1257
1258 /*********************************************************************
1259  *              _ismbblead(MSVCRT.@)
1260  */
1261 int CDECL _ismbblead(unsigned int c)
1262 {
1263   return (get_mbcinfo()->mbctype[(c&0xff) + 1] & _M1) != 0;
1264 }
1265
1266
1267 /*********************************************************************
1268  *              _ismbbtrail(MSVCRT.@)
1269  */
1270 int CDECL _ismbbtrail(unsigned int c)
1271 {
1272   return (get_mbcinfo()->mbctype[(c&0xff) + 1] & _M2) != 0;
1273 }
1274
1275 /*********************************************************************
1276  *              _ismbclegal(MSVCRT.@)
1277  */
1278 int CDECL _ismbclegal(unsigned int c)
1279 {
1280     return _ismbblead(HIBYTE(c)) && _ismbbtrail(LOBYTE(c));
1281 }
1282
1283 /*********************************************************************
1284  *              _ismbslead(MSVCRT.@)
1285  */
1286 int CDECL _ismbslead(const unsigned char* start, const unsigned char* str)
1287 {
1288   int lead = 0;
1289
1290   if(!get_mbcinfo()->ismbcodepage)
1291     return 0;
1292
1293   /* Lead bytes can also be trail bytes so we need to analyse the string
1294    */
1295   while (start <= str)
1296   {
1297     if (!*start)
1298       return 0;
1299     lead = !lead && _ismbblead(*start);
1300     start++;
1301   }
1302
1303   return lead ? -1 : 0;
1304 }
1305
1306 /*********************************************************************
1307  *              _ismbstrail(MSVCRT.@)
1308  */
1309 int CDECL _ismbstrail(const unsigned char* start, const unsigned char* str)
1310 {
1311   /* Note: this function doesn't check _ismbbtrail */
1312   if ((str > start) && _ismbslead(start, str-1))
1313     return -1;
1314   else
1315     return 0;
1316 }
1317
1318 /*********************************************************************
1319  *              _mbsbtype (MSVCRT.@)
1320  */
1321 int CDECL _mbsbtype(const unsigned char *str, MSVCRT_size_t count)
1322 {
1323   int lead = 0;
1324   const unsigned char *end = str + count;
1325
1326   /* Lead bytes can also be trail bytes so we need to analyse the string.
1327    * Also we must return _MBC_ILLEGAL for chars past the end of the string
1328    */
1329   while (str < end) /* Note: we skip the last byte - will check after the loop */
1330   {
1331     if (!*str)
1332       return _MBC_ILLEGAL;
1333     lead = get_mbcinfo()->ismbcodepage && !lead && _ismbblead(*str);
1334     str++;
1335   }
1336
1337   if (lead)
1338     if (_ismbbtrail(*str))
1339       return _MBC_TRAIL;
1340     else
1341       return _MBC_ILLEGAL;
1342   else
1343     if (_ismbblead(*str))
1344       return _MBC_LEAD;
1345     else
1346       return _MBC_SINGLE;
1347 }
1348
1349 /*********************************************************************
1350  *              _mbsset(MSVCRT.@)
1351  */
1352 unsigned char* CDECL _mbsset(unsigned char* str, unsigned int c)
1353 {
1354   unsigned char* ret = str;
1355
1356   if(!get_mbcinfo()->ismbcodepage || c < 256)
1357     return u__strset(str, c); /* ASCII CP or SB char */
1358
1359   c &= 0xffff; /* Strip high bits */
1360
1361   while(str[0] && str[1])
1362   {
1363     *str++ = c >> 8;
1364     *str++ = c & 0xff;
1365   }
1366   if(str[0])
1367     str[0] = '\0'; /* FIXME: OK to shorten? */
1368
1369   return ret;
1370 }
1371
1372 /*********************************************************************
1373  *              _mbsnbset(MSVCRT.@)
1374  */
1375 unsigned char* CDECL _mbsnbset(unsigned char *str, unsigned int c, MSVCRT_size_t len)
1376 {
1377     unsigned char *ret = str;
1378
1379     if(!len)
1380         return ret;
1381
1382     if(!get_mbcinfo()->ismbcodepage || c < 256)
1383         return u__strnset(str, c, len); /* ASCII CP or SB char */
1384
1385     c &= 0xffff; /* Strip high bits */
1386
1387     while(str[0] && str[1] && (len > 1))
1388     {
1389         *str++ = c >> 8;
1390         len--;
1391         *str++ = c & 0xff;
1392         len--;
1393     }
1394     if(len && str[0]) {
1395         /* as per msdn pad with a blank character */
1396         str[0] = ' ';
1397     }
1398
1399     return ret;
1400 }
1401
1402 /*********************************************************************
1403  *              _mbsnset(MSVCRT.@)
1404  */
1405 unsigned char* CDECL _mbsnset(unsigned char* str, unsigned int c, MSVCRT_size_t len)
1406 {
1407   unsigned char *ret = str;
1408
1409   if(!len)
1410     return ret;
1411
1412   if(!get_mbcinfo()->ismbcodepage || c < 256)
1413     return u__strnset(str, c, len); /* ASCII CP or SB char */
1414
1415   c &= 0xffff; /* Strip high bits */
1416
1417   while(str[0] && str[1] && len--)
1418   {
1419     *str++ = c >> 8;
1420     *str++ = c & 0xff;
1421   }
1422   if(len && str[0])
1423     str[0] = '\0'; /* FIXME: OK to shorten? */
1424
1425   return ret;
1426 }
1427
1428 /*********************************************************************
1429  *              _mbsnccnt(MSVCRT.@)
1430  * 'c' is for 'character'.
1431  */
1432 MSVCRT_size_t CDECL _mbsnccnt(const unsigned char* str, MSVCRT_size_t len)
1433 {
1434   MSVCRT_size_t ret;
1435   if(get_mbcinfo()->ismbcodepage)
1436   {
1437     ret=0;
1438     while(*str && len-- > 0)
1439     {
1440       if(_ismbblead(*str))
1441       {
1442         if (!len)
1443           break;
1444         len--;
1445         str++;
1446       }
1447       str++;
1448       ret++;
1449     }
1450     return ret;
1451   }
1452   ret=u_strlen(str);
1453   return min(ret, len); /* ASCII CP */
1454 }
1455
1456 /*********************************************************************
1457  *              _mbsnbcnt(MSVCRT.@)
1458  * 'b' is for byte count.
1459  */
1460 MSVCRT_size_t CDECL _mbsnbcnt(const unsigned char* str, MSVCRT_size_t len)
1461 {
1462   MSVCRT_size_t ret;
1463   if(get_mbcinfo()->ismbcodepage)
1464   {
1465     const unsigned char* xstr = str;
1466     while(*xstr && len-- > 0)
1467     {
1468       if (_ismbblead(*xstr++))
1469         xstr++;
1470     }
1471     return xstr-str;
1472   }
1473   ret=u_strlen(str);
1474   return min(ret, len); /* ASCII CP */
1475 }
1476
1477 /*********************************************************************
1478  *              _mbsnbcat(MSVCRT.@)
1479  */
1480 unsigned char* CDECL _mbsnbcat(unsigned char* dst, const unsigned char* src, MSVCRT_size_t len)
1481 {
1482     if(get_mbcinfo()->ismbcodepage)
1483     {
1484         unsigned char *res = dst;
1485         while (*dst) {
1486             if (_ismbblead(*dst++)) {
1487                 if (*dst) {
1488                     dst++;
1489                 } else {
1490                     /* as per msdn overwrite the lead byte in front of '\0' */
1491                     dst--;
1492                     break;
1493                 }
1494             }
1495         }
1496         while (*src && len--) *dst++ = *src++;
1497         *dst = '\0';
1498         return res;
1499     }
1500     return u_strncat(dst, src, len); /* ASCII CP */
1501 }
1502
1503 int CDECL _mbsnbcat_s(unsigned char *dst, MSVCRT_size_t size, const unsigned char *src, MSVCRT_size_t len)
1504 {
1505     unsigned char *ptr = dst;
1506     MSVCRT_size_t i;
1507
1508     if (!dst && !size && !src && !len)
1509         return 0;
1510
1511     if (!dst || !size || !src)
1512     {
1513         if (dst && size)
1514             *dst = '\0';
1515
1516         *MSVCRT__errno() = MSVCRT_EINVAL;
1517         return MSVCRT_EINVAL;
1518     }
1519
1520     /* Find the null terminator of the destination buffer. */
1521     while (size && *ptr)
1522         size--, ptr++;
1523
1524     if (!size)
1525     {
1526         *dst = '\0';
1527         *MSVCRT__errno() = MSVCRT_EINVAL;
1528         return MSVCRT_EINVAL;
1529     }
1530
1531     /* If necessary, check that the character preceding the null terminator is
1532      * a lead byte and move the pointer back by one for later overwrite. */
1533     if (ptr != dst && get_mbcinfo()->ismbcodepage && _ismbblead(*(ptr - 1)))
1534         size++, ptr--;
1535
1536     for (i = 0; *src && i < len; i++)
1537     {
1538         *ptr++ = *src++;
1539         size--;
1540
1541         if (!size)
1542         {
1543             *dst = '\0';
1544             *MSVCRT__errno() = MSVCRT_ERANGE;
1545             return MSVCRT_ERANGE;
1546         }
1547     }
1548
1549     *ptr = '\0';
1550     return 0;
1551 }
1552
1553 /*********************************************************************
1554  *              _mbsncat(MSVCRT.@)
1555  */
1556 unsigned char* CDECL _mbsncat(unsigned char* dst, const unsigned char* src, MSVCRT_size_t len)
1557 {
1558   if(get_mbcinfo()->ismbcodepage)
1559   {
1560     unsigned char *res = dst;
1561     while (*dst)
1562     {
1563       if (_ismbblead(*dst++))
1564         dst++;
1565     }
1566     while (*src && len--)
1567     {
1568       *dst++ = *src;
1569       if(_ismbblead(*src++))
1570         *dst++ = *src++;
1571     }
1572     *dst = '\0';
1573     return res;
1574   }
1575   return u_strncat(dst, src, len); /* ASCII CP */
1576 }
1577
1578
1579 /*********************************************************************
1580  *              _mbslwr(MSVCRT.@)
1581  */
1582 unsigned char* CDECL _mbslwr(unsigned char* s)
1583 {
1584   unsigned char *ret = s;
1585   if (!s)
1586     return NULL;
1587   if (get_mbcinfo()->ismbcodepage)
1588   {
1589     unsigned int c;
1590     while (*s)
1591     {
1592       c = _mbctolower(_mbsnextc(s));
1593       /* Note that I assume that the size of the character is unchanged */
1594       if (c > 255)
1595       {
1596           *s++=(c>>8);
1597           c=c & 0xff;
1598       }
1599       *s++=c;
1600     }
1601   }
1602   else for ( ; *s; s++) *s = tolower(*s);
1603   return ret;
1604 }
1605
1606
1607 /*********************************************************************
1608  *              _mbslwr_s(MSVCRT.@)
1609  */
1610 int CDECL _mbslwr_s(unsigned char* s, MSVCRT_size_t len)
1611 {
1612   if (!s && !len)
1613   {
1614     return 0;
1615   }
1616   else if (!s || !len)
1617   {
1618     *MSVCRT__errno() = MSVCRT_EINVAL;
1619     return MSVCRT_EINVAL;
1620   }
1621   if (get_mbcinfo()->ismbcodepage)
1622   {
1623     unsigned int c;
1624     for ( ; *s && len > 0; len--)
1625     {
1626       c = _mbctolower(_mbsnextc(s));
1627       /* Note that I assume that the size of the character is unchanged */
1628       if (c > 255)
1629       {
1630           *s++=(c>>8);
1631           c=c & 0xff;
1632       }
1633       *s++=c;
1634     }
1635   }
1636   else for ( ; *s && len > 0; s++, len--) *s = tolower(*s);
1637   if (*s)
1638   {
1639     *s = '\0';
1640     *MSVCRT__errno() = MSVCRT_EINVAL;
1641     return MSVCRT_EINVAL;
1642   }
1643   return 0;
1644 }
1645
1646
1647 /*********************************************************************
1648  *              _mbsupr(MSVCRT.@)
1649  */
1650 unsigned char* CDECL _mbsupr(unsigned char* s)
1651 {
1652   unsigned char *ret = s;
1653   if (!s)
1654     return NULL;
1655   if (get_mbcinfo()->ismbcodepage)
1656   {
1657     unsigned int c;
1658     while (*s)
1659     {
1660       c = _mbctoupper(_mbsnextc(s));
1661       /* Note that I assume that the size of the character is unchanged */
1662       if (c > 255)
1663       {
1664           *s++=(c>>8);
1665           c=c & 0xff;
1666       }
1667       *s++=c;
1668     }
1669   }
1670   else for ( ; *s; s++) *s = toupper(*s);
1671   return ret;
1672 }
1673
1674
1675 /*********************************************************************
1676  *              _mbsupr_s(MSVCRT.@)
1677  */
1678 int CDECL _mbsupr_s(unsigned char* s, MSVCRT_size_t len)
1679 {
1680   if (!s && !len)
1681   {
1682     return 0;
1683   }
1684   else if (!s || !len)
1685   {
1686     *MSVCRT__errno() = MSVCRT_EINVAL;
1687     return MSVCRT_EINVAL;
1688   }
1689   if (get_mbcinfo()->ismbcodepage)
1690   {
1691     unsigned int c;
1692     for ( ; *s && len > 0; len--)
1693     {
1694       c = _mbctoupper(_mbsnextc(s));
1695       /* Note that I assume that the size of the character is unchanged */
1696       if (c > 255)
1697       {
1698           *s++=(c>>8);
1699           c=c & 0xff;
1700       }
1701       *s++=c;
1702     }
1703   }
1704   else for ( ; *s && len > 0; s++, len--) *s = toupper(*s);
1705   if (*s)
1706   {
1707     *s = '\0';
1708     *MSVCRT__errno() = MSVCRT_EINVAL;
1709     return MSVCRT_EINVAL;
1710   }
1711   return 0;
1712 }
1713
1714
1715 /*********************************************************************
1716  *              _mbsspn (MSVCRT.@)
1717  */
1718 MSVCRT_size_t CDECL _mbsspn(const unsigned char* string, const unsigned char* set)
1719 {
1720     const unsigned char *p, *q;
1721
1722     for (p = string; *p; p++)
1723     {
1724         if (_ismbblead(*p))
1725         {
1726             for (q = set; *q; q++)
1727             {
1728                 if (!q[1])
1729                     break;
1730                 if ((*p == *q) &&  (p[1] == q[1]))
1731                     break;
1732                 q++;
1733             }
1734             if (!q[0] || !q[1]) break;
1735         }
1736         else
1737         {
1738             for (q = set; *q; q++)
1739                 if (*p == *q)
1740                     break;
1741             if (!*q) break;
1742         }
1743     }
1744     return p - string;
1745 }
1746
1747 /*********************************************************************
1748  *              _mbsspnp (MSVCRT.@)
1749  */
1750 unsigned char* CDECL _mbsspnp(const unsigned char* string, const unsigned char* set)
1751 {
1752     const unsigned char *p, *q;
1753
1754     for (p = string; *p; p++)
1755     {
1756         if (_ismbblead(*p))
1757         {
1758             for (q = set; *q; q++)
1759             {
1760                 if (!q[1])
1761                     break;
1762                 if ((*p == *q) &&  (p[1] == q[1]))
1763                     break;
1764                 q++;
1765             }
1766             if (!q[0] || !q[1]) break;
1767         }
1768         else
1769         {
1770             for (q = set; *q; q++)
1771                 if (*p == *q)
1772                     break;
1773             if (!*q) break;
1774         }
1775     }
1776     if (*p == '\0')
1777         return NULL;
1778     return (unsigned char *)p;
1779 }
1780
1781 /*********************************************************************
1782  *              _mbscspn(MSVCRT.@)
1783  */
1784 MSVCRT_size_t CDECL _mbscspn(const unsigned char* str, const unsigned char* cmp)
1785 {
1786   if (get_mbcinfo()->ismbcodepage)
1787     FIXME("don't handle double character case\n");
1788   return u_strcspn(str, cmp);
1789 }
1790
1791 /*********************************************************************
1792  *              _mbsrev (MSVCRT.@)
1793  */
1794 unsigned char* CDECL _mbsrev(unsigned char* str)
1795 {
1796     int i, len = _mbslen(str);
1797     unsigned char *p, *temp=MSVCRT_malloc(len*2);
1798
1799     if(!temp)
1800         return str;
1801
1802     /* unpack multibyte string to temp buffer */
1803     p=str;
1804     for(i=0; i<len; i++)
1805     {
1806         if (_ismbblead(*p))
1807         {
1808             temp[i*2]=*p++;
1809             temp[i*2+1]=*p++;
1810         }
1811         else
1812         {
1813             temp[i*2]=*p++;
1814             temp[i*2+1]=0;
1815         }
1816     }
1817
1818     /* repack it in the reverse order */
1819     p=str;
1820     for(i=len-1; i>=0; i--)
1821     {
1822         if(_ismbblead(temp[i*2]))
1823         {
1824             *p++=temp[i*2];
1825             *p++=temp[i*2+1];
1826         }
1827         else
1828         {
1829             *p++=temp[i*2];
1830         }
1831     }
1832
1833     MSVCRT_free(temp);
1834
1835     return str;
1836 }
1837
1838 /*********************************************************************
1839  *              _mbspbrk (MSVCRT.@)
1840  */
1841 unsigned char* CDECL _mbspbrk(const unsigned char* str, const unsigned char* accept)
1842 {
1843     const unsigned char* p;
1844
1845     while(*str)
1846     {
1847         for(p = accept; *p; p += (_ismbblead(*p)?2:1) )
1848         {
1849             if (*p == *str)
1850                 if( !_ismbblead(*p) || ( *(p+1) == *(str+1) ) )
1851                      return (unsigned char*)str;
1852         }
1853         str += (_ismbblead(*str)?2:1);
1854     }
1855     return NULL;
1856 }
1857
1858
1859 /*
1860  * Functions depending on locale codepage
1861  */
1862
1863 /*********************************************************************
1864  *              mblen(MSVCRT.@)
1865  * REMARKS
1866  *  Unlike most of the multibyte string functions this function uses
1867  *  the locale codepage, not the codepage set by _setmbcp
1868  */
1869 int CDECL MSVCRT_mblen(const char* str, MSVCRT_size_t size)
1870 {
1871   if (str && *str && size)
1872   {
1873     if(get_locinfo()->mb_cur_max == 1)
1874       return 1; /* ASCII CP */
1875
1876     return !MSVCRT_isleadbyte(*str) ? 1 : (size>1 ? 2 : -1);
1877   }
1878   return 0;
1879 }
1880
1881 /*********************************************************************
1882  *              _mbstrlen_l(MSVCRT.@)
1883  */
1884 MSVCRT_size_t CDECL _mbstrlen_l(const char* str, MSVCRT__locale_t locale)
1885 {
1886     MSVCRT_pthreadlocinfo locinfo;
1887
1888     if(!locale)
1889         locinfo = get_locinfo();
1890     else
1891         locinfo = locale->locinfo;
1892
1893     if(locinfo->mb_cur_max > 1) {
1894         MSVCRT_size_t len;
1895         len = MultiByteToWideChar(locinfo->lc_codepage, MB_ERR_INVALID_CHARS,
1896                                   str, -1, NULL, 0);
1897         if (!len) {
1898             *MSVCRT__errno() = MSVCRT_EILSEQ;
1899             return -1;
1900         }
1901         return len - 1;
1902     }
1903
1904     return strlen(str);
1905 }
1906
1907 /*********************************************************************
1908  *              _mbstrlen(MSVCRT.@)
1909  */
1910 MSVCRT_size_t CDECL _mbstrlen(const char* str)
1911 {
1912     return _mbstrlen_l(str, NULL);
1913 }
1914
1915 /*********************************************************************
1916  *              _mbtowc_l(MSVCRT.@)
1917  */
1918 int CDECL MSVCRT_mbtowc_l(MSVCRT_wchar_t *dst, const char* str, MSVCRT_size_t n, MSVCRT__locale_t locale)
1919 {
1920     MSVCRT_pthreadlocinfo locinfo;
1921     MSVCRT_wchar_t tmpdst = '\0';
1922
1923     if(!locale)
1924         locinfo = get_locinfo();
1925     else
1926         locinfo = locale->locinfo;
1927
1928     if(n <= 0 || !str)
1929         return 0;
1930     if(!MultiByteToWideChar(locinfo->lc_codepage, 0, str, n, &tmpdst, 1))
1931         return -1;
1932     if(dst)
1933         *dst = tmpdst;
1934     /* return the number of bytes from src that have been used */
1935     if(!*str)
1936         return 0;
1937     if(n >= 2 && MSVCRT__isleadbyte_l(*str, locale) && str[1])
1938         return 2;
1939     return 1;
1940 }
1941
1942 /*********************************************************************
1943  *              mbtowc(MSVCRT.@)
1944  */
1945 int CDECL MSVCRT_mbtowc(MSVCRT_wchar_t *dst, const char* str, MSVCRT_size_t n)
1946 {
1947     return MSVCRT_mbtowc_l(dst, str, n, NULL);
1948 }
1949
1950 /*********************************************************************
1951  *              _mbstowcs_l(MSVCRT.@)
1952  */
1953 MSVCRT_size_t CDECL MSVCRT__mbstowcs_l(MSVCRT_wchar_t *wcstr, const char *mbstr,
1954         MSVCRT_size_t count, MSVCRT__locale_t locale)
1955 {
1956     MSVCRT_pthreadlocinfo locinfo;
1957     MSVCRT_size_t i, size;
1958
1959     if(!locale)
1960         locinfo = get_locinfo();
1961     else
1962         locinfo = locale->locinfo;
1963
1964     /* Ignore count parameter */
1965     if(!wcstr)
1966         return MultiByteToWideChar(locinfo->lc_codepage, 0, mbstr, -1, NULL, 0)-1;
1967
1968     for(i=0, size=0; i<count; i++) {
1969         if(mbstr[size] == '\0')
1970             break;
1971
1972         size += (MSVCRT__isleadbyte_l(mbstr[size], locale) ? 2 : 1);
1973     }
1974
1975     size = MultiByteToWideChar(locinfo->lc_codepage, 0,
1976             mbstr, size, wcstr, count);
1977
1978     if(size<count && wcstr)
1979         wcstr[size] = '\0';
1980
1981     return size;
1982 }
1983
1984 /*********************************************************************
1985  *              mbstowcs(MSVCRT.@)
1986  */
1987 MSVCRT_size_t CDECL MSVCRT_mbstowcs(MSVCRT_wchar_t *wcstr,
1988         const char *mbstr, MSVCRT_size_t count)
1989 {
1990     return MSVCRT__mbstowcs_l(wcstr, mbstr, count, NULL);
1991 }
1992
1993 /*********************************************************************
1994  *              _mbstowcs_s_l(MSVCRT.@)
1995  */
1996 int CDECL MSVCRT__mbstowcs_s_l(MSVCRT_size_t *ret, MSVCRT_wchar_t *wcstr,
1997         MSVCRT_size_t size, const char *mbstr,
1998         MSVCRT_size_t count, MSVCRT__locale_t locale)
1999 {
2000     MSVCRT_size_t conv;
2001
2002     if(!wcstr && !size) {
2003         conv = MSVCRT__mbstowcs_l(NULL, mbstr, 0, locale);
2004         if(ret)
2005             *ret = conv+1;
2006         return 0;
2007     }
2008
2009     if(!MSVCRT_CHECK_PMT(mbstr != NULL) || !MSVCRT_CHECK_PMT(wcstr != NULL)) {
2010         if(wcstr && size)
2011             wcstr[0] = '\0';
2012         *MSVCRT__errno() = MSVCRT_EINVAL;
2013         return MSVCRT_EINVAL;
2014     }
2015
2016     if(count==MSVCRT__TRUNCATE || size<count)
2017         conv = size;
2018     else
2019         conv = count;
2020
2021     conv = MSVCRT__mbstowcs_l(wcstr, mbstr, conv, locale);
2022     if(conv<size)
2023         wcstr[conv++] = '\0';
2024     else if(conv==size && (count==MSVCRT__TRUNCATE || wcstr[conv-1]=='\0'))
2025         wcstr[conv-1] = '\0';
2026     else {
2027         MSVCRT_INVALID_PMT("wcstr[size] is too small");
2028         if(size)
2029             wcstr[0] = '\0';
2030         *MSVCRT__errno() = MSVCRT_ERANGE;
2031         return MSVCRT_ERANGE;
2032     }
2033
2034     if(ret)
2035         *ret = conv;
2036     return 0;
2037 }
2038
2039 /*********************************************************************
2040  *              mbstowcs_s(MSVCRT.@)
2041  */
2042 int CDECL MSVCRT__mbstowcs_s(MSVCRT_size_t *ret, MSVCRT_wchar_t *wcstr,
2043         MSVCRT_size_t size, const char *mbstr, MSVCRT_size_t count)
2044 {
2045     return MSVCRT__mbstowcs_s_l(ret, wcstr, size, mbstr, count, NULL);
2046 }