locale.c 40 KB

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