1 /* Implementation of the locale program according to POSIX 9945-2.
2 Copyright (C) 1995-1997, 1999-2008, 2009 Free Software Foundation, Inc.
3 This file is part of the GNU C Library.
4 Contributed by Ulrich Drepper <drepper@cygnus.com>, 1995.
6 This program is free software; you can redistribute it and/or modify
7 it under the terms of the GNU General Public License as published
8 by the Free Software Foundation; version 2 of the License, or
9 (at your option) any later version.
11 This program is distributed in the hope that it will be useful,
12 but WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 GNU General Public License for more details.
16 You should have received a copy of the GNU General Public License
17 along with this program; if not, write to the Free Software Foundation,
18 Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */
36 #include <stdio_ext.h>
43 #include "localeinfo.h"
44 #include "charmap-dir.h"
45 #include "../locarchive.h"
47 extern void *xmalloc (size_t __n);
48 extern char *xstrdup (const char *__str);
50 #define ARCHIVE_NAME LOCALEDIR "/locale-archive"
52 /* If set print the name of the category. */
53 static int show_category_name;
55 /* If set print the name of the item. */
56 static int show_keyword_name;
58 /* Print names of all available locales. */
61 /* Print names of all available character maps. */
62 static int do_charmaps = 0;
64 /* Nonzero if verbose output is wanted. */
67 /* Name and version of program. */
68 static void print_version (FILE *stream, struct argp_state *state);
69 void (*argp_program_version_hook) (FILE *, struct argp_state *) = print_version;
71 /* Definitions of arguments for argp functions. */
72 static const struct argp_option options[] =
74 { NULL, 0, NULL, 0, N_("System information:") },
75 { "all-locales", 'a', NULL, OPTION_NO_USAGE,
76 N_("Write names of available locales") },
77 { "charmaps", 'm', NULL, OPTION_NO_USAGE,
78 N_("Write names of available charmaps") },
79 { NULL, 0, NULL, 0, N_("Modify output format:") },
80 { "category-name", 'c', NULL, 0, N_("Write names of selected categories") },
81 { "keyword-name", 'k', NULL, 0, N_("Write names of selected keywords") },
82 { "verbose", 'v', NULL, 0, N_("Print more information") },
83 { NULL, 0, NULL, 0, NULL }
86 /* Short description of program. */
87 static const char doc[] = N_("Get locale-specific information.");
89 /* Strings for arguments in help texts. */
90 static const char args_doc[] = N_("NAME\n[-a|-m]");
92 /* Prototype for option handler. */
93 static error_t parse_opt (int key, char *arg, struct argp_state *state);
95 /* Function to print some extra text in the help message. */
96 static char *more_help (int key, const char *text, void *input);
98 /* Data structure to communicate with argp functions. */
99 static struct argp argp =
101 options, parse_opt, args_doc, doc, NULL, more_help
105 /* We don't have these constants defined because we don't use them. Give
107 #define CTYPE_MB_CUR_MIN 0
108 #define CTYPE_MB_CUR_MAX 0
109 #define CTYPE_HASH_SIZE 0
110 #define CTYPE_HASH_LAYERS 0
111 #define CTYPE_CLASS 0
112 #define CTYPE_TOUPPER_EB 0
113 #define CTYPE_TOLOWER_EB 0
114 #define CTYPE_TOUPPER_EL 0
115 #define CTYPE_TOLOWER_EL 0
117 /* Definition of the data structure which represents a category and its
128 enum { std, opt } status;
129 enum value_type value_type;
135 /* Simple helper macro. */
136 #define NELEMS(arr) ((sizeof (arr)) / (sizeof (arr[0])))
138 /* For some tricky stuff. */
139 #define NO_PAREN(Item, More...) Item, ## More
141 /* We have all categories defined in `categories.def'. Now construct
142 the description and data structure used for all categories. */
143 #define DEFINE_ELEMENT(Item, More...) { Item, ## More },
144 #define DEFINE_CATEGORY(category, name, items, postload) \
145 static struct cat_item category##_desc[] = \
150 #include "categories.def"
151 #undef DEFINE_CATEGORY
153 static struct category category[] =
155 #define DEFINE_CATEGORY(category, name, items, postload) \
156 [category] = { _NL_NUM_##category, name, NELEMS (category##_desc), \
158 #include "categories.def"
159 #undef DEFINE_CATEGORY
161 #define NCATEGORIES NELEMS (category)
164 /* Automatically set variable. */
165 extern const char *__progname;
167 /* helper function for extended name handling. */
168 extern void locale_special (const char *name, int show_category_name,
169 int show_keyword_name);
171 /* Prototypes for local functions. */
172 static void print_LC_IDENTIFICATION (void *mapped, size_t size);
173 static void print_LC_CTYPE (void *mapped, size_t size);
174 static void write_locales (void);
175 static int nameentcmp (const void *a, const void *b);
176 static int write_archive_locales (void **all_datap, char *linebuf);
177 static void write_charmaps (void);
178 static void show_locale_vars (void);
179 static void show_info (const char *name);
183 main (int argc, char *argv[])
187 /* Set initial values for global variables. */
188 show_category_name = 0;
189 show_keyword_name = 0;
191 /* Set locale. Do not set LC_ALL because the other categories must
192 not be affected (according to POSIX.2). */
193 if (setlocale (LC_CTYPE, "") == NULL)
194 error (0, errno, gettext ("Cannot set LC_CTYPE to default locale"));
195 if (setlocale (LC_MESSAGES, "") == NULL)
196 error (0, errno, gettext ("Cannot set LC_MESSAGES to default locale"));
198 /* Initialize the message catalog. */
199 textdomain (PACKAGE);
201 /* Parse and process arguments. */
202 argp_parse (&argp, argc, argv, 0, &remaining, NULL);
204 /* `-a' requests the names of all available locales. */
207 if (setlocale (LC_COLLATE, "") == NULL)
209 gettext ("Cannot set LC_COLLATE to default locale"));
214 /* `m' requests the names of all available charmaps. The names can be
215 used for the -f argument to localedef(1). */
216 if (do_charmaps != 0)
222 /* Specific information about the current locale are requested.
223 Change to this locale now. */
224 if (setlocale (LC_ALL, "") == NULL)
225 error (0, errno, gettext ("Cannot set LC_ALL to default locale"));
227 /* If no real argument is given we have to print the contents of the
228 current locale definition variables. These are LANG and the LC_*. */
229 if (remaining == argc && show_keyword_name == 0 && show_category_name == 0)
235 /* Process all given names. */
236 while (remaining < argc)
237 show_info (argv[remaining++]);
243 /* Handle program arguments. */
245 parse_opt (int key, char *arg, struct argp_state *state)
253 show_category_name = 1;
259 show_keyword_name = 1;
265 return ARGP_ERR_UNKNOWN;
272 more_help (int key, const char *text, void *input)
277 case ARGP_KEY_HELP_EXTRA:
278 /* We print some extra information. */
279 if (asprintf (&tp, gettext ("\
280 For bug reporting instructions, please see:\n\
281 %s.\n"), REPORT_BUGS_TO) < 0)
287 return (char *) text;
291 /* Print the version information. */
293 print_version (FILE *stream, struct argp_state *state)
295 fprintf (stream, "locale %s%s\n", PKGVERSION, VERSION);
296 fprintf (stream, gettext ("\
297 Copyright (C) %s Free Software Foundation, Inc.\n\
298 This is free software; see the source for copying conditions. There is NO\n\
299 warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.\n\
301 fprintf (stream, gettext ("Written by %s.\n"), "Ulrich Drepper");
305 /* Simple action function which prints arguments as strings. */
307 print_names (const void *nodep, VISIT value, int level)
309 if (value == postorder || value == leaf)
310 puts (*(char **) nodep);
315 select_dirs (const struct dirent *dirent)
319 if (strcmp (dirent->d_name, ".") != 0 && strcmp (dirent->d_name, "..") != 0)
323 #ifdef _DIRENT_HAVE_D_TYPE
324 if (dirent->d_type != DT_UNKNOWN && dirent->d_type != DT_LNK)
325 mode = DTTOIF (dirent->d_type);
330 char buf[sizeof (LOCALEDIR) + strlen (dirent->d_name) + 1];
332 stpcpy (stpcpy (stpcpy (buf, LOCALEDIR), "/"), dirent->d_name);
334 if (stat64 (buf, &st) == 0)
338 result = S_ISDIR (mode);
346 print_LC_IDENTIFICATION (void *mapped, size_t size)
348 /* Read the information from the file. */
352 unsigned int nstrings;
353 unsigned int strindex[0];
354 } *filedata = mapped;
356 if (filedata->magic == LIMAGIC (LC_IDENTIFICATION)
358 + (filedata->nstrings
359 * sizeof (unsigned int))
364 #define HANDLE(idx, name) \
365 str = ((char *) mapped \
366 + filedata->strindex[_NL_ITEM_INDEX (_NL_IDENTIFICATION_##idx)]); \
368 printf ("%9s | %s\n", name, str)
369 HANDLE (TITLE, "title");
370 HANDLE (SOURCE, "source");
371 HANDLE (ADDRESS, "address");
372 HANDLE (CONTACT, "contact");
373 HANDLE (EMAIL, "email");
374 HANDLE (TEL, "telephone");
376 HANDLE (LANGUAGE, "language");
377 HANDLE (TERRITORY, "territory");
378 HANDLE (AUDIENCE, "audience");
379 HANDLE (APPLICATION, "application");
380 HANDLE (ABBREVIATION, "abbreviation");
381 HANDLE (REVISION, "revision");
382 HANDLE (DATE, "date");
388 print_LC_CTYPE (void *mapped, size_t size)
393 unsigned int nstrings;
394 unsigned int strindex[0];
395 } *filedata = mapped;
397 if (filedata->magic == LIMAGIC (LC_CTYPE)
399 + (filedata->nstrings
400 * sizeof (unsigned int))
405 str = ((char *) mapped
406 + filedata->strindex[_NL_ITEM_INDEX (_NL_CTYPE_CODESET_NAME)]);
408 printf (" codeset | %s\n", str);
413 /* Write the names of all available locales to stdout. We have some
414 sources of the information: the contents of the locale directory
415 and the locale.alias file. To avoid duplicates and print the
416 result is a reasonable order we put all entries is a search tree
417 and print them afterwards. */
422 void *all_data = NULL;
423 struct dirent **dirents;
427 size_t alias_path_len;
429 int first_locale = 1;
431 #define PUT(name) tsearch (name, &all_data, \
432 (int (*) (const void *, const void *)) strcoll)
433 #define GET(name) tfind (name, &all_data, \
434 (int (*) (const void *, const void *)) strcoll)
436 /* `POSIX' locale is always available (POSIX.2 4.34.3). */
438 /* And so is the "C" locale. */
441 memset (linebuf, '-', sizeof (linebuf) - 1);
442 linebuf[sizeof (linebuf) - 1] = '\0';
444 /* First scan the locale archive. */
445 if (write_archive_locales (&all_data, linebuf))
448 /* Now we can look for all files in the directory. */
449 ndirents = scandir (LOCALEDIR, &dirents, select_dirs, alphasort);
450 for (cnt = 0; cnt < ndirents; ++cnt)
452 /* Test whether at least the LC_CTYPE data is there. Some
453 directories only contain translations. */
454 char buf[sizeof (LOCALEDIR) + strlen (dirents[cnt]->d_name)
455 + sizeof "/LC_IDENTIFICATION"];
459 stpcpy (enddir = stpcpy (stpcpy (stpcpy (buf, LOCALEDIR), "/"),
460 dirents[cnt]->d_name),
461 "/LC_IDENTIFICATION");
463 if (stat64 (buf, &st) == 0 && S_ISREG (st.st_mode))
465 if (verbose && GET (dirents[cnt]->d_name) == NULL)
467 /* Provide some nice output of all kinds of
472 putchar_unlocked ('\n');
475 printf ("locale: %-15.15s directory: %.*s\n%s\n",
476 dirents[cnt]->d_name, (int) (enddir - buf), buf,
479 fd = open64 (buf, O_RDONLY);
482 void *mapped = mmap64 (NULL, st.st_size, PROT_READ,
484 if (mapped != MAP_FAILED)
486 print_LC_IDENTIFICATION (mapped, st.st_size);
488 munmap (mapped, st.st_size);
493 /* Now try to get the charset information. */
494 strcpy (enddir, "/LC_CTYPE");
495 fd = open64 (buf, O_RDONLY);
496 if (fd != -1 && fstat64 (fd, &st) >= 0
497 && ((mapped = mmap64 (NULL, st.st_size, PROT_READ,
501 print_LC_CTYPE (mapped, st.st_size);
503 munmap (mapped, st.st_size);
511 /* If the verbose format is not selected we simply
512 collect the names. */
513 PUT (xstrdup (dirents[cnt]->d_name));
519 /* Now read the locale.alias files. */
520 if (argz_create_sep (LOCALE_ALIAS_PATH, ':', &alias_path, &alias_path_len))
521 error (1, errno, gettext ("while preparing output"));
524 while ((entry = argz_next (alias_path, alias_path_len, entry)))
526 static const char aliasfile[] = "/locale.alias";
528 char full_name[strlen (entry) + sizeof aliasfile];
530 stpcpy (stpcpy (full_name, entry), aliasfile);
531 fp = fopen (full_name, "rm");
533 /* Ignore non-existing files. */
536 /* No threads present. */
537 __fsetlocking (fp, FSETLOCKING_BYCALLER);
539 while (! feof_unlocked (fp))
541 /* It is a reasonable approach to use a fix buffer here
543 a) we are only interested in the first two fields
544 b) these fields must be usable as file names and so must
551 if (fgets_unlocked (buf, BUFSIZ, fp) == NULL)
556 /* Ignore leading white space. */
557 while (isspace (cp[0]) && cp[0] != '\n')
560 /* A leading '#' signals a comment line. */
561 if (cp[0] != '\0' && cp[0] != '#' && cp[0] != '\n')
564 while (cp[0] != '\0' && !isspace (cp[0]))
566 /* Terminate alias name. */
570 /* Now look for the beginning of the value. */
571 while (isspace (cp[0]))
577 while (cp[0] != '\0' && !isspace (cp[0]))
579 /* Terminate value. */
582 /* This has to be done to make the following
583 test for the end of line possible. We are
584 looking for the terminating '\n' which do not
589 else if (cp[0] != '\0')
593 if (! verbose && GET (value) != NULL)
594 PUT (xstrdup (alias));
598 /* Possibly not the whole line fits into the buffer.
599 Ignore the rest of the line. */
600 while (strchr (cp, '\n') == NULL)
603 if (fgets_unlocked (buf, BUFSIZ, fp) == NULL)
604 /* Make sure the inner loop will be left. The outer
605 loop will exit at the `feof' test. */
615 twalk (all_data, print_names);
623 uint32_t locrec_offset;
628 nameentcmp (const void *a, const void *b)
630 return strcoll (((const struct nameent *) a)->name,
631 ((const struct nameent *) b)->name);
636 write_archive_locales (void **all_datap, char *linebuf)
639 void *all_data = *all_datap;
641 struct locarhead *head;
642 struct namehashent *namehashtab;
643 char *addr = MAP_FAILED;
647 fd = open64 (ARCHIVE_NAME, O_RDONLY);
651 if (fstat64 (fd, &st) < 0 || st.st_size < sizeof (*head))
655 addr = mmap64 (NULL, len, PROT_READ, MAP_SHARED, fd, 0);
656 if (addr == MAP_FAILED)
659 head = (struct locarhead *) addr;
660 if (head->namehash_offset + head->namehash_size > len
661 || head->string_offset + head->string_size > len
662 || head->locrectab_offset + head->locrectab_size > len
663 || head->sumhash_offset + head->sumhash_size > len)
666 namehashtab = (struct namehashent *) (addr + head->namehash_offset);
669 for (cnt = 0; cnt < head->namehash_size; ++cnt)
670 if (namehashtab[cnt].locrec_offset != 0)
672 PUT (xstrdup (addr + namehashtab[cnt].name_offset));
678 struct nameent *names;
681 names = (struct nameent *) xmalloc (head->namehash_used
682 * sizeof (struct nameent));
683 for (cnt = used = 0; cnt < head->namehash_size; ++cnt)
684 if (namehashtab[cnt].locrec_offset != 0)
686 names[used].name = addr + namehashtab[cnt].name_offset;
687 names[used++].locrec_offset = namehashtab[cnt].locrec_offset;
690 /* Sort the names. */
691 qsort (names, used, sizeof (struct nameent), nameentcmp);
693 for (cnt = 0; cnt < used; ++cnt)
695 struct locrecent *locrec;
697 PUT (xstrdup (names[cnt].name));
700 putchar_unlocked ('\n');
702 printf ("locale: %-15.15s archive: " ARCHIVE_NAME "\n%s\n",
703 names[cnt].name, linebuf);
705 locrec = (struct locrecent *) (addr + names[cnt].locrec_offset);
707 print_LC_IDENTIFICATION (addr
708 + locrec->record[LC_IDENTIFICATION].offset,
709 locrec->record[LC_IDENTIFICATION].len);
711 print_LC_CTYPE (addr + locrec->record[LC_CTYPE].offset,
712 locrec->record[LC_CTYPE].len);
719 if (addr != MAP_FAILED)
722 *all_datap = all_data;
727 /* Write the names of all available character maps to stdout. */
729 write_charmaps (void)
731 void *all_data = NULL;
735 /* Look for all files in the charmap directory. */
736 dir = charmap_opendir (CHARMAP_PATH);
740 while ((dirent = charmap_readdir (dir)) != NULL)
745 PUT (xstrdup (dirent));
747 aliases = charmap_aliases (CHARMAP_PATH, dirent);
750 /* Add the code_set_name and the aliases. */
751 for (p = aliases; *p; p++)
754 /* Add the code_set_name only. Most aliases are obsolete. */
760 charmap_free_aliases (aliases);
763 charmap_closedir (dir);
765 twalk (all_data, print_names);
768 /* Print a properly quoted assignment of NAME with VAL, using double
769 quotes iff DQUOTE is true. */
771 print_assignment (const char *name, const char *val, bool dquote)
773 printf ("%s=", name);
779 = strcspn (val, dquote ? "$`\"\\" : "~|&;<>()$`\\\"' \t\n");
780 printf ("%.*s", (int) segment, val);
792 /* We have to show the contents of the environments determining the
795 show_locale_vars (void)
798 const char *lcall = getenv ("LC_ALL") ? : "";
799 const char *lang = getenv ("LANG") ? : "";
801 auto void get_source (const char *name);
803 void get_source (const char *name)
805 char *val = getenv (name);
807 if (lcall[0] != '\0' || val == NULL)
808 print_assignment (name, lcall[0] ? lcall : lang[0] ? lang : "POSIX",
811 print_assignment (name, val, false);
814 /* LANG has to be the first value. */
815 print_assignment ("LANG", lang, false);
817 /* Now all categories in an unspecified order. */
818 for (cat_no = 0; cat_no < NCATEGORIES; ++cat_no)
819 if (cat_no != LC_ALL)
820 get_source (category[cat_no].name);
822 /* The last is the LC_ALL value. */
823 print_assignment ("LC_ALL", lcall, false);
827 /* Show the information request for NAME. */
829 show_info (const char *name)
833 auto void print_item (struct cat_item *item);
835 void print_item (struct cat_item *item)
837 switch (item->value_type)
840 if (show_keyword_name)
841 printf ("%s=\"", item->name);
842 fputs (nl_langinfo (item->item_id) ? : "", stdout);
843 if (show_keyword_name)
852 if (show_keyword_name)
853 printf ("%s=\"", item->name);
855 for (cnt = 0; cnt < item->max - 1; ++cnt)
857 val = nl_langinfo (item->item_id + cnt);
863 val = nl_langinfo (item->item_id + cnt);
867 if (show_keyword_name)
875 const char *val = nl_langinfo (item->item_id) ? : "";
878 if (show_keyword_name)
879 printf ("%s=", item->name);
881 for (cnt = 0; cnt < item->max && *val != '\0'; ++cnt)
883 printf ("%s%s%s%s", first ? "" : ";",
884 show_keyword_name ? "\"" : "", val,
885 show_keyword_name ? "\"" : "");
886 val = strchr (val, '\0') + 1;
894 const char *val = nl_langinfo (item->item_id);
896 if (show_keyword_name)
897 printf ("%s=", item->name);
900 printf ("%d", *val == '\177' ? -1 : *val);
906 const char *val = nl_langinfo (item->item_id);
907 int cnt = val ? strlen (val) : 0;
909 if (show_keyword_name)
910 printf ("%s=", item->name);
914 printf ("%d;", *val == '\177' ? -1 : *val);
919 printf ("%d\n", cnt == 0 || *val == '\177' ? -1 : *val);
924 union { unsigned int word; char *string; } val;
925 val.string = nl_langinfo (item->item_id);
926 if (show_keyword_name)
927 printf ("%s=", item->name);
929 printf ("%d\n", val.word);
935 /* We don't print wide character information since the same
936 information is available in a multibyte string. */
943 for (cat_no = 0; cat_no < NCATEGORIES; ++cat_no)
944 if (cat_no != LC_ALL)
948 if (strcmp (name, category[cat_no].name) == 0)
949 /* Print the whole category. */
951 if (show_category_name != 0)
952 puts (category[cat_no].name);
954 for (item_no = 0; item_no < category[cat_no].number; ++item_no)
955 print_item (&category[cat_no].item_desc[item_no]);
960 for (item_no = 0; item_no < category[cat_no].number; ++item_no)
961 if (strcmp (name, category[cat_no].item_desc[item_no].name) == 0)
963 if (show_category_name != 0)
964 puts (category[cat_no].name);
966 print_item (&category[cat_no].item_desc[item_no]);
971 /* The name is not a standard one.
972 For testing and perhaps advanced use allow some more symbols. */
973 locale_special (name, show_category_name, show_keyword_name);