diff options
author | delphij <delphij@FreeBSD.org> | 2009-06-22 17:09:46 +0000 |
---|---|---|
committer | delphij <delphij@FreeBSD.org> | 2009-06-22 17:09:46 +0000 |
commit | 3216be3a5a453bb6570d9a31504f54f067832fad (patch) | |
tree | ff466c24979a5205b616c97267983e5b0216ed4c /lib/libkiconv | |
parent | 903095e7105f537fbdcb5a7a542bd833c6b35b3b (diff) | |
download | FreeBSD-src-3216be3a5a453bb6570d9a31504f54f067832fad.zip FreeBSD-src-3216be3a5a453bb6570d9a31504f54f067832fad.tar.gz |
Split tolower/toupper code from usual xlat16 kiconv table, and make it
possible to do tolower/toupper independently without code conversion.
Submitted by: imura (but bugs are mine)
Obtained from: http://people.freebsd.org/~imura/kiconv/
(1_kiconv_wctype_kern.diff, 1_kiconv_wctype_user.diff)
Diffstat (limited to 'lib/libkiconv')
-rw-r--r-- | lib/libkiconv/Makefile | 2 | ||||
-rw-r--r-- | lib/libkiconv/kiconv_sysctl.c | 93 | ||||
-rw-r--r-- | lib/libkiconv/xlat16_iconv.c | 93 |
3 files changed, 163 insertions, 25 deletions
diff --git a/lib/libkiconv/Makefile b/lib/libkiconv/Makefile index afb6392..e66e718 100644 --- a/lib/libkiconv/Makefile +++ b/lib/libkiconv/Makefile @@ -2,7 +2,7 @@ LIB= kiconv SHLIBDIR?= /lib -SRCS= xlat16_iconv.c xlat16_sysctl.c +SRCS= kiconv_sysctl.c xlat16_iconv.c xlat16_sysctl.c SRCS+= quirks.c SHLIB_MAJOR= 3 diff --git a/lib/libkiconv/kiconv_sysctl.c b/lib/libkiconv/kiconv_sysctl.c new file mode 100644 index 0000000..0030f4d --- /dev/null +++ b/lib/libkiconv/kiconv_sysctl.c @@ -0,0 +1,93 @@ +/*- + * Copyright (c) 2005 Ryuichiro Imura + * 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 AND CONTRIBUTORS ``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 OR CONTRIBUTORS 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. + * + * $FreeBSD$ + */ + +#include <sys/types.h> +#include <sys/iconv.h> +#include <sys/sysctl.h> + +#include <ctype.h> +#include <errno.h> +#include <stdlib.h> +#include <string.h> + +int +kiconv_lookupconv(const char *drvname) +{ + size_t size; + int error; + + if (sysctlbyname("kern.iconv.drvlist", NULL, &size, NULL, 0) == -1) + return (errno); + if (size > 0) { + char *drivers, *drvp; + + drivers = malloc(size); + if (drivers == NULL) + return (ENOMEM); + if (sysctlbyname("kern.iconv.drvlist", drivers, &size, NULL, 0) == -1) { + error = errno; + free(drivers); + return (errno); + } + for (drvp = drivers; *drvp != '\0'; drvp += strlen(drvp) + 1) + if (strcmp(drvp, drvname) == 0) { + free(drivers); + return (0); + } + } + return (ENOENT); +} + +int +kiconv_lookupcs(const char *tocode, const char *fromcode) +{ + size_t i, size; + struct iconv_cspair_info *csi, *csip; + int error; + + if (sysctlbyname("kern.iconv.cslist", NULL, &size, NULL, 0) == -1) + return (errno); + if (size > 0) { + csi = malloc(size); + if (csi == NULL) + return (ENOMEM); + if (sysctlbyname("kern.iconv.cslist", csi, &size, NULL, 0) == -1) { + error = errno; + free(csi); + return (error); + } + for (i = 0, csip = csi; i < (size/sizeof(*csi)); i++, csip++){ + if (strcmp(csip->cs_to, tocode) == 0 && + strcmp(csip->cs_from, fromcode) == 0) { + free(csi); + return (0); + } + } + } + return (ENOENT); +} diff --git a/lib/libkiconv/xlat16_iconv.c b/lib/libkiconv/xlat16_iconv.c index db304c3..ce06324 100644 --- a/lib/libkiconv/xlat16_iconv.c +++ b/lib/libkiconv/xlat16_iconv.c @@ -1,5 +1,5 @@ /*- - * Copyright (c) 2003 Ryuichiro Imura + * Copyright (c) 2003, 2005 Ryuichiro Imura * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -41,9 +41,11 @@ #include <dlfcn.h> #include <err.h> #include <errno.h> +#include <locale.h> #include <stdio.h> #include <stdlib.h> #include <string.h> +#include <wctype.h> #include "quirks.h" @@ -56,6 +58,7 @@ struct xlat16_table { }; static struct xlat16_table kiconv_xlat16_open(const char *, const char *, int); +static int chklocale(int, const char *); static int my_iconv_init(void); static iconv_t (*my_iconv_open)(const char *, const char *); @@ -67,30 +70,18 @@ int kiconv_add_xlat16_cspair(const char *tocode, const char *fromcode, int flag) { int error; - size_t i, size, idxsize; - struct iconv_cspair_info *csi; + size_t idxsize; struct xlat16_table xt; void *data; char *p; - if (sysctlbyname("kern.iconv.cslist", NULL, &size, NULL, 0) == -1) - return (-1); - if (size > 0) { - csi = malloc(size); - if (csi == NULL) - return (-1); - if (sysctlbyname("kern.iconv.cslist", csi, &size, NULL, 0) == -1) { - free(csi); - return (-1); - } - for (i = 0; i < (size/sizeof(*csi)); i++, csi++){ - if (strcmp(csi->cs_to, tocode) == 0 && - strcmp(csi->cs_from, fromcode) == 0) - return (0); - } - } + if (kiconv_lookupcs(tocode, fromcode) == 0) + return (0); - xt = kiconv_xlat16_open(tocode, fromcode, flag); + if (flag & KICONV_WCTYPE) + xt = kiconv_xlat16_open(fromcode, fromcode, flag); + else + xt = kiconv_xlat16_open(tocode, fromcode, flag); if (xt.size == 0) return (-1); @@ -117,7 +108,7 @@ kiconv_add_xlat16_cspair(const char *tocode, const char *fromcode, int flag) int kiconv_add_xlat16_cspairs(const char *foreigncode, const char *localcode) { - int error; + int error, locale; error = kiconv_add_xlat16_cspair(foreigncode, localcode, KICONV_FROM_LOWER | KICONV_FROM_UPPER); @@ -127,7 +118,14 @@ kiconv_add_xlat16_cspairs(const char *foreigncode, const char *localcode) KICONV_LOWER | KICONV_UPPER); if (error) return (error); - + locale = chklocale(LC_CTYPE, localcode); + if (locale == 0) { + error = kiconv_add_xlat16_cspair(KICONV_WCTYPE_NAME, localcode, + KICONV_WCTYPE); + if (error) + return (error); + } + return (0); } @@ -175,6 +173,31 @@ kiconv_xlat16_open(const char *tocode, const char *fromcode, int lcase) bzero(dst, outbytesleft); c = ((ls & 0x100 ? us | 0x80 : us) << 8) | (u_char)ls; + + if (lcase & KICONV_WCTYPE) { + if ((c & 0xff) == 0) + c >>= 8; + if (iswupper(c)) { + c = towlower(c); + if ((c & 0xff00) == 0) + c <<= 8; + table[us] = c | XLAT16_HAS_LOWER_CASE; + } else if (iswlower(c)) { + c = towupper(c); + if ((c & 0xff00) == 0) + c <<= 8; + table[us] = c | XLAT16_HAS_UPPER_CASE; + } else + table[us] = 0; + /* + * store not NULL + */ + if (table[us]) + xt.idx[ls] = table; + + continue; + } + c = quirk_vendor2unix(c, pre_q_list, pre_q_size); src[0] = (u_char)(c >> 8); src[1] = (u_char)c; @@ -258,6 +281,24 @@ kiconv_xlat16_open(const char *tocode, const char *fromcode, int lcase) } static int +chklocale(int category, const char *code) +{ + char *p; + int error = -1; + + p = strchr(setlocale(category, NULL), '.'); + if (p++) { + error = strcasecmp(code, p); + if (error) { + /* XXX - can't avoid calling quirk here... */ + error = strcasecmp(code, kiconv_quirkcs(p, + KICONV_VENDOR_MICSFT)); + } + } + return (error); +} + +static int my_iconv_init(void) { void *iconv_lib; @@ -380,17 +421,21 @@ my_iconv_char(iconv_t cd, const u_char **ibuf, size_t * ilen, u_char **obuf, #else /* statically linked */ +#include <sys/types.h> +#include <sys/iconv.h> #include <errno.h> int -kiconv_add_xlat16_cspair(const char *tocode, const char *fromcode, int flag) +kiconv_add_xlat16_cspair(const char *tocode __unused, const char *fromcode __unused, + int flag __unused) { + errno = EINVAL; return (-1); } int -kiconv_add_xlat16_cspairs(const char *tocode, const char *fromcode) +kiconv_add_xlat16_cspairs(const char *tocode __unused, const char *fromcode __unused) { errno = EINVAL; return (-1); |