Forward port eglibc options groups support

Upstream-Status: Pending

Index: git/argp/argp-fmtstream.c
===================================================================
--- git.orig/argp/argp-fmtstream.c
+++ git/argp/argp-fmtstream.c
@@ -42,6 +42,7 @@
 #ifdef _LIBC
 # include <wchar.h>
 # include <libio/libioP.h>
+# include <gnu/option-groups.h>
 # define __vsnprintf(s, l, f, a) _IO_vsnprintf (s, l, f, a)
 #endif
 
@@ -100,7 +101,11 @@ __argp_fmtstream_free (argp_fmtstream_t
   __argp_fmtstream_update (fs);
   if (fs->p > fs->buf)
     {
+#ifdef _LIBC
       __fxprintf (fs->stream, "%.*s", (int) (fs->p - fs->buf), fs->buf);
+#else
+      fwrite_unlocked (fs->buf, 1, fs->p - fs->buf, fs->stream);
+#endif
     }
   free (fs->buf);
   free (fs);
@@ -145,9 +150,17 @@ __argp_fmtstream_update (argp_fmtstream_
 	      size_t i;
 	      for (i = 0; i < pad; i++)
 		{
+#ifdef _LIBC
 		  if (_IO_fwide (fs->stream, 0) > 0)
-		    putwc_unlocked (L' ', fs->stream);
+                    {
+#if ! _LIBC || __OPTION_POSIX_WIDE_CHAR_DEVICE_IO
+                      putwc_unlocked (L' ', fs->stream);
+#else
+                      abort ();
+#endif
+                    }
 		  else
+#endif
 		    putc_unlocked (' ', fs->stream);
 		}
 	    }
@@ -308,9 +321,17 @@ __argp_fmtstream_update (argp_fmtstream_
 	      *nl++ = ' ';
 	  else
 	    for (i = 0; i < fs->wmargin; ++i)
+#ifdef _LIBC
 	      if (_IO_fwide (fs->stream, 0) > 0)
-		putwc_unlocked (L' ', fs->stream);
+                {
+#ifdef OPTION_POSIX_WIDE_CHAR_DEVICE_IO
+                  putwc_unlocked (L' ', fs->stream);
+#else
+                  abort ();
+#endif
+                }
 	      else
+#endif
 		putc_unlocked (' ', fs->stream);
 
 	  /* Copy the tail of the original buffer into the current buffer
Index: git/argp/argp-help.c
===================================================================
--- git.orig/argp/argp-help.c
+++ git/argp/argp-help.c
@@ -51,6 +51,7 @@ char *alloca ();
 #ifdef _LIBC
 # include <../libio/libioP.h>
 # include <wchar.h>
+# include <gnu/option-groups.h>
 #endif
 
 #ifndef _
@@ -1702,7 +1703,7 @@ char *__argp_basename (char *name)
 }
 
 char *
-__argp_short_program_name (void)
+(__argp_short_program_name) (void)
 {
 # if HAVE_DECL_PROGRAM_INVOCATION_SHORT_NAME
   return program_invocation_short_name;
@@ -1873,9 +1874,17 @@ __argp_failure (const struct argp_state
 #endif
 	    }
 
+#ifdef _LIBC
 	  if (_IO_fwide (stream, 0) > 0)
-	    putwc_unlocked (L'\n', stream);
+            {
+#if ! _LIBC || __OPTION_POSIX_WIDE_CHAR_DEVICE_IO
+              putwc_unlocked (L'\n', stream);
+#else
+              abort ();
+#endif
+            }
 	  else
+#endif
 	    putc_unlocked ('\n', stream);
 
 #if _LIBC || (HAVE_FLOCKFILE && HAVE_FUNLOCKFILE)
Index: git/argp/argp-namefrob.h
===================================================================
--- git.orig/argp/argp-namefrob.h
+++ git/argp/argp-namefrob.h
@@ -76,10 +76,12 @@
 #undef __argp_fmtstream_wmargin
 #define __argp_fmtstream_wmargin argp_fmtstream_wmargin
 
+#if 0
 #include "mempcpy.h"
 #include "strcase.h"
 #include "strchrnul.h"
 #include "strndup.h"
+#endif
 
 /* normal libc functions we call */
 #undef __flockfile
Index: git/argp/Makefile
===================================================================
--- git.orig/argp/Makefile
+++ git/argp/Makefile
@@ -18,6 +18,8 @@
 #
 #	Makefile for argp.
 #
+include ../option-groups.mak
+
 subdir	:= argp
 
 include ../Makeconfig
Index: git/catgets/Makefile
===================================================================
--- git.orig/catgets/Makefile
+++ git/catgets/Makefile
@@ -22,20 +22,23 @@ subdir	:= catgets
 
 include ../Makeconfig
 
+include ../option-groups.mak
+
 headers		= nl_types.h
-routines	= catgets open_catalog
-others		= gencat
-install-bin	= gencat
-extra-objs	= $(gencat-modules:=.o)
+routines-$(OPTION_EGLIBC_CATGETS)    := catgets open_catalog
+others-$(OPTION_EGLIBC_CATGETS)      := gencat
+install-bin-$(OPTION_EGLIBC_CATGETS) := gencat
+extra-objs-$(OPTION_EGLIBC_CATGETS)  := $(gencat-modules:=.o)
 
-tests = tst-catgets
-test-srcs = test-gencat
+tests-$(OPTION_EGLIBC_CATGETS)       := tst-catgets
+test-srcs-$(OPTION_EGLIBC_CATGETS)   := test-gencat
 
+ifeq (y,$(OPTION_EGLIBC_CATGETS))
 ifeq ($(run-built-tests),yes)
 tests-special += $(objpfx)de/libc.cat $(objpfx)test1.cat $(objpfx)test2.cat \
 		 $(objpfx)sample.SJIS.cat $(objpfx)test-gencat.out
 endif
-
+endif
 gencat-modules	= xmalloc
 
 # To find xmalloc.c
Index: git/crypt/crypt-entry.c
===================================================================
--- git.orig/crypt/crypt-entry.c
+++ git/crypt/crypt-entry.c
@@ -27,6 +27,7 @@
 #include <stdio.h>
 #endif
 #include <string.h>
+#include <gnu/option-groups.h>
 #include <errno.h>
 #include <fips-private.h>
 
@@ -76,9 +77,11 @@ __crypt_r (key, salt, data)
      const char *salt;
      struct crypt_data * __restrict data;
 {
+#if __OPTION_EGLIBC_CRYPT_UFC
   ufc_long res[4];
   char ktab[9];
   ufc_long xx = 25; /* to cope with GCC long long compiler bugs */
+#endif /*__OPTION_EGLIBC_CRYPT_UFC*/
 
 #ifdef _LIBC
   /* Try to find out whether we have to use MD5 encryption replacement.  */
@@ -105,6 +108,7 @@ __crypt_r (key, salt, data)
 			     sizeof (struct crypt_data));
 #endif
 
+#if __OPTION_EGLIBC_CRYPT_UFC
   /*
    * Hack DES tables according to salt
    */
@@ -144,6 +148,10 @@ __crypt_r (key, salt, data)
    */
   _ufc_output_conversion_r (res[0], res[1], salt, data);
   return data->crypt_3_buf;
+#else /* __OPTION_EGLIBC_CRYPT_UFC */
+  __set_errno (ENOSYS);
+  return NULL;
+#endif /* __OPTION_EGLIBC_CRYPT_UFC */
 }
 weak_alias (__crypt_r, crypt_r)
 
@@ -168,7 +176,12 @@ crypt (key, salt)
     return __sha512_crypt (key, salt);
 #endif
 
+#if __OPTION_EGLIBC_CRYPT_UFC
   return __crypt_r (key, salt, &_ufc_foobar);
+#else /* __OPTION_EGLIBC_CRYPT_UFC */
+  __set_errno (ENOSYS);
+  return NULL;
+#endif /* __OPTION_EGLIBC_CRYPT_UFC */
 }
 
 
Index: git/crypt/Makefile
===================================================================
--- git.orig/crypt/Makefile
+++ git/crypt/Makefile
@@ -18,21 +18,25 @@
 #
 #	Sub-makefile for crypt() portion of the library.
 #
+include ../option-groups.mak
+
 subdir	:= crypt
 
 include ../Makeconfig
 
 headers := crypt.h
 
-extra-libs := libcrypt
-extra-libs-others := $(extra-libs)
+extra-libs-$(OPTION_EGLIBC_CRYPT) := libcrypt
+extra-libs-others-y := $(extra-libs-y)
 
-libcrypt-routines := crypt-entry md5-crypt sha256-crypt sha512-crypt crypt \
-		     crypt_util
+libcrypt-routines :=crypt-entry  md5-crypt sha256-crypt sha512-crypt crypt_common
+libcrypt-routines-$(OPTION_EGLIBC_CRYPT_UFC) := crypt crypt_util
+libcrypt-routines += $(libcrypt-routines-y)
 
-tests := cert md5c-test sha256c-test sha512c-test badsalttest
+tests-$(OPTION_EGLIBC_CRYPT) := md5c-test sha256c-test sha512c-test badsalttest
+tests-$(OPTION_EGLIBC_CRYPT_UFC) += cert
 
-ifeq ($(crypt-in-libc),yes)
+ifeq ($(crypt-in-libc)$(OPTION_EGLIBC_CRYPT),yesy)
 routines += $(libcrypt-routines)
 endif
 
@@ -44,7 +48,7 @@ LDLIBS-crypt.so = -lfreebl3
 else
 libcrypt-routines += md5 sha256 sha512
 
-tests += md5test sha256test sha512test
+tests-$(OPTION_EGLIBC_CRYPT) += md5test sha256test sha512test
 
 # The test md5test-giant uses up to 400 MB of RSS and runs on a fast
 # machine over a minute.
@@ -64,8 +68,10 @@ $(objpfx)sha256test: $(patsubst %, $(obj
 $(objpfx)sha512test: $(patsubst %, $(objpfx)%.o,$(sha512-routines))
 endif
 
+ifeq ($(OPTION_EGLIBC_CRYPT),y)
 ifeq (yes,$(build-shared))
 $(addprefix $(objpfx),$(tests)): $(objpfx)libcrypt.so
 else
 $(addprefix $(objpfx),$(tests)): $(objpfx)libcrypt.a
 endif
+endif # eglibc: OPTION_EGLIBC_CRYPT
Index: git/csu/Makefile
===================================================================
--- git.orig/csu/Makefile
+++ git/csu/Makefile
@@ -22,6 +22,8 @@
 # crtn.o, special "initializer" and "finalizer" files used in the link
 # to make the .init and .fini sections work right.
 
+include ../option-groups.mak
+
 subdir := csu
 
 include ../Makeconfig
Index: git/debug/Makefile
===================================================================
--- git.orig/debug/Makefile
+++ git/debug/Makefile
@@ -18,6 +18,8 @@
 #
 #	Sub-makefile for debug portion of the library.
 #
+include ../option-groups.mak
+
 subdir	:= debug
 
 include ../Makeconfig
@@ -27,7 +29,7 @@ headers	:= execinfo.h
 # Note that ptsname_r_chk and getlogin_r are not here, but in
 # login/Makefile instead.  If that subdir is omitted from the
 # build, its _FORTIFY_SOURCE support will be too.
-routines  = backtrace backtracesyms backtracesymsfd noophooks \
+routines  = noophooks \
 	    memcpy_chk memmove_chk mempcpy_chk memset_chk stpcpy_chk \
 	    strcat_chk strcpy_chk strncat_chk strncpy_chk stpncpy_chk \
 	    sprintf_chk vsprintf_chk snprintf_chk vsnprintf_chk \
@@ -36,20 +38,27 @@ routines  = backtrace backtracesyms back
 	    read_chk pread_chk pread64_chk recv_chk recvfrom_chk \
 	    readlink_chk readlinkat_chk getwd_chk getcwd_chk \
 	    realpath_chk fread_chk fread_u_chk \
-	    wctomb_chk wcscpy_chk wmemcpy_chk wmemmove_chk wmempcpy_chk \
-	    wcpcpy_chk wcsncpy_chk wcscat_chk wcsncat_chk wmemset_chk \
-	    wcpncpy_chk \
-	    swprintf_chk vswprintf_chk wprintf_chk fwprintf_chk \
-	    vwprintf_chk vfwprintf_chk fgetws_chk fgetws_u_chk \
 	    confstr_chk getgroups_chk ttyname_r_chk \
-	    gethostname_chk getdomainname_chk wcrtomb_chk mbsnrtowcs_chk \
-	    wcsnrtombs_chk mbsrtowcs_chk wcsrtombs_chk mbstowcs_chk \
-	    wcstombs_chk asprintf_chk vasprintf_chk dprintf_chk \
+	    gethostname_chk getdomainname_chk \
+	    asprintf_chk vasprintf_chk dprintf_chk \
 	    vdprintf_chk obprintf_chk \
 	    longjmp_chk ____longjmp_chk \
 	    fdelt_chk poll_chk ppoll_chk \
 	    stack_chk_fail fortify_fail \
 	    $(static-only-routines)
+routines-$(OPTION_EGLIBC_BACKTRACE) += backtrace backtracesyms backtracesymsfd
+routines-$(OPTION_POSIX_WIDE_CHAR_DEVICE_IO)			\
+	 += wprintf_chk fwprintf_chk				\
+	    vwprintf_chk vfwprintf_chk fgetws_chk fgetws_u_chk
+routines-$(OPTION_POSIX_C_LANG_WIDE_CHAR)				\
+	 += wctomb_chk wcscpy_chk wmemcpy_chk wmemmove_chk wmempcpy_chk	\
+	    wcpcpy_chk wcsncpy_chk wcscat_chk wcsncat_chk wmemset_chk	\
+	    wcpncpy_chk							\
+	    swprintf_chk vswprintf_chk					\
+	    wcrtomb_chk mbsnrtowcs_chk					\
+	    wcsnrtombs_chk mbsrtowcs_chk wcsrtombs_chk mbstowcs_chk	\
+	    wcstombs_chk
+
 static-only-routines := warning-nop stack_chk_fail_local
 
 CFLAGS-backtrace.c = -fno-omit-frame-pointer
@@ -131,11 +140,15 @@ LDFLAGS-tst-backtrace4 = -rdynamic
 LDFLAGS-tst-backtrace5 = -rdynamic
 LDFLAGS-tst-backtrace6 = -rdynamic
 
-tests = backtrace-tst tst-longjmp_chk tst-chk1 tst-chk2 tst-chk3 \
-	tst-lfschk1 tst-lfschk2 tst-lfschk3 test-strcpy_chk test-stpcpy_chk \
-	tst-chk4 tst-chk5 tst-chk6 tst-lfschk4 tst-lfschk5 tst-lfschk6 \
-	tst-longjmp_chk2 tst-backtrace2 tst-backtrace3 tst-backtrace4 \
-	tst-backtrace5 tst-backtrace6
+tests = tst-longjmp_chk test-strcpy_chk test-stpcpy_chk tst-longjmp_chk2
+tests-$(OPTION_EGLIBC_LOCALE_CODE) \
+      += tst-chk1 tst-chk2 tst-chk3 tst-lfschk1 tst-lfschk2 tst-lfschk3
+tests-$(OPTION_EGLIBC_BACKTRACE) \
+      += backtrace-tst tst-backtrace2 tst-backtrace3 tst-backtrace4 \
+         tst-backtrace5 tst-backtrace6
+ifeq (yy,$(OPTION_EGLIBC_LOCALE_CODE)$(OPTION_EGLIBC_CXX_TESTS))
+tests += tst-chk4 tst-chk5 tst-chk6 tst-lfschk4 tst-lfschk5 tst-lfschk6
+endif
 
 extra-libs = libSegFault libpcprofile
 extra-libs-others = $(extra-libs)
Index: git/debug/segfault.c
===================================================================
--- git.orig/debug/segfault.c
+++ git/debug/segfault.c
@@ -30,6 +30,7 @@
 #include <unistd.h>
 #include <_itoa.h>
 #include <ldsodefs.h>
+#include <gnu/option-groups.h>
 
 /* This file defines macros to access the content of the sigcontext element
    passed up by the signal handler.  */
@@ -68,11 +69,13 @@ write_strsignal (int fd, int signal)
 static void
 catch_segfault (int signal, SIGCONTEXT ctx)
 {
-  int fd, cnt, i;
-  void **arr;
+  int fd;
   struct sigaction sa;
+#if __OPTION_EGLIBC_BACKTRACE
+  int cnt, i;
+  void **arr;
   uintptr_t pc;
-
+#endif
   /* This is the name of the file we are writing to.  If none is given
      or we cannot write to this file write to stderr.  */
   fd = 2;
@@ -91,6 +94,7 @@ catch_segfault (int signal, SIGCONTEXT c
   REGISTER_DUMP;
 #endif
 
+#if __OPTION_EGLIBC_BACKTRACE
   WRITE_STRING ("\nBacktrace:\n");
 
   /* Get the backtrace.  */
@@ -113,6 +117,7 @@ catch_segfault (int signal, SIGCONTEXT c
 
   /* Now generate nicely formatted output.  */
   __backtrace_symbols_fd (arr + i, cnt - i, fd);
+#endif
 
 #ifdef HAVE_PROC_SELF
   /* Now the link map.  */
Index: git/debug/tst-chk1.c
===================================================================
--- git.orig/debug/tst-chk1.c
+++ git/debug/tst-chk1.c
@@ -31,6 +31,7 @@
 #include <sys/select.h>
 #include <sys/socket.h>
 #include <sys/un.h>
+#include <gnu/option-groups.h>
 
 
 #define obstack_chunk_alloc malloc
@@ -307,6 +308,7 @@ do_test (void)
   snprintf (buf + 8, l0 + 3, "%d", num2);
   CHK_FAIL_END
 
+#if __OPTION_POSIX_C_LANG_WIDE_CHAR
   CHK_FAIL_START
   swprintf (wbuf + 8, 3, L"%d", num1);
   CHK_FAIL_END
@@ -314,6 +316,7 @@ do_test (void)
   CHK_FAIL_START
   swprintf (wbuf + 8, l0 + 3, L"%d", num1);
   CHK_FAIL_END
+#endif /* __OPTION_POSIX_C_LANG_WIDE_CHAR */
 # endif
 
   memcpy (buf, str1 + 2, l0 + 9);
@@ -381,6 +384,7 @@ do_test (void)
   CHK_FAIL_END
 #endif
 
+#if __OPTION_POSIX_C_LANG_WIDE_CHAR
 
   /* These ops can be done without runtime checking of object size.  */
   wmemcpy (wbuf, L"abcdefghij", 10);
@@ -605,6 +609,7 @@ do_test (void)
   CHK_FAIL_END
 #endif
 
+#endif /* __OPTION_POSIX_C_LANG_WIDE_CHAR */
 
   /* Now checks for %n protection.  */
 
@@ -1192,6 +1197,7 @@ do_test (void)
 # endif
 #endif
 
+#if __OPTION_POSIX_C_LANG_WIDE_CHAR
   if (setlocale (LC_ALL, "de_DE.UTF-8") != NULL)
     {
       assert (MB_CUR_MAX <= 10);
@@ -1348,6 +1354,7 @@ do_test (void)
       puts ("cannot set locale");
       ret = 1;
     }
+#endif /* __OPTION_POSIX_C_LANG_WIDE_CHAR */
 
   int fd = posix_openpt (O_RDWR);
   if (fd != -1)
Index: git/dlfcn/Makefile
===================================================================
--- git.orig/dlfcn/Makefile
+++ git/dlfcn/Makefile
@@ -15,6 +15,8 @@
 # License along with the GNU C Library; if not, see
 # <http://www.gnu.org/licenses/>.
 
+include ../option-groups.mak
+
 subdir		:= dlfcn
 
 include ../Makeconfig
@@ -36,8 +38,11 @@ endif
 ifeq (yes,$(build-shared))
 tests = glrefmain failtest tst-dladdr default errmsg1 tstcxaatexit \
 	bug-dlopen1 bug-dlsym1 tst-dlinfo bug-atexit1 bug-atexit2 \
-	bug-atexit3 tstatexit bug-dl-leaf tst-rec-dlopen
+	tstatexit bug-dl-leaf tst-rec-dlopen
 endif
+
+tests-$(OPTION_EGLIBC_CXX_TESTS) += bug-atexit3
+
 modules-names = glreflib1 glreflib2 glreflib3 failtestmod defaultmod1 \
 		defaultmod2 errmsg1mod modatexit modcxaatexit \
 		bug-dlsym1-lib1 bug-dlsym1-lib2 bug-atexit1-lib \
Index: git/elf/dl-support.c
===================================================================
--- git.orig/elf/dl-support.c
+++ git/elf/dl-support.c
@@ -19,6 +19,7 @@
 /* This file defines some things that for the dynamic linker are defined in
    rtld.c and dl-sysdep.c in ways appropriate to bootstrap dynamic linking.  */
 
+#include <gnu/option-groups.h>
 #include <errno.h>
 #include <libintl.h>
 #include <stdlib.h>
@@ -42,7 +43,9 @@ char **_dl_argv = &__progname;	/* This i
 const char *_dl_platform;
 size_t _dl_platformlen;
 
+#if __OPTION_EGLIBC_RTLD_DEBUG
 int _dl_debug_mask;
+#endif
 int _dl_lazy;
 ElfW(Addr) _dl_use_load_bias = -2;
 int _dl_dynamic_weak;
Index: git/elf/rtld.c
===================================================================
--- git.orig/elf/rtld.c
+++ git/elf/rtld.c
@@ -16,6 +16,7 @@
    License along with the GNU C Library; if not, see
    <http://www.gnu.org/licenses/>.  */
 
+#include <gnu/option-groups.h>
 #include <errno.h>
 #include <dlfcn.h>
 #include <fcntl.h>
@@ -2200,6 +2201,7 @@ print_missing_version (int errcode __att
 		    objname, errstring);
 }
 
+#if __OPTION_EGLIBC_RTLD_DEBUG
 /* Nonzero if any of the debugging options is enabled.  */
 static int any_debug attribute_relro;
 
@@ -2309,6 +2311,7 @@ a filename can be specified using the LD
       _exit (0);
     }
 }
+#endif /* __OPTION_EGLIBC_RTLD_DEBUG */
 
 static void
 process_dl_audit (char *str)
@@ -2348,8 +2351,9 @@ process_envvars (enum mode *modep)
   char **runp = _environ;
   char *envline;
   enum mode mode = normal;
+#if __OPTION_EGLIBC_RTLD_DEBUG
   char *debug_output = NULL;
-
+#endif
   /* This is the default place for profiling data file.  */
   GLRO(dl_profile_output)
     = &"/var/tmp\0/var/profile"[__libc_enable_secure ? 9 : 0];
@@ -2376,12 +2380,14 @@ process_envvars (enum mode *modep)
 	  break;
 
 	case 5:
+#if __OPTION_EGLIBC_RTLD_DEBUG
 	  /* Debugging of the dynamic linker?  */
 	  if (memcmp (envline, "DEBUG", 5) == 0)
 	    {
 	      process_dl_debug (&envline[6]);
 	      break;
 	    }
+#endif
 	  if (memcmp (envline, "AUDIT", 5) == 0)
 	    process_dl_audit (&envline[6]);
 	  break;
@@ -2447,13 +2453,14 @@ process_envvars (enum mode *modep)
 	      break;
 	    }
 
+#if __OPTION_EGLIBC_RTLD_DEBUG
 	  /* Where to place the profiling data file.  */
 	  if (memcmp (envline, "DEBUG_OUTPUT", 12) == 0)
 	    {
 	      debug_output = &envline[13];
 	      break;
 	    }
-
+#endif
 	  if (!__libc_enable_secure
 	      && memcmp (envline, "DYNAMIC_WEAK", 12) == 0)
 	    GLRO(dl_dynamic_weak) = 1;
@@ -2490,7 +2497,9 @@ process_envvars (enum mode *modep)
 	    {
 	      mode = trace;
 	      GLRO(dl_verbose) = 1;
+#if __OPTION_EGLIBC_RTLD_DEBUG
 	      GLRO_dl_debug_mask |= DL_DEBUG_PRELINK;
+#endif
 	      GLRO(dl_trace_prelink) = &envline[17];
 	    }
 	  break;
@@ -2537,12 +2546,15 @@ process_envvars (enum mode *modep)
       if (__access ("/etc/suid-debug", F_OK) != 0)
 	{
 	  unsetenv ("MALLOC_CHECK_");
+#if __OPTION_EGLIBC_RTLD_DEBUG
 	  GLRO_dl_debug_mask = 0;
+#endif
 	}
 
       if (mode != normal)
 	_exit (5);
     }
+#if __OPTION_EGLIBC_RTLD_DEBUG
   /* If we have to run the dynamic linker in debugging mode and the
      LD_DEBUG_OUTPUT environment variable is given, we write the debug
      messages to this file.  */
@@ -2567,6 +2579,7 @@ process_envvars (enum mode *modep)
 	/* We use standard output if opening the file failed.  */
 	GLRO(dl_debug_fd) = STDOUT_FILENO;
     }
+#endif /* __OPTION_EGLIBC_RTLD_DEBUG */
 }
 
 
Index: git/extra-lib.mk
===================================================================
--- git.orig/extra-lib.mk
+++ git/extra-lib.mk
@@ -25,7 +25,9 @@ install-lib := $(install-lib)
 extra-objs := $(extra-objs)
 
 # The modules that go in $(lib).
-all-$(lib)-routines := $($(lib)-routines) $($(lib)-sysdep_routines)
+all-$(lib)-routines := $($(lib)-routines)		\
+	               $($(lib)-routines-y)		\
+		       $($(lib)-sysdep_routines)
 
 # Add each flavor of library to the lists of things to build and install.
 install-lib += $(foreach o,$(object-suffixes-$(lib)),$(lib:lib%=$(libtype$o)))
@@ -101,7 +103,7 @@ endif
 endif
 
 # This will define `libof-ROUTINE := LIB' for each of the routines.
-cpp-srcs-left := $($(lib)-routines) $($(lib)-sysdep_routines)
+cpp-srcs-left := $(all-$(lib)-routines)
 ifneq (,$(cpp-srcs-left))
 include $(patsubst %,$(..)cppflags-iterator.mk,$(cpp-srcs-left))
 endif
Index: git/grp/Makefile
===================================================================
--- git.orig/grp/Makefile
+++ git/grp/Makefile
@@ -18,6 +18,8 @@
 #
 #	Sub-makefile for grp portion of the library.
 #
+include ../option-groups.mak
+
 subdir	:= grp
 
 include ../Makeconfig
@@ -29,6 +31,9 @@ routines := fgetgrent initgroups setgrou
 	    getgrent_r getgrgid_r getgrnam_r fgetgrent_r
 
 tests := testgrp
+ifneq (y,$(OPTION_EGLIBC_NSSWITCH))
+LDLIBS-testgrp += $(shell cat $(common-objpfx)nss/fixed-nsswitch-libs)
+endif
 
 ifeq (yes,$(build-shared))
 test-srcs :=  tst_fgetgrent
Index: git/hesiod/Makefile
===================================================================
--- git.orig/hesiod/Makefile
+++ git/hesiod/Makefile
@@ -18,12 +18,14 @@
 #
 #	Sub-makefile for hesiod portion of the library.
 #
+include ../option-groups.mak
+
 subdir	:= hesiod
 
 include ../Makeconfig
 
-extra-libs := libnss_hesiod
-extra-libs-others = $(extra-libs)
+extra-libs-$(OPTION_EGLIBC_INET) += libnss_hesiod
+extra-libs-others-y += $(extra-libs-y)
 
 subdir-dirs = nss_hesiod
 vpath %.c nss_hesiod
Index: git/iconv/gconv_db.c
===================================================================
--- git.orig/iconv/gconv_db.c
+++ git/iconv/gconv_db.c
@@ -25,6 +25,7 @@
 #include <sys/param.h>
 #include <bits/libc-lock.h>
 #include <locale/localeinfo.h>
+#include <gnu/option-groups.h>
 
 #include <dlfcn.h>
 #include <gconv_int.h>
@@ -828,9 +829,11 @@ free_modules_db (struct gconv_module *no
 /* Free all resources if necessary.  */
 libc_freeres_fn (free_mem)
 {
+#if __OPTION_EGLIBC_LOCALE_CODE
   /* First free locale memory.  This needs to be done before freeing derivations,
      as ctype cleanup functions dereference steps arrays which we free below.  */
   _nl_locale_subfreeres ();
+#endif
 
   /* finddomain.c has similar problem.  */
   extern void _nl_finddomain_subfreeres (void) attribute_hidden;
Index: git/iconv/gconv_trans.c
===================================================================
--- git.orig/iconv/gconv_trans.c
+++ git/iconv/gconv_trans.c
@@ -23,6 +23,7 @@
 #include <stdint.h>
 #include <string.h>
 #include <stdlib.h>
+#include <gnu/option-groups.h>
 
 #include <bits/libc-lock.h>
 #include "gconv_int.h"
@@ -38,15 +39,19 @@ __gconv_transliterate (struct __gconv_st
 		       unsigned char **outbufstart, size_t *irreversible)
 {
   /* Find out about the locale's transliteration.  */
+#if __OPTION_EGLIBC_LOCALE_CODE
   uint_fast32_t size;
   const uint32_t *from_idx;
   const uint32_t *from_tbl;
   const uint32_t *to_idx;
   const uint32_t *to_tbl;
+#endif
   const uint32_t *winbuf;
   const uint32_t *winbufend;
+#if __OPTION_EGLIBC_LOCALE_CODE
   uint_fast32_t low;
   uint_fast32_t high;
+#endif
 
   /* The input buffer.  There are actually 4-byte values.  */
   winbuf = (const uint32_t *) *inbufp;
@@ -58,6 +63,7 @@ __gconv_transliterate (struct __gconv_st
     PTR_DEMANGLE (fct);
 #endif
 
+#if __OPTION_EGLIBC_LOCALE_CODE
   /* If there is no transliteration information in the locale don't do
      anything and return the error.  */
   size = _NL_CURRENT_WORD (LC_CTYPE, _NL_CTYPE_TRANSLIT_TAB_SIZE);
@@ -193,6 +199,7 @@ __gconv_transliterate (struct __gconv_st
              sorted.  */
 	  break;
     }
+#endif
 
   /* One last chance: use the default replacement.  */
   if (_NL_CURRENT_WORD (LC_CTYPE, _NL_CTYPE_TRANSLIT_DEFAULT_MISSING_LEN) != 0)
Index: git/iconv/iconv_prog.c
===================================================================
--- git.orig/iconv/iconv_prog.c
+++ git/iconv/iconv_prog.c
@@ -35,6 +35,7 @@
 #ifdef _POSIX_MAPPED_FILES
 # include <sys/mman.h>
 #endif
+#include <gnu/option-groups.h>
 #include <charmap.h>
 #include <gconv_int.h>
 #include "iconv_prog.h"
@@ -221,10 +222,17 @@ main (int argc, char *argv[])
 	      bool to_wrong =
 		(iconv_open (to_code, "UTF-8") == (iconv_t) -1
 		 && errno == EINVAL);
+#if __OPTION_EGLIBC_LOCALE_CODE
 	      const char *from_pretty =
 		(from_code[0] ? from_code : nl_langinfo (CODESET));
 	      const char *to_pretty =
 		(orig_to_code[0] ? orig_to_code : nl_langinfo (CODESET));
+#else
+	      const char *from_pretty =
+		(from_code[0] ? from_code : "ANSI_X3.4-1968");
+	      const char *to_pretty =
+                 (orig_to_code[0] ? orig_to_code : "ANSI_X3.4-1968");
+#endif
 
 	      if (from_wrong)
 		{
Index: git/iconv/Makefile
===================================================================
--- git.orig/iconv/Makefile
+++ git/iconv/Makefile
@@ -18,6 +18,8 @@
 #
 #	Makefile for iconv.
 #
+include ../option-groups.mak
+
 subdir	:= iconv
 
 include ../Makeconfig
@@ -39,6 +41,11 @@ CFLAGS-iconv_charmap.c = -I../locale/pro
 CFLAGS-dummy-repertoire.c = -I../locale/programs
 CFLAGS-charmap.c = -DCHARMAP_PATH='"$(i18ndir)/charmaps"' \
 		   -DDEFAULT_CHARMAP=null_pointer -DNEED_NULL_POINTER
+
+ifneq (y,$(OPTION_EGLIBC_SPAWN))
+CFLAGS-charmap-dir.c += -DNO_UNCOMPRESS
+endif
+
 CFLAGS-linereader.c = -DNO_TRANSLITERATION
 CFLAGS-simple-hash.c = -I../locale
 
Index: git/iconvdata/Makefile
===================================================================
--- git.orig/iconvdata/Makefile
+++ git/iconvdata/Makefile
@@ -18,12 +18,15 @@
 #
 #	Makefile for iconv data and code.
 #
+include ../option-groups.mak
+
 subdir	:= iconvdata
 
 include ../Makeconfig
 
 # Names of all the shared objects which implement the transformations.
-modules	:= ISO8859-1 ISO8859-2 ISO8859-3 ISO8859-4 ISO8859-5		 \
+modules-$(OPTION_EGLIBC_CHARSETS)					 \
+	:= ISO8859-1 ISO8859-2 ISO8859-3 ISO8859-4 ISO8859-5		 \
 	   ISO8859-6 ISO8859-7 ISO8859-8 ISO8859-9 ISO8859-10		 \
 	   ISO8859-11 ISO8859-13 ISO8859-14 ISO8859-15 ISO8859-16	 \
 	   T.61 ISO_6937 SJIS KOI-8 HP-ROMAN8 HP-ROMAN9 EBCDIC-AT-DE	 \
@@ -63,11 +66,13 @@ modules	:= ISO8859-1 ISO8859-2 ISO8859-3
 	   MAC-CENTRALEUROPE KOI8-RU ISO8859-9E				 \
 	   CP770 CP771 CP772 CP773 CP774
 
-modules.so := $(addsuffix .so, $(modules))
+modules.so := $(addsuffix .so, $(modules-y))
 
 ifeq (yes,$(build-shared))
 tests = bug-iconv1 bug-iconv2 tst-loading tst-e2big tst-iconv4 bug-iconv4 \
-	tst-iconv6 bug-iconv5 bug-iconv6 tst-iconv7 bug-iconv8 bug-iconv9
+	tst-iconv6 bug-iconv5 bug-iconv8 bug-iconv9
+tests-$(OPTION_EGLIBC_LOCALE_CODE) += bug-iconv6 tst-iconv7
+
 ifeq ($(have-thread-library),yes)
 tests += bug-iconv3
 endif
@@ -127,13 +132,13 @@ ifeq (yes,$(build-shared))
 # Rule to generate the shared objects.
 charmaps = ../localedata/charmaps
 -include $(objpfx)iconv-rules
-extra-modules-left := $(modules)
+extra-modules-left := $(modules-y)
 include extra-module.mk
 
 
 extra-objs	+= $(modules.so)
-install-others	= $(addprefix $(inst_gconvdir)/, $(modules.so))	\
-		  $(inst_gconvdir)/gconv-modules
+install-others-y += $(addprefix $(inst_gconvdir)/, $(modules.so))
+install-others-$(OPTION_EGLIBC_CHARSETS) += $(inst_gconvdir)/gconv-modules
 
 # We can build the conversion tables for numerous charsets automatically.
 
@@ -201,7 +206,7 @@ before-compile += $(addprefix $(objpfx),
 ifndef avoid-generated
 $(objpfx)iconv-rules: Makefile
 	$(make-target-directory)
-	{ echo $(filter-out lib%, $(modules)); \
+	{ echo $(filter-out lib%, $(modules-y)); \
 	  echo 8bit $(gen-8bit-modules); \
 	  echo 8bit-gap $(gen-8bit-gap-modules); } | \
 	LC_ALL=C \
@@ -245,7 +250,7 @@ $(addprefix $(inst_gconvdir)/, $(modules
 	$(do-install-program)
 $(inst_gconvdir)/gconv-modules: gconv-modules $(+force)
 	$(do-install)
-ifeq (no,$(cross-compiling))
+# eglibc: ifeq (no,$(cross-compiling))
 # Update the $(prefix)/lib/gconv/gconv-modules.cache file. This is necessary
 # if this libc has more gconv modules than the previously installed one.
 	if test -f "$(inst_gconvdir)/gconv-modules.cache"; then \
@@ -254,9 +259,9 @@ ifeq (no,$(cross-compiling))
 	   $(common-objpfx)iconv/iconvconfig \
 	     $(addprefix --prefix=,$(install_root)); \
 	fi
-else
-	@echo '*@*@*@ You should recreate $(inst_gconvdir)/gconv-modules.cache'
-endif
+# eglibc: else
+# eglibc:	@echo '*@*@*@ You should recreate $(inst_gconvdir)/gconv-modules.cache'
+# eglibc: endif
 
 endif # build-shared = yes
 
Index: git/include/netdb.h
===================================================================
--- git.orig/include/netdb.h
+++ git/include/netdb.h
@@ -232,6 +232,10 @@ extern enum nss_status _nss_ ## service
 		       (const char *name, int af, struct hostent *host,	      \
 			char *buffer, size_t buflen, int *errnop,	      \
 			int *h_errnop);					      \
+extern enum nss_status _nss_ ## service ## _gethostbyname3_r		      \
+		       (const char *name, int af, struct hostent *result,     \
+			char *buffer, size_t buflen, int *errnop,	      \
+			int *h_errnop, int32_t *ttlp, char **canonp);         \
 extern enum nss_status _nss_ ## service ## _gethostbyname_r		      \
 		       (const char *name, struct hostent *host, char *buffer, \
 			size_t buflen, int *errnop, int *h_errnop);	      \
Index: git/inet/Makefile
===================================================================
--- git.orig/inet/Makefile
+++ git/inet/Makefile
@@ -18,6 +18,8 @@
 #
 #	Sub-makefile for inet portion of the library.
 #
+include ../option-groups.mak
+
 subdir	:= inet
 
 include ../Makeconfig
@@ -27,7 +29,8 @@ headers	:= netinet/ether.h netinet/in.h
 	   netinet/tcp.h netinet/ip.h $(wildcard arpa/*.h protocols/*.h) \
 	   aliases.h ifaddrs.h netinet/ip6.h netinet/icmp6.h bits/in.h
 
-routines := htonl htons		\
+routines-$(OPTION_EGLIBC_INET) \
+	 += htonl htons \
 	    inet_lnaof inet_mkadr	\
 	    inet_netof inet_ntoa inet_net herrno herrno-loc \
 	    gethstbyad gethstbyad_r gethstbynm gethstbynm2 gethstbynm2_r \
@@ -41,18 +44,23 @@ routines := htonl htons		\
 	    getrpcent_r getrpcbyname_r getrpcbynumber_r \
 	    ether_aton ether_aton_r ether_hton ether_line \
 	    ether_ntoa ether_ntoa_r ether_ntoh \
-	    rcmd rexec ruserpass \
 	    getnetgrent_r getnetgrent \
-	    getaliasent_r getaliasent getaliasname getaliasname_r \
-	    in6_addr getnameinfo if_index ifaddrs inet6_option \
+	    in6_addr getnameinfo if_index ifaddrs \
 	    getipv4sourcefilter setipv4sourcefilter \
-	    getsourcefilter setsourcefilter inet6_opt inet6_rth
+	    getsourcefilter setsourcefilter
+routines-$(OPTION_EGLIBC_RCMD) \
+	 += rcmd rexec ruserpass
+routines-$(OPTION_EGLIBC_DB_ALIASES) \
+	 += getaliasent_r getaliasent getaliasname getaliasname_r
+routines-$(OPTION_EGLIBC_ADVANCED_INET6) \
+	 += inet6_option inet6_opt inet6_rth
 
-aux := check_pf check_native ifreq
+aux-$(OPTION_EGLIBC_INET) += check_pf check_native ifreq
 
 tests := htontest test_ifindex tst-ntoa tst-ether_aton tst-network \
-	 tst-gethnm test-ifaddrs bug-if1 test-inet6_opt tst-ether_line \
+	 tst-gethnm test-ifaddrs bug-if1 tst-ether_line \
 	 tst-getni1 tst-getni2 tst-inet6_rth tst-checks
+tests-$(OPTION_EGLIBC_ADVANCED_INET6) += test-inet6_opt
 
 include ../Rules
 
Index: git/intl/dcigettext.c
===================================================================
--- git.orig/intl/dcigettext.c
+++ git/intl/dcigettext.c
@@ -100,11 +100,15 @@ extern int errno;
 # include "libgnuintl.h"
 #endif
 #include "hash-string.h"
+#ifdef _LIBC
+# include <gnu/option-groups.h>
+#endif
 
 /* Handle multi-threaded applications.  */
 #ifdef _LIBC
 # include <bits/libc-lock.h>
 # define gl_rwlock_define_initialized __libc_rwlock_define_initialized
+# define gl_rwlock_define __libc_rwlock_define
 # define gl_rwlock_rdlock __libc_rwlock_rdlock
 # define gl_rwlock_wrlock __libc_rwlock_wrlock
 # define gl_rwlock_unlock __libc_rwlock_unlock
@@ -523,8 +527,10 @@ DCIGETTEXT (const char *domainname, cons
   saved_errno = errno;
 
 #ifdef _LIBC
-  __libc_rwlock_define (extern, __libc_setlocale_lock attribute_hidden)
-  __libc_rwlock_rdlock (__libc_setlocale_lock);
+# if __OPTION_EGLIBC_LOCALE_CODE
+  gl_rwlock_define (extern, __libc_setlocale_lock attribute_hidden)
+  gl_rwlock_rdlock (__libc_setlocale_lock);
+# endif
 #endif
 
   gl_rwlock_rdlock (_nl_state_lock);
@@ -550,7 +556,11 @@ DCIGETTEXT (const char *domainname, cons
 #ifdef HAVE_PER_THREAD_LOCALE
 # ifndef IN_LIBGLOCALE
 #  ifdef _LIBC
-  localename = strdupa (__current_locale_name (category));
+#   if __OPTION_EGLIBC_LOCALE_CODE
+      localename = strdupa (__current_locale_name (category));
+#   else
+      localename = "C";
+#   endif
 #  else
   categoryname = category_to_name (category);
 #   define CATEGORYNAME_INITIALIZED
@@ -581,10 +591,12 @@ DCIGETTEXT (const char *domainname, cons
       else
 	retval = (char *) (*foundp)->translation;
 
-      gl_rwlock_unlock (_nl_state_lock);
 # ifdef _LIBC
-      __libc_rwlock_unlock (__libc_setlocale_lock);
+#  if __OPTION_EGLIBC_LOCALE_CODE
+      gl_rwlock_unlock (__libc_setlocale_lock);
+#  endif
 # endif
+      gl_rwlock_unlock (_nl_state_lock);
       __set_errno (saved_errno);
       return retval;
     }
@@ -838,10 +850,13 @@ DCIGETTEXT (const char *domainname, cons
 	      if (plural)
 		retval = plural_lookup (domain, n, retval, retlen);
 
-	      gl_rwlock_unlock (_nl_state_lock);
 #ifdef _LIBC
-	      __libc_rwlock_unlock (__libc_setlocale_lock);
+# if __OPTION_EGLIBC_LOCALE_CODE
+
+	      gl_rwlock_unlock (__libc_setlocale_lock);
+# endif
 #endif
+	      gl_rwlock_unlock (_nl_state_lock);
 	      return retval;
 	    }
 	}
@@ -850,10 +865,12 @@ DCIGETTEXT (const char *domainname, cons
  return_untranslated:
   /* Return the untranslated MSGID.  */
   FREE_BLOCKS (block_list);
-  gl_rwlock_unlock (_nl_state_lock);
 #ifdef _LIBC
-  __libc_rwlock_unlock (__libc_setlocale_lock);
+# if __OPTION_EGLIBC_LOCALE_CODE
+   gl_rwlock_unlock (__libc_setlocale_lock);
+# endif
 #endif
+  gl_rwlock_unlock (_nl_state_lock);
 #ifndef _LIBC
   if (!ENABLE_SECURE)
     {
@@ -1550,7 +1567,11 @@ guess_category_value (int category, cons
      `LC_xxx', and `LANG'.  On some systems this can be done by the
      `setlocale' function itself.  */
 # ifdef _LIBC
+#  if __OPTION_EGLIBC_LOCALE_CODE
   locale = __current_locale_name (category);
+#  else
+  locale = "C";
+#  endif
 # else
   locale_defaulted = 0;
 #  if HAVE_USELOCALE
Index: git/intl/Makefile
===================================================================
--- git.orig/intl/Makefile
+++ git/intl/Makefile
@@ -16,6 +16,7 @@
 # <http://www.gnu.org/licenses/>.
 
 # Makefile for intl subdirectory: message handling code from GNU gettext.
+include ../option-groups.mak
 
 subdir = intl
 
@@ -48,7 +49,7 @@ endif
 $(objpfx)plural.o: plural.c
 
 ifeq ($(run-built-tests),yes)
-ifeq (yes,$(build-shared))
+ifeq (yyyes,$(OPTION_EGLIBC_LOCALES)$(OPTION_EGLIBC_LOCALE_CODE)$(build-shared))
 ifneq ($(strip $(MSGFMT)),:)
 tests-special += $(objpfx)tst-translit.out $(objpfx)tst-gettext.out \
 		 $(objpfx)tst-gettext2.out $(objpfx)tst-codeset.out \
Index: git/io/Makefile
===================================================================
--- git.orig/io/Makefile
+++ git/io/Makefile
@@ -18,6 +18,8 @@
 #
 #	Sub-makefile for I/O portion of the library.
 #
+include ../option-groups.mak
+
 subdir	:= io
 
 include ../Makeconfig
@@ -36,7 +38,7 @@ routines :=								\
 	fxstatat fxstatat64						\
 	statfs fstatfs statfs64 fstatfs64				\
 	statvfs fstatvfs statvfs64 fstatvfs64				\
-	umask chmod fchmod lchmod fchmodat				\
+	umask chmod fchmod fchmodat					\
 	mkdir mkdirat							\
 	open open_2 open64 open64_2 openat openat_2 openat64 openat64_2	\
 	read write lseek lseek64 access euidaccess faccessat		\
@@ -49,11 +51,13 @@ routines :=								\
 	ttyname ttyname_r isatty					\
 	link linkat symlink symlinkat readlink readlinkat		\
 	unlink unlinkat rmdir						\
-	ftw ftw64 fts poll ppoll					\
+	poll ppoll							\
 	posix_fadvise posix_fadvise64					\
 	posix_fallocate posix_fallocate64				\
 	sendfile sendfile64 \
 	utimensat futimens
+routines-$(OPTION_EGLIBC_BSD) += lchmod
+routines-$(OPTION_EGLIBC_FTRAVERSE) += ftw ftw64 fts
 
 aux := have_o_cloexec
 
@@ -64,18 +68,22 @@ static-only-routines = stat fstat lstat
 		       fstatat fstatat64 mknod mknodat
 
 others		:= pwd
-test-srcs	:= ftwtest
+test-srcs-$(OPTION_EGLIBC_FTRAVERSE) := ftwtest
 tests		:= test-utime test-stat test-stat2 test-lfs tst-getcwd \
-		   tst-fcntl bug-ftw1 bug-ftw2 bug-ftw3 bug-ftw4 tst-statvfs \
+		   tst-fcntl tst-statvfs \
 		   tst-openat tst-unlinkat tst-fstatat tst-futimesat \
 		   tst-renameat tst-fchownat tst-fchmodat tst-faccessat \
 		   tst-symlinkat tst-linkat tst-readlinkat tst-mkdirat \
-		   tst-mknodat tst-mkfifoat tst-ttyname_r bug-ftw5 \
+		   tst-mknodat tst-mkfifoat tst-ttyname_r \
 		   tst-posix_fallocate
+tests-$(OPTION_EGLIBC_FTRAVERSE) += bug-ftw1 bug-ftw2 bug-ftw3 bug-ftw4 \
+				    bug-ftw5
 
 ifeq ($(run-built-tests),yes)
+ifeq (y,$(OPTION_EGLIBC_FTRAVERSE))
 tests-special += $(objpfx)ftwtest.out
 endif
+endif
 
 include ../Rules
 
Index: git/libidn/Makefile
===================================================================
--- git.orig/libidn/Makefile
+++ git/libidn/Makefile
@@ -16,6 +16,7 @@
 # <http://www.gnu.org/licenses/>.
 
 # Makefile for libidn subdirectory of GNU C Library.
+include ../option-groups.mak
 
 subdir	:= libidn
 
@@ -23,8 +24,8 @@ include ../Makeconfig
 
 routines = idn-stub
 
-extra-libs		= libcidn
-extra-libs-others	= $(extra-libs)
+extra-libs-$(OPTION_EGLIBC_IDN) = libcidn
+extra-libs-others-y = $(extra-libs-y)
 
 libcidn-routines := punycode toutf8 nfkc stringprep rfc3454 profiles idna \
 		    iconvme
Index: git/libidn/toutf8.c
===================================================================
--- git.orig/libidn/toutf8.c
+++ git/libidn/toutf8.c
@@ -33,6 +33,11 @@
 /* Get strlen. */
 #include <string.h>
 
+/* Get __OPTION_EGLIBC_LOCALE_CODE.  */
+#ifdef _LIBC
+# include <gnu/option-groups.h>
+#endif
+
 /* Get iconv_string. */
 #include "iconvme.h"
 
@@ -47,7 +52,11 @@
 #endif
 
 #ifdef _LIBC
-# define stringprep_locale_charset() nl_langinfo (CODESET)
+# if __OPTION_EGLIBC_LOCALE_CODE
+#  define stringprep_locale_charset() nl_langinfo (CODESET)
+# else
+#  define stringprep_locale_charset() "ANSI_X3.4-1968"
+# endif
 #else
 /**
  * stringprep_locale_charset - return charset used in current locale
Index: git/libio/fileops.c
===================================================================
--- git.orig/libio/fileops.c
+++ git/libio/fileops.c
@@ -38,6 +38,7 @@
 #include <string.h>
 #include <errno.h>
 #include <unistd.h>
+#include <gnu/option-groups.h>
 #include <stdlib.h>
 #if _LIBC
 # include "../wcsmbs/wcsmbsload.h"
@@ -172,7 +173,7 @@ _IO_new_file_close_it (_IO_FILE *fp)
 
   /* Free buffer. */
 #if defined _LIBC || defined _GLIBCPP_USE_WCHAR_T
-  if (fp->_mode > 0)
+  if (_IO_is_wide (fp))
     {
       if (_IO_have_wbackup (fp))
 	_IO_free_wbackup_area (fp);
@@ -347,6 +348,7 @@ _IO_new_file_fopen (_IO_FILE *fp, const
       cs = strstr (last_recognized + 1, ",ccs=");
       if (cs != NULL)
 	{
+#if __OPTION_POSIX_WIDE_CHAR_DEVICE_IO
 	  /* Yep.  Load the appropriate conversions and set the orientation
 	     to wide.  */
 	  struct gconv_fcts fcts;
@@ -406,6 +408,12 @@ _IO_new_file_fopen (_IO_FILE *fp, const
 
 	  /* Set the mode now.  */
 	  result->_mode = 1;
+#else
+          /* Treat this as if we couldn't find the given character set.  */
+          (void) _IO_file_close_it (fp);
+          __set_errno (EINVAL);
+          return NULL;
+#endif
 	}
     }
 
Index: git/libio/__fpurge.c
===================================================================
--- git.orig/libio/__fpurge.c
+++ git/libio/__fpurge.c
@@ -21,7 +21,7 @@
 void
 __fpurge (FILE *fp)
 {
-  if (fp->_mode > 0)
+  if (_IO_is_wide (fp))
     {
       /* Wide-char stream.  */
       if (_IO_in_backup (fp))
Index: git/libio/iofwide.c
===================================================================
--- git.orig/libio/iofwide.c
+++ git/libio/iofwide.c
@@ -26,6 +26,7 @@
 
 #include <libioP.h>
 #ifdef _LIBC
+# include <gnu/option-groups.h>
 # include <dlfcn.h>
 # include <wchar.h>
 #endif
@@ -43,6 +44,8 @@
 #endif
 
 
+#if ! defined _LIBC || __OPTION_POSIX_C_LANG_WIDE_CHAR
+
 /* Prototypes of libio's codecvt functions.  */
 static enum __codecvt_result do_out (struct _IO_codecvt *codecvt,
 				     __mbstate_t *statep,
@@ -499,3 +502,26 @@ do_max_length (struct _IO_codecvt *codec
   return MB_CUR_MAX;
 #endif
 }
+
+#else
+/* OPTION_POSIX_C_LANG_WIDE_CHAR is disabled.  */
+
+#undef _IO_fwide
+int
+_IO_fwide (fp, mode)
+     _IO_FILE *fp;
+     int mode;
+{
+  /* Die helpfully if the user tries to create a wide stream; I
+     disbelieve that most users check the return value from
+     'fwide (fp, 1)'.  */
+  assert (mode <= 0);
+
+  /* We can only make streams byte-oriented, which is trivial.  */
+  if (mode < 0)
+    fp->_mode = -1;
+
+  return fp->_mode;
+}
+
+#endif
Index: git/libio/ioseekoff.c
===================================================================
--- git.orig/libio/ioseekoff.c
+++ git/libio/ioseekoff.c
@@ -60,7 +60,7 @@ _IO_seekoff_unlocked (fp, offset, dir, m
 	  else
 	    abort ();
 	}
-      if (_IO_fwide (fp, 0) < 0)
+      if (! _IO_is_wide (fp))
 	_IO_free_backup_area (fp);
       else
 	_IO_free_wbackup_area (fp);
Index: git/libio/ioseekpos.c
===================================================================
--- git.orig/libio/ioseekpos.c
+++ git/libio/ioseekpos.c
@@ -35,7 +35,7 @@ _IO_seekpos_unlocked (fp, pos, mode)
   /* If we have a backup buffer, get rid of it, since the __seekoff
      callback may not know to do the right thing about it.
      This may be over-kill, but it'll do for now. TODO */
-  if (_IO_fwide (fp, 0) <= 0)
+  if (! _IO_is_wide (fp))
     {
       if (_IO_have_backup (fp))
 	_IO_free_backup_area (fp);
Index: git/libio/iosetbuffer.c
===================================================================
--- git.orig/libio/iosetbuffer.c
+++ git/libio/iosetbuffer.c
@@ -24,6 +24,8 @@
    This exception applies to code released by its copyright holders
    in files containing the exception.  */
 
+#include <gnu/option-groups.h>
+
 #include "libioP.h"
 
 void
@@ -38,9 +40,11 @@ _IO_setbuffer (fp, buf, size)
   if (!buf)
     size = 0;
   (void) _IO_SETBUF (fp, buf, size);
+#if __OPTION_POSIX_C_LANG_WIDE_CHAR
   if (_IO_vtable_offset (fp) == 0 && fp->_mode == 0 && _IO_CHECK_WIDE (fp))
     /* We also have to set the buffer using the wide char function.  */
     (void) _IO_WSETBUF (fp, buf, size);
+#endif /* __OPTION_POSIX_C_LANG_WIDE_CHAR */
   _IO_release_lock (fp);
 }
 libc_hidden_def (_IO_setbuffer)
Index: git/libio/libioP.h
===================================================================
--- git.orig/libio/libioP.h
+++ git/libio/libioP.h
@@ -42,6 +42,10 @@
 /*# include <comthread.h>*/
 #endif
 
+#if defined _LIBC
+# include <gnu/option-groups.h>
+#endif
+
 #include <math_ldbl_opt.h>
 
 #include "iolibio.h"
@@ -508,8 +512,20 @@ extern void _IO_old_init (_IO_FILE *fp,
 
 
 #if defined _LIBC || defined _GLIBCPP_USE_WCHAR_T
+
+/* _IO_is_wide (fp) is roughly equivalent to '_IO_fwide (fp, 0) > 0',
+   except that when OPTION_POSIX_C_LANG_WIDE_CHAR is disabled, it
+   expands to a constant, allowing the compiler to realize that it can
+   eliminate code that references wide stream handling functions.
+   This, in turn, allows us to omit them.  */
+#if __OPTION_POSIX_C_LANG_WIDE_CHAR
+# define _IO_is_wide(_f) ((_f)->_mode > 0)
+#else
+# define _IO_is_wide(_f) (0)
+#endif
+
 # define _IO_do_flush(_f) \
-  ((_f)->_mode <= 0							      \
+  (! _IO_is_wide (_f)                                                         \
    ? _IO_do_write(_f, (_f)->_IO_write_base,				      \
 		  (_f)->_IO_write_ptr-(_f)->_IO_write_base)		      \
    : _IO_wdo_write(_f, (_f)->_wide_data->_IO_write_base,		      \
Index: git/libio/Makefile
===================================================================
--- git.orig/libio/Makefile
+++ git/libio/Makefile
@@ -18,6 +18,8 @@
 #
 #	Specific makefile for libio.
 #
+include ../option-groups.mak
+
 subdir	:= libio
 
 include ../Makeconfig
@@ -27,16 +29,13 @@ headers	:= stdio.h libio.h _G_config.h b
 
 routines	:=							      \
 	filedoalloc iofclose iofdopen iofflush iofgetpos iofgets iofopen      \
-	iofopncook iofputs iofread iofsetpos ioftell wfiledoalloc	      \
+	iofopncook iofputs iofread iofsetpos ioftell			      \
 	iofwrite iogetdelim iogetline iogets iopadn iopopen ioputs	      \
 	ioseekoff ioseekpos iosetbuffer iosetvbuf ioungetc		      \
 	iovsprintf iovsscanf						      \
 	iofgetpos64 iofopen64 iofsetpos64				      \
-	fputwc fputwc_u getwc getwc_u getwchar getwchar_u iofgetws iofgetws_u \
-	iofputws iofputws_u iogetwline iowpadn ioungetwc putwc putwc_u	      \
-	putwchar putwchar_u putchar putchar_u fwprintf swprintf vwprintf      \
-	wprintf wscanf fwscanf vwscanf vswprintf iovswscanf swscanf wgenops   \
-	wstrops wfileops iofwide fwide wmemstream			      \
+	putchar putchar_u						      \
+	iofwide								      \
 									      \
 	clearerr feof ferror fileno fputc freopen fseek getc getchar	      \
 	memstream pclose putc putchar rewind setbuf setlinebuf vasprintf      \
@@ -48,24 +47,49 @@ routines	:=							      \
 									      \
 	libc_fatal fmemopen
 
-tests = tst_swprintf tst_wprintf tst_swscanf tst_wscanf tst_getwc tst_putwc   \
-	tst_wprintf2 tst-widetext test-fmemopen tst-ext tst-ext2 \
-	tst-fgetws tst-ungetwc1 tst-ungetwc2 tst-swscanf tst-sscanf	      \
-	tst-mmap-setvbuf bug-ungetwc1 bug-ungetwc2 tst-atime tst-eof          \
-	tst-freopen bug-rewind bug-rewind2 bug-ungetc bug-fseek \
+routines-$(OPTION_POSIX_C_LANG_WIDE_CHAR) +=				      \
+	wfiledoalloc                                                          \
+	iowpadn                                                               \
+	swprintf                                                              \
+	vswprintf iovswscanf swscanf wgenops                                  \
+	wstrops wfileops wmemstream
+routines-$(call option-disabled, OPTION_POSIX_C_LANG_WIDE_CHAR) +=	      \
+	wdummyfileops
+routines-$(OPTION_POSIX_WIDE_CHAR_DEVICE_IO) +=				      \
+	fputwc fputwc_u getwc getwc_u getwchar getwchar_u iofgetws iofgetws_u \
+	iofputws iofputws_u iogetwline ioungetwc putwc putwc_u                \
+	putwchar putwchar_u fwprintf vwprintf                                 \
+	wprintf wscanf fwscanf vwscanf                                        \
+	fwide
+
+tests = test-fmemopen tst-ext tst-ext2 \
+	tst-mmap-setvbuf tst-atime tst-eof \
+	tst-freopen bug-ungetc bug-fseek \
 	tst-mmap-eofsync tst-mmap-fflushsync bug-mmap-fflush \
-	tst-mmap2-eofsync tst-mmap-offend bug-fopena+ bug-wfflush \
-	bug-ungetc2 bug-ftell bug-ungetc3 bug-ungetc4 tst-fopenloc2 \
+	tst-mmap2-eofsync tst-mmap-offend bug-fopena+ \
+	bug-ungetc2 bug-ungetc3 bug-ungetc4 \
 	tst-memstream1 tst-memstream2 \
-	tst-wmemstream1 tst-wmemstream2 \
-	bug-memstream1 bug-wmemstream1 \
-	tst-setvbuf1 tst-popen1 tst-fgetwc bug-wsetpos tst-fseek \
-	tst-fwrite-error tst-ftell-partial-wide tst-ftell-active-handler \
-	tst-ftell-append tst-fputws
+	bug-memstream1 tst-popen1 tst-fwrite-error \
+	tst-ftell-active-handler tst-ftell-append
+tests-$(OPTION_EGLIBC_LOCALE_CODE) \
+	+= tst-swscanf tst-fgetws tst-setvbuf1 \
+	tst-ungetwc1 tst-ungetwc2 bug-ftell bug-ungetwc2 \
+	tst-widetext tst-fputws
+tests-$(OPTION_POSIX_WIDE_CHAR_DEVICE_IO) \
+	+= bug-rewind bug-rewind2 bug-ungetwc1 \
+	bug-wfflush bug-wmemstream1 tst-fopenloc2 \
+	tst_getwc \
+	tst_putwc tst_wprintf tst_wprintf2 tst_wscanf \
+	tst-fgetwc bug-wsetpos tst-fseek tst-ftell-partial-wide
+tests-$(OPTION_POSIX_C_LANG_WIDE_CHAR) \
+	+= tst_swprintf tst_swscanf \
+	tst-sscanf \
+	tst-wmemstream1 tst-wmemstream2
+
 ifeq (yes,$(build-shared))
 # Add test-fopenloc only if shared library is enabled since it depends on
 # shared localedata objects.
-tests += tst-fopenloc
+tests-$(OPTION_EGLIBC_LOCALE_CODE) += tst-fopenloc
 endif
 test-srcs = test-freopen
 
@@ -164,13 +188,17 @@ shared-only-routines = oldiofopen oldiof
 		       oldiofsetpos64
 
 ifeq ($(run-built-tests),yes)
+ifeq (y,$(OPTION_POSIX_WIDE_CHAR_DEVICE_IO))
 tests-special += $(objpfx)test-freopen.out
+endif
+ifeq (y,$(OPTION_EGLIBC_LOCALE_CODE))
 ifeq (yes,$(build-shared))
 # Run tst-fopenloc-cmp.out and tst-openloc-mem.out only if shared
 # library is enabled since they depend on tst-fopenloc.out.
 tests-special += $(objpfx)tst-fopenloc-cmp.out $(objpfx)tst-fopenloc-mem.out
 endif
 endif
+endif
 
 include ../Rules
 
Index: git/libio/wdummyfileops.c
===================================================================
--- /dev/null
+++ git/libio/wdummyfileops.c
@@ -0,0 +1,161 @@
+/* Copyright (C) 2007 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 2.1 of the License, or (at your option) any later version.
+
+   The GNU C Library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with the GNU C Library; if not, write to the Free
+   Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+   02111-1307 USA.
+
+   As a special exception, if you link the code in this file with
+   files compiled with a GNU compiler to produce an executable,
+   that does not cause the resulting executable to be covered by
+   the GNU Lesser General Public License.  This exception does not
+   however invalidate any other reasons why the executable file
+   might be covered by the GNU Lesser General Public License.
+   This exception applies to code released by its copyright holders
+   in files containing the exception.  */
+
+#include <assert.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <libioP.h>
+
+static void __THROW __attribute__ ((__noreturn__))
+_IO_wfile_wide_char_support_disabled (void)
+{
+  static const char errstr[]
+    = ("The application tried to use wide character I/O, but libc.so"
+       " was compiled\n"
+       "with the OPTION_POSIX_C_LANG_WIDE_CHAR option group disabled.\n");
+  __libc_write (STDERR_FILENO, errstr, sizeof (errstr) - 1);
+  abort ();
+}
+
+static void
+_IO_wfile_disabled_void_int (_IO_FILE *fp, int x)
+{
+  _IO_wfile_wide_char_support_disabled ();
+}
+
+static int
+_IO_wfile_disabled_int_int (_IO_FILE *fp, int x)
+{
+  _IO_wfile_wide_char_support_disabled ();
+}
+
+static int
+_IO_wfile_disabled_int_none (_IO_FILE *fp)
+{
+  _IO_wfile_wide_char_support_disabled ();
+}
+
+static _IO_size_t
+_IO_wfile_disabled_xsputn (_IO_FILE *fp, const void *data, _IO_size_t n)
+{
+  _IO_wfile_wide_char_support_disabled ();
+}
+
+static _IO_size_t
+_IO_wfile_disabled_xsgetn (_IO_FILE *fp, void *data, _IO_size_t n)
+{
+  _IO_wfile_wide_char_support_disabled ();
+}
+
+static _IO_off64_t
+_IO_wfile_disabled_seekoff (_IO_FILE *fp, _IO_off64_t off, int dir, int mode)
+{
+  _IO_wfile_wide_char_support_disabled ();
+}
+
+static _IO_off64_t
+_IO_wfile_disabled_seekpos (_IO_FILE *fp, _IO_off64_t pos, int flags)
+{
+  _IO_wfile_wide_char_support_disabled ();
+}
+
+static _IO_FILE *
+_IO_wfile_disabled_setbuf (_IO_FILE *fp, char *buffer, _IO_ssize_t length)
+{
+  _IO_wfile_wide_char_support_disabled ();
+}
+
+static _IO_ssize_t
+_IO_wfile_disabled_read (_IO_FILE *fp, void *buffer, _IO_ssize_t length)
+{
+  _IO_wfile_wide_char_support_disabled ();
+}
+
+static _IO_ssize_t
+_IO_wfile_disabled_write (_IO_FILE *fp, const void *buffer, _IO_ssize_t length)
+{
+  _IO_wfile_wide_char_support_disabled ();
+}
+
+static _IO_off64_t
+_IO_wfile_disabled_seek (_IO_FILE *fp, _IO_off64_t offset, int mode)
+{
+  _IO_wfile_wide_char_support_disabled ();
+}
+
+static int
+_IO_wfile_disabled_close (_IO_FILE *fp)
+{
+  _IO_wfile_wide_char_support_disabled ();
+}
+
+static int
+_IO_wfile_disabled_stat (_IO_FILE *fp, void *buf)
+{
+  _IO_wfile_wide_char_support_disabled ();
+}
+
+static int
+_IO_wfile_disabled_showmanyc (_IO_FILE *fp)
+{
+  _IO_wfile_wide_char_support_disabled ();
+}
+
+static void
+_IO_wfile_disabled_imbue (_IO_FILE *fp, void *locale)
+{
+  _IO_wfile_wide_char_support_disabled ();
+}
+
+static const struct _IO_jump_t _IO_wfile_jumps_disabled =
+{
+  JUMP_INIT_DUMMY,
+  JUMP_INIT(finish, _IO_wfile_disabled_void_int),
+  JUMP_INIT(overflow, _IO_wfile_disabled_int_int),
+  JUMP_INIT(underflow, _IO_wfile_disabled_int_none),
+  JUMP_INIT(uflow, _IO_wfile_disabled_int_none),
+  JUMP_INIT(pbackfail, _IO_wfile_disabled_int_int),
+  JUMP_INIT(xsputn, _IO_wfile_disabled_xsputn),
+  JUMP_INIT(xsgetn, _IO_wfile_disabled_xsgetn),
+  JUMP_INIT(seekoff, _IO_wfile_disabled_seekoff),
+  JUMP_INIT(seekpos, _IO_wfile_disabled_seekpos),
+  JUMP_INIT(setbuf, _IO_wfile_disabled_setbuf),
+  JUMP_INIT(sync, _IO_wfile_disabled_int_none),
+  JUMP_INIT(doallocate, _IO_wfile_disabled_int_none),
+  JUMP_INIT(read, _IO_wfile_disabled_read),
+  JUMP_INIT(write, _IO_wfile_disabled_write),
+  JUMP_INIT(seek, _IO_wfile_disabled_seek),
+  JUMP_INIT(close, _IO_wfile_disabled_close),
+  JUMP_INIT(stat, _IO_wfile_disabled_stat),
+  JUMP_INIT(showmanyc, _IO_wfile_disabled_showmanyc),
+  JUMP_INIT(imbue, _IO_wfile_disabled_imbue)
+};
+
+strong_alias (_IO_wfile_jumps_disabled, _IO_wfile_jumps)
+libc_hidden_data_def (_IO_wfile_jumps)
+strong_alias (_IO_wfile_jumps_disabled, _IO_wfile_jumps_mmap)
+strong_alias (_IO_wfile_jumps_disabled, _IO_wfile_jumps_maybe_mmap)
Index: git/locale/catnames.c
===================================================================
--- /dev/null
+++ git/locale/catnames.c
@@ -0,0 +1,48 @@
+/* Copyright (C) 2006  Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 2.1 of the License, or (at your option) any later version.
+
+   The GNU C Library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with the GNU C Library; if not, write to the Free
+   Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+   02111-1307 USA.  */
+
+#include "localeinfo.h"
+
+/* Define an array of category names (also the environment variable names).  */
+const union catnamestr_t _nl_category_names attribute_hidden =
+  {
+    {
+#define DEFINE_CATEGORY(category, category_name, items, a) \
+      category_name,
+#include "categories.def"
+#undef DEFINE_CATEGORY
+    }
+  };
+
+const uint8_t _nl_category_name_idxs[__LC_LAST] attribute_hidden =
+  {
+#define DEFINE_CATEGORY(category, category_name, items, a) \
+    [category] = offsetof (union catnamestr_t, CATNAMEMF (__LINE__)),
+#include "categories.def"
+#undef DEFINE_CATEGORY
+  };
+
+/* An array of their lengths, for convenience.  */
+const uint8_t _nl_category_name_sizes[] attribute_hidden =
+  {
+#define DEFINE_CATEGORY(category, category_name, items, a) \
+    [category] = sizeof (category_name) - 1,
+#include "categories.def"
+#undef	DEFINE_CATEGORY
+    [LC_ALL] = sizeof ("LC_ALL") - 1
+  };
Index: git/locale/C-ctype.c
===================================================================
--- git.orig/locale/C-ctype.c
+++ git/locale/C-ctype.c
@@ -19,8 +19,11 @@
 #include "localeinfo.h"
 #include <endian.h>
 #include <stdint.h>
+#include <gnu/option-groups.h>
 
+#if __OPTION_EGLIBC_LOCALE_CODE
 #include "C-translit.h"
+#endif
 
 /* This table's entries are taken from POSIX.2 Table 2-6
    ``LC_CTYPE Category Definition in the POSIX Locale''.
@@ -647,6 +650,7 @@ const struct __locale_data _nl_C_LC_CTYP
     { .word = L'7' },
     { .word = L'8' },
     { .word = L'9' },
+#if __OPTION_EGLIBC_LOCALE_CODE
     /* _NL_CTYPE_TRANSLIT_TAB_SIZE */
     { .word = NTRANSLIT },
     /* _NL_CTYPE_TRANSLIT_FROM_IDX */
@@ -657,6 +661,22 @@ const struct __locale_data _nl_C_LC_CTYP
     { .wstr = translit_to_idx },
     /* _NL_CTYPE_TRANSLIT_TO_TBL */
     { .wstr = (uint32_t *) translit_to_tbl },
+#else
+    /* If the locale code isn't enabled, we don't have the
+       transliteration code in iconv/gconv_trans.c anyway, so there's
+       no need for the transliteration tables here.  We'll fall back
+       on the default missing replacement, '?'.  */
+    /* _NL_CTYPE_TRANSLIT_TAB_SIZE */
+    { .word = 0 },
+    /* _NL_CTYPE_TRANSLIT_FROM_IDX */
+    { .wstr = NULL },
+    /* _NL_CTYPE_TRANSLIT_FROM_TBL */
+    { .wstr = NULL },
+    /* _NL_CTYPE_TRANSLIT_TO_IDX */
+    { .wstr = NULL },
+    /* _NL_CTYPE_TRANSLIT_TO_TBL */
+    { .wstr = NULL },
+#endif
     /* _NL_CTYPE_TRANSLIT_DEFAULT_MISSING_LEN */
     { .word = 1 },
     /* _NL_CTYPE_TRANSLIT_DEFAULT_MISSING */
Index: git/locale/dummy-setlocale.c
===================================================================
--- /dev/null
+++ git/locale/dummy-setlocale.c
@@ -0,0 +1,33 @@
+/* Copyright (C) 2006  Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 2.1 of the License, or (at your option) any later version.
+
+   The GNU C Library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with the GNU C Library; if not, write to the Free
+   Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+   02111-1307 USA.  */
+
+#include <string.h>
+#include <locale.h>
+
+char *
+setlocale (int category, const char *locale)
+{
+  if (! locale
+      || locale[0] == '\0'
+      || strcmp (locale, "C") == 0
+      || strcmp (locale, "POSIX") == 0)
+    return (char *) "C";
+  else
+    return NULL;
+}
+libc_hidden_def (setlocale)
Index: git/locale/localeinfo.h
===================================================================
--- git.orig/locale/localeinfo.h
+++ git/locale/localeinfo.h
@@ -224,7 +224,7 @@ __libc_tsd_define (extern, __locale_t, L
    unused.  We can manage this playing some tricks with weak references.
    But with thread-local locale settings, it becomes quite ungainly unless
    we can use __thread variables.  So only in that case do we attempt this.  */
-#ifndef SHARED
+#if !defined SHARED && !defined IN_GLIBC_LOCALEDEF
 # include <tls.h>
 # define NL_CURRENT_INDIRECT	1
 #endif
Index: git/locale/Makefile
===================================================================
--- git.orig/locale/Makefile
+++ git/locale/Makefile
@@ -18,27 +18,43 @@
 #
 #	Makefile for locales.
 #
+include ../option-groups.mak
+
 subdir	:= locale
 
 include ../Makeconfig
 
 headers		= locale.h bits/locale.h langinfo.h xlocale.h
-routines	= setlocale findlocale loadlocale loadarchive \
-		  localeconv nl_langinfo nl_langinfo_l mb_cur_max \
-		  newlocale duplocale freelocale uselocale
-tests		= tst-C-locale tst-locname tst-duplocale
+# catnames is needed by OPTION_EGLIBC_LOCALE_CODE and by the 'intl' code.
+# If we put the latter in an option group, too, we can omit catnames
+# when both option groups are disabled.  libstdc++-v3 needs mb_cur_max.
+routines-y      := catnames mb_cur_max
+routines-$(OPTION_EGLIBC_LOCALE_CODE) \
+		+= setlocale findlocale loadlocale loadarchive \
+		   localeconv nl_langinfo nl_langinfo_l \
+		   newlocale duplocale freelocale uselocale
+ifneq (y,$(OPTION_EGLIBC_LOCALE_CODE))
+routines-y	+= dummy-setlocale
+endif
+tests-$(OPTION_EGLIBC_LOCALE_CODE) += tst-C-locale tst-locname tst-duplocale
 categories	= ctype messages monetary numeric time paper name \
 		  address telephone measurement identification collate
-aux		= $(categories:%=lc-%) $(categories:%=C-%) SYS_libc C_name \
-		  xlocale localename global-locale coll-lookup
-others		= localedef locale
+# C-messages belongs in an intl option group.
+aux-y		:= C-ctype C-time \
+		   SYS_libc C_name xlocale global-locale coll-lookup
+aux-$(OPTION_EGLIBC_LOCALE_CODE) \
+		+= $(filter-out $(aux-y), \
+	                        $(categories:%=lc-%) $(categories:%=C-%)) \
+	           localename
+others-$(OPTION_EGLIBC_LOCALE_CODE) = localedef locale
 #others-static	= localedef locale
-install-bin	= localedef locale
-extra-objs	= $(localedef-modules:=.o) $(localedef-aux:=.o) \
+install-bin	= $(others-y)
+extra-objs-$(OPTION_EGLIBC_LOCALE_CODE) \
+		= $(localedef-modules:=.o) $(localedef-aux:=.o) \
 		  $(locale-modules:=.o) $(lib-modules:=.o)
 
-extra-libs	= libBrokenLocale
-extra-libs-others = $(extra-libs)
+extra-libs-$(OPTION_EGLIBC_LOCALE_CODE) = libBrokenLocale
+extra-libs-others = $(extra-libs-y)
 
 libBrokenLocale-routines = broken_cur_max
 
@@ -93,6 +109,9 @@ CPPFLAGS-locale-programs = -DLOCALE_PATH
 CFLAGS-charmap.c = -Wno-write-strings -Wno-char-subscripts
 CFLAGS-locfile.c = -Wno-write-strings -Wno-char-subscripts
 CFLAGS-charmap-dir.c = -Wno-write-strings
+ifneq (y,$(OPTION_EGLIBC_SPAWN))
+CFLAGS-charmap-dir.c += -DNO_UNCOMPRESS
+endif
 
 # Set libof-* for each routine.
 cpp-srcs-left := $(localedef-modules) $(localedef-aux) $(locale-modules) \
Index: git/locale/programs/charmap-dir.c
===================================================================
--- git.orig/locale/programs/charmap-dir.c
+++ git/locale/programs/charmap-dir.c
@@ -19,7 +19,9 @@
 #include <error.h>
 #include <fcntl.h>
 #include <libintl.h>
+#ifndef NO_UNCOMPRESS
 #include <spawn.h>
+#endif
 #include <stdio.h>
 #include <stdlib.h>
 #include <string.h>
@@ -156,6 +158,7 @@ charmap_closedir (CHARMAP_DIR *cdir)
   return closedir (dir);
 }
 
+#ifndef NO_UNCOMPRESS
 /* Creates a subprocess decompressing the given pathname, and returns
    a stream reading its output (the decompressed data).  */
 static
@@ -204,6 +207,7 @@ fopen_uncompressed (const char *pathname
     }
   return NULL;
 }
+#endif
 
 /* Opens a charmap for reading, given its name (not an alias name).  */
 FILE *
@@ -226,6 +230,7 @@ charmap_open (const char *directory, con
   if (stream != NULL)
     return stream;
 
+#ifndef NO_UNCOMPRESS
   memcpy (p, ".gz", 4);
   stream = fopen_uncompressed (pathname, "gzip");
   if (stream != NULL)
@@ -235,6 +240,7 @@ charmap_open (const char *directory, con
   stream = fopen_uncompressed (pathname, "bzip2");
   if (stream != NULL)
     return stream;
+#endif
 
   return NULL;
 }
Index: git/locale/programs/ld-collate.c
===================================================================
--- git.orig/locale/programs/ld-collate.c
+++ git/locale/programs/ld-collate.c
@@ -350,7 +350,7 @@ new_element (struct locale_collate_t *co
     }
   if (wcs != NULL)
     {
-      size_t nwcs = wcslen ((wchar_t *) wcs);
+      size_t nwcs = wcslen_uint32 (wcs);
       uint32_t zero = 0;
       /* Handle <U0000> as a single character.  */
       if (nwcs == 0)
@@ -1776,8 +1776,7 @@ symbol `%s' has the same encoding as"),
 
 	      if ((*eptr)->nwcs == runp->nwcs)
 		{
-		  int c = wmemcmp ((wchar_t *) (*eptr)->wcs,
-				   (wchar_t *) runp->wcs, runp->nwcs);
+		  int c = wmemcmp_uint32 ((*eptr)->wcs, runp->wcs, runp->nwcs);
 
 		  if (c == 0)
 		    {
@@ -2010,9 +2009,9 @@ add_to_tablewc (uint32_t ch, struct elem
 	     one consecutive entry.  */
 	  if (runp->wcnext != NULL
 	      && runp->nwcs == runp->wcnext->nwcs
-	      && wmemcmp ((wchar_t *) runp->wcs,
-			  (wchar_t *)runp->wcnext->wcs,
-			  runp->nwcs - 1) == 0
+	      && wmemcmp_uint32 (runp->wcs,
+				 runp->wcnext->wcs,
+				 runp->nwcs - 1) == 0
 	      && (runp->wcs[runp->nwcs - 1]
 		  == runp->wcnext->wcs[runp->nwcs - 1] + 1))
 	    {
@@ -2036,9 +2035,9 @@ add_to_tablewc (uint32_t ch, struct elem
 		runp = runp->wcnext;
 	      while (runp->wcnext != NULL
 		     && runp->nwcs == runp->wcnext->nwcs
-		     && wmemcmp ((wchar_t *) runp->wcs,
-				 (wchar_t *)runp->wcnext->wcs,
-				 runp->nwcs - 1) == 0
+		     && wmemcmp_uint32 (runp->wcs,
+					runp->wcnext->wcs,
+					runp->nwcs - 1) == 0
 		     && (runp->wcs[runp->nwcs - 1]
 			 == runp->wcnext->wcs[runp->nwcs - 1] + 1));
 
Index: git/locale/programs/ld-ctype.c
===================================================================
--- git.orig/locale/programs/ld-ctype.c
+++ git/locale/programs/ld-ctype.c
@@ -960,7 +960,7 @@ ctype_output (struct localedef_t *locale
   allocate_arrays (ctype, charmap, ctype->repertoire);
 
   default_missing_len = (ctype->default_missing
-			 ? wcslen ((wchar_t *) ctype->default_missing)
+			 ? wcslen_uint32 (ctype->default_missing)
 			 : 0);
 
   init_locale_data (&file, nelems);
@@ -1971,7 +1971,7 @@ read_translit_entry (struct linereader *
 	    ignore = 1;
 	  else
 	    /* This value is usable.  */
-	    obstack_grow (ob, to_wstr, wcslen ((wchar_t *) to_wstr) * 4);
+	    obstack_grow (ob, to_wstr, wcslen_uint32 (to_wstr) * 4);
 
 	  first = 0;
 	}
@@ -2519,8 +2519,8 @@ with character code range values one mus
 	    }
 
 	handle_tok_digit:
-	  class_bit = _ISwdigit;
-	  class256_bit = _ISdigit;
+	  class_bit = BITw (tok_digit);
+	  class256_bit = BIT (tok_digit);
 	  handle_digits = 1;
 	  goto read_charclass;
 
@@ -4002,8 +4002,7 @@ allocate_arrays (struct locale_ctype_t *
 
 	  while (idx < number)
 	    {
-	      int res = wcscmp ((const wchar_t *) sorted[idx]->from,
-				(const wchar_t *) runp->from);
+	      int res = wcscmp_uint32 (sorted[idx]->from, runp->from);
 	      if (res == 0)
 		{
 		  replace = 1;
@@ -4040,11 +4039,11 @@ allocate_arrays (struct locale_ctype_t *
       for (size_t cnt = 0; cnt < number; ++cnt)
 	{
 	  struct translit_to_t *srunp;
-	  from_len += wcslen ((const wchar_t *) sorted[cnt]->from) + 1;
+	  from_len += wcslen_uint32 (sorted[cnt]->from) + 1;
 	  srunp = sorted[cnt]->to;
 	  while (srunp != NULL)
 	    {
-	      to_len += wcslen ((const wchar_t *) srunp->str) + 1;
+	      to_len += wcslen_uint32 (srunp->str) + 1;
 	      srunp = srunp->next;
 	    }
 	  /* Plus one for the extra NUL character marking the end of
@@ -4068,18 +4067,18 @@ allocate_arrays (struct locale_ctype_t *
 	  ctype->translit_from_idx[cnt] = from_len;
 	  ctype->translit_to_idx[cnt] = to_len;
 
-	  len = wcslen ((const wchar_t *) sorted[cnt]->from) + 1;
-	  wmemcpy ((wchar_t *) &ctype->translit_from_tbl[from_len],
-		   (const wchar_t *) sorted[cnt]->from, len);
+	  len = wcslen_uint32 (sorted[cnt]->from) + 1;
+	  wmemcpy_uint32 (&ctype->translit_from_tbl[from_len],
+			  sorted[cnt]->from, len);
 	  from_len += len;
 
 	  ctype->translit_to_idx[cnt] = to_len;
 	  srunp = sorted[cnt]->to;
 	  while (srunp != NULL)
 	    {
-	      len = wcslen ((const wchar_t *) srunp->str) + 1;
-	      wmemcpy ((wchar_t *) &ctype->translit_to_tbl[to_len],
-		       (const wchar_t *) srunp->str, len);
+	      len = wcslen_uint32 (srunp->str) + 1;
+	      wmemcpy_uint32 (&ctype->translit_to_tbl[to_len],
+			      srunp->str, len);
 	      to_len += len;
 	      srunp = srunp->next;
 	    }
Index: git/locale/programs/ld-messages.c
===================================================================
--- git.orig/locale/programs/ld-messages.c
+++ git/locale/programs/ld-messages.c
@@ -25,6 +25,7 @@
 #include <string.h>
 #include <stdint.h>
 #include <sys/uio.h>
+#include <gnu/option-groups.h>
 
 #include <assert.h>
 
@@ -124,6 +125,7 @@ No definition for %s category found"), "
     }
   else
     {
+#if __OPTION_POSIX_REGEXP
       int result;
       regex_t re;
 
@@ -140,6 +142,7 @@ No definition for %s category found"), "
 	}
       else if (result != 0)
 	regfree (&re);
+#endif
     }
 
   if (messages->noexpr == NULL)
@@ -158,6 +161,7 @@ No definition for %s category found"), "
     }
   else
     {
+#if __OPTION_POSIX_REGEXP
       int result;
       regex_t re;
 
@@ -174,6 +178,7 @@ No definition for %s category found"), "
 	}
       else if (result != 0)
 	regfree (&re);
+#endif
     }
 }
 
Index: git/locale/programs/ld-time.c
===================================================================
--- git.orig/locale/programs/ld-time.c
+++ git/locale/programs/ld-time.c
@@ -215,8 +215,10 @@ No definition for %s category found"), "
 	}
       else
 	{
+	  static const uint32_t wt_fmt_ampm[]
+	    = { '%','I',':','%','M',':','%','S',' ','%','p',0 };
 	  time->t_fmt_ampm = "%I:%M:%S %p";
-	  time->wt_fmt_ampm = (const uint32_t *) L"%I:%M:%S %p";
+	  time->wt_fmt_ampm = wt_fmt_ampm;
 	}
     }
 
@@ -226,7 +228,7 @@ No definition for %s category found"), "
       const int days_per_month[12] = { 31, 29, 31, 30, 31, 30,
 				       31, 31, 30, 31 ,30, 31 };
       size_t idx;
-      wchar_t *wstr;
+      uint32_t *wstr;
 
       time->era_entries =
 	(struct era_data *) xmalloc (time->num_era
@@ -464,18 +466,18 @@ No definition for %s category found"), "
 	    }
 
 	  /* Now generate the wide character name and format.  */
-	  wstr = wcschr ((wchar_t *) time->wera[idx], L':');/* end direction */
-	  wstr = wstr ? wcschr (wstr + 1, L':') : NULL;	/* end offset */
-	  wstr = wstr ? wcschr (wstr + 1, L':') : NULL;	/* end start */
-	  wstr = wstr ? wcschr (wstr + 1, L':') : NULL;	/* end end */
+	  wstr = wcschr_uint32 (time->wera[idx], L':'); /* end direction */
+	  wstr = wstr ? wcschr_uint32 (wstr + 1, L':') : NULL; /* end offset */
+	  wstr = wstr ? wcschr_uint32 (wstr + 1, L':') : NULL; /* end start */
+	  wstr = wstr ? wcschr_uint32 (wstr + 1, L':') : NULL; /* end end */
 	  if (wstr != NULL)
 	    {
-	      time->era_entries[idx].wname = (uint32_t *) wstr + 1;
-	      wstr = wcschr (wstr + 1, L':');	/* end name */
+	      time->era_entries[idx].wname = wstr + 1;
+	      wstr = wcschr_uint32 (wstr + 1, L':'); /* end name */
 	      if (wstr != NULL)
 		{
 		  *wstr = L'\0';
-		  time->era_entries[idx].wformat = (uint32_t *) wstr + 1;
+		  time->era_entries[idx].wformat = wstr + 1;
 		}
 	      else
 		time->era_entries[idx].wname =
@@ -530,7 +532,16 @@ No definition for %s category found"), "
   if (time->date_fmt == NULL)
     time->date_fmt = "%a %b %e %H:%M:%S %Z %Y";
   if (time->wdate_fmt == NULL)
-    time->wdate_fmt = (const uint32_t *) L"%a %b %e %H:%M:%S %Z %Y";
+    {
+      static const uint32_t wdate_fmt[] =
+	{ '%','a',' ',
+	  '%','b',' ',
+	  '%','e',' ',
+	  '%','H',':','%','M',':','%','S',' ',
+	  '%','Z',' ',
+	  '%','Y',0 };
+      time->wdate_fmt = wdate_fmt;
+    }
 }
 
 
Index: git/locale/programs/linereader.c
===================================================================
--- git.orig/locale/programs/linereader.c
+++ git/locale/programs/linereader.c
@@ -595,7 +595,7 @@ get_string (struct linereader *lr, const
 {
   int return_widestr = lr->return_widestr;
   char *buf;
-  wchar_t *buf2 = NULL;
+  uint32_t *buf2 = NULL;
   size_t bufact;
   size_t bufmax = 56;
 
Index: git/locale/programs/localedef.c
===================================================================
--- git.orig/locale/programs/localedef.c
+++ git/locale/programs/localedef.c
@@ -114,6 +114,7 @@ void (*argp_program_version_hook) (FILE
 #define OPT_LIST_ARCHIVE 309
 #define OPT_LITTLE_ENDIAN 400
 #define OPT_BIG_ENDIAN 401
+#define OPT_UINT32_ALIGN 402
 
 /* Definitions of arguments for argp functions.  */
 static const struct argp_option options[] =
@@ -150,6 +151,8 @@ static const struct argp_option options[
     N_("Generate little-endian output") },
   { "big-endian", OPT_BIG_ENDIAN, NULL, 0,
     N_("Generate big-endian output") },
+  { "uint32-align", OPT_UINT32_ALIGN, "ALIGNMENT", 0,
+    N_("Set the target's uint32_t alignment in bytes (default 4)") },
   { NULL, 0, NULL, 0, NULL }
 };
 
@@ -239,12 +242,14 @@ main (int argc, char *argv[])
      ctype locale.  (P1003.2 4.35.5.2)  */
   setlocale (LC_CTYPE, "POSIX");
 
+#ifndef NO_SYSCONF
   /* Look whether the system really allows locale definitions.  POSIX
      defines error code 3 for this situation so I think it must be
      a fatal error (see P1003.2 4.35.8).  */
   if (sysconf (_SC_2_LOCALEDEF) < 0)
     WITH_CUR_LOCALE (error (3, 0, _("\
 FATAL: system does not define `_POSIX2_LOCALEDEF'")));
+#endif
 
   /* Process charmap file.  */
   charmap = charmap_read (charmap_file, verbose, 1, be_quiet, 1);
@@ -338,6 +343,9 @@ parse_opt (int key, char *arg, struct ar
     case OPT_BIG_ENDIAN:
       set_big_endian (true);
       break;
+    case OPT_UINT32_ALIGN:
+      uint32_align_mask = strtol (arg, NULL, 0) - 1;
+      break;
     case 'c':
       force_output = 1;
       break;
Index: git/locale/programs/locfile.c
===================================================================
--- git.orig/locale/programs/locfile.c
+++ git/locale/programs/locfile.c
@@ -544,6 +544,9 @@ compare_files (const char *filename1, co
    machine running localedef.  */
 bool swap_endianness_p;
 
+/* The target's value of __align__(uint32_t) - 1.  */
+unsigned int uint32_align_mask = 3;
+
 /* When called outside a start_locale_structure/end_locale_structure
    or start_locale_prelude/end_locale_prelude block, record that the
    next byte in FILE's obstack will be the first byte of a new element.
@@ -621,7 +624,7 @@ add_locale_string (struct locale_file *f
 void
 add_locale_wstring (struct locale_file *file, const uint32_t *string)
 {
-  add_locale_uint32_array (file, string, wcslen ((const wchar_t *) string) + 1);
+  add_locale_uint32_array (file, string, wcslen_uint32 (string) + 1);
 }
 
 /* Record that FILE's next element is the 32-bit integer VALUE.  */
Index: git/locale/programs/locfile.h
===================================================================
--- git.orig/locale/programs/locfile.h
+++ git/locale/programs/locfile.h
@@ -71,6 +71,8 @@ extern void write_all_categories (struct
 
 extern bool swap_endianness_p;
 
+extern unsigned int uint32_align_mask;
+
 /* Change the output to be big-endian if BIG_ENDIAN is true and
    little-endian otherwise.  */
 static inline void
@@ -89,7 +91,8 @@ maybe_swap_uint32 (uint32_t value)
 }
 
 /* Likewise, but munge an array of N uint32_ts starting at ARRAY.  */
-static inline void
+static void
+__attribute__ ((unused))
 maybe_swap_uint32_array (uint32_t *array, size_t n)
 {
   if (swap_endianness_p)
@@ -99,7 +102,8 @@ maybe_swap_uint32_array (uint32_t *array
 
 /* Like maybe_swap_uint32_array, but the array of N elements is at
    the end of OBSTACK's current object.  */
-static inline void
+static void
+__attribute__ ((unused))
 maybe_swap_uint32_obstack (struct obstack *obstack, size_t n)
 {
   maybe_swap_uint32_array ((uint32_t *) obstack_next_free (obstack) - n, n);
@@ -276,4 +280,55 @@ extern void identification_output (struc
 				   const struct charmap_t *charmap,
 				   const char *output_path);
 
+static size_t wcslen_uint32 (const uint32_t *str) __attribute__ ((unused));
+static uint32_t * wmemcpy_uint32 (uint32_t *s1, const uint32_t *s2, size_t n) __attribute__ ((unused));
+static uint32_t * wcschr_uint32 (const uint32_t *s, uint32_t ch) __attribute__ ((unused));
+static int wcscmp_uint32 (const uint32_t *s1, const uint32_t *s2) __attribute__ ((unused));
+static int wmemcmp_uint32 (const uint32_t *s1, const uint32_t *s2, size_t n) __attribute__ ((unused));
+
+static size_t
+wcslen_uint32 (const uint32_t *str)
+{
+  size_t len = 0;
+  while (str[len] != 0)
+    len++;
+  return len;
+}
+
+static  int
+wmemcmp_uint32 (const uint32_t *s1, const uint32_t *s2, size_t n)
+{
+  while (n-- != 0)
+    {
+      int diff = *s1++ - *s2++;
+      if (diff != 0)
+	return diff;
+    }
+  return 0;
+}
+
+static int
+wcscmp_uint32 (const uint32_t *s1, const uint32_t *s2)
+{
+  while (*s1 != 0 && *s1 == *s2)
+    s1++, s2++;
+  return *s1 - *s2;
+}
+
+static uint32_t *
+wmemcpy_uint32 (uint32_t *s1, const uint32_t *s2, size_t n)
+{
+  return memcpy (s1, s2, n * sizeof (uint32_t));
+}
+
+static uint32_t *
+wcschr_uint32 (const uint32_t *s, uint32_t ch)
+{
+  do
+    if (*s == ch)
+      return (uint32_t *) s;
+  while (*s++ != 0);
+  return 0;
+}
+
 #endif /* locfile.h */
Index: git/locale/setlocale.c
===================================================================
--- git.orig/locale/setlocale.c
+++ git/locale/setlocale.c
@@ -64,36 +64,6 @@ static char *const _nl_current_used[] =
 #endif
 
 
-/* Define an array of category names (also the environment variable names).  */
-const union catnamestr_t _nl_category_names attribute_hidden =
-  {
-    {
-#define DEFINE_CATEGORY(category, category_name, items, a) \
-      category_name,
-#include "categories.def"
-#undef DEFINE_CATEGORY
-    }
-  };
-
-const uint8_t _nl_category_name_idxs[__LC_LAST] attribute_hidden =
-  {
-#define DEFINE_CATEGORY(category, category_name, items, a) \
-    [category] = offsetof (union catnamestr_t, CATNAMEMF (__LINE__)),
-#include "categories.def"
-#undef DEFINE_CATEGORY
-  };
-
-/* An array of their lengths, for convenience.  */
-const uint8_t _nl_category_name_sizes[] attribute_hidden =
-  {
-#define DEFINE_CATEGORY(category, category_name, items, a) \
-    [category] = sizeof (category_name) - 1,
-#include "categories.def"
-#undef	DEFINE_CATEGORY
-    [LC_ALL] = sizeof ("LC_ALL") - 1
-  };
-
-
 #ifdef NL_CURRENT_INDIRECT
 # define WEAK_POSTLOAD(postload) weak_extern (postload)
 #else
Index: git/locale/xlocale.c
===================================================================
--- git.orig/locale/xlocale.c
+++ git/locale/xlocale.c
@@ -18,6 +18,7 @@
    <http://www.gnu.org/licenses/>.  */
 
 #include <locale.h>
+#include <gnu/option-groups.h>
 #include "localeinfo.h"
 
 #define DEFINE_CATEGORY(category, category_name, items, a) \
@@ -25,6 +26,19 @@ extern struct __locale_data _nl_C_##cate
 #include "categories.def"
 #undef	DEFINE_CATEGORY
 
+/* If the locale support code isn't enabled, don't generate strong
+   reference to the C locale_data structures here; let the Makefile
+   decide which ones to include.  (In the static linking case, the
+   strong reference to the 'class', 'toupper', and 'tolower' tables
+   will cause C-ctype.o to be brought in, as it should be, even when
+   the reference to _nl_C_LC_CTYPE will be weak.)  */
+#if ! __OPTION_EGLIBC_LOCALE_CODE
+# define DEFINE_CATEGORY(category, category_name, items, a) \
+  weak_extern (_nl_C_##category)
+# include "categories.def"
+# undef	DEFINE_CATEGORY
+#endif
+
 /* Defined in locale/C-ctype.c.  */
 extern const char _nl_C_LC_CTYPE_class[] attribute_hidden;
 extern const char _nl_C_LC_CTYPE_toupper[] attribute_hidden;
@@ -52,3 +66,26 @@ const struct __locale_struct _nl_C_locob
     .__ctype_tolower = (const int *) _nl_C_LC_CTYPE_tolower + 128,
     .__ctype_toupper = (const int *) _nl_C_LC_CTYPE_toupper + 128
   };
+
+
+#if ! __OPTION_EGLIBC_LOCALE_CODE
+/* When locale code is enabled, these are each defined in the
+   appropriate lc-CATEGORY.c file, so that static links (when __thread
+   is supported) bring in only those lc-CATEGORY.o files for
+   categories the program actually uses; look for NL_CURRENT_INDIRECT
+   in localeinfo.h.
+
+   When locale code is disabled, the _nl_C_CATEGORY objects are the
+   only possible referents.  At the moment, there isn't a way to get
+   __OPTION_EGLIBC_LOCALE_CODE defined in every compilation unit that
+   #includes localeinfo.h, so we can't just turn off
+   NL_CURRENT_INDIRECT.  So we'll define the _nl_current_CATEGORY
+   pointers here.  */
+#if defined (NL_CURRENT_INDIRECT)
+#define DEFINE_CATEGORY(category, category_name, items, a)      \
+  __thread struct __locale_data * const *_nl_current_##category   \
+  attribute_hidden = &_nl_C_locobj.__locales[category];
+#include "categories.def"
+#undef DEFINE_CATEGORY
+#endif
+#endif /* __OPTION_EGLIBC_LOCALE_CODE */
Index: git/localedata/Makefile
===================================================================
--- git.orig/localedata/Makefile
+++ git/localedata/Makefile
@@ -21,12 +21,22 @@ subdir := localedata
 
 include ../Makeconfig
 
-# List with all available character set descriptions.
-charmaps := $(wildcard charmaps/[A-I]*) $(wildcard charmaps/[J-Z]*)
+include ../option-groups.mak
 
 # List with all available character set descriptions.
-locales := $(wildcard locales/*)
+all-charmaps := $(wildcard charmaps/[A-I]*) $(wildcard charmaps/[J-Z]*)
+
+all-locales := $(wildcard locales/*)
 
+# If the EGLIBC_LOCALES option group is not enabled, trim the
+# list of charmap and locale source files.
+ifeq ($(OPTION_EGLIBC_LOCALES),y)
+charmaps := $(all-charmaps)
+locales  := $(all-locales)
+else
+charmaps :=
+locales  := locales/POSIX
+endif
 
 subdir-dirs = tests-mbwc
 vpath %.c tests-mbwc
@@ -71,14 +81,20 @@ locale_test_suite := tst_iswalnum tst_is
 		     tst_wcsxfrm tst_wctob tst_wctomb tst_wctrans      \
 		     tst_wctype tst_wcwidth
 
-tests = $(locale_test_suite) tst-digits tst-setlocale bug-iconv-trans \
+# Since these tests build their own locale files, they're not
+# dependent on the OPTION_EGLIBC_LOCALES option group.  But they do
+# need the locale functions to be present.
+tests-$(OPTION_EGLIBC_LOCALE_CODE) \
+     += $(locale_test_suite) tst-digits tst-setlocale bug-iconv-trans \
 	tst-leaks tst-mbswcs1 tst-mbswcs2 tst-mbswcs3 tst-mbswcs4 tst-mbswcs5 \
 	tst-mbswcs6 tst-xlocale1 tst-xlocale2 bug-usesetlocale \
 	tst-strfmon1 tst-sscanf bug-setlocale1 tst-setlocale2 tst-setlocale3 \
 	tst-wctype
+ifeq (y,$(OPTION_EGLIBC_LOCALE_CODE))
 tests-static = bug-setlocale1-static
 tests += $(tests-static)
-ifeq (yes,$(build-shared))
+endif
+ifeq (yesy,$(build-shared)$(OPTION_EGLIBC_LOCALE_CODE))
 ifneq (no,$(PERL))
 tests-special += $(objpfx)mtrace-tst-leaks.out
 endif
@@ -95,6 +111,7 @@ tests: $(objdir)/iconvdata/gconv-modules
 tests-static += tst-langinfo-static
 
 ifeq ($(run-built-tests),yes)
+ifeq (y,$(OPTION_EGLIBC_LOCALE_CODE))
 tests-special += $(objpfx)sort-test.out $(objpfx)tst-fmon.out \
 		 $(objpfx)tst-locale.out $(objpfx)tst-rpmatch.out \
 		 $(objpfx)tst-trans.out $(objpfx)tst-ctype.out \
@@ -113,6 +130,7 @@ CHARMAPS := $(shell echo "$(LOCALES)" |
 CTYPE_FILES = $(addsuffix /LC_CTYPE,$(LOCALES))
 tests-special += $(addprefix $(objpfx),$(CTYPE_FILES))
 endif
+endif
 
 include ../Rules
 
@@ -205,6 +223,11 @@ endif
 
 include SUPPORTED
 
+# Only install locale data if OPTION_EGLIBC_LOCALES is selected.
+ifneq ($(OPTION_EGLIBC_LOCALES),y)
+SUPPORTED-LOCALES :=
+endif
+
 INSTALL-SUPPORTED-LOCALES=$(addprefix install-, $(SUPPORTED-LOCALES))
 
 # Sometimes the whole collection of locale files should be installed.
Index: git/login/Makefile
===================================================================
--- git.orig/login/Makefile
+++ git/login/Makefile
@@ -18,6 +18,7 @@
 #
 #	Sub-makefile for login portion of the library.
 #
+include ../option-groups.mak
 
 subdir	:= login
 
@@ -25,14 +26,16 @@ include ../Makeconfig
 
 headers	:= utmp.h bits/utmp.h lastlog.h pty.h
 
-routines := getlogin getlogin_r setlogin getlogin_r_chk \
-	    getutent getutent_r getutid getutline getutid_r getutline_r \
-	    utmp_file utmpname updwtmp getpt grantpt unlockpt ptsname \
-	    ptsname_r_chk
+routines := getpt grantpt unlockpt ptsname ptsname_r_chk
+routines-$(OPTION_EGLIBC_UTMP) \
+	 += getutent getutent_r getutid getutline getutid_r getutline_r \
+	    utmp_file utmpname updwtmp
+routines-$(OPTION_EGLIBC_GETLOGIN) += getlogin getlogin_r getlogin_r_chk
+routines-$(OPTION_EGLIBC_BSD) += setlogin
 
 CFLAGS-grantpt.c = -DLIBEXECDIR='"$(libexecdir)"'
 
-others = utmpdump
+others-$(OPTION_EGLIBC_UTMP) += utmpdump
 
 ifeq (yes,$(build-pt-chown))
 others += pt_chown
@@ -46,8 +49,8 @@ vpath %.c programs
 tests := tst-utmp tst-utmpx tst-grantpt tst-ptsname
 
 # Build the -lutil library with these extra functions.
-extra-libs      := libutil
-extra-libs-others := $(extra-libs)
+extra-libs-$(OPTION_EGLIBC_UTMP) := libutil
+extra-libs-others := $(extra-libs-y)
 
 libutil-routines:= login login_tty logout logwtmp openpty forkpty
 
Index: git/Makeconfig
===================================================================
--- git.orig/Makeconfig
+++ git/Makeconfig
@@ -582,7 +582,7 @@ elf-objpfx = $(common-objpfx)elf/
 # and run on the build system, causes that program with those
 # arguments to be run on the host for which the library is built.
 ifndef test-wrapper
-test-wrapper =
+test-wrapper = $(cross-test-wrapper)
 endif
 # Likewise, but the name of the program is preceded by
 # <variable>=<value> assignments for environment variables.
@@ -1055,6 +1055,24 @@ else
 libm = $(common-objpfx)math/libm.a
 endif
 
+# Generate a header file that #defines preprocessor symbols indicating
+# which option groups are enabled.  Note that the option-groups.config file
+# may not exist at all.
+before-compile += $(common-objpfx)gnu/option-groups.h
+common-generated += gnu/option-groups.h gnu/option-groups.stmp
+headers += gnu/option-groups.h
+$(common-objpfx)gnu/option-groups.h: $(common-objpfx)gnu/option-groups.stmp; @:
+$(common-objpfx)gnu/option-groups.stmp:					\
+		$(..)scripts/option-groups.awk				\
+		$(..)option-groups.defaults				\
+		$(wildcard $(common-objpfx)option-groups.config)
+	$(make-target-directory)
+	@rm -f ${@:stmp=T} $@
+	LC_ALL=C $(AWK) -f $^ > ${@:stmp=T}
+	$(move-if-change) ${@:stmp=T} ${@:stmp=h}
+	touch $@
+
+
 # These are the subdirectories containing the library source.  The order
 # is more or less arbitrary.  The sorting step will take care of the
 # dependencies.
Index: git/Makerules
===================================================================
--- git.orig/Makerules
+++ git/Makerules
@@ -446,6 +446,25 @@ define sed-remove-objpfx
 endef
 endif
 
+# Include targets in the selected option groups.
+aux                  += $(aux-y)
+extra-libs           += $(extra-libs-y)
+extra-libs-others    += $(extra-libs-others-y)
+extra-objs           += $(extra-objs-y)
+install-bin          += $(install-bin-y)
+install-others       += $(install-others-y)
+install-sbin         += $(install-sbin-y)
+modules              += $(modules-y)
+others               += $(others-y)
+others-pie           += $(others-pie-y)
+routines             += $(routines-y)
+static-only-routines += $(static-only-routines-y)
+sysdep_routines      += $(sysdep_routines-y)
+test-srcs            += $(test-srcs-y)
+tests                += $(tests-y)
+xtests               += $(xtests-y)
+
+
 # Modify the list of routines we build for different targets
 
 ifeq (yes,$(build-shared))
Index: git/malloc/Makefile
===================================================================
--- git.orig/malloc/Makefile
+++ git/malloc/Makefile
@@ -18,6 +18,8 @@
 #
 #	Makefile for malloc routines
 #
+include ../option-groups.mak
+
 subdir	:= malloc
 
 include ../Makeconfig
@@ -36,9 +38,15 @@ install-lib := libmcheck.a
 non-lib.a := libmcheck.a
 
 # Additional library.
+ifeq ($(OPTION_EGLIBC_MEMUSAGE),y)
 extra-libs = libmemusage
 extra-libs-others = $(extra-libs)
 
+ifdef OPTION_EGLIBC_MEMUSAGE_DEFAULT_BUFFER_SIZE
+CPPFLAGS-memusage += -D__OPTION_EGLIBC_MEMUSAGE_DEFAULT_BUFFER_SIZE=$(OPTION_EGLIBC_MEMUSAGE_DEFAULT_BUFFER_SIZE)
+endif
+endif
+
 libmemusage-routines = memusage
 libmemusage-inhibit-o = $(filter-out .os,$(object-suffixes))
 
@@ -65,7 +73,7 @@ endif
 # Unless we get a test for the availability of libgd which also works
 # for cross-compiling we disable the memusagestat generation in this
 # situation.
-ifneq ($(cross-compiling),yes)
+ifeq ($(cross-compiling)$(OPTION_EGLIBC_MEMUSAGE),noy)
 # If the gd library is available we build the `memusagestat' program.
 ifneq ($(LIBGD),no)
 others: $(objpfx)memusage
Index: git/malloc/memusage.c
===================================================================
--- git.orig/malloc/memusage.c
+++ git/malloc/memusage.c
@@ -33,6 +33,7 @@
 #include <stdint.h>
 #include <sys/mman.h>
 #include <sys/time.h>
+#include <gnu/option-groups.h>
 
 #include <memusage.h>
 
@@ -93,7 +94,11 @@ static __thread uintptr_t start_sp;
 #define peak_stack      peak_use[1]
 #define peak_total      peak_use[2]
 
-#define DEFAULT_BUFFER_SIZE     32768
+#ifndef __OPTION_EGLIBC_MEMUSAGE_DEFAULT_BUFFER_SIZE
+# define DEFAULT_BUFFER_SIZE	32768
+#else
+# define DEFAULT_BUFFER_SIZE	__OPTION_EGLIBC_MEMUSAGE_DEFAULT_BUFFER_SIZE
+#endif
 static size_t buffer_size;
 
 static int fd = -1;
Index: git/malloc/memusage.sh
===================================================================
--- git.orig/malloc/memusage.sh
+++ git/malloc/memusage.sh
@@ -35,7 +35,7 @@ do_missing_arg() {
 
 # Print help message
 do_help() {
-  echo $"Usage: memusage [OPTION]... PROGRAM [PROGRAMOPTION]...
+  printf $"Usage: memusage [OPTION]... PROGRAM [PROGRAMOPTION]...
 Profile memory usage of PROGRAM.
 
    -n,--progname=NAME     Name of the program file to profile
Index: git/math/Makefile
===================================================================
--- git.orig/math/Makefile
+++ git/math/Makefile
@@ -21,6 +21,8 @@ subdir		:= math
 
 include ../Makeconfig
 
+include ../option-groups.mak
+
 # Installed header files.
 headers		:= math.h bits/mathcalls.h bits/mathinline.h bits/huge_val.h \
 		   bits/huge_valf.h bits/huge_vall.h bits/inf.h bits/nan.h \
@@ -33,8 +35,8 @@ aux		:= setfpucw fpu_control
 
 # Build the -lm library.
 
-extra-libs	:= libm
-extra-libs-others = $(extra-libs)
+extra-libs-$(OPTION_EGLIBC_LIBM) := libm
+extra-libs-others-$(OPTION_EGLIBC_LIBM) = $(extra-libs-$(OPTION_EGLIBC_LIBM))
 
 libm-support = s_lib_version s_matherr s_signgam			\
 	       fclrexcpt fgetexcptflg fraiseexcpt fsetexcptflg		\
Index: git/misc/err.c
===================================================================
--- git.orig/misc/err.c
+++ git/misc/err.c
@@ -22,6 +22,7 @@
 #include <errno.h>
 #include <string.h>
 #include <stdio.h>
+#include <gnu/option-groups.h>
 
 #include <wchar.h>
 #define flockfile(s) _IO_flockfile (s)
@@ -37,6 +38,7 @@ extern char *__progname;
   va_end (ap);								      \
 }
 
+#if __OPTION_POSIX_WIDE_CHAR_DEVICE_IO
 static void
 convert_and_print (const char *format, __gnuc_va_list ap)
 {
@@ -81,6 +83,7 @@ convert_and_print (const char *format, _
 
   __vfwprintf (stderr, wformat, ap);
 }
+#endif
 
 void
 vwarnx (const char *format, __gnuc_va_list ap)
@@ -88,9 +91,13 @@ vwarnx (const char *format, __gnuc_va_li
   flockfile (stderr);
   if (_IO_fwide (stderr, 0) > 0)
     {
+#if __OPTION_POSIX_WIDE_CHAR_DEVICE_IO
       __fwprintf (stderr, L"%s: ", __progname);
       convert_and_print (format, ap);
       putwc_unlocked (L'\n', stderr);
+#else
+      abort ();
+#endif
     }
   else
     {
@@ -111,6 +118,7 @@ vwarn (const char *format, __gnuc_va_lis
   flockfile (stderr);
   if (_IO_fwide (stderr, 0) > 0)
     {
+#if __OPTION_POSIX_WIDE_CHAR_DEVICE_IO
       __fwprintf (stderr, L"%s: ", __progname);
       if (format)
 	{
@@ -119,6 +127,9 @@ vwarn (const char *format, __gnuc_va_lis
 	}
       __set_errno (error);
       __fwprintf (stderr, L"%m\n");
+#else
+      abort ();
+#endif
     }
   else
     {
Index: git/misc/error.c
===================================================================
--- git.orig/misc/error.c
+++ git/misc/error.c
@@ -35,6 +35,7 @@
 #endif
 
 #ifdef _LIBC
+# include <gnu/option-groups.h>
 # include <libintl.h>
 # include <stdbool.h>
 # include <stdint.h>
@@ -205,6 +206,7 @@ error_tail (int status, int errnum, cons
 #if _LIBC
   if (_IO_fwide (stderr, 0) > 0)
     {
+#if __OPTION_POSIX_WIDE_CHAR_DEVICE_IO
       size_t len = strlen (message) + 1;
       wchar_t *wmessage = NULL;
       mbstate_t st;
@@ -265,6 +267,9 @@ error_tail (int status, int errnum, cons
 
       if (use_malloc)
 	free (wmessage);
+#else
+      abort ();
+#endif
     }
   else
 #endif
Index: git/misc/Makefile
===================================================================
--- git.orig/misc/Makefile
+++ git/misc/Makefile
@@ -19,6 +19,10 @@
 #	Sub-makefile for misc portion of the library.
 #
 
+# Some system-dependent implementations of these functions use option
+# groups (see sysdeps/unix/sysv/linux/Makefile, for example).
+include ../option-groups.mak
+
 subdir	:= misc
 
 include ../Makeconfig
@@ -46,40 +50,47 @@ routines := brk sbrk sstk ioctl \
 	    select pselect \
 	    acct chroot fsync sync fdatasync syncfs reboot \
 	    gethostid sethostid \
-	    revoke vhangup \
+	    vhangup \
 	    swapon swapoff mktemp mkstemp mkstemp64 mkdtemp \
 	    mkostemp mkostemp64 mkstemps mkstemps64 mkostemps mkostemps64 \
 	    ualarm usleep \
 	    gtty stty \
 	    ptrace \
-	    fstab mntent mntent_r \
+	    mntent mntent_r \
 	    utimes lutimes futimes futimesat \
 	    truncate ftruncate truncate64 ftruncate64 \
-	    chflags fchflags \
 	    insremque getttyent getusershell getpass ttyslot \
 	    syslog syscall daemon \
 	    mmap mmap64 munmap mprotect msync madvise mincore remap_file_pages\
 	    mlock munlock mlockall munlockall \
-	    efgcvt efgcvt_r qefgcvt qefgcvt_r \
 	    hsearch hsearch_r tsearch lsearch \
 	    err error ustat \
-	    getsysstats dirname regexp \
+	    getsysstats dirname \
 	    getloadavg getclktck \
 	    fgetxattr flistxattr fremovexattr fsetxattr getxattr \
 	    listxattr lgetxattr llistxattr lremovexattr lsetxattr \
 	    removexattr setxattr getauxval ifunc-impl-list
 
+routines-$(OPTION_POSIX_REGEXP) += regexp
+routines-$(OPTION_EGLIBC_FSTAB) += fstab
+routines-$(OPTION_EGLIBC_BSD) += chflags fchflags revoke
+routines-$(OPTION_EGLIBC_FCVT) += efgcvt efgcvt_r qefgcvt qefgcvt_r
+
 generated += tst-error1.mtrace tst-error1-mem.out
 
 aux := init-misc
 install-lib := libg.a
 gpl2lgpl := error.c error.h
 
-tests := tst-dirname tst-tsearch tst-fdset tst-efgcvt tst-mntent tst-hsearch \
-	 tst-error1 tst-pselect tst-insremque tst-mntent2 bug-hsearch1
+tests := tst-dirname tst-tsearch tst-fdset tst-mntent tst-hsearch \
+	 tst-pselect tst-insremque tst-mntent2 bug-hsearch1
+tests-$(OPTION_POSIX_WIDE_CHAR_DEVICE_IO) += tst-error1
+tests-$(OPTION_EGLIBC_FCVT) += tst-efgcvt
 ifeq ($(run-built-tests),yes)
+ifeq (y,$(OPTION_POSIX_WIDE_CHAR_DEVICE_IO))
 tests-special += $(objpfx)tst-error1-mem.out
 endif
+endif
 
 CFLAGS-select.c = -fexceptions -fasynchronous-unwind-tables
 CFLAGS-tsearch.c = $(uses-callbacks)
Index: git/misc/tst-efgcvt.c
===================================================================
--- git.orig/misc/tst-efgcvt.c
+++ git/misc/tst-efgcvt.c
@@ -59,7 +59,7 @@ static testcase ecvt_tests[] =
   { 123.01, -4, 3, "" },
   { 126.71, -4, 3, "" },
   { 0.0, 4, 1, "0000" },
-#if DBL_MANT_DIG == 53
+#if DBL_MANT_DIG == 53 && !(defined __powerpc__ && defined __NO_FPRS__ && !defined _SOFT_FLOAT && !defined _SOFT_DOUBLE)
   { 0x1p-1074, 3, -323, "494" },
   { -0x1p-1074, 3, -323, "494" },
 #endif
Index: git/nis/Makefile
===================================================================
--- git.orig/nis/Makefile
+++ git/nis/Makefile
@@ -18,6 +18,8 @@
 #
 #	Makefile for NIS/NIS+ part.
 #
+include ../option-groups.mak
+
 subdir	:= nis
 
 include ../Makeconfig
@@ -30,19 +32,26 @@ endif
 
 # These are the databases available for the nis (and perhaps later nisplus)
 # service.  This must be a superset of the services in nss.
-databases		= proto service hosts network grp pwd rpc ethers \
-			  spwd netgrp alias publickey
+databases-y		:= proto service hosts network grp pwd rpc ethers \
+			   spwd netgrp publickey
+databases-$(OPTION_EGLIBC_DB_ALIASES) += alias
 
 # Specify rules for the nss_* modules.
-services		:= nis nisplus compat
+# The 'compat' module includes nis support, and the 'nss' directory
+# includes a bare-bones "files" library, so we'll include 'compat' in
+# OPTION_EGLIBC_NIS.
+services-y		:=
+services-$(OPTION_EGLIBC_NIS) += nis nisplus compat
+
+extra-libs-$(OPTION_EGLIBC_NIS) += libnsl
+extra-libs-y		+= $(services-y:%=libnss_%)
 
-extra-libs		= libnsl $(services:%=libnss_%)
 # These libraries will be built in the `others' pass rather than
 # the `lib' pass, because they depend on libc.so being built already.
-extra-libs-others	= $(extra-libs)
+extra-libs-others-y	+= $(extra-libs-y)
 
 # The sources are found in the appropriate subdir.
-subdir-dirs = $(services:%=nss_%)
+subdir-dirs = $(services-y:%=nss_%)
 vpath %.c $(subdir-dirs)
 
 libnsl-routines = yp_xdr ypclnt ypupdate_xdr \
@@ -60,11 +69,11 @@ libnsl-routines = yp_xdr ypclnt ypupdate
 libnss_compat-routines	:= $(addprefix compat-,grp pwd spwd initgroups)
 libnss_compat-inhibit-o	= $(filter-out .os,$(object-suffixes))
 
-libnss_nis-routines	:= $(addprefix nis-,$(databases)) nis-initgroups \
+libnss_nis-routines	:= $(addprefix nis-,$(databases-y)) nis-initgroups \
 			   nss-nis
 libnss_nis-inhibit-o	= $(filter-out .os,$(object-suffixes))
 
-libnss_nisplus-routines	:= $(addprefix nisplus-,$(databases)) nisplus-parser \
+libnss_nisplus-routines	:= $(addprefix nisplus-,$(databases-y)) nisplus-parser \
 			   nss-nisplus nisplus-initgroups
 libnss_nisplus-inhibit-o = $(filter-out .os,$(object-suffixes))
 
@@ -80,12 +89,12 @@ libnsl-libc = $(common-objpfx)linkobj/li
 # Target-specific variable setting to link objects using deprecated
 # RPC interfaces with the version of libc.so that makes them available
 # for new links:
-$(services:%=$(objpfx)libnss_%.so) $(objpfx)libnsl.so: \
+$(services-y:%=$(objpfx)libnss_%.so) $(objpfx)libnsl.so: \
   libc-for-link = $(libnsl-libc)
 
 
 ifeq ($(build-shared),yes)
-$(others:%=$(objpfx)%): $(objpfx)libnsl.so$(libnsl.so-version)
+$(others-y:%=$(objpfx)%): $(objpfx)libnsl.so$(libnsl.so-version)
 else
-$(others:%=$(objpfx)%): $(objpfx)libnsl.a
+$(others-y:%=$(objpfx)%): $(objpfx)libnsl.a
 endif
Index: git/nptl/Makefile
===================================================================
--- git.orig/nptl/Makefile
+++ git/nptl/Makefile
@@ -18,6 +18,8 @@
 #
 #	Sub-makefile for NPTL portion of the library.
 #
+include ../option-groups.mak
+
 subdir	:= nptl
 
 include ../Makeconfig
@@ -117,7 +119,7 @@ libpthread-routines = nptl-init vars eve
 		      pt-raise pt-system \
 		      flockfile ftrylockfile funlockfile \
 		      sigaction \
-		      herrno res pt-allocrtsig \
+		      pt-allocrtsig \
 		      pthread_kill_other_threads \
 		      pthread_getaffinity pthread_setaffinity \
 		      pthread_attr_getaffinity pthread_attr_setaffinity \
@@ -137,6 +139,8 @@ libpthread-routines = nptl-init vars eve
 #		      pthread_setgid pthread_setegid pthread_setregid \
 #		      pthread_setresgid
 
+libpthread-routines-$(OPTION_EGLIBC_INET) := herrno res
+
 libpthread-shared-only-routines = version pt-allocrtsig unwind-forcedunwind
 libpthread-static-only-routines = pthread_atfork
 
@@ -211,7 +215,7 @@ tests = tst-typesizes \
 	tst-mutexpi1 tst-mutexpi2 tst-mutexpi3 tst-mutexpi4 tst-mutexpi5 \
 	tst-mutexpi5a tst-mutexpi6 tst-mutexpi7 tst-mutexpi7a tst-mutexpi8 \
 	tst-mutexpi9 \
-	tst-spin1 tst-spin2 tst-spin3 tst-spin4 \
+	tst-spin1 tst-spin2 tst-spin3 \
 	tst-cond1 tst-cond2 tst-cond3 tst-cond4 tst-cond5 tst-cond6 tst-cond7 \
 	tst-cond8 tst-cond9 tst-cond10 tst-cond11 tst-cond12 tst-cond13 \
 	tst-cond14 tst-cond15 tst-cond16 tst-cond17 tst-cond18 tst-cond19 \
@@ -245,14 +249,14 @@ tests = tst-typesizes \
 	tst-cancel6 tst-cancel7 tst-cancel8 tst-cancel9 tst-cancel10 \
 	tst-cancel11 tst-cancel12 tst-cancel13 tst-cancel14 tst-cancel15 \
 	tst-cancel16 tst-cancel17 tst-cancel18 tst-cancel19 tst-cancel20 \
-	tst-cancel21 tst-cancel22 tst-cancel23 tst-cancel24 tst-cancel25 \
+	tst-cancel21 tst-cancel22 tst-cancel23 tst-cancel25 \
 	tst-cancel-self tst-cancel-self-cancelstate \
 	tst-cancel-self-canceltype tst-cancel-self-testcancel \
 	tst-cleanup0 tst-cleanup1 tst-cleanup2 tst-cleanup3 tst-cleanup4 \
 	tst-flock1 tst-flock2 \
 	tst-signal1 tst-signal2 tst-signal3 tst-signal4 tst-signal5 \
 	tst-signal6 tst-signal7 \
-	tst-exec1 tst-exec2 tst-exec3 tst-exec4 \
+	tst-exec2 tst-exec3 tst-exec4 \
 	tst-exit1 tst-exit2 tst-exit3 \
 	tst-stdio1 tst-stdio2 \
 	tst-stack1 tst-stack2 tst-stack3 tst-stack4 tst-pthread-getattr \
@@ -260,13 +264,12 @@ tests = tst-typesizes \
 	tst-unload \
 	tst-dlsym1 \
 	tst-sysconf \
-	tst-locale1 tst-locale2 \
+	tst-locale2 \
 	tst-umask1 \
 	tst-popen1 \
 	tst-clock1 \
 	tst-context1 \
 	tst-sched1 \
-	tst-backtrace1 \
 	tst-abstime \
 	tst-vfork1 tst-vfork2 tst-vfork1x tst-vfork2x \
 	tst-getpid1 tst-getpid2 tst-getpid3 \
@@ -277,6 +280,17 @@ xtests = tst-setuid1 tst-setuid1-static
 	tst-mutexpp1 tst-mutexpp6 tst-mutexpp10
 test-srcs = tst-oddstacklimit
 
+# This test uses the posix_spawn functions.
+tests-$(OPTION_EGLIBC_SPAWN) += tst-exec1
+
+# This test uses the 'backtrace' functions.
+tests-$(OPTION_EGLIBC_BACKTRACE) += tst-backtrace1
+
+# This test is written in C++.
+tests-$(OPTION_EGLIBC_CXX_TESTS) += tst-cancel24
+
+tests-$(OPTION_EGLIBC_LOCALE_CODE) += tst-locale1
+
 # Files which must not be linked with libpthread.
 tests-nolibpthread = tst-unload
 
Index: git/nptl/pthread_create.c
===================================================================
--- git.orig/nptl/pthread_create.c
+++ git/nptl/pthread_create.c
@@ -32,6 +32,7 @@
 #include <exit-thread.h>
 #include <default-sched.h>
 
+#include <gnu/option-groups.h>
 #include <shlib-compat.h>
 
 #include <stap-probe.h>
@@ -261,8 +262,10 @@ START_THREAD_DEFN
   THREAD_SETMEM (pd, cpuclock_offset, now);
 #endif
 
+#if __OPTION_EGLIBC_INET
   /* Initialize resolver state pointer.  */
   __resp = &pd->res;
+#endif
 
   /* Initialize pointers to locale data.  */
   __ctype_init ();
@@ -345,8 +348,10 @@ START_THREAD_DEFN
   /* Run the destructor for the thread-local data.  */
   __nptl_deallocate_tsd ();
 
+#if __OPTION_EGLIBC_INET
   /* Clean up any state libc stored in thread-local variables.  */
   __libc_thread_freeres ();
+#endif
 
   /* If this is the last thread we terminate the process now.  We
      do not notify the debugger, it might just irritate it if there
Index: git/nscd/Makefile
===================================================================
--- git.orig/nscd/Makefile
+++ git/nscd/Makefile
@@ -18,14 +18,17 @@
 #
 #	Sub-makefile for nscd portion of the library.
 #
+include ../option-groups.mak
+
 subdir	:= nscd
 
 include ../Makeconfig
 
 ifneq ($(use-nscd),no)
-routines := nscd_getpw_r nscd_getgr_r nscd_gethst_r nscd_getai \
+routines-$(OPTION_EGLIBC_INET) += \
+	     nscd_getpw_r nscd_getgr_r nscd_gethst_r nscd_getai \
 	    nscd_initgroups nscd_getserv_r nscd_netgroup
-aux	:= nscd_helper
+aux-$(OPTION_EGLIBC_INET) += nscd_helper
 endif
 
 # To find xmalloc.c
@@ -37,14 +40,18 @@ nscd-modules := nscd connections pwdcach
 		dbg_log nscd_conf nscd_stat cache mem nscd_setup_thread \
 		xmalloc xstrdup aicache initgrcache gai res_hconf \
 		netgroupcache
-
+ifneq (y,$(OPTION_EGLIBC_NIS))
+# If we haven't build libnsl.so, then we'll need to include our
+# own copy of nis_hash.
+nscd-modules += nis_hash
+endif
 ifeq ($(build-nscd)$(have-thread-library),yesyes)
 
-others += nscd
-others-pie += nscd
-install-sbin := nscd
+others-$(OPTION_EGLIBC_INET) += nscd
+others-pie-$(OPTION_EGLIBC_INET) += nscd
+install-sbin-$(OPTION_EGLIBC_INET) += nscd
 
-extra-objs = $(nscd-modules:=.o)
+extra-objs-$(OPTION_EGLIBC_INET) += $(nscd-modules:=.o)
 
 endif
 
@@ -100,7 +107,15 @@ include $(patsubst %,$(..)cppflags-itera
 $(objpfx)nscd: $(nscd-modules:%=$(objpfx)%.o)
 
 ifeq ($(build-shared),yes)
-$(objpfx)nscd: $(shared-thread-library) $(common-objpfx)nis/libnsl.so
+$(objpfx)nscd: $(shared-thread-library)
+else
+$(objpfx)nscd: $(static-thread-library)
+endif
+
+ifeq (y,$(OPTION_EGLIBC_NIS))
+ifeq ($(build-shared),yes)
+$(objpfx)nscd: $(common-objpfx)nis/libnsl.so
 else
-$(objpfx)nscd: $(static-thread-library) $(common-objpfx)nis/libnsl.a
+$(objpfx)nscd: $(common-objpfx)nis/libnsl.a
+endif
 endif
Index: git/nscd/nis_hash.c
===================================================================
--- /dev/null
+++ git/nscd/nis_hash.c
@@ -0,0 +1,3 @@
+/* If OPTION_EGLIBC_NIS is disabled, nscd can't get this from libnsl.so;
+   we need our own copy.  */
+#include "../nis/nis_hash.c"
Index: git/nss/fixed-nsswitch.conf
===================================================================
--- /dev/null
+++ git/nss/fixed-nsswitch.conf
@@ -0,0 +1,22 @@
+# /etc/nsswitch.conf
+#
+# Example configuration for fixed name service.
+# See the description of OPTION_EGLIBC_NSSWITCH in option-groups.def
+# for details.
+#
+
+aliases:        files
+
+passwd:         files
+group:          files
+shadow:         files
+
+hosts:          files dns
+networks:       files dns
+
+protocols:      files
+services:       files
+ethers:         files
+rpc:            files
+
+netgroup:       files
Index: git/nss/fixed-nsswitch.functions
===================================================================
--- /dev/null
+++ git/nss/fixed-nsswitch.functions
@@ -0,0 +1,121 @@
+/* List of functions defined for fixed NSS in GNU C Library.
+   Copyright (C) 1996, 1997, 1998, 2005 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 2.1 of the License, or (at your option) any later version.
+
+   The GNU C Library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with the GNU C Library; if not, write to the Free
+   Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+   02111-1307 USA.  */
+
+/* When OPTION_EGLIBC_NSSWITCH is disabled (see option-groups.def),
+   EGLIBC does not use the 'dlopen' and 'dlsym' functions to look for
+   database query functions in the individual name service libraries.
+   Instead, it uses a set of functions chosen at compile time, as
+   directed by the OPTION_EGLIBC_NSSWITCH_FIXED_FUNCTIONS file.  This
+   file is a sample of what you might use there.
+
+   This file is C source code; it should only contain invocations of
+   the following macros:
+
+   - DEFINE_ENT (DATABASE, SERVICE, X)
+
+     Declare the 'setXent', 'getXent_r', and 'endXent' functions that
+     query DATABASE using the service library 'libnss_SERVICE.so.2'.
+     DATABASE should be the full name of the database as it appears in
+     'nsswitch.conf', like 'passwd' or 'aliases'.
+
+     (The non-reentrant 'getXent' functions are implemented in terms
+     of the reentrant 'getXent_r' functions, so there is no need to
+     refer to them explicitly here.)
+
+   - DEFINE_GETBY (DATABASE, SERVICE, X, KEY)
+
+     Declare the 'getXbyKEY_r' functions that query DATABASE using
+     SERVICE.  DATABASE and SERVICE are as described above.
+
+     (The non-reentrant 'getXbyKEY' functions are implemented in terms
+     of the reentrant 'getXbyKEY_r' functions, so there is no need to
+     refer to them explicitly here.)
+
+     Use the special key 'name3' for the service library function that
+     implements the 'getaddrinfo' function.
+
+   - DEFINE_GET (DATABASE, SERVICE, QUERY)
+
+     Declare the 'getQUERY_r' functions that query DATABASE using
+     SERVICE.  This is used for functions like 'getpwnam'.
+
+     (The non-reentrant 'getQUERY' functions are implemented in terms
+     of the reentrant 'getQUERY_r' functions, so there is no need to
+     refer to them explicitly here.)
+
+   This sample file only includes functions that consult the files in
+   '/etc', and the Domain Name System (DNS).  */
+
+/* aliases */
+DEFINE_ENT (aliases, files, alias)
+DEFINE_GETBY (aliases, files, alias, name)
+
+/* ethers */
+DEFINE_ENT (ethers, files, ether)
+
+/* group */
+DEFINE_ENT (group, files, gr)
+DEFINE_GET (group, files, grgid)
+DEFINE_GET (group, files, grnam)
+
+/* hosts */
+DEFINE_ENT (hosts, files, host)
+DEFINE_GETBY (hosts, files, host, addr)
+DEFINE_GETBY (hosts, files, host, name)
+DEFINE_GETBY (hosts, files, host, name2)
+DEFINE_GET (hosts, files, hostton)
+DEFINE_GET (hosts, files, ntohost)
+DEFINE_GETBY (hosts, dns, host, addr)
+DEFINE_GETBY (hosts, dns, host, name)
+DEFINE_GETBY (hosts, dns, host, name2)
+DEFINE_GETBY (hosts, dns, host, name3)
+
+/* netgroup */
+DEFINE_ENT (netgroup, files, netgr)
+
+/* networks */
+DEFINE_ENT (networks, files, net)
+DEFINE_GETBY (networks, files, net, name)
+DEFINE_GETBY (networks, files, net, addr)
+DEFINE_GETBY (networks, dns, net, name)
+DEFINE_GETBY (networks, dns, net, addr)
+
+/* protocols */
+DEFINE_ENT (protocols, files, proto)
+DEFINE_GETBY (protocols, files, proto, name)
+DEFINE_GETBY (protocols, files, proto, number)
+
+/* passwd */
+DEFINE_ENT (passwd, files, pw)
+DEFINE_GET (passwd, files, pwnam)
+DEFINE_GET (passwd, files, pwuid)
+
+/* rpc */
+DEFINE_ENT (rpc, files, rpc)
+DEFINE_GETBY (rpc, files, rpc, name)
+DEFINE_GETBY (rpc, files, rpc, number)
+
+/* services */
+DEFINE_ENT (services, files, serv)
+DEFINE_GETBY (services, files, serv, name)
+DEFINE_GETBY (services, files, serv, port)
+
+/* shadow */
+DEFINE_ENT (shadow, files, sp)
+DEFINE_GET (shadow, files, spnam)
Index: git/nss/gen-fixed-nsswitch.c
===================================================================
--- /dev/null
+++ git/nss/gen-fixed-nsswitch.c
@@ -0,0 +1,803 @@
+/* gen-fixed-nsswitch.c --- generate fixed name service data structures
+   Copyright (C) 1996-1999, 2001-2006, 2007 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 2.1 of the License, or (at your option) any later version.
+
+   The GNU C Library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with the GNU C Library; if not, write to the Free
+   Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+   02111-1307 USA.  */
+
+#define _GNU_SOURCE
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <errno.h>
+#include <string.h>
+#include <stdarg.h>
+#include <assert.h>
+#include <ctype.h>
+
+#include "gnu/lib-names.h"
+#include "nss.h"
+
+/* Provide a fallback definition to allow this file to be compiled outside
+   libc.  */
+#ifndef internal_function
+# define internal_function
+#endif
+
+
+/* Simple utilities.  */
+
+void __attribute__ ((noreturn))
+error (const char *message)
+{
+  fprintf (stderr, "%s\n", message);
+  exit (1);
+}
+
+
+void *
+check_alloc (void *p)
+{
+  if (p)
+    return p;
+  else
+    error ("out of memory");
+}
+
+void *
+xmalloc (size_t size)
+{
+  return check_alloc (malloc (size));
+}
+
+
+/* Format ARGS according to FORMAT, and return the result as a
+   malloc'ed string.  */
+char *
+saprintf (const char *format, ...)
+{
+  va_list args;
+  size_t len;
+  char *buf;
+
+  va_start (args, format);
+  len = vsnprintf (NULL, 0, format, args);
+  va_end (args);
+
+  buf = xmalloc (len + 1);
+  va_start (args, format);
+  assert (len == vsnprintf (buf, len + 1, format, args));
+  va_end (args);
+
+  return buf;
+}
+
+
+
+/* Data structures representing the configuration file in memory.  */
+
+/* These are copied from nsswitch.h.
+
+   We could simply #include that file, but this program runs on the
+   build machine and links against the build machine's libraries,
+   whereas that header is meant for use by target code; it uses
+   'libc_hidden_proto', 'internal_function', and related hair.  Since
+   we've copied the parsing code, we might as well copy the data
+   structure definitions as well.  */
+
+/* Actions performed after lookup finished.  */
+typedef enum
+{
+  NSS_ACTION_CONTINUE,
+  NSS_ACTION_RETURN
+} lookup_actions;
+
+
+typedef struct service_library
+{
+  /* Name of service (`files', `dns', `nis', ...).  */
+  const char *name;
+  /* Pointer to the loaded shared library.  */
+  void *lib_handle;
+  /* And the link to the next entry.  */
+  struct service_library *next;
+} service_library;
+
+
+/* For mapping a function name to a function pointer.  It is known in
+   nsswitch.c:nss_lookup_function that a string pointer for the lookup key
+   is the first member.  */
+typedef struct
+{
+  const char *fct_name;
+  void *fct_ptr;
+} known_function;
+
+
+typedef struct service_user
+{
+  /* And the link to the next entry.  */
+  struct service_user *next;
+  /* Action according to result.  */
+  lookup_actions actions[5];
+  /* Link to the underlying library object.  */
+  service_library *library;
+  /* Collection of known functions.
+
+     With OPTION_EGLIBC_NSSWITCH enabled, this is the root of a
+     'tsearch'-style tree.
+
+     With OPTION_EGLIBC_NSSWITCH disabled, this is an array of
+     pointers to known_function structures, NULL-terminated.  */
+  union
+  {
+    void *tree;
+    const known_function **array;
+  } known;
+  /* Name of the service (`files', `dns', `nis', ...).  */
+  const char *name;
+} service_user;
+
+/* To access the action based on the status value use this macro.  */
+#define nss_next_action(ni, status) ((ni)->actions[2 + status])
+
+
+typedef struct name_database_entry
+{
+  /* And the link to the next entry.  */
+  struct name_database_entry *next;
+  /* List of service to be used.  */
+  service_user *service;
+  /* Name of the database.  */
+  const char *name;
+} name_database_entry;
+
+
+typedef struct name_database
+{
+  /* List of all known databases.  */
+  name_database_entry *entry;
+  /* List of libraries with service implementation.  */
+  service_library *library;
+} name_database;
+
+
+
+/* Gathering the contents of the FIXED_FUNCTIONS file.  */
+
+/* It should be possible to generate this list automatically by
+   looking at the services and databases used in the nsswitch.conf
+   file, and having a hard-coded set of queries supported on each
+   database.  */
+
+/* We #include the FIXED_FUNCTIONS file several times to build an
+   array of function structures holding its data.  */
+enum function_kind {
+  fk_end = 0,                   /* Last entry.  */
+  fk_setent,                    /* Like setpwent.  */
+  fk_getent,                    /* Like getpwent.  */
+  fk_endent,                    /* Like endpwent.  */
+  fk_getby,                     /* Like gethostbyname.  */
+  fk_get                        /* Like getpwnam.  */
+};
+
+
+struct function {
+  /* What kind of function this is.  */
+  enum function_kind kind;
+
+  /* The database and service of the function being hardwired in.  */
+  char *database, *service;
+
+  /* The kind of entry being queried, for 'fk_setent', 'fk_getent',
+     'fk_endent', and 'fk_getby' functions.  */
+  char *entry;
+
+  /* The key, for 'fk_getby' entries.  */
+  char *key;
+
+  /* The value and key, for 'fk_get' entries.  */
+  char *value_and_key;
+};
+
+
+const struct function functions[] =
+  {
+
+#define DEFINE_ENT(database, service, entry)    \
+    { fk_setent, #database, #service, #entry }, \
+    { fk_getent, #database, #service, #entry }, \
+    { fk_endent, #database, #service, #entry },
+#define DEFINE_GETBY(database, service, entry, key)   \
+    { fk_getby, #database, #service, #entry, #key },
+#define DEFINE_GET(database, service, value_and_key)     \
+    { fk_get, #database, #service, NULL, NULL, #value_and_key },
+
+#include FIXED_FUNCTIONS
+
+#undef DEFINE_ENT
+#undef DEFINE_GETBY
+#undef DEFINE_GET
+
+    { fk_end }
+  };
+
+
+/* Parsing the config file.  Functions copied from nsswitch.c.  */
+
+#define __strchrnul strchrnul
+#define __getline getline
+#define __strncasecmp strncasecmp
+
+/* Prototypes for the local functions.  */
+static name_database *nss_parse_file (const char *fname) internal_function;
+static name_database_entry *nss_getline (char *line) internal_function;
+static service_user *nss_parse_service_list (const char *line)
+     internal_function;
+
+static name_database *
+internal_function
+nss_parse_file (const char *fname)
+{
+  FILE *fp;
+  name_database *result;
+  name_database_entry *last;
+  char *line;
+  size_t len;
+
+  /* Open the configuration file.  */
+  fp = fopen (fname, "rc");
+  if (fp == NULL)
+    return NULL;
+
+  // /* No threads use this stream.  */
+  // __fsetlocking (fp, FSETLOCKING_BYCALLER);
+
+  result = (name_database *) xmalloc (sizeof (name_database));
+
+  result->entry = NULL;
+  result->library = NULL;
+  last = NULL;
+  line = NULL;
+  len = 0;
+  do
+    {
+      name_database_entry *this;
+      ssize_t n;
+
+      n = __getline (&line, &len, fp);
+      if (n < 0)
+	break;
+      if (line[n - 1] == '\n')
+	line[n - 1] = '\0';
+
+      /* Because the file format does not know any form of quoting we
+	 can search forward for the next '#' character and if found
+	 make it terminating the line.  */
+      *__strchrnul (line, '#') = '\0';
+
+      /* If the line is blank it is ignored.  */
+      if (line[0] == '\0')
+	continue;
+
+      /* Each line completely specifies the actions for a database.  */
+      this = nss_getline (line);
+      if (this != NULL)
+	{
+	  if (last != NULL)
+	    last->next = this;
+	  else
+	    result->entry = this;
+
+	  last = this;
+	}
+    }
+  while (!feof_unlocked (fp));
+
+  /* Free the buffer.  */
+  free (line);
+  /* Close configuration file.  */
+  fclose (fp);
+
+  return result;
+}
+
+
+/* Read the source names:
+	`( <source> ( "[" "!"? (<status> "=" <action> )+ "]" )? )*'
+   */
+static service_user *
+internal_function
+nss_parse_service_list (const char *line)
+{
+  service_user *result = NULL, **nextp = &result;
+
+  while (1)
+    {
+      service_user *new_service;
+      const char *name;
+
+      while (isspace (line[0]))
+	++line;
+      if (line[0] == '\0')
+	/* No source specified.  */
+	return result;
+
+      /* Read <source> identifier.  */
+      name = line;
+      while (line[0] != '\0' && !isspace (line[0]) && line[0] != '[')
+	++line;
+      if (name == line)
+	return result;
+
+
+      new_service = (service_user *) xmalloc (sizeof (*new_service));
+      new_service->name = (char *) xmalloc (line - name + 1);
+
+      *((char *) __mempcpy ((char *) new_service->name, name, line - name))
+        = '\0';
+
+      /* Set default actions.  */
+      new_service->actions[2 + NSS_STATUS_TRYAGAIN] = NSS_ACTION_CONTINUE;
+      new_service->actions[2 + NSS_STATUS_UNAVAIL] = NSS_ACTION_CONTINUE;
+      new_service->actions[2 + NSS_STATUS_NOTFOUND] = NSS_ACTION_CONTINUE;
+      new_service->actions[2 + NSS_STATUS_SUCCESS] = NSS_ACTION_RETURN;
+      new_service->actions[2 + NSS_STATUS_RETURN] = NSS_ACTION_RETURN;
+      new_service->library = NULL;
+      new_service->known.tree = NULL;
+      new_service->next = NULL;
+
+      while (isspace (line[0]))
+	++line;
+
+      if (line[0] == '[')
+	{
+	  /* Read criterions.  */
+	  do
+	    ++line;
+	  while (line[0] != '\0' && isspace (line[0]));
+
+	  do
+	    {
+	      int not;
+	      enum nss_status status;
+	      lookup_actions action;
+
+	      /* Grok ! before name to mean all statii but that one.  */
+	      not = line[0] == '!';
+	      if (not)
+		++line;
+
+	      /* Read status name.  */
+	      name = line;
+	      while (line[0] != '\0' && !isspace (line[0]) && line[0] != '='
+		     && line[0] != ']')
+		++line;
+
+	      /* Compare with known statii.  */
+	      if (line - name == 7)
+		{
+		  if (__strncasecmp (name, "SUCCESS", 7) == 0)
+		    status = NSS_STATUS_SUCCESS;
+		  else if (__strncasecmp (name, "UNAVAIL", 7) == 0)
+		    status = NSS_STATUS_UNAVAIL;
+		  else
+		    return result;
+		}
+	      else if (line - name == 8)
+		{
+		  if (__strncasecmp (name, "NOTFOUND", 8) == 0)
+		    status = NSS_STATUS_NOTFOUND;
+		  else if (__strncasecmp (name, "TRYAGAIN", 8) == 0)
+		    status = NSS_STATUS_TRYAGAIN;
+		  else
+		    return result;
+		}
+	      else
+		return result;
+
+	      while (isspace (line[0]))
+		++line;
+	      if (line[0] != '=')
+		return result;
+	      do
+		++line;
+	      while (isspace (line[0]));
+
+	      name = line;
+	      while (line[0] != '\0' && !isspace (line[0]) && line[0] != '='
+		     && line[0] != ']')
+		++line;
+
+	      if (line - name == 6 && __strncasecmp (name, "RETURN", 6) == 0)
+		action = NSS_ACTION_RETURN;
+	      else if (line - name == 8
+		       && __strncasecmp (name, "CONTINUE", 8) == 0)
+		action = NSS_ACTION_CONTINUE;
+	      else
+		return result;
+
+	      if (not)
+		{
+		  /* Save the current action setting for this status,
+		     set them all to the given action, and reset this one.  */
+		  const lookup_actions save = new_service->actions[2 + status];
+		  new_service->actions[2 + NSS_STATUS_TRYAGAIN] = action;
+		  new_service->actions[2 + NSS_STATUS_UNAVAIL] = action;
+		  new_service->actions[2 + NSS_STATUS_NOTFOUND] = action;
+		  new_service->actions[2 + NSS_STATUS_SUCCESS] = action;
+		  new_service->actions[2 + status] = save;
+		}
+	      else
+		new_service->actions[2 + status] = action;
+
+	      /* Skip white spaces.  */
+	      while (isspace (line[0]))
+		++line;
+	    }
+	  while (line[0] != ']');
+
+	  /* Skip the ']'.  */
+	  ++line;
+	}
+
+      *nextp = new_service;
+      nextp = &new_service->next;
+    }
+}
+
+static name_database_entry *
+internal_function
+nss_getline (char *line)
+{
+  const char *name;
+  name_database_entry *result;
+  size_t len;
+
+  /* Ignore leading white spaces.  ATTENTION: this is different from
+     what is implemented in Solaris.  The Solaris man page says a line
+     beginning with a white space character is ignored.  We regard
+     this as just another misfeature in Solaris.  */
+  while (isspace (line[0]))
+    ++line;
+
+  /* Recognize `<database> ":"'.  */
+  name = line;
+  while (line[0] != '\0' && !isspace (line[0]) && line[0] != ':')
+    ++line;
+  if (line[0] == '\0' || name == line)
+    /* Syntax error.  */
+    return NULL;
+  *line++ = '\0';
+
+  len = strlen (name) + 1;
+
+  result = (name_database_entry *) xmalloc (sizeof (*result));
+  result->name = (char *) xmalloc (len);
+
+  /* Save the database name.  */
+  memcpy ((char *) result->name, name, len);
+
+  /* Parse the list of services.  */
+  result->service = nss_parse_service_list (line);
+
+  result->next = NULL;
+  return result;
+}
+
+
+
+/* Generating code for statically initialized nsswitch structures.  */
+
+
+/* Return the service-neutral suffix of the name of the service
+   library function referred to by the function F.  The result is
+   allocated with malloc.  */
+char *
+known_function_suffix (const struct function *f)
+{
+  switch (f->kind)
+    {
+    case fk_setent:
+      return saprintf ("set%sent", f->entry);
+
+    case fk_getent:
+      return saprintf ("get%sent_r", f->entry);
+
+    case fk_endent:
+      return saprintf ("end%sent", f->entry);
+
+    case fk_getby:
+      return saprintf ("get%sby%s_r", f->entry, f->key);
+
+    case fk_get:
+      return saprintf ("get%s_r", f->value_and_key);
+
+    default:
+      abort ();
+    }
+}
+
+
+/* Return the name of the service library function referred to by the
+   function F.  The result is allocated with malloc.  */
+char *
+known_function_name (const struct function *f)
+{
+  return saprintf ("_nss_%s_%s", f->service, known_function_suffix (f));
+}
+
+
+/* Write initialized known_function structures to OUT for
+   all the functions we'll use.  */
+void
+generate_known_functions (FILE *out)
+{
+  int i;
+
+  /* First, generate weak references to the functions.  The service
+     libraries depend on libc, and if these references weren't weak,
+     we'd be making libc depend circularly on the service
+     libraries.  */
+  for (i = 0; functions[i].kind; i++)
+    {
+      char *name = known_function_name (&functions[i]);
+      fprintf (out, "typeof (%s) %s __attribute__ ((weak));\n",
+               name, name);
+    }
+  fputs ("\n", out);
+
+  /* Then, a table mapping names to functions.  */
+  fputs ("static const known_function fixed_known_functions[] = {\n",
+         out);
+  for (i = 0; functions[i].kind; i++)
+    {
+      const struct function *f = &functions[i];
+      char *suffix = known_function_suffix (f);
+
+      fprintf (out, "  /* %2d */ { \"%s\", _nss_%s_%s },\n",
+               i, suffix, f->service, suffix);
+    }
+  fputs ("};\n", out);
+  fputs ("\n", out);
+}
+
+
+/* Print code to OUT for an initialized array of pointers to the
+   'known_function' structures needed for USER, which is for
+   DATABASE.  Return its name, allocated with malloc.  */
+char *
+generate_known_function_list (FILE *out,
+                              const name_database_entry *database,
+                              const service_user *user)
+{
+  char *list_name = saprintf ("fixed_%s_%s_known_funcs",
+                              database->name, user->name);
+  fprintf (out, "static const known_function *%s[] = {\n",
+           list_name);
+  int i;
+  for (i = 0; functions[i].kind; i++)
+    if (strcmp (functions[i].database, database->name) == 0
+        && strcmp (functions[i].service, user->name) == 0)
+      fprintf (out, "  &fixed_known_functions[%d], /* %s */\n",
+               i, known_function_name (&functions[i]));
+  fputs ("  NULL\n", out);
+  fputs ("};\n", out);
+  fputs ("\n", out);
+
+  return list_name;
+}
+
+
+/* Return the name of the status value STATUS, as a statically
+   allocated string.  */
+const char *
+lookup_status_name (enum nss_status status)
+{
+  switch (status)
+    {
+    case NSS_STATUS_TRYAGAIN: return "NSS_STATUS_TRYAGAIN";
+    case NSS_STATUS_UNAVAIL: return "NSS_STATUS_UNAVAIL";
+    case NSS_STATUS_NOTFOUND: return "NSS_STATUS_NOTFOUND";
+    case NSS_STATUS_SUCCESS: return "NSS_STATUS_SUCCESS";
+    case NSS_STATUS_RETURN: return "NSS_STATUS_RETURN";
+    default: abort ();
+    };
+}
+
+
+/* Return the name of ACTION as a statically allocated string.  */
+const char *
+lookup_action_name (lookup_actions action)
+{
+  switch (action)
+    {
+    case NSS_ACTION_CONTINUE: return "NSS_ACTION_CONTINUE";
+    case NSS_ACTION_RETURN: return "NSS_ACTION_RETURN";
+    default: abort ();
+    }
+}
+
+
+/* Print code to OUT for the list of service_user structures starting
+   with USER, which are all for DATABASE.  Return the name of the
+   first structure in that list, or zero if USER is NULL.  */
+char *
+generate_service_user_list (FILE *out,
+                            name_database_entry *database,
+                            service_user *user)
+{
+  if (user)
+    {
+      /* Generate the tail of the list.  */
+      char *next_name = generate_service_user_list (out, database, user->next);
+      /* Generate our known function list.  */
+      char *known_function_list_name =
+        generate_known_function_list (out, database, user);
+
+      char *name = saprintf ("fixed_%s_%s_user", database->name, user->name);
+
+      fprintf (out, "static const service_user %s = {\n", name);
+      if (next_name)
+        fprintf (out, "  (service_user *) &%s,\n", next_name);
+      else
+        fprintf (out, "  NULL, /* no next entry */\n");
+      fputs ("  {\n", out);
+      int i;
+      for (i = 0; i < sizeof (user->actions) / sizeof (user->actions[0]); i++)
+        fprintf (out, "    %s, /* %s */\n",
+                 lookup_action_name (user->actions[i]),
+                 lookup_status_name (i - 2));
+      fputs ("  },\n", out);
+      fprintf (out, "  NULL,  /* we never need the service library */\n");
+      fprintf (out, "  { .array = %s },\n", known_function_list_name);
+      fprintf (out, "  \"%s\"\n", user->name);
+      fputs ("};\n", out);
+      fputs ("\n", out);
+
+      return name;
+    }
+  else
+    return NULL;
+}
+
+
+/* Print code to OUT for the list of name_database_entry structures
+   starting with DATABASE.  Return the name of the first structure
+   in that list, or zero if DATABASE is NULL.  */
+char *
+generate_name_database_entries (FILE *out, name_database_entry *database)
+{
+  if (database)
+    {
+      char *next_name = generate_name_database_entries (out, database->next);
+      char *service_user_name
+        = generate_service_user_list (out, database, database->service);
+      char *name = saprintf ("fixed_%s_name_database", database->name);
+
+      fprintf (out, "static const name_database_entry %s = {\n", name);
+
+      if (next_name)
+        fprintf (out, "  (name_database_entry *) &%s,\n", next_name);
+      else
+        fprintf (out, "  NULL,\n");
+
+      if (service_user_name)
+        fprintf (out, "  (service_user *) &%s,\n", service_user_name);
+      else
+        fprintf (out, "  NULL,\n");
+
+      fprintf (out, "  \"%s\"\n", database->name);
+      fprintf (out, "};\n");
+      fputs ("\n", out);
+
+      return name;
+    }
+  else
+    return NULL;
+}
+
+
+void
+generate_name_database (FILE *out, name_database *service_table)
+{
+  /* Produce a linked list of the known name_database_entry
+     structures.  */
+  char *entries = generate_name_database_entries (out, service_table->entry);
+
+  /* Now produce the main structure that points to them all.  */
+  fprintf (out, "static const name_database fixed_name_database = {\n");
+  if (entries)
+    fprintf (out, "  (name_database_entry *) &%s,\n", entries);
+  else
+    fprintf (out, "  NULL,\n");
+  fputs ("  NULL /* we don't need the libraries */\n"
+         "};\n",
+         out);
+}
+
+
+
+/* Generating the list of service libraries we generate references to.  */
+
+/* String with revision number of the shared object files.  */
+static const char *const nss_shlib_revision = LIBNSS_FILES_SO + 15;
+
+void
+generate_service_lib_list (FILE *out, name_database *service_table)
+{
+  int i, j;
+  int printed_any = 0;
+
+  for (i = 0; functions[i].kind; i++)
+    {
+      /* Mention each service library only once.  */
+      for (j = 0; j < i; j++)
+        if (strcmp (functions[i].service, functions[j].service) == 0)
+          break;
+
+      if (j >= i)
+        {
+          if (printed_any)
+            putc (' ', out);
+          fprintf (out, "-lnss_%s",
+                   functions[i].service,
+                   nss_shlib_revision);
+          printed_any = 1;
+        }
+    }
+}
+
+
+/* Main.  */
+
+int
+main (int argc, char **argv)
+{
+  if (argc != 4)
+    {
+      fprintf (stderr, "usage: gen-fixed-nsswitch HEADER SERVLIBS CONFIG\n");
+      exit (1);
+    }
+
+  name_database *service_table = nss_parse_file (argv[3]);
+
+  FILE *header = fopen (argv[1], "w");
+  if (! header)
+    {
+      fprintf (stderr,
+               "gen-fixed-nsswitch: couldn't open output file %s: %s\n",
+               argv[1], strerror (errno));
+      exit (1);
+    }
+  fputs ("/* Generated by nss/gen-fixed-nsswitch.c.  */\n", header);
+  fputs ("\n", header);
+  generate_known_functions (header);
+  generate_name_database (header, service_table);
+  fclose (header);
+
+  FILE *service_lib_list = fopen (argv[2], "w");
+  if (! service_lib_list)
+    {
+      fprintf (stderr,
+               "gen-fixed-nsswitch: couldn't open output file %s: %s\n",
+               argv[2], strerror (errno));
+      exit (1);
+    }
+  generate_service_lib_list (service_lib_list, service_table);
+  fclose (service_lib_list);
+
+  return 0;
+}
Index: git/nss/getent.c
===================================================================
--- git.orig/nss/getent.c
+++ git/nss/getent.c
@@ -39,6 +39,7 @@
 #include <netinet/ether.h>
 #include <netinet/in.h>
 #include <sys/socket.h>
+#include <gnu/option-groups.h>
 
 /* Get libc version number.  */
 #include <version.h>
@@ -91,6 +92,7 @@ warranty; not even for MERCHANTABILITY o
   fprintf (stream, gettext ("Written by %s.\n"), "Thorsten Kukuk");
 }
 
+#if __OPTION_EGLIBC_DB_ALIASES
 /* This is for aliases */
 static void
 print_aliases (struct aliasent *alias)
@@ -135,7 +137,9 @@ aliases_keys (int number, char *key[])
 
   return result;
 }
+#endif /* __OPTION_EGLIBC_DB_ALIASES */
 
+#if __OPTION_EGLIBC_INET
 /* This is for ethers */
 static int
 ethers_keys (int number, char *key[])
@@ -179,6 +183,7 @@ ethers_keys (int number, char *key[])
 
   return result;
 }
+#endif /* __OPTION_EGLIBC_INET */
 
 /* This is for group */
 static void
@@ -301,6 +306,7 @@ gshadow_keys (int number, char *key[])
   return result;
 }
 
+#if __OPTION_EGLIBC_INET
 /* This is for hosts */
 static void
 print_hosts (struct hostent *host)
@@ -598,6 +604,7 @@ networks_keys (int number, char *key[])
 
   return result;
 }
+#endif /* __OPTION_EGLIBC_INET */
 
 /* Now is all for passwd */
 static void
@@ -650,6 +657,7 @@ passwd_keys (int number, char *key[])
   return result;
 }
 
+#if __OPTION_EGLIBC_INET
 /* This is for protocols */
 static void
 print_protocols (struct protoent *proto)
@@ -805,6 +813,7 @@ services_keys (int number, char *key[])
 
   return result;
 }
+#endif /* __OPTION_EGLIBC_INET */
 
 /* This is for shadow */
 static void
@@ -871,21 +880,34 @@ struct
   } databases[] =
   {
 #define D(name) { #name, name ## _keys },
-D(ahosts)
-D(ahostsv4)
-D(ahostsv6)
-D(aliases)
-D(ethers)
+
+#if __OPTION_EGLIBC_INET
+#define DN(name) D(name)
+#else
+#define DN(name)
+#endif
+
+#if __OPTION_EGLIBC_DB_ALIASES
+#define DA(name) D(name)
+#else
+#define DA(name)
+#endif
+
+DN(ahosts)
+DN(ahostsv4)
+DN(ahostsv6)
+DA(aliases)
+DN(ethers)
 D(group)
 D(gshadow)
-D(hosts)
-D(initgroups)
-D(netgroup)
-D(networks)
+DN(hosts)
+DN(initgroups)
+DN(netgroup)
+DN(networks)
 D(passwd)
-D(protocols)
-D(rpc)
-D(services)
+DN(protocols)
+DN(rpc)
+DN(services)
 D(shadow)
 #undef D
     { NULL, NULL }
Index: git/nss/getnssent_r.c
===================================================================
--- git.orig/nss/getnssent_r.c
+++ git/nss/getnssent_r.c
@@ -16,6 +16,7 @@
    <http://www.gnu.org/licenses/>.  */
 
 #include <errno.h>
+#include <gnu/option-groups.h>
 #include <netdb.h>
 #include "nsswitch.h"
 
@@ -59,11 +60,13 @@ __nss_setent (const char *func_name, db_
   } fct;
   int no_more;
 
+#if __OPTION_EGLIBC_INET
   if (res && __res_maybe_init (&_res, 0) == -1)
     {
       __set_h_errno (NETDB_INTERNAL);
       return;
     }
+#endif /* __OPTION_EGLIBC_INET */
 
   /* Cycle through the services and run their `setXXent' functions until
      we find an available service.  */
@@ -101,11 +104,13 @@ __nss_endent (const char *func_name, db_
   } fct;
   int no_more;
 
+#if __OPTION_EGLIBC_INET
   if (res && __res_maybe_init (&_res, 0) == -1)
     {
       __set_h_errno (NETDB_INTERNAL);
       return;
     }
+#endif /* __OPTION_EGLIBC_INET */
 
   /* Cycle through all the services and run their endXXent functions.  */
   no_more = setup (func_name, lookup_fct, &fct.ptr, nip, startp, 1);
@@ -141,12 +146,14 @@ __nss_getent_r (const char *getent_func_
   int no_more;
   enum nss_status status;
 
+#if __OPTION_EGLIBC_INET
   if (res && __res_maybe_init (&_res, 0) == -1)
     {
       *h_errnop = NETDB_INTERNAL;
       *result = NULL;
       return errno;
     }
+#endif /* __OPTION_EGLIBC_INET */
 
   /* Initialize status to return if no more functions are found.  */
   status = NSS_STATUS_NOTFOUND;
@@ -161,7 +168,7 @@ __nss_getent_r (const char *getent_func_
       int is_last_nip = *nip == *last_nip;
 
       status = DL_CALL_FCT (fct.f,
-			    (resbuf, buffer, buflen, &errno, &h_errno));
+			    (resbuf, buffer, buflen, &errno, h_errnop));
 
       /* The status is NSS_STATUS_TRYAGAIN and errno is ERANGE the
 	 provided buffer is too small.  In this case we should give
Index: git/nss/Makefile
===================================================================
--- git.orig/nss/Makefile
+++ git/nss/Makefile
@@ -18,29 +18,36 @@
 #
 #	Makefile for name service switch.
 #
+include ../option-groups.mak
+
 subdir	:= nss
 
 include ../Makeconfig
 
 headers			:= nss.h
 
-# This is the trivial part which goes into libc itself.
-routines		= nsswitch getnssent getnssent_r digits_dots \
-			  $(addsuffix -lookup,$(databases))
-
 # These are the databases that go through nss dispatch.
 # Caution: if you add a database here, you must add its real name
 # in databases.def, too.
-databases		= proto service hosts network grp pwd rpc ethers \
-			  spwd netgrp key alias sgrp
+databases-y		= grp pwd spwd sgrp
+databases-$(OPTION_EGLIBC_INET) \
+			+= proto service hosts network rpc ethers \
+			   netgrp key
+databases-$(OPTION_EGLIBC_DB_ALIASES) += alias
+
+# This is the trivial part which goes into libc itself.
+routines-y		+= nsswitch getnssent getnssent_r \
+			  $(addsuffix -lookup,$(databases-y))
+routines-$(OPTION_EGLIBC_INET) += digits_dots
 
 others                  := getent makedb
 install-bin             := getent makedb
 makedb-modules = xmalloc hash-string
 extra-objs		+= $(makedb-modules:=.o)
 
-tests			= test-netdb tst-nss-test1 test-digits-dots
-xtests			= bug-erange
+tests			= tst-nss-test1
+tests-$(OPTION_EGLIBC_INET) += test-netdb test-digits-dots
+xtests-$(OPTION_EGLIBC_INET) += bug-erange
 
 # Specify rules for the nss_* modules.  We have some services.
 services		:= files db
@@ -55,7 +62,7 @@ subdir-dirs = $(services:%=nss_%)
 vpath %.c $(subdir-dirs) ../locale/programs ../intl
 
 
-libnss_files-routines	:= $(addprefix files-,$(databases)) \
+libnss_files-routines	:= $(addprefix files-,$(databases-y)) \
 			   files-initgroups files-have_o_cloexec files-init
 
 libnss_db-dbs		:= $(addprefix db-,\
@@ -78,6 +85,45 @@ tests-static		= tst-nss-static
 tests			+= $(tests-static)
 endif
 
+ifneq ($(OPTION_EGLIBC_NSSWITCH),y)
+
+ifndef OPTION_EGLIBC_NSSWITCH_FIXED_CONFIG
+$(error OPTION_EGLIBC_NSSWITCH_FIXED_CONFIG variable left unset)
+endif
+
+ifndef OPTION_EGLIBC_NSSWITCH_FIXED_FUNCTIONS
+$(error OPTION_EGLIBC_NSSWITCH_FIXED_FUNCTIONS variable left unset)
+endif
+
+ifeq (,$(wildcard $(OPTION_EGLIBC_NSSWITCH_FIXED_CONFIG)))
+$(warning OPTION_EGLIBC_NSSWITCH is disabled, but fixed config file)
+$(error does not exist: $(OPTION_EGLIBC_NSSWITCH_FIXED_CONFIG))
+endif
+
+ifeq (,$(wildcard $(OPTION_EGLIBC_NSSWITCH_FIXED_FUNCTIONS)))
+$(warning OPTION_EGLIBC_NSSWITCH is disabled, but fixed functions file)
+$(error does not exist: $(OPTION_EGLIBC_NSSWITCH_FIXED_FUNCTIONS))
+endif
+
+before-compile := $(objpfx)fixed-nsswitch.h
+generated := fixed-nsswitch.h
+$(objpfx)fixed-nsswitch.h $(objfpx)fixed-nsswitch-libs:	\
+    $(objpfx)gen-fixed-nsswitch				\
+    $(OPTION_EGLIBC_NSSWITCH_FIXED_CONFIG)
+	$< $(objpfx)fixed-nsswitch.h			\
+	   $(objpfx)fixed-nsswitch-libs			\
+	   $(OPTION_EGLIBC_NSSWITCH_FIXED_CONFIG)
+
+$(objpfx)gen-fixed-nsswitch: gen-fixed-nsswitch.c	\
+    $(common-objpfx)option-groups.config		\
+    $(OPTION_EGLIBC_NSSWITCH_FIXED_FUNCTIONS)
+	$(native-compile)
+gen-fixed-nsswitch-CFLAGS =						\
+	-g3 -O -Wall							\
+	-I $(objpfx)							\
+	-DFIXED_FUNCTIONS='"$(OPTION_EGLIBC_NSSWITCH_FIXED_FUNCTIONS)"'
+endif
+
 include ../Rules
 
 ifeq (yes,$(have-selinux))
Index: git/nss/nsswitch.c
===================================================================
--- git.orig/nss/nsswitch.c
+++ git/nss/nsswitch.c
@@ -26,6 +26,7 @@
 #include <stdio_ext.h>
 #include <stdlib.h>
 #include <string.h>
+#include <gnu/option-groups.h>
 
 #include <aliases.h>
 #include <grp.h>
@@ -41,6 +42,15 @@
 #include "../nscd/nscd_proto.h"
 #include <sysdep.h>
 
+/* When OPTION_EGLIBC_NSSWITCH is disabled, we use fixed tables of
+   databases and services, generated at library build time.  Thus:
+   - We can't reconfigure individual databases, so we don't need a
+     name-to-database map.
+   - We never add databases or service libraries, or look up functions
+     at runtime, so there's no need for a lock to protect our tables.
+   See ../option-groups.def for the details.  */
+#if __OPTION_EGLIBC_NSSWITCH
+
 /* Prototypes for the local functions.  */
 static name_database *nss_parse_file (const char *fname) internal_function;
 static name_database_entry *nss_getline (char *line) internal_function;
@@ -79,6 +89,9 @@ bool __nss_database_custom[NSS_DBSIDX_ma
 
 __libc_lock_define_initialized (static, lock)
 
+#define lock_nsswitch __libc_lock_lock (lock)
+#define unlock_nsswitch __libc_lock_unlock (lock)
+
 #if !defined DO_STATIC_NSS || defined SHARED
 /* String with revision number of the shared object files.  */
 static const char *const __nss_shlib_revision = LIBNSS_FILES_SO + 15;
@@ -93,6 +106,20 @@ static name_database *service_table;
    __libc_freeres.  */
 static name_database_entry *defconfig_entries;
 
+#else /* __OPTION_EGLIBC_NSSWITCH */
+
+/* Bring in the statically initialized service table we generated at
+   build time.  */
+#include "fixed-nsswitch.h"
+
+const static name_database *service_table = &fixed_name_database;
+
+/* Nothing ever changes, so there's no need to lock anything.  */
+#define lock_nsswitch (0)
+#define unlock_nsswitch (0)
+
+#endif /* __OPTION_EGLIBC_NSSWITCH */
+
 
 #ifdef USE_NSCD
 /* Nonzero if this is the nscd process.  */
@@ -109,20 +136,22 @@ __nss_database_lookup (const char *datab
 		       const char *defconfig, service_user **ni)
 {
   /* Prevent multiple threads to change the service table.  */
-  __libc_lock_lock (lock);
+  lock_nsswitch;
 
   /* Reconsider database variable in case some other thread called
      `__nss_configure_lookup' while we waited for the lock.  */
   if (*ni != NULL)
     {
-      __libc_lock_unlock (lock);
+      unlock_nsswitch;
       return 0;
     }
 
+#if __OPTION_EGLIBC_NSSWITCH
   /* Are we initialized yet?  */
   if (service_table == NULL)
     /* Read config file.  */
     service_table = nss_parse_file (_PATH_NSSWITCH_CONF);
+#endif
 
   /* Test whether configuration data is available.  */
   if (service_table != NULL)
@@ -144,6 +173,7 @@ __nss_database_lookup (const char *datab
 	    *ni = entry->service;
     }
 
+#if __OPTION_EGLIBC_NSSWITCH
   /* No configuration data is available, either because nsswitch.conf
      doesn't exist or because it doesn't have a line for this database.
 
@@ -166,13 +196,23 @@ __nss_database_lookup (const char *datab
 	    {
 	      entry->next = defconfig_entries;
 	      entry->service = *ni;
-	      entry->name[0] = '\0';
+	      entry->name = "";
 	      defconfig_entries = entry;
 	    }
 	}
     }
+#else
+  /* Without the dynamic behavior, we can't process defconfig.  The
+     databases the user specified at library build time are all you
+     get.  */
+  if (*ni == NULL)
+    {
+      unlock_nsswitch;
+      return -1;
+    }
+#endif
 
-  __libc_lock_unlock (lock);
+  unlock_nsswitch;
 
   return *ni != NULL ? 0 : -1;
 }
@@ -252,6 +292,7 @@ __nss_next2 (service_user **ni, const ch
 libc_hidden_def (__nss_next2)
 
 
+#if __OPTION_EGLIBC_NSSWITCH
 int
 attribute_compat_text_section
 __nss_next (service_user **ni, const char *fct_name, void **fctp, int status,
@@ -300,13 +341,13 @@ __nss_configure_lookup (const char *dbna
     }
 
   /* Prevent multiple threads to change the service table.  */
-  __libc_lock_lock (lock);
+  lock_nsswitch;
 
   /* Install new rules.  */
   *databases[cnt].dbp = new_db;
   __nss_database_custom[cnt] = true;
 
-  __libc_lock_unlock (lock);
+  unlock_nsswitch;
 
   return 0;
 }
@@ -402,7 +443,7 @@ __nss_lookup_function (service_user *ni,
   void **found, *result;
 
   /* We now modify global data.  Protect it.  */
-  __libc_lock_lock (lock);
+  lock_nsswitch;
 
   /* Search the tree of functions previously requested.  Data in the
      tree are `known_function' structures, whose first member is a
@@ -413,7 +454,7 @@ __nss_lookup_function (service_user *ni,
      enough to a pointer to our structure to use as a lookup key that
      will be passed to `known_compare' (above).  */
 
-  found = __tsearch (&fct_name, &ni->known, &known_compare);
+  found = __tsearch (&fct_name, &ni->known.tree, &known_compare);
   if (found == NULL)
     /* This means out-of-memory.  */
     result = NULL;
@@ -440,7 +481,7 @@ __nss_lookup_function (service_user *ni,
 #endif
 	  /* Oops.  We can't instantiate this node properly.
 	     Remove it from the tree.  */
-	  __tdelete (&fct_name, &ni->known, &known_compare);
+	  __tdelete (&fct_name, &ni->known.tree, &known_compare);
 	  free (known);
 	  result = NULL;
 	}
@@ -520,13 +561,43 @@ __nss_lookup_function (service_user *ni,
     }
 
   /* Remove the lock.  */
-  __libc_lock_unlock (lock);
+  unlock_nsswitch;
 
   return result;
 }
 libc_hidden_def (__nss_lookup_function)
 
 
+#else /* below if ! __OPTION_EGLIBC_NSSWITCH */
+
+
+int
+__nss_configure_lookup (const char *dbname, const char *service_line)
+{
+  /* We can't dynamically configure lookup without
+     OPTION_EGLIBC_NSSWITCH.  */
+  __set_errno (EINVAL);
+  return -1;
+}
+
+
+void *
+__nss_lookup_function (service_user *ni, const char *fct_name)
+{
+  int i;
+  const known_function **known = ni->known.array;
+
+  for (i = 0; known[i]; i++)
+    if (strcmp (fct_name, known[i]->fct_name) == 0)
+      return known[i]->fct_ptr;
+
+  return NULL;
+}
+libc_hidden_def (__nss_lookup_function)
+#endif
+
+
+#if __OPTION_EGLIBC_NSSWITCH
 static name_database *
 internal_function
 nss_parse_file (const char *fname)
@@ -632,8 +703,10 @@ nss_parse_service_list (const char *line
 					     + (line - name + 1));
       if (new_service == NULL)
 	return result;
+      new_service->name = (char *) (new_service + 1);
 
-      *((char *) __mempcpy (new_service->name, name, line - name)) = '\0';
+      *((char *) __mempcpy ((char *) new_service->name, name, line - name))
+        = '\0';
 
       /* Set default actions.  */
       new_service->actions[2 + NSS_STATUS_TRYAGAIN] = NSS_ACTION_CONTINUE;
@@ -642,7 +715,7 @@ nss_parse_service_list (const char *line
       new_service->actions[2 + NSS_STATUS_SUCCESS] = NSS_ACTION_RETURN;
       new_service->actions[2 + NSS_STATUS_RETURN] = NSS_ACTION_RETURN;
       new_service->library = NULL;
-      new_service->known = NULL;
+      new_service->known.tree = NULL;
       new_service->next = NULL;
 
       while (isspace (line[0]))
@@ -778,9 +851,10 @@ nss_getline (char *line)
   result = (name_database_entry *) malloc (sizeof (name_database_entry) + len);
   if (result == NULL)
     return NULL;
+  result->name = (char *) (result + 1);
 
   /* Save the database name.  */
-  memcpy (result->name, name, len);
+  memcpy ((char *) result->name, name, len);
 
   /* Parse the list of services.  */
   result->service = nss_parse_service_list (line);
@@ -816,6 +890,7 @@ nss_new_service (name_database *database
   return *currentp;
 }
 #endif
+#endif /* __OPTION_EGLIBC_NSSWITCH */
 
 
 #if defined SHARED && defined USE_NSCD
@@ -834,6 +909,7 @@ nss_load_all_libraries (const char *serv
 }
 
 
+#if __OPTION_EGLIBC_INET
 /* Called by nscd and nscd alone.  */
 void
 __nss_disable_nscd (void (*cb) (size_t, struct traced_file *))
@@ -857,8 +933,10 @@ __nss_disable_nscd (void (*cb) (size_t,
   __nss_not_use_nscd_services = -1;
   __nss_not_use_nscd_netgroup = -1;
 }
+#endif /* __OPTION_EGLIBC_INET */
 #endif
 
+#if __OPTION_EGLIBC_NSSWITCH
 static void
 free_database_entries (name_database_entry *entry)
 {
@@ -871,8 +949,8 @@ free_database_entries (name_database_ent
 	{
 	  service_user *olds = service;
 
-	  if (service->known != NULL)
-	    __tdestroy (service->known, free);
+	  if (service->known.tree != NULL)
+	    __tdestroy (service->known.tree, free);
 
 	  service = service->next;
 	  free (olds);
@@ -926,3 +1004,4 @@ libc_freeres_fn (free_mem)
 
   free (top);
 }
+#endif /* __OPTION_EGLIBC_NSSWITCH */
Index: git/nss/nsswitch.h
===================================================================
--- git.orig/nss/nsswitch.h
+++ git/nss/nsswitch.h
@@ -65,10 +65,20 @@ typedef struct service_user
   lookup_actions actions[5];
   /* Link to the underlying library object.  */
   service_library *library;
-  /* Collection of known functions.  */
-  void *known;
+  /* Collection of known functions.
+
+     With OPTION_EGLIBC_NSSWITCH enabled, this is the root of a
+     'tsearch'-style tree.
+
+     With OPTION_EGLIBC_NSSWITCH disabled, this is an array of
+     pointers to known_function structures, NULL-terminated.  */
+  union
+  {
+    void *tree;
+    const known_function **array;
+  } known;
   /* Name of the service (`files', `dns', `nis', ...).  */
-  char name[0];
+  const char *name;
 } service_user;
 
 /* To access the action based on the status value use this macro.  */
@@ -82,7 +92,7 @@ typedef struct name_database_entry
   /* List of service to be used.  */
   service_user *service;
   /* Name of the database.  */
-  char name[0];
+  const char *name;
 } name_database_entry;
 
 
Index: git/posix/bug-regex1.c
===================================================================
--- git.orig/posix/bug-regex1.c
+++ git/posix/bug-regex1.c
@@ -4,6 +4,7 @@
 #include <string.h>
 #include <regex.h>
 #include <wchar.h>
+#include <gnu/option-groups.h>
 
 int
 main (void)
@@ -17,7 +18,9 @@ main (void)
   memset (&regex, '\0', sizeof (regex));
 
   setlocale (LC_ALL, "de_DE.ISO-8859-1");
+#if __OPTION_POSIX_WIDE_CHAR_DEVICE_IO
   fwide (stdout, -1);
+#endif
 
   re_set_syntax (RE_SYNTAX_POSIX_EGREP | RE_DEBUG);
 
Index: git/posix/bug-regex6.c
===================================================================
--- git.orig/posix/bug-regex6.c
+++ git/posix/bug-regex6.c
@@ -22,6 +22,7 @@
 #include <string.h>
 #include <sys/types.h>
 #include <regex.h>
+#include <gnu/option-groups.h>
 
 
 int
@@ -30,7 +31,12 @@ main (int argc, char *argv[])
   regex_t re;
   regmatch_t mat[10];
   int i, j, ret = 0;
-  const char *locales[] = { "C", "de_DE.UTF-8" };
+  const char *locales[] = {
+    "C",
+#if __OPTION_EGLIBC_LOCALE_CODE
+    "de_DE.UTF-8"
+#endif
+  };
   const char *string = "http://www.regex.com/pattern/matching.html#intro";
   regmatch_t expect[10] = {
     { 0, 48 }, { 0, 5 }, { 0, 4 }, { 5, 20 }, { 7, 20 }, { 20, 42 },
Index: git/posix/fnmatch.c
===================================================================
--- git.orig/posix/fnmatch.c
+++ git/posix/fnmatch.c
@@ -30,6 +30,10 @@
 #include <ctype.h>
 #include <string.h>
 
+#if defined _LIBC
+# include <gnu/option-groups.h>
+#endif
+
 #if defined STDC_HEADERS || defined _LIBC
 # include <stdlib.h>
 #endif
@@ -131,7 +135,7 @@ extern int fnmatch (const char *pattern,
 #   define ISWCTYPE(WC, WT)	iswctype (WC, WT)
 #  endif
 
-#  if (HAVE_MBSTATE_T && HAVE_MBSRTOWCS) || _LIBC
+#  if (HAVE_MBSTATE_T && HAVE_MBSRTOWCS && _LIBC && __OPTION_EGLIBC_LOCALE_CODE)
 /* In this case we are implementing the multibyte character handling.  */
 #   define HANDLE_MULTIBYTE	1
 #  endif
Index: git/posix/fnmatch_loop.c
===================================================================
--- git.orig/posix/fnmatch_loop.c
+++ git/posix/fnmatch_loop.c
@@ -15,6 +15,8 @@
    License along with the GNU C Library; if not, see
    <http://www.gnu.org/licenses/>.  */
 
+#include <gnu/option-groups.h>
+
 #include <stdint.h>
 
 struct STRUCT
@@ -54,10 +56,15 @@ FCT (pattern, string, string_end, no_lea
   const char *collseq = (const char *)
     _NL_CURRENT(LC_COLLATE, _NL_COLLATE_COLLSEQWC);
 # else
+#  if __OPTION_EGLIBC_LOCALE_CODE
   const UCHAR *collseq = (const UCHAR *)
     _NL_CURRENT(LC_COLLATE, _NL_COLLATE_COLLSEQMB);
-# endif
-#endif
+#   define COLLSEQ_BYTE_LOOKUP(ix) (collseq[(ix)])
+#  else
+#   define COLLSEQ_BYTE_LOOKUP(ix) (ix)
+#  endif /* __OPTION_EGLIBC_LOCALE_CODE */
+# endif /* WIDE_CHAR_VERSION */
+#endif /* _LIBC */
 
   while ((c = *p++) != L('\0'))
     {
@@ -277,7 +284,7 @@ FCT (pattern, string, string_end, no_lea
 		    /* Leave room for the null.  */
 		    CHAR str[CHAR_CLASS_MAX_LENGTH + 1];
 		    size_t c1 = 0;
-#if defined _LIBC || (defined HAVE_WCTYPE_H && defined HAVE_WCHAR_H)
+#if defined _LIBC ? __OPTION_POSIX_C_LANG_WIDE_CHAR : (defined HAVE_WCTYPE_H && defined HAVE_WCHAR_H)
 		    wctype_t wt;
 #endif
 		    const CHAR *startp = p;
@@ -307,7 +314,7 @@ FCT (pattern, string, string_end, no_lea
 		      }
 		    str[c1] = L('\0');
 
-#if defined _LIBC || (defined HAVE_WCTYPE_H && defined HAVE_WCHAR_H)
+#if defined _LIBC ? __OPTION_POSIX_C_LANG_WIDE_CHAR : (defined HAVE_WCTYPE_H && defined HAVE_WCHAR_H)
 		    wt = IS_CHAR_CLASS (str);
 		    if (wt == 0)
 		      /* Invalid character class name.  */
@@ -680,8 +687,10 @@ FCT (pattern, string, string_end, no_lea
 			else
 			  lcollseq = __collseq_table_lookup (collseq, cold);
 # else
-			fcollseq = collseq[fn];
-			lcollseq = is_seqval ? cold : collseq[(UCHAR) cold];
+			fcollseq = COLLSEQ_BYTE_LOOKUP (fn);
+			lcollseq = (is_seqval
+                                    ? cold
+                                    : COLLSEQ_BYTE_LOOKUP ((UCHAR) cold));
 # endif
 
 			is_seqval = 0;
@@ -857,7 +866,7 @@ FCT (pattern, string, string_end, no_lea
 				    goto matched;
 				  }
 # else
-				hcollseq = collseq[cend];
+				hcollseq = COLLSEQ_BYTE_LOOKUP (cend);
 # endif
 			      }
 
Index: git/posix/glob.c
===================================================================
--- git.orig/posix/glob.c
+++ git/posix/glob.c
@@ -25,6 +25,9 @@
 #include <sys/types.h>
 #include <sys/stat.h>
 #include <stddef.h>
+#ifdef _LIBC
+# include <gnu/option-groups.h>
+#endif
 
 /* Outcomment the following line for production quality code.  */
 /* #define NDEBUG 1 */
@@ -607,6 +610,7 @@ glob (pattern, flags, errfunc, pglob)
 	  if (home_dir == NULL || home_dir[0] == '\0')
 	    home_dir = "c:/users/default"; /* poor default */
 #  else
+#   if ! _LIBC || __OPTION_EGLIBC_GETLOGIN
 	  if (home_dir == NULL || home_dir[0] == '\0')
 	    {
 	      int success;
@@ -623,19 +627,19 @@ glob (pattern, flags, errfunc, pglob)
 	      if (success)
 		{
 		  struct passwd *p;
-#   if defined HAVE_GETPWNAM_R || defined _LIBC
+#    if defined HAVE_GETPWNAM_R || defined _LIBC
 		  long int pwbuflen = GETPW_R_SIZE_MAX ();
 		  char *pwtmpbuf;
 		  struct passwd pwbuf;
 		  int malloc_pwtmpbuf = 0;
 		  int save = errno;
 
-#    ifndef _LIBC
+#     ifndef _LIBC
 		  if (pwbuflen == -1)
 		    /* `sysconf' does not support _SC_GETPW_R_SIZE_MAX.
 		       Try a moderate value.  */
 		    pwbuflen = 1024;
-#    endif
+#     endif
 		  if (__libc_use_alloca (alloca_used + pwbuflen))
 		    pwtmpbuf = alloca_account (pwbuflen, alloca_used);
 		  else
@@ -682,9 +686,9 @@ glob (pattern, flags, errfunc, pglob)
 			}
 		      __set_errno (save);
 		    }
-#   else
+#    else
 		  p = getpwnam (name);
-#   endif
+#    endif
 		  if (p != NULL)
 		    {
 		      if (!malloc_pwtmpbuf)
@@ -713,6 +717,7 @@ glob (pattern, flags, errfunc, pglob)
 		    }
 		}
 	    }
+#   endif /* ! _LIBC || __OPTION_EGLIBC_GETLOGIN */
 	  if (home_dir == NULL || home_dir[0] == '\0')
 	    {
 	      if (flags & GLOB_TILDE_CHECK)
Index: git/posix/Makefile
===================================================================
--- git.orig/posix/Makefile
+++ git/posix/Makefile
@@ -18,6 +18,8 @@
 #
 #	Sub-makefile for POSIX portion of the library.
 #
+include ../option-groups.mak
+
 subdir	:= posix
 
 include ../Makeconfig
@@ -43,13 +45,24 @@ routines :=								      \
 	getpgid setpgid getpgrp bsd-getpgrp setpgrp getsid setsid	      \
 	getresuid getresgid setresuid setresgid				      \
 	pathconf sysconf fpathconf					      \
-	glob glob64 fnmatch regex					      \
+	glob glob64 fnmatch						      \
 	confstr								      \
 	getopt getopt1 getopt_init					      \
 	sched_setp sched_getp sched_sets sched_gets sched_yield sched_primax  \
 	sched_primin sched_rr_gi sched_getaffinity sched_setaffinity	      \
-	getaddrinfo gai_strerror wordexp				      \
 	pread pwrite pread64 pwrite64					      \
+	posix_madvise							      \
+	get_child_max sched_cpucount sched_cpualloc sched_cpufree
+
+routines-$(OPTION_EGLIBC_INET) += getaddrinfo gai_strerror
+
+ifeq (y,$(OPTION_POSIX_REGEXP_GLIBC))
+routines-$(OPTION_POSIX_REGEXP) += regex
+else
+routines-$(OPTION_POSIX_REGEXP) += xregex
+endif
+
+routines-$(OPTION_EGLIBC_SPAWN) +=					      \
 	spawn_faction_init spawn_faction_destroy spawn_faction_addclose	      \
 	spawn_faction_addopen spawn_faction_adddup2			      \
 	spawnattr_init spawnattr_destroy				      \
@@ -61,37 +74,53 @@ routines :=								      \
 	posix_madvise							      \
 	get_child_max sched_cpucount sched_cpualloc sched_cpufree
 
+routines-$(OPTION_EGLIBC_WORDEXP) += wordexp
+
 aux		:= init-posix environ
-tests		:= tstgetopt testfnm runtests runptests	     \
+tests		:= tstgetopt testfnm runtests	\
 		   tst-preadwrite tst-preadwrite64 test-vfork regexbug1 \
-		   tst-getlogin tst-mmap tst-getaddrinfo tst-truncate \
-		   tst-truncate64 tst-fork tst-fnmatch tst-regexloc tst-dir \
-		   tst-chmod bug-regex1 bug-regex2 bug-regex3 bug-regex4 \
-		   tst-gnuglob tst-regex bug-regex5 bug-regex6 bug-regex7 \
-		   bug-regex8 bug-regex9 bug-regex10 bug-regex11 bug-regex12 \
-		   bug-regex13 bug-regex14 bug-regex15 bug-regex16 \
-		   bug-regex17 bug-regex18 bug-regex19 bug-regex20 \
-		   bug-regex21 bug-regex22 bug-regex23 bug-regex24 \
-		   bug-regex25 bug-regex26 bug-regex27 bug-regex28 \
-		   bug-regex29 bug-regex30 bug-regex31 bug-regex32 \
-		   bug-regex33 tst-nice tst-nanosleep tst-regex2 \
-		   transbug tst-rxspencer tst-pcre tst-boost \
-		   bug-ga1 tst-vfork1 tst-vfork2 tst-vfork3 tst-waitid \
-		   tst-getaddrinfo2 bug-glob1 bug-glob2 bug-glob3 tst-sysconf \
+		   tst-getlogin tst-mmap tst-truncate \
+		   tst-truncate64 tst-fork tst-dir \
+		   tst-chmod bug-regex2 bug-regex3 bug-regex4 \
+		   tst-gnuglob bug-regex6 bug-regex7 \
+		   bug-regex8 bug-regex9 bug-regex10 bug-regex12 \
+		   bug-regex14 bug-regex15 \
+		   bug-regex21 bug-regex24 \
+		   bug-regex27 bug-regex28 \
+		   bug-regex29 bug-regex30 bug-regex31 \
+		   tst-nice tst-nanosleep \
+		   transbug \
+		   tst-vfork1 tst-vfork2 tst-vfork3 tst-waitid \
+		   bug-glob1 bug-glob2 bug-glob3 tst-sysconf \
 		   tst-execvp1 tst-execvp2 tst-execlp1 tst-execlp2 \
 		   tst-execv1 tst-execv2 tst-execl1 tst-execl2 \
 		   tst-execve1 tst-execve2 tst-execle1 tst-execle2 \
-		   tst-execvp3 tst-execvp4 tst-rfc3484 tst-rfc3484-2 \
-		   tst-rfc3484-3 \
-		   tst-getaddrinfo3 tst-fnmatch2 tst-cpucount tst-cpuset \
+		   tst-execvp3 tst-execvp4 \
+		   tst-fnmatch2 tst-cpucount tst-cpuset \
 		   bug-getopt1 bug-getopt2 bug-getopt3 bug-getopt4 \
 		   bug-getopt5 tst-getopt_long1 bug-regex34 bug-regex35 \
 		   tst-pathconf tst-getaddrinfo4 tst-rxspencer-no-utf8 \
 		   tst-fnmatch3 bug-regex36 tst-getaddrinfo5
-xtests		:= bug-ga2
+tests-$(OPTION_EGLIBC_LOCALE_CODE)                                         \
+	+= tst-fnmatch tst-regexloc bug-regex1 bug-regex5 \
+	bug-regex23 bug-regex25 bug-regex32 bug-regex33
+tests-$(OPTION_EGLIBC_INET) \
+	+= tst-getaddrinfo bug-ga1 tst-getaddrinfo2 \
+	tst-rfc3484 tst-rfc3484-2 tst-rfc3484-3 tst-getaddrinfo3
+tests-$(OPTION_POSIX_REGEXP_GLIBC) \
+	+= runptests bug-regex11 bug-regex13 bug-regex16 \
+	tst-regex2 tst-rxspencer tst-pcre tst-boost
+ifeq (yy,$(OPTION_EGLIBC_LOCALE_CODE)$(OPTION_POSIX_REGEXP_GLIBC))
+tests	+= tst-regex bug-regex17 bug-regex18 bug-regex19 bug-regex20 \
+	bug-regex22 bug-regex26
+endif
+xtests-$(OPTION_EGLIBC_INET) += bug-ga2
+
 ifeq (yes,$(build-shared))
 test-srcs	:= globtest
-tests           += wordexp-test tst-exec tst-spawn
+tests           += tst-exec
+tests-$(OPTION_EGLIBC_SPAWN) += tst-spawn
+tests-$(OPTION_EGLIBC_WORDEXP) += wordexp-test
 endif
 tests-static	= tst-exec-static tst-spawn-static
 tests		+= $(tests-static)
@@ -117,7 +146,10 @@ generated += $(addprefix wordexp-test-re
 
 ifeq ($(run-built-tests),yes)
 ifeq (yes,$(build-shared))
-tests-special += $(objpfx)globtest.out $(objpfx)wordexp-tst.out
+tests-special += $(objpfx)globtest.out
+ifeq (y,$(OPTION_EGLIBC_WORDEXP))
+tests-special += $(objpfx)wordexp-tst.out
+endif
 endif
 endif
 
@@ -125,12 +157,16 @@ endif
 # XXX Please note that for now we ignore the result of this test.
 tests-special += $(objpfx)annexc.out
 ifeq ($(run-built-tests),yes)
-tests-special += $(objpfx)bug-regex2-mem.out $(objpfx)bug-regex14-mem.out \
+tests-special += $(objpfx)bug-regex2-mem.out \
 		 $(objpfx)bug-regex21-mem.out $(objpfx)bug-regex31-mem.out \
-		 $(objpfx)tst-rxspencer-no-utf8-mem.out $(objpfx)tst-pcre-mem.out \
-		 $(objpfx)tst-boost-mem.out $(objpfx)tst-getconf.out \
+		 $(objpfx)tst-getconf.out \
 		 $(objpfx)bug-glob2-mem.out $(objpfx)tst-vfork3-mem.out \
 		 $(objpfx)tst-fnmatch-mem.out $(objpfx)bug-regex36-mem.out
+ifeq (y,$(OPTION_POSIX_REGEXP_GLIBC))
+tests-special += $(objpfx)bug-regex14-mem.out $(objpfx)tst-rxspencer-no-utf8-mem.out \
+  		 $(objpfx)tst-pcre-mem.out $(objpfx)tst-boost-mem.out
+endif
+
 xtests-special += $(objpfx)bug-ga2-mem.out
 endif
 
@@ -143,6 +179,8 @@ $(objpfx)globtest.out: globtest.sh $(obj
 	$(SHELL) $< $(common-objpfx) '$(test-via-rtld-prefix)' \
 		'$(test-program-prefix)' '$(test-wrapper-env)'; \
 	$(evaluate-test)
+LDLIBS-globtest += $(shell cat $(common-objpfx)nss/fixed-nsswitch-libs)
+
 $(objpfx)wordexp-tst.out: wordexp-tst.sh $(objpfx)wordexp-test
 	$(SHELL) $< $(common-objpfx) '$(test-program-prefix-before-env)' \
 		 '$(run-program-env)' '$(test-program-prefix-after-env)'; \
@@ -205,7 +243,10 @@ tst-dir-ARGS = `pwd` `cd $(common-objdir
 tst-chmod-ARGS = $(objdir)
 tst-vfork3-ARGS = --test-dir=$(objpfx)
 
-tst-rxspencer-ARGS = --utf8 rxspencer/tests
+tst-rxspencer-ARGS = rxspencer/tests
+ifeq (y,$(OPTION_EGLIBC_LOCALE_CODE))
+tst-rxspencer-ARGS += --utf8
+endif
 tst-rxspencer-no-utf8-ARGS = rxspencer/tests
 tst-pcre-ARGS = PCRE.tests
 tst-boost-ARGS = BOOST.tests
Index: git/posix/regcomp.c
===================================================================
--- git.orig/posix/regcomp.c
+++ git/posix/regcomp.c
@@ -18,6 +18,7 @@
    <http://www.gnu.org/licenses/>.  */
 
 #include <stdint.h>
+#include <gnu/option-groups.h>
 
 #ifdef _LIBC
 # include <locale/weight.h>
@@ -309,7 +310,7 @@ re_compile_fastmap_iter (regex_t *bufp,
 {
   re_dfa_t *dfa = (re_dfa_t *) bufp->buffer;
   int node_cnt;
-  int icase = (dfa->mb_cur_max == 1 && (bufp->syntax & RE_ICASE));
+  int icase = (dfa_mb_cur_max (dfa) == 1 && (bufp->syntax & RE_ICASE));
   for (node_cnt = 0; node_cnt < init_state->nodes.nelem; ++node_cnt)
     {
       int node = init_state->nodes.elems[node_cnt];
@@ -319,9 +320,9 @@ re_compile_fastmap_iter (regex_t *bufp,
 	{
 	  re_set_fastmap (fastmap, icase, dfa->nodes[node].opr.c);
 #ifdef RE_ENABLE_I18N
-	  if ((bufp->syntax & RE_ICASE) && dfa->mb_cur_max > 1)
+	  if ((bufp->syntax & RE_ICASE) && dfa_mb_cur_max (dfa) > 1)
 	    {
-	      unsigned char *buf = alloca (dfa->mb_cur_max), *p;
+	      unsigned char *buf = alloca (dfa_mb_cur_max (dfa)), *p;
 	      wchar_t wc;
 	      mbstate_t state;
 
@@ -352,7 +353,11 @@ re_compile_fastmap_iter (regex_t *bufp,
 		  re_set_fastmap (fastmap, icase, ch);
 	    }
 	}
-#ifdef RE_ENABLE_I18N
+
+      /* When OPTION_EGLIBC_LOCALE_CODE is disabled, the current
+         locale is always C, which has no rules and no multi-byte
+         characters.  */
+#if defined RE_ENABLE_I18N && __OPTION_EGLIBC_LOCALE_CODE
       else if (type == COMPLEX_BRACKET)
 	{
 	  re_charset_t *cset = dfa->nodes[node].opr.mbcset;
@@ -380,7 +385,7 @@ re_compile_fastmap_iter (regex_t *bufp,
 	     i.e. where we would not find an invalid sequence.  This only
 	     applies to multibyte character sets; for single byte character
 	     sets, the SIMPLE_BRACKET again suffices.  */
-	  if (dfa->mb_cur_max > 1
+	  if (dfa_mb_cur_max (dfa) > 1
 	      && (cset->nchar_classes || cset->non_match || cset->nranges
 # ifdef _LIBC
 		  || cset->nequiv_classes
@@ -408,7 +413,7 @@ re_compile_fastmap_iter (regex_t *bufp,
 		  memset (&state, '\0', sizeof (state));
 		  if (__wcrtomb (buf, cset->mbchars[i], &state) != (size_t) -1)
 		    re_set_fastmap (fastmap, icase, *(unsigned char *) buf);
-		  if ((bufp->syntax & RE_ICASE) && dfa->mb_cur_max > 1)
+		  if ((bufp->syntax & RE_ICASE) && dfa_mb_cur_max (dfa) > 1)
 		    {
 		      if (__wcrtomb (buf, towlower (cset->mbchars[i]), &state)
 			  != (size_t) -1)
@@ -417,7 +422,7 @@ re_compile_fastmap_iter (regex_t *bufp,
 		}
 	    }
 	}
-#endif /* RE_ENABLE_I18N */
+#endif /* RE_ENABLE_I18N && __OPTION_EGLIBC_LOCALE_CODE */
       else if (type == OP_PERIOD
 #ifdef RE_ENABLE_I18N
 	       || type == OP_UTF8_PERIOD
@@ -860,11 +865,15 @@ init_dfa (re_dfa_t *dfa, size_t pat_len)
 
   dfa->mb_cur_max = MB_CUR_MAX;
 #ifdef _LIBC
-  if (dfa->mb_cur_max == 6
+  if (dfa_mb_cur_max (dfa) == 6
       && strcmp (_NL_CURRENT (LC_CTYPE, _NL_CTYPE_CODESET_NAME), "UTF-8") == 0)
     dfa->is_utf8 = 1;
+# if __OPTION_EGLIBC_LOCALE_CODE
   dfa->map_notascii = (_NL_CURRENT_WORD (LC_CTYPE, _NL_CTYPE_MAP_TO_NONASCII)
 		       != 0);
+# else
+  dfa->map_notascii = 0;
+# endif
 #else
 # ifdef HAVE_LANGINFO_CODESET
   codeset_name = nl_langinfo (CODESET);
@@ -890,7 +899,7 @@ init_dfa (re_dfa_t *dfa, size_t pat_len)
 #endif
 
 #ifdef RE_ENABLE_I18N
-  if (dfa->mb_cur_max > 1)
+  if (dfa_mb_cur_max (dfa) > 1)
     {
       if (dfa->is_utf8)
 	dfa->sb_char = (re_bitset_ptr_t) utf8_sb_map;
@@ -1788,7 +1797,7 @@ peek_token (re_token_t *token, re_string
   token->word_char = 0;
 #ifdef RE_ENABLE_I18N
   token->mb_partial = 0;
-  if (input->mb_cur_max > 1 &&
+  if (string_mb_cur_max (input) > 1 &&
       !re_string_first_byte (input, re_string_cur_idx (input)))
     {
       token->type = CHARACTER;
@@ -1809,7 +1818,7 @@ peek_token (re_token_t *token, re_string
       token->opr.c = c2;
       token->type = CHARACTER;
 #ifdef RE_ENABLE_I18N
-      if (input->mb_cur_max > 1)
+      if (string_mb_cur_max (input) > 1)
 	{
 	  wint_t wc = re_string_wchar_at (input,
 					  re_string_cur_idx (input) + 1);
@@ -1923,7 +1932,7 @@ peek_token (re_token_t *token, re_string
 
   token->type = CHARACTER;
 #ifdef RE_ENABLE_I18N
-  if (input->mb_cur_max > 1)
+  if (string_mb_cur_max (input) > 1)
     {
       wint_t wc = re_string_wchar_at (input, re_string_cur_idx (input));
       token->word_char = IS_WIDE_WORD_CHAR (wc) != 0;
@@ -2023,7 +2032,7 @@ peek_token_bracket (re_token_t *token, r
   token->opr.c = c;
 
 #ifdef RE_ENABLE_I18N
-  if (input->mb_cur_max > 1 &&
+  if (string_mb_cur_max (input) > 1 &&
       !re_string_first_byte (input, re_string_cur_idx (input)))
     {
       token->type = CHARACTER;
@@ -2246,7 +2255,7 @@ parse_expression (re_string_t *regexp, r
 	  return NULL;
 	}
 #ifdef RE_ENABLE_I18N
-      if (dfa->mb_cur_max > 1)
+      if (dfa_mb_cur_max (dfa) > 1)
 	{
 	  while (!re_string_eoi (regexp)
 		 && !re_string_first_byte (regexp, re_string_cur_idx (regexp)))
@@ -2384,7 +2393,7 @@ parse_expression (re_string_t *regexp, r
 	  *err = REG_ESPACE;
 	  return NULL;
 	}
-      if (dfa->mb_cur_max > 1)
+      if (dfa_mb_cur_max (dfa) > 1)
 	dfa->has_mb_node = 1;
       break;
     case OP_WORD:
@@ -2690,7 +2699,7 @@ build_range_exp (bitset_t sbcset, bracke
        However, for !_LIBC we have no collation elements: if the
        character set is single byte, the single byte character set
        that we build below suffices.  parse_bracket_exp passes
-       no MBCSET if dfa->mb_cur_max == 1.  */
+       no MBCSET if dfa_mb_cur_max (dfa) == 1.  */
     if (mbcset)
       {
 	/* Check the space of the arrays.  */
@@ -2786,7 +2795,13 @@ parse_bracket_exp (re_string_t *regexp,
 		   reg_syntax_t syntax, reg_errcode_t *err)
 {
 #ifdef _LIBC
+#if __OPTION_EGLIBC_LOCALE_CODE
   const unsigned char *collseqmb;
+# define COLLSEQMB_LOOKUP(ix) (collseqmb[(ix)])
+#else
+# define COLLSEQMB_LOOKUP(ix) (ix)
+#endif
+
   const char *collseqwc;
   uint32_t nrules;
   int32_t table_size;
@@ -2834,18 +2849,20 @@ parse_bracket_exp (re_string_t *regexp,
 	  if (MB_CUR_MAX == 1)
 	  */
 	  if (nrules == 0)
-	    return collseqmb[br_elem->opr.ch];
+	    return COLLSEQMB_LOOKUP (br_elem->opr.ch);
 	  else
 	    {
 	      wint_t wc = __btowc (br_elem->opr.ch);
 	      return __collseq_table_lookup (collseqwc, wc);
 	    }
 	}
+#if __OPTION_EGLIBC_LOCALE_CODE
       else if (br_elem->type == MB_CHAR)
 	{
 	  if (nrules != 0)
 	    return __collseq_table_lookup (collseqwc, br_elem->opr.wch);
 	}
+#endif
       else if (br_elem->type == COLL_SYM)
 	{
 	  size_t sym_name_len = strlen ((char *) br_elem->opr.name);
@@ -2876,11 +2893,11 @@ parse_bracket_exp (re_string_t *regexp,
 		{
 		  /* No valid character.  Match it as a single byte
 		     character.  */
-		  return collseqmb[br_elem->opr.name[0]];
+		  return COLLSEQMB_LOOKUP (br_elem->opr.name[0]);
 		}
 	    }
 	  else if (sym_name_len == 1)
-	    return collseqmb[br_elem->opr.name[0]];
+	    return COLLSEQMB_LOOKUP (br_elem->opr.name[0]);
 	}
       return UINT_MAX;
     }
@@ -2920,7 +2937,7 @@ parse_bracket_exp (re_string_t *regexp,
 	 However, if we have no collation elements, and the character set
 	 is single byte, the single byte character set that we
 	 build below suffices. */
-      if (nrules > 0 || dfa->mb_cur_max > 1)
+      if (nrules > 0 || dfa_mb_cur_max (dfa) > 1)
 	{
 	  /* Check the space of the arrays.  */
 	  if (BE (*range_alloc == mbcset->nranges, 0))
@@ -2957,7 +2974,7 @@ parse_bracket_exp (re_string_t *regexp,
 	  if (MB_CUR_MAX == 1)
 	  */
 	  if (nrules == 0)
-	    ch_collseq = collseqmb[ch];
+	    ch_collseq = COLLSEQMB_LOOKUP (ch);
 	  else
 	    ch_collseq = __collseq_table_lookup (collseqwc, __btowc (ch));
 	  if (start_collseq <= ch_collseq && ch_collseq <= end_collseq)
@@ -3035,7 +3052,10 @@ parse_bracket_exp (re_string_t *regexp,
   re_bitset_ptr_t sbcset;
 #ifdef RE_ENABLE_I18N
   re_charset_t *mbcset;
-  int coll_sym_alloc = 0, range_alloc = 0, mbchar_alloc = 0;
+  int coll_sym_alloc = 0, range_alloc = 0;
+#if __OPTION_EGLIBC_LOCALE_CODE
+  int mbchar_alloc = 0;
+#endif
   int equiv_class_alloc = 0, char_class_alloc = 0;
 #endif /* not RE_ENABLE_I18N */
   int non_match = 0;
@@ -3043,9 +3063,15 @@ parse_bracket_exp (re_string_t *regexp,
   int token_len;
   int first_round = 1;
 #ifdef _LIBC
+#if __OPTION_EGLIBC_LOCALE_CODE
   collseqmb = (const unsigned char *)
     _NL_CURRENT (LC_COLLATE, _NL_COLLATE_COLLSEQMB);
   nrules = _NL_CURRENT_WORD (LC_COLLATE, _NL_COLLATE_NRULES);
+#else
+  /* This is true when OPTION_EGLIBC_LOCALE_CODE is disabled, but the
+     compiler can't figure that out.  */
+  nrules = 0;
+#endif
   if (nrules)
     {
       /*
@@ -3175,7 +3201,7 @@ parse_bracket_exp (re_string_t *regexp,
 #else
 # ifdef RE_ENABLE_I18N
 	  *err = build_range_exp (sbcset,
-				  dfa->mb_cur_max > 1 ? mbcset : NULL,
+				  dfa_mb_cur_max (dfa) > 1 ? mbcset : NULL,
 				  &range_alloc, &start_elem, &end_elem);
 # else
 	  *err = build_range_exp (sbcset, &start_elem, &end_elem);
@@ -3191,7 +3217,7 @@ parse_bracket_exp (re_string_t *regexp,
 	    case SB_CHAR:
 	      bitset_set (sbcset, start_elem.opr.ch);
 	      break;
-#ifdef RE_ENABLE_I18N
+#if defined RE_ENABLE_I18N && __OPTION_EGLIBC_LOCALE_CODE
 	    case MB_CHAR:
 	      /* Check whether the array has enough space.  */
 	      if (BE (mbchar_alloc == mbcset->nmbchars, 0))
@@ -3209,7 +3235,7 @@ parse_bracket_exp (re_string_t *regexp,
 		}
 	      mbcset->mbchars[mbcset->nmbchars++] = start_elem.opr.wch;
 	      break;
-#endif /* RE_ENABLE_I18N */
+#endif /* RE_ENABLE_I18N && __OPTION_EGLIBC_LOCALE_CODE */
 	    case EQUIV_CLASS:
 	      *err = build_equiv_class (sbcset,
 #ifdef RE_ENABLE_I18N
@@ -3259,11 +3285,11 @@ parse_bracket_exp (re_string_t *regexp,
 
 #ifdef RE_ENABLE_I18N
   /* Ensure only single byte characters are set.  */
-  if (dfa->mb_cur_max > 1)
+  if (dfa_mb_cur_max (dfa) > 1)
     bitset_mask (sbcset, dfa->sb_char);
 
   if (mbcset->nmbchars || mbcset->ncoll_syms || mbcset->nequiv_classes
-      || mbcset->nranges || (dfa->mb_cur_max > 1 && (mbcset->nchar_classes
+      || mbcset->nranges || (dfa_mb_cur_max (dfa) > 1 && (mbcset->nchar_classes
 						     || mbcset->non_match)))
     {
       bin_tree_t *mbc_tree;
@@ -3332,7 +3358,7 @@ parse_bracket_element (bracket_elem_t *e
 		       re_token_t *token, int token_len, re_dfa_t *dfa,
 		       reg_syntax_t syntax, int accept_hyphen)
 {
-#ifdef RE_ENABLE_I18N
+#if defined RE_ENABLE_I18N && __OPTION_EGLIBC_LOCALE_CODE
   int cur_char_size;
   cur_char_size = re_string_char_size_at (regexp, re_string_cur_idx (regexp));
   if (cur_char_size > 1)
@@ -3342,7 +3368,7 @@ parse_bracket_element (bracket_elem_t *e
       re_string_skip_bytes (regexp, cur_char_size);
       return REG_NOERROR;
     }
-#endif /* RE_ENABLE_I18N */
+#endif /* RE_ENABLE_I18N && __OPTION_EGLIBC_LOCALE_CODE */
   re_string_skip_bytes (regexp, token_len); /* Skip a token.  */
   if (token->type == OP_OPEN_COLL_ELEM || token->type == OP_OPEN_CHAR_CLASS
       || token->type == OP_OPEN_EQUIV_CLASS)
@@ -3422,7 +3448,9 @@ build_equiv_class (bitset_t sbcset, re_c
 build_equiv_class (bitset_t sbcset, const unsigned char *name)
 #endif /* not RE_ENABLE_I18N */
 {
-#ifdef _LIBC
+  /* When __OPTION_EGLIBC_LOCALE_CODE is disabled, only the C locale
+     is supported; it has no collation rules.  */
+#if defined _LIBC && __OPTION_EGLIBC_LOCALE_CODE
   uint32_t nrules = _NL_CURRENT_WORD (LC_COLLATE, _NL_COLLATE_NRULES);
   if (nrules != 0)
     {
@@ -3492,7 +3520,7 @@ build_equiv_class (bitset_t sbcset, cons
       mbcset->equiv_classes[mbcset->nequiv_classes++] = idx1;
     }
   else
-#endif /* _LIBC */
+#endif /* _LIBC && __OPTION_EGLIBC_LOCALE_CODE */
     {
       if (BE (strlen ((const char *) name) != 1, 0))
 	return REG_ECOLLATE;
@@ -3526,7 +3554,7 @@ build_charclass (RE_TRANSLATE_TYPE trans
       && (strcmp (name, "upper") == 0 || strcmp (name, "lower") == 0))
     name = "alpha";
 
-#ifdef RE_ENABLE_I18N
+#if defined RE_ENABLE_I18N && __OPTION_EGLIBC_LOCALE_CODE
   /* Check the space of the arrays.  */
   if (BE (*char_class_alloc == mbcset->nchar_classes, 0))
     {
@@ -3542,7 +3570,7 @@ build_charclass (RE_TRANSLATE_TYPE trans
       *char_class_alloc = new_char_class_alloc;
     }
   mbcset->char_classes[mbcset->nchar_classes++] = __wctype (name);
-#endif /* RE_ENABLE_I18N */
+#endif /* RE_ENABLE_I18N && __OPTION_EGLIBC_LOCALE_CODE */
 
 #define BUILD_CHARCLASS_LOOP(ctype_func)	\
   do {						\
@@ -3653,7 +3681,7 @@ build_charclass_op (re_dfa_t *dfa, RE_TR
 
 #ifdef RE_ENABLE_I18N
   /* Ensure only single byte characters are set.  */
-  if (dfa->mb_cur_max > 1)
+  if (dfa_mb_cur_max (dfa) > 1)
     bitset_mask (sbcset, dfa->sb_char);
 #endif
 
@@ -3665,7 +3693,7 @@ build_charclass_op (re_dfa_t *dfa, RE_TR
     goto build_word_op_espace;
 
 #ifdef RE_ENABLE_I18N
-  if (dfa->mb_cur_max > 1)
+  if (dfa_mb_cur_max (dfa) > 1)
     {
       bin_tree_t *mbc_tree;
       /* Build a tree for complex bracket.  */
Index: git/posix/regexec.c
===================================================================
--- git.orig/posix/regexec.c
+++ git/posix/regexec.c
@@ -18,6 +18,7 @@
    <http://www.gnu.org/licenses/>.  */
 
 #include <stdint.h>
+#include <gnu/option-groups.h>
 
 static reg_errcode_t match_ctx_init (re_match_context_t *cache, int eflags,
 				     int n) internal_function;
@@ -186,11 +187,11 @@ static int build_trtable (const re_dfa_t
 static int check_node_accept_bytes (const re_dfa_t *dfa, int node_idx,
 				    const re_string_t *input, int idx)
      internal_function;
-# ifdef _LIBC
+# if defined _LIBC && __OPTION_EGLIBC_LOCALE_CODE
 static unsigned int find_collation_sequence_value (const unsigned char *mbs,
 						   size_t name_len)
      internal_function;
-# endif /* _LIBC */
+# endif /* _LIBC && __OPTION_EGLIBC_LOCALE_CODE */
 #endif /* RE_ENABLE_I18N */
 static int group_nodes_into_DFAstates (const re_dfa_t *dfa,
 				       const re_dfastate_t *state,
@@ -255,25 +256,9 @@ regexec (preg, string, nmatch, pmatch, e
   return err != REG_NOERROR;
 }
 
-#ifdef _LIBC
-# include <shlib-compat.h>
-versioned_symbol (libc, __regexec, regexec, GLIBC_2_3_4);
-
-# if SHLIB_COMPAT (libc, GLIBC_2_0, GLIBC_2_3_4)
-__typeof__ (__regexec) __compat_regexec;
-
-int
-attribute_compat_text_section
-__compat_regexec (const regex_t *__restrict preg,
-		  const char *__restrict string, size_t nmatch,
-		  regmatch_t pmatch[], int eflags)
-{
-  return regexec (preg, string, nmatch, pmatch,
-		  eflags & (REG_NOTBOL | REG_NOTEOL));
-}
-compat_symbol (libc, __compat_regexec, regexec, GLIBC_2_0);
-# endif
-#endif
+/* EGLIBC: The code that used to be here was move to a separate file
+   so that it can be shared with xregex.c.  */
+#include "regexec-compat.c"
 
 /* Entry points for GNU code.  */
 
@@ -728,7 +713,7 @@ re_search_internal (preg, string, length
   incr = (range < 0) ? -1 : 1;
   left_lim = (range < 0) ? start + range : start;
   right_lim = (range < 0) ? start : start + range;
-  sb = dfa->mb_cur_max == 1;
+  sb = dfa_mb_cur_max (dfa) == 1;
   match_kind =
     (fastmap
      ? ((sb || !(preg->syntax & RE_ICASE || t) ? 4 : 0)
@@ -3448,7 +3433,7 @@ out_free:
 	  if (BE (dest_states_word[i] == NULL && err != REG_NOERROR, 0))
 	    goto out_free;
 
-	  if (dest_states[i] != dest_states_word[i] && dfa->mb_cur_max > 1)
+	  if (dest_states[i] != dest_states_word[i] && dfa_mb_cur_max (dfa) > 1)
 	    need_word_trtable = 1;
 
 	  dest_states_nl[i] = re_acquire_state_context (&err, dfa, &follows,
@@ -3590,7 +3575,7 @@ group_nodes_into_DFAstates (const re_dfa
       else if (type == OP_PERIOD)
 	{
 #ifdef RE_ENABLE_I18N
-	  if (dfa->mb_cur_max > 1)
+	  if (dfa_mb_cur_max (dfa) > 1)
 	    bitset_merge (accepts, dfa->sb_char);
 	  else
 #endif
@@ -3641,7 +3626,7 @@ group_nodes_into_DFAstates (const re_dfa
 		  continue;
 		}
 #ifdef RE_ENABLE_I18N
-	      if (dfa->mb_cur_max > 1)
+	      if (dfa_mb_cur_max (dfa) > 1)
 		for (j = 0; j < BITSET_WORDS; ++j)
 		  any_set |= (accepts[j] &= (dfa->word_char[j] | ~dfa->sb_char[j]));
 	      else
@@ -3660,7 +3645,7 @@ group_nodes_into_DFAstates (const re_dfa
 		  continue;
 		}
 #ifdef RE_ENABLE_I18N
-	      if (dfa->mb_cur_max > 1)
+	      if (dfa_mb_cur_max (dfa) > 1)
 		for (j = 0; j < BITSET_WORDS; ++j)
 		  any_set |= (accepts[j] &= ~(dfa->word_char[j] & dfa->sb_char[j]));
 	      else
@@ -3836,12 +3821,6 @@ check_node_accept_bytes (const re_dfa_t
   if (node->type == COMPLEX_BRACKET)
     {
       const re_charset_t *cset = node->opr.mbcset;
-# ifdef _LIBC
-      const unsigned char *pin
-	= ((const unsigned char *) re_string_get_buffer (input) + str_idx);
-      int j;
-      uint32_t nrules;
-# endif /* _LIBC */
       int match_len = 0;
       wchar_t wc = ((cset->nranges || cset->nchar_classes || cset->nmbchars)
 		    ? re_string_wchar_at (input, str_idx) : 0);
@@ -3853,6 +3832,7 @@ check_node_accept_bytes (const re_dfa_t
 	    match_len = char_len;
 	    goto check_node_accept_bytes_match;
 	  }
+#if __OPTION_EGLIBC_LOCALE_CODE
       /* match with character_class?  */
       for (i = 0; i < cset->nchar_classes; ++i)
 	{
@@ -3863,14 +3843,22 @@ check_node_accept_bytes (const re_dfa_t
 	      goto check_node_accept_bytes_match;
 	    }
 	}
+#endif
+
+      /* When __OPTION_EGLIBC_LOCALE_CODE is disabled, only the C
+         locale is supported; it has no collation rules.  */
+# if defined _LIBC && __OPTION_EGLIBC_LOCALE_CODE
+      const unsigned char *pin
+	= ((const unsigned char *) re_string_get_buffer (input) + str_idx);
+      int j;
+      uint32_t nrules;
 
-# ifdef _LIBC
       nrules = _NL_CURRENT_WORD (LC_COLLATE, _NL_COLLATE_NRULES);
       if (nrules != 0)
 	{
 	  unsigned int in_collseq = 0;
 	  const int32_t *table, *indirect;
-	  const unsigned char *weights, *extra;
+	  const unsigned char *weights, *extra = NULL;
 	  const char *collseqwc;
 
 	  /* match with collating_symbol?  */
@@ -3955,8 +3943,12 @@ check_node_accept_bytes (const re_dfa_t
 	    }
 	}
       else
-# endif /* _LIBC */
+# endif /* _LIBC && __OPTION_EGLIBC_LOCALE_CODE */
 	{
+          /* In the _LIBC version, if OPTION_EGLIBC_LOCALE_CODE is
+             disabled, there can be no multibyte range endpoints, and
+             cset->nranges is always zero.  */
+#if __OPTION_EGLIBC_LOCALE_CODE
 	  /* match with range expression?  */
 #if __GNUC__ >= 2
 	  wchar_t cmp_buf[] = {L'\0', L'\0', wc, L'\0', L'\0', L'\0'};
@@ -3975,6 +3967,7 @@ check_node_accept_bytes (const re_dfa_t
 		  goto check_node_accept_bytes_match;
 		}
 	    }
+#endif /* __OPTION_EGLIBC_LOCALE_CODE */
 	}
     check_node_accept_bytes_match:
       if (!cset->non_match)
@@ -3990,7 +3983,7 @@ check_node_accept_bytes (const re_dfa_t
   return 0;
 }
 
-# ifdef _LIBC
+# if defined _LIBC && __OPTION_EGLIBC_LOCALE_CODE
 static unsigned int
 internal_function
 find_collation_sequence_value (const unsigned char *mbs, size_t mbs_len)
@@ -4048,7 +4041,7 @@ find_collation_sequence_value (const uns
       return UINT_MAX;
     }
 }
-# endif /* _LIBC */
+# endif /* _LIBC && __OPTION_EGLIBC_LOCALE_CODE */
 #endif /* RE_ENABLE_I18N */
 
 /* Check whether the node accepts the byte which is IDX-th
@@ -4139,7 +4132,7 @@ extend_buffers (re_match_context_t *mctx
   if (pstr->icase)
     {
 #ifdef RE_ENABLE_I18N
-      if (pstr->mb_cur_max > 1)
+      if (string_mb_cur_max (pstr) > 1)
 	{
 	  ret = build_wcs_upper_buffer (pstr);
 	  if (BE (ret != REG_NOERROR, 0))
@@ -4152,7 +4145,7 @@ extend_buffers (re_match_context_t *mctx
   else
     {
 #ifdef RE_ENABLE_I18N
-      if (pstr->mb_cur_max > 1)
+      if (string_mb_cur_max (pstr) > 1)
 	build_wcs_buffer (pstr);
       else
 #endif /* RE_ENABLE_I18N  */
Index: git/posix/regexec-compat.c
===================================================================
--- /dev/null
+++ git/posix/regexec-compat.c
@@ -0,0 +1,39 @@
+/* Extended regular expression matching and search library.
+   Copyright (C) 2008 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+   Contributed by Isamu Hasegawa <isamu@yamato.ibm.com>.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 2.1 of the License, or (at your option) any later version.
+
+   The GNU C Library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with the GNU C Library; if not, write to the Free
+   Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+   02111-1307 USA.  */
+
+#ifdef _LIBC
+# include <shlib-compat.h>
+versioned_symbol (libc, __regexec, regexec, GLIBC_2_3_4);
+
+# if SHLIB_COMPAT (libc, GLIBC_2_0, GLIBC_2_3_4)
+__typeof__ (__regexec) __compat_regexec;
+
+int
+attribute_compat_text_section
+__compat_regexec (const regex_t *__restrict preg,
+		  const char *__restrict string, size_t nmatch,
+		  regmatch_t pmatch[], int eflags)
+{
+  return regexec (preg, string, nmatch, pmatch,
+		  eflags & (REG_NOTBOL | REG_NOTEOL));
+}
+compat_symbol (libc, __compat_regexec, regexec, GLIBC_2_0);
+# endif
+#endif
Index: git/posix/regex.h
===================================================================
--- git.orig/posix/regex.h
+++ git/posix/regex.h
@@ -21,6 +21,7 @@
 #define _REGEX_H 1
 
 #include <sys/types.h>
+#include <gnu/option-groups.h>
 
 /* Allow the use in C++ code.  */
 #ifdef __cplusplus
@@ -156,6 +157,8 @@ typedef unsigned long int reg_syntax_t;
    treated as 'a\{1'.  */
 # define RE_INVALID_INTERVAL_ORD (RE_DEBUG << 1)
 
+/* EGLIBC: Old regex implementation does not support these.  */
+# if __OPTION_POSIX_REGEXP_GLIBC
 /* If this bit is set, then ignore case when matching.
    If not set, then case is significant.  */
 # define RE_ICASE (RE_INVALID_INTERVAL_ORD << 1)
@@ -172,6 +175,7 @@ typedef unsigned long int reg_syntax_t;
 /* If this bit is set, then no_sub will be set to 1 during
    re_compile_pattern.  */
 # define RE_NO_SUB (RE_CONTEXT_INVALID_DUP << 1)
+# endif /* __OPTION_POSIX_REGEXP_GLIBC */
 #endif
 
 /* This global variable defines the particular regexp syntax to use (for
@@ -231,8 +235,13 @@ extern reg_syntax_t re_syntax_options;
   (RE_CHAR_CLASSES | RE_DOT_NEWLINE      | RE_DOT_NOT_NULL		\
    | RE_INTERVALS  | RE_NO_EMPTY_RANGES)
 
+#if __OPTION_POSIX_REGEXP_GLIBC
 #define RE_SYNTAX_POSIX_BASIC						\
   (_RE_SYNTAX_POSIX_COMMON | RE_BK_PLUS_QM | RE_CONTEXT_INVALID_DUP)
+#else
+#define RE_SYNTAX_POSIX_BASIC						\
+  (_RE_SYNTAX_POSIX_COMMON | RE_BK_PLUS_QM)
+#endif
 
 /* Differs from ..._POSIX_BASIC only in that RE_BK_PLUS_QM becomes
    RE_LIMITED_OPS, i.e., \? \+ \| are not recognized.  Actually, this
@@ -298,9 +307,11 @@ extern reg_syntax_t re_syntax_options;
 /* Like REG_NOTBOL, except for the end-of-line.  */
 #define REG_NOTEOL (1 << 1)
 
+#if __OPTION_POSIX_REGEXP_GLIBC
 /* Use PMATCH[0] to delimit the start and end of the search in the
    buffer.  */
 #define REG_STARTEND (1 << 2)
+#endif
 
 
 /* If any error codes are removed, changed, or added, update the
Index: git/posix/regex_internal.c
===================================================================
--- git.orig/posix/regex_internal.c
+++ git/posix/regex_internal.c
@@ -43,8 +43,8 @@ re_string_allocate (re_string_t *pstr, c
   int init_buf_len;
 
   /* Ensure at least one character fits into the buffers.  */
-  if (init_len < dfa->mb_cur_max)
-    init_len = dfa->mb_cur_max;
+  if (init_len < dfa_mb_cur_max (dfa))
+    init_len = dfa_mb_cur_max (dfa);
   init_buf_len = (len + 1 < init_len) ? len + 1: init_len;
   re_string_construct_common (str, len, pstr, trans, icase, dfa);
 
@@ -55,7 +55,7 @@ re_string_allocate (re_string_t *pstr, c
   pstr->word_char = dfa->word_char;
   pstr->word_ops_used = dfa->word_ops_used;
   pstr->mbs = pstr->mbs_allocated ? pstr->mbs : (unsigned char *) str;
-  pstr->valid_len = (pstr->mbs_allocated || dfa->mb_cur_max > 1) ? 0 : len;
+  pstr->valid_len = (pstr->mbs_allocated || dfa_mb_cur_max (dfa) > 1) ? 0 : len;
   pstr->valid_raw_len = pstr->valid_len;
   return REG_NOERROR;
 }
@@ -82,7 +82,7 @@ re_string_construct (re_string_t *pstr,
   if (icase)
     {
 #ifdef RE_ENABLE_I18N
-      if (dfa->mb_cur_max > 1)
+      if (dfa_mb_cur_max (dfa) > 1)
 	{
 	  while (1)
 	    {
@@ -91,7 +91,7 @@ re_string_construct (re_string_t *pstr,
 		return ret;
 	      if (pstr->valid_raw_len >= len)
 		break;
-	      if (pstr->bufs_len > pstr->valid_len + dfa->mb_cur_max)
+	      if (pstr->bufs_len > pstr->valid_len + dfa_mb_cur_max (dfa))
 		break;
 	      ret = re_string_realloc_buffers (pstr, pstr->bufs_len * 2);
 	      if (BE (ret != REG_NOERROR, 0))
@@ -105,7 +105,7 @@ re_string_construct (re_string_t *pstr,
   else
     {
 #ifdef RE_ENABLE_I18N
-      if (dfa->mb_cur_max > 1)
+      if (dfa_mb_cur_max (dfa) > 1)
 	build_wcs_buffer (pstr);
       else
 #endif /* RE_ENABLE_I18N  */
@@ -130,7 +130,7 @@ internal_function __attribute_warn_unuse
 re_string_realloc_buffers (re_string_t *pstr, int new_buf_len)
 {
 #ifdef RE_ENABLE_I18N
-  if (pstr->mb_cur_max > 1)
+  if (string_mb_cur_max (pstr) > 1)
     {
       wint_t *new_wcs;
 
@@ -177,7 +177,7 @@ re_string_construct_common (const char *
   pstr->trans = trans;
   pstr->icase = icase ? 1 : 0;
   pstr->mbs_allocated = (trans != NULL || icase);
-  pstr->mb_cur_max = dfa->mb_cur_max;
+  pstr->mb_cur_max = dfa_mb_cur_max (dfa);
   pstr->is_utf8 = dfa->is_utf8;
   pstr->map_notascii = dfa->map_notascii;
   pstr->stop = pstr->len;
@@ -203,7 +203,7 @@ build_wcs_buffer (re_string_t *pstr)
 {
 #ifdef _LIBC
   unsigned char buf[MB_LEN_MAX];
-  assert (MB_LEN_MAX >= pstr->mb_cur_max);
+  assert (MB_LEN_MAX >= string_mb_cur_max (pstr));
 #else
   unsigned char buf[64];
 #endif
@@ -226,7 +226,7 @@ build_wcs_buffer (re_string_t *pstr)
 	{
 	  int i, ch;
 
-	  for (i = 0; i < pstr->mb_cur_max && i < remain_len; ++i)
+	  for (i = 0; i < string_mb_cur_max (pstr) && i < remain_len; ++i)
 	    {
 	      ch = pstr->raw_mbs [pstr->raw_mbs_idx + byte_idx + i];
 	      buf[i] = pstr->mbs[byte_idx + i] = pstr->trans[ch];
@@ -275,7 +275,7 @@ build_wcs_upper_buffer (re_string_t *pst
   size_t mbclen;
 #ifdef _LIBC
   char buf[MB_LEN_MAX];
-  assert (MB_LEN_MAX >= pstr->mb_cur_max);
+  assert (MB_LEN_MAX >= string_mb_cur_max (pstr));
 #else
   char buf[64];
 #endif
@@ -369,7 +369,7 @@ build_wcs_upper_buffer (re_string_t *pst
 	  {
 	    int i, ch;
 
-	    for (i = 0; i < pstr->mb_cur_max && i < remain_len; ++i)
+	    for (i = 0; i < string_mb_cur_max (pstr) && i < remain_len; ++i)
 	      {
 		ch = pstr->raw_mbs [pstr->raw_mbs_idx + src_idx + i];
 		buf[i] = pstr->trans[ch];
@@ -567,8 +567,9 @@ re_string_translate_buffer (re_string_t
 }
 
 /* This function re-construct the buffers.
-   Concretely, convert to wide character in case of pstr->mb_cur_max > 1,
-   convert to upper case in case of REG_ICASE, apply translation.  */
+   Concretely, convert to wide character in case of
+   string_mb_cur_max (pstr) > 1, convert to upper case in case of
+   REG_ICASE, apply translation.  */
 
 static reg_errcode_t
 internal_function __attribute_warn_unused_result__
@@ -579,7 +580,7 @@ re_string_reconstruct (re_string_t *pstr
     {
       /* Reset buffer.  */
 #ifdef RE_ENABLE_I18N
-      if (pstr->mb_cur_max > 1)
+      if (string_mb_cur_max (pstr) > 1)
 	memset (&pstr->cur_state, '\0', sizeof (mbstate_t));
 #endif /* RE_ENABLE_I18N */
       pstr->len = pstr->raw_len;
@@ -670,7 +671,7 @@ re_string_reconstruct (re_string_t *pstr
 	      pstr->tip_context = re_string_context_at (pstr, offset - 1,
 							eflags);
 #ifdef RE_ENABLE_I18N
-	      if (pstr->mb_cur_max > 1)
+	      if (string_mb_cur_max (pstr) > 1)
 		memmove (pstr->wcs, pstr->wcs + offset,
 			 (pstr->valid_len - offset) * sizeof (wint_t));
 #endif /* RE_ENABLE_I18N */
@@ -699,7 +700,7 @@ re_string_reconstruct (re_string_t *pstr
 #endif
 	  pstr->valid_len = 0;
 #ifdef RE_ENABLE_I18N
-	  if (pstr->mb_cur_max > 1)
+	  if (string_mb_cur_max (pstr) > 1)
 	    {
 	      int wcs_idx;
 	      wint_t wc = WEOF;
@@ -711,7 +712,7 @@ re_string_reconstruct (re_string_t *pstr
 		  /* Special case UTF-8.  Multi-byte chars start with any
 		     byte other than 0x80 - 0xbf.  */
 		  raw = pstr->raw_mbs + pstr->raw_mbs_idx;
-		  end = raw + (offset - pstr->mb_cur_max);
+		  end = raw + (offset - string_mb_cur_max (pstr));
 		  if (end < pstr->raw_mbs)
 		    end = pstr->raw_mbs;
 		  p = raw + offset - 1;
@@ -803,7 +804,7 @@ re_string_reconstruct (re_string_t *pstr
 
   /* Then build the buffers.  */
 #ifdef RE_ENABLE_I18N
-  if (pstr->mb_cur_max > 1)
+  if (string_mb_cur_max (pstr) > 1)
     {
       if (pstr->icase)
 	{
@@ -841,7 +842,7 @@ re_string_peek_byte_case (const re_strin
     return re_string_peek_byte (pstr, idx);
 
 #ifdef RE_ENABLE_I18N
-  if (pstr->mb_cur_max > 1
+  if (string_mb_cur_max (pstr) > 1
       && ! re_string_is_single_byte_char (pstr, pstr->cur_idx + idx))
     return re_string_peek_byte (pstr, idx);
 #endif
@@ -930,7 +931,7 @@ re_string_context_at (const re_string_t
     return ((eflags & REG_NOTEOL) ? CONTEXT_ENDBUF
 	    : CONTEXT_NEWLINE | CONTEXT_ENDBUF);
 #ifdef RE_ENABLE_I18N
-  if (input->mb_cur_max > 1)
+  if (string_mb_cur_max (input) > 1)
     {
       wint_t wc;
       int wc_idx = idx;
@@ -1444,7 +1445,7 @@ re_dfa_add_node (re_dfa_t *dfa, re_token
   dfa->nodes[dfa->nodes_len].constraint = 0;
 #ifdef RE_ENABLE_I18N
   dfa->nodes[dfa->nodes_len].accept_mb =
-    (type == OP_PERIOD && dfa->mb_cur_max > 1) || type == COMPLEX_BRACKET;
+    (type == OP_PERIOD && dfa_mb_cur_max (dfa) > 1) || type == COMPLEX_BRACKET;
 #endif
   dfa->nexts[dfa->nodes_len] = -1;
   re_node_set_init_empty (dfa->edests + dfa->nodes_len);
Index: git/posix/regex_internal.h
===================================================================
--- git.orig/posix/regex_internal.h
+++ git/posix/regex_internal.h
@@ -26,6 +26,10 @@
 #include <stdlib.h>
 #include <string.h>
 
+#if defined _LIBC
+# include <gnu/option-groups.h>
+#endif
+
 #if defined HAVE_LANGINFO_H || defined HAVE_LANGINFO_CODESET || defined _LIBC
 # include <langinfo.h>
 #endif
@@ -369,6 +373,13 @@ struct re_string_t
 };
 typedef struct re_string_t re_string_t;
 
+/* When OPTION_EGLIBC_LOCALE_CODE is disabled, this is always 1;
+   help the compiler make use of that fact.  */
+#if __OPTION_EGLIBC_LOCALE_CODE
+# define string_mb_cur_max(str) ((str)->mb_cur_max + 0)
+#else
+# define string_mb_cur_max(str) (1)
+#endif
 
 struct re_dfa_t;
 typedef struct re_dfa_t re_dfa_t;
@@ -654,6 +665,14 @@ struct re_dfa_t
   __libc_lock_define (, lock)
 };
 
+/* When OPTION_EGLIBC_LOCALE_CODE is disabled, this is always 1;
+   help the compiler make use of that fact.  */
+#if __OPTION_EGLIBC_LOCALE_CODE
+# define dfa_mb_cur_max(dfa) ((dfa)->mb_cur_max + 0)
+#else
+# define dfa_mb_cur_max(dfa) (1)
+#endif
+
 #define re_node_set_init_empty(set) memset (set, '\0', sizeof (re_node_set))
 #define re_node_set_remove(set,id) \
   (re_node_set_remove_at (set, re_node_set_contains (set, id) - 1))
@@ -714,7 +733,7 @@ internal_function __attribute__ ((pure,
 re_string_char_size_at (const re_string_t *pstr, int idx)
 {
   int byte_idx;
-  if (pstr->mb_cur_max == 1)
+  if (string_mb_cur_max (pstr) == 1)
     return 1;
   for (byte_idx = 1; idx + byte_idx < pstr->valid_len; ++byte_idx)
     if (pstr->wcs[idx + byte_idx] != WEOF)
@@ -726,7 +745,7 @@ static wint_t
 internal_function __attribute__ ((pure, unused))
 re_string_wchar_at (const re_string_t *pstr, int idx)
 {
-  if (pstr->mb_cur_max == 1)
+  if (string_mb_cur_max (pstr) == 1)
     return (wint_t) pstr->mbs[idx];
   return (wint_t) pstr->wcs[idx];
 }
Index: git/posix/xregex.c
===================================================================
--- /dev/null
+++ git/posix/xregex.c
@@ -0,0 +1,8215 @@
+/* Extended regular expression matching and search library,
+   version 0.12.
+   (Implements POSIX draft P1003.2/D11.2, except for some of the
+   internationalization features.)
+
+   Copyright (C) 1993, 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001,
+   2002, 2005 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 2.1 of the License, or (at your option) any later version.
+
+   The GNU C Library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with the GNU C Library; if not, write to the Free
+   Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+   02110-1301 USA.  */
+
+/* AIX requires this to be the first thing in the file. */
+#if defined _AIX && !defined __GNUC__ && !defined REGEX_MALLOC
+  #pragma alloca
+#endif
+
+#undef	_GNU_SOURCE
+#define _GNU_SOURCE
+
+#ifndef INSIDE_RECURSION
+# ifdef HAVE_CONFIG_H
+#  include <config.h>
+# endif
+#endif
+
+/*#include <ansidecl.h>*/
+
+
+#ifndef INSIDE_RECURSION
+
+# if defined STDC_HEADERS && !defined emacs
+#  include <stddef.h>
+# else
+/* We need this for `regex.h', and perhaps for the Emacs include files.  */
+#  include <sys/types.h>
+# endif
+
+# if (defined HAVE_WCTYPE_H && defined HAVE_WCHAR_H && defined HAVE_BTOWC)
+#  define WIDE_CHAR_SUPPORT (HAVE_WCTYPE_H && HAVE_WCHAR_H && HAVE_BTOWC)
+# else
+#  define WIDE_CHAR_SUPPORT 0
+# endif
+/* For platform which support the ISO C amendement 1 functionality we
+   support user defined character classes.  */
+# if WIDE_CHAR_SUPPORT
+/* Solaris 2.5 has a bug: <wchar.h> must be included before <wctype.h>.  */
+#  include <wchar.h>
+#  include <wctype.h>
+# endif
+
+# ifdef _LIBC
+/* We have to keep the namespace clean.  */
+#  define regfree(preg) __regfree (preg)
+#  define regexec(pr, st, nm, pm, ef) __regexec (pr, st, nm, pm, ef)
+#  define regcomp(preg, pattern, cflags) __regcomp (preg, pattern, cflags)
+#  define regerror(errcode, preg, errbuf, errbuf_size) \
+	__regerror(errcode, preg, errbuf, errbuf_size)
+#  define re_set_registers(bu, re, nu, st, en) \
+	__re_set_registers (bu, re, nu, st, en)
+#  define re_match_2(bufp, string1, size1, string2, size2, pos, regs, stop) \
+	__re_match_2 (bufp, string1, size1, string2, size2, pos, regs, stop)
+#  define re_match(bufp, string, size, pos, regs) \
+	__re_match (bufp, string, size, pos, regs)
+#  define re_search(bufp, string, size, startpos, range, regs) \
+	__re_search (bufp, string, size, startpos, range, regs)
+#  define re_compile_pattern(pattern, length, bufp) \
+	__re_compile_pattern (pattern, length, bufp)
+#  define re_set_syntax(syntax) __re_set_syntax (syntax)
+#  define re_search_2(bufp, st1, s1, st2, s2, startpos, range, regs, stop) \
+	__re_search_2 (bufp, st1, s1, st2, s2, startpos, range, regs, stop)
+#  define re_compile_fastmap(bufp) __re_compile_fastmap (bufp)
+
+#  define btowc __btowc
+
+/* We are also using some library internals.  */
+#  include <locale/localeinfo.h>
+#  include <locale/elem-hash.h>
+#  include <langinfo.h>
+#  include <locale/coll-lookup.h>
+# endif
+
+/* This is for other GNU distributions with internationalized messages.  */
+# if (HAVE_LIBINTL_H && ENABLE_NLS) || defined _LIBC
+#  include <libintl.h>
+#  ifdef _LIBC
+#   undef gettext
+#   define gettext(msgid) __dcgettext ("libc", msgid, LC_MESSAGES)
+#  endif
+# else
+#  define gettext(msgid) (msgid)
+# endif
+
+# ifndef gettext_noop
+/* This define is so xgettext can find the internationalizable
+   strings.  */
+#  define gettext_noop(String) String
+# endif
+
+/* The `emacs' switch turns on certain matching commands
+   that make sense only in Emacs. */
+# ifdef emacs
+
+#  include "lisp.h"
+#  include "buffer.h"
+#  include "syntax.h"
+
+# else  /* not emacs */
+
+/* If we are not linking with Emacs proper,
+   we can't use the relocating allocator
+   even if config.h says that we can.  */
+#  undef REL_ALLOC
+
+#  if defined STDC_HEADERS || defined _LIBC
+#   include <stdlib.h>
+#  else
+char *malloc ();
+char *realloc ();
+#  endif
+
+/* When used in Emacs's lib-src, we need to get bzero and bcopy somehow.
+   If nothing else has been done, use the method below.  */
+#  ifdef INHIBIT_STRING_HEADER
+#   if !(defined HAVE_BZERO && defined HAVE_BCOPY)
+#    if !defined bzero && !defined bcopy
+#     undef INHIBIT_STRING_HEADER
+#    endif
+#   endif
+#  endif
+
+/* This is the normal way of making sure we have a bcopy and a bzero.
+   This is used in most programs--a few other programs avoid this
+   by defining INHIBIT_STRING_HEADER.  */
+#  ifndef INHIBIT_STRING_HEADER
+#   if defined HAVE_STRING_H || defined STDC_HEADERS || defined _LIBC
+#    include <string.h>
+#    ifndef bzero
+#     ifndef _LIBC
+#      define bzero(s, n)	(memset (s, '\0', n), (s))
+#     else
+#      define bzero(s, n)	__bzero (s, n)
+#     endif
+#    endif
+#   else
+#    include <strings.h>
+#    ifndef memcmp
+#     define memcmp(s1, s2, n)	bcmp (s1, s2, n)
+#    endif
+#    ifndef memcpy
+#     define memcpy(d, s, n)	(bcopy (s, d, n), (d))
+#    endif
+#   endif
+#  endif
+
+/* Define the syntax stuff for \<, \>, etc.  */
+
+/* This must be nonzero for the wordchar and notwordchar pattern
+   commands in re_match_2.  */
+#  ifndef Sword
+#   define Sword 1
+#  endif
+
+#  ifdef SWITCH_ENUM_BUG
+#   define SWITCH_ENUM_CAST(x) ((int)(x))
+#  else
+#   define SWITCH_ENUM_CAST(x) (x)
+#  endif
+
+# endif /* not emacs */
+
+# if defined _LIBC || HAVE_LIMITS_H
+#  include <limits.h>
+# endif
+
+# ifndef MB_LEN_MAX
+#  define MB_LEN_MAX 1
+# endif
+
+/* Get the interface, including the syntax bits.  */
+# include "regex.h"
+
+/* isalpha etc. are used for the character classes.  */
+# include <ctype.h>
+
+/* Jim Meyering writes:
+
+   "... Some ctype macros are valid only for character codes that
+   isascii says are ASCII (SGI's IRIX-4.0.5 is one such system --when
+   using /bin/cc or gcc but without giving an ansi option).  So, all
+   ctype uses should be through macros like ISPRINT...  If
+   STDC_HEADERS is defined, then autoconf has verified that the ctype
+   macros don't need to be guarded with references to isascii. ...
+   Defining isascii to 1 should let any compiler worth its salt
+   eliminate the && through constant folding."
+   Solaris defines some of these symbols so we must undefine them first.  */
+
+# undef ISASCII
+# if defined STDC_HEADERS || (!defined isascii && !defined HAVE_ISASCII)
+#  define ISASCII(c) 1
+# else
+#  define ISASCII(c) isascii(c)
+# endif
+
+# ifdef isblank
+#  define ISBLANK(c) (ISASCII (c) && isblank (c))
+# else
+#  define ISBLANK(c) ((c) == ' ' || (c) == '\t')
+# endif
+# ifdef isgraph
+#  define ISGRAPH(c) (ISASCII (c) && isgraph (c))
+# else
+#  define ISGRAPH(c) (ISASCII (c) && isprint (c) && !isspace (c))
+# endif
+
+# undef ISPRINT
+# define ISPRINT(c) (ISASCII (c) && isprint (c))
+# define ISDIGIT(c) (ISASCII (c) && isdigit (c))
+# define ISALNUM(c) (ISASCII (c) && isalnum (c))
+# define ISALPHA(c) (ISASCII (c) && isalpha (c))
+# define ISCNTRL(c) (ISASCII (c) && iscntrl (c))
+# define ISLOWER(c) (ISASCII (c) && islower (c))
+# define ISPUNCT(c) (ISASCII (c) && ispunct (c))
+# define ISSPACE(c) (ISASCII (c) && isspace (c))
+# define ISUPPER(c) (ISASCII (c) && isupper (c))
+# define ISXDIGIT(c) (ISASCII (c) && isxdigit (c))
+
+# ifdef _tolower
+#  define TOLOWER(c) _tolower(c)
+# else
+#  define TOLOWER(c) tolower(c)
+# endif
+
+# ifndef NULL
+#  define NULL (void *)0
+# endif
+
+/* We remove any previous definition of `SIGN_EXTEND_CHAR',
+   since ours (we hope) works properly with all combinations of
+   machines, compilers, `char' and `unsigned char' argument types.
+   (Per Bothner suggested the basic approach.)  */
+# undef SIGN_EXTEND_CHAR
+# if __STDC__
+#  define SIGN_EXTEND_CHAR(c) ((signed char) (c))
+# else  /* not __STDC__ */
+/* As in Harbison and Steele.  */
+#  define SIGN_EXTEND_CHAR(c) ((((unsigned char) (c)) ^ 128) - 128)
+# endif
+
+# ifndef emacs
+/* How many characters in the character set.  */
+#  define CHAR_SET_SIZE 256
+
+#  ifdef SYNTAX_TABLE
+
+extern char *re_syntax_table;
+
+#  else /* not SYNTAX_TABLE */
+
+static char re_syntax_table[CHAR_SET_SIZE];
+
+static void init_syntax_once (void);
+
+static void
+init_syntax_once (void)
+{
+   register int c;
+   static int done = 0;
+
+   if (done)
+     return;
+   bzero (re_syntax_table, sizeof re_syntax_table);
+
+   for (c = 0; c < CHAR_SET_SIZE; ++c)
+     if (ISALNUM (c))
+	re_syntax_table[c] = Sword;
+
+   re_syntax_table['_'] = Sword;
+
+   done = 1;
+}
+
+#  endif /* not SYNTAX_TABLE */
+
+#  define SYNTAX(c) re_syntax_table[(unsigned char) (c)]
+
+# endif /* emacs */
+
+/* Integer type for pointers.  */
+# if !defined _LIBC && !defined HAVE_UINTPTR_T
+typedef unsigned long int uintptr_t;
+# endif
+
+/* Should we use malloc or alloca?  If REGEX_MALLOC is not defined, we
+   use `alloca' instead of `malloc'.  This is because using malloc in
+   re_search* or re_match* could cause memory leaks when C-g is used in
+   Emacs; also, malloc is slower and causes storage fragmentation.  On
+   the other hand, malloc is more portable, and easier to debug.
+
+   Because we sometimes use alloca, some routines have to be macros,
+   not functions -- `alloca'-allocated space disappears at the end of the
+   function it is called in.  */
+
+# ifdef REGEX_MALLOC
+
+#  define REGEX_ALLOCATE malloc
+#  define REGEX_REALLOCATE(source, osize, nsize) realloc (source, nsize)
+#  define REGEX_FREE free
+
+# else /* not REGEX_MALLOC  */
+
+/* Emacs already defines alloca, sometimes.  */
+#  ifndef alloca
+
+/* Make alloca work the best possible way.  */
+#   ifdef __GNUC__
+#    define alloca __builtin_alloca
+#   else /* not __GNUC__ */
+#    if HAVE_ALLOCA_H
+#     include <alloca.h>
+#    endif /* HAVE_ALLOCA_H */
+#   endif /* not __GNUC__ */
+
+#  endif /* not alloca */
+
+#  define REGEX_ALLOCATE alloca
+
+/* Assumes a `char *destination' variable.  */
+#  define REGEX_REALLOCATE(source, osize, nsize)			\
+  (destination = (char *) alloca (nsize),				\
+   memcpy (destination, source, osize))
+
+/* No need to do anything to free, after alloca.  */
+#  define REGEX_FREE(arg) ((void)0) /* Do nothing!  But inhibit gcc warning.  */
+
+# endif /* not REGEX_MALLOC */
+
+/* Define how to allocate the failure stack.  */
+
+# if defined REL_ALLOC && defined REGEX_MALLOC
+
+#  define REGEX_ALLOCATE_STACK(size)				\
+  r_alloc (&failure_stack_ptr, (size))
+#  define REGEX_REALLOCATE_STACK(source, osize, nsize)		\
+  r_re_alloc (&failure_stack_ptr, (nsize))
+#  define REGEX_FREE_STACK(ptr)					\
+  r_alloc_free (&failure_stack_ptr)
+
+# else /* not using relocating allocator */
+
+#  ifdef REGEX_MALLOC
+
+#   define REGEX_ALLOCATE_STACK malloc
+#   define REGEX_REALLOCATE_STACK(source, osize, nsize) realloc (source, nsize)
+#   define REGEX_FREE_STACK free
+
+#  else /* not REGEX_MALLOC */
+
+#   define REGEX_ALLOCATE_STACK alloca
+
+#   define REGEX_REALLOCATE_STACK(source, osize, nsize)			\
+   REGEX_REALLOCATE (source, osize, nsize)
+/* No need to explicitly free anything.  */
+#   define REGEX_FREE_STACK(arg)
+
+#  endif /* not REGEX_MALLOC */
+# endif /* not using relocating allocator */
+
+
+/* True if `size1' is non-NULL and PTR is pointing anywhere inside
+   `string1' or just past its end.  This works if PTR is NULL, which is
+   a good thing.  */
+# define FIRST_STRING_P(ptr) 					\
+  (size1 && string1 <= (ptr) && (ptr) <= string1 + size1)
+
+/* (Re)Allocate N items of type T using malloc, or fail.  */
+# define TALLOC(n, t) ((t *) malloc ((n) * sizeof (t)))
+# define RETALLOC(addr, n, t) ((addr) = (t *) realloc (addr, (n) * sizeof (t)))
+# define RETALLOC_IF(addr, n, t) \
+  if (addr) RETALLOC((addr), (n), t); else (addr) = TALLOC ((n), t)
+# define REGEX_TALLOC(n, t) ((t *) REGEX_ALLOCATE ((n) * sizeof (t)))
+
+# define BYTEWIDTH 8 /* In bits.  */
+
+# define STREQ(s1, s2) ((strcmp (s1, s2) == 0))
+
+# undef MAX
+# undef MIN
+# define MAX(a, b) ((a) > (b) ? (a) : (b))
+# define MIN(a, b) ((a) < (b) ? (a) : (b))
+
+typedef char boolean;
+# define false 0
+# define true 1
+
+static reg_errcode_t byte_regex_compile (const char *pattern, size_t size,
+                                         reg_syntax_t syntax,
+                                         struct re_pattern_buffer *bufp);
+
+static int byte_re_match_2_internal (struct re_pattern_buffer *bufp,
+                                     const char *string1, int size1,
+                                     const char *string2, int size2,
+                                     int pos,
+                                     struct re_registers *regs,
+                                     int stop);
+static int byte_re_search_2 (struct re_pattern_buffer *bufp,
+                             const char *string1, int size1,
+                             const char *string2, int size2,
+                             int startpos, int range,
+                             struct re_registers *regs, int stop);
+static int byte_re_compile_fastmap (struct re_pattern_buffer *bufp);
+
+#ifdef MBS_SUPPORT
+static reg_errcode_t wcs_regex_compile (const char *pattern, size_t size,
+                                        reg_syntax_t syntax,
+                                        struct re_pattern_buffer *bufp);
+
+
+static int wcs_re_match_2_internal (struct re_pattern_buffer *bufp,
+                                    const char *cstring1, int csize1,
+                                    const char *cstring2, int csize2,
+                                    int pos,
+                                    struct re_registers *regs,
+                                    int stop,
+                                    wchar_t *string1, int size1,
+                                    wchar_t *string2, int size2,
+                                    int *mbs_offset1, int *mbs_offset2);
+static int wcs_re_search_2 (struct re_pattern_buffer *bufp,
+                            const char *string1, int size1,
+                            const char *string2, int size2,
+                            int startpos, int range,
+                            struct re_registers *regs, int stop);
+static int wcs_re_compile_fastmap (struct re_pattern_buffer *bufp);
+#endif
+
+/* These are the command codes that appear in compiled regular
+   expressions.  Some opcodes are followed by argument bytes.  A
+   command code can specify any interpretation whatsoever for its
+   arguments.  Zero bytes may appear in the compiled regular expression.  */
+
+typedef enum
+{
+  no_op = 0,
+
+  /* Succeed right away--no more backtracking.  */
+  succeed,
+
+        /* Followed by one byte giving n, then by n literal bytes.  */
+  exactn,
+
+# ifdef MBS_SUPPORT
+	/* Same as exactn, but contains binary data.  */
+  exactn_bin,
+# endif
+
+        /* Matches any (more or less) character.  */
+  anychar,
+
+        /* Matches any one char belonging to specified set.  First
+           following byte is number of bitmap bytes.  Then come bytes
+           for a bitmap saying which chars are in.  Bits in each byte
+           are ordered low-bit-first.  A character is in the set if its
+           bit is 1.  A character too large to have a bit in the map is
+           automatically not in the set.  */
+        /* ifdef MBS_SUPPORT, following element is length of character
+	   classes, length of collating symbols, length of equivalence
+	   classes, length of character ranges, and length of characters.
+	   Next, character class element, collating symbols elements,
+	   equivalence class elements, range elements, and character
+	   elements follow.
+	   See regex_compile function.  */
+  charset,
+
+        /* Same parameters as charset, but match any character that is
+           not one of those specified.  */
+  charset_not,
+
+        /* Start remembering the text that is matched, for storing in a
+           register.  Followed by one byte with the register number, in
+           the range 0 to one less than the pattern buffer's re_nsub
+           field.  Then followed by one byte with the number of groups
+           inner to this one.  (This last has to be part of the
+           start_memory only because we need it in the on_failure_jump
+           of re_match_2.)  */
+  start_memory,
+
+        /* Stop remembering the text that is matched and store it in a
+           memory register.  Followed by one byte with the register
+           number, in the range 0 to one less than `re_nsub' in the
+           pattern buffer, and one byte with the number of inner groups,
+           just like `start_memory'.  (We need the number of inner
+           groups here because we don't have any easy way of finding the
+           corresponding start_memory when we're at a stop_memory.)  */
+  stop_memory,
+
+        /* Match a duplicate of something remembered. Followed by one
+           byte containing the register number.  */
+  duplicate,
+
+        /* Fail unless at beginning of line.  */
+  begline,
+
+        /* Fail unless at end of line.  */
+  endline,
+
+        /* Succeeds if at beginning of buffer (if emacs) or at beginning
+           of string to be matched (if not).  */
+  begbuf,
+
+        /* Analogously, for end of buffer/string.  */
+  endbuf,
+
+        /* Followed by two byte relative address to which to jump.  */
+  jump,
+
+	/* Same as jump, but marks the end of an alternative.  */
+  jump_past_alt,
+
+        /* Followed by two-byte relative address of place to resume at
+           in case of failure.  */
+        /* ifdef MBS_SUPPORT, the size of address is 1.  */
+  on_failure_jump,
+
+        /* Like on_failure_jump, but pushes a placeholder instead of the
+           current string position when executed.  */
+  on_failure_keep_string_jump,
+
+        /* Throw away latest failure point and then jump to following
+           two-byte relative address.  */
+        /* ifdef MBS_SUPPORT, the size of address is 1.  */
+  pop_failure_jump,
+
+        /* Change to pop_failure_jump if know won't have to backtrack to
+           match; otherwise change to jump.  This is used to jump
+           back to the beginning of a repeat.  If what follows this jump
+           clearly won't match what the repeat does, such that we can be
+           sure that there is no use backtracking out of repetitions
+           already matched, then we change it to a pop_failure_jump.
+           Followed by two-byte address.  */
+        /* ifdef MBS_SUPPORT, the size of address is 1.  */
+  maybe_pop_jump,
+
+        /* Jump to following two-byte address, and push a dummy failure
+           point. This failure point will be thrown away if an attempt
+           is made to use it for a failure.  A `+' construct makes this
+           before the first repeat.  Also used as an intermediary kind
+           of jump when compiling an alternative.  */
+        /* ifdef MBS_SUPPORT, the size of address is 1.  */
+  dummy_failure_jump,
+
+	/* Push a dummy failure point and continue.  Used at the end of
+	   alternatives.  */
+  push_dummy_failure,
+
+        /* Followed by two-byte relative address and two-byte number n.
+           After matching N times, jump to the address upon failure.  */
+        /* ifdef MBS_SUPPORT, the size of address is 1.  */
+  succeed_n,
+
+        /* Followed by two-byte relative address, and two-byte number n.
+           Jump to the address N times, then fail.  */
+        /* ifdef MBS_SUPPORT, the size of address is 1.  */
+  jump_n,
+
+        /* Set the following two-byte relative address to the
+           subsequent two-byte number.  The address *includes* the two
+           bytes of number.  */
+        /* ifdef MBS_SUPPORT, the size of address is 1.  */
+  set_number_at,
+
+  wordchar,	/* Matches any word-constituent character.  */
+  notwordchar,	/* Matches any char that is not a word-constituent.  */
+
+  wordbeg,	/* Succeeds if at word beginning.  */
+  wordend,	/* Succeeds if at word end.  */
+
+  wordbound,	/* Succeeds if at a word boundary.  */
+  notwordbound	/* Succeeds if not at a word boundary.  */
+
+# ifdef emacs
+  ,before_dot,	/* Succeeds if before point.  */
+  at_dot,	/* Succeeds if at point.  */
+  after_dot,	/* Succeeds if after point.  */
+
+	/* Matches any character whose syntax is specified.  Followed by
+           a byte which contains a syntax code, e.g., Sword.  */
+  syntaxspec,
+
+	/* Matches any character whose syntax is not that specified.  */
+  notsyntaxspec
+# endif /* emacs */
+} re_opcode_t;
+#endif /* not INSIDE_RECURSION */
+
+
+#ifdef BYTE
+# define CHAR_T char
+# define UCHAR_T unsigned char
+# define COMPILED_BUFFER_VAR bufp->buffer
+# define OFFSET_ADDRESS_SIZE 2
+# define PREFIX(name) byte_##name
+# define ARG_PREFIX(name) name
+# define PUT_CHAR(c) putchar (c)
+# include <locale/weight.h>
+# define FINDIDX findidx
+#else
+# ifdef WCHAR
+#  define CHAR_T wchar_t
+#  define UCHAR_T wchar_t
+#  define COMPILED_BUFFER_VAR wc_buffer
+#  define OFFSET_ADDRESS_SIZE 1 /* the size which STORE_NUMBER macro use */
+#  define CHAR_CLASS_SIZE ((__alignof__(wctype_t)+sizeof(wctype_t))/sizeof(CHAR_T)+1)
+#  define PREFIX(name) wcs_##name
+#  define ARG_PREFIX(name) c##name
+/* Should we use wide stream??  */
+#  define PUT_CHAR(c) printf ("%C", c);
+#  define TRUE 1
+#  define FALSE 0
+#  define findidx findidxwc
+#  include <locale/weightwc.h>
+#  undef findidx
+#  define FINDIDX findidxwc
+# else
+#  ifdef MBS_SUPPORT
+#   define WCHAR
+#   define INSIDE_RECURSION
+#   include "xregex.c"
+#   undef INSIDE_RECURSION
+#  endif
+#  define BYTE
+#  define INSIDE_RECURSION
+#  include "xregex.c"
+#  undef INSIDE_RECURSION
+# endif
+#endif
+
+#ifdef INSIDE_RECURSION
+/* Common operations on the compiled pattern.  */
+
+/* Store NUMBER in two contiguous bytes starting at DESTINATION.  */
+/* ifdef MBS_SUPPORT, we store NUMBER in 1 element.  */
+
+# ifdef WCHAR
+#  define STORE_NUMBER(destination, number)				\
+  do {									\
+    *(destination) = (UCHAR_T)(number);				\
+  } while (0)
+# else /* BYTE */
+#  define STORE_NUMBER(destination, number)				\
+  do {									\
+    (destination)[0] = (number) & 0377;					\
+    (destination)[1] = (number) >> 8;					\
+  } while (0)
+# endif /* WCHAR */
+
+/* Same as STORE_NUMBER, except increment DESTINATION to
+   the byte after where the number is stored.  Therefore, DESTINATION
+   must be an lvalue.  */
+/* ifdef MBS_SUPPORT, we store NUMBER in 1 element.  */
+
+# define STORE_NUMBER_AND_INCR(destination, number)			\
+  do {									\
+    STORE_NUMBER (destination, number);					\
+    (destination) += OFFSET_ADDRESS_SIZE;				\
+  } while (0)
+
+/* Put into DESTINATION a number stored in two contiguous bytes starting
+   at SOURCE.  */
+/* ifdef MBS_SUPPORT, we store NUMBER in 1 element.  */
+
+# ifdef WCHAR
+#  define EXTRACT_NUMBER(destination, source)				\
+  do {									\
+    (destination) = *(source);						\
+  } while (0)
+# else /* BYTE */
+#  define EXTRACT_NUMBER(destination, source)				\
+  do {									\
+    (destination) = *(source) & 0377;					\
+    (destination) += SIGN_EXTEND_CHAR (*((source) + 1)) << 8;		\
+  } while (0)
+# endif
+
+# ifdef DEBUG
+static void PREFIX(extract_number) (int *dest, UCHAR_T *source);
+static void
+PREFIX(extract_number) (int *dest, UCHAR_T *source)
+{
+#  ifdef WCHAR
+  *dest = *source;
+#  else /* BYTE */
+  int temp = SIGN_EXTEND_CHAR (*(source + 1));
+  *dest = *source & 0377;
+  *dest += temp << 8;
+#  endif
+}
+
+#  ifndef EXTRACT_MACROS /* To debug the macros.  */
+#   undef EXTRACT_NUMBER
+#   define EXTRACT_NUMBER(dest, src) PREFIX(extract_number) (&dest, src)
+#  endif /* not EXTRACT_MACROS */
+
+# endif /* DEBUG */
+
+/* Same as EXTRACT_NUMBER, except increment SOURCE to after the number.
+   SOURCE must be an lvalue.  */
+
+# define EXTRACT_NUMBER_AND_INCR(destination, source)			\
+  do {									\
+    EXTRACT_NUMBER (destination, source);				\
+    (source) += OFFSET_ADDRESS_SIZE; 					\
+  } while (0)
+
+# ifdef DEBUG
+static void PREFIX(extract_number_and_incr) (int *destination,
+                                             UCHAR_T **source);
+static void
+PREFIX(extract_number_and_incr) (int *destination, UCHAR_T **source)
+{
+  PREFIX(extract_number) (destination, *source);
+  *source += OFFSET_ADDRESS_SIZE;
+}
+
+#  ifndef EXTRACT_MACROS
+#   undef EXTRACT_NUMBER_AND_INCR
+#   define EXTRACT_NUMBER_AND_INCR(dest, src) \
+  PREFIX(extract_number_and_incr) (&dest, &src)
+#  endif /* not EXTRACT_MACROS */
+
+# endif /* DEBUG */
+
+
+
+/* If DEBUG is defined, Regex prints many voluminous messages about what
+   it is doing (if the variable `debug' is nonzero).  If linked with the
+   main program in `iregex.c', you can enter patterns and strings
+   interactively.  And if linked with the main program in `main.c' and
+   the other test files, you can run the already-written tests.  */
+
+# ifdef DEBUG
+
+#  ifndef DEFINED_ONCE
+
+/* We use standard I/O for debugging.  */
+#   include <stdio.h>
+
+/* It is useful to test things that ``must'' be true when debugging.  */
+#   include <assert.h>
+
+static int debug;
+
+#   define DEBUG_STATEMENT(e) e
+#   define DEBUG_PRINT1(x) if (debug) printf (x)
+#   define DEBUG_PRINT2(x1, x2) if (debug) printf (x1, x2)
+#   define DEBUG_PRINT3(x1, x2, x3) if (debug) printf (x1, x2, x3)
+#   define DEBUG_PRINT4(x1, x2, x3, x4) if (debug) printf (x1, x2, x3, x4)
+#  endif /* not DEFINED_ONCE */
+
+#  define DEBUG_PRINT_COMPILED_PATTERN(p, s, e) 			\
+  if (debug) PREFIX(print_partial_compiled_pattern) (s, e)
+#  define DEBUG_PRINT_DOUBLE_STRING(w, s1, sz1, s2, sz2)		\
+  if (debug) PREFIX(print_double_string) (w, s1, sz1, s2, sz2)
+
+
+/* Print the fastmap in human-readable form.  */
+
+#  ifndef DEFINED_ONCE
+void
+print_fastmap (char *fastmap)
+{
+  unsigned was_a_range = 0;
+  unsigned i = 0;
+
+  while (i < (1 << BYTEWIDTH))
+    {
+      if (fastmap[i++])
+	{
+	  was_a_range = 0;
+          putchar (i - 1);
+          while (i < (1 << BYTEWIDTH)  &&  fastmap[i])
+            {
+              was_a_range = 1;
+              i++;
+            }
+	  if (was_a_range)
+            {
+              printf ("-");
+              putchar (i - 1);
+            }
+        }
+    }
+  putchar ('\n');
+}
+#  endif /* not DEFINED_ONCE */
+
+
+/* Print a compiled pattern string in human-readable form, starting at
+   the START pointer into it and ending just before the pointer END.  */
+
+void
+PREFIX(print_partial_compiled_pattern) (UCHAR_T *start, UCHAR_T *end)
+{
+  int mcnt, mcnt2;
+  UCHAR_T *p1;
+  UCHAR_T *p = start;
+  UCHAR_T *pend = end;
+
+  if (start == NULL)
+    {
+      printf ("(null)\n");
+      return;
+    }
+
+  /* Loop over pattern commands.  */
+  while (p < pend)
+    {
+#  ifdef _LIBC
+      printf ("%td:\t", p - start);
+#  else
+      printf ("%ld:\t", (long int) (p - start));
+#  endif
+
+      switch ((re_opcode_t) *p++)
+	{
+        case no_op:
+          printf ("/no_op");
+          break;
+
+	case exactn:
+	  mcnt = *p++;
+          printf ("/exactn/%d", mcnt);
+          do
+	    {
+              putchar ('/');
+	      PUT_CHAR (*p++);
+            }
+          while (--mcnt);
+          break;
+
+#  ifdef MBS_SUPPORT
+	case exactn_bin:
+	  mcnt = *p++;
+	  printf ("/exactn_bin/%d", mcnt);
+          do
+	    {
+	      printf("/%lx", (long int) *p++);
+            }
+          while (--mcnt);
+          break;
+#  endif /* MBS_SUPPORT */
+
+	case start_memory:
+          mcnt = *p++;
+          printf ("/start_memory/%d/%ld", mcnt, (long int) *p++);
+          break;
+
+	case stop_memory:
+          mcnt = *p++;
+	  printf ("/stop_memory/%d/%ld", mcnt, (long int) *p++);
+          break;
+
+	case duplicate:
+	  printf ("/duplicate/%ld", (long int) *p++);
+	  break;
+
+	case anychar:
+	  printf ("/anychar");
+	  break;
+
+	case charset:
+        case charset_not:
+          {
+#  ifdef WCHAR
+	    int i, length;
+	    wchar_t *workp = p;
+	    printf ("/charset [%s",
+	            (re_opcode_t) *(workp - 1) == charset_not ? "^" : "");
+	    p += 5;
+	    length = *workp++; /* the length of char_classes */
+	    for (i=0 ; i<length ; i++)
+	      printf("[:%lx:]", (long int) *p++);
+	    length = *workp++; /* the length of collating_symbol */
+	    for (i=0 ; i<length ;)
+	      {
+		printf("[.");
+		while(*p != 0)
+		  PUT_CHAR((i++,*p++));
+		i++,p++;
+		printf(".]");
+	      }
+	    length = *workp++; /* the length of equivalence_class */
+	    for (i=0 ; i<length ;)
+	      {
+		printf("[=");
+		while(*p != 0)
+		  PUT_CHAR((i++,*p++));
+		i++,p++;
+		printf("=]");
+	      }
+	    length = *workp++; /* the length of char_range */
+	    for (i=0 ; i<length ; i++)
+	      {
+		wchar_t range_start = *p++;
+		wchar_t range_end = *p++;
+		printf("%C-%C", range_start, range_end);
+	      }
+	    length = *workp++; /* the length of char */
+	    for (i=0 ; i<length ; i++)
+	      printf("%C", *p++);
+	    putchar (']');
+#  else
+            register int c, last = -100;
+	    register int in_range = 0;
+
+	    printf ("/charset [%s",
+	            (re_opcode_t) *(p - 1) == charset_not ? "^" : "");
+
+            assert (p + *p < pend);
+
+            for (c = 0; c < 256; c++)
+	      if (c / 8 < *p
+		  && (p[1 + (c/8)] & (1 << (c % 8))))
+		{
+		  /* Are we starting a range?  */
+		  if (last + 1 == c && ! in_range)
+		    {
+		      putchar ('-');
+		      in_range = 1;
+		    }
+		  /* Have we broken a range?  */
+		  else if (last + 1 != c && in_range)
+              {
+		      putchar (last);
+		      in_range = 0;
+		    }
+
+		  if (! in_range)
+		    putchar (c);
+
+		  last = c;
+              }
+
+	    if (in_range)
+	      putchar (last);
+
+	    putchar (']');
+
+	    p += 1 + *p;
+#  endif /* WCHAR */
+	  }
+	  break;
+
+	case begline:
+	  printf ("/begline");
+          break;
+
+	case endline:
+          printf ("/endline");
+          break;
+
+	case on_failure_jump:
+          PREFIX(extract_number_and_incr) (&mcnt, &p);
+#  ifdef _LIBC
+  	  printf ("/on_failure_jump to %td", p + mcnt - start);
+#  else
+  	  printf ("/on_failure_jump to %ld", (long int) (p + mcnt - start));
+#  endif
+          break;
+
+	case on_failure_keep_string_jump:
+          PREFIX(extract_number_and_incr) (&mcnt, &p);
+#  ifdef _LIBC
+  	  printf ("/on_failure_keep_string_jump to %td", p + mcnt - start);
+#  else
+  	  printf ("/on_failure_keep_string_jump to %ld",
+		  (long int) (p + mcnt - start));
+#  endif
+          break;
+
+	case dummy_failure_jump:
+          PREFIX(extract_number_and_incr) (&mcnt, &p);
+#  ifdef _LIBC
+  	  printf ("/dummy_failure_jump to %td", p + mcnt - start);
+#  else
+  	  printf ("/dummy_failure_jump to %ld", (long int) (p + mcnt - start));
+#  endif
+          break;
+
+	case push_dummy_failure:
+          printf ("/push_dummy_failure");
+          break;
+
+        case maybe_pop_jump:
+          PREFIX(extract_number_and_incr) (&mcnt, &p);
+#  ifdef _LIBC
+  	  printf ("/maybe_pop_jump to %td", p + mcnt - start);
+#  else
+  	  printf ("/maybe_pop_jump to %ld", (long int) (p + mcnt - start));
+#  endif
+	  break;
+
+        case pop_failure_jump:
+	  PREFIX(extract_number_and_incr) (&mcnt, &p);
+#  ifdef _LIBC
+  	  printf ("/pop_failure_jump to %td", p + mcnt - start);
+#  else
+  	  printf ("/pop_failure_jump to %ld", (long int) (p + mcnt - start));
+#  endif
+	  break;
+
+        case jump_past_alt:
+	  PREFIX(extract_number_and_incr) (&mcnt, &p);
+#  ifdef _LIBC
+  	  printf ("/jump_past_alt to %td", p + mcnt - start);
+#  else
+  	  printf ("/jump_past_alt to %ld", (long int) (p + mcnt - start));
+#  endif
+	  break;
+
+        case jump:
+	  PREFIX(extract_number_and_incr) (&mcnt, &p);
+#  ifdef _LIBC
+  	  printf ("/jump to %td", p + mcnt - start);
+#  else
+  	  printf ("/jump to %ld", (long int) (p + mcnt - start));
+#  endif
+	  break;
+
+        case succeed_n:
+          PREFIX(extract_number_and_incr) (&mcnt, &p);
+	  p1 = p + mcnt;
+          PREFIX(extract_number_and_incr) (&mcnt2, &p);
+#  ifdef _LIBC
+	  printf ("/succeed_n to %td, %d times", p1 - start, mcnt2);
+#  else
+	  printf ("/succeed_n to %ld, %d times",
+		  (long int) (p1 - start), mcnt2);
+#  endif
+          break;
+
+        case jump_n:
+          PREFIX(extract_number_and_incr) (&mcnt, &p);
+	  p1 = p + mcnt;
+          PREFIX(extract_number_and_incr) (&mcnt2, &p);
+	  printf ("/jump_n to %d, %d times", p1 - start, mcnt2);
+          break;
+
+        case set_number_at:
+          PREFIX(extract_number_and_incr) (&mcnt, &p);
+	  p1 = p + mcnt;
+          PREFIX(extract_number_and_incr) (&mcnt2, &p);
+#  ifdef _LIBC
+	  printf ("/set_number_at location %td to %d", p1 - start, mcnt2);
+#  else
+	  printf ("/set_number_at location %ld to %d",
+		  (long int) (p1 - start), mcnt2);
+#  endif
+          break;
+
+        case wordbound:
+	  printf ("/wordbound");
+	  break;
+
+	case notwordbound:
+	  printf ("/notwordbound");
+          break;
+
+	case wordbeg:
+	  printf ("/wordbeg");
+	  break;
+
+	case wordend:
+	  printf ("/wordend");
+	  break;
+
+#  ifdef emacs
+	case before_dot:
+	  printf ("/before_dot");
+          break;
+
+	case at_dot:
+	  printf ("/at_dot");
+          break;
+
+	case after_dot:
+	  printf ("/after_dot");
+          break;
+
+	case syntaxspec:
+          printf ("/syntaxspec");
+	  mcnt = *p++;
+	  printf ("/%d", mcnt);
+          break;
+
+	case notsyntaxspec:
+          printf ("/notsyntaxspec");
+	  mcnt = *p++;
+	  printf ("/%d", mcnt);
+	  break;
+#  endif /* emacs */
+
+	case wordchar:
+	  printf ("/wordchar");
+          break;
+
+	case notwordchar:
+	  printf ("/notwordchar");
+          break;
+
+	case begbuf:
+	  printf ("/begbuf");
+          break;
+
+	case endbuf:
+	  printf ("/endbuf");
+          break;
+
+        default:
+          printf ("?%ld", (long int) *(p-1));
+	}
+
+      putchar ('\n');
+    }
+
+#  ifdef _LIBC
+  printf ("%td:\tend of pattern.\n", p - start);
+#  else
+  printf ("%ld:\tend of pattern.\n", (long int) (p - start));
+#  endif
+}
+
+
+void
+PREFIX(print_compiled_pattern) (struct re_pattern_buffer *bufp)
+{
+  UCHAR_T *buffer = (UCHAR_T*) bufp->buffer;
+
+  PREFIX(print_partial_compiled_pattern) (buffer, buffer
+				  + bufp->used / sizeof(UCHAR_T));
+  printf ("%ld bytes used/%ld bytes allocated.\n",
+	  bufp->used, bufp->allocated);
+
+  if (bufp->fastmap_accurate && bufp->fastmap)
+    {
+      printf ("fastmap: ");
+      print_fastmap (bufp->fastmap);
+    }
+
+#  ifdef _LIBC
+  printf ("re_nsub: %Zd\t", bufp->re_nsub);
+#  else
+  printf ("re_nsub: %ld\t", (long int) bufp->re_nsub);
+#  endif
+  printf ("regs_alloc: %d\t", bufp->regs_allocated);
+  printf ("can_be_null: %d\t", bufp->can_be_null);
+  printf ("newline_anchor: %d\n", bufp->newline_anchor);
+  printf ("no_sub: %d\t", bufp->no_sub);
+  printf ("not_bol: %d\t", bufp->not_bol);
+  printf ("not_eol: %d\t", bufp->not_eol);
+  printf ("syntax: %lx\n", bufp->syntax);
+  /* Perhaps we should print the translate table?  */
+}
+
+
+void
+PREFIX(print_double_string) (const CHAR_T *where, const CHAR_T *string1,
+                             int size1, const CHAR_T *string2, int size2)
+{
+  int this_char;
+
+  if (where == NULL)
+    printf ("(null)");
+  else
+    {
+      int cnt;
+
+      if (FIRST_STRING_P (where))
+        {
+          for (this_char = where - string1; this_char < size1; this_char++)
+	    PUT_CHAR (string1[this_char]);
+
+          where = string2;
+        }
+
+      cnt = 0;
+      for (this_char = where - string2; this_char < size2; this_char++)
+	{
+	  PUT_CHAR (string2[this_char]);
+	  if (++cnt > 100)
+	    {
+	      fputs ("...", stdout);
+	      break;
+	    }
+	}
+    }
+}
+
+#  ifndef DEFINED_ONCE
+void
+printchar (int c)
+{
+  putc (c, stderr);
+}
+#  endif
+
+# else /* not DEBUG */
+
+#  ifndef DEFINED_ONCE
+#   undef assert
+#   define assert(e)
+
+#   define DEBUG_STATEMENT(e)
+#   define DEBUG_PRINT1(x)
+#   define DEBUG_PRINT2(x1, x2)
+#   define DEBUG_PRINT3(x1, x2, x3)
+#   define DEBUG_PRINT4(x1, x2, x3, x4)
+#  endif /* not DEFINED_ONCE */
+#  define DEBUG_PRINT_COMPILED_PATTERN(p, s, e)
+#  define DEBUG_PRINT_DOUBLE_STRING(w, s1, sz1, s2, sz2)
+
+# endif /* not DEBUG */
+
+
+
+# ifdef WCHAR
+/* This  convert a multibyte string to a wide character string.
+   And write their correspondances to offset_buffer(see below)
+   and write whether each wchar_t is binary data to is_binary.
+   This assume invalid multibyte sequences as binary data.
+   We assume offset_buffer and is_binary is already allocated
+   enough space.  */
+
+static size_t convert_mbs_to_wcs (CHAR_T *dest, const unsigned char* src,
+				  size_t len, int *offset_buffer,
+				  char *is_binary);
+static size_t
+convert_mbs_to_wcs (CHAR_T *dest, const unsigned char*src, size_t len,
+                    int *offset_buffer, char *is_binary)
+     /* It hold correspondances between src(char string) and
+	dest(wchar_t string) for optimization.
+	e.g. src  = "xxxyzz"
+             dest = {'X', 'Y', 'Z'}
+	      (each "xxx", "y" and "zz" represent one multibyte character
+	       corresponding to 'X', 'Y' and 'Z'.)
+	  offset_buffer = {0, 0+3("xxx"), 0+3+1("y"), 0+3+1+2("zz")}
+	  	        = {0, 3, 4, 6}
+     */
+{
+  wchar_t *pdest = dest;
+  const unsigned char *psrc = src;
+  size_t wc_count = 0;
+
+  mbstate_t mbs;
+  int i, consumed;
+  size_t mb_remain = len;
+  size_t mb_count = 0;
+
+  /* Initialize the conversion state.  */
+  memset (&mbs, 0, sizeof (mbstate_t));
+
+  offset_buffer[0] = 0;
+  for( ; mb_remain > 0 ; ++wc_count, ++pdest, mb_remain -= consumed,
+	 psrc += consumed)
+    {
+#ifdef _LIBC
+      consumed = __mbrtowc (pdest, psrc, mb_remain, &mbs);
+#else
+      consumed = mbrtowc (pdest, psrc, mb_remain, &mbs);
+#endif
+
+      if (consumed <= 0)
+	/* failed to convert. maybe src contains binary data.
+	   So we consume 1 byte manualy.  */
+	{
+	  *pdest = *psrc;
+	  consumed = 1;
+	  is_binary[wc_count] = TRUE;
+	}
+      else
+	is_binary[wc_count] = FALSE;
+      /* In sjis encoding, we use yen sign as escape character in
+	 place of reverse solidus. So we convert 0x5c(yen sign in
+	 sjis) to not 0xa5(yen sign in UCS2) but 0x5c(reverse
+	 solidus in UCS2).  */
+      if (consumed == 1 && (int) *psrc == 0x5c && (int) *pdest == 0xa5)
+	*pdest = (wchar_t) *psrc;
+
+      offset_buffer[wc_count + 1] = mb_count += consumed;
+    }
+
+  /* Fill remain of the buffer with sentinel.  */
+  for (i = wc_count + 1 ; i <= len ; i++)
+    offset_buffer[i] = mb_count + 1;
+
+  return wc_count;
+}
+
+# endif /* WCHAR */
+
+#else /* not INSIDE_RECURSION */
+
+/* Set by `re_set_syntax' to the current regexp syntax to recognize.  Can
+   also be assigned to arbitrarily: each pattern buffer stores its own
+   syntax, so it can be changed between regex compilations.  */
+/* This has no initializer because initialized variables in Emacs
+   become read-only after dumping.  */
+reg_syntax_t re_syntax_options;
+
+
+/* Specify the precise syntax of regexps for compilation.  This provides
+   for compatibility for various utilities which historically have
+   different, incompatible syntaxes.
+
+   The argument SYNTAX is a bit mask comprised of the various bits
+   defined in regex.h.  We return the old syntax.  */
+
+reg_syntax_t
+re_set_syntax (reg_syntax_t syntax)
+{
+  reg_syntax_t ret = re_syntax_options;
+
+  re_syntax_options = syntax;
+# ifdef DEBUG
+  if (syntax & RE_DEBUG)
+    debug = 1;
+  else if (debug) /* was on but now is not */
+    debug = 0;
+# endif /* DEBUG */
+  return ret;
+}
+# ifdef _LIBC
+weak_alias (__re_set_syntax, re_set_syntax)
+# endif
+
+/* This table gives an error message for each of the error codes listed
+   in regex.h.  Obviously the order here has to be same as there.
+   POSIX doesn't require that we do anything for REG_NOERROR,
+   but why not be nice?  */
+
+static const char *re_error_msgid[] =
+  {
+    gettext_noop ("Success"),	/* REG_NOERROR */
+    gettext_noop ("No match"),	/* REG_NOMATCH */
+    gettext_noop ("Invalid regular expression"), /* REG_BADPAT */
+    gettext_noop ("Invalid collation character"), /* REG_ECOLLATE */
+    gettext_noop ("Invalid character class name"), /* REG_ECTYPE */
+    gettext_noop ("Trailing backslash"), /* REG_EESCAPE */
+    gettext_noop ("Invalid back reference"), /* REG_ESUBREG */
+    gettext_noop ("Unmatched [ or [^"),	/* REG_EBRACK */
+    gettext_noop ("Unmatched ( or \\("), /* REG_EPAREN */
+    gettext_noop ("Unmatched \\{"), /* REG_EBRACE */
+    gettext_noop ("Invalid content of \\{\\}"), /* REG_BADBR */
+    gettext_noop ("Invalid range end"),	/* REG_ERANGE */
+    gettext_noop ("Memory exhausted"), /* REG_ESPACE */
+    gettext_noop ("Invalid preceding regular expression"), /* REG_BADRPT */
+    gettext_noop ("Premature end of regular expression"), /* REG_EEND */
+    gettext_noop ("Regular expression too big"), /* REG_ESIZE */
+    gettext_noop ("Unmatched ) or \\)") /* REG_ERPAREN */
+  };
+
+#endif /* INSIDE_RECURSION */
+
+#ifndef DEFINED_ONCE
+/* Avoiding alloca during matching, to placate r_alloc.  */
+
+/* Define MATCH_MAY_ALLOCATE unless we need to make sure that the
+   searching and matching functions should not call alloca.  On some
+   systems, alloca is implemented in terms of malloc, and if we're
+   using the relocating allocator routines, then malloc could cause a
+   relocation, which might (if the strings being searched are in the
+   ralloc heap) shift the data out from underneath the regexp
+   routines.
+
+   Here's another reason to avoid allocation: Emacs
+   processes input from X in a signal handler; processing X input may
+   call malloc; if input arrives while a matching routine is calling
+   malloc, then we're scrod.  But Emacs can't just block input while
+   calling matching routines; then we don't notice interrupts when
+   they come in.  So, Emacs blocks input around all regexp calls
+   except the matching calls, which it leaves unprotected, in the
+   faith that they will not malloc.  */
+
+/* Normally, this is fine.  */
+# define MATCH_MAY_ALLOCATE
+
+/* When using GNU C, we are not REALLY using the C alloca, no matter
+   what config.h may say.  So don't take precautions for it.  */
+# ifdef __GNUC__
+#  undef C_ALLOCA
+# endif
+
+/* The match routines may not allocate if (1) they would do it with malloc
+   and (2) it's not safe for them to use malloc.
+   Note that if REL_ALLOC is defined, matching would not use malloc for the
+   failure stack, but we would still use it for the register vectors;
+   so REL_ALLOC should not affect this.  */
+# if (defined C_ALLOCA || defined REGEX_MALLOC) && defined emacs
+#  undef MATCH_MAY_ALLOCATE
+# endif
+#endif /* not DEFINED_ONCE */
+
+#ifdef INSIDE_RECURSION
+/* Failure stack declarations and macros; both re_compile_fastmap and
+   re_match_2 use a failure stack.  These have to be macros because of
+   REGEX_ALLOCATE_STACK.  */
+
+
+/* Number of failure points for which to initially allocate space
+   when matching.  If this number is exceeded, we allocate more
+   space, so it is not a hard limit.  */
+# ifndef INIT_FAILURE_ALLOC
+#  define INIT_FAILURE_ALLOC 5
+# endif
+
+/* Roughly the maximum number of failure points on the stack.  Would be
+   exactly that if always used MAX_FAILURE_ITEMS items each time we failed.
+   This is a variable only so users of regex can assign to it; we never
+   change it ourselves.  */
+
+
+# ifndef DEFINED_ONCE
+
+#  ifdef INT_IS_16BIT
+#   define RE_M_F_TYPE long int
+#  else
+#   define RE_M_F_TYPE int
+#  endif /* INT_IS_16BIT */
+
+#  ifdef MATCH_MAY_ALLOCATE
+/* 4400 was enough to cause a crash on Alpha OSF/1,
+   whose default stack limit is 2mb.  */
+#   define RE_M_F_DEFAULT 4000
+#  else
+#   define RE_M_F_DEFAULT 2000
+#  endif /* MATCH_MAY_ALLOCATE */
+
+#  include <shlib-compat.h>
+
+#  if SHLIB_COMPAT (libc, GLIBC_2_0, GLIBC_2_3)
+link_warning (re_max_failures, "the 're_max_failures' variable is obsolete and will go away.")
+RE_M_F_TYPE re_max_failures = RE_M_F_DEFAULT;
+#  else
+RE_M_F_TYPE re_max_failures attribute_hidden = RE_M_F_DEFAULT;
+#  endif /* SHLIB_COMPAT */
+
+#  undef RE_M_F_TYPE
+#  undef RE_M_F_DEFAULT
+
+# endif /* DEFINED_ONCE */
+
+# ifdef INT_IS_16BIT
+
+union PREFIX(fail_stack_elt)
+{
+  UCHAR_T *pointer;
+  long int integer;
+};
+
+typedef union PREFIX(fail_stack_elt) PREFIX(fail_stack_elt_t);
+
+typedef struct
+{
+  PREFIX(fail_stack_elt_t) *stack;
+  unsigned long int size;
+  unsigned long int avail;		/* Offset of next open position.  */
+} PREFIX(fail_stack_type);
+
+# else /* not INT_IS_16BIT */
+
+union PREFIX(fail_stack_elt)
+{
+  UCHAR_T *pointer;
+  int integer;
+};
+
+typedef union PREFIX(fail_stack_elt) PREFIX(fail_stack_elt_t);
+
+typedef struct
+{
+  PREFIX(fail_stack_elt_t) *stack;
+  unsigned size;
+  unsigned avail;			/* Offset of next open position.  */
+} PREFIX(fail_stack_type);
+
+# endif /* INT_IS_16BIT */
+
+# ifndef DEFINED_ONCE
+#  define FAIL_STACK_EMPTY()     (fail_stack.avail == 0)
+#  define FAIL_STACK_PTR_EMPTY() (fail_stack_ptr->avail == 0)
+#  define FAIL_STACK_FULL()      (fail_stack.avail == fail_stack.size)
+# endif
+
+
+/* Define macros to initialize and free the failure stack.
+   Do `return -2' if the alloc fails.  */
+
+# ifdef MATCH_MAY_ALLOCATE
+#  define INIT_FAIL_STACK()						\
+  do {									\
+    fail_stack.stack = (PREFIX(fail_stack_elt_t) *)		\
+      REGEX_ALLOCATE_STACK (INIT_FAILURE_ALLOC * sizeof (PREFIX(fail_stack_elt_t))); \
+									\
+    if (fail_stack.stack == NULL)				\
+      return -2;							\
+									\
+    fail_stack.size = INIT_FAILURE_ALLOC;			\
+    fail_stack.avail = 0;					\
+  } while (0)
+
+#  define RESET_FAIL_STACK()  REGEX_FREE_STACK (fail_stack.stack)
+# else
+#  define INIT_FAIL_STACK()						\
+  do {									\
+    fail_stack.avail = 0;					\
+  } while (0)
+
+#  define RESET_FAIL_STACK()
+# endif
+
+
+/* Double the size of FAIL_STACK, up to approximately `re_max_failures' items.
+
+   Return 1 if succeeds, and 0 if either ran out of memory
+   allocating space for it or it was already too large.
+
+   REGEX_REALLOCATE_STACK requires `destination' be declared.   */
+
+# define DOUBLE_FAIL_STACK(fail_stack)					\
+  ((fail_stack).size > (unsigned) (re_max_failures * MAX_FAILURE_ITEMS)	\
+   ? 0									\
+   : ((fail_stack).stack = (PREFIX(fail_stack_elt_t) *)			\
+        REGEX_REALLOCATE_STACK ((fail_stack).stack, 			\
+          (fail_stack).size * sizeof (PREFIX(fail_stack_elt_t)),	\
+          ((fail_stack).size << 1) * sizeof (PREFIX(fail_stack_elt_t))),\
+									\
+      (fail_stack).stack == NULL					\
+      ? 0								\
+      : ((fail_stack).size <<= 1, 					\
+         1)))
+
+
+/* Push pointer POINTER on FAIL_STACK.
+   Return 1 if was able to do so and 0 if ran out of memory allocating
+   space to do so.  */
+# define PUSH_PATTERN_OP(POINTER, FAIL_STACK)				\
+  ((FAIL_STACK_FULL ()							\
+    && !DOUBLE_FAIL_STACK (FAIL_STACK))					\
+   ? 0									\
+   : ((FAIL_STACK).stack[(FAIL_STACK).avail++].pointer = POINTER,	\
+      1))
+
+/* Push a pointer value onto the failure stack.
+   Assumes the variable `fail_stack'.  Probably should only
+   be called from within `PUSH_FAILURE_POINT'.  */
+# define PUSH_FAILURE_POINTER(item)					\
+  fail_stack.stack[fail_stack.avail++].pointer = (UCHAR_T *) (item)
+
+/* This pushes an integer-valued item onto the failure stack.
+   Assumes the variable `fail_stack'.  Probably should only
+   be called from within `PUSH_FAILURE_POINT'.  */
+# define PUSH_FAILURE_INT(item)					\
+  fail_stack.stack[fail_stack.avail++].integer = (item)
+
+/* Push a fail_stack_elt_t value onto the failure stack.
+   Assumes the variable `fail_stack'.  Probably should only
+   be called from within `PUSH_FAILURE_POINT'.  */
+# define PUSH_FAILURE_ELT(item)					\
+  fail_stack.stack[fail_stack.avail++] =  (item)
+
+/* These three POP... operations complement the three PUSH... operations.
+   All assume that `fail_stack' is nonempty.  */
+# define POP_FAILURE_POINTER() fail_stack.stack[--fail_stack.avail].pointer
+# define POP_FAILURE_INT() fail_stack.stack[--fail_stack.avail].integer
+# define POP_FAILURE_ELT() fail_stack.stack[--fail_stack.avail]
+
+/* Used to omit pushing failure point id's when we're not debugging.  */
+# ifdef DEBUG
+#  define DEBUG_PUSH PUSH_FAILURE_INT
+#  define DEBUG_POP(item_addr) *(item_addr) = POP_FAILURE_INT ()
+# else
+#  define DEBUG_PUSH(item)
+#  define DEBUG_POP(item_addr)
+# endif
+
+
+/* Push the information about the state we will need
+   if we ever fail back to it.
+
+   Requires variables fail_stack, regstart, regend, reg_info, and
+   num_regs_pushed be declared.  DOUBLE_FAIL_STACK requires `destination'
+   be declared.
+
+   Does `return FAILURE_CODE' if runs out of memory.  */
+
+# define PUSH_FAILURE_POINT(pattern_place, string_place, failure_code)	\
+  do {									\
+    char *destination;							\
+    /* Must be int, so when we don't save any registers, the arithmetic	\
+       of 0 + -1 isn't done as unsigned.  */				\
+    /* Can't be int, since there is not a shred of a guarantee that int	\
+       is wide enough to hold a value of something to which pointer can	\
+       be assigned */							\
+    active_reg_t this_reg;						\
+    									\
+    DEBUG_STATEMENT (failure_id++);					\
+    DEBUG_STATEMENT (nfailure_points_pushed++);				\
+    DEBUG_PRINT2 ("\nPUSH_FAILURE_POINT #%u:\n", failure_id);		\
+    DEBUG_PRINT2 ("  Before push, next avail: %d\n", (fail_stack).avail);\
+    DEBUG_PRINT2 ("                     size: %d\n", (fail_stack).size);\
+									\
+    DEBUG_PRINT2 ("  slots needed: %ld\n", NUM_FAILURE_ITEMS);		\
+    DEBUG_PRINT2 ("     available: %d\n", REMAINING_AVAIL_SLOTS);	\
+									\
+    /* Ensure we have enough space allocated for what we will push.  */	\
+    while (REMAINING_AVAIL_SLOTS < NUM_FAILURE_ITEMS)			\
+      {									\
+        if (!DOUBLE_FAIL_STACK (fail_stack))				\
+          return failure_code;						\
+									\
+        DEBUG_PRINT2 ("\n  Doubled stack; size now: %d\n",		\
+		       (fail_stack).size);				\
+        DEBUG_PRINT2 ("  slots available: %d\n", REMAINING_AVAIL_SLOTS);\
+      }									\
+									\
+    /* Push the info, starting with the registers.  */			\
+    DEBUG_PRINT1 ("\n");						\
+									\
+    if (1)								\
+      for (this_reg = lowest_active_reg; this_reg <= highest_active_reg; \
+	   this_reg++)							\
+	{								\
+	  DEBUG_PRINT2 ("  Pushing reg: %lu\n", this_reg);		\
+	  DEBUG_STATEMENT (num_regs_pushed++);				\
+									\
+	  DEBUG_PRINT2 ("    start: %p\n", regstart[this_reg]);		\
+	  PUSH_FAILURE_POINTER (regstart[this_reg]);			\
+									\
+	  DEBUG_PRINT2 ("    end: %p\n", regend[this_reg]);		\
+	  PUSH_FAILURE_POINTER (regend[this_reg]);			\
+									\
+	  DEBUG_PRINT2 ("    info: %p\n      ",				\
+			reg_info[this_reg].word.pointer);		\
+	  DEBUG_PRINT2 (" match_null=%d",				\
+			REG_MATCH_NULL_STRING_P (reg_info[this_reg]));	\
+	  DEBUG_PRINT2 (" active=%d", IS_ACTIVE (reg_info[this_reg]));	\
+	  DEBUG_PRINT2 (" matched_something=%d",			\
+			MATCHED_SOMETHING (reg_info[this_reg]));	\
+	  DEBUG_PRINT2 (" ever_matched=%d",				\
+			EVER_MATCHED_SOMETHING (reg_info[this_reg]));	\
+	  DEBUG_PRINT1 ("\n");						\
+	  PUSH_FAILURE_ELT (reg_info[this_reg].word);			\
+	}								\
+									\
+    DEBUG_PRINT2 ("  Pushing  low active reg: %ld\n", lowest_active_reg);\
+    PUSH_FAILURE_INT (lowest_active_reg);				\
+									\
+    DEBUG_PRINT2 ("  Pushing high active reg: %ld\n", highest_active_reg);\
+    PUSH_FAILURE_INT (highest_active_reg);				\
+									\
+    DEBUG_PRINT2 ("  Pushing pattern %p:\n", pattern_place);		\
+    DEBUG_PRINT_COMPILED_PATTERN (bufp, pattern_place, pend);		\
+    PUSH_FAILURE_POINTER (pattern_place);				\
+									\
+    DEBUG_PRINT2 ("  Pushing string %p: `", string_place);		\
+    DEBUG_PRINT_DOUBLE_STRING (string_place, string1, size1, string2,   \
+				 size2);				\
+    DEBUG_PRINT1 ("'\n");						\
+    PUSH_FAILURE_POINTER (string_place);				\
+									\
+    DEBUG_PRINT2 ("  Pushing failure id: %u\n", failure_id);		\
+    DEBUG_PUSH (failure_id);						\
+  } while (0)
+
+# ifndef DEFINED_ONCE
+/* This is the number of items that are pushed and popped on the stack
+   for each register.  */
+#  define NUM_REG_ITEMS  3
+
+/* Individual items aside from the registers.  */
+#  ifdef DEBUG
+#   define NUM_NONREG_ITEMS 5 /* Includes failure point id.  */
+#  else
+#   define NUM_NONREG_ITEMS 4
+#  endif
+
+/* We push at most this many items on the stack.  */
+/* We used to use (num_regs - 1), which is the number of registers
+   this regexp will save; but that was changed to 5
+   to avoid stack overflow for a regexp with lots of parens.  */
+#  define MAX_FAILURE_ITEMS (5 * NUM_REG_ITEMS + NUM_NONREG_ITEMS)
+
+/* We actually push this many items.  */
+#  define NUM_FAILURE_ITEMS				\
+  (((0							\
+     ? 0 : highest_active_reg - lowest_active_reg + 1)	\
+    * NUM_REG_ITEMS)					\
+   + NUM_NONREG_ITEMS)
+
+/* How many items can still be added to the stack without overflowing it.  */
+#  define REMAINING_AVAIL_SLOTS ((fail_stack).size - (fail_stack).avail)
+# endif /* not DEFINED_ONCE */
+
+
+/* Pops what PUSH_FAIL_STACK pushes.
+
+   We restore into the parameters, all of which should be lvalues:
+     STR -- the saved data position.
+     PAT -- the saved pattern position.
+     LOW_REG, HIGH_REG -- the highest and lowest active registers.
+     REGSTART, REGEND -- arrays of string positions.
+     REG_INFO -- array of information about each subexpression.
+
+   Also assumes the variables `fail_stack' and (if debugging), `bufp',
+   `pend', `string1', `size1', `string2', and `size2'.  */
+# define POP_FAILURE_POINT(str, pat, low_reg, high_reg, regstart, regend, reg_info)\
+{									\
+  DEBUG_STATEMENT (unsigned failure_id;)				\
+  active_reg_t this_reg;						\
+  const UCHAR_T *string_temp;						\
+									\
+  assert (!FAIL_STACK_EMPTY ());					\
+									\
+  /* Remove failure points and point to how many regs pushed.  */	\
+  DEBUG_PRINT1 ("POP_FAILURE_POINT:\n");				\
+  DEBUG_PRINT2 ("  Before pop, next avail: %d\n", fail_stack.avail);	\
+  DEBUG_PRINT2 ("                    size: %d\n", fail_stack.size);	\
+									\
+  assert (fail_stack.avail >= NUM_NONREG_ITEMS);			\
+									\
+  DEBUG_POP (&failure_id);						\
+  DEBUG_PRINT2 ("  Popping failure id: %u\n", failure_id);		\
+									\
+  /* If the saved string location is NULL, it came from an		\
+     on_failure_keep_string_jump opcode, and we want to throw away the	\
+     saved NULL, thus retaining our current position in the string.  */	\
+  string_temp = POP_FAILURE_POINTER ();					\
+  if (string_temp != NULL)						\
+    str = (const CHAR_T *) string_temp;					\
+									\
+  DEBUG_PRINT2 ("  Popping string %p: `", str);				\
+  DEBUG_PRINT_DOUBLE_STRING (str, string1, size1, string2, size2);	\
+  DEBUG_PRINT1 ("'\n");							\
+									\
+  pat = (UCHAR_T *) POP_FAILURE_POINTER ();				\
+  DEBUG_PRINT2 ("  Popping pattern %p:\n", pat);			\
+  DEBUG_PRINT_COMPILED_PATTERN (bufp, pat, pend);			\
+									\
+  /* Restore register info.  */						\
+  high_reg = (active_reg_t) POP_FAILURE_INT ();				\
+  DEBUG_PRINT2 ("  Popping high active reg: %ld\n", high_reg);		\
+									\
+  low_reg = (active_reg_t) POP_FAILURE_INT ();				\
+  DEBUG_PRINT2 ("  Popping  low active reg: %ld\n", low_reg);		\
+									\
+  if (1)								\
+    for (this_reg = high_reg; this_reg >= low_reg; this_reg--)		\
+      {									\
+	DEBUG_PRINT2 ("    Popping reg: %ld\n", this_reg);		\
+									\
+	reg_info[this_reg].word = POP_FAILURE_ELT ();			\
+	DEBUG_PRINT2 ("      info: %p\n",				\
+		      reg_info[this_reg].word.pointer);			\
+									\
+	regend[this_reg] = (const CHAR_T *) POP_FAILURE_POINTER ();	\
+	DEBUG_PRINT2 ("      end: %p\n", regend[this_reg]);		\
+									\
+	regstart[this_reg] = (const CHAR_T *) POP_FAILURE_POINTER ();	\
+	DEBUG_PRINT2 ("      start: %p\n", regstart[this_reg]);		\
+      }									\
+  else									\
+    {									\
+      for (this_reg = highest_active_reg; this_reg > high_reg; this_reg--) \
+	{								\
+	  reg_info[this_reg].word.integer = 0;				\
+	  regend[this_reg] = 0;						\
+	  regstart[this_reg] = 0;					\
+	}								\
+      highest_active_reg = high_reg;					\
+    }									\
+									\
+  set_regs_matched_done = 0;						\
+  DEBUG_STATEMENT (nfailure_points_popped++);				\
+} /* POP_FAILURE_POINT */
+
+/* Structure for per-register (a.k.a. per-group) information.
+   Other register information, such as the
+   starting and ending positions (which are addresses), and the list of
+   inner groups (which is a bits list) are maintained in separate
+   variables.
+
+   We are making a (strictly speaking) nonportable assumption here: that
+   the compiler will pack our bit fields into something that fits into
+   the type of `word', i.e., is something that fits into one item on the
+   failure stack.  */
+
+
+/* Declarations and macros for re_match_2.  */
+
+typedef union
+{
+  PREFIX(fail_stack_elt_t) word;
+  struct
+  {
+      /* This field is one if this group can match the empty string,
+         zero if not.  If not yet determined,  `MATCH_NULL_UNSET_VALUE'.  */
+# define MATCH_NULL_UNSET_VALUE 3
+    unsigned match_null_string_p : 2;
+    unsigned is_active : 1;
+    unsigned matched_something : 1;
+    unsigned ever_matched_something : 1;
+  } bits;
+} PREFIX(register_info_type);
+
+# ifndef DEFINED_ONCE
+#  define REG_MATCH_NULL_STRING_P(R)  ((R).bits.match_null_string_p)
+#  define IS_ACTIVE(R)  ((R).bits.is_active)
+#  define MATCHED_SOMETHING(R)  ((R).bits.matched_something)
+#  define EVER_MATCHED_SOMETHING(R)  ((R).bits.ever_matched_something)
+
+
+/* Call this when have matched a real character; it sets `matched' flags
+   for the subexpressions which we are currently inside.  Also records
+   that those subexprs have matched.  */
+#  define SET_REGS_MATCHED()						\
+  do									\
+    {									\
+      if (!set_regs_matched_done)					\
+	{								\
+	  active_reg_t r;						\
+	  set_regs_matched_done = 1;					\
+	  for (r = lowest_active_reg; r <= highest_active_reg; r++)	\
+	    {								\
+	      MATCHED_SOMETHING (reg_info[r])				\
+		= EVER_MATCHED_SOMETHING (reg_info[r])			\
+		= 1;							\
+	    }								\
+	}								\
+    }									\
+  while (0)
+# endif /* not DEFINED_ONCE */
+
+/* Registers are set to a sentinel when they haven't yet matched.  */
+static CHAR_T PREFIX(reg_unset_dummy);
+# define REG_UNSET_VALUE (&PREFIX(reg_unset_dummy))
+# define REG_UNSET(e) ((e) == REG_UNSET_VALUE)
+
+/* Subroutine declarations and macros for regex_compile.  */
+static void PREFIX(store_op1) (re_opcode_t op, UCHAR_T *loc, int arg);
+static void PREFIX(store_op2) (re_opcode_t op, UCHAR_T *loc,
+                               int arg1, int arg2);
+static void PREFIX(insert_op1) (re_opcode_t op, UCHAR_T *loc,
+                                int arg, UCHAR_T *end);
+static void PREFIX(insert_op2) (re_opcode_t op, UCHAR_T *loc,
+                                int arg1, int arg2, UCHAR_T *end);
+static boolean PREFIX(at_begline_loc_p) (const CHAR_T *pattern,
+                                         const CHAR_T *p,
+                                         reg_syntax_t syntax);
+static boolean PREFIX(at_endline_loc_p) (const CHAR_T *p,
+                                         const CHAR_T *pend,
+                                         reg_syntax_t syntax);
+# ifdef WCHAR
+static reg_errcode_t wcs_compile_range (CHAR_T range_start,
+                                        const CHAR_T **p_ptr,
+                                        const CHAR_T *pend,
+                                        char *translate,
+                                        reg_syntax_t syntax,
+                                        UCHAR_T *b,
+                                        CHAR_T *char_set);
+static void insert_space (int num, CHAR_T *loc, CHAR_T *end);
+# else /* BYTE */
+static reg_errcode_t byte_compile_range (unsigned int range_start,
+                                         const char **p_ptr,
+                                         const char *pend,
+                                         RE_TRANSLATE_TYPE translate,
+                                         reg_syntax_t syntax,
+                                         unsigned char *b);
+# endif /* WCHAR */
+
+/* Fetch the next character in the uncompiled pattern---translating it
+   if necessary.  Also cast from a signed character in the constant
+   string passed to us by the user to an unsigned char that we can use
+   as an array index (in, e.g., `translate').  */
+/* ifdef MBS_SUPPORT, we translate only if character <= 0xff,
+   because it is impossible to allocate 4GB array for some encodings
+   which have 4 byte character_set like UCS4.  */
+# ifndef PATFETCH
+#  ifdef WCHAR
+#   define PATFETCH(c)							\
+  do {if (p == pend) return REG_EEND;					\
+    c = (UCHAR_T) *p++;							\
+    if (translate && (c <= 0xff)) c = (UCHAR_T) translate[c];		\
+  } while (0)
+#  else /* BYTE */
+#   define PATFETCH(c)							\
+  do {if (p == pend) return REG_EEND;					\
+    c = (unsigned char) *p++;						\
+    if (translate) c = (unsigned char) translate[c];			\
+  } while (0)
+#  endif /* WCHAR */
+# endif
+
+/* Fetch the next character in the uncompiled pattern, with no
+   translation.  */
+# define PATFETCH_RAW(c)						\
+  do {if (p == pend) return REG_EEND;					\
+    c = (UCHAR_T) *p++; 	       					\
+  } while (0)
+
+/* Go backwards one character in the pattern.  */
+# define PATUNFETCH p--
+
+
+/* If `translate' is non-null, return translate[D], else just D.  We
+   cast the subscript to translate because some data is declared as
+   `char *', to avoid warnings when a string constant is passed.  But
+   when we use a character as a subscript we must make it unsigned.  */
+/* ifdef MBS_SUPPORT, we translate only if character <= 0xff,
+   because it is impossible to allocate 4GB array for some encodings
+   which have 4 byte character_set like UCS4.  */
+
+# ifndef TRANSLATE
+#  ifdef WCHAR
+#   define TRANSLATE(d) \
+  ((translate && ((UCHAR_T) (d)) <= 0xff) \
+   ? (char) translate[(unsigned char) (d)] : (d))
+# else /* BYTE */
+#   define TRANSLATE(d) \
+  (translate ? (char) translate[(unsigned char) (d)] : (char) (d))
+#  endif /* WCHAR */
+# endif
+
+
+/* Macros for outputting the compiled pattern into `buffer'.  */
+
+/* If the buffer isn't allocated when it comes in, use this.  */
+# define INIT_BUF_SIZE  (32 * sizeof(UCHAR_T))
+
+/* Make sure we have at least N more bytes of space in buffer.  */
+# ifdef WCHAR
+#  define GET_BUFFER_SPACE(n)						\
+    while (((unsigned long)b - (unsigned long)COMPILED_BUFFER_VAR	\
+            + (n)*sizeof(CHAR_T)) > bufp->allocated)			\
+      EXTEND_BUFFER ()
+# else /* BYTE */
+#  define GET_BUFFER_SPACE(n)						\
+    while ((unsigned long) (b - bufp->buffer + (n)) > bufp->allocated)	\
+      EXTEND_BUFFER ()
+# endif /* WCHAR */
+
+/* Make sure we have one more byte of buffer space and then add C to it.  */
+# define BUF_PUSH(c)							\
+  do {									\
+    GET_BUFFER_SPACE (1);						\
+    *b++ = (UCHAR_T) (c);						\
+  } while (0)
+
+
+/* Ensure we have two more bytes of buffer space and then append C1 and C2.  */
+# define BUF_PUSH_2(c1, c2)						\
+  do {									\
+    GET_BUFFER_SPACE (2);						\
+    *b++ = (UCHAR_T) (c1);						\
+    *b++ = (UCHAR_T) (c2);						\
+  } while (0)
+
+
+/* As with BUF_PUSH_2, except for three bytes.  */
+# define BUF_PUSH_3(c1, c2, c3)						\
+  do {									\
+    GET_BUFFER_SPACE (3);						\
+    *b++ = (UCHAR_T) (c1);						\
+    *b++ = (UCHAR_T) (c2);						\
+    *b++ = (UCHAR_T) (c3);						\
+  } while (0)
+
+/* Store a jump with opcode OP at LOC to location TO.  We store a
+   relative address offset by the three bytes the jump itself occupies.  */
+# define STORE_JUMP(op, loc, to) \
+ PREFIX(store_op1) (op, loc, (int) ((to) - (loc) - (1 + OFFSET_ADDRESS_SIZE)))
+
+/* Likewise, for a two-argument jump.  */
+# define STORE_JUMP2(op, loc, to, arg) \
+  PREFIX(store_op2) (op, loc, (int) ((to) - (loc) - (1 + OFFSET_ADDRESS_SIZE)), arg)
+
+/* Like `STORE_JUMP', but for inserting.  Assume `b' is the buffer end.  */
+# define INSERT_JUMP(op, loc, to) \
+  PREFIX(insert_op1) (op, loc, (int) ((to) - (loc) - (1 + OFFSET_ADDRESS_SIZE)), b)
+
+/* Like `STORE_JUMP2', but for inserting.  Assume `b' is the buffer end.  */
+# define INSERT_JUMP2(op, loc, to, arg) \
+  PREFIX(insert_op2) (op, loc, (int) ((to) - (loc) - (1 + OFFSET_ADDRESS_SIZE)),\
+	      arg, b)
+
+/* This is not an arbitrary limit: the arguments which represent offsets
+   into the pattern are two bytes long.  So if 2^16 bytes turns out to
+   be too small, many things would have to change.  */
+/* Any other compiler which, like MSC, has allocation limit below 2^16
+   bytes will have to use approach similar to what was done below for
+   MSC and drop MAX_BUF_SIZE a bit.  Otherwise you may end up
+   reallocating to 0 bytes.  Such thing is not going to work too well.
+   You have been warned!!  */
+# ifndef DEFINED_ONCE
+#  if defined _MSC_VER  && !defined WIN32
+/* Microsoft C 16-bit versions limit malloc to approx 65512 bytes.
+   The REALLOC define eliminates a flurry of conversion warnings,
+   but is not required. */
+#   define MAX_BUF_SIZE  65500L
+#   define REALLOC(p,s) realloc ((p), (size_t) (s))
+#  else
+#   define MAX_BUF_SIZE (1L << 16)
+#   define REALLOC(p,s) realloc ((p), (s))
+#  endif
+
+/* Extend the buffer by twice its current size via realloc and
+   reset the pointers that pointed into the old block to point to the
+   correct places in the new one.  If extending the buffer results in it
+   being larger than MAX_BUF_SIZE, then flag memory exhausted.  */
+#  ifndef __BOUNDED_POINTERS__
+#    define __BOUNDED_POINTERS__ 0
+#  endif
+#  if __BOUNDED_POINTERS__
+#   define SET_HIGH_BOUND(P) (__ptrhigh (P) = __ptrlow (P) + bufp->allocated)
+#   define MOVE_BUFFER_POINTER(P) \
+  (__ptrlow (P) += incr, SET_HIGH_BOUND (P), __ptrvalue (P) += incr)
+#   define ELSE_EXTEND_BUFFER_HIGH_BOUND	\
+  else						\
+    {						\
+      SET_HIGH_BOUND (b);			\
+      SET_HIGH_BOUND (begalt);			\
+      if (fixup_alt_jump)			\
+	SET_HIGH_BOUND (fixup_alt_jump);	\
+      if (laststart)				\
+	SET_HIGH_BOUND (laststart);		\
+      if (pending_exact)			\
+	SET_HIGH_BOUND (pending_exact);		\
+    }
+#  else
+#   define MOVE_BUFFER_POINTER(P) (P) += incr
+#   define ELSE_EXTEND_BUFFER_HIGH_BOUND
+#  endif
+# endif /* not DEFINED_ONCE */
+
+# ifdef WCHAR
+#  define EXTEND_BUFFER()						\
+  do {									\
+    UCHAR_T *old_buffer = COMPILED_BUFFER_VAR;				\
+    int wchar_count;							\
+    if (bufp->allocated + sizeof(UCHAR_T) > MAX_BUF_SIZE)		\
+      return REG_ESIZE;							\
+    bufp->allocated <<= 1;						\
+    if (bufp->allocated > MAX_BUF_SIZE)					\
+      bufp->allocated = MAX_BUF_SIZE;					\
+    /* How many characters the new buffer can have?  */			\
+    wchar_count = bufp->allocated / sizeof(UCHAR_T);			\
+    if (wchar_count == 0) wchar_count = 1;				\
+    /* Truncate the buffer to CHAR_T align.  */			\
+    bufp->allocated = wchar_count * sizeof(UCHAR_T);			\
+    RETALLOC (COMPILED_BUFFER_VAR, wchar_count, UCHAR_T);		\
+    bufp->buffer = (char*)COMPILED_BUFFER_VAR;				\
+    if (COMPILED_BUFFER_VAR == NULL)					\
+      return REG_ESPACE;						\
+    /* If the buffer moved, move all the pointers into it.  */		\
+    if (old_buffer != COMPILED_BUFFER_VAR)				\
+      {									\
+	int incr = COMPILED_BUFFER_VAR - old_buffer;			\
+	MOVE_BUFFER_POINTER (b);					\
+	MOVE_BUFFER_POINTER (begalt);					\
+	if (fixup_alt_jump)						\
+	  MOVE_BUFFER_POINTER (fixup_alt_jump);				\
+	if (laststart)							\
+	  MOVE_BUFFER_POINTER (laststart);				\
+	if (pending_exact)						\
+	  MOVE_BUFFER_POINTER (pending_exact);				\
+      }									\
+    ELSE_EXTEND_BUFFER_HIGH_BOUND					\
+  } while (0)
+# else /* BYTE */
+#  define EXTEND_BUFFER()						\
+  do {									\
+    UCHAR_T *old_buffer = COMPILED_BUFFER_VAR;				\
+    if (bufp->allocated == MAX_BUF_SIZE)				\
+      return REG_ESIZE;							\
+    bufp->allocated <<= 1;						\
+    if (bufp->allocated > MAX_BUF_SIZE)					\
+      bufp->allocated = MAX_BUF_SIZE;					\
+    bufp->buffer = (UCHAR_T *) REALLOC (COMPILED_BUFFER_VAR,		\
+						bufp->allocated);	\
+    if (COMPILED_BUFFER_VAR == NULL)					\
+      return REG_ESPACE;						\
+    /* If the buffer moved, move all the pointers into it.  */		\
+    if (old_buffer != COMPILED_BUFFER_VAR)				\
+      {									\
+	int incr = COMPILED_BUFFER_VAR - old_buffer;			\
+	MOVE_BUFFER_POINTER (b);					\
+	MOVE_BUFFER_POINTER (begalt);					\
+	if (fixup_alt_jump)						\
+	  MOVE_BUFFER_POINTER (fixup_alt_jump);				\
+	if (laststart)							\
+	  MOVE_BUFFER_POINTER (laststart);				\
+	if (pending_exact)						\
+	  MOVE_BUFFER_POINTER (pending_exact);				\
+      }									\
+    ELSE_EXTEND_BUFFER_HIGH_BOUND					\
+  } while (0)
+# endif /* WCHAR */
+
+# ifndef DEFINED_ONCE
+/* Since we have one byte reserved for the register number argument to
+   {start,stop}_memory, the maximum number of groups we can report
+   things about is what fits in that byte.  */
+#  define MAX_REGNUM 255
+
+/* But patterns can have more than `MAX_REGNUM' registers.  We just
+   ignore the excess.  */
+typedef unsigned regnum_t;
+
+
+/* Macros for the compile stack.  */
+
+/* Since offsets can go either forwards or backwards, this type needs to
+   be able to hold values from -(MAX_BUF_SIZE - 1) to MAX_BUF_SIZE - 1.  */
+/* int may be not enough when sizeof(int) == 2.  */
+typedef long pattern_offset_t;
+
+typedef struct
+{
+  pattern_offset_t begalt_offset;
+  pattern_offset_t fixup_alt_jump;
+  pattern_offset_t inner_group_offset;
+  pattern_offset_t laststart_offset;
+  regnum_t regnum;
+} compile_stack_elt_t;
+
+
+typedef struct
+{
+  compile_stack_elt_t *stack;
+  unsigned size;
+  unsigned avail;			/* Offset of next open position.  */
+} compile_stack_type;
+
+
+#  define INIT_COMPILE_STACK_SIZE 32
+
+#  define COMPILE_STACK_EMPTY  (compile_stack.avail == 0)
+#  define COMPILE_STACK_FULL  (compile_stack.avail == compile_stack.size)
+
+/* The next available element.  */
+#  define COMPILE_STACK_TOP (compile_stack.stack[compile_stack.avail])
+
+# endif /* not DEFINED_ONCE */
+
+/* Set the bit for character C in a list.  */
+# ifndef DEFINED_ONCE
+#  define SET_LIST_BIT(c)                               \
+  (b[((unsigned char) (c)) / BYTEWIDTH]               \
+   |= 1 << (((unsigned char) c) % BYTEWIDTH))
+# endif /* DEFINED_ONCE */
+
+/* Get the next unsigned number in the uncompiled pattern.  */
+# define GET_UNSIGNED_NUMBER(num) \
+  {									\
+    while (p != pend)							\
+      {									\
+	PATFETCH (c);							\
+	if (c < '0' || c > '9')						\
+	  break;							\
+	if (num <= RE_DUP_MAX)						\
+	  {								\
+	    if (num < 0)						\
+	      num = 0;							\
+	    num = num * 10 + c - '0';					\
+	  }								\
+      }									\
+  }
+
+# ifndef DEFINED_ONCE
+#  if WIDE_CHAR_SUPPORT
+/* The GNU C library provides support for user-defined character classes
+   and the functions from ISO C amendement 1.  */
+#   ifdef CHARCLASS_NAME_MAX
+#    define CHAR_CLASS_MAX_LENGTH CHARCLASS_NAME_MAX
+#   else
+/* This shouldn't happen but some implementation might still have this
+   problem.  Use a reasonable default value.  */
+#    define CHAR_CLASS_MAX_LENGTH 256
+#   endif
+
+#   ifdef _LIBC
+#    define IS_CHAR_CLASS(string) __wctype (string)
+#   else
+#    define IS_CHAR_CLASS(string) wctype (string)
+#   endif
+#  else
+#   define CHAR_CLASS_MAX_LENGTH  6 /* Namely, `xdigit'.  */
+
+#   define IS_CHAR_CLASS(string)					\
+   (STREQ (string, "alpha") || STREQ (string, "upper")			\
+    || STREQ (string, "lower") || STREQ (string, "digit")		\
+    || STREQ (string, "alnum") || STREQ (string, "xdigit")		\
+    || STREQ (string, "space") || STREQ (string, "print")		\
+    || STREQ (string, "punct") || STREQ (string, "graph")		\
+    || STREQ (string, "cntrl") || STREQ (string, "blank"))
+#  endif
+# endif /* DEFINED_ONCE */
+
+# ifndef MATCH_MAY_ALLOCATE
+
+/* If we cannot allocate large objects within re_match_2_internal,
+   we make the fail stack and register vectors global.
+   The fail stack, we grow to the maximum size when a regexp
+   is compiled.
+   The register vectors, we adjust in size each time we
+   compile a regexp, according to the number of registers it needs.  */
+
+static PREFIX(fail_stack_type) fail_stack;
+
+/* Size with which the following vectors are currently allocated.
+   That is so we can make them bigger as needed,
+   but never make them smaller.  */
+#  ifdef DEFINED_ONCE
+static int regs_allocated_size;
+
+static const char **     regstart, **     regend;
+static const char ** old_regstart, ** old_regend;
+static const char **best_regstart, **best_regend;
+static const char **reg_dummy;
+#  endif /* DEFINED_ONCE */
+
+static PREFIX(register_info_type) *PREFIX(reg_info);
+static PREFIX(register_info_type) *PREFIX(reg_info_dummy);
+
+/* Make the register vectors big enough for NUM_REGS registers,
+   but don't make them smaller.  */
+
+static void
+PREFIX(regex_grow_registers) (int num_regs)
+{
+  if (num_regs > regs_allocated_size)
+    {
+      RETALLOC_IF (regstart,	 num_regs, const char *);
+      RETALLOC_IF (regend,	 num_regs, const char *);
+      RETALLOC_IF (old_regstart, num_regs, const char *);
+      RETALLOC_IF (old_regend,	 num_regs, const char *);
+      RETALLOC_IF (best_regstart, num_regs, const char *);
+      RETALLOC_IF (best_regend,	 num_regs, const char *);
+      RETALLOC_IF (PREFIX(reg_info), num_regs, PREFIX(register_info_type));
+      RETALLOC_IF (reg_dummy,	 num_regs, const char *);
+      RETALLOC_IF (PREFIX(reg_info_dummy), num_regs, PREFIX(register_info_type));
+
+      regs_allocated_size = num_regs;
+    }
+}
+
+# endif /* not MATCH_MAY_ALLOCATE */
+
+# ifndef DEFINED_ONCE
+static boolean group_in_compile_stack (compile_stack_type compile_stack,
+                                       regnum_t regnum);
+# endif /* not DEFINED_ONCE */
+
+/* `regex_compile' compiles PATTERN (of length SIZE) according to SYNTAX.
+   Returns one of error codes defined in `regex.h', or zero for success.
+
+   Assumes the `allocated' (and perhaps `buffer') and `translate'
+   fields are set in BUFP on entry.
+
+   If it succeeds, results are put in BUFP (if it returns an error, the
+   contents of BUFP are undefined):
+     `buffer' is the compiled pattern;
+     `syntax' is set to SYNTAX;
+     `used' is set to the length of the compiled pattern;
+     `fastmap_accurate' is zero;
+     `re_nsub' is the number of subexpressions in PATTERN;
+     `not_bol' and `not_eol' are zero;
+
+   The `fastmap' and `newline_anchor' fields are neither
+   examined nor set.  */
+
+/* Return, freeing storage we allocated.  */
+# ifdef WCHAR
+#  define FREE_STACK_RETURN(value)		\
+  return (free(pattern), free(mbs_offset), free(is_binary), free (compile_stack.stack), value)
+# else
+#  define FREE_STACK_RETURN(value)		\
+  return (free (compile_stack.stack), value)
+# endif /* WCHAR */
+
+static reg_errcode_t
+PREFIX(regex_compile) (const char *ARG_PREFIX(pattern),
+                       size_t ARG_PREFIX(size), reg_syntax_t syntax,
+                       struct re_pattern_buffer *bufp)
+{
+  /* We fetch characters from PATTERN here.  Even though PATTERN is
+     `char *' (i.e., signed), we declare these variables as unsigned, so
+     they can be reliably used as array indices.  */
+  register UCHAR_T c, c1;
+
+#ifdef WCHAR
+  /* A temporary space to keep wchar_t pattern and compiled pattern.  */
+  CHAR_T *pattern, *COMPILED_BUFFER_VAR;
+  size_t size;
+  /* offset buffer for optimization. See convert_mbs_to_wc.  */
+  int *mbs_offset = NULL;
+  /* It hold whether each wchar_t is binary data or not.  */
+  char *is_binary = NULL;
+  /* A flag whether exactn is handling binary data or not.  */
+  char is_exactn_bin = FALSE;
+#endif /* WCHAR */
+
+  /* A random temporary spot in PATTERN.  */
+  const CHAR_T *p1;
+
+  /* Points to the end of the buffer, where we should append.  */
+  register UCHAR_T *b;
+
+  /* Keeps track of unclosed groups.  */
+  compile_stack_type compile_stack;
+
+  /* Points to the current (ending) position in the pattern.  */
+#ifdef WCHAR
+  const CHAR_T *p;
+  const CHAR_T *pend;
+#else /* BYTE */
+  const CHAR_T *p = pattern;
+  const CHAR_T *pend = pattern + size;
+#endif /* WCHAR */
+
+  /* How to translate the characters in the pattern.  */
+  RE_TRANSLATE_TYPE translate = bufp->translate;
+
+  /* Address of the count-byte of the most recently inserted `exactn'
+     command.  This makes it possible to tell if a new exact-match
+     character can be added to that command or if the character requires
+     a new `exactn' command.  */
+  UCHAR_T *pending_exact = 0;
+
+  /* Address of start of the most recently finished expression.
+     This tells, e.g., postfix * where to find the start of its
+     operand.  Reset at the beginning of groups and alternatives.  */
+  UCHAR_T *laststart = 0;
+
+  /* Address of beginning of regexp, or inside of last group.  */
+  UCHAR_T *begalt;
+
+  /* Address of the place where a forward jump should go to the end of
+     the containing expression.  Each alternative of an `or' -- except the
+     last -- ends with a forward jump of this sort.  */
+  UCHAR_T *fixup_alt_jump = 0;
+
+  /* Counts open-groups as they are encountered.  Remembered for the
+     matching close-group on the compile stack, so the same register
+     number is put in the stop_memory as the start_memory.  */
+  regnum_t regnum = 0;
+
+#ifdef WCHAR
+  /* Initialize the wchar_t PATTERN and offset_buffer.  */
+  p = pend = pattern = TALLOC(csize + 1, CHAR_T);
+  mbs_offset = TALLOC(csize + 1, int);
+  is_binary = TALLOC(csize + 1, char);
+  if (pattern == NULL || mbs_offset == NULL || is_binary == NULL)
+    {
+      free(pattern);
+      free(mbs_offset);
+      free(is_binary);
+      return REG_ESPACE;
+    }
+  pattern[csize] = L'\0';	/* sentinel */
+  size = convert_mbs_to_wcs(pattern, cpattern, csize, mbs_offset, is_binary);
+  pend = p + size;
+  if (size < 0)
+    {
+      free(pattern);
+      free(mbs_offset);
+      free(is_binary);
+      return REG_BADPAT;
+    }
+#endif
+
+#ifdef DEBUG
+  DEBUG_PRINT1 ("\nCompiling pattern: ");
+  if (debug)
+    {
+      unsigned debug_count;
+
+      for (debug_count = 0; debug_count < size; debug_count++)
+        PUT_CHAR (pattern[debug_count]);
+      putchar ('\n');
+    }
+#endif /* DEBUG */
+
+  /* Initialize the compile stack.  */
+  compile_stack.stack = TALLOC (INIT_COMPILE_STACK_SIZE, compile_stack_elt_t);
+  if (compile_stack.stack == NULL)
+    {
+#ifdef WCHAR
+      free(pattern);
+      free(mbs_offset);
+      free(is_binary);
+#endif
+      return REG_ESPACE;
+    }
+
+  compile_stack.size = INIT_COMPILE_STACK_SIZE;
+  compile_stack.avail = 0;
+
+  /* Initialize the pattern buffer.  */
+  bufp->syntax = syntax;
+  bufp->fastmap_accurate = 0;
+  bufp->not_bol = bufp->not_eol = 0;
+
+  /* Set `used' to zero, so that if we return an error, the pattern
+     printer (for debugging) will think there's no pattern.  We reset it
+     at the end.  */
+  bufp->used = 0;
+
+  /* Always count groups, whether or not bufp->no_sub is set.  */
+  bufp->re_nsub = 0;
+
+#if !defined emacs && !defined SYNTAX_TABLE
+  /* Initialize the syntax table.  */
+   init_syntax_once ();
+#endif
+
+  if (bufp->allocated == 0)
+    {
+      if (bufp->buffer)
+	{ /* If zero allocated, but buffer is non-null, try to realloc
+             enough space.  This loses if buffer's address is bogus, but
+             that is the user's responsibility.  */
+#ifdef WCHAR
+	  /* Free bufp->buffer and allocate an array for wchar_t pattern
+	     buffer.  */
+          free(bufp->buffer);
+          COMPILED_BUFFER_VAR = TALLOC (INIT_BUF_SIZE/sizeof(UCHAR_T),
+					UCHAR_T);
+#else
+          RETALLOC (COMPILED_BUFFER_VAR, INIT_BUF_SIZE, UCHAR_T);
+#endif /* WCHAR */
+        }
+      else
+        { /* Caller did not allocate a buffer.  Do it for them.  */
+          COMPILED_BUFFER_VAR = TALLOC (INIT_BUF_SIZE / sizeof(UCHAR_T),
+					UCHAR_T);
+        }
+
+      if (!COMPILED_BUFFER_VAR) FREE_STACK_RETURN (REG_ESPACE);
+#ifdef WCHAR
+      bufp->buffer = (char*)COMPILED_BUFFER_VAR;
+#endif /* WCHAR */
+      bufp->allocated = INIT_BUF_SIZE;
+    }
+#ifdef WCHAR
+  else
+    COMPILED_BUFFER_VAR = (UCHAR_T*) bufp->buffer;
+#endif
+
+  begalt = b = COMPILED_BUFFER_VAR;
+
+  /* Loop through the uncompiled pattern until we're at the end.  */
+  while (p != pend)
+    {
+      PATFETCH (c);
+
+      switch (c)
+        {
+        case '^':
+          {
+            if (   /* If at start of pattern, it's an operator.  */
+                   p == pattern + 1
+                   /* If context independent, it's an operator.  */
+                || syntax & RE_CONTEXT_INDEP_ANCHORS
+                   /* Otherwise, depends on what's come before.  */
+                || PREFIX(at_begline_loc_p) (pattern, p, syntax))
+              BUF_PUSH (begline);
+            else
+              goto normal_char;
+          }
+          break;
+
+
+        case '$':
+          {
+            if (   /* If at end of pattern, it's an operator.  */
+                   p == pend
+                   /* If context independent, it's an operator.  */
+                || syntax & RE_CONTEXT_INDEP_ANCHORS
+                   /* Otherwise, depends on what's next.  */
+                || PREFIX(at_endline_loc_p) (p, pend, syntax))
+               BUF_PUSH (endline);
+             else
+               goto normal_char;
+           }
+           break;
+
+
+	case '+':
+        case '?':
+          if ((syntax & RE_BK_PLUS_QM)
+              || (syntax & RE_LIMITED_OPS))
+            goto normal_char;
+        handle_plus:
+        case '*':
+          /* If there is no previous pattern... */
+          if (!laststart)
+            {
+              if (syntax & RE_CONTEXT_INVALID_OPS)
+                FREE_STACK_RETURN (REG_BADRPT);
+              else if (!(syntax & RE_CONTEXT_INDEP_OPS))
+                goto normal_char;
+            }
+
+          {
+            /* Are we optimizing this jump?  */
+            boolean keep_string_p = false;
+
+            /* 1 means zero (many) matches is allowed.  */
+            char zero_times_ok = 0, many_times_ok = 0;
+
+            /* If there is a sequence of repetition chars, collapse it
+               down to just one (the right one).  We can't combine
+               interval operators with these because of, e.g., `a{2}*',
+               which should only match an even number of `a's.  */
+
+            for (;;)
+              {
+                zero_times_ok |= c != '+';
+                many_times_ok |= c != '?';
+
+                if (p == pend)
+                  break;
+
+                PATFETCH (c);
+
+                if (c == '*'
+                    || (!(syntax & RE_BK_PLUS_QM) && (c == '+' || c == '?')))
+                  ;
+
+                else if (syntax & RE_BK_PLUS_QM  &&  c == '\\')
+                  {
+                    if (p == pend) FREE_STACK_RETURN (REG_EESCAPE);
+
+                    PATFETCH (c1);
+                    if (!(c1 == '+' || c1 == '?'))
+                      {
+                        PATUNFETCH;
+                        PATUNFETCH;
+                        break;
+                      }
+
+                    c = c1;
+                  }
+                else
+                  {
+                    PATUNFETCH;
+                    break;
+                  }
+
+                /* If we get here, we found another repeat character.  */
+               }
+
+            /* Star, etc. applied to an empty pattern is equivalent
+               to an empty pattern.  */
+            if (!laststart)
+              break;
+
+            /* Now we know whether or not zero matches is allowed
+               and also whether or not two or more matches is allowed.  */
+            if (many_times_ok)
+              { /* More than one repetition is allowed, so put in at the
+                   end a backward relative jump from `b' to before the next
+                   jump we're going to put in below (which jumps from
+                   laststart to after this jump).
+
+                   But if we are at the `*' in the exact sequence `.*\n',
+                   insert an unconditional jump backwards to the .,
+                   instead of the beginning of the loop.  This way we only
+                   push a failure point once, instead of every time
+                   through the loop.  */
+                assert (p - 1 > pattern);
+
+                /* Allocate the space for the jump.  */
+                GET_BUFFER_SPACE (1 + OFFSET_ADDRESS_SIZE);
+
+                /* We know we are not at the first character of the pattern,
+                   because laststart was nonzero.  And we've already
+                   incremented `p', by the way, to be the character after
+                   the `*'.  Do we have to do something analogous here
+                   for null bytes, because of RE_DOT_NOT_NULL?  */
+                if (TRANSLATE (*(p - 2)) == TRANSLATE ('.')
+		    && zero_times_ok
+                    && p < pend && TRANSLATE (*p) == TRANSLATE ('\n')
+                    && !(syntax & RE_DOT_NEWLINE))
+                  { /* We have .*\n.  */
+                    STORE_JUMP (jump, b, laststart);
+                    keep_string_p = true;
+                  }
+                else
+                  /* Anything else.  */
+                  STORE_JUMP (maybe_pop_jump, b, laststart -
+			      (1 + OFFSET_ADDRESS_SIZE));
+
+                /* We've added more stuff to the buffer.  */
+                b += 1 + OFFSET_ADDRESS_SIZE;
+              }
+
+            /* On failure, jump from laststart to b + 3, which will be the
+               end of the buffer after this jump is inserted.  */
+	    /* ifdef WCHAR, 'b + 1 + OFFSET_ADDRESS_SIZE' instead of
+	       'b + 3'.  */
+            GET_BUFFER_SPACE (1 + OFFSET_ADDRESS_SIZE);
+            INSERT_JUMP (keep_string_p ? on_failure_keep_string_jump
+                                       : on_failure_jump,
+                         laststart, b + 1 + OFFSET_ADDRESS_SIZE);
+            pending_exact = 0;
+            b += 1 + OFFSET_ADDRESS_SIZE;
+
+            if (!zero_times_ok)
+              {
+                /* At least one repetition is required, so insert a
+                   `dummy_failure_jump' before the initial
+                   `on_failure_jump' instruction of the loop. This
+                   effects a skip over that instruction the first time
+                   we hit that loop.  */
+                GET_BUFFER_SPACE (1 + OFFSET_ADDRESS_SIZE);
+                INSERT_JUMP (dummy_failure_jump, laststart, laststart +
+			     2 + 2 * OFFSET_ADDRESS_SIZE);
+                b += 1 + OFFSET_ADDRESS_SIZE;
+              }
+            }
+	  break;
+
+
+	case '.':
+          laststart = b;
+          BUF_PUSH (anychar);
+          break;
+
+
+        case '[':
+          {
+            boolean had_char_class = false;
+#ifdef WCHAR
+	    CHAR_T range_start = 0xffffffff;
+#else
+	    unsigned int range_start = 0xffffffff;
+#endif
+            if (p == pend) FREE_STACK_RETURN (REG_EBRACK);
+
+#ifdef WCHAR
+	    /* We assume a charset(_not) structure as a wchar_t array.
+	       charset[0] = (re_opcode_t) charset(_not)
+               charset[1] = l (= length of char_classes)
+               charset[2] = m (= length of collating_symbols)
+               charset[3] = n (= length of equivalence_classes)
+	       charset[4] = o (= length of char_ranges)
+	       charset[5] = p (= length of chars)
+
+               charset[6] = char_class (wctype_t)
+               charset[6+CHAR_CLASS_SIZE] = char_class (wctype_t)
+                         ...
+               charset[l+5]  = char_class (wctype_t)
+
+               charset[l+6]  = collating_symbol (wchar_t)
+                            ...
+               charset[l+m+5]  = collating_symbol (wchar_t)
+					ifdef _LIBC we use the index if
+					_NL_COLLATE_SYMB_EXTRAMB instead of
+					wchar_t string.
+
+               charset[l+m+6]  = equivalence_classes (wchar_t)
+                              ...
+               charset[l+m+n+5]  = equivalence_classes (wchar_t)
+					ifdef _LIBC we use the index in
+					_NL_COLLATE_WEIGHT instead of
+					wchar_t string.
+
+	       charset[l+m+n+6] = range_start
+	       charset[l+m+n+7] = range_end
+	                       ...
+	       charset[l+m+n+2o+4] = range_start
+	       charset[l+m+n+2o+5] = range_end
+					ifdef _LIBC we use the value looked up
+					in _NL_COLLATE_COLLSEQ instead of
+					wchar_t character.
+
+	       charset[l+m+n+2o+6] = char
+	                          ...
+	       charset[l+m+n+2o+p+5] = char
+
+	     */
+
+	    /* We need at least 6 spaces: the opcode, the length of
+               char_classes, the length of collating_symbols, the length of
+               equivalence_classes, the length of char_ranges, the length of
+               chars.  */
+	    GET_BUFFER_SPACE (6);
+
+	    /* Save b as laststart. And We use laststart as the pointer
+	       to the first element of the charset here.
+	       In other words, laststart[i] indicates charset[i].  */
+            laststart = b;
+
+            /* We test `*p == '^' twice, instead of using an if
+               statement, so we only need one BUF_PUSH.  */
+            BUF_PUSH (*p == '^' ? charset_not : charset);
+            if (*p == '^')
+              p++;
+
+            /* Push the length of char_classes, the length of
+               collating_symbols, the length of equivalence_classes, the
+               length of char_ranges and the length of chars.  */
+            BUF_PUSH_3 (0, 0, 0);
+            BUF_PUSH_2 (0, 0);
+
+            /* Remember the first position in the bracket expression.  */
+            p1 = p;
+
+            /* charset_not matches newline according to a syntax bit.  */
+            if ((re_opcode_t) b[-6] == charset_not
+                && (syntax & RE_HAT_LISTS_NOT_NEWLINE))
+	      {
+		BUF_PUSH('\n');
+		laststart[5]++; /* Update the length of characters  */
+	      }
+
+            /* Read in characters and ranges, setting map bits.  */
+            for (;;)
+              {
+                if (p == pend) FREE_STACK_RETURN (REG_EBRACK);
+
+                PATFETCH (c);
+
+                /* \ might escape characters inside [...] and [^...].  */
+                if ((syntax & RE_BACKSLASH_ESCAPE_IN_LISTS) && c == '\\')
+                  {
+                    if (p == pend) FREE_STACK_RETURN (REG_EESCAPE);
+
+                    PATFETCH (c1);
+		    BUF_PUSH(c1);
+		    laststart[5]++; /* Update the length of chars  */
+		    range_start = c1;
+                    continue;
+                  }
+
+                /* Could be the end of the bracket expression.  If it's
+                   not (i.e., when the bracket expression is `[]' so
+                   far), the ']' character bit gets set way below.  */
+                if (c == ']' && p != p1 + 1)
+                  break;
+
+                /* Look ahead to see if it's a range when the last thing
+                   was a character class.  */
+                if (had_char_class && c == '-' && *p != ']')
+                  FREE_STACK_RETURN (REG_ERANGE);
+
+                /* Look ahead to see if it's a range when the last thing
+                   was a character: if this is a hyphen not at the
+                   beginning or the end of a list, then it's the range
+                   operator.  */
+                if (c == '-'
+                    && !(p - 2 >= pattern && p[-2] == '[')
+                    && !(p - 3 >= pattern && p[-3] == '[' && p[-2] == '^')
+                    && *p != ']')
+                  {
+                    reg_errcode_t ret;
+		    /* Allocate the space for range_start and range_end.  */
+		    GET_BUFFER_SPACE (2);
+		    /* Update the pointer to indicate end of buffer.  */
+                    b += 2;
+                    ret = wcs_compile_range (range_start, &p, pend, translate,
+                                         syntax, b, laststart);
+                    if (ret != REG_NOERROR) FREE_STACK_RETURN (ret);
+                    range_start = 0xffffffff;
+                  }
+                else if (p[0] == '-' && p[1] != ']')
+                  { /* This handles ranges made up of characters only.  */
+                    reg_errcode_t ret;
+
+		    /* Move past the `-'.  */
+                    PATFETCH (c1);
+		    /* Allocate the space for range_start and range_end.  */
+		    GET_BUFFER_SPACE (2);
+		    /* Update the pointer to indicate end of buffer.  */
+                    b += 2;
+                    ret = wcs_compile_range (c, &p, pend, translate, syntax, b,
+                                         laststart);
+                    if (ret != REG_NOERROR) FREE_STACK_RETURN (ret);
+		    range_start = 0xffffffff;
+                  }
+
+                /* See if we're at the beginning of a possible character
+                   class.  */
+                else if (syntax & RE_CHAR_CLASSES && c == '[' && *p == ':')
+                  { /* Leave room for the null.  */
+                    char str[CHAR_CLASS_MAX_LENGTH + 1];
+
+                    PATFETCH (c);
+                    c1 = 0;
+
+                    /* If pattern is `[[:'.  */
+                    if (p == pend) FREE_STACK_RETURN (REG_EBRACK);
+
+                    for (;;)
+                      {
+                        PATFETCH (c);
+                        if ((c == ':' && *p == ']') || p == pend)
+                          break;
+			if (c1 < CHAR_CLASS_MAX_LENGTH)
+			  str[c1++] = c;
+			else
+			  /* This is in any case an invalid class name.  */
+			  str[0] = '\0';
+                      }
+                    str[c1] = '\0';
+
+                    /* If isn't a word bracketed by `[:' and `:]':
+                       undo the ending character, the letters, and leave
+                       the leading `:' and `[' (but store them as character).  */
+                    if (c == ':' && *p == ']')
+                      {
+			wctype_t wt;
+			uintptr_t alignedp;
+
+			/* Query the character class as wctype_t.  */
+			wt = IS_CHAR_CLASS (str);
+			if (wt == 0)
+			  FREE_STACK_RETURN (REG_ECTYPE);
+
+                        /* Throw away the ] at the end of the character
+                           class.  */
+                        PATFETCH (c);
+
+                        if (p == pend) FREE_STACK_RETURN (REG_EBRACK);
+
+			/* Allocate the space for character class.  */
+                        GET_BUFFER_SPACE(CHAR_CLASS_SIZE);
+			/* Update the pointer to indicate end of buffer.  */
+                        b += CHAR_CLASS_SIZE;
+			/* Move data which follow character classes
+			    not to violate the data.  */
+                        insert_space(CHAR_CLASS_SIZE,
+				     laststart + 6 + laststart[1],
+				     b - 1);
+			alignedp = ((uintptr_t)(laststart + 6 + laststart[1])
+				    + __alignof__(wctype_t) - 1)
+			  	    & ~(uintptr_t)(__alignof__(wctype_t) - 1);
+			/* Store the character class.  */
+                        *((wctype_t*)alignedp) = wt;
+                        /* Update length of char_classes */
+                        laststart[1] += CHAR_CLASS_SIZE;
+
+                        had_char_class = true;
+                      }
+                    else
+                      {
+                        c1++;
+                        while (c1--)
+                          PATUNFETCH;
+                        BUF_PUSH ('[');
+                        BUF_PUSH (':');
+                        laststart[5] += 2; /* Update the length of characters  */
+			range_start = ':';
+                        had_char_class = false;
+                      }
+                  }
+                else if (syntax & RE_CHAR_CLASSES && c == '[' && (*p == '='
+							  || *p == '.'))
+		  {
+		    CHAR_T str[128];	/* Should be large enough.  */
+		    CHAR_T delim = *p; /* '=' or '.'  */
+# ifdef _LIBC
+		    uint32_t nrules =
+		      _NL_CURRENT_WORD (LC_COLLATE, _NL_COLLATE_NRULES);
+# endif
+		    PATFETCH (c);
+		    c1 = 0;
+
+		    /* If pattern is `[[=' or '[[.'.  */
+		    if (p == pend) FREE_STACK_RETURN (REG_EBRACK);
+
+		    for (;;)
+		      {
+			PATFETCH (c);
+			if ((c == delim && *p == ']') || p == pend)
+			  break;
+			if (c1 < sizeof (str) - 1)
+			  str[c1++] = c;
+			else
+			  /* This is in any case an invalid class name.  */
+			  str[0] = '\0';
+                      }
+		    str[c1] = '\0';
+
+		    if (c == delim && *p == ']' && str[0] != '\0')
+		      {
+                        unsigned int i, offset;
+			/* If we have no collation data we use the default
+			   collation in which each character is in a class
+			   by itself.  It also means that ASCII is the
+			   character set and therefore we cannot have character
+			   with more than one byte in the multibyte
+			   representation.  */
+
+                        /* If not defined _LIBC, we push the name and
+			   `\0' for the sake of matching performance.  */
+			int datasize = c1 + 1;
+
+# ifdef _LIBC
+			int32_t idx = 0;
+			if (nrules == 0)
+# endif
+			  {
+			    if (c1 != 1)
+			      FREE_STACK_RETURN (REG_ECOLLATE);
+			  }
+# ifdef _LIBC
+			else
+			  {
+			    const int32_t *table;
+			    const int32_t *weights;
+			    const int32_t *extra;
+			    const int32_t *indirect;
+			    wint_t *cp;
+
+			    if(delim == '=')
+			      {
+				/* We push the index for equivalence class.  */
+				cp = (wint_t*)str;
+
+				table = (const int32_t *)
+				  _NL_CURRENT (LC_COLLATE,
+					       _NL_COLLATE_TABLEWC);
+				weights = (const int32_t *)
+				  _NL_CURRENT (LC_COLLATE,
+					       _NL_COLLATE_WEIGHTWC);
+				extra = (const wint_t *)
+				  _NL_CURRENT (LC_COLLATE,
+					       _NL_COLLATE_EXTRAWC);
+				indirect = (const int32_t *)
+				  _NL_CURRENT (LC_COLLATE,
+					       _NL_COLLATE_INDIRECTWC);
+
+				idx = FINDIDX (table, indirect, extra, &cp, 1);
+				if (idx == 0 || cp < (wint_t*) str + c1)
+				  /* This is no valid character.  */
+				  FREE_STACK_RETURN (REG_ECOLLATE);
+
+				str[0] = (wchar_t)idx;
+			      }
+			    else /* delim == '.' */
+			      {
+				/* We push collation sequence value
+				   for collating symbol.  */
+				int32_t table_size;
+				const int32_t *symb_table;
+				const unsigned char *extra;
+				int32_t idx;
+				int32_t elem;
+				int32_t second;
+				int32_t hash;
+				char char_str[c1];
+
+				/* We have to convert the name to a single-byte
+				   string.  This is possible since the names
+				   consist of ASCII characters and the internal
+				   representation is UCS4.  */
+				for (i = 0; i < c1; ++i)
+				  char_str[i] = str[i];
+
+				table_size =
+				  _NL_CURRENT_WORD (LC_COLLATE,
+						    _NL_COLLATE_SYMB_HASH_SIZEMB);
+				symb_table = (const int32_t *)
+				  _NL_CURRENT (LC_COLLATE,
+					       _NL_COLLATE_SYMB_TABLEMB);
+				extra = (const unsigned char *)
+				  _NL_CURRENT (LC_COLLATE,
+					       _NL_COLLATE_SYMB_EXTRAMB);
+
+				/* Locate the character in the hashing table.  */
+				hash = elem_hash (char_str, c1);
+
+				idx = 0;
+				elem = hash % table_size;
+				second = hash % (table_size - 2);
+				while (symb_table[2 * elem] != 0)
+				  {
+				    /* First compare the hashing value.  */
+				    if (symb_table[2 * elem] == hash
+					&& c1 == extra[symb_table[2 * elem + 1]]
+					&& memcmp (char_str,
+						   &extra[symb_table[2 * elem + 1]
+							 + 1], c1) == 0)
+				      {
+					/* Yep, this is the entry.  */
+					idx = symb_table[2 * elem + 1];
+					idx += 1 + extra[idx];
+					break;
+				      }
+
+				    /* Next entry.  */
+				    elem += second;
+				  }
+
+				if (symb_table[2 * elem] != 0)
+				  {
+				    /* Compute the index of the byte sequence
+				       in the table.  */
+				    idx += 1 + extra[idx];
+				    /* Adjust for the alignment.  */
+				    idx = (idx + 3) & ~3;
+
+				    str[0] = (wchar_t) idx + 4;
+				  }
+				else if (symb_table[2 * elem] == 0 && c1 == 1)
+				  {
+				    /* No valid character.  Match it as a
+				       single byte character.  */
+				    had_char_class = false;
+				    BUF_PUSH(str[0]);
+				    /* Update the length of characters  */
+				    laststart[5]++;
+				    range_start = str[0];
+
+				    /* Throw away the ] at the end of the
+				       collating symbol.  */
+				    PATFETCH (c);
+				    /* exit from the switch block.  */
+				    continue;
+				  }
+				else
+				  FREE_STACK_RETURN (REG_ECOLLATE);
+			      }
+			    datasize = 1;
+			  }
+# endif
+                        /* Throw away the ] at the end of the equivalence
+                           class (or collating symbol).  */
+                        PATFETCH (c);
+
+			/* Allocate the space for the equivalence class
+			   (or collating symbol) (and '\0' if needed).  */
+                        GET_BUFFER_SPACE(datasize);
+			/* Update the pointer to indicate end of buffer.  */
+                        b += datasize;
+
+			if (delim == '=')
+			  { /* equivalence class  */
+			    /* Calculate the offset of char_ranges,
+			       which is next to equivalence_classes.  */
+			    offset = laststart[1] + laststart[2]
+			      + laststart[3] +6;
+			    /* Insert space.  */
+			    insert_space(datasize, laststart + offset, b - 1);
+
+			    /* Write the equivalence_class and \0.  */
+			    for (i = 0 ; i < datasize ; i++)
+			      laststart[offset + i] = str[i];
+
+			    /* Update the length of equivalence_classes.  */
+			    laststart[3] += datasize;
+			    had_char_class = true;
+			  }
+			else /* delim == '.' */
+			  { /* collating symbol  */
+			    /* Calculate the offset of the equivalence_classes,
+			       which is next to collating_symbols.  */
+			    offset = laststart[1] + laststart[2] + 6;
+			    /* Insert space and write the collationg_symbol
+			       and \0.  */
+			    insert_space(datasize, laststart + offset, b-1);
+			    for (i = 0 ; i < datasize ; i++)
+			      laststart[offset + i] = str[i];
+
+			    /* In re_match_2_internal if range_start < -1, we
+			       assume -range_start is the offset of the
+			       collating symbol which is specified as
+			       the character of the range start.  So we assign
+			       -(laststart[1] + laststart[2] + 6) to
+			       range_start.  */
+			    range_start = -(laststart[1] + laststart[2] + 6);
+			    /* Update the length of collating_symbol.  */
+			    laststart[2] += datasize;
+			    had_char_class = false;
+			  }
+		      }
+                    else
+                      {
+                        c1++;
+                        while (c1--)
+                          PATUNFETCH;
+                        BUF_PUSH ('[');
+                        BUF_PUSH (delim);
+                        laststart[5] += 2; /* Update the length of characters  */
+			range_start = delim;
+                        had_char_class = false;
+                      }
+		  }
+                else
+                  {
+                    had_char_class = false;
+		    BUF_PUSH(c);
+		    laststart[5]++;  /* Update the length of characters  */
+		    range_start = c;
+                  }
+	      }
+
+#else /* BYTE */
+            /* Ensure that we have enough space to push a charset: the
+               opcode, the length count, and the bitset; 34 bytes in all.  */
+	    GET_BUFFER_SPACE (34);
+
+            laststart = b;
+
+            /* We test `*p == '^' twice, instead of using an if
+               statement, so we only need one BUF_PUSH.  */
+            BUF_PUSH (*p == '^' ? charset_not : charset);
+            if (*p == '^')
+              p++;
+
+            /* Remember the first position in the bracket expression.  */
+            p1 = p;
+
+            /* Push the number of bytes in the bitmap.  */
+            BUF_PUSH ((1 << BYTEWIDTH) / BYTEWIDTH);
+
+            /* Clear the whole map.  */
+            bzero (b, (1 << BYTEWIDTH) / BYTEWIDTH);
+
+            /* charset_not matches newline according to a syntax bit.  */
+            if ((re_opcode_t) b[-2] == charset_not
+                && (syntax & RE_HAT_LISTS_NOT_NEWLINE))
+              SET_LIST_BIT ('\n');
+
+            /* Read in characters and ranges, setting map bits.  */
+            for (;;)
+              {
+                if (p == pend) FREE_STACK_RETURN (REG_EBRACK);
+
+                PATFETCH (c);
+
+                /* \ might escape characters inside [...] and [^...].  */
+                if ((syntax & RE_BACKSLASH_ESCAPE_IN_LISTS) && c == '\\')
+                  {
+                    if (p == pend) FREE_STACK_RETURN (REG_EESCAPE);
+
+                    PATFETCH (c1);
+                    SET_LIST_BIT (c1);
+		    range_start = c1;
+                    continue;
+                  }
+
+                /* Could be the end of the bracket expression.  If it's
+                   not (i.e., when the bracket expression is `[]' so
+                   far), the ']' character bit gets set way below.  */
+                if (c == ']' && p != p1 + 1)
+                  break;
+
+                /* Look ahead to see if it's a range when the last thing
+                   was a character class.  */
+                if (had_char_class && c == '-' && *p != ']')
+                  FREE_STACK_RETURN (REG_ERANGE);
+
+                /* Look ahead to see if it's a range when the last thing
+                   was a character: if this is a hyphen not at the
+                   beginning or the end of a list, then it's the range
+                   operator.  */
+                if (c == '-'
+                    && !(p - 2 >= pattern && p[-2] == '[')
+                    && !(p - 3 >= pattern && p[-3] == '[' && p[-2] == '^')
+                    && *p != ']')
+                  {
+                    reg_errcode_t ret
+                      = byte_compile_range (range_start, &p, pend, translate,
+					    syntax, b);
+                    if (ret != REG_NOERROR) FREE_STACK_RETURN (ret);
+		    range_start = 0xffffffff;
+                  }
+
+                else if (p[0] == '-' && p[1] != ']')
+                  { /* This handles ranges made up of characters only.  */
+                    reg_errcode_t ret;
+
+		    /* Move past the `-'.  */
+                    PATFETCH (c1);
+
+                    ret = byte_compile_range (c, &p, pend, translate, syntax, b);
+                    if (ret != REG_NOERROR) FREE_STACK_RETURN (ret);
+		    range_start = 0xffffffff;
+                  }
+
+                /* See if we're at the beginning of a possible character
+                   class.  */
+
+                else if (syntax & RE_CHAR_CLASSES && c == '[' && *p == ':')
+                  { /* Leave room for the null.  */
+                    char str[CHAR_CLASS_MAX_LENGTH + 1];
+
+                    PATFETCH (c);
+                    c1 = 0;
+
+                    /* If pattern is `[[:'.  */
+                    if (p == pend) FREE_STACK_RETURN (REG_EBRACK);
+
+                    for (;;)
+                      {
+                        PATFETCH (c);
+                        if ((c == ':' && *p == ']') || p == pend)
+                          break;
+			if (((int) c1) < CHAR_CLASS_MAX_LENGTH)
+			  str[c1++] = c;
+			else
+			  /* This is in any case an invalid class name.  */
+			  str[0] = '\0';
+                      }
+                    str[c1] = '\0';
+
+                    /* If isn't a word bracketed by `[:' and `:]':
+                       undo the ending character, the letters, and leave
+                       the leading `:' and `[' (but set bits for them).  */
+                    if (c == ':' && *p == ']')
+                      {
+# if WIDE_CHAR_SUPPORT
+                        boolean is_lower = STREQ (str, "lower");
+                        boolean is_upper = STREQ (str, "upper");
+			wctype_t wt;
+                        int ch;
+
+			wt = IS_CHAR_CLASS (str);
+			if (wt == 0)
+			  FREE_STACK_RETURN (REG_ECTYPE);
+
+                        /* Throw away the ] at the end of the character
+                           class.  */
+                        PATFETCH (c);
+
+                        if (p == pend) FREE_STACK_RETURN (REG_EBRACK);
+
+                        for (ch = 0; ch < 1 << BYTEWIDTH; ++ch)
+			  {
+#  ifdef _LIBC
+			    if (__iswctype (__btowc (ch), wt))
+			      SET_LIST_BIT (ch);
+#  else
+			    if (iswctype (btowc (ch), wt))
+			      SET_LIST_BIT (ch);
+#  endif
+
+			    if (translate && (is_upper || is_lower)
+				&& (ISUPPER (ch) || ISLOWER (ch)))
+			      SET_LIST_BIT (ch);
+			  }
+
+                        had_char_class = true;
+# else
+                        int ch;
+                        boolean is_alnum = STREQ (str, "alnum");
+                        boolean is_alpha = STREQ (str, "alpha");
+                        boolean is_blank = STREQ (str, "blank");
+                        boolean is_cntrl = STREQ (str, "cntrl");
+                        boolean is_digit = STREQ (str, "digit");
+                        boolean is_graph = STREQ (str, "graph");
+                        boolean is_lower = STREQ (str, "lower");
+                        boolean is_print = STREQ (str, "print");
+                        boolean is_punct = STREQ (str, "punct");
+                        boolean is_space = STREQ (str, "space");
+                        boolean is_upper = STREQ (str, "upper");
+                        boolean is_xdigit = STREQ (str, "xdigit");
+
+                        if (!IS_CHAR_CLASS (str))
+			  FREE_STACK_RETURN (REG_ECTYPE);
+
+                        /* Throw away the ] at the end of the character
+                           class.  */
+                        PATFETCH (c);
+
+                        if (p == pend) FREE_STACK_RETURN (REG_EBRACK);
+
+                        for (ch = 0; ch < 1 << BYTEWIDTH; ch++)
+                          {
+			    /* This was split into 3 if's to
+			       avoid an arbitrary limit in some compiler.  */
+                            if (   (is_alnum  && ISALNUM (ch))
+                                || (is_alpha  && ISALPHA (ch))
+                                || (is_blank  && ISBLANK (ch))
+                                || (is_cntrl  && ISCNTRL (ch)))
+			      SET_LIST_BIT (ch);
+			    if (   (is_digit  && ISDIGIT (ch))
+                                || (is_graph  && ISGRAPH (ch))
+                                || (is_lower  && ISLOWER (ch))
+                                || (is_print  && ISPRINT (ch)))
+			      SET_LIST_BIT (ch);
+			    if (   (is_punct  && ISPUNCT (ch))
+                                || (is_space  && ISSPACE (ch))
+                                || (is_upper  && ISUPPER (ch))
+                                || (is_xdigit && ISXDIGIT (ch)))
+			      SET_LIST_BIT (ch);
+			    if (   translate && (is_upper || is_lower)
+				&& (ISUPPER (ch) || ISLOWER (ch)))
+			      SET_LIST_BIT (ch);
+                          }
+                        had_char_class = true;
+# endif	/* libc || wctype.h */
+                      }
+                    else
+                      {
+                        c1++;
+                        while (c1--)
+                          PATUNFETCH;
+                        SET_LIST_BIT ('[');
+                        SET_LIST_BIT (':');
+			range_start = ':';
+                        had_char_class = false;
+                      }
+                  }
+                else if (syntax & RE_CHAR_CLASSES && c == '[' && *p == '=')
+		  {
+		    unsigned char str[MB_LEN_MAX + 1];
+# ifdef _LIBC
+		    uint32_t nrules =
+		      _NL_CURRENT_WORD (LC_COLLATE, _NL_COLLATE_NRULES);
+# endif
+
+		    PATFETCH (c);
+		    c1 = 0;
+
+		    /* If pattern is `[[='.  */
+		    if (p == pend) FREE_STACK_RETURN (REG_EBRACK);
+
+		    for (;;)
+		      {
+			PATFETCH (c);
+			if ((c == '=' && *p == ']') || p == pend)
+			  break;
+			if (c1 < MB_LEN_MAX)
+			  str[c1++] = c;
+			else
+			  /* This is in any case an invalid class name.  */
+			  str[0] = '\0';
+                      }
+		    str[c1] = '\0';
+
+		    if (c == '=' && *p == ']' && str[0] != '\0')
+		      {
+			/* If we have no collation data we use the default
+			   collation in which each character is in a class
+			   by itself.  It also means that ASCII is the
+			   character set and therefore we cannot have character
+			   with more than one byte in the multibyte
+			   representation.  */
+# ifdef _LIBC
+			if (nrules == 0)
+# endif
+			  {
+			    if (c1 != 1)
+			      FREE_STACK_RETURN (REG_ECOLLATE);
+
+			    /* Throw away the ] at the end of the equivalence
+			       class.  */
+			    PATFETCH (c);
+
+			    /* Set the bit for the character.  */
+			    SET_LIST_BIT (str[0]);
+			  }
+# ifdef _LIBC
+			else
+			  {
+			    /* Try to match the byte sequence in `str' against
+			       those known to the collate implementation.
+			       First find out whether the bytes in `str' are
+			       actually from exactly one character.  */
+			    const int32_t *table;
+			    const unsigned char *weights;
+			    const unsigned char *extra;
+			    const int32_t *indirect;
+			    int32_t idx;
+			    const unsigned char *cp = str;
+			    int ch;
+
+			    table = (const int32_t *)
+			      _NL_CURRENT (LC_COLLATE, _NL_COLLATE_TABLEMB);
+			    weights = (const unsigned char *)
+			      _NL_CURRENT (LC_COLLATE, _NL_COLLATE_WEIGHTMB);
+			    extra = (const unsigned char *)
+			      _NL_CURRENT (LC_COLLATE, _NL_COLLATE_EXTRAMB);
+			    indirect = (const int32_t *)
+			      _NL_CURRENT (LC_COLLATE, _NL_COLLATE_INDIRECTMB);
+			    idx = FINDIDX (table, indirect, extra, &cp, 1);
+			    if (idx == 0 || cp < str + c1)
+			      /* This is no valid character.  */
+			      FREE_STACK_RETURN (REG_ECOLLATE);
+
+			    /* Throw away the ] at the end of the equivalence
+			       class.  */
+			    PATFETCH (c);
+
+			    /* Now we have to go throught the whole table
+			       and find all characters which have the same
+			       first level weight.
+
+			       XXX Note that this is not entirely correct.
+			       we would have to match multibyte sequences
+			       but this is not possible with the current
+			       implementation.  */
+			    for (ch = 1; ch < 256; ++ch)
+			      /* XXX This test would have to be changed if we
+				 would allow matching multibyte sequences.  */
+			      if (table[ch] > 0)
+				{
+				  int32_t idx2 = table[ch];
+				  size_t len = weights[idx2];
+
+				  /* Test whether the lenghts match.  */
+				  if (weights[idx] == len)
+				    {
+				      /* They do.  New compare the bytes of
+					 the weight.  */
+				      size_t cnt = 0;
+
+				      while (cnt < len
+					     && (weights[idx + 1 + cnt]
+						 == weights[idx2 + 1 + cnt]))
+					++cnt;
+
+				      if (cnt == len)
+					/* They match.  Mark the character as
+					   acceptable.  */
+					SET_LIST_BIT (ch);
+				    }
+				}
+			  }
+# endif
+			had_char_class = true;
+		      }
+                    else
+                      {
+                        c1++;
+                        while (c1--)
+                          PATUNFETCH;
+                        SET_LIST_BIT ('[');
+                        SET_LIST_BIT ('=');
+			range_start = '=';
+                        had_char_class = false;
+                      }
+		  }
+                else if (syntax & RE_CHAR_CLASSES && c == '[' && *p == '.')
+		  {
+		    unsigned char str[128];	/* Should be large enough.  */
+# ifdef _LIBC
+		    uint32_t nrules =
+		      _NL_CURRENT_WORD (LC_COLLATE, _NL_COLLATE_NRULES);
+# endif
+
+		    PATFETCH (c);
+		    c1 = 0;
+
+		    /* If pattern is `[[.'.  */
+		    if (p == pend) FREE_STACK_RETURN (REG_EBRACK);
+
+		    for (;;)
+		      {
+			PATFETCH (c);
+			if ((c == '.' && *p == ']') || p == pend)
+			  break;
+			if (c1 < sizeof (str))
+			  str[c1++] = c;
+			else
+			  /* This is in any case an invalid class name.  */
+			  str[0] = '\0';
+                      }
+		    str[c1] = '\0';
+
+		    if (c == '.' && *p == ']' && str[0] != '\0')
+		      {
+			/* If we have no collation data we use the default
+			   collation in which each character is the name
+			   for its own class which contains only the one
+			   character.  It also means that ASCII is the
+			   character set and therefore we cannot have character
+			   with more than one byte in the multibyte
+			   representation.  */
+# ifdef _LIBC
+			if (nrules == 0)
+# endif
+			  {
+			    if (c1 != 1)
+			      FREE_STACK_RETURN (REG_ECOLLATE);
+
+			    /* Throw away the ] at the end of the equivalence
+			       class.  */
+			    PATFETCH (c);
+
+			    /* Set the bit for the character.  */
+			    SET_LIST_BIT (str[0]);
+			    range_start = ((const unsigned char *) str)[0];
+			  }
+# ifdef _LIBC
+			else
+			  {
+			    /* Try to match the byte sequence in `str' against
+			       those known to the collate implementation.
+			       First find out whether the bytes in `str' are
+			       actually from exactly one character.  */
+			    int32_t table_size;
+			    const int32_t *symb_table;
+			    const unsigned char *extra;
+			    int32_t idx;
+			    int32_t elem;
+			    int32_t second;
+			    int32_t hash;
+
+			    table_size =
+			      _NL_CURRENT_WORD (LC_COLLATE,
+						_NL_COLLATE_SYMB_HASH_SIZEMB);
+			    symb_table = (const int32_t *)
+			      _NL_CURRENT (LC_COLLATE,
+					   _NL_COLLATE_SYMB_TABLEMB);
+			    extra = (const unsigned char *)
+			      _NL_CURRENT (LC_COLLATE,
+					   _NL_COLLATE_SYMB_EXTRAMB);
+
+			    /* Locate the character in the hashing table.  */
+			    hash = elem_hash ((const char *) str, c1);
+
+			    idx = 0;
+			    elem = hash % table_size;
+			    second = hash % (table_size - 2);
+			    while (symb_table[2 * elem] != 0)
+			      {
+				/* First compare the hashing value.  */
+				if (symb_table[2 * elem] == hash
+				    && c1 == extra[symb_table[2 * elem + 1]]
+				    && memcmp (str,
+					       &extra[symb_table[2 * elem + 1]
+						     + 1],
+					       c1) == 0)
+				  {
+				    /* Yep, this is the entry.  */
+				    idx = symb_table[2 * elem + 1];
+				    idx += 1 + extra[idx];
+				    break;
+				  }
+
+				/* Next entry.  */
+				elem += second;
+			      }
+
+			    if (symb_table[2 * elem] == 0)
+			      /* This is no valid character.  */
+			      FREE_STACK_RETURN (REG_ECOLLATE);
+
+			    /* Throw away the ] at the end of the equivalence
+			       class.  */
+			    PATFETCH (c);
+
+			    /* Now add the multibyte character(s) we found
+			       to the accept list.
+
+			       XXX Note that this is not entirely correct.
+			       we would have to match multibyte sequences
+			       but this is not possible with the current
+			       implementation.  Also, we have to match
+			       collating symbols, which expand to more than
+			       one file, as a whole and not allow the
+			       individual bytes.  */
+			    c1 = extra[idx++];
+			    if (c1 == 1)
+			      range_start = extra[idx];
+			    while (c1-- > 0)
+			      {
+				SET_LIST_BIT (extra[idx]);
+				++idx;
+			      }
+			  }
+# endif
+			had_char_class = false;
+		      }
+                    else
+                      {
+                        c1++;
+                        while (c1--)
+                          PATUNFETCH;
+                        SET_LIST_BIT ('[');
+                        SET_LIST_BIT ('.');
+			range_start = '.';
+                        had_char_class = false;
+                      }
+		  }
+                else
+                  {
+                    had_char_class = false;
+                    SET_LIST_BIT (c);
+		    range_start = c;
+                  }
+              }
+
+            /* Discard any (non)matching list bytes that are all 0 at the
+               end of the map.  Decrease the map-length byte too.  */
+            while ((int) b[-1] > 0 && b[b[-1] - 1] == 0)
+              b[-1]--;
+            b += b[-1];
+#endif /* WCHAR */
+          }
+          break;
+
+
+	case '(':
+          if (syntax & RE_NO_BK_PARENS)
+            goto handle_open;
+          else
+            goto normal_char;
+
+
+        case ')':
+          if (syntax & RE_NO_BK_PARENS)
+            goto handle_close;
+          else
+            goto normal_char;
+
+
+        case '\n':
+          if (syntax & RE_NEWLINE_ALT)
+            goto handle_alt;
+          else
+            goto normal_char;
+
+
+	case '|':
+          if (syntax & RE_NO_BK_VBAR)
+            goto handle_alt;
+          else
+            goto normal_char;
+
+
+        case '{':
+           if (syntax & RE_INTERVALS && syntax & RE_NO_BK_BRACES)
+             goto handle_interval;
+           else
+             goto normal_char;
+
+
+        case '\\':
+          if (p == pend) FREE_STACK_RETURN (REG_EESCAPE);
+
+          /* Do not translate the character after the \, so that we can
+             distinguish, e.g., \B from \b, even if we normally would
+             translate, e.g., B to b.  */
+          PATFETCH_RAW (c);
+
+          switch (c)
+            {
+            case '(':
+              if (syntax & RE_NO_BK_PARENS)
+                goto normal_backslash;
+
+            handle_open:
+              bufp->re_nsub++;
+              regnum++;
+
+              if (COMPILE_STACK_FULL)
+                {
+                  RETALLOC (compile_stack.stack, compile_stack.size << 1,
+                            compile_stack_elt_t);
+                  if (compile_stack.stack == NULL) return REG_ESPACE;
+
+                  compile_stack.size <<= 1;
+                }
+
+              /* These are the values to restore when we hit end of this
+                 group.  They are all relative offsets, so that if the
+                 whole pattern moves because of realloc, they will still
+                 be valid.  */
+              COMPILE_STACK_TOP.begalt_offset = begalt - COMPILED_BUFFER_VAR;
+              COMPILE_STACK_TOP.fixup_alt_jump
+                = fixup_alt_jump ? fixup_alt_jump - COMPILED_BUFFER_VAR + 1 : 0;
+              COMPILE_STACK_TOP.laststart_offset = b - COMPILED_BUFFER_VAR;
+              COMPILE_STACK_TOP.regnum = regnum;
+
+              /* We will eventually replace the 0 with the number of
+                 groups inner to this one.  But do not push a
+                 start_memory for groups beyond the last one we can
+                 represent in the compiled pattern.  */
+              if (regnum <= MAX_REGNUM)
+                {
+                  COMPILE_STACK_TOP.inner_group_offset = b
+		    - COMPILED_BUFFER_VAR + 2;
+                  BUF_PUSH_3 (start_memory, regnum, 0);
+                }
+
+              compile_stack.avail++;
+
+              fixup_alt_jump = 0;
+              laststart = 0;
+              begalt = b;
+	      /* If we've reached MAX_REGNUM groups, then this open
+		 won't actually generate any code, so we'll have to
+		 clear pending_exact explicitly.  */
+	      pending_exact = 0;
+              break;
+
+
+            case ')':
+              if (syntax & RE_NO_BK_PARENS) goto normal_backslash;
+
+              if (COMPILE_STACK_EMPTY)
+		{
+		  if (syntax & RE_UNMATCHED_RIGHT_PAREN_ORD)
+		    goto normal_backslash;
+		  else
+		    FREE_STACK_RETURN (REG_ERPAREN);
+		}
+
+            handle_close:
+              if (fixup_alt_jump)
+                { /* Push a dummy failure point at the end of the
+                     alternative for a possible future
+                     `pop_failure_jump' to pop.  See comments at
+                     `push_dummy_failure' in `re_match_2'.  */
+                  BUF_PUSH (push_dummy_failure);
+
+                  /* We allocated space for this jump when we assigned
+                     to `fixup_alt_jump', in the `handle_alt' case below.  */
+                  STORE_JUMP (jump_past_alt, fixup_alt_jump, b - 1);
+                }
+
+              /* See similar code for backslashed left paren above.  */
+              if (COMPILE_STACK_EMPTY)
+		{
+		  if (syntax & RE_UNMATCHED_RIGHT_PAREN_ORD)
+		    goto normal_char;
+		  else
+		    FREE_STACK_RETURN (REG_ERPAREN);
+		}
+
+              /* Since we just checked for an empty stack above, this
+                 ``can't happen''.  */
+              assert (compile_stack.avail != 0);
+              {
+                /* We don't just want to restore into `regnum', because
+                   later groups should continue to be numbered higher,
+                   as in `(ab)c(de)' -- the second group is #2.  */
+                regnum_t this_group_regnum;
+
+                compile_stack.avail--;
+                begalt = COMPILED_BUFFER_VAR + COMPILE_STACK_TOP.begalt_offset;
+                fixup_alt_jump
+                  = COMPILE_STACK_TOP.fixup_alt_jump
+                    ? COMPILED_BUFFER_VAR + COMPILE_STACK_TOP.fixup_alt_jump - 1
+                    : 0;
+                laststart = COMPILED_BUFFER_VAR + COMPILE_STACK_TOP.laststart_offset;
+                this_group_regnum = COMPILE_STACK_TOP.regnum;
+		/* If we've reached MAX_REGNUM groups, then this open
+		   won't actually generate any code, so we'll have to
+		   clear pending_exact explicitly.  */
+		pending_exact = 0;
+
+                /* We're at the end of the group, so now we know how many
+                   groups were inside this one.  */
+                if (this_group_regnum <= MAX_REGNUM)
+                  {
+		    UCHAR_T *inner_group_loc
+                      = COMPILED_BUFFER_VAR + COMPILE_STACK_TOP.inner_group_offset;
+
+                    *inner_group_loc = regnum - this_group_regnum;
+                    BUF_PUSH_3 (stop_memory, this_group_regnum,
+                                regnum - this_group_regnum);
+                  }
+              }
+              break;
+
+
+            case '|':					/* `\|'.  */
+              if (syntax & RE_LIMITED_OPS || syntax & RE_NO_BK_VBAR)
+                goto normal_backslash;
+            handle_alt:
+              if (syntax & RE_LIMITED_OPS)
+                goto normal_char;
+
+              /* Insert before the previous alternative a jump which
+                 jumps to this alternative if the former fails.  */
+              GET_BUFFER_SPACE (1 + OFFSET_ADDRESS_SIZE);
+              INSERT_JUMP (on_failure_jump, begalt,
+			   b + 2 + 2 * OFFSET_ADDRESS_SIZE);
+              pending_exact = 0;
+              b += 1 + OFFSET_ADDRESS_SIZE;
+
+              /* The alternative before this one has a jump after it
+                 which gets executed if it gets matched.  Adjust that
+                 jump so it will jump to this alternative's analogous
+                 jump (put in below, which in turn will jump to the next
+                 (if any) alternative's such jump, etc.).  The last such
+                 jump jumps to the correct final destination.  A picture:
+                          _____ _____
+                          |   | |   |
+                          |   v |   v
+                         a | b   | c
+
+                 If we are at `b', then fixup_alt_jump right now points to a
+                 three-byte space after `a'.  We'll put in the jump, set
+                 fixup_alt_jump to right after `b', and leave behind three
+                 bytes which we'll fill in when we get to after `c'.  */
+
+              if (fixup_alt_jump)
+                STORE_JUMP (jump_past_alt, fixup_alt_jump, b);
+
+              /* Mark and leave space for a jump after this alternative,
+                 to be filled in later either by next alternative or
+                 when know we're at the end of a series of alternatives.  */
+              fixup_alt_jump = b;
+              GET_BUFFER_SPACE (1 + OFFSET_ADDRESS_SIZE);
+              b += 1 + OFFSET_ADDRESS_SIZE;
+
+              laststart = 0;
+              begalt = b;
+              break;
+
+
+            case '{':
+              /* If \{ is a literal.  */
+              if (!(syntax & RE_INTERVALS)
+                     /* If we're at `\{' and it's not the open-interval
+                        operator.  */
+		  || (syntax & RE_NO_BK_BRACES))
+                goto normal_backslash;
+
+            handle_interval:
+              {
+                /* If got here, then the syntax allows intervals.  */
+
+                /* At least (most) this many matches must be made.  */
+                int lower_bound = -1, upper_bound = -1;
+
+		/* Place in the uncompiled pattern (i.e., just after
+		   the '{') to go back to if the interval is invalid.  */
+		const CHAR_T *beg_interval = p;
+
+                if (p == pend)
+		  goto invalid_interval;
+
+                GET_UNSIGNED_NUMBER (lower_bound);
+
+                if (c == ',')
+                  {
+                    GET_UNSIGNED_NUMBER (upper_bound);
+		    if (upper_bound < 0)
+		      upper_bound = RE_DUP_MAX;
+                  }
+                else
+                  /* Interval such as `{1}' => match exactly once. */
+                  upper_bound = lower_bound;
+
+                if (! (0 <= lower_bound && lower_bound <= upper_bound))
+		  goto invalid_interval;
+
+                if (!(syntax & RE_NO_BK_BRACES))
+                  {
+		    if (c != '\\' || p == pend)
+		      goto invalid_interval;
+                    PATFETCH (c);
+                  }
+
+                if (c != '}')
+		  goto invalid_interval;
+
+                /* If it's invalid to have no preceding re.  */
+                if (!laststart)
+                  {
+		    if (syntax & RE_CONTEXT_INVALID_OPS
+			&& !(syntax & RE_INVALID_INTERVAL_ORD))
+                      FREE_STACK_RETURN (REG_BADRPT);
+                    else if (syntax & RE_CONTEXT_INDEP_OPS)
+                      laststart = b;
+                    else
+                      goto unfetch_interval;
+                  }
+
+                /* We just parsed a valid interval.  */
+
+                if (RE_DUP_MAX < upper_bound)
+		  FREE_STACK_RETURN (REG_BADBR);
+
+                /* If the upper bound is zero, don't want to succeed at
+                   all; jump from `laststart' to `b + 3', which will be
+		   the end of the buffer after we insert the jump.  */
+		/* ifdef WCHAR, 'b + 1 + OFFSET_ADDRESS_SIZE'
+		   instead of 'b + 3'.  */
+                 if (upper_bound == 0)
+                   {
+                     GET_BUFFER_SPACE (1 + OFFSET_ADDRESS_SIZE);
+                     INSERT_JUMP (jump, laststart, b + 1
+				  + OFFSET_ADDRESS_SIZE);
+                     b += 1 + OFFSET_ADDRESS_SIZE;
+                   }
+
+                 /* Otherwise, we have a nontrivial interval.  When
+                    we're all done, the pattern will look like:
+                      set_number_at <jump count> <upper bound>
+                      set_number_at <succeed_n count> <lower bound>
+                      succeed_n <after jump addr> <succeed_n count>
+                      <body of loop>
+                      jump_n <succeed_n addr> <jump count>
+                    (The upper bound and `jump_n' are omitted if
+                    `upper_bound' is 1, though.)  */
+                 else
+                   { /* If the upper bound is > 1, we need to insert
+                        more at the end of the loop.  */
+                     unsigned nbytes = 2 + 4 * OFFSET_ADDRESS_SIZE +
+		       (upper_bound > 1) * (2 + 4 * OFFSET_ADDRESS_SIZE);
+
+                     GET_BUFFER_SPACE (nbytes);
+
+                     /* Initialize lower bound of the `succeed_n', even
+                        though it will be set during matching by its
+                        attendant `set_number_at' (inserted next),
+                        because `re_compile_fastmap' needs to know.
+                        Jump to the `jump_n' we might insert below.  */
+                     INSERT_JUMP2 (succeed_n, laststart,
+                                   b + 1 + 2 * OFFSET_ADDRESS_SIZE
+				   + (upper_bound > 1) * (1 + 2 * OFFSET_ADDRESS_SIZE)
+				   , lower_bound);
+                     b += 1 + 2 * OFFSET_ADDRESS_SIZE;
+
+                     /* Code to initialize the lower bound.  Insert
+                        before the `succeed_n'.  The `5' is the last two
+                        bytes of this `set_number_at', plus 3 bytes of
+                        the following `succeed_n'.  */
+		     /* ifdef WCHAR, The '1+2*OFFSET_ADDRESS_SIZE'
+			is the 'set_number_at', plus '1+OFFSET_ADDRESS_SIZE'
+			of the following `succeed_n'.  */
+                     PREFIX(insert_op2) (set_number_at, laststart, 1
+				 + 2 * OFFSET_ADDRESS_SIZE, lower_bound, b);
+                     b += 1 + 2 * OFFSET_ADDRESS_SIZE;
+
+                     if (upper_bound > 1)
+                       { /* More than one repetition is allowed, so
+                            append a backward jump to the `succeed_n'
+                            that starts this interval.
+
+                            When we've reached this during matching,
+                            we'll have matched the interval once, so
+                            jump back only `upper_bound - 1' times.  */
+                         STORE_JUMP2 (jump_n, b, laststart
+				      + 2 * OFFSET_ADDRESS_SIZE + 1,
+                                      upper_bound - 1);
+                         b += 1 + 2 * OFFSET_ADDRESS_SIZE;
+
+                         /* The location we want to set is the second
+                            parameter of the `jump_n'; that is `b-2' as
+                            an absolute address.  `laststart' will be
+                            the `set_number_at' we're about to insert;
+                            `laststart+3' the number to set, the source
+                            for the relative address.  But we are
+                            inserting into the middle of the pattern --
+                            so everything is getting moved up by 5.
+                            Conclusion: (b - 2) - (laststart + 3) + 5,
+                            i.e., b - laststart.
+
+                            We insert this at the beginning of the loop
+                            so that if we fail during matching, we'll
+                            reinitialize the bounds.  */
+                         PREFIX(insert_op2) (set_number_at, laststart,
+					     b - laststart,
+					     upper_bound - 1, b);
+                         b += 1 + 2 * OFFSET_ADDRESS_SIZE;
+                       }
+                   }
+                pending_exact = 0;
+		break;
+
+	      invalid_interval:
+		if (!(syntax & RE_INVALID_INTERVAL_ORD))
+		  FREE_STACK_RETURN (p == pend ? REG_EBRACE : REG_BADBR);
+	      unfetch_interval:
+		/* Match the characters as literals.  */
+		p = beg_interval;
+		c = '{';
+		if (syntax & RE_NO_BK_BRACES)
+		  goto normal_char;
+		else
+		  goto normal_backslash;
+	      }
+
+#ifdef emacs
+            /* There is no way to specify the before_dot and after_dot
+               operators.  rms says this is ok.  --karl  */
+            case '=':
+              BUF_PUSH (at_dot);
+              break;
+
+            case 's':
+              laststart = b;
+              PATFETCH (c);
+              BUF_PUSH_2 (syntaxspec, syntax_spec_code[c]);
+              break;
+
+            case 'S':
+              laststart = b;
+              PATFETCH (c);
+              BUF_PUSH_2 (notsyntaxspec, syntax_spec_code[c]);
+              break;
+#endif /* emacs */
+
+
+            case 'w':
+	      if (syntax & RE_NO_GNU_OPS)
+		goto normal_char;
+              laststart = b;
+              BUF_PUSH (wordchar);
+              break;
+
+
+            case 'W':
+	      if (syntax & RE_NO_GNU_OPS)
+		goto normal_char;
+              laststart = b;
+              BUF_PUSH (notwordchar);
+              break;
+
+
+            case '<':
+	      if (syntax & RE_NO_GNU_OPS)
+		goto normal_char;
+              BUF_PUSH (wordbeg);
+              break;
+
+            case '>':
+	      if (syntax & RE_NO_GNU_OPS)
+		goto normal_char;
+              BUF_PUSH (wordend);
+              break;
+
+            case 'b':
+	      if (syntax & RE_NO_GNU_OPS)
+		goto normal_char;
+              BUF_PUSH (wordbound);
+              break;
+
+            case 'B':
+	      if (syntax & RE_NO_GNU_OPS)
+		goto normal_char;
+              BUF_PUSH (notwordbound);
+              break;
+
+            case '`':
+	      if (syntax & RE_NO_GNU_OPS)
+		goto normal_char;
+              BUF_PUSH (begbuf);
+              break;
+
+            case '\'':
+	      if (syntax & RE_NO_GNU_OPS)
+		goto normal_char;
+              BUF_PUSH (endbuf);
+              break;
+
+            case '1': case '2': case '3': case '4': case '5':
+            case '6': case '7': case '8': case '9':
+              if (syntax & RE_NO_BK_REFS)
+                goto normal_char;
+
+              c1 = c - '0';
+
+              if (c1 > regnum)
+                FREE_STACK_RETURN (REG_ESUBREG);
+
+              /* Can't back reference to a subexpression if inside of it.  */
+              if (group_in_compile_stack (compile_stack, (regnum_t) c1))
+                goto normal_char;
+
+              laststart = b;
+              BUF_PUSH_2 (duplicate, c1);
+              break;
+
+
+            case '+':
+            case '?':
+              if (syntax & RE_BK_PLUS_QM)
+                goto handle_plus;
+              else
+                goto normal_backslash;
+
+            default:
+            normal_backslash:
+              /* You might think it would be useful for \ to mean
+                 not to translate; but if we don't translate it
+                 it will never match anything.  */
+              c = TRANSLATE (c);
+              goto normal_char;
+            }
+          break;
+
+
+	default:
+        /* Expects the character in `c'.  */
+	normal_char:
+	      /* If no exactn currently being built.  */
+          if (!pending_exact
+#ifdef WCHAR
+	      /* If last exactn handle binary(or character) and
+		 new exactn handle character(or binary).  */
+	      || is_exactn_bin != is_binary[p - 1 - pattern]
+#endif /* WCHAR */
+
+              /* If last exactn not at current position.  */
+              || pending_exact + *pending_exact + 1 != b
+
+              /* We have only one byte following the exactn for the count.  */
+	      || *pending_exact == (1 << BYTEWIDTH) - 1
+
+              /* If followed by a repetition operator.  */
+              || *p == '*' || *p == '^'
+	      || ((syntax & RE_BK_PLUS_QM)
+		  ? *p == '\\' && (p[1] == '+' || p[1] == '?')
+		  : (*p == '+' || *p == '?'))
+	      || ((syntax & RE_INTERVALS)
+                  && ((syntax & RE_NO_BK_BRACES)
+		      ? *p == '{'
+                      : (p[0] == '\\' && p[1] == '{'))))
+	    {
+	      /* Start building a new exactn.  */
+
+              laststart = b;
+
+#ifdef WCHAR
+	      /* Is this exactn binary data or character? */
+	      is_exactn_bin = is_binary[p - 1 - pattern];
+	      if (is_exactn_bin)
+		  BUF_PUSH_2 (exactn_bin, 0);
+	      else
+		  BUF_PUSH_2 (exactn, 0);
+#else
+	      BUF_PUSH_2 (exactn, 0);
+#endif /* WCHAR */
+	      pending_exact = b - 1;
+            }
+
+	  BUF_PUSH (c);
+          (*pending_exact)++;
+	  break;
+        } /* switch (c) */
+    } /* while p != pend */
+
+
+  /* Through the pattern now.  */
+
+  if (fixup_alt_jump)
+    STORE_JUMP (jump_past_alt, fixup_alt_jump, b);
+
+  if (!COMPILE_STACK_EMPTY)
+    FREE_STACK_RETURN (REG_EPAREN);
+
+  /* If we don't want backtracking, force success
+     the first time we reach the end of the compiled pattern.  */
+  if (syntax & RE_NO_POSIX_BACKTRACKING)
+    BUF_PUSH (succeed);
+
+#ifdef WCHAR
+  free (pattern);
+  free (mbs_offset);
+  free (is_binary);
+#endif
+  free (compile_stack.stack);
+
+  /* We have succeeded; set the length of the buffer.  */
+#ifdef WCHAR
+  bufp->used = (uintptr_t) b - (uintptr_t) COMPILED_BUFFER_VAR;
+#else
+  bufp->used = b - bufp->buffer;
+#endif
+
+#ifdef DEBUG
+  if (debug)
+    {
+      DEBUG_PRINT1 ("\nCompiled pattern: \n");
+      PREFIX(print_compiled_pattern) (bufp);
+    }
+#endif /* DEBUG */
+
+#ifndef MATCH_MAY_ALLOCATE
+  /* Initialize the failure stack to the largest possible stack.  This
+     isn't necessary unless we're trying to avoid calling alloca in
+     the search and match routines.  */
+  {
+    int num_regs = bufp->re_nsub + 1;
+
+    /* Since DOUBLE_FAIL_STACK refuses to double only if the current size
+       is strictly greater than re_max_failures, the largest possible stack
+       is 2 * re_max_failures failure points.  */
+    if (fail_stack.size < (2 * re_max_failures * MAX_FAILURE_ITEMS))
+      {
+	fail_stack.size = (2 * re_max_failures * MAX_FAILURE_ITEMS);
+
+# ifdef emacs
+	if (! fail_stack.stack)
+	  fail_stack.stack
+	    = (PREFIX(fail_stack_elt_t) *) xmalloc (fail_stack.size
+				    * sizeof (PREFIX(fail_stack_elt_t)));
+	else
+	  fail_stack.stack
+	    = (PREFIX(fail_stack_elt_t) *) xrealloc (fail_stack.stack,
+				     (fail_stack.size
+				      * sizeof (PREFIX(fail_stack_elt_t))));
+# else /* not emacs */
+	if (! fail_stack.stack)
+	  fail_stack.stack
+	    = (PREFIX(fail_stack_elt_t) *) malloc (fail_stack.size
+				   * sizeof (PREFIX(fail_stack_elt_t)));
+	else
+	  fail_stack.stack
+	    = (PREFIX(fail_stack_elt_t) *) realloc (fail_stack.stack,
+					    (fail_stack.size
+				     * sizeof (PREFIX(fail_stack_elt_t))));
+# endif /* not emacs */
+      }
+
+   PREFIX(regex_grow_registers) (num_regs);
+  }
+#endif /* not MATCH_MAY_ALLOCATE */
+
+  return REG_NOERROR;
+} /* regex_compile */
+
+/* Subroutines for `regex_compile'.  */
+
+/* Store OP at LOC followed by two-byte integer parameter ARG.  */
+/* ifdef WCHAR, integer parameter is 1 wchar_t.  */
+
+static void
+PREFIX(store_op1) (re_opcode_t op, UCHAR_T *loc, int arg)
+{
+  *loc = (UCHAR_T) op;
+  STORE_NUMBER (loc + 1, arg);
+}
+
+
+/* Like `store_op1', but for two two-byte parameters ARG1 and ARG2.  */
+/* ifdef WCHAR, integer parameter is 1 wchar_t.  */
+
+static void
+PREFIX(store_op2) (re_opcode_t op, UCHAR_T *loc, int arg1, int arg2)
+{
+  *loc = (UCHAR_T) op;
+  STORE_NUMBER (loc + 1, arg1);
+  STORE_NUMBER (loc + 1 + OFFSET_ADDRESS_SIZE, arg2);
+}
+
+
+/* Copy the bytes from LOC to END to open up three bytes of space at LOC
+   for OP followed by two-byte integer parameter ARG.  */
+/* ifdef WCHAR, integer parameter is 1 wchar_t.  */
+
+static void
+PREFIX(insert_op1) (re_opcode_t op, UCHAR_T *loc, int arg, UCHAR_T *end)
+{
+  register UCHAR_T *pfrom = end;
+  register UCHAR_T *pto = end + 1 + OFFSET_ADDRESS_SIZE;
+
+  while (pfrom != loc)
+    *--pto = *--pfrom;
+
+  PREFIX(store_op1) (op, loc, arg);
+}
+
+
+/* Like `insert_op1', but for two two-byte parameters ARG1 and ARG2.  */
+/* ifdef WCHAR, integer parameter is 1 wchar_t.  */
+
+static void
+PREFIX(insert_op2) (re_opcode_t op, UCHAR_T *loc, int arg1,
+                    int arg2, UCHAR_T *end)
+{
+  register UCHAR_T *pfrom = end;
+  register UCHAR_T *pto = end + 1 + 2 * OFFSET_ADDRESS_SIZE;
+
+  while (pfrom != loc)
+    *--pto = *--pfrom;
+
+  PREFIX(store_op2) (op, loc, arg1, arg2);
+}
+
+
+/* P points to just after a ^ in PATTERN.  Return true if that ^ comes
+   after an alternative or a begin-subexpression.  We assume there is at
+   least one character before the ^.  */
+
+static boolean
+PREFIX(at_begline_loc_p) (const CHAR_T *pattern, const CHAR_T *p,
+                          reg_syntax_t syntax)
+{
+  const CHAR_T *prev = p - 2;
+  boolean prev_prev_backslash = prev > pattern && prev[-1] == '\\';
+
+  return
+       /* After a subexpression?  */
+       (*prev == '(' && (syntax & RE_NO_BK_PARENS || prev_prev_backslash))
+       /* After an alternative?  */
+    || (*prev == '|' && (syntax & RE_NO_BK_VBAR || prev_prev_backslash));
+}
+
+
+/* The dual of at_begline_loc_p.  This one is for $.  We assume there is
+   at least one character after the $, i.e., `P < PEND'.  */
+
+static boolean
+PREFIX(at_endline_loc_p) (const CHAR_T *p, const CHAR_T *pend,
+                          reg_syntax_t syntax)
+{
+  const CHAR_T *next = p;
+  boolean next_backslash = *next == '\\';
+  const CHAR_T *next_next = p + 1 < pend ? p + 1 : 0;
+
+  return
+       /* Before a subexpression?  */
+       (syntax & RE_NO_BK_PARENS ? *next == ')'
+        : next_backslash && next_next && *next_next == ')')
+       /* Before an alternative?  */
+    || (syntax & RE_NO_BK_VBAR ? *next == '|'
+        : next_backslash && next_next && *next_next == '|');
+}
+
+#else /* not INSIDE_RECURSION */
+
+/* Returns true if REGNUM is in one of COMPILE_STACK's elements and
+   false if it's not.  */
+
+static boolean
+group_in_compile_stack (compile_stack_type compile_stack, regnum_t regnum)
+{
+  int this_element;
+
+  for (this_element = compile_stack.avail - 1;
+       this_element >= 0;
+       this_element--)
+    if (compile_stack.stack[this_element].regnum == regnum)
+      return true;
+
+  return false;
+}
+#endif /* not INSIDE_RECURSION */
+
+#ifdef INSIDE_RECURSION
+
+#ifdef WCHAR
+/* This insert space, which size is "num", into the pattern at "loc".
+   "end" must point the end of the allocated buffer.  */
+static void
+insert_space (int num, CHAR_T *loc, CHAR_T *end)
+{
+  register CHAR_T *pto = end;
+  register CHAR_T *pfrom = end - num;
+
+  while (pfrom >= loc)
+    *pto-- = *pfrom--;
+}
+#endif /* WCHAR */
+
+#ifdef WCHAR
+static reg_errcode_t
+wcs_compile_range (CHAR_T range_start_char, const CHAR_T **p_ptr,
+                   const CHAR_T *pend, RE_TRANSLATE_TYPE translate,
+                   reg_syntax_t syntax, CHAR_T *b, CHAR_T *char_set)
+{
+  const CHAR_T *p = *p_ptr;
+  CHAR_T range_start, range_end;
+  reg_errcode_t ret;
+# ifdef _LIBC
+  uint32_t nrules;
+  uint32_t start_val, end_val;
+# endif
+  if (p == pend)
+    return REG_ERANGE;
+
+# ifdef _LIBC
+  nrules = _NL_CURRENT_WORD (LC_COLLATE, _NL_COLLATE_NRULES);
+  if (nrules != 0)
+    {
+      const char *collseq = (const char *) _NL_CURRENT(LC_COLLATE,
+						       _NL_COLLATE_COLLSEQWC);
+      const unsigned char *extra = (const unsigned char *)
+	_NL_CURRENT (LC_COLLATE, _NL_COLLATE_SYMB_EXTRAMB);
+
+      if (range_start_char < -1)
+	{
+	  /* range_start is a collating symbol.  */
+	  int32_t *wextra;
+	  /* Retreive the index and get collation sequence value.  */
+	  wextra = (int32_t*)(extra + char_set[-range_start_char]);
+	  start_val = wextra[1 + *wextra];
+	}
+      else
+	start_val = collseq_table_lookup(collseq, TRANSLATE(range_start_char));
+
+      end_val = collseq_table_lookup (collseq, TRANSLATE (p[0]));
+
+      /* Report an error if the range is empty and the syntax prohibits
+	 this.  */
+      ret = ((syntax & RE_NO_EMPTY_RANGES)
+	     && (start_val > end_val))? REG_ERANGE : REG_NOERROR;
+
+      /* Insert space to the end of the char_ranges.  */
+      insert_space(2, b - char_set[5] - 2, b - 1);
+      *(b - char_set[5] - 2) = (wchar_t)start_val;
+      *(b - char_set[5] - 1) = (wchar_t)end_val;
+      char_set[4]++; /* ranges_index */
+    }
+  else
+# endif
+    {
+      range_start = (range_start_char >= 0)? TRANSLATE (range_start_char):
+	range_start_char;
+      range_end = TRANSLATE (p[0]);
+      /* Report an error if the range is empty and the syntax prohibits
+	 this.  */
+      ret = ((syntax & RE_NO_EMPTY_RANGES)
+	     && (range_start > range_end))? REG_ERANGE : REG_NOERROR;
+
+      /* Insert space to the end of the char_ranges.  */
+      insert_space(2, b - char_set[5] - 2, b - 1);
+      *(b - char_set[5] - 2) = range_start;
+      *(b - char_set[5] - 1) = range_end;
+      char_set[4]++; /* ranges_index */
+    }
+  /* Have to increment the pointer into the pattern string, so the
+     caller isn't still at the ending character.  */
+  (*p_ptr)++;
+
+  return ret;
+}
+#else /* BYTE */
+/* Read the ending character of a range (in a bracket expression) from the
+   uncompiled pattern *P_PTR (which ends at PEND).  We assume the
+   starting character is in `P[-2]'.  (`P[-1]' is the character `-'.)
+   Then we set the translation of all bits between the starting and
+   ending characters (inclusive) in the compiled pattern B.
+
+   Return an error code.
+
+   We use these short variable names so we can use the same macros as
+   `regex_compile' itself.  */
+
+static reg_errcode_t
+byte_compile_range (unsigned int range_start_char, const char **p_ptr,
+                    const char *pend, RE_TRANSLATE_TYPE translate,
+                    reg_syntax_t syntax, unsigned char *b)
+{
+  unsigned this_char;
+  const char *p = *p_ptr;
+  reg_errcode_t ret;
+# if _LIBC
+  const unsigned char *collseq;
+  unsigned int start_colseq;
+  unsigned int end_colseq;
+# else
+  unsigned end_char;
+# endif
+
+  if (p == pend)
+    return REG_ERANGE;
+
+  /* Have to increment the pointer into the pattern string, so the
+     caller isn't still at the ending character.  */
+  (*p_ptr)++;
+
+  /* Report an error if the range is empty and the syntax prohibits this.  */
+  ret = syntax & RE_NO_EMPTY_RANGES ? REG_ERANGE : REG_NOERROR;
+
+# if _LIBC
+  collseq = (const unsigned char *) _NL_CURRENT (LC_COLLATE,
+						 _NL_COLLATE_COLLSEQMB);
+
+  start_colseq = collseq[(unsigned char) TRANSLATE (range_start_char)];
+  end_colseq = collseq[(unsigned char) TRANSLATE (p[0])];
+  for (this_char = 0; this_char <= (unsigned char) -1; ++this_char)
+    {
+      unsigned int this_colseq = collseq[(unsigned char) TRANSLATE (this_char)];
+
+      if (start_colseq <= this_colseq && this_colseq <= end_colseq)
+	{
+	  SET_LIST_BIT (TRANSLATE (this_char));
+	  ret = REG_NOERROR;
+	}
+    }
+# else
+  /* Here we see why `this_char' has to be larger than an `unsigned
+     char' -- we would otherwise go into an infinite loop, since all
+     characters <= 0xff.  */
+  range_start_char = TRANSLATE (range_start_char);
+  /* TRANSLATE(p[0]) is casted to char (not unsigned char) in TRANSLATE,
+     and some compilers cast it to int implicitly, so following for_loop
+     may fall to (almost) infinite loop.
+     e.g. If translate[p[0]] = 0xff, end_char may equals to 0xffffffff.
+     To avoid this, we cast p[0] to unsigned int and truncate it.  */
+  end_char = ((unsigned)TRANSLATE(p[0]) & ((1 << BYTEWIDTH) - 1));
+
+  for (this_char = range_start_char; this_char <= end_char; ++this_char)
+    {
+      SET_LIST_BIT (TRANSLATE (this_char));
+      ret = REG_NOERROR;
+    }
+# endif
+
+  return ret;
+}
+#endif /* WCHAR */
+
+/* re_compile_fastmap computes a ``fastmap'' for the compiled pattern in
+   BUFP.  A fastmap records which of the (1 << BYTEWIDTH) possible
+   characters can start a string that matches the pattern.  This fastmap
+   is used by re_search to skip quickly over impossible starting points.
+
+   The caller must supply the address of a (1 << BYTEWIDTH)-byte data
+   area as BUFP->fastmap.
+
+   We set the `fastmap', `fastmap_accurate', and `can_be_null' fields in
+   the pattern buffer.
+
+   Returns 0 if we succeed, -2 if an internal error.   */
+
+#ifdef WCHAR
+/* local function for re_compile_fastmap.
+   truncate wchar_t character to char.  */
+static unsigned char truncate_wchar (CHAR_T c);
+
+static unsigned char
+truncate_wchar (CHAR_T c)
+{
+  unsigned char buf[MB_CUR_MAX];
+  mbstate_t state;
+  int retval;
+  memset (&state, '\0', sizeof (state));
+# ifdef _LIBC
+  retval = __wcrtomb (buf, c, &state);
+# else
+  retval = wcrtomb (buf, c, &state);
+# endif
+  return retval > 0 ? buf[0] : (unsigned char) c;
+}
+#endif /* WCHAR */
+
+static int
+PREFIX(re_compile_fastmap) (struct re_pattern_buffer *bufp)
+{
+  int j, k;
+#ifdef MATCH_MAY_ALLOCATE
+  PREFIX(fail_stack_type) fail_stack;
+#endif
+#ifndef REGEX_MALLOC
+  char *destination;
+#endif
+
+  register char *fastmap = bufp->fastmap;
+
+#ifdef WCHAR
+  /* We need to cast pattern to (wchar_t*), because we casted this compiled
+     pattern to (char*) in regex_compile.  */
+  UCHAR_T *pattern = (UCHAR_T*)bufp->buffer;
+  register UCHAR_T *pend = (UCHAR_T*) (bufp->buffer + bufp->used);
+#else /* BYTE */
+  UCHAR_T *pattern = bufp->buffer;
+  register UCHAR_T *pend = pattern + bufp->used;
+#endif /* WCHAR */
+  UCHAR_T *p = pattern;
+
+#ifdef REL_ALLOC
+  /* This holds the pointer to the failure stack, when
+     it is allocated relocatably.  */
+  fail_stack_elt_t *failure_stack_ptr;
+#endif
+
+  /* Assume that each path through the pattern can be null until
+     proven otherwise.  We set this false at the bottom of switch
+     statement, to which we get only if a particular path doesn't
+     match the empty string.  */
+  boolean path_can_be_null = true;
+
+  /* We aren't doing a `succeed_n' to begin with.  */
+  boolean succeed_n_p = false;
+
+  assert (fastmap != NULL && p != NULL);
+
+  INIT_FAIL_STACK ();
+  bzero (fastmap, 1 << BYTEWIDTH);  /* Assume nothing's valid.  */
+  bufp->fastmap_accurate = 1;	    /* It will be when we're done.  */
+  bufp->can_be_null = 0;
+
+  while (1)
+    {
+      if (p == pend || *p == (UCHAR_T) succeed)
+	{
+	  /* We have reached the (effective) end of pattern.  */
+	  if (!FAIL_STACK_EMPTY ())
+	    {
+	      bufp->can_be_null |= path_can_be_null;
+
+	      /* Reset for next path.  */
+	      path_can_be_null = true;
+
+	      p = fail_stack.stack[--fail_stack.avail].pointer;
+
+	      continue;
+	    }
+	  else
+	    break;
+	}
+
+      /* We should never be about to go beyond the end of the pattern.  */
+      assert (p < pend);
+
+      switch (SWITCH_ENUM_CAST ((re_opcode_t) *p++))
+	{
+
+        /* I guess the idea here is to simply not bother with a fastmap
+           if a backreference is used, since it's too hard to figure out
+           the fastmap for the corresponding group.  Setting
+           `can_be_null' stops `re_search_2' from using the fastmap, so
+           that is all we do.  */
+	case duplicate:
+	  bufp->can_be_null = 1;
+          goto done;
+
+
+      /* Following are the cases which match a character.  These end
+         with `break'.  */
+
+#ifdef WCHAR
+	case exactn:
+          fastmap[truncate_wchar(p[1])] = 1;
+	  break;
+#else /* BYTE */
+	case exactn:
+          fastmap[p[1]] = 1;
+	  break;
+#endif /* WCHAR */
+#ifdef MBS_SUPPORT
+	case exactn_bin:
+	  fastmap[p[1]] = 1;
+	  break;
+#endif
+
+#ifdef WCHAR
+        /* It is hard to distinguish fastmap from (multi byte) characters
+           which depends on current locale.  */
+        case charset:
+	case charset_not:
+	case wordchar:
+	case notwordchar:
+          bufp->can_be_null = 1;
+          goto done;
+#else /* BYTE */
+        case charset:
+          for (j = *p++ * BYTEWIDTH - 1; j >= 0; j--)
+	    if (p[j / BYTEWIDTH] & (1 << (j % BYTEWIDTH)))
+              fastmap[j] = 1;
+	  break;
+
+
+	case charset_not:
+	  /* Chars beyond end of map must be allowed.  */
+	  for (j = *p * BYTEWIDTH; j < (1 << BYTEWIDTH); j++)
+            fastmap[j] = 1;
+
+	  for (j = *p++ * BYTEWIDTH - 1; j >= 0; j--)
+	    if (!(p[j / BYTEWIDTH] & (1 << (j % BYTEWIDTH))))
+              fastmap[j] = 1;
+          break;
+
+
+	case wordchar:
+	  for (j = 0; j < (1 << BYTEWIDTH); j++)
+	    if (SYNTAX (j) == Sword)
+	      fastmap[j] = 1;
+	  break;
+
+
+	case notwordchar:
+	  for (j = 0; j < (1 << BYTEWIDTH); j++)
+	    if (SYNTAX (j) != Sword)
+	      fastmap[j] = 1;
+	  break;
+#endif /* WCHAR */
+
+        case anychar:
+	  {
+	    int fastmap_newline = fastmap['\n'];
+
+	    /* `.' matches anything ...  */
+	    for (j = 0; j < (1 << BYTEWIDTH); j++)
+	      fastmap[j] = 1;
+
+	    /* ... except perhaps newline.  */
+	    if (!(bufp->syntax & RE_DOT_NEWLINE))
+	      fastmap['\n'] = fastmap_newline;
+
+	    /* Return if we have already set `can_be_null'; if we have,
+	       then the fastmap is irrelevant.  Something's wrong here.  */
+	    else if (bufp->can_be_null)
+	      goto done;
+
+	    /* Otherwise, have to check alternative paths.  */
+	    break;
+	  }
+
+#ifdef emacs
+        case syntaxspec:
+	  k = *p++;
+	  for (j = 0; j < (1 << BYTEWIDTH); j++)
+	    if (SYNTAX (j) == (enum syntaxcode) k)
+	      fastmap[j] = 1;
+	  break;
+
+
+	case notsyntaxspec:
+	  k = *p++;
+	  for (j = 0; j < (1 << BYTEWIDTH); j++)
+	    if (SYNTAX (j) != (enum syntaxcode) k)
+	      fastmap[j] = 1;
+	  break;
+
+
+      /* All cases after this match the empty string.  These end with
+         `continue'.  */
+
+
+	case before_dot:
+	case at_dot:
+	case after_dot:
+          continue;
+#endif /* emacs */
+
+
+        case no_op:
+        case begline:
+        case endline:
+	case begbuf:
+	case endbuf:
+	case wordbound:
+	case notwordbound:
+	case wordbeg:
+	case wordend:
+        case push_dummy_failure:
+          continue;
+
+
+	case jump_n:
+        case pop_failure_jump:
+	case maybe_pop_jump:
+	case jump:
+        case jump_past_alt:
+	case dummy_failure_jump:
+          EXTRACT_NUMBER_AND_INCR (j, p);
+	  p += j;
+	  if (j > 0)
+	    continue;
+
+          /* Jump backward implies we just went through the body of a
+             loop and matched nothing.  Opcode jumped to should be
+             `on_failure_jump' or `succeed_n'.  Just treat it like an
+             ordinary jump.  For a * loop, it has pushed its failure
+             point already; if so, discard that as redundant.  */
+          if ((re_opcode_t) *p != on_failure_jump
+	      && (re_opcode_t) *p != succeed_n)
+	    continue;
+
+          p++;
+          EXTRACT_NUMBER_AND_INCR (j, p);
+          p += j;
+
+          /* If what's on the stack is where we are now, pop it.  */
+          if (!FAIL_STACK_EMPTY ()
+	      && fail_stack.stack[fail_stack.avail - 1].pointer == p)
+            fail_stack.avail--;
+
+          continue;
+
+
+        case on_failure_jump:
+        case on_failure_keep_string_jump:
+	handle_on_failure_jump:
+          EXTRACT_NUMBER_AND_INCR (j, p);
+
+          /* For some patterns, e.g., `(a?)?', `p+j' here points to the
+             end of the pattern.  We don't want to push such a point,
+             since when we restore it above, entering the switch will
+             increment `p' past the end of the pattern.  We don't need
+             to push such a point since we obviously won't find any more
+             fastmap entries beyond `pend'.  Such a pattern can match
+             the null string, though.  */
+          if (p + j < pend)
+            {
+              if (!PUSH_PATTERN_OP (p + j, fail_stack))
+		{
+		  RESET_FAIL_STACK ();
+		  return -2;
+		}
+            }
+          else
+            bufp->can_be_null = 1;
+
+          if (succeed_n_p)
+            {
+              EXTRACT_NUMBER_AND_INCR (k, p);	/* Skip the n.  */
+              succeed_n_p = false;
+	    }
+
+          continue;
+
+
+	case succeed_n:
+          /* Get to the number of times to succeed.  */
+          p += OFFSET_ADDRESS_SIZE;
+
+          /* Increment p past the n for when k != 0.  */
+          EXTRACT_NUMBER_AND_INCR (k, p);
+          if (k == 0)
+	    {
+              p -= 2 * OFFSET_ADDRESS_SIZE;
+  	      succeed_n_p = true;  /* Spaghetti code alert.  */
+              goto handle_on_failure_jump;
+            }
+          continue;
+
+
+	case set_number_at:
+          p += 2 * OFFSET_ADDRESS_SIZE;
+          continue;
+
+
+	case start_memory:
+        case stop_memory:
+	  p += 2;
+	  continue;
+
+
+	default:
+          abort (); /* We have listed all the cases.  */
+        } /* switch *p++ */
+
+      /* Getting here means we have found the possible starting
+         characters for one path of the pattern -- and that the empty
+         string does not match.  We need not follow this path further.
+         Instead, look at the next alternative (remembered on the
+         stack), or quit if no more.  The test at the top of the loop
+         does these things.  */
+      path_can_be_null = false;
+      p = pend;
+    } /* while p */
+
+  /* Set `can_be_null' for the last path (also the first path, if the
+     pattern is empty).  */
+  bufp->can_be_null |= path_can_be_null;
+
+ done:
+  RESET_FAIL_STACK ();
+  return 0;
+}
+
+#else /* not INSIDE_RECURSION */
+
+int
+re_compile_fastmap (struct re_pattern_buffer *bufp)
+{
+# ifdef MBS_SUPPORT
+  if (MB_CUR_MAX != 1)
+    return wcs_re_compile_fastmap(bufp);
+  else
+# endif
+    return byte_re_compile_fastmap(bufp);
+} /* re_compile_fastmap */
+#ifdef _LIBC
+weak_alias (__re_compile_fastmap, re_compile_fastmap)
+#endif
+
+
+/* Set REGS to hold NUM_REGS registers, storing them in STARTS and
+   ENDS.  Subsequent matches using PATTERN_BUFFER and REGS will use
+   this memory for recording register information.  STARTS and ENDS
+   must be allocated using the malloc library routine, and must each
+   be at least NUM_REGS * sizeof (regoff_t) bytes long.
+
+   If NUM_REGS == 0, then subsequent matches should allocate their own
+   register data.
+
+   Unless this function is called, the first search or match using
+   PATTERN_BUFFER will allocate its own register data, without
+   freeing the old data.  */
+
+void
+re_set_registers (struct re_pattern_buffer *bufp,
+                  struct re_registers *regs, unsigned num_regs,
+                  regoff_t *starts, regoff_t *ends)
+{
+  if (num_regs)
+    {
+      bufp->regs_allocated = REGS_REALLOCATE;
+      regs->num_regs = num_regs;
+      regs->start = starts;
+      regs->end = ends;
+    }
+  else
+    {
+      bufp->regs_allocated = REGS_UNALLOCATED;
+      regs->num_regs = 0;
+      regs->start = regs->end = (regoff_t *) 0;
+    }
+}
+#ifdef _LIBC
+weak_alias (__re_set_registers, re_set_registers)
+#endif
+
+/* Searching routines.  */
+
+/* Like re_search_2, below, but only one string is specified, and
+   doesn't let you say where to stop matching.  */
+
+int
+re_search (struct re_pattern_buffer *bufp, const char *string, int size,
+           int startpos, int range, struct re_registers *regs)
+{
+  return re_search_2 (bufp, NULL, 0, string, size, startpos, range,
+		      regs, size);
+}
+#ifdef _LIBC
+weak_alias (__re_search, re_search)
+#endif
+
+
+/* Using the compiled pattern in BUFP->buffer, first tries to match the
+   virtual concatenation of STRING1 and STRING2, starting first at index
+   STARTPOS, then at STARTPOS + 1, and so on.
+
+   STRING1 and STRING2 have length SIZE1 and SIZE2, respectively.
+
+   RANGE is how far to scan while trying to match.  RANGE = 0 means try
+   only at STARTPOS; in general, the last start tried is STARTPOS +
+   RANGE.
+
+   In REGS, return the indices of the virtual concatenation of STRING1
+   and STRING2 that matched the entire BUFP->buffer and its contained
+   subexpressions.
+
+   Do not consider matching one past the index STOP in the virtual
+   concatenation of STRING1 and STRING2.
+
+   We return either the position in the strings at which the match was
+   found, -1 if no match, or -2 if error (such as failure
+   stack overflow).  */
+
+int
+re_search_2 (struct re_pattern_buffer *bufp, const char *string1, int size1,
+             const char *string2, int size2, int startpos, int range,
+             struct re_registers *regs, int stop)
+{
+# ifdef MBS_SUPPORT
+  if (MB_CUR_MAX != 1)
+    return wcs_re_search_2 (bufp, string1, size1, string2, size2, startpos,
+			    range, regs, stop);
+  else
+# endif
+    return byte_re_search_2 (bufp, string1, size1, string2, size2, startpos,
+			     range, regs, stop);
+} /* re_search_2 */
+#ifdef _LIBC
+weak_alias (__re_search_2, re_search_2)
+#endif
+
+#endif /* not INSIDE_RECURSION */
+
+#ifdef INSIDE_RECURSION
+
+#ifdef MATCH_MAY_ALLOCATE
+# define FREE_VAR(var) if (var) REGEX_FREE (var); var = NULL
+#else
+# define FREE_VAR(var) if (var) free (var); var = NULL
+#endif
+
+#ifdef WCHAR
+# define MAX_ALLOCA_SIZE	2000
+
+# define FREE_WCS_BUFFERS() \
+  do {									      \
+    if (size1 > MAX_ALLOCA_SIZE)					      \
+      {									      \
+	free (wcs_string1);						      \
+	free (mbs_offset1);						      \
+      }									      \
+    else								      \
+      {									      \
+	FREE_VAR (wcs_string1);						      \
+	FREE_VAR (mbs_offset1);						      \
+      }									      \
+    if (size2 > MAX_ALLOCA_SIZE) 					      \
+      {									      \
+	free (wcs_string2);						      \
+	free (mbs_offset2);						      \
+      }									      \
+    else								      \
+      {									      \
+	FREE_VAR (wcs_string2);						      \
+	FREE_VAR (mbs_offset2);						      \
+      }									      \
+  } while (0)
+
+#endif
+
+
+static int
+PREFIX(re_search_2) (struct re_pattern_buffer *bufp, const char *string1,
+                     int size1, const char *string2, int size2,
+                     int startpos, int range,
+                     struct re_registers *regs, int stop)
+{
+  int val;
+  register char *fastmap = bufp->fastmap;
+  register RE_TRANSLATE_TYPE translate = bufp->translate;
+  int total_size = size1 + size2;
+  int endpos = startpos + range;
+#ifdef WCHAR
+  /* We need wchar_t* buffers correspond to cstring1, cstring2.  */
+  wchar_t *wcs_string1 = NULL, *wcs_string2 = NULL;
+  /* We need the size of wchar_t buffers correspond to csize1, csize2.  */
+  int wcs_size1 = 0, wcs_size2 = 0;
+  /* offset buffer for optimizatoin. See convert_mbs_to_wc.  */
+  int *mbs_offset1 = NULL, *mbs_offset2 = NULL;
+  /* They hold whether each wchar_t is binary data or not.  */
+  char *is_binary = NULL;
+#endif /* WCHAR */
+
+  /* Check for out-of-range STARTPOS.  */
+  if (startpos < 0 || startpos > total_size)
+    return -1;
+
+  /* Fix up RANGE if it might eventually take us outside
+     the virtual concatenation of STRING1 and STRING2.
+     Make sure we won't move STARTPOS below 0 or above TOTAL_SIZE.  */
+  if (endpos < 0)
+    range = 0 - startpos;
+  else if (endpos > total_size)
+    range = total_size - startpos;
+
+  /* If the search isn't to be a backwards one, don't waste time in a
+     search for a pattern that must be anchored.  */
+  if (bufp->used > 0 && range > 0
+      && ((re_opcode_t) bufp->buffer[0] == begbuf
+	  /* `begline' is like `begbuf' if it cannot match at newlines.  */
+	  || ((re_opcode_t) bufp->buffer[0] == begline
+	      && !bufp->newline_anchor)))
+    {
+      if (startpos > 0)
+	return -1;
+      else
+	range = 1;
+    }
+
+#ifdef emacs
+  /* In a forward search for something that starts with \=.
+     don't keep searching past point.  */
+  if (bufp->used > 0 && (re_opcode_t) bufp->buffer[0] == at_dot && range > 0)
+    {
+      range = PT - startpos;
+      if (range <= 0)
+	return -1;
+    }
+#endif /* emacs */
+
+  /* Update the fastmap now if not correct already.  */
+  if (fastmap && !bufp->fastmap_accurate)
+    if (re_compile_fastmap (bufp) == -2)
+      return -2;
+
+#ifdef WCHAR
+  /* Allocate wchar_t array for wcs_string1 and wcs_string2 and
+     fill them with converted string.  */
+  if (size1 != 0)
+    {
+      if (size1 > MAX_ALLOCA_SIZE)
+	{
+	  wcs_string1 = TALLOC (size1 + 1, CHAR_T);
+	  mbs_offset1 = TALLOC (size1 + 1, int);
+	  is_binary = TALLOC (size1 + 1, char);
+	}
+      else
+	{
+	  wcs_string1 = REGEX_TALLOC (size1 + 1, CHAR_T);
+	  mbs_offset1 = REGEX_TALLOC (size1 + 1, int);
+	  is_binary = REGEX_TALLOC (size1 + 1, char);
+	}
+      if (!wcs_string1 || !mbs_offset1 || !is_binary)
+	{
+	  if (size1 > MAX_ALLOCA_SIZE)
+	    {
+	      free (wcs_string1);
+	      free (mbs_offset1);
+	      free (is_binary);
+	    }
+	  else
+	    {
+	      FREE_VAR (wcs_string1);
+	      FREE_VAR (mbs_offset1);
+	      FREE_VAR (is_binary);
+	    }
+	  return -2;
+	}
+      wcs_size1 = convert_mbs_to_wcs(wcs_string1, string1, size1,
+				     mbs_offset1, is_binary);
+      wcs_string1[wcs_size1] = L'\0'; /* for a sentinel  */
+      if (size1 > MAX_ALLOCA_SIZE)
+	free (is_binary);
+      else
+	FREE_VAR (is_binary);
+    }
+  if (size2 != 0)
+    {
+      if (size2 > MAX_ALLOCA_SIZE)
+	{
+	  wcs_string2 = TALLOC (size2 + 1, CHAR_T);
+	  mbs_offset2 = TALLOC (size2 + 1, int);
+	  is_binary = TALLOC (size2 + 1, char);
+	}
+      else
+	{
+	  wcs_string2 = REGEX_TALLOC (size2 + 1, CHAR_T);
+	  mbs_offset2 = REGEX_TALLOC (size2 + 1, int);
+	  is_binary = REGEX_TALLOC (size2 + 1, char);
+	}
+      if (!wcs_string2 || !mbs_offset2 || !is_binary)
+	{
+	  FREE_WCS_BUFFERS ();
+	  if (size2 > MAX_ALLOCA_SIZE)
+	    free (is_binary);
+	  else
+	    FREE_VAR (is_binary);
+	  return -2;
+	}
+      wcs_size2 = convert_mbs_to_wcs(wcs_string2, string2, size2,
+				     mbs_offset2, is_binary);
+      wcs_string2[wcs_size2] = L'\0'; /* for a sentinel  */
+      if (size2 > MAX_ALLOCA_SIZE)
+	free (is_binary);
+      else
+	FREE_VAR (is_binary);
+    }
+#endif /* WCHAR */
+
+
+  /* Loop through the string, looking for a place to start matching.  */
+  for (;;)
+    {
+      /* If a fastmap is supplied, skip quickly over characters that
+         cannot be the start of a match.  If the pattern can match the
+         null string, however, we don't need to skip characters; we want
+         the first null string.  */
+      if (fastmap && startpos < total_size && !bufp->can_be_null)
+	{
+	  if (range > 0)	/* Searching forwards.  */
+	    {
+	      register const char *d;
+	      register int lim = 0;
+	      int irange = range;
+
+              if (startpos < size1 && startpos + range >= size1)
+                lim = range - (size1 - startpos);
+
+	      d = (startpos >= size1 ? string2 - size1 : string1) + startpos;
+
+              /* Written out as an if-else to avoid testing `translate'
+                 inside the loop.  */
+	      if (translate)
+                while (range > lim
+                       && !fastmap[(unsigned char)
+				   translate[(unsigned char) *d++]])
+                  range--;
+	      else
+                while (range > lim && !fastmap[(unsigned char) *d++])
+                  range--;
+
+	      startpos += irange - range;
+	    }
+	  else				/* Searching backwards.  */
+	    {
+	      register CHAR_T c = (size1 == 0 || startpos >= size1
+				      ? string2[startpos - size1]
+				      : string1[startpos]);
+
+	      if (!fastmap[(unsigned char) TRANSLATE (c)])
+		goto advance;
+	    }
+	}
+
+      /* If can't match the null string, and that's all we have left, fail.  */
+      if (range >= 0 && startpos == total_size && fastmap
+          && !bufp->can_be_null)
+       {
+#ifdef WCHAR
+         FREE_WCS_BUFFERS ();
+#endif
+         return -1;
+       }
+
+#ifdef WCHAR
+      val = wcs_re_match_2_internal (bufp, string1, size1, string2,
+				     size2, startpos, regs, stop,
+				     wcs_string1, wcs_size1,
+				     wcs_string2, wcs_size2,
+				     mbs_offset1, mbs_offset2);
+#else /* BYTE */
+      val = byte_re_match_2_internal (bufp, string1, size1, string2,
+				      size2, startpos, regs, stop);
+#endif /* BYTE */
+
+#ifndef REGEX_MALLOC
+# ifdef C_ALLOCA
+      alloca (0);
+# endif
+#endif
+
+      if (val >= 0)
+	{
+#ifdef WCHAR
+	  FREE_WCS_BUFFERS ();
+#endif
+	  return startpos;
+	}
+
+      if (val == -2)
+	{
+#ifdef WCHAR
+	  FREE_WCS_BUFFERS ();
+#endif
+	  return -2;
+	}
+
+    advance:
+      if (!range)
+        break;
+      else if (range > 0)
+        {
+          range--;
+          startpos++;
+        }
+      else
+        {
+          range++;
+          startpos--;
+        }
+    }
+#ifdef WCHAR
+  FREE_WCS_BUFFERS ();
+#endif
+  return -1;
+}
+
+#ifdef WCHAR
+/* This converts PTR, a pointer into one of the search wchar_t strings
+   `string1' and `string2' into an multibyte string offset from the
+   beginning of that string. We use mbs_offset to optimize.
+   See convert_mbs_to_wcs.  */
+# define POINTER_TO_OFFSET(ptr)						\
+  (FIRST_STRING_P (ptr)							\
+   ? ((regoff_t)(mbs_offset1 != NULL? mbs_offset1[(ptr)-string1] : 0))	\
+   : ((regoff_t)((mbs_offset2 != NULL? mbs_offset2[(ptr)-string2] : 0)	\
+		 + csize1)))
+#else /* BYTE */
+/* This converts PTR, a pointer into one of the search strings `string1'
+   and `string2' into an offset from the beginning of that string.  */
+# define POINTER_TO_OFFSET(ptr)			\
+  (FIRST_STRING_P (ptr)				\
+   ? ((regoff_t) ((ptr) - string1))		\
+   : ((regoff_t) ((ptr) - string2 + size1)))
+#endif /* WCHAR */
+
+/* Macros for dealing with the split strings in re_match_2.  */
+
+#define MATCHING_IN_FIRST_STRING  (dend == end_match_1)
+
+/* Call before fetching a character with *d.  This switches over to
+   string2 if necessary.  */
+#define PREFETCH()							\
+  while (d == dend)						    	\
+    {									\
+      /* End of string2 => fail.  */					\
+      if (dend == end_match_2) 						\
+        goto fail;							\
+      /* End of string1 => advance to string2.  */ 			\
+      d = string2;						        \
+      dend = end_match_2;						\
+    }
+
+/* Test if at very beginning or at very end of the virtual concatenation
+   of `string1' and `string2'.  If only one string, it's `string2'.  */
+#define AT_STRINGS_BEG(d) ((d) == (size1 ? string1 : string2) || !size2)
+#define AT_STRINGS_END(d) ((d) == end2)
+
+
+/* Test if D points to a character which is word-constituent.  We have
+   two special cases to check for: if past the end of string1, look at
+   the first character in string2; and if before the beginning of
+   string2, look at the last character in string1.  */
+#ifdef WCHAR
+/* Use internationalized API instead of SYNTAX.  */
+# define WORDCHAR_P(d)							\
+  (iswalnum ((wint_t)((d) == end1 ? *string2				\
+           : (d) == string2 - 1 ? *(end1 - 1) : *(d))) != 0		\
+   || ((d) == end1 ? *string2						\
+       : (d) == string2 - 1 ? *(end1 - 1) : *(d)) == L'_')
+#else /* BYTE */
+# define WORDCHAR_P(d)							\
+  (SYNTAX ((d) == end1 ? *string2					\
+           : (d) == string2 - 1 ? *(end1 - 1) : *(d))			\
+   == Sword)
+#endif /* WCHAR */
+
+/* Disabled due to a compiler bug -- see comment at case wordbound */
+#if 0
+/* Test if the character before D and the one at D differ with respect
+   to being word-constituent.  */
+#define AT_WORD_BOUNDARY(d)						\
+  (AT_STRINGS_BEG (d) || AT_STRINGS_END (d)				\
+   || WORDCHAR_P (d - 1) != WORDCHAR_P (d))
+#endif
+
+/* Free everything we malloc.  */
+#ifdef MATCH_MAY_ALLOCATE
+# ifdef WCHAR
+#  define FREE_VARIABLES()						\
+  do {									\
+    REGEX_FREE_STACK (fail_stack.stack);				\
+    FREE_VAR (regstart);						\
+    FREE_VAR (regend);							\
+    FREE_VAR (old_regstart);						\
+    FREE_VAR (old_regend);						\
+    FREE_VAR (best_regstart);						\
+    FREE_VAR (best_regend);						\
+    FREE_VAR (reg_info);						\
+    FREE_VAR (reg_dummy);						\
+    FREE_VAR (reg_info_dummy);						\
+    if (!cant_free_wcs_buf)						\
+      {									\
+        FREE_VAR (string1);						\
+        FREE_VAR (string2);						\
+        FREE_VAR (mbs_offset1);						\
+        FREE_VAR (mbs_offset2);						\
+      }									\
+  } while (0)
+# else /* BYTE */
+#  define FREE_VARIABLES()						\
+  do {									\
+    REGEX_FREE_STACK (fail_stack.stack);				\
+    FREE_VAR (regstart);						\
+    FREE_VAR (regend);							\
+    FREE_VAR (old_regstart);						\
+    FREE_VAR (old_regend);						\
+    FREE_VAR (best_regstart);						\
+    FREE_VAR (best_regend);						\
+    FREE_VAR (reg_info);						\
+    FREE_VAR (reg_dummy);						\
+    FREE_VAR (reg_info_dummy);						\
+  } while (0)
+# endif /* WCHAR */
+#else
+# ifdef WCHAR
+#  define FREE_VARIABLES()						\
+  do {									\
+    if (!cant_free_wcs_buf)						\
+      {									\
+        FREE_VAR (string1);						\
+        FREE_VAR (string2);						\
+        FREE_VAR (mbs_offset1);						\
+        FREE_VAR (mbs_offset2);						\
+      }									\
+  } while (0)
+# else /* BYTE */
+#  define FREE_VARIABLES() ((void)0) /* Do nothing!  But inhibit gcc warning. */
+# endif /* WCHAR */
+#endif /* not MATCH_MAY_ALLOCATE */
+
+/* These values must meet several constraints.  They must not be valid
+   register values; since we have a limit of 255 registers (because
+   we use only one byte in the pattern for the register number), we can
+   use numbers larger than 255.  They must differ by 1, because of
+   NUM_FAILURE_ITEMS above.  And the value for the lowest register must
+   be larger than the value for the highest register, so we do not try
+   to actually save any registers when none are active.  */
+#define NO_HIGHEST_ACTIVE_REG (1 << BYTEWIDTH)
+#define NO_LOWEST_ACTIVE_REG (NO_HIGHEST_ACTIVE_REG + 1)
+
+#else /* not INSIDE_RECURSION */
+/* Matching routines.  */
+
+#ifndef emacs   /* Emacs never uses this.  */
+/* re_match is like re_match_2 except it takes only a single string.  */
+
+int
+re_match (struct re_pattern_buffer *bufp, const char *string,
+          int size, int pos, struct re_registers *regs)
+{
+  int result;
+# ifdef MBS_SUPPORT
+  if (MB_CUR_MAX != 1)
+    result = wcs_re_match_2_internal (bufp, NULL, 0, string, size,
+				      pos, regs, size,
+				      NULL, 0, NULL, 0, NULL, NULL);
+  else
+# endif
+    result = byte_re_match_2_internal (bufp, NULL, 0, string, size,
+				  pos, regs, size);
+# ifndef REGEX_MALLOC
+#  ifdef C_ALLOCA
+  alloca (0);
+#  endif
+# endif
+  return result;
+}
+# ifdef _LIBC
+weak_alias (__re_match, re_match)
+# endif
+#endif /* not emacs */
+
+#endif /* not INSIDE_RECURSION */
+
+#ifdef INSIDE_RECURSION
+static boolean PREFIX(group_match_null_string_p) (UCHAR_T **p,
+                                                  UCHAR_T *end,
+					PREFIX(register_info_type) *reg_info);
+static boolean PREFIX(alt_match_null_string_p) (UCHAR_T *p,
+                                                UCHAR_T *end,
+					PREFIX(register_info_type) *reg_info);
+static boolean PREFIX(common_op_match_null_string_p) (UCHAR_T **p,
+                                                      UCHAR_T *end,
+					PREFIX(register_info_type) *reg_info);
+static int PREFIX(bcmp_translate) (const CHAR_T *s1, const CHAR_T *s2,
+                                   register int len,
+				   RE_TRANSLATE_TYPE translate);
+#else /* not INSIDE_RECURSION */
+
+/* re_match_2 matches the compiled pattern in BUFP against the
+   the (virtual) concatenation of STRING1 and STRING2 (of length SIZE1
+   and SIZE2, respectively).  We start matching at POS, and stop
+   matching at STOP.
+
+   If REGS is non-null and the `no_sub' field of BUFP is nonzero, we
+   store offsets for the substring each group matched in REGS.  See the
+   documentation for exactly how many groups we fill.
+
+   We return -1 if no match, -2 if an internal error (such as the
+   failure stack overflowing).  Otherwise, we return the length of the
+   matched substring.  */
+
+int
+re_match_2 (struct re_pattern_buffer *bufp, const char *string1, int size1,
+            const char *string2, int size2, int pos,
+            struct re_registers *regs, int stop)
+{
+  int result;
+# ifdef MBS_SUPPORT
+  if (MB_CUR_MAX != 1)
+    result = wcs_re_match_2_internal (bufp, string1, size1, string2, size2,
+				      pos, regs, stop,
+				      NULL, 0, NULL, 0, NULL, NULL);
+  else
+# endif
+    result = byte_re_match_2_internal (bufp, string1, size1, string2, size2,
+				  pos, regs, stop);
+
+#ifndef REGEX_MALLOC
+# ifdef C_ALLOCA
+  alloca (0);
+# endif
+#endif
+  return result;
+}
+#ifdef _LIBC
+weak_alias (__re_match_2, re_match_2)
+#endif
+
+#endif /* not INSIDE_RECURSION */
+
+#ifdef INSIDE_RECURSION
+
+#ifdef WCHAR
+static int count_mbs_length (int *, int);
+
+/* This check the substring (from 0, to length) of the multibyte string,
+   to which offset_buffer correspond. And count how many wchar_t_characters
+   the substring occupy. We use offset_buffer to optimization.
+   See convert_mbs_to_wcs.  */
+
+static int
+count_mbs_length(int *offset_buffer, int length)
+{
+  int upper, lower;
+
+  /* Check whether the size is valid.  */
+  if (length < 0)
+    return -1;
+
+  if (offset_buffer == NULL)
+    return 0;
+
+  /* If there are no multibyte character, offset_buffer[i] == i.
+   Optmize for this case.  */
+  if (offset_buffer[length] == length)
+    return length;
+
+  /* Set up upper with length. (because for all i, offset_buffer[i] >= i)  */
+  upper = length;
+  lower = 0;
+
+  while (true)
+    {
+      int middle = (lower + upper) / 2;
+      if (middle == lower || middle == upper)
+	break;
+      if (offset_buffer[middle] > length)
+	upper = middle;
+      else if (offset_buffer[middle] < length)
+	lower = middle;
+      else
+	return middle;
+    }
+
+  return -1;
+}
+#endif /* WCHAR */
+
+/* This is a separate function so that we can force an alloca cleanup
+   afterwards.  */
+#ifdef WCHAR
+static int
+wcs_re_match_2_internal (struct re_pattern_buffer *bufp,
+                         const char *cstring1, int csize1,
+                         const char *cstring2, int csize2,
+                         int pos,
+			 struct re_registers *regs,
+                         int stop,
+     /* string1 == string2 == NULL means string1/2, size1/2 and
+	mbs_offset1/2 need seting up in this function.  */
+     /* We need wchar_t* buffers correspond to cstring1, cstring2.  */
+                         wchar_t *string1, int size1,
+                         wchar_t *string2, int size2,
+     /* offset buffer for optimizatoin. See convert_mbs_to_wc.  */
+			 int *mbs_offset1, int *mbs_offset2)
+#else /* BYTE */
+static int
+byte_re_match_2_internal (struct re_pattern_buffer *bufp,
+                          const char *string1, int size1,
+                          const char *string2, int size2,
+                          int pos,
+			  struct re_registers *regs, int stop)
+#endif /* BYTE */
+{
+  /* General temporaries.  */
+  int mcnt;
+  UCHAR_T *p1;
+#ifdef WCHAR
+  /* They hold whether each wchar_t is binary data or not.  */
+  char *is_binary = NULL;
+  /* If true, we can't free string1/2, mbs_offset1/2.  */
+  int cant_free_wcs_buf = 1;
+#endif /* WCHAR */
+
+  /* Just past the end of the corresponding string.  */
+  const CHAR_T *end1, *end2;
+
+  /* Pointers into string1 and string2, just past the last characters in
+     each to consider matching.  */
+  const CHAR_T *end_match_1, *end_match_2;
+
+  /* Where we are in the data, and the end of the current string.  */
+  const CHAR_T *d, *dend;
+
+  /* Where we are in the pattern, and the end of the pattern.  */
+#ifdef WCHAR
+  UCHAR_T *pattern, *p;
+  register UCHAR_T *pend;
+#else /* BYTE */
+  UCHAR_T *p = bufp->buffer;
+  register UCHAR_T *pend = p + bufp->used;
+#endif /* WCHAR */
+
+  /* Mark the opcode just after a start_memory, so we can test for an
+     empty subpattern when we get to the stop_memory.  */
+  UCHAR_T *just_past_start_mem = 0;
+
+  /* We use this to map every character in the string.  */
+  RE_TRANSLATE_TYPE translate = bufp->translate;
+
+  /* Failure point stack.  Each place that can handle a failure further
+     down the line pushes a failure point on this stack.  It consists of
+     restart, regend, and reg_info for all registers corresponding to
+     the subexpressions we're currently inside, plus the number of such
+     registers, and, finally, two char *'s.  The first char * is where
+     to resume scanning the pattern; the second one is where to resume
+     scanning the strings.  If the latter is zero, the failure point is
+     a ``dummy''; if a failure happens and the failure point is a dummy,
+     it gets discarded and the next next one is tried.  */
+#ifdef MATCH_MAY_ALLOCATE /* otherwise, this is global.  */
+  PREFIX(fail_stack_type) fail_stack;
+#endif
+#ifdef DEBUG
+  static unsigned failure_id;
+  unsigned nfailure_points_pushed = 0, nfailure_points_popped = 0;
+#endif
+
+#ifdef REL_ALLOC
+  /* This holds the pointer to the failure stack, when
+     it is allocated relocatably.  */
+  fail_stack_elt_t *failure_stack_ptr;
+#endif
+
+  /* We fill all the registers internally, independent of what we
+     return, for use in backreferences.  The number here includes
+     an element for register zero.  */
+  size_t num_regs = bufp->re_nsub + 1;
+
+  /* The currently active registers.  */
+  active_reg_t lowest_active_reg = NO_LOWEST_ACTIVE_REG;
+  active_reg_t highest_active_reg = NO_HIGHEST_ACTIVE_REG;
+
+  /* Information on the contents of registers. These are pointers into
+     the input strings; they record just what was matched (on this
+     attempt) by a subexpression part of the pattern, that is, the
+     regnum-th regstart pointer points to where in the pattern we began
+     matching and the regnum-th regend points to right after where we
+     stopped matching the regnum-th subexpression.  (The zeroth register
+     keeps track of what the whole pattern matches.)  */
+#ifdef MATCH_MAY_ALLOCATE /* otherwise, these are global.  */
+  const CHAR_T **regstart, **regend;
+#endif
+
+  /* If a group that's operated upon by a repetition operator fails to
+     match anything, then the register for its start will need to be
+     restored because it will have been set to wherever in the string we
+     are when we last see its open-group operator.  Similarly for a
+     register's end.  */
+#ifdef MATCH_MAY_ALLOCATE /* otherwise, these are global.  */
+  const CHAR_T **old_regstart, **old_regend;
+#endif
+
+  /* The is_active field of reg_info helps us keep track of which (possibly
+     nested) subexpressions we are currently in. The matched_something
+     field of reg_info[reg_num] helps us tell whether or not we have
+     matched any of the pattern so far this time through the reg_num-th
+     subexpression.  These two fields get reset each time through any
+     loop their register is in.  */
+#ifdef MATCH_MAY_ALLOCATE /* otherwise, this is global.  */
+  PREFIX(register_info_type) *reg_info;
+#endif
+
+  /* The following record the register info as found in the above
+     variables when we find a match better than any we've seen before.
+     This happens as we backtrack through the failure points, which in
+     turn happens only if we have not yet matched the entire string. */
+  unsigned best_regs_set = false;
+#ifdef MATCH_MAY_ALLOCATE /* otherwise, these are global.  */
+  const CHAR_T **best_regstart, **best_regend;
+#endif
+
+  /* Logically, this is `best_regend[0]'.  But we don't want to have to
+     allocate space for that if we're not allocating space for anything
+     else (see below).  Also, we never need info about register 0 for
+     any of the other register vectors, and it seems rather a kludge to
+     treat `best_regend' differently than the rest.  So we keep track of
+     the end of the best match so far in a separate variable.  We
+     initialize this to NULL so that when we backtrack the first time
+     and need to test it, it's not garbage.  */
+  const CHAR_T *match_end = NULL;
+
+  /* This helps SET_REGS_MATCHED avoid doing redundant work.  */
+  int set_regs_matched_done = 0;
+
+  /* Used when we pop values we don't care about.  */
+#ifdef MATCH_MAY_ALLOCATE /* otherwise, these are global.  */
+  const CHAR_T **reg_dummy;
+  PREFIX(register_info_type) *reg_info_dummy;
+#endif
+
+#ifdef DEBUG
+  /* Counts the total number of registers pushed.  */
+  unsigned num_regs_pushed = 0;
+#endif
+
+  DEBUG_PRINT1 ("\n\nEntering re_match_2.\n");
+
+  INIT_FAIL_STACK ();
+
+#ifdef MATCH_MAY_ALLOCATE
+  /* Do not bother to initialize all the register variables if there are
+     no groups in the pattern, as it takes a fair amount of time.  If
+     there are groups, we include space for register 0 (the whole
+     pattern), even though we never use it, since it simplifies the
+     array indexing.  We should fix this.  */
+  if (bufp->re_nsub)
+    {
+      regstart = REGEX_TALLOC (num_regs, const CHAR_T *);
+      regend = REGEX_TALLOC (num_regs, const CHAR_T *);
+      old_regstart = REGEX_TALLOC (num_regs, const CHAR_T *);
+      old_regend = REGEX_TALLOC (num_regs, const CHAR_T *);
+      best_regstart = REGEX_TALLOC (num_regs, const CHAR_T *);
+      best_regend = REGEX_TALLOC (num_regs, const CHAR_T *);
+      reg_info = REGEX_TALLOC (num_regs, PREFIX(register_info_type));
+      reg_dummy = REGEX_TALLOC (num_regs, const CHAR_T *);
+      reg_info_dummy = REGEX_TALLOC (num_regs, PREFIX(register_info_type));
+
+      if (!(regstart && regend && old_regstart && old_regend && reg_info
+            && best_regstart && best_regend && reg_dummy && reg_info_dummy))
+        {
+          FREE_VARIABLES ();
+          return -2;
+        }
+    }
+  else
+    {
+      /* We must initialize all our variables to NULL, so that
+         `FREE_VARIABLES' doesn't try to free them.  */
+      regstart = regend = old_regstart = old_regend = best_regstart
+        = best_regend = reg_dummy = NULL;
+      reg_info = reg_info_dummy = (PREFIX(register_info_type) *) NULL;
+    }
+#endif /* MATCH_MAY_ALLOCATE */
+
+  /* The starting position is bogus.  */
+#ifdef WCHAR
+  if (pos < 0 || pos > csize1 + csize2)
+#else /* BYTE */
+  if (pos < 0 || pos > size1 + size2)
+#endif
+    {
+      FREE_VARIABLES ();
+      return -1;
+    }
+
+#ifdef WCHAR
+  /* Allocate wchar_t array for string1 and string2 and
+     fill them with converted string.  */
+  if (string1 == NULL && string2 == NULL)
+    {
+      /* We need seting up buffers here.  */
+
+      /* We must free wcs buffers in this function.  */
+      cant_free_wcs_buf = 0;
+
+      if (csize1 != 0)
+	{
+	  string1 = REGEX_TALLOC (csize1 + 1, CHAR_T);
+	  mbs_offset1 = REGEX_TALLOC (csize1 + 1, int);
+	  is_binary = REGEX_TALLOC (csize1 + 1, char);
+	  if (!string1 || !mbs_offset1 || !is_binary)
+	    {
+	      FREE_VAR (string1);
+	      FREE_VAR (mbs_offset1);
+	      FREE_VAR (is_binary);
+	      return -2;
+	    }
+	}
+      if (csize2 != 0)
+	{
+	  string2 = REGEX_TALLOC (csize2 + 1, CHAR_T);
+	  mbs_offset2 = REGEX_TALLOC (csize2 + 1, int);
+	  is_binary = REGEX_TALLOC (csize2 + 1, char);
+	  if (!string2 || !mbs_offset2 || !is_binary)
+	    {
+	      FREE_VAR (string1);
+	      FREE_VAR (mbs_offset1);
+	      FREE_VAR (string2);
+	      FREE_VAR (mbs_offset2);
+	      FREE_VAR (is_binary);
+	      return -2;
+	    }
+	  size2 = convert_mbs_to_wcs(string2, cstring2, csize2,
+				     mbs_offset2, is_binary);
+	  string2[size2] = L'\0'; /* for a sentinel  */
+	  FREE_VAR (is_binary);
+	}
+    }
+
+  /* We need to cast pattern to (wchar_t*), because we casted this compiled
+     pattern to (char*) in regex_compile.  */
+  p = pattern = (CHAR_T*)bufp->buffer;
+  pend = (CHAR_T*)(bufp->buffer + bufp->used);
+
+#endif /* WCHAR */
+
+  /* Initialize subexpression text positions to -1 to mark ones that no
+     start_memory/stop_memory has been seen for. Also initialize the
+     register information struct.  */
+  for (mcnt = 1; (unsigned) mcnt < num_regs; mcnt++)
+    {
+      regstart[mcnt] = regend[mcnt]
+        = old_regstart[mcnt] = old_regend[mcnt] = REG_UNSET_VALUE;
+
+      REG_MATCH_NULL_STRING_P (reg_info[mcnt]) = MATCH_NULL_UNSET_VALUE;
+      IS_ACTIVE (reg_info[mcnt]) = 0;
+      MATCHED_SOMETHING (reg_info[mcnt]) = 0;
+      EVER_MATCHED_SOMETHING (reg_info[mcnt]) = 0;
+    }
+
+  /* We move `string1' into `string2' if the latter's empty -- but not if
+     `string1' is null.  */
+  if (size2 == 0 && string1 != NULL)
+    {
+      string2 = string1;
+      size2 = size1;
+      string1 = 0;
+      size1 = 0;
+#ifdef WCHAR
+      mbs_offset2 = mbs_offset1;
+      csize2 = csize1;
+      mbs_offset1 = NULL;
+      csize1 = 0;
+#endif
+    }
+  end1 = string1 + size1;
+  end2 = string2 + size2;
+
+  /* Compute where to stop matching, within the two strings.  */
+#ifdef WCHAR
+  if (stop <= csize1)
+    {
+      mcnt = count_mbs_length(mbs_offset1, stop);
+      end_match_1 = string1 + mcnt;
+      end_match_2 = string2;
+    }
+  else
+    {
+      if (stop > csize1 + csize2)
+	stop = csize1 + csize2;
+      end_match_1 = end1;
+      mcnt = count_mbs_length(mbs_offset2, stop-csize1);
+      end_match_2 = string2 + mcnt;
+    }
+  if (mcnt < 0)
+    { /* count_mbs_length return error.  */
+      FREE_VARIABLES ();
+      return -1;
+    }
+#else
+  if (stop <= size1)
+    {
+      end_match_1 = string1 + stop;
+      end_match_2 = string2;
+    }
+  else
+    {
+      end_match_1 = end1;
+      end_match_2 = string2 + stop - size1;
+    }
+#endif /* WCHAR */
+
+  /* `p' scans through the pattern as `d' scans through the data.
+     `dend' is the end of the input string that `d' points within.  `d'
+     is advanced into the following input string whenever necessary, but
+     this happens before fetching; therefore, at the beginning of the
+     loop, `d' can be pointing at the end of a string, but it cannot
+     equal `string2'.  */
+#ifdef WCHAR
+  if (size1 > 0 && pos <= csize1)
+    {
+      mcnt = count_mbs_length(mbs_offset1, pos);
+      d = string1 + mcnt;
+      dend = end_match_1;
+    }
+  else
+    {
+      mcnt = count_mbs_length(mbs_offset2, pos-csize1);
+      d = string2 + mcnt;
+      dend = end_match_2;
+    }
+
+  if (mcnt < 0)
+    { /* count_mbs_length return error.  */
+      FREE_VARIABLES ();
+      return -1;
+    }
+#else
+  if (size1 > 0 && pos <= size1)
+    {
+      d = string1 + pos;
+      dend = end_match_1;
+    }
+  else
+    {
+      d = string2 + pos - size1;
+      dend = end_match_2;
+    }
+#endif /* WCHAR */
+
+  DEBUG_PRINT1 ("The compiled pattern is:\n");
+  DEBUG_PRINT_COMPILED_PATTERN (bufp, p, pend);
+  DEBUG_PRINT1 ("The string to match is: `");
+  DEBUG_PRINT_DOUBLE_STRING (d, string1, size1, string2, size2);
+  DEBUG_PRINT1 ("'\n");
+
+  /* This loops over pattern commands.  It exits by returning from the
+     function if the match is complete, or it drops through if the match
+     fails at this starting point in the input data.  */
+  for (;;)
+    {
+#ifdef _LIBC
+      DEBUG_PRINT2 ("\n%p: ", p);
+#else
+      DEBUG_PRINT2 ("\n0x%x: ", p);
+#endif
+
+      if (p == pend)
+	{ /* End of pattern means we might have succeeded.  */
+          DEBUG_PRINT1 ("end of pattern ... ");
+
+	  /* If we haven't matched the entire string, and we want the
+             longest match, try backtracking.  */
+          if (d != end_match_2)
+	    {
+	      /* 1 if this match ends in the same string (string1 or string2)
+		 as the best previous match.  */
+	      boolean same_str_p = (FIRST_STRING_P (match_end)
+				    == MATCHING_IN_FIRST_STRING);
+	      /* 1 if this match is the best seen so far.  */
+	      boolean best_match_p;
+
+	      /* AIX compiler got confused when this was combined
+		 with the previous declaration.  */
+	      if (same_str_p)
+		best_match_p = d > match_end;
+	      else
+		best_match_p = !MATCHING_IN_FIRST_STRING;
+
+              DEBUG_PRINT1 ("backtracking.\n");
+
+              if (!FAIL_STACK_EMPTY ())
+                { /* More failure points to try.  */
+
+                  /* If exceeds best match so far, save it.  */
+                  if (!best_regs_set || best_match_p)
+                    {
+                      best_regs_set = true;
+                      match_end = d;
+
+                      DEBUG_PRINT1 ("\nSAVING match as best so far.\n");
+
+                      for (mcnt = 1; (unsigned) mcnt < num_regs; mcnt++)
+                        {
+                          best_regstart[mcnt] = regstart[mcnt];
+                          best_regend[mcnt] = regend[mcnt];
+                        }
+                    }
+                  goto fail;
+                }
+
+              /* If no failure points, don't restore garbage.  And if
+                 last match is real best match, don't restore second
+                 best one. */
+              else if (best_regs_set && !best_match_p)
+                {
+  	        restore_best_regs:
+                  /* Restore best match.  It may happen that `dend ==
+                     end_match_1' while the restored d is in string2.
+                     For example, the pattern `x.*y.*z' against the
+                     strings `x-' and `y-z-', if the two strings are
+                     not consecutive in memory.  */
+                  DEBUG_PRINT1 ("Restoring best registers.\n");
+
+                  d = match_end;
+                  dend = ((d >= string1 && d <= end1)
+		           ? end_match_1 : end_match_2);
+
+		  for (mcnt = 1; (unsigned) mcnt < num_regs; mcnt++)
+		    {
+		      regstart[mcnt] = best_regstart[mcnt];
+		      regend[mcnt] = best_regend[mcnt];
+		    }
+                }
+            } /* d != end_match_2 */
+
+	succeed_label:
+          DEBUG_PRINT1 ("Accepting match.\n");
+          /* If caller wants register contents data back, do it.  */
+          if (regs && !bufp->no_sub)
+	    {
+	      /* Have the register data arrays been allocated?  */
+              if (bufp->regs_allocated == REGS_UNALLOCATED)
+                { /* No.  So allocate them with malloc.  We need one
+                     extra element beyond `num_regs' for the `-1' marker
+                     GNU code uses.  */
+                  regs->num_regs = MAX (RE_NREGS, num_regs + 1);
+                  regs->start = TALLOC (regs->num_regs, regoff_t);
+                  regs->end = TALLOC (regs->num_regs, regoff_t);
+                  if (regs->start == NULL || regs->end == NULL)
+		    {
+		      FREE_VARIABLES ();
+		      return -2;
+		    }
+                  bufp->regs_allocated = REGS_REALLOCATE;
+                }
+              else if (bufp->regs_allocated == REGS_REALLOCATE)
+                { /* Yes.  If we need more elements than were already
+                     allocated, reallocate them.  If we need fewer, just
+                     leave it alone.  */
+                  if (regs->num_regs < num_regs + 1)
+                    {
+                      regs->num_regs = num_regs + 1;
+                      RETALLOC (regs->start, regs->num_regs, regoff_t);
+                      RETALLOC (regs->end, regs->num_regs, regoff_t);
+                      if (regs->start == NULL || regs->end == NULL)
+			{
+			  FREE_VARIABLES ();
+			  return -2;
+			}
+                    }
+                }
+              else
+		{
+		  /* These braces fend off a "empty body in an else-statement"
+		     warning under GCC when assert expands to nothing.  */
+		  assert (bufp->regs_allocated == REGS_FIXED);
+		}
+
+              /* Convert the pointer data in `regstart' and `regend' to
+                 indices.  Register zero has to be set differently,
+                 since we haven't kept track of any info for it.  */
+              if (regs->num_regs > 0)
+                {
+                  regs->start[0] = pos;
+#ifdef WCHAR
+		  if (MATCHING_IN_FIRST_STRING)
+		    regs->end[0] = mbs_offset1 != NULL ?
+					mbs_offset1[d-string1] : 0;
+		  else
+		    regs->end[0] = csize1 + (mbs_offset2 != NULL ?
+					     mbs_offset2[d-string2] : 0);
+#else
+                  regs->end[0] = (MATCHING_IN_FIRST_STRING
+				  ? ((regoff_t) (d - string1))
+			          : ((regoff_t) (d - string2 + size1)));
+#endif /* WCHAR */
+                }
+
+              /* Go through the first `min (num_regs, regs->num_regs)'
+                 registers, since that is all we initialized.  */
+	      for (mcnt = 1; (unsigned) mcnt < MIN (num_regs, regs->num_regs);
+		   mcnt++)
+		{
+                  if (REG_UNSET (regstart[mcnt]) || REG_UNSET (regend[mcnt]))
+                    regs->start[mcnt] = regs->end[mcnt] = -1;
+                  else
+                    {
+		      regs->start[mcnt]
+			= (regoff_t) POINTER_TO_OFFSET (regstart[mcnt]);
+                      regs->end[mcnt]
+			= (regoff_t) POINTER_TO_OFFSET (regend[mcnt]);
+                    }
+		}
+
+              /* If the regs structure we return has more elements than
+                 were in the pattern, set the extra elements to -1.  If
+                 we (re)allocated the registers, this is the case,
+                 because we always allocate enough to have at least one
+                 -1 at the end.  */
+              for (mcnt = num_regs; (unsigned) mcnt < regs->num_regs; mcnt++)
+                regs->start[mcnt] = regs->end[mcnt] = -1;
+	    } /* regs && !bufp->no_sub */
+
+          DEBUG_PRINT4 ("%u failure points pushed, %u popped (%u remain).\n",
+                        nfailure_points_pushed, nfailure_points_popped,
+                        nfailure_points_pushed - nfailure_points_popped);
+          DEBUG_PRINT2 ("%u registers pushed.\n", num_regs_pushed);
+
+#ifdef WCHAR
+	  if (MATCHING_IN_FIRST_STRING)
+	    mcnt = mbs_offset1 != NULL ? mbs_offset1[d-string1] : 0;
+	  else
+	    mcnt = (mbs_offset2 != NULL ? mbs_offset2[d-string2] : 0) +
+			csize1;
+          mcnt -= pos;
+#else
+          mcnt = d - pos - (MATCHING_IN_FIRST_STRING
+			    ? string1
+			    : string2 - size1);
+#endif /* WCHAR */
+
+          DEBUG_PRINT2 ("Returning %d from re_match_2.\n", mcnt);
+
+          FREE_VARIABLES ();
+          return mcnt;
+        }
+
+      /* Otherwise match next pattern command.  */
+      switch (SWITCH_ENUM_CAST ((re_opcode_t) *p++))
+	{
+        /* Ignore these.  Used to ignore the n of succeed_n's which
+           currently have n == 0.  */
+        case no_op:
+          DEBUG_PRINT1 ("EXECUTING no_op.\n");
+          break;
+
+	case succeed:
+          DEBUG_PRINT1 ("EXECUTING succeed.\n");
+	  goto succeed_label;
+
+        /* Match the next n pattern characters exactly.  The following
+           byte in the pattern defines n, and the n bytes after that
+           are the characters to match.  */
+	case exactn:
+#ifdef MBS_SUPPORT
+	case exactn_bin:
+#endif
+	  mcnt = *p++;
+          DEBUG_PRINT2 ("EXECUTING exactn %d.\n", mcnt);
+
+          /* This is written out as an if-else so we don't waste time
+             testing `translate' inside the loop.  */
+          if (translate)
+	    {
+	      do
+		{
+		  PREFETCH ();
+#ifdef WCHAR
+		  if (*d <= 0xff)
+		    {
+		      if ((UCHAR_T) translate[(unsigned char) *d++]
+			  != (UCHAR_T) *p++)
+			goto fail;
+		    }
+		  else
+		    {
+		      if (*d++ != (CHAR_T) *p++)
+			goto fail;
+		    }
+#else
+		  if ((UCHAR_T) translate[(unsigned char) *d++]
+		      != (UCHAR_T) *p++)
+                    goto fail;
+#endif /* WCHAR */
+		}
+	      while (--mcnt);
+	    }
+	  else
+	    {
+	      do
+		{
+		  PREFETCH ();
+		  if (*d++ != (CHAR_T) *p++) goto fail;
+		}
+	      while (--mcnt);
+	    }
+	  SET_REGS_MATCHED ();
+          break;
+
+
+        /* Match any character except possibly a newline or a null.  */
+	case anychar:
+          DEBUG_PRINT1 ("EXECUTING anychar.\n");
+
+          PREFETCH ();
+
+          if ((!(bufp->syntax & RE_DOT_NEWLINE) && TRANSLATE (*d) == '\n')
+              || (bufp->syntax & RE_DOT_NOT_NULL && TRANSLATE (*d) == '\000'))
+	    goto fail;
+
+          SET_REGS_MATCHED ();
+          DEBUG_PRINT2 ("  Matched `%ld'.\n", (long int) *d);
+          d++;
+	  break;
+
+
+	case charset:
+	case charset_not:
+	  {
+	    register UCHAR_T c;
+#ifdef WCHAR
+	    unsigned int i, char_class_length, coll_symbol_length,
+              equiv_class_length, ranges_length, chars_length, length;
+	    CHAR_T *workp, *workp2, *charset_top;
+#define WORK_BUFFER_SIZE 128
+            CHAR_T str_buf[WORK_BUFFER_SIZE];
+# ifdef _LIBC
+	    uint32_t nrules;
+# endif /* _LIBC */
+#endif /* WCHAR */
+	    boolean negate = (re_opcode_t) *(p - 1) == charset_not;
+
+            DEBUG_PRINT2 ("EXECUTING charset%s.\n", negate ? "_not" : "");
+	    PREFETCH ();
+	    c = TRANSLATE (*d); /* The character to match.  */
+#ifdef WCHAR
+# ifdef _LIBC
+	    nrules = _NL_CURRENT_WORD (LC_COLLATE, _NL_COLLATE_NRULES);
+# endif /* _LIBC */
+	    charset_top = p - 1;
+	    char_class_length = *p++;
+	    coll_symbol_length = *p++;
+	    equiv_class_length = *p++;
+	    ranges_length = *p++;
+	    chars_length = *p++;
+	    /* p points charset[6], so the address of the next instruction
+	       (charset[l+m+n+2o+k+p']) equals p[l+m+n+2*o+p'],
+	       where l=length of char_classes, m=length of collating_symbol,
+	       n=equivalence_class, o=length of char_range,
+	       p'=length of character.  */
+	    workp = p;
+	    /* Update p to indicate the next instruction.  */
+	    p += char_class_length + coll_symbol_length+ equiv_class_length +
+              2*ranges_length + chars_length;
+
+            /* match with char_class?  */
+	    for (i = 0; i < char_class_length ; i += CHAR_CLASS_SIZE)
+	      {
+		wctype_t wctype;
+		uintptr_t alignedp = ((uintptr_t)workp
+				      + __alignof__(wctype_t) - 1)
+		  		      & ~(uintptr_t)(__alignof__(wctype_t) - 1);
+		wctype = *((wctype_t*)alignedp);
+		workp += CHAR_CLASS_SIZE;
+# ifdef _LIBC
+		if (__iswctype((wint_t)c, wctype))
+		  goto char_set_matched;
+# else
+		if (iswctype((wint_t)c, wctype))
+		  goto char_set_matched;
+# endif
+	      }
+
+            /* match with collating_symbol?  */
+# ifdef _LIBC
+	    if (nrules != 0)
+	      {
+		const unsigned char *extra = (const unsigned char *)
+		  _NL_CURRENT (LC_COLLATE, _NL_COLLATE_SYMB_EXTRAMB);
+
+		for (workp2 = workp + coll_symbol_length ; workp < workp2 ;
+		     workp++)
+		  {
+		    int32_t *wextra;
+		    wextra = (int32_t*)(extra + *workp++);
+		    for (i = 0; i < *wextra; ++i)
+		      if (TRANSLATE(d[i]) != wextra[1 + i])
+			break;
+
+		    if (i == *wextra)
+		      {
+			/* Update d, however d will be incremented at
+			   char_set_matched:, we decrement d here.  */
+			d += i - 1;
+			goto char_set_matched;
+		      }
+		  }
+	      }
+	    else /* (nrules == 0) */
+# endif
+	      /* If we can't look up collation data, we use wcscoll
+		 instead.  */
+	      {
+		for (workp2 = workp + coll_symbol_length ; workp < workp2 ;)
+		  {
+		    const CHAR_T *backup_d = d, *backup_dend = dend;
+# ifdef _LIBC
+		    length = __wcslen (workp);
+# else
+		    length = wcslen (workp);
+# endif
+
+		    /* If wcscoll(the collating symbol, whole string) > 0,
+		       any substring of the string never match with the
+		       collating symbol.  */
+# ifdef _LIBC
+		    if (__wcscoll (workp, d) > 0)
+# else
+		    if (wcscoll (workp, d) > 0)
+# endif
+		      {
+			workp += length + 1;
+			continue;
+		      }
+
+		    /* First, we compare the collating symbol with
+		       the first character of the string.
+		       If it don't match, we add the next character to
+		       the compare buffer in turn.  */
+		    for (i = 0 ; i < WORK_BUFFER_SIZE-1 ; i++, d++)
+		      {
+			int match;
+			if (d == dend)
+			  {
+			    if (dend == end_match_2)
+			      break;
+			    d = string2;
+			    dend = end_match_2;
+			  }
+
+			/* add next character to the compare buffer.  */
+			str_buf[i] = TRANSLATE(*d);
+			str_buf[i+1] = '\0';
+
+# ifdef _LIBC
+			match = __wcscoll (workp, str_buf);
+# else
+			match = wcscoll (workp, str_buf);
+# endif
+			if (match == 0)
+			  goto char_set_matched;
+
+			if (match < 0)
+			  /* (str_buf > workp) indicate (str_buf + X > workp),
+			     because for all X (str_buf + X > str_buf).
+			     So we don't need continue this loop.  */
+			  break;
+
+			/* Otherwise(str_buf < workp),
+			   (str_buf+next_character) may equals (workp).
+			   So we continue this loop.  */
+		      }
+		    /* not matched */
+		    d = backup_d;
+		    dend = backup_dend;
+		    workp += length + 1;
+		  }
+              }
+            /* match with equivalence_class?  */
+# ifdef _LIBC
+	    if (nrules != 0)
+	      {
+                const CHAR_T *backup_d = d, *backup_dend = dend;
+		/* Try to match the equivalence class against
+		   those known to the collate implementation.  */
+		const int32_t *table;
+		const int32_t *weights;
+		const int32_t *extra;
+		const int32_t *indirect;
+		int32_t idx, idx2;
+		wint_t *cp;
+		size_t len;
+
+		table = (const int32_t *)
+		  _NL_CURRENT (LC_COLLATE, _NL_COLLATE_TABLEWC);
+		weights = (const wint_t *)
+		  _NL_CURRENT (LC_COLLATE, _NL_COLLATE_WEIGHTWC);
+		extra = (const wint_t *)
+		  _NL_CURRENT (LC_COLLATE, _NL_COLLATE_EXTRAWC);
+		indirect = (const int32_t *)
+		  _NL_CURRENT (LC_COLLATE, _NL_COLLATE_INDIRECTWC);
+
+		/* Write 1 collating element to str_buf, and
+		   get its index.  */
+		idx2 = 0;
+
+		for (i = 0 ; idx2 == 0 && i < WORK_BUFFER_SIZE - 1; i++)
+		  {
+		    cp = (wint_t*)str_buf;
+		    if (d == dend)
+		      {
+			if (dend == end_match_2)
+			  break;
+			d = string2;
+			dend = end_match_2;
+		      }
+		    str_buf[i] = TRANSLATE(*(d+i));
+		    str_buf[i+1] = '\0'; /* sentinel */
+		    idx2 = FINDIDX (table, indirect, extra, &cp, 1);
+		  }
+
+		/* Update d, however d will be incremented at
+		   char_set_matched:, we decrement d here.  */
+		d = backup_d + ((wchar_t*)cp - (wchar_t*)str_buf - 1);
+		if (d >= dend)
+		  {
+		    if (dend == end_match_2)
+			d = dend;
+		    else
+		      {
+			d = string2;
+			dend = end_match_2;
+		      }
+		  }
+
+		len = weights[idx2];
+
+		for (workp2 = workp + equiv_class_length ; workp < workp2 ;
+		     workp++)
+		  {
+		    idx = (int32_t)*workp;
+		    /* We already checked idx != 0 in regex_compile. */
+
+		    if (idx2 != 0 && len == weights[idx])
+		      {
+			int cnt = 0;
+			while (cnt < len && (weights[idx + 1 + cnt]
+					     == weights[idx2 + 1 + cnt]))
+			  ++cnt;
+
+			if (cnt == len)
+			  goto char_set_matched;
+		      }
+		  }
+		/* not matched */
+                d = backup_d;
+                dend = backup_dend;
+	      }
+	    else /* (nrules == 0) */
+# endif
+	      /* If we can't look up collation data, we use wcscoll
+		 instead.  */
+	      {
+		for (workp2 = workp + equiv_class_length ; workp < workp2 ;)
+		  {
+		    const CHAR_T *backup_d = d, *backup_dend = dend;
+# ifdef _LIBC
+		    length = __wcslen (workp);
+# else
+		    length = wcslen (workp);
+# endif
+
+		    /* If wcscoll(the collating symbol, whole string) > 0,
+		       any substring of the string never match with the
+		       collating symbol.  */
+# ifdef _LIBC
+		    if (__wcscoll (workp, d) > 0)
+# else
+		    if (wcscoll (workp, d) > 0)
+# endif
+		      {
+			workp += length + 1;
+			break;
+		      }
+
+		    /* First, we compare the equivalence class with
+		       the first character of the string.
+		       If it don't match, we add the next character to
+		       the compare buffer in turn.  */
+		    for (i = 0 ; i < WORK_BUFFER_SIZE - 1 ; i++, d++)
+		      {
+			int match;
+			if (d == dend)
+			  {
+			    if (dend == end_match_2)
+			      break;
+			    d = string2;
+			    dend = end_match_2;
+			  }
+
+			/* add next character to the compare buffer.  */
+			str_buf[i] = TRANSLATE(*d);
+			str_buf[i+1] = '\0';
+
+# ifdef _LIBC
+			match = __wcscoll (workp, str_buf);
+# else
+			match = wcscoll (workp, str_buf);
+# endif
+
+			if (match == 0)
+			  goto char_set_matched;
+
+			if (match < 0)
+			/* (str_buf > workp) indicate (str_buf + X > workp),
+			   because for all X (str_buf + X > str_buf).
+			   So we don't need continue this loop.  */
+			  break;
+
+			/* Otherwise(str_buf < workp),
+			   (str_buf+next_character) may equals (workp).
+			   So we continue this loop.  */
+		      }
+		    /* not matched */
+		    d = backup_d;
+		    dend = backup_dend;
+		    workp += length + 1;
+		  }
+	      }
+
+            /* match with char_range?  */
+# ifdef _LIBC
+	    if (nrules != 0)
+	      {
+		uint32_t collseqval;
+		const char *collseq = (const char *)
+		  _NL_CURRENT(LC_COLLATE, _NL_COLLATE_COLLSEQWC);
+
+		collseqval = collseq_table_lookup (collseq, c);
+
+		for (; workp < p - chars_length ;)
+		  {
+		    uint32_t start_val, end_val;
+
+		    /* We already compute the collation sequence value
+		       of the characters (or collating symbols).  */
+		    start_val = (uint32_t) *workp++; /* range_start */
+		    end_val = (uint32_t) *workp++; /* range_end */
+
+		    if (start_val <= collseqval && collseqval <= end_val)
+		      goto char_set_matched;
+		  }
+	      }
+	    else
+# endif
+	      {
+		/* We set range_start_char at str_buf[0], range_end_char
+		   at str_buf[4], and compared char at str_buf[2].  */
+		str_buf[1] = 0;
+		str_buf[2] = c;
+		str_buf[3] = 0;
+		str_buf[5] = 0;
+		for (; workp < p - chars_length ;)
+		  {
+		    wchar_t *range_start_char, *range_end_char;
+
+		    /* match if (range_start_char <= c <= range_end_char).  */
+
+		    /* If range_start(or end) < 0, we assume -range_start(end)
+		       is the offset of the collating symbol which is specified
+		       as the character of the range start(end).  */
+
+		    /* range_start */
+		    if (*workp < 0)
+		      range_start_char = charset_top - (*workp++);
+		    else
+		      {
+			str_buf[0] = *workp++;
+			range_start_char = str_buf;
+		      }
+
+		    /* range_end */
+		    if (*workp < 0)
+		      range_end_char = charset_top - (*workp++);
+		    else
+		      {
+			str_buf[4] = *workp++;
+			range_end_char = str_buf + 4;
+		      }
+
+# ifdef _LIBC
+		    if (__wcscoll (range_start_char, str_buf+2) <= 0
+			&& __wcscoll (str_buf+2, range_end_char) <= 0)
+# else
+		    if (wcscoll (range_start_char, str_buf+2) <= 0
+			&& wcscoll (str_buf+2, range_end_char) <= 0)
+# endif
+		      goto char_set_matched;
+		  }
+	      }
+
+            /* match with char?  */
+	    for (; workp < p ; workp++)
+	      if (c == *workp)
+		goto char_set_matched;
+
+	    negate = !negate;
+
+	  char_set_matched:
+	    if (negate) goto fail;
+#else
+            /* Cast to `unsigned' instead of `unsigned char' in case the
+               bit list is a full 32 bytes long.  */
+	    if (c < (unsigned) (*p * BYTEWIDTH)
+		&& p[1 + c / BYTEWIDTH] & (1 << (c % BYTEWIDTH)))
+	      negate = !negate;
+
+	    p += 1 + *p;
+
+	    if (!negate) goto fail;
+#undef WORK_BUFFER_SIZE
+#endif /* WCHAR */
+	    SET_REGS_MATCHED ();
+            d++;
+	    break;
+	  }
+
+
+        /* The beginning of a group is represented by start_memory.
+           The arguments are the register number in the next byte, and the
+           number of groups inner to this one in the next.  The text
+           matched within the group is recorded (in the internal
+           registers data structure) under the register number.  */
+        case start_memory:
+	  DEBUG_PRINT3 ("EXECUTING start_memory %ld (%ld):\n",
+			(long int) *p, (long int) p[1]);
+
+          /* Find out if this group can match the empty string.  */
+	  p1 = p;		/* To send to group_match_null_string_p.  */
+
+          if (REG_MATCH_NULL_STRING_P (reg_info[*p]) == MATCH_NULL_UNSET_VALUE)
+            REG_MATCH_NULL_STRING_P (reg_info[*p])
+              = PREFIX(group_match_null_string_p) (&p1, pend, reg_info);
+
+          /* Save the position in the string where we were the last time
+             we were at this open-group operator in case the group is
+             operated upon by a repetition operator, e.g., with `(a*)*b'
+             against `ab'; then we want to ignore where we are now in
+             the string in case this attempt to match fails.  */
+          old_regstart[*p] = REG_MATCH_NULL_STRING_P (reg_info[*p])
+                             ? REG_UNSET (regstart[*p]) ? d : regstart[*p]
+                             : regstart[*p];
+	  DEBUG_PRINT2 ("  old_regstart: %d\n",
+			 POINTER_TO_OFFSET (old_regstart[*p]));
+
+          regstart[*p] = d;
+	  DEBUG_PRINT2 ("  regstart: %d\n", POINTER_TO_OFFSET (regstart[*p]));
+
+          IS_ACTIVE (reg_info[*p]) = 1;
+          MATCHED_SOMETHING (reg_info[*p]) = 0;
+
+	  /* Clear this whenever we change the register activity status.  */
+	  set_regs_matched_done = 0;
+
+          /* This is the new highest active register.  */
+          highest_active_reg = *p;
+
+          /* If nothing was active before, this is the new lowest active
+             register.  */
+          if (lowest_active_reg == NO_LOWEST_ACTIVE_REG)
+            lowest_active_reg = *p;
+
+          /* Move past the register number and inner group count.  */
+          p += 2;
+	  just_past_start_mem = p;
+
+          break;
+
+
+        /* The stop_memory opcode represents the end of a group.  Its
+           arguments are the same as start_memory's: the register
+           number, and the number of inner groups.  */
+	case stop_memory:
+	  DEBUG_PRINT3 ("EXECUTING stop_memory %ld (%ld):\n",
+			(long int) *p, (long int) p[1]);
+
+          /* We need to save the string position the last time we were at
+             this close-group operator in case the group is operated
+             upon by a repetition operator, e.g., with `((a*)*(b*)*)*'
+             against `aba'; then we want to ignore where we are now in
+             the string in case this attempt to match fails.  */
+          old_regend[*p] = REG_MATCH_NULL_STRING_P (reg_info[*p])
+                           ? REG_UNSET (regend[*p]) ? d : regend[*p]
+			   : regend[*p];
+	  DEBUG_PRINT2 ("      old_regend: %d\n",
+			 POINTER_TO_OFFSET (old_regend[*p]));
+
+          regend[*p] = d;
+	  DEBUG_PRINT2 ("      regend: %d\n", POINTER_TO_OFFSET (regend[*p]));
+
+          /* This register isn't active anymore.  */
+          IS_ACTIVE (reg_info[*p]) = 0;
+
+	  /* Clear this whenever we change the register activity status.  */
+	  set_regs_matched_done = 0;
+
+          /* If this was the only register active, nothing is active
+             anymore.  */
+          if (lowest_active_reg == highest_active_reg)
+            {
+              lowest_active_reg = NO_LOWEST_ACTIVE_REG;
+              highest_active_reg = NO_HIGHEST_ACTIVE_REG;
+            }
+          else
+            { /* We must scan for the new highest active register, since
+                 it isn't necessarily one less than now: consider
+                 (a(b)c(d(e)f)g).  When group 3 ends, after the f), the
+                 new highest active register is 1.  */
+              UCHAR_T r = *p - 1;
+              while (r > 0 && !IS_ACTIVE (reg_info[r]))
+                r--;
+
+              /* If we end up at register zero, that means that we saved
+                 the registers as the result of an `on_failure_jump', not
+                 a `start_memory', and we jumped to past the innermost
+                 `stop_memory'.  For example, in ((.)*) we save
+                 registers 1 and 2 as a result of the *, but when we pop
+                 back to the second ), we are at the stop_memory 1.
+                 Thus, nothing is active.  */
+	      if (r == 0)
+                {
+                  lowest_active_reg = NO_LOWEST_ACTIVE_REG;
+                  highest_active_reg = NO_HIGHEST_ACTIVE_REG;
+                }
+              else
+                highest_active_reg = r;
+            }
+
+          /* If just failed to match something this time around with a
+             group that's operated on by a repetition operator, try to
+             force exit from the ``loop'', and restore the register
+             information for this group that we had before trying this
+             last match.  */
+          if ((!MATCHED_SOMETHING (reg_info[*p])
+               || just_past_start_mem == p - 1)
+	      && (p + 2) < pend)
+            {
+              boolean is_a_jump_n = false;
+
+              p1 = p + 2;
+              mcnt = 0;
+              switch ((re_opcode_t) *p1++)
+                {
+                  case jump_n:
+		    is_a_jump_n = true;
+                  case pop_failure_jump:
+		  case maybe_pop_jump:
+		  case jump:
+		  case dummy_failure_jump:
+                    EXTRACT_NUMBER_AND_INCR (mcnt, p1);
+		    if (is_a_jump_n)
+		      p1 += OFFSET_ADDRESS_SIZE;
+                    break;
+
+                  default:
+                    /* do nothing */ ;
+                }
+	      p1 += mcnt;
+
+              /* If the next operation is a jump backwards in the pattern
+	         to an on_failure_jump right before the start_memory
+                 corresponding to this stop_memory, exit from the loop
+                 by forcing a failure after pushing on the stack the
+                 on_failure_jump's jump in the pattern, and d.  */
+              if (mcnt < 0 && (re_opcode_t) *p1 == on_failure_jump
+                  && (re_opcode_t) p1[1+OFFSET_ADDRESS_SIZE] == start_memory
+		  && p1[2+OFFSET_ADDRESS_SIZE] == *p)
+		{
+                  /* If this group ever matched anything, then restore
+                     what its registers were before trying this last
+                     failed match, e.g., with `(a*)*b' against `ab' for
+                     regstart[1], and, e.g., with `((a*)*(b*)*)*'
+                     against `aba' for regend[3].
+
+                     Also restore the registers for inner groups for,
+                     e.g., `((a*)(b*))*' against `aba' (register 3 would
+                     otherwise get trashed).  */
+
+                  if (EVER_MATCHED_SOMETHING (reg_info[*p]))
+		    {
+		      unsigned r;
+
+                      EVER_MATCHED_SOMETHING (reg_info[*p]) = 0;
+
+		      /* Restore this and inner groups' (if any) registers.  */
+                      for (r = *p; r < (unsigned) *p + (unsigned) *(p + 1);
+			   r++)
+                        {
+                          regstart[r] = old_regstart[r];
+
+                          /* xx why this test?  */
+                          if (old_regend[r] >= regstart[r])
+                            regend[r] = old_regend[r];
+                        }
+                    }
+		  p1++;
+                  EXTRACT_NUMBER_AND_INCR (mcnt, p1);
+                  PUSH_FAILURE_POINT (p1 + mcnt, d, -2);
+
+                  goto fail;
+                }
+            }
+
+          /* Move past the register number and the inner group count.  */
+          p += 2;
+          break;
+
+
+	/* \<digit> has been turned into a `duplicate' command which is
+           followed by the numeric value of <digit> as the register number.  */
+        case duplicate:
+	  {
+	    register const CHAR_T *d2, *dend2;
+	    int regno = *p++;   /* Get which register to match against.  */
+	    DEBUG_PRINT2 ("EXECUTING duplicate %d.\n", regno);
+
+	    /* Can't back reference a group which we've never matched.  */
+            if (REG_UNSET (regstart[regno]) || REG_UNSET (regend[regno]))
+              goto fail;
+
+            /* Where in input to try to start matching.  */
+            d2 = regstart[regno];
+
+            /* Where to stop matching; if both the place to start and
+               the place to stop matching are in the same string, then
+               set to the place to stop, otherwise, for now have to use
+               the end of the first string.  */
+
+            dend2 = ((FIRST_STRING_P (regstart[regno])
+		      == FIRST_STRING_P (regend[regno]))
+		     ? regend[regno] : end_match_1);
+	    for (;;)
+	      {
+		/* If necessary, advance to next segment in register
+                   contents.  */
+		while (d2 == dend2)
+		  {
+		    if (dend2 == end_match_2) break;
+		    if (dend2 == regend[regno]) break;
+
+                    /* End of string1 => advance to string2. */
+                    d2 = string2;
+                    dend2 = regend[regno];
+		  }
+		/* At end of register contents => success */
+		if (d2 == dend2) break;
+
+		/* If necessary, advance to next segment in data.  */
+		PREFETCH ();
+
+		/* How many characters left in this segment to match.  */
+		mcnt = dend - d;
+
+		/* Want how many consecutive characters we can match in
+                   one shot, so, if necessary, adjust the count.  */
+                if (mcnt > dend2 - d2)
+		  mcnt = dend2 - d2;
+
+		/* Compare that many; failure if mismatch, else move
+                   past them.  */
+		if (translate
+                    ? PREFIX(bcmp_translate) (d, d2, mcnt, translate)
+                    : memcmp (d, d2, mcnt*sizeof(UCHAR_T)))
+		  goto fail;
+		d += mcnt, d2 += mcnt;
+
+		/* Do this because we've match some characters.  */
+		SET_REGS_MATCHED ();
+	      }
+	  }
+	  break;
+
+
+        /* begline matches the empty string at the beginning of the string
+           (unless `not_bol' is set in `bufp'), and, if
+           `newline_anchor' is set, after newlines.  */
+	case begline:
+          DEBUG_PRINT1 ("EXECUTING begline.\n");
+
+          if (AT_STRINGS_BEG (d))
+            {
+              if (!bufp->not_bol) break;
+            }
+          else if (d[-1] == '\n' && bufp->newline_anchor)
+            {
+              break;
+            }
+          /* In all other cases, we fail.  */
+          goto fail;
+
+
+        /* endline is the dual of begline.  */
+	case endline:
+          DEBUG_PRINT1 ("EXECUTING endline.\n");
+
+          if (AT_STRINGS_END (d))
+            {
+              if (!bufp->not_eol) break;
+            }
+
+          /* We have to ``prefetch'' the next character.  */
+          else if ((d == end1 ? *string2 : *d) == '\n'
+                   && bufp->newline_anchor)
+            {
+              break;
+            }
+          goto fail;
+
+
+	/* Match at the very beginning of the data.  */
+        case begbuf:
+          DEBUG_PRINT1 ("EXECUTING begbuf.\n");
+          if (AT_STRINGS_BEG (d))
+            break;
+          goto fail;
+
+
+	/* Match at the very end of the data.  */
+        case endbuf:
+          DEBUG_PRINT1 ("EXECUTING endbuf.\n");
+	  if (AT_STRINGS_END (d))
+	    break;
+          goto fail;
+
+
+        /* on_failure_keep_string_jump is used to optimize `.*\n'.  It
+           pushes NULL as the value for the string on the stack.  Then
+           `pop_failure_point' will keep the current value for the
+           string, instead of restoring it.  To see why, consider
+           matching `foo\nbar' against `.*\n'.  The .* matches the foo;
+           then the . fails against the \n.  But the next thing we want
+           to do is match the \n against the \n; if we restored the
+           string value, we would be back at the foo.
+
+           Because this is used only in specific cases, we don't need to
+           check all the things that `on_failure_jump' does, to make
+           sure the right things get saved on the stack.  Hence we don't
+           share its code.  The only reason to push anything on the
+           stack at all is that otherwise we would have to change
+           `anychar's code to do something besides goto fail in this
+           case; that seems worse than this.  */
+        case on_failure_keep_string_jump:
+          DEBUG_PRINT1 ("EXECUTING on_failure_keep_string_jump");
+
+          EXTRACT_NUMBER_AND_INCR (mcnt, p);
+#ifdef _LIBC
+          DEBUG_PRINT3 (" %d (to %p):\n", mcnt, p + mcnt);
+#else
+          DEBUG_PRINT3 (" %d (to 0x%x):\n", mcnt, p + mcnt);
+#endif
+
+          PUSH_FAILURE_POINT (p + mcnt, NULL, -2);
+          break;
+
+
+	/* Uses of on_failure_jump:
+
+           Each alternative starts with an on_failure_jump that points
+           to the beginning of the next alternative.  Each alternative
+           except the last ends with a jump that in effect jumps past
+           the rest of the alternatives.  (They really jump to the
+           ending jump of the following alternative, because tensioning
+           these jumps is a hassle.)
+
+           Repeats start with an on_failure_jump that points past both
+           the repetition text and either the following jump or
+           pop_failure_jump back to this on_failure_jump.  */
+	case on_failure_jump:
+        on_failure:
+          DEBUG_PRINT1 ("EXECUTING on_failure_jump");
+
+          EXTRACT_NUMBER_AND_INCR (mcnt, p);
+#ifdef _LIBC
+          DEBUG_PRINT3 (" %d (to %p)", mcnt, p + mcnt);
+#else
+          DEBUG_PRINT3 (" %d (to 0x%x)", mcnt, p + mcnt);
+#endif
+
+          /* If this on_failure_jump comes right before a group (i.e.,
+             the original * applied to a group), save the information
+             for that group and all inner ones, so that if we fail back
+             to this point, the group's information will be correct.
+             For example, in \(a*\)*\1, we need the preceding group,
+             and in \(zz\(a*\)b*\)\2, we need the inner group.  */
+
+          /* We can't use `p' to check ahead because we push
+             a failure point to `p + mcnt' after we do this.  */
+          p1 = p;
+
+          /* We need to skip no_op's before we look for the
+             start_memory in case this on_failure_jump is happening as
+             the result of a completed succeed_n, as in \(a\)\{1,3\}b\1
+             against aba.  */
+          while (p1 < pend && (re_opcode_t) *p1 == no_op)
+            p1++;
+
+          if (p1 < pend && (re_opcode_t) *p1 == start_memory)
+            {
+              /* We have a new highest active register now.  This will
+                 get reset at the start_memory we are about to get to,
+                 but we will have saved all the registers relevant to
+                 this repetition op, as described above.  */
+              highest_active_reg = *(p1 + 1) + *(p1 + 2);
+              if (lowest_active_reg == NO_LOWEST_ACTIVE_REG)
+                lowest_active_reg = *(p1 + 1);
+            }
+
+          DEBUG_PRINT1 (":\n");
+          PUSH_FAILURE_POINT (p + mcnt, d, -2);
+          break;
+
+
+        /* A smart repeat ends with `maybe_pop_jump'.
+	   We change it to either `pop_failure_jump' or `jump'.  */
+        case maybe_pop_jump:
+          EXTRACT_NUMBER_AND_INCR (mcnt, p);
+          DEBUG_PRINT2 ("EXECUTING maybe_pop_jump %d.\n", mcnt);
+          {
+	    register UCHAR_T *p2 = p;
+
+            /* Compare the beginning of the repeat with what in the
+               pattern follows its end. If we can establish that there
+               is nothing that they would both match, i.e., that we
+               would have to backtrack because of (as in, e.g., `a*a')
+               then we can change to pop_failure_jump, because we'll
+               never have to backtrack.
+
+               This is not true in the case of alternatives: in
+               `(a|ab)*' we do need to backtrack to the `ab' alternative
+               (e.g., if the string was `ab').  But instead of trying to
+               detect that here, the alternative has put on a dummy
+               failure point which is what we will end up popping.  */
+
+	    /* Skip over open/close-group commands.
+	       If what follows this loop is a ...+ construct,
+	       look at what begins its body, since we will have to
+	       match at least one of that.  */
+	    while (1)
+	      {
+		if (p2 + 2 < pend
+		    && ((re_opcode_t) *p2 == stop_memory
+			|| (re_opcode_t) *p2 == start_memory))
+		  p2 += 3;
+		else if (p2 + 2 + 2 * OFFSET_ADDRESS_SIZE < pend
+			 && (re_opcode_t) *p2 == dummy_failure_jump)
+		  p2 += 2 + 2 * OFFSET_ADDRESS_SIZE;
+		else
+		  break;
+	      }
+
+	    p1 = p + mcnt;
+	    /* p1[0] ... p1[2] are the `on_failure_jump' corresponding
+	       to the `maybe_finalize_jump' of this case.  Examine what
+	       follows.  */
+
+            /* If we're at the end of the pattern, we can change.  */
+            if (p2 == pend)
+	      {
+		/* Consider what happens when matching ":\(.*\)"
+		   against ":/".  I don't really understand this code
+		   yet.  */
+  	        p[-(1+OFFSET_ADDRESS_SIZE)] = (UCHAR_T)
+		  pop_failure_jump;
+                DEBUG_PRINT1
+                  ("  End of pattern: change to `pop_failure_jump'.\n");
+              }
+
+            else if ((re_opcode_t) *p2 == exactn
+#ifdef MBS_SUPPORT
+		     || (re_opcode_t) *p2 == exactn_bin
+#endif
+		     || (bufp->newline_anchor && (re_opcode_t) *p2 == endline))
+	      {
+		register UCHAR_T c
+                  = *p2 == (UCHAR_T) endline ? '\n' : p2[2];
+
+                if (((re_opcode_t) p1[1+OFFSET_ADDRESS_SIZE] == exactn
+#ifdef MBS_SUPPORT
+		     || (re_opcode_t) p1[1+OFFSET_ADDRESS_SIZE] == exactn_bin
+#endif
+		    ) && p1[3+OFFSET_ADDRESS_SIZE] != c)
+                  {
+  		    p[-(1+OFFSET_ADDRESS_SIZE)] = (UCHAR_T)
+		      pop_failure_jump;
+#ifdef WCHAR
+		      DEBUG_PRINT3 ("  %C != %C => pop_failure_jump.\n",
+				    (wint_t) c,
+				    (wint_t) p1[3+OFFSET_ADDRESS_SIZE]);
+#else
+		      DEBUG_PRINT3 ("  %c != %c => pop_failure_jump.\n",
+				    (char) c,
+				    (char) p1[3+OFFSET_ADDRESS_SIZE]);
+#endif
+                  }
+
+#ifndef WCHAR
+		else if ((re_opcode_t) p1[3] == charset
+			 || (re_opcode_t) p1[3] == charset_not)
+		  {
+		    int negate = (re_opcode_t) p1[3] == charset_not;
+
+		    if (c < (unsigned) (p1[4] * BYTEWIDTH)
+			&& p1[5 + c / BYTEWIDTH] & (1 << (c % BYTEWIDTH)))
+		      negate = !negate;
+
+                    /* `negate' is equal to 1 if c would match, which means
+                        that we can't change to pop_failure_jump.  */
+		    if (!negate)
+                      {
+  		        p[-3] = (unsigned char) pop_failure_jump;
+                        DEBUG_PRINT1 ("  No match => pop_failure_jump.\n");
+                      }
+		  }
+#endif /* not WCHAR */
+	      }
+#ifndef WCHAR
+            else if ((re_opcode_t) *p2 == charset)
+	      {
+		/* We win if the first character of the loop is not part
+                   of the charset.  */
+                if ((re_opcode_t) p1[3] == exactn
+ 		    && ! ((int) p2[1] * BYTEWIDTH > (int) p1[5]
+ 			  && (p2[2 + p1[5] / BYTEWIDTH]
+ 			      & (1 << (p1[5] % BYTEWIDTH)))))
+		  {
+		    p[-3] = (unsigned char) pop_failure_jump;
+		    DEBUG_PRINT1 ("  No match => pop_failure_jump.\n");
+                  }
+
+		else if ((re_opcode_t) p1[3] == charset_not)
+		  {
+		    int idx;
+		    /* We win if the charset_not inside the loop
+		       lists every character listed in the charset after.  */
+		    for (idx = 0; idx < (int) p2[1]; idx++)
+		      if (! (p2[2 + idx] == 0
+			     || (idx < (int) p1[4]
+				 && ((p2[2 + idx] & ~ p1[5 + idx]) == 0))))
+			break;
+
+		    if (idx == p2[1])
+                      {
+  		        p[-3] = (unsigned char) pop_failure_jump;
+                        DEBUG_PRINT1 ("  No match => pop_failure_jump.\n");
+                      }
+		  }
+		else if ((re_opcode_t) p1[3] == charset)
+		  {
+		    int idx;
+		    /* We win if the charset inside the loop
+		       has no overlap with the one after the loop.  */
+		    for (idx = 0;
+			 idx < (int) p2[1] && idx < (int) p1[4];
+			 idx++)
+		      if ((p2[2 + idx] & p1[5 + idx]) != 0)
+			break;
+
+		    if (idx == p2[1] || idx == p1[4])
+                      {
+  		        p[-3] = (unsigned char) pop_failure_jump;
+                        DEBUG_PRINT1 ("  No match => pop_failure_jump.\n");
+                      }
+		  }
+	      }
+#endif /* not WCHAR */
+	  }
+	  p -= OFFSET_ADDRESS_SIZE;	/* Point at relative address again.  */
+	  if ((re_opcode_t) p[-1] != pop_failure_jump)
+	    {
+	      p[-1] = (UCHAR_T) jump;
+              DEBUG_PRINT1 ("  Match => jump.\n");
+	      goto unconditional_jump;
+	    }
+        /* Note fall through.  */
+
+
+	/* The end of a simple repeat has a pop_failure_jump back to
+           its matching on_failure_jump, where the latter will push a
+           failure point.  The pop_failure_jump takes off failure
+           points put on by this pop_failure_jump's matching
+           on_failure_jump; we got through the pattern to here from the
+           matching on_failure_jump, so didn't fail.  */
+        case pop_failure_jump:
+          {
+            /* We need to pass separate storage for the lowest and
+               highest registers, even though we don't care about the
+               actual values.  Otherwise, we will restore only one
+               register from the stack, since lowest will == highest in
+               `pop_failure_point'.  */
+            active_reg_t dummy_low_reg, dummy_high_reg;
+            UCHAR_T *pdummy __attribute__ ((unused)) = NULL;
+            const CHAR_T *sdummy __attribute__ ((unused)) = NULL;
+
+            DEBUG_PRINT1 ("EXECUTING pop_failure_jump.\n");
+            POP_FAILURE_POINT (sdummy, pdummy,
+                               dummy_low_reg, dummy_high_reg,
+                               reg_dummy, reg_dummy, reg_info_dummy);
+          }
+	  /* Note fall through.  */
+
+	unconditional_jump:
+#ifdef _LIBC
+	  DEBUG_PRINT2 ("\n%p: ", p);
+#else
+	  DEBUG_PRINT2 ("\n0x%x: ", p);
+#endif
+          /* Note fall through.  */
+
+        /* Unconditionally jump (without popping any failure points).  */
+        case jump:
+	  EXTRACT_NUMBER_AND_INCR (mcnt, p);	/* Get the amount to jump.  */
+          DEBUG_PRINT2 ("EXECUTING jump %d ", mcnt);
+	  p += mcnt;				/* Do the jump.  */
+#ifdef _LIBC
+          DEBUG_PRINT2 ("(to %p).\n", p);
+#else
+          DEBUG_PRINT2 ("(to 0x%x).\n", p);
+#endif
+	  break;
+
+
+        /* We need this opcode so we can detect where alternatives end
+           in `group_match_null_string_p' et al.  */
+        case jump_past_alt:
+          DEBUG_PRINT1 ("EXECUTING jump_past_alt.\n");
+          goto unconditional_jump;
+
+
+        /* Normally, the on_failure_jump pushes a failure point, which
+           then gets popped at pop_failure_jump.  We will end up at
+           pop_failure_jump, also, and with a pattern of, say, `a+', we
+           are skipping over the on_failure_jump, so we have to push
+           something meaningless for pop_failure_jump to pop.  */
+        case dummy_failure_jump:
+          DEBUG_PRINT1 ("EXECUTING dummy_failure_jump.\n");
+          /* It doesn't matter what we push for the string here.  What
+             the code at `fail' tests is the value for the pattern.  */
+          PUSH_FAILURE_POINT (NULL, NULL, -2);
+          goto unconditional_jump;
+
+
+        /* At the end of an alternative, we need to push a dummy failure
+           point in case we are followed by a `pop_failure_jump', because
+           we don't want the failure point for the alternative to be
+           popped.  For example, matching `(a|ab)*' against `aab'
+           requires that we match the `ab' alternative.  */
+        case push_dummy_failure:
+          DEBUG_PRINT1 ("EXECUTING push_dummy_failure.\n");
+          /* See comments just above at `dummy_failure_jump' about the
+             two zeroes.  */
+          PUSH_FAILURE_POINT (NULL, NULL, -2);
+          break;
+
+        /* Have to succeed matching what follows at least n times.
+           After that, handle like `on_failure_jump'.  */
+        case succeed_n:
+          EXTRACT_NUMBER (mcnt, p + OFFSET_ADDRESS_SIZE);
+          DEBUG_PRINT2 ("EXECUTING succeed_n %d.\n", mcnt);
+
+          assert (mcnt >= 0);
+          /* Originally, this is how many times we HAVE to succeed.  */
+          if (mcnt > 0)
+            {
+               mcnt--;
+	       p += OFFSET_ADDRESS_SIZE;
+               STORE_NUMBER_AND_INCR (p, mcnt);
+#ifdef _LIBC
+               DEBUG_PRINT3 ("  Setting %p to %d.\n", p - OFFSET_ADDRESS_SIZE
+			     , mcnt);
+#else
+               DEBUG_PRINT3 ("  Setting 0x%x to %d.\n", p - OFFSET_ADDRESS_SIZE
+			     , mcnt);
+#endif
+            }
+	  else if (mcnt == 0)
+            {
+#ifdef _LIBC
+              DEBUG_PRINT2 ("  Setting two bytes from %p to no_op.\n",
+			    p + OFFSET_ADDRESS_SIZE);
+#else
+              DEBUG_PRINT2 ("  Setting two bytes from 0x%x to no_op.\n",
+			    p + OFFSET_ADDRESS_SIZE);
+#endif /* _LIBC */
+
+#ifdef WCHAR
+	      p[1] = (UCHAR_T) no_op;
+#else
+	      p[2] = (UCHAR_T) no_op;
+              p[3] = (UCHAR_T) no_op;
+#endif /* WCHAR */
+              goto on_failure;
+            }
+          break;
+
+        case jump_n:
+          EXTRACT_NUMBER (mcnt, p + OFFSET_ADDRESS_SIZE);
+          DEBUG_PRINT2 ("EXECUTING jump_n %d.\n", mcnt);
+
+          /* Originally, this is how many times we CAN jump.  */
+          if (mcnt)
+            {
+               mcnt--;
+               STORE_NUMBER (p + OFFSET_ADDRESS_SIZE, mcnt);
+
+#ifdef _LIBC
+               DEBUG_PRINT3 ("  Setting %p to %d.\n", p + OFFSET_ADDRESS_SIZE,
+			     mcnt);
+#else
+               DEBUG_PRINT3 ("  Setting 0x%x to %d.\n", p + OFFSET_ADDRESS_SIZE,
+			     mcnt);
+#endif /* _LIBC */
+	       goto unconditional_jump;
+            }
+          /* If don't have to jump any more, skip over the rest of command.  */
+	  else
+	    p += 2 * OFFSET_ADDRESS_SIZE;
+          break;
+
+	case set_number_at:
+	  {
+            DEBUG_PRINT1 ("EXECUTING set_number_at.\n");
+
+            EXTRACT_NUMBER_AND_INCR (mcnt, p);
+            p1 = p + mcnt;
+            EXTRACT_NUMBER_AND_INCR (mcnt, p);
+#ifdef _LIBC
+            DEBUG_PRINT3 ("  Setting %p to %d.\n", p1, mcnt);
+#else
+            DEBUG_PRINT3 ("  Setting 0x%x to %d.\n", p1, mcnt);
+#endif
+	    STORE_NUMBER (p1, mcnt);
+            break;
+          }
+
+#if 0
+	/* The DEC Alpha C compiler 3.x generates incorrect code for the
+	   test  WORDCHAR_P (d - 1) != WORDCHAR_P (d)  in the expansion of
+	   AT_WORD_BOUNDARY, so this code is disabled.  Expanding the
+	   macro and introducing temporary variables works around the bug.  */
+
+	case wordbound:
+	  DEBUG_PRINT1 ("EXECUTING wordbound.\n");
+	  if (AT_WORD_BOUNDARY (d))
+	    break;
+	  goto fail;
+
+	case notwordbound:
+	  DEBUG_PRINT1 ("EXECUTING notwordbound.\n");
+	  if (AT_WORD_BOUNDARY (d))
+	    goto fail;
+	  break;
+#else
+	case wordbound:
+	{
+	  boolean prevchar, thischar;
+
+	  DEBUG_PRINT1 ("EXECUTING wordbound.\n");
+	  if (AT_STRINGS_BEG (d) || AT_STRINGS_END (d))
+	    break;
+
+	  prevchar = WORDCHAR_P (d - 1);
+	  thischar = WORDCHAR_P (d);
+	  if (prevchar != thischar)
+	    break;
+	  goto fail;
+	}
+
+      case notwordbound:
+	{
+	  boolean prevchar, thischar;
+
+	  DEBUG_PRINT1 ("EXECUTING notwordbound.\n");
+	  if (AT_STRINGS_BEG (d) || AT_STRINGS_END (d))
+	    goto fail;
+
+	  prevchar = WORDCHAR_P (d - 1);
+	  thischar = WORDCHAR_P (d);
+	  if (prevchar != thischar)
+	    goto fail;
+	  break;
+	}
+#endif
+
+	case wordbeg:
+          DEBUG_PRINT1 ("EXECUTING wordbeg.\n");
+	  if (!AT_STRINGS_END (d) && WORDCHAR_P (d)
+	      && (AT_STRINGS_BEG (d) || !WORDCHAR_P (d - 1)))
+	    break;
+          goto fail;
+
+	case wordend:
+          DEBUG_PRINT1 ("EXECUTING wordend.\n");
+	  if (!AT_STRINGS_BEG (d) && WORDCHAR_P (d - 1)
+              && (AT_STRINGS_END (d) || !WORDCHAR_P (d)))
+	    break;
+          goto fail;
+
+#ifdef emacs
+  	case before_dot:
+          DEBUG_PRINT1 ("EXECUTING before_dot.\n");
+ 	  if (PTR_CHAR_POS ((unsigned char *) d) >= point)
+  	    goto fail;
+  	  break;
+
+  	case at_dot:
+          DEBUG_PRINT1 ("EXECUTING at_dot.\n");
+ 	  if (PTR_CHAR_POS ((unsigned char *) d) != point)
+  	    goto fail;
+  	  break;
+
+  	case after_dot:
+          DEBUG_PRINT1 ("EXECUTING after_dot.\n");
+          if (PTR_CHAR_POS ((unsigned char *) d) <= point)
+  	    goto fail;
+  	  break;
+
+	case syntaxspec:
+          DEBUG_PRINT2 ("EXECUTING syntaxspec %d.\n", mcnt);
+	  mcnt = *p++;
+	  goto matchsyntax;
+
+        case wordchar:
+          DEBUG_PRINT1 ("EXECUTING Emacs wordchar.\n");
+	  mcnt = (int) Sword;
+        matchsyntax:
+	  PREFETCH ();
+	  /* Can't use *d++ here; SYNTAX may be an unsafe macro.  */
+	  d++;
+	  if (SYNTAX (d[-1]) != (enum syntaxcode) mcnt)
+	    goto fail;
+          SET_REGS_MATCHED ();
+	  break;
+
+	case notsyntaxspec:
+          DEBUG_PRINT2 ("EXECUTING notsyntaxspec %d.\n", mcnt);
+	  mcnt = *p++;
+	  goto matchnotsyntax;
+
+        case notwordchar:
+          DEBUG_PRINT1 ("EXECUTING Emacs notwordchar.\n");
+	  mcnt = (int) Sword;
+        matchnotsyntax:
+	  PREFETCH ();
+	  /* Can't use *d++ here; SYNTAX may be an unsafe macro.  */
+	  d++;
+	  if (SYNTAX (d[-1]) == (enum syntaxcode) mcnt)
+	    goto fail;
+	  SET_REGS_MATCHED ();
+          break;
+
+#else /* not emacs */
+	case wordchar:
+          DEBUG_PRINT1 ("EXECUTING non-Emacs wordchar.\n");
+	  PREFETCH ();
+          if (!WORDCHAR_P (d))
+            goto fail;
+	  SET_REGS_MATCHED ();
+          d++;
+	  break;
+
+	case notwordchar:
+          DEBUG_PRINT1 ("EXECUTING non-Emacs notwordchar.\n");
+	  PREFETCH ();
+	  if (WORDCHAR_P (d))
+            goto fail;
+          SET_REGS_MATCHED ();
+          d++;
+	  break;
+#endif /* not emacs */
+
+        default:
+          abort ();
+	}
+      continue;  /* Successfully executed one pattern command; keep going.  */
+
+
+    /* We goto here if a matching operation fails. */
+    fail:
+      if (!FAIL_STACK_EMPTY ())
+	{ /* A restart point is known.  Restore to that state.  */
+          DEBUG_PRINT1 ("\nFAIL:\n");
+          POP_FAILURE_POINT (d, p,
+                             lowest_active_reg, highest_active_reg,
+                             regstart, regend, reg_info);
+
+          /* If this failure point is a dummy, try the next one.  */
+          if (!p)
+	    goto fail;
+
+          /* If we failed to the end of the pattern, don't examine *p.  */
+	  assert (p <= pend);
+          if (p < pend)
+            {
+              boolean is_a_jump_n = false;
+
+              /* If failed to a backwards jump that's part of a repetition
+                 loop, need to pop this failure point and use the next one.  */
+              switch ((re_opcode_t) *p)
+                {
+                case jump_n:
+                  is_a_jump_n = true;
+                case maybe_pop_jump:
+                case pop_failure_jump:
+                case jump:
+                  p1 = p + 1;
+                  EXTRACT_NUMBER_AND_INCR (mcnt, p1);
+                  p1 += mcnt;
+
+                  if ((is_a_jump_n && (re_opcode_t) *p1 == succeed_n)
+                      || (!is_a_jump_n
+                          && (re_opcode_t) *p1 == on_failure_jump))
+                    goto fail;
+                  break;
+                default:
+                  /* do nothing */ ;
+                }
+            }
+
+          if (d >= string1 && d <= end1)
+	    dend = end_match_1;
+        }
+      else
+        break;   /* Matching at this starting point really fails.  */
+    } /* for (;;) */
+
+  if (best_regs_set)
+    goto restore_best_regs;
+
+  FREE_VARIABLES ();
+
+  return -1;         			/* Failure to match.  */
+} /* re_match_2 */
+
+/* Subroutine definitions for re_match_2.  */
+
+
+/* We are passed P pointing to a register number after a start_memory.
+
+   Return true if the pattern up to the corresponding stop_memory can
+   match the empty string, and false otherwise.
+
+   If we find the matching stop_memory, sets P to point to one past its number.
+   Otherwise, sets P to an undefined byte less than or equal to END.
+
+   We don't handle duplicates properly (yet).  */
+
+static boolean
+PREFIX(group_match_null_string_p) (UCHAR_T **p, UCHAR_T *end,
+                                   PREFIX(register_info_type) *reg_info)
+{
+  int mcnt;
+  /* Point to after the args to the start_memory.  */
+  UCHAR_T *p1 = *p + 2;
+
+  while (p1 < end)
+    {
+      /* Skip over opcodes that can match nothing, and return true or
+	 false, as appropriate, when we get to one that can't, or to the
+         matching stop_memory.  */
+
+      switch ((re_opcode_t) *p1)
+        {
+        /* Could be either a loop or a series of alternatives.  */
+        case on_failure_jump:
+          p1++;
+          EXTRACT_NUMBER_AND_INCR (mcnt, p1);
+
+          /* If the next operation is not a jump backwards in the
+	     pattern.  */
+
+	  if (mcnt >= 0)
+	    {
+              /* Go through the on_failure_jumps of the alternatives,
+                 seeing if any of the alternatives cannot match nothing.
+                 The last alternative starts with only a jump,
+                 whereas the rest start with on_failure_jump and end
+                 with a jump, e.g., here is the pattern for `a|b|c':
+
+                 /on_failure_jump/0/6/exactn/1/a/jump_past_alt/0/6
+                 /on_failure_jump/0/6/exactn/1/b/jump_past_alt/0/3
+                 /exactn/1/c
+
+                 So, we have to first go through the first (n-1)
+                 alternatives and then deal with the last one separately.  */
+
+
+              /* Deal with the first (n-1) alternatives, which start
+                 with an on_failure_jump (see above) that jumps to right
+                 past a jump_past_alt.  */
+
+              while ((re_opcode_t) p1[mcnt-(1+OFFSET_ADDRESS_SIZE)] ==
+		     jump_past_alt)
+                {
+                  /* `mcnt' holds how many bytes long the alternative
+                     is, including the ending `jump_past_alt' and
+                     its number.  */
+
+                  if (!PREFIX(alt_match_null_string_p) (p1, p1 + mcnt -
+						(1 + OFFSET_ADDRESS_SIZE),
+						reg_info))
+                    return false;
+
+                  /* Move to right after this alternative, including the
+		     jump_past_alt.  */
+                  p1 += mcnt;
+
+                  /* Break if it's the beginning of an n-th alternative
+                     that doesn't begin with an on_failure_jump.  */
+                  if ((re_opcode_t) *p1 != on_failure_jump)
+                    break;
+
+		  /* Still have to check that it's not an n-th
+		     alternative that starts with an on_failure_jump.  */
+		  p1++;
+                  EXTRACT_NUMBER_AND_INCR (mcnt, p1);
+                  if ((re_opcode_t) p1[mcnt-(1+OFFSET_ADDRESS_SIZE)] !=
+		      jump_past_alt)
+                    {
+		      /* Get to the beginning of the n-th alternative.  */
+                      p1 -= 1 + OFFSET_ADDRESS_SIZE;
+                      break;
+                    }
+                }
+
+              /* Deal with the last alternative: go back and get number
+                 of the `jump_past_alt' just before it.  `mcnt' contains
+                 the length of the alternative.  */
+              EXTRACT_NUMBER (mcnt, p1 - OFFSET_ADDRESS_SIZE);
+
+              if (!PREFIX(alt_match_null_string_p) (p1, p1 + mcnt, reg_info))
+                return false;
+
+              p1 += mcnt;	/* Get past the n-th alternative.  */
+            } /* if mcnt > 0 */
+          break;
+
+
+        case stop_memory:
+	  assert (p1[1] == **p);
+          *p = p1 + 2;
+          return true;
+
+
+        default:
+          if (!PREFIX(common_op_match_null_string_p) (&p1, end, reg_info))
+            return false;
+        }
+    } /* while p1 < end */
+
+  return false;
+} /* group_match_null_string_p */
+
+
+/* Similar to group_match_null_string_p, but doesn't deal with alternatives:
+   It expects P to be the first byte of a single alternative and END one
+   byte past the last. The alternative can contain groups.  */
+
+static boolean
+PREFIX(alt_match_null_string_p) (UCHAR_T *p, UCHAR_T *end,
+                                 PREFIX(register_info_type) *reg_info)
+{
+  int mcnt;
+  UCHAR_T *p1 = p;
+
+  while (p1 < end)
+    {
+      /* Skip over opcodes that can match nothing, and break when we get
+         to one that can't.  */
+
+      switch ((re_opcode_t) *p1)
+        {
+	/* It's a loop.  */
+        case on_failure_jump:
+          p1++;
+          EXTRACT_NUMBER_AND_INCR (mcnt, p1);
+          p1 += mcnt;
+          break;
+
+	default:
+          if (!PREFIX(common_op_match_null_string_p) (&p1, end, reg_info))
+            return false;
+        }
+    }  /* while p1 < end */
+
+  return true;
+} /* alt_match_null_string_p */
+
+
+/* Deals with the ops common to group_match_null_string_p and
+   alt_match_null_string_p.
+
+   Sets P to one after the op and its arguments, if any.  */
+
+static boolean
+PREFIX(common_op_match_null_string_p) (UCHAR_T **p, UCHAR_T *end,
+                                       PREFIX(register_info_type) *reg_info)
+{
+  int mcnt;
+  boolean ret;
+  int reg_no;
+  UCHAR_T *p1 = *p;
+
+  switch ((re_opcode_t) *p1++)
+    {
+    case no_op:
+    case begline:
+    case endline:
+    case begbuf:
+    case endbuf:
+    case wordbeg:
+    case wordend:
+    case wordbound:
+    case notwordbound:
+#ifdef emacs
+    case before_dot:
+    case at_dot:
+    case after_dot:
+#endif
+      break;
+
+    case start_memory:
+      reg_no = *p1;
+      assert (reg_no > 0 && reg_no <= MAX_REGNUM);
+      ret = PREFIX(group_match_null_string_p) (&p1, end, reg_info);
+
+      /* Have to set this here in case we're checking a group which
+         contains a group and a back reference to it.  */
+
+      if (REG_MATCH_NULL_STRING_P (reg_info[reg_no]) == MATCH_NULL_UNSET_VALUE)
+        REG_MATCH_NULL_STRING_P (reg_info[reg_no]) = ret;
+
+      if (!ret)
+        return false;
+      break;
+
+    /* If this is an optimized succeed_n for zero times, make the jump.  */
+    case jump:
+      EXTRACT_NUMBER_AND_INCR (mcnt, p1);
+      if (mcnt >= 0)
+        p1 += mcnt;
+      else
+        return false;
+      break;
+
+    case succeed_n:
+      /* Get to the number of times to succeed.  */
+      p1 += OFFSET_ADDRESS_SIZE;
+      EXTRACT_NUMBER_AND_INCR (mcnt, p1);
+
+      if (mcnt == 0)
+        {
+          p1 -= 2 * OFFSET_ADDRESS_SIZE;
+          EXTRACT_NUMBER_AND_INCR (mcnt, p1);
+          p1 += mcnt;
+        }
+      else
+        return false;
+      break;
+
+    case duplicate:
+      if (!REG_MATCH_NULL_STRING_P (reg_info[*p1]))
+        return false;
+      break;
+
+    case set_number_at:
+      p1 += 2 * OFFSET_ADDRESS_SIZE;
+
+    default:
+      /* All other opcodes mean we cannot match the empty string.  */
+      return false;
+  }
+
+  *p = p1;
+  return true;
+} /* common_op_match_null_string_p */
+
+
+/* Return zero if TRANSLATE[S1] and TRANSLATE[S2] are identical for LEN
+   bytes; nonzero otherwise.  */
+
+static int
+PREFIX(bcmp_translate) (const CHAR_T *s1, const CHAR_T *s2, register int len,
+                        RE_TRANSLATE_TYPE translate)
+{
+  register const UCHAR_T *p1 = (const UCHAR_T *) s1;
+  register const UCHAR_T *p2 = (const UCHAR_T *) s2;
+  while (len)
+    {
+#ifdef WCHAR
+      if (((*p1<=0xff)?translate[*p1++]:*p1++)
+	  != ((*p2<=0xff)?translate[*p2++]:*p2++))
+	return 1;
+#else /* BYTE */
+      if (translate[*p1++] != translate[*p2++]) return 1;
+#endif /* WCHAR */
+      len--;
+    }
+  return 0;
+}
+
+
+#else /* not INSIDE_RECURSION */
+
+/* Entry points for GNU code.  */
+
+/* re_compile_pattern is the GNU regular expression compiler: it
+   compiles PATTERN (of length SIZE) and puts the result in BUFP.
+   Returns 0 if the pattern was valid, otherwise an error string.
+
+   Assumes the `allocated' (and perhaps `buffer') and `translate' fields
+   are set in BUFP on entry.
+
+   We call regex_compile to do the actual compilation.  */
+
+const char *
+re_compile_pattern (const char *pattern, size_t length,
+                    struct re_pattern_buffer *bufp)
+{
+  reg_errcode_t ret;
+
+  /* GNU code is written to assume at least RE_NREGS registers will be set
+     (and at least one extra will be -1).  */
+  bufp->regs_allocated = REGS_UNALLOCATED;
+
+  /* And GNU code determines whether or not to get register information
+     by passing null for the REGS argument to re_match, etc., not by
+     setting no_sub.  */
+  bufp->no_sub = 0;
+
+  /* Match anchors at newline.  */
+  bufp->newline_anchor = 1;
+
+# ifdef MBS_SUPPORT
+  if (MB_CUR_MAX != 1)
+    ret = wcs_regex_compile (pattern, length, re_syntax_options, bufp);
+  else
+# endif
+    ret = byte_regex_compile (pattern, length, re_syntax_options, bufp);
+
+  if (!ret)
+    return NULL;
+  return gettext (re_error_msgid[(int) ret]);
+}
+#ifdef _LIBC
+weak_alias (__re_compile_pattern, re_compile_pattern)
+#endif
+
+/* Entry points compatible with 4.2 BSD regex library.  We don't define
+   them unless specifically requested.  */
+
+#if defined _REGEX_RE_COMP || defined _LIBC
+
+/* BSD has one and only one pattern buffer.  */
+static struct re_pattern_buffer re_comp_buf;
+
+char *
+#ifdef _LIBC
+/* Make these definitions weak in libc, so POSIX programs can redefine
+   these names if they don't use our functions, and still use
+   regcomp/regexec below without link errors.  */
+weak_function
+#endif
+re_comp (const char *s)
+{
+  reg_errcode_t ret;
+
+  if (!s)
+    {
+      if (!re_comp_buf.buffer)
+	return (char *) gettext ("No previous regular expression");
+      return 0;
+    }
+
+  if (!re_comp_buf.buffer)
+    {
+      re_comp_buf.buffer = (unsigned char *) malloc (200);
+      if (re_comp_buf.buffer == NULL)
+        return (char *) gettext (re_error_msgid[(int) REG_ESPACE]);
+      re_comp_buf.allocated = 200;
+
+      re_comp_buf.fastmap = (char *) malloc (1 << BYTEWIDTH);
+      if (re_comp_buf.fastmap == NULL)
+	return (char *) gettext (re_error_msgid[(int) REG_ESPACE]);
+    }
+
+  /* Since `re_exec' always passes NULL for the `regs' argument, we
+     don't need to initialize the pattern buffer fields which affect it.  */
+
+  /* Match anchors at newlines.  */
+  re_comp_buf.newline_anchor = 1;
+
+# ifdef MBS_SUPPORT
+  if (MB_CUR_MAX != 1)
+    ret = wcs_regex_compile (s, strlen (s), re_syntax_options, &re_comp_buf);
+  else
+# endif
+    ret = byte_regex_compile (s, strlen (s), re_syntax_options, &re_comp_buf);
+
+  if (!ret)
+    return NULL;
+
+  /* Yes, we're discarding `const' here if !HAVE_LIBINTL.  */
+  return (char *) gettext (re_error_msgid[(int) ret]);
+}
+
+
+int
+#ifdef _LIBC
+weak_function
+#endif
+re_exec (const char *s)
+{
+  const int len = strlen (s);
+  return
+    0 <= re_search (&re_comp_buf, s, len, 0, len, (struct re_registers *) 0);
+}
+
+#endif /* _REGEX_RE_COMP */
+
+/* POSIX.2 functions.  Don't define these for Emacs.  */
+
+#ifndef emacs
+
+/* regcomp takes a regular expression as a string and compiles it.
+
+   PREG is a regex_t *.  We do not expect any fields to be initialized,
+   since POSIX says we shouldn't.  Thus, we set
+
+     `buffer' to the compiled pattern;
+     `used' to the length of the compiled pattern;
+     `syntax' to RE_SYNTAX_POSIX_EXTENDED if the
+       REG_EXTENDED bit in CFLAGS is set; otherwise, to
+       RE_SYNTAX_POSIX_BASIC;
+     `newline_anchor' to REG_NEWLINE being set in CFLAGS;
+     `fastmap' to an allocated space for the fastmap;
+     `fastmap_accurate' to zero;
+     `re_nsub' to the number of subexpressions in PATTERN.
+
+   PATTERN is the address of the pattern string.
+
+   CFLAGS is a series of bits which affect compilation.
+
+     If REG_EXTENDED is set, we use POSIX extended syntax; otherwise, we
+     use POSIX basic syntax.
+
+     If REG_NEWLINE is set, then . and [^...] don't match newline.
+     Also, regexec will try a match beginning after every newline.
+
+     If REG_ICASE is set, then we considers upper- and lowercase
+     versions of letters to be equivalent when matching.
+
+     If REG_NOSUB is set, then when PREG is passed to regexec, that
+     routine will report only success or failure, and nothing about the
+     registers.
+
+   It returns 0 if it succeeds, nonzero if it doesn't.  (See regex.h for
+   the return codes and their meanings.)  */
+
+int
+regcomp (regex_t *preg, const char *pattern, int cflags)
+{
+  reg_errcode_t ret;
+  reg_syntax_t syntax
+    = (cflags & REG_EXTENDED) ?
+      RE_SYNTAX_POSIX_EXTENDED : RE_SYNTAX_POSIX_BASIC;
+
+  /* regex_compile will allocate the space for the compiled pattern.  */
+  preg->buffer = 0;
+  preg->allocated = 0;
+  preg->used = 0;
+
+  /* Try to allocate space for the fastmap.  */
+  preg->fastmap = (char *) malloc (1 << BYTEWIDTH);
+
+  if (cflags & REG_ICASE)
+    {
+      int i;
+
+      preg->translate
+	= (RE_TRANSLATE_TYPE) malloc (CHAR_SET_SIZE
+				      * sizeof (*(RE_TRANSLATE_TYPE)0));
+      if (preg->translate == NULL)
+        return (int) REG_ESPACE;
+
+      /* Map uppercase characters to corresponding lowercase ones.  */
+      for (i = 0; i < CHAR_SET_SIZE; i++)
+        preg->translate[i] = ISUPPER (i) ? TOLOWER (i) : i;
+    }
+  else
+    preg->translate = NULL;
+
+  /* If REG_NEWLINE is set, newlines are treated differently.  */
+  if (cflags & REG_NEWLINE)
+    { /* REG_NEWLINE implies neither . nor [^...] match newline.  */
+      syntax &= ~RE_DOT_NEWLINE;
+      syntax |= RE_HAT_LISTS_NOT_NEWLINE;
+      /* It also changes the matching behavior.  */
+      preg->newline_anchor = 1;
+    }
+  else
+    preg->newline_anchor = 0;
+
+  preg->no_sub = !!(cflags & REG_NOSUB);
+
+  /* POSIX says a null character in the pattern terminates it, so we
+     can use strlen here in compiling the pattern.  */
+# ifdef MBS_SUPPORT
+  if (MB_CUR_MAX != 1)
+    ret = wcs_regex_compile (pattern, strlen (pattern), syntax, preg);
+  else
+# endif
+    ret = byte_regex_compile (pattern, strlen (pattern), syntax, preg);
+
+  /* POSIX doesn't distinguish between an unmatched open-group and an
+     unmatched close-group: both are REG_EPAREN.  */
+  if (ret == REG_ERPAREN) ret = REG_EPAREN;
+
+  if (ret == REG_NOERROR && preg->fastmap)
+    {
+      /* Compute the fastmap now, since regexec cannot modify the pattern
+	 buffer.  */
+      if (re_compile_fastmap (preg) == -2)
+	{
+	  /* Some error occurred while computing the fastmap, just forget
+	     about it.  */
+	  free (preg->fastmap);
+	  preg->fastmap = NULL;
+	}
+    }
+
+  return (int) ret;
+}
+#ifdef _LIBC
+weak_alias (__regcomp, regcomp)
+#endif
+
+
+/* regexec searches for a given pattern, specified by PREG, in the
+   string STRING.
+
+   If NMATCH is zero or REG_NOSUB was set in the cflags argument to
+   `regcomp', we ignore PMATCH.  Otherwise, we assume PMATCH has at
+   least NMATCH elements, and we set them to the offsets of the
+   corresponding matched substrings.
+
+   EFLAGS specifies `execution flags' which affect matching: if
+   REG_NOTBOL is set, then ^ does not match at the beginning of the
+   string; if REG_NOTEOL is set, then $ does not match at the end.
+
+   We return 0 if we find a match and REG_NOMATCH if not.  */
+
+int
+regexec (const regex_t *preg, const char *string, size_t nmatch,
+         regmatch_t pmatch[], int eflags)
+{
+  int ret;
+  struct re_registers regs;
+  regex_t private_preg;
+  int len = strlen (string);
+  boolean want_reg_info = !preg->no_sub && nmatch > 0;
+
+  private_preg = *preg;
+
+  private_preg.not_bol = !!(eflags & REG_NOTBOL);
+  private_preg.not_eol = !!(eflags & REG_NOTEOL);
+
+  /* The user has told us exactly how many registers to return
+     information about, via `nmatch'.  We have to pass that on to the
+     matching routines.  */
+  private_preg.regs_allocated = REGS_FIXED;
+
+  if (want_reg_info)
+    {
+      regs.num_regs = nmatch;
+      regs.start = TALLOC (nmatch * 2, regoff_t);
+      if (regs.start == NULL)
+        return (int) REG_NOMATCH;
+      regs.end = regs.start + nmatch;
+    }
+
+  /* Perform the searching operation.  */
+  ret = re_search (&private_preg, string, len,
+                   /* start: */ 0, /* range: */ len,
+                   want_reg_info ? &regs : (struct re_registers *) 0);
+
+  /* Copy the register information to the POSIX structure.  */
+  if (want_reg_info)
+    {
+      if (ret >= 0)
+        {
+          unsigned r;
+
+          for (r = 0; r < nmatch; r++)
+            {
+              pmatch[r].rm_so = regs.start[r];
+              pmatch[r].rm_eo = regs.end[r];
+            }
+        }
+
+      /* If we needed the temporary register info, free the space now.  */
+      free (regs.start);
+    }
+
+  /* We want zero return to mean success, unlike `re_search'.  */
+  return ret >= 0 ? (int) REG_NOERROR : (int) REG_NOMATCH;
+}
+#ifdef _LIBC
+/* EGLIBC: This is handled in regexec-compat.c.  */
+/*weak_alias (__regexec, regexec)*/
+#include "regexec-compat.c"
+#endif
+
+
+/* Returns a message corresponding to an error code, ERRCODE, returned
+   from either regcomp or regexec.   We don't use PREG here.  */
+
+size_t
+regerror (int errcode, const regex_t *preg __attribute__ ((unused)),
+          char *errbuf, size_t errbuf_size)
+{
+  const char *msg;
+  size_t msg_size;
+
+  if (errcode < 0
+      || errcode >= (int) (sizeof (re_error_msgid)
+			   / sizeof (re_error_msgid[0])))
+    /* Only error codes returned by the rest of the code should be passed
+       to this routine.  If we are given anything else, or if other regex
+       code generates an invalid error code, then the program has a bug.
+       Dump core so we can fix it.  */
+    abort ();
+
+  msg = gettext (re_error_msgid[errcode]);
+
+  msg_size = strlen (msg) + 1; /* Includes the null.  */
+
+  if (errbuf_size != 0)
+    {
+      if (msg_size > errbuf_size)
+        {
+#if defined HAVE_MEMPCPY || defined _LIBC
+	  *((char *) mempcpy (errbuf, msg, errbuf_size - 1)) = '\0';
+#else
+          memcpy (errbuf, msg, errbuf_size - 1);
+          errbuf[errbuf_size - 1] = 0;
+#endif
+        }
+      else
+        memcpy (errbuf, msg, msg_size);
+    }
+
+  return msg_size;
+}
+#ifdef _LIBC
+weak_alias (__regerror, regerror)
+#endif
+
+
+/* Free dynamically allocated space used by PREG.  */
+
+void
+regfree (regex_t *preg)
+{
+  if (preg->buffer != NULL)
+    free (preg->buffer);
+  preg->buffer = NULL;
+
+  preg->allocated = 0;
+  preg->used = 0;
+
+  if (preg->fastmap != NULL)
+    free (preg->fastmap);
+  preg->fastmap = NULL;
+  preg->fastmap_accurate = 0;
+
+  if (preg->translate != NULL)
+    free (preg->translate);
+  preg->translate = NULL;
+}
+#ifdef _LIBC
+weak_alias (__regfree, regfree)
+#endif
+
+#endif /* not emacs  */
+
+#endif /* not INSIDE_RECURSION */
+
+
+#undef STORE_NUMBER
+#undef STORE_NUMBER_AND_INCR
+#undef EXTRACT_NUMBER
+#undef EXTRACT_NUMBER_AND_INCR
+
+#undef DEBUG_PRINT_COMPILED_PATTERN
+#undef DEBUG_PRINT_DOUBLE_STRING
+
+#undef INIT_FAIL_STACK
+#undef RESET_FAIL_STACK
+#undef DOUBLE_FAIL_STACK
+#undef PUSH_PATTERN_OP
+#undef PUSH_FAILURE_POINTER
+#undef PUSH_FAILURE_INT
+#undef PUSH_FAILURE_ELT
+#undef POP_FAILURE_POINTER
+#undef POP_FAILURE_INT
+#undef POP_FAILURE_ELT
+#undef DEBUG_PUSH
+#undef DEBUG_POP
+#undef PUSH_FAILURE_POINT
+#undef POP_FAILURE_POINT
+
+#undef REG_UNSET_VALUE
+#undef REG_UNSET
+
+#undef PATFETCH
+#undef PATFETCH_RAW
+#undef PATUNFETCH
+#undef TRANSLATE
+
+#undef INIT_BUF_SIZE
+#undef GET_BUFFER_SPACE
+#undef BUF_PUSH
+#undef BUF_PUSH_2
+#undef BUF_PUSH_3
+#undef STORE_JUMP
+#undef STORE_JUMP2
+#undef INSERT_JUMP
+#undef INSERT_JUMP2
+#undef EXTEND_BUFFER
+#undef GET_UNSIGNED_NUMBER
+#undef FREE_STACK_RETURN
+
+# undef POINTER_TO_OFFSET
+# undef MATCHING_IN_FRST_STRING
+# undef PREFETCH
+# undef AT_STRINGS_BEG
+# undef AT_STRINGS_END
+# undef WORDCHAR_P
+# undef FREE_VAR
+# undef FREE_VARIABLES
+# undef NO_HIGHEST_ACTIVE_REG
+# undef NO_LOWEST_ACTIVE_REG
+
+# undef CHAR_T
+# undef UCHAR_T
+# undef COMPILED_BUFFER_VAR
+# undef OFFSET_ADDRESS_SIZE
+# undef CHAR_CLASS_SIZE
+# undef PREFIX
+# undef ARG_PREFIX
+# undef PUT_CHAR
+# undef BYTE
+# undef WCHAR
+
+# define DEFINED_ONCE
Index: git/pwd/Makefile
===================================================================
--- git.orig/pwd/Makefile
+++ git/pwd/Makefile
@@ -18,6 +18,8 @@
 #
 #	Sub-makefile for pwd portion of the library.
 #
+include ../option-groups.mak
+
 subdir	:= pwd
 
 include ../Makeconfig
Index: git/resolv/Makefile
===================================================================
--- git.orig/resolv/Makefile
+++ git/resolv/Makefile
@@ -18,6 +18,8 @@
 #
 #	Sub-makefile for resolv portion of the library.
 #
+include ../option-groups.mak
+
 subdir	:= resolv
 
 include ../Makeconfig
@@ -27,20 +29,21 @@ headers	:= resolv.h \
 	   arpa/nameser.h arpa/nameser_compat.h \
 	   sys/bitypes.h
 
-routines := herror inet_addr inet_ntop inet_pton nsap_addr res_init \
-	    res_hconf res_libc res-state
+routines-$(OPTION_EGLIBC_INET) \
+	+= herror inet_addr inet_ntop inet_pton nsap_addr res_init \
+	   res_hconf res_libc res-state
 
-tests = tst-aton tst-leaks tst-inet_ntop
-xtests = tst-leaks2
+tests-$(OPTION_EGLIBC_INET) += tst-aton tst-leaks tst-inet_ntop
+xtests-$(OPTION_EGLIBC_INET) += tst-leaks2
 
 generate := mtrace-tst-leaks.out tst-leaks.mtrace tst-leaks2.mtrace
 
-extra-libs := libresolv libnss_dns
+extra-libs-$(OPTION_EGLIBC_INET) += libresolv libnss_dns
 ifeq ($(have-thread-library),yes)
-extra-libs += libanl
-routines += gai_sigqueue
+extra-libs-$(OPTION_EGLIBC_INET_ANL) += libanl
+routines-$(OPTION_EGLIBC_INET) += gai_sigqueue
 endif
-extra-libs-others = $(extra-libs)
+extra-libs-others-y += $(extra-libs-y)
 libresolv-routines := gethnamaddr res_comp res_debug	\
 		      res_data res_mkquery res_query res_send		\
 		      inet_net_ntop inet_net_pton inet_neta base64	\
@@ -60,7 +63,7 @@ routines                += $(libnss_dns-
 static-only-routines    += $(libnss_dns-routines) $(libresolv-routines)
 endif
 
-ifeq (yesyes,$(build-shared)$(have-thread-library))
+ifeq (yesyesy,$(build-shared)$(have-thread-library)$(OPTION_EGLIBC_INET_ANL))
 tests: $(objpfx)ga_test
 endif
 
Index: git/stdio-common/fxprintf.c
===================================================================
--- git.orig/stdio-common/fxprintf.c
+++ git/stdio-common/fxprintf.c
@@ -23,6 +23,7 @@
 #include <wchar.h>
 #include <string.h>
 #include <libioP.h>
+#include <gnu/option-groups.h>
 
 
 int
@@ -37,6 +38,7 @@ __fxprintf (FILE *fp, const char *fmt, .
   int res;
   if (_IO_fwide (fp, 0) > 0)
     {
+#if __OPTION_POSIX_WIDE_CHAR_DEVICE_IO
       size_t len = strlen (fmt) + 1;
       wchar_t wfmt[len];
       for (size_t i = 0; i < len; ++i)
@@ -45,6 +47,9 @@ __fxprintf (FILE *fp, const char *fmt, .
 	  wfmt[i] = fmt[i];
 	}
       res = __vfwprintf (fp, wfmt, ap);
+#else
+      abort();
+#endif
     }
   else
     res = _IO_vfprintf (fp, fmt, ap);
Index: git/stdio-common/_i18n_number.h
===================================================================
--- git.orig/stdio-common/_i18n_number.h
+++ git/stdio-common/_i18n_number.h
@@ -19,10 +19,13 @@
 #include <stdbool.h>
 #include <wchar.h>
 #include <wctype.h>
+#include <gnu/option-groups.h>
 
 #include "../locale/outdigits.h"
 #include "../locale/outdigitswc.h"
 
+#if __OPTION_EGLIBC_LOCALE_CODE
+
 static CHAR_T *
 _i18n_number_rewrite (CHAR_T *w, CHAR_T *rear_ptr, CHAR_T *end)
 {
@@ -115,3 +118,13 @@ _i18n_number_rewrite (CHAR_T *w, CHAR_T
 
   return w;
 }
+
+#else
+
+static CHAR_T *
+_i18n_number_rewrite (CHAR_T *w, CHAR_T *rear_ptr, CHAR_T *end)
+{
+  return w;
+}
+
+#endif
Index: git/stdio-common/Makefile
===================================================================
--- git.orig/stdio-common/Makefile
+++ git/stdio-common/Makefile
@@ -18,6 +18,8 @@
 #
 #	Specific makefile for stdio-common.
 #
+include ../option-groups.mak
+
 subdir	:= stdio-common
 
 include ../Makeconfig
@@ -30,7 +32,7 @@ routines	:=							      \
 	vfprintf vprintf printf_fp reg-printf printf-prs printf_fphex	      \
 	reg-modifier reg-type						      \
 	printf_size fprintf printf snprintf sprintf asprintf dprintf	      \
-	vfwprintf vfscanf vfwscanf					      \
+	vfscanf								      \
 	fscanf scanf sscanf						      \
 	perror psignal							      \
 	tmpfile tmpfile64 tmpnam tmpnam_r tempnam tempname		      \
@@ -41,23 +43,36 @@ routines	:=							      \
 	isoc99_vsscanf							      \
 	psiginfo
 
-aux	:= errlist siglist printf-parsemb printf-parsewc fxprintf
+# Ideally, _itowa and itowa-digits would be in this option group as
+# well, but it is used unconditionally by printf_fp and printf_fphex,
+# and it didn't seem straightforward to disentangle it.
+routines-$(OPTION_POSIX_C_LANG_WIDE_CHAR) \
+	+= vfwprintf vfwscanf
+
+aux	:= errlist siglist printf-parsemb fxprintf
+aux-$(OPTION_POSIX_C_LANG_WIDE_CHAR) += printf-parsewc
 
 tests := tstscanf test_rdwr test-popen tstgetln test-fseek \
 	 temptest tst-fileno test-fwrite tst-ungetc tst-ferror \
 	 xbug errnobug \
 	 bug1 bug2 bug3 bug4 bug5 bug6 bug7 bug8 bug9 bug10 bug11 bug12 bug13 \
-	 tfformat tiformat tllformat tstdiomisc tst-printfsz tst-wc-printf \
+	 tfformat tiformat tllformat tstdiomisc tst-printfsz \
 	 scanf1 scanf2 scanf3 scanf4 scanf5 scanf7 scanf8 scanf9 scanf10 \
-	 scanf11 scanf12 tst-tmpnam tst-cookie tst-obprintf tst-sscanf \
-	 tst-swprintf tst-fseek tst-fmemopen test-vfprintf tst-gets \
-	 tst-perror tst-sprintf tst-rndseek tst-fdopen tst-fphex bug14 \
+	 scanf11 scanf12 tst-tmpnam tst-cookie tst-obprintf \
+	 tst-fseek tst-fmemopen tst-gets \
+	 tst-sprintf tst-rndseek tst-fdopen tst-fphex \
 	 tst-popen tst-unlockedio tst-fmemopen2 tst-put-error tst-fgets \
-	 tst-fwrite bug16 bug17 tst-swscanf tst-sprintf2 bug18 bug18a \
-	 bug19 bug19a tst-popen2 scanf13 scanf14 scanf15 bug20 bug21 bug22 \
-	 scanf16 scanf17 tst-setvbuf1 tst-grouping bug23 bug24 \
-	 bug-vfprintf-nargs tst-long-dbl-fphex tst-fphex-wide tst-sprintf3 \
+	 tst-fwrite bug16 bug17 tst-sprintf2 bug18 \
+	 bug19 tst-popen2 scanf14 scanf15 bug21 bug22 \
+	 scanf16 scanf17 tst-setvbuf1 bug23 bug24 \
+	 bug-vfprintf-nargs tst-sprintf3 \
 	 bug25 tst-printf-round bug23-2 bug23-3 bug23-4 bug26
+tests-$(OPTION_EGLIBC_LOCALE_CODE) \
+	 += tst-sscanf tst-swprintf test-vfprintf bug14 scanf13 tst-grouping
+tests-$(OPTION_POSIX_WIDE_CHAR_DEVICE_IO) \
+	 += tst-perror bug19a bug20 tst-long-dbl-fphex tst-fphex-wide
+tests-$(OPTION_POSIX_C_LANG_WIDE_CHAR) \
+	 += bug18a tst-swscanf tst-wc-printf
 
 test-srcs = tst-unbputc tst-printf
 
Index: git/stdio-common/printf_fp.c
===================================================================
--- git.orig/stdio-common/printf_fp.c
+++ git/stdio-common/printf_fp.c
@@ -39,6 +39,7 @@
 #include <unistd.h>
 #include <stdlib.h>
 #include <wchar.h>
+#include <gnu/option-groups.h>
 #include <stdbool.h>
 #include <rounding-mode.h>
 
@@ -142,6 +143,10 @@ extern mp_size_t __mpn_extract_long_doub
 extern unsigned int __guess_grouping (unsigned int intdig_max,
 				      const char *grouping);
 
+/* Ideally, when OPTION_EGLIBC_LOCALE_CODE is disabled, this should do
+   all its work in ordinary characters, rather than doing it in wide
+   characters and then converting at the end.  But that is a challenge
+   for another day.  */
 
 static wchar_t *group_number (wchar_t *buf, wchar_t *bufend,
 			      unsigned int intdig_no, const char *grouping,
@@ -251,7 +256,14 @@ ___printf_fp (FILE *fp,
   mp_limb_t cy;
 
   /* Nonzero if this is output on a wide character stream.  */
+#if __OPTION_POSIX_C_LANG_WIDE_CHAR
   int wide = info->wide;
+#else
+  /* This should never be called on a wide-oriented stream when
+     OPTION_POSIX_C_LANG_WIDE_CHAR is disabled, but the compiler can't
+     be trusted to figure that out.  */
+  const int wide = 0;
+#endif
 
   /* Buffer in which we produce the output.  */
   wchar_t *wbuffer = NULL;
@@ -261,6 +273,7 @@ ___printf_fp (FILE *fp,
   p.expsign = 0;
 
   /* Figure out the decimal point character.  */
+#if __OPTION_EGLIBC_LOCALE_CODE
   if (info->extra == 0)
     {
       decimal = _NL_CURRENT (LC_NUMERIC, DECIMAL_POINT);
@@ -280,7 +293,13 @@ ___printf_fp (FILE *fp,
   /* The decimal point character must not be zero.  */
   assert (*decimal != '\0');
   assert (decimalwc != L'\0');
+#else
+  /* Hard-code values from 'C' locale.  */
+  decimal = ".";
+  decimalwc = L'.';
+#endif
 
+#if __OPTION_EGLIBC_LOCALE_CODE
   if (info->group)
     {
       if (info->extra == 0)
@@ -324,6 +343,9 @@ ___printf_fp (FILE *fp,
     }
   else
     grouping = NULL;
+#else
+  grouping = NULL;
+#endif
 
   /* Fetch the argument value.	*/
 #ifndef __NO_LONG_DOUBLE_MATH
Index: git/stdio-common/printf_fphex.c
===================================================================
--- git.orig/stdio-common/printf_fphex.c
+++ git/stdio-common/printf_fphex.c
@@ -28,6 +28,7 @@
 #include <_itoa.h>
 #include <_itowa.h>
 #include <locale/localeinfo.h>
+#include <gnu/option-groups.h>
 #include <stdbool.h>
 #include <rounding-mode.h>
 
@@ -139,10 +140,18 @@ __printf_fphex (FILE *fp,
   int done = 0;
 
   /* Nonzero if this is output on a wide character stream.  */
+#if __OPTION_POSIX_C_LANG_WIDE_CHAR
   int wide = info->wide;
+#else
+  /* This should never be called on a wide-oriented stream when
+     OPTION_POSIX_C_LANG_WIDE_CHAR is disabled, but the compiler can't
+     be trusted to figure that out.  */
+  const int wide = 0;
+#endif
 
 
   /* Figure out the decimal point character.  */
+#if __OPTION_EGLIBC_LOCALE_CODE
   if (info->extra == 0)
     {
       decimal = _NL_CURRENT (LC_NUMERIC, DECIMAL_POINT);
@@ -156,6 +165,10 @@ __printf_fphex (FILE *fp,
     }
   /* The decimal point character must never be zero.  */
   assert (*decimal != '\0' && decimalwc != L'\0');
+#else
+  decimal = ".";
+  decimalwc = L'.';
+#endif
 
 
   /* Fetch the argument value.	*/
Index: git/stdio-common/printf_size.c
===================================================================
--- git.orig/stdio-common/printf_size.c
+++ git/stdio-common/printf_size.c
@@ -23,6 +23,7 @@
 #include <math.h>
 #include <printf.h>
 #include <libioP.h>
+#include <gnu/option-groups.h>
 
 
 /* This defines make it possible to use the same code for GNU C library and
@@ -116,7 +117,14 @@ __printf_size (FILE *fp, const struct pr
 
   struct printf_info fp_info;
   int done = 0;
+#if __OPTION_POSIX_C_LANG_WIDE_CHAR
   int wide = info->wide;
+#else
+  /* This should never be called on a wide-oriented stream when
+     OPTION_POSIX_C_LANG_WIDE_CHAR is disabled, but the compiler can't
+     be trusted to figure that out.  */
+  const int wide = 0;
+#endif
   int res;
 
   /* Fetch the argument value.	*/
Index: git/stdio-common/scanf14.c
===================================================================
--- git.orig/stdio-common/scanf14.c
+++ git/stdio-common/scanf14.c
@@ -3,6 +3,7 @@
 #include <string.h>
 #include <wchar.h>
 #include <libc-internal.h>
+#include <gnu/option-groups.h>
 
 #define FAIL() \
   do {							\
@@ -48,6 +49,7 @@ main (void)
   /* See explanation above.  */
   DIAG_PUSH_NEEDS_COMMENT;
   DIAG_IGNORE_NEEDS_COMMENT (4.9, "-Wformat");
+#if __OPTION_EGLIBC_LOCALE_CODE
   if (sscanf (" 3.25S x", "%4aS%3c", &lsp, c) != 2)
     FAIL ();
   else
@@ -57,6 +59,7 @@ main (void)
       memset (lsp, 'x', sizeof L"3.25");
       free (lsp);
     }
+#endif
   if (sscanf ("4.25[0-9.] x", "%a[0-9.]%8c", &sp, c) != 2)
     FAIL ();
   else
Index: git/stdio-common/tstdiomisc.c
===================================================================
--- git.orig/stdio-common/tstdiomisc.c
+++ git/stdio-common/tstdiomisc.c
@@ -4,6 +4,7 @@
 #include <string.h>
 #include <wchar.h>
 #include <libc-internal.h>
+#include <gnu/option-groups.h>
 
 static int
 t1 (void)
@@ -134,6 +135,7 @@ F (void)
   printf ("expected \"-inf -INF -inf -INF -inf -INF -inf -INF\", got \"%s\"\n",
 	  buf);
 
+#if __OPTION_POSIX_C_LANG_WIDE_CHAR
   swprintf (wbuf, sizeof wbuf / sizeof (wbuf[0]), L"%a %A %e %E %f %F %g %G",
 	    qnanval, qnanval, qnanval, qnanval,
 	    qnanval, qnanval, qnanval, qnanval);
@@ -171,6 +173,7 @@ F (void)
   result |= wcscmp (wbuf, L"-inf -INF -inf -INF -inf -INF -inf -INF") != 0;
   printf ("expected L\"-inf -INF -inf -INF -inf -INF -inf -INF\", got L\"%S\"\n",
 	  wbuf);
+#endif /* __OPTION_POSIX_C_LANG_WIDE_CHAR */
 
   lqnanval = NAN;
 
@@ -215,6 +218,7 @@ F (void)
   printf ("expected \"-inf -INF -inf -INF -inf -INF -inf -INF\", got \"%s\"\n",
 	  buf);
 
+#if __OPTION_POSIX_C_LANG_WIDE_CHAR
   swprintf (wbuf, sizeof wbuf / sizeof (wbuf[0]),
 	    L"%La %LA %Le %LE %Lf %LF %Lg %LG",
 	    lqnanval, lqnanval, lqnanval, lqnanval,
@@ -259,6 +263,7 @@ F (void)
   result |= wcscmp (wbuf, L"-inf -INF -inf -INF -inf -INF -inf -INF") != 0;
   printf ("expected L\"-inf -INF -inf -INF -inf -INF -inf -INF\", got L\"%S\"\n",
 	  wbuf);
+#endif /* __OPTION_POSIX_C_LANG_WIDE_CHAR */
 
   return result;
 }
Index: git/stdio-common/tst-popen.c
===================================================================
--- git.orig/stdio-common/tst-popen.c
+++ git/stdio-common/tst-popen.c
@@ -19,6 +19,7 @@
 #include <stdio.h>
 #include <string.h>
 #include <wchar.h>
+#include <gnu/option-groups.h>
 
 static int
 do_test (void)
@@ -34,12 +35,14 @@ do_test (void)
       return 1;
     }
 
+#if __OPTION_POSIX_WIDE_CHAR_DEVICE_IO
   /* POSIX says that pipe streams are byte-oriented.  */
   if (fwide (f, 0) >= 0)
     {
       puts ("popen did not return byte-oriented stream");
       result = 1;
     }
+#endif
 
   if (getline (&line, &len, f) != 5)
     {
Index: git/stdio-common/tst-sprintf.c
===================================================================
--- git.orig/stdio-common/tst-sprintf.c
+++ git/stdio-common/tst-sprintf.c
@@ -3,7 +3,7 @@
 #include <locale.h>
 #include <string.h>
 #include <libc-internal.h>
-
+#include <gnu/option-groups.h>
 
 static int
 do_test (void)
@@ -11,12 +11,14 @@ do_test (void)
   char buf[100];
   int result = 0;
 
+#if __OPTION_POSIX_C_LANG_WIDE_CHAR
   if (sprintf (buf, "%.0ls", L"foo") != 0
       || strlen (buf) != 0)
     {
       puts ("sprintf (buf, \"%.0ls\", L\"foo\") produced some output");
       result = 1;
     }
+#endif /* __OPTION_POSIX_C_LANG_WIDE_CHAR */
 
 #define SIZE (1024*70000)
 #define STR(x) #x
Index: git/stdio-common/vfprintf.c
===================================================================
--- git.orig/stdio-common/vfprintf.c
+++ git/stdio-common/vfprintf.c
@@ -29,6 +29,7 @@
 #include <_itoa.h>
 #include <locale/localeinfo.h>
 #include <stdio.h>
+#include <gnu/option-groups.h>
 
 /* This code is shared between the standard stdio implementation found
    in GNU C library and the libio implementation originally found in
@@ -138,6 +139,18 @@
 # define EOF WEOF
 #endif
 
+#if __OPTION_POSIX_C_LANG_WIDE_CHAR
+# define MULTIBYTE_SUPPORT (1)
+#else
+# define MULTIBYTE_SUPPORT (0)
+#endif
+
+#if __OPTION_EGLIBC_LOCALE_CODE
+# define LOCALE_SUPPORT (1)
+#else
+# define LOCALE_SUPPORT (0)
+#endif
+
 #include "_i18n_number.h"
 
 /* Include the shared code for parsing the format string.  */
@@ -1129,8 +1142,11 @@ vfprintf (FILE *s, const CHAR_T *format,
 # define process_string_arg(fspec) \
     LABEL (form_character):						      \
       /* Character.  */							      \
-      if (is_long)							      \
-	goto LABEL (form_wcharacter);					      \
+      if (is_long)                                                            \
+        {                                                                     \
+          assert (MULTIBYTE_SUPPORT);                                         \
+          goto LABEL (form_wcharacter);                                       \
+        }                                                                     \
       --width;	/* Account for the character itself.  */		      \
       if (!left)							      \
 	PAD (' ');							      \
@@ -1143,6 +1159,7 @@ vfprintf (FILE *s, const CHAR_T *format,
       break;								      \
 									      \
     LABEL (form_wcharacter):						      \
+      assert (MULTIBYTE_SUPPORT);                                             \
       {									      \
 	/* Wide character.  */						      \
 	char buf[MB_CUR_MAX];						      \
@@ -1209,6 +1226,7 @@ vfprintf (FILE *s, const CHAR_T *format,
 	  }								      \
 	else								      \
 	  {								      \
+            assert (MULTIBYTE_SUPPORT);                                       \
 	    const wchar_t *s2 = (const wchar_t *) string;		      \
 	    mbstate_t mbstate;						      \
 									      \
@@ -1409,7 +1427,9 @@ vfprintf (FILE *s, const CHAR_T *format,
     LABEL (flag_quote):
       group = 1;
 
-      if (grouping == (const char *) -1)
+      if (! LOCALE_SUPPORT)
+        grouping = NULL;
+      else if (grouping == (const char *) -1)
 	{
 #ifdef COMPILE_WPRINTF
 	  thousands_sep = _NL_CURRENT_WORD (LC_NUMERIC,
@@ -1708,7 +1728,9 @@ do_positional:
       free (workstart);
     workstart = NULL;
 
-    if (grouping == (const char *) -1)
+    if (! LOCALE_SUPPORT)
+      grouping = NULL;
+    else if (grouping == (const char *) -1)
       {
 #ifdef COMPILE_WPRINTF
 	thousands_sep = _NL_CURRENT_WORD (LC_NUMERIC,
Index: git/stdio-common/vfscanf.c
===================================================================
--- git.orig/stdio-common/vfscanf.c
+++ git/stdio-common/vfscanf.c
@@ -29,6 +29,7 @@
 #include <wctype.h>
 #include <bits/libc-lock.h>
 #include <locale/localeinfo.h>
+#include <gnu/option-groups.h>
 
 #ifdef	__GNUC__
 # define HAVE_LONGLONG
@@ -133,6 +134,12 @@
 # define WINT_T		int
 #endif
 
+#if __OPTION_POSIX_C_LANG_WIDE_CHAR
+# define MULTIBYTE_SUPPORT (1)
+#else
+# define MULTIBYTE_SUPPORT (0)
+#endif
+
 #define encode_error() do {						      \
 			  errval = 4;					      \
 			  __set_errno (EILSEQ);				      \
@@ -316,24 +323,35 @@ _IO_vfscanf_internal (_IO_FILE *s, const
   ARGCHECK (s, format);
 
  {
-#ifndef COMPILE_WSCANF
+#if __OPTION_EGLIBC_LOCALE_CODE && !defined (COMPILE_WSCANF)
    struct __locale_data *const curnumeric = loc->__locales[LC_NUMERIC];
 #endif
 
+#if __OPTION_EGLIBC_LOCALE_CODE
    /* Figure out the decimal point character.  */
-#ifdef COMPILE_WSCANF
+# ifdef COMPILE_WSCANF
    decimal = _NL_CURRENT_WORD (LC_NUMERIC, _NL_NUMERIC_DECIMAL_POINT_WC);
-#else
+# else
    decimal = curnumeric->values[_NL_ITEM_INDEX (DECIMAL_POINT)].string;
-#endif
+# endif
    /* Figure out the thousands separator character.  */
-#ifdef COMPILE_WSCANF
+# ifdef COMPILE_WSCANF
    thousands = _NL_CURRENT_WORD (LC_NUMERIC, _NL_NUMERIC_THOUSANDS_SEP_WC);
-#else
+# else
    thousands = curnumeric->values[_NL_ITEM_INDEX (THOUSANDS_SEP)].string;
    if (*thousands == '\0')
      thousands = NULL;
-#endif
+# endif
+#else /* if ! __OPTION_EGLIBC_LOCALE_CODE */
+   /* Hard-code values from the C locale.  */
+# ifdef COMPILE_WSCANF
+   decimal = L'.';
+   thousands = L'\0';
+# else
+   decimal = ".";
+   thousands = NULL;
+# endif
+#endif /* __OPTION_EGLIBC_LOCALE_CODE */
  }
 
   /* Lock the stream.  */
@@ -385,6 +403,8 @@ _IO_vfscanf_internal (_IO_FILE *s, const
 #ifndef COMPILE_WSCANF
       if (!isascii ((unsigned char) *f))
 	{
+          assert (MULTIBYTE_SUPPORT);
+
 	  /* Non-ASCII, may be a multibyte.  */
 	  int len = __mbrlen (f, strlen (f), &state);
 	  if (len > 0)
@@ -830,6 +850,8 @@ _IO_vfscanf_internal (_IO_FILE *s, const
 	    }
 	  /* FALLTHROUGH */
 	case L_('C'):
+          assert (MULTIBYTE_SUPPORT);
+
 	  if (width == -1)
 	    width = 1;
 
@@ -1172,6 +1194,8 @@ _IO_vfscanf_internal (_IO_FILE *s, const
 	  /* FALLTHROUGH */
 
 	case L_('S'):
+          assert (MULTIBYTE_SUPPORT);
+
 	  {
 #ifndef COMPILE_WSCANF
 	    mbstate_t cstate;
@@ -1419,10 +1443,17 @@ _IO_vfscanf_internal (_IO_FILE *s, const
 	      const char *mbdigits[10];
 	      const char *mbdigits_extended[10];
 #endif
+#if __OPTION_EGLIBC_LOCALE_CODE
 	      /*  "to_inpunct" is a map from ASCII digits to their
 		  equivalent in locale. This is defined for locales
 		  which use an extra digits set.  */
 	      wctrans_t map = __wctrans ("to_inpunct");
+#else
+              /* This will always be the case when
+                 OPTION_EGLIBC_LOCALE_CODE is disabled, but the
+                 compiler can't figure that out.  */
+              wctrans_t map = NULL;
+#endif
 	      int n;
 
 	      from_level = 0;
@@ -2088,6 +2119,7 @@ _IO_vfscanf_internal (_IO_FILE *s, const
 		--width;
 	    }
 
+#if __OPTION_EGLIBC_LOCALE_CODE
 	  wctrans_t map;
 	  if (__builtin_expect ((flags & I18N) != 0, 0)
 	      /* Hexadecimal floats make no sense, fixing localized
@@ -2304,6 +2336,7 @@ _IO_vfscanf_internal (_IO_FILE *s, const
 	      ;
 #endif
 	    }
+#endif /* __OPTION_EGLIBC_LOCALE_CODE */
 
 	  /* Have we read any character?  If we try to read a number
 	     in hexadecimal notation and we have read only the `0x'
@@ -2343,7 +2376,10 @@ _IO_vfscanf_internal (_IO_FILE *s, const
 
 	case L_('['):	/* Character class.  */
 	  if (flags & LONG)
-	    STRING_ARG (wstr, wchar_t, 100);
+            {
+              assert (MULTIBYTE_SUPPORT);
+              STRING_ARG (wstr, wchar_t, 100);
+            }
 	  else
 	    STRING_ARG (str, char, 100);
 
@@ -2417,6 +2453,7 @@ _IO_vfscanf_internal (_IO_FILE *s, const
 	  if (flags & LONG)
 	    {
 	      size_t now = read_in;
+              assert (MULTIBYTE_SUPPORT);
 #ifdef COMPILE_WSCANF
 	      if (__glibc_unlikely (inchar () == WEOF))
 		input_error ();
Index: git/stdlib/Makefile
===================================================================
--- git.orig/stdlib/Makefile
+++ git/stdlib/Makefile
@@ -18,6 +18,8 @@
 #
 #	Makefile for stdlib routines
 #
+include ../option-groups.mak
+
 subdir	:= stdlib
 
 include ../Makeconfig
@@ -30,7 +32,7 @@ headers	:= stdlib.h bits/stdlib.h bits/s
 	   alloca.h fmtmsg.h						      \
 	   bits/stdlib-bsearch.h
 
-routines	:=							      \
+routines-y	:=							      \
 	atof atoi atol atoll						      \
 	abort								      \
 	bsearch qsort msort						      \
@@ -39,7 +41,6 @@ routines	:=							      \
 	quick_exit at_quick_exit cxa_at_quick_exit cxa_thread_atexit_impl     \
 	abs labs llabs							      \
 	div ldiv lldiv							      \
-	mblen mbstowcs mbtowc wcstombs wctomb				      \
 	random random_r rand rand_r					      \
 	drand48 erand48 lrand48 nrand48 mrand48 jrand48			      \
 	srand48 seed48 lcong48						      \
@@ -52,9 +53,18 @@ routines	:=							      \
 	strtof_l strtod_l strtold_l					      \
 	system canonicalize						      \
 	a64l l64a							      \
-	rpmatch strfmon strfmon_l getsubopt xpg_basename fmtmsg		      \
-	strtoimax strtoumax wcstoimax wcstoumax				      \
+	getsubopt xpg_basename						      \
+	strtoimax strtoumax						      \
 	getcontext setcontext makecontext swapcontext
+routines-$(OPTION_EGLIBC_LOCALE_CODE) +=				      \
+	strfmon strfmon_l
+routines-$(OPTION_POSIX_C_LANG_WIDE_CHAR) +=				      \
+	mblen mbstowcs mbtowc wcstombs wctomb				      \
+	wcstoimax wcstoumax
+ifeq (yy,$(OPTION_EGLIBC_LOCALE_CODE)$(OPTION_POSIX_REGEXP))
+routines-y += rpmatch
+endif
+routines-$(OPTION_EGLIBC_FMTMSG) += fmtmsg
 aux =	grouping groupingwc tens_in_limb
 
 # These routines will be omitted from the libc shared object.
@@ -62,20 +72,22 @@ aux =	grouping groupingwc tens_in_limb
 # linked against when the shared library will be used.
 static-only-routines = atexit at_quick_exit
 
-test-srcs	:= tst-fmtmsg
-tests		:= tst-strtol tst-strtod testmb testrand testsort testdiv   \
+test-srcs-$(OPTION_EGLIBC_FMTMSG) := tst-fmtmsg
+tests		:= tst-strtol tst-strtod testrand testsort testdiv          \
 		   test-canon test-canon2 tst-strtoll tst-environ	    \
 		   tst-xpg-basename tst-random tst-random2 tst-bsearch	    \
 		   tst-limits tst-rand48 bug-strtod tst-setcontext	    \
-		   test-a64l tst-qsort tst-system testmb2 bug-strtod2	    \
-		   tst-atof1 tst-atof2 tst-strtod2 tst-strtod3 tst-rand48-2 \
-		   tst-makecontext tst-strtod4 tst-strtod5 tst-qsort2	    \
-		   tst-makecontext2 tst-strtod6 tst-unsetenv1		    \
-		   tst-makecontext3 bug-getcontext bug-fmtmsg1		    \
+		   test-a64l tst-qsort tst-system bug-strtod2		    \
+		   tst-atof1 tst-atof2 tst-strtod2 tst-rand48-2             \
+		   tst-makecontext tst-qsort2 tst-makecontext2 tst-strtod6  \
+		   tst-unsetenv1 tst-makecontext3 bug-getcontext bug-fmtmsg1 \
 		   tst-secure-getenv tst-strtod-overflow tst-strtod-round   \
 		   tst-tininess tst-strtod-underflow tst-tls-atexit
 tests-static	:= tst-secure-getenv
-
+tests-$(OPTION_EGLIBC_LOCALE_CODE) \
+		+= tst-strtod3 tst-strtod4 tst-strtod5 testmb2
+tests-$(OPTION_POSIX_C_LANG_WIDE_CHAR) \
+		+= testmb
 modules-names	= tst-tls-atexit-lib
 
 ifeq ($(build-shared),yes)
@@ -115,8 +127,10 @@ CFLAGS-tst-makecontext2.c = $(stack-alig
 tests-special += $(objpfx)isomac.out
 
 ifeq ($(run-built-tests),yes)
+ifeq (y,$(OPTION_EGLIBC_FMTMSG))
 tests-special += $(objpfx)tst-fmtmsg.out
 endif
+endif
 
 include ../Rules
 
Index: git/stdlib/strtod_l.c
===================================================================
--- git.orig/stdlib/strtod_l.c
+++ git/stdlib/strtod_l.c
@@ -17,6 +17,7 @@
    License along with the GNU C Library; if not, see
    <http://www.gnu.org/licenses/>.  */
 
+#include <gnu/option-groups.h>
 #include <xlocale.h>
 
 extern double ____strtod_l_internal (const char *, char **, int, __locale_t);
@@ -548,6 +549,7 @@ ____STRTOF_INTERNAL (nptr, endptr, group
   /* Used in several places.  */
   int cnt;
 
+#if __OPTION_EGLIBC_LOCALE_CODE
   struct __locale_data *current = loc->__locales[LC_NUMERIC];
 
   if (__glibc_unlikely (group))
@@ -586,6 +588,17 @@ ____STRTOF_INTERNAL (nptr, endptr, group
   decimal_len = strlen (decimal);
   assert (decimal_len > 0);
 #endif
+#else /* if ! __OPTION_EGLIBC_LOCALE_CODE */
+  /* Hard-code values from the 'C' locale.  */
+  grouping = NULL;
+#ifdef USE_WIDE_CHAR
+  decimal = L'.';
+# define decimal_len 1
+#else
+  decimal = ".";
+  decimal_len = 1;
+#endif
+#endif /* __OPTION_EGLIBC_LOCALE_CODE */
 
   /* Prepare number representation.  */
   exponent = 0;
Index: git/stdlib/tst-strtod.c
===================================================================
--- git.orig/stdlib/tst-strtod.c
+++ git/stdlib/tst-strtod.c
@@ -23,6 +23,7 @@
 #include <errno.h>
 #include <string.h>
 #include <math.h>
+#include <gnu/option-groups.h>
 
 struct ltest
   {
@@ -176,7 +177,9 @@ main (int argc, char ** argv)
 
   status |= long_dbl ();
 
+#if __OPTION_EGLIBC_LOCALE_CODE
   status |= locale_test ();
+#endif
 
   return status ? EXIT_FAILURE : EXIT_SUCCESS;
 }
@@ -219,6 +222,7 @@ long_dbl (void)
   return 0;
 }
 
+#if __OPTION_EGLIBC_LOCALE_CODE
 /* Perform a few tests in a locale with thousands separators.  */
 static int
 locale_test (void)
@@ -276,3 +280,4 @@ locale_test (void)
 
   return result;
 }
+#endif /* __OPTION_EGLIBC_LOCALE_CODE */
Index: git/streams/Makefile
===================================================================
--- git.orig/streams/Makefile
+++ git/streams/Makefile
@@ -18,11 +18,14 @@
 #
 #	Makefile for streams.
 #
+include ../option-groups.mak
+
 subdir	:= streams
 
 include ../Makeconfig
 
 headers		= stropts.h sys/stropts.h bits/stropts.h bits/xtitypes.h
-routines	= isastream getmsg getpmsg putmsg putpmsg fattach fdetach
+routines-$(OPTION_EGLIBC_STREAMS) \
+	+= isastream getmsg getpmsg putmsg putpmsg fattach fdetach
 
 include ../Rules
Index: git/string/Makefile
===================================================================
--- git.orig/string/Makefile
+++ git/string/Makefile
@@ -18,6 +18,8 @@
 #
 #	Sub-makefile for string portion of library.
 #
+include ../option-groups.mak
+
 subdir	:= string
 
 include ../Makeconfig
@@ -39,10 +41,12 @@ routines	:= strcat strchr strcmp strcoll
 		   $(addprefix argz-,append count create ctsep next	\
 				     delete extract insert stringify	\
 				     addsep replace)			\
-		   envz basename					\
+		   basename						\
 		   strcoll_l strxfrm_l string-inlines memrchr		\
 		   xpg-strerror strerror_l
 
+routines-$(OPTION_EGLIBC_ENVZ) += envz
+
 strop-tests	:= memchr memcmp memcpy memmove mempcpy memset memccpy	\
 		   stpcpy stpncpy strcat strchr strcmp strcpy strcspn	\
 		   strlen strncmp strncpy strpbrk strrchr strspn memmem	\
@@ -51,10 +55,12 @@ strop-tests	:= memchr memcmp memcpy memm
 tests		:= tester inl-tester noinl-tester testcopy test-ffs	\
 		   tst-strlen stratcliff tst-svc tst-inlcall		\
 		   bug-strncat1 bug-strspn1 bug-strpbrk1 tst-bswap	\
-		   tst-strtok tst-strxfrm bug-strcoll1 tst-strfry	\
+		   tst-strtok tst-strfry	\
 		   bug-strtok1 $(addprefix test-,$(strop-tests))	\
-		   bug-envz1 tst-strxfrm2 tst-endian tst-svc2		\
-		   tst-strtok_r
+		   tst-strxfrm2 tst-endian tst-svc2 tst-strtok_r
+tests-$(OPTION_EGLIBC_ENVZ) += bug-envz1
+tests-$(OPTION_EGLIBC_LOCALE_CODE) \
+		+= tst-strxfrm bug-strcoll1
 
 xtests = tst-strcoll-overflow
 
Index: git/string/strcoll_l.c
===================================================================
--- git.orig/string/strcoll_l.c
+++ git/string/strcoll_l.c
@@ -24,6 +24,7 @@
 #include <stdint.h>
 #include <string.h>
 #include <sys/param.h>
+#include <gnu/option-groups.h>
 
 #ifndef STRING_TYPE
 # define STRING_TYPE char
@@ -247,7 +248,11 @@ int
 STRCOLL (const STRING_TYPE *s1, const STRING_TYPE *s2, __locale_t l)
 {
   struct __locale_data *current = l->__locales[LC_COLLATE];
+#if __OPTION_EGLIBC_LOCALE_CODE
   uint_fast32_t nrules = current->values[_NL_ITEM_INDEX (_NL_COLLATE_NRULES)].word;
+#else
+  const uint_fast32_t nrules = 0;
+#endif
   /* We don't assign the following values right away since it might be
      unnecessary in case there are no rules.  */
   const unsigned char *rulesets;
Index: git/string/strerror_l.c
===================================================================
--- git.orig/string/strerror_l.c
+++ git/string/strerror_l.c
@@ -21,6 +21,7 @@
 #include <stdlib.h>
 #include <string.h>
 #include <sys/param.h>
+#include <gnu/option-groups.h>
 
 
 static __thread char *last_value;
@@ -29,10 +30,14 @@ static __thread char *last_value;
 static const char *
 translate (const char *str, locale_t loc)
 {
+#if __OPTION_EGLIBC_LOCALE_CODE
   locale_t oldloc = __uselocale (loc);
   const char *res = _(str);
   __uselocale (oldloc);
   return res;
+#else
+  return str;
+#endif
 }
 
 
Index: git/string/strxfrm_l.c
===================================================================
--- git.orig/string/strxfrm_l.c
+++ git/string/strxfrm_l.c
@@ -24,6 +24,7 @@
 #include <stdlib.h>
 #include <string.h>
 #include <sys/param.h>
+#include <gnu/option-groups.h>
 
 #ifndef STRING_TYPE
 # define STRING_TYPE char
@@ -670,7 +671,11 @@ STRXFRM (STRING_TYPE *dest, const STRING
 {
   locale_data_t l_data;
   struct __locale_data *current = l->__locales[LC_COLLATE];
+#if __OPTION_EGLIBC_LOCALE_CODE
   l_data.nrules = current->values[_NL_ITEM_INDEX (_NL_COLLATE_NRULES)].word;
+#else
+  l_data.nrules = 0;
+#endif
 
   /* Handle byte comparison case.  */
   if (l_data.nrules == 0)
Index: git/string/test-strcmp.c
===================================================================
--- git.orig/string/test-strcmp.c
+++ git/string/test-strcmp.c
@@ -329,34 +329,6 @@ check (void)
 		FOR_EACH_IMPL (impl, 0)
 		check_result (impl, s1 + i1, s2 + i2, exp_result);
       }
-
-  /* Test cases where there are multiple zero bytes after the first.  */
-
-  for (size_t i = 0; i < 16 + 1; i++)
-    {
-      s1[i] = 0x00;
-      s2[i] = 0x00;
-    }
-
-  for (size_t i = 0; i < 16; i++)
-    {
-      int exp_result;
-
-      for (int val = 0x01; val < 0x100; val++)
-	{
-	  for (size_t j = 0; j < i; j++)
-	    {
-	      s1[j] = val;
-	      s2[j] = val;
-	    }
-
-	  s2[i] = val;
-
-	  exp_result = SIMPLE_STRCMP (s1, s2);
-	  FOR_EACH_IMPL (impl, 0)
-	    check_result (impl, s1, s2, exp_result);
-	}
-    }
 }
 
 
Index: git/string/tst-strxfrm2.c
===================================================================
--- git.orig/string/tst-strxfrm2.c
+++ git/string/tst-strxfrm2.c
@@ -1,6 +1,7 @@
 #include <locale.h>
 #include <stdio.h>
 #include <string.h>
+#include <gnu/option-groups.h>
 
 static int
 do_test (void)
@@ -38,6 +39,7 @@ do_test (void)
       res = 1;
     }
 
+#if __OPTION_EGLIBC_LOCALE_CODE
   if (setlocale (LC_ALL, "de_DE.UTF-8") == NULL)
     {
       puts ("setlocale failed");
@@ -75,6 +77,7 @@ do_test (void)
 	  res = 1;
 	}
     }
+#endif
 
   return res;
 }
Index: git/string/tst-strxfrm.c
===================================================================
--- git.orig/string/tst-strxfrm.c
+++ git/string/tst-strxfrm.c
@@ -3,6 +3,7 @@
 #include <stdio.h>
 #include <stdlib.h>
 #include <string.h>
+#include <gnu/option-groups.h>
 
 
 char const string[] = "";
@@ -64,8 +65,10 @@ do_test (void)
   int result = 0;
 
   result |= test ("C");
+#if __OPTION_EGLIBC_LOCALE_CODE
   result |= test ("en_US.ISO-8859-1");
   result |= test ("de_DE.UTF-8");
+#endif
 
   return result;
 }
Index: git/sunrpc/Makefile
===================================================================
--- git.orig/sunrpc/Makefile
+++ git/sunrpc/Makefile
@@ -18,6 +18,8 @@
 #
 #	Sub-makefile for sunrpc portion of the library.
 #
+include ../option-groups.mak
+
 subdir	:= sunrpc
 
 include ../Makeconfig
@@ -55,7 +57,6 @@ headers-in-tirpc = $(addprefix rpc/,auth
 headers-not-in-tirpc = $(addprefix rpc/,key_prot.h rpc_des.h) \
 		       $(rpcsvc:%=rpcsvc/%) rpcsvc/bootparam.h
 headers = rpc/netdb.h
-install-others = $(inst_sysconfdir)/rpc
 generated += $(rpcsvc:%.x=rpcsvc/%.h) $(rpcsvc:%.x=x%.c) $(rpcsvc:%.x=x%.stmp) \
 	     $(rpcsvc:%.x=rpcsvc/%.stmp) rpcgen
 generated-dirs += rpcsvc
@@ -65,18 +66,28 @@ headers += $(headers-in-tirpc) $(headers
 endif
 
 ifeq ($(build-shared),yes)
-need-export-routines := auth_des auth_unix clnt_gen clnt_perr clnt_tcp \
+need-export-routines-$(OPTION_EGLIBC_SUNRPC) += \
+			auth_des auth_unix clnt_gen clnt_perr clnt_tcp \
 			clnt_udp get_myaddr key_call netname pm_getport \
-			rpc_thread svc svc_tcp svc_udp xcrypt xdr_array xdr \
+			rpc_thread svc svc_tcp svc_udp xdr_array xdr \
 			xdr_intXX_t xdr_mem xdr_ref xdr_sizeof xdr_stdio \
 			svc_run
 
-routines := auth_none authuxprot bindrsvprt clnt_raw clnt_simp \
+need-export-routines-y += xcrypt
+
+need-export-routines := $(need-export-routines-y)
+
+routines-$(OPTION_EGLIBC_SUNRPC) \
+	 += auth_none authuxprot bindrsvprt clnt_raw clnt_simp \
 	    rpc_dtable getrpcport pmap_clnt pm_getmaps pmap_prot pmap_prot2 \
 	    pmap_rmt rpc_prot rpc_common rpc_cmsg svc_auth svc_authux svc_raw \
 	    svc_simple xdr_float xdr_rec publickey authdes_prot \
-	    des_crypt des_impl des_soft key_prot openchild rtime svcauth_des \
-	    clnt_unix svc_unix create_xid $(need-export-routines)
+	    key_prot openchild rtime svcauth_des \
+	    clnt_unix svc_unix create_xid
+
+# xdecrypt is also used by nss/nss_files/files-key.c.
+routines-y += des_crypt des_impl des_soft $(need-export-routines)
+
 ifneq ($(link-obsolete-rpc),yes)
 # We only add the RPC for compatibility to libc.so.
 shared-only-routines = $(routines)
@@ -85,25 +96,28 @@ endif
 
 # We do not build rpcinfo anymore.  It is not needed for a bootstrap
 # and not wanted on complete systems.
-# others := rpcinfo
-# install-sbin := rpcinfo
-install-bin := rpcgen
+# others-$(OPTION_EGLIBC_SUNRPC) += rpcinfo
+# install-sbin-$(OPTION_EGLIBC_SUNRPC) += rpcinfo
+install-bin-$(OPTION_EGLIBC_SUNRPC) += rpcgen
 rpcgen-objs = rpc_main.o rpc_hout.o rpc_cout.o rpc_parse.o \
 	      rpc_scan.o rpc_util.o rpc_svcout.o rpc_clntout.o \
 	      rpc_tblout.o rpc_sample.o
-extra-objs = $(rpcgen-objs) $(addprefix cross-,$(rpcgen-objs))
-others += rpcgen
+extra-objs-$(OPTION_EGLIBC_SUNRPC) = $(rpcgen-objs) $(addprefix cross-,$(rpcgen-objs))
+others-$(OPTION_EGLIBC_SUNRPC) += rpcgen
+
+install-others-$(OPTION_EGLIBC_SUNRPC) += $(inst_sysconfdir)/rpc
 
-tests = tst-xdrmem tst-xdrmem2
-xtests := tst-getmyaddr
+tests-$(OPTION_EGLIBC_SUNRPC) = tst-xdrmem tst-xdrmem2
+xtests-$(OPTION_EGLIBC_SUNRPC) := tst-getmyaddr
 
 ifeq ($(have-thread-library),yes)
-xtests += thrsvc
+xtests-$(OPTION_EGLIBC_SUNRPC) += thrsvc
 endif
 
 headers += $(rpcsvc:%.x=rpcsvc/%.h)
-extra-libs := librpcsvc
-extra-libs-others := librpcsvc # Make it in `others' pass, not `lib' pass.
+extra-libs-$(OPTION_EGLIBC_SUNRPC) += librpcsvc
+# Make it in `others' pass, not `lib' pass.
+extra-libs-others-y += $(extra-libs-y)
 librpcsvc-routines = $(rpcsvc:%.x=x%)
 librpcsvc-inhibit-o = .os # Build no shared rpcsvc library.
 omit-deps = $(librpcsvc-routines)
Index: git/sysdeps/generic/ldsodefs.h
===================================================================
--- git.orig/sysdeps/generic/ldsodefs.h
+++ git/sysdeps/generic/ldsodefs.h
@@ -425,6 +425,12 @@ extern struct rtld_global _rtld_global _
 # undef __rtld_global_attribute__
 #endif
 
+#if __OPTION_EGLIBC_RTLD_DEBUG
+# define GLRO_dl_debug_mask GLRO(dl_debug_mask)
+#else
+# define GLRO_dl_debug_mask 0
+#endif
+
 #ifndef SHARED
 # define GLRO(name) _##name
 #else
@@ -437,8 +443,10 @@ struct rtld_global_ro
 {
 #endif
 
+#if __OPTION_EGLIBC_RTLD_DEBUG
   /* If nonzero the appropriate debug information is printed.  */
   EXTERN int _dl_debug_mask;
+#endif
 #define DL_DEBUG_LIBS	    (1 << 0)
 #define DL_DEBUG_IMPCALLS   (1 << 1)
 #define DL_DEBUG_BINDINGS   (1 << 2)
Index: git/sysdeps/gnu/Makefile
===================================================================
--- git.orig/sysdeps/gnu/Makefile
+++ git/sysdeps/gnu/Makefile
@@ -59,7 +59,8 @@ $(foreach o,$(object-suffixes) $(object-
 endif
 
 ifeq ($(subdir),login)
-sysdep_routines += setutxent getutxent endutxent getutxid getutxline \
+sysdep_routines-$(OPTION_EGLIBC_UTMPX) \
+		+= setutxent getutxent endutxent getutxid getutxline \
 		   pututxline utmpxname updwtmpx getutmpx getutmp
 
 sysdep_headers += utmpx.h bits/utmpx.h
Index: git/sysdeps/ieee754/ldbl-opt/Makefile
===================================================================
--- git.orig/sysdeps/ieee754/ldbl-opt/Makefile
+++ git/sysdeps/ieee754/ldbl-opt/Makefile
@@ -11,19 +11,18 @@ libm-routines += s_nexttowardfd
 routines += math_ldbl_opt nldbl-compat
 
 extra-libs += libnldbl
-libnldbl-calls = asprintf dprintf fprintf fscanf fwprintf fwscanf iovfscanf \
+libnldbl-calls = asprintf dprintf fprintf fscanf iovfscanf \
 		 obstack_printf obstack_vprintf printf scanf snprintf \
-		 sprintf sscanf swprintf swscanf vasprintf vdprintf vfprintf \
-		 vfscanf vfwprintf vfwscanf vprintf vscanf vsnprintf \
-		 vsprintf vsscanf vswprintf vswscanf vwprintf vwscanf \
-		 wprintf wscanf printf_fp printf_size \
-		 fprintf_chk fwprintf_chk printf_chk snprintf_chk sprintf_chk \
-		 swprintf_chk vfprintf_chk vfwprintf_chk vprintf_chk \
-		 vsnprintf_chk vsprintf_chk vswprintf_chk vwprintf_chk \
-		 wprintf_chk asprintf_chk vasprintf_chk dprintf_chk \
+		 sprintf sscanf vasprintf vdprintf vfprintf \
+		 vfscanf vprintf vscanf vsnprintf \
+		 vsprintf vsscanf \
+		 printf_fp printf_size \
+		 fprintf_chk printf_chk snprintf_chk sprintf_chk \
+		 vfprintf_chk vprintf_chk \
+		 vsnprintf_chk vsprintf_chk \
+		 asprintf_chk vasprintf_chk dprintf_chk \
 		 vdprintf_chk obstack_printf_chk obstack_vprintf_chk \
 		 syslog syslog_chk vsyslog vsyslog_chk \
-		 strfmon strfmon_l \
 		 strtold strtold_l strtoldint wcstold wcstold_l wcstoldint \
 		 qecvt qfcvt qgcvt qecvt_r qfcvt_r \
 		 isinf isnan finite signbit scalb log2 lgamma_r ceil \
@@ -38,9 +37,15 @@ libnldbl-calls = asprintf dprintf fprint
 		 casinh cexp clog cproj csin csinh csqrt ctan ctanh cpow \
 		 cabs carg cimag creal clog10 \
 		 isoc99_scanf isoc99_fscanf isoc99_sscanf \
-		 isoc99_vscanf isoc99_vfscanf isoc99_vsscanf \
+		 isoc99_vscanf isoc99_vfscanf isoc99_vsscanf
+libnldbl-calls-$(OPTION_EGLIBC_LOCALE_CODE) += strfmon strfmon_l
+libnldbl-calls-$(OPTION_POSIX_WIDE_CHAR_DEVICE_IO) += fwprintf fwscanf \
+		 swprintf swscanf vfwprintf vfwscanf vswprintf vswscanf \
+		 vwprintf vwscanf wprintf wscanf fwprintf_chk swprintf_chk \
+		 vfwprintf_chk vswprintf_chk vwprintf_chk wprintf_chk \
 		 isoc99_wscanf isoc99_fwscanf isoc99_swscanf \
 		 isoc99_vwscanf isoc99_vfwscanf isoc99_vswscanf
+libnldbl-calls += $(libnldbl-calls-y)
 libnldbl-routines = $(libnldbl-calls:%=nldbl-%)
 libnldbl-inhibit-o = $(object-suffixes)
 libnldbl-static-only-routines = $(libnldbl-routines)
Index: git/sysdeps/ieee754/ldbl-opt/nldbl-compat.c
===================================================================
--- git.orig/sysdeps/ieee754/ldbl-opt/nldbl-compat.c
+++ git/sysdeps/ieee754/ldbl-opt/nldbl-compat.c
@@ -26,6 +26,7 @@
 #include <locale/localeinfo.h>
 #include <sys/syslog.h>
 #include <bits/libc-lock.h>
+#include <gnu/option-groups.h>
 
 #include "nldbl-compat.h"
 
@@ -33,20 +34,14 @@ libc_hidden_proto (__nldbl_vfprintf)
 libc_hidden_proto (__nldbl_vsscanf)
 libc_hidden_proto (__nldbl_vsprintf)
 libc_hidden_proto (__nldbl_vfscanf)
-libc_hidden_proto (__nldbl_vfwscanf)
 libc_hidden_proto (__nldbl_vdprintf)
-libc_hidden_proto (__nldbl_vswscanf)
-libc_hidden_proto (__nldbl_vfwprintf)
-libc_hidden_proto (__nldbl_vswprintf)
 libc_hidden_proto (__nldbl_vsnprintf)
 libc_hidden_proto (__nldbl_vasprintf)
 libc_hidden_proto (__nldbl_obstack_vprintf)
-libc_hidden_proto (__nldbl___vfwprintf_chk)
 libc_hidden_proto (__nldbl___vsnprintf_chk)
 libc_hidden_proto (__nldbl___vfprintf_chk)
 libc_hidden_proto (__nldbl___vsyslog_chk)
 libc_hidden_proto (__nldbl___vsprintf_chk)
-libc_hidden_proto (__nldbl___vswprintf_chk)
 libc_hidden_proto (__nldbl___vasprintf_chk)
 libc_hidden_proto (__nldbl___vdprintf_chk)
 libc_hidden_proto (__nldbl___obstack_vprintf_chk)
@@ -54,8 +49,17 @@ libc_hidden_proto (__nldbl___vstrfmon)
 libc_hidden_proto (__nldbl___vstrfmon_l)
 libc_hidden_proto (__nldbl___isoc99_vsscanf)
 libc_hidden_proto (__nldbl___isoc99_vfscanf)
+
+#if __OPTION_POSIX_WIDE_CHAR_DEVICE_IO
+libc_hidden_proto (__nldbl_vfwscanf)
+libc_hidden_proto (__nldbl_vswscanf)
+libc_hidden_proto (__nldbl_vfwprintf)
+libc_hidden_proto (__nldbl_vswprintf)
+libc_hidden_proto (__nldbl___vfwprintf_chk)
+libc_hidden_proto (__nldbl___vswprintf_chk)
 libc_hidden_proto (__nldbl___isoc99_vswscanf)
 libc_hidden_proto (__nldbl___isoc99_vfwscanf)
+#endif
 
 static void
 __nldbl_cleanup (void *arg)
@@ -117,6 +121,7 @@ __nldbl_fprintf (FILE *stream, const cha
 }
 weak_alias (__nldbl_fprintf, __nldbl__IO_fprintf)
 
+#if __OPTION_POSIX_WIDE_CHAR_DEVICE_IO
 int
 attribute_compat_text_section weak_function
 __nldbl_fwprintf (FILE *stream, const wchar_t *fmt, ...)
@@ -130,6 +135,7 @@ __nldbl_fwprintf (FILE *stream, const wc
 
   return done;
 }
+#endif
 
 int
 attribute_compat_text_section
@@ -226,6 +232,7 @@ __nldbl_snprintf (char *s, size_t maxlen
   return done;
 }
 
+#if __OPTION_POSIX_WIDE_CHAR_DEVICE_IO
 int
 attribute_compat_text_section
 __nldbl_swprintf (wchar_t *s, size_t n, const wchar_t *fmt, ...)
@@ -239,6 +246,7 @@ __nldbl_swprintf (wchar_t *s, size_t n,
 
   return done;
 }
+#endif
 
 int
 attribute_compat_text_section weak_function
@@ -264,6 +272,7 @@ __nldbl_vdprintf (int d, const char *fmt
 }
 libc_hidden_def (__nldbl_vdprintf)
 
+#if __OPTION_POSIX_WIDE_CHAR_DEVICE_IO
 int
 attribute_compat_text_section weak_function
 __nldbl_vfwprintf (FILE *s, const wchar_t *fmt, va_list ap)
@@ -275,6 +284,7 @@ __nldbl_vfwprintf (FILE *s, const wchar_
   return res;
 }
 libc_hidden_def (__nldbl_vfwprintf)
+#endif
 
 int
 attribute_compat_text_section
@@ -297,6 +307,7 @@ __nldbl_vsnprintf (char *string, size_t
 libc_hidden_def (__nldbl_vsnprintf)
 weak_alias (__nldbl_vsnprintf, __nldbl___vsnprintf)
 
+#if __OPTION_POSIX_WIDE_CHAR_DEVICE_IO
 int
 attribute_compat_text_section weak_function
 __nldbl_vswprintf (wchar_t *string, size_t maxlen, const wchar_t *fmt,
@@ -330,6 +341,7 @@ __nldbl_wprintf (const wchar_t *fmt, ...
 
   return done;
 }
+#endif
 
 int
 attribute_compat_text_section
@@ -419,6 +431,7 @@ __nldbl_scanf (const char *fmt, ...)
   return done;
 }
 
+#if __OPTION_POSIX_WIDE_CHAR_DEVICE_IO
 int
 attribute_compat_text_section
 __nldbl_vfwscanf (FILE *s, const wchar_t *fmt, va_list ap)
@@ -491,6 +504,7 @@ __nldbl_wscanf (const wchar_t *fmt, ...)
 
   return done;
 }
+#endif
 
 int
 attribute_compat_text_section
@@ -506,6 +520,7 @@ __nldbl___fprintf_chk (FILE *stream, int
   return done;
 }
 
+#if __OPTION_POSIX_WIDE_CHAR_DEVICE_IO
 int
 attribute_compat_text_section
 __nldbl___fwprintf_chk (FILE *stream, int flag, const wchar_t *fmt, ...)
@@ -519,6 +534,7 @@ __nldbl___fwprintf_chk (FILE *stream, in
 
   return done;
 }
+#endif
 
 int
 attribute_compat_text_section
@@ -563,6 +579,7 @@ __nldbl___sprintf_chk (char *s, int flag
   return done;
 }
 
+#if __OPTION_POSIX_WIDE_CHAR_DEVICE_IO
 int
 attribute_compat_text_section
 __nldbl___swprintf_chk (wchar_t *s, size_t n, int flag, size_t slen,
@@ -577,6 +594,7 @@ __nldbl___swprintf_chk (wchar_t *s, size
 
   return done;
 }
+#endif
 
 int
 attribute_compat_text_section
@@ -590,6 +608,7 @@ __nldbl___vfprintf_chk (FILE *s, int fla
 }
 libc_hidden_def (__nldbl___vfprintf_chk)
 
+#if __OPTION_POSIX_WIDE_CHAR_DEVICE_IO
 int
 attribute_compat_text_section
 __nldbl___vfwprintf_chk (FILE *s, int flag, const wchar_t *fmt, va_list ap)
@@ -601,6 +620,7 @@ __nldbl___vfwprintf_chk (FILE *s, int fl
   return res;
 }
 libc_hidden_def (__nldbl___vfwprintf_chk)
+#endif
 
 int
 attribute_compat_text_section
@@ -635,6 +655,7 @@ __nldbl___vsprintf_chk (char *string, in
 }
 libc_hidden_def (__nldbl___vsprintf_chk)
 
+#if __OPTION_POSIX_WIDE_CHAR_DEVICE_IO
 int
 attribute_compat_text_section
 __nldbl___vswprintf_chk (wchar_t *string, size_t maxlen, int flag, size_t slen,
@@ -668,6 +689,7 @@ __nldbl___wprintf_chk (int flag, const w
 
   return done;
 }
+#endif
 
 int
 attribute_compat_text_section
@@ -775,6 +797,7 @@ __nldbl___printf_fp (FILE *fp, const str
   return ___printf_fp (fp, &info_no_ldbl, args);
 }
 
+#if __OPTION_EGLIBC_LOCALE_CODE
 ssize_t
 attribute_compat_text_section
 __nldbl_strfmon (char *s, size_t maxsize, const char *format, ...)
@@ -829,6 +852,7 @@ __nldbl___vstrfmon_l (char *s, size_t ma
   return res;
 }
 libc_hidden_def (__nldbl___vstrfmon_l)
+#endif
 
 void
 attribute_compat_text_section
@@ -941,6 +965,7 @@ __nldbl___isoc99_scanf (const char *fmt,
   return done;
 }
 
+#if __OPTION_POSIX_WIDE_CHAR_DEVICE_IO
 int
 attribute_compat_text_section
 __nldbl___isoc99_vfwscanf (FILE *s, const wchar_t *fmt, va_list ap)
@@ -1014,6 +1039,7 @@ __nldbl___isoc99_wscanf (const wchar_t *
 
   return done;
 }
+#endif
 
 #if LONG_DOUBLE_COMPAT(libc, GLIBC_2_0)
 compat_symbol (libc, __nldbl__IO_printf, _IO_printf, GLIBC_2_0);
@@ -1057,6 +1083,7 @@ compat_symbol (libc, __nldbl_printf_size
 compat_symbol (libc, __nldbl___strfmon_l, __strfmon_l, GLIBC_2_1);
 #endif
 #if LONG_DOUBLE_COMPAT(libc, GLIBC_2_2)
+# if __OPTION_POSIX_WIDE_CHAR_DEVICE_IO
 compat_symbol (libc, __nldbl_swprintf, swprintf, GLIBC_2_2);
 compat_symbol (libc, __nldbl_vwprintf, vwprintf, GLIBC_2_2);
 compat_symbol (libc, __nldbl_wprintf, wprintf, GLIBC_2_2);
@@ -1069,6 +1096,7 @@ compat_symbol (libc, __nldbl_vfwscanf, v
 compat_symbol (libc, __nldbl_vswscanf, vswscanf, GLIBC_2_2);
 compat_symbol (libc, __nldbl_vwscanf, vwscanf, GLIBC_2_2);
 compat_symbol (libc, __nldbl_wscanf, wscanf, GLIBC_2_2);
+# endif
 #endif
 #if LONG_DOUBLE_COMPAT(libc, GLIBC_2_3)
 compat_symbol (libc, __nldbl_strfmon_l, strfmon_l, GLIBC_2_3);
Index: git/sysdeps/ieee754/ldbl-opt/nldbl-compat.h
===================================================================
--- git.orig/sysdeps/ieee754/ldbl-opt/nldbl-compat.h
+++ git/sysdeps/ieee754/ldbl-opt/nldbl-compat.h
@@ -30,6 +30,7 @@
 #include <math.h>
 #include <monetary.h>
 #include <sys/syslog.h>
+#include <gnu/option-groups.h>
 
 
 /* Declare the __nldbl_NAME function the wrappers call that's in libc.so.  */
@@ -37,19 +38,15 @@
 
 NLDBL_DECL (_IO_vfscanf);
 NLDBL_DECL (vfscanf);
-NLDBL_DECL (vfwscanf);
 NLDBL_DECL (obstack_vprintf);
 NLDBL_DECL (vasprintf);
 NLDBL_DECL (dprintf);
 NLDBL_DECL (vdprintf);
 NLDBL_DECL (fprintf);
 NLDBL_DECL (vfprintf);
-NLDBL_DECL (vfwprintf);
 NLDBL_DECL (vsnprintf);
 NLDBL_DECL (vsprintf);
 NLDBL_DECL (vsscanf);
-NLDBL_DECL (vswprintf);
-NLDBL_DECL (vswscanf);
 NLDBL_DECL (__asprintf);
 NLDBL_DECL (asprintf);
 NLDBL_DECL (__printf_fp);
@@ -66,12 +63,18 @@ NLDBL_DECL (__isoc99_sscanf);
 NLDBL_DECL (__isoc99_vscanf);
 NLDBL_DECL (__isoc99_vfscanf);
 NLDBL_DECL (__isoc99_vsscanf);
+#if __OPTION_POSIX_WIDE_CHAR_DEVICE_IO
+NLDBL_DECL (vfwscanf);
+NLDBL_DECL (vfwprintf);
+NLDBL_DECL (vswprintf);
+NLDBL_DECL (vswscanf);
 NLDBL_DECL (__isoc99_wscanf);
 NLDBL_DECL (__isoc99_fwscanf);
 NLDBL_DECL (__isoc99_swscanf);
 NLDBL_DECL (__isoc99_vwscanf);
 NLDBL_DECL (__isoc99_vfwscanf);
 NLDBL_DECL (__isoc99_vswscanf);
+#endif
 
 /* This one does not exist in the normal interface, only
    __nldbl___vstrfmon really exists.  */
@@ -82,22 +85,23 @@ extern ssize_t __nldbl___vstrfmon (char
    since we don't compile with _FORTIFY_SOURCE.  */
 extern int __nldbl___vfprintf_chk (FILE *__restrict, int,
 				   const char *__restrict, _G_va_list);
-extern int __nldbl___vfwprintf_chk (FILE *__restrict, int,
-				    const wchar_t *__restrict, __gnuc_va_list);
 extern int __nldbl___vsprintf_chk (char *__restrict, int, size_t,
 				   const char *__restrict, _G_va_list) __THROW;
 extern int __nldbl___vsnprintf_chk (char *__restrict, size_t, int, size_t,
 				    const char *__restrict, _G_va_list)
   __THROW;
-extern int __nldbl___vswprintf_chk (wchar_t *__restrict, size_t, int, size_t,
-				    const wchar_t *__restrict, __gnuc_va_list)
-  __THROW;
 extern int __nldbl___vasprintf_chk (char **, int, const char *, _G_va_list)
   __THROW;
 extern int __nldbl___vdprintf_chk (int, int, const char *, _G_va_list);
 extern int __nldbl___obstack_vprintf_chk (struct obstack *, int, const char *,
 					  _G_va_list) __THROW;
 extern void __nldbl___vsyslog_chk (int, int, const char *, va_list);
-
+#if __OPTION_POSIX_WIDE_CHAR_DEVICE_IO
+extern int __nldbl___vfwprintf_chk (FILE *__restrict, int,
+				    const wchar_t *__restrict, __gnuc_va_list);
+extern int __nldbl___vswprintf_chk (wchar_t *__restrict, size_t, int, size_t,
+				    const wchar_t *__restrict, __gnuc_va_list)
+  __THROW;
+#endif
 
 #endif /* __NLDBL_COMPAT_H */
Index: git/sysdeps/unix/sysv/linux/gethostid.c
===================================================================
--- git.orig/sysdeps/unix/sysv/linux/gethostid.c
+++ git/sysdeps/unix/sysv/linux/gethostid.c
@@ -21,6 +21,7 @@
 #include <unistd.h>
 #include <netdb.h>
 #include <not-cancel.h>
+#include <gnu/option-groups.h>
 
 #define HOSTIDFILE "/etc/hostid"
 
@@ -89,6 +90,7 @@ gethostid (void)
 	return id;
     }
 
+#if __OPTION_EGLIBC_INET
   /* Getting from the file was not successful.  An intelligent guess for
      a unique number of a host is its IP address.  Return this.  */
   if (__gethostname (hostname, MAXHOSTNAMELEN) < 0 || hostname[0] == '\0')
@@ -115,5 +117,9 @@ gethostid (void)
   /* For the return value to be not exactly the IP address we do some
      bit fiddling.  */
   return (int32_t) (in.s_addr << 16 | in.s_addr >> 16);
+#else
+  /* Return an arbitrary value.  */
+  return 0;
+#endif
 }
 #endif
Index: git/sysdeps/unix/sysv/linux/libc_fatal.c
===================================================================
--- git.orig/sysdeps/unix/sysv/linux/libc_fatal.c
+++ git/sysdeps/unix/sysv/linux/libc_fatal.c
@@ -23,6 +23,7 @@
 #include <string.h>
 #include <sys/mman.h>
 #include <sys/uio.h>
+#include <gnu/option-groups.h>
 
 static bool
 writev_for_fatal (int fd, const struct iovec *iov, size_t niov, size_t total)
@@ -40,6 +41,7 @@ writev_for_fatal (int fd, const struct i
 static void
 backtrace_and_maps (int do_abort, bool written, int fd)
 {
+#if __OPTION_EGLIBC_BACKTRACE
   if (do_abort > 1 && written)
     {
       void *addrs[64];
@@ -62,6 +64,7 @@ backtrace_and_maps (int do_abort, bool w
           close_not_cancel_no_status (fd2);
         }
     }
+#endif /* __OPTION_EGLIBC_BACKTRACE */
 }
 #define BEFORE_ABORT		backtrace_and_maps
 
Index: git/time/Makefile
===================================================================
--- git.orig/time/Makefile
+++ git/time/Makefile
@@ -18,6 +18,8 @@
 #
 #	Makefile for time routines
 #
+include ../option-groups.mak
+
 subdir	:= time
 
 include ../Makeconfig
@@ -30,15 +32,23 @@ routines := offtime asctime clock ctime
 	    tzfile getitimer setitimer			 \
 	    stime dysize timegm ftime			 \
 	    getdate strptime strptime_l			 \
-	    strftime wcsftime strftime_l wcsftime_l	 \
+	    strftime strftime_l				 \
 	    timespec_get
-aux :=	    era alt_digit lc-time-cleanup
 
-tests	:= test_time clocktest tst-posixtz tst-strptime tst_wcsftime \
-	   tst-getdate tst-mktime tst-mktime2 tst-ftime_l tst-strftime \
+routines-$(OPTION_POSIX_C_LANG_WIDE_CHAR)                \
+	    := wcsftime wcsftime_l
+aux-$(OPTION_EGLIBC_LOCALE_CODE) += alt_digit era lc-time-cleanup
+
+tests	:= test_time clocktest tst-posixtz \
+	   tst-getdate tst-mktime tst-mktime2 tst-strftime \
 	   tst-mktime3 tst-strptime2 bug-asctime bug-asctime_r bug-mktime1 \
 	   tst-strptime3 bug-getdate1 tst-strptime-whitespace tst-ftime
 
+tests-$(OPTION_EGLIBC_LOCALE_CODE) \
+	        += tst-strptime tst-ftime_l
+tests-$(OPTION_POSIX_WIDE_CHAR_DEVICE_IO) \
+	        += tst_wcsftime
+
 include ../Rules
 
 tz-cflags = -DTZDIR='"$(zonedir)"' \
Index: git/time/strftime_l.c
===================================================================
--- git.orig/time/strftime_l.c
+++ git/time/strftime_l.c
@@ -35,6 +35,10 @@
 # include "../locale/localeinfo.h"
 #endif
 
+#ifdef _LIBC
+# include <gnu/option-groups.h>
+#endif
+
 #if defined emacs && !defined HAVE_BCOPY
 # define HAVE_MEMCPY 1
 #endif
@@ -882,7 +886,7 @@ __strftime_internal (s, maxsize, format,
 	case L_('C'):
 	  if (modifier == L_('E'))
 	    {
-#if HAVE_STRUCT_ERA_ENTRY
+#if (! _LIBC || __OPTION_EGLIBC_LOCALE_CODE) && HAVE_STRUCT_ERA_ENTRY
 	      struct era_entry *era = _nl_get_era_entry (tp HELPER_LOCALE_ARG);
 	      if (era)
 		{
@@ -955,7 +959,7 @@ __strftime_internal (s, maxsize, format,
 
 	  if (modifier == L_('O') && 0 <= number_value)
 	    {
-#ifdef _NL_CURRENT
+#if (! _LIBC || __OPTION_EGLIBC_LOCALE_CODE) && defined (_NL_CURRENT)
 	      /* Get the locale specific alternate representation of
 		 the number NUMBER_VALUE.  If none exist NULL is returned.  */
 	      const CHAR_T *cp = nl_get_alt_digit (number_value
@@ -1260,7 +1264,7 @@ __strftime_internal (s, maxsize, format,
 	case L_('Y'):
 	  if (modifier == 'E')
 	    {
-#if HAVE_STRUCT_ERA_ENTRY
+#if (! _LIBC || __OPTION_EGLIBC_LOCALE_CODE) && HAVE_STRUCT_ERA_ENTRY
 	      struct era_entry *era = _nl_get_era_entry (tp HELPER_LOCALE_ARG);
 	      if (era)
 		{
@@ -1285,7 +1289,7 @@ __strftime_internal (s, maxsize, format,
 	case L_('y'):
 	  if (modifier == L_('E'))
 	    {
-#if HAVE_STRUCT_ERA_ENTRY
+#if (! _LIBC || __OPTION_EGLIBC_LOCALE_CODE) && HAVE_STRUCT_ERA_ENTRY
 	      struct era_entry *era = _nl_get_era_entry (tp HELPER_LOCALE_ARG);
 	      if (era)
 		{
Index: git/time/strptime_l.c
===================================================================
--- git.orig/time/strptime_l.c
+++ git/time/strptime_l.c
@@ -29,6 +29,7 @@
 
 #ifdef _LIBC
 # define HAVE_LOCALTIME_R 0
+# include <gnu/option-groups.h>
 # include "../locale/localeinfo.h"
 #endif
 
@@ -84,7 +85,7 @@ localtime_r (t, tp)
     if (val < from || val > to)						      \
       return NULL;							      \
   } while (0)
-#ifdef _NL_CURRENT
+#if (! _LIBC || __OPTION_EGLIBC_LOCALE_CODE) && defined (_NL_CURRENT)
 # define get_alt_number(from, to, n) \
   ({									      \
      __label__ do_normal;						      \
@@ -257,8 +258,10 @@ __strptime_internal (rp, fmt, tmp, state
   int cnt;
   int cnt_longest;
   size_t val;
+#if ! _LIBC || __OPTION_EGLIBC_LOCALE_CODE
   size_t num_eras;
   struct era_entry *era = NULL;
+#endif
   enum ptime_locale_status { not, loc, raw } decided_longest;
   struct __strptime_state
   {
@@ -820,6 +823,7 @@ __strptime_internal (rp, fmt, tmp, state
 	      s.want_xday = 1;
 	      break;
 	    case 'C':
+#if ! _LIBC || __OPTION_EGLIBC_LOCALE_CODE
 	      if (s.decided != raw)
 		{
 		  if (s.era_cnt >= 0)
@@ -856,10 +860,12 @@ __strptime_internal (rp, fmt, tmp, state
 
 		  s.decided = raw;
 		}
+#endif
 	      /* The C locale has no era information, so use the
 		 normal representation.  */
 	      goto match_century;
  	    case 'y':
+#if ! _LIBC || __OPTION_EGLIBC_LOCALE_CODE
 	      if (s.decided != raw)
 		{
 		  get_number(0, 9999, 4);
@@ -918,9 +924,10 @@ __strptime_internal (rp, fmt, tmp, state
 
 		  s.decided = raw;
 		}
-
+#endif
 	      goto match_year_in_century;
 	    case 'Y':
+#if ! _LIBC || __OPTION_EGLIBC_LOCALE_CODE
 	      if (s.decided != raw)
 		{
 		  num_eras = _NL_CURRENT_WORD (LC_TIME,
@@ -948,6 +955,7 @@ __strptime_internal (rp, fmt, tmp, state
 
 		  s.decided = raw;
 		}
+#endif
 	      get_number (0, 9999, 4);
 	      tm->tm_year = val - 1900;
 	      s.want_century = 0;
@@ -1118,6 +1126,7 @@ __strptime_internal (rp, fmt, tmp, state
 	tm->tm_year = (s.century - 19) * 100;
     }
 
+#if ! _LIBC || __OPTION_EGLIBC_LOCALE_CODE
   if (s.era_cnt != -1)
     {
       era = _nl_select_era_entry (s.era_cnt HELPER_LOCALE_ARG);
@@ -1132,6 +1141,7 @@ __strptime_internal (rp, fmt, tmp, state
 	tm->tm_year = era->start_date[0];
     }
   else
+#endif
     if (s.want_era)
       {
 	/* No era found but we have seen an E modifier.  Rectify some
Index: git/timezone/Makefile
===================================================================
--- git.orig/timezone/Makefile
+++ git/timezone/Makefile
@@ -117,7 +117,7 @@ $(testdata)/Asia/Tokyo: asia $(zic-deps)
 
 $(objpfx)tzselect: tzselect.ksh $(common-objpfx)config.make
 	sed -e 's|/bin/bash|/bin/sh|' \
-	    -e 's|TZDIR=[^}]*|TZDIR=$(zonedir)|' \
+	    -e '/TZDIR=/s|\$$(pwd)|$(zonedir)|' \
 	    -e '/TZVERSION=/s|see_Makefile|"$(version)"|' \
 	    -e '/PKGVERSION=/s|=.*|="$(PKGVERSION)"|' \
 	    -e '/REPORT_BUGS_TO=/s|=.*|="$(REPORT_BUGS_TO)"|' \
Index: git/wcsmbs/Makefile
===================================================================
--- git.orig/wcsmbs/Makefile
+++ git/wcsmbs/Makefile
@@ -18,15 +18,21 @@
 #
 #	Sub-makefile for wcsmbs portion of the library.
 #
+include ../option-groups.mak
+
 subdir	:= wcsmbs
 
 include ../Makeconfig
 
 headers	:= wchar.h bits/wchar.h bits/wchar2.h bits/wchar-ldbl.h uchar.h
 
-routines := wcscat wcschr wcscmp wcscpy wcscspn wcsdup wcslen wcsncat \
+# These functions are used by printf_fp.c, even in the plain case; see
+# comments there for OPTION_EGLIBC_LOCALE_CODE.
+routines  := wmemcpy wmemset
+routines-$(OPTION_POSIX_C_LANG_WIDE_CHAR) \
+	  := wcscat wcschr wcscmp wcscpy wcscspn wcsdup wcslen wcsncat \
 	    wcsncmp wcsncpy wcspbrk wcsrchr wcsspn wcstok wcsstr wmemchr \
-	    wmemcmp wmemcpy wmemmove wmemset wcpcpy wcpncpy wmempcpy \
+	    wmemcmp wmemmove wcpcpy wcpncpy wmempcpy \
 	    btowc wctob mbsinit \
 	    mbrlen mbrtowc wcrtomb mbsrtowcs wcsrtombs \
 	    mbsnrtowcs wcsnrtombs wcsnlen wcschrnul \
@@ -38,14 +44,21 @@ routines := wcscat wcschr wcscmp wcscpy
 	    wcscoll_l wcsxfrm_l \
 	    wcscasecmp wcsncase wcscasecmp_l wcsncase_l \
 	    wcsmbsload mbsrtowcs_l \
-	    isoc99_wscanf isoc99_vwscanf isoc99_fwscanf isoc99_vfwscanf \
 	    isoc99_swscanf isoc99_vswscanf \
 	    mbrtoc16 c16rtomb
 
+routines-$(OPTION_POSIX_WIDE_CHAR_DEVICE_IO)                           \
+	+= isoc99_wscanf isoc99_vwscanf isoc99_fwscanf isoc99_vfwscanf
+
 strop-tests :=  wcscmp wmemcmp wcslen wcschr wcsrchr wcscpy
-tests := tst-wcstof wcsmbs-tst1 tst-wcsnlen tst-btowc tst-mbrtowc \
-	 tst-wcrtomb tst-wcpncpy tst-mbsrtowcs tst-wchar-h tst-mbrtowc2 \
-	 tst-c16c32-1 wcsatcliff $(addprefix test-,$(strop-tests))
+
+tests := tst-wchar-h
+tests-$(OPTION_EGLIBC_LOCALE_CODE) \
+	+= tst-btowc tst-mbrtowc tst-mbrtowc2 tst-wcrtomb tst-c16c32-1
+tests-$(OPTION_POSIX_C_LANG_WIDE_CHAR) \
+	+= tst-wcstof wcsmbs-tst1 tst-wcsnlen \
+	 tst-wcpncpy tst-mbsrtowcs \
+	 wcsatcliff $(addprefix test-,$(strop-tests))
 
 include ../Rules
 
Index: git/wcsmbs/wcsmbsload.c
===================================================================
--- git.orig/wcsmbs/wcsmbsload.c
+++ git/wcsmbs/wcsmbsload.c
@@ -21,6 +21,7 @@
 #include <limits.h>
 #include <stdlib.h>
 #include <string.h>
+#include <gnu/option-groups.h>
 
 #include <locale/localeinfo.h>
 #include <wcsmbsload.h>
@@ -143,6 +144,7 @@ __wcsmbs_getfct (const char *to, const c
   })
 
 
+#if __OPTION_EGLIBC_LOCALE_CODE
 /* Some of the functions here must not be used while setlocale is called.  */
 __libc_rwlock_define (extern, __libc_setlocale_lock attribute_hidden)
 
@@ -211,6 +213,17 @@ __wcsmbs_load_conv (struct __locale_data
 
   __libc_rwlock_unlock (__libc_setlocale_lock);
 }
+#else
+void
+internal_function
+__wcsmbs_load_conv (struct __locale_data *new_category)
+{
+  /* When OPTION_EGLIBC_LOCALE_CODE is disabled, we should never reach
+     this point: there is no way to change locales, so every locale
+     passed to get_gconv_fcts should be _nl_C_LC_CTYPE.  */
+  abort ();
+}
+#endif
 
 
 /* Clone the current conversion function set.  */
Index: git/wctype/Makefile
===================================================================
--- git.orig/wctype/Makefile
+++ git/wctype/Makefile
@@ -18,14 +18,20 @@
 #
 #	Sub-makefile for wctype portion of the library.
 #
+include ../option-groups.mak
+
 subdir	:= wctype
 
 include ../Makeconfig
 
 headers		:= wctype.h
-routines	:= wcfuncs wctype iswctype wctrans towctrans \
-		   wcfuncs_l wctype_l iswctype_l wctrans_l towctrans_l
+routines 	:= wctrans towctrans towctrans_l
+routines-$(OPTION_POSIX_C_LANG_WIDE_CHAR) \
+		:= wcfuncs wctype iswctype \
+		   wcfuncs_l wctype_l iswctype_l wctrans_l
 
-tests	:= test_wctype test_wcfuncs bug-wctypeh
+tests	:=
+tests-$(OPTION_POSIX_C_LANG_WIDE_CHAR) \
+     += test_wctype test_wcfuncs bug-wctypeh
 
 include ../Rules
Index: git/sysdeps/nptl/Makefile
===================================================================
--- git.orig/sysdeps/nptl/Makefile
+++ git/sysdeps/nptl/Makefile
@@ -18,6 +18,9 @@
 
 ifeq ($(subdir),nptl)
 libpthread-sysdep_routines += errno-loc
+ifeq ($(OPTION_EGLIBC_BIG_MACROS),n)
+sysdep_routines += small-macros-fns
+endif
 endif
 
 ifeq ($(subdir),rt)
Index: git/sysdeps/nptl/bits/libc-lock.h
===================================================================
--- git.orig/sysdeps/nptl/bits/libc-lock.h
+++ git/sysdeps/nptl/bits/libc-lock.h
@@ -24,6 +24,14 @@
 #include <stddef.h>
 
 
+#ifdef _LIBC
+# include <lowlevellock.h>
+# include <tls.h>
+# include <pthread-functions.h>
+# include <errno.h> /* For EBUSY.  */
+# include <gnu/option-groups.h> /* For __OPTION_EGLIBC_BIG_MACROS.  */
+#endif
+
 /* Mutex type.  */
 #if defined _LIBC || defined _IO_MTSAFE_IO
 # if (!IS_IN (libc) && !IS_IN (libpthread)) || !defined _LIBC
@@ -87,6 +95,15 @@ typedef struct __libc_lock_recursive_opa
 
 /* Lock the recursive named lock variable.  */
 #if defined _LIBC && (IS_IN (libc) || IS_IN (libpthread))
+# if __OPTION_EGLIBC_BIG_MACROS != 1
+/* EGLIBC: Declare wrapper function for a big macro if either
+   !__OPTION_EGLIBC_BIG_MACROS or we are using a back door from
+   small-macros-fns.c (__OPTION_EGLIBC_BIG_MACROS == 2).  */
+extern void __libc_lock_lock_recursive_fn (__libc_lock_recursive_t *);
+libc_hidden_proto (__libc_lock_lock_recursive_fn);
+# endif /* __OPTION_EGLIBC_BIG_MACROS != 1 */
+# if __OPTION_EGLIBC_BIG_MACROS
+
 # define __libc_lock_lock_recursive(NAME) \
   do {									      \
     void *self = THREAD_SELF;						      \
@@ -97,6 +114,10 @@ typedef struct __libc_lock_recursive_opa
       }									      \
     ++(NAME).cnt;							      \
   } while (0)
+# else
+# define __libc_lock_lock_recursive(NAME)				\
+  __libc_lock_lock_recursive_fn (&(NAME))
+# endif /* __OPTION_EGLIBC_BIG_MACROS */
 #else
 # define __libc_lock_lock_recursive(NAME) \
   __libc_maybe_call (__pthread_mutex_lock, (&(NAME).mutex), 0)
@@ -104,6 +125,14 @@ typedef struct __libc_lock_recursive_opa
 
 /* Try to lock the recursive named lock variable.  */
 #if defined _LIBC && (IS_IN (libc) || IS_IN (libpthread))
+# if __OPTION_EGLIBC_BIG_MACROS != 1
+/* EGLIBC: Declare wrapper function for a big macro if either
+   !__OPTION_EGLIBC_BIG_MACROS or we are using a back door from
+   small-macros-fns.c (__OPTION_EGLIBC_BIG_MACROS == 2).  */
+extern int __libc_lock_trylock_recursive_fn (__libc_lock_recursive_t *);
+libc_hidden_proto (__libc_lock_trylock_recursive_fn);
+# endif /* __OPTION_EGLIBC_BIG_MACROS != 1 */
+# if __OPTION_EGLIBC_BIG_MACROS
 # define __libc_lock_trylock_recursive(NAME) \
   ({									      \
     int result = 0;							      \
@@ -122,6 +151,10 @@ typedef struct __libc_lock_recursive_opa
       ++(NAME).cnt;							      \
     result;								      \
   })
+# else
+# define __libc_lock_trylock_recursive(NAME) \
+  __libc_lock_trylock_recursive_fn (&(NAME))
+# endif /* __OPTION_EGLIBC_BIG_MACROS */
 #else
 # define __libc_lock_trylock_recursive(NAME) \
   __libc_maybe_call (__pthread_mutex_trylock, (&(NAME).mutex), 0)
@@ -129,6 +162,14 @@ typedef struct __libc_lock_recursive_opa
 
 /* Unlock the recursive named lock variable.  */
 #if defined _LIBC && (IS_IN (libc) || IS_IN (libpthread))
+# if __OPTION_EGLIBC_BIG_MACROS != 1
+/* EGLIBC: Declare wrapper function for a big macro if either
+   !__OPTION_EGLIBC_BIG_MACROS, or we are using a back door from
+   small-macros-fns.c (__OPTION_EGLIBC_BIG_MACROS == 2).  */
+extern void __libc_lock_unlock_recursive_fn (__libc_lock_recursive_t *);
+libc_hidden_proto (__libc_lock_unlock_recursive_fn);
+# endif /* __OPTION_EGLIBC_BIG_MACROS != 1 */
+# if __OPTION_EGLIBC_BIG_MACROS
 /* We do no error checking here.  */
 # define __libc_lock_unlock_recursive(NAME) \
   do {									      \
@@ -138,6 +179,10 @@ typedef struct __libc_lock_recursive_opa
 	lll_unlock ((NAME).lock, LLL_PRIVATE);				      \
       }									      \
   } while (0)
+# else
+# define __libc_lock_unlock_recursive(NAME) \
+  __libc_lock_unlock_recursive_fn (&(NAME))
+# endif /* __OPTION_EGLIBC_BIG_MACROS */
 #else
 # define __libc_lock_unlock_recursive(NAME) \
   __libc_maybe_call (__pthread_mutex_unlock, (&(NAME).mutex), 0)
Index: git/sysdeps/nptl/bits/libc-lockP.h
===================================================================
--- git.orig/sysdeps/nptl/bits/libc-lockP.h
+++ git/sysdeps/nptl/bits/libc-lockP.h
@@ -33,6 +33,8 @@
 #include <lowlevellock.h>
 #include <tls.h>
 #include <pthread-functions.h>
+#include <errno.h> /* For EBUSY.  */
+#include <gnu/option-groups.h> /* For __OPTION_EGLIBC_BIG_MACROS.  */
 
 #if IS_IN (libpthread)
 /* This gets us the declarations of the __pthread_* internal names,
@@ -171,10 +173,22 @@ typedef pthread_key_t __libc_key_t;
 
 /* Lock the named lock variable.  */
 #if IS_IN (libc) || IS_IN (libpthread)
-# ifndef __libc_lock_lock
-#  define __libc_lock_lock(NAME) \
+# if __OPTION_EGLIBC_BIG_MACROS != 1
+/* EGLIBC: Declare wrapper function for a big macro if either
+   !__OPTION_EGLIBC_BIG_MACROS or we are using a back door from
+   small-macros-fns.c (__OPTION_EGLIBC_BIG_MACROS == 2).  */
+extern void __libc_lock_lock_fn (__libc_lock_t *);
+libc_hidden_proto (__libc_lock_lock_fn);
+# endif /* __OPTION_EGLIBC_BIG_MACROS != 1 */
+# if __OPTION_EGLIBC_BIG_MACROS
+#  ifndef __libc_lock_lock
+#   define __libc_lock_lock(NAME) \
   ({ lll_lock (NAME, LLL_PRIVATE); 0; })
-# endif
+#  endif
+# else
+#  define __libc_lock_lock(NAME)               \
+  __libc_lock_lock_fn (&(NAME))
+# endif /* __OPTION_EGLIBC_BIG_MACROS */
 #else
 # undef __libc_lock_lock
 # define __libc_lock_lock(NAME) \
@@ -187,10 +201,22 @@ typedef pthread_key_t __libc_key_t;
 
 /* Try to lock the named lock variable.  */
 #if IS_IN (libc) || IS_IN (libpthread)
-# ifndef __libc_lock_trylock
-#  define __libc_lock_trylock(NAME) \
+# if __OPTION_EGLIBC_BIG_MACROS != 1
+/* EGLIBC: Declare wrapper function for a big macro if either
+   !__OPTION_EGLIBC_BIG_MACROS or we are using a back door from
+   small-macros-fns.c (__OPTION_EGLIBC_BIG_MACROS == 2).  */
+extern int __libc_lock_trylock_fn (__libc_lock_t *);
+libc_hidden_proto (__libc_lock_trylock_fn);
+# endif /* __OPTION_EGLIBC_BIG_MACROS != 1 */
+# if __OPTION_EGLIBC_BIG_MACROS
+#  ifndef __libc_lock_trylock
+#   define __libc_lock_trylock(NAME) \
   lll_trylock (NAME)
-# endif
+#  endif
+# else
+# define __libc_lock_trylock(NAME) \
+  __libc_lock_trylock_fn (&(NAME))
+# endif /* __OPTION_EGLIBC_BIG_MACROS */
 #else
 # undef __libc_lock_trylock
 # define __libc_lock_trylock(NAME) \
@@ -206,8 +232,20 @@ typedef pthread_key_t __libc_key_t;
 
 /* Unlock the named lock variable.  */
 #if IS_IN (libc) || IS_IN (libpthread)
+# if __OPTION_EGLIBC_BIG_MACROS != 1
+/* EGLIBC: Declare wrapper function for a big macro if either
+   !__OPTION_EGLIBC_BIG_MACROS, or we are using a back door from
+   small-macros-fns.c (__OPTION_EGLIBC_BIG_MACROS == 2).  */
+extern void __libc_lock_unlock_fn (__libc_lock_t *);
+libc_hidden_proto (__libc_lock_unlock_fn);
+# endif /* __OPTION_EGLIBC_BIG_MACROS != 1 */
+# if __OPTION_EGLIBC_BIG_MACROS
 # define __libc_lock_unlock(NAME) \
   lll_unlock (NAME, LLL_PRIVATE)
+# else
+# define __libc_lock_unlock(NAME) \
+  __libc_lock_unlock_fn (&(NAME))
+# endif /* __OPTION_EGLIBC_BIG_MACROS */
 #else
 # define __libc_lock_unlock(NAME) \
   __libc_maybe_call (__pthread_mutex_unlock, (&(NAME)), 0)
Index: git/sysdeps/nptl/small-macros-fns.c
===================================================================
--- /dev/null
+++ git/sysdeps/nptl/small-macros-fns.c
@@ -0,0 +1,72 @@
+/* EGLIBC: function wrappers for big macros.
+   Copyright (C) 2009 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public License as
+   published by the Free Software Foundation; either version 2.1 of the
+   License, or (at your option) any later version.
+
+   The GNU C Library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with the GNU C Library; 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 <gnu/option-groups.h>
+
+/* Handle macros from ./bits/libc-lock.h.  */
+#if defined _LIBC && (!defined NOT_IN_libc || defined IS_IN_libpthread)
+
+/* Get the macros for function bodies through a back door.  */
+# undef __OPTION_EGLIBC_BIG_MACROS
+# define __OPTION_EGLIBC_BIG_MACROS 2
+# include <bits/libc-lock.h>
+
+void
+__libc_lock_lock_fn (__libc_lock_t *name)
+{
+  __libc_lock_lock (*name);
+}
+libc_hidden_def (__libc_lock_lock_fn);
+
+void
+__libc_lock_lock_recursive_fn (__libc_lock_recursive_t *name)
+{
+  __libc_lock_lock_recursive (*name);
+}
+libc_hidden_def (__libc_lock_lock_recursive_fn);
+
+int
+__libc_lock_trylock_fn (__libc_lock_t *name)
+{
+  return __libc_lock_trylock (*name);
+}
+libc_hidden_def (__libc_lock_trylock_fn);
+
+int
+__libc_lock_trylock_recursive_fn (__libc_lock_recursive_t *name)
+{
+  return __libc_lock_trylock_recursive (*name);
+}
+libc_hidden_def (__libc_lock_trylock_recursive_fn);
+
+void
+__libc_lock_unlock_fn (__libc_lock_t *name)
+{
+  __libc_lock_unlock (*name);
+}
+libc_hidden_def (__libc_lock_unlock_fn);
+
+void
+__libc_lock_unlock_recursive_fn (__libc_lock_recursive_t *name)
+{
+  __libc_lock_unlock_recursive (*name);
+}
+libc_hidden_def (__libc_lock_unlock_recursive_fn);
+
+#endif /*defined _LIBC && (!defined NOT_IN_libc || defined IS_IN_libpthread)*/
Index: git/crypt/crypt_common.c
===================================================================
--- /dev/null
+++ git/crypt/crypt_common.c
@@ -0,0 +1,42 @@
+/*
+ * crypt: crypt(3) implementation
+ *
+ * Copyright (C) 1991-2014 Free Software Foundation, Inc.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; see the file COPYING.LIB.  If not,
+ * see <http://www.gnu.org/licenses/>.
+ *
+ * General Support routines
+ *
+ */
+
+#include "crypt-private.h"
+
+/* Table with characters for base64 transformation.  */
+static const char b64t[64] =
+"./0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz";
+
+void
+__b64_from_24bit (char **cp, int *buflen,
+		  unsigned int b2, unsigned int b1, unsigned int b0,
+		  int n)
+{
+  unsigned int w = (b2 << 16) | (b1 << 8) | b0;
+  while (n-- > 0 && (*buflen) > 0)
+    {
+      *(*cp)++ = b64t[w & 0x3f];
+      --(*buflen);
+      w >>= 6;
+    }
+}
Index: git/crypt/crypt_util.c
===================================================================
--- git.orig/crypt/crypt_util.c
+++ git/crypt/crypt_util.c
@@ -242,10 +242,6 @@ static ufc_long eperm32tab[4][256][2];
  */
 static ufc_long efp[16][64][2];
 
-/* Table with characters for base64 transformation.  */
-static const char b64t[64] =
-"./0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz";
-
 /*
  * For use by the old, non-reentrant routines
  * (crypt/encrypt/setkey)
@@ -949,17 +945,3 @@ setkey(__key)
 {
   __setkey_r(__key, &_ufc_foobar);
 }
-
-void
-__b64_from_24bit (char **cp, int *buflen,
-		  unsigned int b2, unsigned int b1, unsigned int b0,
-		  int n)
-{
-  unsigned int w = (b2 << 16) | (b1 << 8) | b0;
-  while (n-- > 0 && (*buflen) > 0)
-    {
-      *(*cp)++ = b64t[w & 0x3f];
-      --(*buflen);
-      w >>= 6;
-    }
-}
Index: git/sysdeps/arm/Makefile
===================================================================
--- git.orig/sysdeps/arm/Makefile
+++ git/sysdeps/arm/Makefile
@@ -37,10 +37,13 @@ ifeq ($(subdir),csu)
 # get offset to rtld_global._dl_hwcap
 gen-as-const-headers += rtld-global-offsets.sym tlsdesc.sym
 aeabi_constants = aeabi_lcsts aeabi_sighandlers aeabi_math
-aeabi_routines = aeabi_assert aeabi_localeconv aeabi_errno_addr \
+aeabi_routines = aeabi_assert aeabi_errno_addr \
 		 aeabi_mb_cur_max aeabi_atexit aeabi_memclr aeabi_memcpy \
 		 aeabi_memmove aeabi_memset \
 		 aeabi_read_tp libc-aeabi_read_tp
+ifeq (y,$(OPTION_EGLIBC_LOCALE_CODE))
+aeabi_routines += aeabi_localeconv
+endif
 
 sysdep_routines += $(aeabi_constants) $(aeabi_routines)
 static-only-routines += $(aeabi_constants) aeabi_read_tp
