summary refs log tree commit diff
diff options
context:
space:
mode:
authorUlrich Drepper <drepper@redhat.com>2000-06-12 19:47:50 +0000
committerUlrich Drepper <drepper@redhat.com>2000-06-12 19:47:50 +0000
commit55985355ade2a038b567dd9b58153a98384ae703 (patch)
treeb6252e23490e6d10d55ae926e30e32173f504190
parenta5b97402f70a3cd43ffee9ccb71560457b4cd88c (diff)
downloadglibc-55985355ade2a038b567dd9b58153a98384ae703.tar.gz
glibc-55985355ade2a038b567dd9b58153a98384ae703.tar.xz
glibc-55985355ade2a038b567dd9b58153a98384ae703.zip
Update.
2000-06-12  Ulrich Drepper  <drepper@redhat.com>

	* Rules (%.out): Define GCONV_PATH in the environment.
	* assert/Depend: New file.
	* iconvdata/Depend: New file.
	* intl/Depend: New file.
	* timezone/Makefile (build-testdata): Add GCONV_PATH to environment.
	* intl/tst-gettext.sh: Likewise.
	* iconv/Makefile (routines): Add gconv_trans.
	* iconv/gconv_trans.c: New file.
	* iconv/gconv.h (struct __gconv_trans_data): New type.
	(__gconv_fct): New parameter with starting position in output buffer.
	(__gconv_trans_fct, __gconv_trans_context_fct, __gconv_trans_query_fct,
	__gconv_trans_init_fct, __gconv_trans_end_fct): New types.
	(struct __gconv_step): Add new member __trans.
	* iconv/gconv_int.h: Pretty print prototypes.
	(gconv_transliterate): New prototype.
	(__BUILTIN_TRANS): Update for new conversion function interface.
	* iconv/gconv.c (__gconv): Pass new parameter to conversion function.
	* iconv/gconv_open.c (__gconv_open): Recognize error handling suffix
	in names, find appropriate function, and install in the conversion
	steps it can be used.
	* iconv/skeleton.c: Add additional parameter for beginning of output
	buffer.  Change calls of downstream functions.
	* iconv/loop.c: Change loop function interface completely.  Pass in
	step and step_data structure.  Remove optimization for BODY with
	NEED_LENGTH_TEST == 0.
	* iconv/gconv_simple.c: Update interfaces of functions.  Insert
	appropriate error handling code to use transliteration steps.  Remove
	optimization for BODY with NEED_LENGTH_TEST == 0.
	* iconvdata/8bit-gap.c: Likewise.
	* iconvdata/8bit-generic.c: Likewise.
	* iconvdata/ansi_x3.110.c: Likewise.
	* iconvdata/big5.c: Likewise.
	* iconvdata/big5hkscs.c: Likewise.
	* iconvdata/euc-cn.c: Likewise.
	* iconvdata/euc-jp.c: Likewise.
	* iconvdata/euc-kr.c: Likewise.
	* iconvdata/euc-tw.c: Likewise.
	* iconvdata/gbgbk.c: Likewise.
	* iconvdata/gbk.c: Likewise.
	* iconvdata/iso-2022-cn.c: Likewise.
	* iconvdata/iso-2022-jp.c: Likewise.
	* iconvdata/iso-2022-kr.c: Likewise.
	* iconvdata/iso646.c: Likewise.
	* iconvdata/iso8859-1.c: Likewise.
	* iconvdata/iso_6937-2.c: Likewise.
	* iconvdata/iso_6937.c: Likewise.
	* iconvdata/johab.c: Likewise.
	* iconvdata/sjis.c: Likewise.
	* iconvdata/t.61.c: Likewise.
	* iconvdata/uhc.c: Likewise.
	* iconvdata/unicode.c: Likewise.
	* iconvdata/utf-16.c: Likewise.
	* libio/iofwide.c: Adjust to new interface of gconv functions.  Use
	DL_CALL_FCT.
	* wcsmbs/btowc.c: Likewise.
	* wcsmbs/mbrtowc.c: Likewise.
	* wcsmbs/mbsnrtowcs.c: Likewise.
	* wcsmbs/mbsrtowcs.c: Likewise.
	* wcsmbs/wcrtomb.c: Likewise.
	* wcsmbs/wcsnrtombs.c: Likewise.
	* wcsmbs/wcsrtombs.c: Likewise.
	* wcsmbs/wctob.c: Likewise.
-rw-r--r--ChangeLog65
-rw-r--r--iconv/Makefile2
-rw-r--r--iconv/gconv.c8
-rw-r--r--iconv/gconv.h39
-rw-r--r--iconv/gconv_int.h48
-rw-r--r--iconv/gconv_open.c102
-rw-r--r--iconv/gconv_simple.c177
-rw-r--r--iconv/gconv_trans.c50
-rw-r--r--iconv/loop.c129
-rw-r--r--iconv/skeleton.c60
-rw-r--r--iconvdata/8bit-gap.c49
-rw-r--r--iconvdata/8bit-generic.c28
-rw-r--r--iconvdata/ansi_x3.110.c64
-rw-r--r--iconvdata/big5.c25
-rw-r--r--iconvdata/big5hkscs.c25
-rw-r--r--iconvdata/euc-cn.c30
-rw-r--r--iconvdata/euc-jp.c40
-rw-r--r--iconvdata/euc-kr.c28
-rw-r--r--iconvdata/euc-tw.c100
-rw-r--r--iconvdata/gbgbk.c29
-rw-r--r--iconvdata/gbk.c29
-rw-r--r--iconvdata/iso-2022-cn.c58
-rw-r--r--iconvdata/iso-2022-jp.c138
-rw-r--r--iconvdata/iso-2022-kr.c36
-rw-r--r--iconvdata/iso646.c21
-rw-r--r--iconvdata/iso8859-1.c20
-rw-r--r--iconvdata/iso_6937-2.c52
-rw-r--r--iconvdata/iso_6937.c44
-rw-r--r--iconvdata/johab.c59
-rw-r--r--iconvdata/sjis.c44
-rw-r--r--iconvdata/t.61.c45
-rw-r--r--iconvdata/uhc.c57
-rw-r--r--iconvdata/unicode.c26
-rw-r--r--iconvdata/utf-16.c55
-rwxr-xr-xintl/tst-gettext.sh3
-rw-r--r--libio/iofwide.c30
-rw-r--r--linuxthreads/ChangeLog2
-rw-r--r--linuxthreads/Makefile3
-rw-r--r--timezone/Makefile5
-rw-r--r--wcsmbs/btowc.c7
-rw-r--r--wcsmbs/mbrtowc.c7
-rw-r--r--wcsmbs/mbsnrtowcs.c14
-rw-r--r--wcsmbs/mbsrtowcs.c12
-rw-r--r--wcsmbs/wcrtomb.c15
-rw-r--r--wcsmbs/wcsnrtombs.c16
-rw-r--r--wcsmbs/wcsrtombs.c16
-rw-r--r--wcsmbs/wctob.c11
47 files changed, 1352 insertions, 571 deletions
diff --git a/ChangeLog b/ChangeLog
index ff88eb8bec..4f3f8ffe9e 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,68 @@
+2000-06-12  Ulrich Drepper  <drepper@redhat.com>
+
+	* Rules (%.out): Define GCONV_PATH in the environment.
+	* assert/Depend: New file.
+	* iconvdata/Depend: New file.
+	* intl/Depend: New file.
+	* timezone/Makefile (build-testdata): Add GCONV_PATH to environment.
+	* intl/tst-gettext.sh: Likewise.
+	* iconv/Makefile (routines): Add gconv_trans.
+	* iconv/gconv_trans.c: New file.
+	* iconv/gconv.h (struct __gconv_trans_data): New type.
+	(__gconv_fct): New parameter with starting position in output buffer.
+	(__gconv_trans_fct, __gconv_trans_context_fct, __gconv_trans_query_fct,
+	__gconv_trans_init_fct, __gconv_trans_end_fct): New types.
+	(struct __gconv_step): Add new member __trans.
+	* iconv/gconv_int.h: Pretty print prototypes.
+	(gconv_transliterate): New prototype.
+	(__BUILTIN_TRANS): Update for new conversion function interface.
+	* iconv/gconv.c (__gconv): Pass new parameter to conversion function.
+	* iconv/gconv_open.c (__gconv_open): Recognize error handling suffix
+	in names, find appropriate function, and install in the conversion
+	steps it can be used.
+	* iconv/skeleton.c: Add additional parameter for beginning of output
+	buffer.  Change calls of downstream functions.
+	* iconv/loop.c: Change loop function interface completely.  Pass in
+	step and step_data structure.  Remove optimization for BODY with
+	NEED_LENGTH_TEST == 0.
+	* iconv/gconv_simple.c: Update interfaces of functions.  Insert
+	appropriate error handling code to use transliteration steps.  Remove
+	optimization for BODY with NEED_LENGTH_TEST == 0.
+	* iconvdata/8bit-gap.c: Likewise.
+	* iconvdata/8bit-generic.c: Likewise.
+	* iconvdata/ansi_x3.110.c: Likewise.
+	* iconvdata/big5.c: Likewise.
+	* iconvdata/big5hkscs.c: Likewise.
+	* iconvdata/euc-cn.c: Likewise.
+	* iconvdata/euc-jp.c: Likewise.
+	* iconvdata/euc-kr.c: Likewise.
+	* iconvdata/euc-tw.c: Likewise.
+	* iconvdata/gbgbk.c: Likewise.
+	* iconvdata/gbk.c: Likewise.
+	* iconvdata/iso-2022-cn.c: Likewise.
+	* iconvdata/iso-2022-jp.c: Likewise.
+	* iconvdata/iso-2022-kr.c: Likewise.
+	* iconvdata/iso646.c: Likewise.
+	* iconvdata/iso8859-1.c: Likewise.
+	* iconvdata/iso_6937-2.c: Likewise.
+	* iconvdata/iso_6937.c: Likewise.
+	* iconvdata/johab.c: Likewise.
+	* iconvdata/sjis.c: Likewise.
+	* iconvdata/t.61.c: Likewise.
+	* iconvdata/uhc.c: Likewise.
+	* iconvdata/unicode.c: Likewise.
+	* iconvdata/utf-16.c: Likewise.
+	* libio/iofwide.c: Adjust to new interface of gconv functions.  Use
+	DL_CALL_FCT.
+	* wcsmbs/btowc.c: Likewise.
+	* wcsmbs/mbrtowc.c: Likewise.
+	* wcsmbs/mbsnrtowcs.c: Likewise.
+	* wcsmbs/mbsrtowcs.c: Likewise.
+	* wcsmbs/wcrtomb.c: Likewise.
+	* wcsmbs/wcsnrtombs.c: Likewise.
+	* wcsmbs/wcsrtombs.c: Likewise.
+	* wcsmbs/wctob.c: Likewise.
+
 2000-04-11  Geoff Keating  <geoffk@cygnus.com>
 
 	* sysdeps/powerpc/dl-machine.c: Include dl-machine.h after the
diff --git a/iconv/Makefile b/iconv/Makefile
index 14076e6f6e..6af661c964 100644
--- a/iconv/Makefile
+++ b/iconv/Makefile
@@ -26,7 +26,7 @@ include ../Makeconfig
 headers		= iconv.h gconv.h
 routines	= iconv_open iconv iconv_close \
 		  gconv_open gconv gconv_close gconv_db gconv_conf \
-		  gconv_builtin gconv_simple
+		  gconv_builtin gconv_simple gconv_trans
 ifeq ($(elf),yes)
 routines	+= gconv_dl
 else
diff --git a/iconv/gconv.c b/iconv/gconv.c
index 06e212b2cb..19f95622a2 100644
--- a/iconv/gconv.c
+++ b/iconv/gconv.c
@@ -46,8 +46,8 @@ __gconv (__gconv_t cd, const unsigned char **inbuf,
   if (inbuf == NULL || *inbuf == NULL)
     /* We just flush.  */
     result = DL_CALL_FCT (cd->__steps->__fct,
-			   (cd->__steps, cd->__data, NULL, NULL,
-			    irreversible, 1, 0));
+			  (cd->__steps, cd->__data, NULL, NULL,
+			   cd->__data[0].__outbuf, irreversible, 1, 0));
   else
     {
       const unsigned char *last_start;
@@ -58,8 +58,8 @@ __gconv (__gconv_t cd, const unsigned char **inbuf,
 	{
 	  last_start = *inbuf;
 	  result = DL_CALL_FCT (cd->__steps->__fct,
-				 (cd->__steps, cd->__data, inbuf, inbufend,
-				  irreversible, 0, 0));
+				(cd->__steps, cd->__data, inbuf, inbufend,
+				 cd->__data[0].__outbuf, irreversible, 0, 0));
 	}
       while (result == __GCONV_EMPTY_INPUT && last_start != *inbuf
 	     && *inbuf + cd->__steps->__min_needed_from <= inbufend);
diff --git a/iconv/gconv.h b/iconv/gconv.h
index 1821844952..5717ddbea0 100644
--- a/iconv/gconv.h
+++ b/iconv/gconv.h
@@ -62,18 +62,52 @@ enum
 struct __gconv_step;
 struct __gconv_step_data;
 struct __gconv_loaded_object;
+struct __gconv_trans_data;
 
 
 /* Type of a conversion function.  */
 typedef int (*__gconv_fct) (struct __gconv_step *, struct __gconv_step_data *,
 			    __const unsigned char **, __const unsigned char *,
-			    size_t *, int, int);
+			    unsigned char *, size_t *, int, int);
 
 /* Constructor and destructor for local data for conversion step.  */
 typedef int (*__gconv_init_fct) (struct __gconv_step *);
 typedef void (*__gconv_end_fct) (struct __gconv_step *);
 
 
+/* Type of a transliteration/transscription function.  */
+typedef int (*__gconv_trans_fct) (struct __gconv_step *step,
+				  struct __gconv_step_data *step_data,
+				  __const unsigned char *,
+				  __const unsigned char **,
+				  __const unsigned char *, unsigned char *,
+				  unsigned char **, unsigned char *, size_t *);
+
+/* Function to call to provide transliteration module with context.  */
+typedef int (*__gconv_trans_context_fct) (struct __gconv_trans_data *data,
+					  __const unsigned char *,
+					  __const unsigned char *,
+					  __const unsigned char *,
+					  unsigned char *, unsigned char *,
+					  unsigned char *);
+
+/* Function to query module about supported encoded character sets.  */
+typedef int (*__gconv_trans_query_fct) (__const char **, size_t *);
+
+/* Constructor and destructor for local data for transliteration.  */
+typedef int (*__gconv_trans_init_fct) (void **, const char *);
+typedef void (*__gconv_trans_end_fct) (void *);
+
+struct __gconv_trans_data
+{
+  /* Transliteration/Transscription function.  */
+  __gconv_trans_fct __trans_fct;
+  __gconv_trans_context_fct __trans_context_fct;
+  __gconv_trans_end_fct __trans_end_fct;
+  void *__data;
+};
+
+
 /* Description of a conversion step.  */
 struct __gconv_step
 {
@@ -124,6 +158,9 @@ struct __gconv_step_data
   __mbstate_t *__statep;
   __mbstate_t __state;	/* This element must not be used directly by
 			   any module; always use STATEP!  */
+
+  /* Transliteration information.  */
+  struct __gconv_trans_data __trans;
 };
 
 
diff --git a/iconv/gconv_int.h b/iconv/gconv_int.h
index 01cebe72c4..87287d7b26 100644
--- a/iconv/gconv_int.h
+++ b/iconv/gconv_int.h
@@ -129,8 +129,8 @@ extern struct gconv_module *__gconv_modules_db;
 
 
 /* Return in *HANDLE decriptor for transformation from FROMSET to TOSET.  */
-extern int __gconv_open (const char *__toset, const char *__fromset,
-			 __gconv_t *__handle, int flags)
+extern int __gconv_open (const char *toset, const char *fromset,
+			 __gconv_t *handle, int flags)
      internal_function;
 
 /* Free resources associated with transformation descriptor CD.  */
@@ -141,55 +141,65 @@ extern int __gconv_close (__gconv_t cd)
    according to rules described by CD and place up to *OUTBYTESLEFT
    bytes in buffer starting at *OUTBUF.  Return number of non-identical
    conversions in *IRREVERSIBLE if this pointer is not null.  */
