Update.
[platform/upstream/glibc.git] / locale / programs / locale.c
1 /* Implementation of the locale program according to POSIX 9945-2.
2    Copyright (C) 1995, 1996, 1997, 1999, 2000 Free Software Foundation, Inc.
3    This file is part of the GNU C Library.
4    Contributed by Ulrich Drepper <drepper@cygnus.com>, 1995.
5
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.
10
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.
15
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.  */
20
21 #ifdef HAVE_CONFIG_H
22 # include <config.h>
23 #endif
24
25 #include <argp.h>
26 #include <argz.h>
27 #include <dirent.h>
28 #include <errno.h>
29 #include <error.h>
30 #include <langinfo.h>
31 #include <libintl.h>
32 #include <limits.h>
33 #include <locale.h>
34 #include <search.h>
35 #include <stdio.h>
36 #include <stdlib.h>
37 #include <string.h>
38 #include <sys/stat.h>
39
40 #include "localeinfo.h"
41 #include "charmap-dir.h"
42
43 extern char *xstrdup (const char *__str);
44
45
46 /* If set print the name of the category.  */
47 static int show_category_name;
48
49 /* If set print the name of the item.  */
50 static int show_keyword_name;
51
52 /* Print names of all available locales.  */
53 static int do_all;
54
55 /* Print names of all available character maps.  */
56 static int do_charmaps = 0;
57
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;
61
62 /* Definitions of arguments for argp functions.  */
63 static const struct argp_option options[] =
64 {
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 }
74 };
75
76 /* Short description of program.  */
77 static const char doc[] = N_("Get locale-specific information.");
78
79 /* Strings for arguments in help texts.  */
80 static const char args_doc[] = N_("NAME\n[-a|-m]");
81
82 /* Prototype for option handler.  */
83 static error_t parse_opt (int key, char *arg, struct argp_state *state);
84
85 /* Function to print some extra text in the help message.  */
86 static char *more_help (int key, const char *text, void *input);
87
88 /* Data structure to communicate with argp functions.  */
89 static struct argp argp =
90 {
91   options, parse_opt, args_doc, doc, NULL, more_help
92 };
93
94
95 /* We don't have these constants defined because we don't use them.  Give
96    default values.  */
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
106
107 /* Definition of the data structure which represents a category and its
108    items.  */
109 struct category
110 {
111   int cat_id;
112   const char *name;
113   size_t number;
114   struct cat_item
115   {
116     int item_id;
117     const char *name;
118     enum { std, opt } status;
119     enum value_type value_type;
120     int min;
121     int max;
122   } *item_desc;
123 };
124
125 /* Simple helper macro.  */
126 #define NELEMS(arr) ((sizeof (arr)) / (sizeof (arr[0])))
127
128 /* For some tricky stuff.  */
129 #define NO_PAREN(Item, More...) Item, ## More
130
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[] =                                \
136       {                                                                       \
137         NO_PAREN items                                                        \
138       };
139
140 #include "categories.def"
141 #undef DEFINE_CATEGORY
142
143 static struct category category[] =
144   {
145 #define DEFINE_CATEGORY(category, name, items, postload) \
146     [category] = { _NL_NUM_##category, name, NELEMS (category##_desc),        \
147                    category##_desc },
148 #include "categories.def"
149 #undef DEFINE_CATEGORY
150   };
151 #define NCATEGORIES NELEMS (category)
152
153
154 /* Automatically set variable.  */
155 extern const char *__progname;
156
157 /* helper function for extended name handling.  */
158 extern void locale_special (const char *name, int show_category_name,
159                             int show_keyword_name);
160
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);
166
167
168 int
169 main (int argc, char *argv[])
170 {
171   int remaining;
172
173   /* Set initial values for global variables.  */
174   show_category_name = 0;
175   show_keyword_name = 0;
176
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, "");
181
182   /* Initialize the message catalog.  */
183   textdomain (PACKAGE);
184
185   /* Parse and process arguments.  */
186   argp_parse (&argp, argc, argv, 0, &remaining, NULL);
187
188   /* `-a' requests the names of all available locales.  */
189   if (do_all != 0)
190     {
191       setlocale (LC_COLLATE, "");
192       write_locales ();
193       exit (EXIT_SUCCESS);
194     }
195
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)
199     {
200       write_charmaps ();
201       exit (EXIT_SUCCESS);
202     }
203
204   /* Specific information about the current locale are requested.
205      Change to this locale now.  */
206   setlocale (LC_ALL, "");
207
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)
211     {
212       show_locale_vars ();
213       exit (EXIT_SUCCESS);
214     }
215
216   /* Process all given names.  */
217   while (remaining <  argc)
218     show_info (argv[remaining++]);
219
220   exit (EXIT_SUCCESS);
221 }
222
223
224 /* Handle program arguments.  */
225 static error_t
226 parse_opt (int key, char *arg, struct argp_state *state)
227 {
228   switch (key)
229     {
230     case 'a':
231       do_all = 1;
232       break;
233     case 'c':
234       show_category_name = 1;
235       break;
236     case 'm':
237       do_charmaps = 1;
238       break;
239     case 'k':
240       show_keyword_name = 1;
241       break;
242     default:
243       return ARGP_ERR_UNKNOWN;
244     }
245   return 0;
246 }
247
248
249 static char *
250 more_help (int key, const char *text, void *input)
251 {
252   switch (key)
253     {
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"));
258     default:
259       break;
260     }
261   return (char *) text;
262 }
263
264 /* Print the version information.  */
265 static void
266 print_version (FILE *stream, struct argp_state *state)
267 {
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\
273 "), "2000");
274   fprintf (stream, gettext ("Written by %s.\n"), "Ulrich Drepper");
275 }
276
277
278 /* Simple action function which prints arguments as strings.  */
279 static void
280 print_names (const void *nodep, VISIT value, int level)
281 {
282   if (value == postorder || value == leaf)
283     puts (*(char **) nodep);
284 }
285
286
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.  */
292 static void
293 write_locales (void)
294 {
295   void *all_data = NULL;
296   DIR *dir;
297   struct dirent *dirent;
298   char *alias_path;
299   size_t alias_path_len;
300   char *entry;
301
302 #define PUT(name) tsearch ((name), &all_data, \
303                            (int (*) (const void *, const void *)) strcoll)
304
305   dir = opendir (LOCALEDIR);
306   if (dir == NULL)
307     {
308       error (1, errno, gettext ("cannot read locale directory `%s'"),
309              LOCALEDIR);
310       return;
311     }
312
313   /* `POSIX' locale is always available (POSIX.2 4.34.3).  */
314   PUT ("POSIX");
315   /* And so is the "C" locale.  */
316   PUT ("C");
317
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)
322       {
323         mode_t mode;
324 #ifdef _DIRENT_HAVE_D_TYPE
325         if (dirent->d_type != DT_UNKNOWN && dirent->d_type != DT_LNK)
326           mode = DTTOIF (dirent->d_type);
327         else
328 #endif
329           {
330             struct stat st;
331             char buf[sizeof (LOCALEDIR) + strlen (dirent->d_name) + 1];
332
333             stpcpy (stpcpy (stpcpy (buf, LOCALEDIR), "/"), dirent->d_name);
334
335             if (stat (buf, &st) < 0)
336               continue;
337             mode = st.st_mode;
338           }
339
340         if (S_ISDIR (mode))
341           {
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"];
346             struct stat st;
347
348             stpcpy (stpcpy (stpcpy (stpcpy (buf, LOCALEDIR), "/"),
349                             dirent->d_name),
350                     "/LC_CTYPE");
351
352             if (stat (buf, &st) == 0 && S_ISREG (st.st_mode))
353               PUT (xstrdup (dirent->d_name));
354           }
355       }
356
357   closedir (dir);
358
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"));
362
363   entry = NULL;
364   while ((entry = argz_next (alias_path, alias_path_len, entry)))
365     {
366       static const char aliasfile[] = "/locale.alias";
367       FILE *fp;
368       char full_name[strlen (entry) + sizeof aliasfile];
369
370       stpcpy (stpcpy (full_name, entry), aliasfile);
371       fp = fopen (full_name, "r");
372       if (fp == NULL)
373         /* Ignore non-existing files.  */
374         continue;
375
376       while (! feof (fp))
377         {
378           /* It is a reasonable approach to use a fix buffer here
379              because
380              a) we are only interested in the first two fields
381              b) these fields must be usable as file names and so must
382                 not be that long  */
383           char buf[BUFSIZ];
384           char *alias;
385           char *value;
386           char *cp;
387
388           if (fgets (buf, BUFSIZ, fp) == NULL)
389             /* EOF reached.  */
390             break;
391
392           cp = buf;
393           /* Ignore leading white space.  */
394           while (isspace (cp[0]) && cp[0] != '\n')
395             ++cp;
396
397           /* A leading '#' signals a comment line.  */
398           if (cp[0] != '\0' && cp[0] != '#' && cp[0] != '\n')
399             {
400               alias = cp++;
401               while (cp[0] != '\0' && !isspace (cp[0]))
402                 ++cp;
403               /* Terminate alias name.  */
404               if (cp[0] != '\0')
405                 *cp++ = '\0';
406
407               /* Now look for the beginning of the value.  */
408               while (isspace (cp[0]))
409                 ++cp;
410
411               if (cp[0] != '\0')
412                 {
413                   value = cp++;
414                   while (cp[0] != '\0' && !isspace (cp[0]))
415                     ++cp;
416                   /* Terminate value.  */
417                   if (cp[0] == '\n')
418                     {
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
422                          overwrite here.  */
423                       *cp++ = '\0';
424                       *cp = '\n';
425                     }
426                   else if (cp[0] != '\0')
427                     *cp++ = '\0';
428
429                   /* Add the alias.  */
430                   PUT (xstrdup (alias));
431                 }
432             }
433
434           /* Possibly not the whole line fits into the buffer.
435              Ignore the rest of the line.  */
436           while (strchr (cp, '\n') == NULL)
437             {
438               cp = buf;
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.  */
442                 *cp = '\n';
443             }
444         }
445
446       fclose (fp);
447     }
448
449   twalk (all_data, print_names);
450 }
451
452
453 /* Write the names of all available character maps to stdout.  */
454 static void
455 write_charmaps (void)
456 {
457   void *all_data = NULL;
458   CHARMAP_DIR *dir;
459   const char *dirent;
460
461   /* Look for all files in the charmap directory.  */
462   dir = charmap_opendir (CHARMAP_PATH);
463   if (dir == NULL)
464     return;
465
466   while ((dirent = charmap_readdir (dir)) != NULL)
467     {
468       char **aliases;
469       char **p;
470
471       PUT (xstrdup (dirent));
472
473       aliases = charmap_aliases (CHARMAP_PATH, dirent);
474
475 #if 0
476       /* Add the code_set_name and the aliases.  */
477       for (p = aliases; *p; p++)
478         PUT (xstrdup (*p));
479 #else
480       /* Add the code_set_name only.  Most aliases are obsolete.  */
481       p = aliases;
482       if (*p)
483         PUT (xstrdup (*p));
484 #endif
485
486       charmap_free_aliases (aliases);
487     }
488
489   charmap_closedir (dir);
490
491   twalk (all_data, print_names);
492 }
493
494
495 /* We have to show the contents of the environments determining the
496    locale.  */
497 static void
498 show_locale_vars (void)
499 {
500   size_t cat_no;
501   const char *lcall = getenv ("LC_ALL");
502   const char *lang = getenv ("LANG") ? : "POSIX";
503
504   void get_source (const char *name)
505     {
506       char *val = getenv (name);
507
508       if ((lcall ?: "")[0] != '\0' || val == NULL)
509         printf ("%s=\"%s\"\n", name, (lcall ?: "")[0] ? lcall : lang);
510       else
511         printf ("%s=%s\n", name, val);
512     }
513
514   /* LANG has to be the first value.  */
515   printf ("LANG=%s\n", lang);
516
517   /* Now all categories in an unspecified order.  */
518   for (cat_no = 0; cat_no < NCATEGORIES; ++cat_no)
519     if (cat_no != LC_ALL)
520       get_source (category[cat_no].name);
521
522   /* The last is the LC_ALL value.  */
523   printf ("LC_ALL=%s\n", lcall ? : "");
524 }
525
526
527 /* Show the information request for NAME.  */
528 static void
529 show_info (const char *name)
530 {
531   size_t cat_no;
532
533   void print_item (struct cat_item *item)
534     {
535       switch (item->value_type)
536         {
537         case string:
538           if (show_keyword_name)
539             printf ("%s=\"", item->name);
540           fputs (nl_langinfo (item->item_id) ? : "", stdout);
541           if (show_keyword_name)
542             putchar ('"');
543           putchar ('\n');
544           break;
545         case stringarray:
546           {
547             int cnt;
548             const char *val;
549
550             if (show_keyword_name)
551               printf ("%s=\"", item->name);
552
553             for (cnt = 0; cnt < item->max - 1; ++cnt)
554               {
555                 val = nl_langinfo (item->item_id + cnt);
556                 if (val != NULL)
557                   fputs (val, stdout);
558                 putchar (';');
559               }
560
561             val = nl_langinfo (item->item_id + cnt);
562             if (val != NULL)
563               fputs (val, stdout);
564
565             if (show_keyword_name)
566               putchar ('"');
567             putchar ('\n');
568           }
569           break;
570         case stringlist:
571           {
572             int first = 1;
573             const char *val = nl_langinfo (item->item_id) ? : "";
574             int cnt;
575
576             if (show_keyword_name)
577               printf ("%s=", item->name);
578
579             for (cnt = 0; cnt < item->max && *val != '\0'; ++cnt)
580               {
581                 printf ("%s%s%s%s", first ? "" : ";",
582                         show_keyword_name ? "\"" : "", val,
583                         show_keyword_name ? "\"" : "");
584                 val = strchr (val, '\0') + 1;
585                 first = 0;
586               }
587             putchar ('\n');
588           }
589           break;
590         case byte:
591           {
592             const char *val = nl_langinfo (item->item_id);
593
594             if (show_keyword_name)
595               printf ("%s=", item->name);
596
597             if (val != NULL)
598               printf ("%d", *val == CHAR_MAX ? -1 : *val);
599             putchar ('\n');
600           }
601           break;
602         case bytearray:
603           {
604             const char *val = nl_langinfo (item->item_id);
605             int cnt = val ? strlen (val) : 0;
606
607             if (show_keyword_name)
608               printf ("%s=", item->name);
609
610             while (cnt > 1)
611               {
612                 printf ("%d;", *val == CHAR_MAX ? -1 : *val);
613                 --cnt;
614                 ++val;
615               }
616
617             printf ("%d\n", cnt == 0 || *val == CHAR_MAX ? -1 : *val);
618           }
619           break;
620         case word:
621           {
622             unsigned int val =
623               (unsigned int) (unsigned long int) nl_langinfo (item->item_id);
624             if (show_keyword_name)
625               printf ("%s=", item->name);
626
627             printf ("%d\n", val);
628           }
629           break;
630         case wstring:
631         case wstringarray:
632         case wstringlist:
633           /* We don't print wide character information since the same
634              information is available in a multibyte string.  */
635         default:
636         }
637     }
638
639   for (cat_no = 0; cat_no < NCATEGORIES; ++cat_no)
640     if (cat_no != LC_ALL)
641       {
642         size_t item_no;
643
644         if (strcmp (name, category[cat_no].name) == 0)
645           /* Print the whole category.  */
646           {
647             if (show_category_name != 0)
648               puts (category[cat_no].name);
649
650             for (item_no = 0; item_no < category[cat_no].number; ++item_no)
651               print_item (&category[cat_no].item_desc[item_no]);
652
653             return;
654           }
655
656         for (item_no = 0; item_no < category[cat_no].number; ++item_no)
657           if (strcmp (name, category[cat_no].item_desc[item_no].name) == 0)
658             {
659               if (show_category_name != 0)
660                 puts (category[cat_no].name);
661
662               print_item (&category[cat_no].item_desc[item_no]);
663               return;
664             }
665       }
666
667   /* The name is not a standard one.
668      For testing and perhaps advanced use allow some more symbols.  */
669   locale_special (name, show_category_name, show_keyword_name);
670 }