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