Added CSIDL_MYVIDEO|MYPICTURES|MYMUSIC to _SHRegisterUserShellFolders.
[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  *              _mbschr(MSVCRT.@)
610  *
611  * Find a multibyte character in a multibyte string.
612  */
613 unsigned char* _mbschr(const unsigned char* s, unsigned int x)
614 {
615   if(MSVCRT___mb_cur_max > 1)
616   {
617     unsigned int c;
618     while (1)
619     {
620       c = _mbsnextc(s);
621       if (c == x)
622         return (unsigned char*)s;
623       if (!c)
624         return NULL;
625       s += c > 255 ? 2 : 1;
626     }
627   }
628   return u_strchr(s, x); /* ASCII CP */
629 }
630
631 /*********************************************************************
632  *              _mbsrchr(MSVCRT.@)
633  */
634 unsigned char* _mbsrchr(const unsigned char* s, unsigned int x)
635 {
636   if(MSVCRT___mb_cur_max > 1)
637   {
638     unsigned int c;
639     unsigned char* match=NULL;
640     if(!s)
641       return NULL;
642     while (1) {
643       c = _mbsnextc(s);
644       if (c == x)
645         match=(unsigned char*)s;
646       if (!c)
647         return match;
648       s +=(c > 255) ? 2 : 1;
649     }
650   }
651   return u_strrchr(s, x);
652 }
653
654 /*********************************************************************
655  *              _mbstok(MSVCRT.@)
656  *
657  * Find and extract tokens from strings
658  */
659 unsigned char* _mbstok(unsigned char *str, const unsigned char *delim)
660 {
661     thread_data_t *data = msvcrt_get_thread_data();
662     unsigned char *ret;
663
664     if(MSVCRT___mb_cur_max > 1)
665     {
666         unsigned int c;
667
668         if (!str)
669             if (!(str = data->mbstok_next)) return NULL;
670
671         while ((c = _mbsnextc(str)) && _mbschr(delim, c)) {
672             str += c > 255 ? 2 : 1;
673         }
674         if (!*str) return NULL;
675         ret = str++;
676         while ((c = _mbsnextc(str)) && !_mbschr(delim, c)) {
677             str += c > 255 ? 2 : 1;
678         }
679         if (*str) {
680             *str++ = 0;
681             if (c > 255) *str++ = 0;
682         }
683         data->mbstok_next = str;
684         return ret;
685     }
686     return u_strtok(str, delim); /* ASCII CP */
687 }
688
689 /*********************************************************************
690  *              mbtowc(MSVCRT.@)
691  */
692 int MSVCRT_mbtowc(MSVCRT_wchar_t *dst, const char* str, MSVCRT_size_t n)
693 {
694     /* temp var needed because MultiByteToWideChar wants non NULL destination */
695     MSVCRT_wchar_t tmpdst = '\0';
696
697     if(n <= 0 || !str)
698         return 0;
699     if(!MultiByteToWideChar(CP_ACP, 0, str, n, &tmpdst, 1))
700         return -1;
701     if(dst)
702         *dst = tmpdst;
703     /* return the number of bytes from src that have been used */
704     if(!*str)
705         return 0;
706     if(n >= 2 && MSVCRT_isleadbyte(*str) && str[1])
707         return 2;
708     return 1;
709 }
710
711 /*********************************************************************
712  *              _mbbtombc(MSVCRT.@)
713  */
714 unsigned int _mbbtombc(unsigned int c)
715 {
716   if(MSVCRT___mb_cur_max > 1 &&
717      ((c >= 0x20 && c <=0x7e) ||(c >= 0xa1 && c <= 0xdf)))
718   {
719     /* FIXME: I can't get this function to return anything
720      * different from what I pass it...
721      */
722   }
723   return c;  /* ASCII CP or no MB char */
724 }
725
726 /*********************************************************************
727  *              _ismbbkana(MSVCRT.@)
728  */
729 int _ismbbkana(unsigned int c)
730 {
731   /* FIXME: use lc_ctype when supported, not lc_all */
732   if(msvcrt_current_lc_all_cp == 932)
733   {
734     /* Japanese/Katakana, CP 932 */
735     return (c >= 0xa1 && c <= 0xdf);
736   }
737   return 0;
738 }
739
740 /*********************************************************************
741  *              _ismbcdigit(MSVCRT.@)
742  */
743 int _ismbcdigit(unsigned int ch)
744 {
745     MSVCRT_wchar_t wch = msvcrt_mbc_to_wc( ch );
746     return (get_char_typeW( wch ) & C1_DIGIT);
747 }
748
749 /*********************************************************************
750  *              _ismbcgraph(MSVCRT.@)
751  */
752 int _ismbcgraph(unsigned int ch)
753 {
754     MSVCRT_wchar_t wch = msvcrt_mbc_to_wc( ch );
755     return (get_char_typeW( wch ) & (C1_UPPER | C1_LOWER | C1_DIGIT | C1_PUNCT | C1_ALPHA));
756 }
757
758 /*********************************************************************
759  *              _ismbcalpha (MSVCRT.@)
760  */
761 int _ismbcalpha(unsigned int ch)
762 {
763     MSVCRT_wchar_t wch = msvcrt_mbc_to_wc( ch );
764     return (get_char_typeW( wch ) & C1_ALPHA);
765 }
766
767 /*********************************************************************
768  *              _ismbclower (MSVCRT.@)
769  */
770 int _ismbclower(unsigned int ch)
771 {
772     MSVCRT_wchar_t wch = msvcrt_mbc_to_wc( ch );
773     return (get_char_typeW( wch ) & C1_UPPER);
774 }
775
776 /*********************************************************************
777  *              _ismbcupper (MSVCRT.@)
778  */
779 int _ismbcupper(unsigned int ch)
780 {
781     MSVCRT_wchar_t wch = msvcrt_mbc_to_wc( ch );
782     return (get_char_typeW( wch ) & C1_LOWER);
783 }
784
785 /*********************************************************************
786  *              _ismbcsymbol(MSVCRT.@)
787  */
788 int _ismbcsymbol(unsigned int ch)
789 {
790     MSVCRT_wchar_t wch = msvcrt_mbc_to_wc( ch );
791     WORD ctype;
792     if (!GetStringTypeW(CT_CTYPE3, &wch, 1, &ctype))
793     {
794         WARN("GetStringTypeW failed on %x\n", ch);
795         return 0;
796     }
797     return ((ctype & C3_SYMBOL) != 0);
798 }
799
800 /*********************************************************************
801  *              _ismbcalnum (MSVCRT.@)
802  */
803 int _ismbcalnum(unsigned int ch)
804 {
805     MSVCRT_wchar_t wch = msvcrt_mbc_to_wc( ch );
806     return (get_char_typeW( wch ) & (C1_ALPHA | C1_DIGIT));
807 }
808
809 /*********************************************************************
810  *              _ismbcspace (MSVCRT.@)
811  */
812 int _ismbcspace(unsigned int ch)
813 {
814     MSVCRT_wchar_t wch = msvcrt_mbc_to_wc( ch );
815     return (get_char_typeW( wch ) & C1_SPACE);
816 }
817
818 /*********************************************************************
819  *              _ismbcprint (MSVCRT.@)
820  */
821 int _ismbcprint(unsigned int ch)
822 {
823     MSVCRT_wchar_t wch = msvcrt_mbc_to_wc( ch );
824     return (get_char_typeW( wch ) & (C1_UPPER | C1_LOWER | C1_DIGIT | C1_PUNCT | C1_ALPHA | C1_SPACE));
825 }
826
827 /*********************************************************************
828  *              _ismbcpunct(MSVCRT.@)
829  */
830 int _ismbcpunct(unsigned int ch)
831 {
832     MSVCRT_wchar_t wch = msvcrt_mbc_to_wc( ch );
833     return (get_char_typeW( wch ) & C1_PUNCT);
834 }
835
836 /*********************************************************************
837  *              _ismbchira(MSVCRT.@)
838  */
839 int _ismbchira(unsigned int c)
840 {
841   /* FIXME: use lc_ctype when supported, not lc_all */
842   if(msvcrt_current_lc_all_cp == 932)
843   {
844     /* Japanese/Hiragana, CP 932 */
845     return (c >= 0x829f && c <= 0x82f1);
846   }
847   return 0;
848 }
849
850 /*********************************************************************
851  *              _ismbckata(MSVCRT.@)
852  */
853 int _ismbckata(unsigned int c)
854 {
855   /* FIXME: use lc_ctype when supported, not lc_all */
856   if(msvcrt_current_lc_all_cp == 932)
857   {
858     if(c < 256)
859       return _ismbbkana(c);
860     /* Japanese/Katakana, CP 932 */
861     return (c >= 0x8340 && c <= 0x8396 && c != 0x837f);
862   }
863   return 0;
864 }
865
866 /*********************************************************************
867  *              _ismbblead(MSVCRT.@)
868  */
869 int _ismbblead(unsigned int c)
870 {
871   /* FIXME: should reference MSVCRT_mbctype */
872   return MSVCRT___mb_cur_max > 1 && MSVCRT_isleadbyte(c);
873 }
874
875
876 /*********************************************************************
877  *              _ismbbtrail(MSVCRT.@)
878  */
879 int _ismbbtrail(unsigned int c)
880 {
881   /* FIXME: should reference MSVCRT_mbctype */
882   return !_ismbblead(c);
883 }
884
885 /*********************************************************************
886  *              _ismbslead(MSVCRT.@)
887  */
888 int _ismbslead(const unsigned char* start, const unsigned char* str)
889 {
890   /* Lead bytes can also be trail bytes if caller messed up
891    * iterating through the string...
892    */
893   if(MSVCRT___mb_cur_max > 1)
894   {
895     while(start < str)
896       start += MSVCRT_isleadbyte(*str) ? 2 : 1;
897
898     if(start == str)
899       return MSVCRT_isleadbyte(*str);
900   }
901   return 0; /* Must have been a trail, we skipped it */
902 }
903
904 /*********************************************************************
905  *              _ismbstrail(MSVCRT.@)
906  */
907 int _ismbstrail(const unsigned char* start, const unsigned char* str)
908 {
909   /* Must not be a lead, and must be preceded by one */
910   return !_ismbslead(start, str) && MSVCRT_isleadbyte(str[-1]);
911 }
912
913 /*********************************************************************
914  *              _mbsset(MSVCRT.@)
915  */
916 unsigned char* _mbsset(unsigned char* str, unsigned int c)
917 {
918   unsigned char* ret = str;
919
920   if(MSVCRT___mb_cur_max == 1 || c < 256)
921     return u__strset(str, c); /* ASCII CP or SB char */
922
923   c &= 0xffff; /* Strip high bits */
924
925   while(str[0] && str[1])
926   {
927     *str++ = c >> 8;
928     *str++ = c & 0xff;
929   }
930   if(str[0])
931     str[0] = '\0'; /* FIXME: OK to shorten? */
932
933   return ret;
934 }
935
936 /*********************************************************************
937  *              _mbsnbset(MSVCRT.@)
938  */
939 unsigned char* _mbsnbset(unsigned char *str, unsigned int c, MSVCRT_size_t len)
940 {
941     unsigned char *ret = str;
942
943     if(!len)
944         return ret;
945
946     if(MSVCRT___mb_cur_max == 1 || c < 256)
947         return u__strnset(str, c, len); /* ASCII CP or SB char */
948
949     c &= 0xffff; /* Strip high bits */
950
951     while(str[0] && str[1] && (len > 1))
952     {
953         *str++ = c >> 8;
954         len--;
955         *str++ = c & 0xff;
956         len--;
957     }
958     if(len && str[0]) {
959         /* as per msdn pad with a blank character */
960         str[0] = ' ';
961     }
962
963     return ret;
964 }
965
966 /*********************************************************************
967  *              _mbsnset(MSVCRT.@)
968  */
969 unsigned char* _mbsnset(unsigned char* str, unsigned int c, MSVCRT_size_t len)
970 {
971   unsigned char *ret = str;
972
973   if(!len)
974     return ret;
975
976   if(MSVCRT___mb_cur_max == 1 || c < 256)
977     return u__strnset(str, c, len); /* ASCII CP or SB char */
978
979   c &= 0xffff; /* Strip high bits */
980
981   while(str[0] && str[1] && len--)
982   {
983     *str++ = c >> 8;
984     *str++ = c & 0xff;
985   }
986   if(len && str[0])
987     str[0] = '\0'; /* FIXME: OK to shorten? */
988
989   return ret;
990 }
991
992 /*********************************************************************
993  *              _mbsnccnt(MSVCRT.@)
994  * 'c' is for 'character'.
995  */
996 MSVCRT_size_t _mbsnccnt(const unsigned char* str, MSVCRT_size_t len)
997 {
998   MSVCRT_size_t ret;
999   if(MSVCRT___mb_cur_max > 1)
1000   {
1001     ret=0;
1002     while(*str && len-- > 0)
1003     {
1004       if(MSVCRT_isleadbyte(*str))
1005       {
1006         if (!len)
1007           break;
1008         len--;
1009         str++;
1010       }
1011       str++;
1012       ret++;
1013     }
1014     return ret;
1015   }
1016   ret=u_strlen(str);
1017   return min(ret, len); /* ASCII CP */
1018 }
1019
1020 /*********************************************************************
1021  *              _mbsnbcnt(MSVCRT.@)
1022  * 'b' is for byte count.
1023  */
1024 MSVCRT_size_t _mbsnbcnt(const unsigned char* str, MSVCRT_size_t len)
1025 {
1026   MSVCRT_size_t ret;
1027   if(MSVCRT___mb_cur_max > 1)
1028   {
1029     const unsigned char* xstr = str;
1030     while(*xstr && len-- > 0)
1031     {
1032       if (MSVCRT_isleadbyte(*xstr++))
1033         xstr++;
1034     }
1035     return xstr-str;
1036   }
1037   ret=u_strlen(str);
1038   return min(ret, len); /* ASCII CP */
1039 }
1040
1041 /*********************************************************************
1042  *              _mbsnbcat(MSVCRT.@)
1043  */
1044 unsigned char* _mbsnbcat(unsigned char* dst, const unsigned char* src, MSVCRT_size_t len)
1045 {
1046     if(MSVCRT___mb_cur_max > 1)
1047     {
1048         unsigned char *res = dst;
1049         while (*dst) {
1050             if (MSVCRT_isleadbyte(*dst++)) {
1051                 if (*dst) {
1052                     dst++;
1053                 } else {
1054                     /* as per msdn overwrite the lead byte in front of '\0' */
1055                     dst--;
1056                     break;
1057                 }
1058             }
1059         }
1060         while (*src && len--) *dst++ = *src++;
1061         *dst = '\0';
1062         return res;
1063     }
1064     return u_strncat(dst, src, len); /* ASCII CP */
1065 }
1066
1067
1068 /*********************************************************************
1069  *              _mbsncat(MSVCRT.@)
1070  */
1071 unsigned char* _mbsncat(unsigned char* dst, const unsigned char* src, MSVCRT_size_t len)
1072 {
1073   if(MSVCRT___mb_cur_max > 1)
1074   {
1075     unsigned char *res = dst;
1076     while (*dst)
1077     {
1078       if (MSVCRT_isleadbyte(*dst++))
1079         dst++;
1080     }
1081     while (*src && len--)
1082     {
1083       *dst++ = *src;
1084       if(MSVCRT_isleadbyte(*src++))
1085         *dst++ = *src++;
1086     }
1087     *dst = '\0';
1088     return res;
1089   }
1090   return u_strncat(dst, src, len); /* ASCII CP */
1091 }
1092
1093
1094 /*********************************************************************
1095  *              _mbslwr(MSVCRT.@)
1096  */
1097 unsigned char* _mbslwr(unsigned char* s)
1098 {
1099   if (!s)
1100     return NULL;
1101   if (MSVCRT___mb_cur_max > 1)
1102   {
1103     unsigned int c;
1104     unsigned char* p=s;
1105     while (*s)
1106     {
1107       c = _mbctolower(_mbsnextc(s));
1108       /* Note that I assume that the size of the character is unchanged */
1109       if (c > 255)
1110       {
1111           *s++=(c>>8);
1112           c=c & 0xff;
1113       }
1114       *s++=c;
1115     }
1116     return p;
1117   }
1118   return u__strlwr(s);
1119 }
1120
1121
1122 /*********************************************************************
1123  *              _mbsupr(MSVCRT.@)
1124  */
1125 unsigned char* _mbsupr(unsigned char* s)
1126 {
1127   if (!s)
1128     return NULL;
1129   if (MSVCRT___mb_cur_max > 1)
1130   {
1131     unsigned int c;
1132     unsigned char* p=s;
1133     while (*s)
1134     {
1135       c = _mbctoupper(_mbsnextc(s));
1136       /* Note that I assume that the size of the character is unchanged */
1137       if (c > 255)
1138       {
1139           *s++=(c>>8);
1140           c=c & 0xff;
1141       }
1142       *s++=c;
1143     }
1144     return p;
1145   }
1146   return u__strupr(s);
1147 }
1148
1149
1150 /*********************************************************************
1151  *              _mbsspn (MSVCRT.@)
1152  */
1153 MSVCRT_size_t _mbsspn(const unsigned char* string, const unsigned char* set)
1154 {
1155     const unsigned char *p, *q;
1156
1157     for (p = string; *p; p++)
1158     {
1159         if (MSVCRT_isleadbyte(*p))
1160         {
1161             for (q = set; *q; q++)
1162             {
1163                 if (!q[1])
1164                     break;
1165                 if ((*p == *q) &&  (p[1] == q[1]))
1166                     break;
1167                 q++;
1168             }
1169             if (!q[0] || !q[1]) break;
1170         }
1171         else
1172         {
1173             for (q = set; *q; q++)
1174                 if (*p == *q)
1175                     break;
1176             if (!*q) break;
1177         }
1178     }
1179     return p - string;
1180 }
1181
1182 /*********************************************************************
1183  *              _mbscspn(MSVCRT.@)
1184  */
1185 MSVCRT_size_t _mbscspn(const unsigned char* str, const unsigned char* cmp)
1186 {
1187   if (MSVCRT___mb_cur_max > 1)
1188     FIXME("don't handle double character case\n");
1189   return u_strcspn(str, cmp);
1190 }
1191
1192 /*********************************************************************
1193  *              _mbsrev (MSVCRT.@)
1194  */
1195 unsigned char* _mbsrev(unsigned char* str)
1196 {
1197     int i, len = _mbslen(str);
1198     unsigned char *p, *temp=MSVCRT_malloc(len*2);
1199
1200     if(!temp)
1201         return str;
1202
1203     /* unpack multibyte string to temp buffer */
1204     p=str;
1205     for(i=0; i<len; i++)
1206     {
1207         if (MSVCRT_isleadbyte(*p))
1208         {
1209             temp[i*2]=*p++;
1210             temp[i*2+1]=*p++;
1211         }
1212         else
1213         {
1214             temp[i*2]=*p++;
1215             temp[i*2+1]=0;
1216         }
1217     }
1218
1219     /* repack it in the reverse order */
1220     p=str;
1221     for(i=len-1; i>=0; i--)
1222     {
1223         if(MSVCRT_isleadbyte(temp[i*2]))
1224         {
1225             *p++=temp[i*2];
1226             *p++=temp[i*2+1];
1227         }
1228         else
1229         {
1230             *p++=temp[i*2];
1231         }
1232     }
1233
1234     MSVCRT_free(temp);
1235
1236     return str;
1237 }
1238
1239 /*********************************************************************
1240  *              _mbspbrk (MSVCRT.@)
1241  */
1242 unsigned char* _mbspbrk(const unsigned char* str, const unsigned char* accept)
1243 {
1244     const unsigned char* p;
1245
1246     while(*str)
1247     {
1248         for(p = accept; *p; p += (MSVCRT_isleadbyte(*p)?2:1) )
1249         {
1250             if (*p == *str)
1251                 if( !MSVCRT_isleadbyte(*p) || ( *(p+1) == *(str+1) ) )
1252                      return (unsigned char*)str;
1253         }
1254         str += (MSVCRT_isleadbyte(*str)?2:1);
1255     }
1256     return NULL;
1257 }