wine/dlls/crtdll/mbstring.c
Jon Griffiths 5d4cf0679a - Add several mbcs and CP 932 functions, fix some existing calls
- Bug fixes, -W warnings and winapi_check updates.
- Don't be so strict setting default locale, store codepage
2000-12-19 23:29:15 +00:00

558 lines
13 KiB
C

/*
* CRTDLL multi-byte string functions
*
* Copyright 1999 Alexandre Julliard
* Copyright 2000 Jon Griffths
*
* NOTES
* See msdn.microsoft.com
* /library/devprods/vs6/visualc/vccore/_crt__ismbb_routines.htm
* For details and CP 932 information.
*
* This code assumes that MB_LEN_MAX is 2 and that [0,0] is an
* invalid MB char. If that changes, this will need to too.
*
* CRTDLL reports valid CP 932 multibyte chars when the current
* code page is not 932. MSVCRT fixes this bug - we implement
* MSVCRT's behaviour, since its correct. However, MSVCRT fails
* to set the code page correctly when the locale is changed, so
* it must be explicitly set to get matching results.
*
* FIXME
* Not currently binary compatable with win32. CRTDLL_mbctype must be
* populated correctly and the ismb* functions should reference it.
*/
#include "crtdll.h"
DEFAULT_DEBUG_CHANNEL(crtdll);
UCHAR CRTDLL_mbctype[257];
/*********************************************************************
* _mbscmp (CRTDLL.??)
*
* Compare two multibyte strings.
*/
INT __cdecl CRTDLL__mbscmp( LPCSTR str, LPCSTR cmp )
{
if (CRTDLL__mb_cur_max_dll > 1)
{
UINT strc, cmpc;
do {
if (!*str)
return *cmp ? -1 : 0;
if (!*cmp)
return 1;
strc = CRTDLL__mbsnextc(str);
cmpc = CRTDLL__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 (CRTDLL.??)
*
* Compare two multibyte strings case insensitively.
*/
INT __cdecl CRTDLL__mbsicmp( LPCSTR str, LPCSTR cmp )
{
/* FIXME: No tolower() for mb strings yet */
if (CRTDLL__mb_cur_max_dll > 1)
return CRTDLL__mbscmp( str, cmp );
return strcasecmp( str, cmp ); /* ASCII CP */
}
/*********************************************************************
* _mbsncmp (CRTDLL.??)
*
* Compare two multibyte strings to 'len' characters.
*/
INT __cdecl CRTDLL__mbsncmp( LPCSTR str, LPCSTR cmp, UINT len )
{
if (!len)
return 0;
if (CRTDLL__mb_cur_max_dll > 1)
{
UINT strc, cmpc;
while (len--)
{
if (!*str)
return *cmp ? -1 : 0;
if (!*cmp)
return 1;
strc = CRTDLL__mbsnextc(str);
cmpc = CRTDLL__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 (CRTDLL.??)
*
* Compare two multibyte strings case insensitively to 'len' characters.
*/
INT __cdecl CRTDLL__mbsnicmp( LPCSTR str, LPCSTR cmp, UINT len )
{
/* FIXME: No tolower() for mb strings yet */
if (CRTDLL__mb_cur_max_dll > 1)
return CRTDLL__mbsncmp( str, cmp, len );
return strncasecmp( str, cmp, len ); /* ASCII CP */
}
/*********************************************************************
* _mbsinc (CRTDLL.205)
*
* Return the next character of a string.
*/
LPSTR __cdecl CRTDLL__mbsinc( LPCSTR str )
{
if (CRTDLL__mb_cur_max_dll > 1 &&
CRTDLL_isleadbyte(*str))
return (LPSTR)str + 2; /* MB char */
return (LPSTR)str + 1; /* ASCII CP or SB char */
}
/*********************************************************************
* _mbsninc (CRTDLL.??)
*
* Return the 'num'th character of a string.
*/
LPSTR CRTDLL__mbsninc( LPCSTR str, INT num )
{
if (!str || num < 1)
return NULL;
if (CRTDLL__mb_cur_max_dll > 1)
{
while(num--)
str = CRTDLL__mbsinc( str );
return (LPSTR)str;
}
return (LPSTR)str + num; /* ASCII CP */
}
/*********************************************************************
* _mbslen (CRTDLL.206)
*
* Get the length of a string.
*/
INT __cdecl CRTDLL__mbslen( LPCSTR str )
{
if (CRTDLL__mb_cur_max_dll > 1)
{
INT len = 0;
while (*str)
{
str += CRTDLL_isleadbyte( *str ) ? 2 : 1;
len++;
}
return len;
}
return strlen( str ); /* ASCII CP */
}
/*********************************************************************
* _mbsrchr (CRTDLL.223)
*/
LPSTR __cdecl CRTDLL__mbsrchr(LPCSTR s,CHAR x)
{
/* FIXME: handle multibyte strings */
return strrchr(s,x);
}
/*********************************************************************
* mbtowc (CRTDLL.430)
*/
INT __cdecl CRTDLL_mbtowc( WCHAR *dst, LPCSTR str, INT n )
{
if (n <= 0) return 0;
if (!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 && CRTDLL_isleadbyte(*str) && str[1]) return 2;
return 1;
}
/*********************************************************************
* _mbccpy (CRTDLL.??)
*
* Copy one multibyte character to another
*/
VOID __cdecl CRTDLL__mbccpy(LPSTR dest, LPSTR src)
{
*dest++ = *src;
if (CRTDLL__mb_cur_max_dll > 1 && CRTDLL_isleadbyte(*src))
*dest = *++src; /* MB char */
}
/*********************************************************************
* _mbsdec (CRTDLL.??)
*
* Return the character before 'cur'.
*/
LPSTR __cdecl CRTDLL__mbsdec( LPCSTR start, LPCSTR cur )
{
if (CRTDLL__mb_cur_max_dll > 1)
return (LPSTR)(CRTDLL__ismbstrail(start,cur-1) ? cur - 2 : cur -1);
return (LPSTR)cur - 1; /* ASCII CP or SB char */
}
/*********************************************************************
* _mbbtombc (CRTDLL.??)
*
* Convert a single byte character to a multi byte character.
*/
USHORT __cdecl CRTDLL__mbbtombc( USHORT c )
{
if (CRTDLL__mb_cur_max_dll > 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 (CRTDLL.??)
*
* Get the length of a multibyte character.
*/
INT __cdecl CRTDLL__mbclen( LPCSTR str )
{
return CRTDLL_isleadbyte( *str ) ? 2 : 1;
}
/*********************************************************************
* _ismbbkana (CRTDLL.??)
*
* Is the given single byte character Katakana?
*/
INT __cdecl CRTDLL__ismbbkana( UINT c )
{
/* FIXME: use lc_ctype when supported, not lc_all */
if (__CRTDLL_current_lc_all_cp == 932)
{
/* Japanese/Katakana, CP 932 */
return (c >= 0xa1 && c <= 0xdf);
}
return 0;
}
/*********************************************************************
* _ismbchira (CRTDLL.??)
*
* Is the given character Hiragana?
*/
INT __cdecl CRTDLL__ismbchira( UINT c )
{
/* FIXME: use lc_ctype when supported, not lc_all */
if (__CRTDLL_current_lc_all_cp == 932)
{
/* Japanese/Hiragana, CP 932 */
return (c >= 0x829f && c <= 0x82f1);
}
return 0;
}
/*********************************************************************
* _ismbckata (CRTDLL.??)
*
* Is the given double byte character Katakana?
*/
INT __cdecl CRTDLL__ismbckata( UINT c )
{
/* FIXME: use lc_ctype when supported, not lc_all */
if (__CRTDLL_current_lc_all_cp == 932)
{
if ( c < 256)
return CRTDLL__ismbbkana( c );
/* Japanese/Katakana, CP 932 */
return (c >= 0x8340 && c <= 0x8396 && c != 0x837f);
}
return 0;
}
/*********************************************************************
* _ismbblead (CRTDLL.??)
*
* Is the given single byte character a lead byte?
*/
INT __cdecl CRTDLL__ismbblead( UINT c )
{
/* FIXME: should reference CRTDLL_mbctype */
return CRTDLL__mb_cur_max_dll > 1 && CRTDLL_isleadbyte( c );
}
/*********************************************************************
* _ismbbtrail (CRTDLL.??)
*
* Is the given single byte character a trail byte?
*/
INT __cdecl CRTDLL__ismbbtrail( UINT c )
{
/* FIXME: should reference CRTDLL_mbctype */
return !CRTDLL__ismbblead( c );
}
/*********************************************************************
* _ismbslead (CRTDLL.??)
*
* Is the character pointed to 'str' a lead byte?
*/
INT __cdecl CRTDLL__ismbslead( LPCSTR start, LPCSTR str )
{
/* Lead bytes can also be trail bytes if caller messed up
* iterating through the string...
*/
if (CRTDLL__mb_cur_max_dll > 1)
{
while (start < str)
start += CRTDLL_isleadbyte ( *str ) ? 2 : 1;
if (start == str)
return CRTDLL_isleadbyte( *str );
}
return 0; /* Must have been a trail, we skipped it */
}
/*********************************************************************
* _ismbstrail (CRTDLL.??)
*
* Is the character pointed to 'str' a trail byte?
*/
INT __cdecl CRTDLL__ismbstrail( LPCSTR start, LPCSTR str )
{
/* Must not be a lead, and must be preceeded by one */
return !CRTDLL__ismbslead( start, str ) && CRTDLL_isleadbyte(str[-1]);
}
/*********************************************************************
* _mbsset (CRTDLL.??)
*
* Fill a multibyte string with a value.
*/
LPSTR __cdecl CRTDLL__mbsset( LPSTR str, UINT c )
{
LPSTR ret = str;
if (CRTDLL__mb_cur_max_dll == 1 || c < 256)
return CRTDLL__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 (CRTDLL.??)
*
* Fill a multibyte string with a value up to 'len' characters.
*/
LPSTR __cdecl CRTDLL__mbsnset( LPSTR str, UINT c, UINT len )
{
LPSTR ret = str;
if (!len)
return ret;
if (CRTDLL__mb_cur_max_dll == 1 || c < 256)
return CRTDLL__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 (CRTDLL.??)
*
* Get the length of a multibyte string.
*/
INT __cdecl CRTDLL__mbstrlen( LPCSTR str )
{
if (CRTDLL__mb_cur_max_dll > 1)
{
INT len = 0;
while (*str)
{
str += CRTDLL_isleadbyte ( *str ) ? 2 : 1;
len++;
}
return len;
}
return strlen( str ); /* ASCII CP */
}
/*********************************************************************
* _mbsnextc (CRTDLL.??)
*
* Get the next character from a multibyte string.
*/
UINT __cdecl CRTDLL__mbsnextc( LPCSTR str )
{
if (CRTDLL__mb_cur_max_dll > 1 && CRTDLL_isleadbyte( *str ))
return *str << 8 | str[1];
return *str; /* ASCII CP or SB char */
}
/*********************************************************************
* _mbsncpy (CRTDLL.??)
*
* Copy one multibyte string to another up to 'len' characters.
*/
LPSTR __cdecl CRTDLL__mbsncpy( LPSTR dst, LPCSTR src, UINT len )
{
if (!len)
return dst;
if (CRTDLL__mb_cur_max_dll > 1)
{
LPSTR 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 (CRTDLL.??)
*
* Find a multibyte character in a multibyte string.
*/
LPSTR __cdecl CRTDLL__mbschr( LPCSTR str, UINT c )
{
if (CRTDLL__mb_cur_max_dll > 1)
{
UINT next;
while((next = CRTDLL__mbsnextc( str )))
{
if (next == c)
return (LPSTR)str;
str += next > 255 ? 2 : 1;
}
return c ? NULL : (LPSTR)str;
}
return strchr( str, c ); /* ASCII CP */
}
/*********************************************************************
* _mbsnccnt (CRTDLL.??)
*
* Return the number of mutibyte characters in 'len' bytes of a string.
*/
UINT __cdecl CRTDLL__mbsnccnt( LPCSTR str, UINT len )
{
int ret = 0;
if (CRTDLL__mb_cur_max_dll > 1)
{
while(*str && len-- > 0)
{
if (CRTDLL_isleadbyte ( *str ))
{
str++;
len--;
}
ret++;
str++;
}
return ret;
}
return min( strlen( str ), len ); /* ASCII CP */
}
/*********************************************************************
* _mbsncat (CRTDLL.??)
*
* Add 'len' characters from one multibyte string to another.
*/
LPSTR __cdecl CRTDLL__mbsncat( LPSTR dst, LPCSTR src, UINT len )
{
if (CRTDLL__mb_cur_max_dll > 1)
{
LPSTR res = dst;
dst += CRTDLL__mbslen( dst );
while (*src && len--)
{
*dst = *src;
if (CRTDLL_isleadbyte( *src ))
*++dst = *++src;
dst++;
src++;
}
*dst++ = '\0';
return res;
}
return strncat( dst, src, len ); /* ASCII CP */
}