Install gettext-0.18.1.1.tar.gz
[msysgit.git] / mingw / share / gettext / intl / langprefs.c
blobde66ad8ccb80a7bedce460b22cf80c082ea0daa6
1 /* Determine the user's language preferences.
2 Copyright (C) 2004-2007 Free Software Foundation, Inc.
4 This program is free software; you can redistribute it and/or modify it
5 under the terms of the GNU Library General Public License as published
6 by the Free Software Foundation; either version 2, or (at your option)
7 any later version.
9 This program is distributed in the hope that it will be useful,
10 but WITHOUT ANY WARRANTY; without even the implied warranty of
11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12 Library General Public License for more details.
14 You should have received a copy of the GNU Library General Public
15 License along with this program; if not, write to the Free Software
16 Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301,
17 USA. */
19 /* Written by Bruno Haible <bruno@clisp.org>.
20 Win32 code originally by Michele Cicciotti <hackbunny@reactos.com>. */
22 #ifdef HAVE_CONFIG_H
23 # include <config.h>
24 #endif
26 #include <stdlib.h>
28 #if HAVE_CFPREFERENCESCOPYAPPVALUE
29 # include <string.h>
30 # include <CoreFoundation/CFPreferences.h>
31 # include <CoreFoundation/CFPropertyList.h>
32 # include <CoreFoundation/CFArray.h>
33 # include <CoreFoundation/CFString.h>
34 extern void _nl_locale_name_canonicalize (char *name);
35 #endif
37 #if defined _WIN32 || defined __WIN32__
38 # define WIN32_NATIVE
39 #endif
41 #ifdef WIN32_NATIVE
42 # define WIN32_LEAN_AND_MEAN
43 # include <windows.h>
45 # ifndef MUI_LANGUAGE_NAME
46 # define MUI_LANGUAGE_NAME 8
47 # endif
48 # ifndef STATUS_BUFFER_OVERFLOW
49 # define STATUS_BUFFER_OVERFLOW 0x80000005
50 # endif
52 extern void _nl_locale_name_canonicalize (char *name);
53 extern const char *_nl_locale_name_from_win32_LANGID (LANGID langid);
54 extern const char *_nl_locale_name_from_win32_LCID (LCID lcid);
56 /* Get the preferences list through the MUI APIs. This works on Windows Vista
57 and newer. */
58 static const char *
59 _nl_language_preferences_win32_mui (HMODULE kernel32)
61 /* DWORD GetUserPreferredUILanguages (ULONG dwFlags,
62 PULONG pulNumLanguages,
63 PWSTR pwszLanguagesBuffer,
64 PULONG pcchLanguagesBuffer); */
65 typedef DWORD (WINAPI *GetUserPreferredUILanguages_func) (ULONG, PULONG, PWSTR, PULONG);
66 GetUserPreferredUILanguages_func p_GetUserPreferredUILanguages;
68 p_GetUserPreferredUILanguages =
69 (GetUserPreferredUILanguages_func)
70 GetProcAddress (kernel32, "GetUserPreferredUILanguages");
71 if (p_GetUserPreferredUILanguages != NULL)
73 ULONG num_languages;
74 ULONG bufsize;
75 DWORD ret;
77 bufsize = 0;
78 ret = p_GetUserPreferredUILanguages (MUI_LANGUAGE_NAME,
79 &num_languages,
80 NULL, &bufsize);
81 if (ret == 0
82 && GetLastError () == STATUS_BUFFER_OVERFLOW
83 && bufsize > 0)
85 WCHAR *buffer = (WCHAR *) malloc (bufsize * sizeof (WCHAR));
86 if (buffer != NULL)
88 ret = p_GetUserPreferredUILanguages (MUI_LANGUAGE_NAME,
89 &num_languages,
90 buffer, &bufsize);
91 if (ret)
93 /* Convert the list from NUL-delimited WCHAR[] Win32 locale
94 names to colon-delimited char[] Unix locale names.
95 We assume that all these locale names are in ASCII,
96 nonempty and contain no colons. */
97 char *languages =
98 (char *) malloc (bufsize + num_languages * 10 + 1);
99 if (languages != NULL)
101 const WCHAR *p = buffer;
102 char *q = languages;
103 ULONG i;
104 for (i = 0; i < num_languages; i++)
106 char *q1;
107 char *q2;
109 q1 = q;
110 if (i > 0)
111 *q++ = ':';
112 q2 = q;
113 for (; *p != (WCHAR)'\0'; p++)
115 if ((unsigned char) *p != *p || *p == ':')
117 /* A non-ASCII character or a colon inside
118 the Win32 locale name! Punt. */
119 q = q1;
120 break;
122 *q++ = (unsigned char) *p;
124 if (q == q1)
125 /* An unexpected Win32 locale name occurred. */
126 break;
127 *q = '\0';
128 _nl_locale_name_canonicalize (q2);
129 q = q2 + strlen (q2);
130 p++;
132 *q = '\0';
133 if (q > languages)
135 free (buffer);
136 return languages;
138 free (languages);
141 free (buffer);
145 return NULL;
148 /* Get a preference. This works on Windows ME and newer. */
149 static const char *
150 _nl_language_preferences_win32_ME (HMODULE kernel32)
152 /* LANGID GetUserDefaultUILanguage (void); */
153 typedef LANGID (WINAPI *GetUserDefaultUILanguage_func) (void);
154 GetUserDefaultUILanguage_func p_GetUserDefaultUILanguage;
156 p_GetUserDefaultUILanguage =
157 (GetUserDefaultUILanguage_func)
158 GetProcAddress (kernel32, "GetUserDefaultUILanguage");
159 if (p_GetUserDefaultUILanguage != NULL)
160 return _nl_locale_name_from_win32_LANGID (p_GetUserDefaultUILanguage ());
161 return NULL;
164 /* Get a preference. This works on Windows 95 and newer. */
165 static const char *
166 _nl_language_preferences_win32_95 ()
168 HKEY desktop_resource_locale_key;
170 if (RegOpenKeyExA (HKEY_CURRENT_USER,
171 "Control Panel\\Desktop\\ResourceLocale",
172 0, KEY_QUERY_VALUE, &desktop_resource_locale_key)
173 == NO_ERROR)
175 DWORD type;
176 char data[8 + 1];
177 DWORD data_size = sizeof (data);
178 DWORD ret;
180 ret = RegQueryValueExA (desktop_resource_locale_key, NULL, NULL,
181 &type, data, &data_size);
182 RegCloseKey (desktop_resource_locale_key);
184 if (ret == NO_ERROR)
186 /* We expect a string, at most 8 bytes long, that parses as a
187 hexadecimal number. */
188 if (type == REG_SZ
189 && data_size <= sizeof (data)
190 && (data_size < sizeof (data)
191 || data[sizeof (data) - 1] == '\0'))
193 LCID lcid;
194 char *endp;
195 /* Ensure it's NUL terminated. */
196 if (data_size < sizeof (data))
197 data[data_size] = '\0';
198 /* Parse it as a hexadecimal number. */
199 lcid = strtoul (data, &endp, 16);
200 if (endp > data && *endp == '\0')
201 return _nl_locale_name_from_win32_LCID (lcid);
205 return NULL;
208 /* Get the system's preference. This can be used as a fallback. */
209 static BOOL CALLBACK
210 ret_first_language (HMODULE h, LPCSTR type, LPCSTR name, WORD lang, LONG_PTR param)
212 *(const char **)param = _nl_locale_name_from_win32_LANGID (lang);
213 return FALSE;
215 static const char *
216 _nl_language_preferences_win32_system (HMODULE kernel32)
218 const char *languages = NULL;
219 /* Ignore the warning on mingw here. mingw has a wrong definition of the last
220 parameter type of ENUMRESLANGPROC. */
221 EnumResourceLanguages (kernel32, RT_VERSION, MAKEINTRESOURCE (1),
222 ret_first_language, (LONG_PTR)&languages);
223 return languages;
226 #endif
228 /* Determine the user's language preferences, as a colon separated list of
229 locale names in XPG syntax
230 language[_territory][.codeset][@modifier]
231 The result must not be freed; it is statically allocated.
232 The LANGUAGE environment variable does not need to be considered; it is
233 already taken into account by the caller. */
235 const char *
236 _nl_language_preferences_default (void)
238 #if HAVE_CFPREFERENCESCOPYAPPVALUE /* MacOS X 10.2 or newer */
240 /* Cache the preferences list, since CoreFoundation calls are expensive. */
241 static const char *cached_languages;
242 static int cache_initialized;
244 if (!cache_initialized)
246 CFTypeRef preferences =
247 CFPreferencesCopyAppValue (CFSTR ("AppleLanguages"),
248 kCFPreferencesCurrentApplication);
249 if (preferences != NULL
250 && CFGetTypeID (preferences) == CFArrayGetTypeID ())
252 CFArrayRef prefArray = (CFArrayRef)preferences;
253 int n = CFArrayGetCount (prefArray);
254 char buf[256];
255 size_t size = 0;
256 int i;
258 for (i = 0; i < n; i++)
260 CFTypeRef element = CFArrayGetValueAtIndex (prefArray, i);
261 if (element != NULL
262 && CFGetTypeID (element) == CFStringGetTypeID ()
263 && CFStringGetCString ((CFStringRef)element,
264 buf, sizeof (buf),
265 kCFStringEncodingASCII))
267 _nl_locale_name_canonicalize (buf);
268 size += strlen (buf) + 1;
269 /* Most GNU programs use msgids in English and don't ship
270 an en.mo message catalog. Therefore when we see "en"
271 in the preferences list, arrange for gettext() to
272 return the msgid, and ignore all further elements of
273 the preferences list. */
274 if (strcmp (buf, "en") == 0)
275 break;
277 else
278 break;
280 if (size > 0)
282 char *languages = (char *) malloc (size);
284 if (languages != NULL)
286 char *p = languages;
288 for (i = 0; i < n; i++)
290 CFTypeRef element =
291 CFArrayGetValueAtIndex (prefArray, i);
292 if (element != NULL
293 && CFGetTypeID (element) == CFStringGetTypeID ()
294 && CFStringGetCString ((CFStringRef)element,
295 buf, sizeof (buf),
296 kCFStringEncodingASCII))
298 _nl_locale_name_canonicalize (buf);
299 strcpy (p, buf);
300 p += strlen (buf);
301 *p++ = ':';
302 if (strcmp (buf, "en") == 0)
303 break;
305 else
306 break;
308 *--p = '\0';
310 cached_languages = languages;
314 cache_initialized = 1;
316 if (cached_languages != NULL)
317 return cached_languages;
319 #endif
321 #ifdef WIN32_NATIVE
323 /* Cache the preferences list, since computing it is expensive. */
324 static const char *cached_languages;
325 static int cache_initialized;
327 /* Activate the new code only when the GETTEXT_MUI environment variable is
328 set, for the time being, since the new code is not well tested. */
329 if (!cache_initialized && getenv ("GETTEXT_MUI") != NULL)
331 const char *languages = NULL;
332 HMODULE kernel32 = GetModuleHandle ("kernel32");
334 if (kernel32 != NULL)
335 languages = _nl_language_preferences_win32_mui (kernel32);
337 if (languages == NULL && kernel32 != NULL)
338 languages = _nl_language_preferences_win32_ME (kernel32);
340 if (languages == NULL)
341 languages = _nl_language_preferences_win32_95 ();
343 if (languages == NULL && kernel32 != NULL)
344 languages = _nl_language_preferences_win32_system (kernel32);
346 cached_languages = languages;
347 cache_initialized = 1;
349 if (cached_languages != NULL)
350 return cached_languages;
352 #endif
354 return NULL;