locale.c 26 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874
  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. * Dec 20, 2002
  26. *
  27. * Added in collation support and updated stub nl_langinfo.
  28. */
  29. /* TODO:
  30. * Implement the shared mmap code so non-mmu platforms can use this.
  31. * Add some basic collate functionality similar to what the previous
  32. * locale support had (8-bit codesets only).
  33. */
  34. #define _GNU_SOURCE
  35. #include <locale.h>
  36. #include <string.h>
  37. #include <stdlib.h>
  38. #include <stddef.h>
  39. #include <limits.h>
  40. #include <stdint.h>
  41. #include <assert.h>
  42. #ifndef __LOCALE_C_ONLY
  43. #define CUR_LOCALE_SPEC (__global_locale.cur_locale)
  44. #undef CODESET_LIST
  45. #define CODESET_LIST (__locale_mmap->codeset_list)
  46. #endif /* __LOCALE_C_ONLY */
  47. /**********************************************************************/
  48. #ifdef L_setlocale
  49. #ifdef __LOCALE_C_ONLY
  50. link_warning(setlocale,"the 'setlocale' function supports only C|POSIX locales")
  51. static const char C_string[] = "C";
  52. char *setlocale(int category, register const char *locale)
  53. {
  54. return ( (((unsigned int)(category)) <= LC_ALL)
  55. && ( (!locale) /* Request for locale category string. */
  56. || (!*locale) /* Implementation-defined default is C. */
  57. || ((*locale == 'C') && !locale[1])
  58. || (!strcmp(locale, "POSIX"))) )
  59. ? (char *) C_string /* Always in C/POSIX locale. */
  60. : NULL;
  61. }
  62. #else /* ---------------------------------------------- __LOCALE_C_ONLY */
  63. #if !defined(NUM_LOCALES) || (NUM_LOCALES <= 1)
  64. #error locales enabled, but not data other than for C locale!
  65. #endif
  66. #define LOCALE_NAMES (__locale_mmap->locale_names5)
  67. #define LOCALES (__locale_mmap->locales)
  68. #define LOCALE_AT_MODIFIERS (__locale_mmap->locale_at_modifiers)
  69. #define CATEGORY_NAMES (__locale_mmap->lc_names)
  70. static const char posix[] = "POSIX";
  71. static const char utf8[] = "UTF-8";
  72. #ifdef __UCLIBC_MJN3_ONLY__
  73. #warning REMINDER: redo the MAX_LOCALE_STR stuff...
  74. #endif
  75. #define MAX_LOCALE_STR 256 /* TODO: Only sufficient for current case. */
  76. static char hr_locale[MAX_LOCALE_STR];
  77. static __inline char *human_readable_locale(int category, const unsigned char *s)
  78. {
  79. const unsigned char *loc;
  80. char *n;
  81. int i;
  82. ++s;
  83. if (category == LC_ALL) {
  84. for (i = 0 ; i < LC_ALL-1 ; i += 2) {
  85. if ((s[i] != s[i+2]) || (s[i+1] != s[i+3])) {
  86. goto SKIP;
  87. }
  88. }
  89. /* All categories the same, so simplify string by using a single
  90. * category. */
  91. category = LC_CTYPE;
  92. }
  93. SKIP:
  94. i = (category == LC_ALL) ? 0 : category;
  95. s += 2*i;
  96. n = hr_locale;
  97. do {
  98. if ((*s != 0xff) || (s[1] != 0xff)) {
  99. loc = LOCALES + WIDTH_LOCALES * ((((int)(*s & 0x7f)) << 7) + (s[1] & 0x7f));
  100. if (category == LC_ALL) {
  101. n = stpcpy(n, CATEGORY_NAMES + (int) CATEGORY_NAMES[i]);
  102. *n++ = '=';
  103. }
  104. if (*loc == 0) {
  105. *n++ = 'C';
  106. *n = 0;
  107. } else {
  108. char at = 0;
  109. memcpy(n, LOCALE_NAMES + 5*((*loc)-1), 5);
  110. if (n[2] != '_') {
  111. at = n[2];
  112. n[2] = '_';
  113. }
  114. n += 5;
  115. *n++ = '.';
  116. if (loc[2] == 2) {
  117. n = stpcpy(n, utf8);
  118. } else if (loc[2] >= 3) {
  119. n = stpcpy(n, CODESET_LIST + (int)(CODESET_LIST[loc[2] - 3]));
  120. }
  121. if (at) {
  122. const char *q;
  123. *n++ = '@';
  124. q = LOCALE_AT_MODIFIERS;
  125. do {
  126. if (q[1] == at) {
  127. n = stpcpy(n, q+2);
  128. break;
  129. }
  130. q += 2 + *q;
  131. } while (*q);
  132. }
  133. }
  134. *n++ = ';';
  135. }
  136. s += 2;
  137. } while (++i < category);
  138. *--n = 0; /* Remove trailing ';' and nul-terminate. */
  139. assert(n-hr_locale < MAX_LOCALE_STR);
  140. return hr_locale;
  141. }
  142. static int find_locale(int category, const char *p, unsigned char *new_locale)
  143. {
  144. int i;
  145. const unsigned char *s;
  146. uint16_t n;
  147. unsigned char lang_cult, codeset;
  148. #if defined(LOCALE_AT_MODIFIERS_LENGTH) && 1
  149. /* Support standard locale handling for @-modifiers. */
  150. #ifdef __UCLIBC_MJN3_ONLY__
  151. #warning REMINDER: fix buf size in find_locale
  152. #endif
  153. char buf[18]; /* TODO: 7+{max codeset name length} */
  154. const char *q;
  155. if ((q = strchr(p,'@')) != NULL) {
  156. if ((((size_t)((q-p)-5)) > (sizeof(buf) - 5)) || (p[2] != '_')) {
  157. return 0;
  158. }
  159. /* locale name at least 5 chars long and 3rd char is '_' */
  160. s = LOCALE_AT_MODIFIERS;
  161. do {
  162. if (!strcmp(s+2, q+1)) {
  163. break;
  164. }
  165. s += 2 + *s; /* TODO - fix this throughout */
  166. } while (*s);
  167. if (!*s) {
  168. return 0;
  169. }
  170. assert(q - p < sizeof(buf));
  171. memcpy(buf, p, q-p);
  172. buf[q-p] = 0;
  173. buf[2] = s[1];
  174. p = buf;
  175. }
  176. #endif
  177. lang_cult = codeset = 0; /* Assume C and default codeset. */
  178. if (((*p == 'C') && !p[1]) || !strcmp(p, posix)) {
  179. goto FIND_LOCALE;
  180. }
  181. if ((strlen(p) > 5) && (p[5] == '.')) { /* Codeset in locale name? */
  182. /* TODO: maybe CODESET_LIST + *s ??? */
  183. /* 7bit is 1, UTF-8 is 2, 8-bit is >= 3 */
  184. codeset = 2;
  185. if (strcmp(utf8,p+6) != 0) {/* TODO - fix! */
  186. s = CODESET_LIST;
  187. do {
  188. ++codeset; /* Increment codeset first. */
  189. if (!strcmp(CODESET_LIST+*s, p+6)) {
  190. goto FIND_LANG_CULT;
  191. }
  192. } while (*++s);
  193. return 0; /* No matching codeset! */
  194. }
  195. }
  196. FIND_LANG_CULT: /* Find language_culture number. */
  197. s = LOCALE_NAMES;
  198. do { /* TODO -- do a binary search? */
  199. /* TODO -- fix gen_mmap!*/
  200. ++lang_cult; /* Increment first since C/POSIX is 0. */
  201. if (!strncmp(s,p,5)) { /* Found a matching locale name; */
  202. goto FIND_LOCALE;
  203. }
  204. s += 5;
  205. } while (lang_cult < NUM_LOCALE_NAMES);
  206. return 0; /* No matching language_culture! */
  207. FIND_LOCALE: /* Find locale row matching name and codeset */
  208. s = LOCALES;
  209. n = 0;
  210. do { /* TODO -- do a binary search? */
  211. if ((lang_cult == *s) && ((codeset == s[1]) || (codeset == s[2]))) {
  212. i = ((category == LC_ALL) ? 0 : category);
  213. s = new_locale + 2*i;
  214. do {
  215. /* Encode current locale row number. */
  216. *((unsigned char *) ++s) = (n >> 7) | 0x80;
  217. *((unsigned char *) ++s) = (n & 0x7f) | 0x80;
  218. } while (++i < category);
  219. return i; /* Return non-zero */
  220. }
  221. s += WIDTH_LOCALES;
  222. ++n;
  223. } while (n <= NUM_LOCALES); /* We started at 1!!! */
  224. return 0; /* Unsupported locale. */
  225. }
  226. static unsigned char *composite_locale(int category, const char *locale, unsigned char *new_locale)
  227. {
  228. char buf[MAX_LOCALE_STR];
  229. char *t;
  230. char *e;
  231. int c;
  232. if (!strchr(locale,'=')) {
  233. if (!find_locale(category, locale, new_locale)) {
  234. return NULL;
  235. }
  236. return new_locale;
  237. }
  238. if (strlen(locale) >= sizeof(buf)) {
  239. return NULL;
  240. }
  241. stpcpy(buf, locale);
  242. t = strtok_r(buf, "=", &e); /* This can't fail because of strchr test above. */
  243. do {
  244. for (c = 0 ; c < LC_ALL ; c++) { /* Find the category... */
  245. if (!strcmp(CATEGORY_NAMES + (int) CATEGORY_NAMES[c], t)) {
  246. break;
  247. }
  248. }
  249. t = strtok_r(NULL, ";", &e);
  250. if ((category == LC_ALL) || (c == category)) {
  251. if (!t || !find_locale(c, t, new_locale)) {
  252. return NULL;
  253. }
  254. }
  255. } while ((t = strtok_r(NULL, "=", &e)) != NULL);
  256. return new_locale;
  257. }
  258. char *setlocale(int category, const char *locale)
  259. {
  260. const unsigned char *p;
  261. int i;
  262. unsigned char new_locale[LOCALE_STRING_SIZE];
  263. if (((unsigned int)(category)) > LC_ALL) {
  264. /* TODO - set errno? SUSv3 doesn't say too. */
  265. return NULL; /* Illegal/unsupported category. */
  266. }
  267. if (locale != NULL) { /* Not just a query... */
  268. stpcpy(new_locale, CUR_LOCALE_SPEC); /* Start with current. */
  269. if (!*locale) { /* locale == "", so check environment. */
  270. i = ((category == LC_ALL) ? 0 : category);
  271. do {
  272. /* Note: SUSv3 doesn't define a fallback mechanism here. So,
  273. * if LC_ALL is invalid, we do _not_ continue trying the other
  274. * environment vars. */
  275. if (!(p = getenv("LC_ALL"))) {
  276. if (!(p = getenv(CATEGORY_NAMES + CATEGORY_NAMES[i]))) {
  277. if (!(p = getenv("LANG"))) {
  278. p = posix;
  279. }
  280. }
  281. }
  282. /* The user set something... is it valid? */
  283. /* Note: Since we don't support user-supplied locales and
  284. * alternate paths, we don't need to worry about special
  285. * handling for suid/sgid apps. */
  286. if (!find_locale(i, p, new_locale)) {
  287. return NULL;
  288. }
  289. } while (++i < category);
  290. } else if (!composite_locale(category, locale, new_locale)) {
  291. return NULL;
  292. }
  293. /* TODO: Ok, everything checks out, so install the new locale. */
  294. _locale_set(new_locale);
  295. }
  296. /* Either a query or a successful set, so return current locale string. */
  297. return human_readable_locale(category, CUR_LOCALE_SPEC);
  298. }
  299. #endif /* __LOCALE_C_ONLY */
  300. #endif
  301. /**********************************************************************/
  302. #ifdef L_localeconv
  303. /* Note: We assume here that the compiler does the sane thing regarding
  304. * placement of the fields in the struct. If necessary, we could ensure
  305. * this usings an array of offsets but at some size cost. */
  306. #ifdef __LOCALE_C_ONLY
  307. link_warning(localeconv,"the 'localeconv' function is hardwired for C/POSIX locale only")
  308. static struct lconv the_lconv;
  309. static const char decpt[] = ".";
  310. struct lconv *localeconv(void)
  311. {
  312. register char *p = (char *)(&the_lconv);
  313. *((char **)p) = (char *) decpt;
  314. do {
  315. p += sizeof(char **);
  316. *((char **)p) = (char *) (decpt+1);
  317. } while (p < (char *) &the_lconv.negative_sign);
  318. p = (&the_lconv.int_frac_digits);
  319. do {
  320. *p = CHAR_MAX;
  321. ++p;
  322. } while (p <= &the_lconv.int_n_sign_posn);
  323. return &the_lconv;
  324. }
  325. #else /* __LOCALE_C_ONLY */
  326. static struct lconv the_lconv;
  327. struct lconv *localeconv(void)
  328. {
  329. register char *p = (char *) &the_lconv;
  330. register char **q = (char **) &__global_locale.decimal_point;
  331. do {
  332. *((char **)p) = *q;
  333. p += sizeof(char **);
  334. ++q;
  335. } while (p < &the_lconv.int_frac_digits);
  336. do {
  337. *p = **q;
  338. ++p;
  339. ++q;
  340. } while (p <= &the_lconv.int_n_sign_posn);
  341. return &the_lconv;
  342. }
  343. #endif /* __LOCALE_C_ONLY */
  344. #endif
  345. /**********************************************************************/
  346. #ifdef L__locale_init
  347. #ifndef __LOCALE_C_ONLY
  348. #define C_LOCALE_SELECTOR "\x23\x80\x80\x80\x80\x80\x80\x80\x80\x80\x80\x80\x80"
  349. #define LOCALE_INIT_FAILED "locale init failed!\n"
  350. #define CUR_LOCALE_SPEC (__global_locale.cur_locale)
  351. __locale_t __global_locale;
  352. typedef struct {
  353. uint16_t num_base;
  354. uint16_t num_der;
  355. uint16_t MAX_WEIGHTS;
  356. uint16_t num_index2weight;
  357. #define num_index2ruleidx num_index2weight
  358. uint16_t num_weightstr;
  359. uint16_t num_multistart;
  360. uint16_t num_override;
  361. uint16_t num_ruletable;
  362. } coldata_header_t;
  363. typedef struct {
  364. uint16_t num_weights;
  365. uint16_t num_starters;
  366. uint16_t ii_shift;
  367. uint16_t ti_shift;
  368. uint16_t ii_len;
  369. uint16_t ti_len;
  370. uint16_t max_weight;
  371. uint16_t num_col_base;
  372. uint16_t max_col_index;
  373. uint16_t undefined_idx;
  374. uint16_t range_low;
  375. uint16_t range_count;
  376. uint16_t range_base_weight;
  377. uint16_t range_rule_offset;
  378. uint16_t index2weight_offset;
  379. uint16_t index2ruleidx_offset;
  380. uint16_t multistart_offset;
  381. uint16_t wcs2colidt_offset_low;
  382. uint16_t wcs2colidt_offset_hi;
  383. } coldata_base_t;
  384. typedef struct {
  385. uint16_t base_idx;
  386. uint16_t undefined_idx;
  387. uint16_t overrides_offset;
  388. uint16_t multistart_offset;
  389. } coldata_der_t;
  390. static int init_cur_collate(int der_num)
  391. {
  392. __collate_t *cur_collate = &__global_locale.collate;
  393. const uint16_t *__locale_collate_tbl = __locale_mmap->collate_data;
  394. coldata_header_t *cdh;
  395. coldata_base_t *cdb;
  396. coldata_der_t *cdd;
  397. const uint16_t *p;
  398. size_t n;
  399. uint16_t i, w;
  400. assert(sizeof(coldata_base_t) == 19*2);
  401. assert(sizeof(coldata_der_t) == 4*2);
  402. assert(sizeof(coldata_header_t) == 8*2);
  403. if (!der_num) { /* C locale... special */
  404. cur_collate->num_weights = 0;
  405. return 1;
  406. }
  407. --der_num;
  408. cdh = (coldata_header_t *) __locale_collate_tbl;
  409. if (der_num >= cdh->num_der) {
  410. return 0;
  411. }
  412. cdd = (coldata_der_t *)(__locale_collate_tbl
  413. + (sizeof(coldata_header_t)
  414. + cdh->num_base * sizeof(coldata_base_t)
  415. + der_num * sizeof(coldata_der_t)
  416. )/2 );
  417. cdb = (coldata_base_t *)(__locale_collate_tbl
  418. + (sizeof(coldata_header_t)
  419. + cdd->base_idx * sizeof(coldata_base_t)
  420. )/2 );
  421. memcpy(cur_collate, cdb, offsetof(coldata_base_t,index2weight_offset));
  422. cur_collate->undefined_idx = cdd->undefined_idx;
  423. cur_collate->ti_mask = (1 << cur_collate->ti_shift)-1;
  424. cur_collate->ii_mask = (1 << cur_collate->ii_shift)-1;
  425. /* printf("base=%d num_col_base: %d %d\n", cdd->base_idx ,cur_collate->num_col_base, cdb->num_col_base); */
  426. n = (sizeof(coldata_header_t) + cdh->num_base * sizeof(coldata_base_t)
  427. + cdh->num_der * sizeof(coldata_der_t))/2;
  428. /* printf("n = %d\n", n); */
  429. cur_collate->index2weight_tbl = __locale_collate_tbl + n + cdb->index2weight_offset;
  430. /* printf("i2w = %d\n", n + cdb->index2weight_offset); */
  431. n += cdh->num_index2weight;
  432. cur_collate->index2ruleidx_tbl = __locale_collate_tbl + n + cdb->index2ruleidx_offset;
  433. /* printf("i2r = %d\n", n + cdb->index2ruleidx_offset); */
  434. n += cdh->num_index2ruleidx;
  435. cur_collate->multistart_tbl = __locale_collate_tbl + n + cdd->multistart_offset;
  436. /* printf("mts = %d\n", n + cdb->multistart_offset); */
  437. n += cdh->num_multistart;
  438. cur_collate->overrides_tbl = __locale_collate_tbl + n + cdd->overrides_offset;
  439. /* printf("ovr = %d\n", n + cdd->overrides_offset); */
  440. n += cdh->num_override;
  441. cur_collate->ruletable = __locale_collate_tbl + n;
  442. /* printf("rtb = %d\n", n); */
  443. n += cdh->num_ruletable;
  444. cur_collate->weightstr = __locale_collate_tbl + n;
  445. /* printf("wts = %d\n", n); */
  446. n += cdh->num_weightstr;
  447. cur_collate->wcs2colidt_tbl = __locale_collate_tbl + n
  448. + (((unsigned long)(cdb->wcs2colidt_offset_hi)) << 16)
  449. + cdb->wcs2colidt_offset_low;
  450. /* printf("wcs = %lu\n", n + (((unsigned long)(cdb->wcs2colidt_offset_hi)) << 16) */
  451. /* + cdb->wcs2colidt_offset_low); */
  452. cur_collate->MAX_WEIGHTS = cdh->MAX_WEIGHTS;
  453. #ifdef __UCLIBC_MJN3_ONLY__
  454. #warning if calloc fails, this is WRONG. there is also a memory leak here at the moment
  455. #warning fix the +1 by increasing max_col_index?
  456. #endif
  457. cur_collate->index2weight = calloc(2*cur_collate->max_col_index+2, sizeof(uint16_t));
  458. if (!cur_collate->index2weight) {
  459. return 0;
  460. }
  461. cur_collate->index2ruleidx = cur_collate->index2weight + cur_collate->max_col_index + 1;
  462. memcpy(cur_collate->index2weight, cur_collate->index2weight_tbl,
  463. cur_collate->num_col_base * sizeof(uint16_t));
  464. memcpy(cur_collate->index2ruleidx, cur_collate->index2ruleidx_tbl,
  465. cur_collate->num_col_base * sizeof(uint16_t));
  466. /* now do the overrides */
  467. p = cur_collate->overrides_tbl;
  468. while (*p > 1) {
  469. /* fprintf(stderr, "processing override -- count = %d\n", *p); */
  470. n = *p++;
  471. w = *p++;
  472. do {
  473. i = *p++;
  474. /* fprintf(stderr, " i=%d w=%d *p=%d\n", i, w, *p); */
  475. cur_collate->index2weight[i-1] = w++;
  476. cur_collate->index2ruleidx[i-1] = *p++;
  477. } while (--n);
  478. }
  479. while (*++p) {
  480. i = *p;
  481. cur_collate->index2weight[i-1] = *++p;
  482. cur_collate->index2ruleidx[i-1] = *++p;
  483. }
  484. for (i=0 ; i < cur_collate->multistart_tbl[0] ; i++) {
  485. p = cur_collate->multistart_tbl;
  486. /* fprintf(stderr, "%2d of %2d: %d ", i, cur_collate->multistart_tbl[0], p[i]); */
  487. p += p[i];
  488. do {
  489. n = *p++;
  490. do {
  491. if (!*p) { /* found it */
  492. /* fprintf(stderr, "found: n=%d (%#lx) |%.*ls|\n", n, (int) *cs->s, n, cs->s); */
  493. /* fprintf(stderr, ": %d - single\n", n); */
  494. goto FOUND;
  495. }
  496. /* the lookup check here is safe since we're assured that *p is a valid colidex */
  497. /* fprintf(stderr, "lookup(%lc)==%d *p==%d\n", cs->s[n], lookup(cs->s[n]), (int) *p); */
  498. /* fprintf(stderr, ": %d - ", n); */
  499. do {
  500. /* fprintf(stderr, "%d|", *p); */
  501. } while (*p++);
  502. break;
  503. } while (1);
  504. } while (1);
  505. FOUND:
  506. continue;
  507. }
  508. return 1;
  509. }
  510. void _locale_init(void)
  511. {
  512. /* TODO: mmap the locale file */
  513. /* TODO - ??? */
  514. memset(CUR_LOCALE_SPEC, 0, LOCALE_STRING_SIZE);
  515. CUR_LOCALE_SPEC[0] = '#';
  516. memcpy(__global_locale.category_item_count,
  517. __locale_mmap->lc_common_item_offsets_LEN,
  518. LC_ALL);
  519. ++__global_locale.category_item_count[0]; /* Increment for codeset entry. */
  520. __global_locale.category_offsets[0] = offsetof(__locale_t, outdigit0_mb);
  521. __global_locale.category_offsets[1] = offsetof(__locale_t, decimal_point);
  522. __global_locale.category_offsets[2] = offsetof(__locale_t, int_curr_symbol);
  523. __global_locale.category_offsets[3] = offsetof(__locale_t, abday_1);
  524. /* __global_locale.category_offsets[4] = offsetof(__locale_t, collate???); */
  525. __global_locale.category_offsets[5] = offsetof(__locale_t, yesexpr);
  526. #ifdef __CTYPE_HAS_8_BIT_LOCALES
  527. __global_locale.tbl8ctype
  528. = (const unsigned char *) &__locale_mmap->tbl8ctype;
  529. __global_locale.tbl8uplow
  530. = (const unsigned char *) &__locale_mmap->tbl8uplow;
  531. #ifdef __WCHAR_ENABLED
  532. __global_locale.tbl8c2wc
  533. = (const uint16_t *) &__locale_mmap->tbl8c2wc;
  534. __global_locale.tbl8wc2c
  535. = (const unsigned char *) &__locale_mmap->tbl8wc2c;
  536. /* translit */
  537. #endif /* __WCHAR_ENABLED */
  538. #endif /* __CTYPE_HAS_8_BIT_LOCALES */
  539. #ifdef __WCHAR_ENABLED
  540. __global_locale.tblwctype
  541. = (const unsigned char *) &__locale_mmap->tblwctype;
  542. __global_locale.tblwuplow
  543. = (const unsigned char *) &__locale_mmap->tblwuplow;
  544. __global_locale.tblwuplow_diff
  545. = (const uint16_t *) &__locale_mmap->tblwuplow_diff;
  546. /* __global_locale.tblwcomb */
  547. /* = (const unsigned char *) &__locale_mmap->tblwcomb; */
  548. /* width?? */
  549. #endif /* __WCHAR_ENABLED */
  550. _locale_set(C_LOCALE_SELECTOR);
  551. }
  552. static const char ascii[] = "ASCII";
  553. static const char utf8[] = "UTF-8";
  554. void _locale_set(const unsigned char *p)
  555. {
  556. const char **x;
  557. unsigned char *s = CUR_LOCALE_SPEC + 1;
  558. const size_t *stp;
  559. const unsigned char *r;
  560. const uint16_t *io;
  561. const uint16_t *ii;
  562. const unsigned char *d;
  563. int row; /* locale row */
  564. int crow; /* category row */
  565. int len;
  566. int c;
  567. int i = 0;
  568. ++p;
  569. do {
  570. if ((*p != *s) || (p[1] != s[1])) {
  571. row = (((int)(*p & 0x7f)) << 7) + (p[1] & 0x7f);
  572. assert(row < NUM_LOCALES);
  573. *s = *p;
  574. s[1] = p[1];
  575. if ((i != LC_COLLATE)
  576. && ((len = __locale_mmap->lc_common_item_offsets_LEN[i]) != 0)
  577. ) {
  578. crow = __locale_mmap->locales[ WIDTH_LOCALES * row + 3 + i ]
  579. * len;
  580. x = (const char **)(((char *) &__global_locale)
  581. + __global_locale.category_offsets[i]);
  582. stp = __locale_mmap->lc_common_tbl_offsets + 4*i;
  583. r = (const unsigned char *)( ((char *)__locale_mmap) + *stp );
  584. io = (const uint16_t *)( ((char *)__locale_mmap) + *++stp );
  585. ii = (const uint16_t *)( ((char *)__locale_mmap) + *++stp );
  586. d = (const unsigned char *)( ((char *)__locale_mmap) + *++stp );
  587. for (c=0 ; c < len ; c++) {
  588. *(x + c) = d + ii[ r[crow + c] + io[c] ];
  589. }
  590. }
  591. if (i == LC_CTYPE) {
  592. c = __locale_mmap->locales[ WIDTH_LOCALES * row + 2 ]; /* codeset */
  593. if (c <= 2) {
  594. if (c == 2) {
  595. __global_locale.codeset = utf8;
  596. __global_locale.encoding = __ctype_encoding_utf8;
  597. /* TODO - fix for bcc */
  598. __global_locale.mb_cur_max = 6;
  599. } else {
  600. assert(c==1);
  601. __global_locale.codeset = ascii;
  602. __global_locale.encoding = __ctype_encoding_7_bit;
  603. __global_locale.mb_cur_max = 1;
  604. }
  605. } else {
  606. const codeset_8_bit_t *c8b;
  607. r = CODESET_LIST;
  608. __global_locale.codeset = r + r[c -= 3];
  609. __global_locale.encoding = __ctype_encoding_8_bit;
  610. #ifdef __UCLIBC_MJN3_ONLY__
  611. #warning REMINDER: update 8 bit mb_cur_max when trasnlit implemented!
  612. #endif
  613. /* TODO - update when translit implemented! */
  614. __global_locale.mb_cur_max = 1;
  615. c8b = __locale_mmap->codeset_8_bit + c;
  616. #ifdef __CTYPE_HAS_8_BIT_LOCALES
  617. __global_locale.idx8ctype = c8b->idx8ctype;
  618. __global_locale.idx8uplow = c8b->idx8uplow;
  619. #ifdef __WCHAR_ENABLED
  620. __global_locale.idx8c2wc = c8b->idx8c2wc;
  621. __global_locale.idx8wc2c = c8b->idx8wc2c;
  622. /* translit */
  623. #endif /* __WCHAR_ENABLED */
  624. #endif /* __CTYPE_HAS_8_BIT_LOCALES */
  625. }
  626. #ifdef __UCLIBC_MJN3_ONLY__
  627. #warning might want to just put this in the locale_mmap object
  628. #endif
  629. d = __global_locale.outdigit_length;
  630. x = &__global_locale.outdigit0_mb;
  631. for (c = 0 ; c < 10 ; c++) {
  632. ((unsigned char *)d)[c] = strlen(x[c]);
  633. assert(d[c] > 0);
  634. }
  635. } else if (i == LC_COLLATE) {
  636. init_cur_collate(__locale_mmap->locales[ WIDTH_LOCALES * row + 3 + i ]);
  637. }
  638. }
  639. ++i;
  640. p += 2;
  641. s += 2;
  642. } while (i < LC_ALL);
  643. }
  644. #endif /* __LOCALE_C_ONLY */
  645. #endif
  646. /**********************************************************************/
  647. #ifdef L_nl_langinfo
  648. #include <langinfo.h>
  649. #include <nl_types.h>
  650. #ifdef __LOCALE_C_ONLY
  651. /* We need to index 320 bytes of data, so you might initially think we
  652. * need to store the offsets in shorts. But since the offset of the
  653. * 64th item is 182, we'll store "offset - 2*64" for all items >= 64
  654. * and always calculate the data offset as "offset[i] + 2*(i & 64)".
  655. * This allows us to pack the data offsets in an unsigned char while
  656. * also avoiding an "if".
  657. *
  658. * Note: Category order is assumed to be:
  659. * ctype, numeric, monetary, time, collate, messages, all
  660. */
  661. #define C_LC_ALL 6
  662. /* Combine the data to avoid size penalty for seperate char arrays when
  663. * compiler aligns objects. The original code is left in as documentation. */
  664. #define cat_start nl_data
  665. #define C_locale_data (nl_data + C_LC_ALL + 1 + 90)
  666. static const unsigned char nl_data[C_LC_ALL + 1 + 90 + 320] = {
  667. /* static const char cat_start[LC_ALL + 1] = { */
  668. '\x00', '\x0b', '\x0e', '\x24', '\x56', '\x56', '\x5a',
  669. /* }; */
  670. /* static const char item_offset[90] = { */
  671. '\x00', '\x02', '\x04', '\x06', '\x08', '\x0a', '\x0c', '\x0e',
  672. '\x10', '\x12', '\x14', '\x1a', '\x1b', '\x1b', '\x1b', '\x1b',
  673. '\x1b', '\x1b', '\x1b', '\x1b', '\x1b', '\x1c', '\x1c', '\x1c',
  674. '\x1c', '\x1c', '\x1c', '\x1c', '\x1c', '\x1c', '\x1c', '\x1c',
  675. '\x1c', '\x1c', '\x1c', '\x1e', '\x20', '\x24', '\x28', '\x2c',
  676. '\x30', '\x34', '\x38', '\x3c', '\x43', '\x4a', '\x52', '\x5c',
  677. '\x65', '\x6c', '\x75', '\x79', '\x7d', '\x81', '\x85', '\x89',
  678. '\x8d', '\x91', '\x95', '\x99', '\x9d', '\xa1', '\xa5', '\xad',
  679. '\x36', '\x3c', '\x42', '\x46', '\x4b', '\x50', '\x57', '\x61',
  680. '\x69', '\x72', '\x7b', '\x7e', '\x81', '\x96', '\x9f', '\xa8',
  681. '\xb3', '\xb3', '\xb3', '\xb3', '\xb3', '\xb3', '\xb4', '\xba',
  682. '\xbf', '\xbf',
  683. /* }; */
  684. /* static const char C_locale_data[320] = { */
  685. '0', '\x00', '1', '\x00', '2', '\x00', '3', '\x00',
  686. '4', '\x00', '5', '\x00', '6', '\x00', '7', '\x00',
  687. '8', '\x00', '9', '\x00', 'A', 'S', 'C', 'I',
  688. 'I', '\x00', '.', '\x00', '\x7f', '\x00', '-', '\x00',
  689. 'S', 'u', 'n', '\x00', 'M', 'o', 'n', '\x00',
  690. 'T', 'u', 'e', '\x00', 'W', 'e', 'd', '\x00',
  691. 'T', 'h', 'u', '\x00', 'F', 'r', 'i', '\x00',
  692. 'S', 'a', 't', '\x00', 'S', 'u', 'n', 'd',
  693. 'a', 'y', '\x00', 'M', 'o', 'n', 'd', 'a',
  694. 'y', '\x00', 'T', 'u', 'e', 's', 'd', 'a',
  695. 'y', '\x00', 'W', 'e', 'd', 'n', 'e', 's',
  696. 'd', 'a', 'y', '\x00', 'T', 'h', 'u', 'r',
  697. 's', 'd', 'a', 'y', '\x00', 'F', 'r', 'i',
  698. 'd', 'a', 'y', '\x00', 'S', 'a', 't', 'u',
  699. 'r', 'd', 'a', 'y', '\x00', 'J', 'a', 'n',
  700. '\x00', 'F', 'e', 'b', '\x00', 'M', 'a', 'r',
  701. '\x00', 'A', 'p', 'r', '\x00', 'M', 'a', 'y',
  702. '\x00', 'J', 'u', 'n', '\x00', 'J', 'u', 'l',
  703. '\x00', 'A', 'u', 'g', '\x00', 'S', 'e', 'p',
  704. '\x00', 'O', 'c', 't', '\x00', 'N', 'o', 'v',
  705. '\x00', 'D', 'e', 'c', '\x00', 'J', 'a', 'n',
  706. 'u', 'a', 'r', 'y', '\x00', 'F', 'e', 'b',
  707. 'r', 'u', 'a', 'r', 'y', '\x00', 'M', 'a',
  708. 'r', 'c', 'h', '\x00', 'A', 'p', 'r', 'i',
  709. 'l', '\x00', 'M', 'a', 'y', '\x00', 'J', 'u',
  710. 'n', 'e', '\x00', 'J', 'u', 'l', 'y', '\x00',
  711. 'A', 'u', 'g', 'u', 's', 't', '\x00', 'S',
  712. 'e', 'p', 't', 'e', 'm', 'b', 'e', 'r',
  713. '\x00', 'O', 'c', 't', 'o', 'b', 'e', 'r',
  714. '\x00', 'N', 'o', 'v', 'e', 'm', 'b', 'e',
  715. 'r', '\x00', 'D', 'e', 'c', 'e', 'm', 'b',
  716. 'e', 'r', '\x00', 'A', 'M', '\x00', 'P', 'M',
  717. '\x00', '%', 'a', ' ', '%', 'b', ' ', '%',
  718. 'e', ' ', '%', 'H', ':', '%', 'M', ':',
  719. '%', 'S', ' ', '%', 'Y', '\x00', '%', 'm',
  720. '/', '%', 'd', '/', '%', 'y', '\x00', '%',
  721. 'H', ':', '%', 'M', ':', '%', 'S', '\x00',
  722. '%', 'I', ':', '%', 'M', ':', '%', 'S',
  723. ' ', '%', 'p', '\x00', '^', '[', 'y', 'Y',
  724. ']', '\x00', '^', '[', 'n', 'N', ']', '\x00',
  725. };
  726. char *nl_langinfo(nl_item item)
  727. {
  728. unsigned int c;
  729. unsigned int i;
  730. if ((c = _NL_ITEM_CATEGORY(item)) < C_LC_ALL) {
  731. if ((i = cat_start[c] + _NL_ITEM_INDEX(item)) < cat_start[c+1]) {
  732. /* return (char *) C_locale_data + item_offset[i] + (i & 64); */
  733. return (char *) C_locale_data + nl_data[C_LC_ALL+1+i] + 2*(i & 64);
  734. }
  735. }
  736. return (char *) cat_start; /* Conveniently, this is the empty string. */
  737. }
  738. #else /* __LOCALE_C_ONLY */
  739. static const char empty[] = "";
  740. char *nl_langinfo(nl_item item)
  741. {
  742. unsigned int c = _NL_ITEM_CATEGORY(item);
  743. unsigned int i = _NL_ITEM_INDEX(item);
  744. if ((c < LC_ALL) && (i < __global_locale.category_item_count[c])) {
  745. return ((char **)(((char *) &__global_locale)
  746. + __global_locale.category_offsets[c]))[i];
  747. }
  748. return (char *) empty;
  749. }
  750. #endif /* __LOCALE_C_ONLY */
  751. #endif
  752. /**********************************************************************/