From e34b0f2902588bbbfaf55829692e32c3c7134b74 Mon Sep 17 00:00:00 2001 From: Ulrich Drepper Date: Mon, 24 Nov 1997 02:08:40 +0000 Subject: Update. 1997-11-24 03:01 Ulrich Drepper * elf/dl-support.c: Call __libc_init_secure to make sure __libc_enable_secure is defined early. * sysdeps/generic/enbl-secure.c: Change function name to __libc_init_secure and make it global instead of a constructor. * iconv/gconv.c: Fix lots of bugs. * iconv/gconv.h: Likewise. * iconv/gconv_builtin.h: Likewise. * iconv/gconv_close.c: Likewise. * iconv/gconv_conf.c: Likewise. * iconv/gconv_db.c: Likewise. * iconv/gconv_dl.c: Likewise. * iconv/gconv_open.c: Likewise. * iconv/gconv_simple.c: Likewise. * iconv/iconv.c: Likewise. * iconv/iconv_close.c: Likewise. * iconv/iconv_open.c: Likewise. * wcsmbs/Makefile (routines): Add wmemrtowcs and wmemrtombs. * wcsmbs/wchar.h: Add prototypes for wmemrtowcs and wmemrtombs. * wcsmbs/wmemrtombs.c: New file. * wcsmbs/wmemrtowcs.c: New file. --- iconv/gconv.c | 3 + iconv/gconv.h | 1 + iconv/gconv_builtin.h | 6 +- iconv/gconv_close.c | 3 +- iconv/gconv_conf.c | 158 +++++++++++++++++++++++++++----------------------- iconv/gconv_db.c | 72 ++++++++++++++++------- iconv/gconv_dl.c | 5 +- iconv/gconv_open.c | 26 ++++----- iconv/gconv_simple.c | 4 +- iconv/iconv.c | 38 +++++++++++- iconv/iconv_close.c | 7 +++ iconv/iconv_open.c | 13 ++--- 12 files changed, 211 insertions(+), 125 deletions(-) (limited to 'iconv') diff --git a/iconv/gconv.c b/iconv/gconv.c index 0cbb052..5df1635 100644 --- a/iconv/gconv.c +++ b/iconv/gconv.c @@ -30,6 +30,9 @@ __gconv (gconv_t cd, const char **inbuf, size_t *inbytesleft, char **outbuf, size_t oldinbytes = *inbytesleft; int result; + if (cd == (gconv_t) -1L) + return GCONV_ILLEGAL_DESCRIPTOR; + cd->data[last_step].outbuf = *outbuf; cd->data[last_step].outbufavail = 0; cd->data[last_step].outbufsize = *outbytesleft; diff --git a/iconv/gconv.h b/iconv/gconv.h index 2c42f99..879db49 100644 --- a/iconv/gconv.h +++ b/iconv/gconv.h @@ -37,6 +37,7 @@ enum GCONV_EMPTY_INPUT, GCONV_FULL_OUTPUT, GCONV_ILLEGAL_INPUT, + GCONV_INCOMPLETE_INPUT, GCONV_ILLEGAL_DESCRIPTOR, GCONV_INTERNAL_ERROR diff --git a/iconv/gconv_builtin.h b/iconv/gconv_builtin.h index a3070a5..8dcc3aa 100644 --- a/iconv/gconv_builtin.h +++ b/iconv/gconv_builtin.h @@ -18,17 +18,17 @@ write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ -BUILTIN_TRANSFORMATION ("\\([^/]+\\)/UCS4/\\([^/]*\\)", NULL, 0, +BUILTIN_TRANSFORMATION ("([^/]+)/UCS4/([^/]*)", NULL, 0, "\\1/UTF8/\\2", 1, "=ucs4->utf8", __gconv_transform_ucs4_utf8, __gconv_transform_init_rstate, __gconv_transform_end_rstate) -BUILTIN_TRANSFORMATION ("\\([^/]+\\)/UTF8/\\([^/]*\\)", NULL, 0, +BUILTIN_TRANSFORMATION ("([^/]+)/UTF8/([^/]*)", NULL, 0, "\\1/UCS4/\\2", 1, "=utf8->ucs4", __gconv_transform_utf8_ucs4, __gconv_transform_init_rstate, __gconv_transform_end_rstate) -BUILTIN_TRANSFORMATION ("\\(.*\\)", NULL, 0, "\\1", 1, "=dummy", +BUILTIN_TRANSFORMATION ("(.*)", NULL, 0, "\\1", 1, "=dummy", __gconv_transform_dummy, NULL, NULL) diff --git a/iconv/gconv_close.c b/iconv/gconv_close.c index d3d023f..791c025 100644 --- a/iconv/gconv_close.c +++ b/iconv/gconv_close.c @@ -48,9 +48,8 @@ __gconv_close (gconv_t cd) /* Next step. */ ++srunp; - ++drunp; } - while (!drunp->is_last); + while (!(drunp++)->is_last); /* Save the pointer, we need it below. */ srunp = cd->steps; diff --git a/iconv/gconv_conf.c b/iconv/gconv_conf.c index d3c13d7..8a72c7a 100644 --- a/iconv/gconv_conf.c +++ b/iconv/gconv_conf.c @@ -19,6 +19,7 @@ Boston, MA 02111-1307, USA. */ #include +#include #include #include #include @@ -35,6 +36,12 @@ static const char default_gconv_path[] = GCONV_PATH; along the path. */ static const char gconv_conf_filename[] = "gconv-modules"; +/* Filename extension for the modules. */ +#ifndef MODULE_EXT +# define MODULE_EXT ".so" +#endif +static const char gconv_module_ext[] = MODULE_EXT; + /* We have a few builtin transformations. */ static struct gconv_module builtin_modules[] = { @@ -111,15 +118,18 @@ add_alias (char *rp) new_alias = (struct gconv_alias *) malloc (sizeof (struct gconv_alias) + (wp - from)); - new_alias->fromname = memcpy ((char *) new_alias - + sizeof (struct gconv_alias), - from, to - from); - new_alias->toname = memcpy ((char *) new_alias + sizeof (struct gconv_alias) - + (to - from), to, wp - to); - - if (__tsearch (new_alias, &__gconv_alias_db, __gconv_alias_compare) == NULL) - /* Something went wrong, free this entry. */ - free (new_alias); + if (new_alias != NULL) + { + new_alias->fromname = memcpy ((char *) new_alias + + sizeof (struct gconv_alias), + from, wp - from); + new_alias->toname = new_alias->fromname + (to - from); + + if (__tsearch (new_alias, &__gconv_alias_db, __gconv_alias_compare) + == NULL) + /* Something went wrong, free this entry. */ + free (new_alias); + } } @@ -138,6 +148,7 @@ add_module (char *rp, const char *directory, size_t dir_len, void **modules, char *from, *to, *module, *wp; size_t const_len; int from_is_regex; + int need_ext; int cost; while (isspace (*rp)) @@ -195,65 +206,68 @@ add_module (char *rp, const char *directory, size_t dir_len, void **modules, /* Increment by one for the slash. */ ++dir_len; + /* See whether we must add the ending. */ + need_ext = 0; + if (wp - module < sizeof (gconv_module_ext) + || memcmp (wp - sizeof (gconv_module_ext), gconv_module_ext, + sizeof (gconv_module_ext)) != 0) + /* We must add the module extension. */ + need_ext = sizeof (gconv_module_ext) - 1; + /* We've collected all the information, now create an entry. */ - const_len = 0; if (from_is_regex) - do - ++const_len; - while (isalnum (from[const_len]) || from[const_len] == '-' - || from[const_len] == '/' || from[const_len] == '.' - || from[const_len] == '_'); + { + const_len = 0; + while (isalnum (from[const_len]) || from[const_len] == '-' + || from[const_len] == '/' || from[const_len] == '.' + || from[const_len] == '_') + ++const_len; + } + else + const_len = to - from - 1; new_module = (struct gconv_module *) malloc (sizeof (struct gconv_module) - + (wp - from) + const_len - + dir_len); + + (wp - from) + + dir_len + need_ext); if (new_module != NULL) { + char *tmp; + + new_module->from_constpfx = memcpy ((char *) new_module + + sizeof (struct gconv_module), + from, to - from); if (from_is_regex) - { - new_module->from_pattern = memcpy ((char *) new_module - + sizeof (struct gconv_module), - from, to - from); - new_module->from_constpfx = memcpy ((char *) new_module->from_pattern - + (to - from), - from, const_len); - ((char *) new_module->from_constpfx)[const_len] = '\0'; - new_module->from_constpfx_len = const_len; - ++const_len; - } + new_module->from_pattern = new_module->from_constpfx; else - { - new_module->from_pattern = NULL; - new_module->from_constpfx = memcpy ((char *) new_module - + sizeof (struct gconv_module), - from, to - from); - new_module->from_constpfx_len = to - from - 1; - const_len = to - from; - } + new_module->from_pattern = NULL; + + new_module->from_constpfx_len = const_len; + new_module->from_regex = NULL; new_module->to_string = memcpy ((char *) new_module->from_constpfx - + const_len + 1, to, module - to); + + (to - from), to, module - to); new_module->cost = cost; + new_module->module_name = (char *) new_module->to_string + (module - to); + if (dir_len == 0) - new_module->module_name = memcpy ((char *) new_module->to_string - + (module - to), - module, wp - module); + tmp = (char *) new_module->module_name; else { - char *tmp; - new_module->module_name = ((char *) new_module->to_string - + (module - to)); tmp = __mempcpy ((char *) new_module->module_name, directory, dir_len - 1); *tmp++ = '/'; - memcpy (tmp, module, wp - module); } - if (__tfind (new_module, *modules, module_compare) != NULL) + tmp = __mempcpy (tmp, module, wp - module); + + if (need_ext) + memcpy (tmp - 1, gconv_module_ext, sizeof (gconv_module_ext)); + + if (__tfind (new_module, modules, module_compare) == NULL) if (__tsearch (new_module, modules, module_compare) == NULL) /* Something went wrong while inserting the new module. */ free (new_module); @@ -267,7 +281,7 @@ static void insert_module (const void *nodep, VISIT value, int level) { if (value == preorder || value == leaf) - __gconv_modules_db[__gconv_nmodules++] = (struct gconv_module *) nodep; + __gconv_modules_db[__gconv_nmodules++] = *(struct gconv_module **) nodep; } static void @@ -302,8 +316,6 @@ read_conf_file (const char *filename, const char *directory, size_t dir_len, break; rp = line; - while (isspace (*rp)) - ++rp; /* Terminate the line (excluding comments or newline) by an NUL byte to simplify the following code. */ endp = strchr (rp, '#'); @@ -316,6 +328,9 @@ read_conf_file (const char *filename, const char *directory, size_t dir_len, *endp = '\0'; } + while (isspace (*rp)) + ++rp; + /* If this is an empty line go on with the next one. */ if (rp == endp) continue; @@ -325,10 +340,10 @@ read_conf_file (const char *filename, const char *directory, size_t dir_len, ++rp; if (rp - word == sizeof ("alias") - 1 - && memcpy (word, "alias", sizeof ("alias") - 1) == 0) + && memcmp (word, "alias", sizeof ("alias") - 1) == 0) add_alias (rp); else if (rp - word == sizeof ("module") - 1 - && memcpy (word, "module", sizeof ("module") - 1) == 0) + && memcmp (word, "module", sizeof ("module") - 1) == 0) add_module (rp, directory, dir_len, modules, nmodules); /* else */ /* Otherwise ignore the line. */ @@ -349,6 +364,7 @@ __gconv_read_conf (void) char *gconv_path, *elem; void *modules = NULL; size_t nmodules = 0; + int save_errno = errno; if (user_path == NULL) /* No user-defined path. Make a modifiable copy of the default path. */ @@ -390,31 +406,31 @@ __gconv_read_conf (void) /* If the configuration files do not contain any valid module specification remember this by setting the pointer to the module array to NULL. */ - nmodules = sizeof (builtin_modules) / sizeof (struct gconv_module); + nmodules += sizeof (builtin_modules) / sizeof (builtin_modules[0]); if (nmodules == 0) + __gconv_modules_db = NULL; + else { - __gconv_modules_db = NULL; - return; - } + __gconv_modules_db = + (struct gconv_module **) malloc (nmodules + * sizeof (struct gconv_module)); + if (__gconv_modules_db != NULL) + { + size_t cnt; - __gconv_modules_db = - (struct gconv_module **) malloc (nmodules * sizeof (struct gconv_module)); - if (__gconv_modules_db == NULL) - /* We cannot do anything. */ - return; + /* Insert all module entries into the array. */ + __twalk (modules, insert_module); - /* First insert the builtin transformations. */ - while (__gconv_nmodules < (sizeof (builtin_modules) - / sizeof (struct gconv_module))) - { - __gconv_modules_db[__gconv_nmodules] = - &builtin_modules[__gconv_nmodules]; - ++__gconv_nmodules; - } + /* No remove the tree data structure. */ + __tdestroy (modules, nothing); - /* Insert all module entries into the array. */ - __twalk (modules, insert_module); + /* Finally insert the builtin transformations. */ + for (cnt = 0; cnt < (sizeof (builtin_modules) + / sizeof (struct gconv_module)); ++cnt) + __gconv_modules_db[__gconv_nmodules++] = &builtin_modules[cnt]; + } + } - /* No remove the tree data structure. */ - __tdestroy (modules, nothing); + /* Restore the error number. */ + __set_errno (save_errno); } diff --git a/iconv/gconv_db.c b/iconv/gconv_db.c index ceb94be..b1320ac 100644 --- a/iconv/gconv_db.c +++ b/iconv/gconv_db.c @@ -99,7 +99,7 @@ derivation_lookup (const char *fromset, const char *toset, struct known_derivation key = { fromset, toset, NULL, 0 }; struct known_derivation *result; - result = __tfind (&key, known_derivations, derivation_compare); + result = __tfind (&key, &known_derivations, derivation_compare); if (result == NULL) return GCONV_NOCONV; @@ -169,11 +169,18 @@ gen_steps (struct derivation_step *best, const char *toset, * step_cnt); if (result != NULL) { + int failed = 0; + + *nsteps = step_cnt; current = best; while (step_cnt-- > 0) { - result[step_cnt].from_name = current->last->result_set; - result[step_cnt].to_name = current->result_set; + result[step_cnt].from_name = (step_cnt == 0 + ? __strdup (fromset) + : current->last->result_set); + result[step_cnt].to_name = (step_cnt + 1 == *nsteps + ? __strdup (current->result_set) + : result[step_cnt + 1].from_name); if (current->code->module_name[0] == '/') { @@ -182,7 +189,10 @@ gen_steps (struct derivation_step *best, const char *toset, __gconv_find_shlib (current->code->module_name); if (shlib_handle == NULL) - break; + { + failed = 1; + break; + } result[step_cnt].shlib_handle = shlib_handle; @@ -192,6 +202,7 @@ gen_steps (struct derivation_step *best, const char *toset, /* Argh, no conversion function. There is something wrong here. */ __gconv_release_shlib (result[step_cnt].shlib_handle); + failed = 1; break; } @@ -208,18 +219,18 @@ gen_steps (struct derivation_step *best, const char *toset, current = current->last; } - if (step_cnt != 0) + if (failed != 0) { /* Something went wrong while initializing the modules. */ - while (step_cnt-- > 0) + while (++step_cnt < *nsteps) __gconv_release_shlib (result[step_cnt].shlib_handle); free (result); + *nsteps = 0; status = GCONV_NOCONV; } else { *handle = result; - *nsteps = step_cnt; status = GCONV_OK; } } @@ -231,12 +242,13 @@ gen_steps (struct derivation_step *best, const char *toset, /* The main function: find a possible derivation from the `fromset' (either the given name or the alias) to the `toset' (again with alias). */ static int +internal_function find_derivation (const char *toset, const char *toset_expand, const char *fromset, const char *fromset_expand, struct gconv_step **handle, size_t *nsteps) { __libc_lock_define_initialized (static, lock) - struct derivation_step *current, **lastp, *best = NULL; + struct derivation_step *first, *current, **lastp, *best = NULL; int best_cost = 0; int result; @@ -260,16 +272,17 @@ find_derivation (const char *toset, const char *toset_expand, The task is to match the `toset' with any of the available. */ if (fromset_expand != NULL) { - current = NEW_STEP (fromset_expand, NULL, NULL); - current->next = NEW_STEP (fromset, NULL, NULL); - lastp = ¤t->next->next; + first = NEW_STEP (fromset_expand, NULL, NULL); + first->next = NEW_STEP (fromset, NULL, NULL); + lastp = &first->next->next; } else { - current = NEW_STEP (fromset, NULL, NULL); - lastp = ¤t->next; + first = NEW_STEP (fromset, NULL, NULL); + lastp = &first->next; } + current = first; while (current != NULL) { /* Now match all the available module specifications against the @@ -419,13 +432,28 @@ find_derivation (const char *toset, const char *toset_expand, } else { - /* Append at the end. */ - *lastp = NEW_STEP (result_set, __gconv_modules_db[cnt], - current); - lastp = &(*lastp)->next; + /* Append at the end if there is no entry with this name. */ + struct derivation_step *runp = first; + + while (runp != NULL) + { + if (__strcasecmp (result_set, runp->result_set) == 0) + break; + runp = runp->next; + } + + if (runp == NULL) + { + *lastp = NEW_STEP (result_set, __gconv_modules_db[cnt], + current); + lastp = &(*lastp)->next; + } } } } + + /* Go on with the next entry. */ + current = current->next; } if (best != NULL) @@ -470,15 +498,15 @@ __gconv_find_transform (const char *toset, const char *fromset, if (__gconv_alias_db != NULL) { struct gconv_alias key; - struct gconv_alias *found; + struct gconv_alias **found; key.fromname = fromset; - found = __tfind (&key, __gconv_alias_db, __gconv_alias_compare); - fromset_expand = found != NULL ? found->toname : NULL; + found = __tfind (&key, &__gconv_alias_db, __gconv_alias_compare); + fromset_expand = found != NULL ? (*found)->toname : NULL; key.fromname = toset; - found = __tfind (&key, __gconv_alias_db, __gconv_alias_compare); - toset_expand = found != NULL ? found->toname : NULL; + found = __tfind (&key, &__gconv_alias_db, __gconv_alias_compare); + toset_expand = found != NULL ? (*found)->toname : NULL; } result = find_derivation (toset, toset_expand, fromset, fromset_expand, diff --git a/iconv/gconv_dl.c b/iconv/gconv_dl.c index a0003a8..a80e5ef 100644 --- a/iconv/gconv_dl.c +++ b/iconv/gconv_dl.c @@ -84,6 +84,7 @@ do_open (void *a) static int +internal_function dlerror_run (void (*operate) (void *), void *args) { char *last_errstring = NULL; @@ -156,7 +157,7 @@ __gconv_find_shlib (const char *name) enough to a pointer to our structure to use as a lookup key that will be passed to `known_compare' (above). */ - found = __tfind (&name, loaded, known_compare); + found = __tfind (&name, &loaded, known_compare); if (found == NULL) { /* This name was not known before. */ @@ -208,7 +209,7 @@ static void *release_handle; static void do_release_shlib (const void *nodep, VISIT value, int level) { - struct loaded_object *obj = (struct loaded_object *) nodep; + struct loaded_object *obj = *(struct loaded_object **) nodep; if (value != preorder && value != leaf) return; diff --git a/iconv/gconv_open.c b/iconv/gconv_open.c index 0e789df..343cb70 100644 --- a/iconv/gconv_open.c +++ b/iconv/gconv_open.c @@ -69,19 +69,19 @@ __gconv_open (const char *toset, const char *fromset, gconv_t *handle) if (res != GCONV_OK) break; } - else - if (!data[cnt].is_last) - { - data[cnt].outbufsize = GCONV_DEFAULT_BUFSIZE; - data[cnt].outbuf = - (char *) malloc (data[cnt].outbufsize); - if (data[cnt].outbuf == NULL) - { - res = GCONV_NOMEM; - break; - } - data[cnt].outbufavail = 0; - } + + if (!data[cnt].is_last && data[cnt].outbuf == NULL) + { + data[cnt].outbufsize = GCONV_DEFAULT_BUFSIZE; + data[cnt].outbuf = + (char *) malloc (data[cnt].outbufsize); + if (data[cnt].outbuf == NULL) + { + res = GCONV_NOMEM; + break; + } + data[cnt].outbufavail = 0; + } } } } diff --git a/iconv/gconv_simple.c b/iconv/gconv_simple.c index 582c6f5..f769795 100644 --- a/iconv/gconv_simple.c +++ b/iconv/gconv_simple.c @@ -117,7 +117,7 @@ __gconv_transform_ucs4_utf8 (struct gconv_step *step, do { const char *newinbuf = inbuf; - size_t actually = __wcsnrtombs (&data->outbuf[data->outbufavail], + size_t actually = __wmemrtombs (&data->outbuf[data->outbufavail], (const wchar_t **) &newinbuf, *inlen / sizeof (wchar_t), data->outbufsize - data->outbufavail, @@ -206,7 +206,7 @@ __gconv_transform_utf8_ucs4 (struct gconv_step *step, do { const char *newinbuf = inbuf; - size_t actually = __mbsnrtowcs ((wchar_t *) &data->outbuf[data->outbufavail], + size_t actually = __wmemrtowcs ((wchar_t *) &data->outbuf[data->outbufavail], &newinbuf, *inlen, ((data->outbufsize - data->outbufavail) diff --git a/iconv/iconv.c b/iconv/iconv.c index e5b0eb7..8804e85 100644 --- a/iconv/iconv.c +++ b/iconv/iconv.c @@ -19,9 +19,12 @@ write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ +#include #include #include +#include + size_t iconv (iconv_t cd, const char **inbuf, size_t *inbytesleft, char **outbuf, @@ -29,10 +32,39 @@ iconv (iconv_t cd, const char **inbuf, size_t *inbytesleft, char **outbuf, { gconv_t gcd = (gconv_t) cd; size_t converted; + int result; + + result = __gconv (gcd, inbuf, inbytesleft, outbuf, outbytesleft, &converted); + switch (result) + { + case GCONV_ILLEGAL_DESCRIPTOR: + __set_errno (EBADF); + converted = (size_t) -1L; + break; + + case GCONV_ILLEGAL_INPUT: + __set_errno (EILSEQ); + converted = (size_t) -1L; + break; + + case GCONV_FULL_OUTPUT: + __set_errno (E2BIG); + converted = (size_t) -1L; + break; + + case GCONV_INCOMPLETE_INPUT: + __set_errno (EINVAL); + converted = (size_t) -1L; + break; + + case GCONV_EMPTY_INPUT: + case GCONV_OK: + /* Nothing. */ + break; - if (__gconv (gcd, inbuf, inbytesleft, outbuf, outbytesleft, &converted) - != GCONV_OK) - return (size_t) -1; + default: + assert (!"Nothing like this should happen"); + } return converted; } diff --git a/iconv/iconv_close.c b/iconv/iconv_close.c index d3123e2..ccd9d5f 100644 --- a/iconv/iconv_close.c +++ b/iconv/iconv_close.c @@ -18,6 +18,7 @@ write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ +#include #include #include @@ -26,5 +27,11 @@ int iconv_close (iconv_t cd) { + if (cd == (iconv_t *) -1L) + { + __set_errno (EBADF); + return -1; + } + return __gconv_close ((gconv_t) cd) ? -1 : 0; } diff --git a/iconv/iconv_open.c b/iconv/iconv_open.c index 82802b7..bfff00d 100644 --- a/iconv/iconv_open.c +++ b/iconv/iconv_open.c @@ -27,11 +27,9 @@ static inline void -strip (char *s) +strip (char *wp, const char *s) { int slash_count = 0; - char *wp; - wp = s; while (*s != '\0') { @@ -39,7 +37,7 @@ strip (char *s) *wp++ = *s; else if (*s == '/') { - if (++slash_count == 2) + if (++slash_count == 3) break; *wp++ = '/'; } @@ -67,14 +65,15 @@ iconv_open (const char *tocode, const char *fromcode) '_', '-', '/', and '.'. */ tocode_len = strlen (tocode); tocode_conv = alloca (tocode_len + 3); - strip (memcpy (tocode_conv, tocode, tocode_len + 1)); + strip (tocode_conv, tocode); fromcode_len = strlen (fromcode); fromcode_conv = alloca (fromcode_len + 3); - strip (memcpy (fromcode_conv, fromcode, fromcode_len + 1)); + strip (fromcode_conv, fromcode); res = __gconv_open (tocode_conv[2] == '\0' ? tocode : tocode_conv, - fromcode_conv[2] == '\0' ? fromcode, fromcode_conv, &cd); + fromcode_conv[2] == '\0' ? fromcode : fromcode_conv, + &cd); if (res != GCONV_OK) { -- cgit v1.1