strxfrm_l.c 18 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746
  1. /* Copyright (C) 1995-2026 Free Software Foundation, Inc.
  2. This file is part of the GNU C Library.
  3. The GNU C Library is free software; you can redistribute it and/or
  4. modify it under the terms of the GNU Lesser General Public
  5. License as published by the Free Software Foundation; either
  6. version 2.1 of the License, or (at your option) any later version.
  7. The GNU C Library is distributed in the hope that it will be useful,
  8. but WITHOUT ANY WARRANTY; without even the implied warranty of
  9. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
  10. Lesser General Public License for more details.
  11. You should have received a copy of the GNU Lesser General Public
  12. License along with the GNU C Library; if not, see
  13. <https://www.gnu.org/licenses/>. */
  14. #include <assert.h>
  15. #include <langinfo.h>
  16. #include <locale.h>
  17. #include <stddef.h>
  18. #include <stdint.h>
  19. #include <stdlib.h>
  20. #include <string.h>
  21. #include <sys/param.h>
  22. #ifndef STRING_TYPE
  23. # define STRING_TYPE char
  24. # define USTRING_TYPE unsigned char
  25. # define STRXFRM __strxfrm_l
  26. # define STRLEN strlen
  27. # define STPNCPY __stpncpy
  28. # define WEIGHT_H "../locale/weight.h"
  29. # define SUFFIX MB
  30. # define L(arg) arg
  31. #endif
  32. #define CONCAT(a,b) CONCAT1(a,b)
  33. #define CONCAT1(a,b) a##b
  34. /* Maximum string size that is calculated with cached indices. Right now this
  35. is an arbitrary value open to optimizations. SMALL_STR_SIZE * 4 has to be
  36. lower than __MAX_ALLOCA_CUTOFF. Keep localedata/xfrm-test.c in sync. */
  37. #define SMALL_STR_SIZE 4095
  38. #include "../locale/localeinfo.h"
  39. #include WEIGHT_H
  40. /* Group locale data for shorter parameter lists. */
  41. typedef struct
  42. {
  43. uint32_t nrules;
  44. unsigned char *rulesets;
  45. USTRING_TYPE *weights;
  46. int32_t *table;
  47. USTRING_TYPE *extra;
  48. int32_t *indirect;
  49. } locale_data_t;
  50. #ifndef WIDE_CHAR_VERSION
  51. /* We need UTF-8 encoding of numbers. */
  52. static int
  53. utf8_encode (char *buf, int val)
  54. {
  55. int retval;
  56. if (val < 0x80)
  57. {
  58. *buf++ = (char) val;
  59. retval = 1;
  60. }
  61. else
  62. {
  63. int step;
  64. for (step = 2; step < 6; ++step)
  65. if ((val & (~(uint32_t)0 << (5 * step + 1))) == 0)
  66. break;
  67. retval = step;
  68. *buf = (unsigned char) (~0xff >> step);
  69. --step;
  70. do
  71. {
  72. buf[step] = 0x80 | (val & 0x3f);
  73. val >>= 6;
  74. }
  75. while (--step > 0);
  76. *buf |= val;
  77. }
  78. return retval;
  79. }
  80. #endif
  81. /* Find next weight and rule index. Inlined since called for every char. */
  82. static __always_inline size_t
  83. find_idx (const USTRING_TYPE **us, int32_t *weight_idx,
  84. unsigned char *rule_idx, const locale_data_t *l_data, const int pass)
  85. {
  86. int32_t tmp = findidx (l_data->table, l_data->indirect, l_data->extra, us,
  87. -1);
  88. *rule_idx = tmp >> 24;
  89. int32_t idx = tmp & 0xffffff;
  90. size_t len = l_data->weights[idx++];
  91. /* Skip over indices of previous levels. */
  92. for (int i = 0; i < pass; i++)
  93. {
  94. idx += len;
  95. len = l_data->weights[idx++];
  96. }
  97. *weight_idx = idx;
  98. return len;
  99. }
  100. static int
  101. find_position (const USTRING_TYPE *us, const locale_data_t *l_data,
  102. const int pass)
  103. {
  104. int32_t weight_idx;
  105. unsigned char rule_idx;
  106. const USTRING_TYPE *usrc = us;
  107. find_idx (&usrc, &weight_idx, &rule_idx, l_data, pass);
  108. return l_data->rulesets[rule_idx * l_data->nrules + pass] & sort_position;
  109. }
  110. /* Do the transformation. */
  111. static size_t
  112. do_xfrm (const USTRING_TYPE *usrc, STRING_TYPE *dest, size_t n,
  113. const locale_data_t *l_data)
  114. {
  115. int32_t weight_idx;
  116. unsigned char rule_idx;
  117. uint32_t pass;
  118. size_t needed = 0;
  119. size_t last_needed;
  120. /* Now the passes over the weights. */
  121. for (pass = 0; pass < l_data->nrules; ++pass)
  122. {
  123. size_t backw_len = 0;
  124. last_needed = needed;
  125. const USTRING_TYPE *cur = usrc;
  126. const USTRING_TYPE *backw_start = NULL;
  127. /* We assume that if a rule has defined `position' in one section
  128. this is true for all of them. */
  129. int position = find_position (cur, l_data, pass);
  130. if (position == 0)
  131. {
  132. while (*cur != L('\0'))
  133. {
  134. const USTRING_TYPE *pos = cur;
  135. size_t len = find_idx (&cur, &weight_idx, &rule_idx, l_data,
  136. pass);
  137. int rule = l_data->rulesets[rule_idx * l_data->nrules + pass];
  138. if ((rule & sort_forward) != 0)
  139. {
  140. /* Handle the pushed backward sequence. */
  141. if (backw_start != NULL)
  142. {
  143. for (size_t i = backw_len; i > 0; )
  144. {
  145. int32_t weight_idx;
  146. unsigned char rule_idx;
  147. size_t len = find_idx (&backw_start, &weight_idx,
  148. &rule_idx, l_data, pass);
  149. if (needed + i < n)
  150. for (size_t j = len; j > 0; j--)
  151. dest[needed + i - j] =
  152. l_data->weights[weight_idx++];
  153. i -= len;
  154. }
  155. needed += backw_len;
  156. backw_start = NULL;
  157. backw_len = 0;
  158. }
  159. /* Now handle the forward element. */
  160. if (needed + len < n)
  161. while (len-- > 0)
  162. dest[needed++] = l_data->weights[weight_idx++];
  163. else
  164. /* No more characters fit into the buffer. */
  165. needed += len;
  166. }
  167. else
  168. {
  169. /* Remember start of the backward sequence & track length. */
  170. if (backw_start == NULL)
  171. backw_start = pos;
  172. backw_len += len;
  173. }
  174. }
  175. /* Handle the pushed backward sequence. */
  176. if (backw_start != NULL)
  177. {
  178. for (size_t i = backw_len; i > 0; )
  179. {
  180. size_t len = find_idx (&backw_start, &weight_idx, &rule_idx,
  181. l_data, pass);
  182. if (needed + i < n)
  183. for (size_t j = len; j > 0; j--)
  184. dest[needed + i - j] =
  185. l_data->weights[weight_idx++];
  186. i -= len;
  187. }
  188. needed += backw_len;
  189. }
  190. }
  191. else
  192. {
  193. int val = 1;
  194. #ifndef WIDE_CHAR_VERSION
  195. char buf[7];
  196. size_t buflen;
  197. #endif
  198. size_t i;
  199. while (*cur != L('\0'))
  200. {
  201. const USTRING_TYPE *pos = cur;
  202. size_t len = find_idx (&cur, &weight_idx, &rule_idx, l_data,
  203. pass);
  204. int rule = l_data->rulesets[rule_idx * l_data->nrules + pass];
  205. if ((rule & sort_forward) != 0)
  206. {
  207. /* Handle the pushed backward sequence. */
  208. if (backw_start != NULL)
  209. {
  210. for (size_t p = backw_len; p > 0; p--)
  211. {
  212. size_t len;
  213. int32_t weight_idx;
  214. unsigned char rule_idx;
  215. const USTRING_TYPE *backw_cur = backw_start;
  216. /* To prevent a warning init the used vars. */
  217. len = find_idx (&backw_cur, &weight_idx,
  218. &rule_idx, l_data, pass);
  219. for (i = 1; i < p; i++)
  220. len = find_idx (&backw_cur, &weight_idx,
  221. &rule_idx, l_data, pass);
  222. if (len != 0)
  223. {
  224. #ifdef WIDE_CHAR_VERSION
  225. if (needed + 1 + len < n)
  226. {
  227. dest[needed] = val;
  228. for (i = 0; i < len; ++i)
  229. dest[needed + 1 + i] =
  230. l_data->weights[weight_idx + i];
  231. }
  232. needed += 1 + len;
  233. #else
  234. buflen = utf8_encode (buf, val);
  235. if (needed + buflen + len < n)
  236. {
  237. for (i = 0; i < buflen; ++i)
  238. dest[needed + i] = buf[i];
  239. for (i = 0; i < len; ++i)
  240. dest[needed + buflen + i] =
  241. l_data->weights[weight_idx + i];
  242. }
  243. needed += buflen + len;
  244. #endif
  245. val = 1;
  246. }
  247. else
  248. ++val;
  249. }
  250. backw_start = NULL;
  251. backw_len = 0;
  252. }
  253. /* Now handle the forward element. */
  254. if (len != 0)
  255. {
  256. #ifdef WIDE_CHAR_VERSION
  257. if (needed + 1 + len < n)
  258. {
  259. dest[needed] = val;
  260. for (i = 0; i < len; ++i)
  261. dest[needed + 1 + i] =
  262. l_data->weights[weight_idx + i];
  263. }
  264. needed += 1 + len;
  265. #else
  266. buflen = utf8_encode (buf, val);
  267. if (needed + buflen + len < n)
  268. {
  269. for (i = 0; i < buflen; ++i)
  270. dest[needed + i] = buf[i];
  271. for (i = 0; i < len; ++i)
  272. dest[needed + buflen + i] =
  273. l_data->weights[weight_idx + i];
  274. }
  275. needed += buflen + len;
  276. #endif
  277. val = 1;
  278. }
  279. else
  280. ++val;
  281. }
  282. else
  283. {
  284. /* Remember start of the backward sequence & track length. */
  285. if (backw_start == NULL)
  286. backw_start = pos;
  287. backw_len++;
  288. }
  289. }
  290. /* Handle the pushed backward sequence. */
  291. if (backw_start != NULL)
  292. {
  293. for (size_t p = backw_len; p > 0; p--)
  294. {
  295. size_t len;
  296. int32_t weight_idx;
  297. unsigned char rule_idx;
  298. const USTRING_TYPE *backw_cur = backw_start;
  299. /* To prevent a warning init the used vars. */
  300. len = find_idx (&backw_cur, &weight_idx,
  301. &rule_idx, l_data, pass);
  302. for (i = 1; i < p; i++)
  303. len = find_idx (&backw_cur, &weight_idx,
  304. &rule_idx, l_data, pass);
  305. if (len != 0)
  306. {
  307. #ifdef WIDE_CHAR_VERSION
  308. if (needed + 1 + len < n)
  309. {
  310. dest[needed] = val;
  311. for (i = 0; i < len; ++i)
  312. dest[needed + 1 + i] =
  313. l_data->weights[weight_idx + i];
  314. }
  315. needed += 1 + len;
  316. #else
  317. buflen = utf8_encode (buf, val);
  318. if (needed + buflen + len < n)
  319. {
  320. for (i = 0; i < buflen; ++i)
  321. dest[needed + i] = buf[i];
  322. for (i = 0; i < len; ++i)
  323. dest[needed + buflen + i] =
  324. l_data->weights[weight_idx + i];
  325. }
  326. needed += buflen + len;
  327. #endif
  328. val = 1;
  329. }
  330. else
  331. ++val;
  332. }
  333. }
  334. }
  335. /* Finally store the byte to separate the passes or terminate
  336. the string. */
  337. if (needed < n)
  338. dest[needed] = pass + 1 < l_data->nrules ? L('\1') : L('\0');
  339. ++needed;
  340. }
  341. /* This is a little optimization: many collation specifications have
  342. a `position' rule at the end and if no non-ignored character
  343. is found the last \1 byte is immediately followed by a \0 byte
  344. signalling this. We can avoid the \1 byte(s). */
  345. if (needed > 2 && needed == last_needed + 1)
  346. {
  347. /* Remove the \1 byte. */
  348. if (--needed <= n)
  349. dest[needed - 1] = L('\0');
  350. }
  351. /* Return the number of bytes/words we need, but don't count the NUL
  352. byte/word at the end. */
  353. return needed - 1;
  354. }
  355. /* Do the transformation using weight-index and rule cache. */
  356. static size_t
  357. do_xfrm_cached (STRING_TYPE *dest, size_t n, const locale_data_t *l_data,
  358. size_t idxmax, int32_t *idxarr, const unsigned char *rulearr)
  359. {
  360. uint32_t nrules = l_data->nrules;
  361. unsigned char *rulesets = l_data->rulesets;
  362. USTRING_TYPE *weights = l_data->weights;
  363. uint32_t pass;
  364. size_t needed = 0;
  365. size_t last_needed;
  366. size_t idxcnt;
  367. /* Now the passes over the weights. */
  368. for (pass = 0; pass < nrules; ++pass)
  369. {
  370. size_t backw_stop = ~0ul;
  371. int rule = rulesets[rulearr[0] * nrules + pass];
  372. /* We assume that if a rule has defined `position' in one section
  373. this is true for all of them. */
  374. int position = rule & sort_position;
  375. last_needed = needed;
  376. if (position == 0)
  377. {
  378. for (idxcnt = 0; idxcnt < idxmax; ++idxcnt)
  379. {
  380. if ((rule & sort_forward) != 0)
  381. {
  382. size_t len;
  383. if (backw_stop != ~0ul)
  384. {
  385. /* Handle the pushed elements now. */
  386. size_t backw;
  387. for (backw = idxcnt; backw > backw_stop; )
  388. {
  389. --backw;
  390. len = weights[idxarr[backw]++];
  391. if (needed + len < n)
  392. while (len-- > 0)
  393. dest[needed++] = weights[idxarr[backw]++];
  394. else
  395. {
  396. /* No more characters fit into the buffer. */
  397. needed += len;
  398. idxarr[backw] += len;
  399. }
  400. }
  401. backw_stop = ~0ul;
  402. }
  403. /* Now handle the forward element. */
  404. len = weights[idxarr[idxcnt]++];
  405. if (needed + len < n)
  406. while (len-- > 0)
  407. dest[needed++] = weights[idxarr[idxcnt]++];
  408. else
  409. {
  410. /* No more characters fit into the buffer. */
  411. needed += len;
  412. idxarr[idxcnt] += len;
  413. }
  414. }
  415. else
  416. {
  417. /* Remember where the backwards series started. */
  418. if (backw_stop == ~0ul)
  419. backw_stop = idxcnt;
  420. }
  421. rule = rulesets[rulearr[idxcnt + 1] * nrules + pass];
  422. }
  423. if (backw_stop != ~0ul)
  424. {
  425. /* Handle the pushed elements now. */
  426. size_t backw;
  427. backw = idxcnt;
  428. while (backw > backw_stop)
  429. {
  430. size_t len = weights[idxarr[--backw]++];
  431. if (needed + len < n)
  432. while (len-- > 0)
  433. dest[needed++] = weights[idxarr[backw]++];
  434. else
  435. {
  436. /* No more characters fit into the buffer. */
  437. needed += len;
  438. idxarr[backw] += len;
  439. }
  440. }
  441. }
  442. }
  443. else
  444. {
  445. int val = 1;
  446. #ifndef WIDE_CHAR_VERSION
  447. char buf[7];
  448. size_t buflen;
  449. #endif
  450. size_t i;
  451. for (idxcnt = 0; idxcnt < idxmax; ++idxcnt)
  452. {
  453. if ((rule & sort_forward) != 0)
  454. {
  455. size_t len;
  456. if (backw_stop != ~0ul)
  457. {
  458. /* Handle the pushed elements now. */
  459. size_t backw;
  460. for (backw = idxcnt; backw > backw_stop; )
  461. {
  462. --backw;
  463. len = weights[idxarr[backw]++];
  464. if (len != 0)
  465. {
  466. #ifdef WIDE_CHAR_VERSION
  467. if (needed + 1 + len < n)
  468. {
  469. dest[needed] = val;
  470. for (i = 0; i < len; ++i)
  471. dest[needed + 1 + i] =
  472. weights[idxarr[backw] + i];
  473. }
  474. needed += 1 + len;
  475. #else
  476. buflen = utf8_encode (buf, val);
  477. if (needed + buflen + len < n)
  478. {
  479. for (i = 0; i < buflen; ++i)
  480. dest[needed + i] = buf[i];
  481. for (i = 0; i < len; ++i)
  482. dest[needed + buflen + i] =
  483. weights[idxarr[backw] + i];
  484. }
  485. needed += buflen + len;
  486. #endif
  487. idxarr[backw] += len;
  488. val = 1;
  489. }
  490. else
  491. ++val;
  492. }
  493. backw_stop = ~0ul;
  494. }
  495. /* Now handle the forward element. */
  496. len = weights[idxarr[idxcnt]++];
  497. if (len != 0)
  498. {
  499. #ifdef WIDE_CHAR_VERSION
  500. if (needed + 1+ len < n)
  501. {
  502. dest[needed] = val;
  503. for (i = 0; i < len; ++i)
  504. dest[needed + 1 + i] =
  505. weights[idxarr[idxcnt] + i];
  506. }
  507. needed += 1 + len;
  508. #else
  509. buflen = utf8_encode (buf, val);
  510. if (needed + buflen + len < n)
  511. {
  512. for (i = 0; i < buflen; ++i)
  513. dest[needed + i] = buf[i];
  514. for (i = 0; i < len; ++i)
  515. dest[needed + buflen + i] =
  516. weights[idxarr[idxcnt] + i];
  517. }
  518. needed += buflen + len;
  519. #endif
  520. idxarr[idxcnt] += len;
  521. val = 1;
  522. }
  523. else
  524. /* Note that we don't have to increment `idxarr[idxcnt]'
  525. since the length is zero. */
  526. ++val;
  527. }
  528. else
  529. {
  530. /* Remember where the backwards series started. */
  531. if (backw_stop == ~0ul)
  532. backw_stop = idxcnt;
  533. }
  534. rule = rulesets[rulearr[idxcnt + 1] * nrules + pass];
  535. }
  536. if (backw_stop != ~0ul)
  537. {
  538. /* Handle the pushed elements now. */
  539. size_t backw;
  540. backw = idxmax - 1;
  541. while (backw > backw_stop)
  542. {
  543. size_t len = weights[idxarr[--backw]++];
  544. if (len != 0)
  545. {
  546. #ifdef WIDE_CHAR_VERSION
  547. if (needed + 1 + len < n)
  548. {
  549. dest[needed] = val;
  550. for (i = 0; i < len; ++i)
  551. dest[needed + 1 + i] =
  552. weights[idxarr[backw] + i];
  553. }
  554. needed += 1 + len;
  555. #else
  556. buflen = utf8_encode (buf, val);
  557. if (needed + buflen + len < n)
  558. {
  559. for (i = 0; i < buflen; ++i)
  560. dest[needed + i] = buf[i];
  561. for (i = 0; i < len; ++i)
  562. dest[needed + buflen + i] =
  563. weights[idxarr[backw] + i];
  564. }
  565. needed += buflen + len;
  566. #endif
  567. idxarr[backw] += len;
  568. val = 1;
  569. }
  570. else
  571. ++val;
  572. }
  573. }
  574. }
  575. /* Finally store the byte to separate the passes or terminate
  576. the string. */
  577. if (needed < n)
  578. dest[needed] = pass + 1 < nrules ? L('\1') : L('\0');
  579. ++needed;
  580. }
  581. /* This is a little optimization: many collation specifications have
  582. a `position' rule at the end and if no non-ignored character
  583. is found the last \1 byte is immediately followed by a \0 byte
  584. signalling this. We can avoid the \1 byte(s). */
  585. if (needed > 2 && needed == last_needed + 1)
  586. {
  587. /* Remove the \1 byte. */
  588. if (--needed <= n)
  589. dest[needed - 1] = L('\0');
  590. }
  591. /* Return the number of bytes/words we need, but don't count the NUL
  592. byte/word at the end. */
  593. return needed - 1;
  594. }
  595. size_t
  596. STRXFRM (STRING_TYPE *dest, const STRING_TYPE *src, size_t n, locale_t l)
  597. {
  598. locale_data_t l_data;
  599. struct __locale_data *current = l->__locales[LC_COLLATE];
  600. l_data.nrules = current->values[_NL_ITEM_INDEX (_NL_COLLATE_NRULES)].word;
  601. /* Handle byte comparison case. */
  602. if (l_data.nrules == 0)
  603. {
  604. size_t srclen = STRLEN (src);
  605. if (n != 0)
  606. STPNCPY (dest, src, MIN (srclen + 1, n));
  607. return srclen;
  608. }
  609. /* Handle an empty string, code hereafter relies on strlen (src) > 0. */
  610. if (*src == L('\0'))
  611. {
  612. if (n != 0)
  613. *dest = L('\0');
  614. return 0;
  615. }
  616. /* Get the locale data. */
  617. l_data.rulesets = (unsigned char *)
  618. current->values[_NL_ITEM_INDEX (_NL_COLLATE_RULESETS)].string;
  619. l_data.table = (int32_t *)
  620. current->values[_NL_ITEM_INDEX (CONCAT(_NL_COLLATE_TABLE,SUFFIX))].string;
  621. l_data.weights = (USTRING_TYPE *)
  622. current->values[_NL_ITEM_INDEX (CONCAT(_NL_COLLATE_WEIGHT,SUFFIX))].string;
  623. l_data.extra = (USTRING_TYPE *)
  624. current->values[_NL_ITEM_INDEX (CONCAT(_NL_COLLATE_EXTRA,SUFFIX))].string;
  625. l_data.indirect = (int32_t *)
  626. current->values[_NL_ITEM_INDEX (CONCAT(_NL_COLLATE_INDIRECT,SUFFIX))].string;
  627. assert (((uintptr_t) l_data.table) % __alignof__ (l_data.table[0]) == 0);
  628. assert (((uintptr_t) l_data.weights) % __alignof__ (l_data.weights[0]) == 0);
  629. assert (((uintptr_t) l_data.extra) % __alignof__ (l_data.extra[0]) == 0);
  630. assert (((uintptr_t) l_data.indirect) % __alignof__ (l_data.indirect[0]) == 0);
  631. /* We need the elements of the string as unsigned values since they
  632. are used as indices. */
  633. const USTRING_TYPE *usrc = (const USTRING_TYPE *) src;
  634. /* Allocate cache for small strings on the stack and fill it with weight and
  635. rule indices. If the cache size is not sufficient, continue with the
  636. uncached xfrm version. */
  637. size_t idxmax = 0;
  638. const USTRING_TYPE *cur = usrc;
  639. int32_t *idxarr = alloca (SMALL_STR_SIZE * sizeof (int32_t));
  640. unsigned char *rulearr = alloca (SMALL_STR_SIZE + 1);
  641. do
  642. {
  643. int32_t tmp = findidx (l_data.table, l_data.indirect, l_data.extra, &cur,
  644. -1);
  645. rulearr[idxmax] = tmp >> 24;
  646. idxarr[idxmax] = tmp & 0xffffff;
  647. ++idxmax;
  648. }
  649. while (*cur != L('\0') && idxmax < SMALL_STR_SIZE);
  650. /* This element is only read, the value never used but to determine
  651. another value which then is ignored. */
  652. rulearr[idxmax] = '\0';
  653. /* Do the transformation. */
  654. if (*cur == L('\0'))
  655. return do_xfrm_cached (dest, n, &l_data, idxmax, idxarr, rulearr);
  656. else
  657. return do_xfrm (usrc, dest, n, &l_data);
  658. }
  659. libc_hidden_def (STRXFRM)
  660. #ifndef WIDE_CHAR_VERSION
  661. weak_alias (__strxfrm_l, strxfrm_l)
  662. #endif