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