From a2036998b1b5d611e7af0546063b12f35a204f39 Mon Sep 17 00:00:00 2001 From: Corinna Vinschen Date: Tue, 23 Feb 2010 14:07:08 +0000 Subject: [PATCH] * locale.cc (printlocale): Remove. (loc_t): New type to keep locale information for printing. (print_codeset): New function to print codeset as on Linux. (print_locale_with_codeset): New function to print single locale. Print verbose style as the Linux locale(1) tool. (print_locale): New function to print single locale plus its UTF-8 variation, if available. (compare_locales): New helper function for bsearch and qsort on loc_t. (add_locale): New function to store locale in loc_t array. (add_locale_alias_locales): New function to store locales from locale.alias file in loc_t. (print_all_locales): Call add_locale instead of printlocale. Call add_locale_alias_locales, sort locales alphabetically and print them. --- winsup/utils/ChangeLog | 17 ++++ winsup/utils/locale.cc | 182 +++++++++++++++++++++++++++++++++++++---- 2 files changed, 182 insertions(+), 17 deletions(-) diff --git a/winsup/utils/ChangeLog b/winsup/utils/ChangeLog index cfa731d73..2687817c0 100644 --- a/winsup/utils/ChangeLog +++ b/winsup/utils/ChangeLog @@ -1,3 +1,20 @@ +2010-02-23 Corinna Vinschen + + * locale.cc (printlocale): Remove. + (loc_t): New type to keep locale information for printing. + (print_codeset): New function to print codeset as on Linux. + (print_locale_with_codeset): New function to print single locale. + Print verbose style as the Linux locale(1) tool. + (print_locale): New function to print single locale plus its UTF-8 + variation, if available. + (compare_locales): New helper function for bsearch and qsort on loc_t. + (add_locale): New function to store locale in loc_t array. + (add_locale_alias_locales): New function to store locales from + locale.alias file in loc_t. + (print_all_locales): Call add_locale instead of printlocale. + Call add_locale_alias_locales, sort locales alphabetically and print + them. + 2010-02-22 Christopher Faylor * strace.cc (mnemonic_table): Add "special" mask option. diff --git a/winsup/utils/locale.cc b/winsup/utils/locale.cc index 125aecd9f..aafd9f6b7 100644 --- a/winsup/utils/locale.cc +++ b/winsup/utils/locale.cc @@ -24,15 +24,20 @@ * SUCH DAMAGE. */ #include +#include #include #include #include #include #include #include +#include #define WINVER 0x0601 #include +#define LOCALE_ALIAS "/usr/share/locale/locale.alias" +#define LOCALE_ALIAS_LINE_LEN 255 + extern char *__progname; void usage (FILE *, int) __attribute__ ((noreturn)); @@ -89,14 +94,155 @@ getlocale (LCID lcid, char *name) return 1; } +typedef struct { + const char *name; + const wchar_t *language; + const wchar_t *territory; + const char *codeset; + bool alias; +} loc_t; +loc_t *locale; +size_t loc_max; +size_t loc_num; + void -printlocale (int verbose, const char *loc, - const wchar_t *lang, const wchar_t *ctry) +print_codeset (const char *codeset) { - printf ("%-16s", loc); + for (; *codeset; ++codeset) + if (*codeset != '-') + putc (tolower ((int)(unsigned char) *codeset), stdout); +} + +void +print_locale_with_codeset (int verbose, loc_t *locale, const char *name, + bool utf8, const char *modifier) +{ + static const char *sysroot; + char locname[32]; + + if (verbose + && (!strcmp (locale->name, "C") || !strcmp (locale->name, "POSIX"))) + return; + if (!sysroot) + { + char sysbuf[PATH_MAX]; + stpcpy (stpcpy (sysbuf, getenv ("SYSTEMROOT")), + "\\system32\\kernel32.dll"); + sysroot = (const char *) cygwin_create_path (CCP_WIN_A_TO_POSIX, sysbuf); + if (!sysroot) + sysroot = "kernel32.dll"; + } + stpcpy (stpcpy (stpcpy (locname, name), utf8 ? ".utf8" : ""), modifier ?: ""); if (verbose) - printf ("%ls (%ls)", lang, ctry); - fputc ('\n', stdout); + fputs ("locale: ", stdout); + printf ("%-15s ", locname); + if (verbose) + { + printf ("archive: %s\n", + locale->alias ? LOCALE_ALIAS : sysroot); + puts ("-------------------------------------------------------------------------------"); + printf (" language | %ls\n", locale->language); + printf ("territory | %ls\n", locale->territory); + printf (" codeset | %s\n", utf8 ? "UTF-8" : locale->codeset); + } + putc ('\n', stdout); +} + +void +print_locale (int verbose, loc_t *locale) +{ + print_locale_with_codeset (verbose, locale, locale->name, false, NULL); + char *modifier = strchr (locale->name, '@'); + if (!locale->alias) + { + if (!modifier) + print_locale_with_codeset (verbose, locale, locale->name, true, NULL); + else if (!strcmp (modifier, "@cjknarrow")) + { + *modifier++ = '\0'; + print_locale_with_codeset (verbose, locale, locale->name, true, + modifier); + } + } +} + +int +compare_locales (const void *a, const void *b) +{ + const loc_t *la = (const loc_t *) a; + const loc_t *lb = (const loc_t *) b; + return strcmp (la->name, lb->name); +} + +void +add_locale (const char *name, const wchar_t *language, const wchar_t *territory, + bool alias = false) +{ + char orig_locale[32]; + + if (loc_num >= loc_max) + { + loc_t *tmp = (loc_t *) realloc (locale, (loc_max + 32) * sizeof (loc_t)); + if (!tmp) + { + fprintf (stderr, "Out of memory!\n"); + exit (1); + } + locale = tmp; + loc_max += 32; + } + locale[loc_num].name = strdup (name); + locale[loc_num].language = wcsdup (language); + locale[loc_num].territory = wcsdup (territory); + strcpy (orig_locale, setlocale (LC_CTYPE, NULL)); + setlocale (LC_CTYPE, name); + locale[loc_num].codeset = strdup (nl_langinfo (CODESET)); + setlocale (LC_CTYPE, orig_locale); + locale[loc_num].alias = alias; + ++loc_num; +} + +void +add_locale_alias_locales () +{ + char alias_buf[LOCALE_ALIAS_LINE_LEN + 1], *c; + const char *alias, *replace; + char orig_locale[32]; + loc_t search, *loc; + + FILE *fp = fopen (LOCALE_ALIAS, "rt"); + if (!fp) + return; + strcpy (orig_locale, setlocale (LC_CTYPE, NULL)); + while (fgets (alias_buf, LOCALE_ALIAS_LINE_LEN + 1, fp)) + { + alias_buf[LOCALE_ALIAS_LINE_LEN] = '\0'; + c = strrchr (alias_buf, '\n'); + if (c) + *c = '\0'; + c = alias_buf; + c += strspn (c, " \t"); + if (!*c || *c == '#') + continue; + alias = c; + c += strcspn (c, " \t"); + *c++ = '\0'; + c += strspn (c, " \t"); + if (*c == '#') + continue; + replace = c; + c += strcspn (c, " \t"); + *c++ = '\0'; + c = strchr (replace, '.'); + if (c) + *c = '\0'; + search.name = replace; + loc = (loc_t *) bsearch (&search, locale, loc_num, sizeof (loc_t), + compare_locales); + add_locale (alias, loc ? loc->language : L"", loc ? loc->territory : L"", + true); + } + fclose (fp); } void @@ -108,8 +254,8 @@ print_all_locales (int verbose) unsigned lang, sublang; - printlocale (verbose, "C", L"C", L"POSIX"); - printlocale (verbose, "POSIX", L"C", L"POSIX"); + add_locale ("C", L"C", L"POSIX"); + add_locale ("POSIX", L"C", L"POSIX", true); for (lang = 1; lang <= 0xff; ++lang) { struct { @@ -176,7 +322,7 @@ print_all_locales (int verbose) if (lcnt < 32) strcpy (loc_list[lcnt++].loc, loc); /* Print */ - printlocale (verbose, loc, language, country); + add_locale (loc, language, country); /* Check for locales which sport a modifier for changing the codeset and other stuff. */ if (lang == LANG_BELARUSIAN @@ -199,7 +345,7 @@ print_all_locales (int verbose) stpcpy (c, "@cjknarrow"); else continue; - printlocale (verbose, loc, language, country); + add_locale (loc, language, country); } } /* Check Serbian language for the available territories. Up to @@ -221,17 +367,19 @@ print_all_locales (int verbose) sr_RS_idx = i; if (sr_CS_idx > 0 && sr_RS_idx == -1) { - printlocale (verbose, "sr_RS@latin", - L"Serbian (Latin)", L"Serbia"); - printlocale (verbose, "sr_RS", - L"Serbian (Cyrillic)", L"Serbia"); - printlocale (verbose, "sr_ME@latin", - L"Serbian (Latin)", L"Montenegro"); - printlocale (verbose, "sr_ME", - L"Serbian (Cyrillic)", L"Montenegro"); + add_locale ("sr_RS@latin", L"Serbian (Latin)", L"Serbia"); + add_locale ("sr_RS", L"Serbian (Cyrillic)", L"Serbia"); + add_locale ("sr_ME@latin", L"Serbian (Latin)", L"Montenegro"); + add_locale ("sr_ME", L"Serbian (Cyrillic)", L"Montenegro"); } } } + /* First sort allows add_locale_alias_locales to bsearch in locales. */ + qsort (locale, loc_num, sizeof (loc_t), compare_locales); + add_locale_alias_locales (); + qsort (locale, loc_num, sizeof (loc_t), compare_locales); + for (size_t i = 0; i < loc_num; ++i) + print_locale (verbose, &locale[i]); } void