diff options
Diffstat (limited to 'usr/src/lib/libc/port/locale/collate.c')
| -rw-r--r-- | usr/src/lib/libc/port/locale/collate.c | 255 |
1 files changed, 255 insertions, 0 deletions
diff --git a/usr/src/lib/libc/port/locale/collate.c b/usr/src/lib/libc/port/locale/collate.c new file mode 100644 index 0000000000..7783cf91bb --- /dev/null +++ b/usr/src/lib/libc/port/locale/collate.c @@ -0,0 +1,255 @@ +/* + * Copyright (c) 1995 Alex Tatmanjants <alex@elvisti.kiev.ua> + * at Electronni Visti IA, Kiev, Ukraine. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +/* + * Copyright 2010 Nexenta Systems, Inc. All rights reserved. + * Use is subject to license terms. + */ + +#include "lint.h" +#include "file64.h" +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <errno.h> +#include <unistd.h> +#include <sysexits.h> +#include <netinet/in.h> + +#include "collate.h" +#include "setlocale.h" +#include "ldpart.h" + +int __collate_load_error = 1; +int __collate_substitute_nontrivial; + +char __collate_substitute_table[UCHAR_MAX + 1][STR_LEN]; +struct __collate_st_char_pri __collate_char_pri_table[UCHAR_MAX + 1]; +struct __collate_st_chain_pri *__collate_chain_pri_table; + +int +__collate_load_tables(const char *encoding) +{ + FILE *fp; + int i, saverr, chains; + uint32_t u32; + char strbuf[STR_LEN], buf[PATH_MAX]; + void *TMP_substitute_table, *TMP_char_pri_table, *TMP_chain_pri_table; + static char collate_encoding[ENCODING_LEN + 1]; + + /* 'encoding' must be already checked. */ + if (strcmp(encoding, "C") == 0 || strcmp(encoding, "POSIX") == 0) { + __collate_load_error = 1; + return (_LDP_CACHE); + } + + /* + * If the locale name is the same as our cache, use the cache. + */ + if (strcmp(encoding, collate_encoding) == 0) { + __collate_load_error = 0; + return (_LDP_CACHE); + } + + /* + * Slurp the locale file into the cache. + */ + + /* 'PathLocale' must be already set & checked. */ + /* Range checking not needed, encoding has fixed size */ + (void) strcpy(buf, _PathLocale); + (void) strcat(buf, "/"); + (void) strcat(buf, encoding); + (void) strcat(buf, "/LC_COLLATE"); + if ((fp = fopen(buf, "r")) == NULL) + return (_LDP_ERROR); + + if (fread(strbuf, sizeof (strbuf), 1, fp) != 1) { + saverr = errno; + (void) fclose(fp); + errno = saverr; + return (_LDP_ERROR); + } + chains = -1; + if (strcmp(strbuf, COLLATE_VERSION) == 0) + chains = 0; + else if (strcmp(strbuf, COLLATE_VERSION1_2) == 0) + chains = 1; + if (chains < 0) { + (void) fclose(fp); + errno = EINVAL; + return (_LDP_ERROR); + } + if (chains) { + if (fread(&u32, sizeof (u32), 1, fp) != 1) { + saverr = errno; + (void) fclose(fp); + errno = saverr; + return (_LDP_ERROR); + } + if ((chains = (int)ntohl(u32)) < 1) { + (void) fclose(fp); + errno = EINVAL; + return (_LDP_ERROR); + } + } else + chains = TABLE_SIZE; + + if ((TMP_substitute_table = + malloc(sizeof (__collate_substitute_table))) == NULL) { + saverr = errno; + (void) fclose(fp); + errno = saverr; + return (_LDP_ERROR); + } + if ((TMP_char_pri_table = + malloc(sizeof (__collate_char_pri_table))) == NULL) { + saverr = errno; + free(TMP_substitute_table); + (void) fclose(fp); + errno = saverr; + return (_LDP_ERROR); + } + if ((TMP_chain_pri_table = + malloc(sizeof (*__collate_chain_pri_table) * chains)) == NULL) { + saverr = errno; + free(TMP_substitute_table); + free(TMP_char_pri_table); + (void) fclose(fp); + errno = saverr; + return (_LDP_ERROR); + } + +#define FREAD(a, b, c, d) \ +{ \ + if (fread(a, b, c, d) != c) { \ + saverr = errno; \ + free(TMP_substitute_table); \ + free(TMP_char_pri_table); \ + free(TMP_chain_pri_table); \ + (void) fclose(d); \ + errno = saverr; \ + return (_LDP_ERROR); \ + } \ +} + + FREAD(TMP_substitute_table, sizeof (__collate_substitute_table), 1, fp); + FREAD(TMP_char_pri_table, sizeof (__collate_char_pri_table), 1, fp); + FREAD(TMP_chain_pri_table, + sizeof (*__collate_chain_pri_table), chains, fp); + (void) fclose(fp); + + (void) strcpy(collate_encoding, encoding); + if (__collate_substitute_table_ptr != NULL) + free(__collate_substitute_table_ptr); + __collate_substitute_table_ptr = TMP_substitute_table; + if (__collate_char_pri_table_ptr != NULL) + free(__collate_char_pri_table_ptr); + __collate_char_pri_table_ptr = TMP_char_pri_table; + for (i = 0; i < UCHAR_MAX + 1; i++) { + __collate_char_pri_table[i].prim = + ntohl(__collate_char_pri_table[i].prim); + __collate_char_pri_table[i].sec = + ntohl(__collate_char_pri_table[i].sec); + } + if (__collate_chain_pri_table != NULL) + free(__collate_chain_pri_table); + __collate_chain_pri_table = TMP_chain_pri_table; + for (i = 0; i < chains; i++) { + __collate_chain_pri_table[i].prim = + ntohl(__collate_chain_pri_table[i].prim); + __collate_chain_pri_table[i].sec = + ntohl(__collate_chain_pri_table[i].sec); + } + __collate_substitute_nontrivial = 0; + for (i = 0; i < UCHAR_MAX + 1; i++) { + if (__collate_substitute_table[i][0] != i || + __collate_substitute_table[i][1] != 0) { + __collate_substitute_nontrivial = 1; + break; + } + } + __collate_load_error = 0; + + return (_LDP_LOADED); +} + +char * +__collate_substitute(const char *str) +{ + int dest_len, len, nlen; + int delta; + char *dest_str = NULL; + uchar_t *s = (uchar_t *)str; + + if (s == NULL || *s == '\0') { + return (strdup("")); + } + + delta = strlen(str); + delta += delta / 8; + dest_str = malloc(dest_len = delta); + if (dest_str == NULL) + return (NULL); + len = 0; + while (*s) { + nlen = len + strlen(__collate_substitute_table[*s]); + if (dest_len <= nlen) { + char *new_str; + new_str = realloc(dest_str, dest_len = nlen + delta); + if (new_str == NULL) { + free(dest_str); + return (NULL); + } + dest_str = new_str; + } + (void) strcpy(dest_str + len, + (char *)__collate_substitute_table[*s++]); + len = nlen; + } + return (dest_str); +} + +void +__collate_lookup(const char *t, int *len, int *prim, int *sec) +{ + struct __collate_st_chain_pri *p2; + + *len = 1; + *prim = *sec = 0; + for (p2 = __collate_chain_pri_table; p2->str[0] != '\0'; p2++) { + if (*t == p2->str[0] && + strncmp(t, (char *)p2->str, strlen((char *)p2->str)) == 0) { + *len = strlen((char *)p2->str); + *prim = p2->prim; + *sec = p2->sec; + return; + } + } + *prim = __collate_char_pri_table[(uchar_t)*t].prim; + *sec = __collate_char_pri_table[(uchar_t)*t].sec; +} |
