1 /* Implementation of the locale program according to POSIX 9945-2.
2 Copyright (C) 1995-1997, 1999, 2000, 2001 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 Library General Public License as
8 published by the Free Software Foundation; either version 2 of the
9 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 Library General Public License for more details.
16 You should have received a copy of the GNU Library General Public
17 License along with the GNU C Library; see the file COPYING.LIB. If not,
18 write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
19 Boston, MA 02111-1307, USA. */
40 #include "localeinfo.h"
41 #include "charmap-dir.h"
43 extern char *xstrdup (const char *__str);
46 /* If set print the name of the category. */
47 static int show_category_name;
49 /* If set print the name of the item. */
50 static int show_keyword_name;
52 /* Print names of all available locales. */
55 /* Print names of all available character maps. */
56 static int do_charmaps = 0;
58 /* Name and version of program. */
59 static void print_version (FILE *stream, struct argp_state *state);
60 void (*argp_program_version_hook) (FILE *, struct argp_state *) = print_version;
62 /* Definitions of arguments for argp functions. */
63 static const struct argp_option options[] =
65 { NULL, 0, NULL, 0, N_("System information:") },
66 { "all-locales", 'a', NULL, OPTION_NO_USAGE,
67 N_("Write names of available locales") },
68 { "charmaps", 'm', NULL, OPTION_NO_USAGE,
69 N_("Write names of available charmaps") },
70 { NULL, 0, NULL, 0, N_("Modify output format:") },
71 { "category-name", 'c', NULL, 0, N_("Write names of selected categories") },
72 { "keyword-name", 'k', NULL, 0, N_("Write names of selected keywords") },
73 { NULL, 0, NULL, 0, NULL }
76 /* Short description of program. */
77 static const char doc[] = N_("Get locale-specific information.");
79 /* Strings for arguments in help texts. */
80 static const char args_doc[] = N_("NAME\n[-a|-m]");
82 /* Prototype for option handler. */
83 static error_t parse_opt (int key, char *arg, struct argp_state *state);
85 /* Function to print some extra text in the help message. */
86 static char *more_help (int key, const char *text, void *input);
88 /* Data structure to communicate with argp functions. */
89 static struct argp argp =
91 options, parse_opt, args_doc, doc, NULL, more_help
95 /* We don't have these constants defined because we don't use them. Give
97 #define CTYPE_MB_CUR_MIN 0
98 #define CTYPE_MB_CUR_MAX 0
99 #define CTYPE_HASH_SIZE 0
100 #define CTYPE_HASH_LAYERS 0
101 #define CTYPE_CLASS 0
102 #define CTYPE_TOUPPER_EB 0
103 #define CTYPE_TOLOWER_EB 0
104 #define CTYPE_TOUPPER_EL 0
105 #define CTYPE_TOLOWER_EL 0
107 /* Definition of the data structure which represents a category and its
118 enum { std, opt } status;
119 enum value_type value_type;
125 /* Simple helper macro. */
126 #define NELEMS(arr) ((sizeof (arr)) / (sizeof (arr[0])))
128 /* For some tricky stuff. */
129 #define NO_PAREN(Item, More...) Item, ## More
131 /* We have all categories defined in `categories.def'. Now construct
132 the description and data structure used for all categories. */
133 #define DEFINE_ELEMENT(Item, More...) { Item, ## More },
134 #define DEFINE_CATEGORY(category, name, items, postload) \
135 static struct cat_item category##_desc[] = \
140 #include "categories.def"
141 #undef DEFINE_CATEGORY
143 static struct category category[] =
145 #define DEFINE_CATEGORY(category, name, items, postload) \
146 [category] = { _NL_NUM_##category, name, NELEMS (category##_desc), \
148 #include "categories.def"
149 #undef DEFINE_CATEGORY
151 #define NCATEGORIES NELEMS (category)
154 /* Automatically set variable. */
155 extern const char *__progname;
157 /* helper function for extended name handling. */
158 extern void locale_special (const char *name, int show_category_name,
159 int show_keyword_name);
161 /* Prototypes for local functions. */
162 static void write_locales (void);
163 static void write_charmaps (void);
164 static void show_locale_vars (void);
165 static void show_info (const char *name);
169 main (int argc, char *argv[])
173 /* Set initial values for global variables. */
174 show_category_name = 0;
175 show_keyword_name = 0;
177 /* Set locale. Do not set LC_ALL because the other categories must
178 not be affected (according to POSIX.2). */
179 setlocale (LC_CTYPE, "");
180 setlocale (LC_MESSAGES, "");
182 /* Initialize the message catalog. */
183 textdomain (PACKAGE);
185 /* Parse and process arguments. */
186 argp_parse (&argp, argc, argv, 0, &remaining, NULL);
188 /* `-a' requests the names of all available locales. */
191 setlocale (LC_COLLATE, "");
196 /* `m' requests the names of all available charmaps. The names can be
197 used for the -f argument to localedef(1). */
198 if (do_charmaps != 0)
204 /* Specific information about the current locale are requested.
205 Change to this locale now. */
206 setlocale (LC_ALL, "");
208 /* If no real argument is given we have to print the contents of the
209 current locale definition variables. These are LANG and the LC_*. */
210 if (remaining == argc && show_keyword_name == 0 && show_category_name == 0)
216 /* Process all given names. */
217 while (remaining < argc)
218 show_info (argv[remaining++]);
224 /* Handle program arguments. */
226 parse_opt (int key, char *arg, struct argp_state *state)
234 show_category_name = 1;
240 show_keyword_name = 1;
243 return ARGP_ERR_UNKNOWN;
250 more_help (int key, const char *text, void *input)
254 case ARGP_KEY_HELP_EXTRA:
255 /* We print some extra information. */
256 return xstrdup (gettext ("\
257 Report bugs using the `glibcbug' script to <bugs@gnu.org>.\n"));
261 return (char *) text;
264 /* Print the version information. */
266 print_version (FILE *stream, struct argp_state *state)
268 fprintf (stream, "locale (GNU %s) %s\n", PACKAGE, VERSION);
269 fprintf (stream, gettext ("\
270 Copyright (C) %s Free Software Foundation, Inc.\n\
271 This is free software; see the source for copying conditions. There is NO\n\
272 warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.\n\
274 fprintf (stream, gettext ("Written by %s.\n"), "Ulrich Drepper");
278 /* Simple action function which prints arguments as strings. */
280 print_names (const void *nodep, VISIT value, int level)
282 if (value == postorder || value == leaf)
283 puts (*(char **) nodep);
287 /* Write the names of all available locales to stdout. We have some
288 sources of the information: the contents of the locale directory
289 and the locale.alias file. To avoid duplicates and print the
290 result is a reasonable order we put all entries is a search tree
291 and print them afterwards. */
295 void *all_data = NULL;
297 struct dirent *dirent;
299 size_t alias_path_len;
302 #define PUT(name) tsearch ((name), &all_data, \
303 (int (*) (const void *, const void *)) strcoll)
305 dir = opendir (LOCALEDIR);
308 error (1, errno, gettext ("cannot read locale directory `%s'"),
313 /* `POSIX' locale is always available (POSIX.2 4.34.3). */
315 /* And so is the "C" locale. */
318 /* Now we can look for all files in the directory. */
319 while ((dirent = readdir (dir)) != NULL)
320 if (strcmp (dirent->d_name, ".") != 0
321 && strcmp (dirent->d_name, "..") != 0)
324 #ifdef _DIRENT_HAVE_D_TYPE
325 if (dirent->d_type != DT_UNKNOWN && dirent->d_type != DT_LNK)
326 mode = DTTOIF (dirent->d_type);
331 char buf[sizeof (LOCALEDIR) + strlen (dirent->d_name) + 1];
333 stpcpy (stpcpy (stpcpy (buf, LOCALEDIR), "/"), dirent->d_name);
335 if (stat (buf, &st) < 0)
342 /* Test whether at least the LC_CTYPE data is there. Some
343 directories only contain translations. */
344 char buf[sizeof (LOCALEDIR) + strlen (dirent->d_name)
345 + sizeof "/LC_CTYPE"];
348 stpcpy (stpcpy (stpcpy (stpcpy (buf, LOCALEDIR), "/"),
352 if (stat (buf, &st) == 0 && S_ISREG (st.st_mode))
353 PUT (xstrdup (dirent->d_name));
359 /* Now read the locale.alias files. */
360 if (argz_create_sep (LOCALE_ALIAS_PATH, ':', &alias_path, &alias_path_len))
361 error (1, errno, gettext ("while preparing output"));
364 while ((entry = argz_next (alias_path, alias_path_len, entry)))
366 static const char aliasfile[] = "/locale.alias";
368 char full_name[strlen (entry) + sizeof aliasfile];
370 stpcpy (stpcpy (full_name, entry), aliasfile);
371 fp = fopen (full_name, "r");
373 /* Ignore non-existing files. */
378 /* It is a reasonable approach to use a fix buffer here
380 a) we are only interested in the first two fields
381 b) these fields must be usable as file names and so must
388 if (fgets (buf, BUFSIZ, fp) == NULL)
393 /* Ignore leading white space. */
394 while (isspace (cp[0]) && cp[0] != '\n')
397 /* A leading '#' signals a comment line. */
398 if (cp[0] != '\0' && cp[0] != '#' && cp[0] != '\n')
401 while (cp[0] != '\0' && !isspace (cp[0]))
403 /* Terminate alias name. */
407 /* Now look for the beginning of the value. */
408 while (isspace (cp[0]))
414 while (cp[0] != '\0' && !isspace (cp[0]))
416 /* Terminate value. */
419 /* This has to be done to make the following
420 test for the end of line possible. We are
421 looking for the terminating '\n' which do not
426 else if (cp[0] != '\0')
430 PUT (xstrdup (alias));
434 /* Possibly not the whole line fits into the buffer.
435 Ignore the rest of the line. */
436 while (strchr (cp, '\n') == NULL)
439 if (fgets (buf, BUFSIZ, fp) == NULL)
440 /* Make sure the inner loop will be left. The outer
441 loop will exit at the `feof' test. */
449 twalk (all_data, print_names);
453 /* Write the names of all available character maps to stdout. */
455 write_charmaps (void)
457 void *all_data = NULL;
461 /* Look for all files in the charmap directory. */
462 dir = charmap_opendir (CHARMAP_PATH);
466 while ((dirent = charmap_readdir (dir)) != NULL)
471 PUT (xstrdup (dirent));
473 aliases = charmap_aliases (CHARMAP_PATH, dirent);
476 /* Add the code_set_name and the aliases. */
477 for (p = aliases; *p; p++)
480 /* Add the code_set_name only. Most aliases are obsolete. */
486 charmap_free_aliases (aliases);
489 charmap_closedir (dir);
491 twalk (all_data, print_names);
495 /* We have to show the contents of the environments determining the
498 show_locale_vars (void)
501 const char *lcall = getenv ("LC_ALL");
502 const char *lang = getenv ("LANG") ? : "POSIX";
504 auto void get_source (const char *name);
506 void get_source (const char *name)
508 char *val = getenv (name);
510 if ((lcall ?: "")[0] != '\0' || val == NULL)
511 printf ("%s=\"%s\"\n", name, (lcall ?: "")[0] ? lcall : lang);
513 printf ("%s=%s\n", name, val);
516 /* LANG has to be the first value. */
517 printf ("LANG=%s\n", lang);
519 /* Now all categories in an unspecified order. */
520 for (cat_no = 0; cat_no < NCATEGORIES; ++cat_no)
521 if (cat_no != LC_ALL)
522 get_source (category[cat_no].name);
524 /* The last is the LC_ALL value. */
525 printf ("LC_ALL=%s\n", lcall ? : "");
529 /* Show the information request for NAME. */
531 show_info (const char *name)
535 auto void print_item (struct cat_item *item);
537 void print_item (struct cat_item *item)
539 switch (item->value_type)
542 if (show_keyword_name)
543 printf ("%s=\"", item->name);
544 fputs (nl_langinfo (item->item_id) ? : "", stdout);
545 if (show_keyword_name)
554 if (show_keyword_name)
555 printf ("%s=\"", item->name);
557 for (cnt = 0; cnt < item->max - 1; ++cnt)
559 val = nl_langinfo (item->item_id + cnt);
565 val = nl_langinfo (item->item_id + cnt);
569 if (show_keyword_name)
577 const char *val = nl_langinfo (item->item_id) ? : "";
580 if (show_keyword_name)
581 printf ("%s=", item->name);
583 for (cnt = 0; cnt < item->max && *val != '\0'; ++cnt)
585 printf ("%s%s%s%s", first ? "" : ";",
586 show_keyword_name ? "\"" : "", val,
587 show_keyword_name ? "\"" : "");
588 val = strchr (val, '\0') + 1;
596 const char *val = nl_langinfo (item->item_id);
598 if (show_keyword_name)
599 printf ("%s=", item->name);
602 printf ("%d", *val == CHAR_MAX ? -1 : *val);
608 const char *val = nl_langinfo (item->item_id);
609 int cnt = val ? strlen (val) : 0;
611 if (show_keyword_name)
612 printf ("%s=", item->name);
616 printf ("%d;", *val == CHAR_MAX ? -1 : *val);
621 printf ("%d\n", cnt == 0 || *val == CHAR_MAX ? -1 : *val);
627 (unsigned int) (unsigned long int) nl_langinfo (item->item_id);
628 if (show_keyword_name)
629 printf ("%s=", item->name);
631 printf ("%d\n", val);
637 /* We don't print wide character information since the same
638 information is available in a multibyte string. */
645 for (cat_no = 0; cat_no < NCATEGORIES; ++cat_no)
646 if (cat_no != LC_ALL)
650 if (strcmp (name, category[cat_no].name) == 0)
651 /* Print the whole category. */
653 if (show_category_name != 0)
654 puts (category[cat_no].name);
656 for (item_no = 0; item_no < category[cat_no].number; ++item_no)
657 print_item (&category[cat_no].item_desc[item_no]);
662 for (item_no = 0; item_no < category[cat_no].number; ++item_no)
663 if (strcmp (name, category[cat_no].item_desc[item_no].name) == 0)
665 if (show_category_name != 0)
666 puts (category[cat_no].name);
668 print_item (&category[cat_no].item_desc[item_no]);
673 /* The name is not a standard one.
674 For testing and perhaps advanced use allow some more symbols. */
675 locale_special (name, show_category_name, show_keyword_name);