aboutsummaryrefslogtreecommitdiffstats
path: root/meta/recipes-core/glibc/glibc/eglibc-use-option-groups.patch
diff options
context:
space:
mode:
Diffstat (limited to 'meta/recipes-core/glibc/glibc/eglibc-use-option-groups.patch')
-rw-r--r--meta/recipes-core/glibc/glibc/eglibc-use-option-groups.patch16631
1 files changed, 16631 insertions, 0 deletions
diff --git a/meta/recipes-core/glibc/glibc/eglibc-use-option-groups.patch b/meta/recipes-core/glibc/glibc/eglibc-use-option-groups.patch
new file mode 100644
index 0000000000..f53a8994fc
--- /dev/null
+++ b/meta/recipes-core/glibc/glibc/eglibc-use-option-groups.patch
@@ -0,0 +1,16631 @@
+Forward port eglibc options groups support
+
+Upstream-Status: Pending
+
+Index: git/argp/argp-fmtstream.c
+===================================================================
+--- git.orig/argp/argp-fmtstream.c 2014-08-29 20:00:42.976070587 -0700
++++ git/argp/argp-fmtstream.c 2014-08-29 20:01:15.188070587 -0700
+@@ -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_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 @@
+ 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 @@
+ *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 2014-08-29 20:00:42.976070587 -0700
++++ git/argp/argp-help.c 2014-08-29 20:01:15.188070587 -0700
+@@ -51,6 +51,7 @@
+ #ifdef _LIBC
+ # include <../libio/libioP.h>
+ # include <wchar.h>
++# include <gnu/option-groups.h>
+ #endif
+
+ #ifndef _
+@@ -1702,7 +1703,7 @@
+ }
+
+ 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 @@
+ #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 2014-08-29 20:00:42.976070587 -0700
++++ git/argp/argp-namefrob.h 2014-08-29 20:01:15.192070587 -0700
+@@ -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 2014-08-29 20:00:42.976070587 -0700
++++ git/argp/Makefile 2014-08-29 20:01:15.192070587 -0700
+@@ -18,6 +18,8 @@
+ #
+ # Makefile for argp.
+ #
++include ../option-groups.mak
++
+ subdir := argp
+
+ include ../Makeconfig
+Index: git/catgets/Makefile
+===================================================================
+--- git.orig/catgets/Makefile 2014-08-29 20:00:43.008070587 -0700
++++ git/catgets/Makefile 2014-08-29 20:01:15.192070587 -0700
+@@ -22,20 +22,23 @@
+
+ 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 2014-08-29 20:00:43.028070587 -0700
++++ git/crypt/crypt-entry.c 2014-08-29 20:01:15.192070587 -0700
+@@ -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 @@
+ 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 @@
+ sizeof (struct crypt_data));
+ #endif
+
++#if __OPTION_EGLIBC_CRYPT_UFC
+ /*
+ * Hack DES tables according to salt
+ */
+@@ -144,6 +148,10 @@
+ */
+ _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 @@
+ 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 2014-08-29 20:00:43.024070587 -0700
++++ git/crypt/Makefile 2014-08-29 20:01:15.192070587 -0700
+@@ -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 @@
+ 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)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 2014-08-29 20:00:43.032070587 -0700
++++ git/csu/Makefile 2014-08-29 20:01:15.192070587 -0700
+@@ -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 2014-08-29 20:00:43.036070587 -0700
++++ git/debug/Makefile 2014-08-29 20:01:15.192070587 -0700
+@@ -18,6 +18,8 @@
+ #
+ # Sub-makefile for debug portion of the library.
+ #
++include ../option-groups.mak
++
+ subdir := debug
+
+ include ../Makeconfig
+@@ -27,7 +29,7 @@
+ # 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 @@
+ 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
+@@ -129,11 +138,15 @@
+ 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
+
+ tests-ifunc := $(stpcpy_chk strcpy_chk:%=test-%-ifunc)
+ tests += $(tests-ifunc)
+Index: git/debug/segfault.c
+===================================================================
+--- git.orig/debug/segfault.c 2014-08-29 20:00:46.280070587 -0700
++++ git/debug/segfault.c 2014-08-29 20:01:15.192070587 -0700
+@@ -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. */
+@@ -91,6 +92,7 @@
+ REGISTER_DUMP;
+ #endif
+
++#if __OPTION_EGLIBC_BACKTRACE
+ WRITE_STRING ("\nBacktrace:\n");
+
+ /* Get the backtrace. */
+@@ -113,6 +115,7 @@
+
+ /* 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 2014-08-29 20:00:46.288070587 -0700
++++ git/debug/tst-chk1.c 2014-08-29 20:01:15.192070587 -0700
+@@ -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 @@
+ 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 @@
+ 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 @@
+ 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 @@
+ CHK_FAIL_END
+ #endif
+
++#endif /* __OPTION_POSIX_C_LANG_WIDE_CHAR */
+
+ /* Now checks for %n protection. */
+
+@@ -1192,6 +1197,7 @@
+ # 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 @@
+ 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 2014-08-29 20:00:46.312070587 -0700
++++ git/dlfcn/Makefile 2014-08-29 20:01:15.192070587 -0700
+@@ -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,7 +38,9 @@
+ 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
++ tstatexit bug-dl-leaf
++
++tests-$(OPTION_EGLIBC_CXX_TESTS) += bug-atexit3
+ endif
+ modules-names = glreflib1 glreflib2 glreflib3 failtestmod defaultmod1 \
+ defaultmod2 errmsg1mod modatexit modcxaatexit \
+Index: git/elf/dl-support.c
+===================================================================
+--- git.orig/elf/dl-support.c 2014-08-29 20:00:46.384070587 -0700
++++ git/elf/dl-support.c 2014-08-29 20:01:15.192070587 -0700
+@@ -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 @@
+ 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 2014-08-29 20:01:14.708070587 -0700
++++ git/elf/rtld.c 2014-08-29 20:01:15.196070587 -0700
+@@ -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 @@
+ 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 @@
+ _exit (0);
+ }
+ }
++#endif /* __OPTION_EGLIBC_RTLD_DEBUG */
+
+ static void
+ process_dl_audit (char *str)
+@@ -2376,12 +2379,14 @@
+ 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;
+@@ -2490,7 +2495,9 @@
+ {
+ 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 +2544,15 @@
+ 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 +2577,7 @@
+ /* 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 2014-08-29 20:00:46.544070587 -0700
++++ git/extra-lib.mk 2014-08-29 20:01:15.196070587 -0700
+@@ -25,7 +25,9 @@
+ 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
+
+ # 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 2014-08-29 20:00:46.556070587 -0700
++++ git/grp/Makefile 2014-08-29 20:01:15.196070587 -0700
+@@ -18,6 +18,8 @@
+ #
+ # Sub-makefile for grp portion of the library.
+ #
++include ../option-groups.mak
++
+ subdir := grp
+
+ include ../Makeconfig
+@@ -29,6 +31,9 @@
+ 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 2014-08-29 20:00:46.580070587 -0700
++++ git/hesiod/Makefile 2014-08-29 20:01:15.196070587 -0700
+@@ -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 2014-08-29 20:00:46.604070587 -0700
++++ git/iconv/gconv_db.c 2014-08-29 20:01:15.196070587 -0700
+@@ -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 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 2014-08-29 20:00:46.612070587 -0700
++++ git/iconv/gconv_trans.c 2014-08-29 20:01:15.196070587 -0700
+@@ -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"
+@@ -59,6 +60,7 @@
+ 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);
+@@ -194,6 +196,7 @@
+ 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 2014-08-29 20:00:46.612070587 -0700
++++ git/iconv/iconv_prog.c 2014-08-29 20:01:15.196070587 -0700
+@@ -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 @@
+ 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 2014-08-29 20:00:46.600070587 -0700
++++ git/iconv/Makefile 2014-08-29 20:01:15.196070587 -0700
+@@ -18,6 +18,8 @@
+ #
+ # Makefile for iconv.
+ #
++include ../option-groups.mak
++
+ subdir := iconv
+
+ include ../Makeconfig
+@@ -57,6 +59,9 @@
+ CPPFLAGS-strtab = -DNOT_IN_libc
+ CPPFLAGS-charmap = -DNOT_IN_libc
+ CPPFLAGS-charmap-dir = -DNOT_IN_libc
++ifneq (y,$(OPTION_EGLIBC_SPAWN))
++CPPFLAGS-charmap-dir.c += -DNO_UNCOMPRESS
++endif
+
+ ifeq ($(run-built-tests),yes)
+ xtests-special += $(objpfx)test-iconvconfig.out
+Index: git/iconvdata/Makefile
+===================================================================
+--- git.orig/iconvdata/Makefile 2014-08-29 20:00:46.628070587 -0700
++++ git/iconvdata/Makefile 2014-08-29 20:01:15.196070587 -0700
+@@ -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 @@
+ 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
+@@ -130,13 +135,13 @@
+ # 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.
+
+@@ -204,7 +209,7 @@
+ 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 \
+@@ -247,7 +252,7 @@
+ $(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 \
+@@ -256,9 +261,9 @@
+ $(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 2014-08-29 20:00:47.152070587 -0700
++++ git/include/netdb.h 2014-08-29 20:01:15.196070587 -0700
+@@ -232,6 +232,10 @@
+ (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 2014-08-29 20:00:47.176070587 -0700
++++ git/inet/Makefile 2014-08-29 20:01:15.200070587 -0700
+@@ -18,6 +18,8 @@
+ #
+ # Sub-makefile for inet portion of the library.
+ #
++include ../option-groups.mak
++
+ subdir := inet
+
+ include ../Makeconfig
+@@ -27,7 +29,8 @@
+ 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 @@
+ 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 2014-08-29 20:00:47.224070587 -0700
++++ git/intl/dcigettext.c 2014-08-29 20:01:15.200070587 -0700
+@@ -77,6 +77,10 @@
+ #endif
+ #include "hash-string.h"
+
++#ifdef _LIBC
++# include <gnu/option-groups.h>
++#endif
++
+ /* Thread safetyness. */
+ #ifdef _LIBC
+ # include <bits/libc-lock.h>
+@@ -449,9 +453,11 @@
+ #endif
+
+ #ifdef _LIBC
++#if __OPTION_EGLIBC_LOCALE_CODE
+ __libc_rwlock_define (extern, __libc_setlocale_lock attribute_hidden)
+ __libc_rwlock_rdlock (__libc_setlocale_lock);
+ #endif
++#endif
+
+ __libc_rwlock_rdlock (_nl_state_lock);
+
+@@ -470,7 +476,11 @@
+ search.category = category;
+ # ifdef HAVE_PER_THREAD_LOCALE
+ # ifdef _LIBC
++# if __OPTION_EGLIBC_LOCALE_CODE
+ localename = strdupa (__current_locale_name (category));
++# else
++ localename = "C";
++# endif
+ # endif
+ search.localename = localename;
+ # endif
+@@ -494,7 +504,9 @@
+ retval = (char *) (*foundp)->translation;
+
+ # ifdef _LIBC
++#if __OPTION_EGLIBC_LOCALE_CODE
+ __libc_rwlock_unlock (__libc_setlocale_lock);
++#endif
+ # endif
+ __libc_rwlock_unlock (_nl_state_lock);
+ return retval;
+@@ -611,7 +623,9 @@
+ {
+ no_translation:
+ FREE_BLOCKS (block_list);
++#if __OPTION_EGLIBC_LOCALE_CODE
+ __libc_rwlock_unlock (__libc_setlocale_lock);
++#endif
+ __libc_rwlock_unlock (_nl_state_lock);
+ __set_errno (saved_errno);
+ return (plural == 0
+@@ -730,7 +744,9 @@
+ if (plural)
+ retval = plural_lookup (domain, n, retval, retlen);
+
++#if __OPTION_EGLIBC_LOCALE_CODE
+ __libc_rwlock_unlock (__libc_setlocale_lock);
++#endif
+ __libc_rwlock_unlock (_nl_state_lock);
+ return retval;
+ }
+@@ -1361,7 +1377,11 @@
+ `LC_xxx', and `LANG'. On some systems this can be done by the
+ `setlocale' function itself. */
+ #ifdef _LIBC
++# if __OPTION_EGLIBC_LOCALE_CODE
+ retval = __current_locale_name (category);
++# else
++ retval = "C";
++# endif
+ #else
+ retval = _nl_locale_name (category, categoryname);
+ #endif
+Index: git/intl/Makefile
+===================================================================
+--- git.orig/intl/Makefile 2014-08-29 20:00:47.220070587 -0700
++++ git/intl/Makefile 2014-08-29 20:01:15.200070587 -0700
+@@ -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 @@
+ $(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 2014-08-29 20:00:47.244070587 -0700
++++ git/io/Makefile 2014-08-29 20:01:15.200070587 -0700
+@@ -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 @@
+ 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 @@
+ 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 @@
+ 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 2014-08-29 20:00:47.316070587 -0700
++++ git/libidn/Makefile 2014-08-29 20:01:15.200070587 -0700
+@@ -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 @@
+
+ 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 2014-08-29 20:00:47.332070587 -0700
++++ git/libidn/toutf8.c 2014-08-29 20:01:15.200070587 -0700
+@@ -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 2014-08-29 20:00:47.352070587 -0700
++++ git/libio/fileops.c 2014-08-29 20:01:15.200070587 -0700
+@@ -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"
+@@ -174,7 +175,7 @@
+
+ /* 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);
+@@ -359,6 +360,7 @@
+ 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;
+@@ -423,6 +425,12 @@
+
+ /* 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 2014-08-29 20:00:47.336070587 -0700
++++ git/libio/__fpurge.c 2014-08-29 20:01:15.200070587 -0700
+@@ -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 2014-08-29 20:00:47.360070587 -0700
++++ git/libio/iofwide.c 2014-08-29 20:01:15.200070587 -0700
+@@ -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,
+@@ -513,3 +516,26 @@
+ 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 2014-08-29 20:00:47.364070587 -0700
++++ git/libio/ioseekoff.c 2014-08-29 20:01:15.200070587 -0700
+@@ -60,7 +60,7 @@
+ 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 2014-08-29 20:00:47.364070587 -0700
++++ git/libio/ioseekpos.c 2014-08-29 20:01:15.200070587 -0700
+@@ -35,7 +35,7 @@
+ /* 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 2014-08-29 20:00:47.364070587 -0700
++++ git/libio/iosetbuffer.c 2014-08-29 20:01:15.204070587 -0700
+@@ -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 @@
+ 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 2014-08-29 20:00:47.372070587 -0700
++++ git/libio/libioP.h 2014-08-29 20:01:15.204070587 -0700
+@@ -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 @@
+
+
+ #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 2014-08-29 20:00:47.332070587 -0700
++++ git/libio/Makefile 2014-08-29 20:01:15.204070587 -0700
+@@ -18,6 +18,8 @@
+ #
+ # Specific makefile for libio.
+ #
++include ../option-groups.mak
++
+ subdir := libio
+
+ include ../Makeconfig
+@@ -27,16 +29,13 @@
+
+ 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 \
+@@ -47,25 +46,48 @@
+ __fpurge __fpending __fsetlocking \
+ \
+ 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 \
+- 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-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
++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-ungetc2 bug-ungetc3 bug-ungetc4 \
++ tst-memstream1 tst-memstream2 \
++ 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
++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 +186,17 @@
+ 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 1970-01-01 00:00:00.000000000 +0000
++++ git/libio/wdummyfileops.c 2014-08-29 20:01:15.204070587 -0700
+@@ -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 1970-01-01 00:00:00.000000000 +0000
++++ git/locale/catnames.c 2014-08-29 20:01:15.204070587 -0700
+@@ -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 2014-08-29 20:00:47.396070587 -0700
++++ git/locale/C-ctype.c 2014-08-29 20:01:15.204070587 -0700
+@@ -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 @@
+ { .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 @@
+ { .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 1970-01-01 00:00:00.000000000 +0000
++++ git/locale/dummy-setlocale.c 2014-08-29 20:01:15.204070587 -0700
+@@ -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 2014-08-29 20:00:47.404070587 -0700
++++ git/locale/localeinfo.h 2014-08-29 20:01:15.204070587 -0700
+@@ -224,7 +224,7 @@
+ 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 2014-08-29 20:00:47.400070587 -0700
++++ git/locale/Makefile 2014-08-29 20:01:15.204070587 -0700
+@@ -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
+
+@@ -94,6 +110,9 @@
+ 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
+
+ # This makes sure -DNOT_IN_libc et al are passed for all these modules.
+ cpp-srcs-left := $(addsuffix .c,$(localedef-modules) $(localedef-aux) \
+Index: git/locale/programs/charmap-dir.c
+===================================================================
+--- git.orig/locale/programs/charmap-dir.c 2014-08-29 20:00:47.408070587 -0700
++++ git/locale/programs/charmap-dir.c 2014-08-29 20:01:15.204070587 -0700
+@@ -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 @@
+ 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 @@
+ }
+ return NULL;
+ }
++#endif
+
+ /* Opens a charmap for reading, given its name (not an alias name). */
+ FILE *
+@@ -226,6 +230,7 @@
+ if (stream != NULL)
+ return stream;
+
++#ifndef NO_UNCOMPRESS
+ memcpy (p, ".gz", 4);
+ stream = fopen_uncompressed (pathname, "gzip");
+ if (stream != NULL)
+@@ -235,6 +240,7 @@
+ stream = fopen_uncompressed (pathname, "bzip2");
+ if (stream != NULL)
+ return stream;
++#endif
+
+ return NULL;
+ }
+@@ -263,8 +269,8 @@
+ char *alias = NULL;
+ char junk[BUFSIZ];
+
+- if (fscanf (stream, " <code_set_name> %ms", &alias) == 1
+- || fscanf (stream, "%% alias %ms", &alias) == 1)
++ if (fscanf (stream, " <code_set_name> %as", &alias) == 1
++ || fscanf (stream, "%% alias %as", &alias) == 1)
+ {
+ aliases = (char **) xrealloc (aliases,
+ (naliases + 2) * sizeof (char *));
+Index: git/locale/programs/ld-collate.c
+===================================================================
+--- git.orig/locale/programs/ld-collate.c 2014-08-29 20:00:47.408070587 -0700
++++ git/locale/programs/ld-collate.c 2014-08-29 20:01:15.208070587 -0700
+@@ -350,7 +350,7 @@
+ }
+ 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 @@
+
+ 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 @@
+ 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 @@
+ 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 2014-08-29 20:00:47.408070587 -0700
++++ git/locale/programs/ld-ctype.c 2014-08-29 20:01:15.208070587 -0700
+@@ -957,7 +957,7 @@
+ 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);
+@@ -1968,7 +1968,7 @@
+ 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;
+ }
+@@ -2516,8 +2516,8 @@
+ }
+
+ 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;
+
+@@ -4001,8 +4001,7 @@
+
+ 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;
+@@ -4039,11 +4038,11 @@
+ for (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
+@@ -4067,18 +4066,18 @@
+ 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 2014-08-29 20:00:47.412070587 -0700
++++ git/locale/programs/ld-messages.c 2014-08-29 20:01:15.208070587 -0700
+@@ -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 @@
+ }
+ else
+ {
++#if __OPTION_POSIX_REGEXP
+ int result;
+ regex_t re;
+
+@@ -140,6 +142,7 @@
+ }
+ else if (result != 0)
+ regfree (&re);
++#endif
+ }
+
+ if (messages->noexpr == NULL)
+@@ -158,6 +161,7 @@
+ }
+ else
+ {
++#if __OPTION_POSIX_REGEXP
+ int result;
+ regex_t re;
+
+@@ -174,6 +178,7 @@
+ }
+ else if (result != 0)
+ regfree (&re);
++#endif
+ }
+ }
+
+Index: git/locale/programs/ld-time.c
+===================================================================
+--- git.orig/locale/programs/ld-time.c 2014-08-29 20:00:47.412070587 -0700
++++ git/locale/programs/ld-time.c 2014-08-29 20:01:15.208070587 -0700
+@@ -215,8 +215,10 @@
+ }
+ 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 @@
+ 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 @@
+ }
+
+ /* 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 @@
+ 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 2014-08-29 20:00:47.412070587 -0700
++++ git/locale/programs/linereader.c 2014-08-29 20:01:15.208070587 -0700
+@@ -595,7 +595,7 @@
+ {
+ 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 2014-08-29 20:00:47.416070587 -0700
++++ git/locale/programs/localedef.c 2014-08-29 20:01:15.208070587 -0700
+@@ -114,6 +114,7 @@
+ #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 @@
+ 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 @@
+ 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 @@
+ 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 2014-08-29 20:00:47.432070587 -0700
++++ git/locale/programs/locfile.c 2014-08-29 20:01:15.208070587 -0700
+@@ -544,6 +544,9 @@
+ 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 @@
+ 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 2014-08-29 20:00:47.432070587 -0700
++++ git/locale/programs/locfile.h 2014-08-29 20:01:15.208070587 -0700
+@@ -71,6 +71,8 @@
+
+ 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
+@@ -275,4 +277,49 @@
+ const struct charmap_t *charmap,
+ const char *output_path);
+
++static inline size_t
++wcslen_uint32 (const uint32_t *str)
++{
++ size_t len = 0;
++ while (str[len] != 0)
++ len++;
++ return len;
++}
++
++static inline 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 inline int
++wcscmp_uint32 (const uint32_t *s1, const uint32_t *s2)
++{
++ while (*s1 != 0 && *s1 == *s2)
++ s1++, s2++;
++ return *s1 - *s2;
++}
++
++static inline uint32_t *
++wmemcpy_uint32 (uint32_t *s1, const uint32_t *s2, size_t n)
++{
++ return memcpy (s1, s2, n * sizeof (uint32_t));
++}
++
++static inline 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 2014-08-29 20:00:47.432070587 -0700
++++ git/locale/setlocale.c 2014-08-29 20:01:15.208070587 -0700
+@@ -64,36 +64,6 @@
+ #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 2014-08-29 20:00:47.436070587 -0700
++++ git/locale/xlocale.c 2014-08-29 20:01:15.208070587 -0700
+@@ -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 @@
+ #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 @@
+ .__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 2014-08-29 20:00:47.444070587 -0700
++++ git/localedata/Makefile 2014-08-29 20:01:15.212070587 -0700
+@@ -21,12 +21,22 @@
+
+ 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 @@
+ 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
+@@ -92,12 +108,14 @@
+
+ tests: $(objdir)/iconvdata/gconv-modules
+
++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 \
+ $(objpfx)tst-langinfo.out $(objpfx)tst-langinfo-static.out \
+ $(objpfx)tst-numeric.out
+ tests-static += tst-langinfo-static
++endif
+
+ ifeq ($(run-built-tests),yes)
+ # We have to generate locales
+@@ -143,9 +161,13 @@
+ $(addprefix $(objpfx),$(CTYPE_FILES)): %: \
+ gen-locale.sh $(common-objpfx)locale/localedef Makefile \
+ $(addprefix charmaps/,$(CHARMAPS)) $(addprefix locales/,$(LOCALE_SRCS))
+- @$(SHELL) gen-locale.sh $(common-objpfx) \
+- '$(built-program-cmd-before-env)' '$(run-program-env)' \
+- '$(built-program-cmd-after-env)' $@; \
++ @$(SHELL) gen-locale.sh $(common-objpfx) \
++ '$(if $(cross-localedef), \
++ $(cross-localedef), \
++ $(built-program-cmd-before-env) \
++ $(run-program-env) \
++ $(built-program-cmd-after-env))' \
++ $@; \
+ $(evaluate-test)
+
+ $(addsuffix .out,$(addprefix $(objpfx),$(tests))): %: \
+@@ -213,6 +235,11 @@
+
+ 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 2014-08-29 20:00:47.736070587 -0700
++++ git/login/Makefile 2014-08-29 20:01:15.212070587 -0700
+@@ -18,6 +18,7 @@
+ #
+ # Sub-makefile for login portion of the library.
+ #
++include ../option-groups.mak
+
+ subdir := login
+
+@@ -25,14 +26,16 @@
+
+ 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 @@
+ 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 2014-08-29 20:00:42.956070587 -0700
++++ git/Makeconfig 2014-08-29 20:01:15.212070587 -0700
+@@ -582,7 +582,7 @@
+ # 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.
+@@ -1057,6 +1057,24 @@
+ 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 2014-08-29 20:00:42.960070587 -0700
++++ git/Makerules 2014-08-29 20:01:15.212070587 -0700
+@@ -379,6 +379,25 @@
+ 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 2014-08-29 20:00:47.760070587 -0700
++++ git/malloc/Makefile 2014-08-29 20:01:15.212070587 -0700
+@@ -18,6 +18,8 @@
+ #
+ # Makefile for malloc routines
+ #
++include ../option-groups.mak
++
+ subdir := malloc
+
+ include ../Makeconfig
+@@ -36,9 +38,15 @@
+ 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))
+
+@@ -67,7 +75,7 @@
+ # 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 2014-08-29 20:00:47.768070587 -0700
++++ git/malloc/memusage.c 2014-08-29 20:01:15.212070587 -0700
+@@ -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 @@
+ #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 2014-08-29 20:00:47.768070587 -0700
++++ git/malloc/memusage.sh 2014-08-29 20:01:15.212070587 -0700
+@@ -35,7 +35,7 @@
+
+ # 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 2014-08-29 20:00:47.836070587 -0700
++++ git/math/Makefile 2014-08-29 20:01:15.212070587 -0700
+@@ -21,6 +21,8 @@
+
+ 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 @@
+
+ # 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 = k_standard s_lib_version s_matherr s_signgam \
+ fclrexcpt fgetexcptflg fraiseexcpt fsetexcptflg \
+Index: git/misc/err.c
+===================================================================
+--- git.orig/misc/err.c 2014-08-29 20:00:48.232070587 -0700
++++ git/misc/err.c 2014-08-29 20:01:15.212070587 -0700
+@@ -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 @@
+ 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 @@
+
+ __vfwprintf (stderr, wformat, ap);
+ }
++#endif
+
+ void
+ vwarnx (const char *format, __gnuc_va_list ap)
+@@ -88,9 +91,13 @@
+ 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 @@
+ 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 @@
+ }
+ __set_errno (error);
+ __fwprintf (stderr, L"%m\n");
++#else
++ abort ();
++#endif
+ }
+ else
+ {
+Index: git/misc/error.c
+===================================================================
+--- git.orig/misc/error.c 2014-08-29 20:00:48.232070587 -0700
++++ git/misc/error.c 2014-08-29 20:01:15.212070587 -0700
+@@ -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 @@
+ #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 @@
+
+ if (use_malloc)
+ free (wmessage);
++#else
++ abort ();
++#endif
+ }
+ else
+ #endif
+Index: git/misc/Makefile
+===================================================================
+--- git.orig/misc/Makefile 2014-08-29 20:00:48.232070587 -0700
++++ git/misc/Makefile 2014-08-29 20:01:15.212070587 -0700
+@@ -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 @@
+ 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/sys/xattr.h
+===================================================================
+--- git.orig/misc/sys/xattr.h 2014-08-29 20:00:52.644070587 -0700
++++ git/misc/sys/xattr.h 2014-08-29 20:01:15.216070587 -0700
+@@ -26,7 +26,6 @@
+
+ /* The following constants should be used for the fifth parameter of
+ `*setxattr'. */
+-#ifndef __USE_KERNEL_XATTR_DEFS
+ enum
+ {
+ XATTR_CREATE = 1, /* set value, fail if attr already exists. */
+@@ -34,7 +33,6 @@
+ XATTR_REPLACE = 2 /* set value, fail if attr does not exist. */
+ #define XATTR_REPLACE XATTR_REPLACE
+ };
+-#endif
+
+ /* Set the attribute NAME of the file pointed to by PATH to VALUE (which
+ is SIZE bytes long). Return 0 on success, -1 for errors. */
+Index: git/misc/tst-efgcvt.c
+===================================================================
+--- git.orig/misc/tst-efgcvt.c 2014-08-29 20:00:52.652070587 -0700
++++ git/misc/tst-efgcvt.c 2014-08-29 20:01:15.216070587 -0700
+@@ -59,7 +59,7 @@
+ { 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 2014-08-29 20:00:52.660070587 -0700
++++ git/nis/Makefile 2014-08-29 20:01:15.216070587 -0700
+@@ -18,6 +18,8 @@
+ #
+ # Makefile for NIS/NIS+ part.
+ #
++include ../option-groups.mak
++
+ subdir := nis
+
+ include ../Makeconfig
+@@ -30,19 +32,26 @@
+
+ # 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 @@
+ 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 @@
+ # 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 2014-08-29 20:00:52.704070587 -0700
++++ git/nptl/Makefile 2014-08-29 20:01:15.216070587 -0700
+@@ -18,6 +18,8 @@
+ #
+ # Sub-makefile for NPTL portion of the library.
+ #
++include ../option-groups.mak
++
+ subdir := nptl
+
+ include ../Makeconfig
+@@ -116,7 +118,7 @@
+ 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 \
+@@ -136,6 +138,8 @@
+ # 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
+
+@@ -210,7 +214,7 @@
+ 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 \
+@@ -244,14 +248,14 @@
+ 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-pthread-getattr \
+@@ -259,13 +263,12 @@
+ 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 \
+@@ -275,6 +278,17 @@
+ 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 2014-08-29 20:00:52.764070587 -0700
++++ git/nptl/pthread_create.c 2014-08-29 20:01:15.216070587 -0700
+@@ -31,6 +31,7 @@
+ #include <kernel-features.h>
+ #include <exit-thread.h>
+
++#include <gnu/option-groups.h>
+ #include <shlib-compat.h>
+
+ #include <stap-probe.h>
+@@ -240,8 +241,10 @@
+ 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 ();
+@@ -322,8 +325,10 @@
+ /* 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 2014-08-29 20:00:52.948070587 -0700
++++ git/nscd/Makefile 2014-08-29 20:01:15.216070587 -0700
+@@ -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 @@
+ 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
+
+@@ -101,7 +108,15 @@
+ $(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 1970-01-01 00:00:00.000000000 +0000
++++ git/nscd/nis_hash.c 2014-08-29 20:01:15.216070587 -0700
+@@ -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 1970-01-01 00:00:00.000000000 +0000
++++ git/nss/fixed-nsswitch.conf 2014-08-29 20:01:15.216070587 -0700
+@@ -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 1970-01-01 00:00:00.000000000 +0000
++++ git/nss/fixed-nsswitch.functions 2014-08-29 20:01:15.216070587 -0700
+@@ -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 1970-01-01 00:00:00.000000000 +0000
++++ git/nss/gen-fixed-nsswitch.c 2014-08-29 20:01:15.216070587 -0700
+@@ -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 2014-08-29 20:00:52.976070587 -0700
++++ git/nss/getent.c 2014-08-29 20:01:15.216070587 -0700
+@@ -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 @@
+ 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 @@
+
+ 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 @@
+
+ return result;
+ }
++#endif /* __OPTION_EGLIBC_INET */
+
+ /* This is for group */
+ static void
+@@ -301,6 +306,7 @@
+ return result;
+ }
+
++#if __OPTION_EGLIBC_INET
+ /* This is for hosts */
+ static void
+ print_hosts (struct hostent *host)
+@@ -598,6 +604,7 @@
+
+ return result;
+ }
++#endif /* __OPTION_EGLIBC_INET */
+
+ /* Now is all for passwd */
+ static void
+@@ -650,6 +657,7 @@
+ return result;
+ }
+
++#if __OPTION_EGLIBC_INET
+ /* This is for protocols */
+ static void
+ print_protocols (struct protoent *proto)
+@@ -805,6 +813,7 @@
+
+ return result;
+ }
++#endif /* __OPTION_EGLIBC_INET */
+
+ /* This is for shadow */
+ static void
+@@ -871,21 +880,34 @@
+ } 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)
++DN(hosts)
+ D(initgroups)
+-D(netgroup)
+-D(networks)
++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 2014-08-29 20:00:52.976070587 -0700
++++ git/nss/getnssent_r.c 2014-08-29 20:01:15.220070587 -0700
+@@ -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 @@
+ } 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 @@
+ } 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 @@
+ 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 @@
+ 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 2014-08-29 20:00:52.972070587 -0700
++++ git/nss/Makefile 2014-08-29 20:01:15.220070587 -0700
+@@ -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 @@
+ 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 += $(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 2014-08-29 20:00:53.004070587 -0700
++++ git/nss/nsswitch.c 2014-08-29 20:01:15.220070587 -0700
+@@ -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 @@
+
+ __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 @@
+ __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 @@
+ 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 @@
+ *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 @@
+ {
+ 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 @@
+ 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 @@
+ }
+
+ /* 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 @@
+ 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 @@
+ 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 @@
+ #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 @@
+ }
+
+ /* 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 @@
+ + (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 @@
+ 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 @@
+ 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 @@
+ return *currentp;
+ }
+ #endif
++#endif /* __OPTION_EGLIBC_NSSWITCH */
+
+
+ #if defined SHARED && defined USE_NSCD
+@@ -834,6 +909,7 @@
+ }
+
+
++#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_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 @@
+ {
+ 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 @@
+
+ free (top);
+ }
++#endif /* __OPTION_EGLIBC_NSSWITCH */
+Index: git/nss/nsswitch.h
+===================================================================
+--- git.orig/nss/nsswitch.h 2014-08-29 20:00:53.012070587 -0700
++++ git/nss/nsswitch.h 2014-08-29 20:01:15.220070587 -0700
+@@ -65,10 +65,20 @@
+ 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 @@
+ /* 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 2014-08-29 20:00:53.184070587 -0700
++++ git/posix/bug-regex1.c 2014-08-29 20:01:15.220070587 -0700
+@@ -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 @@
+ 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 2014-08-29 20:00:53.204070587 -0700
++++ git/posix/bug-regex6.c 2014-08-29 20:01:15.220070587 -0700
+@@ -22,6 +22,7 @@
+ #include <string.h>
+ #include <sys/types.h>
+ #include <regex.h>
++#include <gnu/option-groups.h>
+
+
+ int
+@@ -30,7 +31,12 @@
+ 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 2014-08-29 20:00:53.208070587 -0700
++++ git/posix/fnmatch.c 2014-08-29 20:01:15.220070587 -0700
+@@ -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 @@
+ # 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 2014-08-29 20:00:53.220070587 -0700
++++ git/posix/fnmatch_loop.c 2014-08-29 20:01:15.220070587 -0700
+@@ -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 @@
+ 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 @@
+ /* 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 @@
+ }
+ 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. */
+@@ -681,8 +688,10 @@
+ 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;
+@@ -858,7 +867,7 @@
+ goto matched;
+ }
+ # else
+- hcollseq = collseq[cend];
++ hcollseq = COLLSEQ_BYTE_LOOKUP (cend);
+ # endif
+ }
+
+Index: git/posix/glob.c
+===================================================================
+--- git.orig/posix/glob.c 2014-08-29 20:00:53.232070587 -0700
++++ git/posix/glob.c 2014-08-29 20:01:15.220070587 -0700
+@@ -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 @@
+ 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 @@
+ 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 @@
+ }
+ __set_errno (save);
+ }
+-# else
++# else
+ p = getpwnam (name);
+-# endif
++# endif
+ if (p != NULL)
+ {
+ if (!malloc_pwtmpbuf)
+@@ -713,6 +717,7 @@
+ }
+ }
+ }
++# 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 2014-08-29 20:00:53.160070587 -0700
++++ git/posix/Makefile 2014-08-29 20:01:15.220070587 -0700
+@@ -18,6 +18,8 @@
+ #
+ # Sub-makefile for POSIX portion of the library.
+ #
++include ../option-groups.mak
++
+ subdir := posix
+
+ include ../Makeconfig
+@@ -43,13 +45,24 @@
+ 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 \
+@@ -57,41 +70,53 @@
+ spawnattr_getflags spawnattr_setflags \
+ spawnattr_getpgroup spawnattr_setpgroup spawn spawnp spawni \
+ spawnattr_getsigmask spawnattr_getschedpolicy spawnattr_getschedparam \
+- spawnattr_setsigmask spawnattr_setschedpolicy spawnattr_setschedparam \
+- posix_madvise \
+- get_child_max sched_cpucount sched_cpualloc sched_cpufree
++ spawnattr_setsigmask spawnattr_setschedpolicy spawnattr_setschedparam
++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
+-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 +142,10 @@
+
+ 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 +153,16 @@
+ # 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 $(objpfx)tst-rxspencer-no-utf8-mem \
++ $(objpfx)tst-pcre-mem $(objpfx)tst-boost-mem
++endif
++
+ xtests-special += $(objpfx)bug-ga2-mem.out
+ endif
+
+@@ -143,6 +175,8 @@
+ $(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 +239,10 @@
+ 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 2014-08-29 20:00:53.264070587 -0700
++++ git/posix/regcomp.c 2014-08-29 20:01:15.224070587 -0700
+@@ -18,6 +18,7 @@
+ <http://www.gnu.org/licenses/>. */
+
+ #include <stdint.h>
++#include <gnu/option-groups.h>
+
+ static reg_errcode_t re_compile_internal (regex_t *preg, const char * pattern,
+ size_t length, reg_syntax_t syntax);
+@@ -305,7 +306,7 @@
+ {
+ 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];
+@@ -315,9 +316,9 @@
+ {
+ 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;
+
+@@ -348,7 +349,11 @@
+ 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;
+@@ -376,7 +381,7 @@
+ 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
+@@ -404,7 +409,7 @@
+ 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)
+@@ -413,7 +418,7 @@
+ }
+ }
+ }
+-#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
+@@ -856,11 +861,15 @@
+
+ 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);
+@@ -886,7 +895,7 @@
+ #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;
+@@ -1784,7 +1793,7 @@
+ 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;
+@@ -1805,7 +1814,7 @@
+ 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);
+@@ -1919,7 +1928,7 @@
+
+ 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;
+@@ -2019,7 +2028,7 @@
+ 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;
+@@ -2242,7 +2251,7 @@
+ 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)))
+@@ -2380,7 +2389,7 @@
+ *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:
+@@ -2686,7 +2695,7 @@
+ 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. */
+@@ -2782,7 +2791,13 @@
+ 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;
+@@ -2830,18 +2845,20 @@
+ 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);
+@@ -2872,11 +2889,11 @@
+ {
+ /* 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;
+ }
+@@ -2916,7 +2933,7 @@
+ 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))
+@@ -2953,7 +2970,7 @@
+ 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)
+@@ -3031,7 +3048,10 @@
+ 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;
+@@ -3039,9 +3059,15 @@
+ 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)
+ {
+ /*
+@@ -3169,7 +3195,7 @@
+ #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);
+@@ -3185,7 +3211,7 @@
+ 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))
+@@ -3203,7 +3229,7 @@
+ }
+ 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
+@@ -3253,11 +3279,11 @@
+
+ #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;
+@@ -3326,7 +3352,7 @@
+ 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)
+@@ -3336,7 +3362,7 @@
+ 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)
+@@ -3416,7 +3442,9 @@
+ 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)
+ {
+@@ -3488,7 +3516,7 @@
+ 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;
+@@ -3522,7 +3550,7 @@
+ && (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))
+ {
+@@ -3538,7 +3566,7 @@
+ *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 { \
+@@ -3649,7 +3677,7 @@
+
+ #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
+
+@@ -3661,7 +3689,7 @@
+ 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 2014-08-29 20:00:53.268070587 -0700
++++ git/posix/regexec.c 2014-08-29 20:01:15.224070587 -0700
+@@ -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 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 @@
+ 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 @@
+ 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 @@
+ 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 @@
+ 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 @@
+ 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 @@
+ 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
+@@ -3832,12 +3817,6 @@
+ 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);
+@@ -3849,6 +3828,7 @@
+ 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)
+ {
+@@ -3859,8 +3839,16 @@
+ 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)
+ {
+@@ -3953,8 +3941,12 @@
+ }
+ }
+ 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'};
+@@ -3973,6 +3965,7 @@
+ goto check_node_accept_bytes_match;
+ }
+ }
++#endif /* __OPTION_EGLIBC_LOCALE_CODE */
+ }
+ check_node_accept_bytes_match:
+ if (!cset->non_match)
+@@ -3988,7 +3981,7 @@
+ 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)
+@@ -4046,7 +4039,7 @@
+ 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
+@@ -4137,7 +4130,7 @@
+ 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))
+@@ -4150,7 +4143,7 @@
+ 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 1970-01-01 00:00:00.000000000 +0000
++++ git/posix/regexec-compat.c 2014-08-29 20:01:15.224070587 -0700
+@@ -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 2014-08-29 20:00:53.264070587 -0700
++++ git/posix/regex.h 2014-08-29 20:01:15.224070587 -0700
+@@ -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 @@
+ treated as 'a\{1'. */
+ # define RE_INVALID_INTERVAL_ORD (RE_DEBUG << 1)
+
++/* EGLIBC: Old regex implementation does not support these. */
++# ifdef __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 @@
+ /* 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 @@
+ (RE_CHAR_CLASSES | RE_DOT_NEWLINE | RE_DOT_NOT_NULL \
+ | RE_INTERVALS | RE_NO_EMPTY_RANGES)
+
++#ifdef __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 @@
+ /* Like REG_NOTBOL, except for the end-of-line. */
+ #define REG_NOTEOL (1 << 1)
+
++#ifdef __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 2014-08-29 20:00:53.264070587 -0700
++++ git/posix/regex_internal.c 2014-08-29 20:01:15.224070587 -0700
+@@ -43,8 +43,8 @@
+ 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 @@
+ 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 @@
+ 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 @@
+ 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 @@
+ 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 @@
+ 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 @@
+ 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 @@
+ {
+ #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 @@
+ {
+ 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 @@
+ 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 @@
+ {
+ 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 @@
+ }
+
+ /* 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 @@
+ {
+ /* 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 @@
+ 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 @@
+ #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 @@
+ /* 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 @@
+
+ /* 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 @@
+ 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 @@
+ 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 @@
+ 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 2014-08-29 20:00:53.264070587 -0700
++++ git/posix/regex_internal.h 2014-08-29 20:01:15.224070587 -0700
+@@ -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
+@@ -370,6 +374,13 @@
+ };
+ 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;
+@@ -655,6 +666,14 @@
+ __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))
+@@ -715,7 +734,7 @@
+ 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)
+@@ -727,7 +746,7 @@
+ 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 1970-01-01 00:00:00.000000000 +0000
++++ git/posix/xregex.c 2014-08-29 20:01:15.228070587 -0700
+@@ -0,0 +1,8212 @@
++/* 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
++
++# define WIDE_CHAR_SUPPORT (HAVE_WCTYPE_H && HAVE_WCHAR_H && HAVE_BTOWC)
++
++/* 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)
++#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
++# 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. */
++# 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;
++
++ /* This #include defines a local function! */
++# include <locale/weightwc.h>
++
++ 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 int32_t *)
++ _NL_CURRENT (LC_COLLATE,
++ _NL_COLLATE_EXTRAWC);
++ indirect = (const int32_t *)
++ _NL_CURRENT (LC_COLLATE,
++ _NL_COLLATE_INDIRECTWC);
++
++ idx = findidx ((const wint_t**)&cp, c1);
++ 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;
++
++ /* This #include defines a local function! */
++# include <locale/weight.h>
++
++ 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 (&cp, c1);
++ 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;
++
++ /* This #include defines a local function! */
++# include <locale/weightwc.h>
++
++ 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 ((const wint_t**)&cp, i);
++ }
++
++ /* 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 = NULL;
++ const CHAR_T *sdummy = 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 2014-08-29 20:00:53.316070587 -0700
++++ git/pwd/Makefile 2014-08-29 20:01:15.232070587 -0700
+@@ -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 2014-08-29 20:00:53.320070587 -0700
++++ git/resolv/Makefile 2014-08-29 20:01:15.232070587 -0700
+@@ -18,6 +18,8 @@
+ #
+ # Sub-makefile for resolv portion of the library.
+ #
++include ../option-groups.mak
++
+ subdir := resolv
+
+ include ../Makeconfig
+@@ -27,20 +29,21 @@
+ 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 @@
+ 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 2014-08-29 20:00:53.544070587 -0700
++++ git/stdio-common/fxprintf.c 2014-08-29 20:01:15.232070587 -0700
+@@ -23,6 +23,7 @@
+ #include <wchar.h>
+ #include <string.h>
+ #include <libioP.h>
++#include <gnu/option-groups.h>
+
+
+ int
+@@ -37,6 +38,7 @@
+ 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 @@
+ 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 2014-08-29 20:00:53.500070587 -0700
++++ git/stdio-common/_i18n_number.h 2014-08-29 20:01:15.232070587 -0700
+@@ -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 @@
+
+ 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 2014-08-29 20:00:53.500070587 -0700
++++ git/stdio-common/Makefile 2014-08-29 20:01:15.232070587 -0700
+@@ -18,6 +18,8 @@
+ #
+ # Specific makefile for stdio-common.
+ #
++include ../option-groups.mak
++
+ subdir := stdio-common
+
+ include ../Makeconfig
+@@ -30,7 +32,7 @@
+ 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,37 @@
+ 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 \
++ 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 \
+- bug25 tst-printf-round bug26
++ 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 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 2014-08-29 20:00:53.548070587 -0700
++++ git/stdio-common/printf_fp.c 2014-08-29 20:01:15.232070587 -0700
+@@ -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>
+
+@@ -148,6 +149,10 @@
+ wchar_t thousands_sep, int ngroups)
+ internal_function;
+
++/* 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. */
+
+ int
+ ___printf_fp (FILE *fp,
+@@ -206,7 +211,14 @@
+ 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;
+@@ -258,6 +270,7 @@
+
+
+ /* Figure out the decimal point character. */
++#if __OPTION_EGLIBC_LOCALE_CODE
+ if (info->extra == 0)
+ {
+ decimal = _NL_CURRENT (LC_NUMERIC, DECIMAL_POINT);
+@@ -277,7 +290,13 @@
+ /* 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)
+@@ -321,6 +340,9 @@
+ }
+ 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 2014-08-29 20:00:53.548070587 -0700
++++ git/stdio-common/printf_fphex.c 2014-08-29 20:01:15.232070587 -0700
+@@ -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 @@
+ 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 @@
+ }
+ /* 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 2014-08-29 20:00:53.548070587 -0700
++++ git/stdio-common/printf_size.c 2014-08-29 20:01:15.232070587 -0700
+@@ -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 @@
+
+ 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 2014-08-29 20:00:53.548070587 -0700
++++ git/stdio-common/scanf14.c 2014-08-29 20:01:15.232070587 -0700
+@@ -2,6 +2,7 @@
+ #include <stdlib.h>
+ #include <string.h>
+ #include <wchar.h>
++#include <gnu/option-groups.h>
+
+ #define FAIL() \
+ do { \
+@@ -36,6 +37,7 @@
+ FAIL ();
+ else if (d != 2.25 || memcmp (c, " x", 2) != 0)
+ FAIL ();
++#if __OPTION_EGLIBC_LOCALE_CODE
+ if (sscanf (" 3.25S x", "%4aS%3c", &lsp, c) != 2)
+ FAIL ();
+ else
+@@ -45,6 +47,7 @@
+ 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 2014-08-29 20:00:53.584070587 -0700
++++ git/stdio-common/tstdiomisc.c 2014-08-29 20:01:15.232070587 -0700
+@@ -3,6 +3,7 @@
+ #include <stdio.h>
+ #include <string.h>
+ #include <wchar.h>
++#include <gnu/option-groups.h>
+
+ static int
+ t1 (void)
+@@ -125,6 +126,7 @@
+ 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);
+@@ -162,6 +164,7 @@
+ 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;
+
+@@ -206,6 +209,7 @@
+ 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,
+@@ -250,6 +254,7 @@
+ 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 2014-08-29 20:00:53.576070587 -0700
++++ git/stdio-common/tst-popen.c 2014-08-29 20:01:15.232070587 -0700
+@@ -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 @@
+ 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 2014-08-29 20:00:53.580070587 -0700
++++ git/stdio-common/tst-sprintf.c 2014-08-29 20:01:15.236070587 -0700
+@@ -2,6 +2,7 @@
+ #include <stdlib.h>
+ #include <locale.h>
+ #include <string.h>
++#include <gnu/option-groups.h>
+
+
+ int
+@@ -10,12 +11,14 @@
+ 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 2014-08-29 20:00:53.588070587 -0700
++++ git/stdio-common/vfprintf.c 2014-08-29 20:01:15.236070587 -0700
+@@ -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. */
+@@ -1123,8 +1136,11 @@
+ # 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 (' '); \
+@@ -1137,6 +1153,7 @@
+ break; \
+ \
+ LABEL (form_wcharacter): \
++ assert (MULTIBYTE_SUPPORT); \
+ { \
+ /* Wide character. */ \
+ char buf[MB_CUR_MAX]; \
+@@ -1203,6 +1220,7 @@
+ } \
+ else \
+ { \
++ assert (MULTIBYTE_SUPPORT); \
+ const wchar_t *s2 = (const wchar_t *) string; \
+ mbstate_t mbstate; \
+ \
+@@ -1403,7 +1421,9 @@
+ 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,
+@@ -1702,7 +1722,9 @@
+ 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 2014-08-29 20:00:53.588070587 -0700
++++ git/stdio-common/vfscanf.c 2014-08-29 20:01:15.236070587 -0700
+@@ -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 @@
+ 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 @@
+ #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 @@
+ }
+ /* FALLTHROUGH */
+ case L_('C'):
++ assert (MULTIBYTE_SUPPORT);
++
+ if (width == -1)
+ width = 1;
+
+@@ -1172,6 +1194,8 @@
+ /* FALLTHROUGH */
+
+ case L_('S'):
++ assert (MULTIBYTE_SUPPORT);
++
+ {
+ #ifndef COMPILE_WSCANF
+ mbstate_t cstate;
+@@ -1419,10 +1443,17 @@
+ 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 @@
+ --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 @@
+ ;
+ #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 @@
+
+ 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 @@
+ 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 2014-08-29 20:00:53.588070587 -0700
++++ git/stdlib/Makefile 2014-08-29 20:01:15.236070587 -0700
+@@ -18,6 +18,8 @@
+ #
+ # Makefile for stdlib routines
+ #
++include ../option-groups.mak
++
+ subdir := stdlib
+
+ include ../Makeconfig
+@@ -30,7 +32,7 @@
+ alloca.h fmtmsg.h \
+ bits/stdlib-bsearch.h
+
+-routines := \
++routines-y := \
+ atof atoi atol atoll \
+ abort \
+ bsearch qsort msort \
+@@ -39,7 +41,6 @@
+ 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 @@
+ 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 @@
+ # 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 @@
+ 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 2014-08-29 20:00:53.648070587 -0700
++++ git/stdlib/strtod_l.c 2014-08-29 20:01:15.236070587 -0700
+@@ -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 @@
+ /* 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 @@
+ 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 2014-08-29 20:00:53.700070587 -0700
++++ git/stdlib/tst-strtod.c 2014-08-29 20:01:15.236070587 -0700
+@@ -23,6 +23,7 @@
+ #include <errno.h>
+ #include <string.h>
+ #include <math.h>
++#include <gnu/option-groups.h>
+
+ struct ltest
+ {
+@@ -176,7 +177,9 @@
+
+ status |= long_dbl ();
+
++#if __OPTION_EGLIBC_LOCALE_CODE
+ status |= locale_test ();
++#endif
+
+ return status ? EXIT_FAILURE : EXIT_SUCCESS;
+ }
+@@ -219,6 +222,7 @@
+ 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 @@
+
+ return result;
+ }
++#endif /* __OPTION_EGLIBC_LOCALE_CODE */
+Index: git/streams/Makefile
+===================================================================
+--- git.orig/streams/Makefile 2014-08-29 20:00:53.712070587 -0700
++++ git/streams/Makefile 2014-08-29 20:01:15.236070587 -0700
+@@ -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 2014-08-29 20:00:53.716070587 -0700
++++ git/string/Makefile 2014-08-29 20:01:15.236070587 -0700
+@@ -18,6 +18,8 @@
+ #
+ # Sub-makefile for string portion of library.
+ #
++include ../option-groups.mak
++
+ subdir := string
+
+ include ../Makeconfig
+@@ -39,10 +41,12 @@
+ $(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 @@
+ 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 2014-08-29 20:00:53.744070587 -0700
++++ git/string/strcoll_l.c 2014-08-29 20:01:15.240070587 -0700
+@@ -25,6 +25,7 @@
+ #include <stdlib.h>
+ #include <string.h>
+ #include <sys/param.h>
++#include <gnu/option-groups.h>
+
+ #ifndef STRING_TYPE
+ # define STRING_TYPE char
+@@ -472,7 +473,11 @@
+ 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 2014-08-29 20:00:53.744070587 -0700
++++ git/string/strerror_l.c 2014-08-29 20:01:15.240070587 -0700
+@@ -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 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 2014-08-29 20:00:53.748070587 -0700
++++ git/string/strxfrm_l.c 2014-08-29 20:01:15.240070587 -0700
+@@ -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
+@@ -85,7 +86,11 @@
+ STRXFRM (STRING_TYPE *dest, const STRING_TYPE *src, size_t n, __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/test-strcmp.c
+===================================================================
+--- git.orig/string/test-strcmp.c 2014-08-29 20:00:53.752070587 -0700
++++ git/string/test-strcmp.c 2014-08-29 20:01:15.240070587 -0700
+@@ -329,34 +329,6 @@
+ 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 2014-08-29 20:00:53.756070587 -0700
++++ git/string/tst-strxfrm2.c 2014-08-29 20:01:15.240070587 -0700
+@@ -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 @@
+ res = 1;
+ }
+
++#if __OPTION_EGLIBC_LOCALE_CODE
+ if (setlocale (LC_ALL, "de_DE.UTF-8") == NULL)
+ {
+ puts ("setlocale failed");
+@@ -75,6 +77,7 @@
+ res = 1;
+ }
+ }
++#endif
+
+ return res;
+ }
+Index: git/string/tst-strxfrm.c
+===================================================================
+--- git.orig/string/tst-strxfrm.c 2014-08-29 20:00:53.756070587 -0700
++++ git/string/tst-strxfrm.c 2014-08-29 20:01:15.240070587 -0700
+@@ -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 @@
+ 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 2014-08-29 20:00:53.760070587 -0700
++++ git/sunrpc/Makefile 2014-08-29 20:01:15.240070587 -0700
+@@ -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-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 @@
+ 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 @@
+
+ # 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 2014-08-29 20:00:53.904070587 -0700
++++ git/sysdeps/generic/ldsodefs.h 2014-08-29 20:01:15.240070587 -0700
+@@ -425,6 +425,12 @@
+ # 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 @@
+ {
+ #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 2014-08-29 20:00:53.924070587 -0700
++++ git/sysdeps/gnu/Makefile 2014-08-29 20:01:15.240070587 -0700
+@@ -57,7 +57,8 @@
+ 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/dbl-64/s_sin.c
+===================================================================
+--- git.orig/sysdeps/ieee754/dbl-64/s_sin.c 2014-08-29 20:00:54.260070587 -0700
++++ git/sysdeps/ieee754/dbl-64/s_sin.c 2014-08-29 20:01:15.240070587 -0700
+@@ -447,21 +447,19 @@
+ }
+ else
+ {
+- double t;
+ if (a > 0)
+ {
+ m = 1;
+- t = a;
+ db = da;
+ }
+ else
+ {
+ m = 0;
+- t = -a;
++ a = -a;
+ db = -da;
+ }
+- u.x = big + t;
+- y = t - (u.x - big);
++ u.x = big + a;
++ y = a - (u.x - big);
+ res = do_sin (u, y, db, &cor);
+ cor = (cor > 0) ? 1.035 * cor + eps : 1.035 * cor - eps;
+ retval = ((res == res + cor) ? ((m) ? res : -res)
+@@ -673,21 +671,19 @@
+ }
+ else
+ {
+- double t;
+ if (a > 0)
+ {
+ m = 1;
+- t = a;
+ db = da;
+ }
+ else
+ {
+ m = 0;
+- t = -a;
++ a = -a;
+ db = -da;
+ }
+- u.x = big + t;
+- y = t - (u.x - big);
++ u.x = big + a;
++ y = a - (u.x - big);
+ res = do_sin (u, y, db, &cor);
+ cor = (cor > 0) ? 1.035 * cor + eps : 1.035 * cor - eps;
+ retval = ((res == res + cor) ? ((m) ? res : -res)
+Index: git/sysdeps/ieee754/ldbl-opt/Makefile
+===================================================================
+--- git.orig/sysdeps/ieee754/ldbl-opt/Makefile 2014-08-29 20:00:54.452070587 -0700
++++ git/sysdeps/ieee754/ldbl-opt/Makefile 2014-08-29 20:01:15.244070587 -0700
+@@ -11,19 +11,18 @@
+ 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 @@
+ 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 2014-08-29 20:00:54.468070587 -0700
++++ git/sysdeps/ieee754/ldbl-opt/nldbl-compat.c 2014-08-29 20:01:15.244070587 -0700
+@@ -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_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_l)
+ libc_hidden_proto (__nldbl___isoc99_vsscanf)
+ libc_hidden_proto (__nldbl___isoc99_vfscanf)
++
++#ifdef __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 @@
+ }
+ weak_alias (__nldbl_fprintf, __nldbl__IO_fprintf)
+
++#ifdef __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 @@
+
+ return done;
+ }
++#endif
+
+ int
+ attribute_compat_text_section
+@@ -226,6 +232,7 @@
+ return done;
+ }
+
++#ifdef __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 @@
+
+ return done;
+ }
++#endif
+
+ int
+ attribute_compat_text_section weak_function
+@@ -264,6 +272,7 @@
+ }
+ libc_hidden_def (__nldbl_vdprintf)
+
++#ifdef __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 @@
+ return res;
+ }
+ libc_hidden_def (__nldbl_vfwprintf)
++#endif
+
+ int
+ attribute_compat_text_section
+@@ -297,6 +307,7 @@
+ libc_hidden_def (__nldbl_vsnprintf)
+ weak_alias (__nldbl_vsnprintf, __nldbl___vsnprintf)
+
++#ifdef __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 @@
+
+ return done;
+ }
++#endif
+
+ int
+ attribute_compat_text_section
+@@ -419,6 +431,7 @@
+ return done;
+ }
+
++#ifdef __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 @@
+
+ return done;
+ }
++#endif
+
+ int
+ attribute_compat_text_section
+@@ -506,6 +520,7 @@
+ return done;
+ }
+
++#ifdef __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 @@
+
+ return done;
+ }
++#endif
+
+ int
+ attribute_compat_text_section
+@@ -563,6 +579,7 @@
+ return done;
+ }
+
++#ifdef __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 @@
+
+ return done;
+ }
++#endif
+
+ int
+ attribute_compat_text_section
+@@ -590,6 +608,7 @@
+ }
+ libc_hidden_def (__nldbl___vfprintf_chk)
+
++#ifdef __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 @@
+ return res;
+ }
+ libc_hidden_def (__nldbl___vfwprintf_chk)
++#endif
+
+ int
+ attribute_compat_text_section
+@@ -635,6 +655,7 @@
+ }
+ libc_hidden_def (__nldbl___vsprintf_chk)
+
++#ifdef __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 @@
+
+ return done;
+ }
++#endif
+
+ int
+ attribute_compat_text_section
+@@ -775,6 +797,7 @@
+ 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 @@
+ return res;
+ }
+ libc_hidden_def (__nldbl___vstrfmon_l)
++#endif
+
+ void
+ attribute_compat_text_section
+@@ -941,6 +965,7 @@
+ return done;
+ }
+
++#ifdef __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 @@
+
+ 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___strfmon_l, __strfmon_l, GLIBC_2_1);
+ #endif
+ #if LONG_DOUBLE_COMPAT(libc, GLIBC_2_2)
++# ifdef __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_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 2014-08-29 20:00:54.468070587 -0700
++++ git/sysdeps/ieee754/ldbl-opt/nldbl-compat.h 2014-08-29 20:01:15.244070587 -0700
+@@ -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_vscanf);
+ NLDBL_DECL (__isoc99_vfscanf);
+ NLDBL_DECL (__isoc99_vsscanf);
++#ifdef __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 @@
+ 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);
+-
++#ifdef __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 2014-08-29 20:00:58.840070587 -0700
++++ git/sysdeps/unix/sysv/linux/gethostid.c 2014-08-29 20:01:15.244070587 -0700
+@@ -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 @@
+ 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 @@
+ /* 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 2014-08-29 20:00:58.980070587 -0700
++++ git/sysdeps/unix/sysv/linux/libc_fatal.c 2014-08-29 20:01:15.244070587 -0700
+@@ -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 @@
+ 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 @@
+ close_not_cancel_no_status (fd2);
+ }
+ }
++#endif /* __OPTION_EGLIBC_BACKTRACE */
+ }
+ #define BEFORE_ABORT backtrace_and_maps
+
+Index: git/time/Makefile
+===================================================================
+--- git.orig/time/Makefile 2014-08-29 20:00:59.504070587 -0700
++++ git/time/Makefile 2014-08-29 20:01:15.244070587 -0700
+@@ -18,6 +18,8 @@
+ #
+ # Makefile for time routines
+ #
++include ../option-groups.mak
++
+ subdir := time
+
+ include ../Makeconfig
+@@ -30,14 +32,20 @@
+ 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
++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-strptime tst_wcsftime \
+- tst-getdate tst-mktime tst-mktime2 tst-ftime_l tst-strftime \
++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
++tests-$(OPTION_EGLIBC_LOCALE_CODE) \
++ += tst-strptime tst-ftime_l
++tests-$(OPTION_POSIX_WIDE_CHAR_DEVICE_IO) \
++ += tst_wcsftime
+
+ include ../Rules
+
+Index: git/time/strftime_l.c
+===================================================================
+--- git.orig/time/strftime_l.c 2014-08-29 20:00:59.528070587 -0700
++++ git/time/strftime_l.c 2014-08-29 20:01:15.244070587 -0700
+@@ -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 @@
+ 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 @@
+
+ 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 @@
+ 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 @@
+ 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 2014-08-29 20:00:59.528070587 -0700
++++ git/time/strptime_l.c 2014-08-29 20:01:15.244070587 -0700
+@@ -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 @@
+ 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; \
+@@ -820,6 +821,7 @@
+ s.want_xday = 1;
+ break;
+ case 'C':
++#if ! _LIBC || __OPTION_EGLIBC_LOCALE_CODE
+ if (s.decided != raw)
+ {
+ if (s.era_cnt >= 0)
+@@ -856,10 +858,12 @@
+
+ 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 +922,10 @@
+
+ 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 +953,7 @@
+
+ s.decided = raw;
+ }
++#endif
+ get_number (0, 9999, 4);
+ tm->tm_year = val - 1900;
+ s.want_century = 0;
+@@ -1118,6 +1124,7 @@
+ 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 +1139,7 @@
+ 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 2014-08-29 20:01:14.044070587 -0700
++++ git/timezone/Makefile 2014-08-29 20:01:15.244070587 -0700
+@@ -115,7 +115,7 @@
+
+ $(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 2014-08-29 20:00:59.548070587 -0700
++++ git/wcsmbs/Makefile 2014-08-29 20:01:15.244070587 -0700
+@@ -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,19 @@
+ 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))
+ tests-ifunc := $(strop-tests:%=test-%-ifunc)
+ tests += $(tests-ifunc)
+
+Index: git/wcsmbs/wcsmbsload.c
+===================================================================
+--- git.orig/wcsmbs/wcsmbsload.c 2014-08-29 20:00:59.580070587 -0700
++++ git/wcsmbs/wcsmbsload.c 2014-08-29 20:01:15.248070587 -0700
+@@ -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 @@
+ })
+
+
++#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 @@
+
+ __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 2014-08-29 20:00:59.584070587 -0700
++++ git/wctype/Makefile 2014-08-29 20:01:15.248070587 -0700
+@@ -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 2014-08-29 20:00:58.036070587 -0700
++++ git/sysdeps/nptl/Makefile 2014-08-29 20:01:15.248070587 -0700
+@@ -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 2014-08-29 20:00:58.036070587 -0700
++++ git/sysdeps/nptl/bits/libc-lock.h 2014-08-29 20:01:15.248070587 -0700
+@@ -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 (defined NOT_IN_libc && !defined IS_IN_libpthread) || !defined _LIBC
+@@ -87,6 +95,14 @@
+
+ /* Lock the recursive named lock variable. */
+ #if defined _LIBC && (!defined NOT_IN_libc || defined 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 +113,10 @@
+ } \
+ ++(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 +124,14 @@
+
+ /* Try to lock the recursive named lock variable. */
+ #if defined _LIBC && (!defined NOT_IN_libc || defined 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 +150,10 @@
+ ++(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 +161,14 @@
+
+ /* Unlock the recursive named lock variable. */
+ #if defined _LIBC && (!defined NOT_IN_libc || defined 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 +178,10 @@
+ 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 2014-08-29 20:00:58.044070587 -0700
++++ git/sysdeps/nptl/bits/libc-lockP.h 2014-08-29 20:01:15.248070587 -0700
+@@ -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. */
+
+ /* Mutex type. */
+ #if defined NOT_IN_libc && !defined IS_IN_libpthread
+@@ -159,10 +161,22 @@
+
+ /* Lock the named lock variable. */
+ #if !defined NOT_IN_libc || defined 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) \
+@@ -175,10 +189,22 @@
+
+ /* Try to lock the named lock variable. */
+ #if !defined NOT_IN_libc || defined 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) \
+@@ -194,8 +220,20 @@
+
+ /* Unlock the named lock variable. */
+ #if !defined NOT_IN_libc || defined 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 1970-01-01 00:00:00.000000000 +0000
++++ git/sysdeps/nptl/small-macros-fns.c 2014-08-29 20:01:15.248070587 -0700
+@@ -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/include/libc-symbols.h
+===================================================================
+--- git.orig/include/libc-symbols.h 2014-08-29 20:00:47.144070587 -0700
++++ git/include/libc-symbols.h 2014-08-29 20:01:15.248070587 -0700
+@@ -60,8 +60,11 @@
+ /* Define these macros for the benefit of portable GNU code that wants to check
+ them. Of course, STDC_HEADERS is never false when building libc! */
+ #define STDC_HEADERS 1
+-#define HAVE_MBSTATE_T 1
+-#define HAVE_MBSRTOWCS 1
++
++#if __OPTION_EGLIBC_LOCALE_CODE
++# define HAVE_MBSTATE_T 1
++# define HAVE_MBSRTOWCS 1
++#endif
+ #define HAVE_LIBINTL_H 1
+ #define HAVE_WCTYPE_H 1
+ #define HAVE_ISWCTYPE 1
+Index: git/crypt/crypt_common.c
+===================================================================
+--- /dev/null 1970-01-01 00:00:00.000000000 +0000
++++ git/crypt/crypt_common.c 2014-08-29 20:01:15.248070587 -0700
+@@ -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 2014-08-29 20:00:43.028070587 -0700
++++ git/crypt/crypt_util.c 2014-08-29 20:01:15.248070587 -0700
+@@ -242,10 +242,6 @@
+ */
+ 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_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 2014-08-29 20:29:37.000000000 -0700
++++ git/sysdeps/arm/Makefile 2014-08-29 20:31:09.904070587 -0700
+@@ -37,10 +37,13 @@
+ # 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