1c3d0cca4SAndrey A. Chernov /*-
24d846d26SWarner Losh * SPDX-License-Identifier: BSD-2-Clause
3d915a14eSPedro F. Giffuni *
47b247341SBaptiste Daroussin * Copyright 2014 Garrett D'Amore <garrett@damore.org>
5332fe837SBaptiste Daroussin * Copyright 2010 Nexenta Systems, Inc. All rights reserved.
6c3d0cca4SAndrey A. Chernov * Copyright (c) 1995 Alex Tatmanjants <alex@elvisti.kiev.ua>
7c3d0cca4SAndrey A. Chernov * at Electronni Visti IA, Kiev, Ukraine.
8c3d0cca4SAndrey A. Chernov * All rights reserved.
9c3d0cca4SAndrey A. Chernov *
103c87aa1dSDavid Chisnall * Copyright (c) 2011 The FreeBSD Foundation
115b5fa75aSEd Maste *
123c87aa1dSDavid Chisnall * Portions of this software were developed by David Chisnall
133c87aa1dSDavid Chisnall * under sponsorship from the FreeBSD Foundation.
143c87aa1dSDavid Chisnall *
15c3d0cca4SAndrey A. Chernov * Redistribution and use in source and binary forms, with or without
16c3d0cca4SAndrey A. Chernov * modification, are permitted provided that the following conditions
17c3d0cca4SAndrey A. Chernov * are met:
18c3d0cca4SAndrey A. Chernov * 1. Redistributions of source code must retain the above copyright
19c3d0cca4SAndrey A. Chernov * notice, this list of conditions and the following disclaimer.
20c3d0cca4SAndrey A. Chernov * 2. Redistributions in binary form must reproduce the above copyright
21c3d0cca4SAndrey A. Chernov * notice, this list of conditions and the following disclaimer in the
22c3d0cca4SAndrey A. Chernov * documentation and/or other materials provided with the distribution.
23c3d0cca4SAndrey A. Chernov *
24c3d0cca4SAndrey A. Chernov * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND
25c3d0cca4SAndrey A. Chernov * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
26c3d0cca4SAndrey A. Chernov * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
27c3d0cca4SAndrey A. Chernov * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE
28c3d0cca4SAndrey A. Chernov * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
29c3d0cca4SAndrey A. Chernov * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
30c3d0cca4SAndrey A. Chernov * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
31c3d0cca4SAndrey A. Chernov * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
32c3d0cca4SAndrey A. Chernov * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
33c3d0cca4SAndrey A. Chernov * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
34c3d0cca4SAndrey A. Chernov * SUCH DAMAGE.
352a6abeebSBaptiste Daroussin *
362a6abeebSBaptiste Daroussin * Adapted to xlocale by John Marino <draco@marino.st>
37c3d0cca4SAndrey A. Chernov */
38c3d0cca4SAndrey A. Chernov
39d201fe46SDaniel Eischen #include "namespace.h"
40c25f5140SBaptiste Daroussin
41c25f5140SBaptiste Daroussin #include <sys/types.h>
42c25f5140SBaptiste Daroussin #include <sys/stat.h>
43c25f5140SBaptiste Daroussin #include <sys/mman.h>
44c25f5140SBaptiste Daroussin
45332fe837SBaptiste Daroussin #include <assert.h>
46c3d0cca4SAndrey A. Chernov #include <stdio.h>
47c3d0cca4SAndrey A. Chernov #include <stdlib.h>
48c3d0cca4SAndrey A. Chernov #include <string.h>
492a6abeebSBaptiste Daroussin #include <wchar.h>
50926f20c9SAndrey A. Chernov #include <errno.h>
51926f20c9SAndrey A. Chernov #include <unistd.h>
522a6abeebSBaptiste Daroussin #include <fcntl.h>
53d201fe46SDaniel Eischen #include "un-namespace.h"
54d201fe46SDaniel Eischen
55c3d0cca4SAndrey A. Chernov #include "collate.h"
5663407d34SAndrey A. Chernov #include "setlocale.h"
5776692b80SAndrey A. Chernov #include "ldpart.h"
58536451f9SBaptiste Daroussin #include "libc_private.h"
59c3d0cca4SAndrey A. Chernov
603c87aa1dSDavid Chisnall struct xlocale_collate __xlocale_global_collate = {
612a6abeebSBaptiste Daroussin {{0}, "C"}, 1, 0, 0, 0
623c87aa1dSDavid Chisnall };
633c87aa1dSDavid Chisnall
643c87aa1dSDavid Chisnall struct xlocale_collate __xlocale_C_collate = {
652a6abeebSBaptiste Daroussin {{0}, "C"}, 1, 0, 0, 0
663c87aa1dSDavid Chisnall };
67c3d0cca4SAndrey A. Chernov
68269dea90SYuri Pankov struct xlocale_collate __xlocale_POSIX_collate = {
69269dea90SYuri Pankov {{0}, "POSIX"}, 1, 0, 0, 0
70269dea90SYuri Pankov };
71269dea90SYuri Pankov
72269dea90SYuri Pankov struct xlocale_collate __xlocale_CUTF8_collate = {
73269dea90SYuri Pankov {{0}, "C.UTF-8"}, 1, 0, 0, 0
74269dea90SYuri Pankov };
75269dea90SYuri Pankov
76a6d2922cSBaptiste Daroussin static int
773c87aa1dSDavid Chisnall __collate_load_tables_l(const char *encoding, struct xlocale_collate *table);
783c87aa1dSDavid Chisnall
793c87aa1dSDavid Chisnall static void
destruct_collate(void * t)803c87aa1dSDavid Chisnall destruct_collate(void *t)
813c87aa1dSDavid Chisnall {
823c87aa1dSDavid Chisnall struct xlocale_collate *table = t;
832a6abeebSBaptiste Daroussin if (table->map && (table->maplen > 0)) {
842a6abeebSBaptiste Daroussin (void) munmap(table->map, table->maplen);
853c87aa1dSDavid Chisnall }
863c87aa1dSDavid Chisnall free(t);
873c87aa1dSDavid Chisnall }
883c87aa1dSDavid Chisnall
893c87aa1dSDavid Chisnall void *
__collate_load(const char * encoding,__unused locale_t unused)902a6abeebSBaptiste Daroussin __collate_load(const char *encoding, __unused locale_t unused)
913c87aa1dSDavid Chisnall {
92269dea90SYuri Pankov if (strcmp(encoding, "C") == 0)
93a8be0611SKonstantin Belousov return (&__xlocale_C_collate);
94269dea90SYuri Pankov else if (strcmp(encoding, "POSIX") == 0)
95269dea90SYuri Pankov return (&__xlocale_POSIX_collate);
96269dea90SYuri Pankov else if (strcmp(encoding, "C.UTF-8") == 0)
97269dea90SYuri Pankov return (&__xlocale_CUTF8_collate);
98269dea90SYuri Pankov
99a8be0611SKonstantin Belousov struct xlocale_collate *table = calloc(sizeof(struct xlocale_collate),
100a8be0611SKonstantin Belousov 1);
101b8ad908aSKonstantin Belousov if (table == NULL)
102b8ad908aSKonstantin Belousov return (NULL);
1033c87aa1dSDavid Chisnall table->header.header.destructor = destruct_collate;
104a8be0611SKonstantin Belousov
105a8be0611SKonstantin Belousov /*
106a8be0611SKonstantin Belousov * FIXME: Make sure that _LDP_CACHE is never returned. We
107a8be0611SKonstantin Belousov * should be doing the caching outside of this section.
108a8be0611SKonstantin Belousov */
1093c87aa1dSDavid Chisnall if (__collate_load_tables_l(encoding, table) != _LDP_LOADED) {
1103c87aa1dSDavid Chisnall xlocale_release(table);
111a8be0611SKonstantin Belousov return (NULL);
1123c87aa1dSDavid Chisnall }
113a8be0611SKonstantin Belousov return (table);
1143c87aa1dSDavid Chisnall }
1153c87aa1dSDavid Chisnall
1163c87aa1dSDavid Chisnall /**
1173c87aa1dSDavid Chisnall * Load the collation tables for the specified encoding into the global table.
1183c87aa1dSDavid Chisnall */
1193c87aa1dSDavid Chisnall int
__collate_load_tables(const char * encoding)12076692b80SAndrey A. Chernov __collate_load_tables(const char *encoding)
121c3d0cca4SAndrey A. Chernov {
1225e4bbc69SBaptiste Daroussin
1235e4bbc69SBaptiste Daroussin return (__collate_load_tables_l(encoding, &__xlocale_global_collate));
1243c87aa1dSDavid Chisnall }
1253c87aa1dSDavid Chisnall
12657e64236SMark Johnston static int
__collate_load_tables_l(const char * encoding,struct xlocale_collate * table)1273c87aa1dSDavid Chisnall __collate_load_tables_l(const char *encoding, struct xlocale_collate *table)
1283c87aa1dSDavid Chisnall {
1292a6abeebSBaptiste Daroussin int i, chains, z;
130b89704ceSBaptiste Daroussin char *buf;
1312a6abeebSBaptiste Daroussin char *TMP;
1322a6abeebSBaptiste Daroussin char *map;
1332a6abeebSBaptiste Daroussin collate_info_t *info;
1342a6abeebSBaptiste Daroussin struct stat sbuf;
1352a6abeebSBaptiste Daroussin int fd;
136c3d0cca4SAndrey A. Chernov
137332fe837SBaptiste Daroussin table->__collate_load_error = 1;
138332fe837SBaptiste Daroussin
13976692b80SAndrey A. Chernov /* 'encoding' must be already checked. */
140dd7c41a3SYuri Pankov if (strcmp(encoding, "C") == 0 || strcmp(encoding, "POSIX") == 0 ||
141dd7c41a3SYuri Pankov strncmp(encoding, "C.", 2) == 0) {
14276692b80SAndrey A. Chernov return (_LDP_CACHE);
143377da8e8SAndrey A. Chernov }
14476692b80SAndrey A. Chernov
145dc8507e1SBryan Drewery if (asprintf(&buf, "%s/%s/LC_COLLATE", _PathLocale, encoding) == -1)
146b89704ceSBaptiste Daroussin return (_LDP_ERROR);
14776692b80SAndrey A. Chernov
14898bfb9daSMark Johnston if ((fd = _open(buf, O_RDONLY | O_CLOEXEC)) < 0) {
14928a20bb3SBaptiste Daroussin free(buf);
1502a6abeebSBaptiste Daroussin return (_LDP_ERROR);
15128a20bb3SBaptiste Daroussin }
152b89704ceSBaptiste Daroussin free(buf);
1532a6abeebSBaptiste Daroussin if (_fstat(fd, &sbuf) < 0) {
1542a6abeebSBaptiste Daroussin (void) _close(fd);
1558e52da4dSAndrey A. Chernov return (_LDP_ERROR);
1568e52da4dSAndrey A. Chernov }
157cc7edd25SThomas Munro if (sbuf.st_size < (COLLATE_FMT_VERSION_LEN +
158cc7edd25SThomas Munro XLOCALE_DEF_VERSION_LEN +
159*e15da6b1SKyle Evans sizeof (*info))) {
1602a6abeebSBaptiste Daroussin (void) _close(fd);
1612a6abeebSBaptiste Daroussin errno = EINVAL;
1628e52da4dSAndrey A. Chernov return (_LDP_ERROR);
1638e52da4dSAndrey A. Chernov }
1642a6abeebSBaptiste Daroussin map = mmap(NULL, sbuf.st_size, PROT_READ, MAP_PRIVATE, fd, 0);
1652a6abeebSBaptiste Daroussin (void) _close(fd);
16657e64236SMark Johnston if ((TMP = map) == MAP_FAILED) {
1678e52da4dSAndrey A. Chernov return (_LDP_ERROR);
1688e52da4dSAndrey A. Chernov }
1692a6abeebSBaptiste Daroussin
170cc7edd25SThomas Munro if (strncmp(TMP, COLLATE_FMT_VERSION, COLLATE_FMT_VERSION_LEN) != 0) {
1712a6abeebSBaptiste Daroussin (void) munmap(map, sbuf.st_size);
1722a6abeebSBaptiste Daroussin errno = EINVAL;
1738e52da4dSAndrey A. Chernov return (_LDP_ERROR);
1748e52da4dSAndrey A. Chernov }
175cc7edd25SThomas Munro TMP += COLLATE_FMT_VERSION_LEN;
176cc7edd25SThomas Munro strlcat(table->header.version, TMP, sizeof (table->header.version));
177cc7edd25SThomas Munro TMP += XLOCALE_DEF_VERSION_LEN;
1782a6abeebSBaptiste Daroussin
1792a6abeebSBaptiste Daroussin info = (void *)TMP;
1802a6abeebSBaptiste Daroussin TMP += sizeof (*info);
1812a6abeebSBaptiste Daroussin
1822a6abeebSBaptiste Daroussin if ((info->directive_count < 1) ||
1832a6abeebSBaptiste Daroussin (info->directive_count >= COLL_WEIGHTS_MAX) ||
1844644f9beSYuri Pankov ((chains = info->chain_count) < 0)) {
1852a6abeebSBaptiste Daroussin (void) munmap(map, sbuf.st_size);
1862a6abeebSBaptiste Daroussin errno = EINVAL;
1872a6abeebSBaptiste Daroussin return (_LDP_ERROR);
1882a6abeebSBaptiste Daroussin }
1892a6abeebSBaptiste Daroussin
1902a6abeebSBaptiste Daroussin i = (sizeof (collate_char_t) * (UCHAR_MAX + 1)) +
1912a6abeebSBaptiste Daroussin (sizeof (collate_chain_t) * chains) +
1924644f9beSYuri Pankov (sizeof (collate_large_t) * info->large_count);
193332fe837SBaptiste Daroussin for (z = 0; z < info->directive_count; z++) {
1944644f9beSYuri Pankov i += sizeof (collate_subst_t) * info->subst_count[z];
1952a6abeebSBaptiste Daroussin }
1962a6abeebSBaptiste Daroussin if (i != (sbuf.st_size - (TMP - map))) {
1972a6abeebSBaptiste Daroussin (void) munmap(map, sbuf.st_size);
1982a6abeebSBaptiste Daroussin errno = EINVAL;
1992a6abeebSBaptiste Daroussin return (_LDP_ERROR);
2002a6abeebSBaptiste Daroussin }
2012a6abeebSBaptiste Daroussin
20257e64236SMark Johnston if (table->map && (table->maplen > 0)) {
20357e64236SMark Johnston (void) munmap(table->map, table->maplen);
20457e64236SMark Johnston }
20557e64236SMark Johnston table->map = map;
20657e64236SMark Johnston table->maplen = sbuf.st_size;
207332fe837SBaptiste Daroussin table->info = info;
2082a6abeebSBaptiste Daroussin table->char_pri_table = (void *)TMP;
2092a6abeebSBaptiste Daroussin TMP += sizeof (collate_char_t) * (UCHAR_MAX + 1);
2102a6abeebSBaptiste Daroussin
2112a6abeebSBaptiste Daroussin for (z = 0; z < info->directive_count; z++) {
2124644f9beSYuri Pankov if (info->subst_count[z] > 0) {
2132a6abeebSBaptiste Daroussin table->subst_table[z] = (void *)TMP;
2144644f9beSYuri Pankov TMP += info->subst_count[z] * sizeof (collate_subst_t);
2152a6abeebSBaptiste Daroussin } else {
2162a6abeebSBaptiste Daroussin table->subst_table[z] = NULL;
2172a6abeebSBaptiste Daroussin }
2182a6abeebSBaptiste Daroussin }
2192a6abeebSBaptiste Daroussin
2202a6abeebSBaptiste Daroussin if (chains > 0) {
2212a6abeebSBaptiste Daroussin table->chain_pri_table = (void *)TMP;
2222a6abeebSBaptiste Daroussin TMP += chains * sizeof (collate_chain_t);
2238e52da4dSAndrey A. Chernov } else
2242a6abeebSBaptiste Daroussin table->chain_pri_table = NULL;
2254644f9beSYuri Pankov if (info->large_count > 0)
2262a6abeebSBaptiste Daroussin table->large_pri_table = (void *)TMP;
2272a6abeebSBaptiste Daroussin else
2282a6abeebSBaptiste Daroussin table->large_pri_table = NULL;
2298e52da4dSAndrey A. Chernov
230bb4317bfSDavid Chisnall table->__collate_load_error = 0;
23176692b80SAndrey A. Chernov return (_LDP_LOADED);
232c3d0cca4SAndrey A. Chernov }
233c3d0cca4SAndrey A. Chernov
234332fe837SBaptiste Daroussin static const int32_t *
substsearch(struct xlocale_collate * table,const wchar_t key,int pass)2352a6abeebSBaptiste Daroussin substsearch(struct xlocale_collate *table, const wchar_t key, int pass)
2362a6abeebSBaptiste Daroussin {
237332fe837SBaptiste Daroussin const collate_subst_t *p;
2384644f9beSYuri Pankov int n = table->info->subst_count[pass];
2392a6abeebSBaptiste Daroussin
2402a6abeebSBaptiste Daroussin if (n == 0)
2412a6abeebSBaptiste Daroussin return (NULL);
2422a6abeebSBaptiste Daroussin
2432a6abeebSBaptiste Daroussin if (pass >= table->info->directive_count)
2442a6abeebSBaptiste Daroussin return (NULL);
2452a6abeebSBaptiste Daroussin
2462a6abeebSBaptiste Daroussin if (!(key & COLLATE_SUBST_PRIORITY))
2472a6abeebSBaptiste Daroussin return (NULL);
2482a6abeebSBaptiste Daroussin
2492a6abeebSBaptiste Daroussin p = table->subst_table[pass] + (key & ~COLLATE_SUBST_PRIORITY);
2504644f9beSYuri Pankov assert(p->key == key);
25177bc2a1cSRuslan Bukin
2522a6abeebSBaptiste Daroussin return (p->pri);
253c3d0cca4SAndrey A. Chernov }
2542a6abeebSBaptiste Daroussin
2552a6abeebSBaptiste Daroussin static collate_chain_t *
chainsearch(struct xlocale_collate * table,const wchar_t * key,int * len)2562a6abeebSBaptiste Daroussin chainsearch(struct xlocale_collate *table, const wchar_t *key, int *len)
2572a6abeebSBaptiste Daroussin {
25876e6db68SBaptiste Daroussin int low = 0;
2594644f9beSYuri Pankov int high = table->info->chain_count - 1;
2602a6abeebSBaptiste Daroussin int next, compar, l;
2612a6abeebSBaptiste Daroussin collate_chain_t *p;
26276e6db68SBaptiste Daroussin collate_chain_t *tab = table->chain_pri_table;
2632a6abeebSBaptiste Daroussin
26476e6db68SBaptiste Daroussin if (high < 0)
2652a6abeebSBaptiste Daroussin return (NULL);
2662a6abeebSBaptiste Daroussin
2672a6abeebSBaptiste Daroussin while (low <= high) {
2682a6abeebSBaptiste Daroussin next = (low + high) / 2;
2692a6abeebSBaptiste Daroussin p = tab + next;
2704644f9beSYuri Pankov compar = *key - *p->str;
2712a6abeebSBaptiste Daroussin if (compar == 0) {
2722a6abeebSBaptiste Daroussin l = wcsnlen(p->str, COLLATE_STR_LEN);
2732a6abeebSBaptiste Daroussin compar = wcsncmp(key, p->str, l);
2742a6abeebSBaptiste Daroussin if (compar == 0) {
2752a6abeebSBaptiste Daroussin *len = l;
2762a6abeebSBaptiste Daroussin return (p);
277c3d0cca4SAndrey A. Chernov }
2782a6abeebSBaptiste Daroussin }
2792a6abeebSBaptiste Daroussin if (compar > 0)
2802a6abeebSBaptiste Daroussin low = next + 1;
2812a6abeebSBaptiste Daroussin else
2822a6abeebSBaptiste Daroussin high = next - 1;
2832a6abeebSBaptiste Daroussin }
2842a6abeebSBaptiste Daroussin return (NULL);
2852a6abeebSBaptiste Daroussin }
2862a6abeebSBaptiste Daroussin
2872a6abeebSBaptiste Daroussin static collate_large_t *
largesearch(struct xlocale_collate * table,const wchar_t key)2882a6abeebSBaptiste Daroussin largesearch(struct xlocale_collate *table, const wchar_t key)
2892a6abeebSBaptiste Daroussin {
2902a6abeebSBaptiste Daroussin int low = 0;
2914644f9beSYuri Pankov int high = table->info->large_count - 1;
2922a6abeebSBaptiste Daroussin int next, compar;
2932a6abeebSBaptiste Daroussin collate_large_t *p;
2942a6abeebSBaptiste Daroussin collate_large_t *tab = table->large_pri_table;
2952a6abeebSBaptiste Daroussin
29676e6db68SBaptiste Daroussin if (high < 0)
2972a6abeebSBaptiste Daroussin return (NULL);
2982a6abeebSBaptiste Daroussin
2992a6abeebSBaptiste Daroussin while (low <= high) {
3002a6abeebSBaptiste Daroussin next = (low + high) / 2;
3012a6abeebSBaptiste Daroussin p = tab + next;
3024644f9beSYuri Pankov compar = key - p->val;
3032a6abeebSBaptiste Daroussin if (compar == 0)
3042a6abeebSBaptiste Daroussin return (p);
3052a6abeebSBaptiste Daroussin if (compar > 0)
3062a6abeebSBaptiste Daroussin low = next + 1;
3072a6abeebSBaptiste Daroussin else
3082a6abeebSBaptiste Daroussin high = next - 1;
3092a6abeebSBaptiste Daroussin }
3102a6abeebSBaptiste Daroussin return (NULL);
311c3d0cca4SAndrey A. Chernov }
312c3d0cca4SAndrey A. Chernov
313c3d0cca4SAndrey A. Chernov void
_collate_lookup(struct xlocale_collate * table,const wchar_t * t,int * len,int * pri,int which,const int ** state)3142a6abeebSBaptiste Daroussin _collate_lookup(struct xlocale_collate *table, const wchar_t *t, int *len,
3152a6abeebSBaptiste Daroussin int *pri, int which, const int **state)
316c3d0cca4SAndrey A. Chernov {
3172a6abeebSBaptiste Daroussin collate_chain_t *p2;
3182a6abeebSBaptiste Daroussin collate_large_t *match;
3192a6abeebSBaptiste Daroussin int p, l;
3202a6abeebSBaptiste Daroussin const int *sptr;
321c3d0cca4SAndrey A. Chernov
3222a6abeebSBaptiste Daroussin /*
3232a6abeebSBaptiste Daroussin * If this is the "last" pass for the UNDEFINED, then
3242a6abeebSBaptiste Daroussin * we just return the priority itself.
3252a6abeebSBaptiste Daroussin */
3262a6abeebSBaptiste Daroussin if (which >= table->info->directive_count) {
3272a6abeebSBaptiste Daroussin *pri = *t;
328c3d0cca4SAndrey A. Chernov *len = 1;
3292a6abeebSBaptiste Daroussin *state = NULL;
330c3d0cca4SAndrey A. Chernov return;
331c3d0cca4SAndrey A. Chernov }
3322a6abeebSBaptiste Daroussin
3332a6abeebSBaptiste Daroussin /*
3342a6abeebSBaptiste Daroussin * If we have remaining substitution data from a previous
3352a6abeebSBaptiste Daroussin * call, consume it first.
3362a6abeebSBaptiste Daroussin */
3372a6abeebSBaptiste Daroussin if ((sptr = *state) != NULL) {
3382a6abeebSBaptiste Daroussin *pri = *sptr;
3392a6abeebSBaptiste Daroussin sptr++;
340dee0bbbdSBaptiste Daroussin if ((sptr == *state) || (sptr == NULL))
34176e6db68SBaptiste Daroussin *state = NULL;
34276e6db68SBaptiste Daroussin else
34376e6db68SBaptiste Daroussin *state = sptr;
3442a6abeebSBaptiste Daroussin *len = 0;
3452a6abeebSBaptiste Daroussin return;
346c3d0cca4SAndrey A. Chernov }
347c3d0cca4SAndrey A. Chernov
3482a6abeebSBaptiste Daroussin /* No active substitutions */
3492a6abeebSBaptiste Daroussin *len = 1;
3502a6abeebSBaptiste Daroussin
3512a6abeebSBaptiste Daroussin /*
35232223c1bSPedro F. Giffuni * Check for composites such as diphthongs that collate as a
3532a6abeebSBaptiste Daroussin * single element (aka chains or collating-elements).
3542a6abeebSBaptiste Daroussin */
3552a6abeebSBaptiste Daroussin if (((p2 = chainsearch(table, t, &l)) != NULL) &&
3562a6abeebSBaptiste Daroussin ((p = p2->pri[which]) >= 0)) {
3572a6abeebSBaptiste Daroussin
3582a6abeebSBaptiste Daroussin *len = l;
3592a6abeebSBaptiste Daroussin *pri = p;
3602a6abeebSBaptiste Daroussin
3612a6abeebSBaptiste Daroussin } else if (*t <= UCHAR_MAX) {
3622a6abeebSBaptiste Daroussin
3632a6abeebSBaptiste Daroussin /*
3642a6abeebSBaptiste Daroussin * Character is a small (8-bit) character.
3652a6abeebSBaptiste Daroussin * We just look these up directly for speed.
3662a6abeebSBaptiste Daroussin */
3674644f9beSYuri Pankov *pri = table->char_pri_table[*t].pri[which];
3682a6abeebSBaptiste Daroussin
3694644f9beSYuri Pankov } else if ((table->info->large_count > 0) &&
3702a6abeebSBaptiste Daroussin ((match = largesearch(table, *t)) != NULL)) {
3712a6abeebSBaptiste Daroussin
3722a6abeebSBaptiste Daroussin /*
3732a6abeebSBaptiste Daroussin * Character was found in the extended table.
3742a6abeebSBaptiste Daroussin */
3754644f9beSYuri Pankov *pri = match->pri.pri[which];
3762a6abeebSBaptiste Daroussin
3772a6abeebSBaptiste Daroussin } else {
3782a6abeebSBaptiste Daroussin /*
3792a6abeebSBaptiste Daroussin * Character lacks a specific definition.
3802a6abeebSBaptiste Daroussin */
3812a6abeebSBaptiste Daroussin if (table->info->directive[which] & DIRECTIVE_UNDEFINED) {
3822a6abeebSBaptiste Daroussin /* Mask off sign bit to prevent ordering confusion. */
3832a6abeebSBaptiste Daroussin *pri = (*t & COLLATE_MAX_PRIORITY);
3842a6abeebSBaptiste Daroussin } else {
3854644f9beSYuri Pankov *pri = table->info->undef_pri[which];
3862a6abeebSBaptiste Daroussin }
3872a6abeebSBaptiste Daroussin /* No substitutions for undefined characters! */
3882a6abeebSBaptiste Daroussin return;
3892a6abeebSBaptiste Daroussin }
3902a6abeebSBaptiste Daroussin
3912a6abeebSBaptiste Daroussin /*
3922a6abeebSBaptiste Daroussin * Try substituting (expanding) the character. We are
3932a6abeebSBaptiste Daroussin * currently doing this *after* the chain compression. I
3942a6abeebSBaptiste Daroussin * think it should not matter, but this way might be slightly
3952a6abeebSBaptiste Daroussin * faster.
3962a6abeebSBaptiste Daroussin *
3972a6abeebSBaptiste Daroussin * We do this after the priority search, as this will help us
3982a6abeebSBaptiste Daroussin * to identify a single key value. In order for this to work,
3992a6abeebSBaptiste Daroussin * its important that the priority assigned to a given element
4002a6abeebSBaptiste Daroussin * to be substituted be unique for that level. The localedef
4012a6abeebSBaptiste Daroussin * code ensures this for us.
4022a6abeebSBaptiste Daroussin */
4032a6abeebSBaptiste Daroussin if ((sptr = substsearch(table, *pri, which)) != NULL) {
4044644f9beSYuri Pankov if ((*pri = *sptr) > 0) {
4052a6abeebSBaptiste Daroussin sptr++;
4064644f9beSYuri Pankov *state = *sptr ? sptr : NULL;
4072a6abeebSBaptiste Daroussin }
4082a6abeebSBaptiste Daroussin }
4092a6abeebSBaptiste Daroussin
4102a6abeebSBaptiste Daroussin }
4112a6abeebSBaptiste Daroussin
4122a6abeebSBaptiste Daroussin /*
4132a6abeebSBaptiste Daroussin * This is the meaty part of wcsxfrm & strxfrm. Note that it does
4142a6abeebSBaptiste Daroussin * NOT NULL terminate. That is left to the caller.
4152a6abeebSBaptiste Daroussin */
4162a6abeebSBaptiste Daroussin size_t
_collate_wxfrm(struct xlocale_collate * table,const wchar_t * src,wchar_t * xf,size_t room)4172a6abeebSBaptiste Daroussin _collate_wxfrm(struct xlocale_collate *table, const wchar_t *src, wchar_t *xf,
4182a6abeebSBaptiste Daroussin size_t room)
419c3d0cca4SAndrey A. Chernov {
4202a6abeebSBaptiste Daroussin int pri;
4212a6abeebSBaptiste Daroussin int len;
4222a6abeebSBaptiste Daroussin const wchar_t *t;
4232a6abeebSBaptiste Daroussin wchar_t *tr = NULL;
4242a6abeebSBaptiste Daroussin int direc;
4252a6abeebSBaptiste Daroussin int pass;
4262a6abeebSBaptiste Daroussin const int32_t *state;
4272a6abeebSBaptiste Daroussin size_t want = 0;
4282a6abeebSBaptiste Daroussin size_t need = 0;
429332fe837SBaptiste Daroussin int ndir = table->info->directive_count;
430c3d0cca4SAndrey A. Chernov
431332fe837SBaptiste Daroussin assert(src);
432332fe837SBaptiste Daroussin
433332fe837SBaptiste Daroussin for (pass = 0; pass <= ndir; pass++) {
4342a6abeebSBaptiste Daroussin
4352a6abeebSBaptiste Daroussin state = NULL;
4362a6abeebSBaptiste Daroussin
4372a6abeebSBaptiste Daroussin if (pass != 0) {
4382a6abeebSBaptiste Daroussin /* insert level separator from the previous pass */
4392a6abeebSBaptiste Daroussin if (room) {
4402a6abeebSBaptiste Daroussin *xf++ = 1;
4412a6abeebSBaptiste Daroussin room--;
4422a6abeebSBaptiste Daroussin }
4432a6abeebSBaptiste Daroussin want++;
444c3d0cca4SAndrey A. Chernov }
445c3d0cca4SAndrey A. Chernov
4462a6abeebSBaptiste Daroussin /* special pass for undefined */
447332fe837SBaptiste Daroussin if (pass == ndir) {
4482a6abeebSBaptiste Daroussin direc = DIRECTIVE_FORWARD | DIRECTIVE_UNDEFINED;
4492a6abeebSBaptiste Daroussin } else {
4502a6abeebSBaptiste Daroussin direc = table->info->directive[pass];
4512a6abeebSBaptiste Daroussin }
4522a6abeebSBaptiste Daroussin
4532a6abeebSBaptiste Daroussin t = src;
4542a6abeebSBaptiste Daroussin
4552a6abeebSBaptiste Daroussin if (direc & DIRECTIVE_BACKWARD) {
4562a6abeebSBaptiste Daroussin wchar_t *bp, *fp, c;
4572a6abeebSBaptiste Daroussin free(tr);
4582a6abeebSBaptiste Daroussin if ((tr = wcsdup(t)) == NULL) {
4592a6abeebSBaptiste Daroussin errno = ENOMEM;
4602a6abeebSBaptiste Daroussin goto fail;
4612a6abeebSBaptiste Daroussin }
4622a6abeebSBaptiste Daroussin bp = tr;
4632a6abeebSBaptiste Daroussin fp = tr + wcslen(tr) - 1;
4642a6abeebSBaptiste Daroussin while (bp < fp) {
4652a6abeebSBaptiste Daroussin c = *bp;
4662a6abeebSBaptiste Daroussin *bp++ = *fp;
4672a6abeebSBaptiste Daroussin *fp-- = c;
4682a6abeebSBaptiste Daroussin }
4692a6abeebSBaptiste Daroussin t = (const wchar_t *)tr;
4702a6abeebSBaptiste Daroussin }
4712a6abeebSBaptiste Daroussin
4722a6abeebSBaptiste Daroussin if (direc & DIRECTIVE_POSITION) {
4732a6abeebSBaptiste Daroussin while (*t || state) {
4742a6abeebSBaptiste Daroussin _collate_lookup(table, t, &len, &pri, pass, &state);
4752a6abeebSBaptiste Daroussin t += len;
4762a6abeebSBaptiste Daroussin if (pri <= 0) {
4772a6abeebSBaptiste Daroussin if (pri < 0) {
4782a6abeebSBaptiste Daroussin errno = EINVAL;
4792a6abeebSBaptiste Daroussin goto fail;
4802a6abeebSBaptiste Daroussin }
481dee0bbbdSBaptiste Daroussin state = NULL;
4822a6abeebSBaptiste Daroussin pri = COLLATE_MAX_PRIORITY;
4832a6abeebSBaptiste Daroussin }
4842a6abeebSBaptiste Daroussin if (room) {
4852a6abeebSBaptiste Daroussin *xf++ = pri;
4862a6abeebSBaptiste Daroussin room--;
4872a6abeebSBaptiste Daroussin }
4882a6abeebSBaptiste Daroussin want++;
4892a6abeebSBaptiste Daroussin need = want;
4902a6abeebSBaptiste Daroussin }
4912a6abeebSBaptiste Daroussin } else {
4922a6abeebSBaptiste Daroussin while (*t || state) {
4932a6abeebSBaptiste Daroussin _collate_lookup(table, t, &len, &pri, pass, &state);
4942a6abeebSBaptiste Daroussin t += len;
4952a6abeebSBaptiste Daroussin if (pri <= 0) {
4962a6abeebSBaptiste Daroussin if (pri < 0) {
4972a6abeebSBaptiste Daroussin errno = EINVAL;
4982a6abeebSBaptiste Daroussin goto fail;
4992a6abeebSBaptiste Daroussin }
500dee0bbbdSBaptiste Daroussin state = NULL;
5012a6abeebSBaptiste Daroussin continue;
5022a6abeebSBaptiste Daroussin }
5032a6abeebSBaptiste Daroussin if (room) {
5042a6abeebSBaptiste Daroussin *xf++ = pri;
5052a6abeebSBaptiste Daroussin room--;
5062a6abeebSBaptiste Daroussin }
5072a6abeebSBaptiste Daroussin want++;
5082a6abeebSBaptiste Daroussin need = want;
5092a6abeebSBaptiste Daroussin }
5102a6abeebSBaptiste Daroussin }
5112a6abeebSBaptiste Daroussin }
5122a6abeebSBaptiste Daroussin free(tr);
5132a6abeebSBaptiste Daroussin return (need);
5142a6abeebSBaptiste Daroussin
5152a6abeebSBaptiste Daroussin fail:
5162a6abeebSBaptiste Daroussin free(tr);
5172a6abeebSBaptiste Daroussin return ((size_t)(-1));
5182a6abeebSBaptiste Daroussin }
5192a6abeebSBaptiste Daroussin
5202a6abeebSBaptiste Daroussin /*
5212a6abeebSBaptiste Daroussin * In the non-POSIX case, we transform each character into a string of
5222a6abeebSBaptiste Daroussin * characters representing the character's priority. Since char is usually
5232a6abeebSBaptiste Daroussin * signed, we are limited by 7 bits per byte. To avoid zero, we need to add
5242a6abeebSBaptiste Daroussin * XFRM_OFFSET, so we can't use a full 7 bits. For simplicity, we choose 6
5252a6abeebSBaptiste Daroussin * bits per byte.
5262a6abeebSBaptiste Daroussin *
5272a6abeebSBaptiste Daroussin * It turns out that we sometimes have real priorities that are
5282a6abeebSBaptiste Daroussin * 31-bits wide. (But: be careful using priorities where the high
5292a6abeebSBaptiste Daroussin * order bit is set -- i.e. the priority is negative. The sort order
5302a6abeebSBaptiste Daroussin * may be surprising!)
5312a6abeebSBaptiste Daroussin *
5322a6abeebSBaptiste Daroussin * TODO: This would be a good area to optimize somewhat. It turns out
5332a6abeebSBaptiste Daroussin * that real prioririties *except for the last UNDEFINED pass* are generally
5342a6abeebSBaptiste Daroussin * very small. We need the localedef code to precalculate the max
5352a6abeebSBaptiste Daroussin * priority for us, and ideally also give us a mask, and then we could
5362a6abeebSBaptiste Daroussin * severely limit what we expand to.
5372a6abeebSBaptiste Daroussin */
5382a6abeebSBaptiste Daroussin #define XFRM_BYTES 6
5392a6abeebSBaptiste Daroussin #define XFRM_OFFSET ('0') /* make all printable characters */
5402a6abeebSBaptiste Daroussin #define XFRM_SHIFT 6
5412a6abeebSBaptiste Daroussin #define XFRM_MASK ((1 << XFRM_SHIFT) - 1)
5422a6abeebSBaptiste Daroussin #define XFRM_SEP ('.') /* chosen to be less than XFRM_OFFSET */
5432a6abeebSBaptiste Daroussin
5442a6abeebSBaptiste Daroussin static int
xfrm(struct xlocale_collate * table,unsigned char * p,int pri,int pass)5452a6abeebSBaptiste Daroussin xfrm(struct xlocale_collate *table, unsigned char *p, int pri, int pass)
546926f20c9SAndrey A. Chernov {
5472a6abeebSBaptiste Daroussin /* we use unsigned to ensure zero fill on right shift */
5484644f9beSYuri Pankov uint32_t val = (uint32_t)table->info->pri_count[pass];
5492a6abeebSBaptiste Daroussin int nc = 0;
550926f20c9SAndrey A. Chernov
5512a6abeebSBaptiste Daroussin while (val) {
5522a6abeebSBaptiste Daroussin *p = (pri & XFRM_MASK) + XFRM_OFFSET;
5532a6abeebSBaptiste Daroussin pri >>= XFRM_SHIFT;
5542a6abeebSBaptiste Daroussin val >>= XFRM_SHIFT;
5552a6abeebSBaptiste Daroussin p++;
5562a6abeebSBaptiste Daroussin nc++;
5572a6abeebSBaptiste Daroussin }
5582a6abeebSBaptiste Daroussin return (nc);
559926f20c9SAndrey A. Chernov }
560926f20c9SAndrey A. Chernov
5612a6abeebSBaptiste Daroussin size_t
_collate_sxfrm(struct xlocale_collate * table,const wchar_t * src,char * xf,size_t room)5622a6abeebSBaptiste Daroussin _collate_sxfrm(struct xlocale_collate *table, const wchar_t *src, char *xf,
5632a6abeebSBaptiste Daroussin size_t room)
564c3d0cca4SAndrey A. Chernov {
5652a6abeebSBaptiste Daroussin int pri;
5662a6abeebSBaptiste Daroussin int len;
5672a6abeebSBaptiste Daroussin const wchar_t *t;
5682a6abeebSBaptiste Daroussin wchar_t *tr = NULL;
5692a6abeebSBaptiste Daroussin int direc;
5702a6abeebSBaptiste Daroussin int pass;
5712a6abeebSBaptiste Daroussin const int32_t *state;
5722a6abeebSBaptiste Daroussin size_t want = 0;
5732a6abeebSBaptiste Daroussin size_t need = 0;
5742a6abeebSBaptiste Daroussin int b;
5752a6abeebSBaptiste Daroussin uint8_t buf[XFRM_BYTES];
576332fe837SBaptiste Daroussin int ndir = table->info->directive_count;
577c3d0cca4SAndrey A. Chernov
578332fe837SBaptiste Daroussin assert(src);
579332fe837SBaptiste Daroussin
580332fe837SBaptiste Daroussin for (pass = 0; pass <= ndir; pass++) {
5812a6abeebSBaptiste Daroussin
5822a6abeebSBaptiste Daroussin state = NULL;
5832a6abeebSBaptiste Daroussin
5842a6abeebSBaptiste Daroussin if (pass != 0) {
5852a6abeebSBaptiste Daroussin /* insert level separator from the previous pass */
5862a6abeebSBaptiste Daroussin if (room) {
5872a6abeebSBaptiste Daroussin *xf++ = XFRM_SEP;
5882a6abeebSBaptiste Daroussin room--;
589c3d0cca4SAndrey A. Chernov }
5902a6abeebSBaptiste Daroussin want++;
5912a6abeebSBaptiste Daroussin }
5922a6abeebSBaptiste Daroussin
5932a6abeebSBaptiste Daroussin /* special pass for undefined */
594332fe837SBaptiste Daroussin if (pass == ndir) {
5952a6abeebSBaptiste Daroussin direc = DIRECTIVE_FORWARD | DIRECTIVE_UNDEFINED;
5962a6abeebSBaptiste Daroussin } else {
5972a6abeebSBaptiste Daroussin direc = table->info->directive[pass];
5982a6abeebSBaptiste Daroussin }
5992a6abeebSBaptiste Daroussin
6002a6abeebSBaptiste Daroussin t = src;
6012a6abeebSBaptiste Daroussin
6022a6abeebSBaptiste Daroussin if (direc & DIRECTIVE_BACKWARD) {
6032a6abeebSBaptiste Daroussin wchar_t *bp, *fp, c;
6042a6abeebSBaptiste Daroussin free(tr);
6052a6abeebSBaptiste Daroussin if ((tr = wcsdup(t)) == NULL) {
6062a6abeebSBaptiste Daroussin errno = ENOMEM;
6072a6abeebSBaptiste Daroussin goto fail;
6082a6abeebSBaptiste Daroussin }
6092a6abeebSBaptiste Daroussin bp = tr;
6102a6abeebSBaptiste Daroussin fp = tr + wcslen(tr) - 1;
6112a6abeebSBaptiste Daroussin while (bp < fp) {
6122a6abeebSBaptiste Daroussin c = *bp;
6132a6abeebSBaptiste Daroussin *bp++ = *fp;
6142a6abeebSBaptiste Daroussin *fp-- = c;
6152a6abeebSBaptiste Daroussin }
6162a6abeebSBaptiste Daroussin t = (const wchar_t *)tr;
6172a6abeebSBaptiste Daroussin }
6182a6abeebSBaptiste Daroussin
6192a6abeebSBaptiste Daroussin if (direc & DIRECTIVE_POSITION) {
6202a6abeebSBaptiste Daroussin while (*t || state) {
6212a6abeebSBaptiste Daroussin
6222a6abeebSBaptiste Daroussin _collate_lookup(table, t, &len, &pri, pass, &state);
6232a6abeebSBaptiste Daroussin t += len;
6242a6abeebSBaptiste Daroussin if (pri <= 0) {
6252a6abeebSBaptiste Daroussin if (pri < 0) {
6262a6abeebSBaptiste Daroussin errno = EINVAL;
6272a6abeebSBaptiste Daroussin goto fail;
6282a6abeebSBaptiste Daroussin }
629dee0bbbdSBaptiste Daroussin state = NULL;
6302a6abeebSBaptiste Daroussin pri = COLLATE_MAX_PRIORITY;
6312a6abeebSBaptiste Daroussin }
6322a6abeebSBaptiste Daroussin
6332a6abeebSBaptiste Daroussin b = xfrm(table, buf, pri, pass);
6342a6abeebSBaptiste Daroussin want += b;
6352a6abeebSBaptiste Daroussin if (room) {
6362a6abeebSBaptiste Daroussin while (b) {
6372a6abeebSBaptiste Daroussin b--;
6382a6abeebSBaptiste Daroussin if (room) {
6392a6abeebSBaptiste Daroussin *xf++ = buf[b];
6402a6abeebSBaptiste Daroussin room--;
6412a6abeebSBaptiste Daroussin }
6422a6abeebSBaptiste Daroussin }
6432a6abeebSBaptiste Daroussin }
6442a6abeebSBaptiste Daroussin need = want;
6452a6abeebSBaptiste Daroussin }
6462a6abeebSBaptiste Daroussin } else {
6472a6abeebSBaptiste Daroussin while (*t || state) {
6482a6abeebSBaptiste Daroussin _collate_lookup(table, t, &len, &pri, pass, &state);
6492a6abeebSBaptiste Daroussin t += len;
6502a6abeebSBaptiste Daroussin if (pri <= 0) {
6512a6abeebSBaptiste Daroussin if (pri < 0) {
6522a6abeebSBaptiste Daroussin errno = EINVAL;
6532a6abeebSBaptiste Daroussin goto fail;
6542a6abeebSBaptiste Daroussin }
655dee0bbbdSBaptiste Daroussin state = NULL;
6562a6abeebSBaptiste Daroussin continue;
6572a6abeebSBaptiste Daroussin }
6582a6abeebSBaptiste Daroussin
6592a6abeebSBaptiste Daroussin b = xfrm(table, buf, pri, pass);
6602a6abeebSBaptiste Daroussin want += b;
6612a6abeebSBaptiste Daroussin if (room) {
6622a6abeebSBaptiste Daroussin
6632a6abeebSBaptiste Daroussin while (b) {
6642a6abeebSBaptiste Daroussin b--;
6652a6abeebSBaptiste Daroussin if (room) {
6662a6abeebSBaptiste Daroussin *xf++ = buf[b];
6672a6abeebSBaptiste Daroussin room--;
6682a6abeebSBaptiste Daroussin }
6692a6abeebSBaptiste Daroussin }
6702a6abeebSBaptiste Daroussin }
6712a6abeebSBaptiste Daroussin need = want;
6722a6abeebSBaptiste Daroussin }
6732a6abeebSBaptiste Daroussin }
6742a6abeebSBaptiste Daroussin }
6752a6abeebSBaptiste Daroussin free(tr);
6762a6abeebSBaptiste Daroussin return (need);
6772a6abeebSBaptiste Daroussin
6782a6abeebSBaptiste Daroussin fail:
6792a6abeebSBaptiste Daroussin free(tr);
6802a6abeebSBaptiste Daroussin return ((size_t)(-1));
6812a6abeebSBaptiste Daroussin }
6822a6abeebSBaptiste Daroussin
6832a6abeebSBaptiste Daroussin /*
6842a6abeebSBaptiste Daroussin * __collate_equiv_value returns the primary collation value for the given
6852a6abeebSBaptiste Daroussin * collating symbol specified by str and len. Zero or negative is returned
6862a6abeebSBaptiste Daroussin * if the collating symbol was not found. This function is used by bracket
6872a6abeebSBaptiste Daroussin * code in the TRE regex library.
6882a6abeebSBaptiste Daroussin */
6892a6abeebSBaptiste Daroussin int
__collate_equiv_value(locale_t locale,const wchar_t * str,size_t len)6902a6abeebSBaptiste Daroussin __collate_equiv_value(locale_t locale, const wchar_t *str, size_t len)
6912a6abeebSBaptiste Daroussin {
6922a6abeebSBaptiste Daroussin int32_t e;
6932a6abeebSBaptiste Daroussin
6942a6abeebSBaptiste Daroussin if (len < 1 || len >= COLLATE_STR_LEN)
6952a6abeebSBaptiste Daroussin return (-1);
6962a6abeebSBaptiste Daroussin
6972a6abeebSBaptiste Daroussin FIX_LOCALE(locale);
6982a6abeebSBaptiste Daroussin struct xlocale_collate *table =
6992a6abeebSBaptiste Daroussin (struct xlocale_collate*)locale->components[XLC_COLLATE];
7002a6abeebSBaptiste Daroussin
7012a6abeebSBaptiste Daroussin if (table->__collate_load_error)
7022a6abeebSBaptiste Daroussin return ((len == 1 && *str <= UCHAR_MAX) ? *str : -1);
7032a6abeebSBaptiste Daroussin
7042a6abeebSBaptiste Daroussin if (len == 1) {
7052a6abeebSBaptiste Daroussin e = -1;
7062a6abeebSBaptiste Daroussin if (*str <= UCHAR_MAX)
7072a6abeebSBaptiste Daroussin e = table->char_pri_table[*str].pri[0];
7084644f9beSYuri Pankov else if (table->info->large_count > 0) {
7092a6abeebSBaptiste Daroussin collate_large_t *match_large;
7102a6abeebSBaptiste Daroussin match_large = largesearch(table, *str);
7112a6abeebSBaptiste Daroussin if (match_large)
7122a6abeebSBaptiste Daroussin e = match_large->pri.pri[0];
7132a6abeebSBaptiste Daroussin }
7142a6abeebSBaptiste Daroussin if (e == 0)
7152a6abeebSBaptiste Daroussin return (1);
7162a6abeebSBaptiste Daroussin return (e > 0 ? e : 0);
7172a6abeebSBaptiste Daroussin }
7184644f9beSYuri Pankov if (table->info->chain_count > 0) {
7192a6abeebSBaptiste Daroussin wchar_t name[COLLATE_STR_LEN];
7202a6abeebSBaptiste Daroussin collate_chain_t *match_chain;
7212a6abeebSBaptiste Daroussin int clen;
7222a6abeebSBaptiste Daroussin
7232a6abeebSBaptiste Daroussin wcsncpy (name, str, len);
7242a6abeebSBaptiste Daroussin name[len] = 0;
7252a6abeebSBaptiste Daroussin match_chain = chainsearch(table, name, &clen);
7262a6abeebSBaptiste Daroussin if (match_chain) {
7272a6abeebSBaptiste Daroussin e = match_chain->pri[0];
7282a6abeebSBaptiste Daroussin if (e == 0)
7292a6abeebSBaptiste Daroussin return (1);
7302a6abeebSBaptiste Daroussin return (e < 0 ? -e : e);
7312a6abeebSBaptiste Daroussin }
7322a6abeebSBaptiste Daroussin }
7332a6abeebSBaptiste Daroussin return (0);
7342a6abeebSBaptiste Daroussin }
735