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