/* Copyright (C) 1995 Free Software Foundation, Inc. The GNU C Library is free software; you can redistribute it and/or modify it under the terms of the GNU Library General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. The GNU C Library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Library General Public License for more details. You should have received a copy of the GNU Library General Public License along with the GNU C Library; see the file COPYING.LIB. If not, write to the Free Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ #include #include #include #include #include #include #include #include #include #include #include "localedef.h" /* If set dump C code describing the current locale. */ static int do_dump; /* If set print the name of the category. */ static int show_category_name; /* If set print the name of the item. */ static int show_keyword_name; /* Long options. */ static const struct option long_options[] = { { "all-locales", no_argument, NULL, 'a' }, { "category-name", no_argument, &show_category_name, 1 }, { "charmaps", no_argument, NULL, 'm' }, { "dump", no_argument, &do_dump, 1 }, { "help", no_argument, NULL, 'h' }, { "keyword-name", no_argument, &show_keyword_name, 1 }, { "version", no_argument, NULL, 'v' }, { NULL, 0, NULL, 0 } }; /* We don't have these constants defined because we don't use them. Give default values. */ #define CTYPE_MB_CUR_MIN 0 #define CTYPE_MB_CUR_MAX 0 #define CTYPE_HASH_SIZE 0 #define CTYPE_HASH_LAYERS 0 #define CTYPE_CLASS 0 #define CTYPE_TOUPPER_EB 0 #define CTYPE_TOLOWER_EB 0 #define CTYPE_TOUPPER_EL 0 #define CTYPE_TOLOWER_EL 0 /* We have all categories defined in `categories.def'. Now construct the description and data structure used for all categories. */ #define DEFINE_CATEGORY(category, name, items, postload, in, check, out) \ static struct cat_item category##_desc[] = \ { \ NO_PAREN items \ }; #include "categories.def" #undef DEFINE_CATEGORY static struct category category[] = { #define DEFINE_CATEGORY(category, name, items, postload, in, check, out) \ { _NL_NUM_##category, name, NELEMS (category##_desc) - 1, \ category##_desc, NULL, NULL, NULL, out }, #include "categories.def" #undef DEFINE_CATEGORY }; #define NCATEGORIES NELEMS (category) /* Prototypes for local functions. */ static void usage (int status) __attribute__ ((noreturn)); static void write_locales (void); static void write_charmaps (void); static void show_locale_vars (void); static void show_info (const char *name); static void dump_category (const char *name); int main (int argc, char *argv[]) { int optchar; int do_all = 0; int do_help = 0; int do_version = 0; int do_charmaps = 0; /* Set initial values for global varaibles. */ do_dump = 0; show_category_name = 0; show_keyword_name = 0; /* Set locale. Do not set LC_ALL because the other categories must not be affected (acccording to POSIX.2). */ setlocale (LC_CTYPE, ""); setlocale (LC_MESSAGES, ""); /* Initialize the message catalog. */ textdomain (PACKAGE); while ((optchar = getopt_long (argc, argv, "achkmv", long_options, NULL)) != EOF) switch (optchar) { case '\0': break; case 'a': do_all = 1; break; case 'c': show_category_name = 1; break; case 'h': do_help = 1; break; case 'k': show_keyword_name = 1; break; case 'm': do_charmaps = 1; break; case 'v': do_version = 1; break; default: error (1, 0, gettext ("illegal option \"%s\""), optarg); break; } /* Version information is requested. */ if (do_version) { fprintf (stderr, "GNU %s %s\n", PACKAGE, VERSION); exit (EXIT_SUCCESS); } /* Help is requested. */ if (do_help) usage (EXIT_SUCCESS); /* Dump C code. */ if (do_dump) { printf ("\ /* Generated by GNU %s %s. */\n\ \n\ #include \"localeinfo.h\"\n", program_invocation_name, VERSION); while (optind < argc) dump_category (argv[optind++]); exit (EXIT_SUCCESS); } /* `-a' requests the names of all available locales. */ if (do_all != 0) { write_locales (); exit (EXIT_SUCCESS); } /* `m' requests the names of all available charmaps. The names can be used for the -f argument to localedef(3). */ if (do_charmaps != 0) { write_charmaps (); exit (EXIT_SUCCESS); } /* If no real argument is given we have to print the contents of the current locale definition variables. These are LANG and the LC_*. */ if (optind == argc && show_keyword_name == 0 && show_category_name == 0) { show_locale_vars (); exit (EXIT_SUCCESS); } /* Process all given names. */ while (optind < argc) show_info (argv[optind++]); exit (EXIT_SUCCESS); } /* Display usage information and exit. */ static void usage(int status) { if (status != EXIT_SUCCESS) fprintf (stderr, gettext ("Try `%s --help' for more information.\n"), program_invocation_name); else printf(gettext ("\ Usage: %s [OPTION]... name\n\ Mandatory arguments to long options are mandatory for short options too.\n\ -h, --help display this help and exit\n\ -v, --version output version information and exit\n\ \n\ -a, --all-locales write names of available locales\n\ -m, --charmaps write names of available charmaps\n\ \n\ -c, --category-name write names of selected categories\n\ -k, --keyword-name write names of selected keywords\n\ \n\ --dump dump C code describing the current locale\n\ (this code can be used in the C library)\n\ "), program_invocation_name); exit (status); } /* Write the names of all available locales to stdout. */ static void write_locales (void) { DIR *dir; struct dirent *dirent; /* `POSIX' locale is always available (POSIX.2 4.34.3). */ puts ("POSIX"); dir = opendir (LOCALE_PATH); if (dir == NULL) { error (1, errno, gettext ("cannot read locale directory `%s'"), LOCALE_PATH); return; } /* Now we can look for all files in the directory. */ while ((dirent = readdir (dir)) != NULL) if (strcmp (dirent->d_name, ".") != 0 && strcmp (dirent->d_name, "..") != 0) puts (dirent->d_name); closedir (dir); } /* Write the names of all available character maps to stdout. */ static void write_charmaps (void) { DIR *dir; struct dirent *dirent; dir = opendir (CHARMAP_PATH); if (dir == NULL) { error (1, errno, gettext ("cannot read character map directory `%s'"), CHARMAP_PATH); return; } /* Now we can look for all files in the directory. */ while ((dirent = readdir (dir)) != NULL) if (strcmp (dirent->d_name, ".") != 0 && strcmp (dirent->d_name, "..") != 0) puts (dirent->d_name); closedir (dir); } /* We have to show the contents of the environments determining the locale. */ static void show_locale_vars (void) { size_t cat_no; const char *lcall = getenv ("LC_ALL"); const char *lang = getenv ("LANG") ? : "POSIX"; void get_source (const char *name) { char *val = getenv (name); if (lcall != NULL || val == NULL) printf ("%s=\"%s\"\n", name, lcall ? : lang); else printf ("%s=%s\n", name, val); } /* LANG has to be the first value. */ printf ("LANG=%s\n", lang); /* Now all categories in an unspecified order. */ for (cat_no = 0; cat_no < NCATEGORIES; ++cat_no) get_source (category[cat_no].name); /* The last is the LC_ALL value. */ printf ("LC_ALL=%s\n", lcall ? : ""); } /* Show the information request for NAME. */ static void show_info (const char *name) { size_t cat_no; void print_item (struct cat_item *item) { if (show_keyword_name != 0) printf ("%s=", item->name); switch (item->value_type) { case string: printf ("%s%s%s", show_keyword_name ? "\"" : "", nl_langinfo (item->item_id) ? : "", show_keyword_name ? "\"" : ""); break; case stringarray: { int cnt; const char *val; if (show_keyword_name) putchar ('"'); for (cnt = 0; cnt < item->max - 1; ++cnt) { val = nl_langinfo (item->item_id + cnt); printf ("%s;", val ? : ""); } val = nl_langinfo (item->item_id + cnt); printf ("%s", val ? : ""); if (show_keyword_name) putchar ('"'); } break; case byte: { const char *val = nl_langinfo (item->item_id); if (val != NULL) printf ("%d", *val == CHAR_MAX ? -1 : *val); } break; case bytearray: { const char *val = nl_langinfo (item->item_id); int cnt = val ? strlen (val) : 0; while (cnt > 1) { printf ("%d;", *val == CHAR_MAX ? -1 : *val); --cnt; ++val; } printf ("%d", cnt == 0 || *val == CHAR_MAX ? -1 : *val); } break; default: } putchar ('\n'); } for (cat_no = 0; cat_no < NCATEGORIES; ++cat_no) { size_t item_no; if (category[cat_no].outfct != NULL) /* Categories which need special handling of the output are not written. This is especially for LC_CTYPE and LC_COLLATE. It does not make sense to have this large number of cryptic characters displayed. */ continue; if (strcmp (name, category[cat_no].name) == 0) /* Print the whole category. */ { if (show_category_name != 0) puts (category[cat_no].name); for (item_no = 0; item_no < category[cat_no].number; ++item_no) print_item (&category[cat_no].item_desc[item_no]); return; } for (item_no = 0; item_no < category[cat_no].number; ++item_no) if (strcmp (name, category[cat_no].item_desc[item_no].name) == 0) { if (show_category_name != 0) puts (category[cat_no].name); print_item (&category[cat_no].item_desc[item_no]); return; } } } static void dump_category (const char *name) { char *locname; size_t cat_no, item_no, nstrings; for (cat_no = 0; cat_no < NCATEGORIES; ++cat_no) if (strcmp (name, category[cat_no].name) == 0) break; if (cat_no >= NCATEGORIES) return; /* The NAME specifies a correct locale category. */ if (category[cat_no].outfct != NULL) { category[cat_no].outfct (); return; } locname = (getenv ("LC_ALL") ?: getenv (name) ?: getenv ("LANG") ?: (char *) "POSIX"); /* Determine the number of strings in advance. */ nstrings = 0; for (item_no = 0; item_no < category[cat_no].number; ++item_no) switch (category[cat_no].item_desc[item_no].value_type) { case string: case byte: case bytearray: ++nstrings; break; case stringarray: nstrings += category[cat_no].item_desc[item_no].max; default: } printf ("\nconst struct locale_data _nl_%s_%s =\n{\n" " NULL, 0, /* no file mapped */\n %Zu,\n {\n", locname, name, nstrings); for (item_no = 0; item_no < category[cat_no].number; ++item_no) switch (category[cat_no].item_desc[item_no].value_type) { case string: { const char *val = nl_langinfo ( category[cat_no].item_desc[item_no].item_id); if (val != NULL) printf (" \"%s\",\n", val); else puts (" NULL,"); } break; case stringarray: { const char *val; int cnt; for (cnt = 0; cnt < category[cat_no].item_desc[item_no].max; ++cnt) { val = nl_langinfo ( category[cat_no].item_desc[item_no].item_id + cnt); if (val != NULL) printf (" \"%s\",\n", val); else puts (" NULL,"); } } break; case byte: { const char *val = nl_langinfo ( category[cat_no].item_desc[item_no].item_id); if (val != NULL) printf (" \"\\%o\",\n", *(unsigned char *) val ? : UCHAR_MAX); else puts (" NULL,"); } break; case bytearray: { const char *bytes = nl_langinfo ( category[cat_no].item_desc[item_no].item_id); if (bytes != NULL) { fputs (" \"", stdout); if (*bytes != '\0') do printf ("\\%o", *(unsigned char *) bytes++); while (*bytes != '\0'); else printf ("\\%o", UCHAR_MAX); puts ("\","); } else puts (" NULL,"); } break; default: break; } puts (" }\n};"); } /* * Local Variables: * mode:c * c-basic-offset:2 * End: */