]> sourceware.org Git - newlib-cygwin.git/blame - winsup/utils/locale.cc
include/elf/
[newlib-cygwin.git] / winsup / utils / locale.cc
CommitLineData
ce4f5f76 1/*
3728c79d 2 * Copyright (c) 2010, 2011 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 */
26#include <stdio.h>
a2036998 27#include <ctype.h>
ce4f5f76
CV
28#include <getopt.h>
29#include <string.h>
30#include <wchar.h>
31#include <locale.h>
32#include <langinfo.h>
33#include <limits.h>
a2036998 34#include <sys/cygwin.h>
9198ac4d 35#include <cygwin/version.h>
ce4f5f76
CV
36#define WINVER 0x0601
37#include <windows.h>
38
a2036998
CV
39#define LOCALE_ALIAS "/usr/share/locale/locale.alias"
40#define LOCALE_ALIAS_LINE_LEN 255
41
ce4f5f76
CV
42extern char *__progname;
43
9198ac4d
CV
44void
45usage ()
46{
47 printf (
48"Usage: %1$s [-amvhV]\n"
49" or: %1$s [-ck] NAME\n"
50" or: %1$s [-usfnU]\n"
51"Get locale-specific information.\n"
52"\n"
53"System information:\n"
54"\n"
55" -a, --all-locales List all available supported locales\n"
56" -m, --charmaps List all available character maps\n"
57" -v, --verbose More verbose output\n"
58"\n"
59"Modify output format:\n"
60"\n"
61" -c, --category-name List information about given category NAME\n"
62" -k, --keyword-name Print information about given keyword NAME\n"
63"\n"
64"Default locale information:\n"
65"\n"
66" -u, --user Print locale of user's default UI language\n"
67" -s, --system Print locale of system default UI language\n"
68" -f, --format Print locale of user's regional format settings\n"
69" (time, numeric & monetary)\n"
70" -n, --no-unicode Print system default locale for non-Unicode programs\n"
71" -U, --utf Attach \".UTF-8\" to the result\n"
72"\n"
73"Other options:\n"
74"\n"
75" -h, --help This text\n"
76" -V, --version Print program version and exit\n\n",
77 __progname);
78}
ce4f5f76
CV
79
80void
9198ac4d 81print_version ()
ce4f5f76 82{
9198ac4d
CV
83 printf ("%s (cygwin) %d.%d.%d\n"
84 "Get locale-specific information.\n"
85 "Copyright 2011 Red Hat, Inc.\n"
86 "Compiled on %s\n",
87 __progname,
88 CYGWIN_VERSION_DLL_MAJOR / 1000,
89 CYGWIN_VERSION_DLL_MAJOR % 1000,
90 CYGWIN_VERSION_DLL_MINOR,
91 __DATE__);
ce4f5f76
CV
92}
93
94struct option longopts[] = {
95 {"all-locales", no_argument, NULL, 'a'},
96 {"category-name", no_argument, NULL, 'c'},
9198ac4d
CV
97 {"format", no_argument, NULL, 'f'},
98 {"help", no_argument, NULL, 'h'},
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};
9198ac4d 109const char *opts = "acfhkmnsuUvV";
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 {
157 char sysbuf[PATH_MAX];
71d8f118
CV
158 HMODULE k32 = GetModuleHandleW (L"kernel32.dll");
159 if (GetModuleFileName (k32, sysbuf, PATH_MAX))
160 sysroot = (const char *) cygwin_create_path (CCP_WIN_A_TO_POSIX,
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)
254 *c = '\0';
255 c = alias_buf;
256 c += strspn (c, " \t");
257 if (!*c || *c == '#')
258 continue;
259 alias = c;
260 c += strcspn (c, " \t");
261 *c++ = '\0';
262 c += strspn (c, " \t");
263 if (*c == '#')
264 continue;
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);
328 /* Convert old sr_SP silently to sr_CS on old systems.
329 Make sure sr_CS country is in recent shape. */
330 if (lang == LANG_SERBIAN
331 && (sublang == SUBLANG_SERBIAN_LATIN
332 || sublang == SUBLANG_SERBIAN_CYRILLIC))
333 {
334 c = stpcpy (loc, "sr_CS");
335 wcscpy (country, L"Serbia and Montenegro (Former)");
336 }
337 /* Now check certain conditions to figure out if that
338 locale requires a modifier. */
339 if (lang == LANG_SERBIAN && !strncmp (loc, "sr_", 3)
340 && wcsstr (language, L"(Latin)"))
341 stpcpy (c, "@latin");
342 else if (lang == LANG_UZBEK
343 && sublang == SUBLANG_UZBEK_CYRILLIC)
344 stpcpy (c, "@cyrillic");
345 /* Avoid more dups */
346 for (i = 0; i < lcnt; ++ i)
347 if (!strcmp (loc_list[i].loc, loc))
348 {
349 lcnt++;
350 break;
351 }
352 if (i < lcnt)
353 continue;
354 if (lcnt < 32)
355 strcpy (loc_list[lcnt++].loc, loc);
356 /* Print */
a2036998 357 add_locale (loc, language, country);
ce4f5f76
CV
358 /* Check for locales which sport a modifier for
359 changing the codeset and other stuff. */
360 if (lang == LANG_BELARUSIAN
361 && sublang == SUBLANG_BELARUSIAN_BELARUS)
362 stpcpy (c, "@latin");
363 else if (lang == LANG_TATAR
364 && sublang == SUBLANG_TATAR_RUSSIA)
365 stpcpy (c, "@iqtelif");
366 else if (GetLocaleInfoW (lcid,
367 LOCALE_IDEFAULTANSICODEPAGE
368 | LOCALE_RETURN_NUMBER,
369 (PWCHAR) &cp, sizeof cp)
370 && cp == 1252 /* Latin1*/
371 && GetLocaleInfoW (lcid, LOCALE_SINTLSYMBOL, wbuf, 9)
372 && !wcsncmp (wbuf, L"EUR", 3))
373 stpcpy (c, "@euro");
374 else if (lang == LANG_JAPANESE
375 || lang == LANG_KOREAN
376 || lang == LANG_CHINESE)
377 stpcpy (c, "@cjknarrow");
378 else
379 continue;
a2036998 380 add_locale (loc, language, country);
ce4f5f76
CV
381 }
382 }
383 /* Check Serbian language for the available territories. Up to
384 Server 2003 we only had sr_SP (silently converted to sr_CS
385 above), in Vista we had only sr_CS. First starting with W7 we
386 have the actual sr_RS and sr_ME. However, all of them are
387 supported on all systems in Cygwin. So we fake them here, if
388 they are missing. */
389 if (lang == LANG_SERBIAN)
390 {
391 int sr_CS_idx = -1;
392 int sr_RS_idx = -1;
393 int i;
394
395 for (i = 0; i < lcnt; ++ i)
396 if (!strcmp (loc_list[i].loc, "sr_CS"))
397 sr_CS_idx = i;
398 else if (!strcmp (loc_list[i].loc, "sr_RS"))
399 sr_RS_idx = i;
400 if (sr_CS_idx > 0 && sr_RS_idx == -1)
401 {
a2036998
CV
402 add_locale ("sr_RS@latin", L"Serbian (Latin)", L"Serbia");
403 add_locale ("sr_RS", L"Serbian (Cyrillic)", L"Serbia");
404 add_locale ("sr_ME@latin", L"Serbian (Latin)", L"Montenegro");
405 add_locale ("sr_ME", L"Serbian (Cyrillic)", L"Montenegro");
ce4f5f76
CV
406 }
407 }
408 }
a2036998
CV
409 /* First sort allows add_locale_alias_locales to bsearch in locales. */
410 qsort (locale, loc_num, sizeof (loc_t), compare_locales);
411 add_locale_alias_locales ();
412 qsort (locale, loc_num, sizeof (loc_t), compare_locales);
413 for (size_t i = 0; i < loc_num; ++i)
414 print_locale (verbose, &locale[i]);
ce4f5f76
CV
415}
416
417void
418print_charmaps ()
419{
420 /* FIXME: We need a method to fetch the available charsets from Cygwin, */
421 const char *charmaps[] =
422 {
423 "ASCII",
424 "BIG5",
425 "CP1125",
426 "CP1250",
427 "CP1251",
428 "CP1252",
429 "CP1253",
430 "CP1254",
431 "CP1255",
432 "CP1256",
433 "CP1257",
434 "CP1258",
435 "CP437",
436 "CP720",
437 "CP737",
438 "CP775",
439 "CP850",
440 "CP852",
441 "CP855",
442 "CP857",
443 "CP858",
444 "CP862",
445 "CP866",
446 "CP874",
447 "CP932",
0b66e4d7 448 "EUC-CN",
ce4f5f76
CV
449 "EUC-JP",
450 "EUC-KR",
0b66e4d7 451 "GB2312",
ce4f5f76
CV
452 "GBK",
453 "GEORGIAN-PS",
454 "ISO-8859-1",
455 "ISO-8859-10",
456 "ISO-8859-11",
457 "ISO-8859-13",
458 "ISO-8859-14",
459 "ISO-8859-15",
460 "ISO-8859-16",
461 "ISO-8859-2",
462 "ISO-8859-3",
463 "ISO-8859-4",
464 "ISO-8859-5",
465 "ISO-8859-6",
466 "ISO-8859-7",
467 "ISO-8859-8",
468 "ISO-8859-9",
469 "KOI8-R",
470 "KOI8-U",
471 "PT154",
472 "SJIS",
473 "TIS-620",
474 "UTF-8",
475 NULL
476 };
477 const char **charmap = charmaps;
478 while (*charmap)
479 printf ("%s\n", *charmap++);
480}
481
482void
483print_lc_ivalue (int key, const char *name, int value)
484{
485 if (key)
486 printf ("%s=", name);
487 printf ("%d", value == CHAR_MAX ? -1 : value);
488 fputc ('\n', stdout);
489}
490
491void
492print_lc_svalue (int key, const char *name, const char *value)
493{
494 if (key)
495 printf ("%s=\"", name);
496 fputs (value, stdout);
497 if (key)
498 fputc ('"', stdout);
499 fputc ('\n', stdout);
500}
501
f13fe164
CV
502void
503print_lc_sepstrings (int key, const char *name, const char *value)
504{
505 char *c;
506
507 if (key)
508 printf ("%s=", name);
509 while (value && *value)
510 {
511 if (key)
512 fputc ('"', stdout);
513 c = strchr (value, ';');
514 if (!c)
515 {
516 fputs (value, stdout);
517 value = NULL;
518 }
519 else
520 {
521 printf ("%.*s", c - value, value);
522 value = c + 1;
523 }
524 if (key)
525 fputc ('"', stdout);
526 if (value && *value)
527 fputc (';', stdout);
528 }
529 fputc ('\n', stdout);
530}
531
ce4f5f76
CV
532void
533print_lc_strings (int key, const char *name, int from, int to)
534{
535 if (key)
536 printf ("%s=\"", name);
537 for (int i = from; i <= to; ++i)
538 printf ("%s%s", i > from ? ";" : "", nl_langinfo (i));
539 if (key)
540 fputc ('"', stdout);
541 fputc ('\n', stdout);
542}
543
ce4f5f76
CV
544void
545print_lc_grouping (int key, const char *name, const char *grouping)
546{
547 if (key)
548 printf ("%s=", name);
549 for (const char *g = grouping; *g; ++g)
550 printf ("%s%d", g > grouping ? ";" : "", *g == CHAR_MAX ? -1 : *g);
551 fputc ('\n', stdout);
552}
553
554enum type_t
555{
556 is_string_fake,
22b6e810
CV
557 is_grouping,
558 is_string,
559 is_mstrings,
560 is_sepstrings,
561 is_int,
562 is_wchar,
ce4f5f76
CV
563 is_end
564};
565
566struct lc_names_t
567{
568 const char *name;
569 type_t type;
570 size_t fromval;
571 size_t toval;
572};
573
ce4f5f76
CV
574const char *fake_string[] = {
575 "upper;lower;alpha;digit;xdigit;space;print;graph;blank;cntrl;punct;alnum",
576 "upper\";\"lower\";\"alpha\";\"digit\";\"xdigit\";\"space\";\"print\";\"graph\";\"blank\";\"cntrl\";\"punct\";\"alnum",
577 "toupper;tolower",
578 "toupper\";\"tolower"
579};
580
581lc_names_t lc_ctype_names[] =
582{
22b6e810
CV
583 { "ctype-class-names", is_string_fake, 0, 0 },
584 { "ctype-map-names", is_string_fake, 2, 0 },
585 { "ctype-outdigit0_mb", is_string, _NL_CTYPE_OUTDIGITS0_MB, 0 },
586 { "ctype-outdigit1_mb", is_string, _NL_CTYPE_OUTDIGITS1_MB, 0 },
587 { "ctype-outdigit2_mb", is_string, _NL_CTYPE_OUTDIGITS2_MB, 0 },
588 { "ctype-outdigit3_mb", is_string, _NL_CTYPE_OUTDIGITS3_MB, 0 },
589 { "ctype-outdigit4_mb", is_string, _NL_CTYPE_OUTDIGITS4_MB, 0 },
590 { "ctype-outdigit5_mb", is_string, _NL_CTYPE_OUTDIGITS5_MB, 0 },
591 { "ctype-outdigit6_mb", is_string, _NL_CTYPE_OUTDIGITS6_MB, 0 },
592 { "ctype-outdigit7_mb", is_string, _NL_CTYPE_OUTDIGITS7_MB, 0 },
593 { "ctype-outdigit8_mb", is_string, _NL_CTYPE_OUTDIGITS8_MB, 0 },
594 { "ctype-outdigit9_mb", is_string, _NL_CTYPE_OUTDIGITS9_MB, 0 },
595 { "ctype-outdigit0_wc", is_wchar, _NL_CTYPE_OUTDIGITS0_WC, 0 },
596 { "ctype-outdigit1_wc", is_wchar, _NL_CTYPE_OUTDIGITS1_WC, 0 },
597 { "ctype-outdigit2_wc", is_wchar, _NL_CTYPE_OUTDIGITS2_WC, 0 },
598 { "ctype-outdigit3_wc", is_wchar, _NL_CTYPE_OUTDIGITS3_WC, 0 },
599 { "ctype-outdigit4_wc", is_wchar, _NL_CTYPE_OUTDIGITS4_WC, 0 },
600 { "ctype-outdigit5_wc", is_wchar, _NL_CTYPE_OUTDIGITS5_WC, 0 },
601 { "ctype-outdigit6_wc", is_wchar, _NL_CTYPE_OUTDIGITS6_WC, 0 },
602 { "ctype-outdigit7_wc", is_wchar, _NL_CTYPE_OUTDIGITS7_WC, 0 },
603 { "ctype-outdigit8_wc", is_wchar, _NL_CTYPE_OUTDIGITS8_WC, 0 },
604 { "ctype-outdigit9_wc", is_wchar, _NL_CTYPE_OUTDIGITS9_WC, 0 },
605 { "charmap", is_string, CODESET, 0 },
606 { "ctype-mb-cur-max", is_int, _NL_CTYPE_MB_CUR_MAX, 0 },
607 { NULL, is_end, 0, 0 }
ce4f5f76
CV
608};
609
610lc_names_t lc_numeric_names[] =
611{
22b6e810
CV
612 { "decimal_point", is_string, RADIXCHAR, 0 },
613 { "thousands_sep", is_string, THOUSEP, 0 },
614 { "grouping", is_grouping, _NL_NUMERIC_GROUPING, 0 },
615 { "numeric-decimal-point-wc", is_wchar, _NL_NUMERIC_DECIMAL_POINT_WC, 0 },
616 { "numeric-thousands-sep-wc", is_wchar, _NL_NUMERIC_THOUSANDS_SEP_WC, 0 },
617 { "numeric-codeset", is_string, _NL_NUMERIC_CODESET, 0 },
618 { NULL, is_end, 0, 0 }
ce4f5f76
CV
619};
620
621lc_names_t lc_time_names[] =
622{
22b6e810
CV
623 { "abday", is_mstrings, ABDAY_1, ABDAY_7 },
624 { "day", is_mstrings, DAY_1, DAY_7 },
625 { "abmon", is_mstrings, ABMON_1, ABMON_12 },
626 { "mon", is_mstrings, MON_1, MON_12 },
627 { "am_pm", is_mstrings, AM_STR, PM_STR },
628 { "d_t_fmt", is_string, D_T_FMT, 0 },
629 { "d_fmt", is_string, D_FMT, 0 },
630 { "t_fmt", is_string, T_FMT, 0 },
631 { "t_fmt_ampm", is_string, T_FMT_AMPM, 0 },
632 { "era", is_sepstrings, ERA, 0 },
633 { "era_d_fmt", is_string, ERA_D_FMT, 0 },
634 { "alt_digits", is_sepstrings,ALT_DIGITS, 0 },
635 { "era_d_t_fmt", is_string, ERA_D_T_FMT, 0 },
636 { "era_t_fmt", is_string, ERA_T_FMT, 0 },
637 { "date_fmt", is_string, _DATE_FMT, 0 },
638 { "time-codeset", is_string, _NL_TIME_CODESET, 0 },
639 { NULL, is_end, 0, 0 }
ce4f5f76
CV
640};
641
642lc_names_t lc_collate_names[] =
643{
22b6e810
CV
644 { "collate-codeset", is_string, _NL_COLLATE_CODESET, 0 },
645 { NULL, is_end, 0, 0 }
ce4f5f76
CV
646};
647
648lc_names_t lc_monetary_names[] =
649{
22b6e810
CV
650 { "int_curr_symbol", is_string, _NL_MONETARY_INT_CURR_SYMBOL, 0 },
651 { "currency_symbol", is_string, _NL_MONETARY_CURRENCY_SYMBOL, 0 },
652 { "mon_decimal_point", is_string, _NL_MONETARY_MON_DECIMAL_POINT, 0 },
653 { "mon_thousands_sep", is_string, _NL_MONETARY_MON_THOUSANDS_SEP, 0 },
654 { "mon_grouping", is_grouping, _NL_MONETARY_MON_GROUPING, 0 },
655 { "positive_sign", is_string, _NL_MONETARY_POSITIVE_SIGN, 0 },
656 { "negative_sign", is_string, _NL_MONETARY_NEGATIVE_SIGN, 0 },
657 { "int_frac_digits", is_int, _NL_MONETARY_INT_FRAC_DIGITS, 0 },
658 { "frac_digits", is_int, _NL_MONETARY_FRAC_DIGITS, 0 },
659 { "p_cs_precedes", is_int, _NL_MONETARY_P_CS_PRECEDES, 0 },
660 { "p_sep_by_space", is_int, _NL_MONETARY_P_SEP_BY_SPACE, 0 },
661 { "n_cs_precedes", is_int, _NL_MONETARY_N_CS_PRECEDES, 0 },
662 { "n_sep_by_space", is_int, _NL_MONETARY_N_SEP_BY_SPACE, 0 },
663 { "p_sign_posn", is_int, _NL_MONETARY_P_SIGN_POSN, 0 },
664 { "n_sign_posn", is_int, _NL_MONETARY_N_SIGN_POSN, 0 },
665 { "int_p_cs_precedes", is_int, _NL_MONETARY_INT_P_CS_PRECEDES, 0 },
666 { "int_p_sep_by_space", is_int, _NL_MONETARY_INT_P_SEP_BY_SPACE,0 },
667 { "int_n_cs_precedes", is_int, _NL_MONETARY_INT_N_CS_PRECEDES, 0 },
668 { "int_n_sep_by_space", is_int, _NL_MONETARY_INT_N_SEP_BY_SPACE,0 },
669 { "int_p_sign_posn", is_int, _NL_MONETARY_INT_P_SIGN_POSN, 0 },
670 { "int_n_sign_posn", is_int, _NL_MONETARY_INT_N_SIGN_POSN, 0 },
671 { "monetary-decimal-point-wc", is_wchar, _NL_MONETARY_WMON_DECIMAL_POINT, 0 },
672 { "monetary-thousands-sep-wc", is_wchar, _NL_MONETARY_WMON_THOUSANDS_SEP, 0 },
673 { "monetary-codeset", is_string, _NL_MONETARY_CODESET, 0 },
674 { NULL, is_end, 0, 0 }
ce4f5f76
CV
675};
676
677lc_names_t lc_messages_names[] =
678{
22b6e810
CV
679 { "yesexpr", is_string, YESEXPR, 0 },
680 { "noexpr", is_string, NOEXPR, 0 },
681 { "yesstr", is_string, YESSTR, 0 },
682 { "nostr", is_string, NOSTR, 0 },
683 { "messages-codeset", is_string, _NL_MESSAGES_CODESET, 0 },
684 { NULL, is_end, 0, 0 }
ce4f5f76
CV
685};
686
687void
688print_lc (int cat, int key, const char *category, const char *name,
689 lc_names_t *lc_name)
690{
ce4f5f76
CV
691 if (cat)
692 printf ("%s\n", category);
693 for (lc_names_t *lc = lc_name; lc->type != is_end; ++lc)
694 if (!name || !strcmp (name, lc->name))
695 switch (lc->type)
696 {
697 case is_string_fake:
698 print_lc_svalue (key, lc->name, fake_string[lc->fromval + key]);
699 break;
22b6e810
CV
700 case is_grouping:
701 print_lc_grouping (key, lc->name, nl_langinfo (lc->fromval));
ce4f5f76 702 break;
22b6e810 703 case is_string:
ce4f5f76
CV
704 print_lc_svalue (key, lc->name, nl_langinfo (lc->fromval));
705 break;
22b6e810 706 case is_sepstrings:
f13fe164
CV
707 print_lc_sepstrings (key, lc->name, nl_langinfo (lc->fromval));
708 break;
22b6e810 709 case is_mstrings:
ce4f5f76
CV
710 print_lc_strings (key, lc->name, lc->fromval, lc->toval);
711 break;
22b6e810
CV
712 case is_int:
713 print_lc_ivalue (key, lc->name, (int) *nl_langinfo (lc->fromval));
ce4f5f76 714 break;
22b6e810
CV
715 case is_wchar:
716 print_lc_ivalue (key, lc->name,
717 *(wchar_t *) nl_langinfo (lc->fromval));
ce4f5f76
CV
718 break;
719 default:
720 break;
721 }
722}
723
724struct cat_t
725{
726 const char *category;
727 int lc_cat;
728 lc_names_t *lc_names;
729} categories[] =
730{
731 { "LC_CTYPE", LC_CTYPE, lc_ctype_names },
732 { "LC_NUMERIC", LC_NUMERIC, lc_numeric_names },
733 { "LC_TIME", LC_TIME, lc_time_names },
734 { "LC_COLLATE", LC_COLLATE, lc_collate_names },
735 { "LC_MONETARY", LC_MONETARY, lc_monetary_names },
736 { "LC_MESSAGES", LC_MESSAGES, lc_messages_names },
737 { NULL, 0, NULL }
738};
739
740void
741print_names (int cat, int key, const char *name)
742{
743 struct cat_t *c;
744 lc_names_t *lc;
745
746 for (c = categories; c->category; ++c)
747 if (!strcmp (name, c->category))
748 {
749 print_lc (cat, key, c->category, NULL, c->lc_names);
750 return;
751 }
752 for (c = categories; c->category; ++c)
753 for (lc = c->lc_names; lc->type != is_end; ++lc)
754 if (!strcmp (name, lc->name))
755 {
756 print_lc (cat, key, c->category, lc->name, lc);
757 return;
758 }
759}
760
761void
762print_lc ()
763{
764 printf ("LANG=%s\n", getenv ("LANG") ?: "");
765 printf ("LC_CTYPE=\"%s\"\n", setlocale (LC_CTYPE, NULL));
766 printf ("LC_NUMERIC=\"%s\"\n", setlocale (LC_NUMERIC, NULL));
767 printf ("LC_TIME=\"%s\"\n", setlocale (LC_TIME, NULL));
768 printf ("LC_COLLATE=\"%s\"\n", setlocale (LC_COLLATE, NULL));
769 printf ("LC_MONETARY=\"%s\"\n", setlocale (LC_MONETARY, NULL));
770 printf ("LC_MESSAGES=\"%s\"\n", setlocale (LC_MESSAGES, NULL));
771 printf ("LC_ALL=%s\n", getenv ("LC_ALL") ?: "");
772}
773
774int
775main (int argc, char **argv)
776{
777 int opt;
778 LCID lcid = 0;
779 int all = 0;
780 int cat = 0;
781 int key = 0;
782 int maps = 0;
783 int verbose = 0;
784 const char *utf = "";
785 char name[32];
786
787 setlocale (LC_ALL, "");
788 while ((opt = getopt_long (argc, argv, opts, longopts, NULL)) != EOF)
789 switch (opt)
790 {
791 case 'a':
792 all = 1;
793 break;
794 case 'c':
795 cat = 1;
796 break;
797 case 'k':
798 key = 1;
799 break;
800 case 'm':
801 maps = 1;
802 break;
803 case 's':
9198ac4d 804 lcid = GetSystemDefaultUILanguage ();
ce4f5f76
CV
805 break;
806 case 'u':
9198ac4d
CV
807 lcid = GetUserDefaultUILanguage ();
808 break;
809 case 'f':
810 lcid = GetUserDefaultLCID ();
811 break;
812 case 'n':
813 lcid = GetSystemDefaultLCID ();
ce4f5f76
CV
814 break;
815 case 'U':
816 utf = ".UTF-8";
817 break;
818 case 'v':
819 verbose = 1;
820 break;
821 case 'h':
9198ac4d
CV
822 usage ();
823 return 0;
824 case 'V':
825 print_version ();
826 return 0;
ce4f5f76 827 default:
9198ac4d
CV
828 fprintf (stderr,
829 "Try `%1$s --help' or `%1$s -h' for more information.\n",
830 __progname);
831 return 1;
ce4f5f76
CV
832 }
833 if (all)
834 print_all_locales (verbose);
835 else if (maps)
836 print_charmaps ();
837 else if (lcid)
838 {
839 if (getlocale (lcid, name))
840 printf ("%s%s\n", name, utf);
841 }
842 else if (optind < argc)
843 while (optind < argc)
844 print_names (cat, key, argv[optind++]);
845 else
846 print_lc ();
847 return 0;
848}
This page took 0.185874 seconds and 5 git commands to generate.