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. --- ChangeLog | 25 +++++++ elf/dl-support.c | 8 ++- 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 ++-- sysdeps/generic/enbl-secure.c | 5 +- wcsmbs/Makefile | 2 +- wcsmbs/wchar.h | 20 ++++++ wcsmbs/wmemrtombs.c | 121 ++++++++++++++++++++++++++++++++ wcsmbs/wmemrtowcs.c | 134 +++++++++++++++++++++++++++++++++++ 19 files changed, 520 insertions(+), 131 deletions(-) create mode 100644 wcsmbs/wmemrtombs.c create mode 100644 wcsmbs/wmemrtowcs.c diff --git a/ChangeLog b/ChangeLog index d18f75fa39..ad17e4fc23 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,28 @@ +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. + 1997-11-22 19:28 Ulrich Drepper * iconv/gconv_simple.c: Fix lots of bugs. diff --git a/elf/dl-support.c b/elf/dl-support.c index 41997ccafb..8b69ef07e7 100644 --- a/elf/dl-support.c +++ b/elf/dl-support.c @@ -46,6 +46,8 @@ struct r_search_path *_dl_search_paths; const char *_dl_profile; struct link_map *_dl_profile_map; +extern void __libc_init_secure (void); + static void non_dynamic_init (void) __attribute__ ((unused)); @@ -54,6 +56,10 @@ non_dynamic_init (void) { _dl_verbose = *(getenv ("LD_WARN") ?: "") == '\0' ? 0 : 1; + _dl_pagesize = __getpagesize (); + + __libc_init_secure (); + /* Initialize the data structures for the search paths for shared objects. */ _dl_init_paths (); @@ -65,7 +71,5 @@ non_dynamic_init (void) /* Now determine the length of the platform string. */ if (_dl_platform != NULL) _dl_platformlen = strlen (_dl_platform); - - _dl_pagesize = __getpagesize (); } text_set_element (__libc_subinit, non_dynamic_init); diff --git a/iconv/gconv.c b/iconv/gconv.c index 0cbb052a6d..5df16354b6 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 2c42f99ace..879db49e1c 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 a3070a532f..8dcc3aaaa2 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 d3d023f488..791c0259a3 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 d3c13d75c9..8a72c7aac9 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 ceb94be2b1..b1320ac7e8 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 a0003a82db..a80e5ef4ef 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 0e789df896..343cb70773 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 582c6f5a27..f769795273 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 e5b0eb7c0d..8804e851b6 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 d3123e21d8..ccd9d5f3ad 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 82802b7451..bfff00d917 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) { diff --git a/sysdeps/generic/enbl-secure.c b/sysdeps/generic/enbl-secure.c index b4c8e00017..fdf6f154f6 100644 --- a/sysdeps/generic/enbl-secure.c +++ b/sysdeps/generic/enbl-secure.c @@ -26,9 +26,8 @@ /* Safest assumption, if somehow the initializer isn't run. */ int __libc_enable_secure = 1; -static void -__attribute__ ((unused, constructor)) -init_secure (void) +void +__libc_init_secure (void) { __libc_enable_secure = (__geteuid () != __getuid () || __getegid () != __getgid ()); diff --git a/wcsmbs/Makefile b/wcsmbs/Makefile index 985f5957f9..5dd46da551 100644 --- a/wcsmbs/Makefile +++ b/wcsmbs/Makefile @@ -29,7 +29,7 @@ routines := wcscat wcschr wcscmp wcscpy wcscspn wcsdup wcslen wcsncat \ wmemcmp wmemcpy wmemmove wmemset wcpcpy wcpncpy \ btowc wctob mbsinit \ mbrlen mbrtowc wcrtomb mbsrtowcs wcsrtombs \ - mbsnrtowcs wcsnrtombs \ + mbsnrtowcs wcsnrtombs wmemrtowcs wmemrtombs \ wcstol wcstoul wcstoll wcstoull wcstod wcstold wcstof \ wcstol_l wcstoul_l wcstoll_l wcstoull_l \ wcstod_l wcstold_l wcstof_l \ diff --git a/wcsmbs/wchar.h b/wcsmbs/wchar.h index 966d20cba1..4c8f9a4dcf 100644 --- a/wcsmbs/wchar.h +++ b/wcsmbs/wchar.h @@ -253,6 +253,16 @@ extern size_t mbsnrtowcs __P ((wchar_t *__restrict __dst, __const char **__restrict __src, size_t __nmc, size_t __len, mbstate_t *__restrict __ps)); +/* Similar function to the above but this does not stop at NUL bytes. */ +extern size_t __wmemrtowcs __P ((wchar_t *__restrict __dst, + __const char **__restrict __src, + size_t __nmc, size_t __len, + mbstate_t *__restrict __ps)); +extern size_t wmemrtowcs __P ((wchar_t *__restrict __dst, + __const char **__restrict __src, + size_t __nmc, size_t __len, + mbstate_t *__restrict __ps)); + /* Write multibyte character representation of at most NWC characters from the wide character string SRC to DST. */ extern size_t __wcsnrtombs __P ((char *__restrict __dst, @@ -264,6 +274,16 @@ extern size_t wcsnrtombs __P ((char *__restrict __dst, size_t __nwc, size_t __len, mbstate_t *__restrict __ps)); +/* Similar function to the above but this does not stop at NUL bytes. */ +extern size_t __wmemrtombs __P ((char *__restrict __dst, + __const wchar_t **__restrict __src, + size_t __nwc, size_t len, + mbstate_t *__restrict __ps)); +extern size_t wmemrtombs __P ((char *__restrict __dst, + __const wchar_t **__restrict __src, + size_t __nwc, size_t len, + mbstate_t *__restrict __ps)); + /* The following functions are extensions found in X/Open CAE. */ diff --git a/wcsmbs/wmemrtombs.c b/wcsmbs/wmemrtombs.c new file mode 100644 index 0000000000..2bbd66788e --- /dev/null +++ b/wcsmbs/wmemrtombs.c @@ -0,0 +1,121 @@ +/* Copyright (C) 1997 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Ulrich Drepper , 1997. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public License as + published by the Free Software Foundation; either version 2 of the + License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Library General Public License for more details. + + You should have received a copy of the GNU Library General Public + License along with the GNU C Library; see the file COPYING.LIB. If not, + write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, + Boston, MA 02111-1307, USA. */ + +#include +#include + +#ifndef EILSEQ +#define EILSEQ EINVAL +#endif + + +static const wchar_t encoding_mask[] = +{ + ~0x7ff, ~0xffff, ~0x1fffff, ~0x3ffffff +}; + +static const unsigned char encoding_byte[] = +{ + 0xc0, 0xe0, 0xf0, 0xf8, 0xfc +}; + +/* We don't need the state really because we don't have shift states + to maintain between calls to this function. */ +static mbstate_t internal; + +/* This is a non-standard function but it is very useful in the + implementation of stdio because we have to deal with unterminated + buffers. At most NWC wide character will be converted. */ +size_t +__wmemrtombs (dst, src, nwc, len, ps) + char *dst; + const wchar_t **src; + size_t nwc; + size_t len; + mbstate_t *ps; +{ + size_t written = 0; + const wchar_t *run = *src; + + if (ps == NULL) + ps = &internal; + + if (dst == NULL) + /* The LEN parameter has to be ignored if we don't actually write + anything. */ + len = ~0; + + while (written < len && nwc-- > 0) + { + wchar_t wc = *run++; + + if (wc < 0 || wc > 0x7fffffff) + { + /* This is no correct ISO 10646 character. */ + __set_errno (EILSEQ); + return (size_t) -1; + } + + if (wc < 0x80) + { + /* It's an one byte sequence. */ + if (dst != NULL) + *dst++ = (char) wc; + ++written; + } + else + { + size_t step; + + for (step = 2; step < 6; ++step) + if ((wc & encoding_mask[step - 2]) == 0) + break; + + if (written + step >= len) + /* Too long. */ + break; + + if (dst != NULL) + { + size_t cnt = step; + + dst[0] = encoding_byte[cnt - 2]; + + --cnt; + do + { + dst[cnt] = 0x80 | (wc & 0x3f); + wc >>= 6; + } + while (--cnt > 0); + dst[0] |= wc; + + dst += step; + } + + written += step; + } + } + + /* Store position of first unprocessed word. */ + *src = run; + + return written; +} +weak_alias (__wmemrtombs, wmemrtombs) diff --git a/wcsmbs/wmemrtowcs.c b/wcsmbs/wmemrtowcs.c new file mode 100644 index 0000000000..1686229b8f --- /dev/null +++ b/wcsmbs/wmemrtowcs.c @@ -0,0 +1,134 @@ +/* Copyright (C) 1997 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Ulrich Drepper , 1997. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public License as + published by the Free Software Foundation; either version 2 of the + License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Library General Public License for more details. + + You should have received a copy of the GNU Library General Public + License along with the GNU C Library; see the file COPYING.LIB. If not, + write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, + Boston, MA 02111-1307, USA. */ + +#include +#include + +#ifndef EILSEQ +#define EILSEQ EINVAL +#endif + + +/* We don't need the state really because we don't have shift states + to maintain between calls to this function. */ +static mbstate_t internal; + +/* This is a non-standard function but it is very useful in the + implementation of stdio because we have to deal with unterminated + buffers. At most NMC bytes will be converted. */ +size_t +__wmemrtowcs (dst, src, nmc, len, ps) + wchar_t *dst; + const char **src; + size_t nmc; + size_t len; + mbstate_t *ps; +{ + size_t written = 0; + const char *run = *src; + const char *last = run + nmc; + + if (ps == NULL) + ps = &internal; + + if (dst == NULL) + /* The LEN parameter has to be ignored if we don't actually write + anything. */ + len = ~0; + + /* Copy all words. */ + while (written < len && run < last) + { + wchar_t value; + size_t count; + unsigned char byte = *run++; + + /* We expect a start of a new multibyte character. */ + if (byte < 0x80) + { + /* One byte sequence. */ + count = 0; + value = byte; + } + else if ((byte & 0xe0) == 0xc0) + { + count = 1; + value = byte & 0x1f; + } + else if ((byte & 0xf0) == 0xe0) + { + /* We expect three bytes. */ + count = 2; + value = byte & 0x0f; + } + else if ((byte & 0xf8) == 0xf0) + { + /* We expect four bytes. */ + count = 3; + value = byte & 0x07; + } + else if ((byte & 0xfc) == 0xf8) + { + /* We expect five bytes. */ + count = 4; + value = byte & 0x03; + } + else if ((byte & 0xfe) == 0xfc) + { + /* We expect six bytes. */ + count = 5; + value = byte & 0x01; + } + else + { + /* This is an illegal encoding. */ + __set_errno (EILSEQ); + return (size_t) -1; + } + + /* Read the possible remaining bytes. */ + while (count-- > 0) + { + byte = *run++; + + if ((byte & 0xc0) != 0x80) + { + /* This is an illegal encoding. */ + __set_errno (EILSEQ); + return (size_t) -1; + } + + value <<= 6; + value |= byte & 0x3f; + } + + /* Store value is required. */ + if (dst != NULL) + *dst++ = value; + + /* Increment counter of produced words. */ + ++written; + } + + /* Store address of next byte to process. */ + *src = run; + + return written; +} +weak_alias (__wmemrtowcs, wmemrtowcs) -- cgit v1.2.3