Index: stable/10/lib/libc/iconv/bsd_iconv.c =================================================================== --- stable/10/lib/libc/iconv/bsd_iconv.c (revision 267664) +++ stable/10/lib/libc/iconv/bsd_iconv.c (revision 267665) @@ -1,318 +1,319 @@ /* $FreeBSD$ */ /* $NetBSD: iconv.c,v 1.11 2009/03/03 16:22:33 explorer Exp $ */ /*- * Copyright (c) 2003 Citrus Project, * Copyright (c) 2009, 2010 Gabor Kovesdan , * 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. */ #include #include #include #include #include #include #include #include #include #include #include #include "citrus_types.h" #include "citrus_module.h" #include "citrus_esdb.h" #include "citrus_hash.h" #include "citrus_iconv.h" #include "iconv-internal.h" #define ISBADF(_h_) (!(_h_) || (_h_) == (iconv_t)-1) static iconv_t __bsd___iconv_open(const char *out, const char *in, struct _citrus_iconv *handle) { const char *out_slashes; char *out_noslashes; int ret; /* * Remove anything following a //, as these are options (like * //ignore, //translate, etc) and we just don't handle them. * This is for compatibility with software that uses these * blindly. */ out_slashes = strstr(out, "//"); if (out_slashes != NULL) { out_noslashes = strndup(out, out_slashes - out); if (out_noslashes == NULL) { errno = ENOMEM; return ((iconv_t)-1); } ret = _citrus_iconv_open(&handle, in, out_noslashes); free(out_noslashes); } else { ret = _citrus_iconv_open(&handle, in, out); } if (ret) { errno = ret == ENOENT ? EINVAL : ret; return ((iconv_t)-1); } handle->cv_shared->ci_discard_ilseq = strcasestr(out, "//IGNORE"); + handle->cv_shared->ci_ilseq_invalid = false; handle->cv_shared->ci_hooks = NULL; return ((iconv_t)(void *)handle); } iconv_t __bsd_iconv_open(const char *out, const char *in) { return (__bsd___iconv_open(out, in, NULL)); } int __bsd_iconv_open_into(const char *out, const char *in, iconv_allocation_t *ptr) { struct _citrus_iconv *handle; handle = (struct _citrus_iconv *)ptr; return ((__bsd___iconv_open(out, in, handle) == (iconv_t)-1) ? -1 : 0); } int __bsd_iconv_close(iconv_t handle) { if (ISBADF(handle)) { errno = EBADF; return (-1); } _citrus_iconv_close((struct _citrus_iconv *)(void *)handle); return (0); } size_t __bsd_iconv(iconv_t handle, const char **in, size_t *szin, char **out, size_t *szout) { size_t ret; int err; if (ISBADF(handle)) { errno = EBADF; return ((size_t)-1); } err = _citrus_iconv_convert((struct _citrus_iconv *)(void *)handle, in, szin, out, szout, 0, &ret); if (err) { errno = err; ret = (size_t)-1; } return (ret); } size_t __bsd___iconv(iconv_t handle, const char **in, size_t *szin, char **out, size_t *szout, uint32_t flags, size_t *invalids) { size_t ret; int err; if (ISBADF(handle)) { errno = EBADF; return ((size_t)-1); } err = _citrus_iconv_convert((struct _citrus_iconv *)(void *)handle, in, szin, out, szout, flags, &ret); if (invalids) *invalids = ret; if (err) { errno = err; ret = (size_t)-1; } return (ret); } int __bsd___iconv_get_list(char ***rlist, size_t *rsz, bool sorted) { int ret; ret = _citrus_esdb_get_list(rlist, rsz, sorted); if (ret) { errno = ret; return (-1); } return (0); } void __bsd___iconv_free_list(char **list, size_t sz) { _citrus_esdb_free_list(list, sz); } /* * GNU-compatibile non-standard interfaces. */ static int qsort_helper(const void *first, const void *second) { const char * const *s1; const char * const *s2; s1 = first; s2 = second; return (strcmp(*s1, *s2)); } void __bsd_iconvlist(int (*do_one) (unsigned int, const char * const *, void *), void *data) { char **list, **names; const char * const *np; char *curitem, *curkey, *slashpos; size_t sz; unsigned int i, j; i = 0; if (__bsd___iconv_get_list(&list, &sz, true)) list = NULL; qsort((void *)list, sz, sizeof(char *), qsort_helper); while (i < sz) { j = 0; slashpos = strchr(list[i], '/'); curkey = (char *)malloc(slashpos - list[i] + 2); names = (char **)malloc(sz * sizeof(char *)); if ((curkey == NULL) || (names == NULL)) { __bsd___iconv_free_list(list, sz); return; } strlcpy(curkey, list[i], slashpos - list[i] + 1); - names[j++] = strdup(curkey); + names[j++] = curkey; for (; (i < sz) && (memcmp(curkey, list[i], strlen(curkey)) == 0); i++) { slashpos = strchr(list[i], '/'); curitem = (char *)malloc(strlen(slashpos) + 1); if (curitem == NULL) { __bsd___iconv_free_list(list, sz); return; } strlcpy(curitem, &slashpos[1], strlen(slashpos) + 1); if (strcmp(curkey, curitem) == 0) { continue; } - names[j++] = strdup(curitem); + names[j++] = curitem; } np = (const char * const *)names; do_one(j, np, data); free(names); } __bsd___iconv_free_list(list, sz); } __inline const char * __bsd_iconv_canonicalize(const char *name) { return (_citrus_iconv_canonicalize(name)); } int __bsd_iconvctl(iconv_t cd, int request, void *argument) { struct _citrus_iconv *cv; struct iconv_hooks *hooks; const char *convname; char src[PATH_MAX], *dst; int *i; cv = (struct _citrus_iconv *)(void *)cd; hooks = (struct iconv_hooks *)argument; i = (int *)argument; if (ISBADF(cd)) { errno = EBADF; return (-1); } switch (request) { case ICONV_TRIVIALP: convname = cv->cv_shared->ci_convname; dst = strchr(convname, '/'); strlcpy(src, convname, dst - convname + 1); dst++; if ((convname == NULL) || (src == NULL) || (dst == NULL)) return (-1); *i = strcmp(src, dst) == 0 ? 1 : 0; return (0); case ICONV_GET_TRANSLITERATE: *i = 1; return (0); case ICONV_SET_TRANSLITERATE: return ((*i == 1) ? 0 : -1); case ICONV_GET_DISCARD_ILSEQ: *i = cv->cv_shared->ci_discard_ilseq ? 1 : 0; return (0); case ICONV_SET_DISCARD_ILSEQ: cv->cv_shared->ci_discard_ilseq = *i; return (0); case ICONV_SET_HOOKS: cv->cv_shared->ci_hooks = hooks; return (0); case ICONV_SET_FALLBACKS: errno = EOPNOTSUPP; return (-1); case ICONV_GET_ILSEQ_INVALID: *i = cv->cv_shared->ci_ilseq_invalid ? 1 : 0; return (0); case ICONV_SET_ILSEQ_INVALID: cv->cv_shared->ci_ilseq_invalid = *i; return (0); default: errno = EINVAL; return (-1); } } void __bsd_iconv_set_relocation_prefix(const char *orig_prefix __unused, const char *curr_prefix __unused) { } Index: stable/10/lib/libc/iconv/citrus_db_factory.c =================================================================== --- stable/10/lib/libc/iconv/citrus_db_factory.c (revision 267664) +++ stable/10/lib/libc/iconv/citrus_db_factory.c (revision 267665) @@ -1,339 +1,337 @@ /* $FreeBSD$ */ /* $NetBSD: citrus_db_factory.c,v 1.10 2013/09/14 13:05:51 joerg Exp $ */ /*- * Copyright (c)2003 Citrus Project, * 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. */ #include #include #include #include #include #include #include #include #include #include "citrus_namespace.h" #include "citrus_region.h" #include "citrus_db_file.h" #include "citrus_db_factory.h" struct _citrus_db_factory_entry { STAILQ_ENTRY(_citrus_db_factory_entry) de_entry; struct _citrus_db_factory_entry *de_next; uint32_t de_hashvalue; struct _region de_key; int de_key_free; struct _region de_data; int de_data_free; int de_idx; }; struct _citrus_db_factory { size_t df_num_entries; STAILQ_HEAD(, _citrus_db_factory_entry) df_entries; size_t df_total_key_size; size_t df_total_data_size; uint32_t (*df_hashfunc)(struct _citrus_region *); void *df_hashfunc_closure; }; #define DB_ALIGN 16 int _citrus_db_factory_create(struct _citrus_db_factory **rdf, _citrus_db_hash_func_t hashfunc, void *hashfunc_closure) { struct _citrus_db_factory *df; df = malloc(sizeof(*df)); if (df == NULL) return (errno); df->df_num_entries = 0; df->df_total_key_size = df->df_total_data_size = 0; STAILQ_INIT(&df->df_entries); df->df_hashfunc = hashfunc; df->df_hashfunc_closure = hashfunc_closure; *rdf = df; return (0); } void _citrus_db_factory_free(struct _citrus_db_factory *df) { struct _citrus_db_factory_entry *de; while ((de = STAILQ_FIRST(&df->df_entries)) != NULL) { STAILQ_REMOVE_HEAD(&df->df_entries, de_entry); if (de->de_key_free) free(_region_head(&de->de_key)); if (de->de_data_free) free(_region_head(&de->de_data)); free(de); } free(df); } static __inline size_t ceilto(size_t sz) { return ((sz + DB_ALIGN - 1) & ~(DB_ALIGN - 1)); } int _citrus_db_factory_add(struct _citrus_db_factory *df, struct _region *key, int keyfree, struct _region *data, int datafree) { struct _citrus_db_factory_entry *de; de = malloc(sizeof(*de)); if (de == NULL) return (-1); de->de_hashvalue = df->df_hashfunc(key); de->de_key = *key; de->de_key_free = keyfree; de->de_data = *data; de->de_data_free = datafree; de->de_idx = -1; STAILQ_INSERT_TAIL(&df->df_entries, de, de_entry); df->df_total_key_size += _region_size(key); df->df_total_data_size += ceilto(_region_size(data)); df->df_num_entries++; return (0); } int _citrus_db_factory_add_by_string(struct _citrus_db_factory *df, const char *key, struct _citrus_region *data, int datafree) { struct _region r; char *tmp; tmp = strdup(key); if (tmp == NULL) return (errno); _region_init(&r, tmp, strlen(key)); return _citrus_db_factory_add(df, &r, 1, data, datafree); } int _citrus_db_factory_add8_by_string(struct _citrus_db_factory *df, const char *key, uint8_t val) { struct _region r; uint8_t *p; p = malloc(sizeof(*p)); if (p == NULL) return (errno); *p = val; _region_init(&r, p, 1); return (_citrus_db_factory_add_by_string(df, key, &r, 1)); } int _citrus_db_factory_add16_by_string(struct _citrus_db_factory *df, const char *key, uint16_t val) { struct _region r; uint16_t *p; p = malloc(sizeof(*p)); if (p == NULL) return (errno); *p = htons(val); _region_init(&r, p, 2); return (_citrus_db_factory_add_by_string(df, key, &r, 1)); } int _citrus_db_factory_add32_by_string(struct _citrus_db_factory *df, const char *key, uint32_t val) { struct _region r; uint32_t *p; p = malloc(sizeof(*p)); if (p == NULL) return (errno); *p = htonl(val); _region_init(&r, p, 4); return (_citrus_db_factory_add_by_string(df, key, &r, 1)); } int _citrus_db_factory_add_string_by_string(struct _citrus_db_factory *df, const char *key, const char *data) { char *p; struct _region r; p = strdup(data); if (p == NULL) return (errno); _region_init(&r, p, strlen(p) + 1); return (_citrus_db_factory_add_by_string(df, key, &r, 1)); } size_t _citrus_db_factory_calc_size(struct _citrus_db_factory *df) { size_t sz; sz = ceilto(_CITRUS_DB_HEADER_SIZE); sz += ceilto(_CITRUS_DB_ENTRY_SIZE * df->df_num_entries); sz += ceilto(df->df_total_key_size); sz += df->df_total_data_size; return (sz); } static __inline void put8(struct _region *r, size_t *rofs, uint8_t val) { *(uint8_t *)_region_offset(r, *rofs) = val; *rofs += 1; } static __inline void put32(struct _region *r, size_t *rofs, uint32_t val) { val = htonl(val); memcpy(_region_offset(r, *rofs), &val, 4); *rofs += 4; } static __inline void putpad(struct _region *r, size_t *rofs) { size_t i; for (i = ceilto(*rofs) - *rofs; i > 0; i--) put8(r, rofs, 0); } static __inline void dump_header(struct _region *r, const char *magic, size_t *rofs, size_t num_entries) { while (*rofs<_CITRUS_DB_MAGIC_SIZE) put8(r, rofs, *magic++); put32(r, rofs, num_entries); put32(r, rofs, _CITRUS_DB_HEADER_SIZE); } int _citrus_db_factory_serialize(struct _citrus_db_factory *df, const char *magic, struct _region *r) { struct _citrus_db_factory_entry *de, **depp, *det; size_t dataofs, i, keyofs, nextofs, ofs; ofs = 0; /* check whether more than 0 entries exist */ if (df->df_num_entries == 0) { dump_header(r, magic, &ofs, 0); return (0); } /* allocate hash table */ - depp = malloc(sizeof(*depp) * df->df_num_entries); + depp = calloc(df->df_num_entries, sizeof(*depp)); if (depp == NULL) return (-1); - for (i = 0; i < df->df_num_entries; i++) - depp[i] = NULL; /* step1: store the entries which are not conflicting */ STAILQ_FOREACH(de, &df->df_entries, de_entry) { de->de_hashvalue %= df->df_num_entries; de->de_idx = -1; de->de_next = NULL; if (depp[de->de_hashvalue] == NULL) { depp[de->de_hashvalue] = de; de->de_idx = (int)de->de_hashvalue; } } /* step2: resolve conflicts */ i = 0; STAILQ_FOREACH(de, &df->df_entries, de_entry) { if (de->de_idx == -1) { det = depp[de->de_hashvalue]; while (det->de_next != NULL) det = det->de_next; det->de_next = de; while (depp[i] != NULL) i++; depp[i] = de; de->de_idx = (int)i; } } keyofs = _CITRUS_DB_HEADER_SIZE + ceilto(df->df_num_entries*_CITRUS_DB_ENTRY_SIZE); dataofs = keyofs + ceilto(df->df_total_key_size); /* dump header */ dump_header(r, magic, &ofs, df->df_num_entries); /* dump entries */ for (i = 0; i < df->df_num_entries; i++) { de = depp[i]; nextofs = 0; if (de->de_next) { nextofs = _CITRUS_DB_HEADER_SIZE + de->de_next->de_idx * _CITRUS_DB_ENTRY_SIZE; } put32(r, &ofs, de->de_hashvalue); put32(r, &ofs, nextofs); put32(r, &ofs, keyofs); put32(r, &ofs, _region_size(&de->de_key)); put32(r, &ofs, dataofs); put32(r, &ofs, _region_size(&de->de_data)); memcpy(_region_offset(r, keyofs), _region_head(&de->de_key), _region_size(&de->de_key)); keyofs += _region_size(&de->de_key); memcpy(_region_offset(r, dataofs), _region_head(&de->de_data), _region_size(&de->de_data)); dataofs += _region_size(&de->de_data); putpad(r, &dataofs); } putpad(r, &ofs); putpad(r, &keyofs); free(depp); return (0); } Index: stable/10/lib/libc/iconv/citrus_iconv.c =================================================================== --- stable/10/lib/libc/iconv/citrus_iconv.c (revision 267664) +++ stable/10/lib/libc/iconv/citrus_iconv.c (revision 267665) @@ -1,352 +1,351 @@ /* $FreeBSD$ */ /* $NetBSD: citrus_iconv.c,v 1.10 2011/11/19 18:34:21 tnozaki Exp $ */ /*- * Copyright (c)2003 Citrus Project, * 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. */ #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include "citrus_namespace.h" #include "citrus_bcs.h" #include "citrus_esdb.h" #include "citrus_region.h" #include "citrus_memstream.h" #include "citrus_mmap.h" #include "citrus_module.h" #include "citrus_lock.h" #include "citrus_lookup.h" #include "citrus_hash.h" #include "citrus_iconv.h" #define _CITRUS_ICONV_DIR "iconv.dir" #define _CITRUS_ICONV_ALIAS "iconv.alias" #define CI_HASH_SIZE 101 #define CI_INITIAL_MAX_REUSE 5 #define CI_ENV_MAX_REUSE "ICONV_MAX_REUSE" static bool isinit = false; static int shared_max_reuse, shared_num_unused; static _CITRUS_HASH_HEAD(, _citrus_iconv_shared, CI_HASH_SIZE) shared_pool; static TAILQ_HEAD(, _citrus_iconv_shared) shared_unused; static pthread_rwlock_t ci_lock = PTHREAD_RWLOCK_INITIALIZER; static __inline void init_cache(void) { WLOCK(&ci_lock); if (!isinit) { _CITRUS_HASH_INIT(&shared_pool, CI_HASH_SIZE); TAILQ_INIT(&shared_unused); shared_max_reuse = -1; if (!issetugid() && getenv(CI_ENV_MAX_REUSE)) shared_max_reuse = atoi(getenv(CI_ENV_MAX_REUSE)); if (shared_max_reuse < 0) shared_max_reuse = CI_INITIAL_MAX_REUSE; isinit = true; } UNLOCK(&ci_lock); } static __inline void close_shared(struct _citrus_iconv_shared *ci) { if (ci) { if (ci->ci_module) { if (ci->ci_ops) { if (ci->ci_closure) (*ci->ci_ops->io_uninit_shared)(ci); free(ci->ci_ops); } _citrus_unload_module(ci->ci_module); } free(ci); } } static __inline int open_shared(struct _citrus_iconv_shared * __restrict * __restrict rci, const char * __restrict convname, const char * __restrict src, const char * __restrict dst) { struct _citrus_iconv_shared *ci; _citrus_iconv_getops_t getops; const char *module; size_t len_convname; int ret; #ifdef INCOMPATIBLE_WITH_GNU_ICONV /* * Sadly, the gnu tools expect iconv to actually parse the * byte stream and don't allow for a pass-through when * the (src,dest) encodings are the same. * See gettext-0.18.3+ NEWS: * msgfmt now checks PO file headers more strictly with less * false-positives. * NetBSD don't do this either. */ module = (strcmp(src, dst) != 0) ? "iconv_std" : "iconv_none"; #else module = "iconv_std"; #endif /* initialize iconv handle */ len_convname = strlen(convname); ci = malloc(sizeof(*ci) + len_convname + 1); if (!ci) { ret = errno; goto err; } ci->ci_module = NULL; ci->ci_ops = NULL; ci->ci_closure = NULL; ci->ci_convname = (void *)&ci[1]; memcpy(ci->ci_convname, convname, len_convname + 1); /* load module */ ret = _citrus_load_module(&ci->ci_module, module); if (ret) goto err; /* get operators */ getops = (_citrus_iconv_getops_t)_citrus_find_getops(ci->ci_module, module, "iconv"); if (!getops) { ret = EOPNOTSUPP; goto err; } ci->ci_ops = malloc(sizeof(*ci->ci_ops)); if (!ci->ci_ops) { ret = errno; goto err; } ret = (*getops)(ci->ci_ops); if (ret) goto err; if (ci->ci_ops->io_init_shared == NULL || ci->ci_ops->io_uninit_shared == NULL || ci->ci_ops->io_init_context == NULL || ci->ci_ops->io_uninit_context == NULL || ci->ci_ops->io_convert == NULL) { ret = EINVAL; goto err; } /* initialize the converter */ ret = (*ci->ci_ops->io_init_shared)(ci, src, dst); if (ret) goto err; *rci = ci; return (0); err: close_shared(ci); return (ret); } static __inline int hash_func(const char *key) { return (_string_hash_func(key, CI_HASH_SIZE)); } static __inline int match_func(struct _citrus_iconv_shared * __restrict ci, const char * __restrict key) { return (strcmp(ci->ci_convname, key)); } static int get_shared(struct _citrus_iconv_shared * __restrict * __restrict rci, const char *src, const char *dst) { struct _citrus_iconv_shared * ci; char convname[PATH_MAX]; int hashval, ret = 0; snprintf(convname, sizeof(convname), "%s/%s", src, dst); WLOCK(&ci_lock); /* lookup alread existing entry */ hashval = hash_func(convname); _CITRUS_HASH_SEARCH(&shared_pool, ci, ci_hash_entry, match_func, convname, hashval); if (ci != NULL) { /* found */ if (ci->ci_used_count == 0) { TAILQ_REMOVE(&shared_unused, ci, ci_tailq_entry); shared_num_unused--; } ci->ci_used_count++; *rci = ci; goto quit; } /* create new entry */ ret = open_shared(&ci, convname, src, dst); if (ret) goto quit; _CITRUS_HASH_INSERT(&shared_pool, ci, ci_hash_entry, hashval); ci->ci_used_count = 1; *rci = ci; quit: UNLOCK(&ci_lock); return (ret); } static void release_shared(struct _citrus_iconv_shared * __restrict ci) { WLOCK(&ci_lock); ci->ci_used_count--; if (ci->ci_used_count == 0) { /* put it into unused list */ shared_num_unused++; TAILQ_INSERT_TAIL(&shared_unused, ci, ci_tailq_entry); /* flood out */ while (shared_num_unused > shared_max_reuse) { ci = TAILQ_FIRST(&shared_unused); TAILQ_REMOVE(&shared_unused, ci, ci_tailq_entry); _CITRUS_HASH_REMOVE(ci, ci_hash_entry); shared_num_unused--; close_shared(ci); } } UNLOCK(&ci_lock); } /* * _citrus_iconv_open: * open a converter for the specified in/out codes. */ int _citrus_iconv_open(struct _citrus_iconv * __restrict * __restrict rcv, const char * __restrict src, const char * __restrict dst) { struct _citrus_iconv *cv = NULL; struct _citrus_iconv_shared *ci = NULL; char realdst[PATH_MAX], realsrc[PATH_MAX]; char buf[PATH_MAX], path[PATH_MAX]; int ret; init_cache(); /* GNU behaviour, using locale encoding if "" or "char" is specified */ if ((strcmp(src, "") == 0) || (strcmp(src, "char") == 0)) src = nl_langinfo(CODESET); if ((strcmp(dst, "") == 0) || (strcmp(dst, "char") == 0)) dst = nl_langinfo(CODESET); /* resolve codeset name aliases */ strlcpy(realsrc, _lookup_alias(path, src, buf, (size_t)PATH_MAX, _LOOKUP_CASE_IGNORE), (size_t)PATH_MAX); strlcpy(realdst, _lookup_alias(path, dst, buf, (size_t)PATH_MAX, _LOOKUP_CASE_IGNORE), (size_t)PATH_MAX); /* sanity check */ if (strchr(realsrc, '/') != NULL || strchr(realdst, '/')) return (EINVAL); /* get shared record */ ret = get_shared(&ci, realsrc, realdst); if (ret) return (ret); /* create/init context */ if (*rcv == NULL) { cv = malloc(sizeof(*cv)); if (cv == NULL) { ret = errno; release_shared(ci); return (ret); } *rcv = cv; } (*rcv)->cv_shared = ci; ret = (*ci->ci_ops->io_init_context)(*rcv); if (ret) { release_shared(ci); free(cv); return (ret); } return (0); } /* * _citrus_iconv_close: * close the specified converter. */ void _citrus_iconv_close(struct _citrus_iconv *cv) { if (cv) { (*cv->cv_shared->ci_ops->io_uninit_context)(cv); release_shared(cv->cv_shared); free(cv); } } const char *_citrus_iconv_canonicalize(const char *name) { char *buf; - if ((buf = malloc((size_t)PATH_MAX)) == NULL) + if ((buf = calloc((size_t)PATH_MAX, sizeof(*buf))) == NULL) return (NULL); - memset((void *)buf, 0, (size_t)PATH_MAX); _citrus_esdb_alias(name, buf, (size_t)PATH_MAX); return (buf); } Index: stable/10/lib/libiconv_modules/HZ/citrus_hz.c =================================================================== --- stable/10/lib/libiconv_modules/HZ/citrus_hz.c (revision 267664) +++ stable/10/lib/libiconv_modules/HZ/citrus_hz.c (revision 267665) @@ -1,650 +1,648 @@ /* $FreeBSD$ */ /* $NetBSD: citrus_hz.c,v 1.2 2008/06/14 16:01:07 tnozaki Exp $ */ /*- * Copyright (c)2004, 2006 Citrus Project, * 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. * */ #include #include #include #include #include #include #include #include #include #include #include #include "citrus_namespace.h" #include "citrus_types.h" #include "citrus_bcs.h" #include "citrus_module.h" #include "citrus_stdenc.h" #include "citrus_hz.h" #include "citrus_prop.h" /* * wchar_t mapping: * * CTRL/ASCII 00000000 00000000 00000000 gxxxxxxx * GB2312 00000000 00000000 0xxxxxxx gxxxxxxx * 94/96*n (~M) 0mmmmmmm 0xxxxxxx 0xxxxxxx gxxxxxxx */ #define ESCAPE_CHAR '~' typedef enum { CTRL = 0, ASCII = 1, GB2312 = 2, CS94 = 3, CS96 = 4 } charset_t; typedef struct { int start; int end; int width; } range_t; static const range_t ranges[] = { #define RANGE(start, end) { start, end, (end - start) + 1 } /* CTRL */ RANGE(0x00, 0x1F), /* ASCII */ RANGE(0x20, 0x7F), /* GB2312 */ RANGE(0x21, 0x7E), /* CS94 */ RANGE(0x21, 0x7E), /* CS96 */ RANGE(0x20, 0x7F), #undef RANGE }; typedef struct escape_t escape_t; typedef struct { charset_t charset; escape_t *escape; ssize_t length; #define ROWCOL_MAX 3 } graphic_t; typedef TAILQ_HEAD(escape_list, escape_t) escape_list; struct escape_t { TAILQ_ENTRY(escape_t) entry; escape_list *set; graphic_t *left; graphic_t *right; int ch; }; #define GL(escape) ((escape)->left) #define GR(escape) ((escape)->right) #define SET(escape) ((escape)->set) #define ESC(escape) ((escape)->ch) #define INIT(escape) (TAILQ_FIRST(SET(escape))) static __inline escape_t * find_escape(escape_list *set, int ch) { escape_t *escape; TAILQ_FOREACH(escape, set, entry) { if (ESC(escape) == ch) break; } return (escape); } typedef struct { escape_list e0; escape_list e1; graphic_t *ascii; graphic_t *gb2312; } _HZEncodingInfo; #define E0SET(ei) (&(ei)->e0) #define E1SET(ei) (&(ei)->e1) #define INIT0(ei) (TAILQ_FIRST(E0SET(ei))) #define INIT1(ei) (TAILQ_FIRST(E1SET(ei))) typedef struct { escape_t *inuse; int chlen; char ch[ROWCOL_MAX]; } _HZState; #define _CEI_TO_EI(_cei_) (&(_cei_)->ei) #define _CEI_TO_STATE(_cei_, _func_) (_cei_)->states.s_##_func_ #define _FUNCNAME(m) _citrus_HZ_##m #define _ENCODING_INFO _HZEncodingInfo #define _ENCODING_STATE _HZState #define _ENCODING_MB_CUR_MAX(_ei_) MB_LEN_MAX #define _ENCODING_IS_STATE_DEPENDENT 1 #define _STATE_NEEDS_EXPLICIT_INIT(_ps_) ((_ps_)->inuse == NULL) static __inline void _citrus_HZ_init_state(_HZEncodingInfo * __restrict ei, _HZState * __restrict psenc) { psenc->chlen = 0; psenc->inuse = INIT0(ei); } #if 0 static __inline void /*ARGSUSED*/ _citrus_HZ_pack_state(_HZEncodingInfo * __restrict ei __unused, void *__restrict pspriv, const _HZState * __restrict psenc) { memcpy(pspriv, (const void *)psenc, sizeof(*psenc)); } static __inline void /*ARGSUSED*/ _citrus_HZ_unpack_state(_HZEncodingInfo * __restrict ei __unused, _HZState * __restrict psenc, const void * __restrict pspriv) { memcpy((void *)psenc, pspriv, sizeof(*psenc)); } #endif static int _citrus_HZ_mbrtowc_priv(_HZEncodingInfo * __restrict ei, wchar_t * __restrict pwc, const char ** __restrict s, size_t n, _HZState * __restrict psenc, size_t * __restrict nresult) { escape_t *candidate, *init; graphic_t *graphic; const range_t *range; const char *s0; wchar_t wc; int bit, ch, head, len, tail; if (*s == NULL) { _citrus_HZ_init_state(ei, psenc); *nresult = 1; return (0); } s0 = *s; if (psenc->chlen < 0 || psenc->inuse == NULL) return (EINVAL); wc = (wchar_t)0; bit = head = tail = 0; graphic = NULL; for (len = 0; len <= MB_LEN_MAX;) { if (psenc->chlen == tail) { if (n-- < 1) { *s = s0; *nresult = (size_t)-2; return (0); } psenc->ch[psenc->chlen++] = *s0++; ++len; } ch = (unsigned char)psenc->ch[tail++]; if (tail == 1) { if ((ch & ~0x80) <= 0x1F) { if (psenc->inuse != INIT0(ei)) break; wc = (wchar_t)ch; goto done; } if (ch & 0x80) { graphic = GR(psenc->inuse); bit = 0x80; ch &= ~0x80; } else { graphic = GL(psenc->inuse); if (ch == ESCAPE_CHAR) continue; bit = 0x0; } if (graphic == NULL) break; } else if (tail == 2 && psenc->ch[0] == ESCAPE_CHAR) { if (tail < psenc->chlen) return (EINVAL); if (ch == ESCAPE_CHAR) { ++head; } else if (ch == '\n') { if (psenc->inuse != INIT0(ei)) break; tail = psenc->chlen = 0; continue; } else { candidate = NULL; init = INIT0(ei); if (psenc->inuse == init) { init = INIT1(ei); } else if (INIT(psenc->inuse) == init) { if (ESC(init) != ch) break; candidate = init; } if (candidate == NULL) { candidate = find_escape( SET(psenc->inuse), ch); if (candidate == NULL) { if (init == NULL || ESC(init) != ch) break; candidate = init; } } psenc->inuse = candidate; tail = psenc->chlen = 0; continue; } } else if (ch & 0x80) { if (graphic != GR(psenc->inuse)) break; ch &= ~0x80; } else { if (graphic != GL(psenc->inuse)) break; } range = &ranges[(size_t)graphic->charset]; if (range->start > ch || range->end < ch) break; wc <<= 8; wc |= ch; if (graphic->length == (tail - head)) { if (graphic->charset > GB2312) bit |= ESC(psenc->inuse) << 24; wc |= bit; goto done; } } *nresult = (size_t)-1; return (EILSEQ); done: if (tail < psenc->chlen) return (EINVAL); *s = s0; if (pwc != NULL) *pwc = wc; psenc->chlen = 0; *nresult = (wc == 0) ? 0 : len; return (0); } static int _citrus_HZ_wcrtomb_priv(_HZEncodingInfo * __restrict ei, char * __restrict s, size_t n, wchar_t wc, _HZState * __restrict psenc, size_t * __restrict nresult) { escape_t *candidate, *init; graphic_t *graphic; const range_t *range; size_t len; int bit, ch; if (psenc->chlen != 0 || psenc->inuse == NULL) return (EINVAL); if (wc & 0x80) { bit = 0x80; wc &= ~0x80; } else { bit = 0x0; } if ((uint32_t)wc <= 0x1F) { candidate = INIT0(ei); graphic = (bit == 0) ? candidate->left : candidate->right; if (graphic == NULL) goto ilseq; range = &ranges[(size_t)CTRL]; len = 1; } else if ((uint32_t)wc <= 0x7F) { graphic = ei->ascii; if (graphic == NULL) goto ilseq; candidate = graphic->escape; range = &ranges[(size_t)graphic->charset]; len = graphic->length; } else if ((uint32_t)wc <= 0x7F7F) { graphic = ei->gb2312; if (graphic == NULL) goto ilseq; candidate = graphic->escape; range = &ranges[(size_t)graphic->charset]; len = graphic->length; } else { ch = (wc >> 24) & 0xFF; candidate = find_escape(E0SET(ei), ch); if (candidate == NULL) { candidate = find_escape(E1SET(ei), ch); if (candidate == NULL) goto ilseq; } wc &= ~0xFF000000; graphic = (bit == 0) ? candidate->left : candidate->right; if (graphic == NULL) goto ilseq; range = &ranges[(size_t)graphic->charset]; len = graphic->length; } if (psenc->inuse != candidate) { init = INIT0(ei); if (SET(psenc->inuse) == SET(candidate)) { if (INIT(psenc->inuse) != init || psenc->inuse == init || candidate == init) init = NULL; } else if (candidate == (init = INIT(candidate))) { init = NULL; } if (init != NULL) { if (n < 2) return (E2BIG); n -= 2; psenc->ch[psenc->chlen++] = ESCAPE_CHAR; psenc->ch[psenc->chlen++] = ESC(init); } if (n < 2) return (E2BIG); n -= 2; psenc->ch[psenc->chlen++] = ESCAPE_CHAR; psenc->ch[psenc->chlen++] = ESC(candidate); psenc->inuse = candidate; } if (n < len) return (E2BIG); while (len-- > 0) { ch = (wc >> (len * 8)) & 0xFF; if (range->start > ch || range->end < ch) goto ilseq; psenc->ch[psenc->chlen++] = ch | bit; } memcpy(s, psenc->ch, psenc->chlen); *nresult = psenc->chlen; psenc->chlen = 0; return (0); ilseq: *nresult = (size_t)-1; return (EILSEQ); } static __inline int _citrus_HZ_put_state_reset(_HZEncodingInfo * __restrict ei, char * __restrict s, size_t n, _HZState * __restrict psenc, size_t * __restrict nresult) { escape_t *candidate; if (psenc->chlen != 0 || psenc->inuse == NULL) return (EINVAL); candidate = INIT0(ei); if (psenc->inuse != candidate) { if (n < 2) return (E2BIG); n -= 2; psenc->ch[psenc->chlen++] = ESCAPE_CHAR; psenc->ch[psenc->chlen++] = ESC(candidate); } if (n < 1) return (E2BIG); if (psenc->chlen > 0) memcpy(s, psenc->ch, psenc->chlen); *nresult = psenc->chlen; _citrus_HZ_init_state(ei, psenc); return (0); } static __inline int _citrus_HZ_stdenc_get_state_desc_generic(_HZEncodingInfo * __restrict ei, _HZState * __restrict psenc, int * __restrict rstate) { if (psenc->chlen < 0 || psenc->inuse == NULL) return (EINVAL); *rstate = (psenc->chlen == 0) ? ((psenc->inuse == INIT0(ei)) ? _STDENC_SDGEN_INITIAL : _STDENC_SDGEN_STABLE) : ((psenc->ch[0] == ESCAPE_CHAR) ? _STDENC_SDGEN_INCOMPLETE_SHIFT : _STDENC_SDGEN_INCOMPLETE_CHAR); return (0); } static __inline int /*ARGSUSED*/ _citrus_HZ_stdenc_wctocs(_HZEncodingInfo * __restrict ei __unused, _csid_t * __restrict csid, _index_t * __restrict idx, wchar_t wc) { int bit; if (wc & 0x80) { bit = 0x80; wc &= ~0x80; } else bit = 0x0; if ((uint32_t)wc <= 0x7F) { *csid = (_csid_t)bit; *idx = (_index_t)wc; } else if ((uint32_t)wc <= 0x7F7F) { *csid = (_csid_t)(bit | 0x8000); *idx = (_index_t)wc; } else { *csid = (_index_t)(wc & ~0x00FFFF7F); *idx = (_csid_t)(wc & 0x00FFFF7F); } return (0); } static __inline int /*ARGSUSED*/ _citrus_HZ_stdenc_cstowc(_HZEncodingInfo * __restrict ei __unused, wchar_t * __restrict wc, _csid_t csid, _index_t idx) { *wc = (wchar_t)idx; switch (csid) { case 0x80: case 0x8080: *wc |= (wchar_t)0x80; /*FALLTHROUGH*/ case 0x0: case 0x8000: break; default: *wc |= (wchar_t)csid; } return (0); } static void _citrus_HZ_encoding_module_uninit(_HZEncodingInfo *ei) { escape_t *escape; while ((escape = TAILQ_FIRST(E0SET(ei))) != NULL) { TAILQ_REMOVE(E0SET(ei), escape, entry); free(GL(escape)); free(GR(escape)); free(escape); } while ((escape = TAILQ_FIRST(E1SET(ei))) != NULL) { TAILQ_REMOVE(E1SET(ei), escape, entry); free(GL(escape)); free(GR(escape)); free(escape); } } static int _citrus_HZ_parse_char(void *context, const char *name __unused, const char *s) { escape_t *escape; void **p; p = (void **)context; escape = (escape_t *)p[0]; if (escape->ch != '\0') return (EINVAL); escape->ch = *s++; if (escape->ch == ESCAPE_CHAR || *s != '\0') return (EINVAL); return (0); } static int _citrus_HZ_parse_graphic(void *context, const char *name, const char *s) { _HZEncodingInfo *ei; escape_t *escape; graphic_t *graphic; void **p; p = (void **)context; escape = (escape_t *)p[0]; ei = (_HZEncodingInfo *)p[1]; - graphic = malloc(sizeof(*graphic)); + graphic = calloc(1, sizeof(*graphic)); if (graphic == NULL) return (ENOMEM); - memset(graphic, 0, sizeof(*graphic)); if (strcmp("GL", name) == 0) { if (GL(escape) != NULL) goto release; GL(escape) = graphic; } else if (strcmp("GR", name) == 0) { if (GR(escape) != NULL) goto release; GR(escape) = graphic; } else { release: free(graphic); return (EINVAL); } graphic->escape = escape; if (_bcs_strncasecmp("ASCII", s, 5) == 0) { if (s[5] != '\0') return (EINVAL); graphic->charset = ASCII; graphic->length = 1; ei->ascii = graphic; return (0); } else if (_bcs_strncasecmp("GB2312", s, 6) == 0) { if (s[6] != '\0') return (EINVAL); graphic->charset = GB2312; graphic->length = 2; ei->gb2312 = graphic; return (0); } else if (strncmp("94*", s, 3) == 0) graphic->charset = CS94; else if (strncmp("96*", s, 3) == 0) graphic->charset = CS96; else return (EINVAL); s += 3; switch(*s) { case '1': case '2': case '3': graphic->length = (size_t)(*s - '0'); if (*++s == '\0') break; /*FALLTHROUGH*/ default: return (EINVAL); } return (0); } static const _citrus_prop_hint_t escape_hints[] = { _CITRUS_PROP_HINT_STR("CH", &_citrus_HZ_parse_char), _CITRUS_PROP_HINT_STR("GL", &_citrus_HZ_parse_graphic), _CITRUS_PROP_HINT_STR("GR", &_citrus_HZ_parse_graphic), _CITRUS_PROP_HINT_END }; static int _citrus_HZ_parse_escape(void *context, const char *name, const char *s) { _HZEncodingInfo *ei; escape_t *escape; void *p[2]; ei = (_HZEncodingInfo *)context; - escape = malloc(sizeof(*escape)); + escape = calloc(1, sizeof(*escape)); if (escape == NULL) return (EINVAL); - memset(escape, 0, sizeof(*escape)); if (strcmp("0", name) == 0) { escape->set = E0SET(ei); TAILQ_INSERT_TAIL(E0SET(ei), escape, entry); } else if (strcmp("1", name) == 0) { escape->set = E1SET(ei); TAILQ_INSERT_TAIL(E1SET(ei), escape, entry); } else { free(escape); return (EINVAL); } p[0] = (void *)escape; p[1] = (void *)ei; return (_citrus_prop_parse_variable( escape_hints, (void *)&p[0], s, strlen(s))); } static const _citrus_prop_hint_t root_hints[] = { _CITRUS_PROP_HINT_STR("0", &_citrus_HZ_parse_escape), _CITRUS_PROP_HINT_STR("1", &_citrus_HZ_parse_escape), _CITRUS_PROP_HINT_END }; static int _citrus_HZ_encoding_module_init(_HZEncodingInfo * __restrict ei, const void * __restrict var, size_t lenvar) { int errnum; memset(ei, 0, sizeof(*ei)); TAILQ_INIT(E0SET(ei)); TAILQ_INIT(E1SET(ei)); errnum = _citrus_prop_parse_variable( root_hints, (void *)ei, var, lenvar); if (errnum != 0) _citrus_HZ_encoding_module_uninit(ei); return (errnum); } /* ---------------------------------------------------------------------- * public interface for stdenc */ _CITRUS_STDENC_DECLS(HZ); _CITRUS_STDENC_DEF_OPS(HZ); #include "citrus_stdenc_template.h" Index: stable/10/usr.bin/iconv/iconv.c =================================================================== --- stable/10/usr.bin/iconv/iconv.c (revision 267664) +++ stable/10/usr.bin/iconv/iconv.c (revision 267665) @@ -1,219 +1,220 @@ /* $FreeBSD$ */ /* $NetBSD: iconv.c,v 1.16 2009/02/20 15:28:21 yamt Exp $ */ /*- * Copyright (c)2003 Citrus Project, * 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. */ #include #include #include #include #include #include #include #include #include #include #include #include -static unsigned long long invalids; +static int do_conv(FILE *, const char *, const char *, bool, bool); +static int do_list(unsigned int, const char * const *, void *); +static void usage(void) __dead2; -static void do_conv(FILE *, const char *, const char *, bool, bool); -static int do_list(unsigned int, const char * const *, void *); -static void usage(void); - -static struct option long_options[] = { +static const struct option long_options[] = { {"from-code", required_argument, NULL, 'f'}, {"list", no_argument, NULL, 'l'}, {"silent", no_argument, NULL, 's'}, {"to-code", required_argument, NULL, 't'}, {NULL, no_argument, NULL, 0} }; static void usage(void) { (void)fprintf(stderr, "Usage:\t%1$s [-cs] -f -t [file ...]\n" "\t%1$s -f [-cs] [-t ] [file ...]\n" "\t%1$s -t [-cs] [-f ] [file ...]\n" "\t%1$s -l\n", getprogname()); exit(1); } #define INBUFSIZE 1024 #define OUTBUFSIZE (INBUFSIZE * 2) -static void +static int do_conv(FILE *fp, const char *from, const char *to, bool silent, bool hide_invalid) { iconv_t cd; char inbuf[INBUFSIZE], outbuf[OUTBUFSIZE], *out; + unsigned long long invalids; const char *in; size_t inbytes, outbytes, ret; if ((cd = iconv_open(to, from)) == (iconv_t)-1) err(EXIT_FAILURE, "iconv_open(%s, %s)", to, from); if (hide_invalid) { int arg = 1; if (iconvctl(cd, ICONV_SET_DISCARD_ILSEQ, (void *)&arg) == -1) - err(1, NULL); + err(EXIT_FAILURE, NULL); } + invalids = 0; while ((inbytes = fread(inbuf, 1, INBUFSIZE, fp)) > 0) { in = inbuf; while (inbytes > 0) { size_t inval; out = outbuf; outbytes = OUTBUFSIZE; ret = __iconv(cd, &in, &inbytes, &out, &outbytes, 0, &inval); invalids += inval; if (outbytes < OUTBUFSIZE) (void)fwrite(outbuf, 1, OUTBUFSIZE - outbytes, stdout); if (ret == (size_t)-1 && errno != E2BIG) { if (errno != EINVAL || in == inbuf) err(EXIT_FAILURE, "iconv()"); /* incomplete input character */ (void)memmove(inbuf, in, inbytes); ret = fread(inbuf + inbytes, 1, INBUFSIZE - inbytes, fp); if (ret == 0) { fflush(stdout); if (feof(fp)) errx(EXIT_FAILURE, "unexpected end of file; " "the last character is " "incomplete."); else err(EXIT_FAILURE, "fread()"); } in = inbuf; inbytes += ret; } } } /* reset the shift state of the output buffer */ outbytes = OUTBUFSIZE; out = outbuf; ret = iconv(cd, NULL, NULL, &out, &outbytes); if (ret == (size_t)-1) err(EXIT_FAILURE, "iconv()"); if (outbytes < OUTBUFSIZE) (void)fwrite(outbuf, 1, OUTBUFSIZE - outbytes, stdout); if (invalids > 0 && !silent) warnx("warning: invalid characters: %llu", invalids); iconv_close(cd); + return (invalids > 0); } static int do_list(unsigned int n, const char * const *list, void *data __unused) { unsigned int i; for(i = 0; i < n; i++) { printf("%s", list[i]); if (i < n - 1) printf(" "); } printf("\n"); return (1); } int main(int argc, char **argv) { FILE *fp; char *opt_f, *opt_t; - int ch, i; + int ch, i, res; bool opt_c = false, opt_s = false; opt_f = opt_t = strdup(""); setlocale(LC_ALL, ""); setprogname(argv[0]); while ((ch = getopt_long(argc, argv, "csLlf:t:", long_options, NULL)) != -1) { switch (ch) { case 'c': opt_c = true; break; case 's': opt_s = true; break; case 'l': /* list */ if (opt_s || opt_c || strcmp(opt_f, "") != 0 || strcmp(opt_t, "") != 0) { warnx("-l is not allowed with other flags."); usage(); } iconvlist(do_list, NULL); return (EXIT_SUCCESS); case 'f': /* from */ if (optarg != NULL) opt_f = strdup(optarg); break; case 't': /* to */ if (optarg != NULL) opt_t = strdup(optarg); break; default: usage(); } } argc -= optind; argv += optind; if ((strcmp(opt_f, "") == 0) && (strcmp(opt_t, "") == 0)) usage(); if (argc == 0) - do_conv(stdin, opt_f, opt_t, opt_s, opt_c); + res = do_conv(stdin, opt_f, opt_t, opt_s, opt_c); else { + res = 0; for (i = 0; i < argc; i++) { fp = (strcmp(argv[i], "-") != 0) ? fopen(argv[i], "r") : stdin; if (fp == NULL) err(EXIT_FAILURE, "Cannot open `%s'", argv[i]); - do_conv(fp, opt_f, opt_t, opt_s, - opt_c); + res |= do_conv(fp, opt_f, opt_t, opt_s, opt_c); (void)fclose(fp); } } - return (EXIT_SUCCESS); + return (res == 0 ? EXIT_SUCCESS : EXIT_FAILURE); } Index: stable/10 =================================================================== --- stable/10 (revision 267664) +++ stable/10 (revision 267665) Property changes on: stable/10 ___________________________________________________________________ Modified: svn:mergeinfo ## -0,0 +0,1 ## Merged /head:r267436-267439