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