1*c2c66affSColin Finck /* 2*c2c66affSColin Finck * msvcrt.dll locale functions 3*c2c66affSColin Finck * 4*c2c66affSColin Finck * Copyright 2000 Jon Griffiths 5*c2c66affSColin Finck * 6*c2c66affSColin Finck * This library is free software; you can redistribute it and/or 7*c2c66affSColin Finck * modify it under the terms of the GNU Lesser General Public 8*c2c66affSColin Finck * License as published by the Free Software Foundation; either 9*c2c66affSColin Finck * version 2.1 of the License, or (at your option) any later version. 10*c2c66affSColin Finck * 11*c2c66affSColin Finck * This library is distributed in the hope that it will be useful, 12*c2c66affSColin Finck * but WITHOUT ANY WARRANTY; without even the implied warranty of 13*c2c66affSColin Finck * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 14*c2c66affSColin Finck * Lesser General Public License for more details. 15*c2c66affSColin Finck * 16*c2c66affSColin Finck * You should have received a copy of the GNU Lesser General Public 17*c2c66affSColin Finck * License along with this library; if not, write to the Free Software 18*c2c66affSColin Finck * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA 19*c2c66affSColin Finck */ 20*c2c66affSColin Finck 21*c2c66affSColin Finck #include <precomp.h> 22*c2c66affSColin Finck #include <locale.h> 23*c2c66affSColin Finck 24*c2c66affSColin Finck #include "mbctype.h" 25*c2c66affSColin Finck #include <internal/wine/msvcrt.h> 26*c2c66affSColin Finck 27*c2c66affSColin Finck #define MAX_ELEM_LEN 64 /* Max length of country/language/CP string */ 28*c2c66affSColin Finck #define MAX_LOCALE_LENGTH 256 29*c2c66affSColin Finck 30*c2c66affSColin Finck #ifdef _pctype 31*c2c66affSColin Finck #error _pctype should not be defined 32*c2c66affSColin Finck #endif 33*c2c66affSColin Finck 34*c2c66affSColin Finck unsigned int __lc_codepage = 0; 35*c2c66affSColin Finck int MSVCRT___lc_collate_cp = 0; 36*c2c66affSColin Finck LCID MSVCRT___lc_handle[LC_MAX - LC_MIN + 1] = { 0 }; 37*c2c66affSColin Finck int __mb_cur_max = 1; 38*c2c66affSColin Finck static unsigned char charmax = CHAR_MAX; 39*c2c66affSColin Finck 40*c2c66affSColin Finck unsigned char _mbctype[257] = { 0 }; 41*c2c66affSColin Finck 42*c2c66affSColin Finck /* MT */ 43*c2c66affSColin Finck #define LOCK_LOCALE _mlock(_SETLOCALE_LOCK); 44*c2c66affSColin Finck #define UNLOCK_LOCALE _munlock(_SETLOCALE_LOCK); 45*c2c66affSColin Finck 46*c2c66affSColin Finck #define MSVCRT_LEADBYTE 0x8000 47*c2c66affSColin Finck #define MSVCRT_C1_DEFINED 0x200 48*c2c66affSColin Finck 49*c2c66affSColin Finck /* Friendly country strings & language names abbreviations. */ 50*c2c66affSColin Finck static const char * const _country_synonyms[] = 51*c2c66affSColin Finck { 52*c2c66affSColin Finck "american", "enu", 53*c2c66affSColin Finck "american english", "enu", 54*c2c66affSColin Finck "american-english", "enu", 55*c2c66affSColin Finck "english-american", "enu", 56*c2c66affSColin Finck "english-us", "enu", 57*c2c66affSColin Finck "english-usa", "enu", 58*c2c66affSColin Finck "us", "enu", 59*c2c66affSColin Finck "usa", "enu", 60*c2c66affSColin Finck "australian", "ena", 61*c2c66affSColin Finck "english-aus", "ena", 62*c2c66affSColin Finck "belgian", "nlb", 63*c2c66affSColin Finck "french-belgian", "frb", 64*c2c66affSColin Finck "canadian", "enc", 65*c2c66affSColin Finck "english-can", "enc", 66*c2c66affSColin Finck "french-canadian", "frc", 67*c2c66affSColin Finck "chinese", "chs", 68*c2c66affSColin Finck "chinese-simplified", "chs", 69*c2c66affSColin Finck "chinese-traditional", "cht", 70*c2c66affSColin Finck "dutch-belgian", "nlb", 71*c2c66affSColin Finck "english-nz", "enz", 72*c2c66affSColin Finck "uk", "eng", 73*c2c66affSColin Finck "english-uk", "eng", 74*c2c66affSColin Finck "french-swiss", "frs", 75*c2c66affSColin Finck "swiss", "des", 76*c2c66affSColin Finck "german-swiss", "des", 77*c2c66affSColin Finck "italian-swiss", "its", 78*c2c66affSColin Finck "german-austrian", "dea", 79*c2c66affSColin Finck "portuguese", "ptb", 80*c2c66affSColin Finck "portuguese-brazil", "ptb", 81*c2c66affSColin Finck "spanish-mexican", "esm", 82*c2c66affSColin Finck "norwegian-bokmal", "nor", 83*c2c66affSColin Finck "norwegian-nynorsk", "non", 84*c2c66affSColin Finck "spanish-modern", "esn" 85*c2c66affSColin Finck }; 86*c2c66affSColin Finck 87*c2c66affSColin Finck /* INTERNAL: Map a synonym to an ISO code */ 88*c2c66affSColin Finck static void remap_synonym(char *name) 89*c2c66affSColin Finck { 90*c2c66affSColin Finck unsigned int i; 91*c2c66affSColin Finck for (i = 0; i < sizeof(_country_synonyms)/sizeof(char*); i += 2 ) 92*c2c66affSColin Finck { 93*c2c66affSColin Finck if (!strcasecmp(_country_synonyms[i],name)) 94*c2c66affSColin Finck { 95*c2c66affSColin Finck TRACE(":Mapping synonym %s to %s\n",name,_country_synonyms[i+1]); 96*c2c66affSColin Finck strcpy(name, _country_synonyms[i+1]); 97*c2c66affSColin Finck return; 98*c2c66affSColin Finck } 99*c2c66affSColin Finck } 100*c2c66affSColin Finck } 101*c2c66affSColin Finck 102*c2c66affSColin Finck /* Note: Flags are weighted in order of matching importance */ 103*c2c66affSColin Finck #define FOUND_LANGUAGE 0x4 104*c2c66affSColin Finck #define FOUND_COUNTRY 0x2 105*c2c66affSColin Finck #define FOUND_CODEPAGE 0x1 106*c2c66affSColin Finck 107*c2c66affSColin Finck typedef struct { 108*c2c66affSColin Finck char search_language[MAX_ELEM_LEN]; 109*c2c66affSColin Finck char search_country[MAX_ELEM_LEN]; 110*c2c66affSColin Finck char search_codepage[MAX_ELEM_LEN]; 111*c2c66affSColin Finck char found_codepage[MAX_ELEM_LEN]; 112*c2c66affSColin Finck unsigned int match_flags; 113*c2c66affSColin Finck LANGID found_lang_id; 114*c2c66affSColin Finck } locale_search_t; 115*c2c66affSColin Finck 116*c2c66affSColin Finck #define CONTINUE_LOOKING TRUE 117*c2c66affSColin Finck #define STOP_LOOKING FALSE 118*c2c66affSColin Finck 119*c2c66affSColin Finck /* INTERNAL: Get and compare locale info with a given string */ 120*c2c66affSColin Finck static int compare_info(LCID lcid, DWORD flags, char* buff, const char* cmp, BOOL exact) 121*c2c66affSColin Finck { 122*c2c66affSColin Finck int len; 123*c2c66affSColin Finck 124*c2c66affSColin Finck if(!cmp[0]) 125*c2c66affSColin Finck return 0; 126*c2c66affSColin Finck 127*c2c66affSColin Finck buff[0] = 0; 128*c2c66affSColin Finck GetLocaleInfoA(lcid, flags|LOCALE_NOUSEROVERRIDE, buff, MAX_ELEM_LEN); 129*c2c66affSColin Finck if (!buff[0]) 130*c2c66affSColin Finck return 0; 131*c2c66affSColin Finck 132*c2c66affSColin Finck /* Partial matches are only allowed on language/country names */ 133*c2c66affSColin Finck len = strlen(cmp); 134*c2c66affSColin Finck if(exact || len<=3) 135*c2c66affSColin Finck return !strcasecmp(cmp, buff); 136*c2c66affSColin Finck else 137*c2c66affSColin Finck return !strncasecmp(cmp, buff, len); 138*c2c66affSColin Finck } 139*c2c66affSColin Finck 140*c2c66affSColin Finck static BOOL CALLBACK 141*c2c66affSColin Finck find_best_locale_proc(HMODULE hModule, LPCSTR type, LPCSTR name, WORD LangID, LONG_PTR lParam) 142*c2c66affSColin Finck { 143*c2c66affSColin Finck locale_search_t *res = (locale_search_t *)lParam; 144*c2c66affSColin Finck const LCID lcid = MAKELCID(LangID, SORT_DEFAULT); 145*c2c66affSColin Finck char buff[MAX_ELEM_LEN]; 146*c2c66affSColin Finck unsigned int flags = 0; 147*c2c66affSColin Finck 148*c2c66affSColin Finck if(PRIMARYLANGID(LangID) == LANG_NEUTRAL) 149*c2c66affSColin Finck return CONTINUE_LOOKING; 150*c2c66affSColin Finck 151*c2c66affSColin Finck /* Check Language */ 152*c2c66affSColin Finck if (compare_info(lcid,LOCALE_SISO639LANGNAME,buff,res->search_language, TRUE) || 153*c2c66affSColin Finck compare_info(lcid,LOCALE_SABBREVLANGNAME,buff,res->search_language, TRUE) || 154*c2c66affSColin Finck compare_info(lcid,LOCALE_SENGLANGUAGE,buff,res->search_language, FALSE)) 155*c2c66affSColin Finck { 156*c2c66affSColin Finck TRACE(":Found language: %s->%s\n", res->search_language, buff); 157*c2c66affSColin Finck flags |= FOUND_LANGUAGE; 158*c2c66affSColin Finck } 159*c2c66affSColin Finck else if (res->match_flags & FOUND_LANGUAGE) 160*c2c66affSColin Finck { 161*c2c66affSColin Finck return CONTINUE_LOOKING; 162*c2c66affSColin Finck } 163*c2c66affSColin Finck 164*c2c66affSColin Finck /* Check Country */ 165*c2c66affSColin Finck if (compare_info(lcid,LOCALE_SISO3166CTRYNAME,buff,res->search_country, TRUE) || 166*c2c66affSColin Finck compare_info(lcid,LOCALE_SABBREVCTRYNAME,buff,res->search_country, TRUE) || 167*c2c66affSColin Finck compare_info(lcid,LOCALE_SENGCOUNTRY,buff,res->search_country, FALSE)) 168*c2c66affSColin Finck { 169*c2c66affSColin Finck TRACE("Found country:%s->%s\n", res->search_country, buff); 170*c2c66affSColin Finck flags |= FOUND_COUNTRY; 171*c2c66affSColin Finck } 172*c2c66affSColin Finck else if (!flags && (res->match_flags & FOUND_COUNTRY)) 173*c2c66affSColin Finck { 174*c2c66affSColin Finck return CONTINUE_LOOKING; 175*c2c66affSColin Finck } 176*c2c66affSColin Finck 177*c2c66affSColin Finck /* Check codepage */ 178*c2c66affSColin Finck if (compare_info(lcid,LOCALE_IDEFAULTCODEPAGE,buff,res->search_codepage, TRUE) || 179*c2c66affSColin Finck (compare_info(lcid,LOCALE_IDEFAULTANSICODEPAGE,buff,res->search_codepage, TRUE))) 180*c2c66affSColin Finck { 181*c2c66affSColin Finck TRACE("Found codepage:%s->%s\n", res->search_codepage, buff); 182*c2c66affSColin Finck flags |= FOUND_CODEPAGE; 183*c2c66affSColin Finck memcpy(res->found_codepage,res->search_codepage,MAX_ELEM_LEN); 184*c2c66affSColin Finck } 185*c2c66affSColin Finck else if (!flags && (res->match_flags & FOUND_CODEPAGE)) 186*c2c66affSColin Finck { 187*c2c66affSColin Finck return CONTINUE_LOOKING; 188*c2c66affSColin Finck } 189*c2c66affSColin Finck 190*c2c66affSColin Finck if (flags > res->match_flags) 191*c2c66affSColin Finck { 192*c2c66affSColin Finck /* Found a better match than previously */ 193*c2c66affSColin Finck res->match_flags = flags; 194*c2c66affSColin Finck res->found_lang_id = LangID; 195*c2c66affSColin Finck } 196*c2c66affSColin Finck if ((flags & (FOUND_LANGUAGE | FOUND_COUNTRY | FOUND_CODEPAGE)) == 197*c2c66affSColin Finck (FOUND_LANGUAGE | FOUND_COUNTRY | FOUND_CODEPAGE)) 198*c2c66affSColin Finck { 199*c2c66affSColin Finck TRACE(":found exact locale match\n"); 200*c2c66affSColin Finck return STOP_LOOKING; 201*c2c66affSColin Finck } 202*c2c66affSColin Finck return CONTINUE_LOOKING; 203*c2c66affSColin Finck } 204*c2c66affSColin Finck 205*c2c66affSColin Finck extern int atoi(const char *); 206*c2c66affSColin Finck 207*c2c66affSColin Finck /* Internal: Find the LCID for a locale specification */ 208*c2c66affSColin Finck LCID MSVCRT_locale_to_LCID(const char *locale, unsigned short *codepage) 209*c2c66affSColin Finck { 210*c2c66affSColin Finck LCID lcid; 211*c2c66affSColin Finck locale_search_t search; 212*c2c66affSColin Finck const char *cp, *region; 213*c2c66affSColin Finck 214*c2c66affSColin Finck memset(&search, 0, sizeof(locale_search_t)); 215*c2c66affSColin Finck 216*c2c66affSColin Finck cp = strchr(locale, '.'); 217*c2c66affSColin Finck region = strchr(locale, '_'); 218*c2c66affSColin Finck 219*c2c66affSColin Finck lstrcpynA(search.search_language, locale, MAX_ELEM_LEN); 220*c2c66affSColin Finck if(region) { 221*c2c66affSColin Finck lstrcpynA(search.search_country, region+1, MAX_ELEM_LEN); 222*c2c66affSColin Finck if(region-locale < MAX_ELEM_LEN) 223*c2c66affSColin Finck search.search_language[region-locale] = '\0'; 224*c2c66affSColin Finck } else 225*c2c66affSColin Finck search.search_country[0] = '\0'; 226*c2c66affSColin Finck 227*c2c66affSColin Finck if(cp) { 228*c2c66affSColin Finck lstrcpynA(search.search_codepage, cp+1, MAX_ELEM_LEN); 229*c2c66affSColin Finck if(region && cp-region-1<MAX_ELEM_LEN) 230*c2c66affSColin Finck search.search_country[cp-region-1] = '\0'; 231*c2c66affSColin Finck if(cp-locale < MAX_ELEM_LEN) 232*c2c66affSColin Finck search.search_language[cp-locale] = '\0'; 233*c2c66affSColin Finck } else 234*c2c66affSColin Finck search.search_codepage[0] = '\0'; 235*c2c66affSColin Finck 236*c2c66affSColin Finck if(!search.search_country[0] && !search.search_codepage[0]) 237*c2c66affSColin Finck remap_synonym(search.search_language); 238*c2c66affSColin Finck 239*c2c66affSColin Finck EnumResourceLanguagesA(GetModuleHandleA("KERNEL32"), (LPSTR)RT_STRING, 240*c2c66affSColin Finck (LPCSTR)LOCALE_ILANGUAGE,find_best_locale_proc, 241*c2c66affSColin Finck (LONG_PTR)&search); 242*c2c66affSColin Finck 243*c2c66affSColin Finck if (!search.match_flags) 244*c2c66affSColin Finck return -1; 245*c2c66affSColin Finck 246*c2c66affSColin Finck /* If we were given something that didn't match, fail */ 247*c2c66affSColin Finck if (search.search_country[0] && !(search.match_flags & FOUND_COUNTRY)) 248*c2c66affSColin Finck return -1; 249*c2c66affSColin Finck 250*c2c66affSColin Finck lcid = MAKELCID(search.found_lang_id, SORT_DEFAULT); 251*c2c66affSColin Finck 252*c2c66affSColin Finck /* Populate partial locale, translating LCID to locale string elements */ 253*c2c66affSColin Finck if (!(search.match_flags & FOUND_CODEPAGE)) { 254*c2c66affSColin Finck /* Even if a codepage is not enumerated for a locale 255*c2c66affSColin Finck * it can be set if valid */ 256*c2c66affSColin Finck if (search.search_codepage[0]) { 257*c2c66affSColin Finck if (IsValidCodePage(atoi(search.search_codepage))) 258*c2c66affSColin Finck memcpy(search.found_codepage,search.search_codepage,MAX_ELEM_LEN); 259*c2c66affSColin Finck else { 260*c2c66affSColin Finck /* Special codepage values: OEM & ANSI */ 261*c2c66affSColin Finck if (!strcasecmp(search.search_codepage,"OCP")) { 262*c2c66affSColin Finck GetLocaleInfoA(lcid, LOCALE_IDEFAULTCODEPAGE, 263*c2c66affSColin Finck search.found_codepage, MAX_ELEM_LEN); 264*c2c66affSColin Finck } else if (!strcasecmp(search.search_codepage,"ACP")) { 265*c2c66affSColin Finck GetLocaleInfoA(lcid, LOCALE_IDEFAULTANSICODEPAGE, 266*c2c66affSColin Finck search.found_codepage, MAX_ELEM_LEN); 267*c2c66affSColin Finck } else 268*c2c66affSColin Finck return -1; 269*c2c66affSColin Finck 270*c2c66affSColin Finck if (!atoi(search.found_codepage)) 271*c2c66affSColin Finck return -1; 272*c2c66affSColin Finck } 273*c2c66affSColin Finck } else { 274*c2c66affSColin Finck /* Prefer ANSI codepages if present */ 275*c2c66affSColin Finck GetLocaleInfoA(lcid, LOCALE_IDEFAULTANSICODEPAGE, 276*c2c66affSColin Finck search.found_codepage, MAX_ELEM_LEN); 277*c2c66affSColin Finck if (!search.found_codepage[0] || !atoi(search.found_codepage)) 278*c2c66affSColin Finck GetLocaleInfoA(lcid, LOCALE_IDEFAULTCODEPAGE, 279*c2c66affSColin Finck search.found_codepage, MAX_ELEM_LEN); 280*c2c66affSColin Finck } 281*c2c66affSColin Finck } 282*c2c66affSColin Finck if (codepage) 283*c2c66affSColin Finck *codepage = atoi(search.found_codepage); 284*c2c66affSColin Finck 285*c2c66affSColin Finck return lcid; 286*c2c66affSColin Finck } 287*c2c66affSColin Finck 288*c2c66affSColin Finck /* INTERNAL: Set lc_handle, lc_id and lc_category in threadlocinfo struct */ 289*c2c66affSColin Finck static BOOL update_threadlocinfo_category(LCID lcid, unsigned short cp, 290*c2c66affSColin Finck MSVCRT__locale_t loc, int category) 291*c2c66affSColin Finck { 292*c2c66affSColin Finck char buf[256], *p; 293*c2c66affSColin Finck int len; 294*c2c66affSColin Finck 295*c2c66affSColin Finck if(GetLocaleInfoA(lcid, LOCALE_ILANGUAGE|LOCALE_NOUSEROVERRIDE, buf, 256)) { 296*c2c66affSColin Finck p = buf; 297*c2c66affSColin Finck 298*c2c66affSColin Finck loc->locinfo->lc_id[category].wLanguage = 0; 299*c2c66affSColin Finck while(*p) { 300*c2c66affSColin Finck loc->locinfo->lc_id[category].wLanguage *= 16; 301*c2c66affSColin Finck 302*c2c66affSColin Finck if(*p <= '9') 303*c2c66affSColin Finck loc->locinfo->lc_id[category].wLanguage += *p-'0'; 304*c2c66affSColin Finck else 305*c2c66affSColin Finck loc->locinfo->lc_id[category].wLanguage += *p-'a'+10; 306*c2c66affSColin Finck 307*c2c66affSColin Finck p++; 308*c2c66affSColin Finck } 309*c2c66affSColin Finck 310*c2c66affSColin Finck loc->locinfo->lc_id[category].wCountry = 311*c2c66affSColin Finck loc->locinfo->lc_id[category].wLanguage; 312*c2c66affSColin Finck } 313*c2c66affSColin Finck 314*c2c66affSColin Finck loc->locinfo->lc_id[category].wCodePage = cp; 315*c2c66affSColin Finck 316*c2c66affSColin Finck loc->locinfo->lc_handle[category] = lcid; 317*c2c66affSColin Finck 318*c2c66affSColin Finck len = 0; 319*c2c66affSColin Finck len += GetLocaleInfoA(lcid, LOCALE_SENGLANGUAGE 320*c2c66affSColin Finck |LOCALE_NOUSEROVERRIDE, buf, 256); 321*c2c66affSColin Finck buf[len-1] = '_'; 322*c2c66affSColin Finck len += GetLocaleInfoA(lcid, LOCALE_SENGCOUNTRY 323*c2c66affSColin Finck |LOCALE_NOUSEROVERRIDE, &buf[len], 256-len); 324*c2c66affSColin Finck buf[len-1] = '.'; 325*c2c66affSColin Finck sprintf(buf+len, "%u", cp); 326*c2c66affSColin Finck len += strlen(buf+len)+1; 327*c2c66affSColin Finck 328*c2c66affSColin Finck loc->locinfo->lc_category[category].locale = MSVCRT_malloc(len); 329*c2c66affSColin Finck loc->locinfo->lc_category[category].refcount = MSVCRT_malloc(sizeof(int)); 330*c2c66affSColin Finck if(!loc->locinfo->lc_category[category].locale 331*c2c66affSColin Finck || !loc->locinfo->lc_category[category].refcount) { 332*c2c66affSColin Finck MSVCRT_free(loc->locinfo->lc_category[category].locale); 333*c2c66affSColin Finck MSVCRT_free(loc->locinfo->lc_category[category].refcount); 334*c2c66affSColin Finck loc->locinfo->lc_category[category].locale = NULL; 335*c2c66affSColin Finck loc->locinfo->lc_category[category].refcount = NULL; 336*c2c66affSColin Finck return TRUE; 337*c2c66affSColin Finck } 338*c2c66affSColin Finck memcpy(loc->locinfo->lc_category[category].locale, buf, len); 339*c2c66affSColin Finck *loc->locinfo->lc_category[category].refcount = 1; 340*c2c66affSColin Finck 341*c2c66affSColin Finck return FALSE; 342*c2c66affSColin Finck } 343*c2c66affSColin Finck 344*c2c66affSColin Finck /* INTERNAL: swap pointers values */ 345*c2c66affSColin Finck static inline void swap_pointers(void **p1, void **p2) { 346*c2c66affSColin Finck void *hlp; 347*c2c66affSColin Finck 348*c2c66affSColin Finck hlp = *p1; 349*c2c66affSColin Finck *p1 = *p2; 350*c2c66affSColin Finck *p2 = hlp; 351*c2c66affSColin Finck } 352*c2c66affSColin Finck 353*c2c66affSColin Finck /* INTERNAL: returns pthreadlocinfo struct */ 354*c2c66affSColin Finck MSVCRT_pthreadlocinfo get_locinfo(void) { 355*c2c66affSColin Finck thread_data_t *data = msvcrt_get_thread_data(); 356*c2c66affSColin Finck 357*c2c66affSColin Finck if(!data || !data->have_locale) 358*c2c66affSColin Finck return MSVCRT_locale->locinfo; 359*c2c66affSColin Finck 360*c2c66affSColin Finck return data->locinfo; 361*c2c66affSColin Finck } 362*c2c66affSColin Finck 363*c2c66affSColin Finck /* INTERNAL: returns pthreadlocinfo struct */ 364*c2c66affSColin Finck MSVCRT_pthreadmbcinfo get_mbcinfo(void) { 365*c2c66affSColin Finck thread_data_t *data = msvcrt_get_thread_data(); 366*c2c66affSColin Finck 367*c2c66affSColin Finck if(!data || !data->have_locale) 368*c2c66affSColin Finck return MSVCRT_locale->mbcinfo; 369*c2c66affSColin Finck 370*c2c66affSColin Finck return data->mbcinfo; 371*c2c66affSColin Finck } 372*c2c66affSColin Finck 373*c2c66affSColin Finck /* INTERNAL: constructs string returned by setlocale */ 374*c2c66affSColin Finck static inline char* construct_lc_all(MSVCRT_pthreadlocinfo locinfo) { 375*c2c66affSColin Finck static char current_lc_all[MAX_LOCALE_LENGTH]; 376*c2c66affSColin Finck 377*c2c66affSColin Finck int i; 378*c2c66affSColin Finck 379*c2c66affSColin Finck for(i=MSVCRT_LC_MIN+1; i<MSVCRT_LC_MAX; i++) { 380*c2c66affSColin Finck if(strcmp(locinfo->lc_category[i].locale, 381*c2c66affSColin Finck locinfo->lc_category[i+1].locale)) 382*c2c66affSColin Finck break; 383*c2c66affSColin Finck } 384*c2c66affSColin Finck 385*c2c66affSColin Finck if(i==MSVCRT_LC_MAX) 386*c2c66affSColin Finck return locinfo->lc_category[MSVCRT_LC_COLLATE].locale; 387*c2c66affSColin Finck 388*c2c66affSColin Finck sprintf(current_lc_all, 389*c2c66affSColin Finck "LC_COLLATE=%s;LC_CTYPE=%s;LC_MONETARY=%s;LC_NUMERIC=%s;LC_TIME=%s", 390*c2c66affSColin Finck locinfo->lc_category[MSVCRT_LC_COLLATE].locale, 391*c2c66affSColin Finck locinfo->lc_category[MSVCRT_LC_CTYPE].locale, 392*c2c66affSColin Finck locinfo->lc_category[MSVCRT_LC_MONETARY].locale, 393*c2c66affSColin Finck locinfo->lc_category[MSVCRT_LC_NUMERIC].locale, 394*c2c66affSColin Finck locinfo->lc_category[MSVCRT_LC_TIME].locale); 395*c2c66affSColin Finck 396*c2c66affSColin Finck return current_lc_all; 397*c2c66affSColin Finck } 398*c2c66affSColin Finck 399*c2c66affSColin Finck 400*c2c66affSColin Finck /********************************************************************* 401*c2c66affSColin Finck * wsetlocale (MSVCRT.@) 402*c2c66affSColin Finck */ 403*c2c66affSColin Finck wchar_t* CDECL _wsetlocale(int category, const wchar_t* locale) 404*c2c66affSColin Finck { 405*c2c66affSColin Finck static wchar_t fake[] = { 406*c2c66affSColin Finck 'E','n','g','l','i','s','h','_','U','n','i','t','e','d',' ', 407*c2c66affSColin Finck 'S','t','a','t','e','s','.','1','2','5','2',0 }; 408*c2c66affSColin Finck 409*c2c66affSColin Finck FIXME("%d %s\n", category, debugstr_w(locale)); 410*c2c66affSColin Finck 411*c2c66affSColin Finck return fake; 412*c2c66affSColin Finck } 413*c2c66affSColin Finck 414*c2c66affSColin Finck /********************************************************************* 415*c2c66affSColin Finck * _Getdays (MSVCRT.@) 416*c2c66affSColin Finck */ 417*c2c66affSColin Finck char* CDECL _Getdays(void) 418*c2c66affSColin Finck { 419*c2c66affSColin Finck MSVCRT___lc_time_data *cur = get_locinfo()->lc_time_curr; 420*c2c66affSColin Finck int i, len, size; 421*c2c66affSColin Finck char *out; 422*c2c66affSColin Finck 423*c2c66affSColin Finck TRACE("\n"); 424*c2c66affSColin Finck 425*c2c66affSColin Finck size = cur->str.names.short_mon[0]-cur->str.names.short_wday[0]; 426*c2c66affSColin Finck out = MSVCRT_malloc(size+1); 427*c2c66affSColin Finck if(!out) 428*c2c66affSColin Finck return NULL; 429*c2c66affSColin Finck 430*c2c66affSColin Finck size = 0; 431*c2c66affSColin Finck for(i=0; i<7; i++) { 432*c2c66affSColin Finck out[size++] = ':'; 433*c2c66affSColin Finck len = strlen(cur->str.names.short_wday[i]); 434*c2c66affSColin Finck memcpy(&out[size], cur->str.names.short_wday[i], len); 435*c2c66affSColin Finck size += len; 436*c2c66affSColin Finck 437*c2c66affSColin Finck out[size++] = ':'; 438*c2c66affSColin Finck len = strlen(cur->str.names.wday[i]); 439*c2c66affSColin Finck memcpy(&out[size], cur->str.names.wday[i], len); 440*c2c66affSColin Finck size += len; 441*c2c66affSColin Finck } 442*c2c66affSColin Finck out[size] = '\0'; 443*c2c66affSColin Finck 444*c2c66affSColin Finck return out; 445*c2c66affSColin Finck } 446*c2c66affSColin Finck 447*c2c66affSColin Finck /********************************************************************* 448*c2c66affSColin Finck * _Getmonths (MSVCRT.@) 449*c2c66affSColin Finck */ 450*c2c66affSColin Finck char* CDECL _Getmonths(void) 451*c2c66affSColin Finck { 452*c2c66affSColin Finck MSVCRT___lc_time_data *cur = get_locinfo()->lc_time_curr; 453*c2c66affSColin Finck int i, len, size; 454*c2c66affSColin Finck char *out; 455*c2c66affSColin Finck 456*c2c66affSColin Finck TRACE("\n"); 457*c2c66affSColin Finck 458*c2c66affSColin Finck size = cur->str.names.am-cur->str.names.short_mon[0]; 459*c2c66affSColin Finck out = MSVCRT_malloc(size+1); 460*c2c66affSColin Finck if(!out) 461*c2c66affSColin Finck return NULL; 462*c2c66affSColin Finck 463*c2c66affSColin Finck size = 0; 464*c2c66affSColin Finck for(i=0; i<12; i++) { 465*c2c66affSColin Finck out[size++] = ':'; 466*c2c66affSColin Finck len = strlen(cur->str.names.short_mon[i]); 467*c2c66affSColin Finck memcpy(&out[size], cur->str.names.short_mon[i], len); 468*c2c66affSColin Finck size += len; 469*c2c66affSColin Finck 470*c2c66affSColin Finck out[size++] = ':'; 471*c2c66affSColin Finck len = strlen(cur->str.names.mon[i]); 472*c2c66affSColin Finck memcpy(&out[size], cur->str.names.mon[i], len); 473*c2c66affSColin Finck size += len; 474*c2c66affSColin Finck } 475*c2c66affSColin Finck out[size] = '\0'; 476*c2c66affSColin Finck 477*c2c66affSColin Finck return out; 478*c2c66affSColin Finck } 479*c2c66affSColin Finck 480*c2c66affSColin Finck /********************************************************************* 481*c2c66affSColin Finck * _Gettnames (MSVCRT.@) 482*c2c66affSColin Finck */ 483*c2c66affSColin Finck void* CDECL _Gettnames(void) 484*c2c66affSColin Finck { 485*c2c66affSColin Finck MSVCRT___lc_time_data *ret, *cur = get_locinfo()->lc_time_curr; 486*c2c66affSColin Finck unsigned int i, size = sizeof(MSVCRT___lc_time_data); 487*c2c66affSColin Finck 488*c2c66affSColin Finck TRACE("\n"); 489*c2c66affSColin Finck 490*c2c66affSColin Finck for(i=0; i<sizeof(cur->str.str)/sizeof(cur->str.str[0]); i++) 491*c2c66affSColin Finck size += strlen(cur->str.str[i])+1; 492*c2c66affSColin Finck 493*c2c66affSColin Finck ret = MSVCRT_malloc(size); 494*c2c66affSColin Finck if(!ret) 495*c2c66affSColin Finck return NULL; 496*c2c66affSColin Finck memcpy(ret, cur, size); 497*c2c66affSColin Finck 498*c2c66affSColin Finck size = 0; 499*c2c66affSColin Finck for(i=0; i<sizeof(cur->str.str)/sizeof(cur->str.str[0]); i++) { 500*c2c66affSColin Finck ret->str.str[i] = &ret->data[size]; 501*c2c66affSColin Finck size += strlen(&ret->data[size])+1; 502*c2c66affSColin Finck } 503*c2c66affSColin Finck 504*c2c66affSColin Finck return ret; 505*c2c66affSColin Finck } 506*c2c66affSColin Finck 507*c2c66affSColin Finck /********************************************************************* 508*c2c66affSColin Finck * __crtLCMapStringA (MSVCRT.@) 509*c2c66affSColin Finck */ 510*c2c66affSColin Finck int CDECL __crtLCMapStringA( 511*c2c66affSColin Finck LCID lcid, DWORD mapflags, const char* src, int srclen, char* dst, 512*c2c66affSColin Finck int dstlen, unsigned int codepage, int xflag 513*c2c66affSColin Finck ) { 514*c2c66affSColin Finck FIXME("(lcid %x, flags %x, %s(%d), %p(%d), %x, %d), partial stub!\n", 515*c2c66affSColin Finck lcid,mapflags,src,srclen,dst,dstlen,codepage,xflag); 516*c2c66affSColin Finck /* FIXME: A bit incorrect. But msvcrt itself just converts its 517*c2c66affSColin Finck * arguments to wide strings and then calls LCMapStringW 518*c2c66affSColin Finck */ 519*c2c66affSColin Finck return LCMapStringA(lcid,mapflags,src,srclen,dst,dstlen); 520*c2c66affSColin Finck } 521*c2c66affSColin Finck 522*c2c66affSColin Finck /********************************************************************* 523*c2c66affSColin Finck * __crtLCMapStringW (MSVCRT.@) 524*c2c66affSColin Finck */ 525*c2c66affSColin Finck int CDECL __crtLCMapStringW(LCID lcid, DWORD mapflags, const wchar_t *src, 526*c2c66affSColin Finck int srclen, wchar_t *dst, int dstlen, unsigned int codepage, int xflag) 527*c2c66affSColin Finck { 528*c2c66affSColin Finck FIXME("(lcid %x, flags %x, %s(%d), %p(%d), %x, %d), partial stub!\n", 529*c2c66affSColin Finck lcid, mapflags, debugstr_w(src), srclen, dst, dstlen, codepage, xflag); 530*c2c66affSColin Finck 531*c2c66affSColin Finck return LCMapStringW(lcid, mapflags, src, srclen, dst, dstlen); 532*c2c66affSColin Finck } 533*c2c66affSColin Finck 534*c2c66affSColin Finck /********************************************************************* 535*c2c66affSColin Finck * __crtCompareStringA (MSVCRT.@) 536*c2c66affSColin Finck */ 537*c2c66affSColin Finck int CDECL __crtCompareStringA( LCID lcid, DWORD flags, const char *src1, int len1, 538*c2c66affSColin Finck const char *src2, int len2 ) 539*c2c66affSColin Finck { 540*c2c66affSColin Finck FIXME("(lcid %x, flags %x, %s(%d), %s(%d), partial stub\n", 541*c2c66affSColin Finck lcid, flags, debugstr_a(src1), len1, debugstr_a(src2), len2 ); 542*c2c66affSColin Finck /* FIXME: probably not entirely right */ 543*c2c66affSColin Finck return CompareStringA( lcid, flags, src1, len1, src2, len2 ); 544*c2c66affSColin Finck } 545*c2c66affSColin Finck 546*c2c66affSColin Finck /********************************************************************* 547*c2c66affSColin Finck * __crtCompareStringW (MSVCRT.@) 548*c2c66affSColin Finck */ 549*c2c66affSColin Finck int CDECL __crtCompareStringW( LCID lcid, DWORD flags, const wchar_t *src1, int len1, 550*c2c66affSColin Finck const wchar_t *src2, int len2 ) 551*c2c66affSColin Finck { 552*c2c66affSColin Finck FIXME("(lcid %x, flags %x, %s(%d), %s(%d), partial stub\n", 553*c2c66affSColin Finck lcid, flags, debugstr_w(src1), len1, debugstr_w(src2), len2 ); 554*c2c66affSColin Finck /* FIXME: probably not entirely right */ 555*c2c66affSColin Finck return CompareStringW( lcid, flags, src1, len1, src2, len2 ); 556*c2c66affSColin Finck } 557*c2c66affSColin Finck 558*c2c66affSColin Finck /********************************************************************* 559*c2c66affSColin Finck * __crtGetLocaleInfoW (MSVCRT.@) 560*c2c66affSColin Finck */ 561*c2c66affSColin Finck int CDECL __crtGetLocaleInfoW( LCID lcid, LCTYPE type, wchar_t *buffer, int len ) 562*c2c66affSColin Finck { 563*c2c66affSColin Finck FIXME("(lcid %x, type %x, %p(%d), partial stub\n", lcid, type, buffer, len ); 564*c2c66affSColin Finck /* FIXME: probably not entirely right */ 565*c2c66affSColin Finck return GetLocaleInfoW( lcid, type, buffer, len ); 566*c2c66affSColin Finck } 567*c2c66affSColin Finck 568*c2c66affSColin Finck /********************************************************************* 569*c2c66affSColin Finck * btowc(MSVCRT.@) 570*c2c66affSColin Finck */ 571*c2c66affSColin Finck wint_t CDECL MSVCRT_btowc(int c) 572*c2c66affSColin Finck { 573*c2c66affSColin Finck unsigned char letter = c; 574*c2c66affSColin Finck wchar_t ret; 575*c2c66affSColin Finck 576*c2c66affSColin Finck if(!MultiByteToWideChar(get_locinfo()->lc_handle[LC_CTYPE], 577*c2c66affSColin Finck 0, (LPCSTR)&letter, 1, &ret, 1)) 578*c2c66affSColin Finck return 0; 579*c2c66affSColin Finck 580*c2c66affSColin Finck return ret; 581*c2c66affSColin Finck } 582*c2c66affSColin Finck 583*c2c66affSColin Finck /********************************************************************* 584*c2c66affSColin Finck * __crtGetStringTypeW(MSVCRT.@) 585*c2c66affSColin Finck * 586*c2c66affSColin Finck * This function was accepting different number of arguments in older 587*c2c66affSColin Finck * versions of msvcrt. 588*c2c66affSColin Finck */ 589*c2c66affSColin Finck BOOL CDECL __crtGetStringTypeW(DWORD unk, DWORD type, 590*c2c66affSColin Finck wchar_t *buffer, int len, WORD *out) 591*c2c66affSColin Finck { 592*c2c66affSColin Finck FIXME("(unk %x, type %x, wstr %p(%d), %p) partial stub\n", 593*c2c66affSColin Finck unk, type, buffer, len, out); 594*c2c66affSColin Finck 595*c2c66affSColin Finck return GetStringTypeW(type, buffer, len, out); 596*c2c66affSColin Finck } 597*c2c66affSColin Finck 598*c2c66affSColin Finck /********************************************************************* 599*c2c66affSColin Finck * localeconv (MSVCRT.@) 600*c2c66affSColin Finck */ 601*c2c66affSColin Finck struct lconv * CDECL localeconv(void) 602*c2c66affSColin Finck { 603*c2c66affSColin Finck return (struct lconv*)get_locinfo()->lconv; 604*c2c66affSColin Finck } 605*c2c66affSColin Finck 606*c2c66affSColin Finck /********************************************************************* 607*c2c66affSColin Finck * __lconv_init (MSVCRT.@) 608*c2c66affSColin Finck */ 609*c2c66affSColin Finck int CDECL __lconv_init(void) 610*c2c66affSColin Finck { 611*c2c66affSColin Finck /* this is used to make chars unsigned */ 612*c2c66affSColin Finck charmax = 255; 613*c2c66affSColin Finck return 0; 614*c2c66affSColin Finck } 615*c2c66affSColin Finck 616*c2c66affSColin Finck /********************************************************************* 617*c2c66affSColin Finck * ___lc_handle_func (MSVCRT.@) 618*c2c66affSColin Finck */ 619*c2c66affSColin Finck LCID* CDECL ___lc_handle_func(void) 620*c2c66affSColin Finck { 621*c2c66affSColin Finck return MSVCRT___lc_handle; 622*c2c66affSColin Finck } 623*c2c66affSColin Finck 624*c2c66affSColin Finck /********************************************************************* 625*c2c66affSColin Finck * ___lc_codepage_func (MSVCRT.@) 626*c2c66affSColin Finck */ 627*c2c66affSColin Finck unsigned int CDECL ___lc_codepage_func(void) 628*c2c66affSColin Finck { 629*c2c66affSColin Finck return __lc_codepage; 630*c2c66affSColin Finck } 631*c2c66affSColin Finck 632*c2c66affSColin Finck /********************************************************************* 633*c2c66affSColin Finck * ___lc_collate_cp_func (MSVCRT.@) 634*c2c66affSColin Finck */ 635*c2c66affSColin Finck int CDECL ___lc_collate_cp_func(void) 636*c2c66affSColin Finck { 637*c2c66affSColin Finck return get_locinfo()->lc_collate_cp; 638*c2c66affSColin Finck } 639*c2c66affSColin Finck 640*c2c66affSColin Finck /* INTERNAL: frees MSVCRT_pthreadlocinfo struct */ 641*c2c66affSColin Finck void free_locinfo(MSVCRT_pthreadlocinfo locinfo) 642*c2c66affSColin Finck { 643*c2c66affSColin Finck int i; 644*c2c66affSColin Finck 645*c2c66affSColin Finck if(!locinfo) 646*c2c66affSColin Finck return; 647*c2c66affSColin Finck 648*c2c66affSColin Finck if(InterlockedDecrement(&locinfo->refcount)) 649*c2c66affSColin Finck return; 650*c2c66affSColin Finck 651*c2c66affSColin Finck for(i=MSVCRT_LC_MIN+1; i<=MSVCRT_LC_MAX; i++) { 652*c2c66affSColin Finck MSVCRT_free(locinfo->lc_category[i].locale); 653*c2c66affSColin Finck MSVCRT_free(locinfo->lc_category[i].refcount); 654*c2c66affSColin Finck } 655*c2c66affSColin Finck 656*c2c66affSColin Finck if(locinfo->lconv) { 657*c2c66affSColin Finck MSVCRT_free(locinfo->lconv->decimal_point); 658*c2c66affSColin Finck MSVCRT_free(locinfo->lconv->thousands_sep); 659*c2c66affSColin Finck MSVCRT_free(locinfo->lconv->grouping); 660*c2c66affSColin Finck MSVCRT_free(locinfo->lconv->int_curr_symbol); 661*c2c66affSColin Finck MSVCRT_free(locinfo->lconv->currency_symbol); 662*c2c66affSColin Finck MSVCRT_free(locinfo->lconv->mon_decimal_point); 663*c2c66affSColin Finck MSVCRT_free(locinfo->lconv->mon_thousands_sep); 664*c2c66affSColin Finck MSVCRT_free(locinfo->lconv->mon_grouping); 665*c2c66affSColin Finck MSVCRT_free(locinfo->lconv->positive_sign); 666*c2c66affSColin Finck MSVCRT_free(locinfo->lconv->negative_sign); 667*c2c66affSColin Finck } 668*c2c66affSColin Finck MSVCRT_free(locinfo->lconv_intl_refcount); 669*c2c66affSColin Finck MSVCRT_free(locinfo->lconv_num_refcount); 670*c2c66affSColin Finck MSVCRT_free(locinfo->lconv_mon_refcount); 671*c2c66affSColin Finck MSVCRT_free(locinfo->lconv); 672*c2c66affSColin Finck 673*c2c66affSColin Finck MSVCRT_free(locinfo->ctype1_refcount); 674*c2c66affSColin Finck MSVCRT_free(locinfo->ctype1); 675*c2c66affSColin Finck 676*c2c66affSColin Finck MSVCRT_free(locinfo->pclmap); 677*c2c66affSColin Finck MSVCRT_free(locinfo->pcumap); 678*c2c66affSColin Finck 679*c2c66affSColin Finck MSVCRT_free(locinfo->lc_time_curr); 680*c2c66affSColin Finck 681*c2c66affSColin Finck MSVCRT_free(locinfo); 682*c2c66affSColin Finck } 683*c2c66affSColin Finck 684*c2c66affSColin Finck /* INTERNAL: frees MSVCRT_pthreadmbcinfo struct */ 685*c2c66affSColin Finck void free_mbcinfo(MSVCRT_pthreadmbcinfo mbcinfo) 686*c2c66affSColin Finck { 687*c2c66affSColin Finck if(!mbcinfo) 688*c2c66affSColin Finck return; 689*c2c66affSColin Finck 690*c2c66affSColin Finck if(InterlockedDecrement(&mbcinfo->refcount)) 691*c2c66affSColin Finck return; 692*c2c66affSColin Finck 693*c2c66affSColin Finck MSVCRT_free(mbcinfo); 694*c2c66affSColin Finck } 695*c2c66affSColin Finck 696*c2c66affSColin Finck /* _get_current_locale - not exported in native msvcrt */ 697*c2c66affSColin Finck MSVCRT__locale_t CDECL MSVCRT__get_current_locale(void) 698*c2c66affSColin Finck { 699*c2c66affSColin Finck MSVCRT__locale_t loc = MSVCRT_malloc(sizeof(MSVCRT__locale_tstruct)); 700*c2c66affSColin Finck if(!loc) 701*c2c66affSColin Finck return NULL; 702*c2c66affSColin Finck 703*c2c66affSColin Finck loc->locinfo = get_locinfo(); 704*c2c66affSColin Finck loc->mbcinfo = get_mbcinfo(); 705*c2c66affSColin Finck InterlockedIncrement(&loc->locinfo->refcount); 706*c2c66affSColin Finck InterlockedIncrement(&loc->mbcinfo->refcount); 707*c2c66affSColin Finck return loc; 708*c2c66affSColin Finck } 709*c2c66affSColin Finck 710*c2c66affSColin Finck /* _free_locale - not exported in native msvcrt */ 711*c2c66affSColin Finck void CDECL MSVCRT__free_locale(MSVCRT__locale_t locale) 712*c2c66affSColin Finck { 713*c2c66affSColin Finck if (!locale) 714*c2c66affSColin Finck return; 715*c2c66affSColin Finck 716*c2c66affSColin Finck free_locinfo(locale->locinfo); 717*c2c66affSColin Finck free_mbcinfo(locale->mbcinfo); 718*c2c66affSColin Finck MSVCRT_free(locale); 719*c2c66affSColin Finck } 720*c2c66affSColin Finck 721*c2c66affSColin Finck /* _create_locale - not exported in native msvcrt */ 722*c2c66affSColin Finck MSVCRT__locale_t CDECL MSVCRT__create_locale(int category, const char *locale) 723*c2c66affSColin Finck { 724*c2c66affSColin Finck static const DWORD time_data[] = { 725*c2c66affSColin Finck LOCALE_SABBREVDAYNAME7, LOCALE_SABBREVDAYNAME1, LOCALE_SABBREVDAYNAME2, 726*c2c66affSColin Finck LOCALE_SABBREVDAYNAME3, LOCALE_SABBREVDAYNAME4, LOCALE_SABBREVDAYNAME5, 727*c2c66affSColin Finck LOCALE_SABBREVDAYNAME6, 728*c2c66affSColin Finck LOCALE_SDAYNAME7, LOCALE_SDAYNAME1, LOCALE_SDAYNAME2, LOCALE_SDAYNAME3, 729*c2c66affSColin Finck LOCALE_SDAYNAME4, LOCALE_SDAYNAME5, LOCALE_SDAYNAME6, 730*c2c66affSColin Finck LOCALE_SABBREVMONTHNAME1, LOCALE_SABBREVMONTHNAME2, LOCALE_SABBREVMONTHNAME3, 731*c2c66affSColin Finck LOCALE_SABBREVMONTHNAME4, LOCALE_SABBREVMONTHNAME5, LOCALE_SABBREVMONTHNAME6, 732*c2c66affSColin Finck LOCALE_SABBREVMONTHNAME7, LOCALE_SABBREVMONTHNAME8, LOCALE_SABBREVMONTHNAME9, 733*c2c66affSColin Finck LOCALE_SABBREVMONTHNAME10, LOCALE_SABBREVMONTHNAME11, LOCALE_SABBREVMONTHNAME12, 734*c2c66affSColin Finck LOCALE_SMONTHNAME1, LOCALE_SMONTHNAME2, LOCALE_SMONTHNAME3, LOCALE_SMONTHNAME4, 735*c2c66affSColin Finck LOCALE_SMONTHNAME5, LOCALE_SMONTHNAME6, LOCALE_SMONTHNAME7, LOCALE_SMONTHNAME8, 736*c2c66affSColin Finck LOCALE_SMONTHNAME9, LOCALE_SMONTHNAME10, LOCALE_SMONTHNAME11, LOCALE_SMONTHNAME12, 737*c2c66affSColin Finck LOCALE_S1159, LOCALE_S2359, 738*c2c66affSColin Finck LOCALE_SSHORTDATE, LOCALE_SLONGDATE, 739*c2c66affSColin Finck LOCALE_STIMEFORMAT 740*c2c66affSColin Finck }; 741*c2c66affSColin Finck static const char collate[] = "COLLATE="; 742*c2c66affSColin Finck static const char ctype[] = "CTYPE="; 743*c2c66affSColin Finck static const char monetary[] = "MONETARY="; 744*c2c66affSColin Finck static const char numeric[] = "NUMERIC="; 745*c2c66affSColin Finck static const char time[] = "TIME="; 746*c2c66affSColin Finck static const char cloc_short_date[] = "MM/dd/yy"; 747*c2c66affSColin Finck static const wchar_t cloc_short_dateW[] = {'M','M','/','d','d','/','y','y',0}; 748*c2c66affSColin Finck static const char cloc_long_date[] = "dddd, MMMM dd, yyyy"; 749*c2c66affSColin Finck static const wchar_t cloc_long_dateW[] = {'d','d','d','d',',',' ','M','M','M','M',' ','d','d',',',' ','y','y','y','y',0}; 750*c2c66affSColin Finck static const char cloc_time[] = "HH:mm:ss"; 751*c2c66affSColin Finck static const wchar_t cloc_timeW[] = {'H','H',':','m','m',':','s','s',0}; 752*c2c66affSColin Finck 753*c2c66affSColin Finck MSVCRT__locale_t loc; 754*c2c66affSColin Finck LCID lcid[6] = { 0 }, lcid_tmp; 755*c2c66affSColin Finck unsigned short cp[6] = { 0 }; 756*c2c66affSColin Finck char buf[256]; 757*c2c66affSColin Finck int i, ret, size; 758*c2c66affSColin Finck 759*c2c66affSColin Finck TRACE("(%d %s)\n", category, locale); 760*c2c66affSColin Finck 761*c2c66affSColin Finck if(category<MSVCRT_LC_MIN || category>MSVCRT_LC_MAX || !locale) 762*c2c66affSColin Finck return NULL; 763*c2c66affSColin Finck 764*c2c66affSColin Finck if(locale[0]=='C' && !locale[1]) { 765*c2c66affSColin Finck lcid[0] = 0; 766*c2c66affSColin Finck cp[0] = CP_ACP; 767*c2c66affSColin Finck } else if(!locale[0]) { 768*c2c66affSColin Finck lcid[0] = GetSystemDefaultLCID(); 769*c2c66affSColin Finck GetLocaleInfoA(lcid[0], LOCALE_IDEFAULTANSICODEPAGE 770*c2c66affSColin Finck |LOCALE_NOUSEROVERRIDE, buf, sizeof(buf)); 771*c2c66affSColin Finck cp[0] = atoi(buf); 772*c2c66affSColin Finck 773*c2c66affSColin Finck for(i=1; i<6; i++) { 774*c2c66affSColin Finck lcid[i] = lcid[0]; 775*c2c66affSColin Finck cp[i] = cp[0]; 776*c2c66affSColin Finck } 777*c2c66affSColin Finck } else if (locale[0] == 'L' && locale[1] == 'C' && locale[2] == '_') { 778*c2c66affSColin Finck const char *p; 779*c2c66affSColin Finck 780*c2c66affSColin Finck while(1) { 781*c2c66affSColin Finck locale += 3; /* LC_ */ 782*c2c66affSColin Finck if(!memcmp(locale, collate, sizeof(collate)-1)) { 783*c2c66affSColin Finck i = MSVCRT_LC_COLLATE; 784*c2c66affSColin Finck locale += sizeof(collate)-1; 785*c2c66affSColin Finck } else if(!memcmp(locale, ctype, sizeof(ctype)-1)) { 786*c2c66affSColin Finck i = MSVCRT_LC_CTYPE; 787*c2c66affSColin Finck locale += sizeof(ctype)-1; 788*c2c66affSColin Finck } else if(!memcmp(locale, monetary, sizeof(monetary)-1)) { 789*c2c66affSColin Finck i = MSVCRT_LC_MONETARY; 790*c2c66affSColin Finck locale += sizeof(monetary)-1; 791*c2c66affSColin Finck } else if(!memcmp(locale, numeric, sizeof(numeric)-1)) { 792*c2c66affSColin Finck i = MSVCRT_LC_NUMERIC; 793*c2c66affSColin Finck locale += sizeof(numeric)-1; 794*c2c66affSColin Finck } else if(!memcmp(locale, time, sizeof(time)-1)) { 795*c2c66affSColin Finck i = MSVCRT_LC_TIME; 796*c2c66affSColin Finck locale += sizeof(time)-1; 797*c2c66affSColin Finck } else 798*c2c66affSColin Finck return NULL; 799*c2c66affSColin Finck 800*c2c66affSColin Finck p = strchr(locale, ';'); 801*c2c66affSColin Finck if(locale[0]=='C' && (locale[1]==';' || locale[1]=='\0')) { 802*c2c66affSColin Finck lcid[i] = 0; 803*c2c66affSColin Finck cp[i] = CP_ACP; 804*c2c66affSColin Finck } else if(p) { 805*c2c66affSColin Finck memcpy(buf, locale, p-locale); 806*c2c66affSColin Finck buf[p-locale] = '\0'; 807*c2c66affSColin Finck lcid[i] = MSVCRT_locale_to_LCID(buf, &cp[i]); 808*c2c66affSColin Finck } else 809*c2c66affSColin Finck lcid[i] = MSVCRT_locale_to_LCID(locale, &cp[i]); 810*c2c66affSColin Finck 811*c2c66affSColin Finck if(lcid[i] == -1) 812*c2c66affSColin Finck return NULL; 813*c2c66affSColin Finck 814*c2c66affSColin Finck if(!p || *(p+1)!='L' || *(p+2)!='C' || *(p+3)!='_') 815*c2c66affSColin Finck break; 816*c2c66affSColin Finck 817*c2c66affSColin Finck locale = p+1; 818*c2c66affSColin Finck } 819*c2c66affSColin Finck } else { 820*c2c66affSColin Finck lcid[0] = MSVCRT_locale_to_LCID(locale, &cp[0]); 821*c2c66affSColin Finck if(lcid[0] == -1) 822*c2c66affSColin Finck return NULL; 823*c2c66affSColin Finck 824*c2c66affSColin Finck for(i=1; i<6; i++) { 825*c2c66affSColin Finck lcid[i] = lcid[0]; 826*c2c66affSColin Finck cp[i] = cp[0]; 827*c2c66affSColin Finck } 828*c2c66affSColin Finck } 829*c2c66affSColin Finck 830*c2c66affSColin Finck loc = MSVCRT_malloc(sizeof(MSVCRT__locale_tstruct)); 831*c2c66affSColin Finck if(!loc) 832*c2c66affSColin Finck return NULL; 833*c2c66affSColin Finck 834*c2c66affSColin Finck loc->locinfo = MSVCRT_malloc(sizeof(MSVCRT_threadlocinfo)); 835*c2c66affSColin Finck if(!loc->locinfo) { 836*c2c66affSColin Finck MSVCRT_free(loc); 837*c2c66affSColin Finck return NULL; 838*c2c66affSColin Finck } 839*c2c66affSColin Finck 840*c2c66affSColin Finck loc->mbcinfo = MSVCRT_malloc(sizeof(MSVCRT_threadmbcinfo)); 841*c2c66affSColin Finck if(!loc->mbcinfo) { 842*c2c66affSColin Finck MSVCRT_free(loc->locinfo); 843*c2c66affSColin Finck MSVCRT_free(loc); 844*c2c66affSColin Finck return NULL; 845*c2c66affSColin Finck } 846*c2c66affSColin Finck 847*c2c66affSColin Finck memset(loc->locinfo, 0, sizeof(MSVCRT_threadlocinfo)); 848*c2c66affSColin Finck loc->locinfo->refcount = 1; 849*c2c66affSColin Finck loc->mbcinfo->refcount = 1; 850*c2c66affSColin Finck 851*c2c66affSColin Finck loc->locinfo->lconv = MSVCRT_malloc(sizeof(struct MSVCRT_lconv)); 852*c2c66affSColin Finck if(!loc->locinfo->lconv) { 853*c2c66affSColin Finck MSVCRT__free_locale(loc); 854*c2c66affSColin Finck return NULL; 855*c2c66affSColin Finck } 856*c2c66affSColin Finck memset(loc->locinfo->lconv, 0, sizeof(struct MSVCRT_lconv)); 857*c2c66affSColin Finck 858*c2c66affSColin Finck loc->locinfo->pclmap = MSVCRT_malloc(sizeof(char[256])); 859*c2c66affSColin Finck loc->locinfo->pcumap = MSVCRT_malloc(sizeof(char[256])); 860*c2c66affSColin Finck if(!loc->locinfo->pclmap || !loc->locinfo->pcumap) { 861*c2c66affSColin Finck MSVCRT__free_locale(loc); 862*c2c66affSColin Finck return NULL; 863*c2c66affSColin Finck } 864*c2c66affSColin Finck 865*c2c66affSColin Finck if(lcid[MSVCRT_LC_COLLATE] && (category==MSVCRT_LC_ALL || category==MSVCRT_LC_COLLATE)) { 866*c2c66affSColin Finck if(update_threadlocinfo_category(lcid[MSVCRT_LC_COLLATE], cp[MSVCRT_LC_COLLATE], loc, MSVCRT_LC_COLLATE)) { 867*c2c66affSColin Finck MSVCRT__free_locale(loc); 868*c2c66affSColin Finck return NULL; 869*c2c66affSColin Finck } 870*c2c66affSColin Finck 871*c2c66affSColin Finck loc->locinfo->lc_collate_cp = loc->locinfo->lc_id[MSVCRT_LC_COLLATE].wCodePage; 872*c2c66affSColin Finck } else 873*c2c66affSColin Finck loc->locinfo->lc_category[LC_COLLATE].locale = _strdup("C"); 874*c2c66affSColin Finck 875*c2c66affSColin Finck if(lcid[MSVCRT_LC_CTYPE] && (category==MSVCRT_LC_ALL || category==MSVCRT_LC_CTYPE)) { 876*c2c66affSColin Finck CPINFO cp_info; 877*c2c66affSColin Finck int j; 878*c2c66affSColin Finck 879*c2c66affSColin Finck if(update_threadlocinfo_category(lcid[MSVCRT_LC_CTYPE], cp[MSVCRT_LC_CTYPE], loc, MSVCRT_LC_CTYPE)) { 880*c2c66affSColin Finck MSVCRT__free_locale(loc); 881*c2c66affSColin Finck return NULL; 882*c2c66affSColin Finck } 883*c2c66affSColin Finck 884*c2c66affSColin Finck loc->locinfo->lc_codepage = loc->locinfo->lc_id[MSVCRT_LC_CTYPE].wCodePage; 885*c2c66affSColin Finck loc->locinfo->lc_clike = 1; 886*c2c66affSColin Finck if(!GetCPInfo(loc->locinfo->lc_codepage, &cp_info)) { 887*c2c66affSColin Finck MSVCRT__free_locale(loc); 888*c2c66affSColin Finck return NULL; 889*c2c66affSColin Finck } 890*c2c66affSColin Finck loc->locinfo->mb_cur_max = cp_info.MaxCharSize; 891*c2c66affSColin Finck 892*c2c66affSColin Finck loc->locinfo->ctype1_refcount = MSVCRT_malloc(sizeof(int)); 893*c2c66affSColin Finck loc->locinfo->ctype1 = MSVCRT_malloc(sizeof(short[257])); 894*c2c66affSColin Finck if(!loc->locinfo->ctype1_refcount || !loc->locinfo->ctype1) { 895*c2c66affSColin Finck MSVCRT__free_locale(loc); 896*c2c66affSColin Finck return NULL; 897*c2c66affSColin Finck } 898*c2c66affSColin Finck 899*c2c66affSColin Finck *loc->locinfo->ctype1_refcount = 1; 900*c2c66affSColin Finck loc->locinfo->ctype1[0] = 0; 901*c2c66affSColin Finck loc->locinfo->pctype = loc->locinfo->ctype1+1; 902*c2c66affSColin Finck 903*c2c66affSColin Finck buf[1] = buf[2] = '\0'; 904*c2c66affSColin Finck for(i=1; i<257; i++) { 905*c2c66affSColin Finck buf[0] = i-1; 906*c2c66affSColin Finck 907*c2c66affSColin Finck /* builtin GetStringTypeA doesn't set output to 0 on invalid input */ 908*c2c66affSColin Finck loc->locinfo->ctype1[i] = 0; 909*c2c66affSColin Finck 910*c2c66affSColin Finck GetStringTypeA(lcid[MSVCRT_LC_CTYPE], CT_CTYPE1, buf, 911*c2c66affSColin Finck 1, loc->locinfo->ctype1+i); 912*c2c66affSColin Finck } 913*c2c66affSColin Finck 914*c2c66affSColin Finck for(i=0; cp_info.LeadByte[i+1]!=0; i+=2) 915*c2c66affSColin Finck for(j=cp_info.LeadByte[i]; j<=cp_info.LeadByte[i+1]; j++) 916*c2c66affSColin Finck loc->locinfo->ctype1[j+1] |= _LEADBYTE; 917*c2c66affSColin Finck } else { 918*c2c66affSColin Finck loc->locinfo->lc_clike = 1; 919*c2c66affSColin Finck loc->locinfo->mb_cur_max = 1; 920*c2c66affSColin Finck loc->locinfo->pctype = _ctype+1; 921*c2c66affSColin Finck loc->locinfo->lc_category[LC_CTYPE].locale = _strdup("C"); 922*c2c66affSColin Finck } 923*c2c66affSColin Finck 924*c2c66affSColin Finck for(i=0; i<256; i++) { 925*c2c66affSColin Finck if(loc->locinfo->pctype[i] & _LEADBYTE) 926*c2c66affSColin Finck buf[i] = ' '; 927*c2c66affSColin Finck else 928*c2c66affSColin Finck buf[i] = i; 929*c2c66affSColin Finck 930*c2c66affSColin Finck } 931*c2c66affSColin Finck 932*c2c66affSColin Finck if(lcid[MSVCRT_LC_CTYPE]) { 933*c2c66affSColin Finck LCMapStringA(lcid[MSVCRT_LC_CTYPE], LCMAP_LOWERCASE, buf, 256, 934*c2c66affSColin Finck (char*)loc->locinfo->pclmap, 256); 935*c2c66affSColin Finck LCMapStringA(lcid[MSVCRT_LC_CTYPE], LCMAP_UPPERCASE, buf, 256, 936*c2c66affSColin Finck (char*)loc->locinfo->pcumap, 256); 937*c2c66affSColin Finck } else { 938*c2c66affSColin Finck for(i=0; i<256; i++) { 939*c2c66affSColin Finck loc->locinfo->pclmap[i] = (i>='A' && i<='Z' ? i-'A'+'a' : i); 940*c2c66affSColin Finck loc->locinfo->pcumap[i] = (i>='a' && i<='z' ? i-'a'+'A' : i); 941*c2c66affSColin Finck } 942*c2c66affSColin Finck } 943*c2c66affSColin Finck 944*c2c66affSColin Finck _setmbcp_l(loc->locinfo->lc_id[MSVCRT_LC_CTYPE].wCodePage, lcid[MSVCRT_LC_CTYPE], loc->mbcinfo); 945*c2c66affSColin Finck 946*c2c66affSColin Finck if(lcid[MSVCRT_LC_MONETARY] && (category==MSVCRT_LC_ALL || category==MSVCRT_LC_MONETARY)) { 947*c2c66affSColin Finck if(update_threadlocinfo_category(lcid[MSVCRT_LC_MONETARY], cp[MSVCRT_LC_MONETARY], loc, MSVCRT_LC_MONETARY)) { 948*c2c66affSColin Finck MSVCRT__free_locale(loc); 949*c2c66affSColin Finck return NULL; 950*c2c66affSColin Finck } 951*c2c66affSColin Finck 952*c2c66affSColin Finck loc->locinfo->lconv_intl_refcount = MSVCRT_malloc(sizeof(int)); 953*c2c66affSColin Finck loc->locinfo->lconv_mon_refcount = MSVCRT_malloc(sizeof(int)); 954*c2c66affSColin Finck if(!loc->locinfo->lconv_intl_refcount || !loc->locinfo->lconv_mon_refcount) { 955*c2c66affSColin Finck MSVCRT__free_locale(loc); 956*c2c66affSColin Finck return NULL; 957*c2c66affSColin Finck } 958*c2c66affSColin Finck 959*c2c66affSColin Finck *loc->locinfo->lconv_intl_refcount = 1; 960*c2c66affSColin Finck *loc->locinfo->lconv_mon_refcount = 1; 961*c2c66affSColin Finck 962*c2c66affSColin Finck i = GetLocaleInfoA(lcid[MSVCRT_LC_MONETARY], LOCALE_SINTLSYMBOL 963*c2c66affSColin Finck |LOCALE_NOUSEROVERRIDE, buf, 256); 964*c2c66affSColin Finck if(i && (loc->locinfo->lconv->int_curr_symbol = MSVCRT_malloc(i))) 965*c2c66affSColin Finck memcpy(loc->locinfo->lconv->int_curr_symbol, buf, i); 966*c2c66affSColin Finck else { 967*c2c66affSColin Finck MSVCRT__free_locale(loc); 968*c2c66affSColin Finck return NULL; 969*c2c66affSColin Finck } 970*c2c66affSColin Finck 971*c2c66affSColin Finck i = GetLocaleInfoA(lcid[MSVCRT_LC_MONETARY], LOCALE_SCURRENCY 972*c2c66affSColin Finck |LOCALE_NOUSEROVERRIDE, buf, 256); 973*c2c66affSColin Finck if(i && (loc->locinfo->lconv->currency_symbol = MSVCRT_malloc(i))) 974*c2c66affSColin Finck memcpy(loc->locinfo->lconv->currency_symbol, buf, i); 975*c2c66affSColin Finck else { 976*c2c66affSColin Finck MSVCRT__free_locale(loc); 977*c2c66affSColin Finck return NULL; 978*c2c66affSColin Finck } 979*c2c66affSColin Finck 980*c2c66affSColin Finck i = GetLocaleInfoA(lcid[MSVCRT_LC_MONETARY], LOCALE_SMONDECIMALSEP 981*c2c66affSColin Finck |LOCALE_NOUSEROVERRIDE, buf, 256); 982*c2c66affSColin Finck if(i && (loc->locinfo->lconv->mon_decimal_point = MSVCRT_malloc(i))) 983*c2c66affSColin Finck memcpy(loc->locinfo->lconv->mon_decimal_point, buf, i); 984*c2c66affSColin Finck else { 985*c2c66affSColin Finck MSVCRT__free_locale(loc); 986*c2c66affSColin Finck return NULL; 987*c2c66affSColin Finck } 988*c2c66affSColin Finck 989*c2c66affSColin Finck i = GetLocaleInfoA(lcid[MSVCRT_LC_MONETARY], LOCALE_SMONTHOUSANDSEP 990*c2c66affSColin Finck |LOCALE_NOUSEROVERRIDE, buf, 256); 991*c2c66affSColin Finck if(i && (loc->locinfo->lconv->mon_thousands_sep = MSVCRT_malloc(i))) 992*c2c66affSColin Finck memcpy(loc->locinfo->lconv->mon_thousands_sep, buf, i); 993*c2c66affSColin Finck else { 994*c2c66affSColin Finck MSVCRT__free_locale(loc); 995*c2c66affSColin Finck return NULL; 996*c2c66affSColin Finck } 997*c2c66affSColin Finck 998*c2c66affSColin Finck i = GetLocaleInfoA(lcid[MSVCRT_LC_MONETARY], LOCALE_SMONGROUPING 999*c2c66affSColin Finck |LOCALE_NOUSEROVERRIDE, buf, 256); 1000*c2c66affSColin Finck if(i>1) 1001*c2c66affSColin Finck i = i/2 + (buf[i-2]=='0'?0:1); 1002*c2c66affSColin Finck if(i && (loc->locinfo->lconv->mon_grouping = MSVCRT_malloc(i))) { 1003*c2c66affSColin Finck for(i=0; buf[i+1]==';'; i+=2) 1004*c2c66affSColin Finck loc->locinfo->lconv->mon_grouping[i/2] = buf[i]-'0'; 1005*c2c66affSColin Finck loc->locinfo->lconv->mon_grouping[i/2] = buf[i]-'0'; 1006*c2c66affSColin Finck if(buf[i] != '0') 1007*c2c66affSColin Finck loc->locinfo->lconv->mon_grouping[i/2+1] = 127; 1008*c2c66affSColin Finck } else { 1009*c2c66affSColin Finck MSVCRT__free_locale(loc); 1010*c2c66affSColin Finck return NULL; 1011*c2c66affSColin Finck } 1012*c2c66affSColin Finck 1013*c2c66affSColin Finck i = GetLocaleInfoA(lcid[MSVCRT_LC_MONETARY], LOCALE_SPOSITIVESIGN 1014*c2c66affSColin Finck |LOCALE_NOUSEROVERRIDE, buf, 256); 1015*c2c66affSColin Finck if(i && (loc->locinfo->lconv->positive_sign = MSVCRT_malloc(i))) 1016*c2c66affSColin Finck memcpy(loc->locinfo->lconv->positive_sign, buf, i); 1017*c2c66affSColin Finck else { 1018*c2c66affSColin Finck MSVCRT__free_locale(loc); 1019*c2c66affSColin Finck return NULL; 1020*c2c66affSColin Finck } 1021*c2c66affSColin Finck 1022*c2c66affSColin Finck i = GetLocaleInfoA(lcid[MSVCRT_LC_MONETARY], LOCALE_SNEGATIVESIGN 1023*c2c66affSColin Finck |LOCALE_NOUSEROVERRIDE, buf, 256); 1024*c2c66affSColin Finck if(i && (loc->locinfo->lconv->negative_sign = MSVCRT_malloc(i))) 1025*c2c66affSColin Finck memcpy(loc->locinfo->lconv->negative_sign, buf, i); 1026*c2c66affSColin Finck else { 1027*c2c66affSColin Finck MSVCRT__free_locale(loc); 1028*c2c66affSColin Finck return NULL; 1029*c2c66affSColin Finck } 1030*c2c66affSColin Finck 1031*c2c66affSColin Finck if(GetLocaleInfoA(lcid[MSVCRT_LC_MONETARY], LOCALE_IINTLCURRDIGITS 1032*c2c66affSColin Finck |LOCALE_NOUSEROVERRIDE, buf, 256)) 1033*c2c66affSColin Finck loc->locinfo->lconv->int_frac_digits = atoi(buf); 1034*c2c66affSColin Finck else { 1035*c2c66affSColin Finck MSVCRT__free_locale(loc); 1036*c2c66affSColin Finck return NULL; 1037*c2c66affSColin Finck } 1038*c2c66affSColin Finck 1039*c2c66affSColin Finck if(GetLocaleInfoA(lcid[MSVCRT_LC_MONETARY], LOCALE_ICURRDIGITS 1040*c2c66affSColin Finck |LOCALE_NOUSEROVERRIDE, buf, 256)) 1041*c2c66affSColin Finck loc->locinfo->lconv->frac_digits = atoi(buf); 1042*c2c66affSColin Finck else { 1043*c2c66affSColin Finck MSVCRT__free_locale(loc); 1044*c2c66affSColin Finck return NULL; 1045*c2c66affSColin Finck } 1046*c2c66affSColin Finck 1047*c2c66affSColin Finck if(GetLocaleInfoA(lcid[MSVCRT_LC_MONETARY], LOCALE_IPOSSYMPRECEDES 1048*c2c66affSColin Finck |LOCALE_NOUSEROVERRIDE, buf, 256)) 1049*c2c66affSColin Finck loc->locinfo->lconv->p_cs_precedes = atoi(buf); 1050*c2c66affSColin Finck else { 1051*c2c66affSColin Finck MSVCRT__free_locale(loc); 1052*c2c66affSColin Finck return NULL; 1053*c2c66affSColin Finck } 1054*c2c66affSColin Finck 1055*c2c66affSColin Finck if(GetLocaleInfoA(lcid[MSVCRT_LC_MONETARY], LOCALE_IPOSSEPBYSPACE 1056*c2c66affSColin Finck |LOCALE_NOUSEROVERRIDE, buf, 256)) 1057*c2c66affSColin Finck loc->locinfo->lconv->p_sep_by_space = atoi(buf); 1058*c2c66affSColin Finck else { 1059*c2c66affSColin Finck MSVCRT__free_locale(loc); 1060*c2c66affSColin Finck return NULL; 1061*c2c66affSColin Finck } 1062*c2c66affSColin Finck 1063*c2c66affSColin Finck if(GetLocaleInfoA(lcid[MSVCRT_LC_MONETARY], LOCALE_INEGSYMPRECEDES 1064*c2c66affSColin Finck |LOCALE_NOUSEROVERRIDE, buf, 256)) 1065*c2c66affSColin Finck loc->locinfo->lconv->n_cs_precedes = atoi(buf); 1066*c2c66affSColin Finck else { 1067*c2c66affSColin Finck MSVCRT__free_locale(loc); 1068*c2c66affSColin Finck return NULL; 1069*c2c66affSColin Finck } 1070*c2c66affSColin Finck 1071*c2c66affSColin Finck if(GetLocaleInfoA(lcid[MSVCRT_LC_MONETARY], LOCALE_INEGSEPBYSPACE 1072*c2c66affSColin Finck |LOCALE_NOUSEROVERRIDE, buf, 256)) 1073*c2c66affSColin Finck loc->locinfo->lconv->n_sep_by_space = atoi(buf); 1074*c2c66affSColin Finck else { 1075*c2c66affSColin Finck MSVCRT__free_locale(loc); 1076*c2c66affSColin Finck return NULL; 1077*c2c66affSColin Finck } 1078*c2c66affSColin Finck 1079*c2c66affSColin Finck if(GetLocaleInfoA(lcid[MSVCRT_LC_MONETARY], LOCALE_IPOSSIGNPOSN 1080*c2c66affSColin Finck |LOCALE_NOUSEROVERRIDE, buf, 256)) 1081*c2c66affSColin Finck loc->locinfo->lconv->p_sign_posn = atoi(buf); 1082*c2c66affSColin Finck else { 1083*c2c66affSColin Finck MSVCRT__free_locale(loc); 1084*c2c66affSColin Finck return NULL; 1085*c2c66affSColin Finck } 1086*c2c66affSColin Finck 1087*c2c66affSColin Finck if(GetLocaleInfoA(lcid[MSVCRT_LC_MONETARY], LOCALE_INEGSIGNPOSN 1088*c2c66affSColin Finck |LOCALE_NOUSEROVERRIDE, buf, 256)) 1089*c2c66affSColin Finck loc->locinfo->lconv->n_sign_posn = atoi(buf); 1090*c2c66affSColin Finck else { 1091*c2c66affSColin Finck MSVCRT__free_locale(loc); 1092*c2c66affSColin Finck return NULL; 1093*c2c66affSColin Finck } 1094*c2c66affSColin Finck } else { 1095*c2c66affSColin Finck loc->locinfo->lconv->int_curr_symbol = MSVCRT_malloc(sizeof(char)); 1096*c2c66affSColin Finck loc->locinfo->lconv->currency_symbol = MSVCRT_malloc(sizeof(char)); 1097*c2c66affSColin Finck loc->locinfo->lconv->mon_decimal_point = MSVCRT_malloc(sizeof(char)); 1098*c2c66affSColin Finck loc->locinfo->lconv->mon_thousands_sep = MSVCRT_malloc(sizeof(char)); 1099*c2c66affSColin Finck loc->locinfo->lconv->mon_grouping = MSVCRT_malloc(sizeof(char)); 1100*c2c66affSColin Finck loc->locinfo->lconv->positive_sign = MSVCRT_malloc(sizeof(char)); 1101*c2c66affSColin Finck loc->locinfo->lconv->negative_sign = MSVCRT_malloc(sizeof(char)); 1102*c2c66affSColin Finck 1103*c2c66affSColin Finck if(!loc->locinfo->lconv->int_curr_symbol || !loc->locinfo->lconv->currency_symbol 1104*c2c66affSColin Finck || !loc->locinfo->lconv->mon_decimal_point || !loc->locinfo->lconv->mon_thousands_sep 1105*c2c66affSColin Finck || !loc->locinfo->lconv->mon_grouping || !loc->locinfo->lconv->positive_sign 1106*c2c66affSColin Finck || !loc->locinfo->lconv->negative_sign) { 1107*c2c66affSColin Finck MSVCRT__free_locale(loc); 1108*c2c66affSColin Finck return NULL; 1109*c2c66affSColin Finck } 1110*c2c66affSColin Finck 1111*c2c66affSColin Finck loc->locinfo->lconv->int_curr_symbol[0] = '\0'; 1112*c2c66affSColin Finck loc->locinfo->lconv->currency_symbol[0] = '\0'; 1113*c2c66affSColin Finck loc->locinfo->lconv->mon_decimal_point[0] = '\0'; 1114*c2c66affSColin Finck loc->locinfo->lconv->mon_thousands_sep[0] = '\0'; 1115*c2c66affSColin Finck loc->locinfo->lconv->mon_grouping[0] = '\0'; 1116*c2c66affSColin Finck loc->locinfo->lconv->positive_sign[0] = '\0'; 1117*c2c66affSColin Finck loc->locinfo->lconv->negative_sign[0] = '\0'; 1118*c2c66affSColin Finck loc->locinfo->lconv->int_frac_digits = 127; 1119*c2c66affSColin Finck loc->locinfo->lconv->frac_digits = 127; 1120*c2c66affSColin Finck loc->locinfo->lconv->p_cs_precedes = 127; 1121*c2c66affSColin Finck loc->locinfo->lconv->p_sep_by_space = 127; 1122*c2c66affSColin Finck loc->locinfo->lconv->n_cs_precedes = 127; 1123*c2c66affSColin Finck loc->locinfo->lconv->n_sep_by_space = 127; 1124*c2c66affSColin Finck loc->locinfo->lconv->p_sign_posn = 127; 1125*c2c66affSColin Finck loc->locinfo->lconv->n_sign_posn = 127; 1126*c2c66affSColin Finck 1127*c2c66affSColin Finck loc->locinfo->lc_category[LC_MONETARY].locale = _strdup("C"); 1128*c2c66affSColin Finck } 1129*c2c66affSColin Finck 1130*c2c66affSColin Finck if(lcid[MSVCRT_LC_NUMERIC] && (category==MSVCRT_LC_ALL || category==MSVCRT_LC_NUMERIC)) { 1131*c2c66affSColin Finck if(update_threadlocinfo_category(lcid[MSVCRT_LC_NUMERIC], cp[MSVCRT_LC_NUMERIC], loc, MSVCRT_LC_NUMERIC)) { 1132*c2c66affSColin Finck MSVCRT__free_locale(loc); 1133*c2c66affSColin Finck return NULL; 1134*c2c66affSColin Finck } 1135*c2c66affSColin Finck 1136*c2c66affSColin Finck if(!loc->locinfo->lconv_intl_refcount) 1137*c2c66affSColin Finck loc->locinfo->lconv_intl_refcount = MSVCRT_malloc(sizeof(int)); 1138*c2c66affSColin Finck loc->locinfo->lconv_num_refcount = MSVCRT_malloc(sizeof(int)); 1139*c2c66affSColin Finck if(!loc->locinfo->lconv_intl_refcount || !loc->locinfo->lconv_num_refcount) { 1140*c2c66affSColin Finck MSVCRT__free_locale(loc); 1141*c2c66affSColin Finck return NULL; 1142*c2c66affSColin Finck } 1143*c2c66affSColin Finck 1144*c2c66affSColin Finck *loc->locinfo->lconv_intl_refcount = 1; 1145*c2c66affSColin Finck *loc->locinfo->lconv_num_refcount = 1; 1146*c2c66affSColin Finck 1147*c2c66affSColin Finck i = GetLocaleInfoA(lcid[MSVCRT_LC_NUMERIC], LOCALE_SDECIMAL 1148*c2c66affSColin Finck |LOCALE_NOUSEROVERRIDE, buf, 256); 1149*c2c66affSColin Finck if(i && (loc->locinfo->lconv->decimal_point = MSVCRT_malloc(i))) 1150*c2c66affSColin Finck memcpy(loc->locinfo->lconv->decimal_point, buf, i); 1151*c2c66affSColin Finck else { 1152*c2c66affSColin Finck MSVCRT__free_locale(loc); 1153*c2c66affSColin Finck return NULL; 1154*c2c66affSColin Finck } 1155*c2c66affSColin Finck 1156*c2c66affSColin Finck i = GetLocaleInfoA(lcid[MSVCRT_LC_NUMERIC], LOCALE_STHOUSAND 1157*c2c66affSColin Finck |LOCALE_NOUSEROVERRIDE, buf, 256); 1158*c2c66affSColin Finck if(i && (loc->locinfo->lconv->thousands_sep = MSVCRT_malloc(i))) 1159*c2c66affSColin Finck memcpy(loc->locinfo->lconv->thousands_sep, buf, i); 1160*c2c66affSColin Finck else { 1161*c2c66affSColin Finck MSVCRT__free_locale(loc); 1162*c2c66affSColin Finck return NULL; 1163*c2c66affSColin Finck } 1164*c2c66affSColin Finck 1165*c2c66affSColin Finck i = GetLocaleInfoA(lcid[MSVCRT_LC_NUMERIC], LOCALE_SGROUPING 1166*c2c66affSColin Finck |LOCALE_NOUSEROVERRIDE, buf, 256); 1167*c2c66affSColin Finck if(i>1) 1168*c2c66affSColin Finck i = i/2 + (buf[i-2]=='0'?0:1); 1169*c2c66affSColin Finck if(i && (loc->locinfo->lconv->grouping = MSVCRT_malloc(i))) { 1170*c2c66affSColin Finck for(i=0; buf[i+1]==';'; i+=2) 1171*c2c66affSColin Finck loc->locinfo->lconv->grouping[i/2] = buf[i]-'0'; 1172*c2c66affSColin Finck loc->locinfo->lconv->grouping[i/2] = buf[i]-'0'; 1173*c2c66affSColin Finck if(buf[i] != '0') 1174*c2c66affSColin Finck loc->locinfo->lconv->grouping[i/2+1] = 127; 1175*c2c66affSColin Finck } else { 1176*c2c66affSColin Finck MSVCRT__free_locale(loc); 1177*c2c66affSColin Finck return NULL; 1178*c2c66affSColin Finck } 1179*c2c66affSColin Finck } else { 1180*c2c66affSColin Finck loc->locinfo->lconv->decimal_point = MSVCRT_malloc(sizeof(char[2])); 1181*c2c66affSColin Finck loc->locinfo->lconv->thousands_sep = MSVCRT_malloc(sizeof(char)); 1182*c2c66affSColin Finck loc->locinfo->lconv->grouping = MSVCRT_malloc(sizeof(char)); 1183*c2c66affSColin Finck if(!loc->locinfo->lconv->decimal_point || !loc->locinfo->lconv->thousands_sep 1184*c2c66affSColin Finck || !loc->locinfo->lconv->grouping) { 1185*c2c66affSColin Finck MSVCRT__free_locale(loc); 1186*c2c66affSColin Finck return NULL; 1187*c2c66affSColin Finck } 1188*c2c66affSColin Finck 1189*c2c66affSColin Finck loc->locinfo->lconv->decimal_point[0] = '.'; 1190*c2c66affSColin Finck loc->locinfo->lconv->decimal_point[1] = '\0'; 1191*c2c66affSColin Finck loc->locinfo->lconv->thousands_sep[0] = '\0'; 1192*c2c66affSColin Finck loc->locinfo->lconv->grouping[0] = '\0'; 1193*c2c66affSColin Finck 1194*c2c66affSColin Finck loc->locinfo->lc_category[LC_NUMERIC].locale = _strdup("C"); 1195*c2c66affSColin Finck } 1196*c2c66affSColin Finck 1197*c2c66affSColin Finck if(lcid[MSVCRT_LC_TIME] && (category==MSVCRT_LC_ALL || category==MSVCRT_LC_TIME)) { 1198*c2c66affSColin Finck if(update_threadlocinfo_category(lcid[MSVCRT_LC_TIME], cp[MSVCRT_LC_TIME], loc, MSVCRT_LC_TIME)) { 1199*c2c66affSColin Finck MSVCRT__free_locale(loc); 1200*c2c66affSColin Finck return NULL; 1201*c2c66affSColin Finck } 1202*c2c66affSColin Finck } else 1203*c2c66affSColin Finck loc->locinfo->lc_category[LC_TIME].locale = _strdup("C"); 1204*c2c66affSColin Finck 1205*c2c66affSColin Finck size = sizeof(MSVCRT___lc_time_data); 1206*c2c66affSColin Finck lcid_tmp = lcid[MSVCRT_LC_TIME] ? lcid[MSVCRT_LC_TIME] : MAKELCID(LANG_ENGLISH, SORT_DEFAULT); 1207*c2c66affSColin Finck for(i=0; i<sizeof(time_data)/sizeof(time_data[0]); i++) { 1208*c2c66affSColin Finck if(time_data[i]==LOCALE_SSHORTDATE && !lcid[MSVCRT_LC_TIME]) { 1209*c2c66affSColin Finck size += sizeof(cloc_short_date) + sizeof(cloc_short_dateW); 1210*c2c66affSColin Finck }else if(time_data[i]==LOCALE_SLONGDATE && !lcid[MSVCRT_LC_TIME]) { 1211*c2c66affSColin Finck size += sizeof(cloc_long_date) + sizeof(cloc_long_dateW); 1212*c2c66affSColin Finck }else { 1213*c2c66affSColin Finck ret = GetLocaleInfoA(lcid_tmp, time_data[i] 1214*c2c66affSColin Finck |LOCALE_NOUSEROVERRIDE, NULL, 0); 1215*c2c66affSColin Finck if(!ret) { 1216*c2c66affSColin Finck MSVCRT__free_locale(loc); 1217*c2c66affSColin Finck return NULL; 1218*c2c66affSColin Finck } 1219*c2c66affSColin Finck size += ret; 1220*c2c66affSColin Finck 1221*c2c66affSColin Finck ret = GetLocaleInfoW(lcid_tmp, time_data[i] 1222*c2c66affSColin Finck |LOCALE_NOUSEROVERRIDE, NULL, 0); 1223*c2c66affSColin Finck if(!ret) { 1224*c2c66affSColin Finck MSVCRT__free_locale(loc); 1225*c2c66affSColin Finck return NULL; 1226*c2c66affSColin Finck } 1227*c2c66affSColin Finck size += ret*sizeof(wchar_t); 1228*c2c66affSColin Finck } 1229*c2c66affSColin Finck } 1230*c2c66affSColin Finck 1231*c2c66affSColin Finck loc->locinfo->lc_time_curr = MSVCRT_malloc(size); 1232*c2c66affSColin Finck if(!loc->locinfo->lc_time_curr) { 1233*c2c66affSColin Finck MSVCRT__free_locale(loc); 1234*c2c66affSColin Finck return NULL; 1235*c2c66affSColin Finck } 1236*c2c66affSColin Finck 1237*c2c66affSColin Finck ret = 0; 1238*c2c66affSColin Finck for(i=0; i<sizeof(time_data)/sizeof(time_data[0]); i++) { 1239*c2c66affSColin Finck loc->locinfo->lc_time_curr->str.str[i] = &loc->locinfo->lc_time_curr->data[ret]; 1240*c2c66affSColin Finck if(time_data[i]==LOCALE_SSHORTDATE && !lcid[MSVCRT_LC_TIME]) { 1241*c2c66affSColin Finck memcpy(&loc->locinfo->lc_time_curr->data[ret], cloc_short_date, sizeof(cloc_short_date)); 1242*c2c66affSColin Finck ret += sizeof(cloc_short_date); 1243*c2c66affSColin Finck }else if(time_data[i]==LOCALE_SLONGDATE && !lcid[MSVCRT_LC_TIME]) { 1244*c2c66affSColin Finck memcpy(&loc->locinfo->lc_time_curr->data[ret], cloc_long_date, sizeof(cloc_long_date)); 1245*c2c66affSColin Finck ret += sizeof(cloc_long_date); 1246*c2c66affSColin Finck }else if(time_data[i]==LOCALE_STIMEFORMAT && !lcid[MSVCRT_LC_TIME]) { 1247*c2c66affSColin Finck memcpy(&loc->locinfo->lc_time_curr->data[ret], cloc_time, sizeof(cloc_time)); 1248*c2c66affSColin Finck ret += sizeof(cloc_time); 1249*c2c66affSColin Finck }else { 1250*c2c66affSColin Finck ret += GetLocaleInfoA(lcid_tmp, time_data[i]|LOCALE_NOUSEROVERRIDE, 1251*c2c66affSColin Finck &loc->locinfo->lc_time_curr->data[ret], size-ret); 1252*c2c66affSColin Finck } 1253*c2c66affSColin Finck } 1254*c2c66affSColin Finck for(i=0; i<sizeof(time_data)/sizeof(time_data[0]); i++) { 1255*c2c66affSColin Finck loc->locinfo->lc_time_curr->wstr[i] = (wchar_t*)&loc->locinfo->lc_time_curr->data[ret]; 1256*c2c66affSColin Finck if(time_data[i]==LOCALE_SSHORTDATE && !lcid[MSVCRT_LC_TIME]) { 1257*c2c66affSColin Finck memcpy(&loc->locinfo->lc_time_curr->data[ret], cloc_short_dateW, sizeof(cloc_short_dateW)); 1258*c2c66affSColin Finck ret += sizeof(cloc_short_dateW); 1259*c2c66affSColin Finck }else if(time_data[i]==LOCALE_SLONGDATE && !lcid[MSVCRT_LC_TIME]) { 1260*c2c66affSColin Finck memcpy(&loc->locinfo->lc_time_curr->data[ret], cloc_long_dateW, sizeof(cloc_long_dateW)); 1261*c2c66affSColin Finck ret += sizeof(cloc_long_dateW); 1262*c2c66affSColin Finck }else if(time_data[i]==LOCALE_STIMEFORMAT && !lcid[MSVCRT_LC_TIME]) { memcpy(&loc->locinfo->lc_time_curr->data[ret], cloc_timeW, sizeof(cloc_timeW)); 1263*c2c66affSColin Finck ret += sizeof(cloc_timeW); 1264*c2c66affSColin Finck }else { 1265*c2c66affSColin Finck ret += GetLocaleInfoW(lcid_tmp, time_data[i]|LOCALE_NOUSEROVERRIDE, 1266*c2c66affSColin Finck (wchar_t*)&loc->locinfo->lc_time_curr->data[ret], size-ret)*sizeof(wchar_t); 1267*c2c66affSColin Finck } 1268*c2c66affSColin Finck } 1269*c2c66affSColin Finck loc->locinfo->lc_time_curr->lcid = lcid[MSVCRT_LC_TIME]; 1270*c2c66affSColin Finck 1271*c2c66affSColin Finck return loc; 1272*c2c66affSColin Finck } 1273*c2c66affSColin Finck 1274*c2c66affSColin Finck /********************************************************************* 1275*c2c66affSColin Finck * setlocale (MSVCRT.@) 1276*c2c66affSColin Finck */ 1277*c2c66affSColin Finck char* CDECL setlocale(int category, const char* locale) 1278*c2c66affSColin Finck { 1279*c2c66affSColin Finck MSVCRT__locale_t loc; 1280*c2c66affSColin Finck MSVCRT_pthreadlocinfo locinfo = get_locinfo(); 1281*c2c66affSColin Finck 1282*c2c66affSColin Finck if(category<MSVCRT_LC_MIN || category>MSVCRT_LC_MAX) 1283*c2c66affSColin Finck return NULL; 1284*c2c66affSColin Finck 1285*c2c66affSColin Finck if(!locale) { 1286*c2c66affSColin Finck if(category == MSVCRT_LC_ALL) 1287*c2c66affSColin Finck return construct_lc_all(locinfo); 1288*c2c66affSColin Finck 1289*c2c66affSColin Finck return locinfo->lc_category[category].locale; 1290*c2c66affSColin Finck } 1291*c2c66affSColin Finck 1292*c2c66affSColin Finck loc = MSVCRT__create_locale(category, locale); 1293*c2c66affSColin Finck if(!loc) { 1294*c2c66affSColin Finck WARN("%d %s failed\n", category, locale); 1295*c2c66affSColin Finck return NULL; 1296*c2c66affSColin Finck } 1297*c2c66affSColin Finck 1298*c2c66affSColin Finck LOCK_LOCALE; 1299*c2c66affSColin Finck 1300*c2c66affSColin Finck switch(category) { 1301*c2c66affSColin Finck case MSVCRT_LC_ALL: 1302*c2c66affSColin Finck case MSVCRT_LC_COLLATE: 1303*c2c66affSColin Finck locinfo->lc_collate_cp = loc->locinfo->lc_collate_cp; 1304*c2c66affSColin Finck locinfo->lc_handle[MSVCRT_LC_COLLATE] = 1305*c2c66affSColin Finck loc->locinfo->lc_handle[MSVCRT_LC_COLLATE]; 1306*c2c66affSColin Finck swap_pointers((void**)&locinfo->lc_category[MSVCRT_LC_COLLATE].locale, 1307*c2c66affSColin Finck (void**)&loc->locinfo->lc_category[MSVCRT_LC_COLLATE].locale); 1308*c2c66affSColin Finck swap_pointers((void**)&locinfo->lc_category[MSVCRT_LC_COLLATE].refcount, 1309*c2c66affSColin Finck (void**)&loc->locinfo->lc_category[MSVCRT_LC_COLLATE].refcount); 1310*c2c66affSColin Finck 1311*c2c66affSColin Finck if(category != MSVCRT_LC_ALL) 1312*c2c66affSColin Finck break; 1313*c2c66affSColin Finck /* fall through */ 1314*c2c66affSColin Finck case MSVCRT_LC_CTYPE: 1315*c2c66affSColin Finck locinfo->lc_handle[MSVCRT_LC_CTYPE] = 1316*c2c66affSColin Finck loc->locinfo->lc_handle[MSVCRT_LC_CTYPE]; 1317*c2c66affSColin Finck swap_pointers((void**)&locinfo->lc_category[MSVCRT_LC_CTYPE].locale, 1318*c2c66affSColin Finck (void**)&loc->locinfo->lc_category[MSVCRT_LC_CTYPE].locale); 1319*c2c66affSColin Finck swap_pointers((void**)&locinfo->lc_category[MSVCRT_LC_CTYPE].refcount, 1320*c2c66affSColin Finck (void**)&loc->locinfo->lc_category[MSVCRT_LC_CTYPE].refcount); 1321*c2c66affSColin Finck 1322*c2c66affSColin Finck locinfo->lc_codepage = loc->locinfo->lc_codepage; 1323*c2c66affSColin Finck locinfo->lc_clike = loc->locinfo->lc_clike; 1324*c2c66affSColin Finck locinfo->mb_cur_max = loc->locinfo->mb_cur_max; 1325*c2c66affSColin Finck 1326*c2c66affSColin Finck swap_pointers((void**)&locinfo->ctype1_refcount, 1327*c2c66affSColin Finck (void**)&loc->locinfo->ctype1_refcount); 1328*c2c66affSColin Finck swap_pointers((void**)&locinfo->ctype1, (void**)&loc->locinfo->ctype1); 1329*c2c66affSColin Finck swap_pointers((void**)&locinfo->pctype, (void**)&loc->locinfo->pctype); 1330*c2c66affSColin Finck swap_pointers((void**)&locinfo->pclmap, (void**)&loc->locinfo->pclmap); 1331*c2c66affSColin Finck swap_pointers((void**)&locinfo->pcumap, (void**)&loc->locinfo->pcumap); 1332*c2c66affSColin Finck 1333*c2c66affSColin Finck if(category != MSVCRT_LC_ALL) 1334*c2c66affSColin Finck break; 1335*c2c66affSColin Finck /* fall through */ 1336*c2c66affSColin Finck case MSVCRT_LC_MONETARY: 1337*c2c66affSColin Finck locinfo->lc_handle[MSVCRT_LC_MONETARY] = 1338*c2c66affSColin Finck loc->locinfo->lc_handle[MSVCRT_LC_MONETARY]; 1339*c2c66affSColin Finck swap_pointers((void**)&locinfo->lc_category[MSVCRT_LC_MONETARY].locale, 1340*c2c66affSColin Finck (void**)&loc->locinfo->lc_category[MSVCRT_LC_MONETARY].locale); 1341*c2c66affSColin Finck swap_pointers((void**)&locinfo->lc_category[MSVCRT_LC_MONETARY].refcount, 1342*c2c66affSColin Finck (void**)&loc->locinfo->lc_category[MSVCRT_LC_MONETARY].refcount); 1343*c2c66affSColin Finck 1344*c2c66affSColin Finck swap_pointers((void**)&locinfo->lconv->int_curr_symbol, 1345*c2c66affSColin Finck (void**)&loc->locinfo->lconv->int_curr_symbol); 1346*c2c66affSColin Finck swap_pointers((void**)&locinfo->lconv->currency_symbol, 1347*c2c66affSColin Finck (void**)&loc->locinfo->lconv->currency_symbol); 1348*c2c66affSColin Finck swap_pointers((void**)&locinfo->lconv->mon_decimal_point, 1349*c2c66affSColin Finck (void**)&loc->locinfo->lconv->mon_decimal_point); 1350*c2c66affSColin Finck swap_pointers((void**)&locinfo->lconv->mon_thousands_sep, 1351*c2c66affSColin Finck (void**)&loc->locinfo->lconv->mon_thousands_sep); 1352*c2c66affSColin Finck swap_pointers((void**)&locinfo->lconv->mon_grouping, 1353*c2c66affSColin Finck (void**)&loc->locinfo->lconv->mon_grouping); 1354*c2c66affSColin Finck swap_pointers((void**)&locinfo->lconv->positive_sign, 1355*c2c66affSColin Finck (void**)&loc->locinfo->lconv->positive_sign); 1356*c2c66affSColin Finck swap_pointers((void**)&locinfo->lconv->negative_sign, 1357*c2c66affSColin Finck (void**)&loc->locinfo->lconv->negative_sign); 1358*c2c66affSColin Finck locinfo->lconv->int_frac_digits = loc->locinfo->lconv->int_frac_digits; 1359*c2c66affSColin Finck locinfo->lconv->frac_digits = loc->locinfo->lconv->frac_digits; 1360*c2c66affSColin Finck locinfo->lconv->p_cs_precedes = loc->locinfo->lconv->p_cs_precedes; 1361*c2c66affSColin Finck locinfo->lconv->p_sep_by_space = loc->locinfo->lconv->p_sep_by_space; 1362*c2c66affSColin Finck locinfo->lconv->n_cs_precedes = loc->locinfo->lconv->n_cs_precedes; 1363*c2c66affSColin Finck locinfo->lconv->n_sep_by_space = loc->locinfo->lconv->n_sep_by_space; 1364*c2c66affSColin Finck locinfo->lconv->p_sign_posn = loc->locinfo->lconv->p_sign_posn; 1365*c2c66affSColin Finck locinfo->lconv->n_sign_posn = loc->locinfo->lconv->n_sign_posn; 1366*c2c66affSColin Finck 1367*c2c66affSColin Finck if(category != MSVCRT_LC_ALL) 1368*c2c66affSColin Finck break; 1369*c2c66affSColin Finck /* fall through */ 1370*c2c66affSColin Finck case MSVCRT_LC_NUMERIC: 1371*c2c66affSColin Finck locinfo->lc_handle[MSVCRT_LC_NUMERIC] = 1372*c2c66affSColin Finck loc->locinfo->lc_handle[MSVCRT_LC_NUMERIC]; 1373*c2c66affSColin Finck swap_pointers((void**)&locinfo->lc_category[MSVCRT_LC_NUMERIC].locale, 1374*c2c66affSColin Finck (void**)&loc->locinfo->lc_category[MSVCRT_LC_NUMERIC].locale); 1375*c2c66affSColin Finck swap_pointers((void**)&locinfo->lc_category[MSVCRT_LC_NUMERIC].refcount, 1376*c2c66affSColin Finck (void**)&loc->locinfo->lc_category[MSVCRT_LC_NUMERIC].refcount); 1377*c2c66affSColin Finck 1378*c2c66affSColin Finck swap_pointers((void**)&locinfo->lconv->decimal_point, 1379*c2c66affSColin Finck (void**)&loc->locinfo->lconv->decimal_point); 1380*c2c66affSColin Finck swap_pointers((void**)&locinfo->lconv->thousands_sep, 1381*c2c66affSColin Finck (void**)&loc->locinfo->lconv->thousands_sep); 1382*c2c66affSColin Finck swap_pointers((void**)&locinfo->lconv->grouping, 1383*c2c66affSColin Finck (void**)&loc->locinfo->lconv->grouping); 1384*c2c66affSColin Finck 1385*c2c66affSColin Finck if(category != MSVCRT_LC_ALL) 1386*c2c66affSColin Finck break; 1387*c2c66affSColin Finck /* fall through */ 1388*c2c66affSColin Finck case MSVCRT_LC_TIME: 1389*c2c66affSColin Finck locinfo->lc_handle[MSVCRT_LC_TIME] = 1390*c2c66affSColin Finck loc->locinfo->lc_handle[MSVCRT_LC_TIME]; 1391*c2c66affSColin Finck swap_pointers((void**)&locinfo->lc_category[MSVCRT_LC_TIME].locale, 1392*c2c66affSColin Finck (void**)&loc->locinfo->lc_category[MSVCRT_LC_TIME].locale); 1393*c2c66affSColin Finck swap_pointers((void**)&locinfo->lc_category[MSVCRT_LC_TIME].refcount, 1394*c2c66affSColin Finck (void**)&loc->locinfo->lc_category[MSVCRT_LC_TIME].refcount); 1395*c2c66affSColin Finck swap_pointers((void**)&locinfo->lc_time_curr, 1396*c2c66affSColin Finck (void**)&loc->locinfo->lc_time_curr); 1397*c2c66affSColin Finck 1398*c2c66affSColin Finck if(category != MSVCRT_LC_ALL) 1399*c2c66affSColin Finck break; 1400*c2c66affSColin Finck } 1401*c2c66affSColin Finck 1402*c2c66affSColin Finck MSVCRT__free_locale(loc); 1403*c2c66affSColin Finck UNLOCK_LOCALE; 1404*c2c66affSColin Finck 1405*c2c66affSColin Finck if(locinfo == MSVCRT_locale->locinfo) { 1406*c2c66affSColin Finck int i; 1407*c2c66affSColin Finck 1408*c2c66affSColin Finck __lc_codepage = locinfo->lc_codepage; 1409*c2c66affSColin Finck MSVCRT___lc_collate_cp = locinfo->lc_collate_cp; 1410*c2c66affSColin Finck __mb_cur_max = locinfo->mb_cur_max; 1411*c2c66affSColin Finck _pctype = locinfo->pctype; 1412*c2c66affSColin Finck for(i=LC_MIN; i<=LC_MAX; i++) 1413*c2c66affSColin Finck MSVCRT___lc_handle[i] = MSVCRT_locale->locinfo->lc_handle[i]; 1414*c2c66affSColin Finck } 1415*c2c66affSColin Finck 1416*c2c66affSColin Finck if(category == MSVCRT_LC_ALL) 1417*c2c66affSColin Finck return construct_lc_all(locinfo); 1418*c2c66affSColin Finck 1419*c2c66affSColin Finck _Analysis_assume_(category <= 5); 1420*c2c66affSColin Finck return locinfo->lc_category[category].locale; 1421*c2c66affSColin Finck } 1422*c2c66affSColin Finck 1423*c2c66affSColin Finck /* _configthreadlocale - not exported in native msvcrt */ 1424*c2c66affSColin Finck int CDECL _configthreadlocale(int type) 1425*c2c66affSColin Finck { 1426*c2c66affSColin Finck thread_data_t *data = msvcrt_get_thread_data(); 1427*c2c66affSColin Finck MSVCRT__locale_t locale; 1428*c2c66affSColin Finck int ret; 1429*c2c66affSColin Finck 1430*c2c66affSColin Finck if(!data) 1431*c2c66affSColin Finck return -1; 1432*c2c66affSColin Finck 1433*c2c66affSColin Finck ret = (data->have_locale ? _ENABLE_PER_THREAD_LOCALE : _DISABLE_PER_THREAD_LOCALE); 1434*c2c66affSColin Finck 1435*c2c66affSColin Finck if(type == _ENABLE_PER_THREAD_LOCALE) { 1436*c2c66affSColin Finck if(!data->have_locale) { 1437*c2c66affSColin Finck /* Copy current global locale */ 1438*c2c66affSColin Finck locale = MSVCRT__create_locale(LC_ALL, setlocale(LC_ALL, NULL)); 1439*c2c66affSColin Finck if(!locale) 1440*c2c66affSColin Finck return -1; 1441*c2c66affSColin Finck 1442*c2c66affSColin Finck data->locinfo = locale->locinfo; 1443*c2c66affSColin Finck data->mbcinfo = locale->mbcinfo; 1444*c2c66affSColin Finck data->have_locale = TRUE; 1445*c2c66affSColin Finck MSVCRT_free(locale); 1446*c2c66affSColin Finck } 1447*c2c66affSColin Finck 1448*c2c66affSColin Finck return ret; 1449*c2c66affSColin Finck } 1450*c2c66affSColin Finck 1451*c2c66affSColin Finck if(type == _DISABLE_PER_THREAD_LOCALE) { 1452*c2c66affSColin Finck if(data->have_locale) { 1453*c2c66affSColin Finck free_locinfo(data->locinfo); 1454*c2c66affSColin Finck free_mbcinfo(data->mbcinfo); 1455*c2c66affSColin Finck data->locinfo = MSVCRT_locale->locinfo; 1456*c2c66affSColin Finck data->mbcinfo = MSVCRT_locale->mbcinfo; 1457*c2c66affSColin Finck data->have_locale = FALSE; 1458*c2c66affSColin Finck } 1459*c2c66affSColin Finck 1460*c2c66affSColin Finck return ret; 1461*c2c66affSColin Finck } 1462*c2c66affSColin Finck 1463*c2c66affSColin Finck if(!type) 1464*c2c66affSColin Finck return ret; 1465*c2c66affSColin Finck 1466*c2c66affSColin Finck return -1; 1467*c2c66affSColin Finck } 1468*c2c66affSColin Finck 1469*c2c66affSColin Finck /********************************************************************* 1470*c2c66affSColin Finck * _getmbcp (MSVCRT.@) 1471*c2c66affSColin Finck */ 1472*c2c66affSColin Finck int CDECL _getmbcp(void) 1473*c2c66affSColin Finck { 1474*c2c66affSColin Finck return get_mbcinfo()->mbcodepage; 1475*c2c66affSColin Finck } 1476*c2c66affSColin Finck 1477*c2c66affSColin Finck extern unsigned int __setlc_active; 1478*c2c66affSColin Finck /********************************************************************* 1479*c2c66affSColin Finck * ___setlc_active_func (MSVCRT.@) 1480*c2c66affSColin Finck */ 1481*c2c66affSColin Finck unsigned int CDECL ___setlc_active_func(void) 1482*c2c66affSColin Finck { 1483*c2c66affSColin Finck return __setlc_active; 1484*c2c66affSColin Finck } 1485*c2c66affSColin Finck 1486*c2c66affSColin Finck extern unsigned int __unguarded_readlc_active; 1487*c2c66affSColin Finck /********************************************************************* 1488*c2c66affSColin Finck * ___unguarded_readlc_active_add_func (MSVCRT.@) 1489*c2c66affSColin Finck */ 1490*c2c66affSColin Finck unsigned int * CDECL ___unguarded_readlc_active_add_func(void) 1491*c2c66affSColin Finck { 1492*c2c66affSColin Finck return &__unguarded_readlc_active; 1493*c2c66affSColin Finck } 1494*c2c66affSColin Finck 1495*c2c66affSColin Finck MSVCRT__locale_t global_locale = NULL; 1496*c2c66affSColin Finck void __init_global_locale() 1497*c2c66affSColin Finck { 1498*c2c66affSColin Finck unsigned i; 1499*c2c66affSColin Finck 1500*c2c66affSColin Finck LOCK_LOCALE; 1501*c2c66affSColin Finck /* Someone created it before us */ 1502*c2c66affSColin Finck if(global_locale) 1503*c2c66affSColin Finck return; 1504*c2c66affSColin Finck global_locale = MSVCRT__create_locale(0, "C"); 1505*c2c66affSColin Finck 1506*c2c66affSColin Finck __lc_codepage = MSVCRT_locale->locinfo->lc_codepage; 1507*c2c66affSColin Finck MSVCRT___lc_collate_cp = MSVCRT_locale->locinfo->lc_collate_cp; 1508*c2c66affSColin Finck __mb_cur_max = MSVCRT_locale->locinfo->mb_cur_max; 1509*c2c66affSColin Finck for(i=LC_MIN; i<=LC_MAX; i++) 1510*c2c66affSColin Finck MSVCRT___lc_handle[i] = MSVCRT_locale->locinfo->lc_handle[i]; 1511*c2c66affSColin Finck _setmbcp(_MB_CP_ANSI); 1512*c2c66affSColin Finck UNLOCK_LOCALE; 1513*c2c66affSColin Finck } 1514*c2c66affSColin Finck 1515*c2c66affSColin Finck /* 1516*c2c66affSColin Finck * @implemented 1517*c2c66affSColin Finck */ 1518*c2c66affSColin Finck const unsigned short **__p__pctype(void) 1519*c2c66affSColin Finck { 1520*c2c66affSColin Finck return &get_locinfo()->pctype; 1521*c2c66affSColin Finck } 1522*c2c66affSColin Finck 1523*c2c66affSColin Finck const unsigned short* __cdecl __pctype_func(void) 1524*c2c66affSColin Finck { 1525*c2c66affSColin Finck return get_locinfo()->pctype; 1526*c2c66affSColin Finck } 1527*c2c66affSColin Finck 1528