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