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 # include +# include # 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 +# include #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 #endif #include +#include #include #include @@ -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 #include <_itoa.h> #include +#include /* 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 #include #include +#include #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 # . +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 #include #include #include @@ -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 . */ +#include #include #include #include @@ -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 #include #include +#include #include #include @@ -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 #include #include +#include #include #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 #endif +#include #include #include #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 +#endif + /* Thread safetyness. */ #ifdef _LIBC # include @@ -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 @@ # . # 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 @@ # . # 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 +/* Get __OPTION_EGLIBC_LOCALE_CODE. */ +#ifdef _LIBC +# include +#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 #include #include +#include #include #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 #ifdef _LIBC +# include # include # include #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 + #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 */ #endif +#if defined _LIBC +# include +#endif + #include #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 +#include +#include +#include + +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 #include +#include +#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 +#include + +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 # 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 #include #include +#ifndef NO_UNCOMPRESS #include +#endif #include #include #include @@ -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, " %ms", &alias) == 1 - || fscanf (stream, "%% alias %ms", &alias) == 1) + if (fscanf (stream, " %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 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 #include #include +#include #include @@ -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 @@ . */ #include +#include #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 # = 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 #include #include +#include #include @@ -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 #include #include +#include #include #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 # include # include # include @@ -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 #include +#include #include #include @@ -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 +#include +#include +#include +#include +#include +#include + +#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: + `( ( "[" "!"? ( "=" )+ "]" )? )*' + */ +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 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 ` ":"'. */ + 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 #include #include +#include /* Get libc version number. */ #include @@ -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) +DN(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 @@ . */ #include +#include #include #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 #include #include +#include #include #include @@ -41,6 +42,15 @@ #include "../nscd/nscd_proto.h" #include +/* 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 #include #include +#include int main (void) @@ -17,7 +18,9 @@ memset (®ex, '\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 #include #include +#include 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 #include +#if defined _LIBC +# include +#endif + #if defined STDC_HEADERS || defined _LIBC # include #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 . */ +#include + #include 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 #include #include +#ifdef _LIBC +# include +#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 @@ . */ #include +#include 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 @@ . */ #include +#include 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 -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 . + + 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 +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 +#include /* 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. */ +# if __OPTION_POSIX_REGEXP_GLIBC /* If this bit is set, then ignore case when matching. If not set, then case is significant. */ # define RE_ICASE (RE_INVALID_INTERVAL_ORD << 1) @@ -172,6 +175,7 @@ /* 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) +#if __OPTION_POSIX_REGEXP_GLIBC #define RE_SYNTAX_POSIX_BASIC \ (_RE_SYNTAX_POSIX_COMMON | RE_BK_PLUS_QM | RE_CONTEXT_INVALID_DUP) +#else +#define RE_SYNTAX_POSIX_BASIC \ + (_RE_SYNTAX_POSIX_COMMON | RE_BK_PLUS_QM) +#endif /* Differs from ..._POSIX_BASIC only in that RE_BK_PLUS_QM becomes RE_LIMITED_OPS, i.e., \? \+ \| are not recognized. Actually, this @@ -298,9 +307,11 @@ /* Like REG_NOTBOL, except for the end-of-line. */ #define REG_NOTEOL (1 << 1) +#if __OPTION_POSIX_REGEXP_GLIBC /* Use PMATCH[0] to delimit the start and end of the search in the buffer. */ #define REG_STARTEND (1 << 2) +#endif /* If any error codes are removed, changed, or added, update the Index: git/posix/regex_internal.c =================================================================== --- git.orig/posix/regex_internal.c 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 #include +#if defined _LIBC +# include +#endif + #if defined HAVE_LANGINFO_H || defined HAVE_LANGINFO_CODESET || defined _LIBC # include #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 +# endif +#endif + +/*#include */ + +#ifndef INSIDE_RECURSION + +# if defined STDC_HEADERS && !defined emacs +# include +# else +/* We need this for `regex.h', and perhaps for the Emacs include files. */ +# include +# 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: must be included before . */ +# include +# include +# 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 +# include +# include +# include +# endif + +/* This is for other GNU distributions with internationalized messages. */ +# if (HAVE_LIBINTL_H && ENABLE_NLS) || defined _LIBC +# include +# 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 +# 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 +# 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 +# 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 +# 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 + +/* 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 +# 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 + +/* It is useful to test things that ``must'' be true when debugging. */ +# include + +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 ; ibuffer; + + 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 + +# 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 + + 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 + + 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 + set_number_at + succeed_n + + jump_n + (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 + + 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; + + + /* \ has been turned into a `duplicate' command which is + followed by the numeric value of 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 ? ®s : (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 #include #include +#include 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 #include #include +#include #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 #include #include +#include #include #include @@ -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 +#include #include #include @@ -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 #include #include +#include /* 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 #include #include +#include #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 #include #include +#include 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 #include #include +#include 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 #include #include +#include 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 #include +#include /* 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 #include #include +#include #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 . */ +#include #include 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 #include #include +#include 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 #include #include +#include #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 #include #include +#include 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 #include #include +#include #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 #include #include +#include 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 #include #include +#include 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/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 #include #include +#include #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) + +#if __OPTION_POSIX_WIDE_CHAR_DEVICE_IO +libc_hidden_proto (__nldbl_vfwscanf) +libc_hidden_proto (__nldbl_vswscanf) +libc_hidden_proto (__nldbl_vfwprintf) +libc_hidden_proto (__nldbl_vswprintf) +libc_hidden_proto (__nldbl___vfwprintf_chk) +libc_hidden_proto (__nldbl___vswprintf_chk) libc_hidden_proto (__nldbl___isoc99_vswscanf) libc_hidden_proto (__nldbl___isoc99_vfwscanf) +#endif static void __nldbl_cleanup (void *arg) @@ -117,6 +121,7 @@ } weak_alias (__nldbl_fprintf, __nldbl__IO_fprintf) +#if __OPTION_POSIX_WIDE_CHAR_DEVICE_IO int attribute_compat_text_section weak_function __nldbl_fwprintf (FILE *stream, const wchar_t *fmt, ...) @@ -130,6 +135,7 @@ return done; } +#endif int attribute_compat_text_section @@ -226,6 +232,7 @@ return done; } +#if __OPTION_POSIX_WIDE_CHAR_DEVICE_IO int attribute_compat_text_section __nldbl_swprintf (wchar_t *s, size_t n, const wchar_t *fmt, ...) @@ -239,6 +246,7 @@ return done; } +#endif int attribute_compat_text_section weak_function @@ -264,6 +272,7 @@ } libc_hidden_def (__nldbl_vdprintf) +#if __OPTION_POSIX_WIDE_CHAR_DEVICE_IO int attribute_compat_text_section weak_function __nldbl_vfwprintf (FILE *s, const wchar_t *fmt, va_list ap) @@ -275,6 +284,7 @@ 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) +#if __OPTION_POSIX_WIDE_CHAR_DEVICE_IO int attribute_compat_text_section weak_function __nldbl_vswprintf (wchar_t *string, size_t maxlen, const wchar_t *fmt, @@ -330,6 +341,7 @@ return done; } +#endif int attribute_compat_text_section @@ -419,6 +431,7 @@ return done; } +#if __OPTION_POSIX_WIDE_CHAR_DEVICE_IO int attribute_compat_text_section __nldbl_vfwscanf (FILE *s, const wchar_t *fmt, va_list ap) @@ -491,6 +504,7 @@ return done; } +#endif int attribute_compat_text_section @@ -506,6 +520,7 @@ return done; } +#if __OPTION_POSIX_WIDE_CHAR_DEVICE_IO int attribute_compat_text_section __nldbl___fwprintf_chk (FILE *stream, int flag, const wchar_t *fmt, ...) @@ -519,6 +534,7 @@ return done; } +#endif int attribute_compat_text_section @@ -563,6 +579,7 @@ return done; } +#if __OPTION_POSIX_WIDE_CHAR_DEVICE_IO int attribute_compat_text_section __nldbl___swprintf_chk (wchar_t *s, size_t n, int flag, size_t slen, @@ -577,6 +594,7 @@ return done; } +#endif int attribute_compat_text_section @@ -590,6 +608,7 @@ } libc_hidden_def (__nldbl___vfprintf_chk) +#if __OPTION_POSIX_WIDE_CHAR_DEVICE_IO int attribute_compat_text_section __nldbl___vfwprintf_chk (FILE *s, int flag, const wchar_t *fmt, va_list ap) @@ -601,6 +620,7 @@ return res; } libc_hidden_def (__nldbl___vfwprintf_chk) +#endif int attribute_compat_text_section @@ -635,6 +655,7 @@ } libc_hidden_def (__nldbl___vsprintf_chk) +#if __OPTION_POSIX_WIDE_CHAR_DEVICE_IO int attribute_compat_text_section __nldbl___vswprintf_chk (wchar_t *string, size_t maxlen, int flag, size_t slen, @@ -668,6 +689,7 @@ 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; } +#if __OPTION_POSIX_WIDE_CHAR_DEVICE_IO int attribute_compat_text_section __nldbl___isoc99_vfwscanf (FILE *s, const wchar_t *fmt, va_list ap) @@ -1014,6 +1039,7 @@ 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) +# if __OPTION_POSIX_WIDE_CHAR_DEVICE_IO compat_symbol (libc, __nldbl_swprintf, swprintf, GLIBC_2_2); compat_symbol (libc, __nldbl_vwprintf, vwprintf, GLIBC_2_2); compat_symbol (libc, __nldbl_wprintf, wprintf, GLIBC_2_2); @@ -1069,6 +1096,7 @@ compat_symbol (libc, __nldbl_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 #include #include +#include /* 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); +#if __OPTION_POSIX_WIDE_CHAR_DEVICE_IO +NLDBL_DECL (vfwscanf); +NLDBL_DECL (vfwprintf); +NLDBL_DECL (vswprintf); +NLDBL_DECL (vswscanf); NLDBL_DECL (__isoc99_wscanf); NLDBL_DECL (__isoc99_fwscanf); NLDBL_DECL (__isoc99_swscanf); NLDBL_DECL (__isoc99_vwscanf); NLDBL_DECL (__isoc99_vfwscanf); NLDBL_DECL (__isoc99_vswscanf); +#endif /* This one does not exist in the normal interface, only __nldbl___vstrfmon really exists. */ @@ -82,22 +85,23 @@ since we don't compile with _FORTIFY_SOURCE. */ extern int __nldbl___vfprintf_chk (FILE *__restrict, int, const char *__restrict, _G_va_list); -extern int __nldbl___vfwprintf_chk (FILE *__restrict, int, - const wchar_t *__restrict, __gnuc_va_list); extern int __nldbl___vsprintf_chk (char *__restrict, int, size_t, const char *__restrict, _G_va_list) __THROW; extern int __nldbl___vsnprintf_chk (char *__restrict, size_t, int, size_t, const char *__restrict, _G_va_list) __THROW; -extern int __nldbl___vswprintf_chk (wchar_t *__restrict, size_t, int, size_t, - const wchar_t *__restrict, __gnuc_va_list) - __THROW; extern int __nldbl___vasprintf_chk (char **, int, const char *, _G_va_list) __THROW; extern int __nldbl___vdprintf_chk (int, int, const char *, _G_va_list); extern int __nldbl___obstack_vprintf_chk (struct obstack *, int, const char *, _G_va_list) __THROW; extern void __nldbl___vsyslog_chk (int, int, const char *, va_list); - +#if __OPTION_POSIX_WIDE_CHAR_DEVICE_IO +extern int __nldbl___vfwprintf_chk (FILE *__restrict, int, + const wchar_t *__restrict, __gnuc_va_list); +extern int __nldbl___vswprintf_chk (wchar_t *__restrict, size_t, int, size_t, + const wchar_t *__restrict, __gnuc_va_list) + __THROW; +#endif #endif /* __NLDBL_COMPAT_H */ Index: git/sysdeps/unix/sysv/linux/gethostid.c =================================================================== --- git.orig/sysdeps/unix/sysv/linux/gethostid.c 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 #include #include +#include #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 #include #include +#include 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 +#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 # 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 #include #include +#include #include #include @@ -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 +#ifdef _LIBC +# include +# include +# include +# include /* For EBUSY. */ +# include /* 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 #include #include +#include /* For EBUSY. */ +#include /* 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 + +/* 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 + +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 . + * + * 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