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