Fixed GetLocaleInfoW to handle Unicode properly and completed

implementation.
Update win.ini and registry on startup when language changed.
More logical priority order for locale environment variables.
Implemented SetLocaleInfoW.
Moved some locale functions to kernel32.dll.
This commit is contained in:
Alexandre Julliard 2002-08-15 23:18:47 +00:00
parent becccaf168
commit 66e3183099
11 changed files with 1004 additions and 947 deletions

View File

@ -8,12 +8,14 @@ ALTNAMES = krnl386.exe comm.dll stress.dll system.dll toolhelp.dll windebug.dll
LDIMPORTS = ntdll.dll
C_SRCS = \
$(TOPOBJDIR)/ole/ole2nls.c \
comm.c \
console.c \
debugger.c \
editline.c \
format_msg.c \
kernel_main.c \
locale.c \
stress.c \
string.c \
sync.c \

View File

@ -697,7 +697,7 @@ init MAIN_KernelInit
@ stdcall SetLastError(long) SetLastError
@ stdcall SetLocalTime(ptr) SetLocalTime
@ stdcall SetLocaleInfoA(long long str) SetLocaleInfoA
@ stub SetLocaleInfoW
@ stdcall SetLocaleInfoW(long long wstr) SetLocaleInfoW
@ stub SetMailslotInfo
@ stdcall SetNamedPipeHandleState(long ptr ptr ptr) SetNamedPipeHandleState
@ stdcall SetPriorityClass(long long) SetPriorityClass

View File

@ -38,7 +38,7 @@
#include "module.h"
#include "task.h"
extern void CODEPAGE_Init(void);
extern void LOCALE_Init(void);
extern BOOL RELAY_Init(void);
extern int __wine_set_signal_handler(unsigned, int (*)(unsigned));
@ -58,7 +58,7 @@ static BOOL process_attach(void)
umask( FILE_umask );
/* Setup codepage info */
CODEPAGE_Init();
LOCALE_Init();
/* Initialize relay entry points */
if (!RELAY_Init()) return FALSE;

886
dlls/kernel/locale.c Normal file
View File

