about summary refs log tree commit diff
diff options
context:
space:
mode:
-rw-r--r--ChangeLog25
-rw-r--r--elf/dl-support.c8
-rw-r--r--iconv/gconv.c3
-rw-r--r--iconv/gconv.h1
-rw-r--r--iconv/gconv_builtin.h6
-rw-r--r--iconv/gconv_close.c3
-rw-r--r--iconv/gconv_conf.c158
-rw-r--r--iconv/gconv_db.c72
-rw-r--r--iconv/gconv_dl.c5
-rw-r--r--iconv/gconv_open.c26
-rw-r--r--iconv/gconv_simple.c4
-rw-r--r--iconv/iconv.c38
-rw-r--r--iconv/iconv_close.c7
-rw-r--r--iconv/iconv_open.c13
-rw-r--r--sysdeps/generic/enbl-secure.c5
-rw-r--r--wcsmbs/Makefile2
-rw-r--r--wcsmbs/wchar.h20
-rw-r--r--wcsmbs/wmemrtombs.c121
-rw-r--r--wcsmbs/wmemrtowcs.c134
19 files changed, 520 insertions, 131 deletions
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  <drepper@cygnus.com>
+
+	* 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  <drepper@cygnus.com>
 
 	* 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 <ctype.h>
+#include <errno.h>
 #include <gconv.h>
 #include <search.h>
 #include <stdio.h>
@@ -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 = &current->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 = &current->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 <errno.h>
 #include <iconv.h>
 #include <gconv.h>
 
+#include <assert.h>
+
 
 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 <errno.h>
 #include <iconv.h>
 
 #include <gconv.h>
@@ -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 <drepper@gnu.org>, 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 <errno.h>
+#include <wchar.h>
+
+#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 <drepper@gnu.org>, 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 <errno.h>
+#include <wchar.h>
+
+#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)