]> sourceware.org Git - newlib-cygwin.git/blame - winsup/utils/locale.cc
* winlean.h (__STRALIGN_H_): Drop definition.
[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 */
92b499ac 26#include <errno.h>
ce4f5f76 27#include <stdio.h>
a2036998 28#include <ctype.h>
ce4f5f76
CV
29#include <getopt.h>
30#include <string.h>
31#include <wchar.h>
32#include <locale.h>
33#include <langinfo.h>
34#include <limits.h>
a2036998 35#include <sys/cygwin.h>
9198ac4d 36#include <cygwin/version.h>
ce4f5f76
CV
37#define WINVER 0x0601
38#include <windows.h>
39
a2036998
CV
40#define LOCALE_ALIAS "/usr/share/locale/locale.alias"
41#define LOCALE_ALIAS_LINE_LEN 255
42
9198ac4d
CV
43void
44usage ()
45{
46 printf (
47"Usage: %1$s [-amvhV]\n"
48" or: %1$s [-ck] NAME\n"
49" or: %1$s [-usfnU]\n"
92b499ac 50"\n"
9198ac4d
CV
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",
92b499ac 77 program_invocation_short_name);
9198ac4d 78}
ce4f5f76
CV
79
80void
9198ac4d 81print_version ()
ce4f5f76 82{
92b499ac
CV
83 printf ("locale (cygwin) %d.%d.%d\n"
84 "Get locale-specific information\n"
85 "Copyright (C) 2010 - %s Red Hat, Inc.\n"
86 "This is free software; see the source for copying conditions. There is NO\n"
87 "warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.\n",
9198ac4d
CV
88 CYGWIN_VERSION_DLL_MAJOR / 1000,
89 CYGWIN_VERSION_DLL_MAJOR % 1000,
90 CYGWIN_VERSION_DLL_MINOR,
92b499ac 91 strrchr (__DATE__, ' ') + 1);
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 {
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);
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)
1b23b30b 527 fputc (';', stdout);
f13fe164
CV
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)
1b23b30b 696 {
ce4f5f76
CV
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 {
1b23b30b 749 print_lc (cat, key, c->category, NULL, c->lc_names);
ce4f5f76
CV
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 {
1b23b30b 756 print_lc (cat, key, c->category, lc->name, lc);
ce4f5f76
CV
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, "");
92b499ac 788 while ((opt = getopt_long (argc, argv, opts, longopts, NULL)) != -1)
ce4f5f76
CV
789 switch (opt)
790 {
791 case 'a':
1b23b30b 792 all = 1;
ce4f5f76
CV
793 break;
794 case 'c':
1b23b30b 795 cat = 1;
ce4f5f76
CV
796 break;
797 case 'k':
1b23b30b 798 key = 1;
ce4f5f76
CV
799 break;
800 case 'm':
801 maps = 1;
802 break;
803 case 's':
1b23b30b 804 lcid = GetSystemDefaultUILanguage ();
ce4f5f76
CV
805 break;
806 case 'u':
1b23b30b 807 lcid = GetUserDefaultUILanguage ();
9198ac4d
CV
808 break;
809 case 'f':
1b23b30b 810 lcid = GetUserDefaultLCID ();
9198ac4d
CV
811 break;
812 case 'n':
1b23b30b 813 lcid = GetSystemDefaultLCID ();
ce4f5f76
CV
814 break;
815 case 'U':
1b23b30b 816 utf = ".UTF-8";
ce4f5f76
CV
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:
92b499ac
CV
828 fprintf (stderr, "Try `%s --help' for more information.\n",
829 program_invocation_short_name);
9198ac4d 830 return 1;
ce4f5f76
CV
831 }
832 if (all)
833 print_all_locales (verbose);
834 else if (maps)
835 print_charmaps ();
836 else if (lcid)
837 {
838 if (getlocale (lcid, name))
839 printf ("%s%s\n", name, utf);
840 }
841 else if (optind < argc)
842 while (optind < argc)
843 print_names (cat, key, argv[optind++]);
844 else
845 print_lc ();
846 return 0;
847}
This page took 0.143968 seconds and 5 git commands to generate.