diff --git a/sys/conf/NOTES b/sys/conf/NOTES index b1456aebf0d..3513ef37ec7 100644 --- a/sys/conf/NOTES +++ b/sys/conf/NOTES @@ -978,6 +978,9 @@ device ccd 4 #Concatenated disk driver device vinum #Vinum concat/mirror/raid driver options VINUMDEBUG #enable Vinum debugging hooks +# Kernel side iconv library +options LIBICONV + # Size of the kernel message buffer. Should be N * pagesize. options MSGBUF_SIZE=40960 diff --git a/sys/conf/files b/sys/conf/files index 5dddc371621..604189ccf8a 100644 --- a/sys/conf/files +++ b/sys/conf/files @@ -764,6 +764,9 @@ kern/vfs_vnops.c standard libkern/arc4random.c standard libkern/bcd.c standard libkern/bsearch.c standard +libkern/iconv.c optional libiconv +libkern/iconv_converter_if.m optional libiconv +libkern/iconv_xlat.c optional libiconv libkern/index.c standard libkern/inet_ntoa.c standard libkern/mcount.c optional profiling-routine diff --git a/sys/conf/kmod.mk b/sys/conf/kmod.mk index 31d8f1815a1..7a279f31bb4 100644 --- a/sys/conf/kmod.mk +++ b/sys/conf/kmod.mk @@ -272,7 +272,9 @@ ${_src}: .endfor MFILES?= kern/bus_if.m kern/device_if.m dev/iicbus/iicbb_if.m \ - dev/iicbus/iicbus_if.m isa/isa_if.m dev/mii/miibus_if.m \ + dev/iicbus/iicbus_if.m isa/isa_if.m \ + libkern/iconv_converter_if.m \ + dev/mii/miibus_if.m \ dev/pccard/card_if.m dev/pccard/power_if.m dev/pci/pci_if.m \ dev/pci/pcib_if.m dev/ppbus/ppbus_if.m dev/smbus/smbus_if.m \ dev/usb/usb_if.m dev/sound/pcm/ac97_if.m dev/sound/pcm/channel_if.m \ diff --git a/sys/conf/options b/sys/conf/options index d4c375a0244..07dff222bb2 100644 --- a/sys/conf/options +++ b/sys/conf/options @@ -65,6 +65,7 @@ GDB_REMOTE_CHAT opt_ddb.h DEVFS HW_WDOG KTRACE +LIBICONV MD_ROOT opt_md.h MD_ROOT_SIZE opt_md.h MFS_ROOT opt_mfs.h diff --git a/sys/i386/conf/NOTES b/sys/i386/conf/NOTES index b1456aebf0d..3513ef37ec7 100644 --- a/sys/i386/conf/NOTES +++ b/sys/i386/conf/NOTES @@ -978,6 +978,9 @@ device ccd 4 #Concatenated disk driver device vinum #Vinum concat/mirror/raid driver options VINUMDEBUG #enable Vinum debugging hooks +# Kernel side iconv library +options LIBICONV + # Size of the kernel message buffer. Should be N * pagesize. options MSGBUF_SIZE=40960 diff --git a/sys/libkern/iconv.c b/sys/libkern/iconv.c new file mode 100644 index 00000000000..8eafa281d88 --- /dev/null +++ b/sys/libkern/iconv.c @@ -0,0 +1,479 @@ +/* + * Copyright (c) 2000-2001, Boris Popov + * 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. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by Boris Popov. + * 4. Neither the name of the author nor the names of any co-contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * 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 +#include +#include +#include +#include + +#include "iconv_converter_if.h" + +SYSCTL_DECL(_kern_iconv); + +SYSCTL_NODE(_kern, OID_AUTO, iconv, CTLFLAG_RW, NULL, "kernel iconv interface"); + +MALLOC_DEFINE(M_ICONV, "ICONV", "ICONV structures"); +MALLOC_DEFINE(M_ICONVDATA, "ICONV data", "ICONV data"); + +MODULE_VERSION(libiconv, 1); + +#ifdef notnow +/* + * iconv converter instance + */ +struct iconv_converter { + KOBJ_FIELDS; + void * c_data; +}; +#endif + +struct sysctl_oid *iconv_oid_hook = &sysctl___kern_iconv; + +/* + * List of loaded converters + */ +static TAILQ_HEAD(iconv_converter_list, iconv_converter_class) + iconv_converters = TAILQ_HEAD_INITIALIZER(iconv_converters); + +/* + * List of supported/loaded charsets pairs + */ +static TAILQ_HEAD(, iconv_cspair) + iconv_cslist = TAILQ_HEAD_INITIALIZER(iconv_cslist); +static int iconv_csid = 1; + +static char iconv_unicode_string[] = "unicode"; /* save eight bytes when possible */ + +static void iconv_unregister_cspair(struct iconv_cspair *csp); + +static int +iconv_mod_unload(void) +{ + struct iconv_cspair *csp; + + while ((csp = TAILQ_FIRST(&iconv_cslist)) != NULL) { + if (csp->cp_refcount) + return EBUSY; + iconv_unregister_cspair(csp); + } + return 0; +} + +static int +iconv_mod_handler(module_t mod, int type, void *data) +{ + int error; + + switch (type) { + case MOD_LOAD: + error = 0; + break; + case MOD_UNLOAD: + error = iconv_mod_unload(); + break; + default: + error = EINVAL; + } + return error; +} + +static moduledata_t iconv_mod = { + "iconv", iconv_mod_handler, NULL +}; + +DECLARE_MODULE(iconv, iconv_mod, SI_SUB_DRIVERS, SI_ORDER_SECOND); + +static int +iconv_register_converter(struct iconv_converter_class *dcp) +{ + kobj_class_compile((struct kobj_class*)dcp); + dcp->refs++; + TAILQ_INSERT_TAIL(&iconv_converters, dcp, cc_link); + return 0; +} + +static int +iconv_unregister_converter(struct iconv_converter_class *dcp) +{ + if (dcp->refs > 1) { + ICDEBUG("converter have %d referenses left\n", dcp->refs); + return EBUSY; + } + TAILQ_REMOVE(&iconv_converters, dcp, cc_link); + kobj_class_free((struct kobj_class*)dcp); + return 0; +} + +static int +iconv_lookupconv(const char *name, struct iconv_converter_class **dcpp) +{ + struct iconv_converter_class *dcp; + + TAILQ_FOREACH(dcp, &iconv_converters, cc_link) { + if (name == NULL) + continue; + if (strcmp(name, ICONV_CONVERTER_NAME(dcp)) == 0) { + if (dcpp) + *dcpp = dcp; + return 0; + } + } + return ENOENT; +} + +static int +iconv_lookupcs(const char *to, const char *from, struct iconv_cspair **cspp) +{ + struct iconv_cspair *csp; + + TAILQ_FOREACH(csp, &iconv_cslist, cp_link) { + if (strcmp(csp->cp_to, to) == 0 && + strcmp(csp->cp_from, from) == 0) { + if (cspp) + *cspp = csp; + return 0; + } + } + return ENOENT; +} + +static int +iconv_register_cspair(const char *to, const char *from, + struct iconv_converter_class *dcp, void *data, + struct iconv_cspair **cspp) +{ + struct iconv_cspair *csp; + char *cp; + int csize, ucsto, ucsfrom; + + if (iconv_lookupcs(to, from, NULL) == 0) + return EEXIST; + csize = sizeof(*csp); + ucsto = strcmp(to, iconv_unicode_string) == 0; + if (!ucsto) + csize += strlen(to) + 1; + ucsfrom = strcmp(from, iconv_unicode_string) == 0; + if (!ucsfrom) + csize += strlen(from) + 1; + csp = malloc(csize, M_ICONV, M_WAITOK); + bzero(csp, csize); + csp->cp_id = iconv_csid++; + csp->cp_dcp = dcp; + cp = (char*)(csp + 1); + if (!ucsto) { + strcpy(cp, to); + csp->cp_to = cp; + cp += strlen(cp) + 1; + } else + csp->cp_to = iconv_unicode_string; + if (!ucsfrom) { + strcpy(cp, from); + csp->cp_from = cp; + } else + csp->cp_from = iconv_unicode_string; + csp->cp_data = data; + + TAILQ_INSERT_TAIL(&iconv_cslist, csp, cp_link); + *cspp = csp; + return 0; +} + +static void +iconv_unregister_cspair(struct iconv_cspair *csp) +{ + TAILQ_REMOVE(&iconv_cslist, csp, cp_link); + if (csp->cp_data) + free(csp->cp_data, M_ICONVDATA); + free(csp, M_ICONV); +} + +/* + * Lookup and create an instance of converter. + * Currently this layer didn't have associated 'instance' structure + * to avoid unnesessary memory allocation. + */ +int +iconv_open(const char *to, const char *from, void **handle) +{ + struct iconv_cspair *csp, *cspfrom, *cspto; + struct iconv_converter_class *dcp; + const char *cnvname; + int error; + + /* + * First, lookup fully qualified cspairs + */ + error = iconv_lookupcs(to, from, &csp); + if (error == 0) + return ICONV_CONVERTER_OPEN(csp->cp_dcp, csp, NULL, handle); + + /* + * Well, nothing found. Now try to construct a composite conversion + * ToDo: add a 'capability' field to converter + */ + TAILQ_FOREACH(dcp, &iconv_converters, cc_link) { + cnvname = ICONV_CONVERTER_NAME(dcp); + if (cnvname == NULL) + continue; + error = iconv_lookupcs(cnvname, from, &cspfrom); + if (error) + continue; + error = iconv_lookupcs(to, cnvname, &cspto); + if (error) + continue; + /* + * Fine, we're found a pair which can be combined together + */ + return ICONV_CONVERTER_OPEN(dcp, cspto, cspfrom, handle); + } + return ENOENT; +} + +int +iconv_close(void *handle) +{ + return ICONV_CONVERTER_CLOSE(handle); +} + +int +iconv_conv(void *handle, const char **inbuf, + size_t *inbytesleft, char **outbuf, size_t *outbytesleft) +{ + return ICONV_CONVERTER_CONV(handle, inbuf, inbytesleft, outbuf, outbytesleft); +} + +/* + * Give a list of loaded converters. Each name terminated with 0. + * An empty string terminates the list. + */ +static int +iconv_sysctl_drvlist(SYSCTL_HANDLER_ARGS) +{ + struct iconv_converter_class *dcp; + const char *name; + char spc; + int error; + + error = 0; + + TAILQ_FOREACH(dcp, &iconv_converters, cc_link) { + name = ICONV_CONVERTER_NAME(dcp); + if (name == NULL) + continue; + error = SYSCTL_OUT(req, name, strlen(name) + 1); + if (error) + break; + } + if (error) + return error; + spc = 0; + error = SYSCTL_OUT(req, &spc, sizeof(spc)); + return error; +} + +SYSCTL_PROC(_kern_iconv, OID_AUTO, drvlist, CTLFLAG_RD | CTLTYPE_OPAQUE, + NULL, 0, iconv_sysctl_drvlist, "S,xlat", "registered converters"); + +/* + * List all available charset pairs. + */ +static int +iconv_sysctl_cslist(SYSCTL_HANDLER_ARGS) +{ + struct iconv_cspair *csp; + struct iconv_cspair_info csi; + int error; + + error = 0; + bzero(&csi, sizeof(csi)); + csi.cs_version = ICONV_CSPAIR_INFO_VER; + + TAILQ_FOREACH(csp, &iconv_cslist, cp_link) { + csi.cs_id = csp->cp_id; + csi.cs_refcount = csp->cp_refcount; + csi.cs_base = csp->cp_base ? csp->cp_base->cp_id : 0; + strcpy(csi.cs_to, csp->cp_to); + strcpy(csi.cs_from, csp->cp_from); + error = SYSCTL_OUT(req, &csi, sizeof(csi)); + if (error) + break; + } + return error; +} + +SYSCTL_PROC(_kern_iconv, OID_AUTO, cslist, CTLFLAG_RD | CTLTYPE_OPAQUE, + NULL, 0, iconv_sysctl_cslist, "S,xlat", "registered charset pairs"); + +/* + * Add new charset pair + */ +static int +iconv_sysctl_add(SYSCTL_HANDLER_ARGS) +{ + struct iconv_converter_class *dcp; + struct iconv_cspair *csp; + struct iconv_add_in din; + struct iconv_add_out dout; + int error; + + error = SYSCTL_IN(req, &din, sizeof(din)); + if (error) + return error; + if (din.ia_version != ICONV_ADD_VER) + return EINVAL; + if (din.ia_datalen > ICONV_CSMAXDATALEN) + return EINVAL; + if (iconv_lookupconv(din.ia_converter, &dcp) != 0) + return EINVAL; + error = iconv_register_cspair(din.ia_to, din.ia_from, dcp, NULL, &csp); + if (error) + return error; + if (din.ia_datalen) { + csp->cp_data = malloc(din.ia_datalen, M_ICONVDATA, M_WAITOK); + error = copyin(din.ia_data, csp->cp_data, din.ia_datalen); + if (error) + goto bad; + } + dout.ia_csid = csp->cp_id; + error = SYSCTL_OUT(req, &dout, sizeof(dout)); + if (error) + goto bad; + return 0; +bad: + iconv_unregister_cspair(csp); + return error; +} + +SYSCTL_PROC(_kern_iconv, OID_AUTO, add, CTLFLAG_RW | CTLTYPE_OPAQUE, + NULL, 0, iconv_sysctl_add, "S,xlat", "register charset pair"); + +/* + * Default stubs for converters + */ +int +iconv_converter_initstub(struct iconv_converter_class *dp) +{ + return 0; +} + +int +iconv_converter_donestub(struct iconv_converter_class *dp) +{ + return 0; +} + +int +iconv_converter_handler(module_t mod, int type, void *data) +{ + struct iconv_converter_class *dcp = data; + int error; + + switch (type) { + case MOD_LOAD: + error = iconv_register_converter(dcp); + if (error) + break; + error = ICONV_CONVERTER_INIT(dcp); + if (error) + iconv_unregister_converter(dcp); + break; + case MOD_UNLOAD: + ICONV_CONVERTER_DONE(dcp); + error = iconv_unregister_converter(dcp); + break; + default: + error = EINVAL; + } + return error; +} + +/* + * Common used functions + */ +char * +iconv_convstr(void *handle, char *dst, const char *src) +{ + char *p = dst; + int inlen, outlen, error; + + if (handle == NULL) { + strcpy(dst, src); + return dst; + } + inlen = outlen = strlen(src); + error = iconv_conv(handle, NULL, NULL, &p, &outlen); + if (error) + return NULL; + error = iconv_conv(handle, &src, &inlen, &p, &outlen); + if (error) + return NULL; + *p = 0; + return dst; +} + +void * +iconv_convmem(void *handle, void *dst, const void *src, int size) +{ + const char *s = src; + char *d = dst; + int inlen, outlen, error; + + if (size == 0) + return dst; + if (handle == NULL) { + memcpy(dst, src, size); + return dst; + } + inlen = outlen = size; + error = iconv_conv(handle, NULL, NULL, &d, &outlen); + if (error) + return NULL; + error = iconv_conv(handle, &s, &inlen, &d, &outlen); + if (error) + return NULL; + return dst; +} + +int +iconv_lookupcp(char **cpp, const char *s) +{ + if (cpp == NULL) { + ICDEBUG("warning a NULL list passed\n"); + return ENOENT; + } + for (; *cpp; cpp++) + if (strcmp(*cpp, s) == 0) + return 0; + return ENOENT; +} diff --git a/sys/libkern/iconv_converter_if.m b/sys/libkern/iconv_converter_if.m new file mode 100644 index 00000000000..0b2901c45c5 --- /dev/null +++ b/sys/libkern/iconv_converter_if.m @@ -0,0 +1,68 @@ +# +# Copyright (c) 2000-2001, Boris Popov +# 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. +# 3. All advertising materials mentioning features or use of this software +# must display the following acknowledgement: +# This product includes software developed by Boris Popov. +# 4. Neither the name of the author nor the names of any co-contributors +# may be used to endorse or promote products derived from this software +# without specific prior written permission. +# +# 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 + +INTERFACE iconv_converter; + +STATICMETHOD int open { + struct iconv_converter_class *dcp; + struct iconv_cspair *cspto; + struct iconv_cspair *cspfrom; + void **hpp; +}; + +METHOD int close { + void *handle; +}; + +METHOD int conv { + void *handle; + const char **inbuf; + size_t *inbytesleft; + char **outbuf; + size_t *outbytesleft; +}; + +STATICMETHOD int init { + struct iconv_converter_class *dcp; +} DEFAULT iconv_converter_initstub; + +STATICMETHOD void done { + struct iconv_converter_class *dcp; +} DEFAULT iconv_converter_donestub; + +STATICMETHOD const char * name { + struct iconv_converter_class *dcp; +}; diff --git a/sys/libkern/iconv_xlat.c b/sys/libkern/iconv_xlat.c new file mode 100644 index 00000000000..6dd2800a535 --- /dev/null +++ b/sys/libkern/iconv_xlat.c @@ -0,0 +1,124 @@ +/* + * Copyright (c) 2000-2001, Boris Popov + * 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. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by Boris Popov. + * 4. Neither the name of the author nor the names of any co-contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * 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 +#include +#include +#include +#include + +#include "iconv_converter_if.h" + +/* + * "XLAT" converter + */ + +#ifdef MODULE_DEPEND +MODULE_DEPEND(iconv_xlat, libiconv, 1, 1, 1); +#endif + +/* + * XLAT converter instance + */ +struct iconv_xlat { + KOBJ_FIELDS; + u_char * d_table; + struct iconv_cspair * d_csp; +}; + +static int +iconv_xlat_open(struct iconv_converter_class *dcp, + struct iconv_cspair *csp, struct iconv_cspair *cspf, void **dpp) +{ + struct iconv_xlat *dp; + + dp = (struct iconv_xlat *)kobj_create((struct kobj_class*)dcp, M_ICONV, M_WAITOK); + dp->d_table = csp->cp_data; + dp->d_csp = csp; + csp->cp_refcount++; + *dpp = (void*)dp; + return 0; +} + +static int +iconv_xlat_close(void *data) +{ + struct iconv_xlat *dp = data; + + dp->d_csp->cp_refcount--; + kobj_delete((struct kobj*)data, M_ICONV); + return 0; +} + +static int +iconv_xlat_conv(void *d2p, const char **inbuf, + size_t *inbytesleft, char **outbuf, size_t *outbytesleft) +{ + struct iconv_xlat *dp = (struct iconv_xlat*)d2p; + const char *src; + char *dst; + int n, r; + + if (inbuf == NULL || *inbuf == NULL || outbuf == NULL || *outbuf == NULL) + return 0; + r = n = min(*inbytesleft, *outbytesleft); + src = *inbuf; + dst = *outbuf; + while(r--) + *dst++ = dp->d_table[(u_char)*src++]; + *inbuf += n; + *outbuf += n; + *inbytesleft += n; + *outbytesleft -= n; + return 0; +} + +static const char * +iconv_xlat_name(struct iconv_converter_class *dcp) +{ + return "xlat"; +} + +static kobj_method_t iconv_xlat_methods[] = { + KOBJMETHOD(iconv_converter_open, iconv_xlat_open), + KOBJMETHOD(iconv_converter_close, iconv_xlat_close), + KOBJMETHOD(iconv_converter_conv, iconv_xlat_conv), +#if 0 + KOBJMETHOD(iconv_converter_init, iconv_xlat_init), + KOBJMETHOD(iconv_converter_done, iconv_xlat_done), +#endif + KOBJMETHOD(iconv_converter_name, iconv_xlat_name), + {0, 0} +}; + +KICONV_CONVERTER(xlat, sizeof(struct iconv_xlat)); diff --git a/sys/sys/iconv.h b/sys/sys/iconv.h new file mode 100644 index 00000000000..4764aaf0bfd --- /dev/null +++ b/sys/sys/iconv.h @@ -0,0 +1,156 @@ +/* + * Copyright (c) 2000-2001, Boris Popov + * 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. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by Boris Popov. + * 4. Neither the name of the author nor the names of any co-contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * 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$ + */ +#ifndef _SYS_ICONV_H_ +#define _SYS_ICONV_H_ + +#define ICONV_CSNMAXLEN 31 /* maximum length of charset name */ +#define ICONV_CNVNMAXLEN 31 /* maximum length of converter name */ +#define ICONV_CSMAXDATALEN 1024 /* maximum size of data associated with cs pair */ + +/* + * Entry for cslist sysctl + */ +#define ICONV_CSPAIR_INFO_VER 1 + +struct iconv_cspair_info { + int cs_version; + int cs_id; + int cs_base; + int cs_refcount; + char cs_to[ICONV_CSNMAXLEN]; + char cs_from[ICONV_CSNMAXLEN]; +}; + +/* + * Paramters for 'add' sysctl + */ +#define ICONV_ADD_VER 1 + +struct iconv_add_in { + int ia_version; + char ia_converter[ICONV_CNVNMAXLEN]; + char ia_to[ICONV_CSNMAXLEN]; + char ia_from[ICONV_CSNMAXLEN]; + int ia_datalen; + const void *ia_data; +}; + +struct iconv_add_out { + int ia_csid; +}; + +#ifndef _KERNEL + +__BEGIN_DECLS + +int kiconv_add_xlat_table(const char *, const char *, const u_char *); + +__END_DECLS + +#else /* !_KERNEL */ + +#include +#include /* can't avoid that */ +#include /* can't avoid that */ + +struct iconv_cspair; +struct iconv_cspairdata; + +/* + * iconv converter class definition + */ +struct iconv_converter_class { + KOBJ_CLASS_FIELDS; + TAILQ_ENTRY(iconv_converter_class) cc_link; +}; + +struct iconv_cspair { + int cp_id; /* unique id of charset pair */ + int cp_refcount; /* number of references from other pairs */ + const char * cp_from; + const char * cp_to; + void * cp_data; + struct iconv_converter_class * cp_dcp; + struct iconv_cspair *cp_base; + TAILQ_ENTRY(iconv_cspair) cp_link; +}; + +#define KICONV_CONVERTER(name,size) \ + static DEFINE_CLASS(iconv_ ## name, iconv_ ## name ## _methods, (size)); \ + static moduledata_t iconv_ ## name ## _mod = { \ + "iconv_"#name, iconv_converter_handler, \ + (void*)&iconv_ ## name ## _class \ + }; \ + DECLARE_MODULE(iconv_ ## name, iconv_ ## name ## _mod, SI_SUB_DRIVERS, SI_ORDER_ANY); + +#define KICONV_CES(name,size) \ + static DEFINE_CLASS(iconv_ces_ ## name, iconv_ces_ ## name ## _methods, (size)); \ + static moduledata_t iconv_ces_ ## name ## _mod = { \ + "iconv_ces_"#name, iconv_cesmod_handler, \ + (void*)&iconv_ces_ ## name ## _class \ + }; \ + DECLARE_MODULE(iconv_ces_ ## name, iconv_ces_ ## name ## _mod, SI_SUB_DRIVERS, SI_ORDER_ANY); + +#ifdef MALLOC_DECLARE +MALLOC_DECLARE(M_ICONV); +#endif + +/* + * Basic conversion functions + */ +int iconv_open(const char *to, const char *from, void **handle); +int iconv_close(void *handle); +int iconv_conv(void *handle, const char **inbuf, + size_t *inbytesleft, char **outbuf, size_t *outbytesleft); +char* iconv_convstr(void *handle, char *dst, const char *src); +void* iconv_convmem(void *handle, void *dst, const void *src, int size); + +/* + * Internal functions + */ +int iconv_lookupcp(char **cpp, const char *s); + +int iconv_converter_initstub(struct iconv_converter_class *dp); +int iconv_converter_donestub(struct iconv_converter_class *dp); +int iconv_converter_handler(module_t mod, int type, void *data); + +#ifdef ICONV_DEBUG +#define ICDEBUG(format, args...) printf("%s: "format, __FUNCTION__ ,## args) +#else +#define ICDEBUG(format, args...) +#endif + +#endif /* !_KERNEL */ + +#endif /* !_SYS_ICONV_H_ */