~ [ source navigation ] ~ [ diff markup ] ~ [ identifier search ] ~ [ freetext search ] ~ [ file search ] ~

Wine Cross Reference
wine/dlls/kernel32/locale.c

Version: ~ [ wine-1.0-rc1 ] ~ [ wine-0.9.61 ] ~ [ wine-0.9.60 ] ~ [ wine-0.9.59 ] ~ [ wine-0.9.58 ] ~ [ wine-0.9.57 ] ~ [ wine-0.9.56 ] ~ [ wine-0.9.55 ] ~ [ wine-0.9.54 ] ~ [ wine-0.9.53 ] ~ [ wine-0.9.52 ] ~ [ wine-0.9.51 ] ~ [ wine-0.9.50 ] ~ [ wine-0.9.49 ] ~ [ wine-0.9.48 ] ~ [ wine-0.9.47 ] ~ [ wine-0.9.46 ] ~ [ wine-0.9.45 ] ~ [ wine-0.9.44 ] ~ [ wine-0.9.43 ] ~ [ wine-0.9.42 ] ~ [ wine-0.9.41 ] ~ [ wine-0.9.40 ] ~ [ wine-0.9.39 ] ~ [ wine-0.9.38 ] ~ [ wine-0.9.37 ] ~ [ wine-0.9.36 ] ~ [ wine-0.9.35 ] ~ [ wine-0.9.34 ] ~ [ wine-0.9.33 ] ~ [ wine-0.9.32 ] ~ [ wine-0.9.31 ] ~ [ wine-0.9.30 ] ~ [ wine-0.9.29 ] ~ [ wine-0.9.28 ] ~ [ wine-0.9.27 ] ~ [ wine-0.9.26 ] ~ [ wine-0.9.25 ] ~ [ wine-0.9.24 ] ~ [ wine-0.9.23 ] ~ [ wine-0.9.22 ] ~ [ wine-0.9.21 ] ~ [ wine-0.9.20 ] ~ [ wine-0.9.19 ] ~ [ wine-0.9.18 ] ~ [ wine-0.9.17 ] ~ [ wine-0.9.16 ] ~ [ wine-0.9.15 ] ~ [ wine-0.9.14 ] ~ [ wine-0.9.13 ] ~ [ wine-0.9.12 ] ~ [ wine-0.9.11 ] ~ [ wine-0.9.10 ] ~ [ wine-0.9.9 ] ~ [ wine-0.9.8 ] ~ [ wine-0.9.7 ] ~ [ wine-0.9.6 ] ~ [ wine-0.9.5 ] ~ [ wine-0.9.4 ] ~ [ wine-0.9.3 ] ~ [ wine-0.9.2 ] ~ [ wine-0.9.1 ] ~ [ wine-0.9 ] ~ [ wine20050930 ] ~ [ wine20050830 ] ~ [ wine20050725 ] ~ [ wine20050628 ] ~ [ wine20050524 ] ~ [ wine20050419 ] ~ [ wine20050310 ] ~ [ wine20050211 ] ~ [ wine20050111 ] ~ [ wine20041201 ] ~ [ wine20041019 ] ~ [ wine20040914 ] ~ [ wine20040813 ] ~ [ wine20040716 ] ~ [ wine20040615 ] ~ [ wine20040505 ] ~ [ wine20040408 ] ~ [ wine20040309 ] ~ [ wine20040213 ] ~ [ wine20040121 ] ~ [ wine20031212 ] ~ [ wine20031118 ] ~ [ wine20031016 ] ~ [ wine20030911 ] ~ [ wine20030813 ] ~ [ wine20030709 ] ~ [ wine20030618 ] ~ [ wine20030508 ] ~ [ wine20030408 ] ~ [ wine20030318 ] ~ [ wine20030219 ] ~ [ wine20030115 ] ~ [ wine20021219 ] ~ [ wine20021125 ] ~ [ wine20021031 ] ~ [ wine20021007 ] ~ [ wine20020904 ] ~ [ wine20020804 ] ~ [ wine20020710 ] ~ [ wine20020605 ] ~ [ wine20020509 ] ~ [ wine20020411 ] ~ [ wine20020310 ] ~ [ wine20020228 ] ~ [ wine20011226 ] ~ [ wine20011108 ] ~ [ wine20011004 ] ~ [ wine20010824 ] ~ [ wine20010731 ] ~ [ wine20010629 ] ~ [ wine20010510 ] ~ [ wine20010418 ] ~ [ wine20010326 ] ~ [ wine20010305 ] ~ [ wine20010216 ] ~ [ wine20010112 ] ~ [ wine20001222 ] ~ [ wine20001202 ] ~ [ wine20001026 ] ~ [ wine20001002 ] ~ [ wine20000909 ] ~ [ wine20000821 ] ~ [ wine20000801 ] ~ [ wine20000716 ] ~ [ wine20000326 ] ~ [ wine20000227 ] ~ [ wine20000130 ] ~ [ wine20000109 ] ~

  1 /*
  2  * Locale support
  3  *
  4  * Copyright 1995 Martin von Loewis
  5  * Copyright 1998 David Lee Lambert
  6  * Copyright 2000 Julio César Gázquez
  7  * Copyright 2002 Alexandre Julliard for CodeWeavers
  8  *
  9  * This library is free software; you can redistribute it and/or
 10  * modify it under the terms of the GNU Lesser General Public
 11  * License as published by the Free Software Foundation; either
 12  * version 2.1 of the License, or (at your option) any later version.
 13  *
 14  * This library is distributed in the hope that it will be useful,
 15  * but WITHOUT ANY WARRANTY; without even the implied warranty of
 16  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 17  * Lesser General Public License for more details.
 18  *
 19  * You should have received a copy of the GNU Lesser General Public
 20  * License along with this library; if not, write to the Free Software
 21  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
 22  */
 23 
 24 #include "config.h"
 25 #include "wine/port.h"
 26 
 27 #include <assert.h>
 28 #include <locale.h>
 29 #include <string.h>
 30 #include <stdarg.h>
 31 #include <stdio.h>
 32 #include <ctype.h>
 33 #include <stdlib.h>
 34 
 35 #ifdef __APPLE__
 36 # include <CoreFoundation/CFBundle.h>
 37 # include <CoreFoundation/CFLocale.h>
 38 # include <CoreFoundation/CFString.h>
 39 #endif
 40 
 41 #include "ntstatus.h"
 42 #define WIN32_NO_STATUS
 43 #include "windef.h"
 44 #include "winbase.h"
 45 #include "winuser.h"  /* for RT_STRINGW */
 46 #include "winternl.h"
 47 #include "wine/unicode.h"
 48 #include "winnls.h"
 49 #include "winerror.h"
 50 #include "winver.h"
 51 #include "kernel_private.h"
 52 #include "wine/debug.h"
 53 
 54 WINE_DEFAULT_DEBUG_CHANNEL(nls);
 55 
 56 #define LOCALE_LOCALEINFOFLAGSMASK (LOCALE_NOUSEROVERRIDE|LOCALE_USE_CP_ACP|LOCALE_RETURN_NUMBER)
 57 
 58 /* current code pages */
 59 static const union cptable *ansi_cptable;
 60 static const union cptable *oem_cptable;
 61 static const union cptable *mac_cptable;
 62 static const union cptable *unix_cptable;  /* NULL if UTF8 */
 63 
 64 static HANDLE NLS_RegOpenKey(HANDLE hRootKey, LPCWSTR szKeyName);
 65 
 66 static const WCHAR szNlsKeyName[] = {
 67     'M','a','c','h','i','n','e','\\','S','y','s','t','e','m','\\',
 68     'C','u','r','r','e','n','t','C','o','n','t','r','o','l','S','e','t','\\',
 69     'C','o','n','t','r','o','l','\\','N','l','s','\0'
 70 };
 71 
 72 static const WCHAR szLocaleKeyName[] = {
 73     'M','a','c','h','i','n','e','\\','S','y','s','t','e','m','\\',
 74     'C','u','r','r','e','n','t','C','o','n','t','r','o','l','S','e','t','\\',
 75     'C','o','n','t','r','o','l','\\','N','l','s','\\','L','o','c','a','l','e',0
 76 };
 77 
 78 static const WCHAR szCodepageKeyName[] = {
 79     'M','a','c','h','i','n','e','\\','S','y','s','t','e','m','\\',
 80     'C','u','r','r','e','n','t','C','o','n','t','r','o','l','S','e','t','\\',
 81     'C','o','n','t','r','o','l','\\','N','l','s','\\','C','o','d','e','p','a','g','e',0
 82 };
 83 
 84 static const WCHAR szLangGroupsKeyName[] = {
 85     'M','a','c','h','i','n','e','\\','S','y','s','t','e','m','\\',
 86     'C','u','r','r','e','n','t','C','o','n','t','r','o','l','S','e','t','\\',
 87     'C','o','n','t','r','o','l','\\','N','l','s','\\',
 88     'L','a','n','g','u','a','g','e',' ','G','r','o','u','p','s',0
 89 };
 90 
 91 /* Charset to codepage map, sorted by name. */
 92 static const struct charset_entry
 93 {
 94     const char *charset_name;
 95     UINT        codepage;
 96 } charset_names[] =
 97 {
 98     { "BIG5", 950 },
 99     { "CP1250", 1250 },
100     { "CP1251", 1251 },
101     { "CP1252", 1252 },
102     { "CP1253", 1253 },
103     { "CP1254", 1254 },
104     { "CP1255", 1255 },
105     { "CP1256", 1256 },
106     { "CP1257", 1257 },
107     { "CP1258", 1258 },
108     { "CP932", 932 },
109     { "CP936", 936 },
110     { "CP949", 949 },
111     { "CP950", 950 },
112     { "EUCJP", 20932 },
113     { "GB2312", 936 },
114     { "IBM037", 37 },
115     { "IBM1026", 1026 },
116     { "IBM424", 424 },
117     { "IBM437", 437 },
118     { "IBM500", 500 },
119     { "IBM850", 850 },
120     { "IBM852", 852 },
121     { "IBM855", 855 },
122     { "IBM857", 857 },
123     { "IBM860", 860 },
124     { "IBM861", 861 },
125     { "IBM862", 862 },
126     { "IBM863", 863 },
127     { "IBM864", 864 },
128     { "IBM865", 865 },
129     { "IBM866", 866 },
130     { "IBM869", 869 },
131     { "IBM874", 874 },
132     { "IBM875", 875 },
133     { "ISO88591", 28591 },
134     { "ISO885910", 28600 },
135     { "ISO885913", 28603 },
136     { "ISO885914", 28604 },
137     { "ISO885915", 28605 },
138     { "ISO885916", 28606 },
139     { "ISO88592", 28592 },
140     { "ISO88593", 28593 },
141     { "ISO88594", 28594 },
142     { "ISO88595", 28595 },
143     { "ISO88596", 28596 },
144     { "ISO88597", 28597 },
145     { "ISO88598", 28598 },
146     { "ISO88599", 28599 },
147     { "KOI8R", 20866 },
148     { "KOI8U", 21866 },
149     { "UTF8", CP_UTF8 }
150 };
151 
152 
153 struct locale_name
154 {
155     WCHAR  win_name[128];   /* Windows name ("en-US") */
156     WCHAR  lang[128];       /* language ("en") (note: buffer contains the other strings too) */
157     WCHAR *country;         /* country ("US") */
158     WCHAR *charset;         /* charset ("UTF-8") for Unix format only */
159     WCHAR *script;          /* script ("Latn") for Windows format only */
160     WCHAR *modifier;        /* modifier or sort order */
161     LCID   lcid;            /* corresponding LCID */
162     int    matches;         /* number of elements matching LCID (0..4) */
163     UINT   codepage;        /* codepage corresponding to charset */
164 };
165 
166 /* locale ids corresponding to the various Unix locale parameters */
167 static LCID lcid_LC_COLLATE;
168 static LCID lcid_LC_CTYPE;
169 static LCID lcid_LC_MESSAGES;
170 static LCID lcid_LC_MONETARY;
171 static LCID lcid_LC_NUMERIC;
172 static LCID lcid_LC_TIME;
173 static LCID lcid_LC_PAPER;
174 static LCID lcid_LC_MEASUREMENT;
175 static LCID lcid_LC_TELEPHONE;
176 
177 /* Copy Ascii string to Unicode without using codepages */
178 static inline void strcpynAtoW( WCHAR *dst, const char *src, size_t n )
179 {
180     while (n > 1 && *src)
181     {
182         *dst++ = (unsigned char)*src++;
183         n--;
184     }
185     if (n) *dst = 0;
186 }
187 
188 
189 /***********************************************************************
190  *              get_lcid_codepage
191  *
192  * Retrieve the ANSI codepage for a given locale.
193  */
194 static inline UINT get_lcid_codepage( LCID lcid )
195 {
196     UINT ret;
197     if (!GetLocaleInfoW( lcid, LOCALE_IDEFAULTANSICODEPAGE|LOCALE_RETURN_NUMBER, (WCHAR *)&ret,
198                          sizeof(ret)/sizeof(WCHAR) )) ret = 0;
199     return ret;
200 }
201 
202 
203 /***********************************************************************
204  *              get_codepage_table
205  *
206  * Find the table for a given codepage, handling CP_ACP etc. pseudo-codepages
207  */
208 static const union cptable *get_codepage_table( unsigned int codepage )
209 {
210     const union cptable *ret = NULL;
211 
212     assert( ansi_cptable );  /* init must have been done already */
213 
214     switch(codepage)
215     {
216     case CP_ACP:
217         return ansi_cptable;
218     case CP_OEMCP:
219         return oem_cptable;
220     case CP_MACCP:
221         return mac_cptable;
222     case CP_UTF7:
223     case CP_UTF8:
224         break;
225     case CP_THREAD_ACP:
226         if (!(codepage = kernel_get_thread_data()->code_page)) return ansi_cptable;
227         /* fall through */
228     default:
229         if (codepage == ansi_cptable->info.codepage) return ansi_cptable;
230         if (codepage == oem_cptable->info.codepage) return oem_cptable;
231         if (codepage == mac_cptable->info.codepage) return mac_cptable;
232         ret = wine_cp_get_table( codepage );
233         break;
234     }
235     return ret;
236 }
237 
238 
239 /***********************************************************************
240  *              charset_cmp (internal)
241  */
242 static int charset_cmp( const void *name, const void *entry )
243 {
244     const struct charset_entry *charset = (const struct charset_entry *)entry;
245     return strcasecmp( (const char *)name, charset->charset_name );
246 }
247 
248 /***********************************************************************
249  *              find_charset
250  */
251 static UINT find_charset( const WCHAR *name )
252 {
253     const struct charset_entry *entry;
254     char charset_name[16];
255     size_t i, j;
256 
257     /* remove punctuation characters from charset name */
258     for (i = j = 0; name[i] && j < sizeof(charset_name)-1; i++)
259         if (isalnum((unsigned char)name[i])) charset_name[j++] = name[i];
260     charset_name[j] = 0;
261 
262     entry = bsearch( charset_name, charset_names,
263                      sizeof(charset_names)/sizeof(charset_names[0]),
264                      sizeof(charset_names[0]), charset_cmp );
265     if (entry) return entry->codepage;
266     return 0;
267 }
268 
269 
270 /***********************************************************************
271  *           find_locale_id_callback
272  */
273 static BOOL CALLBACK find_locale_id_callback( HMODULE hModule, LPCWSTR type,
274                                               LPCWSTR name, WORD LangID, LPARAM lParam )
275 {
276     struct locale_name *data = (struct locale_name *)lParam;
277     WCHAR buffer[128];
278     int matches = 0;
279     LCID lcid = MAKELCID( LangID, SORT_DEFAULT );  /* FIXME: handle sort order */
280 
281     if (PRIMARYLANGID(LangID) == LANG_NEUTRAL) return TRUE; /* continue search */
282 
283     /* first check exact name */
284     if (data->win_name[0] &&
285         GetLocaleInfoW( lcid, LOCALE_SNAME | LOCALE_NOUSEROVERRIDE,
286                         buffer, sizeof(buffer)/sizeof(WCHAR) ))
287     {
288         if (!strcmpW( data->win_name, buffer ))
289         {
290             matches = 4;  /* everything matches */
291             goto done;
292         }
293     }
294 
295     if (!GetLocaleInfoW( lcid, LOCALE_SISO639LANGNAME | LOCALE_NOUSEROVERRIDE,
296                          buffer, sizeof(buffer)/sizeof(WCHAR) ))
297         return TRUE;
298     if (strcmpW( buffer, data->lang )) return TRUE;
299     matches++;  /* language name matched */
300 
301     if (data->country)
302     {
303         if (GetLocaleInfoW( lcid, LOCALE_SISO3166CTRYNAME|LOCALE_NOUSEROVERRIDE,
304                             buffer, sizeof(buffer)/sizeof(WCHAR) ))
305         {
306             if (strcmpW( buffer, data->country )) goto done;
307             matches++;  /* country name matched */
308         }
309     }
310     else  /* match default language */
311     {
312         if (SUBLANGID(LangID) == SUBLANG_DEFAULT) matches++;
313     }
314 
315     if (data->codepage)
316     {
317         UINT unix_cp;
318         if (GetLocaleInfoW( lcid, LOCALE_IDEFAULTUNIXCODEPAGE | LOCALE_RETURN_NUMBER,
319                             (LPWSTR)&unix_cp, sizeof(unix_cp)/sizeof(WCHAR) ))
320         {
321             if (unix_cp == data->codepage) matches++;
322         }
323     }
324 
325     /* FIXME: check sort order */
326 
327 done:
328     if (matches > data->matches)
329     {
330         data->lcid = lcid;
331         data->matches = matches;
332     }
333     return (data->matches < 4);  /* no need to continue for perfect match */
334 }
335 
336 
337 /***********************************************************************
338  *              parse_locale_name
339  *
340  * Parse a locale name into a struct locale_name, handling both Windows and Unix formats.
341  * Unix format is: lang[_country][.charset][@modifier]
342  * Windows format is: lang[-script][-country][_modifier]
343  */
344 static void parse_locale_name( const WCHAR *str, struct locale_name *name )
345 {
346     static const WCHAR sepW[] = {'-','_','.','@',0};
347     static const WCHAR winsepW[] = {'-','_',0};
348     static const WCHAR posixW[] = {'P','O','S','I','X',0};
349     static const WCHAR cW[] = {'C',0};
350     static const WCHAR latinW[] = {'l','a','t','i','n',0};
351     static const WCHAR latnW[] = {'-','L','a','t','n',0};
352     WCHAR *p;
353 
354     TRACE("%s\n", debugstr_w(str));
355 
356     name->country = name->charset = name->script = name->modifier = NULL;
357     name->lcid = MAKELCID( MAKELANGID(LANG_ENGLISH,SUBLANG_DEFAULT), SORT_DEFAULT );
358     name->matches = 0;
359     name->codepage = 0;
360     name->win_name[0] = 0;
361     lstrcpynW( name->lang, str, sizeof(name->lang)/sizeof(WCHAR) );
362 
363     if (!(p = strpbrkW( name->lang, sepW )))
364     {
365         if (!strcmpW( name->lang, posixW ) || !strcmpW( name->lang, cW ))
366         {
367             name->matches = 4;  /* perfect match for default English lcid */
368             return;
369         }
370         strcpyW( name->win_name, name->lang );
371     }
372     else if (*p == '-')  /* Windows format */
373     {
374         strcpyW( name->win_name, name->lang );
375         *p++ = 0;
376         name->country = p;
377         if (!(p = strpbrkW( p, winsepW ))) goto done;
378         if (*p == '-')
379         {
380             *p++ = 0;
381             name->script = name->country;
382             name->country = p;
383             if (!(p = strpbrkW( p, winsepW ))) goto done;
384         }
385         *p++ = 0;
386         name->modifier = p;
387     }
388     else  /* Unix format */
389     {
390         if (*p == '_')
391         {
392             *p++ = 0;
393             name->country = p;
394             p = strpbrkW( p, sepW + 2 );
395         }
396         if (p && *p == '.')
397         {
398             *p++ = 0;
399             name->charset = p;
400             p = strchrW( p, '@' );
401         }
402         if (p)
403         {
404             *p++ = 0;
405             name->modifier = p;
406         }
407 
408         if (name->charset)
409             name->codepage = find_charset( name->charset );
410 
411         /* rebuild a Windows name if possible */
412 
413         if (name->charset) goto done;  /* can't specify charset in Windows format */
414         if (name->modifier && strcmpW( name->modifier, latinW ))
415             goto done;  /* only Latn script supported for now */
416         strcpyW( name->win_name, name->lang );
417         if (name->modifier) strcatW( name->win_name, latnW );
418         if (name->country)
419         {
420             p = name->win_name + strlenW(name->win_name);
421             *p++ = '-';
422             strcpyW( p, name->country );
423         }
424     }
425 done:
426     EnumResourceLanguagesW( kernel32_handle, (LPCWSTR)RT_STRING, (LPCWSTR)LOCALE_ILANGUAGE,
427                             find_locale_id_callback, (LPARAM)name );
428 }
429 
430 
431 /***********************************************************************
432  *           convert_default_lcid
433  *
434  * Get the default LCID to use for a given lctype in GetLocaleInfo.
435  */
436 static LCID convert_default_lcid( LCID lcid, LCTYPE lctype )
437 {
438     if (lcid == LOCALE_SYSTEM_DEFAULT ||
439         lcid == LOCALE_USER_DEFAULT ||
440         lcid == LOCALE_NEUTRAL)
441     {
442         LCID default_id = 0;
443 
444         switch(lctype & 0xffff)
445         {
446         case LOCALE_SSORTNAME:
447             default_id = lcid_LC_COLLATE;
448             break;
449 
450         case LOCALE_FONTSIGNATURE:
451         case LOCALE_IDEFAULTANSICODEPAGE:
452         case LOCALE_IDEFAULTCODEPAGE:
453         case LOCALE_IDEFAULTEBCDICCODEPAGE:
454         case LOCALE_IDEFAULTMACCODEPAGE:
455         case LOCALE_IDEFAULTUNIXCODEPAGE:
456             default_id = lcid_LC_CTYPE;
457             break;
458 
459         case LOCALE_ICURRDIGITS:
460         case LOCALE_ICURRENCY:
461         case LOCALE_IINTLCURRDIGITS:
462         case LOCALE_INEGCURR:
463         case LOCALE_INEGSEPBYSPACE:
464         case LOCALE_INEGSIGNPOSN:
465         case LOCALE_INEGSYMPRECEDES:
466         case LOCALE_IPOSSEPBYSPACE:
467         case LOCALE_IPOSSIGNPOSN:
468         case LOCALE_IPOSSYMPRECEDES:
469         case LOCALE_SCURRENCY:
470         case LOCALE_SINTLSYMBOL:
471         case LOCALE_SMONDECIMALSEP:
472         case LOCALE_SMONGROUPING:
473         case LOCALE_SMONTHOUSANDSEP:
474         case LOCALE_SNATIVECURRNAME:
475             default_id = lcid_LC_MONETARY;
476             break;
477 
478         case LOCALE_IDIGITS:
479         case LOCALE_IDIGITSUBSTITUTION:
480         case LOCALE_ILZERO:
481         case LOCALE_INEGNUMBER:
482         case LOCALE_SDECIMAL:
483         case LOCALE_SGROUPING:
484         case LOCALE_SNAN:
485         case LOCALE_SNATIVEDIGITS:
486         case LOCALE_SNEGATIVESIGN:
487         case LOCALE_SNEGINFINITY:
488         case LOCALE_SPOSINFINITY:
489         case LOCALE_SPOSITIVESIGN:
490         case LOCALE_STHOUSAND:
491             default_id = lcid_LC_NUMERIC;
492             break;
493 
494         case LOCALE_ICALENDARTYPE:
495         case LOCALE_ICENTURY:
496         case LOCALE_IDATE:
497         case LOCALE_IDAYLZERO:
498         case LOCALE_IFIRSTDAYOFWEEK:
499         case LOCALE_IFIRSTWEEKOFYEAR:
500         case LOCALE_ILDATE:
501         case LOCALE_IMONLZERO:
502         case LOCALE_IOPTIONALCALENDAR:
503         case LOCALE_ITIME:
504         case LOCALE_ITIMEMARKPOSN:
505         case LOCALE_ITLZERO:
506         case LOCALE_S1159:
507         case LOCALE_S2359:
508         case LOCALE_SABBREVDAYNAME1:
509         case LOCALE_SABBREVDAYNAME2:
510         case LOCALE_SABBREVDAYNAME3:
511         case LOCALE_SABBREVDAYNAME4:
512         case LOCALE_SABBREVDAYNAME5:
513         case LOCALE_SABBREVDAYNAME6:
514         case LOCALE_SABBREVDAYNAME7:
515         case LOCALE_SABBREVMONTHNAME1:
516         case LOCALE_SABBREVMONTHNAME2:
517         case LOCALE_SABBREVMONTHNAME3:
518         case LOCALE_SABBREVMONTHNAME4:
519         case LOCALE_SABBREVMONTHNAME5:
520         case LOCALE_SABBREVMONTHNAME6:
521         case LOCALE_SABBREVMONTHNAME7:
522         case LOCALE_SABBREVMONTHNAME8:
523         case LOCALE_SABBREVMONTHNAME9:
524         case LOCALE_SABBREVMONTHNAME10:
525         case LOCALE_SABBREVMONTHNAME11:
526         case LOCALE_SABBREVMONTHNAME12:
527         case LOCALE_SABBREVMONTHNAME13:
528         case LOCALE_SDATE:
529         case LOCALE_SDAYNAME1:
530         case LOCALE_SDAYNAME2:
531         case LOCALE_SDAYNAME3:
532         case LOCALE_SDAYNAME4:
533         case LOCALE_SDAYNAME5:
534         case LOCALE_SDAYNAME6:
535         case LOCALE_SDAYNAME7:
536         case LOCALE_SDURATION:
537         case LOCALE_SLONGDATE:
538         case LOCALE_SMONTHNAME1:
539         case LOCALE_SMONTHNAME2:
540         case LOCALE_SMONTHNAME3:
541         case LOCALE_SMONTHNAME4:
542         case LOCALE_SMONTHNAME5:
543         case LOCALE_SMONTHNAME6:
544         case LOCALE_SMONTHNAME7:
545         case LOCALE_SMONTHNAME8:
546         case LOCALE_SMONTHNAME9:
547         case LOCALE_SMONTHNAME10:
548         case LOCALE_SMONTHNAME11:
549         case LOCALE_SMONTHNAME12:
550         case LOCALE_SMONTHNAME13:
551         case LOCALE_SSHORTDATE:
552         case LOCALE_SSHORTESTDAYNAME1:
553         case LOCALE_SSHORTESTDAYNAME2:
554         case LOCALE_SSHORTESTDAYNAME3:
555         case LOCALE_SSHORTESTDAYNAME4:
556         case LOCALE_SSHORTESTDAYNAME5:
557         case LOCALE_SSHORTESTDAYNAME6:
558         case LOCALE_SSHORTESTDAYNAME7:
559         case LOCALE_STIME:
560         case LOCALE_STIMEFORMAT:
561         case LOCALE_SYEARMONTH:
562             default_id = lcid_LC_TIME;
563             break;
564 
565         case LOCALE_IPAPERSIZE:
566             default_id = lcid_LC_PAPER;
567             break;
568 
569         case LOCALE_IMEASURE:
570             default_id = lcid_LC_MEASUREMENT;
571             break;
572 
573         case LOCALE_ICOUNTRY:
574             default_id = lcid_LC_TELEPHONE;
575             break;
576         }
577         if (default_id) lcid = default_id;
578     }
579     return ConvertDefaultLocale( lcid );
580 }
581 
582 
583 /***********************************************************************
584  *              create_registry_key
585  *
586  * Create the Control Panel\\International registry key.
587  */
588 static inline HANDLE create_registry_key(void)
589 {
590     static const WCHAR intlW[] = {'C','o','n','t','r','o','l',' ','P','a','n','e','l','\\',
591                                   'I','n','t','e','r','n','a','t','i','o','n','a','l',0};
592     OBJECT_ATTRIBUTES attr;
593     UNICODE_STRING nameW;
594     HANDLE hkey;
595 
596     if (RtlOpenCurrentUser( KEY_ALL_ACCESS, &hkey ) != STATUS_SUCCESS) return 0;
597 
598     attr.Length = sizeof(attr);
599     attr.RootDirectory = hkey;
600     attr.ObjectName = &nameW;
601     attr.Attributes = 0;
602     attr.SecurityDescriptor = NULL;
603     attr.SecurityQualityOfService = NULL;
604     RtlInitUnicodeString( &nameW, intlW );
605 
606     if (NtCreateKey( &hkey, KEY_ALL_ACCESS, &attr, 0, NULL, 0, NULL ) != STATUS_SUCCESS) hkey = 0;
607     NtClose( attr.RootDirectory );
608     return hkey;
609 }
610 
611 
612 /* update the registry settings for a given locale parameter */
613 /* return TRUE if an update was needed */
614 static BOOL locale_update_registry( HKEY hkey, const WCHAR *name, LCID lcid,
615                                     const LCTYPE *values, UINT nb_values )
616 {
617     static const WCHAR formatW[] = { '%','','8','x',0 };
618     WCHAR bufferW[40];
619     UNICODE_STRING nameW;
620     DWORD count, i;
621 
622     RtlInitUnicodeString( &nameW, name );
623     count = sizeof(bufferW);
624     if (!NtQueryValueKey(hkey, &nameW, KeyValuePartialInformation, (LPBYTE)bufferW, count, &count))
625     {
626         const KEY_VALUE_PARTIAL_INFORMATION *info = (KEY_VALUE_PARTIAL_INFORMATION *)bufferW;
627         LPCWSTR text = (LPCWSTR)info->Data;
628 
629         if (strtoulW( text, NULL, 16 ) == lcid) return FALSE; /* already set correctly */
630         TRACE( "updating registry, locale %s changed %s -> %08x\n",
631                debugstr_w(name), debugstr_w(text), lcid );
632     }
633     else TRACE( "updating registry, locale %s changed none -> %08x\n", debugstr_w(name), lcid );
634     sprintfW( bufferW, formatW, lcid );
635     NtSetValueKey( hkey, &nameW, 0, REG_SZ, bufferW, (strlenW(bufferW) + 1) * sizeof(WCHAR) );
636 
637     for (i = 0; i < nb_values; i++)
638     {
639         GetLocaleInfoW( lcid, values[i] | LOCALE_NOUSEROVERRIDE, bufferW,
640                         sizeof(bufferW)/sizeof(WCHAR) );
641         SetLocaleInfoW( lcid, values[i], bufferW );
642     }
643     return TRUE;
644 }
645 
646 
647 /***********************************************************************
648  *              LOCALE_InitRegistry
649  *
650  * Update registry contents on startup if the user locale has changed.
651  * This simulates the action of the Windows control panel.
652  */
653 void LOCALE_InitRegistry(void)
654 {
655     static const WCHAR acpW[] = {'A','C','P',0};
656     static const WCHAR oemcpW[] = {'O','E','M','C','P',0};
657     static const WCHAR maccpW[] = {'M','A','C','C','P',0};
658     static const WCHAR localeW[] = {'L','o','c','a','l','e',0};
659     static const WCHAR lc_ctypeW[] = { 'L','C','_','C','T','Y','P','E',0 };
660     static const WCHAR lc_monetaryW[] = { 'L','C','_','M','O','N','E','T','A','R','Y',0 };
661     static const WCHAR lc_numericW[] = { 'L','C','_','N','U','M','E','R','I','C',0 };
662     static const WCHAR lc_timeW[] = { 'L','C','_','T','I','M','E',0 };
663     static const WCHAR lc_measurementW[] = { 'L','C','_','M','E','A','S','U','R','E','M','E','N','T',0 };
664     static const WCHAR lc_telephoneW[] = { 'L','C','_','T','E','L','E','P','H','O','N','E',0 };
665     static const WCHAR lc_paperW[] = { 'L','C','_','P','A','P','E','R',0};
666     static const struct
667     {
668         LPCWSTR name;
669         USHORT value;
670     } update_cp_values[] = {
671         { acpW, LOCALE_IDEFAULTANSICODEPAGE },
672         { oemcpW, LOCALE_IDEFAULTCODEPAGE },
673         { maccpW, LOCALE_IDEFAULTMACCODEPAGE }
674     };
675     static const LCTYPE lc_messages_values[] = {
676       LOCALE_SLANGUAGE,
677       LOCALE_SCOUNTRY,
678       LOCALE_SLIST };
679     static const LCTYPE lc_monetary_values[] = {
680       LOCALE_SCURRENCY,
681       LOCALE_ICURRENCY,
682       LOCALE_INEGCURR,
683       LOCALE_ICURRDIGITS,
684       LOCALE_ILZERO,
685       LOCALE_SMONDECIMALSEP,
686       LOCALE_SMONGROUPING,
687       LOCALE_SMONTHOUSANDSEP };
688     static const LCTYPE lc_numeric_values[] = {
689       LOCALE_SDECIMAL,
690       LOCALE_STHOUSAND,
691       LOCALE_IDIGITS,
692       LOCALE_IDIGITSUBSTITUTION,
693       LOCALE_SNATIVEDIGITS,
694       LOCALE_INEGNUMBER,
695       LOCALE_SNEGATIVESIGN,
696       LOCALE_SPOSITIVESIGN,
697       LOCALE_SGROUPING };
698     static const LCTYPE lc_time_values[] = {
699       LOCALE_S1159,
700       LOCALE_S2359,
701       LOCALE_STIME,
702       LOCALE_ITIME,
703       LOCALE_ITLZERO,
704       LOCALE_SSHORTDATE,
705       LOCALE_SLONGDATE,
706       LOCALE_SDATE,
707       LOCALE_ITIMEMARKPOSN,
708       LOCALE_ICALENDARTYPE,
709       LOCALE_IFIRSTDAYOFWEEK,
710       LOCALE_IFIRSTWEEKOFYEAR,
711       LOCALE_STIMEFORMAT,
712       LOCALE_SYEARMONTH,
713       LOCALE_IDATE };
714     static const LCTYPE lc_measurement_values[] = { LOCALE_IMEASURE };
715     static const LCTYPE lc_telephone_values[] = { LOCALE_ICOUNTRY };
716     static const LCTYPE lc_paper_values[] = { LOCALE_IPAPERSIZE };
717 
718     UNICODE_STRING nameW;
719     WCHAR bufferW[80];
720     DWORD count, i;
721     HANDLE hkey;
722     LCID lcid = GetUserDefaultLCID();
723 
724     if (!(hkey = create_registry_key()))
725         return;  /* don't do anything if we can't create the registry key */
726 
727     locale_update_registry( hkey, localeW, lcid_LC_MESSAGES, lc_messages_values,
728                             sizeof(lc_messages_values)/sizeof(lc_messages_values[0]) );
729     locale_update_registry( hkey, lc_monetaryW, lcid_LC_MONETARY, lc_monetary_values,
730                             sizeof(lc_monetary_values)/sizeof(lc_monetary_values[0]) );
731     locale_update_registry( hkey, lc_numericW, lcid_LC_NUMERIC, lc_numeric_values,
732                             sizeof(lc_numeric_values)/sizeof(lc_numeric_values[0]) );
733     locale_update_registry( hkey, lc_timeW, lcid_LC_TIME, lc_time_values,
734                             sizeof(lc_time_values)/sizeof(lc_time_values[0]) );
735     locale_update_registry( hkey, lc_measurementW, lcid_LC_MEASUREMENT, lc_measurement_values,
736                             sizeof(lc_measurement_values)/sizeof(lc_measurement_values[0]) );
737     locale_update_registry( hkey, lc_telephoneW, lcid_LC_TELEPHONE, lc_telephone_values,
738                             sizeof(lc_telephone_values)/sizeof(lc_telephone_values[0]) );
739     locale_update_registry( hkey, lc_paperW, lcid_LC_PAPER, lc_paper_values,
740                             sizeof(lc_paper_values)/sizeof(lc_paper_values[0]) );
741 
742     if (locale_update_registry( hkey, lc_ctypeW, lcid_LC_CTYPE, NULL, 0 ))
743     {
744         HKEY nls_key = NLS_RegOpenKey( 0, szCodepageKeyName );
745 
746         for (i = 0; i < sizeof(update_cp_values)/sizeof(update_cp_values[0]); i++)
747         {
748             count = GetLocaleInfoW( lcid, update_cp_values[i].value | LOCALE_NOUSEROVERRIDE,
749                                     bufferW, sizeof(bufferW)/sizeof(WCHAR) );
750             RtlInitUnicodeString( &nameW, update_cp_values[i].name );
751             NtSetValueKey( nls_key, &nameW, 0, REG_SZ, bufferW, count * sizeof(WCHAR) );
752         }
753         NtClose( nls_key );
754     }
755 
756     NtClose( hkey );
757 }
758 
759 
760 /***********************************************************************
761  *           setup_unix_locales
762  */
763 static UINT setup_unix_locales(void)
764 {
765     struct locale_name locale_name;
766     WCHAR buffer[128], ctype_buff[128];
767     char *locale;
768     UINT unix_cp = 0;
769 
770     if ((locale = setlocale( LC_CTYPE, NULL )))
771     {
772         strcpynAtoW( ctype_buff, locale, sizeof(ctype_buff)/sizeof(WCHAR) );
773         parse_locale_name( ctype_buff, &locale_name );
774         lcid_LC_CTYPE = locale_name.lcid;
775         unix_cp = locale_name.codepage;
776     }
777     if (!lcid_LC_CTYPE)  /* this one needs a default value */
778         lcid_LC_CTYPE = MAKELCID( MAKELANGID(LANG_ENGLISH,SUBLANG_DEFAULT), SORT_DEFAULT );
779 
780     TRACE( "got lcid %04x (%d matches) for LC_CTYPE=%s\n",
781            locale_name.lcid, locale_name.matches, debugstr_a(locale) );
782 
783 #define GET_UNIX_LOCALE(cat) do \
784     if ((locale = setlocale( cat, NULL ))) \
785     { \
786         strcpynAtoW( buffer, locale, sizeof(buffer)/sizeof(WCHAR) ); \
787         if (!strcmpW( buffer, ctype_buff )) lcid_##cat = lcid_LC_CTYPE; \
788         else { \
789             parse_locale_name( buffer, &locale_name );  \
790             lcid_##cat = locale_name.lcid; \
791             TRACE( "got lcid %04x (%d matches) for " #cat "=%s\n",        \
792                    locale_name.lcid, locale_name.matches, debugstr_a(locale) ); \
793         } \
794     } while (0)
795 
796     GET_UNIX_LOCALE( LC_COLLATE );
797     GET_UNIX_LOCALE( LC_MESSAGES );
798     GET_UNIX_LOCALE( LC_MONETARY );
799     GET_UNIX_LOCALE( LC_NUMERIC );
800     GET_UNIX_LOCALE( LC_TIME );
801 #ifdef LC_PAPER
802     GET_UNIX_LOCALE( LC_PAPER );
803 #endif
804 #ifdef LC_MEASUREMENT
805     GET_UNIX_LOCALE( LC_MEASUREMENT );
806 #endif
807 #ifdef LC_TELEPHONE
808     GET_UNIX_LOCALE( LC_TELEPHONE );
809 #endif
810 
811 #undef GET_UNIX_LOCALE
812 
813     return unix_cp;
814 }
815 
816 
817 /***********************************************************************
818  *              GetUserDefaultLangID (KERNEL32.@)
819  *
820  * Get the default language Id for the current user.
821  *
822  * PARAMS
823  *  None.
824  *
825  * RETURNS
826  *  The current LANGID of the default language for the current user.
827  */
828 LANGID WINAPI GetUserDefaultLangID(void)
829 {
830     return LANGIDFROMLCID(GetUserDefaultLCID());
831 }
832 
833 
834 /***********************************************************************
835  *              GetSystemDefaultLangID (KERNEL32.@)
836  *
837  * Get the default language Id for the system.
838  *
839  * PARAMS
840  *  None.
841  *
842  * RETURNS
843  *  The current LANGID of the default language for the system.
844  */
845 LANGID WINAPI GetSystemDefaultLangID(void)
846 {
847     return LANGIDFROMLCID(GetSystemDefaultLCID());
848 }
849 
850 
851 /***********************************************************************
852  *              GetUserDefaultLCID (KERNEL32.@)
853  *
854  * Get the default locale Id for the current user.
855  *
856  * PARAMS
857  *  None.
858  *
859  * RETURNS
860  *  The current LCID of the default locale for the current user.
861  */
862 LCID WINAPI GetUserDefaultLCID(void)
863 {
864     LCID lcid;
865     NtQueryDefaultLocale( TRUE, &lcid );
866     return lcid;
867 }
868 
869 
870 /***********************************************************************
871  *              GetSystemDefaultLCID (KERNEL32.@)
872  *
873  * Get the default locale Id for the system.
874  *
875  * PARAMS
876  *  None.
877  *
878  * RETURNS
879  *  The current LCID of the default locale for the system.
880  */
881 LCID WINAPI GetSystemDefaultLCID(void)
882 {
883     LCID lcid;
884     NtQueryDefaultLocale( FALSE, &lcid );
885     return lcid;
886 }
887 
888 
889 /***********************************************************************
890  *              GetUserDefaultUILanguage (KERNEL32.@)
891  *
892  * Get the default user interface language Id for the current user.
893  *
894  * PARAMS
895  *  None.
896  *
897  * RETURNS
898  *  The current LANGID of the default UI language for the current user.
899  */
900 LANGID WINAPI GetUserDefaultUILanguage(void)
901 {
902     LANGID lang;
903     NtQueryDefaultUILanguage( &lang );
904     return lang;
905 }
906 
907 
908 /***********************************************************************
909  *              GetSystemDefaultUILanguage (KERNEL32.@)
910  *
911  * Get the default user interface language Id for the system.
912  *
913  * PARAMS
914  *  None.
915  *
916  * RETURNS
917  *  The current LANGID of the default UI language for the system. This is
918  *  typically the same language used during the installation process.
919  */
920 LANGID WINAPI GetSystemDefaultUILanguage(void)
921 {
922     LANGID lang;
923     NtQueryInstallUILanguage( &lang );
924     return lang;
925 }
926 
927 
928 /***********************************************************************
929  *           LocaleNameToLCID  (KERNEL32.@)
930  */
931 LCID WINAPI LocaleNameToLCID( LPCWSTR name,