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