msvcrt: Use given locale info in _mbtowcs_l.
[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  *              _mbsdec(MSVCRT.@)
468  */
469 unsigned char* CDECL _mbsdec(const unsigned char* start, const unsigned char* cur)
470 {
471   if(get_mbcinfo()->ismbcodepage)
472     return (unsigned char *)(_ismbstrail(start,cur-1) ? cur - 2 : cur -1);
473
474   return (unsigned char *)cur - 1; /* ASCII CP or SB char */
475 }
476
477 /*********************************************************************
478  *              _mbclen(MSVCRT.@)
479  */
480 unsigned int CDECL _mbclen(const unsigned char* str)
481 {
482   return _ismbblead(*str) ? 2 : 1;
483 }
484
485 /*********************************************************************
486  *              _mbsinc(MSVCRT.@)
487  */
488 unsigned char* CDECL _mbsinc(const unsigned char* str)
489 {
490   return (unsigned char *)(str + _mbclen(str));
491 }
492
493 /*********************************************************************
494  *              _mbsninc(MSVCRT.@)
495  */
496 unsigned char* CDECL _mbsninc(const unsigned char* str, MSVCRT_size_t num)
497 {
498   if(!str)
499     return NULL;
500
501   while (num > 0 && *str)
502   {
503     if (_ismbblead(*str))
504     {
505       if (!*(str+1))
506          break;
507       str++;
508     }
509     str++;
510     num--;
511   }
512
513   return (unsigned char*)str;
514 }
515
516 /*********************************************************************
517  *              _mbslen(MSVCRT.@)
518  */
519 MSVCRT_size_t CDECL _mbslen(const unsigned char* str)
520 {
521   MSVCRT_size_t len = 0;
522   while(*str)
523   {
524     if (_ismbblead(*str))
525     {
526       str++;
527       if (!*str)  /* count only full chars */
528         break;
529     }
530     str++;
531     len++;
532   }
533   return len;
534 }
535
536 /*********************************************************************
537  *              _mbccpy(MSVCRT.@)
538  */
539 void CDECL _mbccpy(unsigned char* dest, const unsigned char* src)
540 {
541   *dest = *src;
542   if(_ismbblead(*src))
543     *++dest = *++src; /* MB char */
544 }
545
546 /*********************************************************************
547  *              _mbsncpy(MSVCRT.@)
548  * REMARKS
549  *  The parameter n is the number or characters to copy, not the size of
550  *  the buffer. Use _mbsnbcpy for a function analogical to strncpy
551  */
552 unsigned char* CDECL _mbsncpy(unsigned char* dst, const unsigned char* src, MSVCRT_size_t n)
553 {
554   unsigned char* ret = dst;
555   if(!n)
556     return dst;
557   if (get_mbcinfo()->ismbcodepage)
558   {
559     while (*src && n)
560     {
561       n--;
562       if (_ismbblead(*src))
563       {
564         if (!*(src+1))
565         {
566             *dst++ = 0;
567             *dst++ = 0;
568             break;
569         }
570
571         *dst++ = *src++;
572       }
573
574       *dst++ = *src++;
575     }
576   }
577   else
578   {
579     while (n)
580     {
581         n--;
582         if (!(*dst++ = *src++)) break;
583     }
584   }
585   while (n--) *dst++ = 0;
586   return ret;
587 }
588
589 /*********************************************************************
590  *              _mbsnbcpy_s(MSVCRT.@)
591  * REMARKS
592  * Unlike _mbsnbcpy this function does not pad the rest of the dest
593  * string with 0
594  */
595 int CDECL _mbsnbcpy_s(unsigned char* dst, MSVCRT_size_t size, const unsigned char* src, MSVCRT_size_t n)
596 {
597     MSVCRT_size_t pos = 0;
598
599     if(!dst || size == 0)
600         return MSVCRT_EINVAL;
601     if(!src)
602     {
603         dst[0] = '\0';
604         return MSVCRT_EINVAL;
605     }
606     if(!n)
607         return 0;
608
609     if(get_mbcinfo()->ismbcodepage)
610     {
611         int is_lead = 0;
612         while (*src && n)
613         {
614             if(pos == size)
615             {
616                 dst[0] = '\0';
617                 return MSVCRT_ERANGE;
618             }
619             is_lead = (!is_lead && _ismbblead(*src));
620             n--;
621             dst[pos++] = *src++;
622         }
623
624         if (is_lead) /* if string ends with a lead, remove it */
625             dst[pos - 1] = 0;
626     }
627     else
628     {
629         while (n)
630         {
631             n--;
632             if(pos == size)
633             {
634                 dst[0] = '\0';
635                 return MSVCRT_ERANGE;
636             }
637
638             if(!(*src)) break;
639             dst[pos++] = *src++;
640         }
641     }
642
643     if(pos < size)
644         dst[pos] = '\0';
645     else
646     {
647         dst[0] = '\0';
648         return MSVCRT_ERANGE;
649     }
650
651     return 0;
652 }
653
654 /*********************************************************************
655  *              _mbsnbcpy(MSVCRT.@)
656  * REMARKS
657  *  Like strncpy this function doesn't enforce the string to be
658  *  NUL-terminated
659  */
660 unsigned char* CDECL _mbsnbcpy(unsigned char* dst, const unsigned char* src, MSVCRT_size_t n)
661 {
662   unsigned char* ret = dst;
663   if(!n)
664     return dst;
665   if(get_mbcinfo()->ismbcodepage)
666   {
667     int is_lead = 0;
668     while (*src && n)
669     {
670       is_lead = (!is_lead && _ismbblead(*src));
671       n--;
672       *dst++ = *src++;
673     }
674
675     if (is_lead) /* if string ends with a lead, remove it */
676         *(dst - 1) = 0;
677   }
678   else
679   {
680     while (n)
681     {
682         n--;
683         if (!(*dst++ = *src++)) break;
684     }
685   }
686   while (n--) *dst++ = 0;
687   return ret;
688 }
689
690 /*********************************************************************
691  *              _mbscmp(MSVCRT.@)
692  */
693 int CDECL _mbscmp(const unsigned char* str, const unsigned char* cmp)
694 {
695   if(get_mbcinfo()->ismbcodepage)
696   {
697     unsigned int strc, cmpc;
698     do {
699       if(!*str)
700         return *cmp ? -1 : 0;
701       if(!*cmp)
702         return 1;
703       strc = _mbsnextc(str);
704       cmpc = _mbsnextc(cmp);
705       if(strc != cmpc)
706         return strc < cmpc ? -1 : 1;
707       str +=(strc > 255) ? 2 : 1;
708       cmp +=(strc > 255) ? 2 : 1; /* equal, use same increment */
709     } while(1);
710   }
711   return u_strcmp(str, cmp); /* ASCII CP */
712 }
713
714 /*********************************************************************
715  *              _mbsicoll(MSVCRT.@)
716  * FIXME: handle locales.
717  */
718 int CDECL _mbsicoll(const unsigned char* str, const unsigned char* cmp)
719 {
720   if(get_mbcinfo()->ismbcodepage)
721   {
722     unsigned int strc, cmpc;
723     do {
724       if(!*str)
725         return *cmp ? -1 : 0;
726       if(!*cmp)
727         return 1;
728       strc = _mbctolower(_mbsnextc(str));
729       cmpc = _mbctolower(_mbsnextc(cmp));
730       if(strc != cmpc)
731         return strc < cmpc ? -1 : 1;
732       str +=(strc > 255) ? 2 : 1;
733       cmp +=(strc > 255) ? 2 : 1; /* equal, use same increment */
734     } while(1);
735   }
736   return u_strcasecmp(str, cmp); /* ASCII CP */
737 }
738
739 /*********************************************************************
740  *              _mbscoll(MSVCRT.@)
741  * Performs a case-sensitive comparison according to the current code page
742  * RETURN
743  *   _NLSCMPERROR if error
744  * FIXME: handle locales.
745  */
746 int CDECL _mbscoll(const unsigned char* str, const unsigned char* cmp)
747 {
748   if(get_mbcinfo()->ismbcodepage)
749   {
750     unsigned int strc, cmpc;
751     do {
752       if(!*str)
753         return *cmp ? -1 : 0;
754       if(!*cmp)
755         return 1;
756       strc = _mbsnextc(str);
757       cmpc = _mbsnextc(cmp);
758       if(strc != cmpc)
759         return strc < cmpc ? -1 : 1;
760       str +=(strc > 255) ? 2 : 1;
761       cmp +=(strc > 255) ? 2 : 1; /* equal, use same increment */
762     } while(1);
763   }
764   return u_strcmp(str, cmp); /* ASCII CP */
765 }
766
767
768 /*********************************************************************
769  *              _mbsicmp(MSVCRT.@)
770  */
771 int CDECL _mbsicmp(const unsigned char* str, const unsigned char* cmp)
772 {
773   if(get_mbcinfo()->ismbcodepage)
774   {
775     unsigned int strc, cmpc;
776     do {
777       if(!*str)
778         return *cmp ? -1 : 0;
779       if(!*cmp)
780         return 1;
781       strc = _mbctolower(_mbsnextc(str));
782       cmpc = _mbctolower(_mbsnextc(cmp));
783       if(strc != cmpc)
784         return strc < cmpc ? -1 : 1;
785       str +=(strc > 255) ? 2 : 1;
786       cmp +=(strc > 255) ? 2 : 1; /* equal, use same increment */
787     } while(1);
788   }
789   return u_strcasecmp(str, cmp); /* ASCII CP */
790 }
791
792 /*********************************************************************
793  *              _mbsncmp(MSVCRT.@)
794  */
795 int CDECL _mbsncmp(const unsigned char* str, const unsigned char* cmp, MSVCRT_size_t len)
796 {
797   if(!len)
798     return 0;
799
800   if(get_mbcinfo()->ismbcodepage)
801   {
802     unsigned int strc, cmpc;
803     while(len--)
804     {
805       int inc;
806       if(!*str)
807         return *cmp ? -1 : 0;
808       if(!*cmp)
809         return 1;
810       strc = _mbsnextc(str);
811       cmpc = _mbsnextc(cmp);
812       if(strc != cmpc)
813         return strc < cmpc ? -1 : 1;
814       inc=(strc > 255) ? 2 : 1; /* Equal, use same increment */
815       str += inc;
816       cmp += inc;
817     }
818     return 0; /* Matched len chars */
819   }
820   return u_strncmp(str, cmp, len); /* ASCII CP */
821 }
822
823 /*********************************************************************
824  *              _mbsnbcmp(MSVCRT.@)
825  */
826 int CDECL _mbsnbcmp(const unsigned char* str, const unsigned char* cmp, MSVCRT_size_t len)
827 {
828   if (!len)
829     return 0;
830   if(get_mbcinfo()->ismbcodepage)
831   {
832     unsigned int strc, cmpc;
833     while (len)
834     {
835       int clen;
836       if(!*str)
837         return *cmp ? -1 : 0;
838       if(!*cmp)
839         return 1;
840       if (_ismbblead(*str))
841       {
842         strc=(len>=2)?_mbsnextc(str):0;
843         clen=2;
844       }
845       else
846       {
847         strc=*str;
848         clen=1;
849       }
850       if (_ismbblead(*cmp))
851         cmpc=(len>=2)?_mbsnextc(cmp):0;
852       else
853         cmpc=*str;
854       if(strc != cmpc)
855         return strc < cmpc ? -1 : 1;
856       len -= clen;
857       str += clen;
858       cmp += clen;
859     }
860     return 0; /* Matched len chars */
861   }
862   return u_strncmp(str,cmp,len);
863 }
864
865 /*********************************************************************
866  *              _mbsnicmp(MSVCRT.@)
867  *
868  * Compare two multibyte strings case insensitively to 'len' characters.
869  */
870 int CDECL _mbsnicmp(const unsigned char* str, const unsigned char* cmp, MSVCRT_size_t len)
871 {
872   /* FIXME: No tolower() for mb strings yet */
873   if(get_mbcinfo()->ismbcodepage)
874   {
875     unsigned int strc, cmpc;
876     while(len--)
877     {
878       if(!*str)
879         return *cmp ? -1 : 0;
880       if(!*cmp)
881         return 1;
882       strc = _mbctolower(_mbsnextc(str));
883       cmpc = _mbctolower(_mbsnextc(cmp));
884       if(strc != cmpc)
885         return strc < cmpc ? -1 : 1;
886       str +=(strc > 255) ? 2 : 1;
887       cmp +=(strc > 255) ? 2 : 1; /* Equal, use same increment */
888     }
889     return 0; /* Matched len chars */
890   }
891   return u_strncasecmp(str, cmp, len); /* ASCII CP */
892 }
893
894 /*********************************************************************
895  *              _mbsnbicmp(MSVCRT.@)
896  */
897 int CDECL _mbsnbicmp(const unsigned char* str, const unsigned char* cmp, MSVCRT_size_t len)
898 {
899   if (!len)
900     return 0;
901   if(get_mbcinfo()->ismbcodepage)
902   {
903     unsigned int strc, cmpc;
904     while (len)
905     {
906       int clen;
907       if(!*str)
908         return *cmp ? -1 : 0;
909       if(!*cmp)
910         return 1;
911       if (_ismbblead(*str))
912       {
913         strc=(len>=2)?_mbsnextc(str):0;
914         clen=2;
915       }
916       else
917       {
918         strc=*str;
919         clen=1;
920       }
921       if (_ismbblead(*cmp))
922         cmpc=(len>=2)?_mbsnextc(cmp):0;
923       else
924         cmpc=*str;
925       strc = _mbctolower(strc);
926       cmpc = _mbctolower(cmpc);
927       if(strc != cmpc)
928         return strc < cmpc ? -1 : 1;
929       len -= clen;
930       str += clen;
931       cmp += clen;
932     }
933     return 0; /* Matched len bytes */
934   }
935   return u_strncasecmp(str,cmp,len);
936 }
937
938 /*********************************************************************
939  *              _mbscat (MSVCRT.@)
940  */
941 unsigned char * CDECL _mbscat( unsigned char *dst, const unsigned char *src )
942 {
943     strcat( (char *)dst, (const char *)src );
944     return dst;
945 }
946
947 /*********************************************************************
948  *              _mbscpy (MSVCRT.@)
949  */
950 unsigned char* CDECL _mbscpy( unsigned char *dst, const unsigned char *src )
951 {
952     strcpy( (char *)dst, (const char *)src );
953     return dst;
954 }
955
956 /*********************************************************************
957  *              _mbsstr (MSVCRT.@)
958  */
959 unsigned char * CDECL _mbsstr(const unsigned char *haystack, const unsigned char *needle)
960 {
961     return (unsigned char *)strstr( (const char *)haystack, (const char *)needle );
962 }
963
964 /*********************************************************************
965  *              _mbschr(MSVCRT.@)
966  *
967  * Find a multibyte character in a multibyte string.
968  */
969 unsigned char* CDECL _mbschr(const unsigned char* s, unsigned int x)
970 {
971   if(get_mbcinfo()->ismbcodepage)
972   {
973     unsigned int c;
974     while (1)
975     {
976       c = _mbsnextc(s);
977       if (c == x)
978         return (unsigned char*)s;
979       if (!c)
980         return NULL;
981       s += c > 255 ? 2 : 1;
982     }
983   }
984   return u_strchr(s, x); /* ASCII CP */
985 }
986
987 /*********************************************************************
988  *              _mbsrchr(MSVCRT.@)
989  */
990 unsigned char* CDECL _mbsrchr(const unsigned char* s, unsigned int x)
991 {
992   if(get_mbcinfo()->ismbcodepage)
993   {
994     unsigned int c;
995     unsigned char* match=NULL;
996     if(!s)
997       return NULL;
998     while (1) {
999       c = _mbsnextc(s);
1000       if (c == x)
1001         match=(unsigned char*)s;
1002       if (!c)
1003         return match;
1004       s +=(c > 255) ? 2 : 1;
1005     }
1006   }
1007   return u_strrchr(s, x);
1008 }
1009
1010 /*********************************************************************
1011  *              _mbstok(MSVCRT.@)
1012  *
1013  * Find and extract tokens from strings
1014  */
1015 unsigned char* CDECL _mbstok(unsigned char *str, const unsigned char *delim)
1016 {
1017     thread_data_t *data = msvcrt_get_thread_data();
1018     unsigned char *ret;
1019
1020     if(get_mbcinfo()->ismbcodepage)
1021     {
1022         unsigned int c;
1023
1024         if (!str)
1025             if (!(str = data->mbstok_next)) return NULL;
1026
1027         while ((c = _mbsnextc(str)) && _mbschr(delim, c)) {
1028             str += c > 255 ? 2 : 1;
1029         }
1030         if (!*str) return NULL;
1031         ret = str++;
1032         while ((c = _mbsnextc(str)) && !_mbschr(delim, c)) {
1033             str += c > 255 ? 2 : 1;
1034         }
1035         if (*str) {
1036             *str++ = 0;
1037             if (c > 255) *str++ = 0;
1038         }
1039         data->mbstok_next = str;
1040         return ret;
1041     }
1042     return u_strtok(str, delim); /* ASCII CP */
1043 }
1044
1045 /*********************************************************************
1046  *              _mbbtombc(MSVCRT.@)
1047  */
1048 unsigned int CDECL _mbbtombc(unsigned int c)
1049 {
1050   if(get_mbcinfo()->ismbcodepage &&
1051      ((c >= 0x20 && c <=0x7e) ||(c >= 0xa1 && c <= 0xdf)))
1052   {
1053     /* FIXME: I can't get this function to return anything
1054      * different from what I pass it...
1055      */
1056   }
1057   return c;  /* ASCII CP or no MB char */
1058 }
1059
1060 /*********************************************************************
1061  *              _mbbtype(MSVCRT.@)
1062  */
1063 int CDECL _mbbtype(unsigned char c, int type)
1064 {
1065     if (type == 1)
1066     {
1067         if ((c >= 0x20 && c <= 0x7e) || (c >= 0xa1 && c <= 0xdf))
1068             return _MBC_SINGLE;
1069         else if ((c >= 0x40 && c <= 0x7e) || (c >= 0x80 && c <= 0xfc))
1070             return _MBC_TRAIL;
1071         else
1072             return _MBC_ILLEGAL;
1073     }
1074     else
1075     {
1076         if ((c >= 0x20 && c <= 0x7e) || (c >= 0xa1 && c <= 0xdf))
1077             return _MBC_SINGLE;
1078         else if ((c >= 0x81 && c <= 0x9f) || (c >= 0xe0 && c <= 0xfc))
1079             return _MBC_LEAD;
1080         else
1081             return _MBC_ILLEGAL;
1082     }
1083 }
1084
1085 /*********************************************************************
1086  *              _ismbbkana(MSVCRT.@)
1087  */
1088 int CDECL _ismbbkana(unsigned int c)
1089 {
1090   /* FIXME: use lc_ctype when supported, not lc_all */
1091   if(get_mbcinfo()->mbcodepage == 932)
1092   {
1093     /* Japanese/Katakana, CP 932 */
1094     return (c >= 0xa1 && c <= 0xdf);
1095   }
1096   return 0;
1097 }
1098
1099 /*********************************************************************
1100  *              _ismbcdigit(MSVCRT.@)
1101  */
1102 int CDECL _ismbcdigit(unsigned int ch)
1103 {
1104     MSVCRT_wchar_t wch = msvcrt_mbc_to_wc( ch );
1105     return (get_char_typeW( wch ) & C1_DIGIT);
1106 }
1107
1108 /*********************************************************************
1109  *              _ismbcgraph(MSVCRT.@)
1110  */
1111 int CDECL _ismbcgraph(unsigned int ch)
1112 {
1113     MSVCRT_wchar_t wch = msvcrt_mbc_to_wc( ch );
1114     return (get_char_typeW( wch ) & (C1_UPPER | C1_LOWER | C1_DIGIT | C1_PUNCT | C1_ALPHA));
1115 }
1116
1117 /*********************************************************************
1118  *              _ismbcalpha (MSVCRT.@)
1119  */
1120 int CDECL _ismbcalpha(unsigned int ch)
1121 {
1122     MSVCRT_wchar_t wch = msvcrt_mbc_to_wc( ch );
1123     return (get_char_typeW( wch ) & C1_ALPHA);
1124 }
1125
1126 /*********************************************************************
1127  *              _ismbclower (MSVCRT.@)
1128  */
1129 int CDECL _ismbclower(unsigned int ch)
1130 {
1131     MSVCRT_wchar_t wch = msvcrt_mbc_to_wc( ch );
1132     return (get_char_typeW( wch ) & C1_UPPER);
1133 }
1134
1135 /*********************************************************************
1136  *              _ismbcupper (MSVCRT.@)
1137  */
1138 int CDECL _ismbcupper(unsigned int ch)
1139 {
1140     MSVCRT_wchar_t wch = msvcrt_mbc_to_wc( ch );
1141     return (get_char_typeW( wch ) & C1_LOWER);
1142 }
1143
1144 /*********************************************************************
1145  *              _ismbcsymbol(MSVCRT.@)
1146  */
1147 int CDECL _ismbcsymbol(unsigned int ch)
1148 {
1149     MSVCRT_wchar_t wch = msvcrt_mbc_to_wc( ch );
1150     WORD ctype;
1151     if (!GetStringTypeW(CT_CTYPE3, &wch, 1, &ctype))
1152     {
1153         WARN("GetStringTypeW failed on %x\n", ch);
1154         return 0;
1155     }
1156     return ((ctype & C3_SYMBOL) != 0);
1157 }
1158
1159 /*********************************************************************
1160  *              _ismbcalnum (MSVCRT.@)
1161  */
1162 int CDECL _ismbcalnum(unsigned int ch)
1163 {
1164     MSVCRT_wchar_t wch = msvcrt_mbc_to_wc( ch );
1165     return (get_char_typeW( wch ) & (C1_ALPHA | C1_DIGIT));
1166 }
1167
1168 /*********************************************************************
1169  *              _ismbcspace (MSVCRT.@)
1170  */
1171 int CDECL _ismbcspace(unsigned int ch)
1172 {
1173     MSVCRT_wchar_t wch = msvcrt_mbc_to_wc( ch );
1174     return (get_char_typeW( wch ) & C1_SPACE);
1175 }
1176
1177 /*********************************************************************
1178  *              _ismbcprint (MSVCRT.@)
1179  */
1180 int CDECL _ismbcprint(unsigned int ch)
1181 {
1182     MSVCRT_wchar_t wch = msvcrt_mbc_to_wc( ch );
1183     return (get_char_typeW( wch ) & (C1_UPPER | C1_LOWER | C1_DIGIT | C1_PUNCT | C1_ALPHA | C1_SPACE));
1184 }
1185
1186 /*********************************************************************
1187  *              _ismbcpunct(MSVCRT.@)
1188  */
1189 int CDECL _ismbcpunct(unsigned int ch)
1190 {
1191     MSVCRT_wchar_t wch = msvcrt_mbc_to_wc( ch );
1192     return (get_char_typeW( wch ) & C1_PUNCT);
1193 }
1194
1195 /*********************************************************************
1196  *              _ismbchira(MSVCRT.@)
1197  */
1198 int CDECL _ismbchira(unsigned int c)
1199 {
1200   /* FIXME: use lc_ctype when supported, not lc_all */
1201   if(get_mbcinfo()->mbcodepage == 932)
1202   {
1203     /* Japanese/Hiragana, CP 932 */
1204     return (c >= 0x829f && c <= 0x82f1);
1205   }
1206   return 0;
1207 }
1208
1209 /*********************************************************************
1210  *              _ismbckata(MSVCRT.@)
1211  */
1212 int CDECL _ismbckata(unsigned int c)
1213 {
1214   /* FIXME: use lc_ctype when supported, not lc_all */
1215   if(get_mbcinfo()->mbcodepage == 932)
1216   {
1217     if(c < 256)
1218       return _ismbbkana(c);
1219     /* Japanese/Katakana, CP 932 */
1220     return (c >= 0x8340 && c <= 0x8396 && c != 0x837f);
1221   }
1222   return 0;
1223 }
1224
1225 /*********************************************************************
1226  *              _ismbblead(MSVCRT.@)
1227  */
1228 int CDECL _ismbblead(unsigned int c)
1229 {
1230   return (get_mbcinfo()->mbctype[(c&0xff) + 1] & _M1) != 0;
1231 }
1232
1233
1234 /*********************************************************************
1235  *              _ismbbtrail(MSVCRT.@)
1236  */
1237 int CDECL _ismbbtrail(unsigned int c)
1238 {
1239   return (get_mbcinfo()->mbctype[(c&0xff) + 1] & _M2) != 0;
1240 }
1241
1242 /*********************************************************************
1243  *              _ismbclegal(MSVCRT.@)
1244  */
1245 int CDECL _ismbclegal(unsigned int c)
1246 {
1247     return _ismbblead(HIBYTE(c)) && _ismbbtrail(LOBYTE(c));
1248 }
1249
1250 /*********************************************************************
1251  *              _ismbslead(MSVCRT.@)
1252  */
1253 int CDECL _ismbslead(const unsigned char* start, const unsigned char* str)
1254 {
1255   int lead = 0;
1256
1257   if(!get_mbcinfo()->ismbcodepage)
1258     return 0;
1259
1260   /* Lead bytes can also be trail bytes so we need to analyse the string
1261    */
1262   while (start <= str)
1263   {
1264     if (!*start)
1265       return 0;
1266     lead = !lead && _ismbblead(*start);
1267     start++;
1268   }
1269
1270   return lead ? -1 : 0;
1271 }
1272
1273 /*********************************************************************
1274  *              _ismbstrail(MSVCRT.@)
1275  */
1276 int CDECL _ismbstrail(const unsigned char* start, const unsigned char* str)
1277 {
1278   /* Note: this function doesn't check _ismbbtrail */
1279   if ((str > start) && _ismbslead(start, str-1))
1280     return -1;
1281   else
1282     return 0;
1283 }
1284
1285 /*********************************************************************
1286  *              _mbsbtype (MSVCRT.@)
1287  */
1288 int CDECL _mbsbtype(const unsigned char *str, MSVCRT_size_t count)
1289 {
1290   int lead = 0;
1291   const unsigned char *end = str + count;
1292
1293   /* Lead bytes can also be trail bytes so we need to analyse the string.
1294    * Also we must return _MBC_ILLEGAL for chars past the end of the string
1295    */
1296   while (str < end) /* Note: we skip the last byte - will check after the loop */
1297   {
1298     if (!*str)
1299       return _MBC_ILLEGAL;
1300     lead = get_mbcinfo()->ismbcodepage && !lead && _ismbblead(*str);
1301     str++;
1302   }
1303
1304   if (lead)
1305     if (_ismbbtrail(*str))
1306       return _MBC_TRAIL;
1307     else
1308       return _MBC_ILLEGAL;
1309   else
1310     if (_ismbblead(*str))
1311       return _MBC_LEAD;
1312     else
1313       return _MBC_SINGLE;
1314 }
1315
1316 /*********************************************************************
1317  *              _mbsset(MSVCRT.@)
1318  */
1319 unsigned char* CDECL _mbsset(unsigned char* str, unsigned int c)
1320 {
1321   unsigned char* ret = str;
1322
1323   if(!get_mbcinfo()->ismbcodepage || c < 256)
1324     return u__strset(str, c); /* ASCII CP or SB char */
1325
1326   c &= 0xffff; /* Strip high bits */
1327
1328   while(str[0] && str[1])
1329   {
1330     *str++ = c >> 8;
1331     *str++ = c & 0xff;
1332   }
1333   if(str[0])
1334     str[0] = '\0'; /* FIXME: OK to shorten? */
1335
1336   return ret;
1337 }
1338
1339 /*********************************************************************
1340  *              _mbsnbset(MSVCRT.@)
1341  */
1342 unsigned char* CDECL _mbsnbset(unsigned char *str, unsigned int c, MSVCRT_size_t len)
1343 {
1344     unsigned char *ret = str;
1345
1346     if(!len)
1347         return ret;
1348
1349     if(!get_mbcinfo()->ismbcodepage || c < 256)
1350         return u__strnset(str, c, len); /* ASCII CP or SB char */
1351
1352     c &= 0xffff; /* Strip high bits */
1353
1354     while(str[0] && str[1] && (len > 1))
1355     {
1356         *str++ = c >> 8;
1357         len--;
1358         *str++ = c & 0xff;
1359         len--;
1360     }
1361     if(len && str[0]) {
1362         /* as per msdn pad with a blank character */
1363         str[0] = ' ';
1364     }
1365
1366     return ret;
1367 }
1368
1369 /*********************************************************************
1370  *              _mbsnset(MSVCRT.@)
1371  */
1372 unsigned char* CDECL _mbsnset(unsigned char* str, unsigned int c, MSVCRT_size_t len)
1373 {
1374   unsigned char *ret = str;
1375
1376   if(!len)
1377     return ret;
1378
1379   if(!get_mbcinfo()->ismbcodepage || c < 256)
1380     return u__strnset(str, c, len); /* ASCII CP or SB char */
1381
1382   c &= 0xffff; /* Strip high bits */
1383
1384   while(str[0] && str[1] && len--)
1385   {
1386     *str++ = c >> 8;
1387     *str++ = c & 0xff;
1388   }
1389   if(len && str[0])
1390     str[0] = '\0'; /* FIXME: OK to shorten? */
1391
1392   return ret;
1393 }
1394
1395 /*********************************************************************
1396  *              _mbsnccnt(MSVCRT.@)
1397  * 'c' is for 'character'.
1398  */
1399 MSVCRT_size_t CDECL _mbsnccnt(const unsigned char* str, MSVCRT_size_t len)
1400 {
1401   MSVCRT_size_t ret;
1402   if(get_mbcinfo()->ismbcodepage)
1403   {
1404     ret=0;
1405     while(*str && len-- > 0)
1406     {
1407       if(_ismbblead(*str))
1408       {
1409         if (!len)
1410           break;
1411         len--;
1412         str++;
1413       }
1414       str++;
1415       ret++;
1416     }
1417     return ret;
1418   }
1419   ret=u_strlen(str);
1420   return min(ret, len); /* ASCII CP */
1421 }
1422
1423 /*********************************************************************
1424  *              _mbsnbcnt(MSVCRT.@)
1425  * 'b' is for byte count.
1426  */
1427 MSVCRT_size_t CDECL _mbsnbcnt(const unsigned char* str, MSVCRT_size_t len)
1428 {
1429   MSVCRT_size_t ret;
1430   if(get_mbcinfo()->ismbcodepage)
1431   {
1432     const unsigned char* xstr = str;
1433     while(*xstr && len-- > 0)
1434     {
1435       if (_ismbblead(*xstr++))
1436         xstr++;
1437     }
1438     return xstr-str;
1439   }
1440   ret=u_strlen(str);
1441   return min(ret, len); /* ASCII CP */
1442 }
1443
1444 /*********************************************************************
1445  *              _mbsnbcat(MSVCRT.@)
1446  */
1447 unsigned char* CDECL _mbsnbcat(unsigned char* dst, const unsigned char* src, MSVCRT_size_t len)
1448 {
1449     if(get_mbcinfo()->ismbcodepage)
1450     {
1451         unsigned char *res = dst;
1452         while (*dst) {
1453             if (_ismbblead(*dst++)) {
1454                 if (*dst) {
1455                     dst++;
1456                 } else {
1457                     /* as per msdn overwrite the lead byte in front of '\0' */
1458                     dst--;
1459                     break;
1460                 }
1461             }
1462         }
1463         while (*src && len--) *dst++ = *src++;
1464         *dst = '\0';
1465         return res;
1466     }
1467     return u_strncat(dst, src, len); /* ASCII CP */
1468 }
1469
1470 int CDECL _mbsnbcat_s(unsigned char *dst, MSVCRT_size_t size, const unsigned char *src, MSVCRT_size_t len)
1471 {
1472     unsigned char *ptr = dst;
1473     MSVCRT_size_t i;
1474
1475     if (!dst && !size && !src && !len)
1476         return 0;
1477
1478     if (!dst || !size || !src)
1479     {
1480         if (dst && size)
1481             *dst = '\0';
1482
1483         *MSVCRT__errno() = MSVCRT_EINVAL;
1484         return MSVCRT_EINVAL;
1485     }
1486
1487     /* Find the null terminator of the destination buffer. */
1488     while (size && *ptr)
1489         size--, ptr++;
1490
1491     if (!size)
1492     {
1493         *dst = '\0';
1494         *MSVCRT__errno() = MSVCRT_EINVAL;
1495         return MSVCRT_EINVAL;
1496     }
1497
1498     /* If necessary, check that the character preceding the null terminator is
1499      * a lead byte and move the pointer back by one for later overwrite. */
1500     if (ptr != dst && get_mbcinfo()->ismbcodepage && _ismbblead(*(ptr - 1)))
1501         size++, ptr--;
1502
1503     for (i = 0; *src && i < len; i++)
1504     {
1505         *ptr++ = *src++;
1506         size--;
1507
1508         if (!size)
1509         {
1510             *dst = '\0';
1511             *MSVCRT__errno() = MSVCRT_ERANGE;
1512             return MSVCRT_ERANGE;
1513         }
1514     }
1515
1516     *ptr = '\0';
1517     return 0;
1518 }
1519
1520 /*********************************************************************
1521  *              _mbsncat(MSVCRT.@)
1522  */
1523 unsigned char* CDECL _mbsncat(unsigned char* dst, const unsigned char* src, MSVCRT_size_t len)
1524 {
1525   if(get_mbcinfo()->ismbcodepage)
1526   {
1527     unsigned char *res = dst;
1528     while (*dst)
1529     {
1530       if (_ismbblead(*dst++))
1531         dst++;
1532     }
1533     while (*src && len--)
1534     {
1535       *dst++ = *src;
1536       if(_ismbblead(*src++))
1537         *dst++ = *src++;
1538     }
1539     *dst = '\0';
1540     return res;
1541   }
1542   return u_strncat(dst, src, len); /* ASCII CP */
1543 }
1544
1545
1546 /*********************************************************************
1547  *              _mbslwr(MSVCRT.@)
1548  */
1549 unsigned char* CDECL _mbslwr(unsigned char* s)
1550 {
1551   unsigned char *ret = s;
1552   if (!s)
1553     return NULL;
1554   if (get_mbcinfo()->ismbcodepage)
1555   {
1556     unsigned int c;
1557     while (*s)
1558     {
1559       c = _mbctolower(_mbsnextc(s));
1560       /* Note that I assume that the size of the character is unchanged */
1561       if (c > 255)
1562       {
1563           *s++=(c>>8);
1564           c=c & 0xff;
1565       }
1566       *s++=c;
1567     }
1568   }
1569   else for ( ; *s; s++) *s = tolower(*s);
1570   return ret;
1571 }
1572
1573
1574 /*********************************************************************
1575  *              _mbslwr_s(MSVCRT.@)
1576  */
1577 int CDECL _mbslwr_s(unsigned char* s, MSVCRT_size_t len)
1578 {
1579   if (!s && !len)
1580   {
1581     return 0;
1582   }
1583   else if (!s || !len)
1584   {
1585     *MSVCRT__errno() = MSVCRT_EINVAL;
1586     return MSVCRT_EINVAL;
1587   }
1588   if (get_mbcinfo()->ismbcodepage)
1589   {
1590     unsigned int c;
1591     for ( ; *s && len > 0; len--)
1592     {
1593       c = _mbctolower(_mbsnextc(s));
1594       /* Note that I assume that the size of the character is unchanged */
1595       if (c > 255)
1596       {
1597           *s++=(c>>8);
1598           c=c & 0xff;
1599       }
1600       *s++=c;
1601     }
1602   }
1603   else for ( ; *s && len > 0; s++, len--) *s = tolower(*s);
1604   if (*s)
1605   {
1606     *s = '\0';
1607     *MSVCRT__errno() = MSVCRT_EINVAL;
1608     return MSVCRT_EINVAL;
1609   }
1610   return 0;
1611 }
1612
1613
1614 /*********************************************************************
1615  *              _mbsupr(MSVCRT.@)
1616  */
1617 unsigned char* CDECL _mbsupr(unsigned char* s)
1618 {
1619   unsigned char *ret = s;
1620   if (!s)
1621     return NULL;
1622   if (get_mbcinfo()->ismbcodepage)
1623   {
1624     unsigned int c;
1625     while (*s)
1626     {
1627       c = _mbctoupper(_mbsnextc(s));
1628       /* Note that I assume that the size of the character is unchanged */
1629       if (c > 255)
1630       {
1631           *s++=(c>>8);
1632           c=c & 0xff;
1633       }
1634       *s++=c;
1635     }
1636   }
1637   else for ( ; *s; s++) *s = toupper(*s);
1638   return ret;
1639 }
1640
1641
1642 /*********************************************************************
1643  *              _mbsupr_s(MSVCRT.@)
1644  */
1645 int CDECL _mbsupr_s(unsigned char* s, MSVCRT_size_t len)
1646 {
1647   if (!s && !len)
1648   {
1649     return 0;
1650   }
1651   else if (!s || !len)
1652   {
1653     *MSVCRT__errno() = MSVCRT_EINVAL;
1654     return MSVCRT_EINVAL;
1655   }
1656   if (get_mbcinfo()->ismbcodepage)
1657   {
1658     unsigned int c;
1659     for ( ; *s && len > 0; len--)
1660     {
1661       c = _mbctoupper(_mbsnextc(s));
1662       /* Note that I assume that the size of the character is unchanged */
1663       if (c > 255)
1664       {
1665           *s++=(c>>8);
1666           c=c & 0xff;
1667       }
1668       *s++=c;
1669     }
1670   }
1671   else for ( ; *s && len > 0; s++, len--) *s = toupper(*s);
1672   if (*s)
1673   {
1674     *s = '\0';
1675     *MSVCRT__errno() = MSVCRT_EINVAL;
1676     return MSVCRT_EINVAL;
1677   }
1678   return 0;
1679 }
1680
1681
1682 /*********************************************************************
1683  *              _mbsspn (MSVCRT.@)
1684  */
1685 MSVCRT_size_t CDECL _mbsspn(const unsigned char* string, const unsigned char* set)
1686 {
1687     const unsigned char *p, *q;
1688
1689     for (p = string; *p; p++)
1690     {
1691         if (_ismbblead(*p))
1692         {
1693             for (q = set; *q; q++)
1694             {
1695                 if (!q[1])
1696                     break;
1697                 if ((*p == *q) &&  (p[1] == q[1]))
1698                     break;
1699                 q++;
1700             }
1701             if (!q[0] || !q[1]) break;
1702         }
1703         else
1704         {
1705             for (q = set; *q; q++)
1706                 if (*p == *q)
1707                     break;
1708             if (!*q) break;
1709         }
1710     }
1711     return p - string;
1712 }
1713
1714 /*********************************************************************
1715  *              _mbsspnp (MSVCRT.@)
1716  */
1717 unsigned char* CDECL _mbsspnp(const unsigned char* string, const unsigned char* set)
1718 {
1719     const unsigned char *p, *q;
1720
1721     for (p = string; *p; p++)
1722     {
1723         if (_ismbblead(*p))
1724         {
1725             for (q = set; *q; q++)
1726             {
1727                 if (!q[1])
1728                     break;
1729                 if ((*p == *q) &&  (p[1] == q[1]))
1730                     break;
1731                 q++;
1732             }
1733             if (!q[0] || !q[1]) break;
1734         }
1735         else
1736         {
1737             for (q = set; *q; q++)
1738                 if (*p == *q)
1739                     break;
1740             if (!*q) break;
1741         }
1742     }
1743     if (*p == '\0')
1744         return NULL;
1745     return (unsigned char *)p;
1746 }
1747
1748 /*********************************************************************
1749  *              _mbscspn(MSVCRT.@)
1750  */
1751 MSVCRT_size_t CDECL _mbscspn(const unsigned char* str, const unsigned char* cmp)
1752 {
1753   if (get_mbcinfo()->ismbcodepage)
1754     FIXME("don't handle double character case\n");
1755   return u_strcspn(str, cmp);
1756 }
1757
1758 /*********************************************************************
1759  *              _mbsrev (MSVCRT.@)
1760  */
1761 unsigned char* CDECL _mbsrev(unsigned char* str)
1762 {
1763     int i, len = _mbslen(str);
1764     unsigned char *p, *temp=MSVCRT_malloc(len*2);
1765
1766     if(!temp)
1767         return str;
1768
1769     /* unpack multibyte string to temp buffer */
1770     p=str;
1771     for(i=0; i<len; i++)
1772     {
1773         if (_ismbblead(*p))
1774         {
1775             temp[i*2]=*p++;
1776             temp[i*2+1]=*p++;
1777         }
1778         else
1779         {
1780             temp[i*2]=*p++;
1781             temp[i*2+1]=0;
1782         }
1783     }
1784
1785     /* repack it in the reverse order */
1786     p=str;
1787     for(i=len-1; i>=0; i--)
1788     {
1789         if(_ismbblead(temp[i*2]))
1790         {
1791             *p++=temp[i*2];
1792             *p++=temp[i*2+1];
1793         }
1794         else
1795         {
1796             *p++=temp[i*2];
1797         }
1798     }
1799
1800     MSVCRT_free(temp);
1801
1802     return str;
1803 }
1804
1805 /*********************************************************************
1806  *              _mbspbrk (MSVCRT.@)
1807  */
1808 unsigned char* CDECL _mbspbrk(const unsigned char* str, const unsigned char* accept)
1809 {
1810     const unsigned char* p;
1811
1812     while(*str)
1813     {
1814         for(p = accept; *p; p += (_ismbblead(*p)?2:1) )
1815         {
1816             if (*p == *str)
1817                 if( !_ismbblead(*p) || ( *(p+1) == *(str+1) ) )
1818                      return (unsigned char*)str;
1819         }
1820         str += (_ismbblead(*str)?2:1);
1821     }
1822     return NULL;
1823 }
1824
1825
1826 /*
1827  * Functions depending on locale codepage
1828  */
1829
1830 /*********************************************************************
1831  *              mblen(MSVCRT.@)
1832  * REMARKS
1833  *  Unlike most of the multibyte string functions this function uses
1834  *  the locale codepage, not the codepage set by _setmbcp
1835  */
1836 int CDECL MSVCRT_mblen(const char* str, MSVCRT_size_t size)
1837 {
1838   if (str && *str && size)
1839   {
1840     if(get_locinfo()->mb_cur_max == 1)
1841       return 1; /* ASCII CP */
1842
1843     return !MSVCRT_isleadbyte(*str) ? 1 : (size>1 ? 2 : -1);
1844   }
1845   return 0;
1846 }
1847
1848 /*********************************************************************
1849  *              _mbstrlen_l(MSVCRT.@)
1850  */
1851 MSVCRT_size_t CDECL _mbstrlen_l(const char* str, MSVCRT__locale_t locale)
1852 {
1853     MSVCRT_pthreadlocinfo locinfo;
1854
1855     if(!locale)
1856         locinfo = get_locinfo();
1857     else
1858         locinfo = locale->locinfo;
1859
1860     if(locinfo->mb_cur_max > 1) {
1861         MSVCRT_size_t len = 0;
1862         while(*str) {
1863             /* FIXME: According to the documentation we are supposed to test for
1864              * multi-byte character validity. Whatever that means
1865              */
1866             str += MSVCRT_isleadbyte(*str) ? 2 : 1;
1867             len++;
1868         }
1869         return len;
1870     }
1871
1872     return strlen(str);
1873 }
1874
1875 /*********************************************************************
1876  *              _mbstrlen(MSVCRT.@)
1877  */
1878 MSVCRT_size_t CDECL _mbstrlen(const char* str)
1879 {
1880     return _mbstrlen_l(str, NULL);
1881 }
1882
1883 /*********************************************************************
1884  *              _mbtowc_l(MSVCRT.@)
1885  */
1886 int CDECL MSVCRT_mbtowc_l(MSVCRT_wchar_t *dst, const char* str, MSVCRT_size_t n, MSVCRT__locale_t locale)
1887 {
1888     MSVCRT_pthreadlocinfo locinfo;
1889     MSVCRT_wchar_t tmpdst = '\0';
1890
1891     if(!locale)
1892         locinfo = get_locinfo();
1893     else
1894         locinfo = locale->locinfo;
1895
1896     if(n <= 0 || !str)
1897         return 0;
1898     if(!MultiByteToWideChar(locinfo->lc_codepage, 0, str, n, &tmpdst, 1))
1899         return -1;
1900     if(dst)
1901         *dst = tmpdst;
1902     /* return the number of bytes from src that have been used */
1903     if(!*str)
1904         return 0;
1905     if(n >= 2 && MSVCRT__isleadbyte_l(*str, locale) && str[1])
1906         return 2;
1907     return 1;
1908 }
1909
1910 /*********************************************************************
1911  *              mbtowc(MSVCRT.@)
1912  */
1913 int CDECL MSVCRT_mbtowc(MSVCRT_wchar_t *dst, const char* str, MSVCRT_size_t n)
1914 {
1915     return MSVCRT_mbtowc_l(dst, str, n, NULL);
1916 }
1917
1918 /*********************************************************************
1919  *              _mbstowcs_l(MSVCRT.@)
1920  */
1921 MSVCRT_size_t CDECL MSVCRT__mbstowcs_l(MSVCRT_wchar_t *wcstr, const char *mbstr,
1922         MSVCRT_size_t count, MSVCRT__locale_t locale)
1923 {
1924     MSVCRT_pthreadlocinfo locinfo;
1925     MSVCRT_size_t i, size;
1926
1927     if(!locale)
1928         locinfo = get_locinfo();
1929     else
1930         locinfo = locale->locinfo;
1931
1932     /* Ignore count parameter */
1933     if(!wcstr)
1934         return MultiByteToWideChar(locinfo->lc_codepage, 0, mbstr, -1, NULL, 0)-1;
1935
1936     for(i=0, size=0; i<count; i++) {
1937         if(mbstr[size] == '\0')
1938             break;
1939
1940         size += (MSVCRT__isleadbyte_l(mbstr[size], locale) ? 2 : 1);
1941     }
1942
1943     size = MultiByteToWideChar(locinfo->lc_codepage, 0,
1944             mbstr, size, wcstr, count);
1945
1946     if(size<count && wcstr)
1947         wcstr[size] = '\0';
1948
1949     return size;
1950 }
1951
1952 /*********************************************************************
1953  *              mbstowcs(MSVCRT.@)
1954  */
1955 MSVCRT_size_t CDECL MSVCRT_mbstowcs(MSVCRT_wchar_t *wcstr,
1956         const char *mbstr, MSVCRT_size_t count)
1957 {
1958     return MSVCRT__mbstowcs_l(wcstr, mbstr, count, NULL);
1959 }
1960
1961 /*********************************************************************
1962  *              _mbstowcs_s_l(MSVCRT.@)
1963  */
1964 int CDECL MSVCRT__mbstowcs_s_l(MSVCRT_size_t *ret, MSVCRT_wchar_t *wcstr,
1965         MSVCRT_size_t size, const char *mbstr,
1966         MSVCRT_size_t count, MSVCRT__locale_t locale)
1967 {
1968     MSVCRT_size_t conv;
1969
1970     if(!wcstr && !size) {
1971         conv = MSVCRT__mbstowcs_l(NULL, mbstr, 0, locale);
1972         if(ret)
1973             *ret = conv+1;
1974         return 0;
1975     }
1976
1977     if(!MSVCRT_CHECK_PMT(mbstr != NULL) || !MSVCRT_CHECK_PMT(wcstr != NULL)) {
1978         if(wcstr && size)
1979             wcstr[0] = '\0';
1980         *MSVCRT__errno() = MSVCRT_EINVAL;
1981         return MSVCRT_EINVAL;
1982     }
1983
1984     if(count==MSVCRT__TRUNCATE || size<count)
1985         conv = size;
1986     else
1987         conv = count;
1988
1989     conv = MSVCRT__mbstowcs_l(wcstr, mbstr, conv, locale);
1990     if(conv<size)
1991         wcstr[conv++] = '\0';
1992     else if(conv==size && (count==MSVCRT__TRUNCATE || wcstr[conv-1]=='\0'))
1993         wcstr[conv-1] = '\0';
1994     else {
1995         MSVCRT_INVALID_PMT("wcstr[size] is too small");
1996         if(size)
1997             wcstr[0] = '\0';
1998         *MSVCRT__errno() = MSVCRT_ERANGE;
1999         return MSVCRT_ERANGE;
2000     }
2001
2002     if(ret)
2003         *ret = conv;
2004     return 0;
2005 }
2006
2007 /*********************************************************************
2008  *              mbstowcs_s(MSVCRT.@)
2009  */
2010 int CDECL MSVCRT__mbstowcs_s(MSVCRT_size_t *ret, MSVCRT_wchar_t *wcstr,
2011         MSVCRT_size_t size, const char *mbstr, MSVCRT_size_t count)
2012 {
2013     return MSVCRT__mbstowcs_s_l(ret, wcstr, size, mbstr, count, NULL);
2014 }