Added a test case for %0f and %.0f.
[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  *              _mbscoll(MSVCRT.@)
413  * Performs a case-sensitive comparison according to the current code page
414  * RETURN
415  *   _NLSCMPERROR if error
416  * FIXME: handle locales.
417  */
418 int _mbscoll(const unsigned char* str, const unsigned char* cmp)
419 {
420   if(MSVCRT___mb_cur_max > 1)
421   {
422     unsigned int strc, cmpc;
423     do {
424       if(!*str)
425         return *cmp ? -1 : 0;
426       if(!*cmp)
427         return 1;
428       strc = _mbsnextc(str);
429       cmpc = _mbsnextc(cmp);
430       if(strc != cmpc)
431         return strc < cmpc ? -1 : 1;
432       str +=(strc > 255) ? 2 : 1;
433       cmp +=(strc > 255) ? 2 : 1; /* equal, use same increment */
434     } while(1);
435   }
436   return u_strcmp(str, cmp); /* ASCII CP */
437 }
438
439
440 /*********************************************************************
441  *              _mbsicmp(MSVCRT.@)
442  */
443 int _mbsicmp(const unsigned char* str, const unsigned char* cmp)
444 {
445   if(MSVCRT___mb_cur_max > 1)
446   {
447     unsigned int strc, cmpc;
448     do {
449       if(!*str)
450         return *cmp ? -1 : 0;
451       if(!*cmp)
452         return 1;
453       strc = _mbctolower(_mbsnextc(str));
454       cmpc = _mbctolower(_mbsnextc(cmp));
455       if(strc != cmpc)
456         return strc < cmpc ? -1 : 1;
457       str +=(strc > 255) ? 2 : 1;
458       cmp +=(strc > 255) ? 2 : 1; /* equal, use same increment */
459     } while(1);
460   }
461   return u_strcasecmp(str, cmp); /* ASCII CP */
462 }
463
464 /*********************************************************************
465  *              _mbsncmp(MSVCRT.@)
466  */
467 int _mbsncmp(const unsigned char* str, const unsigned char* cmp, MSVCRT_size_t len)
468 {
469   if(!len)
470     return 0;
471
472   if(MSVCRT___mb_cur_max > 1)
473   {
474     unsigned int strc, cmpc;
475     while(len--)
476     {
477       int inc;
478       if(!*str)
479         return *cmp ? -1 : 0;
480       if(!*cmp)
481         return 1;
482       strc = _mbsnextc(str);
483       cmpc = _mbsnextc(cmp);
484       if(strc != cmpc)
485         return strc < cmpc ? -1 : 1;
486       inc=(strc > 255) ? 2 : 1; /* Equal, use same increment */
487       str += inc;
488       cmp += inc;
489     }
490     return 0; /* Matched len chars */
491   }
492   return u_strncmp(str, cmp, len); /* ASCII CP */
493 }
494
495 /*********************************************************************
496  *              _mbsnbcmp(MSVCRT.@)
497  */
498 int _mbsnbcmp(const unsigned char* str, const unsigned char* cmp, MSVCRT_size_t len)
499 {
500   if (!len)
501     return 0;
502   if(MSVCRT___mb_cur_max > 1)
503   {
504     unsigned int strc, cmpc;
505     while (len)
506     {
507       int clen;
508       if(!*str)
509         return *cmp ? -1 : 0;
510       if(!*cmp)
511         return 1;
512       if (MSVCRT_isleadbyte(*str))
513       {
514         strc=(len>=2)?_mbsnextc(str):0;
515         clen=2;
516       }
517       else
518       {
519         strc=*str;
520         clen=1;
521       }
522       if (MSVCRT_isleadbyte(*cmp))
523         cmpc=(len>=2)?_mbsnextc(cmp):0;
524       else
525         cmpc=*str;
526       if(strc != cmpc)
527         return strc < cmpc ? -1 : 1;
528       len -= clen;
529       str += clen;
530       cmp += clen;
531     }
532     return 0; /* Matched len chars */
533   }
534   return u_strncmp(str,cmp,len);
535 }
536
537 /*********************************************************************
538  *              _mbsnicmp(MSVCRT.@)
539  *
540  * Compare two multibyte strings case insensitively to 'len' characters.
541  */
542 int _mbsnicmp(const unsigned char* str, const unsigned char* cmp, MSVCRT_size_t len)
543 {
544   /* FIXME: No tolower() for mb strings yet */
545   if(MSVCRT___mb_cur_max > 1)
546   {
547     unsigned int strc, cmpc;
548     while(len--)
549     {
550       if(!*str)
551         return *cmp ? -1 : 0;
552       if(!*cmp)
553         return 1;
554       strc = _mbctolower(_mbsnextc(str));
555       cmpc = _mbctolower(_mbsnextc(cmp));
556       if(strc != cmpc)
557         return strc < cmpc ? -1 : 1;
558       str +=(strc > 255) ? 2 : 1;
559       cmp +=(strc > 255) ? 2 : 1; /* Equal, use same increment */
560     }
561     return 0; /* Matched len chars */
562   }
563   return u_strncasecmp(str, cmp, len); /* ASCII CP */
564 }
565
566 /*********************************************************************
567  *              _mbsnbicmp(MSVCRT.@)
568  */
569 int _mbsnbicmp(const unsigned char* str, const unsigned char* cmp, MSVCRT_size_t len)
570 {
571   if (!len)
572     return 0;
573   if(MSVCRT___mb_cur_max > 1)
574   {
575     unsigned int strc, cmpc;
576     while (len)
577     {
578       int clen;
579       if(!*str)
580         return *cmp ? -1 : 0;
581       if(!*cmp)
582         return 1;
583       if (MSVCRT_isleadbyte(*str))
584       {
585         strc=(len>=2)?_mbsnextc(str):0;
586         clen=2;
587       }
588       else
589       {
590         strc=*str;
591         clen=1;
592       }
593       if (MSVCRT_isleadbyte(*cmp))
594         cmpc=(len>=2)?_mbsnextc(cmp):0;
595       else
596         cmpc=*str;
597       strc = _mbctolower(strc);
598       cmpc = _mbctolower(cmpc);
599       if(strc != cmpc)
600         return strc < cmpc ? -1 : 1;
601       len -= clen;
602       str += clen;
603       cmp += clen;
604     }
605     return 0; /* Matched len bytes */
606   }
607   return u_strncmp(str,cmp,len);
608 }
609
610 /*********************************************************************
611  *              _mbschr(MSVCRT.@)
612  *
613  * Find a multibyte character in a multibyte string.
614  */
615 unsigned char* _mbschr(const unsigned char* s, unsigned int x)
616 {
617   if(MSVCRT___mb_cur_max > 1)
618   {
619     unsigned int c;
620     while (1)
621     {
622       c = _mbsnextc(s);
623       if (c == x)
624         return (unsigned char*)s;
625       if (!c)
626         return NULL;
627       s += c > 255 ? 2 : 1;
628     }
629   }
630   return u_strchr(s, x); /* ASCII CP */
631 }
632
633 /*********************************************************************
634  *              _mbsrchr(MSVCRT.@)
635  */
636 unsigned char* _mbsrchr(const unsigned char* s, unsigned int x)
637 {
638   if(MSVCRT___mb_cur_max > 1)
639   {
640     unsigned int c;
641     unsigned char* match=NULL;
642     if(!s)
643       return NULL;
644     while (1) {
645       c = _mbsnextc(s);
646       if (c == x)
647         match=(unsigned char*)s;
648       if (!c)
649         return match;
650       s +=(c > 255) ? 2 : 1;
651     }
652   }
653   return u_strrchr(s, x);
654 }
655
656 /*********************************************************************
657  *              _mbstok(MSVCRT.@)
658  *
659  * Find and extract tokens from strings
660  */
661 unsigned char* _mbstok(unsigned char *str, const unsigned char *delim)
662 {
663     thread_data_t *data = msvcrt_get_thread_data();
664     unsigned char *ret;
665
666     if(MSVCRT___mb_cur_max > 1)
667     {
668         unsigned int c;
669
670         if (!str)
671             if (!(str = data->mbstok_next)) return NULL;
672
673         while ((c = _mbsnextc(str)) && _mbschr(delim, c)) {
674             str += c > 255 ? 2 : 1;
675         }
676         if (!*str) return NULL;
677         ret = str++;
678         while ((c = _mbsnextc(str)) && !_mbschr(delim, c)) {
679             str += c > 255 ? 2 : 1;
680         }
681         if (*str) {
682             *str++ = 0;
683             if (c > 255) *str++ = 0;
684         }
685         data->mbstok_next = str;
686         return ret;
687     }
688     return u_strtok(str, delim); /* ASCII CP */
689 }
690
691 /*********************************************************************
692  *              mbtowc(MSVCRT.@)
693  */
694 int MSVCRT_mbtowc(MSVCRT_wchar_t *dst, const char* str, MSVCRT_size_t n)
695 {
696     /* temp var needed because MultiByteToWideChar wants non NULL destination */
697     MSVCRT_wchar_t tmpdst = '\0';
698
699     if(n <= 0 || !str)
700         return 0;
701     if(!MultiByteToWideChar(CP_ACP, 0, str, n, &tmpdst, 1))
702         return -1;
703     if(dst)
704         *dst = tmpdst;
705     /* return the number of bytes from src that have been used */
706     if(!*str)
707         return 0;
708     if(n >= 2 && MSVCRT_isleadbyte(*str) && str[1])
709         return 2;
710     return 1;
711 }
712
713 /*********************************************************************
714  *              _mbbtombc(MSVCRT.@)
715  */
716 unsigned int _mbbtombc(unsigned int c)
717 {
718   if(MSVCRT___mb_cur_max > 1 &&
719      ((c >= 0x20 && c <=0x7e) ||(c >= 0xa1 && c <= 0xdf)))
720   {
721     /* FIXME: I can't get this function to return anything
722      * different from what I pass it...
723      */
724   }
725   return c;  /* ASCII CP or no MB char */
726 }
727
728 /*********************************************************************
729  *              _ismbbkana(MSVCRT.@)
730  */
731 int _ismbbkana(unsigned int c)
732 {
733   /* FIXME: use lc_ctype when supported, not lc_all */
734   if(msvcrt_current_lc_all_cp == 932)
735   {
736     /* Japanese/Katakana, CP 932 */
737     return (c >= 0xa1 && c <= 0xdf);
738   }
739   return 0;
740 }
741
742 /*********************************************************************
743  *              _ismbcdigit(MSVCRT.@)
744  */
745 int _ismbcdigit(unsigned int ch)
746 {
747     MSVCRT_wchar_t wch = msvcrt_mbc_to_wc( ch );
748     return (get_char_typeW( wch ) & C1_DIGIT);
749 }
750
751 /*********************************************************************
752  *              _ismbcgraph(MSVCRT.@)
753  */
754 int _ismbcgraph(unsigned int ch)
755 {
756     MSVCRT_wchar_t wch = msvcrt_mbc_to_wc( ch );
757     return (get_char_typeW( wch ) & (C1_UPPER | C1_LOWER | C1_DIGIT | C1_PUNCT | C1_ALPHA));
758 }
759
760 /*********************************************************************
761  *              _ismbcalpha (MSVCRT.@)
762  */
763 int _ismbcalpha(unsigned int ch)
764 {
765     MSVCRT_wchar_t wch = msvcrt_mbc_to_wc( ch );
766     return (get_char_typeW( wch ) & C1_ALPHA);
767 }
768
769 /*********************************************************************
770  *              _ismbclower (MSVCRT.@)
771  */
772 int _ismbclower(unsigned int ch)
773 {
774     MSVCRT_wchar_t wch = msvcrt_mbc_to_wc( ch );
775     return (get_char_typeW( wch ) & C1_UPPER);
776 }
777
778 /*********************************************************************
779  *              _ismbcupper (MSVCRT.@)
780  */
781 int _ismbcupper(unsigned int ch)
782 {
783     MSVCRT_wchar_t wch = msvcrt_mbc_to_wc( ch );
784     return (get_char_typeW( wch ) & C1_LOWER);
785 }
786
787 /*********************************************************************
788  *              _ismbcsymbol(MSVCRT.@)
789  */
790 int _ismbcsymbol(unsigned int ch)
791 {
792     MSVCRT_wchar_t wch = msvcrt_mbc_to_wc( ch );
793     WORD ctype;
794     if (!GetStringTypeW(CT_CTYPE3, &wch, 1, &ctype))
795     {
796         WARN("GetStringTypeW failed on %x\n", ch);
797         return 0;
798     }
799     return ((ctype & C3_SYMBOL) != 0);
800 }
801
802 /*********************************************************************
803  *              _ismbcalnum (MSVCRT.@)
804  */
805 int _ismbcalnum(unsigned int ch)
806 {
807     MSVCRT_wchar_t wch = msvcrt_mbc_to_wc( ch );
808     return (get_char_typeW( wch ) & (C1_ALPHA | C1_DIGIT));
809 }
810
811 /*********************************************************************
812  *              _ismbcspace (MSVCRT.@)
813  */
814 int _ismbcspace(unsigned int ch)
815 {
816     MSVCRT_wchar_t wch = msvcrt_mbc_to_wc( ch );
817     return (get_char_typeW( wch ) & C1_SPACE);
818 }
819
820 /*********************************************************************
821  *              _ismbcprint (MSVCRT.@)
822  */
823 int _ismbcprint(unsigned int ch)
824 {
825     MSVCRT_wchar_t wch = msvcrt_mbc_to_wc( ch );
826     return (get_char_typeW( wch ) & (C1_UPPER | C1_LOWER | C1_DIGIT | C1_PUNCT | C1_ALPHA | C1_SPACE));
827 }
828
829 /*********************************************************************
830  *              _ismbcpunct(MSVCRT.@)
831  */
832 int _ismbcpunct(unsigned int ch)
833 {
834     MSVCRT_wchar_t wch = msvcrt_mbc_to_wc( ch );
835     return (get_char_typeW( wch ) & C1_PUNCT);
836 }
837
838 /*********************************************************************
839  *              _ismbchira(MSVCRT.@)
840  */
841 int _ismbchira(unsigned int c)
842 {
843   /* FIXME: use lc_ctype when supported, not lc_all */
844   if(msvcrt_current_lc_all_cp == 932)
845   {
846     /* Japanese/Hiragana, CP 932 */
847     return (c >= 0x829f && c <= 0x82f1);
848   }
849   return 0;
850 }
851
852 /*********************************************************************
853  *              _ismbckata(MSVCRT.@)
854  */
855 int _ismbckata(unsigned int c)
856 {
857   /* FIXME: use lc_ctype when supported, not lc_all */
858   if(msvcrt_current_lc_all_cp == 932)
859   {
860     if(c < 256)
861       return _ismbbkana(c);
862     /* Japanese/Katakana, CP 932 */
863     return (c >= 0x8340 && c <= 0x8396 && c != 0x837f);
864   }
865   return 0;
866 }
867
868 /*********************************************************************
869  *              _ismbblead(MSVCRT.@)
870  */
871 int _ismbblead(unsigned int c)
872 {
873   /* FIXME: should reference MSVCRT_mbctype */
874   return MSVCRT___mb_cur_max > 1 && MSVCRT_isleadbyte(c);
875 }
876
877
878 /*********************************************************************
879  *              _ismbbtrail(MSVCRT.@)
880  */
881 int _ismbbtrail(unsigned int c)
882 {
883   /* FIXME: should reference MSVCRT_mbctype */
884   return !_ismbblead(c);
885 }
886
887 /*********************************************************************
888  *              _ismbslead(MSVCRT.@)
889  */
890 int _ismbslead(const unsigned char* start, const unsigned char* str)
891 {
892   /* Lead bytes can also be trail bytes if caller messed up
893    * iterating through the string...
894    */
895   if(MSVCRT___mb_cur_max > 1)
896   {
897     while(start < str)
898       start += MSVCRT_isleadbyte(*str) ? 2 : 1;
899
900     if(start == str)
901       return MSVCRT_isleadbyte(*str);
902   }
903   return 0; /* Must have been a trail, we skipped it */
904 }
905
906 /*********************************************************************
907  *              _ismbstrail(MSVCRT.@)
908  */
909 int _ismbstrail(const unsigned char* start, const unsigned char* str)
910 {
911   /* Must not be a lead, and must be preceded by one */
912   return !_ismbslead(start, str) && MSVCRT_isleadbyte(str[-1]);
913 }
914
915 /*********************************************************************
916  *              _mbsset(MSVCRT.@)
917  */
918 unsigned char* _mbsset(unsigned char* str, unsigned int c)
919 {
920   unsigned char* ret = str;
921
922   if(MSVCRT___mb_cur_max == 1 || c < 256)
923     return u__strset(str, c); /* ASCII CP or SB char */
924
925   c &= 0xffff; /* Strip high bits */
926
927   while(str[0] && str[1])
928   {
929     *str++ = c >> 8;
930     *str++ = c & 0xff;
931   }
932   if(str[0])
933     str[0] = '\0'; /* FIXME: OK to shorten? */
934
935   return ret;
936 }
937
938 /*********************************************************************
939  *              _mbsnbset(MSVCRT.@)
940  */
941 unsigned char* _mbsnbset(unsigned char *str, unsigned int c, MSVCRT_size_t len)
942 {
943     unsigned char *ret = str;
944
945     if(!len)
946         return ret;
947
948     if(MSVCRT___mb_cur_max == 1 || c < 256)
949         return u__strnset(str, c, len); /* ASCII CP or SB char */
950
951     c &= 0xffff; /* Strip high bits */
952
953     while(str[0] && str[1] && (len > 1))
954     {
955         *str++ = c >> 8;
956         len--;
957         *str++ = c & 0xff;
958         len--;
959     }
960     if(len && str[0]) {
961         /* as per msdn pad with a blank character */
962         str[0] = ' ';
963     }
964
965     return ret;
966 }
967
968 /*********************************************************************
969  *              _mbsnset(MSVCRT.@)
970  */
971 unsigned char* _mbsnset(unsigned char* str, unsigned int c, MSVCRT_size_t len)
972 {
973   unsigned char *ret = str;
974
975   if(!len)
976     return ret;
977
978   if(MSVCRT___mb_cur_max == 1 || c < 256)
979     return u__strnset(str, c, len); /* ASCII CP or SB char */
980
981   c &= 0xffff; /* Strip high bits */
982
983   while(str[0] && str[1] && len--)
984   {
985     *str++ = c >> 8;
986     *str++ = c & 0xff;
987   }
988   if(len && str[0])
989     str[0] = '\0'; /* FIXME: OK to shorten? */
990
991   return ret;
992 }
993
994 /*********************************************************************
995  *              _mbsnccnt(MSVCRT.@)
996  * 'c' is for 'character'.
997  */
998 MSVCRT_size_t _mbsnccnt(const unsigned char* str, MSVCRT_size_t len)
999 {
1000   MSVCRT_size_t ret;
1001   if(MSVCRT___mb_cur_max > 1)
1002   {
1003     ret=0;
1004     while(*str && len-- > 0)
1005     {
1006       if(MSVCRT_isleadbyte(*str))
1007       {
1008         if (!len)
1009           break;
1010         len--;
1011         str++;
1012       }
1013       str++;
1014       ret++;
1015     }
1016     return ret;
1017   }
1018   ret=u_strlen(str);
1019   return min(ret, len); /* ASCII CP */
1020 }
1021
1022 /*********************************************************************
1023  *              _mbsnbcnt(MSVCRT.@)
1024  * 'b' is for byte count.
1025  */
1026 MSVCRT_size_t _mbsnbcnt(const unsigned char* str, MSVCRT_size_t len)
1027 {
1028   MSVCRT_size_t ret;
1029   if(MSVCRT___mb_cur_max > 1)
1030   {
1031     const unsigned char* xstr = str;
1032     while(*xstr && len-- > 0)
1033     {
1034       if (MSVCRT_isleadbyte(*xstr++))
1035         xstr++;
1036     }
1037     return xstr-str;
1038   }
1039   ret=u_strlen(str);
1040   return min(ret, len); /* ASCII CP */
1041 }
1042
1043 /*********************************************************************
1044  *              _mbsnbcat(MSVCRT.@)
1045  */
1046 unsigned char* _mbsnbcat(unsigned char* dst, const unsigned char* src, MSVCRT_size_t len)
1047 {
1048     if(MSVCRT___mb_cur_max > 1)
1049     {
1050         unsigned char *res = dst;
1051         while (*dst) {
1052             if (MSVCRT_isleadbyte(*dst++)) {
1053                 if (*dst) {
1054                     dst++;
1055                 } else {
1056                     /* as per msdn overwrite the lead byte in front of '\0' */
1057                     dst--;
1058                     break;
1059                 }
1060             }
1061         }
1062         while (*src && len--) *dst++ = *src++;
1063         *dst = '\0';
1064         return res;
1065     }
1066     return u_strncat(dst, src, len); /* ASCII CP */
1067 }
1068
1069
1070 /*********************************************************************
1071  *              _mbsncat(MSVCRT.@)
1072  */
1073 unsigned char* _mbsncat(unsigned char* dst, const unsigned char* src, MSVCRT_size_t len)
1074 {
1075   if(MSVCRT___mb_cur_max > 1)
1076   {
1077     unsigned char *res = dst;
1078     while (*dst)
1079     {
1080       if (MSVCRT_isleadbyte(*dst++))
1081         dst++;
1082     }
1083     while (*src && len--)
1084     {
1085       *dst++ = *src;
1086       if(MSVCRT_isleadbyte(*src++))
1087         *dst++ = *src++;
1088     }
1089     *dst = '\0';
1090     return res;
1091   }
1092   return u_strncat(dst, src, len); /* ASCII CP */
1093 }
1094
1095
1096 /*********************************************************************
1097  *              _mbslwr(MSVCRT.@)
1098  */
1099 unsigned char* _mbslwr(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 = _mbctolower(_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__strlwr(s);
1121 }
1122
1123
1124 /*********************************************************************
1125  *              _mbsupr(MSVCRT.@)
1126  */
1127 unsigned char* _mbsupr(unsigned char* s)
1128 {
1129   if (!s)
1130     return NULL;
1131   if (MSVCRT___mb_cur_max > 1)
1132   {
1133     unsigned int c;
1134     unsigned char* p=s;
1135     while (*s)
1136     {
1137       c = _mbctoupper(_mbsnextc(s));
1138       /* Note that I assume that the size of the character is unchanged */
1139       if (c > 255)
1140       {
1141           *s++=(c>>8);
1142           c=c & 0xff;
1143       }
1144       *s++=c;
1145     }
1146     return p;
1147   }
1148   return u__strupr(s);
1149 }
1150
1151
1152 /*********************************************************************
1153  *              _mbsspn (MSVCRT.@)
1154  */
1155 MSVCRT_size_t _mbsspn(const unsigned char* string, const unsigned char* set)
1156 {
1157   const unsigned char *p, *q;
1158
1159   for (p = string; *p; p++)
1160     {
1161       if (MSVCRT_isleadbyte(*p))
1162         {
1163           for (q = set; *q; q++)
1164             {
1165               if (!q[1])
1166                 break;
1167               if ((*p == *q) &&  (p[1] == q[1]))
1168                 break;
1169               q++;
1170             }
1171           if (*++p == '\0')
1172             break;
1173         }
1174       else
1175         for (q = set; *q; q++)
1176           if (*p == *q)
1177             break;
1178     }
1179   return p - string;
1180 }
1181
1182 /*********************************************************************
1183  *              _mbscspn(MSVCRT.@)
1184  */
1185 MSVCRT_size_t _mbscspn(const unsigned char* str, const unsigned char* cmp)
1186 {
1187   if (MSVCRT___mb_cur_max > 1)
1188     FIXME("don't handle double character case\n");
1189   return u_strcspn(str, cmp);
1190 }
1191
1192 /*********************************************************************
1193  *              _mbsrev (MSVCRT.@)
1194  */
1195 unsigned char* _mbsrev(unsigned char* str)
1196 {
1197     int i, len = _mbslen(str);
1198     unsigned char *p, *temp=MSVCRT_malloc(len*2);
1199
1200     if(!temp)
1201         return str;
1202
1203     /* unpack multibyte string to temp buffer */
1204     p=str;
1205     for(i=0; i<len; i++)
1206     {
1207         if (MSVCRT_isleadbyte(*p))
1208         {
1209             temp[i*2]=*p++;
1210             temp[i*2+1]=*p++;
1211         }
1212         else
1213         {
1214             temp[i*2]=*p++;
1215             temp[i*2+1]=0;
1216         }
1217     }
1218
1219     /* repack it in the reverse order */
1220     p=str;
1221     for(i=len-1; i>=0; i--)
1222     {
1223         if(MSVCRT_isleadbyte(temp[i*2]))
1224         {
1225             *p++=temp[i*2];
1226             *p++=temp[i*2+1];
1227         }
1228         else
1229         {
1230             *p++=temp[i*2];
1231         }
1232     }
1233
1234     MSVCRT_free(temp);
1235
1236     return str;
1237 }
1238
1239 /*********************************************************************
1240  *              _mbspbrk (MSVCRT.@)
1241  */
1242 unsigned char* _mbspbrk(const unsigned char* str, const unsigned char* accept)
1243 {
1244     const unsigned char* p;
1245
1246     while(*str)
1247     {
1248         for(p = accept; *p; p += (MSVCRT_isleadbyte(*p)?2:1) )
1249         {
1250             if (*p == *str)
1251                 if( !MSVCRT_isleadbyte(*p) || ( *(p+1) == *(str+1) ) )
1252                      return (unsigned char*)str;
1253         }
1254         str += (MSVCRT_isleadbyte(*str)?2:1);
1255     }
1256     return NULL;
1257 }