_collate.c 17 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673
  1. /*
  2. * Copyright (C) 2002 Manuel Novoa III
  3. * Copyright (C) 2000-2005 Erik Andersen <andersen@uclibc.org>
  4. *
  5. * Licensed under the LGPL v2.1, see the file COPYING.LIB in this tarball.
  6. */
  7. /* Dec 20, 2002
  8. * Initial test implementation of strcoll, strxfrm, wcscoll, and wcsxfrm.
  9. * The code needs to be cleaned up a good bit, but I'd like to see people
  10. * test it out.
  11. *
  12. */
  13. #include "_string.h"
  14. #include <ctype.h>
  15. #include <locale.h>
  16. #include <stdlib.h>
  17. #include <errno.h>
  18. #include <assert.h>
  19. #ifdef __UCLIBC_HAS_LOCALE__
  20. #if defined(L_strxfrm) || defined(L_strxfrm_l) || defined(L_wcsxfrm) || defined(L_wcsxfrm_l)
  21. #ifdef L_strxfrm
  22. #ifndef WANT_WIDE
  23. #error WANT_WIDE should be defined for L_strxfrm
  24. #endif
  25. #ifdef L_wcsxfrm
  26. #error L_wcsxfrm already defined for L_strxfrm
  27. #endif
  28. #endif /* L_strxfrm */
  29. #if defined(L_strxfrm) || defined(L_strxfrm_l)
  30. #define wcscoll strcoll
  31. #define wcscoll_l strcoll_l
  32. #define wcsxfrm strxfrm
  33. #define wcsxfrm_l strxfrm_l
  34. #undef WANT_WIDE
  35. #undef Wvoid
  36. #undef Wchar
  37. #undef Wuchar
  38. #undef Wint
  39. #define Wchar char
  40. #endif /* defined(L_strxfrm) || defined(L_strxfrm_l) */
  41. #if defined(__UCLIBC_HAS_XLOCALE__) && !defined(__UCLIBC_DO_XLOCALE)
  42. int wcscoll (const Wchar *s0, const Wchar *s1)
  43. {
  44. return wcscoll_l(s0, s1, __UCLIBC_CURLOCALE );
  45. }
  46. libc_hidden_def(wcscoll)
  47. size_t wcsxfrm(Wchar *__restrict ws1, const Wchar *__restrict ws2, size_t n)
  48. {
  49. return wcsxfrm_l(ws1, ws2, n, __UCLIBC_CURLOCALE );
  50. }
  51. libc_hidden_def(wcsxfrm)
  52. #else /* defined(__UCLIBC_HAS_XLOCALE__) && !defined(__UCLIBC_DO_XLOCALE) */
  53. #if 0
  54. #define CUR_COLLATE (&__UCLIBC_CURLOCALE->collate)
  55. #else
  56. #define CUR_COLLATE (& __LOCALE_PTR->collate)
  57. #endif
  58. #define MAX_PENDING 8
  59. typedef struct {
  60. const Wchar *s;
  61. const Wchar *eob; /* end of backward */
  62. __uwchar_t weight;
  63. __uwchar_t ui_weight; /* undefined or invalid */
  64. int colitem;
  65. int weightidx;
  66. int rule;
  67. size_t position;
  68. /* should be wchar_t. if wchar < 0 do EILSEQ? */
  69. __uwchar_t *cip;
  70. __uwchar_t ci_pending[MAX_PENDING]; /* nul-terminated */
  71. char *back_buf;
  72. char *bbe; /* end of back_buf (actual last... not 1 past end) */
  73. char *bp; /* ptr into backbuf, NULL if not in backward mode */
  74. char ibb[128];
  75. size_t bb_size;
  76. int ru_pushed;
  77. } col_state_t;
  78. #define WEIGHT_MASK 0x3fffU
  79. #define RULE_MASK 0xc000U
  80. #define RULE_FORWARD (1 << 14)
  81. #define RULE_POSITION (1 << 15)
  82. #define UI_IDX (WEIGHT_MASK-6)
  83. #define POSIT_IDX (WEIGHT_MASK-5)
  84. #define RANGE_IDX (WEIGHT_MASK-4)
  85. #define UNDEF_IDX (WEIGHT_MASK-3)
  86. #define INVAL_IDX (WEIGHT_MASK-2)
  87. #define DITTO_IDX (WEIGHT_MASK-1)
  88. #undef TRACE
  89. #if 0
  90. #define TRACE(X) printf X
  91. #else
  92. #define TRACE(X) ((void)0)
  93. #endif
  94. static int lookup(wchar_t wc __LOCALE_PARAM )
  95. {
  96. unsigned int sc, n, i0, i1;
  97. if (((__uwchar_t) wc) > 0xffffU) {
  98. return 0;
  99. }
  100. sc = wc & CUR_COLLATE->ti_mask;
  101. wc >>= CUR_COLLATE->ti_shift;
  102. n = wc & CUR_COLLATE->ii_mask;
  103. wc >>= CUR_COLLATE->ii_shift;
  104. i0 = CUR_COLLATE->wcs2colidt_tbl[wc];
  105. i0 <<= CUR_COLLATE->ii_shift;
  106. i1 = CUR_COLLATE->wcs2colidt_tbl[CUR_COLLATE->ii_len + i0 + n];
  107. i1 <<= CUR_COLLATE->ti_shift;
  108. return CUR_COLLATE->wcs2colidt_tbl[CUR_COLLATE->ii_len + CUR_COLLATE->ti_len + i1 + sc];
  109. }
  110. static void init_col_state(col_state_t *cs, const Wchar *wcs)
  111. {
  112. memset(cs, 0, sizeof(col_state_t));
  113. cs->s = wcs;
  114. cs->bp = cs->back_buf = cs->ibb;
  115. cs->bb_size = 128;
  116. cs->bbe = cs->back_buf + (cs->bb_size -1);
  117. }
  118. static void next_weight(col_state_t *cs, int pass __LOCALE_PARAM )
  119. {
  120. int r, w, ru, ri, popping_backup_stack;
  121. ssize_t n;
  122. const uint16_t *p;
  123. #ifdef WANT_WIDE
  124. #define WC (*cs->s)
  125. #define N (1)
  126. #else /* WANT_WIDE */
  127. wchar_t WC;
  128. size_t n0, nx;
  129. #define N n0
  130. #endif /* WANT_WIDE */
  131. do {
  132. if (cs->ru_pushed) {
  133. ru = cs->ru_pushed;
  134. TRACE(("ru_pushed = %d\n", ru));
  135. cs->ru_pushed = 0;
  136. goto POSITION_SKIP;
  137. }
  138. #ifdef __UCLIBC_MJN3_ONLY__
  139. #warning should we walk pendings backwards?
  140. #endif
  141. if (cs->cip) { /* possible pending weight */
  142. if ((r = *(cs->cip++)) == 0) {
  143. cs->cip = NULL;
  144. continue;
  145. }
  146. cs->weightidx = r & WEIGHT_MASK;
  147. assert(cs->weightidx);
  148. /* assert(cs->weightidx != WEIGHT_MASK); */
  149. } else { /* get the next collation item from the string */
  150. TRACE(("clearing popping flag\n"));
  151. popping_backup_stack = 0;
  152. IGNORE_LOOP:
  153. /* keep first pos as 0 for a sentinal */
  154. if (*cs->bp) { /* pending backward chars */
  155. POP_BACKUP:
  156. popping_backup_stack = 1;
  157. TRACE(("setting popping flag\n"));
  158. n = 0;
  159. if (*cs->bp > 0) { /* singles pending */
  160. cs->s -= 1;
  161. if ((*cs->bp -= 1) == 0) {
  162. cs->bp -= 1;
  163. }
  164. } else { /* last was a multi */
  165. cs->s += *cs->bp;
  166. cs->bp -= 1;
  167. }
  168. } else if (!*cs->s) { /* not in backward mode and end of string */
  169. cs->weight = 0;
  170. return;
  171. } else {
  172. cs->position += 1;
  173. }
  174. BACK_LOOP:
  175. #ifdef WANT_WIDE
  176. n = 1;
  177. cs->colitem = r = lookup(*cs->s __LOCALE_ARG );
  178. #else /* WANT_WIDE */
  179. n = n0 = __locale_mbrtowc_l(&WC, cs->s, __LOCALE_PTR);
  180. if (n < 0) {
  181. __set_errno(EILSEQ);
  182. cs->weight = 0;
  183. return;
  184. }
  185. cs->colitem = r = lookup(WC __LOCALE_ARG );
  186. #endif /* WANT_WIDE */
  187. TRACE((" r=%d WC=%#lx\n", r, (unsigned long)(WC)));
  188. if (r > CUR_COLLATE->max_col_index) { /* starting char for one or more sequences */
  189. p = CUR_COLLATE->multistart_tbl;
  190. p += p[r-CUR_COLLATE->max_col_index -1];
  191. do {
  192. n = N;
  193. r = *p++;
  194. do {
  195. if (!*p) { /* found it */
  196. cs->colitem = r;
  197. TRACE((" found multi %d\n", n));
  198. goto FOUND;
  199. }
  200. #ifdef WANT_WIDE
  201. /* the lookup check here is safe since we're assured that *p is a valid colidx */
  202. if (!cs->s[n] || (lookup(cs->s[n] __LOCALE_ARG ) != *p)) {
  203. do {} while (*p++);
  204. break;
  205. }
  206. ++p;
  207. ++n;
  208. #else /* WANT_WIDE */
  209. if (cs->s[n]) {
  210. nx = __locale_mbrtowc_l(&WC, cs->s + n, __LOCALE_PTR);
  211. if (nx < 0) {
  212. __set_errno(EILSEQ);
  213. cs->weight = 0;
  214. return;
  215. }
  216. }
  217. if (!cs->s[n] || (lookup(WC __LOCALE_ARG ) != *p)) {
  218. do {} while (*p++);
  219. break;
  220. }
  221. ++p;
  222. n += nx; /* Only gets here if cs->s[n] != 0, so nx is set. */
  223. #endif /* WANT_WIDE */
  224. } while (1);
  225. } while (1);
  226. } else if (r == 0) { /* illegal, undefined, or part of a range */
  227. if ((CUR_COLLATE->range_count)
  228. #ifdef __UCLIBC_MJN3_ONLY__
  229. #warning .. need to introduce range as a collating item?
  230. #endif
  231. && (((__uwchar_t)(WC - CUR_COLLATE->range_low)) <= CUR_COLLATE->range_count)
  232. ) { /* part of a range */
  233. /* Note: cs->colitem = 0 already. */
  234. TRACE((" found range\n"));
  235. ru = CUR_COLLATE->ruletable[CUR_COLLATE->range_rule_offset*CUR_COLLATE->MAX_WEIGHTS + pass];
  236. assert((ru & WEIGHT_MASK) != DITTO_IDX);
  237. if ((ru & WEIGHT_MASK) == WEIGHT_MASK) {
  238. ru = (ru & RULE_MASK) | RANGE_IDX;
  239. cs->weight = CUR_COLLATE->range_base_weight + (WC - CUR_COLLATE->range_low);
  240. }
  241. goto RANGE_SKIP_TO;
  242. } else if (((__uwchar_t)(WC)) <= 0x7fffffffUL) { /* legal but undefined */
  243. UNDEFINED:
  244. /* Note: cs->colitem = 0 already. */
  245. ri = CUR_COLLATE->undefined_idx;
  246. assert(ri != 0); /* implicit undefined isn't supported */
  247. TRACE((" found explicit UNDEFINED\n"));
  248. #ifdef __UCLIBC_MJN3_ONLY__
  249. #warning right now single weight locales do not support ..
  250. #endif
  251. if (CUR_COLLATE->num_weights == 1) {
  252. TRACE((" single weight UNDEFINED\n"));
  253. cs->weightidx = RANGE_IDX;
  254. cs->weight = ri;
  255. cs->s += n;
  256. goto PROCESS_WEIGHT;
  257. }
  258. ri = CUR_COLLATE->index2ruleidx[ri - 1];
  259. ru = CUR_COLLATE->ruletable[ri * CUR_COLLATE->MAX_WEIGHTS + pass];
  260. assert((ru & WEIGHT_MASK) != WEIGHT_MASK); /* TODO: handle ".." */
  261. if ((ru & WEIGHT_MASK) == DITTO_IDX) {
  262. cs->colitem = CUR_COLLATE->undefined_idx;
  263. }
  264. goto RANGE_SKIP_TO;
  265. } else { /* illegal */
  266. TRACE((" found illegal\n"));
  267. __set_errno(EINVAL);
  268. /* We put all illegals in the same equiv class with maximal weight,
  269. * and ignore them after the first pass. */
  270. if (pass > 0) {
  271. cs->s += n;
  272. goto IGNORE_LOOP;
  273. }
  274. ru = (RULE_FORWARD | RANGE_IDX);
  275. cs->weight = 0xffffU;
  276. goto RANGE_SKIP_TO;
  277. }
  278. } else if (CUR_COLLATE->num_weights == 1) {
  279. TRACE((" single weight\n"));
  280. cs->weightidx = RANGE_IDX;
  281. cs->weight = cs->colitem;
  282. cs->s += n;
  283. goto PROCESS_WEIGHT;
  284. } else {
  285. TRACE((" normal\n"));
  286. }
  287. /* if we get here, it is a normal char either singlely weighted, undefined, or in a range */
  288. FOUND:
  289. ri = CUR_COLLATE->index2ruleidx[cs->colitem - 1];
  290. TRACE((" ri=%d ", ri));
  291. #ifdef __UCLIBC_MJN3_ONLY__
  292. #warning make sure this is correct
  293. #endif
  294. if (!ri) {
  295. TRACE(("NOT IN THIS LOCALE\n"));
  296. goto UNDEFINED;
  297. }
  298. ru = CUR_COLLATE->ruletable[ri * CUR_COLLATE->MAX_WEIGHTS + pass];
  299. RANGE_SKIP_TO:
  300. #ifdef __UCLIBC_MJN3_ONLY__
  301. #warning ignoreables probably should not interrupt backwards processing, but this is wrong
  302. #endif
  303. /* if (!(ru & WEIGHT_MASK)) { */
  304. /* TRACE(("IGNORE\n")); */
  305. /* cs->s += n; */
  306. /* continue; */
  307. /* } */
  308. TRACE((" rule = %#x weight = %#x popping = %d s = %p eob = %p\n",
  309. ru & RULE_MASK, ru & WEIGHT_MASK, popping_backup_stack,
  310. cs->s, cs->eob));
  311. /* now we need to check if we're going backwards... */
  312. if (!popping_backup_stack) {
  313. if (!(ru & RULE_MASK)) { /* backward */
  314. TRACE(("backwards\n"));
  315. assert(cs->bp <= cs->bbe);
  316. if (cs->bp == cs->bbe) {
  317. if (cs->back_buf == cs->ibb) { /* was using internal buffer */
  318. cs->bp = malloc(cs->bb_size + 128);
  319. if (!cs->bp) {
  320. __set_errno(ENOMEM);
  321. #ifdef __UCLIBC_MJN3_ONLY__
  322. #warning what to do here?
  323. #endif
  324. cs->weight = 0;
  325. return;
  326. }
  327. memcpy(cs->bp, cs->back_buf, cs->bb_size);
  328. } else {
  329. cs->bp = realloc(cs->back_buf, cs->bb_size + 128);
  330. if (!cs->bp) {
  331. __set_errno(ENOMEM);
  332. #ifdef __UCLIBC_MJN3_ONLY__
  333. #warning what to do here?
  334. #endif
  335. cs->weight = 0;
  336. return;
  337. }
  338. }
  339. cs->bb_size += 128;
  340. cs->bbe = cs->bp + (cs->bbe - cs->back_buf);
  341. cs->back_buf = cs->bp;
  342. cs->bp = cs->bbe;
  343. }
  344. if (n==1) { /* single char */
  345. if (*cs->bp && (((unsigned char)(*cs->bp)) < CHAR_MAX)) {
  346. *cs->bp += 1; /* increment last single's count */
  347. } else { /* last was a multi, or just starting */
  348. if (!cs->bp) {
  349. cs->bp = cs->back_buf;
  350. } else {
  351. assert(cs->bp < cs->bbe);
  352. ++cs->bp;
  353. }
  354. *cs->bp = 1;
  355. }
  356. } else { /* multichar */
  357. assert(n>1);
  358. assert(cs->bp < cs->bbe);
  359. *++cs->bp = -n;
  360. }
  361. cs->s += n;
  362. if (*cs->s) {
  363. goto BACK_LOOP;
  364. }
  365. /* end-of-string so start popping */
  366. cs->eob = cs->s;
  367. TRACE(("popping\n"));
  368. goto POP_BACKUP;
  369. } else if (*cs->bp) { /* was going backward but this element isn't */
  370. /* discard current and use previous backward element */
  371. assert(!cs->cip);
  372. cs->eob = cs->s;
  373. TRACE(("popping\n"));
  374. goto POP_BACKUP;
  375. } else { /* was and still going forward */
  376. TRACE(("forwards\n"));
  377. if ((ru & (RULE_POSITION|WEIGHT_MASK)) > RULE_POSITION) {
  378. assert(ru & WEIGHT_MASK);
  379. cs->ru_pushed = ru;
  380. cs->weight = cs->position;
  381. #ifdef __UCLIBC_MJN3_ONLY__
  382. #warning devel code
  383. #endif
  384. cs->position = 0; /* reset to reduce size for strcoll? */
  385. cs->s += n;
  386. cs->weightidx = RANGE_IDX;
  387. goto PROCESS_WEIGHT;
  388. }
  389. }
  390. } else { /* popping backwards stack */
  391. TRACE(("popping (continued)\n"));
  392. if (!*cs->bp) {
  393. cs->s = cs->eob;
  394. }
  395. cs->s -= n;
  396. }
  397. cs->s += n;
  398. POSITION_SKIP:
  399. cs->weightidx = ru & WEIGHT_MASK;
  400. cs->rule = ru & RULE_MASK;
  401. }
  402. #ifdef __UCLIBC_MJN3_ONLY__
  403. #warning for pending we only want the weight... _not_ the rule
  404. #endif
  405. if (!cs->weightidx) { /* ignore */
  406. continue;
  407. }
  408. PROCESS_WEIGHT:
  409. assert(cs->weightidx);
  410. if (((unsigned int)(cs->weightidx - UI_IDX)) <= (INVAL_IDX-UI_IDX)) {
  411. if (cs->weightidx == UI_IDX) {
  412. cs->weight = cs->ui_weight;
  413. }
  414. return;
  415. }
  416. assert(cs->weightidx != WEIGHT_MASK);
  417. if (cs->weightidx == DITTO_IDX) { /* want the weight of the current collating item */
  418. TRACE(("doing ditto\n"));
  419. w = CUR_COLLATE->index2weight[cs->colitem -1];
  420. } else if (cs->weightidx <= CUR_COLLATE->max_col_index) { /* normal */
  421. TRACE(("doing normal\n"));
  422. w = CUR_COLLATE->index2weight[cs->weightidx -1];
  423. } else { /* a string */
  424. TRACE(("doing string\n"));
  425. assert(!(cs->weightidx & RULE_MASK));
  426. /* note: iso14561 allows null string here */
  427. p = CUR_COLLATE->weightstr + (cs->weightidx - (CUR_COLLATE->max_col_index + 2));
  428. if (*p & WEIGHT_MASK) {
  429. r = 0;
  430. do {
  431. assert(r < MAX_PENDING);
  432. cs->ci_pending[r++] = *p++;
  433. } while (*p & WEIGHT_MASK);
  434. cs->cip = cs->ci_pending;
  435. }
  436. continue;
  437. }
  438. cs->weight = w;
  439. return;
  440. } while (1);
  441. }
  442. libc_hidden_proto(__XL_NPP(wcscoll))
  443. int __XL_NPP(wcscoll) (const Wchar *s0, const Wchar *s1 __LOCALE_PARAM )
  444. {
  445. col_state_t ws[2];
  446. int pass;
  447. if (!CUR_COLLATE->num_weights) { /* C locale */
  448. #ifdef WANT_WIDE
  449. return wcscmp(s0, s1);
  450. #else
  451. return strcmp(s0, s1);
  452. #endif
  453. }
  454. pass = 0;
  455. do { /* loop through the weights levels */
  456. init_col_state(ws, s0);
  457. init_col_state(ws+1, s1);
  458. do { /* loop through the strings */
  459. /* for each string, get the next weight */
  460. next_weight(ws, pass __LOCALE_ARG );
  461. next_weight(ws+1, pass __LOCALE_ARG );
  462. TRACE(("w0=%lu w1=%lu\n",
  463. (unsigned long) ws[0].weight,
  464. (unsigned long) ws[1].weight));
  465. if (ws[0].weight != ws[1].weight) {
  466. return ws[0].weight - ws[1].weight;
  467. }
  468. } while (ws[0].weight);
  469. } while (++pass < CUR_COLLATE->num_weights);
  470. return 0;
  471. }
  472. libc_hidden_def(__XL_NPP(wcscoll))
  473. #ifdef WANT_WIDE
  474. extern size_t __wcslcpy(wchar_t *__restrict dst,
  475. const wchar_t *__restrict src, size_t n);
  476. libc_hidden_proto(__XL_NPP(wcsxfrm))
  477. size_t __XL_NPP(wcsxfrm)(wchar_t *__restrict ws1, const wchar_t *__restrict ws2,
  478. size_t n __LOCALE_PARAM )
  479. {
  480. col_state_t cs;
  481. size_t count;
  482. int pass;
  483. if (!CUR_COLLATE->num_weights) { /* C locale */
  484. return __wcslcpy(ws1, ws2, n);
  485. }
  486. #ifdef __UCLIBC_MJN3_ONLY__
  487. #warning handle empty string as a special case
  488. #endif
  489. count = pass = 0;
  490. do { /* loop through the weights levels */
  491. init_col_state(&cs, ws2);
  492. do { /* loop through the string */
  493. next_weight(&cs, pass __LOCALE_ARG );
  494. TRACE(("weight=%lu (%#lx)\n", (unsigned long) cs.weight, (unsigned long) cs.weight));
  495. if (count < n) {
  496. ws1[count] = cs.weight +1;
  497. }
  498. ++count;
  499. TRACE(("--------------------------------------------\n"));
  500. } while (cs.weight);
  501. if (count <= n) { /* overwrite the trailing 0 end-of-pass marker */
  502. ws1[count-1] = 1;
  503. }
  504. TRACE(("-------------------- pass %d --------------------\n", pass));
  505. } while (++pass < CUR_COLLATE->num_weights);
  506. if (count <= n) { /* oops... change it back */
  507. ws1[count-1] = 0;
  508. }
  509. return count-1;
  510. }
  511. libc_hidden_def(__XL_NPP(wcsxfrm))
  512. #else /* WANT_WIDE */
  513. static const unsigned long bound[] = {
  514. 1UL << 7,
  515. 1UL << 11,
  516. 1UL << 16,
  517. 1UL << 21,
  518. 1UL << 26,
  519. };
  520. static unsigned char first[] = {
  521. 0x0, 0xc0, 0xe0, 0xf0, 0xf8, 0xfc
  522. };
  523. /* Use an extension of UTF-8 to store a 32 bit val in max 6 bytes. */
  524. static size_t store(unsigned char *s, size_t count, size_t n, __uwchar_t weight)
  525. {
  526. int i, r;
  527. i = 0;
  528. do {
  529. if (weight < bound[i]) {
  530. break;
  531. }
  532. } while (++i < sizeof(bound)/sizeof(bound[0]));
  533. r = i+1;
  534. if (i + count < n) {
  535. s += count;
  536. s[0] = first[i];
  537. while (i) {
  538. s[i] = 0x80 | (weight & 0x3f);
  539. weight >>= 6;
  540. --i;
  541. }
  542. s[0] |= weight;
  543. }
  544. return r;
  545. }
  546. libc_hidden_proto(__XL_NPP(strxfrm))
  547. size_t __XL_NPP(strxfrm)(char *__restrict ws1, const char *__restrict ws2, size_t n
  548. __LOCALE_PARAM )
  549. {
  550. col_state_t cs;
  551. size_t count, inc;
  552. int pass;
  553. if (!CUR_COLLATE->num_weights) { /* C locale */
  554. return strlcpy(ws1, ws2, n);
  555. }
  556. #ifdef __UCLIBC_MJN3_ONLY__
  557. #warning handle empty string as a special case
  558. #endif
  559. inc = count = pass = 0;
  560. do { /* loop through the weights levels */
  561. init_col_state(&cs, ws2);
  562. do { /* loop through the string */
  563. next_weight(&cs, pass __LOCALE_ARG );
  564. TRACE(("weight=%lu (%#lx)\n", (unsigned long) cs.weight, (unsigned long) cs.weight));
  565. inc = store((unsigned char *)ws1, count, n, cs.weight + 1);
  566. count += inc;
  567. TRACE(("--------------------------------------------\n"));
  568. } while (cs.weight);
  569. /* overwrite the trailing 0 end-of-pass marker */
  570. assert(inc == 1);
  571. if (count <= n) {
  572. ws1[count-1] = 1;
  573. }
  574. TRACE(("-------------------- pass %d --------------------\n", pass));
  575. } while (++pass < CUR_COLLATE->num_weights);
  576. if (count <= n) { /* oops... change it back */
  577. ws1[count-1] = 0;
  578. }
  579. return count-1;
  580. }
  581. libc_hidden_def(__XL_NPP(strxfrm))
  582. #endif /* WANT_WIDE */
  583. #endif /* defined(__UCLIBC_HAS_XLOCALE__) && !defined(__UCLIBC_DO_XLOCALE) */
  584. #endif /* defined(L_strxfrm) || defined(L_strxfrm_l) || defined(L_wcsxfrm) || defined(L_wcsxfrm_l) */
  585. #endif /* __UCLIBC_HAS_LOCALE__ */
  586. /**********************************************************************/