- Made sure that the files that contains the declarations
[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  */
450 unsigned int _mbsnccnt(const unsigned char *str, unsigned int len)
451 {
452   int ret = 0;
453
454   if(MSVCRT___mb_cur_max > 1)
455   {
456     while(*str && len-- > 0)
457     {
458       if(MSVCRT_isleadbyte(*str))
459       {
460         str++;
461         len--;
462       }
463       ret++;
464       str++;
465     }
466     return ret;
467   }
468   return min(strlen(str), len); /* ASCII CP */
469 }
470
471
472 /*********************************************************************
473  *              _mbsncat(MSVCRT.@)
474  */
475 unsigned char* _mbsncat(unsigned char* dst, const unsigned char* src, MSVCRT_size_t len)
476 {
477   if(MSVCRT___mb_cur_max > 1)
478   {
479     char *res = dst;
480     dst += _mbslen(dst);
481     while(*src && len--)
482     {
483       *dst = *src;
484       if(MSVCRT_isleadbyte(*src))
485         *++dst = *++src;
486       dst++;
487       src++;
488     }
489     *dst++ = '\0';
490     return res;
491   }
492   return strncat(dst, src, len); /* ASCII CP */
493 }
494
495
496 /*********************************************************************
497  *              _ismbcdigit(MSVCRT.@)
498  */
499 int _ismbcdigit( unsigned int ch)
500 {
501   if (ch <0x100)
502     return isdigit(ch);
503   else
504     {
505       FIXME("Handle MBC chars\n");
506       return 0;
507     }
508 }
509
510
511 /*********************************************************************
512  *              _mbsnbcmp(MSVCRT.@)
513  */
514 int _mbsnbcmp( const unsigned char *str,const unsigned char *cmp, MSVCRT_size_t len )
515 {
516   if (!len)
517     return 0;
518   if(MSVCRT___mb_cur_max > 1)
519     {
520       FIXME("%s %s %d\n",str,cmp,len);
521       return 0;
522     }
523   return strncmp(str,cmp,len);
524 }
525
526
527 /*********************************************************************
528  *              _mbslwr(MSVCRT.@)
529  */
530 unsigned char * _mbslwr(  unsigned char *string    )
531 {
532   unsigned char *p;
533
534   if(MSVCRT___mb_cur_max > 1)
535     {
536       FIXME("%s\n",string);
537       return string;
538     }
539   p = string;
540   while (*p)
541     {
542       *p= tolower(*p);
543       p++;
544     }
545   return string;
546 }
547
548
549 /*********************************************************************
550  *              _mbsnbcpy(MSVCRT.@)
551  */
552 unsigned char * _mbsnbcpy(unsigned char *dest,const unsigned char *src,MSVCRT_size_t n)
553 {
554   if(MSVCRT___mb_cur_max > 1)
555     {
556       FIXME("%s %d\n",src,n);
557       return dest;
558     }
559   return strncpy(dest, src, n);
560 }
561
562
563 /*********************************************************************
564  *              _mbsspn (MSVCRT.@)
565  */
566 MSVCRT_size_t _mbsspn(const unsigned char *string, const unsigned char *set)
567 {
568   const unsigned char *p, *q;
569
570   for (p = string; *p; p++)
571     {
572       if (MSVCRT_isleadbyte(*p))
573         {
574           for (q = set; *q; q++)
575             {
576               if (!q[1])
577                 break;
578               if ((*p == *q) &&  (p[1] == q[1]))
579                 break;
580               q++;
581             }
582           if (*++p == '\0')
583             break;
584         }
585       else
586         for (q = set; *q; q++)
587           if (*p == *q)
588             break;
589     }
590   return p - string;
591 }
592
593
594 /*********************************************************************
595  *              _ismbcspace (MSVCRT.@)
596  */
597 int _ismbcspace( unsigned int c)
598 {
599
600   if (c <0x100)
601     return isspace(c);
602   FIXME("%c\n",c);
603   return 0;
604 }