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