| /* | |
| * msvcrt.dll mbcs functions | |
| * | |
| * Copyright 1999 Alexandre Julliard | |
| * Copyright 2000 Jon Griffths | |
| * | |
| * FIXME | |
| * Not currently binary compatible with win32. MSVCRT_mbctype must be | |
| * populated correctly and the ismb* functions should reference it. | |
| */ | |
| #include "msvcrt.h" | |
| #include "msvcrt/string.h" | |
| DEFAULT_DEBUG_CHANNEL(msvcrt); | |
| unsigned char MSVCRT_mbctype[257]; | |
| int MSVCRT___mb_cur_max = 1; | |
| int MSVCRT_isleadbyte(int); | |
| char *_strset(char *, int); | |
| char *_strnset(char *, int, unsigned int); | |
| extern unsigned int MSVCRT_current_lc_all_cp; | |
| /********************************************************************* | |
| * __p__mbctype (MSVCRT.@) | |
| */ | |
| unsigned char *__p__mbctype(void) | |
| { | |
| return MSVCRT_mbctype; | |
| } | |
| /********************************************************************* | |
| * __p___mb_cur_max(MSVCRT.@) | |
| */ | |
| int *__p___mb_cur_max(void) | |
| { | |
| return &MSVCRT___mb_cur_max; | |
| } | |
| /********************************************************************* | |
| * _mbsnextc(MSVCRT.@) | |
| */ | |
| unsigned int _mbsnextc(const unsigned char *str) | |
| { | |
| if(MSVCRT___mb_cur_max > 1 && MSVCRT_isleadbyte(*str)) | |
| return *str << 8 | str[1]; | |
| return *str; /* ASCII CP or SB char */ | |
| } | |
| /********************************************************************* | |
| * _mbscmp(MSVCRT.@) | |
| */ | |
| int _mbscmp(const char *str, const char *cmp) | |
| { | |
| if(MSVCRT___mb_cur_max > 1) | |
| { | |
| unsigned int strc, cmpc; | |
| do { | |
| if(!*str) | |
| return *cmp ? -1 : 0; | |
| if(!*cmp) | |
| return 1; | |
| strc = _mbsnextc(str); | |
| cmpc = _mbsnextc(cmp); | |
| if(strc != cmpc) | |
| return strc < cmpc ? -1 : 1; | |
| str +=(strc > 255) ? 2 : 1; | |
| cmp +=(strc > 255) ? 2 : 1; /* equal, use same increment */ | |
| } while(1); | |
| } | |
| return strcmp(str, cmp); /* ASCII CP */ | |
| } | |
| /********************************************************************* | |
| * _mbsicmp(MSVCRT.@) | |
| */ | |
| int _mbsicmp(const char *str, const char *cmp) | |
| { | |
| /* FIXME: No tolower() for mb strings yet */ | |
| if(MSVCRT___mb_cur_max > 1) | |
| return _mbscmp(str, cmp); | |
| return strcasecmp(str, cmp); /* ASCII CP */ | |
| } | |
| /********************************************************************* | |
| * _mbsncmp (MSVCRT.@) | |
| */ | |
| int _mbsncmp(const char *str, const char *cmp, unsigned int len) | |
| { | |
| if(!len) | |
| return 0; | |
| if(MSVCRT___mb_cur_max > 1) | |
| { | |
| unsigned int strc, cmpc; | |
| while(len--) | |
| { | |
| if(!*str) | |
| return *cmp ? -1 : 0; | |
| if(!*cmp) | |
| return 1; | |
| strc = _mbsnextc(str); | |
| cmpc = _mbsnextc(cmp); | |
| if(strc != cmpc) | |
| return strc < cmpc ? -1 : 1; | |
| str +=(strc > 255) ? 2 : 1; | |
| cmp +=(strc > 255) ? 2 : 1; /* Equal, use same increment */ | |
| } | |
| return 0; /* Matched len chars */ | |
| } | |
| return strncmp(str, cmp, len); /* ASCII CP */ | |
| } | |
| /********************************************************************* | |
| * _mbsnicmp(MSVCRT.@) | |
| * | |
| * Compare two multibyte strings case insensitively to 'len' characters. | |
| */ | |
| int _mbsnicmp(const char *str, const char *cmp, unsigned int len) | |
| { | |
| /* FIXME: No tolower() for mb strings yet */ | |
| if(MSVCRT___mb_cur_max > 1) | |
| return _mbsncmp(str, cmp, len); | |
| return strncasecmp(str, cmp, len); /* ASCII CP */ | |
| } | |
| /********************************************************************* | |
| * _mbsinc(MSVCRT.@) | |
| */ | |
| char *_mbsinc(const unsigned char *str) | |
| { | |
| if(MSVCRT___mb_cur_max > 1 && MSVCRT_isleadbyte(*str)) | |
| return (char *)str + 2; /* MB char */ | |
| return (char *)str + 1; /* ASCII CP or SB char */ | |
| } | |
| /********************************************************************* | |
| * _mbsninc(MSVCRT.@) | |
| */ | |
| char *_mbsninc(const char *str, unsigned int num) | |
| { | |
| if(!str || num < 1) | |
| return NULL; | |
| if(MSVCRT___mb_cur_max > 1) | |
| { | |
| while(num--) | |
| str = _mbsinc(str); | |
| return (char *)str; | |
| } | |
| return (char *)str + num; /* ASCII CP */ | |
| } | |
| /********************************************************************* | |
| * _mbslen(MSVCRT.206) | |
| */ | |
| int _mbslen(const unsigned char *str) | |
| { | |
| if(MSVCRT___mb_cur_max > 1) | |
| { | |
| int len = 0; | |
| while(*str) | |
| { | |
| str += MSVCRT_isleadbyte(*str) ? 2 : 1; | |
| len++; | |
| } | |
| return len; | |
| } | |
| return strlen(str); /* ASCII CP */ | |
| } | |
| /********************************************************************* | |
| * _mbsrchr(MSVCRT.@) | |
| */ | |
| char *_mbsrchr(const char *s,unsigned int x) | |
| { | |
| /* FIXME: handle multibyte strings */ | |
| return strrchr(s,x); | |
| } | |
| /********************************************************************* | |
| * mbtowc(MSVCRT.@) | |
| */ | |
| int MSVCRT_mbtowc(WCHAR *dst, const unsigned char *str, unsigned int n) | |
| { | |
| if(n <= 0 || !str) | |
| return 0; | |
| if(!MultiByteToWideChar(CP_ACP, 0, str, n, dst, 1)) | |
| return 0; | |
| /* return the number of bytes from src that have been used */ | |
| if(!*str) | |
| return 0; | |
| if(n >= 2 && MSVCRT_isleadbyte(*str) && str[1]) | |
| return 2; | |
| return 1; | |
| } | |
| /********************************************************************* | |
| * _mbccpy(MSVCRT.@) | |
| */ | |
| void _mbccpy(char *dest, const unsigned char *src) | |
| { | |
| *dest++ = *src; | |
| if(MSVCRT___mb_cur_max > 1 && MSVCRT_isleadbyte(*src)) | |
| *dest = *++src; /* MB char */ | |
| } | |
| /********************************************************************* | |
| * _mbbtombc(MSVCRT.@) | |
| */ | |
| unsigned int _mbbtombc(unsigned int c) | |
| { | |
| if(MSVCRT___mb_cur_max > 1 && | |
| ((c >= 0x20 && c <=0x7e) ||(c >= 0xa1 && c <= 0xdf))) | |
| { | |
| /* FIXME: I can't get this function to return anything | |
| * different to what I pass it... | |
| */ | |
| } | |
| return c; /* ASCII CP or no MB char */ | |
| } | |
| /********************************************************************* | |
| * _mbclen(MSVCRT.@) | |
| */ | |
| unsigned int _mbclen(const unsigned char *str) | |
| { | |
| return MSVCRT_isleadbyte(*str) ? 2 : 1; | |
| } | |
| /********************************************************************* | |
| * _ismbbkana(MSVCRT.@) | |
| */ | |
| int _ismbbkana(unsigned int c) | |
| { | |
| /* FIXME: use lc_ctype when supported, not lc_all */ | |
| if(MSVCRT_current_lc_all_cp == 932) | |
| { | |
| /* Japanese/Katakana, CP 932 */ | |
| return (c >= 0xa1 && c <= 0xdf); | |
| } | |
| return 0; | |
| } | |
| /********************************************************************* | |
| * _ismbchira(MSVCRT.@) | |
| */ | |
| int _ismbchira(unsigned int c) | |
| { | |
| /* FIXME: use lc_ctype when supported, not lc_all */ | |
| if(MSVCRT_current_lc_all_cp == 932) | |
| { | |
| /* Japanese/Hiragana, CP 932 */ | |
| return (c >= 0x829f && c <= 0x82f1); | |
| } | |
| return 0; | |
| } | |
| /********************************************************************* | |
| * _ismbckata(MSVCRT.@) | |
| */ | |
| int _ismbckata(unsigned int c) | |
| { | |
| /* FIXME: use lc_ctype when supported, not lc_all */ | |
| if(MSVCRT_current_lc_all_cp == 932) | |
| { | |
| if(c < 256) | |
| return _ismbbkana(c); | |
| /* Japanese/Katakana, CP 932 */ | |
| return (c >= 0x8340 && c <= 0x8396 && c != 0x837f); | |
| } | |
| return 0; | |
| } | |
| /********************************************************************* | |
| * _ismbblead(MSVCRT.@) | |
| */ | |
| int _ismbblead(unsigned int c) | |
| { | |
| /* FIXME: should reference MSVCRT_mbctype */ | |
| return MSVCRT___mb_cur_max > 1 && MSVCRT_isleadbyte(c); | |
| } | |
| /********************************************************************* | |
| * _ismbbtrail(MSVCRT.@) | |
| */ | |
| int _ismbbtrail(unsigned int c) | |
| { | |
| /* FIXME: should reference MSVCRT_mbctype */ | |
| return !_ismbblead(c); | |
| } | |
| /********************************************************************* | |
| * _ismbslead(MSVCRT.@) | |
| */ | |
| int _ismbslead(const unsigned char *start, const unsigned char *str) | |
| { | |
| /* Lead bytes can also be trail bytes if caller messed up | |
| * iterating through the string... | |
| */ | |
| if(MSVCRT___mb_cur_max > 1) | |
| { | |
| while(start < str) | |
| start += MSVCRT_isleadbyte(*str) ? 2 : 1; | |
| if(start == str) | |
| return MSVCRT_isleadbyte(*str); | |
| } | |
| return 0; /* Must have been a trail, we skipped it */ | |
| } | |
| /********************************************************************* | |
| * _ismbstrail(MSVCRT.@) | |
| */ | |
| int _ismbstrail(const char *start, const unsigned char *str) | |
| { | |
| /* Must not be a lead, and must be preceeded by one */ | |
| return !_ismbslead(start, str) && MSVCRT_isleadbyte(str[-1]); | |
| } | |
| /********************************************************************* | |
| * _mbsdec(MSVCRT.@) | |
| */ | |
| char *_mbsdec(const char *start, const char *cur) | |
| { | |
| if(MSVCRT___mb_cur_max > 1) | |
| return (char *)(_ismbstrail(start,cur-1) ? cur - 2 : cur -1); | |
| return (char *)cur - 1; /* ASCII CP or SB char */ | |
| } | |
| /********************************************************************* | |
| * _mbsset(MSVCRT.@) | |
| */ | |
| char *_mbsset(char *str, unsigned int c) | |
| { | |
| char *ret = str; | |
| if(MSVCRT___mb_cur_max == 1 || c < 256) | |
| return _strset(str, c); /* ASCII CP or SB char */ | |
| c &= 0xffff; /* Strip high bits */ | |
| while(str[0] && str[1]) | |
| { | |
| *str++ = c >> 8; | |
| *str++ = c & 0xff; | |
| } | |
| if(str[0]) | |
| str[0] = '\0'; /* FIXME: OK to shorten? */ | |
| return ret; | |
| } | |
| /********************************************************************* | |
| * _mbsnset(MSVCRT.@) | |
| */ | |
| char *_mbsnset(char *str, unsigned int c, unsigned int len) | |
| { | |
| char *ret = str; | |
| if(!len) | |
| return ret; | |
| if(MSVCRT___mb_cur_max == 1 || c < 256) | |
| return _strnset(str, c, len); /* ASCII CP or SB char */ | |
| c &= 0xffff; /* Strip high bits */ | |
| while(str[0] && str[1] && len--) | |
| { | |
| *str++ = c >> 8; | |
| *str++ = c & 0xff; | |
| } | |
| if(len && str[0]) | |
| str[0] = '\0'; /* FIXME: OK to shorten? */ | |
| return ret; | |
| } | |
| /********************************************************************* | |
| * _mbstrlen(MSVCRT.@) | |
| */ | |
| int _mbstrlen(const unsigned char *str) | |
| { | |
| if(MSVCRT___mb_cur_max > 1) | |
| { | |
| int len = 0; | |
| while(*str) | |
| { | |
| str += MSVCRT_isleadbyte(*str) ? 2 : 1; | |
| len++; | |
| } | |
| return len; | |
| } | |
| return strlen(str); /* ASCII CP */ | |
| } | |
| /********************************************************************* | |
| * _mbsncpy(MSVCRT.@) | |
| */ | |
| char *_mbsncpy(char *dst, const char *src, unsigned int len) | |
| { | |
| if(!len) | |
| return dst; | |
| if(MSVCRT___mb_cur_max > 1) | |
| { | |
| char *ret = dst; | |
| while(src[0] && src[1] && len--) | |
| { | |
| *dst++ = *src++; | |
| *dst++ = *src++; | |
| } | |
| if(len--) | |
| { | |
| *dst++ = *src++; /* Last char or '\0' */ | |
| while(len--) | |
| *dst++ = '\0'; | |
| } | |
| return ret; | |
| } | |
| return strncpy(dst, src, len); /* ASCII CP */ | |
| } | |
| /********************************************************************* | |
| * _mbschr(MSVCRT.@) | |
| * | |
| * Find a multibyte character in a multibyte string. | |
| */ | |
| unsigned char* _mbschr(const unsigned char* str, unsigned int c) | |
| { | |
| if(MSVCRT___mb_cur_max > 1) | |
| { | |
| unsigned int next; | |
| while((next = _mbsnextc(str))) | |
| { | |
| if(next == c) | |
| return (char *)str; | |
| str += next > 255 ? 2 : 1; | |
| } | |
| return c ? NULL :(char *)str; | |
| } | |
| return strchr(str, c); /* ASCII CP */ | |
| } | |
| /********************************************************************* | |
| * _mbsnccnt(MSVCRT.@) | |
| */ | |
| unsigned int _mbsnccnt(const unsigned char *str, unsigned int len) | |
| { | |
| int ret = 0; | |
| if(MSVCRT___mb_cur_max > 1) | |
| { | |
| while(*str && len-- > 0) | |
| { | |
| if(MSVCRT_isleadbyte(*str)) | |
| { | |
| str++; | |
| len--; | |
| } | |
| ret++; | |
| str++; | |
| } | |
| return ret; | |
| } | |
| return min(strlen(str), len); /* ASCII CP */ | |
| } | |
| /********************************************************************* | |
| * _mbsncat(MSVCRT.@) | |
| */ | |
| unsigned char* _mbsncat(unsigned char* dst, const unsigned char* src, MSVCRT_size_t len) | |
| { | |
| if(MSVCRT___mb_cur_max > 1) | |
| { | |
| char *res = dst; | |
| dst += _mbslen(dst); | |
| while(*src && len--) | |
| { | |
| *dst = *src; | |
| if(MSVCRT_isleadbyte(*src)) | |
| *++dst = *++src; | |
| dst++; | |
| src++; | |
| } | |
| *dst++ = '\0'; | |
| return res; | |
| } | |
| return strncat(dst, src, len); /* ASCII CP */ | |
| } | |