locale.c 20 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670
  1. /* Copyright (C) 2002 Manuel Novoa III
  2. *
  3. * This library is free software; you can redistribute it and/or
  4. * modify it under the terms of the GNU Library General Public
  5. * License as published by the Free Software Foundation; either
  6. * version 2 of the License, or (at your option) any later version.
  7. *
  8. * This library is distributed in the hope that it will be useful,
  9. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  10. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
  11. * Library General Public License for more details.
  12. *
  13. * You should have received a copy of the GNU Library General Public
  14. * License along with this library; if not, write to the Free
  15. * Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
  16. */
  17. /* Nov. 1, 2002
  18. *
  19. * Reworked setlocale() return values and locale arg processing to
  20. * be more like glibc. Applications expecting to be able to
  21. * query locale settings should now work... at the cost of almost
  22. * doubling the size of the setlocale object code.
  23. * Fixed a bug in the internal fixed-size-string locale specifier code.
  24. */
  25. /* TODO:
  26. * Implement the shared mmap code so non-mmu platforms can use this.
  27. * Add some basic collate functionality similar to what the previous
  28. * locale support had (8-bit codesets only).
  29. */
  30. #define _GNU_SOURCE
  31. #include <locale.h>
  32. #include <string.h>
  33. #include <stdlib.h>
  34. #include <stddef.h>
  35. #include <limits.h>
  36. #include <stdint.h>
  37. #include <assert.h>
  38. #ifndef __LOCALE_C_ONLY
  39. #define CUR_LOCALE_SPEC (__global_locale.cur_locale)
  40. #undef CODESET_LIST
  41. #define CODESET_LIST (__locale_mmap->codeset_list)
  42. #endif /* __LOCALE_C_ONLY */
  43. /**********************************************************************/
  44. #ifdef L_setlocale
  45. #ifdef __LOCALE_C_ONLY
  46. link_warning(setlocale,"the 'setlocale' function supports only C|POSIX locales")
  47. static const char C_string[] = "C";
  48. char *setlocale(int category, register const char *locale)
  49. {
  50. return ( (((unsigned int)(category)) <= LC_ALL)
  51. && ( (!locale) /* Request for locale category string. */
  52. || (!*locale) /* Implementation-defined default is C. */
  53. || ((*locale == 'C') && !locale[1])
  54. || (!strcmp(locale, "POSIX"))) )
  55. ? (char *) C_string /* Always in C/POSIX locale. */
  56. : NULL;
  57. }
  58. #else /* ---------------------------------------------- __LOCALE_C_ONLY */
  59. #if !defined(NUM_LOCALES) || (NUM_LOCALES <= 1)
  60. #error locales enabled, but not data other than for C locale!
  61. #endif
  62. #define LOCALE_NAMES (__locale_mmap->locale_names5)
  63. #define LOCALES (__locale_mmap->locales)
  64. #define LOCALE_AT_MODIFIERS (__locale_mmap->locale_at_modifiers)
  65. #define CATEGORY_NAMES (__locale_mmap->lc_names)
  66. static const char posix[] = "POSIX";
  67. static const char utf8[] = "UTF-8";
  68. #ifdef __UCLIBC_MJN3_ONLY__
  69. #warning REMINDER: redo the MAX_LOCALE_STR stuff...
  70. #endif
  71. #define MAX_LOCALE_STR 256 /* TODO: Only sufficient for current case. */
  72. static char hr_locale[MAX_LOCALE_STR];
  73. static __inline char *human_readable_locale(int category, const unsigned char *s)
  74. {
  75. const unsigned char *loc;
  76. char *n;
  77. int i;
  78. ++s;
  79. if (category == LC_ALL) {
  80. for (i = 0 ; i < LC_ALL-1 ; i += 2) {
  81. if ((s[i] != s[i+2]) || (s[i+1] != s[i+3])) {
  82. goto SKIP;
  83. }
  84. }
  85. /* All categories the same, so simplify string by using a single
  86. * category. */
  87. category = LC_CTYPE;
  88. }
  89. SKIP:
  90. i = (category == LC_ALL) ? 0 : category;
  91. s += 2*i;
  92. n = hr_locale;
  93. do {
  94. if ((*s != 0xff) || (s[1] != 0xff)) {
  95. loc = LOCALES + WIDTH_LOCALES * ((((int)(*s & 0x7f)) << 7) + (s[1] & 0x7f));
  96. if (category == LC_ALL) {
  97. n = stpcpy(n, CATEGORY_NAMES + (int) CATEGORY_NAMES[i]);
  98. *n++ = '=';
  99. }
  100. if (*loc == 0) {
  101. *n++ = 'C';
  102. *n = 0;
  103. } else {
  104. char at = 0;
  105. memcpy(n, LOCALE_NAMES + 5*((*loc)-1), 5);
  106. if (n[2] != '_') {
  107. at = n[2];
  108. n[2] = '_';
  109. }
  110. n += 5;
  111. *n++ = '.';
  112. if (loc[2] == 2) {
  113. n = stpcpy(n, utf8);
  114. } else if (loc[2] >= 3) {
  115. n = stpcpy(n, CODESET_LIST + (int)(CODESET_LIST[loc[2] - 3]));
  116. }
  117. if (at) {
  118. const char *q;
  119. *n++ = '@';
  120. q = LOCALE_AT_MODIFIERS;
  121. do {
  122. if (q[1] == at) {
  123. n = stpcpy(n, q+2);
  124. break;
  125. }
  126. q += 2 + *q;
  127. } while (*q);
  128. }
  129. }
  130. *n++ = ';';
  131. }
  132. s += 2;
  133. } while (++i < category);
  134. *--n = 0; /* Remove trailing ';' and nul-terminate. */
  135. assert(n-hr_locale < MAX_LOCALE_STR);
  136. return hr_locale;
  137. }
  138. static int find_locale(int category, const char *p, unsigned char *new_locale)
  139. {
  140. int i;
  141. const unsigned char *s;
  142. uint16_t n;
  143. unsigned char lang_cult, codeset;
  144. #if defined(LOCALE_AT_MODIFIERS_LENGTH) && 1
  145. /* Support standard locale handling for @-modifiers. */
  146. #ifdef __UCLIBC_MJN3_ONLY__
  147. #warning REMINDER: fix buf size in find_locale
  148. #endif
  149. char buf[18]; /* TODO: 7+{max codeset name length} */
  150. const char *q;
  151. if ((q = strchr(p,'@')) != NULL) {
  152. if ((((size_t)((q-p)-5)) > (sizeof(buf) - 5)) || (p[2] != '_')) {
  153. return 0;
  154. }
  155. /* locale name at least 5 chars long and 3rd char is '_' */
  156. s = LOCALE_AT_MODIFIERS;
  157. do {
  158. if (!strcmp(s+2, q+1)) {
  159. break;
  160. }
  161. s += 2 + *s; /* TODO - fix this throughout */
  162. } while (*s);
  163. if (!*s) {
  164. return 0;
  165. }
  166. assert(q - p < sizeof(buf));
  167. memcpy(buf, p, q-p);
  168. buf[q-p] = 0;
  169. buf[2] = s[1];
  170. p = buf;
  171. }
  172. #endif
  173. lang_cult = codeset = 0; /* Assume C and default codeset. */
  174. if (((*p == 'C') && !p[1]) || !strcmp(p, posix)) {
  175. goto FIND_LOCALE;
  176. }
  177. if ((strlen(p) > 5) && (p[5] == '.')) { /* Codeset in locale name? */
  178. /* TODO: maybe CODESET_LIST + *s ??? */
  179. /* 7bit is 1, UTF-8 is 2, 8-bit is >= 3 */
  180. codeset = 2;
  181. if (strcmp(utf8,p+6) != 0) {/* TODO - fix! */
  182. s = CODESET_LIST;
  183. do {
  184. ++codeset; /* Increment codeset first. */
  185. if (!strcmp(CODESET_LIST+*s, p+6)) {
  186. goto FIND_LANG_CULT;
  187. }
  188. } while (*++s);
  189. return 0; /* No matching codeset! */
  190. }
  191. }
  192. FIND_LANG_CULT: /* Find language_culture number. */
  193. s = LOCALE_NAMES;
  194. do { /* TODO -- do a binary search? */
  195. /* TODO -- fix gen_mmap!*/
  196. ++lang_cult; /* Increment first since C/POSIX is 0. */
  197. if (!strncmp(s,p,5)) { /* Found a matching locale name; */
  198. goto FIND_LOCALE;
  199. }
  200. s += 5;
  201. } while (lang_cult < NUM_LOCALE_NAMES);
  202. return 0; /* No matching language_culture! */
  203. FIND_LOCALE: /* Find locale row matching name and codeset */
  204. s = LOCALES;
  205. n = 0;
  206. do { /* TODO -- do a binary search? */
  207. if ((lang_cult == *s) && ((codeset == s[1]) || (codeset == s[2]))) {
  208. i = ((category == LC_ALL) ? 0 : category);
  209. s = new_locale + 2*i;
  210. do {
  211. /* Encode current locale row number. */
  212. *((unsigned char *) ++s) = (n >> 7) | 0x80;
  213. *((unsigned char *) ++s) = (n & 0x7f) | 0x80;
  214. } while (++i < category);
  215. return i; /* Return non-zero */
  216. }
  217. s += WIDTH_LOCALES;
  218. ++n;
  219. } while (n <= NUM_LOCALES); /* We started at 1!!! */
  220. return 0; /* Unsupported locale. */
  221. }
  222. static unsigned char *composite_locale(int category, const char *locale, unsigned char *new_locale)
  223. {
  224. char buf[MAX_LOCALE_STR];
  225. char *t;
  226. char *e;
  227. int c;
  228. if (!strchr(locale,'=')) {
  229. if (!find_locale(category, locale, new_locale)) {
  230. return NULL;
  231. }
  232. return new_locale;
  233. }
  234. if (strlen(locale) >= sizeof(buf)) {
  235. return NULL;
  236. }
  237. stpcpy(buf, locale);
  238. t = strtok_r(buf, "=", &e); /* This can't fail because of strchr test above. */
  239. do {
  240. for (c = 0 ; c < LC_ALL ; c++) { /* Find the category... */
  241. if (!strcmp(CATEGORY_NAMES + (int) CATEGORY_NAMES[c], t)) {
  242. break;
  243. }
  244. }
  245. t = strtok_r(NULL, ";", &e);
  246. if ((category == LC_ALL) || (c == category)) {
  247. if (!t || !find_locale(c, t, new_locale)) {
  248. return NULL;
  249. }
  250. }
  251. } while ((t = strtok_r(NULL, "=", &e)) != NULL);
  252. return new_locale;
  253. }
  254. char *setlocale(int category, const char *locale)
  255. {
  256. const unsigned char *p;
  257. int i;
  258. unsigned char new_locale[LOCALE_STRING_SIZE];
  259. if (((unsigned int)(category)) > LC_ALL) {
  260. /* TODO - set errno? SUSv3 doesn't say too. */
  261. return NULL; /* Illegal/unsupported category. */
  262. }
  263. if (locale != NULL) { /* Not just a query... */
  264. stpcpy(new_locale, CUR_LOCALE_SPEC); /* Start with current. */
  265. if (!*locale) { /* locale == "", so check environment. */
  266. i = ((category == LC_ALL) ? 0 : category);
  267. do {
  268. /* Note: SUSv3 doesn't define a fallback mechanism here. So,
  269. * if LC_ALL is invalid, we do _not_ continue trying the other
  270. * environment vars. */
  271. if (!(p = getenv("LC_ALL"))) {
  272. if (!(p = getenv(CATEGORY_NAMES + CATEGORY_NAMES[i]))) {
  273. if (!(p = getenv("LANG"))) {
  274. p = posix;
  275. }
  276. }
  277. }
  278. /* The user set something... is it valid? */
  279. /* Note: Since we don't support user-supplied locales and
  280. * alternate paths, we don't need to worry about special
  281. * handling for suid/sgid apps. */
  282. if (!find_locale(i, p, new_locale)) {
  283. return NULL;
  284. }
  285. } while (++i < category);
  286. } else if (!composite_locale(category, locale, new_locale)) {
  287. return NULL;
  288. }
  289. /* TODO: Ok, everything checks out, so install the new locale. */
  290. _locale_set(new_locale);
  291. }
  292. /* Either a query or a successful set, so return current locale string. */
  293. return human_readable_locale(category, CUR_LOCALE_SPEC);
  294. }
  295. #endif /* __LOCALE_C_ONLY */
  296. #endif
  297. /**********************************************************************/
  298. #ifdef L_localeconv
  299. /* Note: We assume here that the compiler does the sane thing regarding
  300. * placement of the fields in the struct. If necessary, we could ensure
  301. * this usings an array of offsets but at some size cost. */
  302. #ifdef __LOCALE_C_ONLY
  303. link_warning(localeconv,"the 'localeconv' function is hardwired for C/POSIX locale only")
  304. static struct lconv the_lconv;
  305. static const char decpt[] = ".";
  306. struct lconv *localeconv(void)
  307. {
  308. register char *p = (char *)(&the_lconv);
  309. *((char **)p) = (char *) decpt;
  310. do {
  311. p += sizeof(char **);
  312. *((char **)p) = (char *) (decpt+1);
  313. } while (p < (char *) &the_lconv.negative_sign);
  314. p = (&the_lconv.int_frac_digits);
  315. do {
  316. *p = CHAR_MAX;
  317. ++p;
  318. } while (p <= &the_lconv.int_n_sign_posn);
  319. return &the_lconv;
  320. }
  321. #else /* __LOCALE_C_ONLY */
  322. static struct lconv the_lconv;
  323. struct lconv *localeconv(void)
  324. {
  325. register char *p = (char *) &the_lconv;
  326. register char **q = (char **) &__global_locale.decimal_point;
  327. do {
  328. *((char **)p) = *q;
  329. p += sizeof(char **);
  330. ++q;
  331. } while (p < &the_lconv.int_frac_digits);
  332. do {
  333. *p = **q;
  334. ++p;
  335. ++q;
  336. } while (p <= &the_lconv.int_n_sign_posn);
  337. return &the_lconv;
  338. }
  339. #endif /* __LOCALE_C_ONLY */
  340. #endif
  341. /**********************************************************************/
  342. #ifdef L__locale_init
  343. #ifndef __LOCALE_C_ONLY
  344. #define C_LOCALE_SELECTOR "\x23\x80\x80\x80\x80\x80\x80\x80\x80\x80\x80\x80\x80"
  345. #define LOCALE_INIT_FAILED "locale init failed!\n"
  346. #define CUR_LOCALE_SPEC (__global_locale.cur_locale)
  347. __locale_t __global_locale;
  348. void _locale_init(void)
  349. {
  350. /* TODO: mmap the locale file */
  351. /* TODO - ??? */
  352. memset(CUR_LOCALE_SPEC, 0, LOCALE_STRING_SIZE);
  353. CUR_LOCALE_SPEC[0] = '#';
  354. memcpy(__global_locale.category_item_count,
  355. __locale_mmap->lc_common_item_offsets_LEN,
  356. LC_ALL);
  357. __global_locale.category_offsets[0] = offsetof(__locale_t, codeset);
  358. __global_locale.category_offsets[1] = offsetof(__locale_t, decimal_point);
  359. __global_locale.category_offsets[2] = offsetof(__locale_t, int_curr_symbol);
  360. __global_locale.category_offsets[3] = offsetof(__locale_t, abday_1);
  361. /* __global_locale.category_offsets[4] = offsetof(__locale_t, collate???); */
  362. __global_locale.category_offsets[5] = offsetof(__locale_t, yesexpr);
  363. #ifdef __CTYPE_HAS_8_BIT_LOCALES
  364. __global_locale.tbl8ctype
  365. = (const unsigned char *) &__locale_mmap->tbl8ctype;
  366. __global_locale.tbl8uplow
  367. = (const unsigned char *) &__locale_mmap->tbl8uplow;
  368. #ifdef __WCHAR_ENABLED
  369. __global_locale.tbl8c2wc
  370. = (const uint16_t *) &__locale_mmap->tbl8c2wc;
  371. __global_locale.tbl8wc2c
  372. = (const unsigned char *) &__locale_mmap->tbl8wc2c;
  373. /* translit */
  374. #endif /* __WCHAR_ENABLED */
  375. #endif /* __CTYPE_HAS_8_BIT_LOCALES */
  376. #ifdef __WCHAR_ENABLED
  377. __global_locale.tblwctype
  378. = (const unsigned char *) &__locale_mmap->tblwctype;
  379. __global_locale.tblwuplow
  380. = (const unsigned char *) &__locale_mmap->tblwuplow;
  381. __global_locale.tblwuplow_diff
  382. = (const uint16_t *) &__locale_mmap->tblwuplow_diff;
  383. /* __global_locale.tblwcomb */
  384. /* = (const unsigned char *) &__locale_mmap->tblwcomb; */
  385. /* width?? */
  386. #endif /* __WCHAR_ENABLED */
  387. _locale_set(C_LOCALE_SELECTOR);
  388. }
  389. static const char ascii[] = "ASCII";
  390. static const char utf8[] = "UTF-8";
  391. void _locale_set(const unsigned char *p)
  392. {
  393. const char **x;
  394. unsigned char *s = CUR_LOCALE_SPEC + 1;
  395. const size_t *stp;
  396. const unsigned char *r;
  397. const uint16_t *io;
  398. const uint16_t *ii;
  399. const unsigned char *d;
  400. int row; /* locale row */
  401. int crow; /* category row */
  402. int len;
  403. int c;
  404. int i = 0;
  405. ++p;
  406. do {
  407. if ((*p != *s) || (p[1] != s[1])) {
  408. row = (((int)(*p & 0x7f)) << 7) + (p[1] & 0x7f);
  409. assert(row < NUM_LOCALES);
  410. *s = *p;
  411. s[1] = p[1];
  412. if (i == LC_CTYPE) {
  413. c = __locale_mmap->locales[ WIDTH_LOCALES * row + 2 ]; /* codeset */
  414. if (c <= 2) {
  415. if (c == 2) {
  416. __global_locale.codeset = utf8;
  417. __global_locale.encoding = __ctype_encoding_utf8;
  418. /* TODO - fix for bcc */
  419. __global_locale.mb_cur_max = 6;
  420. } else {
  421. assert(c==1);
  422. __global_locale.codeset = ascii;
  423. __global_locale.encoding = __ctype_encoding_7_bit;
  424. __global_locale.mb_cur_max = 1;
  425. }
  426. } else {
  427. const codeset_8_bit_t *c8b;
  428. r = CODESET_LIST;
  429. __global_locale.codeset = r + r[c -= 3];
  430. __global_locale.encoding = __ctype_encoding_8_bit;
  431. #ifdef __UCLIBC_MJN3_ONLY__
  432. #warning REMINDER: update 8 bit mb_cur_max when trasnlit implemented!
  433. #endif
  434. /* TODO - update when translit implemented! */
  435. __global_locale.mb_cur_max = 1;
  436. c8b = __locale_mmap->codeset_8_bit + c;
  437. #ifdef __CTYPE_HAS_8_BIT_LOCALES
  438. __global_locale.idx8ctype = c8b->idx8ctype;
  439. __global_locale.idx8uplow = c8b->idx8uplow;
  440. #ifdef __WCHAR_ENABLED
  441. __global_locale.idx8c2wc = c8b->idx8c2wc;
  442. __global_locale.idx8wc2c = c8b->idx8wc2c;
  443. /* translit */
  444. #endif /* __WCHAR_ENABLED */
  445. #endif /* __CTYPE_HAS_8_BIT_LOCALES */
  446. }
  447. } else if ((len = __locale_mmap->lc_common_item_offsets_LEN[i]) != 0) {
  448. crow = __locale_mmap->locales[ WIDTH_LOCALES * row + 3 + i ]
  449. * len;
  450. x = (const char **)(((char *) &__global_locale)
  451. + __global_locale.category_offsets[i]);
  452. stp = __locale_mmap->lc_common_tbl_offsets + 4*i;
  453. r = (const unsigned char *)( ((char *)__locale_mmap) + *stp );
  454. io = (const uint16_t *)( ((char *)__locale_mmap) + *++stp );
  455. ii = (const uint16_t *)( ((char *)__locale_mmap) + *++stp );
  456. d = (const unsigned char *)( ((char *)__locale_mmap) + *++stp );
  457. for (c=0 ; c < len ; c++) {
  458. *(x + c) = d + ii[ r[crow + c] + io[c] ];
  459. }
  460. }
  461. }
  462. ++i;
  463. p += 2;
  464. s += 2;
  465. } while (i < LC_ALL);
  466. }
  467. #endif /* __LOCALE_C_ONLY */
  468. #endif
  469. /**********************************************************************/
  470. #ifdef L_nl_langinfo
  471. #include <langinfo.h>
  472. #include <nl_types.h>
  473. #ifdef __LOCALE_C_ONLY
  474. /* We need to index 300 bytes of data, so you might initially think we
  475. * need to store the offsets in shorts. But since the offset of the
  476. * 64th item is 231, we'll store "offset - 64" for all items >= 64
  477. * and always calculate the data offset as "offset[i] + (i & 64)".
  478. * This allows us to pack the data offsets in an unsigned char while
  479. * also avoiding an "if".
  480. *
  481. * Note: Category order is assumed to be:
  482. * ctype, numeric, monetary, time, collate, messages, all
  483. */
  484. #define C_LC_ALL 6
  485. /* Combine the data to avoid size penalty for seperate char arrays when
  486. * compiler aligns objects. The original code is left in as documentation. */
  487. #define cat_start nl_data
  488. #define C_locale_data (nl_data + C_LC_ALL + 1 + 78)
  489. static const unsigned char nl_data[C_LC_ALL + 1 + 78 + 300] = {
  490. /* static const unsigned char cat_start[C_LC_ALL + 1] = { */
  491. '\x00', '\x01', '\x04', '\x1a', '\x4c', '\x4c', '\x4e',
  492. /* }; */
  493. /* static const unsigned char item_offset[78] = { */
  494. '\x00', '\x06', '\x07', '\x07', '\x07', '\x07', '\x07', '\x07',
  495. '\x07', '\x07', '\x07', '\x08', '\x08', '\x08', '\x08', '\x08',
  496. '\x08', '\x08', '\x08', '\x08', '\x08', '\x08', '\x08', '\x08',
  497. '\x08', '\x0a', '\x0c', '\x10', '\x14', '\x18', '\x1c', '\x20',
  498. '\x24', '\x28', '\x2f', '\x36', '\x3e', '\x48', '\x51', '\x58',
  499. '\x61', '\x65', '\x69', '\x6d', '\x71', '\x75', '\x79', '\x7d',
  500. '\x81', '\x85', '\x89', '\x8d', '\x91', '\x99', '\xa2', '\xa8',
  501. '\xae', '\xb2', '\xb7', '\xbc', '\xc3', '\xcd', '\xd5', '\xde',
  502. '\xa7', '\xaa', '\xad', '\xc2', '\xcb', '\xd4', '\xdf', '\xdf',
  503. '\xdf', '\xdf', '\xdf', '\xdf', '\xe0', '\xe6',
  504. /* }; */
  505. /* static const unsigned char C_locale_data[300] = { */
  506. 'A', 'S', 'C', 'I', 'I', '\x00', '.', '\x00',
  507. '\x7f', '\x00', '-', '\x00', 'S', 'u', 'n', '\x00',
  508. 'M', 'o', 'n', '\x00', 'T', 'u', 'e', '\x00',
  509. 'W', 'e', 'd', '\x00', 'T', 'h', 'u', '\x00',
  510. 'F', 'r', 'i', '\x00', 'S', 'a', 't', '\x00',
  511. 'S', 'u', 'n', 'd', 'a', 'y', '\x00', 'M',
  512. 'o', 'n', 'd', 'a', 'y', '\x00', 'T', 'u',
  513. 'e', 's', 'd', 'a', 'y', '\x00', 'W', 'e',
  514. 'd', 'n', 'e', 's', 'd', 'a', 'y', '\x00',
  515. 'T', 'h', 'u', 'r', 's', 'd', 'a', 'y',
  516. '\x00', 'F', 'r', 'i', 'd', 'a', 'y', '\x00',
  517. 'S', 'a', 't', 'u', 'r', 'd', 'a', 'y',
  518. '\x00', 'J', 'a', 'n', '\x00', 'F', 'e', 'b',
  519. '\x00', 'M', 'a', 'r', '\x00', 'A', 'p', 'r',
  520. '\x00', 'M', 'a', 'y', '\x00', 'J', 'u', 'n',
  521. '\x00', 'J', 'u', 'l', '\x00', 'A', 'u', 'g',
  522. '\x00', 'S', 'e', 'p', '\x00', 'O', 'c', 't',
  523. '\x00', 'N', 'o', 'v', '\x00', 'D', 'e', 'c',
  524. '\x00', 'J', 'a', 'n', 'u', 'a', 'r', 'y',
  525. '\x00', 'F', 'e', 'b', 'r', 'u', 'a', 'r',
  526. 'y', '\x00', 'M', 'a', 'r', 'c', 'h', '\x00',
  527. 'A', 'p', 'r', 'i', 'l', '\x00', 'M', 'a',
  528. 'y', '\x00', 'J', 'u', 'n', 'e', '\x00', 'J',
  529. 'u', 'l', 'y', '\x00', 'A', 'u', 'g', 'u',
  530. 's', 't', '\x00', 'S', 'e', 'p', 't', 'e',
  531. 'm', 'b', 'e', 'r', '\x00', 'O', 'c', 't',
  532. 'o', 'b', 'e', 'r', '\x00', 'N', 'o', 'v',
  533. 'e', 'm', 'b', 'e', 'r', '\x00', 'D', 'e',
  534. 'c', 'e', 'm', 'b', 'e', 'r', '\x00', 'A',
  535. 'M', '\x00', 'P', 'M', '\x00', '%', 'a', ' ',
  536. '%', 'b', ' ', '%', 'e', ' ', '%', 'H',
  537. ':', '%', 'M', ':', '%', 'S', ' ', '%',
  538. 'Y', '\x00', '%', 'm', '/', '%', 'd', '/',
  539. '%', 'y', '\x00', '%', 'H', ':', '%', 'M',
  540. ':', '%', 'S', '\x00', '%', 'I', ':', '%',
  541. 'M', ':', '%', 'S', ' ', '%', 'p', '\x00',
  542. '^', '[', 'y', 'Y', ']', '\x00', '^', '[',
  543. 'n', 'N', ']', '\x00',
  544. };
  545. char *nl_langinfo(nl_item item)
  546. {
  547. unsigned int c;
  548. unsigned int i;
  549. if ((c = _NL_ITEM_CATEGORY(item)) < C_LC_ALL) {
  550. if ((i = cat_start[c] + _NL_ITEM_INDEX(item)) < cat_start[c+1]) {
  551. /* return (char *) C_locale_data + item_offset[i] + (i & 64); */
  552. return (char *) C_locale_data + nl_data[C_LC_ALL+1+i] + (i & 64);
  553. }
  554. }
  555. return (char *) cat_start; /* Conveniently, this is the empty string. */
  556. }
  557. #else /* __LOCALE_C_ONLY */
  558. static const char empty[] = "";
  559. char *nl_langinfo(nl_item item)
  560. {
  561. unsigned int c = _NL_ITEM_CATEGORY(item);
  562. unsigned int i = _NL_ITEM_INDEX(item);
  563. if ((c < LC_ALL) && (i < __global_locale.category_item_count[c])) {
  564. return ((char **)(((char *) &__global_locale)
  565. + __global_locale.category_offsets[c]))[i];
  566. }
  567. return (char *) empty;
  568. }
  569. #endif /* __LOCALE_C_ONLY */
  570. #endif
  571. /**********************************************************************/