locale.c 10 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466
  1. /*
  2. *
  3. * Copyright (c) 2008 STMicroelectronics Ltd
  4. * Filippo Arcidiacono (filippo.arcidiacono@st.com)
  5. *
  6. * Licensed under the LGPL v2.1, see the file COPYING.LIB in this tarball.
  7. *
  8. * A 'locale' command implementation for uClibc.
  9. *
  10. */
  11. #include <stdio.h>
  12. #include <stdlib.h>
  13. #include <string.h>
  14. #include <langinfo.h>
  15. #include <getopt.h>
  16. typedef struct {
  17. unsigned char idx_name;
  18. char dot_cs; /* 0 if no codeset specified */
  19. char cs;
  20. unsigned char lc_ctype_row;
  21. unsigned char lc_numeric_row;
  22. unsigned char lc_monetary_row;
  23. unsigned char lc_time_row;
  24. unsigned char lc_collate_row;
  25. unsigned char lc_messages_row;
  26. } locale_entry;
  27. /* Need to include this before locale.h and xlocale.h! */
  28. #include <bits/uClibc_locale.h>
  29. #undef CODESET_LIST
  30. #define CODESET_LIST (__locale_mmap->codeset_list)
  31. #include <locale.h>
  32. #define LOCALE_NAMES (__locale_mmap->locale_names5)
  33. #define LOCALES (__locale_mmap->locales)
  34. #define LOCALE_AT_MODIFIERS (__locale_mmap->locale_at_modifiers)
  35. #define CATEGORY_NAMES (__locale_mmap->lc_names)
  36. #define GET_CODESET_NAME(N) (CODESET_LIST + *(CODESET_LIST + N - 3))
  37. #define GET_LOCALE_ENTRY(R) (locale_entry *)(LOCALES + (__LOCALE_DATA_WIDTH_LOCALES * R))
  38. #define GET_CATEGORY_NAME(X) (CATEGORY_NAMES + *(CATEGORY_NAMES + X))
  39. #define GET_LOCALE_NAME(I) (const char *)(LOCALE_NAMES + 5 * (I - 1))
  40. static const char utf8[] = "UTF-8";
  41. static const char ascii[] = "ASCII";
  42. /* If set print the name of the category. */
  43. static int show_category_name = 0;
  44. /* If set print the name of the item. */
  45. static int show_keyword_name = 0;
  46. /* If set print the usage command. */
  47. static int show_usage = 0;
  48. /* Print names of all available locales. */
  49. static int do_all = 0;
  50. /* Print names of all available character maps. */
  51. static int do_charmaps = 0;
  52. static int remaining = 0;
  53. /* We can map the types of the entries into a few categories. */
  54. enum value_type
  55. {
  56. none,
  57. string,
  58. stringarray,
  59. byte,
  60. bytearray,
  61. word,
  62. stringlist,
  63. wordarray,
  64. wstring,
  65. wstringarray,
  66. wstringlist
  67. };
  68. /* Definition of the data structure which represents a category and its
  69. items. */
  70. struct category
  71. {
  72. int cat_id;
  73. const char *name;
  74. size_t number;
  75. struct cat_item
  76. {
  77. int item_id;
  78. const char *name;
  79. enum { std, opt } status;
  80. enum value_type value_type;
  81. int min;
  82. int max;
  83. } *item_desc;
  84. };
  85. /* Simple helper macro. */
  86. #define NELEMS(arr) ((sizeof (arr)) / (sizeof (arr[0])))
  87. /* For some tricky stuff. */
  88. #define NO_PAREN(Item, More...) Item, ## More
  89. /* We have all categories defined in `categories.def'. Now construct
  90. the description and data structure used for all categories. */
  91. #define DEFINE_ELEMENT(Item, More...) { Item, ## More },
  92. #define DEFINE_CATEGORY(category, name, items, postload) \
  93. static struct cat_item category##_desc[] = \
  94. { \
  95. NO_PAREN items \
  96. };
  97. #include "categories.def"
  98. #undef DEFINE_CATEGORY
  99. static struct category category[] =
  100. {
  101. #define DEFINE_CATEGORY(category, name, items, postload) \
  102. [category] = { _NL_NUM_##category, name, NELEMS (category##_desc), \
  103. category##_desc },
  104. #include "categories.def"
  105. #undef DEFINE_CATEGORY
  106. };
  107. #define NCATEGORIES NELEMS (category)
  108. static void usage(const char *name);
  109. static void usage(const char *name)
  110. {
  111. const char *s;
  112. s = basename(name);
  113. fprintf(stderr,
  114. "Usage: %s [-ck] [--category-name] [--keyword-name] [--help] NAME\n"
  115. "or: %s [OPTION...] [-a|-m] [--all-locales] [--charmaps] \n", s, s);
  116. }
  117. static int argp_parse(int argc, char *argv[]);
  118. static int argp_parse(int argc, char *argv[])
  119. {
  120. static const struct option long_options[] =
  121. {
  122. {"all-locales", no_argument, NULL, 'a'},
  123. {"charmaps", no_argument, NULL, 'm'},
  124. {"category-name", no_argument, NULL, 'c'},
  125. {"keyword-name", no_argument, NULL, 'k'},
  126. {"help", no_argument, NULL, 'h'},
  127. {NULL, 0, NULL, 0 }
  128. };
  129. int c;
  130. char *progname;
  131. progname = *argv;
  132. while ((c = getopt_long (argc, argv, "amckh", long_options, NULL)) >= 0)
  133. switch (c)
  134. {
  135. case 'a':
  136. do_all = 1;
  137. break;
  138. case 'c':
  139. show_category_name = 1;
  140. break;
  141. case 'm':
  142. do_charmaps = 1;
  143. break;
  144. case 'k':
  145. show_keyword_name = 1;
  146. break;
  147. case 'h':
  148. show_usage = 1;
  149. break;
  150. case '?':
  151. fprintf (stderr, "Unknown option.\n");
  152. usage(progname);
  153. return 1;
  154. default:
  155. fprintf (stderr, "This should never happen!\n");
  156. return 1;
  157. }
  158. remaining = optind;
  159. return 0;
  160. }
  161. static unsigned const char * find_at(char c);
  162. static unsigned const char * find_at(char c)
  163. {
  164. const unsigned char *q;
  165. q = LOCALE_AT_MODIFIERS;
  166. do {
  167. if (q[1] == c) {
  168. return (unsigned const char *)q+2;
  169. }
  170. q += 2 + *q;
  171. } while (*q);
  172. return NULL;
  173. }
  174. static void find_locale_string(locale_entry *loc_rec, char *loc)
  175. {
  176. char at = 0;
  177. unsigned char idx;
  178. uint16_t dotcs, cs;
  179. idx = loc_rec->idx_name;
  180. if (!idx) {
  181. *loc++ = 'C'; /* jump the first locale (C) */
  182. *loc = '\0';
  183. }
  184. else {
  185. dotcs = (uint16_t) loc_rec->dot_cs;
  186. cs = (uint16_t) loc_rec->cs;;
  187. loc = strncpy(loc, GET_LOCALE_NAME(idx), 5);
  188. if (loc[2] == '_') {
  189. sprintf(loc, "%5.5s%c%s\0", loc, (dotcs != 0) ? '.' : ' ',
  190. (cs == 1) ? ascii : ((cs == 2) ? utf8 : GET_CODESET_NAME(cs)));
  191. } else {
  192. at = loc[2];
  193. loc[2] = '_';
  194. sprintf(loc, "%5.5s%c%s@%s\0", loc, (dotcs != 0) ? '.' : ' ',
  195. (cs == 1) ? ascii : ((cs == 2) ? utf8 : GET_CODESET_NAME(cs)),
  196. find_at(at));
  197. }
  198. }
  199. }
  200. static void list_locale(void);
  201. static void list_locale()
  202. {
  203. char loc[40];
  204. uint16_t n = 0;
  205. locale_entry *locales = (locale_entry *)LOCALES;
  206. do {
  207. find_locale_string(locales, loc);
  208. printf("%s\n", loc);
  209. ++n;
  210. locales++;
  211. } while (n < __LOCALE_DATA_NUM_LOCALES);
  212. }
  213. static void list_charmaps(void);
  214. static void list_charmaps()
  215. {
  216. unsigned const char *cl;
  217. cl = CODESET_LIST;
  218. do {
  219. printf("%s\n", CODESET_LIST + *cl);
  220. } while (*++cl);
  221. }
  222. static void print_item (struct cat_item *item);
  223. static void print_item (struct cat_item *item)
  224. {
  225. switch (item->value_type)
  226. {
  227. case string:
  228. if (show_keyword_name)
  229. printf ("%s=\"", item->name);
  230. fputs (nl_langinfo (item->item_id) ? : "", stdout);
  231. if (show_keyword_name)
  232. putchar ('"');
  233. putchar ('\n');
  234. break;
  235. case stringarray:
  236. {
  237. int cnt;
  238. const char *val;
  239. if (show_keyword_name)
  240. printf ("%s=\"", item->name);
  241. for (cnt = 0; cnt < item->max - 1; ++cnt)
  242. {
  243. val = nl_langinfo (item->item_id + cnt);
  244. if (val != NULL)
  245. fputs (val, stdout);
  246. putchar (';');
  247. }
  248. val = nl_langinfo (item->item_id + cnt);
  249. if (val != NULL)
  250. fputs (val, stdout);
  251. if (show_keyword_name)
  252. putchar ('"');
  253. putchar ('\n');
  254. }
  255. break;
  256. case stringlist:
  257. {
  258. int first = 1;
  259. const char *val = nl_langinfo (item->item_id) ? : "";
  260. int cnt;
  261. if (show_keyword_name)
  262. printf ("%s=", item->name);
  263. for (cnt = 0; cnt < item->max && *val != '\0'; ++cnt)
  264. {
  265. printf ("%s%s%s%s", first ? "" : ";",
  266. show_keyword_name ? "\"" : "", val,
  267. show_keyword_name ? "\"" : "");
  268. val = strchr (val, '\0') + 1;
  269. first = 0;
  270. }
  271. putchar ('\n');
  272. }
  273. break;
  274. case byte:
  275. {
  276. const char *val = nl_langinfo (item->item_id);
  277. if (show_keyword_name)
  278. printf ("%s=", item->name);
  279. if (val != NULL)
  280. printf ("%d", *val == '\177' ? -1 : *val);
  281. putchar ('\n');
  282. }
  283. break;
  284. case bytearray:
  285. {
  286. const char *val = nl_langinfo (item->item_id);
  287. int cnt = val ? strlen (val) : 0;
  288. if (show_keyword_name)
  289. printf ("%s=", item->name);
  290. while (cnt > 1)
  291. {
  292. printf ("%d;", *val == '\177' ? -1 : *val);
  293. --cnt;
  294. ++val;
  295. }
  296. printf ("%d\n", cnt == 0 || *val == '\177' ? -1 : *val);
  297. }
  298. break;
  299. case word:
  300. {
  301. union { unsigned int word; char *string; } val;
  302. val.string = nl_langinfo (item->item_id);
  303. if (show_keyword_name)
  304. printf ("%s=", item->name);
  305. printf ("%d\n", val.word);
  306. }
  307. break;
  308. case wstring:
  309. case wstringarray:
  310. case wstringlist:
  311. /* We don't print wide character information since the same
  312. information is available in a multibyte string. */
  313. default:
  314. break;
  315. }
  316. }
  317. /* Show the information request for NAME. */
  318. static void show_info(const char *name);
  319. static void show_info(const char *name)
  320. {
  321. size_t cat_no, item_no;
  322. const unsigned char *cat_name;
  323. /* Now all categories in an unspecified order. */
  324. for (cat_no = 0; cat_no < __LC_ALL; ++cat_no) {
  325. cat_name = GET_CATEGORY_NAME(cat_no);
  326. if (strcmp (name, (const char *)cat_name) == 0) {
  327. if (show_category_name)
  328. printf("%s\n", name);
  329. for (item_no = 0; item_no < category[cat_no].number; ++item_no)
  330. print_item (&category[cat_no].item_desc[item_no]);
  331. return;
  332. }
  333. for (item_no = 0; item_no < category[cat_no].number; ++item_no)
  334. if (strcmp (name, category[cat_no].item_desc[item_no].name) == 0) {
  335. if (show_category_name != 0)
  336. puts (category[cat_no].name);
  337. print_item (&category[cat_no].item_desc[item_no]);
  338. return;
  339. }
  340. }
  341. }
  342. static void show_locale_vars(void);
  343. static void show_locale_vars()
  344. {
  345. size_t cat_no;
  346. int row; /* locale row */
  347. const char *lcall = getenv ("LC_ALL");
  348. const char *lang = getenv ("LANG") ? : "";
  349. unsigned char *cur_loc = __global_locale->cur_locale + 1;
  350. char loc_name[40];
  351. locale_entry *locales;
  352. /* LANG has to be the first value. */
  353. printf ("LANG=%s\n", lang);
  354. /* Now all categories in an unspecified order. */
  355. for (cat_no = 0; cat_no < __LC_ALL; ++cat_no) {
  356. row = (((int)(*cur_loc & 0x7f)) << 7) + (cur_loc[1] & 0x7f);
  357. /* assert(row < __LOCALE_DATA_NUM_LOCALES); */
  358. locales = GET_LOCALE_ENTRY(row);
  359. find_locale_string(locales, loc_name);
  360. printf("%s=%s\n", GET_CATEGORY_NAME(cat_no), loc_name);
  361. cur_loc += 2;
  362. }
  363. /* The last is the LC_ALL value. */
  364. printf ("LC_ALL=%s\n", lcall ? : "");
  365. }
  366. int
  367. main (int argc, char *argv[])
  368. {
  369. /* Parse and process arguments. */
  370. if (argp_parse(argc, argv))
  371. return 1;
  372. if (do_all) {
  373. list_locale();
  374. exit (EXIT_SUCCESS);
  375. }
  376. if (do_charmaps) {
  377. list_charmaps();
  378. exit (EXIT_SUCCESS);
  379. }
  380. if (show_usage) {
  381. usage(*argv);
  382. exit (EXIT_SUCCESS);
  383. }
  384. /* If no real argument is given we have to print the contents of the
  385. current locale definition variables. These are LANG and the LC_*. */
  386. if (remaining == argc && show_category_name == 0 && show_keyword_name == 0) {
  387. show_locale_vars ();
  388. exit (EXIT_SUCCESS);
  389. }
  390. /* Process all given names. */
  391. while (remaining < argc)
  392. show_info (argv[remaining++]);
  393. exit (EXIT_SUCCESS);
  394. }