about summary refs log tree commit diff
path: root/REORG.TODO/iconv
diff options
context:
space:
mode:
Diffstat (limited to 'REORG.TODO/iconv')
-rw-r--r--REORG.TODO/iconv/Makefile79
-rw-r--r--REORG.TODO/iconv/Versions13
-rw-r--r--REORG.TODO/iconv/dummy-repertoire.c37
-rw-r--r--REORG.TODO/iconv/gconv.c91
-rw-r--r--REORG.TODO/iconv/gconv.h154
-rw-r--r--REORG.TODO/iconv/gconv_builtin.c87
-rw-r--r--REORG.TODO/iconv/gconv_builtin.h123
-rw-r--r--REORG.TODO/iconv/gconv_cache.c472
-rw-r--r--REORG.TODO/iconv/gconv_charset.h57
-rw-r--r--REORG.TODO/iconv/gconv_close.c50
-rw-r--r--REORG.TODO/iconv/gconv_conf.c616
-rw-r--r--REORG.TODO/iconv/gconv_db.c870
-rw-r--r--REORG.TODO/iconv/gconv_dl.c242
-rw-r--r--REORG.TODO/iconv/gconv_int.h287
-rw-r--r--REORG.TODO/iconv/gconv_open.c208
-rw-r--r--REORG.TODO/iconv/gconv_simple.c1329
-rw-r--r--REORG.TODO/iconv/gconv_trans.c239
-rw-r--r--REORG.TODO/iconv/iconv.c95
-rw-r--r--REORG.TODO/iconv/iconv.h55
-rw-r--r--REORG.TODO/iconv/iconv_charmap.c560
-rw-r--r--REORG.TODO/iconv/iconv_close.c36
-rw-r--r--REORG.TODO/iconv/iconv_open.c88
-rw-r--r--REORG.TODO/iconv/iconv_prog.c803
-rw-r--r--REORG.TODO/iconv/iconv_prog.h41
-rw-r--r--REORG.TODO/iconv/iconvconfig.c1245
-rw-r--r--REORG.TODO/iconv/iconvconfig.h66
-rw-r--r--REORG.TODO/iconv/loop.c523
-rw-r--r--REORG.TODO/iconv/skeleton.c821
-rw-r--r--REORG.TODO/iconv/strtab.c339
-rw-r--r--REORG.TODO/iconv/tst-iconv1.c47
-rw-r--r--REORG.TODO/iconv/tst-iconv2.c102
-rw-r--r--REORG.TODO/iconv/tst-iconv3.c56
-rw-r--r--REORG.TODO/iconv/tst-iconv4.c65
-rw-r--r--REORG.TODO/iconv/tst-iconv5.c161
-rw-r--r--REORG.TODO/iconv/tst-iconv6.c118
35 files changed, 10175 insertions, 0 deletions
diff --git a/REORG.TODO/iconv/Makefile b/REORG.TODO/iconv/Makefile
new file mode 100644
index 0000000000..b2fead0479
--- /dev/null
+++ b/REORG.TODO/iconv/Makefile
@@ -0,0 +1,79 @@
+# Copyright (C) 1997-2017 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
+# modify it under the terms of the GNU Lesser General Public
+# License as published by the Free Software Foundation; either
+# version 2.1 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
+# Lesser General Public License for more details.
+
+# You should have received a copy of the GNU Lesser General Public
+# License along with the GNU C Library; if not, see
+# <http://www.gnu.org/licenses/>.
+
+#
+#	Makefile for iconv.
+#
+subdir	:= iconv
+
+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_trans gconv_cache
+routines	+= gconv_dl
+
+vpath %.c ../locale/programs ../intl
+
+iconv_prog-modules = iconv_charmap charmap charmap-dir linereader \
+		     dummy-repertoire simple-hash xstrdup xmalloc
+iconvconfig-modules = strtab xmalloc hash-string
+extra-objs	   = $(iconv_prog-modules:=.o) $(iconvconfig-modules:=.o)
+CFLAGS-iconv_prog.c = -I../locale/programs
+CFLAGS-iconv_charmap.c = -I../locale/programs
+CFLAGS-dummy-repertoire.c = -I../locale/programs
+CFLAGS-charmap.c = -DCHARMAP_PATH='"$(i18ndir)/charmaps"' \
+		   -DDEFAULT_CHARMAP=null_pointer -DNEED_NULL_POINTER
+CFLAGS-linereader.c = -DNO_TRANSLITERATION
+CFLAGS-simple-hash.c = -I../locale
+
+tests	= tst-iconv1 tst-iconv2 tst-iconv3 tst-iconv4 tst-iconv5 tst-iconv6
+
+others		= iconv_prog iconvconfig
+install-others-programs	= $(inst_bindir)/iconv
+install-sbin	= iconvconfig
+
+CFLAGS-gconv_cache.c += -DGCONV_DIR='"$(gconvdir)"'
+CFLAGS-gconv_conf.c = -DGCONV_PATH='"$(gconvdir)"'
+CFLAGS-iconvconfig.c = -DGCONV_PATH='"$(gconvdir)"' -DGCONV_DIR='"$(gconvdir)"'
+
+# Set libof-* for each routine.
+cpp-srcs-left := $(iconv_prog-modules) $(iconvconfig-modules)
+lib := iconvprogs
+include $(patsubst %,$(..)libof-iterator.mk,$(cpp-srcs-left))
+
+ifeq ($(run-built-tests),yes)
+xtests-special += $(objpfx)test-iconvconfig.out
+endif
+
+include ../Rules
+
+$(inst_bindir)/iconv: $(objpfx)iconv_prog $(+force)
+	$(do-install-program)
+
+$(objpfx)iconv_prog: $(iconv_prog-modules:%=$(objpfx)%.o)
+$(objpfx)iconvconfig: $(iconvconfig-modules:%=$(objpfx)%.o)
+
+$(objpfx)test-iconvconfig.out: /dev/null $(objpfx)iconvconfig
+	(set -e; \
+	 tmp=$(objpfx)gconv-modules.cache.$$$$; \
+	 rm -f $$tmp; \
+	 $(make-test-out) --output=$$tmp --nostdlib $(inst_gconvdir); \
+	 cmp $$tmp $(inst_gconvdir)/gconv-modules.cache; \
+	 rm -f $$tmp) > $@; \
+	$(evaluate-test)
diff --git a/REORG.TODO/iconv/Versions b/REORG.TODO/iconv/Versions
new file mode 100644
index 0000000000..60ab10a277
--- /dev/null
+++ b/REORG.TODO/iconv/Versions
@@ -0,0 +1,13 @@
+libc {
+  GLIBC_2.1 {
+    # i*
+    iconv; iconv_open; iconv_close;
+  }
+  GLIBC_PRIVATE {
+    # functions shared with iconv program
+    __gconv_get_alias_db; __gconv_get_cache; __gconv_get_modules_db;
+
+    # function used by the gconv modules
+    __gconv_transliterate;
+  }
+}
diff --git a/REORG.TODO/iconv/dummy-repertoire.c b/REORG.TODO/iconv/dummy-repertoire.c
new file mode 100644
index 0000000000..a4db977951
--- /dev/null
+++ b/REORG.TODO/iconv/dummy-repertoire.c
@@ -0,0 +1,37 @@
+/* Copyright (C) 2001-2017 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+   Contributed by Ulrich Drepper <drepper@redhat.com>, 2001.
+
+   This program is free software; you can redistribute it and/or modify
+   it under the terms of the GNU General Public License as published
+   by the Free Software Foundation; version 2 of the License, or
+   (at your option) any later version.
+
+   This program 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 General Public License for more details.
+
+   You should have received a copy of the GNU General Public License
+   along with this program; if not, see <http://www.gnu.org/licenses/>.  */
+
+#include <stdint.h>
+
+/* For iconv we don't have to handle repertoire maps.  Provide dummy
+   definitions to allow the use of linereader.c unchanged.  */
+#include <repertoire.h>
+
+
+uint32_t
+repertoire_find_value (const struct repertoire_t *repertoire, const char *name,
+		       size_t len)
+{
+  return ILLEGAL_CHAR_VALUE;
+}
+
+
+const char *
+repertoire_find_symbol (const struct repertoire_t *repertoire, uint32_t ucs)
+{
+  return NULL;
+}
diff --git a/REORG.TODO/iconv/gconv.c b/REORG.TODO/iconv/gconv.c
new file mode 100644
index 0000000000..0aab0546b9
--- /dev/null
+++ b/REORG.TODO/iconv/gconv.c
@@ -0,0 +1,91 @@
+/* Convert characters in input buffer using conversion descriptor to
+   output buffer.
+   Copyright (C) 1997-2017 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+   Contributed by Ulrich Drepper <drepper@cygnus.com>, 1997.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 2.1 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
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with the GNU C Library; if not, see
+   <http://www.gnu.org/licenses/>.  */
+
+#include <assert.h>
+#include <dlfcn.h>
+#include <stddef.h>
+#include <sys/param.h>
+
+#include <gconv_int.h>
+#include <sysdep.h>
+
+
+int
+internal_function
+__gconv (__gconv_t cd, const unsigned char **inbuf,
+	 const unsigned char *inbufend, unsigned char **outbuf,
+	 unsigned char *outbufend, size_t *irreversible)
+{
+  size_t last_step;
+  int result;
+
+  if (cd == (__gconv_t) -1L)
+    return __GCONV_ILLEGAL_DESCRIPTOR;
+
+  last_step = cd->__nsteps - 1;
+
+  assert (irreversible != NULL);
+  *irreversible = 0;
+
+  cd->__data[last_step].__outbuf = outbuf != NULL ? *outbuf : NULL;
+  cd->__data[last_step].__outbufend = outbufend;
+
+  __gconv_fct fct = cd->__steps->__fct;
+#ifdef PTR_DEMANGLE
+  if (cd->__steps->__shlib_handle != NULL)
+    PTR_DEMANGLE (fct);
+#endif
+
+  if (inbuf == NULL || *inbuf == NULL)
+    {
+      /* We just flush.  */
+      result = DL_CALL_FCT (fct,
+			    (cd->__steps, cd->__data, NULL, NULL, NULL,
+			     irreversible,
+			     cd->__data[last_step].__outbuf == NULL ? 2 : 1,
+			     0));
+
+      /* If the flush was successful clear the rest of the state.  */
+      if (result == __GCONV_OK)
+	for (size_t cnt = 0; cnt <= last_step; ++cnt)
+	  cd->__data[cnt].__invocation_counter = 0;
+    }
+  else
+    {
+      const unsigned char *last_start;
+
+      assert (outbuf != NULL && *outbuf != NULL);
+
+      do
+	{
+	  last_start = *inbuf;
+	  result = DL_CALL_FCT (fct,
+				(cd->__steps, cd->__data, inbuf, inbufend,
+				 NULL, irreversible, 0, 0));
+	}
+      while (result == __GCONV_EMPTY_INPUT && last_start != *inbuf
+	     && *inbuf + cd->__steps->__min_needed_from <= inbufend);
+    }
+
+  if (outbuf != NULL && *outbuf != NULL)
+    *outbuf = cd->__data[last_step].__outbuf;
+
+  return result;
+}
diff --git a/REORG.TODO/iconv/gconv.h b/REORG.TODO/iconv/gconv.h
new file mode 100644
index 0000000000..db678dba49
--- /dev/null
+++ b/REORG.TODO/iconv/gconv.h
@@ -0,0 +1,154 @@
+/* Copyright (C) 1997-2017 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
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 2.1 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
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with the GNU C Library; if not, see
+   <http://www.gnu.org/licenses/>.  */
+
+/* This header provides no interface for a user to the internals of
+   the gconv implementation in the libc.  Therefore there is no use
+   for these definitions beside for writing additional gconv modules.  */
+
+#ifndef _GCONV_H
+#define _GCONV_H	1
+
+#include <features.h>
+#include <bits/types/__mbstate_t.h>
+#include <bits/types/wint_t.h>
+
+#define __need_size_t
+#define __need_wchar_t
+#include <stddef.h>
+
+/* ISO 10646 value used to signal invalid value.  */
+#define __UNKNOWN_10646_CHAR	((wchar_t) 0xfffd)
+
+/* Error codes for gconv functions.  */
+enum
+{
+  __GCONV_OK = 0,
+  __GCONV_NOCONV,
+  __GCONV_NODB,
+  __GCONV_NOMEM,
+
+  __GCONV_EMPTY_INPUT,
+  __GCONV_FULL_OUTPUT,
+  __GCONV_ILLEGAL_INPUT,
+  __GCONV_INCOMPLETE_INPUT,
+
+  __GCONV_ILLEGAL_DESCRIPTOR,
+  __GCONV_INTERNAL_ERROR
+};
+
+
+/* Flags the `__gconv_open' function can set.  */
+enum
+{
+  __GCONV_IS_LAST = 0x0001,
+  __GCONV_IGNORE_ERRORS = 0x0002,
+  __GCONV_SWAP = 0x0004,
+  __GCONV_TRANSLIT = 0x0008
+};
+
+
+/* Forward declarations.  */
+struct __gconv_step;
+struct __gconv_step_data;
+struct __gconv_loaded_object;
+
+
+/* Type of a conversion function.  */
+typedef int (*__gconv_fct) (struct __gconv_step *, struct __gconv_step_data *,
+			    const unsigned char **, const unsigned char *,
+			    unsigned char **, size_t *, int, int);
+
+/* Type of a specialized conversion function for a single byte to INTERNAL.  */
+typedef wint_t (*__gconv_btowc_fct) (struct __gconv_step *, unsigned char);
+
+/* 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 *);
+
+
+/* Description of a conversion step.  */
+struct __gconv_step
+{
+  struct __gconv_loaded_object *__shlib_handle;
+  const char *__modname;
+
+  int __counter;
+
+  char *__from_name;
+  char *__to_name;
+
+  __gconv_fct __fct;
+  __gconv_btowc_fct __btowc_fct;
+  __gconv_init_fct __init_fct;
+  __gconv_end_fct __end_fct;
+
+  /* Information about the number of bytes needed or produced in this
+     step.  This helps optimizing the buffer sizes.  */
+  int __min_needed_from;
+  int __max_needed_from;
+  int __min_needed_to;
+  int __max_needed_to;
+
+  /* Flag whether this is a stateful encoding or not.  */
+  int __stateful;
+
+  void *__data;		/* Pointer to step-local data.  */
+};
+
+/* Additional data for steps in use of conversion descriptor.  This is
+   allocated by the `init' function.  */
+struct __gconv_step_data
+{
+  unsigned char *__outbuf;    /* Output buffer for this step.  */
+  unsigned char *__outbufend; /* Address of first byte after the output
+				 buffer.  */
+
+  /* Is this the last module in the chain.  */
+  int __flags;
+
+  /* Counter for number of invocations of the module function for this
+     descriptor.  */
+  int __invocation_counter;
+
+  /* Flag whether this is an internal use of the module (in the mb*towc*
+     and wc*tomb* functions) or regular with iconv(3).  */
+  int __internal_use;
+
+  __mbstate_t *__statep;
+  __mbstate_t __state;	/* This element must not be used directly by
+			   any module; always use STATEP!  */
+};
+
+
+/* Combine conversion step description with data.  */
+typedef struct __gconv_info
+{
+  size_t __nsteps;
+  struct __gconv_step *__steps;
+  __extension__ struct __gconv_step_data __data[0];
+} *__gconv_t;
+
+/* 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,
+				  size_t *irreversible);
+
+#endif /* gconv.h */
diff --git a/REORG.TODO/iconv/gconv_builtin.c b/REORG.TODO/iconv/gconv_builtin.c
new file mode 100644
index 0000000000..111233dab5
--- /dev/null
+++ b/REORG.TODO/iconv/gconv_builtin.c
@@ -0,0 +1,87 @@
+/* Table for builtin transformation mapping.
+   Copyright (C) 1997-2017 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+   Contributed by Ulrich Drepper <drepper@cygnus.com>, 1997.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 2.1 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
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with the GNU C Library; if not, see
+   <http://www.gnu.org/licenses/>.  */
+
+#include <endian.h>
+#include <limits.h>
+#include <stdint.h>
+#include <string.h>
+
+#include <gconv_int.h>
+
+#include <assert.h>
+
+
+static const struct builtin_map
+{
+  const char *name;
+  __gconv_fct fct;
+  __gconv_btowc_fct btowc_fct;
+
+  int8_t min_needed_from;
+  int8_t max_needed_from;
+  int8_t min_needed_to;
+  int8_t max_needed_to;
+
+} map[] =
+{
+#define BUILTIN_TRANSFORMATION(From, To, Cost, Name, Fct, BtowcFct, \
+			       MinF, MaxF, MinT, MaxT) \
+  {									      \
+    .name = Name,							      \
+    .fct = Fct,								      \
+    .btowc_fct = BtowcFct,						      \
+									      \
+    .min_needed_from = MinF,						      \
+    .max_needed_from = MaxF,						      \
+    .min_needed_to = MinT,						      \
+    .max_needed_to = MaxT						      \
+  },
+#define BUILTIN_ALIAS(From, To)
+
+#include <gconv_builtin.h>
+};
+
+
+void
+internal_function
+__gconv_get_builtin_trans (const char *name, struct __gconv_step *step)
+{
+  size_t cnt;
+
+  for (cnt = 0; cnt < sizeof (map) / sizeof (map[0]); ++cnt)
+    if (strcmp (name, map[cnt].name) == 0)
+      break;
+
+  assert (cnt < sizeof (map) / sizeof (map[0]));
+
+  step->__fct = map[cnt].fct;
+  step->__btowc_fct = map[cnt].btowc_fct;
+  step->__init_fct = NULL;
+  step->__end_fct = NULL;
+  step->__shlib_handle = NULL;
+  step->__modname = NULL;
+
+  step->__min_needed_from = map[cnt].min_needed_from;
+  step->__max_needed_from = map[cnt].max_needed_from;
+  step->__min_needed_to = map[cnt].min_needed_to;
+  step->__max_needed_to = map[cnt].max_needed_to;
+
+  /* None of the builtin converters handles stateful encoding.  */
+  step->__stateful = 0;
+}
diff --git a/REORG.TODO/iconv/gconv_builtin.h b/REORG.TODO/iconv/gconv_builtin.h
new file mode 100644
index 0000000000..93e2e4d865
--- /dev/null
+++ b/REORG.TODO/iconv/gconv_builtin.h
@@ -0,0 +1,123 @@
+/* Builtin transformations.
+   Copyright (C) 1997-2017 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+   Contributed by Ulrich Drepper <drepper@cygnus.com>, 1997.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 2.1 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
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with the GNU C Library; if not, see
+   <http://www.gnu.org/licenses/>.  */
+
+/* All encoding named must be in upper case.  There must be no extra
+   spaces.  */
+
+BUILTIN_ALIAS ("UCS4//", "ISO-10646/UCS4/")
+BUILTIN_ALIAS ("UCS-4//", "ISO-10646/UCS4/")
+BUILTIN_ALIAS ("UCS-4BE//", "ISO-10646/UCS4/")
+BUILTIN_ALIAS ("CSUCS4//", "ISO-10646/UCS4/")
+BUILTIN_ALIAS ("ISO-10646//", "ISO-10646/UCS4/")
+BUILTIN_ALIAS ("10646-1:1993//", "ISO-10646/UCS4/")
+BUILTIN_ALIAS ("10646-1:1993/UCS4/", "ISO-10646/UCS4/")
+BUILTIN_ALIAS ("OSF00010104//", "ISO-10646/UCS4/") /* level 1 */
+BUILTIN_ALIAS ("OSF00010105//", "ISO-10646/UCS4/") /* level 2 */
+BUILTIN_ALIAS ("OSF00010106//", "ISO-10646/UCS4/") /* level 3 */
+
+BUILTIN_TRANSFORMATION ("INTERNAL", "ISO-10646/UCS4/", 1, "=INTERNAL->ucs4",
+			__gconv_transform_internal_ucs4, NULL, 4, 4, 4, 4)
+BUILTIN_TRANSFORMATION ("ISO-10646/UCS4/", "INTERNAL", 1, "=ucs4->INTERNAL",
+			__gconv_transform_ucs4_internal, NULL, 4, 4, 4, 4)
+
+BUILTIN_TRANSFORMATION ("INTERNAL", "UCS-4LE//", 1, "=INTERNAL->ucs4le",
+			__gconv_transform_internal_ucs4le, NULL, 4, 4, 4, 4)
+BUILTIN_TRANSFORMATION ("UCS-4LE//", "INTERNAL", 1, "=ucs4le->INTERNAL",
+			__gconv_transform_ucs4le_internal, NULL, 4, 4, 4, 4)
+
+BUILTIN_ALIAS ("WCHAR_T//", "INTERNAL")
+
+BUILTIN_ALIAS ("UTF8//", "ISO-10646/UTF8/")
+BUILTIN_ALIAS ("UTF-8//", "ISO-10646/UTF8/")
+BUILTIN_ALIAS ("ISO-IR-193//", "ISO-10646/UTF8/")
+BUILTIN_ALIAS ("OSF05010001//", "ISO-10646/UTF8/")
+BUILTIN_ALIAS ("ISO-10646/UTF-8/", "ISO-10646/UTF8/")
+
+BUILTIN_TRANSFORMATION ("INTERNAL", "ISO-10646/UTF8/", 1, "=INTERNAL->utf8",
+			__gconv_transform_internal_utf8, NULL, 4, 4, 1, 6)
+
+BUILTIN_TRANSFORMATION ("ISO-10646/UTF8/", "INTERNAL", 1, "=utf8->INTERNAL",
+			__gconv_transform_utf8_internal, __gconv_btwoc_ascii,
+			1, 6, 4, 4)
+
+BUILTIN_ALIAS ("UCS2//", "ISO-10646/UCS2/")
+BUILTIN_ALIAS ("UCS-2//", "ISO-10646/UCS2/")
+BUILTIN_ALIAS ("OSF00010100//", "ISO-10646/UCS2/") /* level 1 */
+BUILTIN_ALIAS ("OSF00010101//", "ISO-10646/UCS2/") /* level 2 */
+BUILTIN_ALIAS ("OSF00010102//", "ISO-10646/UCS2/") /* level 3 */
+
+BUILTIN_TRANSFORMATION ("ISO-10646/UCS2/", "INTERNAL", 1, "=ucs2->INTERNAL",
+			__gconv_transform_ucs2_internal, NULL, 2, 2, 4, 4)
+
+BUILTIN_TRANSFORMATION ("INTERNAL", "ISO-10646/UCS2/", 1, "=INTERNAL->ucs2",
+			__gconv_transform_internal_ucs2, NULL, 4, 4, 2, 2)
+
+
+BUILTIN_ALIAS ("ANSI_X3.4//", "ANSI_X3.4-1968//")
+BUILTIN_ALIAS ("ISO-IR-6//", "ANSI_X3.4-1968//")
+BUILTIN_ALIAS ("ANSI_X3.4-1986//", "ANSI_X3.4-1968//")
+BUILTIN_ALIAS ("ISO_646.IRV:1991//", "ANSI_X3.4-1968//")
+BUILTIN_ALIAS ("ASCII//", "ANSI_X3.4-1968//")
+BUILTIN_ALIAS ("ISO646-US//", "ANSI_X3.4-1968//")
+BUILTIN_ALIAS ("US-ASCII//", "ANSI_X3.4-1968//")
+BUILTIN_ALIAS ("US//", "ANSI_X3.4-1968//")
+BUILTIN_ALIAS ("IBM367//", "ANSI_X3.4-1968//")
+BUILTIN_ALIAS ("CP367//", "ANSI_X3.4-1968//")
+BUILTIN_ALIAS ("CSASCII//", "ANSI_X3.4-1968//")
+BUILTIN_ALIAS ("OSF00010020//", "ANSI_X3.4-1968//")
+
+BUILTIN_TRANSFORMATION ("ANSI_X3.4-1968//", "INTERNAL", 1, "=ascii->INTERNAL",
+			__gconv_transform_ascii_internal, __gconv_btwoc_ascii,
+			1, 1, 4, 4)
+
+BUILTIN_TRANSFORMATION ("INTERNAL", "ANSI_X3.4-1968//", 1, "=INTERNAL->ascii",
+			__gconv_transform_internal_ascii, NULL, 4, 4, 1, 1)
+
+
+#if BYTE_ORDER == BIG_ENDIAN
+BUILTIN_ALIAS ("UNICODEBIG//", "ISO-10646/UCS2/")
+BUILTIN_ALIAS ("UCS-2BE//", "ISO-10646/UCS2/")
+
+BUILTIN_ALIAS ("UCS-2LE//", "UNICODELITTLE//")
+
+BUILTIN_TRANSFORMATION ("UNICODELITTLE//", "INTERNAL", 1,
+			"=ucs2reverse->INTERNAL",
+			__gconv_transform_ucs2reverse_internal, NULL,
+			2, 2, 4, 4)
+
+BUILTIN_TRANSFORMATION ("INTERNAL", "UNICODELITTLE//", 1,
+			"=INTERNAL->ucs2reverse",
+			__gconv_transform_internal_ucs2reverse, NULL,
+			4, 4, 2, 2)
+#else
+BUILTIN_ALIAS ("UNICODELITTLE//", "ISO-10646/UCS2/")
+BUILTIN_ALIAS ("UCS-2LE//", "ISO-10646/UCS2/")
+
+BUILTIN_ALIAS ("UCS-2BE//", "UNICODEBIG//")
+
+BUILTIN_TRANSFORMATION ("UNICODEBIG//", "INTERNAL", 1,
+			"=ucs2reverse->INTERNAL",
+			__gconv_transform_ucs2reverse_internal, NULL,
+			2, 2, 4, 4)
+
+BUILTIN_TRANSFORMATION ("INTERNAL", "UNICODEBIG//", 1,
+			"=INTERNAL->ucs2reverse",
+			__gconv_transform_internal_ucs2reverse, NULL,
+			4, 4, 2, 2)
+#endif
diff --git a/REORG.TODO/iconv/gconv_cache.c b/REORG.TODO/iconv/gconv_cache.c
new file mode 100644
index 0000000000..0cadea3638
--- /dev/null
+++ b/REORG.TODO/iconv/gconv_cache.c
@@ -0,0 +1,472 @@
+/* Cache handling for iconv modules.
+   Copyright (C) 2001-2017 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+   Contributed by Ulrich Drepper <drepper@cygnus.com>, 2001.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 2.1 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
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with the GNU C Library; if not, see
+   <http://www.gnu.org/licenses/>.  */
+
+#include <dlfcn.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+#include <sys/mman.h>
+#include <sys/stat.h>
+
+#include <gconv_int.h>
+#include <iconvconfig.h>
+#include <not-cancel.h>
+
+#include "../intl/hash-string.h"
+
+static void *gconv_cache;
+static size_t cache_size;
+static int cache_malloced;
+
+
+void *
+__gconv_get_cache (void)
+{
+  return gconv_cache;
+}
+
+
+int
+internal_function
+__gconv_load_cache (void)
+{
+  int fd;
+  struct stat64 st;
+  struct gconvcache_header *header;
+
+  /* We cannot use the cache if the GCONV_PATH environment variable is
+     set.  */
+  __gconv_path_envvar = getenv ("GCONV_PATH");
+  if (__gconv_path_envvar != NULL)
+    return -1;
+
+  /* See whether the cache file exists.  */
+  fd = open_not_cancel (GCONV_MODULES_CACHE, O_RDONLY, 0);
+  if (__builtin_expect (fd, 0) == -1)
+    /* Not available.  */
+    return -1;
+
+  /* Get information about the file.  */
+  if (__builtin_expect (__fxstat64 (_STAT_VER, fd, &st), 0) < 0
+      /* We do not have to start looking at the file if it cannot contain
+	 at least the cache header.  */
+      || (size_t) st.st_size < sizeof (struct gconvcache_header))
+    {
+    close_and_exit:
+      close_not_cancel_no_status (fd);
+      return -1;
+    }
+
+  /* Make the file content available.  */
+  cache_size = st.st_size;
+#ifdef _POSIX_MAPPED_FILES
+  gconv_cache = __mmap (NULL, cache_size, PROT_READ, MAP_SHARED, fd, 0);
+  if (__glibc_unlikely (gconv_cache == MAP_FAILED))
+#endif
+    {
+      size_t already_read;
+
+      gconv_cache = malloc (cache_size);
+      if (gconv_cache == NULL)
+	goto close_and_exit;
+
+      already_read = 0;
+      do
+	{
+	  ssize_t n = __read (fd, (char *) gconv_cache + already_read,
+			      cache_size - already_read);
+	  if (__builtin_expect (n, 0) == -1)
+	    {
+	      free (gconv_cache);
+	      gconv_cache = NULL;
+	      goto close_and_exit;
+	    }
+
+	  already_read += n;
+	}
+      while (already_read < cache_size);
+
+      cache_malloced = 1;
+    }
+
+  /* We don't need the file descriptor anymore.  */
+  close_not_cancel_no_status (fd);
+
+  /* Check the consistency.  */
+  header = (struct gconvcache_header *) gconv_cache;
+  if (__builtin_expect (header->magic, GCONVCACHE_MAGIC) != GCONVCACHE_MAGIC
+      || __builtin_expect (header->string_offset >= cache_size, 0)
+      || __builtin_expect (header->hash_offset >= cache_size, 0)
+      || __builtin_expect (header->hash_size == 0, 0)
+      || __builtin_expect ((header->hash_offset
+			    + header->hash_size * sizeof (struct hash_entry))
+			   > cache_size, 0)
+      || __builtin_expect (header->module_offset >= cache_size, 0)
+      || __builtin_expect (header->otherconv_offset > cache_size, 0))
+    {
+      if (cache_malloced)
+	{
+	  free (gconv_cache);
+	  cache_malloced = 0;
+	}
+#ifdef _POSIX_MAPPED_FILES
+      else
+	__munmap (gconv_cache, cache_size);
+#endif
+      gconv_cache = NULL;
+
+      return -1;
+    }
+
+  /* That worked.  */
+  return 0;
+}
+
+
+static int
+internal_function
+find_module_idx (const char *str, size_t *idxp)
+{
+  unsigned int idx;
+  unsigned int hval;
+  unsigned int hval2;
+  const struct gconvcache_header *header;
+  const char *strtab;
+  const struct hash_entry *hashtab;
+  unsigned int limit;
+
+  header = (const struct gconvcache_header *) gconv_cache;
+  strtab = (char *) gconv_cache + header->string_offset;
+  hashtab = (struct hash_entry *) ((char *) gconv_cache
+				   + header->hash_offset);
+
+  hval = __hash_string (str);
+  idx = hval % header->hash_size;
+  hval2 = 1 + hval % (header->hash_size - 2);
+
+  limit = cache_size - header->string_offset;
+  while (hashtab[idx].string_offset != 0)
+    if (hashtab[idx].string_offset < limit
+	&& strcmp (str, strtab + hashtab[idx].string_offset) == 0)
+      {
+	*idxp = hashtab[idx].module_idx;
+	return 0;
+      }
+    else
+      if ((idx += hval2) >= header->hash_size)
+	idx -= header->hash_size;
+
+  /* Nothing found.  */
+  return -1;
+}
+
+
+#ifndef STATIC_GCONV
+static int
+internal_function
+find_module (const char *directory, const char *filename,
+	     struct __gconv_step *result)
+{
+  size_t dirlen = strlen (directory);
+  size_t fnamelen = strlen (filename) + 1;
+  char fullname[dirlen + fnamelen];
+  int status = __GCONV_NOCONV;
+
+  memcpy (__mempcpy (fullname, directory, dirlen), filename, fnamelen);
+
+  result->__shlib_handle = __gconv_find_shlib (fullname);
+  if (result->__shlib_handle != NULL)
+    {
+      status = __GCONV_OK;
+
+      result->__modname = NULL;
+      result->__fct = result->__shlib_handle->fct;
+      result->__init_fct = result->__shlib_handle->init_fct;
+      result->__end_fct = result->__shlib_handle->end_fct;
+
+      /* These settings can be overridden by the init function.  */
+      result->__btowc_fct = NULL;
+      result->__data = NULL;
+
+      /* Call the init function.  */
+      if (result->__init_fct != NULL)
+	{
+	  __gconv_init_fct init_fct = result->__init_fct;
+#ifdef PTR_DEMANGLE
+	  PTR_DEMANGLE (init_fct);
+#endif
+	  status = DL_CALL_FCT (init_fct, (result));
+
+#ifdef PTR_MANGLE
+	  if (result->__btowc_fct != NULL)
+	    PTR_MANGLE (result->__btowc_fct);
+#endif
+	}
+    }
+
+  return status;
+}
+#endif
+
+
+int
+internal_function
+__gconv_compare_alias_cache (const char *name1, const char *name2, int *result)
+{
+  size_t name1_idx;
+  size_t name2_idx;
+
+  if (gconv_cache == NULL)
+    return -1;
+
+  if (find_module_idx (name1, &name1_idx) != 0
+      || find_module_idx (name2, &name2_idx) != 0)
+    *result = strcmp (name1, name2);
+  else
+    *result = (int) (name1_idx - name2_idx);
+
+  return 0;
+}
+
+
+int
+internal_function
+__gconv_lookup_cache (const char *toset, const char *fromset,
+		      struct __gconv_step **handle, size_t *nsteps, int flags)
+{
+  const struct gconvcache_header *header;
+  const char *strtab;
+  size_t fromidx;
+  size_t toidx;
+  const struct module_entry *modtab;
+  const struct module_entry *from_module;
+  const struct module_entry *to_module;
+  struct __gconv_step *result;
+
+  if (gconv_cache == NULL)
+    /* We have no cache available.  */
+    return __GCONV_NODB;
+
+  header = (const struct gconvcache_header *) gconv_cache;
+  strtab = (char *) gconv_cache + header->string_offset;
+  modtab = (const struct module_entry *) ((char *) gconv_cache
+					  + header->module_offset);
+
+  if (find_module_idx (fromset, &fromidx) != 0
+      || (header->module_offset + (fromidx + 1) * sizeof (struct module_entry)
+	  > cache_size))
+    return __GCONV_NOCONV;
+  from_module = &modtab[fromidx];
+
+  if (find_module_idx (toset, &toidx) != 0
+      || (header->module_offset + (toidx + 1) * sizeof (struct module_entry)
+	  > cache_size))
+    return __GCONV_NOCONV;
+  to_module = &modtab[toidx];
+
+  /* Avoid copy-only transformations if the user requests.   */
+  if (__builtin_expect (flags & GCONV_AVOID_NOCONV, 0) && fromidx == toidx)
+    return __GCONV_NULCONV;
+
+  /* If there are special conversions available examine them first.  */
+  if (fromidx != 0 && toidx != 0
+      && __builtin_expect (from_module->extra_offset, 0) != 0)
+    {
+      /* Search through the list to see whether there is a module
+	 matching the destination character set.  */
+      const struct extra_entry *extra;
+
+      /* Note the -1.  This is due to the offset added in iconvconfig.
+	 See there for more explanations.  */
+      extra = (const struct extra_entry *) ((char *) gconv_cache
+					    + header->otherconv_offset
+					    + from_module->extra_offset - 1);
+      while (extra->module_cnt != 0
+	     && extra->module[extra->module_cnt - 1].outname_offset != toidx)
+	extra = (const struct extra_entry *) ((char *) extra
+					      + sizeof (struct extra_entry)
+					      + (extra->module_cnt
+						 * sizeof (struct extra_entry_module)));
+
+      if (extra->module_cnt != 0)
+	{
+	  /* Use the extra module.  First determine how many steps.  */
+	  char *fromname;
+	  int idx;
+
+	  *nsteps = extra->module_cnt;
+	  *handle = result =
+	    (struct __gconv_step *) malloc (extra->module_cnt
+					    * sizeof (struct __gconv_step));
+	  if (result == NULL)
+	    return __GCONV_NOMEM;
+
+	  fromname = (char *) strtab + from_module->canonname_offset;
+	  idx = 0;
+	  do
+	    {
+	      result[idx].__from_name = fromname;
+	      fromname = result[idx].__to_name =
+		(char *) strtab + modtab[extra->module[idx].outname_offset].canonname_offset;
+
+	      result[idx].__counter = 1;
+	      result[idx].__data = NULL;
+
+#ifndef STATIC_GCONV
+	      if (strtab[extra->module[idx].dir_offset] != '\0')
+		{
+		  /* Load the module, return handle for it.  */
+		  int res;
+
+		  res = find_module (strtab + extra->module[idx].dir_offset,
+				     strtab + extra->module[idx].name_offset,
+				     &result[idx]);
+		  if (__builtin_expect (res, __GCONV_OK) != __GCONV_OK)
+		    {
+		      /* Something went wrong.  */
+		      free (result);
+		      goto try_internal;
+		    }
+		}
+	      else
+#endif
+		/* It's a builtin transformation.  */
+		__gconv_get_builtin_trans (strtab
+					   + extra->module[idx].name_offset,
+					   &result[idx]);
+
+	    }
+	  while (++idx < extra->module_cnt);
+
+	  return __GCONV_OK;
+	}
+    }
+
+ try_internal:
+  /* See whether we can convert via the INTERNAL charset.  */
+  if ((fromidx != 0 && __builtin_expect (from_module->fromname_offset, 1) == 0)
+      || (toidx != 0 && __builtin_expect (to_module->toname_offset, 1) == 0)
+      || (fromidx == 0 && toidx == 0))
+    /* Not possible.  Nothing we can do.  */
+    return __GCONV_NOCONV;
+
+  /* We will use up to two modules.  Always allocate room for two.  */
+  result = (struct __gconv_step *) malloc (2 * sizeof (struct __gconv_step));
+  if (result == NULL)
+    return __GCONV_NOMEM;
+
+  *handle = result;
+  *nsteps = 0;
+
+  /* Generate data structure for conversion to INTERNAL.  */
+  if (fromidx != 0)
+    {
+      result[0].__from_name = (char *) strtab + from_module->canonname_offset;
+      result[0].__to_name = (char *) "INTERNAL";
+
+      result[0].__counter = 1;
+      result[0].__data = NULL;
+
+#ifndef STATIC_GCONV
+      if (strtab[from_module->todir_offset] != '\0')
+	{
+	  /* Load the module, return handle for it.  */
+	  int res = find_module (strtab + from_module->todir_offset,
+				 strtab + from_module->toname_offset,
+				 &result[0]);
+	  if (__builtin_expect (res, __GCONV_OK) != __GCONV_OK)
+	    {
+	      /* Something went wrong.  */
+	      free (result);
+	      return res;
+	    }
+	}
+      else
+#endif
+	/* It's a builtin transformation.  */
+	__gconv_get_builtin_trans (strtab + from_module->toname_offset,
+				   &result[0]);
+
+      ++*nsteps;
+    }
+
+  /* Generate data structure for conversion from INTERNAL.  */
+  if (toidx != 0)
+    {
+      int idx = *nsteps;
+
+      result[idx].__from_name = (char *) "INTERNAL";
+      result[idx].__to_name = (char *) strtab + to_module->canonname_offset;
+
+      result[idx].__counter = 1;
+      result[idx].__data = NULL;
+
+#ifndef STATIC_GCONV
+      if (strtab[to_module->fromdir_offset] != '\0')
+	{
+	  /* Load the module, return handle for it.  */
+	  int res = find_module (strtab + to_module->fromdir_offset,
+				 strtab + to_module->fromname_offset,
+				 &result[idx]);
+	  if (__builtin_expect (res, __GCONV_OK) != __GCONV_OK)
+	    {
+	      /* Something went wrong.  */
+	      if (idx != 0)
+		__gconv_release_step (&result[0]);
+	      free (result);
+	      return res;
+	    }
+	}
+      else
+#endif
+	/* It's a builtin transformation.  */
+	__gconv_get_builtin_trans (strtab + to_module->fromname_offset,
+				   &result[idx]);
+
+      ++*nsteps;
+    }
+
+  return __GCONV_OK;
+}
+
+
+/* Free memory allocated for the transformation record.  */
+void
+internal_function
+__gconv_release_cache (struct __gconv_step *steps, size_t nsteps)
+{
+  if (gconv_cache != NULL)
+    /* The only thing we have to deallocate is the record with the
+       steps.  */
+    free (steps);
+}
+
+
+/* Free all resources if necessary.  */
+libc_freeres_fn (free_mem)
+{
+  if (cache_malloced)
+    free (gconv_cache);
+#ifdef _POSIX_MAPPED_FILES
+  else if (gconv_cache != NULL)
+    __munmap (gconv_cache, cache_size);
+#endif
+}
diff --git a/REORG.TODO/iconv/gconv_charset.h b/REORG.TODO/iconv/gconv_charset.h
new file mode 100644
index 0000000000..18d8bd6ae7
--- /dev/null
+++ b/REORG.TODO/iconv/gconv_charset.h
@@ -0,0 +1,57 @@
+/* Charset name normalization.
+   Copyright (C) 2001-2017 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+   Contributed by Ulrich Drepper <drepper@cygnus.com>, 2001.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 2.1 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
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with the GNU C Library; if not, see
+   <http://www.gnu.org/licenses/>.  */
+
+#include <ctype.h>
+#include <locale.h>
+
+
+static void
+strip (char *wp, const char *s)
+{
+  int slash_count = 0;
+
+  while (*s != '\0')
+    {
+      if (__isalnum_l (*s, _nl_C_locobj_ptr)
+	  || *s == '_' || *s == '-' || *s == '.' || *s == ',' || *s == ':')
+	*wp++ = __toupper_l (*s, _nl_C_locobj_ptr);
+      else if (*s == '/')
+	{
+	  if (++slash_count == 3)
+	    break;
+	  *wp++ = '/';
+	}
+      ++s;
+    }
+
+  while (slash_count++ < 2)
+    *wp++ = '/';
+
+  *wp = '\0';
+}
+
+
+static inline char * __attribute__ ((unused, always_inline))
+upstr (char *dst, const char *str)
+{
+  char *cp = dst;
+  while ((*cp++ = __toupper_l (*str++, _nl_C_locobj_ptr)) != '\0')
+    /* nothing */;
+  return dst;
+}
diff --git a/REORG.TODO/iconv/gconv_close.c b/REORG.TODO/iconv/gconv_close.c
new file mode 100644
index 0000000000..4853dd8779
--- /dev/null
+++ b/REORG.TODO/iconv/gconv_close.c
@@ -0,0 +1,50 @@
+/* Release any resource associated with given conversion descriptor.
+   Copyright (C) 1997-2017 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+   Contributed by Ulrich Drepper <drepper@cygnus.com>, 1997.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 2.1 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
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with the GNU C Library; if not, see
+   <http://www.gnu.org/licenses/>.  */
+
+#include <stdlib.h>
+
+#include <gconv_int.h>
+
+
+int
+internal_function
+__gconv_close (__gconv_t cd)
+{
+  struct __gconv_step *srunp;
+  struct __gconv_step_data *drunp;
+  size_t nsteps;
+
+  /* Free all resources by calling destructor functions and release
+     the implementations.  */
+  srunp = cd->__steps;
+  nsteps = cd->__nsteps;
+  drunp = cd->__data;
+  do
+    {
+      if (!(drunp->__flags & __GCONV_IS_LAST) && drunp->__outbuf != NULL)
+	free (drunp->__outbuf);
+    }
+  while (!((drunp++)->__flags & __GCONV_IS_LAST));
+
+  /* Free the data allocated for the descriptor.  */
+  free (cd);
+
+  /* Close the participating modules.  */
+  return __gconv_close_transform (srunp, nsteps);
+}
diff --git a/REORG.TODO/iconv/gconv_conf.c b/REORG.TODO/iconv/gconv_conf.c
new file mode 100644
index 0000000000..5aa055de6e
--- /dev/null
+++ b/REORG.TODO/iconv/gconv_conf.c
@@ -0,0 +1,616 @@
+/* Handle configuration data.
+   Copyright (C) 1997-2017 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+   Contributed by Ulrich Drepper <drepper@cygnus.com>, 1997.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 2.1 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
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with the GNU C Library; if not, see
+   <http://www.gnu.org/licenses/>.  */
+
+#include <assert.h>
+#include <ctype.h>
+#include <errno.h>
+#include <limits.h>
+#include <locale.h>
+#include <search.h>
+#include <stddef.h>
+#include <stdio.h>
+#include <stdio_ext.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+#include <sys/param.h>
+
+#include <libc-lock.h>
+#include <gconv_int.h>
+
+
+/* This is the default path where we look for module lists.  */
+static const char default_gconv_path[] = GCONV_PATH;
+
+/* The path elements, as determined by the __gconv_get_path function.
+   All path elements end in a slash.  */
+struct path_elem *__gconv_path_elem;
+/* Maximum length of a single path element in __gconv_path_elem.  */
+size_t __gconv_max_path_elem_len;
+
+/* We use the following struct if we couldn't allocate memory.  */
+static const struct path_elem empty_path_elem = { NULL, 0 };
+
+/* Name of the file containing the module information in the directories
+   along the path.  */
+static const char gconv_conf_filename[] = "gconv-modules";
+
+/* Filename extension for the modules.  */
+#ifndef MODULE_EXT
+# define MODULE_EXT ".so"
+#endif
+static const char gconv_module_ext[] = MODULE_EXT;
+
+/* We have a few builtin transformations.  */
+static struct gconv_module builtin_modules[] =
+{
+#define BUILTIN_TRANSFORMATION(From, To, Cost, Name, Fct, BtowcFct, \
+			       MinF, MaxF, MinT, MaxT) \
+  {									      \
+    .from_string = From,						      \
+    .to_string = To,							      \
+    .cost_hi = Cost,							      \
+    .cost_lo = INT_MAX,							      \
+    .module_name = Name							      \
+  },
+#define BUILTIN_ALIAS(From, To)
+
+#include "gconv_builtin.h"
+
+#undef BUILTIN_TRANSFORMATION
+#undef BUILTIN_ALIAS
+};
+
+static const char builtin_aliases[] =
+{
+#define BUILTIN_TRANSFORMATION(From, To, Cost, Name, Fct, BtowcFct, \
+			       MinF, MaxF, MinT, MaxT)
+#define BUILTIN_ALIAS(From, To) From "\0" To "\0"
+
+#include "gconv_builtin.h"
+
+#undef BUILTIN_TRANSFORMATION
+#undef BUILTIN_ALIAS
+};
+
+#include <libio/libioP.h>
+#define __getdelim(line, len, c, fp) _IO_getdelim (line, len, c, fp)
+
+
+/* Value of the GCONV_PATH environment variable.  */
+const char *__gconv_path_envvar;
+
+
+/* Test whether there is already a matching module known.  */
+static int
+internal_function
+detect_conflict (const char *alias)
+{
+  struct gconv_module *node = __gconv_modules_db;
+
+  while (node != NULL)
+    {
+      int cmpres = strcmp (alias, node->from_string);
+
+      if (cmpres == 0)
+	/* We have a conflict.  */
+	return 1;
+      else if (cmpres < 0)
+	node = node->left;
+      else
+	node = node->right;
+    }
+
+  return node != NULL;
+}
+
+
+/* The actual code to add aliases.  */
+static void
+add_alias2 (const char *from, const char *to, const char *wp, void *modules)
+{
+  /* Test whether this alias conflicts with any available module.  */
+  if (detect_conflict (from))
+    /* It does conflict, don't add the alias.  */
+    return;
+
+  struct gconv_alias *new_alias = (struct gconv_alias *)
+    malloc (sizeof (struct gconv_alias) + (wp - from));
+  if (new_alias != NULL)
+    {
+      void **inserted;
+
+      new_alias->fromname = memcpy ((char *) new_alias
+				    + sizeof (struct gconv_alias),
+				    from, wp - from);
+      new_alias->toname = new_alias->fromname + (to - from);
+
+      inserted = (void **) __tsearch (new_alias, &__gconv_alias_db,
+				      __gconv_alias_compare);
+      if (inserted == NULL || *inserted != new_alias)
+	/* Something went wrong, free this entry.  */
+	free (new_alias);
+    }
+}
+
+
+/* Add new alias.  */
+static void
+add_alias (char *rp, void *modules)
+{
+  /* We now expect two more string.  The strings are normalized
+     (converted to UPPER case) and strored in the alias database.  */
+  char *from, *to, *wp;
+
+  while (__isspace_l (*rp, _nl_C_locobj_ptr))
+    ++rp;
+  from = wp = rp;
+  while (*rp != '\0' && !__isspace_l (*rp, _nl_C_locobj_ptr))
+    *wp++ = __toupper_l (*rp++, _nl_C_locobj_ptr);
+  if (*rp == '\0')
+    /* There is no `to' string on the line.  Ignore it.  */
+    return;
+  *wp++ = '\0';
+  to = ++rp;
+  while (__isspace_l (*rp, _nl_C_locobj_ptr))
+    ++rp;
+  while (*rp != '\0' && !__isspace_l (*rp, _nl_C_locobj_ptr))
+    *wp++ = __toupper_l (*rp++, _nl_C_locobj_ptr);
+  if (to == wp)
+    /* No `to' string, ignore the line.  */
+    return;
+  *wp++ = '\0';
+
+  add_alias2 (from, to, wp, modules);
+}
+
+
+/* Insert a data structure for a new module in the search tree.  */
+static void
+internal_function
+insert_module (struct gconv_module *newp, int tobefreed)
+{
+  struct gconv_module **rootp = &__gconv_modules_db;
+
+  while (*rootp != NULL)
+    {
+      struct gconv_module *root = *rootp;
+      int cmpres;
+
+      cmpres = strcmp (newp->from_string, root->from_string);
+      if (cmpres == 0)
+	{
+	  /* Both strings are identical.  Insert the string at the
+	     end of the `same' list if it is not already there.  */
+	  while (strcmp (newp->from_string, root->from_string) != 0
+		 || strcmp (newp->to_string, root->to_string) != 0)
+	    {
+	      rootp = &root->same;
+	      root = *rootp;
+	      if (root == NULL)
+		break;
+	    }
+
+	  if (root != NULL)
+	    {
+	      /* This is a no new conversion.  But maybe the cost is
+		 better.  */
+	      if (newp->cost_hi < root->cost_hi
+		  || (newp->cost_hi == root->cost_hi
+		      && newp->cost_lo < root->cost_lo))
+		{
+		  newp->left = root->left;
+		  newp->right = root->right;
+		  newp->same = root->same;
+		  *rootp = newp;
+
+		  free (root);
+		}
+	      else if (tobefreed)
+		free (newp);
+	      return;
+	    }
+
+	  break;
+	}
+      else if (cmpres < 0)
+	rootp = &root->left;
+      else
+	rootp = &root->right;
+    }
+
+  /* Plug in the new node here.  */
+  *rootp = newp;
+}
+
+
+/* Add new module.  */
+static void
+internal_function
+add_module (char *rp, const char *directory, size_t dir_len, void **modules,
+	    size_t *nmodules, int modcounter)
+{
+  /* We expect now
+     1. `from' name
+     2. `to' name
+     3. filename of the module
+     4. an optional cost value
+  */
+  struct gconv_alias fake_alias;
+  struct gconv_module *new_module;
+  char *from, *to, *module, *wp;
+  int need_ext;
+  int cost_hi;
+
+  while (__isspace_l (*rp, _nl_C_locobj_ptr))
+    ++rp;
+  from = rp;
+  while (*rp != '\0' && !__isspace_l (*rp, _nl_C_locobj_ptr))
+    {
+      *rp = __toupper_l (*rp, _nl_C_locobj_ptr);
+      ++rp;
+    }
+  if (*rp == '\0')
+    return;
+  *rp++ = '\0';
+  to = wp = rp;
+  while (__isspace_l (*rp, _nl_C_locobj_ptr))
+    ++rp;
+  while (*rp != '\0' && !__isspace_l (*rp, _nl_C_locobj_ptr))
+    *wp++ = __toupper_l (*rp++, _nl_C_locobj_ptr);
+  if (*rp == '\0')
+    return;
+  *wp++ = '\0';
+  do
+    ++rp;
+  while (__isspace_l (*rp, _nl_C_locobj_ptr));
+  module = wp;
+  while (*rp != '\0' && !__isspace_l (*rp, _nl_C_locobj_ptr))
+    *wp++ = *rp++;
+  if (*rp == '\0')
+    {
+      /* There is no cost, use one by default.  */
+      *wp++ = '\0';
+      cost_hi = 1;
+    }
+  else
+    {
+      /* There might be a cost value.  */
+      char *endp;
+
+      *wp++ = '\0';
+      cost_hi = strtol (rp, &endp, 10);
+      if (rp == endp || cost_hi < 1)
+	/* No useful information.  */
+	cost_hi = 1;
+    }
+
+  if (module[0] == '\0')
+    /* No module name given.  */
+    return;
+  if (module[0] == '/')
+    dir_len = 0;
+
+  /* See whether we must add the ending.  */
+  need_ext = 0;
+  if (wp - module < (ptrdiff_t) sizeof (gconv_module_ext)
+      || memcmp (wp - sizeof (gconv_module_ext), gconv_module_ext,
+		 sizeof (gconv_module_ext)) != 0)
+    /* We must add the module extension.  */
+    need_ext = sizeof (gconv_module_ext) - 1;
+
+  /* See whether we have already an alias with this name defined.  */
+  fake_alias.fromname = strndupa (from, to - from);
+
+  if (__tfind (&fake_alias, &__gconv_alias_db, __gconv_alias_compare) != NULL)
+    /* This module duplicates an alias.  */
+    return;
+
+  new_module = (struct gconv_module *) calloc (1,
+					       sizeof (struct gconv_module)
+					       + (wp - from)
+					       + dir_len + need_ext);
+  if (new_module != NULL)
+    {
+      char *tmp;
+
+      new_module->from_string = tmp = (char *) (new_module + 1);
+      tmp = __mempcpy (tmp, from, to - from);
+
+      new_module->to_string = tmp;
+      tmp = __mempcpy (tmp, to, module - to);
+
+      new_module->cost_hi = cost_hi;
+      new_module->cost_lo = modcounter;
+
+      new_module->module_name = tmp;
+
+      if (dir_len != 0)
+	tmp = __mempcpy (tmp, directory, dir_len);
+
+      tmp = __mempcpy (tmp, module, wp - module);
+
+      if (need_ext)
+	memcpy (tmp - 1, gconv_module_ext, sizeof (gconv_module_ext));
+
+      /* Now insert the new module data structure in our search tree.  */
+      insert_module (new_module, 1);
+    }
+}
+
+
+/* Read the next configuration file.  */
+static void
+internal_function
+read_conf_file (const char *filename, const char *directory, size_t dir_len,
+		void **modules, size_t *nmodules)
+{
+  /* Note the file is opened with cancellation in the I/O functions
+     disabled.  */
+  FILE *fp = fopen (filename, "rce");
+  char *line = NULL;
+  size_t line_len = 0;
+  static int modcounter;
+
+  /* Don't complain if a file is not present or readable, simply silently
+     ignore it.  */
+  if (fp == NULL)
+    return;
+
+  /* No threads reading from this stream.  */
+  __fsetlocking (fp, FSETLOCKING_BYCALLER);
+
+  /* Process the known entries of the file.  Comments start with `#' and
+     end with the end of the line.  Empty lines are ignored.  */
+  while (!feof_unlocked (fp))
+    {
+      char *rp, *endp, *word;
+      ssize_t n = __getdelim (&line, &line_len, '\n', fp);
+      if (n < 0)
+	/* An error occurred.  */
+	break;
+
+      rp = line;
+      /* Terminate the line (excluding comments or newline) by an NUL byte
+	 to simplify the following code.  */
+      endp = strchr (rp, '#');
+      if (endp != NULL)
+	*endp = '\0';
+      else
+	if (rp[n - 1] == '\n')
+	  rp[n - 1] = '\0';
+
+      while (__isspace_l (*rp, _nl_C_locobj_ptr))
+	++rp;
+
+      /* If this is an empty line go on with the next one.  */
+      if (rp == endp)
+	continue;
+
+      word = rp;
+      while (*rp != '\0' && !__isspace_l (*rp, _nl_C_locobj_ptr))
+	++rp;
+
+      if (rp - word == sizeof ("alias") - 1
+	  && memcmp (word, "alias", sizeof ("alias") - 1) == 0)
+	add_alias (rp, *modules);
+      else if (rp - word == sizeof ("module") - 1
+	       && memcmp (word, "module", sizeof ("module") - 1) == 0)
+	add_module (rp, directory, dir_len, modules, nmodules, modcounter++);
+      /* else */
+	/* Otherwise ignore the line.  */
+    }
+
+  free (line);
+
+  fclose (fp);
+}
+
+
+/* Determine the directories we are looking for data in.  */
+void
+internal_function
+__gconv_get_path (void)
+{
+  struct path_elem *result;
+  __libc_lock_define_initialized (static, lock);
+
+  __libc_lock_lock (lock);
+
+  /* Make sure there wasn't a second thread doing it already.  */
+  result = (struct path_elem *) __gconv_path_elem;
+  if (result == NULL)
+    {
+      /* Determine the complete path first.  */
+      char *gconv_path;
+      size_t gconv_path_len;
+      char *elem;
+      char *oldp;
+      char *cp;
+      int nelems;
+      char *cwd;
+      size_t cwdlen;
+
+      if (__gconv_path_envvar == NULL)
+	{
+	  /* No user-defined path.  Make a modifiable copy of the
+	     default path.  */
+	  gconv_path = strdupa (default_gconv_path);
+	  gconv_path_len = sizeof (default_gconv_path);
+	  cwd = NULL;
+	  cwdlen = 0;
+	}
+      else
+	{
+	  /* Append the default path to the user-defined path.  */
+	  size_t user_len = strlen (__gconv_path_envvar);
+
+	  gconv_path_len = user_len + 1 + sizeof (default_gconv_path);
+	  gconv_path = alloca (gconv_path_len);
+	  __mempcpy (__mempcpy (__mempcpy (gconv_path, __gconv_path_envvar,
+					   user_len),
+				":", 1),
+		     default_gconv_path, sizeof (default_gconv_path));
+	  cwd = __getcwd (NULL, 0);
+	  cwdlen = __glibc_unlikely (cwd == NULL) ? 0 : strlen (cwd);
+	}
+      assert (default_gconv_path[0] == '/');
+
+      /* In a first pass we calculate the number of elements.  */
+      oldp = NULL;
+      cp = strchr (gconv_path, ':');
+      nelems = 1;
+      while (cp != NULL)
+	{
+	  if (cp != oldp + 1)
+	    ++nelems;
+	  oldp = cp;
+	  cp =  strchr (cp + 1, ':');
+	}
+
+      /* Allocate the memory for the result.  */
+      result = (struct path_elem *) malloc ((nelems + 1)
+					    * sizeof (struct path_elem)
+					    + gconv_path_len + nelems
+					    + (nelems - 1) * (cwdlen + 1));
+      if (result != NULL)
+	{
+	  char *strspace = (char *) &result[nelems + 1];
+	  int n = 0;
+
+	  /* Separate the individual parts.  */
+	  __gconv_max_path_elem_len = 0;
+	  elem = __strtok_r (gconv_path, ":", &gconv_path);
+	  assert (elem != NULL);
+	  do
+	    {
+	      result[n].name = strspace;
+	      if (elem[0] != '/')
+		{
+		  assert (cwd != NULL);
+		  strspace = __mempcpy (strspace, cwd, cwdlen);
+		  *strspace++ = '/';
+		}
+	      strspace = __stpcpy (strspace, elem);
+	      if (strspace[-1] != '/')
+		*strspace++ = '/';
+
+	      result[n].len = strspace - result[n].name;
+	      if (result[n].len > __gconv_max_path_elem_len)
+		__gconv_max_path_elem_len = result[n].len;
+
+	      *strspace++ = '\0';
+	      ++n;
+	    }
+	  while ((elem = __strtok_r (NULL, ":", &gconv_path)) != NULL);
+
+	  result[n].name = NULL;
+	  result[n].len = 0;
+	}
+
+      __gconv_path_elem = result ?: (struct path_elem *) &empty_path_elem;
+
+      free (cwd);
+    }
+
+  __libc_lock_unlock (lock);
+}
+
+
+/* Read all configuration files found in the user-specified and the default
+   path.  */
+void
+attribute_hidden
+__gconv_read_conf (void)
+{
+  void *modules = NULL;
+  size_t nmodules = 0;
+  int save_errno = errno;
+  size_t cnt;
+
+  /* First see whether we should use the cache.  */
+  if (__gconv_load_cache () == 0)
+    {
+      /* Yes, we are done.  */
+      __set_errno (save_errno);
+      return;
+    }
+
+#ifndef STATIC_GCONV
+  /* Find out where we have to look.  */
+  if (__gconv_path_elem == NULL)
+    __gconv_get_path ();
+
+  for (cnt = 0; __gconv_path_elem[cnt].name != NULL; ++cnt)
+    {
+      const char *elem = __gconv_path_elem[cnt].name;
+      size_t elem_len = __gconv_path_elem[cnt].len;
+      char *filename;
+
+      /* No slash needs to be inserted between elem and gconv_conf_filename;
+	 elem already ends in a slash.  */
+      filename = alloca (elem_len + sizeof (gconv_conf_filename));
+      __mempcpy (__mempcpy (filename, elem, elem_len),
+		 gconv_conf_filename, sizeof (gconv_conf_filename));
+
+      /* Read the next configuration file.  */
+      read_conf_file (filename, elem, elem_len, &modules, &nmodules);
+    }
+#endif
+
+  /* Add the internal modules.  */
+  for (cnt = 0; cnt < sizeof (builtin_modules) / sizeof (builtin_modules[0]);
+       ++cnt)
+    {
+      struct gconv_alias fake_alias;
+
+      fake_alias.fromname = (char *) builtin_modules[cnt].from_string;
+
+      if (__tfind (&fake_alias, &__gconv_alias_db, __gconv_alias_compare)
+	  != NULL)
+	/* It'll conflict so don't add it.  */
+	continue;
+
+      insert_module (&builtin_modules[cnt], 0);
+    }
+
+  /* Add aliases for builtin conversions.  */
+  const char *cp = builtin_aliases;
+  do
+    {
+      const char *from = cp;
+      const char *to = __rawmemchr (from, '\0') + 1;
+      cp = __rawmemchr (to, '\0') + 1;
+
+      add_alias2 (from, to, cp, modules);
+    }
+  while (*cp != '\0');
+
+  /* Restore the error number.  */
+  __set_errno (save_errno);
+}
+
+
+
+/* Free all resources if necessary.  */
+libc_freeres_fn (free_mem)
+{
+  if (__gconv_path_elem != NULL && __gconv_path_elem != &empty_path_elem)
+    free ((void *) __gconv_path_elem);
+}
diff --git a/REORG.TODO/iconv/gconv_db.c b/REORG.TODO/iconv/gconv_db.c
new file mode 100644
index 0000000000..7893fadba1
--- /dev/null
+++ b/REORG.TODO/iconv/gconv_db.c
@@ -0,0 +1,870 @@
+/* Provide access to the collection of available transformation modules.
+   Copyright (C) 1997-2017 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+   Contributed by Ulrich Drepper <drepper@cygnus.com>, 1997.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 2.1 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
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with the GNU C Library; if not, see
+   <http://www.gnu.org/licenses/>.  */
+
+#include <assert.h>
+#include <limits.h>
+#include <search.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/param.h>
+#include <libc-lock.h>
+#include <locale/localeinfo.h>
+
+#include <dlfcn.h>
+#include <gconv_int.h>
+#include <sysdep.h>
+
+
+/* Simple data structure for alias mapping.  We have two names, `from'
+   and `to'.  */
+void *__gconv_alias_db;
+
+/* Array with available modules.  */
+struct gconv_module *__gconv_modules_db;
+
+/* We modify global data.   */
+__libc_lock_define_initialized (, __gconv_lock)
+
+
+/* Provide access to module database.  */
+struct gconv_module *
+__gconv_get_modules_db (void)
+{
+  return __gconv_modules_db;
+}
+
+void *
+__gconv_get_alias_db (void)
+{
+  return __gconv_alias_db;
+}
+
+
+/* Function for searching alias.  */
+int
+__gconv_alias_compare (const void *p1, const void *p2)
+{
+  const struct gconv_alias *s1 = (const struct gconv_alias *) p1;
+  const struct gconv_alias *s2 = (const struct gconv_alias *) p2;
+  return strcmp (s1->fromname, s2->fromname);
+}
+
+
+/* To search for a derivation we create a list of intermediate steps.
+   Each element contains a pointer to the element which precedes it
+   in the derivation order.  */
+struct derivation_step
+{
+  const char *result_set;
+  size_t result_set_len;
+  int cost_lo;
+  int cost_hi;
+  struct gconv_module *code;
+  struct derivation_step *last;
+  struct derivation_step *next;
+};
+
+#define NEW_STEP(result, hi, lo, module, last_mod) \
+  ({ struct derivation_step *newp = alloca (sizeof (struct derivation_step)); \
+     newp->result_set = result;						      \
+     newp->result_set_len = strlen (result);				      \
+     newp->cost_hi = hi;						      \
+     newp->cost_lo = lo;						      \
+     newp->code = module;						      \
+     newp->last = last_mod;						      \
+     newp->next = NULL;							      \
+     newp; })
+
+
+/* If a specific transformation is used more than once we should not need
+   to start looking for it again.  Instead cache each successful result.  */
+struct known_derivation
+{
+  const char *from;
+  const char *to;
+  struct __gconv_step *steps;
+  size_t nsteps;
+};
+
+/* Compare function for database of found derivations.  */
+static int
+derivation_compare (const void *p1, const void *p2)
+{
+  const struct known_derivation *s1 = (const struct known_derivation *) p1;
+  const struct known_derivation *s2 = (const struct known_derivation *) p2;
+  int result;
+
+  result = strcmp (s1->from, s2->from);
+  if (result == 0)
+    result = strcmp (s1->to, s2->to);
+  return result;
+}
+
+/* The search tree for known derivations.  */
+static void *known_derivations;
+
+/* Look up whether given transformation was already requested before.  */
+static int
+internal_function
+derivation_lookup (const char *fromset, const char *toset,
+		   struct __gconv_step **handle, size_t *nsteps)
+{
+  struct known_derivation key = { fromset, toset, NULL, 0 };
+  struct known_derivation **result;
+
+  result = __tfind (&key, &known_derivations, derivation_compare);
+
+  if (result == NULL)
+    return __GCONV_NOCONV;
+
+  *handle = (*result)->steps;
+  *nsteps = (*result)->nsteps;
+
+  /* Please note that we return GCONV_OK even if the last search for
+     this transformation was unsuccessful.  */
+  return __GCONV_OK;
+}
+
+/* Add new derivation to list of known ones.  */
+static void
+internal_function
+add_derivation (const char *fromset, const char *toset,
+		struct __gconv_step *handle, size_t nsteps)
+{
+  struct known_derivation *new_deriv;
+  size_t fromset_len = strlen (fromset) + 1;
+  size_t toset_len = strlen (toset) + 1;
+
+  new_deriv = (struct known_derivation *)
+    malloc (sizeof (struct known_derivation) + fromset_len + toset_len);
+  if (new_deriv != NULL)
+    {
+      new_deriv->from = (char *) (new_deriv + 1);
+      new_deriv->to = memcpy (__mempcpy (new_deriv + 1, fromset, fromset_len),
+			      toset, toset_len);
+
+      new_deriv->steps = handle;
+      new_deriv->nsteps = nsteps;
+
+      if (__tsearch (new_deriv, &known_derivations, derivation_compare)
+	  == NULL)
+	/* There is some kind of memory allocation problem.  */
+	free (new_deriv);
+    }
+  /* Please note that we don't complain if the allocation failed.  This
+     is not tragically but in case we use the memory debugging facilities
+     not all memory will be freed.  */
+}
+
+static void __libc_freeres_fn_section
+free_derivation (void *p)
+{
+  struct known_derivation *deriv = (struct known_derivation *) p;
+  size_t cnt;
+
+  for (cnt = 0; cnt < deriv->nsteps; ++cnt)
+    if (deriv->steps[cnt].__counter > 0
+	&& deriv->steps[cnt].__end_fct != NULL)
+      {
+	assert (deriv->steps[cnt].__shlib_handle != NULL);
+
+	__gconv_end_fct end_fct = deriv->steps[cnt].__end_fct;
+#ifdef PTR_DEMANGLE
+	PTR_DEMANGLE (end_fct);
+#endif
+	DL_CALL_FCT (end_fct, (&deriv->steps[cnt]));
+      }
+
+  /* Free the name strings.  */
+  if (deriv->steps != NULL)
+    {
+      free ((char *) deriv->steps[0].__from_name);
+      free ((char *) deriv->steps[deriv->nsteps - 1].__to_name);
+      free ((struct __gconv_step *) deriv->steps);
+    }
+
+  free (deriv);
+}
+
+
+/* Decrement the reference count for a single step in a steps array.  */
+void
+internal_function
+__gconv_release_step (struct __gconv_step *step)
+{
+  /* Skip builtin modules; they are not reference counted.  */
+  if (step->__shlib_handle != NULL && --step->__counter == 0)
+    {
+      /* Call the destructor.  */
+      if (step->__end_fct != NULL)
+	{
+	  assert (step->__shlib_handle != NULL);
+
+	  __gconv_end_fct end_fct = step->__end_fct;
+#ifdef PTR_DEMANGLE
+	  PTR_DEMANGLE (end_fct);
+#endif
+	  DL_CALL_FCT (end_fct, (step));
+	}
+
+#ifndef STATIC_GCONV
+      /* Release the loaded module.  */
+      __gconv_release_shlib (step->__shlib_handle);
+      step->__shlib_handle = NULL;
+#endif
+    }
+  else if (step->__shlib_handle == NULL)
+    /* Builtin modules should not have end functions.  */
+    assert (step->__end_fct == NULL);
+}
+
+static int
+internal_function
+gen_steps (struct derivation_step *best, const char *toset,
+	   const char *fromset, struct __gconv_step **handle, size_t *nsteps)
+{
+  size_t step_cnt = 0;
+  struct __gconv_step *result;
+  struct derivation_step *current;
+  int status = __GCONV_NOMEM;
+  char *from_name = NULL;
+  char *to_name = NULL;
+
+  /* First determine number of steps.  */
+  for (current = best; current->last != NULL; current = current->last)
+    ++step_cnt;
+
+  result = (struct __gconv_step *) malloc (sizeof (struct __gconv_step)
+					   * step_cnt);
+  if (result != NULL)
+    {
+      int failed = 0;
+
+      status = __GCONV_OK;
+      *nsteps = step_cnt;
+      current = best;
+      while (step_cnt-- > 0)
+	{
+	  if (step_cnt == 0)
+	    {
+	      result[step_cnt].__from_name = from_name = __strdup (fromset);
+	      if (from_name == NULL)
+		{
+		  failed = 1;
+		  break;
+		}
+	    }
+	  else
+	    result[step_cnt].__from_name = (char *)current->last->result_set;
+
+	  if (step_cnt + 1 == *nsteps)
+	    {
+	      result[step_cnt].__to_name = to_name
+		= __strdup (current->result_set);
+	      if (to_name == NULL)
+		{
+		  failed = 1;
+		  break;
+		}
+	    }
+	  else
+	    result[step_cnt].__to_name = result[step_cnt + 1].__from_name;
+
+	  result[step_cnt].__counter = 1;
+	  result[step_cnt].__data = NULL;
+
+#ifndef STATIC_GCONV
+	  if (current->code->module_name[0] == '/')
+	    {
+	      /* Load the module, return handle for it.  */
+	      struct __gconv_loaded_object *shlib_handle =
+		__gconv_find_shlib (current->code->module_name);
+
+	      if (shlib_handle == NULL)
+		{
+		  failed = 1;
+		  break;
+		}
+
+	      result[step_cnt].__shlib_handle = shlib_handle;
+	      result[step_cnt].__modname = shlib_handle->name;
+	      result[step_cnt].__fct = shlib_handle->fct;
+	      result[step_cnt].__init_fct = shlib_handle->init_fct;
+	      result[step_cnt].__end_fct = shlib_handle->end_fct;
+
+	      /* These settings can be overridden by the init function.  */
+	      result[step_cnt].__btowc_fct = NULL;
+
+	      /* Call the init function.  */
+	      __gconv_init_fct init_fct = result[step_cnt].__init_fct;
+	      if (init_fct != NULL)
+		{
+		  assert (result[step_cnt].__shlib_handle != NULL);
+
+# ifdef PTR_DEMANGLE
+		  PTR_DEMANGLE (init_fct);
+# endif
+		  status = DL_CALL_FCT (init_fct, (&result[step_cnt]));
+
+		  if (__builtin_expect (status, __GCONV_OK) != __GCONV_OK)
+		    {
+		      failed = 1;
+		      /* Make sure we unload this modules.  */
+		      --step_cnt;
+		      result[step_cnt].__end_fct = NULL;
+		      break;
+		    }
+
+# ifdef PTR_MANGLE
+		  if (result[step_cnt].__btowc_fct != NULL)
+		    PTR_MANGLE (result[step_cnt].__btowc_fct);
+# endif
+		}
+	    }
+	  else
+#endif
+	    /* It's a builtin transformation.  */
+	    __gconv_get_builtin_trans (current->code->module_name,
+				       &result[step_cnt]);
+
+	  current = current->last;
+	}
+
+      if (__builtin_expect (failed, 0) != 0)
+	{
+	  /* Something went wrong while initializing the modules.  */
+	  while (++step_cnt < *nsteps)
+	    __gconv_release_step (&result[step_cnt]);
+	  free (result);
+	  free (from_name);
+	  free (to_name);
+	  *nsteps = 0;
+	  *handle = NULL;
+	  if (status == __GCONV_OK)
+	    status = __GCONV_NOCONV;
+	}
+      else
+	*handle = result;
+    }
+  else
+    {
+      *nsteps = 0;
+      *handle = NULL;
+    }
+
+  return status;
+}
+
+
+#ifndef STATIC_GCONV
+static int
+internal_function
+increment_counter (struct __gconv_step *steps, size_t nsteps)
+{
+  /* Increment the user counter.  */
+  size_t cnt = nsteps;
+  int result = __GCONV_OK;
+
+  while (cnt-- > 0)
+    {
+      struct __gconv_step *step = &steps[cnt];
+
+      if (step->__counter++ == 0)
+	{
+	  /* Skip builtin modules.  */
+	  if (step->__modname != NULL)
+	    {
+	      /* Reopen a previously used module.  */
+	      step->__shlib_handle = __gconv_find_shlib (step->__modname);
+	      if (step->__shlib_handle == NULL)
+		{
+		  /* Oops, this is the second time we use this module
+		     (after unloading) and this time loading failed!?  */
+		  --step->__counter;
+		  while (++cnt < nsteps)
+		    __gconv_release_step (&steps[cnt]);
+		  result = __GCONV_NOCONV;
+		  break;
+		}
+
+	      /* The function addresses defined by the module may
+		 have changed.  */
+	      step->__fct = step->__shlib_handle->fct;
+	      step->__init_fct = step->__shlib_handle->init_fct;
+	      step->__end_fct = step->__shlib_handle->end_fct;
+
+	      /* These settings can be overridden by the init function.  */
+	      step->__btowc_fct = NULL;
+	    }
+
+	  /* Call the init function.  */
+	  __gconv_init_fct init_fct = step->__init_fct;
+	  if (init_fct != NULL)
+	    {
+#ifdef PTR_DEMANGLE
+	      PTR_DEMANGLE (init_fct);
+#endif
+	      DL_CALL_FCT (init_fct, (step));
+
+#ifdef PTR_MANGLE
+	      if (step->__btowc_fct != NULL)
+		PTR_MANGLE (step->__btowc_fct);
+#endif
+	    }
+	}
+    }
+  return result;
+}
+#endif
+
+
+/* The main function: find a possible derivation from the `fromset' (either
+   the given name or the alias) to the `toset' (again with alias).  */
+static int
+internal_function
+find_derivation (const char *toset, const char *toset_expand,
+		 const char *fromset, const char *fromset_expand,
+		 struct __gconv_step **handle, size_t *nsteps)
+{
+  struct derivation_step *first, *current, **lastp, *solution = NULL;
+  int best_cost_hi = INT_MAX;
+  int best_cost_lo = INT_MAX;
+  int result;
+
+  /* Look whether an earlier call to `find_derivation' has already
+     computed a possible derivation.  If so, return it immediately.  */
+  result = derivation_lookup (fromset_expand ?: fromset, toset_expand ?: toset,
+			      handle, nsteps);
+  if (result == __GCONV_OK)
+    {
+#ifndef STATIC_GCONV
+      result = increment_counter (*handle, *nsteps);
+#endif
+      return result;
+    }
+
+  /* The task is to find a sequence of transformations, backed by the
+     existing modules - whether builtin or dynamically loadable -,
+     starting at `fromset' (or `fromset_expand') and ending at `toset'
+     (or `toset_expand'), and with minimal cost.
+
+     For computer scientists, this is a shortest path search in the
+     graph where the nodes are all possible charsets and the edges are
+     the transformations listed in __gconv_modules_db.
+
+     For now we use a simple algorithm with quadratic runtime behaviour.
+     A breadth-first search, starting at `fromset' and `fromset_expand'.
+     The list starting at `first' contains all nodes that have been
+     visited up to now, in the order in which they have been visited --
+     excluding the goal nodes `toset' and `toset_expand' which get
+     managed in the list starting at `solution'.
+     `current' walks through the list starting at `first' and looks
+     which nodes are reachable from the current node, adding them to
+     the end of the list [`first' or `solution' respectively] (if
+     they are visited the first time) or updating them in place (if
+     they have have already been visited).
+     In each node of either list, cost_lo and cost_hi contain the
+     minimum cost over any paths found up to now, starting at `fromset'
+     or `fromset_expand', ending at that node.  best_cost_lo and
+     best_cost_hi represent the minimum over the elements of the
+     `solution' list.  */
+
+  if (fromset_expand != NULL)
+    {
+      first = NEW_STEP (fromset_expand, 0, 0, NULL, NULL);
+      first->next = NEW_STEP (fromset, 0, 0, NULL, NULL);
+      lastp = &first->next->next;
+    }
+  else
+    {
+      first = NEW_STEP (fromset, 0, 0, NULL, NULL);
+      lastp = &first->next;
+    }
+
+  for (current = first; current != NULL; current = current->next)
+    {
+      /* Now match all the available module specifications against the
+         current charset name.  If any of them matches check whether
+         we already have a derivation for this charset.  If yes, use the
+         one with the lower costs.  Otherwise add the new charset at the
+         end.
+
+	 The module database is organized in a tree form which allows
+	 searching for prefixes.  So we search for the first entry with a
+	 matching prefix and any other matching entry can be found from
+	 this place.  */
+      struct gconv_module *node;
+
+      /* Maybe it is not necessary anymore to look for a solution for
+	 this entry since the cost is already as high (or higher) as
+	 the cost for the best solution so far.  */
+      if (current->cost_hi > best_cost_hi
+	  || (current->cost_hi == best_cost_hi
+	      && current->cost_lo >= best_cost_lo))
+	continue;
+
+      node = __gconv_modules_db;
+      while (node != NULL)
+	{
+	  int cmpres = strcmp (current->result_set, node->from_string);
+	  if (cmpres == 0)
+	    {
+	      /* Walk through the list of modules with this prefix and
+		 try to match the name.  */
+	      struct gconv_module *runp;
+
+	      /* Check all the modules with this prefix.  */
+	      runp = node;
+	      do
+		{
+		  const char *result_set = (strcmp (runp->to_string, "-") == 0
+					    ? (toset_expand ?: toset)
+					    : runp->to_string);
+		  int cost_hi = runp->cost_hi + current->cost_hi;
+		  int cost_lo = runp->cost_lo + current->cost_lo;
+		  struct derivation_step *step;
+
+		  /* We managed to find a derivation.  First see whether
+		     we have reached one of the goal nodes.  */
+		  if (strcmp (result_set, toset) == 0
+		      || (toset_expand != NULL
+			  && strcmp (result_set, toset_expand) == 0))
+		    {
+		      /* Append to the `solution' list if there
+			 is no entry with this name.  */
+		      for (step = solution; step != NULL; step = step->next)
+			if (strcmp (result_set, step->result_set) == 0)
+			  break;
+
+		      if (step == NULL)
+			{
+			  step = NEW_STEP (result_set,
+					   cost_hi, cost_lo,
+					   runp, current);
+			  step->next = solution;
+			  solution = step;
+			}
+		      else if (step->cost_hi > cost_hi
+			       || (step->cost_hi == cost_hi
+				   && step->cost_lo > cost_lo))
+			{
+			  /* A better path was found for the node,
+			     on the `solution' list.  */
+			  step->code = runp;
+			  step->last = current;
+			  step->cost_hi = cost_hi;
+			  step->cost_lo = cost_lo;
+			}
+
+		      /* Update best_cost accordingly.  */
+		      if (cost_hi < best_cost_hi
+			  || (cost_hi == best_cost_hi
+			      && cost_lo < best_cost_lo))
+			{
+			  best_cost_hi = cost_hi;
+			  best_cost_lo = cost_lo;
+			}
+		    }
+		  else if (cost_hi < best_cost_hi
+			   || (cost_hi == best_cost_hi
+			       && cost_lo < best_cost_lo))
+		    {
+		      /* Append at the end of the `first' list if there
+			 is no entry with this name.  */
+		      for (step = first; step != NULL; step = step->next)
+			if (strcmp (result_set, step->result_set) == 0)
+			  break;
+
+		      if (step == NULL)
+			{
+			  *lastp = NEW_STEP (result_set,
+					     cost_hi, cost_lo,
+					     runp, current);
+			  lastp = &(*lastp)->next;
+			}
+		      else if (step->cost_hi > cost_hi
+			       || (step->cost_hi == cost_hi
+				   && step->cost_lo > cost_lo))
+			{
+			  /* A better path was found for the node,
+			     on the `first' list.  */
+			  step->code = runp;
+			  step->last = current;
+
+			  /* Update the cost for all steps.  */
+			  for (step = first; step != NULL;
+			       step = step->next)
+			    /* But don't update the start nodes.  */
+			    if (step->code != NULL)
+			      {
+				struct derivation_step *back;
+				int hi, lo;
+
+				hi = step->code->cost_hi;
+				lo = step->code->cost_lo;
+
+				for (back = step->last; back->code != NULL;
+				     back = back->last)
+				  {
+				    hi += back->code->cost_hi;
+				    lo += back->code->cost_lo;
+				  }
+
+				step->cost_hi = hi;
+				step->cost_lo = lo;
+			      }
+
+			  /* Likewise for the nodes on the solution list.
+			     Also update best_cost accordingly.  */
+			  for (step = solution; step != NULL;
+			       step = step->next)
+			    {
+			      step->cost_hi = (step->code->cost_hi
+					       + step->last->cost_hi);
+			      step->cost_lo = (step->code->cost_lo
+					       + step->last->cost_lo);
+
+			      if (step->cost_hi < best_cost_hi
+				  || (step->cost_hi == best_cost_hi
+				      && step->cost_lo < best_cost_lo))
+				{
+				  best_cost_hi = step->cost_hi;
+				  best_cost_lo = step->cost_lo;
+				}
+			    }
+			}
+		    }
+
+		  runp = runp->same;
+		}
+	      while (runp != NULL);
+
+	      break;
+	    }
+	  else if (cmpres < 0)
+	    node = node->left;
+	  else
+	    node = node->right;
+	}
+    }
+
+  if (solution != NULL)
+    {
+      /* We really found a way to do the transformation.  */
+
+      /* Choose the best solution.  This is easy because we know that
+	 the solution list has at most length 2 (one for every possible
+	 goal node).  */
+      if (solution->next != NULL)
+	{
+	  struct derivation_step *solution2 = solution->next;
+
+	  if (solution2->cost_hi < solution->cost_hi
+	      || (solution2->cost_hi == solution->cost_hi
+		  && solution2->cost_lo < solution->cost_lo))
+	    solution = solution2;
+	}
+
+      /* Now build a data structure describing the transformation steps.  */
+      result = gen_steps (solution, toset_expand ?: toset,
+			  fromset_expand ?: fromset, handle, nsteps);
+    }
+  else
+    {
+      /* We haven't found a transformation.  Clear the result values.  */
+      *handle = NULL;
+      *nsteps = 0;
+    }
+
+  /* Add result in any case to list of known derivations.  */
+  add_derivation (fromset_expand ?: fromset, toset_expand ?: toset,
+		  *handle, *nsteps);
+
+  return result;
+}
+
+
+/* Control of initialization.  */
+__libc_once_define (static, once);
+
+
+static const char *
+do_lookup_alias (const char *name)
+{
+  struct gconv_alias key;
+  struct gconv_alias **found;
+
+  key.fromname = (char *) name;
+  found = __tfind (&key, &__gconv_alias_db, __gconv_alias_compare);
+  return found != NULL ? (*found)->toname : NULL;
+}
+
+
+int
+internal_function
+__gconv_compare_alias (const char *name1, const char *name2)
+{
+  int result;
+
+  /* Ensure that the configuration data is read.  */
+  __libc_once (once, __gconv_read_conf);
+
+  if (__gconv_compare_alias_cache (name1, name2, &result) != 0)
+    result = strcmp (do_lookup_alias (name1) ?: name1,
+		     do_lookup_alias (name2) ?: name2);
+
+  return result;
+}
+
+
+int
+internal_function
+__gconv_find_transform (const char *toset, const char *fromset,
+			struct __gconv_step **handle, size_t *nsteps,
+			int flags)
+{
+  const char *fromset_expand;
+  const char *toset_expand;
+  int result;
+
+  /* Ensure that the configuration data is read.  */
+  __libc_once (once, __gconv_read_conf);
+
+  /* Acquire the lock.  */
+  __libc_lock_lock (__gconv_lock);
+
+  result = __gconv_lookup_cache (toset, fromset, handle, nsteps, flags);
+  if (result != __GCONV_NODB)
+    {
+      /* We have a cache and could resolve the request, successful or not.  */
+      __libc_lock_unlock (__gconv_lock);
+      return result;
+    }
+
+  /* If we don't have a module database return with an error.  */
+  if (__gconv_modules_db == NULL)
+    {
+      __libc_lock_unlock (__gconv_lock);
+      return __GCONV_NOCONV;
+    }
+
+  /* See whether the names are aliases.  */
+  fromset_expand = do_lookup_alias (fromset);
+  toset_expand = do_lookup_alias (toset);
+
+  if (__builtin_expect (flags & GCONV_AVOID_NOCONV, 0)
+      /* We are not supposed to create a pseudo transformation (means
+	 copying) when the input and output character set are the same.  */
+      && (strcmp (toset, fromset) == 0
+	  || (toset_expand != NULL && strcmp (toset_expand, fromset) == 0)
+	  || (fromset_expand != NULL
+	      && (strcmp (toset, fromset_expand) == 0
+		  || (toset_expand != NULL
+		      && strcmp (toset_expand, fromset_expand) == 0)))))
+    {
+      /* Both character sets are the same.  */
+      __libc_lock_unlock (__gconv_lock);
+      return __GCONV_NULCONV;
+    }
+
+  result = find_derivation (toset, toset_expand, fromset, fromset_expand,
+			    handle, nsteps);
+
+  /* Release the lock.  */
+  __libc_lock_unlock (__gconv_lock);
+
+  /* The following code is necessary since `find_derivation' will return
+     GCONV_OK even when no derivation was found but the same request
+     was processed before.  I.e., negative results will also be cached.  */
+  return (result == __GCONV_OK
+	  ? (*handle == NULL ? __GCONV_NOCONV : __GCONV_OK)
+	  : result);
+}
+
+
+/* Release the entries of the modules list.  */
+int
+internal_function
+__gconv_close_transform (struct __gconv_step *steps, size_t nsteps)
+{
+  int result = __GCONV_OK;
+  size_t cnt;
+
+  /* Acquire the lock.  */
+  __libc_lock_lock (__gconv_lock);
+
+#ifndef STATIC_GCONV
+  cnt = nsteps;
+  while (cnt-- > 0)
+    __gconv_release_step (&steps[cnt]);
+#endif
+
+  /* If we use the cache we free a bit more since we don't keep any
+     transformation records around, they are cheap enough to
+     recreate.  */
+  __gconv_release_cache (steps, nsteps);
+
+  /* Release the lock.  */
+  __libc_lock_unlock (__gconv_lock);
+
+  return result;
+}
+
+
+/* Free the modules mentioned.  */
+static void
+internal_function __libc_freeres_fn_section
+free_modules_db (struct gconv_module *node)
+{
+  if (node->left != NULL)
+    free_modules_db (node->left);
+  if (node->right != NULL)
+    free_modules_db (node->right);
+  do
+    {
+      struct gconv_module *act = node;
+      node = node->same;
+      if (act->module_name[0] == '/')
+	free (act);
+    }
+  while (node != NULL);
+}
+
+
+/* Free all resources if necessary.  */
+libc_freeres_fn (free_mem)
+{
+  /* First free locale memory.  This needs to be done before freeing
+     derivations, as ctype cleanup functions dereference steps arrays which we
+     free below.  */
+  _nl_locale_subfreeres ();
+
+  /* finddomain.c has similar problem.  */
+  extern void _nl_finddomain_subfreeres (void) attribute_hidden;
+  _nl_finddomain_subfreeres ();
+
+  if (__gconv_alias_db != NULL)
+    __tdestroy (__gconv_alias_db, free);
+
+  if (__gconv_modules_db != NULL)
+    free_modules_db (__gconv_modules_db);
+
+  if (known_derivations != NULL)
+    __tdestroy (known_derivations, free_derivation);
+}
diff --git a/REORG.TODO/iconv/gconv_dl.c b/REORG.TODO/iconv/gconv_dl.c
new file mode 100644
index 0000000000..241836204d
--- /dev/null
+++ b/REORG.TODO/iconv/gconv_dl.c
@@ -0,0 +1,242 @@
+/* Handle loading/unloading of shared object for transformation.
+   Copyright (C) 1997-2017 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+   Contributed by Ulrich Drepper <drepper@cygnus.com>, 1997.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 2.1 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
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with the GNU C Library; if not, see
+   <http://www.gnu.org/licenses/>.  */
+
+#include <assert.h>
+#include <dlfcn.h>
+#include <inttypes.h>
+#include <search.h>
+#include <stdlib.h>
+#include <string.h>
+#include <libc-lock.h>
+#include <sys/param.h>
+
+#include <gconv_int.h>
+#include <sysdep.h>
+
+
+#ifdef DEBUG
+/* For debugging purposes.  */
+static void print_all (void);
+#endif
+
+
+/* This is a tuning parameter.  If a transformation module is not used
+   anymore it gets not immediately unloaded.  Instead we wait a certain
+   number of load attempts for further modules.  If none of the
+   subsequent load attempts name the same object it finally gets unloaded.
+   Otherwise it is still available which hopefully is the frequent case.
+   The following number is the number of unloading attempts we wait
+   before unloading.  */
+#define TRIES_BEFORE_UNLOAD	2
+
+/* Array of loaded objects.  This is shared by all threads so we have
+   to use semaphores to access it.  */
+static void *loaded;
+
+/* Comparison function for searching `loaded_object' tree.  */
+static int
+known_compare (const void *p1, const void *p2)
+{
+  const struct __gconv_loaded_object *s1 =
+    (const struct __gconv_loaded_object *) p1;
+  const struct __gconv_loaded_object *s2 =
+    (const struct __gconv_loaded_object *) p2;
+
+  return strcmp (s1->name, s2->name);
+}
+
+/* Open the gconv database if necessary.  A non-negative return value
+   means success.  */
+struct __gconv_loaded_object *
+internal_function
+__gconv_find_shlib (const char *name)
+{
+  struct __gconv_loaded_object *found;
+  void *keyp;
+
+  /* Search the tree of shared objects previously requested.  Data in
+     the tree are `loaded_object' structures, whose first member is a
+     `const char *', the lookup key.  The search returns a pointer to
+     the tree node structure; the first member of the is a pointer to
+     our structure (i.e. what will be a `loaded_object'); since the
+     first member of that is the lookup key string, &FCT_NAME is close
+     enough to a pointer to our structure to use as a lookup key that
+     will be passed to `known_compare' (above).  */
+
+  keyp = __tfind (&name, &loaded, known_compare);
+  if (keyp == NULL)
+    {
+      /* This name was not known before.  */
+      size_t namelen = strlen (name) + 1;
+
+      found = malloc (sizeof (struct __gconv_loaded_object) + namelen);
+      if (found != NULL)
+	{
+	  /* Point the tree node at this new structure.  */
+	  found->name = (char *) memcpy (found + 1, name, namelen);
+	  found->counter = -TRIES_BEFORE_UNLOAD - 1;
+	  found->handle = NULL;
+
+	  if (__builtin_expect (__tsearch (found, &loaded, known_compare)
+				== NULL, 0))
+	    {
+	      /* Something went wrong while inserting the entry.  */
+	      free (found);
+	      found = NULL;
+	    }
+	}
+    }
+  else
+    found = *(struct __gconv_loaded_object **) keyp;
+
+  /* Try to load the shared object if the usage count is 0.  This
+     implies that if the shared object is not loadable, the handle is
+     NULL and the usage count > 0.  */
+  if (found != NULL)
+    {
+      if (found->counter < -TRIES_BEFORE_UNLOAD)
+	{
+	  assert (found->handle == NULL);
+	  found->handle = __libc_dlopen (found->name);
+	  if (found->handle != NULL)
+	    {
+	      found->fct = __libc_dlsym (found->handle, "gconv");
+	      if (found->fct == NULL)
+		{
+		  /* Argh, no conversion function.  There is something
+                     wrong here.  */
+		  __gconv_release_shlib (found);
+		  found = NULL;
+		}
+	      else
+		{
+		  found->init_fct = __libc_dlsym (found->handle, "gconv_init");
+		  found->end_fct = __libc_dlsym (found->handle, "gconv_end");
+
+#ifdef PTR_MANGLE
+		  PTR_MANGLE (found->fct);
+		  if (found->init_fct != NULL)
+		    PTR_MANGLE (found->init_fct);
+		  if (found->end_fct !=  NULL)
+		    PTR_MANGLE (found->end_fct);
+#endif
+
+		  /* We have succeeded in loading the shared object.  */
+		  found->counter = 1;
+		}
+	    }
+	  else
+	    /* Error while loading the shared object.  */
+	    found = NULL;
+	}
+      else if (found->handle != NULL)
+	found->counter = MAX (found->counter + 1, 1);
+    }
+
+  return found;
+}
+
+
+/* This is very ugly but the tsearch functions provide no way to pass
+   information to the walker function.  So we use a global variable.
+   It is MT safe since we use a lock.  */
+static struct __gconv_loaded_object *release_handle;
+
+static void
+do_release_shlib (void *nodep, VISIT value, int level)
+{
+  struct __gconv_loaded_object *obj = *(struct __gconv_loaded_object **) nodep;
+
+  if (value != preorder && value != leaf)
+    return;
+
+  if (obj == release_handle)
+    {
+      /* This is the object we want to unload.  Now decrement the
+	 reference counter.  */
+      assert (obj->counter > 0);
+      --obj->counter;
+    }
+  else if (obj->counter <= 0 && obj->counter >= -TRIES_BEFORE_UNLOAD
+	   && --obj->counter < -TRIES_BEFORE_UNLOAD && obj->handle != NULL)
+    {
+      /* Unload the shared object.  */
+      __libc_dlclose (obj->handle);
+      obj->handle = NULL;
+    }
+}
+
+
+/* Notify system that a shared object is not longer needed.  */
+void
+internal_function
+__gconv_release_shlib (struct __gconv_loaded_object *handle)
+{
+  /* Urgh, this is ugly but we have no other possibility.  */
+  release_handle = handle;
+
+  /* Process all entries.  Please note that we also visit entries
+     with release counts <= 0.  This way we can finally unload them
+     if necessary.  */
+  __twalk (loaded, (__action_fn_t) do_release_shlib);
+}
+
+
+/* We run this if we debug the memory allocation.  */
+static void __libc_freeres_fn_section
+do_release_all (void *nodep)
+{
+  struct __gconv_loaded_object *obj = (struct __gconv_loaded_object *) nodep;
+
+  /* Unload the shared object.  */
+  if (obj->handle != NULL)
+    __libc_dlclose (obj->handle);
+
+  free (obj);
+}
+
+libc_freeres_fn (free_mem)
+{
+  __tdestroy (loaded, do_release_all);
+  loaded = NULL;
+}
+
+
+#ifdef DEBUG
+
+#include <stdio.h>
+
+static void
+do_print (const void *nodep, VISIT value, int level)
+{
+  struct __gconv_loaded_object *obj = *(struct __gconv_loaded_object **) nodep;
+
+  printf ("%10s: \"%s\", %d\n",
+	  value == leaf ? "leaf" :
+	  value == preorder ? "preorder" :
+	  value == postorder ? "postorder" : "endorder",
+	  obj->name, obj->counter);
+}
+
+static void __attribute__ ((used))
+print_all (void)
+{
+  __twalk (loaded, do_print);
+}
+#endif
diff --git a/REORG.TODO/iconv/gconv_int.h b/REORG.TODO/iconv/gconv_int.h
new file mode 100644
index 0000000000..85a67ad31b
--- /dev/null
+++ b/REORG.TODO/iconv/gconv_int.h
@@ -0,0 +1,287 @@
+/* Copyright (C) 1997-2017 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+   Contributed by Ulrich Drepper <drepper@cygnus.com>, 1997.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 2.1 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
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with the GNU C Library; if not, see
+   <http://www.gnu.org/licenses/>.  */
+
+#ifndef _GCONV_INT_H
+#define _GCONV_INT_H	1
+
+#include "gconv.h"
+#include <stdlib.h>		/* For alloca used in macro below.  */
+#include <ctype.h>		/* For __toupper_l used in macro below.  */
+#include <string.h>		/* For strlen et al used in macro below.  */
+#include <libc-lock.h>
+
+__BEGIN_DECLS
+
+
+/* Type to represent search path.  */
+struct path_elem
+{
+  const char *name;
+  size_t len;
+};
+
+/* Variable with search path for `gconv' implementation.  */
+extern struct path_elem *__gconv_path_elem attribute_hidden;
+/* Maximum length of a single path element.  */
+extern size_t __gconv_max_path_elem_len attribute_hidden;
+
+
+/* Structure for alias definition.  Simply two strings.  */
+struct gconv_alias
+{
+  char *fromname;
+  char *toname;
+};
+
+
+/* How many character should be converted in one call?  */
+#define GCONV_NCHAR_GOAL	8160
+
+
+/* Structure describing one loaded shared object.  This normally are
+   objects to perform conversation but as a special case the db shared
+   object is also handled.  */
+struct __gconv_loaded_object
+{
+  /* Name of the object.  It must be the first structure element.  */
+  const char *name;
+
+  /* Reference counter for the db functionality.  If no conversion is
+     needed we unload the db library.  */
+  int counter;
+
+  /* The handle for the shared object.  */
+  void *handle;
+
+  /* Pointer to the functions the module defines.  */
+  __gconv_fct fct;
+  __gconv_init_fct init_fct;
+  __gconv_end_fct end_fct;
+};
+
+
+/* Description for an available conversion module.  */
+struct gconv_module
+{
+  const char *from_string;
+  const char *to_string;
+
+  int cost_hi;
+  int cost_lo;
+
+  const char *module_name;
+
+  struct gconv_module *left;	/* Prefix smaller.  */
+  struct gconv_module *same;	/* List of entries with identical prefix.  */
+  struct gconv_module *right;	/* Prefix larger.  */
+};
+
+
+/* Flags for `gconv_open'.  */
+enum
+{
+  GCONV_AVOID_NOCONV = 1 << 0
+};
+
+/* When GCONV_AVOID_NOCONV is set and no conversion is needed,
+   __GCONV_NULCONV should be returned.  */
+enum
+{
+  __GCONV_NULCONV = -1
+};
+
+/* Global variables.  */
+
+/* Database of alias names.  */
+extern void *__gconv_alias_db attribute_hidden;
+
+/* Array with available modules.  */
+extern size_t __gconv_nmodules;
+extern struct gconv_module *__gconv_modules_db attribute_hidden;
+
+/* Value of the GCONV_PATH environment variable.  */
+extern const char *__gconv_path_envvar attribute_hidden;
+
+/* Lock for the conversion database content.  */
+__libc_lock_define (extern, __gconv_lock attribute_hidden)
+
+
+/* The gconv functions expects the name to be in upper case and complete,
+   including the trailing slashes if necessary.  */
+#define norm_add_slashes(str,suffix) \
+  ({									      \
+    const char *cp = (str);						      \
+    char *result;							      \
+    char *tmp;								      \
+    size_t cnt = 0;							      \
+    const size_t suffix_len = strlen (suffix);				      \
+									      \
+    while (*cp != '\0')							      \
+      if (*cp++ == '/')							      \
+	++cnt;								      \
+									      \
+    tmp = result = __alloca (cp - (str) + 3 + suffix_len);		      \
+    cp = (str);								      \
+    while (*cp != '\0')							      \
+      *tmp++ = __toupper_l (*cp++, _nl_C_locobj_ptr);			      \
+    if (cnt < 2)							      \
+      {									      \
+	*tmp++ = '/';							      \
+	if (cnt < 1)							      \
+	  {								      \
+	    *tmp++ = '/';						      \
+	    if (suffix_len != 0)					      \
+	      tmp = __mempcpy (tmp, suffix, suffix_len);		      \
+	  }								      \
+      }									      \
+    *tmp = '\0';							      \
+    result;								      \
+  })
+
+
+/* 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)
+     internal_function;
+
+/* Free resources associated with transformation descriptor CD.  */
+extern int __gconv_close (__gconv_t cd)
+     internal_function;
+
+/* Transform at most *INBYTESLEFT bytes from buffer starting at *INBUF
+   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,
+		    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)
+     internal_function;
+
+/* Search for transformation in cache data.  */
+extern int __gconv_lookup_cache (const char *toset, const char *fromset,
+				 struct __gconv_step **handle, size_t *nsteps,
+				 int flags)
+     internal_function;
+
+/* Compare the two name for whether they are after alias expansion the
+   same.  This function uses the cache and fails if none is
+   loaded.  */
+extern int __gconv_compare_alias_cache (const char *name1, const char *name2,
+					int *result) internal_function;
+
+/* Free data associated with a step's structure.  */
+extern void __gconv_release_step (struct __gconv_step *step)
+     internal_function;
+
+/* Read all the configuration data and cache it.  */
+extern void __gconv_read_conf (void) attribute_hidden;
+
+/* Try to read module cache file.  */
+extern int __gconv_load_cache (void) internal_function;
+
+/* Retrieve pointer to internal cache.  */
+extern void *__gconv_get_cache (void);
+
+/* Retrieve pointer to internal module database.  */
+extern struct gconv_module *__gconv_get_modules_db (void);
+
+/* Retrieve pointer to internal alias database.  */
+extern void *__gconv_get_alias_db (void);
+
+/* Determine the directories we are looking in.  */
+extern void __gconv_get_path (void) internal_function;
+
+/* Comparison function to search alias.  */
+extern int __gconv_alias_compare (const void *p1, const void *p2)
+     attribute_hidden;
+
+/* 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)
+     internal_function;
+
+/* Free all resources allocated for the transformation record when
+   using the cache.  */
+extern void __gconv_release_cache (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)
+     internal_function;
+
+/* Release shared object.  If no further reference is available unload
+   the object.  */
+extern void __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)
+     internal_function;
+
+libc_hidden_proto (__gconv_transliterate)
+
+/* If NAME is an codeset alias expand it.  */
+extern int __gconv_compare_alias (const char *name1, const char *name2)
+     internal_function;
+
+
+/* Builtin transformations.  */
+#ifdef _LIBC
+# define __BUILTIN_TRANSFORM(Name) \
+  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_TRANSFORM (__gconv_transform_ascii_internal);
+__BUILTIN_TRANSFORM (__gconv_transform_internal_ascii);
+__BUILTIN_TRANSFORM (__gconv_transform_utf8_internal);
+__BUILTIN_TRANSFORM (__gconv_transform_internal_utf8);
+__BUILTIN_TRANSFORM (__gconv_transform_ucs2_internal);
+__BUILTIN_TRANSFORM (__gconv_transform_internal_ucs2);
+__BUILTIN_TRANSFORM (__gconv_transform_ucs2reverse_internal);
+__BUILTIN_TRANSFORM (__gconv_transform_internal_ucs2reverse);
+__BUILTIN_TRANSFORM (__gconv_transform_internal_ucs4);
+__BUILTIN_TRANSFORM (__gconv_transform_ucs4_internal);
+__BUILTIN_TRANSFORM (__gconv_transform_internal_ucs4le);
+__BUILTIN_TRANSFORM (__gconv_transform_ucs4le_internal);
+__BUILTIN_TRANSFORM (__gconv_transform_internal_utf16);
+__BUILTIN_TRANSFORM (__gconv_transform_utf16_internal);
+# undef __BUITLIN_TRANSFORM
+
+/* Specialized conversion function for a single byte to INTERNAL, recognizing
+   only ASCII characters.  */
+extern wint_t __gconv_btwoc_ascii (struct __gconv_step *step, unsigned char c);
+
+#endif
+
+__END_DECLS
+
+#endif /* gconv_int.h */
diff --git a/REORG.TODO/iconv/gconv_open.c b/REORG.TODO/iconv/gconv_open.c
new file mode 100644
index 0000000000..ff4fd121eb
--- /dev/null
+++ b/REORG.TODO/iconv/gconv_open.c
@@ -0,0 +1,208 @@
+/* Find matching transformation algorithms and initialize steps.
+   Copyright (C) 1997-2017 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+   Contributed by Ulrich Drepper <drepper@cygnus.com>, 1997.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 2.1 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
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with the GNU C Library; if not, see
+   <http://www.gnu.org/licenses/>.  */
+
+#include <errno.h>
+#include <locale.h>
+#include "../locale/localeinfo.h"
+#include <stdlib.h>
+#include <string.h>
+
+#include <gconv_int.h>
+
+
+int
+internal_function
+__gconv_open (const char *toset, const char *fromset, __gconv_t *handle,
+	      int flags)
+{
+  struct __gconv_step *steps;
+  size_t nsteps;
+  __gconv_t result = NULL;
+  size_t cnt = 0;
+  int res;
+  int conv_flags = 0;
+  const char *errhand;
+  const char *ignore;
+  bool translit = false;
+
+  /* Find out whether any error handling method is specified.  */
+  errhand = strchr (toset, '/');
+  if (errhand != NULL)
+    errhand = strchr (errhand + 1, '/');
+  if (__glibc_likely (errhand != NULL))
+    {
+      if (*++errhand == '\0')
+	errhand = NULL;
+      else
+	{
+	  /* Make copy without the error handling description.  */
+	  char *newtoset = (char *) alloca (errhand - toset + 1);
+	  char *tok;
+	  char *ptr = NULL /* Work around a bogus warning */;
+
+	  newtoset[errhand - toset] = '\0';
+	  toset = memcpy (newtoset, toset, errhand - toset);
+
+	  /* Find the appropriate transliteration handlers.  */
+	  tok = strdupa (errhand);
+
+	  tok = __strtok_r (tok, ",", &ptr);
+	  while (tok != NULL)
+	    {
+	      if (__strcasecmp_l (tok, "TRANSLIT", _nl_C_locobj_ptr) == 0)
+		translit = true;
+	      else if (__strcasecmp_l (tok, "IGNORE", _nl_C_locobj_ptr) == 0)
+		/* Set the flag to ignore all errors.  */
+		conv_flags |= __GCONV_IGNORE_ERRORS;
+
+	      tok = __strtok_r (NULL, ",", &ptr);
+	    }
+	}
+    }
+
+  /* For the source character set we ignore the error handler specification.
+     XXX Is this really always the best?  */
+  ignore = strchr (fromset, '/');
+  if (ignore != NULL && (ignore = strchr (ignore + 1, '/')) != NULL
+      && *++ignore != '\0')
+    {
+      char *newfromset = (char *) alloca (ignore - fromset + 1);
+
+      newfromset[ignore - fromset] = '\0';
+      fromset = memcpy (newfromset, fromset, ignore - fromset);
+    }
+
+  /* If the string is empty define this to mean the charset of the
+     currently selected locale.  */
+  if (strcmp (toset, "//") == 0)
+    {
+      const char *codeset = _NL_CURRENT (LC_CTYPE, CODESET);
+      size_t len = strlen (codeset);
+      char *dest;
+      toset = dest = (char *) alloca (len + 3);
+      memcpy (__mempcpy (dest, codeset, len), "//", 3);
+    }
+  if (strcmp (fromset, "//") == 0)
+    {
+      const char *codeset = _NL_CURRENT (LC_CTYPE, CODESET);
+      size_t len = strlen (codeset);
+      char *dest;
+      fromset = dest = (char *) alloca (len + 3);
+      memcpy (__mempcpy (dest, codeset, len), "//", 3);
+    }
+
+  res = __gconv_find_transform (toset, fromset, &steps, &nsteps, flags);
+  if (res == __GCONV_OK)
+    {
+      /* Allocate room for handle.  */
+      result = (__gconv_t) malloc (sizeof (struct __gconv_info)
+				   + (nsteps
+				      * sizeof (struct __gconv_step_data)));
+      if (result == NULL)
+	res = __GCONV_NOMEM;
+      else
+	{
+	  /* Remember the list of steps.  */
+	  result->__steps = steps;
+	  result->__nsteps = nsteps;
+
+	  /* Clear the array for the step data.  */
+	  memset (result->__data, '\0',
+		  nsteps * sizeof (struct __gconv_step_data));
+
+	  /* Call all initialization functions for the transformation
+	     step implementations.  */
+	  for (cnt = 0; cnt < nsteps; ++cnt)
+	    {
+	      size_t size;
+
+	      /* Would have to be done if we would not clear the whole
+                 array above.  */
+#if 0
+	      /* Reset the counter.  */
+	      result->__data[cnt].__invocation_counter = 0;
+
+	      /* It's a regular use.  */
+	      result->__data[cnt].__internal_use = 0;
+#endif
+
+	      /* We use the `mbstate_t' member in DATA.  */
+	      result->__data[cnt].__statep = &result->__data[cnt].__state;
+
+	      /* The builtin transliteration handling only
+		 supports the internal encoding.  */
+	      if (translit
+		  && __strcasecmp_l (steps[cnt].__from_name,
+				     "INTERNAL", _nl_C_locobj_ptr) == 0)
+		conv_flags |= __GCONV_TRANSLIT;
+
+	      /* If this is the last step we must not allocate an
+		 output buffer.  */
+	      if (cnt < nsteps - 1)
+		{
+		  result->__data[cnt].__flags = conv_flags;
+
+		  /* Allocate the buffer.  */
+		  size = (GCONV_NCHAR_GOAL * steps[cnt].__max_needed_to);
+
+		  result->__data[cnt].__outbuf = malloc (size);
+		  if (result->__data[cnt].__outbuf == NULL)
+		    {
+		      res = __GCONV_NOMEM;
+		      goto bail;
+		    }
+
+		  result->__data[cnt].__outbufend =
+		    result->__data[cnt].__outbuf + size;
+		}
+	      else
+		{
+		  /* Handle the last entry.  */
+		  result->__data[cnt].__flags = conv_flags | __GCONV_IS_LAST;
+
+		  break;
+		}
+	    }
+	}
+
+      if (res != __GCONV_OK)
+	{
+	  /* Something went wrong.  Free all the resources.  */
+	  int serrno;
+	bail:
+	  serrno = errno;
+
+	  if (result != NULL)
+	    {
+	      while (cnt-- > 0)
+		free (result->__data[cnt].__outbuf);
+
+	      free (result);
+	      result = NULL;
+	    }
+
+	  __gconv_close_transform (steps, nsteps);
+
+	  __set_errno (serrno);
+	}
+    }
+
+  *handle = result;
+  return res;
+}
diff --git a/REORG.TODO/iconv/gconv_simple.c b/REORG.TODO/iconv/gconv_simple.c
new file mode 100644
index 0000000000..863d3dcc3f
--- /dev/null
+++ b/REORG.TODO/iconv/gconv_simple.c
@@ -0,0 +1,1329 @@
+/* Simple transformations functions.
+   Copyright (C) 1997-2017 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+   Contributed by Ulrich Drepper <drepper@cygnus.com>, 1997.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 2.1 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
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with the GNU C Library; if not, see
+   <http://www.gnu.org/licenses/>.  */
+
+#include <byteswap.h>
+#include <dlfcn.h>
+#include <endian.h>
+#include <errno.h>
+#include <gconv.h>
+#include <stdint.h>
+#include <stdlib.h>
+#include <string.h>
+#include <wchar.h>
+#include <sys/param.h>
+#include <gconv_int.h>
+
+#define BUILTIN_ALIAS(s1, s2) /* nothing */
+#define BUILTIN_TRANSFORMATION(From, To, Cost, Name, Fct, BtowcFct, \
+			       MinF, MaxF, MinT, MaxT) \
+  extern int Fct (struct __gconv_step *, struct __gconv_step_data *,	      \
+		  const unsigned char **, const unsigned char *,	      \
+		  unsigned char **, size_t *, int, int);
+#include "gconv_builtin.h"
+
+
+#ifndef EILSEQ
+# define EILSEQ EINVAL
+#endif
+
+
+/* Specialized conversion function for a single byte to INTERNAL, recognizing
+   only ASCII characters.  */
+wint_t
+__gconv_btwoc_ascii (struct __gconv_step *step, unsigned char c)
+{
+  if (c < 0x80)
+    return c;
+  else
+    return WEOF;
+}
+
+
+/* Transform from the internal, UCS4-like format, to UCS4.  The
+   difference between the internal ucs4 format and the real UCS4
+   format is, if any, the endianess.  The Unicode/ISO 10646 says that
+   unless some higher protocol specifies it differently, the byte
+   order is big endian.*/
+#define DEFINE_INIT		0
+#define DEFINE_FINI		0
+#define MIN_NEEDED_FROM		4
+#define MIN_NEEDED_TO		4
+#define FROM_DIRECTION		1
+#define FROM_LOOP		internal_ucs4_loop
+#define TO_LOOP			internal_ucs4_loop /* This is not used.  */
+#define FUNCTION_NAME		__gconv_transform_internal_ucs4
+#define ONE_DIRECTION		0
+
+
+static inline int
+__attribute ((always_inline))
+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,
+		    size_t *irreversible)
+{
+  const unsigned char *inptr = *inptrp;
+  unsigned char *outptr = *outptrp;
+  size_t n_convert = MIN (inend - inptr, outend - outptr) / 4;
+  int result;
+
+#if __BYTE_ORDER == __LITTLE_ENDIAN
+  /* Sigh, we have to do some real work.  */
+  size_t cnt;
+  uint32_t *outptr32 = (uint32_t *) outptr;
+
+  for (cnt = 0; cnt < n_convert; ++cnt, inptr += 4)
+    *outptr32++ = bswap_32 (*(const uint32_t *) inptr);
+
+  *inptrp = inptr;
+  *outptrp = (unsigned char *) outptr32;
+#elif __BYTE_ORDER == __BIG_ENDIAN
+  /* Simply copy the data.  */
+  *inptrp = inptr + n_convert * 4;
+  *outptrp = __mempcpy (outptr, inptr, n_convert * 4);
+#else
+# error "This endianess is not supported."
+#endif
+
+  /* Determine the status.  */
+  if (*inptrp == inend)
+    result = __GCONV_EMPTY_INPUT;
+  else if (*outptrp + 4 > outend)
+    result = __GCONV_FULL_OUTPUT;
+  else
+    result = __GCONV_INCOMPLETE_INPUT;
+
+  return result;
+}
+
+#if !_STRING_ARCH_unaligned
+static inline int
+__attribute ((always_inline))
+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,
+			      size_t *irreversible)
+{
+  const unsigned char *inptr = *inptrp;
+  unsigned char *outptr = *outptrp;
+  size_t n_convert = MIN (inend - inptr, outend - outptr) / 4;
+  int result;
+
+# if __BYTE_ORDER == __LITTLE_ENDIAN
+  /* Sigh, we have to do some real work.  */
+  size_t cnt;
+
+  for (cnt = 0; cnt < n_convert; ++cnt, inptr += 4, outptr += 4)
+    {
+      outptr[0] = inptr[3];
+      outptr[1] = inptr[2];
+      outptr[2] = inptr[1];
+      outptr[3] = inptr[0];
+    }
+
+  *inptrp = inptr;
+  *outptrp = outptr;
+# elif __BYTE_ORDER == __BIG_ENDIAN
+  /* Simply copy the data.  */
+  *inptrp = inptr + n_convert * 4;
+  *outptrp = __mempcpy (outptr, inptr, n_convert * 4);
+# else
+#  error "This endianess is not supported."
+# endif
+
+  /* Determine the status.  */
+  if (*inptrp == inend)
+    result = __GCONV_EMPTY_INPUT;
+  else if (*outptrp + 4 > outend)
+    result = __GCONV_FULL_OUTPUT;
+  else
+    result = __GCONV_INCOMPLETE_INPUT;
+
+  return result;
+}
+#endif
+
+
+static inline int
+__attribute ((always_inline))
+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,
+			   size_t *irreversible)
+{
+  mbstate_t *state = step_data->__statep;
+  size_t cnt = state->__count & 7;
+
+  while (*inptrp < inend && cnt < 4)
+    state->__value.__wchb[cnt++] = *(*inptrp)++;
+
+  if (__glibc_unlikely (cnt < 4))
+    {
+      /* Still not enough bytes.  Store the ones in the input buffer.  */
+      state->__count &= ~7;
+      state->__count |= cnt;
+
+      return __GCONV_INCOMPLETE_INPUT;
+    }
+
+#if __BYTE_ORDER == __LITTLE_ENDIAN
+  (*outptrp)[0] = state->__value.__wchb[3];
+  (*outptrp)[1] = state->__value.__wchb[2];
+  (*outptrp)[2] = state->__value.__wchb[1];
+  (*outptrp)[3] = state->__value.__wchb[0];
+
+#elif __BYTE_ORDER == __BIG_ENDIAN
+  /* XXX unaligned */
+  (*outptrp)[0] = state->__value.__wchb[0];
+  (*outptrp)[1] = state->__value.__wchb[1];
+  (*outptrp)[2] = state->__value.__wchb[2];
+  (*outptrp)[3] = state->__value.__wchb[3];
+#else
+# error "This endianess is not supported."
+#endif
+  *outptrp += 4;
+
+  /* Clear the state buffer.  */
+  state->__count &= ~7;
+
+  return __GCONV_OK;
+}
+
+#include <iconv/skeleton.c>
+
+
+/* Transform from UCS4 to the internal, UCS4-like format.  Unlike
+   for the other direction we have to check for correct values here.  */
+#define DEFINE_INIT		0
+#define DEFINE_FINI		0
+#define MIN_NEEDED_FROM		4
+#define MIN_NEEDED_TO		4
+#define FROM_DIRECTION		1
+#define FROM_LOOP		ucs4_internal_loop
+#define TO_LOOP			ucs4_internal_loop /* This is not used.  */
+#define FUNCTION_NAME		__gconv_transform_ucs4_internal
+#define ONE_DIRECTION		0
+
+
+static inline int
+__attribute ((always_inline))
+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,
+		    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)
+    {
+      uint32_t inval;
+
+#if __BYTE_ORDER == __LITTLE_ENDIAN
+      inval = bswap_32 (*(const uint32_t *) inptr);
+#else
+      inval = *(const uint32_t *) inptr;
+#endif
+
+      if (__glibc_unlikely (inval > 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 (irreversible == NULL)
+	    /* We are transliterating, don't try to correct anything.  */
+	    return __GCONV_ILLEGAL_INPUT;
+
+	  if (flags & __GCONV_IGNORE_ERRORS)
+	    {
+	      /* Just ignore this character.  */
+	      ++*irreversible;
+	      continue;
+	    }
+
+	  *inptrp = inptr;
+	  *outptrp = outptr;
+	  return __GCONV_ILLEGAL_INPUT;
+	}
+
+      *((uint32_t *) outptr) = inval;
+      outptr += sizeof (uint32_t);
+    }
+
+  *inptrp = inptr;
+  *outptrp = outptr;
+
+  /* Determine the status.  */
+  if (*inptrp == inend)
+    result = __GCONV_EMPTY_INPUT;
+  else if (*outptrp + 4 > outend)
+    result = __GCONV_FULL_OUTPUT;
+  else
+    result = __GCONV_INCOMPLETE_INPUT;
+
+  return result;
+}
+
+#if !_STRING_ARCH_unaligned
+static inline int
+__attribute ((always_inline))
+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,
+			      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)
+    {
+      if (__glibc_unlikely (inptr[0] > 0x80))
+	{
+	  /* 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 (irreversible == NULL)
+	    /* We are transliterating, don't try to correct anything.  */
+	    return __GCONV_ILLEGAL_INPUT;
+
+	  if (flags & __GCONV_IGNORE_ERRORS)
+	    {
+	      /* Just ignore this character.  */
+	      ++*irreversible;
+	      continue;
+	    }
+
+	  *inptrp = inptr;
+	  *outptrp = outptr;
+	  return __GCONV_ILLEGAL_INPUT;
+	}
+
+# if __BYTE_ORDER == __LITTLE_ENDIAN
+      outptr[3] = inptr[0];
+      outptr[2] = inptr[1];
+      outptr[1] = inptr[2];
+      outptr[0] = inptr[3];
+# else
+      outptr[0] = inptr[0];
+      outptr[1] = inptr[1];
+      outptr[2] = inptr[2];
+      outptr[3] = inptr[3];
+# endif
+      outptr += 4;
+    }
+
+  *inptrp = inptr;
+  *outptrp = outptr;
+
+  /* Determine the status.  */
+  if (*inptrp == inend)
+    result = __GCONV_EMPTY_INPUT;
+  else if (*outptrp + 4 > outend)
+    result = __GCONV_FULL_OUTPUT;
+  else
+    result = __GCONV_INCOMPLETE_INPUT;
+
+  return result;
+}
+#endif
+
+
+static inline int
+__attribute ((always_inline))
+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,
+			   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)
+    state->__value.__wchb[cnt++] = *(*inptrp)++;
+
+  if (__glibc_unlikely (cnt < 4))
+    {
+      /* Still not enough bytes.  Store the ones in the input buffer.  */
+      state->__count &= ~7;
+      state->__count |= cnt;
+
+      return __GCONV_INCOMPLETE_INPUT;
+    }
+
+  if (__builtin_expect (((unsigned char *) state->__value.__wchb)[0] > 0x80,
+			0))
+    {
+      /* 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);
+	  return __GCONV_ILLEGAL_INPUT;
+	}
+    }
+  else
+    {
+#if __BYTE_ORDER == __LITTLE_ENDIAN
+      (*outptrp)[0] = state->__value.__wchb[3];
+      (*outptrp)[1] = state->__value.__wchb[2];
+      (*outptrp)[2] = state->__value.__wchb[1];
+      (*outptrp)[3] = state->__value.__wchb[0];
+#elif __BYTE_ORDER == __BIG_ENDIAN
+      (*outptrp)[0] = state->__value.__wchb[0];
+      (*outptrp)[1] = state->__value.__wchb[1];
+      (*outptrp)[2] = state->__value.__wchb[2];
+      (*outptrp)[3] = state->__value.__wchb[3];
+#endif
+
+      *outptrp += 4;
+    }
+
+  /* Clear the state buffer.  */
+  state->__count &= ~7;
+
+  return __GCONV_OK;
+}
+
+#include <iconv/skeleton.c>
+
+
+/* Similarly for the little endian form.  */
+#define DEFINE_INIT		0
+#define DEFINE_FINI		0
+#define MIN_NEEDED_FROM		4
+#define MIN_NEEDED_TO		4
+#define FROM_DIRECTION		1
+#define FROM_LOOP		internal_ucs4le_loop
+#define TO_LOOP			internal_ucs4le_loop /* This is not used.  */
+#define FUNCTION_NAME		__gconv_transform_internal_ucs4le
+#define ONE_DIRECTION		0
+
+
+static inline int
+__attribute ((always_inline))
+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,
+		      size_t *irreversible)
+{
+  const unsigned char *inptr = *inptrp;
+  unsigned char *outptr = *outptrp;
+  size_t n_convert = MIN (inend - inptr, outend - outptr) / 4;
+  int result;
+
+#if __BYTE_ORDER == __BIG_ENDIAN
+  /* Sigh, we have to do some real work.  */
+  size_t cnt;
+  uint32_t *outptr32 = (uint32_t *) outptr;
+
+  for (cnt = 0; cnt < n_convert; ++cnt, inptr += 4)
+    *outptr32++ = bswap_32 (*(const uint32_t *) inptr);
+  outptr = (unsigned char *) outptr32;
+
+  *inptrp = inptr;
+  *outptrp = outptr;
+#elif __BYTE_ORDER == __LITTLE_ENDIAN
+  /* Simply copy the data.  */
+  *inptrp = inptr + n_convert * 4;
+  *outptrp = __mempcpy (outptr, inptr, n_convert * 4);
+#else
+# error "This endianess is not supported."
+#endif
+
+  /* Determine the status.  */
+  if (*inptrp == inend)
+    result = __GCONV_EMPTY_INPUT;
+  else if (*outptrp + 4 > outend)
+    result = __GCONV_FULL_OUTPUT;
+  else
+    result = __GCONV_INCOMPLETE_INPUT;
+
+  return result;
+}
+
+#if !_STRING_ARCH_unaligned
+static inline int
+__attribute ((always_inline))
+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,
+				size_t *irreversible)
+{
+  const unsigned char *inptr = *inptrp;
+  unsigned char *outptr = *outptrp;
+  size_t n_convert = MIN (inend - inptr, outend - outptr) / 4;
+  int result;
+
+# if __BYTE_ORDER == __BIG_ENDIAN
+  /* Sigh, we have to do some real work.  */
+  size_t cnt;
+
+  for (cnt = 0; cnt < n_convert; ++cnt, inptr += 4, outptr += 4)
+    {
+      outptr[0] = inptr[3];
+      outptr[1] = inptr[2];
+      outptr[2] = inptr[1];
+      outptr[3] = inptr[0];
+    }
+
+  *inptrp = inptr;
+  *outptrp = outptr;
+# elif __BYTE_ORDER == __LITTLE_ENDIAN
+  /* Simply copy the data.  */
+  *inptrp = inptr + n_convert * 4;
+  *outptrp = __mempcpy (outptr, inptr, n_convert * 4);
+# else
+#  error "This endianess is not supported."
+# endif
+
+  /* Determine the status.  */
+  if (*inptrp == inend)
+    result = __GCONV_EMPTY_INPUT;
+  else if (*inptrp + 4 > inend)
+    result = __GCONV_INCOMPLETE_INPUT;
+  else
+    {
+      assert (*outptrp + 4 > outend);
+      result = __GCONV_FULL_OUTPUT;
+    }
+
+  return result;
+}
+#endif
+
+
+static inline int
+__attribute ((always_inline))
+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,
+			     size_t *irreversible)
+{
+  mbstate_t *state = step_data->__statep;
+  size_t cnt = state->__count & 7;
+
+  while (*inptrp < inend && cnt < 4)
+    state->__value.__wchb[cnt++] = *(*inptrp)++;
+
+  if (__glibc_unlikely (cnt < 4))
+    {
+      /* Still not enough bytes.  Store the ones in the input buffer.  */
+      state->__count &= ~7;
+      state->__count |= cnt;
+
+      return __GCONV_INCOMPLETE_INPUT;
+    }
+
+#if __BYTE_ORDER == __BIG_ENDIAN
+  (*outptrp)[0] = state->__value.__wchb[3];
+  (*outptrp)[1] = state->__value.__wchb[2];
+  (*outptrp)[2] = state->__value.__wchb[1];
+  (*outptrp)[3] = state->__value.__wchb[0];
+
+#else
+  /* XXX unaligned */
+  (*outptrp)[0] = state->__value.__wchb[0];
+  (*outptrp)[1] = state->__value.__wchb[1];
+  (*outptrp)[2] = state->__value.__wchb[2];
+  (*outptrp)[3] = state->__value.__wchb[3];
+
+#endif
+
+  *outptrp += 4;
+
+  /* Clear the state buffer.  */
+  state->__count &= ~7;
+
+  return __GCONV_OK;
+}
+
+#include <iconv/skeleton.c>
+
+
+/* And finally from UCS4-LE to the internal encoding.  */
+#define DEFINE_INIT		0
+#define DEFINE_FINI		0
+#define MIN_NEEDED_FROM		4
+#define MIN_NEEDED_TO		4
+#define FROM_DIRECTION		1
+#define FROM_LOOP		ucs4le_internal_loop
+#define TO_LOOP			ucs4le_internal_loop /* This is not used.  */
+#define FUNCTION_NAME		__gconv_transform_ucs4le_internal
+#define ONE_DIRECTION		0
+
+
+static inline int
+__attribute ((always_inline))
+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,
+		      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)
+    {
+      uint32_t inval;
+
+#if __BYTE_ORDER == __BIG_ENDIAN
+      inval = bswap_32 (*(const uint32_t *) inptr);
+#else
+      inval = *(const uint32_t *) inptr;
+#endif
+
+      if (__glibc_unlikely (inval > 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 (irreversible == NULL)
+	    /* We are transliterating, don't try to correct anything.  */
+	    return __GCONV_ILLEGAL_INPUT;
+
+	  if (flags & __GCONV_IGNORE_ERRORS)
+	    {
+	      /* Just ignore this character.  */
+	      ++*irreversible;
+	      continue;
+	    }
+
+	  *inptrp = inptr;
+	  *outptrp = outptr;
+	  return __GCONV_ILLEGAL_INPUT;
+	}
+
+      *((uint32_t *) outptr) = inval;
+      outptr += sizeof (uint32_t);
+    }
+
+  *inptrp = inptr;
+  *outptrp = outptr;
+
+  /* Determine the status.  */
+  if (*inptrp == inend)
+    result = __GCONV_EMPTY_INPUT;
+  else if (*inptrp + 4 > inend)
+    result = __GCONV_INCOMPLETE_INPUT;
+  else
+    {
+      assert (*outptrp + 4 > outend);
+      result = __GCONV_FULL_OUTPUT;
+    }
+
+  return result;
+}
+
+#if !_STRING_ARCH_unaligned
+static inline int
+__attribute ((always_inline))
+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,
+				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)
+    {
+      if (__glibc_unlikely (inptr[3] > 0x80))
+	{
+	  /* 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 (irreversible == NULL)
+	    /* We are transliterating, don't try to correct anything.  */
+	    return __GCONV_ILLEGAL_INPUT;
+
+	  if (flags & __GCONV_IGNORE_ERRORS)
+	    {
+	      /* Just ignore this character.  */
+	      ++*irreversible;
+	      continue;
+	    }
+
+	  *inptrp = inptr;
+	  *outptrp = outptr;
+	  return __GCONV_ILLEGAL_INPUT;
+	}
+
+# if __BYTE_ORDER == __BIG_ENDIAN
+      outptr[3] = inptr[0];
+      outptr[2] = inptr[1];
+      outptr[1] = inptr[2];
+      outptr[0] = inptr[3];
+# else
+      outptr[0] = inptr[0];
+      outptr[1] = inptr[1];
+      outptr[2] = inptr[2];
+      outptr[3] = inptr[3];
+# endif
+
+      outptr += 4;
+    }
+
+  *inptrp = inptr;
+  *outptrp = outptr;
+
+  /* Determine the status.  */
+  if (*inptrp == inend)
+    result = __GCONV_EMPTY_INPUT;
+  else if (*inptrp + 4 > inend)
+    result = __GCONV_INCOMPLETE_INPUT;
+  else
+    {
+      assert (*outptrp + 4 > outend);
+      result = __GCONV_FULL_OUTPUT;
+    }
+
+  return result;
+}
+#endif
+
+
+static inline int
+__attribute ((always_inline))
+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,
+			     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)
+    state->__value.__wchb[cnt++] = *(*inptrp)++;
+
+  if (__glibc_unlikely (cnt < 4))
+    {
+      /* Still not enough bytes.  Store the ones in the input buffer.  */
+      state->__count &= ~7;
+      state->__count |= cnt;
+
+      return __GCONV_INCOMPLETE_INPUT;
+    }
+
+  if (__builtin_expect (((unsigned char *) state->__value.__wchb)[3] > 0x80,
+			0))
+    {
+      /* 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;
+    }
+  else
+    {
+#if __BYTE_ORDER == __BIG_ENDIAN
+      (*outptrp)[0] = state->__value.__wchb[3];
+      (*outptrp)[1] = state->__value.__wchb[2];
+      (*outptrp)[2] = state->__value.__wchb[1];
+      (*outptrp)[3] = state->__value.__wchb[0];
+#else
+      (*outptrp)[0] = state->__value.__wchb[0];
+      (*outptrp)[1] = state->__value.__wchb[1];
+      (*outptrp)[2] = state->__value.__wchb[2];
+      (*outptrp)[3] = state->__value.__wchb[3];
+#endif
+
+      *outptrp += 4;
+    }
+
+  /* Clear the state buffer.  */
+  state->__count &= ~7;
+
+  return __GCONV_OK;
+}
+
+#include <iconv/skeleton.c>
+
+
+/* Convert from ISO 646-IRV to the internal (UCS4-like) format.  */
+#define DEFINE_INIT		0
+#define DEFINE_FINI		0
+#define MIN_NEEDED_FROM		1
+#define MIN_NEEDED_TO		4
+#define FROM_DIRECTION		1
+#define FROM_LOOP		ascii_internal_loop
+#define TO_LOOP			ascii_internal_loop /* This is not used.  */
+#define FUNCTION_NAME		__gconv_transform_ascii_internal
+#define ONE_DIRECTION		1
+
+#define MIN_NEEDED_INPUT	MIN_NEEDED_FROM
+#define MIN_NEEDED_OUTPUT	MIN_NEEDED_TO
+#define LOOPFCT			FROM_LOOP
+#define BODY \
+  {									      \
+    if (__glibc_unlikely (*inptr > '\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.  */			      \
+	STANDARD_FROM_LOOP_ERR_HANDLER (1);				      \
+      }									      \
+    else								      \
+      {									      \
+	/* It's an one byte sequence.  */				      \
+	*((uint32_t *) outptr) = *inptr++;				      \
+	outptr += sizeof (uint32_t);					      \
+      }									      \
+  }
+#define LOOP_NEED_FLAGS
+#include <iconv/loop.c>
+#include <iconv/skeleton.c>
+
+
+/* Convert from the internal (UCS4-like) format to ISO 646-IRV.  */
+#define DEFINE_INIT		0
+#define DEFINE_FINI		0
+#define MIN_NEEDED_FROM		4
+#define MIN_NEEDED_TO		1
+#define FROM_DIRECTION		1
+#define FROM_LOOP		internal_ascii_loop
+#define TO_LOOP			internal_ascii_loop /* This is not used.  */
+#define FUNCTION_NAME		__gconv_transform_internal_ascii
+#define ONE_DIRECTION		1
+
+#define MIN_NEEDED_INPUT	MIN_NEEDED_FROM
+#define MIN_NEEDED_OUTPUT	MIN_NEEDED_TO
+#define LOOPFCT			FROM_LOOP
+#define BODY \
+  {									      \
+    if (__glibc_unlikely (*((const uint32_t *) inptr) > 0x7f))		      \
+      {									      \
+	UNICODE_TAG_HANDLER (*((const uint32_t *) inptr), 4);		      \
+	STANDARD_TO_LOOP_ERR_HANDLER (4);				      \
+      }									      \
+    else								      \
+      {									      \
+	/* It's an one byte sequence.  */				      \
+	*outptr++ = *((const uint32_t *) inptr);			      \
+	inptr += sizeof (uint32_t);					      \
+      }									      \
+  }
+#define LOOP_NEED_FLAGS
+#include <iconv/loop.c>
+#include <iconv/skeleton.c>
+
+
+/* Convert from the internal (UCS4-like) format to UTF-8.  */
+#define DEFINE_INIT		0
+#define DEFINE_FINI		0
+#define MIN_NEEDED_FROM		4
+#define MIN_NEEDED_TO		1
+#define MAX_NEEDED_TO		6
+#define FROM_DIRECTION		1
+#define FROM_LOOP		internal_utf8_loop
+#define TO_LOOP			internal_utf8_loop /* This is not used.  */
+#define FUNCTION_NAME		__gconv_transform_internal_utf8
+#define ONE_DIRECTION		1
+
+#define MIN_NEEDED_INPUT	MIN_NEEDED_FROM
+#define MIN_NEEDED_OUTPUT	MIN_NEEDED_TO
+#define MAX_NEEDED_OUTPUT	MAX_NEEDED_TO
+#define LOOPFCT			FROM_LOOP
+#define BODY \
+  {									      \
+    uint32_t wc = *((const uint32_t *) inptr);				      \
+									      \
+    if (__glibc_likely (wc < 0x80))					      \
+      /* It's an one byte sequence.  */					      \
+      *outptr++ = (unsigned char) wc;					      \
+    else if (__glibc_likely (wc <= 0x7fffffff				      \
+			     && (wc < 0xd800 || wc > 0xdfff)))		      \
+      {									      \
+	size_t step;							      \
+	unsigned char *start;						      \
+									      \
+	for (step = 2; step < 6; ++step)				      \
+	  if ((wc & (~(uint32_t)0 << (5 * step + 1))) == 0)		      \
+	    break;							      \
+									      \
+	if (__glibc_unlikely (outptr + step > outend))			      \
+	  {								      \
+	    /* Too long.  */						      \
+	    result = __GCONV_FULL_OUTPUT;				      \
+	    break;							      \
+	  }								      \
+									      \
+	start = outptr;							      \
+	*outptr = (unsigned char) (~0xff >> step);			      \
+	outptr += step;							      \
+	do								      \
+	  {								      \
+	    start[--step] = 0x80 | (wc & 0x3f);				      \
+	    wc >>= 6;							      \
+	  }								      \
+	while (step > 1);						      \
+	start[0] |= wc;							      \
+      }									      \
+    else								      \
+      {									      \
+	STANDARD_TO_LOOP_ERR_HANDLER (4);				      \
+      }									      \
+									      \
+    inptr += 4;								      \
+  }
+#define LOOP_NEED_FLAGS
+#include <iconv/loop.c>
+#include <iconv/skeleton.c>
+
+
+/* Convert from UTF-8 to the internal (UCS4-like) format.  */
+#define DEFINE_INIT		0
+#define DEFINE_FINI		0
+#define MIN_NEEDED_FROM		1
+#define MAX_NEEDED_FROM		6
+#define MIN_NEEDED_TO		4
+#define FROM_DIRECTION		1
+#define FROM_LOOP		utf8_internal_loop
+#define TO_LOOP			utf8_internal_loop /* This is not used.  */
+#define FUNCTION_NAME		__gconv_transform_utf8_internal
+#define ONE_DIRECTION		1
+
+#define MIN_NEEDED_INPUT	MIN_NEEDED_FROM
+#define MAX_NEEDED_INPUT	MAX_NEEDED_FROM
+#define MIN_NEEDED_OUTPUT	MIN_NEEDED_TO
+#define LOOPFCT			FROM_LOOP
+#define BODY \
+  {									      \
+    /* Next input byte.  */						      \
+    uint32_t ch = *inptr;						      \
+									      \
+    if (__glibc_likely (ch < 0x80))					      \
+      {									      \
+	/* One byte sequence.  */					      \
+	++inptr;							      \
+      }									      \
+    else								      \
+      {									      \
+	uint_fast32_t cnt;						      \
+	uint_fast32_t i;						      \
+									      \
+	if (ch >= 0xc2 && ch < 0xe0)					      \
+	  {								      \
+	    /* We expect two bytes.  The first byte cannot be 0xc0 or 0xc1,   \
+	       otherwise the wide character could have been represented	      \
+	       using a single byte.  */					      \
+	    cnt = 2;							      \
+	    ch &= 0x1f;							      \
+	  }								      \
+	else if (__glibc_likely ((ch & 0xf0) == 0xe0))			      \
+	  {								      \
+	    /* We expect three bytes.  */				      \
+	    cnt = 3;							      \
+	    ch &= 0x0f;							      \
+	  }								      \
+	else if (__glibc_likely ((ch & 0xf8) == 0xf0))			      \
+	  {								      \
+	    /* We expect four bytes.  */				      \
+	    cnt = 4;							      \
+	    ch &= 0x07;							      \
+	  }								      \
+	else if (__glibc_likely ((ch & 0xfc) == 0xf8))			      \
+	  {								      \
+	    /* We expect five bytes.  */				      \
+	    cnt = 5;							      \
+	    ch &= 0x03;							      \
+	  }								      \
+	else if (__glibc_likely ((ch & 0xfe) == 0xfc))			      \
+	  {								      \
+	    /* We expect six bytes.  */					      \
+	    cnt = 6;							      \
+	    ch &= 0x01;							      \
+	  }								      \
+	else								      \
+	  {								      \
+	    /* Search the end of this ill-formed UTF-8 character.  This	      \
+	       is the next byte with (x & 0xc0) != 0x80.  */		      \
+	    i = 0;							      \
+	    do								      \
+	      ++i;							      \
+	    while (inptr + i < inend					      \
+		   && (*(inptr + i) & 0xc0) == 0x80			      \
+		   && i < 5);						      \
+									      \
+	  errout:							      \
+	    STANDARD_FROM_LOOP_ERR_HANDLER (i);				      \
+	  }								      \
+									      \
+	if (__glibc_unlikely (inptr + cnt > inend))			      \
+	  {								      \
+	    /* We don't have enough input.  But before we report that check   \
+	       that all the bytes are correct.  */			      \
+	    for (i = 1; inptr + i < inend; ++i)				      \
+	      if ((inptr[i] & 0xc0) != 0x80)				      \
+		break;							      \
+									      \
+	    if (__glibc_likely (inptr + i == inend))			      \
+	      {								      \
+		result = __GCONV_INCOMPLETE_INPUT;			      \
+		break;							      \
+	      }								      \
+									      \
+	    goto errout;						      \
+	  }								      \
+									      \
+	/* Read the possible remaining bytes.  */			      \
+	for (i = 1; i < cnt; ++i)					      \
+	  {								      \
+	    uint32_t byte = inptr[i];					      \
+									      \
+	    if ((byte & 0xc0) != 0x80)					      \
+	      /* This is an illegal encoding.  */			      \
+	      break;							      \
+									      \
+	    ch <<= 6;							      \
+	    ch |= byte & 0x3f;						      \
+	  }								      \
+									      \
+	/* If i < cnt, some trail byte was not >= 0x80, < 0xc0.		      \
+	   If cnt > 2 and ch < 2^(5*cnt-4), the wide character ch could	      \
+	   have been represented with fewer than cnt bytes.  */		      \
+	if (i < cnt || (cnt > 2 && (ch >> (5 * cnt - 4)) == 0)		      \
+	    /* Do not accept UTF-16 surrogates.  */			      \
+	    || (ch >= 0xd800 && ch <= 0xdfff))				      \
+	  {								      \
+	    /* This is an illegal encoding.  */				      \
+	    goto errout;						      \
+	  }								      \
+									      \
+	inptr += cnt;							      \
+      }									      \
+									      \
+    /* Now adjust the pointers and store the result.  */		      \
+    *((uint32_t *) outptr) = ch;					      \
+    outptr += sizeof (uint32_t);					      \
+  }
+#define LOOP_NEED_FLAGS
+
+#define STORE_REST \
+  {									      \
+    /* We store the remaining bytes while converting them into the UCS4	      \
+       format.  We can assume that the first byte in the buffer is	      \
+       correct and that it requires a larger number of bytes than there	      \
+       are in the input buffer.  */					      \
+    wint_t ch = **inptrp;						      \
+    size_t cnt, r;							      \
+									      \
+    state->__count = inend - *inptrp;					      \
+									      \
+    assert (ch != 0xc0 && ch != 0xc1);					      \
+    if (ch >= 0xc2 && ch < 0xe0)					      \
+      {									      \
+	/* We expect two bytes.  The first byte cannot be 0xc0 or	      \
+	   0xc1, otherwise the wide character could have been		      \
+	   represented using a single byte.  */				      \
+	cnt = 2;							      \
+	ch &= 0x1f;							      \
+      }									      \
+    else if (__glibc_likely ((ch & 0xf0) == 0xe0))			      \
+      {									      \
+	/* We expect three bytes.  */					      \
+	cnt = 3;							      \
+	ch &= 0x0f;							      \
+      }									      \
+    else if (__glibc_likely ((ch & 0xf8) == 0xf0))			      \
+      {									      \
+	/* We expect four bytes.  */					      \
+	cnt = 4;							      \
+	ch &= 0x07;							      \
+      }									      \
+    else if (__glibc_likely ((ch & 0xfc) == 0xf8))			      \
+      {									      \
+	/* We expect five bytes.  */					      \
+	cnt = 5;							      \
+	ch &= 0x03;							      \
+      }									      \
+    else								      \
+      {									      \
+	/* We expect six bytes.  */					      \
+	cnt = 6;							      \
+	ch &= 0x01;							      \
+      }									      \
+									      \
+    /* The first byte is already consumed.  */				      \
+    r = cnt - 1;							      \
+    while (++(*inptrp) < inend)						      \
+      {									      \
+	ch <<= 6;							      \
+	ch |= **inptrp & 0x3f;						      \
+	--r;								      \
+      }									      \
+									      \
+    /* Shift for the so far missing bytes.  */				      \
+    ch <<= r * 6;							      \
+									      \
+    /* Store the number of bytes expected for the entire sequence.  */	      \
+    state->__count |= cnt << 8;						      \
+									      \
+    /* Store the value.  */						      \
+    state->__value.__wch = ch;						      \
+  }
+
+#define UNPACK_BYTES \
+  {									      \
+    static const unsigned char inmask[5] = { 0xc0, 0xe0, 0xf0, 0xf8, 0xfc };  \
+    wint_t wch = state->__value.__wch;					      \
+    size_t ntotal = state->__count >> 8;				      \
+									      \
+    inlen = state->__count & 255;					      \
+									      \
+    bytebuf[0] = inmask[ntotal - 2];					      \
+									      \
+    do									      \
+      {									      \
+	if (--ntotal < inlen)						      \
+	  bytebuf[ntotal] = 0x80 | (wch & 0x3f);			      \
+	wch >>= 6;							      \
+      }									      \
+    while (ntotal > 1);							      \
+									      \
+    bytebuf[0] |= wch;							      \
+  }
+
+#define CLEAR_STATE \
+  state->__count = 0
+
+
+#include <iconv/loop.c>
+#include <iconv/skeleton.c>
+
+
+/* Convert from UCS2 to the internal (UCS4-like) format.  */
+#define DEFINE_INIT		0
+#define DEFINE_FINI		0
+#define MIN_NEEDED_FROM		2
+#define MIN_NEEDED_TO		4
+#define FROM_DIRECTION		1
+#define FROM_LOOP		ucs2_internal_loop
+#define TO_LOOP			ucs2_internal_loop /* This is not used.  */
+#define FUNCTION_NAME		__gconv_transform_ucs2_internal
+#define ONE_DIRECTION		1
+
+#define MIN_NEEDED_INPUT	MIN_NEEDED_FROM
+#define MIN_NEEDED_OUTPUT	MIN_NEEDED_TO
+#define LOOPFCT			FROM_LOOP
+#define BODY \
+  {									      \
+    uint16_t u1 = get16 (inptr);					      \
+									      \
+    if (__glibc_unlikely (u1 >= 0xd800 && u1 < 0xe000))			      \
+      {									      \
+	/* Surrogate characters in UCS-2 input are not valid.  Reject	      \
+	   them.  (Catching this here is not security relevant.)  */	      \
+	STANDARD_FROM_LOOP_ERR_HANDLER (2);				      \
+      }									      \
+									      \
+    *((uint32_t *) outptr) = u1;					      \
+    outptr += sizeof (uint32_t);					      \
+    inptr += 2;								      \
+  }
+#define LOOP_NEED_FLAGS
+#include <iconv/loop.c>
+#include <iconv/skeleton.c>
+
+
+/* Convert from the internal (UCS4-like) format to UCS2.  */
+#define DEFINE_INIT		0
+#define DEFINE_FINI		0
+#define MIN_NEEDED_FROM		4
+#define MIN_NEEDED_TO		2
+#define FROM_DIRECTION		1
+#define FROM_LOOP		internal_ucs2_loop
+#define TO_LOOP			internal_ucs2_loop /* This is not used.  */
+#define FUNCTION_NAME		__gconv_transform_internal_ucs2
+#define ONE_DIRECTION		1
+
+#define MIN_NEEDED_INPUT	MIN_NEEDED_FROM
+#define MIN_NEEDED_OUTPUT	MIN_NEEDED_TO
+#define LOOPFCT			FROM_LOOP
+#define BODY \
+  {									      \
+    uint32_t val = *((const uint32_t *) inptr);				      \
+									      \
+    if (__glibc_unlikely (val >= 0x10000))				      \
+      {									      \
+	UNICODE_TAG_HANDLER (val, 4);					      \
+	STANDARD_TO_LOOP_ERR_HANDLER (4);				      \
+      }									      \
+    else if (__glibc_unlikely (val >= 0xd800 && val < 0xe000))		      \
+      {									      \
+	/* Surrogate characters in UCS-4 input are not valid.		      \
+	   We must catch this, because the UCS-2 output might be	      \
+	   interpreted as UTF-16 by other programs.  If we let		      \
+	   surrogates pass through, attackers could make a security	      \
+	   hole exploit by synthesizing any desired plane 1-16		      \
+	   character.  */						      \
+	result = __GCONV_ILLEGAL_INPUT;					      \
+	if (! ignore_errors_p ())					      \
+	  break;							      \
+	inptr += 4;							      \
+	++*irreversible;						      \
+	continue;							      \
+      }									      \
+    else								      \
+      {									      \
+	put16 (outptr, val);						      \
+	outptr += sizeof (uint16_t);					      \
+	inptr += 4;							      \
+      }									      \
+  }
+#define LOOP_NEED_FLAGS
+#include <iconv/loop.c>
+#include <iconv/skeleton.c>
+
+
+/* Convert from UCS2 in other endianness to the internal (UCS4-like) format. */
+#define DEFINE_INIT		0
+#define DEFINE_FINI		0
+#define MIN_NEEDED_FROM		2
+#define MIN_NEEDED_TO		4
+#define FROM_DIRECTION		1
+#define FROM_LOOP		ucs2reverse_internal_loop
+#define TO_LOOP			ucs2reverse_internal_loop/* This is not used.*/
+#define FUNCTION_NAME		__gconv_transform_ucs2reverse_internal
+#define ONE_DIRECTION		1
+
+#define MIN_NEEDED_INPUT	MIN_NEEDED_FROM
+#define MIN_NEEDED_OUTPUT	MIN_NEEDED_TO
+#define LOOPFCT			FROM_LOOP
+#define BODY \
+  {									      \
+    uint16_t u1 = bswap_16 (get16 (inptr));				      \
+									      \
+    if (__glibc_unlikely (u1 >= 0xd800 && u1 < 0xe000))			      \
+      {									      \
+	/* Surrogate characters in UCS-2 input are not valid.  Reject	      \
+	   them.  (Catching this here is not security relevant.)  */	      \
+	if (! ignore_errors_p ())					      \
+	  {								      \
+	    result = __GCONV_ILLEGAL_INPUT;				      \
+	    break;							      \
+	  }								      \
+	inptr += 2;							      \
+	++*irreversible;						      \
+	continue;							      \
+      }									      \
+									      \
+    *((uint32_t *) outptr) = u1;					      \
+    outptr += sizeof (uint32_t);					      \
+    inptr += 2;								      \
+  }
+#define LOOP_NEED_FLAGS
+#include <iconv/loop.c>
+#include <iconv/skeleton.c>
+
+
+/* Convert from the internal (UCS4-like) format to UCS2 in other endianness. */
+#define DEFINE_INIT		0
+#define DEFINE_FINI		0
+#define MIN_NEEDED_FROM		4
+#define MIN_NEEDED_TO		2
+#define FROM_DIRECTION		1
+#define FROM_LOOP		internal_ucs2reverse_loop
+#define TO_LOOP			internal_ucs2reverse_loop/* This is not used.*/
+#define FUNCTION_NAME		__gconv_transform_internal_ucs2reverse
+#define ONE_DIRECTION		1
+
+#define MIN_NEEDED_INPUT	MIN_NEEDED_FROM
+#define MIN_NEEDED_OUTPUT	MIN_NEEDED_TO
+#define LOOPFCT			FROM_LOOP
+#define BODY \
+  {									      \
+    uint32_t val = *((const uint32_t *) inptr);				      \
+    if (__glibc_unlikely (val >= 0x10000))				      \
+      {									      \
+	UNICODE_TAG_HANDLER (val, 4);					      \
+	STANDARD_TO_LOOP_ERR_HANDLER (4);				      \
+      }									      \
+    else if (__glibc_unlikely (val >= 0xd800 && val < 0xe000))		      \
+      {									      \
+	/* Surrogate characters in UCS-4 input are not valid.		      \
+	   We must catch this, because the UCS-2 output might be	      \
+	   interpreted as UTF-16 by other programs.  If we let		      \
+	   surrogates pass through, attackers could make a security	      \
+	   hole exploit by synthesizing any desired plane 1-16		      \
+	   character.  */						      \
+	if (! ignore_errors_p ())					      \
+	  {								      \
+	    result = __GCONV_ILLEGAL_INPUT;				      \
+	    break;							      \
+	  }								      \
+	inptr += 4;							      \
+	++*irreversible;						      \
+	continue;							      \
+      }									      \
+    else								      \
+      {									      \
+	put16 (outptr, bswap_16 (val));					      \
+	outptr += sizeof (uint16_t);					      \
+	inptr += 4;							      \
+      }									      \
+  }
+#define LOOP_NEED_FLAGS
+#include <iconv/loop.c>
+#include <iconv/skeleton.c>
diff --git a/REORG.TODO/iconv/gconv_trans.c b/REORG.TODO/iconv/gconv_trans.c
new file mode 100644
index 0000000000..53b8822615
--- /dev/null
+++ b/REORG.TODO/iconv/gconv_trans.c
@@ -0,0 +1,239 @@
+/* Transliteration using the locale's data.
+   Copyright (C) 2000-2017 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 Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 2.1 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
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with the GNU C Library; if not, see
+   <http://www.gnu.org/licenses/>.  */
+
+#include <assert.h>
+#include <dlfcn.h>
+#include <search.h>
+#include <stdint.h>
+#include <string.h>
+#include <stdlib.h>
+
+#include <libc-lock.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, size_t *irreversible)
+{
+  /* Find out about the locale's transliteration.  */
+  uint_fast32_t size;
+  const uint32_t *from_idx;
+  const uint32_t *from_tbl;
+  const uint32_t *to_idx;
+  const uint32_t *to_tbl;
+  const uint32_t *winbuf;
+  const uint32_t *winbufend;
+  uint_fast32_t low;
+  uint_fast32_t high;
+
+  /* The input buffer.  There are actually 4-byte values.  */
+  winbuf = (const uint32_t *) *inbufp;
+  winbufend = (const uint32_t *) inbufend;
+
+  __gconv_fct fct = step->__fct;
+#ifdef PTR_DEMANGLE
+  if (step->__shlib_handle != NULL)
+    PTR_DEMANGLE (fct);
+#endif
+
+  /* If there is no transliteration information in the locale don't do
+     anything and return the error.  */
+  size = _NL_CURRENT_WORD (LC_CTYPE, _NL_CTYPE_TRANSLIT_TAB_SIZE);
+  if (size == 0)
+    goto no_rules;
+
+  /* Get the rest of the values.  */
+  from_idx =
+    (const uint32_t *) _NL_CURRENT (LC_CTYPE, _NL_CTYPE_TRANSLIT_FROM_IDX);
+  from_tbl =
+    (const uint32_t *) _NL_CURRENT (LC_CTYPE, _NL_CTYPE_TRANSLIT_FROM_TBL);
+  to_idx =
+    (const uint32_t *) _NL_CURRENT (LC_CTYPE, _NL_CTYPE_TRANSLIT_TO_IDX);
+  to_tbl =
+    (const uint32_t *) _NL_CURRENT (LC_CTYPE, _NL_CTYPE_TRANSLIT_TO_TBL);
+
+  /* Test whether there is enough input.  */
+  if (winbuf + 1 > winbufend)
+    return (winbuf == winbufend
+	    ? __GCONV_EMPTY_INPUT : __GCONV_INCOMPLETE_INPUT);
+
+  /* The array starting at FROM_IDX contains indeces to the string table
+     in FROM_TBL.  The indeces are sorted wrt to the strings.  I.e., we
+     are doing binary search.  */
+  low = 0;
+  high = size;
+  while (low < high)
+    {
+      uint_fast32_t med = (low + high) / 2;
+      uint32_t idx;
+      int cnt;
+
+      /* Compare the string at this index with the string at the current
+	 position in the input buffer.  */
+      idx = from_idx[med];
+      cnt = 0;
+      do
+	{
+	  if (from_tbl[idx + cnt] != winbuf[cnt])
+	    /* Does not match.  */
+	    break;
+	  ++cnt;
+	}
+      while (from_tbl[idx + cnt] != L'\0' && winbuf + cnt < winbufend);
+
+      if (cnt > 0 && from_tbl[idx + cnt] == L'\0')
+	{
+	  /* Found a matching input sequence.  Now try to convert the
+	     possible replacements.  */
+	  uint32_t idx2 = to_idx[med];
+
+	  do
+	    {
+	      /* Determine length of replacement.  */
+	      uint_fast32_t len = 0;
+	      int res;
+	      const unsigned char *toinptr;
+	      unsigned char *outptr;
+
+	      while (to_tbl[idx2 + len] != L'\0')
+		++len;
+
+	      /* Try this input text.  */
+	      toinptr = (const unsigned char *) &to_tbl[idx2];
+	      outptr = *outbufstart;
+	      res = DL_CALL_FCT (fct,
+				 (step, step_data, &toinptr,
+				  (const unsigned char *) &to_tbl[idx2 + len],
+				  &outptr, NULL, 0, 0));
+	      if (res != __GCONV_ILLEGAL_INPUT)
+		{
+		  /* If the conversion succeeds we have to increment the
+		     input buffer.  */
+		  if (res == __GCONV_EMPTY_INPUT)
+		    {
+		      *inbufp += cnt * sizeof (uint32_t);
+		      ++*irreversible;
+		      res = __GCONV_OK;
+		    }
+		  /* Do not increment the output pointer if we could not
+		     store the entire output. */
+		  if (res != __GCONV_FULL_OUTPUT)
+		    *outbufstart = outptr;
+
+		  return res;
+		}
+
+	      /* Next replacement.  */
+	      idx2 += len + 1;
+	    }
+	  while (to_tbl[idx2] != L'\0');
+
+	  /* Nothing found, continue searching.  */
+	}
+      else if (cnt > 0)
+	/* This means that the input buffer contents matches a prefix of
+	   an entry.  Since we cannot match it unless we get more input,
+	   we will tell the caller about it.  */
+	return __GCONV_INCOMPLETE_INPUT;
+
+      if (winbuf + cnt >= winbufend || from_tbl[idx + cnt] < winbuf[cnt])
+	low = med + 1;
+      else
+	high = med;
+    }
+
+ no_rules:
+  /* Maybe the character is supposed to be ignored.  */
+  if (_NL_CURRENT_WORD (LC_CTYPE, _NL_CTYPE_TRANSLIT_IGNORE_LEN) != 0)
+    {
+      int n = _NL_CURRENT_WORD (LC_CTYPE, _NL_CTYPE_TRANSLIT_IGNORE_LEN);
+      const uint32_t *ranges =
+	(const uint32_t *) _NL_CURRENT (LC_CTYPE, _NL_CTYPE_TRANSLIT_IGNORE);
+      const uint32_t wc = *(const uint32_t *) (*inbufp);
+      int i;
+
+      /* Test whether there is enough input.  */
+      if (winbuf + 1 > winbufend)
+	return (winbuf == winbufend
+		? __GCONV_EMPTY_INPUT : __GCONV_INCOMPLETE_INPUT);
+
+      for (i = 0; i < n; ranges += 3, ++i)
+	if (ranges[0] <= wc && wc <= ranges[1]
+	    && (wc - ranges[0]) % ranges[2] == 0)
+	  {
+	    /* Matches the range.  Ignore it.  */
+	    *inbufp += 4;
+	    ++*irreversible;
+	    return __GCONV_OK;
+	  }
+	else if (wc < ranges[0])
+	  /* There cannot be any other matching range since they are
+             sorted.  */
+	  break;
+    }
+
+  /* One last chance: use the default replacement.  */
+  if (_NL_CURRENT_WORD (LC_CTYPE, _NL_CTYPE_TRANSLIT_DEFAULT_MISSING_LEN) != 0)
+    {
+      const uint32_t *default_missing = (const uint32_t *)
+	_NL_CURRENT (LC_CTYPE, _NL_CTYPE_TRANSLIT_DEFAULT_MISSING);
+      const unsigned char *toinptr = (const unsigned char *) default_missing;
+      uint32_t len = _NL_CURRENT_WORD (LC_CTYPE,
+				       _NL_CTYPE_TRANSLIT_DEFAULT_MISSING_LEN);
+      unsigned char *outptr;
+      int res;
+
+      /* Test whether there is enough input.  */
+      if (winbuf + 1 > winbufend)
+	return (winbuf == winbufend
+		? __GCONV_EMPTY_INPUT : __GCONV_INCOMPLETE_INPUT);
+
+      outptr = *outbufstart;
+      res = DL_CALL_FCT (fct,
+			 (step, step_data, &toinptr,
+			  (const unsigned char *) (default_missing + len),
+			  &outptr, NULL, 0, 0));
+
+      if (res != __GCONV_ILLEGAL_INPUT)
+	{
+	  /* If the conversion succeeds we have to increment the
+	     input buffer.  */
+	  if (res == __GCONV_EMPTY_INPUT)
+	    {
+	      /* This worked but is not reversible.  */
+	      ++*irreversible;
+	      *inbufp += 4;
+	      res = __GCONV_OK;
+	    }
+	  *outbufstart = outptr;
+
+	  return res;
+	}
+    }
+
+  /* Haven't found a match.  */
+  return __GCONV_ILLEGAL_INPUT;
+}
+libc_hidden_def (__gconv_transliterate)
diff --git a/REORG.TODO/iconv/iconv.c b/REORG.TODO/iconv/iconv.c
new file mode 100644
index 0000000000..2c6f0f0bd1
--- /dev/null
+++ b/REORG.TODO/iconv/iconv.c
@@ -0,0 +1,95 @@
+/* Convert characters in input buffer using conversion descriptor to
+   output buffer.
+   Copyright (C) 1997-2017 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+   Contributed by Ulrich Drepper <drepper@cygnus.com>, 1997.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 2.1 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
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with the GNU C Library; if not, see
+   <http://www.gnu.org/licenses/>.  */
+
+#include <stddef.h> /* for NULL */
+#include <errno.h>
+#include <iconv.h>
+
+#include <gconv_int.h>
+
+#include <assert.h>
+
+
+size_t
+iconv (iconv_t cd, char **inbuf, size_t *inbytesleft, char **outbuf,
+       size_t *outbytesleft)
+{
+  __gconv_t gcd = (__gconv_t) cd;
+  char *outstart = outbuf ? *outbuf : NULL;
+  size_t irreversible;
+  int result;
+
+  if (__glibc_unlikely (inbuf == NULL || *inbuf == NULL))
+    {
+      if (outbuf == NULL || *outbuf == NULL)
+	result = __gconv (gcd, NULL, NULL, NULL, NULL, &irreversible);
+      else
+	result = __gconv (gcd, NULL, NULL, (unsigned char **) outbuf,
+			  (unsigned char *) (outstart + *outbytesleft),
+			  &irreversible);
+    }
+  else
+    {
+      const char *instart = *inbuf;
+
+      result = __gconv (gcd, (const unsigned char **) inbuf,
+			(const unsigned char *)  (*inbuf + *inbytesleft),
+			(unsigned char **) outbuf,
+			(unsigned char *) (*outbuf + *outbytesleft),
+			&irreversible);
+
+      *inbytesleft -= *inbuf - instart;
+    }
+  if (outstart != NULL)
+    *outbytesleft -= *outbuf - outstart;
+
+  switch (__builtin_expect (result, __GCONV_OK))
+    {
+    case __GCONV_ILLEGAL_DESCRIPTOR:
+      __set_errno (EBADF);
+      irreversible = (size_t) -1L;
+      break;
+
+    case __GCONV_ILLEGAL_INPUT:
+      __set_errno (EILSEQ);
+      irreversible = (size_t) -1L;
+      break;
+
+    case __GCONV_FULL_OUTPUT:
+      __set_errno (E2BIG);
+      irreversible = (size_t) -1L;
+      break;
+
+    case __GCONV_INCOMPLETE_INPUT:
+      __set_errno (EINVAL);
+      irreversible = (size_t) -1L;
+      break;
+
+    case __GCONV_EMPTY_INPUT:
+    case __GCONV_OK:
+      /* Nothing.  */
+      break;
+
+    default:
+      assert (!"Nothing like this should happen");
+    }
+
+  return irreversible;
+}
diff --git a/REORG.TODO/iconv/iconv.h b/REORG.TODO/iconv/iconv.h
new file mode 100644
index 0000000000..d5d9d00f6b
--- /dev/null
+++ b/REORG.TODO/iconv/iconv.h
@@ -0,0 +1,55 @@
+/* Copyright (C) 1997-2017 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
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 2.1 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
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with the GNU C Library; if not, see
+   <http://www.gnu.org/licenses/>.  */
+
+#ifndef _ICONV_H
+#define _ICONV_H	1
+
+#include <features.h>
+#define __need_size_t
+#include <stddef.h>
+
+
+__BEGIN_DECLS
+
+/* Identifier for conversion method from one codeset to another.  */
+typedef void *iconv_t;
+
+
+/* Allocate descriptor for code conversion from codeset FROMCODE to
+   codeset TOCODE.
+
+   This function is a possible cancellation point and therefore not
+   marked with __THROW.  */
+extern iconv_t iconv_open (const char *__tocode, const char *__fromcode);
+
+/* Convert at most *INBYTESLEFT bytes from *INBUF according to the
+   code conversion algorithm specified by CD and place up to
+   *OUTBYTESLEFT bytes in buffer at *OUTBUF.  */
+extern size_t iconv (iconv_t __cd, char **__restrict __inbuf,
+		     size_t *__restrict __inbytesleft,
+		     char **__restrict __outbuf,
+		     size_t *__restrict __outbytesleft);
+
+/* Free resources allocated for descriptor CD for code conversion.
+
+   This function is a possible cancellation point and therefore not
+   marked with __THROW.  */
+extern int iconv_close (iconv_t __cd);
+
+__END_DECLS
+
+#endif /* iconv.h */
diff --git a/REORG.TODO/iconv/iconv_charmap.c b/REORG.TODO/iconv/iconv_charmap.c
new file mode 100644
index 0000000000..b8ece3bda2
--- /dev/null
+++ b/REORG.TODO/iconv/iconv_charmap.c
@@ -0,0 +1,560 @@
+/* Convert using charmaps and possibly iconv().
+   Copyright (C) 2001-2017 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+   Contributed by Ulrich Drepper <drepper@redhat.com>, 2001.
+
+   This program is free software; you can redistribute it and/or modify
+   it under the terms of the GNU General Public License as published
+   by the Free Software Foundation; version 2 of the License, or
+   (at your option) any later version.
+
+   This program 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 General Public License for more details.
+
+   You should have received a copy of the GNU General Public License
+   along with this program; if not, see <http://www.gnu.org/licenses/>.  */
+
+#include <assert.h>
+#include <errno.h>
+#include <error.h>
+#include <fcntl.h>
+#include <iconv.h>
+#include <libintl.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <stdint.h>
+#include <sys/mman.h>
+#include <sys/stat.h>
+
+#include "iconv_prog.h"
+
+
+/* Prototypes for a few program-wide used functions.  */
+#include <programs/xmalloc.h>
+
+
+struct convtable
+{
+  int term[256 / 8];
+  union
+  {
+    struct convtable *sub;
+    struct charseq *out;
+  } val[256];
+};
+
+
+static inline struct convtable *
+allocate_table (void)
+{
+  return (struct convtable *) xcalloc (1, sizeof (struct convtable));
+}
+
+
+static inline int
+is_term (struct convtable *tbl, unsigned int idx)
+{
+  return tbl->term[idx / 8] & (1 << (idx % 8));
+}
+
+
+static inline void
+clear_term (struct convtable *tbl, unsigned int idx)
+{
+  tbl->term[idx / 8] &= ~(1 << (idx % 8));
+}
+
+
+static inline void
+set_term (struct convtable *tbl, unsigned int idx)
+{
+  tbl->term[idx / 8] |= 1 << (idx % 8);
+}
+
+
+/* Generate the conversion table.  */
+static struct convtable *use_from_charmap (struct charmap_t *from_charmap,
+					   const char *to_code);
+static struct convtable *use_to_charmap (const char *from_code,
+					 struct charmap_t *to_charmap);
+static struct convtable *use_both_charmaps (struct charmap_t *from_charmap,
+					    struct charmap_t *to_charmap);
+
+/* Prototypes for the functions doing the actual work.  */
+static int process_block (struct convtable *tbl, char *addr, size_t len,
+			  FILE *output);
+static int process_fd (struct convtable *tbl, int fd, FILE *output);
+static int process_file (struct convtable *tbl, FILE *input, FILE *output);
+
+
+int
+charmap_conversion (const char *from_code, struct charmap_t *from_charmap,
+		    const char *to_code, struct charmap_t *to_charmap,
+		    int argc, int remaining, char *argv[],
+		    const char *output_file)
+{
+  struct convtable *cvtbl;
+  int status = EXIT_SUCCESS;
+
+  /* We have three different cases to handle:
+
+     - both, from_charmap and to_charmap, are available.  This means we
+       can assume that the symbolic names match and use them to create
+       the mapping.
+
+     - only from_charmap is available.  In this case we can only hope that
+       the symbolic names used are of the <Uxxxx> form in which case we
+       can use a UCS4->"to_code" iconv() conversion for the second step.
+
+     - only to_charmap is available.  This is similar, only that we would
+       use iconv() for the "to_code"->UCS4 conversion.
+
+       We first create a table which maps input bytes into output bytes.
+       Once this is done we can handle all three of the cases above
+       equally.  */
+  if (from_charmap != NULL)
+    {
+      if (to_charmap == NULL)
+	cvtbl = use_from_charmap (from_charmap, to_code);
+      else
+	cvtbl = use_both_charmaps (from_charmap, to_charmap);
+    }
+  else
+    {
+      assert (to_charmap != NULL);
+      cvtbl = use_to_charmap (from_code, to_charmap);
+    }
+
+  /* If we couldn't generate a table stop now.  */
+  if (cvtbl == NULL)
+    return EXIT_FAILURE;
+
+  /* Determine output file.  */
+  FILE *output;
+  if (output_file != NULL && strcmp (output_file, "-") != 0)
+    {
+      output = fopen (output_file, "w");
+      if (output == NULL)
+	error (EXIT_FAILURE, errno, _("cannot open output file"));
+    }
+  else
+    output = stdout;
+
+  /* We can now start the conversion.  */
+  if (remaining == argc)
+    {
+      if (process_file (cvtbl, stdin, output) != 0)
+	status = EXIT_FAILURE;
+    }
+  else
+    do
+      {
+	int fd;
+
+	if (verbose)
+	  printf ("%s:\n", argv[remaining]);
+	if (strcmp (argv[remaining], "-") == 0)
+	  fd = 0;
+	else
+	  {
+	    fd = open (argv[remaining], O_RDONLY);
+
+	    if (fd == -1)
+	      {
+		error (0, errno, _("cannot open input file `%s'"),
+		       argv[remaining]);
+		status = EXIT_FAILURE;
+		continue;
+	      }
+	  }
+
+#ifdef _POSIX_MAPPED_FILES
+	struct stat64 st;
+	char *addr;
+	/* We have possibilities for reading the input file.  First try
+	   to mmap() it since this will provide the fastest solution.  */
+	if (fstat64 (fd, &st) == 0
+	    && ((addr = mmap (NULL, st.st_size, PROT_READ, MAP_PRIVATE,
+			      fd, 0)) != MAP_FAILED))
+	  {
+	    /* Yes, we can use mmap().  The descriptor is not needed
+	       anymore.  */
+	    if (close (fd) != 0)
+	      error (EXIT_FAILURE, errno,
+		     _("error while closing input `%s'"), argv[remaining]);
+
+	    if (process_block (cvtbl, addr, st.st_size, output) < 0)
+	      {
+		/* Something went wrong.  */
+		status = EXIT_FAILURE;
+
+		/* We don't need the input data anymore.  */
+		munmap ((void *) addr, st.st_size);
+
+		/* We cannot go on with producing output since it might
+		   lead to problem because the last output might leave
+		   the output stream in an undefined state.  */
+		break;
+	      }
+
+	    /* We don't need the input data anymore.  */
+	    munmap ((void *) addr, st.st_size);
+	  }
+	else
+#endif	/* _POSIX_MAPPED_FILES */
+	  {
+	    /* Read the file in pieces.  */
+	    if (process_fd (cvtbl, fd, output) != 0)
+	      {
+		/* Something went wrong.  */
+		status = EXIT_FAILURE;
+
+		/* We don't need the input file anymore.  */
+		close (fd);
+
+		/* We cannot go on with producing output since it might
+		   lead to problem because the last output might leave
+		   the output stream in an undefined state.  */
+		break;
+	      }
+
+	    /* Now close the file.  */
+	    close (fd);
+	  }
+      }
+    while (++remaining < argc);
+
+  /* All done.  */
+  return status;
+}
+
+
+/* Add the IN->OUT mapping to TBL.  OUT is potentially stored in the table.
+   IN is used only here, so it need not be kept live afterwards.  */
+static void
+add_bytes (struct convtable *tbl, const struct charseq *in, struct charseq *out)
+{
+  int n = 0;
+  unsigned int byte;
+
+  assert (in->nbytes > 0);
+
+  byte = ((unsigned char *) in->bytes)[n];
+  while (n + 1 < in->nbytes)
+    {
+      if (is_term (tbl, byte) || tbl->val[byte].sub == NULL)
+	{
+	  /* Note that we simply ignore a definition for a byte sequence
+	     which is also the prefix for a longer one.  */
+	  clear_term (tbl, byte);
+	  tbl->val[byte].sub =
+	    (struct convtable *) xcalloc (1, sizeof (struct convtable));
+	}
+
+      tbl = tbl->val[byte].sub;
+
+      byte = ((unsigned char *) in->bytes)[++n];
+    }
+
+  /* Only add the new sequence if there is none yet and the byte sequence
+     is not part of an even longer one.  */
+  if (! is_term (tbl, byte) && tbl->val[byte].sub == NULL)
+    {
+      set_term (tbl, byte);
+      tbl->val[byte].out = out;
+    }
+}
+
+/* Try to convert SEQ from WCHAR_T format using CD.
+   Returns a malloc'd struct or NULL.  */
+static struct charseq *
+convert_charseq (iconv_t cd, const struct charseq *seq)
+{
+  struct charseq *result = NULL;
+
+  if (seq->ucs4 != UNINITIALIZED_CHAR_VALUE)
+    {
+      /* There is a chance.  Try the iconv module.  */
+      wchar_t inbuf[1] = { seq->ucs4 };
+      unsigned char outbuf[64];
+      char *inptr = (char *) inbuf;
+      size_t inlen = sizeof (inbuf);
+      char *outptr = (char *) outbuf;
+      size_t outlen = sizeof (outbuf);
+
+      (void) iconv (cd, &inptr, &inlen, &outptr, &outlen);
+
+      if (outptr != (char *) outbuf)
+        {
+          /* We got some output.  Good, use it.  */
+          outlen = sizeof (outbuf) - outlen;
+          assert ((char *) outbuf + outlen == outptr);
+
+          result = xmalloc (sizeof (struct charseq) + outlen);
+          result->name = seq->name;
+          result->ucs4 = seq->ucs4;
+          result->nbytes = outlen;
+          memcpy (result->bytes, outbuf, outlen);
+        }
+
+      /* Clear any possible state left behind.  */
+      (void) iconv (cd, NULL, NULL, NULL, NULL);
+    }
+
+  return result;
+}
+
+
+static struct convtable *
+use_from_charmap (struct charmap_t *from_charmap, const char *to_code)
+{
+  /* We iterate over all entries in the from_charmap and for those which
+     have a known UCS4 representation we use an iconv() call to determine
+     the mapping to the to_code charset.  */
+  struct convtable *rettbl;
+  iconv_t cd;
+  void *ptr = NULL;
+  const void *key;
+  size_t keylen;
+  void *data;
+
+  cd = iconv_open (to_code, "WCHAR_T");
+  if (cd == (iconv_t) -1)
+    /* We cannot do anything.  */
+    return NULL;
+
+  rettbl = allocate_table ();
+
+  while (iterate_table (&from_charmap->char_table, &ptr, &key, &keylen, &data)
+	 >= 0)
+    {
+      struct charseq *in = data;
+      struct charseq *newp = convert_charseq (cd, in);
+      if (newp != NULL)
+        add_bytes (rettbl, in, newp);
+    }
+
+  iconv_close (cd);
+
+  return rettbl;
+}
+
+
+static struct convtable *
+use_to_charmap (const char *from_code, struct charmap_t *to_charmap)
+{
+  /* We iterate over all entries in the to_charmap and for those which
+     have a known UCS4 representation we use an iconv() call to determine
+     the mapping to the from_code charset.  */
+  struct convtable *rettbl;
+  iconv_t cd;
+  void *ptr = NULL;
+  const void *key;
+  size_t keylen;
+  void *data;
+
+  /* Note that the conversion we use here is the reverse direction.  Without
+     exhaustive search we cannot figure out which input yields the UCS4
+     character we are looking for.  Therefore we determine it the other
+     way round.  */
+  cd = iconv_open (from_code, "WCHAR_T");
+  if (cd == (iconv_t) -1)
+    /* We cannot do anything.  */
+    return NULL;
+
+  rettbl = allocate_table ();
+
+  while (iterate_table (&to_charmap->char_table, &ptr, &key, &keylen, &data)
+	 >= 0)
+    {
+      struct charseq *out = data;
+      struct charseq *newp = convert_charseq (cd, out);
+      if (newp != NULL)
+        {
+          add_bytes (rettbl, newp, out);
+          free (newp);
+        }
+    }
+
+  iconv_close (cd);
+
+  return rettbl;
+}
+
+
+static struct convtable *
+use_both_charmaps (struct charmap_t *from_charmap,
+		   struct charmap_t *to_charmap)
+{
+  /* In this case we iterate over all the entries in the from_charmap,
+     determine the internal name, and find an appropriate entry in the
+     to_charmap (if it exists).  */
+  struct convtable *rettbl = allocate_table ();
+  void *ptr = NULL;
+  const void *key;
+  size_t keylen;
+  void *data;
+
+  while (iterate_table (&from_charmap->char_table, &ptr, &key, &keylen, &data)
+	 >= 0)
+    {
+      struct charseq *in = (struct charseq *) data;
+      struct charseq *out = charmap_find_value (to_charmap, key, keylen);
+
+      if (out != NULL)
+	add_bytes (rettbl, in, out);
+    }
+
+  return rettbl;
+}
+
+
+static int
+process_block (struct convtable *tbl, char *addr, size_t len, FILE *output)
+{
+  size_t n = 0;
+
+  while (n < len)
+    {
+      struct convtable *cur = tbl;
+      unsigned char *curp = (unsigned char *) addr;
+      unsigned int byte = *curp;
+      int cnt;
+      struct charseq *out;
+
+      while (! is_term (cur, byte))
+	if (cur->val[byte].sub == NULL)
+	  {
+	    /* This is an invalid sequence.  Skip the first byte if we are
+	       ignoring errors.  Otherwise punt.  */
+	    if (! omit_invalid)
+	      {
+		error (0, 0, _("illegal input sequence at position %Zd"), n);
+		return -1;
+	      }
+
+	    n -= curp - (unsigned char *) addr;
+
+	    byte = *(curp = (unsigned char *) ++addr);
+	    if (++n >= len)
+	      /* All converted.  */
+	      return 0;
+
+	    cur = tbl;
+	  }
+	else
+	  {
+	    cur = cur->val[byte].sub;
+
+	    if (++n >= len)
+	      {
+		error (0, 0, _("\
+incomplete character or shift sequence at end of buffer"));
+		return -1;
+	      }
+
+	    byte = *++curp;
+	  }
+
+      /* We found a final byte.  Write the output bytes.  */
+      out = cur->val[byte].out;
+      for (cnt = 0; cnt < out->nbytes; ++cnt)
+	fputc_unlocked (out->bytes[cnt], output);
+
+      addr = (char *) curp + 1;
+      ++n;
+    }
+
+  return 0;
+}
+
+
+static int
+process_fd (struct convtable *tbl, int fd, FILE *output)
+{
+  /* We have a problem with reading from a descriptor since we must not
+     provide the iconv() function an incomplete character or shift
+     sequence at the end of the buffer.  Since we have to deal with
+     arbitrary encodings we must read the whole text in a buffer and
+     process it in one step.  */
+  static char *inbuf = NULL;
+  static size_t maxlen = 0;
+  char *inptr = inbuf;
+  size_t actlen = 0;
+
+  while (actlen < maxlen)
+    {
+      ssize_t n = read (fd, inptr, maxlen - actlen);
+
+      if (n == 0)
+	/* No more text to read.  */
+	break;
+
+      if (n == -1)
+	{
+	  /* Error while reading.  */
+	  error (0, errno, _("error while reading the input"));
+	  return -1;
+	}
+
+      inptr += n;
+      actlen += n;
+    }
+
+  if (actlen == maxlen)
+    while (1)
+      {
+	ssize_t n;
+	char *new_inbuf;
+
+	/* Increase the buffer.  */
+	new_inbuf = (char *) realloc (inbuf, maxlen + 32768);
+	if (new_inbuf == NULL)
+	  {
+	    error (0, errno, _("unable to allocate buffer for input"));
+	    return -1;
+	  }
+	inbuf = new_inbuf;
+	maxlen += 32768;
+	inptr = inbuf + actlen;
+
+	do
+	  {
+	    n = read (fd, inptr, maxlen - actlen);
+
+	    if (n == 0)
+	      /* No more text to read.  */
+	      break;
+
+	    if (n == -1)
+	      {
+		/* Error while reading.  */
+		error (0, errno, _("error while reading the input"));
+		return -1;
+	      }
+
+	    inptr += n;
+	    actlen += n;
+	  }
+	while (actlen < maxlen);
+
+	if (n == 0)
+	  /* Break again so we leave both loops.  */
+	  break;
+      }
+
+  /* Now we have all the input in the buffer.  Process it in one run.  */
+  return process_block (tbl, inbuf, actlen, output);
+}
+
+
+static int
+process_file (struct convtable *tbl, FILE *input, FILE *output)
+{
+  /* This should be safe since we use this function only for `stdin' and
+     we haven't read anything so far.  */
+  return process_fd (tbl, fileno (input), output);
+}
diff --git a/REORG.TODO/iconv/iconv_close.c b/REORG.TODO/iconv/iconv_close.c
new file mode 100644
index 0000000000..b4b3aff082
--- /dev/null
+++ b/REORG.TODO/iconv/iconv_close.c
@@ -0,0 +1,36 @@
+/* Release any resource associated with given conversion descriptor.
+   Copyright (C) 1997-2017 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+   Contributed by Ulrich Drepper <drepper@cygnus.com>, 1997.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 2.1 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
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with the GNU C Library; if not, see
+   <http://www.gnu.org/licenses/>.  */
+
+#include <errno.h>
+#include <iconv.h>
+
+#include <gconv_int.h>
+
+
+int
+iconv_close (iconv_t cd)
+{
+  if (__glibc_unlikely (cd == (iconv_t *) -1L))
+    {
+      __set_errno (EBADF);
+      return -1;
+    }
+
+  return __gconv_close ((__gconv_t) cd) ? -1 : 0;
+}
diff --git a/REORG.TODO/iconv/iconv_open.c b/REORG.TODO/iconv/iconv_open.c
new file mode 100644
index 0000000000..02e2b7d85e
--- /dev/null
+++ b/REORG.TODO/iconv/iconv_open.c
@@ -0,0 +1,88 @@
+/* Get descriptor for character set conversion.
+   Copyright (C) 1997-2017 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+   Contributed by Ulrich Drepper <drepper@cygnus.com>, 1997.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 2.1 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
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with the GNU C Library; if not, see
+   <http://www.gnu.org/licenses/>.  */
+
+#include <alloca.h>
+#include <errno.h>
+#include <iconv.h>
+#include <stdbool.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include <gconv_int.h>
+#include "gconv_charset.h"
+
+
+iconv_t
+iconv_open (const char *tocode, const char *fromcode)
+{
+  /* Normalize the name.  We remove all characters beside alpha-numeric,
+     '_', '-', '/', '.', and ':'.  */
+  size_t tocode_len = strlen (tocode) + 3;
+  char *tocode_conv;
+  bool tocode_usealloca = __libc_use_alloca (tocode_len);
+  if (tocode_usealloca)
+    tocode_conv = (char *) alloca (tocode_len);
+  else
+    {
+      tocode_conv = (char *) malloc (tocode_len);
+      if (tocode_conv == NULL)
+	return (iconv_t) -1;
+    }
+  strip (tocode_conv, tocode);
+  tocode = (tocode_conv[2] == '\0' && tocode[0] != '\0'
+	    ? upstr (tocode_conv, tocode) : tocode_conv);
+
+  size_t fromcode_len = strlen (fromcode) + 3;
+  char *fromcode_conv;
+  bool fromcode_usealloca = __libc_use_alloca (fromcode_len);
+  if (fromcode_usealloca)
+    fromcode_conv = (char *) alloca (fromcode_len);
+  else
+    {
+      fromcode_conv = (char *) malloc (fromcode_len);
+      if (fromcode_conv == NULL)
+	{
+	  if (! tocode_usealloca)
+	    free (tocode_conv);
+	  return (iconv_t) -1;
+	}
+    }
+  strip (fromcode_conv, fromcode);
+  fromcode = (fromcode_conv[2] == '\0' && fromcode[0] != '\0'
+	      ? upstr (fromcode_conv, fromcode) : fromcode_conv);
+
+  __gconv_t cd;
+  int res = __gconv_open (tocode, fromcode, &cd, 0);
+
+  if (! fromcode_usealloca)
+    free (fromcode_conv);
+  if (! tocode_usealloca)
+    free (tocode_conv);
+
+  if (__builtin_expect (res, __GCONV_OK) != __GCONV_OK)
+    {
+      /* We must set the error number according to the specs.  */
+      if (res == __GCONV_NOCONV || res == __GCONV_NODB)
+	__set_errno (EINVAL);
+
+      cd = (iconv_t) -1;
+    }
+
+  return (iconv_t) cd;
+}
diff --git a/REORG.TODO/iconv/iconv_prog.c b/REORG.TODO/iconv/iconv_prog.c
new file mode 100644
index 0000000000..1397d2e9bd
--- /dev/null
+++ b/REORG.TODO/iconv/iconv_prog.c
@@ -0,0 +1,803 @@
+/* Convert text in given files from the specified from-set to the to-set.
+   Copyright (C) 1998-2017 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+   Contributed by Ulrich Drepper <drepper@cygnus.com>, 1998.
+
+   This program is free software; you can redistribute it and/or modify
+   it under the terms of the GNU General Public License as published
+   by the Free Software Foundation; version 2 of the License, or
+   (at your option) any later version.
+
+   This program 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 General Public License for more details.
+
+   You should have received a copy of the GNU General Public License
+   along with this program; if not, see <http://www.gnu.org/licenses/>.  */
+
+#include <argp.h>
+#include <assert.h>
+#include <ctype.h>
+#include <errno.h>
+#include <error.h>
+#include <fcntl.h>
+#include <iconv.h>
+#include <langinfo.h>
+#include <locale.h>
+#include <search.h>
+#include <stdbool.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+#include <libintl.h>
+#ifdef _POSIX_MAPPED_FILES
+# include <sys/mman.h>
+#endif
+#include <charmap.h>
+#include <gconv_int.h>
+#include "iconv_prog.h"
+#include "iconvconfig.h"
+
+/* Get libc version number.  */
+#include "../version.h"
+
+#define PACKAGE _libc_intl_domainname
+
+
+/* Name and version of program.  */
+static void print_version (FILE *stream, struct argp_state *state);
+void (*argp_program_version_hook) (FILE *, struct argp_state *) = print_version;
+
+#define OPT_VERBOSE	1000
+#define OPT_LIST	'l'
+
+/* Definitions of arguments for argp functions.  */
+static const struct argp_option options[] =
+{
+  { NULL, 0, NULL, 0, N_("Input/Output format specification:") },
+  { "from-code", 'f', N_("NAME"), 0, N_("encoding of original text") },
+  { "to-code", 't', N_("NAME"), 0, N_("encoding for output") },
+  { NULL, 0, NULL, 0, N_("Information:") },
+  { "list", 'l', NULL, 0, N_("list all known coded character sets") },
+  { NULL, 0, NULL, 0, N_("Output control:") },
+  { NULL, 'c', NULL, 0, N_("omit invalid characters from output") },
+  { "output", 'o', N_("FILE"), 0, N_("output file") },
+  { "silent", 's', NULL, 0, N_("suppress warnings") },
+  { "verbose", OPT_VERBOSE, NULL, 0, N_("print progress information") },
+  { NULL, 0, NULL, 0, NULL }
+};
+
+/* Short description of program.  */
+static const char doc[] = N_("\
+Convert encoding of given files from one encoding to another.");
+
+/* Strings for arguments in help texts.  */
+static const char args_doc[] = N_("[FILE...]");
+
+/* Prototype for option handler.  */
+static error_t parse_opt (int key, char *arg, struct argp_state *state);
+
+/* Function to print some extra text in the help message.  */
+static char *more_help (int key, const char *text, void *input);
+
+/* Data structure to communicate with argp functions.  */
+static struct argp argp =
+{
+  options, parse_opt, args_doc, doc, NULL, more_help
+};
+
+/* Code sets to convert from and to respectively.  An empty string as the
+   default causes the 'iconv_open' function to look up the charset of the
+   currently selected locale and use it.  */
+static const char *from_code = "";
+static const char *to_code = "";
+
+/* File to write output to.  If NULL write to stdout.  */
+static const char *output_file;
+
+/* Nonzero if verbose ouput is wanted.  */
+int verbose;
+
+/* Nonzero if list of all coded character sets is wanted.  */
+static int list;
+
+/* If nonzero omit invalid character from output.  */
+int omit_invalid;
+
+/* Prototypes for the functions doing the actual work.  */
+static int process_block (iconv_t cd, char *addr, size_t len, FILE **output,
+			  const char *output_file);
+static int process_fd (iconv_t cd, int fd, FILE **output,
+		       const char *output_file);
+static int process_file (iconv_t cd, FILE *input, FILE **output,
+			 const char *output_file);
+static void print_known_names (void) internal_function;
+
+
+int
+main (int argc, char *argv[])
+{
+  int status = EXIT_SUCCESS;
+  int remaining;
+  iconv_t cd;
+  const char *orig_to_code;
+  struct charmap_t *from_charmap = NULL;
+  struct charmap_t *to_charmap = NULL;
+
+  /* Set locale via LC_ALL.  */
+  setlocale (LC_ALL, "");
+
+  /* Set the text message domain.  */
+  textdomain (_libc_intl_domainname);
+
+  /* Parse and process arguments.  */
+  argp_parse (&argp, argc, argv, 0, &remaining, NULL);
+
+  /* List all coded character sets if wanted.  */
+  if (list)
+    {
+      print_known_names ();
+      exit (EXIT_SUCCESS);
+    }
+
+  /* If we have to ignore errors make sure we use the appropriate name for
+     the to-character-set.  */
+  orig_to_code = to_code;
+  if (omit_invalid)
+    {
+      const char *errhand = strchrnul (to_code, '/');
+      int nslash = 2;
+      char *newp;
+      char *cp;
+
+      if (*errhand == '/')
+	{
+	  --nslash;
+	  errhand = strchrnul (errhand + 1, '/');
+
+	  if (*errhand == '/')
+	    {
+	      --nslash;
+	      errhand = strchr (errhand, '\0');
+	    }
+	}
+
+      newp = (char *) alloca (errhand - to_code + nslash + 7 + 1);
+      cp = mempcpy (newp, to_code, errhand - to_code);
+      while (nslash-- > 0)
+	*cp++ = '/';
+      if (cp[-1] != '/')
+	*cp++ = ',';
+      memcpy (cp, "IGNORE", sizeof ("IGNORE"));
+
+      to_code = newp;
+    }
+
+  /* POSIX 1003.2b introduces a silly thing: the arguments to -t anf -f
+     can be file names of charmaps.  In this case iconv will have to read
+     those charmaps and use them to do the conversion.  But there are
+     holes in the specification.  There is nothing said that if -f is a
+     charmap filename that -t must be, too.  And vice versa.  There is
+     also no word about the symbolic names used.  What if they don't
+     match?  */
+  if (strchr (from_code, '/') != NULL)
+    /* The from-name might be a charmap file name.  Try reading the
+       file.  */
+    from_charmap = charmap_read (from_code, /*0, 1*/1, 0, 0, 0);
+
+  if (strchr (orig_to_code, '/') != NULL)
+    /* The to-name might be a charmap file name.  Try reading the
+       file.  */
+    to_charmap = charmap_read (orig_to_code, /*0, 1,*/1, 0, 0, 0);
+
+
+  /* At this point we have to handle two cases.  The first one is
+     where a charmap is used for the from- or to-charset, or both.  We
+     handle this special since it is very different from the sane way of
+     doing things.  The other case allows converting using the iconv()
+     function.  */
+  if (from_charmap != NULL || to_charmap != NULL)
+    /* Construct the conversion table and do the conversion.  */
+    status = charmap_conversion (from_code, from_charmap, to_code, to_charmap,
+				 argc, remaining, argv, output_file);
+  else
+    {
+      /* Let's see whether we have these coded character sets.  */
+      cd = iconv_open (to_code, from_code);
+      if (cd == (iconv_t) -1)
+	{
+	  if (errno == EINVAL)
+	    {
+	      /* Try to be nice with the user and tell her which of the
+		 two encoding names is wrong.  This is possible because
+		 all supported encodings can be converted from/to Unicode,
+		 in other words, because the graph of encodings is
+		 connected.  */
+	      bool from_wrong =
+		(iconv_open ("UTF-8", from_code) == (iconv_t) -1
+		 && errno == EINVAL);
+	      bool to_wrong =
+		(iconv_open (to_code, "UTF-8") == (iconv_t) -1
+		 && errno == EINVAL);
+	      const char *from_pretty =
+		(from_code[0] ? from_code : nl_langinfo (CODESET));
+	      const char *to_pretty =
+		(orig_to_code[0] ? orig_to_code : nl_langinfo (CODESET));
+
+	      if (from_wrong)
+		{
+		  if (to_wrong)
+		    error (0, 0,
+			   _("\
+conversions from `%s' and to `%s' are not supported"),
+			   from_pretty, to_pretty);
+		  else
+		    error (0, 0,
+			   _("conversion from `%s' is not supported"),
+			   from_pretty);
+		}
+	      else
+		{
+		  if (to_wrong)
+		    error (0, 0,
+			   _("conversion to `%s' is not supported"),
+			   to_pretty);
+		  else
+		    error (0, 0,
+			   _("conversion from `%s' to `%s' is not supported"),
+			   from_pretty, to_pretty);
+		}
+
+	      argp_help (&argp, stderr, ARGP_HELP_SEE,
+			 program_invocation_short_name);
+	      exit (1);
+	    }
+	  else
+	    error (EXIT_FAILURE, errno,
+		   _("failed to start conversion processing"));
+	}
+
+      /* The output file.  Will be opened when we are ready to produce
+	 output.  */
+      FILE *output = NULL;
+
+      /* Now process the remaining files.  Write them to stdout or the file
+	 specified with the `-o' parameter.  If we have no file given as
+	 the parameter process all from stdin.  */
+      if (remaining == argc)
+	{
+	  if (process_file (cd, stdin, &output, output_file) != 0)
+	    status = EXIT_FAILURE;
+	}
+      else
+	do
+	  {
+#ifdef _POSIX_MAPPED_FILES
+	    struct stat64 st;
+	    char *addr;
+#endif
+	    int fd, ret;
+
+	    if (verbose)
+	      fprintf (stderr, "%s:\n", argv[remaining]);
+	    if (strcmp (argv[remaining], "-") == 0)
+	      fd = 0;
+	    else
+	      {
+		fd = open (argv[remaining], O_RDONLY);
+
+		if (fd == -1)
+		  {
+		    error (0, errno, _("cannot open input file `%s'"),
+			   argv[remaining]);
+		    status = EXIT_FAILURE;
+		    continue;
+		  }
+	      }
+
+#ifdef _POSIX_MAPPED_FILES
+	    /* We have possibilities for reading the input file.  First try
+	       to mmap() it since this will provide the fastest solution.  */
+	    if (fstat64 (fd, &st) == 0
+		&& ((addr = mmap (NULL, st.st_size, PROT_READ, MAP_PRIVATE,
+				  fd, 0)) != MAP_FAILED))
+	      {
+		/* Yes, we can use mmap().  The descriptor is not needed
+		   anymore.  */
+		if (close (fd) != 0)
+		  error (EXIT_FAILURE, errno,
+			 _("error while closing input `%s'"),
+			 argv[remaining]);
+
+		ret = process_block (cd, addr, st.st_size, &output,
+				     output_file);
+
+		/* We don't need the input data anymore.  */
+		munmap ((void *) addr, st.st_size);
+
+		if (ret != 0)
+		  {
+		    status = EXIT_FAILURE;
+
+		    if (ret < 0)
+		      /* We cannot go on with producing output since it might
+			 lead to problem because the last output might leave
+			 the output stream in an undefined state.  */
+		      break;
+		  }
+	      }
+	    else
+#endif	/* _POSIX_MAPPED_FILES */
+	      {
+		/* Read the file in pieces.  */
+		ret = process_fd (cd, fd, &output, output_file);
+
+		/* Now close the file.  */
+		close (fd);
+
+		if (ret != 0)
+		  {
+		    /* Something went wrong.  */
+		    status = EXIT_FAILURE;
+
+		    if (ret < 0)
+		      /* We cannot go on with producing output since it might
+			 lead to problem because the last output might leave
+			 the output stream in an undefined state.  */
+		      break;
+		  }
+	      }
+	  }
+	while (++remaining < argc);
+
+      /* Close the output file now.  */
+      if (output != NULL && fclose (output))
+	error (EXIT_FAILURE, errno, _("error while closing output file"));
+    }
+
+  return status;
+}
+
+
+/* Handle program arguments.  */
+static error_t
+parse_opt (int key, char *arg, struct argp_state *state)
+{
+  switch (key)
+    {
+    case 'f':
+      from_code = arg;
+      break;
+    case 't':
+      to_code = arg;
+      break;
+    case 'o':
+      output_file = arg;
+      break;
+    case 's':
+      /* Nothing, for now at least.  We are not giving out any information
+	 about missing character or so.  */
+      break;
+    case 'c':
+      /* Omit invalid characters from output.  */
+      omit_invalid = 1;
+      break;
+    case OPT_VERBOSE:
+      verbose = 1;
+      break;
+    case OPT_LIST:
+      list = 1;
+      break;
+    default:
+      return ARGP_ERR_UNKNOWN;
+    }
+  return 0;
+}
+
+
+static char *
+more_help (int key, const char *text, void *input)
+{
+  char *tp = NULL;
+  switch (key)
+    {
+    case ARGP_KEY_HELP_EXTRA:
+      /* We print some extra information.  */
+      if (asprintf (&tp, gettext ("\
+For bug reporting instructions, please see:\n\
+%s.\n"), REPORT_BUGS_TO) < 0)
+	return NULL;
+      return tp;
+    default:
+      break;
+    }
+  return (char *) text;
+}
+
+
+/* Print the version information.  */
+static void
+print_version (FILE *stream, struct argp_state *state)
+{
+  fprintf (stream, "iconv %s%s\n", PKGVERSION, VERSION);
+  fprintf (stream, gettext ("\
+Copyright (C) %s Free Software Foundation, Inc.\n\
+This is free software; see the source for copying conditions.  There is NO\n\
+warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.\n\
+"), "2017");
+  fprintf (stream, gettext ("Written by %s.\n"), "Ulrich Drepper");
+}
+
+
+static int
+write_output (const char *outbuf, const char *outptr, FILE **output,
+	      const char *output_file)
+{
+  /* We have something to write out.  */
+  int errno_save = errno;
+
+  if (*output == NULL)
+    {
+      /* Determine output file.  */
+      if (output_file != NULL && strcmp (output_file, "-") != 0)
+	{
+	  *output = fopen (output_file, "w");
+	  if (*output == NULL)
+	    error (EXIT_FAILURE, errno, _("cannot open output file"));
+	}
+      else
+	*output = stdout;
+    }
+
+  if (fwrite (outbuf, 1, outptr - outbuf, *output) < (size_t) (outptr - outbuf)
+      || ferror (*output))
+    {
+      /* Error occurred while printing the result.  */
+      error (0, 0, _("\
+conversion stopped due to problem in writing the output"));
+      return -1;
+    }
+
+  errno = errno_save;
+
+  return 0;
+}
+
+
+static int
+process_block (iconv_t cd, char *addr, size_t len, FILE **output,
+	       const char *output_file)
+{
+#define OUTBUF_SIZE	32768
+  const char *start = addr;
+  char outbuf[OUTBUF_SIZE];
+  char *outptr;
+  size_t outlen;
+  size_t n;
+  int ret = 0;
+
+  while (len > 0)
+    {
+      outptr = outbuf;
+      outlen = OUTBUF_SIZE;
+      n = iconv (cd, &addr, &len, &outptr, &outlen);
+
+      if (n == (size_t) -1 && omit_invalid && errno == EILSEQ)
+	{
+	  ret = 1;
+	  if (len == 0)
+	    n = 0;
+	  else
+	    errno = E2BIG;
+	}
+
+      if (outptr != outbuf)
+	{
+	  ret = write_output (outbuf, outptr, output, output_file);
+	  if (ret != 0)
+	    break;
+	}
+
+      if (n != (size_t) -1)
+	{
+	  /* All the input test is processed.  For state-dependent
+	     character sets we have to flush the state now.  */
+	  outptr = outbuf;
+	  outlen = OUTBUF_SIZE;
+	  n = iconv (cd, NULL, NULL, &outptr, &outlen);
+
+	  if (outptr != outbuf)
+	    {
+	      ret = write_output (outbuf, outptr, output, output_file);
+	      if (ret != 0)
+		break;
+	    }
+
+	  if (n != (size_t) -1)
+	    break;
+
+	  if (omit_invalid && errno == EILSEQ)
+	    {
+	      ret = 1;
+	      break;
+	    }
+	}
+
+      if (errno != E2BIG)
+	{
+	  /* iconv() ran into a problem.  */
+	  switch (errno)
+	    {
+	    case EILSEQ:
+	      if (! omit_invalid)
+		error (0, 0, _("illegal input sequence at position %ld"),
+		       (long int) (addr - start));
+	      break;
+	    case EINVAL:
+	      error (0, 0, _("\
+incomplete character or shift sequence at end of buffer"));
+	      break;
+	    case EBADF:
+	      error (0, 0, _("internal error (illegal descriptor)"));
+	      break;
+	    default:
+	      error (0, 0, _("unknown iconv() error %d"), errno);
+	      break;
+	    }
+
+	  return -1;
+	}
+    }
+
+  return ret;
+}
+
+
+static int
+process_fd (iconv_t cd, int fd, FILE **output, const char *output_file)
+{
+  /* we have a problem with reading from a desriptor since we must not
+     provide the iconv() function an incomplete character or shift
+     sequence at the end of the buffer.  Since we have to deal with
+     arbitrary encodings we must read the whole text in a buffer and
+     process it in one step.  */
+  static char *inbuf = NULL;
+  static size_t maxlen = 0;
+  char *inptr = NULL;
+  size_t actlen = 0;
+
+  while (actlen < maxlen)
+    {
+      ssize_t n = read (fd, inptr, maxlen - actlen);
+
+      if (n == 0)
+	/* No more text to read.  */
+	break;
+
+      if (n == -1)
+	{
+	  /* Error while reading.  */
+	  error (0, errno, _("error while reading the input"));
+	  return -1;
+	}
+
+      inptr += n;
+      actlen += n;
+    }
+
+  if (actlen == maxlen)
+    while (1)
+      {
+	ssize_t n;
+	char *new_inbuf;
+
+	/* Increase the buffer.  */
+	new_inbuf = (char *) realloc (inbuf, maxlen + 32768);
+	if (new_inbuf == NULL)
+	  {
+	    error (0, errno, _("unable to allocate buffer for input"));
+	    return -1;
+	  }
+	inbuf = new_inbuf;
+	maxlen += 32768;
+	inptr = inbuf + actlen;
+
+	do
+	  {
+	    n = read (fd, inptr, maxlen - actlen);
+
+	    if (n == 0)
+	      /* No more text to read.  */
+	      break;
+
+	    if (n == -1)
+	      {
+		/* Error while reading.  */
+		error (0, errno, _("error while reading the input"));
+		return -1;
+	      }
+
+	    inptr += n;
+	    actlen += n;
+	  }
+	while (actlen < maxlen);
+
+	if (n == 0)
+	  /* Break again so we leave both loops.  */
+	  break;
+      }
+
+  /* Now we have all the input in the buffer.  Process it in one run.  */
+  return process_block (cd, inbuf, actlen, output, output_file);
+}
+
+
+static int
+process_file (iconv_t cd, FILE *input, FILE **output, const char *output_file)
+{
+  /* This should be safe since we use this function only for `stdin' and
+     we haven't read anything so far.  */
+  return process_fd (cd, fileno (input), output, output_file);
+}
+
+
+/* Print all known character sets/encodings.  */
+static void *printlist;
+static size_t column;
+static int not_first;
+
+static void
+insert_print_list (const void *nodep, VISIT value, int level)
+{
+  if (value == leaf || value == postorder)
+    {
+      const struct gconv_alias *s = *(const struct gconv_alias **) nodep;
+      tsearch (s->fromname, &printlist, (__compar_fn_t) strverscmp);
+    }
+}
+
+static void
+do_print_human  (const void *nodep, VISIT value, int level)
+{
+  if (value == leaf || value == postorder)
+    {
+      const char *s = *(const char **) nodep;
+      size_t len = strlen (s);
+      size_t cnt;
+
+      while (len > 0 && s[len - 1] == '/')
+	--len;
+
+      for (cnt = 0; cnt < len; ++cnt)
+	if (isalnum (s[cnt]))
+	  break;
+      if (cnt == len)
+	return;
+
+      if (not_first)
+	{
+	  putchar (',');
+	  ++column;
+
+	  if (column > 2 && column + len > 77)
+	    {
+	      fputs ("\n  ", stdout);
+	      column = 2;
+	    }
+	  else
+	    {
+	      putchar (' ');
+	      ++column;
+	    }
+	}
+      else
+	not_first = 1;
+
+      fwrite (s, len, 1, stdout);
+      column += len;
+    }
+}
+
+static void
+do_print  (const void *nodep, VISIT value, int level)
+{
+  if (value == leaf || value == postorder)
+    {
+      const char *s = *(const char **) nodep;
+
+      puts (s);
+    }
+}
+
+static void
+internal_function
+add_known_names (struct gconv_module *node)
+{
+  if (node->left != NULL)
+    add_known_names (node->left);
+  if (node->right != NULL)
+    add_known_names (node->right);
+  do
+    {
+      if (strcmp (node->from_string, "INTERNAL") != 0)
+	tsearch (node->from_string, &printlist, (__compar_fn_t) strverscmp);
+      if (strcmp (node->to_string, "INTERNAL") != 0)
+	tsearch (node->to_string, &printlist, (__compar_fn_t) strverscmp);
+
+      node = node->same;
+    }
+  while (node != NULL);
+}
+
+
+static void
+insert_cache (void)
+{
+  const struct gconvcache_header *header;
+  const char *strtab;
+  const struct hash_entry *hashtab;
+  size_t cnt;
+
+  header = (const struct gconvcache_header *) __gconv_get_cache ();
+  strtab = (char *) header + header->string_offset;
+  hashtab = (struct hash_entry *) ((char *) header + header->hash_offset);
+
+  for (cnt = 0; cnt < header->hash_size; ++cnt)
+    if (hashtab[cnt].string_offset != 0)
+      {
+	const char *str = strtab + hashtab[cnt].string_offset;
+
+	if (strcmp (str, "INTERNAL") != 0)
+	  tsearch (str, &printlist, (__compar_fn_t) strverscmp);
+      }
+}
+
+
+static void
+internal_function
+print_known_names (void)
+{
+  iconv_t h;
+  void *cache;
+
+  /* We must initialize the internal databases first.  */
+  h = iconv_open ("L1", "L1");
+  iconv_close (h);
+
+  /* See whether we have a cache.  */
+  cache = __gconv_get_cache ();
+  if (cache != NULL)
+    /* Yep, use only this information.  */
+    insert_cache ();
+  else
+    {
+      struct gconv_module *modules;
+
+      /* No, then use the information read from the gconv-modules file.
+	 First add the aliases.  */
+      twalk (__gconv_get_alias_db (), insert_print_list);
+
+      /* Add the from- and to-names from the known modules.  */
+      modules = __gconv_get_modules_db ();
+      if (modules != NULL)
+	add_known_names (modules);
+    }
+
+  bool human_readable = isatty (fileno (stdout));
+
+  if (human_readable)
+    fputs (_("\
+The following list contains all the coded character sets known.  This does\n\
+not necessarily mean that all combinations of these names can be used for\n\
+the FROM and TO command line parameters.  One coded character set can be\n\
+listed with several different names (aliases).\n\n  "), stdout);
+
+  /* Now print the collected names.  */
+  column = 2;
+  twalk (printlist, human_readable ? do_print_human : do_print);
+
+  if (human_readable && column != 0)
+    puts ("");
+}
diff --git a/REORG.TODO/iconv/iconv_prog.h b/REORG.TODO/iconv/iconv_prog.h
new file mode 100644
index 0000000000..1571fc9181
--- /dev/null
+++ b/REORG.TODO/iconv/iconv_prog.h
@@ -0,0 +1,41 @@
+/* Copyright (C) 2001-2017 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+   Contributed by Ulrich Drepper <drepper@redhat.com>, 2001.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 2.1 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
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with the GNU C Library; if not, see
+   <http://www.gnu.org/licenses/>.  */
+
+#ifndef _ICONV_PROG_H
+#define _ICONV_PROG_H	1
+
+#include <stdio.h>
+#include <charmap.h>
+
+
+/* Nonzero if verbose ouput is wanted.  */
+extern int verbose;
+
+/* If nonzero omit invalid character from output.  */
+extern int omit_invalid;
+
+/* Perform the conversion using a charmap or two.  */
+extern int charmap_conversion (const char *from_code,
+			       struct charmap_t *from_charmap,
+			       const char *to_code,
+			       struct charmap_t *to_charmap,
+			       int argc, int remaining, char *argv[],
+			       const char *output_file);
+
+
+#endif	/* iconv_prog.h */
diff --git a/REORG.TODO/iconv/iconvconfig.c b/REORG.TODO/iconv/iconvconfig.c
new file mode 100644
index 0000000000..9be4111a42
--- /dev/null
+++ b/REORG.TODO/iconv/iconvconfig.c
@@ -0,0 +1,1245 @@
+/* Generate fastloading iconv module configuration files.
+   Copyright (C) 2000-2017 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+   Contributed by Ulrich Drepper <drepper@redhat.com>, 2000.
+
+   This program is free software; you can redistribute it and/or modify
+   it under the terms of the GNU General Public License as published
+   by the Free Software Foundation; version 2 of the License, or
+   (at your option) any later version.
+
+   This program 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 General Public License for more details.
+
+   You should have received a copy of the GNU General Public License
+   along with this program; if not, see <http://www.gnu.org/licenses/>.  */
+
+#include <argp.h>
+#include <assert.h>
+#include <error.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <libintl.h>
+#include <locale.h>
+#include <mcheck.h>
+#include <search.h>
+#include <stdint.h>
+#include <stdbool.h>
+#include <stdio.h>
+#include <stdio_ext.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+#include <sys/cdefs.h>
+#include <sys/uio.h>
+
+#include "iconvconfig.h"
+
+/* Get libc version number.  */
+#include "../version.h"
+
+#define PACKAGE _libc_intl_domainname
+
+
+/* The hashing function we use.  */
+#include "../intl/hash-string.h"
+
+
+/* Types used.  */
+struct module
+{
+  char *fromname;
+  struct Strent *fromname_strent;
+  char *filename;
+  struct Strent *filename_strent;
+  const char *directory;
+  struct Strent *directory_strent;
+  struct module *next;
+  int cost;
+  struct Strent *toname_strent;
+  char toname[0];
+};
+
+struct alias
+{
+  char *fromname;
+  struct Strent *froment;
+  struct module *module;
+  struct Strent *toent;
+  char toname[0];
+};
+
+struct name
+{
+  const char *name;
+  struct Strent *strent;
+  int module_idx;
+  uint32_t hashval;
+};
+
+struct name_info
+{
+  const char *canonical_name;
+  struct Strent *canonical_strent;
+
+  struct module *from_internal;
+  struct module *to_internal;
+
+  struct other_conv_list
+  {
+    int dest_idx;
+    struct other_conv
+    {
+      gidx_t module_idx;
+      struct module *module;
+      struct other_conv *next;
+    } other_conv;
+    struct other_conv_list *next;
+  } *other_conv_list;
+};
+
+
+/* Name and version of program.  */
+static void print_version (FILE *stream, struct argp_state *state);
+void (*argp_program_version_hook) (FILE *, struct argp_state *) = print_version;
+
+/* Short description of program.  */
+static const char doc[] = N_("\
+Create fastloading iconv module configuration file.");
+
+/* Strings for arguments in help texts.  */
+static const char args_doc[] = N_("[DIR...]");
+
+/* Prototype for option handler.  */
+static error_t parse_opt (int key, char *arg, struct argp_state *state);
+
+/* Function to print some extra text in the help message.  */
+static char *more_help (int key, const char *text, void *input);
+
+/* Definitions of arguments for argp functions.  */
+#define OPT_PREFIX 300
+#define OPT_NOSTDLIB 301
+static const struct argp_option options[] =
+{
+  { "prefix", OPT_PREFIX, N_("PATH"), 0,
+    N_("Prefix used for all file accesses") },
+  { "output", 'o', N_("FILE"), 0, N_("\
+Put output in FILE instead of installed location\
+ (--prefix does not apply to FILE)") },
+  { "nostdlib", OPT_NOSTDLIB, NULL, 0,
+    N_("Do not search standard directories, only those on the command line") },
+  { NULL, 0, NULL, 0, NULL }
+};
+
+/* Data structure to communicate with argp functions.  */
+static struct argp argp =
+{
+  options, parse_opt, args_doc, doc, NULL, more_help
+};
+
+
+/* The function doing the actual work.  */
+static int handle_dir (const char *dir);
+
+/* Add all known builtin conversions and aliases.  */
+static void add_builtins (void);
+
+/* Create list of all aliases without circular aliases.  */
+static void get_aliases (void);
+
+/* Create list of all modules.  */
+static void get_modules (void);
+
+/* Get list of all the names and thereby indexing them.  */
+static void generate_name_list (void);
+
+/* Collect information about all the names.  */
+static void generate_name_info (void);
+
+/* Write the output file.  */
+static int write_output (void);
+
+
+/* Prefix to be used for all file accesses.  */
+static const char *prefix = "";
+/* Its length.  */
+static size_t prefix_len;
+
+/* Directory to place output file in.  */
+static const char *output_file;
+/* Its length.  */
+static size_t output_file_len;
+
+/* If true, omit the GCONV_PATH directories and require some arguments.  */
+static bool nostdlib;
+
+/* Search tree of the modules we know.  */
+static void *modules;
+
+/* Search tree of the aliases we know.  */
+static void *aliases;
+
+/* Search tree for name to index mapping.  */
+static void *names;
+
+/* Number of names we know about.  */
+static int nnames;
+
+/* List of all aliases.  */
+static struct alias **alias_list;
+static size_t nalias_list;
+static size_t nalias_list_max;
+
+/* List of all modules.  */
+static struct module **module_list;
+static size_t nmodule_list;
+static size_t nmodule_list_max;
+
+/* Names and information about them.  */
+static struct name_info *name_info;
+static size_t nname_info;
+
+/* Number of translations not from or to INTERNAL.  */
+static size_t nextra_modules;
+
+
+/* Names and aliases for the builtin transformations.  */
+static struct
+{
+  const char *from;
+  const char *to;
+} builtin_alias[] =
+  {
+#define BUILTIN_ALIAS(alias, real) \
+    { .from = alias, .to = real },
+#define BUILTIN_TRANSFORMATION(From, To, Cost, Name, Fct, BtowcFct, \
+			       MinF, MaxF, MinT, MaxT)
+#include <gconv_builtin.h>
+  };
+#undef BUILTIN_ALIAS
+#undef BUILTIN_TRANSFORMATION
+#define nbuiltin_alias (sizeof (builtin_alias) / sizeof (builtin_alias[0]))
+
+static struct
+{
+  const char *from;
+  const char *to;
+  const char *module;
+  int cost;
+} builtin_trans[] =
+  {
+#define BUILTIN_ALIAS(alias, real)
+#define BUILTIN_TRANSFORMATION(From, To, Cost, Name, Fct, BtowcFct, \
+			       MinF, MaxF, MinT, MaxT) \
+    { .from = From, .to = To, .module = Name, .cost = Cost },
+#include <gconv_builtin.h>
+  };
+#undef BUILTIN_ALIAS
+#undef BUILTIN_TRANSFORMATION
+#define nbuiltin_trans (sizeof (builtin_trans) / sizeof (builtin_trans[0]))
+
+
+/* Filename extension for the modules.  */
+#ifndef MODULE_EXT
+# define MODULE_EXT ".so"
+#endif
+static const char gconv_module_ext[] = MODULE_EXT;
+
+
+#include <programs/xmalloc.h>
+
+
+/* C string table handling.  */
+struct Strtab;
+struct Strent;
+
+/* Create new C string table object in memory.  */
+extern struct Strtab *strtabinit (void);
+
+/* Free resources allocated for C string table ST.  */
+extern void strtabfree (struct Strtab *st);
+
+/* Add string STR (length LEN is != 0) to C string table ST.  */
+extern struct Strent *strtabadd (struct Strtab *st, const char *str,
+				 size_t len);
+
+/* Finalize string table ST and store size in *SIZE and return a pointer.  */
+extern void *strtabfinalize (struct Strtab *st, size_t *size);
+
+/* Get offset in string table for string associated with SE.  */
+extern size_t strtaboffset (struct Strent *se);
+
+/* String table we construct.  */
+static struct Strtab *strtab;
+
+
+
+int
+main (int argc, char *argv[])
+{
+  int remaining;
+  int status = 0;
+
+  /* Enable memory use testing.  */
+  /* mcheck_pedantic (NULL); */
+  mtrace ();
+
+  /* Set locale via LC_ALL.  */
+  setlocale (LC_ALL, "");
+
+  /* Set the text message domain.  */
+  textdomain (_libc_intl_domainname);
+
+  /* Parse and process arguments.  */
+  argp_parse (&argp, argc, argv, 0, &remaining, NULL);
+
+  if (nostdlib && remaining == argc)
+    error (2, 0, _("Directory arguments required when using --nostdlib"));
+
+  /* Initialize the string table.  */
+  strtab = strtabinit ();
+
+  /* Handle all directories mentioned.  */
+  while (remaining < argc)
+    status |= handle_dir (argv[remaining++]);
+
+  if (! nostdlib)
+    {
+      /* In any case also handle the standard directory.  */
+      char *path = strdupa (GCONV_PATH), *tp = strsep (&path, ":");
+      while (tp != NULL)
+	{
+	  status |= handle_dir (tp);
+
+	  tp = strsep (&path, ":");
+	}
+    }
+
+  /* Add the builtin transformations and aliases without overwriting
+     anything.  */
+  add_builtins ();
+
+  /* Store aliases in an array.  */
+  get_aliases ();
+
+  /* Get list of all modules.  */
+  get_modules ();
+
+  /* Generate list of all the names we know to handle in some way.  */
+  generate_name_list ();
+
+  /* Now we know all the names we will handle, collect information
+     about them.  */
+  generate_name_info ();
+
+  /* Write the output file, but only if we haven't seen any error.  */
+  if (status == 0)
+    status = write_output ();
+  else
+    error (1, 0, _("no output file produced because warnings were issued"));
+
+  return status;
+}
+
+
+/* Handle program arguments.  */
+static error_t
+parse_opt (int key, char *arg, struct argp_state *state)
+{
+  switch (key)
+    {
+    case OPT_PREFIX:
+      prefix = arg;
+      prefix_len = strlen (prefix);
+      break;
+    case 'o':
+      output_file = arg;
+      output_file_len = strlen (output_file);
+      break;
+    case OPT_NOSTDLIB:
+      nostdlib = true;
+      break;
+    default:
+      return ARGP_ERR_UNKNOWN;
+    }
+  return 0;
+}
+
+
+static char *
+more_help (int key, const char *text, void *input)
+{
+  char *tp = NULL;
+  switch (key)
+    {
+    case ARGP_KEY_HELP_EXTRA:
+      /* We print some extra information.  */
+      if (asprintf (&tp, gettext ("\
+For bug reporting instructions, please see:\n\
+%s.\n"), REPORT_BUGS_TO) < 0)
+	return NULL;
+      return tp;
+    default:
+      break;
+    }
+  return (char *) text;
+}
+
+
+/* Print the version information.  */
+static void
+print_version (FILE *stream, struct argp_state *state)
+{
+  fprintf (stream, "iconvconfig %s%s\n", PKGVERSION, VERSION);
+  fprintf (stream, gettext ("\
+Copyright (C) %s Free Software Foundation, Inc.\n\
+This is free software; see the source for copying conditions.  There is NO\n\
+warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.\n\
+"), "2017");
+  fprintf (stream, gettext ("Written by %s.\n"), "Ulrich Drepper");
+}
+
+
+static int
+alias_compare (const void *p1, const void *p2)
+{
+  const struct alias *a1 = (const struct alias *) p1;
+  const struct alias *a2 = (const struct alias *) p2;
+
+  return strcmp (a1->fromname, a2->fromname);
+}
+
+
+static void
+new_alias (const char *fromname, size_t fromlen, const char *toname,
+	   size_t tolen)
+{
+  struct alias *newp;
+  void **inserted;
+
+  newp = (struct alias *) xmalloc (sizeof (struct alias) + fromlen + tolen);
+
+  newp->fromname = mempcpy (newp->toname, toname, tolen);
+  memcpy (newp->fromname, fromname, fromlen);
+  newp->module = NULL;
+
+  inserted = (void **) tsearch (newp, &aliases, alias_compare);
+  if (inserted == NULL)
+    error (EXIT_FAILURE, errno, gettext ("while inserting in search tree"));
+  if (*inserted != newp)
+    /* Something went wrong, free this entry.  */
+    free (newp);
+  else
+    {
+      newp->froment = strtabadd (strtab, newp->fromname, fromlen);
+      newp->toent = strtabadd (strtab, newp->toname, tolen);
+    }
+}
+
+
+/* Add new alias.  */
+static void
+add_alias (char *rp)
+{
+  /* We now expect two more string.  The strings are normalized
+     (converted to UPPER case) and strored in the alias database.  */
+  char *from;
+  char *to;
+  char *wp;
+
+  while (isspace (*rp))
+    ++rp;
+  from = wp = rp;
+  while (*rp != '\0' && !isspace (*rp))
+    *wp++ = toupper (*rp++);
+  if (*rp == '\0')
+    /* There is no `to' string on the line.  Ignore it.  */
+    return;
+  *wp++ = '\0';
+  to = ++rp;
+  while (isspace (*rp))
+    ++rp;
+  while (*rp != '\0' && !isspace (*rp))
+    *wp++ = toupper (*rp++);
+  if (to == wp)
+    /* No `to' string, ignore the line.  */
+    return;
+  *wp++ = '\0';
+
+  assert (strlen (from) + 1 == (size_t) (to - from));
+  assert (strlen (to) + 1 == (size_t) (wp - to));
+
+  new_alias (from, to - from, to, wp - to);
+}
+
+
+static void
+append_alias (const void *nodep, VISIT value, int level)
+{
+  if (value != leaf && value != postorder)
+    return;
+
+  if (nalias_list_max == nalias_list)
+    {
+      nalias_list_max += 50;
+      alias_list = (struct alias **) xrealloc (alias_list,
+					       (nalias_list_max
+						* sizeof (struct alias *)));
+    }
+
+  alias_list[nalias_list++] = *(struct alias **) nodep;
+}
+
+
+static void
+get_aliases (void)
+{
+  twalk (aliases, append_alias);
+}
+
+
+static int
+module_compare (const void *p1, const void *p2)
+{
+  const struct module *m1 = (const struct module *) p1;
+  const struct module *m2 = (const struct module *) p2;
+  int result;
+
+  result = strcmp (m1->fromname, m2->fromname);
+  if (result == 0)
+    result = strcmp (m1->toname, m2->toname);
+
+  return result;
+}
+
+
+/* Create new module record.  */
+static void
+new_module (const char *fromname, size_t fromlen, const char *toname,
+	    size_t tolen, const char *directory,
+	    const char *filename, size_t filelen, int cost, size_t need_ext)
+{
+  struct module *new_module;
+  size_t dirlen = strlen (directory) + 1;
+  char *tmp;
+  void **inserted;
+
+  new_module = (struct module *) xmalloc (sizeof (struct module)
+					  + fromlen + tolen + filelen
+					  + need_ext);
+
+  new_module->fromname = mempcpy (new_module->toname, toname, tolen);
+
+  new_module->filename = mempcpy (new_module->fromname, fromname, fromlen);
+
+  new_module->cost = cost;
+  new_module->next = NULL;
+
+  tmp = mempcpy (new_module->filename, filename, filelen);
+  if (need_ext)
+    {
+      memcpy (tmp - 1, gconv_module_ext, need_ext + 1);
+      filelen += need_ext;
+    }
+  new_module->directory = directory;
+
+  /* Now insert the new module data structure in our search tree.  */
+  inserted = (void **) tsearch (new_module, &modules, module_compare);
+  if (inserted == NULL)
+    error (EXIT_FAILURE, errno, "while inserting in search tree");
+  if (*inserted != new_module)
+    free (new_module);
+  else
+    {
+      new_module->fromname_strent = strtabadd (strtab, new_module->fromname,
+					       fromlen);
+      new_module->toname_strent = strtabadd (strtab, new_module->toname,
+					     tolen);
+      new_module->filename_strent = strtabadd (strtab, new_module->filename,
+					       filelen);
+      new_module->directory_strent = strtabadd (strtab, directory, dirlen);
+    }
+}
+
+
+/* Add new module.  */
+static void
+internal_function
+add_module (char *rp, const char *directory)
+{
+  /* We expect now
+     1. `from' name
+     2. `to' name
+     3. filename of the module
+     4. an optional cost value
+  */
+  char *from;
+  char *to;
+  char *module;
+  char *wp;
+  int need_ext;
+  int cost;
+
+  while (isspace (*rp))
+    ++rp;
+  from = rp;
+  while (*rp != '\0' && !isspace (*rp))
+    {
+      *rp = toupper (*rp);
+      ++rp;
+    }
+  if (*rp == '\0')
+    return;
+  *rp++ = '\0';
+  to = wp = rp;
+  while (isspace (*rp))
+    ++rp;
+  while (*rp != '\0' && !isspace (*rp))
+    *wp++ = toupper (*rp++);
+  if (*rp == '\0')
+    return;
+  *wp++ = '\0';
+  do
+    ++rp;
+  while (isspace (*rp));
+  module = wp;
+  while (*rp != '\0' && !isspace (*rp))
+    *wp++ = *rp++;
+  if (*rp == '\0')
+    {
+      /* There is no cost, use one by default.  */
+      *wp++ = '\0';
+      cost = 1;
+    }
+  else
+    {
+      /* There might be a cost value.  */
+      char *endp;
+
+      *wp++ = '\0';
+      cost = strtol (rp, &endp, 10);
+      if (rp == endp || cost < 1)
+	/* No useful information.  */
+	cost = 1;
+    }
+
+  if (module[0] == '\0')
+    /* No module name given.  */
+    return;
+
+  /* See whether we must add the ending.  */
+  need_ext = 0;
+  if ((size_t) (wp - module) < sizeof (gconv_module_ext)
+      || memcmp (wp - sizeof (gconv_module_ext), gconv_module_ext,
+		 sizeof (gconv_module_ext)) != 0)
+    /* We must add the module extension.  */
+    need_ext = sizeof (gconv_module_ext) - 1;
+
+  assert (strlen (from) + 1 == (size_t) (to - from));
+  assert (strlen (to) + 1 == (size_t) (module - to));
+  assert (strlen (module) + 1 == (size_t) (wp - module));
+
+  new_module (from, to - from, to, module - to, directory, module, wp - module,
+	      cost, need_ext);
+}
+
+
+/* Read the config file and add the data for this directory to that.  */
+static int
+handle_dir (const char *dir)
+{
+  char *cp;
+  FILE *fp;
+  char *line = NULL;
+  size_t linelen = 0;
+  size_t dirlen = strlen (dir);
+
+  if (dir[dirlen - 1] != '/')
+    {
+      char *newp = (char *) xmalloc (dirlen + 2);
+      dir = memcpy (newp, dir, dirlen);
+      newp[dirlen++] = '/';
+      newp[dirlen] = '\0';
+    }
+
+  char infile[prefix_len + dirlen + sizeof "gconv-modules"];
+  cp = infile;
+  if (dir[0] == '/')
+    cp = mempcpy (cp, prefix, prefix_len);
+  strcpy (mempcpy (cp, dir, dirlen), "gconv-modules");
+
+  fp = fopen (infile, "r");
+  if (fp == NULL)
+    {
+      error (0, errno, "cannot open `%s'", infile);
+      return 1;
+    }
+
+  /* No threads present.  */
+  __fsetlocking (fp, FSETLOCKING_BYCALLER);
+
+  while (!feof_unlocked (fp))
+    {
+      char *rp, *endp, *word;
+      ssize_t n = __getdelim (&line, &linelen, '\n', fp);
+
+      if (n < 0)
+	/* An error occurred.  */
+	break;
+
+      rp = line;
+      /* Terminate the line (excluding comments or newline) with a NUL
+	 byte to simplify the following code.  */
+      endp = strchr (rp, '#');
+      if (endp != NULL)
+	*endp = '\0';
+      else
+	if (rp[n - 1] == '\n')
+	  rp[n - 1] = '\0';
+
+      while (isspace (*rp))
+	++rp;
+
+      /* If this is an empty line go on with the next one.  */
+      if (rp == endp)
+	continue;
+
+      word = rp;
+      while (*rp != '\0' && !isspace (*rp))
+	++rp;
+
+      if (rp - word == sizeof ("alias") - 1
+	  && memcmp (word, "alias", sizeof ("alias") - 1) == 0)
+	add_alias (rp);
+      else if (rp - word == sizeof ("module") - 1
+	       && memcmp (word, "module", sizeof ("module") - 1) == 0)
+	add_module (rp, dir);
+      /* else */
+	/* Otherwise ignore the line.  */
+    }
+
+  free (line);
+
+  fclose (fp);
+
+  return 0;
+}
+
+
+static void
+append_module (const void *nodep, VISIT value, int level)
+{
+  struct module *mo;
+
+  if (value != leaf && value != postorder)
+    return;
+
+  mo = *(struct module **) nodep;
+
+  if (nmodule_list > 0
+      && strcmp (module_list[nmodule_list - 1]->fromname, mo->fromname) == 0)
+    {
+      /* Same name.  */
+      mo->next = module_list[nmodule_list - 1];
+      module_list[nmodule_list - 1] = mo;
+
+      return;
+    }
+
+  if (nmodule_list_max == nmodule_list)
+    {
+      nmodule_list_max += 50;
+      module_list = (struct module **) xrealloc (module_list,
+						 (nmodule_list_max
+						  * sizeof (struct module *)));
+    }
+
+  module_list[nmodule_list++] = mo;
+}
+
+
+static void
+get_modules (void)
+{
+  twalk (modules, append_module);
+}
+
+
+static void
+add_builtins (void)
+{
+  size_t cnt;
+
+  /* Add all aliases.  */
+  for (cnt = 0; cnt < nbuiltin_alias; ++cnt)
+    new_alias (builtin_alias[cnt].from,
+	       strlen (builtin_alias[cnt].from) + 1,
+	       builtin_alias[cnt].to,
+	       strlen (builtin_alias[cnt].to) + 1);
+
+  /* add the builtin transformations.  */
+  for (cnt = 0; cnt < nbuiltin_trans; ++cnt)
+    new_module (builtin_trans[cnt].from,
+		strlen (builtin_trans[cnt].from) + 1,
+		builtin_trans[cnt].to,
+		strlen (builtin_trans[cnt].to) + 1,
+		"", builtin_trans[cnt].module,
+		strlen (builtin_trans[cnt].module) + 1,
+		builtin_trans[cnt].cost, 0);
+}
+
+
+static int
+name_compare (const void *p1, const void *p2)
+{
+  const struct name *n1 = (const struct name *) p1;
+  const struct name *n2 = (const struct name *) p2;
+
+  return strcmp (n1->name, n2->name);
+}
+
+
+static struct name *
+new_name (const char *str, struct Strent *strent)
+{
+  struct name *newp = (struct name *) xmalloc (sizeof (struct name));
+
+  newp->name = str;
+  newp->strent = strent;
+  newp->module_idx = -1;
+  newp->hashval = __hash_string (str);
+
+  ++nnames;
+
+  return newp;
+}
+
+
+static void
+generate_name_list (void)
+{
+  size_t i;
+
+  /* A name we always need.  */
+  tsearch (new_name ("INTERNAL", strtabadd (strtab, "INTERNAL",
+					    sizeof ("INTERNAL"))),
+	   &names, name_compare);
+
+  for (i = 0; i < nmodule_list; ++i)
+    {
+      struct module *runp;
+
+      if (strcmp (module_list[i]->fromname, "INTERNAL") != 0)
+	tsearch (new_name (module_list[i]->fromname,
+			   module_list[i]->fromname_strent),
+		 &names, name_compare);
+
+      for (runp = module_list[i]; runp != NULL; runp = runp->next)
+	if (strcmp (runp->toname, "INTERNAL") != 0)
+	  tsearch (new_name (runp->toname, runp->toname_strent),
+		   &names, name_compare);
+    }
+}
+
+
+static int
+name_to_module_idx (const char *name, int add)
+{
+  struct name **res;
+  struct name fake_name = { .name = name };
+  int idx;
+
+  res = (struct name **) tfind (&fake_name, &names, name_compare);
+  if (res == NULL)
+    abort ();
+
+  idx = (*res)->module_idx;
+  if (idx == -1 && add)
+    /* No module index assigned yet.  */
+    idx = (*res)->module_idx = nname_info++;
+
+  return idx;
+}
+
+
+static void
+generate_name_info (void)
+{
+  size_t i;
+  int idx;
+
+  name_info = (struct name_info *) xcalloc (nmodule_list + 1,
+					    sizeof (struct name_info));
+
+  /* First add a special entry for the INTERNAL name.  This must have
+     index zero.  */
+  idx = name_to_module_idx ("INTERNAL", 1);
+  name_info[0].canonical_name = "INTERNAL";
+  name_info[0].canonical_strent = strtabadd (strtab, "INTERNAL",
+					     sizeof ("INTERNAL"));
+  assert (nname_info == 1);
+
+  for (i = 0; i < nmodule_list; ++i)
+    {
+      struct module *runp;
+
+      for (runp = module_list[i]; runp != NULL; runp = runp->next)
+	if (strcmp (runp->fromname, "INTERNAL") == 0)
+	  {
+	    idx = name_to_module_idx (runp->toname, 1);
+	    name_info[idx].from_internal = runp;
+	    assert (name_info[idx].canonical_name == NULL
+		    || strcmp (name_info[idx].canonical_name,
+			       runp->toname) == 0);
+	    name_info[idx].canonical_name = runp->toname;
+	    name_info[idx].canonical_strent = runp->toname_strent;
+	  }
+	else if (strcmp (runp->toname, "INTERNAL") == 0)
+	  {
+	    idx = name_to_module_idx (runp->fromname, 1);
+	    name_info[idx].to_internal = runp;
+	    assert (name_info[idx].canonical_name == NULL
+		    || strcmp (name_info[idx].canonical_name,
+			       runp->fromname) == 0);
+	    name_info[idx].canonical_name = runp->fromname;
+	    name_info[idx].canonical_strent = runp->fromname_strent;
+	  }
+	else
+	  {
+	    /* This is a transformation not to or from the INTERNAL
+	       encoding.  */
+	    int from_idx = name_to_module_idx (runp->fromname, 1);
+	    int to_idx = name_to_module_idx (runp->toname, 1);
+	    struct other_conv_list *newp;
+
+	    newp = (struct other_conv_list *)
+	      xmalloc (sizeof (struct other_conv_list));
+	    newp->other_conv.module_idx = to_idx;
+	    newp->other_conv.module = runp;
+	    newp->other_conv.next = NULL; /* XXX Allow multiple module sequence */
+	    newp->dest_idx = to_idx;
+	    newp->next = name_info[from_idx].other_conv_list;
+	    name_info[from_idx].other_conv_list = newp;
+	    assert (name_info[from_idx].canonical_name == NULL
+		    || strcmp (name_info[from_idx].canonical_name,
+			       runp->fromname) == 0);
+	    name_info[from_idx].canonical_name = runp->fromname;
+	    name_info[from_idx].canonical_strent = runp->fromname_strent;
+
+	    ++nextra_modules;
+	  }
+    }
+
+  /* Now add the module index information for all the aliases.  */
+  for (i = 0; i < nalias_list; ++i)
+    {
+      struct name fake_name = { .name = alias_list[i]->toname };
+      struct name **tonamep;
+
+      tonamep = (struct name **) tfind (&fake_name, &names, name_compare);
+      if (tonamep != NULL)
+	{
+	  struct name *newp = new_name (alias_list[i]->fromname,
+					alias_list[i]->froment);
+	  newp->module_idx = (*tonamep)->module_idx;
+	  tsearch (newp, &names, name_compare);
+	}
+    }
+}
+
+
+static int
+is_prime (unsigned long int candidate)
+{
+  /* No even number and none less than 10 will be passed here.  */
+  unsigned long int divn = 3;
+  unsigned long int sq = divn * divn;
+
+  while (sq < candidate && candidate % divn != 0)
+    {
+      ++divn;
+      sq += 4 * divn;
+      ++divn;
+    }
+
+  return candidate % divn != 0;
+}
+
+
+static uint32_t
+next_prime (uint32_t seed)
+{
+  /* Make it definitely odd.  */
+  seed |= 1;
+
+  while (!is_prime (seed))
+    seed += 2;
+
+  return seed;
+}
+
+
+/* Format of the output file.
+
+   Offset   Length       Description
+   0000     4            Magic header bytes
+   0004     2            Offset of string table (stoff)
+   0006     2            Offset of name hashing table (hoff)
+   0008     2            Hashing table size (hsize)
+   000A     2            Offset of module table (moff)
+   000C     2            Offset of other conversion module table (ooff)
+
+   stoff    ???          String table
+
+   hoff     8*hsize      Array of tuples
+			    string table offset
+			    module index
+
+   moff     ???          Array of tuples
+			    canonical name offset
+			    from-internal module dir name offset
+			    from-internal module name off
+			    to-internal module dir name offset
+			    to-internal module name offset
+			    offset into other conversion table
+
+   ooff     ???          One or more of
+			    number of steps/modules
+			    one or more of tuple
+			      canonical name offset for output
+			      module dir name offset
+			      module name offset
+			 (following last entry with step count 0)
+*/
+
+static struct hash_entry *hash_table;
+static size_t hash_size;
+
+/* Function to insert the names.  */
+static void name_insert (const void *nodep, VISIT value, int level)
+{
+  struct name *name;
+  unsigned int idx;
+  unsigned int hval2;
+
+  if (value != leaf && value != postorder)
+    return;
+
+  name = *(struct name **) nodep;
+  idx = name->hashval % hash_size;
+  hval2 = 1 + name->hashval % (hash_size - 2);
+
+  while (hash_table[idx].string_offset != 0)
+    if ((idx += hval2) >= hash_size)
+      idx -= hash_size;
+
+  hash_table[idx].string_offset = strtaboffset (name->strent);
+
+  assert (name->module_idx != -1);
+  hash_table[idx].module_idx = name->module_idx;
+}
+
+static int
+write_output (void)
+{
+  int fd;
+  char *string_table;
+  size_t string_table_size;
+  struct gconvcache_header header;
+  struct module_entry *module_table;
+  char *extra_table;
+  char *cur_extra_table;
+  size_t n;
+  int idx;
+  struct iovec iov[6];
+  static const gidx_t null_word;
+  size_t total;
+  char finalname[prefix_len + sizeof GCONV_MODULES_CACHE];
+  char tmpfname[(output_file == NULL ? sizeof finalname : output_file_len + 1)
+		+ strlen (".XXXXXX")];
+
+  /* Open the output file.  */
+  if (output_file == NULL)
+    {
+      assert (GCONV_MODULES_CACHE[0] == '/');
+      strcpy (stpcpy (mempcpy (tmpfname, prefix, prefix_len),
+		      GCONV_MODULES_CACHE),
+	      ".XXXXXX");
+      strcpy (mempcpy (finalname, prefix, prefix_len), GCONV_MODULES_CACHE);
+    }
+  else
+    strcpy (mempcpy (tmpfname, output_file, output_file_len), ".XXXXXX");
+  fd = mkstemp (tmpfname);
+  if (fd == -1)
+    return 1;
+
+  /* Create the string table.  */
+  string_table = strtabfinalize (strtab, &string_table_size);
+
+  /* Create the hashing table.  We know how many strings we have.
+     Creating a perfect hash table is not reasonable here.  Therefore
+     we use open hashing and a table size which is the next prime 40%
+     larger than the number of strings.  */
+  hash_size = next_prime (nnames * 1.4);
+  hash_table = (struct hash_entry *) xcalloc (hash_size,
+					      sizeof (struct hash_entry));
+  /* Fill the hash table.  */
+  twalk (names, name_insert);
+
+  /* Create the section for the module list.  */
+  module_table = (struct module_entry *) xcalloc (sizeof (struct module_entry),
+						  nname_info);
+
+  /* Allocate memory for the non-INTERNAL conversions.  The allocated
+     memory can be more than is actually needed.  */
+  extra_table = (char *) xcalloc (sizeof (struct extra_entry)
+				  + sizeof (gidx_t)
+				  + sizeof (struct extra_entry_module),
+				  nextra_modules);
+  cur_extra_table = extra_table;
+
+  /* Fill in the module information.  */
+  for (n = 0; n < nname_info; ++n)
+    {
+      module_table[n].canonname_offset =
+	strtaboffset (name_info[n].canonical_strent);
+
+      if (name_info[n].from_internal == NULL)
+	{
+	  module_table[n].fromdir_offset = 0;
+	  module_table[n].fromname_offset = 0;
+	}
+      else
+	{
+	  module_table[n].fromdir_offset =
+	    strtaboffset (name_info[n].from_internal->directory_strent);
+	  module_table[n].fromname_offset =
+	    strtaboffset (name_info[n].from_internal->filename_strent);
+	}
+
+      if (name_info[n].to_internal == NULL)
+	{
+	  module_table[n].todir_offset = 0;
+	  module_table[n].toname_offset = 0;
+	}
+      else
+	{
+	  module_table[n].todir_offset =
+	    strtaboffset (name_info[n].to_internal->directory_strent);
+	  module_table[n].toname_offset =
+	    strtaboffset (name_info[n].to_internal->filename_strent);
+	}
+
+      if (name_info[n].other_conv_list != NULL)
+	{
+	  struct other_conv_list *other = name_info[n].other_conv_list;
+
+	  /* Store the reference.  We add 1 to distinguish the entry
+	     at offset zero from the case where no extra modules are
+	     available.  The file reader has to account for the
+	     offset.  */
+	  module_table[n].extra_offset = 1 + cur_extra_table - extra_table;
+
+	  do
+	    {
+	      struct other_conv *runp;
+	      struct extra_entry *extra;
+
+	      /* Allocate new entry.  */
+	      extra = (struct extra_entry *) cur_extra_table;
+	      cur_extra_table += sizeof (struct extra_entry);
+	      extra->module_cnt = 0;
+
+	      runp = &other->other_conv;
+	      do
+		{
+		  cur_extra_table += sizeof (struct extra_entry_module);
+		  extra->module[extra->module_cnt].outname_offset =
+		    runp->next == NULL
+		    ? other->dest_idx : runp->next->module_idx;
+		  extra->module[extra->module_cnt].dir_offset =
+		    strtaboffset (runp->module->directory_strent);
+		  extra->module[extra->module_cnt].name_offset =
+		    strtaboffset (runp->module->filename_strent);
+		  ++extra->module_cnt;
+
+		  runp = runp->next;
+		}
+	      while (runp != NULL);
+
+	      other = other->next;
+	    }
+	  while (other != NULL);
+
+	  /* Final module_cnt is zero.  */
+	  *((gidx_t *) cur_extra_table) = 0;
+	  cur_extra_table += sizeof (gidx_t);
+	}
+    }
+
+  /* Clear padding.  */
+  memset (&header, 0, sizeof (struct gconvcache_header));
+
+  header.magic = GCONVCACHE_MAGIC;
+
+  iov[0].iov_base = &header;
+  iov[0].iov_len = sizeof (struct gconvcache_header);
+  total = iov[0].iov_len;
+
+  header.string_offset = total;
+  iov[1].iov_base = string_table;
+  iov[1].iov_len = string_table_size;
+  total += iov[1].iov_len;
+
+  idx = 2;
+  if ((string_table_size & (sizeof (gidx_t) - 1)) != 0)
+    {
+      iov[2].iov_base = (void *) &null_word;
+      iov[2].iov_len = (sizeof (gidx_t)
+			- (string_table_size & (sizeof (gidx_t) - 1)));
+      total += iov[2].iov_len;
+      ++idx;
+    }
+
+  header.hash_offset = total;
+  header.hash_size = hash_size;
+  iov[idx].iov_base = hash_table;
+  iov[idx].iov_len = hash_size * sizeof (struct hash_entry);
+  total += iov[idx].iov_len;
+  ++idx;
+
+  header.module_offset = total;
+  iov[idx].iov_base = module_table;
+  iov[idx].iov_len = nname_info * sizeof (struct module_entry);
+  total += iov[idx].iov_len;
+  ++idx;
+
+  assert ((size_t) (cur_extra_table - extra_table)
+	  <= ((sizeof (struct extra_entry) + sizeof (gidx_t)
+	       + sizeof (struct extra_entry_module))
+	      * nextra_modules));
+  header.otherconv_offset = total;
+  iov[idx].iov_base = extra_table;
+  iov[idx].iov_len = cur_extra_table - extra_table;
+  total += iov[idx].iov_len;
+  ++idx;
+
+  if ((size_t) TEMP_FAILURE_RETRY (writev (fd, iov, idx)) != total
+      /* The file was created with mode 0600.  Make it world-readable.  */
+      || fchmod (fd, 0644) != 0
+      /* Rename the file, possibly replacing an old one.  */
+      || rename (tmpfname, output_file ?: finalname) != 0)
+    {
+      int save_errno = errno;
+      close (fd);
+      unlink (tmpfname);
+      error (EXIT_FAILURE, save_errno,
+	     gettext ("cannot generate output file"));
+    }
+
+  close (fd);
+
+  return 0;
+}
diff --git a/REORG.TODO/iconv/iconvconfig.h b/REORG.TODO/iconv/iconvconfig.h
new file mode 100644
index 0000000000..3f9fbdb1f4
--- /dev/null
+++ b/REORG.TODO/iconv/iconvconfig.h
@@ -0,0 +1,66 @@
+/* Copyright (C) 2000-2017 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+   Contributed by Ulrich Drepper <drepper@redhat.com>, 2000.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public License as
+   published by the Free Software Foundation; either version 2.1 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
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with the GNU C Library; see the file COPYING.LIB.  If
+   not, see <http://www.gnu.org/licenses/>.  */
+
+#include <stdint.h>
+
+
+typedef uint16_t gidx_t;
+
+
+struct gconvcache_header
+{
+  uint32_t magic;
+  gidx_t string_offset;
+  gidx_t hash_offset;
+  gidx_t hash_size;
+  gidx_t module_offset;
+  gidx_t otherconv_offset;
+};
+
+struct hash_entry
+{
+  gidx_t string_offset;
+  gidx_t module_idx;
+};
+
+struct module_entry
+{
+  gidx_t canonname_offset;
+  gidx_t fromdir_offset;
+  gidx_t fromname_offset;
+  gidx_t todir_offset;
+  gidx_t toname_offset;
+  gidx_t extra_offset;
+};
+
+struct extra_entry
+{
+  gidx_t module_cnt;
+  struct extra_entry_module
+  {
+    gidx_t outname_offset;
+    gidx_t dir_offset;
+    gidx_t name_offset;
+  } module[0];
+};
+
+
+#define GCONVCACHE_MAGIC	0x20010324
+
+
+#define GCONV_MODULES_CACHE	GCONV_DIR "/gconv-modules.cache"
diff --git a/REORG.TODO/iconv/loop.c b/REORG.TODO/iconv/loop.c
new file mode 100644
index 0000000000..0160f72cd6
--- /dev/null
+++ b/REORG.TODO/iconv/loop.c
@@ -0,0 +1,523 @@
+/* Conversion loop frame work.
+   Copyright (C) 1998-2017 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+   Contributed by Ulrich Drepper <drepper@cygnus.com>, 1998.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 2.1 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
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with the GNU C Library; if not, see
+   <http://www.gnu.org/licenses/>.  */
+
+/* This file provides a frame for the reader loop in all conversion modules.
+   The actual code must (of course) be provided in the actual module source
+   code but certain actions can be written down generically, with some
+   customization options which are these:
+
+     MIN_NEEDED_INPUT	minimal number of input bytes needed for the next
+			conversion.
+     MIN_NEEDED_OUTPUT	minimal number of bytes produced by the next round
+			of conversion.
+
+     MAX_NEEDED_INPUT	you guess it, this is the maximal number of input
+			bytes needed.  It defaults to MIN_NEEDED_INPUT
+     MAX_NEEDED_OUTPUT	likewise for output bytes.
+
+     LOOPFCT		name of the function created.  If not specified
+			the name is `loop' but this prevents the use
+			of multiple functions in the same file.
+
+     BODY		this is supposed to expand to the body of the loop.
+			The user must provide this.
+
+     EXTRA_LOOP_DECLS	extra arguments passed from conversion loop call.
+
+     INIT_PARAMS	code to define and initialize variables from params.
+     UPDATE_PARAMS	code to store result in params.
+
+     ONEBYTE_BODY	body of the specialized conversion function for a
+			single byte from the current character set to INTERNAL.
+*/
+
+#include <assert.h>
+#include <endian.h>
+#include <gconv.h>
+#include <stdint.h>
+#include <string.h>
+#include <wchar.h>
+#include <sys/param.h>		/* For MIN.  */
+#define __need_size_t
+#include <stddef.h>
+#include <libc-diag.h>
+
+/* We have to provide support for machines which are not able to handled
+   unaligned memory accesses.  Some of the character encodings have
+   representations with a fixed width of 2 or 4 bytes.  But if we cannot
+   access unaligned memory we still have to read byte-wise.  */
+#undef FCTNAME2
+#if _STRING_ARCH_unaligned || !defined DEFINE_UNALIGNED
+/* We can handle unaligned memory access.  */
+# define get16(addr) *((const uint16_t *) (addr))
+# define get32(addr) *((const uint32_t *) (addr))
+
+/* We need no special support for writing values either.  */
+# define put16(addr, val) *((uint16_t *) (addr)) = (val)
+# define put32(addr, val) *((uint32_t *) (addr)) = (val)
+
+# define FCTNAME2(name) name
+#else
+/* Distinguish between big endian and little endian.  */
+# if __BYTE_ORDER == __LITTLE_ENDIAN
+#  define get16(addr) \
+     (((const unsigned char *) (addr))[1] << 8				      \
+      | ((const unsigned char *) (addr))[0])
+#  define get32(addr) \
+     (((((const unsigned char *) (addr))[3] << 8			      \
+	| ((const unsigned char *) (addr))[2]) << 8			      \
+       | ((const unsigned char *) (addr))[1]) << 8			      \
+      | ((const unsigned char *) (addr))[0])
+
+#  define put16(addr, val) \
+     ({ uint16_t __val = (val);						      \
+	((unsigned char *) (addr))[0] = __val;				      \
+	((unsigned char *) (addr))[1] = __val >> 8;			      \
+	(void) 0; })
+#  define put32(addr, val) \
+     ({ uint32_t __val = (val);						      \
+	((unsigned char *) (addr))[0] = __val;				      \
+	__val >>= 8;							      \
+	((unsigned char *) (addr))[1] = __val;				      \
+	__val >>= 8;							      \
+	((unsigned char *) (addr))[2] = __val;				      \
+	__val >>= 8;							      \
+	((unsigned char *) (addr))[3] = __val;				      \
+	(void) 0; })
+# else
+#  define get16(addr) \
+     (((const unsigned char *) (addr))[0] << 8				      \
+      | ((const unsigned char *) (addr))[1])
+#  define get32(addr) \
+     (((((const unsigned char *) (addr))[0] << 8			      \
+	| ((const unsigned char *) (addr))[1]) << 8			      \
+       | ((const unsigned char *) (addr))[2]) << 8			      \
+      | ((const unsigned char *) (addr))[3])
+
+#  define put16(addr, val) \
+     ({ uint16_t __val = (val);						      \
+	((unsigned char *) (addr))[1] = __val;				      \
+	((unsigned char *) (addr))[0] = __val >> 8;			      \
+	(void) 0; })
+#  define put32(addr, val) \
+     ({ uint32_t __val = (val);						      \
+	((unsigned char *) (addr))[3] = __val;				      \
+	__val >>= 8;							      \
+	((unsigned char *) (addr))[2] = __val;				      \
+	__val >>= 8;							      \
+	((unsigned char *) (addr))[1] = __val;				      \
+	__val >>= 8;							      \
+	((unsigned char *) (addr))[0] = __val;				      \
+	(void) 0; })
+# endif
+
+# define FCTNAME2(name) name##_unaligned
+#endif
+#define FCTNAME(name) FCTNAME2(name)
+
+
+/* We need at least one byte for the next round.  */
+#ifndef MIN_NEEDED_INPUT
+# error "MIN_NEEDED_INPUT definition missing"
+#elif MIN_NEEDED_INPUT < 1
+# error "MIN_NEEDED_INPUT must be >= 1"
+#endif
+
+/* Let's see how many bytes we produce.  */
+#ifndef MAX_NEEDED_INPUT
+# define MAX_NEEDED_INPUT	MIN_NEEDED_INPUT
+#endif
+
+/* We produce at least one byte in the next round.  */
+#ifndef MIN_NEEDED_OUTPUT
+# error "MIN_NEEDED_OUTPUT definition missing"
+#elif MIN_NEEDED_OUTPUT < 1
+# error "MIN_NEEDED_OUTPUT must be >= 1"
+#endif
+
+/* Let's see how many bytes we produce.  */
+#ifndef MAX_NEEDED_OUTPUT
+# define MAX_NEEDED_OUTPUT	MIN_NEEDED_OUTPUT
+#endif
+
+/* Default name for the function.  */
+#ifndef LOOPFCT
+# define LOOPFCT		loop
+#endif
+
+/* Make sure we have a loop body.  */
+#ifndef BODY
+# error "Definition of BODY missing for function" LOOPFCT
+#endif
+
+
+/* If no arguments have to passed to the loop function define the macro
+   as empty.  */
+#ifndef EXTRA_LOOP_DECLS
+# define EXTRA_LOOP_DECLS
+#endif
+
+/* Allow using UPDATE_PARAMS in macros where #ifdef UPDATE_PARAMS test
+   isn't possible.  */
+#ifndef UPDATE_PARAMS
+# define UPDATE_PARAMS do { } while (0)
+#endif
+#ifndef REINIT_PARAMS
+# define REINIT_PARAMS do { } while (0)
+#endif
+
+
+/* To make it easier for the writers of the modules, we define a macro
+   to test whether we have to ignore errors.  */
+#define ignore_errors_p() \
+  (irreversible != NULL && (flags & __GCONV_IGNORE_ERRORS))
+
+
+/* Error handling for the FROM_LOOP direction, with ignoring of errors.
+   Note that we cannot use the do while (0) trick since `break' and
+   `continue' must reach certain points.  */
+#define STANDARD_FROM_LOOP_ERR_HANDLER(Incr) \
+  {									      \
+    result = __GCONV_ILLEGAL_INPUT;					      \
+									      \
+    if (! ignore_errors_p ())						      \
+      break;								      \
+									      \
+    /* We ignore the invalid input byte sequence.  */			      \
+    inptr += (Incr);							      \
+    ++*irreversible;							      \
+    /* But we keep result == __GCONV_ILLEGAL_INPUT, because of the constraint \
+       that "iconv -c" must give the same exitcode as "iconv".  */	      \
+    continue;								      \
+  }
+
+/* Error handling for the TO_LOOP direction, with use of transliteration/
+   transcription functions and ignoring of errors.  Note that we cannot use
+   the do while (0) trick since `break' and `continue' must reach certain
+   points.  */
+#define STANDARD_TO_LOOP_ERR_HANDLER(Incr) \
+  {									      \
+    result = __GCONV_ILLEGAL_INPUT;					      \
+									      \
+    if (irreversible == NULL)						      \
+      /* This means we are in call from __gconv_transliterate.  In this	      \
+	 case we are not doing any error recovery outself.  */		      \
+      break;								      \
+									      \
+    /* If needed, flush any conversion state, so that __gconv_transliterate   \
+       starts with current shift state.  */				      \
+    UPDATE_PARAMS;							      \
+									      \
+    /* First try the transliteration methods.  */			      \
+    if ((step_data->__flags & __GCONV_TRANSLIT) != 0)			      \
+      result = __gconv_transliterate					      \
+	(step, step_data, *inptrp,					      \
+	 &inptr, inend, &outptr, irreversible);			      \
+									      \
+    REINIT_PARAMS;							      \
+									      \
+    /* If any of them recognized the input continue with the loop.  */	      \
+    if (result != __GCONV_ILLEGAL_INPUT)				      \
+      {									      \
+	if (__glibc_unlikely (result == __GCONV_FULL_OUTPUT))		      \
+	  break;							      \
+									      \
+	continue;							      \
+      }									      \
+									      \
+    /* Next see whether we have to ignore the error.  If not, stop.  */	      \
+    if (! ignore_errors_p ())						      \
+      break;								      \
+									      \
+    /* When we come here it means we ignore the character.  */		      \
+    ++*irreversible;							      \
+    inptr += Incr;							      \
+    /* But we keep result == __GCONV_ILLEGAL_INPUT, because of the constraint \
+       that "iconv -c" must give the same exitcode as "iconv".  */	      \
+    continue;								      \
+  }
+
+
+/* Handling of Unicode 3.1 TAG characters.  Unicode recommends
+   "If language codes are not relevant to the particular processing
+    operation, then they should be ignored."  This macro is usually
+   called right before  STANDARD_TO_LOOP_ERR_HANDLER (Incr).  */
+#define UNICODE_TAG_HANDLER(Character, Incr) \
+  {									      \
+    /* TAG characters are those in the range U+E0000..U+E007F.  */	      \
+    if (((Character) >> 7) == (0xe0000 >> 7))				      \
+      {									      \
+	inptr += Incr;							      \
+	continue;							      \
+      }									      \
+  }
+
+
+/* The function returns the status, as defined in gconv.h.  */
+static inline int
+__attribute ((always_inline))
+FCTNAME (LOOPFCT) (struct __gconv_step *step,
+		   struct __gconv_step_data *step_data,
+		   const unsigned char **inptrp, const unsigned char *inend,
+		   unsigned char **outptrp, const unsigned char *outend,
+		   size_t *irreversible EXTRA_LOOP_DECLS)
+{
+#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;
+
+#ifdef INIT_PARAMS
+  INIT_PARAMS;
+#endif
+
+  while (inptr != inend)
+    {
+      /* `if' cases for MIN_NEEDED_OUTPUT ==/!= 1 is made to help the
+	 compiler generating better code.  They will be optimized away
+	 since MIN_NEEDED_OUTPUT is always a constant.  */
+      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;
+	}
+      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;
+	}
+
+      /* 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.  */
+  *inptrp = inptr;
+  *outptrp = outptr;
+  UPDATE_PARAMS;
+
+  return result;
+}
+
+
+/* Include the file a second time to define the function to handle
+   unaligned access.  */
+#if !defined DEFINE_UNALIGNED && !_STRING_ARCH_unaligned \
+    && MIN_NEEDED_INPUT != 1 && MAX_NEEDED_INPUT % MIN_NEEDED_INPUT == 0 \
+    && MIN_NEEDED_OUTPUT != 1 && MAX_NEEDED_OUTPUT % MIN_NEEDED_OUTPUT == 0
+# undef get16
+# undef get32
+# undef put16
+# undef put32
+# undef unaligned
+
+# define DEFINE_UNALIGNED
+# include "loop.c"
+# undef DEFINE_UNALIGNED
+#else
+# if MAX_NEEDED_INPUT > 1
+#  define SINGLE(fct) SINGLE2 (fct)
+#  define SINGLE2(fct) fct##_single
+static inline int
+__attribute ((always_inline))
+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,
+		 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;
+  unsigned char *outptr = *outptrp;
+  size_t inlen;
+
+#  ifdef INIT_PARAMS
+  INIT_PARAMS;
+#  endif
+
+#  ifdef UNPACK_BYTES
+  UNPACK_BYTES
+#  else
+  /* Add the bytes from the state to the input buffer.  */
+  assert ((state->__count & 7) <= sizeof (state->__value));
+  for (inlen = 0; inlen < (size_t) (state->__count & 7); ++inlen)
+    bytebuf[inlen] = state->__value.__wchb[inlen];
+#  endif
+
+  /* Are there enough bytes in the input buffer?  */
+  if (MIN_NEEDED_INPUT > 1
+      && __builtin_expect (inptr + (MIN_NEEDED_INPUT - inlen) > inend, 0))
+    {
+      *inptrp = inend;
+#  ifdef STORE_REST
+
+      /* Building with -O3 GCC emits a `array subscript is above array
+	 bounds' warning.  GCC BZ #64739 has been opened for this.  */
+      DIAG_PUSH_NEEDS_COMMENT;
+      DIAG_IGNORE_NEEDS_COMMENT (4.9, "-Warray-bounds");
+      while (inptr < inend)
+	bytebuf[inlen++] = *inptr++;
+      DIAG_POP_NEEDS_COMMENT;
+
+      inptr = bytebuf;
+      inptrp = &inptr;
+      inend = &bytebuf[inlen];
+
+      STORE_REST
+#  else
+      /* We don't have enough input for another complete input
+	 character.  */
+      while (inptr < inend)
+	state->__value.__wchb[inlen++] = *inptr++;
+#  endif
+
+      return __GCONV_INCOMPLETE_INPUT;
+    }
+
+  /* Enough space in output buffer.  */
+  if ((MIN_NEEDED_OUTPUT != 1 && outptr + MIN_NEEDED_OUTPUT > outend)
+      || (MIN_NEEDED_OUTPUT == 1 && outptr >= outend))
+    /* Overflow in the output buffer.  */
+    return __GCONV_FULL_OUTPUT;
+
+  /*  Now add characters from the normal input buffer.  */
+  do
+    bytebuf[inlen++] = *inptr++;
+  while (inlen < MAX_NEEDED_INPUT && inptr < inend);
+
+  inptr = bytebuf;
+  inend = &bytebuf[inlen];
+
+  do
+    {
+      BODY
+    }
+  while (0);
+
+  /* Now we either have produced an output character and consumed all the
+     bytes from the state and at least one more, or the character is still
+     incomplete, or we have some other error (like illegal input character,
+     no space in output buffer).  */
+  if (__glibc_likely (inptr != bytebuf))
+    {
+      /* We found a new character.  */
+      assert (inptr - bytebuf > (state->__count & 7));
+
+      *inptrp += inptr - bytebuf - (state->__count & 7);
+      *outptrp = outptr;
+
+      result = __GCONV_OK;
+
+      /* Clear the state buffer.  */
+#  ifdef CLEAR_STATE
+      CLEAR_STATE;
+#  else
+      state->__count &= ~7;
+#  endif
+    }
+  else if (result == __GCONV_INCOMPLETE_INPUT)
+    {
+      /* This can only happen if we have less than MAX_NEEDED_INPUT bytes
+	 available.  */
+      assert (inend != &bytebuf[MAX_NEEDED_INPUT]);
+
+      *inptrp += inend - bytebuf - (state->__count & 7);
+#  ifdef STORE_REST
+      inptrp = &inptr;
+
+      STORE_REST
+#  else
+      /* We don't have enough input for another complete input
+	 character.  */
+      assert (inend - inptr > (state->__count & ~7));
+      assert (inend - inptr <= sizeof (state->__value));
+      state->__count = (state->__count & ~7) | (inend - inptr);
+      inlen = 0;
+      while (inptr < inend)
+	state->__value.__wchb[inlen++] = *inptr++;
+#  endif
+    }
+
+  return result;
+}
+#  undef SINGLE
+#  undef SINGLE2
+# endif
+
+
+# ifdef ONEBYTE_BODY
+/* Define the shortcut function for btowc.  */
+static wint_t
+gconv_btowc (struct __gconv_step *step, unsigned char c)
+  ONEBYTE_BODY
+#  define FROM_ONEBYTE gconv_btowc
+# endif
+
+#endif
+
+/* We remove the macro definitions so that we can include this file again
+   for the definition of another function.  */
+#undef MIN_NEEDED_INPUT
+#undef MAX_NEEDED_INPUT
+#undef MIN_NEEDED_OUTPUT
+#undef MAX_NEEDED_OUTPUT
+#undef LOOPFCT
+#undef BODY
+#undef LOOPFCT
+#undef EXTRA_LOOP_DECLS
+#undef INIT_PARAMS
+#undef UPDATE_PARAMS
+#undef REINIT_PARAMS
+#undef ONEBYTE_BODY
+#undef UNPACK_BYTES
+#undef CLEAR_STATE
+#undef LOOP_NEED_STATE
+#undef LOOP_NEED_FLAGS
+#undef LOOP_NEED_DATA
+#undef get16
+#undef get32
+#undef put16
+#undef put32
+#undef unaligned
diff --git a/REORG.TODO/iconv/skeleton.c b/REORG.TODO/iconv/skeleton.c
new file mode 100644
index 0000000000..a12119dc20
--- /dev/null
+++ b/REORG.TODO/iconv/skeleton.c
@@ -0,0 +1,821 @@
+/* Skeleton for a conversion module.
+   Copyright (C) 1998-2017 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+   Contributed by Ulrich Drepper <drepper@cygnus.com>, 1998.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 2.1 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
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with the GNU C Library; if not, see
+   <http://www.gnu.org/licenses/>.  */
+
+/* This file can be included to provide definitions of several things
+   many modules have in common.  It can be customized using the following
+   macros:
+
+     DEFINE_INIT	define the default initializer.  This requires the
+			following symbol to be defined.
+
+     CHARSET_NAME	string with official name of the coded character
+			set (in all-caps)
+
+     DEFINE_FINI	define the default destructor function.
+
+     MIN_NEEDED_FROM	minimal number of bytes needed for the from-charset.
+     MIN_NEEDED_TO	likewise for the to-charset.
+
+     MAX_NEEDED_FROM	maximal number of bytes needed for the from-charset.
+			This macro is optional, it defaults to MIN_NEEDED_FROM.
+     MAX_NEEDED_TO	likewise for the to-charset.
+
+     FROM_LOOP_MIN_NEEDED_FROM
+     FROM_LOOP_MAX_NEEDED_FROM
+			minimal/maximal number of bytes needed on input
+			of one round through the FROM_LOOP.  Defaults
+			to MIN_NEEDED_FROM and MAX_NEEDED_FROM, respectively.
+     FROM_LOOP_MIN_NEEDED_TO
+     FROM_LOOP_MAX_NEEDED_TO
+			minimal/maximal number of bytes needed on output
+			of one round through the FROM_LOOP.  Defaults
+			to MIN_NEEDED_TO and MAX_NEEDED_TO, respectively.
+     TO_LOOP_MIN_NEEDED_FROM
+     TO_LOOP_MAX_NEEDED_FROM
+			minimal/maximal number of bytes needed on input
+			of one round through the TO_LOOP.  Defaults
+			to MIN_NEEDED_TO and MAX_NEEDED_TO, respectively.
+     TO_LOOP_MIN_NEEDED_TO
+     TO_LOOP_MAX_NEEDED_TO
+			minimal/maximal number of bytes needed on output
+			of one round through the TO_LOOP.  Defaults
+			to MIN_NEEDED_FROM and MAX_NEEDED_FROM, respectively.
+
+     FROM_DIRECTION	this macro is supposed to return a value != 0
+			if we convert from the current character set,
+			otherwise it return 0.
+
+     EMIT_SHIFT_TO_INIT	this symbol is optional.  If it is defined it
+			defines some code which writes out a sequence
+			of bytes which bring the current state into
+			the initial state.
+
+     FROM_LOOP		name of the function implementing the conversion
+			from the current character set.
+     TO_LOOP		likewise for the other direction
+
+     ONE_DIRECTION	optional.  If defined to 1, only one conversion
+			direction is defined instead of two.  In this
+			case, FROM_DIRECTION should be defined to 1, and
+			FROM_LOOP and TO_LOOP should have the same value.
+
+     SAVE_RESET_STATE	in case of an error we must reset the state for
+			the rerun so this macro must be defined for
+			stateful encodings.  It takes an argument which
+			is nonzero when saving.
+
+     RESET_INPUT_BUFFER	If the input character sets allow this the macro
+			can be defined to reset the input buffer pointers
+			to cover only those characters up to the error.
+
+     FUNCTION_NAME	if not set the conversion function is named `gconv'.
+
+     PREPARE_LOOP	optional code preparing the conversion loop.  Can
+			contain variable definitions.
+     END_LOOP		also optional, may be used to store information
+
+     EXTRA_LOOP_ARGS	optional macro specifying extra arguments passed
+			to loop function.
+
+     STORE_REST		optional, needed only when MAX_NEEDED_FROM > 4.
+			This macro stores the seen but unconverted input bytes
+			in the state.
+
+     FROM_ONEBYTE	optional.  If defined, should be the name of a
+			specialized conversion function for a single byte
+			from the current character set to INTERNAL.  This
+			function has prototype
+			   wint_t
+			   FROM_ONEBYTE (struct __gconv_step *, unsigned char);
+			and does a special conversion:
+			- The input is a single byte.
+			- The output is a single uint32_t.
+			- The state before the conversion is the initial state;
+			  the state after the conversion is irrelevant.
+			- No transliteration.
+			- __invocation_counter = 0.
+			- __internal_use = 1.
+			- do_flush = 0.
+
+   Modules can use mbstate_t to store conversion state as follows:
+
+   * Bits 2..0 of '__count' contain the number of lookahead input bytes
+     stored in __value.__wchb.  Always zero if the converter never
+     returns __GCONV_INCOMPLETE_INPUT.
+
+   * Bits 31..3 of '__count' are module dependent shift state.
+
+   * __value: When STORE_REST/UNPACK_BYTES aren't defined and when the
+     converter has returned __GCONV_INCOMPLETE_INPUT, this contains
+     at most 4 lookahead bytes. Converters with an mb_cur_max > 4
+     (currently only UTF-8) must find a way to store their state
+     in __value.__wch and define STORE_REST/UNPACK_BYTES appropriately.
+
+   When __value contains lookahead, __count must not be zero, because
+   the converter is not in the initial state then, and mbsinit() --
+   defined as a (__count == 0) test -- must reflect this.
+ */
+
+#include <assert.h>
+#include <gconv.h>
+#include <string.h>
+#define __need_size_t
+#define __need_NULL
+#include <stddef.h>
+
+#ifndef STATIC_GCONV
+# include <dlfcn.h>
+#endif
+
+#include <sysdep.h>
+#include <stdint.h>
+
+#ifndef DL_CALL_FCT
+# define DL_CALL_FCT(fct, args) fct args
+#endif
+
+/* The direction objects.  */
+#if DEFINE_INIT
+# ifndef FROM_DIRECTION
+#  define FROM_DIRECTION_VAL NULL
+#  define TO_DIRECTION_VAL ((void *) ~((uintptr_t) 0))
+#  define FROM_DIRECTION (step->__data == FROM_DIRECTION_VAL)
+# endif
+#else
+# ifndef FROM_DIRECTION
+#  error "FROM_DIRECTION must be provided if non-default init is used"
+# endif
+#endif
+
+/* How many bytes are needed at most for the from-charset.  */
+#ifndef MAX_NEEDED_FROM
+# define MAX_NEEDED_FROM	MIN_NEEDED_FROM
+#endif
+
+/* Same for the to-charset.  */
+#ifndef MAX_NEEDED_TO
+# define MAX_NEEDED_TO		MIN_NEEDED_TO
+#endif
+
+/* Defaults for the per-direction min/max constants.  */
+#ifndef FROM_LOOP_MIN_NEEDED_FROM
+# define FROM_LOOP_MIN_NEEDED_FROM	MIN_NEEDED_FROM
+#endif
+#ifndef FROM_LOOP_MAX_NEEDED_FROM
+# define FROM_LOOP_MAX_NEEDED_FROM	MAX_NEEDED_FROM
+#endif
+#ifndef FROM_LOOP_MIN_NEEDED_TO
+# define FROM_LOOP_MIN_NEEDED_TO	MIN_NEEDED_TO
+#endif
+#ifndef FROM_LOOP_MAX_NEEDED_TO
+# define FROM_LOOP_MAX_NEEDED_TO	MAX_NEEDED_TO
+#endif
+#ifndef TO_LOOP_MIN_NEEDED_FROM
+# define TO_LOOP_MIN_NEEDED_FROM	MIN_NEEDED_TO
+#endif
+#ifndef TO_LOOP_MAX_NEEDED_FROM
+# define TO_LOOP_MAX_NEEDED_FROM	MAX_NEEDED_TO
+#endif
+#ifndef TO_LOOP_MIN_NEEDED_TO
+# define TO_LOOP_MIN_NEEDED_TO		MIN_NEEDED_FROM
+#endif
+#ifndef TO_LOOP_MAX_NEEDED_TO
+# define TO_LOOP_MAX_NEEDED_TO		MAX_NEEDED_FROM
+#endif
+
+
+/* Define macros which can access unaligned buffers.  These macros are
+   supposed to be used only in code outside the inner loops.  For the inner
+   loops we have other definitions which allow optimized access.  */
+#if _STRING_ARCH_unaligned
+/* We can handle unaligned memory access.  */
+# define get16u(addr) *((const uint16_t *) (addr))
+# define get32u(addr) *((const uint32_t *) (addr))
+
+/* We need no special support for writing values either.  */
+# define put16u(addr, val) *((uint16_t *) (addr)) = (val)
+# define put32u(addr, val) *((uint32_t *) (addr)) = (val)
+#else
+/* Distinguish between big endian and little endian.  */
+# if __BYTE_ORDER == __LITTLE_ENDIAN
+#  define get16u(addr) \
+     (((const unsigned char *) (addr))[1] << 8				      \
+      | ((const unsigned char *) (addr))[0])
+#  define get32u(addr) \
+     (((((const unsigned char *) (addr))[3] << 8			      \
+	| ((const unsigned char *) (addr))[2]) << 8			      \
+       | ((const unsigned char *) (addr))[1]) << 8			      \
+      | ((const unsigned char *) (addr))[0])
+
+#  define put16u(addr, val) \
+     ({ uint16_t __val = (val);						      \
+	((unsigned char *) (addr))[0] = __val;				      \
+	((unsigned char *) (addr))[1] = __val >> 8;			      \
+	(void) 0; })
+#  define put32u(addr, val) \
+     ({ uint32_t __val = (val);						      \
+	((unsigned char *) (addr))[0] = __val;				      \
+	__val >>= 8;							      \
+	((unsigned char *) (addr))[1] = __val;				      \
+	__val >>= 8;							      \
+	((unsigned char *) (addr))[2] = __val;				      \
+	__val >>= 8;							      \
+	((unsigned char *) (addr))[3] = __val;				      \
+	(void) 0; })
+# else
+#  define get16u(addr) \
+     (((const unsigned char *) (addr))[0] << 8				      \
+      | ((const unsigned char *) (addr))[1])
+#  define get32u(addr) \
+     (((((const unsigned char *) (addr))[0] << 8			      \
+	| ((const unsigned char *) (addr))[1]) << 8			      \
+       | ((const unsigned char *) (addr))[2]) << 8			      \
+      | ((const unsigned char *) (addr))[3])
+
+#  define put16u(addr, val) \
+     ({ uint16_t __val = (val);						      \
+	((unsigned char *) (addr))[1] = __val;				      \
+	((unsigned char *) (addr))[0] = __val >> 8;			      \
+	(void) 0; })
+#  define put32u(addr, val) \
+     ({ uint32_t __val = (val);						      \
+	((unsigned char *) (addr))[3] = __val;				      \
+	__val >>= 8;							      \
+	((unsigned char *) (addr))[2] = __val;				      \
+	__val >>= 8;							      \
+	((unsigned char *) (addr))[1] = __val;				      \
+	__val >>= 8;							      \
+	((unsigned char *) (addr))[0] = __val;				      \
+	(void) 0; })
+# endif
+#endif
+
+
+/* For conversions from a fixed width character set to another fixed width
+   character set we can define RESET_INPUT_BUFFER in a very fast way.  */
+#if !defined RESET_INPUT_BUFFER && !defined SAVE_RESET_STATE
+# if FROM_LOOP_MIN_NEEDED_FROM == FROM_LOOP_MAX_NEEDED_FROM \
+     && FROM_LOOP_MIN_NEEDED_TO == FROM_LOOP_MAX_NEEDED_TO \
+     && TO_LOOP_MIN_NEEDED_FROM == TO_LOOP_MAX_NEEDED_FROM \
+     && TO_LOOP_MIN_NEEDED_TO == TO_LOOP_MAX_NEEDED_TO
+/* We have to use these `if's here since the compiler cannot know that
+   (outbuf - outerr) is always divisible by FROM/TO_LOOP_MIN_NEEDED_TO.
+   The ?:1 avoids division by zero warnings that gcc 3.2 emits even for
+   obviously unreachable code.  */
+#  define RESET_INPUT_BUFFER \
+  if (FROM_DIRECTION)							      \
+    {									      \
+      if (FROM_LOOP_MIN_NEEDED_FROM % FROM_LOOP_MIN_NEEDED_TO == 0)	      \
+	*inptrp -= (outbuf - outerr)					      \
+		   * (FROM_LOOP_MIN_NEEDED_FROM / FROM_LOOP_MIN_NEEDED_TO);   \
+      else if (FROM_LOOP_MIN_NEEDED_TO % FROM_LOOP_MIN_NEEDED_FROM == 0)      \
+	*inptrp -= (outbuf - outerr)					      \
+		   / (FROM_LOOP_MIN_NEEDED_TO / FROM_LOOP_MIN_NEEDED_FROM     \
+		      ? : 1);						      \
+      else								      \
+	*inptrp -= ((outbuf - outerr) / FROM_LOOP_MIN_NEEDED_TO)	      \
+		   * FROM_LOOP_MIN_NEEDED_FROM;				      \
+    }									      \
+  else									      \
+    {									      \
+      if (TO_LOOP_MIN_NEEDED_FROM % TO_LOOP_MIN_NEEDED_TO == 0)		      \
+	*inptrp -= (outbuf - outerr)					      \
+		   * (TO_LOOP_MIN_NEEDED_FROM / TO_LOOP_MIN_NEEDED_TO);	      \
+      else if (TO_LOOP_MIN_NEEDED_TO % TO_LOOP_MIN_NEEDED_FROM == 0)	      \
+	*inptrp -= (outbuf - outerr)					      \
+		   / (TO_LOOP_MIN_NEEDED_TO / TO_LOOP_MIN_NEEDED_FROM ? : 1); \
+      else								      \
+	*inptrp -= ((outbuf - outerr) / TO_LOOP_MIN_NEEDED_TO)		      \
+		   * TO_LOOP_MIN_NEEDED_FROM;				      \
+    }
+# endif
+#endif
+
+
+/* The default init function.  It simply matches the name and initializes
+   the step data to point to one of the objects above.  */
+#if DEFINE_INIT
+# ifndef CHARSET_NAME
+#  error "CHARSET_NAME not defined"
+# endif
+
+extern int gconv_init (struct __gconv_step *step);
+int
+gconv_init (struct __gconv_step *step)
+{
+  /* Determine which direction.  */
+  if (strcmp (step->__from_name, CHARSET_NAME) == 0)
+    {
+      step->__data = FROM_DIRECTION_VAL;
+
+      step->__min_needed_from = FROM_LOOP_MIN_NEEDED_FROM;
+      step->__max_needed_from = FROM_LOOP_MAX_NEEDED_FROM;
+      step->__min_needed_to = FROM_LOOP_MIN_NEEDED_TO;
+      step->__max_needed_to = FROM_LOOP_MAX_NEEDED_TO;
+
+#ifdef FROM_ONEBYTE
+      step->__btowc_fct = FROM_ONEBYTE;
+#endif
+    }
+  else if (__builtin_expect (strcmp (step->__to_name, CHARSET_NAME), 0) == 0)
+    {
+      step->__data = TO_DIRECTION_VAL;
+
+      step->__min_needed_from = TO_LOOP_MIN_NEEDED_FROM;
+      step->__max_needed_from = TO_LOOP_MAX_NEEDED_FROM;
+      step->__min_needed_to = TO_LOOP_MIN_NEEDED_TO;
+      step->__max_needed_to = TO_LOOP_MAX_NEEDED_TO;
+    }
+  else
+    return __GCONV_NOCONV;
+
+#ifdef SAVE_RESET_STATE
+  step->__stateful = 1;
+#else
+  step->__stateful = 0;
+#endif
+
+  return __GCONV_OK;
+}
+#endif
+
+
+/* The default destructor function does nothing in the moment and so
+   we don't define it at all.  But we still provide the macro just in
+   case we need it some day.  */
+#if DEFINE_FINI
+#endif
+
+
+/* If no arguments have to passed to the loop function define the macro
+   as empty.  */
+#ifndef EXTRA_LOOP_ARGS
+# define EXTRA_LOOP_ARGS
+#endif
+
+
+/* This is the actual conversion function.  */
+#ifndef FUNCTION_NAME
+# define FUNCTION_NAME	gconv
+#endif
+
+/* The macros are used to access the function to convert single characters.  */
+#define SINGLE(fct) SINGLE2 (fct)
+#define SINGLE2(fct) fct##_single
+
+
+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);
+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)
+{
+  struct __gconv_step *next_step = step + 1;
+  struct __gconv_step_data *next_data = data + 1;
+  __gconv_fct fct = NULL;
+  int status;
+
+  if ((data->__flags & __GCONV_IS_LAST) == 0)
+    {
+      fct = next_step->__fct;
+#ifdef PTR_DEMANGLE
+      if (next_step->__shlib_handle != NULL)
+	PTR_DEMANGLE (fct);
+#endif
+    }
+
+  /* If the function is called with no input this means we have to reset
+     to the initial state.  The possibly partly converted input is
+     dropped.  */
+  if (__glibc_unlikely (do_flush))
+    {
+      /* This should never happen during error handling.  */
+      assert (outbufstart == NULL);
+
+      status = __GCONV_OK;
+
+#ifdef EMIT_SHIFT_TO_INIT
+      if (do_flush == 1)
+	{
+	  /* We preserve the initial values of the pointer variables.  */
+	  unsigned char *outbuf = data->__outbuf;
+	  unsigned char *outstart = outbuf;
+	  unsigned char *outend = data->__outbufend;
+
+# ifdef PREPARE_LOOP
+	  PREPARE_LOOP
+# endif
+
+# ifdef SAVE_RESET_STATE
+	  SAVE_RESET_STATE (1);
+# endif
+
+	  /* Emit the escape sequence to reset the state.  */
+	  EMIT_SHIFT_TO_INIT;
+
+	  /* Call the steps down the chain if there are any but only if we
+	     successfully emitted the escape sequence.  This should only
+	     fail if the output buffer is full.  If the input is invalid
+	     it should be discarded since the user wants to start from a
+	     clean state.  */
+	  if (status == __GCONV_OK)
+	    {
+	      if (data->__flags & __GCONV_IS_LAST)
+		/* Store information about how many bytes are available.  */
+		data->__outbuf = outbuf;
+	      else
+		{
+		  /* Write out all output which was produced.  */
+		  if (outbuf > outstart)
+		    {
+		      const unsigned char *outerr = outstart;
+		      int result;
+
+		      result = DL_CALL_FCT (fct, (next_step, next_data,
+						  &outerr, outbuf, NULL,
+						  irreversible, 0,
+						  consume_incomplete));
+
+		      if (result != __GCONV_EMPTY_INPUT)
+			{
+			  if (__glibc_unlikely (outerr != outbuf))
+			    {
+			      /* We have a problem.  Undo the conversion.  */
+			      outbuf = outstart;
+
+			      /* Restore the state.  */
+# ifdef SAVE_RESET_STATE
+			      SAVE_RESET_STATE (0);
+# endif
+			    }
+
+			  /* Change the status.  */
+			  status = result;
+			}
+		    }
+
+		  if (status == __GCONV_OK)
+		    /* Now flush the remaining steps.  */
+		    status = DL_CALL_FCT (fct, (next_step, next_data, NULL,
+						NULL, NULL, irreversible, 1,
+						consume_incomplete));
+		}
+	    }
+	}
+      else
+#endif
+	{
+	  /* Clear the state object.  There might be bytes in there from
+	     previous calls with CONSUME_INCOMPLETE == 1.  But don't emit
+	     escape sequences.  */
+	  memset (data->__statep, '\0', sizeof (*data->__statep));
+
+	  if (! (data->__flags & __GCONV_IS_LAST))
+	    /* Now flush the remaining steps.  */
+	    status = DL_CALL_FCT (fct, (next_step, next_data, NULL, NULL,
+					NULL, irreversible, do_flush,
+					consume_incomplete));
+	}
+    }
+  else
+    {
+      /* We preserve the initial values of the pointer variables,
+	 but only some conversion modules need it.  */
+      const unsigned char *inptr __attribute__ ((__unused__)) = *inptrp;
+      unsigned char *outbuf = (__builtin_expect (outbufstart == NULL, 1)
+			       ? data->__outbuf : *outbufstart);
+      unsigned char *outend = data->__outbufend;
+      unsigned char *outstart;
+      /* This variable is used to count the number of characters we
+	 actually converted.  */
+      size_t lirreversible = 0;
+      size_t *lirreversiblep = irreversible ? &lirreversible : NULL;
+
+      /* The following assumes that encodings, which have a variable length
+	 what might unalign a buffer even though it is an aligned in the
+	 beginning, either don't have the minimal number of bytes as a divisor
+	 of the maximum length or have a minimum length of 1.  This is true
+	 for all known and supported encodings.
+	 We use && instead of || to combine the subexpression for the FROM
+	 encoding and for the TO encoding, because usually one of them is
+	 INTERNAL, for which the subexpression evaluates to 1, but INTERNAL
+	 buffers are always aligned correctly.  */
+#define POSSIBLY_UNALIGNED \
+  (!_STRING_ARCH_unaligned					              \
+   && (((FROM_LOOP_MIN_NEEDED_FROM != 1					      \
+	 && FROM_LOOP_MAX_NEEDED_FROM % FROM_LOOP_MIN_NEEDED_FROM == 0)	      \
+	&& (FROM_LOOP_MIN_NEEDED_TO != 1				      \
+	    && FROM_LOOP_MAX_NEEDED_TO % FROM_LOOP_MIN_NEEDED_TO == 0))	      \
+       || ((TO_LOOP_MIN_NEEDED_FROM != 1				      \
+	    && TO_LOOP_MAX_NEEDED_FROM % TO_LOOP_MIN_NEEDED_FROM == 0)	      \
+	   && (TO_LOOP_MIN_NEEDED_TO != 1				      \
+	       && TO_LOOP_MAX_NEEDED_TO % TO_LOOP_MIN_NEEDED_TO == 0))))
+#if POSSIBLY_UNALIGNED
+      int unaligned;
+# define GEN_unaligned(name) GEN_unaligned2 (name)
+# define GEN_unaligned2(name) name##_unaligned
+#else
+# define unaligned 0
+#endif
+
+#ifdef PREPARE_LOOP
+      PREPARE_LOOP
+#endif
+
+#if FROM_LOOP_MAX_NEEDED_FROM > 1 || TO_LOOP_MAX_NEEDED_FROM > 1
+      /* If the function is used to implement the mb*towc*() or wc*tomb*()
+	 functions we must test whether any bytes from the last call are
+	 stored in the `state' object.  */
+      if (((FROM_LOOP_MAX_NEEDED_FROM > 1 && TO_LOOP_MAX_NEEDED_FROM > 1)
+	   || (FROM_LOOP_MAX_NEEDED_FROM > 1 && FROM_DIRECTION)
+	   || (TO_LOOP_MAX_NEEDED_FROM > 1 && !FROM_DIRECTION))
+	  && consume_incomplete && (data->__statep->__count & 7) != 0)
+	{
+	  /* Yep, we have some bytes left over.  Process them now.
+	     But this must not happen while we are called from an
+	     error handler.  */
+	  assert (outbufstart == NULL);
+
+# if FROM_LOOP_MAX_NEEDED_FROM > 1
+	  if (TO_LOOP_MAX_NEEDED_FROM == 1 || FROM_DIRECTION)
+	    status = SINGLE(FROM_LOOP) (step, data, inptrp, inend, &outbuf,
+					outend, lirreversiblep
+					EXTRA_LOOP_ARGS);
+# endif
+# if !ONE_DIRECTION
+#  if FROM_LOOP_MAX_NEEDED_FROM > 1 && TO_LOOP_MAX_NEEDED_FROM > 1
+	  else
+#  endif
+#  if TO_LOOP_MAX_NEEDED_FROM > 1
+	    status = SINGLE(TO_LOOP) (step, data, inptrp, inend, &outbuf,
+				      outend, lirreversiblep EXTRA_LOOP_ARGS);
+#  endif
+# endif
+
+	  if (__builtin_expect (status, __GCONV_OK) != __GCONV_OK)
+	    return status;
+	}
+#endif
+
+#if POSSIBLY_UNALIGNED
+      unaligned =
+	((FROM_DIRECTION
+	  && ((uintptr_t) inptr % FROM_LOOP_MIN_NEEDED_FROM != 0
+	      || ((data->__flags & __GCONV_IS_LAST)
+		  && (uintptr_t) outbuf % FROM_LOOP_MIN_NEEDED_TO != 0)))
+	 || (!FROM_DIRECTION
+	     && (((data->__flags & __GCONV_IS_LAST)
+		  && (uintptr_t) outbuf % TO_LOOP_MIN_NEEDED_TO != 0)
+		 || (uintptr_t) inptr % TO_LOOP_MIN_NEEDED_FROM != 0)));
+#endif
+
+      while (1)
+	{
+	  /* Remember the start value for this round.  */
+	  inptr = *inptrp;
+	  /* The outbuf buffer is empty.  */
+	  outstart = outbuf;
+
+#ifdef SAVE_RESET_STATE
+	  SAVE_RESET_STATE (1);
+#endif
+
+	  if (__glibc_likely (!unaligned))
+	    {
+	      if (FROM_DIRECTION)
+		/* Run the conversion loop.  */
+		status = FROM_LOOP (step, data, inptrp, inend, &outbuf, outend,
+				    lirreversiblep EXTRA_LOOP_ARGS);
+	      else
+		/* Run the conversion loop.  */
+		status = TO_LOOP (step, data, inptrp, inend, &outbuf, outend,
+				  lirreversiblep EXTRA_LOOP_ARGS);
+	    }
+#if POSSIBLY_UNALIGNED
+	  else
+	    {
+	      if (FROM_DIRECTION)
+		/* Run the conversion loop.  */
+		status = GEN_unaligned (FROM_LOOP) (step, data, inptrp, inend,
+						    &outbuf, outend,
+						    lirreversiblep
+						    EXTRA_LOOP_ARGS);
+	      else
+		/* Run the conversion loop.  */
+		status = GEN_unaligned (TO_LOOP) (step, data, inptrp, inend,
+						  &outbuf, outend,
+						  lirreversiblep
+						  EXTRA_LOOP_ARGS);
+	    }
+#endif
+
+	  /* If we were called as part of an error handling module we
+	     don't do anything else here.  */
+	  if (__glibc_unlikely (outbufstart != NULL))
+	    {
+	      *outbufstart = outbuf;
+	      return status;
+	    }
+
+	  /* We finished one use of the loops.  */
+	  ++data->__invocation_counter;
+
+	  /* If this is the last step leave the loop, there is nothing
+	     we can do.  */
+	  if (__glibc_unlikely (data->__flags & __GCONV_IS_LAST))
+	    {
+	      /* Store information about how many bytes are available.  */
+	      data->__outbuf = outbuf;
+
+	      /* Remember how many non-identical characters we
+		 converted in an irreversible way.  */
+	      *irreversible += lirreversible;
+
+	      break;
+	    }
+
+	  /* Write out all output which was produced.  */
+	  if (__glibc_likely (outbuf > outstart))
+	    {
+	      const unsigned char *outerr = data->__outbuf;
+	      int result;
+
+	      result = DL_CALL_FCT (fct, (next_step, next_data, &outerr,
+					  outbuf, NULL, irreversible, 0,
+					  consume_incomplete));
+
+	      if (result != __GCONV_EMPTY_INPUT)
+		{
+		  if (__glibc_unlikely (outerr != outbuf))
+		    {
+#ifdef RESET_INPUT_BUFFER
+		      RESET_INPUT_BUFFER;
+#else
+		      /* We have a problem in one of the functions below.
+			 Undo the conversion upto the error point.  */
+		      size_t nstatus __attribute__ ((unused));
+
+		      /* Reload the pointers.  */
+		      *inptrp = inptr;
+		      outbuf = outstart;
+
+		      /* Restore the state.  */
+# ifdef SAVE_RESET_STATE
+		      SAVE_RESET_STATE (0);
+# endif
+
+		      if (__glibc_likely (!unaligned))
+			{
+			  if (FROM_DIRECTION)
+			    /* Run the conversion loop.  */
+			    nstatus = FROM_LOOP (step, data, inptrp, inend,
+						 &outbuf, outerr,
+						 lirreversiblep
+						 EXTRA_LOOP_ARGS);
+			  else
+			    /* Run the conversion loop.  */
+			    nstatus = TO_LOOP (step, data, inptrp, inend,
+					       &outbuf, outerr,
+					       lirreversiblep
+					       EXTRA_LOOP_ARGS);
+			}
+# if POSSIBLY_UNALIGNED
+		      else
+			{
+			  if (FROM_DIRECTION)
+			    /* Run the conversion loop.  */
+			    nstatus = GEN_unaligned (FROM_LOOP) (step, data,
+								 inptrp, inend,
+								 &outbuf,
+								 outerr,
+								 lirreversiblep
+								 EXTRA_LOOP_ARGS);
+			  else
+			    /* Run the conversion loop.  */
+			    nstatus = GEN_unaligned (TO_LOOP) (step, data,
+							       inptrp, inend,
+							       &outbuf, outerr,
+							       lirreversiblep
+							       EXTRA_LOOP_ARGS);
+			}
+# endif
+
+		      /* We must run out of output buffer space in this
+			 rerun.  */
+		      assert (outbuf == outerr);
+		      assert (nstatus == __GCONV_FULL_OUTPUT);
+
+		      /* If we haven't consumed a single byte decrement
+			 the invocation counter.  */
+		      if (__glibc_unlikely (outbuf == outstart))
+			--data->__invocation_counter;
+#endif	/* reset input buffer */
+		    }
+
+		  /* Change the status.  */
+		  status = result;
+		}
+	      else
+		/* All the output is consumed, we can make another run
+		   if everything was ok.  */
+		if (status == __GCONV_FULL_OUTPUT)
+		  {
+		    status = __GCONV_OK;
+		    outbuf = data->__outbuf;
+		  }
+	    }
+
+	  if (status != __GCONV_OK)
+	    break;
+
+	  /* Reset the output buffer pointer for the next round.  */
+	  outbuf = data->__outbuf;
+	}
+
+#ifdef END_LOOP
+      END_LOOP
+#endif
+
+      /* If we are supposed to consume all character store now all of the
+	 remaining characters in the `state' object.  */
+#if FROM_LOOP_MAX_NEEDED_FROM > 1 || TO_LOOP_MAX_NEEDED_FROM > 1
+      if (((FROM_LOOP_MAX_NEEDED_FROM > 1 && TO_LOOP_MAX_NEEDED_FROM > 1)
+	   || (FROM_LOOP_MAX_NEEDED_FROM > 1 && FROM_DIRECTION)
+	   || (TO_LOOP_MAX_NEEDED_FROM > 1 && !FROM_DIRECTION))
+	  && __builtin_expect (consume_incomplete, 0)
+	  && status == __GCONV_INCOMPLETE_INPUT)
+	{
+# ifdef STORE_REST
+	  mbstate_t *state = data->__statep;
+
+	  STORE_REST
+# else
+	  /* Make sure the remaining bytes fit into the state objects
+	     buffer.  */
+	  assert (inend - *inptrp < 4);
+
+	  size_t cnt;
+	  for (cnt = 0; *inptrp < inend; ++cnt)
+	    data->__statep->__value.__wchb[cnt] = *(*inptrp)++;
+	  data->__statep->__count &= ~7;
+	  data->__statep->__count |= cnt;
+# endif
+	}
+#endif
+#undef unaligned
+#undef POSSIBLY_UNALIGNED
+    }
+
+  return status;
+}
+
+#undef DEFINE_INIT
+#undef CHARSET_NAME
+#undef DEFINE_FINI
+#undef MIN_NEEDED_FROM
+#undef MIN_NEEDED_TO
+#undef MAX_NEEDED_FROM
+#undef MAX_NEEDED_TO
+#undef FROM_LOOP_MIN_NEEDED_FROM
+#undef FROM_LOOP_MAX_NEEDED_FROM
+#undef FROM_LOOP_MIN_NEEDED_TO
+#undef FROM_LOOP_MAX_NEEDED_TO
+#undef TO_LOOP_MIN_NEEDED_FROM
+#undef TO_LOOP_MAX_NEEDED_FROM
+#undef TO_LOOP_MIN_NEEDED_TO
+#undef TO_LOOP_MAX_NEEDED_TO
+#undef FROM_DIRECTION
+#undef EMIT_SHIFT_TO_INIT
+#undef FROM_LOOP
+#undef TO_LOOP
+#undef ONE_DIRECTION
+#undef SAVE_RESET_STATE
+#undef RESET_INPUT_BUFFER
+#undef FUNCTION_NAME
+#undef PREPARE_LOOP
+#undef END_LOOP
+#undef EXTRA_LOOP_ARGS
+#undef STORE_REST
+#undef FROM_ONEBYTE
diff --git a/REORG.TODO/iconv/strtab.c b/REORG.TODO/iconv/strtab.c
new file mode 100644
index 0000000000..89b28c5dde
--- /dev/null
+++ b/REORG.TODO/iconv/strtab.c
@@ -0,0 +1,339 @@
+/* C string table handling.
+   Copyright (C) 2000-2017 Free Software Foundation, Inc.
+   Written by Ulrich Drepper <drepper@redhat.com>, 2000.
+
+   This program is free software; you can redistribute it and/or modify
+   it under the terms of the GNU General Public License as published by
+   the Free Software Foundation; either version 2, or (at your option)
+   any later version.
+
+   This program 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 General Public License for more details.
+
+   You should have received a copy of the GNU General Public License
+   along with this program; if not, see <http://www.gnu.org/licenses/>.  */
+
+#ifdef HAVE_CONFIG_H
+# include <config.h>
+#endif
+
+#include <assert.h>
+#include <inttypes.h>
+#include <stddef.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+#include <sys/cdefs.h>
+#include <sys/param.h>
+
+
+struct Strent
+{
+  const char *string;
+  size_t len;
+  struct Strent *next;
+  struct Strent *left;
+  struct Strent *right;
+  size_t offset;
+  char reverse[0];
+};
+
+
+struct memoryblock
+{
+  struct memoryblock *next;
+  char memory[0];
+};
+
+
+struct Strtab
+{
+  struct Strent *root;
+  struct memoryblock *memory;
+  char *backp;
+  size_t left;
+  size_t total;
+
+  struct Strent null;
+};
+
+
+/* Cache for the pagesize.  We correct this value a bit so that `malloc'
+   is not allocating more than a page.  */
+static size_t ps;
+
+
+#include <programs/xmalloc.h>
+
+/* Prototypes for our functions that are used from iconvconfig.c.  If
+   you change these, change also iconvconfig.c.  */
+/* Create new C string table object in memory.  */
+extern struct Strtab *strtabinit (void);
+
+/* Free resources allocated for C string table ST.  */
+extern void strtabfree (struct Strtab *st);
+
+/* Add string STR (length LEN is != 0) to C string table ST.  */
+extern struct Strent *strtabadd (struct Strtab *st, const char *str,
+				 size_t len);
+
+/* Finalize string table ST and store size in *SIZE and return a pointer.  */
+extern void *strtabfinalize (struct Strtab *st, size_t *size);
+
+/* Get offset in string table for string associated with SE.  */
+extern size_t strtaboffset (struct Strent *se);
+
+
+struct Strtab *
+strtabinit (void)
+{
+  struct Strtab *ret;
+
+  if (ps == 0)
+    {
+      ps = sysconf (_SC_PAGESIZE) - 2 * sizeof (void *);
+      assert (sizeof (struct memoryblock) < ps);
+    }
+
+  ret = (struct Strtab *) calloc (1, sizeof (struct Strtab));
+  if (ret != NULL)
+    {
+      ret->null.len = 1;
+      ret->null.string = "";
+    }
+  return ret;
+}
+
+
+static void
+morememory (struct Strtab *st, size_t len)
+{
+  struct memoryblock *newmem;
+
+  if (len < ps)
+    len = ps;
+  newmem = (struct memoryblock *) malloc (len);
+  if (newmem == NULL)
+    abort ();
+
+  newmem->next = st->memory;
+  st->memory = newmem;
+  st->backp = newmem->memory;
+  st->left = len - offsetof (struct memoryblock, memory);
+}
+
+
+void
+strtabfree (struct Strtab *st)
+{
+  struct memoryblock *mb = st->memory;
+
+  while (mb != NULL)
+    {
+      void *old = mb;
+      mb = mb->next;
+      free (old);
+    }
+
+  free (st);
+}
+
+
+static struct Strent *
+newstring (struct Strtab *st, const char *str, size_t len)
+{
+  struct Strent *newstr;
+  size_t align;
+  int i;
+
+  /* Compute the amount of padding needed to make the structure aligned.  */
+  align = ((__alignof__ (struct Strent)
+	    - (((uintptr_t) st->backp)
+	       & (__alignof__ (struct Strent) - 1)))
+	   & (__alignof__ (struct Strent) - 1));
+
+  /* Make sure there is enough room in the memory block.  */
+  if (st->left < align + sizeof (struct Strent) + len)
+    {
+      morememory (st, sizeof (struct Strent) + len);
+      align = 0;
+    }
+
+  /* Create the reserved string.  */
+  newstr = (struct Strent *) (st->backp + align);
+  newstr->string = str;
+  newstr->len = len;
+  newstr->next = NULL;
+  newstr->left = NULL;
+  newstr->right = NULL;
+  newstr->offset = 0;
+  for (i = len - 2; i >= 0; --i)
+    newstr->reverse[i] = str[len - 2 - i];
+  newstr->reverse[len - 1] = '\0';
+  st->backp += align + sizeof (struct Strent) + len;
+  st->left -= align + sizeof (struct Strent) + len;
+
+  return newstr;
+}
+
+
+/* XXX This function should definitely be rewritten to use a balancing
+   tree algorithm (AVL, red-black trees).  For now a simple, correct
+   implementation is enough.  */
+static struct Strent **
+searchstring (struct Strent **sep, struct Strent *newstr)
+{
+  int cmpres;
+
+  /* More strings?  */
+  if (*sep == NULL)
+    {
+      *sep = newstr;
+      return sep;
+    }
+
+  /* Compare the strings.  */
+  cmpres = memcmp ((*sep)->reverse, newstr->reverse,
+		   MIN ((*sep)->len, newstr->len) - 1);
+  if (cmpres == 0)
+    /* We found a matching string.  */
+    return sep;
+  else if (cmpres > 0)
+    return searchstring (&(*sep)->left, newstr);
+  else
+    return searchstring (&(*sep)->right, newstr);
+}
+
+
+/* Add new string.  The actual string is assumed to be permanent.  */
+struct Strent *
+strtabadd (struct Strtab *st, const char *str, size_t len)
+{
+  struct Strent *newstr;
+  struct Strent **sep;
+
+  /* Compute the string length if the caller doesn't know it.  */
+  if (len == 0)
+    len = strlen (str) + 1;
+
+  /* Make sure all "" strings get offset 0.  */
+  if (len == 1)
+    return &st->null;
+
+  /* Allocate memory for the new string and its associated information.  */
+  newstr = newstring (st, str, len);
+
+  /* Search in the array for the place to insert the string.  If there
+     is no string with matching prefix and no string with matching
+     leading substring, create a new entry.  */
+  sep = searchstring (&st->root, newstr);
+  if (*sep != newstr)
+    {
+      /* This is not the same entry.  This means we have a prefix match.  */
+      if ((*sep)->len > newstr->len)
+	{
+	  struct Strent *subs;
+
+	  for (subs = (*sep)->next; subs; subs = subs->next)
+	    if (subs->len == newstr->len)
+	      {
+		/* We have an exact match with a substring.  Free the memory
+		   we allocated.  */
+		st->left += st->backp - (char *) newstr;
+		st->backp = (char *) newstr;
+
+		return subs;
+	      }
+
+	  /* We have a new substring.  This means we don't need the reverse
+	     string of this entry anymore.  */
+	  st->backp -= newstr->len;
+	  st->left += newstr->len;
+
+	  newstr->next = (*sep)->next;
+	  (*sep)->next = newstr;
+	}
+      else if ((*sep)->len != newstr->len)
+	{
+	  /* When we get here it means that the string we are about to
+	     add has a common prefix with a string we already have but
+	     it is longer.  In this case we have to put it first.  */
+	  st->total += newstr->len - (*sep)->len;
+	  newstr->next = *sep;
+	  newstr->left = (*sep)->left;
+	  newstr->right = (*sep)->right;
+	  *sep = newstr;
+	}
+      else
+	{
+	  /* We have an exact match.  Free the memory we allocated.  */
+	  st->left += st->backp - (char *) newstr;
+	  st->backp = (char *) newstr;
+
+	  newstr = *sep;
+	}
+    }
+  else
+    st->total += newstr->len;
+
+  return newstr;
+}
+
+
+static void
+copystrings (struct Strent *nodep, char **freep, size_t *offsetp)
+{
+  struct Strent *subs;
+
+  if (nodep->left != NULL)
+    copystrings (nodep->left, freep, offsetp);
+
+  /* Process the current node.  */
+  nodep->offset = *offsetp;
+  *freep = (char *) mempcpy (*freep, nodep->string, nodep->len);
+  *offsetp += nodep->len;
+
+  for (subs = nodep->next; subs != NULL; subs = subs->next)
+    {
+      assert (subs->len < nodep->len);
+      subs->offset = nodep->offset + nodep->len - subs->len;
+    }
+
+  if (nodep->right != NULL)
+    copystrings (nodep->right, freep, offsetp);
+}
+
+
+void *
+strtabfinalize (struct Strtab *st, size_t *size)
+{
+  size_t copylen;
+  char *endp;
+  char *retval;
+
+  /* Fill in the information.  */
+  endp = retval = (char *) xmalloc (st->total + 1);
+
+  /* Always put an empty string at the beginning so that a zero offset
+     can mean error.  */
+  *endp++ = '\0';
+
+  /* Now run through the tree and add all the string while also updating
+     the offset members of the elfstrent records.  */
+  copylen = 1;
+  copystrings (st->root, &endp, &copylen);
+  assert (copylen == st->total + 1);
+  assert (endp == retval + st->total + 1);
+  *size = copylen;
+
+  return retval;
+}
+
+
+size_t
+strtaboffset (struct Strent *se)
+{
+  return se->offset;
+}
diff --git a/REORG.TODO/iconv/tst-iconv1.c b/REORG.TODO/iconv/tst-iconv1.c
new file mode 100644
index 0000000000..0609f50e50
--- /dev/null
+++ b/REORG.TODO/iconv/tst-iconv1.c
@@ -0,0 +1,47 @@
+/* Test case by yaoz@nih.gov.  */
+
+#include <iconv.h>
+#include <stddef.h>
+#include <stdio.h>
+#include <string.h>
+
+static int
+do_test (void)
+{
+  char utf8[5];
+  wchar_t ucs4[5];
+  iconv_t cd;
+  char *inbuf;
+  char *outbuf;
+  size_t inbytes;
+  size_t outbytes;
+  size_t n;
+
+  strcpy (utf8, "abcd");
+
+  /* From UTF8 to UCS4. */
+  cd = iconv_open ("UCS4", "UTF8");
+  if (cd == (iconv_t) -1)
+    {
+      perror ("iconv_open");
+      return 1;
+    }
+
+  inbuf = utf8;
+  inbytes = 4;
+  outbuf = (char *) ucs4;
+  outbytes = 4 * sizeof (wchar_t);    /* "Argument list too long" error. */
+  n = iconv (cd, &inbuf, &inbytes, &outbuf, &outbytes);
+  if (n == (size_t) -1)
+    {
+      printf ("iconv: %m\n");
+      iconv_close (cd);
+      return 1;
+    }
+  iconv_close (cd);
+
+  return 0;
+}
+
+#define TEST_FUNCTION do_test ()
+#include "../test-skeleton.c"
diff --git a/REORG.TODO/iconv/tst-iconv2.c b/REORG.TODO/iconv/tst-iconv2.c
new file mode 100644
index 0000000000..af78d78350
--- /dev/null
+++ b/REORG.TODO/iconv/tst-iconv2.c
@@ -0,0 +1,102 @@
+/* Copyright (C) 2001-2017 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+   Contributed by Ulrich Drepper <drepper@cygnus.com>, 2001.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 2.1 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
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with the GNU C Library; if not, see
+   <http://www.gnu.org/licenses/>.  */
+
+#include <errno.h>
+#include <iconv.h>
+#include <mcheck.h>
+#include <stddef.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+
+static int
+do_test (void)
+{
+  char buf[3];
+  const wchar_t wc[1] = L"a";
+  iconv_t cd;
+  char *inptr;
+  size_t inlen;
+  char *outptr;
+  size_t outlen;
+  size_t n;
+  int e;
+  int result = 0;
+
+  mtrace ();
+
+  cd = iconv_open ("UCS4", "WCHAR_T");
+  if (cd == (iconv_t) -1)
+    {
+      printf ("cannot convert from wchar_t to UCS4: %m\n");
+      exit (1);
+    }
+
+  inptr = (char *) wc;
+  inlen = sizeof (wchar_t);
+  outptr = buf;
+  outlen = 3;
+
+  n = iconv (cd, &inptr, &inlen, &outptr, &outlen);
+  e = errno;
+
+  if (n != (size_t) -1)
+    {
+      printf ("incorrect iconv() return value: %zd, expected -1\n", n);
+      result = 1;
+    }
+
+  if (e != E2BIG)
+    {
+      printf ("incorrect error value: %s, expected %s\n",
+	      strerror (e), strerror (E2BIG));
+      result = 1;
+    }
+
+  if (inptr != (char *) wc)
+    {
+      puts ("inptr changed");
+      result = 1;
+    }
+
+  if (inlen != sizeof (wchar_t))
+    {
+      puts ("inlen changed");
+      result = 1;
+    }
+
+  if (outptr != buf)
+    {
+      puts ("outptr changed");
+      result = 1;
+    }
+
+  if (outlen != 3)
+    {
+      puts ("outlen changed");
+      result = 1;
+    }
+
+  iconv_close (cd);
+
+  return result;
+}
+
+#define TEST_FUNCTION do_test ()
+#include "../test-skeleton.c"
diff --git a/REORG.TODO/iconv/tst-iconv3.c b/REORG.TODO/iconv/tst-iconv3.c
new file mode 100644
index 0000000000..b06f75f0bc
--- /dev/null
+++ b/REORG.TODO/iconv/tst-iconv3.c
@@ -0,0 +1,56 @@
+/* Contributed by Owen Taylor <otaylor@redhat.com>.  */
+
+#include <iconv.h>
+#include <errno.h>
+#include <stddef.h>
+#include <stdio.h>
+
+#define BUFSIZE 10000
+
+static int
+do_test (void)
+{
+  char inbuf[BUFSIZE];
+  wchar_t outbuf[BUFSIZE];
+
+  iconv_t cd;
+  int i;
+  char *inptr;
+  char *outptr;
+  size_t inbytes_left, outbytes_left;
+  int count;
+  int result = 0;
+
+  for (i=0; i < BUFSIZE; i++)
+    inbuf[i] = 'a';
+
+  cd = iconv_open ("UCS-4LE", "UTF-8");
+
+  inbytes_left = BUFSIZE;
+  outbytes_left = BUFSIZE * 4;
+  inptr = inbuf;
+  outptr = (char *) outbuf;
+
+  count = iconv (cd, &inptr, &inbytes_left, &outptr, &outbytes_left);
+
+  if (count < 0)
+    {
+      if (errno == E2BIG)
+	printf ("Received E2BIG\n");
+      else
+	printf ("Received something else\n");
+
+      printf ("inptr change: %td\n", inptr - inbuf);
+      printf ("inlen change: %zd\n", BUFSIZE - inbytes_left);
+      printf ("outptr change: %td\n", outptr - (char *) outbuf);
+      printf ("outlen change: %zd\n", BUFSIZE * 4 - outbytes_left);
+      result = 1;
+    }
+  else
+    printf ("Succeeded\n");
+
+  return result;
+}
+
+#define TEST_FUNCTION do_test ()
+#include "../test-skeleton.c"
diff --git a/REORG.TODO/iconv/tst-iconv4.c b/REORG.TODO/iconv/tst-iconv4.c
new file mode 100644
index 0000000000..b5ff39306c
--- /dev/null
+++ b/REORG.TODO/iconv/tst-iconv4.c
@@ -0,0 +1,65 @@
+// Derived from BZ #9793
+#include <errno.h>
+#include <iconv.h>
+#include <stdio.h>
+
+
+static int
+do_test (void)
+{
+  iconv_t cd = iconv_open ("ASCII//TRANSLIT", "UTF-8");
+  if (cd == (iconv_t) -1)
+    {
+      puts ("iconv_open failed");
+      return 1;
+    }
+
+  char input[2] = { 0xc2, 0xae };	/* Registered trademark */
+  char *inptr = input;
+  size_t insize = sizeof (input);
+  char output[2];			/* Too short to contain "(R)".  */
+  char *outptr = output;
+  size_t outsize = sizeof (output);
+
+  size_t ret = iconv (cd, &inptr, &insize, &outptr, &outsize);
+  if (ret != (size_t) -1)
+    {
+      puts ("iconv succeeded");
+      return 1;
+    }
+  if (errno != E2BIG)
+    {
+      puts ("iconv did not set errno to E2BIG");
+      return 1;
+    }
+  int res = 0;
+  if (inptr != input)
+    {
+      puts ("inptr changed");
+      res = 1;
+    }
+  if (insize != sizeof (input))
+    {
+      puts ("insize changed");
+      res = 1;
+    }
+  if (outptr != output)
+    {
+      puts ("outptr changed");
+      res = 1;
+    }
+  if (outsize != sizeof (output))
+    {
+      puts ("outsize changed");
+      res = 1;
+    }
+  if (iconv_close (cd) == -1)
+    {
+      puts ("iconv_close failed");
+      res = 1;
+    }
+  return res;
+}
+
+#define TEST_FUNCTION do_test ()
+#include "../test-skeleton.c"
diff --git a/REORG.TODO/iconv/tst-iconv5.c b/REORG.TODO/iconv/tst-iconv5.c
new file mode 100644
index 0000000000..52f93d6695
--- /dev/null
+++ b/REORG.TODO/iconv/tst-iconv5.c
@@ -0,0 +1,161 @@
+/* Copyright (C) 2004-2017 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+   Contributed by GOTO Masanori <gotom@debian.or.jp>, 2004
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 2.1 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
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with the GNU C Library; if not, see
+   <http://www.gnu.org/licenses/>.  */
+
+#include <iconv.h>
+#include <string.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <errno.h>
+
+#define SIZE 256		/* enough room for conversion */
+#define SAMPLESTR "abc"
+
+struct unalign
+{
+  char str1[1];
+  char str2[SIZE];
+};
+
+struct convcode
+{
+  const char *tocode;
+  const char *fromcode;
+};
+
+/* test builtin transformation */
+static const struct convcode testcode[] = {
+  {"ASCII", "ASCII"},
+  {"UTF-8", "ASCII"},
+  {"UCS-2BE", "ASCII"},
+  {"UCS-2LE", "ASCII"},
+  {"UCS-4BE", "ASCII"},
+  {"UCS-4LE", "ASCII"},
+};
+
+static const int number = (int) sizeof (testcode) / sizeof (struct convcode);
+
+static int
+convert (const char *tocode, const char *fromcode, char *inbufp,
+	 size_t inbytesleft, char *outbufp, size_t outbytesleft)
+{
+  iconv_t *ic;
+  size_t outbytes = outbytesleft;
+  int ret;
+
+  ic = iconv_open (tocode, fromcode);
+  if (ic == (iconv_t *) - 1)
+    {
+      printf ("iconv_open failed: from: %s, to: %s: %s",
+	      fromcode, tocode, strerror (errno));
+      return -1;
+    }
+
+  while (inbytesleft > 0)
+    {
+      ret = iconv (ic, &inbufp, &inbytesleft, &outbufp, &outbytes);
+      if (ret == -1)
+	{
+	  printf ("iconv failed: from: %s, to: %s: %s",
+		  fromcode, tocode, strerror (errno));
+	  return -1;
+	}
+    }
+
+  ret = iconv_close (ic);
+  if (ret == -1)
+    {
+      printf ("iconv_close failed: from: %s, to: %s: %s",
+	      fromcode, tocode, strerror (errno));
+      return -1;
+    }
+
+  return outbytesleft - outbytes;
+}
+
+
+static int
+test_unalign (const struct convcode *codes, const char *str, int len)
+{
+  struct unalign *inbufp, *outbufp;
+  char *inbuf, *outbuf;
+  size_t inbytesleft, outbytesleft;
+  int retlen;
+
+  /* allocating unaligned buffer for both inbuf and outbuf */
+  inbufp = (struct unalign *) malloc (sizeof (struct unalign));
+  if (!inbufp)
+    {
+      printf ("no memory available\n");
+      exit (1);
+    }
+  inbuf = inbufp->str2;
+
+  outbufp = (struct unalign *) malloc (sizeof (struct unalign));
+  if (!outbufp)
+    {
+      printf ("no memory available\n");
+      exit (1);
+    }
+  outbuf = outbufp->str2;
+
+  /* first iconv phase */
+  memcpy (inbuf, str, len);
+  inbytesleft = len;
+  outbytesleft = sizeof (struct unalign);
+  retlen = convert (codes->tocode, codes->fromcode, inbuf, inbytesleft,
+		    outbuf, outbytesleft);
+  if (retlen == -1)	/* failed */
+    return 1;
+
+  /* second round trip iconv phase */
+  memcpy (inbuf, outbuf, retlen);
+  inbytesleft = retlen;
+  outbytesleft = sizeof (struct unalign);
+  retlen = convert (codes->fromcode, codes->tocode, inbuf, inbytesleft,
+		    outbuf, outbytesleft);
+  if (retlen == -1)	/* failed */
+    return 1;
+
+  free (inbufp);
+  free (outbufp);
+
+  return 0;
+}
+
+static int
+do_test (void)
+{
+  int i;
+  int ret = 0;
+
+  for (i = 0; i < number; i++)
+    {
+      ret = test_unalign (&testcode[i], (char *) SAMPLESTR, sizeof (SAMPLESTR));
+      if (ret)
+	break;
+      printf ("iconv: %s <-> %s: ok\n",
+	      testcode[i].fromcode, testcode[i].tocode);
+    }
+  if (ret == 0)
+    printf ("Succeeded.\n");
+
+  return ret;
+}
+
+#define TEST_FUNCTION do_test ()
+#include "../test-skeleton.c"
diff --git a/REORG.TODO/iconv/tst-iconv6.c b/REORG.TODO/iconv/tst-iconv6.c
new file mode 100644
index 0000000000..ace7dc68b2
--- /dev/null
+++ b/REORG.TODO/iconv/tst-iconv6.c
@@ -0,0 +1,118 @@
+/* Testing ucs4le_internal_loop() in gconv_simple.c.
+   Copyright (C) 2016-2017 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
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 2.1 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
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with the GNU C Library; if not, see
+   <http://www.gnu.org/licenses/>.  */
+
+#include <stdio.h>
+#include <errno.h>
+#include <string.h>
+#include <inttypes.h>
+#include <iconv.h>
+#include <byteswap.h>
+#include <endian.h>
+
+static int
+do_test (void)
+{
+  iconv_t cd;
+  char *inptr;
+  size_t inlen;
+  char *outptr;
+  size_t outlen;
+  size_t n;
+  int e;
+  int result = 0;
+
+#if __BYTE_ORDER == __BIG_ENDIAN
+  /* On big-endian machines, ucs4le_internal_loop() swaps the bytes before
+     error checking. Thus the input values has to be swapped.  */
+# define VALUE(val) bswap_32 (val)
+#else
+# define VALUE(val) val
+#endif
+  uint32_t inbuf[3] = { VALUE (0x41), VALUE (0x80000000), VALUE (0x42) };
+  uint32_t outbuf[3] = { 0, 0, 0 };
+
+  cd = iconv_open ("WCHAR_T", "UCS-4LE");
+  if (cd == (iconv_t) -1)
+    {
+      printf ("cannot convert from UCS4LE to wchar_t: %m\n");
+      return 1;
+    }
+
+  inptr = (char *) inbuf;
+  inlen = sizeof (inbuf);
+  outptr = (char *) outbuf;
+  outlen = sizeof (outbuf);
+
+  n = iconv (cd, &inptr, &inlen, &outptr, &outlen);
+  e = errno;
+
+  if (n != (size_t) -1)
+    {
+      printf ("incorrect iconv() return value: %zd, expected -1\n", n);
+      result = 1;
+    }
+
+  if (e != EILSEQ)
+    {
+      printf ("incorrect error value: %s, expected %s\n",
+	      strerror (e), strerror (EILSEQ));
+      result = 1;
+    }
+
+  if (inptr != (char *) &inbuf[1])
+    {
+      printf ("inptr=0x%p does not point to invalid character! Expected=0x%p\n"
+	      , inptr, &inbuf[1]);
+      result = 1;
+    }
+
+  if (inlen != sizeof (inbuf) - sizeof (uint32_t))
+    {
+      printf ("inlen=%zd != %zd\n"
+	      , inlen, sizeof (inbuf) - sizeof (uint32_t));
+      result = 1;
+    }
+
+  if (outptr != (char *) &outbuf[1])
+    {
+      printf ("outptr=0x%p does not point to invalid character in inbuf! "
+	      "Expected=0x%p\n"
+	      , outptr, &outbuf[1]);
+      result = 1;
+    }
+
+  if (outlen != sizeof (inbuf) - sizeof (uint32_t))
+    {
+      printf ("outlen=%zd != %zd\n"
+	      , outlen, sizeof (outbuf) - sizeof (uint32_t));
+      result = 1;
+    }
+
+  if (outbuf[0] != 0x41 || outbuf[1] != 0 || outbuf[2] != 0)
+    {
+      puts ("Characters conversion is incorrect!");
+      result = 1;
+    }
+
+  iconv_close (cd);
+
+  return result;
+}
+
+#define TEST_FUNCTION do_test ()
+#include "../test-skeleton.c"