1 /* $NetBSD: citrus_iconv.c,v 1.1 2003/06/25 09:51:34 tshiozak Exp $ */ 2 3 /*- 4 * Copyright (c)2003 Citrus Project, 5 * All rights reserved. 6 * 7 * Redistribution and use in source and binary forms, with or without 8 * modification, are permitted provided that the following conditions 9 * are met: 10 * 1. Redistributions of source code must retain the above copyright 11 * notice, this list of conditions and the following disclaimer. 12 * 2. Redistributions in binary form must reproduce the above copyright 13 * notice, this list of conditions and the following disclaimer in the 14 * documentation and/or other materials provided with the distribution. 15 * 16 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 17 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 18 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 19 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 20 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 21 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 22 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 23 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 24 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 25 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 26 * SUCH DAMAGE. 27 */ 28 29 #include <sys/cdefs.h> 30 #if defined(LIBC_SCCS) && !defined(lint) 31 __RCSID("$NetBSD: citrus_iconv.c,v 1.1 2003/06/25 09:51:34 tshiozak Exp $"); 32 #endif /* LIBC_SCCS and not lint */ 33 34 #include "namespace.h" 35 #include <assert.h> 36 #include <stdio.h> 37 #include <stdlib.h> 38 #include <string.h> 39 #include <errno.h> 40 #include <limits.h> 41 #include <unistd.h> 42 #include <paths.h> 43 #include <dirent.h> 44 #include <sys/types.h> 45 46 #include "citrus_namespace.h" 47 #include "citrus_bcs.h" 48 #include "citrus_region.h" 49 #include "citrus_memstream.h" 50 #include "citrus_mmap.h" 51 #include "citrus_module.h" 52 #include "citrus_lookup.h" 53 #include "citrus_iconv.h" 54 55 #define _CITRUS_ICONV_DIR "iconv.dir" 56 #define _CITRUS_ICONV_ALIAS "iconv.alias" 57 58 /* 59 * lookup_iconv_entry: 60 * lookup iconv.dir entry in the specified directory. 61 * 62 * line format of iconv.dir file: 63 * key module arg 64 * key : lookup key. 65 * module : iconv module name. 66 * arg : argument for the module (generally, description file name) 67 * 68 */ 69 static __inline int 70 lookup_iconv_entry(const char *curdir, const char *key, 71 char *linebuf, size_t linebufsize, 72 const char **module, const char **variable) 73 { 74 const char *cp, *cq; 75 char *p, path[PATH_MAX]; 76 77 /* iconv.dir path */ 78 snprintf(path, PATH_MAX, "%s/" _CITRUS_ICONV_DIR, curdir); 79 80 /* lookup db */ 81 cp = p = _lookup_simple(path, key, linebuf, linebufsize); 82 if (p == NULL) 83 return ENOENT; 84 85 /* get module name */ 86 *module = p; 87 cq = _bcs_skip_nonws(cp); 88 p[cq-cp] = '\0'; 89 p += cq-cp+1; 90 cq++; 91 92 /* get variable */ 93 cp = _bcs_skip_ws(cq); 94 *variable = p += cp - cq; 95 cq = _bcs_skip_nonws(cp); 96 p[cq-cp] = '\0'; 97 98 return 0; 99 } 100 101 /* 102 * _citrus_iconv_open: 103 * open a converter for the specified in/out codes. 104 */ 105 int 106 _citrus_iconv_open(struct _citrus_iconv * __restrict * __restrict rci, 107 const char * __restrict basedir, 108 const char * __restrict src, const char * __restrict dst) 109 { 110 int ret; 111 struct _citrus_iconv *ci; 112 _citrus_iconv_getops_t getops; 113 char realsrc[PATH_MAX], realdst[PATH_MAX], key[PATH_MAX]; 114 char linebuf[PATH_MAX], path[PATH_MAX]; 115 const char *module, *variable; 116 117 /* resolve codeset name aliases */ 118 snprintf(path, sizeof(path), "%s/%s", basedir, _CITRUS_ICONV_ALIAS); 119 strlcpy(realsrc, _lookup_alias(path, src, linebuf, PATH_MAX), PATH_MAX); 120 strlcpy(realdst, _lookup_alias(path, dst, linebuf, PATH_MAX), PATH_MAX); 121 122 /* sanity check */ 123 if (strchr(realsrc, '/') != NULL || strchr(realdst, '/')) 124 return EINVAL; 125 126 /* search converter entry */ 127 snprintf(key, sizeof(key), "%s/%s", realsrc, realdst); 128 ret = lookup_iconv_entry(basedir, key, linebuf, PATH_MAX, 129 &module, &variable); 130 if (ret) { 131 if (ret == ENOENT) 132 /* fallback */ 133 ret = lookup_iconv_entry(basedir, "*", 134 linebuf, PATH_MAX, 135 &module, &variable); 136 if (ret) 137 return ret; 138 } 139 140 /* initialize iconv handle */ 141 ci = malloc(sizeof(*ci)); 142 if (!ci) { 143 ret = errno; 144 goto err; 145 } 146 ci->ci_module = NULL; 147 ci->ci_ops = NULL; 148 ci->ci_closure = NULL; 149 150 /* load module */ 151 ret = _citrus_load_module(&ci->ci_module, module); 152 if (ret) 153 goto err; 154 155 /* get operators */ 156 getops = (_citrus_iconv_getops_t) 157 _citrus_find_getops(ci->ci_module, module, "iconv"); 158 if (!getops) { 159 ret = EOPNOTSUPP; 160 goto err; 161 } 162 ci->ci_ops = malloc(sizeof(*ci->ci_ops)); 163 if (!ci->ci_ops) { 164 ret = errno; 165 goto err; 166 } 167 ret = (*getops)(ci->ci_ops, sizeof(*ci->ci_ops), 168 _CITRUS_ICONV_ABI_VERSION); 169 if (ret) 170 goto err; 171 172 if (!ci->ci_ops->io_init || 173 !ci->ci_ops->io_uninit || 174 !ci->ci_ops->io_convert) 175 goto err; 176 177 /* initialize the converter */ 178 ret = (*ci->ci_ops->io_init)(ci, basedir, realsrc, realdst, 179 (const void *)variable, 180 strlen(variable)+1); 181 if (ret) 182 goto err; 183 184 *rci = ci; 185 186 return 0; 187 err: 188 _citrus_iconv_close(ci); 189 return ret; 190 } 191 192 /* 193 * _citrus_iconv_close: 194 * close the specified converter. 195 */ 196 void 197 _citrus_iconv_close(struct _citrus_iconv *ci) 198 { 199 if (ci) { 200 if (ci->ci_module) { 201 if (ci->ci_ops) { 202 if (ci->ci_closure) 203 (*ci->ci_ops->io_uninit)(ci); 204 free(ci->ci_ops); 205 } 206 _citrus_unload_module(ci->ci_module); 207 } 208 free(ci); 209 } 210 } 211