@ -0,0 +1,886 @@
/*
* Locale support
*
* Copyright 1995 Martin von Loewis
* Copyright 1998 David Lee Lambert
* Copyright 2000 Julio César Gázquez
* Copyright 2002 Alexandre Julliard for Codeweavers
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
#include "config.h"
#include "wine/port.h"
#include <string.h>
#include <stdio.h>
#include <ctype.h>
#include <stdlib.h>
#include "windef.h"
#include "winbase.h"
#include "winuser.h" /* for RT_STRINGW */
#include "ntddk.h"
#include "wine/unicode.h"
#include "winnls.h"
#include "winerror.h"
#include "thread.h"
#include "wine/debug.h"
WINE_DEFAULT_DEBUG_CHANNEL(nls);
#define LOCALE_LOCALEINFOFLAGSMASK (LOCALE_NOUSEROVERRIDE|LOCALE_USE_CP_ACP|LOCALE_RETURN_NUMBER)
extern void CODEPAGE_Init( UINT ansi, UINT oem, UINT mac, LCID lcid );
#define NLS_MAX_LANGUAGES 20
typedef struct {
char lang[128];
char country[128];
LANGID found_lang_id[NLS_MAX_LANGUAGES];
char found_language[NLS_MAX_LANGUAGES][3];
char found_country[NLS_MAX_LANGUAGES][3];
int n_found;
} LANG_FIND_DATA;
/***********************************************************************
* get_lcid_codepage
*
* Retrieve the ANSI codepage for a given locale.
*/
inline static UINT get_lcid_codepage( LCID lcid )
{
UINT ret;
if (!GetLocaleInfoW( lcid, LOCALE_IDEFAULTANSICODEPAGE|LOCALE_RETURN_NUMBER, (WCHAR *)&ret,
sizeof(ret)/sizeof(WCHAR) )) ret = 0;
return ret;
}
/***********************************************************************
* update_registry
*
* Update registry contents on startup if the user locale has changed.
* This simulates the action of the Windows control panel.
*/
inline static void update_registry( LCID lcid )
{
char buffer[20];
WCHAR bufferW[80];
DWORD count = sizeof(buffer);
HKEY hkey;
if (RegCreateKeyExA( HKEY_CURRENT_USER, "Control Panel\\International", 0, NULL,
0, KEY_ALL_ACCESS, NULL, &hkey, NULL ))
return; /* don't do anything if we can't create the registry key */
if (!RegQueryValueExA( hkey, "Locale", NULL, NULL, (LPBYTE)buffer, &count ))
{
if (strtol( buffer, NULL, 16 ) == lcid) /* already set correctly */
{
RegCloseKey( hkey );
return;
}
TRACE( "updating registry, locale changed %s -> %08lx\n", buffer, lcid );
}
else TRACE( "updating registry, locale changed none -> %08lx\n", lcid );
sprintf( buffer, "%08lx", lcid );
RegSetValueExA( hkey, "Locale", 0, REG_SZ, (LPBYTE)buffer, strlen(buffer)+1 );
RegCloseKey( hkey );
#define UPDATE_VALUE(lctype) do { \
GetLocaleInfoW( lcid, (lctype)|LOCALE_NOUSEROVERRIDE, bufferW, sizeof(bufferW)/sizeof(WCHAR) ); \
SetLocaleInfoW( lcid, (lctype), bufferW ); } while (0)
UPDATE_VALUE(LOCALE_SLANGUAGE);
UPDATE_VALUE(LOCALE_SCOUNTRY);
UPDATE_VALUE(LOCALE_ICOUNTRY);
UPDATE_VALUE(LOCALE_S1159);
UPDATE_VALUE(LOCALE_S2359);
UPDATE_VALUE(LOCALE_STIME);
UPDATE_VALUE(LOCALE_ITIME);
UPDATE_VALUE(LOCALE_ITLZERO);
UPDATE_VALUE(LOCALE_SSHORTDATE);
UPDATE_VALUE(LOCALE_IDATE);
UPDATE_VALUE(LOCALE_SLONGDATE);
UPDATE_VALUE(LOCALE_SDATE);
UPDATE_VALUE(LOCALE_SCURRENCY);
UPDATE_VALUE(LOCALE_ICURRENCY);
UPDATE_VALUE(LOCALE_INEGCURR);
UPDATE_VALUE(LOCALE_ICURRDIGITS);
UPDATE_VALUE(LOCALE_SDECIMAL);
UPDATE_VALUE(LOCALE_SLIST);
UPDATE_VALUE(LOCALE_STHOUSAND);
UPDATE_VALUE(LOCALE_IDIGITS);
UPDATE_VALUE(LOCALE_ILZERO);
UPDATE_VALUE(LOCALE_IMEASURE);
#undef UPDATE_VALUE
}
/***********************************************************************
* find_language_id_proc
*/
static BOOL CALLBACK find_language_id_proc( HMODULE hModule, LPCSTR type,
LPCSTR name, WORD LangID, LPARAM lParam )
{
LANG_FIND_DATA *l_data = (LANG_FIND_DATA *)lParam;
LCID lcid = MAKELCID(LangID, SORT_DEFAULT);
char buf_language[128];
char buf_country[128];
char buf_en_language[128];
TRACE("%04X\n", (UINT)LangID);
if(PRIMARYLANGID(LangID) == LANG_NEUTRAL)
return TRUE; /* continue search */
buf_language[0] = 0;
buf_country[0] = 0;
GetLocaleInfoA(lcid, LOCALE_SISO639LANGNAME|LOCALE_NOUSEROVERRIDE|LOCALE_USE_CP_ACP,
buf_language, sizeof(buf_language));
TRACE("LOCALE_SISO639LANGNAME: %s\n", buf_language);
GetLocaleInfoA(lcid, LOCALE_SISO3166CTRYNAME|LOCALE_NOUSEROVERRIDE|LOCALE_USE_CP_ACP,
buf_country, sizeof(buf_country));
TRACE("LOCALE_SISO3166CTRYNAME: %s\n", buf_country);
if(l_data->lang && strlen(l_data->lang) > 0 && !strcasecmp(l_data->lang, buf_language))
{
if(l_data->country && strlen(l_data->country) > 0)
{
if(!strcasecmp(l_data->country, buf_country))
{
l_data->found_lang_id[0] = LangID;
l_data->n_found = 1;
TRACE("Found lang_id %04X for %s_%s\n", LangID, l_data->lang, l_data->country);
return FALSE; /* stop enumeration */
}
}
else /* l_data->country not specified */
{
if(l_data->n_found < NLS_MAX_LANGUAGES)
{
l_data->found_lang_id[l_data->n_found] = LangID;
strncpy(l_data->found_country[l_data->n_found], buf_country, 3);
strncpy(l_data->found_language[l_data->n_found], buf_language, 3);
l_data->n_found++;
TRACE("Found lang_id %04X for %s\n", LangID, l_data->lang);
return TRUE; /* continue search */
}
}
}
/* Just in case, check LOCALE_SENGLANGUAGE too,
* in hope that possible alias name might have that value.
*/
buf_en_language[0] = 0;
GetLocaleInfoA(lcid, LOCALE_SENGLANGUAGE|LOCALE_NOUSEROVERRIDE|LOCALE_USE_CP_ACP,
buf_en_language, sizeof(buf_en_language));
TRACE("LOCALE_SENGLANGUAGE: %s\n", buf_en_language);
if(l_data->lang && strlen(l_data->lang) > 0 && !strcasecmp(l_data->lang, buf_en_language))
{
l_data->found_lang_id[l_data->n_found] = LangID;
strncpy(l_data->found_country[l_data->n_found], buf_country, 3);
strncpy(l_data->found_language[l_data->n_found], buf_language, 3);
l_data->n_found++;
TRACE("Found lang_id %04X for %s\n", LangID, l_data->lang);
}
return TRUE; /* continue search */
}
/***********************************************************************
* get_language_id
*
* INPUT:
* Lang: a string whose two first chars are the iso name of a language.
* Country: a string whose two first chars are the iso name of country
* Charset: a string defining the chosen charset encoding
* Dialect: a string defining a variation of the locale
*
* all those values are from the standardized format of locale
* name in unix which is: Lang[_Country][.Charset][@Dialect]
*
* RETURNS:
* the numeric code of the language used by Windows
*
* FIXME: Charset and Dialect are not handled
*/
static LANGID get_language_id(LPCSTR Lang, LPCSTR Country, LPCSTR Charset, LPCSTR Dialect)
{
LANG_FIND_DATA l_data;
char lang_string[256];
if(!Lang)
{
l_data.found_lang_id[0] = MAKELANGID(LANG_ENGLISH, SUBLANG_DEFAULT);
goto END;
}
memset(&l_data, 0, sizeof(LANG_FIND_DATA));
strncpy(l_data.lang, Lang, sizeof(l_data.lang));
if(Country && strlen(Country) > 0)
strncpy(l_data.country, Country, sizeof(l_data.country));
EnumResourceLanguagesA(GetModuleHandleA("KERNEL32"), RT_STRINGA,
(LPCSTR)LOCALE_ILANGUAGE, find_language_id_proc, (LPARAM)&l_data);
strcpy(lang_string, l_data.lang);
if(l_data.country && strlen(l_data.country) > 0)
{
strcat(lang_string, "_");
strcat(lang_string, l_data.country);
}
if(!l_data.n_found)
{
if(l_data.country && strlen(l_data.country) > 0)
{
MESSAGE("Warning: Language '%s' was not found, retrying without country name...\n", lang_string);
l_data.country[0] = 0;
EnumResourceLanguagesA(GetModuleHandleA("KERNEL32"), RT_STRINGA,
(LPCSTR)LOCALE_ILANGUAGE, find_language_id_proc, (LONG)&l_data);
}
}
/* Re-evaluate lang_string */
strcpy(lang_string, l_data.lang);
if(l_data.country && strlen(l_data.country) > 0)
{
strcat(lang_string, "_");
strcat(lang_string, l_data.country);
}
if(!l_data.n_found)
{
MESSAGE("Warning: Language '%s' was not recognized, defaulting to English\n", lang_string);
l_data.found_lang_id[0] = MAKELANGID(LANG_ENGLISH, SUBLANG_DEFAULT);
}
else
{
if(l_data.n_found == 1)
TRACE("For language '%s' lang_id %04X was found\n", lang_string, l_data.found_lang_id[0]);
else /* l_data->n_found > 1 */
{
int i;
MESSAGE("For language '%s' several language ids were found:\n", lang_string);
for(i = 0; i < l_data.n_found; i++)
MESSAGE("%s_%s - %04X; ", l_data.found_language[i], l_data.found_country[i], l_data.found_lang_id[i]);
MESSAGE("\nInstead of using first in the list, suggest to define\n"
"your LANG environment variable like this: LANG=%s_%s\n",
l_data.found_language[0], l_data.found_country[0]);
}
}
END:
TRACE("Returning %04X\n", l_data.found_lang_id[0]);
return l_data.found_lang_id[0];
}
/***********************************************************************
* init_default_lcid
*/
static LCID init_default_lcid(void)
{
char buf[256];
char *lang,*country,*charset,*dialect,*next;
LCID ret = 0;
if (GetEnvironmentVariableA( "LC_ALL", buf, sizeof(buf) ) ||
GetEnvironmentVariableA( "LC_CTYPE", buf, sizeof(buf) ) ||
GetEnvironmentVariableA( "LANGUAGE", buf, sizeof(buf) ) ||
GetEnvironmentVariableA( "LC_MESSAGES", buf, sizeof(buf) ) ||
GetEnvironmentVariableA( "LANG", buf, sizeof(buf) ))
{
if (!strcmp(buf,"POSIX") || !strcmp(buf,"C")) goto done;
lang=buf;
do {
next=strchr(lang,':'); if (next) *next++='\0';
dialect=strchr(lang,'@'); if (dialect) *dialect++='\0';
charset=strchr(lang,'.'); if (charset) *charset++='\0';
country=strchr(lang,'_'); if (country) *country++='\0';
ret = get_language_id(lang, country, charset, dialect);
lang=next;
} while (lang && !ret);
if (!ret) MESSAGE("Warning: language '%s' not recognized, defaulting to English\n", buf);
}
done:
if (!ret) ret = MAKELCID( MAKELANGID(LANG_ENGLISH,SUBLANG_DEFAULT), SORT_DEFAULT) ;
return ret;
}
/******************************************************************************
* get_locale_value_name
*
* Gets the registry value name for a given lctype.
*/
static const WCHAR *get_locale_value_name( DWORD lctype )
{
static const WCHAR iCalendarTypeW[] = {'i','C','a','l','e','n','d','a','r','T','y','p','e',0};
static const WCHAR iCountryW[] = {'i','C','o','u','n','t','r','y',0};
static const WCHAR iCurrDigitsW[] = {'i','C','u','r','r','D','i','g','i','t','s',0};
static const WCHAR iCurrencyW[] = {'i','C','u','r','r','e','n','c','y',0};
static const WCHAR iDateW[] = {'i','D','a','t','e',0};
static const WCHAR iDigitsW[] = {'i','D','i','g','i','t','s',0};
static const WCHAR iFirstDayOfWeekW[] = {'i','F','i','r','s','t','D','a','y','O','f','W','e','e','k',0};
static const WCHAR iFirstWeekOfYearW[] = {'i','F','i','r','s','t','W','e','e','k','O','f','Y','e','a','r',0};
static const WCHAR iLDateW[] = {'i','L','D','a','t','e',0};
static const WCHAR iLZeroW[] = {'i','L','Z','e','r','o',0};
static const WCHAR iMeasureW[] = {'i','M','e','a','s','u','r','e',0};
static const WCHAR iNegCurrW[] = {'i','N','e','g','C','u','r','r',0};
static const WCHAR iNegNumberW[] = {'i','N','e','g','N','u','m','b','e','r',0};
static const WCHAR iPaperSizeW[] = {'i','P','a','p','e','r','S','i','z','e',0};
static const WCHAR iTLZeroW[] = {'i','T','L','Z','e','r','o',0};
static const WCHAR iTimeW[] = {'i','T','i','m','e',0};
static const WCHAR s1159W[] = {'s','1','1','5','9',0};
static const WCHAR s2359W[] = {'s','2','3','5','9',0};
static const WCHAR sCountryW[] = {'s','C','o','u','n','t','r','y',0};
static const WCHAR sCurrencyW[] = {'s','C','u','r','r','e','n','c','y',0};
static const WCHAR sDateW[] = {'s','D','a','t','e',0};
static const WCHAR sDecimalW[] = {'s','D','e','c','i','m','a','l',0};
static const WCHAR sGroupingW[] = {'s','G','r','o','u','p','i','n','g',0};
static const WCHAR sLanguageW[] = {'s','L','a','n','g','u','a','g','e',0};
static const WCHAR sListW[] = {'s','L','i','s','t',0};
static const WCHAR sLongDateW[] = {'s','L','o','n','g','D','a','t','e',0};
static const WCHAR sMonDecimalSepW[] = {'s','M','o','n','D','e','c','i','m','a','l','S','e','p',0};
static const WCHAR sMonGroupingW[] = {'s','M','o','n','G','r','o','u','p','i','n','g',0};
static const WCHAR sMonThousandSepW[] = {'s','M','o','n','T','h','o','u','s','a','n','d','S','e','p',0};
static const WCHAR sNegativeSignW[] = {'s','N','e','g','a','t','i','v','e','S','i','g','n',0};
static const WCHAR sPositiveSignW[] = {'s','P','o','s','i','t','i','v','e','S','i','g','n',0};
static const WCHAR sShortDateW[] = {'s','S','h','o','r','t','D','a','t','e',0};
static const WCHAR sThousandW[] = {'s','T','h','o','u','s','a','n','d',0};
static const WCHAR sTimeFormatW[] = {'s','T','i','m','e','F','o','r','m','a','t',0};
static const WCHAR sTimeW[] = {'s','T','i','m','e',0};
static const WCHAR sYearMonthW[] = {'s','Y','e','a','r','M','o','n','t','h',0};
switch (lctype & ~LOCALE_LOCALEINFOFLAGSMASK)
{
/* These values are used by SetLocaleInfo and GetLocaleInfo, and
* the values are stored in the registry, confirmed under Windows.
*/
case LOCALE_ICALENDARTYPE: return iCalendarTypeW;
case LOCALE_ICURRDIGITS: return iCurrDigitsW;
case LOCALE_ICURRENCY: return iCurrencyW;
case LOCALE_IDIGITS: return iDigitsW;
case LOCALE_IFIRSTDAYOFWEEK: return iFirstDayOfWeekW;
case LOCALE_IFIRSTWEEKOFYEAR: return iFirstWeekOfYearW;
case LOCALE_ILZERO: return iLZeroW;
case LOCALE_IMEASURE: return iMeasureW;
case LOCALE_INEGCURR: return iNegCurrW;
case LOCALE_INEGNUMBER: return iNegNumberW;
case LOCALE_IPAPERSIZE: return iPaperSizeW;
case LOCALE_ITIME: return iTimeW;
case LOCALE_S1159: return s1159W;
case LOCALE_S2359: return s2359W;
case LOCALE_SCURRENCY: return sCurrencyW;
case LOCALE_SDATE: return sDateW;
case LOCALE_SDECIMAL: return sDecimalW;
case LOCALE_SGROUPING: return sGroupingW;
case LOCALE_SLIST: return sListW;
case LOCALE_SLONGDATE: return sLongDateW;
case LOCALE_SMONDECIMALSEP: return sMonDecimalSepW;
case LOCALE_SMONGROUPING: return sMonGroupingW;
case LOCALE_SMONTHOUSANDSEP: return sMonThousandSepW;
case LOCALE_SNEGATIVESIGN: return sNegativeSignW;
case LOCALE_SPOSITIVESIGN: return sPositiveSignW;
case LOCALE_SSHORTDATE: return sShortDateW;
case LOCALE_STHOUSAND: return sThousandW;
case LOCALE_STIME: return sTimeW;
case LOCALE_STIMEFORMAT: return sTimeFormatW;
case LOCALE_SYEARMONTH: return sYearMonthW;
/* The following are not listed under MSDN as supported,
* but seem to be used and also stored in the registry.
*/
case LOCALE_ICOUNTRY: return iCountryW;
case LOCALE_IDATE: return iDateW;
case LOCALE_ILDATE: return iLDateW;
case LOCALE_ITLZERO: return iTLZeroW;
case LOCALE_SCOUNTRY: return sCountryW;
case LOCALE_SLANGUAGE: return sLanguageW;
}
return NULL;
}
/******************************************************************************
* get_registry_locale_info
*
* Retrieve user-modified locale info from the registry.
* Return length, 0 on error, -1 if not found.
*/
static INT get_registry_locale_info( LPCWSTR value, LPWSTR buffer, INT len )
{
DWORD size;
INT ret;
HKEY hkey;
NTSTATUS status;
UNICODE_STRING nameW;
KEY_VALUE_PARTIAL_INFORMATION *info;
static const int info_size = info->Data - (UCHAR *)info;
if (RegOpenKeyExA( HKEY_CURRENT_USER, "Control Panel\\International", 0, KEY_READ, &hkey))
return -1;
RtlInitUnicodeString( &nameW, value );
size = info_size + len * sizeof(WCHAR);
if (!(info = HeapAlloc( GetProcessHeap(), 0, size )))
{
RegCloseKey( hkey );
SetLastError( ERROR_NOT_ENOUGH_MEMORY );
return 0;
}
status = NtQueryValueKey( hkey, &nameW, KeyValuePartialInformation, info, size, &size );
if (status == STATUS_BUFFER_OVERFLOW && !buffer) status = 0;
if (!status)
{
ret = (size - info_size) / sizeof(WCHAR);
/* append terminating null if needed */
if (!ret || ((WCHAR *)info->Data)[ret-1])
{
if (ret < len || !buffer) ret++;
else
{
SetLastError( ERROR_INSUFFICIENT_BUFFER );
ret = 0;
}
}
if (ret && buffer)
{
memcpy( buffer, info->Data, (ret-1) * sizeof(WCHAR) );
buffer[ret-1] = 0;
}
}
else
{
if (status == STATUS_OBJECT_NAME_NOT_FOUND) ret = -1;
else
{
SetLastError( RtlNtStatusToDosError(status) );
ret = 0;
}
}
RegCloseKey( hkey );
HeapFree( GetProcessHeap(), 0, info );
return ret;
}
/******************************************************************************
* GetLocaleInfoA (KERNEL32.@)
*
* NOTES
* LANG_NEUTRAL is equal to LOCALE_SYSTEM_DEFAULT
*
* MS online documentation states that the string returned is NULL terminated
* except for LOCALE_FONTSIGNATURE which "will return a non-NULL
* terminated string".
*/
INT WINAPI GetLocaleInfoA( LCID lcid, LCTYPE lctype, LPSTR buffer, INT len )
{
WCHAR *bufferW;
INT lenW, ret;
if (len < 0 || (len && !buffer))
{
SetLastError( ERROR_INVALID_PARAMETER );
return 0;
}
if (!len) buffer = NULL;
if (!(lenW = GetLocaleInfoW( lcid, lctype, NULL, 0 ))) return 0;
if (!(bufferW = HeapAlloc( GetProcessHeap(), 0, lenW * sizeof(WCHAR) )))
{
SetLastError( ERROR_NOT_ENOUGH_MEMORY );
return 0;
}
if ((ret = GetLocaleInfoW( lcid, lctype, bufferW, lenW )))
{
if ((lctype & LOCALE_RETURN_NUMBER) ||
((lctype & ~LOCALE_LOCALEINFOFLAGSMASK) == LOCALE_FONTSIGNATURE))
{
/* it's not an ASCII string, just bytes */
ret *= sizeof(WCHAR);
if (buffer)
{
if (ret <= len) memcpy( buffer, bufferW, ret );
else
{
SetLastError( ERROR_INSUFFICIENT_BUFFER );
ret = 0;
}
}
}
else
{
UINT codepage = CP_ACP;
if (!(lctype & LOCALE_USE_CP_ACP)) codepage = get_lcid_codepage( lcid );
ret = WideCharToMultiByte( codepage, 0, bufferW, ret, buffer, len, NULL, NULL );
}
}
HeapFree( GetProcessHeap(), 0, bufferW );
return ret;
}
/******************************************************************************
* GetLocaleInfoA (KERNEL32.@)
*
* NOTES
* LANG_NEUTRAL is equal to LOCALE_SYSTEM_DEFAULT
*
* MS online documentation states that the string returned is NULL terminated
* except for LOCALE_FONTSIGNATURE which "will return a non-NULL
* terminated string".
*/
INT WINAPI GetLocaleInfoW( LCID lcid, LCTYPE lctype, LPWSTR buffer, INT len )
{
LANGID lang_id;
HRSRC hrsrc;
HGLOBAL hmem;
HMODULE hModule;
INT ret;
UINT lcflags;
const WCHAR *p;
int i;
if (len < 0 || (len && !buffer))
{
SetLastError( ERROR_INVALID_PARAMETER );
return 0;
}
if (!len) buffer = NULL;
if (lcid == LOCALE_NEUTRAL || lcid == LANG_SYSTEM_DEFAULT) lcid = GetSystemDefaultLCID();
else if (lcid == LANG_USER_DEFAULT) lcid = GetUserDefaultLCID();
lcflags = lctype & LOCALE_LOCALEINFOFLAGSMASK;
lctype &= ~LOCALE_LOCALEINFOFLAGSMASK;
/* first check for overrides in the registry */
if (!(lcflags & LOCALE_NOUSEROVERRIDE) && lcid == GetUserDefaultLCID())
{
const WCHAR *value = get_locale_value_name(lctype);
if (value && ((ret = get_registry_locale_info( value, buffer, len )) != -1)) return ret;
}
/* now load it from kernel resources */
lang_id = LANGIDFROMLCID( lcid );
/* replace SUBLANG_NEUTRAL by SUBLANG_DEFAULT */
if (SUBLANGID(lang_id) == SUBLANG_NEUTRAL)
lang_id = MAKELANGID(PRIMARYLANGID(lang_id), SUBLANG_DEFAULT);
hModule = GetModuleHandleA( "kernel32.dll" );
if (!(hrsrc = FindResourceExW( hModule, RT_STRINGW, (LPCWSTR)((lctype >> 4) + 1), lang_id )))
{
SetLastError( ERROR_INVALID_FLAGS ); /* no such lctype */
return 0;
}
if (!(hmem = LoadResource( hModule, hrsrc )))
return 0;
p = LockResource( hmem );
for (i = 0; i < (lctype & 0x0f); i++) p += *p + 1;
if (lcflags & LOCALE_RETURN_NUMBER) ret = sizeof(UINT)/sizeof(WCHAR);
else ret = (lctype == LOCALE_FONTSIGNATURE) ? *p : *p + 1;
if (!buffer) return ret;
if (ret > len)
{
SetLastError( ERROR_INSUFFICIENT_BUFFER );
return 0;
}
if (lcflags & LOCALE_RETURN_NUMBER)
{
UINT number;
WCHAR *end, *tmp = HeapAlloc( GetProcessHeap(), 0, (*p + 1) * sizeof(WCHAR) );
if (!tmp) return 0;
memcpy( tmp, p + 1, *p * sizeof(WCHAR) );
tmp[*p] = 0;
number = strtolW( tmp, &end, 10 );
if (!*end)
memcpy( buffer, &number, sizeof(number) );
else /* invalid number */
{
SetLastError( ERROR_INVALID_FLAGS );
ret = 0;
}
HeapFree( GetProcessHeap(), 0, tmp );
TRACE( "(lcid=0x%lx,lctype=0x%lx,%p,%d) returning number %d\n",
lcid, lctype, buffer, len, number );
}
else
{
memcpy( buffer, p + 1, *p * sizeof(WCHAR) );
if (lctype != LOCALE_FONTSIGNATURE) buffer[ret-1] = 0;
TRACE( "(lcid=0x%lx,lctype=0x%lx,%p,%d) returning %d %s\n",
lcid, lctype, buffer, len, ret, debugstr_w(buffer) );
}
return ret;
}
/******************************************************************************
* SetLocaleInfoA [KERNEL32.@]
*/
BOOL WINAPI SetLocaleInfoA(LCID lcid, LCTYPE lctype, LPCSTR data)
{
UINT codepage = CP_ACP;
WCHAR *strW;
DWORD len;
BOOL ret;
if (lcid == LOCALE_NEUTRAL || lcid == LANG_SYSTEM_DEFAULT) lcid = GetSystemDefaultLCID();
else if (lcid == LANG_USER_DEFAULT) lcid = GetUserDefaultLCID();
if (!(lctype & LOCALE_USE_CP_ACP)) codepage = get_lcid_codepage( lcid );
len = MultiByteToWideChar( codepage, 0, data, -1, NULL, 0 );
if (!(strW = HeapAlloc( GetProcessHeap(), 0, len * sizeof(WCHAR) )))
{
SetLastError( ERROR_NOT_ENOUGH_MEMORY );
return FALSE;
}
MultiByteToWideChar( codepage, 0, data, -1, strW, len );
ret = SetLocaleInfoW( lcid, lctype, strW );
HeapFree( GetProcessHeap(), 0, strW );
return ret;
}
/******************************************************************************
* SetLocaleInfoW (KERNEL32.@)
*/
BOOL WINAPI SetLocaleInfoW( LCID lcid, LCTYPE lctype, LPCWSTR data )
{
const WCHAR *value;
const WCHAR intlW[] = {'i','n','t','l',0 };
UNICODE_STRING valueW;
NTSTATUS status;
HKEY hkey;
if (lcid == LOCALE_NEUTRAL || lcid == LANG_SYSTEM_DEFAULT) lcid = GetSystemDefaultLCID();
else if (lcid == LANG_USER_DEFAULT) lcid = GetUserDefaultLCID();
if (!(value = get_locale_value_name( lctype )))
{
SetLastError( ERROR_INVALID_PARAMETER );
return FALSE;
}
if (lcid != GetUserDefaultLCID()) return TRUE; /* fake success */
TRACE("setting %lx to %s\n", lctype, debugstr_w(data) );
/* FIXME: should check that data to set is sane */
/* FIXME: profile functions should map to registry */
WriteProfileStringW( intlW, value, data );
if (RegCreateKeyExA( HKEY_CURRENT_USER, "Control Panel\\International", 0, NULL,
0, KEY_ALL_ACCESS, NULL, &hkey, NULL )) return FALSE;
RtlInitUnicodeString( &valueW, value );
status = NtSetValueKey( hkey, &valueW, 0, REG_SZ, data, (strlenW(data)+1)*sizeof(WCHAR) );
RegCloseKey( hkey );
if (status) SetLastError( RtlNtStatusToDosError(status) );
return !status;
return TRUE;
}
/***********************************************************************
* GetThreadLocale (KERNEL32.@)
*/
LCID WINAPI GetThreadLocale(void)
{
LCID ret = NtCurrentTeb()->CurrentLocale;
if (!ret) NtCurrentTeb()->CurrentLocale = ret = GetUserDefaultLCID();
return ret;
}
/**********************************************************************
* SetThreadLocale (KERNEL32.@)
*
* FIXME
* check if lcid is a valid cp
*/
BOOL WINAPI SetThreadLocale( LCID lcid ) /* [in] Locale identifier */
{
if (lcid == LOCALE_NEUTRAL || lcid == LANG_SYSTEM_DEFAULT) lcid = GetSystemDefaultLCID();
else if (lcid == LANG_USER_DEFAULT) lcid = GetUserDefaultLCID();
NtCurrentTeb()->CurrentLocale = lcid;
NtCurrentTeb()->code_page = get_lcid_codepage( lcid );
return TRUE;
}
/******************************************************************************
* GetStringTypeW (KERNEL32.@)
*/
BOOL WINAPI GetStringTypeW( DWORD type, LPCWSTR src, INT count, LPWORD chartype )
{
if (count == -1) count = strlenW(src) + 1;
switch(type)
{
case CT_CTYPE1:
while (count--) *chartype++ = get_char_typeW( *src++ ) & 0xfff;
break;
case CT_CTYPE2:
while (count--) *chartype++ = get_char_typeW( *src++ ) >> 12;
break;
case CT_CTYPE3:
{
WARN("CT_CTYPE3: semi-stub.\n");
while (count--)
{
int c = *src;
WORD type1, type3 = 0; /* C3_NOTAPPLICABLE */
type1 = get_char_typeW( *src++ ) & 0xfff;
/* try to construct type3 from type1 */
if(type1 & C1_SPACE) type3 |= C3_SYMBOL;
if(type1 & C1_ALPHA) type3 |= C3_ALPHA;
if ((c>=0x30A0)&&(c<=0x30FF)) type3 |= C3_KATAKANA;
if ((c>=0x3040)&&(c<=0x309F)) type3 |= C3_HIRAGANA;
if ((c>=0x4E00)&&(c<=0x9FAF)) type3 |= C3_IDEOGRAPH;
if ((c>=0x0600)&&(c<=0x06FF)) type3 |= C3_KASHIDA;
if ((c>=0x3000)&&(c<=0x303F)) type3 |= C3_SYMBOL;
if ((c>=0xFF00)&&(c<=0xFF60)) type3 |= C3_FULLWIDTH;
if ((c>=0xFF00)&&(c<=0xFF20)) type3 |= C3_SYMBOL;
if ((c>=0xFF3B)&&(c<=0xFF40)) type3 |= C3_SYMBOL;
if ((c>=0xFF5B)&&(c<=0xFF60)) type3 |= C3_SYMBOL;
if ((c>=0xFF21)&&(c<=0xFF3A)) type3 |= C3_ALPHA;
if ((c>=0xFF41)&&(c<=0xFF5A)) type3 |= C3_ALPHA;
if ((c>=0xFFE0)&&(c<=0xFFE6)) type3 |= C3_FULLWIDTH;
if ((c>=0xFFE0)&&(c<=0xFFE6)) type3 |= C3_SYMBOL;
if ((c>=0xFF61)&&(c<=0xFFDC)) type3 |= C3_HALFWIDTH;
if ((c>=0xFF61)&&(c<=0xFF64)) type3 |= C3_SYMBOL;
if ((c>=0xFF65)&&(c<=0xFF9F)) type3 |= C3_KATAKANA;
if ((c>=0xFF65)&&(c<=0xFF9F)) type3 |= C3_ALPHA;
if ((c>=0xFFE8)&&(c<=0xFFEE)) type3 |= C3_HALFWIDTH;
if ((c>=0xFFE8)&&(c<=0xFFEE)) type3 |= C3_SYMBOL;
*chartype++ = type3;
}
break;
}
default:
SetLastError( ERROR_INVALID_PARAMETER );
return FALSE;
}
return TRUE;
}
/******************************************************************************
* GetStringTypeExW (KERNEL32.@)
*/
BOOL WINAPI GetStringTypeExW( LCID locale, DWORD type, LPCWSTR src, INT count, LPWORD chartype )
{
/* locale is ignored for Unicode */
return GetStringTypeW( type, src, count, chartype );
}
/******************************************************************************
* GetStringTypeA (KERNEL32.@)
*/
BOOL WINAPI GetStringTypeA( LCID locale, DWORD type, LPCSTR src, INT count, LPWORD chartype )
{
UINT cp;
INT countW;
LPWSTR srcW;
BOOL ret = FALSE;
if(count == -1) count = strlen(src) + 1;
if (!(cp = get_lcid_codepage( locale )))
{
FIXME("For locale %04lx using current ANSI code page\n", locale);
cp = GetACP();
}
countW = MultiByteToWideChar(cp, 0, src, count, NULL, 0);
if((srcW = HeapAlloc(GetProcessHeap(), 0, countW * sizeof(WCHAR))))
{
MultiByteToWideChar(cp, 0, src, count, srcW, countW);
/*
* NOTE: the target buffer has 1 word for each CHARACTER in the source
* string, with multibyte characters there maybe be more bytes in count
* than character space in the buffer!
*/
ret = GetStringTypeW(type, srcW, countW, chartype);
HeapFree(GetProcessHeap(), 0, srcW);
}
return ret;
}
/******************************************************************************
* GetStringTypeExA (KERNEL32.@)
*/
BOOL WINAPI GetStringTypeExA( LCID locale, DWORD type, LPCSTR src, INT count, LPWORD chartype )
{
return GetStringTypeA(locale, type, src, count, chartype);
}
/******************************************************************************
* LOCALE_Init
*/
void LOCALE_Init(void)
{
UINT ansi = 1252, oem = 437, mac = 10000;
LCID lcid = init_default_lcid();
GetLocaleInfoW( lcid, LOCALE_IDEFAULTANSICODEPAGE | LOCALE_RETURN_NUMBER,
(LPWSTR)&ansi, sizeof(ansi)/sizeof(WCHAR) );
GetLocaleInfoW( lcid, LOCALE_IDEFAULTMACCODEPAGE | LOCALE_RETURN_NUMBER,
(LPWSTR)&mac, sizeof(mac)/sizeof(WCHAR) );
GetLocaleInfoW( lcid, LOCALE_IDEFAULTCODEPAGE | LOCALE_RETURN_NUMBER,
(LPWSTR)&oem, sizeof(oem)/sizeof(WCHAR) );
CODEPAGE_Init( ansi, oem, mac, lcid );
update_registry( lcid );
}

