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