wine/dlls/msvcrt/mbcs.c
Alexandre Julliard bd1689ec0a Don't include debugtools.h in the header file, moved it to the C files
that need it (and used the new wine/debug.h while we are at it).
2002-01-22 00:57:16 +00:00

883 lines
19 KiB
C

/*
* 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/mbctype.h"
#include "msvcrt/mbstring.h"
#include "msvcrt/stdlib.h"
#include "msvcrt/string.h"
#include "msvcrt/wctype.h"
#include "wine/debug.h"
WINE_DEFAULT_DEBUG_CHANNEL(msvcrt);
unsigned char MSVCRT_mbctype[257];
int MSVCRT___mb_cur_max = 1;
/*********************************************************************
* __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 */
}
/*********************************************************************
* _mbctolower(MSVCRT.@)
*/
unsigned int _mbctolower(unsigned int c)
{
if (MSVCRT_isleadbyte(c))
{
FIXME("Handle MBC chars\n");
return c;
}
return tolower(c); /* ASCII CP or SB char */
}
/*********************************************************************
* _mbctoupper(MSVCRT.@)
*/
unsigned int _mbctoupper(unsigned int c)
{
if (MSVCRT_isleadbyte(c))
{
FIXME("Handle MBC chars\n");
return c;
}
return toupper(c); /* ASCII CP or SB char */
}
/*********************************************************************
* _mbsdec(MSVCRT.@)
*/
unsigned char* _mbsdec(const unsigned char* start, const unsigned 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 */
}
/*********************************************************************
* _mbsinc(MSVCRT.@)
*/
unsigned char* _mbsinc(const unsigned char* str)
{
if(MSVCRT___mb_cur_max > 1 && MSVCRT_isleadbyte(*str))
return (unsigned char*)str + 2; /* MB char */
return (unsigned char*)str + 1; /* ASCII CP or SB char */
}
/*********************************************************************
* _mbsninc(MSVCRT.@)
*/
unsigned char* _mbsninc(const unsigned char* str, MSVCRT_size_t num)
{
if(!str || num < 1)
return NULL;
if(MSVCRT___mb_cur_max > 1)
{
while(num--)
str = _mbsinc(str);
return (unsigned char*)str;
}
return (unsigned char*)str + num; /* ASCII CP */
}
/*********************************************************************
* _mbclen(MSVCRT.@)
*/
unsigned int _mbclen(const unsigned char* str)
{
return MSVCRT_isleadbyte(*str) ? 2 : 1;
}
/*********************************************************************
* mblen(MSVCRT.@)
*/
int MSVCRT_mblen(const char* str, MSVCRT_size_t size)
{
if (str && *str && size)
{
if(MSVCRT___mb_cur_max == 1)
return 1; /* ASCII CP */
return !MSVCRT_isleadbyte(*str) ? 1 : (size>1 ? 2 : -1);
}
return 0;
}
/*********************************************************************
* _mbslen(MSVCRT.@)
*/
MSVCRT_size_t _mbslen(const unsigned char* str)
{
if(MSVCRT___mb_cur_max > 1)
{
MSVCRT_size_t len = 0;
while(*str)
{
str += MSVCRT_isleadbyte(*str) ? 2 : 1;
len++;
}
return len;
}
return strlen(str); /* ASCII CP */
}
/*********************************************************************
* _mbstrlen(MSVCRT.@)
*/
MSVCRT_size_t _mbstrlen(const char* str)
{
if(MSVCRT___mb_cur_max > 1)
{
MSVCRT_size_t len = 0;
while(*str)
{
/* FIXME: According to the documentation we are supposed to test for
* multi-byte character validity. Whatever that means
*/
str += MSVCRT_isleadbyte(*str) ? 2 : 1;
len++;
}
return len;
}
return strlen(str); /* ASCII CP */
}
/*********************************************************************
* _mbccpy(MSVCRT.@)
*/
void _mbccpy(unsigned char* dest, const unsigned char* src)
{
*dest++ = *src;
if(MSVCRT___mb_cur_max > 1 && MSVCRT_isleadbyte(*src))
*dest = *++src; /* MB char */
else
ERR("failure.. is this ok?\n");
}
/*********************************************************************
* _mbsncpy(MSVCRT.@)
*/
unsigned char* _mbsncpy(unsigned char* dst, const unsigned char* src, MSVCRT_size_t n)
{
if(!n)
return dst;
if(MSVCRT___mb_cur_max > 1)
{
unsigned char* ret = dst;
while (*src && n--)
{
*dst++ = *src;
if (MSVCRT_isleadbyte(*src++))
*dst++ = *src++;
}
while(n--)
*dst++ = '\0';
return ret;
}
return strncpy(dst, src, n); /* ASCII CP */
}
/*********************************************************************
* _mbsnbcpy(MSVCRT.@)
*/
unsigned char* _mbsnbcpy(unsigned char* dst, const unsigned char* src, MSVCRT_size_t n)
{
if(!n)
return dst;
if(MSVCRT___mb_cur_max > 1)
{
unsigned char* ret = dst;
while (*src && (n-- > 1))
{
*dst++ = *src;
if (MSVCRT_isleadbyte(*src++))
{
*dst++ = *src++;
n--;
}
}
if (*src && n && !MSVCRT_isleadbyte(*src))
{
/* If the last character is a multi-byte character then
* we cannot copy it since we have only one byte left
*/
*dst++ = *src;
n--;
}
while (n--)
*dst++ = '\0';
return ret;
}
return strncpy(dst, src, n); /* ASCII CP */
}
/*********************************************************************
* _mbscmp(MSVCRT.@)
*/
int _mbscmp(const unsigned char* str, const unsigned 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 unsigned char* str, const unsigned char* cmp)
{
if(MSVCRT___mb_cur_max > 1)
{
unsigned int strc, cmpc;
do {
if(!*str)
return *cmp ? -1 : 0;
if(!*cmp)
return 1;
strc = _mbctolower(_mbsnextc(str));
cmpc = _mbctolower(_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 strcasecmp(str, cmp); /* ASCII CP */
}
/*********************************************************************
* _mbsncmp(MSVCRT.@)
*/
int _mbsncmp(const unsigned char* str, const unsigned char* cmp, MSVCRT_size_t len)
{
if(!len)
return 0;
if(MSVCRT___mb_cur_max > 1)
{
unsigned int strc, cmpc;
while(len--)
{
int inc;
if(!*str)
return *cmp ? -1 : 0;
if(!*cmp)
return 1;
strc = _mbsnextc(str);
cmpc = _mbsnextc(cmp);
if(strc != cmpc)
return strc < cmpc ? -1 : 1;
inc=(strc > 255) ? 2 : 1; /* Equal, use same increment */
str += inc;
cmp += inc;
}
return 0; /* Matched len chars */
}
return strncmp(str, cmp, len); /* ASCII CP */
}
/*********************************************************************
* _mbsnbcmp(MSVCRT.@)
*/
int _mbsnbcmp(const unsigned char* str, const unsigned char* cmp, MSVCRT_size_t len)
{
if (!len)
return 0;
if(MSVCRT___mb_cur_max > 1)
{
unsigned int strc, cmpc;
while (len)
{
int clen;
if(!*str)
return *cmp ? -1 : 0;
if(!*cmp)
return 1;
if (MSVCRT_isleadbyte(*str))
{
strc=(len>=2)?_mbsnextc(str):0;
clen=2;
}
else
{
strc=*str;
clen=1;
}
if (MSVCRT_isleadbyte(*cmp))
cmpc=(len>=2)?_mbsnextc(cmp):0;
else
cmpc=*str;
if(strc != cmpc)
return strc < cmpc ? -1 : 1;
len -= clen;
str += clen;
cmp += clen;
}
return 0; /* Matched len chars */
FIXME("%s %s %d\n",str,cmp,len);
}
return strncmp(str,cmp,len);
}
/*********************************************************************
* _mbsnicmp(MSVCRT.@)
*
* Compare two multibyte strings case insensitively to 'len' characters.
*/
int _mbsnicmp(const unsigned char* str, const unsigned char* cmp, MSVCRT_size_t len)
{
/* FIXME: No tolower() for mb strings yet */
if(MSVCRT___mb_cur_max > 1)
{
unsigned int strc, cmpc;
while(len--)
{
if(!*str)
return *cmp ? -1 : 0;
if(!*cmp)
return 1;
strc = _mbctolower(_mbsnextc(str));
cmpc = _mbctolower(_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 strncasecmp(str, cmp, len); /* ASCII CP */
}
/*********************************************************************
* _mbschr(MSVCRT.@)
*
* Find a multibyte character in a multibyte string.
*/
unsigned char* _mbschr(const unsigned char* s, unsigned int x)
{
if(MSVCRT___mb_cur_max > 1)
{
unsigned int c;
while (1)
{
c = _mbsnextc(s);
if (c == x)
return (unsigned char*)s;
if (!c)
return NULL;
s += c > 255 ? 2 : 1;
}
}
return strchr(s, x); /* ASCII CP */
}
/*********************************************************************
* _mbsrchr(MSVCRT.@)
*/
unsigned char* _mbsrchr(const unsigned char* s, unsigned int x)
{
if(MSVCRT___mb_cur_max > 1)
{
unsigned int c;
unsigned char* match=NULL;
if(!s)
return NULL;
while (1) {
c = _mbsnextc(s);
if (c == x)
match=(unsigned char*)s;
if (!c)
return match;
s +=(c > 255) ? 2 : 1;
}
}
return strrchr(s,x);
}
/*********************************************************************
* mbtowc(MSVCRT.@)
*/
int MSVCRT_mbtowc(WCHAR *dst, const char* str, MSVCRT_size_t 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;
}
/*********************************************************************
* _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 */
}
/*********************************************************************
* _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;
}
/*********************************************************************
* _ismbcdigit(MSVCRT.@)
*/
int _ismbcdigit(unsigned int ch)
{
if (ch <0x100)
return isdigit(ch);
else
{
FIXME("Handle MBC chars\n");
return 0;
}
}
/*********************************************************************
* _ismbcspace (MSVCRT.@)
*/
int _ismbcspace(unsigned int c)
{
if (c<0x100)
return isspace(c);
FIXME("%c\n",c);
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 unsigned 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]);
}
/*********************************************************************
* _mbsset(MSVCRT.@)
*/
unsigned char* _mbsset(unsigned char* str, unsigned int c)
{
unsigned 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.@)
*/
unsigned char* _mbsnset(unsigned char* str, unsigned int c, MSVCRT_size_t len)
{
unsigned 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;
}
/*********************************************************************
* _mbsnccnt(MSVCRT.@)
* 'c' is for 'character'.
*/
MSVCRT_size_t _mbsnccnt(const unsigned char* str, MSVCRT_size_t len)
{
MSVCRT_size_t ret;
if(MSVCRT___mb_cur_max > 1)
{
ret=0;
while(*str && len-- > 0)
{
if(MSVCRT_isleadbyte(*str))
{
if (!len)
break;
len--;
str++;
}
str++;
ret++;
}
return ret;
}
ret=strlen(str);
return min(ret, len); /* ASCII CP */
}
/*********************************************************************
* _mbsnbcnt(MSVCRT.@)
* 'b' is for byte count.
*/
MSVCRT_size_t _mbsnbcnt(const unsigned char* str, MSVCRT_size_t len)
{
MSVCRT_size_t ret;
if(MSVCRT___mb_cur_max > 1)
{
const unsigned char* xstr = str;
while(*xstr && len-- > 0)
{
if (MSVCRT_isleadbyte(*xstr++))
xstr++;
}
return xstr-str;
}
ret=strlen(str);
return min(ret, 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;
while (*dst)
{
if (MSVCRT_isleadbyte(*dst++))
dst++;
}
while (*src && len--)
{
*dst++ = *src;
if(MSVCRT_isleadbyte(*src++))
*dst++ = *src++;
}
*dst = '\0';
return res;
}
return strncat(dst, src, len); /* ASCII CP */
}
/*********************************************************************
* _mbslwr(MSVCRT.@)
*/
unsigned char* _mbslwr(unsigned char* s)
{
if (!s)
return NULL;
if (MSVCRT___mb_cur_max > 1)
{
unsigned int c;
unsigned char* p=s;
while (*s)
{
c = _mbctolower(_mbsnextc(s));
/* Note that I assume that the size of the character is unchanged */
if (c > 255)
{
*s++=(c>>8);
c=c & 0xff;
}
*s++=c;
}
return p;
}
return _strlwr(s);
}
/*********************************************************************
* _mbsupr(MSVCRT.@)
*/
unsigned char* _mbsupr(unsigned char* s)
{
if (!s)
return NULL;
if (MSVCRT___mb_cur_max > 1)
{
unsigned int c;
unsigned char* p=s;
while (*s)
{
c = _mbctoupper(_mbsnextc(s));
/* Note that I assume that the size of the character is unchanged */
if (c > 255)
{
*s++=(c>>8);
c=c & 0xff;
}
*s++=c;
}
return p;
}
return _strupr(s);
}
/*********************************************************************
* _mbsspn (MSVCRT.@)
*/
MSVCRT_size_t _mbsspn(const unsigned char* string, const unsigned char* set)
{
const unsigned char *p, *q;
for (p = string; *p; p++)
{
if (MSVCRT_isleadbyte(*p))
{
for (q = set; *q; q++)
{
if (!q[1])
break;
if ((*p == *q) && (p[1] == q[1]))
break;
q++;
}
if (*++p == '\0')
break;
}
else
for (q = set; *q; q++)
if (*p == *q)
break;
}
return p - string;
}
/*********************************************************************
* _mbscspn(MSVCRT.@)
*/
MSVCRT_size_t _mbscspn(const unsigned char* str, const unsigned char* cmp)
{
if (MSVCRT___mb_cur_max > 1)
FIXME("don't handle double character case\n");
return strcspn(str, cmp);
}
/*********************************************************************
* _mbsrev (MSVCRT.@)
*/
unsigned char* _mbsrev(unsigned char* str)
{
int i, len = _mbslen(str);
unsigned char *p, *temp=MSVCRT_malloc(len*2);
if(!temp)
return str;
/* unpack multibyte string to temp buffer */
p=str;
for(i=0; i<len; i++)
{
if (MSVCRT_isleadbyte(*p))
{
temp[i*2]=*p++;
temp[i*2+1]=*p++;
}
else
{
temp[i*2]=*p++;
temp[i*2+1]=0;
}
}
/* repack it in the reverse order */
p=str;
for(i=len-1; i>=0; i--)
{
if(MSVCRT_isleadbyte(temp[i*2]))
{
*p++=temp[i*2];
*p++=temp[i*2+1];
}
else
{
*p++=temp[i*2];
}
}
MSVCRT_free(temp);
return str;
}
/*********************************************************************
* _mbspbrk (MSVCRT.@)
*/
unsigned char* _mbspbrk(const unsigned char* str, const unsigned char* accept)
{
const unsigned char* p;
while(*str)
{
for(p = accept; *p; p += (MSVCRT_isleadbyte(*p)?2:1) )
{
if (*p == *str)
if( !MSVCRT_isleadbyte(*p) || ( *(p+1) == *(str+1) ) )
return (unsigned char*)str;
}
str += (MSVCRT_isleadbyte(*str)?2:1);
}
return NULL;
}