Implemented multibyte string reverse.
[wine/wine-kai.git] / dlls / msvcrt / mbcs.c
blobf144e9fa11fd69432902a52d1283f773c9cfdadd
1 /*
2 * msvcrt.dll mbcs functions
4 * Copyright 1999 Alexandre Julliard
5 * Copyright 2000 Jon Griffths
7 * FIXME
8 * Not currently binary compatible with win32. MSVCRT_mbctype must be
9 * populated correctly and the ismb* functions should reference it.
12 #include "msvcrt.h"
14 #include "msvcrt/stdlib.h"
15 #include "msvcrt/string.h"
16 #include "msvcrt/wctype.h"
19 DEFAULT_DEBUG_CHANNEL(msvcrt);
21 unsigned char MSVCRT_mbctype[257];
22 int MSVCRT___mb_cur_max = 1;
24 /*********************************************************************
25 * __p__mbctype (MSVCRT.@)
27 unsigned char *__p__mbctype(void)
29 return MSVCRT_mbctype;
32 /*********************************************************************
33 * __p___mb_cur_max(MSVCRT.@)
35 int *__p___mb_cur_max(void)
37 return &MSVCRT___mb_cur_max;
40 /*********************************************************************
41 * _mbsnextc(MSVCRT.@)
43 unsigned int _mbsnextc(const unsigned char *str)
45 if(MSVCRT___mb_cur_max > 1 && MSVCRT_isleadbyte(*str))
46 return *str << 8 | str[1];
47 return *str; /* ASCII CP or SB char */
50 /*********************************************************************
51 * _mbscmp(MSVCRT.@)
53 int _mbscmp(const char *str, const char *cmp)
55 if(MSVCRT___mb_cur_max > 1)
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);
71 return strcmp(str, cmp); /* ASCII CP */
74 /*********************************************************************
75 * _mbsicmp(MSVCRT.@)
77 int _mbsicmp(const char *str, const char *cmp)
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 */
85 /*********************************************************************
86 * _mbsncmp (MSVCRT.@)
88 int _mbsncmp(const char *str, const char *cmp, unsigned int len)
90 if(!len)
91 return 0;
93 if(MSVCRT___mb_cur_max > 1)
95 unsigned int strc, cmpc;
96 while(len--)
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 */
109 return 0; /* Matched len chars */
111 return strncmp(str, cmp, len); /* ASCII CP */
114 /*********************************************************************
115 * _mbsnicmp(MSVCRT.@)
117 * Compare two multibyte strings case insensitively to 'len' characters.
119 int _mbsnicmp(const char *str, const char *cmp, unsigned int len)
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 */
127 /*********************************************************************
128 * _mbsinc(MSVCRT.@)
130 char *_mbsinc(const unsigned char *str)
132 if(MSVCRT___mb_cur_max > 1 && MSVCRT_isleadbyte(*str))
133 return (char *)str + 2; /* MB char */
135 return (char *)str + 1; /* ASCII CP or SB char */
138 /*********************************************************************
139 * _mbsninc(MSVCRT.@)
141 char *_mbsninc(const char *str, unsigned int num)
143 if(!str || num < 1)
144 return NULL;
145 if(MSVCRT___mb_cur_max > 1)
147 while(num--)
148 str = _mbsinc(str);
149 return (char *)str;
151 return (char *)str + num; /* ASCII CP */
154 /*********************************************************************
155 * _mbslen(MSVCRT.@)
157 int _mbslen(const unsigned char *str)
159 if(MSVCRT___mb_cur_max > 1)
161 int len = 0;
162 while(*str)
164 str += MSVCRT_isleadbyte(*str) ? 2 : 1;
165 len++;
167 return len;
169 return strlen(str); /* ASCII CP */
172 /*********************************************************************
173 * _mbsrchr(MSVCRT.@)
175 char *_mbsrchr(const char *s,unsigned int x)
177 /* FIXME: handle multibyte strings */
178 return strrchr(s,x);
181 /*********************************************************************
182 * mbtowc(MSVCRT.@)
184 int MSVCRT_mbtowc(WCHAR *dst, const char *str, unsigned int n)
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;
198 /*********************************************************************
199 * _mbccpy(MSVCRT.@)
201 void _mbccpy(char *dest, const unsigned char *src)
203 *dest++ = *src;
204 if(MSVCRT___mb_cur_max > 1 && MSVCRT_isleadbyte(*src))
205 *dest = *++src; /* MB char */
208 /*********************************************************************
209 * _mbbtombc(MSVCRT.@)
211 unsigned int _mbbtombc(unsigned int c)
213 if(MSVCRT___mb_cur_max > 1 &&
214 ((c >= 0x20 && c <=0x7e) ||(c >= 0xa1 && c <= 0xdf)))
216 /* FIXME: I can't get this function to return anything
217 * different to what I pass it...
220 return c; /* ASCII CP or no MB char */
223 /*********************************************************************
224 * _mbclen(MSVCRT.@)
226 unsigned int _mbclen(const unsigned char *str)
228 return MSVCRT_isleadbyte(*str) ? 2 : 1;
231 /*********************************************************************
232 * _ismbbkana(MSVCRT.@)
234 int _ismbbkana(unsigned int c)
236 /* FIXME: use lc_ctype when supported, not lc_all */
237 if(MSVCRT_current_lc_all_cp == 932)
239 /* Japanese/Katakana, CP 932 */
240 return (c >= 0xa1 && c <= 0xdf);
242 return 0;
245 /*********************************************************************
246 * _ismbchira(MSVCRT.@)
248 int _ismbchira(unsigned int c)
250 /* FIXME: use lc_ctype when supported, not lc_all */
251 if(MSVCRT_current_lc_all_cp == 932)
253 /* Japanese/Hiragana, CP 932 */
254 return (c >= 0x829f && c <= 0x82f1);
256 return 0;
259 /*********************************************************************
260 * _ismbckata(MSVCRT.@)
262 int _ismbckata(unsigned int c)
264 /* FIXME: use lc_ctype when supported, not lc_all */
265 if(MSVCRT_current_lc_all_cp == 932)
267 if(c < 256)
268 return _ismbbkana(c);
269 /* Japanese/Katakana, CP 932 */
270 return (c >= 0x8340 && c <= 0x8396 && c != 0x837f);
272 return 0;
275 /*********************************************************************
276 * _ismbblead(MSVCRT.@)
278 int _ismbblead(unsigned int c)
280 /* FIXME: should reference MSVCRT_mbctype */
281 return MSVCRT___mb_cur_max > 1 && MSVCRT_isleadbyte(c);
285 /*********************************************************************
286 * _ismbbtrail(MSVCRT.@)
288 int _ismbbtrail(unsigned int c)
290 /* FIXME: should reference MSVCRT_mbctype */
291 return !_ismbblead(c);
294 /*********************************************************************
295 * _ismbslead(MSVCRT.@)
297 int _ismbslead(const unsigned char *start, const unsigned char *str)
299 /* Lead bytes can also be trail bytes if caller messed up
300 * iterating through the string...
302 if(MSVCRT___mb_cur_max > 1)
304 while(start < str)
305 start += MSVCRT_isleadbyte(*str) ? 2 : 1;
307 if(start == str)
308 return MSVCRT_isleadbyte(*str);
310 return 0; /* Must have been a trail, we skipped it */
313 /*********************************************************************
314 * _ismbstrail(MSVCRT.@)
316 int _ismbstrail(const char *start, const unsigned char *str)
318 /* Must not be a lead, and must be preceeded by one */
319 return !_ismbslead(start, str) && MSVCRT_isleadbyte(str[-1]);
322 /*********************************************************************
323 * _mbsdec(MSVCRT.@)
325 char *_mbsdec(const char *start, const char *cur)
327 if(MSVCRT___mb_cur_max > 1)
328 return (char *)(_ismbstrail(start,cur-1) ? cur - 2 : cur -1);
330 return (char *)cur - 1; /* ASCII CP or SB char */
333 /*********************************************************************
334 * _mbsset(MSVCRT.@)
336 char *_mbsset(char *str, unsigned int c)
338 char *ret = str;
340 if(MSVCRT___mb_cur_max == 1 || c < 256)
341 return _strset(str, c); /* ASCII CP or SB char */
343 c &= 0xffff; /* Strip high bits */
345 while(str[0] && str[1])
347 *str++ = c >> 8;
348 *str++ = c & 0xff;
350 if(str[0])
351 str[0] = '\0'; /* FIXME: OK to shorten? */
353 return ret;
356 /*********************************************************************
357 * _mbsnset(MSVCRT.@)
359 char *_mbsnset(char *str, unsigned int c, unsigned int len)
361 char *ret = str;
363 if(!len)
364 return ret;
366 if(MSVCRT___mb_cur_max == 1 || c < 256)
367 return _strnset(str, c, len); /* ASCII CP or SB char */
369 c &= 0xffff; /* Strip high bits */
371 while(str[0] && str[1] && len--)
373 *str++ = c >> 8;
374 *str++ = c & 0xff;
376 if(len && str[0])
377 str[0] = '\0'; /* FIXME: OK to shorten? */
379 return ret;
382 /*********************************************************************
383 * _mbstrlen(MSVCRT.@)
385 MSVCRT_size_t _mbstrlen(const char *str)
387 if(MSVCRT___mb_cur_max > 1)
389 int len = 0;
390 while(*str)
392 str += MSVCRT_isleadbyte(*str) ? 2 : 1;
393 len++;
395 return len;
397 return strlen(str); /* ASCII CP */
400 /*********************************************************************
401 * _mbsncpy(MSVCRT.@)
403 char *_mbsncpy(char *dst, const char *src, unsigned int len)
405 if(!len)
406 return dst;
407 if(MSVCRT___mb_cur_max > 1)
409 char *ret = dst;
410 while(src[0] && src[1] && len--)
412 *dst++ = *src++;
413 *dst++ = *src++;
415 if(len--)
417 *dst++ = *src++; /* Last char or '\0' */
418 while(len--)
419 *dst++ = '\0';
421 return ret;
423 return strncpy(dst, src, len); /* ASCII CP */
426 /*********************************************************************
427 * _mbschr(MSVCRT.@)
429 * Find a multibyte character in a multibyte string.
431 unsigned char* _mbschr(const unsigned char* str, unsigned int c)
433 if(MSVCRT___mb_cur_max > 1)
435 unsigned int next;
436 while((next = _mbsnextc(str)))
438 if(next == c)
439 return (char *)str;
440 str += next > 255 ? 2 : 1;
442 return c ? NULL :(char *)str;
444 return strchr(str, c); /* ASCII CP */
447 /*********************************************************************
448 * _mbsnccnt(MSVCRT.@)
450 unsigned int _mbsnccnt(const unsigned char *str, unsigned int len)
452 int ret = 0;
454 if(MSVCRT___mb_cur_max > 1)
456 while(*str && len-- > 0)
458 if(MSVCRT_isleadbyte(*str))
460 str++;
461 len--;
463 ret++;
464 str++;
466 return ret;
468 return min(strlen(str), len); /* ASCII CP */
472 /*********************************************************************
473 * _mbsncat(MSVCRT.@)
475 unsigned char* _mbsncat(unsigned char* dst, const unsigned char* src, MSVCRT_size_t len)
477 if(MSVCRT___mb_cur_max > 1)
479 char *res = dst;
480 dst += _mbslen(dst);
481 while(*src && len--)
483 *dst = *src;
484 if(MSVCRT_isleadbyte(*src))
485 *++dst = *++src;
486 dst++;
487 src++;
489 *dst++ = '\0';
490 return res;
492 return strncat(dst, src, len); /* ASCII CP */
496 /*********************************************************************
497 * _ismbcdigit(MSVCRT.@)
499 int _ismbcdigit( unsigned int ch)
501 if (ch <0x100)
502 return isdigit(ch);
503 else
505 FIXME("Handle MBC chars\n");
506 return 0;
511 /*********************************************************************
512 * _mbsnbcmp(MSVCRT.@)
514 int _mbsnbcmp( const unsigned char *str,const unsigned char *cmp, MSVCRT_size_t len )
516 if (!len)
517 return 0;
518 if(MSVCRT___mb_cur_max > 1)
520 FIXME("%s %s %d\n",str,cmp,len);
521 return 0;
523 return strncmp(str,cmp,len);
527 /*********************************************************************
528 * _mbslwr(MSVCRT.@)
530 unsigned char * _mbslwr( unsigned char *string )
532 unsigned char *p;
534 if(MSVCRT___mb_cur_max > 1)
536 FIXME("%s\n",string);
537 return string;
539 p = string;
540 while (*p)
542 *p= tolower(*p);
543 p++;
545 return string;
549 /*********************************************************************
550 * _mbsnbcpy(MSVCRT.@)
552 unsigned char * _mbsnbcpy(unsigned char *dest,const unsigned char *src,MSVCRT_size_t n)
554 if(MSVCRT___mb_cur_max > 1)
556 FIXME("%s %d\n",src,n);
557 return dest;
559 return strncpy(dest, src, n);
563 /*********************************************************************
564 * _mbsspn (MSVCRT.@)
566 MSVCRT_size_t _mbsspn(const unsigned char *string, const unsigned char *set)
568 const unsigned char *p, *q;
570 for (p = string; *p; p++)
572 if (MSVCRT_isleadbyte(*p))
574 for (q = set; *q; q++)
576 if (!q[1])
577 break;
578 if ((*p == *q) && (p[1] == q[1]))
579 break;
580 q++;
582 if (*++p == '\0')
583 break;
585 else
586 for (q = set; *q; q++)
587 if (*p == *q)
588 break;
590 return p - string;
594 /*********************************************************************
595 * _ismbcspace (MSVCRT.@)
597 int _ismbcspace( unsigned int c)
600 if (c <0x100)
601 return isspace(c);
602 FIXME("%c\n",c);
603 return 0;
606 /*********************************************************************
607 * _mbsrev (MSVCRT.@)
609 char *_mbsrev(char *str)
611 int i, len = _mbslen(str);
612 char *p, *temp=MSVCRT_malloc(len*2);
614 if(!temp)
615 return str;
617 /* unpack multibyte string to temp buffer */
618 p=str;
619 for(i=0; i<len; i++)
621 if (MSVCRT_isleadbyte(*p))
623 temp[i*2]=*p++;
624 temp[i*2+1]=*p++;
626 else
628 temp[i*2]=*p++;
629 temp[i*2+1]=0;
633 /* repack it in the reverse order */
634 p=str;
635 for(i=len-1; i>=0; i--)
637 if(MSVCRT_isleadbyte(temp[i*2]))
639 *p++=temp[i*2];
640 *p++=temp[i*2+1];
642 else
644 *p++=temp[i*2];
648 MSVCRT_free(temp);
650 return str;