bsd_iconv.c revision 250981
1240116Smarcel/* $FreeBSD: head/lib/libc/iconv/iconv.c 250981 2013-05-25 12:13:54Z ed $ */ 2240116Smarcel/* $NetBSD: iconv.c,v 1.11 2009/03/03 16:22:33 explorer Exp $ */ 3240116Smarcel 4240116Smarcel/*- 5240116Smarcel * Copyright (c) 2003 Citrus Project, 6240116Smarcel * Copyright (c) 2009, 2010 Gabor Kovesdan <gabor@FreeBSD.org>, 7240116Smarcel * All rights reserved. 8240116Smarcel * 9240116Smarcel * Redistribution and use in source and binary forms, with or without 10240116Smarcel * modification, are permitted provided that the following conditions 11240116Smarcel * are met: 12240116Smarcel * 1. Redistributions of source code must retain the above copyright 13240116Smarcel * notice, this list of conditions and the following disclaimer. 14240116Smarcel * 2. Redistributions in binary form must reproduce the above copyright 15240116Smarcel * notice, this list of conditions and the following disclaimer in the 16240116Smarcel * documentation and/or other materials provided with the distribution. 17240116Smarcel * 18240116Smarcel * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 19240116Smarcel * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 20240116Smarcel * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 21240116Smarcel * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 22240116Smarcel * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 23240116Smarcel * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 24240116Smarcel * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 25240116Smarcel * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 26240116Smarcel * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 27240116Smarcel * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 28240116Smarcel * SUCH DAMAGE. 29240116Smarcel */ 30240116Smarcel 31240116Smarcel#include <sys/cdefs.h> 32240116Smarcel#include <sys/queue.h> 33240116Smarcel#include <sys/types.h> 34240116Smarcel 35240116Smarcel#include <assert.h> 36240116Smarcel#include <errno.h> 37240116Smarcel#include <iconv.h> 38240116Smarcel#include <limits.h> 39240116Smarcel#include <paths.h> 40240116Smarcel#include <stdbool.h> 41240116Smarcel#include <stdlib.h> 42240116Smarcel#include <string.h> 43240116Smarcel 44240116Smarcel#include "citrus_types.h" 45240116Smarcel#include "citrus_module.h" 46240116Smarcel#include "citrus_esdb.h" 47240116Smarcel#include "citrus_hash.h" 48240116Smarcel#include "citrus_iconv.h" 49240116Smarcel 50240116Smarcel#ifdef __weak_alias 51240116Smarcel__weak_alias(libiconv, _iconv) 52240116Smarcel__weak_alias(libiconv_open, _iconv_open) 53240116Smarcel__weak_alias(libiconv_open_into, _iconv_open_into) 54240116Smarcel__weak_alias(libiconv_close, _iconv_close) 55240116Smarcel__weak_alias(libiconvlist, _iconvlist) 56240116Smarcel__weak_alias(libiconvctl, _iconvctl) 57243051Smarcel__weak_alias(libiconv_set_relocation_prefix, _iconv_set_relocation_prefix) 58240116Smarcel__weak_alias(iconv_canonicalize, _iconv_canonicalize) 59240116Smarcel#endif 60240116Smarcel 61240116Smarcel#define ISBADF(_h_) (!(_h_) || (_h_) == (iconv_t)-1) 62240116Smarcel 63240116Smarcelint _libiconv_version = _LIBICONV_VERSION; 64240116Smarcel 65240116Smarceliconv_t _iconv_open(const char *out, const char *in, 66240116Smarcel struct _citrus_iconv *prealloc); 67240116Smarcel 68240116Smarceliconv_t 69240116Smarcel_iconv_open(const char *out, const char *in, struct _citrus_iconv *handle) 70240116Smarcel{ 71240116Smarcel const char *out_slashes; 72240116Smarcel char *out_noslashes; 73240116Smarcel int ret; 74240116Smarcel 75240116Smarcel /* 76240116Smarcel * Remove anything following a //, as these are options (like 77240116Smarcel * //ignore, //translate, etc) and we just don't handle them. 78240116Smarcel * This is for compatibility with software that uses these 79240116Smarcel * blindly. 80240116Smarcel */ 81240116Smarcel out_slashes = strstr(out, "//"); 82243051Smarcel if (out_slashes != NULL) { 83240116Smarcel out_noslashes = strndup(out, out_slashes - out); 84240116Smarcel if (out_noslashes == NULL) { 85240116Smarcel errno = ENOMEM; 86240116Smarcel return ((iconv_t)-1); 87240116Smarcel } 88240116Smarcel ret = _citrus_iconv_open(&handle, in, out_noslashes); 89240116Smarcel free(out_noslashes); 90240116Smarcel } else { 91240116Smarcel ret = _citrus_iconv_open(&handle, in, out); 92240116Smarcel } 93240116Smarcel 94240116Smarcel if (ret) { 95240116Smarcel errno = ret == ENOENT ? EINVAL : ret; 96240116Smarcel return ((iconv_t)-1); 97240116Smarcel } 98240116Smarcel 99240116Smarcel handle->cv_shared->ci_discard_ilseq = strcasestr(out, "//IGNORE"); 100240116Smarcel handle->cv_shared->ci_hooks = NULL; 101240116Smarcel 102240116Smarcel return ((iconv_t)(void *)handle); 103240116Smarcel} 104240116Smarcel 105240116Smarceliconv_t 106240116Smarcellibiconv_open(const char *out, const char *in) 107240116Smarcel{ 108240116Smarcel 109240116Smarcel return (_iconv_open(out, in, NULL)); 110240116Smarcel} 111240116Smarcel 112240116Smarcelint 113240116Smarcellibiconv_open_into(const char *out, const char *in, iconv_allocation_t *ptr) 114240116Smarcel{ 115240116Smarcel struct _citrus_iconv *handle; 116240116Smarcel 117240116Smarcel handle = (struct _citrus_iconv *)ptr; 118240116Smarcel return ((_iconv_open(out, in, handle) == (iconv_t)-1) ? -1 : 0); 119240116Smarcel} 120240116Smarcel 121240116Smarcelint 122240116Smarcellibiconv_close(iconv_t handle) 123240116Smarcel{ 124240116Smarcel 125240116Smarcel if (ISBADF(handle)) { 126240116Smarcel errno = EBADF; 127240116Smarcel return (-1); 128240116Smarcel } 129240116Smarcel 130240116Smarcel _citrus_iconv_close((struct _citrus_iconv *)(void *)handle); 131240116Smarcel 132240116Smarcel return (0); 133240116Smarcel} 134240116Smarcel 135240116Smarcelsize_t 136240116Smarcellibiconv(iconv_t handle, char **in, size_t *szin, char **out, size_t *szout) 137240116Smarcel{ 138240116Smarcel size_t ret; 139240116Smarcel int err; 140240116Smarcel 141240116Smarcel if (ISBADF(handle)) { 142240116Smarcel errno = EBADF; 143240116Smarcel return ((size_t)-1); 144240116Smarcel } 145240116Smarcel 146240116Smarcel err = _citrus_iconv_convert((struct _citrus_iconv *)(void *)handle, 147240116Smarcel in, szin, out, szout, 0, &ret); 148240116Smarcel if (err) { 149240116Smarcel errno = err; 150240116Smarcel ret = (size_t)-1; 151240116Smarcel } 152240116Smarcel 153240116Smarcel return (ret); 154240116Smarcel} 155240116Smarcel 156240116Smarcelsize_t 157240116Smarcel__iconv(iconv_t handle, char **in, size_t *szin, char **out, 158240116Smarcel size_t *szout, uint32_t flags, size_t *invalids) 159240116Smarcel{ 160240116Smarcel size_t ret; 161240116Smarcel int err; 162240116Smarcel 163240116Smarcel if (ISBADF(handle)) { 164240116Smarcel errno = EBADF; 165240116Smarcel return ((size_t)-1); 166240116Smarcel } 167240116Smarcel 168240116Smarcel err = _citrus_iconv_convert((struct _citrus_iconv *)(void *)handle, 169240116Smarcel in, szin, out, szout, flags, &ret); 170240116Smarcel if (invalids) 171260029Sjmmv *invalids = ret; 172260029Sjmmv if (err) { 173260029Sjmmv errno = err; 174260029Sjmmv ret = (size_t)-1; 175260029Sjmmv } 176260029Sjmmv 177260029Sjmmv return (ret); 178260029Sjmmv} 179260029Sjmmv 180260029Sjmmvint 181260029Sjmmv__iconv_get_list(char ***rlist, size_t *rsz, bool sorted) 182260029Sjmmv{ 183260029Sjmmv int ret; 184260029Sjmmv 185260029Sjmmv ret = _citrus_esdb_get_list(rlist, rsz, sorted); 186240116Smarcel if (ret) { 187240116Smarcel errno = ret; 188240116Smarcel return (-1); 189240116Smarcel } 190240116Smarcel 191240116Smarcel return (0); 192240116Smarcel} 193240116Smarcel 194260029Sjmmvvoid 195240116Smarcel__iconv_free_list(char **list, size_t sz) 196240116Smarcel{ 197240116Smarcel 198 _citrus_esdb_free_list(list, sz); 199} 200 201/* 202 * GNU-compatibile non-standard interfaces. 203 */ 204static int 205qsort_helper(const void *first, const void *second) 206{ 207 const char * const *s1; 208 const char * const *s2; 209 210 s1 = first; 211 s2 = second; 212 return (strcmp(*s1, *s2)); 213} 214 215void 216libiconvlist(int (*do_one) (unsigned int, const char * const *, 217 void *), void *data) 218{ 219 char **list, **names; 220 const char * const *np; 221 char *curitem, *curkey, *slashpos; 222 size_t sz; 223 unsigned int i, j; 224 225 i = 0; 226 227 if (__iconv_get_list(&list, &sz, true)) 228 list = NULL; 229 qsort((void *)list, sz, sizeof(char *), qsort_helper); 230 while (i < sz) { 231 j = 0; 232 slashpos = strchr(list[i], '/'); 233 curkey = (char *)malloc(slashpos - list[i] + 2); 234 names = (char **)malloc(sz * sizeof(char *)); 235 if ((curkey == NULL) || (names == NULL)) { 236 __iconv_free_list(list, sz); 237 return; 238 } 239 strlcpy(curkey, list[i], slashpos - list[i] + 1); 240 names[j++] = strdup(curkey); 241 for (; (i < sz) && (memcmp(curkey, list[i], strlen(curkey)) == 0); i++) { 242 slashpos = strchr(list[i], '/'); 243 curitem = (char *)malloc(strlen(slashpos) + 1); 244 if (curitem == NULL) { 245 __iconv_free_list(list, sz); 246 return; 247 } 248 strlcpy(curitem, &slashpos[1], strlen(slashpos) + 1); 249 if (strcmp(curkey, curitem) == 0) { 250 continue; 251 } 252 names[j++] = strdup(curitem); 253 } 254 np = (const char * const *)names; 255 do_one(j, np, data); 256 free(names); 257 } 258 259 __iconv_free_list(list, sz); 260} 261 262__inline const char 263*iconv_canonicalize(const char *name) 264{ 265 266 return (_citrus_iconv_canonicalize(name)); 267} 268 269int 270libiconvctl(iconv_t cd, int request, void *argument) 271{ 272 struct _citrus_iconv *cv; 273 struct iconv_hooks *hooks; 274 const char *convname; 275 char src[PATH_MAX], *dst; 276 int *i; 277 278 cv = (struct _citrus_iconv *)(void *)cd; 279 hooks = (struct iconv_hooks *)argument; 280 i = (int *)argument; 281 282 if (ISBADF(cd)) { 283 errno = EBADF; 284 return (-1); 285 } 286 287 switch (request) { 288 case ICONV_TRIVIALP: 289 convname = cv->cv_shared->ci_convname; 290 dst = strchr(convname, '/'); 291 292 strlcpy(src, convname, dst - convname + 1); 293 dst++; 294 if ((convname == NULL) || (src == NULL) || (dst == NULL)) 295 return (-1); 296 *i = strcmp(src, dst) == 0 ? 1 : 0; 297 return (0); 298 case ICONV_GET_TRANSLITERATE: 299 *i = 1; 300 return (0); 301 case ICONV_SET_TRANSLITERATE: 302 return ((*i == 1) ? 0 : -1); 303 case ICONV_GET_DISCARD_ILSEQ: 304 *i = cv->cv_shared->ci_discard_ilseq ? 1 : 0; 305 return (0); 306 case ICONV_SET_DISCARD_ILSEQ: 307 cv->cv_shared->ci_discard_ilseq = *i; 308 return (0); 309 case ICONV_SET_HOOKS: 310 cv->cv_shared->ci_hooks = hooks; 311 return (0); 312 case ICONV_SET_FALLBACKS: 313 errno = EOPNOTSUPP; 314 return (-1); 315 default: 316 errno = EINVAL; 317 return (-1); 318 } 319} 320 321void 322libiconv_set_relocation_prefix(const char *orig_prefix __unused, 323 const char *curr_prefix __unused) 324{ 325 326} 327