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