1 /* Implementation of the locale program according to POSIX 9945-2.
2 Copyright (C) 1995-1997, 1999-2002, 2003 Free Software Foundation, Inc.
3 This file is part of the GNU C Library.
4 Contributed by Ulrich Drepper <drepper@cygnus.com>, 1995.
6 The GNU C Library is free software; you can redistribute it and/or
7 modify it under the terms of the GNU Lesser General Public
8 License as published by the Free Software Foundation; either
9 version 2.1 of the License, or (at your option) any later version.
11 The GNU C Library 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 GNU
14 Lesser General Public License for more details.
16 You should have received a copy of the GNU Lesser General Public
17 License along with the GNU C Library; if not, write to the Free
18 Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
37 #include <stdio_ext.h>
44 #include "localeinfo.h"
45 #include "charmap-dir.h"
46 #include "../locarchive.h"
48 extern void *xmalloc (size_t __n);
49 extern char *xstrdup (const char *__str);
51 #define ARCHIVE_NAME LOCALEDIR "/locale-archive"
53 /* If set print the name of the category. */
54 static int show_category_name;
56 /* If set print the name of the item. */
57 static int show_keyword_name;
59 /* Print names of all available locales. */
62 /* Print names of all available character maps. */
63 static int do_charmaps = 0;
65 /* Nonzero if verbose output is wanted. */
68 /* Name and version of program. */
69 static void print_version (FILE *stream, struct argp_state *state);
70 void (*argp_program_version_hook) (FILE *, struct argp_state *) = print_version;
72 /* Definitions of arguments for argp functions. */
73 static const struct argp_option options[] =
75 { NULL, 0, NULL, 0, N_("System information:") },
76 { "all-locales", 'a', NULL, OPTION_NO_USAGE,
77 N_("Write names of available locales") },
78 { "charmaps", 'm', NULL, OPTION_NO_USAGE,
79 N_("Write names of available charmaps") },
80 { NULL, 0, NULL, 0, N_("Modify output format:") },
81 { "category-name", 'c', NULL, 0, N_("Write names of selected categories") },
82 { "keyword-name", 'k', NULL, 0, N_("Write names of selected keywords") },
83 { "verbose", 'v', NULL, 0, N_("Print more information") },
84 { NULL, 0, NULL, 0, NULL }
87 /* Short description of program. */
88 static const char doc[] = N_("Get locale-specific information.");
90 /* Strings for arguments in help texts. */
91 static const char args_doc[] = N_("NAME\n[-a|-m]");
93 /* Prototype for option handler. */
94 static error_t parse_opt (int key, char *arg, struct argp_state *state);
96 /* Function to print some extra text in the help message. */
97 static char *more_help (int key, const char *text, void *input);
99 /* Data structure to communicate with argp functions. */
100 static struct argp argp =
102 options, parse_opt, args_doc, doc, NULL, more_help
106 /* We don't have these constants defined because we don't use them. Give
108 #define CTYPE_MB_CUR_MIN 0
109 #define CTYPE_MB_CUR_MAX 0
110 #define CTYPE_HASH_SIZE 0
111 #define CTYPE_HASH_LAYERS 0
112 #define CTYPE_CLASS 0
113 #define CTYPE_TOUPPER_EB 0
114 #define CTYPE_TOLOWER_EB 0
115 #define CTYPE_TOUPPER_EL 0
116 #define CTYPE_TOLOWER_EL 0
118 /* Definition of the data structure which represents a category and its
129 enum { std, opt } status;
130 enum value_type value_type;
136 /* Simple helper macro. */
137 #define NELEMS(arr) ((sizeof (arr)) / (sizeof (arr[0])))
139 /* For some tricky stuff. */
140 #define NO_PAREN(Item, More...) Item, ## More
142 /* We have all categories defined in `categories.def'. Now construct
143 the description and data structure used for all categories. */
144 #define DEFINE_ELEMENT(Item, More...) { Item, ## More },
145 #define DEFINE_CATEGORY(category, name, items, postload) \
146 static struct cat_item category##_desc[] = \
151 #include "categories.def"
152 #undef DEFINE_CATEGORY
154 static struct category category[] =
156 #define DEFINE_CATEGORY(category, name, items, postload) \
157 [category] = { _NL_NUM_##category, name, NELEMS (category##_desc), \
159 #include "categories.def"
160 #undef DEFINE_CATEGORY
162 #define NCATEGORIES NELEMS (category)
165 /* Automatically set variable. */
166 extern const char *__progname;
168 /* helper function for extended name handling. */
169 extern void locale_special (const char *name, int show_category_name,
170 int show_keyword_name);
172 /* Prototypes for local functions. */
173 static void print_LC_IDENTIFICATION (void *mapped, size_t size);
174 static void print_LC_CTYPE (void *mapped, size_t size);
175 static void write_locales (void);
176 static int nameentcmp (const void *a, const void *b);
177 static int write_archive_locales (void **all_datap, char *linebuf);
178 static void write_charmaps (void);
179 static void show_locale_vars (void);
180 static void show_info (const char *name);
184 main (int argc, char *argv[])
188 /* Set initial values for global variables. */
189 show_category_name = 0;
190 show_keyword_name = 0;
192 /* Set locale. Do not set LC_ALL because the other categories must
193 not be affected (according to POSIX.2). */
194 if (setlocale (LC_CTYPE, "") == NULL)
195 error (0, errno, gettext ("Cannot set LC_CTYPE to default locale"));
196 if (setlocale (LC_MESSAGES, "") == NULL)
197 error (0, errno, gettext ("Cannot set LC_MESSAGES to default locale"));
199 /* Initialize the message catalog. */
200 textdomain (PACKAGE);
202 /* Parse and process arguments. */
203 argp_parse (&argp, argc, argv, 0, &remaining, NULL);
205 /* `-a' requests the names of all available locales. */
208 if (setlocale (LC_COLLATE, "") == NULL)
210 gettext ("Cannot set LC_COLLATE to default locale"));
215 /* `m' requests the names of all available charmaps. The names can be
216 used for the -f argument to localedef(1). */
217 if (do_charmaps != 0)
223 /* Specific information about the current locale are requested.
224 Change to this locale now. */
225 if (setlocale (LC_ALL, "") == NULL)
226 error (0, errno, gettext ("Cannot set LC_ALL to default locale"));
228 /* If no real argument is given we have to print the contents of the
229 current locale definition variables. These are LANG and the LC_*. */
230 if (remaining == argc && show_keyword_name == 0 && show_category_name == 0)
236 /* Process all given names. */
237 while (remaining < argc)
238 show_info (argv[remaining++]);
244 /* Handle program arguments. */
246 parse_opt (int key, char *arg, struct argp_state *state)
254 show_category_name = 1;
260 show_keyword_name = 1;
266 return ARGP_ERR_UNKNOWN;
273 more_help (int key, const char *text, void *input)
277 case ARGP_KEY_HELP_EXTRA:
278 /* We print some extra information. */
279 return xstrdup (gettext ("\
280 Report bugs using the `glibcbug' script to <bugs@gnu.org>.\n"));
284 return (char *) text;
287 /* Print the version information. */
289 print_version (FILE *stream, struct argp_state *state)
291 fprintf (stream, "locale (GNU %s) %s\n", PACKAGE, VERSION);
292 fprintf (stream, gettext ("\
293 Copyright (C) %s Free Software Foundation, Inc.\n\
294 This is free software; see the source for copying conditions. There is NO\n\
295 warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.\n\
297 fprintf (stream, gettext ("Written by %s.\n"), "Ulrich Drepper");
301 /* Simple action function which prints arguments as strings. */
303 print_names (const void *nodep, VISIT value, int level)
305 if (value == postorder || value == leaf)
306 puts (*(char **) nodep);
311 select_dirs (const struct dirent *dirent)
315 if (strcmp (dirent->d_name, ".") != 0 && strcmp (dirent->d_name, "..") != 0)
319 #ifdef _DIRENT_HAVE_D_TYPE
320 if (dirent->d_type != DT_UNKNOWN && dirent->d_type != DT_LNK)
321 mode = DTTOIF (dirent->d_type);
326 char buf[sizeof (LOCALEDIR) + strlen (dirent->d_name) + 1];
328 stpcpy (stpcpy (stpcpy (buf, LOCALEDIR), "/"), dirent->d_name);
330 if (stat64 (buf, &st) == 0)
334 result = S_ISDIR (mode);
342 print_LC_IDENTIFICATION (void *mapped, size_t size)
344 /* Read the information from the file. */
348 unsigned int nstrings;
349 unsigned int strindex[0];
350 } *filedata = mapped;
352 if (filedata->magic == LIMAGIC (LC_IDENTIFICATION)
354 + (filedata->nstrings
355 * sizeof (unsigned int))
360 #define HANDLE(idx, name) \
361 str = ((char *) mapped \
362 + filedata->strindex[_NL_ITEM_INDEX (_NL_IDENTIFICATION_##idx)]); \
364 printf ("%9s | %s\n", name, str)
365 HANDLE (TITLE, "title");
366 HANDLE (SOURCE, "source");
367 HANDLE (ADDRESS, "address");
368 HANDLE (CONTACT, "contact");
369 HANDLE (EMAIL, "email");
370 HANDLE (TEL, "telephone");
372 HANDLE (LANGUAGE, "language");
373 HANDLE (TERRITORY, "territory");
374 HANDLE (AUDIENCE, "audience");
375 HANDLE (APPLICATION, "application");
376 HANDLE (ABBREVIATION, "abbreviation");
377 HANDLE (REVISION, "revision");
378 HANDLE (DATE, "date");
384 print_LC_CTYPE (void *mapped, size_t size)
389 unsigned int nstrings;
390 unsigned int strindex[0];
391 } *filedata = mapped;
393 if (filedata->magic == LIMAGIC (LC_CTYPE)
395 + (filedata->nstrings
396 * sizeof (unsigned int))
401 str = ((char *) mapped
402 + filedata->strindex[_NL_ITEM_INDEX (_NL_CTYPE_CODESET_NAME)]);
404 printf (" codeset | %s\n", str);
409 /* Write the names of all available locales to stdout. We have some
410 sources of the information: the contents of the locale directory
411 and the locale.alias file. To avoid duplicates and print the
412 result is a reasonable order we put all entries is a search tree
413 and print them afterwards. */
418 void *all_data = NULL;
419 struct dirent **dirents;
423 size_t alias_path_len;
425 int first_locale = 1;
427 #define PUT(name) tsearch (name, &all_data, \
428 (int (*) (const void *, const void *)) strcoll)
429 #define GET(name) tfind (name, &all_data, \
430 (int (*) (const void *, const void *)) strcoll)
432 /* `POSIX' locale is always available (POSIX.2 4.34.3). */
434 /* And so is the "C" locale. */
437 memset (linebuf, '-', sizeof (linebuf) - 1);
438 linebuf[sizeof (linebuf) - 1] = '\0';
440 /* First scan the locale archive. */
441 if (write_archive_locales (&all_data, linebuf))
444 /* Now we can look for all files in the directory. */
445 ndirents = scandir (LOCALEDIR, &dirents, select_dirs, alphasort);
446 for (cnt = 0; cnt < ndirents; ++cnt)
448 /* Test whether at least the LC_CTYPE data is there. Some
449 directories only contain translations. */
450 char buf[sizeof (LOCALEDIR) + strlen (dirents[cnt]->d_name)
451 + sizeof "/LC_IDENTIFICATION"];
455 stpcpy (enddir = stpcpy (stpcpy (stpcpy (buf, LOCALEDIR), "/"),
456 dirents[cnt]->d_name),
457 "/LC_IDENTIFICATION");
459 if (stat64 (buf, &st) == 0 && S_ISREG (st.st_mode))
461 if (verbose && GET (dirents[cnt]->d_name) == NULL)
463 /* Provide some nice output of all kinds of
468 putchar_unlocked ('\n');
471 printf ("locale: %-15.15s directory: %.*s\n%s\n",
472 dirents[cnt]->d_name, (int) (enddir - buf), buf,
475 fd = open64 (buf, O_RDONLY);
478 void *mapped = mmap64 (NULL, st.st_size, PROT_READ,
480 if (mapped != MAP_FAILED)
482 print_LC_IDENTIFICATION (mapped, st.st_size);
484 munmap (mapped, st.st_size);
489 /* Now try to get the charset information. */
490 strcpy (enddir, "/LC_CTYPE");
491 fd = open64 (buf, O_RDONLY);
492 if (fd != -1 && fstat64 (fd, &st) >= 0
493 && ((mapped = mmap64 (NULL, st.st_size, PROT_READ,
497 print_LC_CTYPE (mapped, st.st_size);
499 munmap (mapped, st.st_size);
507 /* If the verbose format is not selected we simply
508 collect the names. */
509 PUT (xstrdup (dirents[cnt]->d_name));
515 /* Now read the locale.alias files. */
516 if (argz_create_sep (LOCALE_ALIAS_PATH, ':', &alias_path, &alias_path_len))
517 error (1, errno, gettext ("while preparing output"));
520 while ((entry = argz_next (alias_path, alias_path_len, entry)))
522 static const char aliasfile[] = "/locale.alias";
524 char full_name[strlen (entry) + sizeof aliasfile];
526 stpcpy (stpcpy (full_name, entry), aliasfile);
527 fp = fopen (full_name, "rm");
529 /* Ignore non-existing files. */
532 /* No threads present. */
533 __fsetlocking (fp, FSETLOCKING_BYCALLER);
535 while (! feof_unlocked (fp))
537 /* It is a reasonable approach to use a fix buffer here
539 a) we are only interested in the first two fields
540 b) these fields must be usable as file names and so must
547 if (fgets_unlocked (buf, BUFSIZ, fp) == NULL)
552 /* Ignore leading white space. */
553 while (isspace (cp[0]) && cp[0] != '\n')
556 /* A leading '#' signals a comment line. */
557 if (cp[0] != '\0' && cp[0] != '#' && cp[0] != '\n')
560 while (cp[0] != '\0' && !isspace (cp[0]))
562 /* Terminate alias name. */
566 /* Now look for the beginning of the value. */
567 while (isspace (cp[0]))
573 while (cp[0] != '\0' && !isspace (cp[0]))
575 /* Terminate value. */
578 /* This has to be done to make the following
579 test for the end of line possible. We are
580 looking for the terminating '\n' which do not
585 else if (cp[0] != '\0')
589 if (! verbose && GET (value) != NULL)
590 PUT (xstrdup (alias));
594 /* Possibly not the whole line fits into the buffer.
595 Ignore the rest of the line. */
596 while (strchr (cp, '\n') == NULL)
599 if (fgets_unlocked (buf, BUFSIZ, fp) == NULL)
600 /* Make sure the inner loop will be left. The outer
601 loop will exit at the `feof' test. */
611 twalk (all_data, print_names);
619 uint32_t locrec_offset;
624 nameentcmp (const void *a, const void *b)
626 return strcoll (((const struct nameent *) a)->name,
627 ((const struct nameent *) b)->name);
632 write_archive_locales (void **all_datap, char *linebuf)
635 void *all_data = *all_datap;
637 struct locarhead *head;
638 struct namehashent *namehashtab;
639 char *addr = MAP_FAILED;
643 fd = open64 (ARCHIVE_NAME, O_RDONLY);
647 if (fstat64 (fd, &st) < 0 || st.st_size < sizeof (*head))
651 addr = mmap64 (NULL, len, PROT_READ, MAP_SHARED, fd, 0);
652 if (addr == MAP_FAILED)
655 head = (struct locarhead *) addr;
656 if (head->namehash_offset + head->namehash_size > len
657 || head->string_offset + head->string_size > len
658 || head->locrectab_offset + head->locrectab_size > len
659 || head->sumhash_offset + head->sumhash_size > len)
662 namehashtab = (struct namehashent *) (addr + head->namehash_offset);
665 for (cnt = 0; cnt < head->namehash_size; ++cnt)
666 if (namehashtab[cnt].locrec_offset != 0)
668 PUT (xstrdup (addr + namehashtab[cnt].name_offset));
674 struct nameent *names;
677 names = (struct nameent *) xmalloc (head->namehash_used
678 * sizeof (struct nameent));
679 for (cnt = used = 0; cnt < head->namehash_size; ++cnt)
680 if (namehashtab[cnt].locrec_offset != 0)
682 names[used].name = addr + namehashtab[cnt].name_offset;
683 names[used++].locrec_offset = namehashtab[cnt].locrec_offset;
686 /* Sort the names. */
687 qsort (names, used, sizeof (struct nameent), nameentcmp);
689 for (cnt = 0; cnt < used; ++cnt)
691 struct locrecent *locrec;
693 PUT (xstrdup (names[cnt].name));
696 putchar_unlocked ('\n');
698 printf ("locale: %-15.15s archive: " ARCHIVE_NAME "\n%s\n",
699 names[cnt].name, linebuf);
701 locrec = (struct locrecent *) (addr + names[cnt].locrec_offset);
703 print_LC_IDENTIFICATION (addr
704 + locrec->record[LC_IDENTIFICATION].offset,
705 locrec->record[LC_IDENTIFICATION].len);
707 print_LC_CTYPE (addr + locrec->record[LC_CTYPE].offset,
708 locrec->record[LC_CTYPE].len);
715 if (addr != MAP_FAILED)
718 *all_datap = all_data;
723 /* Write the names of all available character maps to stdout. */
725 write_charmaps (void)
727 void *all_data = NULL;
731 /* Look for all files in the charmap directory. */
732 dir = charmap_opendir (CHARMAP_PATH);
736 while ((dirent = charmap_readdir (dir)) != NULL)
741 PUT (xstrdup (dirent));
743 aliases = charmap_aliases (CHARMAP_PATH, dirent);
746 /* Add the code_set_name and the aliases. */
747 for (p = aliases; *p; p++)
750 /* Add the code_set_name only. Most aliases are obsolete. */
756 charmap_free_aliases (aliases);
759 charmap_closedir (dir);
761 twalk (all_data, print_names);
765 /* We have to show the contents of the environments determining the
768 show_locale_vars (void)
771 const char *lcall = getenv ("LC_ALL");
772 const char *lang = getenv ("LANG") ? : "POSIX";
774 auto void get_source (const char *name);
776 void get_source (const char *name)
778 char *val = getenv (name);
780 if ((lcall ?: "")[0] != '\0' || val == NULL)
781 printf ("%s=\"%s\"\n", name, (lcall ?: "")[0] ? lcall : lang);
783 printf ("%s=%s\n", name, val);
786 /* LANG has to be the first value. */
787 printf ("LANG=%s\n", lang);
789 /* Now all categories in an unspecified order. */
790 for (cat_no = 0; cat_no < NCATEGORIES; ++cat_no)
791 if (cat_no != LC_ALL)
792 get_source (category[cat_no].name);
794 /* The last is the LC_ALL value. */
795 printf ("LC_ALL=%s\n", lcall ? : "");
799 /* Show the information request for NAME. */
801 show_info (const char *name)
805 auto void print_item (struct cat_item *item);
807 void print_item (struct cat_item *item)
809 switch (item->value_type)
812 if (show_keyword_name)
813 printf ("%s=\"", item->name);
814 fputs (nl_langinfo (item->item_id) ? : "", stdout);
815 if (show_keyword_name)
824 if (show_keyword_name)
825 printf ("%s=\"", item->name);
827 for (cnt = 0; cnt < item->max - 1; ++cnt)
829 val = nl_langinfo (item->item_id + cnt);
835 val = nl_langinfo (item->item_id + cnt);
839 if (show_keyword_name)
847 const char *val = nl_langinfo (item->item_id) ? : "";
850 if (show_keyword_name)
851 printf ("%s=", item->name);
853 for (cnt = 0; cnt < item->max && *val != '\0'; ++cnt)
855 printf ("%s%s%s%s", first ? "" : ";",
856 show_keyword_name ? "\"" : "", val,
857 show_keyword_name ? "\"" : "");
858 val = strchr (val, '\0') + 1;
866 const char *val = nl_langinfo (item->item_id);
868 if (show_keyword_name)
869 printf ("%s=", item->name);
872 printf ("%d", *val == '\177' ? -1 : *val);
878 const char *val = nl_langinfo (item->item_id);
879 int cnt = val ? strlen (val) : 0;
881 if (show_keyword_name)
882 printf ("%s=", item->name);
886 printf ("%d;", *val == '\177' ? -1 : *val);
891 printf ("%d\n", cnt == 0 || *val == '\177' ? -1 : *val);
897 (unsigned int) (unsigned long int) nl_langinfo (item->item_id);
898 if (show_keyword_name)
899 printf ("%s=", item->name);
901 printf ("%d\n", val);
907 /* We don't print wide character information since the same
908 information is available in a multibyte string. */
915 for (cat_no = 0; cat_no < NCATEGORIES; ++cat_no)
916 if (cat_no != LC_ALL)
920 if (strcmp (name, category[cat_no].name) == 0)
921 /* Print the whole category. */
923 if (show_category_name != 0)
924 puts (category[cat_no].name);
926 for (item_no = 0; item_no < category[cat_no].number; ++item_no)
927 print_item (&category[cat_no].item_desc[item_no]);
932 for (item_no = 0; item_no < category[cat_no].number; ++item_no)
933 if (strcmp (name, category[cat_no].item_desc[item_no].name) == 0)
935 if (show_category_name != 0)
936 puts (category[cat_no].name);
938 print_item (&category[cat_no].item_desc[item_no]);
943 /* The name is not a standard one.
944 For testing and perhaps advanced use allow some more symbols. */
945 locale_special (name, show_category_name, show_keyword_name);