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