Changeset View
Changeset View
Standalone View
Standalone View
head/lib/libc/locale/collate.c
Show First 20 Lines • Show All 47 Lines • ▼ Show 20 Lines | |||||
#include <stdlib.h> | #include <stdlib.h> | ||||
#include <string.h> | #include <string.h> | ||||
#include <wchar.h> | #include <wchar.h> | ||||
#include <errno.h> | #include <errno.h> | ||||
#include <unistd.h> | #include <unistd.h> | ||||
#include <fcntl.h> | #include <fcntl.h> | ||||
#include "un-namespace.h" | #include "un-namespace.h" | ||||
#include "endian.h" | |||||
#include "collate.h" | #include "collate.h" | ||||
#include "setlocale.h" | #include "setlocale.h" | ||||
#include "ldpart.h" | #include "ldpart.h" | ||||
#include "libc_private.h" | #include "libc_private.h" | ||||
struct xlocale_collate __xlocale_global_collate = { | struct xlocale_collate __xlocale_global_collate = { | ||||
{{0}, "C"}, 1, 0, 0, 0 | {{0}, "C"}, 1, 0, 0, 0 | ||||
}; | }; | ||||
▲ Show 20 Lines • Show All 91 Lines • ▼ Show 20 Lines | __collate_load_tables_l(const char *encoding, struct xlocale_collate *table) | ||||
} | } | ||||
TMP += COLLATE_STR_LEN; | TMP += COLLATE_STR_LEN; | ||||
info = (void *)TMP; | info = (void *)TMP; | ||||
TMP += sizeof (*info); | TMP += sizeof (*info); | ||||
if ((info->directive_count < 1) || | if ((info->directive_count < 1) || | ||||
(info->directive_count >= COLL_WEIGHTS_MAX) || | (info->directive_count >= COLL_WEIGHTS_MAX) || | ||||
((chains = info->chain_count) < 0)) { | ((chains = BSWAP(info->chain_count)) < 0)) { | ||||
(void) munmap(map, sbuf.st_size); | (void) munmap(map, sbuf.st_size); | ||||
errno = EINVAL; | errno = EINVAL; | ||||
return (_LDP_ERROR); | return (_LDP_ERROR); | ||||
} | } | ||||
i = (sizeof (collate_char_t) * (UCHAR_MAX + 1)) + | i = (sizeof (collate_char_t) * (UCHAR_MAX + 1)) + | ||||
(sizeof (collate_chain_t) * chains) + | (sizeof (collate_chain_t) * chains) + | ||||
(sizeof (collate_large_t) * info->large_count); | (sizeof (collate_large_t) * BSWAP(info->large_count)); | ||||
for (z = 0; z < info->directive_count; z++) { | for (z = 0; z < info->directive_count; z++) { | ||||
i += sizeof (collate_subst_t) * info->subst_count[z]; | i += sizeof (collate_subst_t) * BSWAP(info->subst_count[z]); | ||||
} | } | ||||
if (i != (sbuf.st_size - (TMP - map))) { | if (i != (sbuf.st_size - (TMP - map))) { | ||||
(void) munmap(map, sbuf.st_size); | (void) munmap(map, sbuf.st_size); | ||||
errno = EINVAL; | errno = EINVAL; | ||||
return (_LDP_ERROR); | return (_LDP_ERROR); | ||||
} | } | ||||
table->info = info; | table->info = info; | ||||
table->char_pri_table = (void *)TMP; | table->char_pri_table = (void *)TMP; | ||||
TMP += sizeof (collate_char_t) * (UCHAR_MAX + 1); | TMP += sizeof (collate_char_t) * (UCHAR_MAX + 1); | ||||
for (z = 0; z < info->directive_count; z++) { | for (z = 0; z < info->directive_count; z++) { | ||||
if (info->subst_count[z] > 0) { | if (BSWAP(info->subst_count[z]) > 0) { | ||||
table->subst_table[z] = (void *)TMP; | table->subst_table[z] = (void *)TMP; | ||||
TMP += info->subst_count[z] * sizeof (collate_subst_t); | TMP += BSWAP(info->subst_count[z]) * sizeof (collate_subst_t); | ||||
} else { | } else { | ||||
table->subst_table[z] = NULL; | table->subst_table[z] = NULL; | ||||
} | } | ||||
} | } | ||||
if (chains > 0) { | if (chains > 0) { | ||||
table->chain_pri_table = (void *)TMP; | table->chain_pri_table = (void *)TMP; | ||||
TMP += chains * sizeof (collate_chain_t); | TMP += chains * sizeof (collate_chain_t); | ||||
} else | } else | ||||
table->chain_pri_table = NULL; | table->chain_pri_table = NULL; | ||||
if (info->large_count > 0) | if (BSWAP(info->large_count) > 0) | ||||
table->large_pri_table = (void *)TMP; | table->large_pri_table = (void *)TMP; | ||||
else | else | ||||
table->large_pri_table = NULL; | table->large_pri_table = NULL; | ||||
table->__collate_load_error = 0; | table->__collate_load_error = 0; | ||||
return (_LDP_LOADED); | return (_LDP_LOADED); | ||||
} | } | ||||
static const int32_t * | static const int32_t * | ||||
substsearch(struct xlocale_collate *table, const wchar_t key, int pass) | substsearch(struct xlocale_collate *table, const wchar_t key, int pass) | ||||
{ | { | ||||
const collate_subst_t *p; | const collate_subst_t *p; | ||||
int n = table->info->subst_count[pass]; | int n = BSWAP(table->info->subst_count[pass]); | ||||
if (n == 0) | if (n == 0) | ||||
return (NULL); | return (NULL); | ||||
if (pass >= table->info->directive_count) | if (pass >= table->info->directive_count) | ||||
return (NULL); | return (NULL); | ||||
if (!(key & COLLATE_SUBST_PRIORITY)) | if (!(key & COLLATE_SUBST_PRIORITY)) | ||||
return (NULL); | return (NULL); | ||||
p = table->subst_table[pass] + (key & ~COLLATE_SUBST_PRIORITY); | p = table->subst_table[pass] + (key & ~COLLATE_SUBST_PRIORITY); | ||||
assert(p->key == key); | assert(BSWAP(p->key) == key); | ||||
return (p->pri); | return (p->pri); | ||||
} | } | ||||
static collate_chain_t * | static collate_chain_t * | ||||
chainsearch(struct xlocale_collate *table, const wchar_t *key, int *len) | chainsearch(struct xlocale_collate *table, const wchar_t *key, int *len) | ||||
{ | { | ||||
int low = 0; | int low = 0; | ||||
int high = table->info->chain_count - 1;; | int high = BSWAP(table->info->chain_count) - 1; | ||||
int next, compar, l; | int next, compar, l; | ||||
collate_chain_t *p; | collate_chain_t *p; | ||||
collate_chain_t *tab = table->chain_pri_table; | collate_chain_t *tab = table->chain_pri_table; | ||||
if (high < 0) | if (high < 0) | ||||
return (NULL); | return (NULL); | ||||
while (low <= high) { | while (low <= high) { | ||||
next = (low + high) / 2; | next = (low + high) / 2; | ||||
p = tab + next; | p = tab + next; | ||||
compar = *key - *p->str; | compar = *key - le16toh(*p->str); | ||||
if (compar == 0) { | if (compar == 0) { | ||||
l = wcsnlen(p->str, COLLATE_STR_LEN); | l = wcsnlen(p->str, COLLATE_STR_LEN); | ||||
compar = wcsncmp(key, p->str, l); | compar = wcsncmp(key, p->str, l); | ||||
if (compar == 0) { | if (compar == 0) { | ||||
*len = l; | *len = l; | ||||
return (p); | return (p); | ||||
} | } | ||||
} | } | ||||
if (compar > 0) | if (compar > 0) | ||||
low = next + 1; | low = next + 1; | ||||
else | else | ||||
high = next - 1; | high = next - 1; | ||||
} | } | ||||
return (NULL); | return (NULL); | ||||
} | } | ||||
static collate_large_t * | static collate_large_t * | ||||
largesearch(struct xlocale_collate *table, const wchar_t key) | largesearch(struct xlocale_collate *table, const wchar_t key) | ||||
{ | { | ||||
int low = 0; | int low = 0; | ||||
int high = table->info->large_count - 1; | int high = BSWAP(table->info->large_count) - 1; | ||||
int next, compar; | int next, compar; | ||||
collate_large_t *p; | collate_large_t *p; | ||||
collate_large_t *tab = table->large_pri_table; | collate_large_t *tab = table->large_pri_table; | ||||
if (high < 0) | if (high < 0) | ||||
return (NULL); | return (NULL); | ||||
while (low <= high) { | while (low <= high) { | ||||
next = (low + high) / 2; | next = (low + high) / 2; | ||||
p = tab + next; | p = tab + next; | ||||
compar = key - p->val; | compar = key - BSWAP(p->val); | ||||
if (compar == 0) | if (compar == 0) | ||||
return (p); | return (p); | ||||
if (compar > 0) | if (compar > 0) | ||||
low = next + 1; | low = next + 1; | ||||
else | else | ||||
high = next - 1; | high = next - 1; | ||||
} | } | ||||
return (NULL); | return (NULL); | ||||
▲ Show 20 Lines • Show All 48 Lines • ▼ Show 20 Lines | if (((p2 = chainsearch(table, t, &l)) != NULL) && | ||||
*pri = p; | *pri = p; | ||||
} else if (*t <= UCHAR_MAX) { | } else if (*t <= UCHAR_MAX) { | ||||
/* | /* | ||||
* Character is a small (8-bit) character. | * Character is a small (8-bit) character. | ||||
* We just look these up directly for speed. | * We just look these up directly for speed. | ||||
*/ | */ | ||||
*pri = table->char_pri_table[*t].pri[which]; | *pri = BSWAP(table->char_pri_table[*t].pri[which]); | ||||
} else if ((table->info->large_count > 0) && | } else if ((BSWAP(table->info->large_count) > 0) && | ||||
((match = largesearch(table, *t)) != NULL)) { | ((match = largesearch(table, *t)) != NULL)) { | ||||
/* | /* | ||||
* Character was found in the extended table. | * Character was found in the extended table. | ||||
*/ | */ | ||||
*pri = match->pri.pri[which]; | *pri = BSWAP(match->pri.pri[which]); | ||||
} else { | } else { | ||||
/* | /* | ||||
* Character lacks a specific definition. | * Character lacks a specific definition. | ||||
*/ | */ | ||||
if (table->info->directive[which] & DIRECTIVE_UNDEFINED) { | if (table->info->directive[which] & DIRECTIVE_UNDEFINED) { | ||||
/* Mask off sign bit to prevent ordering confusion. */ | /* Mask off sign bit to prevent ordering confusion. */ | ||||
*pri = (*t & COLLATE_MAX_PRIORITY); | *pri = (*t & COLLATE_MAX_PRIORITY); | ||||
} else { | } else { | ||||
*pri = table->info->undef_pri[which]; | *pri = BSWAP(table->info->undef_pri[which]); | ||||
} | } | ||||
/* No substitutions for undefined characters! */ | /* No substitutions for undefined characters! */ | ||||
return; | return; | ||||
} | } | ||||
/* | /* | ||||
* Try substituting (expanding) the character. We are | * Try substituting (expanding) the character. We are | ||||
* currently doing this *after* the chain compression. I | * currently doing this *after* the chain compression. I | ||||
* think it should not matter, but this way might be slightly | * think it should not matter, but this way might be slightly | ||||
* faster. | * faster. | ||||
* | * | ||||
* We do this after the priority search, as this will help us | * We do this after the priority search, as this will help us | ||||
* to identify a single key value. In order for this to work, | * to identify a single key value. In order for this to work, | ||||
* its important that the priority assigned to a given element | * its important that the priority assigned to a given element | ||||
* to be substituted be unique for that level. The localedef | * to be substituted be unique for that level. The localedef | ||||
* code ensures this for us. | * code ensures this for us. | ||||
*/ | */ | ||||
if ((sptr = substsearch(table, *pri, which)) != NULL) { | if ((sptr = substsearch(table, *pri, which)) != NULL) { | ||||
if ((*pri = *sptr) > 0) { | if ((*pri = BSWAP(*sptr)) > 0) { | ||||
sptr++; | sptr++; | ||||
*state = *sptr ? sptr : NULL; | *state = BSWAP(*sptr) ? sptr : NULL; | ||||
} | } | ||||
} | } | ||||
} | } | ||||
/* | /* | ||||
* This is the meaty part of wcsxfrm & strxfrm. Note that it does | * This is the meaty part of wcsxfrm & strxfrm. Note that it does | ||||
* NOT NULL terminate. That is left to the caller. | * NOT NULL terminate. That is left to the caller. | ||||
▲ Show 20 Lines • Show All 125 Lines • ▼ Show 20 Lines | |||||
#define XFRM_SHIFT 6 | #define XFRM_SHIFT 6 | ||||
#define XFRM_MASK ((1 << XFRM_SHIFT) - 1) | #define XFRM_MASK ((1 << XFRM_SHIFT) - 1) | ||||
#define XFRM_SEP ('.') /* chosen to be less than XFRM_OFFSET */ | #define XFRM_SEP ('.') /* chosen to be less than XFRM_OFFSET */ | ||||
static int | static int | ||||
xfrm(struct xlocale_collate *table, unsigned char *p, int pri, int pass) | xfrm(struct xlocale_collate *table, unsigned char *p, int pri, int pass) | ||||
{ | { | ||||
/* we use unsigned to ensure zero fill on right shift */ | /* we use unsigned to ensure zero fill on right shift */ | ||||
uint32_t val = (uint32_t)table->info->pri_count[pass]; | uint32_t val = BSWAP((uint32_t)table->info->pri_count[pass]); | ||||
int nc = 0; | int nc = 0; | ||||
while (val) { | while (val) { | ||||
*p = (pri & XFRM_MASK) + XFRM_OFFSET; | *p = (pri & XFRM_MASK) + XFRM_OFFSET; | ||||
pri >>= XFRM_SHIFT; | pri >>= XFRM_SHIFT; | ||||
val >>= XFRM_SHIFT; | val >>= XFRM_SHIFT; | ||||
p++; | p++; | ||||
nc++; | nc++; | ||||
▲ Show 20 Lines • Show All 143 Lines • ▼ Show 20 Lines | __collate_equiv_value(locale_t locale, const wchar_t *str, size_t len) | ||||
if (table->__collate_load_error) | if (table->__collate_load_error) | ||||
return ((len == 1 && *str <= UCHAR_MAX) ? *str : -1); | return ((len == 1 && *str <= UCHAR_MAX) ? *str : -1); | ||||
if (len == 1) { | if (len == 1) { | ||||
e = -1; | e = -1; | ||||
if (*str <= UCHAR_MAX) | if (*str <= UCHAR_MAX) | ||||
e = table->char_pri_table[*str].pri[0]; | e = table->char_pri_table[*str].pri[0]; | ||||
else if (table->info->large_count > 0) { | else if (BSWAP(table->info->large_count) > 0) { | ||||
collate_large_t *match_large; | collate_large_t *match_large; | ||||
match_large = largesearch(table, *str); | match_large = largesearch(table, *str); | ||||
if (match_large) | if (match_large) | ||||
e = match_large->pri.pri[0]; | e = match_large->pri.pri[0]; | ||||
} | } | ||||
if (e == 0) | if (e == 0) | ||||
return (1); | return (1); | ||||
return (e > 0 ? e : 0); | return (e > 0 ? e : 0); | ||||
} | } | ||||
if (table->info->chain_count > 0) { | if (BSWAP(table->info->chain_count) > 0) { | ||||
wchar_t name[COLLATE_STR_LEN]; | wchar_t name[COLLATE_STR_LEN]; | ||||
collate_chain_t *match_chain; | collate_chain_t *match_chain; | ||||
int clen; | int clen; | ||||
wcsncpy (name, str, len); | wcsncpy (name, str, len); | ||||
name[len] = 0; | name[len] = 0; | ||||
match_chain = chainsearch(table, name, &clen); | match_chain = chainsearch(table, name, &clen); | ||||
if (match_chain) { | if (match_chain) { | ||||
e = match_chain->pri[0]; | e = match_chain->pri[0]; | ||||
if (e == 0) | if (e == 0) | ||||
return (1); | return (1); | ||||
return (e < 0 ? -e : e); | return (e < 0 ? -e : e); | ||||
} | } | ||||
} | } | ||||
return (0); | return (0); | ||||
} | } |