From f13d6dd9129f4fed3baf8d387cd11f98e005713d Mon Sep 17 00:00:00 2001 From: Jakob Kaivo Date: Wed, 13 Mar 2019 21:36:11 -0400 Subject: migrate to gitlab --- locale.c | 294 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 294 insertions(+) create mode 100644 locale.c diff --git a/locale.c b/locale.c new file mode 100644 index 0000000..7066832 --- /dev/null +++ b/locale.c @@ -0,0 +1,294 @@ +#define _XOPEN_SOURCE +#include +#include +#include +#include +#include +#include +#include + +#define ASIZEOF(_a) (sizeof(_a) / sizeof(_a[0])) + +#define FLAG_A (1<<0) +#define FLAG_C (1<<1) +#define FLAG_K (1<<2) +#define FLAG_M (1<<3) + +static char *categories[] = { + [LC_ALL] = "LC_ALL", + [LC_COLLATE] = "LC_COLLATE", + [LC_CTYPE] = "LC_CTYPE", + [LC_MESSAGES] = "LC_MESSAGES", + [LC_MONETARY] = "LC_MONETARY", + [LC_NUMERIC] = "LC_NUMERIC", + [LC_TIME] = "LC_TIME", +}; + +#define OFF(_m) (offsetof(struct lconv, _m)), {0}, 0 + +static struct { + char *name; + int cat; + enum { NL, LCS, LCI, LCA } source; + size_t noff; + nl_item items[12]; + int print; +} keywords[] = { + { "codeset", LC_CTYPE, NL, 1, { CODESET }, 0 }, + { "abday", LC_TIME, NL, 7, { ABDAY_1, ABDAY_2, ABDAY_3, ABDAY_4, + ABDAY_5, ABDAY_6, ABDAY_7 }, 0 }, + { "day", LC_TIME, NL, 7, { DAY_1, DAY_2, DAY_3, DAY_4, DAY_5, + DAY_6, DAY_7 }, 0 }, + { "abmon", LC_TIME, NL, 12, { ABMON_1, ABMON_2, ABMON_3, + ABMON_4, ABMON_5, ABMON_6, ABMON_7, + ABMON_8, ABMON_9, ABMON_10, ABMON_11, + ABMON_12 }, 0 }, + { "mon", LC_TIME, NL, 12, { MON_1, MON_2, MON_3, MON_4, MON_5, + MON_6, MON_7, MON_8, MON_9, MON_10, + MON_11, MON_12 }, 0 }, + { "am_pm", LC_TIME, NL, 2, { AM_STR, PM_STR }, 0 }, + { "d_t_fmt", LC_TIME, NL, 1, { D_T_FMT }, 0 }, + { "d_fmt", LC_TIME, NL, 1, { D_FMT }, 0 }, + { "t_fmt", LC_TIME, NL, 1, { T_FMT }, 0 }, + { "t_fmt_ampm", LC_TIME, NL, 1, { T_FMT_AMPM }, 0 }, + { "era", LC_TIME, NL, 1, { ERA }, 0 }, + { "era_d_fmt", LC_TIME, NL, 1, { ERA_D_FMT }, 0 }, + { "era_d_t_fmt",LC_TIME, NL, 1, { ERA_D_T_FMT }, 0 }, + { "era_t_fmt", LC_TIME, NL, 1, { ERA_T_FMT }, 0 }, + { "alt_digits", LC_TIME, NL, 1, { ALT_DIGITS }, 0 }, + { "yesexp", LC_MESSAGES, NL, 1, { YESEXPR }, 0 }, + { "noexpr", LC_MESSAGES, NL, 1, { NOEXPR }, 0 }, + { "crncystr", LC_MONETARY, NL, 1, { CRNCYSTR }, 0 }, + { "decimal_point", LC_NUMERIC, NL, 1, { RADIXCHAR }, 0 }, + { "thousands_sep", LC_NUMERIC, NL, 1, { THOUSEP }, 0 }, + { "int_curr_symbol", LC_MONETARY, LCS, OFF(int_curr_symbol) }, + { "currency_symbol", LC_MONETARY, LCS, OFF(currency_symbol) }, + { "mon_decimal_point", LC_MONETARY, LCS, OFF(mon_decimal_point) }, + { "mon_thousands_sep", LC_MONETARY, LCS, OFF(mon_thousands_sep) }, + { "mon_grouping", LC_MONETARY, LCA, OFF(mon_grouping) }, + { "positive_sign", LC_MONETARY, LCS, OFF(positive_sign) }, + { "negative_sign", LC_MONETARY, LCS, OFF(negative_sign) }, + { "int_frac_digits", LC_MONETARY, LCI, OFF(int_frac_digits) }, + { "frac_digits", LC_MONETARY, LCI, OFF(frac_digits) }, + { "p_cs_precedes", LC_MONETARY, LCI, OFF(p_cs_precedes) }, + { "p_sep_by_space", LC_MONETARY, LCI, OFF(p_sep_by_space) }, + { "n_cs_precedes", LC_MONETARY, LCI, OFF(n_cs_precedes) }, + { "n_sep_by_space", LC_MONETARY, LCI, OFF(n_sep_by_space) }, + { "p_sign_posn", LC_MONETARY, LCI, OFF(p_sign_posn) }, + { "n_sign_posn", LC_MONETARY, LCI, OFF(n_sign_posn) }, + { "int_p_cs_precedes", LC_MONETARY, LCI, OFF(int_p_cs_precedes) }, + { "int_n_cs_precedes", LC_MONETARY, LCI, OFF(int_n_cs_precedes) }, + { "int_p_sep_by_space", LC_MONETARY, LCI, OFF(int_p_sep_by_space) }, + { "int_n_sep_by_space", LC_MONETARY, LCI, OFF(int_n_sep_by_space) }, + { "int_p_sign_posn", LC_MONETARY, LCI, OFF(int_p_sign_posn) }, + { "int_n_sign_posn", LC_MONETARY, LCI, OFF(int_n_sign_posn) }, + { "grouping", LC_NUMERIC, LCA, OFF(grouping) }, +}; + +void printkw(size_t n, int flags) +{ + char *value = NULL; + static struct lconv *lconv = NULL; + if (lconv == NULL) { + lconv = localeconv(); + } + + if (flags & FLAG_K) { + printf("%s=", keywords[n].name); + } + + if (keywords[n].source != NL) { + value = ((char*)lconv) + keywords[n].noff; + + if (keywords[n].source == LCI) { + printf("%d\n", *value); + return; + } + + if (flags & FLAG_K) { + putchar('"'); + } + + /* value contains the address of a pointer to a string, + * not the address of a string itself, so dereference once */ + value = *((char**)value); + + if (keywords[n].source == LCS) { + printf("%s", value); + } else { + /* LCA */ + while (*value) { + printf("%hhd", *value); + value++; + if (*value) { + putchar(';'); + } + } + } + + if (flags & FLAG_K) { + putchar('"'); + } + putchar('\n'); + return; + } + + if (flags & FLAG_K) { + putchar('"'); + } + + for (size_t i = 0; i < keywords[n].noff; i++) { + value = nl_langinfo(keywords[n].items[i]); + printf("%s", value); + if (i < keywords[n].noff - 1) { + putchar(';'); + } + } + + if (flags & FLAG_K) { + putchar('"'); + } + putchar('\n'); +} + +int main(int argc, char *argv[]) +{ + int flags = 0; + int c; + + while ((c = getopt(argc, argv, "ackm")) != -1) { + switch (c) { + case 'a': + flags |= FLAG_A; + break; + + case 'c': + flags |= FLAG_C; + break; + + case 'k': + flags |= FLAG_K; + break; + + case 'm': + flags |= FLAG_M; + break; + + default: + return 1; + } + } + + setlocale(LC_ALL, ""); + + if (flags == FLAG_A) { + if (argc >= optind) { + fprintf(stderr, "no args to -a\n"); + return 1; + } + /* write about all public locales */ + /* + for (size_t i = 0; i < number_of_public_locales; i++) { + printf("%s\n", public_locale[i]); + } + */ + return 0; + } + + if (flags == FLAG_M) { + if (argc >= optind) { + fprintf(stderr, "no args to -m\n"); + } + /* write available charmaps */ + /* + for (size_t i = 0; i < number_of_available_charmaps; i++) { + printf("%s\n", available_charmaps[i]); + } + */ + return 0; + } + + if ((flags & FLAG_A) || (flags & FLAG_M)) { + fprintf(stderr, "can't combine -a or -m with other flags\n"); + return 1; + } + + char *lang = getenv("LANG"); + printf("LANG=%s\n", lang ? lang : ""); + + if (optind >= argc) { + char *lc_all = getenv("LC_ALL"); + + for (size_t i = 0; i < ASIZEOF(categories); i++) { + if (i == LC_ALL || categories[i] == NULL) { + continue; + } + + char *val = getenv(categories[i]); + if (val) { + printf("%s=%s\n", categories[i], val); + } else { + printf("%s=\"%s\"\n", categories[i], lc_all ? lc_all : lang); + } + } + + printf("LC_ALL=%s\n", lc_all ? lc_all : ""); + return 0; + } + + + do { + int found = 0; + + for (size_t i = 0; i < ASIZEOF(categories); i++) { + if (i == LC_ALL || categories[i] == NULL) { + continue; + } + + if (!strcmp(argv[optind], categories[i])) { + found = 1; + for (size_t j = 0; j < ASIZEOF(keywords); j++) { + if (keywords[j].cat == (int)i) { + keywords[j].print = 1; + } + } + break; + } + } + + if (found) { + continue; + } + + for (size_t i = 0; i < ASIZEOF(keywords); i++) { + if (!strcmp(argv[optind], keywords[i].name)) { + found = 1; + keywords[i].print = 1; + break; + } + } + + if (!found) { + fprintf(stderr, "unknown keyword '%s'\n", argv[optind]); + } + } while (argv[++optind]); + + for (size_t i = 0; i < ASIZEOF(categories); i++) { + if (i == LC_ALL || categories[i] == NULL) { + continue; + } + + int catprinted = 0; + for (size_t j = 0; j < ASIZEOF(keywords); j++) { + if (keywords[j].cat == (int)i && keywords[j].print == 1) { + if ((flags & FLAG_C) && catprinted == 0) { + printf("%s\n", categories[i]); + catprinted = 1; + } + printkw(j, flags); + } + } + } + + return 0; +} -- cgit v1.2.1