When including 'wine/port.h', include it first.
[wine] / dlls / msvcrt / mbcs.c
1 /*
2  * msvcrt.dll mbcs functions
3  *
4  * Copyright 1999 Alexandre Julliard
5  * Copyright 2000 Jon Griffths
6  *
7  * FIXME
8  * Not currently binary compatible with win32. MSVCRT_mbctype must be
9  * populated correctly and the ismb* functions should reference it.
10  */
11
12 #include "msvcrt.h"
13
14 #include "msvcrt/stdlib.h"
15 #include "msvcrt/string.h"
16 #include "msvcrt/wctype.h"
17
18
19 DEFAULT_DEBUG_CHANNEL(msvcrt);
20
21 unsigned char MSVCRT_mbctype[257];
22 int MSVCRT___mb_cur_max = 1;
23
24 /*********************************************************************
25  *              __p__mbctype (MSVCRT.@)
26  */
27 unsigned char *__p__mbctype(void)
28 {
29   return MSVCRT_mbctype;
30 }
31
32 /*********************************************************************
33  *              __p___mb_cur_max(MSVCRT.@)
34  */
35 int *__p___mb_cur_max(void)
36 {
37   return &MSVCRT___mb_cur_max;
38 }
39
40 /*********************************************************************
41  *              _mbsnextc(MSVCRT.@)
42  */
43 unsigned int _mbsnextc(const unsigned char *str)
44 {
45   if(MSVCRT___mb_cur_max > 1 && MSVCRT_isleadbyte(*str))
46     return *str << 8 | str[1];
47   return *str; /* ASCII CP or SB char */
48 }
49
50 /*********************************************************************
51  *              _mbscmp(MSVCRT.@)
52  */
53 int _mbscmp(const char *str, const char *cmp)
54 {
55   if(MSVCRT___mb_cur_max > 1)
56   {
57     unsigned int strc, cmpc;
58     do {
59       if(!*str)
60         return *cmp ? -1 : 0;
61       if(!*cmp)
62         return 1;
63       strc = _mbsnextc(str);
64       cmpc = _mbsnextc(cmp);
65       if(strc != cmpc)
66         return strc < cmpc ? -1 : 1;
67       str +=(strc > 255) ? 2 : 1;
68       cmp +=(strc > 255) ? 2 : 1; /* equal, use same increment */
69     } while(1);
70   }
71   return strcmp(str, cmp); /* ASCII CP */
72 }
73
74 /*********************************************************************
75  *              _mbsicmp(MSVCRT.@)
76  */
77 int _mbsicmp(const char *str, const char *cmp)
78 {
79   /* FIXME: No tolower() for mb strings yet */
80   if(MSVCRT___mb_cur_max > 1)
81     return _mbscmp(str, cmp);
82   return strcasecmp(str, cmp); /* ASCII CP */
83 }
84
85 /*********************************************************************
86  *              _mbsncmp    (MSVCRT.@)
87  */
88 int _mbsncmp(const char *str, const char *cmp, unsigned int len)
89 {
90   if(!len)
91     return 0;
92
93   if(MSVCRT___mb_cur_max > 1)
94   {
95     unsigned int strc, cmpc;
96     while(len--)
97     {
98       if(!*str)
99         return *cmp ? -1 : 0;
100       if(!*cmp)
101         return 1;
102       strc = _mbsnextc(str);
103       cmpc = _mbsnextc(cmp);
104       if(strc != cmpc)
105         return strc < cmpc ? -1 : 1;
106       str +=(strc > 255) ? 2 : 1;
107       cmp +=(strc > 255) ? 2 : 1; /* Equal, use same increment */
108     }
109     return 0; /* Matched len chars */
110   }
111   return strncmp(str, cmp, len); /* ASCII CP */
112 }
113
114 /*********************************************************************
115  *                  _mbsnicmp(MSVCRT.@)
116  *
117  * Compare two multibyte strings case insensitively to 'len' characters.
118  */
119 int _mbsnicmp(const char *str, const char *cmp, unsigned int len)
120 {
121   /* FIXME: No tolower() for mb strings yet */
122   if(MSVCRT___mb_cur_max > 1)
123     return _mbsncmp(str, cmp, len);
124   return strncasecmp(str, cmp, len); /* ASCII CP */
125 }
126
127 /*********************************************************************
128  *              _mbsinc(MSVCRT.@)
129  */
130 char *_mbsinc(const unsigned char *str)
131 {
132   if(MSVCRT___mb_cur_max > 1 && MSVCRT_isleadbyte(*str))
133     return (char *)str + 2; /* MB char */
134
135   return (char *)str + 1; /* ASCII CP or SB char */
136 }
137
138 /*********************************************************************
139  *              _mbsninc(MSVCRT.@)
140  */
141 char *_mbsninc(const char *str, unsigned int 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 (char *)str;
150   }
151   return (char *)str + num; /* ASCII CP */
152 }
153
154 /*********************************************************************
155  *              _mbslen(MSVCRT.@)
156  */
157 int _mbslen(const unsigned char *str)
158 {
159   if(MSVCRT___mb_cur_max > 1)
160   {
161     int len = 0;
162     while(*str)
163     {
164       str += MSVCRT_isleadbyte(*str) ? 2 : 1;
165       len++;
166     }
167     return len;
168   }
169   return strlen(str); /* ASCII CP */
170 }
171
172 /*********************************************************************
173  *              _mbsrchr(MSVCRT.@)
174  */
175 char *_mbsrchr(const char *s,unsigned int x)
176 {
177   /* FIXME: handle multibyte strings */
178   return strrchr(s,x);
179 }
180
181 /*********************************************************************
182  *              mbtowc(MSVCRT.@)
183  */
184 int MSVCRT_mbtowc(WCHAR *dst, const char *str, unsigned int n)
185 {
186   if(n <= 0 || !str)
187     return 0;
188   if(!MultiByteToWideChar(CP_ACP, 0, str, n, dst, 1))
189     return 0;
190   /* return the number of bytes from src that have been used */
191   if(!*str)
192     return 0;
193   if(n >= 2 && MSVCRT_isleadbyte(*str) && str[1])
194     return 2;
195   return 1;
196 }
197
198 /*********************************************************************
199  *              _mbccpy(MSVCRT.@)
200  */
201 void _mbccpy(char *dest, const unsigned char *src)
202 {
203   *dest++ = *src;
204   if(MSVCRT___mb_cur_max > 1 && MSVCRT_isleadbyte(*src))
205     *dest = *++src; /* MB char */
206 }
207
208 /*********************************************************************
209  *              _mbbtombc(MSVCRT.@)
210  */
211 unsigned int _mbbtombc(unsigned int c)
212 {
213   if(MSVCRT___mb_cur_max > 1 &&
214      ((c >= 0x20 && c <=0x7e) ||(c >= 0xa1 && c <= 0xdf)))
215   {
216     /* FIXME: I can't get this function to return anything
217      * different to what I pass it...
218      */
219   }
220   return c;  /* ASCII CP or no MB char */
221 }
222
223 /*********************************************************************
224  *              _mbclen(MSVCRT.@)
225  */
226 unsigned int _mbclen(const unsigned char *str)
227 {
228   return MSVCRT_isleadbyte(*str) ? 2 : 1;
229 }
230
231 /*********************************************************************
232  *              _ismbbkana(MSVCRT.@)
233  */
234 int _ismbbkana(unsigned int c)
235 {
236   /* FIXME: use lc_ctype when supported, not lc_all */
237   if(MSVCRT_current_lc_all_cp == 932)
238   {
239     /* Japanese/Katakana, CP 932 */
240     return (c >= 0xa1 && c <= 0xdf);
241   }
242   return 0;
243 }
244
245 /*********************************************************************
246  *              _ismbchira(MSVCRT.@)
247  */
248 int _ismbchira(unsigned int c)
249 {
250   /* FIXME: use lc_ctype when supported, not lc_all */
251   if(MSVCRT_current_lc_all_cp == 932)
252   {
253     /* Japanese/Hiragana, CP 932 */
254     return (c >= 0x829f && c <= 0x82f1);
255   }
256   return 0;
257 }
258
259 /*********************************************************************
260  *              _ismbckata(MSVCRT.@)
261  */
262 int _ismbckata(unsigned int c)
263 {
264   /* FIXME: use lc_ctype when supported, not lc_all */
265   if(MSVCRT_current_lc_all_cp == 932)
266   {
267     if(c < 256)
268       return _ismbbkana(c);
269     /* Japanese/Katakana, CP 932 */
270     return (c >= 0x8340 && c <= 0x8396 && c != 0x837f);
271   }
272   return 0;
273 }
274
275 /*********************************************************************
276  *              _ismbblead(MSVCRT.@)
277  */
278 int _ismbblead(unsigned int c)
279 {
280   /* FIXME: should reference MSVCRT_mbctype */
281   return MSVCRT___mb_cur_max > 1 && MSVCRT_isleadbyte(c);
282 }
283
284
285 /*********************************************************************
286  *              _ismbbtrail(MSVCRT.@)
287  */
288 int _ismbbtrail(unsigned int c)
289 {
290   /* FIXME: should reference MSVCRT_mbctype */
291   return !_ismbblead(c);
292 }
293
294 /*********************************************************************
295  *              _ismbslead(MSVCRT.@)
296  */
297 int _ismbslead(const unsigned char *start, const unsigned char *str)
298 {
299   /* Lead bytes can also be trail bytes if caller messed up
300    * iterating through the string...
301    */
302   if(MSVCRT___mb_cur_max > 1)
303   {
304     while(start < str)
305       start += MSVCRT_isleadbyte(*str) ? 2 : 1;
306
307     if(start == str)
308       return MSVCRT_isleadbyte(*str);
309   }
310   return 0; /* Must have been a trail, we skipped it */
311 }
312
313 /*********************************************************************
314  *              _ismbstrail(MSVCRT.@)
315  */
316 int _ismbstrail(const char *start, const unsigned char *str)
317 {
318   /* Must not be a lead, and must be preceeded by one */
319   return !_ismbslead(start, str) && MSVCRT_isleadbyte(str[-1]);
320 }
321
322 /*********************************************************************
323  *              _mbsdec(MSVCRT.@)
324  */
325 char *_mbsdec(const char *start, const char *cur)
326 {
327   if(MSVCRT___mb_cur_max > 1)
328     return (char *)(_ismbstrail(start,cur-1) ? cur - 2 : cur -1);
329
330   return (char *)cur - 1; /* ASCII CP or SB char */
331 }
332
333 /*********************************************************************
334  *              _mbsset(MSVCRT.@)
335  */
336 char *_mbsset(char *str, unsigned int c)
337 {
338   char *ret = str;
339
340   if(MSVCRT___mb_cur_max == 1 || c < 256)
341     return _strset(str, c); /* ASCII CP or SB char */
342
343   c &= 0xffff; /* Strip high bits */
344
345   while(str[0] && str[1])
346   {
347     *str++ = c >> 8;
348     *str++ = c & 0xff;
349   }
350   if(str[0])
351     str[0] = '\0'; /* FIXME: OK to shorten? */
352
353   return ret;
354 }
355
356 /*********************************************************************
357  *              _mbsnset(MSVCRT.@)
358  */
359 char *_mbsnset(char *str, unsigned int c, unsigned int len)
360 {
361   char *ret = str;
362
363   if(!len)
364     return ret;
365
366   if(MSVCRT___mb_cur_max == 1 || c < 256)
367     return _strnset(str, c, len); /* ASCII CP or SB char */
368
369   c &= 0xffff; /* Strip high bits */
370
371   while(str[0] && str[1] && len--)
372   {
373     *str++ = c >> 8;
374     *str++ = c & 0xff;
375   }
376   if(len && str[0])
377     str[0] = '\0'; /* FIXME: OK to shorten? */
378
379   return ret;
380 }
381
382 /*********************************************************************
383  *              _mbstrlen(MSVCRT.@)
384  */
385 MSVCRT_size_t _mbstrlen(const char *str)
386 {
387   if(MSVCRT___mb_cur_max > 1)
388   {
389     int len = 0;
390     while(*str)
391     {
392       str += MSVCRT_isleadbyte(*str) ? 2 : 1;
393       len++;
394     }
395     return len;
396   }
397   return strlen(str); /* ASCII CP */
398 }
399
400 /*********************************************************************
401  *              _mbsncpy(MSVCRT.@)
402  */
403 char *_mbsncpy(char *dst, const char *src, unsigned int len)
404 {
405   if(!len)
406     return dst;
407   if(MSVCRT___mb_cur_max > 1)
408   {
409     char *ret = dst;
410     while(src[0] && src[1] && len--)
411     {
412       *dst++ = *src++;
413       *dst++ = *src++;
414     }
415     if(len--)
416     {
417       *dst++ = *src++; /* Last char or '\0' */
418       while(len--)
419         *dst++ = '\0';
420     }
421     return ret;
422   }
423   return strncpy(dst, src, len); /* ASCII CP */
424 }
425
426 /*********************************************************************
427  *              _mbschr(MSVCRT.@)
428  *
429  * Find a multibyte character in a multibyte string.
430  */
431 unsigned char* _mbschr(const unsigned char* str, unsigned int c)
432 {
433   if(MSVCRT___mb_cur_max > 1)
434   {
435     unsigned int next;
436     while((next = _mbsnextc(str)))
437     {
438       if(next == c)
439         return (char *)str;
440       str += next > 255 ? 2 : 1;
441     }
442     return c ? NULL :(char *)str;
443   }
444   return strchr(str, c); /* ASCII CP */
445 }
446
447 /*********************************************************************
448  *              _mbsnccnt(MSVCRT.@)
449  * 'c' is for 'character'.
450  */
451 unsigned int _mbsnccnt(const unsigned char *str, unsigned int len)
452 {
453   int ret = 0;
454
455   if(MSVCRT___mb_cur_max > 1)
456   {
457     while(*str && len-- > 0)
458     {
459       if(MSVCRT_isleadbyte(*str))
460       {
461         str++;
462         len--;
463       }
464       ret++;
465       str++;
466     }
467     return ret;
468   }
469   return min(strlen(str), len); /* ASCII CP */
470 }
471
472 /*********************************************************************
473  *              _mbsnbcnt(MSVCRT.@)
474  * 'b' is for byte count.
475  */
476 unsigned int _mbsnbcnt(const unsigned char *str, unsigned int len)
477 {
478   const unsigned char *xstr = str;
479
480   if(MSVCRT___mb_cur_max > 1)
481   {
482     while(*xstr && len-- > 0)
483     {
484       if(MSVCRT_isleadbyte(*xstr))
485       {
486         xstr++;
487         len--;
488       }
489       xstr++;
490     }
491     return xstr-str;
492   }
493   return min(strlen(str), len); /* ASCII CP */
494 }
495
496
497 /*********************************************************************
498  *              _mbsncat(MSVCRT.@)
499  */
500 unsigned char* _mbsncat(unsigned char* dst, const unsigned char* src, MSVCRT_size_t len)
501 {
502   if(MSVCRT___mb_cur_max > 1)
503   {
504     char *res = dst;
505     dst += _mbslen(dst);
506     while(*src && len--)
507     {
508       *dst = *src;
509       if(MSVCRT_isleadbyte(*src))
510         *++dst = *++src;
511       dst++;
512       src++;
513     }
514     *dst++ = '\0';
515     return res;
516   }
517   return strncat(dst, src, len); /* ASCII CP */
518 }
519
520
521 /*********************************************************************
522  *              _ismbcdigit(MSVCRT.@)
523  */
524 int _ismbcdigit( unsigned int ch)
525 {
526   if (ch <0x100)
527     return isdigit(ch);
528   else
529     {
530       FIXME("Handle MBC chars\n");
531       return 0;
532     }
533 }
534
535
536 /*********************************************************************
537  *              _mbsnbcmp(MSVCRT.@)
538  */
539 int _mbsnbcmp( const unsigned char *str,const unsigned char *cmp, MSVCRT_size_t len )
540 {
541   if (!len)
542     return 0;
543   if(MSVCRT___mb_cur_max > 1)
544     {
545       FIXME("%s %s %d\n",str,cmp,len);
546       return 0;
547     }
548   return strncmp(str,cmp,len);
549 }
550
551
552 /*********************************************************************
553  *              _mbslwr(MSVCRT.@)
554  */
555 unsigned char * _mbslwr(  unsigned char *string    )
556 {
557   unsigned char *p;
558
559   if(MSVCRT___mb_cur_max > 1)
560     {
561       FIXME("%s\n",string);
562       return string;
563     }
564   p = string;
565   while (*p)
566     {
567       *p= tolower(*p);
568       p++;
569     }
570   return string;
571 }
572
573
574 /*********************************************************************
575  *              _mbsupr(MSVCRT.@)
576  */
577 unsigned char * _mbsupr( unsigned char *string )
578 {
579   unsigned char *p;
580
581   if(MSVCRT___mb_cur_max > 1)
582     {
583       FIXME("%s\n",string);
584       return string;
585     }
586   p = string;
587   while (*p)
588     {
589       *p= toupper(*p);
590       p++;
591     }
592   return string;
593 }
594
595
596 /*********************************************************************
597  *              _mbsnbcpy(MSVCRT.@)
598  */
599 unsigned char * _mbsnbcpy(unsigned char *dest,const unsigned char *src,MSVCRT_size_t n)
600 {
601   if(MSVCRT___mb_cur_max > 1)
602     {
603       FIXME("%s %d\n",src,n);
604       return dest;
605     }
606   return strncpy(dest, src, n);
607 }
608
609
610 /*********************************************************************
611  *              _mbsspn (MSVCRT.@)
612  */
613 MSVCRT_size_t _mbsspn(const unsigned char *string, const unsigned char *set)
614 {
615   const unsigned char *p, *q;
616
617   for (p = string; *p; p++)
618     {
619       if (MSVCRT_isleadbyte(*p))
620         {
621           for (q = set; *q; q++)
622             {
623               if (!q[1])
624                 break;
625               if ((*p == *q) &&  (p[1] == q[1]))
626                 break;
627               q++;
628             }
629           if (*++p == '\0')
630             break;
631         }
632       else
633         for (q = set; *q; q++)
634           if (*p == *q)
635             break;
636     }
637   return p - string;
638 }
639
640
641 /*********************************************************************
642  *              _ismbcspace (MSVCRT.@)
643  */
644 int _ismbcspace( unsigned int c)
645 {
646
647   if (c <0x100)
648     return isspace(c);
649   FIXME("%c\n",c);
650   return 0;
651 }
652
653 /*********************************************************************
654  *              _mbsrev (MSVCRT.@)
655  */
656 char *_mbsrev(char *str)
657 {
658     int i, len = _mbslen(str);
659     char *p, *temp=MSVCRT_malloc(len*2);
660
661     if(!temp)
662         return str;
663
664     /* unpack multibyte string to temp buffer */
665     p=str;
666     for(i=0; i<len; i++)
667     {
668         if (MSVCRT_isleadbyte(*p))
669         {
670             temp[i*2]=*p++;
671             temp[i*2+1]=*p++;
672         }
673         else
674         {
675             temp[i*2]=*p++;
676             temp[i*2+1]=0;
677         }
678     }
679
680     /* repack it in the reverse order */
681     p=str;
682     for(i=len-1; i>=0; i--)
683     {
684         if(MSVCRT_isleadbyte(temp[i*2]))
685         {
686             *p++=temp[i*2];
687             *p++=temp[i*2+1];
688         }
689         else
690         {
691             *p++=temp[i*2];
692         }
693     }
694
695     MSVCRT_free(temp);
696
697     return str;
698 }
699
700 /*********************************************************************
701  *              _mbspbrk (MSVCRT.@)
702  */
703 const char *_mbspbrk(const char *str, const char *accept)
704 {
705     const char *p;
706
707     while(*str)
708     {
709         for(p = accept; *p; p += (MSVCRT_isleadbyte(*p)?2:1) )
710         {
711             if (*p == *str)
712                 if( !MSVCRT_isleadbyte(*p) || ( *(p+1) == *(str+1) ) )
713                      return str;
714         }
715         str += (MSVCRT_isleadbyte(*str)?2:1);
716     }
717     return NULL;
718 }
719