1c3d0cca4SAndrey A. Chernov /*- 2*4d846d26SWarner 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 39333fc21eSDavid E. O'Brien #include <sys/cdefs.h> 40333fc21eSDavid E. O'Brien __FBSDID("$FreeBSD$"); 41333fc21eSDavid E. O'Brien 42d201fe46SDaniel Eischen #include "namespace.h" 43c25f5140SBaptiste Daroussin 44c25f5140SBaptiste Daroussin #include <sys/types.h> 45c25f5140SBaptiste Daroussin #include <sys/stat.h> 46c25f5140SBaptiste Daroussin #include <sys/mman.h> 47c25f5140SBaptiste Daroussin 48332fe837SBaptiste Daroussin #include <assert.h> 49c3d0cca4SAndrey A. Chernov #include <stdio.h> 50c3d0cca4SAndrey A. Chernov #include <stdlib.h> 51c3d0cca4SAndrey A. Chernov #include <string.h> 522a6abeebSBaptiste Daroussin #include <wchar.h> 53926f20c9SAndrey A. Chernov #include <errno.h> 54926f20c9SAndrey A. Chernov #include <unistd.h> 552a6abeebSBaptiste Daroussin #include <fcntl.h> 56d201fe46SDaniel Eischen #include "un-namespace.h" 57d201fe46SDaniel Eischen 58c3d0cca4SAndrey A. Chernov #include "collate.h" 5963407d34SAndrey A. Chernov #include "setlocale.h" 6076692b80SAndrey A. Chernov #include "ldpart.h" 61536451f9SBaptiste Daroussin #include "libc_private.h" 62c3d0cca4SAndrey A. Chernov 633c87aa1dSDavid Chisnall struct xlocale_collate __xlocale_global_collate = { 642a6abeebSBaptiste Daroussin {{0}, "C"}, 1, 0, 0, 0 653c87aa1dSDavid Chisnall }; 663c87aa1dSDavid Chisnall 673c87aa1dSDavid Chisnall struct xlocale_collate __xlocale_C_collate = { 682a6abeebSBaptiste Daroussin {{0}, "C"}, 1, 0, 0, 0 693c87aa1dSDavid Chisnall }; 70c3d0cca4SAndrey A. Chernov 71269dea90SYuri Pankov struct xlocale_collate __xlocale_POSIX_collate = { 72269dea90SYuri Pankov {{0}, "POSIX"}, 1, 0, 0, 0 73269dea90SYuri Pankov }; 74269dea90SYuri Pankov 75269dea90SYuri Pankov struct xlocale_collate __xlocale_CUTF8_collate = { 76269dea90SYuri Pankov {{0}, "C.UTF-8"}, 1, 0, 0, 0 77269dea90SYuri Pankov }; 78269dea90SYuri Pankov 79a6d2922cSBaptiste Daroussin static int 803c87aa1dSDavid Chisnall __collate_load_tables_l(const char *encoding, struct xlocale_collate *table); 813c87aa1dSDavid Chisnall 823c87aa1dSDavid Chisnall static void 833c87aa1dSDavid Chisnall destruct_collate(void *t) 843c87aa1dSDavid Chisnall { 853c87aa1dSDavid Chisnall struct xlocale_collate *table = t; 862a6abeebSBaptiste Daroussin if (table->map && (table->maplen > 0)) { 872a6abeebSBaptiste Daroussin (void) munmap(table->map, table->maplen); 883c87aa1dSDavid Chisnall } 893c87aa1dSDavid Chisnall free(t); 903c87aa1dSDavid Chisnall } 913c87aa1dSDavid Chisnall 923c87aa1dSDavid Chisnall void * 932a6abeebSBaptiste Daroussin __collate_load(const char *encoding, __unused locale_t unused) 943c87aa1dSDavid Chisnall { 95269dea90SYuri Pankov if (strcmp(encoding, "C") == 0) 96a8be0611SKonstantin Belousov return (&__xlocale_C_collate); 97269dea90SYuri Pankov else if (strcmp(encoding, "POSIX") == 0) 98269dea90SYuri Pankov return (&__xlocale_POSIX_collate); 99269dea90SYuri Pankov else if (strcmp(encoding, "C.UTF-8") == 0) 100269dea90SYuri Pankov return (&__xlocale_CUTF8_collate); 101269dea90SYuri Pankov 102a8be0611SKonstantin Belousov struct xlocale_collate *table = calloc(sizeof(struct xlocale_collate), 103a8be0611SKonstantin Belousov 1); 104b8ad908aSKonstantin Belousov if (table == NULL) 105b8ad908aSKonstantin Belousov return (NULL); 1063c87aa1dSDavid Chisnall table->header.header.destructor = destruct_collate; 107a8be0611SKonstantin Belousov 108a8be0611SKonstantin Belousov /* 109a8be0611SKonstantin Belousov * FIXME: Make sure that _LDP_CACHE is never returned. We 110a8be0611SKonstantin Belousov * should be doing the caching outside of this section. 111a8be0611SKonstantin Belousov */ 1123c87aa1dSDavid Chisnall if (__collate_load_tables_l(encoding, table) != _LDP_LOADED) { 1133c87aa1dSDavid Chisnall xlocale_release(table); 114a8be0611SKonstantin Belousov return (NULL); 1153c87aa1dSDavid Chisnall } 116a8be0611SKonstantin Belousov return (table); 1173c87aa1dSDavid Chisnall } 1183c87aa1dSDavid Chisnall 1193c87aa1dSDavid Chisnall /** 1203c87aa1dSDavid Chisnall * Load the collation tables for the specified encoding into the global table. 1213c87aa1dSDavid Chisnall */ 1223c87aa1dSDavid Chisnall int 12376692b80SAndrey A. Chernov __collate_load_tables(const char *encoding) 124c3d0cca4SAndrey A. Chernov { 1255e4bbc69SBaptiste Daroussin 1265e4bbc69SBaptiste Daroussin return (__collate_load_tables_l(encoding, &__xlocale_global_collate)); 1273c87aa1dSDavid Chisnall } 1283c87aa1dSDavid Chisnall 12957e64236SMark Johnston static int 1303c87aa1dSDavid Chisnall __collate_load_tables_l(const char *encoding, struct xlocale_collate *table) 1313c87aa1dSDavid Chisnall { 1322a6abeebSBaptiste Daroussin int i, chains, z; 133b89704ceSBaptiste Daroussin char *buf; 1342a6abeebSBaptiste Daroussin char *TMP; 1352a6abeebSBaptiste Daroussin char *map; 1362a6abeebSBaptiste Daroussin collate_info_t *info; 1372a6abeebSBaptiste Daroussin struct stat sbuf; 1382a6abeebSBaptiste Daroussin int fd; 139c3d0cca4SAndrey A. Chernov 140332fe837SBaptiste Daroussin table->__collate_load_error = 1; 141332fe837SBaptiste Daroussin 14276692b80SAndrey A. Chernov /* 'encoding' must be already checked. */ 143dd7c41a3SYuri Pankov if (strcmp(encoding, "C") == 0 || strcmp(encoding, "POSIX") == 0 || 144dd7c41a3SYuri Pankov strncmp(encoding, "C.", 2) == 0) { 14576692b80SAndrey A. Chernov return (_LDP_CACHE); 146377da8e8SAndrey A. Chernov } 14776692b80SAndrey A. Chernov 148dc8507e1SBryan Drewery if (asprintf(&buf, "%s/%s/LC_COLLATE", _PathLocale, encoding) == -1) 149b89704ceSBaptiste Daroussin return (_LDP_ERROR); 15076692b80SAndrey A. Chernov 15198bfb9daSMark Johnston if ((fd = _open(buf, O_RDONLY | O_CLOEXEC)) < 0) { 15228a20bb3SBaptiste Daroussin free(buf); 1532a6abeebSBaptiste Daroussin return (_LDP_ERROR); 15428a20bb3SBaptiste Daroussin } 155b89704ceSBaptiste Daroussin free(buf); 1562a6abeebSBaptiste Daroussin if (_fstat(fd, &sbuf) < 0) { 1572a6abeebSBaptiste Daroussin (void) _close(fd); 1588e52da4dSAndrey A. Chernov return (_LDP_ERROR); 1598e52da4dSAndrey A. Chernov } 160cc7edd25SThomas Munro if (sbuf.st_size < (COLLATE_FMT_VERSION_LEN + 161cc7edd25SThomas Munro XLOCALE_DEF_VERSION_LEN + 162cc7edd25SThomas Munro sizeof (info))) { 1632a6abeebSBaptiste Daroussin (void) _close(fd); 1642a6abeebSBaptiste Daroussin errno = EINVAL; 1658e52da4dSAndrey A. Chernov return (_LDP_ERROR); 1668e52da4dSAndrey A. Chernov } 1672a6abeebSBaptiste Daroussin map = mmap(NULL, sbuf.st_size, PROT_READ, MAP_PRIVATE, fd, 0); 1682a6abeebSBaptiste Daroussin (void) _close(fd); 16957e64236SMark Johnston if ((TMP = map) == MAP_FAILED) { 1708e52da4dSAndrey A. Chernov return (_LDP_ERROR); 1718e52da4dSAndrey A. Chernov } 1722a6abeebSBaptiste Daroussin 173cc7edd25SThomas Munro if (strncmp(TMP, COLLATE_FMT_VERSION, COLLATE_FMT_VERSION_LEN) != 0) { 1742a6abeebSBaptiste Daroussin (void) munmap(map, sbuf.st_size); 1752a6abeebSBaptiste Daroussin errno = EINVAL; 1768e52da4dSAndrey A. Chernov return (_LDP_ERROR); 1778e52da4dSAndrey A. Chernov } 178cc7edd25SThomas Munro TMP += COLLATE_FMT_VERSION_LEN; 179cc7edd25SThomas Munro strlcat(table->header.version, TMP, sizeof (table->header.version)); 180cc7edd25SThomas Munro TMP += XLOCALE_DEF_VERSION_LEN; 1812a6abeebSBaptiste Daroussin 1822a6abeebSBaptiste Daroussin info = (void *)TMP; 1832a6abeebSBaptiste Daroussin TMP += sizeof (*info); 1842a6abeebSBaptiste Daroussin 1852a6abeebSBaptiste Daroussin if ((info->directive_count < 1) || 1862a6abeebSBaptiste Daroussin (info->directive_count >= COLL_WEIGHTS_MAX) || 1874644f9beSYuri Pankov ((chains = info->chain_count) < 0)) { 1882a6abeebSBaptiste Daroussin (void) munmap(map, sbuf.st_size); 1892a6abeebSBaptiste Daroussin errno = EINVAL; 1902a6abeebSBaptiste Daroussin return (_LDP_ERROR); 1912a6abeebSBaptiste Daroussin } 1922a6abeebSBaptiste Daroussin 1932a6abeebSBaptiste Daroussin i = (sizeof (collate_char_t) * (UCHAR_MAX + 1)) + 1942a6abeebSBaptiste Daroussin (sizeof (collate_chain_t) * chains) + 1954644f9beSYuri Pankov (sizeof (collate_large_t) * info->large_count); 196332fe837SBaptiste Daroussin for (z = 0; z < info->directive_count; z++) { 1974644f9beSYuri Pankov i += sizeof (collate_subst_t) * info->subst_count[z]; 1982a6abeebSBaptiste Daroussin } 1992a6abeebSBaptiste Daroussin if (i != (sbuf.st_size - (TMP - map))) { 2002a6abeebSBaptiste Daroussin (void) munmap(map, sbuf.st_size); 2012a6abeebSBaptiste Daroussin errno = EINVAL; 2022a6abeebSBaptiste Daroussin return (_LDP_ERROR); 2032a6abeebSBaptiste Daroussin } 2042a6abeebSBaptiste Daroussin 20557e64236SMark Johnston if (table->map && (table->maplen > 0)) { 20657e64236SMark Johnston (void) munmap(table->map, table->maplen); 20757e64236SMark Johnston } 20857e64236SMark Johnston table->map = map; 20957e64236SMark Johnston table->maplen = sbuf.st_size; 210332fe837SBaptiste Daroussin table->info = info; 2112a6abeebSBaptiste Daroussin table->char_pri_table = (void *)TMP; 2122a6abeebSBaptiste Daroussin TMP += sizeof (collate_char_t) * (UCHAR_MAX + 1); 2132a6abeebSBaptiste Daroussin 2142a6abeebSBaptiste Daroussin for (z = 0; z < info->directive_count; z++) { 2154644f9beSYuri Pankov if (info->subst_count[z] > 0) { 2162a6abeebSBaptiste Daroussin table->subst_table[z] = (void *)TMP; 2174644f9beSYuri Pankov TMP += info->subst_count[z] * sizeof (collate_subst_t); 2182a6abeebSBaptiste Daroussin } else { 2192a6abeebSBaptiste Daroussin table->subst_table[z] = NULL; 2202a6abeebSBaptiste Daroussin } 2212a6abeebSBaptiste Daroussin } 2222a6abeebSBaptiste Daroussin 2232a6abeebSBaptiste Daroussin if (chains > 0) { 2242a6abeebSBaptiste Daroussin table->chain_pri_table = (void *)TMP; 2252a6abeebSBaptiste Daroussin TMP += chains * sizeof (collate_chain_t); 2268e52da4dSAndrey A. Chernov } else 2272a6abeebSBaptiste Daroussin table->chain_pri_table = NULL; 2284644f9beSYuri Pankov if (info->large_count > 0) 2292a6abeebSBaptiste Daroussin table->large_pri_table = (void *)TMP; 2302a6abeebSBaptiste Daroussin else 2312a6abeebSBaptiste Daroussin table->large_pri_table = NULL; 2328e52da4dSAndrey A. Chernov 233bb4317bfSDavid Chisnall table->__collate_load_error = 0; 23476692b80SAndrey A. Chernov return (_LDP_LOADED); 235c3d0cca4SAndrey A. Chernov } 236c3d0cca4SAndrey A. Chernov 237332fe837SBaptiste Daroussin static const int32_t * 2382a6abeebSBaptiste Daroussin substsearch(struct xlocale_collate *table, const wchar_t key, int pass) 2392a6abeebSBaptiste Daroussin { 240332fe837SBaptiste Daroussin const collate_subst_t *p; 2414644f9beSYuri Pankov int n = table->info->subst_count[pass]; 2422a6abeebSBaptiste Daroussin 2432a6abeebSBaptiste Daroussin if (n == 0) 2442a6abeebSBaptiste Daroussin return (NULL); 2452a6abeebSBaptiste Daroussin 2462a6abeebSBaptiste Daroussin if (pass >= table->info->directive_count) 2472a6abeebSBaptiste Daroussin return (NULL); 2482a6abeebSBaptiste Daroussin 2492a6abeebSBaptiste Daroussin if (!(key & COLLATE_SUBST_PRIORITY)) 2502a6abeebSBaptiste Daroussin return (NULL); 2512a6abeebSBaptiste Daroussin 2522a6abeebSBaptiste Daroussin p = table->subst_table[pass] + (key & ~COLLATE_SUBST_PRIORITY); 2534644f9beSYuri Pankov assert(p->key == key); 25477bc2a1cSRuslan Bukin 2552a6abeebSBaptiste Daroussin return (p->pri); 256c3d0cca4SAndrey A. Chernov } 2572a6abeebSBaptiste Daroussin 2582a6abeebSBaptiste Daroussin static collate_chain_t * 2592a6abeebSBaptiste Daroussin chainsearch(struct xlocale_collate *table, const wchar_t *key, int *len) 2602a6abeebSBaptiste Daroussin { 26176e6db68SBaptiste Daroussin int low = 0; 2624644f9beSYuri Pankov int high = table->info->chain_count - 1; 2632a6abeebSBaptiste Daroussin int next, compar, l; 2642a6abeebSBaptiste Daroussin collate_chain_t *p; 26576e6db68SBaptiste Daroussin collate_chain_t *tab = table->chain_pri_table; 2662a6abeebSBaptiste Daroussin 26776e6db68SBaptiste Daroussin if (high < 0) 2682a6abeebSBaptiste Daroussin return (NULL); 2692a6abeebSBaptiste Daroussin 2702a6abeebSBaptiste Daroussin while (low <= high) { 2712a6abeebSBaptiste Daroussin next = (low + high) / 2; 2722a6abeebSBaptiste Daroussin p = tab + next; 2734644f9beSYuri Pankov compar = *key - *p->str; 2742a6abeebSBaptiste Daroussin if (compar == 0) { 2752a6abeebSBaptiste Daroussin l = wcsnlen(p->str, COLLATE_STR_LEN); 2762a6abeebSBaptiste Daroussin compar = wcsncmp(key, p->str, l); 2772a6abeebSBaptiste Daroussin if (compar == 0) { 2782a6abeebSBaptiste Daroussin *len = l; 2792a6abeebSBaptiste Daroussin return (p); 280c3d0cca4SAndrey A. Chernov } 2812a6abeebSBaptiste Daroussin } 2822a6abeebSBaptiste Daroussin if (compar > 0) 2832a6abeebSBaptiste Daroussin low = next + 1; 2842a6abeebSBaptiste Daroussin else 2852a6abeebSBaptiste Daroussin high = next - 1; 2862a6abeebSBaptiste Daroussin } 2872a6abeebSBaptiste Daroussin return (NULL); 2882a6abeebSBaptiste Daroussin } 2892a6abeebSBaptiste Daroussin 2902a6abeebSBaptiste Daroussin static collate_large_t * 2912a6abeebSBaptiste Daroussin largesearch(struct xlocale_collate *table, const wchar_t key) 2922a6abeebSBaptiste Daroussin { 2932a6abeebSBaptiste Daroussin int low = 0; 2944644f9beSYuri Pankov int high = table->info->large_count - 1; 2952a6abeebSBaptiste Daroussin int next, compar; 2962a6abeebSBaptiste Daroussin collate_large_t *p; 2972a6abeebSBaptiste Daroussin collate_large_t *tab = table->large_pri_table; 2982a6abeebSBaptiste Daroussin 29976e6db68SBaptiste Daroussin if (high < 0) 3002a6abeebSBaptiste Daroussin return (NULL); 3012a6abeebSBaptiste Daroussin 3022a6abeebSBaptiste Daroussin while (low <= high) { 3032a6abeebSBaptiste Daroussin next = (low + high) / 2; 3042a6abeebSBaptiste Daroussin p = tab + next; 3054644f9beSYuri Pankov compar = key - p->val; 3062a6abeebSBaptiste Daroussin if (compar == 0) 3072a6abeebSBaptiste Daroussin return (p); 3082a6abeebSBaptiste Daroussin if (compar > 0) 3092a6abeebSBaptiste Daroussin low = next + 1; 3102a6abeebSBaptiste Daroussin else 3112a6abeebSBaptiste Daroussin high = next - 1; 3122a6abeebSBaptiste Daroussin } 3132a6abeebSBaptiste Daroussin return (NULL); 314c3d0cca4SAndrey A. Chernov } 315c3d0cca4SAndrey A. Chernov 316c3d0cca4SAndrey A. Chernov void 3172a6abeebSBaptiste Daroussin _collate_lookup(struct xlocale_collate *table, const wchar_t *t, int *len, 3182a6abeebSBaptiste Daroussin int *pri, int which, const int **state) 319c3d0cca4SAndrey A. Chernov { 3202a6abeebSBaptiste Daroussin collate_chain_t *p2; 3212a6abeebSBaptiste Daroussin collate_large_t *match; 3222a6abeebSBaptiste Daroussin int p, l; 3232a6abeebSBaptiste Daroussin const int *sptr; 324c3d0cca4SAndrey A. Chernov 3252a6abeebSBaptiste Daroussin /* 3262a6abeebSBaptiste Daroussin * If this is the "last" pass for the UNDEFINED, then 3272a6abeebSBaptiste Daroussin * we just return the priority itself. 3282a6abeebSBaptiste Daroussin */ 3292a6abeebSBaptiste Daroussin if (which >= table->info->directive_count) { 3302a6abeebSBaptiste Daroussin *pri = *t; 331c3d0cca4SAndrey A. Chernov *len = 1; 3322a6abeebSBaptiste Daroussin *state = NULL; 333c3d0cca4SAndrey A. Chernov return; 334c3d0cca4SAndrey A. Chernov } 3352a6abeebSBaptiste Daroussin 3362a6abeebSBaptiste Daroussin /* 3372a6abeebSBaptiste Daroussin * If we have remaining substitution data from a previous 3382a6abeebSBaptiste Daroussin * call, consume it first. 3392a6abeebSBaptiste Daroussin */ 3402a6abeebSBaptiste Daroussin if ((sptr = *state) != NULL) { 3412a6abeebSBaptiste Daroussin *pri = *sptr; 3422a6abeebSBaptiste Daroussin sptr++; 343dee0bbbdSBaptiste Daroussin if ((sptr == *state) || (sptr == NULL)) 34476e6db68SBaptiste Daroussin *state = NULL; 34576e6db68SBaptiste Daroussin else 34676e6db68SBaptiste Daroussin *state = sptr; 3472a6abeebSBaptiste Daroussin *len = 0; 3482a6abeebSBaptiste Daroussin return; 349c3d0cca4SAndrey A. Chernov } 350c3d0cca4SAndrey A. Chernov 3512a6abeebSBaptiste Daroussin /* No active substitutions */ 3522a6abeebSBaptiste Daroussin *len = 1; 3532a6abeebSBaptiste Daroussin 3542a6abeebSBaptiste Daroussin /* 35532223c1bSPedro F. Giffuni * Check for composites such as diphthongs that collate as a 3562a6abeebSBaptiste Daroussin * single element (aka chains or collating-elements). 3572a6abeebSBaptiste Daroussin */ 3582a6abeebSBaptiste Daroussin if (((p2 = chainsearch(table, t, &l)) != NULL) && 3592a6abeebSBaptiste Daroussin ((p = p2->pri[which]) >= 0)) { 3602a6abeebSBaptiste Daroussin 3612a6abeebSBaptiste Daroussin *len = l; 3622a6abeebSBaptiste Daroussin *pri = p; 3632a6abeebSBaptiste Daroussin 3642a6abeebSBaptiste Daroussin } else if (*t <= UCHAR_MAX) { 3652a6abeebSBaptiste Daroussin 3662a6abeebSBaptiste Daroussin /* 3672a6abeebSBaptiste Daroussin * Character is a small (8-bit) character. 3682a6abeebSBaptiste Daroussin * We just look these up directly for speed. 3692a6abeebSBaptiste Daroussin */ 3704644f9beSYuri Pankov *pri = table->char_pri_table[*t].pri[which]; 3712a6abeebSBaptiste Daroussin 3724644f9beSYuri Pankov } else if ((table->info->large_count > 0) && 3732a6abeebSBaptiste Daroussin ((match = largesearch(table, *t)) != NULL)) { 3742a6abeebSBaptiste Daroussin 3752a6abeebSBaptiste Daroussin /* 3762a6abeebSBaptiste Daroussin * Character was found in the extended table. 3772a6abeebSBaptiste Daroussin */ 3784644f9beSYuri Pankov *pri = match->pri.pri[which]; 3792a6abeebSBaptiste Daroussin 3802a6abeebSBaptiste Daroussin } else { 3812a6abeebSBaptiste Daroussin /* 3822a6abeebSBaptiste Daroussin * Character lacks a specific definition. 3832a6abeebSBaptiste Daroussin */ 3842a6abeebSBaptiste Daroussin if (table->info->directive[which] & DIRECTIVE_UNDEFINED) { 3852a6abeebSBaptiste Daroussin /* Mask off sign bit to prevent ordering confusion. */ 3862a6abeebSBaptiste Daroussin *pri = (*t & COLLATE_MAX_PRIORITY); 3872a6abeebSBaptiste Daroussin } else { 3884644f9beSYuri Pankov *pri = table->info->undef_pri[which]; 3892a6abeebSBaptiste Daroussin } 3902a6abeebSBaptiste Daroussin /* No substitutions for undefined characters! */ 3912a6abeebSBaptiste Daroussin return; 3922a6abeebSBaptiste Daroussin } 3932a6abeebSBaptiste Daroussin 3942a6abeebSBaptiste Daroussin /* 3952a6abeebSBaptiste Daroussin * Try substituting (expanding) the character. We are 3962a6abeebSBaptiste Daroussin * currently doing this *after* the chain compression. I 3972a6abeebSBaptiste Daroussin * think it should not matter, but this way might be slightly 3982a6abeebSBaptiste Daroussin * faster. 3992a6abeebSBaptiste Daroussin * 4002a6abeebSBaptiste Daroussin * We do this after the priority search, as this will help us 4012a6abeebSBaptiste Daroussin * to identify a single key value. In order for this to work, 4022a6abeebSBaptiste Daroussin * its important that the priority assigned to a given element 4032a6abeebSBaptiste Daroussin * to be substituted be unique for that level. The localedef 4042a6abeebSBaptiste Daroussin * code ensures this for us. 4052a6abeebSBaptiste Daroussin */ 4062a6abeebSBaptiste Daroussin if ((sptr = substsearch(table, *pri, which)) != NULL) { 4074644f9beSYuri Pankov if ((*pri = *sptr) > 0) { 4082a6abeebSBaptiste Daroussin sptr++; 4094644f9beSYuri Pankov *state = *sptr ? sptr : NULL; 4102a6abeebSBaptiste Daroussin } 4112a6abeebSBaptiste Daroussin } 4122a6abeebSBaptiste Daroussin 4132a6abeebSBaptiste Daroussin } 4142a6abeebSBaptiste Daroussin 4152a6abeebSBaptiste Daroussin /* 4162a6abeebSBaptiste Daroussin * This is the meaty part of wcsxfrm & strxfrm. Note that it does 4172a6abeebSBaptiste Daroussin * NOT NULL terminate. That is left to the caller. 4182a6abeebSBaptiste Daroussin */ 4192a6abeebSBaptiste Daroussin size_t 4202a6abeebSBaptiste Daroussin _collate_wxfrm(struct xlocale_collate *table, const wchar_t *src, wchar_t *xf, 4212a6abeebSBaptiste Daroussin size_t room) 422c3d0cca4SAndrey A. Chernov { 4232a6abeebSBaptiste Daroussin int pri; 4242a6abeebSBaptiste Daroussin int len; 4252a6abeebSBaptiste Daroussin const wchar_t *t; 4262a6abeebSBaptiste Daroussin wchar_t *tr = NULL; 4272a6abeebSBaptiste Daroussin int direc; 4282a6abeebSBaptiste Daroussin int pass; 4292a6abeebSBaptiste Daroussin const int32_t *state; 4302a6abeebSBaptiste Daroussin size_t want = 0; 4312a6abeebSBaptiste Daroussin size_t need = 0; 432332fe837SBaptiste Daroussin int ndir = table->info->directive_count; 433c3d0cca4SAndrey A. Chernov 434332fe837SBaptiste Daroussin assert(src); 435332fe837SBaptiste Daroussin 436332fe837SBaptiste Daroussin for (pass = 0; pass <= ndir; pass++) { 4372a6abeebSBaptiste Daroussin 4382a6abeebSBaptiste Daroussin state = NULL; 4392a6abeebSBaptiste Daroussin 4402a6abeebSBaptiste Daroussin if (pass != 0) { 4412a6abeebSBaptiste Daroussin /* insert level separator from the previous pass */ 4422a6abeebSBaptiste Daroussin if (room) { 4432a6abeebSBaptiste Daroussin *xf++ = 1; 4442a6abeebSBaptiste Daroussin room--; 4452a6abeebSBaptiste Daroussin } 4462a6abeebSBaptiste Daroussin want++; 447c3d0cca4SAndrey A. Chernov } 448c3d0cca4SAndrey A. Chernov 4492a6abeebSBaptiste Daroussin /* special pass for undefined */ 450332fe837SBaptiste Daroussin if (pass == ndir) { 4512a6abeebSBaptiste Daroussin direc = DIRECTIVE_FORWARD | DIRECTIVE_UNDEFINED; 4522a6abeebSBaptiste Daroussin } else { 4532a6abeebSBaptiste Daroussin direc = table->info->directive[pass]; 4542a6abeebSBaptiste Daroussin } 4552a6abeebSBaptiste Daroussin 4562a6abeebSBaptiste Daroussin t = src; 4572a6abeebSBaptiste Daroussin 4582a6abeebSBaptiste Daroussin if (direc & DIRECTIVE_BACKWARD) { 4592a6abeebSBaptiste Daroussin wchar_t *bp, *fp, c; 4602a6abeebSBaptiste Daroussin free(tr); 4612a6abeebSBaptiste Daroussin if ((tr = wcsdup(t)) == NULL) { 4622a6abeebSBaptiste Daroussin errno = ENOMEM; 4632a6abeebSBaptiste Daroussin goto fail; 4642a6abeebSBaptiste Daroussin } 4652a6abeebSBaptiste Daroussin bp = tr; 4662a6abeebSBaptiste Daroussin fp = tr + wcslen(tr) - 1; 4672a6abeebSBaptiste Daroussin while (bp < fp) { 4682a6abeebSBaptiste Daroussin c = *bp; 4692a6abeebSBaptiste Daroussin *bp++ = *fp; 4702a6abeebSBaptiste Daroussin *fp-- = c; 4712a6abeebSBaptiste Daroussin } 4722a6abeebSBaptiste Daroussin t = (const wchar_t *)tr; 4732a6abeebSBaptiste Daroussin } 4742a6abeebSBaptiste Daroussin 4752a6abeebSBaptiste Daroussin if (direc & DIRECTIVE_POSITION) { 4762a6abeebSBaptiste Daroussin while (*t || state) { 4772a6abeebSBaptiste Daroussin _collate_lookup(table, t, &len, &pri, pass, &state); 4782a6abeebSBaptiste Daroussin t += len; 4792a6abeebSBaptiste Daroussin if (pri <= 0) { 4802a6abeebSBaptiste Daroussin if (pri < 0) { 4812a6abeebSBaptiste Daroussin errno = EINVAL; 4822a6abeebSBaptiste Daroussin goto fail; 4832a6abeebSBaptiste Daroussin } 484dee0bbbdSBaptiste Daroussin state = NULL; 4852a6abeebSBaptiste Daroussin pri = COLLATE_MAX_PRIORITY; 4862a6abeebSBaptiste Daroussin } 4872a6abeebSBaptiste Daroussin if (room) { 4882a6abeebSBaptiste Daroussin *xf++ = pri; 4892a6abeebSBaptiste Daroussin room--; 4902a6abeebSBaptiste Daroussin } 4912a6abeebSBaptiste Daroussin want++; 4922a6abeebSBaptiste Daroussin need = want; 4932a6abeebSBaptiste Daroussin } 4942a6abeebSBaptiste Daroussin } else { 4952a6abeebSBaptiste Daroussin while (*t || state) { 4962a6abeebSBaptiste Daroussin _collate_lookup(table, t, &len, &pri, pass, &state); 4972a6abeebSBaptiste Daroussin t += len; 4982a6abeebSBaptiste Daroussin if (pri <= 0) { 4992a6abeebSBaptiste Daroussin if (pri < 0) { 5002a6abeebSBaptiste Daroussin errno = EINVAL; 5012a6abeebSBaptiste Daroussin goto fail; 5022a6abeebSBaptiste Daroussin } 503dee0bbbdSBaptiste Daroussin state = NULL; 5042a6abeebSBaptiste Daroussin continue; 5052a6abeebSBaptiste Daroussin } 5062a6abeebSBaptiste Daroussin if (room) { 5072a6abeebSBaptiste Daroussin *xf++ = pri; 5082a6abeebSBaptiste Daroussin room--; 5092a6abeebSBaptiste Daroussin } 5102a6abeebSBaptiste Daroussin want++; 5112a6abeebSBaptiste Daroussin need = want; 5122a6abeebSBaptiste Daroussin } 5132a6abeebSBaptiste Daroussin } 5142a6abeebSBaptiste Daroussin } 5152a6abeebSBaptiste Daroussin free(tr); 5162a6abeebSBaptiste Daroussin return (need); 5172a6abeebSBaptiste Daroussin 5182a6abeebSBaptiste Daroussin fail: 5192a6abeebSBaptiste Daroussin free(tr); 5202a6abeebSBaptiste Daroussin return ((size_t)(-1)); 5212a6abeebSBaptiste Daroussin } 5222a6abeebSBaptiste Daroussin 5232a6abeebSBaptiste Daroussin /* 5242a6abeebSBaptiste Daroussin * In the non-POSIX case, we transform each character into a string of 5252a6abeebSBaptiste Daroussin * characters representing the character's priority. Since char is usually 5262a6abeebSBaptiste Daroussin * signed, we are limited by 7 bits per byte. To avoid zero, we need to add 5272a6abeebSBaptiste Daroussin * XFRM_OFFSET, so we can't use a full 7 bits. For simplicity, we choose 6 5282a6abeebSBaptiste Daroussin * bits per byte. 5292a6abeebSBaptiste Daroussin * 5302a6abeebSBaptiste Daroussin * It turns out that we sometimes have real priorities that are 5312a6abeebSBaptiste Daroussin * 31-bits wide. (But: be careful using priorities where the high 5322a6abeebSBaptiste Daroussin * order bit is set -- i.e. the priority is negative. The sort order 5332a6abeebSBaptiste Daroussin * may be surprising!) 5342a6abeebSBaptiste Daroussin * 5352a6abeebSBaptiste Daroussin * TODO: This would be a good area to optimize somewhat. It turns out 5362a6abeebSBaptiste Daroussin * that real prioririties *except for the last UNDEFINED pass* are generally 5372a6abeebSBaptiste Daroussin * very small. We need the localedef code to precalculate the max 5382a6abeebSBaptiste Daroussin * priority for us, and ideally also give us a mask, and then we could 5392a6abeebSBaptiste Daroussin * severely limit what we expand to. 5402a6abeebSBaptiste Daroussin */ 5412a6abeebSBaptiste Daroussin #define XFRM_BYTES 6 5422a6abeebSBaptiste Daroussin #define XFRM_OFFSET ('0') /* make all printable characters */ 5432a6abeebSBaptiste Daroussin #define XFRM_SHIFT 6 5442a6abeebSBaptiste Daroussin #define XFRM_MASK ((1 << XFRM_SHIFT) - 1) 5452a6abeebSBaptiste Daroussin #define XFRM_SEP ('.') /* chosen to be less than XFRM_OFFSET */ 5462a6abeebSBaptiste Daroussin 5472a6abeebSBaptiste Daroussin static int 5482a6abeebSBaptiste Daroussin xfrm(struct xlocale_collate *table, unsigned char *p, int pri, int pass) 549926f20c9SAndrey A. Chernov { 5502a6abeebSBaptiste Daroussin /* we use unsigned to ensure zero fill on right shift */ 5514644f9beSYuri Pankov uint32_t val = (uint32_t)table->info->pri_count[pass]; 5522a6abeebSBaptiste Daroussin int nc = 0; 553926f20c9SAndrey A. Chernov 5542a6abeebSBaptiste Daroussin while (val) { 5552a6abeebSBaptiste Daroussin *p = (pri & XFRM_MASK) + XFRM_OFFSET; 5562a6abeebSBaptiste Daroussin pri >>= XFRM_SHIFT; 5572a6abeebSBaptiste Daroussin val >>= XFRM_SHIFT; 5582a6abeebSBaptiste Daroussin p++; 5592a6abeebSBaptiste Daroussin nc++; 5602a6abeebSBaptiste Daroussin } 5612a6abeebSBaptiste Daroussin return (nc); 562926f20c9SAndrey A. Chernov } 563926f20c9SAndrey A. Chernov 5642a6abeebSBaptiste Daroussin size_t 5652a6abeebSBaptiste Daroussin _collate_sxfrm(struct xlocale_collate *table, const wchar_t *src, char *xf, 5662a6abeebSBaptiste Daroussin size_t room) 567c3d0cca4SAndrey A. Chernov { 5682a6abeebSBaptiste Daroussin int pri; 5692a6abeebSBaptiste Daroussin int len; 5702a6abeebSBaptiste Daroussin const wchar_t *t; 5712a6abeebSBaptiste Daroussin wchar_t *tr = NULL; 5722a6abeebSBaptiste Daroussin int direc; 5732a6abeebSBaptiste Daroussin int pass; 5742a6abeebSBaptiste Daroussin const int32_t *state; 5752a6abeebSBaptiste Daroussin size_t want = 0; 5762a6abeebSBaptiste Daroussin size_t need = 0; 5772a6abeebSBaptiste Daroussin int b; 5782a6abeebSBaptiste Daroussin uint8_t buf[XFRM_BYTES]; 579332fe837SBaptiste Daroussin int ndir = table->info->directive_count; 580c3d0cca4SAndrey A. Chernov 581332fe837SBaptiste Daroussin assert(src); 582332fe837SBaptiste Daroussin 583332fe837SBaptiste Daroussin for (pass = 0; pass <= ndir; pass++) { 5842a6abeebSBaptiste Daroussin 5852a6abeebSBaptiste Daroussin state = NULL; 5862a6abeebSBaptiste Daroussin 5872a6abeebSBaptiste Daroussin if (pass != 0) { 5882a6abeebSBaptiste Daroussin /* insert level separator from the previous pass */ 5892a6abeebSBaptiste Daroussin if (room) { 5902a6abeebSBaptiste Daroussin *xf++ = XFRM_SEP; 5912a6abeebSBaptiste Daroussin room--; 592c3d0cca4SAndrey A. Chernov } 5932a6abeebSBaptiste Daroussin want++; 5942a6abeebSBaptiste Daroussin } 5952a6abeebSBaptiste Daroussin 5962a6abeebSBaptiste Daroussin /* special pass for undefined */ 597332fe837SBaptiste Daroussin if (pass == ndir) { 5982a6abeebSBaptiste Daroussin direc = DIRECTIVE_FORWARD | DIRECTIVE_UNDEFINED; 5992a6abeebSBaptiste Daroussin } else { 6002a6abeebSBaptiste Daroussin direc = table->info->directive[pass]; 6012a6abeebSBaptiste Daroussin } 6022a6abeebSBaptiste Daroussin 6032a6abeebSBaptiste Daroussin t = src; 6042a6abeebSBaptiste Daroussin 6052a6abeebSBaptiste Daroussin if (direc & DIRECTIVE_BACKWARD) { 6062a6abeebSBaptiste Daroussin wchar_t *bp, *fp, c; 6072a6abeebSBaptiste Daroussin free(tr); 6082a6abeebSBaptiste Daroussin if ((tr = wcsdup(t)) == NULL) { 6092a6abeebSBaptiste Daroussin errno = ENOMEM; 6102a6abeebSBaptiste Daroussin goto fail; 6112a6abeebSBaptiste Daroussin } 6122a6abeebSBaptiste Daroussin bp = tr; 6132a6abeebSBaptiste Daroussin fp = tr + wcslen(tr) - 1; 6142a6abeebSBaptiste Daroussin while (bp < fp) { 6152a6abeebSBaptiste Daroussin c = *bp; 6162a6abeebSBaptiste Daroussin *bp++ = *fp; 6172a6abeebSBaptiste Daroussin *fp-- = c; 6182a6abeebSBaptiste Daroussin } 6192a6abeebSBaptiste Daroussin t = (const wchar_t *)tr; 6202a6abeebSBaptiste Daroussin } 6212a6abeebSBaptiste Daroussin 6222a6abeebSBaptiste Daroussin if (direc & DIRECTIVE_POSITION) { 6232a6abeebSBaptiste Daroussin while (*t || state) { 6242a6abeebSBaptiste Daroussin 6252a6abeebSBaptiste Daroussin _collate_lookup(table, t, &len, &pri, pass, &state); 6262a6abeebSBaptiste Daroussin t += len; 6272a6abeebSBaptiste Daroussin if (pri <= 0) { 6282a6abeebSBaptiste Daroussin if (pri < 0) { 6292a6abeebSBaptiste Daroussin errno = EINVAL; 6302a6abeebSBaptiste Daroussin goto fail; 6312a6abeebSBaptiste Daroussin } 632dee0bbbdSBaptiste Daroussin state = NULL; 6332a6abeebSBaptiste Daroussin pri = COLLATE_MAX_PRIORITY; 6342a6abeebSBaptiste Daroussin } 6352a6abeebSBaptiste Daroussin 6362a6abeebSBaptiste Daroussin b = xfrm(table, buf, pri, pass); 6372a6abeebSBaptiste Daroussin want += b; 6382a6abeebSBaptiste Daroussin if (room) { 6392a6abeebSBaptiste Daroussin while (b) { 6402a6abeebSBaptiste Daroussin b--; 6412a6abeebSBaptiste Daroussin if (room) { 6422a6abeebSBaptiste Daroussin *xf++ = buf[b]; 6432a6abeebSBaptiste Daroussin room--; 6442a6abeebSBaptiste Daroussin } 6452a6abeebSBaptiste Daroussin } 6462a6abeebSBaptiste Daroussin } 6472a6abeebSBaptiste Daroussin need = want; 6482a6abeebSBaptiste Daroussin } 6492a6abeebSBaptiste Daroussin } else { 6502a6abeebSBaptiste Daroussin while (*t || state) { 6512a6abeebSBaptiste Daroussin _collate_lookup(table, t, &len, &pri, pass, &state); 6522a6abeebSBaptiste Daroussin t += len; 6532a6abeebSBaptiste Daroussin if (pri <= 0) { 6542a6abeebSBaptiste Daroussin if (pri < 0) { 6552a6abeebSBaptiste Daroussin errno = EINVAL; 6562a6abeebSBaptiste Daroussin goto fail; 6572a6abeebSBaptiste Daroussin } 658dee0bbbdSBaptiste Daroussin state = NULL; 6592a6abeebSBaptiste Daroussin continue; 6602a6abeebSBaptiste Daroussin } 6612a6abeebSBaptiste Daroussin 6622a6abeebSBaptiste Daroussin b = xfrm(table, buf, pri, pass); 6632a6abeebSBaptiste Daroussin want += b; 6642a6abeebSBaptiste Daroussin if (room) { 6652a6abeebSBaptiste Daroussin 6662a6abeebSBaptiste Daroussin while (b) { 6672a6abeebSBaptiste Daroussin b--; 6682a6abeebSBaptiste Daroussin if (room) { 6692a6abeebSBaptiste Daroussin *xf++ = buf[b]; 6702a6abeebSBaptiste Daroussin room--; 6712a6abeebSBaptiste Daroussin } 6722a6abeebSBaptiste Daroussin } 6732a6abeebSBaptiste Daroussin } 6742a6abeebSBaptiste Daroussin need = want; 6752a6abeebSBaptiste Daroussin } 6762a6abeebSBaptiste Daroussin } 6772a6abeebSBaptiste Daroussin } 6782a6abeebSBaptiste Daroussin free(tr); 6792a6abeebSBaptiste Daroussin return (need); 6802a6abeebSBaptiste Daroussin 6812a6abeebSBaptiste Daroussin fail: 6822a6abeebSBaptiste Daroussin free(tr); 6832a6abeebSBaptiste Daroussin return ((size_t)(-1)); 6842a6abeebSBaptiste Daroussin } 6852a6abeebSBaptiste Daroussin 6862a6abeebSBaptiste Daroussin /* 6872a6abeebSBaptiste Daroussin * __collate_equiv_value returns the primary collation value for the given 6882a6abeebSBaptiste Daroussin * collating symbol specified by str and len. Zero or negative is returned 6892a6abeebSBaptiste Daroussin * if the collating symbol was not found. This function is used by bracket 6902a6abeebSBaptiste Daroussin * code in the TRE regex library. 6912a6abeebSBaptiste Daroussin */ 6922a6abeebSBaptiste Daroussin int 6932a6abeebSBaptiste Daroussin __collate_equiv_value(locale_t locale, const wchar_t *str, size_t len) 6942a6abeebSBaptiste Daroussin { 6952a6abeebSBaptiste Daroussin int32_t e; 6962a6abeebSBaptiste Daroussin 6972a6abeebSBaptiste Daroussin if (len < 1 || len >= COLLATE_STR_LEN) 6982a6abeebSBaptiste Daroussin return (-1); 6992a6abeebSBaptiste Daroussin 7002a6abeebSBaptiste Daroussin FIX_LOCALE(locale); 7012a6abeebSBaptiste Daroussin struct xlocale_collate *table = 7022a6abeebSBaptiste Daroussin (struct xlocale_collate*)locale->components[XLC_COLLATE]; 7032a6abeebSBaptiste Daroussin 7042a6abeebSBaptiste Daroussin if (table->__collate_load_error) 7052a6abeebSBaptiste Daroussin return ((len == 1 && *str <= UCHAR_MAX) ? *str : -1); 7062a6abeebSBaptiste Daroussin 7072a6abeebSBaptiste Daroussin if (len == 1) { 7082a6abeebSBaptiste Daroussin e = -1; 7092a6abeebSBaptiste Daroussin if (*str <= UCHAR_MAX) 7102a6abeebSBaptiste Daroussin e = table->char_pri_table[*str].pri[0]; 7114644f9beSYuri Pankov else if (table->info->large_count > 0) { 7122a6abeebSBaptiste Daroussin collate_large_t *match_large; 7132a6abeebSBaptiste Daroussin match_large = largesearch(table, *str); 7142a6abeebSBaptiste Daroussin if (match_large) 7152a6abeebSBaptiste Daroussin e = match_large->pri.pri[0]; 7162a6abeebSBaptiste Daroussin } 7172a6abeebSBaptiste Daroussin if (e == 0) 7182a6abeebSBaptiste Daroussin return (1); 7192a6abeebSBaptiste Daroussin return (e > 0 ? e : 0); 7202a6abeebSBaptiste Daroussin } 7214644f9beSYuri Pankov if (table->info->chain_count > 0) { 7222a6abeebSBaptiste Daroussin wchar_t name[COLLATE_STR_LEN]; 7232a6abeebSBaptiste Daroussin collate_chain_t *match_chain; 7242a6abeebSBaptiste Daroussin int clen; 7252a6abeebSBaptiste Daroussin 7262a6abeebSBaptiste Daroussin wcsncpy (name, str, len); 7272a6abeebSBaptiste Daroussin name[len] = 0; 7282a6abeebSBaptiste Daroussin match_chain = chainsearch(table, name, &clen); 7292a6abeebSBaptiste Daroussin if (match_chain) { 7302a6abeebSBaptiste Daroussin e = match_chain->pri[0]; 7312a6abeebSBaptiste Daroussin if (e == 0) 7322a6abeebSBaptiste Daroussin return (1); 7332a6abeebSBaptiste Daroussin return (e < 0 ? -e : e); 7342a6abeebSBaptiste Daroussin } 7352a6abeebSBaptiste Daroussin } 7362a6abeebSBaptiste Daroussin return (0); 7372a6abeebSBaptiste Daroussin } 738