1 /* Implementation of the locale program according to POSIX 9945-2.
2 Copyright (C) 1995-1997, 1999-2008, 2009 Free Software Foundation, Inc.
3 This file is part of the GNU C Library.
4 Contributed by Ulrich Drepper <drepper@cygnus.com>, 1995.
6 This program is free software; you can redistribute it and/or modify
7 it under the terms of the GNU General Public License as published
8 by the Free Software Foundation; version 2 of the License, or
9 (at your option) any later version.
11 This program 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
14 GNU General Public License for more details.
16 You should have received a copy of the GNU General Public License
17 along with this program; if not, write to the Free Software Foundation,
18 Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */
36 #include <stdio_ext.h>
43 #include "localeinfo.h"
44 #include "charmap-dir.h"
45 #include "../locarchive.h"
47 extern void *xmalloc (size_t __n
);
48 extern char *xstrdup (const char *__str
);
50 #define ARCHIVE_NAME LOCALEDIR "/locale-archive"
52 /* If set print the name of the category. */
53 static int show_category_name
;
55 /* If set print the name of the item. */
56 static int show_keyword_name
;
58 /* Print names of all available locales. */
61 /* Print names of all available character maps. */
62 static int do_charmaps
= 0;
64 /* Nonzero if verbose output is wanted. */
67 /* Name and version of program. */
68 static void print_version (FILE *stream
, struct argp_state
*state
);
69 void (*argp_program_version_hook
) (FILE *, struct argp_state
*) = print_version
;
71 /* Definitions of arguments for argp functions. */
72 static const struct argp_option options
[] =
74 { NULL
, 0, NULL
, 0, N_("System information:") },
75 { "all-locales", 'a', NULL
, OPTION_NO_USAGE
,
76 N_("Write names of available locales") },
77 { "charmaps", 'm', NULL
, OPTION_NO_USAGE
,
78 N_("Write names of available charmaps") },
79 { NULL
, 0, NULL
, 0, N_("Modify output format:") },
80 { "category-name", 'c', NULL
, 0, N_("Write names of selected categories") },
81 { "keyword-name", 'k', NULL
, 0, N_("Write names of selected keywords") },
82 { "verbose", 'v', NULL
, 0, N_("Print more information") },
83 { NULL
, 0, NULL
, 0, NULL
}
86 /* Short description of program. */
87 static const char doc
[] = N_("Get locale-specific information.");
89 /* Strings for arguments in help texts. */
90 static const char args_doc
[] = N_("NAME\n[-a|-m]");
92 /* Prototype for option handler. */
93 static error_t
parse_opt (int key
, char *arg
, struct argp_state
*state
);
95 /* Function to print some extra text in the help message. */
96 static char *more_help (int key
, const char *text
, void *input
);
98 /* Data structure to communicate with argp functions. */
99 static struct argp argp
=
101 options
, parse_opt
, args_doc
, doc
, NULL
, more_help
105 /* We don't have these constants defined because we don't use them. Give
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
117 /* Definition of the data structure which represents a category and its
128 enum { std
, opt
} status
;
129 enum value_type value_type
;
135 /* Simple helper macro. */
136 #define NELEMS(arr) ((sizeof (arr)) / (sizeof (arr[0])))
138 /* For some tricky stuff. */
139 #define NO_PAREN(Item, More...) Item, ## More
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[] = \
150 #include "categories.def"
151 #undef DEFINE_CATEGORY
153 static struct category category
[] =
155 #define DEFINE_CATEGORY(category, name, items, postload) \
156 [category] = { _NL_NUM_##category, name, NELEMS (category##_desc), \
158 #include "categories.def"
159 #undef DEFINE_CATEGORY
161 #define NCATEGORIES NELEMS (category)
164 /* Automatically set variable. */
165 extern const char *__progname
;
167 /* helper function for extended name handling. */
168 extern void locale_special (const char *name
, int show_category_name
,
169 int show_keyword_name
);
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
);
183 main (int argc
, char *argv
[])
187 /* Set initial values for global variables. */
188 show_category_name
= 0;
189 show_keyword_name
= 0;
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"));
198 /* Initialize the message catalog. */
199 textdomain (PACKAGE
);
201 /* Parse and process arguments. */
202 argp_parse (&argp
, argc
, argv
, 0, &remaining
, NULL
);
204 /* `-a' requests the names of all available locales. */
207 if (setlocale (LC_COLLATE
, "") == NULL
)
209 gettext ("Cannot set LC_COLLATE to default locale"));
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)
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"));
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)
235 /* Process all given names. */
236 while (remaining
< argc
)
237 show_info (argv
[remaining
++]);
243 /* Handle program arguments. */
245 parse_opt (int key
, char *arg
, struct argp_state
*state
)
253 show_category_name
= 1;
259 show_keyword_name
= 1;
265 return ARGP_ERR_UNKNOWN
;
272 more_help (int key
, const char *text
, void *input
)
276 case ARGP_KEY_HELP_EXTRA
:
277 /* We print some extra information. */
278 return strdup (gettext ("\
279 For bug reporting instructions, please see:\n\
280 <http://www.gnu.org/software/libc/bugs.html>.\n"));
284 return (char *) text
;
288 /* Print the version information. */
290 print_version (FILE *stream
, struct argp_state
*state
)
292 fprintf (stream
, "locale (GNU %s) %s\n", PACKAGE
, VERSION
);
293 fprintf (stream
, gettext ("\
294 Copyright (C) %s Free Software Foundation, Inc.\n\
295 This is free software; see the source for copying conditions. There is NO\n\
296 warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.\n\
298 fprintf (stream
, gettext ("Written by %s.\n"), "Ulrich Drepper");
302 /* Simple action function which prints arguments as strings. */
304 print_names (const void *nodep
, VISIT value
, int level
)
306 if (value
== postorder
|| value
== leaf
)
307 puts (*(char **) nodep
);
312 select_dirs (const struct dirent
*dirent
)
316 if (strcmp (dirent
->d_name
, ".") != 0 && strcmp (dirent
->d_name
, "..") != 0)
320 #ifdef _DIRENT_HAVE_D_TYPE
321 if (dirent
->d_type
!= DT_UNKNOWN
&& dirent
->d_type
!= DT_LNK
)
322 mode
= DTTOIF (dirent
->d_type
);
327 char buf
[sizeof (LOCALEDIR
) + strlen (dirent
->d_name
) + 1];
329 stpcpy (stpcpy (stpcpy (buf
, LOCALEDIR
), "/"), dirent
->d_name
);
331 if (stat64 (buf
, &st
) == 0)
335 result
= S_ISDIR (mode
);
343 print_LC_IDENTIFICATION (void *mapped
, size_t size
)
345 /* Read the information from the file. */
349 unsigned int nstrings
;
350 unsigned int strindex
[0];
351 } *filedata
= mapped
;
353 if (filedata
->magic
== LIMAGIC (LC_IDENTIFICATION
)
355 + (filedata
->nstrings
356 * sizeof (unsigned int))
361 #define HANDLE(idx, name) \
362 str = ((char *) mapped \
363 + filedata->strindex[_NL_ITEM_INDEX (_NL_IDENTIFICATION_##idx)]); \
365 printf ("%9s | %s\n", name, str)
366 HANDLE (TITLE
, "title");
367 HANDLE (SOURCE
, "source");
368 HANDLE (ADDRESS
, "address");
369 HANDLE (CONTACT
, "contact");
370 HANDLE (EMAIL
, "email");
371 HANDLE (TEL
, "telephone");
373 HANDLE (LANGUAGE
, "language");
374 HANDLE (TERRITORY
, "territory");
375 HANDLE (AUDIENCE
, "audience");
376 HANDLE (APPLICATION
, "application");
377 HANDLE (ABBREVIATION
, "abbreviation");
378 HANDLE (REVISION
, "revision");
379 HANDLE (DATE
, "date");
385 print_LC_CTYPE (void *mapped
, size_t size
)
390 unsigned int nstrings
;
391 unsigned int strindex
[0];
392 } *filedata
= mapped
;
394 if (filedata
->magic
== LIMAGIC (LC_CTYPE
)
396 + (filedata
->nstrings
397 * sizeof (unsigned int))
402 str
= ((char *) mapped
403 + filedata
->strindex
[_NL_ITEM_INDEX (_NL_CTYPE_CODESET_NAME
)]);
405 printf (" codeset | %s\n", str
);
410 /* Write the names of all available locales to stdout. We have some
411 sources of the information: the contents of the locale directory
412 and the locale.alias file. To avoid duplicates and print the
413 result is a reasonable order we put all entries is a search tree
414 and print them afterwards. */
419 void *all_data
= NULL
;
420 struct dirent
**dirents
;
424 size_t alias_path_len
;
426 int first_locale
= 1;
428 #define PUT(name) tsearch (name, &all_data, \
429 (int (*) (const void *, const void *)) strcoll)
430 #define GET(name) tfind (name, &all_data, \
431 (int (*) (const void *, const void *)) strcoll)
433 /* `POSIX' locale is always available (POSIX.2 4.34.3). */
435 /* And so is the "C" locale. */
438 memset (linebuf
, '-', sizeof (linebuf
) - 1);
439 linebuf
[sizeof (linebuf
) - 1] = '\0';
441 /* First scan the locale archive. */
442 if (write_archive_locales (&all_data
, linebuf
))
445 /* Now we can look for all files in the directory. */
446 ndirents
= scandir (LOCALEDIR
, &dirents
, select_dirs
, alphasort
);
447 for (cnt
= 0; cnt
< ndirents
; ++cnt
)
449 /* Test whether at least the LC_CTYPE data is there. Some
450 directories only contain translations. */
451 char buf
[sizeof (LOCALEDIR
) + strlen (dirents
[cnt
]->d_name
)
452 + sizeof "/LC_IDENTIFICATION"];
456 stpcpy (enddir
= stpcpy (stpcpy (stpcpy (buf
, LOCALEDIR
), "/"),
457 dirents
[cnt
]->d_name
),
458 "/LC_IDENTIFICATION");
460 if (stat64 (buf
, &st
) == 0 && S_ISREG (st
.st_mode
))
462 if (verbose
&& GET (dirents
[cnt
]->d_name
) == NULL
)
464 /* Provide some nice output of all kinds of
469 putchar_unlocked ('\n');
472 printf ("locale: %-15.15s directory: %.*s\n%s\n",
473 dirents
[cnt
]->d_name
, (int) (enddir
- buf
), buf
,
476 fd
= open64 (buf
, O_RDONLY
);
479 void *mapped
= mmap64 (NULL
, st
.st_size
, PROT_READ
,
481 if (mapped
!= MAP_FAILED
)
483 print_LC_IDENTIFICATION (mapped
, st
.st_size
);
485 munmap (mapped
, st
.st_size
);
490 /* Now try to get the charset information. */
491 strcpy (enddir
, "/LC_CTYPE");
492 fd
= open64 (buf
, O_RDONLY
);
493 if (fd
!= -1 && fstat64 (fd
, &st
) >= 0
494 && ((mapped
= mmap64 (NULL
, st
.st_size
, PROT_READ
,
498 print_LC_CTYPE (mapped
, st
.st_size
);
500 munmap (mapped
, st
.st_size
);
508 /* If the verbose format is not selected we simply
509 collect the names. */
510 PUT (xstrdup (dirents
[cnt
]->d_name
));
516 /* Now read the locale.alias files. */
517 if (argz_create_sep (LOCALE_ALIAS_PATH
, ':', &alias_path
, &alias_path_len
))
518 error (1, errno
, gettext ("while preparing output"));
521 while ((entry
= argz_next (alias_path
, alias_path_len
, entry
)))
523 static const char aliasfile
[] = "/locale.alias";
525 char full_name
[strlen (entry
) + sizeof aliasfile
];
527 stpcpy (stpcpy (full_name
, entry
), aliasfile
);
528 fp
= fopen (full_name
, "rm");
530 /* Ignore non-existing files. */
533 /* No threads present. */
534 __fsetlocking (fp
, FSETLOCKING_BYCALLER
);
536 while (! feof_unlocked (fp
))
538 /* It is a reasonable approach to use a fix buffer here
540 a) we are only interested in the first two fields
541 b) these fields must be usable as file names and so must
548 if (fgets_unlocked (buf
, BUFSIZ
, fp
) == NULL
)
553 /* Ignore leading white space. */
554 while (isspace (cp
[0]) && cp
[0] != '\n')
557 /* A leading '#' signals a comment line. */
558 if (cp
[0] != '\0' && cp
[0] != '#' && cp
[0] != '\n')
561 while (cp
[0] != '\0' && !isspace (cp
[0]))
563 /* Terminate alias name. */
567 /* Now look for the beginning of the value. */
568 while (isspace (cp
[0]))
574 while (cp
[0] != '\0' && !isspace (cp
[0]))
576 /* Terminate value. */
579 /* This has to be done to make the following
580 test for the end of line possible. We are
581 looking for the terminating '\n' which do not
586 else if (cp
[0] != '\0')
590 if (! verbose
&& GET (value
) != NULL
)
591 PUT (xstrdup (alias
));
595 /* Possibly not the whole line fits into the buffer.
596 Ignore the rest of the line. */
597 while (strchr (cp
, '\n') == NULL
)
600 if (fgets_unlocked (buf
, BUFSIZ
, fp
) == NULL
)
601 /* Make sure the inner loop will be left. The outer
602 loop will exit at the `feof' test. */
612 twalk (all_data
, print_names
);
620 uint32_t locrec_offset
;
625 nameentcmp (const void *a
, const void *b
)
627 return strcoll (((const struct nameent
*) a
)->name
,
628 ((const struct nameent
*) b
)->name
);
633 write_archive_locales (void **all_datap
, char *linebuf
)
636 void *all_data
= *all_datap
;
638 struct locarhead
*head
;
639 struct namehashent
*namehashtab
;
640 char *addr
= MAP_FAILED
;
644 fd
= open64 (ARCHIVE_NAME
, O_RDONLY
);
648 if (fstat64 (fd
, &st
) < 0 || st
.st_size
< sizeof (*head
))
652 addr
= mmap64 (NULL
, len
, PROT_READ
, MAP_SHARED
, fd
, 0);
653 if (addr
== MAP_FAILED
)
656 head
= (struct locarhead
*) addr
;
657 if (head
->namehash_offset
+ head
->namehash_size
> len
658 || head
->string_offset
+ head
->string_size
> len
659 || head
->locrectab_offset
+ head
->locrectab_size
> len
660 || head
->sumhash_offset
+ head
->sumhash_size
> len
)
663 namehashtab
= (struct namehashent
*) (addr
+ head
->namehash_offset
);
666 for (cnt
= 0; cnt
< head
->namehash_size
; ++cnt
)
667 if (namehashtab
[cnt
].locrec_offset
!= 0)
669 PUT (xstrdup (addr
+ namehashtab
[cnt
].name_offset
));
675 struct nameent
*names
;
678 names
= (struct nameent
*) xmalloc (head
->namehash_used
679 * sizeof (struct nameent
));
680 for (cnt
= used
= 0; cnt
< head
->namehash_size
; ++cnt
)
681 if (namehashtab
[cnt
].locrec_offset
!= 0)
683 names
[used
].name
= addr
+ namehashtab
[cnt
].name_offset
;
684 names
[used
++].locrec_offset
= namehashtab
[cnt
].locrec_offset
;
687 /* Sort the names. */
688 qsort (names
, used
, sizeof (struct nameent
), nameentcmp
);
690 for (cnt
= 0; cnt
< used
; ++cnt
)
692 struct locrecent
*locrec
;
694 PUT (xstrdup (names
[cnt
].name
));
697 putchar_unlocked ('\n');
699 printf ("locale: %-15.15s archive: " ARCHIVE_NAME
"\n%s\n",
700 names
[cnt
].name
, linebuf
);
702 locrec
= (struct locrecent
*) (addr
+ names
[cnt
].locrec_offset
);
704 print_LC_IDENTIFICATION (addr
705 + locrec
->record
[LC_IDENTIFICATION
].offset
,
706 locrec
->record
[LC_IDENTIFICATION
].len
);
708 print_LC_CTYPE (addr
+ locrec
->record
[LC_CTYPE
].offset
,
709 locrec
->record
[LC_CTYPE
].len
);
716 if (addr
!= MAP_FAILED
)
719 *all_datap
= all_data
;
724 /* Write the names of all available character maps to stdout. */
726 write_charmaps (void)
728 void *all_data
= NULL
;
732 /* Look for all files in the charmap directory. */
733 dir
= charmap_opendir (CHARMAP_PATH
);
737 while ((dirent
= charmap_readdir (dir
)) != NULL
)
742 PUT (xstrdup (dirent
));
744 aliases
= charmap_aliases (CHARMAP_PATH
, dirent
);
747 /* Add the code_set_name and the aliases. */
748 for (p
= aliases
; *p
; p
++)
751 /* Add the code_set_name only. Most aliases are obsolete. */
757 charmap_free_aliases (aliases
);
760 charmap_closedir (dir
);
762 twalk (all_data
, print_names
);
766 /* We have to show the contents of the environments determining the
769 show_locale_vars (void)
772 const char *lcall
= getenv ("LC_ALL");
773 const char *lang
= getenv ("LANG") ? : "";
775 auto void get_source (const char *name
);
777 void get_source (const char *name
)
779 char *val
= getenv (name
);
781 if ((lcall
?: "")[0] != '\0' || val
== NULL
)
782 printf ("%s=\"%s\"\n", name
,
783 (lcall
?: "")[0] ? lcall
: (lang
?: "")[0] ? lang
: "POSIX");
785 printf ("%s=%s\n", name
, val
);
788 /* LANG has to be the first value. */
789 printf ("LANG=%s\n", lang
);
791 /* Now all categories in an unspecified order. */
792 for (cat_no
= 0; cat_no
< NCATEGORIES
; ++cat_no
)
793 if (cat_no
!= LC_ALL
)
794 get_source (category
[cat_no
].name
);
796 /* The last is the LC_ALL value. */
797 printf ("LC_ALL=%s\n", lcall
? : "");
801 /* Show the information request for NAME. */
803 show_info (const char *name
)
807 auto void print_item (struct cat_item
*item
);
809 void print_item (struct cat_item
*item
)
811 switch (item
->value_type
)
814 if (show_keyword_name
)
815 printf ("%s=\"", item
->name
);
816 fputs (nl_langinfo (item
->item_id
) ? : "", stdout
);
817 if (show_keyword_name
)
826 if (show_keyword_name
)
827 printf ("%s=\"", item
->name
);
829 for (cnt
= 0; cnt
< item
->max
- 1; ++cnt
)
831 val
= nl_langinfo (item
->item_id
+ cnt
);
837 val
= nl_langinfo (item
->item_id
+ cnt
);
841 if (show_keyword_name
)
849 const char *val
= nl_langinfo (item
->item_id
) ? : "";
852 if (show_keyword_name
)
853 printf ("%s=", item
->name
);
855 for (cnt
= 0; cnt
< item
->max
&& *val
!= '\0'; ++cnt
)
857 printf ("%s%s%s%s", first
? "" : ";",
858 show_keyword_name
? "\"" : "", val
,
859 show_keyword_name
? "\"" : "");
860 val
= strchr (val
, '\0') + 1;
868 const char *val
= nl_langinfo (item
->item_id
);
870 if (show_keyword_name
)
871 printf ("%s=", item
->name
);
874 printf ("%d", *val
== '\177' ? -1 : *val
);
880 const char *val
= nl_langinfo (item
->item_id
);
881 int cnt
= val
? strlen (val
) : 0;
883 if (show_keyword_name
)
884 printf ("%s=", item
->name
);
888 printf ("%d;", *val
== '\177' ? -1 : *val
);
893 printf ("%d\n", cnt
== 0 || *val
== '\177' ? -1 : *val
);
898 union { unsigned int word
; char *string
; } val
;
899 val
.string
= nl_langinfo (item
->item_id
);
900 if (show_keyword_name
)
901 printf ("%s=", item
->name
);
903 printf ("%d\n", val
.word
);
909 /* We don't print wide character information since the same
910 information is available in a multibyte string. */
917 for (cat_no
= 0; cat_no
< NCATEGORIES
; ++cat_no
)
918 if (cat_no
!= LC_ALL
)
922 if (strcmp (name
, category
[cat_no
].name
) == 0)
923 /* Print the whole category. */
925 if (show_category_name
!= 0)
926 puts (category
[cat_no
].name
);
928 for (item_no
= 0; item_no
< category
[cat_no
].number
; ++item_no
)
929 print_item (&category
[cat_no
].item_desc
[item_no
]);
934 for (item_no
= 0; item_no
< category
[cat_no
].number
; ++item_no
)
935 if (strcmp (name
, category
[cat_no
].item_desc
[item_no
].name
) == 0)
937 if (show_category_name
!= 0)
938 puts (category
[cat_no
].name
);
940 print_item (&category
[cat_no
].item_desc
[item_no
]);
945 /* The name is not a standard one.
946 For testing and perhaps advanced use allow some more symbols. */
947 locale_special (name
, show_category_name
, show_keyword_name
);