Updated.
[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 #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 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 __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 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 *MSVCRT__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 = MSVCRT__mbsinc(str);
149     return (char *)str;
150   }
151   return (char *)str + num; /* ASCII CP */
152 }
153
154 /*********************************************************************
155  *              _mbslen(MSVCRT.206)
156  */
157 int __cdecl MSVCRT__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 *__cdecl MSVCRT__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 __cdecl MSVCRT_mbtowc(WCHAR *dst, const unsigned 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 __cdecl MSVCRT__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 __cdecl MSVCRT__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 __cdecl MSVCRT__mbclen(const unsigned char *str)
227 {
228   return MSVCRT_isleadbyte(*str) ? 2 : 1;
229 }
230
231 /*********************************************************************
232  *              _ismbbkana(MSVCRT.@)
233  */
234 int __cdecl MSVCRT__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 __cdecl MSVCRT__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 __cdecl MSVCRT__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 MSVCRT__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 __cdecl MSVCRT__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 __cdecl MSVCRT__ismbbtrail(unsigned int c)
289 {
290   /* FIXME: should reference MSVCRT_mbctype */
291   return !MSVCRT__ismbblead(c);
292 }
293
294 /*********************************************************************
295  *              _ismbslead(MSVCRT.@)
296  */
297 int __cdecl MSVCRT__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 __cdecl MSVCRT__ismbstrail(const char *start, const unsigned char *str)
317 {
318   /* Must not be a lead, and must be preceeded by one */
319   return !MSVCRT__ismbslead(start, str) && MSVCRT_isleadbyte(str[-1]);
320 }
321
322 /*********************************************************************
323  *              _mbsdec(MSVCRT.@)
324  */
325 char *__cdecl MSVCRT__mbsdec(const char *start, const char *cur)
326 {
327   if(MSVCRT___mb_cur_max > 1)
328     return (char *)(MSVCRT__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 *__cdecl MSVCRT__mbsset(char *str, unsigned int c)
337 {
338   char *ret = str;
339
340   if(MSVCRT___mb_cur_max == 1 || c < 256)
341     return MSVCRT__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 *__cdecl MSVCRT__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 MSVCRT__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 int __cdecl MSVCRT__mbstrlen(const unsigned 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 *__cdecl MSVCRT__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 char *__cdecl MSVCRT__mbschr(const char *str, unsigned int c)
432 {
433   if(MSVCRT___mb_cur_max > 1)
434   {
435     unsigned int next;
436     while((next = MSVCRT__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 __cdecl MSVCRT__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 char *__cdecl MSVCRT__mbsncat(char *dst, const unsigned char *src, unsigned int len)
476 {
477   if(MSVCRT___mb_cur_max > 1)
478   {
479     char *res = dst;
480     dst += MSVCRT__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