- Implemented setlocale parsing and LC_TYPE behavior.
- Implemented isleadbyte, snprintf.
- Added NLS IsValidCodePage prototype, misc CRTDLL fixes.
diff --git a/dlls/crtdll/Makefile.in b/dlls/crtdll/Makefile.in
index a8fbe3c..10b626b 100644
--- a/dlls/crtdll/Makefile.in
+++ b/dlls/crtdll/Makefile.in
@@ -13,6 +13,7 @@
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 867920c..30bfc6b 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 @@
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 @@
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 9d78ae8..2327d32 100644
--- a/dlls/crtdll/crtdll.spec
+++ b/dlls/crtdll/crtdll.spec
@@ -38,7 +38,7 @@
@ 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 @@
@ 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 @@
@ 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 @@
@ 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 @@
@ 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 5a01d2d..cdf2e88 100644
--- a/dlls/crtdll/crtdll_main.c
+++ b/dlls/crtdll/crtdll_main.c
@@ -72,6 +72,7 @@
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 @@
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 @@
if (fdwReason == DLL_PROCESS_ATTACH) {
__CRTDLL__init_io();
+ CRTDLL_setlocale( CRTDLL_LC_ALL, "C" );
CRTDLL_HUGE_dll = HUGE_VAL;
}
return TRUE;
@@ -641,32 +654,29 @@
/*********************************************************************
- * 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;
}
@@ -997,6 +1007,15 @@
/*********************************************************************
+ * isleadbyte (CRTDLL.447)
+ */
+INT __cdecl CRTDLL_isleadbyte(unsigned char c)
+{
+ return CRTDLL__isctype( c, CRTDLL_LEADBYTE );
+}
+
+
+/*********************************************************************
* islower (CRTDLL.447)
*/
INT __cdecl CRTDLL_islower(INT c)
@@ -1639,3 +1658,17 @@
}
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 0000000..b99c80c
--- /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 <winnt.h>
+#include <string.h>
+#include <stdlib.h>
+#include <stdio.h>
+
+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 4e6744b..1d72eba 100644
--- a/dlls/crtdll/time.c
+++ b/dlls/crtdll/time.c
@@ -84,7 +84,7 @@
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 b4307c7..1ffdd3c 100644
--- a/include/winnls.h
+++ b/include/winnls.h
@@ -344,6 +344,7 @@
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);