From ce4f5f76abcdc6c889bfc3815bd106e9088591cd Mon Sep 17 00:00:00 2001 From: Corinna Vinschen Date: Wed, 17 Feb 2010 15:01:56 +0000 Subject: [PATCH] * Makefile.in (CYGWIN_BINS): Rename getlocale to locale. * getlocale.c: Rename to ... * locale.cc: Revamp to add full functionality of POSIX locale(1) tool, as far as Cygwin supports it. * utils.sgml (getlocale): Move and rename to ... (locale): Accommodate new functionality. --- winsup/utils/ChangeLog | 9 + winsup/utils/Makefile.in | 2 +- winsup/utils/getlocale.c | 236 --------------- winsup/utils/locale.cc | 622 +++++++++++++++++++++++++++++++++++++++ winsup/utils/utils.sgml | 142 +++++---- 5 files changed, 719 insertions(+), 292 deletions(-) delete mode 100644 winsup/utils/getlocale.c create mode 100644 winsup/utils/locale.cc diff --git a/winsup/utils/ChangeLog b/winsup/utils/ChangeLog index 8b006f455..4c622207c 100644 --- a/winsup/utils/ChangeLog +++ b/winsup/utils/ChangeLog @@ -1,3 +1,12 @@ +2010-02-17 Corinna Vinschen + + * Makefile.in (CYGWIN_BINS): Rename getlocale to locale. + * getlocale.c: Rename to ... + * locale.cc: Revamp to add full functionality of POSIX locale(1) tool, + as far as Cygwin supports it. + * utils.sgml (getlocale): Move and rename to ... + (locale): Accommodate new functionality. + 2010-02-13 Ilguiz Latypov * cygpath.cc (do_pathconv): Fix potential crash. diff --git a/winsup/utils/Makefile.in b/winsup/utils/Makefile.in index 04ce39fad..165ac60aa 100644 --- a/winsup/utils/Makefile.in +++ b/winsup/utils/Makefile.in @@ -52,7 +52,7 @@ MINGW_CXX := ${srcdir}/mingw ${CXX} -I${updir} # List all binaries to be linked in Cygwin mode. Each binary on this list # must have a corresponding .o of the same name. -CYGWIN_BINS := ${addsuffix .exe,cygpath getfacl getlocale ldd kill mkgroup \ +CYGWIN_BINS := ${addsuffix .exe,cygpath getfacl ldd locale kill mkgroup \ mkpasswd mount passwd ps regtool setfacl setmetamode ssp umount} # List all binaries to be linked in MinGW mode. Each binary on this list diff --git a/winsup/utils/getlocale.c b/winsup/utils/getlocale.c deleted file mode 100644 index 9d6a3827a..000000000 --- a/winsup/utils/getlocale.c +++ /dev/null @@ -1,236 +0,0 @@ -/* - * Copyright (c) 2010, Corinna Vinschen - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * - * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS - * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY - * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF - * SUCH DAMAGE. - */ -#include -#include -#include -#include -#include -#define WINVER 0x0601 -#include - -extern char *__progname; - -void usage (FILE *, int) __attribute__ ((noreturn)); - -void -usage (FILE * stream, int status) -{ - fprintf (stream, - "Usage: %s [-asuh]\n" - "Print default locale or list of all supported locales\n" - "\n" - "Options:\n" - "\n" - " -a, --all List all available supported locales\n" - " -s, --system Print system default locale\n" - " (default is current user default locale)\n" - " -u, --utf Attach \".UTF-8\" to the result\n" - " -h, --help this text\n", - __progname); - exit (status); -} - -struct option longopts[] = { - {"all", no_argument, NULL, 'a'}, - {"system", no_argument, NULL, 's'}, - {"utf", no_argument, NULL, 'u'}, - {"help", no_argument, NULL, 'h'}, - {0, no_argument, NULL, 0} -}; -const char *opts = "ahsu"; - -int -getlocale (LCID lcid, char *name) -{ - char iso639[10]; - char iso3166[10]; - - iso3166[0] = '\0'; - if (!GetLocaleInfo (lcid, LOCALE_SISO639LANGNAME, iso639, 10)) - return 0; - GetLocaleInfo (lcid, LOCALE_SISO3166CTRYNAME, iso3166, 10); - sprintf (name, "%s%s%s", iso639, lcid > 0x3ff ? "_" : "", - lcid > 0x3ff ? iso3166 : ""); - return 1; -} - -int main (int argc, char **argv) -{ - int opt; - LCID lcid = LOCALE_USER_DEFAULT; - int all = 0; - const char *utf = ""; - char name[32]; - DWORD cp; - - setlocale (LC_ALL, ""); - while ((opt = getopt_long (argc, argv, opts, longopts, NULL)) != EOF) - switch (opt) - { - case 'a': - all = 1; - break; - case 's': - lcid = LOCALE_SYSTEM_DEFAULT; - break; - case 'u': - utf = ".UTF-8"; - break; - case 'h': - usage (stdout, 0); - break; - default: - usage (stderr, 1); - break; - } - if (all) - { - unsigned lang, sublang; - - for (lang = 1; lang <= 0xff; ++lang) - { - struct { - wchar_t language[256]; - wchar_t country[256]; - char loc[32]; - } loc_list[32]; - int lcnt = 0; - - for (sublang = 1; sublang <= 0x3f; ++sublang) - { - lcid = (sublang << 10) | lang; - if (getlocale (lcid, name)) - { - wchar_t language[256]; - wchar_t country[256]; - int i; - char *c, loc[32]; - wchar_t wbuf[9]; - - /* Go figure. Even the English name of a language or - locale might contain native characters. */ - GetLocaleInfoW (lcid, LOCALE_SENGLANGUAGE, language, 256); - GetLocaleInfoW (lcid, LOCALE_SENGCOUNTRY, country, 256); - /* Avoid dups */ - for (i = 0; i < lcnt; ++ i) - if (!wcscmp (loc_list[i].language, language) - && !wcscmp (loc_list[i].country, country)) - break; - if (i < lcnt) - continue; - if (lcnt < 32) - { - wcscpy (loc_list[lcnt].language, language); - wcscpy (loc_list[lcnt].country, country); - } - c = stpcpy (loc, name); - /* Convert old sr_SP silently to sr_CS on old systems. - Make sure sr_CS country is in recent shape. */ - if (lang == LANG_SERBIAN - && (sublang == SUBLANG_SERBIAN_LATIN - || sublang == SUBLANG_SERBIAN_CYRILLIC)) - { - c = stpcpy (loc, "sr_CS"); - wcscpy (country, L"Serbia and Montenegro (Former)"); - } - /* Now check certain conditions to figure out if that - locale requires a modifier. */ - if (lang == LANG_SERBIAN && !strncmp (loc, "sr_", 3) - && wcsstr (language, L"(Latin)")) - stpcpy (c, "@latin"); - else if (lang == LANG_UZBEK - && sublang == SUBLANG_UZBEK_CYRILLIC) - stpcpy (c, "@cyrillic"); - /* Avoid more dups */ - for (i = 0; i < lcnt; ++ i) - if (!strcmp (loc_list[i].loc, loc)) - { - lcnt++; - break; - } - if (i < lcnt) - continue; - if (lcnt < 32) - strcpy (loc_list[lcnt++].loc, loc); - /* Print */ - printf ("%-16s %ls (%ls)\n", loc, language, country); - /* Check for locales which sport a modifier for - changing the codeset and other stuff. */ - if (lang == LANG_BELARUSIAN - && sublang == SUBLANG_BELARUSIAN_BELARUS) - stpcpy (c, "@latin"); - else if (lang == LANG_TATAR - && sublang == SUBLANG_TATAR_RUSSIA) - stpcpy (c, "@iqtelif"); - else if (GetLocaleInfoW (lcid, - LOCALE_IDEFAULTANSICODEPAGE - | LOCALE_RETURN_NUMBER, - (PWCHAR) &cp, sizeof cp) - && cp == 1252 /* Latin1*/ - && GetLocaleInfoW (lcid, LOCALE_SINTLSYMBOL, wbuf, 9) - && !wcsncmp (wbuf, L"EUR", 3)) - stpcpy (c, "@euro"); - else if (lang == LANG_JAPANESE - || lang == LANG_KOREAN - || lang == LANG_CHINESE) - stpcpy (c, "@cjknarrow"); - else - continue; - printf ("%-16s %ls (%ls)\n", loc, language, country); - } - } - /* Check Serbian language for the available territories. Up to - Server 2003 we only had sr_SP (silently converted to sr_CS - above), in Vista we had only sr_CS. First starting with W7 we - have the actual sr_RS and sr_ME. However, all of them are - supported on all systems in Cygwin. So we fake them here, if - they are missing. */ - if (lang == LANG_SERBIAN) - { - int sr_CS_idx = -1; - int sr_RS_idx = -1; - int i; - - for (i = 0; i < lcnt; ++ i) - if (!strcmp (loc_list[i].loc, "sr_CS")) - sr_CS_idx = i; - else if (!strcmp (loc_list[i].loc, "sr_RS")) - sr_RS_idx = i; - if (sr_CS_idx > 0 && sr_RS_idx == -1) - { - puts ("sr_RS@latin Serbian (Latin) (Serbia)"); - puts ("sr_RS Serbian (Latin) (Serbia)"); - puts ("sr_ME@latin Serbian (Latin) (Montenegro)"); - puts ("sr_ME Serbian (Latin) (Montenegro)"); - } - } - } - return 0; - } - if (getlocale (lcid, name)) - printf ("%s%s\n", name, utf); - return 0; -} diff --git a/winsup/utils/locale.cc b/winsup/utils/locale.cc new file mode 100644 index 000000000..3691278d7 --- /dev/null +++ b/winsup/utils/locale.cc @@ -0,0 +1,622 @@ +/* + * Copyright (c) 2010, Corinna Vinschen + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ +#include +#include +#include +#include +#include +#include +#include +#define WINVER 0x0601 +#include + +extern char *__progname; + +void usage (FILE *, int) __attribute__ ((noreturn)); + +void +usage (FILE * stream, int status) +{ + fprintf (stream, + "Usage: %s [-amsuUvh]\n" + " or: %s [-ck] NAME\n" + "Get locale-specific information.\n" + "\n" + "Options:\n" + "\n" + " -a, --all-locales List all available supported locales\n" + " -c, --category-name List information about given category NAME\n" + " -k, --keyword-name Print information about given keyword NAME\n" + " -m, --charmaps List all available character maps\n" + " -s, --system Print system default locale\n" + " -u, --user Print user's default locale\n" + " -U, --utf Attach \".UTF-8\" to the result\n" + " -v, --verbose More verbose output\n" + " -h, --help This text\n", + __progname, __progname); + exit (status); +} + +struct option longopts[] = { + {"all-locales", no_argument, NULL, 'a'}, + {"category-name", no_argument, NULL, 'c'}, + {"keyword-name", no_argument, NULL, 'k'}, + {"charmaps", no_argument, NULL, 'm'}, + {"system", no_argument, NULL, 's'}, + {"user", no_argument, NULL, 'u'}, + {"utf", no_argument, NULL, 'U'}, + {"verbose", no_argument, NULL, 'v'}, + {"help", no_argument, NULL, 'h'}, + {0, no_argument, NULL, 0} +}; +const char *opts = "achkmsuUv"; + +int +getlocale (LCID lcid, char *name) +{ + char iso639[10]; + char iso3166[10]; + + iso3166[0] = '\0'; + if (!GetLocaleInfo (lcid, LOCALE_SISO639LANGNAME, iso639, 10)) + return 0; + GetLocaleInfo (lcid, LOCALE_SISO3166CTRYNAME, iso3166, 10); + sprintf (name, "%s%s%s", iso639, lcid > 0x3ff ? "_" : "", + lcid > 0x3ff ? iso3166 : ""); + return 1; +} + +void +printlocale (int verbose, const char *loc, + const wchar_t *lang, const wchar_t *ctry) +{ + printf ("%-16s", loc); + if (verbose) + printf ("%ls (%ls)", lang, ctry); + fputc ('\n', stdout); +} + +void +print_all_locales (int verbose) +{ + LCID lcid = 0; + char name[32]; + DWORD cp; + + unsigned lang, sublang; + + printlocale (verbose, "C", L"C", L"POSIX"); + printlocale (verbose, "POSIX", L"C", L"POSIX"); + for (lang = 1; lang <= 0xff; ++lang) + { + struct { + wchar_t language[256]; + wchar_t country[256]; + char loc[32]; + } loc_list[32]; + int lcnt = 0; + + for (sublang = 1; sublang <= 0x3f; ++sublang) + { + lcid = (sublang << 10) | lang; + if (getlocale (lcid, name)) + { + wchar_t language[256]; + wchar_t country[256]; + int i; + char *c, loc[32]; + wchar_t wbuf[9]; + + /* Go figure. Even the English name of a language or + locale might contain native characters. */ + GetLocaleInfoW (lcid, LOCALE_SENGLANGUAGE, language, 256); + GetLocaleInfoW (lcid, LOCALE_SENGCOUNTRY, country, 256); + /* Avoid dups */ + for (i = 0; i < lcnt; ++ i) + if (!wcscmp (loc_list[i].language, language) + && !wcscmp (loc_list[i].country, country)) + break; + if (i < lcnt) + continue; + if (lcnt < 32) + { + wcscpy (loc_list[lcnt].language, language); + wcscpy (loc_list[lcnt].country, country); + } + c = stpcpy (loc, name); + /* Convert old sr_SP silently to sr_CS on old systems. + Make sure sr_CS country is in recent shape. */ + if (lang == LANG_SERBIAN + && (sublang == SUBLANG_SERBIAN_LATIN + || sublang == SUBLANG_SERBIAN_CYRILLIC)) + { + c = stpcpy (loc, "sr_CS"); + wcscpy (country, L"Serbia and Montenegro (Former)"); + } + /* Now check certain conditions to figure out if that + locale requires a modifier. */ + if (lang == LANG_SERBIAN && !strncmp (loc, "sr_", 3) + && wcsstr (language, L"(Latin)")) + stpcpy (c, "@latin"); + else if (lang == LANG_UZBEK + && sublang == SUBLANG_UZBEK_CYRILLIC) + stpcpy (c, "@cyrillic"); + /* Avoid more dups */ + for (i = 0; i < lcnt; ++ i) + if (!strcmp (loc_list[i].loc, loc)) + { + lcnt++; + break; + } + if (i < lcnt) + continue; + if (lcnt < 32) + strcpy (loc_list[lcnt++].loc, loc); + /* Print */ + printlocale (verbose, loc, language, country); + /* Check for locales which sport a modifier for + changing the codeset and other stuff. */ + if (lang == LANG_BELARUSIAN + && sublang == SUBLANG_BELARUSIAN_BELARUS) + stpcpy (c, "@latin"); + else if (lang == LANG_TATAR + && sublang == SUBLANG_TATAR_RUSSIA) + stpcpy (c, "@iqtelif"); + else if (GetLocaleInfoW (lcid, + LOCALE_IDEFAULTANSICODEPAGE + | LOCALE_RETURN_NUMBER, + (PWCHAR) &cp, sizeof cp) + && cp == 1252 /* Latin1*/ + && GetLocaleInfoW (lcid, LOCALE_SINTLSYMBOL, wbuf, 9) + && !wcsncmp (wbuf, L"EUR", 3)) + stpcpy (c, "@euro"); + else if (lang == LANG_JAPANESE + || lang == LANG_KOREAN + || lang == LANG_CHINESE) + stpcpy (c, "@cjknarrow"); + else + continue; + printlocale (verbose, loc, language, country); + } + } + /* Check Serbian language for the available territories. Up to + Server 2003 we only had sr_SP (silently converted to sr_CS + above), in Vista we had only sr_CS. First starting with W7 we + have the actual sr_RS and sr_ME. However, all of them are + supported on all systems in Cygwin. So we fake them here, if + they are missing. */ + if (lang == LANG_SERBIAN) + { + int sr_CS_idx = -1; + int sr_RS_idx = -1; + int i; + + for (i = 0; i < lcnt; ++ i) + if (!strcmp (loc_list[i].loc, "sr_CS")) + sr_CS_idx = i; + else if (!strcmp (loc_list[i].loc, "sr_RS")) + 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"); + } + } + } +} + +void +print_charmaps () +{ + /* FIXME: We need a method to fetch the available charsets from Cygwin, */ + const char *charmaps[] = + { + "ASCII", + "BIG5", + "CP1125", + "CP1250", + "CP1251", + "CP1252", + "CP1253", + "CP1254", + "CP1255", + "CP1256", + "CP1257", + "CP1258", + "CP437", + "CP720", + "CP737", + "CP775", + "CP850", + "CP852", + "CP855", + "CP857", + "CP858", + "CP862", + "CP866", + "CP874", + "CP932", + "EUC-JP", + "EUC-KR", + "GBK", + "GEORGIAN-PS", + "ISO-8859-1", + "ISO-8859-10", + "ISO-8859-11", + "ISO-8859-13", + "ISO-8859-14", + "ISO-8859-15", + "ISO-8859-16", + "ISO-8859-2", + "ISO-8859-3", + "ISO-8859-4", + "ISO-8859-5", + "ISO-8859-6", + "ISO-8859-7", + "ISO-8859-8", + "ISO-8859-9", + "KOI8-R", + "KOI8-U", + "PT154", + "SJIS", + "TIS-620", + "UTF-8", + NULL + }; + const char **charmap = charmaps; + while (*charmap) + printf ("%s\n", *charmap++); +} + +void +print_lc_ivalue (int key, const char *name, int value) +{ + if (key) + printf ("%s=", name); + printf ("%d", value == CHAR_MAX ? -1 : value); + fputc ('\n', stdout); +} + +void +print_lc_svalue (int key, const char *name, const char *value) +{ + if (key) + printf ("%s=\"", name); + fputs (value, stdout); + if (key) + fputc ('"', stdout); + fputc ('\n', stdout); +} + +void +print_lc_strings (int key, const char *name, int from, int to) +{ + if (key) + printf ("%s=\"", name); + for (int i = from; i <= to; ++i) + printf ("%s%s", i > from ? ";" : "", nl_langinfo (i)); + if (key) + fputc ('"', stdout); + fputc ('\n', stdout); +} + +void +print_lc_xxx_charset (int key, int lc_cat, const char *name) +{ + char lc_ctype_locale[32]; + char lc_xxx_locale[32]; + + strcpy (lc_ctype_locale, setlocale (LC_CTYPE, NULL)); + strcpy (lc_xxx_locale, setlocale (lc_cat, NULL)); + setlocale (LC_CTYPE, lc_xxx_locale); + print_lc_svalue (key, name, nl_langinfo (CODESET)); + setlocale (LC_CTYPE, lc_ctype_locale); +} + +void +print_lc_grouping (int key, const char *name, const char *grouping) +{ + if (key) + printf ("%s=", name); + for (const char *g = grouping; *g; ++g) + printf ("%s%d", g > grouping ? ";" : "", *g == CHAR_MAX ? -1 : *g); + fputc ('\n', stdout); +} + +enum type_t +{ + is_string_fake, + is_string_lconv, + is_int_lconv, + is_grouping_lconv, + is_string_linf, + is_mstrings_linf, + is_mb_cur_max, + is_codeset, + is_end +}; + +struct lc_names_t +{ + const char *name; + type_t type; + size_t fromval; + size_t toval; +}; + +#define _O(M) __builtin_offsetof (struct lconv, M) +#define _MS(l,lc) (*(const char **)(((const char *)(l))+(lc)->fromval)) +#define _MI(l,lc) ((int)*(((const char *)(l))+(lc)->fromval)) + +const char *fake_string[] = { + "upper;lower;alpha;digit;xdigit;space;print;graph;blank;cntrl;punct;alnum", + "upper\";\"lower\";\"alpha\";\"digit\";\"xdigit\";\"space\";\"print\";\"graph\";\"blank\";\"cntrl\";\"punct\";\"alnum", + "toupper;tolower", + "toupper\";\"tolower" +}; + +lc_names_t lc_ctype_names[] = +{ + { "ctype-class-names",is_string_fake, 0, 0 }, + { "ctype-map-names", is_string_fake, 2, 0 }, + { "charmap", is_string_linf, CODESET, 0 }, + { "ctype-mb-cur-max", is_mb_cur_max, 0, 0 }, + { NULL, is_end, 0, 0 } +}; + +lc_names_t lc_numeric_names[] = +{ + { "decimal_point", is_string_lconv, _O(decimal_point), 0 }, + { "thousands_sep", is_string_lconv, _O(thousands_sep), 0 }, + { "grouping", is_grouping_lconv, _O(grouping), 0 }, + { "numeric-codeset", is_codeset, LC_NUMERIC, 0 }, + { NULL, is_end, 0, 0 } +}; + +lc_names_t lc_time_names[] = +{ + { "abday", is_mstrings_linf, ABDAY_1, ABDAY_7 }, + { "day", is_mstrings_linf, DAY_1, DAY_7 }, + { "abmon", is_mstrings_linf, ABMON_1, ABMON_12 }, + { "mon", is_mstrings_linf, MON_1, MON_12 }, + { "am_pm", is_mstrings_linf, AM_STR, PM_STR }, + { "d_t_fmt", is_string_linf, D_T_FMT, 0 }, + { "d_fmt", is_string_linf, D_FMT, 0 }, + { "t_fmt", is_string_linf, T_FMT, 0 }, + { "t_fmt_ampm", is_string_linf, T_FMT_AMPM, 0 }, + { "era", is_string_linf, ERA, 0 }, + { "era_d_fmt", is_string_linf, ERA_D_FMT, 0 }, + { "alt_digits", is_string_linf, ALT_DIGITS, 0 }, + { "era_d_t_fmt", is_string_linf, ERA_D_T_FMT, 0 }, + { "era_t_fmt", is_string_linf, ERA_T_FMT, 0 }, + { "time-codeset", is_codeset, LC_TIME, 0 }, + { NULL, is_end, 0, 0 } +}; + +lc_names_t lc_collate_names[] = +{ + { "collate-codeset", is_codeset, LC_COLLATE, 0 }, + { NULL, is_end, 0, 0 } +}; + +lc_names_t lc_monetary_names[] = +{ + { "int_curr_symbol", is_string_lconv, _O(int_curr_symbol), 0 }, + { "currency_symbol", is_string_lconv, _O(currency_symbol), 0 }, + { "mon_decimal_point",is_string_lconv, _O(mon_decimal_point), 0 }, + { "mon_thousands_sep",is_string_lconv, _O(mon_thousands_sep), 0 }, + { "mon_grouping", is_grouping_lconv, _O(mon_grouping), 0 }, + { "positive_sign", is_string_lconv, _O(positive_sign), 0 }, + { "negative_sign", is_string_lconv, _O(negative_sign), 0 }, + { "int_frac_digits", is_int_lconv, _O(int_frac_digits), 0 }, + { "frac_digits", is_int_lconv, _O(frac_digits), 0 }, + { "p_cs_precedes", is_int_lconv, _O(p_cs_precedes), 0 }, + { "p_sep_by_space", is_int_lconv, _O(p_sep_by_space), 0 }, + { "n_cs_precedes", is_int_lconv, _O(n_cs_precedes), 0 }, + { "n_sep_by_space", is_int_lconv, _O(n_sep_by_space), 0 }, + { "p_sign_posn", is_int_lconv, _O(p_sign_posn), 0 }, + { "n_sign_posn", is_int_lconv, _O(n_sign_posn), 0 }, + { "int_p_cs_precedes",is_int_lconv, _O(int_p_cs_precedes), 0 }, + { "int_p_sep_by_space",is_int_lconv, _O(int_p_sep_by_space), 0 }, + { "int_n_cs_precedes",is_int_lconv, _O(int_n_cs_precedes), 0 }, + { "int_n_sep_by_space",is_int_lconv, _O(int_n_sep_by_space), 0 }, + { "int_p_sign_posn", is_int_lconv, _O(int_p_sign_posn), 0 }, + { "int_n_sign_posn", is_int_lconv, _O(int_n_sign_posn), 0 }, + { "monetary-codeset", is_codeset, LC_MONETARY, 0 }, + { NULL, is_end, 0, 0 } +}; + +lc_names_t lc_messages_names[] = +{ + { "yesexpr", is_string_linf, YESEXPR, 0 }, + { "noexpr", is_string_linf, NOEXPR, 0 }, + { "yesstr", is_string_linf, YESSTR, 0 }, + { "nostr", is_string_linf, NOSTR, 0 }, + { "messages-codeset", is_codeset, LC_MESSAGES, 0 }, + { NULL, is_end, 0, 0 } +}; + +void +print_lc (int cat, int key, const char *category, const char *name, + lc_names_t *lc_name) +{ + struct lconv *l = localeconv (); + + if (cat) + printf ("%s\n", category); + for (lc_names_t *lc = lc_name; lc->type != is_end; ++lc) + if (!name || !strcmp (name, lc->name)) + switch (lc->type) + { + case is_string_fake: + print_lc_svalue (key, lc->name, fake_string[lc->fromval + key]); + break; + case is_string_lconv: + print_lc_svalue (key, lc->name, _MS (l, lc)); + break; + case is_int_lconv: + print_lc_ivalue (key, lc->name, _MI (l, lc)); + break; + case is_grouping_lconv: + print_lc_grouping (key, lc->name, _MS (l, lc)); + break; + case is_string_linf: + print_lc_svalue (key, lc->name, nl_langinfo (lc->fromval)); + break; + case is_mstrings_linf: + print_lc_strings (key, lc->name, lc->fromval, lc->toval); + break; + case is_mb_cur_max: + print_lc_ivalue (key, lc->name, MB_CUR_MAX); + break; + case is_codeset: + print_lc_xxx_charset (key, lc->fromval, lc->name); + break; + default: + break; + } +} + +struct cat_t +{ + const char *category; + int lc_cat; + lc_names_t *lc_names; +} categories[] = +{ + { "LC_CTYPE", LC_CTYPE, lc_ctype_names }, + { "LC_NUMERIC", LC_NUMERIC, lc_numeric_names }, + { "LC_TIME", LC_TIME, lc_time_names }, + { "LC_COLLATE", LC_COLLATE, lc_collate_names }, + { "LC_MONETARY", LC_MONETARY, lc_monetary_names }, + { "LC_MESSAGES", LC_MESSAGES, lc_messages_names }, + { NULL, 0, NULL } +}; + +void +print_names (int cat, int key, const char *name) +{ + struct cat_t *c; + lc_names_t *lc; + + for (c = categories; c->category; ++c) + if (!strcmp (name, c->category)) + { + print_lc (cat, key, c->category, NULL, c->lc_names); + return; + } + for (c = categories; c->category; ++c) + for (lc = c->lc_names; lc->type != is_end; ++lc) + if (!strcmp (name, lc->name)) + { + print_lc (cat, key, c->category, lc->name, lc); + return; + } +} + +void +print_lc () +{ + printf ("LANG=%s\n", getenv ("LANG") ?: ""); + printf ("LC_CTYPE=\"%s\"\n", setlocale (LC_CTYPE, NULL)); + printf ("LC_NUMERIC=\"%s\"\n", setlocale (LC_NUMERIC, NULL)); + printf ("LC_TIME=\"%s\"\n", setlocale (LC_TIME, NULL)); + printf ("LC_COLLATE=\"%s\"\n", setlocale (LC_COLLATE, NULL)); + printf ("LC_MONETARY=\"%s\"\n", setlocale (LC_MONETARY, NULL)); + printf ("LC_MESSAGES=\"%s\"\n", setlocale (LC_MESSAGES, NULL)); + printf ("LC_ALL=%s\n", getenv ("LC_ALL") ?: ""); +} + +int +main (int argc, char **argv) +{ + int opt; + LCID lcid = 0; + int all = 0; + int cat = 0; + int key = 0; + int maps = 0; + int verbose = 0; + const char *utf = ""; + char name[32]; + + setlocale (LC_ALL, ""); + while ((opt = getopt_long (argc, argv, opts, longopts, NULL)) != EOF) + switch (opt) + { + case 'a': + all = 1; + break; + case 'c': + cat = 1; + break; + case 'k': + key = 1; + break; + case 'm': + maps = 1; + break; + case 's': + lcid = LOCALE_SYSTEM_DEFAULT; + break; + case 'u': + lcid = LOCALE_USER_DEFAULT; + break; + case 'U': + utf = ".UTF-8"; + break; + case 'v': + verbose = 1; + break; + case 'h': + usage (stdout, 0); + break; + default: + usage (stderr, 1); + break; + } + if (all) + print_all_locales (verbose); + else if (maps) + print_charmaps (); + else if (lcid) + { + if (getlocale (lcid, name)) + printf ("%s%s\n", name, utf); + } + else if (optind < argc) + while (optind < argc) + print_names (cat, key, argv[optind++]); + else + print_lc (); + return 0; +} diff --git a/winsup/utils/utils.sgml b/winsup/utils/utils.sgml index 79673c274..fcd259a6d 100644 --- a/winsup/utils/utils.sgml +++ b/winsup/utils/utils.sgml @@ -501,61 +501,6 @@ The format for ACL output is as follows: -getlocale - - -Usage: getlocale [-asuh] -Print Windows locale(s) - -Options: - - -a, --all List all available locales - -s, --system Print system default locale - (default is current user default locale) - -u, --utf Attach ".UTF-8" to the result - -h, --help this text - - -getlocale without parameters just prints the -current user's Windows default locale to stdout. The -s -option prints the systems default locale instead. With the --u option getlocale appends a ".UTF-8". -This can be used in scripts to set the Cygwin locale to the Windows user -or system default, for instance, for a US-based user: - - - -bash$ export LANG=$(getlocale -u) -bash$ echo $LANG -en_US.UTF-8 - - -The -a option is helpful to learn which locales -are supported by your Windows machine. It prints all available locales, -their meaning, and the allowed modifiers. Example: - - -bash$ getlocale -a -ar_SA Arabic (Saudi Arabia) -ar_IQ Arabic (Iraq) -... -zh_TW Chinese (Traditional) (Taiwan) -zh_TW@cjknarrow Chinese (Traditional) (Taiwan) -... -de_AT German (Austria) -de_AT@euro German (Austria) -... -en_US English (United States) -en_GB English (United Kingdom) -en_AU English (Australia) -... -sr_RS Serbian (Cyrillic) (Serbia) -sr_RS@latin Serbian (Latin) (Serbia) -... - - - - kill @@ -655,6 +600,93 @@ SIGUSR2 31 user defined signal 2 +locale + + +Usage: locale [-amsuUvh] + or: locale [-ck] NAME +Get locale-specific information. + +Options: + + -a, --all-locales List all available supported locales + -c, --category-name List information about given category NAME + -k, --keyword-name Print information about given keyword NAME + -m, --charmaps List all available character maps + -s, --system Print system default locale + -u, --user Print user's default locale + -U, --utf Attach ".UTF-8" to the result + -v, --verbose More verbose output + -h, --help This text + + +locale without parameters prints information about +the current locale environment settings. + +The -u option prints the current user's Windows +default locale to stdout. The -s option prints the +systems default locale instead. With the -U option +locale appends a ".UTF-8". This can be used in scripts +to set the Cygwin locale to the Windows user or system default, for instance: + + + +bash$ export LANG=$(locale -uU) +bash$ echo $LANG +en_US.UTF-8 + + +The -a option is helpful to learn which locales +are supported by your Windows machine. It prints all available locales +and the allowed modifiers. The -v option prints +additionally the English names of the language and territory connected +to this locale. Example: + + +bash$ locale -av +ar_SA Arabic (Saudi Arabia) +ar_IQ Arabic (Iraq) +... +zh_TW Chinese (Traditional) (Taiwan) +zh_TW@cjknarrow Chinese (Traditional) (Taiwan) +... +de_AT German (Austria) +de_AT@euro German (Austria) +... +en_US English (United States) +en_GB English (United Kingdom) +en_AU English (Australia) +... +sr_RS Serbian (Cyrillic) (Serbia) +sr_RS@latin Serbian (Latin) (Serbia) +... + + +The -m option prints the names of the available +charmaps supported by Cygwin to stdout. + +Otherwise, if arguments are given, locale prints +the values assigned to these arguments. Arguments can be names of locale +categories (for instance: LC_CTYPE, LC_MONETARY), or names of keywords +supported in the locale categories (for instance: thousands_sep, charmap). +The -c option prints additionally the name of the category. +The -k option prints additionally the name of the keyword. +Example: + + +bash$ locale -ck LC_MESSAGES +LC_MESSAGES +yesexpr="^[yY]" +noexpr="^[nN]" +yesstr="yes" +nostr="no" +messages-codeset="UTF-8" +bash$ locale noexpr +^[nN] + + + + mkgroup