mirror of
git://source.winehq.org/git/wine.git
synced 2024-11-05 18:01:34 +00:00
5d4cf0679a
- Bug fixes, -W warnings and winapi_check updates. - Don't be so strict setting default locale, store codepage
558 lines
13 KiB
C
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 */
|
|
}
|
|
|