View File

@ -70,7 +70,6 @@ C_SRCS = \
$(TOPOBJDIR)/msdos/ioports.c \
$(TOPOBJDIR)/msdos/ppdev.c \
$(TOPOBJDIR)/msdos/vxd.c \
$(TOPOBJDIR)/ole/ole2nls.c \
$(TOPOBJDIR)/relay32/builtin32.c \
$(TOPOBJDIR)/relay32/relay386.c \
$(TOPOBJDIR)/relay32/snoop.c \
@ -131,7 +130,6 @@ EXTRASUBDIRS = \
$(TOPOBJDIR)/memory \
$(TOPOBJDIR)/misc \
$(TOPOBJDIR)/msdos \
$(TOPOBJDIR)/ole \
$(TOPOBJDIR)/relay32 \
$(TOPOBJDIR)/scheduler \
$(TOPOBJDIR)/win32

View File

@ -103,7 +103,8 @@ typedef struct _TEB
DWORD unknown6[5]; /* --n 1e8 Unknown */
/* The following are Wine-specific fields (NT: GDI stuff) */
DWORD unused[4]; /* --3 1fc Was server buffer */
UINT code_page; /* --3 1fc Thread code page */
DWORD unused[3]; /* --3 200 Was server buffer */
int request_fd; /* --3 20c fd for sending server requests */
int reply_fd; /* --3 210 fd for receiving server replies */
int wait_fd[2]; /* --3 214 fd for sleeping server requests */

