2.5-18.1
[platform/upstream/glibc.git] / locale / programs / locale.c
1 /* Implementation of the locale program according to POSIX 9945-2.
2    Copyright (C) 1995-1997, 1999-2005, 2006 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    This program is free software; you can redistribute it and/or modify
7    it under the terms of the GNU General Public License version 2 as
8    published by the Free Software Foundation.
9
10    This program is distributed in the hope that it will be useful,
11    but WITHOUT ANY WARRANTY; without even the implied warranty of
12    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13    GNU General Public License for more details.
14
15    You should have received a copy of the GNU General Public License
16    along with this program; if not, write to the Free Software Foundation,
17    Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.  */
18
19 #ifdef HAVE_CONFIG_H
20 # include <config.h>
21 #endif
22
23 #include <argp.h>
24 #include <argz.h>
25 #include <dirent.h>
26 #include <errno.h>
27 #include <error.h>
28 #include <fcntl.h>
29 #include <langinfo.h>
30 #include <libintl.h>
31 #include <limits.h>
32 #include <locale.h>
33 #include <search.h>
34 #include <stdio.h>
35 #include <stdio_ext.h>
36 #include <stdlib.h>
37 #include <string.h>
38 #include <unistd.h>
39 #include <sys/mman.h>
40 #include <sys/stat.h>
41
42 #include "localeinfo.h"
43 #include "charmap-dir.h"
44 #include "../locarchive.h"
45
46 extern void *xmalloc (size_t __n);
47 extern char *xstrdup (const char *__str);
48
49 #define ARCHIVE_NAME LOCALEDIR "/locale-archive"
50
51 /* If set print the name of the category.  */
52 static int show_category_name;
53
54 /* If set print the name of the item.  */
55 static int show_keyword_name;
56
57 /* Print names of all available locales.  */
58 static int do_all;
59
60 /* Print names of all available character maps.  */
61 static int do_charmaps = 0;
62
63 /* Nonzero if verbose output is wanted.  */
64 static int verbose;
65
66 /* Name and version of program.  */
67 static void print_version (FILE *stream, struct argp_state *state);
68 void (*argp_program_version_hook) (FILE *, struct argp_state *) = print_version;
69
70 /* Definitions of arguments for argp functions.  */
71 static const struct argp_option options[] =
72 {
73   { NULL, 0, NULL, 0, N_("System information:") },
74   { "all-locales", 'a', NULL, OPTION_NO_USAGE,
75     N_("Write names of available locales") },
76   { "charmaps", 'm', NULL, OPTION_NO_USAGE,
77     N_("Write names of available charmaps") },
78   { NULL, 0, NULL, 0, N_("Modify output format:") },
79   { "category-name", 'c', NULL, 0, N_("Write names of selected categories") },
80   { "keyword-name", 'k', NULL, 0, N_("Write names of selected keywords") },
81   { "verbose", 'v', NULL, 0, N_("Print more information") },
82   { NULL, 0, NULL, 0, NULL }
83 };
84
85 /* Short description of program.  */
86 static const char doc[] = N_("Get locale-specific information.\v\
87 For bug reporting instructions, please see:\n\
88 <http://www.gnu.org/software/libc/bugs.html>.\n");
89
90 /* Strings for arguments in help texts.  */
91 static const char args_doc[] = N_("NAME\n[-a|-m]");
92
93 /* Prototype for option handler.  */
94 static error_t parse_opt (int key, char *arg, struct argp_state *state);
95
96 /* Data structure to communicate with argp functions.  */
97 static struct argp argp =
98 {
99   options, parse_opt, args_doc, doc
100 };
101
102
103 /* We don't have these constants defined because we don't use them.  Give
104    default values.  */
105 #define CTYPE_MB_CUR_MIN 0
106 #define CTYPE_MB_CUR_MAX 0
107 #define CTYPE_HASH_SIZE 0
108 #define CTYPE_HASH_LAYERS 0
109 #define CTYPE_CLASS 0
110 #define CTYPE_TOUPPER_EB 0
111 #define CTYPE_TOLOWER_EB 0
112 #define CTYPE_TOUPPER_EL 0
113 #define CTYPE_TOLOWER_EL 0
114
115 /* Definition of the data structure which represents a category and its
116    items.  */
117 struct category
118 {
119   int cat_id;
120   const char *name;
121   size_t number;
122   struct cat_item
123   {
124     int item_id;
125     const char *name;
126     enum { std, opt } status;
127     enum value_type value_type;
128     int min;
129     int max;
130   } *item_desc;
131 };
132
133 /* Simple helper macro.  */
134 #define NELEMS(arr) ((sizeof (arr)) / (sizeof (arr[0])))
135
136 /* For some tricky stuff.  */
137 #define NO_PAREN(Item, More...) Item, ## More
138
139 /* We have all categories defined in `categories.def'.  Now construct
140    the description and data structure used for all categories.  */
141 #define DEFINE_ELEMENT(Item, More...) { Item, ## More },
142 #define DEFINE_CATEGORY(category, name, items, postload) \
143     static struct cat_item category##_desc[] =                                \
144       {                                                                       \
145         NO_PAREN items                                                        \
146       };
147
148 #include "categories.def"
149 #undef DEFINE_CATEGORY
150
151 static struct category category[] =
152   {
153 #define DEFINE_CATEGORY(category, name, items, postload) \
154     [category] = { _NL_NUM_##category, name, NELEMS (category##_desc),        \
155                    category##_desc },
156 #include "categories.def"
157 #undef DEFINE_CATEGORY
158   };
159 #define NCATEGORIES NELEMS (category)
160
161
162 /* Automatically set variable.  */
163 extern const char *__progname;
164
165 /* helper function for extended name handling.  */
166 extern void locale_special (const char *name, int show_category_name,
167                             int show_keyword_name);
168
169 /* Prototypes for local functions.  */
170 static void print_LC_IDENTIFICATION (void *mapped, size_t size);
171 static void print_LC_CTYPE (void *mapped, size_t size);
172 static void write_locales (void);
173 static int nameentcmp (const void *a, const void *b);
174 static int write_archive_locales (void **all_datap, char *linebuf);
175 static void write_charmaps (void);
176 static void show_locale_vars (void);
177 static void show_info (const char *name);
178
179
180 int
181 main (int argc, char *argv[])
182 {
183   int remaining;
184
185   /* Set initial values for global variables.  */
186   show_category_name = 0;
187   show_keyword_name = 0;
188
189   /* Set locale.  Do not set LC_ALL because the other categories must
190      not be affected (according to POSIX.2).  */
191   if (setlocale (LC_CTYPE, "") == NULL)
192     error (0, errno, gettext ("Cannot set LC_CTYPE to default locale"));
193   if (setlocale (LC_MESSAGES, "") == NULL)
194     error (0, errno, gettext ("Cannot set LC_MESSAGES to default locale"));
195
196   /* Initialize the message catalog.  */
197   textdomain (PACKAGE);
198
199   /* Parse and process arguments.  */
200   argp_parse (&argp, argc, argv, 0, &remaining, NULL);
201
202   /* `-a' requests the names of all available locales.  */
203   if (do_all != 0)
204     {
205       if (setlocale (LC_COLLATE, "") == NULL)
206         error (0, errno,
207                gettext ("Cannot set LC_COLLATE to default locale"));
208       write_locales ();
209       exit (EXIT_SUCCESS);
210     }
211
212   /* `m' requests the names of all available charmaps.  The names can be
213      used for the -f argument to localedef(1).  */
214   if (do_charmaps != 0)
215     {
216       write_charmaps ();
217       exit (EXIT_SUCCESS);
218     }
219
220   /* Specific information about the current locale are requested.
221      Change to this locale now.  */
222   if (setlocale (LC_ALL, "") == NULL)
223     error (0, errno, gettext ("Cannot set LC_ALL to default locale"));
224
225   /* If no real argument is given we have to print the contents of the
226      current locale definition variables.  These are LANG and the LC_*.  */
227   if (remaining == argc && show_keyword_name == 0 && show_category_name == 0)
228     {
229       show_locale_vars ();
230       exit (EXIT_SUCCESS);
231     }
232
233   /* Process all given names.  */
234   while (remaining <  argc)
235     show_info (argv[remaining++]);
236
237   exit (EXIT_SUCCESS);
238 }
239
240
241 /* Handle program arguments.  */
242 static error_t
243 parse_opt (int key, char *arg, struct argp_state *state)
244 {
245   switch (key)
246     {
247     case 'a':
248       do_all = 1;
249       break;
250     case 'c':
251       show_category_name = 1;
252       break;
253     case 'm':
254       do_charmaps = 1;
255       break;
256     case 'k':
257       show_keyword_name = 1;
258       break;
259     case 'v':
260       verbose = 1;
261       break;
262     default:
263       return ARGP_ERR_UNKNOWN;
264     }
265   return 0;
266 }
267
268
269 /* Print the version information.  */
270 static void
271 print_version (FILE *stream, struct argp_state *state)
272 {
273   fprintf (stream, "locale (GNU %s) %s\n", PACKAGE, VERSION);
274   fprintf (stream, gettext ("\
275 Copyright (C) %s Free Software Foundation, Inc.\n\
276 This is free software; see the source for copying conditions.  There is NO\n\
277 warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.\n\
278 "), "2006");
279   fprintf (stream, gettext ("Written by %s.\n"), "Ulrich Drepper");
280 }
281
282
283 /* Simple action function which prints arguments as strings.  */
284 static void
285 print_names (const void *nodep, VISIT value, int level)
286 {
287   if (value == postorder || value == leaf)
288     puts (*(char **) nodep);
289 }
290
291
292 static int
293 select_dirs (const struct dirent *dirent)
294 {
295   int result = 0;
296
297   if (strcmp (dirent->d_name, ".") != 0 && strcmp (dirent->d_name, "..") != 0)
298     {
299       mode_t mode = 0;
300
301 #ifdef _DIRENT_HAVE_D_TYPE
302       if (dirent->d_type != DT_UNKNOWN && dirent->d_type != DT_LNK)
303         mode = DTTOIF (dirent->d_type);
304       else
305 #endif
306         {
307           struct stat64 st;
308           char buf[sizeof (LOCALEDIR) + strlen (dirent->d_name) + 1];
309
310           stpcpy (stpcpy (stpcpy (buf, LOCALEDIR), "/"), dirent->d_name);
311
312           if (stat64 (buf, &st) == 0)
313             mode = st.st_mode;
314         }
315
316       result = S_ISDIR (mode);
317     }
318
319   return result;
320 }
321
322
323 static void
324 print_LC_IDENTIFICATION (void *mapped, size_t size)
325 {
326   /* Read the information from the file.  */
327   struct
328     {
329       unsigned int magic;
330       unsigned int nstrings;
331       unsigned int strindex[0];
332     } *filedata = mapped;
333
334   if (filedata->magic == LIMAGIC (LC_IDENTIFICATION)
335       && (sizeof *filedata
336           + (filedata->nstrings
337              * sizeof (unsigned int))
338           <= size))
339     {
340       const char *str;
341
342 #define HANDLE(idx, name) \
343   str = ((char *) mapped                                                      \
344          + filedata->strindex[_NL_ITEM_INDEX (_NL_IDENTIFICATION_##idx)]);    \
345   if (*str != '\0')                                                           \
346     printf ("%9s | %s\n", name, str)
347       HANDLE (TITLE, "title");
348       HANDLE (SOURCE, "source");
349       HANDLE (ADDRESS, "address");
350       HANDLE (CONTACT, "contact");
351       HANDLE (EMAIL, "email");
352       HANDLE (TEL, "telephone");
353       HANDLE (FAX, "fax");
354       HANDLE (LANGUAGE, "language");
355       HANDLE (TERRITORY, "territory");
356       HANDLE (AUDIENCE, "audience");
357       HANDLE (APPLICATION, "application");
358       HANDLE (ABBREVIATION, "abbreviation");
359       HANDLE (REVISION, "revision");
360       HANDLE (DATE, "date");
361     }
362 }
363
364
365 static void
366 print_LC_CTYPE (void *mapped, size_t size)
367 {
368   struct
369     {
370       unsigned int magic;
371       unsigned int nstrings;
372       unsigned int strindex[0];
373     } *filedata = mapped;
374
375   if (filedata->magic == LIMAGIC (LC_CTYPE)
376       && (sizeof *filedata
377           + (filedata->nstrings
378              * sizeof (unsigned int))
379           <= size))
380     {
381       const char *str;
382
383       str = ((char *) mapped
384              + filedata->strindex[_NL_ITEM_INDEX (_NL_CTYPE_CODESET_NAME)]);
385       if (*str != '\0')
386         printf ("  codeset | %s\n", str);
387     }
388 }
389
390
391 /* Write the names of all available locales to stdout.  We have some
392    sources of the information: the contents of the locale directory
393    and the locale.alias file.  To avoid duplicates and print the
394    result is a reasonable order we put all entries is a search tree
395    and print them afterwards.  */
396 static void
397 write_locales (void)
398 {
399   char linebuf[80];
400   void *all_data = NULL;
401   struct dirent **dirents;
402   int ndirents;
403   int cnt;
404   char *alias_path;
405   size_t alias_path_len;
406   char *entry;
407   int first_locale = 1;
408
409 #define PUT(name) tsearch (name, &all_data, \
410                            (int (*) (const void *, const void *)) strcoll)
411 #define GET(name) tfind (name, &all_data, \
412                            (int (*) (const void *, const void *)) strcoll)
413
414   /* `POSIX' locale is always available (POSIX.2 4.34.3).  */
415   PUT ("POSIX");
416   /* And so is the "C" locale.  */
417   PUT ("C");
418
419   memset (linebuf, '-', sizeof (linebuf) - 1);
420   linebuf[sizeof (linebuf) - 1] = '\0';
421
422   /* First scan the locale archive.  */
423   if (write_archive_locales (&all_data, linebuf))
424     first_locale = 0;
425
426   /* Now we can look for all files in the directory.  */
427   ndirents = scandir (LOCALEDIR, &dirents, select_dirs, alphasort);
428   for (cnt = 0; cnt < ndirents; ++cnt)
429     {
430       /* Test whether at least the LC_CTYPE data is there.  Some
431          directories only contain translations.  */
432       char buf[sizeof (LOCALEDIR) + strlen (dirents[cnt]->d_name)
433               + sizeof "/LC_IDENTIFICATION"];
434       char *enddir;
435       struct stat64 st;
436
437       stpcpy (enddir = stpcpy (stpcpy (stpcpy (buf, LOCALEDIR), "/"),
438                                dirents[cnt]->d_name),
439               "/LC_IDENTIFICATION");
440
441       if (stat64 (buf, &st) == 0 && S_ISREG (st.st_mode))
442         {
443           if (verbose && GET (dirents[cnt]->d_name) == NULL)
444             {
445               /* Provide some nice output of all kinds of
446                  information.  */
447               int fd;
448
449               if (! first_locale)
450                 putchar_unlocked ('\n');
451               first_locale = 0;
452
453               printf ("locale: %-15.15s directory: %.*s\n%s\n",
454                       dirents[cnt]->d_name, (int) (enddir - buf), buf,
455                       linebuf);
456
457               fd = open64 (buf, O_RDONLY);
458               if (fd != -1)
459                 {
460                   void *mapped = mmap64 (NULL, st.st_size, PROT_READ,
461                                          MAP_SHARED, fd, 0);
462                   if (mapped != MAP_FAILED)
463                     {
464                       print_LC_IDENTIFICATION (mapped, st.st_size);
465
466                       munmap (mapped, st.st_size);
467                     }
468
469                   close (fd);
470
471                   /* Now try to get the charset information.  */
472                   strcpy (enddir, "/LC_CTYPE");
473                   fd = open64 (buf, O_RDONLY);
474                   if (fd != -1 && fstat64 (fd, &st) >= 0
475                       && ((mapped = mmap64 (NULL, st.st_size, PROT_READ,
476                                             MAP_SHARED, fd, 0))
477                           != MAP_FAILED))
478                     {
479                       print_LC_CTYPE (mapped, st.st_size);
480
481                       munmap (mapped, st.st_size);
482                     }
483
484                   if (fd != -1)
485                     close (fd);
486                 }
487             }
488
489           /* If the verbose format is not selected we simply
490              collect the names.  */
491           PUT (xstrdup (dirents[cnt]->d_name));
492         }
493     }
494   if (ndirents > 0)
495     free (dirents);
496
497   /* Now read the locale.alias files.  */
498   if (argz_create_sep (LOCALE_ALIAS_PATH, ':', &alias_path, &alias_path_len))
499     error (1, errno, gettext ("while preparing output"));
500
501   entry = NULL;
502   while ((entry = argz_next (alias_path, alias_path_len, entry)))
503     {
504       static const char aliasfile[] = "/locale.alias";
505       FILE *fp;
506       char full_name[strlen (entry) + sizeof aliasfile];
507
508       stpcpy (stpcpy (full_name, entry), aliasfile);
509       fp = fopen (full_name, "rm");
510       if (fp == NULL)
511         /* Ignore non-existing files.  */
512         continue;
513
514       /* No threads present.  */
515       __fsetlocking (fp, FSETLOCKING_BYCALLER);
516
517       while (! feof_unlocked (fp))
518         {
519           /* It is a reasonable approach to use a fix buffer here
520              because
521              a) we are only interested in the first two fields
522              b) these fields must be usable as file names and so must
523                 not be that long  */
524           char buf[BUFSIZ];
525           char *alias;
526           char *value;
527           char *cp;
528
529           if (fgets_unlocked (buf, BUFSIZ, fp) == NULL)
530             /* EOF reached.  */
531             break;
532
533           cp = buf;
534           /* Ignore leading white space.  */
535           while (isspace (cp[0]) && cp[0] != '\n')
536             ++cp;
537
538           /* A leading '#' signals a comment line.  */
539           if (cp[0] != '\0' && cp[0] != '#' && cp[0] != '\n')
540             {
541               alias = cp++;
542               while (cp[0] != '\0' && !isspace (cp[0]))
543                 ++cp;
544               /* Terminate alias name.  */
545               if (cp[0] != '\0')
546                 *cp++ = '\0';
547
548               /* Now look for the beginning of the value.  */
549               while (isspace (cp[0]))
550                 ++cp;
551
552               if (cp[0] != '\0')
553                 {
554                   value = cp++;
555                   while (cp[0] != '\0' && !isspace (cp[0]))
556                     ++cp;
557                   /* Terminate value.  */
558                   if (cp[0] == '\n')
559                     {
560                       /* This has to be done to make the following
561                          test for the end of line possible.  We are
562                          looking for the terminating '\n' which do not
563                          overwrite here.  */
564                       *cp++ = '\0';
565                       *cp = '\n';
566                     }
567                   else if (cp[0] != '\0')
568                     *cp++ = '\0';
569
570                   /* Add the alias.  */
571                   if (! verbose && GET (value) != NULL)
572                     PUT (xstrdup (alias));
573                 }
574             }
575
576           /* Possibly not the whole line fits into the buffer.
577              Ignore the rest of the line.  */
578           while (strchr (cp, '\n') == NULL)
579             {
580               cp = buf;
581               if (fgets_unlocked (buf, BUFSIZ, fp) == NULL)
582                 /* Make sure the inner loop will be left.  The outer
583                    loop will exit at the `feof' test.  */
584                 *cp = '\n';
585             }
586         }
587
588       fclose (fp);
589     }
590
591   if (! verbose)
592     {
593       twalk (all_data, print_names);
594     }
595 }
596
597
598 struct nameent
599 {
600   char *name;
601   uint32_t locrec_offset;
602 };
603
604
605 static int
606 nameentcmp (const void *a, const void *b)
607 {
608   return strcoll (((const struct nameent *) a)->name,
609                   ((const struct nameent *) b)->name);
610 }
611
612
613 static int
614 write_archive_locales (void **all_datap, char *linebuf)
615 {
616   struct stat64 st;
617   void *all_data = *all_datap;
618   size_t len = 0;
619   struct locarhead *head;
620   struct namehashent *namehashtab;
621   char *addr = MAP_FAILED;
622   int fd, ret = 0;
623   uint32_t cnt;
624
625   fd = open64 (ARCHIVE_NAME, O_RDONLY);
626   if (fd < 0)
627     return 0;
628
629   if (fstat64 (fd, &st) < 0 || st.st_size < sizeof (*head))
630     goto error_out;
631
632   len = st.st_size;
633   addr = mmap64 (NULL, len, PROT_READ, MAP_SHARED, fd, 0);
634   if (addr == MAP_FAILED)
635     goto error_out;
636
637   head = (struct locarhead *) addr;
638   if (head->namehash_offset + head->namehash_size > len
639       || head->string_offset + head->string_size > len
640       || head->locrectab_offset + head->locrectab_size > len
641       || head->sumhash_offset + head->sumhash_size > len)
642     goto error_out;
643
644   namehashtab = (struct namehashent *) (addr + head->namehash_offset);
645   if (! verbose)
646     {
647       for (cnt = 0; cnt < head->namehash_size; ++cnt)
648         if (namehashtab[cnt].locrec_offset != 0)
649           {
650             PUT (xstrdup (addr + namehashtab[cnt].name_offset));
651             ++ret;
652           }
653     }
654   else
655     {
656       struct nameent *names;
657       uint32_t used;
658
659       names = (struct nameent *) xmalloc (head->namehash_used
660                                           * sizeof (struct nameent));
661       for (cnt = used = 0; cnt < head->namehash_size; ++cnt)
662         if (namehashtab[cnt].locrec_offset != 0)
663           {
664             names[used].name = addr + namehashtab[cnt].name_offset;
665             names[used++].locrec_offset = namehashtab[cnt].locrec_offset;
666           }
667
668       /* Sort the names.  */
669       qsort (names, used, sizeof (struct nameent), nameentcmp);
670
671       for (cnt = 0; cnt < used; ++cnt)
672         {
673           struct locrecent *locrec;
674
675           PUT (xstrdup (names[cnt].name));
676
677           if (cnt)
678             putchar_unlocked ('\n');
679
680           printf ("locale: %-15.15s archive: " ARCHIVE_NAME "\n%s\n",
681                   names[cnt].name, linebuf);
682
683           locrec = (struct locrecent *) (addr + names[cnt].locrec_offset);
684
685           print_LC_IDENTIFICATION (addr
686                                    + locrec->record[LC_IDENTIFICATION].offset,
687                                    locrec->record[LC_IDENTIFICATION].len);
688
689           print_LC_CTYPE (addr + locrec->record[LC_CTYPE].offset,
690                           locrec->record[LC_CTYPE].len);
691         }
692
693       ret = used;
694     }
695
696 error_out:
697   if (addr != MAP_FAILED)
698     munmap (addr, len);
699   close (fd);
700   *all_datap = all_data;
701   return ret;
702 }
703
704
705 /* Write the names of all available character maps to stdout.  */
706 static void
707 write_charmaps (void)
708 {
709   void *all_data = NULL;
710   CHARMAP_DIR *dir;
711   const char *dirent;
712
713   /* Look for all files in the charmap directory.  */
714   dir = charmap_opendir (CHARMAP_PATH);
715   if (dir == NULL)
716     return;
717
718   while ((dirent = charmap_readdir (dir)) != NULL)
719     {
720       char **aliases;
721       char **p;
722
723       PUT (xstrdup (dirent));
724
725       aliases = charmap_aliases (CHARMAP_PATH, dirent);
726
727 #if 0
728       /* Add the code_set_name and the aliases.  */
729       for (p = aliases; *p; p++)
730         PUT (xstrdup (*p));
731 #else
732       /* Add the code_set_name only.  Most aliases are obsolete.  */
733       p = aliases;
734       if (*p)
735         PUT (xstrdup (*p));
736 #endif
737
738       charmap_free_aliases (aliases);
739     }
740
741   charmap_closedir (dir);
742
743   twalk (all_data, print_names);
744 }
745
746
747 /* We have to show the contents of the environments determining the
748    locale.  */
749 static void
750 show_locale_vars (void)
751 {
752   size_t cat_no;
753   const char *lcall = getenv ("LC_ALL");
754   const char *lang = getenv ("LANG") ? : "";
755
756   auto void get_source (const char *name);
757
758   void get_source (const char *name)
759     {
760       char *val = getenv (name);
761
762       if ((lcall ?: "")[0] != '\0' || val == NULL)
763         printf ("%s=\"%s\"\n", name,
764                 (lcall ?: "")[0] ? lcall : (lang ?: "")[0] ? lang : "POSIX");
765       else
766         printf ("%s=%s\n", name, val);
767     }
768
769   /* LANG has to be the first value.  */
770   printf ("LANG=%s\n", lang);
771
772   /* Now all categories in an unspecified order.  */
773   for (cat_no = 0; cat_no < NCATEGORIES; ++cat_no)
774     if (cat_no != LC_ALL)
775       get_source (category[cat_no].name);
776
777   /* The last is the LC_ALL value.  */
778   printf ("LC_ALL=%s\n", lcall ? : "");
779 }
780
781
782 /* Show the information request for NAME.  */
783 static void
784 show_info (const char *name)
785 {
786   size_t cat_no;
787
788   auto void print_item (struct cat_item *item);
789
790   void print_item (struct cat_item *item)
791     {
792       switch (item->value_type)
793         {
794         case string:
795           if (show_keyword_name)
796             printf ("%s=\"", item->name);
797           fputs (nl_langinfo (item->item_id) ? : "", stdout);
798           if (show_keyword_name)
799             putchar ('"');
800           putchar ('\n');
801           break;
802         case stringarray:
803           {
804             int cnt;
805             const char *val;
806
807             if (show_keyword_name)
808               printf ("%s=\"", item->name);
809
810             for (cnt = 0; cnt < item->max - 1; ++cnt)
811               {
812                 val = nl_langinfo (item->item_id + cnt);
813                 if (val != NULL)
814                   fputs (val, stdout);
815                 putchar (';');
816               }
817
818             val = nl_langinfo (item->item_id + cnt);
819             if (val != NULL)
820               fputs (val, stdout);
821
822             if (show_keyword_name)
823               putchar ('"');
824             putchar ('\n');
825           }
826           break;
827         case stringlist:
828           {
829             int first = 1;
830             const char *val = nl_langinfo (item->item_id) ? : "";
831             int cnt;
832
833             if (show_keyword_name)
834               printf ("%s=", item->name);
835
836             for (cnt = 0; cnt < item->max && *val != '\0'; ++cnt)
837               {
838                 printf ("%s%s%s%s", first ? "" : ";",
839                         show_keyword_name ? "\"" : "", val,
840                         show_keyword_name ? "\"" : "");
841                 val = strchr (val, '\0') + 1;
842                 first = 0;
843               }
844             putchar ('\n');
845           }
846           break;
847         case byte:
848           {
849             const char *val = nl_langinfo (item->item_id);
850
851             if (show_keyword_name)
852               printf ("%s=", item->name);
853
854             if (val != NULL)
855               printf ("%d", *val == '\177' ? -1 : *val);
856             putchar ('\n');
857           }
858           break;
859         case bytearray:
860           {
861             const char *val = nl_langinfo (item->item_id);
862             int cnt = val ? strlen (val) : 0;
863
864             if (show_keyword_name)
865               printf ("%s=", item->name);
866
867             while (cnt > 1)
868               {
869                 printf ("%d;", *val == '\177' ? -1 : *val);
870                 --cnt;
871                 ++val;
872               }
873
874             printf ("%d\n", cnt == 0 || *val == '\177' ? -1 : *val);
875           }
876           break;
877         case word:
878           {
879             union { unsigned int word; char *string; } val;
880             val.string = nl_langinfo (item->item_id);
881             if (show_keyword_name)
882               printf ("%s=", item->name);
883
884             printf ("%d\n", val.word);
885           }
886           break;
887         case wstring:
888         case wstringarray:
889         case wstringlist:
890           /* We don't print wide character information since the same
891              information is available in a multibyte string.  */
892         default:
893           break;
894
895         }
896     }
897
898   for (cat_no = 0; cat_no < NCATEGORIES; ++cat_no)
899     if (cat_no != LC_ALL)
900       {
901         size_t item_no;
902
903         if (strcmp (name, category[cat_no].name) == 0)
904           /* Print the whole category.  */
905           {
906             if (show_category_name != 0)
907               puts (category[cat_no].name);
908
909             for (item_no = 0; item_no < category[cat_no].number; ++item_no)
910               print_item (&category[cat_no].item_desc[item_no]);
911
912             return;
913           }
914
915         for (item_no = 0; item_no < category[cat_no].number; ++item_no)
916           if (strcmp (name, category[cat_no].item_desc[item_no].name) == 0)
917             {
918               if (show_category_name != 0)
919                 puts (category[cat_no].name);
920
921               print_item (&category[cat_no].item_desc[item_no]);
922               return;
923             }
924       }
925
926   /* The name is not a standard one.
927      For testing and perhaps advanced use allow some more symbols.  */
928   locale_special (name, show_category_name, show_keyword_name);
929 }