/* * * Copyright (c) 2016 Konstantin Pugin * Konstantin Pugin (ria.freelander@gmail.com) * * Licensed under the LGPL v3. * * A 'locale' command implementation for musl. * */ #include #include #include #include #include #include #include #include #include #include #include #include #include #include "config.h" #include "categories.h" /* If set print the name of the category. */ static bool show_category_name = 0; /* If set print the name of the item. */ static bool show_keyword_name = 0; /* If set print the usage command. */ static bool show_usage = 0; /* Print names of all available locales. */ static bool do_all = 0; /* Print names of all available character maps. */ static bool do_charmaps = 0; static int remaining = 0; static void usage(char *name) { char *s; s = basename(name); fprintf(stderr, gettext ("Usage: %s [-a | -m] [FORMAT] name...\n\n" "\t-a, --all-locales\tWrite names of all available locales\n" "\t-m, --charmaps\tWrite names of available charmaps\n" "\nFORMAT:\n" "\t-c, --category-name\tWrite names of selected categories\n" "\t-k, --keyword-name\tWrite names of selected keywords\n" ), s); } static int argp_parse(int argc, char *argv[]) { int c; char *progname; static const struct option long_options[] = { {"all-locales", no_argument, NULL, 'a'}, {"charmaps", no_argument, NULL, 'm'}, {"category-name", no_argument, NULL, 'c'}, {"keyword-name", no_argument, NULL, 'k'}, {"help", no_argument, NULL, 'h'}, {NULL, 0, NULL, 0}}; progname = *argv; while ((c = getopt_long(argc, argv, "amckh", long_options, NULL)) >= 0) switch (c) { case 'a': do_all = 1; break; case 'c': show_category_name = 1; break; case 'm': do_charmaps = 1; break; case 'k': show_keyword_name = 1; break; case 'h': show_usage = 1; break; case '?': fprintf(stderr, gettext("Unknown option.\n")); usage(progname); return 1; default: fprintf(stderr, gettext("This should never happen!\n")); return 1; } remaining = optind; return 0; } static void list_locale() { const char *locpath = getenv("MUSL_LOCPATH"); printf("C\n"); printf("C.UTF-8\n"); if(locpath != NULL) { DIR *dir = opendir(locpath); struct dirent *pDir; while ((pDir = readdir(dir)) != NULL){ if (strcmp(pDir->d_name,".") && strcmp(pDir->d_name,"..")) printf("%s\n",pDir->d_name); } } } static void list_charmaps() { printf("ASCII\n"); printf("UTF-8\n"); return; } static void print_item (struct cat_item item) { switch (item.type) { case CAT_TYPE_STRING: if (show_keyword_name) printf ("%s=\"", item.name); fputs (nl_langinfo (item.id) ? : "", stdout); if (show_keyword_name) putchar ('"'); putchar ('\n'); break; case CAT_TYPE_STRINGARRAY: { const char *val; if (show_keyword_name) printf ("%s=\"", item.name); for (int cnt = item.min; cnt <= item.max; cnt++) { val = nl_langinfo (cnt); if (val != NULL) fputs (val, stdout); if (cnt < item.max) putchar (';'); } if (show_keyword_name) putchar ('"'); putchar ('\n'); } break; } } /* Show the information request for NAME. */ static void show_info(const char *name) { for (size_t cat_no = 0; cat_no < LC_ALL; cat_no++) { if (strcmp (name, get_name_for_cat(cat_no)) == 0) /* Print the whole category. */ { if (show_category_name != 0) puts (get_name_for_cat(cat_no)); const struct cat_item* items = get_cat_for_locale_cat(cat_no); for(int j = 0; items[j].type != CAT_TYPE_END; j++) print_item(items[j]); return; } } if (show_category_name != 0) puts (get_cat_name_for_item_name(name)); print_item(get_cat_item_for_name(name)); } static void show_locale_vars() { const char *lcall = getenv("LC_ALL") ? : "\0"; const char *lang = getenv("LANG") ? : ""; /* LANG has to be the first value. */ printf("LANG=%s\n", lang); for (size_t cat_no = 0; cat_no < LC_ALL; ++cat_no) { printf("%s=%s\n",get_name_for_cat(cat_no),lcall[0] != '\0' ? lcall : lang[0] != '\0' ? lang : "POSIX"); } /* The last is the LC_ALL value. */ printf("LC_ALL=%s\n", lcall); } int main(int argc, char *argv[]) { if (setlocale (LC_CTYPE, "") == NULL) fprintf (stderr, gettext ("Cannot set LC_CTYPE to default locale")); if (setlocale (LC_MESSAGES, "") == NULL) fprintf (stderr, gettext ("Cannot set LC_MESSAGES to default locale")); bindtextdomain(PACKAGE,LOCALEDIR); textdomain(PACKAGE); /* Parse and process arguments. */ if (argp_parse(argc, argv)) return 1; if (do_all) { if (setlocale (LC_COLLATE, "") == NULL) fprintf (stderr, gettext ("Cannot set LC_COLLATE to default locale")); else list_locale(); exit(EXIT_SUCCESS); } if (do_charmaps) { list_charmaps(); exit(EXIT_SUCCESS); } if (show_usage) { usage(*argv); exit(EXIT_SUCCESS); } if (setlocale (LC_ALL, "") == NULL) fprintf (stderr, gettext ("Cannot set LC_ALL to default locale")); /* 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 (remaining == argc && show_category_name == 0 && show_keyword_name == 0) { show_locale_vars(); exit(EXIT_SUCCESS); } /* Process all given names. */ while (remaining < argc) show_info(argv[remaining++]); exit(EXIT_SUCCESS); }