View File

@ -39,8 +39,6 @@ extern "C" {
#define LOCALE_USE_CP_ACP 0x40000000
#define LOCALE_RETURN_NUMBER 0x20000000
#define LOCALE_LOCALEINFOFLAGSMASK 0xC0000000
/* When adding new defines, don't forget to add an entry to the
* locale_name2id map in ole/ole2nls.c
*/

View File

@ -27,6 +27,7 @@
#include "winerror.h"
#include "winnls.h"
#include "wine/unicode.h"
#include "thread.h"
#include "wine/debug.h"
WINE_DEFAULT_DEBUG_CHANNEL(string);
@ -35,16 +36,7 @@ WINE_DEFAULT_DEBUG_CHANNEL(string);
static const union cptable *ansi_cptable;
static const union cptable *oem_cptable;
static const union cptable *mac_cptable;
/* retrieve a code page table from the locale info */
static const union cptable *get_locale_cp( LCID lcid, LCTYPE type )
{
const union cptable *table = NULL;
char buf[32];
if (GetLocaleInfoA( lcid, type, buf, sizeof(buf) )) table = cp_get_table( atoi(buf) );
return table;
}
static LCID default_lcid = MAKELCID( MAKELANGID(LANG_ENGLISH,SUBLANG_DEFAULT), SORT_DEFAULT );
/* setup default codepage info before we can get at the locale stuff */
static void init_codepages(void)
@ -66,13 +58,18 @@ static const union cptable *get_codepage_table( unsigned int codepage )
switch(codepage)
{
case CP_ACP: return ansi_cptable;
case CP_OEMCP: return oem_cptable;
case CP_MACCP: return mac_cptable;
case CP_THREAD_ACP: return get_locale_cp( GetThreadLocale(), LOCALE_IDEFAULTANSICODEPAGE );
case CP_ACP:
return ansi_cptable;
case CP_OEMCP:
return oem_cptable;
case CP_MACCP:
return mac_cptable;
case CP_UTF7:
case CP_UTF8:
break;
case CP_THREAD_ACP:
if (!(codepage = NtCurrentTeb()->code_page)) return ansi_cptable;
/* fall through */
default:
if (codepage == ansi_cptable->info.codepage) return ansi_cptable;
if (codepage == oem_cptable->info.codepage) return oem_cptable;
@ -86,17 +83,17 @@ static const union cptable *get_codepage_table( unsigned int codepage )
/* initialize default code pages from locale info */
/* FIXME: should be done in init_codepages, but it can't right now */
/* since it needs KERNEL32 to be loaded for the locale info. */
void CODEPAGE_Init(void)
void CODEPAGE_Init( UINT ansi, UINT oem, UINT mac, LCID lcid )
{
extern void __wine_init_codepages( const union cptable *ansi, const union cptable *oem );
const union cptable *table;
LCID lcid = GetUserDefaultLCID();
default_lcid = lcid;
if (!ansi_cptable) init_codepages(); /* just in case */
if ((table = get_locale_cp( lcid, LOCALE_IDEFAULTANSICODEPAGE ))) ansi_cptable = table;
if ((table = get_locale_cp( lcid, LOCALE_IDEFAULTMACCODEPAGE ))) mac_cptable = table;
if ((table = get_locale_cp( lcid, LOCALE_IDEFAULTCODEPAGE ))) oem_cptable = table;
if ((table = cp_get_table( ansi ))) ansi_cptable = table;
if ((table = cp_get_table( oem ))) oem_cptable = table;
if ((table = cp_get_table( mac ))) mac_cptable = table;
__wine_init_codepages( ansi_cptable, oem_cptable );
TRACE( "ansi=%03d oem=%03d mac=%03d\n", ansi_cptable->info.codepage,
@ -111,7 +108,7 @@ void CODEPAGE_Init(void)
*/
UINT WINAPI GetACP(void)
{
if (!ansi_cptable) init_codepages();
if (!ansi_cptable) return 1252;
return ansi_cptable->info.codepage;
}
@ -121,7 +118,7 @@ UINT WINAPI GetACP(void)
*/
UINT WINAPI GetOEMCP(void)
{
if (!oem_cptable) init_codepages();
if (!oem_cptable) return 437;
return oem_cptable->info.codepage;
}
@ -143,6 +140,42 @@ BOOL WINAPI IsValidCodePage( UINT codepage )
}
/***********************************************************************
* GetUserDefaultLangID (KERNEL32.@)
*/
LANGID WINAPI GetUserDefaultLangID(void)
{
return LANGIDFROMLCID(default_lcid);
}
/***********************************************************************
* GetSystemDefaultLangID (KERNEL32.@)
*/
LANGID WINAPI GetSystemDefaultLangID(void)
{
return GetUserDefaultLangID();
}
/***********************************************************************
* GetUserDefaultLCID (KERNEL32.@)
*/
LCID WINAPI GetUserDefaultLCID(void)
{
return default_lcid;
}
/***********************************************************************
* GetSystemDefaultLCID (KERNEL32.@)
*/
LCID WINAPI GetSystemDefaultLCID(void)
{
return GetUserDefaultLCID();
}
/***********************************************************************
* IsDBCSLeadByteEx (KERNEL32.@)
*/
@ -159,7 +192,7 @@ BOOL WINAPI IsDBCSLeadByteEx( UINT codepage, BYTE testchar )
*/
BOOL WINAPI IsDBCSLeadByte( BYTE testchar )
{
if (!ansi_cptable) init_codepages();
if (!ansi_cptable) return FALSE;
return is_dbcs_leadbyte( ansi_cptable, testchar );
}
@ -383,118 +416,3 @@ INT WINAPI WideCharToMultiByte( UINT page, DWORD flags, LPCWSTR src, INT srclen,
}
return ret;
}
/******************************************************************************
* GetStringTypeW (KERNEL32.@)
*
*/
BOOL WINAPI GetStringTypeW( DWORD type, LPCWSTR src, INT count, LPWORD chartype )
{
if (count == -1) count = strlenW(src) + 1;
switch(type)
{
case CT_CTYPE1:
while (count--) *chartype++ = get_char_typeW( *src++ ) & 0xfff;
break;
case CT_CTYPE2:
while (count--) *chartype++ = get_char_typeW( *src++ ) >> 12;
break;
case CT_CTYPE3:
{
WARN("CT_CTYPE3: semi-stub.\n");
while (count--)
{
int c = *src;
WORD type1, type3 = 0; /* C3_NOTAPPLICABLE */
type1 = get_char_typeW( *src++ ) & 0xfff;
/* try to construct type3 from type1 */
if(type1 & C1_SPACE) type3 |= C3_SYMBOL;
if(type1 & C1_ALPHA) type3 |= C3_ALPHA;
if ((c>=0x30A0)&&(c<=0x30FF)) type3 |= C3_KATAKANA;
if ((c>=0x3040)&&(c<=0x309F)) type3 |= C3_HIRAGANA;
if ((c>=0x4E00)&&(c<=0x9FAF)) type3 |= C3_IDEOGRAPH;
if ((c>=0x0600)&&(c<=0x06FF)) type3 |= C3_KASHIDA;
if ((c>=0x3000)&&(c<=0x303F)) type3 |= C3_SYMBOL;
if ((c>=0xFF00)&&(c<=0xFF60)) type3 |= C3_FULLWIDTH;
if ((c>=0xFF00)&&(c<=0xFF20)) type3 |= C3_SYMBOL;
if ((c>=0xFF3B)&&(c<=0xFF40)) type3 |= C3_SYMBOL;
if ((c>=0xFF5B)&&(c<=0xFF60)) type3 |= C3_SYMBOL;
if ((c>=0xFF21)&&(c<=0xFF3A)) type3 |= C3_ALPHA;
if ((c>=0xFF41)&&(c<=0xFF5A)) type3 |= C3_ALPHA;
if ((c>=0xFFE0)&&(c<=0xFFE6)) type3 |= C3_FULLWIDTH;
if ((c>=0xFFE0)&&(c<=0xFFE6)) type3 |= C3_SYMBOL;
if ((c>=0xFF61)&&(c<=0xFFDC)) type3 |= C3_HALFWIDTH;
if ((c>=0xFF61)&&(c<=0xFF64)) type3 |= C3_SYMBOL;
if ((c>=0xFF65)&&(c<=0xFF9F)) type3 |= C3_KATAKANA;
if ((c>=0xFF65)&&(c<=0xFF9F)) type3 |= C3_ALPHA;
if ((c>=0xFFE8)&&(c<=0xFFEE)) type3 |= C3_HALFWIDTH;
if ((c>=0xFFE8)&&(c<=0xFFEE)) type3 |= C3_SYMBOL;
*chartype++ = type3;
}
break;
}
default:
SetLastError( ERROR_INVALID_PARAMETER );
return FALSE;
}
return TRUE;
}
/******************************************************************************
* GetStringTypeExW (KERNEL32.@)
*/
BOOL WINAPI GetStringTypeExW( LCID locale, DWORD type, LPCWSTR src, INT count, LPWORD chartype )
{
/* locale is ignored for Unicode */
return GetStringTypeW( type, src, count, chartype );
}
/******************************************************************************
* GetStringTypeA [KERNEL32.@]
*/
BOOL WINAPI GetStringTypeA(LCID locale, DWORD type, LPCSTR src, INT count, LPWORD chartype)
{
char buf[20];
UINT cp;
INT countW;
LPWSTR srcW;
BOOL ret = FALSE;
if(count == -1) count = strlen(src) + 1;
if(!GetLocaleInfoA(locale, LOCALE_IDEFAULTANSICODEPAGE | LOCALE_NOUSEROVERRIDE,
buf, sizeof(buf)))
{
FIXME("For locale %04lx using current ANSI code page\n", locale);
cp = GetACP();
}
else
cp = atoi(buf);
countW = MultiByteToWideChar(cp, 0, src, count, NULL, 0);
if((srcW = HeapAlloc(GetProcessHeap(), 0, countW * sizeof(WCHAR))))
{
MultiByteToWideChar(cp, 0, src, count, srcW, countW);
/*
* NOTE: the target buffer has 1 word for each CHARACTER in the source
* string, with multibyte characters there maybe be more bytes in count
* than character space in the buffer!
*/
ret = GetStringTypeW(type, srcW, countW, chartype);
HeapFree(GetProcessHeap(), 0, srcW);
}
return ret;
}
/******************************************************************************
* GetStringTypeExA [KERNEL32.@]
*/
BOOL WINAPI GetStringTypeExA(LCID locale, DWORD type, LPCSTR src, INT count, LPWORD chartype)
{
return GetStringTypeA(locale, type, src, count, chartype);
}

View File

@ -117,58 +117,6 @@ SEGPTR WINAPI lstrcatn16( SEGPTR dst, LPCSTR src, INT16 n )
}
/***********************************************************************
* lstrcmp (KERNEL32.@)
* lstrcmpA (KERNEL32.@)
*/
INT WINAPI lstrcmpA( LPCSTR str1, LPCSTR str2 )
{
return CompareStringA(LOCALE_SYSTEM_DEFAULT,0,str1,-1,str2,-1) - 2 ;
}
/***********************************************************************
* lstrcmpW (KERNEL32.@)
* FIXME : should call CompareStringW, when it is implemented.
* This implementation is not "word sort", as it should.
*/
INT WINAPI lstrcmpW( LPCWSTR str1, LPCWSTR str2 )
{
TRACE("%s and %s\n",
debugstr_w (str1), debugstr_w (str2));
if (!str1 || !str2) {
SetLastError(ERROR_INVALID_PARAMETER);
return 0;
}
while (*str1 && (*str1 == *str2)) { str1++; str2++; }
return (INT)(*str1 - *str2);
}
/***********************************************************************
* lstrcmpi (KERNEL32.@)
* lstrcmpiA (KERNEL32.@)
*/
INT WINAPI lstrcmpiA( LPCSTR str1, LPCSTR str2 )
{ TRACE("strcmpi %s and %s\n",
debugstr_a (str1), debugstr_a (str2));
return CompareStringA(LOCALE_SYSTEM_DEFAULT,NORM_IGNORECASE,str1,-1,str2,-1)-2;
}
/***********************************************************************
* lstrcmpiW (KERNEL32.@)
*/
INT WINAPI lstrcmpiW( LPCWSTR str1, LPCWSTR str2 )
{
if (!str1 || !str2) {
SetLastError(ERROR_INVALID_PARAMETER);
return 0;
}
return strcmpiW( str1, str2 );
}
/***********************************************************************
* lstrcpy (KERNEL.88)
*/

View File

@ -33,6 +33,7 @@
#include "winbase.h"
#include "wingdi.h"
#include "winuser.h"
#include "ntddk.h"
#include "wine/unicode.h"
#include "winver.h"
#include "winnls.h"
@ -40,365 +41,8 @@
#include "winerror.h"
#include "wine/debug.h"
WINE_DEFAULT_DEBUG_CHANNEL(string);
WINE_DEFAULT_DEBUG_CHANNEL(nls);
/* Locale name to id map. used by EnumSystemLocales, GetLocaleInfoA
* MUST contain all #defines from winnls.h
* last entry has NULL name, 0 id.
*/
#define LOCALE_ENTRY(x) {#x,LOCALE_##x}
static const struct tagLOCALE_NAME2ID {
const char *name;
LCTYPE id;
} locale_name2id[]= {
LOCALE_ENTRY(ILANGUAGE),
LOCALE_ENTRY(SLANGUAGE),
LOCALE_ENTRY(SENGLANGUAGE),
LOCALE_ENTRY(SABBREVLANGNAME),
LOCALE_ENTRY(SNATIVELANGNAME),
LOCALE_ENTRY(ICOUNTRY),
LOCALE_ENTRY(SCOUNTRY),
LOCALE_ENTRY(SENGCOUNTRY),
LOCALE_ENTRY(SABBREVCTRYNAME),
LOCALE_ENTRY(SNATIVECTRYNAME),
LOCALE_ENTRY(IDEFAULTLANGUAGE),
LOCALE_ENTRY(IDEFAULTCOUNTRY),
LOCALE_ENTRY(IDEFAULTCODEPAGE),
LOCALE_ENTRY(IDEFAULTANSICODEPAGE),
LOCALE_ENTRY(IDEFAULTMACCODEPAGE),
LOCALE_ENTRY(SLIST),
LOCALE_ENTRY(IMEASURE),
LOCALE_ENTRY(SDECIMAL),
LOCALE_ENTRY(STHOUSAND),
LOCALE_ENTRY(SGROUPING),
LOCALE_ENTRY(IDIGITS),
LOCALE_ENTRY(ILZERO),
LOCALE_ENTRY(INEGNUMBER),
LOCALE_ENTRY(SNATIVEDIGITS),
LOCALE_ENTRY(SCURRENCY),
LOCALE_ENTRY(SINTLSYMBOL),
LOCALE_ENTRY(SMONDECIMALSEP),
LOCALE_ENTRY(SMONTHOUSANDSEP),
LOCALE_ENTRY(SMONGROUPING),
LOCALE_ENTRY(ICURRDIGITS),
LOCALE_ENTRY(IINTLCURRDIGITS),
LOCALE_ENTRY(ICURRENCY),
LOCALE_ENTRY(INEGCURR),
LOCALE_ENTRY(SDATE),
LOCALE_ENTRY(STIME),
LOCALE_ENTRY(SSHORTDATE),
LOCALE_ENTRY(SLONGDATE),
LOCALE_ENTRY(STIMEFORMAT),
LOCALE_ENTRY(IDATE),
LOCALE_ENTRY(ILDATE),
LOCALE_ENTRY(ITIME),
LOCALE_ENTRY(ITIMEMARKPOSN),
LOCALE_ENTRY(ICENTURY),
LOCALE_ENTRY(ITLZERO),
LOCALE_ENTRY(IDAYLZERO),
LOCALE_ENTRY(IMONLZERO),
LOCALE_ENTRY(S1159),
LOCALE_ENTRY(S2359),
LOCALE_ENTRY(ICALENDARTYPE),
LOCALE_ENTRY(IOPTIONALCALENDAR),
LOCALE_ENTRY(IFIRSTDAYOFWEEK),
LOCALE_ENTRY(IFIRSTWEEKOFYEAR),
LOCALE_ENTRY(SDAYNAME1),
LOCALE_ENTRY(SDAYNAME2),
LOCALE_ENTRY(SDAYNAME3),
LOCALE_ENTRY(SDAYNAME4),
LOCALE_ENTRY(SDAYNAME5),
LOCALE_ENTRY(SDAYNAME6),
LOCALE_ENTRY(SDAYNAME7),
LOCALE_ENTRY(SABBREVDAYNAME1),
LOCALE_ENTRY(SABBREVDAYNAME2),
LOCALE_ENTRY(SABBREVDAYNAME3),
LOCALE_ENTRY(SABBREVDAYNAME4),
LOCALE_ENTRY(SABBREVDAYNAME5),
LOCALE_ENTRY(SABBREVDAYNAME6),
LOCALE_ENTRY(SABBREVDAYNAME7),
LOCALE_ENTRY(SMONTHNAME1),
LOCALE_ENTRY(SMONTHNAME2),
LOCALE_ENTRY(SMONTHNAME3),
LOCALE_ENTRY(SMONTHNAME4),
LOCALE_ENTRY(SMONTHNAME5),
LOCALE_ENTRY(SMONTHNAME6),
LOCALE_ENTRY(SMONTHNAME7),
LOCALE_ENTRY(SMONTHNAME8),
LOCALE_ENTRY(SMONTHNAME9),
LOCALE_ENTRY(SMONTHNAME10),
LOCALE_ENTRY(SMONTHNAME11),
LOCALE_ENTRY(SMONTHNAME12),
LOCALE_ENTRY(SMONTHNAME13),
LOCALE_ENTRY(SABBREVMONTHNAME1),
LOCALE_ENTRY(SABBREVMONTHNAME2),
LOCALE_ENTRY(SABBREVMONTHNAME3),
LOCALE_ENTRY(SABBREVMONTHNAME4),
LOCALE_ENTRY(SABBREVMONTHNAME5),
LOCALE_ENTRY(SABBREVMONTHNAME6),
LOCALE_ENTRY(SABBREVMONTHNAME7),
LOCALE_ENTRY(SABBREVMONTHNAME8),
LOCALE_ENTRY(SABBREVMONTHNAME9),
LOCALE_ENTRY(SABBREVMONTHNAME10),
LOCALE_ENTRY(SABBREVMONTHNAME11),
LOCALE_ENTRY(SABBREVMONTHNAME12),
LOCALE_ENTRY(SABBREVMONTHNAME13),
LOCALE_ENTRY(SPOSITIVESIGN),
LOCALE_ENTRY(SNEGATIVESIGN),
LOCALE_ENTRY(IPOSSIGNPOSN),
LOCALE_ENTRY(INEGSIGNPOSN),
LOCALE_ENTRY(IPOSSYMPRECEDES),
LOCALE_ENTRY(IPOSSEPBYSPACE),
LOCALE_ENTRY(INEGSYMPRECEDES),
LOCALE_ENTRY(INEGSEPBYSPACE),
LOCALE_ENTRY(FONTSIGNATURE),
LOCALE_ENTRY(SISO639LANGNAME),
LOCALE_ENTRY(SISO3166CTRYNAME),
{NULL,0}
};
static char *GetLocaleSubkeyName( DWORD lctype );
/***********************************************************************
* GetUserDefaultLCID (KERNEL32.@)
*/
LCID WINAPI GetUserDefaultLCID(void)
{
return MAKELCID( GetUserDefaultLangID() , SORT_DEFAULT );
}
/***********************************************************************
* GetSystemDefaultLCID (KERNEL32.@)
*/
LCID WINAPI GetSystemDefaultLCID(void)
{
return GetUserDefaultLCID();
}
#define NLS_MAX_LANGUAGES 20
typedef struct {
char lang[128];
char country[128];
LANGID found_lang_id[NLS_MAX_LANGUAGES];
char found_language[NLS_MAX_LANGUAGES][3];
char found_country[NLS_MAX_LANGUAGES][3];
int n_found;
} LANG_FIND_DATA;
static BOOL CALLBACK NLS_FindLanguageID_ProcA(HMODULE hModule, LPCSTR type,
LPCSTR name, WORD LangID, LONG lParam)
{
LANG_FIND_DATA *l_data = (LANG_FIND_DATA *)lParam;
LCID lcid = MAKELCID(LangID, SORT_DEFAULT);
char buf_language[128];
char buf_country[128];
char buf_en_language[128];
TRACE("%04X\n", (UINT)LangID);
if(PRIMARYLANGID(LangID) == LANG_NEUTRAL)
return TRUE; /* continue search */
buf_language[0] = 0;
buf_country[0] = 0;
GetLocaleInfoA(lcid, LOCALE_SISO639LANGNAME|LOCALE_NOUSEROVERRIDE,
buf_language, sizeof(buf_language));
TRACE("LOCALE_SISO639LANGNAME: %s\n", buf_language);
GetLocaleInfoA(lcid, LOCALE_SISO3166CTRYNAME|LOCALE_NOUSEROVERRIDE,
buf_country, sizeof(buf_country));
TRACE("LOCALE_SISO3166CTRYNAME: %s\n", buf_country);
if(l_data->lang && strlen(l_data->lang) > 0 && !strcasecmp(l_data->lang, buf_language))
{
if(l_data->country && strlen(l_data->country) > 0)
{
if(!strcasecmp(l_data->country, buf_country))
{
l_data->found_lang_id[0] = LangID;
l_data->n_found = 1;
TRACE("Found lang_id %04X for %s_%s\n", LangID, l_data->lang, l_data->country);
return FALSE; /* stop enumeration */
}
}
else /* l_data->country not specified */
{
if(l_data->n_found < NLS_MAX_LANGUAGES)
{
l_data->found_lang_id[l_data->n_found] = LangID;
strncpy(l_data->found_country[l_data->n_found], buf_country, 3);
strncpy(l_data->found_language[l_data->n_found], buf_language, 3);
l_data->n_found++;
TRACE("Found lang_id %04X for %s\n", LangID, l_data->lang);
return TRUE; /* continue search */
}
}
}
/* Just in case, check LOCALE_SENGLANGUAGE too,
* in hope that possible alias name might have that value.
*/
buf_en_language[0] = 0;
GetLocaleInfoA(lcid, LOCALE_SENGLANGUAGE|LOCALE_NOUSEROVERRIDE,
buf_en_language, sizeof(buf_en_language));
TRACE("LOCALE_SENGLANGUAGE: %s\n", buf_en_language);
if(l_data->lang && strlen(l_data->lang) > 0 && !strcasecmp(l_data->lang, buf_en_language))
{
l_data->found_lang_id[l_data->n_found] = LangID;
strncpy(l_data->found_country[l_data->n_found], buf_country, 3);
strncpy(l_data->found_language[l_data->n_found], buf_language, 3);
l_data->n_found++;
TRACE("Found lang_id %04X for %s\n", LangID, l_data->lang);
}
return TRUE; /* continue search */
}
/***********************************************************************
* NLS_GetLanguageID
*
* INPUT:
* Lang: a string whose two first chars are the iso name of a language.
* Country: a string whose two first chars are the iso name of country
* Charset: a string defining the chossen charset encoding
* Dialect: a string defining a variation of the locale
*
* all those values are from the standardized format of locale
* name in unix which is: Lang[_Country][.Charset][@Dialect]
*
* RETURNS:
* the numeric code of the language used by Windows
*
* FIXME: Charset and Dialect are not handled
*/
static LANGID NLS_GetLanguageID(LPCSTR Lang, LPCSTR Country, LPCSTR Charset, LPCSTR Dialect)
{
LANG_FIND_DATA l_data;
char lang_string[256];
if(!Lang)
{
l_data.found_lang_id[0] = MAKELANGID(LANG_ENGLISH, SUBLANG_DEFAULT);
goto END;
}
memset(&l_data, 0, sizeof(LANG_FIND_DATA));
strncpy(l_data.lang, Lang, sizeof(l_data.lang));
if(Country && strlen(Country) > 0)
strncpy(l_data.country, Country, sizeof(l_data.country));
EnumResourceLanguagesA(GetModuleHandleA("KERNEL32"), RT_STRINGA,
(LPCSTR)LOCALE_ILANGUAGE, NLS_FindLanguageID_ProcA, (LONG)&l_data);
strcpy(lang_string, l_data.lang);
if(l_data.country && strlen(l_data.country) > 0)
{
strcat(lang_string, "_");
strcat(lang_string, l_data.country);
}
if(!l_data.n_found)
{
if(l_data.country && strlen(l_data.country) > 0)
{
MESSAGE("Warning: Language '%s' was not found, retrying without country name...\n", lang_string);
l_data.country[0] = 0;
EnumResourceLanguagesA(GetModuleHandleA("KERNEL32"), RT_STRINGA,
(LPCSTR)LOCALE_ILANGUAGE, NLS_FindLanguageID_ProcA, (LONG)&l_data);
}
}
/* Re-evaluate lang_string */
strcpy(lang_string, l_data.lang);
if(l_data.country && strlen(l_data.country) > 0)
{
strcat(lang_string, "_");
strcat(lang_string, l_data.country);
}
if(!l_data.n_found)
{
MESSAGE("Warning: Language '%s' was not recognized, defaulting to English\n", lang_string);
l_data.found_lang_id[0] = MAKELANGID(LANG_ENGLISH, SUBLANG_DEFAULT);
}
else
{
if(l_data.n_found == 1)
TRACE("For language '%s' lang_id %04X was found\n", lang_string, l_data.found_lang_id[0]);
else /* l_data->n_found > 1 */
{
int i;
MESSAGE("For language '%s' several language ids were found:\n", lang_string);
for(i = 0; i < l_data.n_found; i++)
MESSAGE("%s_%s - %04X; ", l_data.found_language[i], l_data.found_country[i], l_data.found_lang_id[i]);
MESSAGE("\nInstead of using first in the list, suggest to define\n"
"your LANG environment variable like this: LANG=%s_%s\n",
l_data.found_language[0], l_data.found_country[0]);
}
}
END:
TRACE("Returning %04X\n", l_data.found_lang_id[0]);
return l_data.found_lang_id[0];
}
/***********************************************************************
* GetUserDefaultLangID (KERNEL32.@)
*/
LANGID WINAPI GetUserDefaultLangID(void)
{
/* caching result, if defined from environment, which should (?) not change during a WINE session */
static LANGID userLCID = 0;
if (userLCID == 0)
{
char buf[256];
char *lang,*country,*charset,*dialect,*next;
if (GetEnvironmentVariableA( "LANGUAGE", buf, sizeof(buf) )) goto ok;
if (GetEnvironmentVariableA( "LANG", buf, sizeof(buf) )) goto ok;
if (GetEnvironmentVariableA( "LC_ALL", buf, sizeof(buf) )) goto ok;
if (GetEnvironmentVariableA( "LC_MESSAGES", buf, sizeof(buf) )) goto ok;
if (GetEnvironmentVariableA( "LC_CTYPE", buf, sizeof(buf) )) goto ok;
return userLCID = MAKELANGID( LANG_ENGLISH, SUBLANG_DEFAULT );
ok:
if (!strcmp(buf,"POSIX") || !strcmp(buf,"C"))
return userLCID = MAKELANGID( LANG_ENGLISH, SUBLANG_DEFAULT );
lang=buf;
do {
next=strchr(lang,':'); if (next) *next++='\0';
dialect=strchr(lang,'@'); if (dialect) *dialect++='\0';
charset=strchr(lang,'.'); if (charset) *charset++='\0';
country=strchr(lang,'_'); if (country) *country++='\0';
userLCID = NLS_GetLanguageID(lang, country, charset, dialect);
lang=next;
} while (lang && !userLCID);
if (!userLCID)
{
MESSAGE( "Warning: language '%s' not recognized, defaulting to English\n",
buf );
userLCID = MAKELANGID( LANG_ENGLISH, SUBLANG_DEFAULT );
}
}
return userLCID;
}
/***********************************************************************
* GetSystemDefaultLangID (KERNEL32.@)
*/
LANGID WINAPI GetSystemDefaultLangID(void)
{
return GetUserDefaultLangID();
}
/******************************************************************************
* ConvertDefaultLocale (KERNEL32.@)
@ -415,357 +59,6 @@ LCID WINAPI ConvertDefaultLocale (LCID lcid)
return MAKELANGID( PRIMARYLANGID(lcid), SUBLANG_NEUTRAL);
}
/* Enhanced version of LoadStringW.
* It takes LanguageId to find and load language dependant resources.
* Resource is copied as is: "binary" strings are not truncated.
* Return: length of resource + 1 to distinguish absent resources
* from the resources with zero length.
*/
static INT NLS_LoadStringExW(HMODULE hModule, LANGID lang_id, UINT res_id, LPWSTR buffer, INT buflen)
{
HRSRC hrsrc;
HGLOBAL hmem;
WCHAR *p;
int string_num;
int i;
/* Replace SUBLANG_NEUTRAL by SUBLANG_DEFAULT */
if(SUBLANGID(lang_id) == SUBLANG_NEUTRAL)
lang_id = MAKELANGID(PRIMARYLANGID(lang_id), SUBLANG_DEFAULT);
hrsrc = FindResourceExW(hModule, RT_STRINGW, (LPCWSTR)((res_id >> 4) + 1), lang_id);
if(!hrsrc) return 0;
hmem = LoadResource(hModule, hrsrc);
if(!hmem) return 0;
p = LockResource(hmem);
string_num = res_id & 0x000f;
for(i = 0; i < string_num; i++)
p += *p + 1;
TRACE("strlen = %d\n", (int)*p );
if (buffer == NULL) return *p;
i = min(buflen - 1, *p);
if (i > 0) {
memcpy(buffer, p + 1, i * sizeof (WCHAR));
buffer[i] = (WCHAR) 0;
} else {
if (buflen > 1)
buffer[0] = (WCHAR) 0;
}
FreeResource(hmem);
TRACE("%s loaded!\n", debugstr_w(buffer));
return (i + 1);
}
/******************************************************************************
* GetLocaleInfoA (KERNEL32.@)
*
* NOTES
* LANG_NEUTRAL is equal to LOCALE_SYSTEM_DEFAULT
*
* MS online documentation states that the string returned is NULL terminated
* except for LOCALE_FONTSIGNATURE which "will return a non-NULL
* terminated string".
*/
INT WINAPI GetLocaleInfoA(LCID lcid,LCTYPE LCType,LPSTR buf,INT len)
{
LPCSTR retString = NULL;
int found = 0, i;
char *pacKey;
char acBuffer[128];
DWORD dwBufferSize=128;
BOOL NoUserOverride;
TRACE("(lcid=0x%lx,lctype=0x%lx,%p,%x)\n",lcid,LCType,buf,len);
if (len && (! buf) ) {
SetLastError(ERROR_INSUFFICIENT_BUFFER);
return 0;
}
if (lcid == LOCALE_NEUTRAL || lcid == LANG_SYSTEM_DEFAULT)
{
lcid = GetSystemDefaultLCID();
}
else if (lcid == LANG_USER_DEFAULT) /*0x800*/
{
lcid = GetUserDefaultLCID();
}
/* LOCALE_NOUSEROVERRIDE means: do not get user redefined settings
from the registry. Instead, use system default values. */
NoUserOverride = (LCType & LOCALE_NOUSEROVERRIDE) != 0;
LCType &= ~(LOCALE_NOUSEROVERRIDE|LOCALE_USE_CP_ACP);
/* First, check if it's in the registry. */
/* All user customized values are stored in the registry by SetLocaleInfo */
if ( !NoUserOverride && (pacKey = GetLocaleSubkeyName(LCType)) )
{
char acRealKey[128];
HKEY hKey;
sprintf( acRealKey, "Control Panel\\International\\%s", pacKey );
if ( RegOpenKeyExA( HKEY_CURRENT_USER, acRealKey,
0, KEY_READ, &hKey) == ERROR_SUCCESS )
{
if ( RegQueryValueExA( hKey, NULL, NULL, NULL, (LPBYTE)acBuffer,
&dwBufferSize ) == ERROR_SUCCESS )
{
retString = acBuffer;
found = 1;
}
RegCloseKey(hKey);
}
}
/* If not in the registry, get it from the NLS entries. */
if(!found) {
WCHAR wcBuffer[128];
int res_size;
/* check if language is registered in the kernel32 resources */
if((res_size = NLS_LoadStringExW(GetModuleHandleA("KERNEL32"), LANGIDFROMLCID(lcid),
LCType, wcBuffer, sizeof(wcBuffer)/sizeof(wcBuffer[0])))) {
WideCharToMultiByte(CP_ACP, 0, wcBuffer, res_size, acBuffer, dwBufferSize, NULL, NULL);
retString = acBuffer;
found = 1;
}
}
/* if not found report a most descriptive error */
if(!found) {
retString=0;
/* If we are through all of this, retLen should not be zero anymore.
If it is, the value is not supported */
i=0;
while (locale_name2id[i].name!=NULL) {
if (LCType == locale_name2id[i].id) {
retString = locale_name2id[i].name;
break;
}
i++;
}
if(!retString)
FIXME("Unkown LC type %lX\n", LCType);
else
FIXME("'%s' is not defined for your language (%04X).\n"
"Please define it in dlls/kernel/nls/YourLanguage.nls\n"
"and submit patch for inclusion into the next Wine release.\n",
retString, LOWORD(lcid));
SetLastError(ERROR_INVALID_PARAMETER);
return 0;
}
/* a FONTSIGNATURE is not a string, just 6 DWORDs */
if (LCType == LOCALE_FONTSIGNATURE) {
if (len) {
len = (len < sizeof(FONTSIGNATURE)) ? len : sizeof(FONTSIGNATURE);
memcpy(buf, retString, len);
return len;
}
return sizeof(FONTSIGNATURE);
}
/* if len=0 return only the length, don't touch the buffer*/
if (len) {
/* Like Windows we copy len bytes to buffer and we check len after */
INT ret = strlen(retString) + 1;
memcpy( buf, retString, min(len, ret) );
return (len < ret) ? 0 : ret;
}
return strlen(retString)+1;
}
/******************************************************************************
* GetLocaleInfoW (KERNEL32.@)
*
* NOTES
* MS documentation states that len "specifies the size, in bytes (ANSI version)
* or characters (Unicode version), of" wbuf. Thus the number returned is
* the same between GetLocaleInfoW and GetLocaleInfoA.
*/
INT WINAPI GetLocaleInfoW(LCID lcid,LCTYPE LCType,LPWSTR wbuf,INT len)
{ WORD wlen;
LPSTR abuf;
if (len && (! wbuf) )
{ SetLastError(ERROR_INSUFFICIENT_BUFFER);
return 0;
}
abuf = (LPSTR)HeapAlloc(GetProcessHeap(),0,len);
wlen = GetLocaleInfoA(lcid, LCType, abuf, len);
if (wlen && len) /* if len=0 return only the length*/
MultiByteToWideChar( CP_ACP, 0, abuf, -1, wbuf, len );
HeapFree(GetProcessHeap(),0,abuf);
return wlen;
}
/******************************************************************************
*
* GetLocaleSubkeyName [helper function]
*
* - For use with the registry.
* - Gets the registry subkey name for a given lctype.
*/
static char *GetLocaleSubkeyName( DWORD lctype )
{
char *pacKey=NULL;
switch ( lctype )
{
/* These values are used by SetLocaleInfo and GetLocaleInfo, and
* the values are stored in the registry, confirmed under Windows,
* for the ones that actually assign pacKey. Cases that aren't finished
* have not been confirmed, so that must be done before they can be
* added.
*/
case LOCALE_SDATE : /* The date separator. */
pacKey = "sDate";
break;
case LOCALE_ICURRDIGITS:
pacKey = "iCurrDigits";
break;
case LOCALE_SDECIMAL :
pacKey = "sDecimal";
break;
case LOCALE_ICURRENCY:
pacKey = "iCurrency";
break;
case LOCALE_SGROUPING :
pacKey = "sGrouping";
break;
case LOCALE_IDIGITS:
pacKey = "iDigits";
break;
case LOCALE_SLIST :
pacKey = "sList";
break;
/* case LOCALE_ICALENDARTYPE: */
/* case LOCALE_IFIRSTDAYOFWEEK: */
/* case LOCALE_IFIRSTWEEKOFYEAR: */
/* case LOCALE_SYEARMONTH : */
/* case LOCALE_SPOSITIVESIGN : */
/* case LOCALE_IPAPERSIZE: */
/* break; */
case LOCALE_SLONGDATE :
pacKey = "sLongDate";
break;
case LOCALE_SMONDECIMALSEP :
pacKey = "sMonDecimalSep";
break;
case LOCALE_SMONGROUPING:
pacKey = "sMonGrouping";
break;
case LOCALE_IMEASURE:
pacKey = "iMeasure";
break;
case LOCALE_SMONTHOUSANDSEP :
pacKey = "sMonThousandSep";
break;
case LOCALE_INEGCURR:
pacKey = "iNegCurr";
break;
case LOCALE_SNEGATIVESIGN :
pacKey = "sNegativeSign";
break;
case LOCALE_INEGNUMBER:
pacKey = "iNegNumber";
break;
case LOCALE_SSHORTDATE :
pacKey = "sShortDate";
break;
case LOCALE_ILDATE: /* Long Date format ordering specifier. */
pacKey = "iLDate";
break;
case LOCALE_ILZERO:
pacKey = "iLZero";
break;
case LOCALE_ITLZERO:
pacKey = "iTLZero";
break;
case LOCALE_ITIME: /* Time format specifier. */
pacKey = "iTime";
break;
case LOCALE_STHOUSAND :
pacKey = "sThousand";
break;
case LOCALE_S1159: /* AM */
pacKey = "s1159";
break;
case LOCALE_STIME:
pacKey = "sTime";
break;
case LOCALE_S2359: /* PM */
pacKey = "s2359";
break;
case LOCALE_STIMEFORMAT :
pacKey = "sTimeFormat";
break;
case LOCALE_SCURRENCY:
pacKey = "sCurrency";
break;
/* The following are not listed under MSDN as supported,
* but seem to be used and also stored in the registry.
*/
case LOCALE_IDATE:
pacKey = "iDate";
break;
case LOCALE_SCOUNTRY:
pacKey = "sCountry";
break;
case LOCALE_ICOUNTRY:
pacKey = "iCountry";
break;
case LOCALE_SLANGUAGE:
pacKey = "sLanguage";
break;
default:
break;
}
return( pacKey );
}
/******************************************************************************
* SetLocaleInfoA [KERNEL32.@]
*/
BOOL WINAPI SetLocaleInfoA(LCID lcid, LCTYPE lctype, LPCSTR data)
{
HKEY hKey;
char *pacKey;
char acRealKey[128];
if ( (pacKey = GetLocaleSubkeyName(lctype)) )
{
sprintf( acRealKey, "Control Panel\\International\\%s", pacKey );
if ( RegCreateKeyA( HKEY_CURRENT_USER, acRealKey,
&hKey ) == ERROR_SUCCESS )
{
if ( RegSetValueExA( hKey, NULL, 0, REG_SZ,
data, strlen(data)+1 ) != ERROR_SUCCESS )
{
ERR("SetLocaleInfoA: %s did not work\n", pacKey );
}
RegCloseKey( hKey );
}
}
else
{
FIXME("(%ld,%ld,%s): stub\n",lcid,lctype,data);
}
return TRUE;
}
/******************************************************************************
* IsValidLocale [KERNEL32.@]
@ -785,7 +78,7 @@ static BOOL CALLBACK EnumResourceLanguagesProcW(HMODULE hModule, LPCWSTR type,
CHAR bufA[20];
WCHAR bufW[20];
LOCALE_ENUMPROCW lpfnLocaleEnum = (LOCALE_ENUMPROCW)lParam;
sprintf(bufA, "%08X", (UINT)LangID);
sprintf(bufA, "%08x", (UINT)LangID);
MultiByteToWideChar(CP_ACP, 0, bufA, -1, bufW, sizeof(bufW)/sizeof(bufW[0]));
return lpfnLocaleEnum(bufW);
}
@ -810,7 +103,7 @@ static BOOL CALLBACK EnumResourceLanguagesProcA(HMODULE hModule, LPCSTR type,
{
CHAR bufA[20];
LOCALE_ENUMPROCA lpfnLocaleEnum = (LOCALE_ENUMPROCA)lParam;
sprintf(bufA, "%08X", (UINT)LangID);
sprintf(bufA, "%08x", (UINT)LangID);
return lpfnLocaleEnum(bufA);
}
@ -1979,6 +1272,58 @@ int WINAPI CompareStringW(LCID lcid, DWORD fdwStyle,
return (l1<l2)? 1 : 3;
}
/***********************************************************************
* lstrcmp (KERNEL32.@)
* lstrcmpA (KERNEL32.@)
*/
INT WINAPI lstrcmpA( LPCSTR str1, LPCSTR str2 )
{
return CompareStringA(LOCALE_SYSTEM_DEFAULT,0,str1,-1,str2,-1) - 2 ;
}
/***********************************************************************
* lstrcmpW (KERNEL32.@)
* FIXME : should call CompareStringW, when it is implemented.
* This implementation is not "word sort", as it should.
*/
INT WINAPI lstrcmpW( LPCWSTR str1, LPCWSTR str2 )
{
TRACE("%s and %s\n",
debugstr_w (str1), debugstr_w (str2));
if (!str1 || !str2) {
SetLastError(ERROR_INVALID_PARAMETER);
return 0;
}
while (*str1 && (*str1 == *str2)) { str1++; str2++; }
return (INT)(*str1 - *str2);
}
/***********************************************************************
* lstrcmpi (KERNEL32.@)
* lstrcmpiA (KERNEL32.@)
*/
INT WINAPI lstrcmpiA( LPCSTR str1, LPCSTR str2 )
{ TRACE("strcmpi %s and %s\n",
debugstr_a (str1), debugstr_a (str2));
return CompareStringA(LOCALE_SYSTEM_DEFAULT,NORM_IGNORECASE,str1,-1,str2,-1)-2;
}
/***********************************************************************
* lstrcmpiW (KERNEL32.@)
*/
INT WINAPI lstrcmpiW( LPCWSTR str1, LPCWSTR str2 )
{
if (!str1 || !str2) {
SetLastError(ERROR_INVALID_PARAMETER);
return 0;
}
return strcmpiW( str1, str2 );
}
/******************************************************************************
* OLE_GetFormatA [Internal]
*

View File

@ -712,45 +712,6 @@ VOID WINAPI VWin32_BoostThreadStatic( DWORD threadId, INT boost )
}
/***********************************************************************
* GetThreadLocale (KERNEL32.@)
*/
LCID WINAPI GetThreadLocale(void)
{
LCID ret = NtCurrentTeb()->CurrentLocale;
if (!ret) NtCurrentTeb()->CurrentLocale = ret = GetUserDefaultLCID();
return ret;
}
/**********************************************************************
* SetThreadLocale [KERNEL32.@] Sets the calling threads current locale.
*
* RETURNS
* Success: TRUE
* Failure: FALSE
*
* FIXME
* check if lcid is a valid cp
*/
BOOL WINAPI SetThreadLocale(
LCID lcid) /* [in] Locale identifier */
{
switch (lcid)
{
case LOCALE_SYSTEM_DEFAULT:
lcid = GetSystemDefaultLCID();
break;
case LOCALE_USER_DEFAULT:
case LOCALE_NEUTRAL:
lcid = GetUserDefaultLCID();
break;
}
NtCurrentTeb()->CurrentLocale = lcid;
return TRUE;
}
/***********************************************************************
* GetCurrentThread [KERNEL32.@] Gets pseudohandle for current thread
*