summaryrefslogtreecommitdiff
path: root/extra/locale/programs/locale.c
diff options
context:
space:
mode:
authorCarmelo Amoroso <carmelo.amoroso@st.com>2008-05-02 13:57:02 +0000
committerCarmelo Amoroso <carmelo.amoroso@st.com>2008-05-02 13:57:02 +0000
commitfc5abf4933bebea46105b5bb9cd81b77ae670fc9 (patch)
tree034ca6caf7b421f0780ada4fb8c235749f1a8bee /extra/locale/programs/locale.c
parent2167a906ffd7499685e25af093107db4770a7069 (diff)
Added implementation for 'locale' command.
Signed-off-by: Filippo Arcidiacono <filippo.arcidiacono@st.com>
Diffstat (limited to 'extra/locale/programs/locale.c')
-rw-r--r--extra/locale/programs/locale.c466
1 files changed, 466 insertions, 0 deletions
diff --git a/extra/locale/programs/locale.c b/extra/locale/programs/locale.c
new file mode 100644
index 000000000..0ec9515fb
--- /dev/null
+++ b/extra/locale/programs/locale.c
@@ -0,0 +1,466 @@
+/*
+ *
+ * Copyright (c) 2008 STMicroelectronics Ltd
+ * Filippo Arcidiacono (filippo.arcidiacono@st.com)
+ *
+ * Licensed under the LGPL v2.1, see the file COPYING.LIB in this tarball.
+ *
+ * A 'locale' command implementation for uClibc.
+ *
+ */
+
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <langinfo.h>
+#include <getopt.h>
+
+typedef struct {
+ unsigned char idx_name;
+ char dot_cs; /* 0 if no codeset specified */
+ char cs;
+ unsigned char lc_ctype_row;
+ unsigned char lc_numeric_row;
+ unsigned char lc_monetary_row;
+ unsigned char lc_time_row;
+ unsigned char lc_collate_row;
+ unsigned char lc_messages_row;
+} locale_entry;
+
+/* Need to include this before locale.h and xlocale.h! */
+#include <bits/uClibc_locale.h>
+
+#undef CODESET_LIST
+#define CODESET_LIST (__locale_mmap->codeset_list)
+#include <locale.h>
+#define LOCALE_NAMES (__locale_mmap->locale_names5)
+#define LOCALES (__locale_mmap->locales)
+#define LOCALE_AT_MODIFIERS (__locale_mmap->locale_at_modifiers)
+#define CATEGORY_NAMES (__locale_mmap->lc_names)
+
+#define GET_CODESET_NAME(N) (CODESET_LIST + *(CODESET_LIST + N - 3))
+#define GET_LOCALE_ENTRY(R) (locale_entry *)(LOCALES + (__LOCALE_DATA_WIDTH_LOCALES * R))
+#define GET_CATEGORY_NAME(X) (CATEGORY_NAMES + *(CATEGORY_NAMES + X))
+#define GET_LOCALE_NAME(I) (const char *)(LOCALE_NAMES + 5 * (I - 1))
+
+static const char utf8[] = "UTF-8";
+static const char ascii[] = "ASCII";
+
+/* If set print the name of the category. */
+static int show_category_name = 0;
+
+/* If set print the name of the item. */
+static int show_keyword_name = 0;
+
+/* If set print the usage command. */
+static int show_usage = 0;
+
+/* Print names of all available locales. */
+static int do_all = 0;
+
+/* Print names of all available character maps. */
+static int do_charmaps = 0;
+
+static int remaining = 0;
+
+/* We can map the types of the entries into a few categories. */
+enum value_type
+{
+ none,
+ string,
+ stringarray,
+ byte,
+ bytearray,
+ word,
+ stringlist,
+ wordarray,
+ wstring,
+ wstringarray,
+ wstringlist
+};
+
+/* Definition of the data structure which represents a category and its
+ items. */
+struct category
+{
+ int cat_id;
+ const char *name;
+ size_t number;
+ struct cat_item
+ {
+ int item_id;
+ const char *name;
+ enum { std, opt } status;
+ enum value_type value_type;
+ int min;
+ int max;
+ } *item_desc;
+};
+
+/* Simple helper macro. */
+#define NELEMS(arr) ((sizeof (arr)) / (sizeof (arr[0])))
+
+/* For some tricky stuff. */
+#define NO_PAREN(Item, More...) Item, ## More
+
+/* We have all categories defined in `categories.def'. Now construct
+ the description and data structure used for all categories. */
+#define DEFINE_ELEMENT(Item, More...) { Item, ## More },
+#define DEFINE_CATEGORY(category, name, items, postload) \
+ 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) \
+ [category] = { _NL_NUM_##category, name, NELEMS (category##_desc), \
+ category##_desc },
+#include "categories.def"
+#undef DEFINE_CATEGORY
+ };
+#define NCATEGORIES NELEMS (category)
+
+static void usage(const char *name);
+static void usage(const char *name)
+{
+ const char *s;
+
+ s = basename(name);
+ fprintf(stderr,
+ "Usage: %s [-ck] [--category-name] [--keyword-name] [--help] NAME\n"
+ "or: %s [OPTION...] [-a|-m] [--all-locales] [--charmaps] \n", s, s);
+}
+
+static int argp_parse(int argc, char *argv[]);
+static int argp_parse(int argc, char *argv[])
+{
+ 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 }
+ };
+ int c;
+ char *progname;
+
+ 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, "Unknown option.\n");
+ usage(progname);
+ return 1;
+
+ default:
+ fprintf (stderr, "This should never happen!\n");
+ return 1;
+ }
+
+ remaining = optind;
+
+ return 0;
+}
+
+static unsigned const char * find_at(char c);
+static unsigned const char * find_at(char c)
+{
+ const unsigned char *q;
+
+ q = LOCALE_AT_MODIFIERS;
+ do {
+ if (q[1] == c) {
+ return (unsigned const char *)q+2;
+ }
+ q += 2 + *q;
+ } while (*q);
+
+ return NULL;
+}
+
+static void find_locale_string(locale_entry *loc_rec, char *loc)
+{
+ char at = 0;
+ unsigned char idx;
+ uint16_t dotcs, cs;
+
+ idx = loc_rec->idx_name;
+ if (!idx) {
+ *loc++ = 'C'; /* jump the first locale (C) */
+ *loc = '\0';
+ }
+ else {
+ dotcs = (uint16_t) loc_rec->dot_cs;
+ cs = (uint16_t) loc_rec->cs;;
+ loc = strncpy(loc, GET_LOCALE_NAME(idx), 5);
+
+ if (loc[2] == '_') {
+ sprintf(loc, "%5.5s%c%s\0", loc, (dotcs != 0) ? '.' : ' ',
+ (cs == 1) ? ascii : ((cs == 2) ? utf8 : GET_CODESET_NAME(cs)));
+ } else {
+ at = loc[2];
+ loc[2] = '_';
+ sprintf(loc, "%5.5s%c%s@%s\0", loc, (dotcs != 0) ? '.' : ' ',
+ (cs == 1) ? ascii : ((cs == 2) ? utf8 : GET_CODESET_NAME(cs)),
+ find_at(at));
+ }
+ }
+}
+
+static void list_locale(void);
+static void list_locale()
+{
+ char loc[40];
+ uint16_t n = 0;
+ locale_entry *locales = (locale_entry *)LOCALES;
+
+ do {
+ find_locale_string(locales, loc);
+ printf("%s\n", loc);
+ ++n;
+ locales++;
+ } while (n < __LOCALE_DATA_NUM_LOCALES);
+}
+
+static void list_charmaps(void);
+static void list_charmaps()
+{
+ unsigned const char *cl;
+
+ cl = CODESET_LIST;
+ do {
+ printf("%s\n", CODESET_LIST + *cl);
+ } while (*++cl);
+
+}
+
+static void print_item (struct cat_item *item);
+static void print_item (struct cat_item *item)
+{
+ switch (item->value_type)
+ {
+ case string:
+ if (show_keyword_name)
+ printf ("%s=\"", item->name);
+ fputs (nl_langinfo (item->item_id) ? : "", stdout);
+ if (show_keyword_name)
+ putchar ('"');
+ putchar ('\n');
+ break;
+ case stringarray:
+ {
+ int cnt;
+ const char *val;
+
+ if (show_keyword_name)
+ printf ("%s=\"", item->name);
+
+ for (cnt = 0; cnt < item->max - 1; ++cnt)
+ {
+ val = nl_langinfo (item->item_id + cnt);
+ if (val != NULL)
+ fputs (val, stdout);
+ putchar (';');
+ }
+
+ val = nl_langinfo (item->item_id + cnt);
+ if (val != NULL)
+ fputs (val, stdout);
+
+ if (show_keyword_name)
+ putchar ('"');
+ putchar ('\n');
+ }
+ break;
+ case stringlist:
+ {
+ int first = 1;
+ const char *val = nl_langinfo (item->item_id) ? : "";
+ int cnt;
+
+ if (show_keyword_name)
+ printf ("%s=", item->name);
+
+ for (cnt = 0; cnt < item->max && *val != '\0'; ++cnt)
+ {
+ printf ("%s%s%s%s", first ? "" : ";",
+ show_keyword_name ? "\"" : "", val,
+ show_keyword_name ? "\"" : "");
+ val = strchr (val, '\0') + 1;
+ first = 0;
+ }
+ putchar ('\n');
+ }
+ break;
+ case byte:
+ {
+ const char *val = nl_langinfo (item->item_id);
+
+ if (show_keyword_name)
+ printf ("%s=", item->name);
+
+ if (val != NULL)
+ printf ("%d", *val == '\177' ? -1 : *val);
+ putchar ('\n');
+ }
+ break;
+ case bytearray:
+ {
+ const char *val = nl_langinfo (item->item_id);
+ int cnt = val ? strlen (val) : 0;
+
+ if (show_keyword_name)
+ printf ("%s=", item->name);
+
+ while (cnt > 1)
+ {
+ printf ("%d;", *val == '\177' ? -1 : *val);
+ --cnt;
+ ++val;
+ }
+
+ printf ("%d\n", cnt == 0 || *val == '\177' ? -1 : *val);
+ }
+ break;
+ case word:
+ {
+ union { unsigned int word; char *string; } val;
+ val.string = nl_langinfo (item->item_id);
+ if (show_keyword_name)
+ printf ("%s=", item->name);
+
+ printf ("%d\n", val.word);
+ }
+ break;
+ case wstring:
+ case wstringarray:
+ case wstringlist:
+ /* We don't print wide character information since the same
+ information is available in a multibyte string. */
+ default:
+ break;
+
+ }
+}
+
+/* Show the information request for NAME. */
+static void show_info(const char *name);
+static void show_info(const char *name)
+{
+ size_t cat_no, item_no;
+ const unsigned char *cat_name;
+
+ /* Now all categories in an unspecified order. */
+ for (cat_no = 0; cat_no < __LC_ALL; ++cat_no) {
+ cat_name = GET_CATEGORY_NAME(cat_no);
+ if (strcmp (name, (const char *)cat_name) == 0) {
+ if (show_category_name)
+ printf("%s\n", 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 show_locale_vars(void);
+static void show_locale_vars()
+{
+ size_t cat_no;
+ int row; /* locale row */
+ const char *lcall = getenv ("LC_ALL");
+ const char *lang = getenv ("LANG") ? : "";
+ unsigned char *cur_loc = __global_locale->cur_locale + 1;
+ char loc_name[40];
+ locale_entry *locales;
+
+ /* 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 < __LC_ALL; ++cat_no) {
+ row = (((int)(*cur_loc & 0x7f)) << 7) + (cur_loc[1] & 0x7f);
+/* assert(row < __LOCALE_DATA_NUM_LOCALES); */
+
+ locales = GET_LOCALE_ENTRY(row);
+ find_locale_string(locales, loc_name);
+ printf("%s=%s\n", GET_CATEGORY_NAME(cat_no), loc_name);
+
+ cur_loc += 2;
+ }
+
+ /* The last is the LC_ALL value. */
+ printf ("LC_ALL=%s\n", lcall ? : "");
+}
+
+int
+main (int argc, char *argv[])
+{
+ /* Parse and process arguments. */
+ if (argp_parse(argc, argv))
+ return 1;
+
+ if (do_all) {
+ list_locale();
+ exit (EXIT_SUCCESS);
+ }
+
+ if (do_charmaps) {
+ list_charmaps();
+ exit (EXIT_SUCCESS);
+ }
+
+ if (show_usage) {
+ usage(*argv);
+ 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 (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);
+
+}