locale.c 43 KB

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