diff options
Diffstat (limited to 'gnulib-tests/localename.c')
-rw-r--r-- | gnulib-tests/localename.c | 113 |
1 files changed, 111 insertions, 2 deletions
diff --git a/gnulib-tests/localename.c b/gnulib-tests/localename.c index 52d545a0..35b6de40 100644 --- a/gnulib-tests/localename.c +++ b/gnulib-tests/localename.c @@ -1,5 +1,5 @@ /* Determine name of the currently selected locale. - Copyright (C) 1995-2014 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 General Public License as published by @@ -42,6 +42,10 @@ # if !defined IN_LIBINTL # include "glthread/lock.h" # endif +# if defined __sun +/* Solaris >= 12. */ +extern char * getlocalename_l(int, locale_t); +# endif #endif #if HAVE_CFLOCALECOPYCURRENT || HAVE_CFPREFERENCESCOPYAPPVALUE @@ -55,11 +59,15 @@ #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 @@ -1124,6 +1132,9 @@ # ifndef LOCALE_SNAME # define LOCALE_SNAME 0x5c # endif +# ifndef LOCALE_NAME_MAX_LENGTH +# define LOCALE_NAME_MAX_LENGTH 85 +# endif #endif @@ -2502,10 +2513,82 @@ gl_locale_name_from_win32_LCID (LCID lcid) 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. */ @@ -2644,6 +2727,11 @@ gl_locale_name_thread_unsafe (int category, const char *categoryname) return ""; } return querylocale (mask, thread_locale); +# elif defined __sun + /* Solaris >= 12. */ + return getlocalename_l (category, thread_locale); +# elif defined __ANDROID__ + return MB_CUR_MAX == 4 ? "C.UTF-8" : "C"; # endif } } @@ -2660,6 +2748,27 @@ gl_locale_name_thread (int category, const char *categoryname) 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; } |