]> sourceware.org Git - newlib-cygwin.git/blame - winsup/utils/locale.cc
Cygwin: add 3.2.1 release file and add fixes up to this point
[newlib-cygwin.git] / winsup / utils / locale.cc
CommitLineData
ce4f5f76 1/*
61522196 2 * Copyright (c) 2010, 2011, 2012, 2013 Corinna Vinschen
ce4f5f76
CV
3 * All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
8 * 1. Redistributions of source code must retain the above copyright
9 * notice, this list of conditions and the following disclaimer.
10 * 2. Redistributions in binary form must reproduce the above copyright
11 * notice, this list of conditions and the following disclaimer in the
12 * documentation and/or other materials provided with the distribution.
13 *
14 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
15 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
16 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
17 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
18 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
19 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
20 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
21 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
22 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
23 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
24 * SUCH DAMAGE.
25 */
92b499ac 26#include <errno.h>
ce4f5f76 27#include <stdio.h>
9cfc9511 28#include <stdlib.h>
a2036998 29#include <ctype.h>
ce4f5f76
CV
30#include <getopt.h>
31#include <string.h>
32#include <wchar.h>
33#include <locale.h>
34#include <langinfo.h>
35#include <limits.h>
a2036998 36#include <sys/cygwin.h>
9198ac4d 37#include <cygwin/version.h>
d21b6359
CV
38#define _WIN32_WINNT 0x0a00
39#define WINVER 0x0a00
ce4f5f76
CV
40#include <windows.h>
41
a2036998
CV
42#define LOCALE_ALIAS "/usr/share/locale/locale.alias"
43#define LOCALE_ALIAS_LINE_LEN 255
44
e7fca6f8 45static void __attribute__ ((__noreturn__))
9198ac4d
CV
46usage ()
47{
48 printf (
49"Usage: %1$s [-amvhV]\n"
50" or: %1$s [-ck] NAME\n"
c02ac89f 51" or: %1$s [-iusfnU]\n"
92b499ac 52"\n"
9198ac4d
CV
53"Get locale-specific information.\n"
54"\n"
55"System information:\n"
56"\n"
57" -a, --all-locales List all available supported locales\n"
58" -m, --charmaps List all available character maps\n"
59" -v, --verbose More verbose output\n"
60"\n"
61"Modify output format:\n"
62"\n"
63" -c, --category-name List information about given category NAME\n"
64" -k, --keyword-name Print information about given keyword NAME\n"
65"\n"
66"Default locale information:\n"
67"\n"
c02ac89f 68" -i, --input Print current input locale\n"
9198ac4d
CV
69" -u, --user Print locale of user's default UI language\n"
70" -s, --system Print locale of system default UI language\n"
71" -f, --format Print locale of user's regional format settings\n"
72" (time, numeric & monetary)\n"
73" -n, --no-unicode Print system default locale for non-Unicode programs\n"
74" -U, --utf Attach \".UTF-8\" to the result\n"
75"\n"
76"Other options:\n"
77"\n"
78" -h, --help This text\n"
79" -V, --version Print program version and exit\n\n",
92b499ac 80 program_invocation_short_name);
e7fca6f8 81 exit (0);
9198ac4d 82}
ce4f5f76
CV
83
84void
9198ac4d 85print_version ()
ce4f5f76 86{
6e623e93 87 printf ("locale (cygwin) %d.%d.%d\n",
9198ac4d
CV
88 CYGWIN_VERSION_DLL_MAJOR / 1000,
89 CYGWIN_VERSION_DLL_MAJOR % 1000,
6e623e93 90 CYGWIN_VERSION_DLL_MINOR);
ce4f5f76
CV
91}
92
93struct option longopts[] = {
94 {"all-locales", no_argument, NULL, 'a'},
95 {"category-name", no_argument, NULL, 'c'},
9198ac4d
CV
96 {"format", no_argument, NULL, 'f'},
97 {"help", no_argument, NULL, 'h'},
c02ac89f 98 {"input", no_argument, NULL, 'i'},
ce4f5f76
CV
99 {"keyword-name", no_argument, NULL, 'k'},
100 {"charmaps", no_argument, NULL, 'm'},
9198ac4d 101 {"no-unicode", no_argument, NULL, 'n'},
ce4f5f76
CV
102 {"system", no_argument, NULL, 's'},
103 {"user", no_argument, NULL, 'u'},
104 {"utf", no_argument, NULL, 'U'},
105 {"verbose", no_argument, NULL, 'v'},
9198ac4d 106 {"version", no_argument, NULL, 'V'},
ce4f5f76
CV
107 {0, no_argument, NULL, 0}
108};
c02ac89f 109const char *opts = "acfhikmnsuUvV";
ce4f5f76
CV
110
111int
112getlocale (LCID lcid, char *name)
113{
114 char iso639[10];
115 char iso3166[10];
116
117 iso3166[0] = '\0';
118 if (!GetLocaleInfo (lcid, LOCALE_SISO639LANGNAME, iso639, 10))
119 return 0;
120 GetLocaleInfo (lcid, LOCALE_SISO3166CTRYNAME, iso3166, 10);
121 sprintf (name, "%s%s%s", iso639, lcid > 0x3ff ? "_" : "",
122 lcid > 0x3ff ? iso3166 : "");
123 return 1;
124}
125
a2036998
CV
126typedef struct {
127 const char *name;
128 const wchar_t *language;
129 const wchar_t *territory;
130 const char *codeset;
131 bool alias;
132} loc_t;
133loc_t *locale;
134size_t loc_max;
135size_t loc_num;
136
137void
138print_codeset (const char *codeset)
139{
140 for (; *codeset; ++codeset)
141 if (*codeset != '-')
142 putc (tolower ((int)(unsigned char) *codeset), stdout);
143}
144
ce4f5f76 145void
1d4c87a1
CV
146print_locale_with_codeset (int verbose, loc_t *locale, bool utf8,
147 const char *modifier)
ce4f5f76 148{
a2036998
CV
149 static const char *sysroot;
150 char locname[32];
151
152 if (verbose
153 && (!strcmp (locale->name, "C") || !strcmp (locale->name, "POSIX")))
154 return;
155 if (!sysroot)
156 {
c1af7c27 157 WCHAR sysbuf[PATH_MAX];
71d8f118 158 HMODULE k32 = GetModuleHandleW (L"kernel32.dll");
c1af7c27
CV
159 if (GetModuleFileNameW (k32, sysbuf, PATH_MAX))
160 sysroot = (const char *) cygwin_create_path (CCP_WIN_W_TO_POSIX,
71d8f118 161 sysbuf);
a2036998
CV
162 if (!sysroot)
163 sysroot = "kernel32.dll";
164 }
1d4c87a1
CV
165 snprintf (locname, 32, "%s%s%s%s", locale->name, utf8 ? ".utf8" : "",
166 modifier ? "@" : "", modifier ?: "");
a2036998
CV
167 if (verbose)
168 fputs ("locale: ", stdout);
ce4f5f76 169 if (verbose)
a2036998 170 {
3728c79d 171 printf ("%-15s ", locname);
a2036998
CV
172 printf ("archive: %s\n",
173 locale->alias ? LOCALE_ALIAS : sysroot);
174 puts ("-------------------------------------------------------------------------------");
175 printf (" language | %ls\n", locale->language);
176 printf ("territory | %ls\n", locale->territory);
3728c79d 177 printf (" codeset | %s\n\n", utf8 ? "UTF-8" : locale->codeset);
a2036998 178 }
3728c79d
CV
179 else
180 printf ("%s\n", locname);
a2036998
CV
181}
182
183void
184print_locale (int verbose, loc_t *locale)
185{
1d4c87a1 186 print_locale_with_codeset (verbose, locale, false, NULL);
a2036998
CV
187 char *modifier = strchr (locale->name, '@');
188 if (!locale->alias)
189 {
190 if (!modifier)
1d4c87a1 191 print_locale_with_codeset (verbose, locale, true, NULL);
a2036998
CV
192 else if (!strcmp (modifier, "@cjknarrow"))
193 {
194 *modifier++ = '\0';
1d4c87a1 195 print_locale_with_codeset (verbose, locale, true, modifier);
a2036998
CV
196 }
197 }
198}
199
200int
201compare_locales (const void *a, const void *b)
202{
203 const loc_t *la = (const loc_t *) a;
204 const loc_t *lb = (const loc_t *) b;
205 return strcmp (la->name, lb->name);
206}
207
208void
209add_locale (const char *name, const wchar_t *language, const wchar_t *territory,
210 bool alias = false)
211{
212 char orig_locale[32];
213
214 if (loc_num >= loc_max)
215 {
216 loc_t *tmp = (loc_t *) realloc (locale, (loc_max + 32) * sizeof (loc_t));
217 if (!tmp)
218 {
219 fprintf (stderr, "Out of memory!\n");
220 exit (1);
221 }
222 locale = tmp;
223 loc_max += 32;
224 }
225 locale[loc_num].name = strdup (name);
226 locale[loc_num].language = wcsdup (language);
227 locale[loc_num].territory = wcsdup (territory);
228 strcpy (orig_locale, setlocale (LC_CTYPE, NULL));
229 setlocale (LC_CTYPE, name);
230 locale[loc_num].codeset = strdup (nl_langinfo (CODESET));
231 setlocale (LC_CTYPE, orig_locale);
232 locale[loc_num].alias = alias;
233 ++loc_num;
234}
235
236void
237add_locale_alias_locales ()
238{
239 char alias_buf[LOCALE_ALIAS_LINE_LEN + 1], *c;
240 const char *alias, *replace;
241 char orig_locale[32];
242 loc_t search, *loc;
536ad253 243 size_t orig_loc_num = loc_num;
a2036998
CV
244
245 FILE *fp = fopen (LOCALE_ALIAS, "rt");
246 if (!fp)
247 return;
248 strcpy (orig_locale, setlocale (LC_CTYPE, NULL));
249 while (fgets (alias_buf, LOCALE_ALIAS_LINE_LEN + 1, fp))
250 {
251 alias_buf[LOCALE_ALIAS_LINE_LEN] = '\0';
252 c = strrchr (alias_buf, '\n');
253 if (c)
1b23b30b 254 *c = '\0';
a2036998
CV
255 c = alias_buf;
256 c += strspn (c, " \t");
257 if (!*c || *c == '#')
1b23b30b 258 continue;
a2036998
CV
259 alias = c;
260 c += strcspn (c, " \t");
261 *c++ = '\0';
262 c += strspn (c, " \t");
263 if (*c == '#')
1b23b30b 264 continue;
a2036998
CV
265 replace = c;
266 c += strcspn (c, " \t");
267 *c++ = '\0';
268 c = strchr (replace, '.');
269 if (c)
270 *c = '\0';
271 search.name = replace;
536ad253 272 loc = (loc_t *) bsearch (&search, locale, orig_loc_num, sizeof (loc_t),
a2036998
CV
273 compare_locales);
274 add_locale (alias, loc ? loc->language : L"", loc ? loc->territory : L"",
275 true);
276 }
277 fclose (fp);
ce4f5f76
CV
278}
279
280void
281print_all_locales (int verbose)
282{
283 LCID lcid = 0;
284 char name[32];
285 DWORD cp;
286
287 unsigned lang, sublang;
288
a2036998
CV
289 add_locale ("C", L"C", L"POSIX");
290 add_locale ("POSIX", L"C", L"POSIX", true);
ce4f5f76
CV
291 for (lang = 1; lang <= 0xff; ++lang)
292 {
293 struct {
294 wchar_t language[256];
295 wchar_t country[256];
296 char loc[32];
297 } loc_list[32];
298 int lcnt = 0;
299
300 for (sublang = 1; sublang <= 0x3f; ++sublang)
301 {
302 lcid = (sublang << 10) | lang;
303 if (getlocale (lcid, name))
304 {
305 wchar_t language[256];
306 wchar_t country[256];
307 int i;
308 char *c, loc[32];
309 wchar_t wbuf[9];
310
311 /* Go figure. Even the English name of a language or
312 locale might contain native characters. */
313 GetLocaleInfoW (lcid, LOCALE_SENGLANGUAGE, language, 256);
314 GetLocaleInfoW (lcid, LOCALE_SENGCOUNTRY, country, 256);
315 /* Avoid dups */
316 for (i = 0; i < lcnt; ++ i)
317 if (!wcscmp (loc_list[i].language, language)
318 && !wcscmp (loc_list[i].country, country))
319 break;
320 if (i < lcnt)
321 continue;
322 if (lcnt < 32)
323 {
324 wcscpy (loc_list[lcnt].language, language);
325 wcscpy (loc_list[lcnt].country, country);
326 }
327 c = stpcpy (loc, name);
ce4f5f76
CV
328 /* Now check certain conditions to figure out if that
329 locale requires a modifier. */
330 if (lang == LANG_SERBIAN && !strncmp (loc, "sr_", 3)
331 && wcsstr (language, L"(Latin)"))
332 stpcpy (c, "@latin");
333 else if (lang == LANG_UZBEK
334 && sublang == SUBLANG_UZBEK_CYRILLIC)
335 stpcpy (c, "@cyrillic");
336 /* Avoid more dups */
337 for (i = 0; i < lcnt; ++ i)
338 if (!strcmp (loc_list[i].loc, loc))
339 {
340 lcnt++;
341 break;
342 }
343 if (i < lcnt)
344 continue;
345 if (lcnt < 32)
346 strcpy (loc_list[lcnt++].loc, loc);
347 /* Print */
a2036998 348 add_locale (loc, language, country);
ce4f5f76
CV
349 /* Check for locales which sport a modifier for
350 changing the codeset and other stuff. */
351 if (lang == LANG_BELARUSIAN
352 && sublang == SUBLANG_BELARUSIAN_BELARUS)
353 stpcpy (c, "@latin");
354 else if (lang == LANG_TATAR
355 && sublang == SUBLANG_TATAR_RUSSIA)
356 stpcpy (c, "@iqtelif");
357 else if (GetLocaleInfoW (lcid,
358 LOCALE_IDEFAULTANSICODEPAGE
359 | LOCALE_RETURN_NUMBER,
360 (PWCHAR) &cp, sizeof cp)
361 && cp == 1252 /* Latin1*/
362 && GetLocaleInfoW (lcid, LOCALE_SINTLSYMBOL, wbuf, 9)
363 && !wcsncmp (wbuf, L"EUR", 3))
364 stpcpy (c, "@euro");
365 else if (lang == LANG_JAPANESE
366 || lang == LANG_KOREAN
367 || lang == LANG_CHINESE)
368 stpcpy (c, "@cjknarrow");
369 else
370 continue;
a2036998 371 add_locale (loc, language, country);
ce4f5f76
CV
372 }
373 }
b6693e7c
CV
374 /* Check Serbian language for the available territories. Vista only
375 had sr_CS. Only starting with W7 we have the actual sr_RS and sr_ME.
376 However, they are supported on Vista as well in Cygwin. So we fake
377 them here, if they are missing. */
ce4f5f76
CV
378 if (lang == LANG_SERBIAN)
379 {
380 int sr_CS_idx = -1;
381 int sr_RS_idx = -1;
382 int i;
383
384 for (i = 0; i < lcnt; ++ i)
385 if (!strcmp (loc_list[i].loc, "sr_CS"))
386 sr_CS_idx = i;
387 else if (!strcmp (loc_list[i].loc, "sr_RS"))
388 sr_RS_idx = i;
389 if (sr_CS_idx > 0 && sr_RS_idx == -1)
390 {
a2036998
CV
391 add_locale ("sr_RS@latin", L"Serbian (Latin)", L"Serbia");
392 add_locale ("sr_RS", L"Serbian (Cyrillic)", L"Serbia");
393 add_locale ("sr_ME@latin", L"Serbian (Latin)", L"Montenegro");
394 add_locale ("sr_ME", L"Serbian (Cyrillic)", L"Montenegro");
ce4f5f76
CV
395 }
396 }
397 }
a2036998
CV
398 /* First sort allows add_locale_alias_locales to bsearch in locales. */
399 qsort (locale, loc_num, sizeof (loc_t), compare_locales);
400 add_locale_alias_locales ();
401 qsort (locale, loc_num, sizeof (loc_t), compare_locales);
402 for (size_t i = 0; i < loc_num; ++i)
403 print_locale (verbose, &locale[i]);
ce4f5f76
CV
404}
405
406void
407print_charmaps ()
408{
409 /* FIXME: We need a method to fetch the available charsets from Cygwin, */
410 const char *charmaps[] =
411 {
412 "ASCII",
413 "BIG5",
414 "CP1125",
415 "CP1250",
416 "CP1251",
417 "CP1252",
418 "CP1253",
419 "CP1254",
420 "CP1255",
421 "CP1256",
422 "CP1257",
423 "CP1258",
424 "CP437",
425 "CP720",
426 "CP737",
427 "CP775",
428 "CP850",
429 "CP852",
430 "CP855",
431 "CP857",
432 "CP858",
433 "CP862",
434 "CP866",
435 "CP874",
436 "CP932",
0b66e4d7 437 "EUC-CN",
ce4f5f76
CV
438 "EUC-JP",
439 "EUC-KR",
0b66e4d7 440 "GB2312",
ce4f5f76
CV
441 "GBK",
442 "GEORGIAN-PS",
443 "ISO-8859-1",
444 "ISO-8859-10",
445 "ISO-8859-11",
446 "ISO-8859-13",
447 "ISO-8859-14",
448 "ISO-8859-15",
449 "ISO-8859-16",
450 "ISO-8859-2",
451 "ISO-8859-3",
452 "ISO-8859-4",
453 "ISO-8859-5",
454 "ISO-8859-6",
455 "ISO-8859-7",
456 "ISO-8859-8",
457 "ISO-8859-9",
458 "KOI8-R",
459 "KOI8-U",
460 "PT154",
461 "SJIS",
462 "TIS-620",
463 "UTF-8",
464 NULL
465 };
466 const char **charmap = charmaps;
467 while (*charmap)
468 printf ("%s\n", *charmap++);
469}
470
471void
472print_lc_ivalue (int key, const char *name, int value)
473{
474 if (key)
475 printf ("%s=", name);
476 printf ("%d", value == CHAR_MAX ? -1 : value);
477 fputc ('\n', stdout);
478}
479
480void
481print_lc_svalue (int key, const char *name, const char *value)
482{
483 if (key)
484 printf ("%s=\"", name);
485 fputs (value, stdout);
486 if (key)
487 fputc ('"', stdout);
488 fputc ('\n', stdout);
489}
490
f13fe164
CV
491void
492print_lc_sepstrings (int key, const char *name, const char *value)
493{
494 char *c;
495
496 if (key)
497 printf ("%s=", name);
498 while (value && *value)
499 {
500 if (key)
501 fputc ('"', stdout);
502 c = strchr (value, ';');
503 if (!c)
504 {
505 fputs (value, stdout);
506 value = NULL;
507 }
508 else
509 {
61522196 510 printf ("%.*s", (int) (c - value), value);
f13fe164
CV
511 value = c + 1;
512 }
513 if (key)
514 fputc ('"', stdout);
515 if (value && *value)
1b23b30b 516 fputc (';', stdout);
f13fe164
CV
517 }
518 fputc ('\n', stdout);
519}
520
ce4f5f76
CV
521void
522print_lc_strings (int key, const char *name, int from, int to)
523{
524 if (key)
525 printf ("%s=\"", name);
526 for (int i = from; i <= to; ++i)
527 printf ("%s%s", i > from ? ";" : "", nl_langinfo (i));
528 if (key)
529 fputc ('"', stdout);
530 fputc ('\n', stdout);
531}
532
ce4f5f76
CV
533void
534print_lc_grouping (int key, const char *name, const char *grouping)
535{
536 if (key)
537 printf ("%s=", name);
538 for (const char *g = grouping; *g; ++g)
539 printf ("%s%d", g > grouping ? ";" : "", *g == CHAR_MAX ? -1 : *g);
540 fputc ('\n', stdout);
541}
542
543enum type_t
544{
545 is_string_fake,
22b6e810
CV
546 is_grouping,
547 is_string,
548 is_mstrings,
549 is_sepstrings,
550 is_int,
551 is_wchar,
ce4f5f76
CV
552 is_end
553};
554
555struct lc_names_t
556{
557 const char *name;
558 type_t type;
559 size_t fromval;
560 size_t toval;
561};
562
ce4f5f76
CV
563const char *fake_string[] = {
564 "upper;lower;alpha;digit;xdigit;space;print;graph;blank;cntrl;punct;alnum",
565 "upper\";\"lower\";\"alpha\";\"digit\";\"xdigit\";\"space\";\"print\";\"graph\";\"blank\";\"cntrl\";\"punct\";\"alnum",
566 "toupper;tolower",
567 "toupper\";\"tolower"
568};
569
570lc_names_t lc_ctype_names[] =
571{
22b6e810
CV
572 { "ctype-class-names", is_string_fake, 0, 0 },
573 { "ctype-map-names", is_string_fake, 2, 0 },
574 { "ctype-outdigit0_mb", is_string, _NL_CTYPE_OUTDIGITS0_MB, 0 },
575 { "ctype-outdigit1_mb", is_string, _NL_CTYPE_OUTDIGITS1_MB, 0 },
576 { "ctype-outdigit2_mb", is_string, _NL_CTYPE_OUTDIGITS2_MB, 0 },
577 { "ctype-outdigit3_mb", is_string, _NL_CTYPE_OUTDIGITS3_MB, 0 },
578 { "ctype-outdigit4_mb", is_string, _NL_CTYPE_OUTDIGITS4_MB, 0 },
579 { "ctype-outdigit5_mb", is_string, _NL_CTYPE_OUTDIGITS5_MB, 0 },
580 { "ctype-outdigit6_mb", is_string, _NL_CTYPE_OUTDIGITS6_MB, 0 },
581 { "ctype-outdigit7_mb", is_string, _NL_CTYPE_OUTDIGITS7_MB, 0 },
582 { "ctype-outdigit8_mb", is_string, _NL_CTYPE_OUTDIGITS8_MB, 0 },
583 { "ctype-outdigit9_mb", is_string, _NL_CTYPE_OUTDIGITS9_MB, 0 },
584 { "ctype-outdigit0_wc", is_wchar, _NL_CTYPE_OUTDIGITS0_WC, 0 },
585 { "ctype-outdigit1_wc", is_wchar, _NL_CTYPE_OUTDIGITS1_WC, 0 },
586 { "ctype-outdigit2_wc", is_wchar, _NL_CTYPE_OUTDIGITS2_WC, 0 },
587 { "ctype-outdigit3_wc", is_wchar, _NL_CTYPE_OUTDIGITS3_WC, 0 },
588 { "ctype-outdigit4_wc", is_wchar, _NL_CTYPE_OUTDIGITS4_WC, 0 },
589 { "ctype-outdigit5_wc", is_wchar, _NL_CTYPE_OUTDIGITS5_WC, 0 },
590 { "ctype-outdigit6_wc", is_wchar, _NL_CTYPE_OUTDIGITS6_WC, 0 },
591 { "ctype-outdigit7_wc", is_wchar, _NL_CTYPE_OUTDIGITS7_WC, 0 },
592 { "ctype-outdigit8_wc", is_wchar, _NL_CTYPE_OUTDIGITS8_WC, 0 },
593 { "ctype-outdigit9_wc", is_wchar, _NL_CTYPE_OUTDIGITS9_WC, 0 },
594 { "charmap", is_string, CODESET, 0 },
595 { "ctype-mb-cur-max", is_int, _NL_CTYPE_MB_CUR_MAX, 0 },
596 { NULL, is_end, 0, 0 }
ce4f5f76
CV
597};
598
599lc_names_t lc_numeric_names[] =
600{
22b6e810
CV
601 { "decimal_point", is_string, RADIXCHAR, 0 },
602 { "thousands_sep", is_string, THOUSEP, 0 },
603 { "grouping", is_grouping, _NL_NUMERIC_GROUPING, 0 },
604 { "numeric-decimal-point-wc", is_wchar, _NL_NUMERIC_DECIMAL_POINT_WC, 0 },
605 { "numeric-thousands-sep-wc", is_wchar, _NL_NUMERIC_THOUSANDS_SEP_WC, 0 },
606 { "numeric-codeset", is_string, _NL_NUMERIC_CODESET, 0 },
607 { NULL, is_end, 0, 0 }
ce4f5f76
CV
608};
609
610lc_names_t lc_time_names[] =
611{
22b6e810
CV
612 { "abday", is_mstrings, ABDAY_1, ABDAY_7 },
613 { "day", is_mstrings, DAY_1, DAY_7 },
614 { "abmon", is_mstrings, ABMON_1, ABMON_12 },
615 { "mon", is_mstrings, MON_1, MON_12 },
616 { "am_pm", is_mstrings, AM_STR, PM_STR },
617 { "d_t_fmt", is_string, D_T_FMT, 0 },
618 { "d_fmt", is_string, D_FMT, 0 },
619 { "t_fmt", is_string, T_FMT, 0 },
620 { "t_fmt_ampm", is_string, T_FMT_AMPM, 0 },
621 { "era", is_sepstrings, ERA, 0 },
622 { "era_d_fmt", is_string, ERA_D_FMT, 0 },
623 { "alt_digits", is_sepstrings,ALT_DIGITS, 0 },
624 { "era_d_t_fmt", is_string, ERA_D_T_FMT, 0 },
625 { "era_t_fmt", is_string, ERA_T_FMT, 0 },
626 { "date_fmt", is_string, _DATE_FMT, 0 },
627 { "time-codeset", is_string, _NL_TIME_CODESET, 0 },
628 { NULL, is_end, 0, 0 }
ce4f5f76
CV
629};
630
631lc_names_t lc_collate_names[] =
632{
22b6e810
CV
633 { "collate-codeset", is_string, _NL_COLLATE_CODESET, 0 },
634 { NULL, is_end, 0, 0 }
ce4f5f76
CV
635};
636
637lc_names_t lc_monetary_names[] =
638{
22b6e810
CV
639 { "int_curr_symbol", is_string, _NL_MONETARY_INT_CURR_SYMBOL, 0 },
640 { "currency_symbol", is_string, _NL_MONETARY_CURRENCY_SYMBOL, 0 },
641 { "mon_decimal_point", is_string, _NL_MONETARY_MON_DECIMAL_POINT, 0 },
642 { "mon_thousands_sep", is_string, _NL_MONETARY_MON_THOUSANDS_SEP, 0 },
643 { "mon_grouping", is_grouping, _NL_MONETARY_MON_GROUPING, 0 },
644 { "positive_sign", is_string, _NL_MONETARY_POSITIVE_SIGN, 0 },
645 { "negative_sign", is_string, _NL_MONETARY_NEGATIVE_SIGN, 0 },
646 { "int_frac_digits", is_int, _NL_MONETARY_INT_FRAC_DIGITS, 0 },
647 { "frac_digits", is_int, _NL_MONETARY_FRAC_DIGITS, 0 },
648 { "p_cs_precedes", is_int, _NL_MONETARY_P_CS_PRECEDES, 0 },
649 { "p_sep_by_space", is_int, _NL_MONETARY_P_SEP_BY_SPACE, 0 },
650 { "n_cs_precedes", is_int, _NL_MONETARY_N_CS_PRECEDES, 0 },
651 { "n_sep_by_space", is_int, _NL_MONETARY_N_SEP_BY_SPACE, 0 },
652 { "p_sign_posn", is_int, _NL_MONETARY_P_SIGN_POSN, 0 },
653 { "n_sign_posn", is_int, _NL_MONETARY_N_SIGN_POSN, 0 },
654 { "int_p_cs_precedes", is_int, _NL_MONETARY_INT_P_CS_PRECEDES, 0 },
655 { "int_p_sep_by_space", is_int, _NL_MONETARY_INT_P_SEP_BY_SPACE,0 },
656 { "int_n_cs_precedes", is_int, _NL_MONETARY_INT_N_CS_PRECEDES, 0 },
657 { "int_n_sep_by_space", is_int, _NL_MONETARY_INT_N_SEP_BY_SPACE,0 },
658 { "int_p_sign_posn", is_int, _NL_MONETARY_INT_P_SIGN_POSN, 0 },
659 { "int_n_sign_posn", is_int, _NL_MONETARY_INT_N_SIGN_POSN, 0 },
660 { "monetary-decimal-point-wc", is_wchar, _NL_MONETARY_WMON_DECIMAL_POINT, 0 },
661 { "monetary-thousands-sep-wc", is_wchar, _NL_MONETARY_WMON_THOUSANDS_SEP, 0 },
662 { "monetary-codeset", is_string, _NL_MONETARY_CODESET, 0 },
663 { NULL, is_end, 0, 0 }
ce4f5f76
CV
664};
665
666lc_names_t lc_messages_names[] =
667{
22b6e810
CV
668 { "yesexpr", is_string, YESEXPR, 0 },
669 { "noexpr", is_string, NOEXPR, 0 },
670 { "yesstr", is_string, YESSTR, 0 },
671 { "nostr", is_string, NOSTR, 0 },
672 { "messages-codeset", is_string, _NL_MESSAGES_CODESET, 0 },
673 { NULL, is_end, 0, 0 }
ce4f5f76
CV
674};
675
676void
677print_lc (int cat, int key, const char *category, const char *name,
678 lc_names_t *lc_name)
679{
ce4f5f76
CV
680 if (cat)
681 printf ("%s\n", category);
682 for (lc_names_t *lc = lc_name; lc->type != is_end; ++lc)
683 if (!name || !strcmp (name, lc->name))
684 switch (lc->type)
1b23b30b 685 {
ce4f5f76
CV
686 case is_string_fake:
687 print_lc_svalue (key, lc->name, fake_string[lc->fromval + key]);
688 break;
22b6e810
CV
689 case is_grouping:
690 print_lc_grouping (key, lc->name, nl_langinfo (lc->fromval));
ce4f5f76 691 break;
22b6e810 692 case is_string:
ce4f5f76
CV
693 print_lc_svalue (key, lc->name, nl_langinfo (lc->fromval));
694 break;
22b6e810 695 case is_sepstrings:
f13fe164
CV
696 print_lc_sepstrings (key, lc->name, nl_langinfo (lc->fromval));
697 break;
22b6e810 698 case is_mstrings:
ce4f5f76
CV
699 print_lc_strings (key, lc->name, lc->fromval, lc->toval);
700 break;
22b6e810
CV
701 case is_int:
702 print_lc_ivalue (key, lc->name, (int) *nl_langinfo (lc->fromval));
ce4f5f76 703 break;
22b6e810
CV
704 case is_wchar:
705 print_lc_ivalue (key, lc->name,
706 *(wchar_t *) nl_langinfo (lc->fromval));
ce4f5f76
CV
707 break;
708 default:
709 break;
710 }
711}
712
713struct cat_t
714{
715 const char *category;
716 int lc_cat;
717 lc_names_t *lc_names;
718} categories[] =
719{
720 { "LC_CTYPE", LC_CTYPE, lc_ctype_names },
721 { "LC_NUMERIC", LC_NUMERIC, lc_numeric_names },
722 { "LC_TIME", LC_TIME, lc_time_names },
723 { "LC_COLLATE", LC_COLLATE, lc_collate_names },
724 { "LC_MONETARY", LC_MONETARY, lc_monetary_names },
725 { "LC_MESSAGES", LC_MESSAGES, lc_messages_names },
726 { NULL, 0, NULL }
727};
728
729void
730print_names (int cat, int key, const char *name)
731{
732 struct cat_t *c;
733 lc_names_t *lc;
734
735 for (c = categories; c->category; ++c)
736 if (!strcmp (name, c->category))
737 {
1b23b30b 738 print_lc (cat, key, c->category, NULL, c->lc_names);
ce4f5f76
CV
739 return;
740 }
741 for (c = categories; c->category; ++c)
742 for (lc = c->lc_names; lc->type != is_end; ++lc)
743 if (!strcmp (name, lc->name))
744 {
1b23b30b 745 print_lc (cat, key, c->category, lc->name, lc);
ce4f5f76
CV
746 return;
747 }
748}
749
750void
751print_lc ()
752{
753 printf ("LANG=%s\n", getenv ("LANG") ?: "");
754 printf ("LC_CTYPE=\"%s\"\n", setlocale (LC_CTYPE, NULL));
755 printf ("LC_NUMERIC=\"%s\"\n", setlocale (LC_NUMERIC, NULL));
756 printf ("LC_TIME=\"%s\"\n", setlocale (LC_TIME, NULL));
757 printf ("LC_COLLATE=\"%s\"\n", setlocale (LC_COLLATE, NULL));
758 printf ("LC_MONETARY=\"%s\"\n", setlocale (LC_MONETARY, NULL));
759 printf ("LC_MESSAGES=\"%s\"\n", setlocale (LC_MESSAGES, NULL));
760 printf ("LC_ALL=%s\n", getenv ("LC_ALL") ?: "");
761}
762
763int
764main (int argc, char **argv)
765{
766 int opt;
767 LCID lcid = 0;
768 int all = 0;
769 int cat = 0;
770 int key = 0;
771 int maps = 0;
772 int verbose = 0;
773 const char *utf = "";
774 char name[32];
775
776 setlocale (LC_ALL, "");
92b499ac 777 while ((opt = getopt_long (argc, argv, opts, longopts, NULL)) != -1)
ce4f5f76
CV
778 switch (opt)
779 {
780 case 'a':
1b23b30b 781 all = 1;
ce4f5f76
CV
782 break;
783 case 'c':
1b23b30b 784 cat = 1;
ce4f5f76
CV
785 break;
786 case 'k':
1b23b30b 787 key = 1;
ce4f5f76
CV
788 break;
789 case 'm':
790 maps = 1;
791 break;
c02ac89f
CV
792 case 'i':
793 lcid = (UINT_PTR) GetKeyboardLayout (0) & 0xffff;
794 break;
ce4f5f76 795 case 's':
1b23b30b 796 lcid = GetSystemDefaultUILanguage ();
ce4f5f76
CV
797 break;
798 case 'u':
1b23b30b 799 lcid = GetUserDefaultUILanguage ();
9198ac4d
CV
800 break;
801 case 'f':
1b23b30b 802 lcid = GetUserDefaultLCID ();
9198ac4d
CV
803 break;
804 case 'n':
1b23b30b 805 lcid = GetSystemDefaultLCID ();
ce4f5f76
CV
806 break;
807 case 'U':
1b23b30b 808 utf = ".UTF-8";
ce4f5f76
CV
809 break;
810 case 'v':
811 verbose = 1;
812 break;
813 case 'h':
9198ac4d 814 usage ();
9198ac4d
CV
815 case 'V':
816 print_version ();
817 return 0;
ce4f5f76 818 default:
92b499ac
CV
819 fprintf (stderr, "Try `%s --help' for more information.\n",
820 program_invocation_short_name);
9198ac4d 821 return 1;
ce4f5f76
CV
822 }
823 if (all)
824 print_all_locales (verbose);
825 else if (maps)
826 print_charmaps ();
827 else if (lcid)
828 {
829 if (getlocale (lcid, name))
830 printf ("%s%s\n", name, utf);
831 }
832 else if (optind < argc)
833 while (optind < argc)
834 print_names (cat, key, argv[optind++]);
835 else
836 print_lc ();
837 return 0;
838}
This page took 0.219597 seconds and 5 git commands to generate.