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