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