-extern int __gconv (__gconv_t __cd, const unsigned char **__inbuf,
-		    const unsigned char *inbufend, unsigned char **__outbuf,
+extern int __gconv (__gconv_t cd, const unsigned char **inbuf,
+		    const unsigned char *inbufend, unsigned char **outbuf,
 		    unsigned char *outbufend, size_t *irreversible)
      internal_function;
 
 /* Return in *HANDLE a pointer to an array with *NSTEPS elements describing
    the single steps necessary for transformation from FROMSET to TOSET.  */
-extern int __gconv_find_transform (const char *__toset, const char *__fromset,
-				   struct __gconv_step **__handle,
-				   size_t *__nsteps, int flags)
+extern int __gconv_find_transform (const char *toset, const char *fromset,
+				   struct __gconv_step **handle,
+				   size_t *nsteps, int flags)
      internal_function;
 
 /* Read all the configuration data and cache it.  */
 extern void __gconv_read_conf (void);
 
 /* Comparison function to search alias.  */
-extern int __gconv_alias_compare (const void *__p1, const void *__p2);
+extern int __gconv_alias_compare (const void *p1, const void *p2);
 
 /* Clear reference to transformation step implementations which might
    cause the code to be unloaded.  */
-extern int __gconv_close_transform (struct __gconv_step *__steps,
-				    size_t __nsteps)
+extern int __gconv_close_transform (struct __gconv_step *steps,
+				    size_t nsteps)
      internal_function;
 
 /* Load shared object named by NAME.  If already loaded increment reference
    count.  */
-extern struct __gconv_loaded_object *__gconv_find_shlib (const char *__name)
+extern struct __gconv_loaded_object *__gconv_find_shlib (const char *name)
      internal_function;
 
 /* Release shared object.  If no further reference is available unload
    the object.  */
-extern int __gconv_release_shlib (struct __gconv_loaded_object *__handle)
+extern int __gconv_release_shlib (struct __gconv_loaded_object *handle)
      internal_function;
 
 /* Fill STEP with information about builtin module with NAME.  */
-extern void __gconv_get_builtin_trans (const char *__name,
-				       struct __gconv_step *__step)
+extern void __gconv_get_builtin_trans (const char *name,
+				       struct __gconv_step *step)
      internal_function;
 
+/* Transliteration using the locale's data.  */
+extern int gconv_transliterate (struct __gconv_step *step,
+				struct __gconv_step_data *step_data,
+				__const unsigned char *inbufstart,
+				__const unsigned char **inbufp,
+				__const unsigned char *inbufend,
+				unsigned char *outbufstart,
+				unsigned char **outbufp,
+				unsigned char *outbufend,
+				size_t *irreversible);
 
 
 /* Builtin transformations.  */
 #ifdef _LIBC
 # define __BUILTIN_TRANS(Name) \
-  extern int Name (struct __gconv_step *__step,				      \
-		   struct __gconv_step_data *__data,			      \
-		   const unsigned char **__inbuf,			      \
-		   const unsigned char *__inbufend, size_t *__written,	      \
-		   int __do_flush, int __consume_incomplete)
+  extern int Name (struct __gconv_step *step,				      \
+		   struct __gconv_step_data *data,			      \
+		   const unsigned char **inbuf,				      \
+		   const unsigned char *inbufend, unsigned char *outbufstart, \
+		   size_t *irreversible, int do_flush, int consume_incomplete)
 
 __BUILTIN_TRANS (__gconv_transform_ascii_internal);
 __BUILTIN_TRANS (__gconv_transform_internal_ascii);
diff --git a/iconv/gconv_open.c b/iconv/gconv_open.c
index da00b1abbd..984ca9dc5d 100644
--- a/iconv/gconv_open.c
+++ b/iconv/gconv_open.c
@@ -36,25 +36,65 @@ __gconv_open (const char *toset, const char *fromset, __gconv_t *handle,
   size_t cnt = 0;
   int res;
   int conv_flags = 0;
-  const char *runp;
+  const char *errhand;
 
-  /* Find out whether "IGNORE" is part of the options in the `toset'
-     name.  If yes, remove the string and remember this in the flag.  */
-  runp = __strchrnul (__strchrnul (toset, '/'), '/');
-  if (strcmp (runp, "IGNORE") == 0)
+  /* Find out whether any error handling method is specified.  */
+  errhand = strchr (toset, '/');
+  if (errhand != NULL)
+    errhand = strchr (errhand + 1, '/');
+  if (__builtin_expect (errhand != NULL, 1))
     {
-      /* Found it.  This means we should ignore conversion errors.  */
-      char *newtoset = (char *) alloca (runp - toset + 1);
+      if (errhand[1] == '\0')
+	errhand = NULL;
+      else
+	{
+	  /* Make copy without the error handling description.  */
+	  char *newtoset = (char *) alloca (errhand - toset + 1);
 
-      newtoset[runp - toset] = '\0';
-      toset = memcpy (newtoset, toset, runp - toset);
+	  newtoset[errhand - toset] = '\0';
+	  toset = memcpy (newtoset, toset, errhand - toset);
 
-      flags = __GCONV_IGNORE_ERRORS;
+	  flags = __GCONV_IGNORE_ERRORS;
+
+	  if (strcasecmp (errhand, "IGNORE") == 0)
+	    {
+	      /* Found it.  This means we should ignore conversion errors.  */
+	      flags = __GCONV_IGNORE_ERRORS;
+	      errhand = NULL;
+	    }
+	}
     }
 
   res = __gconv_find_transform (toset, fromset, &steps, &nsteps, flags);
   if (res == __GCONV_OK)
     {
+      const char **csnames = NULL;
+      size_t ncsnames = 0;
+      __gconv_trans_fct trans_fct = NULL;
+      __gconv_trans_context_fct trans_context_fct = NULL;
+      __gconv_trans_init_fct trans_init_fct = NULL;
+      __gconv_trans_end_fct trans_end_fct = NULL;
+
+      if (errhand != NULL)
+	{
+	  /* Find the appropriate transliteration handling.  */
+	  if (strcasecmp (errhand, "TRANSLIT") == 0)
+	    {
+	      /* It's the builtin transliteration handling.  We only
+                 suport for it working on the internal encoding.  */
+	      static const char *internal_trans_names[1] = { "INTERNAL" };
+
+	      csnames = internal_trans_names;
+	      ncsnames = 1;
+	      trans_fct = gconv_transliterate;
+	      /* No context, init, or end function.  */
+	    }
+	  else if (strcasecmp (errhand, "WORK AROUND A GCC BUG") == 0)
+	    {
+	      trans_init_fct = (__gconv_trans_init_fct) 1;
+	    }
+	}
+
       /* Allocate room for handle.  */
       result = (__gconv_t) malloc (sizeof (struct __gconv_info)
 				   + (nsteps
@@ -63,6 +103,8 @@ __gconv_open (const char *toset, const char *fromset, __gconv_t *handle,
 	res = __GCONV_NOMEM;
       else
 	{
+	  size_t n;
+
 	  /* Remember the list of steps.  */
 	  result->__steps = steps;
 	  result->__nsteps = nsteps;
@@ -105,6 +147,26 @@ __gconv_open (const char *toset, const char *fromset, __gconv_t *handle,
 		}
 	      result->__data[cnt].__outbufend =
 		result->__data[cnt].__outbuf + size;
+
+	      /* Now see whether we can use the transliteration module
+		 for this step.  */
+	      for (n = 0; n < ncsnames; ++n)
+		if (strcasecmp (steps[cnt].__from_name, csnames[n]) == 0)
+		  {
+		    /* Match!  Now try the initializer.  */
+		    if (trans_init_fct == NULL
+			|| (trans_init_fct (&result->__data[cnt].__trans.__data,
+					    steps[cnt].__to_name)
+			    == __GCONV_OK))
+		      {
+			result->__data[cnt].__trans.__trans_fct = trans_fct;
+			result->__data[cnt].__trans.__trans_context_fct =
+			  trans_context_fct;
+			result->__data[cnt].__trans.__trans_end_fct =
+			  trans_end_fct;
+		      }
+		    break;
+		  }
 	    }
 
 	  /* Now handle the last entry.  */
@@ -116,6 +178,26 @@ __gconv_open (const char *toset, const char *fromset, __gconv_t *handle,
 	  result->__data[cnt].__internal_use = 0;
 #endif
 	  result->__data[cnt].__statep = &result->__data[cnt].__state;
+
+	  /* Now see whether we can use the transliteration module
+	     for this step.  */
+	  for (n = 0; n < ncsnames; ++n)
+	    if (strcasecmp (steps[cnt].__from_name, csnames[n]) == 0)
+	      {
+		/* Match!  Now try the initializer.  */
+		if (trans_init_fct == NULL
+		    || trans_init_fct (&result->__data[cnt].__trans.__data,
+				       steps[cnt].__to_name)
+		    == __GCONV_OK)
+		  {
+		    result->__data[cnt].__trans.__trans_fct = trans_fct;
+		    result->__data[cnt].__trans.__trans_context_fct =
+		      trans_context_fct;
+		    result->__data[cnt].__trans.__trans_end_fct =
+		      trans_end_fct;
+		  }
+		break;
+	      }
 	}
 
       if (res != __GCONV_OK)
diff --git a/iconv/gconv_simple.c b/iconv/gconv_simple.c
index 4b7004caa6..188fc04c0e 100644
--- a/iconv/gconv_simple.c
+++ b/iconv/gconv_simple.c
@@ -19,6 +19,7 @@
    Boston, MA 02111-1307, USA.  */
 
 #include <byteswap.h>
+#include <dlfcn.h>
 #include <endian.h>
 #include <errno.h>
 #include <gconv.h>
@@ -62,9 +63,10 @@ static const unsigned char encoding_byte[] =
 
 
 static inline int
-internal_ucs4_loop (const unsigned char **inptrp, const unsigned char *inend,
+internal_ucs4_loop (struct __gconv_step *step,
+		    struct __gconv_step_data *step_data,
+		    const unsigned char **inptrp, const unsigned char *inend,
 		    unsigned char **outptrp, unsigned char *outend,
-		    mbstate_t *state, int flags, void *data,
 		    size_t *irreversible)
 {
   const unsigned char *inptr = *inptrp;
@@ -102,10 +104,11 @@ internal_ucs4_loop (const unsigned char **inptrp, const unsigned char *inend,
 
 #ifndef _STRING_ARCH_unaligned
 static inline int
-internal_ucs4_loop_unaligned (const unsigned char **inptrp,
+internal_ucs4_loop_unaligned (struct __gconv_step *step,
+			      struct __gconv_step_data *step_data,
+			      const unsigned char **inptrp,
 			      const unsigned char *inend,
 			      unsigned char **outptrp, unsigned char *outend,
-			      mbstate_t *state, int flags, void *data,
 			      size_t *irreversible)
 {
   const unsigned char *inptr = *inptrp;
@@ -149,12 +152,14 @@ internal_ucs4_loop_unaligned (const unsigned char **inptrp,
 
 
 static inline int
-internal_ucs4_loop_single (const unsigned char **inptrp,
+internal_ucs4_loop_single (struct __gconv_step *step,
+			   struct __gconv_step_data *step_data,
+			   const unsigned char **inptrp,
 			   const unsigned char *inend,
 			   unsigned char **outptrp, unsigned char *outend,
-			   mbstate_t *state, int flags, void *data,
 			   size_t *irreversible)
 {
+  mbstate_t *state = step_data->__statep;
   size_t cnt = state->__count & 7;
 
   while (*inptrp < inend && cnt < 4)
@@ -205,11 +210,13 @@ internal_ucs4_loop_single (const unsigned char **inptrp,
 
 
 static inline int
-ucs4_internal_loop (const unsigned char **inptrp, const unsigned char *inend,
+ucs4_internal_loop (struct __gconv_step *step,
+		    struct __gconv_step_data *step_data,
+		    const unsigned char **inptrp, const unsigned char *inend,
 		    unsigned char **outptrp, unsigned char *outend,
-		    mbstate_t *state, int flags, void *data,
 		    size_t *irreversible)
 {
+  int flags = step_data->__flags;
   const unsigned char *inptr = *inptrp;
   unsigned char *outptr = *outptrp;
   size_t n_convert = MIN (inend - inptr, outend - outptr) / 4;
@@ -228,6 +235,10 @@ ucs4_internal_loop (const unsigned char **inptrp, const unsigned char *inend,
 
       if (__builtin_expect (inval, 0) > 0x7fffffff)
 	{
+	  /* The value is too large.  We don't try transliteration here since
+	     this is not an error because of the lack of possibilities to
+	     represent the result.  This is a genuine bug in the input since
+	     UCS4 does not allow such values.  */
 	  if (flags & __GCONV_IGNORE_ERRORS)
 	    {
 	      /* Just ignore this character.  */
@@ -259,23 +270,28 @@ ucs4_internal_loop (const unsigned char **inptrp, const unsigned char *inend,
 
 #ifndef _STRING_ARCH_unaligned
 static inline int
-ucs4_internal_loop_unaligned (const unsigned char **inptrp,
+ucs4_internal_loop_unaligned (struct __gconv_step *step,
+			      struct __gconv_step_data *step_data,
+			      const unsigned char **inptrp,
 			      const unsigned char *inend,
 			      unsigned char **outptrp, unsigned char *outend,
-			      mbstate_t *state, int flags, void *data,
 			      size_t *irreversible)
 {
+  int flags = step_data->__flags;
   const unsigned char *inptr = *inptrp;
   unsigned char *outptr = *outptrp;
   size_t n_convert = MIN (inend - inptr, outend - outptr) / 4;
   int result;
   size_t cnt;
 
-  for (cnt = 0; cnt < n_convert; ++cnt, inptr += 4, outptr += 4)
+  for (cnt = 0; cnt < n_convert; ++cnt, inptr += 4)
     {
       if (__builtin_expect (inptr[0], 0) > 0x80)
 	{
-	  /* The value is too large.  */
+	  /* The value is too large.  We don't try transliteration here since
+	     this is not an error because of the lack of possibilities to
+	     represent the result.  This is a genuine bug in the input since
+	     UCS4 does not allow such values.  */
 	  if (flags & __GCONV_IGNORE_ERRORS)
 	    {
 	      /* Just ignore this character.  */
@@ -299,6 +315,7 @@ ucs4_internal_loop_unaligned (const unsigned char **inptrp,
       outptr[2] = inptr[2];
       outptr[3] = inptr[3];
 # endif
+      outptr += 4;
     }
 
   *inptrp = inptr;
@@ -318,12 +335,15 @@ ucs4_internal_loop_unaligned (const unsigned char **inptrp,
 
 
 static inline int
-ucs4_internal_loop_single (const unsigned char **inptrp,
+ucs4_internal_loop_single (struct __gconv_step *step,
+			   struct __gconv_step_data *step_data,
+			   const unsigned char **inptrp,
 			   const unsigned char *inend,
 			   unsigned char **outptrp, unsigned char *outend,
-			   mbstate_t *state, int flags, void *data,
 			   size_t *irreversible)
 {
+  mbstate_t *state = step_data->__statep;
+  int flags = step_data->__flags;
   size_t cnt = state->__count & 7;
 
   while (*inptrp < inend && cnt < 4)
@@ -341,7 +361,10 @@ ucs4_internal_loop_single (const unsigned char **inptrp,
   if (__builtin_expect (((unsigned char *) state->__value.__wchb)[0], 0)
       > 0x80)
     {
-      /* The value is too large.  */
+      /* The value is too large.  We don't try transliteration here since
+	 this is not an error because of the lack of possibilities to
+	 represent the result.  This is a genuine bug in the input since
+	 UCS4 does not allow such values.  */
       if (!(flags & __GCONV_IGNORE_ERRORS))
 	{
 	  *inptrp -= cnt - (state->__count & 7);
@@ -386,9 +409,10 @@ ucs4_internal_loop_single (const unsigned char **inptrp,
 
 
 static inline int
-internal_ucs4le_loop (const unsigned char **inptrp, const unsigned char *inend,
+internal_ucs4le_loop (struct __gconv_step *step,
+		      struct __gconv_step_data *step_data,
+		      const unsigned char **inptrp, const unsigned char *inend,
 		      unsigned char **outptrp, unsigned char *outend,
-		      mbstate_t *state, int flags, void *data,
 		      size_t *irreversible)
 {
   const unsigned char *inptr = *inptrp;
@@ -426,10 +450,11 @@ internal_ucs4le_loop (const unsigned char **inptrp, const unsigned char *inend,
 
 #ifndef _STRING_ARCH_unaligned
 static inline int
-internal_ucs4le_loop_unaligned (const unsigned char **inptrp,
+internal_ucs4le_loop_unaligned (struct __gconv_step *step,
+				struct __gconv_step_data *step_data,
+				const unsigned char **inptrp,
 				const unsigned char *inend,
 				unsigned char **outptrp, unsigned char *outend,
-				mbstate_t *state, int flags, void *data,
 				size_t *irreversible)
 {
   const unsigned char *inptr = *inptrp;
@@ -473,12 +498,14 @@ internal_ucs4le_loop_unaligned (const unsigned char **inptrp,
 
 
 static inline int
-internal_ucs4le_loop_single (const unsigned char **inptrp,
+internal_ucs4le_loop_single (struct __gconv_step *step,
+			     struct __gconv_step_data *step_data,
+			     const unsigned char **inptrp,
 			     const unsigned char *inend,
 			     unsigned char **outptrp, unsigned char *outend,
-			     mbstate_t *state, int flags, void *data,
 			     size_t *irreversible)
 {
+  mbstate_t *state = step_data->__statep;
   size_t cnt = state->__count & 7;
 
   while (*inptrp < inend && cnt < 4)
@@ -526,11 +553,13 @@ internal_ucs4le_loop_single (const unsigned char **inptrp,
 
 
 static inline int
-ucs4le_internal_loop (const unsigned char **inptrp, const unsigned char *inend,
+ucs4le_internal_loop (struct __gconv_step *step,
+		      struct __gconv_step_data *step_data,
+		      const unsigned char **inptrp, const unsigned char *inend,
 		      unsigned char **outptrp, unsigned char *outend,
-		      mbstate_t *state, int flags, void *data,
 		      size_t *irreversible)
 {
+  int flags = step_data->__flags;
   const unsigned char *inptr = *inptrp;
   unsigned char *outptr = *outptrp;
   size_t n_convert = MIN (inend - inptr, outend - outptr) / 4;
@@ -549,6 +578,10 @@ ucs4le_internal_loop (const unsigned char **inptrp, const unsigned char *inend,
 
       if (__builtin_expect (inval, 0) > 0x7fffffff)
 	{
+	  /* The value is too large.  We don't try transliteration here since
+	     this is not an error because of the lack of possibilities to
+	     represent the result.  This is a genuine bug in the input since
+	     UCS4 does not allow such values.  */
 	  if (flags & __GCONV_IGNORE_ERRORS)
 	    {
 	      /* Just ignore this character.  */
@@ -578,12 +611,14 @@ ucs4le_internal_loop (const unsigned char **inptrp, const unsigned char *inend,
 
 #ifndef _STRING_ARCH_unaligned
 static inline int
-ucs4le_internal_loop_unaligned (const unsigned char **inptrp,
+ucs4le_internal_loop_unaligned (struct __gconv_step *step,
+				struct __gconv_step_data *step_data,
+				const unsigned char **inptrp,
 				const unsigned char *inend,
 				unsigned char **outptrp, unsigned char *outend,
-				mbstate_t *state, int flags, void *data,
 				size_t *irreversible)
 {
+  int flags = step_data->__flags;
   const unsigned char *inptr = *inptrp;
   unsigned char *outptr = *outptrp;
   size_t n_convert = MIN (inend - inptr, outend - outptr) / 4;
@@ -594,7 +629,10 @@ ucs4le_internal_loop_unaligned (const unsigned char **inptrp,
     {
       if (__builtin_expect (inptr[3], 0) > 0x80)
 	{
-	  /* The value is too large.  */
+	  /* The value is too large.  We don't try transliteration here since
+	     this is not an error because of the lack of possibilities to
+	     represent the result.  This is a genuine bug in the input since
+	     UCS4 does not allow such values.  */
 	  if (flags & __GCONV_IGNORE_ERRORS)
 	    {
 	      /* Just ignore this character.  */
@@ -639,12 +677,15 @@ ucs4le_internal_loop_unaligned (const unsigned char **inptrp,
 
 
 static inline int
-ucs4le_internal_loop_single (const unsigned char **inptrp,
+ucs4le_internal_loop_single (struct __gconv_step *step,
+			     struct __gconv_step_data *step_data,
+			     const unsigned char **inptrp,
 			     const unsigned char *inend,
 			     unsigned char **outptrp, unsigned char *outend,
-			     mbstate_t *state, int flags, void *data,
 			     size_t *irreversible)
 {
+  mbstate_t *state = step_data->__statep;
+  int flags = step_data->__flags;
   size_t cnt = state->__count & 7;
 
   while (*inptrp < inend && cnt < 4)
@@ -662,7 +703,10 @@ ucs4le_internal_loop_single (const unsigned char **inptrp,
   if (__builtin_expect (((unsigned char *) state->__value.__wchb)[3], 0)
       > 0x80)
     {
-      /* The value is too large.  */
+      /* The value is too large.  We don't try transliteration here since
+	 this is not an error because of the lack of possibilities to
+	 represent the result.  This is a genuine bug in the input since
+	 UCS4 does not allow such values.  */
       if (!(flags & __GCONV_IGNORE_ERRORS))
 	return __GCONV_ILLEGAL_INPUT;
     }
@@ -710,6 +754,10 @@ ucs4le_internal_loop_single (const unsigned char **inptrp,
   {									      \
     if (__builtin_expect (*inptr, 0) > '\x7f')				      \
       {									      \
+	/* The value is too large.  We don't try transliteration here since   \
+	   this is not an error because of the lack of possibilities to	      \
+	   represent the result.  This is a genuine bug in the input since    \
+	   ASCII does not allow such values.  */			      \
 	if (! ignore_errors_p ())					      \
 	  {								      \
 	    /* This is no correct ANSI_X3.4-1968 character.  */		      \
@@ -718,13 +766,14 @@ ucs4le_internal_loop_single (const unsigned char **inptrp,
 	  }								      \
 									      \
 	++*irreversible;						      \
-	++inptr; 							      \
+	++inptr;							      \
       }									      \
     else								      \
       /* It's an one byte sequence.  */					      \
       /* XXX unaligned.  */						      \
       *((uint32_t *) outptr)++ = *inptr++;				      \
   }
+#define LOOP_NEED_FLAGS
 #include <iconv/loop.c>
 #include <iconv/skeleton.c>
 
@@ -740,6 +789,13 @@ ucs4le_internal_loop_single (const unsigned char **inptrp,
 #define FUNCTION_NAME		__gconv_transform_internal_ascii
 #define ONE_DIRECTION		1
 
+extern int FUNCTION_NAME (struct __gconv_step *step,
+			  struct __gconv_step_data *data,
+			  const unsigned char **inptrp,
+			  const unsigned char *inend,
+			  unsigned char *outbufstart, size_t *irreversible,
+			  int do_flush, int consume_incomplete);
+
 #define MIN_NEEDED_INPUT	MIN_NEEDED_FROM
 #define MIN_NEEDED_OUTPUT	MIN_NEEDED_TO
 #define LOOPFCT			FROM_LOOP
@@ -748,20 +804,31 @@ ucs4le_internal_loop_single (const unsigned char **inptrp,
     /* XXX unaligned.  */						      \
     if (__builtin_expect (*((uint32_t *) inptr), 0) > 0x7f)		      \
       {									      \
-	if (! ignore_errors_p ())					      \
+	if (step_data->__trans.__trans_fct != NULL)			      \
+	  {								      \
+	    result = DL_CALL_FCT (step_data->__trans.__trans_fct,	      \
+				  (step, step_data, *inptrp, &inptr, inend,   \
+				   *outptrp, &outptr, outend, irreversible)); \
+	    if (result != __GCONV_OK)					      \
+	      break;							      \
+	  }								      \
+	else if (! ignore_errors_p ())					      \
 	  {								      \
 	    /* This is no correct ANSI_X3.4-1968 character.  */		      \
 	    result = __GCONV_ILLEGAL_INPUT;				      \
 	    break;							      \
 	  }								      \
-									      \
-	++*irreversible;						      \
-	inptr += 4; 							      \
+	else								      \
+	  {								      \
+	    ++*irreversible;						      \
+	    inptr += 4; 						      \
+	  }								      \
       }									      \
     else								      \
       /* It's an one byte sequence.  */					      \
       *outptr++ = *((uint32_t *) inptr)++;				      \
   }
+#define LOOP_NEED_FLAGS
 #include <iconv/loop.c>
 #include <iconv/skeleton.c>
 
@@ -916,7 +983,7 @@ ucs4le_internal_loop_single (const unsigned char **inptrp,
 	     continue;							      \
 	  }								      \
 									      \
-	if (NEED_LENGTH_TEST && __builtin_expect (inptr + cnt > inend, 0))    \
+	if (__builtin_expect (inptr + cnt > inend, 0))			    \
 	  {								      \
 	    /* We don't have enough input.  But before we report that check   \
 	       that all the bytes are correct.  */			      \
@@ -979,6 +1046,7 @@ ucs4le_internal_loop_single (const unsigned char **inptrp,
     /* Now adjust the pointers and store the result.  */		      \
     *((uint32_t *) outptr)++ = ch;					      \
   }
+#define LOOP_NEED_FLAGS
 
 #define STORE_REST \
   {									      \
@@ -1125,18 +1193,29 @@ ucs4le_internal_loop_single (const unsigned char **inptrp,
   {									      \
     if (__builtin_expect (*((uint32_t *) inptr), 0) >= 0x10000)		      \
       {									      \
-	if (! ignore_errors_p ())					      \
+	if (step_data->__trans.__trans_fct != NULL)			      \
+	  {								      \
+	    result = DL_CALL_FCT (step_data->__trans.__trans_fct,	      \
+				  (step, step_data, *inptrp, &inptr, inend,   \
+				   *outptrp, &outptr, outend, irreversible)); \
+	    if (result != __GCONV_OK)					      \
+	      break;							      \
+	  }								      \
+	else if (! ignore_errors_p ())					      \
 	  {								      \
 	    result = __GCONV_ILLEGAL_INPUT;				      \
 	    break;							      \
 	  }								      \
-									      \
-	inptr += 4;							      \
-	++*irreversible;						      \
+	else								      \
+	  {								      \
+	    inptr += 4;							      \
+	    ++*irreversible;						      \
+	  }								      \
       }									      \
     else 								      \
       *((uint16_t *) outptr)++ = *((uint32_t *) inptr)++;		      \
   }
+#define LOOP_NEED_FLAGS
 #include <iconv/loop.c>
 #include <iconv/skeleton.c>
 
@@ -1181,17 +1260,29 @@ ucs4le_internal_loop_single (const unsigned char **inptrp,
     uint32_t val = *((uint32_t *) inptr);				      \
     if (__builtin_expect (val, 0) >= 0x10000)				      \
       {									      \
-	if (! ignore_errors_p ())					      \
+	if (step_data->__trans.__trans_fct != NULL)			      \
+	  {								      \
+	    result = DL_CALL_FCT (step_data->__trans.__trans_fct,	      \
+				  (step, step_data, *inptrp, &inptr, inend,   \
+				   *outptrp, &outptr, outend, irreversible)); \
+	    if (result != __GCONV_OK)					      \
+	      break;							      \
+	  }								      \
+	else if (! ignore_errors_p ())					      \
 	  {								      \
 	    result = __GCONV_ILLEGAL_INPUT;				      \
 	    break;							      \
 	  }								      \
-									      \
-	inptr += 4;							      \
-	++*irreversible;						      \
+	else								      \
+	  {								      \
+	    inptr += 4;							      \
+	    ++*irreversible;						      \
+	  }								      \
+	continue;							      \
       }									      \
     *((uint16_t *) outptr)++ = bswap_16 (val);				      \
     inptr += 4;								      \
   }
+#define LOOP_NEED_FLAGS
 #include <iconv/loop.c>
 #include <iconv/skeleton.c>
diff --git a/iconv/gconv_trans.c b/iconv/gconv_trans.c
new file mode 100644
index 0000000000..11c542e744
--- /dev/null
+++ b/iconv/gconv_trans.c
@@ -0,0 +1,50 @@
+/* Transliteration using the locale's data.
+   Copyright (C) 2000 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+   Contributed by Ulrich Drepper <drepper@cygnus.com>, 2000.
+
+   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 <stdint.h>
+
+#include "gconv_int.h"
+#include "../locale/localeinfo.h"
+
+
+int
+gconv_transliterate (struct __gconv_step *step,
+		     struct __gconv_step_data *step_data,
+		     __const unsigned char *inbufstart,
+		     __const unsigned char **inbufp,
+		     __const unsigned char *inbufend,
+		     unsigned char *outbufstart,
+		     unsigned char **outbufp, unsigned char *outbufend,
+		     size_t *irreversible)
+{
+  /* Find out about the locale's transliteration.  */
+  uint_fast32_t size = _NL_CURRENT_WORD (LC_CTYPE,
+					 _NL_CTYPE_TRANSLIT_HASH_SIZE);
+  uint_fast32_t layers = _NL_CURRENT_WORD (LC_CTYPE,
+					   _NL_CTYPE_TRANSLIT_HASH_LAYERS);
+
+  /* If there is no transliteration information in the locale don't do
+     anything and return the error.  */
+  if (size == 0)
+    return __GCONV_ILLEGAL_INPUT;
+
+  /* XXX For now we don't do anything.  */
+  return __GCONV_ILLEGAL_INPUT;
+}
diff --git a/iconv/loop.c b/iconv/loop.c
index c01e52040e..ebbc1362b3 100644
--- a/iconv/loop.c
+++ b/iconv/loop.c
@@ -175,88 +175,57 @@
 
 /* The function returns the status, as defined in gconv.h.  */
 static inline int
-FCTNAME (LOOPFCT) (const unsigned char **inptrp, const unsigned char *inend,
+FCTNAME (LOOPFCT) (struct __gconv_step *step,
+		   struct __gconv_step_data *step_data,
+		   const unsigned char **inptrp, const unsigned char *inend,
 		   unsigned char **outptrp, unsigned char *outend,
-		   mbstate_t *state, int flags, void *data,
 		   size_t *irreversible EXTRA_LOOP_DECLS)
 {
-  int result = __GCONV_OK;
+#ifdef LOOP_NEED_STATE
+  mbstate_t *state = step_data->__statep;
+#endif
+#ifdef LOOP_NEED_FLAGS
+  int flags = step_data->__flags;
+#endif
+#ifdef LOOP_NEED_DATA
+  void *data = step->__data;
+#endif
+  int result = __GCONV_EMPTY_INPUT;
   const unsigned char *inptr = *inptrp;
   unsigned char *outptr = *outptrp;
 
-  /* We run one loop where we avoid checks for underflow/overflow of the
-     buffers to speed up the conversion a bit.  */
-  size_t min_in_rounds = (inend - inptr) / MAX_NEEDED_INPUT;
-  size_t min_out_rounds = (outend - outptr) / MAX_NEEDED_OUTPUT;
-  size_t min_rounds = MIN (min_in_rounds, min_out_rounds);
-
 #ifdef INIT_PARAMS
   INIT_PARAMS;
 #endif
 
-#undef NEED_LENGTH_TEST
-#define NEED_LENGTH_TEST	0
-  while (min_rounds-- > 0)
+  while (inptr != inend)
     {
-      /* Here comes the body the user provides.  It can stop with RESULT
-	 set to GCONV_INCOMPLETE_INPUT (if the size of the input characters
-	 vary in size), GCONV_ILLEGAL_INPUT, or GCONV_FULL_OUTPUT (if the
-	 output characters vary in size.  */
-      BODY
-    }
-
-  if (result == __GCONV_OK)
-    {
-#if MIN_NEEDED_INPUT == MAX_NEEDED_INPUT \
-    && MIN_NEEDED_OUTPUT == MAX_NEEDED_OUTPUT
-      /* We don't need to start another loop since we were able to determine
-	 the maximal number of characters to copy in advance.  What remains
-	 to be determined is the status.  */
-      if (inptr == inend)
-	/* No more input.  */
-	result = __GCONV_EMPTY_INPUT;
-      else if ((MIN_NEEDED_OUTPUT != 1 && outptr + MIN_NEEDED_OUTPUT > outend)
-	       || (MIN_NEEDED_OUTPUT == 1 && outptr >= outend))
-	/* Overflow in the output buffer.  */
-	result = __GCONV_FULL_OUTPUT;
-      else
-	/* We have something left in the input buffer.  */
-	result = __GCONV_INCOMPLETE_INPUT;
-#else
-      result = __GCONV_EMPTY_INPUT;
-
-# undef NEED_LENGTH_TEST
-# define NEED_LENGTH_TEST	1
-      while (inptr != inend)
+      /* `if' cases for MIN_NEEDED_OUTPUT ==/!= 1 is made to help the
+	 compiler generating better code.  It will optimized away
+	 since MIN_NEEDED_OUTPUT is always a constant.  */
+      if ((MIN_NEEDED_OUTPUT != 1
+	   && __builtin_expect (outptr + MIN_NEEDED_OUTPUT > outend, 0))
+	  || (MIN_NEEDED_OUTPUT == 1
+	      && __builtin_expect (outptr >= outend, 0)))
+	{
+	  /* Overflow in the output buffer.  */
+	  result = __GCONV_FULL_OUTPUT;
+	  break;
+	}
+      if (MIN_NEEDED_INPUT > 1
+	  && __builtin_expect (inptr + MIN_NEEDED_INPUT > inend, 0))
 	{
-	  /* `if' cases for MIN_NEEDED_OUTPUT ==/!= 1 is made to help the
-	     compiler generating better code.  It will optimized away
-	     since MIN_NEEDED_OUTPUT is always a constant.  */
-	  if ((MIN_NEEDED_OUTPUT != 1
-	       && __builtin_expect (outptr + MIN_NEEDED_OUTPUT > outend, 0))
-	      || (MIN_NEEDED_OUTPUT == 1
-		  && __builtin_expect (outptr >= outend, 0)))
-	    {
-	      /* Overflow in the output buffer.  */
-	      result = __GCONV_FULL_OUTPUT;
-	      break;
-	    }
-	  if (MIN_NEEDED_INPUT > 1
-	      && __builtin_expect (inptr + MIN_NEEDED_INPUT > inend, 0))
-	    {
-	      /* We don't have enough input for another complete input
-		 character.  */
-	      result = __GCONV_INCOMPLETE_INPUT;
-	      break;
-	    }
-
-	  /* Here comes the body the user provides.  It can stop with
-	     RESULT set to GCONV_INCOMPLETE_INPUT (if the size of the
-	     input characters vary in size), GCONV_ILLEGAL_INPUT, or
-	     GCONV_FULL_OUTPUT (if the output characters vary in size).  */
-	  BODY
+	  /* We don't have enough input for another complete input
+	     character.  */
+	  result = __GCONV_INCOMPLETE_INPUT;
+	  break;
 	}
-#endif	/* Input and output charset are not both fixed width.  */
+
+      /* Here comes the body the user provides.  It can stop with
+	 RESULT set to GCONV_INCOMPLETE_INPUT (if the size of the
+	 input characters vary in size), GCONV_ILLEGAL_INPUT, or
+	 GCONV_FULL_OUTPUT (if the output characters vary in size).  */
+      BODY
     }
 
   /* Update the pointers pointed to by the parameters.  */
@@ -291,11 +260,19 @@ FCTNAME (LOOPFCT) (const unsigned char **inptrp, const unsigned char *inend,
 # define SINGLE(fct) SINGLE2 (fct)
 # define SINGLE2(fct) fct##_single
 static inline int
-SINGLE(LOOPFCT) (const unsigned char **inptrp, const unsigned char *inend,
+SINGLE(LOOPFCT) (struct __gconv_step *step,
+		 struct __gconv_step_data *step_data,
+		 const unsigned char **inptrp, const unsigned char *inend,
 		 unsigned char **outptrp, unsigned char *outend,
-		 mbstate_t *state, int flags, void *data, size_t *irreversible
-		 EXTRA_LOOP_DECLS)
+		 size_t *irreversible EXTRA_LOOP_DECLS)
 {
+  mbstate_t *state = step_data->__statep;
+#ifdef LOOP_NEED_FLAGS
+  int flags = step_data->__flags;
+#endif
+#ifdef LOOP_NEED_DATA
+  void *data = step->__data;
+#endif
   int result = __GCONV_OK;
   unsigned char bytebuf[MAX_NEEDED_INPUT];
   const unsigned char *inptr = *inptrp;
@@ -347,8 +324,7 @@ SINGLE(LOOPFCT) (const unsigned char **inptrp, const unsigned char *inend,
 
   inptr = bytebuf;
   inend = &bytebuf[inlen];
-#undef NEED_LENGTH_TEST
-#define NEED_LENGTH_TEST	1
+
   do
     {
       BODY
@@ -410,9 +386,12 @@ SINGLE(LOOPFCT) (const unsigned char **inptrp, const unsigned char *inend,
 #undef EXTRA_LOOP_DECLS
 #undef INIT_PARAMS
 #undef UPDATE_PARAMS
+#undef UNPACK_BYTES
+#undef LOOP_NEED_STATE
+#undef LOOP_NEED_FLAGS
+#undef LOOP_NEED_DATA
 #undef get16
 #undef get32
 #undef put16
 #undef put32
 #undef unaligned
-#undef UNPACK_BYTES
diff --git a/iconv/skeleton.c b/iconv/skeleton.c
index 9b7b4a1125..dca2c7f7a6 100644
--- a/iconv/skeleton.c
+++ b/iconv/skeleton.c
@@ -271,7 +271,8 @@ gconv_init (struct __gconv_step *step)
 int
 FUNCTION_NAME (struct __gconv_step *step, struct __gconv_step_data *data,
 	       const unsigned char **inptrp, const unsigned char *inend,
-	       size_t *irreversible, int do_flush, int consume_incomplete)
+	       unsigned char *outbufstart, size_t *irreversible, int do_flush,
+	       int consume_incomplete)
 {
   struct __gconv_step *next_step = step + 1;
   struct __gconv_step_data *next_data = data + 1;
@@ -295,13 +296,14 @@ FUNCTION_NAME (struct __gconv_step *step, struct __gconv_step_data *data,
          successfully emitted the escape sequence.  */
       if (status == __GCONV_OK && ! (data->__flags & __GCONV_IS_LAST))
 	status = DL_CALL_FCT (fct, (next_step, next_data, NULL, NULL,
-				    irreversible, 1, consume_incomplete));
+				    next_data->__outbuf, irreversible, 1,
+				    consume_incomplete));
     }
   else
     {
       /* We preserve the initial values of the pointer variables.  */
       const unsigned char *inptr = *inptrp;
-      unsigned char *outbuf = data->__outbuf;
+      unsigned char *outbuf = outbufstart;
       unsigned char *outend = data->__outbufend;
       unsigned char *outstart;
       /* This variable is used to count the number of characters we
@@ -333,19 +335,16 @@ FUNCTION_NAME (struct __gconv_step *step, struct __gconv_step_data *data,
 
 # if MAX_NEEDED_FROM > 1
 	  if (MAX_NEEDED_TO == 1 || FROM_DIRECTION)
-	    status = SINGLE(FROM_LOOP) (inptrp, inend, &outbuf, outend,
-					data->__statep, data->__flags,
-					step->__data, &lirreversible
+	    status = SINGLE(FROM_LOOP) (step, data, inptrp, inend, &outbuf,
+					outend, &lirreversible
 					EXTRA_LOOP_ARGS);
 # endif
 # if MAX_NEEDED_FROM > 1 && MAX_NEEDED_TO > 1 && !ONE_DIRECTION
 	  else
 # endif
 # if MAX_NEEDED_TO > 1 && !ONE_DIRECTION
-	    status = SINGLE(TO_LOOP) (inptrp, inend, &outbuf, outend,
-				      data->__statep, data->__flags,
-				      step->__data, &lirreversible
-				      EXTRA_LOOP_ARGS);
+	    status = SINGLE(TO_LOOP) (step, data, inptrp, inend, &outbuf,
+				      outend, &lirreversible EXTRA_LOOP_ARGS);
 # endif
 
 	  if (__builtin_expect (status, __GCONV_OK) != __GCONV_OK)
@@ -386,16 +385,12 @@ FUNCTION_NAME (struct __gconv_step *step, struct __gconv_step_data *data,
 	    {
 	      if (FROM_DIRECTION)
 		/* Run the conversion loop.  */
-		status = FROM_LOOP (inptrp, inend, &outbuf, outend,
-				    data->__statep, data->__flags,
-				    step->__data, &lirreversible
-				    EXTRA_LOOP_ARGS);
+		status = FROM_LOOP (step, data, inptrp, inend, &outbuf, outend,
+				    &lirreversible EXTRA_LOOP_ARGS);
 	      else
 		/* Run the conversion loop.  */
-		status = TO_LOOP (inptrp, inend, &outbuf, outend,
-				  data->__statep, data->__flags,
-				  step->__data, &lirreversible
-				  EXTRA_LOOP_ARGS);
+		status = TO_LOOP (step, data, inptrp, inend, &outbuf, outend,
+				  &lirreversible EXTRA_LOOP_ARGS);
 	    }
 #if !defined _STRING_ARCH_unaligned \
     && MIN_NEEDED_FROM != 1 && MAX_NEEDED_FROM % MIN_NEEDED_FROM == 0 \
@@ -404,18 +399,14 @@ FUNCTION_NAME (struct __gconv_step *step, struct __gconv_step_data *data,
 	    {
 	      if (FROM_DIRECTION)
 		/* Run the conversion loop.  */
-		status = GEN_unaligned (FROM_LOOP) (inptrp, inend, &outbuf,
-						    outend, data->__statep,
-						    data->__flags,
-						    step->__data,
+		status = GEN_unaligned (FROM_LOOP) (step, data, inptrp, inend,
+						    &outbuf, outend,
 						    &lirreversible
 						    EXTRA_LOOP_ARGS);
 	      else
 		/* Run the conversion loop.  */
-		status = GEN_unaligned (TO_LOOP) (inptrp, inend, &outbuf,
-						  outend, data->__statep,
-						  data->__flags,
-						  step->__data,
+		status = GEN_unaligned (TO_LOOP) (step, data, inptrp, inend,
+						  &outbuf, outend,
 						  &lirreversible
 						  EXTRA_LOOP_ARGS);
 	    }
@@ -445,7 +436,8 @@ FUNCTION_NAME (struct __gconv_step *step, struct __gconv_step_data *data,
 	      int result;
 
 	      result = DL_CALL_FCT (fct, (next_step, next_data, &outerr,
-					  outbuf, irreversible, 0,
+					  outbuf, next_data->__outbuf,
+					  irreversible, 0,
 					  consume_incomplete));
 
 	      if (result != __GCONV_EMPTY_INPUT)
@@ -471,22 +463,20 @@ FUNCTION_NAME (struct __gconv_step *step, struct __gconv_step_data *data,
 		      /* XXX Handle unaligned access here as well.  */
 		      if (FROM_DIRECTION)
 			/* Run the conversion loop.  */
-			nstatus = FROM_LOOP ((const unsigned char **) inptrp,
+			nstatus = FROM_LOOP (step, data,
+					     (const unsigned char **) inptrp,
 					     (const unsigned char *) inend,
 					     (unsigned char **) &outbuf,
 					     (unsigned char *) outerr,
-					     data->__statep, data->__flags,
-					     step->__data, &lirreversible
-					     EXTRA_LOOP_ARGS);
+					     &lirreversible EXTRA_LOOP_ARGS);
 		      else
 			/* Run the conversion loop.  */
-			nstatus = TO_LOOP ((const unsigned char **) inptrp,
+			nstatus = TO_LOOP (step, data,
+					   (const unsigned char **) inptrp,
 					   (const unsigned char *) inend,
 					   (unsigned char **) &outbuf,
 					   (unsigned char *) outerr,
-					   data->__statep, data->__flags,
-					   step->__data, &lirreversible
-					   EXTRA_LOOP_ARGS);
+					   &lirreversible EXTRA_LOOP_ARGS);
 
 		      /* We must run out of output buffer space in this
 			 rerun.  */
diff --git a/iconvdata/8bit-gap.c b/iconvdata/8bit-gap.c
index 2d66f8b666..23a63fd9e4 100644
--- a/iconvdata/8bit-gap.c
+++ b/iconvdata/8bit-gap.c
@@ -19,6 +19,7 @@
    write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
    Boston, MA 02111-1307, USA.  */
 
+#include <dlfcn.h>
 #include <stdint.h>
 
 struct gap
@@ -67,6 +68,7 @@ struct gap
 									      \
     ++inptr;								      \
   }
+#define LOOP_NEED_FLAGS
 #include <iconv/loop.c>
 
 
@@ -83,7 +85,15 @@ struct gap
     if (__builtin_expect (ch, 0) >= 0xffff)				      \
       {									      \
 	/* This is an illegal character.  */				      \
-	if (! ignore_errors_p ())					      \
+	if (step_data->__trans.__trans_fct != NULL)			      \
+	  {								      \
+	    result = DL_CALL_FCT (step_data->__trans.__trans_fct,	      \
+				  (step, step_data, *inptrp, &inptr, inend,   \
+				   *outptrp, &outptr, outend, irreversible)); \
+	    if (result != __GCONV_OK)					      \
+	      break;							      \
+	  }								      \
+	else if (! ignore_errors_p ())					      \
 	  {								      \
 	    result = __GCONV_ILLEGAL_INPUT;				      \
 	    break;							      \
@@ -98,14 +108,24 @@ struct gap
     if (__builtin_expect (ch < rp->start, 0))				      \
       {									      \
 	/* This is an illegal character.  */				      \
-	if (! ignore_errors_p ())					      \
+	if (step_data->__trans.__trans_fct != NULL)			      \
+	  {								      \
+	    result = DL_CALL_FCT (step_data->__trans.__trans_fct,	      \
+				  (step, step_data, *inptrp, &inptr, inend,   \
+				   *outptrp, &outptr, outend, irreversible)); \
+	    if (result != __GCONV_OK)					      \
+	      break;							      \
+	  }								      \
+	else if (! ignore_errors_p ())					      \
 	  {								      \
 	    result = __GCONV_ILLEGAL_INPUT;				      \
 	    break;							      \
 	  }								      \
-									      \
-	++*irreversible;						      \
-	inptr += 4;							      \
+	else								      \
+	  {								      \
+	    ++*irreversible;						      \
+	    inptr += 4;							      \
+	  }								      \
 	continue;							      \
       }									      \
 									      \
@@ -113,20 +133,31 @@ struct gap
     if (__builtin_expect (res, '\1') == '\0' && ch != 0)		      \
       {									      \
 	/* This is an illegal character.  */				      \
-	if (! ignore_errors_p ())					      \
+	if (step_data->__trans.__trans_fct != NULL)			      \
+	  {								      \
+	    result = DL_CALL_FCT (step_data->__trans.__trans_fct,	      \
+				  (step, step_data, *inptrp, &inptr, inend,   \
+				   *outptrp, &outptr, outend, irreversible)); \
+	    if (result != __GCONV_OK)					      \
+	      break;							      \
+	  }								      \
+	else if (! ignore_errors_p ())					      \
 	  {								      \
 	    result = __GCONV_ILLEGAL_INPUT;				      \
 	    break;							      \
 	  }								      \
-									      \
-	++*irreversible;						      \
-	inptr += 4;							      \
+	else								      \
+	  {								      \
+	    ++*irreversible;						      \
+	    inptr += 4;							      \
+	  }								      \
 	continue;							      \
       }									      \
 									      \
     *outptr++ = res;							      \
     inptr += 4;								      \
   }
+#define LOOP_NEED_FLAGS
 #include <iconv/loop.c>
 
 
diff --git a/iconvdata/8bit-generic.c b/iconvdata/8bit-generic.c
index 97ca193194..62160c6efa 100644
--- a/iconvdata/8bit-generic.c
+++ b/iconvdata/8bit-generic.c
@@ -18,6 +18,8 @@
    write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
    Boston, MA 02111-1307, USA.  */
 
+#include <dlfcn.h>
+
 #define FROM_LOOP		from_generic
 #define TO_LOOP			to_generic
 #define DEFINE_INIT		1
@@ -50,6 +52,7 @@
     outptr += 4;							      \
     ++inptr;								      \
   }
+#define LOOP_NEED_FLAGS
 #include <iconv/loop.c>
 
 
@@ -65,19 +68,32 @@
 	|| (__builtin_expect (from_ucs4[ch], '\1') == '\0' && ch != 0))	      \
       {									      \
 	/* This is an illegal character.  */				      \
-	if (! ignore_errors_p ())					      \
+	if (step_data->__trans.__trans_fct != NULL)			      \
+	  {								      \
+	    result = DL_CALL_FCT (step_data->__trans.__trans_fct,	      \
+				  (step, step_data, *inptrp, &inptr, inend,   \
+				   *outptrp, &outptr, outend, irreversible)); \
+	    if (result != __GCONV_OK)					      \
+	      break;							      \
+	  }								      \
+	else if (! ignore_errors_p ())					      \
 	  {								      \
 	    result = __GCONV_ILLEGAL_INPUT;				      \
 	    break;							      \
 	  }								      \
-									      \
-	++*irreversible;						      \
+	else								      \
+	  {								      \
+	    ++*irreversible;						      \
+	    inptr += 4;							      \
+	  }								      \
       }									      \
     else								      \
-      *outptr++ = from_ucs4[ch];					      \
-									      \
-    inptr += 4;								      \
+      {									      \
+	*outptr++ = from_ucs4[ch];					      \
+	inptr += 4;							      \
+      }									      \
   }
+#define LOOP_NEED_FLAGS
 #include <iconv/loop.c>
 
 
diff --git a/iconvdata/ansi_x3.110.c b/iconvdata/ansi_x3.110.c
index 2dd082d3b9..f403773d9d 100644
--- a/iconvdata/ansi_x3.110.c
+++ b/iconvdata/ansi_x3.110.c
@@ -18,6 +18,7 @@
    write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
    Boston, MA 02111-1307, USA.  */
 
+#include <dlfcn.h>
 #include <gconv.h>
 #include <stdint.h>
 #include <string.h>
@@ -407,7 +408,7 @@ static const char from_ucs4[][2] =
 	   is also available.  */					      \
 	uint32_t ch2;							      \
 									      \
-	if (NEED_LENGTH_TEST && inptr + 1 >= inend)			      \
+	if (inptr + 1 >= inend)						      \
 	  {								      \
 	    /* The second character is not available.  */		      \
 	    result = __GCONV_INCOMPLETE_INPUT;				      \
@@ -458,6 +459,7 @@ static const char from_ucs4[][2] =
 									      \
     inptr += incr;							      \
   }
+#define LOOP_NEED_FLAGS
 #include <iconv/loop.c>
 
 
@@ -495,14 +497,25 @@ static const char from_ucs4[][2] =
 	    if (tmp[0] == '\0')						      \
 	      {								      \
 		/* Illegal characters.  */				      \
-		if (! ignore_errors_p ())				      \
+		if (step_data->__trans.__trans_fct != NULL)		      \
+		  {							      \
+		    result = DL_CALL_FCT (step_data->__trans.__trans_fct,     \
+					  (step, step_data, *inptrp, &inptr,  \
+					   inend, *outptrp, &outptr, outend,  \
+					   irreversible));		      \
+		    if (result != __GCONV_OK)				      \
+		      break;						      \
+		  }							      \
+		else if (! ignore_errors_p ())				      \
 		  {							      \
 		    result = __GCONV_ILLEGAL_INPUT;			      \
 		    break;						      \
 		  }							      \
-									      \
-		++*irreversible;					      \
-		inptr += 4;						      \
+		else							      \
+		  {							      \
+		    ++*irreversible;					      \
+		    inptr += 4;						      \
+		  }							      \
 		continue;						      \
 	      }								      \
 	    tmp[1] = '\0';						      \
@@ -543,14 +556,25 @@ static const char from_ucs4[][2] =
 	else								      \
 	  {								      \
 	    /* Illegal characters.  */					      \
-	    if (! ignore_errors_p ())					      \
+	    if (step_data->__trans.__trans_fct != NULL)			      \
+	      {								      \
+		result = DL_CALL_FCT (step_data->__trans.__trans_fct,	      \
+				      (step, step_data, *inptrp, &inptr,      \
+				       inend, *outptrp, &outptr, outend,      \
+				       irreversible));			      \
+		if (result != __GCONV_OK)				      \
+		  break;						      \
+	      }								      \
+	    else if (! ignore_errors_p ())				      \
 	      {								      \
 		result = __GCONV_ILLEGAL_INPUT;				      \
 		break;							      \
 	      }								      \
-									      \
-	    ++*irreversible;						      \
-	    inptr += 4;							      \
+	    else							      \
+	      {								      \
+		++*irreversible;					      \
+		inptr += 4;						      \
+	      }								      \
 	    continue;							      \
 	  }								      \
       }									      \
@@ -561,14 +585,25 @@ static const char from_ucs4[][2] =
 	if (__builtin_expect (cp[0], '\1') == '\0' && ch != 0)		      \
 	  {								      \
 	    /* Illegal characters.  */					      \
-	    if (! ignore_errors_p ())					      \
+	    if (step_data->__trans.__trans_fct != NULL)			      \
+	      {								      \
+		result = DL_CALL_FCT (step_data->__trans.__trans_fct,	      \
+				      (step, step_data, *inptrp, &inptr,      \
+				       inend, *outptrp, &outptr, outend,      \
+				       irreversible));			      \
+		if (result != __GCONV_OK)				      \
+		  break;						      \
+	      }								      \
+	    else if (! ignore_errors_p ())				      \
 	      {								      \
 		result = __GCONV_ILLEGAL_INPUT;				      \
 		break;							      \
 	      }								      \
-									      \
-	    ++*irreversible;						      \
-	    inptr += 4;							      \
+	    else							      \
+	      {								      \
+		++*irreversible;					      \
+		inptr += 4;						      \
+	      }								      \
 	    continue;							      \
 	  }								      \
       }									      \
@@ -577,7 +612,7 @@ static const char from_ucs4[][2] =
     /* Now test for a possible second byte and write this if possible.  */    \
     if (cp[1] != '\0')							      \
       {									      \
-	if (NEED_LENGTH_TEST && __builtin_expect (outptr >= outend, 0))	      \
+	if (__builtin_expect (outptr >= outend, 0))	 		      \
 	  {								      \
 	    /* The result does not fit into the buffer.  */		      \
 	    --outptr;							      \
@@ -590,6 +625,7 @@ static const char from_ucs4[][2] =
 									      \
     inptr += 4;								      \
   }
+#define LOOP_NEED_FLAGS
 #include <iconv/loop.c>
 
 
diff --git a/iconvdata/big5.c b/iconvdata/big5.c
index a52f850f73..2e039376d0 100644
--- a/iconvdata/big5.c
+++ b/iconvdata/big5.c
@@ -18,6 +18,7 @@
    write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
    Boston, MA 02111-1307, USA.  */
 
+#include <dlfcn.h>
 #include <gconv.h>
 #include <stdint.h>
 #include <stdlib.h>
@@ -8438,7 +8439,7 @@ static const char from_ucs4_tab13[][2] =
 	uint32_t ch2;							      \
 	int idx;							      \
 									      \
-	if (NEED_LENGTH_TEST && inptr + 1 >= inend)			      \
+	if (__builtin_expect (inptr + 1 >= inend, 0))			      \
 	  {								      \
 	    /* The second character is not available.  */		      \
 	    result = __GCONV_INCOMPLETE_INPUT;				      \
@@ -8493,6 +8494,7 @@ static const char from_ucs4_tab13[][2] =
     put32 (outptr, ch);							      \
     outptr += 4;							      \
   }
+#define LOOP_NEED_FLAGS
 #include <iconv/loop.c>
 
 
@@ -8583,18 +8585,30 @@ static const char from_ucs4_tab13[][2] =
     if (__builtin_expect (cp[0], '\1') == '\0' && ch != 0)		      \
       {									      \
 	/* Illegal character.  */					      \
-	if (! ignore_errors_p ())					      \
+	if (step_data->__trans.__trans_fct != NULL)			      \
+	  {								      \
+	    result = DL_CALL_FCT (step_data->__trans.__trans_fct,	      \
+				  (step, step_data, *inptrp, &inptr, inend,   \
+				   *outptrp, &outptr, outend, irreversible)); \
+	    if (result != __GCONV_OK)					      \
+	      break;							      \
+	  }								      \
+	else if (! ignore_errors_p ())					      \
 	  {								      \
 	    result = __GCONV_ILLEGAL_INPUT;				      \
 	    break;							      \
 	  }								      \
-									      \
-	++*irreversible;						      \
+	else								      \
+	  {								      \
+	    ++*irreversible;						      \
+	    inptr += 4;							      \
+	  }								      \
+	continue;							      \
       }									      \
     else								      \
       {									      \
 	/* See whether there is enough room for the second byte we write.  */ \
-	if (NEED_LENGTH_TEST && __builtin_expect (cp[1], '\1') != '\0'	      \
+	if (__builtin_expect (cp[1], '\1') != '\0'			      \
 	    && __builtin_expect (outptr + 1 >= outend, 0))		      \
 	  {								      \
 	    /* We have not enough room.  */				      \
@@ -8609,6 +8623,7 @@ static const char from_ucs4_tab13[][2] =
 									      \
     inptr += 4;								      \
   }
+#define LOOP_NEED_FLAGS
 #include <iconv/loop.c>
 
 
diff --git a/iconvdata/big5hkscs.c b/iconvdata/big5hkscs.c
index 1ca22d65a6..b5fe9663e5 100644
--- a/iconvdata/big5hkscs.c
+++ b/iconvdata/big5hkscs.c
@@ -19,6 +19,7 @@
    write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
    Boston, MA 02111-1307, USA.  */
 
+#include <dlfcn.h>
 #include <gconv.h>
 #include <stdint.h>
 #include <stdlib.h>
@@ -12592,7 +12593,7 @@ static const char from_ucs4_tab14[][2] =
 	uint32_t ch2;							      \
 	int idx;							      \
 									      \
-	if (NEED_LENGTH_TEST && inptr + 1 >= inend)			      \
+	if (__builtin_expect (inptr + 1 >= inend, 0))			      \
 	  {								      \
 	    /* The second character is not available.  */		      \
 	    result = __GCONV_INCOMPLETE_INPUT;				      \
@@ -12647,6 +12648,7 @@ static const char from_ucs4_tab14[][2] =
     put32 (outptr, ch);							      \
     outptr += 4;							      \
   }
+#define LOOP_NEED_FLAGS
 #include <iconv/loop.c>
 
 
@@ -12740,18 +12742,30 @@ static const char from_ucs4_tab14[][2] =
     if (__builtin_expect (cp[0], '\1') == '\0' && ch != 0)		      \
       {									      \
 	/* Illegal character.  */					      \
-	if (! ignore_errors_p ())					      \
+	if (step_data->__trans.__trans_fct != NULL)			      \
+	  {								      \
+	    result = DL_CALL_FCT (step_data->__trans.__trans_fct,	      \
+				  (step, step_data, *inptrp, &inptr, inend,   \
+				   *outptrp, &outptr, outend, irreversible)); \
+	    if (result != __GCONV_OK)					      \
+	      break;							      \
+	  }								      \
+	else if (! ignore_errors_p ())					      \
 	  {								      \
 	    result = __GCONV_ILLEGAL_INPUT;				      \
 	    break;							      \
 	  }								      \
-									      \
-	++*irreversible;						      \
+	else								      \
+	  {								      \
+	    ++*irreversible;						      \
+	    inptr += 4;							      \
+	  }								      \
+	continue;							      \
       }									      \
     else								      \
       {									      \
 	/* See whether there is enough room for the second byte we write.  */ \
-	if (NEED_LENGTH_TEST && __builtin_expect (cp[1], '\1') != '\0'	      \
+	if (__builtin_expect (cp[1], '\1') != '\0'			      \
 	    && __builtin_expect (outptr + 1 >= outend, 0))		      \
 	  {								      \
 	    /* We have not enough room.  */				      \
@@ -12766,6 +12780,7 @@ static const char from_ucs4_tab14[][2] =
 									      \
     inptr += 4;								      \
   }
+#define LOOP_NEED_FLAGS
 #include <iconv/loop.c>
 
 
diff --git a/iconvdata/euc-cn.c b/iconvdata/euc-cn.c
index 2c2b36e433..c7a02c2cd4 100644
--- a/iconvdata/euc-cn.c
+++ b/iconvdata/euc-cn.c
@@ -18,6 +18,7 @@
    write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
    Boston, MA 02111-1307, USA.  */
 
+#include <dlfcn.h>
 #include <gb2312.h>
 #include <stdint.h>
 
@@ -64,7 +65,7 @@
 	     next character is also available.  */			      \
 	  const unsigned char *endp;					      \
 									      \
-	  if (NEED_LENGTH_TEST && __builtin_expect (inptr + 1 >= inend, 0))   \
+	  if (__builtin_expect (inptr + 1 >= inend, 0))			      \
 	    {								      \
 	      /* The second character is not available.  Store		      \
 		 the intermediate result.  */				      \
@@ -114,6 +115,7 @@
     put32 (outptr, ch);							      \
     outptr += 4;							      \
   }
+#define LOOP_NEED_FLAGS
 #include <iconv/loop.c>
 
 
@@ -133,22 +135,31 @@
       {									      \
 	size_t found;							      \
 									      \
-	found = ucs4_to_gb2312 (ch, outptr,				      \
-				(NEED_LENGTH_TEST			      \
-				 ? outend - outptr : MAX_NEEDED_OUTPUT));     \
-	if (!NEED_LENGTH_TEST || __builtin_expect (found, 1) != 0)	      \
+	found = ucs4_to_gb2312 (ch, outptr, outend - outptr);		      \
+	if (__builtin_expect (found, 1) != 0)				      \
 	  {								      \
 	    if (__builtin_expect (found, 0) == __UNKNOWN_10646_CHAR)	      \
 	      {								      \
 		/* Illegal character.  */				      \
-		if (! ignore_errors_p ())				      \
+		if (step_data->__trans.__trans_fct != NULL)		      \
+		  {							      \
+		    result = DL_CALL_FCT (step_data->__trans.__trans_fct,     \
+					  (step, step_data, *inptrp, &inptr,  \
+					   inend, *outptrp, &outptr, outend,  \
+					   irreversible));		      \
+		    if (result != __GCONV_OK)				      \
+		      break;						      \
+		  }							      \
+		else if (! ignore_errors_p ())				      \
 		  {							      \
 		    result = __GCONV_ILLEGAL_INPUT;			      \
 		    break;						      \
 		  }							      \
-									      \
-		inptr += 4;						      \
-		++*irreversible;					      \
+		else							      \
+		  {							      \
+		    inptr += 4;						      \
+		    ++*irreversible;					      \
+		  }							      \
 		continue;						      \
 	      }								      \
 									      \
@@ -165,6 +176,7 @@
       }									      \
     inptr += 4;								      \
   }
+#define LOOP_NEED_FLAGS
 #include <iconv/loop.c>
 
 
diff --git a/iconvdata/euc-jp.c b/iconvdata/euc-jp.c
index 93622e778e..6cf89e3aa6 100644
--- a/iconvdata/euc-jp.c
+++ b/iconvdata/euc-jp.c
@@ -18,6 +18,7 @@
    write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
    Boston, MA 02111-1307, USA.  */
 
+#include <dlfcn.h>
 #include <stdint.h>
 #include <gconv.h>
 #include <jis0201.h>
@@ -66,7 +67,7 @@
 	   character is also available.  */				      \
 	int ch2;							      \
 									      \
-	if (NEED_LENGTH_TEST && __builtin_expect (inptr + 1 >= inend, 0))     \
+	if (__builtin_expect (inptr + 1 >= inend, 0))			      \
 	  {								      \
 	    /* The second character is not available.  Store the	      \
 	       intermediate result.  */					      \
@@ -106,21 +107,17 @@
 		/* This is code set 3: JIS X 0212-1990.  */		      \
 		endp = inptr + 1;					      \
 									      \
-		ch = jisx0212_to_ucs4 (&endp,				      \
-				       NEED_LENGTH_TEST ? inend - endp : 2,   \
-				       0x80);				      \
+		ch = jisx0212_to_ucs4 (&endp, inend - endp, 0x80);	      \
 	      }								      \
 	    else							      \
 	      {								      \
 		/* This is code set 1: JIS X 0208.  */			      \
 		endp = inptr;						      \
 									      \
-		ch = jisx0208_to_ucs4 (&endp,				      \
-				       NEED_LENGTH_TEST ? inend - inptr : 2,  \
-				       0x80);				      \
+		ch = jisx0208_to_ucs4 (&endp, inend - inptr, 0x80);	      \
 	      }								      \
 									      \
-	    if (NEED_LENGTH_TEST && __builtin_expect (ch, 1) == 0)	      \
+	    if (__builtin_expect (ch, 1) == 0)				      \
 	      {								      \
 		/* Not enough input available.  */			      \
 		result = __GCONV_INCOMPLETE_INPUT;			      \
@@ -147,6 +144,7 @@
     put32 (outptr, ch);							      \
     outptr += 4;							      \
   }
+#define LOOP_NEED_FLAGS
 #include <iconv/loop.c>
 
 
@@ -174,7 +172,7 @@
 	size_t found;							      \
 									      \
 	/* See whether we have room for at least two characters.  */	      \
-	if (NEED_LENGTH_TEST && __builtin_expect (outptr + 1 >= outend, 0))   \
+	if (__builtin_expect (outptr + 1 >= outend, 0))			      \
 	  {								      \
 	    result = __GCONV_FULL_OUTPUT;				      \
 	    break;							      \
@@ -202,8 +200,7 @@
 	      {								      \
 		/* No JIS 0208 character.  */				      \
 		found = ucs4_to_jisx0212 (ch, outptr + 1,		      \
-					  (NEED_LENGTH_TEST		      \
-					   ? outend - outptr - 1 : 2));	      \
+					  outend - outptr - 1);		      \
 		  							      \
 		if (__builtin_expect (found, 1) == 0)			      \
 		  {							      \
@@ -221,14 +218,26 @@
 		else							      \
 		  {							      \
 		    /* Illegal character.  */				      \
-		    if (! ignore_errors_p ())				      \
+		    if (step_data->__trans.__trans_fct != NULL)		      \
+		      {							      \
+			result = DL_CALL_FCT (step_data->__trans.__trans_fct, \
+					      (step, step_data, *inptrp,      \
+					       &inptr, inend, *outptrp,	      \
+					       &outptr, outend,		      \
+					       irreversible));		      \
+			if (result != __GCONV_OK)			      \
+			  break;					      \
+		      }							      \
+		    else if (! ignore_errors_p ())			      \
 		      {							      \
 			result = __GCONV_ILLEGAL_INPUT;			      \
 			break;						      \
 		      }							      \
-									      \
-		    inptr += 4;						      \
-		    ++*irreversible;					      \
+		    else						      \
+		      {							      \
+			inptr += 4;					      \
+			++*irreversible;				      \
+		      }							      \
 		    continue;						      \
 		  }							      \
 	      }								      \
@@ -237,6 +246,7 @@
 									      \
     inptr += 4;								      \
   }
+#define LOOP_NEED_FLAGS
 #include <iconv/loop.c>
 
 
diff --git a/iconvdata/euc-kr.c b/iconvdata/euc-kr.c
index f067fbc548..88794f2f02 100644
--- a/iconvdata/euc-kr.c
+++ b/iconvdata/euc-kr.c
@@ -19,6 +19,7 @@
    write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
    Boston, MA 02111-1307, USA.  */
 
+#include <dlfcn.h>
 #include <stdint.h>
 #include <ksc5601.h>
 
@@ -98,9 +99,8 @@ euckr_from_ucs4 (uint32_t ch, unsigned char *cp)
       {									      \
 	/* Two-byte character.  First test whether the next character	      \
 	   is also available.  */					      \
-	ch = ksc5601_to_ucs4 (&inptr,					      \
-			      NEED_LENGTH_TEST ? inptr - inend : 2, 0x80);    \
-	if (NEED_LENGTH_TEST && __builtin_expect (ch, 1) == 0)		      \
+	ch = ksc5601_to_ucs4 (&inptr, inptr - inend, 0x80);		      \
+	if (__builtin_expect (ch, 1) == 0)				      \
 	  {								      \
 	    /* The second character is not available.  */		      \
 	    result = __GCONV_INCOMPLETE_INPUT;				      \
@@ -125,6 +125,7 @@ euckr_from_ucs4 (uint32_t ch, unsigned char *cp)
     put32 (outptr, ch);							      \
     outptr += 4;							      \
   }
+#define LOOP_NEED_FLAGS
 #include <iconv/loop.c>
 
 
@@ -145,14 +146,24 @@ euckr_from_ucs4 (uint32_t ch, unsigned char *cp)
     if (__builtin_expect (cp[0], '\1') == '\0' && ch != 0)		      \
       {									      \
 	/* Illegal character.  */					      \
-	if (! ignore_errors_p ())					      \
+	if (step_data->__trans.__trans_fct != NULL)			      \
+	  {								      \
+	    result = DL_CALL_FCT (step_data->__trans.__trans_fct,	      \
+				  (step, step_data, *inptrp, &inptr, inend,   \
+				   *outptrp, &outptr, outend, irreversible)); \
+	    if (result != __GCONV_OK)					      \
+	      break;							      \
+	  }								      \
+	else if (! ignore_errors_p ())					      \
 	  {								      \
 	    result = __GCONV_ILLEGAL_INPUT;				      \
 	    break;							      \
 	  }								      \
-									      \
-	inptr += 4;							      \
-	++*irreversible;						      \
+	else								      \
+	  {								      \
+	    inptr += 4;							      \
+	    ++*irreversible;						      \
+	  }								      \
 	continue;							      \
       }									      \
 									      \
@@ -160,7 +171,7 @@ euckr_from_ucs4 (uint32_t ch, unsigned char *cp)
     /* Now test for a possible second byte and write this if possible.  */    \
     if (cp[1] != '\0')							      \
       {									      \
-	if (NEED_LENGTH_TEST && __builtin_expect (outptr >= outend, 0))	      \
+	if (__builtin_expect (outptr >= outend, 0))			      \
 	  {								      \
 	    /* The result does not fit into the buffer.  */		      \
 	    --outptr;							      \
@@ -172,6 +183,7 @@ euckr_from_ucs4 (uint32_t ch, unsigned char *cp)
 									      \
     inptr += 4;								      \
   }
+#define LOOP_NEED_FLAGS
 #include <iconv/loop.c>
 
 
diff --git a/iconvdata/euc-tw.c b/iconvdata/euc-tw.c
index a508c848ef..ee88d4e2a7 100644
--- a/iconvdata/euc-tw.c
+++ b/iconvdata/euc-tw.c
@@ -18,6 +18,7 @@
    write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
    Boston, MA 02111-1307, USA.  */
 
+#include <dlfcn.h>
 #include <stdint.h>
 #include <cns11643l1.h>
 #include <cns11643.h>
@@ -48,8 +49,15 @@
     else if ((ch <= 0xa0 || ch > 0xfe) && ch != 0x8e)			      \
       {									      \
 	/* This is illegal.  */						      \
-	result = __GCONV_ILLEGAL_INPUT;					      \
-	break;								      \
+	if (! ignore_errors_p ())					      \
+	  {								      \
+	    result = __GCONV_ILLEGAL_INPUT;				      \
+	    break;							      \
+	  }								      \
+									      \
+	++inptr;							      \
+	++*irreversible;						      \
+	continue;							      \
       }									      \
     else								      \
       {									      \
@@ -57,7 +65,7 @@
 	   character is also available.  */				      \
 	uint32_t ch2;							      \
 									      \
-	if (NEED_LENGTH_TEST && inptr + (ch == 0x8e ? 3 : 1) >= inend)	      \
+	if (inptr + (ch == 0x8e ? 3 : 1) >= inend)			      \
 	  {								      \
 	    /* The second character is not available.  Store the	      \
 	       intermediate result.  */					      \
@@ -70,9 +78,16 @@
 	/* All second bytes of a multibyte character must be >= 0xa1. */      \
 	if (ch2 < 0xa1 || ch2 == 0xff)					      \
 	  {								      \
-	    /* This is an illegal character.  */			      \
-	    result = __GCONV_ILLEGAL_INPUT;				      \
-	    break;							      \
+	    /* This is illegal.  */					      \
+	    if (! ignore_errors_p ())					      \
+	      {								      \
+	        result = __GCONV_ILLEGAL_INPUT;				      \
+	        break;							      \
+	      }								      \
+									      \
+	    ++inptr;							      \
+	    ++*irreversible;						      \
+	    continue;							      \
 	  }								      \
 									      \
 	if (ch == 0x8e)							      \
@@ -80,16 +95,22 @@
 	    /* This is code set 2: CNS 11643, planes 1 to 16.  */	      \
 	    const char *endp = inptr + 1;				      \
 									      \
-	    ch = cns11643_to_ucs4 (&endp,				      \
-				   NEED_LENGTH_TEST ? inend - inptr - 1 : 3,  \
-				   0x80);				      \
+	    ch = cns11643_to_ucs4 (&endp, inend - inptr - 1, 0x80);	      \
 	    /* Please note that we need not test for the missing input	      \
 	       characters here anymore.  */				      \
 	    if (ch == __UNKNOWN_10646_CHAR)				      \
 	      {								      \
 		/* Illegal input.  */					      \
-		result = __GCONV_ILLEGAL_INPUT;				      \
-		break;							      \
+		if (! ignore_errors_p ())				      \
+		  {							      \
+		    /* This is an illegal character.  */		      \
+		    result = __GCONV_ILLEGAL_INPUT;			      \
+		    break;						      \
+		  }							      \
+									      \
+		++inptr;						      \
+		++*irreversible;					      \
+		continue;						      \
 	      }								      \
 									      \
 	    inptr += 4;							      \
@@ -99,16 +120,22 @@
 	    /* This is code set 1: CNS 11643, plane 1.  */		      \
 	    const unsigned char *endp = inptr;				      \
 									      \
-	    ch = cns11643l1_to_ucs4 (&endp,				      \
-				     NEED_LENGTH_TEST ? inend - inptr : 2,    \
-				     0x80);				      \
+	    ch = cns11643l1_to_ucs4 (&endp, inend - inptr, 0x80);	      \
 	    /* Please note that we need not test for the missing input	      \
 	       characters here anymore.  */				      \
 	    if (ch == __UNKNOWN_10646_CHAR)				      \
 	      {								      \
 		/* Illegal input.  */					      \
-		result = __GCONV_ILLEGAL_INPUT;				      \
-		break;							      \
+		if (! ignore_errors_p ())				      \
+		  {							      \
+		    /* This is an illegal character.  */		      \
+		    result = __GCONV_ILLEGAL_INPUT;			      \
+		    break;						      \
+		  }							      \
+									      \
+		inptr += 2;						      \
+		++*irreversible;					      \
+		continue;						      \
 	      }								      \
 									      \
 	    inptr += 2;							      \
@@ -118,6 +145,7 @@
     put32 (outptr, ch);							      \
     outptr += 4;							      \
   }
+#define LOOP_NEED_FLAGS
 #include <iconv/loop.c>
 
 
@@ -138,15 +166,14 @@
 	/* Try the JIS character sets.  */				      \
 	size_t found;							      \
 									      \
-	found = ucs4_to_cns11643l1 (ch, outptr,				      \
-				    NEED_LENGTH_TEST ? outend - outptr : 2);  \
-	if (NEED_LENGTH_TEST && found == 0)				      \
+	found = ucs4_to_cns11643l1 (ch, outptr, outend - outptr);	      \
+	if (__builtin_expect (found, 1) == 0)				      \
 	  {								      \
 	    /* We ran out of space.  */					      \
 	    result = __GCONV_INCOMPLETE_INPUT;				      \
 	    break;							      \
 	  }								      \
-	if (found != __UNKNOWN_10646_CHAR)				      \
+	if (__builtin_expect (found, 1) != __UNKNOWN_10646_CHAR)	      \
 	  {								      \
 	    /* It's a CNS 11643, plane 1 character, adjust it for EUC-TW.  */ \
 	    *outptr++ += 0x80;						      \
@@ -156,20 +183,36 @@
 	  {								      \
 	    /* No CNS 11643, plane 1 character.  */			      \
 									      \
-	    found = ucs4_to_cns11643 (ch, outptr + 1,			      \
-				      (NEED_LENGTH_TEST			      \
-				       ? outend - outptr - 1 : 3));	      \
-	    if (NEED_LENGTH_TEST && found == 0)				      \
+	    found = ucs4_to_cns11643 (ch, outptr + 1, outend - outptr - 1);   \
+	    if (__builtin_expect (found, 1) == 0)			      \
 	      {								      \
 		/* We ran out of space.  */				      \
 		result = __GCONV_INCOMPLETE_INPUT;			      \
 		break;							      \
 	      }								      \
-	    if (found == __UNKNOWN_10646_CHAR)				      \
+	    if (__builtin_expect (found, 0) == __UNKNOWN_10646_CHAR)	      \
 	      {								      \
-		/* No legal input.  */					      \
-		result = __GCONV_ILLEGAL_INPUT;				      \
-		break;							      \
+		/* Illegal character.  */				      \
+		if (step_data->__trans.__trans_fct != NULL)		      \
+		  {							      \
+		    result = DL_CALL_FCT (step_data->__trans.__trans_fct,     \
+					  (step, step_data, *inptrp, &inptr,  \
+					   inend, *outptrp, &outptr, outend,  \
+					   irreversible));		      \
+		    if (result != __GCONV_OK)				      \
+		      break;						      \
+		  }							      \
+		else if (! ignore_errors_p ())				      \
+		  {							      \
+		    result = __GCONV_ILLEGAL_INPUT;			      \
+		    break;						      \
+		  }							      \
+		else							      \
+		  {							      \
+		    inptr += 4;						      \
+		    ++*irreversible;					      \
+		  }							      \
+		continue;						      \
 	      }								      \
 									      \
 	    /* It's a CNS 11643 character, adjust it for EUC-TW.  */	      \
@@ -182,6 +225,7 @@
 									      \
     inptr += 4;								      \
   }
+#define LOOP_NEED_FLAGS
 #include <iconv/loop.c>
 
 
diff --git a/iconvdata/gbgbk.c b/iconvdata/gbgbk.c
index 0fbbfc81e4..c6f2e4e0c2 100644
--- a/iconvdata/gbgbk.c
+++ b/iconvdata/gbgbk.c
@@ -18,6 +18,7 @@
    write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
    Boston, MA 02111-1307, USA.  */
 
+#include <dlfcn.h>
 #include <gconv.h>
 #include <stdint.h>
 
@@ -71,7 +72,7 @@
 		UCS4 -> GB2312 -> GBK -> UCS4				      \
 									      \
 	   might not produce identical text.  */			      \
-	if (NEED_LENGTH_TEST && __builtin_expect (inptr + 1 >= inend, 0))     \
+	if (__builtin_expect (inptr + 1 >= inend, 0))			      \
 	  {								      \
 	    /* The second character is not available.  Store		      \
 	       the intermediate result.  */				      \
@@ -79,7 +80,7 @@
 	    break;							      \
 	  }								      \
 									      \
-	if (NEED_LENGTH_TEST && __builtin_expect (outend - outptr < 2, 0))    \
+	if (__builtin_expect (outend - outptr < 2, 0))			      \
 	  {								      \
 	    /* We ran out of space.  */					      \
 	    result = __GCONV_FULL_OUTPUT;				      \
@@ -101,14 +102,25 @@
 		&& __builtin_expect (ch, 0xa1a1) <= 0xa8c0))		      \
 	  {								      \
 	    /* One of the characters we cannot map.  */			      \
-	    if (! ignore_errors_p ())					      \
+	    if (step_data->__trans.__trans_fct != NULL)			      \
+	      {								      \
+		result = DL_CALL_FCT (step_data->__trans.__trans_fct,	      \
+				      (step, step_data, *inptrp, &inptr,      \
+				       inend, *outptrp, &outptr, outend,      \
+				       irreversible));			      \
+		if (result != __GCONV_OK)				      \
+		  break;						      \
+	      }								      \
+	    else if (! ignore_errors_p ())				      \
 	      {								      \
 		result = __GCONV_ILLEGAL_INPUT;				      \
 		break;							      \
 	      }								      \
-									      \
-	    inptr += 2;							      \
-	    ++*irreversible;						      \
+	    else							      \
+	      {								      \
+		inptr += 2;						      \
+		++*irreversible;					      \
+	      }								      \
 	  }								      \
 	else								      \
 	  {								      \
@@ -118,6 +130,7 @@
 	  }								      \
       }									      \
   }
+#define LOOP_NEED_FLAGS
 #include <iconv/loop.c>
 
 
@@ -136,7 +149,7 @@
 									      \
     if (ch > 0x7f)							      \
       {									      \
-	if (NEED_LENGTH_TEST && __builtin_expect (inptr + 1 >= inend, 0))     \
+	if (__builtin_expect (inptr + 1 >= inend, 0))			      \
 	  {								      \
 	    /* The second character is not available.  Store		      \
 		 the intermediate result.  */				      \
@@ -144,7 +157,7 @@
 	    break;							      \
 	  }								      \
 									      \
-	if (NEED_LENGTH_TEST && __builtin_expect (outend - outptr < 2, 0))    \
+	if (__builtin_expect (outend - outptr < 2, 0))			      \
 	  {								      \
 	    /* We ran out of space.  */					      \
 	    result = __GCONV_FULL_OUTPUT;				      \
diff --git a/iconvdata/gbk.c b/iconvdata/gbk.c
index 952f76ab73..f82059195e 100644
--- a/iconvdata/gbk.c
+++ b/iconvdata/gbk.c
@@ -18,6 +18,7 @@
    write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
    Boston, MA 02111-1307, USA.  */
 
+#include <dlfcn.h>
 #include <gconv.h>
 #include <stdint.h>
 #include <stdlib.h>
@@ -13109,7 +13110,7 @@ static const char __gbk_from_ucs4_tab12[][2] =
 #define MIN_NEEDED_TO		4
 
 
-/* First define the conversion function from ISO 8859-1 to UCS4.  */
+/* First define the conversion function from GBK to UCS4.  */
 #define MIN_NEEDED_INPUT	MIN_NEEDED_FROM
 #define MAX_NEEDED_INPUT	MAX_NEEDED_FROM
 #define MIN_NEEDED_OUTPUT	MIN_NEEDED_TO
@@ -13142,7 +13143,7 @@ static const char __gbk_from_ucs4_tab12[][2] =
 	  uint32_t ch2;							      \
 	  int idx;							      \
 									      \
-	  if (NEED_LENGTH_TEST && __builtin_expect (inptr + 1 >= inend, 0))   \
+	  if (__builtin_expect (inptr + 1 >= inend, 0))			      \
 	    {								      \
 	      /* The second character is not available.  Store		      \
 		 the intermediate result.  */				      \
@@ -13194,6 +13195,7 @@ static const char __gbk_from_ucs4_tab12[][2] =
     put32 (outptr, ch);							      \
     outptr += 4;							      \
   }
+#define LOOP_NEED_FLAGS
 #include <iconv/loop.c>
 
 
@@ -13450,17 +13452,29 @@ static const char __gbk_from_ucs4_tab12[][2] =
       if (__builtin_expect (cp[0], '\1') == '\0' && ch != 0)		      \
 	{								      \
 	  /* Illegal character.  */					      \
-	  if (! ignore_errors_p ())					      \
+	  if (step_data->__trans.__trans_fct != NULL)			      \
+	    {								      \
+	      result = DL_CALL_FCT (step_data->__trans.__trans_fct,	      \
+				    (step, step_data, *inptrp, &inptr, inend, \
+				     *outptrp, &outptr, outend,		      \
+				     irreversible));			      \
+	      if (result != __GCONV_OK)					      \
+		break;							      \
+	    }								      \
+	  else if (! ignore_errors_p ())				      \
 	    {								      \
 	      result = __GCONV_ILLEGAL_INPUT;				      \
 	      break;							      \
 	    }								      \
-									      \
-	  ++*irreversible;						      \
+	  else								      \
+	    {								      \
+	      inptr += 4;						      \
+	      ++*irreversible;						      \
+	    }								      \
+	  continue;							      \
 	}								      \
       /* See whether there is enough room for the second byte we write.  */   \
-      else if (NEED_LENGTH_TEST && cp[1] != '\0'			      \
-	       && __builtin_expect (outptr + 1 >= outend, 0))		      \
+      else if (cp[1] != '\0' && __builtin_expect (outptr + 1 >= outend, 0))   \
 	{								      \
 	  /* We have not enough room.  */				      \
 	  result = __GCONV_FULL_OUTPUT;					      \
@@ -13476,6 +13490,7 @@ static const char __gbk_from_ucs4_tab12[][2] =
 									      \
     inptr += 4;                                                               \
   }
+#define LOOP_NEED_FLAGS
 #include <iconv/loop.c>
 
 
diff --git a/iconvdata/iso-2022-cn.c b/iconvdata/iso-2022-cn.c
index 38b138b928..af7f92d3ac 100644
--- a/iconvdata/iso-2022-cn.c
+++ b/iconvdata/iso-2022-cn.c
@@ -18,6 +18,7 @@
    write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
    Boston, MA 02111-1307, USA.  */
 
+#include <dlfcn.h>
 #include <gconv.h>
 #include <stdint.h>
 #include <string.h>
@@ -140,16 +141,15 @@ enum
 	     line; we can simply ignore them				      \
 	   - the initial byte of the SS2 sequence.			      \
 	*/								      \
-	if (NEED_LENGTH_TEST						      \
-	    && (__builtin_expect (inptr + 1 > inend, 0)			      \
-		|| (inptr[1] == '$'					      \
-		    && (__builtin_expect (inptr + 2 > inend, 0)		      \
-			|| (inptr[2] == ')'				      \
-			    && __builtin_expect (inptr + 3 > inend, 0))	      \
-			|| (inptr[2] == '*'				      \
-			    && __builtin_expect (inptr + 3 > inend, 0))))     \
-		|| (inptr[1] == SS2_1					      \
-		    && __builtin_expect (inptr + 3 > inend, 0))))	      \
+	if (__builtin_expect (inptr + 1 > inend, 0)			      \
+	    || (inptr[1] == '$'						      \
+		&& (__builtin_expect (inptr + 2 > inend, 0)		      \
+		    || (inptr[2] == ')'					      \
+			&& __builtin_expect (inptr + 3 > inend, 0))	      \
+		    || (inptr[2] == '*'					      \
+			&& __builtin_expect (inptr + 3 > inend, 0))))	      \
+	    || (inptr[1] == SS2_1					      \
+		&& __builtin_expect (inptr + 3 > inend, 0)))		      \
 	  {								      \
 	    result = __GCONV_EMPTY_INPUT;				      \
 	    break;							      \
@@ -216,16 +216,14 @@ enum
       {									      \
 	/* That's pretty easy, we have a dedicated functions for this.  */    \
 	if (set == GB2312_set)						      \
-	  ch = gb2312_to_ucs4 (&inptr,					      \
-			       NEED_LENGTH_TEST ? inend - inptr : 2, 0);      \
+	  ch = gb2312_to_ucs4 (&inptr, inend - inptr, 0);		      \
 	else								      \
 	  {								      \
 	    assert (set == CNS11643_1_set);				      \
-	    ch = cns11643l1_to_ucs4 (&inptr,				      \
-				     NEED_LENGTH_TEST ? inend - inptr : 2, 0);\
+	    ch = cns11643l1_to_ucs4 (&inptr, inend - inptr, 0);		      \
 	  }								      \
 									      \
-	if (NEED_LENGTH_TEST && __builtin_expect (ch, 1) == 0)		      \
+	if (__builtin_expect (ch, 1) == 0)				      \
 	  {								      \
 	    result = __GCONV_EMPTY_INPUT;				      \
 	    break;							      \
@@ -248,6 +246,7 @@ enum
     put32 (outptr, ch);							      \
     outptr += 4;							      \
   }
+#define LOOP_NEED_FLAGS
 #define EXTRA_LOOP_DECLS	, int *setp
 #define INIT_PARAMS		int set = *setp & CURRENT_SEL_MASK; \
 				int ann = *setp & CURRENT_ANN_MASK
@@ -272,7 +271,7 @@ enum
 	  {								      \
 	    *outptr++ = SI;						      \
 	    set = ASCII_set;						      \
-	    if (NEED_LENGTH_TEST && __builtin_expect (outptr == outend, 0))   \
+	    if (__builtin_expect (outptr == outend, 0))			      \
 	      {								      \
 		result = __GCONV_FULL_OUTPUT;				      \
 		break;							      \
@@ -325,14 +324,26 @@ enum
 		else							      \
 		  {							      \
 		    /* Even this does not work.  Error.  */		      \
-		    if (! ignore_errors_p ())				      \
+		    if (step_data->__trans.__trans_fct != NULL)		      \
+		      {							      \
+			result = DL_CALL_FCT (step_data->__trans.__trans_fct, \
+					      (step, step_data, *inptrp,      \
+					       &inptr, inend, *outptrp,	      \
+					       &outptr, outend,		      \
+					       irreversible));		      \
+			if (result != __GCONV_OK)			      \
+			  break;					      \
+		      }							      \
+		    else if (! ignore_errors_p ())			      \
 		      {							      \
 			result = __GCONV_ILLEGAL_INPUT;			      \
 			break;						      \
 		      }							      \
-									      \
-		    inptr += 4;						      \
-		    ++*irreversible;					      \
+		    else						      \
+		      {							      \
+			inptr += 4;					      \
+			++*irreversible;				      \
+		      }							      \
 		    continue;						      \
 		  }							      \
 	      }								      \
@@ -348,8 +359,7 @@ enum
 	      {								      \
 		const char *escseq;					      \
 									      \
-		if (NEED_LENGTH_TEST					      \
-		    && __builtin_expect (outptr + 4 > outend, 0))	      \
+		if (__builtin_expect (outptr + 4 > outend, 0))		      \
 		  {							      \
 		    result = __GCONV_FULL_OUTPUT;			      \
 		    break;						      \
@@ -404,8 +414,7 @@ enum
 		break;							      \
 	      }								      \
 	  }								      \
-	else if (NEED_LENGTH_TEST					      \
-		 && __builtin_expect (outptr + 2 > outend, 0))		      \
+	else if (__builtin_expect (outptr + 2 > outend, 0))		      \
 	  {								      \
 	    result = __GCONV_FULL_OUTPUT;				      \
 	    break;							      \
@@ -418,6 +427,7 @@ enum
     /* Now that we wrote the output increment the input pointer.  */	      \
     inptr += 4;								      \
   }
+#define LOOP_NEED_FLAGS
 #define EXTRA_LOOP_DECLS	, int *setp
 #define INIT_PARAMS		int set = *setp & CURRENT_SEL_MASK; \
 				int ann = *setp & CURRENT_ANN_MASK
diff --git a/iconvdata/iso-2022-jp.c b/iconvdata/iso-2022-jp.c
index 9b22ddd6b3..c6a43d121d 100644
--- a/iconvdata/iso-2022-jp.c
+++ b/iconvdata/iso-2022-jp.c
@@ -18,6 +18,7 @@
    write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
    Boston, MA 02111-1307, USA.  */
 
+#include <dlfcn.h>
 #include <gconv.h>
 #include <stdint.h>
 #include <stdlib.h>
@@ -444,26 +445,22 @@ gconv_end (struct __gconv_step *data)
 	     JIS X 0208.  Therefore I'm using the tables for JIS X	      \
 	     0208-1990.  If somebody has problems with this please	      \
 	     provide the appropriate tables.  */			      \
-	  ch = jisx0208_to_ucs4 (&inptr,				      \
-				 NEED_LENGTH_TEST ? inend - inptr : 2, 0);    \
+	  ch = jisx0208_to_ucs4 (&inptr, inend - inptr, 0);		      \
 	else if (set == JISX0212_set)					      \
 	  /* Use the JIS X 0212 table.  */				      \
-	  ch = jisx0212_to_ucs4 (&inptr,				      \
-				 NEED_LENGTH_TEST ? inend - inptr : 2, 0);    \
+	  ch = jisx0212_to_ucs4 (&inptr, inend - inptr, 0);		      \
 	else if (set == GB2312_set)					      \
 	  /* Use the GB 2312 table.  */					      \
-	  ch = gb2312_to_ucs4 (&inptr,					      \
-			       NEED_LENGTH_TEST ? inend - inptr : 2, 0);      \
+	  ch = gb2312_to_ucs4 (&inptr, inend - inptr, 0);		      \
 	else								      \
 	  {								      \
 	    assert (set == KSC5601_set);				      \
 									      \
 	    /* Use the KSC 5601 table.  */				      \
-	    ch = ksc5601_to_ucs4 (&inptr,				      \
-				  NEED_LENGTH_TEST ? inend - inptr : 2, 0);   \
+	    ch = ksc5601_to_ucs4 (&inptr, inend - inptr, 0);		      \
 	  }								      \
 									      \
-	if (NEED_LENGTH_TEST && __builtin_expect (ch, 1) == 0)		      \
+	if (__builtin_expect (ch, 1) == 0)				      \
 	  {								      \
 	    result = __GCONV_EMPTY_INPUT;				      \
 	    break;							      \
@@ -485,6 +482,7 @@ gconv_end (struct __gconv_step *data)
     put32 (outptr, ch);							      \
     outptr += 4;							      \
   }
+#define LOOP_NEED_FLAGS
 #define EXTRA_LOOP_DECLS	, enum variant var, int *setp
 #define INIT_PARAMS		int set = *setp & CURRENT_SEL_MASK;	      \
 				int set2 = *setp & CURRENT_ASSIGN_MASK
@@ -554,26 +552,19 @@ gconv_end (struct __gconv_step *data)
     else								      \
       {									      \
 	if (set == JISX0208_1978_set || set == JISX0208_1983_set)	      \
-	  written = ucs4_to_jisx0208 (ch, outptr,			      \
-				      (NEED_LENGTH_TEST			      \
-				       ? outend - outptr : 2));		      \
+	  written = ucs4_to_jisx0208 (ch, outptr, outend - outptr);	      \
 	else if (set == JISX0212_set)					      \
-	  written = ucs4_to_jisx0212 (ch, outptr,			      \
-				      (NEED_LENGTH_TEST			      \
-				       ? outend - outptr : 2));		      \
+	  written = ucs4_to_jisx0212 (ch, outptr, outend - outptr);	      \
 	else if (set == GB2312_set)					      \
-	  written = ucs4_to_gb2312 (ch, outptr, (NEED_LENGTH_TEST	      \
-						 ? outend - outptr : 2));     \
+	  written = ucs4_to_gb2312 (ch, outptr, outend - outptr);	      \
 	else								      \
 	  {								      \
 	    assert (set == KSC5601_set);				      \
 									      \
-	    written = ucs4_to_ksc5601 (ch, outptr,			      \
-				       (NEED_LENGTH_TEST		      \
-					? outend - outptr : 2));	      \
+	    written = ucs4_to_ksc5601 (ch, outptr, outend - outptr);	      \
 	  }								      \
 									      \
-	if (NEED_LENGTH_TEST && __builtin_expect (written, 1) == 0)	      \
+	if (__builtin_expect (written, 1) == 0)				      \
 	  {								      \
 	    result = __GCONV_FULL_OUTPUT;				      \
 	    break;							      \
@@ -631,7 +622,7 @@ gconv_end (struct __gconv_step *data)
 	  {								      \
 	    /* We must encode using ASCII.  First write out the		      \
 	       escape sequence.  */					      \
-	    if (NEED_LENGTH_TEST && __builtin_expect (outptr + 3 > outend, 0))\
+	    if (__builtin_expect (outptr + 3 > outend, 0))		      \
 	      {								      \
 		result = __GCONV_FULL_OUTPUT;				      \
 		break;							      \
@@ -642,7 +633,7 @@ gconv_end (struct __gconv_step *data)
 	    *outptr++ = 'B';						      \
 	    set = ASCII_set;						      \
 									      \
-	    if (NEED_LENGTH_TEST && __builtin_expect (outptr + 1 > outend, 0))\
+	    if (__builtin_expect (outptr + 1 > outend, 0))		      \
 	      {								      \
 		result = __GCONV_FULL_OUTPUT;				      \
 		break;							      \
@@ -666,8 +657,7 @@ gconv_end (struct __gconv_step *data)
 	    if (written != __UNKNOWN_10646_CHAR && buf[0] < 0x80)	      \
 	      {								      \
 		/* We use JIS X 0201.  */				      \
-		if (NEED_LENGTH_TEST					      \
-		    && __builtin_expect (outptr + 3 > outend, 0))	      \
+		if (__builtin_expect (outptr + 3 > outend, 0))		      \
 		  {							      \
 		    result = __GCONV_FULL_OUTPUT;			      \
 		    break;						      \
@@ -678,8 +668,7 @@ gconv_end (struct __gconv_step *data)
 		*outptr++ = 'J';					      \
 		set = JISX0201_Roman_set;				      \
 									      \
-		if (NEED_LENGTH_TEST					      \
-		    && __builtin_expect (outptr + 1 > outend, 0))	      \
+		if (__builtin_expect (outptr + 1 > outend, 0))		      \
 		  {							      \
 		    result = __GCONV_FULL_OUTPUT;			      \
 		    break;						      \
@@ -692,8 +681,7 @@ gconv_end (struct __gconv_step *data)
 		if (written != __UNKNOWN_10646_CHAR)			      \
 		  {							      \
 		    /* We use JIS X 0208.  */				      \
-		    if (NEED_LENGTH_TEST				      \
-			&& __builtin_expect (outptr + 3 > outend, 0))	      \
+		    if (__builtin_expect (outptr + 3 > outend, 0))	      \
 		      {							      \
 			result = __GCONV_FULL_OUTPUT;			      \
 			break;						      \
@@ -704,8 +692,7 @@ gconv_end (struct __gconv_step *data)
 		    *outptr++ = 'B';					      \
 		    set = JISX0208_1983_set;				      \
 									      \
-		    if (NEED_LENGTH_TEST				      \
-			&& __builtin_expect (outptr + 2 > outend, 0))	      \
+		    if (__builtin_expect (outptr + 2 > outend, 0))	      \
 		      {							      \
 			result = __GCONV_FULL_OUTPUT;			      \
 			break;						      \
@@ -716,13 +703,27 @@ gconv_end (struct __gconv_step *data)
 		else if (__builtin_expect (var, iso2022jp2) == iso2022jp)     \
 		  {							      \
 		    /* We have no other choice.  */			      \
-		    if (! ignore_errors_p ())				      \
+		    if (step_data->__trans.__trans_fct != NULL)		      \
+		      {							      \
+			result = DL_CALL_FCT (step_data->__trans.__trans_fct, \
+					      (step, step_data, *inptrp,      \
+					       &inptr, inend, *outptrp,	      \
+					       &outptr, outend,		      \
+					       irreversible));		      \
+			if (result != __GCONV_OK)			      \
+			  break;					      \
+		      }							      \
+		    else if (! ignore_errors_p ())			      \
 		      {							      \
 			result = __GCONV_ILLEGAL_INPUT;			      \
 			break;						      \
 		      }							      \
-									      \
-		    ++*irreversible;					      \
+		    else						      \
+		      {							      \
+			inptr += 4;					      \
+			++*irreversible;				      \
+		      }							      \
+		    continue;						      \
 		  }							      \
 		else							      \
 		  {							      \
@@ -730,8 +731,7 @@ gconv_end (struct __gconv_step *data)
 		    if (written != __UNKNOWN_10646_CHAR)		      \
 		      {							      \
 			/* We use JIS X 0212.  */			      \
-			if (NEED_LENGTH_TEST				      \
-			    && __builtin_expect (outptr + 4 > outend, 0))     \
+			if (__builtin_expect (outptr + 4 > outend, 0))	      \
 			  {						      \
 			    result = __GCONV_FULL_OUTPUT;		      \
 			    break;					      \
@@ -742,8 +742,7 @@ gconv_end (struct __gconv_step *data)
 			*outptr++ = 'D';				      \
 			set = JISX0212_set;				      \
 									      \
-			if (NEED_LENGTH_TEST				      \
-			    && __builtin_expect (outptr + 2 > outend, 0))     \
+			if (__builtin_expect (outptr + 2 > outend, 0))	      \
 			  {						      \
 			    result = __GCONV_FULL_OUTPUT;		      \
 			    break;					      \
@@ -758,8 +757,7 @@ gconv_end (struct __gconv_step *data)
 			    && buf[0] >= 0x80)				      \
 			  {						      \
 			    /* We use JIS X 0201.  */			      \
-			    if (NEED_LENGTH_TEST			      \
-				&& __builtin_expect (outptr + 3 > outend, 0)) \
+			    if (__builtin_expect (outptr + 3 > outend, 0))    \
 			      {						      \
 			        result = __GCONV_FULL_OUTPUT;		      \
 			        break;					      \
@@ -770,8 +768,7 @@ gconv_end (struct __gconv_step *data)
 			    *outptr++ = 'I';				      \
 			    set = JISX0201_Kana_set;			      \
 									      \
-			    if (NEED_LENGTH_TEST			      \
-				&& __builtin_expect (outptr + 1 > outend, 0)) \
+			    if (__builtin_expect (outptr + 1 > outend, 0))    \
 			      {						      \
 			        result = __GCONV_FULL_OUTPUT;		      \
 			        break;					      \
@@ -781,8 +778,7 @@ gconv_end (struct __gconv_step *data)
 			else if (ch != 0xa5 && ch >= 0x80 && ch <= 0xff)      \
 			  {						      \
 			    /* ISO 8859-1 upper half.   */		      \
-			    if (NEED_LENGTH_TEST			      \
-				&& __builtin_expect (outptr + 3 > outend, 0)) \
+			    if (__builtin_expect (outptr + 3 > outend, 0))    \
 			      {						      \
 				result = __GCONV_FULL_OUTPUT;		      \
 				break;					      \
@@ -793,8 +789,7 @@ gconv_end (struct __gconv_step *data)
 			    *outptr++ = 'A';				      \
 			    set2 = ISO88591_set;			      \
 									      \
-			    if (NEED_LENGTH_TEST			      \
-				&& __builtin_expect (outptr + 3 > outend, 0)) \
+			    if (__builtin_expect (outptr + 3 > outend, 0))    \
 			      {						      \
 				result = __GCONV_FULL_OUTPUT;		      \
 				break;					      \
@@ -809,9 +804,7 @@ gconv_end (struct __gconv_step *data)
 			    if (written != __UNKNOWN_10646_CHAR)	      \
 			      {						      \
 				/* We use GB 2312.  */			      \
-				if (NEED_LENGTH_TEST			      \
-				    && __builtin_expect (outptr + 3 > outend, \
-							 0))		      \
+				if (__builtin_expect (outptr + 3 > outend, 0))\
 				  {					      \
 				    result = __GCONV_FULL_OUTPUT;	      \
 				    break;				      \
@@ -822,9 +815,7 @@ gconv_end (struct __gconv_step *data)
 				*outptr++ = 'A';			      \
 				set = GB2312_set;			      \
 									      \
-				if (NEED_LENGTH_TEST			      \
-				    && __builtin_expect (outptr + 2 > outend, \
-							 0))		      \
+				if (__builtin_expect (outptr + 2 > outend, 0))\
 				  {					      \
 				    result = __GCONV_FULL_OUTPUT;	      \
 				    break;				      \
@@ -838,9 +829,8 @@ gconv_end (struct __gconv_step *data)
 				if (written != __UNKNOWN_10646_CHAR)	      \
 				  {					      \
 				    /* We use KSC 5601.  */		      \
-				    if (NEED_LENGTH_TEST		      \
-					&& __builtin_expect (outptr + 4	      \
-							     > outend, 0))    \
+				    if (__builtin_expect (outptr + 4 > outend,\
+							  0))		      \
 				      {					      \
 					result = __GCONV_FULL_OUTPUT;	      \
 					break;				      \
@@ -851,9 +841,8 @@ gconv_end (struct __gconv_step *data)
 				    *outptr++ = 'C';			      \
 				    set = KSC5601_set;			      \
 									      \
-				    if (NEED_LENGTH_TEST		      \
-					&& __builtin_expect (outptr + 2	      \
-							     > outend, 0))    \
+				    if (__builtin_expect (outptr + 2 > outend,\
+							  0))		      \
 				      {					      \
 					result = __GCONV_FULL_OUTPUT;	      \
 					break;				      \
@@ -877,9 +866,8 @@ gconv_end (struct __gconv_step *data)
 				    if (__builtin_expect (gch, 1) != 0)	      \
 				      {					      \
 					/* We use ISO 8859-7 greek.  */	      \
-					if (NEED_LENGTH_TEST		      \
-					    && __builtin_expect (outptr + 3   \
-								 > outend, 0))\
+					if (__builtin_expect (outptr + 3      \
+							      > outend, 0))   \
 					  {				      \
 					    result = __GCONV_FULL_OUTPUT;     \
 					    break;			      \
@@ -889,9 +877,8 @@ gconv_end (struct __gconv_step *data)
 					*outptr++ = 'F';		      \
 					set2 = ISO88597_set;		      \
 									      \
-					if (NEED_LENGTH_TEST		      \
-					    && __builtin_expect (outptr + 3   \
-								 > outend, 0))\
+					if (__builtin_expect (outptr + 3      \
+							      > outend, 0))   \
 					  {				      \
 					    result = __GCONV_FULL_OUTPUT;     \
 					    break;			      \
@@ -902,13 +889,29 @@ gconv_end (struct __gconv_step *data)
 				      }					      \
 				    else				      \
 				      {					      \
-					if (! ignore_errors_p ())	      \
+					if (step_data->__trans.__trans_fct    \
+					    != NULL)			      \
+					  {				      \
+					    result = DL_CALL_FCT	      \
+  					      (step_data->__trans.__trans_fct,\
+					       (step, step_data, *inptrp,     \
+						&inptr, inend, *outptrp,      \
+						&outptr, outend,	      \
+						irreversible));		      \
+					    if (result != __GCONV_OK)	      \
+					      break;			      \
+					  }				      \
+					else if (! ignore_errors_p ())	      \
 					  {				      \
 					     result = __GCONV_ILLEGAL_INPUT;  \
 					     break;			      \
 					  }				      \
-									      \
-					++*irreversible;		      \
+					else				      \
+					  {				      \
+					    ++*irreversible;		      \
+					    inptr += 4;			      \
+					  }				      \
+					continue;			      \
 				      }					      \
 				  }					      \
 			      }						      \
@@ -922,6 +925,7 @@ gconv_end (struct __gconv_step *data)
     /* Now that we wrote the output increment the input pointer.  */	      \
     inptr += 4;								      \
   }
+#define LOOP_NEED_FLAGS
 #define EXTRA_LOOP_DECLS	, enum variant var, int *setp
 #define INIT_PARAMS		int set = *setp & CURRENT_SEL_MASK;	      \
 				int set2 = *setp & CURRENT_ASSIGN_MASK
diff --git a/iconvdata/iso-2022-kr.c b/iconvdata/iso-2022-kr.c
index 99208c9522..4601e22e68 100644
--- a/iconvdata/iso-2022-kr.c
+++ b/iconvdata/iso-2022-kr.c
@@ -18,6 +18,7 @@
    write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
    Boston, MA 02111-1307, USA.  */
 
+#include <dlfcn.h>
 #include <gconv.h>
 #include <stdint.h>
 #include <string.h>
@@ -141,10 +142,9 @@ enum
 	   switching is done using the SI and SO bytes.  But we have to	      \
 	   recognize `Esc $ ) C' since this is a kind of flag for this	      \
 	   encoding.  We simply ignore it.  */				      \
-	if ((NEED_LENGTH_TEST && __builtin_expect (inptr + 1 > inend, 0))     \
+	if (__builtin_expect (inptr + 1 > inend, 0)			      \
 	    || (inptr[1] == '$'						      \
-		&& ((NEED_LENGTH_TEST					      \
-		     && __builtin_expect (inptr + 2 > inend, 0))	      \
+		&& (__builtin_expect (inptr + 2 > inend, 0)		      \
 		    || (inptr[2] == ')'					      \
 			&& __builtin_expect (inptr + 3 > inend, 0)))))	      \
 									      \
@@ -184,10 +184,9 @@ enum
 	assert (set == KSC5601_set);					      \
 									      \
 	/* Use the KSC 5601 table.  */					      \
-	ch = ksc5601_to_ucs4 (&inptr,					      \
-			      NEED_LENGTH_TEST ? inend - inptr : 2, 0);	      \
+	ch = ksc5601_to_ucs4 (&inptr, inend - inptr, 0);		      \
 									      \
-	if (NEED_LENGTH_TEST && __builtin_expect (ch, 1) == 0)		      \
+	if (__builtin_expect (ch, 1) == 0)				      \
 	  {								      \
 	    result = __GCONV_EMPTY_INPUT;				      \
 	    break;							      \
@@ -210,6 +209,7 @@ enum
     put32 (outptr, ch);							      \
     outptr += 4;							      \
   }
+#define LOOP_NEED_FLAGS
 #define EXTRA_LOOP_DECLS	, int *setp
 #define INIT_PARAMS		int set = *setp
 #define UPDATE_PARAMS		*setp = set
@@ -236,7 +236,7 @@ enum
 	  {								      \
 	    *outptr++ = SI;						      \
 	    set = ASCII_set;						      \
-	    if (NEED_LENGTH_TEST && outptr == outend)			      \
+	    if (__builtin_expect (outptr == outend, 0))			      \
 	      {								      \
 		result = __GCONV_FULL_OUTPUT;				      \
 		break;							      \
@@ -255,13 +255,26 @@ enum
 	if (__builtin_expect (written, 0) == __UNKNOWN_10646_CHAR)	      \
 	  {								      \
 	    /* Illegal character.  */					      \
-	    if (! ignore_errors_p ())					      \
+	    if (step_data->__trans.__trans_fct != NULL)			      \
+	      {								      \
+		result = DL_CALL_FCT (step_data->__trans.__trans_fct,	      \
+				      (step, step_data, *inptrp, &inptr,      \
+				       inend, *outptrp, &outptr, outend,      \
+				       irreversible));			      \
+		if (result != __GCONV_OK)				      \
+		  break;						      \
+	      }								      \
+	    else if (! ignore_errors_p ())				      \
 	      {								      \
 		result = __GCONV_ILLEGAL_INPUT;				      \
 		break;							      \
 	      }								      \
-									      \
-	    ++*irreversible;						      \
+	    else							      \
+	      {								      \
+		++*irreversible;					      \
+		inptr += 4;						      \
+	      }								      \
+	    continue;							      \
 	  }								      \
 	else								      \
 	  {								      \
@@ -274,7 +287,7 @@ enum
 		set = KSC5601_set;					      \
 	      }								      \
 									      \
-	    if (NEED_LENGTH_TEST && __builtin_expect (outptr + 2 > outend, 0))\
+	    if (__builtin_expect (outptr + 2 > outend, 0))		      \
 	      {								      \
 		result = __GCONV_FULL_OUTPUT;				      \
 		break;							      \
@@ -288,6 +301,7 @@ enum
     /* Now that we wrote the output increment the input pointer.  */	      \
     inptr += 4;								      \
   }
+#define LOOP_NEED_FLAGS
 #define EXTRA_LOOP_DECLS	, int *setp
 #define INIT_PARAMS		int set = *setp
 #define UPDATE_PARAMS		*setp = set
diff --git a/iconvdata/iso646.c b/iconvdata/iso646.c
index cdc77fc651..f39f1b4d6d 100644
--- a/iconvdata/iso646.c
+++ b/iconvdata/iso646.c
@@ -31,6 +31,7 @@
    allows one to easily provide a tuned implementation in case this
    proofs to be necessary.  */
 
+#include <dlfcn.h>
 #include <gconv.h>
 #include <stdint.h>
 #include <stdlib.h>
@@ -422,6 +423,7 @@ gconv_end (struct __gconv_step *data)
       }									      \
     ++inptr;								      \
   }
+#define LOOP_NEED_FLAGS
 #define EXTRA_LOOP_DECLS	, enum variant var
 #include <iconv/loop.c>
 
@@ -883,19 +885,32 @@ gconv_end (struct __gconv_step *data)
 									      \
     if (__builtin_expect (failure, __GCONV_OK) == __GCONV_ILLEGAL_INPUT)      \
       {									      \
-	if (! ignore_errors_p ())					      \
+	if (step_data->__trans.__trans_fct != NULL)			      \
+	  {								      \
+	    result = DL_CALL_FCT (step_data->__trans.__trans_fct,	      \
+				  (step, step_data, *inptrp, &inptr, inend,   \
+				   *outptrp, &outptr, outend, irreversible)); \
+	    if (result != __GCONV_OK)					      \
+	      break;							      \
+	  }								      \
+	else if (! ignore_errors_p ())					      \
 	  {								      \
 	    /* Exit the loop with an error.  */				      \
 	    result = __GCONV_ILLEGAL_INPUT;				      \
 	    break;							      \
 	  }								      \
-									      \
-	++*irreversible;						      \
+	else								      \
+	  {								      \
+	    ++*irreversible;						      \
+	    inptr += 4;							      \
+	  }								      \
+	continue;							      \
       }									      \
     else								      \
       *outptr++ = (unsigned char) ch;					      \
     inptr += 4;								      \
   }
+#define LOOP_NEED_FLAGS
 #define EXTRA_LOOP_DECLS	, enum variant var
 #include <iconv/loop.c>
 
diff --git a/iconvdata/iso8859-1.c b/iconvdata/iso8859-1.c
index 7a5be60373..fb1fabc4f6 100644
--- a/iconvdata/iso8859-1.c
+++ b/iconvdata/iso8859-1.c
@@ -18,6 +18,7 @@
    write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
    Boston, MA 02111-1307, USA.  */
 
+#include <dlfcn.h>
 #include <stdint.h>
 
 /* Definitions used in the body of the `gconv' function.  */
@@ -48,18 +49,31 @@
     if (__builtin_expect (ch, 0) > 0xff)				      \
       {									      \
 	/* We have an illegal character.  */				      \
-	if (! ignore_errors_p ())					      \
+	if (step_data->__trans.__trans_fct != NULL)			      \
+	  {								      \
+	    result = DL_CALL_FCT (step_data->__trans.__trans_fct,	      \
+				  (step, step_data, *inptrp, &inptr, inend,   \
+				   *outptrp, &outptr, outend, irreversible)); \
+	    if (result != __GCONV_OK)					      \
+	      break;							      \
+	  }								      \
+	else if (! ignore_errors_p ())					      \
 	  {								      \
 	    result = __GCONV_ILLEGAL_INPUT;				      \
 	    break;							      \
 	  }								      \
-									      \
-	++*irreversible;						      \
+	else								      \
+	  {								      \
+	    inptr += 4;							      \
+	    ++*irreversible;						      \
+	  }								      \
+	continue;							      \
       }									      \
     else								      \
       *outptr++ = (unsigned char) ch;					      \
     inptr += 4;								      \
   }
+#define LOOP_NEED_FLAGS
 #include <iconv/loop.c>
 
 
diff --git a/iconvdata/iso_6937-2.c b/iconvdata/iso_6937-2.c
index 6895879744..4f5a8689b8 100644
--- a/iconvdata/iso_6937-2.c
+++ b/iconvdata/iso_6937-2.c
@@ -18,6 +18,7 @@
    write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
    Boston, MA 02111-1307, USA.  */
 
+#include <dlfcn.h>
 #include <stdint.h>
 
 /* Data taken from the WG15 tables.  */
@@ -405,7 +406,7 @@ static const char from_ucs4[][2] =
 	   is also available.  */					      \
 	int ch2;							      \
 									      \
-	if (NEED_LENGTH_TEST && __builtin_expect (inptr + 1 >= inend, 0))     \
+	if (__builtin_expect (inptr + 1 >= inend, 0))			      \
 	  {								      \
 	    /* The second character is not available.  Store the	      \
 	       intermediate result.  */					      \
@@ -474,6 +475,7 @@ static const char from_ucs4[][2] =
     put32 (outptr, ch);							      \
     outptr += 4;							      \
   }
+#define LOOP_NEED_FLAGS
 #include <iconv/loop.c>
 
 
@@ -491,7 +493,6 @@ static const char from_ucs4[][2] =
     if (__builtin_expect (ch, 0)					      \
 	>= sizeof (from_ucs4) / sizeof (from_ucs4[0]))			      \
       {									      \
-	int fail = 0;							      \
 	switch (ch)							      \
 	  {								      \
 	  case 0x2c7:							      \
@@ -562,36 +563,52 @@ static const char from_ucs4[][2] =
 	    cp = "\xd5";						      \
 	    break;							      \
 	  default:							      \
-	    cp = NULL;							      \
-	    fail = 1;							      \
-	  }								      \
-									      \
-	if (__builtin_expect (fail, 0))					      \
-	  {								      \
 	    /* Illegal characters.  */					      \
-	    if (! ignore_errors_p ())					      \
+	    cp = NULL;							      \
+	    if (step_data->__trans.__trans_fct != NULL)			      \
+	      {								      \
+		result = DL_CALL_FCT (step_data->__trans.__trans_fct,	      \
+				      (step, step_data, *inptrp, &inptr,      \
+				       inend, *outptrp, &outptr, outend,      \
+				       irreversible));			      \
+		if (result != __GCONV_OK)				      \
+		  break;						      \
+	      }								      \
+	    else if (! ignore_errors_p ())				      \
 	      {								      \
 	        /* This is an illegal character.  */			      \
 		result = __GCONV_ILLEGAL_INPUT;				      \
 		break;							      \
 	      }								      \
-									      \
-	    inptr += 4;							      \
-	    ++*irreversible;						      \
+	    else							      \
+	      {								      \
+		inptr += 4;						      \
+		++*irreversible;					      \
+	      }								      \
 	    continue;							      \
 	  }								      \
       }									      \
     else if (__builtin_expect (from_ucs4[ch][0], '\1') == '\0' && ch != 0)    \
       {									      \
 	/* Illegal characters.  */					      \
-	if (! ignore_errors_p ())					      \
+	if (step_data->__trans.__trans_fct != NULL)			      \
+	  {								      \
+	    result = DL_CALL_FCT (step_data->__trans.__trans_fct,	      \
+				  (step, step_data, *inptrp, &inptr, inend,   \
+				   *outptrp, &outptr, outend, irreversible)); \
+	    if (result != __GCONV_OK)					      \
+	      break;							      \
+	  }								      \
+	else if (! ignore_errors_p ())					      \
 	  {								      \
 	    result = __GCONV_ILLEGAL_INPUT;				      \
 	    break;							      \
 	  }								      \
-									      \
-	++*irreversible;						      \
-	inptr += 4;							      \
+	else								      \
+	  {								      \
+	    inptr += 4;							      \
+	    ++*irreversible;						      \
+	  }								      \
 	continue;							      \
       }									      \
     else								      \
@@ -601,7 +618,7 @@ static const char from_ucs4[][2] =
     /* Now test for a possible second byte and write this if possible.  */    \
     if (cp[1] != '\0')							      \
       {									      \
-	if (NEED_LENGTH_TEST && __builtin_expect (outptr >= outend, 0))	      \
+	if (__builtin_expect (outptr >= outend, 0))			      \
 	  {								      \
 	    /* The result does not fit into the buffer.  */		      \
 	    --outptr;							      \
@@ -613,6 +630,7 @@ static const char from_ucs4[][2] =
 									      \
     inptr += 4;								      \
   }
+#define LOOP_NEED_FLAGS
 #include <iconv/loop.c>
 
 
diff --git a/iconvdata/iso_6937.c b/iconvdata/iso_6937.c
index d27b923689..b7ab0841eb 100644
--- a/iconvdata/iso_6937.c
+++ b/iconvdata/iso_6937.c
@@ -18,6 +18,7 @@
    write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
    Boston, MA 02111-1307, USA.  */
 
+#include <dlfcn.h>
 #include <stdint.h>
 
 /* Data taken from the WG15 tables.  */
@@ -397,7 +398,7 @@ static const char from_ucs4[][2] =
 	   is also available.  */					      \
 	int ch2;							      \
 									      \
-	if (NEED_LENGTH_TEST && __builtin_expect (inptr + 1 >= inend, 0))     \
+	if (__builtin_expect (inptr + 1 >= inend, 0))			      \
 	  {								      \
 	    /* The second character is not available.  Store the	      \
 	       intermediate result.  */					      \
@@ -466,6 +467,7 @@ static const char from_ucs4[][2] =
     put32 (outptr, ch);							      \
     outptr += 4;							      \
   }
+#define LOOP_NEED_FLAGS
 #include <iconv/loop.c>
 
 
@@ -540,29 +542,50 @@ static const char from_ucs4[][2] =
 	if (__builtin_expect (fail, 0))					      \
 	  {								      \
 	    /* Illegal characters.  */					      \
-	    if (! ignore_errors_p ())					      \
+	    if (step_data->__trans.__trans_fct != NULL)			      \
+	      {								      \
+		result = DL_CALL_FCT (step_data->__trans.__trans_fct,	      \
+				      (step, step_data, *inptrp, &inptr,      \
+				       inend, *outptrp, &outptr, outend,      \
+				       irreversible));			      \
+		if (result != __GCONV_OK)				      \
+		  break;						      \
+	      }								      \
+	    else if (! ignore_errors_p ())				      \
 	      {								      \
 	        /* This is an illegal character.  */			      \
 		result = __GCONV_ILLEGAL_INPUT;				      \
 		break;							      \
 	      }								      \
-									      \
-	    inptr += 4;							      \
-	    ++*irreversible;						      \
+	    else							      \
+	      {								      \
+		inptr += 4;						      \
+		++*irreversible;					      \
+	      }								      \
 	    continue;							      \
 	  }								      \
       }									      \
     else if (__builtin_expect (from_ucs4[ch][0], '\1') == '\0' && ch != 0)    \
       {									      \
 	/* Illegal characters.  */					      \
-	if (! ignore_errors_p ())					      \
+	if (step_data->__trans.__trans_fct != NULL)			      \
+	  {								      \
+	    result = DL_CALL_FCT (step_data->__trans.__trans_fct,	      \
+				  (step, step_data, *inptrp, &inptr, inend,   \
+				   *outptrp, &outptr, outend, irreversible)); \
+	    if (result != __GCONV_OK)					      \
+	      break;							      \
+	  }								      \
+	else if (! ignore_errors_p ())					      \
 	  {								      \
 	    result = __GCONV_ILLEGAL_INPUT;				      \
 	    break;							      \
 	  }								      \
-									      \
-	++*irreversible;						      \
-	inptr += 4;							      \
+	else								      \
+	  {								      \
+	    inptr += 4;							      \
+	    ++*irreversible;						      \
+	  }								      \
 	continue;							      \
       }									      \
     else								      \
@@ -572,7 +595,7 @@ static const char from_ucs4[][2] =
     /* Now test for a possible second byte and write this if possible.  */    \
     if (cp[1] != '\0')							      \
       {									      \
-	if (NEED_LENGTH_TEST && __builtin_expect (outptr >= outend, 0))	      \
+	if (__builtin_expect (outptr >= outend, 0))			      \
 	  {								      \
 	    /* The result does not fit into the buffer.  */		      \
 	    --outptr;							      \
@@ -584,6 +607,7 @@ static const char from_ucs4[][2] =
 									      \
     inptr += 4;								      \
   }
+#define LOOP_NEED_FLAGS
 #include <iconv/loop.c>
 
 
diff --git a/iconvdata/johab.c b/iconvdata/johab.c
index 50b974686b..7253ff6cb8 100644
--- a/iconvdata/johab.c
+++ b/iconvdata/johab.c
@@ -19,6 +19,7 @@
    write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
    Boston, MA 02111-1307, USA.  */
 
+#include <dlfcn.h>
 #include <stdint.h>
 #include <ksc5601.h>
 
@@ -203,7 +204,7 @@ johab_sym_hanja_to_ucs (uint_fast32_t idx, uint_fast32_t c1, uint_fast32_t c2)
 	    uint32_t ch2;						      \
 	    uint_fast32_t idx;						      \
 									      \
-	    if (NEED_LENGTH_TEST && __builtin_expect (inptr + 1 >= inend, 0)) \
+	    if (__builtin_expect (inptr + 1 >= inend, 0))		      \
 	      {								      \
 		/* The second character is not available.  Store the	      \
 		   intermediate result.  */				      \
@@ -319,6 +320,7 @@ johab_sym_hanja_to_ucs (uint_fast32_t idx, uint_fast32_t c1, uint_fast32_t c2)
     put32 (outptr, ch);							      \
     outptr += 4;							      \
   }
+#define LOOP_NEED_FLAGS
 #include <iconv/loop.c>
 
 
@@ -350,7 +352,7 @@ johab_sym_hanja_to_ucs (uint_fast32_t idx, uint_fast32_t c1, uint_fast32_t c2)
       {									      \
 	if (ch >= 0xac00 && ch <= 0xd7a3)				      \
 	  {								      \
-	    if (NEED_LENGTH_TEST && __builtin_expect (outptr + 2 > outend, 0))\
+	    if (__builtin_expect (outptr + 2 > outend, 0))		      \
 	      {								      \
 		result = __GCONV_FULL_OUTPUT;				      \
 		break;							      \
@@ -371,7 +373,7 @@ johab_sym_hanja_to_ucs (uint_fast32_t idx, uint_fast32_t c1, uint_fast32_t c2)
 	  {								      \
 	    ch = jamo_from_ucs_table[ch - 0x3131];			      \
 									      \
-	    if (NEED_LENGTH_TEST && __builtin_expect (outptr + 2 > outend, 0))\
+	    if (__builtin_expect (outptr + 2 > outend, 0))		      \
 	      {								      \
 		result = __GCONV_FULL_OUTPUT;				      \
 		break;							      \
@@ -386,25 +388,34 @@ johab_sym_hanja_to_ucs (uint_fast32_t idx, uint_fast32_t c1, uint_fast32_t c2)
 	    size_t written;						      \
 	    uint32_t temp;						      \
 									      \
-	    written = ucs4_to_ksc5601_hanja (ch, outptr,		      \
-					     (NEED_LENGTH_TEST		      \
-					      ? outend - outptr : 2));	      \
-	    if (NEED_LENGTH_TEST && __builtin_expect (written, 1) == 0)	      \
+	    written = ucs4_to_ksc5601_hanja (ch, outptr, outend - outptr);    \
+	    if (__builtin_expect (written, 1) == 0)			      \
 	      {								      \
 		result = __GCONV_FULL_OUTPUT;				      \
 		break;							      \
 	      }								      \
 	    if (__builtin_expect (written, 0) == __UNKNOWN_10646_CHAR)	      \
 	      {								      \
-		if (! ignore_errors_p ())				      \
+		if (step_data->__trans.__trans_fct != NULL)		      \
+		  {							      \
+		    result = DL_CALL_FCT (step_data->__trans.__trans_fct,     \
+					  (step, step_data, *inptrp, &inptr,  \
+ 					   inend, *outptrp, &outptr, outend,  \
+					   irreversible));		      \
+		    if (result != __GCONV_OK)				      \
+		      break;						      \
+		  }							      \
+		else if (! ignore_errors_p ())				      \
 		  {							      \
 		    /* This is an illegal character.  */		      \
 		    result = __GCONV_ILLEGAL_INPUT;			      \
 		    break;						      \
 		  }							      \
-									      \
-		inptr += 4;						      \
-		++*irreversible;					      \
+		else							      \
+		  {							      \
+		    inptr += 4;						      \
+		    ++*irreversible;					      \
+		  }							      \
 		continue;						      \
 	      }								      \
 									      \
@@ -423,25 +434,34 @@ johab_sym_hanja_to_ucs (uint_fast32_t idx, uint_fast32_t c1, uint_fast32_t c2)
 	  {								      \
 	    size_t written;						      \
 									      \
-	    written = ucs4_to_ksc5601_sym (ch, outptr,			      \
-					   (NEED_LENGTH_TEST		      \
-					    ? outend - outptr : 2));	      \
-	    if (NEED_LENGTH_TEST && __builtin_expect (written, 1) == 0)	      \
+	    written = ucs4_to_ksc5601_sym (ch, outptr, outend - outptr);      \
+	    if (__builtin_expect (written, 1) == 0)			      \
 	      {								      \
 		result = __GCONV_FULL_OUTPUT;				      \
 		break;							      \
 	      }								      \
 	    if (__builtin_expect (written, 1) == __UNKNOWN_10646_CHAR)	      \
 	      {								      \
-		if (! ignore_errors_p ())				      \
+		if (step_data->__trans.__trans_fct != NULL)		      \
+		  {							      \
+		    result = DL_CALL_FCT (step_data->__trans.__trans_fct,     \
+					  (step, step_data, *inptrp, &inptr,  \
+					   inend, *outptrp, &outptr, outend,  \
+					   irreversible));		      \
+		    if (result != __GCONV_OK)				      \
+		      break;						      \
+		  }							      \
+		else if (! ignore_errors_p ())				      \
 		  {							      \
 		    /* This is an illegal character.  */		      \
 		    result = __GCONV_ILLEGAL_INPUT;			      \
 		    break;						      \
 		  }							      \
-									      \
-		inptr += 4;						      \
-		++*irreversible;					      \
+		else							      \
+		  {							      \
+		    inptr += 4;						      \
+		    ++*irreversible;					      \
+		  }							      \
 		continue;						      \
 	      }								      \
 									      \
@@ -460,6 +480,7 @@ johab_sym_hanja_to_ucs (uint_fast32_t idx, uint_fast32_t c1, uint_fast32_t c2)
 									      \
     inptr += 4;								      \
   }
+#define LOOP_NEED_FLAGS
 #include <iconv/loop.c>
 
 
diff --git a/iconvdata/sjis.c b/iconvdata/sjis.c
index 0f38362fb3..2641b24743 100644
--- a/iconvdata/sjis.c
+++ b/iconvdata/sjis.c
@@ -18,6 +18,7 @@
    write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
    Boston, MA 02111-1307, USA.  */
 
+#include <dlfcn.h>
 #include <stdint.h>
 #include <wchar.h>
 
@@ -4377,7 +4378,7 @@ static const char from_ucs4_extra[0x100][2] =
 	uint32_t ch2;							      \
 	uint_fast32_t idx;						      \
 									      \
-	if (NEED_LENGTH_TEST && __builtin_expect (inptr + 1 >= inend, 0))     \
+	if (__builtin_expect (inptr + 1 >= inend, 0))			      \
 	  {								      \
 	    /* The second character is not available.  Store		      \
 	       the intermediate result.  */				      \
@@ -4441,6 +4442,7 @@ static const char from_ucs4_extra[0x100][2] =
     put32 (outptr, ch);							      \
     outptr += 4;							      \
   }
+#define LOOP_NEED_FLAGS
 #include <iconv/loop.c>
 
 
@@ -4466,15 +4468,26 @@ static const char from_ucs4_extra[0x100][2] =
 	else								      \
 	  {								      \
 	    /* Illegal character.  */					      \
-	    if (! ignore_errors_p ())					      \
+	    if (step_data->__trans.__trans_fct != NULL)			      \
+	      {								      \
+		result = DL_CALL_FCT (step_data->__trans.__trans_fct,	      \
+				      (step, step_data, *inptrp, &inptr,      \
+				       inend, *outptrp, &outptr, outend,      \
+				       irreversible));			      \
+		if (result != __GCONV_OK)				      \
+		  break;						      \
+	      }								      \
+	    else if (! ignore_errors_p ())				      \
 	      {								      \
 	        /* This is an illegal character.  */			      \
 		result = __GCONV_ILLEGAL_INPUT;				      \
 		break;							      \
 	      }								      \
-									      \
-	    inptr += 4;							      \
-	    ++*irreversible;						      \
+	    else							      \
+	      {								      \
+		inptr += 4;						      \
+		++*irreversible;					      \
+	      }								      \
 	    continue;							      \
 	  }								      \
       }									      \
@@ -4484,14 +4497,26 @@ static const char from_ucs4_extra[0x100][2] =
     if (__builtin_expect (cp[0], '\1') == '\0' && ch != 0)		      \
       {									      \
 	/* Illegal character.  */					      \
-	if (! ignore_errors_p ())					      \
+	if (step_data->__trans.__trans_fct != NULL)			      \
+	  {								      \
+	    result = DL_CALL_FCT (step_data->__trans.__trans_fct,	      \
+				  (step, step_data, *inptrp, &inptr, inend,   \
+				   *outptrp, &outptr, outend, irreversible)); \
+	    if (result != __GCONV_OK)					      \
+	      break;							      \
+	  }								      \
+	else if (! ignore_errors_p ())					      \
 	  {								      \
 	    /* This is an illegal character.  */			      \
 	    result = __GCONV_ILLEGAL_INPUT;				      \
 	    break;							      \
 	  }								      \
-									      \
-	++*irreversible;						      \
+	else								      \
+	  {								      \
+	    inptr += 4;							      \
+	    ++*irreversible;						      \
+	  }								      \
+	continue;							      \
       }									      \
     else								      \
       {									      \
@@ -4499,7 +4524,7 @@ static const char from_ucs4_extra[0x100][2] =
 	/* Now test for a possible second byte and write this if possible.  */\
 	if (cp[1] != '\0')						      \
 	  {								      \
-	    if (NEED_LENGTH_TEST && __builtin_expect (outptr >= outend, 0))   \
+	    if (__builtin_expect (outptr >= outend, 0))			      \
 	      {								      \
 		/* The result does not fit into the buffer.  */		      \
 		result = __GCONV_FULL_OUTPUT;				      \
@@ -4511,6 +4536,7 @@ static const char from_ucs4_extra[0x100][2] =
 									      \
     inptr += 4;								      \
   }
+#define LOOP_NEED_FLAGS
 #include <iconv/loop.c>
 
 
diff --git a/iconvdata/t.61.c b/iconvdata/t.61.c
index 74fbf8aca7..991cce1626 100644
--- a/iconvdata/t.61.c
+++ b/iconvdata/t.61.c
@@ -18,6 +18,7 @@
    write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
    Boston, MA 02111-1307, USA.  */
 
+#include <dlfcn.h>
 #include <gconv.h>
 #include <stdint.h>
 #include <string.h>
@@ -390,7 +391,7 @@ static const char from_ucs4[][2] =
 	   is also available.  */					      \
 	uint32_t ch2;							      \
 									      \
-	if (NEED_LENGTH_TEST && __builtin_expect (inptr + 1 >= inend, 0))     \
+	if (__builtin_expect (inptr + 1 >= inend, 0))			      \
 	  {								      \
 	    /* The second character is not available.  */		      \
 	    result = __GCONV_INCOMPLETE_INPUT;				      \
@@ -441,6 +442,7 @@ static const char from_ucs4[][2] =
       }									      \
     inptr += increment;							      \
   }
+#define LOOP_NEED_FLAGS
 #include <iconv/loop.c>
 
 
@@ -467,15 +469,26 @@ static const char from_ucs4[][2] =
 		 || __builtin_expect (ch, 0x2d8) == 0x02dc)		      \
 	  {								      \
 	    /* Illegal characters.  */					      \
-	    if (! ignore_errors_p ())					      \
+	    if (step_data->__trans.__trans_fct != NULL)			      \
+	      {								      \
+		result = DL_CALL_FCT (step_data->__trans.__trans_fct,	      \
+				      (step, step_data, *inptrp, &inptr,      \
+ 				       inend, *outptrp, &outptr, outend,      \
+				       irreversible));			      \
+		if (result != __GCONV_OK)				      \
+		  break;						      \
+	      }								      \
+	    else if (! ignore_errors_p ())				      \
 	      {								      \
 	        /* This is an illegal character.  */			      \
 		result = __GCONV_ILLEGAL_INPUT;				      \
 		break;							      \
 	      }								      \
-									      \
-	    inptr += 4;							      \
-	    ++*irreversible;						      \
+	    else							      \
+	      {								      \
+		inptr += 4;						      \
+		++*irreversible;					      \
+	      }								      \
 	    continue;							      \
 	  }								      \
 	else								      \
@@ -494,15 +507,26 @@ static const char from_ucs4[][2] =
 	if (__builtin_expect (cp[0], '\1') == '\0' && ch != 0)		      \
 	  {								      \
 	    /* Illegal.  */						      \
-	    if (! ignore_errors_p ())					      \
+	    if (step_data->__trans.__trans_fct != NULL)			      \
+	      {								      \
+		result = DL_CALL_FCT (step_data->__trans.__trans_fct,	      \
+				      (step, step_data, *inptrp, &inptr,      \
+				       inend, *outptrp, &outptr, outend,      \
+				       irreversible));			      \
+		if (result != __GCONV_OK)				      \
+		  break;						      \
+	      }								      \
+	    else if (! ignore_errors_p ())				      \
 	      {								      \
 	        /* This is an illegal character.  */			      \
 		result = __GCONV_ILLEGAL_INPUT;				      \
 		break;							      \
 	      }								      \
-									      \
-	    inptr += 4;							      \
-	    ++*irreversible;						      \
+	    else							      \
+	      {								      \
+		inptr += 4;						      \
+		++*irreversible;					      \
+	      }								      \
 	    continue;							      \
 	  }								      \
       }									      \
@@ -511,7 +535,7 @@ static const char from_ucs4[][2] =
     /* Now test for a possible second byte and write this if possible.  */    \
     if (cp[1] != '\0')							      \
       {									      \
-	if (NEED_LENGTH_TEST && __builtin_expect (outptr >= outend, 0))	      \
+	if (__builtin_expect (outptr >= outend, 0))			      \
 	  {								      \
 	    /* The result does not fit into the buffer.  */		      \
 	    --outptr;							      \
@@ -524,6 +548,7 @@ static const char from_ucs4[][2] =
 									      \
     inptr += 4;								      \
   }
+#define LOOP_NEED_FLAGS
 #include <iconv/loop.c>
 
 
diff --git a/iconvdata/uhc.c b/iconvdata/uhc.c
index d62f93bf29..232e5c8416 100644
--- a/iconvdata/uhc.c
+++ b/iconvdata/uhc.c
@@ -18,6 +18,7 @@
    write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
    Boston, MA 02111-1307, USA.  */
 
+#include <dlfcn.h>
 #include <stdint.h>
 #include <ksc5601.h>
 
@@ -3085,7 +3086,7 @@ static const char uhc_hangul_from_ucs[11172][2] =
 	   is also available.  */					      \
 	uint32_t ch2;							      \
 									      \
-	if (NEED_LENGTH_TEST && __builtin_expect (inptr + 1 >= inend, 0))     \
+	if (__builtin_expect (inptr + 1 >= inend, 0))			      \
 	  {								      \
 	    /* The second character is not available.  Store		      \
 	       the intermediate result.  */				      \
@@ -3180,6 +3181,7 @@ static const char uhc_hangul_from_ucs[11172][2] =
     put32 (outptr, ch);							      \
     outptr += 4;							      \
   }
+#define LOOP_NEED_FLAGS
 #include <iconv/loop.c>
 
 
@@ -3199,7 +3201,7 @@ static const char uhc_hangul_from_ucs[11172][2] =
       {									      \
 	const char *s = uhc_hangul_from_ucs[ch - 0xac00];		      \
 									      \
-	if (NEED_LENGTH_TEST && __builtin_expect (outptr + 2 > outend, 0))    \
+	if (__builtin_expect (outptr + 2 > outend, 0))			      \
 	  {								      \
 	    result = __GCONV_FULL_OUTPUT;				      \
 	    break;							      \
@@ -3210,26 +3212,35 @@ static const char uhc_hangul_from_ucs[11172][2] =
       }									      \
     else if ((ch >= 0x4e00 && ch <= 0x9fa5) || (ch >= 0xf900 && ch <= 0xfa0b))\
       {									      \
-	size_t written = ucs4_to_ksc5601_hanja (ch, outptr,		      \
-						(NEED_LENGTH_TEST	      \
-						 ? outend - outptr : 2));     \
+	size_t written = ucs4_to_ksc5601_hanja (ch, outptr, outend - outptr); \
 									      \
-	if (NEED_LENGTH_TEST && __builtin_expect (written, 1) == 0)	      \
+	if (__builtin_expect (written, 1) == 0)				      \
 	  {								      \
 	    result = __GCONV_FULL_OUTPUT;				      \
 	    break;							      \
 	  }								      \
 	if (__builtin_expect (written, 0) == __UNKNOWN_10646_CHAR)	      \
 	  {								      \
-	    if (! ignore_errors_p ())					      \
+	    if (step_data->__trans.__trans_fct != NULL)			      \
+	      {								      \
+		result = DL_CALL_FCT (step_data->__trans.__trans_fct,	      \
+				      (step, step_data, *inptrp, &inptr,      \
+				       inend, *outptrp, &outptr, outend,      \
+				       irreversible));			      \
+		if (result != __GCONV_OK)				      \
+		  break;						      \
+	      }								      \
+	    else if (! ignore_errors_p ())				      \
 	      {								      \
 	        /* This is an illegal character.  */			      \
 		result = __GCONV_ILLEGAL_INPUT;				      \
 		break;							      \
 	      }								      \
-									      \
-	    inptr += 4;							      \
-	    ++*irreversible;						      \
+	    else							      \
+	      {								      \
+		inptr += 4;						      \
+		++*irreversible;					      \
+	      }								      \
 	    continue;							      \
 	  }								      \
 									      \
@@ -3242,26 +3253,35 @@ static const char uhc_hangul_from_ucs[11172][2] =
 */									      \
     else								      \
       {									      \
-	size_t written = ucs4_to_ksc5601_sym (ch, outptr,		      \
-					      (NEED_LENGTH_TEST		      \
-					       ? outend - outptr : 2));	      \
+	size_t written = ucs4_to_ksc5601_sym (ch, outptr, outend - outptr);   \
 									      \
-	if (NEED_LENGTH_TEST && __builtin_expect (written, 1) == 0)	      \
+	if (__builtin_expect (written, 1) == 0)				      \
 	  {								      \
 	    result = __GCONV_FULL_OUTPUT;				      \
 	    break;							      \
 	  }								      \
 	if (__builtin_expect (written, 0) == __UNKNOWN_10646_CHAR)	      \
 	  {								      \
-	    if (! ignore_errors_p ())					      \
+	    if (step_data->__trans.__trans_fct != NULL)			      \
+	      {								      \
+		result = DL_CALL_FCT (step_data->__trans.__trans_fct,	      \
+				      (step, step_data, *inptrp, &inptr,      \
+				       inend, *outptrp, &outptr, outend,      \
+				       irreversible));			      \
+		if (result != __GCONV_OK)				      \
+		  break;						      \
+	      }								      \
+	    else if (! ignore_errors_p ())				      \
 	      {								      \
 	        /* This is an illegal character.  */			      \
 		result = __GCONV_ILLEGAL_INPUT;				      \
 		break;							      \
 	      }								      \
-									      \
-	    inptr += 4;							      \
-	    ++*irreversible;						      \
+	    else							      \
+	      {								      \
+		inptr += 4;						      \
+		++*irreversible;					      \
+	      }								      \
 	    continue;							      \
 	  }								      \
 									      \
@@ -3271,6 +3291,7 @@ static const char uhc_hangul_from_ucs[11172][2] =
 									      \
     inptr += 4;								      \
   }
+#define LOOP_NEED_FLAGS
 #include <iconv/loop.c>
 
 
diff --git a/iconvdata/unicode.c b/iconvdata/unicode.c
index 5309fc267f..438658edb9 100644
--- a/iconvdata/unicode.c
+++ b/iconvdata/unicode.c
@@ -19,6 +19,7 @@
    Boston, MA 02111-1307, USA.  */
 
 #include <byteswap.h>
+#include <dlfcn.h>
 #include <gconv.h>
 #include <stddef.h>
 #include <stdint.h>
@@ -70,7 +71,7 @@
       outbuf += 2;							      \
     }									      \
   swap = ((struct unicode_data *) step->__data)->swap;
-#define EXTRA_LOOP_ARGS		, data, swap
+#define EXTRA_LOOP_ARGS		, swap
 
 
 /* Direction of the transformation.  */
@@ -151,14 +152,26 @@ gconv_end (struct __gconv_step *data)
 									      \
     if (__builtin_expect (c, 0) >= 0x10000)				      \
       {									      \
-	if (! ignore_errors_p ())					      \
+	if (step_data->__trans.__trans_fct != NULL)			      \
+	  {								      \
+	    result = DL_CALL_FCT (step_data->__trans.__trans_fct,	      \
+				  (step, step_data, *inptrp, &inptr, inend,   \
+				   *outptrp, &outptr, outend, irreversible)); \
+	    if (result != __GCONV_OK)					      \
+	      break;							      \
+	  }								      \
+	else if (! ignore_errors_p ())					      \
 	  {								      \
 	    /* This is an illegal character.  */			      \
 	    result = __GCONV_ILLEGAL_INPUT;				      \
 	    break;							      \
 	  }								      \
-									      \
-	++*irreversible;						      \
+	else								      \
+	  {								      \
+	    ++*irreversible;						      \
+	    inptr += 4;							      \
+	  }								      \
+	continue;							      \
       }									      \
     else								      \
       {									      \
@@ -168,8 +181,9 @@ gconv_end (struct __gconv_step *data)
 									      \
     inptr += 4;								      \
   }
+#define LOOP_NEED_FLAGS
 #define EXTRA_LOOP_DECLS \
-	, struct __gconv_step_data *step_data, int swap
+	, int swap
 #include <iconv/loop.c>
 
 
@@ -190,7 +204,7 @@ gconv_end (struct __gconv_step *data)
     outptr += 4;							      \
   }
 #define EXTRA_LOOP_DECLS \
-	, struct __gconv_step_data *step_data, int swap
+	, int swap
 #include <iconv/loop.c>
 
 
diff --git a/iconvdata/utf-16.c b/iconvdata/utf-16.c
index d24b55b2bc..bbb546ef9a 100644
--- a/iconvdata/utf-16.c
+++ b/iconvdata/utf-16.c
@@ -19,6 +19,7 @@
    Boston, MA 02111-1307, USA.  */
 
 #include <byteswap.h>
+#include <dlfcn.h>
 #include <gconv.h>
 #include <stddef.h>
 #include <stdint.h>
@@ -72,7 +73,7 @@
       put16u (outbuf, BOM);						      \
       outbuf += 2;							      \
     }
-#define EXTRA_LOOP_ARGS		, var, data, swap
+#define EXTRA_LOOP_ARGS		, var, swap
 
 
 /* Direction of the transformation.  */
@@ -201,20 +202,31 @@ gconv_end (struct __gconv_step *data)
 	  {								      \
 	    if (__builtin_expect (c, 0) >= 0x110000)			      \
 	      {								      \
-		if (! ignore_errors_p ())				      \
+		if (step_data->__trans.__trans_fct != NULL)		      \
+		  {							      \
+		    result = DL_CALL_FCT (step_data->__trans.__trans_fct,     \
+					  (step, step_data, *inptrp, &inptr,  \
+					   inend, *outptrp, &outptr, outend,  \
+					   irreversible));		      \
+		    if (result != __GCONV_OK)				      \
+		      break;						      \
+		  }							      \
+		else if (! ignore_errors_p ())				      \
 		  {							      \
 		    /* This is an illegal character.  */		      \
 		    result = __GCONV_ILLEGAL_INPUT;			      \
 		    break;						      \
 		  }							      \
-									      \
-		++*irreversible;					      \
-		inptr += 4;						      \
+		else							      \
+		  {							      \
+		    ++*irreversible;					      \
+		    inptr += 4;						      \
+		  }							      \
 		continue;						      \
 	      }								      \
 									      \
 	    /* Generate a surrogate character.  */			      \
-	    if (NEED_LENGTH_TEST && __builtin_expect (outptr + 4 > outend, 0))\
+	    if (__builtin_expect (outptr + 4 > outend, 0))		      \
 	      {								      \
 		/* Overflow in the output buffer.  */			      \
 		result = __GCONV_FULL_OUTPUT;				      \
@@ -234,20 +246,31 @@ gconv_end (struct __gconv_step *data)
 	  {								      \
 	    if (__builtin_expect (c, 0) >= 0x110000)			      \
 	      {								      \
-		if (! ignore_errors_p ())				      \
+		if (step_data->__trans.__trans_fct != NULL)		      \
+		  {							      \
+		    result = DL_CALL_FCT (step_data->__trans.__trans_fct,     \
+					  (step, step_data, *inptrp, &inptr,  \
+					   inend, *outptrp, &outptr, outend,  \
+					   irreversible));		      \
+		    if (result != __GCONV_OK)				      \
+		      break;						      \
+		  }							      \
+		else if (! ignore_errors_p ())				      \
 		  {							      \
 		    /* This is an illegal character.  */		      \
 		    result = __GCONV_ILLEGAL_INPUT;			      \
 		    break;						      \
 		  }							      \
-									      \
-		++*irreversible;					      \
-		inptr += 4;						      \
+		else							      \
+		  {							      \
+		    ++*irreversible;					      \
+		    inptr += 4;						      \
+		  }							      \
 		continue;						      \
 	      }								      \
 									      \
 	    /* Generate a surrogate character.  */			      \
-	    if (NEED_LENGTH_TEST && __builtin_expect (outptr + 4 > outend, 0))\
+	    if (__builtin_expect (outptr + 4 > outend, 0))		      \
 	      {								      \
 		/* Overflow in the output buffer.  */			      \
 		result = __GCONV_FULL_OUTPUT;				      \
@@ -264,8 +287,9 @@ gconv_end (struct __gconv_step *data)
     outptr += 2;							      \
     inptr += 4;								      \
   }
+#define LOOP_NEED_FLAGS
 #define EXTRA_LOOP_DECLS \
-	, enum variant var, struct __gconv_step_data *step_data, int swap
+	, enum variant var, int swap
 #include <iconv/loop.c>
 
 
@@ -294,7 +318,7 @@ gconv_end (struct __gconv_step *data)
 									      \
 	    /* It's a surrogate character.  At least the first word says      \
 	       it is.  */						      \
-	    if (NEED_LENGTH_TEST && __builtin_expect (inptr + 4 > inend, 0))  \
+	    if (__builtin_expect (inptr + 4 > inend, 0))		      \
 	      {								      \
 		/* We don't have enough input for another complete input      \
 		   character.  */					      \
@@ -337,7 +361,7 @@ gconv_end (struct __gconv_step *data)
 									      \
 	    /* It's a surrogate character.  At least the first word says      \
 	       it is.  */						      \
-	    if (NEED_LENGTH_TEST && __builtin_expect (inptr + 4 > inend, 0))  \
+	    if (__builtin_expect (inptr + 4 > inend, 0))		      \
 	      {								      \
 		/* We don't have enough input for another complete input      \
 		   character.  */					      \
@@ -368,8 +392,9 @@ gconv_end (struct __gconv_step *data)
       }									      \
     outptr += 4;							      \
   }
+#define LOOP_NEED_FLAGS
 #define EXTRA_LOOP_DECLS \
-	, enum variant var, struct __gconv_step_data *step_data, int swap
+	, enum variant var, int swap
 #include <iconv/loop.c>
 
 
diff --git a/intl/tst-gettext.sh b/intl/tst-gettext.sh
index db3653ad73..9d2151f6b6 100755
--- a/intl/tst-gettext.sh
+++ b/intl/tst-gettext.sh
@@ -21,6 +21,9 @@
 common_objpfx=$1
 objpfx=$2
 
+GCONV_PATH=${common_objpfx}iconvdata
+export GCONV_PATH
+
 # Generate the test data.
 test -d ${objpfx}domaindir || mkdir ${objpfx}domaindir
 # Create the locale directories.
diff --git a/libio/iofwide.c b/libio/iofwide.c
index d1a0f1ef13..5ca0a84f0d 100644
--- a/libio/iofwide.c
+++ b/libio/iofwide.c
@@ -25,6 +25,7 @@
 
 #include <libioP.h>
 #ifdef _LIBC
+# include <dlfcn.h>
 # include <wchar.h>
 #endif
 #include <stdlib.h>
@@ -165,15 +166,17 @@ do_out (struct _IO_codecvt *codecvt, __mbstate_t *statep,
 #ifdef _LIBC
   struct __gconv_step *gs = codecvt->__cd_out.__cd.__steps;
   int status;
-  size_t written;
+  size_t dummy;
   const unsigned char *from_start_copy = (unsigned char *) from_start;
 
   codecvt->__cd_out.__cd.__data[0].__outbuf = to_start;
   codecvt->__cd_out.__cd.__data[0].__outbufend = to_end;
   codecvt->__cd_out.__cd.__data[0].__statep = statep;
 
-  status = (*gs->__fct) (gs, codecvt->__cd_out.__cd.__data, &from_start_copy,
-			 (const unsigned char *) from_end, &written, 0, 0);
+  status = DL_CALL_FCT (gs->__fct,
+			(gs, codecvt->__cd_out.__cd.__data, &from_start_copy,
+			 (const unsigned char *) from_end, to_start,
+			 &dummy, 0, 0));
 
   *from_stop = (wchar_t *) from_start_copy;
   *to_stop = codecvt->__cd_out.__cd.__data[0].__outbuf;
@@ -212,14 +215,15 @@ do_unshift (struct _IO_codecvt *codecvt, __mbstate_t *statep,
 #ifdef _LIBC
   struct __gconv_step *gs = codecvt->__cd_out.__cd.__steps;
   int status;
-  size_t written;
+  size_t dummy;
 
   codecvt->__cd_out.__cd.__data[0].__outbuf = to_start;
   codecvt->__cd_out.__cd.__data[0].__outbufend = to_end;
   codecvt->__cd_out.__cd.__data[0].__statep = statep;
 
-  status = (*gs->__fct) (gs, codecvt->__cd_out.__cd.__data, NULL, NULL,
-			 &written, 1, 0);
+  status = DL_CALL_FCT (gs->__fct,
+			(gs, codecvt->__cd_out.__cd.__data, NULL, NULL,
+			 to_start, &dummy, 1, 0));
 
   *to_stop = codecvt->__cd_out.__cd.__data[0].__outbuf;
 
@@ -258,15 +262,16 @@ do_in (struct _IO_codecvt *codecvt, __mbstate_t *statep,
 #ifdef _LIBC
   struct __gconv_step *gs = codecvt->__cd_in.__cd.__steps;
   int status;
-  size_t written;
+  size_t dummy;
   const unsigned char *from_start_copy = (unsigned char *) from_start;
 
   codecvt->__cd_in.__cd.__data[0].__outbuf = (char *) to_start;
   codecvt->__cd_in.__cd.__data[0].__outbufend = (char *) to_end;
   codecvt->__cd_in.__cd.__data[0].__statep = statep;
 
-  status = (*gs->__fct) (gs, codecvt->__cd_in.__cd.__data, &from_start_copy,
-			 from_end, &written, 0, 0);
+  status = DL_CALL_FCT (gs->__fct,
+			(gs, codecvt->__cd_in.__cd.__data, &from_start_copy,
+			 from_end, (char *) to_start, &dummy, 0, 0));
 
   *from_stop = from_start_copy;
   *to_stop = (wchar_t *) codecvt->__cd_in.__cd.__data[0].__outbuf;
@@ -335,14 +340,15 @@ do_length (struct _IO_codecvt *codecvt, __mbstate_t *statep,
   wchar_t to_buf[max];
   struct __gconv_step *gs = codecvt->__cd_in.__cd.__steps;
   int status;
-  size_t written;
+  size_t dummy;
 
   codecvt->__cd_in.__cd.__data[0].__outbuf = (char *) to_buf;
   codecvt->__cd_in.__cd.__data[0].__outbufend = (char *) &to_buf[max];
   codecvt->__cd_in.__cd.__data[0].__statep = statep;
 
-  status = (*gs->__fct) (gs, codecvt->__cd_in.__cd.__data, &cp, from_end,
-			 &written, 0, 0);
+  status = DL_CALL_FCT (gs->__fct,
+			(gs, codecvt->__cd_in.__cd.__data, &cp, from_end,
+			 (char *) to_buf, &dummy, 0, 0));
 
   result = cp - (const unsigned char *) from_start;
 #else
diff --git a/linuxthreads/ChangeLog b/linuxthreads/ChangeLog
index c4236bd748..3066c0d1e2 100644
--- a/linuxthreads/ChangeLog
+++ b/linuxthreads/ChangeLog
@@ -1,5 +1,7 @@
 2000-06-12  Ulrich Drepper  <drepper@redhat.com>
 
+	* Makefile (tests): Add joinrace.
+
 	* Examples/ex6.c: Test return value of pthread_join.
 
 2000-06-11  Geoff Keating  <geoffk@cygnus.com>
diff --git a/linuxthreads/Makefile b/linuxthreads/Makefile
index afbe51c618..6e9f8141bd 100644
--- a/linuxthreads/Makefile
+++ b/linuxthreads/Makefile
@@ -38,7 +38,7 @@ libpthread-routines := attr cancel condvar join manager mutex ptfork \
 		       oldsemaphore events getcpuclockid pspinlock
 
 vpath %.c Examples
-tests = ex1 ex2 ex3 ex4 ex5 ex6 ex7 ex8
+tests = ex1 ex2 ex3 ex4 ex5 ex6 ex7 ex8 joinrace
 
 include ../Rules
 
@@ -68,3 +68,4 @@ $(objpfx)ex5: $(libpthread)
 $(objpfx)ex6: $(libpthread)
 $(objpfx)ex7: $(libpthread)
 $(objpfx)ex8: $(libpthread)
+$(objpfx)joinrace: $(libpthread)
diff --git a/timezone/Makefile b/timezone/Makefile
index 45a9ea64c0..93478d4948 100644
--- a/timezone/Makefile
+++ b/timezone/Makefile
@@ -1,4 +1,4 @@
-# Copyright (C) 1998, 1999 Free Software Foundation, Inc.
+# Copyright (C) 1998, 1999, 2000 Free Software Foundation, Inc.
 # This file is part of the GNU C Library.
 
 # The GNU C Library is free software; you can redistribute it and/or
@@ -174,7 +174,8 @@ CFLAGS-scheck.c = -Wno-strict-prototypes -DNOID
 # leapseconds.
 testdata = $(objpfx)testdata
 define build-testdata
-$(built-program-cmd) -d $(testdata) -y ./yearistype $<
+GCONV_PATH=${common-objpfx}iconvdata \
+  $(built-program-cmd) -d $(testdata) -y ./yearistype $<
 endef
 
 $(objpfx)test-tz.out: $(addprefix $(testdata)/, America/New_York Etc/UTC UTC)
diff --git a/wcsmbs/btowc.c b/wcsmbs/btowc.c
index 0978f097f1..1271a01ed6 100644
--- a/wcsmbs/btowc.c
+++ b/wcsmbs/btowc.c
@@ -17,6 +17,7 @@
    write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
    Boston, MA 02111-1307, USA.  */
 
+#include <dlfcn.h>
 #include <gconv.h>
 #include <stdio.h>
 #include <string.h>
@@ -58,9 +59,9 @@ __btowc (c)
   /* Create the input string.  */
   inbuf[0] = c;
 
-  status = (*__wcsmbs_gconv_fcts.towc->__fct) (__wcsmbs_gconv_fcts.towc, &data,
-					       &inptr, inptr + 1, &dummy,
-					       0, 1);
+  status = DL_CALL_FCT (__wcsmbs_gconv_fcts.towc->__fct,
+			(__wcsmbs_gconv_fcts.towc, &data, &inptr, inptr + 1,
+			 data.__outbuf, &dummy, 0, 1));
   /* The conversion failed.  */
   if (status != __GCONV_OK && status != __GCONV_FULL_OUTPUT
       && status != __GCONV_EMPTY_INPUT)
diff --git a/wcsmbs/mbrtowc.c b/wcsmbs/mbrtowc.c
index 6ecbdc5b5c..9809ed51a2 100644
--- a/wcsmbs/mbrtowc.c
+++ b/wcsmbs/mbrtowc.c
@@ -17,6 +17,7 @@
    write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
    Boston, MA 02111-1307, USA.  */
 
+#include <dlfcn.h>
 #include <errno.h>
 #include <gconv.h>
 #include <wchar.h>
@@ -69,9 +70,9 @@ __mbrtowc (wchar_t *pwc, const char *s, size_t n, mbstate_t *ps)
 
   /* Do a normal conversion.  */
   inbuf = (const unsigned char *) s;
-  status = (*__wcsmbs_gconv_fcts.towc->__fct) (__wcsmbs_gconv_fcts.towc,
-					       &data, &inbuf, inbuf + n,
-					       &dummy, 0, 1);
+  status = DL_CALL_FCT (__wcsmbs_gconv_fcts.towc->__fct,
+			(__wcsmbs_gconv_fcts.towc, &data, &inbuf, inbuf + n,
+			 data.__outbuf, &dummy, 0, 1));
 
   /* There must not be any problems with the conversion but illegal input
      characters.  The output buffer must be large enough, otherwise the
diff --git a/wcsmbs/mbsnrtowcs.c b/wcsmbs/mbsnrtowcs.c
index 540afd0800..238458d25d 100644
--- a/wcsmbs/mbsnrtowcs.c
+++ b/wcsmbs/mbsnrtowcs.c
@@ -17,6 +17,7 @@
    write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
    Boston, MA 02111-1307, USA.  */
 
+#include <dlfcn.h>
 #include <errno.h>
 #include <gconv.h>
 #include <string.h>
@@ -49,7 +50,7 @@ __mbsnrtowcs (dst, src, nmc, len, ps)
   size_t result;
   int status;
   struct __gconv_step *towc;
-  size_t non_reversible;
+  size_t dummy;
 
   /* Tell where we want the result.  */
   data.__invocation_counter = 0;
@@ -79,8 +80,9 @@ __mbsnrtowcs (dst, src, nmc, len, ps)
 	{
 	  data.__outbuf = (unsigned char *) buf;
 
-	  status = (*towc->__fct) (__wcsmbs_gconv_fcts.towc, &data, &inbuf,
-				   srcend, &non_reversible, 0, 1);
+	  status = DL_CALL_FCT (towc->__fct,
+				(towc, &data, &inbuf, srcend, data.__outbuf,
+				 &dummy, 0, 1));
 
 	  result += (wchar_t *) data.__outbuf - buf;
 	}
@@ -99,9 +101,9 @@ __mbsnrtowcs (dst, src, nmc, len, ps)
       data.__outbuf = (unsigned char *) dst;
       data.__outbufend = data.__outbuf + len * sizeof (wchar_t);
 
-      status = (*towc->__fct) (__wcsmbs_gconv_fcts.towc, &data,
-			       (const unsigned char **) src, srcend,
-			       &non_reversible, 0, 1);
+      status = DL_CALL_FCT (towc->__fct,
+			    (towc, &data, (const unsigned char **) src, srcend,
+			     data.__outbuf, &dummy, 0, 1));
 
       result = (wchar_t *) data.__outbuf - dst;
 
diff --git a/wcsmbs/mbsrtowcs.c b/wcsmbs/mbsrtowcs.c
index aaafe3bf1e..3c1f86a196 100644
--- a/wcsmbs/mbsrtowcs.c
+++ b/wcsmbs/mbsrtowcs.c
@@ -17,6 +17,7 @@
    write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
    Boston, MA 02111-1307, USA.  */
 
+#include <dlfcn.h>
 #include <errno.h>
 #include <gconv.h>
 #include <stdlib.h>
@@ -76,8 +77,9 @@ __mbsrtowcs (dst, src, len, ps)
 	{
 	  data.__outbuf = (char *) buf;
 
-	  status = (*towc->__fct) (__wcsmbs_gconv_fcts.towc, &data, &inbuf,
-				   srcend, &non_reversible, 0, 1);
+	  status = DL_CALL_FCT (towc->__fct,
+				(towc, &data, &inbuf, srcend, data.__outbuf,
+				 &non_reversible, 0, 1));
 
 	  result += (wchar_t *) data.__outbuf - buf;
 	}
@@ -105,9 +107,9 @@ __mbsrtowcs (dst, src, len, ps)
       data.__outbuf = (unsigned char *) dst;
       data.__outbufend = data.__outbuf + len * sizeof (wchar_t);
 
-      status = (*towc->__fct) (__wcsmbs_gconv_fcts.towc, &data,
-			       (const unsigned char **) src, srcend,
-			       &non_reversible, 0, 1);
+      status = DL_CALL_FCT (towc->__fct,
+			    (towc, &data, (const unsigned char **) src, srcend,
+			     data.__outbuf, &non_reversible, 0, 1));
 
       result = (wchar_t *) data.__outbuf - dst;
 
diff --git a/wcsmbs/wcrtomb.c b/wcsmbs/wcrtomb.c
index 5af383178c..f0bc824584 100644
--- a/wcsmbs/wcrtomb.c
+++ b/wcsmbs/wcrtomb.c
@@ -17,6 +17,7 @@
    write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
    Boston, MA 02111-1307, USA.  */
 
+#include <dlfcn.h>
 #include <errno.h>
 #include <gconv.h>
 #include <stdlib.h>
@@ -71,9 +72,9 @@ __wcrtomb (char *s, wchar_t wc, mbstate_t *ps)
      by a NUL byte.  */
   if (wc == L'\0')
     {
-      status = (*__wcsmbs_gconv_fcts.tomb->__fct) (__wcsmbs_gconv_fcts.tomb,
-						   &data, NULL, NULL,
-						   &dummy, 1, 1);
+      status = DL_CALL_FCT (__wcsmbs_gconv_fcts.tomb->__fct,
+			    (__wcsmbs_gconv_fcts.tomb, &data, NULL, NULL,
+			     data.__outbuf, &dummy, 1, 1));
 
       if (status == __GCONV_OK || status == __GCONV_EMPTY_INPUT)
 	*data.__outbuf++ = '\0';
@@ -83,10 +84,10 @@ __wcrtomb (char *s, wchar_t wc, mbstate_t *ps)
       /* Do a normal conversion.  */
       const unsigned char *inbuf = (const unsigned char *) &wc;
 
-      status = (*__wcsmbs_gconv_fcts.tomb->__fct) (__wcsmbs_gconv_fcts.tomb,
-						   &data, &inbuf,
-						   inbuf + sizeof (wchar_t),
-						   &dummy, 0, 1);
+      status = DL_CALL_FCT (__wcsmbs_gconv_fcts.tomb->__fct,
+			    (__wcsmbs_gconv_fcts.tomb, &data, &inbuf,
+			     inbuf + sizeof (wchar_t), data.__outbuf, &dummy,
+			     0, 1));
     }
 
   /* There must not be any problems with the conversion but illegal input
diff --git a/wcsmbs/wcsnrtombs.c b/wcsmbs/wcsnrtombs.c
index 7005bdcf12..dae2216ae5 100644
--- a/wcsmbs/wcsnrtombs.c
+++ b/wcsmbs/wcsnrtombs.c
@@ -17,6 +17,7 @@
    write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
    Boston, MA 02111-1307, USA.  */
 
+#include <dlfcn.h>
 #include <errno.h>
 #include <gconv.h>
 #include <wchar.h>
@@ -79,10 +80,10 @@ __wcsnrtombs (dst, src, nwc, len, ps)
 	{
 	  data.__outbuf = buf;
 
-	  status = (*tomb->__fct) (__wcsmbs_gconv_fcts.tomb, &data,
-				   (const unsigned char **) &inbuf,
-				   (const unsigned char *) srcend, &dummy,
-				   0, 1);
+	  status = DL_CALL_FCT (tomb->__fct,
+				(tomb, &data, (const unsigned char **) &inbuf,
+				 (const unsigned char *) srcend, data.__outbuf,
+				 &dummy, 0, 1));
 
 	  /* Count the number of bytes.  */
 	  result += data.__outbuf - buf;
@@ -104,9 +105,10 @@ __wcsnrtombs (dst, src, nwc, len, ps)
       data.__outbuf = dst;
       data.__outbufend = dst + len;
 
-      status = (*tomb->__fct) (__wcsmbs_gconv_fcts.tomb, &data,
-			       (const unsigned char **) src,
-			       (const unsigned char *) srcend, &dummy, 0, 1);
+      status = DL_CALL_FCT (tomb->__fct,
+			    (tomb, &data, (const unsigned char **) src,
+			     (const unsigned char *) srcend, data.__outbuf,
+			     &dummy, 0, 1));
 
       /* Count the number of bytes.  */
       result = data.__outbuf - (unsigned char *) dst;
diff --git a/wcsmbs/wcsrtombs.c b/wcsmbs/wcsrtombs.c
index 875ef16f75..03ef013c7c 100644
--- a/wcsmbs/wcsrtombs.c
+++ b/wcsmbs/wcsrtombs.c
@@ -17,6 +17,7 @@
    write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
    Boston, MA 02111-1307, USA.  */
 
+#include <dlfcn.h>
 #include <errno.h>
 #include <stdlib.h>
 #include <gconv.h>
@@ -76,10 +77,10 @@ __wcsrtombs (dst, src, len, ps)
 	{
 	  data.__outbuf = buf;
 
-	  status = (*tomb->__fct) (__wcsmbs_gconv_fcts.tomb, &data,
-				   (const unsigned char **) &inbuf,
-				   (const unsigned char *) srcend, &dummy,
-				   0, 1);
+	  status = DL_CALL_FCT (tomb->__fct,
+				(tomb, &data, (const unsigned char **) &inbuf,
+				 (const unsigned char *) srcend, data.__outbuf,
+				 &dummy, 0, 1));
 
 	  /* Count the number of bytes.  */
 	  result += data.__outbuf - buf;
@@ -105,9 +106,10 @@ __wcsrtombs (dst, src, len, ps)
       data.__outbuf = dst;
       data.__outbufend = dst + len;
 
-      status = (*tomb->__fct) (__wcsmbs_gconv_fcts.tomb, &data,
-			       (const unsigned char **) src,
-			       (const unsigned char *) srcend, &dummy, 0, 1);
+      status = DL_CALL_FCT (tomb->__fct,
+			    (tomb, &data, (const unsigned char **) src,
+			     (const unsigned char *) srcend, data.__outbuf,
+			     &dummy, 0, 1));
 
       /* Count the number of bytes.  */
       result = data.__outbuf - (unsigned char *) dst;
diff --git a/wcsmbs/wctob.c b/wcsmbs/wctob.c
index 8c6372558e..fc4c38331d 100644
--- a/wcsmbs/wctob.c
+++ b/wcsmbs/wctob.c
@@ -17,6 +17,7 @@
    write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
    Boston, MA 02111-1307, USA.  */
 
+#include <dlfcn.h>
 #include <gconv.h>
 #include <stdio.h>
 #include <string.h>
@@ -52,10 +53,12 @@ wctob (c)
   /* Create the input string.  */
   inbuf[0] = c;
 
-  status = (*__wcsmbs_gconv_fcts.tomb->__fct) (__wcsmbs_gconv_fcts.tomb, &data,
-					       (const unsigned char **) &inptr,
-					       (const unsigned char *) &inbuf[1],
-					       &dummy, 0, 1);
+  status = DL_CALL_FCT (__wcsmbs_gconv_fcts.tomb->__fct,
+			(__wcsmbs_gconv_fcts.tomb, &data,
+			 (const unsigned char **) &inptr,
+			 (const unsigned char *) &inbuf[1],
+			 data.__outbuf, &dummy, 0, 1));
+
   /* The conversion failed or the output is too long.  */
   if ((status != __GCONV_OK && status != __GCONV_FULL_OUTPUT
        && status != __GCONV_EMPTY_INPUT)