From e371e682cb2975a684910459e78bdb91c5faf6df Mon Sep 17 00:00:00 2001 From: Jon Griffiths Date: Tue, 12 Dec 2000 00:37:27 +0000 Subject: [PATCH] - Implemented setlocale parsing and LC_TYPE behavior. - Implemented isleadbyte, snprintf. - Added NLS IsValidCodePage prototype, misc CRTDLL fixes. --- dlls/crtdll/Makefile.in | 1 + dlls/crtdll/crtdll.h | 29 ++- dlls/crtdll/crtdll.spec | 10 +- dlls/crtdll/crtdll_main.c | 79 +++++-- dlls/crtdll/locale.c | 447 ++++++++++++++++++++++++++++++++++++++ dlls/crtdll/time.c | 2 +- include/winnls.h | 1 + 7 files changed, 529 insertions(+), 40 deletions(-) create mode 100644 dlls/crtdll/locale.c diff --git a/dlls/crtdll/Makefile.in b/dlls/crtdll/Makefile.in index a8fbe3cb896..10b626b6945 100644 --- a/dlls/crtdll/Makefile.in +++ b/dlls/crtdll/Makefile.in @@ -13,6 +13,7 @@ C_SRCS = \ dir.c \ exit.c \ file.c \ + locale.c \ mbstring.c \ memory.c \ spawn.c \ diff --git a/dlls/crtdll/crtdll.h b/dlls/crtdll/crtdll.h index 867920c1917..30bfc6b69e0 100644 --- a/dlls/crtdll/crtdll.h +++ b/dlls/crtdll/crtdll.h @@ -19,20 +19,20 @@ #define CRTDLL_LC_MONETARY 3 #define CRTDLL_LC_NUMERIC 4 #define CRTDLL_LC_TIME 5 -#define CRTDLL_LC_MIN LC_ALL -#define CRTDLL_LC_MAX LC_TIME +#define CRTDLL_LC_MIN CRTDLL_LC_ALL +#define CRTDLL_LC_MAX CRTDLL_LC_TIME /* ctype defines */ -#define CRTDLL_UPPER 0x1 -#define CRTDLL_LOWER 0x2 -#define CRTDLL_DIGIT 0x4 -#define CRTDLL_SPACE 0x8 -#define CRTDLL_PUNCT 0x10 -#define CRTDLL_CONTROL 0x20 -#define CRTDLL_BLANK 0x40 -#define CRTDLL_HEX 0x80 +#define CRTDLL_UPPER C1_UPPER +#define CRTDLL_LOWER C1_LOWER +#define CRTDLL_DIGIT C1_DIGIT +#define CRTDLL_SPACE C1_SPACE +#define CRTDLL_PUNCT C1_PUNCT +#define CRTDLL_CONTROL C1_CNTRL +#define CRTDLL_BLANK C1_BLANK +#define CRTDLL_HEX C1_XDIGIT #define CRTDLL_LEADBYTE 0x8000 -#define CRTDLL_ALPHA (0x0100|CRTDLL_UPPER|CRTDLL_LOWER) +#define CRTDLL_ALPHA (C1_ALPHA|CRTDLL_UPPER|CRTDLL_LOWER) /* stat() mode bits */ #define _S_IFMT 0170000 @@ -416,6 +416,7 @@ VOID __cdecl CRTDLL__purecall( VOID ); double __cdecl CRTDLL__y0( double x ); double __cdecl CRTDLL__y1( double x ); double __cdecl CRTDLL__yn( INT x, double y ); +double __cdecl CRTDLL__nextafter( double x, double y ); /* CRTDLL_mem.c */ LPVOID __cdecl CRTDLL_new( DWORD size ); @@ -487,4 +488,10 @@ void __CRTDLL__set_errno(ULONG err); LPSTR __CRTDLL__strndup(LPSTR buf, INT size); VOID __CRTDLL__init_io(VOID); +extern WORD CRTDLL_ctype [257]; +extern WORD __CRTDLL_current_ctype[257]; +extern WORD* CRTDLL_pctype_dll; +extern INT CRTDLL__mb_cur_max_dll; +extern LCID __CRTDLL_current_lc_all_lcid; + #endif /* __WINE_CRTDLL_H */ diff --git a/dlls/crtdll/crtdll.spec b/dlls/crtdll/crtdll.spec index 9d78ae8c639..2327d32bbae 100644 --- a/dlls/crtdll/crtdll.spec +++ b/dlls/crtdll/crtdll.spec @@ -38,7 +38,7 @@ debug_channels (crtdll) @ cdecl __isascii(long) CRTDLL___isascii @ cdecl __iscsym(long) CRTDLL___iscsym @ cdecl __iscsymf(long) CRTDLL___iscsymf -@ stub __mb_cur_max_dll +@ extern __mb_cur_max_dll CRTDLL__mb_cur_max_dll @ stub __pxcptinfoptrs @ forward __threadhandle kernel32.GetCurrentThread @ forward __threadid kernel32.GetCurrentThreadId @@ -244,7 +244,7 @@ debug_channels (crtdll) @ cdecl _mkdir(str) CRTDLL__mkdir @ cdecl _mktemp(str) CRTDLL__mktemp @ cdecl _msize(ptr) CRTDLL__msize -@ cdecl _nextafter(double double) nextafter +@ cdecl _nextafter(double double) CRTDLL__nextafter @ cdecl _onexit(ptr) CRTDLL__onexit @ cdecl _open(str long) CRTDLL__open @ cdecl _open_osfhandle(long long) CRTDLL__open_osfhandle @@ -254,7 +254,7 @@ debug_channels (crtdll) @ extern _osver_dll CRTDLL_osver_dll @ extern _osversion_dll CRTDLL_osversion_dll @ stub _pclose -@ stub _pctype_dll +@ extern _pctype_dll CRTDLL_pctype_dll @ stub _pgmptr_dll @ stub _pipe @ stub _popen @@ -275,7 +275,7 @@ debug_channels (crtdll) @ cdecl _setmode(long long) CRTDLL__setmode @ stub _setsystime @ cdecl _sleep(long) CRTDLL__sleep -@ stub _snprintf +@ varargs _snprintf(ptr long ptr) snprintf @ stub _snwprintf @ stub _sopen @ stub _spawnl @@ -406,7 +406,7 @@ debug_channels (crtdll) @ cdecl iscntrl(long) CRTDLL_iscntrl @ cdecl isdigit(long) CRTDLL_isdigit @ cdecl isgraph(long) CRTDLL_isgraph -@ stub isleadbyte +@ cdecl isleadbyte(long) CRTDLL_isleadbyte @ cdecl islower(long) CRTDLL_islower @ cdecl isprint(long) CRTDLL_isprint @ cdecl ispunct(long) CRTDLL_ispunct diff --git a/dlls/crtdll/crtdll_main.c b/dlls/crtdll/crtdll_main.c index 5a01d2d439d..cdf2e886ed0 100644 --- a/dlls/crtdll/crtdll_main.c +++ b/dlls/crtdll/crtdll_main.c @@ -72,6 +72,7 @@ UINT CRTDLL_winminor_dll; /* CRTDLL.330 */ UINT CRTDLL_winver_dll; /* CRTDLL.331 */ INT CRTDLL_doserrno = 0; INT CRTDLL_errno = 0; +INT CRTDLL__mb_cur_max_dll = 1; const INT CRTDLL__sys_nerr = 43; /* ASCII char classification flags - binary compatible */ @@ -103,6 +104,17 @@ WORD CRTDLL_ctype [257] = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }; +/* Internal: Current ctype table for locale */ +WORD __CRTDLL_current_ctype[257]; + +/* pctype is used by macros in the Win32 headers. It must point + * To a table of flags exactly like ctype. To allow locale + * changes to affect ctypes (i.e. isleadbyte), we use a second table + * and update its flags whenever the current locale changes. + */ +WORD* CRTDLL_pctype_dll = __CRTDLL_current_ctype + 1; + + /********************************************************************* * CRTDLL_MainInit (CRTDLL.init) */ @@ -112,6 +124,7 @@ BOOL WINAPI CRTDLL_Init(HINSTANCE hinstDLL,DWORD fdwReason,LPVOID lpvReserved) if (fdwReason == DLL_PROCESS_ATTACH) { __CRTDLL__init_io(); + CRTDLL_setlocale( CRTDLL_LC_ALL, "C" ); CRTDLL_HUGE_dll = HUGE_VAL; } return TRUE; @@ -640,33 +653,30 @@ VOID __cdecl CRTDLL_longjmp(jmp_buf env, int val) } -/********************************************************************* - * setlocale (CRTDLL.453) - */ -LPSTR __cdecl CRTDLL_setlocale(INT category,LPCSTR locale) -{ - LPSTR categorystr; - - switch (category) { - case CRTDLL_LC_ALL: categorystr="LC_ALL";break; - case CRTDLL_LC_COLLATE: categorystr="LC_COLLATE";break; - case CRTDLL_LC_CTYPE: categorystr="LC_CTYPE";break; - case CRTDLL_LC_MONETARY: categorystr="LC_MONETARY";break; - case CRTDLL_LC_NUMERIC: categorystr="LC_NUMERIC";break; - case CRTDLL_LC_TIME: categorystr="LC_TIME";break; - default: categorystr = "UNKNOWN?";break; - } - FIXME("(%s,%s),stub!\n",categorystr,locale); - return "C"; -} - - /********************************************************************* * _isctype (CRTDLL.138) */ -INT __cdecl CRTDLL__isctype(INT c,UINT type) +INT __cdecl CRTDLL__isctype(INT c, UINT type) { - return CRTDLL_ctype[(UINT)c+1] & type; + if (c >= -1 && c <= 255) + return CRTDLL_pctype_dll[c] & type; + + if (CRTDLL__mb_cur_max_dll != 1 && c > 0) + { + /* FIXME: Is there a faster way to do this? */ + WORD typeInfo; + char convert[3], *pconv = convert; + + if (CRTDLL_pctype_dll[(UINT)c >> 8] & CRTDLL_LEADBYTE) + *pconv++ = (UINT)c >> 8; + *pconv++ = c & 0xff; + *pconv = 0; + /* FIXME: Use ctype LCID */ + if (GetStringTypeExA(__CRTDLL_current_lc_all_lcid, CT_CTYPE1, + convert, convert[1] ? 2 : 1, &typeInfo)) + return typeInfo & type; + } + return 0; } @@ -996,6 +1006,15 @@ INT __cdecl CRTDLL_isgraph(INT c) } +/********************************************************************* + * isleadbyte (CRTDLL.447) + */ +INT __cdecl CRTDLL_isleadbyte(unsigned char c) +{ + return CRTDLL__isctype( c, CRTDLL_LEADBYTE ); +} + + /********************************************************************* * islower (CRTDLL.447) */ @@ -1639,3 +1658,17 @@ double __cdecl CRTDLL__yn(INT x, double y) } return retVal; } + + +/********************************************************************* + * _nextafter (CRTDLL.235) + * + */ +double __cdecl CRTDLL__nextafter(double x, double y) +{ + double retVal; + if (!finite(x) || !finite(y)) CRTDLL_errno = EDOM; + retVal = nextafter(x,y); + return retVal; +} + diff --git a/dlls/crtdll/locale.c b/dlls/crtdll/locale.c new file mode 100644 index 00000000000..b99c80ce7ee --- /dev/null +++ b/dlls/crtdll/locale.c @@ -0,0 +1,447 @@ +/* + * CRT Locale functions + * + * Copyright 2000 Jon Griffiths + * + * NOTES: + * Currently only LC_CTYPE behaviour is actually implemented. + * Passing a code page only is not yet supported. + * + * The code maps a (potentially incomplete) locale description to + * an LCID. The algorithm enumerates supported locales and + * compares the locale strings to the locale information given. + * Fully qualified locales should be completely compatable. + * Some countries (e.g. US) have synonyms that can be used in + * setlocale() calls - these are mapped to ISO codes before + * searching begins, but I may have missed some out of the list. + * + * It should be noted that the algorithm may locate a valid + * locale from a 2 letter ISO code, while the real DLL won't + * (it requires 3 letter codes or synonyms at a minimum). + * e.g. setlocale(LC_ALL,"de") will return "German_Germany.1252" + * with this implementation, while this fails in win32. + * + * It should also be noted that this implementation follows + * the MSVCRT behaviour, and not the CRTDLL behaviour. + * This is because MSVCRT provides a superset of the CRTDLL + * allowed locales, so this code can be used for both. Also + * The CRTDLL implementation can be considered broken. + * + * The code currently works for isleadbyte() but will fail + * (produce potentially incorrect values) for other locales + * with isalpha() etc. This is because the current Wine + * implementation of GetStringTypeA() is not locale aware. + * Fixing this requires a table of which characters in the + * code page are upper/lower/digit etc. If you locate such + * a table for a supported Wine locale, mail it to me and + * I will add the needed support (jon_p_griffiths@yahoo.com). + */ +#include "crtdll.h" +#include +#include +#include +#include + +DEFAULT_DEBUG_CHANNEL(crtdll); + +#define MAX_ELEM_LEN 64 /* Max length of country/language/CP string */ +#define MAX_LOCALE_LENGTH 256 + +/* FIXME: Need to hold locale for each LC_* type and aggregate + * string to produce lc_all. + */ +char __CRTDLL_current_lc_all[MAX_LOCALE_LENGTH]; +LCID __CRTDLL_current_lc_all_lcid; + +/* Friendly country strings & iso codes for synonym support. + * Based on MS documentation for setlocale(). + */ +static const char* _country_synonyms[] = +{ + "Hong Kong","HK", + "Hong-Kong","HK", + "New Zealand","NZ", + "New-Zealand","NZ", + "PR China","CN", + "PR-China","CN", + "United Kingdom","GB", + "United-Kingdom","GB", + "Britain","GB", + "England","GB", + "Great Britain","GB", + "United States","US", + "United-States","US", + "America","US" +}; + +/* INTERNAL: Map a synonym to an ISO code */ +static void remap_synonym(char *name) +{ + int i; + for (i = 0; i < sizeof(_country_synonyms)/sizeof(char*); i += 2 ) + { + if (!strcasecmp(_country_synonyms[i],name)) + { + TRACE(":Mapping synonym %s to %s\n",name,_country_synonyms[i+1]); + name[0] = _country_synonyms[i+1][0]; + name[1] = _country_synonyms[i+1][1]; + name[2] = '\0'; + return; + } + } +} + +/* Note: Flags are weighted in order of matching importance */ +#define FOUND_LANGUAGE 0x4 +#define FOUND_COUNTRY 0x2 +#define FOUND_CODEPAGE 0x1 + +typedef struct { + char search_language[MAX_ELEM_LEN]; + char search_country[MAX_ELEM_LEN]; + char search_codepage[MAX_ELEM_LEN]; + char found_language[MAX_ELEM_LEN]; + char found_country[MAX_ELEM_LEN]; + char found_codepage[MAX_ELEM_LEN]; + unsigned int match_flags; + LANGID found_lang_id; +} locale_search_t; + +#define CONTINUE_LOOKING TRUE +#define STOP_LOOKING FALSE + +/* INTERNAL: Get and compare locale info with a given string */ +static int compare_info(LCID lcid, DWORD flags, char* buff, const char* cmp) +{ + buff[0] = 0; + GetLocaleInfoA(lcid, flags|LOCALE_NOUSEROVERRIDE,buff, MAX_ELEM_LEN); + if (!buff[0] || !cmp[0]) + return 0; + /* Partial matches are allowed, e.g. "Germ" matches "Germany" */ + return !strncasecmp(cmp, buff, strlen(cmp)); +} + + +/* INTERNAL: Callback for enumerated languages */ +static BOOL CALLBACK +find_best_locale_proc(HMODULE hModule, LPCSTR type, + LPCSTR name, WORD LangID, LONG lParam) +{ + locale_search_t *res = (locale_search_t *)lParam; + const LCID lcid = MAKELCID(LangID, SORT_DEFAULT); + char buff[MAX_ELEM_LEN]; + unsigned int flags = 0; + + if(PRIMARYLANGID(LangID) == LANG_NEUTRAL) + return CONTINUE_LOOKING; + + /* Check Language */ + if (compare_info(lcid,LOCALE_SISO639LANGNAME,buff,res->search_language) || + compare_info(lcid,LOCALE_SABBREVLANGNAME,buff,res->search_language) || + compare_info(lcid,LOCALE_SENGLANGUAGE,buff,res->search_language)) + { + TRACE(":Found language: %s->%s\n", res->search_language, buff); + flags |= FOUND_LANGUAGE; + memcpy(res->found_language,res->search_language,MAX_ELEM_LEN); + } + else if (res->match_flags & FOUND_LANGUAGE) + { + return CONTINUE_LOOKING; + } + + /* Check Country */ + if (compare_info(lcid,LOCALE_SISO3166CTRYNAME,buff,res->search_country) || + compare_info(lcid,LOCALE_SABBREVCTRYNAME,buff,res->search_country) || + compare_info(lcid,LOCALE_SENGCOUNTRY,buff,res->search_country)) + { + TRACE("Found country:%s->%s\n", res->search_country, buff); + flags |= FOUND_COUNTRY; + memcpy(res->found_country,res->search_country,MAX_ELEM_LEN); + } + else if (res->match_flags & FOUND_COUNTRY) + { + return CONTINUE_LOOKING; + } + + /* Check codepage */ + if (compare_info(lcid,LOCALE_IDEFAULTCODEPAGE,buff,res->search_codepage) || + (compare_info(lcid,LOCALE_IDEFAULTANSICODEPAGE,buff,res->search_codepage))) + { + TRACE("Found codepage:%s->%s\n", res->search_codepage, buff); + flags |= FOUND_CODEPAGE; + memcpy(res->found_codepage,res->search_codepage,MAX_ELEM_LEN); + } + else if (res->match_flags & FOUND_CODEPAGE) + { + return CONTINUE_LOOKING; + } + + if (flags > res->match_flags) + { + /* Found a better match than previously */ + res->match_flags = flags; + res->found_lang_id = LangID; + } + if (flags & (FOUND_LANGUAGE & FOUND_COUNTRY & FOUND_CODEPAGE)) + { + TRACE(":found exact locale match\n"); + return STOP_LOOKING; + } + return CONTINUE_LOOKING; +} + +/* Internal: Find the LCID for a locale specification */ +static LCID __CRTDLL_locale_to_LCID(locale_search_t* locale) +{ + LCID lcid; + EnumResourceLanguagesA(GetModuleHandleA("KERNEL32"), RT_STRINGA, + (LPCSTR)LOCALE_ILANGUAGE,find_best_locale_proc, + (LONG)locale); + + if (!locale->match_flags) + return 0; + + /* If we were given something that didn't match, fail */ + if (locale->search_country[0] && !(locale->match_flags & FOUND_COUNTRY)) + return 0; + + lcid = MAKELCID(locale->found_lang_id, SORT_DEFAULT); + + /* Populate partial locale, translating LCID to locale string elements */ + if (!locale->found_codepage[0]) + { + /* Even if a codepage is not enumerated for a locale + * it can be set if valid */ + if (locale->search_codepage[0]) + { + if (IsValidCodePage(atoi(locale->search_codepage))) + memcpy(locale->found_codepage,locale->search_codepage,MAX_ELEM_LEN); + else + { + /* Special codepage values: OEM & ANSI */ + if (strcasecmp(locale->search_codepage,"OCP")) + { + GetLocaleInfoA(lcid, LOCALE_IDEFAULTCODEPAGE, + locale->found_codepage, MAX_ELEM_LEN); + } + if (strcasecmp(locale->search_codepage,"ACP")) + { + GetLocaleInfoA(lcid, LOCALE_IDEFAULTANSICODEPAGE, + locale->found_codepage, MAX_ELEM_LEN); + } + else + return 0; + + if (!atoi(locale->found_codepage)) + return 0; + } + } + else + { + /* Prefer ANSI codepages if present */ + GetLocaleInfoA(lcid, LOCALE_IDEFAULTANSICODEPAGE, + locale->found_codepage, MAX_ELEM_LEN); + if (!locale->found_codepage[0] || !atoi(locale->found_codepage)) + GetLocaleInfoA(lcid, LOCALE_IDEFAULTCODEPAGE, + locale->found_codepage, MAX_ELEM_LEN); + } + } + GetLocaleInfoA(lcid, LOCALE_SENGLANGUAGE|LOCALE_NOUSEROVERRIDE, + locale->found_language, MAX_ELEM_LEN); + GetLocaleInfoA(lcid, LOCALE_SENGCOUNTRY|LOCALE_NOUSEROVERRIDE, + locale->found_country, MAX_ELEM_LEN); + return lcid; +} + + +/* INTERNAL: Set ctype behaviour for a codepage */ +static void __CRTDLL_set_ctype(UINT codepage, LCID lcid) +{ + CPINFO cp; + + memset(&cp, 0, sizeof(CPINFO)); + + if (GetCPInfo(codepage, &cp)) + { + int i; + char str[3]; + unsigned char *traverse = (unsigned char *)cp.LeadByte; + + memset(__CRTDLL_current_ctype, 0, sizeof(CRTDLL_ctype)); + + /* Switch ctype macros to MBCS if needed */ + CRTDLL__mb_cur_max_dll = cp.MaxCharSize; + + /* Set remaining ctype flags: FIXME: faster way to do this? */ + str[1] = str[2] = 0; + for (i = 0; i < 256; i++) + { + if (!(CRTDLL_pctype_dll[i] & CRTDLL_LEADBYTE)) + { + str[0] = i; + GetStringTypeA(lcid, CT_CTYPE1, str, 1, CRTDLL_pctype_dll + i); + } + } + + /* Set leadbyte flags */ + while (traverse[0] || traverse[1]) + { + for( i = traverse[0]; i <= traverse[1]; i++ ) + __CRTDLL_current_ctype[i+1] |= CRTDLL_LEADBYTE; + traverse += 2; + }; + } +} + + +/********************************************************************* + * setlocale (CRTDLL.453) + */ +LPSTR __cdecl CRTDLL_setlocale(INT category, LPCSTR locale) +{ + LCID lcid = 0; + locale_search_t lc; + int haveLang, haveCountry, haveCP; + char* next; + int lc_all = 0; + + if (category < CRTDLL_LC_MIN || category > CRTDLL_LC_MAX) + return NULL; + + if (locale == NULL) + { + /* Report the current Locale */ + return __CRTDLL_current_lc_all; + } + + if (locale[0] == 'L' && locale[1] == 'C' && locale[2] == '_') + { + FIXME(":restore previous locale not implemented!\n"); + /* FIXME: Easiest way to do this is parse the string and + * call this function recursively with its elements, + * Where they differ for each lc_ type. + */ + return __CRTDLL_current_lc_all; + } + + /* Default Locale: Special case handling */ + if (!strlen(locale) || ((toupper(locale[0]) == 'C') && !locale[1])) + { + if ((toupper(__CRTDLL_current_lc_all[0]) != 'C') + || __CRTDLL_current_lc_all[1]) + { + __CRTDLL_current_lc_all[0] = 'C'; + __CRTDLL_current_lc_all[1] = 0; + switch (category) { + case CRTDLL_LC_ALL: + lc_all = 1; /* Fall through all cases ... */ + case CRTDLL_LC_COLLATE: + if (!lc_all) break; + case CRTDLL_LC_CTYPE: + /* Restore C locale ctype info */ + CRTDLL__mb_cur_max_dll = 1; + memcpy(__CRTDLL_current_ctype, CRTDLL_ctype, sizeof(CRTDLL_ctype)); + if (!lc_all) break; + case CRTDLL_LC_MONETARY: + if (!lc_all) break; + case CRTDLL_LC_NUMERIC: + if (!lc_all) break; + case CRTDLL_LC_TIME: + } + return __CRTDLL_current_lc_all; + } + } + + /* Get locale elements */ + haveLang = haveCountry = haveCP = 0; + memset(&lc,0,sizeof(lc)); + + next = strchr(locale,'_'); + if (next && next != locale) + { + haveLang = 1; + strncpy(lc.search_language,locale,next-locale); + locale += next-locale+1; + } + + next = strchr(locale,'.'); + if (next) + { + haveCP = 1; + if (next == locale) + { + locale++; + strncpy(lc.search_codepage, locale, MAX_ELEM_LEN); + } + else + { + if (haveLang) + { + haveCountry = 1; + strncpy(lc.search_country,locale,next-locale); + locale += next-locale+1; + } + else + { + haveLang = 1; + strncpy(lc.search_language,locale,next-locale); + locale += next-locale+1; + } + strncpy(lc.search_codepage, locale, MAX_ELEM_LEN); + } + } + else + { + if (haveLang) + { + haveCountry = 1; + strncpy(lc.search_country, locale, MAX_ELEM_LEN); + } + else + { + haveLang = 1; + strncpy(lc.search_language, locale, MAX_ELEM_LEN); + } + } + + if (haveCountry) + remap_synonym(lc.search_country); + + if (haveCP && !haveCountry && !haveLang) + { + FIXME(":Codepage only locale not implemented"); + /* FIXME: Use default lang/country and skip locale_to_LCID() + * call below... + */ + return NULL; + } + + lcid = __CRTDLL_locale_to_LCID(&lc); + + TRACE(":found LCID %ld\n",lcid); + + if (lcid == 0) + return NULL; + + __CRTDLL_current_lc_all_lcid = lcid; + + snprintf(__CRTDLL_current_lc_all,MAX_LOCALE_LENGTH,"%s_%s.%s", + lc.found_language,lc.found_country,lc.found_codepage); + + switch (category) { + case CRTDLL_LC_ALL: + lc_all = 1; /* Fall through all cases ... */ + case CRTDLL_LC_COLLATE: + if (!lc_all) break; + case CRTDLL_LC_CTYPE: + __CRTDLL_set_ctype(atoi(lc.found_codepage),lcid); + if (!lc_all) break; + break; + case CRTDLL_LC_MONETARY: + if (!lc_all) break; + case CRTDLL_LC_NUMERIC: + if (!lc_all) break; + case CRTDLL_LC_TIME: + } + return __CRTDLL_current_lc_all; +} diff --git a/dlls/crtdll/time.c b/dlls/crtdll/time.c index 4e6744ba6c0..1d72ebac2d5 100644 --- a/dlls/crtdll/time.c +++ b/dlls/crtdll/time.c @@ -84,7 +84,7 @@ clock_t __cdecl CRTDLL_clock(void) times(&alltimes); res = alltimes.tms_utime + alltimes.tms_stime+ alltimes.tms_cutime + alltimes.tms_cstime; - /* Fixme: We need some symbolic representation + /* FIXME: We need some symbolic representation for (Hostsystem_)CLOCKS_PER_SEC and (Emulated_system_)CLOCKS_PER_SEC 10 holds only for Windows/Linux_i86) diff --git a/include/winnls.h b/include/winnls.h index b4307c7b607..1ffdd3c3dd1 100644 --- a/include/winnls.h +++ b/include/winnls.h @@ -344,6 +344,7 @@ BOOL WINAPI EnumCalendarInfoW(CALINFO_ENUMPROCW lpCalInfoEnumProc,LCID Locale,CA LCID WINAPI ConvertDefaultLocale(LCID Locale); +BOOL WINAPI IsValidCodePage(UINT); BOOL WINAPI GetCPInfo(UINT,LPCPINFO); BOOL WINAPI GetCPInfoExA(UINT,DWORD,LPCPINFOEXA); BOOL WINAPI GetCPInfoExW(UINT,DWORD,LPCPINFOEXW);