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