/* Determine name of the currently selected locale.
- Copyright (C) 1995-2012 Free Software Foundation, Inc.
+ Copyright (C) 1995-2015 Free Software Foundation, Inc.
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU Lesser General Public License as published by
# if defined __APPLE__ && defined __MACH__
# include <xlocale.h>
# endif
-# include <langinfo.h>
+# if __GLIBC__ >= 2 && !defined __UCLIBC__
+# include <langinfo.h>
+# endif
# if !defined IN_LIBINTL
# include "glthread/lock.h"
# endif
+# if defined __sun && HAVE_GETLOCALENAME_L
+/* Solaris >= 12. */
+extern char * getlocalename_l(int, locale_t);
+# endif
#endif
#if HAVE_CFLOCALECOPYCURRENT || HAVE_CFPREFERENCESCOPYAPPVALUE
#if defined _WIN32 || defined __WIN32__
# define WINDOWS_NATIVE
+# if !defined IN_LIBINTL
+# include "glthread/lock.h"
+# endif
#endif
#if defined WINDOWS_NATIVE || defined __CYGWIN__ /* Native Windows or Cygwin */
# define WIN32_LEAN_AND_MEAN
# include <windows.h>
+# include <winnls.h>
/* List of language codes, sorted by value:
0x01 LANG_ARABIC
0x02 LANG_BULGARIAN
# ifndef LOCALE_SNAME
# define LOCALE_SNAME 0x5c
# endif
+# ifndef LOCALE_NAME_MAX_LENGTH
+# define LOCALE_NAME_MAX_LENGTH 85
+# endif
#endif
return gl_locale_name_from_win32_LANGID (langid);
}
+# ifdef WINDOWS_NATIVE
+
+/* Two variables to interface between get_lcid and the EnumLocales
+ callback function below. */
+static LCID found_lcid;
+static char lname[LC_MAX * (LOCALE_NAME_MAX_LENGTH + 1) + 1];
+
+/* Callback function for EnumLocales. */
+static BOOL CALLBACK
+enum_locales_fn (LPTSTR locale_num_str)
+{
+ char *endp;
+ char locval[2 * LOCALE_NAME_MAX_LENGTH + 1 + 1];
+ LCID try_lcid = strtoul (locale_num_str, &endp, 16);
+
+ if (GetLocaleInfo (try_lcid, LOCALE_SENGLANGUAGE,
+ locval, LOCALE_NAME_MAX_LENGTH))
+ {
+ strcat (locval, "_");
+ if (GetLocaleInfo (try_lcid, LOCALE_SENGCOUNTRY,
+ locval + strlen (locval), LOCALE_NAME_MAX_LENGTH))
+ {
+ size_t locval_len = strlen (locval);
+
+ if (strncmp (locval, lname, locval_len) == 0
+ && (lname[locval_len] == '.'
+ || lname[locval_len] == '\0'))
+ {
+ found_lcid = try_lcid;
+ return FALSE;
+ }
+ }
+ }
+ return TRUE;
+}
+
+/* This lock protects the get_lcid against multiple simultaneous calls. */
+gl_lock_define_initialized(static, get_lcid_lock)
+
+/* Return the Locale ID (LCID) number given the locale's name, a
+ string, in LOCALE_NAME. This works by enumerating all the locales
+ supported by the system, until we find one whose name matches
+ LOCALE_NAME. */
+static LCID
+get_lcid (const char *locale_name)
+{
+ /* A simple cache. */
+ static LCID last_lcid;
+ static char last_locale[1000];
+
+ /* Lock while looking for an LCID, to protect access to static
+ variables: last_lcid, last_locale, found_lcid, and lname. */
+ gl_lock_lock (get_lcid_lock);
+ if (last_lcid > 0 && strcmp (locale_name, last_locale) == 0)
+ {
+ gl_lock_unlock (get_lcid_lock);
+ return last_lcid;
+ }
+ strncpy (lname, locale_name, sizeof (lname) - 1);
+ lname[sizeof (lname) - 1] = '\0';
+ found_lcid = 0;
+ EnumSystemLocales (enum_locales_fn, LCID_SUPPORTED);
+ if (found_lcid > 0)
+ {
+ last_lcid = found_lcid;
+ strcpy (last_locale, locale_name);
+ }
+ gl_lock_unlock (get_lcid_lock);
+ return found_lcid;
+}
+
+# endif
#endif
-#if HAVE_USELOCALE /* glibc or Mac OS X */
+#if HAVE_USELOCALE /* glibc, Solaris >= 12 or Mac OS X */
/* Simple hash set of strings. We don't want to drag in lots of hash table
code here. */
/* A hash function for NUL-terminated char* strings using
the method described by Bruno Haible.
See http://www.haible.de/bruno/hashfunc.html. */
-static size_t
+static size_t _GL_ATTRIBUTE_PURE
string_hash (const void *x)
{
const char *s = (const char *) x;
return "";
}
return querylocale (mask, thread_locale);
+# elif defined __sun && HAVE_GETLOCALENAME_L
+ /* Solaris >= 12. */
+ return getlocalename_l (category, thread_locale);
+# elif defined __ANDROID__
+ return MB_CUR_MAX == 4 ? "C.UTF-8" : "C";
# endif
}
}
const char *name = gl_locale_name_thread_unsafe (category, categoryname);
if (name != NULL)
return struniq (name);
+#elif defined WINDOWS_NATIVE
+ if (LC_MIN <= category && category <= LC_MAX)
+ {
+ char *locname = setlocale (category, NULL);
+ LCID lcid = 0;
+
+ /* If CATEGORY is LC_ALL, the result might be a semi-colon
+ separated list of locales. We need only one, so we take the
+ one corresponding to LC_CTYPE, as the most important for
+ character translations. */
+ if (strchr (locname, ';'))
+ locname = setlocale (LC_CTYPE, NULL);
+
+ /* Convert locale name to LCID. We don't want to use
+ LocaleNameToLCID because (a) it is only available since Vista,
+ and (b) it doesn't accept locale names returned by 'setlocale'. */
+ lcid = get_lcid (locname);
+
+ if (lcid > 0)
+ return gl_locale_name_from_win32_LCID (lcid);
+ }
#endif
return NULL;
}