summary refs log tree commit diff
diff options
context:
space:
mode:
-rw-r--r--ChangeLog238
-rw-r--r--FAQ34
-rw-r--r--FAQ.in32
-rw-r--r--bits/socket.h5
-rw-r--r--csu/init.c4
-rw-r--r--db2/compat.h1
-rw-r--r--elf/dl-minimal.c5
-rw-r--r--iconv/Makefile10
-rw-r--r--iconv/gconv.c53
-rw-r--r--iconv/gconv.h14
-rw-r--r--iconv/gconv_builtin.c17
-rw-r--r--iconv/gconv_builtin.h21
-rw-r--r--iconv/gconv_conf.c4
-rw-r--r--iconv/gconv_db.c8
-rw-r--r--iconv/gconv_int.h13
-rw-r--r--iconv/gconv_open.c17
-rw-r--r--iconv/gconv_simple.c1220
-rw-r--r--iconv/iconv.c19
-rw-r--r--iconv/iconv_prog.c9
-rw-r--r--iconv/loop.c226
-rw-r--r--iconv/skeleton.c328
-rw-r--r--iconvdata/8bit-gap.c255
-rw-r--r--iconvdata/8bit-generic.c236
-rw-r--r--iconvdata/Makefile6
-rw-r--r--iconvdata/big5.c451
-rw-r--r--iconvdata/cns11643.c6
-rw-r--r--iconvdata/cns11643.h220
-rw-r--r--iconvdata/cns11643l1.c30
-rw-r--r--iconvdata/cns11643l1.h210
-rw-r--r--iconvdata/ebcdic-at-de-a.c11
-rw-r--r--iconvdata/ebcdic-at-de.c11
-rw-r--r--iconvdata/ebcdic-ca-fr.c11
-rw-r--r--iconvdata/euccn.c376
-rw-r--r--iconvdata/eucjp.c480
-rw-r--r--iconvdata/euckr.c377
-rw-r--r--iconvdata/euctw.c459
-rw-r--r--iconvdata/gb2312.c20
-rw-r--r--iconvdata/gb2312.h251
-rw-r--r--iconvdata/hp-roman8.c11
-rw-r--r--iconvdata/iso646.c12
-rw-r--r--iconvdata/iso6937.c464
-rw-r--r--iconvdata/iso8859-1.c217
-rw-r--r--iconvdata/iso8859-10.c10
-rw-r--r--iconvdata/iso8859-2.c10
-rw-r--r--iconvdata/iso8859-3.c10
-rw-r--r--iconvdata/iso8859-4.c10
-rw-r--r--iconvdata/iso8859-5.c10
-rw-r--r--iconvdata/iso8859-6.c10
-rw-r--r--iconvdata/iso8859-7.c10
-rw-r--r--iconvdata/iso8859-8.c10
-rw-r--r--iconvdata/iso8859-9.c10
-rw-r--r--iconvdata/jis0201.c6
-rw-r--r--iconvdata/jis0201.h8
-rw-r--r--iconvdata/jis0208.c16
-rw-r--r--iconvdata/jis0208.h34
-rw-r--r--iconvdata/jis0212.c13
-rw-r--r--iconvdata/jis0212.h32
-rw-r--r--iconvdata/johab.c546
-rw-r--r--iconvdata/koi-8.c10
-rw-r--r--iconvdata/koi8-r.c11
-rw-r--r--iconvdata/ksc5601.c12
-rw-r--r--iconvdata/ksc5601.h53
-rw-r--r--iconvdata/latin-greek-1.c9
-rw-r--r--iconvdata/latin-greek.c9
-rwxr-xr-xiconvdata/run-iconv-test.sh10
-rw-r--r--iconvdata/sjis.c407
-rw-r--r--iconvdata/t61.c370
-rw-r--r--iconvdata/uhc.c448
-rw-r--r--inet/netinet/in.h16
-rw-r--r--libc.map6
-rw-r--r--libio/fileops.c1
-rw-r--r--libio/oldfileops.c2
-rw-r--r--linuxthreads/ChangeLog11
-rw-r--r--linuxthreads/Makefile4
-rw-r--r--linuxthreads/internals.h17
-rw-r--r--linuxthreads/ptlongjmp.c44
-rw-r--r--linuxthreads/spinlock.c59
-rw-r--r--linuxthreads/spinlock.h4
-rw-r--r--login/Makefile2
-rw-r--r--login/getutent.c3
-rw-r--r--login/getutent_r.c5
-rw-r--r--login/getutid.c3
-rw-r--r--login/getutline.c3
-rw-r--r--login/utmp.h8
-rw-r--r--manual/creature.texi2
-rw-r--r--posix/getopt.c65
-rw-r--r--posix/regex.c21
-rw-r--r--posix/wordexp-test.c19
-rw-r--r--signal/sighold.c2
-rw-r--r--signal/sigrelse.c2
-rw-r--r--stdlib/mblen.c30
-rw-r--r--stdlib/mbtowc.c24
-rw-r--r--sysdeps/arm/bits/setjmp.h18
-rw-r--r--sysdeps/arm/strlen.S55
-rw-r--r--sysdeps/generic/bits/socket.h5
-rw-r--r--sysdeps/generic/endutxent.c (renamed from sysdeps/generic/bits/utmpx.h)27
-rw-r--r--sysdeps/generic/getutxent.c27
-rw-r--r--sysdeps/generic/getutxid.c27
-rw-r--r--sysdeps/generic/getutxline.c27
-rw-r--r--sysdeps/generic/longjmp.c10
-rw-r--r--sysdeps/generic/pututxline.c27
-rw-r--r--sysdeps/generic/setjmp.c6
-rw-r--r--sysdeps/generic/setutxent.c27
-rw-r--r--sysdeps/generic/strcasestr.c5
-rw-r--r--sysdeps/generic/updwtmp.c (renamed from login/updwtmp.c)27
-rw-r--r--sysdeps/generic/updwtmpx.c27
-rw-r--r--sysdeps/generic/utmp_file.c (renamed from login/utmp_file.c)18
-rw-r--r--sysdeps/generic/utmpxname.c27
-rw-r--r--sysdeps/gnu/Makefile7
-rw-r--r--sysdeps/gnu/bits/utmpx.h19
-rw-r--r--sysdeps/gnu/updwtmp.c30
-rw-r--r--sysdeps/gnu/utmp_file.c30
-rw-r--r--sysdeps/gnu/utmpx.h (renamed from login/utmpx.h)21
-rw-r--r--sysdeps/i386/bits/setjmp.h18
-rw-r--r--sysdeps/m68k/bits/setjmp.h18
-rw-r--r--sysdeps/mach/hurd/Subdirs1
-rw-r--r--sysdeps/mach/hurd/bits/ioctls.h7
-rw-r--r--sysdeps/posix/sigignore.c2
-rw-r--r--sysdeps/posix/sigset.c2
-rw-r--r--sysdeps/posix/waitid.c4
-rw-r--r--sysdeps/powerpc/bits/setjmp.h18
-rw-r--r--sysdeps/powerpc/elf/start.c125
-rw-r--r--sysdeps/sparc/sparc32/bits/setjmp.h18
-rw-r--r--sysdeps/unix/sysv/linux/i386/s_pread64.S2
-rw-r--r--sysdeps/unix/sysv/linux/paths.h1
-rw-r--r--sysdeps/unix/sysv/linux/powerpc/dl-sysdep.c5
-rw-r--r--sysdeps/unix/sysv/linux/powerpc/syscall.h357
-rw-r--r--sysdeps/unix/sysv/linux/rt_sigsuspend.c4
-rw-r--r--sysdeps/unix/sysv/linux/rt_sigtimedwait.c4
-rw-r--r--sysdeps/unix/sysv/linux/sigwaitinfo.c4
-rw-r--r--sysdeps/unix/sysv/linux/updwtmp.c34
-rw-r--r--sysdeps/unix/sysv/linux/utmp_file.c34
-rw-r--r--wcsmbs/btowc.c8
-rw-r--r--wcsmbs/mbrtowc.c18
-rw-r--r--wcsmbs/mbsnrtowcs.c23
-rw-r--r--wcsmbs/mbsrtowcs.c23
-rw-r--r--wcsmbs/wcrtomb.c20
-rw-r--r--wcsmbs/wcsmbsload.c12
-rw-r--r--wcsmbs/wcsnrtombs.c35
-rw-r--r--wcsmbs/wcsrtombs.c35
-rw-r--r--wcsmbs/wctob.c13
141 files changed, 4524 insertions, 5617 deletions
diff --git a/ChangeLog b/ChangeLog
index 65210542a1..105bed4c21 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,241 @@
+1998-04-20 18:00  Ulrich Drepper  <drepper@cygnus.com>
+
+	* libc.map: Add __dgettext to GLIBC_2.0 and __libc_longjmp, and
+	__libc_siglongjmp to GLIBC_2.1.
+
+	* elf/dl-minimal.c (__assert_perror_fail): Don't use strerror, use
+	__strerror_r.
+
+	* iconv/Makefile: Don't run tests now.
+
+	* iconv/iconv_prog.c (process_block): If loop is repeated, call iconv
+	with correct output buffer.
+
+	Major rewrite of the low-level gconv functionality.
+	* iconv/gconv.c: Rewritten.
+	* iconv/gconv.h: Likewise.
+	* iconv/gconv_builtin.c: Likewise.
+	* iconv/gconv_builtin.h: Likewise.
+	* iconv/gconv_conf.c: Likewise.
+	* iconv/gconv_int.h: Likewise.
+	* iconv/gconv_open.c: Likewise.
+	* iconv/gconv_simple.c: Likewise.
+	* iconv/iconv.c: Likewise.
+	* iconvdata/8bit-gap.c: Likewise.
+	* iconvdata/8bit-generic.c: Likewise.
+	* iconvdata/Makefile: Likewise.
+	* iconvdata/big5.c: Likewise.
+	* iconvdata/cns11643.c: Likewise.
+	* iconvdata/cns11643.h: Likewise.
+	* iconvdata/cns11643l1.c: Likewise.
+	* iconvdata/cns11643l1.h: Likewise.
+	* iconvdata/ebcdic-at-de-a.c: Likewise.
+	* iconvdata/ebcdic-at-de.c: Likewise.
+	* iconvdata/ebcdic-ca-fr.c: Likewise.
+	* iconvdata/euccn.c: Likewise.
+	* iconvdata/eucjp.c: Likewise.
+	* iconvdata/euckr.c: Likewise.
+	* iconvdata/euctw.c: Likewise.
+	* iconvdata/gb2312.c: Likewise.
+	* iconvdata/gb2312.h: Likewise.
+	* iconvdata/hp-roman8.c: Likewise.
+	* iconvdata/iso646.c: Likewise.
+	* iconvdata/iso6937.c: Likewise.
+	* iconvdata/iso8859-1.c: Likewise.
+	* iconvdata/iso8859-10.c: Likewise.
+	* iconvdata/iso8859-2.c: Likewise.
+	* iconvdata/iso8859-3.c: Likewise.
+	* iconvdata/iso8859-4.c: Likewise.
+	* iconvdata/iso8859-5.c: Likewise.
+	* iconvdata/iso8859-6.c: Likewise.
+	* iconvdata/iso8859-7.c: Likewise.
+	* iconvdata/iso8859-8.c: Likewise.
+	* iconvdata/iso8859-9.c: Likewise.
+	* iconvdata/jis0201.c: Likewise.
+	* iconvdata/jis0201.h: Likewise.
+	* iconvdata/jis0208.c: Likewise.
+	* iconvdata/jis0208.h: Likewise.
+	* iconvdata/jis0212.c: Likewise.
+	* iconvdata/jis0212.h: Likewise.
+	* iconvdata/johab.c: Likewise.
+	* iconvdata/koi-8.c: Likewise.
+	* iconvdata/koi8-r.c: Likewise.
+	* iconvdata/ksc5601.c: Likewise.
+	* iconvdata/ksc5601.h: Likewise.
+	* iconvdata/latin-greek-1.c: Likewise.
+	* iconvdata/latin-greek.c: Likewise.
+	* iconvdata/run-iconv-test.sh: Likewise.
+	* iconvdata/sjis.c: Likewise.
+	* iconvdata/t61.c: Likewise.
+	* iconvdata/uhc.c: Likewise.
+	* wcsmbs/btowc.c: Likewise.
+	* wcsmbs/mbrtowc.c: Likewise.
+	* wcsmbs/mbsnrtowcs.c: Likewise.
+	* wcsmbs/mbsrtowcs.c: Likewise.
+	* wcsmbs/wcrtomb.c: Likewise.
+	* wcsmbs/wcsmbsload.c: Likewise.
+	* wcsmbs/wcsnrtombs.c: Likewise.
+	* wcsmbs/wcsrtombs.c: Likewise.
+	* wcsmbs/wctob.c: Likewise.
+	* iconv/loop.c: New file.
+	* iconv/skeleton.c: New file.
+
+	* stdlib/mblen.c: Handle empty input string correctly.
+	* stdlib/mbtowc.c: Likewise.
+
+	* posix/getopt.c: Various cleanups.
+
+	* sysdeps/arm/bits/setjmp.h: Add copyright text.
+	* sysdeps/i386/bits/setjmp.h: Likewise.
+	* sysdeps/m68k/bits/setjmp.h: Likewise.
+	* sysdeps/powerpc/bits/setjmp.h: Likewise.
+	* sysdeps/sparc/sparc32/bits/setjmp.h: Likewise.
+
+	* sysdeps/generic/longjmp.c: Rename function to __libc_siglongjmp
+	and make longjmp weak alias.
+
+1998-04-18 20:29  Philip Blundell  <Philip.Blundell@pobox.com>
+
+	* iconv/Makefile (routines): Only include gconv_dl if building for
+	an ELF system - dynamic linking is not available on a.out.
+	(CFLAGS-gconv_conf.c): Define STATIC_GCONV if omitting gconv_dl
+	due to above check.
+	* iconv/gconv_db.c: If STATIC_GCONV defined, don't try to call
+	routines from gconv_dl.
+
+1998-04-17  Gordon Matzigkeit  <gord@profitpress.com>
+
+	* csu/init.c (_IO_stdin_used): Protect with USE_IN_LIBIO so that
+	we can compile without libio.
+
+1998-04-20 16:28  Ulrich Drepper  <drepper@cygnus.com>
+
+	* sysdeps/mach/hurd/Subdirs: Remove login.
+
+1998-04-11  Gordon Matzigkeit  <gord@profitpress.com>
+
+	* db2/compat.h: Include <errno.h>, to make sure we get the
+	definition of EFTYPE before we define it ourselves.
+
+1998-04-10  Gordon Matzigkeit  <gord@profitpress.com>
+
+	* sysdeps/generic/bits/socket.h: Protect against multiple inclusion.
+	* sysdeps/mach/hurd/bits/ioctls.h: Likewise.
+	Fix typo to allow inclusion from sys/ioctl.h again.
+
+1998-04-16  Andreas Schwab  <schwab@issan.informatik.uni-dortmund.de>
+
+	* iconvdata/*.[ch]: Clean up namespace.  Optimize character lookup.
+
+1998-04-16  Andreas Schwab  <schwab@issan.informatik.uni-dortmund.de>
+
+	* libc.map: Export __strerror_r.  Remove _strerror_internal.
+
+1998-04-16  Andreas Schwab  <schwab@issan.informatik.uni-dortmund.de>
+
+	* sysdeps/generic/strcasestr.c: Undefine strcasestr, not strstr.
+	Also undefine __strcasestr.
+
+1998-04-16  Andreas Schwab  <schwab@issan.informatik.uni-dortmund.de>
+
+	* posix/regex.c: Rename __re_max_failures back to re_max_failures,
+	aliases do not work with global variables due to copy relocations.
+
+1998-04-20 15:12  Ulrich Drepper  <drepper@cygnus.com>
+
+	* manual/creature.texi: Fix type.  Patch by Andreas Schwab.
+
+1998-04-20 13:47  Ulrich Drepper  <drepper@cygnus.com>
+
+	* signal/sighold.c: Include stddef.h for NULL definition.
+	* signal/sigrelse.c: Likewise.
+	* sysdeps/posix/sigignore.c: Likewise.
+	* sysdeps/posix/sigset.c: Likewise.
+	* sysdeps/posix/waitid.c: Likewise.
+	* sysdeps/unix/sysv/linux/rt_sigsuspend.c: Likewise.
+	* sysdeps/unix/sysv/linux/rt_sigtimedwait.c: Likewise.
+	* sysdeps/unix/sysv/linux/sigwaitinfo.c: Likewise.
+	* wcsmbs/mbsrtowcs.c: Include stdlib.h for MB_CUR_MAX.
+	Patch by Franz Sirl <Franz.Sirl-kernel@lauterbach.com>.
+
+1998-04-13  Mark Kettenis  <kettenis@phys.uva.nl>
+
+	* login/Makefile (headers): Remove utmpx.h and bits/utmpx.h.
+	* login/getutent.c (getutxent): Remove alias.
+	* login/getutent_r.c (setutxent, pututxline, endutxent):
+	Remove aliases.
+	* login/getutid.c (getutxid): Remove alias.
+	* login/getutline.c (getutxline): Remove alias.
+	* login/utmp.h: Add prototypes for __updwtmp, __getutent,
+	__getutid, __getutline and __pututline.
+	* login/utmpx.h: Moved to ...
+	* sysdeps/gnu/utmpx.h: ... here.  [__USE_GNU]: Define UTMPX_FILE,
+	UTMPX_FILENAME, WTMPX_FILE and WTMPX_FILENAME, declare utmpxname
+	and updwtmpx.
+	* login/updwtmp.c: Moved to ...
+	* sysdeps/generic/updwtmp.c: ... here.  (updwtmp): Generalized by
+	allowing file name transformation.
+	* sysdeps/gnu/updwtmp.c: New file.  Use generic implementation with
+	additional file name transformation.
+	* sysdeps/unix/sysv/linux/updwtmp.c: Likewise.
+	* login/utmp_file.c: Moved to ...
+	* sysdeps/generic/utmp_file.c: ... here.  (setutent_file):
+	Generalized by allowing file name transformation.  Do not
+	print error message.  Library functions should not print them.
+	Reported by Jim Meyering.
+	* sysdeps/gnu/utmp_file.c: New file.  Use generic implementation
+	with additional file name transformation.
+	* sysdeps/unix/sysv/linux/utmp_file.c: Likewise.
+	* sysdeps/gnu/Makefile [$(subdir)=login] (sysdep_routines): Add
+	setutxent, getutxent, endutxent, getutxid, getutxid, getutxline,
+	pututxline, utmpxname and updwtmpx.  (sysdep_headers): Add utmpx.h
+	and bits/utmpx.h.
+	* sysdeps/gnu/bits/utmpx.h [__USE_GNU] Include paths.h.
+	(_PATH_UTMPX): Define to _PATH_UTMP.  (_PATH_WTMPX): Define to
+	_PATH_WTMPX.  (RUN_LVL): Define only if __USE_GNU.  (ACCOUNTING):
+	Define if __USE_GNU.
+	* sysdeps/gnu/setutxent.c: New file.
+	* sysdeps/gnu/getutxent.c: New file.
+	* sysdeps/gnu/endutxent.c: New file.
+	* sysdeps/gnu/getutxid.c: New file.
+	* sysdeps/gnu/getutxline.c: New file.
+	* sysdeps/gnu/pututxline.c: New file.
+	* sysdeps/gnu/utmpxname.c: New file.
+	* sysdeps/gnu/updwtmpx.c: New file.
+	* sysdeps/unix/sysv/linux/paths.h (_PATH_UTMP_DB): Remove.
+	* sysdeps/generic/bits/utmpx.h: Remove.
+
+1998-04-20  Ulrich Drepper  <drepper@cygnus.com>
+
+	* posix/wordexp-test.c (main): Initialize ifs element of ts for
+	~root test.
+
+1998-04-17 07:53  H.J. Lu  <hjl@gnu.org>
+
+	* sysdeps/unix/sysv/linux/i386/s_pread64.S: Fix a typo.
+
+1998-04-17 11:32  Ulrich Drepper  <drepper@cygnus.com>
+
+	* libio/oldfileops.c (_IO_old_file_seekoff): Define temporary st
+	variable using _G_stat64.
+	* libio/fileops.c: Remove macro definition of fstat, it is in the
+	global header.
+	Reported by Thorsten Kukuk <kukuk@weber.uni-paderborn.de>.
+
+1998-04-17  Philip Blundell  <pb@nexus.co.uk>
+
+	* sysdeps/arm/strlen.S: New file, based on code by Matthew Wilcox
+	<willy@odie.barnet.ac.uk>.
+
+1998-04-16  Philip Blundell  <Philip.Blundell@pobox.com>
+
+	* inet/netinet/in.h (IN6_IS_ADDR_MC_NODELOCAL): New macro,
+	required by IPv6 Basic API.
+	(IN6_IS_ADDR_MC_LINKLOCAL): Likewise.
+	(IN6_IS_ADDR_MC_SITELOCAL): Likewise.
+	(IN6_IS_ADDR_MC_ORGLOCAL): Likewise.
+	(IN6_IS_ADDR_MC_GLOBAL): Likewise.
+
 1998-04-15 16:41  Ulrich Drepper  <drepper@cygnus.com>
 
 	Don't name internal representation since it might be different from
diff --git a/FAQ b/FAQ
index 6eb4ff0fef..ed4658149c 100644
--- a/FAQ
+++ b/FAQ
@@ -24,7 +24,7 @@ please let me know.
 1.3.	When I try to compile glibc I get only error messages.
 	What's wrong?
 1.4.	Do I need a special linker or archiver?
-1.5.	What tools do I need for powerpc?
+1.5.	Which compiler should I use for powerpc?
 1.6.	Do I need some more things to compile GNU C Library?
 1.7.	What version of the Linux kernel headers should be used?
 1.8.	When I run `nm -u libc.so' on the produced library I still
@@ -203,25 +203,19 @@ may have native linker support, but it's moot right now, because glibc
 has not been ported to them.
 
 
-1.5.	What tools do I need for powerpc?
+1.5.	Which compiler should I use for powerpc?
 
-{GK} For a successful installation you definitely need the most recent
-tools. You can safely assume that anything earlier than binutils
-2.8.1.0.17 and egcs-1.0 will have problems. We'd advise at the moment
-binutils 2.8.1.0.18 and egcs-1.0.1.
+{GK} You want to use egcs 1.0.1 or later (together with the right
+versions of all the other tools, of course).
 
-In fact, egcs 1.0.1 currently has two serious bugs that prevent a
-clean make; one relates to switch statement folding, for which there
-is a temporary patch at
+In fact, egcs 1.0.1 has a serious bug that prevents a clean make,
+relating to switch statement folding.  It also causes the resulting
+shared libraries to use more memory than they should.  There is a
+patch at:
 
-<http://discus.anu.edu.au/~geoffk/egcs-1.0-geoffk.diff.gz>
+<http://discus.anu.edu.au/~geoffk/egcs-1.0.1-geoffk.diff>
 
-and the other relates to 'forbidden register spilled', for which the
-workaround is to put
-
-CFLAGS-condvar.c += -fno-inline
-
-in configparms.  Later versions of egcs may fix these problems.
+Later versions of egcs may fix these problems.
 
 
 1.6.	Do I need some more things to compile GNU C Library?
@@ -247,7 +241,8 @@ in configparms.  Later versions of egcs may fix these problems.
 * When compiling for Linux, the header files of the Linux kernel must
   be available to the compiler as <linux/*.h> and <asm/*.h>.
 
-* lots of disk space (~170MB for i?86-linux; more for RISC platforms).
+* lots of disk space (~170MB for i?86-linux; more for RISC platforms,
+  as much as 400MB).
 
 * plenty of time.  Compiling just the shared and static libraries for
   i?86-linux takes approximately 1h on an i586@133, or 2.5h on
@@ -290,9 +285,6 @@ symbols:
 
 * symbols starting with _dl_* come from the dynamic linker
 
-* symbols resolved by using libgcc.a
-  (__udivdi3, __umoddi3, or similar)
-
 * weak symbols, which need not be resolved at all (fabs for example)
 
 Generally, you should make sure you find a real program which produces
@@ -1141,7 +1133,7 @@ Answers were given by:
 {MK} Mark Kettenis, <kettenis@phys.uva.nl>
 {ZW} Zack Weinberg, <zack@rabi.phys.columbia.edu>
 {TK} Thorsten Kukuk, <kukuk@vt.uni-paderborn.de>
-{GK} Geoffrey Keating, <Geoff.Keating@anu.edu.au>
+{GK} Geoffrey Keating, <geoffk@ozemail.com.au>
 {HJ} H.J. Lu, <hjl@gnu.org>
 
 Local Variables:
diff --git a/FAQ.in b/FAQ.in
index 7ca0218ec6..0a8277fbe2 100644
--- a/FAQ.in
+++ b/FAQ.in
@@ -89,25 +89,19 @@ required.  For Linux, get binutils-2.8.1.0.23 or later.  Other systems
 may have native linker support, but it's moot right now, because glibc
 has not been ported to them.
 
-??powerpc	What tools do I need for powerpc?
+??powerpc	Which compiler should I use for powerpc?
 
-{GK} For a successful installation you definitely need the most recent
-tools. You can safely assume that anything earlier than binutils
-2.8.1.0.17 and egcs-1.0 will have problems. We'd advise at the moment
-binutils 2.8.1.0.18 and egcs-1.0.1.
+{GK} You want to use egcs 1.0.1 or later (together with the right
+versions of all the other tools, of course).
 
-In fact, egcs 1.0.1 currently has two serious bugs that prevent a
-clean make; one relates to switch statement folding, for which there
-is a temporary patch at
+In fact, egcs 1.0.1 has a serious bug that prevents a clean make,
+relating to switch statement folding.  It also causes the resulting
+shared libraries to use more memory than they should.  There is a
+patch at:
 
-<http://discus.anu.edu.au/~geoffk/egcs-1.0-geoffk.diff.gz>
+<http://discus.anu.edu.au/~geoffk/egcs-1.0.1-geoffk.diff>
 
-and the other relates to 'forbidden register spilled', for which the
-workaround is to put
-
-CFLAGS-condvar.c += -fno-inline
-
-in configparms.  Later versions of egcs may fix these problems.
+Later versions of egcs may fix these problems.
 
 
 ??	Do I need some more things to compile GNU C Library?
@@ -133,7 +127,8 @@ in configparms.  Later versions of egcs may fix these problems.
 * When compiling for Linux, the header files of the Linux kernel must
   be available to the compiler as <linux/*.h> and <asm/*.h>.
 
-* lots of disk space (~170MB for i?86-linux; more for RISC platforms).
+* lots of disk space (~170MB for i?86-linux; more for RISC platforms,
+  as much as 400MB).
 
 * plenty of time.  Compiling just the shared and static libraries for
   i?86-linux takes approximately 1h on an i586@133, or 2.5h on
@@ -174,9 +169,6 @@ symbols:
 
 * symbols starting with _dl_* come from the dynamic linker
 
-* symbols resolved by using libgcc.a
-  (__udivdi3, __umoddi3, or similar)
-
 * weak symbols, which need not be resolved at all (fabs for example)
 
 Generally, you should make sure you find a real program which produces
@@ -981,7 +973,7 @@ Answers were given by:
 {MK} Mark Kettenis, <kettenis@phys.uva.nl>
 {ZW} Zack Weinberg, <zack@rabi.phys.columbia.edu>
 {TK} Thorsten Kukuk, <kukuk@vt.uni-paderborn.de>
-{GK} Geoffrey Keating, <Geoff.Keating@anu.edu.au>
+{GK} Geoffrey Keating, <geoffk@ozemail.com.au>
 {HJ} H.J. Lu, <hjl@gnu.org>
 
 Local Variables:
diff --git a/bits/socket.h b/bits/socket.h
index 5dc1e65370..01844bc143 100644
--- a/bits/socket.h
+++ b/bits/socket.h
@@ -17,6 +17,9 @@
    write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
    Boston, MA 02111-1307, USA.  */
 
+#ifndef __BITS_SOCKET_H
+#define __BITS_SOCKET_H	1
+
 #if !defined _SYS_SOCKET_H && !defined _NETINET_IN_H
 # error "Never include <bits/socket.h> directly; use <sys/socket.h> instead."
 #endif
@@ -196,3 +199,5 @@ struct linger
     int l_onoff;		/* Nonzero to linger on close.  */
     int l_linger;		/* Time to linger.  */
   };
+
+#endif	/* bits/socket.h */
diff --git a/csu/init.c b/csu/init.c
index 2b7a2ef0ff..df08f6c918 100644
--- a/csu/init.c
+++ b/csu/init.c
@@ -1,5 +1,5 @@
 /* Special startup support.
-   Copyright (C) 1997 Free Software Foundation, Inc.
+   Copyright (C) 1997, 1998 Free Software Foundation, Inc.
    This file is part of the GNU C Library.
 
    The GNU C Library is free software; you can redistribute it
@@ -26,7 +26,7 @@
    write to the Free Software Foundation, 59 Temple Place - Suite 330,
    Boston, MA 02111-1307, USA.  */
 
-#if defined __GNUC__ && __GNUC__ >= 2
+#if defined USE_IN_LIBIO && defined __GNUC__ && __GNUC__ >= 2
 
 #undef _LIBC
 #include <libio.h>
diff --git a/db2/compat.h b/db2/compat.h
index 8652ad97ec..86909aeb13 100644
--- a/db2/compat.h
+++ b/db2/compat.h
@@ -1,6 +1,7 @@
 /* Compatibility gunk for the db library.  */
 
 #include <sys/types.h>
+#include <errno.h>
 
 #ifndef EFTYPE
 # define EFTYPE EINVAL
diff --git a/elf/dl-minimal.c b/elf/dl-minimal.c
index b0c8c465e4..70b5aeeeac 100644
--- a/elf/dl-minimal.c
+++ b/elf/dl-minimal.c
@@ -193,12 +193,15 @@ __assert_perror_fail (int errnum,
 		      const char *file, unsigned int line,
 		      const char *function)
 {
+  char errbuf[64];
   char buf[64];
   buf[sizeof buf - 1] = '\0';
   _dl_sysdep_fatal ("BUG IN DYNAMIC LINKER ld.so: ",
 		    file, ": ", _itoa_word (line, buf + sizeof buf - 1, 10, 0),
 		    ": ", function ?: "", function ? ": " : "",
-		    "Unexpected error: ", strerror (errnum), "\n", NULL);
+		    "Unexpected error: ",
+		    __strerror_r (errnum, errbuf, sizeof (errbuf)), "\n",
+		    NULL);
 
 }
 
diff --git a/iconv/Makefile b/iconv/Makefile
index 783b1d55b5..e4cd0fc53d 100644
--- a/iconv/Makefile
+++ b/iconv/Makefile
@@ -21,10 +21,18 @@
 #
 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_dl gconv_builtin gconv_simple
+		  gconv_builtin gconv_simple
+ifeq ($(elf),yes)
+routines	+= gconv_dl
+else
+CFLAGS-gconv_db.c = -DSTATIC_GCONV
+endif
+
 distribute	= gconv_builtin.h gconv_int.h
 
 others		= iconv_prog
diff --git a/iconv/gconv.c b/iconv/gconv.c
index f8b7c8050d..aa58bdba7d 100644
--- a/iconv/gconv.c
+++ b/iconv/gconv.c
@@ -19,39 +19,58 @@
    write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
    Boston, MA 02111-1307, USA.  */
 
+#include <assert.h>
 #include <gconv.h>
+#include <sys/param.h>
 
 
 int
 internal_function
-__gconv (gconv_t cd, const char **inbuf, size_t *inbytesleft, char **outbuf,
-	 size_t *outbytesleft, size_t *converted)
+__gconv (gconv_t cd, const char **inbuf, const char *inbufend, char **outbuf,
+	 char *outbufend, size_t *converted)
 {
   size_t last_step = cd->nsteps - 1;
-  size_t oldinbytes = *inbytesleft;
   int result;
 
   if (cd == (gconv_t) -1L)
     return GCONV_ILLEGAL_DESCRIPTOR;
 
-  cd->data[last_step].outbuf = outbuf ? *outbuf : NULL;
-  cd->data[last_step].outbufavail = 0;
-  cd->data[last_step].outbufsize = *outbytesleft;
+  assert (converted != NULL);
+  *converted = 0;
 
-  if (converted != NULL)
-    *converted = 0;
+  if (inbuf == NULL || *inbuf == NULL)
+    /* We just flush.  */
+    result = (*cd->steps->fct) (cd->steps, cd->data, NULL, NULL, converted, 1);
+  else
+    {
+      const char *last_start;
 
-  result = (*cd->steps->fct) (cd->steps, cd->data,
-			      inbuf ? *inbuf : NULL, inbytesleft,
-			      converted, inbuf == NULL || *inbuf == NULL);
+      assert (outbuf != NULL && *outbuf != NULL);
+      cd->data[last_step].outbuf = *outbuf;
+      cd->data[last_step].outbufend = outbufend;
 
-  if (inbuf != NULL && *inbuf != NULL)
-    *inbuf += oldinbytes - *inbytesleft;
-  if (outbuf != NULL && *outbuf != NULL)
-    {
-      *outbuf += cd->data[last_step].outbufavail;
-      *outbytesleft -= cd->data[last_step].outbufavail;
+      do
+	{
+	  /* See whether the input size is reasoable for the output
+	     size.  If not adjust it.  */
+	  size_t inlen = ((inbufend - *inbuf) / cd->steps->max_needed_from
+			  * cd->steps->max_needed_from);
+
+	  if (cd->nsteps > 1)
+	    inlen = MIN (inlen, (((outbufend - cd->data[last_step].outbuf)
+				  / cd->steps[last_step].max_needed_to)
+				 * cd->steps[last_step].max_needed_to));
+
+	  last_start = *inbuf;
+	  result = (*cd->steps->fct) (cd->steps, cd->data, inbuf,
+				      *inbuf + inlen, converted, 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/iconv/gconv.h b/iconv/gconv.h
index f3f80f4c14..cd0e3de1dc 100644
--- a/iconv/gconv.h
+++ b/iconv/gconv.h
@@ -57,8 +57,8 @@ struct gconv_loaded_object;
 
 /* Type of a conversion function.  */
 typedef int (*gconv_fct) __P ((struct gconv_step *,
-			       struct gconv_step_data *,
-			       __const char *, size_t *, size_t *, int));
+			       struct gconv_step_data *, __const char **,
+			       __const char *, size_t *, int));
 
 /* Constructor and destructor for local data for conversion step.  */
 typedef int (*gconv_init_fct) __P ((struct gconv_step *));
@@ -80,6 +80,13 @@ struct gconv_step
   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;
+
   void *data;		/* Pointer to step-local data.  */
 };
 
@@ -88,8 +95,7 @@ struct gconv_step
 struct gconv_step_data
 {
   char *outbuf;		/* Output buffer for this step.  */
-  size_t outbufavail;	/* Bytes already available in output buffer.  */
-  size_t outbufsize;	/* Size of output buffer.  */
+  char *outbufend;	/* Address of first byte after the output buffer.  */
 
   int is_last;
 
diff --git a/iconv/gconv_builtin.c b/iconv/gconv_builtin.c
index 6b14804da3..a970fcc8f2 100644
--- a/iconv/gconv_builtin.c
+++ b/iconv/gconv_builtin.c
@@ -33,15 +33,25 @@ static struct builtin_map
   gconv_init_fct init;
   gconv_end_fct end;
 
+  int min_needed_from;
+  int max_needed_from;
+  int min_needed_to;
+  int max_needed_to;
+
 } map[] =
 {
 #define BUILTIN_TRANSFORMATION(From, ConstPfx, ConstLen, To, Cost, Name, \
-			       Fct, Init, End) \
+			       Fct, Init, End, MinF, MaxF, MinT, MaxT) \
   {									      \
     name: Name,								      \
     fct: Fct,								      \
     init: Init,								      \
     end: End,								      \
+									      \
+    min_needed_from: MinF,						      \
+    max_needed_from: MaxF,						      \
+    min_needed_to: MinT,						      \
+    max_needed_to: MaxT							      \
   },
 #define BUILTIN_ALIAS(From, To)
 
@@ -66,4 +76,9 @@ __gconv_get_builtin_trans (const char *name, struct gconv_step *step)
   step->end_fct = map[cnt].end;
   step->counter = INT_MAX;
   step->shlib_handle = 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;
 }
diff --git a/iconv/gconv_builtin.h b/iconv/gconv_builtin.h
index 265dca1f01..3d214ff4f0 100644
--- a/iconv/gconv_builtin.h
+++ b/iconv/gconv_builtin.h
@@ -26,10 +26,12 @@ BUILTIN_ALIAS ("10646-1:1993/UCS4/", "ISO-10646/UCS4/")
 
 BUILTIN_TRANSFORMATION (NULL, "INTERNAL", 8,
 			"ISO-10646/UCS4/", 1, "=INTERNAL->ucs4",
-			__gconv_transform_internal_ucs4, NULL, NULL)
+			__gconv_transform_internal_ucs4, NULL, NULL,
+			4, 4, 4, 4)
 BUILTIN_TRANSFORMATION (NULL, "ISO-10646/UCS4/", 15,
 			"INTERNAL", 1, "=ucs4->INTERNAL",
-			__gconv_transform_internal_ucs4, NULL, NULL)
+			__gconv_transform_internal_ucs4, NULL, NULL,
+			4, 4, 4, 4)
 /* Please note that we need only one function for both direction.  */
 
 BUILTIN_ALIAS ("UTF8//", "ISO-10646/UTF8/")
@@ -37,22 +39,27 @@ BUILTIN_ALIAS ("UTF-8//", "ISO-10646/UTF8/")
 
 BUILTIN_TRANSFORMATION (NULL, "INTERNAL", 8,
 			"ISO-10646/UTF8/", 1, "=INTERNAL->utf8",
-			__gconv_transform_internal_utf8, NULL, NULL)
+			__gconv_transform_internal_utf8, NULL, NULL,
+			4, 4, 1, 6)
 
 BUILTIN_TRANSFORMATION ("ISO-10646/UTF-?8/", "ISO-10646/UTF", 13,
 			"INTERNAL", 1, "=utf8->INTERNAL",
-			__gconv_transform_utf8_internal, NULL, NULL)
+			__gconv_transform_utf8_internal, NULL, NULL,
+			1, 6, 4, 4)
 
 BUILTIN_ALIAS ("UCS2//", "ISO-10646/UCS2/")
 BUILTIN_ALIAS ("UCS-2//", "ISO-10646/UCS2/")
 
 BUILTIN_TRANSFORMATION (NULL, "ISO-10646/UCS2/", 15, "INTERNAL",
 			1, "=ucs2->INTERNAL",
-			__gconv_transform_ucs2_internal, NULL, NULL)
+			__gconv_transform_ucs2_internal, NULL, NULL,
+			2, 2, 4, 4)
 
 BUILTIN_TRANSFORMATION (NULL, "INTERNAL", 8, "ISO-10646/UCS2/",
 			1, "=INTERNAL->ucs2",
-			__gconv_transform_internal_ucs2, NULL, NULL)
+			__gconv_transform_internal_ucs2, NULL, NULL,
+			4, 4, 2, 2)
 
 BUILTIN_TRANSFORMATION ("(.*)", NULL, 0, "\\1", 1, "=dummy",
-			__gconv_transform_dummy, NULL, NULL)
+			__gconv_transform_dummy, NULL, NULL,
+			1, 1, 1, 1)
diff --git a/iconv/gconv_conf.c b/iconv/gconv_conf.c
index c67a0d8f8c..ae5ba19e5d 100644
--- a/iconv/gconv_conf.c
+++ b/iconv/gconv_conf.c
@@ -47,7 +47,7 @@ static const char gconv_module_ext[] = MODULE_EXT;
 static struct gconv_module builtin_modules[] =
 {
 #define BUILTIN_TRANSFORMATION(From, ConstPfx, ConstLen, To, Cost, Name, \
-			       Fct, Init, End) \
+			       Fct, Init, End, MinF, MaxF, MinT, MaxT) \
   {									      \
     from_pattern: From,							      \
     from_constpfx: ConstPfx,						      \
@@ -69,7 +69,7 @@ static const char *
 builtin_aliases[] =
 {
 #define BUILTIN_TRANSFORMATION(From, ConstPfx, ConstLen, To, Cost, Name, \
-			       Fct, Init, End)
+			       Fct, Init, End, MinF, MaxF, MinT, MaxT)
 #define BUILTIN_ALIAS(From, To) From " " To,
 
 #include "gconv_builtin.h"
diff --git a/iconv/gconv_db.c b/iconv/gconv_db.c
index 9f4366b7df..62d8f0540c 100644
--- a/iconv/gconv_db.c
+++ b/iconv/gconv_db.c
@@ -192,6 +192,7 @@ gen_steps (struct derivation_step *best, const char *toset,
 				      ? __strdup (current->result_set)
 				      : result[step_cnt + 1].from_name);
 
+#ifndef STATIC_GCONV
 	  if (current->code->module_name[0] == '/')
 	    {
 	      /* Load the module, return handle for it.  */
@@ -212,6 +213,7 @@ gen_steps (struct derivation_step *best, const char *toset,
 	      result[step_cnt].end_fct = shlib_handle->end_fct;
 	    }
 	  else
+#endif
 	    /* It's a builtin transformation.  */
 	    __gconv_get_builtin_trans (current->code->module_name,
 				       &result[step_cnt]);
@@ -230,7 +232,9 @@ gen_steps (struct derivation_step *best, const char *toset,
 	    {
 	      if (result[step_cnt].end_fct != NULL)
 		(*result[step_cnt].end_fct) (&result[step_cnt]);
+#ifndef STATIC_GCONV
 	      __gconv_release_shlib (result[step_cnt].shlib_handle);
+#endif
 	    }
 	  free (result);
 	  *nsteps = 0;
@@ -525,6 +529,7 @@ __gconv_find_transform (const char *toset, const char *fromset,
   result = find_derivation (toset, toset_expand, fromset, fromset_expand,
 			    handle, nsteps);
 
+#ifndef STATIC_GCONV
   /* Increment the user counter.  */
   if (result == GCONV_OK)
     {
@@ -548,6 +553,7 @@ __gconv_find_transform (const char *toset, const char *fromset,
 	  }
       while (cnt > 0);
     }
+#endif
 
   /* Release the lock.  */
   __libc_lock_unlock (lock);
@@ -568,6 +574,7 @@ __gconv_close_transform (struct gconv_step *steps, size_t nsteps)
 {
   int result = GCONV_OK;
 
+#ifndef STATIC_GCONV
   /* Acquire the lock.  */
   __libc_lock_lock (lock);
 
@@ -583,6 +590,7 @@ __gconv_close_transform (struct gconv_step *steps, size_t nsteps)
 
   /* Release the lock.  */
   __libc_lock_unlock (lock);
+#endif
 
   return result;
 }
diff --git a/iconv/gconv_int.h b/iconv/gconv_int.h
index a1475f8508..86e892f874 100644
--- a/iconv/gconv_int.h
+++ b/iconv/gconv_int.h
@@ -34,8 +34,8 @@ struct gconv_alias
 };
 
 
-/* Default size of intermediate buffers.  */
-#define GCONV_DEFAULT_BUFSIZE	8160
+/* How many character should be conveted in one call?  */
+#define GCONV_NCHAR_GOAL	8160
 
 
 /* Structure describing one loaded shared object.  This normally are
@@ -99,9 +99,8 @@ extern int __gconv_close (gconv_t cd)
    according to rules described by CD and place up to *OUTBYTESLEFT
    bytes in buffer starting at *OUTBUF.  Return number of written
    characters in *CONVERTED if this pointer is not null.  */
-extern int __gconv (gconv_t __cd, const char **__inbuf, size_t *__inbytesleft,
-		    char **__outbuf, size_t *__outbytesleft,
-		    size_t *__converted)
+extern int __gconv (gconv_t __cd, const char **__inbuf, const char *inbufend,
+		    char **__outbuf, char *outbufend, size_t *__converted)
      internal_function;
 
 /* Return in *HANDLE a pointer to an array with *NSTEPS elements describing
@@ -149,8 +148,8 @@ extern void __gconv_get_builtin_trans (const char *__name,
 #ifdef _LIBC
 # define __BUILTIN_TRANS(Name) \
   extern int Name (struct gconv_step *__step, struct gconv_step_data *__data, \
-		   const char *__inbuf, size_t *__inlen, size_t *__written,   \
-		   int __do_flush)
+		   const char **__inbuf, const char *__inbufend,	      \
+		   size_t *__written, int __do_flush)
 
 __BUILTIN_TRANS (__gconv_transform_dummy);
 __BUILTIN_TRANS (__gconv_transform_ascii_internal);
diff --git a/iconv/gconv_open.c b/iconv/gconv_open.c
index d82dcfee48..831794fc22 100644
--- a/iconv/gconv_open.c
+++ b/iconv/gconv_open.c
@@ -62,21 +62,24 @@ __gconv_open (const char *toset, const char *fromset, gconv_t *handle)
 	      for (cnt = 0; cnt < nsteps; ++cnt)
 		{
 		  /* If this is the last step we must not allocate an output
-		     buffer.  Signal this to the initializer.  */
+		     buffer.  */
 		  data[cnt].is_last = cnt == nsteps - 1;
 
 		  /* We use the `mbstate_t' member in DATA.  */
 		  data[cnt].statep = &data[cnt].__state;
 
 		  /* Allocate the buffer.  */
-		  data[cnt].outbufsize = GCONV_DEFAULT_BUFSIZE;
-		  data[cnt].outbuf = (char *) malloc (data[cnt].outbufsize);
-		  if (data[cnt].outbuf == NULL)
+		  if (!data[cnt].is_last)
 		    {
-		      res = GCONV_NOMEM;
-		      break;
+		      data[cnt].outbuf =
+			(char *) malloc (GCONV_NCHAR_GOAL
+					 * steps[cnt].max_needed_to);
+		      if (data[cnt].outbuf == NULL)
+			{
+			  res = GCONV_NOMEM;
+			  break;
+			}
 		    }
-		  data[cnt].outbufavail = 0;
 		}
 	    }
 	}
diff --git a/iconv/gconv_simple.c b/iconv/gconv_simple.c
index b72e61edcc..f2fec12fb8 100644
--- a/iconv/gconv_simple.c
+++ b/iconv/gconv_simple.c
@@ -35,7 +35,7 @@
 
 /* These are definitions used by some of the functions for handling
    UTF-8 encoding below.  */
-static const wchar_t encoding_mask[] =
+static const uint32_t encoding_mask[] =
 {
   ~0x7ff, ~0xffff, ~0x1fffff, ~0x3ffffff
 };
@@ -49,8 +49,8 @@ static const unsigned char encoding_byte[] =
 
 int
 __gconv_transform_dummy (struct gconv_step *step, struct gconv_step_data *data,
-			 const char *inbuf, size_t *inlen, size_t *written,
-			 int do_flush)
+			 const char **inbuf, const char *inbufend,
+			 size_t *written, int do_flush)
 {
   size_t do_write;
 
@@ -60,12 +60,12 @@ __gconv_transform_dummy (struct gconv_step *step, struct gconv_step_data *data,
     do_write = 0;
   else
     {
-      do_write = MIN (*inlen, data->outbufsize - data->outbufavail);
+      do_write = MIN (inbufend - *inbuf, data->outbufend - data->outbuf);
 
       memcpy (data->outbuf, inbuf, do_write);
 
-      *inlen -= do_write;
-      data->outbufavail += do_write;
+      *inbuf -= do_write;
+      *data->outbuf += do_write;
     }
 
   /* ### TODO Actually, this number must be devided according to the
@@ -83,934 +83,330 @@ __gconv_transform_dummy (struct gconv_step *step, struct gconv_step_data *data,
    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.*/
-int
-__gconv_transform_internal_ucs4 (struct gconv_step *step,
-				  struct gconv_step_data *data,
-				  const char *inbuf, size_t *inlen,
-				  size_t *written, int do_flush)
+#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
+
+
+static inline int
+internal_ucs4_loop (const unsigned char **inptrp, const unsigned char *inend,
+		    unsigned char **outptrp, unsigned char *outend,
+		    mbstate_t *state, void *data, size_t *converted)
 {
-  struct gconv_step *next_step = step + 1;
-  struct gconv_step_data *next_data = data + 1;
-  gconv_fct fct = next_step->fct;
-  size_t do_write = 0;
+  const unsigned char *inptr = *inptrp;
+  unsigned char *outptr = *outptrp;
+  size_t n_convert = MIN (inend - inptr, outend - outptr) / 4;
   int result;
 
-  /* 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 (do_flush)
-    {
-      /* Clear the state.  */
-      memset (data->statep, '\0', sizeof (mbstate_t));
-
-      /* Call the steps down the chain if there are any.  */
-      if (data->is_last)
-	result = GCONV_OK;
-      else
-	{
-	  struct gconv_step *next_step = step + 1;
-	  struct gconv_step_data *next_data = data + 1;
-
-	  result = (*fct) (next_step, next_data, NULL, 0, written, 1);
-
-	  /* Clear output buffer.  */
-	  data->outbufavail = 0;
-	}
-    }
-  else
-    {
-      int save_errno = errno;
-
-      result = GCONV_OK;
-      do
-	{
-	  size_t n_convert = (MIN (*inlen,
-				   (data->outbufsize - data->outbufavail))
-			      / sizeof (wchar_t));
-
 #if __BYTE_ORDER == __LITTLE_ENDIAN
-	  /* Sigh, we have to do some real work.  */
-	  wchar_t *outbuf = (wchar_t *) &data->outbuf[data->outbufavail];
-	  size_t cnt;
+  /* Sigh, we have to do some real work.  */
+  size_t cnt;
 
-	  for (cnt = 0; cnt < n_convert; ++cnt)
-	    outbuf[cnt] = bswap_32 (((wchar_t *) inbuf)[cnt]);
+  for (cnt = 0; cnt < n_convert; ++cnt)
+    *((uint32_t *) outptr)++ = bswap_32 (*((uint32_t *) inptr)++);
 
+  *inptrp = inptr;
+  *outptrp = outptr;
 #elif __BYTE_ORDER == __BIG_ENDIAN
-	  /* Simply copy the data.  */
-	  memcpy (&data->outbuf[data->outbufsize], inbuf,
-		  n_convert * sizeof (wchar_t));
+  /* Simply copy the data.  */
+  *inptrp = inptr + n_convert * 4;
+  *outptrp = __mempcpy (outptr, inptr, n_convert * 4);
 #else
 # error "This endianess is not supported."
 #endif
 
-	  *inlen -= n_convert * sizeof (wchar_t);
-	  inbuf += n_convert * sizeof (wchar_t);
-	  data->outbufavail += n_convert * sizeof (wchar_t);
-	  do_write += n_convert;
-
-	  if (*inlen > 0 && *inlen < sizeof (wchar_t))
-	    {
-	      /* We have an incomplete character at the end.  */
-	      result = GCONV_INCOMPLETE_INPUT;
-	      break;
-	    }
-
-	  if (data->is_last)
-	    {
-	      /* This is the last step.  */
-	      result = (*inlen < sizeof (wchar_t)
-			? GCONV_EMPTY_INPUT : GCONV_FULL_OUTPUT);
-	      break;
-	    }
-
-	  /* Status so far.  */
-	  result = GCONV_EMPTY_INPUT;
-
-	  if (data->outbufavail > 0)
-	    {
-	      /* Call the functions below in the chain.  */
-	      size_t newavail = data->outbufavail;
-
-	      result = (*fct) (next_step, next_data, data->outbuf, &newavail,
-			       written, 0);
-
-	      /* Correct the output buffer.  */
-	      if (newavail != data->outbufavail && newavail > 0)
-		{
-		  memmove (data->outbuf,
-			   &data->outbuf[data->outbufavail - newavail],
-			   newavail);
-		  data->outbufavail = newavail;
-		}
-	    }
-	}
-      while (*inlen >= sizeof (wchar_t) && result == GCONV_EMPTY_INPUT);
-
-      __set_errno (save_errno);
-    }
-
-  if (written != NULL && data->is_last)
-    *written = do_write;
-
-  return result;
-}
-
-
-/* Convert from ISO 646-IRV to the internal (UCS4-like) format.  */
-int
-__gconv_transform_ascii_internal (struct gconv_step *step,
-				  struct gconv_step_data *data,
-				  const char *inbuf, size_t *inlen,
-				  size_t *written, int do_flush)
-{
-  struct gconv_step *next_step = step + 1;
-  struct gconv_step_data *next_data = data + 1;
-  gconv_fct fct = next_step->fct;
-  size_t do_write = 0;
-  int result;
-
-  /* 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 (do_flush)
-    {
-      /* Clear the state.  */
-      memset (data->statep, '\0', sizeof (mbstate_t));
-
-      /* Call the steps down the chain if there are any.  */
-      if (data->is_last)
-	result = GCONV_OK;
-      else
-	{
-	  struct gconv_step *next_step = step + 1;
-	  struct gconv_step_data *next_data = data + 1;
-
-	  result = (*fct) (next_step, next_data, NULL, 0, written, 1);
-
-	  /* Clear output buffer.  */
-	  data->outbufavail = 0;
-	}
-    }
-  else
-    {
-      const unsigned char *newinbuf = inbuf;
-      int save_errno = errno;
-
-      result = GCONV_OK;
-      do
-	{
-	  size_t actually = 0;
-	  size_t cnt = 0;
-
-	  while (data->outbufavail + sizeof (wchar_t) <= data->outbufsize
-		 && cnt < *inlen)
-	    {
-	      if (*newinbuf > '\x7f')
-		{
-		  /* This is no correct ANSI_X3.4-1968 character.  */
-		  result = GCONV_ILLEGAL_INPUT;
-		  break;
-		}
-
-	      /* It's an one byte sequence.  */
-	      *(wchar_t *) &data->outbuf[data->outbufavail]
-		= (wchar_t) *newinbuf;
-	      data->outbufavail += sizeof (wchar_t);
-	      ++actually;
-
-	      ++newinbuf;
-	      ++cnt;
-	    }
-
-	  /* Remember how much we converted.  */
-	  do_write += cnt * sizeof (wchar_t);
-	  *inlen -= cnt;
-
-	  /* Check whether an illegal character appeared.  */
-	  if (result != GCONV_OK)
-	    break;
-
-	  if (data->is_last)
-	    {
-	      /* This is the last step.  */
-	      result = (*inlen == 0 ? GCONV_EMPTY_INPUT : GCONV_FULL_OUTPUT);
-	      break;
-	    }
-
-	  /* Status so far.  */
-	  result = GCONV_EMPTY_INPUT;
-
-	  if (data->outbufavail > 0)
-	    {
-	      /* Call the functions below in the chain.  */
-	      size_t newavail = data->outbufavail;
-
-	      result = (*fct) (next_step, next_data, data->outbuf, &newavail,
-			       written, 0);
-
-	      /* Correct the output buffer.  */
-	      if (newavail != data->outbufavail && newavail > 0)
-		{
-		  memmove (data->outbuf,
-			   &data->outbuf[data->outbufavail - newavail],
-			   newavail);
-		  data->outbufavail = newavail;
-		}
-	    }
-	}
-      while (*inlen > 0 && result == GCONV_EMPTY_INPUT);
-
-      __set_errno (save_errno);
-    }
-
-  if (written != NULL && data->is_last)
-    *written = do_write / sizeof (wchar_t);
-
-  return result;
-}
-
-
-/* Convert from ISO 10646/UCS to ISO 646-IRV.  */
-int
-__gconv_transform_internal_ascii (struct gconv_step *step,
-				  struct gconv_step_data *data,
-				  const char *inbuf, size_t *inlen,
-				  size_t *written, int do_flush)
-{
-  struct gconv_step *next_step = step + 1;
-  struct gconv_step_data *next_data = data + 1;
-  gconv_fct fct = next_step->fct;
-  size_t do_write;
-  int result;
-
-  /* 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 (do_flush)
-    {
-      /* Clear the state.  */
-      memset (data->statep, '\0', sizeof (mbstate_t));
-      do_write = 0;
-
-      /* Call the steps down the chain if there are any.  */
-      if (data->is_last)
-	result = GCONV_OK;
-      else
-	{
-	  struct gconv_step *next_step = step + 1;
-	  struct gconv_step_data *next_data = data + 1;
-
-	  result = (*fct) (next_step, next_data, NULL, 0, written, 1);
-
-	  /* Clear output buffer.  */
-	  data->outbufavail = 0;
-	}
-    }
-  else
-    {
-      const wchar_t *newinbuf = (const wchar_t *) inbuf;
-      int save_errno = errno;
-      do_write = 0;
-
-      result = GCONV_OK;
-      do
-	{
-	  size_t actually = 0;
-	  size_t cnt = 0;
-
-	  while (data->outbufavail < data->outbufsize
-		 && cnt + 3 < *inlen)
-	    {
-	      if (*newinbuf < L'\0' || *newinbuf > L'\x7f')
-		{
-		  /* This is no correct ANSI_X3.4-1968 character.  */
-		  result = GCONV_ILLEGAL_INPUT;
-		  break;
-		}
-
-	      /* It's an one byte sequence.  */
-	      data->outbuf[data->outbufavail++] = (char) *newinbuf;
-	      ++actually;
-
-	      ++newinbuf;
-	      cnt += sizeof (wchar_t);
-	    }
-
-	  /* Remember how much we converted.  */
-	  do_write += cnt / sizeof (wchar_t);
-	  *inlen -= cnt;
-
-	  /* Check whether an illegal character appeared.  */
-	  if (result != GCONV_OK)
-	    break;
-
-	  /* Check for incomplete input.  */
-	  if (*inlen > 0 && *inlen < sizeof (wchar_t))
-	    {
-	      /* We have an incomplete character at the end.  */
-	      result = GCONV_INCOMPLETE_INPUT;
-	      break;
-	    }
-
-	  if (data->is_last)
-	    {
-	      /* This is the last step.  */
-	      result = *inlen == 0 ? GCONV_EMPTY_INPUT : GCONV_FULL_OUTPUT;
-	      break;
-	    }
-
-	  /* Status so far.  */
-	  result = GCONV_EMPTY_INPUT;
-
-	  if (data->outbufavail > 0)
-	    {
-	      /* Call the functions below in the chain.  */
-	      size_t newavail = data->outbufavail;
-
-	      result = (*fct) (next_step, next_data, data->outbuf, &newavail,
-			       written, 0);
-
-	      /* Correct the output buffer.  */
-	      if (newavail != data->outbufavail && newavail > 0)
-		{
-		  memmove (data->outbuf,
-			   &data->outbuf[data->outbufavail - newavail],
-			   newavail);
-		  data->outbufavail = newavail;
-		}
-	    }
-	}
-      while (*inlen > 0 && result == GCONV_EMPTY_INPUT);
-
-      __set_errno (save_errno);
-    }
-
-  if (written != NULL && data->is_last)
-    *written = do_write;
-
-  return result;
-}
-
-
-int
-__gconv_transform_internal_utf8 (struct gconv_step *step,
-				 struct gconv_step_data *data,
-				 const char *inbuf, size_t *inlen,
-				 size_t *written, int do_flush)
-{
-  struct gconv_step *next_step = step + 1;
-  struct gconv_step_data *next_data = data + 1;
-  gconv_fct fct = next_step->fct;
-  size_t do_write;
-  int result;
-
-  /* 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 (do_flush)
-    {
-      /* Clear the state.  */
-      memset (data->statep, '\0', sizeof (mbstate_t));
-      do_write = 0;
-
-      /* Call the steps down the chain if there are any.  */
-      if (data->is_last)
-	result = GCONV_OK;
-      else
-	{
-	  struct gconv_step *next_step = step + 1;
-	  struct gconv_step_data *next_data = data + 1;
-
-	  result = (*fct) (next_step, next_data, NULL, 0, written, 1);
-
-	  /* Clear output buffer.  */
-	  data->outbufavail = 0;
-	}
-    }
-  else
-    {
-      const wchar_t *newinbuf = (const wchar_t *) inbuf;
-      int save_errno = errno;
-      do_write = 0;
-
-      result = GCONV_OK;
-      do
-	{
-	  size_t cnt = 0;
-
-	  while (data->outbufavail < data->outbufsize
-		 && cnt * sizeof (wchar_t) + 3 < *inlen)
-	    {
-	      wchar_t wc = newinbuf[cnt];
-
-	      if (wc < 0 && wc > 0x7fffffff)
-		{
-		  /* This is no correct ISO 10646 character.  */
-		  result = GCONV_ILLEGAL_INPUT;
-		  break;
-		}
-
-	      if (wc < 0x80)
-		/* It's an one byte sequence.  */
-		data->outbuf[data->outbufavail++] = (char) wc;
-	      else
-		{
-		  size_t step;
-		  size_t start;
-
-		  for (step = 2; step < 6; ++step)
-		    if ((wc & encoding_mask[step - 2]) == 0)
-		      break;
-
-		  if (data->outbufavail + step >= data->outbufsize)
-		    /* Too long.  */
-		    break;
-
-		  start = data->outbufavail;
-		  data->outbufavail += step;
-		  data->outbuf[start] = encoding_byte[step - 2];
-		  --step;
-		  do
-		    {
-		      data->outbuf[start + step] = 0x80 | (wc & 0x3f);
-		      wc >>= 6;
-		    }
-		  while (--step > 0);
-		  data->outbuf[start] |= wc;
-		}
-
-	      ++cnt;
-	    }
-
-	  /* Remember how much we converted.  */
-	  do_write += cnt;
-	  *inlen -= cnt * sizeof (wchar_t);
-	  newinbuf += cnt;
-
-	  /* Check whether an illegal character appeared.  */
-	  if (result != GCONV_OK)
-	    break;
-
-	  /* Check for incomplete input.  */
-	  if (*inlen > 0 && *inlen < sizeof (wchar_t))
-	    {
-	      /* We have an incomplete character at the end.  */
-	      result = GCONV_INCOMPLETE_INPUT;
-	      break;
-	    }
-
-	  if (data->is_last)
-	    {
-	      /* This is the last step.  */
-	      result = *inlen == 0 ? GCONV_EMPTY_INPUT : GCONV_FULL_OUTPUT;
-	      break;
-	    }
-
-	  /* Status so far.  */
-	  result = GCONV_EMPTY_INPUT;
-
-	  if (data->outbufavail > 0)
-	    {
-	      /* Call the functions below in the chain.  */
-	      size_t newavail = data->outbufavail;
-
-	      result = (*fct) (next_step, next_data, data->outbuf, &newavail,
-			       written, 0);
-
-	      /* Correct the output buffer.  */
-	      if (newavail != data->outbufavail && newavail > 0)
-		{
-		  memmove (data->outbuf,
-			   &data->outbuf[data->outbufavail - newavail],
-			   newavail);
-		  data->outbufavail = newavail;
-		}
-	    }
-	}
-      while (*inlen > 0 && result == GCONV_EMPTY_INPUT);
-
-      __set_errno (save_errno);
-    }
-
-  if (written != NULL && data->is_last)
-    *written = do_write;
-
-  return result;
-}
-
-
-int
-__gconv_transform_utf8_internal (struct gconv_step *step,
-				 struct gconv_step_data *data,
-				 const char *inbuf, size_t *inlen,
-				 size_t *written, int do_flush)
-{
-  struct gconv_step *next_step = step + 1;
-  struct gconv_step_data *next_data = data + 1;
-  gconv_fct fct = next_step->fct;
-  size_t do_write;
-  int result;
-
-  /* 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 (do_flush)
-    {
-      /* Clear the state.  */
-      memset (data->statep, '\0', sizeof (mbstate_t));
-      do_write = 0;
-
-      /* Call the steps down the chain if there are any.  */
-      if (data->is_last)
-	result = GCONV_OK;
-      else
-	{
-	  struct gconv_step *next_step = step + 1;
-	  struct gconv_step_data *next_data = data + 1;
-
-	  result = (*fct) (next_step, next_data, NULL, 0, written, 1);
-	}
-    }
+  /* Determine the status.  */
+  if (*outptrp == outend)
+    result = GCONV_FULL_OUTPUT;
+  else if (*inptrp == inend)
+    result = GCONV_EMPTY_INPUT;
   else
-    {
-      int save_errno = errno;
-      int extra = 0;
-      do_write = 0;
-
-      result = GCONV_OK;
-      do
-	{
-	  wchar_t *outbuf = (wchar_t *) &data->outbuf[data->outbufavail];
-	  size_t cnt = 0;
-	  size_t actually = 0;
-
-	  while (data->outbufavail + sizeof (wchar_t) <= data->outbufsize
-		 && cnt < *inlen)
-	    {
-	      size_t start = cnt;
-	      wchar_t value;
-	      unsigned char byte;
-	      int count;
-
-	      /* Next input byte.  */
-	      byte = inbuf[cnt++];
-
-	      if (byte < 0x80)
-		{
-		  /* One byte sequence.  */
-		  count = 0;
-		  value = byte;
-		}
-	      else if ((byte & 0xe0) == 0xc0)
-		{
-		  count = 1;
-		  value = byte & 0x1f;
-		}
-	      else if ((byte & 0xf0) == 0xe0)
-		{
-		  /* We expect three bytes.  */
-		  count = 2;
-		  value = byte & 0x0f;
-		}
-	      else if ((byte & 0xf8) == 0xf0)
-		{
-		  /* We expect four bytes.  */
-		  count = 3;
-		  value = byte & 0x07;
-		}
-	      else if ((byte & 0xfc) == 0xf8)
-		{
-		  /* We expect five bytes.  */
-		  count = 4;
-		  value = byte & 0x03;
-		}
-	      else if ((byte & 0xfe) == 0xfc)
-		{
-		  /* We expect six bytes.  */
-		  count = 5;
-		  value = byte & 0x01;
-		}
-	      else
-		{
-		  /* This is an illegal encoding.  */
-		  result = GCONV_ILLEGAL_INPUT;
-		  break;
-		}
-
-	      if (cnt + count > *inlen)
-		{
-		  /* We don't have enough input.  */
-		  --cnt;
-		  extra = count;
-		  break;
-		}
-
-	      /* Read the possible remaining bytes.  */
-	      while (count > 0)
-		{
-		  byte = inbuf[cnt++];
-		  --count;
-
-		  if ((byte & 0xc0) != 0x80)
-		    {
-		      /* This is an illegal encoding.  */
-		      result = GCONV_ILLEGAL_INPUT;
-		      break;
-		    }
-
-		  value <<= 6;
-		  value |= byte & 0x3f;
-		}
-
-	      if (result != GCONV_OK)
-		{
-		  cnt = start;
-		  break;
-		}
-
-	      *outbuf++ = value;
-	      ++actually;
-	    }
-
-	  /* Remember how much we converted.  */
-	  do_write += actually;
-	  *inlen -= cnt;
-	  inbuf += cnt;
-
-	  data->outbufavail += actually * sizeof (wchar_t);
-
-	  /* Check whether an illegal character appeared.  */
-	  if (result != GCONV_OK)
-	    {
-	      result = GCONV_ILLEGAL_INPUT;
-	      break;
-	    }
-
-	  if (*inlen > 0 && *inlen < extra)
-	    {
-	      /* We have an incomplete character at the end.  */
-	      result = GCONV_INCOMPLETE_INPUT;
-	      break;
-	    }
-
-	  if (data->is_last)
-	    {
-	      /* This is the last step.  */
-	      result = (data->outbufavail + sizeof (wchar_t) > data->outbufsize
-			? GCONV_FULL_OUTPUT : GCONV_EMPTY_INPUT);
-	      break;
-	    }
-
-	  /* Status so far.  */
-	  result = GCONV_EMPTY_INPUT;
-
-	  if (data->outbufavail > 0)
-	    {
-	      /* Call the functions below in the chain.  */
-	      size_t newavail = data->outbufavail;
-
-	      result = (*fct) (next_step, next_data, data->outbuf, &newavail,
-			       written, 0);
-
-	      /* Correct the output buffer.  */
-	      if (newavail != data->outbufavail && newavail > 0)
-		{
-		  memmove (data->outbuf,
-			   &data->outbuf[data->outbufavail - newavail],
-			   newavail);
-		  data->outbufavail = newavail;
-		}
-	    }
-	}
-      while (*inlen > 0 && result == GCONV_EMPTY_INPUT);
-
-      __set_errno (save_errno);
-    }
+    result = GCONV_INCOMPLETE_INPUT;
 
-  if (written != NULL && data->is_last)
-    *written = do_write;
+  if (converted != NULL)
+    converted += n_convert;
 
   return result;
 }
 
+#include <iconv/skeleton.c>
 
-int
-__gconv_transform_ucs2_internal (struct gconv_step *step,
-				 struct gconv_step_data *data,
-				 const char *inbuf, size_t *inlen,
-				 size_t *written, int do_flush)
-{
-  struct gconv_step *next_step = step + 1;
-  struct gconv_step_data *next_data = data + 1;
-  gconv_fct fct = next_step->fct;
-  size_t do_write;
-  int result;
-
-  /* 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 (do_flush)
-    {
-      /* Clear the state.  */
-      memset (data->statep, '\0', sizeof (mbstate_t));
-      do_write = 0;
-
-      /* Call the steps down the chain if there are any.  */
-      if (data->is_last)
-	result = GCONV_OK;
-      else
-	{
-	  struct gconv_step *next_step = step + 1;
-	  struct gconv_step_data *next_data = data + 1;
-
-	  result = (*fct) (next_step, next_data, NULL, 0, written, 1);
-	}
-    }
-  else
-    {
-      const uint16_t *newinbuf = (const uint16_t *) inbuf;
-      int save_errno = errno;
-      do_write = 0;
-
-      do
-	{
-	  wchar_t *outbuf = (wchar_t *) &data->outbuf[data->outbufavail];
-	  size_t actually = 0;
-
-	  errno = 0;
 
-	  while (data->outbufavail + 4 <= data->outbufsize
-		 && *inlen >= 2)
-	    {
+/* 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 MIN_NEEDED_INPUT	MIN_NEEDED_FROM
+#define MIN_NEEDED_OUTPUT	MIN_NEEDED_TO
+#define LOOPFCT			FROM_LOOP
+#define BODY \
+  {									      \
+    if (*inptr > '\x7f')						      \
+      {									      \
+	/* This is no correct ANSI_X3.4-1968 character.  */		      \
+	result = GCONV_ILLEGAL_INPUT;					      \
+	break;								      \
+      }									      \
+									      \
+    /* It's an one byte sequence.  */					      \
+    *((uint32_t *) outptr)++ = *inptr++;				      \
+  }
+#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 MIN_NEEDED_INPUT	MIN_NEEDED_FROM
+#define MIN_NEEDED_OUTPUT	MIN_NEEDED_TO
+#define LOOPFCT			FROM_LOOP
+#define BODY \
+  {									      \
+    if (*((uint32_t *) inptr) > '\x7f')					      \
+      {									      \
+	/* This is no correct ANSI_X3.4-1968 character.  */		      \
+	result = GCONV_ILLEGAL_INPUT;					      \
+	break;								      \
+      }									      \
+									      \
+    /* It's an one byte sequence.  */					      \
+    *outptr++ = *((uint32_t *) inptr)++;				      \
+  }
+#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 MIN_NEEDED_INPUT	MIN_NEEDED_FROM
+#define MIN_NEEDED_OUTPUT	MIN_NEEDED_TO
+#define LOOPFCT			FROM_LOOP
+#define BODY \
+  {									      \
+    uint32_t wc = *((uint32_t *) inptr);				      \
+									      \
+    /* Since we control every character we read this cannot happen.  */	      \
+    assert (wc <= 0x7fffffff);						      \
+									      \
+    if (wc < 0x80)							      \
+      /* It's an one byte sequence.  */					      \
+      *outptr++ = (unsigned char) wc;					      \
+    else								      \
+      {									      \
+	size_t step;							      \
+	char *start;							      \
+									      \
+	for (step = 2; step < 6; ++step)				      \
+	  if ((wc & encoding_mask[step - 2]) == 0)			      \
+	    break;							      \
+									      \
+	if (outptr + step >= outend)					      \
+	  {								      \
+	    /* Too long.  */						      \
+	    result = GCONV_FULL_OUTPUT;					      \
+	    break;							      \
+	  }								      \
+									      \
+	start = outptr;							      \
+	*outptr = encoding_byte[step - 2];				      \
+	outptr += step;							      \
+	--step;								      \
+	do								      \
+	  {								      \
+	    start[step] = 0x80 | (wc & 0x3f);				      \
+	    wc >>= 6;							      \
+	  }								      \
+	while (--step > 0);						      \
+	start[0] |= wc;							      \
+      }									      \
+									      \
+    inptr += 4;								      \
+  }
+#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 MIN_NEEDED_INPUT	MIN_NEEDED_FROM
+#define MIN_NEEDED_OUTPUT	MIN_NEEDED_TO
+#define LOOPFCT			FROM_LOOP
+#define BODY \
+  {									      \
+    uint32_t ch;							      \
+    uint_fast32_t cnt;							      \
+    uint_fast32_t i;							      \
+									      \
+    /* Next input byte.  */						      \
+    ch = *inptr;							      \
+									      \
+    if (ch < 0x80)							      \
+      /* One byte sequence.  */						      \
+      cnt = 1;								      \
+    else if ((ch & 0xe0) == 0xc0)					      \
+      {									      \
+	cnt = 2;							      \
+	ch &= 0x1f;							      \
+      }									      \
+    else if ((ch & 0xf0) == 0xe0)					      \
+      {									      \
+	/* We expect three bytes.  */					      \
+	cnt = 3;							      \
+	ch &= 0x0f;							      \
+      }									      \
+    else if ((ch & 0xf8) == 0xf0)					      \
+      {									      \
+	/* We expect four bytes.  */					      \
+	cnt = 4;							      \
+	ch &= 0x07;							      \
+      }									      \
+    else if ((ch & 0xfc) == 0xf8)					      \
+      {									      \
+	/* We expect five bytes.  */					      \
+	cnt = 5;							      \
+	ch &= 0x03;							      \
+      }									      \
+    else if ((ch & 0xfe) == 0xfc)					      \
+      {									      \
+	/* We expect six bytes.  */					      \
+	cnt = 6;							      \
+	ch &= 0x01;							      \
+      }									      \
+    else								      \
+      {									      \
+	/* This is an illegal encoding.  */				      \
+	result = GCONV_ILLEGAL_INPUT;					      \
+	break;								      \
+      }									      \
+									      \
+    if (NEED_LENGTH_TEST && inptr + cnt >= inend)			      \
+      {									      \
+	/* We don't have enough input.  */				      \
+	result = GCONV_INCOMPLETE_INPUT;				      \
+	break;								      \
+      }									      \
+									      \
+    /* 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.  */				      \
+	    result = GCONV_ILLEGAL_INPUT;				      \
+	    break;							      \
+	  }								      \
+									      \
+	ch <<= 6;							      \
+	ch |= byte & 0x3f;						      \
+      }									      \
+									      \
+    /* Now adjust the pointers and store the result.  */		      \
+    inptr += cnt;							      \
+    *((uint32_t *) outptr)++ = ch;					      \
+  }
+#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 MIN_NEEDED_INPUT	MIN_NEEDED_FROM
+#define MIN_NEEDED_OUTPUT	MIN_NEEDED_TO
+#define LOOPFCT			FROM_LOOP
 #if __BYTE_ORDER == __LITTLE_ENDIAN
-	      outbuf[actually++] = (wchar_t) bswap_16 (*newinbuf++);
+# define BODY \
+  *((uint32_t *) outptr)++ = bswap_16 (*((uint16_t *) inptr)++);
 #else
-	      outbuf[actually++] = (wchar_t) *newinbuf++;
+# define BODY \
+  *((uint32_t *) outptr)++ = *((uint16_t *) inptr)++;
 #endif
-	      data->outbufavail += 4;
-	      *inlen -= 2;
-	    }
-
-	  /* Remember how much we converted.  */
-	  do_write += actually * sizeof (wchar_t);
-
-	  if (*inlen == 1)
-	    {
-	      /* We have an incomplete character at the end.  */
-	      result = GCONV_INCOMPLETE_INPUT;
-	      break;
-	    }
-
-	  /* Check whether an illegal character appeared.  */
-	  if (errno != 0)
-	    {
-	      result = GCONV_ILLEGAL_INPUT;
-	      break;
-	    }
-
-	  if (data->is_last)
-	    {
-	      /* This is the last step.  */
-	      result = (data->outbufavail + sizeof (wchar_t) > data->outbufsize
-			? GCONV_FULL_OUTPUT : GCONV_EMPTY_INPUT);
-	      break;
-	    }
-
-	  /* Status so far.  */
-	  result = GCONV_EMPTY_INPUT;
-
-	  if (data->outbufavail > 0)
-	    {
-	      /* Call the functions below in the chain.  */
-	      size_t newavail = data->outbufavail;
-
-	      result = (*fct) (next_step, next_data, data->outbuf, &newavail,
-			       written, 0);
-
-	      /* Correct the output buffer.  */
-	      if (newavail != data->outbufavail && newavail > 0)
-		{
-		  memmove (data->outbuf,
-			   &data->outbuf[data->outbufavail - newavail],
-			   newavail);
-		  data->outbufavail = newavail;
-		}
-	    }
-	}
-      while (*inlen > 0 && result == GCONV_EMPTY_INPUT);
-
-      __set_errno (save_errno);
-    }
-
-  if (written != NULL && data->is_last)
-    *written = do_write;
-
-  return result;
-}
-
-
-int
-__gconv_transform_internal_ucs2 (struct gconv_step *step,
-				 struct gconv_step_data *data,
-				 const char *inbuf, size_t *inlen,
-				 size_t *written, int do_flush)
-{
-  struct gconv_step *next_step = step + 1;
-  struct gconv_step_data *next_data = data + 1;
-  gconv_fct fct = next_step->fct;
-  size_t do_write;
-  int result;
-
-  /* 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 (do_flush)
-    {
-      /* Clear the state.  */
-      memset (data->statep, '\0', sizeof (mbstate_t));
-      do_write = 0;
-
-      /* Call the steps down the chain if there are any.  */
-      if (data->is_last)
-	result = GCONV_OK;
-      else
-	{
-	  struct gconv_step *next_step = step + 1;
-	  struct gconv_step_data *next_data = data + 1;
-
-	  result = (*fct) (next_step, next_data, NULL, 0, written, 1);
-
-	  /* Clear output buffer.  */
-	  data->outbufavail = 0;
-	}
-    }
-  else
-    {
-      const wchar_t *newinbuf = (const wchar_t *) inbuf;
-      int save_errno = errno;
-      do_write = 0;
-
-      do
-	{
-	  uint16_t *outbuf = (uint16_t *) &data->outbuf[data->outbufavail];
-	  size_t actually = 0;
-
-	  errno = 0;
-
-	  while (data->outbufavail + 2 <= data->outbufsize
-		 && *inlen >= 4)
-	    {
-	      if (*newinbuf >= 0x10000)
-		{
-		  __set_errno (EILSEQ);
-		    break;
-		}
+#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 MIN_NEEDED_INPUT	MIN_NEEDED_FROM
+#define MIN_NEEDED_OUTPUT	MIN_NEEDED_TO
+#define LOOPFCT			FROM_LOOP
 #if __BYTE_ORDER == __LITTLE_ENDIAN
-	      /* Please note that we use the `uint32_t' pointer as a
-		 `uint16_t' pointer which works since we are on a
-		 little endian machine.  */
-	      outbuf[actually++] = bswap_16 (*((uint16_t *) newinbuf));
-	      ++newinbuf;
+# define BODY \
+  {									      \
+    if (*((uint32_t *) inptr) >= 0x10000)				      \
+      {									      \
+	result = GCONV_ILLEGAL_INPUT;					      \
+	break;								      \
+      }									      \
+    /* Please note that we use the `uint32_t' from-pointer as an `uint16_t'   \
+       pointer which works since we are on a little endian machine.  */	      \
+    *((uint16_t *) outptr)++ = bswap_16 (*((uint16_t *) inptr));	      \
+    inptr += 4;								      \
+  }
 #else
-	      outbuf[actually++] = *newinbuf++;
+# define BODY \
+  {									      \
+    if (*((uint32_t *) inptr) >= 0x10000)				      \
+      {									      \
+	result = GCONV_ILLEGAL_INPUT;					      \
+	break;								      \
+      }									      \
+    *((uint16_t *) outptr)++ = *((uint32_t *) inptr)++;			      \
+  }
 #endif
-	      *inlen -= 4;
-	      data->outbufavail += 2;
-	    }
-
-	  /* Remember how much we converted.  */
-	  do_write += (const char *) newinbuf - inbuf;
-
-	  if (*inlen > 0 && *inlen < 4)
-	    {
-	      /* We have an incomplete input character.  */
-	      result = GCONV_INCOMPLETE_INPUT;
-	      break;
-	    }
-
-	  /* Check whether an illegal character appeared.  */
-	  if (errno != 0)
-	    {
-	      result = GCONV_ILLEGAL_INPUT;
-	      break;
-	    }
-
-	  if (data->is_last)
-	    {
-	      /* This is the last step.  */
-	      result = *inlen == 0 ? GCONV_EMPTY_INPUT : GCONV_FULL_OUTPUT;
-	      break;
-	    }
-
-	  /* Status so far.  */
-	  result = GCONV_EMPTY_INPUT;
-
-	  if (data->outbufavail > 0)
-	    {
-	      /* Call the functions below in the chain.  */
-	      size_t newavail = data->outbufavail;
-
-	      result = (*fct) (next_step, next_data, data->outbuf, &newavail,
-			       written, 0);
-
-	      /* Correct the output buffer.  */
-	      if (newavail != data->outbufavail && newavail > 0)
-		{
-		  memmove (data->outbuf,
-			   &data->outbuf[data->outbufavail - newavail],
-			   newavail);
-		  data->outbufavail = newavail;
-		}
-	    }
-	}
-      while (*inlen > 0 && result == GCONV_EMPTY_INPUT);
-
-      __set_errno (save_errno);
-    }
-
-  if (written != NULL && data->is_last)
-    *written = do_write / sizeof (wchar_t);
-
-  return result;
-}
+#include <iconv/loop.c>
+#include <iconv/skeleton.c>
diff --git a/iconv/iconv.c b/iconv/iconv.c
index fc0ed41b50..2f57295097 100644
--- a/iconv/iconv.c
+++ b/iconv/iconv.c
@@ -32,10 +32,27 @@ iconv (iconv_t cd, const char **inbuf, size_t *inbytesleft, char **outbuf,
        size_t *outbytesleft)
 {
   gconv_t gcd = (gconv_t) cd;
+  char *outstart = outbuf ? *outbuf : NULL;
   size_t converted;
   int result;
 
-  result = __gconv (gcd, inbuf, inbytesleft, outbuf, outbytesleft, &converted);
+  if (inbuf == NULL || *inbuf == NULL)
+    {
+      result = __gconv (gcd, NULL, NULL, outbuf, outstart + *outbytesleft,
+			&converted);
+    }
+  else
+    {
+      const char *instart = *inbuf;
+
+      result = __gconv (gcd, inbuf, *inbuf + *inbytesleft, outbuf,
+			*outbuf + *outbytesleft, &converted);
+
+      *inbytesleft -= *inbuf - instart;
+    }
+  if (outstart != NULL)
+    *outbytesleft -= *outbuf - outstart;
+
   switch (result)
     {
     case GCONV_ILLEGAL_DESCRIPTOR:
diff --git a/iconv/iconv_prog.c b/iconv/iconv_prog.c
index 569bd3b3ec..2452a88c5e 100644
--- a/iconv/iconv_prog.c
+++ b/iconv/iconv_prog.c
@@ -299,12 +299,15 @@ process_block (iconv_t cd, const char *addr, size_t len, FILE *output)
 {
 #define OUTBUF_SIZE	32768
   char outbuf[OUTBUF_SIZE];
-  char *outptr = outbuf;
-  size_t outlen = OUTBUF_SIZE;
+  char *outptr;
+  size_t outlen;
+  size_t n;
 
   while (len > 0)
     {
-      size_t n = iconv (cd, &addr, &len, &outptr, &outlen);
+      outptr = outbuf;
+      outlen = OUTBUF_SIZE;
+      n = iconv (cd, &addr, &len, &outptr, &outlen);
 
       if (outptr != outbuf)
 	{
diff --git a/iconv/loop.c b/iconv/loop.c
new file mode 100644
index 0000000000..b8657d574c
--- /dev/null
+++ b/iconv/loop.c
@@ -0,0 +1,226 @@
+/* Conversion loop frame work.
+   Copyright (C) 1998 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 Library General Public License as
+   published by the Free Software Foundation; either version 2 of the
+   License, or (at your option) any later version.
+
+   The GNU C Library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   Library General Public License for more details.
+
+   You should have received a copy of the GNU Library General Public
+   License along with the GNU C Library; see the file COPYING.LIB.  If not,
+   write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+   Boston, MA 02111-1307, USA.  */
+
+/* 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.
+
+   Both values have a default of 1.
+
+     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.
+
+     COUNT_CONVERTED	optional macro which is used to count the actual
+			number of characters converted.  For some conversion
+			it is easy to compute the value afterwards, but for
+			others explicit counting is cheaper.
+
+     BODY		this is supposed to expand to the body of the loop.
+			The user must provide this.
+*/
+
+#include <gconv.h>
+#include <sys/param.h>		/* For MIN.  */
+#define __need_size_t
+#include <stddef.h>
+
+
+/* We need at least one byte for the next round.  */
+#ifndef MIN_NEEDED_INPUT
+# define MIN_NEEDED_INPUT	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
+# define MIN_NEEDED_OUTPUT	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
+
+/* We can calculate the number of converted characters easily if one
+   of the character sets has a fixed width.  */
+#ifndef COUNT_CONVERTED
+# if MIN_NEEDED_INPUT == MAX_NEEDED_INPUT
+#  if MIN_NEEDED_OUTPUT == MAX_NEEDED_OUTPUT
+/* Decide whether one of the charsets has size 1.  */
+#   if MIN_NEEDED_INPUT == 1
+#    define COUNT_CONVERTED	(inptr - *inptrp)
+#   elif MIN_NEEDED_OUTPUT == 1
+#    define COUNT_CONVERTED	(outptr - *outptrp)
+#   else
+/* Else we should see whether one of the two numbers is a power of 2.  */
+#    define COUNT_CONVERTED \
+  ((MIN_NEEDED_INPUT & (-MIN_NEEDED_INPUT)) == MIN_NEEDED_INPUT		      \
+   ? (inptr - *inptrp) : (outptr - *outptrp))
+#   endif
+#  else
+#   define COUNT_CONVERTED	(inptr - *inptrp)
+#  endif
+# elif MIN_NEEDED_OUTPUT == MAX_NEEDED_OUTPUT
+#  define COUNT_CONVERTED	(outptr - *outptrp)
+# endif
+#endif
+
+
+/* The function returns the status, as defined in gconv.h.  */
+static inline int
+LOOPFCT (const unsigned char **inptrp, const unsigned char *inend,
+	 unsigned char **outptrp, unsigned char *outend, mbstate_t *state,
+	 void *data, size_t *converted)
+{
+  int result = GCONV_OK;
+  const unsigned char *inptr = *inptrp;
+  unsigned char *outptr = *outptrp;
+#ifndef COUNT_CONVERTED
+  size_t done = 0;
+#endif
+
+  /* We run one loop where we avoid checks for underflow/overflow of the
+     buffers to speed up the conversion a bit.  */
+  size_t min_in_rounds = (inend - inptr) / MAX_NEEDED_INPUT;
+  size_t min_out_rounds = (outend - outptr) / MAX_NEEDED_OUTPUT;
+  size_t min_rounds = MIN (min_in_rounds, min_out_rounds);
+
+#undef NEED_LENGTH_TEST
+#define NEED_LENGTH_TEST	0
+  while (min_rounds-- > 0)
+    {
+      /* Here comes the body the user provides.  It can stop with RESULT
+	 set to GCONV_INCOMPLETE_INPUT (if the size of the input characters
+	 vary in size), GCONV_ILLEGAL_INPUT, or GCONV_FULL_OUTPUT (if the
+	 output characters vary in size.  */
+      BODY
+
+      /* If necessary count the successful conversion.  */
+#ifndef COUNT_CONVERTED
+      ++done;
+#endif
+    }
+
+  if (result == GCONV_OK)
+    {
+#if MIN_NEEDED_INPUT == MAX_NEEDED_INPUT \
+    && MIN_NEEDED_OUTPUT == MAX_NEEDED_OUTPUT
+      /* We don't need to start another loop since we were able to determine
+	 the maximal number of characters to copy in advance.  What remains
+	 to be determined is the status.  */
+      if (inptr == inend)
+	/* No more input.  */
+	result = GCONV_EMPTY_INPUT;
+      else if ((MIN_NEEDED_OUTPUT != 1 && outptr + MIN_NEEDED_OUTPUT > outend)
+	       || (MIN_NEEDED_OUTPUT == 1 && outptr >= outend))
+	/* Overflow in the output buffer.  */
+	result = GCONV_FULL_OUTPUT;
+      else
+	/* We have something left in the input buffer.  */
+	result = GCONV_INCOMPLETE_INPUT;
+#else
+      result = GCONV_EMPTY_INPUT;
+
+# undef NEED_LENGTH_TEST
+# define NEED_LENGTH_TEST	1
+      while (inptr != inend)
+	{
+	  /* `if' cases for MIN_NEEDED_OUTPUT ==/!= 1 is made to help the
+	     compiler generating better code.  It will optimized away
+	     since MIN_NEEDED_OUTPUT is always a constant.  */
+	  if ((MIN_NEEDED_OUTPUT != 1 && outptr + MIN_NEEDED_OUTPUT > outend)
+	      || (MIN_NEEDED_OUTPUT == 1 && outptr >= outend))
+	    {
+	      /* Overflow in the output buffer.  */
+	      result = GCONV_FULL_OUTPUT;
+	      break;
+	    }
+	  if (MIN_NEEDED_INPUT > 1 && inptr + MIN_NEEDED_INPUT > inend)
+	    {
+	      /* We don't have enough input for another complete input
+		 character.  */
+	      result = GCONV_INCOMPLETE_INPUT;
+	      break;
+	    }
+
+	  /* Here comes the body the user provides.  It can stop with
+	     RESULT set to GCONV_INCOMPLETE_INPUT (if the size of the
+	     input characters vary in size), GCONV_ILLEGAL_INPUT, or
+	     GCONV_FULL_OUTPUT (if the output characters vary in size.  */
+	  BODY
+
+	  /* If necessary count the successful conversion.  */
+# ifndef COUNT_CONVERTED
+	  ++done;
+# endif
+	}
+#endif	/* Input and output charset are not both fixed width.  */
+    }
+
+  /* Add the number of characters we actually converted.  */
+#ifdef COUNT_CONVERTED
+  *converted += COUNT_CONVERTED;
+#else
+  *converted += done;
+#endif
+
+  /* Update the pointers pointed to by the parameters.  */
+  *inptrp = inptr;
+  *outptrp = outptr;
+
+  return result;
+}
+
+
+/* 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 COUNT_CONVERTED
+#undef BODY
+#undef LOOPFCT
diff --git a/iconv/skeleton.c b/iconv/skeleton.c
new file mode 100644
index 0000000000..3582f14110
--- /dev/null
+++ b/iconv/skeleton.c
@@ -0,0 +1,328 @@
+/* Skeleton for a converison module.
+   Copyright (C) 1998 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 Library General Public License as
+   published by the Free Software Foundation; either version 2 of the
+   License, or (at your option) any later version.
+
+   The GNU C Library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   Library General Public License for more details.
+
+   You should have received a copy of the GNU Library General Public
+   License along with the GNU C Library; see the file COPYING.LIB.  If not,
+   write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+   Boston, MA 02111-1307, USA.  */
+
+/* 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.
+
+     DEFINE_DIRECTION_OBJECTS
+			two objects will be defined to be used when the
+			`gconv' function must only distinguish two
+			directions.  This is implied by DEFINE_INIT.
+			If this macro is not defined the following
+			macro must be available.
+
+     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 characters which bring the current state into
+			the initial state.
+
+     FROM_LOOP		name of the function implementing the conversion
+			from the current characters.
+     TO_LOOP		likewise for the other direction
+
+     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'.
+ */
+
+#include <assert.h>
+#include <gconv.h>
+#include <string.h>
+#define __need_size_t
+#define __need_NULL
+#include <stddef.h>
+
+
+/* The direction objects.  */
+#if DEFINE_DIRECTION_OBJECTS || DEFINE_INIT
+static int from_object;
+static int to_object;
+
+# ifndef FROM_DIRECTION
+#  define FROM_DIRECTION step->data == &from_object
+# endif
+#else
+# ifndef FROM_DIRECTION
+#  error "FROM_DIRECTION must be provided if direction objects are not 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
+
+
+/* For conversions from a fixed width character sets to another fixed width
+   character set we we can define RESET_INPUT_BUFFER is necessary.  */
+#if !defined RESET_INPUT_BUFFER && !defined SAVE_RESET_STATE
+# if MIN_NEEDED_FROM == MAX_NEEDED_FROM && MIN_NEEDED_TO == MAX_NEEDED_TO
+/* We have to used these `if's here since the compiler cannot know that
+   (outbuf - outerr) is always divisible by MIN_NEEDED_TO.  */
+#  define RESET_INPUT_BUFFER \
+  if (MIN_NEEDED_FROM % MIN_NEEDED_TO == 0)				      \
+    *inbuf -= (outbuf - outerr) * (MIN_NEEDED_FROM / MIN_NEEDED_TO);	      \
+  else if (MIN_NEEDED_TO % MIN_NEEDED_FROM == 0)			      \
+    *inbuf -= (outbuf - outerr) / (MIN_NEEDED_TO / MIN_NEEDED_FROM);	      \
+  else									      \
+    *inbuf -= ((outbuf - outerr) / MIN_NEEDED_TO) * 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
+
+int
+gconv_init (struct gconv_step *step)
+{
+  /* Determine which direction.  */
+  if (__strcasestr (step->from_name, CHARSET_NAME) != NULL)
+    step->data = &from_object;
+  else if (__strcasestr (step->to_name, CHARSET_NAME) != NULL)
+    step->data = &to_object;
+  else
+    return GCONV_NOCONV;
+
+  step->min_needed_from = MIN_NEEDED_FROM;
+  step->max_needed_from = MAX_NEEDED_FROM;
+  step->min_needed_to = MIN_NEEDED_TO;
+  step->max_needed_to = MAX_NEEDED_TO;
+
+  return GCONV_OK;
+}
+#endif
+
+
+/* The default destructor function does nothing in the moment and so
+   be define it at all.  But we still provide the macro just in case
+   we need it some day.  */
+#if DEFINE_FINI
+#endif
+
+
+/* This is the actual conversion function.  */
+#ifndef FUNCTION_NAME
+# define FUNCTION_NAME	gconv
+#endif
+
+int
+FUNCTION_NAME (struct gconv_step *step, struct gconv_step_data *data,
+	       const char **inbuf, const char *inbufend, size_t *written,
+	       int do_flush)
+{
+  struct gconv_step *next_step = step + 1;
+  struct gconv_step_data *next_data = data + 1;
+  gconv_fct fct = next_step->fct;
+  int status;
+
+  /* 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 (do_flush)
+    {
+      /* Call the steps down the chain if there are any.  */
+      if (data->is_last)
+	status = GCONV_OK;
+      else
+	{
+#ifdef EMIT_SHIFT_TO_INIT
+	  status = GCONV_OK;
+
+	  EMIT_SHIFT_TO_INIT;
+
+	  if (status == GCONV_OK)
+#endif
+	    /* Give the modules below the same chance.  */
+	    status = (*fct) (next_step, next_data, NULL, NULL, written, 1);
+	}
+    }
+  else
+    {
+      /* This variable is used to count the number of characters we
+         actually converted.  */
+      size_t converted = 0;
+
+      /* We preserve the initial values of the pointer variables.  */
+      const char *inptr = *inbuf;
+      char *outbuf = data->outbuf;
+      char *outend = data->outbufend;
+      char *outptr;
+
+      do
+	{
+	  /* Remember the start value for this round.  */
+	  inptr = *inbuf;
+	  /* The outbuf buffer is empty.  */
+	  outptr = outbuf;
+
+	  /* Save the state.  */
+#ifdef SAVE_RESET_STATE
+	  SAVE_RESET_STATE (1);
+#endif
+
+	  if (FROM_DIRECTION)
+	    /* Run the conversion loop.  */
+	    status = FROM_LOOP ((const unsigned char **) inbuf,
+				(const unsigned char *) inbufend,
+				(unsigned char **) &outbuf,
+				(unsigned char *) outend,
+				data->statep, step->data, &converted);
+	  else
+	    /* Run the conversion loop.  */
+	    status = TO_LOOP ((const unsigned char **) inbuf,
+			      (const unsigned char *) inbufend,
+			      (unsigned char **) &outbuf,
+			      (unsigned char *) outend,
+			      data->statep, step->data, &converted);
+
+	  /* If this is the last step leave the loop, there is nothgin
+             we can do.  */
+	  if (data->is_last)
+	    {
+	      /* Store information about how many bytes are available.  */
+	      data->outbuf = outbuf;
+	      break;
+	    }
+
+	  /* Write out all output which was produced.  */
+	  if (outbuf > outptr)
+	    {
+	      const char *outerr = outbuf;
+	      int result;
+
+	      result = (*fct) (next_step, next_data, &outerr, outbuf,
+			       written, 0);
+
+	      if (result != GCONV_EMPTY_INPUT)
+		{
+		  if (outerr != outbuf)
+		    {
+#ifdef RESET_INPUT_BUFFER
+		      RESET_INPUT_BUFFER;
+#else
+		      /* We have a problem with the in on of the functions
+			 below.  Undo the conversion upto the error point.  */
+		      size_t nstatus;
+
+		      /* Reload the pointers.  */
+		      *inbuf = inptr;
+		      outbuf = outptr;
+
+		      /* Reset the state.  */
+# ifdef SAVE_RESET_STATE
+		      SAVE_RESET_STATE (0);
+# endif
+
+		      if (FROM_DIRECTION)
+			/* Run the conversion loop.  */
+			nstatus = FROM_LOOP ((const unsigned char **) inbuf,
+					     (const unsigned char *) inbufend,
+					     (unsigned char **) &outbuf,
+					     (unsigned char *) outerr,
+					     data->statep, step->data,
+					     &converted);
+		      else
+			/* Run the conversion loop.  */
+			nstatus = TO_LOOP ((const unsigned char **) inbuf,
+					   (const unsigned char *) inbufend,
+					   (unsigned char **) &outbuf,
+					   (unsigned char *) outerr,
+					   data->statep, step->data,
+					   &converted);
+
+		      /* We must run out of output buffer space in this
+			 rerun.  */
+		      assert (nstatus == GCONV_FULL_OUTPUT
+			      && outbuf == outerr);
+#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;
+	    }
+	}
+      while (status == GCONV_OK);
+
+      /* Remember how many characters we converted.  */
+      *written += converted;
+    }
+
+  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 DEFINE_DIRECTION_OBJECTS
+#undef FROM_DIRECTION
+#undef EMIT_SHIFT_TO_INIT
+#undef FROM_LOOP
+#undef TO_LOOP
+#undef RESET_STATE
+#undef RESET_INPUT_BUFFER
+#undef FUNCTION_NAME
diff --git a/iconvdata/8bit-gap.c b/iconvdata/8bit-gap.c
index a8d3c99a68..4065a6d777 100644
--- a/iconvdata/8bit-gap.c
+++ b/iconvdata/8bit-gap.c
@@ -19,10 +19,7 @@
    write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
    Boston, MA 02111-1307, USA.  */
 
-#include <gconv.h>
 #include <stdint.h>
-#include <string.h>
-
 
 struct gap
 {
@@ -34,192 +31,68 @@ struct gap
 /* Now we can include the tables.  */
 #include TABLES
 
-/* We use three objects to describe the operation mode.  */
-static int from_8bit_object;
-static int to_8bit_object;
-
-
-int
-gconv_init (struct gconv_step *step)
-{
-  /* Determine which direction.  */
-  if (strcasestr (step->from_name, NAME) != NULL)
-    step->data = &from_8bit_object;
-  else if (strcasestr (step->to_name, NAME) != NULL)
-    step->data = &to_8bit_object;
-  else
-    return GCONV_NOCONV;
-
-  return GCONV_OK;
-}
-
-
-void
-gconv_end (struct gconv_step *data)
-{
-  /* Nothing to do.  */
-}
-
-
-int
-gconv (struct gconv_step *step, struct gconv_step_data *data,
-       const char *inbuf, size_t *inbufsize, size_t *written, int do_flush)
-{
-  struct gconv_step *next_step = step + 1;
-  struct gconv_step_data *next_data = data + 1;
-  gconv_fct fct = next_step->fct;
-  size_t do_write;
-  int result;
-
-  /* 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 (do_flush)
-    {
-      do_write = 0;
-
-      /* Call the steps down the chain if there are any.  */
-      if (data->is_last)
-	result = GCONV_OK;
-      else
-	{
-	  struct gconv_step *next_step = step + 1;
-	  struct gconv_step_data *next_data = data + 1;
-
-	  result = (*fct) (next_step, next_data, NULL, 0, written, 1);
-
-	  /* Clear output buffer.  */
-	  data->outbufavail = 0;
-	}
-    }
-  else
-    {
-      do_write = 0;
-
-      do
-	{
-	  result = GCONV_OK;
-
-	  if (step->data == &from_8bit_object)
-	    {
-	      size_t inchars = *inbufsize;
-	      size_t outwchars = data->outbufavail;
-	      char *outbuf = data->outbuf;
-	      size_t cnt = 0;
-
-	      while (cnt < inchars
-		     && (outwchars + sizeof (wchar_t) <= data->outbufsize))
-		{
-		  wchar_t ch = to_ucs4[((unsigned char *) inbuf)[cnt]];
-
-		  if (ch == L'\0' && inbuf[cnt] != '\0')
-		    {
-		      /* This is an illegal character.  */
-		      result = GCONV_ILLEGAL_INPUT;
-		      break;
-		    }
-
-		  *((wchar_t *) (outbuf + outwchars)) = ch;
-		  ++do_write;
-		  outwchars += sizeof (wchar_t);
-		  ++cnt;
-		}
-	      *inbufsize -= cnt;
-	      inbuf += cnt;
-	      data->outbufavail = outwchars;
-	    }
-	  else
-	    {
-	      size_t inwchars = *inbufsize;
-	      size_t outchars = data->outbufavail;
-	      char *outbuf = data->outbuf;
-	      size_t cnt = 0;
-
-	      while (inwchars >= cnt + sizeof (wchar_t)
-		     && outchars < data->outbufsize)
-		{
-		  const struct gap *rp = from_idx;
-		  unsigned int ch = *((wchar_t *) (inbuf + cnt));
-		  char res;
-
-		  while (ch > rp->end)
-		    ++rp;
-		  if (ch < rp->start)
-		    /* No valid character.  */
-		    break;
-
-		  res = from_ucs4[ch + rp->idx];
-		  if (res == '\0' && ch != 0)
-		    /* No valid character.  */
-		    break;
-
-		  outbuf[outchars] = res;
-		  ++do_write;
-		  ++outchars;
-		  cnt += sizeof (wchar_t);
-		}
-	      *inbufsize -= cnt;
-	      inbuf += cnt;
-	      data->outbufavail = outchars;
-
-	      if (outchars < data->outbufsize)
-		{
-		  /* If there is still room in the output buffer something
-		     is wrong with the input.  */
-		  if (inwchars >= cnt + sizeof (wchar_t))
-		    {
-		      /* An error occurred.  */
-		      result = GCONV_ILLEGAL_INPUT;
-		      break;
-		    }
-		  if (inwchars != cnt)
-		    {
-		      /* There are some unprocessed bytes at the end of the
-			 input buffer.  */
-		      result = GCONV_INCOMPLETE_INPUT;
-		      break;
-		    }
-		}
-	    }
-
-	  if (result != GCONV_OK)
-	    break;
-
-	  if (data->is_last)
-	    {
-	      /* This is the last step.  */
-	      result = (*inbufsize > (step->data == &from_8bit_object
-				      ? 0 : sizeof (wchar_t) - 1)
-			? GCONV_FULL_OUTPUT : GCONV_EMPTY_INPUT);
-	      break;
-	    }
-
-	  /* Status so far.  */
-	  result = GCONV_EMPTY_INPUT;
-
-	  if (data->outbufavail > 0)
-	    {
-	      /* Call the functions below in the chain.  */
-	      size_t newavail = data->outbufavail;
-
-	      result = (*fct) (next_step, next_data, data->outbuf, &newavail,
-			       written, 0);
-
-	      /* Correct the output buffer.  */
-	      if (newavail != data->outbufavail && newavail > 0)
-		{
-		  memmove (data->outbuf,
-			   &data->outbuf[data->outbufavail - newavail],
-			   newavail);
-		  data->outbufavail = newavail;
-		}
-	    }
-	}
-      while (*inbufsize > 0 && result == GCONV_EMPTY_INPUT);
-    }
-
-  if (written != NULL && data->is_last)
-    *written = do_write;
 
-  return result;
-}
+#define FROM_LOOP		from_gap
+#define TO_LOOP			to_gap
+#define DEFINE_INIT		1
+#define DEFINE_FINI		1
+#define MIN_NEEDED_FROM		1
+#define MIN_NEEDED_TO		4
+
+
+/* First define the conversion function from the 8bit charset to UCS4.  */
+#define MIN_NEEDED_INPUT	MIN_NEEDED_FROM
+#define MIN_NEEDED_OUTPUT	MIN_NEEDED_TO
+#define LOOPFCT			FROM_LOOP
+#define BODY \
+  {									      \
+    uint32_t ch = to_ucs4[*inptr];					      \
+									      \
+    if (HAS_HOLES && ch == L'\0' && *inptr != '\0')			      \
+      {									      \
+	/* This is an illegal character.  */				      \
+	result = GCONV_ILLEGAL_INPUT;					      \
+	break;								      \
+      }									      \
+									      \
+    *((uint32_t *) outptr)++ = ch;					      \
+    ++inptr;								      \
+  }
+#include <iconv/loop.c>
+
+
+/* Next, define the other direction.  */
+#define MIN_NEEDED_INPUT	MIN_NEEDED_TO
+#define MIN_NEEDED_OUTPUT	MIN_NEEDED_FROM
+#define LOOPFCT			TO_LOOP
+#define BODY \
+  {									      \
+    const struct gap *rp = from_idx;					      \
+    uint32_t ch = *((uint32_t *) inptr);				      \
+    unsigned char res;							      \
+									      \
+    while (ch > rp->end)						      \
+      ++rp;								      \
+    if (ch < rp->start)							      \
+      {									      \
+	/* This is an illegal character.  */				      \
+	result = GCONV_ILLEGAL_INPUT;					      \
+	break;								      \
+      }									      \
+									      \
+    res = from_ucs4[ch + rp->idx];					      \
+    if (ch != 0 && res == '\0')						      \
+      {									      \
+	/* This is an illegal character.  */				      \
+	result = GCONV_ILLEGAL_INPUT;					      \
+	break;								      \
+      }									      \
+									      \
+    *outptr++ = res;							      \
+    inptr += 4;								      \
+  }
+#include <iconv/loop.c>
+
+
+/* Now define the toplevel functions.  */
+#include <iconv/skeleton.c>
diff --git a/iconvdata/8bit-generic.c b/iconvdata/8bit-generic.c
index 19194ad068..2ea333199e 100644
--- a/iconvdata/8bit-generic.c
+++ b/iconvdata/8bit-generic.c
@@ -18,186 +18,56 @@
    write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
    Boston, MA 02111-1307, USA.  */
 
-#include <gconv.h>
-#include <string.h>
-
-/* We use three objects to describe the operation mode.  */
-static int from_8bit_object;
-static int to_8bit_object;
-
-
-int
-gconv_init (struct gconv_step *step)
-{
-  /* Determine which direction.  */
-  if (strcasestr (step->from_name, NAME) != NULL)
-    step->data = &from_8bit_object;
-  else if (strcasestr (step->to_name, NAME) != NULL)
-    step->data = &to_8bit_object;
-  else
-    return GCONV_NOCONV;
-
-  return GCONV_OK;
-}
-
-
-void
-gconv_end (struct gconv_step *data)
-{
-  /* Nothing to do.  */
-}
-
-
-int
-gconv (struct gconv_step *step, struct gconv_step_data *data,
-       const char *inbuf, size_t *inbufsize, size_t *written, int do_flush)
-{
-  struct gconv_step *next_step = step + 1;
-  struct gconv_step_data *next_data = data + 1;
-  gconv_fct fct = next_step->fct;
-  size_t do_write;
-  int result;
-
-  /* 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 (do_flush)
-    {
-      do_write = 0;
-
-      /* Call the steps down the chain if there are any.  */
-      if (data->is_last)
-	result = GCONV_OK;
-      else
-	{
-	  struct gconv_step *next_step = step + 1;
-	  struct gconv_step_data *next_data = data + 1;
-
-	  result = (*fct) (next_step, next_data, NULL, 0, written, 1);
-
-	  /* Clear output buffer.  */
-	  data->outbufavail = 0;
-	}
-    }
-  else
-    {
-      do_write = 0;
-
-      do
-	{
-	  result = GCONV_OK;
-
-	  if (step->data == &from_8bit_object)
-	    {
-	      size_t inchars = *inbufsize;
-	      size_t outwchars = data->outbufavail;
-	      char *outbuf = data->outbuf;
-	      size_t cnt = 0;
-
-	      while (cnt < inchars
-		     && (outwchars + sizeof (wchar_t) <= data->outbufsize))
-		{
-		  wchar_t ch = to_ucs4[((unsigned char *) inbuf)[cnt]];
-
-		  if (ch == L'\0' && inbuf[cnt] != '\0')
-		    {
-		      /* This is an illegal character.  */
-		      result = GCONV_ILLEGAL_INPUT;
-		      break;
-		    }
-
-		  *((wchar_t *) (outbuf + outwchars)) = ch;
-		  ++do_write;
-		  outwchars += sizeof (wchar_t);
-		  ++cnt;
-		}
-	      *inbufsize -= cnt;
-	      inbuf += cnt;
-	      data->outbufavail = outwchars;
-	    }
-	  else
-	    {
-	      size_t inwchars = *inbufsize;
-	      size_t outchars = data->outbufavail;
-	      char *outbuf = data->outbuf;
-	      size_t cnt = 0;
-
-	      while (inwchars >= cnt + sizeof (wchar_t)
-		     && outchars < data->outbufsize)
-		{
-		  int ch = *((wchar_t *) (inbuf + cnt));
-
-		  if (ch >= sizeof (from_ucs4) / sizeof (from_ucs4[0])
-		      || ch < 0 || (from_ucs4[ch] == '\0' && ch != 0))
-		    break;
-
-		  outbuf[outchars] = from_ucs4[ch];
-		  ++do_write;
-		  ++outchars;
-		  cnt += sizeof (wchar_t);
-		}
-	      *inbufsize -= cnt;
-	      inbuf += cnt;
-	      data->outbufavail = outchars;
-
-	      if (outchars < data->outbufsize)
-		{
-		  /* If there is still room in the output buffer something
-		     is wrong with the input.  */
-		  if (inwchars >= cnt + sizeof (wchar_t))
-		    {
-		      /* An error occurred.  */
-		      result = GCONV_ILLEGAL_INPUT;
-		      break;
-		    }
-		  if (inwchars != cnt)
-		    {
-		      /* There are some unprocessed bytes at the end of the
-			 input buffer.  */
-		      result = GCONV_INCOMPLETE_INPUT;
-		      break;
-		    }
-		}
-	    }
-
-	  if (result != GCONV_OK)
-	    break;
-
-	  if (data->is_last)
-	    {
-	      /* This is the last step.  */
-	      result = (*inbufsize > (step->data == &from_8bit_object
-				      ? 0 : sizeof (wchar_t) - 1)
-			? GCONV_FULL_OUTPUT : GCONV_EMPTY_INPUT);
-	      break;
-	    }
-
-	  /* Status so far.  */
-	  result = GCONV_EMPTY_INPUT;
-
-	  if (data->outbufavail > 0)
-	    {
-	      /* Call the functions below in the chain.  */
-	      size_t newavail = data->outbufavail;
-
-	      result = (*fct) (next_step, next_data, data->outbuf, &newavail,
-			       written, 0);
-
-	      /* Correct the output buffer.  */
-	      if (newavail != data->outbufavail && newavail > 0)
-		{
-		  memmove (data->outbuf,
-			   &data->outbuf[data->outbufavail - newavail],
-			   newavail);
-		  data->outbufavail = newavail;
-		}
-	    }
-	}
-      while (*inbufsize > 0 && result == GCONV_EMPTY_INPUT);
-    }
-
-  if (written != NULL && data->is_last)
-    *written = do_write;
-
-  return result;
-}
+#define FROM_LOOP		from_generic
+#define TO_LOOP			to_generic
+#define DEFINE_INIT		1
+#define DEFINE_FINI		1
+#define MIN_NEEDED_FROM		1
+#define MIN_NEEDED_TO		4
+
+
+/* First define the conversion function from the 8bit charset to UCS4.  */
+#define MIN_NEEDED_INPUT	MIN_NEEDED_FROM
+#define MIN_NEEDED_OUTPUT	MIN_NEEDED_TO
+#define LOOPFCT			FROM_LOOP
+#define BODY \
+  {									      \
+    uint32_t ch = to_ucs4[*inptr];					      \
+									      \
+    if (HAS_HOLES && ch == L'\0' && *inptr != '\0')			      \
+      {									      \
+	/* This is an illegal character.  */				      \
+	result = GCONV_ILLEGAL_INPUT;					      \
+	break;								      \
+      }									      \
+									      \
+    *((uint32_t *) outptr)++ = ch;					      \
+    ++inptr;								      \
+  }
+#include <iconv/loop.c>
+
+
+/* Next, define the other direction.  */
+#define MIN_NEEDED_INPUT	MIN_NEEDED_TO
+#define MIN_NEEDED_OUTPUT	MIN_NEEDED_FROM
+#define LOOPFCT			TO_LOOP
+#define BODY \
+  {									      \
+    uint32_t ch = *((uint32_t *) inptr);				      \
+									      \
+    if (ch >= sizeof (from_ucs4) / sizeof (from_ucs4[0])		      \
+	|| (ch != 0 && from_ucs4[ch] == '\0'))				      \
+      {									      \
+	/* This is an illegal character.  */				      \
+	result = GCONV_ILLEGAL_INPUT;					      \
+	break;								      \
+      }									      \
+									      \
+    *outptr++ = from_ucs4[ch];						      \
+    inptr += 4;								      \
+  }
+#include <iconv/loop.c>
+
+
+/* Now define the toplevel functions.  */
+#include <iconv/skeleton.c>
diff --git a/iconvdata/Makefile b/iconvdata/Makefile
index dd1c391c6c..69576859ec 100644
--- a/iconvdata/Makefile
+++ b/iconvdata/Makefile
@@ -26,8 +26,8 @@ modules	:= ISO8859-1 ISO8859-2 ISO8859-3 ISO8859-4 ISO8859-5		\
 	   ISO8859-6 ISO8859-7 ISO8859-8 ISO8859-9 ISO8859-10		\
 	   T.61 ISO_6937 SJIS KOI-8 KOI8-R LATIN-GREEK LATIN-GREEK-1	\
 	   HP-ROMAN8 EBCDIC-AT-DE EBCDIC-AT-DE-A EBCDIC-CA-FR		\
-	   EUC-KR UHC JOHAB libJIS libKSC ISO646 BIG5 EUC-JP libGB	\
-	   EUC-CN libCNS EUC-TW
+	   EUC-KR UHC JOHAB libJIS libKSC BIG5 EUC-JP libGB		\
+	   EUC-CN libCNS EUC-TW # ISO646
 modules.so := $(addsuffix .so, $(modules))
 
 
@@ -211,7 +211,7 @@ endif
 include ../Rules
 
 .PHONY: do-iconv-test
-tests: do-iconv-test
+#tests: do-iconv-test
 
 do-iconv-test: run-iconv-test.sh $(objpfx)gconv-modules \
 	       $(addprefix $(objpfx),$(modules.so)) \
diff --git a/iconvdata/big5.c b/iconvdata/big5.c
index a6a2580dd7..2962712167 100644
--- a/iconvdata/big5.c
+++ b/iconvdata/big5.c
@@ -8411,289 +8411,180 @@ static const char from_ucs4_tab13[][2] =
 };
 
 
-/* Direction of the transformation.  */
-static int to_big5_object;
-static int from_big5_object;
+/* Definitions used in the body of the `gconv' function.  */
+#define CHARSET_NAME		"BIG5"
+#define FROM_LOOP		from_big5
+#define TO_LOOP			to_big5
+#define DEFINE_INIT		1
+#define DEFINE_FINI		1
+#define MIN_NEEDED_FROM		1
+#define MAX_NEEDED_FROM		2
+#define MIN_NEEDED_TO		4
 
 
-int
-gconv_init (struct gconv_step *step)
-{
-  /* Determine which direction.  */
-  if (strcasestr (step->from_name, "BIG5") != NULL)
-    step->data = &from_big5_object;
-  else if (strcasestr (step->to_name, "BIG5") != NULL)
-    step->data = &to_big5_object;
-  else
-    return GCONV_NOCONV;
-
-  return GCONV_OK;
-}
-
-
-void
-gconv_end (struct gconv_step *data)
-{
-  /* Nothing to do.  */
-}
-
-
-int
-gconv (struct gconv_step *step, struct gconv_step_data *data,
-       const char *inbuf, size_t *inbufsize, size_t *written, int do_flush)
-{
-  struct gconv_step *next_step = step + 1;
-  struct gconv_step_data *next_data = data + 1;
-  gconv_fct fct = next_step->fct;
-  size_t do_write;
-  int result;
-
-  /* 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 (do_flush)
-    {
-      do_write = 0;
-
-      /* Call the steps down the chain if there are any.  */
-      if (data->is_last)
-	result = GCONV_OK;
-      else
-	{
-	  result = (*fct) (next_step, next_data, NULL, 0, written, 1);
-
-	  /* Clear output buffer.  */
-	  data->outbufavail = 0;
-	}
-    }
-  else
-    {
-      do_write = 0;
-
-      do
-	{
-	  result = GCONV_OK;
-
-	  if (step->data == &from_big5_object)
-	    {
-	      size_t inchars = *inbufsize;
-	      size_t outwchars = data->outbufavail;
-	      char *outbuf = data->outbuf;
-	      size_t cnt = 0;
-
-	      while (cnt < inchars
-		     && (outwchars + sizeof (wchar_t) <= data->outbufsize))
-		{
-		  int inchar = inbuf[cnt];
-		  wchar_t ch;
-
-		  if (inchar < '\xa1' || inchar > '\xfe')
-		    ch = (wchar_t) inchar;
-		  else
-		    {
-		      /* Two-byte character.  First test whether the next
-			 character is also available.  */
-		      int inchar2;
-		      int idx;
-
-		      if (cnt + 1 >= inchars)
-			{
-			  /* The second character is not available.  Store
-			     the intermediate result.  */
-			  result = GCONV_INCOMPLETE_INPUT;
-			  break;
-			}
-
-		      idx = (inchar - 0xa1) * 157;
-		      inchar2 = inbuf[++cnt];
-		      /* See whether the second byte is in the correct
-			 range.  */
-		      if (inchar2 >= '\x40' && inchar2 <= '\x7e')
-			idx += inchar2 - 0x40;
-		      else if (inchar2 >= '\xa1' && inchar2 <= '\xfe')
-			idx += 0x3f + (inchar2 - 0xa1);
-		      else
-			{
-			  /* This is illegal.  */
-			  --cnt;
-			  result  = GCONV_ILLEGAL_INPUT;
-			  break;
-			}
-
-		      /* Get the value from the table.  */
-		      ch = big5_to_ucs[idx];
-
-		      if (ch == L'\0')
-			--cnt;
-		    }
-
-		  if (ch == L'\0' && inbuf[cnt] != '\0')
-		    {
-		      /* This is an illegal character.  */
-		      result = GCONV_ILLEGAL_INPUT;
-		      break;
-		    }
-
-		  *((wchar_t *) (outbuf + outwchars)) = ch;
-		  ++do_write;
-		  outwchars += sizeof (wchar_t);
-		  ++cnt;
-		}
-	      *inbufsize -= cnt;
-	      inbuf += cnt;
-	      data->outbufavail = outwchars;
-	    }
-	  else
-	    {
-	      size_t inwchars = *inbufsize;
-	      size_t outchars = data->outbufavail;
-	      char *outbuf = data->outbuf;
-	      size_t cnt = 0;
-	      int extra = 0;
-
-	      while (inwchars >= cnt + sizeof (wchar_t)
-		     && outchars < data->outbufsize)
-		{
-		  int ch = *((wchar_t *) (inbuf + cnt));
-		  char buf[2];
-		  const char *cp;
-
-		  if (ch >= (sizeof (from_ucs4_tab1)
-			     / sizeof (from_ucs4_tab1[0])))
-		    {
-		      if (ch >= 0x2c7 && ch <= 0x2d9)
-			cp = from_ucs4_tab2[ch - 0x2c7];
-		      else if (ch >= 0x391 && ch <= 0x451)
-			cp = from_ucs4_tab3[ch - 0x391];
-		      else if (ch >= 0x2013 && ch <= 0x203e)
-			cp = from_ucs4_tab4[ch - 0x2013];
-		      else if (ch == 0x2103)
-			cp = "\xa2\x4a";
-		      else if (ch == 0x2105)
-			cp = "\xa1\xc1";
-		      else if (ch == 0x2109)
-			cp = "\xa2\x4b";
-		      else if (ch >= 0x2160 && ch <= 0x2169)
-			{
-			  buf[0] = '\xa2';
-			  buf[1] = '\xb9' + (ch - 0x2160);
-			  cp = buf;
-			}
-		      else if (ch >= 0x2190 && ch <= 0x2199)
-			cp = from_ucs4_tab5[ch - 0x2190];
-		      else if (ch >= 0x221a && ch <= 0x22bf)
-			cp = from_ucs4_tab6[ch - 0x221a];
-		      else if (ch >= 0x2460 && ch <= 0x247d)
-			cp = from_ucs4_tab7[ch - 0x2460];
-		      else if (ch >= 0x2500 && ch <= 0x2642)
-			cp = from_ucs4_tab8[ch - 0x2500];
-		      else if (ch >= 0x3000 && ch <= 0x3129)
-			cp = from_ucs4_tab9[ch - 0x3000];
-		      else if (ch == 0x32a3)
-			cp = "\xa1\xc0";
-		      else if (ch >= 0x338e && ch <= 0x33d5)
-			cp = from_ucs4_tab10[ch - 0x338e];
-		      else if (ch >= 0x4e00 && ch <= 0x9fa4)
-			cp = from_ucs4_tab11[ch - 0x4e00];
-		      else if (ch == 0xfa0c)
-			cp = "\xc9\x4a";
-		      else if (ch == 0xfa0d)
-			cp = "\xdd\xfc";
-		      else if (ch >= 0xfe30 && ch <= 0xfe6b)
-			cp = from_ucs4_tab12[ch - 0xfe30];
-		      else if (ch >= 0xff01 && ch <= 0xff64)
-			cp = from_ucs4_tab13[ch - 0xff01];
-		      else
-			/* Illegal character.  */
-			break;
-		    }
-		  else
-		    cp = from_ucs4_tab1[ch];
-
-		  if (cp[0] == '\0' && ch != 0)
-		    /* Illegal character.  */
-		    break;
-
-		  outbuf[outchars] = cp[0];
-		  /* Now test for a possible second byte and write this
-		     if possible.  */
-		  if (cp[1] != '\0')
-		    {
-		      if (outchars + 1 >= data->outbufsize)
-			{
-			  /* The result does not fit into the buffer.  */
-			  extra = 1;
-			  break;
-			}
-		      outbuf[++outchars] = cp[1];
-		    }
-
-		  ++do_write;
-		  ++outchars;
-		  cnt += sizeof (wchar_t);
-		}
-	      *inbufsize -= cnt;
-	      inbuf += cnt;
-	      data->outbufavail = outchars;
-
-	      if (outchars + extra < data->outbufsize)
-		{
-		  /* If there is still room in the output buffer something
-		     is wrong with the input.  */
-		  if (inwchars >= cnt + sizeof (wchar_t))
-		    {
-		      /* An error occurred.  */
-		      result = GCONV_ILLEGAL_INPUT;
-		      break;
-		    }
-		  if (inwchars != cnt)
-		    {
-		      /* There are some unprocessed bytes at the end of the
-			 input buffer.  */
-		      result = GCONV_INCOMPLETE_INPUT;
-		      break;
-		    }
-		}
-	    }
-
-	  if (result != GCONV_OK)
-	    break;
-
-	  if (data->is_last)
-	    {
-	      /* This is the last step.  */
-	      result = (*inbufsize > (step->data == &from_big5_object
-				      ? 0 : sizeof (wchar_t) - 1)
-			? GCONV_FULL_OUTPUT : GCONV_EMPTY_INPUT);
-	      break;
-	    }
-
-	  /* Status so far.  */
-	  result = GCONV_EMPTY_INPUT;
-
-	  if (data->outbufavail > 0)
-	    {
-	      /* Call the functions below in the chain.  */
-	      size_t newavail = data->outbufavail;
+/* First define the conversion function from Big5 to UCS4.  */
+#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 \
+  {									      \
+    uint32_t ch = *inptr;						      \
+									      \
+    if (ch >= '\xa1' && ch <= '\xff')					      \
+      {									      \
+	/* Two-byte character.  First test whether the next character	      \
+	   is also available.  */					      \
+	uint32_t ch2;							      \
+	int idx;							      \
+									      \
+	if (NEED_LENGTH_TEST && inptr + 1 >= inend)			      \
+	  {								      \
+	    /* The second character is not available.  */		      \
+	    result = GCONV_INCOMPLETE_INPUT;				      \
+	    break;							      \
+	  }								      \
+									      \
+	idx = (ch - 0xa1) * 157;					      \
+	ch2 = inptr[1];							      \
+	/* See whether the second byte is in the correct range.  */	      \
+	if (ch2 >= '\x40' && ch2 <= '\x7e')				      \
+	  idx += ch2 - 0x40;						      \
+	else if (ch2 >= '\xa1' && ch2 <= '\xfe')			      \
+	  idx += 0x3f + (ch2 - 0xa1);					      \
+	else								      \
+	  {								      \
+	    /* This is illegal.  */					      \
+	    result = GCONV_ILLEGAL_INPUT;				      \
+	    break;							      \
+	  }								      \
+									      \
+	/* Get the value from the table.  */				      \
+	ch = big5_to_ucs[idx];						      \
+									      \
+	/* Is this character defined?  */				      \
+	if (ch == L'\0' && *inptr != '\0')				      \
+	  {								      \
+	    /* This is an illegal character.  */			      \
+	    result = GCONV_ILLEGAL_INPUT;				      \
+	    break;							      \
+	  }								      \
+									      \
+	inptr += 2;							      \
+      }									      \
+    else								      \
+      ++inptr;								      \
+									      \
+    *((uint32_t *) outptr)++ = ch;					      \
+  }
+#include <iconv/loop.c>
 
-	      result = (*fct) (next_step, next_data, data->outbuf, &newavail,
-			       written, 0);
 
-	      /* Correct the output buffer.  */
-	      if (newavail != data->outbufavail && newavail > 0)
-		{
-		  memmove (data->outbuf,
-			   &data->outbuf[data->outbufavail - newavail],
-			   newavail);
-		  data->outbufavail = newavail;
-		}
-	    }
-	}
-      while (*inbufsize > 0 && result == GCONV_EMPTY_INPUT);
-    }
+/* Next, define the other direction.  */
+#define MIN_NEEDED_INPUT	MIN_NEEDED_TO
+#define MIN_NEEDED_OUTPUT	MIN_NEEDED_FROM
+#define MAX_NEEDED_OUTPUT	MAX_NEEDED_FROM
+#define LOOPFCT			TO_LOOP
+#define BODY \
+  {									      \
+    uint32_t ch = *((uint32_t *) inptr);				      \
+    char buf[2];							      \
+    const char *cp;							      \
+									      \
+    if (ch >= sizeof (from_ucs4_tab1) / sizeof (from_ucs4_tab1[0]))	      \
+      switch (ch)							      \
+	{								      \
+        case 0x2c7 ... 0x2d9:						      \
+	  cp = from_ucs4_tab2[ch - 0x2c7];				      \
+	  break;							      \
+	case 0x391 ... 0x451:						      \
+	  cp = from_ucs4_tab3[ch - 0x391];				      \
+	  break;							      \
+	case 0x2013 ... 0x203e:						      \
+	  cp = from_ucs4_tab4[ch - 0x2013];				      \
+	  break;							      \
+	case 0x2103:							      \
+	  cp = "\xa2\x4a";						      \
+	  break;							      \
+	case 0x2105:							      \
+	  cp = "\xa1\xc1";						      \
+	  break;							      \
+	case 0x2109:							      \
+	  cp = "\xa2\x4b";						      \
+	  break;							      \
+	case 0x2160 ... 0x2169:						      \
+	  {								      \
+	    buf[0] = '\xa2';						      \
+	    buf[1] = '\xb9' + (ch - 0x2160);				      \
+	    cp = buf;							      \
+	  }								      \
+	  break;							      \
+	case 0x2190 ... 0x2199:						      \
+	  cp = from_ucs4_tab5[ch - 0x2190];				      \
+	  break;							      \
+	case 0x221a ...	0x22bf:						      \
+	  cp = from_ucs4_tab6[ch - 0x221a];				      \
+	  break;							      \
+	case 0x2460 ... 0x247d:						      \
+	  cp = from_ucs4_tab7[ch - 0x2460];				      \
+	  break;							      \
+	case 0x2500 ... 0x2642:						      \
+	  cp = from_ucs4_tab8[ch - 0x2500];				      \
+	  break;							      \
+	case 0x3000 ... 0x3129:						      \
+	  cp = from_ucs4_tab9[ch - 0x3000];				      \
+	  break;							      \
+	case 0x32a3:							      \
+	  cp = "\xa1\xc0";						      \
+	  break;							      \
+	case 0x338e ... 0x33d5:						      \
+	  cp = from_ucs4_tab10[ch - 0x338e];				      \
+	  break;							      \
+	case 0x4e00 ... 0x9fa4:						      \
+	  cp = from_ucs4_tab11[ch - 0x4e00];				      \
+	  break;							      \
+	case 0xfa0c:							      \
+	  cp = "\xc9\x4a";						      \
+	  break;							      \
+	case 0xfa0d:							      \
+	  cp = "\xdd\xfc";						      \
+	  break;							      \
+	case 0xfe30 ... 0xfe6b:						      \
+	  cp = from_ucs4_tab12[ch - 0xfe30];				      \
+	  break;							      \
+	case 0xff01 ... 0xff64:						      \
+	  cp = from_ucs4_tab13[ch - 0xff01];				      \
+	  break;							      \
+	default:							      \
+	  /* Illegal character.  */					      \
+	  cp = "";							      \
+	  break;							      \
+	}								      \
+    else								      \
+      cp = from_ucs4_tab1[ch];						      \
+									      \
+    if (cp[0] == '\0' && ch != 0)					      \
+      {									      \
+	/* Illegal character.  */					      \
+	result = GCONV_ILLEGAL_INPUT;					      \
+	break;								      \
+      }									      \
+									      \
+    /* See whether there is enough room for the second byte we write.  */     \
+    if (NEED_LENGTH_TEST && cp[1] != '\0' && outptr + 1 >= outend)	      \
+      {									      \
+	/* We have not enough room.  */					      \
+	result = GCONV_FULL_OUTPUT;					      \
+	break;								      \
+      }									      \
+									      \
+    *outptr++ = cp[0];							      \
+    if (cp[1] != '\0')							      \
+      *outptr++ = cp[1];						      \
+    inptr += 4;								      \
+  }
+#include <iconv/loop.c>
 
-  if (written != NULL && data->is_last)
-    *written = do_write;
 
-  return result;
-}
+/* Now define the toplevel functions.  */
+#include <iconv/skeleton.c>
diff --git a/iconvdata/cns11643.c b/iconvdata/cns11643.c
index 903548261b..bd1994f1d9 100644
--- a/iconvdata/cns11643.c
+++ b/iconvdata/cns11643.c
@@ -44,7 +44,7 @@
    printf ("\n");
    ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
 */
-const uint16_t cns11643l2_to_ucs4_tab[] =
+const uint16_t __cns11643l2_to_ucs4_tab[] =
 {
   [0x0000] = 0x4e42, [0x0001] = 0x4e5c, [0x0002] = 0x51f5, [0x0003] = 0x531a,
   [0x0004] = 0x5382, [0x0005] = 0x4e07, [0x0006] = 0x4e0c, [0x0007] = 0x4e47,
@@ -1985,7 +1985,7 @@ const uint16_t cns11643l2_to_ucs4_tab[] =
    printf ("\n");
    ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
 */
-const uint16_t cns11643l14_to_ucs4_tab[] =
+const uint16_t __cns11643l14_to_ucs4_tab[] =
 {
   [0x0000] = 0x4e28, [0x0001] = 0x4e36, [0x0002] = 0x4e3f, [0x0003] = 0x4e85,
   [0x0004] = 0x4e05, [0x0005] = 0x4e04, [0x0006] = 0x5182, [0x0007] = 0x5196,
@@ -3064,7 +3064,7 @@ const uint16_t cns11643l14_to_ucs4_tab[] =
    printf ("\n");
    ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
 */
-const char cns11643_from_ucs4_tab[][3] =
+const char __cns11643_from_ucs4_tab[][3] =
 {
   [0x0000] = "\x01\x44\x21", [0x0001] = "\x01\x44\x23",
   [0x0003] = "\x01\x44\x24", [0x0004] = "\x0e\x21\x26",
diff --git a/iconvdata/cns11643.h b/iconvdata/cns11643.h
index f791d4cdb3..ccab8011ce 100644
--- a/iconvdata/cns11643.h
+++ b/iconvdata/cns11643.h
@@ -21,8 +21,8 @@
 #include <stdint.h>
 
 /* Table for CNS 11643, plane 2 to UCS4 conversion.  */
-extern const uint16_t cns11643l2_to_ucs4_tab[];
-extern const uint16_t cns11643l14_to_ucs4_tab[];
+extern const uint16_t __cns11643l2_to_ucs4_tab[];
+extern const uint16_t __cns11643l14_to_ucs4_tab[];
 
 
 static inline wchar_t
@@ -54,19 +54,19 @@ cns11643_to_ucs4 (const char **s, size_t avail, unsigned char offset)
     {
       if (idx > 0x2196)
 	return UNKNOWN_10646_CHAR;
-      result = cns11643l1_to_ucs4_tab[idx];
+      result = __cns11643l1_to_ucs4_tab[idx];
     }
   else if ((ch - 0x21 - offset) == 2)
     {
       if (idx > 0x1de1)
 	return UNKNOWN_10646_CHAR;
-      result = cns11643l2_to_ucs4_tab[idx];
+      result = __cns11643l2_to_ucs4_tab[idx];
     }
   else if ((ch - 0x21 - offset) == 0xe)
     {
       if (idx > 0x19bd)
 	return UNKNOWN_10646_CHAR;
-      result = cns11643l14_to_ucs4_tab[idx];
+      result = __cns11643l14_to_ucs4_tab[idx];
     }
   else
     return UNKNOWN_10646_CHAR;
@@ -81,21 +81,21 @@ cns11643_to_ucs4 (const char **s, size_t avail, unsigned char offset)
 
 
 /* Tables for the UCS4 -> CNS conversion.  */
-extern const char cns11643l1_from_ucs4_tab1[][2];
-extern const char cns11643l1_from_ucs4_tab2[][2];
-extern const char cns11643l1_from_ucs4_tab3[][2];
-extern const char cns11643l1_from_ucs4_tab4[][2];
-extern const char cns11643l1_from_ucs4_tab5[][2];
-extern const char cns11643l1_from_ucs4_tab6[][2];
-extern const char cns11643l1_from_ucs4_tab7[][2];
-extern const char cns11643l1_from_ucs4_tab8[][2];
-extern const char cns11643l1_from_ucs4_tab9[][2];
-extern const char cns11643l1_from_ucs4_tab10[][2];
-extern const char cns11643l1_from_ucs4_tab11[][2];
-extern const char cns11643l1_from_ucs4_tab12[][2];
-extern const char cns11643l1_from_ucs4_tab13[][2];
-extern const char cns11643l1_from_ucs4_tab14[][2];
-extern const char cns11643_from_ucs4_tab[][3];
+extern const char __cns11643l1_from_ucs4_tab1[][2];
+extern const char __cns11643l1_from_ucs4_tab2[][2];
+extern const char __cns11643l1_from_ucs4_tab3[][2];
+extern const char __cns11643l1_from_ucs4_tab4[][2];
+extern const char __cns11643l1_from_ucs4_tab5[][2];
+extern const char __cns11643l1_from_ucs4_tab6[][2];
+extern const char __cns11643l1_from_ucs4_tab7[][2];
+extern const char __cns11643l1_from_ucs4_tab8[][2];
+extern const char __cns11643l1_from_ucs4_tab9[][2];
+extern const char __cns11643l1_from_ucs4_tab10[][2];
+extern const char __cns11643l1_from_ucs4_tab11[][2];
+extern const char __cns11643l1_from_ucs4_tab12[][2];
+extern const char __cns11643l1_from_ucs4_tab13[][2];
+extern const char __cns11643l1_from_ucs4_tab14[][2];
+extern const char __cns11643_from_ucs4_tab[][3];
 
 
 static inline size_t
@@ -103,120 +103,104 @@ ucs4_to_cns11643 (wchar_t wch, char *s, size_t avail)
 {
   unsigned int ch = (unsigned int) wch;
   char buf[2];
-  const char *cp = NULL;
+  const char *cp = buf;
   int needed = 2;
 
-  if (ch < 0xa7)
-    cp = "";
-  else if (ch < 0xf7)
-    cp = cns11643l1_from_ucs4_tab1[ch - 0xa7];
-  else if (ch < 0x2c7)
-    cp = "";
-  else if (ch <= 0x2d9)
-    cp = cns11643l1_from_ucs4_tab2[ch - 0x2c7];
-  else if (ch < 0x391)
-    cp = "";
-  else if (ch <= 0x3c9)
-    cp = cns11643l1_from_ucs4_tab3[ch - 0x391];
-  else if (ch < 0x2013)
-    cp = "";
-  else if (ch <= 0x203e)
-    cp = cns11643l1_from_ucs4_tab4[ch - 0x2013];
-  else if (ch == 0x2103)
-    cp = "\x22\x6a";
-  else if (ch == 0x2105)
-    cp = "\x22\x22";
-  else if (ch == 0x2109)
-    cp = "\x22\x6b";
-  else if (ch < 0x2160)
-    cp = "";
-  else if (ch <= 0x2169)
+  switch (ch)
     {
+    case 0xa7 ... 0xf7:
+      cp = __cns11643l1_from_ucs4_tab1[ch - 0xa7];
+      break;
+    case 0x2c7 ... 0x2d9:
+      cp = __cns11643l1_from_ucs4_tab2[ch - 0x2c7];
+      break;
+    case 0x391 ... 0x3c9:
+      cp = __cns11643l1_from_ucs4_tab3[ch - 0x391];
+      break;
+    case 0x2013 ... 0x203e:
+      cp = __cns11643l1_from_ucs4_tab4[ch - 0x2013];
+      break;
+    case 0x2103:
+      cp = "\x22\x6a";
+      break;
+    case 0x2105:
+      cp = "\x22\x22";
+      break;
+    case 0x2109:
+      cp = "\x22\x6b";
+      break;
+    case 0x2160 ...0x2169:
       buf[0] = '\x24';
       buf[1] = '\x2b' + (ch - 0x2160);
-      cp = buf;
-    }
-  else if (ch < 0x2170)
-    cp = "";
-  else if (ch <= 0x2179)
-    {
+      break;
+    case 0x2170 ... 0x2179:
       buf[0] = '\x26';
       buf[1] = '\x35' + (ch - 0x2170);
-      cp = buf;
-    }
-  else if (ch < 0x2190)
-    cp = "";
-  else if (ch <= 0x2199)
-    cp = cns11643l1_from_ucs4_tab5[ch - 0x2190];
-  else if (ch < 0x2215)
-    cp = "";
-  else if (ch <= 0x2267)
-    cp = cns11643l1_from_ucs4_tab6[ch - 0x2215];
-  else if (ch == 0x22a5)
-    cp = "\x22\x47";
-  else if (ch == 0x22bf)
-    cp = "\x22\x4a";
-  else if (ch < 0x2400)
-    cp = "";
-  else if (ch <= 0x2421)
-    cp = cns11643l1_from_ucs4_tab7[ch - 0x2400];
-  else if (ch < 0x2460)
-    cp = "";
-  else if (ch <= 0x247d)
-    cp = cns11643l1_from_ucs4_tab8[ch - 0x2460];
-  else if (ch < 0x2500)
-    cp = "";
-  else if (ch <= 0x2642)
-    cp = cns11643l1_from_ucs4_tab9[ch - 0x2500];
-  else if (ch < 0x3000)
-    cp = "";
-  else if (ch <= 0x3029)
-    cp = cns11643l1_from_ucs4_tab10[ch - 0x3000];
-  else if (ch == 0x30fb)
-    cp = "\x21\x26";
-  else if (ch < 0x3105)
-    cp = "";
-  else if (ch <= 0x3129)
-    {
+      break;
+    case 0x2190 ... 0x2199:
+      cp = __cns11643l1_from_ucs4_tab5[ch - 0x2190];
+      break;
+    case 0x2215 ... 0x2267:
+      cp = __cns11643l1_from_ucs4_tab6[ch - 0x2215];
+      break;
+    case 0x22a5:
+      cp = "\x22\x47";
+      break;
+    case 0x22bf:
+      cp = "\x22\x4a";
+      break;
+    case 0x2400 ... 0x2421:
+      cp = __cns11643l1_from_ucs4_tab7[ch - 0x2400];
+      break;
+    case 0x2460 ... 0x247d:
+      cp = __cns11643l1_from_ucs4_tab8[ch - 0x2460];
+      break;
+    case 0x2500 ... 0x2642:
+      cp = __cns11643l1_from_ucs4_tab9[ch - 0x2500];
+    case 0x3000 ... 0x3029:
+      cp = __cns11643l1_from_ucs4_tab10[ch - 0x3000];
+      break;
+    case 0x30fb:
+      cp = "\x21\x26";
+      break;
+    case 0x3105 ... 0x3129:
       buf[0] = '\x25';
       buf[1] = '\x26' + (ch - 0x3105);
-      cp = buf;
-    }
-  else if (ch == 0x32a3)
-    cp = "\x22\x21";
-  else if (ch < 0x338e)
-    cp = "";
-  else if (ch <= 0x33d5)
-    cp = cns11643l1_from_ucs4_tab11[ch - 0x338e];
-  else if (ch < 0x4e00)
-    cp = "";
-  else if (ch <= 0x9f9c)
-    {
-      cp = cns11643l1_from_ucs4_tab12[ch - 0x4e00];
+      break;
+    case 0x32a3:
+      cp = "\x22\x21";
+      break;
+    case 0x338e ... 0x33d5:
+      cp = __cns11643l1_from_ucs4_tab11[ch - 0x338e];
+      break;
+    case 0x4e00 ... 0x9f9c:
+      cp = __cns11643l1_from_ucs4_tab12[ch - 0x4e00];
 
       if (cp[0] == '\0')
 	{
 	  /* Let's try the other planes.  */
 	  needed = 3;
-	  cp = cns11643_from_ucs4_tab[ch - 0x4e00];
+	  cp = __cns11643_from_ucs4_tab[ch - 0x4e00];
 	}
+      break;
+    case 0xfe30 ... 0xfe6b:
+      cp = __cns11643l1_from_ucs4_tab13[ch - 0xfe30];
+      break;
+    case 0xff01 ... 0xff5d:
+      cp = __cns11643l1_from_ucs4_tab14[ch - 0xff01];
+      break;
+    case 0xffe0:
+      cp = "\x22\x66";
+      break;
+    case 0xffe1:
+      cp = "\x22\x67";
+      break;
+    case 0xffe5:
+      cp = "\x22\x64";
+      break;
+    default:
+      cp = "";
     }
-  else if (ch < 0xfe30)
-    cp = "";
-  else if (ch <= 0xfe6b)
-    cp = cns11643l1_from_ucs4_tab13[ch - 0xfe30];
-  else if (ch < 0xff01)
-    cp = "";
-  else if (ch <= 0xff5d)
-    cp = cns11643l1_from_ucs4_tab14[ch - 0xff01];
-  else if (ch == 0xffe0)
-    cp = "\x22\x66";
-  else if (ch == 0xffe1)
-    cp = "\x22\x67";
-  else if (ch == 0xffe5)
-    cp = "\x22\x64";
-  else
-    cp = "";
 
   if (cp[0] == '\0')
     return UNKNOWN_10646_CHAR;
diff --git a/iconvdata/cns11643l1.c b/iconvdata/cns11643l1.c
index 730fb550ab..d106b3d34c 100644
--- a/iconvdata/cns11643l1.c
+++ b/iconvdata/cns11643l1.c
@@ -45,7 +45,7 @@
    printf ("\n");
    ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
 */
-const uint16_t cns11643l1_to_ucs4_tab[] =
+const uint16_t __cns11643l1_to_ucs4_tab[] =
 {
   [0x0000] = 0x3000, [0x0001] = 0xff0c, [0x0002] = 0x3001, [0x0003] = 0x3002,
   [0x0004] = 0xff0e, [0x0005] = 0x30fb, [0x0006] = 0xff1b, [0x0007] = 0xff1a,
@@ -1517,7 +1517,7 @@ const uint16_t cns11643l1_to_ucs4_tab[] =
 
 
 /* Some Latin1 characters, starting at U+00a7.  */
-const char cns11643l1_from_ucs4_tab1[][2] =
+const char __cns11643l1_from_ucs4_tab1[][2] =
 {
   [0x00] = "\x21\x70", [0x09] = "\x22\x78", [0x0a] = "\x22\x34",
   [0x10] = "\x21\x31", [0x30] = "\x22\x32", [0x50] = "\x22\x33"
@@ -1525,7 +1525,7 @@ const char cns11643l1_from_ucs4_tab1[][2] =
 
 
 /* Some phonetic modifiers, starting at U+02c7.  */
-const char cns11643l1_from_ucs4_tab2[][2] =
+const char __cns11643l1_from_ucs4_tab2[][2] =
 {
   [0x00] = "\x25\x6f", [0x02] = "\x25\x6d", [0x03] = "\x25\x6e",
   [0x04] = "\x25\x70", [0x12] = "\x25\x6c"
@@ -1552,7 +1552,7 @@ const char cns11643l1_from_ucs4_tab2[][2] =
    printf ("\n");
    ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
 */
-const char cns11643l1_from_ucs4_tab3[][2] =
+const char __cns11643l1_from_ucs4_tab3[][2] =
 {
   [0x0000] = "\x24\x75", [0x0001] = "\x24\x76", [0x0002] = "\x24\x77",
   [0x0003] = "\x24\x78", [0x0004] = "\x24\x79", [0x0005] = "\x24\x7a",
@@ -1593,7 +1593,7 @@ const char cns11643l1_from_ucs4_tab3[][2] =
    printf ("\n");
    ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
 */
-const char cns11643l1_from_ucs4_tab4[][2] =
+const char __cns11643l1_from_ucs4_tab4[][2] =
 {
   [0x0000] = "\x21\x39", [0x0001] = "\x21\x37", [0x0003] = "\x22\x5d",
   [0x0005] = "\x21\x64", [0x0006] = "\x21\x65", [0x0009] = "\x21\x66",
@@ -1603,7 +1603,7 @@ const char cns11643l1_from_ucs4_tab4[][2] =
 };
 
 
-const char cns11643l1_from_ucs4_tab5[][2] =
+const char __cns11643l1_from_ucs4_tab5[][2] =
 {
   [0x00] = "\x22\x58", [0x01] = "\x22\x55", [0x02] = "\x22\x57",
   [0x03] = "\x22\x56", [0x06] = "\x22\x59", [0x07] = "\x22\x5a",
@@ -1631,7 +1631,7 @@ const char cns11643l1_from_ucs4_tab5[][2] =
    printf ("\n");
    ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
 */
-const char cns11643l1_from_ucs4_tab6[][2] =
+const char __cns11643l1_from_ucs4_tab6[][2] =
 {
   [0x0000] = "\x22\x61", [0x0005] = "\x22\x35", [0x0009] = "\x22\x3c",
   [0x000a] = "\x22\x49", [0x000b] = "\x22\x48", [0x0014] = "\x22\x45",
@@ -1661,7 +1661,7 @@ const char cns11643l1_from_ucs4_tab6[][2] =
    printf ("\n");
    ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
 */
-const char cns11643l1_from_ucs4_tab7[][2] =
+const char __cns11643l1_from_ucs4_tab7[][2] =
 {
   [0x0000] = "\x42\x21", [0x0001] = "\x42\x22", [0x0002] = "\x42\x23",
   [0x0003] = "\x42\x24", [0x0004] = "\x42\x25", [0x0005] = "\x42\x26",
@@ -1697,7 +1697,7 @@ const char cns11643l1_from_ucs4_tab7[][2] =
    printf ("\n");
    ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
 */
-const char cns11643l1_from_ucs4_tab8[][2] =
+const char __cns11643l1_from_ucs4_tab8[][2] =
 {
   [0x0000] = "\x26\x21", [0x0001] = "\x26\x22", [0x0002] = "\x26\x23",
   [0x0003] = "\x26\x24", [0x0004] = "\x26\x25", [0x0005] = "\x26\x26",
@@ -1729,7 +1729,7 @@ const char cns11643l1_from_ucs4_tab8[][2] =
    printf ("\n");
    ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
 */
-const char cns11643l1_from_ucs4_tab9[][2] =
+const char __cns11643l1_from_ucs4_tab9[][2] =
 {
   [0x0000] = "\x23\x39", [0x0002] = "\x23\x3a", [0x000c] = "\x23\x3c",
   [0x0010] = "\x23\x3d", [0x0014] = "\x23\x3e", [0x0018] = "\x23\x3f",
@@ -1774,7 +1774,7 @@ const char cns11643l1_from_ucs4_tab9[][2] =
    printf ("\n");
    ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
 */
-const char cns11643l1_from_ucs4_tab10[][2] =
+const char __cns11643l1_from_ucs4_tab10[][2] =
 {
   [0x0000] = "\x21\x21", [0x0001] = "\x21\x23", [0x0002] = "\x21\x24",
   [0x0003] = "\x21\x71", [0x0008] = "\x21\x52", [0x0009] = "\x21\x53",
@@ -1809,7 +1809,7 @@ const char cns11643l1_from_ucs4_tab10[][2] =
    printf ("\n");
    ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
 */
-const char cns11643l1_from_ucs4_tab11[][2] =
+const char __cns11643l1_from_ucs4_tab11[][2] =
 {
   [0x0000] = "\x22\x75", [0x0001] = "\x22\x76", [0x000e] = "\x22\x70",
   [0x000f] = "\x22\x71", [0x0010] = "\x22\x72", [0x0013] = "\x22\x74",
@@ -1838,7 +1838,7 @@ const char cns11643l1_from_ucs4_tab11[][2] =
    printf ("\n");
    ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
 */
-const char cns11643l1_from_ucs4_tab12[][2] =
+const char __cns11643l1_from_ucs4_tab12[][2] =
 {
   [0x0000] = "\x44\x21", [0x0001] = "\x44\x23", [0x0003] = "\x44\x24",
   [0x0008] = "\x44\x37", [0x0009] = "\x44\x35", [0x000a] = "\x44\x38",
@@ -3667,7 +3667,7 @@ const char cns11643l1_from_ucs4_tab12[][2] =
    printf ("\n");
    ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
 */
-const char cns11643l1_from_ucs4_tab13[][2] =
+const char __cns11643l1_from_ucs4_tab13[][2] =
 {
   [0x0000] = "\x21\x2b", [0x0001] = "\x21\x36", [0x0002] = "\x21\x38",
   [0x0005] = "\x21\x40", [0x0006] = "\x21\x41", [0x0007] = "\x21\x44",
@@ -3709,7 +3709,7 @@ const char cns11643l1_from_ucs4_tab13[][2] =
    printf ("\n");
    ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
 */
-const char cns11643l1_from_ucs4_tab14[][2] =
+const char __cns11643l1_from_ucs4_tab14[][2] =
 {
   [0x0000] = "\x21\x2a", [0x0002] = "\x21\x6c", [0x0003] = "\x22\x63",
   [0x0004] = "\x22\x68", [0x0005] = "\x21\x6d", [0x0007] = "\x21\x3e",
diff --git a/iconvdata/cns11643l1.h b/iconvdata/cns11643l1.h
index 4f9d08513d..aa78c26d6c 100644
--- a/iconvdata/cns11643l1.h
+++ b/iconvdata/cns11643l1.h
@@ -19,9 +19,10 @@
    Boston, MA 02111-1307, USA.  */
 
 #include <stdint.h>
+#include <gconv.h>
 
 /* Table for CNS 11643, plane 1 to UCS4 conversion.  */
-extern const uint16_t cns11643l1_to_ucs4_tab[];
+extern const uint16_t __cns11643l1_to_ucs4_tab[];
 
 
 static inline wchar_t
@@ -47,25 +48,25 @@ cns11643l1_to_ucs4 (const char **s, size_t avail, unsigned char offset)
 
   (*s) += 2;
 
-  return cns11643l1_to_ucs4_tab[idx] ?: ((*s) -= 2, UNKNOWN_10646_CHAR);
+  return __cns11643l1_to_ucs4_tab[idx] ?: ((*s) -= 2, UNKNOWN_10646_CHAR);
 }
 
 
 /* Tables for the UCS4 -> CNS conversion.  */
-extern const char cns11643l1_from_ucs4_tab1[][2];
-extern const char cns11643l1_from_ucs4_tab2[][2];
-extern const char cns11643l1_from_ucs4_tab3[][2];
-extern const char cns11643l1_from_ucs4_tab4[][2];
-extern const char cns11643l1_from_ucs4_tab5[][2];
-extern const char cns11643l1_from_ucs4_tab6[][2];
-extern const char cns11643l1_from_ucs4_tab7[][2];
-extern const char cns11643l1_from_ucs4_tab8[][2];
-extern const char cns11643l1_from_ucs4_tab9[][2];
-extern const char cns11643l1_from_ucs4_tab10[][2];
-extern const char cns11643l1_from_ucs4_tab11[][2];
-extern const char cns11643l1_from_ucs4_tab12[][2];
-extern const char cns11643l1_from_ucs4_tab13[][2];
-extern const char cns11643l1_from_ucs4_tab14[][2];
+extern const char __cns11643l1_from_ucs4_tab1[][2];
+extern const char __cns11643l1_from_ucs4_tab2[][2];
+extern const char __cns11643l1_from_ucs4_tab3[][2];
+extern const char __cns11643l1_from_ucs4_tab4[][2];
+extern const char __cns11643l1_from_ucs4_tab5[][2];
+extern const char __cns11643l1_from_ucs4_tab6[][2];
+extern const char __cns11643l1_from_ucs4_tab7[][2];
+extern const char __cns11643l1_from_ucs4_tab8[][2];
+extern const char __cns11643l1_from_ucs4_tab9[][2];
+extern const char __cns11643l1_from_ucs4_tab10[][2];
+extern const char __cns11643l1_from_ucs4_tab11[][2];
+extern const char __cns11643l1_from_ucs4_tab12[][2];
+extern const char __cns11643l1_from_ucs4_tab13[][2];
+extern const char __cns11643l1_from_ucs4_tab14[][2];
 
 
 static inline size_t
@@ -73,110 +74,95 @@ ucs4_to_cns11643l1 (wchar_t wch, char *s, size_t avail)
 {
   unsigned int ch = (unsigned int) wch;
   char buf[2];
-  const char *cp = NULL;
-
-  if (ch < 0xa7)
-    cp = "";
-  else if (ch < 0xf7)
-    cp = cns11643l1_from_ucs4_tab1[ch - 0xa7];
-  else if (ch < 0x2c7)
-    cp = "";
-  else if (ch <= 0x2d9)
-    cp = cns11643l1_from_ucs4_tab2[ch - 0x2c7];
-  else if (ch < 0x391)
-    cp = "";
-  else if (ch <= 0x3c9)
-    cp = cns11643l1_from_ucs4_tab3[ch - 0x391];
-  else if (ch < 0x2013)
-    cp = "";
-  else if (ch <= 0x203e)
-    cp = cns11643l1_from_ucs4_tab4[ch - 0x2013];
-  else if (ch == 0x2103)
-    cp = "\x22\x6a";
-  else if (ch == 0x2105)
-    cp = "\x22\x22";
-  else if (ch == 0x2109)
-    cp = "\x22\x6b";
-  else if (ch < 0x2160)
-    cp = "";
-  else if (ch <= 0x2169)
+  const char *cp = buf;
+
+  switch (ch)
     {
+    case 0xa7 ... 0xf7:
+      cp = __cns11643l1_from_ucs4_tab1[ch - 0xa7];
+      break;
+    case 0x2c7 ... 0x2d9:
+      cp = __cns11643l1_from_ucs4_tab2[ch - 0x2c7];
+      break;
+    case 0x391 ... 0x3c9:
+      cp = __cns11643l1_from_ucs4_tab3[ch - 0x391];
+    case 0x2013 ... 0x203e:
+      cp = __cns11643l1_from_ucs4_tab4[ch - 0x2013];
+    case 0x2103:
+      cp = "\x22\x6a";
+      break;
+    case 0x2105:
+      cp = "\x22\x22";
+      break;
+    case 0x2109:
+      cp = "\x22\x6b";
+      break;
+    case 0x2160 ... 0x2169:
       buf[0] = '\x24';
       buf[1] = '\x2b' + (ch - 0x2160);
-      cp = buf;
-    }
-  else if (ch < 0x2170)
-    cp = "";
-  else if (ch <= 0x2179)
-    {
+      break;
+    case 0x2170 ... 0x2179:
       buf[0] = '\x26';
       buf[1] = '\x35' + (ch - 0x2170);
-      cp = buf;
-    }
-  else if (ch < 0x2190)
-    cp = "";
-  else if (ch <= 0x2199)
-    cp = cns11643l1_from_ucs4_tab5[ch - 0x2190];
-  else if (ch < 0x2215)
-    cp = "";
-  else if (ch <= 0x2267)
-    cp = cns11643l1_from_ucs4_tab6[ch - 0x2215];
-  else if (ch == 0x22a5)
-    cp = "\x22\x47";
-  else if (ch == 0x22bf)
-    cp = "\x22\x4a";
-  else if (ch < 0x2400)
-    cp = "";
-  else if (ch <= 0x2421)
-    cp = cns11643l1_from_ucs4_tab7[ch - 0x2400];
-  else if (ch < 0x2460)
-    cp = "";
-  else if (ch <= 0x247d)
-    cp = cns11643l1_from_ucs4_tab8[ch - 0x2460];
-  else if (ch < 0x2500)
-    cp = "";
-  else if (ch <= 0x2642)
-    cp = cns11643l1_from_ucs4_tab9[ch - 0x2500];
-  else if (ch < 0x3000)
-    cp = "";
-  else if (ch <= 0x3029)
-    cp = cns11643l1_from_ucs4_tab10[ch - 0x3000];
-  else if (ch == 0x30fb)
-    cp = "\x21\x26";
-  else if (ch < 0x3105)
-    cp = "";
-  else if (ch <= 0x3129)
-    {
+      break;
+    case 0x2190 ...0x2199:
+      cp = __cns11643l1_from_ucs4_tab5[ch - 0x2190];
+      break;
+    case 0x2215 ... 0x2267:
+      cp = __cns11643l1_from_ucs4_tab6[ch - 0x2215];
+      break;
+    case 0x22a5:
+      cp = "\x22\x47";
+      break;
+    case 0x22bf:
+      cp = "\x22\x4a";
+      break;
+    case 0x2400 ... 0x2421:
+      cp = __cns11643l1_from_ucs4_tab7[ch - 0x2400];
+      break;
+    case 0x2460 ... 0x247d:
+      cp = __cns11643l1_from_ucs4_tab8[ch - 0x2460];
+      break;
+    case 0x2500 ... 0x2642:
+      cp = __cns11643l1_from_ucs4_tab9[ch - 0x2500];
+      break;
+    case 0x3000 ... 0x3029:
+      cp = __cns11643l1_from_ucs4_tab10[ch - 0x3000];
+      break;
+    case 0x30fb:
+      cp = "\x21\x26";
+      break;
+    case 0x3105 ... 0x3129:
       buf[0] = '\x25';
       buf[1] = '\x26' + (ch - 0x3105);
-      cp = buf;
+      break;
+    case 0x32a3:
+      cp = "\x22\x21";
+      break;
+    case 0x338e ... 0x33d5:
+      cp = __cns11643l1_from_ucs4_tab11[ch - 0x338e];
+      break;
+    case 0x4e00 ... 0x9f9c:
+      cp = __cns11643l1_from_ucs4_tab12[ch - 0x4e00];
+      break;
+    case 0xfe30 ... 0xfe6b:
+      cp = __cns11643l1_from_ucs4_tab13[ch - 0xfe30];
+      break;
+    case 0xff01 ... 0xff5d:
+      cp = __cns11643l1_from_ucs4_tab14[ch - 0xff01];
+      break;
+    case 0xffe0:
+      cp = "\x22\x66";
+      break;
+    case 0xffe1:
+      cp = "\x22\x67";
+      break;
+    case 0xffe5:
+      cp = "\x22\x64";
+      break;
+    default:
+      buf[0] = '\0';
     }
-  else if (ch == 0x32a3)
-    cp = "\x22\x21";
-  else if (ch < 0x338e)
-    cp = "";
-  else if (ch <= 0x33d5)
-    cp = cns11643l1_from_ucs4_tab11[ch - 0x338e];
-  else if (ch < 0x4e00)
-    cp = "";
-  else if (ch <= 0x9f9c)
-    cp = cns11643l1_from_ucs4_tab12[ch - 0x4e00];
-  else if (ch < 0xfe30)
-    cp = "";
-  else if (ch <= 0xfe6b)
-    cp = cns11643l1_from_ucs4_tab13[ch - 0xfe30];
-  else if (ch < 0xff01)
-    cp = "";
-  else if (ch <= 0xff5d)
-    cp = cns11643l1_from_ucs4_tab14[ch - 0xff01];
-  else if (ch == 0xffe0)
-    cp = "\x22\x66";
-  else if (ch == 0xffe1)
-    cp = "\x22\x67";
-  else if (ch == 0xffe5)
-    cp = "\x22\x64";
-  else
-    cp = "";
 
   if (cp[0] == '\0')
     return UNKNOWN_10646_CHAR;
diff --git a/iconvdata/ebcdic-at-de-a.c b/iconvdata/ebcdic-at-de-a.c
index 7251490ae7..654bdf87fd 100644
--- a/iconvdata/ebcdic-at-de-a.c
+++ b/iconvdata/ebcdic-at-de-a.c
@@ -1,5 +1,5 @@
 /* Conversion from and to EBCDIC-AT-DE-A.
-   Copyright (C) 1997 Free Software Foundation, Inc.
+   Copyright (C) 1997, 1998 Free Software Foundation, Inc.
    This file is part of the GNU C Library.
    Contributed by Ulrich Drepper <drepper@cygnus.com>, 1997.
 
@@ -18,7 +18,12 @@
    write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
    Boston, MA 02111-1307, USA.  */
 
-#include <wchar.h>
+#include <stdint.h>
+
+/* Get the conversion table.  */
 #include <ebcdic-at-de-a.h>
-#define NAME "EBCDIC-AT-DE-A"
+
+#define CHARSET_NAME	"EBCDIC-AT-DE-A"
+#define HAS_HOLES	1	/* Not all 256 character are defined.  */
+
 #include <8bit-generic.c>
diff --git a/iconvdata/ebcdic-at-de.c b/iconvdata/ebcdic-at-de.c
index d9168fcc1d..ab718851d9 100644
--- a/iconvdata/ebcdic-at-de.c
+++ b/iconvdata/ebcdic-at-de.c
@@ -1,5 +1,5 @@
 /* Conversion from and to EBCDIC-AT-DE.
-   Copyright (C) 1997 Free Software Foundation, Inc.
+   Copyright (C) 1997, 1998 Free Software Foundation, Inc.
    This file is part of the GNU C Library.
    Contributed by Ulrich Drepper <drepper@cygnus.com>, 1997.
 
@@ -18,7 +18,12 @@
    write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
    Boston, MA 02111-1307, USA.  */
 
-#include <wchar.h>
+#include <stdint.h>
+
+/* Get the conversion table.  */
 #include <ebcdic-at-de.h>
-#define NAME "EBCDIC-AT-DE"
+
+#define CHARSET_NAME	"EBCDIC-AT-DE"
+#define HAS_HOLES	1	/* Not all 256 character are defined.  */
+
 #include <8bit-generic.c>
diff --git a/iconvdata/ebcdic-ca-fr.c b/iconvdata/ebcdic-ca-fr.c
index a42914e50e..91cf5aa388 100644
--- a/iconvdata/ebcdic-ca-fr.c
+++ b/iconvdata/ebcdic-ca-fr.c
@@ -1,5 +1,5 @@
 /* Conversion from and to EBCDIC-CA-FR.
-   Copyright (C) 1997 Free Software Foundation, Inc.
+   Copyright (C) 1997, 1998 Free Software Foundation, Inc.
    This file is part of the GNU C Library.
    Contributed by Ulrich Drepper <drepper@cygnus.com>, 1997.
 
@@ -18,7 +18,12 @@
    write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
    Boston, MA 02111-1307, USA.  */
 
-#include <wchar.h>
+#include <stdint.h>
+
+/* Get the conversion table.  */
 #include <ebcdic-ca-fr.h>
-#define NAME "EBCDIC-CA-FR"
+
+#define CHARSET_NAME	"EBCDIC-CA-FR"
+#define HAS_HOLES	1	/* Not all 256 character are defined.  */
+
 #include <8bit-generic.c>
diff --git a/iconvdata/euccn.c b/iconvdata/euccn.c
index f683836ff7..90e82cb41e 100644
--- a/iconvdata/euccn.c
+++ b/iconvdata/euccn.c
@@ -18,262 +18,124 @@
    write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
    Boston, MA 02111-1307, USA.  */
 
-#include <gconv.h>
-#include <stdint.h>
-#include <string.h>
-#include <wchar.h>
 #include <gb2312.h>
+#include <stdint.h>
 
-/* Direction of the transformation.  */
-static int to_euccn_object;
-static int from_euccn_object;
-
-
-int
-gconv_init (struct gconv_step *step)
-{
-  /* Determine which direction.  */
-  if (strcasestr (step->from_name, "EUC-CN") != NULL)
-    step->data = &from_euccn_object;
-  else if (strcasestr (step->to_name, "EUC-CN") != NULL)
-    step->data = &to_euccn_object;
-  else
-    return GCONV_NOCONV;
-
-  return GCONV_OK;
-}
-
-
-void
-gconv_end (struct gconv_step *data)
-{
-  /* Nothing to do.  */
-}
-
-
-int
-gconv (struct gconv_step *step, struct gconv_step_data *data,
-       const char *inbuf, size_t *inbufsize, size_t *written, int do_flush)
-{
-  struct gconv_step *next_step = step + 1;
-  struct gconv_step_data *next_data = data + 1;
-  gconv_fct fct = next_step->fct;
-  size_t do_write;
-  int result;
-
-  /* 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 (do_flush)
-    {
-      do_write = 0;
-
-      /* Call the steps down the chain if there are any.  */
-      if (data->is_last)
-	result = GCONV_OK;
-      else
-	{
-	  struct gconv_step *next_step = step + 1;
-	  struct gconv_step_data *next_data = data + 1;
-
-	  result = (*fct) (next_step, next_data, NULL, 0, written, 1);
-
-	  /* Clear output buffer.  */
-	  data->outbufavail = 0;
-	}
-    }
-  else
-    {
-      do_write = 0;
-
-      do
-	{
-	  result = GCONV_OK;
-
-	  if (step->data == &from_euccn_object)
-	    {
-	      size_t inchars = *inbufsize;
-	      size_t outwchars = data->outbufavail;
-	      char *outbuf = data->outbuf;
-	      size_t cnt = 0;
-
-	      while (cnt < inchars
-		     && (outwchars + sizeof (wchar_t) <= data->outbufsize))
-		{
-		  int inchar = (unsigned char) inbuf[cnt];
-		  wchar_t ch;
-
-		  if (inchar <= 0x7f)
-		    ch = (wchar_t) inchar;
-                  else if ((inchar <= 0xa0 || inchar > 0xfe)
-			   && inchar != 0x8e && inchar != 0x8f)
-                      /* This is illegal.  */
-                      ch = L'\0';
-		  else
-		    {
-		      /* Two or more byte character.  First test whether the
-			 next character is also available.  */
-		      const char *endp;
-		      int inchar2;
-
-		      if (cnt + 1 >= inchars)
-			{
-			  /* The second character is not available.  Store
-			     the intermediate result.  */
-			  result = GCONV_INCOMPLETE_INPUT;
-			  break;
-			}
-
-		      inchar2 = (unsigned char) inbuf[++cnt];
-
-		      /* All second bytes of a multibyte character must be
-			 >= 0xa1. */
-		      if (inchar2 < 0xa1)
-			{
-			  /* This is an illegal character.  */
-			  --cnt;
-			  result = GCONV_ILLEGAL_INPUT;
-			  break;
-			}
-
-		      /* This is code set 1: GB 2312-80.  */
-		      endp = &inbuf[cnt - 1];
-
-		      ch = gb2312_to_ucs4 (&endp, 2, 0x80);
-		      if (ch != L'\0')
-			++cnt;
-
-		      if (ch == UNKNOWN_10646_CHAR)
-                         ch = L'\0';
-
-		      if (ch == L'\0')
-			--cnt;
-		    }
-
-		  if (ch == L'\0' && inbuf[cnt] != '\0')
-		    {
-		      /* This is an illegal character.  */
-		      result = GCONV_ILLEGAL_INPUT;
-		      break;
-		    }
-
-		  *((wchar_t *) (outbuf + outwchars)) = ch;
-		  ++do_write;
-		  outwchars += sizeof (wchar_t);
-		  ++cnt;
-		}
-	      *inbufsize -= cnt;
-	      inbuf += cnt;
-	      data->outbufavail = outwchars;
-	    }
-	  else
-	    {
-	      size_t inwchars = *inbufsize;
-	      size_t outchars = data->outbufavail;
-	      char *outbuf = data->outbuf;
-	      size_t cnt = 0;
-	      int extra = 0;
-
-	      while (inwchars >= cnt + sizeof (wchar_t)
-		     && outchars < data->outbufsize)
-		{
-		  wchar_t ch = *((wchar_t *) (inbuf + cnt));
-
-		  if (ch <= L'\x7f')
-		    /* It's plain ASCII.  */
-		    outbuf[outchars] = ch;
-		  else
-		    {
-		      /* Try the JIS character sets.  */
-		      size_t found;
-
-		      found = ucs4_to_gb2312 (ch, &outbuf[outchars],
-					      (data->outbufsize
-					       - outchars));
-		      if (found > 0)
-			{
-			  /* It's a GB 2312 character, adjust it for
-			     EUC-CN.  */
-			  outbuf[outchars++] += 0x80;
-			  outbuf[outchars] += 0x80;
-			}
-		      else if (found == 0)
-			{
-			  /* We ran out of space.  */
-			  extra = 2;
-			  break;
-			}
-		      else
-			/* Illegal character.  */
-			break;
-		    }
-
-		  ++do_write;
-		  ++outchars;
-		  cnt += sizeof (wchar_t);
-		}
-	      *inbufsize -= cnt;
-	      inbuf += cnt;
-	      data->outbufavail = outchars;
-
-	      if (outchars + extra < data->outbufsize)
-		{
-		  /* If there is still room in the output buffer something
-		     is wrong with the input.  */
-		  if (inwchars >= cnt + sizeof (wchar_t))
-		    {
-		      /* An error occurred.  */
-		      result = GCONV_ILLEGAL_INPUT;
-		      break;
-		    }
-		  if (inwchars != cnt)
-		    {
-		      /* There are some unprocessed bytes at the end of the
-			 input buffer.  */
-		      result = GCONV_INCOMPLETE_INPUT;
-		      break;
-		    }
-		}
-	    }
-
-	  if (result != GCONV_OK)
-	    break;
-
-	  if (data->is_last)
-	    {
-	      /* This is the last step.  */
-	      result = (*inbufsize > (step->data == &from_euccn_object
-				      ? 0 : sizeof (wchar_t) - 1)
-			? GCONV_FULL_OUTPUT : GCONV_EMPTY_INPUT);
-	      break;
-	    }
-
-	  /* Status so far.  */
-	  result = GCONV_EMPTY_INPUT;
-
-	  if (data->outbufavail > 0)
-	    {
-	      /* Call the functions below in the chain.  */
-	      size_t newavail = data->outbufavail;
-
-	      result = (*fct) (next_step, next_data, data->outbuf, &newavail,
-			       written, 0);
-
-	      /* Correct the output buffer.  */
-	      if (newavail != data->outbufavail && newavail > 0)
-		{
-		  memmove (data->outbuf,
-			   &data->outbuf[data->outbufavail - newavail],
-			   newavail);
-		  data->outbufavail = newavail;
-		}
-	    }
-	}
-      while (*inbufsize > 0 && result == GCONV_EMPTY_INPUT);
-    }
-
-  if (written != NULL && data->is_last)
-    *written = do_write;
-
-  return result;
-}
+/* Definitions used in the body of the `gconv' function.  */
+#define CHARSET_NAME		"EUC-CN"
+#define FROM_LOOP		from_euc_cn
+#define TO_LOOP			to_euc_cn
+#define DEFINE_INIT		1
+#define DEFINE_FINI		1
+#define MIN_NEEDED_FROM		1
+#define MAX_NEEDED_FROM		2
+#define MIN_NEEDED_TO		4
+
+
+/* First define the conversion function from ISO 8859-1 to UCS4.  */
+#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 \
+  {									      \
+    uint32_t ch = *inptr;						      \
+									      \
+    if (ch <= 0x7f)							      \
+      ++inptr;								      \
+    else								      \
+      if ((ch <= 0xa0 || ch > 0xfe) && ch != 0x8e && ch != 0x8f)	      \
+	{								      \
+	  /* This is illegal.  */					      \
+	  result = GCONV_ILLEGAL_INPUT;					      \
+	  break;							      \
+	}								      \
+      else								      \
+	{								      \
+	  /* Two or more byte character.  First test whether the	      \
+	     next character is also available.  */			      \
+	  const char *endp;						      \
+									      \
+	  if (NEED_LENGTH_TEST && inptr + 1 >= inend)			      \
+	    {								      \
+	      /* The second character is not available.  Store		      \
+		 the intermediate result.  */				      \
+	      result = GCONV_INCOMPLETE_INPUT;				      \
+	      break;							      \
+	    }								      \
+									      \
+	  ch = inptr[1];						      \
+									      \
+	  /* All second bytes of a multibyte character must be >= 0xa1. */    \
+	  if (ch < 0xa1)						      \
+	    {								      \
+	      /* This is an illegal character.  */			      \
+	      result = GCONV_ILLEGAL_INPUT;				      \
+	      break;							      \
+	    }								      \
+									      \
+	  /* This is code set 1: GB 2312-80.  */			      \
+	  endp = inptr;							      \
+									      \
+	  ch = gb2312_to_ucs4 (&endp, 2, 0x80);				      \
+	  if (ch == UNKNOWN_10646_CHAR)					      \
+	    {								      \
+	      /* This is an illegal character.  */			      \
+	      result = GCONV_ILLEGAL_INPUT;				      \
+	      break;							      \
+	    }								      \
+									      \
+	  inptr += 2;							      \
+	}								      \
+									      \
+    *((uint32_t *) outptr)++ = ch;					      \
+  }
+#include <iconv/loop.c>
+
+
+/* Next, define the other direction.  */
+#define MIN_NEEDED_INPUT	MIN_NEEDED_TO
+#define MIN_NEEDED_OUTPUT	MIN_NEEDED_FROM
+#define MAX_NEEDED_OUTPUT	MAX_NEEDED_FROM
+#define LOOPFCT			TO_LOOP
+#define BODY \
+  {									      \
+    uint32_t ch = *((uint32_t *) inptr);				      \
+									      \
+    if (ch <= L'\x7f')							      \
+      /* It's plain ASCII.  */						      \
+      *outptr++ = (unsigned char) ch;					      \
+    else								      \
+      {									      \
+	size_t found;							      \
+									      \
+	found = ucs4_to_gb2312 (ch, outptr,				      \
+				(NEED_LENGTH_TEST			      \
+				 ? outend - outptr : MAX_NEEDED_OUTPUT));     \
+	if (!NEED_LENGTH_TEST || found != 0)				      \
+	  {								      \
+	    if (found == UNKNOWN_10646_CHAR)				      \
+	      {								      \
+		/* Illegal character.  */				      \
+		result = GCONV_ILLEGAL_INPUT;				      \
+		break;							      \
+	      }								      \
+									      \
+	    /* It's a GB 2312 character, adjust it for EUC-CN.  */	      \
+	    *outptr++ += 0x80;						      \
+	    *outptr++ += 0x80;						      \
+	  }								      \
+	else								      \
+	  {								      \
+	    /* We ran out of space.  */					      \
+	    result = GCONV_FULL_OUTPUT;					      \
+	    break;							      \
+	  }								      \
+      }									      \
+    inptr += 4;								      \
+  }
+#include <iconv/loop.c>
+
+
+/* Now define the toplevel functions.  */
+#include <iconv/skeleton.c>
diff --git a/iconvdata/eucjp.c b/iconvdata/eucjp.c
index e6a71cc791..24ebed94ec 100644
--- a/iconvdata/eucjp.c
+++ b/iconvdata/eucjp.c
@@ -18,306 +18,190 @@
    write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
    Boston, MA 02111-1307, USA.  */
 
-#include <gconv.h>
 #include <stdint.h>
-#include <string.h>
-#include <wchar.h>
+#include <gconv.h>
 #include <jis0201.h>
 #include <jis0208.h>
 #include <jis0212.h>
 
-/* Direction of the transformation.  */
-static int to_eucjp_object;
-static int from_eucjp_object;
-
-
-int
-gconv_init (struct gconv_step *step)
-{
-  /* Determine which direction.  */
-  if (strcasestr (step->from_name, "EUC-JP") != NULL)
-    step->data = &from_eucjp_object;
-  else if (strcasestr (step->to_name, "EUC-JP") != NULL)
-    step->data = &to_eucjp_object;
-  else
-    return GCONV_NOCONV;
-
-  return GCONV_OK;
-}
-
-
-void
-gconv_end (struct gconv_step *data)
-{
-  /* Nothing to do.  */
-}
-
-
-int
-gconv (struct gconv_step *step, struct gconv_step_data *data,
-       const char *inbuf, size_t *inbufsize, size_t *written, int do_flush)
-{
-  struct gconv_step *next_step = step + 1;
-  struct gconv_step_data *next_data = data + 1;
-  gconv_fct fct = next_step->fct;
-  size_t do_write;
-  int result;
-
-  /* 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 (do_flush)
-    {
-      do_write = 0;
-
-      /* Call the steps down the chain if there are any.  */
-      if (data->is_last)
-	result = GCONV_OK;
-      else
-	{
-	  struct gconv_step *next_step = step + 1;
-	  struct gconv_step_data *next_data = data + 1;
-
-	  result = (*fct) (next_step, next_data, NULL, 0, written, 1);
-
-	  /* Clear output buffer.  */
-	  data->outbufavail = 0;
-	}
-    }
-  else
-    {
-      do_write = 0;
-
-      do
-	{
-	  result = GCONV_OK;
-
-	  if (step->data == &from_eucjp_object)
-	    {
-	      size_t inchars = *inbufsize;
-	      size_t outwchars = data->outbufavail;
-	      char *outbuf = data->outbuf;
-	      size_t cnt = 0;
-
-	      while (cnt < inchars
-		     && (outwchars + sizeof (wchar_t) <= data->outbufsize))
-		{
-		  int inchar = (unsigned char) inbuf[cnt];
-		  wchar_t ch;
-
-		  if (inchar <= 0x7f)
-		    ch = (wchar_t) inchar;
-                  else if ((inchar <= 0xa0 || inchar > 0xfe)
-			   && inchar != 0x8e && inchar != 0x8f)
-                      /* This is illegal.  */
-                      ch = L'\0';
-		  else
-		    {
-		      /* Two or more byte character.  First test whether the
-			 next character is also available.  */
-		      int inchar2;
-
-		      if (cnt + 1 >= inchars)
-			{
-			  /* The second character is not available.  Store
-			     the intermediate result.  */
-			  result = GCONV_INCOMPLETE_INPUT;
-			  break;
-			}
-
-		      inchar2 = (unsigned char) inbuf[++cnt];
-
-		      /* All second bytes of a multibyte character must be
-			 >= 0xa1. */
-		      if (inchar2 < 0xa1)
-			{
-			  /* This is an illegal character.  */
-			  --cnt;
-			  result = GCONV_ILLEGAL_INPUT;
-			  break;
-			}
-
-		      if (inchar == '\x8e')
-			/* This is code set 2: half-width katakana.  */
-			ch = jisx0201_to_ucs4 (inchar2);
-		      else if (inchar == '\x8f')
-			{
-			  /* This is code set 3: JIS X 0212-1990.  */
-			  const char *endp = &inbuf[cnt];
-
-			  ch = jisx0212_to_ucs4 (&endp, 1 + inchars - cnt,
-						 0x80);
-			  cnt = endp - inbuf;
-			}
-		      else
-			{
-			  /* This is code set 1: JIS X 0208.  */
-			  const char *endp = &inbuf[cnt - 1];
-
-			  ch = jisx0208_to_ucs4 (&endp, 2 + inchars - cnt,
-						 0x80);
-			  if (ch != L'\0')
-			    ++cnt;
-			}
-
-		      if (ch == UNKNOWN_10646_CHAR)
-                         ch = L'\0';
-
-		      if (ch == L'\0')
-			--cnt;
-		    }
-
-		  if (ch == L'\0' && inbuf[cnt] != '\0')
-		    {
-		      /* This is an illegal character.  */
-		      result = GCONV_ILLEGAL_INPUT;
-		      break;
-		    }
-
-		  *((wchar_t *) (outbuf + outwchars)) = ch;
-		  ++do_write;
-		  outwchars += sizeof (wchar_t);
-		  ++cnt;
-		}
-	      *inbufsize -= cnt;
-	      inbuf += cnt;
-	      data->outbufavail = outwchars;
-	    }
-	  else
-	    {
-	      size_t inwchars = *inbufsize;
-	      size_t outchars = data->outbufavail;
-	      char *outbuf = data->outbuf;
-	      size_t cnt = 0;
-	      int extra = 0;
-
-	      while (inwchars >= cnt + sizeof (wchar_t)
-		     && outchars < data->outbufsize)
-		{
-		  wchar_t ch = *((wchar_t *) (inbuf + cnt));
-
-		  if (ch <= L'\x7f')
-		    /* It's plain ASCII.  */
-		    outbuf[outchars] = ch;
-		  else
-		    {
-		      /* Try the JIS character sets.  */
-		      size_t found;
-
-		      found = ucs4_to_jisx0201 (ch, &outbuf[outchars]);
-
-		      if (found == UNKNOWN_10646_CHAR)
-			{
-			  /* No JIS 0201 character.  */
-			  found = ucs4_to_jisx0208 (ch, &outbuf[outchars],
-						    (data->outbufsize
-						     - outchars));
-			  if (found == 0)
-			    {
-			      /* We ran out of space.  */
-			      extra = 2;
-			      break;
-			    }
-			  else if (found != UNKNOWN_10646_CHAR)
-			    {
-			      /* It's a JIS 0208 character, adjust it for
-				 EUC-JP.  */
-			      outbuf[outchars++] += 0x80;
-			      outbuf[outchars] += 0x80;
-			    }
-			  else
-			    {
-			      /* No JIS 0208 character.  */
-			      found = ucs4_to_jisx0212 (ch, &outbuf[outchars],
-							(data->outbufsize
-							 - outchars));
-
-			      if (found == 0)
-				{
-				  /* We ran out of space.  */
-				  extra = 2;
-				  break;
-				}
-			      else if (found != UNKNOWN_10646_CHAR)
-				{
-				  /* It's a JIS 0212 character, adjust it for
-				     EUC-JP.  */
-				  outbuf[outchars++] += 0x80;
-				  outbuf[outchars] += 0x80;
-				}
-			      else
-				/* Illegal character.  */
-				break;
-			    }
-			}
-		    }
-
-		  ++do_write;
-		  ++outchars;
-		  cnt += sizeof (wchar_t);
-		}
-	      *inbufsize -= cnt;
-	      inbuf += cnt;
-	      data->outbufavail = outchars;
-
-	      if (outchars + extra < data->outbufsize)
-		{
-		  /* If there is still room in the output buffer something
-		     is wrong with the input.  */
-		  if (inwchars >= cnt + sizeof (wchar_t))
-		    {
-		      /* An error occurred.  */
-		      result = GCONV_ILLEGAL_INPUT;
-		      break;
-		    }
-		  if (inwchars != cnt)
-		    {
-		      /* There are some unprocessed bytes at the end of the
-			 input buffer.  */
-		      result = GCONV_INCOMPLETE_INPUT;
-		      break;
-		    }
-		}
-	    }
-
-	  if (result != GCONV_OK)
-	    break;
-
-	  if (data->is_last)
-	    {
-	      /* This is the last step.  */
-	      result = (*inbufsize > (step->data == &from_eucjp_object
-				      ? 0 : sizeof (wchar_t) - 1)
-			? GCONV_FULL_OUTPUT : GCONV_EMPTY_INPUT);
-	      break;
-	    }
-
-	  /* Status so far.  */
-	  result = GCONV_EMPTY_INPUT;
-
-	  if (data->outbufavail > 0)
-	    {
-	      /* Call the functions below in the chain.  */
-	      size_t newavail = data->outbufavail;
-
-	      result = (*fct) (next_step, next_data, data->outbuf, &newavail,
-			       written, 0);
-
-	      /* Correct the output buffer.  */
-	      if (newavail != data->outbufavail && newavail > 0)
-		{
-		  memmove (data->outbuf,
-			   &data->outbuf[data->outbufavail - newavail],
-			   newavail);
-		  data->outbufavail = newavail;
-		}
-	    }
-	}
-      while (*inbufsize > 0 && result == GCONV_EMPTY_INPUT);
-    }
-
-  if (written != NULL && data->is_last)
-    *written = do_write;
-
-  return result;
-}
+/* Definitions used in the body of the `gconv' function.  */
+#define CHARSET_NAME		"EUC-JP"
+#define FROM_LOOP		from_euc_jp
+#define TO_LOOP			to_euc_jp
+#define DEFINE_INIT		1
+#define DEFINE_FINI		1
+#define MIN_NEEDED_FROM		1
+#define MAX_NEEDED_FROM		3
+#define MIN_NEEDED_TO		4
+
+
+/* First define the conversion function from EUC-JP to UCS4.  */
+#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 \
+  {									      \
+    uint32_t ch = *inptr;						      \
+									      \
+    if (ch <= 0x7f)							      \
+      ++inptr;								      \
+    else if ((ch <= 0xa0 || ch > 0xfe) && ch != 0x8e && ch != 0x8f)	      \
+      {									      \
+	/* This is illegal.  */						      \
+	result = GCONV_ILLEGAL_INPUT;					      \
+	break;								      \
+      }									      \
+    else								      \
+      {									      \
+	/* Two or more byte character.  First test whether the next	      \
+	   character is also available.  */				      \
+	int ch2;							      \
+									      \
+	if (NEED_LENGTH_TEST && inptr + 1 >= inend)			      \
+	  {								      \
+	    /* The second character is not available.  Store the	      \
+	       intermediate result.  */					      \
+	    result = GCONV_INCOMPLETE_INPUT;				      \
+	    break;							      \
+	  }								      \
+									      \
+	ch2 = inptr[1];							      \
+									      \
+	/* All second bytes of a multibyte character must be >= 0xa1. */      \
+	if (ch2 < 0xa1)							      \
+	  {								      \
+	    /* This is an illegal character.  */			      \
+	    result = GCONV_ILLEGAL_INPUT;				      \
+	    break;							      \
+	  }								      \
+									      \
+	if (ch == 0x8e)							      \
+	  {								      \
+	    /* This is code set 2: half-width katakana.  */		      \
+	    ch = jisx0201_to_ucs4 (ch2);				      \
+	    inptr += 2;							      \
+	  }								      \
+	else								      \
+	  {								      \
+	    const unsigned char *endp;					      \
+									      \
+	    if (ch == 0x8f)						      \
+	      {								      \
+		/* This is code set 3: JIS X 0212-1990.  */		      \
+		endp = inptr + 1;					      \
+									      \
+		ch = jisx0212_to_ucs4 (&endp,				      \
+				       NEED_LENGTH_TEST ? inend - endp : 2,   \
+				       0x80);				      \
+	      }								      \
+	    else							      \
+	      {								      \
+		/* This is code set 1: JIS X 0208.  */			      \
+		endp = inptr;						      \
+									      \
+		ch = jisx0208_to_ucs4 (&endp,				      \
+				       NEED_LENGTH_TEST ? inend - inptr : 2,  \
+				       0x80);				      \
+	      }								      \
+									      \
+	    if (NEED_LENGTH_TEST && ch == 0)				      \
+	      {								      \
+		/* Not enough input available.  */			      \
+		result = GCONV_INCOMPLETE_INPUT;			      \
+		break;							      \
+	      }								      \
+	    if (ch == UNKNOWN_10646_CHAR)				      \
+	      {								      \
+		/* Illegal character.  */				      \
+		result = GCONV_ILLEGAL_INPUT;				      \
+		break;							      \
+	      }								      \
+	    inptr = endp;						      \
+	  }								      \
+      }									      \
+									      \
+    *((uint32_t *) outptr)++ = ch;					      \
+  }
+#include <iconv/loop.c>
+
+
+/* Next, define the other direction.  */
+#define MIN_NEEDED_INPUT	MIN_NEEDED_TO
+#define MIN_NEEDED_OUTPUT	MIN_NEEDED_FROM
+#define MAX_NEEDED_OUTPUT	MAX_NEEDED_FROM
+#define LOOPFCT			TO_LOOP
+#define BODY \
+  {									      \
+    uint32_t ch = *((uint32_t *) inptr);				      \
+									      \
+    if (ch <= 0x7f)							      \
+      /* It's plain ASCII.  */						      \
+      *outptr++ = ch;							      \
+    else								      \
+      {									      \
+	/* Try the JIS character sets.  */				      \
+	size_t found;							      \
+									      \
+	/* See whether we have room for at least two characters.  */	      \
+	if (NEED_LENGTH_TEST && outptr + 1 >= outend)			      \
+	  {								      \
+	    result = GCONV_FULL_OUTPUT;					      \
+	    break;							      \
+	  }								      \
+									      \
+	found = ucs4_to_jisx0201 (ch, outptr + 1);			      \
+	if (found != UNKNOWN_10646_CHAR)				      \
+	  {								      \
+	    /* Yes, it's a JIS 0201 character.  Store the shift byte.  */     \
+	    *outptr = 0x8e;						      \
+	    outptr += 2;						      \
+	  }								      \
+	else								      \
+	  {								      \
+	    /* No JIS 0201 character.  */				      \
+	    found = ucs4_to_jisx0208 (ch, outptr, 2);			      \
+	    /* Please note that we always have enough room for the output. */ \
+	    if (found != UNKNOWN_10646_CHAR)				      \
+	      {								      \
+		/* It's a JIS 0208 character, adjust it for EUC-JP.  */	      \
+		*outptr++ += 0x80;					      \
+		*outptr++ += 0x80;					      \
+	      }								      \
+	    else							      \
+	      {								      \
+		/* No JIS 0208 character.  */				      \
+		found = ucs4_to_jisx0212 (ch, outptr + 1,		      \
+					  (NEED_LENGTH_TEST		      \
+					   ? outend - outptr - 1 : 2));	      \
+		  							      \
+		if (found == 0)						      \
+		  {							      \
+		    /* We ran out of space.  */				      \
+		    result = GCONV_FULL_OUTPUT;				      \
+		    break;						      \
+		  }							      \
+		else if (found != UNKNOWN_10646_CHAR)			      \
+		  {							      \
+		    /* It's a JIS 0212 character, adjust it for EUC-JP.  */   \
+		    *outptr++ = 0x8f;					      \
+		    *outptr++ += 0x80;					      \
+		    *outptr++ += 0x80;					      \
+		  }							      \
+		else							      \
+		  {							      \
+		    /* Illegal character.  */				      \
+		    result = GCONV_ILLEGAL_INPUT;			      \
+		    break;						      \
+		  }							      \
+	      }								      \
+	  }								      \
+      }									      \
+									      \
+    inptr += 4;								      \
+  }
+#include <iconv/loop.c>
+
+
+/* Now define the toplevel functions.  */
+#include <iconv/skeleton.c>
diff --git a/iconvdata/euckr.c b/iconvdata/euckr.c
index 2ad9478729..50e4b40838 100644
--- a/iconvdata/euckr.c
+++ b/iconvdata/euckr.c
@@ -1,7 +1,8 @@
 /* Mapping tables for EUC-KR handling.
    Copyright (C) 1998 Free Software Foundation, Inc.
    This file is part of the GNU C Library.
-   Contributed by Jungshik Shin <jshin@pantheon.yale.edu>, 1998.
+   Contributed by Jungshik Shin <jshin@pantheon.yale.edu>
+   and 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 Library General Public License as
@@ -18,276 +19,142 @@
    write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
    Boston, MA 02111-1307, USA.  */
 
-#include <gconv.h>
 #include <stdint.h>
-#include <stdlib.h>
-#include <string.h>
-#include <wchar.h>
 #include <ksc5601.h>
 
-/* Direction of the transformation.  */
-static int to_euckr_object;
-static int from_euckr_object;
-
 
 static inline void
-euckr_from_ucs4(wchar_t ch, unsigned char *cp)
+euckr_from_ucs4 (uint32_t ch, unsigned char *cp)
 {
   if (ch > 0x7f)
     {
-      uint16_t idx=0;
+      uint16_t idx = 0;
 
       if (ucs4_to_ksc5601 (ch, &idx))
 	idx |= 0x8080;
 
-      *cp = (unsigned char) (idx/256);
-      *(cp+1) = (unsigned char) (idx & 0xff) ;
+      cp[0] = (unsigned char) (idx / 256);
+      cp[1] = (unsigned char) (idx & 0xff);
     }
-  /* think about 0x5c ; '\' */
+  /* XXX Think about 0x5c ; '\'.  */
   else
     {
-      *cp = (unsigned char) (0x7f & ch) ;
-      *(cp+1) = (unsigned char) 0;
+      cp[0] = (unsigned char) ch;
+      cp[1] = '\0';
     }
 }
 
 
-int
-gconv_init (struct gconv_step *step)
-{
-  /* Determine which direction.  */
-  if (strcasestr (step->from_name, "EUC-KR") != NULL)
-    step->data = &from_euckr_object;
-  else if (strcasestr (step->to_name, "EUC-KR") != NULL)
-    step->data = &to_euckr_object;
-  else
-    return GCONV_NOCONV;
-
-  return GCONV_OK;
-}
-
-
-void
-gconv_end (struct gconv_step *data)
-{
-  /* Nothing to do.  */
-}
-
-
-int
-gconv (struct gconv_step *step, struct gconv_step_data *data,
-       const char *inbuf, size_t *inbufsize, size_t *written, int do_flush)
-{
-  struct gconv_step *next_step = step + 1;
-  struct gconv_step_data *next_data = data + 1;
-  gconv_fct fct = next_step->fct;
-  size_t do_write;
-  int result;
-
-  /* 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 (do_flush)
-    {
-      do_write = 0;
-
-      /* Call the steps down the chain if there are any.  */
-      if (data->is_last)
-	result = GCONV_OK;
-      else
-	{
-	  struct gconv_step *next_step = step + 1;
-	  struct gconv_step_data *next_data = data + 1;
-
-	  result = (*fct) (next_step, next_data, NULL, 0, written, 1);
-
-	  /* Clear output buffer.  */
-	  data->outbufavail = 0;
-	}
-    }
-  else
-    {
-      do_write = 0;
-
-      do
-	{
-	  result = GCONV_OK;
-
-	  if (step->data == &from_euckr_object)
-	    {
-	      size_t inchars = *inbufsize;
-	      size_t outwchars = data->outbufavail;
-	      char *outbuf = data->outbuf;
-	      size_t cnt = 0;
-
-	      while (cnt < inchars
-		     && (outwchars + sizeof (wchar_t) <= data->outbufsize))
-		{
-		  int inchar = (unsigned char) inbuf[cnt];
-		  wchar_t ch;
-
-		  /*
-		    half-width Korean Currency WON sign
-
-		    if (inchar == 0x5c)
-		      ch =  0x20a9;
-		    else if (inchar <= 0x7f)
-		      ch = (wchar_t) inchar;
-		  */
-
-		  if (inchar <= 0x7f)
-		    ch = (wchar_t) inchar;
-
-
-/* 0xfe(->0x7e : row 94) and 0xc9(->0x59 : row 41) are user-defined areas */
-
-                  else if ( inchar <= 0xa0 || inchar > 0xfe || inchar == 0xc9)
-                      /* This is illegal.  */
-                      ch = L'\0';
-		  else
-		    {
-		      /* Two-byte character.  First test whether the next
-			 character is also available.  */
-		      int inchar2;
-
-		      if (cnt + 1 >= inchars)
-			{
-			  /* The second character is not available.  Store
-			     the intermediate result.  */
-			  result = GCONV_INCOMPLETE_INPUT;
-			  break;
-			}
-
-		      inchar2 = (unsigned char) inbuf[++cnt];
-
-		      ch = ksc5601_to_ucs4 ((uint16_t) (inchar * 256 + inchar2)
-					    & 0x7f7f);
-		      if (ch == UNKNOWN_10646_CHAR)
-                         ch = L'\0';
-
-		      if (ch == L'\0')
-			--cnt;
-		    }
-
-		  if (ch == L'\0' && inbuf[cnt] != '\0')
-		    {
-		      /* This is an illegal character.  */
-		      result = GCONV_ILLEGAL_INPUT;
-		      break;
-		    }
-
-		  *((wchar_t *) (outbuf + outwchars)) = ch;
-		  ++do_write;
-		  outwchars += sizeof (wchar_t);
-		  ++cnt;
-		}
-	      *inbufsize -= cnt;
-	      inbuf += cnt;
-	      data->outbufavail = outwchars;
-	    }
-	  else
-	    {
-	      size_t inwchars = *inbufsize;
-	      size_t outchars = data->outbufavail;
-	      char *outbuf = data->outbuf;
-	      size_t cnt = 0;
-	      int extra = 0;
-
-	      while (inwchars >= cnt + sizeof (wchar_t)
-		     && outchars < data->outbufsize)
-		{
-		  wchar_t ch = *((wchar_t *) (inbuf + cnt));
-		  unsigned char cp[2];
-
-/* decomposing Hangul syllables not available in KS C 5601 into Jamos
-   should be considered either here or in euckr_from_ucs4() */
-
-                  euckr_from_ucs4(ch,cp) ;
-
-		  if (cp[0] == '\0' && ch != 0)
-		    /* Illegal character.  */
-		    break;
-
-		  outbuf[outchars] = cp[0];
-		  /* Now test for a possible second byte and write this
-		     if possible.  */
-		  if (cp[1] != '\0')
-		    {
-		      if (outchars + 1 >= data->outbufsize)
-			{
-			  /* The result does not fit into the buffer.  */
-			  extra = 1;
-			  break;
-			}
-		      outbuf[++outchars] = cp[1];
-		    }
-
-		  ++do_write;
-		  ++outchars;
-		  cnt += sizeof (wchar_t);
-		}
-	      *inbufsize -= cnt;
-	      inbuf += cnt;
-	      data->outbufavail = outchars;
-
-	      if (outchars + extra < data->outbufsize)
-		{
-		  /* If there is still room in the output buffer something
-		     is wrong with the input.  */
-		  if (inwchars >= cnt + sizeof (wchar_t))
-		    {
-		      /* An error occurred.  */
-		      result = GCONV_ILLEGAL_INPUT;
-		      break;
-		    }
-		  if (inwchars != cnt)
-		    {
-		      /* There are some unprocessed bytes at the end of the
-			 input buffer.  */
-		      result = GCONV_INCOMPLETE_INPUT;
-		      break;
-		    }
-		}
-	    }
-
-	  if (result != GCONV_OK)
-	    break;
-
-	  if (data->is_last)
-	    {
-	      /* This is the last step.  */
-	      result = (*inbufsize > (step->data == &from_euckr_object
-				      ? 0 : sizeof (wchar_t) - 1)
-			? GCONV_FULL_OUTPUT : GCONV_EMPTY_INPUT);
-	      break;
-	    }
-
-	  /* Status so far.  */
-	  result = GCONV_EMPTY_INPUT;
-
-	  if (data->outbufavail > 0)
-	    {
-	      /* Call the functions below in the chain.  */
-	      size_t newavail = data->outbufavail;
-
-	      result = (*fct) (next_step, next_data, data->outbuf, &newavail,
-			       written, 0);
-
-	      /* Correct the output buffer.  */
-	      if (newavail != data->outbufavail && newavail > 0)
-		{
-		  memmove (data->outbuf,
-			   &data->outbuf[data->outbufavail - newavail],
-			   newavail);
-		  data->outbufavail = newavail;
-		}
-	    }
-	}
-      while (*inbufsize > 0 && result == GCONV_EMPTY_INPUT);
-    }
-
-  if (written != NULL && data->is_last)
-    *written = do_write;
-
-  return result;
-}
+/* Definitions used in the body of the `gconv' function.  */
+#define CHARSET_NAME		"EUC-KR"
+#define FROM_LOOP		from_euc_kr
+#define TO_LOOP			to_euc_kr
+#define DEFINE_INIT		1
+#define DEFINE_FINI		1
+#define MIN_NEEDED_FROM		1
+#define MAX_NEEDED_FROM		2
+#define MIN_NEEDED_TO		4
+
+
+/* First define the conversion function from EUC-KR to UCS4.  */
+#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 \
+  {									      \
+    uint32_t ch = *inptr;						      \
+									      \
+    /* Half-width Korean Currency WON sign				      \
+									      \
+       if (inchar == 0x5c)						      \
+	 ch =  0x20a9;							      \
+       else if (inchar <= 0x7f)						      \
+	 ch = (wchar_t) inchar;						      \
+    */									      \
+									      \
+    if (ch <= 0x7f)							      \
+      /* Plain ASCII.  */						      \
+      ++inptr;								      \
+    /* 0xfe(->0x7e : row 94) and 0xc9(->0x59 : row 41) are		      \
+       user-defined areas.  */						      \
+    else if (ch <= 0xa0 || ch > 0xfe || ch == 0xc9)			      \
+      {									      \
+	/* This is illegal.  */						      \
+	result = GCONV_ILLEGAL_INPUT;					      \
+	break;								      \
+      }									      \
+    else								      \
+      {									      \
+	/* Two-byte character.  First test whether the next character	      \
+	   is also available.  */					      \
+	int ch2;							      \
+									      \
+	if (NEED_LENGTH_TEST && inptr + 1 >= inend)			      \
+	  {								      \
+	    /* The second character is not available.  */		      \
+	    result = GCONV_INCOMPLETE_INPUT;				      \
+	    break;							      \
+	  }								      \
+									      \
+	ch2 = inptr[1];							      \
+									      \
+	if (ch2 < 0xa1 || ch2 >= 0xfe					      \
+	    || ((ch = ksc5601_to_ucs4 ((uint16_t) (ch * 256 + ch2) & 0x7f7f)) \
+		== UNKNOWN_10646_CHAR))					      \
+	  {								      \
+	    /* This is an illegal character.  */			      \
+	    result = GCONV_ILLEGAL_INPUT;				      \
+	    break;							      \
+	  }								      \
+									      \
+	inptr += 2;							      \
+      }									      \
+									      \
+    *((uint32_t *) outptr)++ = ch;					      \
+  }
+#include <iconv/loop.c>
+
+
+/* Next, define the other direction.  */
+#define MIN_NEEDED_INPUT	MIN_NEEDED_TO
+#define MIN_NEEDED_OUTPUT	MIN_NEEDED_FROM
+#define MAX_NEEDED_OUTPUT	MAX_NEEDED_FROM
+#define LOOPFCT			TO_LOOP
+#define BODY \
+  {									      \
+    uint32_t ch = *((uint32_t *) inptr);				      \
+    unsigned char cp[2];						      \
+									      \
+    /* Decomposing Hangul syllables not available in KS C 5601 into	      \
+       Jamos should be considered either here or in euckr_from_ucs4() */      \
+    euckr_from_ucs4 (ch, cp) ;						      \
+									      \
+    if (cp[0] == '\0' && ch != 0)					      \
+      {									      \
+	/* Illegal character.  */					      \
+	result = GCONV_ILLEGAL_INPUT;					      \
+	break;								      \
+      }									      \
+									      \
+    *outptr++ = cp[0];							      \
+    /* Now test for a possible second byte and write this if possible.  */    \
+    if (cp[1] != '\0')							      \
+      {									      \
+	if (NEED_LENGTH_TEST && outptr >= outend)			      \
+	  {								      \
+	    /* The result does not fit into the buffer.  */		      \
+	    --outptr;							      \
+	    result = GCONV_FULL_OUTPUT;					      \
+	    break;							      \
+	  }								      \
+	*outptr++ = cp[1];						      \
+      }									      \
+									      \
+    inptr += 4;								      \
+  }
+#include <iconv/loop.c>
+
+
+/* Now define the toplevel functions.  */
+#include <iconv/skeleton.c>
diff --git a/iconvdata/euctw.c b/iconvdata/euctw.c
index fd422c1fb0..406dd67f29 100644
--- a/iconvdata/euctw.c
+++ b/iconvdata/euctw.c
@@ -18,302 +18,171 @@
    write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
    Boston, MA 02111-1307, USA.  */
 
-#include <gconv.h>
 #include <stdint.h>
-#include <string.h>
-#include <wchar.h>
 #include <cns11643l1.h>
 #include <cns11643.h>
 
-/* Direction of the transformation.  */
-static int to_euctw_object;
-static int from_euctw_object;
-
-
-int
-gconv_init (struct gconv_step *step)
-{
-  /* Determine which direction.  */
-  if (strcasestr (step->from_name, "EUC-TW") != NULL)
-    step->data = &from_euctw_object;
-  else if (strcasestr (step->to_name, "EUC-TW") != NULL)
-    step->data = &to_euctw_object;
-  else
-    return GCONV_NOCONV;
-
-  return GCONV_OK;
-}
-
-
-void
-gconv_end (struct gconv_step *data)
-{
-  /* Nothing to do.  */
-}
-
-
-int
-gconv (struct gconv_step *step, struct gconv_step_data *data,
-       const char *inbuf, size_t *inbufsize, size_t *written, int do_flush)
-{
-  struct gconv_step *next_step = step + 1;
-  struct gconv_step_data *next_data = data + 1;
-  gconv_fct fct = next_step->fct;
-  size_t do_write;
-  int result;
-
-  /* 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 (do_flush)
-    {
-      do_write = 0;
-
-      /* Call the steps down the chain if there are any.  */
-      if (data->is_last)
-	result = GCONV_OK;
-      else
-	{
-	  struct gconv_step *next_step = step + 1;
-	  struct gconv_step_data *next_data = data + 1;
-
-	  result = (*fct) (next_step, next_data, NULL, 0, written, 1);
-
-	  /* Clear output buffer.  */
-	  data->outbufavail = 0;
-	}
-    }
-  else
-    {
-      do_write = 0;
-
-      do
-	{
-	  result = GCONV_OK;
-
-	  if (step->data == &from_euctw_object)
-	    {
-	      size_t inchars = *inbufsize;
-	      size_t outwchars = data->outbufavail;
-	      char *outbuf = data->outbuf;
-	      size_t cnt = 0;
-
-	      while (cnt < inchars
-		     && (outwchars + sizeof (wchar_t) <= data->outbufsize))
-		{
-		  int inchar = (unsigned char) inbuf[cnt];
-		  wchar_t ch;
-
-		  if (inchar <= 0x7f)
-		    ch = (wchar_t) inchar;
-                  else if ((inchar <= 0xa0 || inchar > 0xfe)
-			   && inchar != 0x8e)
-                      /* This is illegal.  */
-                      ch = L'\0';
-		  else
-		    {
-		      /* Two or more byte character.  First test whether the
-			 next character is also available.  */
-		      int inchar2;
-
-		      if (cnt + 1 + (inchar == 0x8e ? 2 : 0) >= inchars)
-			{
-			  /* The second character is not available.  Store
-			     the intermediate result.  */
-			  result = GCONV_INCOMPLETE_INPUT;
-			  break;
-			}
-
-		      inchar2 = (unsigned char) inbuf[++cnt];
-
-		      /* All second bytes of a multibyte character must be
-			 >= 0xa1. */
-		      if (inchar2 < 0xa1 && inchar2 == 0xff)
-			{
-			  /* This is an illegal character.  */
-			  --cnt;
-			  result = GCONV_ILLEGAL_INPUT;
-			  break;
-			}
-
-		      if (inchar == '\x8e')
-			{
-			  /* This is code set 2: CNS 11643, planes 1 to 16.  */
-			  const char *endp = &inbuf[cnt];
-
-			  ch = cns11643_to_ucs4 (&endp, 2 + inchars - cnt,
-						 0x80);
-
-			  if (ch == UNKNOWN_10646_CHAR)
-			    ch = L'\0';
-			  if (ch != L'\0')
-			    cnt += 2;
-			}
-		      else
-			{
-			  /* This is code set 1: CNS 11643, plane 1.  */
-			  const char *endp = &inbuf[cnt - 1];
-
-			  ch = cns11643l1_to_ucs4 (&endp, 2 + inchars - cnt,
-						   0x80);
-
-			  if (ch == UNKNOWN_10646_CHAR)
-			    ch = L'\0';
-			  if (ch != L'\0')
-			    ++cnt;
-			}
-
-		      if (ch == L'\0')
-			--cnt;
-		    }
-
-		  if (ch == L'\0' && inbuf[cnt] != '\0')
-		    {
-		      /* This is an illegal character.  */
-		      result = GCONV_ILLEGAL_INPUT;
-		      break;
-		    }
-
-		  *((wchar_t *) (outbuf + outwchars)) = ch;
-		  ++do_write;
-		  outwchars += sizeof (wchar_t);
-		  ++cnt;
-		}
-	      *inbufsize -= cnt;
-	      inbuf += cnt;
-	      data->outbufavail = outwchars;
-	    }
-	  else
-	    {
-	      size_t inwchars = *inbufsize;
-	      size_t outchars = data->outbufavail;
-	      char *outbuf = data->outbuf;
-	      size_t cnt = 0;
-	      int extra = 0;
-
-	      while (inwchars >= cnt + sizeof (wchar_t)
-		     && outchars < data->outbufsize)
-		{
-		  wchar_t ch = *((wchar_t *) (inbuf + cnt));
-
-		  if (ch <= L'\x7f')
-		    /* It's plain ASCII.  */
-		    outbuf[outchars] = ch;
-		  else
-		    {
-		      /* Try the JIS character sets.  */
-		      size_t found;
-
-		      found = ucs4_to_cns11643l1 (ch, &outbuf[outchars],
-						  (data->outbufsize
-						     - outchars));
-		      if (found == 0)
-			{
-			  /* We ran out of space.  */
-			  extra = 2;
-			  break;
-			}
-		      else if (found != UNKNOWN_10646_CHAR)
-			{
-			  /* It's a CNS 11643, plane 1 character, adjust it
-			     for EUC-TW.  */
-			  outbuf[outchars++] += 0x80;
-			  outbuf[outchars] += 0x80;
-			}
-		      else
-			{
-			  /* No CNS 11643, plane 1 character.  */
-			  outbuf[outchars] = '\x8e';
-
-			  found = ucs4_to_cns11643 (ch, &outbuf[outchars + 1],
-						    (data->outbufsize
-						     - outchars - 1));
-			  if (found > 0)
-			    {
-			      /* It's a CNS 11643 character, adjust it for
-				 EUC-TW.  */
-			      outbuf[++outchars] += 0xa0;
-			      outbuf[++outchars] += 0x80;
-			      outbuf[outchars] += 0x80;
-			    }
-			  else if (found == 0)
-			    {
-			      /* We ran out of space.  */
-			      extra = 4;
-			      break;
-			    }
-			  else
-			    /* Illegal character.  */
-			    break;
-			}
-		    }
-
-		  ++do_write;
-		  ++outchars;
-		  cnt += sizeof (wchar_t);
-		}
-	      *inbufsize -= cnt;
-	      inbuf += cnt;
-	      data->outbufavail = outchars;
-
-	      if (outchars + extra < data->outbufsize)
-		{
-		  /* If there is still room in the output buffer something
-		     is wrong with the input.  */
-		  if (inwchars >= cnt + sizeof (wchar_t))
-		    {
-		      /* An error occurred.  */
-		      result = GCONV_ILLEGAL_INPUT;
-		      break;
-		    }
-		  if (inwchars != cnt)
-		    {
-		      /* There are some unprocessed bytes at the end of the
-			 input buffer.  */
-		      result = GCONV_INCOMPLETE_INPUT;
-		      break;
-		    }
-		}
-	    }
-
-	  if (result != GCONV_OK)
-	    break;
-
-	  if (data->is_last)
-	    {
-	      /* This is the last step.  */
-	      result = (*inbufsize > (step->data == &from_euctw_object
-				      ? 0 : sizeof (wchar_t) - 1)
-			? GCONV_FULL_OUTPUT : GCONV_EMPTY_INPUT);
-	      break;
-	    }
-
-	  /* Status so far.  */
-	  result = GCONV_EMPTY_INPUT;
-
-	  if (data->outbufavail > 0)
-	    {
-	      /* Call the functions below in the chain.  */
-	      size_t newavail = data->outbufavail;
-
-	      result = (*fct) (next_step, next_data, data->outbuf, &newavail,
-			       written, 0);
-
-	      /* Correct the output buffer.  */
-	      if (newavail != data->outbufavail && newavail > 0)
-		{
-		  memmove (data->outbuf,
-			   &data->outbuf[data->outbufavail - newavail],
-			   newavail);
-		  data->outbufavail = newavail;
-		}
-	    }
-	}
-      while (*inbufsize > 0 && result == GCONV_EMPTY_INPUT);
-    }
-
-  if (written != NULL && data->is_last)
-    *written = do_write;
-
-  return result;
-}
+/* Definitions used in the body of the `gconv' function.  */
+#define CHARSET_NAME		"EUC-TW"
+#define FROM_LOOP		from_euc_tw
+#define TO_LOOP			to_euc_tw
+#define DEFINE_INIT		1
+#define DEFINE_FINI		1
+#define MIN_NEEDED_FROM		1
+#define MAX_NEEDED_FROM		4
+#define MIN_NEEDED_TO		4
+
+
+/* First define the conversion function from EUC-TW to UCS4.  */
+#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 \
+  {									      \
+    uint32_t ch = *inptr;						      \
+    									      \
+    if (ch <= 0x7f)							      \
+      /* Plain ASCII.  */						      \
+      ++inptr;								      \
+    else if ((ch <= 0xa0 || ch > 0xfe) && ch != 0x8e)			      \
+      {									      \
+	/* This is illegal.  */						      \
+	result = GCONV_ILLEGAL_INPUT;					      \
+	break;								      \
+      }									      \
+    else								      \
+      {									      \
+	/* Two or more byte character.  First test whether the next	      \
+	   character is also available.  */				      \
+	uint32_t ch2;							      \
+									      \
+	if (NEED_LENGTH_TEST && inptr + (ch == 0x8e ? 3 : 1) >= inend)	      \
+	  {								      \
+	    /* The second character is not available.  Store the	      \
+	       intermediate result.  */					      \
+	    result = GCONV_INCOMPLETE_INPUT;				      \
+	    break;							      \
+	  }								      \
+									      \
+	ch2 = *inptr;							      \
+									      \
+	/* All second bytes of a multibyte character must be >= 0xa1. */      \
+	if (ch2 < 0xa1 || ch2 == 0xff)					      \
+	  {								      \
+	    /* This is an illegal character.  */			      \
+	    result = GCONV_ILLEGAL_INPUT;				      \
+	    break;							      \
+	  }								      \
+									      \
+	if (ch == 0x8e)							      \
+	  {								      \
+	    /* This is code set 2: CNS 11643, planes 1 to 16.  */	      \
+	    const char *endp = inptr + 1;				      \
+									      \
+	    ch = cns11643_to_ucs4 (&endp,				      \
+				   NEED_LENGTH_TEST ? inend - inptr - 1 : 3,  \
+				   0x80);				      \
+	    /* Please note that we need not test for the missing input	      \
+	       characters here anymore.  */				      \
+	    if (ch == UNKNOWN_10646_CHAR)				      \
+	      {								      \
+		/* Illegal input.  */					      \
+		result = GCONV_ILLEGAL_INPUT;				      \
+		break;							      \
+	      }								      \
+									      \
+	    inptr += 4;							      \
+	  }								      \
+	else								      \
+	  {								      \
+	    /* This is code set 1: CNS 11643, plane 1.  */		      \
+	    const char *endp = inptr;					      \
+									      \
+	    ch = cns11643l1_to_ucs4 (&endp,				      \
+				     NEED_LENGTH_TEST ? inend - inptr : 2,    \
+				     0x80);				      \
+	    /* Please note that we need not test for the missing input	      \
+	       characters here anymore.  */				      \
+	    if (ch == UNKNOWN_10646_CHAR)				      \
+	      {								      \
+		/* Illegal input.  */					      \
+		result = GCONV_ILLEGAL_INPUT;				      \
+		break;							      \
+	      }								      \
+									      \
+	    inptr += 2;							      \
+	  }								      \
+      }									      \
+									      \
+    *((uint32_t *) outptr)++ = ch;					      \
+  }
+#include <iconv/loop.c>
+
+
+/* Next, define the other direction.  */
+#define MIN_NEEDED_INPUT	MIN_NEEDED_TO
+#define MIN_NEEDED_OUTPUT	MIN_NEEDED_FROM
+#define MAX_NEEDED_OUTPUT	MAX_NEEDED_FROM
+#define LOOPFCT			TO_LOOP
+#define BODY \
+  {									      \
+    uint32_t ch = *((uint32_t *) inptr);				      \
+									      \
+    if (ch <= 0x7f)							      \
+      /* It's plain ASCII.  */						      \
+      *outptr++ = ch;							      \
+    else								      \
+      {									      \
+	/* Try the JIS character sets.  */				      \
+	size_t found;							      \
+									      \
+	found = ucs4_to_cns11643l1 (ch, outptr,				      \
+				    NEED_LENGTH_TEST ? outend - outptr : 2);  \
+	if (NEED_LENGTH_TEST && found == 0)				      \
+	  {								      \
+	    /* We ran out of space.  */					      \
+	    result = GCONV_INCOMPLETE_INPUT;				      \
+	    break;							      \
+	  }								      \
+	if (found != UNKNOWN_10646_CHAR)				      \
+	  {								      \
+	    /* It's a CNS 11643, plane 1 character, adjust it for EUC-TW.  */ \
+	    *outptr++ += 0x80;						      \
+	    *outptr++ += 0x80;						      \
+	  }								      \
+	else								      \
+	  {								      \
+	    /* No CNS 11643, plane 1 character.  */			      \
+									      \
+	    found = ucs4_to_cns11643 (ch, outptr + 1,			      \
+				      (NEED_LENGTH_TEST			      \
+				       ? outend - outptr - 1 : 3));	      \
+	    if (NEED_LENGTH_TEST && found == 0)				      \
+	      {								      \
+		/* We ran out of space.  */				      \
+		result = GCONV_INCOMPLETE_INPUT;			      \
+		break;							      \
+	      }								      \
+	    if (found == UNKNOWN_10646_CHAR)				      \
+	      {								      \
+		/* No legal input.  */					      \
+		result = GCONV_ILLEGAL_INPUT;				      \
+		break;							      \
+	      }								      \
+									      \
+	    /* It's a CNS 11643 character, adjust it for EUC-TW.  */	      \
+	    *outptr++ = '\x8e';						      \
+	    *outptr++ += 0xa0;						      \
+	    *outptr++ += 0x80;						      \
+	    *outptr++ += 0x80;						      \
+	  }								      \
+      }									      \
+									      \
+    inptr += 4;								      \
+  }
+#include <iconv/loop.c>
+
+
+/* Now define the toplevel functions.  */
+#include <iconv/skeleton.c>
diff --git a/iconvdata/gb2312.c b/iconvdata/gb2312.c
index 89d716196f..9cde1c8fe7 100644
--- a/iconvdata/gb2312.c
+++ b/iconvdata/gb2312.c
@@ -40,7 +40,7 @@
    printf ("\n");
    ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  */
-const uint16_t gb2312_to_ucs[] =
+const uint16_t __gb2312_to_ucs[] =
 {
   [0x0000] = 0x3000, [0x0001] = 0x3001, [0x0002] = 0x3002, [0x0003] = 0x30fb,
   [0x0004] = 0x02c9, [0x0005] = 0x02c7, [0x0006] = 0x00a8, [0x0007] = 0x3003,
@@ -1907,7 +1907,7 @@ const uint16_t gb2312_to_ucs[] =
 };
 
 
-const char gb2312_from_ucs4_tab1[][2] =
+const char __gb2312_from_ucs4_tab1[][2] =
 {
   [0x00] = "\x21\x68", [0x03] = "\x21\x6c", [0x04] = "\x21\x27",
   [0x0c] = "\x21\x63", [0x0d] = "\x21\x40", [0x33] = "\x21\x41",
@@ -1939,7 +1939,7 @@ const char gb2312_from_ucs4_tab1[][2] =
    printf ("\n");
    ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
 */
-const char gb2312_from_ucs4_tab2[][2] =
+const char __gb2312_from_ucs4_tab2[][2] =
 {
   [0x0000] = "\x26\x21", [0x0001] = "\x26\x22", [0x0002] = "\x26\x23",
   [0x0003] = "\x26\x24", [0x0004] = "\x26\x25", [0x0005] = "\x26\x26",
@@ -1980,7 +1980,7 @@ const char gb2312_from_ucs4_tab2[][2] =
    printf ("\n");
    ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
 */
-const char gb2312_from_ucs4_tab3[][2] =
+const char __gb2312_from_ucs4_tab3[][2] =
 {
   [0x0000] = "\x27\x27", [0x000f] = "\x27\x21", [0x0010] = "\x27\x22",
   [0x0011] = "\x27\x23", [0x0012] = "\x27\x24", [0x0013] = "\x27\x25",
@@ -2027,7 +2027,7 @@ const char gb2312_from_ucs4_tab3[][2] =
    printf ("\n");
    ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
 */
-const char gb2312_from_ucs4_tab4[][2] =
+const char __gb2312_from_ucs4_tab4[][2] =
 {
   [0x0000] = "\x21\x2a", [0x0003] = "\x21\x2e", [0x0004] = "\x21\x2f",
   [0x0007] = "\x21\x30", [0x0008] = "\x21\x31", [0x0011] = "\x21\x2d",
@@ -2059,7 +2059,7 @@ const char gb2312_from_ucs4_tab4[][2] =
    But we have a problem here since U+2225 maps to either 0x212C or
    0x214E.  We simply choose the first solution here.
 */
-const char gb2312_from_ucs4_tab5[][2] =
+const char __gb2312_from_ucs4_tab5[][2] =
 {
   [0x0000] = "\x21\x66", [0x0013] = "\x21\x6d", [0x005d] = "\x22\x71",
   [0x005e] = "\x22\x72", [0x005f] = "\x22\x73", [0x0060] = "\x22\x74",
@@ -2100,7 +2100,7 @@ const char gb2312_from_ucs4_tab5[][2] =
    printf ("\n");
    ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
 */
-const char gb2312_from_ucs4_tab6[][2] =
+const char __gb2312_from_ucs4_tab6[][2] =
 {
   [0x0000] = "\x22\x59", [0x0001] = "\x22\x5a", [0x0002] = "\x22\x5b",
   [0x0003] = "\x22\x5c", [0x0004] = "\x22\x5d", [0x0005] = "\x22\x5e",
@@ -2142,7 +2142,7 @@ const char gb2312_from_ucs4_tab6[][2] =
    printf ("\n");
    ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
 */
-const char gb2312_from_ucs4_tab7[][2] =
+const char __gb2312_from_ucs4_tab7[][2] =
 {
   [0x0000] = "\x21\x21", [0x0001] = "\x21\x22", [0x0002] = "\x21\x23",
   [0x0003] = "\x21\x28", [0x0005] = "\x21\x29", [0x0008] = "\x21\x34",
@@ -2243,7 +2243,7 @@ const char gb2312_from_ucs4_tab7[][2] =
    printf ("\n");
    ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
 */
-const char gb2312_from_ucs4_tab8[][2] =
+const char __gb2312_from_ucs4_tab8[][2] =
 {
   [0x0000] = "\x52\x3b", [0x0001] = "\x36\x21", [0x0003] = "\x46\x5f",
   [0x0007] = "\x4d\x72", [0x0008] = "\x55\x49", [0x0009] = "\x48\x7d",
@@ -4523,7 +4523,7 @@ const char gb2312_from_ucs4_tab8[][2] =
    printf ("\n");
    ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
 */
-const char gb2312_from_ucs4_tab9[][2] =
+const char __gb2312_from_ucs4_tab9[][2] =
 {
   [0x0000] = "\x23\x21", [0x0001] = "\x23\x22", [0x0002] = "\x23\x23",
   [0x0003] = "\x21\x67", [0x0004] = "\x23\x25", [0x0005] = "\x23\x26",
diff --git a/iconvdata/gb2312.h b/iconvdata/gb2312.h
index 922fcc8f77..df87950436 100644
--- a/iconvdata/gb2312.h
+++ b/iconvdata/gb2312.h
@@ -25,7 +25,7 @@
 #include <stdint.h>
 
 /* Conversion table.  */
-extern const uint16_t gb2312_to_ucs[];
+extern const uint16_t __gb2312_to_ucs[];
 
 
 static inline wchar_t
@@ -51,127 +51,166 @@ gb2312_to_ucs4 (const char **s, size_t avail, unsigned char offset)
 
   (*s) += 2;
 
-  return gb2312_to_ucs[idx] ?: ((*s) -= 2, UNKNOWN_10646_CHAR);
+  return __gb2312_to_ucs[idx] ?: ((*s) -= 2, UNKNOWN_10646_CHAR);
 }
 
 
-extern const char gb2312_from_ucs4_tab1[][2];
-extern const char gb2312_from_ucs4_tab2[][2];
-extern const char gb2312_from_ucs4_tab3[][2];
-extern const char gb2312_from_ucs4_tab4[][2];
-extern const char gb2312_from_ucs4_tab5[][2];
-extern const char gb2312_from_ucs4_tab6[][2];
-extern const char gb2312_from_ucs4_tab7[][2];
-extern const char gb2312_from_ucs4_tab8[][2];
-extern const char gb2312_from_ucs4_tab9[][2];
+extern const char __gb2312_from_ucs4_tab1[][2];
+extern const char __gb2312_from_ucs4_tab2[][2];
+extern const char __gb2312_from_ucs4_tab3[][2];
+extern const char __gb2312_from_ucs4_tab4[][2];
+extern const char __gb2312_from_ucs4_tab5[][2];
+extern const char __gb2312_from_ucs4_tab6[][2];
+extern const char __gb2312_from_ucs4_tab7[][2];
+extern const char __gb2312_from_ucs4_tab8[][2];
+extern const char __gb2312_from_ucs4_tab9[][2];
 
 static inline size_t
 ucs4_to_gb2312 (wchar_t wch, char *s, size_t avail)
 {
   unsigned int ch = (unsigned int) wch;
   char buf[2];
-  const char *cp = NULL;
+  const char *cp = buf;
 
-  if (ch < 0xa4)
-    return UNKNOWN_10646_CHAR;
-  else if (ch < 0x101)
-    cp = gb2312_from_ucs4_tab1[ch - 0xa4];
-  else if (ch == 0x113)
-    cp = "\x28\x25";
-  else if (ch == 0x11b)
-    cp = "\x28\x27";
-  else if (ch == 0x12b)
-    cp = "\x28\x29";
-  else if (ch == 0x14d)
-    cp = "\x28\x2d";
-  else if (ch == 0x16b)
-    cp = "\x28\x31";
-  else if (ch == 0x1ce)
-    cp = "\x28\x23";
-  else if (ch == 0x1d0)
-    cp = "\x28\x2b";
-  else if (ch == 0x1d2)
-    cp = "\x28\x2f";
-  else if (ch == 0x1d4)
-    cp = "\x28\x33";
-  else if (ch == 0x1d6)
-    cp = "\x28\x35";
-  else if (ch == 0x1d8)
-    cp = "\x28\x36";
-  else if (ch == 0x1da)
-    cp = "\x28\x37";
-  else if (ch == 0x1dc)
-    cp = "\x28\x38";
-  else if (ch == 0x2c7)
-    cp = "\x21\x26";
-  else if (ch == 0x2c9)
-    cp = "\x21\x25";
-  else if (ch >= 0x391 && ch <= 0x3c9)
-    cp = gb2312_from_ucs4_tab2[ch - 0x391];
-  else if (ch >= 0x401 && ch <= 0x451)
-    cp = gb2312_from_ucs4_tab3[ch - 0x401];
-  else if (ch >= 0x2015 && ch <= 0x203b)
-    cp = gb2312_from_ucs4_tab4[ch - 0x2015];
-  else if (ch >= 0x2103 && ch <= 0x22a5)
-    cp = gb2312_from_ucs4_tab5[ch - 0x2103];
-  else if (ch == 0x2313)
-    cp = "\x21\x50";
-  else if (ch >= 0x2460 && ch <= 0x249b)
-    cp = gb2312_from_ucs4_tab6[ch - 0x2460];
-  else if (ch >= 0x2500 && ch <= 0x254b)
+  switch (ch)
     {
+    case 0xa4 ... 0x100:
+      cp = __gb2312_from_ucs4_tab1[ch - 0xa4];
+      break;
+    case 0x113:
+      cp = "\x28\x25";
+      break;
+    case 0x11b:
+      cp = "\x28\x27";
+      break;
+    case 0x12b:
+      cp = "\x28\x29";
+      break;
+    case 0x14d:
+      cp = "\x28\x2d";
+      break;
+    case 0x16b:
+      cp = "\x28\x31";
+      break;
+    case 0x1ce:
+      cp = "\x28\x23";
+      break;
+    case 0x1d0:
+      cp = "\x28\x2b";
+      break;
+    case 0x1d2:
+      cp = "\x28\x2f";
+      break;
+    case 0x1d4:
+      cp = "\x28\x33";
+      break;
+    case 0x1d6:
+      cp = "\x28\x35";
+      break;
+    case 0x1d8:
+      cp = "\x28\x36";
+      break;
+    case 0x1da:
+      cp = "\x28\x37";
+      break;
+    case 0x1dc:
+      cp = "\x28\x38";
+      break;
+    case 0x2c7:
+      cp = "\x21\x26";
+      break;
+    case 0x2c9:
+      cp = "\x21\x25";
+      break;
+    case 0x391 ... 0x3c9:
+      cp = __gb2312_from_ucs4_tab2[ch - 0x391];
+      break;
+    case 0x401 ... 0x451:
+      cp = __gb2312_from_ucs4_tab3[ch - 0x401];
+      break;
+    case 0x2015 ... 0x203b:
+      cp = __gb2312_from_ucs4_tab4[ch - 0x2015];
+      break;
+    case 0x2103 ... 0x22a5:
+      cp = __gb2312_from_ucs4_tab5[ch - 0x2103];
+      break;
+    case 0x2313:
+      cp = "\x21\x50";
+      break;
+    case 0x2460 ... 0x249b:
+      cp = __gb2312_from_ucs4_tab6[ch - 0x2460];
+      break;
+    case 0x2500 ... 0x254b:
       buf[0] = '\x29';
       buf[1] = '\x24' + (ch & 256);
-      cp = buf;
-    }
-  else if (ch == 0x25a0)
-    cp = "\x21\x76";
-  else if (ch == 0x25a1)
-    cp = "\x21\x75";
-  else if (ch == 0x25b2)
-    cp = "\x21\x78";
-  else if (ch == 0x25b3)
-    cp = "\x21\x77";
-  else if (ch == 0x25c6)
-    cp = "\x21\x74";
-  else if (ch == 0x25c7)
-    cp = "\x21\x73";
-  else if (ch == 0x25cb)
-    cp = "\x21\x70";
-  else if (ch == 0x25ce)
-    cp = "\x21\x72";
-  else if (ch == 0x25cf)
-    cp = "\x21\x71";
-  else if (ch == 0x2605)
-    cp = "\x21\x6f";
-  else if (ch == 0x2606)
-    cp = "\x21\x6e";
-  else if (ch == 0x2640)
-    cp = "\x21\x62";
-  else if (ch == 0x2642)
-    cp = "\x21\x61";
-  else if (ch >= 0x3000 && ch <= 0x3129)
-    cp = gb2312_from_ucs4_tab7[ch - 0x3000];
-  else if (ch >= 0x3220 && ch <= 0x3229)
-    {
+      break;
+    case 0x25a0:
+      cp = "\x21\x76";
+      break;
+    case 0x25a1:
+      cp = "\x21\x75";
+      break;
+    case 0x25b2:
+      cp = "\x21\x78";
+      break;
+    case 0x25b3:
+      cp = "\x21\x77";
+      break;
+    case 0x25c6:
+      cp = "\x21\x74";
+      break;
+    case 0x25c7:
+      cp = "\x21\x73";
+      break;
+    case 0x25cb:
+      cp = "\x21\x70";
+      break;
+    case 0x25ce:
+      cp = "\x21\x72";
+      break;
+    case 0x25cf:
+      cp = "\x21\x71";
+      break;
+    case 0x2605:
+      cp = "\x21\x6f";
+      break;
+    case 0x2606:
+      cp = "\x21\x6e";
+      break;
+    case 0x2640:
+      cp = "\x21\x62";
+      break;
+    case 0x2642:
+      cp = "\x21\x61";
+      break;
+    case 0x3000 ... 0x3129:
+      cp = __gb2312_from_ucs4_tab7[ch - 0x3000];
+      break;
+    case 0x3220 ... 0x3229:
       buf[0] = '\x22';
       buf[1] = '\x65' + (ch - 0x3220);
-      cp = buf;
+      break;
+    case 0x4e00 ... 0x9fa0:
+      cp = __gb2312_from_ucs4_tab8[ch - 0x4e00];
+      break;
+    case 0xff01 ... 0xff5e:
+      cp = __gb2312_from_ucs4_tab9[ch - 0xff01];
+      break;
+    case 0xffe0:
+      cp = "\x21\x69";
+      break;
+    case 0xffe1:
+      cp = "\x21\x6a";
+      break;
+    case 0xffe3:
+      cp = "\x23\x7e";
+      break;
+    case 0xffe5:
+      cp = "\x23\x24";
+      break;
+    default:
+      return UNKNOWN_10646_CHAR;
     }
-  else if (ch >= 0x4e00 && ch <= 0x9fa0)
-    cp = gb2312_from_ucs4_tab8[ch - 0x4e00];
-  else if (ch >= 0xff01 && ch <= 0xff5e)
-    cp = gb2312_from_ucs4_tab9[ch - 0xff01];
-  else if (ch == 0xffe0)
-    cp = "\x21\x69";
-  else if (ch == 0xffe1)
-    cp = "\x21\x6a";
-  else if (ch == 0xffe3)
-    cp = "\x23\x7e";
-  else if (ch == 0xffe5)
-    cp = "\x23\x24";
-  else
-    return UNKNOWN_10646_CHAR;
 
   if (cp[1] != '\0' && avail < 2)
     return 0;
diff --git a/iconvdata/hp-roman8.c b/iconvdata/hp-roman8.c
index db36ceab9d..62e29ea463 100644
--- a/iconvdata/hp-roman8.c
+++ b/iconvdata/hp-roman8.c
@@ -1,5 +1,5 @@
 /* Conversion from and to HP-ROMAN8.
-   Copyright (C) 1997 Free Software Foundation, Inc.
+   Copyright (C) 1997, 1998 Free Software Foundation, Inc.
    This file is part of the GNU C Library.
    Contributed by Ulrich Drepper <drepper@cygnus.com>, 1997.
 
@@ -18,7 +18,12 @@
    write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
    Boston, MA 02111-1307, USA.  */
 
-#include <wchar.h>
+#include <stdint.h>
+
+/* Get the conversion table.  */
 #include <hp-roman8.h>
-#define NAME "HP-ROMAN8"
+
+#define CHARSET_NAME	"HP-ROMAN8"
+#define HAS_HOLES	1	/* Not all 256 character are defined.  */
+
 #include <8bit-generic.c>
diff --git a/iconvdata/iso646.c b/iconvdata/iso646.c
index 53ca76cb14..3c40c8fd0c 100644
--- a/iconvdata/iso646.c
+++ b/iconvdata/iso646.c
@@ -292,19 +292,17 @@ gconv (struct gconv_step *step, struct gconv_step_data *data,
 
 	      /* Correct the output buffer.  */
 	      if (newavail != data->outbufavail && newavail > 0)
-		{
-		  memmove (data->outbuf,
-			   &data->outbuf[data->outbufavail - newavail],
-			   newavail);
-		  data->outbufavail = newavail;
-		}
+		memmove (data->outbuf,
+			 &data->outbuf[data->outbufavail - newavail],
+			 newavail);
+	      data->outbufavail = newavail;
 	    }
 	}
       while (*inbufsize > 0 && result == GCONV_EMPTY_INPUT);
     }
 
   if (written != NULL && data->is_last)
-    *written = do_write;
+    *written += do_write;
 
   return result;
 }
diff --git a/iconvdata/iso6937.c b/iconvdata/iso6937.c
index 21e3ab4898..b121ffa77a 100644
--- a/iconvdata/iso6937.c
+++ b/iconvdata/iso6937.c
@@ -18,11 +18,10 @@
    write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
    Boston, MA 02111-1307, USA.  */
 
-#include <gconv.h>
-#include <string.h>
+#include <stdint.h>
 
 /* Data taken from the WG15 tables.  */
-static const wchar_t to_ucs4[256] =
+static const uint32_t to_ucs4[256] =
 {
   /* 0x00 */ 0x0000, 0x0001, 0x0002, 0x0003, 0x0004, 0x0005, 0x0006, 0x0007,
   /* 0x08 */ 0x0008, 0x0009, 0x000a, 0x000b, 0x000c, 0x000d, 0x000e, 0x000f,
@@ -60,7 +59,7 @@ static const wchar_t to_ucs4[256] =
 
 /* The outer array range runs from 0xc1 to 0xcf, the inner range from 0x20
    to 0x7f.  */
-static const wchar_t to_ucs4_comb[15][96] =
+static const uint32_t to_ucs4_comb[15][96] =
 {
   /* 0xc1 */
   {
@@ -371,290 +370,179 @@ static const char from_ucs4[][2] =
 */
 };
 
-/* Direction of the transformation.  */
-static int to_iso6937_object;
-static int from_iso6937_object;
 
+/* Definitions used in the body of the `gconv' function.  */
+#define CHARSET_NAME		"ISO_6937"
+#define FROM_LOOP		from_iso6937
+#define TO_LOOP			to_iso6937
+#define DEFINE_INIT		1
+#define DEFINE_FINI		1
+#define MIN_NEEDED_FROM	1
+#define MAX_NEEDED_FROM	2
+#define MIN_NEEDED_TO		4
+
+
+/* First define the conversion function from ISO 6937 to UCS4.  */
+#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 \
+  {									      \
+    uint32_t ch = *inptr;						      \
+									      \
+    if (ch >= 0xc1 && ch <= 0xcf)					      \
+      {									      \
+	/* Composed character.  First test whether the next character	      \
+	   is also available.  */					      \
+	int ch2;							      \
+									      \
+	if (inptr + 1 >= inend)						      \
+	  {								      \
+	    /* The second character is not available.  Store the	      \
+	       intermediate result.  */					      \
+	    result = GCONV_INCOMPLETE_INPUT;				      \
+	    break;							      \
+	  }								      \
+									      \
+	ch2 = inptr[1];							      \
+									      \
+	if (ch2 < 0x20 || ch2 >= 0x80)					      \
+	  {								      \
+	    /* This is illegal.  */					      \
+	    result = GCONV_ILLEGAL_INPUT;				      \
+	    break;							      \
+	  }								      \
+									      \
+	ch = to_ucs4_comb[ch - 0xc1][ch2 - 0x20];			      \
+									      \
+	if (ch == 0)							      \
+	  {								      \
+	    /* Illegal character.  */					      \
+	    result = GCONV_ILLEGAL_INPUT;				      \
+	    break;							      \
+	  }								      \
+									      \
+	inptr += 2;							      \
+      }									      \
+    else								      \
+      {									      \
+	ch = to_ucs4[ch];						      \
+									      \
+	if (ch == 0 && *inptr != '\0')					      \
+	  {								      \
+	    /* This is an illegal character.  */			      \
+	    result = GCONV_ILLEGAL_INPUT;				      \
+	    break;							      \
+	  }								      \
+	++inptr;							      \
+      }									      \
+									      \
+    *((uint32_t *) outptr)++ = ch;					      \
+  }
+#include <iconv/loop.c>
+
+
+/* Next, define the other direction.  */
+#define MIN_NEEDED_INPUT	MIN_NEEDED_TO
+#define MIN_NEEDED_OUTPUT	MIN_NEEDED_FROM
+#define MAX_NEEDED_OUTPUT	MAX_NEEDED_FROM
+#define LOOPFCT			TO_LOOP
+#define BODY \
+  {									      \
+    char tmp[2];							      \
+    uint32_t ch = *((uint32_t *) inptr);				      \
+    const char *cp;							      \
+									      \
+    if (ch >= sizeof (from_ucs4) / sizeof (from_ucs4[0]))		      \
+      {									      \
+	int fail = 0;							      \
+	switch (ch)							      \
+	  {								      \
+	  case 0x2c7:							      \
+	    cp = "\xcf\x20";						      \
+	    break;							      \
+	  case 0x2d8 ... 0x2dd:						      \
+	    {								      \
+	      static const char map[5] = "\xc6\xc7\xca\xce\xcd";	      \
+									      \
+	      tmp[0] = map[ch - 0x2d8];					      \
+	      tmp[1] = ' ';						      \
+	      cp = tmp;							      \
+	    }								      \
+	    break;							      \
+	  case 0x2014:							      \
+	    cp = "\xd0";						      \
+	    break;							      \
+	  case 0x2018:							      \
+	    cp = "\xa9";						      \
+	    break;							      \
+	  case 0x2019:							      \
+	    cp = "\xb9";						      \
+	    break;							      \
+	  case 0x201c:							      \
+	    cp = "\xaa";						      \
+	    break;							      \
+	  case 0x201d:							      \
+	    cp = "\xba";						      \
+	    break;							      \
+	  case 0x2122:							      \
+	    cp = "\xd4";						      \
+	    break;							      \
+	  case 0x2126:							      \
+	    cp = "\xe0";						      \
+	    break;							      \
+	  case 0x215b ... 0x215e:					      \
+	    tmp[0] = 0xdc + (ch - 0x215b);				      \
+	    tmp[1] = '\0';						      \
+	    cp = tmp;							      \
+	    break;							      \
+	  case 0x2190 ... 0x2193:					      \
+	    tmp[0] = 0xac + (ch - 0x2190);				      \
+	    tmp[1] = '\0';						      \
+	    cp = tmp;							      \
+	    break;							      \
+	  case 0x266a:							      \
+	    cp = "\xd5";						      \
+	    break;							      \
+	  default:							      \
+	    cp = NULL;							      \
+	    fail = 1;							      \
+	  }								      \
+									      \
+	if (fail)							      \
+	  {								      \
+	    /* Illegal characters.  */					      \
+	    result = GCONV_ILLEGAL_INPUT;				      \
+	    break;							      \
+	  }								      \
+      }									      \
+    else if (from_ucs4[ch][0] == '\0' && ch != 0)			      \
+      {									      \
+	/* Illegal characters.  */					      \
+	result = GCONV_ILLEGAL_INPUT;					      \
+	break;								      \
+      }									      \
+    else								      \
+      cp = from_ucs4[ch];						      \
+									      \
+    *outptr++ = cp[0];							      \
+    /* Now test for a possible second byte and write this if possible.  */    \
+    if (cp[1] != '\0')							      \
+      {									      \
+	if (NEED_LENGTH_TEST && outptr >= outend)			      \
+	  {								      \
+	    /* The result does not fit into the buffer.  */		      \
+	    result = GCONV_FULL_OUTPUT;					      \
+	    break;							      \
+	  }								      \
+	*outptr++ = cp[1];						      \
+      }									      \
+									      \
+    inptr += 4;								      \
+  }
+#include <iconv/loop.c>
 
-int
-gconv_init (struct gconv_step *step)
-{
-  /* Determine which direction.  */
-  if (strcasestr (step->from_name, "ISO_6937") != NULL)
-    step->data = &from_iso6937_object;
-  else if (strcasestr (step->to_name, "ISO_6937") != NULL)
-    step->data = &to_iso6937_object;
-  else
-    return GCONV_NOCONV;
-
-  return GCONV_OK;
-}
-
-
-void
-gconv_end (struct gconv_step *data)
-{
-  /* Nothign to do.  */
-}
-
-
-int
-gconv (struct gconv_step *step, struct gconv_step_data *data,
-       const char *inbuf, size_t *inbufsize, size_t *written, int do_flush)
-{
-  struct gconv_step *next_step = step + 1;
-  struct gconv_step_data *next_data = data + 1;
-  gconv_fct fct = next_step->fct;
-  size_t do_write;
-  int result;
-
-  /* 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 (do_flush)
-    {
-      do_write = 0;
-
-      /* Call the steps down the chain if there are any.  */
-      if (data->is_last)
-	result = GCONV_OK;
-      else
-	{
-	  struct gconv_step *next_step = step + 1;
-	  struct gconv_step_data *next_data = data + 1;
-
-	  result = (*fct) (next_step, next_data, NULL, 0, written, 1);
-
-	  /* Clear output buffer.  */
-	  data->outbufavail = 0;
-	}
-    }
-  else
-    {
-      do_write = 0;
-
-      do
-	{
-	  result = GCONV_OK;
-
-	  if (step->data == &from_iso6937_object)
-	    {
-	      size_t inchars = *inbufsize;
-	      size_t outwchars = data->outbufavail;
-	      char *outbuf = data->outbuf;
-	      size_t cnt = 0;
-
-	      while (cnt < inchars
-		     && (outwchars + sizeof (wchar_t) <= data->outbufsize))
-		{
-		  int inchar = inbuf[cnt];
-		  wchar_t ch;
-
-		  if (inchar >= '\xc1' && inchar <= '\xcf')
-		    {
-		      /* Composed character.  First test whether the next
-			 character is also available.  */
-		      int inchar2;
-
-		      if (cnt + 1 >= inchars)
-			{
-			  /* The second character is not available.  Store
-			     the intermediate result.  */
-			  result = GCONV_INCOMPLETE_INPUT;
-			  break;
-			}
-
-		      inchar2 = inbuf[++cnt];
-
-		      if (inchar2 < '\x20' || inchar2 >= '\x80')
-			/* This is illegal.  */
-			ch = L'\0';
-		      else
-			ch = to_ucs4_comb[inchar - 0xc1][inchar2 - 0x20];
-
-		      if (ch == L'\0')
-			/* Undo the increment for illegal characters.  */
-			--cnt;
-		    }
-		  else
-		    ch = to_ucs4[inchar];
-
-		  if (ch == L'\0' && inbuf[cnt] != '\0')
-		    {
-		      /* This is an illegal character.  */
-		      result = GCONV_ILLEGAL_INPUT;
-		      break;
-		    }
-
-		  *((wchar_t *) (outbuf + outwchars)) = ch;
-		  ++do_write;
-		  outwchars += sizeof (wchar_t);
-		  ++cnt;
-		}
-	      *inbufsize -= cnt;
-	      inbuf += cnt;
-	      data->outbufavail = outwchars;
-	    }
-	  else
-	    {
-	      size_t inwchars = *inbufsize;
-	      size_t outchars = data->outbufavail;
-	      char *outbuf = data->outbuf;
-	      size_t cnt = 0;
-	      int extra = 0;
-
-	      while (inwchars >= cnt + sizeof (wchar_t)
-		     && outchars < data->outbufsize)
-		{
-		  char tmp[2];
-		  int ch = *((wchar_t *) (inbuf + cnt));
-		  const char *cp;
-
-		  if (ch >= sizeof (from_ucs4) / sizeof (from_ucs4[0]))
-		    {
-		      int fail = 0;
-		      switch (ch)
-			{
-			case 0x2c7:
-			  cp = "\xcf\x20";
-			  break;
-			case 0x2d8 ... 0x2dd:
-			  {
-			    static const char map[5] = "\xc6\xc7\xca\xce\xcd";
-
-			    tmp[0] = map[ch - 0x2d8];
-			    tmp[1] = ' ';
-			    cp = tmp;
-			  }
-			  break;
-			case 0x2014:
-			  cp = "\xd0";
-			  break;
-			case 0x2018:
-			  cp = "\xa9";
-			  break;
-			case 0x2019:
-			  cp = "\xb9";
-			  break;
-			case 0x201c:
-			  cp = "\xaa";
-			  break;
-			case 0x201d:
-			  cp = "\xba";
-			  break;
-			case 0x2122:
-			  cp = "\xd4";
-			  break;
-			case 0x2126:
-			  cp = "\xe0";
-			  break;
-			case 0x215b ... 0x215e:
-			  tmp[0] = 0xdc + (ch - 0x215b);
-			  tmp[1] = '\0';
-			  cp = tmp;
-			  break;
-			case 0x2190 ... 0x2193:
-			  tmp[0] = 0xac + (ch - 0x2190);
-			  tmp[1] = '\0';
-			  cp = tmp;
-			  break;
-			case 0x266a:
-			  cp = "\xd5";
-			  break;
-			default:
-			  cp = NULL;
-			  fail = 1;
-			}
-
-		      if (fail)
-			/* Illegal characters.  */
-			break;
-		    }
-		  else if (ch < 0 || (from_ucs4[ch][0] == '\0' && ch != 0))
-		    break;
-		  else
-		    cp = from_ucs4[ch];
-
-		  outbuf[outchars] = cp[0];
-		  /* Now test for a possible second byte and write this
-		     if possible.  */
-		  if (cp[1] != '\0')
-		    {
-		      if (outchars + 1 >= data->outbufsize)
-			{
-			  /* The result does not fit into the buffer.  */
-			  extra = 1;
-			  break;
-			}
-		      outbuf[++outchars] = cp[1];
-		    }
-
-		  ++do_write;
-		  ++outchars;
-		  cnt += sizeof (wchar_t);
-		}
-	      *inbufsize -= cnt;
-	      inbuf += cnt;
-	      data->outbufavail = outchars;
-
-	      if (outchars + extra < data->outbufsize)
-		{
-		  /* If there is still room in the output buffer something
-		     is wrong with the input.  */
-		  if (inwchars >= cnt + sizeof (wchar_t))
-		    {
-		      /* An error occurred.  */
-		      result = GCONV_ILLEGAL_INPUT;
-		      break;
-		    }
-		  if (inwchars != cnt)
-		    {
-		      /* There are some unprocessed bytes at the end of the
-			 input buffer.  */
-		      result = GCONV_INCOMPLETE_INPUT;
-		      break;
-		    }
-		}
-	    }
-
-	  if (result != GCONV_OK)
-	    break;
-
-	  if (data->is_last)
-	    {
-	      /* This is the last step.  */
-	      result = (*inbufsize > (step->data == &from_iso6937_object
-				      ? 0 : sizeof (wchar_t) - 1)
-			? GCONV_FULL_OUTPUT : GCONV_EMPTY_INPUT);
-	      break;
-	    }
-
-	  /* Status so far.  */
-	  result = GCONV_EMPTY_INPUT;
-
-	  if (data->outbufavail > 0)
-	    {
-	      /* Call the functions below in the chain.  */
-	      size_t newavail = data->outbufavail;
-
-	      result = (*fct) (next_step, next_data, data->outbuf, &newavail,
-			       written, 0);
-
-	      /* Correct the output buffer.  */
-	      if (newavail != data->outbufavail && newavail > 0)
-		{
-		  memmove (data->outbuf,
-			   &data->outbuf[data->outbufavail - newavail],
-			   newavail);
-		  data->outbufavail = newavail;
-		}
-	    }
-	}
-      while (*inbufsize > 0 && result == GCONV_EMPTY_INPUT);
-    }
-
-  if (written != NULL && data->is_last)
-    *written = do_write;
 
-  return result;
-}
+/* Now define the toplevel functions.  */
+#include <iconv/skeleton.c>
diff --git a/iconvdata/iso8859-1.c b/iconvdata/iso8859-1.c
index b9484a06b7..3e50b79f17 100644
--- a/iconvdata/iso8859-1.c
+++ b/iconvdata/iso8859-1.c
@@ -18,179 +18,44 @@
    write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
    Boston, MA 02111-1307, USA.  */
 
-#include <gconv.h>
-#include <string.h>
-
-/* Direction of the transformation.  */
-static int to_iso88591_object;
-static int from_iso88591_object;
-
-
-int
-gconv_init (struct gconv_step *step)
-{
-  /* Determine which direction.  */
-  if (strcasestr (step->from_name, "ISO-8859-1") != NULL)
-    step->data = &from_iso88591_object;
-  else if (strcasestr (step->to_name, "ISO-8859-1") != NULL)
-    step->data = &to_iso88591_object;
-  else
-    return GCONV_NOCONV;
-
-  return GCONV_OK;
-}
-
-
-void
-gconv_end (struct gconv_step *data)
-{
-  /* Nothing to do.  */
-}
-
-
-int
-gconv (struct gconv_step *step, struct gconv_step_data *data,
-       const char *inbuf, size_t *inbufsize, size_t *written, int do_flush)
-{
-  struct gconv_step *next_step = step + 1;
-  struct gconv_step_data *next_data = data + 1;
-  gconv_fct fct = next_step->fct;
-  size_t do_write;
-  int result;
-
-  /* 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 (do_flush)
-    {
-      do_write = 0;
-
-      /* Call the steps down the chain if there are any.  */
-      if (data->is_last)
-	result = GCONV_OK;
-      else
-	{
-	  struct gconv_step *next_step = step + 1;
-	  struct gconv_step_data *next_data = data + 1;
-
-	  result = (*fct) (next_step, next_data, NULL, 0, written, 1);
-
-	  /* Clear output buffer.  */
-	  data->outbufavail = 0;
-	}
-    }
-  else
-    {
-      do_write = 0;
-
-      do
-	{
-	  result = GCONV_OK;
-
-	  if (step->data == &from_iso88591_object)
-	    {
-	      size_t inchars = *inbufsize;
-	      size_t outwchars = data->outbufavail;
-	      char *outbuf = data->outbuf;
-	      size_t cnt = 0;
-
-	      while (cnt < inchars
-		     && (outwchars + sizeof (wchar_t) <= data->outbufsize))
-		{
-		  *((wchar_t *) (outbuf + outwchars)) =
-		    (unsigned char) inbuf[cnt];
-		  ++do_write;
-		  outwchars += sizeof (wchar_t);
-		  ++cnt;
-		}
-	      *inbufsize -= cnt;
-	      inbuf += cnt;
-	      data->outbufavail = outwchars;
-	    }
-	  else
-	    {
-	      size_t inwchars = *inbufsize;
-	      size_t outchars = data->outbufavail;
-	      char *outbuf = data->outbuf;
-	      size_t cnt = 0;
-
-	      while (inwchars >= cnt + sizeof (wchar_t)
-		     && outchars < data->outbufsize)
-		{
-		  if (*((wchar_t *) (inbuf + cnt)) >= L'\0'
-		      && *((wchar_t *) (inbuf + cnt)) <= L'\377')
-		    outbuf[outchars] = *((wchar_t *) (inbuf + cnt));
-		  else
-		    /* Here is where the transliteration would enter the
-		       scene.  */
-		    break;
-
-		  ++do_write;
-		  ++outchars;
-		  cnt += sizeof (wchar_t);
-		}
-	      *inbufsize -= cnt;
-	      inbuf += cnt;
-	      data->outbufavail = outchars;
-
-	      if (outchars < data->outbufsize)
-		{
-		  /* If there is still room in the output buffer something
-		     is wrong with the input.  */
-		  if (inwchars >= cnt + sizeof (wchar_t))
-		    {
-		      /* An error occurred.  */
-		      result = GCONV_ILLEGAL_INPUT;
-		      break;
-		    }
-		  if (inwchars != cnt)
-		    {
-		      /* There are some unprocessed bytes at the end of the
-			 input buffer.  */
-		      result = GCONV_INCOMPLETE_INPUT;
-		      break;
-		    }
-		}
-	    }
-
-	  if (result != GCONV_OK)
-	    break;
-
-	  if (data->is_last)
-	    {
-	      /* This is the last step.  */
-	      result = (*inbufsize > (step->data == &from_iso88591_object
-				      ? 0 : sizeof (wchar_t) - 1)
-			? GCONV_FULL_OUTPUT : GCONV_EMPTY_INPUT);
-	      break;
-	    }
-
-	  /* Status so far.  */
-	  result = GCONV_EMPTY_INPUT;
-
-	  if (data->outbufavail > 0)
-	    {
-	      /* Call the functions below in the chain.  */
-	      size_t newavail = data->outbufavail;
-
-	      result = (*fct) (next_step, next_data, data->outbuf, &newavail,
-			       written, 0);
-
-	      /* Correct the output buffer.  */
-	      if (newavail != data->outbufavail && newavail > 0)
-		{
-		  memmove (data->outbuf,
-			   &data->outbuf[data->outbufavail - newavail],
-			   newavail);
-		  data->outbufavail = newavail;
-		}
-	    }
-	}
-      while (*inbufsize > 0 && result == GCONV_EMPTY_INPUT);
-    }
-
-  if (written != NULL && data->is_last)
-    *written = do_write;
-
-  return result;
-}
+#include <stdint.h>
+
+/* Definitions used in the body of the `gconv' function.  */
+#define CHARSET_NAME		"ISO-8859-1"
+#define FROM_LOOP		from_iso8859_1
+#define TO_LOOP			to_iso8859_1
+#define DEFINE_INIT		1
+#define DEFINE_FINI		1
+#define MIN_NEEDED_FROM		1
+#define MIN_NEEDED_TO		4
+
+/* First define the conversion function from ISO 8859-1 to UCS4.  */
+#define MIN_NEEDED_INPUT	MIN_NEEDED_FROM
+#define MIN_NEEDED_OUTPUT	MIN_NEEDED_TO
+#define LOOPFCT			FROM_LOOP
+#define BODY \
+  *((uint32_t *) outptr)++ = *inptr++;
+#include <iconv/loop.c>
+
+
+/* Next, define the other direction.  */
+#define MIN_NEEDED_INPUT	MIN_NEEDED_FROM
+#define MIN_NEEDED_OUTPUT	MIN_NEEDED_TO
+#define LOOPFCT			TO_LOOP
+#define BODY \
+  {									      \
+    uint32_t ch = *((uint32_t *) inptr);				      \
+    if (ch > 0xff)							      \
+      {									      \
+	/* We have an illegal character.  */				      \
+	result = GCONV_ILLEGAL_INPUT;					      \
+	break;								      \
+      }									      \
+    *outptr++ = (unsigned char) ch;					      \
+    inptr += 4;								      \
+  }
+#include <iconv/loop.c>
+
+
+/* Now define the toplevel functions.  */
+#include <iconv/skeleton.c>
diff --git a/iconvdata/iso8859-10.c b/iconvdata/iso8859-10.c
index eb54e49342..acce3257e3 100644
--- a/iconvdata/iso8859-10.c
+++ b/iconvdata/iso8859-10.c
@@ -1,5 +1,5 @@
 /* Conversion from and to ISO 8859-10.
-   Copyright (C) 1997 Free Software Foundation, Inc.
+   Copyright (C) 1997, 1998 Free Software Foundation, Inc.
    This file is part of the GNU C Library.
    Contributed by Ulrich Drepper <drepper@cygnus.com>, 1997.
 
@@ -18,7 +18,11 @@
    write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
    Boston, MA 02111-1307, USA.  */
 
-#include <wchar.h>
+/* Get the conversion table.  */
+#include <stdint.h>
 #include <iso8859-10.h>
-#define NAME "ISO-8859-10"
+
+#define CHARSET_NAME	"ISO-8859-10"
+#define HAS_HOLES	0	/* All 256 character are defined.  */
+
 #include <8bit-generic.c>
diff --git a/iconvdata/iso8859-2.c b/iconvdata/iso8859-2.c
index fa07b752c6..8a5e62418f 100644
--- a/iconvdata/iso8859-2.c
+++ b/iconvdata/iso8859-2.c
@@ -1,5 +1,5 @@
 /* Conversion from and to ISO 8859-2.
-   Copyright (C) 1997 Free Software Foundation, Inc.
+   Copyright (C) 1997, 1998 Free Software Foundation, Inc.
    This file is part of the GNU C Library.
    Contributed by Ulrich Drepper <drepper@cygnus.com>, 1997.
 
@@ -18,7 +18,11 @@
    write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
    Boston, MA 02111-1307, USA.  */
 
-#include <wchar.h>
+/* Get the conversion table.  */
+#include <stdint.h>
 #include <iso8859-2.h>
-#define NAME "ISO-8859-2"
+
+#define CHARSET_NAME	"ISO-8859-2"
+#define HAS_HOLES	0	/* All 256 character are defined.  */
+
 #include <8bit-generic.c>
diff --git a/iconvdata/iso8859-3.c b/iconvdata/iso8859-3.c
index c31d388ca2..10e52e429f 100644
--- a/iconvdata/iso8859-3.c
+++ b/iconvdata/iso8859-3.c
@@ -1,5 +1,5 @@
 /* Conversion from and to ISO 8859-3.
-   Copyright (C) 1997 Free Software Foundation, Inc.
+   Copyright (C) 1997, 1998 Free Software Foundation, Inc.
    This file is part of the GNU C Library.
    Contributed by Ulrich Drepper <drepper@cygnus.com>, 1997.
 
@@ -18,7 +18,11 @@
    write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
    Boston, MA 02111-1307, USA.  */
 
-#include <wchar.h>
+/* Get the conversion table.  */
+#include <stdint.h>
 #include <iso8859-3.h>
-#define NAME "ISO-8859-3"
+
+#define CHARSET_NAME	"ISO-8859-3"
+#define HAS_HOLES	1	/* Not all 256 character are defined.  */
+
 #include <8bit-generic.c>
diff --git a/iconvdata/iso8859-4.c b/iconvdata/iso8859-4.c
index 7ae98473ca..01cdbf0b98 100644
--- a/iconvdata/iso8859-4.c
+++ b/iconvdata/iso8859-4.c
@@ -1,5 +1,5 @@
 /* Conversion from and to ISO 8859-4.
-   Copyright (C) 1997 Free Software Foundation, Inc.
+   Copyright (C) 1997, 1998 Free Software Foundation, Inc.
    This file is part of the GNU C Library.
    Contributed by Ulrich Drepper <drepper@cygnus.com>, 1997.
 
@@ -18,7 +18,11 @@
    write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
    Boston, MA 02111-1307, USA.  */
 
-#include <wchar.h>
+/* Get the conversion table.  */
+#include <stdint.h>
 #include <iso8859-4.h>
-#define NAME "ISO-8859-4"
+
+#define CHARSET_NAME	"ISO-8859-4"
+#define HAS_HOLES	0	/* All 256 character are defined.  */
+
 #include <8bit-generic.c>
diff --git a/iconvdata/iso8859-5.c b/iconvdata/iso8859-5.c
index b4791f1bf5..edf0f47b5c 100644
--- a/iconvdata/iso8859-5.c
+++ b/iconvdata/iso8859-5.c
@@ -1,5 +1,5 @@
 /* Conversion from and to ISO 8859-5.
-   Copyright (C) 1997 Free Software Foundation, Inc.
+   Copyright (C) 1997, 1998 Free Software Foundation, Inc.
    This file is part of the GNU C Library.
    Contributed by Ulrich Drepper <drepper@cygnus.com>, 1997.
 
@@ -18,7 +18,11 @@
    write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
    Boston, MA 02111-1307, USA.  */
 
-#include <wchar.h>
+/* Get the conversion table.  */
+#include <stdint.h>
 #include <iso8859-5.h>
-#define NAME "ISO-8859-5"
+
+#define CHARSET_NAME	"ISO-8859-5"
+#define HAS_HOLES	0	/* All 256 character are defined.  */
+
 #include <8bit-generic.c>
diff --git a/iconvdata/iso8859-6.c b/iconvdata/iso8859-6.c
index 1e88ec9d22..59ce3f2cc1 100644
--- a/iconvdata/iso8859-6.c
+++ b/iconvdata/iso8859-6.c
@@ -1,5 +1,5 @@
 /* Conversion from and to ISO 8859-6.
-   Copyright (C) 1997 Free Software Foundation, Inc.
+   Copyright (C) 1997, 1998 Free Software Foundation, Inc.
    This file is part of the GNU C Library.
    Contributed by Ulrich Drepper <drepper@cygnus.com>, 1997.
 
@@ -18,7 +18,11 @@
    write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
    Boston, MA 02111-1307, USA.  */
 
-#include <wchar.h>
+/* Get the conversion table.  */
+#include <stdint.h>
 #include <iso8859-6.h>
-#define NAME "ISO-8859-6"
+
+#define CHARSET_NAME	"ISO-8859-6"
+#define HAS_HOLES	1	/* Not all 256 character are defined.  */
+
 #include <8bit-generic.c>
diff --git a/iconvdata/iso8859-7.c b/iconvdata/iso8859-7.c
index 63220bb822..d75e93e204 100644
--- a/iconvdata/iso8859-7.c
+++ b/iconvdata/iso8859-7.c
@@ -1,5 +1,5 @@
 /* Conversion from and to ISO 8859-7.
-   Copyright (C) 1997 Free Software Foundation, Inc.
+   Copyright (C) 1997, 1998 Free Software Foundation, Inc.
    This file is part of the GNU C Library.
    Contributed by Ulrich Drepper <drepper@cygnus.com>, 1997.
 
@@ -18,7 +18,11 @@
    write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
    Boston, MA 02111-1307, USA.  */
 
-#include <wchar.h>
+/* Get the conversion table.  */
+#include <stdint.h>
 #include <iso8859-7.h>
-#define NAME "ISO-8859-7"
+
+#define CHARSET_NAME	"ISO-8859-7"
+#define HAS_HOLES	1	/* Not all 256 character are defined.  */
+
 #include <8bit-generic.c>
diff --git a/iconvdata/iso8859-8.c b/iconvdata/iso8859-8.c
index 2246ae4e52..1612f148f4 100644
--- a/iconvdata/iso8859-8.c
+++ b/iconvdata/iso8859-8.c
@@ -1,5 +1,5 @@
 /* Conversion from and to ISO 8859-8.
-   Copyright (C) 1997 Free Software Foundation, Inc.
+   Copyright (C) 1997, 1998 Free Software Foundation, Inc.
    This file is part of the GNU C Library.
    Contributed by Ulrich Drepper <drepper@cygnus.com>, 1997.
 
@@ -18,7 +18,11 @@
    write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
    Boston, MA 02111-1307, USA.  */
 
-#include <wchar.h>
+/* Get the conversion table.  */
+#include <stdint.h>
 #include <iso8859-8.h>
-#define NAME "ISO-8859-8"
+
+#define CHARSET_NAME	"ISO-8859-8"
+#define HAS_HOLES	1	/* Not all 256 character are defined.  */
+
 #include <8bit-generic.c>
diff --git a/iconvdata/iso8859-9.c b/iconvdata/iso8859-9.c
index 5260362f0c..063f189aba 100644
--- a/iconvdata/iso8859-9.c
+++ b/iconvdata/iso8859-9.c
@@ -1,5 +1,5 @@
 /* Conversion from and to ISO 8859-9.
-   Copyright (C) 1997 Free Software Foundation, Inc.
+   Copyright (C) 1997, 1998 Free Software Foundation, Inc.
    This file is part of the GNU C Library.
    Contributed by Ulrich Drepper <drepper@cygnus.com>, 1997.
 
@@ -18,7 +18,11 @@
    write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
    Boston, MA 02111-1307, USA.  */
 
-#include <wchar.h>
+/* Get the conversion table.  */
+#include <stdint.h>
 #include <iso8859-9.h>
-#define NAME "ISO-8859-9"
+
+#define CHARSET_NAME "ISO-8859-9"
+#define HAS_HOLES	0	/* All 256 character are defined.  */
+
 #include <8bit-generic.c>
diff --git a/iconvdata/jis0201.c b/iconvdata/jis0201.c
index e8e04e171b..65321e4cd7 100644
--- a/iconvdata/jis0201.c
+++ b/iconvdata/jis0201.c
@@ -1,5 +1,5 @@
 /* Mapping tables for JIS0201 handling.
-   Copyright (C) 1997 Free Software Foundation, Inc.
+   Copyright (C) 1997, 1998 Free Software Foundation, Inc.
    This file is part of the GNU C Library.
    Contributed by Ulrich Drepper <drepper@cygnus.com>, 1997.
 
@@ -18,10 +18,10 @@
    write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
    Boston, MA 02111-1307, USA.  */
 
-#include <wchar.h>
+#include <stdint.h>
 
 
-const wchar_t jisx0201_to_ucs4[256] =
+const uint32_t __jisx0201_to_ucs4[256] =
 {
   0x0000, 0x0001, 0x0002, 0x0003, 0x0004, 0x0005, 0x0006, 0x0007,
   0x0008, 0x0009, 0x000a, 0x000b, 0x000c, 0x000d, 0x000e, 0x000f,
diff --git a/iconvdata/jis0201.h b/iconvdata/jis0201.h
index 8f920f9ec8..1514c88d73 100644
--- a/iconvdata/jis0201.h
+++ b/iconvdata/jis0201.h
@@ -22,13 +22,13 @@
 #define _JIS0201_H	1
 
 /* Conversion table.  */
-extern const wchar_t jis0201_to_ucs4[];
+extern const uint32_t __jis0201_to_ucs4[];
 
 
-static inline wchar_t
+static inline uint32_t
 jisx0201_to_ucs4 (char ch)
 {
-  wchar_t val = jis0201_to_ucs4[(unsigned char) ch];
+  uint32_t val = __jis0201_to_ucs4[(unsigned char) ch];
 
   if (val == 0 && ch != '\0')
     val = UNKNOWN_10646_CHAR;
@@ -38,7 +38,7 @@ jisx0201_to_ucs4 (char ch)
 
 
 static inline size_t
-ucs4_to_jisx0201 (wchar_t wch, char *s)
+ucs4_to_jisx0201 (uint32_t wch, char *s)
 {
   char ch;
 
diff --git a/iconvdata/jis0208.c b/iconvdata/jis0208.c
index 8db4085a9c..964f73dd26 100644
--- a/iconvdata/jis0208.c
+++ b/iconvdata/jis0208.c
@@ -1,5 +1,5 @@
 /* Mapping tables for JIS0208 handling.
-   Copyright (C) 1997 Free Software Foundation, Inc.
+   Copyright (C) 1997, 1998 Free Software Foundation, Inc.
    This file is part of the GNU C Library.
    Contributed by Ulrich Drepper <drepper@cygnus.com>, 1997.
 
@@ -18,7 +18,7 @@
    write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
    Boston, MA 02111-1307, USA.  */
 
-#include <wchar.h>
+#include <stdint.h>
 
 #include "jis0208.h"
 
@@ -58,7 +58,7 @@
    printf ("\n");
    ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
 */
-const uint16_t jis0208_to_ucs[0x1e80] =
+const uint16_t __jis0208_to_ucs[0x1e80] =
 {
   [0x0000] = 0x3000, [0x0001] = 0x3001, [0x0002] = 0x3002, [0x0003] = 0xff0c,
   [0x0004] = 0xff0e, [0x0005] = 0x30fb, [0x0006] = 0xff1a, [0x0007] = 0xff1b,
@@ -1783,7 +1783,7 @@ const uint16_t jis0208_to_ucs[0x1e80] =
 };
 
 
-const char jisx0208_from_ucs4_lat1[256][2] =
+const char __jisx0208_from_ucs4_lat1[256][2] =
 {
   [0x005C] = "\x21\x40", [0x00A2] = "\x21\x71", [0x00A3] = "\x21\x72",
   [0x00A7] = "\x21\x78", [0x00A8] = "\x21\x2f", [0x00AC] = "\x22\x4c",
@@ -1814,7 +1814,7 @@ const char jisx0208_from_ucs4_lat1[256][2] =
    printf ("\n");
    ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
 */
-const char jisx0208_from_ucs4_greek[0xc1][2] =
+const char __jisx0208_from_ucs4_greek[0xc1][2] =
 {
   [0x00] = "\x26\x21", [0x01] = "\x26\x22", [0x02] = "\x26\x23",
   [0x03] = "\x26\x24", [0x04] = "\x26\x25", [0x05] = "\x26\x26",
@@ -1887,7 +1887,7 @@ const char jisx0208_from_ucs4_greek[0xc1][2] =
    ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
 */
 
-const struct jisx0208_ucs_idx jisx0208_from_ucs_idx[] =
+const struct jisx0208_ucs_idx __jisx0208_from_ucs_idx[] =
 {
   { start: 0x2010, end: 0x2026, idx:     0 },
   { start: 0x2030, end: 0x2033, idx:    23 },
@@ -2596,7 +2596,7 @@ const struct jisx0208_ucs_idx jisx0208_from_ucs_idx[] =
   { start: 0x9f9c, end: 0x9fa0, idx: 14109 },
   { start: 0xff01, end: 0xff5d, idx: 14114 },
   { start: 0xffe3, end: 0xffe5, idx: 14207 },
-  { start: 0 }
+  { start: 0xffff, end: 0xffff, idx:     0 }
 };
 
 
@@ -2637,7 +2637,7 @@ const struct jisx0208_ucs_idx jisx0208_from_ucs_idx[] =
    }
    ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
 */
-const char jisx0208_from_ucs_tab[14210][2] =
+const char __jisx0208_from_ucs_tab[14210][2] =
 {
   "\x20\x10", "\x00\x00", "\x00\x00", "\x00\x00", "\x00\x00", "\x20\x15",
   "\x20\x16", "\x00\x00", "\x20\x18", "\x20\x19", "\x00\x00", "\x00\x00",
diff --git a/iconvdata/jis0208.h b/iconvdata/jis0208.h
index 94d27642c6..a83ee3bbda 100644
--- a/iconvdata/jis0208.h
+++ b/iconvdata/jis0208.h
@@ -25,12 +25,12 @@
 #include <stdint.h>
 
 /* Conversion table.  */
-extern const uint16_t jis0208_to_ucs[];
+extern const uint16_t __jis0208_to_ucs[];
 
-extern const char jisx0208_from_ucs4_lat1[256][2];
-extern const char jisx0208_from_ucs4_greek[0xc1][2];
-extern const struct jisx0208_ucs_idx jisx0208_from_ucs_idx[];
-extern const char jisx0208_from_ucs_tab[][2];
+extern const char __jisx0208_from_ucs4_lat1[256][2];
+extern const char __jisx0208_from_ucs4_greek[0xc1][2];
+extern const struct jisx0208_ucs_idx __jisx0208_from_ucs_idx[];
+extern const char __jisx0208_from_ucs_tab[][2];
 
 
 /* Struct for table with indeces in UCS mapping table.  */
@@ -42,8 +42,8 @@ struct jisx0208_ucs_idx
 };
 
 
-static inline wchar_t
-jisx0208_to_ucs4 (const char **s, size_t avail, unsigned char offset)
+static inline uint32_t
+jisx0208_to_ucs4 (const unsigned char **s, size_t avail, unsigned char offset)
 {
   unsigned char ch = *(*s);
   unsigned char ch2;
@@ -65,34 +65,38 @@ jisx0208_to_ucs4 (const char **s, size_t avail, unsigned char offset)
 
   (*s) += 2;
 
-  return jis0208_to_ucs[idx] ?: ((*s) -= 2, UNKNOWN_10646_CHAR);
+  return __jis0208_to_ucs[idx] ?: ((*s) -= 2, UNKNOWN_10646_CHAR);
 }
 
 
 static inline size_t
-ucs4_to_jisx0208 (wchar_t wch, char *s, size_t avail)
+ucs4_to_jisx0208 (uint32_t wch, char *s, size_t avail)
 {
   unsigned int ch = (unsigned int) wch;
-  const char *cp = NULL;
+  const char *cp;
 
   if (avail < 2)
     return 0;
 
   if (ch < 0x100)
-    cp = jisx0208_from_ucs4_lat1[ch];
+    cp = __jisx0208_from_ucs4_lat1[ch];
   else if (ch >= 0x391 && ch <= 0x451)
-    cp = jisx0208_from_ucs4_greek[ch];
+    cp = __jisx0208_from_ucs4_greek[ch];
   else
     {
-      const struct jisx0208_ucs_idx *rp = jisx0208_from_ucs_idx;
+      const struct jisx0208_ucs_idx *rp = __jisx0208_from_ucs_idx;
 
+      if (ch >= 0xffff)
+	return UNKNOWN_10646_CHAR;
       while (ch > rp->end)
 	++rp;
       if (ch >= rp->start)
-	cp = jisx0208_from_ucs_tab[rp->idx + ch - rp->start];
+	cp = __jisx0208_from_ucs_tab[rp->idx + ch - rp->start];
+      else
+	return UNKNOWN_10646_CHAR;
     }
 
-  if (cp == NULL || cp[0] == '\0')
+  if (cp[0] == '\0')
     return UNKNOWN_10646_CHAR;
 
   s[0] = cp[0];
diff --git a/iconvdata/jis0212.c b/iconvdata/jis0212.c
index 7484c5e84c..eca645f45a 100644
--- a/iconvdata/jis0212.c
+++ b/iconvdata/jis0212.c
@@ -19,7 +19,6 @@
    Boston, MA 02111-1307, USA.  */
 
 #include <stdint.h>
-#include <wchar.h>
 
 #include <jis0212.h>
 
@@ -54,7 +53,7 @@
 	   $first, $last, $idx);
    ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
 */
-const struct jisx0212_idx jisx0212_to_ucs_idx[] =
+const struct jisx0212_idx __jisx0212_to_ucs_idx[] =
 {
  { start: 0x006c, end: 0x0076, idx:     0 },
  { start: 0x007f, end: 0x0081, idx:    11 },
@@ -67,7 +66,7 @@ const struct jisx0212_idx jisx0212_to_ucs_idx[] =
  { start: 0x034e, end: 0x03a4, idx:   107 },
  { start: 0x03ac, end: 0x0402, idx:   194 },
  { start: 0x0582, end: 0x1c2a, idx:   281 },
- { start: 0 },
+ { start: 0xffff, end: 0xffff, idx:     0 },
 };
 
 
@@ -109,7 +108,7 @@ const struct jisx0212_idx jisx0212_to_ucs_idx[] =
    }
    ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
 */
-const uint16_t jisx0212_to_ucs[] =
+const uint16_t __jisx0212_to_ucs[] =
 {
   0x02d8, 0x02c7, 0x00b8, 0x02d9, 0x02dd, 0x00af, 0x02db, 0x02da,
   0x007e, 0x0384, 0x0385, 0x00a1, 0x00a6, 0x00bf, 0x00ba, 0x00aa,
@@ -905,7 +904,7 @@ const uint16_t jisx0212_to_ucs[] =
 	   $first, $last, $idx);
    ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
 */
-const struct jisx0212_idx jisx0212_from_ucs_idx[] =
+const struct jisx0212_idx __jisx0212_from_ucs_idx[] =
 {
   { start: 0x007e, end: 0x007e, idx:     0 },
   { start: 0x00a1, end: 0x00af, idx:     1 },
@@ -1654,7 +1653,7 @@ const struct jisx0212_idx jisx0212_from_ucs_idx[] =
   { start: 0x9f68, end: 0x9f7d, idx: 13393 },
   { start: 0x9f8f, end: 0x9f97, idx: 13415 },
   { start: 0x9f9e, end: 0x9fa5, idx: 13424 },
-  { start: 0 }
+  { start: 0xffff, end: 0xffff, idx:     0 }
 };
 
 
@@ -1697,7 +1696,7 @@ const struct jisx0212_idx jisx0212_from_ucs_idx[] =
    }
    ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
 */
-const char jisx0212_from_ucs[][2] =
+const char __jisx0212_from_ucs[][2] =
 {
   "\x7e\x00", "\xa1\x00", "\x00\x00", "\x00\x00", "\xa4\x00", "\x00\x00",
   "\xa6\x00", "\x00\x00", "\x00\x00", "\xa9\x00", "\xaa\x00", "\x00\x00",
diff --git a/iconvdata/jis0212.h b/iconvdata/jis0212.h
index cf5d919109..4930437128 100644
--- a/iconvdata/jis0212.h
+++ b/iconvdata/jis0212.h
@@ -34,20 +34,20 @@ struct jisx0212_idx
 };
 
 /* Conversion table.  */
-extern const struct jisx0212_idx jisx0212_to_ucs_idx[];
-extern const uint16_t jisx0212_to_ucs[];
+extern const struct jisx0212_idx __jisx0212_to_ucs_idx[];
+extern const uint16_t __jisx0212_to_ucs[];
 
-extern const struct jisx0212_idx jisx0212_from_ucs_idx[];
-extern const char jisx0212_from_ucs[][2];
+extern const struct jisx0212_idx __jisx0212_from_ucs_idx[];
+extern const char __jisx0212_from_ucs[][2];
 
 
 static inline wchar_t
-jisx0212_to_ucs4 (const char **s, size_t avail, unsigned char offset)
+jisx0212_to_ucs4 (const unsigned char **s, size_t avail, unsigned char offset)
 {
-  const struct jisx0212_idx *rp = jisx0212_to_ucs_idx;
+  const struct jisx0212_idx *rp = __jisx0212_to_ucs_idx;
   unsigned char ch = *(*s);
   unsigned char ch2;
-  wchar_t wch = L'\0';
+  uint32_t wch = 0;
   int idx;
 
   if (ch < offset || (ch - offset) <= 0x6d || (ch - offset) > 0xea)
@@ -62,10 +62,10 @@ jisx0212_to_ucs4 (const char **s, size_t avail, unsigned char offset)
 
   idx = (ch - 0x21 - offset) * 94 + (ch2 - 0x21 - offset);
 
-  while (idx < rp->start)
+  while (idx > rp->end)
     ++rp;
-  if (idx <= rp->end)
-    wch = jisx0212_to_ucs[rp->idx + idx - rp->start];
+  if (idx >= rp->start)
+    wch = __jisx0212_to_ucs[rp->idx + idx - rp->start];
 
   if (wch != L'\0')
     (*s) += 2;
@@ -79,16 +79,20 @@ jisx0212_to_ucs4 (const char **s, size_t avail, unsigned char offset)
 static inline size_t
 ucs4_to_jisx0212 (wchar_t wch, char *s, size_t avail)
 {
-  const struct jisx0212_idx *rp = jisx0212_from_ucs_idx;
+  const struct jisx0212_idx *rp = __jisx0212_from_ucs_idx;
   unsigned int ch = (unsigned int) wch;
-  const char *cp = NULL;
+  const char *cp;
 
+  if (ch >= 0xffff)
+    return UNKNOWN_10646_CHAR;
   while (ch > rp->end)
     ++rp;
   if (ch >= rp->start)
-    cp = jisx0212_from_ucs[rp->idx + ch - rp->start];
+    cp = __jisx0212_from_ucs[rp->idx + ch - rp->start];
+  else
+    return UNKNOWN_10646_CHAR;
 
-  if (cp == NULL || cp[0] == '\0')
+  if (cp[0] == '\0')
     return UNKNOWN_10646_CHAR;
 
   s[0] = cp[0];
diff --git a/iconvdata/johab.c b/iconvdata/johab.c
index c9912a71d0..6a582c0b70 100644
--- a/iconvdata/johab.c
+++ b/iconvdata/johab.c
@@ -1,7 +1,8 @@
 /* Mapping tables for JOHAB handling.
    Copyright (C) 1998 Free Software Foundation, Inc.
    This file is part of the GNU C Library.
-   Contributed by Jungshik Shin <jshin@pantheon.yale.edu>, 1998.
+   Contributed by Jungshik Shin <jshin@pantheon.yale.edu>
+   and 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 Library General Public License as
@@ -18,16 +19,9 @@
    write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
    Boston, MA 02111-1307, USA.  */
 
-#include <gconv.h>
 #include <stdint.h>
-#include <string.h>
-#include <wchar.h>
 #include <ksc5601.h>
 
-/* Direction of the transformation.  */
-static int to_johab_object;
-static int from_johab_object;
-
 /* The table for Bit pattern to Hangul Jamo
    5 bits each are used to encode
    leading consonants(19 + 1 filler), medial vowels(21 + 1 filler)
@@ -37,19 +31,19 @@ static int from_johab_object;
    0 : Filler, -1: invalid, >= 1 : valid
 
  */
-const int init[32] =
+static const int init[32] =
 {
   -1, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18,
   19, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1
 };
-const int mid[32] =
+static const int mid[32] =
 {
   -1, -1, 0, 1, 2, 3, 4, 5,
   -1, -1, 6, 7, 8, 9, 10, 11,
   -1, -1, 12, 13, 14, 15, 16, 17,
   -1, -1, 18, 19, 20, 21, -1, -1
 };
-const int final[32] =
+static const int final[32] =
 {
   -1, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16,
   -1, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, -1, -1
@@ -63,14 +57,14 @@ const int final[32] =
    block [0x3131,0x314e] or Hangul Conjoining Jamo block, [0x1100,0x11ff]
 
  */
-const wchar_t init_to_ucs[19] =
+static const uint32_t init_to_ucs[19] =
 {
   0x3131, 0x3132, 0x3134, 0x3137, 0x3138, 0x3139, 0x3141, 0x3142,
   0x3143, 0x3145, 0x3146, 0x3147, 0x3148, 0x3149, 0x314a, 0x314b,
   0x314c, 0x314d, 0x314e
 };
 
-const wchar_t final_to_ucs[27] =
+static const uint32_t final_to_ucs[27] =
 {
   L'\0', L'\0', 0x3133, L'\0', 0x3135, 0x3136, L'\0', L'\0',
   0x313a, 0x313b, 0x314c, 0x313d, 0x313e, 0x313f,
@@ -88,7 +82,7 @@ const wchar_t final_to_ucs[27] =
    to get the same result arithmetically.
 
  */
-const int init_to_bit[19] =
+static const int init_to_bit[19] =
 {
   0x8800, 0x8c00, 0x9000, 0x9400, 0x9800, 0x9c00,
   0xa000, 0xa400, 0xa800, 0xac00, 0xb000, 0xb400,
@@ -96,7 +90,7 @@ const int init_to_bit[19] =
   0xd000
 };
 
-const int mid_to_bit[21] =
+static const int mid_to_bit[21] =
 {
           0x0060, 0x0080, 0x00a0, 0x00c0, 0x00e0,
   0x0140, 0x0160, 0x0180, 0x01a0, 0x01c0, 0x1e0,
@@ -104,7 +98,7 @@ const int mid_to_bit[21] =
   0x0340, 0x0360, 0x0380, 0x03a0
 };
 
-const int final_to_bit[28] =
+static const int final_to_bit[28] =
 {
   1, 2, 3, 4, 5, 6, 7, 8, 9, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, 0x10, 0x11,
   0x13, 0x14, 0x15, 0x16, 0x17, 0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d
@@ -118,7 +112,7 @@ const int final_to_bit[28] =
    2. Unicode 2.0 manual
 
  */
-const uint16_t jamo_from_ucs_table[51] =
+static const uint16_t jamo_from_ucs_table[51] =
 {
   0x8841, 0x8c41,
   0x8444,
@@ -137,21 +131,20 @@ const uint16_t jamo_from_ucs_table[51] =
 };
 
 
-static inline wchar_t
-johab_sym_hanja_to_ucs (int idx, int c1, int c2)
+static inline uint32_t
+johab_sym_hanja_to_ucs (uint_fast32_t idx, uint_fast32_t c1, uint_fast32_t c2)
 {
   if (idx <= 0xdefe)
-    return (wchar_t) ksc5601_sym_to_ucs[(c1 - 0xd9) * 188 + c2
-					- (c2 > 0x90 ? 0x43 : 0x31)];
+    return (uint32_t) __ksc5601_sym_to_ucs[(c1 - 0xd9) * 188 + c2
+					   - (c2 > 0x90 ? 0x43 : 0x31)];
   else
-    return (wchar_t) ksc5601_hanja_to_ucs[(c1 - 0xe0) * 188 + c2
-					  - (c2 > 0x90 ? 0x43 : 0x31)];
+    return (uint32_t) __ksc5601_hanja_to_ucs[(c1 - 0xe0) * 188 + c2
+					     - (c2 > 0x90 ? 0x43 : 0x31)];
 }
 
 static uint16_t
-johab_hanja_from_ucs (wchar_t ch)
+johab_hanja_from_ucs (uint32_t ch)
 {
-
   uint16_t idx;
   if (ucs4_to_ksc5601_hanja (ch, &idx))
     {
@@ -168,7 +161,7 @@ johab_hanja_from_ucs (wchar_t ch)
 }
 
 static uint16_t
-johab_sym_from_ucs (wchar_t ch)
+johab_sym_from_ucs (uint32_t ch)
 {
   uint16_t idx;
   if (ucs4_to_ksc5601_sym (ch, &idx))
@@ -186,9 +179,8 @@ johab_sym_from_ucs (wchar_t ch)
 }
 
 
-
 static inline void
-johab_from_ucs4 (wchar_t ch, unsigned char *cp)
+johab_from_ucs4 (uint32_t ch, unsigned char *cp)
 {
   if (ch >= 0x7f)
     {
@@ -215,315 +207,205 @@ johab_from_ucs4 (wchar_t ch, unsigned char *cp)
       else
 	idx = johab_sym_from_ucs (ch);
 
-      *cp = (char) (idx / 256);
-      *(cp + 1) = (char) (idx & 0xff);
+      cp[0] = (unsigned char) (idx / 256);
+      cp[1] = (unsigned char) (idx & 0xff);
 
     }
   else
     {
-      *cp = (char) (0x7f & ch);
-      *(cp + 1) = (char) 0;
+      cp[0] = (unsigned char) ch;
+      cp[1] = 0;
     }
-
-}
-
-
-int
-gconv_init (struct gconv_step *step)
-{
-  /* Determine which direction.  */
-  if (strcasestr (step->from_name, "JOHAB") != NULL)
-    step->data = &from_johab_object;
-  else if (strcasestr (step->to_name, "JOHAB") != NULL)
-    step->data = &to_johab_object;
-  else
-    return GCONV_NOCONV;
-
-  return GCONV_OK;
-}
-
-
-void
-gconv_end (struct gconv_step *data)
-{
-  /* Nothing to do.  */
 }
 
 
-int
-gconv (struct gconv_step *step, struct gconv_step_data *data,
-       const char *inbuf, size_t *inbufsize, size_t * written, int do_flush)
-{
-  struct gconv_step *next_step = step + 1;
-  struct gconv_step_data *next_data = data + 1;
-  gconv_fct fct = next_step->fct;
-  size_t do_write;
-  int result;
-
-  /* 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 (do_flush)
-    {
-      do_write = 0;
-
-      /* Call the steps down the chain if there are any.  */
-      if (data->is_last)
-	result = GCONV_OK;
-      else
-	{
-	  struct gconv_step *next_step = step + 1;
-	  struct gconv_step_data *next_data = data + 1;
-
-	  result = (*fct) (next_step, next_data, NULL, 0, written, 1);
-
-	  /* Clear output buffer.  */
-	  data->outbufavail = 0;
-	}
-    }
-  else
-    {
-      do_write = 0;
-
-      do
-	{
-	  result = GCONV_OK;
-
-	  if (step->data == &from_johab_object)
-	    {
-	      size_t inchars = *inbufsize;
-	      size_t outwchars = data->outbufavail;
-	      char *outbuf = data->outbuf;
-	      size_t cnt = 0;
-
-	      while (cnt < inchars
-		     && (outwchars + sizeof (wchar_t) <= data->outbufsize))
-		{
-		  int inchar = (unsigned char) inbuf[cnt];
-		  wchar_t ch;
-		  /* half-width Korean Currency WON sign
-		     if (inchar == 0x5c)
-		     ch =  0x20a9;
-		     else if (inchar < 0x7f)
-		     ch = (wchar_t) inchar;
-		  */
-		  if (inchar < 0x7f)
-		    ch = (wchar_t) inchar;
-
-		  /* Johab : 1. Hangul
-		     1st byte : 0x84-0xd3
-		     2nd byte : 0x41-0x7e, 0x81-0xfe
-		     2. Hanja & Symbol  :
-		     1st byte : 0xd8-0xde, 0xe0-0xf9
-		     2nd byte : 0x31-0x7e, 0x91-0xfe
-		     0xd831-0xd87e and 0xd891-0xd8fe are user-defined area */
-
-		  else if (inchar > 0xf9 || inchar == 0xdf
-			   || (inchar > 0x7e && inchar < 0x84)
-			   || (inchar > 0xd3 && inchar < 0xd9))
-		    /* These are illegal.  */
-		    ch = L'\0';
-		  else
-		    {
-		      /* Two-byte character.  First test whether the next
-		         character is also available.  */
-		      int inchar2;
-		      int idx;
-
-		      if (cnt + 1 >= inchars)
-			{
-			  /* The second character is not available.  Store
-			     the intermediate result.  */
-			  result = GCONV_INCOMPLETE_INPUT;
-			  break;
-			}
-
-		      inchar2 = (unsigned char) inbuf[++cnt];
-		      idx = inchar * 256 + inchar2;
-		      if (inchar <= 0xd3)
-			{	/* Hangul */
-			  int i, m, f;
-			  i = init[(idx & 0x7c00) >> 10];
-			  m = mid[(idx & 0x03e0) >> 5];
-			  f = final[idx & 0x001f];
-			  if (i == -1 || m == -1 || f == -1)
-			    /* This is illegal.  */
-			    ch = L'\0';
-			  else if (i > 0 && m > 0)
-			    ch = ((i - 1) * 21 + (m - 1)) * 28 + f + 0xac00;
-			  else if (i > 0 && m == 0 & f == 0)
-			    ch = init_to_ucs[i - 1];
-			  else if (i == 0 && m > 0 & f == 0)
-			    ch = 0x314e + m;	/* 0x314f + m - 1 */
-			  else if (i == 0 && m == 0 & f > 0)
-			    ch = final_to_ucs[f - 1];	/* round trip?? */
-			  else
-			    /* This is illegal.  */
-			    ch = L'\0';
-			}
-		      else
-			{
-			  if (inchar2 < 0x31
-			      || (inchar2 > 0x7e && inchar2 < 0x91)
-			      || inchar2 == 0xff)
-			    /* This is illegal.  */
-			    ch = L'\0';
-			  else if (inchar == 0xda
-				   && inchar2 > 0xa0 && inchar2 < 0xd4)
-			    /* This is illegal.  */
-			    /* Modern Hangul Jaso is defined elsewhere
-			       in Johab */
-			    ch = L'\0';
-			  else
-			    {
-			      ch = johab_sym_hanja_to_ucs (idx, inchar,
-							   inchar2);
-			      /*                if (idx <= 0xdefe)
-			         ch = ksc5601_sym_to_ucs[(inchar - 0xd9) * 192
-			         + inchar2
-			         -  (inchar2>0x90 ? 0x43 : 0x31)];
-
-			         else
-			         ch = ksc5601_hanja_to_ucs[(inchar - 0xe0) *192
-			         + inchar2
-			         -  (inchar2>0x90 ? 0x43 : 0x31)];
-			       */
-			    }
-			}
-
-		      if (ch == L'\0')
-			--cnt;
-		    }
-
-		  if (ch == L'\0' && inbuf[cnt] != '\0')
-		    {
-		      /* This is an illegal character.  */
-		      result = GCONV_ILLEGAL_INPUT;
-		      break;
-		    }
-
-		  *((wchar_t *) (outbuf + outwchars)) = ch;
-		  ++do_write;
-		  outwchars += sizeof (wchar_t);
-		  ++cnt;
-		}
-	      *inbufsize -= cnt;
-	      inbuf += cnt;
-	      data->outbufavail = outwchars;
-	    }
-	  else
-	    {
-	      size_t inwchars = *inbufsize;
-	      size_t outchars = data->outbufavail;
-	      char *outbuf = data->outbuf;
-	      size_t cnt = 0;
-	      int extra = 0;
-
-	      while (inwchars >= cnt + sizeof (wchar_t)
-		     && outchars < data->outbufsize)
-		{
-		  wchar_t ch = *((wchar_t *) (inbuf + cnt));
-		  unsigned char cp[2];
-		  /*
-		    if (ch >= (sizeof (from_ucs4_lat1)
-			/ sizeof (from_ucs4_lat1[0])))
-		      {
-			if (ch >= 0x0391 && ch <= 0x0451)
-			  cp = from_ucs4_greek[ch - 0x391];
-			else if (ch >= 0x2010 && ch <= 0x9fa0)
-			  cp = from_ucs4_cjk[ch - 0x02010];
-			else
-			  break;
-		      }
-		    else
-		      cp = from_ucs4_lat1[ch];
-		  */
-		  johab_from_ucs4 (ch, cp);
-
-		  if (cp[0] == '\0' && ch != 0)
-		    /* Illegal character.  */
-		    break;
-
-		  outbuf[outchars] = cp[0];
-		  /* Now test for a possible second byte and write this
-		     if possible.  */
-		  if (cp[1] != '\0')
-		    {
-		      if (outchars + 1 >= data->outbufsize)
-			{
-			  /* The result does not fit into the buffer.  */
-			  extra = 1;
-			  break;
-			}
-		      outbuf[++outchars] = cp[1];
-		    }
-
-		  ++do_write;
-		  ++outchars;
-		  cnt += sizeof (wchar_t);
-		}
-	      *inbufsize -= cnt;
-	      inbuf += cnt;
-	      data->outbufavail = outchars;
-
-	      if (outchars + extra < data->outbufsize)
-		{
-		  /* If there is still room in the output buffer something
-		     is wrong with the input.  */
-		  if (inwchars >= cnt + sizeof (wchar_t))
-		    {
-		      /* An error occurred.  */
-		      result = GCONV_ILLEGAL_INPUT;
-		      break;
-		    }
-		  if (inwchars != cnt)
-		    {
-		      /* There are some unprocessed bytes at the end of the
-		         input buffer.  */
-		      result = GCONV_INCOMPLETE_INPUT;
-		      break;
-		    }
-		}
-	    }
-
-	  if (result != GCONV_OK)
-	    break;
-
-	  if (data->is_last)
-	    {
-	      /* This is the last step.  */
-	      result = (*inbufsize > (step->data == &from_johab_object
-				      ? 0 : sizeof (wchar_t) - 1)
-			? GCONV_FULL_OUTPUT : GCONV_EMPTY_INPUT);
-	      break;
-	    }
-
-	  /* Status so far.  */
-	  result = GCONV_EMPTY_INPUT;
-
-	  if (data->outbufavail > 0)
-	    {
-	      /* Call the functions below in the chain.  */
-	      size_t newavail = data->outbufavail;
-
-	      result = (*fct) (next_step, next_data, data->outbuf, &newavail,
-			       written, 0);
-
-	      /* Correct the output buffer.  */
-	      if (newavail != data->outbufavail && newavail > 0)
-		{
-		  memmove (data->outbuf,
-			   &data->outbuf[data->outbufavail - newavail],
-			   newavail);
-		  data->outbufavail = newavail;
-		}
-	    }
-	}
-      while (*inbufsize > 0 && result == GCONV_EMPTY_INPUT);
-    }
-
-  if (written != NULL && data->is_last)
-    *written = do_write;
-
-  return result;
-}
+/* Definitions used in the body of the `gconv' function.  */
+#define CHARSET_NAME		"JOHAB"
+#define FROM_LOOP		from_johab
+#define TO_LOOP			to_johab
+#define DEFINE_INIT		1
+#define DEFINE_FINI		1
+#define MIN_NEEDED_FROM		1
+#define MAX_NEEDED_FROM		2
+#define MIN_NEEDED_TO		4
+
+
+/* First define the conversion function from JOHAB to UCS4.  */
+#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 \
+  {									      \
+    uint32_t ch = *inptr;						      \
+									      \
+    /* half-width Korean Currency WON sign				      \
+       if (ch == 0x5c)							      \
+	 ch =  0x20a9;							      \
+       else if (ch < 0x7f)						      \
+	 ch = (wchar_t) ch;						      \
+    */									      \
+    if (ch < 0x7f)							      \
+      /* Plain ASCII.  */						      \
+      ++inptr;								      \
+    /* Johab : 1. Hangul						      \
+       1st byte : 0x84-0xd3						      \
+       2nd byte : 0x41-0x7e, 0x81-0xfe					      \
+       2. Hanja & Symbol  :						      \
+       1st byte : 0xd8-0xde, 0xe0-0xf9					      \
+       2nd byte : 0x31-0x7e, 0x91-0xfe					      \
+       0xd831-0xd87e and 0xd891-0xd8fe are user-defined area */		      \
+    else								      \
+      {									      \
+	if (ch > 0xf9 || ch == 0xdf || (ch > 0x7e && ch < 0x84)		      \
+	    || (ch > 0xd3 && ch < 0xd9))				      \
+	  {								      \
+	    /* These are illegal.  */					      \
+	    result = GCONV_ILLEGAL_INPUT;				      \
+	    break;							      \
+	  }								      \
+	else								      \
+	  {								      \
+	    /* Two-byte character.  First test whether the next		      \
+	       character is also available.  */				      \
+	    uint32_t ch2;						      \
+	    uint_fast32_t idx;						      \
+									      \
+	    if (NEED_LENGTH_TEST && inptr + 1 >= inend)			      \
+	      {								      \
+		/* The second character is not available.  Store the	      \
+		   intermediate result.  */				      \
+		result = GCONV_INCOMPLETE_INPUT;			      \
+		break;							      \
+	      }								      \
+									      \
+	    ch2 = inptr[1];						      \
+	    idx = ch * 256 + ch2;					      \
+	    if (ch <= 0xd3)						      \
+	      {								      \
+		/* Hangul */						      \
+		uint_fast32_t i, m, f;					      \
+									      \
+		i = init[(idx & 0x7c00) >> 10];				      \
+		m = mid[(idx & 0x03e0) >> 5];				      \
+		f = final[idx & 0x001f];				      \
+									      \
+		if (i == -1 || m == -1 || f == -1)			      \
+		  {							      \
+		    /* This is illegal.  */				      \
+		    result = GCONV_ILLEGAL_INPUT;			      \
+		    break;						      \
+		  }							      \
+		else if (i > 0 && m > 0)				      \
+		  ch = ((i - 1) * 21 + (m - 1)) * 28 + f + 0xac00;	      \
+		else if (i > 0 && m == 0 & f == 0)			      \
+		  ch = init_to_ucs[i - 1];				      \
+		else if (i == 0 && m > 0 & f == 0)			      \
+		  ch = 0x314e + m;	/* 0x314f + m - 1 */		      \
+		else if (i == 0 && m == 0 & f > 0)			      \
+		  ch = final_to_ucs[f - 1];	/* round trip?? */	      \
+		else							      \
+		  {							      \
+		    /* This is illegal.  */				      \
+		    result = GCONV_ILLEGAL_INPUT;			      \
+		    break;						      \
+		  }							      \
+	      }								      \
+	    else							      \
+	      {								      \
+		if (ch2 < 0x31 || (ch2 > 0x7e && ch2 < 0x91) || ch2 == 0xff)  \
+		  {							      \
+		    /* This is illegal.  */				      \
+		    result = GCONV_ILLEGAL_INPUT;			      \
+		    break;						      \
+		  }							      \
+		else if (ch == 0xda && ch2 > 0xa0 && ch2 < 0xd4)	      \
+		  {							      \
+		    /* This is illegal.  Modern Hangul Jaso is defined	      \
+		       elsewhere in Johab */				      \
+		    result = GCONV_ILLEGAL_INPUT;			      \
+		    break;						      \
+		  }							      \
+		else							      \
+		  {							      \
+		    ch = johab_sym_hanja_to_ucs (idx, ch, ch2);		      \
+		    /* if (idx <= 0xdefe)				      \
+			 ch = __ksc5601_sym_to_ucs[(ch - 0xd9) * 192	      \
+						   + ch2 - (ch2 > 0x90	      \
+							    ? 0x43 : 0x31)];  \
+		       else						      \
+		         ch = __ksc5601_hanja_to_ucs[(ch - 0xe0) *192	      \
+						     + ch2 -  (ch2 > 0x90     \
+							       ?0x43 : 0x31)];\
+		    */							      \
+		  }							      \
+	      }								      \
+	  }								      \
+									      \
+	if (ch == 0)							      \
+	  {								      \
+	    /* This is an illegal character.  */			      \
+	    result = GCONV_ILLEGAL_INPUT;				      \
+	    break;							      \
+	  }								      \
+									      \
+	inptr += 2;							      \
+      }									      \
+									      \
+    *((uint32_t *) outptr)++ = ch;					      \
+  }
+#include <iconv/loop.c>
+
+
+/* Next, define the other direction.  */
+#define MIN_NEEDED_INPUT	MIN_NEEDED_TO
+#define MIN_NEEDED_OUTPUT	MIN_NEEDED_FROM
+#define MAX_NEEDED_OUTPUT	MAX_NEEDED_FROM
+#define LOOPFCT			TO_LOOP
+#define BODY \
+  {									      \
+    uint32_t ch = *((uint32_t *) inptr);				      \
+    unsigned char cp[2];						      \
+    /*									      \
+       if (ch >= (sizeof (from_ucs4_lat1) / sizeof (from_ucs4_lat1[0])))      \
+	 {								      \
+	   if (ch >= 0x0391 && ch <= 0x0451)				      \
+	     cp = from_ucs4_greek[ch - 0x391];				      \
+	   else if (ch >= 0x2010 && ch <= 0x9fa0)			      \
+	     cp = from_ucs4_cjk[ch - 0x02010];				      \
+	   else								      \
+	     break;							      \
+	 }								      \
+       else								      \
+	 cp = from_ucs4_lat1[ch];					      \
+    */									      \
+    johab_from_ucs4 (ch, cp);						      \
+									      \
+    if (cp[0] == '\0' && ch != 0)					      \
+      {									      \
+	/* Illegal character.  */					      \
+	result = GCONV_ILLEGAL_INPUT;					      \
+	break;								      \
+      }									      \
+									      \
+    *outptr++ = cp[0];							      \
+    /* Now test for a possible second byte and write this if possible.  */    \
+    if (cp[1] != '\0')							      \
+      {									      \
+	if (NEED_LENGTH_TEST && outptr >= outend)			      \
+	  {								      \
+	    /* The result does not fit into the buffer.  */		      \
+	    --outptr;							      \
+	    result = GCONV_FULL_OUTPUT;					      \
+	    break;							      \
+	  }								      \
+	*outptr++ = cp[1];						      \
+      }									      \
+									      \
+    inptr += 4;								      \
+  }
+#include <iconv/loop.c>
+
+
+/* Now define the toplevel functions.  */
+#include <iconv/skeleton.c>
diff --git a/iconvdata/koi-8.c b/iconvdata/koi-8.c
index 2228456801..b2332c2a6a 100644
--- a/iconvdata/koi-8.c
+++ b/iconvdata/koi-8.c
@@ -1,5 +1,5 @@
 /* Conversion from and to KOI-8.
-   Copyright (C) 1997 Free Software Foundation, Inc.
+   Copyright (C) 1997, 1998 Free Software Foundation, Inc.
    This file is part of the GNU C Library.
    Contributed by Ulrich Drepper <drepper@cygnus.com>, 1997.
 
@@ -18,7 +18,11 @@
    write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
    Boston, MA 02111-1307, USA.  */
 
-#include <wchar.h>
+/* Get the conversion table.  */
+#include <stdint.h>
 #include <koi-8.h>
-#define NAME "KOI-8"
+
+#define CHARSET_NAME	"KOI-8"
+#define HAS_HOLES	1	/* Not all 256 character are defined.  */
+
 #include <8bit-generic.c>
diff --git a/iconvdata/koi8-r.c b/iconvdata/koi8-r.c
index 502132b338..ee317bd25b 100644
--- a/iconvdata/koi8-r.c
+++ b/iconvdata/koi8-r.c
@@ -1,5 +1,5 @@
 /* Conversion from and to KOI8-R.
-   Copyright (C) 1997 Free Software Foundation, Inc.
+   Copyright (C) 1997, 1998 Free Software Foundation, Inc.
    This file is part of the GNU C Library.
    Contributed by Ulrich Drepper <drepper@cygnus.com>, 1997.
 
@@ -18,7 +18,12 @@
    write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
    Boston, MA 02111-1307, USA.  */
 
-#include <wchar.h>
+#include <stdint.h>
+
+/* Specify the conversion table.  */
 #define TABLES <koi8-r.h>
-#define NAME "KOI8-R"
+
+#define CHARSET_NAME	"KOI8-R"
+#define HAS_HOLES	1	/* Not all 256 character are defined.  */
+
 #include <8bit-gap.c>
diff --git a/iconvdata/ksc5601.c b/iconvdata/ksc5601.c
index c919425aa7..da64c430f4 100644
--- a/iconvdata/ksc5601.c
+++ b/iconvdata/ksc5601.c
@@ -18,7 +18,7 @@
    write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
    Boston, MA 02111-1307, USA.  */
 
-#include <wchar.h>
+#include <stdint.h>
 #include "ksc5601.h"
 
 /*
@@ -50,7 +50,7 @@ perl tab21.pl > ksc_hangul1.tb
 */
 
 
-const uint16_t ksc5601_hangul_to_ucs[KSC5601_HANGUL]=
+const uint16_t __ksc5601_hangul_to_ucs[KSC5601_HANGUL]=
 {
   0xac00, 0xac01, 0xac04, 0xac07, 0xac08, 0xac09, 0xac0a, 0xac10,
   0xac11, 0xac12, 0xac13, 0xac14, 0xac15, 0xac16, 0xac17, 0xac19,
@@ -369,7 +369,7 @@ grep -v '# HANGUL SYLLABLE' | perl tab11.pl  > ksc_sym1.tb
 
 */
 
-const uint16_t ksc5601_sym_to_ucs[] =
+const uint16_t __ksc5601_sym_to_ucs[] =
 {
   [0x0000] = 0x3000, [0x0001] = 0x3001, [0x0002] = 0x3002, [0x0003] = 0x00b7,
   [0x0004] = 0x2025, [0x0005] = 0x2026, [0x0006] = 0x00a8, [0x0007] = 0x3003,
@@ -646,7 +646,7 @@ perl tab12.pl > ksc_sym2.tb
 
 */
 
-const uint16_t ksc5601_sym_from_ucs[KSC5601_SYMBOL][2] =
+const uint16_t __ksc5601_sym_from_ucs[KSC5601_SYMBOL][2] =
 {
   {0x00a1, 0x222e}, {0x00a4, 0x2234}, {0x00a7, 0x2157}, {0x00a8, 0x2127},
   {0x00aa, 0x2823}, {0x00ad, 0x2129}, {0x00b0, 0x2146}, {0x00b1, 0x213e},
@@ -914,7 +914,7 @@ perl tab21.pl > ksc_hanja1.tb
    printf ("\n");
 */
 
-const uint16_t ksc5601_hanja_to_ucs[KSC5601_HANJA]=
+const uint16_t __ksc5601_hanja_to_ucs[KSC5601_HANJA]=
 {
   0x4f3d, 0x4f73, 0x5047, 0x50f9, 0x52a0, 0x53ef, 0x5475, 0x54e5,
   0x5609, 0x5ac1, 0x5bb6, 0x6687, 0x67b6, 0x67b7, 0x67ef, 0x6b4c,
@@ -1550,7 +1550,7 @@ awk '{print $2,$1}' | sort -u | perl tab12.pl > ksc_hanja2.tb
 
 */
 
-const uint16_t ksc5601_hanja_from_ucs[KSC5601_HANJA][2]=
+const uint16_t __ksc5601_hanja_from_ucs[KSC5601_HANJA][2]=
 {
   {0x4e00, 0x6c69}, {0x4e01, 0x6f4b}, {0x4e03, 0x7652}, {0x4e07, 0x5832},
   {0x4e08, 0x6d5b}, {0x4e09, 0x5f32}, {0x4e0a, 0x5f3e}, {0x4e0b, 0x793b},
diff --git a/iconvdata/ksc5601.h b/iconvdata/ksc5601.h
index 0d86c7b253..8a5c40e5dd 100644
--- a/iconvdata/ksc5601.h
+++ b/iconvdata/ksc5601.h
@@ -28,18 +28,18 @@
 #include <stdint.h>
 
 /* Conversion table.  */
-extern const uint16_t ksc5601_hangul_to_ucs[KSC5601_HANGUL];
-extern const uint16_t ksc5601_sym_to_ucs[];
-extern const uint16_t ksc5601_sym_from_ucs[KSC5601_SYMBOL][2];
-extern const uint16_t ksc5601_hanja_to_ucs[KSC5601_HANJA];
-extern const uint16_t ksc5601_hanja_from_ucs[KSC5601_HANJA][2];
+extern const uint16_t __ksc5601_hangul_to_ucs[KSC5601_HANGUL];
+extern const uint16_t __ksc5601_sym_to_ucs[];
+extern const uint16_t __ksc5601_sym_from_ucs[KSC5601_SYMBOL][2];
+extern const uint16_t __ksc5601_hanja_to_ucs[KSC5601_HANJA];
+extern const uint16_t __ksc5601_hanja_from_ucs[KSC5601_HANJA][2];
 
 
 /*
 static inline wchar_t
 ksc5601_to_ucs4 (char **s, size_t avail)
 */
-static inline wchar_t
+static inline uint32_t
 ksc5601_to_ucs4 (uint16_t s)
 {
   unsigned char ch = s / 256;
@@ -61,23 +61,25 @@ ksc5601_to_ucs4 (uint16_t s)
      Hangul in KS C 5601 : row 16 - row 40 */
 
   if (idx >= 1410 && idx < 3760)
-    return ksc5601_hangul_to_ucs[idx-1410];
+    return __ksc5601_hangul_to_ucs[idx-1410];
   else if (idx > 3854)
     /* Hanja : row 42 - row 93 : 3854 = 94 * (42-1) */
-   return ksc5601_hanja_to_ucs[idx-3854];
+   return __ksc5601_hanja_to_ucs[idx-3854];
   else
-    return ksc5601_sym_to_ucs[idx] ?: UNKNOWN_10646_CHAR;
+    return __ksc5601_sym_to_ucs[idx] ?: UNKNOWN_10646_CHAR;
 }
 
 static inline size_t
-ucs4_to_ksc5601_hangul (wchar_t wch, uint16_t *s)
+ucs4_to_ksc5601_hangul (uint32_t wch, uint16_t *s)
 {
-  int l=0,m,u=KSC5601_HANGUL-1;
-  wchar_t try;
+  int l = 0;
+  int m;
+  int u = KSC5601_HANGUL - 1;
+  uint32_t try;
 
   while (l <= u)
     {
-      try = (wchar_t) ksc5601_hangul_to_ucs[m=(l+u)/2];
+      try = (uint32_t) __ksc5601_hangul_to_ucs[m=(l+u)/2];
       if (try > wch)
 	u = m - 1;
       else if (try < wch)
@@ -93,21 +95,24 @@ ucs4_to_ksc5601_hangul (wchar_t wch, uint16_t *s)
 
 
 static inline size_t
-ucs4_to_ksc5601_hanja (wchar_t wch, uint16_t *s)
+ucs4_to_ksc5601_hanja (uint32_t wch, uint16_t *s)
 {
-  int l=0,m,u=KSC5601_HANJA-1;
-  wchar_t try;
+  int l = 0;
+  int m;
+  int u = KSC5601_HANJA - 1;
+  uint32_t try;
 
   while (l <= u)
     {
-      try = (wchar_t) ksc5601_hanja_from_ucs[m=(l+u)/2][0];
+      m = (l + u) / 2;
+      try = (uint32_t) __ksc5601_hanja_from_ucs[m][0];
       if (try > wch)
 	u=m-1;
       else if (try < wch)
 	l = m + 1;
       else
 	{
-	  *s = ksc5601_hanja_from_ucs[m][1];
+	  *s = __ksc5601_hanja_from_ucs[m][1];
 	  return 2;
 	}
     }
@@ -115,24 +120,24 @@ ucs4_to_ksc5601_hanja (wchar_t wch, uint16_t *s)
 }
 
 static inline  size_t
-ucs4_to_ksc5601_sym (wchar_t wch, uint16_t *s)
+ucs4_to_ksc5601_sym (uint32_t wch, uint16_t *s)
 {
   int l = 0;
   int m;
   int u = KSC5601_SYMBOL - 1;
-  wchar_t try;
+  uint32_t try;
 
   while (l <= u)
     {
       m = (l + u) / 2;
-      try = ksc5601_sym_from_ucs[m][0];
+      try = __ksc5601_sym_from_ucs[m][0];
       if (try > wch)
 	u = m - 1;
       else if (try < wch)
 	l = m + 1;
       else
 	{
-	  *s = ksc5601_sym_from_ucs[m][1];
+	  *s = __ksc5601_sym_from_ucs[m][1];
 	  return 2;
 	}
     }
@@ -146,13 +151,13 @@ ucs4_to_ksc5601 (wchar_t wch, char **s, size_t avail)
 */
 
 static inline size_t
-ucs4_to_ksc5601 (wchar_t ch, uint16_t *s)
+ucs4_to_ksc5601 (uint32_t ch, uint16_t *s)
 {
   *s = (uint16_t) UNKNOWN_10646_CHAR;  /* FIXIT */
 
   if (ch >= 0xac00 && ch <= 0xd7a3)
     return ucs4_to_ksc5601_hangul (ch, s);
-  else if (ch >= 0x4e00 && ch <= 0x9fff ||  ch >= 0xf900 && ch <= 0xfa0b)
+  else if (ch >= 0x4e00 && ch <= 0x9fff || ch >= 0xf900 && ch <= 0xfa0b)
     return ucs4_to_ksc5601_hanja (ch, s);
   else
     return ucs4_to_ksc5601_sym (ch, s);
diff --git a/iconvdata/latin-greek-1.c b/iconvdata/latin-greek-1.c
index d62969a77d..37ccf09c09 100644
--- a/iconvdata/latin-greek-1.c
+++ b/iconvdata/latin-greek-1.c
@@ -1,5 +1,5 @@
 /* Conversion from and to LATIN-GREEK-1.
-   Copyright (C) 1997 Free Software Foundation, Inc.
+   Copyright (C) 1997, 1998 Free Software Foundation, Inc.
    This file is part of the GNU C Library.
    Contributed by Ulrich Drepper <drepper@cygnus.com>, 1997.
 
@@ -18,7 +18,10 @@
    write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
    Boston, MA 02111-1307, USA.  */
 
-#include <wchar.h>
+/* Specify the conversion table.  */
 #define TABLES <latin-greek-1.h>
-#define NAME "LATIN-GREEK-1"
+
+#define CHARSET_NAME	"LATIN-GREEK-1"
+#define HAS_HOLES	1	/* Not all 256 character are defined.  */
+
 #include <8bit-gap.c>
diff --git a/iconvdata/latin-greek.c b/iconvdata/latin-greek.c
index 90270e0e07..8810f4a2e0 100644
--- a/iconvdata/latin-greek.c
+++ b/iconvdata/latin-greek.c
@@ -1,5 +1,5 @@
 /* Conversion from and to LATIN-GREEK.
-   Copyright (C) 1997 Free Software Foundation, Inc.
+   Copyright (C) 1997, 1998 Free Software Foundation, Inc.
    This file is part of the GNU C Library.
    Contributed by Ulrich Drepper <drepper@cygnus.com>, 1997.
 
@@ -18,7 +18,10 @@
    write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
    Boston, MA 02111-1307, USA.  */
 
-#include <wchar.h>
+/* Specify the conversion table.  */
 #define TABLES <latin-greek.h>
-#define NAME "LATIN-GREEK"
+
+#define CHARSET_NAME	"LATIN-GREEK"
+#define HAS_HOLES	1	/* Not all 256 character are defined.  */
+
 #include <8bit-gap.c>
diff --git a/iconvdata/run-iconv-test.sh b/iconvdata/run-iconv-test.sh
index ebafa2f298..af6a136c4a 100755
--- a/iconvdata/run-iconv-test.sh
+++ b/iconvdata/run-iconv-test.sh
@@ -52,10 +52,18 @@ while read from to targets; do
       { echo "*** conversion from $t to $to failed"; exit 1; }
     test -s $temp1 && cmp testdata/$from $temp2 >& /dev/null ||
       { echo "*** $from -> t -> $to conversion failed"; exit 1; }
+    rm -f $temp1 $temp2
+
+    # Now test some bigger text, entirely in ASCII.
+    $ICONV -f $from -t $t testdata/suntzus |
+    $ICONV -f $t -t $to > $temp1 ||
+      { echo "*** conversion $from->$t->$to of suntzus failed"; exit 1; }
+    cmp testdata/suntzus.txt $temp1 ||
+      { echo "*** conversion $from->$t->$to of suntzus incorrect"; exit 1; }
+    rm -f $temp1
 
     # All tests ok.
     echo "$from -> $t -> $to ok"
-    rm -f $temp1 $temp2
   done
 done < TESTS
 
diff --git a/iconvdata/sjis.c b/iconvdata/sjis.c
index 33dc2f1d65..d65b905b32 100644
--- a/iconvdata/sjis.c
+++ b/iconvdata/sjis.c
@@ -18,12 +18,10 @@
    write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
    Boston, MA 02111-1307, USA.  */
 
-#include <gconv.h>
 #include <stdint.h>
-#include <string.h>
 #include <wchar.h>
 
-static const wchar_t halfkana_to_ucs4[] =
+static const uint32_t halfkana_to_ucs4[] =
 {
   0xff61, 0xff62, 0xff63, 0xff64, 0xff65, 0xff66, 0xff67, 0xff68,
   0xff69, 0xff6a, 0xff6b, 0xff6c, 0xff6d, 0xff6e, 0xff6f, 0xff70,
@@ -3981,268 +3979,151 @@ static const char from_ucs4_cjk[32657][2] =
 };
 
 
-/* Direction of the transformation.  */
-static int to_sjis_object;
-static int from_sjis_object;
+/* Definitions used in the body of the `gconv' function.  */
+#define CHARSET_NAME		"SJIS"
+#define FROM_LOOP		from_sjis
+#define TO_LOOP			to_sjis
+#define DEFINE_INIT		1
+#define DEFINE_FINI		1
+#define MIN_NEEDED_FROM		1
+#define MAX_NEEDED_FROM		2
+#define MIN_NEEDED_TO		4
 
+/* First define the conversion function from SJIS to UCS4.  */
+#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 \
+  {									      \
+    uint32_t ch = *inptr;						      \
+									      \
+    if (ch == 0x5c)							      \
+      {									      \
+	ch = 0xa5;							      \
+	++inptr;							      \
+      }									      \
+    else if (ch == 0x7e)						      \
+      {									      \
+	ch = 0x203e;							      \
+	++inptr;							      \
+      }									      \
+    else if (ch < 0x7e)							      \
+      ++inptr;								      \
+    else if (ch >= 0xa1 && ch <= 0xdf)					      \
+      {									      \
+	ch = halfkana_to_ucs4[ch - 0xa1];				      \
+	++inptr;							      \
+      }									      \
+    else if (ch > 0xea || ch == 0xa0 || ch == 0x7f || ch == 0x80)	      \
+      {									      \
+	/* These are illegal.  */					      \
+	result = GCONV_ILLEGAL_INPUT;					      \
+	break;								      \
+      }									      \
+    else								      \
+      {									      \
+	/* Two-byte character.  First test whether the next character	      \
+	   is also available.  */					      \
+	uint32_t ch2;							      \
+	uint_fast32_t idx;						      \
+									      \
+	if (NEED_LENGTH_TEST && inptr + 1 >= inend)			      \
+	  {								      \
+	    /* The second character is not available.  Store		      \
+	       the intermediate result.  */				      \
+	    result = GCONV_INCOMPLETE_INPUT;				      \
+	    break;							      \
+	  }								      \
+									      \
+	ch2 = inptr[1];							      \
+	idx = ch * 256 + ch2;						      \
+	if (idx < 0x8140 || (idx > 0x84be && idx < 0x889f)		      \
+	    || (idx > 0x89fc && idx < 0x9040)				      \
+	    || (idx > 0x9ffc && idx < 0xe040) || idx > 0xeaa4)		      \
+	  {								      \
+	    /* This is illegal.  */					      \
+	    result = GCONV_ILLEGAL_INPUT;				      \
+	    break;							      \
+	  }								      \
+	else								      \
+	  {								      \
+	    /* We could pack the data a bit more dense.  The second	      \
+	       byte will never be 0x7f and it will also be never	      \
+	       >0xfc.  But this would mean yet more `if's.  */		      \
+	    if (idx <= 0x84be)						      \
+	      ch = cjk_block1[(ch - 0x81) * 192 + ch2 - 0x40];		      \
+	    else if (idx <= 0x89fc)					      \
+	      ch = cjk_block2[(ch - 0x88) * 192 + ch2 - 0x9f];		      \
+	    else if (idx <= 0x9ffc)					      \
+	      ch = cjk_block3[(ch - 0x90) * 192 + ch2 - 0x40];		      \
+	    else							      \
+	      ch = cjk_block4[(ch - 0xe0) * 192 + ch2 - 0x40];		      \
+	  }								      \
+									      \
+	if (ch == 0)							      \
+	  {								      \
+	    /* This is an illegal character.  */			      \
+	    result = GCONV_ILLEGAL_INPUT;				      \
+	    break;							      \
+	  }								      \
+      }									      \
+									      \
+    *((uint32_t *) outptr)++ = ch;					      \
+  }
+#include <iconv/loop.c>
 
-int
-gconv_init (struct gconv_step *step)
-{
-  /* Determine which direction.  */
-  if (strcasestr (step->from_name, "SJIS") != NULL)
-    step->data = &from_sjis_object;
-  else if (strcasestr (step->to_name, "SJIS") != NULL)
-    step->data = &to_sjis_object;
-  else
-    return GCONV_NOCONV;
-
-  return GCONV_OK;
-}
-
-
-void
-gconv_end (struct gconv_step *data)
-{
-  /* Nothing to do.  */
-}
-
-
-int
-gconv (struct gconv_step *step, struct gconv_step_data *data,
-       const char *inbuf, size_t *inbufsize, size_t *written, int do_flush)
-{
-  struct gconv_step *next_step = step + 1;
-  struct gconv_step_data *next_data = data + 1;
-  gconv_fct fct = next_step->fct;
-  size_t do_write;
-  int result;
-
-  /* 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 (do_flush)
-    {
-      do_write = 0;
-
-      /* Call the steps down the chain if there are any.  */
-      if (data->is_last)
-	result = GCONV_OK;
-      else
-	{
-	  result = (*fct) (next_step, next_data, NULL, 0, written, 1);
-
-	  /* Clear output buffer.  */
-	  data->outbufavail = 0;
-	}
-    }
-  else
-    {
-      do_write = 0;
-
-      do
-	{
-	  result = GCONV_OK;
-
-	  if (step->data == &from_sjis_object)
-	    {
-	      size_t inchars = *inbufsize;
-	      size_t outwchars = data->outbufavail;
-	      char *outbuf = data->outbuf;
-	      size_t cnt = 0;
-
-	      while (cnt < inchars
-		     && (outwchars + sizeof (wchar_t) <= data->outbufsize))
-		{
-		  int inchar = inbuf[cnt];
-		  wchar_t ch;
-
-		  if (inchar == 0x5c)
-		    ch = L'\xa5';
-		  else if (inchar == 0x7e)
-		    ch = 0x203e;
-		  else if (inchar < 0x7e)
-		    ch = (wchar_t) inchar;
-		  else if (inchar >= 0xa1 && inchar <= 0xdf)
-		    ch = halfkana_to_ucs4[inchar - 0xa1];
-		  else if (inchar > 0xea || inchar == 0xa0 || inchar == 0x7f
-			   || inchar == 0x80)
-		    /* These are illegal.  */
-		    ch = L'\0';
-		  else
-		    {
-		      /* Two-byte character.  First test whether the next
-			 character is also available.  */
-		      int inchar2;
-		      int idx;
-
-		      if (cnt + 1 >= inchars)
-			{
-			  /* The second character is not available.  Store
-			     the intermediate result.  */
-			  result = GCONV_INCOMPLETE_INPUT;
-			  break;
-			}
-
-		      inchar2 = inbuf[++cnt];
-		      idx = inchar * 256 + inchar2;
-		      if (idx < 0x8140 || (idx > 0x84be && idx < 0x889f)
-			  || (idx > 0x89fc && idx < 0x9040)
-			  || (idx > 0x9ffc && idx < 0xe040) || idx > 0xeaa4)
-			/* This is illegal.  */
-			ch = L'\0';
-		      else
-			{
-			  /* We could pack the data a bit more dense.
-			     The second byte will never be 0x7f and it
-			     will also be never >0xfc.  But this would
-			     mean yet more `if's.  */
-			  if (idx <= 0x84be)
-			    ch = cjk_block1[(inchar - 0x81) * 192
-					   + inchar2 - 0x40];
-			  else if (idx <= 0x89fc)
-			    ch = cjk_block2[(inchar - 0x88) * 192
-					   + inchar2 - 0x9f];
-			  else if (idx <= 0x9ffc)
-			    ch = cjk_block3[(inchar - 0x90) * 192
-					   + inchar2 - 0x40];
-			  else
-			    ch = cjk_block4[(inchar - 0xe0) * 192
-					   + inchar2 - 0x40];
-			}
-
-		      if (ch == L'\0')
-			--cnt;
-		    }
-
-		  if (ch == L'\0' && inbuf[cnt] != '\0')
-		    {
-		      /* This is an illegal character.  */
-		      result = GCONV_ILLEGAL_INPUT;
-		      break;
-		    }
-
-		  *((wchar_t *) (outbuf + outwchars)) = ch;
-		  ++do_write;
-		  outwchars += sizeof (wchar_t);
-		  ++cnt;
-		}
-	      *inbufsize -= cnt;
-	      inbuf += cnt;
-	      data->outbufavail = outwchars;
-	    }
-	  else
-	    {
-	      size_t inwchars = *inbufsize;
-	      size_t outchars = data->outbufavail;
-	      char *outbuf = data->outbuf;
-	      size_t cnt = 0;
-	      int extra = 0;
-
-	      while (inwchars >= cnt + sizeof (wchar_t)
-		     && outchars < data->outbufsize)
-		{
-		  int ch = *((wchar_t *) (inbuf + cnt));
-		  const char *cp;
-
-		  if (ch >= (sizeof (from_ucs4_lat1)
-			     / sizeof (from_ucs4_lat1[0])))
-		    {
-		      if (ch >= 0x0391 && ch <= 0x0451)
-			cp = from_ucs4_greek[ch - 0x391];
-		      else if (ch >= 0x2010 && ch <= 0x9fa0)
-			cp = from_ucs4_cjk[ch - 0x02010];
-		      else
-			/* Illegal character.  */
-			break;
-		    }
-		  else
-		    cp = from_ucs4_lat1[ch];
-
-		  if (cp[0] == '\0' && ch != 0)
-		    /* Illegal character.  */
-		    break;
-
-		  outbuf[outchars] = cp[0];
-		  /* Now test for a possible second byte and write this
-		     if possible.  */
-		  if (cp[1] != '\0')
-		    {
-		      if (outchars + 1 >= data->outbufsize)
-			{
-			  /* The result does not fit into the buffer.  */
-			  extra = 1;
-			  break;
-			}
-		      outbuf[++outchars] = cp[1];
-		    }
-
-		  ++do_write;
-		  ++outchars;
-		  cnt += sizeof (wchar_t);
-		}
-	      *inbufsize -= cnt;
-	      inbuf += cnt;
-	      data->outbufavail = outchars;
-
-	      if (outchars + extra < data->outbufsize)
-		{
-		  /* If there is still room in the output buffer something
-		     is wrong with the input.  */
-		  if (inwchars >= cnt + sizeof (wchar_t))
-		    {
-		      /* An error occurred.  */
-		      result = GCONV_ILLEGAL_INPUT;
-		      break;
-		    }
-		  if (inwchars != cnt)
-		    {
-		      /* There are some unprocessed bytes at the end of the
-			 input buffer.  */
-		      result = GCONV_INCOMPLETE_INPUT;
-		      break;
-		    }
-		}
-	    }
-
-	  if (result != GCONV_OK)
-	    break;
-
-	  if (data->is_last)
-	    {
-	      /* This is the last step.  */
-	      result = (*inbufsize > (step->data == &from_sjis_object
-				      ? 0 : sizeof (wchar_t) - 1)
-			? GCONV_FULL_OUTPUT : GCONV_EMPTY_INPUT);
-	      break;
-	    }
-
-	  /* Status so far.  */
-	  result = GCONV_EMPTY_INPUT;
-
-	  if (data->outbufavail > 0)
-	    {
-	      /* Call the functions below in the chain.  */
-	      size_t newavail = data->outbufavail;
-
-	      result = (*fct) (next_step, next_data, data->outbuf, &newavail,
-			       written, 0);
 
-	      /* Correct the output buffer.  */
-	      if (newavail != data->outbufavail && newavail > 0)
-		{
-		  memmove (data->outbuf,
-			   &data->outbuf[data->outbufavail - newavail],
-			   newavail);
-		  data->outbufavail = newavail;
-		}
-	    }
-	}
-      while (*inbufsize > 0 && result == GCONV_EMPTY_INPUT);
-    }
+/* Next, define the other direction.  */
+#define MIN_NEEDED_INPUT	MIN_NEEDED_TO
+#define MIN_NEEDED_OUTPUT	MIN_NEEDED_FROM
+#define MAX_NEEDED_OUTPUT	MAX_NEEDED_FROM
+#define LOOPFCT			TO_LOOP
+#define BODY \
+  {									      \
+    uint32_t ch = *((uint32_t *) inptr);				      \
+    const char *cp;							      \
+									      \
+    if (ch >= (sizeof (from_ucs4_lat1) / sizeof (from_ucs4_lat1[0])))	      \
+      {									      \
+	if (ch >= 0x0391 && ch <= 0x0451)				      \
+	  cp = from_ucs4_greek[ch - 0x391];				      \
+	else if (ch >= 0x2010 && ch <= 0x9fa0)				      \
+	  cp = from_ucs4_cjk[ch - 0x02010];				      \
+	else								      \
+	  {								      \
+	    /* Illegal character.  */					      \
+	    result = GCONV_ILLEGAL_INPUT;				      \
+	    break;							      \
+	  }								      \
+      }									      \
+    else								      \
+      cp = from_ucs4_lat1[ch];						      \
+									      \
+    if (cp[0] == '\0' && ch != 0)					      \
+      {									      \
+	/* Illegal character.  */					      \
+	result = GCONV_ILLEGAL_INPUT;					      \
+	break;								      \
+      }									      \
+									      \
+    *outptr++ = cp[0];							      \
+    /* Now test for a possible second byte and write this if possible.  */    \
+    if (cp[1] != '\0')							      \
+      {									      \
+	if (NEED_LENGTH_TEST && outptr >= outend)			      \
+	  {								      \
+	    /* The result does not fit into the buffer.  */		      \
+	    result = GCONV_FULL_OUTPUT;					      \
+	    break;							      \
+	  }								      \
+	*outptr++ = cp[1];						      \
+      }									      \
+									      \
+    inptr += 4;								      \
+  }
+#include <iconv/loop.c>
 
-  if (written != NULL && data->is_last)
-    *written = do_write;
 
-  return result;
-}
+/* Now define the toplevel functions.  */
+#include <iconv/skeleton.c>
diff --git a/iconvdata/t61.c b/iconvdata/t61.c
index b77ee71248..8c288adca2 100644
--- a/iconvdata/t61.c
+++ b/iconvdata/t61.c
@@ -19,6 +19,7 @@
    Boston, MA 02111-1307, USA.  */
 
 #include <gconv.h>
+#include <stdint.h>
 #include <string.h>
 
 /* Data taken from the WG15 tables.  */
@@ -362,248 +363,133 @@ static const char from_ucs4[][2] =
 */
 };
 
-/* Direction of the transformation.  */
-static int to_t61_object;
-static int from_t61_object;
 
+/* Definitions used in the body of the `gconv' function.  */
+#define CHARSET_NAME		"T.61"
+#define FROM_LOOP		from_t_61
+#define TO_LOOP			to_t_61
+#define DEFINE_INIT		1
+#define DEFINE_FINI		1
+#define MIN_NEEDED_FROM		1
+#define MAX_NEEDED_FROM		2
+#define MIN_NEEDED_TO		4
+
+/* First define the conversion function from T.61 to UCS4.  */
+#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 \
+  {									      \
+    uint32_t ch = *inptr;						      \
+									      \
+    if (ch >= 0xc1 && ch <= 0xcf)					      \
+      {									      \
+	/* Composed character.  First test whether the next character	      \
+	   is also available.  */					      \
+	uint32_t ch2;							      \
+									      \
+	if (NEED_LENGTH_TEST && inptr + 1 >= inend)			      \
+	  {								      \
+	    /* The second character is not available.  */		      \
+	    result = GCONV_INCOMPLETE_INPUT;				      \
+	    break;							      \
+	  }								      \
+									      \
+	ch2 = inptr[1];							      \
+									      \
+	if (ch2 < 0x20 || ch2 >= 0x80)					      \
+	  {								      \
+	    /* This is illegal.  */					      \
+	    result = GCONV_ILLEGAL_INPUT;				      \
+	    break;							      \
+	  }								      \
+									      \
+	ch = to_ucs4_comb[ch - 0xc1][ch2 - 0x20];			      \
+									      \
+	inptr += 2;							      \
+      }									      \
+    else								      \
+      {									      \
+	ch = to_ucs4[ch];						      \
+	++inptr;							      \
+      }									      \
+									      \
+    if (ch == 0 && *inptr != '\0')					      \
+      {									      \
+	/* This is an illegal character.  */				      \
+	result = GCONV_ILLEGAL_INPUT;					      \
+	break;								      \
+      }									      \
+									      \
+    *((uint32_t *) outptr)++ = ch;					      \
+  }
+#include <iconv/loop.c>
+
+
+/* Next, define the other direction.  */
+#define MIN_NEEDED_INPUT	MIN_NEEDED_TO
+#define MIN_NEEDED_OUTPUT	MIN_NEEDED_FROM
+#define MAX_NEEDED_OUTPUT	MAX_NEEDED_FROM
+#define LOOPFCT			TO_LOOP
+#define BODY \
+  {									      \
+    char tmp[2];							      \
+    uint32_t ch = *((uint32_t *) inptr);				      \
+    const char *cp;							      \
+									      \
+    if (ch >= sizeof (from_ucs4) / sizeof (from_ucs4[0]))		      \
+      {									      \
+	if (ch == 0x2126)						      \
+	  cp = "\xe0";							      \
+	else if (ch == 0x2c7)						      \
+	  cp = "\xcf\x20";						      \
+	else if (ch < 0x2d8 || ch > 0x2dd)				      \
+	  {								      \
+	    /* Illegal characters.  */					      \
+	    result = GCONV_ILLEGAL_INPUT;				      \
+	    break;							      \
+	  }								      \
+	else								      \
+	  {								      \
+	    static const char map[5] = "\xc6\xc7\xca\xce\xcd";		      \
+									      \
+	    tmp[0] = map[ch - 0x2d8];					      \
+	    tmp[1] = ' ';						      \
+	    cp = tmp;							      \
+	  }								      \
+      }									      \
+    else								      \
+      {									      \
+	cp = from_ucs4[ch];						      \
+									      \
+	if (cp[0] == '\0' && ch != 0)					      \
+	  {								      \
+	    /* Illegal.  */						      \
+	    result = GCONV_ILLEGAL_INPUT;				      \
+	    break;							      \
+	  }								      \
+      }									      \
+									      \
+    *outptr++ = cp[0];							      \
+    /* Now test for a possible second byte and write this if possible.  */    \
+    if (cp[1] != '\0')							      \
+      {									      \
+	if (NEED_LENGTH_TEST && outptr >= outend)			      \
+	  {								      \
+	    /* The result does not fit into the buffer.  */		      \
+	    --outptr;							      \
+	    result = GCONV_FULL_OUTPUT;					      \
+	    break;							      \
+	  }								      \
+									      \
+	*outptr++ = cp[1];						      \
+      }									      \
+									      \
+    inptr += 4;								      \
+  }
+#include <iconv/loop.c>
 
-int
-gconv_init (struct gconv_step *step)
-{
-  /* Determine which direction.  */
-  if (strcasestr (step->from_name, "T.61") != NULL)
-    step->data = &from_t61_object;
-  else if (strcasestr (step->to_name, "T.61") != NULL)
-    step->data = &to_t61_object;
-  else
-    return GCONV_NOCONV;
-
-  return GCONV_OK;
-}
-
-
-void
-gconv_end (struct gconv_step *data)
-{
-  /* Nothing to do.  */
-}
-
-
-int
-gconv (struct gconv_step *step, struct gconv_step_data *data,
-       const char *inbuf, size_t *inbufsize, size_t *written, int do_flush)
-{
-  struct gconv_step *next_step = step + 1;
-  struct gconv_step_data *next_data = data + 1;
-  gconv_fct fct = next_step->fct;
-  size_t do_write;
-  int result;
-
-  /* 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 (do_flush)
-    {
-      do_write = 0;
-
-      /* Call the steps down the chain if there are any.  */
-      if (data->is_last)
-	result = GCONV_OK;
-      else
-	{
-	  struct gconv_step *next_step = step + 1;
-	  struct gconv_step_data *next_data = data + 1;
-
-	  result = (*fct) (next_step, next_data, NULL, 0, written, 1);
-
-	  /* Clear output buffer.  */
-	  data->outbufavail = 0;
-	}
-    }
-  else
-    {
-      do_write = 0;
-
-      do
-	{
-	  result = GCONV_OK;
-
-	  if (step->data == &from_t61_object)
-	    {
-	      size_t inchars = *inbufsize;
-	      size_t outwchars = data->outbufavail;
-	      char *outbuf = data->outbuf;
-	      size_t cnt = 0;
-
-	      while (cnt < inchars
-		     && (outwchars + sizeof (wchar_t) <= data->outbufsize))
-		{
-		  int inchar = inbuf[cnt];
-		  wchar_t ch;
-
-		  if (inchar >= '\xc1' && inchar <= '\xcf')
-		    {
-		      /* Composed character.  First test whether the next
-			 character is also available.  */
-		      int inchar2;
-
-		      if (cnt + 1 >= inchars)
-			{
-			  /* The second character is not available.  Store
-			     the intermediate result.  */
-			  result = GCONV_INCOMPLETE_INPUT;
-			  break;
-			}
-
-		      inchar2 = inbuf[++cnt];
-
-		      if (inchar2 < '\x20' || inchar2 >= '\x80')
-			/* This is illegal.  */
-			ch = L'\0';
-		      else
-			ch = to_ucs4_comb[inchar - 0xc1][inchar2 - 0x20];
-
-		      if (ch == L'\0')
-			/* Undo the increment for illegal characters.  */
-			--cnt;
-		    }
-		  else
-		    ch = to_ucs4[inchar];
-
-		  if (ch == L'\0' && inbuf[cnt] != '\0')
-		    {
-		      /* This is an illegal character.  */
-		      result = GCONV_ILLEGAL_INPUT;
-		      break;
-		    }
-
-		  *((wchar_t *) (outbuf + outwchars)) = ch;
-		  ++do_write;
-		  outwchars += sizeof (wchar_t);
-		  ++cnt;
-		}
-	      *inbufsize -= cnt;
-	      inbuf += cnt;
-	      data->outbufavail = outwchars;
-	    }
-	  else
-	    {
-	      size_t inwchars = *inbufsize;
-	      size_t outchars = data->outbufavail;
-	      char *outbuf = data->outbuf;
-	      size_t cnt = 0;
-	      int extra = 0;
-
-	      while (inwchars >= cnt + sizeof (wchar_t)
-		     && outchars < data->outbufsize)
-		{
-		  char tmp[2];
-		  int ch = *((wchar_t *) (inbuf + cnt));
-		  const char *cp;
-
-		  if (ch >= sizeof (from_ucs4) / sizeof (from_ucs4[0]))
-		    {
-		      if (ch == 0x2126)
-			cp = "\xe0";
-		      else if (ch == 0x2c7)
-			cp = "\xcf\x20";
-		      else if (ch < 0x2d8 || ch > 0x2dd)
-			/* Illegal characters.  */
-			break;
-		      else
-			{
-			  static const char map[5] = "\xc6\xc7\xca\xce\xcd";
-
-			  tmp[0] = map[ch - 0x2d8];
-			  tmp[1] = ' ';
-			  cp = tmp;
-			}
-		    }
-		  else if (ch < 0 || (from_ucs4[ch][0] == '\0' && ch != 0))
-		    break;
-		  else
-		    cp = from_ucs4[ch];
-
-		  outbuf[outchars] = cp[0];
-		  /* Now test for a possible second byte and write this
-		     if possible.  */
-		  if (cp[1] != '\0')
-		    {
-		      if (outchars + 1 >= data->outbufsize)
-			{
-			  /* The result does not fit into the buffer.  */
-			  extra = 1;
-			  break;
-			}
-		      outbuf[++outchars] = cp[1];
-		    }
-
-		  ++do_write;
-		  ++outchars;
-		  cnt += sizeof (wchar_t);
-		}
-	      *inbufsize -= cnt;
-	      inbuf += cnt;
-	      data->outbufavail = outchars;
-
-	      if (outchars + extra < data->outbufsize)
-		{
-		  /* If there is still room in the output buffer something
-		     is wrong with the input.  */
-		  if (inwchars >= cnt + sizeof (wchar_t))
-		    {
-		      /* An error occurred.  */
-		      result = GCONV_ILLEGAL_INPUT;
-		      break;
-		    }
-		  if (inwchars != cnt)
-		    {
-		      /* There are some unprocessed bytes at the end of the
-			 input buffer.  */
-		      result = GCONV_INCOMPLETE_INPUT;
-		      break;
-		    }
-		}
-	    }
-
-	  if (result != GCONV_OK)
-	    break;
-
-	  if (data->is_last)
-	    {
-	      /* This is the last step.  */
-	      result = (*inbufsize > (step->data == &from_t61_object
-				      ? 0 : sizeof (wchar_t) - 1)
-			? GCONV_FULL_OUTPUT : GCONV_EMPTY_INPUT);
-	      break;
-	    }
-
-	  /* Status so far.  */
-	  result = GCONV_EMPTY_INPUT;
-
-	  if (data->outbufavail > 0)
-	    {
-	      /* Call the functions below in the chain.  */
-	      size_t newavail = data->outbufavail;
-
-	      result = (*fct) (next_step, next_data, data->outbuf, &newavail,
-			       written, 0);
-
-	      /* Correct the output buffer.  */
-	      if (newavail != data->outbufavail && newavail > 0)
-		{
-		  memmove (data->outbuf,
-			   &data->outbuf[data->outbufavail - newavail],
-			   newavail);
-		  data->outbufavail = newavail;
-		}
-	    }
-	}
-      while (*inbufsize > 0 && result == GCONV_EMPTY_INPUT);
-    }
-
-  if (written != NULL && data->is_last)
-    *written = do_write;
 
-  return result;
-}
+/* Now define the toplevel functions.  */
+#include <iconv/skeleton.c>
diff --git a/iconvdata/uhc.c b/iconvdata/uhc.c
index ed4b7adb70..f3addd4c4d 100644
--- a/iconvdata/uhc.c
+++ b/iconvdata/uhc.c
@@ -18,16 +18,9 @@
    write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
    Boston, MA 02111-1307, USA.  */
 
-#include <gconv.h>
 #include <stdint.h>
-#include <string.h>
-#include <wchar.h>
 #include <ksc5601.h>
 
-/* Direction of the transformation.  */
-static int to_uhc_object;
-static int from_uhc_object;
-
 
 /*
 egrep \
@@ -2576,20 +2569,20 @@ static const uint16_t uhc_hangul_from_ucs[11172]=
   0xc64f, 0xc650, 0xc651, 0xc652
 };
 
+
 static inline void
-uhc_from_ucs4(wchar_t ch, unsigned char *cp)
+uhc_from_ucs4 (uint32_t ch, unsigned char *cp)
 {
   if (ch >= 0x7f)
     {
       uint16_t idx=0;
 
       if (ch >= 0xac00 && ch <= 0xd7a3)
-	idx = uhc_hangul_from_ucs[(int) ch - 0xac00];
-      else if (ch >= 0x4e00 && ch <= 0x9fa5
-	       || ch >= 0xf900 && ch <= 0xfa0b)
+	idx = uhc_hangul_from_ucs[ch - 0xac00];
+      else if (ch >= 0x4e00 && ch <= 0x9fa5 || ch >= 0xf900 && ch <= 0xfa0b)
 	{
 	  ucs4_to_ksc5601_hanja (ch,&idx);
-	  idx |= (idx ?  0x8080 : 0);
+	  idx |= (idx ? 0x8080 : 0);
 	}
 /* Half-width Korean Currency Won Sign
       else if (ch == 0x20a9)
@@ -2598,286 +2591,169 @@ uhc_from_ucs4(wchar_t ch, unsigned char *cp)
       else
 	{
 	  ucs4_to_ksc5601_sym (ch, &idx);
-	  idx |= (idx ?  0x8080 : 0);
+	  idx |= (idx ? 0x8080 : 0);
 	}
 
-      *cp = (char) (idx / 256);
-      *(cp + 1) = (char) (idx & 0xff) ;
+      cp[0] = (unsigned char) (idx / 256);
+      cp[1] = (unsigned char) (idx & 0xff);
     }
-  /* think about 0x5c ; '\' */
+  /* XXX Think about 0x5c ; '\'.  */
   else
     {
-      *cp = (char) (0x7f & ch) ;
-      *(cp + 1) = (char) 0;
+      cp[0] = (unsigned char) ch;
+      cp[1] = (unsigned char) 0;
     }
 }
 
 
-int
-gconv_init (struct gconv_step *step)
-{
-  /* Determine which direction.  */
-  if (strcasestr (step->from_name, "UHC") != NULL)
-    step->data = &from_uhc_object;
-  else if (strcasestr (step->to_name, "UHC") != NULL)
-    step->data = &to_uhc_object;
-  else
-    return GCONV_NOCONV;
-
-  return GCONV_OK;
-}
-
-
-void
-gconv_end (struct gconv_step *data)
-{
-  /* Nothing to do.  */
-}
-
-
-int
-gconv (struct gconv_step *step, struct gconv_step_data *data,
-       const char *inbuf, size_t *inbufsize, size_t *written, int do_flush)
-{
-  struct gconv_step *next_step = step + 1;
-  struct gconv_step_data *next_data = data + 1;
-  gconv_fct fct = next_step->fct;
-  size_t do_write;
-  int result;
-
-  /* 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 (do_flush)
-    {
-      do_write = 0;
-
-      /* Call the steps down the chain if there are any.  */
-      if (data->is_last)
-	result = GCONV_OK;
-      else
-	{
-	  struct gconv_step *next_step = step + 1;
-	  struct gconv_step_data *next_data = data + 1;
-
-	  result = (*fct) (next_step, next_data, NULL, 0, written, 1);
-
-	  /* Clear output buffer.  */
-	  data->outbufavail = 0;
-	}
-    }
-  else
-    {
-      do_write = 0;
-
-      do
-	{
-	  result = GCONV_OK;
-
-	  if (step->data == &from_uhc_object)
-	    {
-	      size_t inchars = *inbufsize;
-	      size_t outwchars = data->outbufavail;
-	      char *outbuf = data->outbuf;
-	      size_t cnt = 0;
-
-	      while (cnt < inchars
-		     && (outwchars + sizeof (wchar_t) <= data->outbufsize))
-		{
-		  int inchar = (unsigned char) inbuf[cnt];
-		  wchar_t ch;
-/* half-width Korean Currency WON sign
-
-		  if (inchar == 0x5c)
-		    ch =  0x20a9;
-		  else if (inchar <= 0x7f)
-		    ch = (wchar_t) inchar;
-*/
-		  if (inchar <= 0x7f)
-		    ch = (wchar_t) inchar;
-
-
-                  else if ( inchar <= 0x80 || inchar >= 0xfe || inchar == 0xc9)
-                      /* This is illegal.  */
-                      ch = L'\0';
-		  else
-		    {
-		      /* Two-byte character.  First test whether the next
-			 character is also available.  */
-		      int inchar2;
-
-		      if (cnt + 1 >= inchars)
-			{
-			  /* The second character is not available.  Store
-			     the intermediate result.  */
-			  result = GCONV_INCOMPLETE_INPUT;
-			  break;
-			}
-
-		      inchar2 = (unsigned char) inbuf[++cnt];
-
-/*
-  Additional code points not present in EUC-KR
-
-         1st byte             2nd byte
-     0x81-0xa0            0x41-0x5a, 0x61-0x7a, 0x81-0xfe         total
-      (32)                 (26)   +    (26)   +    (126) = 178     5696
-
-     0xa1-0xc5            0x41-0x5a  0x61-0x7a  0x81-0xa0
-      (37)                  (26)  +   (26)    +    (32) =  84      3108
-
-     0xc6                 0x41-0x52
-      (1)                    (18)                                   18
-
-                                                                    8822
-
-
-  8822(only in UHC) + 2350(both in EUC-KR and UHC) =  11,172
-*/
-
-                      if ( inchar < 0xa1 || inchar2 < 0xa1)
-                           if ( inchar > 0xc6 || inchar2 <0x41 ||
-                                inchar2 > 0x5a && inchar2 < 0x61 ||
-                                inchar2 > 0x7a && inchar2 < 0x81 ||
-                                inchar == 0xc6 && inchar2 >  0x52 )
-                              ch = L'0';
-                           else
-                             {
-                               ch = uhc_extra_to_ucs[ inchar2 - 0x41
-                                    -  ( inchar2 > 0x80 ? 12 :
-                                       ( inchar2 > 0x60 ?  6 :  0 ) )
-                                    +  ( inchar < 0xa1  ?
-                                         (inchar - 0x81) * 178  :
-                                         5696 + (inchar - 0xa1) * 84 ) ] ;
-                             }
-
-                      else
-		         if ( ( ch = ksc5601_to_ucs4(
-                              (uint16_t) (inchar * 256 + inchar2) & 0x7f7f) )
-                             == UNKNOWN_10646_CHAR )
-
-                               ch = L'\0';
-
-		      if (ch == L'\0')
-			--cnt;
-		    }
-
-		  if (ch == L'\0' && inbuf[cnt] != '\0')
-		    {
-		      /* This is an illegal character.  */
-		      result = GCONV_ILLEGAL_INPUT;
-		      break;
-		    }
-
-		  *((wchar_t *) (outbuf + outwchars)) = ch;
-		  ++do_write;
-		  outwchars += sizeof (wchar_t);
-		  ++cnt;
-		}
-	      *inbufsize -= cnt;
-	      inbuf += cnt;
-	      data->outbufavail = outwchars;
-	    }
-	  else
-	    {
-	      size_t inwchars = *inbufsize;
-	      size_t outchars = data->outbufavail;
-	      char *outbuf = data->outbuf;
-	      size_t cnt = 0;
-	      int extra = 0;
-
-	      while (inwchars >= cnt + sizeof (wchar_t)
-		     && outchars < data->outbufsize)
-		{
-		  wchar_t ch = *((wchar_t *) (inbuf + cnt));
-		  unsigned char cp[2];
-
-                  uhc_from_ucs4(ch,cp) ;
-
-		  if (cp[0] == '\0' && ch != 0)
-		    /* Illegal character.  */
-		    break;
-
-		  outbuf[outchars] = cp[0];
-		  /* Now test for a possible second byte and write this
-		     if possible.  */
-		  if (cp[1] != '\0')
-		    {
-		      if (outchars + 1 >= data->outbufsize)
-			{
-			  /* The result does not fit into the buffer.  */
-			  extra = 1;
-			  break;
-			}
-		      outbuf[++outchars] = cp[1];
-		    }
-
-		  ++do_write;
-		  ++outchars;
-		  cnt += sizeof (wchar_t);
-		}
-	      *inbufsize -= cnt;
-	      inbuf += cnt;
-	      data->outbufavail = outchars;
-
-	      if (outchars + extra < data->outbufsize)
-		{
-		  /* If there is still room in the output buffer something
-		     is wrong with the input.  */
-		  if (inwchars >= cnt + sizeof (wchar_t))
-		    {
-		      /* An error occurred.  */
-		      result = GCONV_ILLEGAL_INPUT;
-		      break;
-		    }
-		  if (inwchars != cnt)
-		    {
-		      /* There are some unprocessed bytes at the end of the
-			 input buffer.  */
-		      result = GCONV_INCOMPLETE_INPUT;
-		      break;
-		    }
-		}
-	    }
-
-	  if (result != GCONV_OK)
-	    break;
-
-	  if (data->is_last)
-	    {
-	      /* This is the last step.  */
-	      result = (*inbufsize > (step->data == &from_uhc_object
-				      ? 0 : sizeof (wchar_t) - 1)
-			? GCONV_FULL_OUTPUT : GCONV_EMPTY_INPUT);
-	      break;
-	    }
-
-	  /* Status so far.  */
-	  result = GCONV_EMPTY_INPUT;
-
-	  if (data->outbufavail > 0)
-	    {
-	      /* Call the functions below in the chain.  */
-	      size_t newavail = data->outbufavail;
-
-	      result = (*fct) (next_step, next_data, data->outbuf, &newavail,
-			       written, 0);
-
-	      /* Correct the output buffer.  */
-	      if (newavail != data->outbufavail && newavail > 0)
-		{
-		  memmove (data->outbuf,
-			   &data->outbuf[data->outbufavail - newavail],
-			   newavail);
-		  data->outbufavail = newavail;
-		}
-	    }
-	}
-      while (*inbufsize > 0 && result == GCONV_EMPTY_INPUT);
-    }
-
-  if (written != NULL && data->is_last)
-    *written = do_write;
-
-  return result;
-}
+/* Definitions used in the body of the `gconv' function.  */
+#define CHARSET_NAME		"UHC"
+#define FROM_LOOP		from_uhc
+#define TO_LOOP			to_uhc
+#define DEFINE_INIT		1
+#define DEFINE_FINI		1
+#define MIN_NEEDED_FROM		1
+#define MAX_NEEDED_FROM		2
+#define MIN_NEEDED_TO		4
+
+/* First define the conversion function from UHC to UCS4.  */
+#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 \
+  {									      \
+    uint32_t ch = (uint32_t) *inptr;					      \
+									      \
+/* half-width Korean Currency WON sign					      \
+									      \
+    if (ch == 0x5c)							      \
+      ch =  0x20a9;							      \
+    else if (ch <= 0x7f)						      \
+      ch = (wchar_t) ch;						      \
+*/									      \
+    if (ch <= 0x7f)							      \
+      ++inptr;								      \
+    else if (ch <= 0x80 || ch >= 0xfe || ch == 0xc9)			      \
+      {									      \
+	/* This is illegal.  */						      \
+	result = GCONV_ILLEGAL_INPUT;					      \
+	break;								      \
+      }									      \
+    else								      \
+      {									      \
+	/* Two-byte character.  First test whether the next character	      \
+	   is also available.  */					      \
+	uint32_t ch2;							      \
+									      \
+	if (NEED_LENGTH_TEST && inptr + 1 >= inend)			      \
+	  {								      \
+	    /* The second character is not available.  Store		      \
+	       the intermediate result.  */				      \
+	    result = GCONV_INCOMPLETE_INPUT;				      \
+	    break;							      \
+	  }								      \
+									      \
+	ch2 = inptr[1];							      \
+									      \
+/*									      \
+  Additional code points not present in EUC-KR				      \
+									      \
+         1st byte             2nd byte					      \
+     0x81-0xa0            0x41-0x5a, 0x61-0x7a, 0x81-0xfe         total	      \
+      (32)                 (26)   +    (26)   +    (126) = 178     5696	      \
+									      \
+     0xa1-0xc5            0x41-0x5a  0x61-0x7a  0x81-0xa0		      \
+      (37)                  (26)  +   (26)    +    (32) =  84      3108	      \
+									      \
+     0xc6                 0x41-0x52					      \
+      (1)                    (18)                                   18	      \
+									      \
+                                                                    8822      \
+									      \
+  8822(only in UHC) + 2350(both in EUC-KR and UHC) =  11,172		      \
+*/									      \
+									      \
+	if (ch < 0xa1 || ch2 < 0xa1)					      \
+	  {								      \
+	    if (ch > 0xc6 || ch2 <0x41 || (ch2 > 0x5a && ch2 < 0x61)	      \
+		|| (ch2 > 0x7a && ch2 < 0x81) || (ch == 0xc6 && ch2 > 0x52))  \
+	      {								      \
+		/* This is not legal.  */				      \
+		result = GCONV_ILLEGAL_INPUT;				      \
+		break;							      \
+	      }								      \
+									      \
+	    ch = uhc_extra_to_ucs[ch2 - 0x41				      \
+				 - (ch2 > 0x80 ? 12 : (ch2 > 0x60 ? 6 : 0))   \
+				 +  (ch < 0xa1				      \
+				     ? (ch - 0x81) * 178		      \
+				     : 5696 + (ch - 0xa1) * 84)];	      \
+	  }								      \
+	else								      \
+	  {								      \
+	    ch = ksc5601_to_ucs4 ((ch * 256 + ch2) & 0x7f7f);		      \
+									      \
+	    if (ch == UNKNOWN_10646_CHAR)				      \
+	      {								      \
+		/* Illegal.  */						      \
+		result = GCONV_ILLEGAL_INPUT;				      \
+		break;							      \
+	      }								      \
+	  }								      \
+									      \
+	if (ch == 0)							      \
+	  {								      \
+	    /* This is an illegal character.  */			      \
+	    result = GCONV_ILLEGAL_INPUT;				      \
+	    break;							      \
+	  }								      \
+									      \
+	inptr += 2;							      \
+      }									      \
+									      \
+    *((uint32_t *) outptr)++ = ch;					      \
+  }
+#include <iconv/loop.c>
+
+
+/* Next, define the other direction.  */
+#define MIN_NEEDED_INPUT	MIN_NEEDED_TO
+#define MIN_NEEDED_OUTPUT	MIN_NEEDED_FROM
+#define MAX_NEEDED_OUTPUT	MAX_NEEDED_FROM
+#define LOOPFCT			TO_LOOP
+#define BODY \
+  {									      \
+    uint32_t ch = *((uint32_t *) inptr);				      \
+    unsigned char cp[2];						      \
+									      \
+    uhc_from_ucs4 (ch, cp);						      \
+									      \
+    if (cp[0] == '\0' && ch != 0)					      \
+      {									      \
+	/* Illegal character.  */					      \
+	result = GCONV_ILLEGAL_INPUT;					      \
+	break;								      \
+      }									      \
+									      \
+    *outptr++ = cp[0];							      \
+    /* Now test for a possible second byte and write this if possible.  */    \
+    if (cp[1] != '\0')							      \
+      {									      \
+	if (NEED_LENGTH_TEST && outptr >= outend)			      \
+	  {								      \
+	    /* The result does not fit into the buffer.  */		      \
+	    result = GCONV_FULL_OUTPUT;					      \
+	    break;							      \
+	  }								      \
+									      \
+	*outptr++ = cp[1];						      \
+      }									      \
+									      \
+    inptr += 4;								      \
+  }
+#include <iconv/loop.c>
+
+
+/* Now define the toplevel functions.  */
+#include <iconv/skeleton.c>
diff --git a/inet/netinet/in.h b/inet/netinet/in.h
index ff8476e5c7..c6985ffa0a 100644
--- a/inet/netinet/in.h
+++ b/inet/netinet/in.h
@@ -277,6 +277,22 @@ extern uint16_t htons __P ((uint16_t __hostshort));
 extern int bindresvport __P ((int __sockfd, struct sockaddr_in *__sock_in));
 
 
+
+#define IN6_IS_ADDR_MC_NODELOCAL(a) \
+	(IN6_IS_ADDR_MULTICAST(a) && ((((u_int8_t *) (a))[1] & 0xf) == 0x1))
+
+#define IN6_IS_ADDR_MC_LINKLOCAL(a) \
+	(IN6_IS_ADDR_MULTICAST(a) && ((((u_int8_t *) (a))[1] & 0xf) == 0x2))
+
+#define IN6_IS_ADDR_MC_SITELOCAL(a) \
+	(IN6_IS_ADDR_MULTICAST(a) && ((((u_int8_t *) (a))[1] & 0xf) == 0x5))
+
+#define IN6_IS_ADDR_MC_ORGLOCAL(a) \
+	(IN6_IS_ADDR_MULTICAST(a) && ((((u_int8_t *) (a))[1] & 0xf) == 0x8))
+
+#define IN6_IS_ADDR_MC_GLOBAL(a) \
+	(IN6_IS_ADDR_MULTICAST(a) && ((((u_int8_t *) (a))[1] & 0xf) == 0xe))
+
 /* IPv6 packet information.  */
 struct in6_pktinfo
   {
diff --git a/libc.map b/libc.map
index 6a40713d81..bc3c28660e 100644
--- a/libc.map
+++ b/libc.map
@@ -100,11 +100,12 @@ GLIBC_2.0 {
     __vsscanf; __vfscanf; __vsnprintf;
     _rpc_dtablesize; _null_auth; _seterr_reply;
     __res_randomid;  __getpid;
-    __strcasecmp; __write; _strerror_internal; _dl_sysdep_output;
+    __strcasecmp; __strerror_r; __write; _dl_sysdep_output;
     _dl_debug_message;
     __ffs;
     __close; __connect; __fcntl; __lseek; __open; __read; __send; __wait;
     __ieee_get_fp_control; __ieee_set_fp_control;
+    __dgettext;
 
     # Exception handling support functions from libgcc
     __register_frame; __register_frame_table; __deregister_frame;
@@ -440,13 +441,14 @@ GLIBC_2.1 {
     __signbit; __signbitf; __signbitl; __libc_sa_len;
 
     # functions used in other libraries
-    _IO_fclose; _IO_fopen; _IO_fdopen; __asprintf;
+    _IO_fclose; _IO_fopen; _IO_fdopen; __asprintf; __strcasestr;
     __syscall_rt_sigqueueinfo;
     __xstat64; __fxstat64; __lxstat64;
     __pread64; __pwrite64;
 
     # helper functions
     __libc_current_sigrtmin; __libc_current_sigrtmax; __libc_allocate_rtsig;
+    __libc_longjmp; __libc_siglongjmp;
 
     # Since we have new signals this structure changed.
     _sys_siglist; sys_siglist; sys_sigabbrev;
diff --git a/libio/fileops.c b/libio/fileops.c
index 7e60f7c8df..e5ffb245aa 100644
--- a/libio/fileops.c
+++ b/libio/fileops.c
@@ -48,7 +48,6 @@ extern int errno;
 # define lseek(FD, Offset, Whence) __lseek (FD, Offset, Whence)
 # define read(FD, Buf, NBytes) __read (FD, Buf, NBytes)
 # define write(FD, Buf, NBytes) __write (FD, Buf, NBytes)
-# define fstat(FD, Buf) __fxstat (_STAT_VER, FD, Buf)
 #endif
 
 /* An fstream can be in at most one of put mode, get mode, or putback mode.
diff --git a/libio/oldfileops.c b/libio/oldfileops.c
index 41fbc692e8..7cf4fdf22c 100644
--- a/libio/oldfileops.c
+++ b/libio/oldfileops.c
@@ -483,7 +483,7 @@ _IO_old_file_seekoff (fp, offset, dir, mode)
       break;
     case _IO_seek_end:
       {
-	struct stat st;
+	struct _G_stat64 st;
 	if (_IO_SYSSTAT (fp, &st) == 0 && S_ISREG (st.st_mode))
 	  {
 	    offset += st.st_size;
diff --git a/linuxthreads/ChangeLog b/linuxthreads/ChangeLog
index 7913e085f1..ba2a20f4d0 100644
--- a/linuxthreads/ChangeLog
+++ b/linuxthreads/ChangeLog
@@ -1,3 +1,14 @@
+1998-04-20 14:55  Ulrich Drepper  <drepper@cygnus.com>
+
+	* Makefile (libpthread-routines): Add ptlongjmp and spinlock.
+	* internals.h: Add definitions for new spinlock implementation.
+	* ptlongjmp.c: New file.
+	* spinlock.c: New file.
+	* spinlock.h (acquire): Don't reschedule using __sched_yield, use
+	new function __pthread_acquire to prevent deadlocks with thread
+	with different priorities.
+	Patches by Xavier Leroy <Xavier.Leroy@inria.fr>.
+
 1998-03-16  Andreas Schwab  <schwab@issan.informatik.uni-dortmund.de>
 
 	* manager.c (__pthread_manager): Reduce first argument to select
diff --git a/linuxthreads/Makefile b/linuxthreads/Makefile
index 8813ae110f..cdfe06c66e 100644
--- a/linuxthreads/Makefile
+++ b/linuxthreads/Makefile
@@ -32,8 +32,8 @@ extra-libs := libpthread
 extra-libs-others := $(extra-libs)
 
 libpthread-routines := attr cancel condvar join manager mutex ptfork \
-		       pthread signals specific errno lockfile \
-		       semaphore wrapsyscall rwlock
+		       ptlongjmp pthread signals specific errno lockfile \
+		       semaphore spinlock wrapsyscall rwlock
 libpthread-map	:= libpthread.map
 
 include ../Rules
diff --git a/linuxthreads/internals.h b/linuxthreads/internals.h
index 0649e0d460..c56829684e 100644
--- a/linuxthreads/internals.h
+++ b/linuxthreads/internals.h
@@ -250,6 +250,23 @@ static inline pthread_descr thread_self (void)
 #endif
 }
 
+/* Max number of times we must spin on a spinlock calling sched_yield().
+   After MAX_SPIN_COUNT iterations, we put the calling thread to sleep. */
+
+#ifndef MAX_SPIN_COUNT
+#define MAX_SPIN_COUNT 50
+#endif
+
+/* Duration of sleep (in nanoseconds) when we can't acquire a spinlock
+   after MAX_SPIN_COUNT iterations of sched_yield().
+   With the 2.0 and 2.1 kernels, this MUST BE > 2ms.
+   (Otherwise the kernel does busy-waiting for realtime threads,
+    giving other threads no chance to run.) */
+
+#ifndef SPIN_SLEEP_DURATION
+#define SPIN_SLEEP_DURATION 2000001
+#endif
+
 /* Debugging */
 
 #ifdef DEBUG
diff --git a/linuxthreads/ptlongjmp.c b/linuxthreads/ptlongjmp.c
new file mode 100644
index 0000000000..1397dba43a
--- /dev/null
+++ b/linuxthreads/ptlongjmp.c
@@ -0,0 +1,44 @@
+/* Linuxthreads - a simple clone()-based implementation of Posix        */
+/* threads for Linux.                                                   */
+/* Copyright (C) 1998 Xavier Leroy (Xavier.Leroy@inria.fr)              */
+/*                                                                      */
+/* This program is free software; you can redistribute it and/or        */
+/* modify it under the terms of the GNU Library General Public License  */
+/* as published by the Free Software Foundation; either version 2       */
+/* of the License, or (at your option) any later version.               */
+/*                                                                      */
+/* 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 Library General Public License for more details.                 */
+
+/* Redefine siglongjmp and longjmp so that they interact correctly
+   with cleanup handlers */
+
+#include <setjmp.h>
+#include "pthread.h"
+#include "internals.h"
+
+static void pthread_cleanup_upto(__jmp_buf target)
+{
+  pthread_descr self = thread_self();
+  struct _pthread_cleanup_buffer * c;
+
+  for (c = self->p_cleanup;
+       c != NULL && _JMPBUF_UNWINDS(target, c);
+       c = c->prev)
+    c->routine(c->arg);
+  self->p_cleanup = c;
+}
+
+void siglongjmp(sigjmp_buf env, int val)
+{
+  pthread_cleanup_upto(env->__jmpbuf);
+  __libc_siglongjmp(env, val);
+}
+
+void longjmp(jmp_buf env, int val)
+{
+  pthread_cleanup_upto(env->__jmpbuf);
+  __libc_longjmp(env, val);
+}
diff --git a/linuxthreads/spinlock.c b/linuxthreads/spinlock.c
new file mode 100644
index 0000000000..170d9ae8d0
--- /dev/null
+++ b/linuxthreads/spinlock.c
@@ -0,0 +1,59 @@
+/* Linuxthreads - a simple clone()-based implementation of Posix        */
+/* threads for Linux.                                                   */
+/* Copyright (C) 1998 Xavier Leroy (Xavier.Leroy@inria.fr)              */
+/*                                                                      */
+/* This program is free software; you can redistribute it and/or        */
+/* modify it under the terms of the GNU Library General Public License  */
+/* as published by the Free Software Foundation; either version 2       */
+/* of the License, or (at your option) any later version.               */
+/*                                                                      */
+/* 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 Library General Public License for more details.                 */
+
+/* Spin locks */
+
+#include <sched.h>
+#include <time.h>
+#include "pthread.h"
+#include "internals.h"
+#include "spinlock.h"
+
+/* This function is called if the inlined test-and-set in acquire() failed */
+
+/* The retry strategy is as follows:
+   - We test and set the spinlock MAX_SPIN_COUNT times, calling
+     sched_yield() each time.  This gives ample opportunity for other
+     threads with priority >= our priority to make progress and
+     release the spinlock.
+   - If a thread with priority < our priority owns the spinlock,
+     calling sched_yield() repeatedly is useless, since we're preventing
+     the owning thread from making progress and releasing the spinlock.
+     So, after MAX_SPIN_LOCK attemps, we suspend the calling thread
+     using nanosleep().  This again should give time to the owning thread
+     for releasing the spinlock.
+     Notice that the nanosleep() interval must not be too small,
+     since the kernel does busy-waiting for short intervals in a realtime
+     process (!).  The smallest duration that guarantees thread
+     suspension is currently 2ms.
+   - When nanosleep() returns, we try again, doing MAX_SPIN_COUNT
+     sched_yield(), then sleeping again if needed. */
+
+void __pthread_acquire(int * spinlock)
+{
+  int cnt = 0;
+  struct timespec tm;
+
+  while (testandset(spinlock)) {
+    if (cnt < MAX_SPIN_COUNT) {
+      sched_yield();
+      cnt++;
+    } else {
+      tm.tv_sec = 0;
+      tm.tv_nsec = SPIN_SLEEP_DURATION;
+      nanosleep(&tm, NULL);
+      cnt = 0;
+    }
+  }
+}
diff --git a/linuxthreads/spinlock.h b/linuxthreads/spinlock.h
index d324abbc84..1707d3e42a 100644
--- a/linuxthreads/spinlock.h
+++ b/linuxthreads/spinlock.h
@@ -15,9 +15,11 @@
 
 /* Spin locks */
 
+extern void __pthread_acquire(int * spinlock);
+
 static inline void acquire(int * spinlock)
 {
-  while (testandset(spinlock)) __sched_yield();
+  if (testandset(spinlock)) __pthread_acquire(spinlock);
 }
 
 static inline void release(int * spinlock)
diff --git a/login/Makefile b/login/Makefile
index 5f7861b61c..96c75f7b4a 100644
--- a/login/Makefile
+++ b/login/Makefile
@@ -22,7 +22,7 @@
 
 subdir	:= login
 
-headers	:= utmp.h bits/utmp.h utmpx.h bits/utmpx.h lastlog.h pty.h
+headers	:= utmp.h bits/utmp.h lastlog.h pty.h
 
 routines := getutent getutent_r getutid getutline getutid_r getutline_r \
 	    utmp_file utmp_daemon utmpname updwtmp \
diff --git a/login/getutent.c b/login/getutent.c
index eb99158592..51e147586e 100644
--- a/login/getutent.c
+++ b/login/getutent.c
@@ -1,4 +1,4 @@
-/* Copyright (C) 1996, 1997 Free Software Foundation, Inc.
+/* Copyright (C) 1996, 1997, 1998 Free Software Foundation, Inc.
    This file is part of the GNU C Library.
    Contributed by Ulrich Drepper <drepper@cygnus.com>, 1996.
 
@@ -35,4 +35,3 @@ __getutent (void)
   return result;
 }
 weak_alias (__getutent, getutent)
-weak_alias (__getutent, getutxent)
diff --git a/login/getutent_r.c b/login/getutent_r.c
index 96c458f3a3..8391331cd5 100644
--- a/login/getutent_r.c
+++ b/login/getutent_r.c
@@ -1,4 +1,4 @@
-/* Copyright (C) 1996, 1997 Free Software Foundation, Inc.
+/* Copyright (C) 1996, 1997, 1998 Free Software Foundation, Inc.
    This file is part of the GNU C Library.
    Contributed by Ulrich Drepper <drepper@cygnus.com>
    and Paul Janzen <pcj@primenet.com>, 1996.
@@ -143,7 +143,6 @@ __setutent (void)
   __libc_lock_unlock (__libc_utmp_lock);
 }
 weak_alias (__setutent, setutent)
-weak_alias (__setutent, setutxent)
 
 
 int
@@ -176,7 +175,6 @@ __pututline (const struct utmp *data)
   return buffer;
 }
 weak_alias (__pututline, pututline)
-weak_alias (__pututline, pututxline)
 
 
 void
@@ -190,4 +188,3 @@ __endutent (void)
   __libc_lock_unlock (__libc_utmp_lock);
 }
 weak_alias (__endutent, endutent)
-weak_alias (__endutent, endutxent)
diff --git a/login/getutid.c b/login/getutid.c
index 98e8e4adc3..91e3ea20ac 100644
--- a/login/getutid.c
+++ b/login/getutid.c
@@ -1,4 +1,4 @@
-/* Copyright (C) 1996, 1997 Free Software Foundation, Inc.
+/* Copyright (C) 1996, 1997, 1998 Free Software Foundation, Inc.
    This file is part of the GNU C Library.
    Contributed by Ulrich Drepper <drepper@cygnus.com>, 1996.
 
@@ -35,4 +35,3 @@ __getutid (const struct utmp *id)
   return result;
 }
 weak_alias (__getutid, getutid)
-weak_alias (__getutid, getutxid)
diff --git a/login/getutline.c b/login/getutline.c
index 1e1ecb1ce3..7fc402ffdd 100644
--- a/login/getutline.c
+++ b/login/getutline.c
@@ -1,4 +1,4 @@
-/* Copyright (C) 1996, 1997 Free Software Foundation, Inc.
+/* Copyright (C) 1996, 1997, 1998 Free Software Foundation, Inc.
    This file is part of the GNU C Library.
    Contributed by Ulrich Drepper <drepper@cygnus.com>, 1996.
 
@@ -35,4 +35,3 @@ __getutline (const struct utmp *line)
   return result;
 }
 weak_alias (__getutline, getutline)
-weak_alias (__getutline, getutxline)
diff --git a/login/utmp.h b/login/utmp.h
index 82f3fcce9a..ccf29b27ad 100644
--- a/login/utmp.h
+++ b/login/utmp.h
@@ -1,4 +1,4 @@
-/* Copyright (C) 1993, 1996, 1997 Free Software Foundation, Inc.
+/* Copyright (C) 1993, 1996, 1997, 1998 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
@@ -53,6 +53,8 @@ extern void logwtmp __P ((__const char *__ut_line, __const char *__ut_name,
 			  __const char *__ut_host));
 
 /* Append entry UTMP to the wtmp-like file WTMP_FILE.  */
+extern void __updwtmp __P ((__const char *__wtmp_file,
+			    __const struct utmp *__utmp));
 extern void updwtmp __P ((__const char *__wtmp_file,
 			  __const struct utmp *__utmp));
 
@@ -61,6 +63,7 @@ extern int __utmpname __P ((__const char *__file));
 extern int utmpname __P ((__const char *__file));
 
 /* Read next entry from a utmp-like file.  */
+extern struct utmp *__getutent __P ((void));
 extern struct utmp *getutent __P ((void));
 
 /* Reset the input stream to the beginning of the file.  */
@@ -73,13 +76,16 @@ extern void endutent __P ((void));
 
 /* Search forward from the current point in the utmp file until the
    next entry with a ut_type matching ID->ut_type.  */
+extern struct utmp *__getutid __P ((__const struct utmp *__id));
 extern struct utmp *getutid __P ((__const struct utmp *__id));
 
 /* Search forward from the current point in the utmp file until the
    next entry with a ut_line matching LINE->ut_line.  */
+extern struct utmp *__getutline __P ((__const struct utmp *__line));
 extern struct utmp *getutline __P ((__const struct utmp *__line));
 
 /* Write out entry pointed to by UTMP_PTR into the utmp file.  */
+extern struct utmp *__pututline __P ((__const struct utmp *__utmp_ptr));
 extern struct utmp *pututline __P ((__const struct utmp *__utmp_ptr));
 
 
diff --git a/manual/creature.texi b/manual/creature.texi
index 66e53aceb4..00e3aada90 100644
--- a/manual/creature.texi
+++ b/manual/creature.texi
@@ -151,7 +151,7 @@ not generally used (see @code{_FILE_OFFSET_BITS}.
 
 @comment (NONE)
 @comment X/Open
-@defvr _FILE_OFFSET_BITS
+@defvr Macro _FILE_OFFSET_BITS
 This macro lets decide which file system interface shall be used, one
 replacing the other.  While @code{_LARGEFILE64_SOURCE} makes the @w{64
 bit} interface available as an additional interface
diff --git a/posix/getopt.c b/posix/getopt.c
index 7afe6c4a96..4cbf3614cc 100644
--- a/posix/getopt.c
+++ b/posix/getopt.c
@@ -24,19 +24,19 @@
 /* This tells Alpha OSF/1 not to define a getopt prototype in <stdio.h>.
    Ditto for AIX 3.2 and <stdlib.h>.  */
 #ifndef _NO_PROTO
-#define _NO_PROTO
+# define _NO_PROTO
 #endif
 
 #ifdef HAVE_CONFIG_H
-#include <config.h>
+# include <config.h>
 #endif
 
 #if !defined __STDC__ || !__STDC__
 /* This is a separate conditional since some stdc systems
    reject `defined (const)'.  */
-#ifndef const
-#define const
-#endif
+# ifndef const
+#  define const
+# endif
 #endif
 
 #include <stdio.h>
@@ -51,10 +51,10 @@
 
 #define GETOPT_INTERFACE_VERSION 2
 #if !defined _LIBC && defined __GLIBC__ && __GLIBC__ >= 2
-#include <gnu-versions.h>
-#if _GNU_GETOPT_INTERFACE_VERSION == GETOPT_INTERFACE_VERSION
-#define ELIDE_CODE
-#endif
+# include <gnu-versions.h>
+# if _GNU_GETOPT_INTERFACE_VERSION == GETOPT_INTERFACE_VERSION
+#  define ELIDE_CODE
+# endif
 #endif
 
 #ifndef ELIDE_CODE
@@ -65,26 +65,26 @@
 #ifdef	__GNU_LIBRARY__
 /* Don't include stdlib.h for non-GNU C libraries because some of them
    contain conflicting prototypes for getopt.  */
-#include <stdlib.h>
-#include <unistd.h>
+# include <stdlib.h>
+# include <unistd.h>
 #endif	/* GNU C library.  */
 
 #ifdef VMS
-#include <unixlib.h>
-#if HAVE_STRING_H - 0
-#include <string.h>
-#endif
+# include <unixlib.h>
+# if HAVE_STRING_H - 0
+#  include <string.h>
+# endif
 #endif
 
 #ifndef _
 /* This is for other GNU distributions with internationalized messages.
    When compiling libc, the _ macro is predefined.  */
-#ifdef HAVE_LIBINTL_H
-# include <libintl.h>
-# define _(msgid)	gettext (msgid)
-#else
-# define _(msgid)	(msgid)
-#endif
+# ifdef HAVE_LIBINTL_H
+#  include <libintl.h>
+#  define _(msgid)	gettext (msgid)
+# else
+#  define _(msgid)	(msgid)
+# endif
 #endif
 
 /* This version of `getopt' appears to the caller like standard Unix `getopt'
@@ -194,14 +194,19 @@ static char *posixly_correct;
    because there are many ways it can cause trouble.
    On some systems, it contains special magic macros that don't work
    in GCC.  */
-#include <string.h>
-#define	my_index	strchr
+# include <string.h>
+# define my_index	strchr
 #else
 
 /* Avoid depending on library functions or files
    whose names are inconsistent.  */
 
-char *getenv ();
+#ifndef getenv
+extern char *getenv ();
+#endif
+#ifndef strncmp
+extern int strncmp ();
+#endif
 
 static char *
 my_index (str, chr)
@@ -222,11 +227,11 @@ my_index (str, chr)
 #ifdef __GNUC__
 /* Note that Motorola Delta 68k R3V7 comes with GCC but not stddef.h.
    That was relevant to code that was here before.  */
-#if !defined __STDC__ || !__STDC__
+# if (!defined __STDC__ || !__STDC__) && !defined strlen
 /* gcc with -traditional declares the built-in strlen to return int,
    and has done so at least since version 2.4.5. -- rms.  */
 extern int strlen (const char *);
-#endif /* not __STDC__ */
+# endif /* not __STDC__ */
 #endif /* __GNUC__ */
 
 #endif /* not __GNU_LIBRARY__ */
@@ -524,11 +529,11 @@ _getopt_internal (argc, argv, optstring, longopts, longind, long_only)
      from the shell indicating it is not an option.  The later information
      is only used when the used in the GNU libc.  */
 #ifdef _LIBC
-#define NONOPTION_P (argv[optind][0] != '-' || argv[optind][1] == '\0'	      \
-		     || (optind < nonoption_flags_len			      \
-			 && __getopt_nonoption_flags[optind] == '1'))
+# define NONOPTION_P (argv[optind][0] != '-' || argv[optind][1] == '\0'	      \
+		      || (optind < nonoption_flags_len			      \
+			  && __getopt_nonoption_flags[optind] == '1'))
 #else
-#define NONOPTION_P (argv[optind][0] != '-' || argv[optind][1] == '\0')
+# define NONOPTION_P (argv[optind][0] != '-' || argv[optind][1] == '\0')
 #endif
 
   if (nextchar == NULL || *nextchar == '\0')
diff --git a/posix/regex.c b/posix/regex.c
index b7fb962d61..e2d31a0427 100644
--- a/posix/regex.c
+++ b/posix/regex.c
@@ -1083,17 +1083,9 @@ static const char *re_error_msgid[] =
 # if defined MATCH_MAY_ALLOCATE
 /* 4400 was enough to cause a crash on Alpha OSF/1,
    whose default stack limit is 2mb.  */
-#  ifdef _LIBC
-long int __re_max_failures = 4000;
-#  else
 long int re_max_failures = 4000;
-#  endif
 # else
-#  ifdef _LIBC
-long int __re_max_failures = 2000;
-#  else
 long int re_max_failures = 2000;
-#  endif
 # endif
 
 union fail_stack_elt
@@ -1116,24 +1108,11 @@ typedef struct
 # if defined MATCH_MAY_ALLOCATE
 /* 4400 was enough to cause a crash on Alpha OSF/1,
    whose default stack limit is 2mb.  */
-#  ifdef _LIBC
-int __re_max_failures = 20000;
-#  else
 int re_max_failures = 20000;
-#  endif
 # else
-#  ifdef _LIBC
-int __re_max_failures = 2000;
-#  else
 int re_max_failures = 2000;
-#  endif
 # endif
 
-#ifdef _LIBC
-weak_alias (__re_max_failures, re_max_failures)
-# define re_max_failures __re_max_failures
-#endif
-
 union fail_stack_elt
 {
   unsigned char *pointer;
diff --git a/posix/wordexp-test.c b/posix/wordexp-test.c
index ba69476e4c..81f93a1577 100644
--- a/posix/wordexp-test.c
+++ b/posix/wordexp-test.c
@@ -150,6 +150,7 @@ struct test_case_struct
   };
 
 static int testit (struct test_case_struct *tc);
+static int tests;
 
 void
 command_line_test (const char *words)
@@ -204,17 +205,28 @@ main (int argc, char *argv[])
     {
       struct test_case_struct ts;
 
+      printf ("Test %d (~root): ", ++tests);
+      fflush (stdout);
+
       ts.retval = 0;
       ts.env = NULL;
       ts.words = "~root";
       ts.flags = 0;
       ts.wordc = 1;
       ts.wordv[0] = pw->pw_dir;
+      ts.ifs = IFS;
 
       if (testit (&ts))
-	++fail;
+	{
+	  printf ("FAILED\n");
+	  ++fail;
+	}
+      else
+	printf ("OK\n");
     }
 
+  puts ("tests completed, now cleaning up");
+
   /* Clean up */
   for (i = 0; globfile[i]; ++i)
     remove (globfile[i]);
@@ -225,6 +237,8 @@ main (int argc, char *argv[])
   chdir (cwd);
   rmdir (tmpdir);
 
+  printf ("tests failed: %d\n", fail);
+
   return fail != 0;
 }
 
@@ -232,7 +246,6 @@ main (int argc, char *argv[])
 static int
 testit (struct test_case_struct *tc)
 {
-  static int test;
   int retval;
   wordexp_t we;
   int bzzzt = 0;
@@ -248,7 +261,7 @@ testit (struct test_case_struct *tc)
   else
     unsetenv ("IFS");
 
-  printf ("Test %d: ", ++test);
+  printf ("Test %d (%s): ", ++tests, tc->words);
   retval = wordexp (tc->words, &we, tc->flags);
 
   if (retval != tc->retval || (retval == 0 && we.we_wordc != tc->wordc))
diff --git a/signal/sighold.c b/signal/sighold.c
index d2cb537912..730bcacb72 100644
--- a/signal/sighold.c
+++ b/signal/sighold.c
@@ -18,6 +18,8 @@
    write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
    Boston, MA 02111-1307, USA.  */
 
+#define __need_NULL
+#include <stddef.h>
 #include <signal.h>
 
 int
diff --git a/signal/sigrelse.c b/signal/sigrelse.c
index 44e1001a06..971d60ffdf 100644
--- a/signal/sigrelse.c
+++ b/signal/sigrelse.c
@@ -18,6 +18,8 @@
    write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
    Boston, MA 02111-1307, USA.  */
 
+#define __need_NULL
+#include <stddef.h>
 #include <signal.h>
 
 int
diff --git a/stdlib/mblen.c b/stdlib/mblen.c
index e43b076371..d60a1fb160 100644
--- a/stdlib/mblen.c
+++ b/stdlib/mblen.c
@@ -1,4 +1,4 @@
-/* Copyright (C) 1991, 1997 Free Software Foundation, Inc.
+/* Copyright (C) 1991, 1997, 1998 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
@@ -37,17 +37,23 @@ mblen (const char *s, size_t n)
      restartable functions.  We simply say here all encodings have a
      state.  */
   if (s == NULL)
-    return 1;
-
-  state.count = 0;
-  state.value = 0;
-
-  result = __mbrtowc (NULL, s, n, &state);
-
-  /* The `mbrtowc' functions tell us more than we need.  Fold the -1
-     and -2 result into -1.  */
-  if (result < 0)
-    result = -1;
+    result = 1;
+  else if (*s == '\0')
+    /* According to the ISO C 89 standard this is the expected behaviour.
+       Idiotic, but true.  */
+    result = 0;
+  else
+    {
+      state.count = 0;
+      state.value = 0;
+
+      result = __mbrtowc (NULL, s, n, &state);
+
+      /* The `mbrtowc' functions tell us more than we need.  Fold the -1
+	 and -2 result into -1.  */
+      if (result < 0)
+	result = -1;
+    }
 
   return result;
 }
diff --git a/stdlib/mbtowc.c b/stdlib/mbtowc.c
index 61b46f882e..50e7c09834 100644
--- a/stdlib/mbtowc.c
+++ b/stdlib/mbtowc.c
@@ -1,4 +1,4 @@
-/* Copyright (C) 1991, 1992, 1995, 1996, 1997 Free Software Foundation, Inc.
+/* Copyright (C) 1991, 92, 95, 96, 97, 98 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
@@ -43,14 +43,22 @@ mbtowc (wchar_t *pwc, const char *s, size_t n)
      restartable functions.  We simply say here all encodings have a
      state.  */
   if (s == NULL)
-    return 1;
+    result = 1;
+  else if (*s == '\0')
+    {
+      if (pwc != NULL)
+	*pwc = L'\0';
+      result = 0;
+    }
+  else
+    {
+      result = __mbrtowc (pwc, s, n, &__no_r_state);
 
-  result = __mbrtowc (pwc, s, n, &__no_r_state);
-
-  /* The `mbrtowc' functions tell us more than we need.  Fold the -1
-     and -2 result into -1.  */
-  if (result < 0)
-    result = -1;
+      /* The `mbrtowc' functions tell us more than we need.  Fold the -1
+	 and -2 result into -1.  */
+      if (result < 0)
+	result = -1;
+    }
 
   return result;
 }
diff --git a/sysdeps/arm/bits/setjmp.h b/sysdeps/arm/bits/setjmp.h
index 5cf9cd75c7..ea25a9ba87 100644
--- a/sysdeps/arm/bits/setjmp.h
+++ b/sysdeps/arm/bits/setjmp.h
@@ -1,3 +1,21 @@
+/* Copyright (C) 1997, 1998 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 Library General Public License as
+   published by the Free Software Foundation; either version 2 of the
+   License, or (at your option) any later version.
+
+   The GNU C Library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   Library General Public License for more details.
+
+   You should have received a copy of the GNU Library General Public
+   License along with the GNU C Library; see the file COPYING.LIB.  If not,
+   write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+   Boston, MA 02111-1307, USA.  */
+
 /* Define the machine-dependent type `jmp_buf'.  ARM version. */
 
 #ifndef _SETJMP_H
diff --git a/sysdeps/arm/strlen.S b/sysdeps/arm/strlen.S
new file mode 100644
index 0000000000..9acef4f935
--- /dev/null
+++ b/sysdeps/arm/strlen.S
@@ -0,0 +1,55 @@
+/* Copyright (C) 1998 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+   Code contributed by Matthew Wilcox <willy@odie.barnet.ac.uk>
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Library General Public License as
+   published by the Free Software Foundation; either version 2 of the
+   License, or (at your option) any later version.
+
+   The GNU C Library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   Library General Public License for more details.
+
+   You should have received a copy of the GNU Library General Public
+   License along with the GNU C Library; see the file COPYING.LIB.  If not,
+   write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+   Boston, MA 02111-1307, USA.  */
+
+#include <sysdep.h>
+
+/* size_t strlen(const char *S)
+ * entry: r0 -> string
+ * exit: r0 = len
+ */
+
+ENTRY(strlen)
+	bic     r1, r0, $3              @ addr of word containing first byte
+	ldr     r2, [r1], $4            @ get the first word
+	ands    r3, r0, $3              @ how many bytes are duff?
+	rsb     r0, r3, $0              @ get - that number into counter.
+	beq     Laligned                @ skip into main check routine if no
+					@ more
+	orr     r2, r2, $0xff000000     @ set this byte to non-zero
+	subs    r3, r3, $1              @ any more to do?
+	orrgt   r2, r2, $0x00ff0000     @ if so, set this byte
+	subs    r3, r3, $1              @ more?
+	orrgt   r2, r2, $0x0000ff00     @ then set.
+Laligned:				@ here, we have a word in r2.  Does it
+	tst     r2, $0x000000ff         @ contain any zeroes?
+	tstne   r2, $0x0000ff00         @
+	tstne   r2, $0x00ff0000         @
+	tstne   r2, $0xff000000         @
+	addne   r0, r0, $4              @ if not, the string is 4 bytes longer
+	ldrne   r2, [r1], $4            @ and we continue to the next word
+	bne     Laligned                @
+Llastword:				@ drop through to here once we find a
+	tst     r2, $0x000000ff         @ word that has a zero byte in it
+	addne   r0, r0, $1              @
+	tstne   r2, $0x0000ff00         @ and add up to 3 bytes on to it
+	addne   r0, r0, $1              @
+	tstne   r2, $0x00ff0000         @ (if first three all non-zero, 4th
+	addne   r0, r0, $1              @  must be zero)
+	RETINSTR(mov,pc,lr)
+END(strlen)
diff --git a/sysdeps/generic/bits/socket.h b/sysdeps/generic/bits/socket.h
index 5dc1e65370..01844bc143 100644
--- a/sysdeps/generic/bits/socket.h
+++ b/sysdeps/generic/bits/socket.h
@@ -17,6 +17,9 @@
    write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
    Boston, MA 02111-1307, USA.  */
 
+#ifndef __BITS_SOCKET_H
+#define __BITS_SOCKET_H	1
+
 #if !defined _SYS_SOCKET_H && !defined _NETINET_IN_H
 # error "Never include <bits/socket.h> directly; use <sys/socket.h> instead."
 #endif
@@ -196,3 +199,5 @@ struct linger
     int l_onoff;		/* Nonzero to linger on close.  */
     int l_linger;		/* Time to linger.  */
   };
+
+#endif	/* bits/socket.h */
diff --git a/sysdeps/generic/bits/utmpx.h b/sysdeps/generic/endutxent.c
index e22660f6d6..cd8d7e4122 100644
--- a/sysdeps/generic/bits/utmpx.h
+++ b/sysdeps/generic/endutxent.c
@@ -1,5 +1,6 @@
-/* Structures and definitions for the user accounting database.  Generic/BSDish
-   Copyright (C) 1993, 1996, 1997 Free Software Foundation, Inc.
+/* Copyright (C) 1998 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+   Contributed by Mark Kettenis <kettenis@phys.uva.nl>, 1998.
 
    The GNU C Library is free software; you can redistribute it and/or
    modify it under the terms of the GNU Library General Public License as
@@ -16,19 +17,11 @@
    write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
    Boston, MA 02111-1307, USA.  */
 
-#ifndef _UTMPX_H
-# error "Never include <bits/utmpx.h> directly; use <utmpx.h> instead."
-#endif
+#include <utmp.h>
+#include <utmpx.h>
 
-
-#define	__UT_NAMESIZE	8
-#define	__UT_LINESIZE	8
-#define	__UT_HOSTSIZE	16
-
-struct utmpx
-  {
-    char ut_line[__UT_LINESIZE];
-    char ut_name[__UT_NAMESIZE];
-    char ut_host[__UT_HOSTSIZE];
-    long int ut_time;
-  };
+void
+endutxent (void)
+{
+  __endutent ();
+}
diff --git a/sysdeps/generic/getutxent.c b/sysdeps/generic/getutxent.c
new file mode 100644
index 0000000000..f6f07d5c44
--- /dev/null
+++ b/sysdeps/generic/getutxent.c
@@ -0,0 +1,27 @@
+/* Copyright (C) 1998 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+   Contributed by Mark Kettenis <kettenis@phys.uva.nl>, 1998.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Library General Public License as
+   published by the Free Software Foundation; either version 2 of the
+   License, or (at your option) any later version.
+
+   The GNU C Library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   Library General Public License for more details.
+
+   You should have received a copy of the GNU Library General Public
+   License along with the GNU C Library; see the file COPYING.LIB.  If not,
+   write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+   Boston, MA 02111-1307, USA.  */
+
+#include <utmp.h>
+#include <utmpx.h>
+
+struct utmpx *
+getutxent (void)
+{
+  return (struct utmpx *) __getutent ();
+}
diff --git a/sysdeps/generic/getutxid.c b/sysdeps/generic/getutxid.c
new file mode 100644
index 0000000000..d58f4c307d
--- /dev/null
+++ b/sysdeps/generic/getutxid.c
@@ -0,0 +1,27 @@
+/* Copyright (C) 1998 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+   Contributed by Mark Kettenis <kettenis@phys.uva.nl>, 1998.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Library General Public License as
+   published by the Free Software Foundation; either version 2 of the
+   License, or (at your option) any later version.
+
+   The GNU C Library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   Library General Public License for more details.
+
+   You should have received a copy of the GNU Library General Public
+   License along with the GNU C Library; see the file COPYING.LIB.  If not,
+   write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+   Boston, MA 02111-1307, USA.  */
+
+#include <utmp.h>
+#include <utmpx.h>
+
+struct utmpx *
+getutxid (const struct utmpx *id)
+{
+  return (struct utmpx *) __getutid ((const struct utmp *) id);
+}
diff --git a/sysdeps/generic/getutxline.c b/sysdeps/generic/getutxline.c
new file mode 100644
index 0000000000..4296ea615b
--- /dev/null
+++ b/sysdeps/generic/getutxline.c
@@ -0,0 +1,27 @@
+/* Copyright (C) 1998 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+   Contributed by Mark Kettenis <kettenis@phys.uva.nl>, 1998.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Library General Public License as
+   published by the Free Software Foundation; either version 2 of the
+   License, or (at your option) any later version.
+
+   The GNU C Library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   Library General Public License for more details.
+
+   You should have received a copy of the GNU Library General Public
+   License along with the GNU C Library; see the file COPYING.LIB.  If not,
+   write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+   Boston, MA 02111-1307, USA.  */
+
+#include <utmp.h>
+#include <utmpx.h>
+
+struct utmpx *
+getutxline (const struct utmpx *line)
+{
+  return (struct utmpx *) __getutline ((const struct utmp *) line);
+}
diff --git a/sysdeps/generic/longjmp.c b/sysdeps/generic/longjmp.c
index f46f1601c3..1a4850f1b8 100644
--- a/sysdeps/generic/longjmp.c
+++ b/sysdeps/generic/longjmp.c
@@ -1,4 +1,4 @@
-/* Copyright (C) 1991, 1992, 1994, 1995, 1997 Free Software Foundation, Inc.
+/* Copyright (C) 1991, 92, 94, 95, 97, 98 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
@@ -27,7 +27,7 @@ extern void _longjmp_unwind (jmp_buf env, int val);
    to the position specified in ENV, causing the setjmp
    call there to return VAL, or 1 if VAL is 0.  */
 void
-longjmp (sigjmp_buf env, int val)
+__libc_siglongjmp (sigjmp_buf env, int val)
 {
   /* Perform any cleanups needed by the frames being unwound.  */
   _longjmp_unwind (env, val);
@@ -41,5 +41,7 @@ longjmp (sigjmp_buf env, int val)
   __longjmp (env[0].__jmpbuf, val ?: 1);
 }
 
-weak_alias (longjmp, _longjmp)
-weak_alias (longjmp, siglongjmp)
+strong_alias (__libc_siglongjmp, __libc_longjmp)
+weak_alias (__libc_siglongjmp, _longjmp)
+weak_alias (__libc_siglongjmp, longjmp)
+weak_alias (__libc_siglongjmp, siglongjmp)
diff --git a/sysdeps/generic/pututxline.c b/sysdeps/generic/pututxline.c
new file mode 100644
index 0000000000..d1246bc5a4
--- /dev/null
+++ b/sysdeps/generic/pututxline.c
@@ -0,0 +1,27 @@
+/* Copyright (C) 1998 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+   Contributed by Mark Kettenis <kettenis@phys.uva.nl>, 1998.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Library General Public License as
+   published by the Free Software Foundation; either version 2 of the
+   License, or (at your option) any later version.
+
+   The GNU C Library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   Library General Public License for more details.
+
+   You should have received a copy of the GNU Library General Public
+   License along with the GNU C Library; see the file COPYING.LIB.  If not,
+   write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+   Boston, MA 02111-1307, USA.  */
+
+#include <utmp.h>
+#include <utmpx.h>
+
+struct utmpx *
+pututxline (const struct utmpx *utmpx)
+{
+  return (struct utmpx *) __pututline ((const struct utmp *) utmpx);
+}
diff --git a/sysdeps/generic/setjmp.c b/sysdeps/generic/setjmp.c
index 8b1dfa6a83..56230aabf7 100644
--- a/sysdeps/generic/setjmp.c
+++ b/sysdeps/generic/setjmp.c
@@ -1,4 +1,4 @@
-/* Copyright (C) 1991, 1994, 1995, 1996, 1997 Free Software Foundation, Inc.
+/* Copyright (C) 1991, 94, 95, 96, 97, 98 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
@@ -22,7 +22,7 @@
 
 /* Save the current program position in ENV and return 0.  */
 int
-__sigsetjmp (jmp_buf env, int savemask)
+__libc_sigsetjmp (jmp_buf env, int savemask)
 {
   /* Save the signal mask if requested.  */
   __sigjmp_save (env, savemask);
@@ -32,6 +32,6 @@ __sigsetjmp (jmp_buf env, int savemask)
   return 0;
 }
 
-
+weak_alias (__libc_sigsetjmp, __sigsetjmp)
 stub_warning (__sigsetjmp)
 #include <stub-tag.h>
diff --git a/sysdeps/generic/setutxent.c b/sysdeps/generic/setutxent.c
new file mode 100644
index 0000000000..267a1bd7d1
--- /dev/null
+++ b/sysdeps/generic/setutxent.c
@@ -0,0 +1,27 @@
+/* Copyright (C) 1998 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+   Contributed by Mark Kettenis <kettenis@phys.uva.nl>, 1998.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Library General Public License as
+   published by the Free Software Foundation; either version 2 of the
+   License, or (at your option) any later version.
+
+   The GNU C Library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   Library General Public License for more details.
+
+   You should have received a copy of the GNU Library General Public
+   License along with the GNU C Library; see the file COPYING.LIB.  If not,
+   write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+   Boston, MA 02111-1307, USA.  */
+
+#include <utmp.h>
+#include <utmpx.h>
+
+void
+setutxent (void)
+{
+  return __setutent ();
+}
diff --git a/sysdeps/generic/strcasestr.c b/sysdeps/generic/strcasestr.c
index ec8727d268..a5786fac58 100644
--- a/sysdeps/generic/strcasestr.c
+++ b/sysdeps/generic/strcasestr.c
@@ -1,5 +1,5 @@
 /* Return the offset of one string within another.
-   Copyright (C) 1994, 1996, 1997 Free Software Foundation, Inc.
+   Copyright (C) 1994, 1996, 1997, 1998 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
@@ -38,7 +38,8 @@
 
 typedef unsigned chartype;
 
-#undef strstr
+#undef strcasestr
+#undef __strcasestr
 
 char *
 __strcasestr (phaystack, pneedle)
diff --git a/login/updwtmp.c b/sysdeps/generic/updwtmp.c
index 9965a61fbb..d6f29b1851 100644
--- a/login/updwtmp.c
+++ b/sysdeps/generic/updwtmp.c
@@ -1,4 +1,4 @@
-/* Copyright (C) 1997 Free Software Foundation, Inc.
+/* Copyright (C) 1997, 1998 Free Software Foundation, Inc.
    This file is part of the GNU C Library.
    Contributed by Mark Kettenis <kettenis@phys.uva.nl>, 1997.
 
@@ -17,30 +17,25 @@
    write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
    Boston, MA 02111-1307, USA.  */
 
-#include <unistd.h>
 #include <utmp.h>
 
 #include "utmp-private.h"
 
+#ifndef TRANSFORM_UTMP_FILE_NAME
+# define TRANSFORM_UTMP_FILE_NAME(file_name) (file_name)
+#endif
 
 void
-updwtmp (const char *wtmp_file, const struct utmp *utmp)
+__updwtmp (const char *wtmp_file, const struct utmp *utmp)
 {
   /* See whether utmpd is running.  */
   if ((*__libc_utmp_daemon_functions.updwtmp) (wtmp_file, utmp) < 0)
     {
-      /* Use the normal file, but if the current file is _PATH_UTMP or
-         _PATH_WTMP and the corresponding extended file (with an extra
-         'x' added to the pathname) exists, we use the extended file,
-         because the original file is in a different format.  */
-      if (strcmp (wtmp_file, _PATH_UTMP) == 0
-	  && __access (_PATH_UTMP "x", F_OK) == 0)
-	(*__libc_utmp_file_functions.updwtmp) (_PATH_UTMP "x", utmp);
-      else if (strcmp (wtmp_file, _PATH_WTMP) == 0
-	       && __access (_PATH_WTMP "x", F_OK) == 0)
-	(*__libc_utmp_file_functions.updwtmp) (_PATH_WTMP "x", utmp);
-      else
-	(*__libc_utmp_file_functions.updwtmp) (wtmp_file, utmp);
+      const char *file_name;
+
+      file_name = TRANSFORM_UTMP_FILE_NAME (wtmp_file);
+
+      (*__libc_utmp_file_functions.updwtmp) (file_name, utmp);
     }
 }
-
+weak_alias (__updwtmp, updwtmp)
diff --git a/sysdeps/generic/updwtmpx.c b/sysdeps/generic/updwtmpx.c
new file mode 100644
index 0000000000..097bf380d2
--- /dev/null
+++ b/sysdeps/generic/updwtmpx.c
@@ -0,0 +1,27 @@
+/* Copyright (C) 1998 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+   Contributed by Mark Kettenis <kettenis@phys.uva.nl>, 1998.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Library General Public License as
+   published by the Free Software Foundation; either version 2 of the
+   License, or (at your option) any later version.
+
+   The GNU C Library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   Library General Public License for more details.
+
+   You should have received a copy of the GNU Library General Public
+   License along with the GNU C Library; see the file COPYING.LIB.  If not,
+   write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+   Boston, MA 02111-1307, USA.  */
+
+#include <utmp.h>
+#include <utmpx.h>
+
+void
+__updwtmpx (const char *wtmpx_file, const struct utmpx *utmpx)
+{
+  __updwtmp (wtmpx_file, (const struct utmp *) utmpx);
+}
diff --git a/login/utmp_file.c b/sysdeps/generic/utmp_file.c
index 9cdb88ebec..08675185ce 100644
--- a/login/utmp_file.c
+++ b/sysdeps/generic/utmp_file.c
@@ -61,19 +61,18 @@ struct utfuncs __libc_utmp_file_functions =
 };
 
 
+#ifndef TRANSFORM_UTMP_FILE_NAME
+# define TRANSFORM_UTMP_FILE_NAME(file_name) (file_name)
+#endif
+
 static int
 setutent_file (void)
 {
   if (file_fd < 0)
     {
-      const char *file_name = __libc_utmp_file_name;
+      const char *file_name;
 
-      if (strcmp (__libc_utmp_file_name, _PATH_UTMP) == 0
-	  && __access (_PATH_UTMP "x", F_OK) == 0)
-	file_name = _PATH_UTMP "x";
-      else if (strcmp (__libc_utmp_file_name, _PATH_WTMP) == 0
-	       && __access (_PATH_WTMP "x", F_OK) == 0)
-	file_name = _PATH_WTMP "x";
+      file_name = TRANSFORM_UTMP_FILE_NAME (__libc_utmp_file_name);
 
       file_fd = open (file_name, O_RDWR);
       if (file_fd == -1)
@@ -81,10 +80,7 @@ setutent_file (void)
 	  /* Hhm, read-write access did not work.  Try read-only.  */
 	  file_fd = open (file_name, O_RDONLY);
 	  if (file_fd == -1)
-	    {
-	      perror (_("while opening UTMP file"));
-	      return 0;
-	    }
+	    return 0;
 	}
     }
 
diff --git a/sysdeps/generic/utmpxname.c b/sysdeps/generic/utmpxname.c
new file mode 100644
index 0000000000..41c91937d0
--- /dev/null
+++ b/sysdeps/generic/utmpxname.c
@@ -0,0 +1,27 @@
+/* Copyright (C) 1998 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+   Contributed by Mark Kettenis <kettenis@phys.uva.nl>, 1998.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Library General Public License as
+   published by the Free Software Foundation; either version 2 of the
+   License, or (at your option) any later version.
+
+   The GNU C Library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   Library General Public License for more details.
+
+   You should have received a copy of the GNU Library General Public
+   License along with the GNU C Library; see the file COPYING.LIB.  If not,
+   write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+   Boston, MA 02111-1307, USA.  */
+
+#include <utmp.h>
+#include <utmpx.h>
+
+int
+utmpxname (const char *file)
+{
+  return __utmpname (file);
+}
diff --git a/sysdeps/gnu/Makefile b/sysdeps/gnu/Makefile
index e491fa2be4..762f79b866 100644
--- a/sysdeps/gnu/Makefile
+++ b/sysdeps/gnu/Makefile
@@ -28,3 +28,10 @@ $(..)sysdeps/gnu/errlist.c: $(..)sysdeps/gnu/errlist.awk \
 ifeq ($(with-cvs),yes)
 	test ! -d CVS || cvs commit -m'Regenerated from $^' $@
 endif
+
+ifeq ($(subdir),login)
+sysdep_routines += setutxent getutxent endutxent getutxid getutxline \
+                   pututxline utmpxname updwtmpx
+
+sysdep_headers += utmpx.h bits/utmpx.h
+endif
diff --git a/sysdeps/gnu/bits/utmpx.h b/sysdeps/gnu/bits/utmpx.h
index 4ecbb3a026..b367bfba3c 100644
--- a/sysdeps/gnu/bits/utmpx.h
+++ b/sysdeps/gnu/bits/utmpx.h
@@ -1,5 +1,5 @@
 /* Structures and defenitions for the user accounting database.  GNU version.
-   Copyright (C) 1997 Free Software Foundation, Inc.
+   Copyright (C) 1997, 1998 Free Software Foundation, Inc.
 
    The GNU C Library is free software; you can redistribute it and/or
    modify it under the terms of the GNU Library General Public License as
@@ -24,6 +24,13 @@
 #include <sys/time.h>
 
 
+#ifdef __USE_GNU
+# include <paths.h>
+# define _PATH_UTMPX	_PATH_UTMP
+# define _PATH_WTMPX	_PATH_WTMP
+#endif
+
+
 #define __UT_LINESIZE	32
 #define __UT_NAMESIZE	32
 #define __UT_HOSTSIZE	256
@@ -56,10 +63,12 @@ struct utmpx
 };
 
 
-/* Values for the `ut_type' field of a `struct utmp'.  */
+/* Values for the `ut_type' field of a `struct utmpx'.  */
 #define EMPTY		0	/* No valid user accounting information.  */
 
-#define RUN_LVL		1	/* The system's runlevel.  */
+#ifdef __USE_GNU
+# define RUN_LVL	1	/* The system's runlevel.  */
+#endif
 #define BOOT_TIME	2	/* Time of system boot.  */
 #define NEW_TIME	3	/* Time after system clock changed.  */
 #define OLD_TIME	4	/* Time when system clock changed.  */
@@ -68,3 +77,7 @@ struct utmpx
 #define LOGIN_PROCESS	6	/* Session leader of a logged in user.  */
 #define USER_PROCESS	7	/* Normal process.  */
 #define DEAD_PROCESS	8	/* Terminated process.  */
+
+#ifdef __USE_GNU
+# define ACCOUNTING	9	/* System accounting.  */
+#endif
diff --git a/sysdeps/gnu/updwtmp.c b/sysdeps/gnu/updwtmp.c
new file mode 100644
index 0000000000..19a77657b3
--- /dev/null
+++ b/sysdeps/gnu/updwtmp.c
@@ -0,0 +1,30 @@
+/* Copyright (C) 1998 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+   Contributed by Mark Kettenis <kettenis@phys.uva.nl>, 1998.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Library General Public License as
+   published by the Free Software Foundation; either version 2 of the
+   License, or (at your option) any later version.
+
+   The GNU C Library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   Library General Public License for more details.
+
+   You should have received a copy of the GNU Library General Public
+   License along with the GNU C Library; see the file COPYING.LIB.  If not,
+   write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+   Boston, MA 02111-1307, USA.  */
+
+#include <string.h>
+#include <unistd.h>
+
+#define TRANSFORM_UTMP_FILE_NAME(file_name) \
+    ((strcmp (file_name, _PATH_UTMP "x") == 0 \
+      && __access (_PATH_UTMP "x", F_OK) != 0) ? _PATH_UTMP : \
+     ((strcmp (file_name, _PATH_WTMP "x") == 0 \
+       && __access (_PATH_WTMP "x", F_OK) != 0) ? _PATH_WTMP : \
+      file_name))
+
+#include <sysdeps/generic/updwtmp.c>
diff --git a/sysdeps/gnu/utmp_file.c b/sysdeps/gnu/utmp_file.c
new file mode 100644
index 0000000000..05bbcd1ce1
--- /dev/null
+++ b/sysdeps/gnu/utmp_file.c
@@ -0,0 +1,30 @@
+/* Copyright (C) 1998 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+   Contributed by Mark Kettenis <kettenis@phys.uva.nl>, 1998.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Library General Public License as
+   published by the Free Software Foundation; either version 2 of the
+   License, or (at your option) any later version.
+
+   The GNU C Library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   Library General Public License for more details.
+
+   You should have received a copy of the GNU Library General Public
+   License along with the GNU C Library; see the file COPYING.LIB.  If not,
+   write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+   Boston, MA 02111-1307, USA.  */
+
+#include <string.h>
+#include <unistd.>
+
+#define TRANSFORM_UTMP_FILE_NAME(file_name) \
+    ((strcmp (file_name, _PATH_UTMP "x") == 0 \
+      && __access (_PATH_UTMP "x", F_OK) != 0) ? _PATH_UTMP : \
+     ((strcmp (file_name, _PATH_WTMP "x") == 0 \
+       && __access (_PATH_WTMP "x", F_OK) != 0) ? _PATH_WTMP : \
+      file_name))
+
+#include <sysdeps/generic/utmp_file.c>
diff --git a/login/utmpx.h b/sysdeps/gnu/utmpx.h
index 5873bf9310..e9f2389b75 100644
--- a/login/utmpx.h
+++ b/sysdeps/gnu/utmpx.h
@@ -1,4 +1,4 @@
-/* Copyright (C) 1997 Free Software Foundation, Inc.
+/* Copyright (C) 1997, 1998 Free Software Foundation, Inc.
    This file is part of the GNU C Library.
    Contributed by Mark Kettenis <kettenis@phys.uva.nl>, 1997.
 
@@ -27,8 +27,16 @@ __BEGIN_DECLS
 /* Get system dependent values and data structures.  */
 #include <bits/utmpx.h>
 
+#ifdef __USE_GNU
+/* Compatibility names for the strings of the canonical file names.  */
+# define UTMPX_FILE	_PATH_UTMPX
+# define UTMPX_FILENAME	_PATH_UTMPX
+# define WTMPX_FILE	_PATH_WTMPX
+# define WTMPX_FILENAME	_PATH_WTMPX
+#endif
+
 /* Open user accounting database.  */
-extern void *setutxent __P ((void));
+extern void setutxent __P ((void));
 
 /* Close user accounting database.  */
 extern void endutxent __P ((void));
@@ -45,6 +53,15 @@ extern struct utmpx *getutxline __P ((const struct utmpx *__line));
 /* Write the entry UTMPX into the user accounting database.  */
 extern struct utmpx *pututxline __P ((const struct utmpx *__utmpx));
 
+#ifdef __USE_GNU
+/* Change name of the utmpx file to be examined.  */
+extern int utmpxname __P ((__const char *__file));
+
+/* Append entry UTMP to the wtmpx-like file WTMPX_FILE.  */
+extern void updwtmpx __P ((__const char *__wtmpx_file,
+			   __const struct utmpx *__utmpx));
+#endif
+
 __END_DECLS
 
 #endif /* utmpx.h  */
diff --git a/sysdeps/i386/bits/setjmp.h b/sysdeps/i386/bits/setjmp.h
index 5cb60a8c7d..46729224fd 100644
--- a/sysdeps/i386/bits/setjmp.h
+++ b/sysdeps/i386/bits/setjmp.h
@@ -1,3 +1,21 @@
+/* Copyright (C) 1997, 1998 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 Library General Public License as
+   published by the Free Software Foundation; either version 2 of the
+   License, or (at your option) any later version.
+
+   The GNU C Library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   Library General Public License for more details.
+
+   You should have received a copy of the GNU Library General Public
+   License along with the GNU C Library; see the file COPYING.LIB.  If not,
+   write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+   Boston, MA 02111-1307, USA.  */
+
 /* Define the machine-dependent type `jmp_buf'.  Intel 386 version.  */
 
 #ifndef _SETJMP_H
diff --git a/sysdeps/m68k/bits/setjmp.h b/sysdeps/m68k/bits/setjmp.h
index 2991232915..a302b72393 100644
--- a/sysdeps/m68k/bits/setjmp.h
+++ b/sysdeps/m68k/bits/setjmp.h
@@ -1,3 +1,21 @@
+/* Copyright (C) 1997, 1998 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 Library General Public License as
+   published by the Free Software Foundation; either version 2 of the
+   License, or (at your option) any later version.
+
+   The GNU C Library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   Library General Public License for more details.
+
+   You should have received a copy of the GNU Library General Public
+   License along with the GNU C Library; see the file COPYING.LIB.  If not,
+   write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+   Boston, MA 02111-1307, USA.  */
+
 /* Define the machine-dependent type `jmp_buf'.  m68k version.  */
 
 #ifndef _SETJMP_H
diff --git a/sysdeps/mach/hurd/Subdirs b/sysdeps/mach/hurd/Subdirs
index 739919f4b1..16b8348437 100644
--- a/sysdeps/mach/hurd/Subdirs
+++ b/sysdeps/mach/hurd/Subdirs
@@ -1,2 +1 @@
 hurd
-login
diff --git a/sysdeps/mach/hurd/bits/ioctls.h b/sysdeps/mach/hurd/bits/ioctls.h
index 1145560ab9..1e063e3e66 100644
--- a/sysdeps/mach/hurd/bits/ioctls.h
+++ b/sysdeps/mach/hurd/bits/ioctls.h
@@ -16,7 +16,10 @@
    write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
    Boston, MA 02111-1307, USA.  */
 
-#if !defined _HURD_IOCTL_H && !defined _SYS_IOCTLS_H
+#ifndef __BITS_IOCTLS_H
+#define __BITS_IOCTLS_H	1
+
+#if !defined _HURD_IOCTL_H && !defined _SYS_IOCTL_H
 # error "Never use <bits/ioctls.h> directly; include <hurd/ioctl.h> instead."
 #endif
 
@@ -345,3 +348,5 @@ enum __ioctl_datum { IOC_8, IOC_16, IOC_32, IOC_64 };
 # define EXTA	14
 # define EXTB	15
 #endif /* USE_OLD_TTY */
+
+#endif /* bits/ioctls.h */
diff --git a/sysdeps/posix/sigignore.c b/sysdeps/posix/sigignore.c
index f24aca70c9..497af577f8 100644
--- a/sysdeps/posix/sigignore.c
+++ b/sysdeps/posix/sigignore.c
@@ -19,6 +19,8 @@
    Boston, MA 02111-1307, USA.  */
 
 #include <errno.h>
+#define __need_NULL
+#include <stddef.h>
 #include <signal.h>
 
 int
diff --git a/sysdeps/posix/sigset.c b/sysdeps/posix/sigset.c
index 4bd3bf38c8..1a6b1a4fd3 100644
--- a/sysdeps/posix/sigset.c
+++ b/sysdeps/posix/sigset.c
@@ -17,6 +17,8 @@
    Boston, MA 02111-1307, USA.  */
 
 #include <errno.h>
+#define __need_NULL
+#include <stddef.h>
 #include <signal.h>
 
 
diff --git a/sysdeps/posix/waitid.c b/sysdeps/posix/waitid.c
index a36883a8d2..fa9021115f 100644
--- a/sysdeps/posix/waitid.c
+++ b/sysdeps/posix/waitid.c
@@ -1,5 +1,5 @@
 /* Pseudo implementation of waitid.
-   Copyright (C) 1997 Free Software Foundation, Inc.
+   Copyright (C) 1997, 1998 Free Software Foundation, Inc.
    This file is part of the GNU C Library.
    Contributed by Zack Weinberg <zack@rabi.phys.columbia.edu>, 1997.
 
@@ -20,6 +20,8 @@
 
 #include <errno.h>
 #include <signal.h>
+#define __need_NULL
+#include <stddef.h>
 #include <sys/wait.h>
 #include <sys/types.h>
 
diff --git a/sysdeps/powerpc/bits/setjmp.h b/sysdeps/powerpc/bits/setjmp.h
index 7bb654c0bc..65db364555 100644
--- a/sysdeps/powerpc/bits/setjmp.h
+++ b/sysdeps/powerpc/bits/setjmp.h
@@ -1,3 +1,21 @@
+/* Copyright (C) 1997, 1998 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 Library General Public License as
+   published by the Free Software Foundation; either version 2 of the
+   License, or (at your option) any later version.
+
+   The GNU C Library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   Library General Public License for more details.
+
+   You should have received a copy of the GNU Library General Public
+   License along with the GNU C Library; see the file COPYING.LIB.  If not,
+   write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+   Boston, MA 02111-1307, USA.  */
+
 /* Define the machine-dependent type `jmp_buf'.  PowerPC version.  */
 
 #ifndef _SETJMP_H
diff --git a/sysdeps/powerpc/elf/start.c b/sysdeps/powerpc/elf/start.c
deleted file mode 100644
index d32aeee6c7..0000000000
--- a/sysdeps/powerpc/elf/start.c
+++ /dev/null
@@ -1,125 +0,0 @@
-/* Startup code compliant to the ELF PowerPC ABI.
-   Copyright (C) 1997 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 Library General Public License as
-   published by the Free Software Foundation; either version 2 of the
-   License, or (at your option) any later version.
-
-   The GNU C Library is distributed in the hope that it will be useful,
-   but WITHOUT ANY WARRANTY; without even the implied warranty of
-   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
-   Library General Public License for more details.
-
-   You should have received a copy of the GNU Library General Public
-   License along with the GNU C Library; see the file COPYING.LIB.  If not,
-   write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
-   Boston, MA 02111-1307, USA.  */
-
-/* This is SVR4/PPC ABI compliant, and works under Linux when
-   statically linked.  */
-
-#include <unistd.h>
-#include <stdlib.h>
-
-/* Just a little assembler stub before gcc gets its hands on our
-   stack pointer... */
-asm ("\
-	.section \".text\"
-	.align 2
-	.globl _start
-	.type _start,@function
-_start:
- # save the stack pointer, in case we're statically linked under Linux
-	mr 8,1
- # set up an initial stack frame, and clear the LR
-	addi 1,1,-16
-	clrrwi 1,1,4
-	li 0,0
-	stw 0,0(1)
-	mtlr 0
- # set r13 to point at the 'small data area'
-	lis 13,_SDA_BASE_@ha
-	addi 13,13,_SDA_BASE_@l
- # and continue below.
-	b __start1
-0:
-	.size	 _start,0b-_start
- # undo '.section text'.
-	.previous
-");
-
-/* Define a symbol for the first piece of initialized data.  */
-int __data_start = 0;
-weak_alias (__data_start, data_start)
-
-/* these probably should go, at least go somewhere else
-   (sysdeps/mach/something?). */
-void (*_mach_init_routine) (void);
-void (*_thread_init_routine) (void);
-
-extern void __libc_init_first (int argc, char **argv, char **envp);
-extern int main (int argc, char **argv, char **envp, void *auxvec);
-#ifdef HAVE_INITFINI
-extern void _init (void);
-extern void _fini (void);
-#endif
-
-#if 0
-/* I'd like to say this, but it causes GCC to strip the whole procedure
-   from the object file (this is sort of reasonable, because you've told
-   GCC that the procedure is unused). :-( */
-static void __start1(int argc, char **argv, char **envp,
-		     void *auxvec, void (*exitfn) (void),
-		     char **stack_on_entry)
-     __attribute__ ((unused));
-
-static
-#endif
-void
-__start1(int argc, char **argv, char **envp,
-	 void *auxvec, void (*exitfn) (void),
-	 char **stack_on_entry)
-{
-  /* the PPC SVR4 ABI says that the top thing on the stack will
-     be a NULL pointer, so if not we assume that we're being called
-     as a statically-linked program by Linux...	 */
-  if (*stack_on_entry != NULL)
-    {
-      /* ...in which case, we have argc as the top thing on the
-	 stack, followed by argv (NULL-terminated), envp (likewise),
-	 and the auxilary vector.  */
-      argc = *(int *) stack_on_entry;
-      argv = stack_on_entry + 1;
-      envp = argv + argc + 1;
-      auxvec = envp;
-      while (*(char **) auxvec != NULL)
-	++auxvec;
-      ++auxvec;
-      exitfn = NULL;
-    }
-
-  if (exitfn != NULL)
-    atexit (exitfn);
-
-  /* libc init routine, in case we are statically linked
-     (otherwise ld.so will have called it when it loaded libc, but
-     calling it twice doesn't hurt). */
-  __libc_init_first (argc, argv, envp);
-
-#ifdef HAVE_INITFINI
-  /* ELF constructors/destructors */
-  atexit (_fini);
-  _init ();
-#endif
-
-  /* Stuff so we can build Mach/Linux executables (like vmlinux).  */
-  if (_mach_init_routine != 0)
-    _mach_init_routine ();
-  if (_thread_init_routine != 0)
-    _thread_init_routine ();
-
-  /* the rest of the program */
-  exit (main (argc, argv, envp, auxvec));
-}
diff --git a/sysdeps/sparc/sparc32/bits/setjmp.h b/sysdeps/sparc/sparc32/bits/setjmp.h
index 0e61fe7805..3d39132eab 100644
--- a/sysdeps/sparc/sparc32/bits/setjmp.h
+++ b/sysdeps/sparc/sparc32/bits/setjmp.h
@@ -1,3 +1,21 @@
+/* Copyright (C) 1997, 1998 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 Library General Public License as
+   published by the Free Software Foundation; either version 2 of the
+   License, or (at your option) any later version.
+
+   The GNU C Library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   Library General Public License for more details.
+
+   You should have received a copy of the GNU Library General Public
+   License along with the GNU C Library; see the file COPYING.LIB.  If not,
+   write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+   Boston, MA 02111-1307, USA.  */
+
 /* Define the machine-dependent type `jmp_buf'.  SPARC version.  */
 
 #ifndef _SETJMP_H
diff --git a/sysdeps/unix/sysv/linux/i386/s_pread64.S b/sysdeps/unix/sysv/linux/i386/s_pread64.S
index 7f8816b3ba..23d7d14ba5 100644
--- a/sysdeps/unix/sysv/linux/i386/s_pread64.S
+++ b/sysdeps/unix/sysv/linux/i386/s_pread64.S
@@ -49,7 +49,7 @@ ENTRY (__syscall_pread64)
 	cmpl	$-4095, %eax	/* Check %eax for error.  */
 	jae	syscall_error	/* Jump to error handler if error.  */
 #endif
-	ret			/* Return to caller.  */
 L(pseudo_end):
+	ret			/* Return to caller.  */
 
 PSEUDO_END (__syscall_pread64)
diff --git a/sysdeps/unix/sysv/linux/paths.h b/sysdeps/unix/sysv/linux/paths.h
index 53c4fc5dcb..cb5b57122c 100644
--- a/sysdeps/unix/sysv/linux/paths.h
+++ b/sysdeps/unix/sysv/linux/paths.h
@@ -64,7 +64,6 @@
 #define	_PATH_TTY	"/dev/tty"
 #define	_PATH_UNIX	"/vmlinux"
 #define _PATH_UTMP	"/var/run/utmp"
-#define _PATH_UTMP_DB	"/var/run/utmp.db"
 #define	_PATH_VI	"/usr/bin/vi"
 #define _PATH_WTMP	"/var/log/wtmp"
 
diff --git a/sysdeps/unix/sysv/linux/powerpc/dl-sysdep.c b/sysdeps/unix/sysv/linux/powerpc/dl-sysdep.c
index fa946cf774..9e31ed4096 100644
--- a/sysdeps/unix/sysv/linux/powerpc/dl-sysdep.c
+++ b/sysdeps/unix/sysv/linux/powerpc/dl-sysdep.c
@@ -30,7 +30,7 @@
     for (_tmp = (envp); *_tmp; ++_tmp)				\
       continue;							\
     /* The following '++' is important!  */			\
-    (auxp) = ++_tmp;						\
+    ++_tmp;							\
     if (*_tmp == 0)						\
       {								\
 	size_t _test = (size_t)_tmp;				\
@@ -42,8 +42,9 @@
 	   vector will have to be laid out to allow for this	\
 	   test :-(.  */					\
 	if (((ElfW(auxv_t) *)_test)->a_type <= AT_PHDR)		\
-	  (auxp) = (ElfW(auxv_t) *) _tmp;			\
+	  _tmp = (char **)_test;				\
       }								\
+    (auxp) = (ElfW(auxv_t) *) _tmp;				\
   } while (0)
 
 
diff --git a/sysdeps/unix/sysv/linux/powerpc/syscall.h b/sysdeps/unix/sysv/linux/powerpc/syscall.h
deleted file mode 100644
index c6bac3de5b..0000000000
--- a/sysdeps/unix/sysv/linux/powerpc/syscall.h
+++ /dev/null
@@ -1,357 +0,0 @@
-/* Copyright (C) 1997 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 Library General Public License as
-   published by the Free Software Foundation; either version 2 of the
-   License, or (at your option) any later version.
-
-   The GNU C Library is distributed in the hope that it will be useful,
-   but WITHOUT ANY WARRANTY; without even the implied warranty of
-   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
-   Library General Public License for more details.
-
-   You should have received a copy of the GNU Library General Public
-   License along with the GNU C Library; see the file COPYING.LIB.  If not,
-   write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
-   Boston, MA 02111-1307, USA.  */
-
-#ifndef _SYSCALL_H
-#define _SYSCALL_H	1
-
-/* normally, we'd get syscalls from asm/unistd.h under Linux, but this
-   is very broken under MkLinux/PPC, so we list them right here directly. */
-
-#define __NR_setup		  0
-#define __NR_exit		  1
-#define __NR_fork		  2
-#define __NR_read		  3
-#define __NR_write		  4
-#define __NR_open		  5
-#define __NR_close		  6
-#define __NR_waitpid		  7
-#define __NR_creat		  8
-#define __NR_link		  9
-#define __NR_unlink		 10
-#define __NR_execve		 11
-#define __NR_chdir		 12
-#define __NR_time		 13
-#define __NR_mknod		 14
-#define __NR_chmod		 15
-#define __NR_chown		 16
-#define __NR_break		 17
-#define __NR_oldstat		 18
-#define __NR_lseek		 19
-#define __NR_getpid		 20
-#define __NR_mount		 21
-#define __NR_umount		 22
-#define __NR_setuid		 23
-#define __NR_getuid		 24
-#define __NR_stime		 25
-#define __NR_ptrace		 26
-#define __NR_alarm		 27
-#define __NR_oldfstat		 28
-#define __NR_pause		 29
-#define __NR_utime		 30
-#define __NR_stty		 31
-#define __NR_gtty		 32
-#define __NR_access		 33
-#define __NR_nice		 34
-#define __NR_ftime		 35
-#define __NR_sync		 36
-#define __NR_kill		 37
-#define __NR_rename		 38
-#define __NR_mkdir		 39
-#define __NR_rmdir		 40
-#define __NR_dup		 41
-#define __NR_pipe		 42
-#define __NR_times		 43
-#define __NR_prof		 44
-#define __NR_brk		 45
-#define __NR_setgid		 46
-#define __NR_getgid		 47
-#define __NR_signal		 48
-#define __NR_geteuid		 49
-#define __NR_getegid		 50
-#define __NR_acct		 51
-#define __NR_phys		 52
-#define __NR_lock		 53
-#define __NR_ioctl		 54
-#define __NR_fcntl		 55
-#define __NR_mpx		 56
-#define __NR_setpgid		 57
-#define __NR_ulimit		 58
-#define __NR_oldolduname	 59
-#define __NR_umask		 60
-#define __NR_chroot		 61
-#define __NR_ustat		 62
-#define __NR_dup2		 63
-#define __NR_getppid		 64
-#define __NR_getpgrp		 65
-#define __NR_setsid		 66
-#define __NR_sigaction		 67
-#define __NR_sgetmask		 68
-#define __NR_ssetmask		 69
-#define __NR_setreuid		 70
-#define __NR_setregid		 71
-#define __NR_sigsuspend		 72
-#define __NR_sigpending		 73
-#define __NR_sethostname	 74
-#define __NR_setrlimit		 75
-#define __NR_getrlimit		 76
-#define __NR_getrusage		 77
-#define __NR_gettimeofday	 78
-#define __NR_settimeofday	 79
-#define __NR_getgroups		 80
-#define __NR_setgroups		 81
-#define __NR_select		 82
-#define __NR_symlink		 83
-#define __NR_oldlstat		 84
-#define __NR_readlink		 85
-#define __NR_uselib		 86
-#define __NR_swapon		 87
-#define __NR_reboot		 88
-#define __NR_readdir		 89
-#define __NR_mmap		 90
-#define __NR_munmap		 91
-#define __NR_truncate		 92
-#define __NR_ftruncate		 93
-#define __NR_fchmod		 94
-#define __NR_fchown		 95
-#define __NR_getpriority	 96
-#define __NR_setpriority	 97
-#define __NR_profil		 98
-#define __NR_statfs		 99
-#define __NR_fstatfs		100
-#define __NR_ioperm		101
-#define __NR_socketcall		102
-#define __NR_syslog		103
-#define __NR_setitimer		104
-#define __NR_getitimer		105
-#define __NR_stat		106
-#define __NR_lstat		107
-#define __NR_fstat		108
-#define __NR_olduname		109
-#define __NR_iopl		110
-#define __NR_vhangup		111
-#define __NR_idle		112
-#define __NR_vm86		113
-#define __NR_wait4		114
-#define __NR_swapoff		115
-#define __NR_sysinfo		116
-#define __NR_ipc		117
-#define __NR_fsync		118
-#define __NR_sigreturn		119
-#define __NR_clone		120
-#define __NR_setdomainname	121
-#define __NR_uname		122
-#define __NR_modify_ldt		123
-#define __NR_adjtimex		124
-#define __NR_mprotect		125
-#define __NR_sigprocmask	126
-#define __NR_create_module	127
-#define __NR_init_module	128
-#define __NR_delete_module	129
-#define __NR_get_kernel_syms	130
-#define __NR_quotactl		131
-#define __NR_getpgid		132
-#define __NR_fchdir		133
-#define __NR_bdflush		134
-#define __NR_sysfs		135
-#define __NR_personality	136
-#define __NR_afs_syscall	137 /* Syscall for Andrew File System */
-#define __NR_setfsuid		138
-#define __NR_setfsgid		139
-#define __NR__llseek		140
-#define __NR_getdents		141
-#define __NR__newselect		142
-#define __NR_flock		143
-#define __NR_msync		144
-#define __NR_readv              145
-#define __NR_writev             146
-#define __NR_getsid             147
-#define __NR_fdatasync          148
-#define __NR__sysctl            149
-#define __NR_mlock              150
-#define __NR_munlock            151
-#define __NR_mlockall           152
-#define __NR_munlockall         153
-#define __NR_sched_setparam     154
-#define __NR_sched_getparam     155
-#define __NR_sched_setscheduler 156
-#define __NR_sched_getscheduler 157
-#define __NR_sched_yield        158
-#define __NR_sched_get_priority_max 159
-#define __NR_sched_get_priority_min 160
-#define __NR_sched_rr_get_interval 161
-#define __NR_nanosleep          162
-#define __NR_mremap             163
-
-#ifndef _LIBC
-#define SYS_setup		  0
-#define SYS_exit		  1
-#define SYS_fork		  2
-#define SYS_read		  3
-#define SYS_write		  4
-#define SYS_open		  5
-#define SYS_close		  6
-#define SYS_waitpid		  7
-#define SYS_creat		  8
-#define SYS_link		  9
-#define SYS_unlink		 10
-#define SYS_execve		 11
-#define SYS_chdir		 12
-#define SYS_time		 13
-#define SYS_mknod		 14
-#define SYS_chmod		 15
-#define SYS_chown		 16
-#define SYS_break		 17
-#define SYS_oldstat		 18
-#define SYS_lseek		 19
-#define SYS_getpid		 20
-#define SYS_mount		 21
-#define SYS_umount		 22
-#define SYS_setuid		 23
-#define SYS_getuid		 24
-#define SYS_stime		 25
-#define SYS_ptrace		 26
-#define SYS_alarm		 27
-#define SYS_oldfstat		 28
-#define SYS_pause		 29
-#define SYS_utime		 30
-#define SYS_stty		 31
-#define SYS_gtty		 32
-#define SYS_access		 33
-#define SYS_nice		 34
-#define SYS_ftime		 35
-#define SYS_sync		 36
-#define SYS_kill		 37
-#define SYS_rename		 38
-#define SYS_mkdir		 39
-#define SYS_rmdir		 40
-#define SYS_dup		 41
-#define SYS_pipe		 42
-#define SYS_times		 43
-#define SYS_prof		 44
-#define SYS_brk		 45
-#define SYS_setgid		 46
-#define SYS_getgid		 47
-#define SYS_signal		 48
-#define SYS_geteuid		 49
-#define SYS_getegid		 50
-#define SYS_acct		 51
-#define SYS_phys		 52
-#define SYS_lock		 53
-#define SYS_ioctl		 54
-#define SYS_fcntl		 55
-#define SYS_mpx		 56
-#define SYS_setpgid		 57
-#define SYS_ulimit		 58
-#define SYS_oldolduname	 59
-#define SYS_umask		 60
-#define SYS_chroot		 61
-#define SYS_ustat		 62
-#define SYS_dup2		 63
-#define SYS_getppid		 64
-#define SYS_getpgrp		 65
-#define SYS_setsid		 66
-#define SYS_sigaction		 67
-#define SYS_sgetmask		 68
-#define SYS_ssetmask		 69
-#define SYS_setreuid		 70
-#define SYS_setregid		 71
-#define SYS_sigsuspend		 72
-#define SYS_sigpending		 73
-#define SYS_sethostname	 74
-#define SYS_setrlimit		 75
-#define SYS_getrlimit		 76
-#define SYS_getrusage		 77
-#define SYS_gettimeofday	 78
-#define SYS_settimeofday	 79
-#define SYS_getgroups		 80
-#define SYS_setgroups		 81
-#define SYS_select		 82
-#define SYS_symlink		 83
-#define SYS_oldlstat		 84
-#define SYS_readlink		 85
-#define SYS_uselib		 86
-#define SYS_swapon		 87
-#define SYS_reboot		 88
-#define SYS_readdir		 89
-#define SYS_mmap		 90
-#define SYS_munmap		 91
-#define SYS_truncate		 92
-#define SYS_ftruncate		 93
-#define SYS_fchmod		 94
-#define SYS_fchown		 95
-#define SYS_getpriority	 96
-#define SYS_setpriority	 97
-#define SYS_profil		 98
-#define SYS_statfs		 99
-#define SYS_fstatfs		100
-#define SYS_ioperm		101
-#define SYS_socketcall		102
-#define SYS_syslog		103
-#define SYS_setitimer		104
-#define SYS_getitimer		105
-#define SYS_stat		106
-#define SYS_lstat		107
-#define SYS_fstat		108
-#define SYS_olduname		109
-#define SYS_iopl		110
-#define SYS_vhangup		111
-#define SYS_idle		112
-#define SYS_vm86		113
-#define SYS_wait4		114
-#define SYS_swapoff		115
-#define SYS_sysinfo		116
-#define SYS_ipc		117
-#define SYS_fsync		118
-#define SYS_sigreturn		119
-#define SYS_clone		120
-#define SYS_setdomainname	121
-#define SYS_uname		122
-#define SYS_modify_ldt		123
-#define SYS_adjtimex		124
-#define SYS_mprotect		125
-#define SYS_sigprocmask	126
-#define SYS_create_module	127
-#define SYS_init_module	128
-#define SYS_delete_module	129
-#define SYS_get_kernel_syms	130
-#define SYS_quotactl		131
-#define SYS_getpgid		132
-#define SYS_fchdir		133
-#define SYS_bdflush		134
-#define SYS_sysfs		135
-#define SYS_personality	136
-#define SYS_afs_syscall	137 /* Syscall for Andrew File System */
-#define SYS_setfsuid		138
-#define SYS_setfsgid		139
-#define SYS__llseek		140
-#define SYS_getdents		141
-#define SYS__newselect		142
-#define SYS_flock		143
-#define SYS_msync		144
-#define SYS_readv              145
-#define SYS_writev             146
-#define SYS_getsid             147
-#define SYS_fdatasync          148
-#define SYS__sysctl            149
-#define SYS_mlock              150
-#define SYS_munlock            151
-#define SYS_mlockall           152
-#define SYS_munlockall         153
-#define SYS_sched_setparam     154
-#define SYS_sched_getparam     155
-#define SYS_sched_setscheduler 156
-#define SYS_sched_getscheduler 157
-#define SYS_sched_yield        158
-#define SYS_sched_get_priority_max 159
-#define SYS_sched_get_priority_min 160
-#define SYS_sched_rr_get_interval 161
-#define SYS_nanosleep          162
-#define SYS_mremap             163
-#endif
-
-#endif
diff --git a/sysdeps/unix/sysv/linux/rt_sigsuspend.c b/sysdeps/unix/sysv/linux/rt_sigsuspend.c
index dc32dcc067..f6f4987cd1 100644
--- a/sysdeps/unix/sysv/linux/rt_sigsuspend.c
+++ b/sysdeps/unix/sysv/linux/rt_sigsuspend.c
@@ -1,4 +1,4 @@
-/* Copyright (C) 1997 Free Software Foundation, Inc.
+/* Copyright (C) 1997, 1998 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
@@ -18,6 +18,8 @@
 
 #include <errno.h>
 #include <signal.h>
+#define __need_NULL
+#include <stddef.h>
 
 int
 __syscall_rt_sigsuspend (const sigset_t *set, size_t setsize)
diff --git a/sysdeps/unix/sysv/linux/rt_sigtimedwait.c b/sysdeps/unix/sysv/linux/rt_sigtimedwait.c
index 4513026f44..3bf9834fa7 100644
--- a/sysdeps/unix/sysv/linux/rt_sigtimedwait.c
+++ b/sysdeps/unix/sysv/linux/rt_sigtimedwait.c
@@ -1,4 +1,4 @@
-/* Copyright (C) 1997 Free Software Foundation, Inc.
+/* Copyright (C) 1997, 1998 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
@@ -18,6 +18,8 @@
 
 #include <errno.h>
 #include <signal.h>
+#define __need_NULL
+#include <stddef.h>
 
 int
 __syscall_rt_sigtimedwait (const sigset_t *set, siginfo_t *info,
diff --git a/sysdeps/unix/sysv/linux/sigwaitinfo.c b/sysdeps/unix/sysv/linux/sigwaitinfo.c
index 5f41ba054b..da4624e53e 100644
--- a/sysdeps/unix/sysv/linux/sigwaitinfo.c
+++ b/sysdeps/unix/sysv/linux/sigwaitinfo.c
@@ -1,4 +1,4 @@
-/* Copyright (C) 1997 Free Software Foundation, Inc.
+/* Copyright (C) 1997, 1998 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
@@ -17,6 +17,8 @@
    Boston, MA 02111-1307, USA.  */
 
 #include <signal.h>
+#define __need_NULL
+#include <stddef.h>
 
 extern int __syscall_rt_sigtimedwait (const sigset_t *, siginfo_t *,
 				      const struct timespec *, size_t);
diff --git a/sysdeps/unix/sysv/linux/updwtmp.c b/sysdeps/unix/sysv/linux/updwtmp.c
new file mode 100644
index 0000000000..e2156a123b
--- /dev/null
+++ b/sysdeps/unix/sysv/linux/updwtmp.c
@@ -0,0 +1,34 @@
+/* Copyright (C) 1998 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+   Contributed by Mark Kettenis <kettenis@phys.uva.nl>, 1998.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Library General Public License as
+   published by the Free Software Foundation; either version 2 of the
+   License, or (at your option) any later version.
+
+   The GNU C Library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   Library General Public License for more details.
+
+   You should have received a copy of the GNU Library General Public
+   License along with the GNU C Library; see the file COPYING.LIB.  If not,
+   write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+   Boston, MA 02111-1307, USA.  */
+
+#include <string.h>
+#include <unistd.h>
+
+#define TRANSFORM_UTMP_FILE_NAME(file_name) \
+    ((strcmp (file_name, _PATH_UTMP) == 0 \
+      && __access (_PATH_UTMP "x", F_OK) == 0) ? (_PATH_UTMP "x") : \
+     ((strcmp (file_name, _PATH_WTMP) == 0 \
+       && __access ( _PATH_WTMP "x", F_OK) == 0) ? (_PATH_WTMP "x") : \
+      ((strcmp (file_name, _PATH_UTMP "x") == 0 \
+	&& __access (_PATH_UTMP "x", F_OK) != 0) ? _PATH_UTMP : \
+       ((strcmp (file_name, _PATH_WTMP "x") == 0 \
+	 && __access (_PATH_WTMP "x", F_OK) != 0) ? _PATH_WTMP : \
+	file_name))))
+
+#include <sysdeps/generic/updwtmp.c>
diff --git a/sysdeps/unix/sysv/linux/utmp_file.c b/sysdeps/unix/sysv/linux/utmp_file.c
new file mode 100644
index 0000000000..5775270123
--- /dev/null
+++ b/sysdeps/unix/sysv/linux/utmp_file.c
@@ -0,0 +1,34 @@
+/* Copyright (C) 1998 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+   Contributed by Mark Kettenis <kettenis@phys.uva.nl>, 1998.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Library General Public License as
+   published by the Free Software Foundation; either version 2 of the
+   License, or (at your option) any later version.
+
+   The GNU C Library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   Library General Public License for more details.
+
+   You should have received a copy of the GNU Library General Public
+   License along with the GNU C Library; see the file COPYING.LIB.  If not,
+   write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+   Boston, MA 02111-1307, USA.  */
+
+#include <string.h>
+#include <unistd.h>
+
+#define TRANSFORM_UTMP_FILE_NAME(file_name) \
+    ((strcmp (file_name, _PATH_UTMP) == 0 \
+      && __access (_PATH_UTMP "x", F_OK) == 0) ? (_PATH_UTMP "x") : \
+     ((strcmp (file_name, _PATH_WTMP) == 0 \
+       && __access ( _PATH_WTMP "x", F_OK) == 0) ? (_PATH_WTMP "x") : \
+      ((strcmp (file_name, _PATH_UTMP "x") == 0 \
+	&& __access (_PATH_UTMP "x", F_OK) != 0) ? _PATH_UTMP : \
+       ((strcmp (file_name, _PATH_WTMP "x") == 0 \
+	 && __access (_PATH_WTMP "x", F_OK) != 0) ? _PATH_WTMP : \
+	file_name))))
+
+#include <sysdeps/generic/utmp_file.c>
diff --git a/wcsmbs/btowc.c b/wcsmbs/btowc.c
index 7efe62e5f1..b40a98f65b 100644
--- a/wcsmbs/btowc.c
+++ b/wcsmbs/btowc.c
@@ -31,7 +31,7 @@ __btowc (c)
   char buf[sizeof (wchar_t)];
   struct gconv_step_data data;
   char inbuf[1];
-  size_t inbytes;
+  char *inptr = inbuf;
   size_t converted;
   int status;
 
@@ -42,8 +42,7 @@ __btowc (c)
 
   /* Tell where we want the result.  */
   data.outbuf = (char *) buf;
-  data.outbufavail = 0;
-  data.outbufsize = sizeof (wchar_t);
+  data.outbufend = data.outbuf + sizeof (wchar_t);
   data.is_last = 1;
   data.statep = &data.__state;
 
@@ -55,10 +54,9 @@ __btowc (c)
 
   /* Create the input string.  */
   inbuf[0] = c;
-  inbytes = 1;
 
   status = (*__wcsmbs_gconv_fcts.towc->fct) (__wcsmbs_gconv_fcts.towc,
-					     &data, inbuf, &inbytes,
+					     &data, &inptr, inptr + 1,
 					     &converted, 0);
   /* The conversion failed.  */
   if (status != GCONV_OK && status != GCONV_FULL_OUTPUT
diff --git a/wcsmbs/mbrtowc.c b/wcsmbs/mbrtowc.c
index 14ca0b0975..1dcaf968ea 100644
--- a/wcsmbs/mbrtowc.c
+++ b/wcsmbs/mbrtowc.c
@@ -36,14 +36,15 @@ __mbrtowc (wchar_t *pwc, const char *s, size_t n, mbstate_t *ps)
 {
   wchar_t buf[1];
   struct gconv_step_data data;
-  size_t inbytes;
   int status;
   size_t result;
+  size_t dummy;
+  const char *inbuf;
+  char *outbuf = (char *) (pwc ?: buf);
 
   /* Tell where we want the result.  */
-  data.outbuf = (char *) (pwc ?: buf);
-  data.outbufavail = 0;
-  data.outbufsize = sizeof (wchar_t);
+  data.outbuf = outbuf;
+  data.outbufend = outbuf + sizeof (wchar_t);
   data.is_last = 1;
   data.statep = ps ?: &state;
 
@@ -60,9 +61,10 @@ __mbrtowc (wchar_t *pwc, const char *s, size_t n, mbstate_t *ps)
   update_conversion_ptrs ();
 
   /* Do a normal conversion.  */
-  inbytes = n;
+  inbuf = s;
   status = (*__wcsmbs_gconv_fcts.towc->fct) (__wcsmbs_gconv_fcts.towc,
-					     &data, s, &inbytes, NULL, 0);
+					     &data, &inbuf, inbuf + n,
+					     &dummy, 0);
 
   /* There must not be any problems with the conversion but illegal input
      characters.  The output buffer must be large enough, otherwise the
@@ -76,14 +78,14 @@ __mbrtowc (wchar_t *pwc, const char *s, size_t n, mbstate_t *ps)
   if (status == GCONV_OK || status == GCONV_EMPTY_INPUT
       || status == GCONV_FULL_OUTPUT)
     {
-      if (data.outbufavail > 0 && *(wchar_t *)data.outbuf == L'\0')
+      if (data.outbuf != outbuf && *(wchar_t *)data.outbuf == L'\0')
 	{
 	  /* The converted character is the NUL character.  */
 	  assert (__mbsinit (data.statep));
 	  result = 0;
 	}
       else
-	result = n - inbytes;
+	result = inbuf - s;
     }
   else
     {
diff --git a/wcsmbs/mbsnrtowcs.c b/wcsmbs/mbsnrtowcs.c
index d408b39430..46a718b3f5 100644
--- a/wcsmbs/mbsnrtowcs.c
+++ b/wcsmbs/mbsnrtowcs.c
@@ -44,7 +44,7 @@ __mbsnrtowcs (dst, src, nmc, len, ps)
      size_t len;
      mbstate_t *ps;
 {
-  size_t inbytes_in;
+  const char *srcend;
   struct gconv_step_data data;
   size_t result = 0;
   int status;
@@ -55,7 +55,7 @@ __mbsnrtowcs (dst, src, nmc, len, ps)
 
   if (nmc == 0)
     return 0;
-  inbytes_in = __strnlen (*src, nmc - 1) + 1;
+  srcend = *src + __strnlen (*src, nmc - 1) + 1;
 
   /* Make sure we use the correct function.  */
   update_conversion_ptrs ();
@@ -64,21 +64,15 @@ __mbsnrtowcs (dst, src, nmc, len, ps)
   if (dst == NULL)
     {
       wchar_t buf[64];		/* Just an arbitrary size.  */
-      size_t inbytes = inbytes_in;
       const char *inbuf = *src;
       size_t written;
 
       data.outbuf = (char *) buf;
-      data.outbufsize = sizeof (buf);
+      data.outbufend = data.outbuf + sizeof (buf);
       do
 	{
-	  inbuf += inbytes_in - inbytes;
-	  inbytes_in = inbytes;
-	  data.outbufavail = 0;
-	  written = 0;
-
 	  status = (*__wcsmbs_gconv_fcts.towc->fct) (__wcsmbs_gconv_fcts.towc,
-						     &data, inbuf, &inbytes,
+						     &data, &inbuf, srcend,
 						     &written, 0);
 	  result += written;
 	}
@@ -94,14 +88,11 @@ __mbsnrtowcs (dst, src, nmc, len, ps)
       /* This code is based on the safe assumption that all internal
 	 multi-byte encodings use the NUL byte only to mark the end
 	 of the string.  */
-      size_t inbytes = inbytes_in;
-
       data.outbuf = (char *) dst;
-      data.outbufsize = len * sizeof (wchar_t);
-      data.outbufavail = 0;
+      data.outbufend = data.outbuf + len * sizeof (wchar_t);
 
       status = (*__wcsmbs_gconv_fcts.towc->fct) (__wcsmbs_gconv_fcts.towc,
-						 &data, *src, &inbytes,
+						 &data, src, srcend,
 						 &result, 0);
 
       /* We have to determine whether the last character converted
@@ -114,8 +105,6 @@ __mbsnrtowcs (dst, src, nmc, len, ps)
 	  *src = NULL;
 	  --result;
 	}
-      else
-	*src += inbytes_in - inbytes;
     }
 
   /* There must not be any problems with the conversion but illegal input
diff --git a/wcsmbs/mbsrtowcs.c b/wcsmbs/mbsrtowcs.c
index 8f9efb3285..9172fd9ede 100644
--- a/wcsmbs/mbsrtowcs.c
+++ b/wcsmbs/mbsrtowcs.c
@@ -19,6 +19,7 @@
 
 #include <errno.h>
 #include <gconv.h>
+#include <stdlib.h>
 #include <string.h>
 #include <wchar.h>
 #include <wcsmbsload.h>
@@ -55,22 +56,16 @@ __mbsrtowcs (dst, src, len, ps)
   if (dst == NULL)
     {
       wchar_t buf[64];		/* Just an arbitrary size.  */
-      size_t inbytes_in = strlen (*src) + 1;
-      size_t inbytes = inbytes_in;
+      const char *srcend = *src + strlen (*src) + 1;
       const char *inbuf = *src;
       size_t written;
 
       data.outbuf = (char *) buf;
-      data.outbufsize = sizeof (buf);
+      data.outbufend = data.outbuf + sizeof (buf);
       do
 	{
-	  inbuf += inbytes_in - inbytes;
-	  inbytes_in = inbytes;
-	  data.outbufavail = 0;
-	  written = 0;
-
 	  status = (*__wcsmbs_gconv_fcts.towc->fct) (__wcsmbs_gconv_fcts.towc,
-						     &data, inbuf, &inbytes,
+						     &data, &inbuf, srcend,
 						     &written, 0);
 	  result += written;
 	}
@@ -86,15 +81,13 @@ __mbsrtowcs (dst, src, len, ps)
       /* This code is based on the safe assumption that all internal
 	 multi-byte encodings use the NUL byte only to mark the end
 	 of the string.  */
-      size_t inbytes_in = __strnlen (*src, len * MB_CUR_MAX) + 1;
-      size_t inbytes = inbytes_in;
+      const char *srcend = *src + __strnlen (*src, len * MB_CUR_MAX) + 1;
 
       data.outbuf = (char *) dst;
-      data.outbufsize = len * sizeof (wchar_t);
-      data.outbufavail = 0;
+      data.outbufend = data.outbuf + len * sizeof (wchar_t);
 
       status = (*__wcsmbs_gconv_fcts.towc->fct) (__wcsmbs_gconv_fcts.towc,
-						 &data, *src, &inbytes,
+						 &data, src, srcend,
 						 &result, 0);
 
       /* We have to determine whether the last character converted
@@ -107,8 +100,6 @@ __mbsrtowcs (dst, src, len, ps)
 	  *src = NULL;
 	  --result;
 	}
-      else
-	*src += inbytes_in - inbytes;
     }
 
   /* There must not be any problems with the conversion but illegal input
diff --git a/wcsmbs/wcrtomb.c b/wcsmbs/wcrtomb.c
index dcc2ef67cd..6fd33e06b3 100644
--- a/wcsmbs/wcrtomb.c
+++ b/wcsmbs/wcrtomb.c
@@ -40,11 +40,11 @@ __wcrtomb (char *s, wchar_t wc, mbstate_t *ps)
   struct gconv_step_data data;
   int status;
   size_t result;
+  size_t dummy;
 
   /* Tell where we want the result.  */
   data.outbuf = s;
-  data.outbufavail = 0;
-  data.outbufsize = MB_CUR_MAX;
+  data.outbufend = s + MB_CUR_MAX;
   data.is_last = 1;
   data.statep = ps ?: &state;
 
@@ -64,23 +64,21 @@ __wcrtomb (char *s, wchar_t wc, mbstate_t *ps)
      by a NUL byte.  */
   if (wc == L'\0')
     {
-      size_t inbytes = 0;
-
       status = (*__wcsmbs_gconv_fcts.tomb->fct) (__wcsmbs_gconv_fcts.tomb,
-						 &data, NULL, &inbytes,
-						 NULL, 1);
+						 &data, NULL, NULL, &dummy, 1);
 
       if (status == GCONV_OK || status == GCONV_EMPTY_INPUT)
-	data.outbuf[data.outbufavail++] = '\0';
+	*data.outbuf++ = '\0';
     }
   else
     {
       /* Do a normal conversion.  */
-      size_t inbytes = sizeof (wchar_t);
+      const char *inbuf = (const char *) &wc;
 
       status = (*__wcsmbs_gconv_fcts.tomb->fct) (__wcsmbs_gconv_fcts.tomb,
-						 &data, (char *) &wc, &inbytes,
-						 NULL, 0);
+						 &data, &inbuf,
+						 inbuf + sizeof (wchar_t),
+						 &dummy, 0);
     }
 
   /* There must not be any problems with the conversion but illegal input
@@ -94,7 +92,7 @@ __wcrtomb (char *s, wchar_t wc, mbstate_t *ps)
 
   if (status == GCONV_OK || status == GCONV_EMPTY_INPUT
       || status == GCONV_FULL_OUTPUT)
-    result = data.outbufavail;
+    result = data.outbuf - s;
   else
     {
       result = (size_t) -1;
diff --git a/wcsmbs/wcsmbsload.c b/wcsmbs/wcsmbsload.c
index c7e5651fe6..f4babc4eb3 100644
--- a/wcsmbs/wcsmbsload.c
+++ b/wcsmbs/wcsmbsload.c
@@ -37,8 +37,8 @@ static struct gconv_step to_wc =
   shlib_handle: NULL,
   modname: NULL,
   counter: INT_MAX,
-  from_name: "ANSI_X3.4-1968",
-  to_name: "#INTERNAL#",
+  from_name: "ANSI_X3.4-1968//",
+  to_name: "INTERNAL",
   fct: __gconv_transform_ascii_internal,
   init_fct: NULL,
   end_fct: NULL,
@@ -50,8 +50,8 @@ static struct gconv_step to_mb =
   shlib_handle: NULL,
   modname: NULL,
   counter: INT_MAX,
-  from_name: "#INTERNAL#",
-  to_name: "ANSI_X3.4-1968",
+  from_name: "INTERNAL",
+  to_name: "ANSI_X3.4-1968//",
   fct: __gconv_transform_internal_ascii,
   init_fct: NULL,
   end_fct: NULL,
@@ -113,8 +113,8 @@ __wcsmbs_load_conv (const struct locale_data *new_category)
 	  /* Get name of charset of the locale.  */
 	  charset_name = new_category->values[_NL_ITEM_INDEX(CODESET)].string;
 
-	  __wcsmbs_gconv_fcts.tomb = getfct (charset_name, "#INTERNAL#");
-	  __wcsmbs_gconv_fcts.towc = getfct ("#INTERNAL#", charset_name);
+	  __wcsmbs_gconv_fcts.tomb = getfct (charset_name, "INTERNAL");
+	  __wcsmbs_gconv_fcts.towc = getfct ("INTERNAL", charset_name);
 
 	  /* If any of the conversion functions is not available we don't
 	     use any since this would mean we cannot convert back and
diff --git a/wcsmbs/wcsnrtombs.c b/wcsmbs/wcsnrtombs.c
index 0daf0e3077..4b6232a182 100644
--- a/wcsmbs/wcsnrtombs.c
+++ b/wcsmbs/wcsnrtombs.c
@@ -44,7 +44,7 @@ __wcsnrtombs (dst, src, nwc, len, ps)
      mbstate_t *ps;
 {
   struct gconv_step_data data;
-  size_t inbytes_in;
+  const wchar_t *srcend;
   int status;
   size_t result;
 
@@ -54,7 +54,7 @@ __wcsnrtombs (dst, src, nwc, len, ps)
 
   if (nwc == 0)
     return 0;
-  inbytes_in = (__wcsnlen (*src, nwc - 1) + 1) * sizeof (wchar_t);
+  srcend = *src + __wcsnlen (*src, nwc - 1) + 1;
 
   /* Make sure we use the correct function.  */
   update_conversion_ptrs ();
@@ -63,30 +63,25 @@ __wcsnrtombs (dst, src, nwc, len, ps)
   if (dst == NULL)
     {
       char buf[256];		/* Just an arbitrary value.  */
-      size_t inbytes = inbytes_in;
       const wchar_t *inbuf = *src;
       size_t written;
 
       data.outbuf = buf;
-      data.outbufsize = sizeof (buf);
+      data.outbufend = buf + sizeof (buf);
 
       do
 	{
-	  inbuf += (inbytes_in - inbytes) / sizeof (wchar_t);
-	  inbytes_in = inbytes;
-	  data.outbufavail = 0;
-	  written = 0;
-
 	  status = (*__wcsmbs_gconv_fcts.tomb->fct) (__wcsmbs_gconv_fcts.tomb,
 						     &data,
-						     (const char *) inbuf,
-						     &inbytes, &written, 0);
+						     (const char **) &inbuf,
+						     (const char *) srcend,
+						     &written, 0);
 	  result += written;
 	}
       while (status == GCONV_FULL_OUTPUT);
 
       if ((status == GCONV_OK || status == GCONV_EMPTY_INPUT)
-	  && buf[data.outbufavail - 1] == '\0')
+	  && data.outbuf[-1] == '\0')
 	/* Don't count the NUL character in.  */
 	--result;
     }
@@ -95,28 +90,24 @@ __wcsnrtombs (dst, src, nwc, len, ps)
       /* This code is based on the safe assumption that all internal
 	 multi-byte encodings use the NUL byte only to mark the end
 	 of the string.  */
-      size_t inbytes = inbytes_in;
-
       data.outbuf = dst;
-      data.outbufavail = 0;
-      data.outbufsize = len;
+      data.outbufend = dst + len;
 
       status = (*__wcsmbs_gconv_fcts.tomb->fct) (__wcsmbs_gconv_fcts.tomb,
-						 &data, (const char *) *src,
-						 &inbytes, &result, 0);
+						 &data, (const char **) src,
+						 (const char *) srcend,
+						 &result, 0);
 
       /* We have to determine whether the last character converted
 	 is the NUL character.  */
       if ((status == GCONV_OK || status == GCONV_EMPTY_INPUT)
-	  && dst[data.outbufavail - 1] == '\0')
+	  && data.outbuf[-1] == '\0')
 	{
-	  assert (data.outbufavail > 0);
+	  assert (data.outbuf != dst);
 	  assert (__mbsinit (data.statep));
 	  *src = NULL;
 	  --result;
 	}
-      else
-	*src += result;
     }
 
   /* There must not be any problems with the conversion but illegal input
diff --git a/wcsmbs/wcsrtombs.c b/wcsmbs/wcsrtombs.c
index 7b59fc725a..428ef3d4dd 100644
--- a/wcsmbs/wcsrtombs.c
+++ b/wcsmbs/wcsrtombs.c
@@ -55,31 +55,26 @@ __wcsrtombs (dst, src, len, ps)
   if (dst == NULL)
     {
       char buf[256];		/* Just an arbitrary value.  */
-      size_t inbytes_in = (__wcslen (*src) + 1) * sizeof (wchar_t);
-      size_t inbytes = inbytes_in;
+      const wchar_t *srcend = *src + __wcslen (*src) + 1;
       const wchar_t *inbuf = *src;
       size_t written;
 
       data.outbuf = buf;
-      data.outbufsize = sizeof (buf);
+      data.outbufend = buf + sizeof (buf);
 
       do
 	{
-	  inbuf += (inbytes_in - inbytes) / sizeof (wchar_t);
-	  inbytes_in = inbytes;
-	  data.outbufavail = 0;
-	  written = 0;
-
 	  status = (*__wcsmbs_gconv_fcts.tomb->fct) (__wcsmbs_gconv_fcts.tomb,
 						     &data,
-						     (const char *) inbuf,
-						     &inbytes, &written, 0);
+						     (const char **) &inbuf,
+						     (const char *) srcend,
+						     &written, 0);
 	  result += written;
 	}
       while (status == GCONV_FULL_OUTPUT);
 
       if ((status == GCONV_OK || status == GCONV_EMPTY_INPUT)
-	  && buf[data.outbufavail - 1] == '\0')
+	  && data.outbuf[-1] == '\0')
 	/* Don't count the NUL character in.  */
 	--result;
     }
@@ -88,31 +83,27 @@ __wcsrtombs (dst, src, len, ps)
       /* This code is based on the safe assumption that all internal
 	 multi-byte encodings use the NUL byte only to mark the end
 	 of the string.  */
-      size_t inbytes_in = ((__wcsnlen (*src, len * MB_CUR_MAX) + 1)
-			   * sizeof (wchar_t));
-      size_t inbytes = inbytes_in;
+      const wchar_t *srcend = *src + __wcsnlen (*src, len * MB_CUR_MAX) + 1;
 
       data.outbuf = dst;
-      data.outbufavail = 0;
-      data.outbufsize = len;
+      data.outbufend = dst + len;
 
       status = (*__wcsmbs_gconv_fcts.tomb->fct) (__wcsmbs_gconv_fcts.tomb,
-						 &data, (const char *) *src,
-						 &inbytes, &result, 0);
+						 &data, (const char **) src,
+						 (const char *) srcend,
+						 &result, 0);
 
       /* We have to determine whether the last character converted
 	 is the NUL character.  */
       if ((status == GCONV_OK || status == GCONV_EMPTY_INPUT
 	   || status == GCONV_FULL_OUTPUT)
-	  && dst[data.outbufavail - 1] == '\0')
+	  && data.outbuf[-1] == '\0')
 	{
-	  assert (data.outbufavail > 0);
+	  assert (data.outbuf != dst);
 	  assert (__mbsinit (data.statep));
 	  *src = NULL;
 	  --result;
 	}
-      else
-	*src += result;
     }
 
   /* There must not be any problems with the conversion but illegal input
diff --git a/wcsmbs/wctob.c b/wcsmbs/wctob.c
index e70b4e7fe6..b06d170388 100644
--- a/wcsmbs/wctob.c
+++ b/wcsmbs/wctob.c
@@ -31,14 +31,13 @@ wctob (c)
   char buf[MB_LEN_MAX];
   struct gconv_step_data data;
   wchar_t inbuf[1];
-  size_t inbytes;
+  wchar_t *inptr = inbuf;
   size_t converted;
   int status;
 
   /* Tell where we want the result.  */
-  data.outbuf = (char *) buf;
-  data.outbufavail = 0;
-  data.outbufsize = MB_LEN_MAX;
+  data.outbuf = buf;
+  data.outbufend = buf + MB_LEN_MAX;
   data.is_last = 1;
   data.statep = &data.__state;
 
@@ -50,15 +49,15 @@ wctob (c)
 
   /* Create the input string.  */
   inbuf[0] = c;
-  inbytes = sizeof (wchar_t);
 
   status = (*__wcsmbs_gconv_fcts.tomb->fct) (__wcsmbs_gconv_fcts.tomb, &data,
-					     (const char *) inbuf, &inbytes,
+					     (const char **) &inptr,
+					     (const char *) &inbuf[1],
 					     &converted, 0);
   /* The conversion failed or the output is too long.  */
   if ((status != GCONV_OK && status != GCONV_FULL_OUTPUT
        && status != GCONV_EMPTY_INPUT)
-      || data.outbufavail != 1)
+      || data.outbuf != buf + 1)
     return EOF;
 
   return buf[0];