locale.c 37 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299
  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. #define __CTYPE_HAS_8_BIT_LOCALES 1
  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. #include <errno.h>
  43. #include <ctype.h>
  44. #undef __LOCALE_C_ONLY
  45. #ifndef __UCLIBC_HAS_LOCALE__
  46. #define __LOCALE_C_ONLY
  47. #endif /* __UCLIBC_HAS_LOCALE__ */
  48. #ifdef __LOCALE_C_ONLY
  49. #include <locale.h>
  50. #else /* __LOCALE_C_ONLY */
  51. #ifdef __UCLIBC_MJN3_ONLY__
  52. #ifdef L_setlocale
  53. #warning TODO: Fix the __CTYPE_HAS_8_BIT_LOCALES define at the top of the file.
  54. #warning TODO: Fix __WCHAR_ENABLED.
  55. #endif
  56. #endif
  57. /* Need to include this before locale.h and xlocale.h! */
  58. #include <bits/uClibc_locale.h>
  59. #undef CODESET_LIST
  60. #define CODESET_LIST (__locale_mmap->codeset_list)
  61. #ifdef __UCLIBC_HAS_XLOCALE__
  62. #include <xlocale.h>
  63. #include <locale.h>
  64. #else /* __UCLIBC_HAS_XLOCALE__ */
  65. /* We need this internally... */
  66. #define __UCLIBC_HAS_XLOCALE__ 1
  67. #include <xlocale.h>
  68. #include <locale.h>
  69. #undef __UCLIBC_HAS_XLOCALE__
  70. #endif /* __UCLIBC_HAS_XLOCALE__ */
  71. #include <wchar.h>
  72. #define LOCALE_NAMES (__locale_mmap->locale_names5)
  73. #define LOCALES (__locale_mmap->locales)
  74. #define LOCALE_AT_MODIFIERS (__locale_mmap->locale_at_modifiers)
  75. #define CATEGORY_NAMES (__locale_mmap->lc_names)
  76. #ifdef __UCLIBC_MJN3_ONLY__
  77. #warning REMINDER: redo the MAX_LOCALE_STR stuff...
  78. #endif
  79. #define MAX_LOCALE_STR 256 /* TODO: Only sufficient for current case. */
  80. #define MAX_LOCALE_CATEGORY_STR 32 /* TODO: Only sufficient for current case. */
  81. /* Note: Best if MAX_LOCALE_CATEGORY_STR is a power of 2. */
  82. extern int _locale_set_l(const unsigned char *p, __locale_t base);
  83. extern void _locale_init_l(__locale_t base);
  84. #endif /* __LOCALE_C_ONLY */
  85. #undef LOCALE_STRING_SIZE
  86. #define LOCALE_SELECTOR_SIZE (2 * __LC_ALL + 2)
  87. #ifdef __UCLIBC_MJN3_ONLY__
  88. #ifdef L_setlocale
  89. #warning TODO: Create a C locale selector string.
  90. #endif
  91. #endif
  92. #define C_LOCALE_SELECTOR "\x23\x80\x80\x80\x80\x80\x80\x80\x80\x80\x80\x80\x80"
  93. #include <langinfo.h>
  94. #include <nl_types.h>
  95. /**********************************************************************/
  96. #ifdef L_setlocale
  97. #ifdef __LOCALE_C_ONLY
  98. link_warning(setlocale,"REMINDER: The 'setlocale' function supports only C|POSIX locales.")
  99. static const char C_string[] = "C";
  100. char *setlocale(int category, register const char *locale)
  101. {
  102. return ( (((unsigned int)(category)) <= LC_ALL)
  103. && ( (!locale) /* Request for locale category string. */
  104. || (!*locale) /* Implementation-defined default is C. */
  105. || ((*locale == 'C') && !locale[1])
  106. || (!strcmp(locale, "POSIX"))) )
  107. ? (char *) C_string /* Always in C/POSIX locale. */
  108. : NULL;
  109. }
  110. #else /* ---------------------------------------------- __LOCALE_C_ONLY */
  111. #ifdef __UCLIBC_HAS_THREADS__
  112. link_warning(setlocale,"REMINDER: The 'setlocale' function is _not_ threadsafe except for simple queries.")
  113. #endif
  114. #if !defined(__LOCALE_DATA_NUM_LOCALES) || (__LOCALE_DATA_NUM_LOCALES <= 1)
  115. #error locales enabled, but not data other than for C locale!
  116. #endif
  117. #ifdef __UCLIBC_MJN3_ONLY__
  118. #warning TODO: Move posix and utf8 strings.
  119. #endif
  120. static const char posix[] = "POSIX";
  121. static const char utf8[] = "UTF-8";
  122. #ifdef __UCLIBC_MJN3_ONLY__
  123. #warning TODO: Fix dimensions of hr_locale.
  124. #endif
  125. /* Individual category strings start at hr_locale + category * MAX_LOCALE_CATEGORY.
  126. * This holds for LC_ALL as well.
  127. */
  128. static char hr_locale[(MAX_LOCALE_CATEGORY_STR * LC_ALL) + MAX_LOCALE_STR];
  129. static void update_hr_locale(const unsigned char *spec)
  130. {
  131. const unsigned char *loc;
  132. const unsigned char *s;
  133. char *n;
  134. int i, category, done;
  135. done = category = 0;
  136. do {
  137. s = spec + 1;
  138. n = hr_locale + category * MAX_LOCALE_CATEGORY_STR;
  139. if (category == LC_ALL) {
  140. done = 1;
  141. for (i = 0 ; i < LC_ALL-1 ; i += 2) {
  142. if ((s[i] != s[i+2]) || (s[i+1] != s[i+3])) {
  143. goto SKIP;
  144. }
  145. }
  146. /* All categories the same, so simplify string by using a single
  147. * category. */
  148. category = LC_CTYPE;
  149. }
  150. SKIP:
  151. i = (category == LC_ALL) ? 0 : category;
  152. s += 2*i;
  153. do {
  154. if ((*s != 0xff) || (s[1] != 0xff)) {
  155. loc = LOCALES
  156. + __LOCALE_DATA_WIDTH_LOCALES * ((((int)(*s & 0x7f)) << 7)
  157. + (s[1] & 0x7f));
  158. if (category == LC_ALL) {
  159. n = stpcpy(n, CATEGORY_NAMES + (int) CATEGORY_NAMES[i]);
  160. *n++ = '=';
  161. }
  162. if (*loc == 0) {
  163. *n++ = 'C';
  164. *n = 0;
  165. } else {
  166. char at = 0;
  167. memcpy(n, LOCALE_NAMES + 5*((*loc)-1), 5);
  168. if (n[2] != '_') {
  169. at = n[2];
  170. n[2] = '_';
  171. }
  172. n += 5;
  173. *n++ = '.';
  174. if (loc[2] == 2) {
  175. n = stpcpy(n, utf8);
  176. } else if (loc[2] >= 3) {
  177. n = stpcpy(n, CODESET_LIST + (int)(CODESET_LIST[loc[2] - 3]));
  178. }
  179. if (at) {
  180. const char *q;
  181. *n++ = '@';
  182. q = LOCALE_AT_MODIFIERS;
  183. do {
  184. if (q[1] == at) {
  185. n = stpcpy(n, q+2);
  186. break;
  187. }
  188. q += 2 + *q;
  189. } while (*q);
  190. }
  191. }
  192. *n++ = ';';
  193. }
  194. s += 2;
  195. } while (++i < category);
  196. *--n = 0; /* Remove trailing ';' and nul-terminate. */
  197. ++category;
  198. } while (!done);
  199. }
  200. char *setlocale(int category, const char *locale)
  201. {
  202. if (((unsigned int)(category)) > LC_ALL) {
  203. #if 0
  204. __set_errno(EINVAL); /* glibc sets errno -- SUSv3 doesn't say. */
  205. #endif
  206. return NULL; /* Illegal/unsupported category. */
  207. }
  208. if (locale != NULL) { /* Not just a query... */
  209. if (!__newlocale((category == LC_ALL) ? LC_ALL_MASK : (1 << category),
  210. locale, __global_locale)
  211. ) { /* Failed! */
  212. return NULL;
  213. }
  214. update_hr_locale(__global_locale->cur_locale);
  215. }
  216. /* Either a query or a successful set, so return current locale string. */
  217. return hr_locale + (category * MAX_LOCALE_CATEGORY_STR);
  218. }
  219. #endif /* __LOCALE_C_ONLY */
  220. #endif
  221. /**********************************************************************/
  222. #ifdef L_localeconv
  223. /* Note: We assume here that the compiler does the sane thing regarding
  224. * placement of the fields in the struct. If necessary, we could ensure
  225. * this usings an array of offsets but at some size cost. */
  226. #ifdef __LOCALE_C_ONLY
  227. link_warning(localeconv,"REMINDER: The 'localeconv' function is hardwired for C/POSIX locale only.")
  228. static struct lconv the_lconv;
  229. static const char decpt[] = ".";
  230. struct lconv *localeconv(void)
  231. {
  232. register char *p = (char *)(&the_lconv);
  233. *((char **)p) = (char *) decpt;
  234. do {
  235. p += sizeof(char **);
  236. *((char **)p) = (char *) (decpt+1);
  237. } while (p < (char *) &the_lconv.negative_sign);
  238. p = (&the_lconv.int_frac_digits);
  239. do {
  240. *p = CHAR_MAX;
  241. ++p;
  242. } while (p <= &the_lconv.int_n_sign_posn);
  243. return &the_lconv;
  244. }
  245. #else /* __LOCALE_C_ONLY */
  246. static struct lconv the_lconv;
  247. struct lconv *localeconv(void)
  248. {
  249. register char *p = (char *) &the_lconv;
  250. register char **q = (char **) &(__UCLIBC_CURLOCALE_DATA).decimal_point;
  251. do {
  252. *((char **)p) = *q;
  253. p += sizeof(char **);
  254. ++q;
  255. } while (p < &the_lconv.int_frac_digits);
  256. do {
  257. *p = **q;
  258. ++p;
  259. ++q;
  260. } while (p <= &the_lconv.int_n_sign_posn);
  261. return &the_lconv;
  262. }
  263. #endif /* __LOCALE_C_ONLY */
  264. #endif
  265. /**********************************************************************/
  266. #if defined(L__locale_init) && !defined(__LOCALE_C_ONLY)
  267. static __uclibc_locale_t __global_locale_data;
  268. __locale_t __global_locale = &__global_locale_data;
  269. #ifdef __UCLIBC_HAS_XLOCALE__
  270. __locale_t __curlocale_var = &__global_locale_data;
  271. #endif
  272. /*----------------------------------------------------------------------*/
  273. #ifdef __UCLIBC_MJN3_ONLY__
  274. #warning TODO: Move utf8 and ascii strings.
  275. #endif
  276. static const char utf8[] = "UTF-8";
  277. static const char ascii[] = "ASCII";
  278. typedef struct {
  279. uint16_t num_base;
  280. uint16_t num_der;
  281. uint16_t MAX_WEIGHTS;
  282. uint16_t num_index2weight;
  283. #define num_index2ruleidx num_index2weight
  284. uint16_t num_weightstr;
  285. uint16_t num_multistart;
  286. uint16_t num_override;
  287. uint16_t num_ruletable;
  288. } coldata_header_t;
  289. typedef struct {
  290. uint16_t num_weights;
  291. uint16_t num_starters;
  292. uint16_t ii_shift;
  293. uint16_t ti_shift;
  294. uint16_t ii_len;
  295. uint16_t ti_len;
  296. uint16_t max_weight;
  297. uint16_t num_col_base;
  298. uint16_t max_col_index;
  299. uint16_t undefined_idx;
  300. uint16_t range_low;
  301. uint16_t range_count;
  302. uint16_t range_base_weight;
  303. uint16_t range_rule_offset;
  304. uint16_t index2weight_offset;
  305. uint16_t index2ruleidx_offset;
  306. uint16_t multistart_offset;
  307. uint16_t wcs2colidt_offset_low;
  308. uint16_t wcs2colidt_offset_hi;
  309. } coldata_base_t;
  310. typedef struct {
  311. uint16_t base_idx;
  312. uint16_t undefined_idx;
  313. uint16_t overrides_offset;
  314. uint16_t multistart_offset;
  315. } coldata_der_t;
  316. static int init_cur_collate(int der_num, __collate_t *cur_collate)
  317. {
  318. const uint16_t *__locale_collate_tbl = __locale_mmap->collate_data;
  319. coldata_header_t *cdh;
  320. coldata_base_t *cdb;
  321. coldata_der_t *cdd;
  322. const uint16_t *p;
  323. size_t n;
  324. uint16_t i, w;
  325. assert(sizeof(coldata_base_t) == 19*2);
  326. assert(sizeof(coldata_der_t) == 4*2);
  327. assert(sizeof(coldata_header_t) == 8*2);
  328. if (!der_num) { /* C locale... special */
  329. cur_collate->num_weights = 0;
  330. return 1;
  331. }
  332. --der_num;
  333. cdh = (coldata_header_t *) __locale_collate_tbl;
  334. #ifdef __UCLIBC_MJN3_ONLY__
  335. #warning CONSIDER: Should we assert here?
  336. #endif
  337. #if 0
  338. if (der_num >= cdh->num_der) {
  339. return 0;
  340. }
  341. #else
  342. assert((der_num < cdh->num_der));
  343. #endif
  344. cdd = (coldata_der_t *)(__locale_collate_tbl
  345. + (sizeof(coldata_header_t)
  346. + cdh->num_base * sizeof(coldata_base_t)
  347. + der_num * sizeof(coldata_der_t)
  348. )/2 );
  349. cdb = (coldata_base_t *)(__locale_collate_tbl
  350. + (sizeof(coldata_header_t)
  351. + cdd->base_idx * sizeof(coldata_base_t)
  352. )/2 );
  353. memcpy(cur_collate, cdb, offsetof(coldata_base_t,index2weight_offset));
  354. cur_collate->undefined_idx = cdd->undefined_idx;
  355. cur_collate->ti_mask = (1 << cur_collate->ti_shift)-1;
  356. cur_collate->ii_mask = (1 << cur_collate->ii_shift)-1;
  357. /* printf("base=%d num_col_base: %d %d\n", cdd->base_idx ,cur_collate->num_col_base, cdb->num_col_base); */
  358. n = (sizeof(coldata_header_t) + cdh->num_base * sizeof(coldata_base_t)
  359. + cdh->num_der * sizeof(coldata_der_t))/2;
  360. /* printf("n = %d\n", n); */
  361. cur_collate->index2weight_tbl = __locale_collate_tbl + n + cdb->index2weight_offset;
  362. /* printf("i2w = %d\n", n + cdb->index2weight_offset); */
  363. n += cdh->num_index2weight;
  364. cur_collate->index2ruleidx_tbl = __locale_collate_tbl + n + cdb->index2ruleidx_offset;
  365. /* printf("i2r = %d\n", n + cdb->index2ruleidx_offset); */
  366. n += cdh->num_index2ruleidx;
  367. cur_collate->multistart_tbl = __locale_collate_tbl + n + cdd->multistart_offset;
  368. /* printf("mts = %d\n", n + cdb->multistart_offset); */
  369. n += cdh->num_multistart;
  370. cur_collate->overrides_tbl = __locale_collate_tbl + n + cdd->overrides_offset;
  371. /* printf("ovr = %d\n", n + cdd->overrides_offset); */
  372. n += cdh->num_override;
  373. cur_collate->ruletable = __locale_collate_tbl + n;
  374. /* printf("rtb = %d\n", n); */
  375. n += cdh->num_ruletable;
  376. cur_collate->weightstr = __locale_collate_tbl + n;
  377. /* printf("wts = %d\n", n); */
  378. n += cdh->num_weightstr;
  379. cur_collate->wcs2colidt_tbl = __locale_collate_tbl + n
  380. + (((unsigned long)(cdb->wcs2colidt_offset_hi)) << 16)
  381. + cdb->wcs2colidt_offset_low;
  382. /* printf("wcs = %lu\n", n + (((unsigned long)(cdb->wcs2colidt_offset_hi)) << 16) */
  383. /* + cdb->wcs2colidt_offset_low); */
  384. cur_collate->MAX_WEIGHTS = cdh->MAX_WEIGHTS;
  385. #ifdef __UCLIBC_MJN3_ONLY__
  386. #warning CONSIDER: Fix the +1 by increasing max_col_index?
  387. #warning CONSIDER: Since this collate info is dependent only on LC_COLLATE ll_cc and not on codeset, we could just globally allocate this for each in a table
  388. #endif
  389. cur_collate->index2weight = calloc(2*cur_collate->max_col_index+2,
  390. sizeof(uint16_t));
  391. if (!cur_collate->index2weight) {
  392. return 0;
  393. }
  394. cur_collate->index2ruleidx = cur_collate->index2weight
  395. + cur_collate->max_col_index + 1;
  396. memcpy(cur_collate->index2weight, cur_collate->index2weight_tbl,
  397. cur_collate->num_col_base * sizeof(uint16_t));
  398. memcpy(cur_collate->index2ruleidx, cur_collate->index2ruleidx_tbl,
  399. cur_collate->num_col_base * sizeof(uint16_t));
  400. /* now do the overrides */
  401. p = cur_collate->overrides_tbl;
  402. while (*p > 1) {
  403. /* fprintf(stderr, "processing override -- count = %d\n", *p); */
  404. n = *p++;
  405. w = *p++;
  406. do {
  407. i = *p++;
  408. /* fprintf(stderr, " i=%d w=%d *p=%d\n", i, w, *p); */
  409. cur_collate->index2weight[i-1] = w++;
  410. cur_collate->index2ruleidx[i-1] = *p++;
  411. } while (--n);
  412. }
  413. while (*++p) {
  414. i = *p;
  415. cur_collate->index2weight[i-1] = *++p;
  416. cur_collate->index2ruleidx[i-1] = *++p;
  417. }
  418. for (i=0 ; i < cur_collate->multistart_tbl[0] ; i++) {
  419. p = cur_collate->multistart_tbl;
  420. /* fprintf(stderr, "%2d of %2d: %d ", i, cur_collate->multistart_tbl[0], p[i]); */
  421. p += p[i];
  422. do {
  423. n = *p++;
  424. do {
  425. if (!*p) { /* found it */
  426. /* fprintf(stderr, "found: n=%d (%#lx) |%.*ls|\n", n, (int) *cs->s, n, cs->s); */
  427. /* fprintf(stderr, ": %d - single\n", n); */
  428. goto FOUND;
  429. }
  430. /* the lookup check here is safe since we're assured that *p is a valid colidex */
  431. /* fprintf(stderr, "lookup(%lc)==%d *p==%d\n", cs->s[n], lookup(cs->s[n]), (int) *p); */
  432. /* fprintf(stderr, ": %d - ", n); */
  433. do {
  434. /* fprintf(stderr, "%d|", *p); */
  435. } while (*p++);
  436. break;
  437. } while (1);
  438. } while (1);
  439. FOUND:
  440. continue;
  441. }
  442. return 1;
  443. }
  444. int _locale_set_l(const unsigned char *p, __locale_t base)
  445. {
  446. const char **x;
  447. unsigned char *s = base->cur_locale + 1;
  448. const size_t *stp;
  449. const unsigned char *r;
  450. const uint16_t *io;
  451. const uint16_t *ii;
  452. const unsigned char *d;
  453. int row; /* locale row */
  454. int crow; /* category row */
  455. int len;
  456. int c;
  457. int i = 0;
  458. __collate_t newcol;
  459. ++p;
  460. newcol.index2weight = NULL;
  461. if ((p[2*LC_COLLATE] != s[2*LC_COLLATE])
  462. || (p[2*LC_COLLATE + 1] != s[2*LC_COLLATE + 1])
  463. ) {
  464. row = (((int)(*p & 0x7f)) << 7) + (p[1] & 0x7f);
  465. assert(row < __LOCALE_DATA_NUM_LOCALES);
  466. if (!init_cur_collate(__locale_mmap->locales[ __LOCALE_DATA_WIDTH_LOCALES
  467. * row + 3 + i ],
  468. &newcol)
  469. ) {
  470. return 0; /* calloc failed. */
  471. }
  472. free(base->collate.index2weight);
  473. memcpy(&base->collate, &newcol, sizeof(__collate_t));
  474. }
  475. do {
  476. if ((*p != *s) || (p[1] != s[1])) {
  477. row = (((int)(*p & 0x7f)) << 7) + (p[1] & 0x7f);
  478. assert(row < __LOCALE_DATA_NUM_LOCALES);
  479. *s = *p;
  480. s[1] = p[1];
  481. if ((i != LC_COLLATE)
  482. && ((len = __locale_mmap->lc_common_item_offsets_LEN[i]) != 0)
  483. ) {
  484. crow = __locale_mmap->locales[ __LOCALE_DATA_WIDTH_LOCALES * row
  485. + 3 + i ]
  486. * len;
  487. x = (const char **)(((char *) base)
  488. + base->category_offsets[i]);
  489. stp = __locale_mmap->lc_common_tbl_offsets + 4*i;
  490. r = (const unsigned char *)( ((char *)__locale_mmap) + *stp );
  491. io = (const uint16_t *)( ((char *)__locale_mmap) + *++stp );
  492. ii = (const uint16_t *)( ((char *)__locale_mmap) + *++stp );
  493. d = (const unsigned char *)( ((char *)__locale_mmap) + *++stp );
  494. for (c=0 ; c < len ; c++) {
  495. *(x + c) = d + ii[ r[crow + c] + io[c] ];
  496. }
  497. }
  498. if (i == LC_CTYPE) {
  499. c = __locale_mmap->locales[ __LOCALE_DATA_WIDTH_LOCALES * row
  500. + 2 ]; /* codeset */
  501. if (c <= 2) {
  502. if (c == 2) {
  503. base->codeset = utf8;
  504. base->encoding = __ctype_encoding_utf8;
  505. /* TODO - fix for bcc */
  506. base->mb_cur_max = 6;
  507. } else {
  508. assert(c==1);
  509. base->codeset = ascii;
  510. base->encoding = __ctype_encoding_7_bit;
  511. base->mb_cur_max = 1;
  512. }
  513. } else {
  514. const __codeset_8_bit_t *c8b;
  515. r = CODESET_LIST;
  516. base->codeset = r + r[c -= 3];
  517. base->encoding = __ctype_encoding_8_bit;
  518. #ifdef __UCLIBC_MJN3_ONLY__
  519. #warning REMINDER: update 8 bit mb_cur_max when translit implemented!
  520. #endif
  521. /* TODO - update when translit implemented! */
  522. base->mb_cur_max = 1;
  523. c8b = __locale_mmap->codeset_8_bit + c;
  524. #ifdef __CTYPE_HAS_8_BIT_LOCALES
  525. base->idx8ctype = c8b->idx8ctype;
  526. base->idx8uplow = c8b->idx8uplow;
  527. #ifdef __UCLIBC_HAS_WCHAR__
  528. base->idx8c2wc = c8b->idx8c2wc;
  529. base->idx8wc2c = c8b->idx8wc2c;
  530. /* translit */
  531. #endif /* __UCLIBC_HAS_WCHAR__ */
  532. #endif /* __CTYPE_HAS_8_BIT_LOCALES */
  533. }
  534. #ifdef __UCLIBC_MJN3_ONLY__
  535. #warning TODO: Put the outdigit string length in the locale_mmap object.
  536. #endif
  537. d = base->outdigit_length;
  538. x = &base->outdigit0_mb;
  539. for (c = 0 ; c < 10 ; c++) {
  540. ((unsigned char *)d)[c] = strlen(x[c]);
  541. assert(d[c] > 0);
  542. }
  543. } else if (i == LC_NUMERIC) {
  544. assert(LC_NUMERIC > LC_CTYPE); /* Need ctype initialized. */
  545. base->decimal_point_len
  546. = __locale_mbrtowc_l(&base->decimal_point_wc,
  547. base->decimal_point, base);
  548. assert(base->decimal_point_len > 0);
  549. assert(base->decimal_point[base->decimal_point_len] == 0);
  550. if (*base->grouping) {
  551. base->thousands_sep_len
  552. = __locale_mbrtowc_l(&base->thousands_sep_wc,
  553. base->thousands_sep, base);
  554. assert(base->thousands_sep_len > 0);
  555. assert(base->thousands_sep[base->thousands_sep_len] == 0);
  556. }
  557. /* } else if (i == LC_COLLATE) { */
  558. /* init_cur_collate(__locale_mmap->locales[ __LOCALE_DATA_WIDTH_LOCALES */
  559. /* * row + 3 + i ], */
  560. /* &base->collate); */
  561. }
  562. }
  563. ++i;
  564. p += 2;
  565. s += 2;
  566. } while (i < LC_ALL);
  567. return 1;
  568. }
  569. static const uint16_t __code2flag[16] = {
  570. 0, /* unclassified = 0 */
  571. _ISprint|_ISgraph|_ISalnum|_ISalpha, /* alpha_nonupper_nonlower */
  572. _ISprint|_ISgraph|_ISalnum|_ISalpha|_ISlower, /* alpha_lower */
  573. _ISprint|_ISgraph|_ISalnum|_ISalpha|_ISlower|_ISupper, /* alpha_upper_lower */
  574. _ISprint|_ISgraph|_ISalnum|_ISalpha|_ISupper, /* alpha_upper */
  575. _ISprint|_ISgraph|_ISalnum|_ISdigit, /* digit */
  576. _ISprint|_ISgraph|_ISpunct, /* punct */
  577. _ISprint|_ISgraph, /* graph */
  578. _ISprint|_ISspace, /* print_space_nonblank */
  579. _ISprint|_ISspace|_ISblank, /* print_space_blank */
  580. _ISspace, /* space_nonblank_noncntrl */
  581. _ISspace|_ISblank, /* space_blank_noncntrl */
  582. _IScntrl|_ISspace, /* cntrl_space_nonblank */
  583. _IScntrl|_ISspace|_ISblank, /* cntrl_space_blank */
  584. _IScntrl /* cntrl_nonspace */
  585. };
  586. void _locale_init_l(__locale_t base)
  587. {
  588. memset(base->cur_locale, 0, LOCALE_SELECTOR_SIZE);
  589. base->cur_locale[0] = '#';
  590. memcpy(base->category_item_count,
  591. __locale_mmap->lc_common_item_offsets_LEN,
  592. LC_ALL);
  593. ++base->category_item_count[0]; /* Increment for codeset entry. */
  594. base->category_offsets[0] = offsetof(__uclibc_locale_t, outdigit0_mb);
  595. base->category_offsets[1] = offsetof(__uclibc_locale_t, decimal_point);
  596. base->category_offsets[2] = offsetof(__uclibc_locale_t, int_curr_symbol);
  597. base->category_offsets[3] = offsetof(__uclibc_locale_t, abday_1);
  598. /* base->category_offsets[4] = offsetof(__uclibc_locale_t, collate???); */
  599. base->category_offsets[5] = offsetof(__uclibc_locale_t, yesexpr);
  600. #ifdef __CTYPE_HAS_8_BIT_LOCALES
  601. base->tbl8ctype
  602. = (const unsigned char *) &__locale_mmap->tbl8ctype;
  603. base->tbl8uplow
  604. = (const unsigned char *) &__locale_mmap->tbl8uplow;
  605. #ifdef __UCLIBC_HAS_WCHAR__
  606. base->tbl8c2wc
  607. = (const uint16_t *) &__locale_mmap->tbl8c2wc;
  608. base->tbl8wc2c
  609. = (const unsigned char *) &__locale_mmap->tbl8wc2c;
  610. /* translit */
  611. #endif /* __UCLIBC_HAS_WCHAR__ */
  612. #endif /* __CTYPE_HAS_8_BIT_LOCALES */
  613. #ifdef __UCLIBC_HAS_WCHAR__
  614. base->tblwctype
  615. = (const unsigned char *) &__locale_mmap->tblwctype;
  616. base->tblwuplow
  617. = (const unsigned char *) &__locale_mmap->tblwuplow;
  618. base->tblwuplow_diff
  619. = (const uint16_t *) &__locale_mmap->tblwuplow_diff;
  620. /* base->tblwcomb */
  621. /* = (const unsigned char *) &__locale_mmap->tblwcomb; */
  622. /* width?? */
  623. #endif /* __UCLIBC_HAS_WCHAR__ */
  624. #ifdef __UCLIBC_MJN3_ONLY__
  625. #warning wrong for now, but always set ctype arrays to global C version
  626. #endif
  627. #ifdef __UCLIBC_HAS_XLOCALE__
  628. base->__ctype_b = __C_ctype_b;
  629. base->__ctype_tolower = __C_ctype_tolower;
  630. base->__ctype_toupper = __C_ctype_toupper;
  631. #else /* __UCLIBC_HAS_XLOCALE__ */
  632. __ctype_b = __C_ctype_b;
  633. __ctype_tolower = __C_ctype_tolower;
  634. __ctype_toupper = __C_ctype_toupper;
  635. #endif /* __UCLIBC_HAS_XLOCALE__ */
  636. #ifdef __UCLIBC_MJN3_ONLY__
  637. #warning TODO: Initialize code2flag correctly based on locale_mmap.
  638. #endif
  639. base->code2flag = __code2flag;
  640. _locale_set_l(C_LOCALE_SELECTOR, base);
  641. }
  642. void _locale_init(void)
  643. {
  644. /* TODO: mmap the locale file */
  645. /* TODO - ??? */
  646. _locale_init_l(__global_locale);
  647. }
  648. #endif
  649. /**********************************************************************/
  650. #if defined(L_nl_langinfo) || defined(L_nl_langinfo_l)
  651. #ifdef __LOCALE_C_ONLY
  652. /* We need to index 320 bytes of data, so you might initially think we
  653. * need to store the offsets in shorts. But since the offset of the
  654. * 64th item is 182, we'll store "offset - 2*64" for all items >= 64
  655. * and always calculate the data offset as "offset[i] + 2*(i & 64)".
  656. * This allows us to pack the data offsets in an unsigned char while
  657. * also avoiding an "if".
  658. *
  659. * Note: Category order is assumed to be:
  660. * ctype, numeric, monetary, time, collate, messages, all
  661. */
  662. #define C_LC_ALL 6
  663. /* Combine the data to avoid size penalty for seperate char arrays when
  664. * compiler aligns objects. The original code is left in as documentation. */
  665. #define cat_start nl_data
  666. #define C_locale_data (nl_data + C_LC_ALL + 1 + 90)
  667. static const unsigned char nl_data[C_LC_ALL + 1 + 90 + 320] = {
  668. /* static const char cat_start[LC_ALL + 1] = { */
  669. '\x00', '\x0b', '\x0e', '\x24', '\x56', '\x56', '\x5a',
  670. /* }; */
  671. /* static const char item_offset[90] = { */
  672. '\x00', '\x02', '\x04', '\x06', '\x08', '\x0a', '\x0c', '\x0e',
  673. '\x10', '\x12', '\x14', '\x1a', '\x1b', '\x1b', '\x1b', '\x1b',
  674. '\x1b', '\x1b', '\x1b', '\x1b', '\x1b', '\x1c', '\x1c', '\x1c',
  675. '\x1c', '\x1c', '\x1c', '\x1c', '\x1c', '\x1c', '\x1c', '\x1c',
  676. '\x1c', '\x1c', '\x1c', '\x1e', '\x20', '\x24', '\x28', '\x2c',
  677. '\x30', '\x34', '\x38', '\x3c', '\x43', '\x4a', '\x52', '\x5c',
  678. '\x65', '\x6c', '\x75', '\x79', '\x7d', '\x81', '\x85', '\x89',
  679. '\x8d', '\x91', '\x95', '\x99', '\x9d', '\xa1', '\xa5', '\xad',
  680. '\x36', '\x3c', '\x42', '\x46', '\x4b', '\x50', '\x57', '\x61',
  681. '\x69', '\x72', '\x7b', '\x7e', '\x81', '\x96', '\x9f', '\xa8',
  682. '\xb3', '\xb3', '\xb3', '\xb3', '\xb3', '\xb3', '\xb4', '\xba',
  683. '\xbf', '\xbf',
  684. /* }; */
  685. /* static const char C_locale_data[320] = { */
  686. '0', '\x00', '1', '\x00', '2', '\x00', '3', '\x00',
  687. '4', '\x00', '5', '\x00', '6', '\x00', '7', '\x00',
  688. '8', '\x00', '9', '\x00', 'A', 'S', 'C', 'I',
  689. 'I', '\x00', '.', '\x00', '\x7f', '\x00', '-', '\x00',
  690. 'S', 'u', 'n', '\x00', 'M', 'o', 'n', '\x00',
  691. 'T', 'u', 'e', '\x00', 'W', 'e', 'd', '\x00',
  692. 'T', 'h', 'u', '\x00', 'F', 'r', 'i', '\x00',
  693. 'S', 'a', 't', '\x00', 'S', 'u', 'n', 'd',
  694. 'a', 'y', '\x00', 'M', 'o', 'n', 'd', 'a',
  695. 'y', '\x00', 'T', 'u', 'e', 's', 'd', 'a',
  696. 'y', '\x00', 'W', 'e', 'd', 'n', 'e', 's',
  697. 'd', 'a', 'y', '\x00', 'T', 'h', 'u', 'r',
  698. 's', 'd', 'a', 'y', '\x00', 'F', 'r', 'i',
  699. 'd', 'a', 'y', '\x00', 'S', 'a', 't', 'u',
  700. 'r', 'd', 'a', 'y', '\x00', 'J', 'a', 'n',
  701. '\x00', 'F', 'e', 'b', '\x00', 'M', 'a', 'r',
  702. '\x00', 'A', 'p', 'r', '\x00', 'M', 'a', 'y',
  703. '\x00', 'J', 'u', 'n', '\x00', 'J', 'u', 'l',
  704. '\x00', 'A', 'u', 'g', '\x00', 'S', 'e', 'p',
  705. '\x00', 'O', 'c', 't', '\x00', 'N', 'o', 'v',
  706. '\x00', 'D', 'e', 'c', '\x00', 'J', 'a', 'n',
  707. 'u', 'a', 'r', 'y', '\x00', 'F', 'e', 'b',
  708. 'r', 'u', 'a', 'r', 'y', '\x00', 'M', 'a',
  709. 'r', 'c', 'h', '\x00', 'A', 'p', 'r', 'i',
  710. 'l', '\x00', 'M', 'a', 'y', '\x00', 'J', 'u',
  711. 'n', 'e', '\x00', 'J', 'u', 'l', 'y', '\x00',
  712. 'A', 'u', 'g', 'u', 's', 't', '\x00', 'S',
  713. 'e', 'p', 't', 'e', 'm', 'b', 'e', 'r',
  714. '\x00', 'O', 'c', 't', 'o', 'b', 'e', 'r',
  715. '\x00', 'N', 'o', 'v', 'e', 'm', 'b', 'e',
  716. 'r', '\x00', 'D', 'e', 'c', 'e', 'm', 'b',
  717. 'e', 'r', '\x00', 'A', 'M', '\x00', 'P', 'M',
  718. '\x00', '%', 'a', ' ', '%', 'b', ' ', '%',
  719. 'e', ' ', '%', 'H', ':', '%', 'M', ':',
  720. '%', 'S', ' ', '%', 'Y', '\x00', '%', 'm',
  721. '/', '%', 'd', '/', '%', 'y', '\x00', '%',
  722. 'H', ':', '%', 'M', ':', '%', 'S', '\x00',
  723. '%', 'I', ':', '%', 'M', ':', '%', 'S',
  724. ' ', '%', 'p', '\x00', '^', '[', 'y', 'Y',
  725. ']', '\x00', '^', '[', 'n', 'N', ']', '\x00',
  726. };
  727. char *nl_langinfo(nl_item item)
  728. {
  729. unsigned int c;
  730. unsigned int i;
  731. if ((c = _NL_ITEM_CATEGORY(item)) < C_LC_ALL) {
  732. if ((i = cat_start[c] + _NL_ITEM_INDEX(item)) < cat_start[c+1]) {
  733. /* return (char *) C_locale_data + item_offset[i] + (i & 64); */
  734. return (char *) C_locale_data + nl_data[C_LC_ALL+1+i] + 2*(i & 64);
  735. }
  736. }
  737. return (char *) cat_start; /* Conveniently, this is the empty string. */
  738. }
  739. #else /* __LOCALE_C_ONLY */
  740. #if defined(__UCLIBC_HAS_XLOCALE__) && !defined(__UCLIBC_DO_XLOCALE)
  741. char *nl_langinfo(nl_item item)
  742. {
  743. return nl_langinfo_l(item, __UCLIBC_CURLOCALE);
  744. }
  745. #else /* defined(__UCLIBC_HAS_XLOCALE__) && !defined(__UCLIBC_DO_XLOCALE) */
  746. static const char empty[] = "";
  747. char *__XL(nl_langinfo)(nl_item item __LOCALE_PARAM )
  748. {
  749. unsigned int c = _NL_ITEM_CATEGORY(item);
  750. unsigned int i = _NL_ITEM_INDEX(item);
  751. if ((c < LC_ALL) && (i < __LOCALE_PTR->category_item_count[c])) {
  752. return ((char **)(((char *) __LOCALE_PTR)
  753. + __LOCALE_PTR->category_offsets[c]))[i];
  754. }
  755. return (char *) empty;
  756. }
  757. #endif /* defined(__UCLIBC_HAS_XLOCALE__) && !defined(__UCLIBC_DO_XLOCALE) */
  758. #endif /* __LOCALE_C_ONLY */
  759. #endif
  760. /**********************************************************************/
  761. #ifdef L_newlocale
  762. #ifdef __UCLIBC_MJN3_ONLY__
  763. #warning TODO: Move posix and utf8 strings.
  764. #endif
  765. static const char posix[] = "POSIX";
  766. static const char utf8[] = "UTF-8";
  767. static int find_locale(int category_mask, const char *p,
  768. unsigned char *new_locale)
  769. {
  770. int i;
  771. const unsigned char *s;
  772. uint16_t n;
  773. unsigned char lang_cult, codeset;
  774. #if defined(__LOCALE_DATA_AT_MODIFIERS_LENGTH) && 1
  775. /* Support standard locale handling for @-modifiers. */
  776. #ifdef __UCLIBC_MJN3_ONLY__
  777. #warning REMINDER: Fix buf size in find_locale.
  778. #endif
  779. char buf[18]; /* TODO: 7+{max codeset name length} */
  780. const char *q;
  781. if ((q = strchr(p,'@')) != NULL) {
  782. if ((((size_t)((q-p)-5)) > (sizeof(buf) - 5)) || (p[2] != '_')) {
  783. return 0;
  784. }
  785. /* locale name at least 5 chars long and 3rd char is '_' */
  786. s = LOCALE_AT_MODIFIERS;
  787. do {
  788. if (!strcmp(s+2, q+1)) {
  789. break;
  790. }
  791. s += 2 + *s; /* TODO - fix this throughout */
  792. } while (*s);
  793. if (!*s) {
  794. return 0;
  795. }
  796. assert(q - p < sizeof(buf));
  797. memcpy(buf, p, q-p);
  798. buf[q-p] = 0;
  799. buf[2] = s[1];
  800. p = buf;
  801. }
  802. #endif
  803. lang_cult = codeset = 0; /* Assume C and default codeset. */
  804. if (((*p == 'C') && !p[1]) || !strcmp(p, posix)) {
  805. goto FIND_LOCALE;
  806. }
  807. if ((strlen(p) > 5) && (p[5] == '.')) { /* Codeset in locale name? */
  808. /* TODO: maybe CODESET_LIST + *s ??? */
  809. /* 7bit is 1, UTF-8 is 2, 8-bit is >= 3 */
  810. codeset = 2;
  811. if (strcmp(utf8,p+6) != 0) {/* TODO - fix! */
  812. s = CODESET_LIST;
  813. do {
  814. ++codeset; /* Increment codeset first. */
  815. if (!strcmp(CODESET_LIST+*s, p+6)) {
  816. goto FIND_LANG_CULT;
  817. }
  818. } while (*++s);
  819. return 0; /* No matching codeset! */
  820. }
  821. }
  822. FIND_LANG_CULT: /* Find language_culture number. */
  823. s = LOCALE_NAMES;
  824. do { /* TODO -- do a binary search? */
  825. /* TODO -- fix gen_mmap!*/
  826. ++lang_cult; /* Increment first since C/POSIX is 0. */
  827. if (!strncmp(s,p,5)) { /* Found a matching locale name; */
  828. goto FIND_LOCALE;
  829. }
  830. s += 5;
  831. } while (lang_cult < __LOCALE_DATA_NUM_LOCALE_NAMES);
  832. return 0; /* No matching language_culture! */
  833. FIND_LOCALE: /* Find locale row matching name and codeset */
  834. s = LOCALES;
  835. n = 0;
  836. do { /* TODO -- do a binary search? */
  837. if ((lang_cult == *s) && ((codeset == s[1]) || (codeset == s[2]))) {
  838. i = 1;
  839. s = new_locale + 1;
  840. do {
  841. if (category_mask & i) {
  842. /* Encode current locale row number. */
  843. ((unsigned char *) s)[0] = (n >> 7) | 0x80;
  844. ((unsigned char *) s)[1] = (n & 0x7f) | 0x80;
  845. }
  846. s += 2;
  847. i += i;
  848. } while (i < (1 << LC_ALL));
  849. return i; /* Return non-zero */
  850. }
  851. s += __LOCALE_DATA_WIDTH_LOCALES;
  852. ++n;
  853. } while (n <= __LOCALE_DATA_NUM_LOCALES); /* We started at 1!!! */
  854. return 0; /* Unsupported locale. */
  855. }
  856. static unsigned char *composite_locale(int category_mask, const char *locale,
  857. unsigned char *new_locale)
  858. {
  859. char buf[MAX_LOCALE_STR];
  860. char *t;
  861. char *e;
  862. int c;
  863. int component_mask;
  864. if (!strchr(locale,'=')) {
  865. if (!find_locale(category_mask, locale, new_locale)) {
  866. return NULL;
  867. }
  868. return new_locale;
  869. }
  870. if (strlen(locale) >= sizeof(buf)) {
  871. return NULL;
  872. }
  873. stpcpy(buf, locale);
  874. component_mask = 0;
  875. t = strtok_r(buf, "=", &e); /* This can't fail because of strchr test above. */
  876. do {
  877. c = 0;
  878. while (strcmp(CATEGORY_NAMES + (int) CATEGORY_NAMES[c], t)) {
  879. if (++c == LC_ALL) { /* Unknown category name! */
  880. return NULL;
  881. }
  882. }
  883. t = strtok_r(NULL, ";", &e);
  884. c = (1 << c);
  885. if (component_mask & c) { /* Multiple components for one category. */
  886. return NULL;
  887. }
  888. component_mask |= c;
  889. if ((category_mask & c) && (!t || !find_locale(c, t, new_locale))) {
  890. return NULL;
  891. }
  892. } while ((t = strtok_r(NULL, "=", &e)) != NULL);
  893. if (category_mask & ~component_mask) { /* Category component(s) missing. */
  894. return NULL;
  895. }
  896. return new_locale;
  897. }
  898. __locale_t __newlocale(int category_mask, const char *locale, __locale_t base)
  899. {
  900. const unsigned char *p;
  901. int i, j, k;
  902. unsigned char new_selector[LOCALE_SELECTOR_SIZE];
  903. if (!locale || (((unsigned int)(category_mask)) > LC_ALL_MASK)) {
  904. INVALID:
  905. __set_errno(EINVAL);
  906. return NULL; /* No locale or illegal/unsupported category. */
  907. }
  908. #ifdef __UCLIBC_MJN3_ONLY__
  909. #warning TODO: Rename cur_locale to locale_selector.
  910. #endif
  911. strcpy((char *) new_selector,
  912. (base ? (char *) base->cur_locale : C_LOCALE_SELECTOR));
  913. if (!*locale) { /* locale == "", so check environment. */
  914. #ifndef __UCLIBC_HAS_THREADS__
  915. static /* If no threads, then envstr can be static. */
  916. #endif /* __UCLIBC_HAS_THREADS__ */
  917. const char *envstr[4] = { "LC_ALL", NULL, "LANG", posix };
  918. i = 1;
  919. k = 0;
  920. do {
  921. if (category_mask & i) {
  922. /* Note: SUSv3 doesn't define a fallback mechanism here.
  923. * So, if LC_ALL is invalid, we do _not_ continue trying
  924. * the other environment vars. */
  925. envstr[1] = CATEGORY_NAMES + CATEGORY_NAMES[k];
  926. j = 0;
  927. do {
  928. p = envstr[j];
  929. } while ((++j < 4) && (!(p = getenv(p)) || !*p));
  930. /* The user set something... is it valid? */
  931. /* Note: Since we don't support user-supplied locales and
  932. * alternate paths, we don't need to worry about special
  933. * handling for suid/sgid apps. */
  934. if (!find_locale(i, p, new_selector)) {
  935. goto INVALID;
  936. }
  937. }
  938. i += i;
  939. } while (++k < LC_ALL);
  940. } else if (!composite_locale(category_mask, locale, new_selector)) {
  941. goto INVALID;
  942. }
  943. #ifdef __UCLIBC_MJN3_ONLY__
  944. #warning TODO: Do a compatible codeset check!
  945. #endif
  946. /* If we get here, the new selector corresponds to a valid locale. */
  947. #ifdef __UCLIBC_MJN3_ONLY__
  948. #warning CONSIDER: Probably want a _locale_new func to allow for caching of locales.
  949. #endif
  950. #if 0
  951. if (base) {
  952. _locale_set_l(new_selector, base);
  953. } else {
  954. base = _locale_new(new_selector);
  955. }
  956. #else
  957. if (!base) {
  958. if ((base = malloc(sizeof(__uclibc_locale_t))) == NULL) {
  959. return base;
  960. }
  961. _locale_init_l(base);
  962. }
  963. _locale_set_l(new_selector, base);
  964. #endif
  965. return base;
  966. }
  967. weak_alias(__newlocale, newlocale)
  968. #endif
  969. /**********************************************************************/
  970. #ifdef L_duplocale
  971. #ifdef __UCLIBC_MJN3_ONLY__
  972. #warning REMINDER: When we allocate ctype tables, remember to dup them.
  973. #endif
  974. __locale_t duplocale(__locale_t dataset)
  975. {
  976. __locale_t r;
  977. uint16_t * i2w;
  978. assert(dataset != LC_GLOBAL_LOCALE);
  979. if ((r = malloc(sizeof(__uclibc_locale_t))) != NULL) {
  980. if ((i2w = calloc(2*dataset->collate.max_col_index+2,
  981. sizeof(uint16_t)))
  982. != NULL
  983. ) {
  984. memcpy(r, dataset, sizeof(__uclibc_locale_t));
  985. r->collate.index2weight = i2w;
  986. } else {
  987. free(r);
  988. r = NULL;
  989. }
  990. }
  991. return r;
  992. }
  993. #endif
  994. /**********************************************************************/
  995. #ifdef L_freelocale
  996. #ifdef __UCLIBC_MJN3_ONLY__
  997. #warning REMINDER: When we allocate ctype tables, remember to free them.
  998. #endif
  999. void freelocale(__locale_t dataset)
  1000. {
  1001. assert(dataset != __global_locale);
  1002. assert(dataset != LC_GLOBAL_LOCALE);
  1003. free(dataset->collate.index2weight); /* Free collation data. */
  1004. free(dataset); /* Free locale */
  1005. }
  1006. #endif
  1007. /**********************************************************************/
  1008. #ifdef L_uselocale
  1009. __locale_t uselocale(__locale_t dataset)
  1010. {
  1011. __locale_t old;
  1012. if (!dataset) {
  1013. old = __UCLIBC_CURLOCALE;
  1014. } else {
  1015. if (dataset == LC_GLOBAL_LOCALE) {
  1016. dataset = __global_locale;
  1017. }
  1018. #ifdef __UCLIBC_HAS_THREADS__
  1019. old = __curlocale_set(dataset);
  1020. #else
  1021. old = __curlocale_var;
  1022. __curlocale_var = dataset;
  1023. #endif
  1024. }
  1025. if (old == __global_locale) {
  1026. return LC_GLOBAL_LOCALE;
  1027. }
  1028. return old;
  1029. }
  1030. #endif
  1031. /**********************************************************************/
  1032. #ifdef L___curlocale
  1033. #ifdef __UCLIBC_HAS_THREADS__
  1034. __locale_t weak_const_function __curlocale(void)
  1035. {
  1036. return __curlocale_var; /* This is overriden by the thread version. */
  1037. }
  1038. __locale_t weak_function __curlocale_set(__locale_t newloc)
  1039. {
  1040. assert(newloc != LC_GLOBAL_LOCALE);
  1041. __locale_t oldloc = __curlocale_var;
  1042. __curlocale_var = newloc;
  1043. return oldloc;
  1044. }
  1045. #endif
  1046. #endif
  1047. /**********************************************************************/
  1048. #ifdef L___locale_mbrtowc_l
  1049. /* NOTE: This returns an int... not size_t. Also, it is not a general
  1050. * routine. It is actually a very stripped-down version of mbrtowc
  1051. * that takes a __locale_t arg. This is used by strcoll and strxfrm.
  1052. * It is also used above to generate wchar_t versions of the decimal point
  1053. * and thousands seperator. */
  1054. #ifndef __CTYPE_HAS_UTF_8_LOCALES
  1055. #warning __CTYPE_HAS_UTF_8_LOCALES not set!
  1056. #endif
  1057. #ifndef __CTYPE_HAS_8_BIT_LOCALES
  1058. #warning __CTYPE_HAS_8_BIT_LOCALES not set!
  1059. #endif
  1060. #define Cc2wc_IDX_SHIFT __LOCALE_DATA_Cc2wc_IDX_SHIFT
  1061. #define Cc2wc_ROW_LEN __LOCALE_DATA_Cc2wc_ROW_LEN
  1062. extern size_t _wchar_utf8sntowcs(wchar_t *__restrict pwc, size_t wn,
  1063. const char **__restrict src, size_t n,
  1064. mbstate_t *ps, int allow_continuation);
  1065. int __locale_mbrtowc_l(wchar_t *__restrict dst,
  1066. const char *__restrict src,
  1067. __locale_t loc )
  1068. {
  1069. #ifdef __CTYPE_HAS_UTF_8_LOCALES
  1070. if (loc->encoding == __ctype_encoding_utf8) {
  1071. mbstate_t ps;
  1072. const char *p = src;
  1073. size_t r;
  1074. ps.mask = 0;
  1075. r = _wchar_utf8sntowcs(dst, 1, &p, SIZE_MAX, &ps, 1);
  1076. return (r == 1) ? (p-src) : r; /* Need to return 0 if nul char. */
  1077. }
  1078. #endif
  1079. #ifdef __CTYPE_HAS_8_BIT_LOCALES
  1080. assert((loc->encoding == __ctype_encoding_7_bit) || (loc->encoding == __ctype_encoding_8_bit));
  1081. #else
  1082. assert(loc->encoding == __ctype_encoding_7_bit);
  1083. #endif
  1084. if ((*dst = ((unsigned char)(*src))) < 0x80) { /* ASCII... */
  1085. return (*src != 0);
  1086. }
  1087. #ifdef __CTYPE_HAS_8_BIT_LOCALES
  1088. if (loc->encoding == __ctype_encoding_8_bit) {
  1089. wchar_t wc = *dst - 0x80;
  1090. *dst = __LOCALE_PTR->tbl8c2wc[
  1091. (__LOCALE_PTR->idx8c2wc[wc >> Cc2wc_IDX_SHIFT]
  1092. << Cc2wc_IDX_SHIFT) + (wc & (Cc2wc_ROW_LEN - 1))];
  1093. if (*dst) {
  1094. return 1;
  1095. }
  1096. }
  1097. #endif
  1098. return -1;
  1099. }
  1100. #endif
  1101. /**********************************************************************/