locale.c 41 KB

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