- Migrate CRTDLL to MSVCRT.
[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 compatable with win32. MSVCRT_mbctype must be
9  * populated correctly and the ismb* functions should reference it.
10  */
11 #include "msvcrt.h"
12
13 DEFAULT_DEBUG_CHANNEL(msvcrt);
14
15 unsigned char MSVCRT_mbctype[257];
16 int MSVCRT___mb_cur_max = 1;
17
18 int __cdecl MSVCRT_isleadbyte(int);
19 char *__cdecl MSVCRT__strset(char *, int);
20 char *__cdecl MSVCRT__strnset(char *, int, unsigned int);
21 extern unsigned int MSVCRT_current_lc_all_cp;
22
23
24 /*********************************************************************
25  *              __p__mbctype (MSVCRT.@)
26  */
27 unsigned char *__cdecl MSVCRT___p__mbctype(void)
28 {
29   return MSVCRT_mbctype;
30 }
31
32 /*********************************************************************
33  *              __p___mb_cur_max(MSVCRT.@)
34  */
35 int *__cdecl MSVCRT___p___mb_cur_max(void)
36 {
37   return &MSVCRT___mb_cur_max;
38 }
39
40 /*********************************************************************
41  *              _mbsnextc(MSVCRT.@)
42  */
43 unsigned int __cdecl MSVCRT__mbsnextc(const 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 __cdecl MSVCRT__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 = MSVCRT__mbsnextc(str);
64       cmpc = MSVCRT__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 __cdecl MSVCRT__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 MSVCRT__mbscmp(str, cmp);
82   return strcasecmp(str, cmp); /* ASCII CP */
83 }
84
85 /*********************************************************************
86  *              _mbsncmp    (MSVCRT.@)
87  */
88 int __cdecl MSVCRT__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 = MSVCRT__mbsnextc(str);
103       cmpc = MSVCRT__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 __cdecl MSVCRT__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 MSVCRT__mbsncmp(str, cmp, len);
124   return strncasecmp(str, cmp, len); /* ASCII CP */
125 }
126
127 /*********************************************************************
128  *              _mbsinc(MSVCRT.@)
129  */
130 char *__cdecl MSVCRT__mbsinc(const char *str)
131 {
132   if(MSVCRT___mb_cur_max > 1 &&
133       MSVCRT_isleadbyte(*str))
134     return(char *)str + 2; /* MB char */
135
136   return(char *)str + 1; /* ASCII CP or SB char */
137 }
138
139 /*********************************************************************
140  *              _mbsninc(MSVCRT.@)
141  */
142 char *MSVCRT__mbsninc(const char *str, unsigned int num)
143 {
144   if(!str || num < 1)
145     return NULL;
146   if(MSVCRT___mb_cur_max > 1)
147   {
148     while(num--)
149       str = MSVCRT__mbsinc(str);
150     return(char *)str;
151   }
152   return(char *)str + num; /* ASCII CP */
153 }
154
155 /*********************************************************************
156  *              _mbslen(MSVCRT.206)
157  */
158 int __cdecl MSVCRT__mbslen(const char *str)
159 {
160   if(MSVCRT___mb_cur_max > 1)
161   {
162     int len = 0;
163     while(*str)
164     {
165       str += MSVCRT_isleadbyte(*str) ? 2 : 1;
166       len++;
167     }
168     return len;
169   }
170   return strlen(str); /* ASCII CP */
171 }
172
173 /*********************************************************************
174  *              _mbsrchr(MSVCRT.@)
175  */
176 char *__cdecl MSVCRT__mbsrchr(const char *s,unsigned int x)
177 {
178   /* FIXME: handle multibyte strings */
179   return strrchr(s,x);
180 }
181
182 /*********************************************************************
183  *              mbtowc(MSVCRT.@)
184  */
185 int __cdecl MSVCRT_mbtowc(WCHAR *dst, const char *str, unsigned int n)
186 {
187   if(n <= 0 || !str)
188     return 0;
189   if(!MultiByteToWideChar(CP_ACP, 0, str, n, dst, 1))
190     return 0;
191   /* return the number of bytes from src that have been used */
192   if(!*str)
193     return 0;
194   if(n >= 2 && MSVCRT_isleadbyte(*str) && str[1])
195     return 2;
196   return 1;
197 }
198
199 /*********************************************************************
200  *              _mbccpy(MSVCRT.@)
201  */
202 void __cdecl MSVCRT__mbccpy(char *dest, char *src)
203 {
204   *dest++ = *src;
205   if(MSVCRT___mb_cur_max > 1 && MSVCRT_isleadbyte(*src))
206     *dest = *++src; /* MB char */
207 }
208
209 /*********************************************************************
210  *              _mbbtombc(MSVCRT.@)
211  */
212 unsigned int __cdecl MSVCRT__mbbtombc(unsigned int c)
213 {
214   if(MSVCRT___mb_cur_max > 1 &&
215      ((c >= 0x20 && c <=0x7e) ||(c >= 0xa1 && c <= 0xdf)))
216   {
217     /* FIXME: I can't get this function to return anything
218      * different to what I pass it...
219      */
220   }
221   return c;  /* ASCII CP or no MB char */
222 }
223
224 /*********************************************************************
225  *              _mbclen(MSVCRT.@)
226  */
227 unsigned int __cdecl MSVCRT__mbclen(const char *str)
228 {
229   return MSVCRT_isleadbyte(*str) ? 2 : 1;
230 }
231
232 /*********************************************************************
233  *              _ismbbkana(MSVCRT.@)
234  */
235 int __cdecl MSVCRT__ismbbkana(unsigned int c)
236 {
237   /* FIXME: use lc_ctype when supported, not lc_all */
238   if(MSVCRT_current_lc_all_cp == 932)
239   {
240     /* Japanese/Katakana, CP 932 */
241     return(c >= 0xa1 && c <= 0xdf);
242   }
243   return 0;
244 }
245
246 /*********************************************************************
247  *              _ismbchira(MSVCRT.@)
248  */
249 int __cdecl MSVCRT__ismbchira(unsigned int c)
250 {
251   /* FIXME: use lc_ctype when supported, not lc_all */
252   if(MSVCRT_current_lc_all_cp == 932)
253   {
254     /* Japanese/Hiragana, CP 932 */
255     return(c >= 0x829f && c <= 0x82f1);
256   }
257   return 0;
258 }
259
260 /*********************************************************************
261  *              _ismbckata(MSVCRT.@)
262  */
263 int __cdecl MSVCRT__ismbckata(unsigned int c)
264 {
265   /* FIXME: use lc_ctype when supported, not lc_all */
266   if(MSVCRT_current_lc_all_cp == 932)
267   {
268     if(c < 256)
269       return MSVCRT__ismbbkana(c);
270     /* Japanese/Katakana, CP 932 */
271     return(c >= 0x8340 && c <= 0x8396 && c != 0x837f);
272   }
273   return 0;
274 }
275
276 /*********************************************************************
277  *              _ismbblead(MSVCRT.@)
278  */
279 int __cdecl MSVCRT__ismbblead(unsigned int c)
280 {
281   /* FIXME: should reference MSVCRT_mbctype */
282   return MSVCRT___mb_cur_max > 1 && MSVCRT_isleadbyte(c);
283 }
284
285
286 /*********************************************************************
287  *              _ismbbtrail(MSVCRT.@)
288  */
289 int __cdecl MSVCRT__ismbbtrail(unsigned int c)
290 {
291   /* FIXME: should reference MSVCRT_mbctype */
292   return !MSVCRT__ismbblead(c);
293 }
294
295 /*********************************************************************
296  *              _ismbslead(MSVCRT.@)
297  */
298 int __cdecl MSVCRT__ismbslead(const char *start, const char *str)
299 {
300   /* Lead bytes can also be trail bytes if caller messed up
301    * iterating through the string...
302    */
303   if(MSVCRT___mb_cur_max > 1)
304   {
305     while(start < str)
306       start += MSVCRT_isleadbyte(*str) ? 2 : 1;
307
308     if(start == str)
309       return MSVCRT_isleadbyte(*str);
310   }
311   return 0; /* Must have been a trail, we skipped it */
312 }
313
314 /*********************************************************************
315  *              _ismbstrail(MSVCRT.@)
316  */
317 int __cdecl MSVCRT__ismbstrail(const char *start, const char *str)
318 {
319   /* Must not be a lead, and must be preceeded by one */
320   return !MSVCRT__ismbslead(start, str) && MSVCRT_isleadbyte(str[-1]);
321 }
322
323 /*********************************************************************
324  *              _mbsdec(MSVCRT.@)
325  */
326 char *__cdecl MSVCRT__mbsdec(const char *start, const char *cur)
327 {
328   if(MSVCRT___mb_cur_max > 1)
329     return(char *)(MSVCRT__ismbstrail(start,cur-1) ? cur - 2 : cur -1);
330
331   return(char *)cur - 1; /* ASCII CP or SB char */
332 }
333
334 /*********************************************************************
335  *              _mbsset(MSVCRT.@)
336  */
337 char *__cdecl MSVCRT__mbsset(char *str, unsigned int c)
338 {
339   char *ret = str;
340
341   if(MSVCRT___mb_cur_max == 1 || c < 256)
342     return MSVCRT__strset(str, c); /* ASCII CP or SB char */
343
344   c &= 0xffff; /* Strip high bits */
345
346   while(str[0] && str[1])
347   {
348     *str++ = c >> 8;
349     *str++ = c & 0xff;
350   }
351   if(str[0])
352     str[0] = '\0'; /* FIXME: OK to shorten? */
353
354   return ret;
355 }
356
357 /*********************************************************************
358  *              _mbsnset(MSVCRT.@)
359  */
360 char *__cdecl MSVCRT__mbsnset(char *str, unsigned int c, unsigned int len)
361 {
362   char *ret = str;
363
364   if(!len)
365     return ret;
366
367   if(MSVCRT___mb_cur_max == 1 || c < 256)
368     return MSVCRT__strnset(str, c, len); /* ASCII CP or SB char */
369
370   c &= 0xffff; /* Strip high bits */
371
372   while(str[0] && str[1] && len--)
373   {
374     *str++ = c >> 8;
375     *str++ = c & 0xff;
376   }
377   if(len && str[0])
378     str[0] = '\0'; /* FIXME: OK to shorten? */
379
380   return ret;
381 }
382
383 /*********************************************************************
384  *              _mbstrlen(MSVCRT.@)
385  */
386 int __cdecl MSVCRT__mbstrlen(const char *str)
387 {
388   if(MSVCRT___mb_cur_max > 1)
389   {
390     int len = 0;
391     while(*str)
392     {
393       str += MSVCRT_isleadbyte(*str) ? 2 : 1;
394       len++;
395     }
396     return len;
397   }
398   return strlen(str); /* ASCII CP */
399 }
400
401 /*********************************************************************
402  *              _mbsncpy(MSVCRT.@)
403  */
404 char *__cdecl MSVCRT__mbsncpy(char *dst, const char *src, unsigned int len)
405 {
406   if(!len)
407     return dst;
408   if(MSVCRT___mb_cur_max > 1)
409   {
410     char *ret = dst;
411     while(src[0] && src[1] && len--)
412     {
413       *dst++ = *src++;
414       *dst++ = *src++;
415     }
416     if(len--)
417     {
418       *dst++ = *src++; /* Last char or '\0' */
419       while(len--)
420         *dst++ = '\0';
421     }
422     return ret;
423   }
424   return strncpy(dst, src, len); /* ASCII CP */
425 }
426
427 /*********************************************************************
428  *              _mbschr(MSVCRT.@)
429  *
430  * Find a multibyte character in a multibyte string.
431  */
432 char *__cdecl MSVCRT__mbschr(const char *str, unsigned int c)
433 {
434   if(MSVCRT___mb_cur_max > 1)
435   {
436     unsigned int next;
437     while((next = MSVCRT__mbsnextc(str)))
438     {
439       if(next == c)
440         return(char *)str;
441       str += next > 255 ? 2 : 1;
442     }
443     return c ? NULL :(char *)str;
444   }
445   return strchr(str, c); /* ASCII CP */
446 }
447
448 /*********************************************************************
449  *              _mbsnccnt(MSVCRT.@)
450  */
451 unsigned int __cdecl MSVCRT__mbsnccnt(const 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 /*********************************************************************
474  *              _mbsncat(MSVCRT.@)
475  */
476 char *__cdecl MSVCRT__mbsncat(char *dst, const char *src, unsigned int len)
477 {
478   if(MSVCRT___mb_cur_max > 1)
479   {
480     char *res = dst;
481     dst += MSVCRT__mbslen(dst);
482     while(*src && len--)
483     {
484       *dst = *src;
485       if(MSVCRT_isleadbyte(*src))
486         *++dst = *++src;
487       dst++;
488       src++;
489     }
490     *dst++ = '\0';
491     return res;
492   }
493   return strncat(dst, src, len); /* ASCII CP */
494 }
495