Added an unknown VxD error code.
[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 #include "msvcrt/string.h"
14
15
16 DEFAULT_DEBUG_CHANNEL(msvcrt);
17
18 unsigned char MSVCRT_mbctype[257];
19 int MSVCRT___mb_cur_max = 1;
20
21 int MSVCRT_isleadbyte(int);
22 char *_strset(char *, int);
23 char *_strnset(char *, int, unsigned int);
24 extern unsigned int MSVCRT_current_lc_all_cp;
25
26
27 /*********************************************************************
28  *              __p__mbctype (MSVCRT.@)
29  */
30 unsigned char *__p__mbctype(void)
31 {
32   return MSVCRT_mbctype;
33 }
34
35 /*********************************************************************
36  *              __p___mb_cur_max(MSVCRT.@)
37  */
38 int *__p___mb_cur_max(void)
39 {
40   return &MSVCRT___mb_cur_max;
41 }
42
43 /*********************************************************************
44  *              _mbsnextc(MSVCRT.@)
45  */
46 unsigned int _mbsnextc(const unsigned char *str)
47 {
48   if(MSVCRT___mb_cur_max > 1 && MSVCRT_isleadbyte(*str))
49     return *str << 8 | str[1];
50   return *str; /* ASCII CP or SB char */
51 }
52
53 /*********************************************************************
54  *              _mbscmp(MSVCRT.@)
55  */
56 int _mbscmp(const char *str, const char *cmp)
57 {
58   if(MSVCRT___mb_cur_max > 1)
59   {
60     unsigned int strc, cmpc;
61     do {
62       if(!*str)
63         return *cmp ? -1 : 0;
64       if(!*cmp)
65         return 1;
66       strc = _mbsnextc(str);
67       cmpc = _mbsnextc(cmp);
68       if(strc != cmpc)
69         return strc < cmpc ? -1 : 1;
70       str +=(strc > 255) ? 2 : 1;
71       cmp +=(strc > 255) ? 2 : 1; /* equal, use same increment */
72     } while(1);
73   }
74   return strcmp(str, cmp); /* ASCII CP */
75 }
76
77 /*********************************************************************
78  *              _mbsicmp(MSVCRT.@)
79  */
80 int _mbsicmp(const char *str, const char *cmp)
81 {
82   /* FIXME: No tolower() for mb strings yet */
83   if(MSVCRT___mb_cur_max > 1)
84     return _mbscmp(str, cmp);
85   return strcasecmp(str, cmp); /* ASCII CP */
86 }
87
88 /*********************************************************************
89  *              _mbsncmp    (MSVCRT.@)
90  */
91 int _mbsncmp(const char *str, const char *cmp, unsigned int len)
92 {
93   if(!len)
94     return 0;
95
96   if(MSVCRT___mb_cur_max > 1)
97   {
98     unsigned int strc, cmpc;
99     while(len--)
100     {
101       if(!*str)
102         return *cmp ? -1 : 0;
103       if(!*cmp)
104         return 1;
105       strc = _mbsnextc(str);
106       cmpc = _mbsnextc(cmp);
107       if(strc != cmpc)
108         return strc < cmpc ? -1 : 1;
109       str +=(strc > 255) ? 2 : 1;
110       cmp +=(strc > 255) ? 2 : 1; /* Equal, use same increment */
111     }
112     return 0; /* Matched len chars */
113   }
114   return strncmp(str, cmp, len); /* ASCII CP */
115 }
116
117 /*********************************************************************
118  *                  _mbsnicmp(MSVCRT.@)
119  *
120  * Compare two multibyte strings case insensitively to 'len' characters.
121  */
122 int _mbsnicmp(const char *str, const char *cmp, unsigned int len)
123 {
124   /* FIXME: No tolower() for mb strings yet */
125   if(MSVCRT___mb_cur_max > 1)
126     return _mbsncmp(str, cmp, len);
127   return strncasecmp(str, cmp, len); /* ASCII CP */
128 }
129
130 /*********************************************************************
131  *              _mbsinc(MSVCRT.@)
132  */
133 char *_mbsinc(const unsigned char *str)
134 {
135   if(MSVCRT___mb_cur_max > 1 && MSVCRT_isleadbyte(*str))
136     return (char *)str + 2; /* MB char */
137
138   return (char *)str + 1; /* ASCII CP or SB char */
139 }
140
141 /*********************************************************************
142  *              _mbsninc(MSVCRT.@)
143  */
144 char *_mbsninc(const char *str, unsigned int num)
145 {
146   if(!str || num < 1)
147     return NULL;
148   if(MSVCRT___mb_cur_max > 1)
149   {
150     while(num--)
151       str = _mbsinc(str);
152     return (char *)str;
153   }
154   return (char *)str + num; /* ASCII CP */
155 }
156
157 /*********************************************************************
158  *              _mbslen(MSVCRT.206)
159  */
160 int _mbslen(const unsigned char *str)
161 {
162   if(MSVCRT___mb_cur_max > 1)
163   {
164     int len = 0;
165     while(*str)
166     {
167       str += MSVCRT_isleadbyte(*str) ? 2 : 1;
168       len++;
169     }
170     return len;
171   }
172   return strlen(str); /* ASCII CP */
173 }
174
175 /*********************************************************************
176  *              _mbsrchr(MSVCRT.@)
177  */
178 char *_mbsrchr(const char *s,unsigned int x)
179 {
180   /* FIXME: handle multibyte strings */
181   return strrchr(s,x);
182 }
183
184 /*********************************************************************
185  *              mbtowc(MSVCRT.@)
186  */
187 int MSVCRT_mbtowc(WCHAR *dst, const unsigned char *str, unsigned int n)
188 {
189   if(n <= 0 || !str)
190     return 0;
191   if(!MultiByteToWideChar(CP_ACP, 0, str, n, dst, 1))
192     return 0;
193   /* return the number of bytes from src that have been used */
194   if(!*str)
195     return 0;
196   if(n >= 2 && MSVCRT_isleadbyte(*str) && str[1])
197     return 2;
198   return 1;
199 }
200
201 /*********************************************************************
202  *              _mbccpy(MSVCRT.@)
203  */
204 void _mbccpy(char *dest, const unsigned char *src)
205 {
206   *dest++ = *src;
207   if(MSVCRT___mb_cur_max > 1 && MSVCRT_isleadbyte(*src))
208     *dest = *++src; /* MB char */
209 }
210
211 /*********************************************************************
212  *              _mbbtombc(MSVCRT.@)
213  */
214 unsigned int _mbbtombc(unsigned int c)
215 {
216   if(MSVCRT___mb_cur_max > 1 &&
217      ((c >= 0x20 && c <=0x7e) ||(c >= 0xa1 && c <= 0xdf)))
218   {
219     /* FIXME: I can't get this function to return anything
220      * different to what I pass it...
221      */
222   }
223   return c;  /* ASCII CP or no MB char */
224 }
225
226 /*********************************************************************
227  *              _mbclen(MSVCRT.@)
228  */
229 unsigned int _mbclen(const unsigned char *str)
230 {
231   return MSVCRT_isleadbyte(*str) ? 2 : 1;
232 }
233
234 /*********************************************************************
235  *              _ismbbkana(MSVCRT.@)
236  */
237 int _ismbbkana(unsigned int c)
238 {
239   /* FIXME: use lc_ctype when supported, not lc_all */
240   if(MSVCRT_current_lc_all_cp == 932)
241   {
242     /* Japanese/Katakana, CP 932 */
243     return (c >= 0xa1 && c <= 0xdf);
244   }
245   return 0;
246 }
247
248 /*********************************************************************
249  *              _ismbchira(MSVCRT.@)
250  */
251 int _ismbchira(unsigned int c)
252 {
253   /* FIXME: use lc_ctype when supported, not lc_all */
254   if(MSVCRT_current_lc_all_cp == 932)
255   {
256     /* Japanese/Hiragana, CP 932 */
257     return (c >= 0x829f && c <= 0x82f1);
258   }
259   return 0;
260 }
261
262 /*********************************************************************
263  *              _ismbckata(MSVCRT.@)
264  */
265 int _ismbckata(unsigned int c)
266 {
267   /* FIXME: use lc_ctype when supported, not lc_all */
268   if(MSVCRT_current_lc_all_cp == 932)
269   {
270     if(c < 256)
271       return _ismbbkana(c);
272     /* Japanese/Katakana, CP 932 */
273     return (c >= 0x8340 && c <= 0x8396 && c != 0x837f);
274   }
275   return 0;
276 }
277
278 /*********************************************************************
279  *              _ismbblead(MSVCRT.@)
280  */
281 int _ismbblead(unsigned int c)
282 {
283   /* FIXME: should reference MSVCRT_mbctype */
284   return MSVCRT___mb_cur_max > 1 && MSVCRT_isleadbyte(c);
285 }
286
287
288 /*********************************************************************
289  *              _ismbbtrail(MSVCRT.@)
290  */
291 int _ismbbtrail(unsigned int c)
292 {
293   /* FIXME: should reference MSVCRT_mbctype */
294   return !_ismbblead(c);
295 }
296
297 /*********************************************************************
298  *              _ismbslead(MSVCRT.@)
299  */
300 int _ismbslead(const unsigned char *start, const unsigned char *str)
301 {
302   /* Lead bytes can also be trail bytes if caller messed up
303    * iterating through the string...
304    */
305   if(MSVCRT___mb_cur_max > 1)
306   {
307     while(start < str)
308       start += MSVCRT_isleadbyte(*str) ? 2 : 1;
309
310     if(start == str)
311       return MSVCRT_isleadbyte(*str);
312   }
313   return 0; /* Must have been a trail, we skipped it */
314 }
315
316 /*********************************************************************
317  *              _ismbstrail(MSVCRT.@)
318  */
319 int _ismbstrail(const char *start, const unsigned char *str)
320 {
321   /* Must not be a lead, and must be preceeded by one */
322   return !_ismbslead(start, str) && MSVCRT_isleadbyte(str[-1]);
323 }
324
325 /*********************************************************************
326  *              _mbsdec(MSVCRT.@)
327  */
328 char *_mbsdec(const char *start, const char *cur)
329 {
330   if(MSVCRT___mb_cur_max > 1)
331     return (char *)(_ismbstrail(start,cur-1) ? cur - 2 : cur -1);
332
333   return (char *)cur - 1; /* ASCII CP or SB char */
334 }
335
336 /*********************************************************************
337  *              _mbsset(MSVCRT.@)
338  */
339 char *_mbsset(char *str, unsigned int c)
340 {
341   char *ret = str;
342
343   if(MSVCRT___mb_cur_max == 1 || c < 256)
344     return _strset(str, c); /* ASCII CP or SB char */
345
346   c &= 0xffff; /* Strip high bits */
347
348   while(str[0] && str[1])
349   {
350     *str++ = c >> 8;
351     *str++ = c & 0xff;
352   }
353   if(str[0])
354     str[0] = '\0'; /* FIXME: OK to shorten? */
355
356   return ret;
357 }
358
359 /*********************************************************************
360  *              _mbsnset(MSVCRT.@)
361  */
362 char *_mbsnset(char *str, unsigned int c, unsigned int len)
363 {
364   char *ret = str;
365
366   if(!len)
367     return ret;
368
369   if(MSVCRT___mb_cur_max == 1 || c < 256)
370     return _strnset(str, c, len); /* ASCII CP or SB char */
371
372   c &= 0xffff; /* Strip high bits */
373
374   while(str[0] && str[1] && len--)
375   {
376     *str++ = c >> 8;
377     *str++ = c & 0xff;
378   }
379   if(len && str[0])
380     str[0] = '\0'; /* FIXME: OK to shorten? */
381
382   return ret;
383 }
384
385 /*********************************************************************
386  *              _mbstrlen(MSVCRT.@)
387  */
388 int _mbstrlen(const unsigned char *str)
389 {
390   if(MSVCRT___mb_cur_max > 1)
391   {
392     int len = 0;
393     while(*str)
394     {
395       str += MSVCRT_isleadbyte(*str) ? 2 : 1;
396       len++;
397     }
398     return len;
399   }
400   return strlen(str); /* ASCII CP */
401 }
402
403 /*********************************************************************
404  *              _mbsncpy(MSVCRT.@)
405  */
406 char *_mbsncpy(char *dst, const char *src, unsigned int len)
407 {
408   if(!len)
409     return dst;
410   if(MSVCRT___mb_cur_max > 1)
411   {
412     char *ret = dst;
413     while(src[0] && src[1] && len--)
414     {
415       *dst++ = *src++;
416       *dst++ = *src++;
417     }
418     if(len--)
419     {
420       *dst++ = *src++; /* Last char or '\0' */
421       while(len--)
422         *dst++ = '\0';
423     }
424     return ret;
425   }
426   return strncpy(dst, src, len); /* ASCII CP */
427 }
428
429 /*********************************************************************
430  *              _mbschr(MSVCRT.@)
431  *
432  * Find a multibyte character in a multibyte string.
433  */
434 unsigned char* _mbschr(const unsigned char* str, unsigned int c)
435 {
436   if(MSVCRT___mb_cur_max > 1)
437   {
438     unsigned int next;
439     while((next = _mbsnextc(str)))
440     {
441       if(next == c)
442         return (char *)str;
443       str += next > 255 ? 2 : 1;
444     }
445     return c ? NULL :(char *)str;
446   }
447   return strchr(str, c); /* ASCII CP */
448 }
449
450 /*********************************************************************
451  *              _mbsnccnt(MSVCRT.@)
452  */
453 unsigned int _mbsnccnt(const unsigned char *str, unsigned int len)
454 {
455   int ret = 0;
456
457   if(MSVCRT___mb_cur_max > 1)
458   {
459     while(*str && len-- > 0)
460     {
461       if(MSVCRT_isleadbyte(*str))
462       {
463         str++;
464         len--;
465       }
466       ret++;
467       str++;
468     }
469     return ret;
470   }
471   return min(strlen(str), len); /* ASCII CP */
472 }
473
474
475 /*********************************************************************
476  *              _mbsncat(MSVCRT.@)
477  */
478 unsigned char* _mbsncat(unsigned char* dst, const unsigned char* src, MSVCRT_size_t len)
479 {
480   if(MSVCRT___mb_cur_max > 1)
481   {
482     char *res = dst;
483     dst += _mbslen(dst);
484     while(*src && len--)
485     {
486       *dst = *src;
487       if(MSVCRT_isleadbyte(*src))
488         *++dst = *++src;
489       dst++;
490       src++;
491     }
492     *dst++ = '\0';
493     return res;
494   }
495   return strncat(dst, src, len); /* ASCII CP */
496 }
497