| From 2a5d7bcf0ff791c95ee1388772408a1bf4454694 Mon Sep 17 00:00:00 2001 |
| From: Khem Raj <raj.khem@gmail.com> |
| Date: Wed, 18 Mar 2015 01:33:49 +0000 |
| Subject: [PATCH 24/27] eglibc: Forward port eglibc options groups support |
| |
| Upstream-Status: Pending |
| |
| Signed-off-by: Khem Raj <raj.khem@gmail.com> |
| --- |
| Makeconfig | 20 +- |
| Makerules | 19 + |
| argp/Makefile | 2 + |
| argp/argp-fmtstream.c | 25 +- |
| argp/argp-help.c | 13 +- |
| argp/argp-namefrob.h | 2 + |
| catgets/Makefile | 17 +- |
| crypt/Makefile | 20 +- |
| crypt/crypt-entry.c | 13 + |
| crypt/crypt_common.c | 42 + |
| crypt/crypt_util.c | 18 - |
| csu/Makefile | 2 + |
| debug/Makefile | 41 +- |
| debug/segfault.c | 11 +- |
| debug/tst-chk1.c | 7 + |
| dlfcn/Makefile | 7 +- |
| elf/dl-support.c | 3 + |
| elf/rtld.c | 17 +- |
| extra-lib.mk | 6 +- |
| grp/Makefile | 5 + |
| hesiod/Makefile | 6 +- |
| iconv/Makefile | 7 + |
| iconv/gconv_db.c | 3 + |
| iconv/gconv_trans.c | 7 + |
| iconv/iconv_prog.c | 8 + |
| iconvdata/Makefile | 27 +- |
| include/netdb.h | 4 + |
| inet/Makefile | 22 +- |
| intl/Makefile | 3 +- |
| intl/dcigettext.c | 39 +- |
| io/Makefile | 18 +- |
| libidn/Makefile | 5 +- |
| libidn/toutf8.c | 11 +- |
| libio/Makefile | 66 +- |
| libio/__fpurge.c | 2 +- |
| libio/fileops.c | 10 +- |
| libio/iofwide.c | 26 + |
| libio/ioseekoff.c | 2 +- |
| libio/ioseekpos.c | 2 +- |
| libio/iosetbuffer.c | 4 + |
| libio/libioP.h | 18 +- |
| libio/wdummyfileops.c | 161 + |
| locale/C-ctype.c | 20 + |
| locale/Makefile | 41 +- |
| locale/catnames.c | 48 + |
| locale/dummy-setlocale.c | 33 + |
| locale/localeinfo.h | 2 +- |
| locale/programs/charmap-dir.c | 6 + |
| locale/programs/ld-collate.c | 17 +- |
| locale/programs/ld-ctype.c | 27 +- |
| locale/programs/ld-messages.c | 5 + |
| locale/programs/ld-time.c | 31 +- |
| locale/programs/linereader.c | 2 +- |
| locale/programs/localedef.c | 8 + |
| locale/programs/locfile.c | 5 +- |
| locale/programs/locfile.h | 59 +- |
| locale/setlocale.c | 30 - |
| locale/xlocale.c | 37 + |
| localedata/Makefile | 35 +- |
| login/Makefile | 17 +- |
| malloc/Makefile | 10 +- |
| malloc/memusage.c | 7 +- |
| malloc/memusage.sh | 2 +- |
| math/Makefile | 6 +- |
| misc/Makefile | 25 +- |
| misc/err.c | 11 + |
| misc/error.c | 5 + |
| misc/tst-efgcvt.c | 2 +- |
| nis/Makefile | 31 +- |
| nptl/Makefile | 28 +- |
| nptl/pthread_create.c | 5 + |
| nscd/Makefile | 33 +- |
| nscd/nis_hash.c | 3 + |
| nss/Makefile | 67 +- |
| nss/fixed-nsswitch.conf | 22 + |
| nss/fixed-nsswitch.functions | 121 + |
| nss/gen-fixed-nsswitch.c | 803 +++ |
| nss/getent.c | 46 +- |
| nss/getnssent_r.c | 9 +- |
| nss/nsswitch.c | 109 +- |
| nss/nsswitch.h | 18 +- |
| posix/Makefile | 94 +- |
| posix/bug-regex1.c | 3 + |
| posix/bug-regex6.c | 8 +- |
| posix/fnmatch.c | 6 +- |
| posix/fnmatch_loop.c | 23 +- |
| posix/glob.c | 15 +- |
| posix/regcomp.c | 98 +- |
| posix/regex.h | 11 + |
| posix/regex_internal.c | 45 +- |
| posix/regex_internal.h | 23 +- |
| posix/regexec-compat.c | 39 + |
| posix/regexec.c | 71 +- |
| posix/xregex.c | 8215 +++++++++++++++++++++++++++++++ |
| pwd/Makefile | 2 + |
| resolv/Makefile | 21 +- |
| stdio-common/Makefile | 35 +- |
| stdio-common/_i18n_number.h | 13 + |
| stdio-common/fxprintf.c | 5 + |
| stdio-common/printf_fp.c | 22 + |
| stdio-common/printf_fphex.c | 13 + |
| stdio-common/printf_size.c | 8 + |
| stdio-common/scanf14.c | 3 + |
| stdio-common/tst-popen.c | 3 + |
| stdio-common/tst-sprintf.c | 4 +- |
| stdio-common/tstdiomisc.c | 5 + |
| stdio-common/vfprintf.c | 31 +- |
| stdio-common/vfscanf.c | 53 +- |
| stdlib/Makefile | 34 +- |
| stdlib/strtod_l.c | 13 + |
| stdlib/tst-strtod.c | 5 + |
| streams/Makefile | 5 +- |
| string/Makefile | 14 +- |
| string/strcoll_l.c | 5 + |
| string/strerror_l.c | 5 + |
| string/strxfrm_l.c | 5 + |
| string/test-strcmp.c | 28 - |
| string/tst-strxfrm.c | 3 + |
| string/tst-strxfrm2.c | 3 + |
| sunrpc/Makefile | 44 +- |
| sysdeps/arm/Makefile | 5 +- |
| sysdeps/generic/ldsodefs.h | 8 + |
| sysdeps/gnu/Makefile | 3 +- |
| sysdeps/ieee754/ldbl-opt/Makefile | 27 +- |
| sysdeps/ieee754/ldbl-opt/nldbl-compat.c | 40 +- |
| sysdeps/ieee754/ldbl-opt/nldbl-compat.h | 24 +- |
| sysdeps/nptl/Makefile | 3 + |
| sysdeps/nptl/bits/libc-lock.h | 45 + |
| sysdeps/nptl/bits/libc-lockP.h | 50 +- |
| sysdeps/nptl/small-macros-fns.c | 72 + |
| sysdeps/unix/sysv/linux/gethostid.c | 6 + |
| sysdeps/unix/sysv/linux/libc_fatal.c | 3 + |
| time/Makefile | 18 +- |
| time/strftime_l.c | 12 +- |
| time/strptime_l.c | 14 +- |
| timezone/Makefile | 2 +- |
| wcsmbs/Makefile | 27 +- |
| wcsmbs/wcsmbsload.c | 13 + |
| wctype/Makefile | 14 +- |
| 139 files changed, 11363 insertions(+), 583 deletions(-) |
| create mode 100644 crypt/crypt_common.c |
| create mode 100644 libio/wdummyfileops.c |
| create mode 100644 locale/catnames.c |
| create mode 100644 locale/dummy-setlocale.c |
| create mode 100644 nscd/nis_hash.c |
| create mode 100644 nss/fixed-nsswitch.conf |
| create mode 100644 nss/fixed-nsswitch.functions |
| create mode 100644 nss/gen-fixed-nsswitch.c |
| create mode 100644 posix/regexec-compat.c |
| create mode 100644 posix/xregex.c |
| create mode 100644 sysdeps/nptl/small-macros-fns.c |
| |
| diff --git a/Makeconfig b/Makeconfig |
| index f136b88..52dae8f 100644 |
| --- a/Makeconfig |
| +++ b/Makeconfig |
| @@ -609,7 +609,7 @@ elf-objpfx = $(common-objpfx)elf/ |
| # and run on the build system, causes that program with those |
| # arguments to be run on the host for which the library is built. |
| ifndef test-wrapper |
| -test-wrapper = |
| +test-wrapper = $(cross-test-wrapper) |
| endif |
| # Likewise, but the name of the program is preceded by |
| # <variable>=<value> assignments for environment variables. |
| @@ -1089,6 +1089,24 @@ libm = $(common-objpfx)math/libm.a |
| libmvec = $(common-objpfx)mathvec/libmvec.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. |
| diff --git a/Makerules b/Makerules |
| index f9ca3f5..1dd41aa 100644 |
| --- a/Makerules |
| +++ b/Makerules |
| @@ -456,6 +456,25 @@ define sed-remove-objpfx |
| endef |
| endif |
| |
| +# Include targets in the selected option groups. |
| +aux += $(aux-y) |
| +extra-libs += $(extra-libs-y) |
| +extra-libs-others += $(extra-libs-others-y) |
| +extra-objs += $(extra-objs-y) |
| +install-bin += $(install-bin-y) |
| +install-others += $(install-others-y) |
| +install-sbin += $(install-sbin-y) |
| +modules += $(modules-y) |
| +others += $(others-y) |
| +others-pie += $(others-pie-y) |
| +routines += $(routines-y) |
| +static-only-routines += $(static-only-routines-y) |
| +sysdep_routines += $(sysdep_routines-y) |
| +test-srcs += $(test-srcs-y) |
| +tests += $(tests-y) |
| +xtests += $(xtests-y) |
| + |
| + |
| # Modify the list of routines we build for different targets |
| |
| ifeq (yes,$(build-shared)) |
| diff --git a/argp/Makefile b/argp/Makefile |
| index 1a87629..f7c1e40 100644 |
| --- a/argp/Makefile |
| +++ b/argp/Makefile |
| @@ -18,6 +18,8 @@ |
| # |
| # Makefile for argp. |
| # |
| +include ../option-groups.mak |
| + |
| subdir := argp |
| |
| include ../Makeconfig |
| diff --git a/argp/argp-fmtstream.c b/argp/argp-fmtstream.c |
| index 2b845e0..c344e7b 100644 |
| --- a/argp/argp-fmtstream.c |
| +++ b/argp/argp-fmtstream.c |
| @@ -42,6 +42,7 @@ |
| #ifdef _LIBC |
| # include <wchar.h> |
| # include <libio/libioP.h> |
| +# include <gnu/option-groups.h> |
| # define __vsnprintf(s, l, f, a) _IO_vsnprintf (s, l, f, a) |
| #endif |
| |
| @@ -100,7 +101,11 @@ __argp_fmtstream_free (argp_fmtstream_t fs) |
| __argp_fmtstream_update (fs); |
| if (fs->p > fs->buf) |
| { |
| +#ifdef _LIBC |
| __fxprintf (fs->stream, "%.*s", (int) (fs->p - fs->buf), fs->buf); |
| +#else |
| + fwrite_unlocked (fs->buf, 1, fs->p - fs->buf, fs->stream); |
| +#endif |
| } |
| free (fs->buf); |
| free (fs); |
| @@ -145,9 +150,17 @@ __argp_fmtstream_update (argp_fmtstream_t fs) |
| size_t i; |
| for (i = 0; i < pad; i++) |
| { |
| +#ifdef _LIBC |
| if (_IO_fwide (fs->stream, 0) > 0) |
| - putwc_unlocked (L' ', fs->stream); |
| + { |
| +#if ! _LIBC || __OPTION_POSIX_WIDE_CHAR_DEVICE_IO |
| + putwc_unlocked (L' ', fs->stream); |
| +#else |
| + abort (); |
| +#endif |
| + } |
| else |
| +#endif |
| putc_unlocked (' ', fs->stream); |
| } |
| } |
| @@ -308,9 +321,17 @@ __argp_fmtstream_update (argp_fmtstream_t fs) |
| *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 |
| diff --git a/argp/argp-help.c b/argp/argp-help.c |
| index b055e45..6b3c4c1 100644 |
| --- a/argp/argp-help.c |
| +++ b/argp/argp-help.c |
| @@ -51,6 +51,7 @@ char *alloca (); |
| #ifdef _LIBC |
| # include <../libio/libioP.h> |
| # include <wchar.h> |
| +# include <gnu/option-groups.h> |
| #endif |
| |
| #ifndef _ |
| @@ -1702,7 +1703,7 @@ char *__argp_basename (char *name) |
| } |
| |
| char * |
| -__argp_short_program_name (void) |
| +(__argp_short_program_name) (void) |
| { |
| # if HAVE_DECL_PROGRAM_INVOCATION_SHORT_NAME |
| return program_invocation_short_name; |
| @@ -1873,9 +1874,17 @@ __argp_failure (const struct argp_state *state, int status, int errnum, |
| #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) |
| diff --git a/argp/argp-namefrob.h b/argp/argp-namefrob.h |
| index f67c58f..e2002dc 100644 |
| --- a/argp/argp-namefrob.h |
| +++ b/argp/argp-namefrob.h |
| @@ -76,10 +76,12 @@ |
| #undef __argp_fmtstream_wmargin |
| #define __argp_fmtstream_wmargin argp_fmtstream_wmargin |
| |
| +#if 0 |
| #include "mempcpy.h" |
| #include "strcase.h" |
| #include "strchrnul.h" |
| #include "strndup.h" |
| +#endif |
| |
| /* normal libc functions we call */ |
| #undef __flockfile |
| diff --git a/catgets/Makefile b/catgets/Makefile |
| index 4624a88..05714fd 100644 |
| --- a/catgets/Makefile |
| +++ b/catgets/Makefile |
| @@ -22,20 +22,23 @@ subdir := catgets |
| |
| include ../Makeconfig |
| |
| +include ../option-groups.mak |
| + |
| headers = nl_types.h |
| -routines = catgets open_catalog |
| -others = gencat |
| -install-bin = gencat |
| -extra-objs = $(gencat-modules:=.o) |
| +routines-$(OPTION_EGLIBC_CATGETS) := catgets open_catalog |
| +others-$(OPTION_EGLIBC_CATGETS) := gencat |
| +install-bin-$(OPTION_EGLIBC_CATGETS) := gencat |
| +extra-objs-$(OPTION_EGLIBC_CATGETS) := $(gencat-modules:=.o) |
| |
| -tests = tst-catgets |
| -test-srcs = test-gencat |
| +tests-$(OPTION_EGLIBC_CATGETS) := tst-catgets |
| +test-srcs-$(OPTION_EGLIBC_CATGETS) := test-gencat |
| |
| +ifeq (y,$(OPTION_EGLIBC_CATGETS)) |
| ifeq ($(run-built-tests),yes) |
| tests-special += $(objpfx)de/libc.cat $(objpfx)test1.cat $(objpfx)test2.cat \ |
| $(objpfx)sample.SJIS.cat $(objpfx)test-gencat.out |
| endif |
| - |
| +endif |
| gencat-modules = xmalloc |
| |
| # To find xmalloc.c |
| diff --git a/crypt/Makefile b/crypt/Makefile |
| index 34c4dd7..7c18c88 100644 |
| --- a/crypt/Makefile |
| +++ b/crypt/Makefile |
| @@ -18,21 +18,25 @@ |
| # |
| # Sub-makefile for crypt() portion of the library. |
| # |
| +include ../option-groups.mak |
| + |
| subdir := crypt |
| |
| include ../Makeconfig |
| |
| headers := crypt.h |
| |
| -extra-libs := libcrypt |
| -extra-libs-others := $(extra-libs) |
| +extra-libs-$(OPTION_EGLIBC_CRYPT) := libcrypt |
| +extra-libs-others-y := $(extra-libs-y) |
| |
| -libcrypt-routines := crypt-entry md5-crypt sha256-crypt sha512-crypt crypt \ |
| - crypt_util |
| +libcrypt-routines :=crypt-entry md5-crypt sha256-crypt sha512-crypt crypt_common |
| +libcrypt-routines-$(OPTION_EGLIBC_CRYPT_UFC) := crypt crypt_util |
| +libcrypt-routines += $(libcrypt-routines-y) |
| |
| -tests := cert md5c-test sha256c-test sha512c-test badsalttest |
| +tests-$(OPTION_EGLIBC_CRYPT) := md5c-test sha256c-test sha512c-test badsalttest |
| +tests-$(OPTION_EGLIBC_CRYPT_UFC) += cert |
| |
| -ifeq ($(crypt-in-libc),yes) |
| +ifeq ($(crypt-in-libc)$(OPTION_EGLIBC_CRYPT),yesy) |
| routines += $(libcrypt-routines) |
| endif |
| |
| @@ -44,7 +48,7 @@ LDLIBS-crypt.so = -lfreebl3 |
| else |
| libcrypt-routines += md5 sha256 sha512 |
| |
| -tests += md5test sha256test sha512test |
| +tests-$(OPTION_EGLIBC_CRYPT) += md5test sha256test sha512test |
| |
| # The test md5test-giant uses up to 400 MB of RSS and runs on a fast |
| # machine over a minute. |
| @@ -64,8 +68,10 @@ $(objpfx)sha256test: $(patsubst %, $(objpfx)%.o,$(sha256-routines)) |
| $(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 |
| diff --git a/crypt/crypt-entry.c b/crypt/crypt-entry.c |
| index 7e655ba..6ae5c2b 100644 |
| --- a/crypt/crypt-entry.c |
| +++ b/crypt/crypt-entry.c |
| @@ -27,6 +27,7 @@ |
| #include <stdio.h> |
| #endif |
| #include <string.h> |
| +#include <gnu/option-groups.h> |
| #include <errno.h> |
| #include <fips-private.h> |
| |
| @@ -76,9 +77,11 @@ __crypt_r (key, salt, data) |
| const char *salt; |
| struct crypt_data * __restrict data; |
| { |
| +#if __OPTION_EGLIBC_CRYPT_UFC |
| ufc_long res[4]; |
| char ktab[9]; |
| ufc_long xx = 25; /* to cope with GCC long long compiler bugs */ |
| +#endif /*__OPTION_EGLIBC_CRYPT_UFC*/ |
| |
| #ifdef _LIBC |
| /* Try to find out whether we have to use MD5 encryption replacement. */ |
| @@ -105,6 +108,7 @@ __crypt_r (key, salt, data) |
| sizeof (struct crypt_data)); |
| #endif |
| |
| +#if __OPTION_EGLIBC_CRYPT_UFC |
| /* |
| * Hack DES tables according to salt |
| */ |
| @@ -144,6 +148,10 @@ __crypt_r (key, salt, data) |
| */ |
| _ufc_output_conversion_r (res[0], res[1], salt, data); |
| return data->crypt_3_buf; |
| +#else /* __OPTION_EGLIBC_CRYPT_UFC */ |
| + __set_errno (ENOSYS); |
| + return NULL; |
| +#endif /* __OPTION_EGLIBC_CRYPT_UFC */ |
| } |
| weak_alias (__crypt_r, crypt_r) |
| |
| @@ -168,7 +176,12 @@ crypt (key, salt) |
| return __sha512_crypt (key, salt); |
| #endif |
| |
| +#if __OPTION_EGLIBC_CRYPT_UFC |
| return __crypt_r (key, salt, &_ufc_foobar); |
| +#else /* __OPTION_EGLIBC_CRYPT_UFC */ |
| + __set_errno (ENOSYS); |
| + return NULL; |
| +#endif /* __OPTION_EGLIBC_CRYPT_UFC */ |
| } |
| |
| |
| diff --git a/crypt/crypt_common.c b/crypt/crypt_common.c |
| new file mode 100644 |
| index 0000000..cce6a31 |
| --- /dev/null |
| +++ b/crypt/crypt_common.c |
| @@ -0,0 +1,42 @@ |
| +/* |
| + * crypt: crypt(3) implementation |
| + * |
| + * Copyright (C) 1991-2014 Free Software Foundation, Inc. |
| + * |
| + * This library is free software; you can redistribute it and/or |
| + * modify it under the terms of the GNU Lesser General Public |
| + * License as published by the Free Software Foundation; either |
| + * version 2.1 of the License, or (at your option) any later version. |
| + * |
| + * This library is distributed in the hope that it will be useful, |
| + * but WITHOUT ANY WARRANTY; without even the implied warranty of |
| + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU |
| + * Lesser General Public License for more details. |
| + * |
| + * You should have received a copy of the GNU Lesser General Public |
| + * License along with this library; see the file COPYING.LIB. If not, |
| + * see <http://www.gnu.org/licenses/>. |
| + * |
| + * General Support routines |
| + * |
| + */ |
| + |
| +#include "crypt-private.h" |
| + |
| +/* Table with characters for base64 transformation. */ |
| +static const char b64t[64] = |
| +"./0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz"; |
| + |
| +void |
| +__b64_from_24bit (char **cp, int *buflen, |
| + unsigned int b2, unsigned int b1, unsigned int b0, |
| + int n) |
| +{ |
| + unsigned int w = (b2 << 16) | (b1 << 8) | b0; |
| + while (n-- > 0 && (*buflen) > 0) |
| + { |
| + *(*cp)++ = b64t[w & 0x3f]; |
| + --(*buflen); |
| + w >>= 6; |
| + } |
| +} |
| diff --git a/crypt/crypt_util.c b/crypt/crypt_util.c |
| index 1597885..9297974 100644 |
| --- a/crypt/crypt_util.c |
| +++ b/crypt/crypt_util.c |
| @@ -242,10 +242,6 @@ static ufc_long eperm32tab[4][256][2]; |
| */ |
| static ufc_long efp[16][64][2]; |
| |
| -/* Table with characters for base64 transformation. */ |
| -static const char b64t[64] = |
| -"./0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz"; |
| - |
| /* |
| * For use by the old, non-reentrant routines |
| * (crypt/encrypt/setkey) |
| @@ -949,17 +945,3 @@ setkey(__key) |
| { |
| __setkey_r(__key, &_ufc_foobar); |
| } |
| - |
| -void |
| -__b64_from_24bit (char **cp, int *buflen, |
| - unsigned int b2, unsigned int b1, unsigned int b0, |
| - int n) |
| -{ |
| - unsigned int w = (b2 << 16) | (b1 << 8) | b0; |
| - while (n-- > 0 && (*buflen) > 0) |
| - { |
| - *(*cp)++ = b64t[w & 0x3f]; |
| - --(*buflen); |
| - w >>= 6; |
| - } |
| -} |
| diff --git a/csu/Makefile b/csu/Makefile |
| index 9f0855a..b1c3363 100644 |
| --- a/csu/Makefile |
| +++ b/csu/Makefile |
| @@ -22,6 +22,8 @@ |
| # crtn.o, special "initializer" and "finalizer" files used in the link |
| # to make the .init and .fini sections work right. |
| |
| +include ../option-groups.mak |
| + |
| subdir := csu |
| |
| include ../Makeconfig |
| diff --git a/debug/Makefile b/debug/Makefile |
| index 9ff357b..d23d97d 100644 |
| --- a/debug/Makefile |
| +++ b/debug/Makefile |
| @@ -18,6 +18,8 @@ |
| # |
| # Sub-makefile for debug portion of the library. |
| # |
| +include ../option-groups.mak |
| + |
| subdir := debug |
| |
| include ../Makeconfig |
| @@ -27,7 +29,7 @@ headers := execinfo.h |
| # Note that ptsname_r_chk and getlogin_r are not here, but in |
| # login/Makefile instead. If that subdir is omitted from the |
| # build, its _FORTIFY_SOURCE support will be too. |
| -routines = backtrace backtracesyms backtracesymsfd noophooks \ |
| +routines = noophooks \ |
| memcpy_chk memmove_chk mempcpy_chk memset_chk stpcpy_chk \ |
| strcat_chk strcpy_chk strncat_chk strncpy_chk stpncpy_chk \ |
| sprintf_chk vsprintf_chk snprintf_chk vsnprintf_chk \ |
| @@ -36,20 +38,27 @@ routines = backtrace backtracesyms backtracesymsfd noophooks \ |
| read_chk pread_chk pread64_chk recv_chk recvfrom_chk \ |
| readlink_chk readlinkat_chk getwd_chk getcwd_chk \ |
| realpath_chk fread_chk fread_u_chk \ |
| - wctomb_chk wcscpy_chk wmemcpy_chk wmemmove_chk wmempcpy_chk \ |
| - wcpcpy_chk wcsncpy_chk wcscat_chk wcsncat_chk wmemset_chk \ |
| - wcpncpy_chk \ |
| - swprintf_chk vswprintf_chk wprintf_chk fwprintf_chk \ |
| - vwprintf_chk vfwprintf_chk fgetws_chk fgetws_u_chk \ |
| confstr_chk getgroups_chk ttyname_r_chk \ |
| - gethostname_chk getdomainname_chk wcrtomb_chk mbsnrtowcs_chk \ |
| - wcsnrtombs_chk mbsrtowcs_chk wcsrtombs_chk mbstowcs_chk \ |
| - wcstombs_chk asprintf_chk vasprintf_chk dprintf_chk \ |
| + gethostname_chk getdomainname_chk \ |
| + asprintf_chk vasprintf_chk dprintf_chk \ |
| vdprintf_chk obprintf_chk \ |
| longjmp_chk ____longjmp_chk \ |
| fdelt_chk poll_chk ppoll_chk \ |
| stack_chk_fail fortify_fail \ |
| $(static-only-routines) |
| +routines-$(OPTION_EGLIBC_BACKTRACE) += backtrace backtracesyms backtracesymsfd |
| +routines-$(OPTION_POSIX_WIDE_CHAR_DEVICE_IO) \ |
| + += wprintf_chk fwprintf_chk \ |
| + vwprintf_chk vfwprintf_chk fgetws_chk fgetws_u_chk |
| +routines-$(OPTION_POSIX_C_LANG_WIDE_CHAR) \ |
| + += wctomb_chk wcscpy_chk wmemcpy_chk wmemmove_chk wmempcpy_chk \ |
| + wcpcpy_chk wcsncpy_chk wcscat_chk wcsncat_chk wmemset_chk \ |
| + wcpncpy_chk \ |
| + swprintf_chk vswprintf_chk \ |
| + wcrtomb_chk mbsnrtowcs_chk \ |
| + wcsnrtombs_chk mbsrtowcs_chk wcsrtombs_chk mbstowcs_chk \ |
| + wcstombs_chk |
| + |
| static-only-routines := warning-nop stack_chk_fail_local |
| |
| CFLAGS-backtrace.c = -fno-omit-frame-pointer |
| @@ -131,11 +140,15 @@ LDFLAGS-tst-backtrace4 = -rdynamic |
| LDFLAGS-tst-backtrace5 = -rdynamic |
| LDFLAGS-tst-backtrace6 = -rdynamic |
| |
| -tests = backtrace-tst tst-longjmp_chk tst-chk1 tst-chk2 tst-chk3 \ |
| - tst-lfschk1 tst-lfschk2 tst-lfschk3 test-strcpy_chk test-stpcpy_chk \ |
| - tst-chk4 tst-chk5 tst-chk6 tst-lfschk4 tst-lfschk5 tst-lfschk6 \ |
| - tst-longjmp_chk2 tst-backtrace2 tst-backtrace3 tst-backtrace4 \ |
| - tst-backtrace5 tst-backtrace6 |
| +tests = tst-longjmp_chk test-strcpy_chk test-stpcpy_chk tst-longjmp_chk2 |
| +tests-$(OPTION_EGLIBC_LOCALE_CODE) \ |
| + += tst-chk1 tst-chk2 tst-chk3 tst-lfschk1 tst-lfschk2 tst-lfschk3 |
| +tests-$(OPTION_EGLIBC_BACKTRACE) \ |
| + += backtrace-tst tst-backtrace2 tst-backtrace3 tst-backtrace4 \ |
| + tst-backtrace5 tst-backtrace6 |
| +ifeq (yy,$(OPTION_EGLIBC_LOCALE_CODE)$(OPTION_EGLIBC_CXX_TESTS)) |
| +tests += tst-chk4 tst-chk5 tst-chk6 tst-lfschk4 tst-lfschk5 tst-lfschk6 |
| +endif |
| |
| ifeq (,$(CXX)) |
| tests-unsupported = tst-chk4 tst-chk5 tst-chk6 \ |
| diff --git a/debug/segfault.c b/debug/segfault.c |
| index 3459a2a..ee9a146 100644 |
| --- a/debug/segfault.c |
| +++ b/debug/segfault.c |
| @@ -30,6 +30,7 @@ |
| #include <unistd.h> |
| #include <_itoa.h> |
| #include <ldsodefs.h> |
| +#include <gnu/option-groups.h> |
| |
| /* This file defines macros to access the content of the sigcontext element |
| passed up by the signal handler. */ |
| @@ -68,11 +69,13 @@ write_strsignal (int fd, int signal) |
| static void |
| catch_segfault (int signal, SIGCONTEXT ctx) |
| { |
| - int fd, cnt, i; |
| - void **arr; |
| + int fd; |
| struct sigaction sa; |
| +#if __OPTION_EGLIBC_BACKTRACE |
| + int cnt, i; |
| + void **arr; |
| uintptr_t pc; |
| - |
| +#endif |
| /* This is the name of the file we are writing to. If none is given |
| or we cannot write to this file write to stderr. */ |
| fd = 2; |
| @@ -91,6 +94,7 @@ catch_segfault (int signal, SIGCONTEXT ctx) |
| REGISTER_DUMP; |
| #endif |
| |
| +#if __OPTION_EGLIBC_BACKTRACE |
| WRITE_STRING ("\nBacktrace:\n"); |
| |
| /* Get the backtrace. */ |
| @@ -113,6 +117,7 @@ catch_segfault (int signal, SIGCONTEXT ctx) |
| |
| /* Now generate nicely formatted output. */ |
| __backtrace_symbols_fd (arr + i, cnt - i, fd); |
| +#endif |
| |
| #ifdef HAVE_PROC_SELF |
| /* Now the link map. */ |
| diff --git a/debug/tst-chk1.c b/debug/tst-chk1.c |
| index 53559e6..362d92a 100644 |
| --- a/debug/tst-chk1.c |
| +++ b/debug/tst-chk1.c |
| @@ -31,6 +31,7 @@ |
| #include <sys/select.h> |
| #include <sys/socket.h> |
| #include <sys/un.h> |
| +#include <gnu/option-groups.h> |
| |
| |
| #define obstack_chunk_alloc malloc |
| @@ -307,6 +308,7 @@ do_test (void) |
| snprintf (buf + 8, l0 + 3, "%d", num2); |
| CHK_FAIL_END |
| |
| +#if __OPTION_POSIX_C_LANG_WIDE_CHAR |
| CHK_FAIL_START |
| swprintf (wbuf + 8, 3, L"%d", num1); |
| CHK_FAIL_END |
| @@ -314,6 +316,7 @@ do_test (void) |
| CHK_FAIL_START |
| swprintf (wbuf + 8, l0 + 3, L"%d", num1); |
| CHK_FAIL_END |
| +#endif /* __OPTION_POSIX_C_LANG_WIDE_CHAR */ |
| # endif |
| |
| memcpy (buf, str1 + 2, l0 + 9); |
| @@ -381,6 +384,7 @@ do_test (void) |
| CHK_FAIL_END |
| #endif |
| |
| +#if __OPTION_POSIX_C_LANG_WIDE_CHAR |
| |
| /* These ops can be done without runtime checking of object size. */ |
| wmemcpy (wbuf, L"abcdefghij", 10); |
| @@ -605,6 +609,7 @@ do_test (void) |
| CHK_FAIL_END |
| #endif |
| |
| +#endif /* __OPTION_POSIX_C_LANG_WIDE_CHAR */ |
| |
| /* Now checks for %n protection. */ |
| |
| @@ -1192,6 +1197,7 @@ do_test (void) |
| # endif |
| #endif |
| |
| +#if __OPTION_POSIX_C_LANG_WIDE_CHAR |
| if (setlocale (LC_ALL, "de_DE.UTF-8") != NULL) |
| { |
| assert (MB_CUR_MAX <= 10); |
| @@ -1348,6 +1354,7 @@ do_test (void) |
| puts ("cannot set locale"); |
| ret = 1; |
| } |
| +#endif /* __OPTION_POSIX_C_LANG_WIDE_CHAR */ |
| |
| int fd = posix_openpt (O_RDWR); |
| if (fd != -1) |
| diff --git a/dlfcn/Makefile b/dlfcn/Makefile |
| index 759780d..3827607 100644 |
| --- a/dlfcn/Makefile |
| +++ b/dlfcn/Makefile |
| @@ -15,6 +15,8 @@ |
| # License along with the GNU C Library; if not, see |
| # <http://www.gnu.org/licenses/>. |
| |
| +include ../option-groups.mak |
| + |
| subdir := dlfcn |
| |
| include ../Makeconfig |
| @@ -36,8 +38,11 @@ endif |
| ifeq (yes,$(build-shared)) |
| tests = glrefmain failtest tst-dladdr default errmsg1 tstcxaatexit \ |
| bug-dlopen1 bug-dlsym1 tst-dlinfo bug-atexit1 bug-atexit2 \ |
| - bug-atexit3 tstatexit bug-dl-leaf tst-rec-dlopen |
| + tstatexit bug-dl-leaf tst-rec-dlopen |
| endif |
| + |
| +tests-$(OPTION_EGLIBC_CXX_TESTS) += bug-atexit3 |
| + |
| modules-names = glreflib1 glreflib2 glreflib3 failtestmod defaultmod1 \ |
| defaultmod2 errmsg1mod modatexit modcxaatexit \ |
| bug-dlsym1-lib1 bug-dlsym1-lib2 bug-atexit1-lib \ |
| diff --git a/elf/dl-support.c b/elf/dl-support.c |
| index 4d036f1..c15f405 100644 |
| --- a/elf/dl-support.c |
| +++ b/elf/dl-support.c |
| @@ -19,6 +19,7 @@ |
| /* This file defines some things that for the dynamic linker are defined in |
| rtld.c and dl-sysdep.c in ways appropriate to bootstrap dynamic linking. */ |
| |
| +#include <gnu/option-groups.h> |
| #include <errno.h> |
| #include <libintl.h> |
| #include <stdlib.h> |
| @@ -42,7 +43,9 @@ char **_dl_argv = &__progname; /* This is checked for some error messages. */ |
| 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; |
| diff --git a/elf/rtld.c b/elf/rtld.c |
| index 6d3add7..fc3a2db 100644 |
| --- a/elf/rtld.c |
| +++ b/elf/rtld.c |
| @@ -16,6 +16,7 @@ |
| License along with the GNU C Library; if not, see |
| <http://www.gnu.org/licenses/>. */ |
| |
| +#include <gnu/option-groups.h> |
| #include <errno.h> |
| #include <dlfcn.h> |
| #include <fcntl.h> |
| @@ -2201,6 +2202,7 @@ print_missing_version (int errcode __attribute__ ((unused)), |
| objname, errstring); |
| } |
| |
| +#if __OPTION_EGLIBC_RTLD_DEBUG |
| /* Nonzero if any of the debugging options is enabled. */ |
| static int any_debug attribute_relro; |
| |
| @@ -2310,6 +2312,7 @@ a filename can be specified using the LD_DEBUG_OUTPUT environment variable.\n"); |
| _exit (0); |
| } |
| } |
| +#endif /* __OPTION_EGLIBC_RTLD_DEBUG */ |
| |
| static void |
| process_dl_audit (char *str) |
| @@ -2349,8 +2352,9 @@ process_envvars (enum mode *modep) |
| char **runp = _environ; |
| char *envline; |
| enum mode mode = normal; |
| +#if __OPTION_EGLIBC_RTLD_DEBUG |
| char *debug_output = NULL; |
| - |
| +#endif |
| /* This is the default place for profiling data file. */ |
| GLRO(dl_profile_output) |
| = &"/var/tmp\0/var/profile"[__libc_enable_secure ? 9 : 0]; |
| @@ -2377,12 +2381,14 @@ process_envvars (enum mode *modep) |
| break; |
| |
| case 5: |
| +#if __OPTION_EGLIBC_RTLD_DEBUG |
| /* Debugging of the dynamic linker? */ |
| if (memcmp (envline, "DEBUG", 5) == 0) |
| { |
| process_dl_debug (&envline[6]); |
| break; |
| } |
| +#endif |
| if (memcmp (envline, "AUDIT", 5) == 0) |
| process_dl_audit (&envline[6]); |
| break; |
| @@ -2448,13 +2454,14 @@ process_envvars (enum mode *modep) |
| break; |
| } |
| |
| +#if __OPTION_EGLIBC_RTLD_DEBUG |
| /* Where to place the profiling data file. */ |
| if (memcmp (envline, "DEBUG_OUTPUT", 12) == 0) |
| { |
| debug_output = &envline[13]; |
| break; |
| } |
| - |
| +#endif |
| if (!__libc_enable_secure |
| && memcmp (envline, "DYNAMIC_WEAK", 12) == 0) |
| GLRO(dl_dynamic_weak) = 1; |
| @@ -2491,7 +2498,9 @@ process_envvars (enum mode *modep) |
| { |
| mode = trace; |
| GLRO(dl_verbose) = 1; |
| +#if __OPTION_EGLIBC_RTLD_DEBUG |
| GLRO(dl_debug_mask) |= DL_DEBUG_PRELINK; |
| +#endif |
| GLRO(dl_trace_prelink) = &envline[17]; |
| } |
| break; |
| @@ -2538,12 +2547,15 @@ process_envvars (enum mode *modep) |
| if (__access ("/etc/suid-debug", F_OK) != 0) |
| { |
| unsetenv ("MALLOC_CHECK_"); |
| +#if __OPTION_EGLIBC_RTLD_DEBUG |
| GLRO(dl_debug_mask) = 0; |
| +#endif |
| } |
| |
| if (mode != normal) |
| _exit (5); |
| } |
| +#if __OPTION_EGLIBC_RTLD_DEBUG |
| /* If we have to run the dynamic linker in debugging mode and the |
| LD_DEBUG_OUTPUT environment variable is given, we write the debug |
| messages to this file. */ |
| @@ -2568,6 +2580,7 @@ process_envvars (enum mode *modep) |
| /* We use standard output if opening the file failed. */ |
| GLRO(dl_debug_fd) = STDOUT_FILENO; |
| } |
| +#endif /* __OPTION_EGLIBC_RTLD_DEBUG */ |
| } |
| |
| |
| diff --git a/extra-lib.mk b/extra-lib.mk |
| index b10748d..d71a06f 100644 |
| --- a/extra-lib.mk |
| +++ b/extra-lib.mk |
| @@ -25,7 +25,9 @@ install-lib := $(install-lib) |
| extra-objs := $(extra-objs) |
| |
| # The modules that go in $(lib). |
| -all-$(lib)-routines := $($(lib)-routines) $($(lib)-sysdep_routines) |
| +all-$(lib)-routines := $($(lib)-routines) \ |
| + $($(lib)-routines-y) \ |
| + $($(lib)-sysdep_routines) |
| |
| # Add each flavor of library to the lists of things to build and install. |
| install-lib += $(foreach o,$(object-suffixes-$(lib)),$(lib:lib%=$(libtype$o))) |
| @@ -101,7 +103,7 @@ endif |
| endif |
| |
| # This will define `libof-ROUTINE := LIB' for each of the routines. |
| -cpp-srcs-left := $($(lib)-routines) $($(lib)-sysdep_routines) |
| +cpp-srcs-left := $(all-$(lib)-routines) |
| ifneq (,$(cpp-srcs-left)) |
| include $(patsubst %,$(..)cppflags-iterator.mk,$(cpp-srcs-left)) |
| endif |
| diff --git a/grp/Makefile b/grp/Makefile |
| index c63b552..7486f32 100644 |
| --- a/grp/Makefile |
| +++ b/grp/Makefile |
| @@ -18,6 +18,8 @@ |
| # |
| # Sub-makefile for grp portion of the library. |
| # |
| +include ../option-groups.mak |
| + |
| subdir := grp |
| |
| include ../Makeconfig |
| @@ -29,6 +31,9 @@ routines := fgetgrent initgroups setgroups \ |
| 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 |
| diff --git a/hesiod/Makefile b/hesiod/Makefile |
| index ac0bc01..38263b4 100644 |
| --- a/hesiod/Makefile |
| +++ b/hesiod/Makefile |
| @@ -18,12 +18,14 @@ |
| # |
| # Sub-makefile for hesiod portion of the library. |
| # |
| +include ../option-groups.mak |
| + |
| subdir := hesiod |
| |
| include ../Makeconfig |
| |
| -extra-libs := libnss_hesiod |
| -extra-libs-others = $(extra-libs) |
| +extra-libs-$(OPTION_EGLIBC_INET) += libnss_hesiod |
| +extra-libs-others-y += $(extra-libs-y) |
| |
| subdir-dirs = nss_hesiod |
| vpath %.c nss_hesiod |
| diff --git a/iconv/Makefile b/iconv/Makefile |
| index 0d55eda..a1847c6 100644 |
| --- a/iconv/Makefile |
| +++ b/iconv/Makefile |
| @@ -18,6 +18,8 @@ |
| # |
| # Makefile for iconv. |
| # |
| +include ../option-groups.mak |
| + |
| subdir := iconv |
| |
| include ../Makeconfig |
| @@ -39,6 +41,11 @@ CFLAGS-iconv_charmap.c = -I../locale/programs |
| CFLAGS-dummy-repertoire.c = -I../locale/programs |
| CFLAGS-charmap.c = -DCHARMAP_PATH='"$(i18ndir)/charmaps"' \ |
| -DDEFAULT_CHARMAP=null_pointer -DNEED_NULL_POINTER |
| + |
| +ifneq (y,$(OPTION_EGLIBC_SPAWN)) |
| +CFLAGS-charmap-dir.c += -DNO_UNCOMPRESS |
| +endif |
| + |
| CFLAGS-linereader.c = -DNO_TRANSLITERATION |
| CFLAGS-simple-hash.c = -I../locale |
| |
| diff --git a/iconv/gconv_db.c b/iconv/gconv_db.c |
| index ce46216..ea18964 100644 |
| --- a/iconv/gconv_db.c |
| +++ b/iconv/gconv_db.c |
| @@ -25,6 +25,7 @@ |
| #include <sys/param.h> |
| #include <bits/libc-lock.h> |
| #include <locale/localeinfo.h> |
| +#include <gnu/option-groups.h> |
| |
| #include <dlfcn.h> |
| #include <gconv_int.h> |
| @@ -828,9 +829,11 @@ free_modules_db (struct gconv_module *node) |
| /* 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; |
| diff --git a/iconv/gconv_trans.c b/iconv/gconv_trans.c |
| index 5d5d4d7..a7d3072 100644 |
| --- a/iconv/gconv_trans.c |
| +++ b/iconv/gconv_trans.c |
| @@ -23,6 +23,7 @@ |
| #include <stdint.h> |
| #include <string.h> |
| #include <stdlib.h> |
| +#include <gnu/option-groups.h> |
| |
| #include <bits/libc-lock.h> |
| #include "gconv_int.h" |
| @@ -38,15 +39,19 @@ __gconv_transliterate (struct __gconv_step *step, |
| unsigned char **outbufstart, size_t *irreversible) |
| { |
| /* Find out about the locale's transliteration. */ |
| +#if __OPTION_EGLIBC_LOCALE_CODE |
| uint_fast32_t size; |
| const uint32_t *from_idx; |
| const uint32_t *from_tbl; |
| const uint32_t *to_idx; |
| const uint32_t *to_tbl; |
| +#endif |
| const uint32_t *winbuf; |
| const uint32_t *winbufend; |
| +#if __OPTION_EGLIBC_LOCALE_CODE |
| uint_fast32_t low; |
| uint_fast32_t high; |
| +#endif |
| |
| /* The input buffer. There are actually 4-byte values. */ |
| winbuf = (const uint32_t *) *inbufp; |
| @@ -58,6 +63,7 @@ __gconv_transliterate (struct __gconv_step *step, |
| PTR_DEMANGLE (fct); |
| #endif |
| |
| +#if __OPTION_EGLIBC_LOCALE_CODE |
| /* If there is no transliteration information in the locale don't do |
| anything and return the error. */ |
| size = _NL_CURRENT_WORD (LC_CTYPE, _NL_CTYPE_TRANSLIT_TAB_SIZE); |
| @@ -193,6 +199,7 @@ __gconv_transliterate (struct __gconv_step *step, |
| sorted. */ |
| break; |
| } |
| +#endif |
| |
| /* One last chance: use the default replacement. */ |
| if (_NL_CURRENT_WORD (LC_CTYPE, _NL_CTYPE_TRANSLIT_DEFAULT_MISSING_LEN) != 0) |
| diff --git a/iconv/iconv_prog.c b/iconv/iconv_prog.c |
| index e249bce..403ece5 100644 |
| --- a/iconv/iconv_prog.c |
| +++ b/iconv/iconv_prog.c |
| @@ -35,6 +35,7 @@ |
| #ifdef _POSIX_MAPPED_FILES |
| # include <sys/mman.h> |
| #endif |
| +#include <gnu/option-groups.h> |
| #include <charmap.h> |
| #include <gconv_int.h> |
| #include "iconv_prog.h" |
| @@ -221,10 +222,17 @@ main (int argc, char *argv[]) |
| bool to_wrong = |
| (iconv_open (to_code, "UTF-8") == (iconv_t) -1 |
| && errno == EINVAL); |
| +#if __OPTION_EGLIBC_LOCALE_CODE |
| const char *from_pretty = |
| (from_code[0] ? from_code : nl_langinfo (CODESET)); |
| const char *to_pretty = |
| (orig_to_code[0] ? orig_to_code : nl_langinfo (CODESET)); |
| +#else |
| + const char *from_pretty = |
| + (from_code[0] ? from_code : "ANSI_X3.4-1968"); |
| + const char *to_pretty = |
| + (orig_to_code[0] ? orig_to_code : "ANSI_X3.4-1968"); |
| +#endif |
| |
| if (from_wrong) |
| { |
| diff --git a/iconvdata/Makefile b/iconvdata/Makefile |
| index a3d1d09..0832708 100644 |
| --- a/iconvdata/Makefile |
| +++ b/iconvdata/Makefile |
| @@ -18,12 +18,15 @@ |
| # |
| # Makefile for iconv data and code. |
| # |
| +include ../option-groups.mak |
| + |
| subdir := iconvdata |
| |
| include ../Makeconfig |
| |
| # Names of all the shared objects which implement the transformations. |
| -modules := ISO8859-1 ISO8859-2 ISO8859-3 ISO8859-4 ISO8859-5 \ |
| +modules-$(OPTION_EGLIBC_CHARSETS) \ |
| + := ISO8859-1 ISO8859-2 ISO8859-3 ISO8859-4 ISO8859-5 \ |
| ISO8859-6 ISO8859-7 ISO8859-8 ISO8859-9 ISO8859-10 \ |
| ISO8859-11 ISO8859-13 ISO8859-14 ISO8859-15 ISO8859-16 \ |
| T.61 ISO_6937 SJIS KOI-8 HP-ROMAN8 HP-ROMAN9 EBCDIC-AT-DE \ |
| @@ -63,11 +66,13 @@ modules := ISO8859-1 ISO8859-2 ISO8859-3 ISO8859-4 ISO8859-5 \ |
| MAC-CENTRALEUROPE KOI8-RU ISO8859-9E \ |
| CP770 CP771 CP772 CP773 CP774 |
| |
| -modules.so := $(addsuffix .so, $(modules)) |
| +modules.so := $(addsuffix .so, $(modules-y)) |
| |
| ifeq (yes,$(build-shared)) |
| tests = bug-iconv1 bug-iconv2 tst-loading tst-e2big tst-iconv4 bug-iconv4 \ |
| - tst-iconv6 bug-iconv5 bug-iconv6 tst-iconv7 bug-iconv8 bug-iconv9 |
| + tst-iconv6 bug-iconv5 bug-iconv8 bug-iconv9 |
| +tests-$(OPTION_EGLIBC_LOCALE_CODE) += bug-iconv6 tst-iconv7 |
| + |
| ifeq ($(have-thread-library),yes) |
| tests += bug-iconv3 |
| endif |
| @@ -127,13 +132,13 @@ ifeq (yes,$(build-shared)) |
| # Rule to generate the shared objects. |
| charmaps = ../localedata/charmaps |
| -include $(objpfx)iconv-rules |
| -extra-modules-left := $(modules) |
| +extra-modules-left := $(modules-y) |
| include extra-module.mk |
| |
| |
| extra-objs += $(modules.so) |
| -install-others = $(addprefix $(inst_gconvdir)/, $(modules.so)) \ |
| - $(inst_gconvdir)/gconv-modules |
| +install-others-y += $(addprefix $(inst_gconvdir)/, $(modules.so)) |
| +install-others-$(OPTION_EGLIBC_CHARSETS) += $(inst_gconvdir)/gconv-modules |
| |
| # We can build the conversion tables for numerous charsets automatically. |
| |
| @@ -201,7 +206,7 @@ before-compile += $(addprefix $(objpfx),$(generated-modules:=.h)) |
| ifndef avoid-generated |
| $(objpfx)iconv-rules: Makefile |
| $(make-target-directory) |
| - { echo $(filter-out lib%, $(modules)); \ |
| + { echo $(filter-out lib%, $(modules-y)); \ |
| echo 8bit $(gen-8bit-modules); \ |
| echo 8bit-gap $(gen-8bit-gap-modules); } | \ |
| LC_ALL=C \ |
| @@ -245,7 +250,7 @@ $(addprefix $(inst_gconvdir)/, $(modules.so)): \ |
| $(do-install-program) |
| $(inst_gconvdir)/gconv-modules: gconv-modules $(+force) |
| $(do-install) |
| -ifeq (no,$(cross-compiling)) |
| +# eglibc: ifeq (no,$(cross-compiling)) |
| # Update the $(prefix)/lib/gconv/gconv-modules.cache file. This is necessary |
| # if this libc has more gconv modules than the previously installed one. |
| if test -f "$(inst_gconvdir)/gconv-modules.cache"; then \ |
| @@ -254,9 +259,9 @@ ifeq (no,$(cross-compiling)) |
| $(common-objpfx)iconv/iconvconfig \ |
| $(addprefix --prefix=,$(install_root)); \ |
| fi |
| -else |
| - @echo '*@*@*@ You should recreate $(inst_gconvdir)/gconv-modules.cache' |
| -endif |
| +# eglibc: else |
| +# eglibc: @echo '*@*@*@ You should recreate $(inst_gconvdir)/gconv-modules.cache' |
| +# eglibc: endif |
| |
| endif # build-shared = yes |
| |
| diff --git a/include/netdb.h b/include/netdb.h |
| index e1f051d..f6d15aa 100644 |
| --- a/include/netdb.h |
| +++ b/include/netdb.h |
| @@ -232,6 +232,10 @@ extern enum nss_status _nss_ ## service ## _gethostbyname2_r \ |
| (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); \ |
| diff --git a/inet/Makefile b/inet/Makefile |
| index f1d871f..7cb1709 100644 |
| --- a/inet/Makefile |
| +++ b/inet/Makefile |
| @@ -18,6 +18,8 @@ |
| # |
| # Sub-makefile for inet portion of the library. |
| # |
| +include ../option-groups.mak |
| + |
| subdir := inet |
| |
| include ../Makeconfig |
| @@ -27,7 +29,8 @@ headers := netinet/ether.h netinet/in.h netinet/in_systm.h \ |
| netinet/tcp.h netinet/ip.h $(wildcard arpa/*.h protocols/*.h) \ |
| aliases.h ifaddrs.h netinet/ip6.h netinet/icmp6.h bits/in.h |
| |
| -routines := htonl htons \ |
| +routines-$(OPTION_EGLIBC_INET) \ |
| + += htonl htons \ |
| inet_lnaof inet_mkadr \ |
| inet_netof inet_ntoa inet_net herrno herrno-loc \ |
| gethstbyad gethstbyad_r gethstbynm gethstbynm2 gethstbynm2_r \ |
| @@ -39,18 +42,23 @@ routines := htonl htons \ |
| getservent_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 |
| |
| diff --git a/intl/Makefile b/intl/Makefile |
| index 9ecf8fe..587bc0d 100644 |
| --- a/intl/Makefile |
| +++ b/intl/Makefile |
| @@ -16,6 +16,7 @@ |
| # <http://www.gnu.org/licenses/>. |
| |
| # Makefile for intl subdirectory: message handling code from GNU gettext. |
| +include ../option-groups.mak |
| |
| subdir = intl |
| |
| @@ -48,7 +49,7 @@ endif |
| $(objpfx)plural.o: plural.c |
| |
| ifeq ($(run-built-tests),yes) |
| -ifeq (yes,$(build-shared)) |
| +ifeq (yyyes,$(OPTION_EGLIBC_LOCALES)$(OPTION_EGLIBC_LOCALE_CODE)$(build-shared)) |
| ifneq ($(strip $(MSGFMT)),:) |
| tests-special += $(objpfx)tst-translit.out $(objpfx)tst-gettext.out \ |
| $(objpfx)tst-gettext2.out $(objpfx)tst-codeset.out \ |
| diff --git a/intl/dcigettext.c b/intl/dcigettext.c |
| index 8a3f091..e271648 100644 |
| --- a/intl/dcigettext.c |
| +++ b/intl/dcigettext.c |
| @@ -100,11 +100,15 @@ extern int errno; |
| # include "libgnuintl.h" |
| #endif |
| #include "hash-string.h" |
| +#ifdef _LIBC |
| +# include <gnu/option-groups.h> |
| +#endif |
| |
| /* Handle multi-threaded applications. */ |
| #ifdef _LIBC |
| # include <bits/libc-lock.h> |
| # define gl_rwlock_define_initialized __libc_rwlock_define_initialized |
| +# define gl_rwlock_define __libc_rwlock_define |
| # define gl_rwlock_rdlock __libc_rwlock_rdlock |
| # define gl_rwlock_wrlock __libc_rwlock_wrlock |
| # define gl_rwlock_unlock __libc_rwlock_unlock |
| @@ -523,8 +527,10 @@ DCIGETTEXT (const char *domainname, const char *msgid1, const char *msgid2, |
| saved_errno = errno; |
| |
| #ifdef _LIBC |
| - __libc_rwlock_define (extern, __libc_setlocale_lock attribute_hidden) |
| - __libc_rwlock_rdlock (__libc_setlocale_lock); |
| +# if __OPTION_EGLIBC_LOCALE_CODE |
| + gl_rwlock_define (extern, __libc_setlocale_lock attribute_hidden) |
| + gl_rwlock_rdlock (__libc_setlocale_lock); |
| +# endif |
| #endif |
| |
| gl_rwlock_rdlock (_nl_state_lock); |
| @@ -550,7 +556,11 @@ DCIGETTEXT (const char *domainname, const char *msgid1, const char *msgid2, |
| #ifdef HAVE_PER_THREAD_LOCALE |
| # ifndef IN_LIBGLOCALE |
| # ifdef _LIBC |
| - localename = strdupa (__current_locale_name (category)); |
| +# if __OPTION_EGLIBC_LOCALE_CODE |
| + localename = strdupa (__current_locale_name (category)); |
| +# else |
| + localename = "C"; |
| +# endif |
| # else |
| categoryname = category_to_name (category); |
| # define CATEGORYNAME_INITIALIZED |
| @@ -581,10 +591,12 @@ DCIGETTEXT (const char *domainname, const char *msgid1, const char *msgid2, |
| else |
| retval = (char *) (*foundp)->translation; |
| |
| - gl_rwlock_unlock (_nl_state_lock); |
| # ifdef _LIBC |
| - __libc_rwlock_unlock (__libc_setlocale_lock); |
| +# if __OPTION_EGLIBC_LOCALE_CODE |
| + gl_rwlock_unlock (__libc_setlocale_lock); |
| +# endif |
| # endif |
| + gl_rwlock_unlock (_nl_state_lock); |
| __set_errno (saved_errno); |
| return retval; |
| } |
| @@ -838,10 +850,13 @@ DCIGETTEXT (const char *domainname, const char *msgid1, const char *msgid2, |
| if (plural) |
| retval = plural_lookup (domain, n, retval, retlen); |
| |
| - gl_rwlock_unlock (_nl_state_lock); |
| #ifdef _LIBC |
| - __libc_rwlock_unlock (__libc_setlocale_lock); |
| +# if __OPTION_EGLIBC_LOCALE_CODE |
| + |
| + gl_rwlock_unlock (__libc_setlocale_lock); |
| +# endif |
| #endif |
| + gl_rwlock_unlock (_nl_state_lock); |
| return retval; |
| } |
| } |
| @@ -850,10 +865,12 @@ DCIGETTEXT (const char *domainname, const char *msgid1, const char *msgid2, |
| return_untranslated: |
| /* Return the untranslated MSGID. */ |
| FREE_BLOCKS (block_list); |
| - gl_rwlock_unlock (_nl_state_lock); |
| #ifdef _LIBC |
| - __libc_rwlock_unlock (__libc_setlocale_lock); |
| +# if __OPTION_EGLIBC_LOCALE_CODE |
| + gl_rwlock_unlock (__libc_setlocale_lock); |
| +# endif |
| #endif |
| + gl_rwlock_unlock (_nl_state_lock); |
| #ifndef _LIBC |
| if (!ENABLE_SECURE) |
| { |
| @@ -1550,7 +1567,11 @@ guess_category_value (int category, const char *categoryname) |
| `LC_xxx', and `LANG'. On some systems this can be done by the |
| `setlocale' function itself. */ |
| # ifdef _LIBC |
| +# if __OPTION_EGLIBC_LOCALE_CODE |
| locale = __current_locale_name (category); |
| +# else |
| + locale = "C"; |
| +# endif |
| # else |
| locale_defaulted = 0; |
| # if HAVE_USELOCALE |
| diff --git a/io/Makefile b/io/Makefile |
| index 613dce0..697439e 100644 |
| --- a/io/Makefile |
| +++ b/io/Makefile |
| @@ -18,6 +18,8 @@ |
| # |
| # Sub-makefile for I/O portion of the library. |
| # |
| +include ../option-groups.mak |
| + |
| subdir := io |
| |
| include ../Makeconfig |
| @@ -36,7 +38,7 @@ routines := \ |
| fxstatat fxstatat64 \ |
| statfs fstatfs statfs64 fstatfs64 \ |
| statvfs fstatvfs statvfs64 fstatvfs64 \ |
| - umask chmod fchmod lchmod fchmodat \ |
| + umask chmod fchmod fchmodat \ |
| mkdir mkdirat \ |
| open open_2 open64 open64_2 openat openat_2 openat64 openat64_2 \ |
| read write lseek lseek64 access euidaccess faccessat \ |
| @@ -49,11 +51,13 @@ routines := \ |
| ttyname ttyname_r isatty \ |
| link linkat symlink symlinkat readlink readlinkat \ |
| unlink unlinkat rmdir \ |
| - ftw ftw64 fts poll ppoll \ |
| + poll ppoll \ |
| posix_fadvise posix_fadvise64 \ |
| posix_fallocate posix_fallocate64 \ |
| sendfile sendfile64 \ |
| utimensat futimens |
| +routines-$(OPTION_EGLIBC_BSD) += lchmod |
| +routines-$(OPTION_EGLIBC_FTRAVERSE) += ftw ftw64 fts |
| |
| aux := have_o_cloexec |
| |
| @@ -64,18 +68,22 @@ static-only-routines = stat fstat lstat stat64 fstat64 lstat64 \ |
| 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 |
| |
| diff --git a/libidn/Makefile b/libidn/Makefile |
| index 940fa52..43aad0c 100644 |
| --- a/libidn/Makefile |
| +++ b/libidn/Makefile |
| @@ -16,6 +16,7 @@ |
| # <http://www.gnu.org/licenses/>. |
| |
| # Makefile for libidn subdirectory of GNU C Library. |
| +include ../option-groups.mak |
| |
| subdir := libidn |
| |
| @@ -23,8 +24,8 @@ include ../Makeconfig |
| |
| routines = idn-stub |
| |
| -extra-libs = libcidn |
| -extra-libs-others = $(extra-libs) |
| +extra-libs-$(OPTION_EGLIBC_IDN) = libcidn |
| +extra-libs-others-y = $(extra-libs-y) |
| |
| libcidn-routines := punycode toutf8 nfkc stringprep rfc3454 profiles idna \ |
| iconvme |
| diff --git a/libidn/toutf8.c b/libidn/toutf8.c |
| index c7e67ca..62df478 100644 |
| --- a/libidn/toutf8.c |
| +++ b/libidn/toutf8.c |
| @@ -33,6 +33,11 @@ |
| /* Get strlen. */ |
| #include <string.h> |
| |
| +/* Get __OPTION_EGLIBC_LOCALE_CODE. */ |
| +#ifdef _LIBC |
| +# include <gnu/option-groups.h> |
| +#endif |
| + |
| /* Get iconv_string. */ |
| #include "iconvme.h" |
| |
| @@ -47,7 +52,11 @@ |
| #endif |
| |
| #ifdef _LIBC |
| -# define stringprep_locale_charset() nl_langinfo (CODESET) |
| +# if __OPTION_EGLIBC_LOCALE_CODE |
| +# define stringprep_locale_charset() nl_langinfo (CODESET) |
| +# else |
| +# define stringprep_locale_charset() "ANSI_X3.4-1968" |
| +# endif |
| #else |
| /** |
| * stringprep_locale_charset - return charset used in current locale |
| diff --git a/libio/Makefile b/libio/Makefile |
| index 7b3bcf9..27c9186 100644 |
| --- a/libio/Makefile |
| +++ b/libio/Makefile |
| @@ -18,6 +18,8 @@ |
| # |
| # Specific makefile for libio. |
| # |
| +include ../option-groups.mak |
| + |
| subdir := libio |
| |
| include ../Makeconfig |
| @@ -27,16 +29,13 @@ headers := stdio.h libio.h _G_config.h bits/stdio.h bits/stdio-lock.h \ |
| |
| routines := \ |
| filedoalloc iofclose iofdopen iofflush iofgetpos iofgets iofopen \ |
| - iofopncook iofputs iofread iofsetpos ioftell wfiledoalloc \ |
| + iofopncook iofputs iofread iofsetpos ioftell \ |
| iofwrite iogetdelim iogetline iogets iopadn iopopen ioputs \ |
| ioseekoff ioseekpos iosetbuffer iosetvbuf ioungetc \ |
| iovsprintf iovsscanf \ |
| iofgetpos64 iofopen64 iofsetpos64 \ |
| - fputwc fputwc_u getwc getwc_u getwchar getwchar_u iofgetws iofgetws_u \ |
| - iofputws iofputws_u iogetwline iowpadn ioungetwc putwc putwc_u \ |
| - putwchar putwchar_u putchar putchar_u fwprintf swprintf vwprintf \ |
| - wprintf wscanf fwscanf vwscanf vswprintf iovswscanf swscanf wgenops \ |
| - wstrops wfileops iofwide fwide wmemstream \ |
| + putchar putchar_u \ |
| + iofwide \ |
| \ |
| clearerr feof ferror fileno fputc freopen fseek getc getchar \ |
| memstream pclose putc putchar rewind setbuf setlinebuf vasprintf \ |
| @@ -48,24 +47,49 @@ routines := \ |
| \ |
| libc_fatal fmemopen oldfmemopen |
| |
| -tests = tst_swprintf tst_wprintf tst_swscanf tst_wscanf tst_getwc tst_putwc \ |
| - tst_wprintf2 tst-widetext test-fmemopen tst-ext tst-ext2 \ |
| - tst-fgetws tst-ungetwc1 tst-ungetwc2 tst-swscanf tst-sscanf \ |
| - tst-mmap-setvbuf bug-ungetwc1 bug-ungetwc2 tst-atime tst-eof \ |
| - tst-freopen bug-rewind bug-rewind2 bug-ungetc bug-fseek \ |
| +routines-$(OPTION_POSIX_C_LANG_WIDE_CHAR) += \ |
| + wfiledoalloc \ |
| + iowpadn \ |
| + swprintf \ |
| + vswprintf iovswscanf swscanf wgenops \ |
| + wstrops wfileops wmemstream |
| +routines-$(call option-disabled, OPTION_POSIX_C_LANG_WIDE_CHAR) += \ |
| + wdummyfileops |
| +routines-$(OPTION_POSIX_WIDE_CHAR_DEVICE_IO) += \ |
| + fputwc fputwc_u getwc getwc_u getwchar getwchar_u iofgetws iofgetws_u \ |
| + iofputws iofputws_u iogetwline ioungetwc putwc putwc_u \ |
| + putwchar putwchar_u fwprintf vwprintf \ |
| + wprintf wscanf fwscanf vwscanf \ |
| + fwide |
| + |
| +tests = test-fmemopen tst-ext tst-ext2 \ |
| + tst-mmap-setvbuf tst-atime tst-eof \ |
| + tst-freopen bug-ungetc bug-fseek \ |
| tst-mmap-eofsync tst-mmap-fflushsync bug-mmap-fflush \ |
| - tst-mmap2-eofsync tst-mmap-offend bug-fopena+ bug-wfflush \ |
| - bug-ungetc2 bug-ftell bug-ungetc3 bug-ungetc4 tst-fopenloc2 \ |
| + tst-mmap2-eofsync tst-mmap-offend bug-fopena+ \ |
| + bug-ungetc2 bug-ungetc3 bug-ungetc4 \ |
| tst-memstream1 tst-memstream2 \ |
| - tst-wmemstream1 tst-wmemstream2 \ |
| - bug-memstream1 bug-wmemstream1 \ |
| - tst-setvbuf1 tst-popen1 tst-fgetwc bug-wsetpos tst-fseek \ |
| - tst-fwrite-error tst-ftell-partial-wide tst-ftell-active-handler \ |
| - tst-ftell-append tst-fputws |
| + bug-memstream1 tst-popen1 tst-fwrite-error \ |
| + tst-ftell-active-handler tst-ftell-append |
| +tests-$(OPTION_EGLIBC_LOCALE_CODE) \ |
| + += tst-swscanf tst-fgetws tst-setvbuf1 \ |
| + tst-ungetwc1 tst-ungetwc2 bug-ftell bug-ungetwc2 \ |
| + tst-widetext tst-fputws |
| +tests-$(OPTION_POSIX_WIDE_CHAR_DEVICE_IO) \ |
| + += bug-rewind bug-rewind2 bug-ungetwc1 \ |
| + bug-wfflush bug-wmemstream1 tst-fopenloc2 \ |
| + tst_getwc \ |
| + tst_putwc tst_wprintf tst_wprintf2 tst_wscanf \ |
| + tst-fgetwc bug-wsetpos tst-fseek tst-ftell-partial-wide |
| +tests-$(OPTION_POSIX_C_LANG_WIDE_CHAR) \ |
| + += tst_swprintf tst_swscanf \ |
| + tst-sscanf \ |
| + tst-wmemstream1 tst-wmemstream2 |
| + |
| ifeq (yes,$(build-shared)) |
| # Add test-fopenloc only if shared library is enabled since it depends on |
| # shared localedata objects. |
| -tests += tst-fopenloc |
| +tests-$(OPTION_EGLIBC_LOCALE_CODE) += tst-fopenloc |
| endif |
| test-srcs = test-freopen |
| |
| @@ -164,13 +188,17 @@ shared-only-routines = oldiofopen oldiofdopen oldiofclose oldfileops \ |
| 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 |
| |
| diff --git a/libio/__fpurge.c b/libio/__fpurge.c |
| index 065cf61..e32a3e9 100644 |
| --- a/libio/__fpurge.c |
| +++ b/libio/__fpurge.c |
| @@ -21,7 +21,7 @@ |
| void |
| __fpurge (FILE *fp) |
| { |
| - if (fp->_mode > 0) |
| + if (_IO_is_wide (fp)) |
| { |
| /* Wide-char stream. */ |
| if (_IO_in_backup (fp)) |
| diff --git a/libio/fileops.c b/libio/fileops.c |
| index cbcd6f5..19e43c2 100644 |
| --- a/libio/fileops.c |
| +++ b/libio/fileops.c |
| @@ -39,6 +39,7 @@ |
| #include <string.h> |
| #include <errno.h> |
| #include <unistd.h> |
| +#include <gnu/option-groups.h> |
| #include <stdlib.h> |
| #if _LIBC |
| # include "../wcsmbs/wcsmbsload.h" |
| @@ -173,7 +174,7 @@ _IO_new_file_close_it (_IO_FILE *fp) |
| |
| /* Free buffer. */ |
| #if defined _LIBC || defined _GLIBCPP_USE_WCHAR_T |
| - if (fp->_mode > 0) |
| + if (_IO_is_wide (fp)) |
| { |
| if (_IO_have_wbackup (fp)) |
| _IO_free_wbackup_area (fp); |
| @@ -348,6 +349,7 @@ _IO_new_file_fopen (_IO_FILE *fp, const char *filename, const char *mode, |
| 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; |
| @@ -418,6 +420,12 @@ _IO_new_file_fopen (_IO_FILE *fp, const char *filename, const char *mode, |
| |
| /* 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 |
| } |
| } |
| |
| diff --git a/libio/iofwide.c b/libio/iofwide.c |
| index 0c175d1..3e9f52b 100644 |
| --- a/libio/iofwide.c |
| +++ b/libio/iofwide.c |
| @@ -26,6 +26,7 @@ |
| |
| #include <libioP.h> |
| #ifdef _LIBC |
| +# include <gnu/option-groups.h> |
| # include <dlfcn.h> |
| # include <wchar.h> |
| #endif |
| @@ -43,6 +44,8 @@ |
| #endif |
| |
| |
| +#if ! defined _LIBC || __OPTION_POSIX_C_LANG_WIDE_CHAR |
| + |
| /* Prototypes of libio's codecvt functions. */ |
| static enum __codecvt_result do_out (struct _IO_codecvt *codecvt, |
| __mbstate_t *statep, |
| @@ -499,3 +502,26 @@ do_max_length (struct _IO_codecvt *codecvt) |
| 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 |
| diff --git a/libio/ioseekoff.c b/libio/ioseekoff.c |
| index 11765cf..15d6230 100644 |
| --- a/libio/ioseekoff.c |
| +++ b/libio/ioseekoff.c |
| @@ -60,7 +60,7 @@ _IO_seekoff_unlocked (fp, offset, dir, mode) |
| else |
| abort (); |
| } |
| - if (_IO_fwide (fp, 0) < 0) |
| + if (! _IO_is_wide (fp)) |
| _IO_free_backup_area (fp); |
| else |
| _IO_free_wbackup_area (fp); |
| diff --git a/libio/ioseekpos.c b/libio/ioseekpos.c |
| index a7652a1..6938b68 100644 |
| --- a/libio/ioseekpos.c |
| +++ b/libio/ioseekpos.c |
| @@ -35,7 +35,7 @@ _IO_seekpos_unlocked (fp, pos, mode) |
| /* If we have a backup buffer, get rid of it, since the __seekoff |
| callback may not know to do the right thing about it. |
| This may be over-kill, but it'll do for now. TODO */ |
| - if (_IO_fwide (fp, 0) <= 0) |
| + if (! _IO_is_wide (fp)) |
| { |
| if (_IO_have_backup (fp)) |
| _IO_free_backup_area (fp); |
| diff --git a/libio/iosetbuffer.c b/libio/iosetbuffer.c |
| index 0a41c10..3d99fa0 100644 |
| --- a/libio/iosetbuffer.c |
| +++ b/libio/iosetbuffer.c |
| @@ -24,6 +24,8 @@ |
| This exception applies to code released by its copyright holders |
| in files containing the exception. */ |
| |
| +#include <gnu/option-groups.h> |
| + |
| #include "libioP.h" |
| |
| void |
| @@ -38,9 +40,11 @@ _IO_setbuffer (fp, buf, size) |
| if (!buf) |
| size = 0; |
| (void) _IO_SETBUF (fp, buf, size); |
| +#if __OPTION_POSIX_C_LANG_WIDE_CHAR |
| if (_IO_vtable_offset (fp) == 0 && fp->_mode == 0 && _IO_CHECK_WIDE (fp)) |
| /* We also have to set the buffer using the wide char function. */ |
| (void) _IO_WSETBUF (fp, buf, size); |
| +#endif /* __OPTION_POSIX_C_LANG_WIDE_CHAR */ |
| _IO_release_lock (fp); |
| } |
| libc_hidden_def (_IO_setbuffer) |
| diff --git a/libio/libioP.h b/libio/libioP.h |
| index 0f16e2d..d2626d6 100644 |
| --- a/libio/libioP.h |
| +++ b/libio/libioP.h |
| @@ -44,6 +44,10 @@ |
| /*# include <comthread.h>*/ |
| #endif |
| |
| +#if defined _LIBC |
| +# include <gnu/option-groups.h> |
| +#endif |
| + |
| #include <math_ldbl_opt.h> |
| |
| #include "iolibio.h" |
| @@ -523,8 +527,20 @@ extern void _IO_old_init (_IO_FILE *fp, int flags) __THROW; |
| |
| |
| #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, \ |
| diff --git a/libio/wdummyfileops.c b/libio/wdummyfileops.c |
| new file mode 100644 |
| index 0000000..c0150b8 |
| --- /dev/null |
| +++ b/libio/wdummyfileops.c |
| @@ -0,0 +1,161 @@ |
| +/* Copyright (C) 2007 Free Software Foundation, Inc. |
| + This file is part of the GNU C Library. |
| + |
| + The GNU C Library is free software; you can redistribute it and/or |
| + modify it under the terms of the GNU Lesser General Public |
| + License as published by the Free Software Foundation; either |
| + version 2.1 of the License, or (at your option) any later version. |
| + |
| + The GNU C Library is distributed in the hope that it will be useful, |
| + but WITHOUT ANY WARRANTY; without even the implied warranty of |
| + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU |
| + Lesser General Public License for more details. |
| + |
| + You should have received a copy of the GNU Lesser General Public |
| + License along with the GNU C Library; if not, write to the Free |
| + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA |
| + 02111-1307 USA. |
| + |
| + As a special exception, if you link the code in this file with |
| + files compiled with a GNU compiler to produce an executable, |
| + that does not cause the resulting executable to be covered by |
| + the GNU Lesser General Public License. This exception does not |
| + however invalidate any other reasons why the executable file |
| + might be covered by the GNU Lesser General Public License. |
| + This exception applies to code released by its copyright holders |
| + in files containing the exception. */ |
| + |
| +#include <assert.h> |
| +#include <stdio.h> |
| +#include <stdlib.h> |
| +#include <libioP.h> |
| + |
| +static void __THROW __attribute__ ((__noreturn__)) |
| +_IO_wfile_wide_char_support_disabled (void) |
| +{ |
| + static const char errstr[] |
| + = ("The application tried to use wide character I/O, but libc.so" |
| + " was compiled\n" |
| + "with the OPTION_POSIX_C_LANG_WIDE_CHAR option group disabled.\n"); |
| + __libc_write (STDERR_FILENO, errstr, sizeof (errstr) - 1); |
| + abort (); |
| +} |
| + |
| +static void |
| +_IO_wfile_disabled_void_int (_IO_FILE *fp, int x) |
| +{ |
| + _IO_wfile_wide_char_support_disabled (); |
| +} |
| + |
| +static int |
| +_IO_wfile_disabled_int_int (_IO_FILE *fp, int x) |
| +{ |
| + _IO_wfile_wide_char_support_disabled (); |
| +} |
| + |
| +static int |
| +_IO_wfile_disabled_int_none (_IO_FILE *fp) |
| +{ |
| + _IO_wfile_wide_char_support_disabled (); |
| +} |
| + |
| +static _IO_size_t |
| +_IO_wfile_disabled_xsputn (_IO_FILE *fp, const void *data, _IO_size_t n) |
| +{ |
| + _IO_wfile_wide_char_support_disabled (); |
| +} |
| + |
| +static _IO_size_t |
| +_IO_wfile_disabled_xsgetn (_IO_FILE *fp, void *data, _IO_size_t n) |
| +{ |
| + _IO_wfile_wide_char_support_disabled (); |
| +} |
| + |
| +static _IO_off64_t |
| +_IO_wfile_disabled_seekoff (_IO_FILE *fp, _IO_off64_t off, int dir, int mode) |
| +{ |
| + _IO_wfile_wide_char_support_disabled (); |
| +} |
| + |
| +static _IO_off64_t |
| +_IO_wfile_disabled_seekpos (_IO_FILE *fp, _IO_off64_t pos, int flags) |
| +{ |
| + _IO_wfile_wide_char_support_disabled (); |
| +} |
| + |
| +static _IO_FILE * |
| +_IO_wfile_disabled_setbuf (_IO_FILE *fp, char *buffer, _IO_ssize_t length) |
| +{ |
| + _IO_wfile_wide_char_support_disabled (); |
| +} |
| + |
| +static _IO_ssize_t |
| +_IO_wfile_disabled_read (_IO_FILE *fp, void *buffer, _IO_ssize_t length) |
| +{ |
| + _IO_wfile_wide_char_support_disabled (); |
| +} |
| + |
| +static _IO_ssize_t |
| +_IO_wfile_disabled_write (_IO_FILE *fp, const void *buffer, _IO_ssize_t length) |
| +{ |
| + _IO_wfile_wide_char_support_disabled (); |
| +} |
| + |
| +static _IO_off64_t |
| +_IO_wfile_disabled_seek (_IO_FILE *fp, _IO_off64_t offset, int mode) |
| +{ |
| + _IO_wfile_wide_char_support_disabled (); |
| +} |
| + |
| +static int |
| +_IO_wfile_disabled_close (_IO_FILE *fp) |
| +{ |
| + _IO_wfile_wide_char_support_disabled (); |
| +} |
| + |
| +static int |
| +_IO_wfile_disabled_stat (_IO_FILE *fp, void *buf) |
| +{ |
| + _IO_wfile_wide_char_support_disabled (); |
| +} |
| + |
| +static int |
| +_IO_wfile_disabled_showmanyc (_IO_FILE *fp) |
| +{ |
| + _IO_wfile_wide_char_support_disabled (); |
| +} |
| + |
| +static void |
| +_IO_wfile_disabled_imbue (_IO_FILE *fp, void *locale) |
| +{ |
| + _IO_wfile_wide_char_support_disabled (); |
| +} |
| + |
| +static const struct _IO_jump_t _IO_wfile_jumps_disabled = |
| +{ |
| + JUMP_INIT_DUMMY, |
| + JUMP_INIT(finish, _IO_wfile_disabled_void_int), |
| + JUMP_INIT(overflow, _IO_wfile_disabled_int_int), |
| + JUMP_INIT(underflow, _IO_wfile_disabled_int_none), |
| + JUMP_INIT(uflow, _IO_wfile_disabled_int_none), |
| + JUMP_INIT(pbackfail, _IO_wfile_disabled_int_int), |
| + JUMP_INIT(xsputn, _IO_wfile_disabled_xsputn), |
| + JUMP_INIT(xsgetn, _IO_wfile_disabled_xsgetn), |
| + JUMP_INIT(seekoff, _IO_wfile_disabled_seekoff), |
| + JUMP_INIT(seekpos, _IO_wfile_disabled_seekpos), |
| + JUMP_INIT(setbuf, _IO_wfile_disabled_setbuf), |
| + JUMP_INIT(sync, _IO_wfile_disabled_int_none), |
| + JUMP_INIT(doallocate, _IO_wfile_disabled_int_none), |
| + JUMP_INIT(read, _IO_wfile_disabled_read), |
| + JUMP_INIT(write, _IO_wfile_disabled_write), |
| + JUMP_INIT(seek, _IO_wfile_disabled_seek), |
| + JUMP_INIT(close, _IO_wfile_disabled_close), |
| + JUMP_INIT(stat, _IO_wfile_disabled_stat), |
| + JUMP_INIT(showmanyc, _IO_wfile_disabled_showmanyc), |
| + JUMP_INIT(imbue, _IO_wfile_disabled_imbue) |
| +}; |
| + |
| +strong_alias (_IO_wfile_jumps_disabled, _IO_wfile_jumps) |
| +libc_hidden_data_def (_IO_wfile_jumps) |
| +strong_alias (_IO_wfile_jumps_disabled, _IO_wfile_jumps_mmap) |
| +strong_alias (_IO_wfile_jumps_disabled, _IO_wfile_jumps_maybe_mmap) |
| diff --git a/locale/C-ctype.c b/locale/C-ctype.c |
| index aa5f19f..06be081 100644 |
| --- a/locale/C-ctype.c |
| +++ b/locale/C-ctype.c |
| @@ -19,8 +19,11 @@ |
| #include "localeinfo.h" |
| #include <endian.h> |
| #include <stdint.h> |
| +#include <gnu/option-groups.h> |
| |
| +#if __OPTION_EGLIBC_LOCALE_CODE |
| #include "C-translit.h" |
| +#endif |
| |
| /* This table's entries are taken from POSIX.2 Table 2-6 |
| ``LC_CTYPE Category Definition in the POSIX Locale''. |
| @@ -634,6 +637,7 @@ const struct __locale_data _nl_C_LC_CTYPE attribute_hidden = |
| { .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 */ |
| @@ -644,6 +648,22 @@ const struct __locale_data _nl_C_LC_CTYPE attribute_hidden = |
| { .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 */ |
| diff --git a/locale/Makefile b/locale/Makefile |
| index f1b4343..599a1a9 100644 |
| --- a/locale/Makefile |
| +++ b/locale/Makefile |
| @@ -18,27 +18,43 @@ |
| # |
| # Makefile for locales. |
| # |
| +include ../option-groups.mak |
| + |
| subdir := locale |
| |
| include ../Makeconfig |
| |
| headers = locale.h bits/locale.h langinfo.h xlocale.h |
| -routines = setlocale findlocale loadlocale loadarchive \ |
| - localeconv nl_langinfo nl_langinfo_l mb_cur_max \ |
| - newlocale duplocale freelocale uselocale |
| -tests = tst-C-locale tst-locname tst-duplocale |
| +# catnames is needed by OPTION_EGLIBC_LOCALE_CODE and by the 'intl' code. |
| +# If we put the latter in an option group, too, we can omit catnames |
| +# when both option groups are disabled. libstdc++-v3 needs mb_cur_max. |
| +routines-y := catnames mb_cur_max |
| +routines-$(OPTION_EGLIBC_LOCALE_CODE) \ |
| + += setlocale findlocale loadlocale loadarchive \ |
| + localeconv nl_langinfo nl_langinfo_l \ |
| + newlocale duplocale freelocale uselocale |
| +ifneq (y,$(OPTION_EGLIBC_LOCALE_CODE)) |
| +routines-y += dummy-setlocale |
| +endif |
| +tests-$(OPTION_EGLIBC_LOCALE_CODE) += tst-C-locale tst-locname tst-duplocale |
| categories = ctype messages monetary numeric time paper name \ |
| address telephone measurement identification collate |
| -aux = $(categories:%=lc-%) $(categories:%=C-%) SYS_libc C_name \ |
| - xlocale localename global-locale coll-lookup |
| -others = localedef locale |
| +# C-messages belongs in an intl option group. |
| +aux-y := C-ctype C-time \ |
| + SYS_libc C_name xlocale global-locale coll-lookup |
| +aux-$(OPTION_EGLIBC_LOCALE_CODE) \ |
| + += $(filter-out $(aux-y), \ |
| + $(categories:%=lc-%) $(categories:%=C-%)) \ |
| + localename |
| +others-$(OPTION_EGLIBC_LOCALE_CODE) = localedef locale |
| #others-static = localedef locale |
| -install-bin = localedef locale |
| -extra-objs = $(localedef-modules:=.o) $(localedef-aux:=.o) \ |
| +install-bin = $(others-y) |
| +extra-objs-$(OPTION_EGLIBC_LOCALE_CODE) \ |
| + = $(localedef-modules:=.o) $(localedef-aux:=.o) \ |
| $(locale-modules:=.o) $(lib-modules:=.o) |
| |
| -extra-libs = libBrokenLocale |
| -extra-libs-others = $(extra-libs) |
| +extra-libs-$(OPTION_EGLIBC_LOCALE_CODE) = libBrokenLocale |
| +extra-libs-others = $(extra-libs-y) |
| |
| libBrokenLocale-routines = broken_cur_max |
| |
| @@ -93,6 +109,9 @@ CPPFLAGS-locale-programs = -DLOCALE_PATH='$(localepath)' \ |
| CFLAGS-charmap.c = -Wno-write-strings -Wno-char-subscripts |
| CFLAGS-locfile.c = -Wno-write-strings -Wno-char-subscripts |
| CFLAGS-charmap-dir.c = -Wno-write-strings |
| +ifneq (y,$(OPTION_EGLIBC_SPAWN)) |
| +CFLAGS-charmap-dir.c += -DNO_UNCOMPRESS |
| +endif |
| |
| # Set libof-* for each routine. |
| cpp-srcs-left := $(localedef-modules) $(localedef-aux) $(locale-modules) \ |
| diff --git a/locale/catnames.c b/locale/catnames.c |
| new file mode 100644 |
| index 0000000..9fad357 |
| --- /dev/null |
| +++ b/locale/catnames.c |
| @@ -0,0 +1,48 @@ |
| +/* Copyright (C) 2006 Free Software Foundation, Inc. |
| + This file is part of the GNU C Library. |
| + |
| + The GNU C Library is free software; you can redistribute it and/or |
| + modify it under the terms of the GNU Lesser General Public |
| + License as published by the Free Software Foundation; either |
| + version 2.1 of the License, or (at your option) any later version. |
| + |
| + The GNU C Library is distributed in the hope that it will be useful, |
| + but WITHOUT ANY WARRANTY; without even the implied warranty of |
| + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU |
| + Lesser General Public License for more details. |
| + |
| + You should have received a copy of the GNU Lesser General Public |
| + License along with the GNU C Library; if not, write to the Free |
| + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA |
| + 02111-1307 USA. */ |
| + |
| +#include "localeinfo.h" |
| + |
| +/* Define an array of category names (also the environment variable names). */ |
| +const union catnamestr_t _nl_category_names attribute_hidden = |
| + { |
| + { |
| +#define DEFINE_CATEGORY(category, category_name, items, a) \ |
| + category_name, |
| +#include "categories.def" |
| +#undef DEFINE_CATEGORY |
| + } |
| + }; |
| + |
| +const uint8_t _nl_category_name_idxs[__LC_LAST] attribute_hidden = |
| + { |
| +#define DEFINE_CATEGORY(category, category_name, items, a) \ |
| + [category] = offsetof (union catnamestr_t, CATNAMEMF (__LINE__)), |
| +#include "categories.def" |
| +#undef DEFINE_CATEGORY |
| + }; |
| + |
| +/* An array of their lengths, for convenience. */ |
| +const uint8_t _nl_category_name_sizes[] attribute_hidden = |
| + { |
| +#define DEFINE_CATEGORY(category, category_name, items, a) \ |
| + [category] = sizeof (category_name) - 1, |
| +#include "categories.def" |
| +#undef DEFINE_CATEGORY |
| + [LC_ALL] = sizeof ("LC_ALL") - 1 |
| + }; |
| diff --git a/locale/dummy-setlocale.c b/locale/dummy-setlocale.c |
| new file mode 100644 |
| index 0000000..219964a |
| --- /dev/null |
| +++ b/locale/dummy-setlocale.c |
| @@ -0,0 +1,33 @@ |
| +/* Copyright (C) 2006 Free Software Foundation, Inc. |
| + This file is part of the GNU C Library. |
| + |
| + The GNU C Library is free software; you can redistribute it and/or |
| + modify it under the terms of the GNU Lesser General Public |
| + License as published by the Free Software Foundation; either |
| + version 2.1 of the License, or (at your option) any later version. |
| + |
| + The GNU C Library is distributed in the hope that it will be useful, |
| + but WITHOUT ANY WARRANTY; without even the implied warranty of |
| + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU |
| + Lesser General Public License for more details. |
| + |
| + You should have received a copy of the GNU Lesser General Public |
| + License along with the GNU C Library; if not, write to the Free |
| + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA |
| + 02111-1307 USA. */ |
| + |
| +#include <string.h> |
| +#include <locale.h> |
| + |
| +char * |
| +setlocale (int category, const char *locale) |
| +{ |
| + if (! locale |
| + || locale[0] == '\0' |
| + || strcmp (locale, "C") == 0 |
| + || strcmp (locale, "POSIX") == 0) |
| + return (char *) "C"; |
| + else |
| + return NULL; |
| +} |
| +libc_hidden_def (setlocale) |
| diff --git a/locale/localeinfo.h b/locale/localeinfo.h |
| index bdab9fe..a7516c0 100644 |
| --- a/locale/localeinfo.h |
| +++ b/locale/localeinfo.h |
| @@ -232,7 +232,7 @@ __libc_tsd_define (extern, __locale_t, LOCALE) |
| unused. We can manage this playing some tricks with weak references. |
| But with thread-local locale settings, it becomes quite ungainly unless |
| we can use __thread variables. So only in that case do we attempt this. */ |
| -#ifndef SHARED |
| +#if !defined SHARED && !defined IN_GLIBC_LOCALEDEF |
| # include <tls.h> |
| # define NL_CURRENT_INDIRECT 1 |
| #endif |
| diff --git a/locale/programs/charmap-dir.c b/locale/programs/charmap-dir.c |
| index cf7adea..ef3b811 100644 |
| --- a/locale/programs/charmap-dir.c |
| +++ b/locale/programs/charmap-dir.c |
| @@ -19,7 +19,9 @@ |
| #include <error.h> |
| #include <fcntl.h> |
| #include <libintl.h> |
| +#ifndef NO_UNCOMPRESS |
| #include <spawn.h> |
| +#endif |
| #include <stdio.h> |
| #include <stdlib.h> |
| #include <string.h> |
| @@ -156,6 +158,7 @@ charmap_closedir (CHARMAP_DIR *cdir) |
| return closedir (dir); |
| } |
| |
| +#ifndef NO_UNCOMPRESS |
| /* Creates a subprocess decompressing the given pathname, and returns |
| a stream reading its output (the decompressed data). */ |
| static |
| @@ -204,6 +207,7 @@ fopen_uncompressed (const char *pathname, const char *compressor) |
| } |
| return NULL; |
| } |
| +#endif |
| |
| /* Opens a charmap for reading, given its name (not an alias name). */ |
| FILE * |
| @@ -226,6 +230,7 @@ charmap_open (const char *directory, const char *name) |
| if (stream != NULL) |
| return stream; |
| |
| +#ifndef NO_UNCOMPRESS |
| memcpy (p, ".gz", 4); |
| stream = fopen_uncompressed (pathname, "gzip"); |
| if (stream != NULL) |
| @@ -235,6 +240,7 @@ charmap_open (const char *directory, const char *name) |
| stream = fopen_uncompressed (pathname, "bzip2"); |
| if (stream != NULL) |
| return stream; |
| +#endif |
| |
| return NULL; |
| } |
| diff --git a/locale/programs/ld-collate.c b/locale/programs/ld-collate.c |
| index a39a94f..16e9039 100644 |
| --- a/locale/programs/ld-collate.c |
| +++ b/locale/programs/ld-collate.c |
| @@ -351,7 +351,7 @@ new_element (struct locale_collate_t *collate, const char *mbs, size_t mbslen, |
| } |
| if (wcs != NULL) |
| { |
| - size_t nwcs = wcslen ((wchar_t *) wcs); |
| + size_t nwcs = wcslen_uint32 (wcs); |
| uint32_t zero = 0; |
| /* Handle <U0000> as a single character. */ |
| if (nwcs == 0) |
| @@ -1777,8 +1777,7 @@ symbol `%s' has the same encoding as"), (*eptr)->name); |
| |
| 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) |
| { |
| @@ -2011,9 +2010,9 @@ add_to_tablewc (uint32_t ch, struct element_t *runp) |
| 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)) |
| { |
| @@ -2037,9 +2036,9 @@ add_to_tablewc (uint32_t ch, struct element_t *runp) |
| 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)); |
| |
| diff --git a/locale/programs/ld-ctype.c b/locale/programs/ld-ctype.c |
| index 3f464ef..b7b6b51 100644 |
| --- a/locale/programs/ld-ctype.c |
| +++ b/locale/programs/ld-ctype.c |
| @@ -926,7 +926,7 @@ ctype_output (struct localedef_t *locale, const struct charmap_t *charmap, |
| 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); |
| @@ -1937,7 +1937,7 @@ read_translit_entry (struct linereader *ldfile, struct locale_ctype_t *ctype, |
| 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; |
| } |
| @@ -2471,8 +2471,8 @@ with character code range values one must use the absolute ellipsis `...'")); |
| } |
| |
| 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; |
| |
| @@ -3929,8 +3929,7 @@ allocate_arrays (struct locale_ctype_t *ctype, const struct charmap_t *charmap, |
| |
| 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; |
| @@ -3967,11 +3966,11 @@ allocate_arrays (struct locale_ctype_t *ctype, const struct charmap_t *charmap, |
| for (size_t cnt = 0; cnt < number; ++cnt) |
| { |
| struct translit_to_t *srunp; |
| - from_len += wcslen ((const wchar_t *) sorted[cnt]->from) + 1; |
| + from_len += wcslen_uint32 (sorted[cnt]->from) + 1; |
| srunp = sorted[cnt]->to; |
| while (srunp != NULL) |
| { |
| - to_len += wcslen ((const wchar_t *) srunp->str) + 1; |
| + to_len += wcslen_uint32 (srunp->str) + 1; |
| srunp = srunp->next; |
| } |
| /* Plus one for the extra NUL character marking the end of |
| @@ -3995,18 +3994,18 @@ allocate_arrays (struct locale_ctype_t *ctype, const struct charmap_t *charmap, |
| 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; |
| } |
| diff --git a/locale/programs/ld-messages.c b/locale/programs/ld-messages.c |
| index ec1a80b..736eed8 100644 |
| --- a/locale/programs/ld-messages.c |
| +++ b/locale/programs/ld-messages.c |
| @@ -25,6 +25,7 @@ |
| #include <string.h> |
| #include <stdint.h> |
| #include <sys/uio.h> |
| +#include <gnu/option-groups.h> |
| |
| #include <assert.h> |
| |
| @@ -124,6 +125,7 @@ No definition for %s category found"), "LC_MESSAGES")); |
| } |
| else |
| { |
| +#if __OPTION_POSIX_REGEXP |
| int result; |
| regex_t re; |
| |
| @@ -140,6 +142,7 @@ No definition for %s category found"), "LC_MESSAGES")); |
| } |
| else if (result != 0) |
| regfree (&re); |
| +#endif |
| } |
| |
| if (messages->noexpr == NULL) |
| @@ -158,6 +161,7 @@ No definition for %s category found"), "LC_MESSAGES")); |
| } |
| else |
| { |
| +#if __OPTION_POSIX_REGEXP |
| int result; |
| regex_t re; |
| |
| @@ -174,6 +178,7 @@ No definition for %s category found"), "LC_MESSAGES")); |
| } |
| else if (result != 0) |
| regfree (&re); |
| +#endif |
| } |
| } |
| |
| diff --git a/locale/programs/ld-time.c b/locale/programs/ld-time.c |
| index db490c6..75dc505 100644 |
| --- a/locale/programs/ld-time.c |
| +++ b/locale/programs/ld-time.c |
| @@ -215,8 +215,10 @@ No definition for %s category found"), "LC_TIME")); |
| } |
| else |
| { |
| + static const uint32_t wt_fmt_ampm[] |
| + = { '%','I',':','%','M',':','%','S',' ','%','p',0 }; |
| time->t_fmt_ampm = "%I:%M:%S %p"; |
| - time->wt_fmt_ampm = (const uint32_t *) L"%I:%M:%S %p"; |
| + time->wt_fmt_ampm = wt_fmt_ampm; |
| } |
| } |
| |
| @@ -226,7 +228,7 @@ No definition for %s category found"), "LC_TIME")); |
| const int days_per_month[12] = { 31, 29, 31, 30, 31, 30, |
| 31, 31, 30, 31 ,30, 31 }; |
| size_t idx; |
| - wchar_t *wstr; |
| + uint32_t *wstr; |
| |
| time->era_entries = |
| (struct era_data *) xmalloc (time->num_era |
| @@ -464,18 +466,18 @@ No definition for %s category found"), "LC_TIME")); |
| } |
| |
| /* Now generate the wide character name and format. */ |
| - wstr = wcschr ((wchar_t *) time->wera[idx], L':');/* end direction */ |
| - wstr = wstr ? wcschr (wstr + 1, L':') : NULL; /* end offset */ |
| - wstr = wstr ? wcschr (wstr + 1, L':') : NULL; /* end start */ |
| - wstr = wstr ? wcschr (wstr + 1, L':') : NULL; /* end end */ |
| + wstr = wcschr_uint32 (time->wera[idx], L':'); /* end direction */ |
| + wstr = wstr ? wcschr_uint32 (wstr + 1, L':') : NULL; /* end offset */ |
| + wstr = wstr ? wcschr_uint32 (wstr + 1, L':') : NULL; /* end start */ |
| + wstr = wstr ? wcschr_uint32 (wstr + 1, L':') : NULL; /* end end */ |
| if (wstr != NULL) |
| { |
| - time->era_entries[idx].wname = (uint32_t *) wstr + 1; |
| - wstr = wcschr (wstr + 1, L':'); /* end name */ |
| + time->era_entries[idx].wname = wstr + 1; |
| + wstr = wcschr_uint32 (wstr + 1, L':'); /* end name */ |
| if (wstr != NULL) |
| { |
| *wstr = L'\0'; |
| - time->era_entries[idx].wformat = (uint32_t *) wstr + 1; |
| + time->era_entries[idx].wformat = wstr + 1; |
| } |
| else |
| time->era_entries[idx].wname = |
| @@ -530,7 +532,16 @@ No definition for %s category found"), "LC_TIME")); |
| 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; |
| + } |
| } |
| |
| |
| diff --git a/locale/programs/linereader.c b/locale/programs/linereader.c |
| index 2e05130..653b68c 100644 |
| --- a/locale/programs/linereader.c |
| +++ b/locale/programs/linereader.c |
| @@ -595,7 +595,7 @@ get_string (struct linereader *lr, const struct charmap_t *charmap, |
| { |
| int return_widestr = lr->return_widestr; |
| char *buf; |
| - wchar_t *buf2 = NULL; |
| + uint32_t *buf2 = NULL; |
| size_t bufact; |
| size_t bufmax = 56; |
| |
| diff --git a/locale/programs/localedef.c b/locale/programs/localedef.c |
| index 2a0f2aa..583d233 100644 |
| --- a/locale/programs/localedef.c |
| +++ b/locale/programs/localedef.c |
| @@ -114,6 +114,7 @@ void (*argp_program_version_hook) (FILE *, struct argp_state *) = print_version; |
| #define OPT_LIST_ARCHIVE 309 |
| #define OPT_LITTLE_ENDIAN 400 |
| #define OPT_BIG_ENDIAN 401 |
| +#define OPT_UINT32_ALIGN 402 |
| |
| /* Definitions of arguments for argp functions. */ |
| static const struct argp_option options[] = |
| @@ -150,6 +151,8 @@ static const struct argp_option options[] = |
| N_("Generate little-endian output") }, |
| { "big-endian", OPT_BIG_ENDIAN, NULL, 0, |
| N_("Generate big-endian output") }, |
| + { "uint32-align", OPT_UINT32_ALIGN, "ALIGNMENT", 0, |
| + N_("Set the target's uint32_t alignment in bytes (default 4)") }, |
| { NULL, 0, NULL, 0, NULL } |
| }; |
| |
| @@ -239,12 +242,14 @@ main (int argc, char *argv[]) |
| ctype locale. (P1003.2 4.35.5.2) */ |
| setlocale (LC_CTYPE, "POSIX"); |
| |
| +#ifndef NO_SYSCONF |
| /* Look whether the system really allows locale definitions. POSIX |
| defines error code 3 for this situation so I think it must be |
| a fatal error (see P1003.2 4.35.8). */ |
| if (sysconf (_SC_2_LOCALEDEF) < 0) |
| WITH_CUR_LOCALE (error (3, 0, _("\ |
| FATAL: system does not define `_POSIX2_LOCALEDEF'"))); |
| +#endif |
| |
| /* Process charmap file. */ |
| charmap = charmap_read (charmap_file, verbose, 1, be_quiet, 1); |
| @@ -338,6 +343,9 @@ parse_opt (int key, char *arg, struct argp_state *state) |
| 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; |
| diff --git a/locale/programs/locfile.c b/locale/programs/locfile.c |
| index 33da52e..f790c4c 100644 |
| --- a/locale/programs/locfile.c |
| +++ b/locale/programs/locfile.c |
| @@ -544,6 +544,9 @@ compare_files (const char *filename1, const char *filename2, size_t size, |
| machine running localedef. */ |
| bool swap_endianness_p; |
| |
| +/* The target's value of __align__(uint32_t) - 1. */ |
| +unsigned int uint32_align_mask = 3; |
| + |
| /* When called outside a start_locale_structure/end_locale_structure |
| or start_locale_prelude/end_locale_prelude block, record that the |
| next byte in FILE's obstack will be the first byte of a new element. |
| @@ -621,7 +624,7 @@ add_locale_string (struct locale_file *file, const char *string) |
| 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. */ |
| diff --git a/locale/programs/locfile.h b/locale/programs/locfile.h |
| index 6fc441b..118b171 100644 |
| --- a/locale/programs/locfile.h |
| +++ b/locale/programs/locfile.h |
| @@ -71,6 +71,8 @@ extern void write_all_categories (struct localedef_t *definitions, |
| |
| extern bool swap_endianness_p; |
| |
| +extern unsigned int uint32_align_mask; |
| + |
| /* Change the output to be big-endian if BIG_ENDIAN is true and |
| little-endian otherwise. */ |
| static inline void |
| @@ -89,7 +91,8 @@ maybe_swap_uint32 (uint32_t value) |
| } |
| |
| /* Likewise, but munge an array of N uint32_ts starting at ARRAY. */ |
| -static inline void |
| +static void |
| +__attribute__ ((unused)) |
| maybe_swap_uint32_array (uint32_t *array, size_t n) |
| { |
| if (swap_endianness_p) |
| @@ -99,7 +102,8 @@ maybe_swap_uint32_array (uint32_t *array, size_t n) |
| |
| /* Like maybe_swap_uint32_array, but the array of N elements is at |
| the end of OBSTACK's current object. */ |
| -static inline void |
| +static void |
| +__attribute__ ((unused)) |
| maybe_swap_uint32_obstack (struct obstack *obstack, size_t n) |
| { |
| maybe_swap_uint32_array ((uint32_t *) obstack_next_free (obstack) - n, n); |
| @@ -276,4 +280,55 @@ extern void identification_output (struct localedef_t *locale, |
| const struct charmap_t *charmap, |
| const char *output_path); |
| |
| +static size_t wcslen_uint32 (const uint32_t *str) __attribute__ ((unused)); |
| +static uint32_t * wmemcpy_uint32 (uint32_t *s1, const uint32_t *s2, size_t n) __attribute__ ((unused)); |
| +static uint32_t * wcschr_uint32 (const uint32_t *s, uint32_t ch) __attribute__ ((unused)); |
| +static int wcscmp_uint32 (const uint32_t *s1, const uint32_t *s2) __attribute__ ((unused)); |
| +static int wmemcmp_uint32 (const uint32_t *s1, const uint32_t *s2, size_t n) __attribute__ ((unused)); |
| + |
| +static size_t |
| +wcslen_uint32 (const uint32_t *str) |
| +{ |
| + size_t len = 0; |
| + while (str[len] != 0) |
| + len++; |
| + return len; |
| +} |
| + |
| +static int |
| +wmemcmp_uint32 (const uint32_t *s1, const uint32_t *s2, size_t n) |
| +{ |
| + while (n-- != 0) |
| + { |
| + int diff = *s1++ - *s2++; |
| + if (diff != 0) |
| + return diff; |
| + } |
| + return 0; |
| +} |
| + |
| +static int |
| +wcscmp_uint32 (const uint32_t *s1, const uint32_t *s2) |
| +{ |
| + while (*s1 != 0 && *s1 == *s2) |
| + s1++, s2++; |
| + return *s1 - *s2; |
| +} |
| + |
| +static uint32_t * |
| +wmemcpy_uint32 (uint32_t *s1, const uint32_t *s2, size_t n) |
| +{ |
| + return memcpy (s1, s2, n * sizeof (uint32_t)); |
| +} |
| + |
| +static uint32_t * |
| +wcschr_uint32 (const uint32_t *s, uint32_t ch) |
| +{ |
| + do |
| + if (*s == ch) |
| + return (uint32_t *) s; |
| + while (*s++ != 0); |
| + return 0; |
| +} |
| + |
| #endif /* locfile.h */ |
| diff --git a/locale/setlocale.c b/locale/setlocale.c |
| index fa9cb3a..8eee284 100644 |
| --- a/locale/setlocale.c |
| +++ b/locale/setlocale.c |
| @@ -64,36 +64,6 @@ static char *const _nl_current_used[] = |
| #endif |
| |
| |
| -/* Define an array of category names (also the environment variable names). */ |
| -const union catnamestr_t _nl_category_names attribute_hidden = |
| - { |
| - { |
| -#define DEFINE_CATEGORY(category, category_name, items, a) \ |
| - category_name, |
| -#include "categories.def" |
| -#undef DEFINE_CATEGORY |
| - } |
| - }; |
| - |
| -const uint8_t _nl_category_name_idxs[__LC_LAST] attribute_hidden = |
| - { |
| -#define DEFINE_CATEGORY(category, category_name, items, a) \ |
| - [category] = offsetof (union catnamestr_t, CATNAMEMF (__LINE__)), |
| -#include "categories.def" |
| -#undef DEFINE_CATEGORY |
| - }; |
| - |
| -/* An array of their lengths, for convenience. */ |
| -const uint8_t _nl_category_name_sizes[] attribute_hidden = |
| - { |
| -#define DEFINE_CATEGORY(category, category_name, items, a) \ |
| - [category] = sizeof (category_name) - 1, |
| -#include "categories.def" |
| -#undef DEFINE_CATEGORY |
| - [LC_ALL] = sizeof ("LC_ALL") - 1 |
| - }; |
| - |
| - |
| #ifdef NL_CURRENT_INDIRECT |
| # define WEAK_POSTLOAD(postload) weak_extern (postload) |
| #else |
| diff --git a/locale/xlocale.c b/locale/xlocale.c |
| index fec4564..f00269c 100644 |
| --- a/locale/xlocale.c |
| +++ b/locale/xlocale.c |
| @@ -18,6 +18,7 @@ |
| <http://www.gnu.org/licenses/>. */ |
| |
| #include <locale.h> |
| +#include <gnu/option-groups.h> |
| #include "localeinfo.h" |
| |
| #define DEFINE_CATEGORY(category, category_name, items, a) \ |
| @@ -25,6 +26,19 @@ extern struct __locale_data _nl_C_##category; |
| #include "categories.def" |
| #undef DEFINE_CATEGORY |
| |
| +/* If the locale support code isn't enabled, don't generate strong |
| + reference to the C locale_data structures here; let the Makefile |
| + decide which ones to include. (In the static linking case, the |
| + strong reference to the 'class', 'toupper', and 'tolower' tables |
| + will cause C-ctype.o to be brought in, as it should be, even when |
| + the reference to _nl_C_LC_CTYPE will be weak.) */ |
| +#if ! __OPTION_EGLIBC_LOCALE_CODE |
| +# define DEFINE_CATEGORY(category, category_name, items, a) \ |
| + weak_extern (_nl_C_##category) |
| +# include "categories.def" |
| +# undef DEFINE_CATEGORY |
| +#endif |
| + |
| /* Defined in locale/C-ctype.c. */ |
| extern const char _nl_C_LC_CTYPE_class[] attribute_hidden; |
| extern const char _nl_C_LC_CTYPE_toupper[] attribute_hidden; |
| @@ -52,3 +66,26 @@ const struct __locale_struct _nl_C_locobj attribute_hidden = |
| .__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 */ |
| diff --git a/localedata/Makefile b/localedata/Makefile |
| index ebf6ac9..1870753 100644 |
| --- a/localedata/Makefile |
| +++ b/localedata/Makefile |
| @@ -21,12 +21,22 @@ subdir := localedata |
| |
| include ../Makeconfig |
| |
| -# List with all available character set descriptions. |
| -charmaps := $(wildcard charmaps/[A-I]*) $(wildcard charmaps/[J-Z]*) |
| +include ../option-groups.mak |
| |
| # List with all available character set descriptions. |
| -locales := $(wildcard locales/*) |
| - |
| +all-charmaps := $(wildcard charmaps/[A-I]*) $(wildcard charmaps/[J-Z]*) |
| + |
| +all-locales := $(wildcard locales/*) |
| + |
| +# If the EGLIBC_LOCALES option group is not enabled, trim the |
| +# list of charmap and locale source files. |
| +ifeq ($(OPTION_EGLIBC_LOCALES),y) |
| +charmaps := $(all-charmaps) |
| +locales := $(all-locales) |
| +else |
| +charmaps := |
| +locales := locales/POSIX |
| +endif |
| |
| subdir-dirs = tests-mbwc |
| vpath %.c tests-mbwc |
| @@ -71,14 +81,20 @@ locale_test_suite := tst_iswalnum tst_iswalpha tst_iswcntrl \ |
| tst_wcsxfrm tst_wctob tst_wctomb tst_wctrans \ |
| tst_wctype tst_wcwidth |
| |
| -tests = $(locale_test_suite) tst-digits tst-setlocale bug-iconv-trans \ |
| +# Since these tests build their own locale files, they're not |
| +# dependent on the OPTION_EGLIBC_LOCALES option group. But they do |
| +# need the locale functions to be present. |
| +tests-$(OPTION_EGLIBC_LOCALE_CODE) \ |
| + += $(locale_test_suite) tst-digits tst-setlocale bug-iconv-trans \ |
| tst-leaks tst-mbswcs1 tst-mbswcs2 tst-mbswcs3 tst-mbswcs4 tst-mbswcs5 \ |
| tst-mbswcs6 tst-xlocale1 tst-xlocale2 bug-usesetlocale \ |
| tst-strfmon1 tst-sscanf bug-setlocale1 tst-setlocale2 tst-setlocale3 \ |
| tst-wctype |
| +ifeq (y,$(OPTION_EGLIBC_LOCALE_CODE)) |
| tests-static = bug-setlocale1-static |
| tests += $(tests-static) |
| -ifeq (yes,$(build-shared)) |
| +endif |
| +ifeq (yesy,$(build-shared)$(OPTION_EGLIBC_LOCALE_CODE)) |
| ifneq (no,$(PERL)) |
| tests-special += $(objpfx)mtrace-tst-leaks.out |
| endif |
| @@ -95,6 +111,7 @@ tests: $(objdir)/iconvdata/gconv-modules |
| tests-static += tst-langinfo-static |
| |
| ifeq ($(run-built-tests),yes) |
| +ifeq (y,$(OPTION_EGLIBC_LOCALE_CODE)) |
| tests-special += $(objpfx)sort-test.out $(objpfx)tst-fmon.out \ |
| $(objpfx)tst-locale.out $(objpfx)tst-rpmatch.out \ |
| $(objpfx)tst-trans.out $(objpfx)tst-ctype.out \ |
| @@ -109,6 +126,7 @@ LOCALES := de_DE.ISO-8859-1 de_DE.UTF-8 en_US.ANSI_X3.4-1968 \ |
| tr_TR.ISO-8859-9 en_GB.UTF-8 uk_UA.UTF-8 |
| include ../gen-locales.mk |
| endif |
| +endif |
| |
| include ../Rules |
| |
| @@ -191,6 +209,11 @@ endif |
| |
| include SUPPORTED |
| |
| +# Only install locale data if OPTION_EGLIBC_LOCALES is selected. |
| +ifneq ($(OPTION_EGLIBC_LOCALES),y) |
| +SUPPORTED-LOCALES := |
| +endif |
| + |
| INSTALL-SUPPORTED-LOCALES=$(addprefix install-, $(SUPPORTED-LOCALES)) |
| |
| # Sometimes the whole collection of locale files should be installed. |
| diff --git a/login/Makefile b/login/Makefile |
| index 0f4bb22..4036ddb 100644 |
| --- a/login/Makefile |
| +++ b/login/Makefile |
| @@ -18,6 +18,7 @@ |
| # |
| # Sub-makefile for login portion of the library. |
| # |
| +include ../option-groups.mak |
| |
| subdir := login |
| |
| @@ -25,14 +26,16 @@ include ../Makeconfig |
| |
| headers := utmp.h bits/utmp.h lastlog.h pty.h |
| |
| -routines := getlogin getlogin_r setlogin getlogin_r_chk \ |
| - getutent getutent_r getutid getutline getutid_r getutline_r \ |
| - utmp_file utmpname updwtmp getpt grantpt unlockpt ptsname \ |
| - ptsname_r_chk |
| +routines := getpt grantpt unlockpt ptsname ptsname_r_chk |
| +routines-$(OPTION_EGLIBC_UTMP) \ |
| + += getutent getutent_r getutid getutline getutid_r getutline_r \ |
| + utmp_file utmpname updwtmp |
| +routines-$(OPTION_EGLIBC_GETLOGIN) += getlogin getlogin_r getlogin_r_chk |
| +routines-$(OPTION_EGLIBC_BSD) += setlogin |
| |
| CFLAGS-grantpt.c = -DLIBEXECDIR='"$(libexecdir)"' |
| |
| -others = utmpdump |
| +others-$(OPTION_EGLIBC_UTMP) += utmpdump |
| |
| ifeq (yes,$(build-pt-chown)) |
| others += pt_chown |
| @@ -46,8 +49,8 @@ vpath %.c programs |
| tests := tst-utmp tst-utmpx tst-grantpt tst-ptsname tst-getlogin |
| |
| # 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 |
| |
| diff --git a/malloc/Makefile b/malloc/Makefile |
| index 67ed293..272ca4d 100644 |
| --- a/malloc/Makefile |
| +++ b/malloc/Makefile |
| @@ -18,6 +18,8 @@ |
| # |
| # Makefile for malloc routines |
| # |
| +include ../option-groups.mak |
| + |
| subdir := malloc |
| |
| include ../Makeconfig |
| @@ -39,9 +41,15 @@ install-lib := libmcheck.a |
| non-lib.a := libmcheck.a |
| |
| # Additional library. |
| +ifeq ($(OPTION_EGLIBC_MEMUSAGE),y) |
| extra-libs = libmemusage |
| extra-libs-others = $(extra-libs) |
| |
| +ifdef OPTION_EGLIBC_MEMUSAGE_DEFAULT_BUFFER_SIZE |
| +CPPFLAGS-memusage += -D__OPTION_EGLIBC_MEMUSAGE_DEFAULT_BUFFER_SIZE=$(OPTION_EGLIBC_MEMUSAGE_DEFAULT_BUFFER_SIZE) |
| +endif |
| +endif |
| + |
| libmemusage-routines = memusage |
| libmemusage-inhibit-o = $(filter-out .os,$(object-suffixes)) |
| |
| @@ -71,7 +79,7 @@ endif |
| # Unless we get a test for the availability of libgd which also works |
| # for cross-compiling we disable the memusagestat generation in this |
| # situation. |
| -ifneq ($(cross-compiling),yes) |
| +ifeq ($(cross-compiling)$(OPTION_EGLIBC_MEMUSAGE),noy) |
| # If the gd library is available we build the `memusagestat' program. |
| ifneq ($(LIBGD),no) |
| others: $(objpfx)memusage |
| diff --git a/malloc/memusage.c b/malloc/memusage.c |
| index a57ba8e..732ba9d 100644 |
| --- a/malloc/memusage.c |
| +++ b/malloc/memusage.c |
| @@ -33,6 +33,7 @@ |
| #include <stdint.h> |
| #include <sys/mman.h> |
| #include <sys/time.h> |
| +#include <gnu/option-groups.h> |
| |
| #include <memusage.h> |
| |
| @@ -93,7 +94,11 @@ static __thread uintptr_t start_sp; |
| #define peak_stack peak_use[1] |
| #define peak_total peak_use[2] |
| |
| -#define DEFAULT_BUFFER_SIZE 32768 |
| +#ifndef __OPTION_EGLIBC_MEMUSAGE_DEFAULT_BUFFER_SIZE |
| +# define DEFAULT_BUFFER_SIZE 32768 |
| +#else |
| +# define DEFAULT_BUFFER_SIZE __OPTION_EGLIBC_MEMUSAGE_DEFAULT_BUFFER_SIZE |
| +#endif |
| static size_t buffer_size; |
| |
| static int fd = -1; |
| diff --git a/malloc/memusage.sh b/malloc/memusage.sh |
| index 8ab8cc2..d18f446 100755 |
| --- a/malloc/memusage.sh |
| +++ b/malloc/memusage.sh |
| @@ -35,7 +35,7 @@ do_missing_arg() { |
| |
| # Print help message |
| do_help() { |
| - echo $"Usage: memusage [OPTION]... PROGRAM [PROGRAMOPTION]... |
| + printf $"Usage: memusage [OPTION]... PROGRAM [PROGRAMOPTION]... |
| Profile memory usage of PROGRAM. |
| |
| -n,--progname=NAME Name of the program file to profile |
| diff --git a/math/Makefile b/math/Makefile |
| index 6388bae..ed1c511 100644 |
| --- a/math/Makefile |
| +++ b/math/Makefile |
| @@ -21,6 +21,8 @@ subdir := math |
| |
| include ../Makeconfig |
| |
| +include ../option-groups.mak |
| + |
| # Installed header files. |
| headers := math.h bits/mathcalls.h bits/mathinline.h bits/huge_val.h \ |
| bits/huge_valf.h bits/huge_vall.h bits/inf.h bits/nan.h \ |
| @@ -34,8 +36,8 @@ aux := setfpucw fpu_control |
| |
| # Build the -lm library. |
| |
| -extra-libs := libm |
| -extra-libs-others = $(extra-libs) |
| +extra-libs-$(OPTION_EGLIBC_LIBM) := libm |
| +extra-libs-others-$(OPTION_EGLIBC_LIBM) = $(extra-libs-$(OPTION_EGLIBC_LIBM)) |
| |
| libm-support = s_lib_version s_matherr s_signgam \ |
| fclrexcpt fgetexcptflg fraiseexcpt fsetexcptflg \ |
| diff --git a/misc/Makefile b/misc/Makefile |
| index aecb0da..e6b7c23 100644 |
| --- a/misc/Makefile |
| +++ b/misc/Makefile |
| @@ -19,6 +19,10 @@ |
| # Sub-makefile for misc portion of the library. |
| # |
| |
| +# Some system-dependent implementations of these functions use option |
| +# groups (see sysdeps/unix/sysv/linux/Makefile, for example). |
| +include ../option-groups.mak |
| + |
| subdir := misc |
| |
| include ../Makeconfig |
| @@ -46,40 +50,47 @@ routines := brk sbrk sstk ioctl \ |
| select pselect \ |
| acct chroot fsync sync fdatasync syncfs reboot \ |
| gethostid sethostid \ |
| - revoke vhangup \ |
| + vhangup \ |
| swapon swapoff mktemp mkstemp mkstemp64 mkdtemp \ |
| mkostemp mkostemp64 mkstemps mkstemps64 mkostemps mkostemps64 \ |
| ualarm usleep \ |
| gtty stty \ |
| ptrace \ |
| - fstab mntent mntent_r \ |
| + mntent mntent_r \ |
| utimes lutimes futimes futimesat \ |
| truncate ftruncate truncate64 ftruncate64 \ |
| - chflags fchflags \ |
| insremque getttyent getusershell getpass ttyslot \ |
| syslog syscall daemon \ |
| mmap mmap64 munmap mprotect msync madvise mincore remap_file_pages\ |
| mlock munlock mlockall munlockall \ |
| - efgcvt efgcvt_r qefgcvt qefgcvt_r \ |
| hsearch hsearch_r tsearch lsearch \ |
| err error ustat \ |
| - getsysstats dirname regexp \ |
| + getsysstats dirname \ |
| getloadavg getclktck \ |
| fgetxattr flistxattr fremovexattr fsetxattr getxattr \ |
| listxattr lgetxattr llistxattr lremovexattr lsetxattr \ |
| removexattr setxattr getauxval ifunc-impl-list |
| |
| +routines-$(OPTION_POSIX_REGEXP) += regexp |
| +routines-$(OPTION_EGLIBC_FSTAB) += fstab |
| +routines-$(OPTION_EGLIBC_BSD) += chflags fchflags revoke |
| +routines-$(OPTION_EGLIBC_FCVT) += efgcvt efgcvt_r qefgcvt qefgcvt_r |
| + |
| generated += tst-error1.mtrace tst-error1-mem.out |
| |
| aux := init-misc |
| install-lib := libg.a |
| gpl2lgpl := error.c error.h |
| |
| -tests := tst-dirname tst-tsearch tst-fdset tst-efgcvt tst-mntent tst-hsearch \ |
| - tst-error1 tst-pselect tst-insremque tst-mntent2 bug-hsearch1 |
| +tests := tst-dirname tst-tsearch tst-fdset tst-mntent tst-hsearch \ |
| + tst-pselect tst-insremque tst-mntent2 bug-hsearch1 |
| +tests-$(OPTION_POSIX_WIDE_CHAR_DEVICE_IO) += tst-error1 |
| +tests-$(OPTION_EGLIBC_FCVT) += tst-efgcvt |
| ifeq ($(run-built-tests),yes) |
| +ifeq (y,$(OPTION_POSIX_WIDE_CHAR_DEVICE_IO)) |
| tests-special += $(objpfx)tst-error1-mem.out |
| endif |
| +endif |
| |
| CFLAGS-select.c = -fexceptions -fasynchronous-unwind-tables |
| CFLAGS-tsearch.c = $(uses-callbacks) |
| diff --git a/misc/err.c b/misc/err.c |
| index 7b98157..efce8d5 100644 |
| --- a/misc/err.c |
| +++ b/misc/err.c |
| @@ -22,6 +22,7 @@ |
| #include <errno.h> |
| #include <string.h> |
| #include <stdio.h> |
| +#include <gnu/option-groups.h> |
| |
| #include <wchar.h> |
| #define flockfile(s) _IO_flockfile (s) |
| @@ -37,6 +38,7 @@ extern char *__progname; |
| va_end (ap); \ |
| } |
| |
| +#if __OPTION_POSIX_WIDE_CHAR_DEVICE_IO |
| static void |
| convert_and_print (const char *format, __gnuc_va_list ap) |
| { |
| @@ -81,6 +83,7 @@ convert_and_print (const char *format, __gnuc_va_list ap) |
| |
| __vfwprintf (stderr, wformat, ap); |
| } |
| +#endif |
| |
| void |
| vwarnx (const char *format, __gnuc_va_list ap) |
| @@ -88,9 +91,13 @@ vwarnx (const char *format, __gnuc_va_list ap) |
| flockfile (stderr); |
| if (_IO_fwide (stderr, 0) > 0) |
| { |
| +#if __OPTION_POSIX_WIDE_CHAR_DEVICE_IO |
| __fwprintf (stderr, L"%s: ", __progname); |
| convert_and_print (format, ap); |
| putwc_unlocked (L'\n', stderr); |
| +#else |
| + abort (); |
| +#endif |
| } |
| else |
| { |
| @@ -111,6 +118,7 @@ vwarn (const char *format, __gnuc_va_list ap) |
| flockfile (stderr); |
| if (_IO_fwide (stderr, 0) > 0) |
| { |
| +#if __OPTION_POSIX_WIDE_CHAR_DEVICE_IO |
| __fwprintf (stderr, L"%s: ", __progname); |
| if (format) |
| { |
| @@ -119,6 +127,9 @@ vwarn (const char *format, __gnuc_va_list ap) |
| } |
| __set_errno (error); |
| __fwprintf (stderr, L"%m\n"); |
| +#else |
| + abort (); |
| +#endif |
| } |
| else |
| { |
| diff --git a/misc/error.c b/misc/error.c |
| index aaa120d..d6cbc82 100644 |
| --- a/misc/error.c |
| +++ b/misc/error.c |
| @@ -35,6 +35,7 @@ |
| #endif |
| |
| #ifdef _LIBC |
| +# include <gnu/option-groups.h> |
| # include <libintl.h> |
| # include <stdbool.h> |
| # include <stdint.h> |
| @@ -205,6 +206,7 @@ error_tail (int status, int errnum, const char *message, va_list args) |
| #if _LIBC |
| if (_IO_fwide (stderr, 0) > 0) |
| { |
| +#if __OPTION_POSIX_WIDE_CHAR_DEVICE_IO |
| size_t len = strlen (message) + 1; |
| wchar_t *wmessage = NULL; |
| mbstate_t st; |
| @@ -265,6 +267,9 @@ error_tail (int status, int errnum, const char *message, va_list args) |
| |
| if (use_malloc) |
| free (wmessage); |
| +#else |
| + abort (); |
| +#endif |
| } |
| else |
| #endif |
| diff --git a/misc/tst-efgcvt.c b/misc/tst-efgcvt.c |
| index 5083fec..79ed36c 100644 |
| --- a/misc/tst-efgcvt.c |
| +++ b/misc/tst-efgcvt.c |
| @@ -59,7 +59,7 @@ static testcase ecvt_tests[] = |
| { 123.01, -4, 3, "" }, |
| { 126.71, -4, 3, "" }, |
| { 0.0, 4, 1, "0000" }, |
| -#if DBL_MANT_DIG == 53 |
| +#if DBL_MANT_DIG == 53 && !(defined __powerpc__ && defined __NO_FPRS__ && !defined _SOFT_FLOAT && !defined _SOFT_DOUBLE) |
| { 0x1p-1074, 3, -323, "494" }, |
| { -0x1p-1074, 3, -323, "494" }, |
| #endif |
| diff --git a/nis/Makefile b/nis/Makefile |
| index 037e674..c967850 100644 |
| --- a/nis/Makefile |
| +++ b/nis/Makefile |
| @@ -18,6 +18,8 @@ |
| # |
| # Makefile for NIS/NIS+ part. |
| # |
| +include ../option-groups.mak |
| + |
| subdir := nis |
| |
| include ../Makeconfig |
| @@ -30,19 +32,26 @@ endif |
| |
| # These are the databases available for the nis (and perhaps later nisplus) |
| # service. This must be a superset of the services in nss. |
| -databases = proto service hosts network grp pwd rpc ethers \ |
| - spwd netgrp alias publickey |
| +databases-y := proto service hosts network grp pwd rpc ethers \ |
| + spwd netgrp publickey |
| +databases-$(OPTION_EGLIBC_DB_ALIASES) += alias |
| |
| # Specify rules for the nss_* modules. |
| -services := nis nisplus compat |
| +# The 'compat' module includes nis support, and the 'nss' directory |
| +# includes a bare-bones "files" library, so we'll include 'compat' in |
| +# OPTION_EGLIBC_NIS. |
| +services-y := |
| +services-$(OPTION_EGLIBC_NIS) += nis nisplus compat |
| + |
| +extra-libs-$(OPTION_EGLIBC_NIS) += libnsl |
| +extra-libs-y += $(services-y:%=libnss_%) |
| |
| -extra-libs = libnsl $(services:%=libnss_%) |
| # These libraries will be built in the `others' pass rather than |
| # the `lib' pass, because they depend on libc.so being built already. |
| -extra-libs-others = $(extra-libs) |
| +extra-libs-others-y += $(extra-libs-y) |
| |
| # The sources are found in the appropriate subdir. |
| -subdir-dirs = $(services:%=nss_%) |
| +subdir-dirs = $(services-y:%=nss_%) |
| vpath %.c $(subdir-dirs) |
| |
| libnsl-routines = yp_xdr ypclnt ypupdate_xdr \ |
| @@ -60,11 +69,11 @@ libnsl-routines = yp_xdr ypclnt ypupdate_xdr \ |
| libnss_compat-routines := $(addprefix compat-,grp pwd spwd initgroups) |
| libnss_compat-inhibit-o = $(filter-out .os,$(object-suffixes)) |
| |
| -libnss_nis-routines := $(addprefix nis-,$(databases)) nis-initgroups \ |
| +libnss_nis-routines := $(addprefix nis-,$(databases-y)) nis-initgroups \ |
| nss-nis |
| libnss_nis-inhibit-o = $(filter-out .os,$(object-suffixes)) |
| |
| -libnss_nisplus-routines := $(addprefix nisplus-,$(databases)) nisplus-parser \ |
| +libnss_nisplus-routines := $(addprefix nisplus-,$(databases-y)) nisplus-parser \ |
| nss-nisplus nisplus-initgroups |
| libnss_nisplus-inhibit-o = $(filter-out .os,$(object-suffixes)) |
| |
| @@ -80,12 +89,12 @@ libnsl-libc = $(common-objpfx)linkobj/libc.so |
| # 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 |
| diff --git a/nptl/Makefile b/nptl/Makefile |
| index aaca0a4..596ca3c 100644 |
| --- a/nptl/Makefile |
| +++ b/nptl/Makefile |
| @@ -18,6 +18,8 @@ |
| # |
| # Sub-makefile for NPTL portion of the library. |
| # |
| +include ../option-groups.mak |
| + |
| subdir := nptl |
| |
| include ../Makeconfig |
| @@ -118,7 +120,7 @@ libpthread-routines = nptl-init vars events version pt-interp \ |
| 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 \ |
| @@ -138,8 +140,10 @@ libpthread-routines = nptl-init vars events version pt-interp \ |
| # pthread_setgid pthread_setegid pthread_setregid \ |
| # pthread_setresgid |
| |
| +libpthread-routines-$(OPTION_EGLIBC_INET) := herrno res |
| libpthread-shared-only-routines = version pt-interp pt-allocrtsig \ |
| unwind-forcedunwind |
| + |
| libpthread-static-only-routines = pthread_atfork |
| |
| # Since cancellation handling is in large parts handled using exceptions |
| @@ -220,7 +224,7 @@ tests = tst-typesizes \ |
| tst-mutexpi1 tst-mutexpi2 tst-mutexpi3 tst-mutexpi4 tst-mutexpi5 \ |
| tst-mutexpi5a tst-mutexpi6 tst-mutexpi7 tst-mutexpi7a tst-mutexpi8 \ |
| tst-mutexpi9 \ |
| - tst-spin1 tst-spin2 tst-spin3 tst-spin4 \ |
| + tst-spin1 tst-spin2 tst-spin3 \ |
| tst-cond1 tst-cond2 tst-cond3 tst-cond4 tst-cond5 tst-cond6 tst-cond7 \ |
| tst-cond8 tst-cond9 tst-cond10 tst-cond11 tst-cond12 tst-cond13 \ |
| tst-cond14 tst-cond15 tst-cond16 tst-cond17 tst-cond18 tst-cond19 \ |
| @@ -256,14 +260,14 @@ tests = tst-typesizes \ |
| tst-cancel6 tst-cancel7 tst-cancel8 tst-cancel9 tst-cancel10 \ |
| tst-cancel11 tst-cancel12 tst-cancel13 tst-cancel14 tst-cancel15 \ |
| tst-cancel16 tst-cancel17 tst-cancel18 tst-cancel19 tst-cancel20 \ |
| - tst-cancel21 tst-cancel22 tst-cancel23 tst-cancel24 tst-cancel25 \ |
| + tst-cancel21 tst-cancel22 tst-cancel23 tst-cancel25 \ |
| tst-cancel-self tst-cancel-self-cancelstate \ |
| tst-cancel-self-canceltype tst-cancel-self-testcancel \ |
| tst-cleanup0 tst-cleanup1 tst-cleanup2 tst-cleanup3 tst-cleanup4 \ |
| tst-flock1 tst-flock2 \ |
| tst-signal1 tst-signal2 tst-signal3 tst-signal4 tst-signal5 \ |
| tst-signal6 tst-signal7 \ |
| - tst-exec1 tst-exec2 tst-exec3 tst-exec4 \ |
| + tst-exec2 tst-exec3 tst-exec4 \ |
| tst-exit1 tst-exit2 tst-exit3 \ |
| tst-stdio1 tst-stdio2 \ |
| tst-stack1 tst-stack2 tst-stack3 tst-stack4 tst-pthread-getattr \ |
| @@ -271,13 +275,12 @@ tests = tst-typesizes \ |
| tst-unload \ |
| tst-dlsym1 \ |
| tst-sysconf \ |
| - tst-locale1 tst-locale2 \ |
| + tst-locale2 \ |
| tst-umask1 \ |
| tst-popen1 \ |
| tst-clock1 \ |
| tst-context1 \ |
| tst-sched1 \ |
| - tst-backtrace1 \ |
| tst-abstime \ |
| tst-vfork1 tst-vfork2 tst-vfork1x tst-vfork2x \ |
| tst-getpid3 \ |
| @@ -288,9 +291,16 @@ xtests = tst-setuid1 tst-setuid1-static tst-setuid2 \ |
| tst-mutexpp1 tst-mutexpp6 tst-mutexpp10 |
| test-srcs = tst-oddstacklimit |
| |
| -# Test expected to fail on most targets (except x86_64) due to bug |
| -# 18435 - pthread_once hangs when init routine throws an exception. |
| -test-xfail-tst-once5 = yes |
| +# 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 |
| diff --git a/nptl/pthread_create.c b/nptl/pthread_create.c |
| index d10f4ea..14257ce 100644 |
| --- a/nptl/pthread_create.c |
| +++ b/nptl/pthread_create.c |
| @@ -33,6 +33,7 @@ |
| #include <default-sched.h> |
| #include <futex-internal.h> |
| |
| +#include <gnu/option-groups.h> |
| #include <shlib-compat.h> |
| |
| #include <stap-probe.h> |
| @@ -262,8 +263,10 @@ START_THREAD_DEFN |
| THREAD_SETMEM (pd, cpuclock_offset, now); |
| #endif |
| |
| +#if __OPTION_EGLIBC_INET |
| /* Initialize resolver state pointer. */ |
| __resp = &pd->res; |
| +#endif |
| |
| /* Initialize pointers to locale data. */ |
| __ctype_init (); |
| @@ -346,8 +349,10 @@ START_THREAD_DEFN |
| /* Run the destructor for the thread-local data. */ |
| __nptl_deallocate_tsd (); |
| |
| +#if __OPTION_EGLIBC_INET |
| /* Clean up any state libc stored in thread-local variables. */ |
| __libc_thread_freeres (); |
| +#endif |
| |
| /* If this is the last thread we terminate the process now. We |
| do not notify the debugger, it might just irritate it if there |
| diff --git a/nscd/Makefile b/nscd/Makefile |
| index ede941d..f4f3f8d 100644 |
| --- a/nscd/Makefile |
| +++ b/nscd/Makefile |
| @@ -18,14 +18,17 @@ |
| # |
| # Sub-makefile for nscd portion of the library. |
| # |
| +include ../option-groups.mak |
| + |
| subdir := nscd |
| |
| include ../Makeconfig |
| |
| ifneq ($(use-nscd),no) |
| -routines := nscd_getpw_r nscd_getgr_r nscd_gethst_r nscd_getai \ |
| +routines-$(OPTION_EGLIBC_INET) += \ |
| + nscd_getpw_r nscd_getgr_r nscd_gethst_r nscd_getai \ |
| nscd_initgroups nscd_getserv_r nscd_netgroup |
| -aux := nscd_helper |
| +aux-$(OPTION_EGLIBC_INET) += nscd_helper |
| endif |
| |
| # To find xmalloc.c |
| @@ -37,14 +40,18 @@ nscd-modules := nscd connections pwdcache getpwnam_r getpwuid_r grpcache \ |
| dbg_log nscd_conf nscd_stat cache mem nscd_setup_thread \ |
| xmalloc xstrdup aicache initgrcache gai res_hconf \ |
| netgroupcache |
| - |
| +ifneq (y,$(OPTION_EGLIBC_NIS)) |
| +# If we haven't build libnsl.so, then we'll need to include our |
| +# own copy of nis_hash. |
| +nscd-modules += nis_hash |
| +endif |
| ifeq ($(build-nscd)$(have-thread-library),yesyes) |
| |
| -others += nscd |
| -others-pie += nscd |
| -install-sbin := nscd |
| +others-$(OPTION_EGLIBC_INET) += nscd |
| +others-pie-$(OPTION_EGLIBC_INET) += nscd |
| +install-sbin-$(OPTION_EGLIBC_INET) += nscd |
| |
| -extra-objs = $(nscd-modules:=.o) |
| +extra-objs-$(OPTION_EGLIBC_INET) += $(nscd-modules:=.o) |
| |
| endif |
| |
| @@ -100,7 +107,15 @@ include $(patsubst %,$(..)cppflags-iterator.mk,$(cpp-srcs-left)) |
| $(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 |
| diff --git a/nscd/nis_hash.c b/nscd/nis_hash.c |
| new file mode 100644 |
| index 0000000..d244c41 |
| --- /dev/null |
| +++ b/nscd/nis_hash.c |
| @@ -0,0 +1,3 @@ |
| +/* If OPTION_EGLIBC_NIS is disabled, nscd can't get this from libnsl.so; |
| + we need our own copy. */ |
| +#include "../nis/nis_hash.c" |
| diff --git a/nss/Makefile b/nss/Makefile |
| index 65ab7b5..19f0aef 100644 |
| --- a/nss/Makefile |
| +++ b/nss/Makefile |
| @@ -18,28 +18,35 @@ |
| # |
| # 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 ethers \ |
| - spwd netgrp alias sgrp |
| +databases-y = grp pwd spwd sgrp |
| +databases-$(OPTION_EGLIBC_INET) \ |
| + += proto service hosts network ethers \ |
| + netgrp |
| +databases-$(OPTION_EGLIBC_DB_ALIASES) += alias |
| + |
| +routines-$(OPTION_EGLIBC_INET) += digits_dots |
| |
| ifneq (,$(filter sunrpc,$(subdirs))) |
| -databases += key rpc |
| +databases-$(OPTION_EGLIBC_INET) += key rpc |
| have-sunrpc := 1 |
| else |
| have-sunrpc := 0 |
| endif |
| +# This is the trivial part which goes into libc itself. |
| +routines-y += nsswitch getnssent getnssent_r \ |
| + $(addsuffix -lookup,$(databases-y)) |
| + |
| CPPFLAGS-getent.c = -DHAVE_SUNRPC=$(have-sunrpc) |
| |
| others := getent makedb |
| @@ -47,8 +54,9 @@ install-bin := getent makedb |
| makedb-modules = xmalloc hash-string |
| extra-objs += $(makedb-modules:=.o) |
| |
| -tests = test-netdb tst-nss-test1 test-digits-dots tst-nss-getpwent |
| -xtests = bug-erange |
| +tests = tst-nss-test1 tst-nss-getpwent |
| +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 |
| @@ -63,7 +71,7 @@ subdir-dirs = $(services:%=nss_%) |
| vpath %.c $(subdir-dirs) ../locale/programs ../intl |
| |
| |
| -libnss_files-routines := $(addprefix files-,$(databases)) \ |
| +libnss_files-routines := $(addprefix files-,$(databases-y)) \ |
| files-initgroups files-have_o_cloexec files-init |
| |
| libnss_db-dbs := $(addprefix db-,\ |
| @@ -86,6 +94,45 @@ tests-static = tst-nss-static |
| tests += $(tests-static) |
| endif |
| |
| +ifneq ($(OPTION_EGLIBC_NSSWITCH),y) |
| + |
| +ifndef OPTION_EGLIBC_NSSWITCH_FIXED_CONFIG |
| +$(error OPTION_EGLIBC_NSSWITCH_FIXED_CONFIG variable left unset) |
| +endif |
| + |
| +ifndef OPTION_EGLIBC_NSSWITCH_FIXED_FUNCTIONS |
| +$(error OPTION_EGLIBC_NSSWITCH_FIXED_FUNCTIONS variable left unset) |
| +endif |
| + |
| +ifeq (,$(wildcard $(OPTION_EGLIBC_NSSWITCH_FIXED_CONFIG))) |
| +$(warning OPTION_EGLIBC_NSSWITCH is disabled, but fixed config file) |
| +$(error does not exist: $(OPTION_EGLIBC_NSSWITCH_FIXED_CONFIG)) |
| +endif |
| + |
| +ifeq (,$(wildcard $(OPTION_EGLIBC_NSSWITCH_FIXED_FUNCTIONS))) |
| +$(warning OPTION_EGLIBC_NSSWITCH is disabled, but fixed functions file) |
| +$(error does not exist: $(OPTION_EGLIBC_NSSWITCH_FIXED_FUNCTIONS)) |
| +endif |
| + |
| +before-compile := $(objpfx)fixed-nsswitch.h |
| +generated := fixed-nsswitch.h |
| +$(objpfx)fixed-nsswitch.h $(objfpx)fixed-nsswitch-libs: \ |
| + $(objpfx)gen-fixed-nsswitch \ |
| + $(OPTION_EGLIBC_NSSWITCH_FIXED_CONFIG) |
| + $< $(objpfx)fixed-nsswitch.h \ |
| + $(objpfx)fixed-nsswitch-libs \ |
| + $(OPTION_EGLIBC_NSSWITCH_FIXED_CONFIG) |
| + |
| +$(objpfx)gen-fixed-nsswitch: gen-fixed-nsswitch.c \ |
| + $(common-objpfx)option-groups.config \ |
| + $(OPTION_EGLIBC_NSSWITCH_FIXED_FUNCTIONS) |
| + $(native-compile) |
| +gen-fixed-nsswitch-CFLAGS = \ |
| + -g3 -O -Wall \ |
| + -I $(objpfx) \ |
| + -DFIXED_FUNCTIONS='"$(OPTION_EGLIBC_NSSWITCH_FIXED_FUNCTIONS)"' |
| +endif |
| + |
| include ../Rules |
| |
| ifeq (yes,$(have-selinux)) |
| diff --git a/nss/fixed-nsswitch.conf b/nss/fixed-nsswitch.conf |
| new file mode 100644 |
| index 0000000..91bb675 |
| --- /dev/null |
| +++ b/nss/fixed-nsswitch.conf |
| @@ -0,0 +1,22 @@ |
| +# /etc/nsswitch.conf |
| +# |
| +# Example configuration for fixed name service. |
| +# See the description of OPTION_EGLIBC_NSSWITCH in option-groups.def |
| +# for details. |
| +# |
| + |
| +aliases: files |
| + |
| +passwd: files |
| +group: files |
| +shadow: files |
| + |
| +hosts: files dns |
| +networks: files dns |
| + |
| +protocols: files |
| +services: files |
| +ethers: files |
| +rpc: files |
| + |
| +netgroup: files |
| diff --git a/nss/fixed-nsswitch.functions b/nss/fixed-nsswitch.functions |
| new file mode 100644 |
| index 0000000..2f3fa83 |
| --- /dev/null |
| +++ b/nss/fixed-nsswitch.functions |
| @@ -0,0 +1,121 @@ |
| +/* List of functions defined for fixed NSS in GNU C Library. |
| + Copyright (C) 1996, 1997, 1998, 2005 Free Software Foundation, Inc. |
| + This file is part of the GNU C Library. |
| + |
| + The GNU C Library is free software; you can redistribute it and/or |
| + modify it under the terms of the GNU Lesser General Public |
| + License as published by the Free Software Foundation; either |
| + version 2.1 of the License, or (at your option) any later version. |
| + |
| + The GNU C Library is distributed in the hope that it will be useful, |
| + but WITHOUT ANY WARRANTY; without even the implied warranty of |
| + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU |
| + Lesser General Public License for more details. |
| + |
| + You should have received a copy of the GNU Lesser General Public |
| + License along with the GNU C Library; if not, write to the Free |
| + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA |
| + 02111-1307 USA. */ |
| + |
| +/* When OPTION_EGLIBC_NSSWITCH is disabled (see option-groups.def), |
| + EGLIBC does not use the 'dlopen' and 'dlsym' functions to look for |
| + database query functions in the individual name service libraries. |
| + Instead, it uses a set of functions chosen at compile time, as |
| + directed by the OPTION_EGLIBC_NSSWITCH_FIXED_FUNCTIONS file. This |
| + file is a sample of what you might use there. |
| + |
| + This file is C source code; it should only contain invocations of |
| + the following macros: |
| + |
| + - DEFINE_ENT (DATABASE, SERVICE, X) |
| + |
| + Declare the 'setXent', 'getXent_r', and 'endXent' functions that |
| + query DATABASE using the service library 'libnss_SERVICE.so.2'. |
| + DATABASE should be the full name of the database as it appears in |
| + 'nsswitch.conf', like 'passwd' or 'aliases'. |
| + |
| + (The non-reentrant 'getXent' functions are implemented in terms |
| + of the reentrant 'getXent_r' functions, so there is no need to |
| + refer to them explicitly here.) |
| + |
| + - DEFINE_GETBY (DATABASE, SERVICE, X, KEY) |
| + |
| + Declare the 'getXbyKEY_r' functions that query DATABASE using |
| + SERVICE. DATABASE and SERVICE are as described above. |
| + |
| + (The non-reentrant 'getXbyKEY' functions are implemented in terms |
| + of the reentrant 'getXbyKEY_r' functions, so there is no need to |
| + refer to them explicitly here.) |
| + |
| + Use the special key 'name3' for the service library function that |
| + implements the 'getaddrinfo' function. |
| + |
| + - DEFINE_GET (DATABASE, SERVICE, QUERY) |
| + |
| + Declare the 'getQUERY_r' functions that query DATABASE using |
| + SERVICE. This is used for functions like 'getpwnam'. |
| + |
| + (The non-reentrant 'getQUERY' functions are implemented in terms |
| + of the reentrant 'getQUERY_r' functions, so there is no need to |
| + refer to them explicitly here.) |
| + |
| + This sample file only includes functions that consult the files in |
| + '/etc', and the Domain Name System (DNS). */ |
| + |
| +/* aliases */ |
| +DEFINE_ENT (aliases, files, alias) |
| +DEFINE_GETBY (aliases, files, alias, name) |
| + |
| +/* ethers */ |
| +DEFINE_ENT (ethers, files, ether) |
| + |
| +/* group */ |
| +DEFINE_ENT (group, files, gr) |
| +DEFINE_GET (group, files, grgid) |
| +DEFINE_GET (group, files, grnam) |
| + |
| +/* hosts */ |
| +DEFINE_ENT (hosts, files, host) |
| +DEFINE_GETBY (hosts, files, host, addr) |
| +DEFINE_GETBY (hosts, files, host, name) |
| +DEFINE_GETBY (hosts, files, host, name2) |
| +DEFINE_GET (hosts, files, hostton) |
| +DEFINE_GET (hosts, files, ntohost) |
| +DEFINE_GETBY (hosts, dns, host, addr) |
| +DEFINE_GETBY (hosts, dns, host, name) |
| +DEFINE_GETBY (hosts, dns, host, name2) |
| +DEFINE_GETBY (hosts, dns, host, name3) |
| + |
| +/* netgroup */ |
| +DEFINE_ENT (netgroup, files, netgr) |
| + |
| +/* networks */ |
| +DEFINE_ENT (networks, files, net) |
| +DEFINE_GETBY (networks, files, net, name) |
| +DEFINE_GETBY (networks, files, net, addr) |
| +DEFINE_GETBY (networks, dns, net, name) |
| +DEFINE_GETBY (networks, dns, net, addr) |
| + |
| +/* protocols */ |
| +DEFINE_ENT (protocols, files, proto) |
| +DEFINE_GETBY (protocols, files, proto, name) |
| +DEFINE_GETBY (protocols, files, proto, number) |
| + |
| +/* passwd */ |
| +DEFINE_ENT (passwd, files, pw) |
| +DEFINE_GET (passwd, files, pwnam) |
| +DEFINE_GET (passwd, files, pwuid) |
| + |
| +/* rpc */ |
| +DEFINE_ENT (rpc, files, rpc) |
| +DEFINE_GETBY (rpc, files, rpc, name) |
| +DEFINE_GETBY (rpc, files, rpc, number) |
| + |
| +/* services */ |
| +DEFINE_ENT (services, files, serv) |
| +DEFINE_GETBY (services, files, serv, name) |
| +DEFINE_GETBY (services, files, serv, port) |
| + |
| +/* shadow */ |
| +DEFINE_ENT (shadow, files, sp) |
| +DEFINE_GET (shadow, files, spnam) |
| diff --git a/nss/gen-fixed-nsswitch.c b/nss/gen-fixed-nsswitch.c |
| new file mode 100644 |
| index 0000000..6e1c98c |
| --- /dev/null |
| +++ b/nss/gen-fixed-nsswitch.c |
| @@ -0,0 +1,803 @@ |
| +/* gen-fixed-nsswitch.c --- generate fixed name service data structures |
| + Copyright (C) 1996-1999, 2001-2006, 2007 Free Software Foundation, Inc. |
| + This file is part of the GNU C Library. |
| + |
| + The GNU C Library is free software; you can redistribute it and/or |
| + modify it under the terms of the GNU Lesser General Public |
| + License as published by the Free Software Foundation; either |
| + version 2.1 of the License, or (at your option) any later version. |
| + |
| + The GNU C Library is distributed in the hope that it will be useful, |
| + but WITHOUT ANY WARRANTY; without even the implied warranty of |
| + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU |
| + Lesser General Public License for more details. |
| + |
| + You should have received a copy of the GNU Lesser General Public |
| + License along with the GNU C Library; if not, write to the Free |
| + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA |
| + 02111-1307 USA. */ |
| + |
| +#define _GNU_SOURCE |
| + |
| +#include <stdlib.h> |
| +#include <stdio.h> |
| +#include <errno.h> |
| +#include <string.h> |
| +#include <stdarg.h> |
| +#include <assert.h> |
| +#include <ctype.h> |
| + |
| +#include "gnu/lib-names.h" |
| +#include "nss.h" |
| + |
| +/* Provide a fallback definition to allow this file to be compiled outside |
| + libc. */ |
| +#ifndef internal_function |
| +# define internal_function |
| +#endif |
| + |
| + |
| +/* Simple utilities. */ |
| + |
| +void __attribute__ ((noreturn)) |
| +error (const char *message) |
| +{ |
| + fprintf (stderr, "%s\n", message); |
| + exit (1); |
| +} |
| + |
| + |
| +void * |
| +check_alloc (void *p) |
| +{ |
| + if (p) |
| + return p; |
| + else |
| + error ("out of memory"); |
| +} |
| + |
| +void * |
| +xmalloc (size_t size) |
| +{ |
| + return check_alloc (malloc (size)); |
| +} |
| + |
| + |
| +/* Format ARGS according to FORMAT, and return the result as a |
| + malloc'ed string. */ |
| +char * |
| +saprintf (const char *format, ...) |
| +{ |
| + va_list args; |
| + size_t len; |
| + char *buf; |
| + |
| + va_start (args, format); |
| + len = vsnprintf (NULL, 0, format, args); |
| + va_end (args); |
| + |
| + buf = xmalloc (len + 1); |
| + va_start (args, format); |
| + assert (len == vsnprintf (buf, len + 1, format, args)); |
| + va_end (args); |
| + |
| + return buf; |
| +} |
| + |
| + |
| + |
| +/* Data structures representing the configuration file in memory. */ |
| + |
| +/* These are copied from nsswitch.h. |
| + |
| + We could simply #include that file, but this program runs on the |
| + build machine and links against the build machine's libraries, |
| + whereas that header is meant for use by target code; it uses |
| + 'libc_hidden_proto', 'internal_function', and related hair. Since |
| + we've copied the parsing code, we might as well copy the data |
| + structure definitions as well. */ |
| + |
| +/* Actions performed after lookup finished. */ |
| +typedef enum |
| +{ |
| + NSS_ACTION_CONTINUE, |
| + NSS_ACTION_RETURN |
| +} lookup_actions; |
| + |
| + |
| +typedef struct service_library |
| +{ |
| + /* Name of service (`files', `dns', `nis', ...). */ |
| + const char *name; |
| + /* Pointer to the loaded shared library. */ |
| + void *lib_handle; |
| + /* And the link to the next entry. */ |
| + struct service_library *next; |
| +} service_library; |
| + |
| + |
| +/* For mapping a function name to a function pointer. It is known in |
| + nsswitch.c:nss_lookup_function that a string pointer for the lookup key |
| + is the first member. */ |
| +typedef struct |
| +{ |
| + const char *fct_name; |
| + void *fct_ptr; |
| +} known_function; |
| + |
| + |
| +typedef struct service_user |
| +{ |
| + /* And the link to the next entry. */ |
| + struct service_user *next; |
| + /* Action according to result. */ |
| + lookup_actions actions[5]; |
| + /* Link to the underlying library object. */ |
| + service_library *library; |
| + /* Collection of known functions. |
| + |
| + With OPTION_EGLIBC_NSSWITCH enabled, this is the root of a |
| + 'tsearch'-style tree. |
| + |
| + With OPTION_EGLIBC_NSSWITCH disabled, this is an array of |
| + pointers to known_function structures, NULL-terminated. */ |
| + union |
| + { |
| + void *tree; |
| + const known_function **array; |
| + } known; |
| + /* Name of the service (`files', `dns', `nis', ...). */ |
| + const char *name; |
| +} service_user; |
| + |
| +/* To access the action based on the status value use this macro. */ |
| +#define nss_next_action(ni, status) ((ni)->actions[2 + status]) |
| + |
| + |
| +typedef struct name_database_entry |
| +{ |
| + /* And the link to the next entry. */ |
| + struct name_database_entry *next; |
| + /* List of service to be used. */ |
| + service_user *service; |
| + /* Name of the database. */ |
| + const char *name; |
| +} name_database_entry; |
| + |
| + |
| +typedef struct name_database |
| +{ |
| + /* List of all known databases. */ |
| + name_database_entry *entry; |
| + /* List of libraries with service implementation. */ |
| + service_library *library; |
| +} name_database; |
| + |
| + |
| + |
| +/* Gathering the contents of the FIXED_FUNCTIONS file. */ |
| + |
| +/* It should be possible to generate this list automatically by |
| + looking at the services and databases used in the nsswitch.conf |
| + file, and having a hard-coded set of queries supported on each |
| + database. */ |
| + |
| +/* We #include the FIXED_FUNCTIONS file several times to build an |
| + array of function structures holding its data. */ |
| +enum function_kind { |
| + fk_end = 0, /* Last entry. */ |
| + fk_setent, /* Like setpwent. */ |
| + fk_getent, /* Like getpwent. */ |
| + fk_endent, /* Like endpwent. */ |
| + fk_getby, /* Like gethostbyname. */ |
| + fk_get /* Like getpwnam. */ |
| +}; |
| + |
| + |
| +struct function { |
| + /* What kind of function this is. */ |
| + enum function_kind kind; |
| + |
| + /* The database and service of the function being hardwired in. */ |
| + char *database, *service; |
| + |
| + /* The kind of entry being queried, for 'fk_setent', 'fk_getent', |
| + 'fk_endent', and 'fk_getby' functions. */ |
| + char *entry; |
| + |
| + /* The key, for 'fk_getby' entries. */ |
| + char *key; |
| + |
| + /* The value and key, for 'fk_get' entries. */ |
| + char *value_and_key; |
| +}; |
| + |
| + |
| +const struct function functions[] = |
| + { |
| + |
| +#define DEFINE_ENT(database, service, entry) \ |
| + { fk_setent, #database, #service, #entry }, \ |
| + { fk_getent, #database, #service, #entry }, \ |
| + { fk_endent, #database, #service, #entry }, |
| +#define DEFINE_GETBY(database, service, entry, key) \ |
| + { fk_getby, #database, #service, #entry, #key }, |
| +#define DEFINE_GET(database, service, value_and_key) \ |
| + { fk_get, #database, #service, NULL, NULL, #value_and_key }, |
| + |
| +#include FIXED_FUNCTIONS |
| + |
| +#undef DEFINE_ENT |
| +#undef DEFINE_GETBY |
| +#undef DEFINE_GET |
| + |
| + { fk_end } |
| + }; |
| + |
| + |
| +/* Parsing the config file. Functions copied from nsswitch.c. */ |
| + |
| +#define __strchrnul strchrnul |
| +#define __getline getline |
| +#define __strncasecmp strncasecmp |
| + |
| +/* Prototypes for the local functions. */ |
| +static name_database *nss_parse_file (const char *fname) internal_function; |
| +static name_database_entry *nss_getline (char *line) internal_function; |
| +static service_user *nss_parse_service_list (const char *line) |
| + internal_function; |
| + |
| +static name_database * |
| +internal_function |
| +nss_parse_file (const char *fname) |
| +{ |
| + FILE *fp; |
| + name_database *result; |
| + name_database_entry *last; |
| + char *line; |
| + size_t len; |
| + |
| + /* Open the configuration file. */ |
| + fp = fopen (fname, "rc"); |
| + if (fp == NULL) |
| + return NULL; |
| + |
| + // /* No threads use this stream. */ |
| + // __fsetlocking (fp, FSETLOCKING_BYCALLER); |
| + |
| + result = (name_database *) xmalloc (sizeof (name_database)); |
| + |
| + result->entry = NULL; |
| + result->library = NULL; |
| + last = NULL; |
| + line = NULL; |
| + len = 0; |
| + do |
| + { |
| + name_database_entry *this; |
| + ssize_t n; |
| + |
| + n = __getline (&line, &len, fp); |
| + if (n < 0) |
| + break; |
| + if (line[n - 1] == '\n') |
| + line[n - 1] = '\0'; |
| + |
| + /* Because the file format does not know any form of quoting we |
| + can search forward for the next '#' character and if found |
| + make it terminating the line. */ |
| + *__strchrnul (line, '#') = '\0'; |
| + |
| + /* If the line is blank it is ignored. */ |
| + if (line[0] == '\0') |
| + continue; |
| + |
| + /* Each line completely specifies the actions for a database. */ |
| + this = nss_getline (line); |
| + if (this != NULL) |
| + { |
| + if (last != NULL) |
| + last->next = this; |
| + else |
| + result->entry = this; |
| + |
| + last = this; |
| + } |
| + } |
| + while (!feof_unlocked (fp)); |
| + |
| + /* Free the buffer. */ |
| + free (line); |
| + /* Close configuration file. */ |
| + fclose (fp); |
| + |
| + return result; |
| +} |
| + |
| + |
| +/* Read the source names: |
| + `( <source> ( "[" "!"? (<status> "=" <action> )+ "]" )? )*' |
| + */ |
| +static service_user * |
| +internal_function |
| +nss_parse_service_list (const char *line) |
| +{ |
| + service_user *result = NULL, **nextp = &result; |
| + |
| + while (1) |
| + { |
| + service_user *new_service; |
| + const char *name; |
| + |
| + while (isspace (line[0])) |
| + ++line; |
| + if (line[0] == '\0') |
| + /* No source specified. */ |
| + return result; |
| + |
| + /* Read <source> identifier. */ |
| + name = line; |
| + while (line[0] != '\0' && !isspace (line[0]) && line[0] != '[') |
| + ++line; |
| + if (name == line) |
| + return result; |
| + |
| + |
| + new_service = (service_user *) xmalloc (sizeof (*new_service)); |
| + new_service->name = (char *) xmalloc (line - name + 1); |
| + |
| + *((char *) __mempcpy ((char *) new_service->name, name, line - name)) |
| + = '\0'; |
| + |
| + /* Set default actions. */ |
| + new_service->actions[2 + NSS_STATUS_TRYAGAIN] = NSS_ACTION_CONTINUE; |
| + new_service->actions[2 + NSS_STATUS_UNAVAIL] = NSS_ACTION_CONTINUE; |
| + new_service->actions[2 + NSS_STATUS_NOTFOUND] = NSS_ACTION_CONTINUE; |
| + new_service->actions[2 + NSS_STATUS_SUCCESS] = NSS_ACTION_RETURN; |
| + new_service->actions[2 + NSS_STATUS_RETURN] = NSS_ACTION_RETURN; |
| + new_service->library = NULL; |
| + new_service->known.tree = NULL; |
| + new_service->next = NULL; |
| + |
| + while (isspace (line[0])) |
| + ++line; |
| + |
| + if (line[0] == '[') |
| + { |
| + /* Read criterions. */ |
| + do |
| + ++line; |
| + while (line[0] != '\0' && isspace (line[0])); |
| + |
| + do |
| + { |
| + int not; |
| + enum nss_status status; |
| + lookup_actions action; |
| + |
| + /* Grok ! before name to mean all statii but that one. */ |
| + not = line[0] == '!'; |
| + if (not) |
| + ++line; |
| + |
| + /* Read status name. */ |
| + name = line; |
| + while (line[0] != '\0' && !isspace (line[0]) && line[0] != '=' |
| + && line[0] != ']') |
| + ++line; |
| + |
| + /* Compare with known statii. */ |
| + if (line - name == 7) |
| + { |
| + if (__strncasecmp (name, "SUCCESS", 7) == 0) |
| + status = NSS_STATUS_SUCCESS; |
| + else if (__strncasecmp (name, "UNAVAIL", 7) == 0) |
| + status = NSS_STATUS_UNAVAIL; |
| + else |
| + return result; |
| + } |
| + else if (line - name == 8) |
| + { |
| + if (__strncasecmp (name, "NOTFOUND", 8) == 0) |
| + status = NSS_STATUS_NOTFOUND; |
| + else if (__strncasecmp (name, "TRYAGAIN", 8) == 0) |
| + status = NSS_STATUS_TRYAGAIN; |
| + else |
| + return result; |
| + } |
| + else |
| + return result; |
| + |
| + while (isspace (line[0])) |
| + ++line; |
| + if (line[0] != '=') |
| + return result; |
| + do |
| + ++line; |
| + while (isspace (line[0])); |
| + |
| + name = line; |
| + while (line[0] != '\0' && !isspace (line[0]) && line[0] != '=' |
| + && line[0] != ']') |
| + ++line; |
| + |
| + if (line - name == 6 && __strncasecmp (name, "RETURN", 6) == 0) |
| + action = NSS_ACTION_RETURN; |
| + else if (line - name == 8 |
| + && __strncasecmp (name, "CONTINUE", 8) == 0) |
| + action = NSS_ACTION_CONTINUE; |
| + else |
| + return result; |
| + |
| + if (not) |
| + { |
| + /* Save the current action setting for this status, |
| + set them all to the given action, and reset this one. */ |
| + const lookup_actions save = new_service->actions[2 + status]; |
| + new_service->actions[2 + NSS_STATUS_TRYAGAIN] = action; |
| + new_service->actions[2 + NSS_STATUS_UNAVAIL] = action; |
| + new_service->actions[2 + NSS_STATUS_NOTFOUND] = action; |
| + new_service->actions[2 + NSS_STATUS_SUCCESS] = action; |
| + new_service->actions[2 + status] = save; |
| + } |
| + else |
| + new_service->actions[2 + status] = action; |
| + |
| + /* Skip white spaces. */ |
| + while (isspace (line[0])) |
| + ++line; |
| + } |
| + while (line[0] != ']'); |
| + |
| + /* Skip the ']'. */ |
| + ++line; |
| + } |
| + |
| + *nextp = new_service; |
| + nextp = &new_service->next; |
| + } |
| +} |
| + |
| +static name_database_entry * |
| +internal_function |
| +nss_getline (char *line) |
| +{ |
| + const char *name; |
| + name_database_entry *result; |
| + size_t len; |
| + |
| + /* Ignore leading white spaces. ATTENTION: this is different from |
| + what is implemented in Solaris. The Solaris man page says a line |
| + beginning with a white space character is ignored. We regard |
| + this as just another misfeature in Solaris. */ |
| + while (isspace (line[0])) |
| + ++line; |
| + |
| + /* Recognize `<database> ":"'. */ |
| + name = line; |
| + while (line[0] != '\0' && !isspace (line[0]) && line[0] != ':') |
| + ++line; |
| + if (line[0] == '\0' || name == line) |
| + /* Syntax error. */ |
| + return NULL; |
| + *line++ = '\0'; |
| + |
| + len = strlen (name) + 1; |
| + |
| + result = (name_database_entry *) xmalloc (sizeof (*result)); |
| + result->name = (char *) xmalloc (len); |
| + |
| + /* Save the database name. */ |
| + memcpy ((char *) result->name, name, len); |
| + |
| + /* Parse the list of services. */ |
| + result->service = nss_parse_service_list (line); |
| + |
| + result->next = NULL; |
| + return result; |
| +} |
| + |
| + |
| + |
| +/* Generating code for statically initialized nsswitch structures. */ |
| + |
| + |
| +/* Return the service-neutral suffix of the name of the service |
| + library function referred to by the function F. The result is |
| + allocated with malloc. */ |
| +char * |
| +known_function_suffix (const struct function *f) |
| +{ |
| + switch (f->kind) |
| + { |
| + case fk_setent: |
| + return saprintf ("set%sent", f->entry); |
| + |
| + case fk_getent: |
| + return saprintf ("get%sent_r", f->entry); |
| + |
| + case fk_endent: |
| + return saprintf ("end%sent", f->entry); |
| + |
| + case fk_getby: |
| + return saprintf ("get%sby%s_r", f->entry, f->key); |
| + |
| + case fk_get: |
| + return saprintf ("get%s_r", f->value_and_key); |
| + |
| + default: |
| + abort (); |
| + } |
| +} |
| + |
| + |
| +/* Return the name of the service library function referred to by the |
| + function F. The result is allocated with malloc. */ |
| +char * |
| +known_function_name (const struct function *f) |
| +{ |
| + return saprintf ("_nss_%s_%s", f->service, known_function_suffix (f)); |
| +} |
| + |
| + |
| +/* Write initialized known_function structures to OUT for |
| + all the functions we'll use. */ |
| +void |
| +generate_known_functions (FILE *out) |
| +{ |
| + int i; |
| + |
| + /* First, generate weak references to the functions. The service |
| + libraries depend on libc, and if these references weren't weak, |
| + we'd be making libc depend circularly on the service |
| + libraries. */ |
| + for (i = 0; functions[i].kind; i++) |
| + { |
| + char *name = known_function_name (&functions[i]); |
| + fprintf (out, "typeof (%s) %s __attribute__ ((weak));\n", |
| + name, name); |
| + } |
| + fputs ("\n", out); |
| + |
| + /* Then, a table mapping names to functions. */ |
| + fputs ("static const known_function fixed_known_functions[] = {\n", |
| + out); |
| + for (i = 0; functions[i].kind; i++) |
| + { |
| + const struct function *f = &functions[i]; |
| + char *suffix = known_function_suffix (f); |
| + |
| + fprintf (out, " /* %2d */ { \"%s\", _nss_%s_%s },\n", |
| + i, suffix, f->service, suffix); |
| + } |
| + fputs ("};\n", out); |
| + fputs ("\n", out); |
| +} |
| + |
| + |
| +/* Print code to OUT for an initialized array of pointers to the |
| + 'known_function' structures needed for USER, which is for |
| + DATABASE. Return its name, allocated with malloc. */ |
| +char * |
| +generate_known_function_list (FILE *out, |
| + const name_database_entry *database, |
| + const service_user *user) |
| +{ |
| + char *list_name = saprintf ("fixed_%s_%s_known_funcs", |
| + database->name, user->name); |
| + fprintf (out, "static const known_function *%s[] = {\n", |
| + list_name); |
| + int i; |
| + for (i = 0; functions[i].kind; i++) |
| + if (strcmp (functions[i].database, database->name) == 0 |
| + && strcmp (functions[i].service, user->name) == 0) |
| + fprintf (out, " &fixed_known_functions[%d], /* %s */\n", |
| + i, known_function_name (&functions[i])); |
| + fputs (" NULL\n", out); |
| + fputs ("};\n", out); |
| + fputs ("\n", out); |
| + |
| + return list_name; |
| +} |
| + |
| + |
| +/* Return the name of the status value STATUS, as a statically |
| + allocated string. */ |
| +const char * |
| +lookup_status_name (enum nss_status status) |
| +{ |
| + switch (status) |
| + { |
| + case NSS_STATUS_TRYAGAIN: return "NSS_STATUS_TRYAGAIN"; |
| + case NSS_STATUS_UNAVAIL: return "NSS_STATUS_UNAVAIL"; |
| + case NSS_STATUS_NOTFOUND: return "NSS_STATUS_NOTFOUND"; |
| + case NSS_STATUS_SUCCESS: return "NSS_STATUS_SUCCESS"; |
| + case NSS_STATUS_RETURN: return "NSS_STATUS_RETURN"; |
| + default: abort (); |
| + }; |
| +} |
| + |
| + |
| +/* Return the name of ACTION as a statically allocated string. */ |
| +const char * |
| +lookup_action_name (lookup_actions action) |
| +{ |
| + switch (action) |
| + { |
| + case NSS_ACTION_CONTINUE: return "NSS_ACTION_CONTINUE"; |
| + case NSS_ACTION_RETURN: return "NSS_ACTION_RETURN"; |
| + default: abort (); |
| + } |
| +} |
| + |
| + |
| +/* Print code to OUT for the list of service_user structures starting |
| + with USER, which are all for DATABASE. Return the name of the |
| + first structure in that list, or zero if USER is NULL. */ |
| +char * |
| +generate_service_user_list (FILE *out, |
| + name_database_entry *database, |
| + service_user *user) |
| +{ |
| + if (user) |
| + { |
| + /* Generate the tail of the list. */ |
| + char *next_name = generate_service_user_list (out, database, user->next); |
| + /* Generate our known function list. */ |
| + char *known_function_list_name = |
| + generate_known_function_list (out, database, user); |
| + |
| + char *name = saprintf ("fixed_%s_%s_user", database->name, user->name); |
| + |
| + fprintf (out, "static const service_user %s = {\n", name); |
| + if (next_name) |
| + fprintf (out, " (service_user *) &%s,\n", next_name); |
| + else |
| + fprintf (out, " NULL, /* no next entry */\n"); |
| + fputs (" {\n", out); |
| + int i; |
| + for (i = 0; i < sizeof (user->actions) / sizeof (user->actions[0]); i++) |
| + fprintf (out, " %s, /* %s */\n", |
| + lookup_action_name (user->actions[i]), |
| + lookup_status_name (i - 2)); |
| + fputs (" },\n", out); |
| + fprintf (out, " NULL, /* we never need the service library */\n"); |
| + fprintf (out, " { .array = %s },\n", known_function_list_name); |
| + fprintf (out, " \"%s\"\n", user->name); |
| + fputs ("};\n", out); |
| + fputs ("\n", out); |
| + |
| + return name; |
| + } |
| + else |
| + return NULL; |
| +} |
| + |
| + |
| +/* Print code to OUT for the list of name_database_entry structures |
| + starting with DATABASE. Return the name of the first structure |
| + in that list, or zero if DATABASE is NULL. */ |
| +char * |
| +generate_name_database_entries (FILE *out, name_database_entry *database) |
| +{ |
| + if (database) |
| + { |
| + char *next_name = generate_name_database_entries (out, database->next); |
| + char *service_user_name |
| + = generate_service_user_list (out, database, database->service); |
| + char *name = saprintf ("fixed_%s_name_database", database->name); |
| + |
| + fprintf (out, "static const name_database_entry %s = {\n", name); |
| + |
| + if (next_name) |
| + fprintf (out, " (name_database_entry *) &%s,\n", next_name); |
| + else |
| + fprintf (out, " NULL,\n"); |
| + |
| + if (service_user_name) |
| + fprintf (out, " (service_user *) &%s,\n", service_user_name); |
| + else |
| + fprintf (out, " NULL,\n"); |
| + |
| + fprintf (out, " \"%s\"\n", database->name); |
| + fprintf (out, "};\n"); |
| + fputs ("\n", out); |
| + |
| + return name; |
| + } |
| + else |
| + return NULL; |
| +} |
| + |
| + |
| +void |
| +generate_name_database (FILE *out, name_database *service_table) |
| +{ |
| + /* Produce a linked list of the known name_database_entry |
| + structures. */ |
| + char *entries = generate_name_database_entries (out, service_table->entry); |
| + |
| + /* Now produce the main structure that points to them all. */ |
| + fprintf (out, "static const name_database fixed_name_database = {\n"); |
| + if (entries) |
| + fprintf (out, " (name_database_entry *) &%s,\n", entries); |
| + else |
| + fprintf (out, " NULL,\n"); |
| + fputs (" NULL /* we don't need the libraries */\n" |
| + "};\n", |
| + out); |
| +} |
| + |
| + |
| + |
| +/* Generating the list of service libraries we generate references to. */ |
| + |
| +/* String with revision number of the shared object files. */ |
| +static const char *const nss_shlib_revision = LIBNSS_FILES_SO + 15; |
| + |
| +void |
| +generate_service_lib_list (FILE *out, name_database *service_table) |
| +{ |
| + int i, j; |
| + int printed_any = 0; |
| + |
| + for (i = 0; functions[i].kind; i++) |
| + { |
| + /* Mention each service library only once. */ |
| + for (j = 0; j < i; j++) |
| + if (strcmp (functions[i].service, functions[j].service) == 0) |
| + break; |
| + |
| + if (j >= i) |
| + { |
| + if (printed_any) |
| + putc (' ', out); |
| + fprintf (out, "-lnss_%s", |
| + functions[i].service, |
| + nss_shlib_revision); |
| + printed_any = 1; |
| + } |
| + } |
| +} |
| + |
| + |
| +/* Main. */ |
| + |
| +int |
| +main (int argc, char **argv) |
| +{ |
| + if (argc != 4) |
| + { |
| + fprintf (stderr, "usage: gen-fixed-nsswitch HEADER SERVLIBS CONFIG\n"); |
| + exit (1); |
| + } |
| + |
| + name_database *service_table = nss_parse_file (argv[3]); |
| + |
| + FILE *header = fopen (argv[1], "w"); |
| + if (! header) |
| + { |
| + fprintf (stderr, |
| + "gen-fixed-nsswitch: couldn't open output file %s: %s\n", |
| + argv[1], strerror (errno)); |
| + exit (1); |
| + } |
| + fputs ("/* Generated by nss/gen-fixed-nsswitch.c. */\n", header); |
| + fputs ("\n", header); |
| + generate_known_functions (header); |
| + generate_name_database (header, service_table); |
| + fclose (header); |
| + |
| + FILE *service_lib_list = fopen (argv[2], "w"); |
| + if (! service_lib_list) |
| + { |
| + fprintf (stderr, |
| + "gen-fixed-nsswitch: couldn't open output file %s: %s\n", |
| + argv[2], strerror (errno)); |
| + exit (1); |
| + } |
| + generate_service_lib_list (service_lib_list, service_table); |
| + fclose (service_lib_list); |
| + |
| + return 0; |
| +} |
| diff --git a/nss/getent.c b/nss/getent.c |
| index 34df848..674c8ee 100644 |
| --- a/nss/getent.c |
| +++ b/nss/getent.c |
| @@ -39,6 +39,7 @@ |
| #include <netinet/ether.h> |
| #include <netinet/in.h> |
| #include <sys/socket.h> |
| +#include <gnu/option-groups.h> |
| |
| /* Get libc version number. */ |
| #include <version.h> |
| @@ -91,6 +92,7 @@ warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.\n\ |
| fprintf (stream, gettext ("Written by %s.\n"), "Thorsten Kukuk"); |
| } |
| |
| +#if __OPTION_EGLIBC_DB_ALIASES |
| /* This is for aliases */ |
| static void |
| print_aliases (struct aliasent *alias) |
| @@ -135,7 +137,9 @@ aliases_keys (int number, char *key[]) |
| |
| return result; |
| } |
| +#endif /* __OPTION_EGLIBC_DB_ALIASES */ |
| |
| +#if __OPTION_EGLIBC_INET |
| /* This is for ethers */ |
| static int |
| ethers_keys (int number, char *key[]) |
| @@ -179,6 +183,7 @@ ethers_keys (int number, char *key[]) |
| |
| return result; |
| } |
| +#endif /* __OPTION_EGLIBC_INET */ |
| |
| /* This is for group */ |
| static void |
| @@ -301,6 +306,7 @@ gshadow_keys (int number, char *key[]) |
| return result; |
| } |
| |
| +#if __OPTION_EGLIBC_INET |
| /* This is for hosts */ |
| static void |
| print_hosts (struct hostent *host) |
| @@ -598,6 +604,7 @@ networks_keys (int number, char *key[]) |
| |
| return result; |
| } |
| +#endif /* __OPTION_EGLIBC_INET */ |
| |
| /* Now is all for passwd */ |
| static void |
| @@ -650,6 +657,7 @@ passwd_keys (int number, char *key[]) |
| return result; |
| } |
| |
| +#if __OPTION_EGLIBC_INET |
| /* This is for protocols */ |
| static void |
| print_protocols (struct protoent *proto) |
| @@ -807,6 +815,7 @@ services_keys (int number, char *key[]) |
| |
| return result; |
| } |
| +#endif /* __OPTION_EGLIBC_INET */ |
| |
| /* This is for shadow */ |
| static void |
| @@ -873,23 +882,36 @@ struct |
| } databases[] = |
| { |
| #define D(name) { #name, name ## _keys }, |
| -D(ahosts) |
| -D(ahostsv4) |
| -D(ahostsv6) |
| -D(aliases) |
| -D(ethers) |
| + |
| +#if __OPTION_EGLIBC_INET |
| +# define DN(name) D(name) |
| +#else |
| +# define DN(name) |
| +#endif |
| + |
| +#if __OPTION_EGLIBC_DB_ALIASES |
| +# define DA(name) D(name) |
| +#else |
| +# define DA(name) |
| +#endif |
| + |
| +DN(ahosts) |
| +DN(ahostsv4) |
| +DN(ahostsv6) |
| +DA(aliases) |
| +DN(ethers) |
| D(group) |
| D(gshadow) |
| -D(hosts) |
| -D(initgroups) |
| -D(netgroup) |
| -D(networks) |
| +DN(hosts) |
| +DN(initgroups) |
| +DN(netgroup) |
| +DN(networks) |
| D(passwd) |
| -D(protocols) |
| +DN(protocols) |
| #if HAVE_SUNRPC |
| -D(rpc) |
| +DN(rpc) |
| #endif |
| -D(services) |
| +DN(services) |
| D(shadow) |
| #undef D |
| { NULL, NULL } |
| diff --git a/nss/getnssent_r.c b/nss/getnssent_r.c |
| index f5b9036..f09f7fe 100644 |
| --- a/nss/getnssent_r.c |
| +++ b/nss/getnssent_r.c |
| @@ -16,6 +16,7 @@ |
| <http://www.gnu.org/licenses/>. */ |
| |
| #include <errno.h> |
| +#include <gnu/option-groups.h> |
| #include <netdb.h> |
| #include "nsswitch.h" |
| |
| @@ -59,11 +60,13 @@ __nss_setent (const char *func_name, db_lookup_function lookup_fct, |
| } fct; |
| int no_more; |
| |
| +#if __OPTION_EGLIBC_INET |
| if (res && __res_maybe_init (&_res, 0) == -1) |
| { |
| __set_h_errno (NETDB_INTERNAL); |
| return; |
| } |
| +#endif /* __OPTION_EGLIBC_INET */ |
| |
| /* Cycle through the services and run their `setXXent' functions until |
| we find an available service. */ |
| @@ -101,11 +104,13 @@ __nss_endent (const char *func_name, db_lookup_function lookup_fct, |
| } fct; |
| int no_more; |
| |
| +#if __OPTION_EGLIBC_INET |
| if (res && __res_maybe_init (&_res, 0) == -1) |
| { |
| __set_h_errno (NETDB_INTERNAL); |
| return; |
| } |
| +#endif /* __OPTION_EGLIBC_INET */ |
| |
| /* Cycle through all the services and run their endXXent functions. */ |
| no_more = setup (func_name, lookup_fct, &fct.ptr, nip, startp, 1); |
| @@ -141,12 +146,14 @@ __nss_getent_r (const char *getent_func_name, |
| int no_more; |
| enum nss_status status; |
| |
| +#if __OPTION_EGLIBC_INET |
| if (res && __res_maybe_init (&_res, 0) == -1) |
| { |
| *h_errnop = NETDB_INTERNAL; |
| *result = NULL; |
| return errno; |
| } |
| +#endif /* __OPTION_EGLIBC_INET */ |
| |
| /* Initialize status to return if no more functions are found. */ |
| status = NSS_STATUS_NOTFOUND; |
| @@ -161,7 +168,7 @@ __nss_getent_r (const char *getent_func_name, |
| 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 |
| diff --git a/nss/nsswitch.c b/nss/nsswitch.c |
| index 9712623..c81e207 100644 |
| --- a/nss/nsswitch.c |
| +++ b/nss/nsswitch.c |
| @@ -26,6 +26,7 @@ |
| #include <stdio_ext.h> |
| #include <stdlib.h> |
| #include <string.h> |
| +#include <gnu/option-groups.h> |
| |
| #include <aliases.h> |
| #include <grp.h> |
| @@ -41,6 +42,15 @@ |
| #include "../nscd/nscd_proto.h" |
| #include <sysdep.h> |
| |
| +/* When OPTION_EGLIBC_NSSWITCH is disabled, we use fixed tables of |
| + databases and services, generated at library build time. Thus: |
| + - We can't reconfigure individual databases, so we don't need a |
| + name-to-database map. |
| + - We never add databases or service libraries, or look up functions |
| + at runtime, so there's no need for a lock to protect our tables. |
| + See ../option-groups.def for the details. */ |
| +#if __OPTION_EGLIBC_NSSWITCH |
| + |
| /* Prototypes for the local functions. */ |
| static name_database *nss_parse_file (const char *fname) internal_function; |
| static name_database_entry *nss_getline (char *line) internal_function; |
| @@ -79,6 +89,9 @@ bool __nss_database_custom[NSS_DBSIDX_max]; |
| |
| __libc_lock_define_initialized (static, lock) |
| |
| +#define lock_nsswitch __libc_lock_lock (lock) |
| +#define unlock_nsswitch __libc_lock_unlock (lock) |
| + |
| #if !defined DO_STATIC_NSS || defined SHARED |
| /* String with revision number of the shared object files. */ |
| static const char *const __nss_shlib_revision = LIBNSS_FILES_SO + 15; |
| @@ -93,6 +106,20 @@ static name_database *service_table; |
| __libc_freeres. */ |
| static name_database_entry *defconfig_entries; |
| |
| +#else /* __OPTION_EGLIBC_NSSWITCH */ |
| + |
| +/* Bring in the statically initialized service table we generated at |
| + build time. */ |
| +#include "fixed-nsswitch.h" |
| + |
| +const static name_database *service_table = &fixed_name_database; |
| + |
| +/* Nothing ever changes, so there's no need to lock anything. */ |
| +#define lock_nsswitch (0) |
| +#define unlock_nsswitch (0) |
| + |
| +#endif /* __OPTION_EGLIBC_NSSWITCH */ |
| + |
| |
| #ifdef USE_NSCD |
| /* Nonzero if this is the nscd process. */ |
| @@ -109,20 +136,22 @@ __nss_database_lookup (const char *database, const char *alternate_name, |
| const char *defconfig, service_user **ni) |
| { |
| /* Prevent multiple threads to change the service table. */ |
| - __libc_lock_lock (lock); |
| + lock_nsswitch; |
| |
| /* Reconsider database variable in case some other thread called |
| `__nss_configure_lookup' while we waited for the lock. */ |
| if (*ni != NULL) |
| { |
| - __libc_lock_unlock (lock); |
| + unlock_nsswitch; |
| return 0; |
| } |
| |
| +#if __OPTION_EGLIBC_NSSWITCH |
| /* Are we initialized yet? */ |
| if (service_table == NULL) |
| /* Read config file. */ |
| service_table = nss_parse_file (_PATH_NSSWITCH_CONF); |
| +#endif |
| |
| /* Test whether configuration data is available. */ |
| if (service_table != NULL) |
| @@ -144,6 +173,7 @@ __nss_database_lookup (const char *database, const char *alternate_name, |
| *ni = entry->service; |
| } |
| |
| +#if __OPTION_EGLIBC_NSSWITCH |
| /* No configuration data is available, either because nsswitch.conf |
| doesn't exist or because it doesn't have a line for this database. |
| |
| @@ -166,13 +196,23 @@ __nss_database_lookup (const char *database, const char *alternate_name, |
| { |
| entry->next = defconfig_entries; |
| entry->service = *ni; |
| - entry->name[0] = '\0'; |
| + entry->name = ""; |
| defconfig_entries = entry; |
| } |
| } |
| } |
| +#else |
| + /* Without the dynamic behavior, we can't process defconfig. The |
| + databases the user specified at library build time are all you |
| + get. */ |
| + if (*ni == NULL) |
| + { |
| + unlock_nsswitch; |
| + return -1; |
| + } |
| +#endif |
| |
| - __libc_lock_unlock (lock); |
| + unlock_nsswitch; |
| |
| return *ni != NULL ? 0 : -1; |
| } |
| @@ -252,6 +292,7 @@ __nss_next2 (service_user **ni, const char *fct_name, const char *fct2_name, |
| libc_hidden_def (__nss_next2) |
| |
| |
| +#if __OPTION_EGLIBC_NSSWITCH |
| int |
| attribute_compat_text_section |
| __nss_next (service_user **ni, const char *fct_name, void **fctp, int status, |
| @@ -300,13 +341,13 @@ __nss_configure_lookup (const char *dbname, const char *service_line) |
| } |
| |
| /* Prevent multiple threads to change the service table. */ |
| - __libc_lock_lock (lock); |
| + lock_nsswitch; |
| |
| /* Install new rules. */ |
| *databases[cnt].dbp = new_db; |
| __nss_database_custom[cnt] = true; |
| |
| - __libc_lock_unlock (lock); |
| + unlock_nsswitch; |
| |
| return 0; |
| } |
| @@ -402,7 +443,7 @@ __nss_lookup_function (service_user *ni, const char *fct_name) |
| void **found, *result; |
| |
| /* We now modify global data. Protect it. */ |
| - __libc_lock_lock (lock); |
| + lock_nsswitch; |
| |
| /* Search the tree of functions previously requested. Data in the |
| tree are `known_function' structures, whose first member is a |
| @@ -413,7 +454,7 @@ __nss_lookup_function (service_user *ni, const char *fct_name) |
| enough to a pointer to our structure to use as a lookup key that |
| will be passed to `known_compare' (above). */ |
| |
| - found = __tsearch (&fct_name, &ni->known, &known_compare); |
| + found = __tsearch (&fct_name, &ni->known.tree, &known_compare); |
| if (found == NULL) |
| /* This means out-of-memory. */ |
| result = NULL; |
| @@ -440,7 +481,7 @@ __nss_lookup_function (service_user *ni, const char *fct_name) |
| #endif |
| /* Oops. We can't instantiate this node properly. |
| Remove it from the tree. */ |
| - __tdelete (&fct_name, &ni->known, &known_compare); |
| + __tdelete (&fct_name, &ni->known.tree, &known_compare); |
| free (known); |
| result = NULL; |
| } |
| @@ -520,13 +561,43 @@ __nss_lookup_function (service_user *ni, const char *fct_name) |
| } |
| |
| /* Remove the lock. */ |
| - __libc_lock_unlock (lock); |
| + unlock_nsswitch; |
| |
| return result; |
| } |
| libc_hidden_def (__nss_lookup_function) |
| |
| |
| +#else /* below if ! __OPTION_EGLIBC_NSSWITCH */ |
| + |
| + |
| +int |
| +__nss_configure_lookup (const char *dbname, const char *service_line) |
| +{ |
| + /* We can't dynamically configure lookup without |
| + OPTION_EGLIBC_NSSWITCH. */ |
| + __set_errno (EINVAL); |
| + return -1; |
| +} |
| + |
| + |
| +void * |
| +__nss_lookup_function (service_user *ni, const char *fct_name) |
| +{ |
| + int i; |
| + const known_function **known = ni->known.array; |
| + |
| + for (i = 0; known[i]; i++) |
| + if (strcmp (fct_name, known[i]->fct_name) == 0) |
| + return known[i]->fct_ptr; |
| + |
| + return NULL; |
| +} |
| +libc_hidden_def (__nss_lookup_function) |
| +#endif |
| + |
| + |
| +#if __OPTION_EGLIBC_NSSWITCH |
| static name_database * |
| internal_function |
| nss_parse_file (const char *fname) |
| @@ -632,8 +703,10 @@ nss_parse_service_list (const char *line) |
| + (line - name + 1)); |
| if (new_service == NULL) |
| return result; |
| + new_service->name = (char *) (new_service + 1); |
| |
| - *((char *) __mempcpy (new_service->name, name, line - name)) = '\0'; |
| + *((char *) __mempcpy ((char *) new_service->name, name, line - name)) |
| + = '\0'; |
| |
| /* Set default actions. */ |
| new_service->actions[2 + NSS_STATUS_TRYAGAIN] = NSS_ACTION_CONTINUE; |
| @@ -642,7 +715,7 @@ nss_parse_service_list (const char *line) |
| new_service->actions[2 + NSS_STATUS_SUCCESS] = NSS_ACTION_RETURN; |
| new_service->actions[2 + NSS_STATUS_RETURN] = NSS_ACTION_RETURN; |
| new_service->library = NULL; |
| - new_service->known = NULL; |
| + new_service->known.tree = NULL; |
| new_service->next = NULL; |
| |
| while (isspace (line[0])) |
| @@ -778,9 +851,10 @@ nss_getline (char *line) |
| result = (name_database_entry *) malloc (sizeof (name_database_entry) + len); |
| if (result == NULL) |
| return NULL; |
| + result->name = (char *) (result + 1); |
| |
| /* Save the database name. */ |
| - memcpy (result->name, name, len); |
| + memcpy ((char *) result->name, name, len); |
| |
| /* Parse the list of services. */ |
| result->service = nss_parse_service_list (line); |
| @@ -816,6 +890,7 @@ nss_new_service (name_database *database, const char *name) |
| return *currentp; |
| } |
| #endif |
| +#endif /* __OPTION_EGLIBC_NSSWITCH */ |
| |
| |
| #if defined SHARED && defined USE_NSCD |
| @@ -834,6 +909,7 @@ nss_load_all_libraries (const char *service, const char *def) |
| } |
| |
| |
| +#if __OPTION_EGLIBC_INET |
| /* Called by nscd and nscd alone. */ |
| void |
| __nss_disable_nscd (void (*cb) (size_t, struct traced_file *)) |
| @@ -857,8 +933,10 @@ __nss_disable_nscd (void (*cb) (size_t, struct traced_file *)) |
| __nss_not_use_nscd_services = -1; |
| __nss_not_use_nscd_netgroup = -1; |
| } |
| +#endif /* __OPTION_EGLIBC_INET */ |
| #endif |
| |
| +#if __OPTION_EGLIBC_NSSWITCH |
| static void |
| free_database_entries (name_database_entry *entry) |
| { |
| @@ -871,8 +949,8 @@ free_database_entries (name_database_entry *entry) |
| { |
| service_user *olds = service; |
| |
| - if (service->known != NULL) |
| - __tdestroy (service->known, free); |
| + if (service->known.tree != NULL) |
| + __tdestroy (service->known.tree, free); |
| |
| service = service->next; |
| free (olds); |
| @@ -926,3 +1004,4 @@ libc_freeres_fn (free_mem) |
| |
| free (top); |
| } |
| +#endif /* __OPTION_EGLIBC_NSSWITCH */ |
| diff --git a/nss/nsswitch.h b/nss/nsswitch.h |
| index a5318fa..1730977 100644 |
| --- a/nss/nsswitch.h |
| +++ b/nss/nsswitch.h |
| @@ -65,10 +65,20 @@ typedef struct service_user |
| lookup_actions actions[5]; |
| /* Link to the underlying library object. */ |
| service_library *library; |
| - /* Collection of known functions. */ |
| - void *known; |
| + /* Collection of known functions. |
| + |
| + With OPTION_EGLIBC_NSSWITCH enabled, this is the root of a |
| + 'tsearch'-style tree. |
| + |
| + With OPTION_EGLIBC_NSSWITCH disabled, this is an array of |
| + pointers to known_function structures, NULL-terminated. */ |
| + union |
| + { |
| + void *tree; |
| + const known_function **array; |
| + } known; |
| /* Name of the service (`files', `dns', `nis', ...). */ |
| - char name[0]; |
| + const char *name; |
| } service_user; |
| |
| /* To access the action based on the status value use this macro. */ |
| @@ -82,7 +92,7 @@ typedef struct name_database_entry |
| /* List of service to be used. */ |
| service_user *service; |
| /* Name of the database. */ |
| - char name[0]; |
| + const char *name; |
| } name_database_entry; |
| |
| |
| diff --git a/posix/Makefile b/posix/Makefile |
| index 15e8818..609ed03 100644 |
| --- a/posix/Makefile |
| +++ b/posix/Makefile |
| @@ -18,6 +18,8 @@ |
| # |
| # Sub-makefile for POSIX portion of the library. |
| # |
| +include ../option-groups.mak |
| + |
| subdir := posix |
| |
| include ../Makeconfig |
| @@ -43,13 +45,24 @@ routines := \ |
| getpgid setpgid getpgrp bsd-getpgrp setpgrp getsid setsid \ |
| getresuid getresgid setresuid setresgid \ |
| pathconf sysconf fpathconf \ |
| - glob glob64 fnmatch regex \ |
| + glob glob64 fnmatch \ |
| confstr \ |
| getopt getopt1 getopt_init \ |
| sched_setp sched_getp sched_sets sched_gets sched_yield sched_primax \ |
| sched_primin sched_rr_gi sched_getaffinity sched_setaffinity \ |
| - getaddrinfo gai_strerror wordexp \ |
| pread pwrite pread64 pwrite64 \ |
| + posix_madvise \ |
| + get_child_max sched_cpucount sched_cpualloc sched_cpufree |
| + |
| +routines-$(OPTION_EGLIBC_INET) += getaddrinfo gai_strerror |
| + |
| +ifeq (y,$(OPTION_POSIX_REGEXP_GLIBC)) |
| +routines-$(OPTION_POSIX_REGEXP) += regex |
| +else |
| +routines-$(OPTION_POSIX_REGEXP) += xregex |
| +endif |
| + |
| +routines-$(OPTION_EGLIBC_SPAWN) += \ |
| spawn_faction_init spawn_faction_destroy spawn_faction_addclose \ |
| spawn_faction_addopen spawn_faction_adddup2 \ |
| spawnattr_init spawnattr_destroy \ |
| @@ -61,37 +74,54 @@ routines := \ |
| posix_madvise \ |
| get_child_max sched_cpucount sched_cpualloc sched_cpufree |
| |
| +routines-$(OPTION_EGLIBC_WORDEXP) += wordexp |
| + |
| aux := init-posix environ |
| -tests := tstgetopt testfnm runtests runptests \ |
| +tests := tstgetopt testfnm runtests \ |
| tst-preadwrite tst-preadwrite64 test-vfork regexbug1 \ |
| - tst-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 \ |
| + 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 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-nice tst-nanosleep \ |
| + transbug \ |
| + tst-vfork1 tst-vfork2 tst-vfork3 tst-waitid \ |
| + bug-glob1 bug-glob2 bug-glob3 tst-sysconf \ |
| tst-execvp1 tst-execvp2 tst-execlp1 tst-execlp2 \ |
| tst-execv1 tst-execv2 tst-execl1 tst-execl2 \ |
| tst-execve1 tst-execve2 tst-execle1 tst-execle2 \ |
| - tst-execvp3 tst-execvp4 tst-rfc3484 tst-rfc3484-2 \ |
| - tst-rfc3484-3 \ |
| - tst-getaddrinfo3 tst-fnmatch2 tst-cpucount tst-cpuset \ |
| + tst-execvp3 tst-execvp4 \ |
| + tst-fnmatch2 tst-cpucount tst-cpuset \ |
| bug-getopt1 bug-getopt2 bug-getopt3 bug-getopt4 \ |
| bug-getopt5 tst-getopt_long1 bug-regex34 bug-regex35 \ |
| tst-pathconf tst-getaddrinfo4 tst-rxspencer-no-utf8 \ |
| tst-fnmatch3 bug-regex36 tst-getaddrinfo5 |
| -xtests := bug-ga2 |
| + |
| +tests-$(OPTION_EGLIBC_LOCALE_CODE) \ |
| + += tst-fnmatch tst-regexloc bug-regex1 bug-regex5 \ |
| + bug-regex23 bug-regex25 bug-regex32 bug-regex33 |
| +tests-$(OPTION_EGLIBC_INET) \ |
| + += tst-getaddrinfo bug-ga1 tst-getaddrinfo2 \ |
| + tst-rfc3484 tst-rfc3484-2 tst-rfc3484-3 tst-getaddrinfo3 |
| +tests-$(OPTION_POSIX_REGEXP_GLIBC) \ |
| + += runptests bug-regex11 bug-regex13 bug-regex16 \ |
| + tst-regex2 tst-rxspencer tst-pcre tst-boost |
| +ifeq (yy,$(OPTION_EGLIBC_LOCALE_CODE)$(OPTION_POSIX_REGEXP_GLIBC)) |
| +tests += tst-regex bug-regex17 bug-regex18 bug-regex19 bug-regex20 \ |
| + bug-regex22 bug-regex26 |
| +endif |
| +xtests-$(OPTION_EGLIBC_INET) += bug-ga2 |
| + |
| ifeq (yes,$(build-shared)) |
| test-srcs := globtest |
| -tests += wordexp-test tst-exec tst-spawn |
| +tests += tst-exec |
| +tests-$(OPTION_EGLIBC_SPAWN) += tst-spawn |
| +tests-$(OPTION_EGLIBC_WORDEXP) += wordexp-test |
| endif |
| tests-static = tst-exec-static tst-spawn-static |
| tests += $(tests-static) |
| @@ -117,7 +147,10 @@ generated += $(addprefix wordexp-test-result, 1 2 3 4 5 6 7 8 9 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 +158,16 @@ endif |
| # XXX Please note that for now we ignore the result of this test. |
| tests-special += $(objpfx)annexc.out |
| ifeq ($(run-built-tests),yes) |
| -tests-special += $(objpfx)bug-regex2-mem.out $(objpfx)bug-regex14-mem.out \ |
| +tests-special += $(objpfx)bug-regex2-mem.out \ |
| $(objpfx)bug-regex21-mem.out $(objpfx)bug-regex31-mem.out \ |
| - $(objpfx)tst-rxspencer-no-utf8-mem.out $(objpfx)tst-pcre-mem.out \ |
| - $(objpfx)tst-boost-mem.out $(objpfx)tst-getconf.out \ |
| + $(objpfx)tst-getconf.out \ |
| $(objpfx)bug-glob2-mem.out $(objpfx)tst-vfork3-mem.out \ |
| $(objpfx)tst-fnmatch-mem.out $(objpfx)bug-regex36-mem.out |
| +ifeq (y,$(OPTION_POSIX_REGEXP_GLIBC)) |
| +tests-special += $(objpfx)bug-regex14-mem.out $(objpfx)tst-rxspencer-no-utf8-mem.out \ |
| + $(objpfx)tst-pcre-mem.out $(objpfx)tst-boost-mem.out |
| +endif |
| + |
| xtests-special += $(objpfx)bug-ga2-mem.out |
| endif |
| |
| @@ -143,6 +180,8 @@ $(objpfx)globtest.out: globtest.sh $(objpfx)globtest |
| $(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 +244,10 @@ tst-dir-ARGS = `pwd` `cd $(common-objdir)/$(subdir); pwd` `cd $(common-objdir); |
| tst-chmod-ARGS = $(objdir) |
| tst-vfork3-ARGS = --test-dir=$(objpfx) |
| |
| -tst-rxspencer-ARGS = --utf8 rxspencer/tests |
| +tst-rxspencer-ARGS = rxspencer/tests |
| +ifeq (y,$(OPTION_EGLIBC_LOCALE_CODE)) |
| +tst-rxspencer-ARGS += --utf8 |
| +endif |
| tst-rxspencer-no-utf8-ARGS = rxspencer/tests |
| tst-pcre-ARGS = PCRE.tests |
| tst-boost-ARGS = BOOST.tests |
| diff --git a/posix/bug-regex1.c b/posix/bug-regex1.c |
| index 38eb543..17cd1a0 100644 |
| --- a/posix/bug-regex1.c |
| +++ b/posix/bug-regex1.c |
| @@ -4,6 +4,7 @@ |
| #include <string.h> |
| #include <regex.h> |
| #include <wchar.h> |
| +#include <gnu/option-groups.h> |
| |
| int |
| main (void) |
| @@ -17,7 +18,9 @@ main (void) |
| memset (®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); |
| |
| diff --git a/posix/bug-regex6.c b/posix/bug-regex6.c |
| index efcc890..3b270c7 100644 |
| --- a/posix/bug-regex6.c |
| +++ b/posix/bug-regex6.c |
| @@ -22,6 +22,7 @@ |
| #include <string.h> |
| #include <sys/types.h> |
| #include <regex.h> |
| +#include <gnu/option-groups.h> |
| |
| |
| int |
| @@ -30,7 +31,12 @@ main (int argc, char *argv[]) |
| regex_t re; |
| regmatch_t mat[10]; |
| int i, j, ret = 0; |
| - const char *locales[] = { "C", "de_DE.UTF-8" }; |
| + const char *locales[] = { |
| + "C", |
| +#if __OPTION_EGLIBC_LOCALE_CODE |
| + "de_DE.UTF-8" |
| +#endif |
| + }; |
| const char *string = "http://www.regex.com/pattern/matching.html#intro"; |
| regmatch_t expect[10] = { |
| { 0, 48 }, { 0, 5 }, { 0, 4 }, { 5, 20 }, { 7, 20 }, { 20, 42 }, |
| diff --git a/posix/fnmatch.c b/posix/fnmatch.c |
| index fd85efa..01cc9fe 100644 |
| --- a/posix/fnmatch.c |
| +++ b/posix/fnmatch.c |
| @@ -30,6 +30,10 @@ |
| #include <ctype.h> |
| #include <string.h> |
| |
| +#if defined _LIBC |
| +# include <gnu/option-groups.h> |
| +#endif |
| + |
| #if defined STDC_HEADERS || defined _LIBC |
| # include <stdlib.h> |
| #endif |
| @@ -131,7 +135,7 @@ extern int fnmatch (const char *pattern, const char *string, int flags); |
| # 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 |
| diff --git a/posix/fnmatch_loop.c b/posix/fnmatch_loop.c |
| index f46c9df..74e1754 100644 |
| --- a/posix/fnmatch_loop.c |
| +++ b/posix/fnmatch_loop.c |
| @@ -15,6 +15,8 @@ |
| License along with the GNU C Library; if not, see |
| <http://www.gnu.org/licenses/>. */ |
| |
| +#include <gnu/option-groups.h> |
| + |
| #include <stdint.h> |
| |
| struct STRUCT |
| @@ -54,10 +56,15 @@ FCT (pattern, string, string_end, no_leading_period, flags, ends, alloca_used) |
| const char *collseq = (const char *) |
| _NL_CURRENT(LC_COLLATE, _NL_COLLATE_COLLSEQWC); |
| # else |
| +# if __OPTION_EGLIBC_LOCALE_CODE |
| const UCHAR *collseq = (const UCHAR *) |
| _NL_CURRENT(LC_COLLATE, _NL_COLLATE_COLLSEQMB); |
| -# endif |
| -#endif |
| +# define COLLSEQ_BYTE_LOOKUP(ix) (collseq[(ix)]) |
| +# else |
| +# define COLLSEQ_BYTE_LOOKUP(ix) (ix) |
| +# endif /* __OPTION_EGLIBC_LOCALE_CODE */ |
| +# endif /* WIDE_CHAR_VERSION */ |
| +#endif /* _LIBC */ |
| |
| while ((c = *p++) != L('\0')) |
| { |
| @@ -277,7 +284,7 @@ FCT (pattern, string, string_end, no_leading_period, flags, ends, alloca_used) |
| /* Leave room for the null. */ |
| CHAR str[CHAR_CLASS_MAX_LENGTH + 1]; |
| size_t c1 = 0; |
| -#if defined _LIBC || (defined HAVE_WCTYPE_H && defined HAVE_WCHAR_H) |
| +#if defined _LIBC ? __OPTION_POSIX_C_LANG_WIDE_CHAR : (defined HAVE_WCTYPE_H && defined HAVE_WCHAR_H) |
| wctype_t wt; |
| #endif |
| const CHAR *startp = p; |
| @@ -307,7 +314,7 @@ FCT (pattern, string, string_end, no_leading_period, flags, ends, alloca_used) |
| } |
| str[c1] = L('\0'); |
| |
| -#if defined _LIBC || (defined HAVE_WCTYPE_H && defined HAVE_WCHAR_H) |
| +#if defined _LIBC ? __OPTION_POSIX_C_LANG_WIDE_CHAR : (defined HAVE_WCTYPE_H && defined HAVE_WCHAR_H) |
| wt = IS_CHAR_CLASS (str); |
| if (wt == 0) |
| /* Invalid character class name. */ |
| @@ -680,8 +687,10 @@ FCT (pattern, string, string_end, no_leading_period, flags, ends, alloca_used) |
| else |
| lcollseq = __collseq_table_lookup (collseq, cold); |
| # else |
| - fcollseq = collseq[fn]; |
| - lcollseq = is_seqval ? cold : collseq[(UCHAR) cold]; |
| + fcollseq = COLLSEQ_BYTE_LOOKUP (fn); |
| + lcollseq = (is_seqval |
| + ? cold |
| + : COLLSEQ_BYTE_LOOKUP ((UCHAR) cold)); |
| # endif |
| |
| is_seqval = 0; |
| @@ -857,7 +866,7 @@ FCT (pattern, string, string_end, no_leading_period, flags, ends, alloca_used) |
| goto matched; |
| } |
| # else |
| - hcollseq = collseq[cend]; |
| + hcollseq = COLLSEQ_BYTE_LOOKUP (cend); |
| # endif |
| } |
| |
| diff --git a/posix/glob.c b/posix/glob.c |
| index d65e55d..1ac00a1 100644 |
| --- a/posix/glob.c |
| +++ b/posix/glob.c |
| @@ -25,6 +25,9 @@ |
| #include <sys/types.h> |
| #include <sys/stat.h> |
| #include <stddef.h> |
| +#ifdef _LIBC |
| +# include <gnu/option-groups.h> |
| +#endif |
| |
| /* Outcomment the following line for production quality code. */ |
| /* #define NDEBUG 1 */ |
| @@ -607,6 +610,7 @@ glob (pattern, flags, errfunc, pglob) |
| if (home_dir == NULL || home_dir[0] == '\0') |
| home_dir = "c:/users/default"; /* poor default */ |
| # else |
| +# if ! _LIBC || __OPTION_EGLIBC_GETLOGIN |
| if (home_dir == NULL || home_dir[0] == '\0') |
| { |
| int success; |
| @@ -623,19 +627,19 @@ glob (pattern, flags, errfunc, pglob) |
| if (success) |
| { |
| struct passwd *p; |
| -# if defined HAVE_GETPWNAM_R || defined _LIBC |
| +# if defined HAVE_GETPWNAM_R || defined _LIBC |
| long int pwbuflen = GETPW_R_SIZE_MAX (); |
| char *pwtmpbuf; |
| struct passwd pwbuf; |
| int malloc_pwtmpbuf = 0; |
| int save = errno; |
| |
| -# ifndef _LIBC |
| +# ifndef _LIBC |
| if (pwbuflen == -1) |
| /* `sysconf' does not support _SC_GETPW_R_SIZE_MAX. |
| Try a moderate value. */ |
| pwbuflen = 1024; |
| -# endif |
| +# endif |
| if (__libc_use_alloca (alloca_used + pwbuflen)) |
| pwtmpbuf = alloca_account (pwbuflen, alloca_used); |
| else |
| @@ -682,9 +686,9 @@ glob (pattern, flags, errfunc, pglob) |
| } |
| __set_errno (save); |
| } |
| -# else |
| +# else |
| p = getpwnam (name); |
| -# endif |
| +# endif |
| if (p != NULL) |
| { |
| if (!malloc_pwtmpbuf) |
| @@ -713,6 +717,7 @@ glob (pattern, flags, errfunc, pglob) |
| } |
| } |
| } |
| +# endif /* ! _LIBC || __OPTION_EGLIBC_GETLOGIN */ |
| if (home_dir == NULL || home_dir[0] == '\0') |
| { |
| if (flags & GLOB_TILDE_CHECK) |
| diff --git a/posix/regcomp.c b/posix/regcomp.c |
| index bf8aa16..6a41251 100644 |
| --- a/posix/regcomp.c |
| +++ b/posix/regcomp.c |
| @@ -18,6 +18,7 @@ |
| <http://www.gnu.org/licenses/>. */ |
| |
| #include <stdint.h> |
| +#include <gnu/option-groups.h> |
| |
| #ifdef _LIBC |
| # include <locale/weight.h> |
| @@ -309,7 +310,7 @@ re_compile_fastmap_iter (regex_t *bufp, const re_dfastate_t *init_state, |
| { |
| re_dfa_t *dfa = (re_dfa_t *) bufp->buffer; |
| int node_cnt; |
| - int icase = (dfa->mb_cur_max == 1 && (bufp->syntax & RE_ICASE)); |
| + int icase = (dfa_mb_cur_max (dfa) == 1 && (bufp->syntax & RE_ICASE)); |
| for (node_cnt = 0; node_cnt < init_state->nodes.nelem; ++node_cnt) |
| { |
| int node = init_state->nodes.elems[node_cnt]; |
| @@ -319,9 +320,9 @@ re_compile_fastmap_iter (regex_t *bufp, const re_dfastate_t *init_state, |
| { |
| re_set_fastmap (fastmap, icase, dfa->nodes[node].opr.c); |
| #ifdef RE_ENABLE_I18N |
| - if ((bufp->syntax & RE_ICASE) && dfa->mb_cur_max > 1) |
| + if ((bufp->syntax & RE_ICASE) && dfa_mb_cur_max (dfa) > 1) |
| { |
| - unsigned char *buf = alloca (dfa->mb_cur_max), *p; |
| + unsigned char *buf = alloca (dfa_mb_cur_max (dfa)), *p; |
| wchar_t wc; |
| mbstate_t state; |
| |
| @@ -352,7 +353,11 @@ re_compile_fastmap_iter (regex_t *bufp, const re_dfastate_t *init_state, |
| re_set_fastmap (fastmap, icase, ch); |
| } |
| } |
| -#ifdef RE_ENABLE_I18N |
| + |
| + /* When OPTION_EGLIBC_LOCALE_CODE is disabled, the current |
| + locale is always C, which has no rules and no multi-byte |
| + characters. */ |
| +#if defined RE_ENABLE_I18N && __OPTION_EGLIBC_LOCALE_CODE |
| else if (type == COMPLEX_BRACKET) |
| { |
| re_charset_t *cset = dfa->nodes[node].opr.mbcset; |
| @@ -380,7 +385,7 @@ re_compile_fastmap_iter (regex_t *bufp, const re_dfastate_t *init_state, |
| i.e. where we would not find an invalid sequence. This only |
| applies to multibyte character sets; for single byte character |
| sets, the SIMPLE_BRACKET again suffices. */ |
| - if (dfa->mb_cur_max > 1 |
| + if (dfa_mb_cur_max (dfa) > 1 |
| && (cset->nchar_classes || cset->non_match || cset->nranges |
| # ifdef _LIBC |
| || cset->nequiv_classes |
| @@ -408,7 +413,7 @@ re_compile_fastmap_iter (regex_t *bufp, const re_dfastate_t *init_state, |
| memset (&state, '\0', sizeof (state)); |
| if (__wcrtomb (buf, cset->mbchars[i], &state) != (size_t) -1) |
| re_set_fastmap (fastmap, icase, *(unsigned char *) buf); |
| - if ((bufp->syntax & RE_ICASE) && dfa->mb_cur_max > 1) |
| + if ((bufp->syntax & RE_ICASE) && dfa_mb_cur_max (dfa) > 1) |
| { |
| if (__wcrtomb (buf, __towlower (cset->mbchars[i]), &state) |
| != (size_t) -1) |
| @@ -417,7 +422,7 @@ re_compile_fastmap_iter (regex_t *bufp, const re_dfastate_t *init_state, |
| } |
| } |
| } |
| -#endif /* RE_ENABLE_I18N */ |
| +#endif /* RE_ENABLE_I18N && __OPTION_EGLIBC_LOCALE_CODE */ |
| else if (type == OP_PERIOD |
| #ifdef RE_ENABLE_I18N |
| || type == OP_UTF8_PERIOD |
| @@ -860,11 +865,15 @@ init_dfa (re_dfa_t *dfa, size_t pat_len) |
| |
| dfa->mb_cur_max = MB_CUR_MAX; |
| #ifdef _LIBC |
| - if (dfa->mb_cur_max == 6 |
| + if (dfa_mb_cur_max (dfa) == 6 |
| && strcmp (_NL_CURRENT (LC_CTYPE, _NL_CTYPE_CODESET_NAME), "UTF-8") == 0) |
| dfa->is_utf8 = 1; |
| +# if __OPTION_EGLIBC_LOCALE_CODE |
| dfa->map_notascii = (_NL_CURRENT_WORD (LC_CTYPE, _NL_CTYPE_MAP_TO_NONASCII) |
| != 0); |
| +# else |
| + dfa->map_notascii = 0; |
| +# endif |
| #else |
| # ifdef HAVE_LANGINFO_CODESET |
| codeset_name = nl_langinfo (CODESET); |
| @@ -890,7 +899,7 @@ init_dfa (re_dfa_t *dfa, size_t pat_len) |
| #endif |
| |
| #ifdef RE_ENABLE_I18N |
| - if (dfa->mb_cur_max > 1) |
| + if (dfa_mb_cur_max (dfa) > 1) |
| { |
| if (dfa->is_utf8) |
| dfa->sb_char = (re_bitset_ptr_t) utf8_sb_map; |
| @@ -1788,7 +1797,7 @@ peek_token (re_token_t *token, re_string_t *input, reg_syntax_t syntax) |
| token->word_char = 0; |
| #ifdef RE_ENABLE_I18N |
| token->mb_partial = 0; |
| - if (input->mb_cur_max > 1 && |
| + if (string_mb_cur_max (input) > 1 && |
| !re_string_first_byte (input, re_string_cur_idx (input))) |
| { |
| token->type = CHARACTER; |
| @@ -1809,7 +1818,7 @@ peek_token (re_token_t *token, re_string_t *input, reg_syntax_t syntax) |
| token->opr.c = c2; |
| token->type = CHARACTER; |
| #ifdef RE_ENABLE_I18N |
| - if (input->mb_cur_max > 1) |
| + if (string_mb_cur_max (input) > 1) |
| { |
| wint_t wc = re_string_wchar_at (input, |
| re_string_cur_idx (input) + 1); |
| @@ -1923,7 +1932,7 @@ peek_token (re_token_t *token, re_string_t *input, reg_syntax_t syntax) |
| |
| token->type = CHARACTER; |
| #ifdef RE_ENABLE_I18N |
| - if (input->mb_cur_max > 1) |
| + if (string_mb_cur_max (input) > 1) |
| { |
| wint_t wc = re_string_wchar_at (input, re_string_cur_idx (input)); |
| token->word_char = IS_WIDE_WORD_CHAR (wc) != 0; |
| @@ -2023,7 +2032,7 @@ peek_token_bracket (re_token_t *token, re_string_t *input, reg_syntax_t syntax) |
| token->opr.c = c; |
| |
| #ifdef RE_ENABLE_I18N |
| - if (input->mb_cur_max > 1 && |
| + if (string_mb_cur_max (input) > 1 && |
| !re_string_first_byte (input, re_string_cur_idx (input))) |
| { |
| token->type = CHARACTER; |
| @@ -2246,7 +2255,7 @@ parse_expression (re_string_t *regexp, regex_t *preg, re_token_t *token, |
| return NULL; |
| } |
| #ifdef RE_ENABLE_I18N |
| - if (dfa->mb_cur_max > 1) |
| + if (dfa_mb_cur_max (dfa) > 1) |
| { |
| while (!re_string_eoi (regexp) |
| && !re_string_first_byte (regexp, re_string_cur_idx (regexp))) |
| @@ -2384,7 +2393,7 @@ parse_expression (re_string_t *regexp, regex_t *preg, re_token_t *token, |
| *err = REG_ESPACE; |
| return NULL; |
| } |
| - if (dfa->mb_cur_max > 1) |
| + if (dfa_mb_cur_max (dfa) > 1) |
| dfa->has_mb_node = 1; |
| break; |
| case OP_WORD: |
| @@ -2690,7 +2699,7 @@ build_range_exp (bitset_t sbcset, bracket_elem_t *start_elem, |
| However, for !_LIBC we have no collation elements: if the |
| character set is single byte, the single byte character set |
| that we build below suffices. parse_bracket_exp passes |
| - no MBCSET if dfa->mb_cur_max == 1. */ |
| + no MBCSET if dfa_mb_cur_max (dfa) == 1. */ |
| if (mbcset) |
| { |
| /* Check the space of the arrays. */ |
| @@ -2786,7 +2795,13 @@ parse_bracket_exp (re_string_t *regexp, re_dfa_t *dfa, re_token_t *token, |
| reg_syntax_t syntax, reg_errcode_t *err) |
| { |
| #ifdef _LIBC |
| +#if __OPTION_EGLIBC_LOCALE_CODE |
| const unsigned char *collseqmb; |
| +# define COLLSEQMB_LOOKUP(ix) (collseqmb[(ix)]) |
| +#else |
| +# define COLLSEQMB_LOOKUP(ix) (ix) |
| +#endif |
| + |
| const char *collseqwc; |
| uint32_t nrules; |
| int32_t table_size; |
| @@ -2834,18 +2849,20 @@ parse_bracket_exp (re_string_t *regexp, re_dfa_t *dfa, re_token_t *token, |
| if (MB_CUR_MAX == 1) |
| */ |
| if (nrules == 0) |
| - return collseqmb[br_elem->opr.ch]; |
| + return COLLSEQMB_LOOKUP (br_elem->opr.ch); |
| else |
| { |
| wint_t wc = __btowc (br_elem->opr.ch); |
| return __collseq_table_lookup (collseqwc, wc); |
| } |
| } |
| +#if __OPTION_EGLIBC_LOCALE_CODE |
| else if (br_elem->type == MB_CHAR) |
| { |
| if (nrules != 0) |
| return __collseq_table_lookup (collseqwc, br_elem->opr.wch); |
| } |
| +#endif |
| else if (br_elem->type == COLL_SYM) |
| { |
| size_t sym_name_len = strlen ((char *) br_elem->opr.name); |
| @@ -2876,11 +2893,11 @@ parse_bracket_exp (re_string_t *regexp, re_dfa_t *dfa, re_token_t *token, |
| { |
| /* No valid character. Match it as a single byte |
| character. */ |
| - return collseqmb[br_elem->opr.name[0]]; |
| + return COLLSEQMB_LOOKUP (br_elem->opr.name[0]); |
| } |
| } |
| else if (sym_name_len == 1) |
| - return collseqmb[br_elem->opr.name[0]]; |
| + return COLLSEQMB_LOOKUP (br_elem->opr.name[0]); |
| } |
| return UINT_MAX; |
| } |
| @@ -2920,7 +2937,7 @@ parse_bracket_exp (re_string_t *regexp, re_dfa_t *dfa, re_token_t *token, |
| However, if we have no collation elements, and the character set |
| is single byte, the single byte character set that we |
| build below suffices. */ |
| - if (nrules > 0 || dfa->mb_cur_max > 1) |
| + if (nrules > 0 || dfa_mb_cur_max (dfa) > 1) |
| { |
| /* Check the space of the arrays. */ |
| if (BE (*range_alloc == mbcset->nranges, 0)) |
| @@ -2957,7 +2974,7 @@ parse_bracket_exp (re_string_t *regexp, re_dfa_t *dfa, re_token_t *token, |
| if (MB_CUR_MAX == 1) |
| */ |
| if (nrules == 0) |
| - ch_collseq = collseqmb[ch]; |
| + ch_collseq = COLLSEQMB_LOOKUP (ch); |
| else |
| ch_collseq = __collseq_table_lookup (collseqwc, __btowc (ch)); |
| if (start_collseq <= ch_collseq && ch_collseq <= end_collseq) |
| @@ -3035,7 +3052,10 @@ parse_bracket_exp (re_string_t *regexp, re_dfa_t *dfa, re_token_t *token, |
| re_bitset_ptr_t sbcset; |
| #ifdef RE_ENABLE_I18N |
| re_charset_t *mbcset; |
| - int coll_sym_alloc = 0, range_alloc = 0, mbchar_alloc = 0; |
| + int coll_sym_alloc = 0, range_alloc = 0; |
| +#if __OPTION_EGLIBC_LOCALE_CODE |
| + int mbchar_alloc = 0; |
| +#endif |
| int equiv_class_alloc = 0, char_class_alloc = 0; |
| #endif /* not RE_ENABLE_I18N */ |
| int non_match = 0; |
| @@ -3043,9 +3063,15 @@ parse_bracket_exp (re_string_t *regexp, re_dfa_t *dfa, re_token_t *token, |
| int token_len; |
| int first_round = 1; |
| #ifdef _LIBC |
| +#if __OPTION_EGLIBC_LOCALE_CODE |
| collseqmb = (const unsigned char *) |
| _NL_CURRENT (LC_COLLATE, _NL_COLLATE_COLLSEQMB); |
| nrules = _NL_CURRENT_WORD (LC_COLLATE, _NL_COLLATE_NRULES); |
| +#else |
| + /* This is true when OPTION_EGLIBC_LOCALE_CODE is disabled, but the |
| + compiler can't figure that out. */ |
| + nrules = 0; |
| +#endif |
| if (nrules) |
| { |
| /* |
| @@ -3175,7 +3201,7 @@ parse_bracket_exp (re_string_t *regexp, re_dfa_t *dfa, re_token_t *token, |
| #else |
| # ifdef RE_ENABLE_I18N |
| *err = build_range_exp (sbcset, |
| - dfa->mb_cur_max > 1 ? mbcset : NULL, |
| + dfa_mb_cur_max (dfa) > 1 ? mbcset : NULL, |
| &range_alloc, &start_elem, &end_elem); |
| # else |
| *err = build_range_exp (sbcset, &start_elem, &end_elem); |
| @@ -3191,7 +3217,7 @@ parse_bracket_exp (re_string_t *regexp, re_dfa_t *dfa, re_token_t *token, |
| case SB_CHAR: |
| bitset_set (sbcset, start_elem.opr.ch); |
| break; |
| -#ifdef RE_ENABLE_I18N |
| +#if defined RE_ENABLE_I18N && __OPTION_EGLIBC_LOCALE_CODE |
| case MB_CHAR: |
| /* Check whether the array has enough space. */ |
| if (BE (mbchar_alloc == mbcset->nmbchars, 0)) |
| @@ -3209,7 +3235,7 @@ parse_bracket_exp (re_string_t *regexp, re_dfa_t *dfa, re_token_t *token, |
| } |
| mbcset->mbchars[mbcset->nmbchars++] = start_elem.opr.wch; |
| break; |
| -#endif /* RE_ENABLE_I18N */ |
| +#endif /* RE_ENABLE_I18N && __OPTION_EGLIBC_LOCALE_CODE */ |
| case EQUIV_CLASS: |
| *err = build_equiv_class (sbcset, |
| #ifdef RE_ENABLE_I18N |
| @@ -3259,11 +3285,11 @@ parse_bracket_exp (re_string_t *regexp, re_dfa_t *dfa, re_token_t *token, |
| |
| #ifdef RE_ENABLE_I18N |
| /* Ensure only single byte characters are set. */ |
| - if (dfa->mb_cur_max > 1) |
| + if (dfa_mb_cur_max (dfa) > 1) |
| bitset_mask (sbcset, dfa->sb_char); |
| |
| if (mbcset->nmbchars || mbcset->ncoll_syms || mbcset->nequiv_classes |
| - || mbcset->nranges || (dfa->mb_cur_max > 1 && (mbcset->nchar_classes |
| + || mbcset->nranges || (dfa_mb_cur_max (dfa) > 1 && (mbcset->nchar_classes |
| || mbcset->non_match))) |
| { |
| bin_tree_t *mbc_tree; |
| @@ -3332,7 +3358,7 @@ parse_bracket_element (bracket_elem_t *elem, re_string_t *regexp, |
| re_token_t *token, int token_len, re_dfa_t *dfa, |
| reg_syntax_t syntax, int accept_hyphen) |
| { |
| -#ifdef RE_ENABLE_I18N |
| +#if defined RE_ENABLE_I18N && __OPTION_EGLIBC_LOCALE_CODE |
| int cur_char_size; |
| cur_char_size = re_string_char_size_at (regexp, re_string_cur_idx (regexp)); |
| if (cur_char_size > 1) |
| @@ -3342,7 +3368,7 @@ parse_bracket_element (bracket_elem_t *elem, re_string_t *regexp, |
| re_string_skip_bytes (regexp, cur_char_size); |
| return REG_NOERROR; |
| } |
| -#endif /* RE_ENABLE_I18N */ |
| +#endif /* RE_ENABLE_I18N && __OPTION_EGLIBC_LOCALE_CODE */ |
| re_string_skip_bytes (regexp, token_len); /* Skip a token. */ |
| if (token->type == OP_OPEN_COLL_ELEM || token->type == OP_OPEN_CHAR_CLASS |
| || token->type == OP_OPEN_EQUIV_CLASS) |
| @@ -3422,7 +3448,9 @@ build_equiv_class (bitset_t sbcset, re_charset_t *mbcset, |
| build_equiv_class (bitset_t sbcset, const unsigned char *name) |
| #endif /* not RE_ENABLE_I18N */ |
| { |
| -#ifdef _LIBC |
| + /* When __OPTION_EGLIBC_LOCALE_CODE is disabled, only the C locale |
| + is supported; it has no collation rules. */ |
| +#if defined _LIBC && __OPTION_EGLIBC_LOCALE_CODE |
| uint32_t nrules = _NL_CURRENT_WORD (LC_COLLATE, _NL_COLLATE_NRULES); |
| if (nrules != 0) |
| { |
| @@ -3492,7 +3520,7 @@ build_equiv_class (bitset_t sbcset, const unsigned char *name) |
| mbcset->equiv_classes[mbcset->nequiv_classes++] = idx1; |
| } |
| else |
| -#endif /* _LIBC */ |
| +#endif /* _LIBC && __OPTION_EGLIBC_LOCALE_CODE */ |
| { |
| if (BE (strlen ((const char *) name) != 1, 0)) |
| return REG_ECOLLATE; |
| @@ -3526,7 +3554,7 @@ build_charclass (RE_TRANSLATE_TYPE trans, bitset_t sbcset, |
| && (strcmp (name, "upper") == 0 || strcmp (name, "lower") == 0)) |
| name = "alpha"; |
| |
| -#ifdef RE_ENABLE_I18N |
| +#if defined RE_ENABLE_I18N && __OPTION_EGLIBC_LOCALE_CODE |
| /* Check the space of the arrays. */ |
| if (BE (*char_class_alloc == mbcset->nchar_classes, 0)) |
| { |
| @@ -3542,7 +3570,7 @@ build_charclass (RE_TRANSLATE_TYPE trans, bitset_t sbcset, |
| *char_class_alloc = new_char_class_alloc; |
| } |
| mbcset->char_classes[mbcset->nchar_classes++] = __wctype (name); |
| -#endif /* RE_ENABLE_I18N */ |
| +#endif /* RE_ENABLE_I18N && __OPTION_EGLIBC_LOCALE_CODE */ |
| |
| #define BUILD_CHARCLASS_LOOP(ctype_func) \ |
| do { \ |
| @@ -3653,7 +3681,7 @@ build_charclass_op (re_dfa_t *dfa, RE_TRANSLATE_TYPE trans, |
| |
| #ifdef RE_ENABLE_I18N |
| /* Ensure only single byte characters are set. */ |
| - if (dfa->mb_cur_max > 1) |
| + if (dfa_mb_cur_max (dfa) > 1) |
| bitset_mask (sbcset, dfa->sb_char); |
| #endif |
| |
| @@ -3665,7 +3693,7 @@ build_charclass_op (re_dfa_t *dfa, RE_TRANSLATE_TYPE trans, |
| 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. */ |
| diff --git a/posix/regex.h b/posix/regex.h |
| index 5b1981e..2941f94 100644 |
| --- a/posix/regex.h |
| +++ b/posix/regex.h |
| @@ -21,6 +21,7 @@ |
| #define _REGEX_H 1 |
| |
| #include <sys/types.h> |
| +#include <gnu/option-groups.h> |
| |
| /* Allow the use in C++ code. */ |
| #ifdef __cplusplus |
| @@ -156,6 +157,8 @@ typedef unsigned long int reg_syntax_t; |
| treated as 'a\{1'. */ |
| # define RE_INVALID_INTERVAL_ORD (RE_DEBUG << 1) |
| |
| +/* EGLIBC: Old regex implementation does not support these. */ |
| +# if __OPTION_POSIX_REGEXP_GLIBC |
| /* If this bit is set, then ignore case when matching. |
| If not set, then case is significant. */ |
| # define RE_ICASE (RE_INVALID_INTERVAL_ORD << 1) |
| @@ -172,6 +175,7 @@ typedef unsigned long int reg_syntax_t; |
| /* If this bit is set, then no_sub will be set to 1 during |
| re_compile_pattern. */ |
| # define RE_NO_SUB (RE_CONTEXT_INVALID_DUP << 1) |
| +# endif /* __OPTION_POSIX_REGEXP_GLIBC */ |
| #endif |
| |
| /* This global variable defines the particular regexp syntax to use (for |
| @@ -231,8 +235,13 @@ extern reg_syntax_t re_syntax_options; |
| (RE_CHAR_CLASSES | RE_DOT_NEWLINE | RE_DOT_NOT_NULL \ |
| | RE_INTERVALS | RE_NO_EMPTY_RANGES) |
| |
| +#if __OPTION_POSIX_REGEXP_GLIBC |
| #define RE_SYNTAX_POSIX_BASIC \ |
| (_RE_SYNTAX_POSIX_COMMON | RE_BK_PLUS_QM | RE_CONTEXT_INVALID_DUP) |
| +#else |
| +#define RE_SYNTAX_POSIX_BASIC \ |
| + (_RE_SYNTAX_POSIX_COMMON | RE_BK_PLUS_QM) |
| +#endif |
| |
| /* Differs from ..._POSIX_BASIC only in that RE_BK_PLUS_QM becomes |
| RE_LIMITED_OPS, i.e., \? \+ \| are not recognized. Actually, this |
| @@ -298,9 +307,11 @@ extern reg_syntax_t re_syntax_options; |
| /* Like REG_NOTBOL, except for the end-of-line. */ |
| #define REG_NOTEOL (1 << 1) |
| |
| +#if __OPTION_POSIX_REGEXP_GLIBC |
| /* Use PMATCH[0] to delimit the start and end of the search in the |
| buffer. */ |
| #define REG_STARTEND (1 << 2) |
| +#endif |
| |
| |
| /* If any error codes are removed, changed, or added, update the |
| diff --git a/posix/regex_internal.c b/posix/regex_internal.c |
| index 8597d7e..d53b2a8 100644 |
| --- a/posix/regex_internal.c |
| +++ b/posix/regex_internal.c |
| @@ -43,8 +43,8 @@ re_string_allocate (re_string_t *pstr, const char *str, int len, int init_len, |
| int init_buf_len; |
| |
| /* Ensure at least one character fits into the buffers. */ |
| - if (init_len < dfa->mb_cur_max) |
| - init_len = dfa->mb_cur_max; |
| + if (init_len < dfa_mb_cur_max (dfa)) |
| + init_len = dfa_mb_cur_max (dfa); |
| init_buf_len = (len + 1 < init_len) ? len + 1: init_len; |
| re_string_construct_common (str, len, pstr, trans, icase, dfa); |
| |
| @@ -55,7 +55,7 @@ re_string_allocate (re_string_t *pstr, const char *str, int len, int init_len, |
| pstr->word_char = dfa->word_char; |
| pstr->word_ops_used = dfa->word_ops_used; |
| pstr->mbs = pstr->mbs_allocated ? pstr->mbs : (unsigned char *) str; |
| - pstr->valid_len = (pstr->mbs_allocated || dfa->mb_cur_max > 1) ? 0 : len; |
| + pstr->valid_len = (pstr->mbs_allocated || dfa_mb_cur_max (dfa) > 1) ? 0 : len; |
| pstr->valid_raw_len = pstr->valid_len; |
| return REG_NOERROR; |
| } |
| @@ -82,7 +82,7 @@ re_string_construct (re_string_t *pstr, const char *str, int len, |
| if (icase) |
| { |
| #ifdef RE_ENABLE_I18N |
| - if (dfa->mb_cur_max > 1) |
| + if (dfa_mb_cur_max (dfa) > 1) |
| { |
| while (1) |
| { |
| @@ -91,7 +91,7 @@ re_string_construct (re_string_t *pstr, const char *str, int len, |
| return ret; |
| if (pstr->valid_raw_len >= len) |
| break; |
| - if (pstr->bufs_len > pstr->valid_len + dfa->mb_cur_max) |
| + if (pstr->bufs_len > pstr->valid_len + dfa_mb_cur_max (dfa)) |
| break; |
| ret = re_string_realloc_buffers (pstr, pstr->bufs_len * 2); |
| if (BE (ret != REG_NOERROR, 0)) |
| @@ -105,7 +105,7 @@ re_string_construct (re_string_t *pstr, const char *str, int len, |
| else |
| { |
| #ifdef RE_ENABLE_I18N |
| - if (dfa->mb_cur_max > 1) |
| + if (dfa_mb_cur_max (dfa) > 1) |
| build_wcs_buffer (pstr); |
| else |
| #endif /* RE_ENABLE_I18N */ |
| @@ -130,7 +130,7 @@ internal_function __attribute_warn_unused_result__ |
| re_string_realloc_buffers (re_string_t *pstr, int new_buf_len) |
| { |
| #ifdef RE_ENABLE_I18N |
| - if (pstr->mb_cur_max > 1) |
| + if (string_mb_cur_max (pstr) > 1) |
| { |
| wint_t *new_wcs; |
| |
| @@ -177,7 +177,7 @@ re_string_construct_common (const char *str, int len, re_string_t *pstr, |
| pstr->trans = trans; |
| pstr->icase = icase ? 1 : 0; |
| pstr->mbs_allocated = (trans != NULL || icase); |
| - pstr->mb_cur_max = dfa->mb_cur_max; |
| + pstr->mb_cur_max = dfa_mb_cur_max (dfa); |
| pstr->is_utf8 = dfa->is_utf8; |
| pstr->map_notascii = dfa->map_notascii; |
| pstr->stop = pstr->len; |
| @@ -203,7 +203,7 @@ build_wcs_buffer (re_string_t *pstr) |
| { |
| #ifdef _LIBC |
| unsigned char buf[MB_LEN_MAX]; |
| - assert (MB_LEN_MAX >= pstr->mb_cur_max); |
| + assert (MB_LEN_MAX >= string_mb_cur_max (pstr)); |
| #else |
| unsigned char buf[64]; |
| #endif |
| @@ -226,7 +226,7 @@ build_wcs_buffer (re_string_t *pstr) |
| { |
| int i, ch; |
| |
| - for (i = 0; i < pstr->mb_cur_max && i < remain_len; ++i) |
| + for (i = 0; i < string_mb_cur_max (pstr) && i < remain_len; ++i) |
| { |
| ch = pstr->raw_mbs [pstr->raw_mbs_idx + byte_idx + i]; |
| buf[i] = pstr->mbs[byte_idx + i] = pstr->trans[ch]; |
| @@ -275,7 +275,7 @@ build_wcs_upper_buffer (re_string_t *pstr) |
| size_t mbclen; |
| #ifdef _LIBC |
| char buf[MB_LEN_MAX]; |
| - assert (MB_LEN_MAX >= pstr->mb_cur_max); |
| + assert (MB_LEN_MAX >= string_mb_cur_max (pstr)); |
| #else |
| char buf[64]; |
| #endif |
| @@ -369,7 +369,7 @@ build_wcs_upper_buffer (re_string_t *pstr) |
| { |
| int i, ch; |
| |
| - for (i = 0; i < pstr->mb_cur_max && i < remain_len; ++i) |
| + for (i = 0; i < string_mb_cur_max (pstr) && i < remain_len; ++i) |
| { |
| ch = pstr->raw_mbs [pstr->raw_mbs_idx + src_idx + i]; |
| buf[i] = pstr->trans[ch]; |
| @@ -567,8 +567,9 @@ re_string_translate_buffer (re_string_t *pstr) |
| } |
| |
| /* This function re-construct the buffers. |
| - Concretely, convert to wide character in case of pstr->mb_cur_max > 1, |
| - convert to upper case in case of REG_ICASE, apply translation. */ |
| + Concretely, convert to wide character in case of |
| + string_mb_cur_max (pstr) > 1, convert to upper case in case of |
| + REG_ICASE, apply translation. */ |
| |
| static reg_errcode_t |
| internal_function __attribute_warn_unused_result__ |
| @@ -579,7 +580,7 @@ re_string_reconstruct (re_string_t *pstr, int idx, int eflags) |
| { |
| /* Reset buffer. */ |
| #ifdef RE_ENABLE_I18N |
| - if (pstr->mb_cur_max > 1) |
| + if (string_mb_cur_max (pstr) > 1) |
| memset (&pstr->cur_state, '\0', sizeof (mbstate_t)); |
| #endif /* RE_ENABLE_I18N */ |
| pstr->len = pstr->raw_len; |
| @@ -670,7 +671,7 @@ re_string_reconstruct (re_string_t *pstr, int idx, int eflags) |
| pstr->tip_context = re_string_context_at (pstr, offset - 1, |
| eflags); |
| #ifdef RE_ENABLE_I18N |
| - if (pstr->mb_cur_max > 1) |
| + if (string_mb_cur_max (pstr) > 1) |
| memmove (pstr->wcs, pstr->wcs + offset, |
| (pstr->valid_len - offset) * sizeof (wint_t)); |
| #endif /* RE_ENABLE_I18N */ |
| @@ -699,7 +700,7 @@ re_string_reconstruct (re_string_t *pstr, int idx, int eflags) |
| #endif |
| pstr->valid_len = 0; |
| #ifdef RE_ENABLE_I18N |
| - if (pstr->mb_cur_max > 1) |
| + if (string_mb_cur_max (pstr) > 1) |
| { |
| int wcs_idx; |
| wint_t wc = WEOF; |
| @@ -711,7 +712,7 @@ re_string_reconstruct (re_string_t *pstr, int idx, int eflags) |
| /* Special case UTF-8. Multi-byte chars start with any |
| byte other than 0x80 - 0xbf. */ |
| raw = pstr->raw_mbs + pstr->raw_mbs_idx; |
| - end = raw + (offset - pstr->mb_cur_max); |
| + end = raw + (offset - string_mb_cur_max (pstr)); |
| if (end < pstr->raw_mbs) |
| end = pstr->raw_mbs; |
| p = raw + offset - 1; |
| @@ -803,7 +804,7 @@ re_string_reconstruct (re_string_t *pstr, int idx, int eflags) |
| |
| /* Then build the buffers. */ |
| #ifdef RE_ENABLE_I18N |
| - if (pstr->mb_cur_max > 1) |
| + if (string_mb_cur_max (pstr) > 1) |
| { |
| if (pstr->icase) |
| { |
| @@ -841,7 +842,7 @@ re_string_peek_byte_case (const re_string_t *pstr, int idx) |
| return re_string_peek_byte (pstr, idx); |
| |
| #ifdef RE_ENABLE_I18N |
| - if (pstr->mb_cur_max > 1 |
| + if (string_mb_cur_max (pstr) > 1 |
| && ! re_string_is_single_byte_char (pstr, pstr->cur_idx + idx)) |
| return re_string_peek_byte (pstr, idx); |
| #endif |
| @@ -930,7 +931,7 @@ re_string_context_at (const re_string_t *input, int idx, int eflags) |
| return ((eflags & REG_NOTEOL) ? CONTEXT_ENDBUF |
| : CONTEXT_NEWLINE | CONTEXT_ENDBUF); |
| #ifdef RE_ENABLE_I18N |
| - if (input->mb_cur_max > 1) |
| + if (string_mb_cur_max (input) > 1) |
| { |
| wint_t wc; |
| int wc_idx = idx; |
| @@ -1444,7 +1445,7 @@ re_dfa_add_node (re_dfa_t *dfa, re_token_t token) |
| dfa->nodes[dfa->nodes_len].constraint = 0; |
| #ifdef RE_ENABLE_I18N |
| dfa->nodes[dfa->nodes_len].accept_mb = |
| - (type == OP_PERIOD && dfa->mb_cur_max > 1) || type == COMPLEX_BRACKET; |
| + (type == OP_PERIOD && dfa_mb_cur_max (dfa) > 1) || type == COMPLEX_BRACKET; |
| #endif |
| dfa->nexts[dfa->nodes_len] = -1; |
| re_node_set_init_empty (dfa->edests + dfa->nodes_len); |
| diff --git a/posix/regex_internal.h b/posix/regex_internal.h |
| index 154e969..c43909a 100644 |
| --- a/posix/regex_internal.h |
| +++ b/posix/regex_internal.h |
| @@ -26,6 +26,10 @@ |
| #include <stdlib.h> |
| #include <string.h> |
| |
| +#if defined _LIBC |
| +# include <gnu/option-groups.h> |
| +#endif |
| + |
| #if defined HAVE_LANGINFO_H || defined HAVE_LANGINFO_CODESET || defined _LIBC |
| # include <langinfo.h> |
| #endif |
| @@ -369,6 +373,13 @@ struct re_string_t |
| }; |
| typedef struct re_string_t re_string_t; |
| |
| +/* When OPTION_EGLIBC_LOCALE_CODE is disabled, this is always 1; |
| + help the compiler make use of that fact. */ |
| +#if __OPTION_EGLIBC_LOCALE_CODE |
| +# define string_mb_cur_max(str) ((str)->mb_cur_max + 0) |
| +#else |
| +# define string_mb_cur_max(str) (1) |
| +#endif |
| |
| struct re_dfa_t; |
| typedef struct re_dfa_t re_dfa_t; |
| @@ -654,6 +665,14 @@ struct re_dfa_t |
| __libc_lock_define (, lock) |
| }; |
| |
| +/* When OPTION_EGLIBC_LOCALE_CODE is disabled, this is always 1; |
| + help the compiler make use of that fact. */ |
| +#if __OPTION_EGLIBC_LOCALE_CODE |
| +# define dfa_mb_cur_max(dfa) ((dfa)->mb_cur_max + 0) |
| +#else |
| +# define dfa_mb_cur_max(dfa) (1) |
| +#endif |
| + |
| #define re_node_set_init_empty(set) memset (set, '\0', sizeof (re_node_set)) |
| #define re_node_set_remove(set,id) \ |
| (re_node_set_remove_at (set, re_node_set_contains (set, id) - 1)) |
| @@ -714,7 +733,7 @@ internal_function __attribute__ ((pure, unused)) |
| re_string_char_size_at (const re_string_t *pstr, int idx) |
| { |
| int byte_idx; |
| - if (pstr->mb_cur_max == 1) |
| + if (string_mb_cur_max (pstr) == 1) |
| return 1; |
| for (byte_idx = 1; idx + byte_idx < pstr->valid_len; ++byte_idx) |
| if (pstr->wcs[idx + byte_idx] != WEOF) |
| @@ -726,7 +745,7 @@ static wint_t |
| internal_function __attribute__ ((pure, unused)) |
| re_string_wchar_at (const re_string_t *pstr, int idx) |
| { |
| - if (pstr->mb_cur_max == 1) |
| + if (string_mb_cur_max (pstr) == 1) |
| return (wint_t) pstr->mbs[idx]; |
| return (wint_t) pstr->wcs[idx]; |
| } |
| diff --git a/posix/regexec-compat.c b/posix/regexec-compat.c |
| new file mode 100644 |
| index 0000000..0f9b7c7 |
| --- /dev/null |
| +++ b/posix/regexec-compat.c |
| @@ -0,0 +1,39 @@ |
| +/* Extended regular expression matching and search library. |
| + Copyright (C) 2008 Free Software Foundation, Inc. |
| + This file is part of the GNU C Library. |
| + Contributed by Isamu Hasegawa <isamu@yamato.ibm.com>. |
| + |
| + The GNU C Library is free software; you can redistribute it and/or |
| + modify it under the terms of the GNU Lesser General Public |
| + License as published by the Free Software Foundation; either |
| + version 2.1 of the License, or (at your option) any later version. |
| + |
| + The GNU C Library is distributed in the hope that it will be useful, |
| + but WITHOUT ANY WARRANTY; without even the implied warranty of |
| + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU |
| + Lesser General Public License for more details. |
| + |
| + You should have received a copy of the GNU Lesser General Public |
| + License along with the GNU C Library; if not, write to the Free |
| + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA |
| + 02111-1307 USA. */ |
| + |
| +#ifdef _LIBC |
| +# include <shlib-compat.h> |
| +versioned_symbol (libc, __regexec, regexec, GLIBC_2_3_4); |
| + |
| +# if SHLIB_COMPAT (libc, GLIBC_2_0, GLIBC_2_3_4) |
| +__typeof__ (__regexec) __compat_regexec; |
| + |
| +int |
| +attribute_compat_text_section |
| +__compat_regexec (const regex_t *__restrict preg, |
| + const char *__restrict string, size_t nmatch, |
| + regmatch_t pmatch[], int eflags) |
| +{ |
| + return regexec (preg, string, nmatch, pmatch, |
| + eflags & (REG_NOTBOL | REG_NOTEOL)); |
| +} |
| +compat_symbol (libc, __compat_regexec, regexec, GLIBC_2_0); |
| +# endif |
| +#endif |
| diff --git a/posix/regexec.c b/posix/regexec.c |
| index 70cd606..e3b49e4 100644 |
| --- a/posix/regexec.c |
| +++ b/posix/regexec.c |
| @@ -18,6 +18,7 @@ |
| <http://www.gnu.org/licenses/>. */ |
| |
| #include <stdint.h> |
| +#include <gnu/option-groups.h> |
| |
| static reg_errcode_t match_ctx_init (re_match_context_t *cache, int eflags, |
| int n) internal_function; |
| @@ -186,11 +187,11 @@ static int build_trtable (const re_dfa_t *dfa, |
| static int check_node_accept_bytes (const re_dfa_t *dfa, int node_idx, |
| const re_string_t *input, int idx) |
| internal_function; |
| -# ifdef _LIBC |
| +# if defined _LIBC && __OPTION_EGLIBC_LOCALE_CODE |
| static unsigned int find_collation_sequence_value (const unsigned char *mbs, |
| size_t name_len) |
| internal_function; |
| -# endif /* _LIBC */ |
| +# endif /* _LIBC && __OPTION_EGLIBC_LOCALE_CODE */ |
| #endif /* RE_ENABLE_I18N */ |
| static int group_nodes_into_DFAstates (const re_dfa_t *dfa, |
| const re_dfastate_t *state, |
| @@ -255,25 +256,9 @@ regexec (preg, string, nmatch, pmatch, eflags) |
| return err != REG_NOERROR; |
| } |
| |
| -#ifdef _LIBC |
| -# include <shlib-compat.h> |
| -versioned_symbol (libc, __regexec, regexec, GLIBC_2_3_4); |
| - |
| -# if SHLIB_COMPAT (libc, GLIBC_2_0, GLIBC_2_3_4) |
| -__typeof__ (__regexec) __compat_regexec; |
| - |
| -int |
| -attribute_compat_text_section |
| -__compat_regexec (const regex_t *__restrict preg, |
| - const char *__restrict string, size_t nmatch, |
| - regmatch_t pmatch[], int eflags) |
| -{ |
| - return regexec (preg, string, nmatch, pmatch, |
| - eflags & (REG_NOTBOL | REG_NOTEOL)); |
| -} |
| -compat_symbol (libc, __compat_regexec, regexec, GLIBC_2_0); |
| -# endif |
| -#endif |
| +/* EGLIBC: The code that used to be here was move to a separate file |
| + so that it can be shared with xregex.c. */ |
| +#include "regexec-compat.c" |
| |
| /* Entry points for GNU code. */ |
| |
| @@ -728,7 +713,7 @@ re_search_internal (preg, string, length, start, range, stop, nmatch, pmatch, |
| incr = (range < 0) ? -1 : 1; |
| left_lim = (range < 0) ? start + range : start; |
| right_lim = (range < 0) ? start : start + range; |
| - sb = dfa->mb_cur_max == 1; |
| + sb = dfa_mb_cur_max (dfa) == 1; |
| match_kind = |
| (fastmap |
| ? ((sb || !(preg->syntax & RE_ICASE || t) ? 4 : 0) |
| @@ -3448,7 +3433,7 @@ out_free: |
| if (BE (dest_states_word[i] == NULL && err != REG_NOERROR, 0)) |
| goto out_free; |
| |
| - if (dest_states[i] != dest_states_word[i] && dfa->mb_cur_max > 1) |
| + if (dest_states[i] != dest_states_word[i] && dfa_mb_cur_max (dfa) > 1) |
| need_word_trtable = 1; |
| |
| dest_states_nl[i] = re_acquire_state_context (&err, dfa, &follows, |
| @@ -3590,7 +3575,7 @@ group_nodes_into_DFAstates (const re_dfa_t *dfa, const re_dfastate_t *state, |
| else if (type == OP_PERIOD) |
| { |
| #ifdef RE_ENABLE_I18N |
| - if (dfa->mb_cur_max > 1) |
| + if (dfa_mb_cur_max (dfa) > 1) |
| bitset_merge (accepts, dfa->sb_char); |
| else |
| #endif |
| @@ -3641,7 +3626,7 @@ group_nodes_into_DFAstates (const re_dfa_t *dfa, const re_dfastate_t *state, |
| continue; |
| } |
| #ifdef RE_ENABLE_I18N |
| - if (dfa->mb_cur_max > 1) |
| + if (dfa_mb_cur_max (dfa) > 1) |
| for (j = 0; j < BITSET_WORDS; ++j) |
| any_set |= (accepts[j] &= (dfa->word_char[j] | ~dfa->sb_char[j])); |
| else |
| @@ -3660,7 +3645,7 @@ group_nodes_into_DFAstates (const re_dfa_t *dfa, const re_dfastate_t *state, |
| continue; |
| } |
| #ifdef RE_ENABLE_I18N |
| - if (dfa->mb_cur_max > 1) |
| + if (dfa_mb_cur_max (dfa) > 1) |
| for (j = 0; j < BITSET_WORDS; ++j) |
| any_set |= (accepts[j] &= ~(dfa->word_char[j] & dfa->sb_char[j])); |
| else |
| @@ -3836,12 +3821,6 @@ check_node_accept_bytes (const re_dfa_t *dfa, int node_idx, |
| if (node->type == COMPLEX_BRACKET) |
| { |
| const re_charset_t *cset = node->opr.mbcset; |
| -# ifdef _LIBC |
| - const unsigned char *pin |
| - = ((const unsigned char *) re_string_get_buffer (input) + str_idx); |
| - int j; |
| - uint32_t nrules; |
| -# endif /* _LIBC */ |
| int match_len = 0; |
| wchar_t wc = ((cset->nranges || cset->nchar_classes || cset->nmbchars) |
| ? re_string_wchar_at (input, str_idx) : 0); |
| @@ -3853,6 +3832,7 @@ check_node_accept_bytes (const re_dfa_t *dfa, int node_idx, |
| match_len = char_len; |
| goto check_node_accept_bytes_match; |
| } |
| +#if __OPTION_EGLIBC_LOCALE_CODE |
| /* match with character_class? */ |
| for (i = 0; i < cset->nchar_classes; ++i) |
| { |
| @@ -3863,14 +3843,22 @@ check_node_accept_bytes (const re_dfa_t *dfa, int node_idx, |
| goto check_node_accept_bytes_match; |
| } |
| } |
| +#endif |
| + |
| + /* When __OPTION_EGLIBC_LOCALE_CODE is disabled, only the C |
| + locale is supported; it has no collation rules. */ |
| +# if defined _LIBC && __OPTION_EGLIBC_LOCALE_CODE |
| + const unsigned char *pin |
| + = ((const unsigned char *) re_string_get_buffer (input) + str_idx); |
| + int j; |
| + uint32_t nrules; |
| |
| -# ifdef _LIBC |
| nrules = _NL_CURRENT_WORD (LC_COLLATE, _NL_COLLATE_NRULES); |
| if (nrules != 0) |
| { |
| unsigned int in_collseq = 0; |
| const int32_t *table, *indirect; |
| - const unsigned char *weights, *extra; |
| + const unsigned char *weights, *extra = NULL; |
| const char *collseqwc; |
| |
| /* match with collating_symbol? */ |
| @@ -3955,8 +3943,12 @@ check_node_accept_bytes (const re_dfa_t *dfa, int node_idx, |
| } |
| } |
| else |
| -# endif /* _LIBC */ |
| +# endif /* _LIBC && __OPTION_EGLIBC_LOCALE_CODE */ |
| { |
| + /* In the _LIBC version, if OPTION_EGLIBC_LOCALE_CODE is |
| + disabled, there can be no multibyte range endpoints, and |
| + cset->nranges is always zero. */ |
| +#if __OPTION_EGLIBC_LOCALE_CODE |
| /* match with range expression? */ |
| #if __GNUC__ >= 2 |
| wchar_t cmp_buf[] = {L'\0', L'\0', wc, L'\0', L'\0', L'\0'}; |
| @@ -3975,6 +3967,7 @@ check_node_accept_bytes (const re_dfa_t *dfa, int node_idx, |
| goto check_node_accept_bytes_match; |
| } |
| } |
| +#endif /* __OPTION_EGLIBC_LOCALE_CODE */ |
| } |
| check_node_accept_bytes_match: |
| if (!cset->non_match) |
| @@ -3990,7 +3983,7 @@ check_node_accept_bytes (const re_dfa_t *dfa, int node_idx, |
| return 0; |
| } |
| |
| -# ifdef _LIBC |
| +# if defined _LIBC && __OPTION_EGLIBC_LOCALE_CODE |
| static unsigned int |
| internal_function |
| find_collation_sequence_value (const unsigned char *mbs, size_t mbs_len) |
| @@ -4048,7 +4041,7 @@ find_collation_sequence_value (const unsigned char *mbs, size_t mbs_len) |
| return UINT_MAX; |
| } |
| } |
| -# endif /* _LIBC */ |
| +# endif /* _LIBC && __OPTION_EGLIBC_LOCALE_CODE */ |
| #endif /* RE_ENABLE_I18N */ |
| |
| /* Check whether the node accepts the byte which is IDX-th |
| @@ -4139,7 +4132,7 @@ extend_buffers (re_match_context_t *mctx, int min_len) |
| if (pstr->icase) |
| { |
| #ifdef RE_ENABLE_I18N |
| - if (pstr->mb_cur_max > 1) |
| + if (string_mb_cur_max (pstr) > 1) |
| { |
| ret = build_wcs_upper_buffer (pstr); |
| if (BE (ret != REG_NOERROR, 0)) |
| @@ -4152,7 +4145,7 @@ extend_buffers (re_match_context_t *mctx, int min_len) |
| 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 */ |
| diff --git a/posix/xregex.c b/posix/xregex.c |
| new file mode 100644 |
| index 0000000..d3f7ace |
| --- /dev/null |
| +++ b/posix/xregex.c |
| @@ -0,0 +1,8215 @@ |
| +/* Extended regular expression matching and search library, |
| + version 0.12. |
| + (Implements POSIX draft P1003.2/D11.2, except for some of the |
| + internationalization features.) |
| + |
| + Copyright (C) 1993, 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, |
| + 2002, 2005 Free Software Foundation, Inc. |
| + This file is part of the GNU C Library. |
| + |
| + The GNU C Library is free software; you can redistribute it and/or |
| + modify it under the terms of the GNU Lesser General Public |
| + License as published by the Free Software Foundation; either |
| + version 2.1 of the License, or (at your option) any later version. |
| + |
| + The GNU C Library is distributed in the hope that it will be useful, |
| + but WITHOUT ANY WARRANTY; without even the implied warranty of |
| + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU |
| + Lesser General Public License for more details. |
| + |
| + You should have received a copy of the GNU Lesser General Public |
| + License along with the GNU C Library; if not, write to the Free |
| + Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA |
| + 02110-1301 USA. */ |
| + |
| +/* AIX requires this to be the first thing in the file. */ |
| +#if defined _AIX && !defined __GNUC__ && !defined REGEX_MALLOC |
| + #pragma alloca |
| +#endif |
| + |
| +#undef _GNU_SOURCE |
| +#define _GNU_SOURCE |
| + |
| +#ifndef INSIDE_RECURSION |
| +# ifdef HAVE_CONFIG_H |
| +# include <config.h> |
| +# endif |
| +#endif |
| + |
| +/*#include <ansidecl.h>*/ |
| + |
| + |
| +#ifndef INSIDE_RECURSION |
| + |
| +# if defined STDC_HEADERS && !defined emacs |
| +# include <stddef.h> |
| +# else |
| +/* We need this for `regex.h', and perhaps for the Emacs include files. */ |
| +# include <sys/types.h> |
| +# endif |
| + |
| +# if (defined HAVE_WCTYPE_H && defined HAVE_WCHAR_H && defined HAVE_BTOWC) |
| +# define WIDE_CHAR_SUPPORT (HAVE_WCTYPE_H && HAVE_WCHAR_H && HAVE_BTOWC) |
| +# else |
| +# define WIDE_CHAR_SUPPORT 0 |
| +# endif |
| +/* For platform which support the ISO C amendement 1 functionality we |
| + support user defined character classes. */ |
| +# if WIDE_CHAR_SUPPORT |
| +/* Solaris 2.5 has a bug: <wchar.h> must be included before <wctype.h>. */ |
| +# include <wchar.h> |
| +# include <wctype.h> |
| +# endif |
| + |
| +# ifdef _LIBC |
| +/* We have to keep the namespace clean. */ |
| +# define regfree(preg) __regfree (preg) |
| +# define regexec(pr, st, nm, pm, ef) __regexec (pr, st, nm, pm, ef) |
| +# define regcomp(preg, pattern, cflags) __regcomp (preg, pattern, cflags) |
| +# define regerror(errcode, preg, errbuf, errbuf_size) \ |
| + __regerror(errcode, preg, errbuf, errbuf_size) |
| +# define re_set_registers(bu, re, nu, st, en) \ |
| + __re_set_registers (bu, re, nu, st, en) |
| +# define re_match_2(bufp, string1, size1, string2, size2, pos, regs, stop) \ |
| + __re_match_2 (bufp, string1, size1, string2, size2, pos, regs, stop) |
| +# define re_match(bufp, string, size, pos, regs) \ |
| + __re_match (bufp, string, size, pos, regs) |
| +# define re_search(bufp, string, size, startpos, range, regs) \ |
| + __re_search (bufp, string, size, startpos, range, regs) |
| +# define re_compile_pattern(pattern, length, bufp) \ |
| + __re_compile_pattern (pattern, length, bufp) |
| +# define re_set_syntax(syntax) __re_set_syntax (syntax) |
| +# define re_search_2(bufp, st1, s1, st2, s2, startpos, range, regs, stop) \ |
| + __re_search_2 (bufp, st1, s1, st2, s2, startpos, range, regs, stop) |
| +# define re_compile_fastmap(bufp) __re_compile_fastmap (bufp) |
| + |
| +# define btowc __btowc |
| + |
| +/* We are also using some library internals. */ |
| +# include <locale/localeinfo.h> |
| +# include <locale/elem-hash.h> |
| +# include <langinfo.h> |
| +# include <locale/coll-lookup.h> |
| +# endif |
| + |
| +/* This is for other GNU distributions with internationalized messages. */ |
| +# if (HAVE_LIBINTL_H && ENABLE_NLS) || defined _LIBC |
| +# include <libintl.h> |
| +# ifdef _LIBC |
| +# undef gettext |
| +# define gettext(msgid) __dcgettext ("libc", msgid, LC_MESSAGES) |
| +# endif |
| +# else |
| +# define gettext(msgid) (msgid) |
| +# endif |
| + |
| +# ifndef gettext_noop |
| +/* This define is so xgettext can find the internationalizable |
| + strings. */ |
| +# define gettext_noop(String) String |
| +# endif |
| + |
| +/* The `emacs' switch turns on certain matching commands |
| + that make sense only in Emacs. */ |
| +# ifdef emacs |
| + |
| +# include "lisp.h" |
| +# include "buffer.h" |
| +# include "syntax.h" |
| + |
| +# else /* not emacs */ |
| + |
| +/* If we are not linking with Emacs proper, |
| + we can't use the relocating allocator |
| + even if config.h says that we can. */ |
| +# undef REL_ALLOC |
| + |
| +# if defined STDC_HEADERS || defined _LIBC |
| +# include <stdlib.h> |
| +# else |
| +char *malloc (); |
| +char *realloc (); |
| +# endif |
| + |
| +/* When used in Emacs's lib-src, we need to get bzero and bcopy somehow. |
| + If nothing else has been done, use the method below. */ |
| +# ifdef INHIBIT_STRING_HEADER |
| +# if !(defined HAVE_BZERO && defined HAVE_BCOPY) |
| +# if !defined bzero && !defined bcopy |
| +# undef INHIBIT_STRING_HEADER |
| +# endif |
| +# endif |
| +# endif |
| + |
| +/* This is the normal way of making sure we have a bcopy and a bzero. |
| + This is used in most programs--a few other programs avoid this |
| + by defining INHIBIT_STRING_HEADER. */ |
| +# ifndef INHIBIT_STRING_HEADER |
| +# if defined HAVE_STRING_H || defined STDC_HEADERS || defined _LIBC |
| +# include <string.h> |
| +# ifndef bzero |
| +# ifndef _LIBC |
| +# define bzero(s, n) (memset (s, '\0', n), (s)) |
| +# else |
| +# define bzero(s, n) __bzero (s, n) |
| +# endif |
| +# endif |
| +# else |
| +# include <strings.h> |
| +# ifndef memcmp |
| +# define memcmp(s1, s2, n) bcmp (s1, s2, n) |
| +# endif |
| +# ifndef memcpy |
| +# define memcpy(d, s, n) (bcopy (s, d, n), (d)) |
| +# endif |
| +# endif |
| +# endif |
| + |
| +/* Define the syntax stuff for \<, \>, etc. */ |
| + |
| +/* This must be nonzero for the wordchar and notwordchar pattern |
| + commands in re_match_2. */ |
| +# ifndef Sword |
| +# define Sword 1 |
| +# endif |
| + |
| +# ifdef SWITCH_ENUM_BUG |
| +# define SWITCH_ENUM_CAST(x) ((int)(x)) |
| +# else |
| +# define SWITCH_ENUM_CAST(x) (x) |
| +# endif |
| + |
| +# endif /* not emacs */ |
| + |
| +# if defined _LIBC || HAVE_LIMITS_H |
| +# include <limits.h> |
| +# endif |
| + |
| +# ifndef MB_LEN_MAX |
| +# define MB_LEN_MAX 1 |
| +# endif |
| + |
| +/* Get the interface, including the syntax bits. */ |
| +# include "regex.h" |
| + |
| +/* isalpha etc. are used for the character classes. */ |
| +# include <ctype.h> |
| + |
| +/* Jim Meyering writes: |
| + |
| + "... Some ctype macros are valid only for character codes that |
| + isascii says are ASCII (SGI's IRIX-4.0.5 is one such system --when |
| + using /bin/cc or gcc but without giving an ansi option). So, all |
| + ctype uses should be through macros like ISPRINT... If |
| + STDC_HEADERS is defined, then autoconf has verified that the ctype |
| + macros don't need to be guarded with references to isascii. ... |
| + Defining isascii to 1 should let any compiler worth its salt |
| + eliminate the && through constant folding." |
| + Solaris defines some of these symbols so we must undefine them first. */ |
| + |
| +# undef ISASCII |
| +# if defined STDC_HEADERS || (!defined isascii && !defined HAVE_ISASCII) |
| +# define ISASCII(c) 1 |
| +# else |
| +# define ISASCII(c) isascii(c) |
| +# endif |
| + |
| +# ifdef isblank |
| +# define ISBLANK(c) (ISASCII (c) && isblank (c)) |
| +# else |
| +# define ISBLANK(c) ((c) == ' ' || (c) == '\t') |
| +# endif |
| +# ifdef isgraph |
| +# define ISGRAPH(c) (ISASCII (c) && isgraph (c)) |
| +# else |
| +# define ISGRAPH(c) (ISASCII (c) && isprint (c) && !isspace (c)) |
| +# endif |
| + |
| +# undef ISPRINT |
| +# define ISPRINT(c) (ISASCII (c) && isprint (c)) |
| +# define ISDIGIT(c) (ISASCII (c) && isdigit (c)) |
| +# define ISALNUM(c) (ISASCII (c) && isalnum (c)) |
| +# define ISALPHA(c) (ISASCII (c) && isalpha (c)) |
| +# define ISCNTRL(c) (ISASCII (c) && iscntrl (c)) |
| +# define ISLOWER(c) (ISASCII (c) && islower (c)) |
| +# define ISPUNCT(c) (ISASCII (c) && ispunct (c)) |
| +# define ISSPACE(c) (ISASCII (c) && isspace (c)) |
| +# define ISUPPER(c) (ISASCII (c) && isupper (c)) |
| +# define ISXDIGIT(c) (ISASCII (c) && isxdigit (c)) |
| + |
| +# ifdef _tolower |
| +# define TOLOWER(c) _tolower(c) |
| +# else |
| +# define TOLOWER(c) tolower(c) |
| +# endif |
| + |
| +# ifndef NULL |
| +# define NULL (void *)0 |
| +# endif |
| + |
| +/* We remove any previous definition of `SIGN_EXTEND_CHAR', |
| + since ours (we hope) works properly with all combinations of |
| + machines, compilers, `char' and `unsigned char' argument types. |
| + (Per Bothner suggested the basic approach.) */ |
| +# undef SIGN_EXTEND_CHAR |
| +# if __STDC__ |
| +# define SIGN_EXTEND_CHAR(c) ((signed char) (c)) |
| +# else /* not __STDC__ */ |
| +/* As in Harbison and Steele. */ |
| +# define SIGN_EXTEND_CHAR(c) ((((unsigned char) (c)) ^ 128) - 128) |
| +# endif |
| + |
| +# ifndef emacs |
| +/* How many characters in the character set. */ |
| +# define CHAR_SET_SIZE 256 |
| + |
| +# ifdef SYNTAX_TABLE |
| + |
| +extern char *re_syntax_table; |
| + |
| +# else /* not SYNTAX_TABLE */ |
| + |
| +static char re_syntax_table[CHAR_SET_SIZE]; |
| + |
| +static void init_syntax_once (void); |
| + |
| +static void |
| +init_syntax_once (void) |
| +{ |
| + register int c; |
| + static int done = 0; |
| + |
| + if (done) |
| + return; |
| + bzero (re_syntax_table, sizeof re_syntax_table); |
| + |
| + for (c = 0; c < CHAR_SET_SIZE; ++c) |
| + if (ISALNUM (c)) |
| + re_syntax_table[c] = Sword; |
| + |
| + re_syntax_table['_'] = Sword; |
| + |
| + done = 1; |
| +} |
| + |
| +# endif /* not SYNTAX_TABLE */ |
| + |
| +# define SYNTAX(c) re_syntax_table[(unsigned char) (c)] |
| + |
| +# endif /* emacs */ |
| + |
| +/* Integer type for pointers. */ |
| +# if !defined _LIBC && !defined HAVE_UINTPTR_T |
| +typedef unsigned long int uintptr_t; |
| +# endif |
| + |
| +/* Should we use malloc or alloca? If REGEX_MALLOC is not defined, we |
| + use `alloca' instead of `malloc'. This is because using malloc in |
| + re_search* or re_match* could cause memory leaks when C-g is used in |
| + Emacs; also, malloc is slower and causes storage fragmentation. On |
| + the other hand, malloc is more portable, and easier to debug. |
| + |
| + Because we sometimes use alloca, some routines have to be macros, |
| + not functions -- `alloca'-allocated space disappears at the end of the |
| + function it is called in. */ |
| + |
| +# ifdef REGEX_MALLOC |
| + |
| +# define REGEX_ALLOCATE malloc |
| +# define REGEX_REALLOCATE(source, osize, nsize) realloc (source, nsize) |
| +# define REGEX_FREE free |
| + |
| +# else /* not REGEX_MALLOC */ |
| + |
| +/* Emacs already defines alloca, sometimes. */ |
| +# ifndef alloca |
| + |
| +/* Make alloca work the best possible way. */ |
| +# ifdef __GNUC__ |
| +# define alloca __builtin_alloca |
| +# else /* not __GNUC__ */ |
| +# if HAVE_ALLOCA_H |
| +# include <alloca.h> |
| +# endif /* HAVE_ALLOCA_H */ |
| +# endif /* not __GNUC__ */ |
| + |
| +# endif /* not alloca */ |
| + |
| +# define REGEX_ALLOCATE alloca |
| + |
| +/* Assumes a `char *destination' variable. */ |
| +# define REGEX_REALLOCATE(source, osize, nsize) \ |
| + (destination = (char *) alloca (nsize), \ |
| + memcpy (destination, source, osize)) |
| + |
| +/* No need to do anything to free, after alloca. */ |
| +# define REGEX_FREE(arg) ((void)0) /* Do nothing! But inhibit gcc warning. */ |
| + |
| +# endif /* not REGEX_MALLOC */ |
| + |
| +/* Define how to allocate the failure stack. */ |
| + |
| +# if defined REL_ALLOC && defined REGEX_MALLOC |
| + |
| +# define REGEX_ALLOCATE_STACK(size) \ |
| + r_alloc (&failure_stack_ptr, (size)) |
| +# define REGEX_REALLOCATE_STACK(source, osize, nsize) \ |
| + r_re_alloc (&failure_stack_ptr, (nsize)) |
| +# define REGEX_FREE_STACK(ptr) \ |
| + r_alloc_free (&failure_stack_ptr) |
| + |
| +# else /* not using relocating allocator */ |
| + |
| +# ifdef REGEX_MALLOC |
| + |
| +# define REGEX_ALLOCATE_STACK malloc |
| +# define REGEX_REALLOCATE_STACK(source, osize, nsize) realloc (source, nsize) |
| +# define REGEX_FREE_STACK free |
| + |
| +# else /* not REGEX_MALLOC */ |
| + |
| +# define REGEX_ALLOCATE_STACK alloca |
| + |
| +# define REGEX_REALLOCATE_STACK(source, osize, nsize) \ |
| + REGEX_REALLOCATE (source, osize, nsize) |
| +/* No need to explicitly free anything. */ |
| +# define REGEX_FREE_STACK(arg) |
| + |
| +# endif /* not REGEX_MALLOC */ |
| +# endif /* not using relocating allocator */ |
| + |
| + |
| +/* True if `size1' is non-NULL and PTR is pointing anywhere inside |
| + `string1' or just past its end. This works if PTR is NULL, which is |
| + a good thing. */ |
| +# define FIRST_STRING_P(ptr) \ |
| + (size1 && string1 <= (ptr) && (ptr) <= string1 + size1) |
| + |
| +/* (Re)Allocate N items of type T using malloc, or fail. */ |
| +# define TALLOC(n, t) ((t *) malloc ((n) * sizeof (t))) |
| +# define RETALLOC(addr, n, t) ((addr) = (t *) realloc (addr, (n) * sizeof (t))) |
| +# define RETALLOC_IF(addr, n, t) \ |
| + if (addr) RETALLOC((addr), (n), t); else (addr) = TALLOC ((n), t) |
| +# define REGEX_TALLOC(n, t) ((t *) REGEX_ALLOCATE ((n) * sizeof (t))) |
| + |
| +# define BYTEWIDTH 8 /* In bits. */ |
| + |
| +# define STREQ(s1, s2) ((strcmp (s1, s2) == 0)) |
| + |
| +# undef MAX |
| +# undef MIN |
| +# define MAX(a, b) ((a) > (b) ? (a) : (b)) |
| +# define MIN(a, b) ((a) < (b) ? (a) : (b)) |
| + |
| +typedef char boolean; |
| +# define false 0 |
| +# define true 1 |
| + |
| +static reg_errcode_t byte_regex_compile (const char *pattern, size_t size, |
| + reg_syntax_t syntax, |
| + struct re_pattern_buffer *bufp); |
| + |
| +static int byte_re_match_2_internal (struct re_pattern_buffer *bufp, |
| + const char *string1, int size1, |
| + const char *string2, int size2, |
| + int pos, |
| + struct re_registers *regs, |
| + int stop); |
| +static int byte_re_search_2 (struct re_pattern_buffer *bufp, |
| + const char *string1, int size1, |
| + const char *string2, int size2, |
| + int startpos, int range, |
| + struct re_registers *regs, int stop); |
| +static int byte_re_compile_fastmap (struct re_pattern_buffer *bufp); |
| + |
| +#ifdef MBS_SUPPORT |
| +static reg_errcode_t wcs_regex_compile (const char *pattern, size_t size, |
| + reg_syntax_t syntax, |
| + struct re_pattern_buffer *bufp); |
| + |
| + |
| +static int wcs_re_match_2_internal (struct re_pattern_buffer *bufp, |
| + const char *cstring1, int csize1, |
| + const char *cstring2, int csize2, |
| + int pos, |
| + struct re_registers *regs, |
| + int stop, |
| + wchar_t *string1, int size1, |
| + wchar_t *string2, int size2, |
| + int *mbs_offset1, int *mbs_offset2); |
| +static int wcs_re_search_2 (struct re_pattern_buffer *bufp, |
| + const char *string1, int size1, |
| + const char *string2, int size2, |
| + int startpos, int range, |
| + struct re_registers *regs, int stop); |
| +static int wcs_re_compile_fastmap (struct re_pattern_buffer *bufp); |
| +#endif |
| + |
| +/* These are the command codes that appear in compiled regular |
| + expressions. Some opcodes are followed by argument bytes. A |
| + command code can specify any interpretation whatsoever for its |
| + arguments. Zero bytes may appear in the compiled regular expression. */ |
| + |
| +typedef enum |
| +{ |
| + no_op = 0, |
| + |
| + /* Succeed right away--no more backtracking. */ |
| + succeed, |
| + |
| + /* Followed by one byte giving n, then by n literal bytes. */ |
| + exactn, |
| + |
| +# ifdef MBS_SUPPORT |
| + /* Same as exactn, but contains binary data. */ |
| + exactn_bin, |
| +# endif |
| + |
| + /* Matches any (more or less) character. */ |
| + anychar, |
| + |
| + /* Matches any one char belonging to specified set. First |
| + following byte is number of bitmap bytes. Then come bytes |
| + for a bitmap saying which chars are in. Bits in each byte |
| + are ordered low-bit-first. A character is in the set if its |
| + bit is 1. A character too large to have a bit in the map is |
| + automatically not in the set. */ |
| + /* ifdef MBS_SUPPORT, following element is length of character |
| + classes, length of collating symbols, length of equivalence |
| + classes, length of character ranges, and length of characters. |
| + Next, character class element, collating symbols elements, |
| + equivalence class elements, range elements, and character |
| + elements follow. |
| + See regex_compile function. */ |
| + charset, |
| + |
| + /* Same parameters as charset, but match any character that is |
| + not one of those specified. */ |
| + charset_not, |
| + |
| + /* Start remembering the text that is matched, for storing in a |
| + register. Followed by one byte with the register number, in |
| + the range 0 to one less than the pattern buffer's re_nsub |
| + field. Then followed by one byte with the number of groups |
| + inner to this one. (This last has to be part of the |
| + start_memory only because we need it in the on_failure_jump |
| + of re_match_2.) */ |
| + start_memory, |
| + |
| + /* Stop remembering the text that is matched and store it in a |
| + memory register. Followed by one byte with the register |
| + number, in the range 0 to one less than `re_nsub' in the |
| + pattern buffer, and one byte with the number of inner groups, |
| + just like `start_memory'. (We need the number of inner |
| + groups here because we don't have any easy way of finding the |
| + corresponding start_memory when we're at a stop_memory.) */ |
| + stop_memory, |
| + |
| + /* Match a duplicate of something remembered. Followed by one |
| + byte containing the register number. */ |
| + duplicate, |
| + |
| + /* Fail unless at beginning of line. */ |
| + begline, |
| + |
| + /* Fail unless at end of line. */ |
| + endline, |
| + |
| + /* Succeeds if at beginning of buffer (if emacs) or at beginning |
| + of string to be matched (if not). */ |
| + begbuf, |
| + |
| + /* Analogously, for end of buffer/string. */ |
| + endbuf, |
| + |
| + /* Followed by two byte relative address to which to jump. */ |
| + jump, |
| + |
| + /* Same as jump, but marks the end of an alternative. */ |
| + jump_past_alt, |
| + |
| + /* Followed by two-byte relative address of place to resume at |
| + in case of failure. */ |
| + /* ifdef MBS_SUPPORT, the size of address is 1. */ |
| + on_failure_jump, |
| + |
| + /* Like on_failure_jump, but pushes a placeholder instead of the |
| + current string position when executed. */ |
| + on_failure_keep_string_jump, |
| + |
| + /* Throw away latest failure point and then jump to following |
| + two-byte relative address. */ |
| + /* ifdef MBS_SUPPORT, the size of address is 1. */ |
| + pop_failure_jump, |
| + |
| + /* Change to pop_failure_jump if know won't have to backtrack to |
| + match; otherwise change to jump. This is used to jump |
| + back to the beginning of a repeat. If what follows this jump |
| + clearly won't match what the repeat does, such that we can be |
| + sure that there is no use backtracking out of repetitions |
| + already matched, then we change it to a pop_failure_jump. |
| + Followed by two-byte address. */ |
| + /* ifdef MBS_SUPPORT, the size of address is 1. */ |
| + maybe_pop_jump, |
| + |
| + /* Jump to following two-byte address, and push a dummy failure |
| + point. This failure point will be thrown away if an attempt |
| + is made to use it for a failure. A `+' construct makes this |
| + before the first repeat. Also used as an intermediary kind |
| + of jump when compiling an alternative. */ |
| + /* ifdef MBS_SUPPORT, the size of address is 1. */ |
| + dummy_failure_jump, |
| + |
| + /* Push a dummy failure point and continue. Used at the end of |
| + alternatives. */ |
| + push_dummy_failure, |
| + |
| + /* Followed by two-byte relative address and two-byte number n. |
| + After matching N times, jump to the address upon failure. */ |
| + /* ifdef MBS_SUPPORT, the size of address is 1. */ |
| + succeed_n, |
| + |
| + /* Followed by two-byte relative address, and two-byte number n. |
| + Jump to the address N times, then fail. */ |
| + /* ifdef MBS_SUPPORT, the size of address is 1. */ |
| + jump_n, |
| + |
| + /* Set the following two-byte relative address to the |
| + subsequent two-byte number. The address *includes* the two |
| + bytes of number. */ |
| + /* ifdef MBS_SUPPORT, the size of address is 1. */ |
| + set_number_at, |
| + |
| + wordchar, /* Matches any word-constituent character. */ |
| + notwordchar, /* Matches any char that is not a word-constituent. */ |
| + |
| + wordbeg, /* Succeeds if at word beginning. */ |
| + wordend, /* Succeeds if at word end. */ |
| + |
| + wordbound, /* Succeeds if at a word boundary. */ |
| + notwordbound /* Succeeds if not at a word boundary. */ |
| + |
| +# ifdef emacs |
| + ,before_dot, /* Succeeds if before point. */ |
| + at_dot, /* Succeeds if at point. */ |
| + after_dot, /* Succeeds if after point. */ |
| + |
| + /* Matches any character whose syntax is specified. Followed by |
| + a byte which contains a syntax code, e.g., Sword. */ |
| + syntaxspec, |
| + |
| + /* Matches any character whose syntax is not that specified. */ |
| + notsyntaxspec |
| +# endif /* emacs */ |
| +} re_opcode_t; |
| +#endif /* not INSIDE_RECURSION */ |
| + |
| + |
| +#ifdef BYTE |
| +# define CHAR_T char |
| +# define UCHAR_T unsigned char |
| +# define COMPILED_BUFFER_VAR bufp->buffer |
| +# define OFFSET_ADDRESS_SIZE 2 |
| +# define PREFIX(name) byte_##name |
| +# define ARG_PREFIX(name) name |
| +# define PUT_CHAR(c) putchar (c) |
| +# include <locale/weight.h> |
| +# define FINDIDX findidx |
| +#else |
| +# ifdef WCHAR |
| +# define CHAR_T wchar_t |
| +# define UCHAR_T wchar_t |
| +# define COMPILED_BUFFER_VAR wc_buffer |
| +# define OFFSET_ADDRESS_SIZE 1 /* the size which STORE_NUMBER macro use */ |
| +# define CHAR_CLASS_SIZE ((__alignof__(wctype_t)+sizeof(wctype_t))/sizeof(CHAR_T)+1) |
| +# define PREFIX(name) wcs_##name |
| +# define ARG_PREFIX(name) c##name |
| +/* Should we use wide stream?? */ |
| +# define PUT_CHAR(c) printf ("%C", c); |
| +# define TRUE 1 |
| +# define FALSE 0 |
| +# define findidx findidxwc |
| +# include <locale/weightwc.h> |
| +# undef findidx |
| +# define FINDIDX findidxwc |
| +# else |
| +# ifdef MBS_SUPPORT |
| +# define WCHAR |
| +# define INSIDE_RECURSION |
| +# include "xregex.c" |
| +# undef INSIDE_RECURSION |
| +# endif |
| +# define BYTE |
| +# define INSIDE_RECURSION |
| +# include "xregex.c" |
| +# undef INSIDE_RECURSION |
| +# endif |
| +#endif |
| + |
| +#ifdef INSIDE_RECURSION |
| +/* Common operations on the compiled pattern. */ |
| + |
| +/* Store NUMBER in two contiguous bytes starting at DESTINATION. */ |
| +/* ifdef MBS_SUPPORT, we store NUMBER in 1 element. */ |
| + |
| +# ifdef WCHAR |
| +# define STORE_NUMBER(destination, number) \ |
| + do { \ |
| + *(destination) = (UCHAR_T)(number); \ |
| + } while (0) |
| +# else /* BYTE */ |
| +# define STORE_NUMBER(destination, number) \ |
| + do { \ |
| + (destination)[0] = (number) & 0377; \ |
| + (destination)[1] = (number) >> 8; \ |
| + } while (0) |
| +# endif /* WCHAR */ |
| + |
| +/* Same as STORE_NUMBER, except increment DESTINATION to |
| + the byte after where the number is stored. Therefore, DESTINATION |
| + must be an lvalue. */ |
| +/* ifdef MBS_SUPPORT, we store NUMBER in 1 element. */ |
| + |
| +# define STORE_NUMBER_AND_INCR(destination, number) \ |
| + do { \ |
| + STORE_NUMBER (destination, number); \ |
| + (destination) += OFFSET_ADDRESS_SIZE; \ |
| + } while (0) |
| + |
| +/* Put into DESTINATION a number stored in two contiguous bytes starting |
| + at SOURCE. */ |
| +/* ifdef MBS_SUPPORT, we store NUMBER in 1 element. */ |
| + |
| +# ifdef WCHAR |
| +# define EXTRACT_NUMBER(destination, source) \ |
| + do { \ |
| + (destination) = *(source); \ |
| + } while (0) |
| +# else /* BYTE */ |
| +# define EXTRACT_NUMBER(destination, source) \ |
| + do { \ |
| + (destination) = *(source) & 0377; \ |
| + (destination) += SIGN_EXTEND_CHAR (*((source) + 1)) << 8; \ |
| + } while (0) |
| +# endif |
| + |
| +# ifdef DEBUG |
| +static void PREFIX(extract_number) (int *dest, UCHAR_T *source); |
| +static void |
| +PREFIX(extract_number) (int *dest, UCHAR_T *source) |
| +{ |
| +# ifdef WCHAR |
| + *dest = *source; |
| +# else /* BYTE */ |
| + int temp = SIGN_EXTEND_CHAR (*(source + 1)); |
| + *dest = *source & 0377; |
| + *dest += temp << 8; |
| +# endif |
| +} |
| + |
| +# ifndef EXTRACT_MACROS /* To debug the macros. */ |
| +# undef EXTRACT_NUMBER |
| +# define EXTRACT_NUMBER(dest, src) PREFIX(extract_number) (&dest, src) |
| +# endif /* not EXTRACT_MACROS */ |
| + |
| +# endif /* DEBUG */ |
| + |
| +/* Same as EXTRACT_NUMBER, except increment SOURCE to after the number. |
| + SOURCE must be an lvalue. */ |
| + |
| +# define EXTRACT_NUMBER_AND_INCR(destination, source) \ |
| + do { \ |
| + EXTRACT_NUMBER (destination, source); \ |
| + (source) += OFFSET_ADDRESS_SIZE; \ |
| + } while (0) |
| + |
| +# ifdef DEBUG |
| +static void PREFIX(extract_number_and_incr) (int *destination, |
| + UCHAR_T **source); |
| +static void |
| +PREFIX(extract_number_and_incr) (int *destination, UCHAR_T **source) |
| +{ |
| + PREFIX(extract_number) (destination, *source); |
| + *source += OFFSET_ADDRESS_SIZE; |
| +} |
| + |
| +# ifndef EXTRACT_MACROS |
| +# undef EXTRACT_NUMBER_AND_INCR |
| +# define EXTRACT_NUMBER_AND_INCR(dest, src) \ |
| + PREFIX(extract_number_and_incr) (&dest, &src) |
| +# endif /* not EXTRACT_MACROS */ |
| + |
| +# endif /* DEBUG */ |
| + |
| + |
| + |
| +/* If DEBUG is defined, Regex prints many voluminous messages about what |
| + it is doing (if the variable `debug' is nonzero). If linked with the |
| + main program in `iregex.c', you can enter patterns and strings |
| + interactively. And if linked with the main program in `main.c' and |
| + the other test files, you can run the already-written tests. */ |
| + |
| +# ifdef DEBUG |
| + |
| +# ifndef DEFINED_ONCE |
| + |
| +/* We use standard I/O for debugging. */ |
| +# include <stdio.h> |
| + |
| +/* It is useful to test things that ``must'' be true when debugging. */ |
| +# include <assert.h> |
| + |
| +static int debug; |
| + |
| +# define DEBUG_STATEMENT(e) e |
| +# define DEBUG_PRINT1(x) if (debug) printf (x) |
| +# define DEBUG_PRINT2(x1, x2) if (debug) printf (x1, x2) |
| +# define DEBUG_PRINT3(x1, x2, x3) if (debug) printf (x1, x2, x3) |
| +# define DEBUG_PRINT4(x1, x2, x3, x4) if (debug) printf (x1, x2, x3, x4) |
| +# endif /* not DEFINED_ONCE */ |
| + |
| +# define DEBUG_PRINT_COMPILED_PATTERN(p, s, e) \ |
| + if (debug) PREFIX(print_partial_compiled_pattern) (s, e) |
| +# define DEBUG_PRINT_DOUBLE_STRING(w, s1, sz1, s2, sz2) \ |
| + if (debug) PREFIX(print_double_string) (w, s1, sz1, s2, sz2) |
| + |
| + |
| +/* Print the fastmap in human-readable form. */ |
| + |
| +# ifndef DEFINED_ONCE |
| +void |
| +print_fastmap (char *fastmap) |
| +{ |
| + unsigned was_a_range = 0; |
| + unsigned i = 0; |
| + |
| + while (i < (1 << BYTEWIDTH)) |
| + { |
| + if (fastmap[i++]) |
| + { |
| + was_a_range = 0; |
| + putchar (i - 1); |
| + while (i < (1 << BYTEWIDTH) && fastmap[i]) |
| + { |
| + was_a_range = 1; |
| + i++; |
| + } |
| + if (was_a_range) |
| + { |
| + printf ("-"); |
| + putchar (i - 1); |
| + } |
| + } |
| + } |
| + putchar ('\n'); |
| +} |
| +# endif /* not DEFINED_ONCE */ |
| + |
| + |
| +/* Print a compiled pattern string in human-readable form, starting at |
| + the START pointer into it and ending just before the pointer END. */ |
| + |
| +void |
| +PREFIX(print_partial_compiled_pattern) (UCHAR_T *start, UCHAR_T *end) |
| +{ |
| + int mcnt, mcnt2; |
| + UCHAR_T *p1; |
| + UCHAR_T *p = start; |
| + UCHAR_T *pend = end; |
| + |
| + if (start == NULL) |
| + { |
| + printf ("(null)\n"); |
| + return; |
| + } |
| + |
| + /* Loop over pattern commands. */ |
| + while (p < pend) |
| + { |
| +# ifdef _LIBC |
| + printf ("%td:\t", p - start); |
| +# else |
| + printf ("%ld:\t", (long int) (p - start)); |
| +# endif |
| + |
| + switch ((re_opcode_t) *p++) |
| + { |
| + case no_op: |
| + printf ("/no_op"); |
| + break; |
| + |
| + case exactn: |
| + mcnt = *p++; |
| + printf ("/exactn/%d", mcnt); |
| + do |
| + { |
| + putchar ('/'); |
| + PUT_CHAR (*p++); |
| + } |
| + while (--mcnt); |
| + break; |
| + |
| +# ifdef MBS_SUPPORT |
| + case exactn_bin: |
| + mcnt = *p++; |
| + printf ("/exactn_bin/%d", mcnt); |
| + do |
| + { |
| + printf("/%lx", (long int) *p++); |
| + } |
| + while (--mcnt); |
| + break; |
| +# endif /* MBS_SUPPORT */ |
| + |
| + case start_memory: |
| + mcnt = *p++; |
| + printf ("/start_memory/%d/%ld", mcnt, (long int) *p++); |
| + break; |
| + |
| + case stop_memory: |
| + mcnt = *p++; |
| + printf ("/stop_memory/%d/%ld", mcnt, (long int) *p++); |
| + break; |
| + |
| + case duplicate: |
| + printf ("/duplicate/%ld", (long int) *p++); |
| + break; |
| + |
| + case anychar: |
| + printf ("/anychar"); |
| + break; |
| + |
| + case charset: |
| + case charset_not: |
| + { |
| +# ifdef WCHAR |
| + int i, length; |
| + wchar_t *workp = p; |
| + printf ("/charset [%s", |
| + (re_opcode_t) *(workp - 1) == charset_not ? "^" : ""); |
| + p += 5; |
| + length = *workp++; /* the length of char_classes */ |
| + for (i=0 ; i<length ; i++) |
| + printf("[:%lx:]", (long int) *p++); |
| + length = *workp++; /* the length of collating_symbol */ |
| + for (i=0 ; i<length ;) |
| + { |
| + printf("[."); |
| + while(*p != 0) |
| + PUT_CHAR((i++,*p++)); |
| + i++,p++; |
| + printf(".]"); |
| + } |
| + length = *workp++; /* the length of equivalence_class */ |
| + for (i=0 ; i<length ;) |
| + { |
| + printf("[="); |
| + while(*p != 0) |
| + PUT_CHAR((i++,*p++)); |
| + i++,p++; |
| + printf("=]"); |
| + } |
| + length = *workp++; /* the length of char_range */ |
| + for (i=0 ; i<length ; i++) |
| + { |
| + wchar_t range_start = *p++; |
| + wchar_t range_end = *p++; |
| + printf("%C-%C", range_start, range_end); |
| + } |
| + length = *workp++; /* the length of char */ |
| + for (i=0 ; i<length ; i++) |
| + printf("%C", *p++); |
| + putchar (']'); |
| +# else |
| + register int c, last = -100; |
| + register int in_range = 0; |
| + |
| + printf ("/charset [%s", |
| + (re_opcode_t) *(p - 1) == charset_not ? "^" : ""); |
| + |
| + assert (p + *p < pend); |
| + |
| + for (c = 0; c < 256; c++) |
| + if (c / 8 < *p |
| + && (p[1 + (c/8)] & (1 << (c % 8)))) |
| + { |
| + /* Are we starting a range? */ |
| + if (last + 1 == c && ! in_range) |
| + { |
| + putchar ('-'); |
| + in_range = 1; |
| + } |
| + /* Have we broken a range? */ |
| + else if (last + 1 != c && in_range) |
| + { |
| + putchar (last); |
| + in_range = 0; |
| + } |
| + |
| + if (! in_range) |
| + putchar (c); |
| + |
| + last = c; |
| + } |
| + |
| + if (in_range) |
| + putchar (last); |
| + |
| + putchar (']'); |
| + |
| + p += 1 + *p; |
| +# endif /* WCHAR */ |
| + } |
| + break; |
| + |
| + case begline: |
| + printf ("/begline"); |
| + break; |
| + |
| + case endline: |
| + printf ("/endline"); |
| + break; |
| + |
| + case on_failure_jump: |
| + PREFIX(extract_number_and_incr) (&mcnt, &p); |
| +# ifdef _LIBC |
| + printf ("/on_failure_jump to %td", p + mcnt - start); |
| +# else |
| + printf ("/on_failure_jump to %ld", (long int) (p + mcnt - start)); |
| +# endif |
| + break; |
| + |
| + case on_failure_keep_string_jump: |
| + PREFIX(extract_number_and_incr) (&mcnt, &p); |
| +# ifdef _LIBC |
| + printf ("/on_failure_keep_string_jump to %td", p + mcnt - start); |
| +# else |
| + printf ("/on_failure_keep_string_jump to %ld", |
| + (long int) (p + mcnt - start)); |
| +# endif |
| + break; |
| + |
| + case dummy_failure_jump: |
| + PREFIX(extract_number_and_incr) (&mcnt, &p); |
| +# ifdef _LIBC |
| + printf ("/dummy_failure_jump to %td", p + mcnt - start); |
| +# else |
| + printf ("/dummy_failure_jump to %ld", (long int) (p + mcnt - start)); |
| +# endif |
| + break; |
| + |
| + case push_dummy_failure: |
| + printf ("/push_dummy_failure"); |
| + break; |
| + |
| + case maybe_pop_jump: |
| + PREFIX(extract_number_and_incr) (&mcnt, &p); |
| +# ifdef _LIBC |
| + printf ("/maybe_pop_jump to %td", p + mcnt - start); |
| +# else |
| + printf ("/maybe_pop_jump to %ld", (long int) (p + mcnt - start)); |
| +# endif |
| + break; |
| + |
| + case pop_failure_jump: |
| + PREFIX(extract_number_and_incr) (&mcnt, &p); |
| +# ifdef _LIBC |
| + printf ("/pop_failure_jump to %td", p + mcnt - start); |
| +# else |
| + printf ("/pop_failure_jump to %ld", (long int) (p + mcnt - start)); |
| +# endif |
| + break; |
| + |
| + case jump_past_alt: |
| + PREFIX(extract_number_and_incr) (&mcnt, &p); |
| +# ifdef _LIBC |
| + printf ("/jump_past_alt to %td", p + mcnt - start); |
| +# else |
| + printf ("/jump_past_alt to %ld", (long int) (p + mcnt - start)); |
| +# endif |
| + break; |
| + |
| + case jump: |
| + PREFIX(extract_number_and_incr) (&mcnt, &p); |
| +# ifdef _LIBC |
| + printf ("/jump to %td", p + mcnt - start); |
| +# else |
| + printf ("/jump to %ld", (long int) (p + mcnt - start)); |
| +# endif |
| + break; |
| + |
| + case succeed_n: |
| + PREFIX(extract_number_and_incr) (&mcnt, &p); |
| + p1 = p + mcnt; |
| + PREFIX(extract_number_and_incr) (&mcnt2, &p); |
| +# ifdef _LIBC |
| + printf ("/succeed_n to %td, %d times", p1 - start, mcnt2); |
| +# else |
| + printf ("/succeed_n to %ld, %d times", |
| + (long int) (p1 - start), mcnt2); |
| +# endif |
| + break; |
| + |
| + case jump_n: |
| + PREFIX(extract_number_and_incr) (&mcnt, &p); |
| + p1 = p + mcnt; |
| + PREFIX(extract_number_and_incr) (&mcnt2, &p); |
| + printf ("/jump_n to %d, %d times", p1 - start, mcnt2); |
| + break; |
| + |
| + case set_number_at: |
| + PREFIX(extract_number_and_incr) (&mcnt, &p); |
| + p1 = p + mcnt; |
| + PREFIX(extract_number_and_incr) (&mcnt2, &p); |
| +# ifdef _LIBC |
| + printf ("/set_number_at location %td to %d", p1 - start, mcnt2); |
| +# else |
| + printf ("/set_number_at location %ld to %d", |
| + (long int) (p1 - start), mcnt2); |
| +# endif |
| + break; |
| + |
| + case wordbound: |
| + printf ("/wordbound"); |
| + break; |
| + |
| + case notwordbound: |
| + printf ("/notwordbound"); |
| + break; |
| + |
| + case wordbeg: |
| + printf ("/wordbeg"); |
| + break; |
| + |
| + case wordend: |
| + printf ("/wordend"); |
| + break; |
| + |
| +# ifdef emacs |
| + case before_dot: |
| + printf ("/before_dot"); |
| + break; |
| + |
| + case at_dot: |
| + printf ("/at_dot"); |
| + break; |
| + |
| + case after_dot: |
| + printf ("/after_dot"); |
| + break; |
| + |
| + case syntaxspec: |
| + printf ("/syntaxspec"); |
| + mcnt = *p++; |
| + printf ("/%d", mcnt); |
| + break; |
| + |
| + case notsyntaxspec: |
| + printf ("/notsyntaxspec"); |
| + mcnt = *p++; |
| + printf ("/%d", mcnt); |
| + break; |
| +# endif /* emacs */ |
| + |
| + case wordchar: |
| + printf ("/wordchar"); |
| + break; |
| + |
| + case notwordchar: |
| + printf ("/notwordchar"); |
| + break; |
| + |
| + case begbuf: |
| + printf ("/begbuf"); |
| + break; |
| + |
| + case endbuf: |
| + printf ("/endbuf"); |
| + break; |
| + |
| + default: |
| + printf ("?%ld", (long int) *(p-1)); |
| + } |
| + |
| + putchar ('\n'); |
| + } |
| + |
| +# ifdef _LIBC |
| + printf ("%td:\tend of pattern.\n", p - start); |
| +# else |
| + printf ("%ld:\tend of pattern.\n", (long int) (p - start)); |
| +# endif |
| +} |
| + |
| + |
| +void |
| +PREFIX(print_compiled_pattern) (struct re_pattern_buffer *bufp) |
| +{ |
| + UCHAR_T *buffer = (UCHAR_T*) bufp->buffer; |
| + |
| + PREFIX(print_partial_compiled_pattern) (buffer, buffer |
| + + bufp->used / sizeof(UCHAR_T)); |
| + printf ("%ld bytes used/%ld bytes allocated.\n", |
| + bufp->used, bufp->allocated); |
| + |
| + if (bufp->fastmap_accurate && bufp->fastmap) |
| + { |
| + printf ("fastmap: "); |
| + print_fastmap (bufp->fastmap); |
| + } |
| + |
| +# ifdef _LIBC |
| + printf ("re_nsub: %Zd\t", bufp->re_nsub); |
| +# else |
| + printf ("re_nsub: %ld\t", (long int) bufp->re_nsub); |
| +# endif |
| + printf ("regs_alloc: %d\t", bufp->regs_allocated); |
| + printf ("can_be_null: %d\t", bufp->can_be_null); |
| + printf ("newline_anchor: %d\n", bufp->newline_anchor); |
| + printf ("no_sub: %d\t", bufp->no_sub); |
| + printf ("not_bol: %d\t", bufp->not_bol); |
| + printf ("not_eol: %d\t", bufp->not_eol); |
| + printf ("syntax: %lx\n", bufp->syntax); |
| + /* Perhaps we should print the translate table? */ |
| +} |
| + |
| + |
| +void |
| +PREFIX(print_double_string) (const CHAR_T *where, const CHAR_T *string1, |
| + int size1, const CHAR_T *string2, int size2) |
| +{ |
| + int this_char; |
| + |
| + if (where == NULL) |
| + printf ("(null)"); |
| + else |
| + { |
| + int cnt; |
| + |
| + if (FIRST_STRING_P (where)) |
| + { |
| + for (this_char = where - string1; this_char < size1; this_char++) |
| + PUT_CHAR (string1[this_char]); |
| + |
| + where = string2; |
| + } |
| + |
| + cnt = 0; |
| + for (this_char = where - string2; this_char < size2; this_char++) |
| + { |
| + PUT_CHAR (string2[this_char]); |
| + if (++cnt > 100) |
| + { |
| + fputs ("...", stdout); |
| + break; |
| + } |
| + } |
| + } |
| +} |
| + |
| +# ifndef DEFINED_ONCE |
| +void |
| +printchar (int c) |
| +{ |
| + putc (c, stderr); |
| +} |
| +# endif |
| + |
| +# else /* not DEBUG */ |
| + |
| +# ifndef DEFINED_ONCE |
| +# undef assert |
| +# define assert(e) |
| + |
| +# define DEBUG_STATEMENT(e) |
| +# define DEBUG_PRINT1(x) |
| +# define DEBUG_PRINT2(x1, x2) |
| +# define DEBUG_PRINT3(x1, x2, x3) |
| +# define DEBUG_PRINT4(x1, x2, x3, x4) |
| +# endif /* not DEFINED_ONCE */ |
| +# define DEBUG_PRINT_COMPILED_PATTERN(p, s, e) |
| +# define DEBUG_PRINT_DOUBLE_STRING(w, s1, sz1, s2, sz2) |
| + |
| +# endif /* not DEBUG */ |
| + |
| + |
| + |
| +# ifdef WCHAR |
| +/* This convert a multibyte string to a wide character string. |
| + And write their correspondances to offset_buffer(see below) |
| + and write whether each wchar_t is binary data to is_binary. |
| + This assume invalid multibyte sequences as binary data. |
| + We assume offset_buffer and is_binary is already allocated |
| + enough space. */ |
| + |
| +static size_t convert_mbs_to_wcs (CHAR_T *dest, const unsigned char* src, |
| + size_t len, int *offset_buffer, |
| + char *is_binary); |
| +static size_t |
| +convert_mbs_to_wcs (CHAR_T *dest, const unsigned char*src, size_t len, |
| + int *offset_buffer, char *is_binary) |
| + /* It hold correspondances between src(char string) and |
| + dest(wchar_t string) for optimization. |
| + e.g. src = "xxxyzz" |
| + dest = {'X', 'Y', 'Z'} |
| + (each "xxx", "y" and "zz" represent one multibyte character |
| + corresponding to 'X', 'Y' and 'Z'.) |
| + offset_buffer = {0, 0+3("xxx"), 0+3+1("y"), 0+3+1+2("zz")} |
| + = {0, 3, 4, 6} |
| + */ |
| +{ |
| + wchar_t *pdest = dest; |
| + const unsigned char *psrc = src; |
| + size_t wc_count = 0; |
| + |
| + mbstate_t mbs; |
| + int i, consumed; |
| + size_t mb_remain = len; |
| + size_t mb_count = 0; |
| + |
| + /* Initialize the conversion state. */ |
| + memset (&mbs, 0, sizeof (mbstate_t)); |
| + |
| + offset_buffer[0] = 0; |
| + for( ; mb_remain > 0 ; ++wc_count, ++pdest, mb_remain -= consumed, |
| + psrc += consumed) |
| + { |
| +#ifdef _LIBC |
| + consumed = __mbrtowc (pdest, psrc, mb_remain, &mbs); |
| +#else |
| + consumed = mbrtowc (pdest, psrc, mb_remain, &mbs); |
| +#endif |
| + |
| + if (consumed <= 0) |
| + /* failed to convert. maybe src contains binary data. |
| + So we consume 1 byte manualy. */ |
| + { |
| + *pdest = *psrc; |
| + consumed = 1; |
| + is_binary[wc_count] = TRUE; |
| + } |
| + else |
| + is_binary[wc_count] = FALSE; |
| + /* In sjis encoding, we use yen sign as escape character in |
| + place of reverse solidus. So we convert 0x5c(yen sign in |
| + sjis) to not 0xa5(yen sign in UCS2) but 0x5c(reverse |
| + solidus in UCS2). */ |
| + if (consumed == 1 && (int) *psrc == 0x5c && (int) *pdest == 0xa5) |
| + *pdest = (wchar_t) *psrc; |
| + |
| + offset_buffer[wc_count + 1] = mb_count += consumed; |
| + } |
| + |
| + /* Fill remain of the buffer with sentinel. */ |
| + for (i = wc_count + 1 ; i <= len ; i++) |
| + offset_buffer[i] = mb_count + 1; |
| + |
| + return wc_count; |
| +} |
| + |
| +# endif /* WCHAR */ |
| + |
| +#else /* not INSIDE_RECURSION */ |
| + |
| +/* Set by `re_set_syntax' to the current regexp syntax to recognize. Can |
| + also be assigned to arbitrarily: each pattern buffer stores its own |
| + syntax, so it can be changed between regex compilations. */ |
| +/* This has no initializer because initialized variables in Emacs |
| + become read-only after dumping. */ |
| +reg_syntax_t re_syntax_options; |
| + |
| + |
| +/* Specify the precise syntax of regexps for compilation. This provides |
| + for compatibility for various utilities which historically have |
| + different, incompatible syntaxes. |
| + |
| + The argument SYNTAX is a bit mask comprised of the various bits |
| + defined in regex.h. We return the old syntax. */ |
| + |
| +reg_syntax_t |
| +re_set_syntax (reg_syntax_t syntax) |
| +{ |
| + reg_syntax_t ret = re_syntax_options; |
| + |
| + re_syntax_options = syntax; |
| +# ifdef DEBUG |
| + if (syntax & RE_DEBUG) |
| + debug = 1; |
| + else if (debug) /* was on but now is not */ |
| + debug = 0; |
| +# endif /* DEBUG */ |
| + return ret; |
| +} |
| +# ifdef _LIBC |
| +weak_alias (__re_set_syntax, re_set_syntax) |
| +# endif |
| + |
| +/* This table gives an error message for each of the error codes listed |
| + in regex.h. Obviously the order here has to be same as there. |
| + POSIX doesn't require that we do anything for REG_NOERROR, |
| + but why not be nice? */ |
| + |
| +static const char *re_error_msgid[] = |
| + { |
| + gettext_noop ("Success"), /* REG_NOERROR */ |
| + gettext_noop ("No match"), /* REG_NOMATCH */ |
| + gettext_noop ("Invalid regular expression"), /* REG_BADPAT */ |
| + gettext_noop ("Invalid collation character"), /* REG_ECOLLATE */ |
| + gettext_noop ("Invalid character class name"), /* REG_ECTYPE */ |
| + gettext_noop ("Trailing backslash"), /* REG_EESCAPE */ |
| + gettext_noop ("Invalid back reference"), /* REG_ESUBREG */ |
| + gettext_noop ("Unmatched [ or [^"), /* REG_EBRACK */ |
| + gettext_noop ("Unmatched ( or \\("), /* REG_EPAREN */ |
| + gettext_noop ("Unmatched \\{"), /* REG_EBRACE */ |
| + gettext_noop ("Invalid content of \\{\\}"), /* REG_BADBR */ |
| + gettext_noop ("Invalid range end"), /* REG_ERANGE */ |
| + gettext_noop ("Memory exhausted"), /* REG_ESPACE */ |
| + gettext_noop ("Invalid preceding regular expression"), /* REG_BADRPT */ |
| + gettext_noop ("Premature end of regular expression"), /* REG_EEND */ |
| + gettext_noop ("Regular expression too big"), /* REG_ESIZE */ |
| + gettext_noop ("Unmatched ) or \\)") /* REG_ERPAREN */ |
| + }; |
| + |
| +#endif /* INSIDE_RECURSION */ |
| + |
| +#ifndef DEFINED_ONCE |
| +/* Avoiding alloca during matching, to placate r_alloc. */ |
| + |
| +/* Define MATCH_MAY_ALLOCATE unless we need to make sure that the |
| + searching and matching functions should not call alloca. On some |
| + systems, alloca is implemented in terms of malloc, and if we're |
| + using the relocating allocator routines, then malloc could cause a |
| + relocation, which might (if the strings being searched are in the |
| + ralloc heap) shift the data out from underneath the regexp |
| + routines. |
| + |
| + Here's another reason to avoid allocation: Emacs |
| + processes input from X in a signal handler; processing X input may |
| + call malloc; if input arrives while a matching routine is calling |
| + malloc, then we're scrod. But Emacs can't just block input while |
| + calling matching routines; then we don't notice interrupts when |
| + they come in. So, Emacs blocks input around all regexp calls |
| + except the matching calls, which it leaves unprotected, in the |
| + faith that they will not malloc. */ |
| + |
| +/* Normally, this is fine. */ |
| +# define MATCH_MAY_ALLOCATE |
| + |
| +/* When using GNU C, we are not REALLY using the C alloca, no matter |
| + what config.h may say. So don't take precautions for it. */ |
| +# ifdef __GNUC__ |
| +# undef C_ALLOCA |
| +# endif |
| + |
| +/* The match routines may not allocate if (1) they would do it with malloc |
| + and (2) it's not safe for them to use malloc. |
| + Note that if REL_ALLOC is defined, matching would not use malloc for the |
| + failure stack, but we would still use it for the register vectors; |
| + so REL_ALLOC should not affect this. */ |
| +# if (defined C_ALLOCA || defined REGEX_MALLOC) && defined emacs |
| +# undef MATCH_MAY_ALLOCATE |
| +# endif |
| +#endif /* not DEFINED_ONCE */ |
| + |
| +#ifdef INSIDE_RECURSION |
| +/* Failure stack declarations and macros; both re_compile_fastmap and |
| + re_match_2 use a failure stack. These have to be macros because of |
| + REGEX_ALLOCATE_STACK. */ |
| + |
| + |
| +/* Number of failure points for which to initially allocate space |
| + when matching. If this number is exceeded, we allocate more |
| + space, so it is not a hard limit. */ |
| +# ifndef INIT_FAILURE_ALLOC |
| +# define INIT_FAILURE_ALLOC 5 |
| +# endif |
| + |
| +/* Roughly the maximum number of failure points on the stack. Would be |
| + exactly that if always used MAX_FAILURE_ITEMS items each time we failed. |
| + This is a variable only so users of regex can assign to it; we never |
| + change it ourselves. */ |
| + |
| + |
| +# ifndef DEFINED_ONCE |
| + |
| +# ifdef INT_IS_16BIT |
| +# define RE_M_F_TYPE long int |
| +# else |
| +# define RE_M_F_TYPE int |
| +# endif /* INT_IS_16BIT */ |
| + |
| +# ifdef MATCH_MAY_ALLOCATE |
| +/* 4400 was enough to cause a crash on Alpha OSF/1, |
| + whose default stack limit is 2mb. */ |
| +# define RE_M_F_DEFAULT 4000 |
| +# else |
| +# define RE_M_F_DEFAULT 2000 |
| +# endif /* MATCH_MAY_ALLOCATE */ |
| + |
| +# include <shlib-compat.h> |
| + |
| +# if SHLIB_COMPAT (libc, GLIBC_2_0, GLIBC_2_3) |
| +link_warning (re_max_failures, "the 're_max_failures' variable is obsolete and will go away.") |
| +RE_M_F_TYPE re_max_failures = RE_M_F_DEFAULT; |
| +# else |
| +RE_M_F_TYPE re_max_failures attribute_hidden = RE_M_F_DEFAULT; |
| +# endif /* SHLIB_COMPAT */ |
| + |
| +# undef RE_M_F_TYPE |
| +# undef RE_M_F_DEFAULT |
| + |
| +# endif /* DEFINED_ONCE */ |
| + |
| +# ifdef INT_IS_16BIT |
| + |
| +union PREFIX(fail_stack_elt) |
| +{ |
| + UCHAR_T *pointer; |
| + long int integer; |
| +}; |
| + |
| +typedef union PREFIX(fail_stack_elt) PREFIX(fail_stack_elt_t); |
| + |
| +typedef struct |
| +{ |
| + PREFIX(fail_stack_elt_t) *stack; |
| + unsigned long int size; |
| + unsigned long int avail; /* Offset of next open position. */ |
| +} PREFIX(fail_stack_type); |
| + |
| +# else /* not INT_IS_16BIT */ |
| + |
| +union PREFIX(fail_stack_elt) |
| +{ |
| + UCHAR_T *pointer; |
| + int integer; |
| +}; |
| + |
| +typedef union PREFIX(fail_stack_elt) PREFIX(fail_stack_elt_t); |
| + |
| +typedef struct |
| +{ |
| + PREFIX(fail_stack_elt_t) *stack; |
| + unsigned size; |
| + unsigned avail; /* Offset of next open position. */ |
| +} PREFIX(fail_stack_type); |
| + |
| +# endif /* INT_IS_16BIT */ |
| + |
| +# ifndef DEFINED_ONCE |
| +# define FAIL_STACK_EMPTY() (fail_stack.avail == 0) |
| +# define FAIL_STACK_PTR_EMPTY() (fail_stack_ptr->avail == 0) |
| +# define FAIL_STACK_FULL() (fail_stack.avail == fail_stack.size) |
| +# endif |
| + |
| + |
| +/* Define macros to initialize and free the failure stack. |
| + Do `return -2' if the alloc fails. */ |
| + |
| +# ifdef MATCH_MAY_ALLOCATE |
| +# define INIT_FAIL_STACK() \ |
| + do { \ |
| + fail_stack.stack = (PREFIX(fail_stack_elt_t) *) \ |
| + REGEX_ALLOCATE_STACK (INIT_FAILURE_ALLOC * sizeof (PREFIX(fail_stack_elt_t))); \ |
| + \ |
| + if (fail_stack.stack == NULL) \ |
| + return -2; \ |
| + \ |
| + fail_stack.size = INIT_FAILURE_ALLOC; \ |
| + fail_stack.avail = 0; \ |
| + } while (0) |
| + |
| +# define RESET_FAIL_STACK() REGEX_FREE_STACK (fail_stack.stack) |
| +# else |
| +# define INIT_FAIL_STACK() \ |
| + do { \ |
| + fail_stack.avail = 0; \ |
| + } while (0) |
| + |
| +# define RESET_FAIL_STACK() |
| +# endif |
| + |
| + |
| +/* Double the size of FAIL_STACK, up to approximately `re_max_failures' items. |
| + |
| + Return 1 if succeeds, and 0 if either ran out of memory |
| + allocating space for it or it was already too large. |
| + |
| + REGEX_REALLOCATE_STACK requires `destination' be declared. */ |
| + |
| +# define DOUBLE_FAIL_STACK(fail_stack) \ |
| + ((fail_stack).size > (unsigned) (re_max_failures * MAX_FAILURE_ITEMS) \ |
| + ? 0 \ |
| + : ((fail_stack).stack = (PREFIX(fail_stack_elt_t) *) \ |
| + REGEX_REALLOCATE_STACK ((fail_stack).stack, \ |
| + (fail_stack).size * sizeof (PREFIX(fail_stack_elt_t)), \ |
| + ((fail_stack).size << 1) * sizeof (PREFIX(fail_stack_elt_t))),\ |
| + \ |
| + (fail_stack).stack == NULL \ |
| + ? 0 \ |
| + : ((fail_stack).size <<= 1, \ |
| + 1))) |
| + |
| + |
| +/* Push pointer POINTER on FAIL_STACK. |
| + Return 1 if was able to do so and 0 if ran out of memory allocating |
| + space to do so. */ |
| +# define PUSH_PATTERN_OP(POINTER, FAIL_STACK) \ |
| + ((FAIL_STACK_FULL () \ |
| + && !DOUBLE_FAIL_STACK (FAIL_STACK)) \ |
| + ? 0 \ |
| + : ((FAIL_STACK).stack[(FAIL_STACK).avail++].pointer = POINTER, \ |
| + 1)) |
| + |
| +/* Push a pointer value onto the failure stack. |
| + Assumes the variable `fail_stack'. Probably should only |
| + be called from within `PUSH_FAILURE_POINT'. */ |
| +# define PUSH_FAILURE_POINTER(item) \ |
| + fail_stack.stack[fail_stack.avail++].pointer = (UCHAR_T *) (item) |
| + |
| +/* This pushes an integer-valued item onto the failure stack. |
| + Assumes the variable `fail_stack'. Probably should only |
| + be called from within `PUSH_FAILURE_POINT'. */ |
| +# define PUSH_FAILURE_INT(item) \ |
| + fail_stack.stack[fail_stack.avail++].integer = (item) |
| + |
| +/* Push a fail_stack_elt_t value onto the failure stack. |
| + Assumes the variable `fail_stack'. Probably should only |
| + be called from within `PUSH_FAILURE_POINT'. */ |
| +# define PUSH_FAILURE_ELT(item) \ |
| + fail_stack.stack[fail_stack.avail++] = (item) |
| + |
| +/* These three POP... operations complement the three PUSH... operations. |
| + All assume that `fail_stack' is nonempty. */ |
| +# define POP_FAILURE_POINTER() fail_stack.stack[--fail_stack.avail].pointer |
| +# define POP_FAILURE_INT() fail_stack.stack[--fail_stack.avail].integer |
| +# define POP_FAILURE_ELT() fail_stack.stack[--fail_stack.avail] |
| + |
| +/* Used to omit pushing failure point id's when we're not debugging. */ |
| +# ifdef DEBUG |
| +# define DEBUG_PUSH PUSH_FAILURE_INT |
| +# define DEBUG_POP(item_addr) *(item_addr) = POP_FAILURE_INT () |
| +# else |
| +# define DEBUG_PUSH(item) |
| +# define DEBUG_POP(item_addr) |
| +# endif |
| + |
| + |
| +/* Push the information about the state we will need |
| + if we ever fail back to it. |
| + |
| + Requires variables fail_stack, regstart, regend, reg_info, and |
| + num_regs_pushed be declared. DOUBLE_FAIL_STACK requires `destination' |
| + be declared. |
| + |
| + Does `return FAILURE_CODE' if runs out of memory. */ |
| + |
| +# define PUSH_FAILURE_POINT(pattern_place, string_place, failure_code) \ |
| + do { \ |
| + char *destination; \ |
| + /* Must be int, so when we don't save any registers, the arithmetic \ |
| + of 0 + -1 isn't done as unsigned. */ \ |
| + /* Can't be int, since there is not a shred of a guarantee that int \ |
| + is wide enough to hold a value of something to which pointer can \ |
| + be assigned */ \ |
| + active_reg_t this_reg; \ |
| + \ |
| + DEBUG_STATEMENT (failure_id++); \ |
| + DEBUG_STATEMENT (nfailure_points_pushed++); \ |
| + DEBUG_PRINT2 ("\nPUSH_FAILURE_POINT #%u:\n", failure_id); \ |
| + DEBUG_PRINT2 (" Before push, next avail: %d\n", (fail_stack).avail);\ |
| + DEBUG_PRINT2 (" size: %d\n", (fail_stack).size);\ |
| + \ |
| + DEBUG_PRINT2 (" slots needed: %ld\n", NUM_FAILURE_ITEMS); \ |
| + DEBUG_PRINT2 (" available: %d\n", REMAINING_AVAIL_SLOTS); \ |
| + \ |
| + /* Ensure we have enough space allocated for what we will push. */ \ |
| + while (REMAINING_AVAIL_SLOTS < NUM_FAILURE_ITEMS) \ |
| + { \ |
| + if (!DOUBLE_FAIL_STACK (fail_stack)) \ |
| + return failure_code; \ |
| + \ |
| + DEBUG_PRINT2 ("\n Doubled stack; size now: %d\n", \ |
| + (fail_stack).size); \ |
| + DEBUG_PRINT2 (" slots available: %d\n", REMAINING_AVAIL_SLOTS);\ |
| + } \ |
| + \ |
| + /* Push the info, starting with the registers. */ \ |
| + DEBUG_PRINT1 ("\n"); \ |
| + \ |
| + if (1) \ |
| + for (this_reg = lowest_active_reg; this_reg <= highest_active_reg; \ |
| + this_reg++) \ |
| + { \ |
| + DEBUG_PRINT2 (" Pushing reg: %lu\n", this_reg); \ |
| + DEBUG_STATEMENT (num_regs_pushed++); \ |
| + \ |
| + DEBUG_PRINT2 (" start: %p\n", regstart[this_reg]); \ |
| + PUSH_FAILURE_POINTER (regstart[this_reg]); \ |
| + \ |
| + DEBUG_PRINT2 (" end: %p\n", regend[this_reg]); \ |
| + PUSH_FAILURE_POINTER (regend[this_reg]); \ |
| + \ |
| + DEBUG_PRINT2 (" info: %p\n ", \ |
| + reg_info[this_reg].word.pointer); \ |
| + DEBUG_PRINT2 (" match_null=%d", \ |
| + REG_MATCH_NULL_STRING_P (reg_info[this_reg])); \ |
| + DEBUG_PRINT2 (" active=%d", IS_ACTIVE (reg_info[this_reg])); \ |
| + DEBUG_PRINT2 (" matched_something=%d", \ |
| + MATCHED_SOMETHING (reg_info[this_reg])); \ |
| + DEBUG_PRINT2 (" ever_matched=%d", \ |
| + EVER_MATCHED_SOMETHING (reg_info[this_reg])); \ |
| + DEBUG_PRINT1 ("\n"); \ |
| + PUSH_FAILURE_ELT (reg_info[this_reg].word); \ |
| + } \ |
| + \ |
| + DEBUG_PRINT2 (" Pushing low active reg: %ld\n", lowest_active_reg);\ |
| + PUSH_FAILURE_INT (lowest_active_reg); \ |
| + \ |
| + DEBUG_PRINT2 (" Pushing high active reg: %ld\n", highest_active_reg);\ |
| + PUSH_FAILURE_INT (highest_active_reg); \ |
| + \ |
| + DEBUG_PRINT2 (" Pushing pattern %p:\n", pattern_place); \ |
| + DEBUG_PRINT_COMPILED_PATTERN (bufp, pattern_place, pend); \ |
| + PUSH_FAILURE_POINTER (pattern_place); \ |
| + \ |
| + DEBUG_PRINT2 (" Pushing string %p: `", string_place); \ |
| + DEBUG_PRINT_DOUBLE_STRING (string_place, string1, size1, string2, \ |
| + size2); \ |
| + DEBUG_PRINT1 ("'\n"); \ |
| + PUSH_FAILURE_POINTER (string_place); \ |
| + \ |
| + DEBUG_PRINT2 (" Pushing failure id: %u\n", failure_id); \ |
| + DEBUG_PUSH (failure_id); \ |
| + } while (0) |
| + |
| +# ifndef DEFINED_ONCE |
| +/* This is the number of items that are pushed and popped on the stack |
| + for each register. */ |
| +# define NUM_REG_ITEMS 3 |
| + |
| +/* Individual items aside from the registers. */ |
| +# ifdef DEBUG |
| +# define NUM_NONREG_ITEMS 5 /* Includes failure point id. */ |
| +# else |
| +# define NUM_NONREG_ITEMS 4 |
| +# endif |
| + |
| +/* We push at most this many items on the stack. */ |
| +/* We used to use (num_regs - 1), which is the number of registers |
| + this regexp will save; but that was changed to 5 |
| + to avoid stack overflow for a regexp with lots of parens. */ |
| +# define MAX_FAILURE_ITEMS (5 * NUM_REG_ITEMS + NUM_NONREG_ITEMS) |
| + |
| +/* We actually push this many items. */ |
| +# define NUM_FAILURE_ITEMS \ |
| + (((0 \ |
| + ? 0 : highest_active_reg - lowest_active_reg + 1) \ |
| + * NUM_REG_ITEMS) \ |
| + + NUM_NONREG_ITEMS) |
| + |
| +/* How many items can still be added to the stack without overflowing it. */ |
| +# define REMAINING_AVAIL_SLOTS ((fail_stack).size - (fail_stack).avail) |
| +# endif /* not DEFINED_ONCE */ |
| + |
| + |
| +/* Pops what PUSH_FAIL_STACK pushes. |
| + |
| + We restore into the parameters, all of which should be lvalues: |
| + STR -- the saved data position. |
| + PAT -- the saved pattern position. |
| + LOW_REG, HIGH_REG -- the highest and lowest active registers. |
| + REGSTART, REGEND -- arrays of string positions. |
| + REG_INFO -- array of information about each subexpression. |
| + |
| + Also assumes the variables `fail_stack' and (if debugging), `bufp', |
| + `pend', `string1', `size1', `string2', and `size2'. */ |
| +# define POP_FAILURE_POINT(str, pat, low_reg, high_reg, regstart, regend, reg_info)\ |
| +{ \ |
| + DEBUG_STATEMENT (unsigned failure_id;) \ |
| + active_reg_t this_reg; \ |
| + const UCHAR_T *string_temp; \ |
| + \ |
| + assert (!FAIL_STACK_EMPTY ()); \ |
| + \ |
| + /* Remove failure points and point to how many regs pushed. */ \ |
| + DEBUG_PRINT1 ("POP_FAILURE_POINT:\n"); \ |
| + DEBUG_PRINT2 (" Before pop, next avail: %d\n", fail_stack.avail); \ |
| + DEBUG_PRINT2 (" size: %d\n", fail_stack.size); \ |
| + \ |
| + assert (fail_stack.avail >= NUM_NONREG_ITEMS); \ |
| + \ |
| + DEBUG_POP (&failure_id); \ |
| + DEBUG_PRINT2 (" Popping failure id: %u\n", failure_id); \ |
| + \ |
| + /* If the saved string location is NULL, it came from an \ |
| + on_failure_keep_string_jump opcode, and we want to throw away the \ |
| + saved NULL, thus retaining our current position in the string. */ \ |
| + string_temp = POP_FAILURE_POINTER (); \ |
| + if (string_temp != NULL) \ |
| + str = (const CHAR_T *) string_temp; \ |
| + \ |
| + DEBUG_PRINT2 (" Popping string %p: `", str); \ |
| + DEBUG_PRINT_DOUBLE_STRING (str, string1, size1, string2, size2); \ |
| + DEBUG_PRINT1 ("'\n"); \ |
| + \ |
| + pat = (UCHAR_T *) POP_FAILURE_POINTER (); \ |
| + DEBUG_PRINT2 (" Popping pattern %p:\n", pat); \ |
| + DEBUG_PRINT_COMPILED_PATTERN (bufp, pat, pend); \ |
| + \ |
| + /* Restore register info. */ \ |
| + high_reg = (active_reg_t) POP_FAILURE_INT (); \ |
| + DEBUG_PRINT2 (" Popping high active reg: %ld\n", high_reg); \ |
| + \ |
| + low_reg = (active_reg_t) POP_FAILURE_INT (); \ |
| + DEBUG_PRINT2 (" Popping low active reg: %ld\n", low_reg); \ |
| + \ |
| + if (1) \ |
| + for (this_reg = high_reg; this_reg >= low_reg; this_reg--) \ |
| + { \ |
| + DEBUG_PRINT2 (" Popping reg: %ld\n", this_reg); \ |
| + \ |
| + reg_info[this_reg].word = POP_FAILURE_ELT (); \ |
| + DEBUG_PRINT2 (" info: %p\n", \ |
| + reg_info[this_reg].word.pointer); \ |
| + \ |
| + regend[this_reg] = (const CHAR_T *) POP_FAILURE_POINTER (); \ |
| + DEBUG_PRINT2 (" end: %p\n", regend[this_reg]); \ |
| + \ |
| + regstart[this_reg] = (const CHAR_T *) POP_FAILURE_POINTER (); \ |
| + DEBUG_PRINT2 (" start: %p\n", regstart[this_reg]); \ |
| + } \ |
| + else \ |
| + { \ |
| + for (this_reg = highest_active_reg; this_reg > high_reg; this_reg--) \ |
| + { \ |
| + reg_info[this_reg].word.integer = 0; \ |
| + regend[this_reg] = 0; \ |
| + regstart[this_reg] = 0; \ |
| + } \ |
| + highest_active_reg = high_reg; \ |
| + } \ |
| + \ |
| + set_regs_matched_done = 0; \ |
| + DEBUG_STATEMENT (nfailure_points_popped++); \ |
| +} /* POP_FAILURE_POINT */ |
| + |
| +/* Structure for per-register (a.k.a. per-group) information. |
| + Other register information, such as the |
| + starting and ending positions (which are addresses), and the list of |
| + inner groups (which is a bits list) are maintained in separate |
| + variables. |
| + |
| + We are making a (strictly speaking) nonportable assumption here: that |
| + the compiler will pack our bit fields into something that fits into |
| + the type of `word', i.e., is something that fits into one item on the |
| + failure stack. */ |
| + |
| + |
| +/* Declarations and macros for re_match_2. */ |
| + |
| +typedef union |
| +{ |
| + PREFIX(fail_stack_elt_t) word; |
| + struct |
| + { |
| + /* This field is one if this group can match the empty string, |
| + zero if not. If not yet determined, `MATCH_NULL_UNSET_VALUE'. */ |
| +# define MATCH_NULL_UNSET_VALUE 3 |
| + unsigned match_null_string_p : 2; |
| + unsigned is_active : 1; |
| + unsigned matched_something : 1; |
| + unsigned ever_matched_something : 1; |
| + } bits; |
| +} PREFIX(register_info_type); |
| + |
| +# ifndef DEFINED_ONCE |
| +# define REG_MATCH_NULL_STRING_P(R) ((R).bits.match_null_string_p) |
| +# define IS_ACTIVE(R) ((R).bits.is_active) |
| +# define MATCHED_SOMETHING(R) ((R).bits.matched_something) |
| +# define EVER_MATCHED_SOMETHING(R) ((R).bits.ever_matched_something) |
| + |
| + |
| +/* Call this when have matched a real character; it sets `matched' flags |
| + for the subexpressions which we are currently inside. Also records |
| + that those subexprs have matched. */ |
| +# define SET_REGS_MATCHED() \ |
| + do \ |
| + { \ |
| + if (!set_regs_matched_done) \ |
| + { \ |
| + active_reg_t r; \ |
| + set_regs_matched_done = 1; \ |
| + for (r = lowest_active_reg; r <= highest_active_reg; r++) \ |
| + { \ |
| + MATCHED_SOMETHING (reg_info[r]) \ |
| + = EVER_MATCHED_SOMETHING (reg_info[r]) \ |
| + = 1; \ |
| + } \ |
| + } \ |
| + } \ |
| + while (0) |
| +# endif /* not DEFINED_ONCE */ |
| + |
| +/* Registers are set to a sentinel when they haven't yet matched. */ |
| +static CHAR_T PREFIX(reg_unset_dummy); |
| +# define REG_UNSET_VALUE (&PREFIX(reg_unset_dummy)) |
| +# define REG_UNSET(e) ((e) == REG_UNSET_VALUE) |
| + |
| +/* Subroutine declarations and macros for regex_compile. */ |
| +static void PREFIX(store_op1) (re_opcode_t op, UCHAR_T *loc, int arg); |
| +static void PREFIX(store_op2) (re_opcode_t op, UCHAR_T *loc, |
| + int arg1, int arg2); |
| +static void PREFIX(insert_op1) (re_opcode_t op, UCHAR_T *loc, |
| + int arg, UCHAR_T *end); |
| +static void PREFIX(insert_op2) (re_opcode_t op, UCHAR_T *loc, |
| + int arg1, int arg2, UCHAR_T *end); |
| +static boolean PREFIX(at_begline_loc_p) (const CHAR_T *pattern, |
| + const CHAR_T *p, |
| + reg_syntax_t syntax); |
| +static boolean PREFIX(at_endline_loc_p) (const CHAR_T *p, |
| + const CHAR_T *pend, |
| + reg_syntax_t syntax); |
| +# ifdef WCHAR |
| +static reg_errcode_t wcs_compile_range (CHAR_T range_start, |
| + const CHAR_T **p_ptr, |
| + const CHAR_T *pend, |
| + char *translate, |
| + reg_syntax_t syntax, |
| + UCHAR_T *b, |
| + CHAR_T *char_set); |
| +static void insert_space (int num, CHAR_T *loc, CHAR_T *end); |
| +# else /* BYTE */ |
| +static reg_errcode_t byte_compile_range (unsigned int range_start, |
| + const char **p_ptr, |
| + const char *pend, |
| + RE_TRANSLATE_TYPE translate, |
| + reg_syntax_t syntax, |
| + unsigned char *b); |
| +# endif /* WCHAR */ |
| + |
| +/* Fetch the next character in the uncompiled pattern---translating it |
| + if necessary. Also cast from a signed character in the constant |
| + string passed to us by the user to an unsigned char that we can use |
| + as an array index (in, e.g., `translate'). */ |
| +/* ifdef MBS_SUPPORT, we translate only if character <= 0xff, |
| + because it is impossible to allocate 4GB array for some encodings |
| + which have 4 byte character_set like UCS4. */ |
| +# ifndef PATFETCH |
| +# ifdef WCHAR |
| +# define PATFETCH(c) \ |
| + do {if (p == pend) return REG_EEND; \ |
| + c = (UCHAR_T) *p++; \ |
| + if (translate && (c <= 0xff)) c = (UCHAR_T) translate[c]; \ |
| + } while (0) |
| +# else /* BYTE */ |
| +# define PATFETCH(c) \ |
| + do {if (p == pend) return REG_EEND; \ |
| + c = (unsigned char) *p++; \ |
| + if (translate) c = (unsigned char) translate[c]; \ |
| + } while (0) |
| +# endif /* WCHAR */ |
| +# endif |
| + |
| +/* Fetch the next character in the uncompiled pattern, with no |
| + translation. */ |
| +# define PATFETCH_RAW(c) \ |
| + do {if (p == pend) return REG_EEND; \ |
| + c = (UCHAR_T) *p++; \ |
| + } while (0) |
| + |
| +/* Go backwards one character in the pattern. */ |
| +# define PATUNFETCH p-- |
| + |
| + |
| +/* If `translate' is non-null, return translate[D], else just D. We |
| + cast the subscript to translate because some data is declared as |
| + `char *', to avoid warnings when a string constant is passed. But |
| + when we use a character as a subscript we must make it unsigned. */ |
| +/* ifdef MBS_SUPPORT, we translate only if character <= 0xff, |
| + because it is impossible to allocate 4GB array for some encodings |
| + which have 4 byte character_set like UCS4. */ |
| + |
| +# ifndef TRANSLATE |
| +# ifdef WCHAR |
| +# define TRANSLATE(d) \ |
| + ((translate && ((UCHAR_T) (d)) <= 0xff) \ |
| + ? (char) translate[(unsigned char) (d)] : (d)) |
| +# else /* BYTE */ |
| +# define TRANSLATE(d) \ |
| + (translate ? (char) translate[(unsigned char) (d)] : (char) (d)) |
| +# endif /* WCHAR */ |
| +# endif |
| + |
| + |
| +/* Macros for outputting the compiled pattern into `buffer'. */ |
| + |
| +/* If the buffer isn't allocated when it comes in, use this. */ |
| +# define INIT_BUF_SIZE (32 * sizeof(UCHAR_T)) |
| + |
| +/* Make sure we have at least N more bytes of space in buffer. */ |
| +# ifdef WCHAR |
| +# define GET_BUFFER_SPACE(n) \ |
| + while (((unsigned long)b - (unsigned long)COMPILED_BUFFER_VAR \ |
| + + (n)*sizeof(CHAR_T)) > bufp->allocated) \ |
| + EXTEND_BUFFER () |
| +# else /* BYTE */ |
| +# define GET_BUFFER_SPACE(n) \ |
| + while ((unsigned long) (b - bufp->buffer + (n)) > bufp->allocated) \ |
| + EXTEND_BUFFER () |
| +# endif /* WCHAR */ |
| + |
| +/* Make sure we have one more byte of buffer space and then add C to it. */ |
| +# define BUF_PUSH(c) \ |
| + do { \ |
| + GET_BUFFER_SPACE (1); \ |
| + *b++ = (UCHAR_T) (c); \ |
| + } while (0) |
| + |
| + |
| +/* Ensure we have two more bytes of buffer space and then append C1 and C2. */ |
| +# define BUF_PUSH_2(c1, c2) \ |
| + do { \ |
| + GET_BUFFER_SPACE (2); \ |
| + *b++ = (UCHAR_T) (c1); \ |
| + *b++ = (UCHAR_T) (c2); \ |
| + } while (0) |
| + |
| + |
| +/* As with BUF_PUSH_2, except for three bytes. */ |
| +# define BUF_PUSH_3(c1, c2, c3) \ |
| + do { \ |
| + GET_BUFFER_SPACE (3); \ |
| + *b++ = (UCHAR_T) (c1); \ |
| + *b++ = (UCHAR_T) (c2); \ |
| + *b++ = (UCHAR_T) (c3); \ |
| + } while (0) |
| + |
| +/* Store a jump with opcode OP at LOC to location TO. We store a |
| + relative address offset by the three bytes the jump itself occupies. */ |
| +# define STORE_JUMP(op, loc, to) \ |
| + PREFIX(store_op1) (op, loc, (int) ((to) - (loc) - (1 + OFFSET_ADDRESS_SIZE))) |
| + |
| +/* Likewise, for a two-argument jump. */ |
| +# define STORE_JUMP2(op, loc, to, arg) \ |
| + PREFIX(store_op2) (op, loc, (int) ((to) - (loc) - (1 + OFFSET_ADDRESS_SIZE)), arg) |
| + |
| +/* Like `STORE_JUMP', but for inserting. Assume `b' is the buffer end. */ |
| +# define INSERT_JUMP(op, loc, to) \ |
| + PREFIX(insert_op1) (op, loc, (int) ((to) - (loc) - (1 + OFFSET_ADDRESS_SIZE)), b) |
| + |
| +/* Like `STORE_JUMP2', but for inserting. Assume `b' is the buffer end. */ |
| +# define INSERT_JUMP2(op, loc, to, arg) \ |
| + PREFIX(insert_op2) (op, loc, (int) ((to) - (loc) - (1 + OFFSET_ADDRESS_SIZE)),\ |
| + arg, b) |
| + |
| +/* This is not an arbitrary limit: the arguments which represent offsets |
| + into the pattern are two bytes long. So if 2^16 bytes turns out to |
| + be too small, many things would have to change. */ |
| +/* Any other compiler which, like MSC, has allocation limit below 2^16 |
| + bytes will have to use approach similar to what was done below for |
| + MSC and drop MAX_BUF_SIZE a bit. Otherwise you may end up |
| + reallocating to 0 bytes. Such thing is not going to work too well. |
| + You have been warned!! */ |
| +# ifndef DEFINED_ONCE |
| +# if defined _MSC_VER && !defined WIN32 |
| +/* Microsoft C 16-bit versions limit malloc to approx 65512 bytes. |
| + The REALLOC define eliminates a flurry of conversion warnings, |
| + but is not required. */ |
| +# define MAX_BUF_SIZE 65500L |
| +# define REALLOC(p,s) realloc ((p), (size_t) (s)) |
| +# else |
| +# define MAX_BUF_SIZE (1L << 16) |
| +# define REALLOC(p,s) realloc ((p), (s)) |
| +# endif |
| + |
| +/* Extend the buffer by twice its current size via realloc and |
| + reset the pointers that pointed into the old block to point to the |
| + correct places in the new one. If extending the buffer results in it |
| + being larger than MAX_BUF_SIZE, then flag memory exhausted. */ |
| +# ifndef __BOUNDED_POINTERS__ |
| +# define __BOUNDED_POINTERS__ 0 |
| +# endif |
| +# if __BOUNDED_POINTERS__ |
| +# define SET_HIGH_BOUND(P) (__ptrhigh (P) = __ptrlow (P) + bufp->allocated) |
| +# define MOVE_BUFFER_POINTER(P) \ |
| + (__ptrlow (P) += incr, SET_HIGH_BOUND (P), __ptrvalue (P) += incr) |
| +# define ELSE_EXTEND_BUFFER_HIGH_BOUND \ |
| + else \ |
| + { \ |
| + SET_HIGH_BOUND (b); \ |
| + SET_HIGH_BOUND (begalt); \ |
| + if (fixup_alt_jump) \ |
| + SET_HIGH_BOUND (fixup_alt_jump); \ |
| + if (laststart) \ |
| + SET_HIGH_BOUND (laststart); \ |
| + if (pending_exact) \ |
| + SET_HIGH_BOUND (pending_exact); \ |
| + } |
| +# else |
| +# define MOVE_BUFFER_POINTER(P) (P) += incr |
| +# define ELSE_EXTEND_BUFFER_HIGH_BOUND |
| +# endif |
| +# endif /* not DEFINED_ONCE */ |
| + |
| +# ifdef WCHAR |
| +# define EXTEND_BUFFER() \ |
| + do { \ |
| + UCHAR_T *old_buffer = COMPILED_BUFFER_VAR; \ |
| + int wchar_count; \ |
| + if (bufp->allocated + sizeof(UCHAR_T) > MAX_BUF_SIZE) \ |
| + return REG_ESIZE; \ |
| + bufp->allocated <<= 1; \ |
| + if (bufp->allocated > MAX_BUF_SIZE) \ |
| + bufp->allocated = MAX_BUF_SIZE; \ |
| + /* How many characters the new buffer can have? */ \ |
| + wchar_count = bufp->allocated / sizeof(UCHAR_T); \ |
| + if (wchar_count == 0) wchar_count = 1; \ |
| + /* Truncate the buffer to CHAR_T align. */ \ |
| + bufp->allocated = wchar_count * sizeof(UCHAR_T); \ |
| + RETALLOC (COMPILED_BUFFER_VAR, wchar_count, UCHAR_T); \ |
| + bufp->buffer = (char*)COMPILED_BUFFER_VAR; \ |
| + if (COMPILED_BUFFER_VAR == NULL) \ |
| + return REG_ESPACE; \ |
| + /* If the buffer moved, move all the pointers into it. */ \ |
| + if (old_buffer != COMPILED_BUFFER_VAR) \ |
| + { \ |
| + int incr = COMPILED_BUFFER_VAR - old_buffer; \ |
| + MOVE_BUFFER_POINTER (b); \ |
| + MOVE_BUFFER_POINTER (begalt); \ |
| + if (fixup_alt_jump) \ |
| + MOVE_BUFFER_POINTER (fixup_alt_jump); \ |
| + if (laststart) \ |
| + MOVE_BUFFER_POINTER (laststart); \ |
| + if (pending_exact) \ |
| + MOVE_BUFFER_POINTER (pending_exact); \ |
| + } \ |
| + ELSE_EXTEND_BUFFER_HIGH_BOUND \ |
| + } while (0) |
| +# else /* BYTE */ |
| +# define EXTEND_BUFFER() \ |
| + do { \ |
| + UCHAR_T *old_buffer = COMPILED_BUFFER_VAR; \ |
| + if (bufp->allocated == MAX_BUF_SIZE) \ |
| + return REG_ESIZE; \ |
| + bufp->allocated <<= 1; \ |
| + if (bufp->allocated > MAX_BUF_SIZE) \ |
| + bufp->allocated = MAX_BUF_SIZE; \ |
| + bufp->buffer = (UCHAR_T *) REALLOC (COMPILED_BUFFER_VAR, \ |
| + bufp->allocated); \ |
| + if (COMPILED_BUFFER_VAR == NULL) \ |
| + return REG_ESPACE; \ |
| + /* If the buffer moved, move all the pointers into it. */ \ |
| + if (old_buffer != COMPILED_BUFFER_VAR) \ |
| + { \ |
| + int incr = COMPILED_BUFFER_VAR - old_buffer; \ |
| + MOVE_BUFFER_POINTER (b); \ |
| + MOVE_BUFFER_POINTER (begalt); \ |
| + if (fixup_alt_jump) \ |
| + MOVE_BUFFER_POINTER (fixup_alt_jump); \ |
| + if (laststart) \ |
| + MOVE_BUFFER_POINTER (laststart); \ |
| + if (pending_exact) \ |
| + MOVE_BUFFER_POINTER (pending_exact); \ |
| + } \ |
| + ELSE_EXTEND_BUFFER_HIGH_BOUND \ |
| + } while (0) |
| +# endif /* WCHAR */ |
| + |
| +# ifndef DEFINED_ONCE |
| +/* Since we have one byte reserved for the register number argument to |
| + {start,stop}_memory, the maximum number of groups we can report |
| + things about is what fits in that byte. */ |
| +# define MAX_REGNUM 255 |
| + |
| +/* But patterns can have more than `MAX_REGNUM' registers. We just |
| + ignore the excess. */ |
| +typedef unsigned regnum_t; |
| + |
| + |
| +/* Macros for the compile stack. */ |
| + |
| +/* Since offsets can go either forwards or backwards, this type needs to |
| + be able to hold values from -(MAX_BUF_SIZE - 1) to MAX_BUF_SIZE - 1. */ |
| +/* int may be not enough when sizeof(int) == 2. */ |
| +typedef long pattern_offset_t; |
| + |
| +typedef struct |
| +{ |
| + pattern_offset_t begalt_offset; |
| + pattern_offset_t fixup_alt_jump; |
| + pattern_offset_t inner_group_offset; |
| + pattern_offset_t laststart_offset; |
| + regnum_t regnum; |
| +} compile_stack_elt_t; |
| + |
| + |
| +typedef struct |
| +{ |
| + compile_stack_elt_t *stack; |
| + unsigned size; |
| + unsigned avail; /* Offset of next open position. */ |
| +} compile_stack_type; |
| + |
| + |
| +# define INIT_COMPILE_STACK_SIZE 32 |
| + |
| +# define COMPILE_STACK_EMPTY (compile_stack.avail == 0) |
| +# define COMPILE_STACK_FULL (compile_stack.avail == compile_stack.size) |
| + |
| +/* The next available element. */ |
| +# define COMPILE_STACK_TOP (compile_stack.stack[compile_stack.avail]) |
| + |
| +# endif /* not DEFINED_ONCE */ |
| + |
| +/* Set the bit for character C in a list. */ |
| +# ifndef DEFINED_ONCE |
| +# define SET_LIST_BIT(c) \ |
| + (b[((unsigned char) (c)) / BYTEWIDTH] \ |
| + |= 1 << (((unsigned char) c) % BYTEWIDTH)) |
| +# endif /* DEFINED_ONCE */ |
| + |
| +/* Get the next unsigned number in the uncompiled pattern. */ |
| +# define GET_UNSIGNED_NUMBER(num) \ |
| + { \ |
| + while (p != pend) \ |
| + { \ |
| + PATFETCH (c); \ |
| + if (c < '0' || c > '9') \ |
| + break; \ |
| + if (num <= RE_DUP_MAX) \ |
| + { \ |
| + if (num < 0) \ |
| + num = 0; \ |
| + num = num * 10 + c - '0'; \ |
| + } \ |
| + } \ |
| + } |
| + |
| +# ifndef DEFINED_ONCE |
| +# if WIDE_CHAR_SUPPORT |
| +/* The GNU C library provides support for user-defined character classes |
| + and the functions from ISO C amendement 1. */ |
| +# ifdef CHARCLASS_NAME_MAX |
| +# define CHAR_CLASS_MAX_LENGTH CHARCLASS_NAME_MAX |
| +# else |
| +/* This shouldn't happen but some implementation might still have this |
| + problem. Use a reasonable default value. */ |
| +# define CHAR_CLASS_MAX_LENGTH 256 |
| +# endif |
| + |
| +# ifdef _LIBC |
| +# define IS_CHAR_CLASS(string) __wctype (string) |
| +# else |
| +# define IS_CHAR_CLASS(string) wctype (string) |
| +# endif |
| +# else |
| +# define CHAR_CLASS_MAX_LENGTH 6 /* Namely, `xdigit'. */ |
| + |
| +# define IS_CHAR_CLASS(string) \ |
| + (STREQ (string, "alpha") || STREQ (string, "upper") \ |
| + || STREQ (string, "lower") || STREQ (string, "digit") \ |
| + || STREQ (string, "alnum") || STREQ (string, "xdigit") \ |
| + || STREQ (string, "space") || STREQ (string, "print") \ |
| + || STREQ (string, "punct") || STREQ (string, "graph") \ |
| + || STREQ (string, "cntrl") || STREQ (string, "blank")) |
| +# endif |
| +# endif /* DEFINED_ONCE */ |
| + |
| +# ifndef MATCH_MAY_ALLOCATE |
| + |
| +/* If we cannot allocate large objects within re_match_2_internal, |
| + we make the fail stack and register vectors global. |
| + The fail stack, we grow to the maximum size when a regexp |
| + is compiled. |
| + The register vectors, we adjust in size each time we |
| + compile a regexp, according to the number of registers it needs. */ |
| + |
| +static PREFIX(fail_stack_type) fail_stack; |
| + |
| +/* Size with which the following vectors are currently allocated. |
| + That is so we can make them bigger as needed, |
| + but never make them smaller. */ |
| +# ifdef DEFINED_ONCE |
| +static int regs_allocated_size; |
| + |
| +static const char ** regstart, ** regend; |
| +static const char ** old_regstart, ** old_regend; |
| +static const char **best_regstart, **best_regend; |
| +static const char **reg_dummy; |
| +# endif /* DEFINED_ONCE */ |
| + |
| +static PREFIX(register_info_type) *PREFIX(reg_info); |
| +static PREFIX(register_info_type) *PREFIX(reg_info_dummy); |
| + |
| +/* Make the register vectors big enough for NUM_REGS registers, |
| + but don't make them smaller. */ |
| + |
| +static void |
| +PREFIX(regex_grow_registers) (int num_regs) |
| +{ |
| + if (num_regs > regs_allocated_size) |
| + { |
| + RETALLOC_IF (regstart, num_regs, const char *); |
| + RETALLOC_IF (regend, num_regs, const char *); |
| + RETALLOC_IF (old_regstart, num_regs, const char *); |
| + RETALLOC_IF (old_regend, num_regs, const char *); |
| + RETALLOC_IF (best_regstart, num_regs, const char *); |
| + RETALLOC_IF (best_regend, num_regs, const char *); |
| + RETALLOC_IF (PREFIX(reg_info), num_regs, PREFIX(register_info_type)); |
| + RETALLOC_IF (reg_dummy, num_regs, const char *); |
| + RETALLOC_IF (PREFIX(reg_info_dummy), num_regs, PREFIX(register_info_type)); |
| + |
| + regs_allocated_size = num_regs; |
| + } |
| +} |
| + |
| +# endif /* not MATCH_MAY_ALLOCATE */ |
| + |
| +# ifndef DEFINED_ONCE |
| +static boolean group_in_compile_stack (compile_stack_type compile_stack, |
| + regnum_t regnum); |
| +# endif /* not DEFINED_ONCE */ |
| + |
| +/* `regex_compile' compiles PATTERN (of length SIZE) according to SYNTAX. |
| + Returns one of error codes defined in `regex.h', or zero for success. |
| + |
| + Assumes the `allocated' (and perhaps `buffer') and `translate' |
| + fields are set in BUFP on entry. |
| + |
| + If it succeeds, results are put in BUFP (if it returns an error, the |
| + contents of BUFP are undefined): |
| + `buffer' is the compiled pattern; |
| + `syntax' is set to SYNTAX; |
| + `used' is set to the length of the compiled pattern; |
| + `fastmap_accurate' is zero; |
| + `re_nsub' is the number of subexpressions in PATTERN; |
| + `not_bol' and `not_eol' are zero; |
| + |
| + The `fastmap' and `newline_anchor' fields are neither |
| + examined nor set. */ |
| + |
| +/* Return, freeing storage we allocated. */ |
| +# ifdef WCHAR |
| +# define FREE_STACK_RETURN(value) \ |
| + return (free(pattern), free(mbs_offset), free(is_binary), free (compile_stack.stack), value) |
| +# else |
| +# define FREE_STACK_RETURN(value) \ |
| + return (free (compile_stack.stack), value) |
| +# endif /* WCHAR */ |
| + |
| +static reg_errcode_t |
| +PREFIX(regex_compile) (const char *ARG_PREFIX(pattern), |
| + size_t ARG_PREFIX(size), reg_syntax_t syntax, |
| + struct re_pattern_buffer *bufp) |
| +{ |
| + /* We fetch characters from PATTERN here. Even though PATTERN is |
| + `char *' (i.e., signed), we declare these variables as unsigned, so |
| + they can be reliably used as array indices. */ |
| + register UCHAR_T c, c1; |
| + |
| +#ifdef WCHAR |
| + /* A temporary space to keep wchar_t pattern and compiled pattern. */ |
| + CHAR_T *pattern, *COMPILED_BUFFER_VAR; |
| + size_t size; |
| + /* offset buffer for optimization. See convert_mbs_to_wc. */ |
| + int *mbs_offset = NULL; |
| + /* It hold whether each wchar_t is binary data or not. */ |
| + char *is_binary = NULL; |
| + /* A flag whether exactn is handling binary data or not. */ |
| + char is_exactn_bin = FALSE; |
| +#endif /* WCHAR */ |
| + |
| + /* A random temporary spot in PATTERN. */ |
| + const CHAR_T *p1; |
| + |
| + /* Points to the end of the buffer, where we should append. */ |
| + register UCHAR_T *b; |
| + |
| + /* Keeps track of unclosed groups. */ |
| + compile_stack_type compile_stack; |
| + |
| + /* Points to the current (ending) position in the pattern. */ |
| +#ifdef WCHAR |
| + const CHAR_T *p; |
| + const CHAR_T *pend; |
| +#else /* BYTE */ |
| + const CHAR_T *p = pattern; |
| + const CHAR_T *pend = pattern + size; |
| +#endif /* WCHAR */ |
| + |
| + /* How to translate the characters in the pattern. */ |
| + RE_TRANSLATE_TYPE translate = bufp->translate; |
| + |
| + /* Address of the count-byte of the most recently inserted `exactn' |
| + command. This makes it possible to tell if a new exact-match |
| + character can be added to that command or if the character requires |
| + a new `exactn' command. */ |
| + UCHAR_T *pending_exact = 0; |
| + |
| + /* Address of start of the most recently finished expression. |
| + This tells, e.g., postfix * where to find the start of its |
| + operand. Reset at the beginning of groups and alternatives. */ |
| + UCHAR_T *laststart = 0; |
| + |
| + /* Address of beginning of regexp, or inside of last group. */ |
| + UCHAR_T *begalt; |
| + |
| + /* Address of the place where a forward jump should go to the end of |
| + the containing expression. Each alternative of an `or' -- except the |
| + last -- ends with a forward jump of this sort. */ |
| + UCHAR_T *fixup_alt_jump = 0; |
| + |
| + /* Counts open-groups as they are encountered. Remembered for the |
| + matching close-group on the compile stack, so the same register |
| + number is put in the stop_memory as the start_memory. */ |
| + regnum_t regnum = 0; |
| + |
| +#ifdef WCHAR |
| + /* Initialize the wchar_t PATTERN and offset_buffer. */ |
| + p = pend = pattern = TALLOC(csize + 1, CHAR_T); |
| + mbs_offset = TALLOC(csize + 1, int); |
| + is_binary = TALLOC(csize + 1, char); |
| + if (pattern == NULL || mbs_offset == NULL || is_binary == NULL) |
| + { |
| + free(pattern); |
| + free(mbs_offset); |
| + free(is_binary); |
| + return REG_ESPACE; |
| + } |
| + pattern[csize] = L'\0'; /* sentinel */ |
| + size = convert_mbs_to_wcs(pattern, cpattern, csize, mbs_offset, is_binary); |
| + pend = p + size; |
| + if (size < 0) |
| + { |
| + free(pattern); |
| + free(mbs_offset); |
| + free(is_binary); |
| + return REG_BADPAT; |
| + } |
| +#endif |
| + |
| +#ifdef DEBUG |
| + DEBUG_PRINT1 ("\nCompiling pattern: "); |
| + if (debug) |
| + { |
| + unsigned debug_count; |
| + |
| + for (debug_count = 0; debug_count < size; debug_count++) |
| + PUT_CHAR (pattern[debug_count]); |
| + putchar ('\n'); |
| + } |
| +#endif /* DEBUG */ |
| + |
| + /* Initialize the compile stack. */ |
| + compile_stack.stack = TALLOC (INIT_COMPILE_STACK_SIZE, compile_stack_elt_t); |
| + if (compile_stack.stack == NULL) |
| + { |
| +#ifdef WCHAR |
| + free(pattern); |
| + free(mbs_offset); |
| + free(is_binary); |
| +#endif |
| + return REG_ESPACE; |
| + } |
| + |
| + compile_stack.size = INIT_COMPILE_STACK_SIZE; |
| + compile_stack.avail = 0; |
| + |
| + /* Initialize the pattern buffer. */ |
| + bufp->syntax = syntax; |
| + bufp->fastmap_accurate = 0; |
| + bufp->not_bol = bufp->not_eol = 0; |
| + |
| + /* Set `used' to zero, so that if we return an error, the pattern |
| + printer (for debugging) will think there's no pattern. We reset it |
| + at the end. */ |
| + bufp->used = 0; |
| + |
| + /* Always count groups, whether or not bufp->no_sub is set. */ |
| + bufp->re_nsub = 0; |
| + |
| +#if !defined emacs && !defined SYNTAX_TABLE |
| + /* Initialize the syntax table. */ |
| + init_syntax_once (); |
| +#endif |
| + |
| + if (bufp->allocated == 0) |
| + { |
| + if (bufp->buffer) |
| + { /* If zero allocated, but buffer is non-null, try to realloc |
| + enough space. This loses if buffer's address is bogus, but |
| + that is the user's responsibility. */ |
| +#ifdef WCHAR |
| + /* Free bufp->buffer and allocate an array for wchar_t pattern |
| + buffer. */ |
| + free(bufp->buffer); |
| + COMPILED_BUFFER_VAR = TALLOC (INIT_BUF_SIZE/sizeof(UCHAR_T), |
| + UCHAR_T); |
| +#else |
| + RETALLOC (COMPILED_BUFFER_VAR, INIT_BUF_SIZE, UCHAR_T); |
| +#endif /* WCHAR */ |
| + } |
| + else |
| + { /* Caller did not allocate a buffer. Do it for them. */ |
| + COMPILED_BUFFER_VAR = TALLOC (INIT_BUF_SIZE / sizeof(UCHAR_T), |
| + UCHAR_T); |
| + } |
| + |
| + if (!COMPILED_BUFFER_VAR) FREE_STACK_RETURN (REG_ESPACE); |
| +#ifdef WCHAR |
| + bufp->buffer = (char*)COMPILED_BUFFER_VAR; |
| +#endif /* WCHAR */ |
| + bufp->allocated = INIT_BUF_SIZE; |
| + } |
| +#ifdef WCHAR |
| + else |
| + COMPILED_BUFFER_VAR = (UCHAR_T*) bufp->buffer; |
| +#endif |
| + |
| + begalt = b = COMPILED_BUFFER_VAR; |
| + |
| + /* Loop through the uncompiled pattern until we're at the end. */ |
| + while (p != pend) |
| + { |
| + PATFETCH (c); |
| + |
| + switch (c) |
| + { |
| + case '^': |
| + { |
| + if ( /* If at start of pattern, it's an operator. */ |
| + p == pattern + 1 |
| + /* If context independent, it's an operator. */ |
| + || syntax & RE_CONTEXT_INDEP_ANCHORS |
| + /* Otherwise, depends on what's come before. */ |
| + || PREFIX(at_begline_loc_p) (pattern, p, syntax)) |
| + BUF_PUSH (begline); |
| + else |
| + goto normal_char; |
| + } |
| + break; |
| + |
| + |
| + case '$': |
| + { |
| + if ( /* If at end of pattern, it's an operator. */ |
| + p == pend |
| + /* If context independent, it's an operator. */ |
| + || syntax & RE_CONTEXT_INDEP_ANCHORS |
| + /* Otherwise, depends on what's next. */ |
| + || PREFIX(at_endline_loc_p) (p, pend, syntax)) |
| + BUF_PUSH (endline); |
| + else |
| + goto normal_char; |
| + } |
| + break; |
| + |
| + |
| + case '+': |
| + case '?': |
| + if ((syntax & RE_BK_PLUS_QM) |
| + || (syntax & RE_LIMITED_OPS)) |
| + goto normal_char; |
| + handle_plus: |
| + case '*': |
| + /* If there is no previous pattern... */ |
| + if (!laststart) |
| + { |
| + if (syntax & RE_CONTEXT_INVALID_OPS) |
| + FREE_STACK_RETURN (REG_BADRPT); |
| + else if (!(syntax & RE_CONTEXT_INDEP_OPS)) |
| + goto normal_char; |
| + } |
| + |
| + { |
| + /* Are we optimizing this jump? */ |
| + boolean keep_string_p = false; |
| + |
| + /* 1 means zero (many) matches is allowed. */ |
| + char zero_times_ok = 0, many_times_ok = 0; |
| + |
| + /* If there is a sequence of repetition chars, collapse it |
| + down to just one (the right one). We can't combine |
| + interval operators with these because of, e.g., `a{2}*', |
| + which should only match an even number of `a's. */ |
| + |
| + for (;;) |
| + { |
| + zero_times_ok |= c != '+'; |
| + many_times_ok |= c != '?'; |
| + |
| + if (p == pend) |
| + break; |
| + |
| + PATFETCH (c); |
| + |
| + if (c == '*' |
| + || (!(syntax & RE_BK_PLUS_QM) && (c == '+' || c == '?'))) |
| + ; |
| + |
| + else if (syntax & RE_BK_PLUS_QM && c == '\\') |
| + { |
| + if (p == pend) FREE_STACK_RETURN (REG_EESCAPE); |
| + |
| + PATFETCH (c1); |
| + if (!(c1 == '+' || c1 == '?')) |
| + { |
| + PATUNFETCH; |
| + PATUNFETCH; |
| + break; |
| + } |
| + |
| + c = c1; |
| + } |
| + else |
| + { |
| + PATUNFETCH; |
| + break; |
| + } |
| + |
| + /* If we get here, we found another repeat character. */ |
| + } |
| + |
| + /* Star, etc. applied to an empty pattern is equivalent |
| + to an empty pattern. */ |
| + if (!laststart) |
| + break; |
| + |
| + /* Now we know whether or not zero matches is allowed |
| + and also whether or not two or more matches is allowed. */ |
| + if (many_times_ok) |
| + { /* More than one repetition is allowed, so put in at the |
| + end a backward relative jump from `b' to before the next |
| + jump we're going to put in below (which jumps from |
| + laststart to after this jump). |
| + |
| + But if we are at the `*' in the exact sequence `.*\n', |
| + insert an unconditional jump backwards to the ., |
| + instead of the beginning of the loop. This way we only |
| + push a failure point once, instead of every time |
| + through the loop. */ |
| + assert (p - 1 > pattern); |
| + |
| + /* Allocate the space for the jump. */ |
| + GET_BUFFER_SPACE (1 + OFFSET_ADDRESS_SIZE); |
| + |
| + /* We know we are not at the first character of the pattern, |
| + because laststart was nonzero. And we've already |
| + incremented `p', by the way, to be the character after |
| + the `*'. Do we have to do something analogous here |
| + for null bytes, because of RE_DOT_NOT_NULL? */ |
| + if (TRANSLATE (*(p - 2)) == TRANSLATE ('.') |
| + && zero_times_ok |
| + && p < pend && TRANSLATE (*p) == TRANSLATE ('\n') |
| + && !(syntax & RE_DOT_NEWLINE)) |
| + { /* We have .*\n. */ |
| + STORE_JUMP (jump, b, laststart); |
| + keep_string_p = true; |
| + } |
| + else |
| + /* Anything else. */ |
| + STORE_JUMP (maybe_pop_jump, b, laststart - |
| + (1 + OFFSET_ADDRESS_SIZE)); |
| + |
| + /* We've added more stuff to the buffer. */ |
| + b += 1 + OFFSET_ADDRESS_SIZE; |
| + } |
| + |
| + /* On failure, jump from laststart to b + 3, which will be the |
| + end of the buffer after this jump is inserted. */ |
| + /* ifdef WCHAR, 'b + 1 + OFFSET_ADDRESS_SIZE' instead of |
| + 'b + 3'. */ |
| + GET_BUFFER_SPACE (1 + OFFSET_ADDRESS_SIZE); |
| + INSERT_JUMP (keep_string_p ? on_failure_keep_string_jump |
| + : on_failure_jump, |
| + laststart, b + 1 + OFFSET_ADDRESS_SIZE); |
| + pending_exact = 0; |
| + b += 1 + OFFSET_ADDRESS_SIZE; |
| + |
| + if (!zero_times_ok) |
| + { |
| + /* At least one repetition is required, so insert a |
| + `dummy_failure_jump' before the initial |
| + `on_failure_jump' instruction of the loop. This |
| + effects a skip over that instruction the first time |
| + we hit that loop. */ |
| + GET_BUFFER_SPACE (1 + OFFSET_ADDRESS_SIZE); |
| + INSERT_JUMP (dummy_failure_jump, laststart, laststart + |
| + 2 + 2 * OFFSET_ADDRESS_SIZE); |
| + b += 1 + OFFSET_ADDRESS_SIZE; |
| + } |
| + } |
| + break; |
| + |
| + |
| + case '.': |
| + laststart = b; |
| + BUF_PUSH (anychar); |
| + break; |
| + |
| + |
| + case '[': |
| + { |
| + boolean had_char_class = false; |
| +#ifdef WCHAR |
| + CHAR_T range_start = 0xffffffff; |
| +#else |
| + unsigned int range_start = 0xffffffff; |
| +#endif |
| + if (p == pend) FREE_STACK_RETURN (REG_EBRACK); |
| + |
| +#ifdef WCHAR |
| + /* We assume a charset(_not) structure as a wchar_t array. |
| + charset[0] = (re_opcode_t) charset(_not) |
| + charset[1] = l (= length of char_classes) |
| + charset[2] = m (= length of collating_symbols) |
| + charset[3] = n (= length of equivalence_classes) |
| + charset[4] = o (= length of char_ranges) |
| + charset[5] = p (= length of chars) |
| + |
| + charset[6] = char_class (wctype_t) |
| + charset[6+CHAR_CLASS_SIZE] = char_class (wctype_t) |
| + ... |
| + charset[l+5] = char_class (wctype_t) |
| + |
| + charset[l+6] = collating_symbol (wchar_t) |
| + ... |
| + charset[l+m+5] = collating_symbol (wchar_t) |
| + ifdef _LIBC we use the index if |
| + _NL_COLLATE_SYMB_EXTRAMB instead of |
| + wchar_t string. |
| + |
| + charset[l+m+6] = equivalence_classes (wchar_t) |
| + ... |
| + charset[l+m+n+5] = equivalence_classes (wchar_t) |
| + ifdef _LIBC we use the index in |
| + _NL_COLLATE_WEIGHT instead of |
| + wchar_t string. |
| + |
| + charset[l+m+n+6] = range_start |
| + charset[l+m+n+7] = range_end |
| + ... |
| + charset[l+m+n+2o+4] = range_start |
| + charset[l+m+n+2o+5] = range_end |
| + ifdef _LIBC we use the value looked up |
| + in _NL_COLLATE_COLLSEQ instead of |
| + wchar_t character. |
| + |
| + charset[l+m+n+2o+6] = char |
| + ... |
| + charset[l+m+n+2o+p+5] = char |
| + |
| + */ |
| + |
| + /* We need at least 6 spaces: the opcode, the length of |
| + char_classes, the length of collating_symbols, the length of |
| + equivalence_classes, the length of char_ranges, the length of |
| + chars. */ |
| + GET_BUFFER_SPACE (6); |
| + |
| + /* Save b as laststart. And We use laststart as the pointer |
| + to the first element of the charset here. |
| + In other words, laststart[i] indicates charset[i]. */ |
| + laststart = b; |
| + |
| + /* We test `*p == '^' twice, instead of using an if |
| + statement, so we only need one BUF_PUSH. */ |
| + BUF_PUSH (*p == '^' ? charset_not : charset); |
| + if (*p == '^') |
| + p++; |
| + |
| + /* Push the length of char_classes, the length of |
| + collating_symbols, the length of equivalence_classes, the |
| + length of char_ranges and the length of chars. */ |
| + BUF_PUSH_3 (0, 0, 0); |
| + BUF_PUSH_2 (0, 0); |
| + |
| + /* Remember the first position in the bracket expression. */ |
| + p1 = p; |
| + |
| + /* charset_not matches newline according to a syntax bit. */ |
| + if ((re_opcode_t) b[-6] == charset_not |
| + && (syntax & RE_HAT_LISTS_NOT_NEWLINE)) |
| + { |
| + BUF_PUSH('\n'); |
| + laststart[5]++; /* Update the length of characters */ |
| + } |
| + |
| + /* Read in characters and ranges, setting map bits. */ |
| + for (;;) |
| + { |
| + if (p == pend) FREE_STACK_RETURN (REG_EBRACK); |
| + |
| + PATFETCH (c); |
| + |
| + /* \ might escape characters inside [...] and [^...]. */ |
| + if ((syntax & RE_BACKSLASH_ESCAPE_IN_LISTS) && c == '\\') |
| + { |
| + if (p == pend) FREE_STACK_RETURN (REG_EESCAPE); |
| + |
| + PATFETCH (c1); |
| + BUF_PUSH(c1); |
| + laststart[5]++; /* Update the length of chars */ |
| + range_start = c1; |
| + continue; |
| + } |
| + |
| + /* Could be the end of the bracket expression. If it's |
| + not (i.e., when the bracket expression is `[]' so |
| + far), the ']' character bit gets set way below. */ |
| + if (c == ']' && p != p1 + 1) |
| + break; |
| + |
| + /* Look ahead to see if it's a range when the last thing |
| + was a character class. */ |
| + if (had_char_class && c == '-' && *p != ']') |
| + FREE_STACK_RETURN (REG_ERANGE); |
| + |
| + /* Look ahead to see if it's a range when the last thing |
| + was a character: if this is a hyphen not at the |
| + beginning or the end of a list, then it's the range |
| + operator. */ |
| + if (c == '-' |
| + && !(p - 2 >= pattern && p[-2] == '[') |
| + && !(p - 3 >= pattern && p[-3] == '[' && p[-2] == '^') |
| + && *p != ']') |
| + { |
| + reg_errcode_t ret; |
| + /* Allocate the space for range_start and range_end. */ |
| + GET_BUFFER_SPACE (2); |
| + /* Update the pointer to indicate end of buffer. */ |
| + b += 2; |
| + ret = wcs_compile_range (range_start, &p, pend, translate, |
| + syntax, b, laststart); |
| + if (ret != REG_NOERROR) FREE_STACK_RETURN (ret); |
| + range_start = 0xffffffff; |
| + } |
| + else if (p[0] == '-' && p[1] != ']') |
| + { /* This handles ranges made up of characters only. */ |
| + reg_errcode_t ret; |
| + |
| + /* Move past the `-'. */ |
| + PATFETCH (c1); |
| + /* Allocate the space for range_start and range_end. */ |
| + GET_BUFFER_SPACE (2); |
| + /* Update the pointer to indicate end of buffer. */ |
| + b += 2; |
| + ret = wcs_compile_range (c, &p, pend, translate, syntax, b, |
| + laststart); |
| + if (ret != REG_NOERROR) FREE_STACK_RETURN (ret); |
| + range_start = 0xffffffff; |
| + } |
| + |
| + /* See if we're at the beginning of a possible character |
| + class. */ |
| + else if (syntax & RE_CHAR_CLASSES && c == '[' && *p == ':') |
| + { /* Leave room for the null. */ |
| + char str[CHAR_CLASS_MAX_LENGTH + 1]; |
| + |
| + PATFETCH (c); |
| + c1 = 0; |
| + |
| + /* If pattern is `[[:'. */ |
| + if (p == pend) FREE_STACK_RETURN (REG_EBRACK); |
| + |
| + for (;;) |
| + { |
| + PATFETCH (c); |
| + if ((c == ':' && *p == ']') || p == pend) |
| + break; |
| + if (c1 < CHAR_CLASS_MAX_LENGTH) |
| + str[c1++] = c; |
| + else |
| + /* This is in any case an invalid class name. */ |
| + str[0] = '\0'; |
| + } |
| + str[c1] = '\0'; |
| + |
| + /* If isn't a word bracketed by `[:' and `:]': |
| + undo the ending character, the letters, and leave |
| + the leading `:' and `[' (but store them as character). */ |
| + if (c == ':' && *p == ']') |
| + { |
| + wctype_t wt; |
| + uintptr_t alignedp; |
| + |
| + /* Query the character class as wctype_t. */ |
| + wt = IS_CHAR_CLASS (str); |
| + if (wt == 0) |
| + FREE_STACK_RETURN (REG_ECTYPE); |
| + |
| + /* Throw away the ] at the end of the character |
| + class. */ |
| + PATFETCH (c); |
| + |
| + if (p == pend) FREE_STACK_RETURN (REG_EBRACK); |
| + |
| + /* Allocate the space for character class. */ |
| + GET_BUFFER_SPACE(CHAR_CLASS_SIZE); |
| + /* Update the pointer to indicate end of buffer. */ |
| + b += CHAR_CLASS_SIZE; |
| + /* Move data which follow character classes |
| + not to violate the data. */ |
| + insert_space(CHAR_CLASS_SIZE, |
| + laststart + 6 + laststart[1], |
| + b - 1); |
| + alignedp = ((uintptr_t)(laststart + 6 + laststart[1]) |
| + + __alignof__(wctype_t) - 1) |
| + & ~(uintptr_t)(__alignof__(wctype_t) - 1); |
| + /* Store the character class. */ |
| + *((wctype_t*)alignedp) = wt; |
| + /* Update length of char_classes */ |
| + laststart[1] += CHAR_CLASS_SIZE; |
| + |
| + had_char_class = true; |
| + } |
| + else |
| + { |
| + c1++; |
| + while (c1--) |
| + PATUNFETCH; |
| + BUF_PUSH ('['); |
| + BUF_PUSH (':'); |
| + laststart[5] += 2; /* Update the length of characters */ |
| + range_start = ':'; |
| + had_char_class = false; |
| + } |
| + } |
| + else if (syntax & RE_CHAR_CLASSES && c == '[' && (*p == '=' |
| + || *p == '.')) |
| + { |
| + CHAR_T str[128]; /* Should be large enough. */ |
| + CHAR_T delim = *p; /* '=' or '.' */ |
| +# ifdef _LIBC |
| + uint32_t nrules = |
| + _NL_CURRENT_WORD (LC_COLLATE, _NL_COLLATE_NRULES); |
| +# endif |
| + PATFETCH (c); |
| + c1 = 0; |
| + |
| + /* If pattern is `[[=' or '[[.'. */ |
| + if (p == pend) FREE_STACK_RETURN (REG_EBRACK); |
| + |
| + for (;;) |
| + { |
| + PATFETCH (c); |
| + if ((c == delim && *p == ']') || p == pend) |
| + break; |
| + if (c1 < sizeof (str) - 1) |
| + str[c1++] = c; |
| + else |
| + /* This is in any case an invalid class name. */ |
| + str[0] = '\0'; |
| + } |
| + str[c1] = '\0'; |
| + |
| + if (c == delim && *p == ']' && str[0] != '\0') |
| + { |
| + unsigned int i, offset; |
| + /* If we have no collation data we use the default |
| + collation in which each character is in a class |
| + by itself. It also means that ASCII is the |
| + character set and therefore we cannot have character |
| + with more than one byte in the multibyte |
| + representation. */ |
| + |
| + /* If not defined _LIBC, we push the name and |
| + `\0' for the sake of matching performance. */ |
| + int datasize = c1 + 1; |
| + |
| +# ifdef _LIBC |
| + int32_t idx = 0; |
| + if (nrules == 0) |
| +# endif |
| + { |
| + if (c1 != 1) |
| + FREE_STACK_RETURN (REG_ECOLLATE); |
| + } |
| +# ifdef _LIBC |
| + else |
| + { |
| + const int32_t *table; |
| + const int32_t *weights; |
| + const int32_t *extra; |
| + const int32_t *indirect; |
| + wint_t *cp; |
| + |
| + if(delim == '=') |
| + { |
| + /* We push the index for equivalence class. */ |
| + cp = (wint_t*)str; |
| + |
| + table = (const int32_t *) |
| + _NL_CURRENT (LC_COLLATE, |
| + _NL_COLLATE_TABLEWC); |
| + weights = (const int32_t *) |
| + _NL_CURRENT (LC_COLLATE, |
| + _NL_COLLATE_WEIGHTWC); |
| + extra = (const wint_t *) |
| + _NL_CURRENT (LC_COLLATE, |
| + _NL_COLLATE_EXTRAWC); |
| + indirect = (const int32_t *) |
| + _NL_CURRENT (LC_COLLATE, |
| + _NL_COLLATE_INDIRECTWC); |
| + |
| + idx = FINDIDX (table, indirect, extra, &cp, 1); |
| + if (idx == 0 || cp < (wint_t*) str + c1) |
| + /* This is no valid character. */ |
| + FREE_STACK_RETURN (REG_ECOLLATE); |
| + |
| + str[0] = (wchar_t)idx; |
| + } |
| + else /* delim == '.' */ |
| + { |
| + /* We push collation sequence value |
| + for collating symbol. */ |
| + int32_t table_size; |
| + const int32_t *symb_table; |
| + const unsigned char *extra; |
| + int32_t idx; |
| + int32_t elem; |
| + int32_t second; |
| + int32_t hash; |
| + char char_str[c1]; |
| + |
| + /* We have to convert the name to a single-byte |
| + string. This is possible since the names |
| + consist of ASCII characters and the internal |
| + representation is UCS4. */ |
| + for (i = 0; i < c1; ++i) |
| + char_str[i] = str[i]; |
| + |
| + table_size = |
| + _NL_CURRENT_WORD (LC_COLLATE, |
| + _NL_COLLATE_SYMB_HASH_SIZEMB); |
| + symb_table = (const int32_t *) |
| + _NL_CURRENT (LC_COLLATE, |
| + _NL_COLLATE_SYMB_TABLEMB); |
| + extra = (const unsigned char *) |
| + _NL_CURRENT (LC_COLLATE, |
| + _NL_COLLATE_SYMB_EXTRAMB); |
| + |
| + /* Locate the character in the hashing table. */ |
| + hash = elem_hash (char_str, c1); |
| + |
| + idx = 0; |
| + elem = hash % table_size; |
| + second = hash % (table_size - 2); |
| + while (symb_table[2 * elem] != 0) |
| + { |
| + /* First compare the hashing value. */ |
| + if (symb_table[2 * elem] == hash |
| + && c1 == extra[symb_table[2 * elem + 1]] |
| + && memcmp (char_str, |
| + &extra[symb_table[2 * elem + 1] |
| + + 1], c1) == 0) |
| + { |
| + /* Yep, this is the entry. */ |
| + idx = symb_table[2 * elem + 1]; |
| + idx += 1 + extra[idx]; |
| + break; |
| + } |
| + |
| + /* Next entry. */ |
| + elem += second; |
| + } |
| + |
| + if (symb_table[2 * elem] != 0) |
| + { |
| + /* Compute the index of the byte sequence |
| + in the table. */ |
| + idx += 1 + extra[idx]; |
| + /* Adjust for the alignment. */ |
| + idx = (idx + 3) & ~3; |
| + |
| + str[0] = (wchar_t) idx + 4; |
| + } |
| + else if (symb_table[2 * elem] == 0 && c1 == 1) |
| + { |
| + /* No valid character. Match it as a |
| + single byte character. */ |
| + had_char_class = false; |
| + BUF_PUSH(str[0]); |
| + /* Update the length of characters */ |
| + laststart[5]++; |
| + range_start = str[0]; |
| + |
| + /* Throw away the ] at the end of the |
| + collating symbol. */ |
| + PATFETCH (c); |
| + /* exit from the switch block. */ |
| + continue; |
| + } |
| + else |
| + FREE_STACK_RETURN (REG_ECOLLATE); |
| + } |
| + datasize = 1; |
| + } |
| +# endif |
| + /* Throw away the ] at the end of the equivalence |
| + class (or collating symbol). */ |
| + PATFETCH (c); |
| + |
| + /* Allocate the space for the equivalence class |
| + (or collating symbol) (and '\0' if needed). */ |
| + GET_BUFFER_SPACE(datasize); |
| + /* Update the pointer to indicate end of buffer. */ |
| + b += datasize; |
| + |
| + if (delim == '=') |
| + { /* equivalence class */ |
| + /* Calculate the offset of char_ranges, |
| + which is next to equivalence_classes. */ |
| + offset = laststart[1] + laststart[2] |
| + + laststart[3] +6; |
| + /* Insert space. */ |
| + insert_space(datasize, laststart + offset, b - 1); |
| + |
| + /* Write the equivalence_class and \0. */ |
| + for (i = 0 ; i < datasize ; i++) |
| + laststart[offset + i] = str[i]; |
| + |
| + /* Update the length of equivalence_classes. */ |
| + laststart[3] += datasize; |
| + had_char_class = true; |
| + } |
| + else /* delim == '.' */ |
| + { /* collating symbol */ |
| + /* Calculate the offset of the equivalence_classes, |
| + which is next to collating_symbols. */ |
| + offset = laststart[1] + laststart[2] + 6; |
| + /* Insert space and write the collationg_symbol |
| + and \0. */ |
| + insert_space(datasize, laststart + offset, b-1); |
| + for (i = 0 ; i < datasize ; i++) |
| + laststart[offset + i] = str[i]; |
| + |
| + /* In re_match_2_internal if range_start < -1, we |
| + assume -range_start is the offset of the |
| + collating symbol which is specified as |
| + the character of the range start. So we assign |
| + -(laststart[1] + laststart[2] + 6) to |
| + range_start. */ |
| + range_start = -(laststart[1] + laststart[2] + 6); |
| + /* Update the length of collating_symbol. */ |
| + laststart[2] += datasize; |
| + had_char_class = false; |
| + } |
| + } |
| + else |
| + { |
| + c1++; |
| + while (c1--) |
| + PATUNFETCH; |
| + BUF_PUSH ('['); |
| + BUF_PUSH (delim); |
| + laststart[5] += 2; /* Update the length of characters */ |
| + range_start = delim; |
| + had_char_class = false; |
| + } |
| + } |
| + else |
| + { |
| + had_char_class = false; |
| + BUF_PUSH(c); |
| + laststart[5]++; /* Update the length of characters */ |
| + range_start = c; |
| + } |
| + } |
| + |
| +#else /* BYTE */ |
| + /* Ensure that we have enough space to push a charset: the |
| + opcode, the length count, and the bitset; 34 bytes in all. */ |
| + GET_BUFFER_SPACE (34); |
| + |
| + laststart = b; |
| + |
| + /* We test `*p == '^' twice, instead of using an if |
| + statement, so we only need one BUF_PUSH. */ |
| + BUF_PUSH (*p == '^' ? charset_not : charset); |
| + if (*p == '^') |
| + p++; |
| + |
| + /* Remember the first position in the bracket expression. */ |
| + p1 = p; |
| + |
| + /* Push the number of bytes in the bitmap. */ |
| + BUF_PUSH ((1 << BYTEWIDTH) / BYTEWIDTH); |
| + |
| + /* Clear the whole map. */ |
| + bzero (b, (1 << BYTEWIDTH) / BYTEWIDTH); |
| + |
| + /* charset_not matches newline according to a syntax bit. */ |
| + if ((re_opcode_t) b[-2] == charset_not |
| + && (syntax & RE_HAT_LISTS_NOT_NEWLINE)) |
| + SET_LIST_BIT ('\n'); |
| + |
| + /* Read in characters and ranges, setting map bits. */ |
| + for (;;) |
| + { |
| + if (p == pend) FREE_STACK_RETURN (REG_EBRACK); |
| + |
| + PATFETCH (c); |
| + |
| + /* \ might escape characters inside [...] and [^...]. */ |
| + if ((syntax & RE_BACKSLASH_ESCAPE_IN_LISTS) && c == '\\') |
| + { |
| + if (p == pend) FREE_STACK_RETURN (REG_EESCAPE); |
| + |
| + PATFETCH (c1); |
| + SET_LIST_BIT (c1); |
| + range_start = c1; |
| + continue; |
| + } |
| + |
| + /* Could be the end of the bracket expression. If it's |
| + not (i.e., when the bracket expression is `[]' so |
| + far), the ']' character bit gets set way below. */ |
| + if (c == ']' && p != p1 + 1) |
| + break; |
| + |
| + /* Look ahead to see if it's a range when the last thing |
| + was a character class. */ |
| + if (had_char_class && c == '-' && *p != ']') |
| + FREE_STACK_RETURN (REG_ERANGE); |
| + |
| + /* Look ahead to see if it's a range when the last thing |
| + was a character: if this is a hyphen not at the |
| + beginning or the end of a list, then it's the range |
| + operator. */ |
| + if (c == '-' |
| + && !(p - 2 >= pattern && p[-2] == '[') |
| + && !(p - 3 >= pattern && p[-3] == '[' && p[-2] == '^') |
| + && *p != ']') |
| + { |
| + reg_errcode_t ret |
| + = byte_compile_range (range_start, &p, pend, translate, |
| + syntax, b); |
| + if (ret != REG_NOERROR) FREE_STACK_RETURN (ret); |
| + range_start = 0xffffffff; |
| + } |
| + |
| + else if (p[0] == '-' && p[1] != ']') |
| + { /* This handles ranges made up of characters only. */ |
| + reg_errcode_t ret; |
| + |
| + /* Move past the `-'. */ |
| + PATFETCH (c1); |
| + |
| + ret = byte_compile_range (c, &p, pend, translate, syntax, b); |
| + if (ret != REG_NOERROR) FREE_STACK_RETURN (ret); |
| + range_start = 0xffffffff; |
| + } |
| + |
| + /* See if we're at the beginning of a possible character |
| + class. */ |
| + |
| + else if (syntax & RE_CHAR_CLASSES && c == '[' && *p == ':') |
| + { /* Leave room for the null. */ |
| + char str[CHAR_CLASS_MAX_LENGTH + 1]; |
| + |
| + PATFETCH (c); |
| + c1 = 0; |
| + |
| + /* If pattern is `[[:'. */ |
| + if (p == pend) FREE_STACK_RETURN (REG_EBRACK); |
| + |
| + for (;;) |
| + { |
| + PATFETCH (c); |
| + if ((c == ':' && *p == ']') || p == pend) |
| + break; |
| + if (((int) c1) < CHAR_CLASS_MAX_LENGTH) |
| + str[c1++] = c; |
| + else |
| + /* This is in any case an invalid class name. */ |
| + str[0] = '\0'; |
| + } |
| + str[c1] = '\0'; |
| + |
| + /* If isn't a word bracketed by `[:' and `:]': |
| + undo the ending character, the letters, and leave |
| + the leading `:' and `[' (but set bits for them). */ |
| + if (c == ':' && *p == ']') |
| + { |
| +# if WIDE_CHAR_SUPPORT |
| + boolean is_lower = STREQ (str, "lower"); |
| + boolean is_upper = STREQ (str, "upper"); |
| + wctype_t wt; |
| + int ch; |
| + |
| + wt = IS_CHAR_CLASS (str); |
| + if (wt == 0) |
| + FREE_STACK_RETURN (REG_ECTYPE); |
| + |
| + /* Throw away the ] at the end of the character |
| + class. */ |
| + PATFETCH (c); |
| + |
| + if (p == pend) FREE_STACK_RETURN (REG_EBRACK); |
| + |
| + for (ch = 0; ch < 1 << BYTEWIDTH; ++ch) |
| + { |
| +# ifdef _LIBC |
| + if (__iswctype (__btowc (ch), wt)) |
| + SET_LIST_BIT (ch); |
| +# else |
| + if (iswctype (btowc (ch), wt)) |
| + SET_LIST_BIT (ch); |
| +# endif |
| + |
| + if (translate && (is_upper || is_lower) |
| + && (ISUPPER (ch) || ISLOWER (ch))) |
| + SET_LIST_BIT (ch); |
| + } |
| + |
| + had_char_class = true; |
| +# else |
| + int ch; |
| + boolean is_alnum = STREQ (str, "alnum"); |
| + boolean is_alpha = STREQ (str, "alpha"); |
| + boolean is_blank = STREQ (str, "blank"); |
| + boolean is_cntrl = STREQ (str, "cntrl"); |
| + boolean is_digit = STREQ (str, "digit"); |
| + boolean is_graph = STREQ (str, "graph"); |
| + boolean is_lower = STREQ (str, "lower"); |
| + boolean is_print = STREQ (str, "print"); |
| + boolean is_punct = STREQ (str, "punct"); |
| + boolean is_space = STREQ (str, "space"); |
| + boolean is_upper = STREQ (str, "upper"); |
| + boolean is_xdigit = STREQ (str, "xdigit"); |
| + |
| + if (!IS_CHAR_CLASS (str)) |
| + FREE_STACK_RETURN (REG_ECTYPE); |
| + |
| + /* Throw away the ] at the end of the character |
| + class. */ |
| + PATFETCH (c); |
| + |
| + if (p == pend) FREE_STACK_RETURN (REG_EBRACK); |
| + |
| + for (ch = 0; ch < 1 << BYTEWIDTH; ch++) |
| + { |
| + /* This was split into 3 if's to |
| + avoid an arbitrary limit in some compiler. */ |
| + if ( (is_alnum && ISALNUM (ch)) |
| + || (is_alpha && ISALPHA (ch)) |
| + || (is_blank && ISBLANK (ch)) |
| + || (is_cntrl && ISCNTRL (ch))) |
| + SET_LIST_BIT (ch); |
| + if ( (is_digit && ISDIGIT (ch)) |
| + || (is_graph && ISGRAPH (ch)) |
| + || (is_lower && ISLOWER (ch)) |
| + || (is_print && ISPRINT (ch))) |
| + SET_LIST_BIT (ch); |
| + if ( (is_punct && ISPUNCT (ch)) |
| + || (is_space && ISSPACE (ch)) |
| + || (is_upper && ISUPPER (ch)) |
| + || (is_xdigit && ISXDIGIT (ch))) |
| + SET_LIST_BIT (ch); |
| + if ( translate && (is_upper || is_lower) |
| + && (ISUPPER (ch) || ISLOWER (ch))) |
| + SET_LIST_BIT (ch); |
| + } |
| + had_char_class = true; |
| +# endif /* libc || wctype.h */ |
| + } |
| + else |
| + { |
| + c1++; |
| + while (c1--) |
| + PATUNFETCH; |
| + SET_LIST_BIT ('['); |
| + SET_LIST_BIT (':'); |
| + range_start = ':'; |
| + had_char_class = false; |
| + } |
| + } |
| + else if (syntax & RE_CHAR_CLASSES && c == '[' && *p == '=') |
| + { |
| + unsigned char str[MB_LEN_MAX + 1]; |
| +# ifdef _LIBC |
| + uint32_t nrules = |
| + _NL_CURRENT_WORD (LC_COLLATE, _NL_COLLATE_NRULES); |
| +# endif |
| + |
| + PATFETCH (c); |
| + c1 = 0; |
| + |
| + /* If pattern is `[[='. */ |
| + if (p == pend) FREE_STACK_RETURN (REG_EBRACK); |
| + |
| + for (;;) |
| + { |
| + PATFETCH (c); |
| + if ((c == '=' && *p == ']') || p == pend) |
| + break; |
| + if (c1 < MB_LEN_MAX) |
| + str[c1++] = c; |
| + else |
| + /* This is in any case an invalid class name. */ |
| + str[0] = '\0'; |
| + } |
| + str[c1] = '\0'; |
| + |
| + if (c == '=' && *p == ']' && str[0] != '\0') |
| + { |
| + /* If we have no collation data we use the default |
| + collation in which each character is in a class |
| + by itself. It also means that ASCII is the |
| + character set and therefore we cannot have character |
| + with more than one byte in the multibyte |
| + representation. */ |
| +# ifdef _LIBC |
| + if (nrules == 0) |
| +# endif |
| + { |
| + if (c1 != 1) |
| + FREE_STACK_RETURN (REG_ECOLLATE); |
| + |
| + /* Throw away the ] at the end of the equivalence |
| + class. */ |
| + PATFETCH (c); |
| + |
| + /* Set the bit for the character. */ |
| + SET_LIST_BIT (str[0]); |
| + } |
| +# ifdef _LIBC |
| + else |
| + { |
| + /* Try to match the byte sequence in `str' against |
| + those known to the collate implementation. |
| + First find out whether the bytes in `str' are |
| + actually from exactly one character. */ |
| + const int32_t *table; |
| + const unsigned char *weights; |
| + const unsigned char *extra; |
| + const int32_t *indirect; |
| + int32_t idx; |
| + const unsigned char *cp = str; |
| + int ch; |
| + |
| + table = (const int32_t *) |
| + _NL_CURRENT (LC_COLLATE, _NL_COLLATE_TABLEMB); |
| + weights = (const unsigned char *) |
| + _NL_CURRENT (LC_COLLATE, _NL_COLLATE_WEIGHTMB); |
| + extra = (const unsigned char *) |
| + _NL_CURRENT (LC_COLLATE, _NL_COLLATE_EXTRAMB); |
| + indirect = (const int32_t *) |
| + _NL_CURRENT (LC_COLLATE, _NL_COLLATE_INDIRECTMB); |
| + idx = FINDIDX (table, indirect, extra, &cp, 1); |
| + if (idx == 0 || cp < str + c1) |
| + /* This is no valid character. */ |
| + FREE_STACK_RETURN (REG_ECOLLATE); |
| + |
| + /* Throw away the ] at the end of the equivalence |
| + class. */ |
| + PATFETCH (c); |
| + |
| + /* Now we have to go throught the whole table |
| + and find all characters which have the same |
| + first level weight. |
| + |
| + XXX Note that this is not entirely correct. |
| + we would have to match multibyte sequences |
| + but this is not possible with the current |
| + implementation. */ |
| + for (ch = 1; ch < 256; ++ch) |
| + /* XXX This test would have to be changed if we |
| + would allow matching multibyte sequences. */ |
| + if (table[ch] > 0) |
| + { |
| + int32_t idx2 = table[ch]; |
| + size_t len = weights[idx2]; |
| + |
| + /* Test whether the lenghts match. */ |
| + if (weights[idx] == len) |
| + { |
| + /* They do. New compare the bytes of |
| + the weight. */ |
| + size_t cnt = 0; |
| + |
| + while (cnt < len |
| + && (weights[idx + 1 + cnt] |
| + == weights[idx2 + 1 + cnt])) |
| + ++cnt; |
| + |
| + if (cnt == len) |
| + /* They match. Mark the character as |
| + acceptable. */ |
| + SET_LIST_BIT (ch); |
| + } |
| + } |
| + } |
| +# endif |
| + had_char_class = true; |
| + } |
| + else |
| + { |
| + c1++; |
| + while (c1--) |
| + PATUNFETCH; |
| + SET_LIST_BIT ('['); |
| + SET_LIST_BIT ('='); |
| + range_start = '='; |
| + had_char_class = false; |
| + } |
| + } |
| + else if (syntax & RE_CHAR_CLASSES && c == '[' && *p == '.') |
| + { |
| + unsigned char str[128]; /* Should be large enough. */ |
| +# ifdef _LIBC |
| + uint32_t nrules = |
| + _NL_CURRENT_WORD (LC_COLLATE, _NL_COLLATE_NRULES); |
| +# endif |
| + |
| + PATFETCH (c); |
| + c1 = 0; |
| + |
| + /* If pattern is `[[.'. */ |
| + if (p == pend) FREE_STACK_RETURN (REG_EBRACK); |
| + |
| + for (;;) |
| + { |
| + PATFETCH (c); |
| + if ((c == '.' && *p == ']') || p == pend) |
| + break; |
| + if (c1 < sizeof (str)) |
| + str[c1++] = c; |
| + else |
| + /* This is in any case an invalid class name. */ |
| + str[0] = '\0'; |
| + } |
| + str[c1] = '\0'; |
| + |
| + if (c == '.' && *p == ']' && str[0] != '\0') |
| + { |
| + /* If we have no collation data we use the default |
| + collation in which each character is the name |
| + for its own class which contains only the one |
| + character. It also means that ASCII is the |
| + character set and therefore we cannot have character |
| + with more than one byte in the multibyte |
| + representation. */ |
| +# ifdef _LIBC |
| + if (nrules == 0) |
| +# endif |
| + { |
| + if (c1 != 1) |
| + FREE_STACK_RETURN (REG_ECOLLATE); |
| + |
| + /* Throw away the ] at the end of the equivalence |
| + class. */ |
| + PATFETCH (c); |
| + |
| + /* Set the bit for the character. */ |
| + SET_LIST_BIT (str[0]); |
| + range_start = ((const unsigned char *) str)[0]; |
| + } |
| +# ifdef _LIBC |
| + else |
| + { |
| + /* Try to match the byte sequence in `str' against |
| + those known to the collate implementation. |
| + First find out whether the bytes in `str' are |
| + actually from exactly one character. */ |
| + int32_t table_size; |
| + const int32_t *symb_table; |
| + const unsigned char *extra; |
| + int32_t idx; |
| + int32_t elem; |
| + int32_t second; |
| + int32_t hash; |
| + |
| + table_size = |
| + _NL_CURRENT_WORD (LC_COLLATE, |
| + _NL_COLLATE_SYMB_HASH_SIZEMB); |
| + symb_table = (const int32_t *) |
| + _NL_CURRENT (LC_COLLATE, |
| + _NL_COLLATE_SYMB_TABLEMB); |
| + extra = (const unsigned char *) |
| + _NL_CURRENT (LC_COLLATE, |
| + _NL_COLLATE_SYMB_EXTRAMB); |
| + |
| + /* Locate the character in the hashing table. */ |
| + hash = elem_hash ((const char *) str, c1); |
| + |
| + idx = 0; |
| + elem = hash % table_size; |
| + second = hash % (table_size - 2); |
| + while (symb_table[2 * elem] != 0) |
| + { |
| + /* First compare the hashing value. */ |
| + if (symb_table[2 * elem] == hash |
| + && c1 == extra[symb_table[2 * elem + 1]] |
| + && memcmp (str, |
| + &extra[symb_table[2 * elem + 1] |
| + + 1], |
| + c1) == 0) |
| + { |
| + /* Yep, this is the entry. */ |
| + idx = symb_table[2 * elem + 1]; |
| + idx += 1 + extra[idx]; |
| + break; |
| + } |
| + |
| + /* Next entry. */ |
| + elem += second; |
| + } |
| + |
| + if (symb_table[2 * elem] == 0) |
| + /* This is no valid character. */ |
| + FREE_STACK_RETURN (REG_ECOLLATE); |
| + |
| + /* Throw away the ] at the end of the equivalence |
| + class. */ |
| + PATFETCH (c); |
| + |
| + /* Now add the multibyte character(s) we found |
| + to the accept list. |
| + |
| + XXX Note that this is not entirely correct. |
| + we would have to match multibyte sequences |
| + but this is not possible with the current |
| + implementation. Also, we have to match |
| + collating symbols, which expand to more than |
| + one file, as a whole and not allow the |
| + individual bytes. */ |
| + c1 = extra[idx++]; |
| + if (c1 == 1) |
| + range_start = extra[idx]; |
| + while (c1-- > 0) |
| + { |
| + SET_LIST_BIT (extra[idx]); |
| + ++idx; |
| + } |
| + } |
| +# endif |
| + had_char_class = false; |
| + } |
| + else |
| + { |
| + c1++; |
| + while (c1--) |
| + PATUNFETCH; |
| + SET_LIST_BIT ('['); |
| + SET_LIST_BIT ('.'); |
| + range_start = '.'; |
| + had_char_class = false; |
| + } |
| + } |
| + else |
| + { |
| + had_char_class = false; |
| + SET_LIST_BIT (c); |
| + range_start = c; |
| + } |
| + } |
| + |
| + /* Discard any (non)matching list bytes that are all 0 at the |
| + end of the map. Decrease the map-length byte too. */ |
| + while ((int) b[-1] > 0 && b[b[-1] - 1] == 0) |
| + b[-1]--; |
| + b += b[-1]; |
| +#endif /* WCHAR */ |
| + } |
| + break; |
| + |
| + |
| + case '(': |
| + if (syntax & RE_NO_BK_PARENS) |
| + goto handle_open; |
| + else |
| + goto normal_char; |
| + |
| + |
| + case ')': |
| + if (syntax & RE_NO_BK_PARENS) |
| + goto handle_close; |
| + else |
| + goto normal_char; |
| + |
| + |
| + case '\n': |
| + if (syntax & RE_NEWLINE_ALT) |
| + goto handle_alt; |
| + else |
| + goto normal_char; |
| + |
| + |
| + case '|': |
| + if (syntax & RE_NO_BK_VBAR) |
| + goto handle_alt; |
| + else |
| + goto normal_char; |
| + |
| + |
| + case '{': |
| + if (syntax & RE_INTERVALS && syntax & RE_NO_BK_BRACES) |
| + goto handle_interval; |
| + else |
| + goto normal_char; |
| + |
| + |
| + case '\\': |
| + if (p == pend) FREE_STACK_RETURN (REG_EESCAPE); |
| + |
| + /* Do not translate the character after the \, so that we can |
| + distinguish, e.g., \B from \b, even if we normally would |
| + translate, e.g., B to b. */ |
| + PATFETCH_RAW (c); |
| + |
| + switch (c) |
| + { |
| + case '(': |
| + if (syntax & RE_NO_BK_PARENS) |
| + goto normal_backslash; |
| + |
| + handle_open: |
| + bufp->re_nsub++; |
| + regnum++; |
| + |
| + if (COMPILE_STACK_FULL) |
| + { |
| + RETALLOC (compile_stack.stack, compile_stack.size << 1, |
| + compile_stack_elt_t); |
| + if (compile_stack.stack == NULL) return REG_ESPACE; |
| + |
| + compile_stack.size <<= 1; |
| + } |
| + |
| + /* These are the values to restore when we hit end of this |
| + group. They are all relative offsets, so that if the |
| + whole pattern moves because of realloc, they will still |
| + be valid. */ |
| + COMPILE_STACK_TOP.begalt_offset = begalt - COMPILED_BUFFER_VAR; |
| + COMPILE_STACK_TOP.fixup_alt_jump |
| + = fixup_alt_jump ? fixup_alt_jump - COMPILED_BUFFER_VAR + 1 : 0; |
| + COMPILE_STACK_TOP.laststart_offset = b - COMPILED_BUFFER_VAR; |
| + COMPILE_STACK_TOP.regnum = regnum; |
| + |
| + /* We will eventually replace the 0 with the number of |
| + groups inner to this one. But do not push a |
| + start_memory for groups beyond the last one we can |
| + represent in the compiled pattern. */ |
| + if (regnum <= MAX_REGNUM) |
| + { |
| + COMPILE_STACK_TOP.inner_group_offset = b |
| + - COMPILED_BUFFER_VAR + 2; |
| + BUF_PUSH_3 (start_memory, regnum, 0); |
| + } |
| + |
| + compile_stack.avail++; |
| + |
| + fixup_alt_jump = 0; |
| + laststart = 0; |
| + begalt = b; |
| + /* If we've reached MAX_REGNUM groups, then this open |
| + won't actually generate any code, so we'll have to |
| + clear pending_exact explicitly. */ |
| + pending_exact = 0; |
| + break; |
| + |
| + |
| + case ')': |
| + if (syntax & RE_NO_BK_PARENS) goto normal_backslash; |
| + |
| + if (COMPILE_STACK_EMPTY) |
| + { |
| + if (syntax & RE_UNMATCHED_RIGHT_PAREN_ORD) |
| + goto normal_backslash; |
| + else |
| + FREE_STACK_RETURN (REG_ERPAREN); |
| + } |
| + |
| + handle_close: |
| + if (fixup_alt_jump) |
| + { /* Push a dummy failure point at the end of the |
| + alternative for a possible future |
| + `pop_failure_jump' to pop. See comments at |
| + `push_dummy_failure' in `re_match_2'. */ |
| + BUF_PUSH (push_dummy_failure); |
| + |
| + /* We allocated space for this jump when we assigned |
| + to `fixup_alt_jump', in the `handle_alt' case below. */ |
| + STORE_JUMP (jump_past_alt, fixup_alt_jump, b - 1); |
| + } |
| + |
| + /* See similar code for backslashed left paren above. */ |
| + if (COMPILE_STACK_EMPTY) |
| + { |
| + if (syntax & RE_UNMATCHED_RIGHT_PAREN_ORD) |
| + goto normal_char; |
| + else |
| + FREE_STACK_RETURN (REG_ERPAREN); |
| + } |
| + |
| + /* Since we just checked for an empty stack above, this |
| + ``can't happen''. */ |
| + assert (compile_stack.avail != 0); |
| + { |
| + /* We don't just want to restore into `regnum', because |
| + later groups should continue to be numbered higher, |
| + as in `(ab)c(de)' -- the second group is #2. */ |
| + regnum_t this_group_regnum; |
| + |
| + compile_stack.avail--; |
| + begalt = COMPILED_BUFFER_VAR + COMPILE_STACK_TOP.begalt_offset; |
| + fixup_alt_jump |
| + = COMPILE_STACK_TOP.fixup_alt_jump |
| + ? COMPILED_BUFFER_VAR + COMPILE_STACK_TOP.fixup_alt_jump - 1 |
| + : 0; |
| + laststart = COMPILED_BUFFER_VAR + COMPILE_STACK_TOP.laststart_offset; |
| + this_group_regnum = COMPILE_STACK_TOP.regnum; |
| + /* If we've reached MAX_REGNUM groups, then this open |
| + won't actually generate any code, so we'll have to |
| + clear pending_exact explicitly. */ |
| + pending_exact = 0; |
| + |
| + /* We're at the end of the group, so now we know how many |
| + groups were inside this one. */ |
| + if (this_group_regnum <= MAX_REGNUM) |
| + { |
| + UCHAR_T *inner_group_loc |
| + = COMPILED_BUFFER_VAR + COMPILE_STACK_TOP.inner_group_offset; |
| + |
| + *inner_group_loc = regnum - this_group_regnum; |
| + BUF_PUSH_3 (stop_memory, this_group_regnum, |
| + regnum - this_group_regnum); |
| + } |
| + } |
| + break; |
| + |
| + |
| + case '|': /* `\|'. */ |
| + if (syntax & RE_LIMITED_OPS || syntax & RE_NO_BK_VBAR) |
| + goto normal_backslash; |
| + handle_alt: |
| + if (syntax & RE_LIMITED_OPS) |
| + goto normal_char; |
| + |
| + /* Insert before the previous alternative a jump which |
| + jumps to this alternative if the former fails. */ |
| + GET_BUFFER_SPACE (1 + OFFSET_ADDRESS_SIZE); |
| + INSERT_JUMP (on_failure_jump, begalt, |
| + b + 2 + 2 * OFFSET_ADDRESS_SIZE); |
| + pending_exact = 0; |
| + b += 1 + OFFSET_ADDRESS_SIZE; |
| + |
| + /* The alternative before this one has a jump after it |
| + which gets executed if it gets matched. Adjust that |
| + jump so it will jump to this alternative's analogous |
| + jump (put in below, which in turn will jump to the next |
| + (if any) alternative's such jump, etc.). The last such |
| + jump jumps to the correct final destination. A picture: |
| + _____ _____ |
| + | | | | |
| + | v | v |
| + a | b | c |
| + |
| + If we are at `b', then fixup_alt_jump right now points to a |
| + three-byte space after `a'. We'll put in the jump, set |
| + fixup_alt_jump to right after `b', and leave behind three |
| + bytes which we'll fill in when we get to after `c'. */ |
| + |
| + if (fixup_alt_jump) |
| + STORE_JUMP (jump_past_alt, fixup_alt_jump, b); |
| + |
| + /* Mark and leave space for a jump after this alternative, |
| + to be filled in later either by next alternative or |
| + when know we're at the end of a series of alternatives. */ |
| + fixup_alt_jump = b; |
| + GET_BUFFER_SPACE (1 + OFFSET_ADDRESS_SIZE); |
| + b += 1 + OFFSET_ADDRESS_SIZE; |
| + |
| + laststart = 0; |
| + begalt = b; |
| + break; |
| + |
| + |
| + case '{': |
| + /* If \{ is a literal. */ |
| + if (!(syntax & RE_INTERVALS) |
| + /* If we're at `\{' and it's not the open-interval |
| + operator. */ |
| + || (syntax & RE_NO_BK_BRACES)) |
| + goto normal_backslash; |
| + |
| + handle_interval: |
| + { |
| + /* If got here, then the syntax allows intervals. */ |
| + |
| + /* At least (most) this many matches must be made. */ |
| + int lower_bound = -1, upper_bound = -1; |
| + |
| + /* Place in the uncompiled pattern (i.e., just after |
| + the '{') to go back to if the interval is invalid. */ |
| + const CHAR_T *beg_interval = p; |
| + |
| + if (p == pend) |
| + goto invalid_interval; |
| + |
| + GET_UNSIGNED_NUMBER (lower_bound); |
| + |
| + if (c == ',') |
| + { |
| + GET_UNSIGNED_NUMBER (upper_bound); |
| + if (upper_bound < 0) |
| + upper_bound = RE_DUP_MAX; |
| + } |
| + else |
| + /* Interval such as `{1}' => match exactly once. */ |
| + upper_bound = lower_bound; |
| + |
| + if (! (0 <= lower_bound && lower_bound <= upper_bound)) |
| + goto invalid_interval; |
| + |
| + if (!(syntax & RE_NO_BK_BRACES)) |
| + { |
| + if (c != '\\' || p == pend) |
| + goto invalid_interval; |
| + PATFETCH (c); |
| + } |
| + |
| + if (c != '}') |
| + goto invalid_interval; |
| + |
| + /* If it's invalid to have no preceding re. */ |
| + if (!laststart) |
| + { |
| + if (syntax & RE_CONTEXT_INVALID_OPS |
| + && !(syntax & RE_INVALID_INTERVAL_ORD)) |
| + FREE_STACK_RETURN (REG_BADRPT); |
| + else if (syntax & RE_CONTEXT_INDEP_OPS) |
| + laststart = b; |
| + else |
| + goto unfetch_interval; |
| + } |
| + |
| + /* We just parsed a valid interval. */ |
| + |
| + if (RE_DUP_MAX < upper_bound) |
| + FREE_STACK_RETURN (REG_BADBR); |
| + |
| + /* If the upper bound is zero, don't want to succeed at |
| + all; jump from `laststart' to `b + 3', which will be |
| + the end of the buffer after we insert the jump. */ |
| + /* ifdef WCHAR, 'b + 1 + OFFSET_ADDRESS_SIZE' |
| + instead of 'b + 3'. */ |
| + if (upper_bound == 0) |
| + { |
| + GET_BUFFER_SPACE (1 + OFFSET_ADDRESS_SIZE); |
| + INSERT_JUMP (jump, laststart, b + 1 |
| + + OFFSET_ADDRESS_SIZE); |
| + b += 1 + OFFSET_ADDRESS_SIZE; |
| + } |
| + |
| + /* Otherwise, we have a nontrivial interval. When |
| + we're all done, the pattern will look like: |
| + set_number_at <jump count> <upper bound> |
| + set_number_at <succeed_n count> <lower bound> |
| + succeed_n <after jump addr> <succeed_n count> |
| + <body of loop> |
| + jump_n <succeed_n addr> <jump count> |
| + (The upper bound and `jump_n' are omitted if |
| + `upper_bound' is 1, though.) */ |
| + else |
| + { /* If the upper bound is > 1, we need to insert |
| + more at the end of the loop. */ |
| + unsigned nbytes = 2 + 4 * OFFSET_ADDRESS_SIZE + |
| + (upper_bound > 1) * (2 + 4 * OFFSET_ADDRESS_SIZE); |
| + |
| + GET_BUFFER_SPACE (nbytes); |
| + |
| + /* Initialize lower bound of the `succeed_n', even |
| + though it will be set during matching by its |
| + attendant `set_number_at' (inserted next), |
| + because `re_compile_fastmap' needs to know. |
| + Jump to the `jump_n' we might insert below. */ |
| + INSERT_JUMP2 (succeed_n, laststart, |
| + b + 1 + 2 * OFFSET_ADDRESS_SIZE |
| + + (upper_bound > 1) * (1 + 2 * OFFSET_ADDRESS_SIZE) |
| + , lower_bound); |
| + b += 1 + 2 * OFFSET_ADDRESS_SIZE; |
| + |
| + /* Code to initialize the lower bound. Insert |
| + before the `succeed_n'. The `5' is the last two |
| + bytes of this `set_number_at', plus 3 bytes of |
| + the following `succeed_n'. */ |
| + /* ifdef WCHAR, The '1+2*OFFSET_ADDRESS_SIZE' |
| + is the 'set_number_at', plus '1+OFFSET_ADDRESS_SIZE' |
| + of the following `succeed_n'. */ |
| + PREFIX(insert_op2) (set_number_at, laststart, 1 |
| + + 2 * OFFSET_ADDRESS_SIZE, lower_bound, b); |
| + b += 1 + 2 * OFFSET_ADDRESS_SIZE; |
| + |
| + if (upper_bound > 1) |
| + { /* More than one repetition is allowed, so |
| + append a backward jump to the `succeed_n' |
| + that starts this interval. |
| + |
| + When we've reached this during matching, |
| + we'll have matched the interval once, so |
| + jump back only `upper_bound - 1' times. */ |
| + STORE_JUMP2 (jump_n, b, laststart |
| + + 2 * OFFSET_ADDRESS_SIZE + 1, |
| + upper_bound - 1); |
| + b += 1 + 2 * OFFSET_ADDRESS_SIZE; |
| + |
| + /* The location we want to set is the second |
| + parameter of the `jump_n'; that is `b-2' as |
| + an absolute address. `laststart' will be |
| + the `set_number_at' we're about to insert; |
| + `laststart+3' the number to set, the source |
| + for the relative address. But we are |
| + inserting into the middle of the pattern -- |
| + so everything is getting moved up by 5. |
| + Conclusion: (b - 2) - (laststart + 3) + 5, |
| + i.e., b - laststart. |
| + |
| + We insert this at the beginning of the loop |
| + so that if we fail during matching, we'll |
| + reinitialize the bounds. */ |
| + PREFIX(insert_op2) (set_number_at, laststart, |
| + b - laststart, |
| + upper_bound - 1, b); |
| + b += 1 + 2 * OFFSET_ADDRESS_SIZE; |
| + } |
| + } |
| + pending_exact = 0; |
| + break; |
| + |
| + invalid_interval: |
| + if (!(syntax & RE_INVALID_INTERVAL_ORD)) |
| + FREE_STACK_RETURN (p == pend ? REG_EBRACE : REG_BADBR); |
| + unfetch_interval: |
| + /* Match the characters as literals. */ |
| + p = beg_interval; |
| + c = '{'; |
| + if (syntax & RE_NO_BK_BRACES) |
| + goto normal_char; |
| + else |
| + goto normal_backslash; |
| + } |
| + |
| +#ifdef emacs |
| + /* There is no way to specify the before_dot and after_dot |
| + operators. rms says this is ok. --karl */ |
| + case '=': |
| + BUF_PUSH (at_dot); |
| + break; |
| + |
| + case 's': |
| + laststart = b; |
| + PATFETCH (c); |
| + BUF_PUSH_2 (syntaxspec, syntax_spec_code[c]); |
| + break; |
| + |
| + case 'S': |
| + laststart = b; |
| + PATFETCH (c); |
| + BUF_PUSH_2 (notsyntaxspec, syntax_spec_code[c]); |
| + break; |
| +#endif /* emacs */ |
| + |
| + |
| + case 'w': |
| + if (syntax & RE_NO_GNU_OPS) |
| + goto normal_char; |
| + laststart = b; |
| + BUF_PUSH (wordchar); |
| + break; |
| + |
| + |
| + case 'W': |
| + if (syntax & RE_NO_GNU_OPS) |
| + goto normal_char; |
| + laststart = b; |
| + BUF_PUSH (notwordchar); |
| + break; |
| + |
| + |
| + case '<': |
| + if (syntax & RE_NO_GNU_OPS) |
| + goto normal_char; |
| + BUF_PUSH (wordbeg); |
| + break; |
| + |
| + case '>': |
| + if (syntax & RE_NO_GNU_OPS) |
| + goto normal_char; |
| + BUF_PUSH (wordend); |
| + break; |
| + |
| + case 'b': |
| + if (syntax & RE_NO_GNU_OPS) |
| + goto normal_char; |
| + BUF_PUSH (wordbound); |
| + break; |
| + |
| + case 'B': |
| + if (syntax & RE_NO_GNU_OPS) |
| + goto normal_char; |
| + BUF_PUSH (notwordbound); |
| + break; |
| + |
| + case '`': |
| + if (syntax & RE_NO_GNU_OPS) |
| + goto normal_char; |
| + BUF_PUSH (begbuf); |
| + break; |
| + |
| + case '\'': |
| + if (syntax & RE_NO_GNU_OPS) |
| + goto normal_char; |
| + BUF_PUSH (endbuf); |
| + break; |
| + |
| + case '1': case '2': case '3': case '4': case '5': |
| + case '6': case '7': case '8': case '9': |
| + if (syntax & RE_NO_BK_REFS) |
| + goto normal_char; |
| + |
| + c1 = c - '0'; |
| + |
| + if (c1 > regnum) |
| + FREE_STACK_RETURN (REG_ESUBREG); |
| + |
| + /* Can't back reference to a subexpression if inside of it. */ |
| + if (group_in_compile_stack (compile_stack, (regnum_t) c1)) |
| + goto normal_char; |
| + |
| + laststart = b; |
| + BUF_PUSH_2 (duplicate, c1); |
| + break; |
| + |
| + |
| + case '+': |
| + case '?': |
| + if (syntax & RE_BK_PLUS_QM) |
| + goto handle_plus; |
| + else |
| + goto normal_backslash; |
| + |
| + default: |
| + normal_backslash: |
| + /* You might think it would be useful for \ to mean |
| + not to translate; but if we don't translate it |
| + it will never match anything. */ |
| + c = TRANSLATE (c); |
| + goto normal_char; |
| + } |
| + break; |
| + |
| + |
| + default: |
| + /* Expects the character in `c'. */ |
| + normal_char: |
| + /* If no exactn currently being built. */ |
| + if (!pending_exact |
| +#ifdef WCHAR |
| + /* If last exactn handle binary(or character) and |
| + new exactn handle character(or binary). */ |
| + || is_exactn_bin != is_binary[p - 1 - pattern] |
| +#endif /* WCHAR */ |
| + |
| + /* If last exactn not at current position. */ |
| + || pending_exact + *pending_exact + 1 != b |
| + |
| + /* We have only one byte following the exactn for the count. */ |
| + || *pending_exact == (1 << BYTEWIDTH) - 1 |
| + |
| + /* If followed by a repetition operator. */ |
| + || *p == '*' || *p == '^' |
| + || ((syntax & RE_BK_PLUS_QM) |
| + ? *p == '\\' && (p[1] == '+' || p[1] == '?') |
| + : (*p == '+' || *p == '?')) |
| + || ((syntax & RE_INTERVALS) |
| + && ((syntax & RE_NO_BK_BRACES) |
| + ? *p == '{' |
| + : (p[0] == '\\' && p[1] == '{')))) |
| + { |
| + /* Start building a new exactn. */ |
| + |
| + laststart = b; |
| + |
| +#ifdef WCHAR |
| + /* Is this exactn binary data or character? */ |
| + is_exactn_bin = is_binary[p - 1 - pattern]; |
| + if (is_exactn_bin) |
| + BUF_PUSH_2 (exactn_bin, 0); |
| + else |
| + BUF_PUSH_2 (exactn, 0); |
| +#else |
| + BUF_PUSH_2 (exactn, 0); |
| +#endif /* WCHAR */ |
| + pending_exact = b - 1; |
| + } |
| + |
| + BUF_PUSH (c); |
| + (*pending_exact)++; |
| + break; |
| + } /* switch (c) */ |
| + } /* while p != pend */ |
| + |
| + |
| + /* Through the pattern now. */ |
| + |
| + if (fixup_alt_jump) |
| + STORE_JUMP (jump_past_alt, fixup_alt_jump, b); |
| + |
| + if (!COMPILE_STACK_EMPTY) |
| + FREE_STACK_RETURN (REG_EPAREN); |
| + |
| + /* If we don't want backtracking, force success |
| + the first time we reach the end of the compiled pattern. */ |
| + if (syntax & RE_NO_POSIX_BACKTRACKING) |
| + BUF_PUSH (succeed); |
| + |
| +#ifdef WCHAR |
| + free (pattern); |
| + free (mbs_offset); |
| + free (is_binary); |
| +#endif |
| + free (compile_stack.stack); |
| + |
| + /* We have succeeded; set the length of the buffer. */ |
| +#ifdef WCHAR |
| + bufp->used = (uintptr_t) b - (uintptr_t) COMPILED_BUFFER_VAR; |
| +#else |
| + bufp->used = b - bufp->buffer; |
| +#endif |
| + |
| +#ifdef DEBUG |
| + if (debug) |
| + { |
| + DEBUG_PRINT1 ("\nCompiled pattern: \n"); |
| + PREFIX(print_compiled_pattern) (bufp); |
| + } |
| +#endif /* DEBUG */ |
| + |
| +#ifndef MATCH_MAY_ALLOCATE |
| + /* Initialize the failure stack to the largest possible stack. This |
| + isn't necessary unless we're trying to avoid calling alloca in |
| + the search and match routines. */ |
| + { |
| + int num_regs = bufp->re_nsub + 1; |
| + |
| + /* Since DOUBLE_FAIL_STACK refuses to double only if the current size |
| + is strictly greater than re_max_failures, the largest possible stack |
| + is 2 * re_max_failures failure points. */ |
| + if (fail_stack.size < (2 * re_max_failures * MAX_FAILURE_ITEMS)) |
| + { |
| + fail_stack.size = (2 * re_max_failures * MAX_FAILURE_ITEMS); |
| + |
| +# ifdef emacs |
| + if (! fail_stack.stack) |
| + fail_stack.stack |
| + = (PREFIX(fail_stack_elt_t) *) xmalloc (fail_stack.size |
| + * sizeof (PREFIX(fail_stack_elt_t))); |
| + else |
| + fail_stack.stack |
| + = (PREFIX(fail_stack_elt_t) *) xrealloc (fail_stack.stack, |
| + (fail_stack.size |
| + * sizeof (PREFIX(fail_stack_elt_t)))); |
| +# else /* not emacs */ |
| + if (! fail_stack.stack) |
| + fail_stack.stack |
| + = (PREFIX(fail_stack_elt_t) *) malloc (fail_stack.size |
| + * sizeof (PREFIX(fail_stack_elt_t))); |
| + else |
| + fail_stack.stack |
| + = (PREFIX(fail_stack_elt_t) *) realloc (fail_stack.stack, |
| + (fail_stack.size |
| + * sizeof (PREFIX(fail_stack_elt_t)))); |
| +# endif /* not emacs */ |
| + } |
| + |
| + PREFIX(regex_grow_registers) (num_regs); |
| + } |
| +#endif /* not MATCH_MAY_ALLOCATE */ |
| + |
| + return REG_NOERROR; |
| +} /* regex_compile */ |
| + |
| +/* Subroutines for `regex_compile'. */ |
| + |
| +/* Store OP at LOC followed by two-byte integer parameter ARG. */ |
| +/* ifdef WCHAR, integer parameter is 1 wchar_t. */ |
| + |
| +static void |
| +PREFIX(store_op1) (re_opcode_t op, UCHAR_T *loc, int arg) |
| +{ |
| + *loc = (UCHAR_T) op; |
| + STORE_NUMBER (loc + 1, arg); |
| +} |
| + |
| + |
| +/* Like `store_op1', but for two two-byte parameters ARG1 and ARG2. */ |
| +/* ifdef WCHAR, integer parameter is 1 wchar_t. */ |
| + |
| +static void |
| +PREFIX(store_op2) (re_opcode_t op, UCHAR_T *loc, int arg1, int arg2) |
| +{ |
| + *loc = (UCHAR_T) op; |
| + STORE_NUMBER (loc + 1, arg1); |
| + STORE_NUMBER (loc + 1 + OFFSET_ADDRESS_SIZE, arg2); |
| +} |
| + |
| + |
| +/* Copy the bytes from LOC to END to open up three bytes of space at LOC |
| + for OP followed by two-byte integer parameter ARG. */ |
| +/* ifdef WCHAR, integer parameter is 1 wchar_t. */ |
| + |
| +static void |
| +PREFIX(insert_op1) (re_opcode_t op, UCHAR_T *loc, int arg, UCHAR_T *end) |
| +{ |
| + register UCHAR_T *pfrom = end; |
| + register UCHAR_T *pto = end + 1 + OFFSET_ADDRESS_SIZE; |
| + |
| + while (pfrom != loc) |
| + *--pto = *--pfrom; |
| + |
| + PREFIX(store_op1) (op, loc, arg); |
| +} |
| + |
| + |
| +/* Like `insert_op1', but for two two-byte parameters ARG1 and ARG2. */ |
| +/* ifdef WCHAR, integer parameter is 1 wchar_t. */ |
| + |
| +static void |
| +PREFIX(insert_op2) (re_opcode_t op, UCHAR_T *loc, int arg1, |
| + int arg2, UCHAR_T *end) |
| +{ |
| + register UCHAR_T *pfrom = end; |
| + register UCHAR_T *pto = end + 1 + 2 * OFFSET_ADDRESS_SIZE; |
| + |
| + while (pfrom != loc) |
| + *--pto = *--pfrom; |
| + |
| + PREFIX(store_op2) (op, loc, arg1, arg2); |
| +} |
| + |
| + |
| +/* P points to just after a ^ in PATTERN. Return true if that ^ comes |
| + after an alternative or a begin-subexpression. We assume there is at |
| + least one character before the ^. */ |
| + |
| +static boolean |
| +PREFIX(at_begline_loc_p) (const CHAR_T *pattern, const CHAR_T *p, |
| + reg_syntax_t syntax) |
| +{ |
| + const CHAR_T *prev = p - 2; |
| + boolean prev_prev_backslash = prev > pattern && prev[-1] == '\\'; |
| + |
| + return |
| + /* After a subexpression? */ |
| + (*prev == '(' && (syntax & RE_NO_BK_PARENS || prev_prev_backslash)) |
| + /* After an alternative? */ |
| + || (*prev == '|' && (syntax & RE_NO_BK_VBAR || prev_prev_backslash)); |
| +} |
| + |
| + |
| +/* The dual of at_begline_loc_p. This one is for $. We assume there is |
| + at least one character after the $, i.e., `P < PEND'. */ |
| + |
| +static boolean |
| +PREFIX(at_endline_loc_p) (const CHAR_T *p, const CHAR_T *pend, |
| + reg_syntax_t syntax) |
| +{ |
| + const CHAR_T *next = p; |
| + boolean next_backslash = *next == '\\'; |
| + const CHAR_T *next_next = p + 1 < pend ? p + 1 : 0; |
| + |
| + return |
| + /* Before a subexpression? */ |
| + (syntax & RE_NO_BK_PARENS ? *next == ')' |
| + : next_backslash && next_next && *next_next == ')') |
| + /* Before an alternative? */ |
| + || (syntax & RE_NO_BK_VBAR ? *next == '|' |
| + : next_backslash && next_next && *next_next == '|'); |
| +} |
| + |
| +#else /* not INSIDE_RECURSION */ |
| + |
| +/* Returns true if REGNUM is in one of COMPILE_STACK's elements and |
| + false if it's not. */ |
| + |
| +static boolean |
| +group_in_compile_stack (compile_stack_type compile_stack, regnum_t regnum) |
| +{ |
| + int this_element; |
| + |
| + for (this_element = compile_stack.avail - 1; |
| + this_element >= 0; |
| + this_element--) |
| + if (compile_stack.stack[this_element].regnum == regnum) |
| + return true; |
| + |
| + return false; |
| +} |
| +#endif /* not INSIDE_RECURSION */ |
| + |
| +#ifdef INSIDE_RECURSION |
| + |
| +#ifdef WCHAR |
| +/* This insert space, which size is "num", into the pattern at "loc". |
| + "end" must point the end of the allocated buffer. */ |
| +static void |
| +insert_space (int num, CHAR_T *loc, CHAR_T *end) |
| +{ |
| + register CHAR_T *pto = end; |
| + register CHAR_T *pfrom = end - num; |
| + |
| + while (pfrom >= loc) |
| + *pto-- = *pfrom--; |
| +} |
| +#endif /* WCHAR */ |
| + |
| +#ifdef WCHAR |
| +static reg_errcode_t |
| +wcs_compile_range (CHAR_T range_start_char, const CHAR_T **p_ptr, |
| + const CHAR_T *pend, RE_TRANSLATE_TYPE translate, |
| + reg_syntax_t syntax, CHAR_T *b, CHAR_T *char_set) |
| +{ |
| + const CHAR_T *p = *p_ptr; |
| + CHAR_T range_start, range_end; |
| + reg_errcode_t ret; |
| +# ifdef _LIBC |
| + uint32_t nrules; |
| + uint32_t start_val, end_val; |
| +# endif |
| + if (p == pend) |
| + return REG_ERANGE; |
| + |
| +# ifdef _LIBC |
| + nrules = _NL_CURRENT_WORD (LC_COLLATE, _NL_COLLATE_NRULES); |
| + if (nrules != 0) |
| + { |
| + const char *collseq = (const char *) _NL_CURRENT(LC_COLLATE, |
| + _NL_COLLATE_COLLSEQWC); |
| + const unsigned char *extra = (const unsigned char *) |
| + _NL_CURRENT (LC_COLLATE, _NL_COLLATE_SYMB_EXTRAMB); |
| + |
| + if (range_start_char < -1) |
| + { |
| + /* range_start is a collating symbol. */ |
| + int32_t *wextra; |
| + /* Retreive the index and get collation sequence value. */ |
| + wextra = (int32_t*)(extra + char_set[-range_start_char]); |
| + start_val = wextra[1 + *wextra]; |
| + } |
| + else |
| + start_val = collseq_table_lookup(collseq, TRANSLATE(range_start_char)); |
| + |
| + end_val = collseq_table_lookup (collseq, TRANSLATE (p[0])); |
| + |
| + /* Report an error if the range is empty and the syntax prohibits |
| + this. */ |
| + ret = ((syntax & RE_NO_EMPTY_RANGES) |
| + && (start_val > end_val))? REG_ERANGE : REG_NOERROR; |
| + |
| + /* Insert space to the end of the char_ranges. */ |
| + insert_space(2, b - char_set[5] - 2, b - 1); |
| + *(b - char_set[5] - 2) = (wchar_t)start_val; |
| + *(b - char_set[5] - 1) = (wchar_t)end_val; |
| + char_set[4]++; /* ranges_index */ |
| + } |
| + else |
| +# endif |
| + { |
| + range_start = (range_start_char >= 0)? TRANSLATE (range_start_char): |
| + range_start_char; |
| + range_end = TRANSLATE (p[0]); |
| + /* Report an error if the range is empty and the syntax prohibits |
| + this. */ |
| + ret = ((syntax & RE_NO_EMPTY_RANGES) |
| + && (range_start > range_end))? REG_ERANGE : REG_NOERROR; |
| + |
| + /* Insert space to the end of the char_ranges. */ |
| + insert_space(2, b - char_set[5] - 2, b - 1); |
| + *(b - char_set[5] - 2) = range_start; |
| + *(b - char_set[5] - 1) = range_end; |
| + char_set[4]++; /* ranges_index */ |
| + } |
| + /* Have to increment the pointer into the pattern string, so the |
| + caller isn't still at the ending character. */ |
| + (*p_ptr)++; |
| + |
| + return ret; |
| +} |
| +#else /* BYTE */ |
| +/* Read the ending character of a range (in a bracket expression) from the |
| + uncompiled pattern *P_PTR (which ends at PEND). We assume the |
| + starting character is in `P[-2]'. (`P[-1]' is the character `-'.) |
| + Then we set the translation of all bits between the starting and |
| + ending characters (inclusive) in the compiled pattern B. |
| + |
| + Return an error code. |
| + |
| + We use these short variable names so we can use the same macros as |
| + `regex_compile' itself. */ |
| + |
| +static reg_errcode_t |
| +byte_compile_range (unsigned int range_start_char, const char **p_ptr, |
| + const char *pend, RE_TRANSLATE_TYPE translate, |
| + reg_syntax_t syntax, unsigned char *b) |
| +{ |
| + unsigned this_char; |
| + const char *p = *p_ptr; |
| + reg_errcode_t ret; |
| +# if _LIBC |
| + const unsigned char *collseq; |
| + unsigned int start_colseq; |
| + unsigned int end_colseq; |
| +# else |
| + unsigned end_char; |
| +# endif |
| + |
| + if (p == pend) |
| + return REG_ERANGE; |
| + |
| + /* Have to increment the pointer into the pattern string, so the |
| + caller isn't still at the ending character. */ |
| + (*p_ptr)++; |
| + |
| + /* Report an error if the range is empty and the syntax prohibits this. */ |
| + ret = syntax & RE_NO_EMPTY_RANGES ? REG_ERANGE : REG_NOERROR; |
| + |
| +# if _LIBC |
| + collseq = (const unsigned char *) _NL_CURRENT (LC_COLLATE, |
| + _NL_COLLATE_COLLSEQMB); |
| + |
| + start_colseq = collseq[(unsigned char) TRANSLATE (range_start_char)]; |
| + end_colseq = collseq[(unsigned char) TRANSLATE (p[0])]; |
| + for (this_char = 0; this_char <= (unsigned char) -1; ++this_char) |
| + { |
| + unsigned int this_colseq = collseq[(unsigned char) TRANSLATE (this_char)]; |
| + |
| + if (start_colseq <= this_colseq && this_colseq <= end_colseq) |
| + { |
| + SET_LIST_BIT (TRANSLATE (this_char)); |
| + ret = REG_NOERROR; |
| + } |
| + } |
| +# else |
| + /* Here we see why `this_char' has to be larger than an `unsigned |
| + char' -- we would otherwise go into an infinite loop, since all |
| + characters <= 0xff. */ |
| + range_start_char = TRANSLATE (range_start_char); |
| + /* TRANSLATE(p[0]) is casted to char (not unsigned char) in TRANSLATE, |
| + and some compilers cast it to int implicitly, so following for_loop |
| + may fall to (almost) infinite loop. |
| + e.g. If translate[p[0]] = 0xff, end_char may equals to 0xffffffff. |
| + To avoid this, we cast p[0] to unsigned int and truncate it. */ |
| + end_char = ((unsigned)TRANSLATE(p[0]) & ((1 << BYTEWIDTH) - 1)); |
| + |
| + for (this_char = range_start_char; this_char <= end_char; ++this_char) |
| + { |
| + SET_LIST_BIT (TRANSLATE (this_char)); |
| + ret = REG_NOERROR; |
| + } |
| +# endif |
| + |
| + return ret; |
| +} |
| +#endif /* WCHAR */ |
| + |
| +/* re_compile_fastmap computes a ``fastmap'' for the compiled pattern in |
| + BUFP. A fastmap records which of the (1 << BYTEWIDTH) possible |
| + characters can start a string that matches the pattern. This fastmap |
| + is used by re_search to skip quickly over impossible starting points. |
| + |
| + The caller must supply the address of a (1 << BYTEWIDTH)-byte data |
| + area as BUFP->fastmap. |
| + |
| + We set the `fastmap', `fastmap_accurate', and `can_be_null' fields in |
| + the pattern buffer. |
| + |
| + Returns 0 if we succeed, -2 if an internal error. */ |
| + |
| +#ifdef WCHAR |
| +/* local function for re_compile_fastmap. |
| + truncate wchar_t character to char. */ |
| +static unsigned char truncate_wchar (CHAR_T c); |
| + |
| +static unsigned char |
| +truncate_wchar (CHAR_T c) |
| +{ |
| + unsigned char buf[MB_CUR_MAX]; |
| + mbstate_t state; |
| + int retval; |
| + memset (&state, '\0', sizeof (state)); |
| +# ifdef _LIBC |
| + retval = __wcrtomb (buf, c, &state); |
| +# else |
| + retval = wcrtomb (buf, c, &state); |
| +# endif |
| + return retval > 0 ? buf[0] : (unsigned char) c; |
| +} |
| +#endif /* WCHAR */ |
| + |
| +static int |
| +PREFIX(re_compile_fastmap) (struct re_pattern_buffer *bufp) |
| +{ |
| + int j, k; |
| +#ifdef MATCH_MAY_ALLOCATE |
| + PREFIX(fail_stack_type) fail_stack; |
| +#endif |
| +#ifndef REGEX_MALLOC |
| + char *destination; |
| +#endif |
| + |
| + register char *fastmap = bufp->fastmap; |
| + |
| +#ifdef WCHAR |
| + /* We need to cast pattern to (wchar_t*), because we casted this compiled |
| + pattern to (char*) in regex_compile. */ |
| + UCHAR_T *pattern = (UCHAR_T*)bufp->buffer; |
| + register UCHAR_T *pend = (UCHAR_T*) (bufp->buffer + bufp->used); |
| +#else /* BYTE */ |
| + UCHAR_T *pattern = bufp->buffer; |
| + register UCHAR_T *pend = pattern + bufp->used; |
| +#endif /* WCHAR */ |
| + UCHAR_T *p = pattern; |
| + |
| +#ifdef REL_ALLOC |
| + /* This holds the pointer to the failure stack, when |
| + it is allocated relocatably. */ |
| + fail_stack_elt_t *failure_stack_ptr; |
| +#endif |
| + |
| + /* Assume that each path through the pattern can be null until |
| + proven otherwise. We set this false at the bottom of switch |
| + statement, to which we get only if a particular path doesn't |
| + match the empty string. */ |
| + boolean path_can_be_null = true; |
| + |
| + /* We aren't doing a `succeed_n' to begin with. */ |
| + boolean succeed_n_p = false; |
| + |
| + assert (fastmap != NULL && p != NULL); |
| + |
| + INIT_FAIL_STACK (); |
| + bzero (fastmap, 1 << BYTEWIDTH); /* Assume nothing's valid. */ |
| + bufp->fastmap_accurate = 1; /* It will be when we're done. */ |
| + bufp->can_be_null = 0; |
| + |
| + while (1) |
| + { |
| + if (p == pend || *p == (UCHAR_T) succeed) |
| + { |
| + /* We have reached the (effective) end of pattern. */ |
| + if (!FAIL_STACK_EMPTY ()) |
| + { |
| + bufp->can_be_null |= path_can_be_null; |
| + |
| + /* Reset for next path. */ |
| + path_can_be_null = true; |
| + |
| + p = fail_stack.stack[--fail_stack.avail].pointer; |
| + |
| + continue; |
| + } |
| + else |
| + break; |
| + } |
| + |
| + /* We should never be about to go beyond the end of the pattern. */ |
| + assert (p < pend); |
| + |
| + switch (SWITCH_ENUM_CAST ((re_opcode_t) *p++)) |
| + { |
| + |
| + /* I guess the idea here is to simply not bother with a fastmap |
| + if a backreference is used, since it's too hard to figure out |
| + the fastmap for the corresponding group. Setting |
| + `can_be_null' stops `re_search_2' from using the fastmap, so |
| + that is all we do. */ |
| + case duplicate: |
| + bufp->can_be_null = 1; |
| + goto done; |
| + |
| + |
| + /* Following are the cases which match a character. These end |
| + with `break'. */ |
| + |
| +#ifdef WCHAR |
| + case exactn: |
| + fastmap[truncate_wchar(p[1])] = 1; |
| + break; |
| +#else /* BYTE */ |
| + case exactn: |
| + fastmap[p[1]] = 1; |
| + break; |
| +#endif /* WCHAR */ |
| +#ifdef MBS_SUPPORT |
| + case exactn_bin: |
| + fastmap[p[1]] = 1; |
| + break; |
| +#endif |
| + |
| +#ifdef WCHAR |
| + /* It is hard to distinguish fastmap from (multi byte) characters |
| + which depends on current locale. */ |
| + case charset: |
| + case charset_not: |
| + case wordchar: |
| + case notwordchar: |
| + bufp->can_be_null = 1; |
| + goto done; |
| +#else /* BYTE */ |
| + case charset: |
| + for (j = *p++ * BYTEWIDTH - 1; j >= 0; j--) |
| + if (p[j / BYTEWIDTH] & (1 << (j % BYTEWIDTH))) |
| + fastmap[j] = 1; |
| + break; |
| + |
| + |
| + case charset_not: |
| + /* Chars beyond end of map must be allowed. */ |
| + for (j = *p * BYTEWIDTH; j < (1 << BYTEWIDTH); j++) |
| + fastmap[j] = 1; |
| + |
| + for (j = *p++ * BYTEWIDTH - 1; j >= 0; j--) |
| + if (!(p[j / BYTEWIDTH] & (1 << (j % BYTEWIDTH)))) |
| + fastmap[j] = 1; |
| + break; |
| + |
| + |
| + case wordchar: |
| + for (j = 0; j < (1 << BYTEWIDTH); j++) |
| + if (SYNTAX (j) == Sword) |
| + fastmap[j] = 1; |
| + break; |
| + |
| + |
| + case notwordchar: |
| + for (j = 0; j < (1 << BYTEWIDTH); j++) |
| + if (SYNTAX (j) != Sword) |
| + fastmap[j] = 1; |
| + break; |
| +#endif /* WCHAR */ |
| + |
| + case anychar: |
| + { |
| + int fastmap_newline = fastmap['\n']; |
| + |
| + /* `.' matches anything ... */ |
| + for (j = 0; j < (1 << BYTEWIDTH); j++) |
| + fastmap[j] = 1; |
| + |
| + /* ... except perhaps newline. */ |
| + if (!(bufp->syntax & RE_DOT_NEWLINE)) |
| + fastmap['\n'] = fastmap_newline; |
| + |
| + /* Return if we have already set `can_be_null'; if we have, |
| + then the fastmap is irrelevant. Something's wrong here. */ |
| + else if (bufp->can_be_null) |
| + goto done; |
| + |
| + /* Otherwise, have to check alternative paths. */ |
| + break; |
| + } |
| + |
| +#ifdef emacs |
| + case syntaxspec: |
| + k = *p++; |
| + for (j = 0; j < (1 << BYTEWIDTH); j++) |
| + if (SYNTAX (j) == (enum syntaxcode) k) |
| + fastmap[j] = 1; |
| + break; |
| + |
| + |
| + case notsyntaxspec: |
| + k = *p++; |
| + for (j = 0; j < (1 << BYTEWIDTH); j++) |
| + if (SYNTAX (j) != (enum syntaxcode) k) |
| + fastmap[j] = 1; |
| + break; |
| + |
| + |
| + /* All cases after this match the empty string. These end with |
| + `continue'. */ |
| + |
| + |
| + case before_dot: |
| + case at_dot: |
| + case after_dot: |
| + continue; |
| +#endif /* emacs */ |
| + |
| + |
| + case no_op: |
| + case begline: |
| + case endline: |
| + case begbuf: |
| + case endbuf: |
| + case wordbound: |
| + case notwordbound: |
| + case wordbeg: |
| + case wordend: |
| + case push_dummy_failure: |
| + continue; |
| + |
| + |
| + case jump_n: |
| + case pop_failure_jump: |
| + case maybe_pop_jump: |
| + case jump: |
| + case jump_past_alt: |
| + case dummy_failure_jump: |
| + EXTRACT_NUMBER_AND_INCR (j, p); |
| + p += j; |
| + if (j > 0) |
| + continue; |
| + |
| + /* Jump backward implies we just went through the body of a |
| + loop and matched nothing. Opcode jumped to should be |
| + `on_failure_jump' or `succeed_n'. Just treat it like an |
| + ordinary jump. For a * loop, it has pushed its failure |
| + point already; if so, discard that as redundant. */ |
| + if ((re_opcode_t) *p != on_failure_jump |
| + && (re_opcode_t) *p != succeed_n) |
| + continue; |
| + |
| + p++; |
| + EXTRACT_NUMBER_AND_INCR (j, p); |
| + p += j; |
| + |
| + /* If what's on the stack is where we are now, pop it. */ |
| + if (!FAIL_STACK_EMPTY () |
| + && fail_stack.stack[fail_stack.avail - 1].pointer == p) |
| + fail_stack.avail--; |
| + |
| + continue; |
| + |
| + |
| + case on_failure_jump: |
| + case on_failure_keep_string_jump: |
| + handle_on_failure_jump: |
| + EXTRACT_NUMBER_AND_INCR (j, p); |
| + |
| + /* For some patterns, e.g., `(a?)?', `p+j' here points to the |
| + end of the pattern. We don't want to push such a point, |
| + since when we restore it above, entering the switch will |
| + increment `p' past the end of the pattern. We don't need |
| + to push such a point since we obviously won't find any more |
| + fastmap entries beyond `pend'. Such a pattern can match |
| + the null string, though. */ |
| + if (p + j < pend) |
| + { |
| + if (!PUSH_PATTERN_OP (p + j, fail_stack)) |
| + { |
| + RESET_FAIL_STACK (); |
| + return -2; |
| + } |
| + } |
| + else |
| + bufp->can_be_null = 1; |
| + |
| + if (succeed_n_p) |
| + { |
| + EXTRACT_NUMBER_AND_INCR (k, p); /* Skip the n. */ |
| + succeed_n_p = false; |
| + } |
| + |
| + continue; |
| + |
| + |
| + case succeed_n: |
| + /* Get to the number of times to succeed. */ |
| + p += OFFSET_ADDRESS_SIZE; |
| + |
| + /* Increment p past the n for when k != 0. */ |
| + EXTRACT_NUMBER_AND_INCR (k, p); |
| + if (k == 0) |
| + { |
| + p -= 2 * OFFSET_ADDRESS_SIZE; |
| + succeed_n_p = true; /* Spaghetti code alert. */ |
| + goto handle_on_failure_jump; |
| + } |
| + continue; |
| + |
| + |
| + case set_number_at: |
| + p += 2 * OFFSET_ADDRESS_SIZE; |
| + continue; |
| + |
| + |
| + case start_memory: |
| + case stop_memory: |
| + p += 2; |
| + continue; |
| + |
| + |
| + default: |
| + abort (); /* We have listed all the cases. */ |
| + } /* switch *p++ */ |
| + |
| + /* Getting here means we have found the possible starting |
| + characters for one path of the pattern -- and that the empty |
| + string does not match. We need not follow this path further. |
| + Instead, look at the next alternative (remembered on the |
| + stack), or quit if no more. The test at the top of the loop |
| + does these things. */ |
| + path_can_be_null = false; |
| + p = pend; |
| + } /* while p */ |
| + |
| + /* Set `can_be_null' for the last path (also the first path, if the |
| + pattern is empty). */ |
| + bufp->can_be_null |= path_can_be_null; |
| + |
| + done: |
| + RESET_FAIL_STACK (); |
| + return 0; |
| +} |
| + |
| +#else /* not INSIDE_RECURSION */ |
| + |
| +int |
| +re_compile_fastmap (struct re_pattern_buffer *bufp) |
| +{ |
| +# ifdef MBS_SUPPORT |
| + if (MB_CUR_MAX != 1) |
| + return wcs_re_compile_fastmap(bufp); |
| + else |
| +# endif |
| + return byte_re_compile_fastmap(bufp); |
| +} /* re_compile_fastmap */ |
| +#ifdef _LIBC |
| +weak_alias (__re_compile_fastmap, re_compile_fastmap) |
| +#endif |
| + |
| + |
| +/* Set REGS to hold NUM_REGS registers, storing them in STARTS and |
| + ENDS. Subsequent matches using PATTERN_BUFFER and REGS will use |
| + this memory for recording register information. STARTS and ENDS |
| + must be allocated using the malloc library routine, and must each |
| + be at least NUM_REGS * sizeof (regoff_t) bytes long. |
| + |
| + If NUM_REGS == 0, then subsequent matches should allocate their own |
| + register data. |
| + |
| + Unless this function is called, the first search or match using |
| + PATTERN_BUFFER will allocate its own register data, without |
| + freeing the old data. */ |
| + |
| +void |
| +re_set_registers (struct re_pattern_buffer *bufp, |
| + struct re_registers *regs, unsigned num_regs, |
| + regoff_t *starts, regoff_t *ends) |
| +{ |
| + if (num_regs) |
| + { |
| + bufp->regs_allocated = REGS_REALLOCATE; |
| + regs->num_regs = num_regs; |
| + regs->start = starts; |
| + regs->end = ends; |
| + } |
| + else |
| + { |
| + bufp->regs_allocated = REGS_UNALLOCATED; |
| + regs->num_regs = 0; |
| + regs->start = regs->end = (regoff_t *) 0; |
| + } |
| +} |
| +#ifdef _LIBC |
| +weak_alias (__re_set_registers, re_set_registers) |
| +#endif |
| + |
| +/* Searching routines. */ |
| + |
| +/* Like re_search_2, below, but only one string is specified, and |
| + doesn't let you say where to stop matching. */ |
| + |
| +int |
| +re_search (struct re_pattern_buffer *bufp, const char *string, int size, |
| + int startpos, int range, struct re_registers *regs) |
| +{ |
| + return re_search_2 (bufp, NULL, 0, string, size, startpos, range, |
| + regs, size); |
| +} |
| +#ifdef _LIBC |
| +weak_alias (__re_search, re_search) |
| +#endif |
| + |
| + |
| +/* Using the compiled pattern in BUFP->buffer, first tries to match the |
| + virtual concatenation of STRING1 and STRING2, starting first at index |
| + STARTPOS, then at STARTPOS + 1, and so on. |
| + |
| + STRING1 and STRING2 have length SIZE1 and SIZE2, respectively. |
| + |
| + RANGE is how far to scan while trying to match. RANGE = 0 means try |
| + only at STARTPOS; in general, the last start tried is STARTPOS + |
| + RANGE. |
| + |
| + In REGS, return the indices of the virtual concatenation of STRING1 |
| + and STRING2 that matched the entire BUFP->buffer and its contained |
| + subexpressions. |
| + |
| + Do not consider matching one past the index STOP in the virtual |
| + concatenation of STRING1 and STRING2. |
| + |
| + We return either the position in the strings at which the match was |
| + found, -1 if no match, or -2 if error (such as failure |
| + stack overflow). */ |
| + |
| +int |
| +re_search_2 (struct re_pattern_buffer *bufp, const char *string1, int size1, |
| + const char *string2, int size2, int startpos, int range, |
| + struct re_registers *regs, int stop) |
| +{ |
| +# ifdef MBS_SUPPORT |
| + if (MB_CUR_MAX != 1) |
| + return wcs_re_search_2 (bufp, string1, size1, string2, size2, startpos, |
| + range, regs, stop); |
| + else |
| +# endif |
| + return byte_re_search_2 (bufp, string1, size1, string2, size2, startpos, |
| + range, regs, stop); |
| +} /* re_search_2 */ |
| +#ifdef _LIBC |
| +weak_alias (__re_search_2, re_search_2) |
| +#endif |
| + |
| +#endif /* not INSIDE_RECURSION */ |
| + |
| +#ifdef INSIDE_RECURSION |
| + |
| +#ifdef MATCH_MAY_ALLOCATE |
| +# define FREE_VAR(var) if (var) REGEX_FREE (var); var = NULL |
| +#else |
| +# define FREE_VAR(var) if (var) free (var); var = NULL |
| +#endif |
| + |
| +#ifdef WCHAR |
| +# define MAX_ALLOCA_SIZE 2000 |
| + |
| +# define FREE_WCS_BUFFERS() \ |
| + do { \ |
| + if (size1 > MAX_ALLOCA_SIZE) \ |
| + { \ |
| + free (wcs_string1); \ |
| + free (mbs_offset1); \ |
| + } \ |
| + else \ |
| + { \ |
| + FREE_VAR (wcs_string1); \ |
| + FREE_VAR (mbs_offset1); \ |
| + } \ |
| + if (size2 > MAX_ALLOCA_SIZE) \ |
| + { \ |
| + free (wcs_string2); \ |
| + free (mbs_offset2); \ |
| + } \ |
| + else \ |
| + { \ |
| + FREE_VAR (wcs_string2); \ |
| + FREE_VAR (mbs_offset2); \ |
| + } \ |
| + } while (0) |
| + |
| +#endif |
| + |
| + |
| +static int |
| +PREFIX(re_search_2) (struct re_pattern_buffer *bufp, const char *string1, |
| + int size1, const char *string2, int size2, |
| + int startpos, int range, |
| + struct re_registers *regs, int stop) |
| +{ |
| + int val; |
| + register char *fastmap = bufp->fastmap; |
| + register RE_TRANSLATE_TYPE translate = bufp->translate; |
| + int total_size = size1 + size2; |
| + int endpos = startpos + range; |
| +#ifdef WCHAR |
| + /* We need wchar_t* buffers correspond to cstring1, cstring2. */ |
| + wchar_t *wcs_string1 = NULL, *wcs_string2 = NULL; |
| + /* We need the size of wchar_t buffers correspond to csize1, csize2. */ |
| + int wcs_size1 = 0, wcs_size2 = 0; |
| + /* offset buffer for optimizatoin. See convert_mbs_to_wc. */ |
| + int *mbs_offset1 = NULL, *mbs_offset2 = NULL; |
| + /* They hold whether each wchar_t is binary data or not. */ |
| + char *is_binary = NULL; |
| +#endif /* WCHAR */ |
| + |
| + /* Check for out-of-range STARTPOS. */ |
| + if (startpos < 0 || startpos > total_size) |
| + return -1; |
| + |
| + /* Fix up RANGE if it might eventually take us outside |
| + the virtual concatenation of STRING1 and STRING2. |
| + Make sure we won't move STARTPOS below 0 or above TOTAL_SIZE. */ |
| + if (endpos < 0) |
| + range = 0 - startpos; |
| + else if (endpos > total_size) |
| + range = total_size - startpos; |
| + |
| + /* If the search isn't to be a backwards one, don't waste time in a |
| + search for a pattern that must be anchored. */ |
| + if (bufp->used > 0 && range > 0 |
| + && ((re_opcode_t) bufp->buffer[0] == begbuf |
| + /* `begline' is like `begbuf' if it cannot match at newlines. */ |
| + || ((re_opcode_t) bufp->buffer[0] == begline |
| + && !bufp->newline_anchor))) |
| + { |
| + if (startpos > 0) |
| + return -1; |
| + else |
| + range = 1; |
| + } |
| + |
| +#ifdef emacs |
| + /* In a forward search for something that starts with \=. |
| + don't keep searching past point. */ |
| + if (bufp->used > 0 && (re_opcode_t) bufp->buffer[0] == at_dot && range > 0) |
| + { |
| + range = PT - startpos; |
| + if (range <= 0) |
| + return -1; |
| + } |
| +#endif /* emacs */ |
| + |
| + /* Update the fastmap now if not correct already. */ |
| + if (fastmap && !bufp->fastmap_accurate) |
| + if (re_compile_fastmap (bufp) == -2) |
| + return -2; |
| + |
| +#ifdef WCHAR |
| + /* Allocate wchar_t array for wcs_string1 and wcs_string2 and |
| + fill them with converted string. */ |
| + if (size1 != 0) |
| + { |
| + if (size1 > MAX_ALLOCA_SIZE) |
| + { |
| + wcs_string1 = TALLOC (size1 + 1, CHAR_T); |
| + mbs_offset1 = TALLOC (size1 + 1, int); |
| + is_binary = TALLOC (size1 + 1, char); |
| + } |
| + else |
| + { |
| + wcs_string1 = REGEX_TALLOC (size1 + 1, CHAR_T); |
| + mbs_offset1 = REGEX_TALLOC (size1 + 1, int); |
| + is_binary = REGEX_TALLOC (size1 + 1, char); |
| + } |
| + if (!wcs_string1 || !mbs_offset1 || !is_binary) |
| + { |
| + if (size1 > MAX_ALLOCA_SIZE) |
| + { |
| + free (wcs_string1); |
| + free (mbs_offset1); |
| + free (is_binary); |
| + } |
| + else |
| + { |
| + FREE_VAR (wcs_string1); |
| + FREE_VAR (mbs_offset1); |
| + FREE_VAR (is_binary); |
| + } |
| + return -2; |
| + } |
| + wcs_size1 = convert_mbs_to_wcs(wcs_string1, string1, size1, |
| + mbs_offset1, is_binary); |
| + wcs_string1[wcs_size1] = L'\0'; /* for a sentinel */ |
| + if (size1 > MAX_ALLOCA_SIZE) |
| + free (is_binary); |
| + else |
| + FREE_VAR (is_binary); |
| + } |
| + if (size2 != 0) |
| + { |
| + if (size2 > MAX_ALLOCA_SIZE) |
| + { |
| + wcs_string2 = TALLOC (size2 + 1, CHAR_T); |
| + mbs_offset2 = TALLOC (size2 + 1, int); |
| + is_binary = TALLOC (size2 + 1, char); |
| + } |
| + else |
| + { |
| + wcs_string2 = REGEX_TALLOC (size2 + 1, CHAR_T); |
| + mbs_offset2 = REGEX_TALLOC (size2 + 1, int); |
| + is_binary = REGEX_TALLOC (size2 + 1, char); |
| + } |
| + if (!wcs_string2 || !mbs_offset2 || !is_binary) |
| + { |
| + FREE_WCS_BUFFERS (); |
| + if (size2 > MAX_ALLOCA_SIZE) |
| + free (is_binary); |
| + else |
| + FREE_VAR (is_binary); |
| + return -2; |
| + } |
| + wcs_size2 = convert_mbs_to_wcs(wcs_string2, string2, size2, |
| + mbs_offset2, is_binary); |
| + wcs_string2[wcs_size2] = L'\0'; /* for a sentinel */ |
| + if (size2 > MAX_ALLOCA_SIZE) |
| + free (is_binary); |
| + else |
| + FREE_VAR (is_binary); |
| + } |
| +#endif /* WCHAR */ |
| + |
| + |
| + /* Loop through the string, looking for a place to start matching. */ |
| + for (;;) |
| + { |
| + /* If a fastmap is supplied, skip quickly over characters that |
| + cannot be the start of a match. If the pattern can match the |
| + null string, however, we don't need to skip characters; we want |
| + the first null string. */ |
| + if (fastmap && startpos < total_size && !bufp->can_be_null) |
| + { |
| + if (range > 0) /* Searching forwards. */ |
| + { |
| + register const char *d; |
| + register int lim = 0; |
| + int irange = range; |
| + |
| + if (startpos < size1 && startpos + range >= size1) |
| + lim = range - (size1 - startpos); |
| + |
| + d = (startpos >= size1 ? string2 - size1 : string1) + startpos; |
| + |
| + /* Written out as an if-else to avoid testing `translate' |
| + inside the loop. */ |
| + if (translate) |
| + while (range > lim |
| + && !fastmap[(unsigned char) |
| + translate[(unsigned char) *d++]]) |
| + range--; |
| + else |
| + while (range > lim && !fastmap[(unsigned char) *d++]) |
| + range--; |
| + |
| + startpos += irange - range; |
| + } |
| + else /* Searching backwards. */ |
| + { |
| + register CHAR_T c = (size1 == 0 || startpos >= size1 |
| + ? string2[startpos - size1] |
| + : string1[startpos]); |
| + |
| + if (!fastmap[(unsigned char) TRANSLATE (c)]) |
| + goto advance; |
| + } |
| + } |
| + |
| + /* If can't match the null string, and that's all we have left, fail. */ |
| + if (range >= 0 && startpos == total_size && fastmap |
| + && !bufp->can_be_null) |
| + { |
| +#ifdef WCHAR |
| + FREE_WCS_BUFFERS (); |
| +#endif |
| + return -1; |
| + } |
| + |
| +#ifdef WCHAR |
| + val = wcs_re_match_2_internal (bufp, string1, size1, string2, |
| + size2, startpos, regs, stop, |
| + wcs_string1, wcs_size1, |
| + wcs_string2, wcs_size2, |
| + mbs_offset1, mbs_offset2); |
| +#else /* BYTE */ |
| + val = byte_re_match_2_internal (bufp, string1, size1, string2, |
| + size2, startpos, regs, stop); |
| +#endif /* BYTE */ |
| + |
| +#ifndef REGEX_MALLOC |
| +# ifdef C_ALLOCA |
| + alloca (0); |
| +# endif |
| +#endif |
| + |
| + if (val >= 0) |
| + { |
| +#ifdef WCHAR |
| + FREE_WCS_BUFFERS (); |
| +#endif |
| + return startpos; |
| + } |
| + |
| + if (val == -2) |
| + { |
| +#ifdef WCHAR |
| + FREE_WCS_BUFFERS (); |
| +#endif |
| + return -2; |
| + } |
| + |
| + advance: |
| + if (!range) |
| + break; |
| + else if (range > 0) |
| + { |
| + range--; |
| + startpos++; |
| + } |
| + else |
| + { |
| + range++; |
| + startpos--; |
| + } |
| + } |
| +#ifdef WCHAR |
| + FREE_WCS_BUFFERS (); |
| +#endif |
| + return -1; |
| +} |
| + |
| +#ifdef WCHAR |
| +/* This converts PTR, a pointer into one of the search wchar_t strings |
| + `string1' and `string2' into an multibyte string offset from the |
| + beginning of that string. We use mbs_offset to optimize. |
| + See convert_mbs_to_wcs. */ |
| +# define POINTER_TO_OFFSET(ptr) \ |
| + (FIRST_STRING_P (ptr) \ |
| + ? ((regoff_t)(mbs_offset1 != NULL? mbs_offset1[(ptr)-string1] : 0)) \ |
| + : ((regoff_t)((mbs_offset2 != NULL? mbs_offset2[(ptr)-string2] : 0) \ |
| + + csize1))) |
| +#else /* BYTE */ |
| +/* This converts PTR, a pointer into one of the search strings `string1' |
| + and `string2' into an offset from the beginning of that string. */ |
| +# define POINTER_TO_OFFSET(ptr) \ |
| + (FIRST_STRING_P (ptr) \ |
| + ? ((regoff_t) ((ptr) - string1)) \ |
| + : ((regoff_t) ((ptr) - string2 + size1))) |
| +#endif /* WCHAR */ |
| + |
| +/* Macros for dealing with the split strings in re_match_2. */ |
| + |
| +#define MATCHING_IN_FIRST_STRING (dend == end_match_1) |
| + |
| +/* Call before fetching a character with *d. This switches over to |
| + string2 if necessary. */ |
| +#define PREFETCH() \ |
| + while (d == dend) \ |
| + { \ |
| + /* End of string2 => fail. */ \ |
| + if (dend == end_match_2) \ |
| + goto fail; \ |
| + /* End of string1 => advance to string2. */ \ |
| + d = string2; \ |
| + dend = end_match_2; \ |
| + } |
| + |
| +/* Test if at very beginning or at very end of the virtual concatenation |
| + of `string1' and `string2'. If only one string, it's `string2'. */ |
| +#define AT_STRINGS_BEG(d) ((d) == (size1 ? string1 : string2) || !size2) |
| +#define AT_STRINGS_END(d) ((d) == end2) |
| + |
| + |
| +/* Test if D points to a character which is word-constituent. We have |
| + two special cases to check for: if past the end of string1, look at |
| + the first character in string2; and if before the beginning of |
| + string2, look at the last character in string1. */ |
| +#ifdef WCHAR |
| +/* Use internationalized API instead of SYNTAX. */ |
| +# define WORDCHAR_P(d) \ |
| + (iswalnum ((wint_t)((d) == end1 ? *string2 \ |
| + : (d) == string2 - 1 ? *(end1 - 1) : *(d))) != 0 \ |
| + || ((d) == end1 ? *string2 \ |
| + : (d) == string2 - 1 ? *(end1 - 1) : *(d)) == L'_') |
| +#else /* BYTE */ |
| +# define WORDCHAR_P(d) \ |
| + (SYNTAX ((d) == end1 ? *string2 \ |
| + : (d) == string2 - 1 ? *(end1 - 1) : *(d)) \ |
| + == Sword) |
| +#endif /* WCHAR */ |
| + |
| +/* Disabled due to a compiler bug -- see comment at case wordbound */ |
| +#if 0 |
| +/* Test if the character before D and the one at D differ with respect |
| + to being word-constituent. */ |
| +#define AT_WORD_BOUNDARY(d) \ |
| + (AT_STRINGS_BEG (d) || AT_STRINGS_END (d) \ |
| + || WORDCHAR_P (d - 1) != WORDCHAR_P (d)) |
| +#endif |
| + |
| +/* Free everything we malloc. */ |
| +#ifdef MATCH_MAY_ALLOCATE |
| +# ifdef WCHAR |
| +# define FREE_VARIABLES() \ |
| + do { \ |
| + REGEX_FREE_STACK (fail_stack.stack); \ |
| + FREE_VAR (regstart); \ |
| + FREE_VAR (regend); \ |
| + FREE_VAR (old_regstart); \ |
| + FREE_VAR (old_regend); \ |
| + FREE_VAR (best_regstart); \ |
| + FREE_VAR (best_regend); \ |
| + FREE_VAR (reg_info); \ |
| + FREE_VAR (reg_dummy); \ |
| + FREE_VAR (reg_info_dummy); \ |
| + if (!cant_free_wcs_buf) \ |
| + { \ |
| + FREE_VAR (string1); \ |
| + FREE_VAR (string2); \ |
| + FREE_VAR (mbs_offset1); \ |
| + FREE_VAR (mbs_offset2); \ |
| + } \ |
| + } while (0) |
| +# else /* BYTE */ |
| +# define FREE_VARIABLES() \ |
| + do { \ |
| + REGEX_FREE_STACK (fail_stack.stack); \ |
| + FREE_VAR (regstart); \ |
| + FREE_VAR (regend); \ |
| + FREE_VAR (old_regstart); \ |
| + FREE_VAR (old_regend); \ |
| + FREE_VAR (best_regstart); \ |
| + FREE_VAR (best_regend); \ |
| + FREE_VAR (reg_info); \ |
| + FREE_VAR (reg_dummy); \ |
| + FREE_VAR (reg_info_dummy); \ |
| + } while (0) |
| +# endif /* WCHAR */ |
| +#else |
| +# ifdef WCHAR |
| +# define FREE_VARIABLES() \ |
| + do { \ |
| + if (!cant_free_wcs_buf) \ |
| + { \ |
| + FREE_VAR (string1); \ |
| + FREE_VAR (string2); \ |
| + FREE_VAR (mbs_offset1); \ |
| + FREE_VAR (mbs_offset2); \ |
| + } \ |
| + } while (0) |
| +# else /* BYTE */ |
| +# define FREE_VARIABLES() ((void)0) /* Do nothing! But inhibit gcc warning. */ |
| +# endif /* WCHAR */ |
| +#endif /* not MATCH_MAY_ALLOCATE */ |
| + |
| +/* These values must meet several constraints. They must not be valid |
| + register values; since we have a limit of 255 registers (because |
| + we use only one byte in the pattern for the register number), we can |
| + use numbers larger than 255. They must differ by 1, because of |
| + NUM_FAILURE_ITEMS above. And the value for the lowest register must |
| + be larger than the value for the highest register, so we do not try |
| + to actually save any registers when none are active. */ |
| +#define NO_HIGHEST_ACTIVE_REG (1 << BYTEWIDTH) |
| +#define NO_LOWEST_ACTIVE_REG (NO_HIGHEST_ACTIVE_REG + 1) |
| + |
| +#else /* not INSIDE_RECURSION */ |
| +/* Matching routines. */ |
| + |
| +#ifndef emacs /* Emacs never uses this. */ |
| +/* re_match is like re_match_2 except it takes only a single string. */ |
| + |
| +int |
| +re_match (struct re_pattern_buffer *bufp, const char *string, |
| + int size, int pos, struct re_registers *regs) |
| +{ |
| + int result; |
| +# ifdef MBS_SUPPORT |
| + if (MB_CUR_MAX != 1) |
| + result = wcs_re_match_2_internal (bufp, NULL, 0, string, size, |
| + pos, regs, size, |
| + NULL, 0, NULL, 0, NULL, NULL); |
| + else |
| +# endif |
| + result = byte_re_match_2_internal (bufp, NULL, 0, string, size, |
| + pos, regs, size); |
| +# ifndef REGEX_MALLOC |
| +# ifdef C_ALLOCA |
| + alloca (0); |
| +# endif |
| +# endif |
| + return result; |
| +} |
| +# ifdef _LIBC |
| +weak_alias (__re_match, re_match) |
| +# endif |
| +#endif /* not emacs */ |
| + |
| +#endif /* not INSIDE_RECURSION */ |
| + |
| +#ifdef INSIDE_RECURSION |
| +static boolean PREFIX(group_match_null_string_p) (UCHAR_T **p, |
| + UCHAR_T *end, |
| + PREFIX(register_info_type) *reg_info); |
| +static boolean PREFIX(alt_match_null_string_p) (UCHAR_T *p, |
| + UCHAR_T *end, |
| + PREFIX(register_info_type) *reg_info); |
| +static boolean PREFIX(common_op_match_null_string_p) (UCHAR_T **p, |
| + UCHAR_T *end, |
| + PREFIX(register_info_type) *reg_info); |
| +static int PREFIX(bcmp_translate) (const CHAR_T *s1, const CHAR_T *s2, |
| + register int len, |
| + RE_TRANSLATE_TYPE translate); |
| +#else /* not INSIDE_RECURSION */ |
| + |
| +/* re_match_2 matches the compiled pattern in BUFP against the |
| + the (virtual) concatenation of STRING1 and STRING2 (of length SIZE1 |
| + and SIZE2, respectively). We start matching at POS, and stop |
| + matching at STOP. |
| + |
| + If REGS is non-null and the `no_sub' field of BUFP is nonzero, we |
| + store offsets for the substring each group matched in REGS. See the |
| + documentation for exactly how many groups we fill. |
| + |
| + We return -1 if no match, -2 if an internal error (such as the |
| + failure stack overflowing). Otherwise, we return the length of the |
| + matched substring. */ |
| + |
| +int |
| +re_match_2 (struct re_pattern_buffer *bufp, const char *string1, int size1, |
| + const char *string2, int size2, int pos, |
| + struct re_registers *regs, int stop) |
| +{ |
| + int result; |
| +# ifdef MBS_SUPPORT |
| + if (MB_CUR_MAX != 1) |
| + result = wcs_re_match_2_internal (bufp, string1, size1, string2, size2, |
| + pos, regs, stop, |
| + NULL, 0, NULL, 0, NULL, NULL); |
| + else |
| +# endif |
| + result = byte_re_match_2_internal (bufp, string1, size1, string2, size2, |
| + pos, regs, stop); |
| + |
| +#ifndef REGEX_MALLOC |
| +# ifdef C_ALLOCA |
| + alloca (0); |
| +# endif |
| +#endif |
| + return result; |
| +} |
| +#ifdef _LIBC |
| +weak_alias (__re_match_2, re_match_2) |
| +#endif |
| + |
| +#endif /* not INSIDE_RECURSION */ |
| + |
| +#ifdef INSIDE_RECURSION |
| + |
| +#ifdef WCHAR |
| +static int count_mbs_length (int *, int); |
| + |
| +/* This check the substring (from 0, to length) of the multibyte string, |
| + to which offset_buffer correspond. And count how many wchar_t_characters |
| + the substring occupy. We use offset_buffer to optimization. |
| + See convert_mbs_to_wcs. */ |
| + |
| +static int |
| +count_mbs_length(int *offset_buffer, int length) |
| +{ |
| + int upper, lower; |
| + |
| + /* Check whether the size is valid. */ |
| + if (length < 0) |
| + return -1; |
| + |
| + if (offset_buffer == NULL) |
| + return 0; |
| + |
| + /* If there are no multibyte character, offset_buffer[i] == i. |
| + Optmize for this case. */ |
| + if (offset_buffer[length] == length) |
| + return length; |
| + |
| + /* Set up upper with length. (because for all i, offset_buffer[i] >= i) */ |
| + upper = length; |
| + lower = 0; |
| + |
| + while (true) |
| + { |
| + int middle = (lower + upper) / 2; |
| + if (middle == lower || middle == upper) |
| + break; |
| + if (offset_buffer[middle] > length) |
| + upper = middle; |
| + else if (offset_buffer[middle] < length) |
| + lower = middle; |
| + else |
| + return middle; |
| + } |
| + |
| + return -1; |
| +} |
| +#endif /* WCHAR */ |
| + |
| +/* This is a separate function so that we can force an alloca cleanup |
| + afterwards. */ |
| +#ifdef WCHAR |
| +static int |
| +wcs_re_match_2_internal (struct re_pattern_buffer *bufp, |
| + const char *cstring1, int csize1, |
| + const char *cstring2, int csize2, |
| + int pos, |
| + struct re_registers *regs, |
| + int stop, |
| + /* string1 == string2 == NULL means string1/2, size1/2 and |
| + mbs_offset1/2 need seting up in this function. */ |
| + /* We need wchar_t* buffers correspond to cstring1, cstring2. */ |
| + wchar_t *string1, int size1, |
| + wchar_t *string2, int size2, |
| + /* offset buffer for optimizatoin. See convert_mbs_to_wc. */ |
| + int *mbs_offset1, int *mbs_offset2) |
| +#else /* BYTE */ |
| +static int |
| +byte_re_match_2_internal (struct re_pattern_buffer *bufp, |
| + const char *string1, int size1, |
| + const char *string2, int size2, |
| + int pos, |
| + struct re_registers *regs, int stop) |
| +#endif /* BYTE */ |
| +{ |
| + /* General temporaries. */ |
| + int mcnt; |
| + UCHAR_T *p1; |
| +#ifdef WCHAR |
| + /* They hold whether each wchar_t is binary data or not. */ |
| + char *is_binary = NULL; |
| + /* If true, we can't free string1/2, mbs_offset1/2. */ |
| + int cant_free_wcs_buf = 1; |
| +#endif /* WCHAR */ |
| + |
| + /* Just past the end of the corresponding string. */ |
| + const CHAR_T *end1, *end2; |
| + |
| + /* Pointers into string1 and string2, just past the last characters in |
| + each to consider matching. */ |
| + const CHAR_T *end_match_1, *end_match_2; |
| + |
| + /* Where we are in the data, and the end of the current string. */ |
| + const CHAR_T *d, *dend; |
| + |
| + /* Where we are in the pattern, and the end of the pattern. */ |
| +#ifdef WCHAR |
| + UCHAR_T *pattern, *p; |
| + register UCHAR_T *pend; |
| +#else /* BYTE */ |
| + UCHAR_T *p = bufp->buffer; |
| + register UCHAR_T *pend = p + bufp->used; |
| +#endif /* WCHAR */ |
| + |
| + /* Mark the opcode just after a start_memory, so we can test for an |
| + empty subpattern when we get to the stop_memory. */ |
| + UCHAR_T *just_past_start_mem = 0; |
| + |
| + /* We use this to map every character in the string. */ |
| + RE_TRANSLATE_TYPE translate = bufp->translate; |
| + |
| + /* Failure point stack. Each place that can handle a failure further |
| + down the line pushes a failure point on this stack. It consists of |
| + restart, regend, and reg_info for all registers corresponding to |
| + the subexpressions we're currently inside, plus the number of such |
| + registers, and, finally, two char *'s. The first char * is where |
| + to resume scanning the pattern; the second one is where to resume |
| + scanning the strings. If the latter is zero, the failure point is |
| + a ``dummy''; if a failure happens and the failure point is a dummy, |
| + it gets discarded and the next next one is tried. */ |
| +#ifdef MATCH_MAY_ALLOCATE /* otherwise, this is global. */ |
| + PREFIX(fail_stack_type) fail_stack; |
| +#endif |
| +#ifdef DEBUG |
| + static unsigned failure_id; |
| + unsigned nfailure_points_pushed = 0, nfailure_points_popped = 0; |
| +#endif |
| + |
| +#ifdef REL_ALLOC |
| + /* This holds the pointer to the failure stack, when |
| + it is allocated relocatably. */ |
| + fail_stack_elt_t *failure_stack_ptr; |
| +#endif |
| + |
| + /* We fill all the registers internally, independent of what we |
| + return, for use in backreferences. The number here includes |
| + an element for register zero. */ |
| + size_t num_regs = bufp->re_nsub + 1; |
| + |
| + /* The currently active registers. */ |
| + active_reg_t lowest_active_reg = NO_LOWEST_ACTIVE_REG; |
| + active_reg_t highest_active_reg = NO_HIGHEST_ACTIVE_REG; |
| + |
| + /* Information on the contents of registers. These are pointers into |
| + the input strings; they record just what was matched (on this |
| + attempt) by a subexpression part of the pattern, that is, the |
| + regnum-th regstart pointer points to where in the pattern we began |
| + matching and the regnum-th regend points to right after where we |
| + stopped matching the regnum-th subexpression. (The zeroth register |
| + keeps track of what the whole pattern matches.) */ |
| +#ifdef MATCH_MAY_ALLOCATE /* otherwise, these are global. */ |
| + const CHAR_T **regstart, **regend; |
| +#endif |
| + |
| + /* If a group that's operated upon by a repetition operator fails to |
| + match anything, then the register for its start will need to be |
| + restored because it will have been set to wherever in the string we |
| + are when we last see its open-group operator. Similarly for a |
| + register's end. */ |
| +#ifdef MATCH_MAY_ALLOCATE /* otherwise, these are global. */ |
| + const CHAR_T **old_regstart, **old_regend; |
| +#endif |
| + |
| + /* The is_active field of reg_info helps us keep track of which (possibly |
| + nested) subexpressions we are currently in. The matched_something |
| + field of reg_info[reg_num] helps us tell whether or not we have |
| + matched any of the pattern so far this time through the reg_num-th |
| + subexpression. These two fields get reset each time through any |
| + loop their register is in. */ |
| +#ifdef MATCH_MAY_ALLOCATE /* otherwise, this is global. */ |
| + PREFIX(register_info_type) *reg_info; |
| +#endif |
| + |
| + /* The following record the register info as found in the above |
| + variables when we find a match better than any we've seen before. |
| + This happens as we backtrack through the failure points, which in |
| + turn happens only if we have not yet matched the entire string. */ |
| + unsigned best_regs_set = false; |
| +#ifdef MATCH_MAY_ALLOCATE /* otherwise, these are global. */ |
| + const CHAR_T **best_regstart, **best_regend; |
| +#endif |
| + |
| + /* Logically, this is `best_regend[0]'. But we don't want to have to |
| + allocate space for that if we're not allocating space for anything |
| + else (see below). Also, we never need info about register 0 for |
| + any of the other register vectors, and it seems rather a kludge to |
| + treat `best_regend' differently than the rest. So we keep track of |
| + the end of the best match so far in a separate variable. We |
| + initialize this to NULL so that when we backtrack the first time |
| + and need to test it, it's not garbage. */ |
| + const CHAR_T *match_end = NULL; |
| + |
| + /* This helps SET_REGS_MATCHED avoid doing redundant work. */ |
| + int set_regs_matched_done = 0; |
| + |
| + /* Used when we pop values we don't care about. */ |
| +#ifdef MATCH_MAY_ALLOCATE /* otherwise, these are global. */ |
| + const CHAR_T **reg_dummy; |
| + PREFIX(register_info_type) *reg_info_dummy; |
| +#endif |
| + |
| +#ifdef DEBUG |
| + /* Counts the total number of registers pushed. */ |
| + unsigned num_regs_pushed = 0; |
| +#endif |
| + |
| + DEBUG_PRINT1 ("\n\nEntering re_match_2.\n"); |
| + |
| + INIT_FAIL_STACK (); |
| + |
| +#ifdef MATCH_MAY_ALLOCATE |
| + /* Do not bother to initialize all the register variables if there are |
| + no groups in the pattern, as it takes a fair amount of time. If |
| + there are groups, we include space for register 0 (the whole |
| + pattern), even though we never use it, since it simplifies the |
| + array indexing. We should fix this. */ |
| + if (bufp->re_nsub) |
| + { |
| + regstart = REGEX_TALLOC (num_regs, const CHAR_T *); |
| + regend = REGEX_TALLOC (num_regs, const CHAR_T *); |
| + old_regstart = REGEX_TALLOC (num_regs, const CHAR_T *); |
| + old_regend = REGEX_TALLOC (num_regs, const CHAR_T *); |
| + best_regstart = REGEX_TALLOC (num_regs, const CHAR_T *); |
| + best_regend = REGEX_TALLOC (num_regs, const CHAR_T *); |
| + reg_info = REGEX_TALLOC (num_regs, PREFIX(register_info_type)); |
| + reg_dummy = REGEX_TALLOC (num_regs, const CHAR_T *); |
| + reg_info_dummy = REGEX_TALLOC (num_regs, PREFIX(register_info_type)); |
| + |
| + if (!(regstart && regend && old_regstart && old_regend && reg_info |
| + && best_regstart && best_regend && reg_dummy && reg_info_dummy)) |
| + { |
| + FREE_VARIABLES (); |
| + return -2; |
| + } |
| + } |
| + else |
| + { |
| + /* We must initialize all our variables to NULL, so that |
| + `FREE_VARIABLES' doesn't try to free them. */ |
| + regstart = regend = old_regstart = old_regend = best_regstart |
| + = best_regend = reg_dummy = NULL; |
| + reg_info = reg_info_dummy = (PREFIX(register_info_type) *) NULL; |
| + } |
| +#endif /* MATCH_MAY_ALLOCATE */ |
| + |
| + /* The starting position is bogus. */ |
| +#ifdef WCHAR |
| + if (pos < 0 || pos > csize1 + csize2) |
| +#else /* BYTE */ |
| + if (pos < 0 || pos > size1 + size2) |
| +#endif |
| + { |
| + FREE_VARIABLES (); |
| + return -1; |
| + } |
| + |
| +#ifdef WCHAR |
| + /* Allocate wchar_t array for string1 and string2 and |
| + fill them with converted string. */ |
| + if (string1 == NULL && string2 == NULL) |
| + { |
| + /* We need seting up buffers here. */ |
| + |
| + /* We must free wcs buffers in this function. */ |
| + cant_free_wcs_buf = 0; |
| + |
| + if (csize1 != 0) |
| + { |
| + string1 = REGEX_TALLOC (csize1 + 1, CHAR_T); |
| + mbs_offset1 = REGEX_TALLOC (csize1 + 1, int); |
| + is_binary = REGEX_TALLOC (csize1 + 1, char); |
| + if (!string1 || !mbs_offset1 || !is_binary) |
| + { |
| + FREE_VAR (string1); |
| + FREE_VAR (mbs_offset1); |
| + FREE_VAR (is_binary); |
| + return -2; |
| + } |
| + } |
| + if (csize2 != 0) |
| + { |
| + string2 = REGEX_TALLOC (csize2 + 1, CHAR_T); |
| + mbs_offset2 = REGEX_TALLOC (csize2 + 1, int); |
| + is_binary = REGEX_TALLOC (csize2 + 1, char); |
| + if (!string2 || !mbs_offset2 || !is_binary) |
| + { |
| + FREE_VAR (string1); |
| + FREE_VAR (mbs_offset1); |
| + FREE_VAR (string2); |
| + FREE_VAR (mbs_offset2); |
| + FREE_VAR (is_binary); |
| + return -2; |
| + } |
| + size2 = convert_mbs_to_wcs(string2, cstring2, csize2, |
| + mbs_offset2, is_binary); |
| + string2[size2] = L'\0'; /* for a sentinel */ |
| + FREE_VAR (is_binary); |
| + } |
| + } |
| + |
| + /* We need to cast pattern to (wchar_t*), because we casted this compiled |
| + pattern to (char*) in regex_compile. */ |
| + p = pattern = (CHAR_T*)bufp->buffer; |
| + pend = (CHAR_T*)(bufp->buffer + bufp->used); |
| + |
| +#endif /* WCHAR */ |
| + |
| + /* Initialize subexpression text positions to -1 to mark ones that no |
| + start_memory/stop_memory has been seen for. Also initialize the |
| + register information struct. */ |
| + for (mcnt = 1; (unsigned) mcnt < num_regs; mcnt++) |
| + { |
| + regstart[mcnt] = regend[mcnt] |
| + = old_regstart[mcnt] = old_regend[mcnt] = REG_UNSET_VALUE; |
| + |
| + REG_MATCH_NULL_STRING_P (reg_info[mcnt]) = MATCH_NULL_UNSET_VALUE; |
| + IS_ACTIVE (reg_info[mcnt]) = 0; |
| + MATCHED_SOMETHING (reg_info[mcnt]) = 0; |
| + EVER_MATCHED_SOMETHING (reg_info[mcnt]) = 0; |
| + } |
| + |
| + /* We move `string1' into `string2' if the latter's empty -- but not if |
| + `string1' is null. */ |
| + if (size2 == 0 && string1 != NULL) |
| + { |
| + string2 = string1; |
| + size2 = size1; |
| + string1 = 0; |
| + size1 = 0; |
| +#ifdef WCHAR |
| + mbs_offset2 = mbs_offset1; |
| + csize2 = csize1; |
| + mbs_offset1 = NULL; |
| + csize1 = 0; |
| +#endif |
| + } |
| + end1 = string1 + size1; |
| + end2 = string2 + size2; |
| + |
| + /* Compute where to stop matching, within the two strings. */ |
| +#ifdef WCHAR |
| + if (stop <= csize1) |
| + { |
| + mcnt = count_mbs_length(mbs_offset1, stop); |
| + end_match_1 = string1 + mcnt; |
| + end_match_2 = string2; |
| + } |
| + else |
| + { |
| + if (stop > csize1 + csize2) |
| + stop = csize1 + csize2; |
| + end_match_1 = end1; |
| + mcnt = count_mbs_length(mbs_offset2, stop-csize1); |
| + end_match_2 = string2 + mcnt; |
| + } |
| + if (mcnt < 0) |
| + { /* count_mbs_length return error. */ |
| + FREE_VARIABLES (); |
| + return -1; |
| + } |
| +#else |
| + if (stop <= size1) |
| + { |
| + end_match_1 = string1 + stop; |
| + end_match_2 = string2; |
| + } |
| + else |
| + { |
| + end_match_1 = end1; |
| + end_match_2 = string2 + stop - size1; |
| + } |
| +#endif /* WCHAR */ |
| + |
| + /* `p' scans through the pattern as `d' scans through the data. |
| + `dend' is the end of the input string that `d' points within. `d' |
| + is advanced into the following input string whenever necessary, but |
| + this happens before fetching; therefore, at the beginning of the |
| + loop, `d' can be pointing at the end of a string, but it cannot |
| + equal `string2'. */ |
| +#ifdef WCHAR |
| + if (size1 > 0 && pos <= csize1) |
| + { |
| + mcnt = count_mbs_length(mbs_offset1, pos); |
| + d = string1 + mcnt; |
| + dend = end_match_1; |
| + } |
| + else |
| + { |
| + mcnt = count_mbs_length(mbs_offset2, pos-csize1); |
| + d = string2 + mcnt; |
| + dend = end_match_2; |
| + } |
| + |
| + if (mcnt < 0) |
| + { /* count_mbs_length return error. */ |
| + FREE_VARIABLES (); |
| + return -1; |
| + } |
| +#else |
| + if (size1 > 0 && pos <= size1) |
| + { |
| + d = string1 + pos; |
| + dend = end_match_1; |
| + } |
| + else |
| + { |
| + d = string2 + pos - size1; |
| + dend = end_match_2; |
| + } |
| +#endif /* WCHAR */ |
| + |
| + DEBUG_PRINT1 ("The compiled pattern is:\n"); |
| + DEBUG_PRINT_COMPILED_PATTERN (bufp, p, pend); |
| + DEBUG_PRINT1 ("The string to match is: `"); |
| + DEBUG_PRINT_DOUBLE_STRING (d, string1, size1, string2, size2); |
| + DEBUG_PRINT1 ("'\n"); |
| + |
| + /* This loops over pattern commands. It exits by returning from the |
| + function if the match is complete, or it drops through if the match |
| + fails at this starting point in the input data. */ |
| + for (;;) |
| + { |
| +#ifdef _LIBC |
| + DEBUG_PRINT2 ("\n%p: ", p); |
| +#else |
| + DEBUG_PRINT2 ("\n0x%x: ", p); |
| +#endif |
| + |
| + if (p == pend) |
| + { /* End of pattern means we might have succeeded. */ |
| + DEBUG_PRINT1 ("end of pattern ... "); |
| + |
| + /* If we haven't matched the entire string, and we want the |
| + longest match, try backtracking. */ |
| + if (d != end_match_2) |
| + { |
| + /* 1 if this match ends in the same string (string1 or string2) |
| + as the best previous match. */ |
| + boolean same_str_p = (FIRST_STRING_P (match_end) |
| + == MATCHING_IN_FIRST_STRING); |
| + /* 1 if this match is the best seen so far. */ |
| + boolean best_match_p; |
| + |
| + /* AIX compiler got confused when this was combined |
| + with the previous declaration. */ |
| + if (same_str_p) |
| + best_match_p = d > match_end; |
| + else |
| + best_match_p = !MATCHING_IN_FIRST_STRING; |
| + |
| + DEBUG_PRINT1 ("backtracking.\n"); |
| + |
| + if (!FAIL_STACK_EMPTY ()) |
| + { /* More failure points to try. */ |
| + |
| + /* If exceeds best match so far, save it. */ |
| + if (!best_regs_set || best_match_p) |
| + { |
| + best_regs_set = true; |
| + match_end = d; |
| + |
| + DEBUG_PRINT1 ("\nSAVING match as best so far.\n"); |
| + |
| + for (mcnt = 1; (unsigned) mcnt < num_regs; mcnt++) |
| + { |
| + best_regstart[mcnt] = regstart[mcnt]; |
| + best_regend[mcnt] = regend[mcnt]; |
| + } |
| + } |
| + goto fail; |
| + } |
| + |
| + /* If no failure points, don't restore garbage. And if |
| + last match is real best match, don't restore second |
| + best one. */ |
| + else if (best_regs_set && !best_match_p) |
| + { |
| + restore_best_regs: |
| + /* Restore best match. It may happen that `dend == |
| + end_match_1' while the restored d is in string2. |
| + For example, the pattern `x.*y.*z' against the |
| + strings `x-' and `y-z-', if the two strings are |
| + not consecutive in memory. */ |
| + DEBUG_PRINT1 ("Restoring best registers.\n"); |
| + |
| + d = match_end; |
| + dend = ((d >= string1 && d <= end1) |
| + ? end_match_1 : end_match_2); |
| + |
| + for (mcnt = 1; (unsigned) mcnt < num_regs; mcnt++) |
| + { |
| + regstart[mcnt] = best_regstart[mcnt]; |
| + regend[mcnt] = best_regend[mcnt]; |
| + } |
| + } |
| + } /* d != end_match_2 */ |
| + |
| + succeed_label: |
| + DEBUG_PRINT1 ("Accepting match.\n"); |
| + /* If caller wants register contents data back, do it. */ |
| + if (regs && !bufp->no_sub) |
| + { |
| + /* Have the register data arrays been allocated? */ |
| + if (bufp->regs_allocated == REGS_UNALLOCATED) |
| + { /* No. So allocate them with malloc. We need one |
| + extra element beyond `num_regs' for the `-1' marker |
| + GNU code uses. */ |
| + regs->num_regs = MAX (RE_NREGS, num_regs + 1); |
| + regs->start = TALLOC (regs->num_regs, regoff_t); |
| + regs->end = TALLOC (regs->num_regs, regoff_t); |
| + if (regs->start == NULL || regs->end == NULL) |
| + { |
| + FREE_VARIABLES (); |
| + return -2; |
| + } |
| + bufp->regs_allocated = REGS_REALLOCATE; |
| + } |
| + else if (bufp->regs_allocated == REGS_REALLOCATE) |
| + { /* Yes. If we need more elements than were already |
| + allocated, reallocate them. If we need fewer, just |
| + leave it alone. */ |
| + if (regs->num_regs < num_regs + 1) |
| + { |
| + regs->num_regs = num_regs + 1; |
| + RETALLOC (regs->start, regs->num_regs, regoff_t); |
| + RETALLOC (regs->end, regs->num_regs, regoff_t); |
| + if (regs->start == NULL || regs->end == NULL) |
| + { |
| + FREE_VARIABLES (); |
| + return -2; |
| + } |
| + } |
| + } |
| + else |
| + { |
| + /* These braces fend off a "empty body in an else-statement" |
| + warning under GCC when assert expands to nothing. */ |
| + assert (bufp->regs_allocated == REGS_FIXED); |
| + } |
| + |
| + /* Convert the pointer data in `regstart' and `regend' to |
| + indices. Register zero has to be set differently, |
| + since we haven't kept track of any info for it. */ |
| + if (regs->num_regs > 0) |
| + { |
| + regs->start[0] = pos; |
| +#ifdef WCHAR |
| + if (MATCHING_IN_FIRST_STRING) |
| + regs->end[0] = mbs_offset1 != NULL ? |
| + mbs_offset1[d-string1] : 0; |
| + else |
| + regs->end[0] = csize1 + (mbs_offset2 != NULL ? |
| + mbs_offset2[d-string2] : 0); |
| +#else |
| + regs->end[0] = (MATCHING_IN_FIRST_STRING |
| + ? ((regoff_t) (d - string1)) |
| + : ((regoff_t) (d - string2 + size1))); |
| +#endif /* WCHAR */ |
| + } |
| + |
| + /* Go through the first `min (num_regs, regs->num_regs)' |
| + registers, since that is all we initialized. */ |
| + for (mcnt = 1; (unsigned) mcnt < MIN (num_regs, regs->num_regs); |
| + mcnt++) |
| + { |
| + if (REG_UNSET (regstart[mcnt]) || REG_UNSET (regend[mcnt])) |
| + regs->start[mcnt] = regs->end[mcnt] = -1; |
| + else |
| + { |
| + regs->start[mcnt] |
| + = (regoff_t) POINTER_TO_OFFSET (regstart[mcnt]); |
| + regs->end[mcnt] |
| + = (regoff_t) POINTER_TO_OFFSET (regend[mcnt]); |
| + } |
| + } |
| + |
| + /* If the regs structure we return has more elements than |
| + were in the pattern, set the extra elements to -1. If |
| + we (re)allocated the registers, this is the case, |
| + because we always allocate enough to have at least one |
| + -1 at the end. */ |
| + for (mcnt = num_regs; (unsigned) mcnt < regs->num_regs; mcnt++) |
| + regs->start[mcnt] = regs->end[mcnt] = -1; |
| + } /* regs && !bufp->no_sub */ |
| + |
| + DEBUG_PRINT4 ("%u failure points pushed, %u popped (%u remain).\n", |
| + nfailure_points_pushed, nfailure_points_popped, |
| + nfailure_points_pushed - nfailure_points_popped); |
| + DEBUG_PRINT2 ("%u registers pushed.\n", num_regs_pushed); |
| + |
| +#ifdef WCHAR |
| + if (MATCHING_IN_FIRST_STRING) |
| + mcnt = mbs_offset1 != NULL ? mbs_offset1[d-string1] : 0; |
| + else |
| + mcnt = (mbs_offset2 != NULL ? mbs_offset2[d-string2] : 0) + |
| + csize1; |
| + mcnt -= pos; |
| +#else |
| + mcnt = d - pos - (MATCHING_IN_FIRST_STRING |
| + ? string1 |
| + : string2 - size1); |
| +#endif /* WCHAR */ |
| + |
| + DEBUG_PRINT2 ("Returning %d from re_match_2.\n", mcnt); |
| + |
| + FREE_VARIABLES (); |
| + return mcnt; |
| + } |
| + |
| + /* Otherwise match next pattern command. */ |
| + switch (SWITCH_ENUM_CAST ((re_opcode_t) *p++)) |
| + { |
| + /* Ignore these. Used to ignore the n of succeed_n's which |
| + currently have n == 0. */ |
| + case no_op: |
| + DEBUG_PRINT1 ("EXECUTING no_op.\n"); |
| + break; |
| + |
| + case succeed: |
| + DEBUG_PRINT1 ("EXECUTING succeed.\n"); |
| + goto succeed_label; |
| + |
| + /* Match the next n pattern characters exactly. The following |
| + byte in the pattern defines n, and the n bytes after that |
| + are the characters to match. */ |
| + case exactn: |
| +#ifdef MBS_SUPPORT |
| + case exactn_bin: |
| +#endif |
| + mcnt = *p++; |
| + DEBUG_PRINT2 ("EXECUTING exactn %d.\n", mcnt); |
| + |
| + /* This is written out as an if-else so we don't waste time |
| + testing `translate' inside the loop. */ |
| + if (translate) |
| + { |
| + do |
| + { |
| + PREFETCH (); |
| +#ifdef WCHAR |
| + if (*d <= 0xff) |
| + { |
| + if ((UCHAR_T) translate[(unsigned char) *d++] |
| + != (UCHAR_T) *p++) |
| + goto fail; |
| + } |
| + else |
| + { |
| + if (*d++ != (CHAR_T) *p++) |
| + goto fail; |
| + } |
| +#else |
| + if ((UCHAR_T) translate[(unsigned char) *d++] |
| + != (UCHAR_T) *p++) |
| + goto fail; |
| +#endif /* WCHAR */ |
| + } |
| + while (--mcnt); |
| + } |
| + else |
| + { |
| + do |
| + { |
| + PREFETCH (); |
| + if (*d++ != (CHAR_T) *p++) goto fail; |
| + } |
| + while (--mcnt); |
| + } |
| + SET_REGS_MATCHED (); |
| + break; |
| + |
| + |
| + /* Match any character except possibly a newline or a null. */ |
| + case anychar: |
| + DEBUG_PRINT1 ("EXECUTING anychar.\n"); |
| + |
| + PREFETCH (); |
| + |
| + if ((!(bufp->syntax & RE_DOT_NEWLINE) && TRANSLATE (*d) == '\n') |
| + || (bufp->syntax & RE_DOT_NOT_NULL && TRANSLATE (*d) == '\000')) |
| + goto fail; |
| + |
| + SET_REGS_MATCHED (); |
| + DEBUG_PRINT2 (" Matched `%ld'.\n", (long int) *d); |
| + d++; |
| + break; |
| + |
| + |
| + case charset: |
| + case charset_not: |
| + { |
| + register UCHAR_T c; |
| +#ifdef WCHAR |
| + unsigned int i, char_class_length, coll_symbol_length, |
| + equiv_class_length, ranges_length, chars_length, length; |
| + CHAR_T *workp, *workp2, *charset_top; |
| +#define WORK_BUFFER_SIZE 128 |
| + CHAR_T str_buf[WORK_BUFFER_SIZE]; |
| +# ifdef _LIBC |
| + uint32_t nrules; |
| +# endif /* _LIBC */ |
| +#endif /* WCHAR */ |
| + boolean negate = (re_opcode_t) *(p - 1) == charset_not; |
| + |
| + DEBUG_PRINT2 ("EXECUTING charset%s.\n", negate ? "_not" : ""); |
| + PREFETCH (); |
| + c = TRANSLATE (*d); /* The character to match. */ |
| +#ifdef WCHAR |
| +# ifdef _LIBC |
| + nrules = _NL_CURRENT_WORD (LC_COLLATE, _NL_COLLATE_NRULES); |
| +# endif /* _LIBC */ |
| + charset_top = p - 1; |
| + char_class_length = *p++; |
| + coll_symbol_length = *p++; |
| + equiv_class_length = *p++; |
| + ranges_length = *p++; |
| + chars_length = *p++; |
| + /* p points charset[6], so the address of the next instruction |
| + (charset[l+m+n+2o+k+p']) equals p[l+m+n+2*o+p'], |
| + where l=length of char_classes, m=length of collating_symbol, |
| + n=equivalence_class, o=length of char_range, |
| + p'=length of character. */ |
| + workp = p; |
| + /* Update p to indicate the next instruction. */ |
| + p += char_class_length + coll_symbol_length+ equiv_class_length + |
| + 2*ranges_length + chars_length; |
| + |
| + /* match with char_class? */ |
| + for (i = 0; i < char_class_length ; i += CHAR_CLASS_SIZE) |
| + { |
| + wctype_t wctype; |
| + uintptr_t alignedp = ((uintptr_t)workp |
| + + __alignof__(wctype_t) - 1) |
| + & ~(uintptr_t)(__alignof__(wctype_t) - 1); |
| + wctype = *((wctype_t*)alignedp); |
| + workp += CHAR_CLASS_SIZE; |
| +# ifdef _LIBC |
| + if (__iswctype((wint_t)c, wctype)) |
| + goto char_set_matched; |
| +# else |
| + if (iswctype((wint_t)c, wctype)) |
| + goto char_set_matched; |
| +# endif |
| + } |
| + |
| + /* match with collating_symbol? */ |
| +# ifdef _LIBC |
| + if (nrules != 0) |
| + { |
| + const unsigned char *extra = (const unsigned char *) |
| + _NL_CURRENT (LC_COLLATE, _NL_COLLATE_SYMB_EXTRAMB); |
| + |
| + for (workp2 = workp + coll_symbol_length ; workp < workp2 ; |
| + workp++) |
| + { |
| + int32_t *wextra; |
| + wextra = (int32_t*)(extra + *workp++); |
| + for (i = 0; i < *wextra; ++i) |
| + if (TRANSLATE(d[i]) != wextra[1 + i]) |
| + break; |
| + |
| + if (i == *wextra) |
| + { |
| + /* Update d, however d will be incremented at |
| + char_set_matched:, we decrement d here. */ |
| + d += i - 1; |
| + goto char_set_matched; |
| + } |
| + } |
| + } |
| + else /* (nrules == 0) */ |
| +# endif |
| + /* If we can't look up collation data, we use wcscoll |
| + instead. */ |
| + { |
| + for (workp2 = workp + coll_symbol_length ; workp < workp2 ;) |
| + { |
| + const CHAR_T *backup_d = d, *backup_dend = dend; |
| +# ifdef _LIBC |
| + length = __wcslen (workp); |
| +# else |
| + length = wcslen (workp); |
| +# endif |
| + |
| + /* If wcscoll(the collating symbol, whole string) > 0, |
| + any substring of the string never match with the |
| + collating symbol. */ |
| +# ifdef _LIBC |
| + if (__wcscoll (workp, d) > 0) |
| +# else |
| + if (wcscoll (workp, d) > 0) |
| +# endif |
| + { |
| + workp += length + 1; |
| + continue; |
| + } |
| + |
| + /* First, we compare the collating symbol with |
| + the first character of the string. |
| + If it don't match, we add the next character to |
| + the compare buffer in turn. */ |
| + for (i = 0 ; i < WORK_BUFFER_SIZE-1 ; i++, d++) |
| + { |
| + int match; |
| + if (d == dend) |
| + { |
| + if (dend == end_match_2) |
| + break; |
| + d = string2; |
| + dend = end_match_2; |
| + } |
| + |
| + /* add next character to the compare buffer. */ |
| + str_buf[i] = TRANSLATE(*d); |
| + str_buf[i+1] = '\0'; |
| + |
| +# ifdef _LIBC |
| + match = __wcscoll (workp, str_buf); |
| +# else |
| + match = wcscoll (workp, str_buf); |
| +# endif |
| + if (match == 0) |
| + goto char_set_matched; |
| + |
| + if (match < 0) |
| + /* (str_buf > workp) indicate (str_buf + X > workp), |
| + because for all X (str_buf + X > str_buf). |
| + So we don't need continue this loop. */ |
| + break; |
| + |
| + /* Otherwise(str_buf < workp), |
| + (str_buf+next_character) may equals (workp). |
| + So we continue this loop. */ |
| + } |
| + /* not matched */ |
| + d = backup_d; |
| + dend = backup_dend; |
| + workp += length + 1; |
| + } |
| + } |
| + /* match with equivalence_class? */ |
| +# ifdef _LIBC |
| + if (nrules != 0) |
| + { |
| + const CHAR_T *backup_d = d, *backup_dend = dend; |
| + /* Try to match the equivalence class against |
| + those known to the collate implementation. */ |
| + const int32_t *table; |
| + const int32_t *weights; |
| + const int32_t *extra; |
| + const int32_t *indirect; |
| + int32_t idx, idx2; |
| + wint_t *cp; |
| + size_t len; |
| + |
| + table = (const int32_t *) |
| + _NL_CURRENT (LC_COLLATE, _NL_COLLATE_TABLEWC); |
| + weights = (const wint_t *) |
| + _NL_CURRENT (LC_COLLATE, _NL_COLLATE_WEIGHTWC); |
| + extra = (const wint_t *) |
| + _NL_CURRENT (LC_COLLATE, _NL_COLLATE_EXTRAWC); |
| + indirect = (const int32_t *) |
| + _NL_CURRENT (LC_COLLATE, _NL_COLLATE_INDIRECTWC); |
| + |
| + /* Write 1 collating element to str_buf, and |
| + get its index. */ |
| + idx2 = 0; |
| + |
| + for (i = 0 ; idx2 == 0 && i < WORK_BUFFER_SIZE - 1; i++) |
| + { |
| + cp = (wint_t*)str_buf; |
| + if (d == dend) |
| + { |
| + if (dend == end_match_2) |
| + break; |
| + d = string2; |
| + dend = end_match_2; |
| + } |
| + str_buf[i] = TRANSLATE(*(d+i)); |
| + str_buf[i+1] = '\0'; /* sentinel */ |
| + idx2 = FINDIDX (table, indirect, extra, &cp, 1); |
| + } |
| + |
| + /* Update d, however d will be incremented at |
| + char_set_matched:, we decrement d here. */ |
| + d = backup_d + ((wchar_t*)cp - (wchar_t*)str_buf - 1); |
| + if (d >= dend) |
| + { |
| + if (dend == end_match_2) |
| + d = dend; |
| + else |
| + { |
| + d = string2; |
| + dend = end_match_2; |
| + } |
| + } |
| + |
| + len = weights[idx2]; |
| + |
| + for (workp2 = workp + equiv_class_length ; workp < workp2 ; |
| + workp++) |
| + { |
| + idx = (int32_t)*workp; |
| + /* We already checked idx != 0 in regex_compile. */ |
| + |
| + if (idx2 != 0 && len == weights[idx]) |
| + { |
| + int cnt = 0; |
| + while (cnt < len && (weights[idx + 1 + cnt] |
| + == weights[idx2 + 1 + cnt])) |
| + ++cnt; |
| + |
| + if (cnt == len) |
| + goto char_set_matched; |
| + } |
| + } |
| + /* not matched */ |
| + d = backup_d; |
| + dend = backup_dend; |
| + } |
| + else /* (nrules == 0) */ |
| +# endif |
| + /* If we can't look up collation data, we use wcscoll |
| + instead. */ |
| + { |
| + for (workp2 = workp + equiv_class_length ; workp < workp2 ;) |
| + { |
| + const CHAR_T *backup_d = d, *backup_dend = dend; |
| +# ifdef _LIBC |
| + length = __wcslen (workp); |
| +# else |
| + length = wcslen (workp); |
| +# endif |
| + |
| + /* If wcscoll(the collating symbol, whole string) > 0, |
| + any substring of the string never match with the |
| + collating symbol. */ |
| +# ifdef _LIBC |
| + if (__wcscoll (workp, d) > 0) |
| +# else |
| + if (wcscoll (workp, d) > 0) |
| +# endif |
| + { |
| + workp += length + 1; |
| + break; |
| + } |
| + |
| + /* First, we compare the equivalence class with |
| + the first character of the string. |
| + If it don't match, we add the next character to |
| + the compare buffer in turn. */ |
| + for (i = 0 ; i < WORK_BUFFER_SIZE - 1 ; i++, d++) |
| + { |
| + int match; |
| + if (d == dend) |
| + { |
| + if (dend == end_match_2) |
| + break; |
| + d = string2; |
| + dend = end_match_2; |
| + } |
| + |
| + /* add next character to the compare buffer. */ |
| + str_buf[i] = TRANSLATE(*d); |
| + str_buf[i+1] = '\0'; |
| + |
| +# ifdef _LIBC |
| + match = __wcscoll (workp, str_buf); |
| +# else |
| + match = wcscoll (workp, str_buf); |
| +# endif |
| + |
| + if (match == 0) |
| + goto char_set_matched; |
| + |
| + if (match < 0) |
| + /* (str_buf > workp) indicate (str_buf + X > workp), |
| + because for all X (str_buf + X > str_buf). |
| + So we don't need continue this loop. */ |
| + break; |
| + |
| + /* Otherwise(str_buf < workp), |
| + (str_buf+next_character) may equals (workp). |
| + So we continue this loop. */ |
| + } |
| + /* not matched */ |
| + d = backup_d; |
| + dend = backup_dend; |
| + workp += length + 1; |
| + } |
| + } |
| + |
| + /* match with char_range? */ |
| +# ifdef _LIBC |
| + if (nrules != 0) |
| + { |
| + uint32_t collseqval; |
| + const char *collseq = (const char *) |
| + _NL_CURRENT(LC_COLLATE, _NL_COLLATE_COLLSEQWC); |
| + |
| + collseqval = collseq_table_lookup (collseq, c); |
| + |
| + for (; workp < p - chars_length ;) |
| + { |
| + uint32_t start_val, end_val; |
| + |
| + /* We already compute the collation sequence value |
| + of the characters (or collating symbols). */ |
| + start_val = (uint32_t) *workp++; /* range_start */ |
| + end_val = (uint32_t) *workp++; /* range_end */ |
| + |
| + if (start_val <= collseqval && collseqval <= end_val) |
| + goto char_set_matched; |
| + } |
| + } |
| + else |
| +# endif |
| + { |
| + /* We set range_start_char at str_buf[0], range_end_char |
| + at str_buf[4], and compared char at str_buf[2]. */ |
| + str_buf[1] = 0; |
| + str_buf[2] = c; |
| + str_buf[3] = 0; |
| + str_buf[5] = 0; |
| + for (; workp < p - chars_length ;) |
| + { |
| + wchar_t *range_start_char, *range_end_char; |
| + |
| + /* match if (range_start_char <= c <= range_end_char). */ |
| + |
| + /* If range_start(or end) < 0, we assume -range_start(end) |
| + is the offset of the collating symbol which is specified |
| + as the character of the range start(end). */ |
| + |
| + /* range_start */ |
| + if (*workp < 0) |
| + range_start_char = charset_top - (*workp++); |
| + else |
| + { |
| + str_buf[0] = *workp++; |
| + range_start_char = str_buf; |
| + } |
| + |
| + /* range_end */ |
| + if (*workp < 0) |
| + range_end_char = charset_top - (*workp++); |
| + else |
| + { |
| + str_buf[4] = *workp++; |
| + range_end_char = str_buf + 4; |
| + } |
| + |
| +# ifdef _LIBC |
| + if (__wcscoll (range_start_char, str_buf+2) <= 0 |
| + && __wcscoll (str_buf+2, range_end_char) <= 0) |
| +# else |
| + if (wcscoll (range_start_char, str_buf+2) <= 0 |
| + && wcscoll (str_buf+2, range_end_char) <= 0) |
| +# endif |
| + goto char_set_matched; |
| + } |
| + } |
| + |
| + /* match with char? */ |
| + for (; workp < p ; workp++) |
| + if (c == *workp) |
| + goto char_set_matched; |
| + |
| + negate = !negate; |
| + |
| + char_set_matched: |
| + if (negate) goto fail; |
| +#else |
| + /* Cast to `unsigned' instead of `unsigned char' in case the |
| + bit list is a full 32 bytes long. */ |
| + if (c < (unsigned) (*p * BYTEWIDTH) |
| + && p[1 + c / BYTEWIDTH] & (1 << (c % BYTEWIDTH))) |
| + negate = !negate; |
| + |
| + p += 1 + *p; |
| + |
| + if (!negate) goto fail; |
| +#undef WORK_BUFFER_SIZE |
| +#endif /* WCHAR */ |
| + SET_REGS_MATCHED (); |
| + d++; |
| + break; |
| + } |
| + |
| + |
| + /* The beginning of a group is represented by start_memory. |
| + The arguments are the register number in the next byte, and the |
| + number of groups inner to this one in the next. The text |
| + matched within the group is recorded (in the internal |
| + registers data structure) under the register number. */ |
| + case start_memory: |
| + DEBUG_PRINT3 ("EXECUTING start_memory %ld (%ld):\n", |
| + (long int) *p, (long int) p[1]); |
| + |
| + /* Find out if this group can match the empty string. */ |
| + p1 = p; /* To send to group_match_null_string_p. */ |
| + |
| + if (REG_MATCH_NULL_STRING_P (reg_info[*p]) == MATCH_NULL_UNSET_VALUE) |
| + REG_MATCH_NULL_STRING_P (reg_info[*p]) |
| + = PREFIX(group_match_null_string_p) (&p1, pend, reg_info); |
| + |
| + /* Save the position in the string where we were the last time |
| + we were at this open-group operator in case the group is |
| + operated upon by a repetition operator, e.g., with `(a*)*b' |
| + against `ab'; then we want to ignore where we are now in |
| + the string in case this attempt to match fails. */ |
| + old_regstart[*p] = REG_MATCH_NULL_STRING_P (reg_info[*p]) |
| + ? REG_UNSET (regstart[*p]) ? d : regstart[*p] |
| + : regstart[*p]; |
| + DEBUG_PRINT2 (" old_regstart: %d\n", |
| + POINTER_TO_OFFSET (old_regstart[*p])); |
| + |
| + regstart[*p] = d; |
| + DEBUG_PRINT2 (" regstart: %d\n", POINTER_TO_OFFSET (regstart[*p])); |
| + |
| + IS_ACTIVE (reg_info[*p]) = 1; |
| + MATCHED_SOMETHING (reg_info[*p]) = 0; |
| + |
| + /* Clear this whenever we change the register activity status. */ |
| + set_regs_matched_done = 0; |
| + |
| + /* This is the new highest active register. */ |
| + highest_active_reg = *p; |
| + |
| + /* If nothing was active before, this is the new lowest active |
| + register. */ |
| + if (lowest_active_reg == NO_LOWEST_ACTIVE_REG) |
| + lowest_active_reg = *p; |
| + |
| + /* Move past the register number and inner group count. */ |
| + p += 2; |
| + just_past_start_mem = p; |
| + |
| + break; |
| + |
| + |
| + /* The stop_memory opcode represents the end of a group. Its |
| + arguments are the same as start_memory's: the register |
| + number, and the number of inner groups. */ |
| + case stop_memory: |
| + DEBUG_PRINT3 ("EXECUTING stop_memory %ld (%ld):\n", |
| + (long int) *p, (long int) p[1]); |
| + |
| + /* We need to save the string position the last time we were at |
| + this close-group operator in case the group is operated |
| + upon by a repetition operator, e.g., with `((a*)*(b*)*)*' |
| + against `aba'; then we want to ignore where we are now in |
| + the string in case this attempt to match fails. */ |
| + old_regend[*p] = REG_MATCH_NULL_STRING_P (reg_info[*p]) |
| + ? REG_UNSET (regend[*p]) ? d : regend[*p] |
| + : regend[*p]; |
| + DEBUG_PRINT2 (" old_regend: %d\n", |
| + POINTER_TO_OFFSET (old_regend[*p])); |
| + |
| + regend[*p] = d; |
| + DEBUG_PRINT2 (" regend: %d\n", POINTER_TO_OFFSET (regend[*p])); |
| + |
| + /* This register isn't active anymore. */ |
| + IS_ACTIVE (reg_info[*p]) = 0; |
| + |
| + /* Clear this whenever we change the register activity status. */ |
| + set_regs_matched_done = 0; |
| + |
| + /* If this was the only register active, nothing is active |
| + anymore. */ |
| + if (lowest_active_reg == highest_active_reg) |
| + { |
| + lowest_active_reg = NO_LOWEST_ACTIVE_REG; |
| + highest_active_reg = NO_HIGHEST_ACTIVE_REG; |
| + } |
| + else |
| + { /* We must scan for the new highest active register, since |
| + it isn't necessarily one less than now: consider |
| + (a(b)c(d(e)f)g). When group 3 ends, after the f), the |
| + new highest active register is 1. */ |
| + UCHAR_T r = *p - 1; |
| + while (r > 0 && !IS_ACTIVE (reg_info[r])) |
| + r--; |
| + |
| + /* If we end up at register zero, that means that we saved |
| + the registers as the result of an `on_failure_jump', not |
| + a `start_memory', and we jumped to past the innermost |
| + `stop_memory'. For example, in ((.)*) we save |
| + registers 1 and 2 as a result of the *, but when we pop |
| + back to the second ), we are at the stop_memory 1. |
| + Thus, nothing is active. */ |
| + if (r == 0) |
| + { |
| + lowest_active_reg = NO_LOWEST_ACTIVE_REG; |
| + highest_active_reg = NO_HIGHEST_ACTIVE_REG; |
| + } |
| + else |
| + highest_active_reg = r; |
| + } |
| + |
| + /* If just failed to match something this time around with a |
| + group that's operated on by a repetition operator, try to |
| + force exit from the ``loop'', and restore the register |
| + information for this group that we had before trying this |
| + last match. */ |
| + if ((!MATCHED_SOMETHING (reg_info[*p]) |
| + || just_past_start_mem == p - 1) |
| + && (p + 2) < pend) |
| + { |
| + boolean is_a_jump_n = false; |
| + |
| + p1 = p + 2; |
| + mcnt = 0; |
| + switch ((re_opcode_t) *p1++) |
| + { |
| + case jump_n: |
| + is_a_jump_n = true; |
| + case pop_failure_jump: |
| + case maybe_pop_jump: |
| + case jump: |
| + case dummy_failure_jump: |
| + EXTRACT_NUMBER_AND_INCR (mcnt, p1); |
| + if (is_a_jump_n) |
| + p1 += OFFSET_ADDRESS_SIZE; |
| + break; |
| + |
| + default: |
| + /* do nothing */ ; |
| + } |
| + p1 += mcnt; |
| + |
| + /* If the next operation is a jump backwards in the pattern |
| + to an on_failure_jump right before the start_memory |
| + corresponding to this stop_memory, exit from the loop |
| + by forcing a failure after pushing on the stack the |
| + on_failure_jump's jump in the pattern, and d. */ |
| + if (mcnt < 0 && (re_opcode_t) *p1 == on_failure_jump |
| + && (re_opcode_t) p1[1+OFFSET_ADDRESS_SIZE] == start_memory |
| + && p1[2+OFFSET_ADDRESS_SIZE] == *p) |
| + { |
| + /* If this group ever matched anything, then restore |
| + what its registers were before trying this last |
| + failed match, e.g., with `(a*)*b' against `ab' for |
| + regstart[1], and, e.g., with `((a*)*(b*)*)*' |
| + against `aba' for regend[3]. |
| + |
| + Also restore the registers for inner groups for, |
| + e.g., `((a*)(b*))*' against `aba' (register 3 would |
| + otherwise get trashed). */ |
| + |
| + if (EVER_MATCHED_SOMETHING (reg_info[*p])) |
| + { |
| + unsigned r; |
| + |
| + EVER_MATCHED_SOMETHING (reg_info[*p]) = 0; |
| + |
| + /* Restore this and inner groups' (if any) registers. */ |
| + for (r = *p; r < (unsigned) *p + (unsigned) *(p + 1); |
| + r++) |
| + { |
| + regstart[r] = old_regstart[r]; |
| + |
| + /* xx why this test? */ |
| + if (old_regend[r] >= regstart[r]) |
| + regend[r] = old_regend[r]; |
| + } |
| + } |
| + p1++; |
| + EXTRACT_NUMBER_AND_INCR (mcnt, p1); |
| + PUSH_FAILURE_POINT (p1 + mcnt, d, -2); |
| + |
| + goto fail; |
| + } |
| + } |
| + |
| + /* Move past the register number and the inner group count. */ |
| + p += 2; |
| + break; |
| + |
| + |
| + /* \<digit> has been turned into a `duplicate' command which is |
| + followed by the numeric value of <digit> as the register number. */ |
| + case duplicate: |
| + { |
| + register const CHAR_T *d2, *dend2; |
| + int regno = *p++; /* Get which register to match against. */ |
| + DEBUG_PRINT2 ("EXECUTING duplicate %d.\n", regno); |
| + |
| + /* Can't back reference a group which we've never matched. */ |
| + if (REG_UNSET (regstart[regno]) || REG_UNSET (regend[regno])) |
| + goto fail; |
| + |
| + /* Where in input to try to start matching. */ |
| + d2 = regstart[regno]; |
| + |
| + /* Where to stop matching; if both the place to start and |
| + the place to stop matching are in the same string, then |
| + set to the place to stop, otherwise, for now have to use |
| + the end of the first string. */ |
| + |
| + dend2 = ((FIRST_STRING_P (regstart[regno]) |
| + == FIRST_STRING_P (regend[regno])) |
| + ? regend[regno] : end_match_1); |
| + for (;;) |
| + { |
| + /* If necessary, advance to next segment in register |
| + contents. */ |
| + while (d2 == dend2) |
| + { |
| + if (dend2 == end_match_2) break; |
| + if (dend2 == regend[regno]) break; |
| + |
| + /* End of string1 => advance to string2. */ |
| + d2 = string2; |
| + dend2 = regend[regno]; |
| + } |
| + /* At end of register contents => success */ |
| + if (d2 == dend2) break; |
| + |
| + /* If necessary, advance to next segment in data. */ |
| + PREFETCH (); |
| + |
| + /* How many characters left in this segment to match. */ |
| + mcnt = dend - d; |
| + |
| + /* Want how many consecutive characters we can match in |
| + one shot, so, if necessary, adjust the count. */ |
| + if (mcnt > dend2 - d2) |
| + mcnt = dend2 - d2; |
| + |
| + /* Compare that many; failure if mismatch, else move |
| + past them. */ |
| + if (translate |
| + ? PREFIX(bcmp_translate) (d, d2, mcnt, translate) |
| + : memcmp (d, d2, mcnt*sizeof(UCHAR_T))) |
| + goto fail; |
| + d += mcnt, d2 += mcnt; |
| + |
| + /* Do this because we've match some characters. */ |
| + SET_REGS_MATCHED (); |
| + } |
| + } |
| + break; |
| + |
| + |
| + /* begline matches the empty string at the beginning of the string |
| + (unless `not_bol' is set in `bufp'), and, if |
| + `newline_anchor' is set, after newlines. */ |
| + case begline: |
| + DEBUG_PRINT1 ("EXECUTING begline.\n"); |
| + |
| + if (AT_STRINGS_BEG (d)) |
| + { |
| + if (!bufp->not_bol) break; |
| + } |
| + else if (d[-1] == '\n' && bufp->newline_anchor) |
| + { |
| + break; |
| + } |
| + /* In all other cases, we fail. */ |
| + goto fail; |
| + |
| + |
| + /* endline is the dual of begline. */ |
| + case endline: |
| + DEBUG_PRINT1 ("EXECUTING endline.\n"); |
| + |
| + if (AT_STRINGS_END (d)) |
| + { |
| + if (!bufp->not_eol) break; |
| + } |
| + |
| + /* We have to ``prefetch'' the next character. */ |
| + else if ((d == end1 ? *string2 : *d) == '\n' |
| + && bufp->newline_anchor) |
| + { |
| + break; |
| + } |
| + goto fail; |
| + |
| + |
| + /* Match at the very beginning of the data. */ |
| + case begbuf: |
| + DEBUG_PRINT1 ("EXECUTING begbuf.\n"); |
| + if (AT_STRINGS_BEG (d)) |
| + break; |
| + goto fail; |
| + |
| + |
| + /* Match at the very end of the data. */ |
| + case endbuf: |
| + DEBUG_PRINT1 ("EXECUTING endbuf.\n"); |
| + if (AT_STRINGS_END (d)) |
| + break; |
| + goto fail; |
| + |
| + |
| + /* on_failure_keep_string_jump is used to optimize `.*\n'. It |
| + pushes NULL as the value for the string on the stack. Then |
| + `pop_failure_point' will keep the current value for the |
| + string, instead of restoring it. To see why, consider |
| + matching `foo\nbar' against `.*\n'. The .* matches the foo; |
| + then the . fails against the \n. But the next thing we want |
| + to do is match the \n against the \n; if we restored the |
| + string value, we would be back at the foo. |
| + |
| + Because this is used only in specific cases, we don't need to |
| + check all the things that `on_failure_jump' does, to make |
| + sure the right things get saved on the stack. Hence we don't |
| + share its code. The only reason to push anything on the |
| + stack at all is that otherwise we would have to change |
| + `anychar's code to do something besides goto fail in this |
| + case; that seems worse than this. */ |
| + case on_failure_keep_string_jump: |
| + DEBUG_PRINT1 ("EXECUTING on_failure_keep_string_jump"); |
| + |
| + EXTRACT_NUMBER_AND_INCR (mcnt, p); |
| +#ifdef _LIBC |
| + DEBUG_PRINT3 (" %d (to %p):\n", mcnt, p + mcnt); |
| +#else |
| + DEBUG_PRINT3 (" %d (to 0x%x):\n", mcnt, p + mcnt); |
| +#endif |
| + |
| + PUSH_FAILURE_POINT (p + mcnt, NULL, -2); |
| + break; |
| + |
| + |
| + /* Uses of on_failure_jump: |
| + |
| + Each alternative starts with an on_failure_jump that points |
| + to the beginning of the next alternative. Each alternative |
| + except the last ends with a jump that in effect jumps past |
| + the rest of the alternatives. (They really jump to the |
| + ending jump of the following alternative, because tensioning |
| + these jumps is a hassle.) |
| + |
| + Repeats start with an on_failure_jump that points past both |
| + the repetition text and either the following jump or |
| + pop_failure_jump back to this on_failure_jump. */ |
| + case on_failure_jump: |
| + on_failure: |
| + DEBUG_PRINT1 ("EXECUTING on_failure_jump"); |
| + |
| + EXTRACT_NUMBER_AND_INCR (mcnt, p); |
| +#ifdef _LIBC |
| + DEBUG_PRINT3 (" %d (to %p)", mcnt, p + mcnt); |
| +#else |
| + DEBUG_PRINT3 (" %d (to 0x%x)", mcnt, p + mcnt); |
| +#endif |
| + |
| + /* If this on_failure_jump comes right before a group (i.e., |
| + the original * applied to a group), save the information |
| + for that group and all inner ones, so that if we fail back |
| + to this point, the group's information will be correct. |
| + For example, in \(a*\)*\1, we need the preceding group, |
| + and in \(zz\(a*\)b*\)\2, we need the inner group. */ |
| + |
| + /* We can't use `p' to check ahead because we push |
| + a failure point to `p + mcnt' after we do this. */ |
| + p1 = p; |
| + |
| + /* We need to skip no_op's before we look for the |
| + start_memory in case this on_failure_jump is happening as |
| + the result of a completed succeed_n, as in \(a\)\{1,3\}b\1 |
| + against aba. */ |
| + while (p1 < pend && (re_opcode_t) *p1 == no_op) |
| + p1++; |
| + |
| + if (p1 < pend && (re_opcode_t) *p1 == start_memory) |
| + { |
| + /* We have a new highest active register now. This will |
| + get reset at the start_memory we are about to get to, |
| + but we will have saved all the registers relevant to |
| + this repetition op, as described above. */ |
| + highest_active_reg = *(p1 + 1) + *(p1 + 2); |
| + if (lowest_active_reg == NO_LOWEST_ACTIVE_REG) |
| + lowest_active_reg = *(p1 + 1); |
| + } |
| + |
| + DEBUG_PRINT1 (":\n"); |
| + PUSH_FAILURE_POINT (p + mcnt, d, -2); |
| + break; |
| + |
| + |
| + /* A smart repeat ends with `maybe_pop_jump'. |
| + We change it to either `pop_failure_jump' or `jump'. */ |
| + case maybe_pop_jump: |
| + EXTRACT_NUMBER_AND_INCR (mcnt, p); |
| + DEBUG_PRINT2 ("EXECUTING maybe_pop_jump %d.\n", mcnt); |
| + { |
| + register UCHAR_T *p2 = p; |
| + |
| + /* Compare the beginning of the repeat with what in the |
| + pattern follows its end. If we can establish that there |
| + is nothing that they would both match, i.e., that we |
| + would have to backtrack because of (as in, e.g., `a*a') |
| + then we can change to pop_failure_jump, because we'll |
| + never have to backtrack. |
| + |
| + This is not true in the case of alternatives: in |
| + `(a|ab)*' we do need to backtrack to the `ab' alternative |
| + (e.g., if the string was `ab'). But instead of trying to |
| + detect that here, the alternative has put on a dummy |
| + failure point which is what we will end up popping. */ |
| + |
| + /* Skip over open/close-group commands. |
| + If what follows this loop is a ...+ construct, |
| + look at what begins its body, since we will have to |
| + match at least one of that. */ |
| + while (1) |
| + { |
| + if (p2 + 2 < pend |
| + && ((re_opcode_t) *p2 == stop_memory |
| + || (re_opcode_t) *p2 == start_memory)) |
| + p2 += 3; |
| + else if (p2 + 2 + 2 * OFFSET_ADDRESS_SIZE < pend |
| + && (re_opcode_t) *p2 == dummy_failure_jump) |
| + p2 += 2 + 2 * OFFSET_ADDRESS_SIZE; |
| + else |
| + break; |
| + } |
| + |
| + p1 = p + mcnt; |
| + /* p1[0] ... p1[2] are the `on_failure_jump' corresponding |
| + to the `maybe_finalize_jump' of this case. Examine what |
| + follows. */ |
| + |
| + /* If we're at the end of the pattern, we can change. */ |
| + if (p2 == pend) |
| + { |
| + /* Consider what happens when matching ":\(.*\)" |
| + against ":/". I don't really understand this code |
| + yet. */ |
| + p[-(1+OFFSET_ADDRESS_SIZE)] = (UCHAR_T) |
| + pop_failure_jump; |
| + DEBUG_PRINT1 |
| + (" End of pattern: change to `pop_failure_jump'.\n"); |
| + } |
| + |
| + else if ((re_opcode_t) *p2 == exactn |
| +#ifdef MBS_SUPPORT |
| + || (re_opcode_t) *p2 == exactn_bin |
| +#endif |
| + || (bufp->newline_anchor && (re_opcode_t) *p2 == endline)) |
| + { |
| + register UCHAR_T c |
| + = *p2 == (UCHAR_T) endline ? '\n' : p2[2]; |
| + |
| + if (((re_opcode_t) p1[1+OFFSET_ADDRESS_SIZE] == exactn |
| +#ifdef MBS_SUPPORT |
| + || (re_opcode_t) p1[1+OFFSET_ADDRESS_SIZE] == exactn_bin |
| +#endif |
| + ) && p1[3+OFFSET_ADDRESS_SIZE] != c) |
| + { |
| + p[-(1+OFFSET_ADDRESS_SIZE)] = (UCHAR_T) |
| + pop_failure_jump; |
| +#ifdef WCHAR |
| + DEBUG_PRINT3 (" %C != %C => pop_failure_jump.\n", |
| + (wint_t) c, |
| + (wint_t) p1[3+OFFSET_ADDRESS_SIZE]); |
| +#else |
| + DEBUG_PRINT3 (" %c != %c => pop_failure_jump.\n", |
| + (char) c, |
| + (char) p1[3+OFFSET_ADDRESS_SIZE]); |
| +#endif |
| + } |
| + |
| +#ifndef WCHAR |
| + else if ((re_opcode_t) p1[3] == charset |
| + || (re_opcode_t) p1[3] == charset_not) |
| + { |
| + int negate = (re_opcode_t) p1[3] == charset_not; |
| + |
| + if (c < (unsigned) (p1[4] * BYTEWIDTH) |
| + && p1[5 + c / BYTEWIDTH] & (1 << (c % BYTEWIDTH))) |
| + negate = !negate; |
| + |
| + /* `negate' is equal to 1 if c would match, which means |
| + that we can't change to pop_failure_jump. */ |
| + if (!negate) |
| + { |
| + p[-3] = (unsigned char) pop_failure_jump; |
| + DEBUG_PRINT1 (" No match => pop_failure_jump.\n"); |
| + } |
| + } |
| +#endif /* not WCHAR */ |
| + } |
| +#ifndef WCHAR |
| + else if ((re_opcode_t) *p2 == charset) |
| + { |
| + /* We win if the first character of the loop is not part |
| + of the charset. */ |
| + if ((re_opcode_t) p1[3] == exactn |
| + && ! ((int) p2[1] * BYTEWIDTH > (int) p1[5] |
| + && (p2[2 + p1[5] / BYTEWIDTH] |
| + & (1 << (p1[5] % BYTEWIDTH))))) |
| + { |
| + p[-3] = (unsigned char) pop_failure_jump; |
| + DEBUG_PRINT1 (" No match => pop_failure_jump.\n"); |
| + } |
| + |
| + else if ((re_opcode_t) p1[3] == charset_not) |
| + { |
| + int idx; |
| + /* We win if the charset_not inside the loop |
| + lists every character listed in the charset after. */ |
| + for (idx = 0; idx < (int) p2[1]; idx++) |
| + if (! (p2[2 + idx] == 0 |
| + || (idx < (int) p1[4] |
| + && ((p2[2 + idx] & ~ p1[5 + idx]) == 0)))) |
| + break; |
| + |
| + if (idx == p2[1]) |
| + { |
| + p[-3] = (unsigned char) pop_failure_jump; |
| + DEBUG_PRINT1 (" No match => pop_failure_jump.\n"); |
| + } |
| + } |
| + else if ((re_opcode_t) p1[3] == charset) |
| + { |
| + int idx; |
| + /* We win if the charset inside the loop |
| + has no overlap with the one after the loop. */ |
| + for (idx = 0; |
| + idx < (int) p2[1] && idx < (int) p1[4]; |
| + idx++) |
| + if ((p2[2 + idx] & p1[5 + idx]) != 0) |
| + break; |
| + |
| + if (idx == p2[1] || idx == p1[4]) |
| + { |
| + p[-3] = (unsigned char) pop_failure_jump; |
| + DEBUG_PRINT1 (" No match => pop_failure_jump.\n"); |
| + } |
| + } |
| + } |
| +#endif /* not WCHAR */ |
| + } |
| + p -= OFFSET_ADDRESS_SIZE; /* Point at relative address again. */ |
| + if ((re_opcode_t) p[-1] != pop_failure_jump) |
| + { |
| + p[-1] = (UCHAR_T) jump; |
| + DEBUG_PRINT1 (" Match => jump.\n"); |
| + goto unconditional_jump; |
| + } |
| + /* Note fall through. */ |
| + |
| + |
| + /* The end of a simple repeat has a pop_failure_jump back to |
| + its matching on_failure_jump, where the latter will push a |
| + failure point. The pop_failure_jump takes off failure |
| + points put on by this pop_failure_jump's matching |
| + on_failure_jump; we got through the pattern to here from the |
| + matching on_failure_jump, so didn't fail. */ |
| + case pop_failure_jump: |
| + { |
| + /* We need to pass separate storage for the lowest and |
| + highest registers, even though we don't care about the |
| + actual values. Otherwise, we will restore only one |
| + register from the stack, since lowest will == highest in |
| + `pop_failure_point'. */ |
| + active_reg_t dummy_low_reg, dummy_high_reg; |
| + UCHAR_T *pdummy __attribute__ ((unused)) = NULL; |
| + const CHAR_T *sdummy __attribute__ ((unused)) = NULL; |
| + |
| + DEBUG_PRINT1 ("EXECUTING pop_failure_jump.\n"); |
| + POP_FAILURE_POINT (sdummy, pdummy, |
| + dummy_low_reg, dummy_high_reg, |
| + reg_dummy, reg_dummy, reg_info_dummy); |
| + } |
| + /* Note fall through. */ |
| + |
| + unconditional_jump: |
| +#ifdef _LIBC |
| + DEBUG_PRINT2 ("\n%p: ", p); |
| +#else |
| + DEBUG_PRINT2 ("\n0x%x: ", p); |
| +#endif |
| + /* Note fall through. */ |
| + |
| + /* Unconditionally jump (without popping any failure points). */ |
| + case jump: |
| + EXTRACT_NUMBER_AND_INCR (mcnt, p); /* Get the amount to jump. */ |
| + DEBUG_PRINT2 ("EXECUTING jump %d ", mcnt); |
| + p += mcnt; /* Do the jump. */ |
| +#ifdef _LIBC |
| + DEBUG_PRINT2 ("(to %p).\n", p); |
| +#else |
| + DEBUG_PRINT2 ("(to 0x%x).\n", p); |
| +#endif |
| + break; |
| + |
| + |
| + /* We need this opcode so we can detect where alternatives end |
| + in `group_match_null_string_p' et al. */ |
| + case jump_past_alt: |
| + DEBUG_PRINT1 ("EXECUTING jump_past_alt.\n"); |
| + goto unconditional_jump; |
| + |
| + |
| + /* Normally, the on_failure_jump pushes a failure point, which |
| + then gets popped at pop_failure_jump. We will end up at |
| + pop_failure_jump, also, and with a pattern of, say, `a+', we |
| + are skipping over the on_failure_jump, so we have to push |
| + something meaningless for pop_failure_jump to pop. */ |
| + case dummy_failure_jump: |
| + DEBUG_PRINT1 ("EXECUTING dummy_failure_jump.\n"); |
| + /* It doesn't matter what we push for the string here. What |
| + the code at `fail' tests is the value for the pattern. */ |
| + PUSH_FAILURE_POINT (NULL, NULL, -2); |
| + goto unconditional_jump; |
| + |
| + |
| + /* At the end of an alternative, we need to push a dummy failure |
| + point in case we are followed by a `pop_failure_jump', because |
| + we don't want the failure point for the alternative to be |
| + popped. For example, matching `(a|ab)*' against `aab' |
| + requires that we match the `ab' alternative. */ |
| + case push_dummy_failure: |
| + DEBUG_PRINT1 ("EXECUTING push_dummy_failure.\n"); |
| + /* See comments just above at `dummy_failure_jump' about the |
| + two zeroes. */ |
| + PUSH_FAILURE_POINT (NULL, NULL, -2); |
| + break; |
| + |
| + /* Have to succeed matching what follows at least n times. |
| + After that, handle like `on_failure_jump'. */ |
| + case succeed_n: |
| + EXTRACT_NUMBER (mcnt, p + OFFSET_ADDRESS_SIZE); |
| + DEBUG_PRINT2 ("EXECUTING succeed_n %d.\n", mcnt); |
| + |
| + assert (mcnt >= 0); |
| + /* Originally, this is how many times we HAVE to succeed. */ |
| + if (mcnt > 0) |
| + { |
| + mcnt--; |
| + p += OFFSET_ADDRESS_SIZE; |
| + STORE_NUMBER_AND_INCR (p, mcnt); |
| +#ifdef _LIBC |
| + DEBUG_PRINT3 (" Setting %p to %d.\n", p - OFFSET_ADDRESS_SIZE |
| + , mcnt); |
| +#else |
| + DEBUG_PRINT3 (" Setting 0x%x to %d.\n", p - OFFSET_ADDRESS_SIZE |
| + , mcnt); |
| +#endif |
| + } |
| + else if (mcnt == 0) |
| + { |
| +#ifdef _LIBC |
| + DEBUG_PRINT2 (" Setting two bytes from %p to no_op.\n", |
| + p + OFFSET_ADDRESS_SIZE); |
| +#else |
| + DEBUG_PRINT2 (" Setting two bytes from 0x%x to no_op.\n", |
| + p + OFFSET_ADDRESS_SIZE); |
| +#endif /* _LIBC */ |
| + |
| +#ifdef WCHAR |
| + p[1] = (UCHAR_T) no_op; |
| +#else |
| + p[2] = (UCHAR_T) no_op; |
| + p[3] = (UCHAR_T) no_op; |
| +#endif /* WCHAR */ |
| + goto on_failure; |
| + } |
| + break; |
| + |
| + case jump_n: |
| + EXTRACT_NUMBER (mcnt, p + OFFSET_ADDRESS_SIZE); |
| + DEBUG_PRINT2 ("EXECUTING jump_n %d.\n", mcnt); |
| + |
| + /* Originally, this is how many times we CAN jump. */ |
| + if (mcnt) |
| + { |
| + mcnt--; |
| + STORE_NUMBER (p + OFFSET_ADDRESS_SIZE, mcnt); |
| + |
| +#ifdef _LIBC |
| + DEBUG_PRINT3 (" Setting %p to %d.\n", p + OFFSET_ADDRESS_SIZE, |
| + mcnt); |
| +#else |
| + DEBUG_PRINT3 (" Setting 0x%x to %d.\n", p + OFFSET_ADDRESS_SIZE, |
| + mcnt); |
| +#endif /* _LIBC */ |
| + goto unconditional_jump; |
| + } |
| + /* If don't have to jump any more, skip over the rest of command. */ |
| + else |
| + p += 2 * OFFSET_ADDRESS_SIZE; |
| + break; |
| + |
| + case set_number_at: |
| + { |
| + DEBUG_PRINT1 ("EXECUTING set_number_at.\n"); |
| + |
| + EXTRACT_NUMBER_AND_INCR (mcnt, p); |
| + p1 = p + mcnt; |
| + EXTRACT_NUMBER_AND_INCR (mcnt, p); |
| +#ifdef _LIBC |
| + DEBUG_PRINT3 (" Setting %p to %d.\n", p1, mcnt); |
| +#else |
| + DEBUG_PRINT3 (" Setting 0x%x to %d.\n", p1, mcnt); |
| +#endif |
| + STORE_NUMBER (p1, mcnt); |
| + break; |
| + } |
| + |
| +#if 0 |
| + /* The DEC Alpha C compiler 3.x generates incorrect code for the |
| + test WORDCHAR_P (d - 1) != WORDCHAR_P (d) in the expansion of |
| + AT_WORD_BOUNDARY, so this code is disabled. Expanding the |
| + macro and introducing temporary variables works around the bug. */ |
| + |
| + case wordbound: |
| + DEBUG_PRINT1 ("EXECUTING wordbound.\n"); |
| + if (AT_WORD_BOUNDARY (d)) |
| + break; |
| + goto fail; |
| + |
| + case notwordbound: |
| + DEBUG_PRINT1 ("EXECUTING notwordbound.\n"); |
| + if (AT_WORD_BOUNDARY (d)) |
| + goto fail; |
| + break; |
| +#else |
| + case wordbound: |
| + { |
| + boolean prevchar, thischar; |
| + |
| + DEBUG_PRINT1 ("EXECUTING wordbound.\n"); |
| + if (AT_STRINGS_BEG (d) || AT_STRINGS_END (d)) |
| + break; |
| + |
| + prevchar = WORDCHAR_P (d - 1); |
| + thischar = WORDCHAR_P (d); |
| + if (prevchar != thischar) |
| + break; |
| + goto fail; |
| + } |
| + |
| + case notwordbound: |
| + { |
| + boolean prevchar, thischar; |
| + |
| + DEBUG_PRINT1 ("EXECUTING notwordbound.\n"); |
| + if (AT_STRINGS_BEG (d) || AT_STRINGS_END (d)) |
| + goto fail; |
| + |
| + prevchar = WORDCHAR_P (d - 1); |
| + thischar = WORDCHAR_P (d); |
| + if (prevchar != thischar) |
| + goto fail; |
| + break; |
| + } |
| +#endif |
| + |
| + case wordbeg: |
| + DEBUG_PRINT1 ("EXECUTING wordbeg.\n"); |
| + if (!AT_STRINGS_END (d) && WORDCHAR_P (d) |
| + && (AT_STRINGS_BEG (d) || !WORDCHAR_P (d - 1))) |
| + break; |
| + goto fail; |
| + |
| + case wordend: |
| + DEBUG_PRINT1 ("EXECUTING wordend.\n"); |
| + if (!AT_STRINGS_BEG (d) && WORDCHAR_P (d - 1) |
| + && (AT_STRINGS_END (d) || !WORDCHAR_P (d))) |
| + break; |
| + goto fail; |
| + |
| +#ifdef emacs |
| + case before_dot: |
| + DEBUG_PRINT1 ("EXECUTING before_dot.\n"); |
| + if (PTR_CHAR_POS ((unsigned char *) d) >= point) |
| + goto fail; |
| + break; |
| + |
| + case at_dot: |
| + DEBUG_PRINT1 ("EXECUTING at_dot.\n"); |
| + if (PTR_CHAR_POS ((unsigned char *) d) != point) |
| + goto fail; |
| + break; |
| + |
| + case after_dot: |
| + DEBUG_PRINT1 ("EXECUTING after_dot.\n"); |
| + if (PTR_CHAR_POS ((unsigned char *) d) <= point) |
| + goto fail; |
| + break; |
| + |
| + case syntaxspec: |
| + DEBUG_PRINT2 ("EXECUTING syntaxspec %d.\n", mcnt); |
| + mcnt = *p++; |
| + goto matchsyntax; |
| + |
| + case wordchar: |
| + DEBUG_PRINT1 ("EXECUTING Emacs wordchar.\n"); |
| + mcnt = (int) Sword; |
| + matchsyntax: |
| + PREFETCH (); |
| + /* Can't use *d++ here; SYNTAX may be an unsafe macro. */ |
| + d++; |
| + if (SYNTAX (d[-1]) != (enum syntaxcode) mcnt) |
| + goto fail; |
| + SET_REGS_MATCHED (); |
| + break; |
| + |
| + case notsyntaxspec: |
| + DEBUG_PRINT2 ("EXECUTING notsyntaxspec %d.\n", mcnt); |
| + mcnt = *p++; |
| + goto matchnotsyntax; |
| + |
| + case notwordchar: |
| + DEBUG_PRINT1 ("EXECUTING Emacs notwordchar.\n"); |
| + mcnt = (int) Sword; |
| + matchnotsyntax: |
| + PREFETCH (); |
| + /* Can't use *d++ here; SYNTAX may be an unsafe macro. */ |
| + d++; |
| + if (SYNTAX (d[-1]) == (enum syntaxcode) mcnt) |
| + goto fail; |
| + SET_REGS_MATCHED (); |
| + break; |
| + |
| +#else /* not emacs */ |
| + case wordchar: |
| + DEBUG_PRINT1 ("EXECUTING non-Emacs wordchar.\n"); |
| + PREFETCH (); |
| + if (!WORDCHAR_P (d)) |
| + goto fail; |
| + SET_REGS_MATCHED (); |
| + d++; |
| + break; |
| + |
| + case notwordchar: |
| + DEBUG_PRINT1 ("EXECUTING non-Emacs notwordchar.\n"); |
| + PREFETCH (); |
| + if (WORDCHAR_P (d)) |
| + goto fail; |
| + SET_REGS_MATCHED (); |
| + d++; |
| + break; |
| +#endif /* not emacs */ |
| + |
| + default: |
| + abort (); |
| + } |
| + continue; /* Successfully executed one pattern command; keep going. */ |
| + |
| + |
| + /* We goto here if a matching operation fails. */ |
| + fail: |
| + if (!FAIL_STACK_EMPTY ()) |
| + { /* A restart point is known. Restore to that state. */ |
| + DEBUG_PRINT1 ("\nFAIL:\n"); |
| + POP_FAILURE_POINT (d, p, |
| + lowest_active_reg, highest_active_reg, |
| + regstart, regend, reg_info); |
| + |
| + /* If this failure point is a dummy, try the next one. */ |
| + if (!p) |
| + goto fail; |
| + |
| + /* If we failed to the end of the pattern, don't examine *p. */ |
| + assert (p <= pend); |
| + if (p < pend) |
| + { |
| + boolean is_a_jump_n = false; |
| + |
| + /* If failed to a backwards jump that's part of a repetition |
| + loop, need to pop this failure point and use the next one. */ |
| + switch ((re_opcode_t) *p) |
| + { |
| + case jump_n: |
| + is_a_jump_n = true; |
| + case maybe_pop_jump: |
| + case pop_failure_jump: |
| + case jump: |
| + p1 = p + 1; |
| + EXTRACT_NUMBER_AND_INCR (mcnt, p1); |
| + p1 += mcnt; |
| + |
| + if ((is_a_jump_n && (re_opcode_t) *p1 == succeed_n) |
| + || (!is_a_jump_n |
| + && (re_opcode_t) *p1 == on_failure_jump)) |
| + goto fail; |
| + break; |
| + default: |
| + /* do nothing */ ; |
| + } |
| + } |
| + |
| + if (d >= string1 && d <= end1) |
| + dend = end_match_1; |
| + } |
| + else |
| + break; /* Matching at this starting point really fails. */ |
| + } /* for (;;) */ |
| + |
| + if (best_regs_set) |
| + goto restore_best_regs; |
| + |
| + FREE_VARIABLES (); |
| + |
| + return -1; /* Failure to match. */ |
| +} /* re_match_2 */ |
| + |
| +/* Subroutine definitions for re_match_2. */ |
| + |
| + |
| +/* We are passed P pointing to a register number after a start_memory. |
| + |
| + Return true if the pattern up to the corresponding stop_memory can |
| + match the empty string, and false otherwise. |
| + |
| + If we find the matching stop_memory, sets P to point to one past its number. |
| + Otherwise, sets P to an undefined byte less than or equal to END. |
| + |
| + We don't handle duplicates properly (yet). */ |
| + |
| +static boolean |
| +PREFIX(group_match_null_string_p) (UCHAR_T **p, UCHAR_T *end, |
| + PREFIX(register_info_type) *reg_info) |
| +{ |
| + int mcnt; |
| + /* Point to after the args to the start_memory. */ |
| + UCHAR_T *p1 = *p + 2; |
| + |
| + while (p1 < end) |
| + { |
| + /* Skip over opcodes that can match nothing, and return true or |
| + false, as appropriate, when we get to one that can't, or to the |
| + matching stop_memory. */ |
| + |
| + switch ((re_opcode_t) *p1) |
| + { |
| + /* Could be either a loop or a series of alternatives. */ |
| + case on_failure_jump: |
| + p1++; |
| + EXTRACT_NUMBER_AND_INCR (mcnt, p1); |
| + |
| + /* If the next operation is not a jump backwards in the |
| + pattern. */ |
| + |
| + if (mcnt >= 0) |
| + { |
| + /* Go through the on_failure_jumps of the alternatives, |
| + seeing if any of the alternatives cannot match nothing. |
| + The last alternative starts with only a jump, |
| + whereas the rest start with on_failure_jump and end |
| + with a jump, e.g., here is the pattern for `a|b|c': |
| + |
| + /on_failure_jump/0/6/exactn/1/a/jump_past_alt/0/6 |
| + /on_failure_jump/0/6/exactn/1/b/jump_past_alt/0/3 |
| + /exactn/1/c |
| + |
| + So, we have to first go through the first (n-1) |
| + alternatives and then deal with the last one separately. */ |
| + |
| + |
| + /* Deal with the first (n-1) alternatives, which start |
| + with an on_failure_jump (see above) that jumps to right |
| + past a jump_past_alt. */ |
| + |
| + while ((re_opcode_t) p1[mcnt-(1+OFFSET_ADDRESS_SIZE)] == |
| + jump_past_alt) |
| + { |
| + /* `mcnt' holds how many bytes long the alternative |
| + is, including the ending `jump_past_alt' and |
| + its number. */ |
| + |
| + if (!PREFIX(alt_match_null_string_p) (p1, p1 + mcnt - |
| + (1 + OFFSET_ADDRESS_SIZE), |
| + reg_info)) |
| + return false; |
| + |
| + /* Move to right after this alternative, including the |
| + jump_past_alt. */ |
| + p1 += mcnt; |
| + |
| + /* Break if it's the beginning of an n-th alternative |
| + that doesn't begin with an on_failure_jump. */ |
| + if ((re_opcode_t) *p1 != on_failure_jump) |
| + break; |
| + |
| + /* Still have to check that it's not an n-th |
| + alternative that starts with an on_failure_jump. */ |
| + p1++; |
| + EXTRACT_NUMBER_AND_INCR (mcnt, p1); |
| + if ((re_opcode_t) p1[mcnt-(1+OFFSET_ADDRESS_SIZE)] != |
| + jump_past_alt) |
| + { |
| + /* Get to the beginning of the n-th alternative. */ |
| + p1 -= 1 + OFFSET_ADDRESS_SIZE; |
| + break; |
| + } |
| + } |
| + |
| + /* Deal with the last alternative: go back and get number |
| + of the `jump_past_alt' just before it. `mcnt' contains |
| + the length of the alternative. */ |
| + EXTRACT_NUMBER (mcnt, p1 - OFFSET_ADDRESS_SIZE); |
| + |
| + if (!PREFIX(alt_match_null_string_p) (p1, p1 + mcnt, reg_info)) |
| + return false; |
| + |
| + p1 += mcnt; /* Get past the n-th alternative. */ |
| + } /* if mcnt > 0 */ |
| + break; |
| + |
| + |
| + case stop_memory: |
| + assert (p1[1] == **p); |
| + *p = p1 + 2; |
| + return true; |
| + |
| + |
| + default: |
| + if (!PREFIX(common_op_match_null_string_p) (&p1, end, reg_info)) |
| + return false; |
| + } |
| + } /* while p1 < end */ |
| + |
| + return false; |
| +} /* group_match_null_string_p */ |
| + |
| + |
| +/* Similar to group_match_null_string_p, but doesn't deal with alternatives: |
| + It expects P to be the first byte of a single alternative and END one |
| + byte past the last. The alternative can contain groups. */ |
| + |
| +static boolean |
| +PREFIX(alt_match_null_string_p) (UCHAR_T *p, UCHAR_T *end, |
| + PREFIX(register_info_type) *reg_info) |
| +{ |
| + int mcnt; |
| + UCHAR_T *p1 = p; |
| + |
| + while (p1 < end) |
| + { |
| + /* Skip over opcodes that can match nothing, and break when we get |
| + to one that can't. */ |
| + |
| + switch ((re_opcode_t) *p1) |
| + { |
| + /* It's a loop. */ |
| + case on_failure_jump: |
| + p1++; |
| + EXTRACT_NUMBER_AND_INCR (mcnt, p1); |
| + p1 += mcnt; |
| + break; |
| + |
| + default: |
| + if (!PREFIX(common_op_match_null_string_p) (&p1, end, reg_info)) |
| + return false; |
| + } |
| + } /* while p1 < end */ |
| + |
| + return true; |
| +} /* alt_match_null_string_p */ |
| + |
| + |
| +/* Deals with the ops common to group_match_null_string_p and |
| + alt_match_null_string_p. |
| + |
| + Sets P to one after the op and its arguments, if any. */ |
| + |
| +static boolean |
| +PREFIX(common_op_match_null_string_p) (UCHAR_T **p, UCHAR_T *end, |
| + PREFIX(register_info_type) *reg_info) |
| +{ |
| + int mcnt; |
| + boolean ret; |
| + int reg_no; |
| + UCHAR_T *p1 = *p; |
| + |
| + switch ((re_opcode_t) *p1++) |
| + { |
| + case no_op: |
| + case begline: |
| + case endline: |
| + case begbuf: |
| + case endbuf: |
| + case wordbeg: |
| + case wordend: |
| + case wordbound: |
| + case notwordbound: |
| +#ifdef emacs |
| + case before_dot: |
| + case at_dot: |
| + case after_dot: |
| +#endif |
| + break; |
| + |
| + case start_memory: |
| + reg_no = *p1; |
| + assert (reg_no > 0 && reg_no <= MAX_REGNUM); |
| + ret = PREFIX(group_match_null_string_p) (&p1, end, reg_info); |
| + |
| + /* Have to set this here in case we're checking a group which |
| + contains a group and a back reference to it. */ |
| + |
| + if (REG_MATCH_NULL_STRING_P (reg_info[reg_no]) == MATCH_NULL_UNSET_VALUE) |
| + REG_MATCH_NULL_STRING_P (reg_info[reg_no]) = ret; |
| + |
| + if (!ret) |
| + return false; |
| + break; |
| + |
| + /* If this is an optimized succeed_n for zero times, make the jump. */ |
| + case jump: |
| + EXTRACT_NUMBER_AND_INCR (mcnt, p1); |
| + if (mcnt >= 0) |
| + p1 += mcnt; |
| + else |
| + return false; |
| + break; |
| + |
| + case succeed_n: |
| + /* Get to the number of times to succeed. */ |
| + p1 += OFFSET_ADDRESS_SIZE; |
| + EXTRACT_NUMBER_AND_INCR (mcnt, p1); |
| + |
| + if (mcnt == 0) |
| + { |
| + p1 -= 2 * OFFSET_ADDRESS_SIZE; |
| + EXTRACT_NUMBER_AND_INCR (mcnt, p1); |
| + p1 += mcnt; |
| + } |
| + else |
| + return false; |
| + break; |
| + |
| + case duplicate: |
| + if (!REG_MATCH_NULL_STRING_P (reg_info[*p1])) |
| + return false; |
| + break; |
| + |
| + case set_number_at: |
| + p1 += 2 * OFFSET_ADDRESS_SIZE; |
| + |
| + default: |
| + /* All other opcodes mean we cannot match the empty string. */ |
| + return false; |
| + } |
| + |
| + *p = p1; |
| + return true; |
| +} /* common_op_match_null_string_p */ |
| + |
| + |
| +/* Return zero if TRANSLATE[S1] and TRANSLATE[S2] are identical for LEN |
| + bytes; nonzero otherwise. */ |
| + |
| +static int |
| +PREFIX(bcmp_translate) (const CHAR_T *s1, const CHAR_T *s2, register int len, |
| + RE_TRANSLATE_TYPE translate) |
| +{ |
| + register const UCHAR_T *p1 = (const UCHAR_T *) s1; |
| + register const UCHAR_T *p2 = (const UCHAR_T *) s2; |
| + while (len) |
| + { |
| +#ifdef WCHAR |
| + if (((*p1<=0xff)?translate[*p1++]:*p1++) |
| + != ((*p2<=0xff)?translate[*p2++]:*p2++)) |
| + return 1; |
| +#else /* BYTE */ |
| + if (translate[*p1++] != translate[*p2++]) return 1; |
| +#endif /* WCHAR */ |
| + len--; |
| + } |
| + return 0; |
| +} |
| + |
| + |
| +#else /* not INSIDE_RECURSION */ |
| + |
| +/* Entry points for GNU code. */ |
| + |
| +/* re_compile_pattern is the GNU regular expression compiler: it |
| + compiles PATTERN (of length SIZE) and puts the result in BUFP. |
| + Returns 0 if the pattern was valid, otherwise an error string. |
| + |
| + Assumes the `allocated' (and perhaps `buffer') and `translate' fields |
| + are set in BUFP on entry. |
| + |
| + We call regex_compile to do the actual compilation. */ |
| + |
| +const char * |
| +re_compile_pattern (const char *pattern, size_t length, |
| + struct re_pattern_buffer *bufp) |
| +{ |
| + reg_errcode_t ret; |
| + |
| + /* GNU code is written to assume at least RE_NREGS registers will be set |
| + (and at least one extra will be -1). */ |
| + bufp->regs_allocated = REGS_UNALLOCATED; |
| + |
| + /* And GNU code determines whether or not to get register information |
| + by passing null for the REGS argument to re_match, etc., not by |
| + setting no_sub. */ |
| + bufp->no_sub = 0; |
| + |
| + /* Match anchors at newline. */ |
| + bufp->newline_anchor = 1; |
| + |
| +# ifdef MBS_SUPPORT |
| + if (MB_CUR_MAX != 1) |
| + ret = wcs_regex_compile (pattern, length, re_syntax_options, bufp); |
| + else |
| +# endif |
| + ret = byte_regex_compile (pattern, length, re_syntax_options, bufp); |
| + |
| + if (!ret) |
| + return NULL; |
| + return gettext (re_error_msgid[(int) ret]); |
| +} |
| +#ifdef _LIBC |
| +weak_alias (__re_compile_pattern, re_compile_pattern) |
| +#endif |
| + |
| +/* Entry points compatible with 4.2 BSD regex library. We don't define |
| + them unless specifically requested. */ |
| + |
| +#if defined _REGEX_RE_COMP || defined _LIBC |
| + |
| +/* BSD has one and only one pattern buffer. */ |
| +static struct re_pattern_buffer re_comp_buf; |
| + |
| +char * |
| +#ifdef _LIBC |
| +/* Make these definitions weak in libc, so POSIX programs can redefine |
| + these names if they don't use our functions, and still use |
| + regcomp/regexec below without link errors. */ |
| +weak_function |
| +#endif |
| +re_comp (const char *s) |
| +{ |
| + reg_errcode_t ret; |
| + |
| + if (!s) |
| + { |
| + if (!re_comp_buf.buffer) |
| + return (char *) gettext ("No previous regular expression"); |
| + return 0; |
| + } |
| + |
| + if (!re_comp_buf.buffer) |
| + { |
| + re_comp_buf.buffer = (unsigned char *) malloc (200); |
| + if (re_comp_buf.buffer == NULL) |
| + return (char *) gettext (re_error_msgid[(int) REG_ESPACE]); |
| + re_comp_buf.allocated = 200; |
| + |
| + re_comp_buf.fastmap = (char *) malloc (1 << BYTEWIDTH); |
| + if (re_comp_buf.fastmap == NULL) |
| + return (char *) gettext (re_error_msgid[(int) REG_ESPACE]); |
| + } |
| + |
| + /* Since `re_exec' always passes NULL for the `regs' argument, we |
| + don't need to initialize the pattern buffer fields which affect it. */ |
| + |
| + /* Match anchors at newlines. */ |
| + re_comp_buf.newline_anchor = 1; |
| + |
| +# ifdef MBS_SUPPORT |
| + if (MB_CUR_MAX != 1) |
| + ret = wcs_regex_compile (s, strlen (s), re_syntax_options, &re_comp_buf); |
| + else |
| +# endif |
| + ret = byte_regex_compile (s, strlen (s), re_syntax_options, &re_comp_buf); |
| + |
| + if (!ret) |
| + return NULL; |
| + |
| + /* Yes, we're discarding `const' here if !HAVE_LIBINTL. */ |
| + return (char *) gettext (re_error_msgid[(int) ret]); |
| +} |
| + |
| + |
| +int |
| +#ifdef _LIBC |
| +weak_function |
| +#endif |
| +re_exec (const char *s) |
| +{ |
| + const int len = strlen (s); |
| + return |
| + 0 <= re_search (&re_comp_buf, s, len, 0, len, (struct re_registers *) 0); |
| +} |
| + |
| +#endif /* _REGEX_RE_COMP */ |
| + |
| +/* POSIX.2 functions. Don't define these for Emacs. */ |
| + |
| +#ifndef emacs |
| + |
| +/* regcomp takes a regular expression as a string and compiles it. |
| + |
| + PREG is a regex_t *. We do not expect any fields to be initialized, |
| + since POSIX says we shouldn't. Thus, we set |
| + |
| + `buffer' to the compiled pattern; |
| + `used' to the length of the compiled pattern; |
| + `syntax' to RE_SYNTAX_POSIX_EXTENDED if the |
| + REG_EXTENDED bit in CFLAGS is set; otherwise, to |
| + RE_SYNTAX_POSIX_BASIC; |
| + `newline_anchor' to REG_NEWLINE being set in CFLAGS; |
| + `fastmap' to an allocated space for the fastmap; |
| + `fastmap_accurate' to zero; |
| + `re_nsub' to the number of subexpressions in PATTERN. |
| + |
| + PATTERN is the address of the pattern string. |
| + |
| + CFLAGS is a series of bits which affect compilation. |
| + |
| + If REG_EXTENDED is set, we use POSIX extended syntax; otherwise, we |
| + use POSIX basic syntax. |
| + |
| + If REG_NEWLINE is set, then . and [^...] don't match newline. |
| + Also, regexec will try a match beginning after every newline. |
| + |
| + If REG_ICASE is set, then we considers upper- and lowercase |
| + versions of letters to be equivalent when matching. |
| + |
| + If REG_NOSUB is set, then when PREG is passed to regexec, that |
| + routine will report only success or failure, and nothing about the |
| + registers. |
| + |
| + It returns 0 if it succeeds, nonzero if it doesn't. (See regex.h for |
| + the return codes and their meanings.) */ |
| + |
| +int |
| +regcomp (regex_t *preg, const char *pattern, int cflags) |
| +{ |
| + reg_errcode_t ret; |
| + reg_syntax_t syntax |
| + = (cflags & REG_EXTENDED) ? |
| + RE_SYNTAX_POSIX_EXTENDED : RE_SYNTAX_POSIX_BASIC; |
| + |
| + /* regex_compile will allocate the space for the compiled pattern. */ |
| + preg->buffer = 0; |
| + preg->allocated = 0; |
| + preg->used = 0; |
| + |
| + /* Try to allocate space for the fastmap. */ |
| + preg->fastmap = (char *) malloc (1 << BYTEWIDTH); |
| + |
| + if (cflags & REG_ICASE) |
| + { |
| + int i; |
| + |
| + preg->translate |
| + = (RE_TRANSLATE_TYPE) malloc (CHAR_SET_SIZE |
| + * sizeof (*(RE_TRANSLATE_TYPE)0)); |
| + if (preg->translate == NULL) |
| + return (int) REG_ESPACE; |
| + |
| + /* Map uppercase characters to corresponding lowercase ones. */ |
| + for (i = 0; i < CHAR_SET_SIZE; i++) |
| + preg->translate[i] = ISUPPER (i) ? TOLOWER (i) : i; |
| + } |
| + else |
| + preg->translate = NULL; |
| + |
| + /* If REG_NEWLINE is set, newlines are treated differently. */ |
| + if (cflags & REG_NEWLINE) |
| + { /* REG_NEWLINE implies neither . nor [^...] match newline. */ |
| + syntax &= ~RE_DOT_NEWLINE; |
| + syntax |= RE_HAT_LISTS_NOT_NEWLINE; |
| + /* It also changes the matching behavior. */ |
| + preg->newline_anchor = 1; |
| + } |
| + else |
| + preg->newline_anchor = 0; |
| + |
| + preg->no_sub = !!(cflags & REG_NOSUB); |
| + |
| + /* POSIX says a null character in the pattern terminates it, so we |
| + can use strlen here in compiling the pattern. */ |
| +# ifdef MBS_SUPPORT |
| + if (MB_CUR_MAX != 1) |
| + ret = wcs_regex_compile (pattern, strlen (pattern), syntax, preg); |
| + else |
| +# endif |
| + ret = byte_regex_compile (pattern, strlen (pattern), syntax, preg); |
| + |
| + /* POSIX doesn't distinguish between an unmatched open-group and an |
| + unmatched close-group: both are REG_EPAREN. */ |
| + if (ret == REG_ERPAREN) ret = REG_EPAREN; |
| + |
| + if (ret == REG_NOERROR && preg->fastmap) |
| + { |
| + /* Compute the fastmap now, since regexec cannot modify the pattern |
| + buffer. */ |
| + if (re_compile_fastmap (preg) == -2) |
| + { |
| + /* Some error occurred while computing the fastmap, just forget |
| + about it. */ |
| + free (preg->fastmap); |
| + preg->fastmap = NULL; |
| + } |
| + } |
| + |
| + return (int) ret; |
| +} |
| +#ifdef _LIBC |
| +weak_alias (__regcomp, regcomp) |
| +#endif |
| + |
| + |
| +/* regexec searches for a given pattern, specified by PREG, in the |
| + string STRING. |
| + |
| + If NMATCH is zero or REG_NOSUB was set in the cflags argument to |
| + `regcomp', we ignore PMATCH. Otherwise, we assume PMATCH has at |
| + least NMATCH elements, and we set them to the offsets of the |
| + corresponding matched substrings. |
| + |
| + EFLAGS specifies `execution flags' which affect matching: if |
| + REG_NOTBOL is set, then ^ does not match at the beginning of the |
| + string; if REG_NOTEOL is set, then $ does not match at the end. |
| + |
| + We return 0 if we find a match and REG_NOMATCH if not. */ |
| + |
| +int |
| +regexec (const regex_t *preg, const char *string, size_t nmatch, |
| + regmatch_t pmatch[], int eflags) |
| +{ |
| + int ret; |
| + struct re_registers regs; |
| + regex_t private_preg; |
| + int len = strlen (string); |
| + boolean want_reg_info = !preg->no_sub && nmatch > 0; |
| + |
| + private_preg = *preg; |
| + |
| + private_preg.not_bol = !!(eflags & REG_NOTBOL); |
| + private_preg.not_eol = !!(eflags & REG_NOTEOL); |
| + |
| + /* The user has told us exactly how many registers to return |
| + information about, via `nmatch'. We have to pass that on to the |
| + matching routines. */ |
| + private_preg.regs_allocated = REGS_FIXED; |
| + |
| + if (want_reg_info) |
| + { |
| + regs.num_regs = nmatch; |
| + regs.start = TALLOC (nmatch * 2, regoff_t); |
| + if (regs.start == NULL) |
| + return (int) REG_NOMATCH; |
| + regs.end = regs.start + nmatch; |
| + } |
| + |
| + /* Perform the searching operation. */ |
| + ret = re_search (&private_preg, string, len, |
| + /* start: */ 0, /* range: */ len, |
| + want_reg_info ? ®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 |
| diff --git a/pwd/Makefile b/pwd/Makefile |
| index 7f6de03..916d546 100644 |
| --- a/pwd/Makefile |
| +++ b/pwd/Makefile |
| @@ -18,6 +18,8 @@ |
| # |
| # Sub-makefile for pwd portion of the library. |
| # |
| +include ../option-groups.mak |
| + |
| subdir := pwd |
| |
| include ../Makeconfig |
| diff --git a/resolv/Makefile b/resolv/Makefile |
| index 1dcb75f..2e4b630 100644 |
| --- a/resolv/Makefile |
| +++ b/resolv/Makefile |
| @@ -18,6 +18,8 @@ |
| # |
| # Sub-makefile for resolv portion of the library. |
| # |
| +include ../option-groups.mak |
| + |
| subdir := resolv |
| |
| include ../Makeconfig |
| @@ -27,21 +29,22 @@ headers := resolv.h \ |
| arpa/nameser.h arpa/nameser_compat.h \ |
| sys/bitypes.h |
| |
| -routines := herror inet_addr inet_ntop inet_pton nsap_addr res_init \ |
| - res_hconf res_libc res-state |
| +routines-$(OPTION_EGLIBC_INET) \ |
| + += herror inet_addr inet_ntop inet_pton nsap_addr res_init \ |
| + res_hconf res_libc res-state |
| |
| -tests = tst-aton tst-leaks tst-inet_ntop |
| -xtests = tst-leaks2 |
| +tests-$(OPTION_EGLIBC_INET) += tst-aton tst-leaks tst-inet_ntop |
| +xtests-$(OPTION_EGLIBC_INET) += tst-leaks2 |
| |
| generate := mtrace-tst-leaks.out tst-leaks.mtrace tst-leaks2.mtrace |
| |
| -extra-libs := libresolv libnss_dns |
| +extra-libs-$(OPTION_EGLIBC_INET) += libresolv libnss_dns |
| ifeq ($(have-thread-library),yes) |
| -extra-libs += libanl |
| -routines += gai_sigqueue |
| +extra-libs-$(OPTION_EGLIBC_INET_ANL) += libanl |
| +routines-$(OPTION_EGLIBC_INET) += gai_sigqueue |
| tests += tst-res_hconf_reorder |
| 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 \ |
| @@ -61,7 +64,7 @@ routines += $(libnss_dns-routines) $(libresolv-routines) |
| 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 |
| |
| diff --git a/stdio-common/Makefile b/stdio-common/Makefile |
| index d0bf0e1..8655801 100644 |
| --- a/stdio-common/Makefile |
| +++ b/stdio-common/Makefile |
| @@ -18,6 +18,8 @@ |
| # |
| # Specific makefile for stdio-common. |
| # |
| +include ../option-groups.mak |
| + |
| subdir := stdio-common |
| |
| include ../Makeconfig |
| @@ -30,7 +32,7 @@ routines := \ |
| vfprintf vprintf printf_fp reg-printf printf-prs printf_fphex \ |
| reg-modifier reg-type \ |
| printf_size fprintf printf snprintf sprintf asprintf dprintf \ |
| - vfwprintf vfscanf vfwscanf \ |
| + vfscanf \ |
| fscanf scanf sscanf \ |
| perror psignal \ |
| tmpfile tmpfile64 tmpnam tmpnam_r tempnam tempname \ |
| @@ -41,23 +43,36 @@ routines := \ |
| isoc99_vsscanf \ |
| psiginfo |
| |
| -aux := errlist siglist printf-parsemb printf-parsewc fxprintf |
| +# Ideally, _itowa and itowa-digits would be in this option group as |
| +# well, but it is used unconditionally by printf_fp and printf_fphex, |
| +# and it didn't seem straightforward to disentangle it. |
| +routines-$(OPTION_POSIX_C_LANG_WIDE_CHAR) \ |
| + += vfwprintf vfwscanf |
| + |
| +aux := errlist siglist printf-parsemb fxprintf |
| +aux-$(OPTION_POSIX_C_LANG_WIDE_CHAR) += printf-parsewc |
| |
| tests := tstscanf test_rdwr test-popen tstgetln test-fseek \ |
| temptest tst-fileno test-fwrite tst-ungetc tst-ferror \ |
| xbug errnobug \ |
| bug1 bug2 bug3 bug4 bug5 bug6 bug7 bug8 bug9 bug10 bug11 bug12 bug13 \ |
| - tfformat tiformat tllformat tstdiomisc tst-printfsz tst-wc-printf \ |
| + tfformat tiformat tllformat tstdiomisc tst-printfsz \ |
| scanf1 scanf2 scanf3 scanf4 scanf5 scanf7 scanf8 scanf9 scanf10 \ |
| - scanf11 scanf12 tst-tmpnam tst-cookie tst-obprintf tst-sscanf \ |
| - tst-swprintf tst-fseek tst-fmemopen test-vfprintf tst-gets \ |
| - tst-perror tst-sprintf tst-rndseek tst-fdopen tst-fphex bug14 \ |
| + scanf11 scanf12 tst-tmpnam tst-cookie tst-obprintf \ |
| + tst-fseek tst-fmemopen tst-gets \ |
| + tst-sprintf tst-rndseek tst-fdopen tst-fphex \ |
| tst-popen tst-unlockedio tst-fmemopen2 tst-put-error tst-fgets \ |
| - tst-fwrite bug16 bug17 tst-swscanf tst-sprintf2 bug18 bug18a \ |
| - bug19 bug19a tst-popen2 scanf13 scanf14 scanf15 bug20 bug21 bug22 \ |
| - scanf16 scanf17 tst-setvbuf1 tst-grouping bug23 bug24 \ |
| - bug-vfprintf-nargs tst-long-dbl-fphex tst-fphex-wide tst-sprintf3 \ |
| + tst-fwrite bug16 bug17 tst-sprintf2 bug18 \ |
| + bug19 tst-popen2 scanf14 scanf15 bug21 bug22 \ |
| + scanf16 scanf17 tst-setvbuf1 bug23 bug24 \ |
| + bug-vfprintf-nargs tst-sprintf3 \ |
| bug25 tst-printf-round bug23-2 bug23-3 bug23-4 bug26 tst-fmemopen3 |
| +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 |
| |
| diff --git a/stdio-common/_i18n_number.h b/stdio-common/_i18n_number.h |
| index 3c73044..ac62b3a 100644 |
| --- a/stdio-common/_i18n_number.h |
| +++ b/stdio-common/_i18n_number.h |
| @@ -19,10 +19,13 @@ |
| #include <stdbool.h> |
| #include <wchar.h> |
| #include <wctype.h> |
| +#include <gnu/option-groups.h> |
| |
| #include "../locale/outdigits.h" |
| #include "../locale/outdigitswc.h" |
| |
| +#if __OPTION_EGLIBC_LOCALE_CODE |
| + |
| static CHAR_T * |
| _i18n_number_rewrite (CHAR_T *w, CHAR_T *rear_ptr, CHAR_T *end) |
| { |
| @@ -115,3 +118,13 @@ _i18n_number_rewrite (CHAR_T *w, CHAR_T *rear_ptr, CHAR_T *end) |
| |
| return w; |
| } |
| + |
| +#else |
| + |
| +static CHAR_T * |
| +_i18n_number_rewrite (CHAR_T *w, CHAR_T *rear_ptr, CHAR_T *end) |
| +{ |
| + return w; |
| +} |
| + |
| +#endif |
| diff --git a/stdio-common/fxprintf.c b/stdio-common/fxprintf.c |
| index 7b2eb94..8476076 100644 |
| --- a/stdio-common/fxprintf.c |
| +++ b/stdio-common/fxprintf.c |
| @@ -23,6 +23,7 @@ |
| #include <wchar.h> |
| #include <string.h> |
| #include <libioP.h> |
| +#include <gnu/option-groups.h> |
| |
| |
| int |
| @@ -37,6 +38,7 @@ __fxprintf (FILE *fp, const char *fmt, ...) |
| int res; |
| if (_IO_fwide (fp, 0) > 0) |
| { |
| +#if __OPTION_POSIX_WIDE_CHAR_DEVICE_IO |
| size_t len = strlen (fmt) + 1; |
| wchar_t wfmt[len]; |
| for (size_t i = 0; i < len; ++i) |
| @@ -45,6 +47,9 @@ __fxprintf (FILE *fp, const char *fmt, ...) |
| wfmt[i] = fmt[i]; |
| } |
| res = __vfwprintf (fp, wfmt, ap); |
| +#else |
| + abort(); |
| +#endif |
| } |
| else |
| res = _IO_vfprintf (fp, fmt, ap); |
| diff --git a/stdio-common/printf_fp.c b/stdio-common/printf_fp.c |
| index 3023b20..bd0df66 100644 |
| --- a/stdio-common/printf_fp.c |
| +++ b/stdio-common/printf_fp.c |
| @@ -39,6 +39,7 @@ |
| #include <unistd.h> |
| #include <stdlib.h> |
| #include <wchar.h> |
| +#include <gnu/option-groups.h> |
| #include <stdbool.h> |
| #include <rounding-mode.h> |
| |
| @@ -142,6 +143,10 @@ extern mp_size_t __mpn_extract_long_double (mp_ptr res_ptr, mp_size_t size, |
| extern unsigned int __guess_grouping (unsigned int intdig_max, |
| const char *grouping); |
| |
| +/* Ideally, when OPTION_EGLIBC_LOCALE_CODE is disabled, this should do |
| + all its work in ordinary characters, rather than doing it in wide |
| + characters and then converting at the end. But that is a challenge |
| + for another day. */ |
| |
| static wchar_t *group_number (wchar_t *buf, wchar_t *bufend, |
| unsigned int intdig_no, const char *grouping, |
| @@ -251,7 +256,14 @@ ___printf_fp (FILE *fp, |
| mp_limb_t cy; |
| |
| /* Nonzero if this is output on a wide character stream. */ |
| +#if __OPTION_POSIX_C_LANG_WIDE_CHAR |
| int wide = info->wide; |
| +#else |
| + /* This should never be called on a wide-oriented stream when |
| + OPTION_POSIX_C_LANG_WIDE_CHAR is disabled, but the compiler can't |
| + be trusted to figure that out. */ |
| + const int wide = 0; |
| +#endif |
| |
| /* Buffer in which we produce the output. */ |
| wchar_t *wbuffer = NULL; |
| @@ -261,6 +273,7 @@ ___printf_fp (FILE *fp, |
| p.expsign = 0; |
| |
| /* Figure out the decimal point character. */ |
| +#if __OPTION_EGLIBC_LOCALE_CODE |
| if (info->extra == 0) |
| { |
| decimal = _NL_CURRENT (LC_NUMERIC, DECIMAL_POINT); |
| @@ -280,7 +293,13 @@ ___printf_fp (FILE *fp, |
| /* The decimal point character must not be zero. */ |
| assert (*decimal != '\0'); |
| assert (decimalwc != L'\0'); |
| +#else |
| + /* Hard-code values from 'C' locale. */ |
| + decimal = "."; |
| + decimalwc = L'.'; |
| +#endif |
| |
| +#if __OPTION_EGLIBC_LOCALE_CODE |
| if (info->group) |
| { |
| if (info->extra == 0) |
| @@ -324,6 +343,9 @@ ___printf_fp (FILE *fp, |
| } |
| else |
| grouping = NULL; |
| +#else |
| + grouping = NULL; |
| +#endif |
| |
| /* Fetch the argument value. */ |
| #ifndef __NO_LONG_DOUBLE_MATH |
| diff --git a/stdio-common/printf_fphex.c b/stdio-common/printf_fphex.c |
| index 6c3b5e9..f660ce0 100644 |
| --- a/stdio-common/printf_fphex.c |
| +++ b/stdio-common/printf_fphex.c |
| @@ -28,6 +28,7 @@ |
| #include <_itoa.h> |
| #include <_itowa.h> |
| #include <locale/localeinfo.h> |
| +#include <gnu/option-groups.h> |
| #include <stdbool.h> |
| #include <rounding-mode.h> |
| |
| @@ -139,10 +140,18 @@ __printf_fphex (FILE *fp, |
| int done = 0; |
| |
| /* Nonzero if this is output on a wide character stream. */ |
| +#if __OPTION_POSIX_C_LANG_WIDE_CHAR |
| int wide = info->wide; |
| +#else |
| + /* This should never be called on a wide-oriented stream when |
| + OPTION_POSIX_C_LANG_WIDE_CHAR is disabled, but the compiler can't |
| + be trusted to figure that out. */ |
| + const int wide = 0; |
| +#endif |
| |
| |
| /* Figure out the decimal point character. */ |
| +#if __OPTION_EGLIBC_LOCALE_CODE |
| if (info->extra == 0) |
| { |
| decimal = _NL_CURRENT (LC_NUMERIC, DECIMAL_POINT); |
| @@ -156,6 +165,10 @@ __printf_fphex (FILE *fp, |
| } |
| /* The decimal point character must never be zero. */ |
| assert (*decimal != '\0' && decimalwc != L'\0'); |
| +#else |
| + decimal = "."; |
| + decimalwc = L'.'; |
| +#endif |
| |
| |
| /* Fetch the argument value. */ |
| diff --git a/stdio-common/printf_size.c b/stdio-common/printf_size.c |
| index 7dcd58e..6fb7491 100644 |
| --- a/stdio-common/printf_size.c |
| +++ b/stdio-common/printf_size.c |
| @@ -23,6 +23,7 @@ |
| #include <math.h> |
| #include <printf.h> |
| #include <libioP.h> |
| +#include <gnu/option-groups.h> |
| |
| |
| /* This defines make it possible to use the same code for GNU C library and |
| @@ -116,7 +117,14 @@ __printf_size (FILE *fp, const struct printf_info *info, |
| |
| 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. */ |
| diff --git a/stdio-common/scanf14.c b/stdio-common/scanf14.c |
| index cffccb0..6cc260a 100644 |
| --- a/stdio-common/scanf14.c |
| +++ b/stdio-common/scanf14.c |
| @@ -3,6 +3,7 @@ |
| #include <string.h> |
| #include <wchar.h> |
| #include <libc-internal.h> |
| +#include <gnu/option-groups.h> |
| |
| #define FAIL() \ |
| do { \ |
| @@ -48,6 +49,7 @@ main (void) |
| /* See explanation above. */ |
| DIAG_PUSH_NEEDS_COMMENT; |
| DIAG_IGNORE_NEEDS_COMMENT (4.9, "-Wformat"); |
| +#if __OPTION_EGLIBC_LOCALE_CODE |
| if (sscanf (" 3.25S x", "%4aS%3c", &lsp, c) != 2) |
| FAIL (); |
| else |
| @@ -57,6 +59,7 @@ main (void) |
| memset (lsp, 'x', sizeof L"3.25"); |
| free (lsp); |
| } |
| +#endif |
| if (sscanf ("4.25[0-9.] x", "%a[0-9.]%8c", &sp, c) != 2) |
| FAIL (); |
| else |
| diff --git a/stdio-common/tst-popen.c b/stdio-common/tst-popen.c |
| index 5def27f..7c9b91e 100644 |
| --- a/stdio-common/tst-popen.c |
| +++ b/stdio-common/tst-popen.c |
| @@ -19,6 +19,7 @@ |
| #include <stdio.h> |
| #include <string.h> |
| #include <wchar.h> |
| +#include <gnu/option-groups.h> |
| |
| static int |
| do_test (void) |
| @@ -34,12 +35,14 @@ do_test (void) |
| return 1; |
| } |
| |
| +#if __OPTION_POSIX_WIDE_CHAR_DEVICE_IO |
| /* POSIX says that pipe streams are byte-oriented. */ |
| if (fwide (f, 0) >= 0) |
| { |
| puts ("popen did not return byte-oriented stream"); |
| result = 1; |
| } |
| +#endif |
| |
| if (getline (&line, &len, f) != 5) |
| { |
| diff --git a/stdio-common/tst-sprintf.c b/stdio-common/tst-sprintf.c |
| index d5284b9..f1e3d21 100644 |
| --- a/stdio-common/tst-sprintf.c |
| +++ b/stdio-common/tst-sprintf.c |
| @@ -3,7 +3,7 @@ |
| #include <locale.h> |
| #include <string.h> |
| #include <libc-internal.h> |
| - |
| +#include <gnu/option-groups.h> |
| |
| static int |
| do_test (void) |
| @@ -11,12 +11,14 @@ do_test (void) |
| char buf[100]; |
| int result = 0; |
| |
| +#if __OPTION_POSIX_C_LANG_WIDE_CHAR |
| if (sprintf (buf, "%.0ls", L"foo") != 0 |
| || strlen (buf) != 0) |
| { |
| puts ("sprintf (buf, \"%.0ls\", L\"foo\") produced some output"); |
| result = 1; |
| } |
| +#endif /* __OPTION_POSIX_C_LANG_WIDE_CHAR */ |
| |
| #define SIZE (1024*70000) |
| #define STR(x) #x |
| diff --git a/stdio-common/tstdiomisc.c b/stdio-common/tstdiomisc.c |
| index 5548a71..31ed024 100644 |
| --- a/stdio-common/tstdiomisc.c |
| +++ b/stdio-common/tstdiomisc.c |
| @@ -4,6 +4,7 @@ |
| #include <string.h> |
| #include <wchar.h> |
| #include <libc-internal.h> |
| +#include <gnu/option-groups.h> |
| |
| static int |
| t1 (void) |
| @@ -134,6 +135,7 @@ F (void) |
| printf ("expected \"-inf -INF -inf -INF -inf -INF -inf -INF\", got \"%s\"\n", |
| buf); |
| |
| +#if __OPTION_POSIX_C_LANG_WIDE_CHAR |
| swprintf (wbuf, sizeof wbuf / sizeof (wbuf[0]), L"%a %A %e %E %f %F %g %G", |
| qnanval, qnanval, qnanval, qnanval, |
| qnanval, qnanval, qnanval, qnanval); |
| @@ -171,6 +173,7 @@ F (void) |
| result |= wcscmp (wbuf, L"-inf -INF -inf -INF -inf -INF -inf -INF") != 0; |
| printf ("expected L\"-inf -INF -inf -INF -inf -INF -inf -INF\", got L\"%S\"\n", |
| wbuf); |
| +#endif /* __OPTION_POSIX_C_LANG_WIDE_CHAR */ |
| |
| lqnanval = NAN; |
| |
| @@ -215,6 +218,7 @@ F (void) |
| printf ("expected \"-inf -INF -inf -INF -inf -INF -inf -INF\", got \"%s\"\n", |
| buf); |
| |
| +#if __OPTION_POSIX_C_LANG_WIDE_CHAR |
| swprintf (wbuf, sizeof wbuf / sizeof (wbuf[0]), |
| L"%La %LA %Le %LE %Lf %LF %Lg %LG", |
| lqnanval, lqnanval, lqnanval, lqnanval, |
| @@ -259,6 +263,7 @@ F (void) |
| result |= wcscmp (wbuf, L"-inf -INF -inf -INF -inf -INF -inf -INF") != 0; |
| printf ("expected L\"-inf -INF -inf -INF -inf -INF -inf -INF\", got L\"%S\"\n", |
| wbuf); |
| +#endif /* __OPTION_POSIX_C_LANG_WIDE_CHAR */ |
| |
| return result; |
| } |
| diff --git a/stdio-common/vfprintf.c b/stdio-common/vfprintf.c |
| index 0592e70..f21d973 100644 |
| --- a/stdio-common/vfprintf.c |
| +++ b/stdio-common/vfprintf.c |
| @@ -29,6 +29,7 @@ |
| #include <_itoa.h> |
| #include <locale/localeinfo.h> |
| #include <stdio.h> |
| +#include <gnu/option-groups.h> |
| |
| /* This code is shared between the standard stdio implementation found |
| in GNU C library and the libio implementation originally found in |
| @@ -140,6 +141,18 @@ typedef wchar_t THOUSANDS_SEP_T; |
| # 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. */ |
| @@ -1065,8 +1078,11 @@ static const uint8_t jump_table[] = |
| # 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 (' '); \ |
| @@ -1079,6 +1095,7 @@ static const uint8_t jump_table[] = |
| break; \ |
| \ |
| LABEL (form_wcharacter): \ |
| + assert (MULTIBYTE_SUPPORT); \ |
| { \ |
| /* Wide character. */ \ |
| char buf[MB_CUR_MAX]; \ |
| @@ -1145,6 +1162,7 @@ static const uint8_t jump_table[] = |
| } \ |
| else \ |
| { \ |
| + assert (MULTIBYTE_SUPPORT); \ |
| const wchar_t *s2 = (const wchar_t *) string; \ |
| mbstate_t mbstate; \ |
| \ |
| @@ -1399,7 +1417,9 @@ vfprintf (FILE *s, const CHAR_T *format, va_list ap) |
| 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, |
| @@ -1728,8 +1748,9 @@ printf_positional (_IO_FILE *s, const CHAR_T *format, int readonly_format, |
| size_t cnt; |
| |
| CHAR_T *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, |
| diff --git a/stdio-common/vfscanf.c b/stdio-common/vfscanf.c |
| index 0e204e7..66cc0af 100644 |
| --- a/stdio-common/vfscanf.c |
| +++ b/stdio-common/vfscanf.c |
| @@ -29,6 +29,7 @@ |
| #include <wctype.h> |
| #include <bits/libc-lock.h> |
| #include <locale/localeinfo.h> |
| +#include <gnu/option-groups.h> |
| |
| #ifdef __GNUC__ |
| # define HAVE_LONGLONG |
| @@ -133,6 +134,12 @@ |
| # define WINT_T int |
| #endif |
| |
| +#if __OPTION_POSIX_C_LANG_WIDE_CHAR |
| +# define MULTIBYTE_SUPPORT (1) |
| +#else |
| +# define MULTIBYTE_SUPPORT (0) |
| +#endif |
| + |
| #define encode_error() do { \ |
| errval = 4; \ |
| __set_errno (EILSEQ); \ |
| @@ -316,24 +323,35 @@ _IO_vfscanf_internal (_IO_FILE *s, const char *format, _IO_va_list argptr, |
| ARGCHECK (s, format); |
| |
| { |
| -#ifndef COMPILE_WSCANF |
| +#if __OPTION_EGLIBC_LOCALE_CODE && !defined (COMPILE_WSCANF) |
| struct __locale_data *const curnumeric = loc->__locales[LC_NUMERIC]; |
| #endif |
| |
| +#if __OPTION_EGLIBC_LOCALE_CODE |
| /* Figure out the decimal point character. */ |
| -#ifdef COMPILE_WSCANF |
| +# ifdef COMPILE_WSCANF |
| decimal = _NL_CURRENT_WORD (LC_NUMERIC, _NL_NUMERIC_DECIMAL_POINT_WC); |
| -#else |
| +# else |
| decimal = curnumeric->values[_NL_ITEM_INDEX (DECIMAL_POINT)].string; |
| -#endif |
| +# endif |
| /* Figure out the thousands separator character. */ |
| -#ifdef COMPILE_WSCANF |
| +# ifdef COMPILE_WSCANF |
| thousands = _NL_CURRENT_WORD (LC_NUMERIC, _NL_NUMERIC_THOUSANDS_SEP_WC); |
| -#else |
| +# else |
| thousands = curnumeric->values[_NL_ITEM_INDEX (THOUSANDS_SEP)].string; |
| if (*thousands == '\0') |
| thousands = NULL; |
| -#endif |
| +# endif |
| +#else /* if ! __OPTION_EGLIBC_LOCALE_CODE */ |
| + /* Hard-code values from the C locale. */ |
| +# ifdef COMPILE_WSCANF |
| + decimal = L'.'; |
| + thousands = L'\0'; |
| +# else |
| + decimal = "."; |
| + thousands = NULL; |
| +# endif |
| +#endif /* __OPTION_EGLIBC_LOCALE_CODE */ |
| } |
| |
| /* Lock the stream. */ |
| @@ -385,6 +403,8 @@ _IO_vfscanf_internal (_IO_FILE *s, const char *format, _IO_va_list argptr, |
| #ifndef COMPILE_WSCANF |
| if (!isascii ((unsigned char) *f)) |
| { |
| + assert (MULTIBYTE_SUPPORT); |
| + |
| /* Non-ASCII, may be a multibyte. */ |
| int len = __mbrlen (f, strlen (f), &state); |
| if (len > 0) |
| @@ -830,6 +850,8 @@ _IO_vfscanf_internal (_IO_FILE *s, const char *format, _IO_va_list argptr, |
| } |
| /* FALLTHROUGH */ |
| case L_('C'): |
| + assert (MULTIBYTE_SUPPORT); |
| + |
| if (width == -1) |
| width = 1; |
| |
| @@ -1172,6 +1194,8 @@ _IO_vfscanf_internal (_IO_FILE *s, const char *format, _IO_va_list argptr, |
| /* FALLTHROUGH */ |
| |
| case L_('S'): |
| + assert (MULTIBYTE_SUPPORT); |
| + |
| { |
| #ifndef COMPILE_WSCANF |
| mbstate_t cstate; |
| @@ -1419,10 +1443,17 @@ _IO_vfscanf_internal (_IO_FILE *s, const char *format, _IO_va_list argptr, |
| const char *mbdigits[10]; |
| const char *mbdigits_extended[10]; |
| #endif |
| +#if __OPTION_EGLIBC_LOCALE_CODE |
| /* "to_inpunct" is a map from ASCII digits to their |
| equivalent in locale. This is defined for locales |
| which use an extra digits set. */ |
| wctrans_t map = __wctrans ("to_inpunct"); |
| +#else |
| + /* This will always be the case when |
| + OPTION_EGLIBC_LOCALE_CODE is disabled, but the |
| + compiler can't figure that out. */ |
| + wctrans_t map = NULL; |
| +#endif |
| int n; |
| |
| from_level = 0; |
| @@ -2088,6 +2119,7 @@ _IO_vfscanf_internal (_IO_FILE *s, const char *format, _IO_va_list argptr, |
| --width; |
| } |
| |
| +#if __OPTION_EGLIBC_LOCALE_CODE |
| wctrans_t map; |
| if (__builtin_expect ((flags & I18N) != 0, 0) |
| /* Hexadecimal floats make no sense, fixing localized |
| @@ -2304,6 +2336,7 @@ _IO_vfscanf_internal (_IO_FILE *s, const char *format, _IO_va_list argptr, |
| ; |
| #endif |
| } |
| +#endif /* __OPTION_EGLIBC_LOCALE_CODE */ |
| |
| /* Have we read any character? If we try to read a number |
| in hexadecimal notation and we have read only the `0x' |
| @@ -2343,7 +2376,10 @@ _IO_vfscanf_internal (_IO_FILE *s, const char *format, _IO_va_list argptr, |
| |
| case L_('['): /* Character class. */ |
| if (flags & LONG) |
| - STRING_ARG (wstr, wchar_t, 100); |
| + { |
| + assert (MULTIBYTE_SUPPORT); |
| + STRING_ARG (wstr, wchar_t, 100); |
| + } |
| else |
| STRING_ARG (str, char, 100); |
| |
| @@ -2417,6 +2453,7 @@ _IO_vfscanf_internal (_IO_FILE *s, const char *format, _IO_va_list argptr, |
| if (flags & LONG) |
| { |
| size_t now = read_in; |
| + assert (MULTIBYTE_SUPPORT); |
| #ifdef COMPILE_WSCANF |
| if (__glibc_unlikely (inchar () == WEOF)) |
| input_error (); |
| diff --git a/stdlib/Makefile b/stdlib/Makefile |
| index 402466a..7e7e304 100644 |
| --- a/stdlib/Makefile |
| +++ b/stdlib/Makefile |
| @@ -18,6 +18,8 @@ |
| # |
| # Makefile for stdlib routines |
| # |
| +include ../option-groups.mak |
| + |
| subdir := stdlib |
| |
| include ../Makeconfig |
| @@ -30,7 +32,7 @@ headers := stdlib.h bits/stdlib.h bits/stdlib-ldbl.h bits/stdlib-float.h \ |
| alloca.h fmtmsg.h \ |
| bits/stdlib-bsearch.h |
| |
| -routines := \ |
| +routines-y := \ |
| atof atoi atol atoll \ |
| abort \ |
| bsearch qsort msort \ |
| @@ -39,7 +41,6 @@ routines := \ |
| quick_exit at_quick_exit cxa_at_quick_exit cxa_thread_atexit_impl \ |
| abs labs llabs \ |
| div ldiv lldiv \ |
| - mblen mbstowcs mbtowc wcstombs wctomb \ |
| random random_r rand rand_r \ |
| drand48 erand48 lrand48 nrand48 mrand48 jrand48 \ |
| srand48 seed48 lcong48 \ |
| @@ -52,9 +53,18 @@ routines := \ |
| strtof_l strtod_l strtold_l \ |
| system canonicalize \ |
| a64l l64a \ |
| - rpmatch strfmon strfmon_l getsubopt xpg_basename fmtmsg \ |
| - strtoimax strtoumax wcstoimax wcstoumax \ |
| + getsubopt xpg_basename \ |
| + strtoimax strtoumax \ |
| getcontext setcontext makecontext swapcontext |
| +routines-$(OPTION_EGLIBC_LOCALE_CODE) += \ |
| + strfmon strfmon_l |
| +routines-$(OPTION_POSIX_C_LANG_WIDE_CHAR) += \ |
| + mblen mbstowcs mbtowc wcstombs wctomb \ |
| + wcstoimax wcstoumax |
| +ifeq (yy,$(OPTION_EGLIBC_LOCALE_CODE)$(OPTION_POSIX_REGEXP)) |
| +routines-y += rpmatch |
| +endif |
| +routines-$(OPTION_EGLIBC_FMTMSG) += fmtmsg |
| aux = grouping groupingwc tens_in_limb |
| |
| # These routines will be omitted from the libc shared object. |
| @@ -62,20 +72,24 @@ aux = grouping groupingwc tens_in_limb |
| # linked against when the shared library will be used. |
| static-only-routines = atexit at_quick_exit |
| |
| -test-srcs := tst-fmtmsg |
| -tests := tst-strtol tst-strtod testmb testrand testsort testdiv \ |
| +test-srcs-$(OPTION_EGLIBC_FMTMSG) := tst-fmtmsg |
| +tests := tst-strtol tst-strtod testrand testsort testdiv \ |
| test-canon test-canon2 tst-strtoll tst-environ \ |
| tst-xpg-basename tst-random tst-random2 tst-bsearch \ |
| tst-limits tst-rand48 bug-strtod tst-setcontext \ |
| - tst-setcontext2 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-setcontext2 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 \ |
| tst-setcontext3 tst-tls-atexit-nodelete |
| 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 |
| |
| @@ -116,8 +130,10 @@ CFLAGS-tst-makecontext2.c = $(stack-align-test-flags) |
| 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 |
| |
| diff --git a/stdlib/strtod_l.c b/stdlib/strtod_l.c |
| index e13ab1e..63efe41 100644 |
| --- a/stdlib/strtod_l.c |
| +++ b/stdlib/strtod_l.c |
| @@ -17,6 +17,7 @@ |
| License along with the GNU C Library; if not, see |
| <http://www.gnu.org/licenses/>. */ |
| |
| +#include <gnu/option-groups.h> |
| #include <xlocale.h> |
| |
| extern double ____strtod_l_internal (const char *, char **, int, __locale_t); |
| @@ -548,6 +549,7 @@ ____STRTOF_INTERNAL (nptr, endptr, group, loc) |
| /* Used in several places. */ |
| int cnt; |
| |
| +#if __OPTION_EGLIBC_LOCALE_CODE |
| struct __locale_data *current = loc->__locales[LC_NUMERIC]; |
| |
| if (__glibc_unlikely (group)) |
| @@ -586,6 +588,17 @@ ____STRTOF_INTERNAL (nptr, endptr, group, loc) |
| 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; |
| diff --git a/stdlib/tst-strtod.c b/stdlib/tst-strtod.c |
| index a469208..28fb423 100644 |
| --- a/stdlib/tst-strtod.c |
| +++ b/stdlib/tst-strtod.c |
| @@ -23,6 +23,7 @@ |
| #include <errno.h> |
| #include <string.h> |
| #include <math.h> |
| +#include <gnu/option-groups.h> |
| |
| struct ltest |
| { |
| @@ -176,7 +177,9 @@ main (int argc, char ** argv) |
| |
| status |= long_dbl (); |
| |
| +#if __OPTION_EGLIBC_LOCALE_CODE |
| status |= locale_test (); |
| +#endif |
| |
| return status ? EXIT_FAILURE : EXIT_SUCCESS; |
| } |
| @@ -219,6 +222,7 @@ long_dbl (void) |
| return 0; |
| } |
| |
| +#if __OPTION_EGLIBC_LOCALE_CODE |
| /* Perform a few tests in a locale with thousands separators. */ |
| static int |
| locale_test (void) |
| @@ -276,3 +280,4 @@ locale_test (void) |
| |
| return result; |
| } |
| +#endif /* __OPTION_EGLIBC_LOCALE_CODE */ |
| diff --git a/streams/Makefile b/streams/Makefile |
| index a8a6162..ceb423f 100644 |
| --- a/streams/Makefile |
| +++ b/streams/Makefile |
| @@ -18,11 +18,14 @@ |
| # |
| # Makefile for streams. |
| # |
| +include ../option-groups.mak |
| + |
| subdir := streams |
| |
| include ../Makeconfig |
| |
| headers = stropts.h sys/stropts.h bits/stropts.h bits/xtitypes.h |
| -routines = isastream getmsg getpmsg putmsg putpmsg fattach fdetach |
| +routines-$(OPTION_EGLIBC_STREAMS) \ |
| + += isastream getmsg getpmsg putmsg putpmsg fattach fdetach |
| |
| include ../Rules |
| diff --git a/string/Makefile b/string/Makefile |
| index 8424a61..5988834 100644 |
| --- a/string/Makefile |
| +++ b/string/Makefile |
| @@ -18,6 +18,8 @@ |
| # |
| # Sub-makefile for string portion of library. |
| # |
| +include ../option-groups.mak |
| + |
| subdir := string |
| |
| include ../Makeconfig |
| @@ -39,10 +41,12 @@ routines := strcat strchr strcmp strcoll strcpy strcspn \ |
| $(addprefix argz-,append count create ctsep next \ |
| delete extract insert stringify \ |
| addsep replace) \ |
| - envz basename \ |
| + basename \ |
| strcoll_l strxfrm_l string-inlines memrchr \ |
| xpg-strerror strerror_l |
| |
| +routines-$(OPTION_EGLIBC_ENVZ) += envz |
| + |
| strop-tests := memchr memcmp memcpy memmove mempcpy memset memccpy \ |
| stpcpy stpncpy strcat strchr strcmp strcpy strcspn \ |
| strlen strncmp strncpy strpbrk strrchr strspn memmem \ |
| @@ -51,10 +55,12 @@ strop-tests := memchr memcmp memcpy memmove mempcpy memset memccpy \ |
| 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 |
| |
| diff --git a/string/strcoll_l.c b/string/strcoll_l.c |
| index 8f1225f..b36b18c 100644 |
| --- a/string/strcoll_l.c |
| +++ b/string/strcoll_l.c |
| @@ -24,6 +24,7 @@ |
| #include <stdint.h> |
| #include <string.h> |
| #include <sys/param.h> |
| +#include <gnu/option-groups.h> |
| |
| #ifndef STRING_TYPE |
| # define STRING_TYPE char |
| @@ -260,7 +261,11 @@ int |
| STRCOLL (const STRING_TYPE *s1, const STRING_TYPE *s2, __locale_t l) |
| { |
| struct __locale_data *current = l->__locales[LC_COLLATE]; |
| +#if __OPTION_EGLIBC_LOCALE_CODE |
| uint_fast32_t nrules = current->values[_NL_ITEM_INDEX (_NL_COLLATE_NRULES)].word; |
| +#else |
| + const uint_fast32_t nrules = 0; |
| +#endif |
| /* We don't assign the following values right away since it might be |
| unnecessary in case there are no rules. */ |
| const unsigned char *rulesets; |
| diff --git a/string/strerror_l.c b/string/strerror_l.c |
| index 2ed78b5..6584813 100644 |
| --- a/string/strerror_l.c |
| +++ b/string/strerror_l.c |
| @@ -21,6 +21,7 @@ |
| #include <stdlib.h> |
| #include <string.h> |
| #include <sys/param.h> |
| +#include <gnu/option-groups.h> |
| |
| |
| static __thread char *last_value; |
| @@ -29,10 +30,14 @@ static __thread char *last_value; |
| static const char * |
| translate (const char *str, locale_t loc) |
| { |
| +#if __OPTION_EGLIBC_LOCALE_CODE |
| locale_t oldloc = __uselocale (loc); |
| const char *res = _(str); |
| __uselocale (oldloc); |
| return res; |
| +#else |
| + return str; |
| +#endif |
| } |
| |
| |
| diff --git a/string/strxfrm_l.c b/string/strxfrm_l.c |
| index 8b61ea2..41fdc22 100644 |
| --- a/string/strxfrm_l.c |
| +++ b/string/strxfrm_l.c |
| @@ -24,6 +24,7 @@ |
| #include <stdlib.h> |
| #include <string.h> |
| #include <sys/param.h> |
| +#include <gnu/option-groups.h> |
| |
| #ifndef STRING_TYPE |
| # define STRING_TYPE char |
| @@ -669,7 +670,11 @@ STRXFRM (STRING_TYPE *dest, const STRING_TYPE *src, size_t n, __locale_t l) |
| { |
| locale_data_t l_data; |
| struct __locale_data *current = l->__locales[LC_COLLATE]; |
| +#if __OPTION_EGLIBC_LOCALE_CODE |
| l_data.nrules = current->values[_NL_ITEM_INDEX (_NL_COLLATE_NRULES)].word; |
| +#else |
| + l_data.nrules = 0; |
| +#endif |
| |
| /* Handle byte comparison case. */ |
| if (l_data.nrules == 0) |
| diff --git a/string/test-strcmp.c b/string/test-strcmp.c |
| index dc4ba6f..a978656 100644 |
| --- a/string/test-strcmp.c |
| +++ b/string/test-strcmp.c |
| @@ -329,34 +329,6 @@ check (void) |
| FOR_EACH_IMPL (impl, 0) |
| check_result (impl, s1 + i1, s2 + i2, exp_result); |
| } |
| - |
| - /* Test cases where there are multiple zero bytes after the first. */ |
| - |
| - for (size_t i = 0; i < 16 + 1; i++) |
| - { |
| - s1[i] = 0x00; |
| - s2[i] = 0x00; |
| - } |
| - |
| - for (size_t i = 0; i < 16; i++) |
| - { |
| - int exp_result; |
| - |
| - for (int val = 0x01; val < 0x100; val++) |
| - { |
| - for (size_t j = 0; j < i; j++) |
| - { |
| - s1[j] = val; |
| - s2[j] = val; |
| - } |
| - |
| - s2[i] = val; |
| - |
| - exp_result = SIMPLE_STRCMP (s1, s2); |
| - FOR_EACH_IMPL (impl, 0) |
| - check_result (impl, s1, s2, exp_result); |
| - } |
| - } |
| } |
| |
| |
| diff --git a/string/tst-strxfrm.c b/string/tst-strxfrm.c |
| index f48cfc0..c3a51f9 100644 |
| --- a/string/tst-strxfrm.c |
| +++ b/string/tst-strxfrm.c |
| @@ -3,6 +3,7 @@ |
| #include <stdio.h> |
| #include <stdlib.h> |
| #include <string.h> |
| +#include <gnu/option-groups.h> |
| |
| |
| char const string[] = ""; |
| @@ -64,8 +65,10 @@ do_test (void) |
| int result = 0; |
| |
| result |= test ("C"); |
| +#if __OPTION_EGLIBC_LOCALE_CODE |
| result |= test ("en_US.ISO-8859-1"); |
| result |= test ("de_DE.UTF-8"); |
| +#endif |
| |
| return result; |
| } |
| diff --git a/string/tst-strxfrm2.c b/string/tst-strxfrm2.c |
| index d5a1115..19c7f30 100644 |
| --- a/string/tst-strxfrm2.c |
| +++ b/string/tst-strxfrm2.c |
| @@ -1,6 +1,7 @@ |
| #include <locale.h> |
| #include <stdio.h> |
| #include <string.h> |
| +#include <gnu/option-groups.h> |
| |
| static int |
| do_test (void) |
| @@ -38,6 +39,7 @@ do_test (void) |
| res = 1; |
| } |
| |
| +#if __OPTION_EGLIBC_LOCALE_CODE |
| if (setlocale (LC_ALL, "de_DE.UTF-8") == NULL) |
| { |
| puts ("setlocale failed"); |
| @@ -75,6 +77,7 @@ do_test (void) |
| res = 1; |
| } |
| } |
| +#endif |
| |
| return res; |
| } |
| diff --git a/sunrpc/Makefile b/sunrpc/Makefile |
| index 60caa0a..5bc70ab 100644 |
| --- a/sunrpc/Makefile |
| +++ b/sunrpc/Makefile |
| @@ -18,6 +18,8 @@ |
| # |
| # Sub-makefile for sunrpc portion of the library. |
| # |
| +include ../option-groups.mak |
| + |
| subdir := sunrpc |
| |
| include ../Makeconfig |
| @@ -55,7 +57,6 @@ headers-in-tirpc = $(addprefix rpc/,auth.h auth_unix.h clnt.h pmap_clnt.h \ |
| 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,20 +66,28 @@ headers += $(headers-in-tirpc) $(headers-not-in-tirpc) |
| 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 |
| +need-export-routines-y += xcrypt |
| +need-export-routines := $(need-export-routines-y) |
| |
| -routines := auth_none authuxprot bindrsvprt clnt_raw clnt_simp \ |
| +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 \ |
| + key_prot openchild rtime svcauth_des \ |
| getrpcent getrpcbyname getrpcbynumber \ |
| getrpcent_r getrpcbyname_r getrpcbynumber_r \ |
| - clnt_unix svc_unix create_xid $(need-export-routines) |
| + 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) |
| @@ -87,25 +96,28 @@ endif |
| |
| # We do not build rpcinfo anymore. It is not needed for a bootstrap |
| # and not wanted on complete systems. |
| -# others := rpcinfo |
| -# install-sbin := rpcinfo |
| -install-bin := rpcgen |
| +# others-$(OPTION_EGLIBC_SUNRPC) += rpcinfo |
| +# install-sbin-$(OPTION_EGLIBC_SUNRPC) += rpcinfo |
| +install-bin-$(OPTION_EGLIBC_SUNRPC) += rpcgen |
| rpcgen-objs = rpc_main.o rpc_hout.o rpc_cout.o rpc_parse.o \ |
| rpc_scan.o rpc_util.o rpc_svcout.o rpc_clntout.o \ |
| rpc_tblout.o rpc_sample.o |
| -extra-objs = $(rpcgen-objs) $(addprefix cross-,$(rpcgen-objs)) |
| -others += rpcgen |
| +extra-objs-$(OPTION_EGLIBC_SUNRPC) = $(rpcgen-objs) $(addprefix cross-,$(rpcgen-objs)) |
| +others-$(OPTION_EGLIBC_SUNRPC) += rpcgen |
| + |
| +install-others-$(OPTION_EGLIBC_SUNRPC) += $(inst_sysconfdir)/rpc |
| |
| -tests = tst-xdrmem tst-xdrmem2 test-rpcent |
| -xtests := tst-getmyaddr |
| +tests-$(OPTION_EGLIBC_SUNRPC) = tst-xdrmem tst-xdrmem2 test-rpcent |
| +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) |
| diff --git a/sysdeps/arm/Makefile b/sysdeps/arm/Makefile |
| index 17c129b..543791a 100644 |
| --- a/sysdeps/arm/Makefile |
| +++ b/sysdeps/arm/Makefile |
| @@ -37,10 +37,13 @@ ifeq ($(subdir),csu) |
| # get offset to rtld_global._dl_hwcap |
| gen-as-const-headers += rtld-global-offsets.sym tlsdesc.sym |
| aeabi_constants = aeabi_lcsts aeabi_sighandlers aeabi_math |
| -aeabi_routines = aeabi_assert aeabi_localeconv aeabi_errno_addr \ |
| +aeabi_routines = aeabi_assert aeabi_errno_addr \ |
| aeabi_mb_cur_max aeabi_atexit aeabi_memclr aeabi_memcpy \ |
| aeabi_memmove aeabi_memset \ |
| aeabi_read_tp libc-aeabi_read_tp |
| +ifeq (y,$(OPTION_EGLIBC_LOCALE_CODE)) |
| +aeabi_routines += aeabi_localeconv |
| +endif |
| |
| sysdep_routines += $(aeabi_constants) $(aeabi_routines) |
| static-only-routines += $(aeabi_constants) aeabi_read_tp |
| diff --git a/sysdeps/generic/ldsodefs.h b/sysdeps/generic/ldsodefs.h |
| index 7a0fe8d..a3e2c0a 100644 |
| --- a/sysdeps/generic/ldsodefs.h |
| +++ b/sysdeps/generic/ldsodefs.h |
| @@ -435,6 +435,12 @@ extern struct rtld_global _rtld_global __rtld_global_attribute__; |
| # 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 |
| @@ -447,8 +453,10 @@ struct rtld_global_ro |
| { |
| #endif |
| |
| +#if __OPTION_EGLIBC_RTLD_DEBUG |
| /* If nonzero the appropriate debug information is printed. */ |
| EXTERN int _dl_debug_mask; |
| +#endif |
| #define DL_DEBUG_LIBS (1 << 0) |
| #define DL_DEBUG_IMPCALLS (1 << 1) |
| #define DL_DEBUG_BINDINGS (1 << 2) |
| diff --git a/sysdeps/gnu/Makefile b/sysdeps/gnu/Makefile |
| index ea68037..3175cc3 100644 |
| --- a/sysdeps/gnu/Makefile |
| +++ b/sysdeps/gnu/Makefile |
| @@ -59,7 +59,8 @@ $(foreach o,$(object-suffixes) $(object-suffixes:=.d),\ |
| 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 |
| diff --git a/sysdeps/ieee754/ldbl-opt/Makefile b/sysdeps/ieee754/ldbl-opt/Makefile |
| index 222122d..4509357 100644 |
| --- a/sysdeps/ieee754/ldbl-opt/Makefile |
| +++ b/sysdeps/ieee754/ldbl-opt/Makefile |
| @@ -11,19 +11,18 @@ libm-routines += s_nexttowardfd |
| routines += math_ldbl_opt nldbl-compat |
| |
| extra-libs += libnldbl |
| -libnldbl-calls = asprintf dprintf fprintf fscanf fwprintf fwscanf iovfscanf \ |
| +libnldbl-calls = asprintf dprintf fprintf fscanf iovfscanf \ |
| obstack_printf obstack_vprintf printf scanf snprintf \ |
| - sprintf sscanf swprintf swscanf vasprintf vdprintf vfprintf \ |
| - vfscanf vfwprintf vfwscanf vprintf vscanf vsnprintf \ |
| - vsprintf vsscanf vswprintf vswscanf vwprintf vwscanf \ |
| - wprintf wscanf printf_fp printf_size \ |
| - fprintf_chk fwprintf_chk printf_chk snprintf_chk sprintf_chk \ |
| - swprintf_chk vfprintf_chk vfwprintf_chk vprintf_chk \ |
| - vsnprintf_chk vsprintf_chk vswprintf_chk vwprintf_chk \ |
| - wprintf_chk asprintf_chk vasprintf_chk dprintf_chk \ |
| + sprintf sscanf vasprintf vdprintf vfprintf \ |
| + vfscanf vprintf vscanf vsnprintf \ |
| + vsprintf vsscanf \ |
| + printf_fp printf_size \ |
| + fprintf_chk printf_chk snprintf_chk sprintf_chk \ |
| + vfprintf_chk vprintf_chk \ |
| + vsnprintf_chk vsprintf_chk \ |
| + asprintf_chk vasprintf_chk dprintf_chk \ |
| vdprintf_chk obstack_printf_chk obstack_vprintf_chk \ |
| syslog syslog_chk vsyslog vsyslog_chk \ |
| - strfmon strfmon_l \ |
| strtold strtold_l strtoldint wcstold wcstold_l wcstoldint \ |
| qecvt qfcvt qgcvt qecvt_r qfcvt_r \ |
| isinf isnan finite signbit scalb log2 lgamma_r ceil \ |
| @@ -38,9 +37,15 @@ libnldbl-calls = asprintf dprintf fprintf fscanf fwprintf fwscanf iovfscanf \ |
| 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) |
| diff --git a/sysdeps/ieee754/ldbl-opt/nldbl-compat.c b/sysdeps/ieee754/ldbl-opt/nldbl-compat.c |
| index 0198886..55501cd 100644 |
| --- a/sysdeps/ieee754/ldbl-opt/nldbl-compat.c |
| +++ b/sysdeps/ieee754/ldbl-opt/nldbl-compat.c |
| @@ -26,6 +26,7 @@ |
| #include <locale/localeinfo.h> |
| #include <sys/syslog.h> |
| #include <bits/libc-lock.h> |
| +#include <gnu/option-groups.h> |
| |
| #include "nldbl-compat.h" |
| |
| @@ -33,20 +34,14 @@ libc_hidden_proto (__nldbl_vfprintf) |
| libc_hidden_proto (__nldbl_vsscanf) |
| libc_hidden_proto (__nldbl_vsprintf) |
| libc_hidden_proto (__nldbl_vfscanf) |
| -libc_hidden_proto (__nldbl_vfwscanf) |
| libc_hidden_proto (__nldbl_vdprintf) |
| -libc_hidden_proto (__nldbl_vswscanf) |
| -libc_hidden_proto (__nldbl_vfwprintf) |
| -libc_hidden_proto (__nldbl_vswprintf) |
| libc_hidden_proto (__nldbl_vsnprintf) |
| libc_hidden_proto (__nldbl_vasprintf) |
| libc_hidden_proto (__nldbl_obstack_vprintf) |
| -libc_hidden_proto (__nldbl___vfwprintf_chk) |
| libc_hidden_proto (__nldbl___vsnprintf_chk) |
| libc_hidden_proto (__nldbl___vfprintf_chk) |
| libc_hidden_proto (__nldbl___vsyslog_chk) |
| libc_hidden_proto (__nldbl___vsprintf_chk) |
| -libc_hidden_proto (__nldbl___vswprintf_chk) |
| libc_hidden_proto (__nldbl___vasprintf_chk) |
| libc_hidden_proto (__nldbl___vdprintf_chk) |
| libc_hidden_proto (__nldbl___obstack_vprintf_chk) |
| @@ -54,8 +49,17 @@ libc_hidden_proto (__nldbl___vstrfmon) |
| libc_hidden_proto (__nldbl___vstrfmon_l) |
| libc_hidden_proto (__nldbl___isoc99_vsscanf) |
| libc_hidden_proto (__nldbl___isoc99_vfscanf) |
| + |
| +#if __OPTION_POSIX_WIDE_CHAR_DEVICE_IO |
| +libc_hidden_proto (__nldbl_vfwscanf) |
| +libc_hidden_proto (__nldbl_vswscanf) |
| +libc_hidden_proto (__nldbl_vfwprintf) |
| +libc_hidden_proto (__nldbl_vswprintf) |
| +libc_hidden_proto (__nldbl___vfwprintf_chk) |
| +libc_hidden_proto (__nldbl___vswprintf_chk) |
| libc_hidden_proto (__nldbl___isoc99_vswscanf) |
| libc_hidden_proto (__nldbl___isoc99_vfwscanf) |
| +#endif |
| |
| static void |
| __nldbl_cleanup (void *arg) |
| @@ -117,6 +121,7 @@ __nldbl_fprintf (FILE *stream, const char *fmt, ...) |
| } |
| weak_alias (__nldbl_fprintf, __nldbl__IO_fprintf) |
| |
| +#if __OPTION_POSIX_WIDE_CHAR_DEVICE_IO |
| int |
| attribute_compat_text_section weak_function |
| __nldbl_fwprintf (FILE *stream, const wchar_t *fmt, ...) |
| @@ -130,6 +135,7 @@ __nldbl_fwprintf (FILE *stream, const wchar_t *fmt, ...) |
| |
| return done; |
| } |
| +#endif |
| |
| int |
| attribute_compat_text_section |
| @@ -226,6 +232,7 @@ __nldbl_snprintf (char *s, size_t maxlen, const char *fmt, ...) |
| return done; |
| } |
| |
| +#if __OPTION_POSIX_WIDE_CHAR_DEVICE_IO |
| int |
| attribute_compat_text_section |
| __nldbl_swprintf (wchar_t *s, size_t n, const wchar_t *fmt, ...) |
| @@ -239,6 +246,7 @@ __nldbl_swprintf (wchar_t *s, size_t n, const wchar_t *fmt, ...) |
| |
| return done; |
| } |
| +#endif |
| |
| int |
| attribute_compat_text_section weak_function |
| @@ -264,6 +272,7 @@ __nldbl_vdprintf (int d, const char *fmt, va_list arg) |
| } |
| libc_hidden_def (__nldbl_vdprintf) |
| |
| +#if __OPTION_POSIX_WIDE_CHAR_DEVICE_IO |
| int |
| attribute_compat_text_section weak_function |
| __nldbl_vfwprintf (FILE *s, const wchar_t *fmt, va_list ap) |
| @@ -275,6 +284,7 @@ __nldbl_vfwprintf (FILE *s, const wchar_t *fmt, va_list ap) |
| return res; |
| } |
| libc_hidden_def (__nldbl_vfwprintf) |
| +#endif |
| |
| int |
| attribute_compat_text_section |
| @@ -297,6 +307,7 @@ __nldbl_vsnprintf (char *string, size_t maxlen, const char *fmt, |
| libc_hidden_def (__nldbl_vsnprintf) |
| weak_alias (__nldbl_vsnprintf, __nldbl___vsnprintf) |
| |
| +#if __OPTION_POSIX_WIDE_CHAR_DEVICE_IO |
| int |
| attribute_compat_text_section weak_function |
| __nldbl_vswprintf (wchar_t *string, size_t maxlen, const wchar_t *fmt, |
| @@ -330,6 +341,7 @@ __nldbl_wprintf (const wchar_t *fmt, ...) |
| |
| return done; |
| } |
| +#endif |
| |
| int |
| attribute_compat_text_section |
| @@ -419,6 +431,7 @@ __nldbl_scanf (const char *fmt, ...) |
| return done; |
| } |
| |
| +#if __OPTION_POSIX_WIDE_CHAR_DEVICE_IO |
| int |
| attribute_compat_text_section |
| __nldbl_vfwscanf (FILE *s, const wchar_t *fmt, va_list ap) |
| @@ -491,6 +504,7 @@ __nldbl_wscanf (const wchar_t *fmt, ...) |
| |
| return done; |
| } |
| +#endif |
| |
| int |
| attribute_compat_text_section |
| @@ -506,6 +520,7 @@ __nldbl___fprintf_chk (FILE *stream, int flag, const char *fmt, ...) |
| return done; |
| } |
| |
| +#if __OPTION_POSIX_WIDE_CHAR_DEVICE_IO |
| int |
| attribute_compat_text_section |
| __nldbl___fwprintf_chk (FILE *stream, int flag, const wchar_t *fmt, ...) |
| @@ -519,6 +534,7 @@ __nldbl___fwprintf_chk (FILE *stream, int flag, const wchar_t *fmt, ...) |
| |
| return done; |
| } |
| +#endif |
| |
| int |
| attribute_compat_text_section |
| @@ -563,6 +579,7 @@ __nldbl___sprintf_chk (char *s, int flag, size_t slen, const char *fmt, ...) |
| return done; |
| } |
| |
| +#if __OPTION_POSIX_WIDE_CHAR_DEVICE_IO |
| int |
| attribute_compat_text_section |
| __nldbl___swprintf_chk (wchar_t *s, size_t n, int flag, size_t slen, |
| @@ -577,6 +594,7 @@ __nldbl___swprintf_chk (wchar_t *s, size_t n, int flag, size_t slen, |
| |
| return done; |
| } |
| +#endif |
| |
| int |
| attribute_compat_text_section |
| @@ -590,6 +608,7 @@ __nldbl___vfprintf_chk (FILE *s, int flag, const char *fmt, va_list ap) |
| } |
| libc_hidden_def (__nldbl___vfprintf_chk) |
| |
| +#if __OPTION_POSIX_WIDE_CHAR_DEVICE_IO |
| int |
| attribute_compat_text_section |
| __nldbl___vfwprintf_chk (FILE *s, int flag, const wchar_t *fmt, va_list ap) |
| @@ -601,6 +620,7 @@ __nldbl___vfwprintf_chk (FILE *s, int flag, const wchar_t *fmt, va_list ap) |
| return res; |
| } |
| libc_hidden_def (__nldbl___vfwprintf_chk) |
| +#endif |
| |
| int |
| attribute_compat_text_section |
| @@ -635,6 +655,7 @@ __nldbl___vsprintf_chk (char *string, int flag, size_t slen, const char *fmt, |
| } |
| libc_hidden_def (__nldbl___vsprintf_chk) |
| |
| +#if __OPTION_POSIX_WIDE_CHAR_DEVICE_IO |
| int |
| attribute_compat_text_section |
| __nldbl___vswprintf_chk (wchar_t *string, size_t maxlen, int flag, size_t slen, |
| @@ -668,6 +689,7 @@ __nldbl___wprintf_chk (int flag, const wchar_t *fmt, ...) |
| |
| return done; |
| } |
| +#endif |
| |
| int |
| attribute_compat_text_section |
| @@ -775,6 +797,7 @@ __nldbl___printf_fp (FILE *fp, const struct printf_info *info, |
| return ___printf_fp (fp, &info_no_ldbl, args); |
| } |
| |
| +#if __OPTION_EGLIBC_LOCALE_CODE |
| ssize_t |
| attribute_compat_text_section |
| __nldbl_strfmon (char *s, size_t maxsize, const char *format, ...) |
| @@ -829,6 +852,7 @@ __nldbl___vstrfmon_l (char *s, size_t maxsize, __locale_t loc, |
| return res; |
| } |
| libc_hidden_def (__nldbl___vstrfmon_l) |
| +#endif |
| |
| void |
| attribute_compat_text_section |
| @@ -941,6 +965,7 @@ __nldbl___isoc99_scanf (const char *fmt, ...) |
| return done; |
| } |
| |
| +#if __OPTION_POSIX_WIDE_CHAR_DEVICE_IO |
| int |
| attribute_compat_text_section |
| __nldbl___isoc99_vfwscanf (FILE *s, const wchar_t *fmt, va_list ap) |
| @@ -1014,6 +1039,7 @@ __nldbl___isoc99_wscanf (const wchar_t *fmt, ...) |
| |
| return done; |
| } |
| +#endif |
| |
| #if LONG_DOUBLE_COMPAT(libc, GLIBC_2_0) |
| compat_symbol (libc, __nldbl__IO_printf, _IO_printf, GLIBC_2_0); |
| @@ -1057,6 +1083,7 @@ compat_symbol (libc, __nldbl_printf_size, printf_size, GLIBC_2_1); |
| compat_symbol (libc, __nldbl___strfmon_l, __strfmon_l, GLIBC_2_1); |
| #endif |
| #if LONG_DOUBLE_COMPAT(libc, GLIBC_2_2) |
| +# if __OPTION_POSIX_WIDE_CHAR_DEVICE_IO |
| compat_symbol (libc, __nldbl_swprintf, swprintf, GLIBC_2_2); |
| compat_symbol (libc, __nldbl_vwprintf, vwprintf, GLIBC_2_2); |
| compat_symbol (libc, __nldbl_wprintf, wprintf, GLIBC_2_2); |
| @@ -1069,6 +1096,7 @@ compat_symbol (libc, __nldbl_vfwscanf, vfwscanf, GLIBC_2_2); |
| 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); |
| diff --git a/sysdeps/ieee754/ldbl-opt/nldbl-compat.h b/sysdeps/ieee754/ldbl-opt/nldbl-compat.h |
| index 0d2c8af..f4cea50 100644 |
| --- a/sysdeps/ieee754/ldbl-opt/nldbl-compat.h |
| +++ b/sysdeps/ieee754/ldbl-opt/nldbl-compat.h |
| @@ -30,6 +30,7 @@ |
| #include <math.h> |
| #include <monetary.h> |
| #include <sys/syslog.h> |
| +#include <gnu/option-groups.h> |
| |
| |
| /* Declare the __nldbl_NAME function the wrappers call that's in libc.so. */ |
| @@ -37,19 +38,15 @@ |
| |
| NLDBL_DECL (_IO_vfscanf); |
| NLDBL_DECL (vfscanf); |
| -NLDBL_DECL (vfwscanf); |
| NLDBL_DECL (obstack_vprintf); |
| NLDBL_DECL (vasprintf); |
| NLDBL_DECL (dprintf); |
| NLDBL_DECL (vdprintf); |
| NLDBL_DECL (fprintf); |
| NLDBL_DECL (vfprintf); |
| -NLDBL_DECL (vfwprintf); |
| NLDBL_DECL (vsnprintf); |
| NLDBL_DECL (vsprintf); |
| NLDBL_DECL (vsscanf); |
| -NLDBL_DECL (vswprintf); |
| -NLDBL_DECL (vswscanf); |
| NLDBL_DECL (__asprintf); |
| NLDBL_DECL (asprintf); |
| NLDBL_DECL (__printf_fp); |
| @@ -66,12 +63,18 @@ NLDBL_DECL (__isoc99_sscanf); |
| NLDBL_DECL (__isoc99_vscanf); |
| NLDBL_DECL (__isoc99_vfscanf); |
| NLDBL_DECL (__isoc99_vsscanf); |
| +#if __OPTION_POSIX_WIDE_CHAR_DEVICE_IO |
| +NLDBL_DECL (vfwscanf); |
| +NLDBL_DECL (vfwprintf); |
| +NLDBL_DECL (vswprintf); |
| +NLDBL_DECL (vswscanf); |
| NLDBL_DECL (__isoc99_wscanf); |
| NLDBL_DECL (__isoc99_fwscanf); |
| NLDBL_DECL (__isoc99_swscanf); |
| NLDBL_DECL (__isoc99_vwscanf); |
| NLDBL_DECL (__isoc99_vfwscanf); |
| NLDBL_DECL (__isoc99_vswscanf); |
| +#endif |
| |
| /* This one does not exist in the normal interface, only |
| __nldbl___vstrfmon really exists. */ |
| @@ -82,22 +85,23 @@ extern ssize_t __nldbl___vstrfmon (char *, size_t, const char *, va_list) |
| 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 */ |
| diff --git a/sysdeps/nptl/Makefile b/sysdeps/nptl/Makefile |
| index e9339a3..782009b 100644 |
| --- a/sysdeps/nptl/Makefile |
| +++ b/sysdeps/nptl/Makefile |
| @@ -18,6 +18,9 @@ |
| |
| ifeq ($(subdir),nptl) |
| libpthread-sysdep_routines += errno-loc |
| +ifeq ($(OPTION_EGLIBC_BIG_MACROS),n) |
| +sysdep_routines += small-macros-fns |
| +endif |
| endif |
| |
| ifeq ($(subdir),rt) |
| diff --git a/sysdeps/nptl/bits/libc-lock.h b/sysdeps/nptl/bits/libc-lock.h |
| index 5599cf1..b839378 100644 |
| --- a/sysdeps/nptl/bits/libc-lock.h |
| +++ b/sysdeps/nptl/bits/libc-lock.h |
| @@ -24,6 +24,14 @@ |
| #include <stddef.h> |
| |
| |
| +#ifdef _LIBC |
| +# include <lowlevellock.h> |
| +# include <tls.h> |
| +# include <pthread-functions.h> |
| +# include <errno.h> /* For EBUSY. */ |
| +# include <gnu/option-groups.h> /* For __OPTION_EGLIBC_BIG_MACROS. */ |
| +#endif |
| + |
| /* Mutex type. */ |
| #if defined _LIBC || defined _IO_MTSAFE_IO |
| # if (!IS_IN (libc) && !IS_IN (libpthread)) || !defined _LIBC |
| @@ -87,6 +95,15 @@ typedef struct __libc_lock_recursive_opaque__ __libc_lock_recursive_t; |
| |
| /* Lock the recursive named lock variable. */ |
| #if defined _LIBC && (IS_IN (libc) || IS_IN (libpthread)) |
| +# if __OPTION_EGLIBC_BIG_MACROS != 1 |
| +/* EGLIBC: Declare wrapper function for a big macro if either |
| + !__OPTION_EGLIBC_BIG_MACROS or we are using a back door from |
| + small-macros-fns.c (__OPTION_EGLIBC_BIG_MACROS == 2). */ |
| +extern void __libc_lock_lock_recursive_fn (__libc_lock_recursive_t *); |
| +libc_hidden_proto (__libc_lock_lock_recursive_fn); |
| +# endif /* __OPTION_EGLIBC_BIG_MACROS != 1 */ |
| +# if __OPTION_EGLIBC_BIG_MACROS |
| + |
| # define __libc_lock_lock_recursive(NAME) \ |
| do { \ |
| void *self = THREAD_SELF; \ |
| @@ -97,6 +114,10 @@ typedef struct __libc_lock_recursive_opaque__ __libc_lock_recursive_t; |
| } \ |
| ++(NAME).cnt; \ |
| } while (0) |
| +# else |
| +# define __libc_lock_lock_recursive(NAME) \ |
| + __libc_lock_lock_recursive_fn (&(NAME)) |
| +# endif /* __OPTION_EGLIBC_BIG_MACROS */ |
| #else |
| # define __libc_lock_lock_recursive(NAME) \ |
| __libc_maybe_call (__pthread_mutex_lock, (&(NAME).mutex), 0) |
| @@ -104,6 +125,14 @@ typedef struct __libc_lock_recursive_opaque__ __libc_lock_recursive_t; |
| |
| /* Try to lock the recursive named lock variable. */ |
| #if defined _LIBC && (IS_IN (libc) || IS_IN (libpthread)) |
| +# if __OPTION_EGLIBC_BIG_MACROS != 1 |
| +/* EGLIBC: Declare wrapper function for a big macro if either |
| + !__OPTION_EGLIBC_BIG_MACROS or we are using a back door from |
| + small-macros-fns.c (__OPTION_EGLIBC_BIG_MACROS == 2). */ |
| +extern int __libc_lock_trylock_recursive_fn (__libc_lock_recursive_t *); |
| +libc_hidden_proto (__libc_lock_trylock_recursive_fn); |
| +# endif /* __OPTION_EGLIBC_BIG_MACROS != 1 */ |
| +# if __OPTION_EGLIBC_BIG_MACROS |
| # define __libc_lock_trylock_recursive(NAME) \ |
| ({ \ |
| int result = 0; \ |
| @@ -122,6 +151,10 @@ typedef struct __libc_lock_recursive_opaque__ __libc_lock_recursive_t; |
| ++(NAME).cnt; \ |
| result; \ |
| }) |
| +# else |
| +# define __libc_lock_trylock_recursive(NAME) \ |
| + __libc_lock_trylock_recursive_fn (&(NAME)) |
| +# endif /* __OPTION_EGLIBC_BIG_MACROS */ |
| #else |
| # define __libc_lock_trylock_recursive(NAME) \ |
| __libc_maybe_call (__pthread_mutex_trylock, (&(NAME).mutex), 0) |
| @@ -129,6 +162,14 @@ typedef struct __libc_lock_recursive_opaque__ __libc_lock_recursive_t; |
| |
| /* Unlock the recursive named lock variable. */ |
| #if defined _LIBC && (IS_IN (libc) || IS_IN (libpthread)) |
| +# if __OPTION_EGLIBC_BIG_MACROS != 1 |
| +/* EGLIBC: Declare wrapper function for a big macro if either |
| + !__OPTION_EGLIBC_BIG_MACROS, or we are using a back door from |
| + small-macros-fns.c (__OPTION_EGLIBC_BIG_MACROS == 2). */ |
| +extern void __libc_lock_unlock_recursive_fn (__libc_lock_recursive_t *); |
| +libc_hidden_proto (__libc_lock_unlock_recursive_fn); |
| +# endif /* __OPTION_EGLIBC_BIG_MACROS != 1 */ |
| +# if __OPTION_EGLIBC_BIG_MACROS |
| /* We do no error checking here. */ |
| # define __libc_lock_unlock_recursive(NAME) \ |
| do { \ |
| @@ -138,6 +179,10 @@ typedef struct __libc_lock_recursive_opaque__ __libc_lock_recursive_t; |
| 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) |
| diff --git a/sysdeps/nptl/bits/libc-lockP.h b/sysdeps/nptl/bits/libc-lockP.h |
| index f55f621..da98869 100644 |
| --- a/sysdeps/nptl/bits/libc-lockP.h |
| +++ b/sysdeps/nptl/bits/libc-lockP.h |
| @@ -33,6 +33,8 @@ |
| #include <lowlevellock.h> |
| #include <tls.h> |
| #include <pthread-functions.h> |
| +#include <errno.h> /* For EBUSY. */ |
| +#include <gnu/option-groups.h> /* For __OPTION_EGLIBC_BIG_MACROS. */ |
| |
| #if IS_IN (libpthread) |
| /* This gets us the declarations of the __pthread_* internal names, |
| @@ -171,10 +173,22 @@ typedef pthread_key_t __libc_key_t; |
| |
| /* Lock the named lock variable. */ |
| #if IS_IN (libc) || IS_IN (libpthread) |
| -# ifndef __libc_lock_lock |
| -# define __libc_lock_lock(NAME) \ |
| +# if __OPTION_EGLIBC_BIG_MACROS != 1 |
| +/* EGLIBC: Declare wrapper function for a big macro if either |
| + !__OPTION_EGLIBC_BIG_MACROS or we are using a back door from |
| + small-macros-fns.c (__OPTION_EGLIBC_BIG_MACROS == 2). */ |
| +extern void __libc_lock_lock_fn (__libc_lock_t *); |
| +libc_hidden_proto (__libc_lock_lock_fn); |
| +# endif /* __OPTION_EGLIBC_BIG_MACROS != 1 */ |
| +# if __OPTION_EGLIBC_BIG_MACROS |
| +# ifndef __libc_lock_lock |
| +# define __libc_lock_lock(NAME) \ |
| ({ lll_lock (NAME, LLL_PRIVATE); 0; }) |
| -# endif |
| +# endif |
| +# else |
| +# define __libc_lock_lock(NAME) \ |
| + __libc_lock_lock_fn (&(NAME)) |
| +# endif /* __OPTION_EGLIBC_BIG_MACROS */ |
| #else |
| # undef __libc_lock_lock |
| # define __libc_lock_lock(NAME) \ |
| @@ -187,10 +201,22 @@ typedef pthread_key_t __libc_key_t; |
| |
| /* Try to lock the named lock variable. */ |
| #if IS_IN (libc) || IS_IN (libpthread) |
| -# ifndef __libc_lock_trylock |
| -# define __libc_lock_trylock(NAME) \ |
| +# if __OPTION_EGLIBC_BIG_MACROS != 1 |
| +/* EGLIBC: Declare wrapper function for a big macro if either |
| + !__OPTION_EGLIBC_BIG_MACROS or we are using a back door from |
| + small-macros-fns.c (__OPTION_EGLIBC_BIG_MACROS == 2). */ |
| +extern int __libc_lock_trylock_fn (__libc_lock_t *); |
| +libc_hidden_proto (__libc_lock_trylock_fn); |
| +# endif /* __OPTION_EGLIBC_BIG_MACROS != 1 */ |
| +# if __OPTION_EGLIBC_BIG_MACROS |
| +# ifndef __libc_lock_trylock |
| +# define __libc_lock_trylock(NAME) \ |
| lll_trylock (NAME) |
| -# endif |
| +# endif |
| +# else |
| +# define __libc_lock_trylock(NAME) \ |
| + __libc_lock_trylock_fn (&(NAME)) |
| +# endif /* __OPTION_EGLIBC_BIG_MACROS */ |
| #else |
| # undef __libc_lock_trylock |
| # define __libc_lock_trylock(NAME) \ |
| @@ -206,8 +232,20 @@ typedef pthread_key_t __libc_key_t; |
| |
| /* Unlock the named lock variable. */ |
| #if IS_IN (libc) || IS_IN (libpthread) |
| +# if __OPTION_EGLIBC_BIG_MACROS != 1 |
| +/* EGLIBC: Declare wrapper function for a big macro if either |
| + !__OPTION_EGLIBC_BIG_MACROS, or we are using a back door from |
| + small-macros-fns.c (__OPTION_EGLIBC_BIG_MACROS == 2). */ |
| +extern void __libc_lock_unlock_fn (__libc_lock_t *); |
| +libc_hidden_proto (__libc_lock_unlock_fn); |
| +# endif /* __OPTION_EGLIBC_BIG_MACROS != 1 */ |
| +# if __OPTION_EGLIBC_BIG_MACROS |
| # define __libc_lock_unlock(NAME) \ |
| lll_unlock (NAME, LLL_PRIVATE) |
| +# else |
| +# define __libc_lock_unlock(NAME) \ |
| + __libc_lock_unlock_fn (&(NAME)) |
| +# endif /* __OPTION_EGLIBC_BIG_MACROS */ |
| #else |
| # define __libc_lock_unlock(NAME) \ |
| __libc_maybe_call (__pthread_mutex_unlock, (&(NAME)), 0) |
| diff --git a/sysdeps/nptl/small-macros-fns.c b/sysdeps/nptl/small-macros-fns.c |
| new file mode 100644 |
| index 0000000..f751053 |
| --- /dev/null |
| +++ b/sysdeps/nptl/small-macros-fns.c |
| @@ -0,0 +1,72 @@ |
| +/* EGLIBC: function wrappers for big macros. |
| + Copyright (C) 2009 Free Software Foundation, Inc. |
| + This file is part of the GNU C Library. |
| + |
| + The GNU C Library is free software; you can redistribute it and/or |
| + modify it under the terms of the GNU Lesser General Public License as |
| + published by the Free Software Foundation; either version 2.1 of the |
| + License, or (at your option) any later version. |
| + |
| + The GNU C Library is distributed in the hope that it will be useful, |
| + but WITHOUT ANY WARRANTY; without even the implied warranty of |
| + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU |
| + Lesser General Public License for more details. |
| + |
| + You should have received a copy of the GNU Lesser General Public |
| + License along with the GNU C Library; see the file COPYING.LIB. If not, |
| + write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, |
| + Boston, MA 02111-1307, USA. */ |
| + |
| +#include <gnu/option-groups.h> |
| + |
| +/* Handle macros from ./bits/libc-lock.h. */ |
| +#if defined _LIBC && (!defined NOT_IN_libc || defined IS_IN_libpthread) |
| + |
| +/* Get the macros for function bodies through a back door. */ |
| +# undef __OPTION_EGLIBC_BIG_MACROS |
| +# define __OPTION_EGLIBC_BIG_MACROS 2 |
| +# include <bits/libc-lock.h> |
| + |
| +void |
| +__libc_lock_lock_fn (__libc_lock_t *name) |
| +{ |
| + __libc_lock_lock (*name); |
| +} |
| +libc_hidden_def (__libc_lock_lock_fn); |
| + |
| +void |
| +__libc_lock_lock_recursive_fn (__libc_lock_recursive_t *name) |
| +{ |
| + __libc_lock_lock_recursive (*name); |
| +} |
| +libc_hidden_def (__libc_lock_lock_recursive_fn); |
| + |
| +int |
| +__libc_lock_trylock_fn (__libc_lock_t *name) |
| +{ |
| + return __libc_lock_trylock (*name); |
| +} |
| +libc_hidden_def (__libc_lock_trylock_fn); |
| + |
| +int |
| +__libc_lock_trylock_recursive_fn (__libc_lock_recursive_t *name) |
| +{ |
| + return __libc_lock_trylock_recursive (*name); |
| +} |
| +libc_hidden_def (__libc_lock_trylock_recursive_fn); |
| + |
| +void |
| +__libc_lock_unlock_fn (__libc_lock_t *name) |
| +{ |
| + __libc_lock_unlock (*name); |
| +} |
| +libc_hidden_def (__libc_lock_unlock_fn); |
| + |
| +void |
| +__libc_lock_unlock_recursive_fn (__libc_lock_recursive_t *name) |
| +{ |
| + __libc_lock_unlock_recursive (*name); |
| +} |
| +libc_hidden_def (__libc_lock_unlock_recursive_fn); |
| + |
| +#endif /*defined _LIBC && (!defined NOT_IN_libc || defined IS_IN_libpthread)*/ |
| diff --git a/sysdeps/unix/sysv/linux/gethostid.c b/sysdeps/unix/sysv/linux/gethostid.c |
| index 26e4692..d0a26c8 100644 |
| --- a/sysdeps/unix/sysv/linux/gethostid.c |
| +++ b/sysdeps/unix/sysv/linux/gethostid.c |
| @@ -21,6 +21,7 @@ |
| #include <unistd.h> |
| #include <netdb.h> |
| #include <not-cancel.h> |
| +#include <gnu/option-groups.h> |
| |
| #define HOSTIDFILE "/etc/hostid" |
| |
| @@ -89,6 +90,7 @@ gethostid (void) |
| return id; |
| } |
| |
| +#if __OPTION_EGLIBC_INET |
| /* Getting from the file was not successful. An intelligent guess for |
| a unique number of a host is its IP address. Return this. */ |
| if (__gethostname (hostname, MAXHOSTNAMELEN) < 0 || hostname[0] == '\0') |
| @@ -115,5 +117,9 @@ gethostid (void) |
| /* For the return value to be not exactly the IP address we do some |
| bit fiddling. */ |
| return (int32_t) (in.s_addr << 16 | in.s_addr >> 16); |
| +#else |
| + /* Return an arbitrary value. */ |
| + return 0; |
| +#endif |
| } |
| #endif |
| diff --git a/sysdeps/unix/sysv/linux/libc_fatal.c b/sysdeps/unix/sysv/linux/libc_fatal.c |
| index 53a8bbb..cb110d4 100644 |
| --- a/sysdeps/unix/sysv/linux/libc_fatal.c |
| +++ b/sysdeps/unix/sysv/linux/libc_fatal.c |
| @@ -23,6 +23,7 @@ |
| #include <string.h> |
| #include <sys/mman.h> |
| #include <sys/uio.h> |
| +#include <gnu/option-groups.h> |
| |
| static bool |
| writev_for_fatal (int fd, const struct iovec *iov, size_t niov, size_t total) |
| @@ -40,6 +41,7 @@ writev_for_fatal (int fd, const struct iovec *iov, size_t niov, size_t total) |
| static void |
| backtrace_and_maps (int do_abort, bool written, int fd) |
| { |
| +#if __OPTION_EGLIBC_BACKTRACE |
| if (do_abort > 1 && written) |
| { |
| void *addrs[64]; |
| @@ -62,6 +64,7 @@ backtrace_and_maps (int do_abort, bool written, int fd) |
| close_not_cancel_no_status (fd2); |
| } |
| } |
| +#endif /* __OPTION_EGLIBC_BACKTRACE */ |
| } |
| #define BEFORE_ABORT backtrace_and_maps |
| |
| diff --git a/time/Makefile b/time/Makefile |
| index a411f62..2d022ca 100644 |
| --- a/time/Makefile |
| +++ b/time/Makefile |
| @@ -18,6 +18,8 @@ |
| # |
| # Makefile for time routines |
| # |
| +include ../option-groups.mak |
| + |
| subdir := time |
| |
| include ../Makeconfig |
| @@ -30,15 +32,23 @@ routines := offtime asctime clock ctime ctime_r difftime \ |
| tzfile getitimer setitimer \ |
| stime dysize timegm ftime \ |
| getdate strptime strptime_l \ |
| - strftime wcsftime strftime_l wcsftime_l \ |
| + strftime strftime_l \ |
| timespec_get |
| -aux := era alt_digit lc-time-cleanup |
| |
| -tests := test_time clocktest tst-posixtz tst-strptime tst_wcsftime \ |
| - tst-getdate tst-mktime tst-mktime2 tst-ftime_l tst-strftime \ |
| +routines-$(OPTION_POSIX_C_LANG_WIDE_CHAR) \ |
| + := wcsftime wcsftime_l |
| +aux-$(OPTION_EGLIBC_LOCALE_CODE) += alt_digit era lc-time-cleanup |
| + |
| +tests := test_time clocktest tst-posixtz \ |
| + tst-getdate tst-mktime tst-mktime2 tst-strftime \ |
| tst-mktime3 tst-strptime2 bug-asctime bug-asctime_r bug-mktime1 \ |
| tst-strptime3 bug-getdate1 tst-strptime-whitespace tst-ftime |
| |
| +tests-$(OPTION_EGLIBC_LOCALE_CODE) \ |
| + += tst-strptime tst-ftime_l |
| +tests-$(OPTION_POSIX_WIDE_CHAR_DEVICE_IO) \ |
| + += tst_wcsftime |
| + |
| include ../Rules |
| |
| tz-cflags = -DTZDIR='"$(zonedir)"' \ |
| diff --git a/time/strftime_l.c b/time/strftime_l.c |
| index b48ef34..bfdd618 100644 |
| --- a/time/strftime_l.c |
| +++ b/time/strftime_l.c |
| @@ -35,6 +35,10 @@ |
| # include "../locale/localeinfo.h" |
| #endif |
| |
| +#ifdef _LIBC |
| +# include <gnu/option-groups.h> |
| +#endif |
| + |
| #if defined emacs && !defined HAVE_BCOPY |
| # define HAVE_MEMCPY 1 |
| #endif |
| @@ -882,7 +886,7 @@ __strftime_internal (s, maxsize, format, tp, tzset_called ut_argument |
| case L_('C'): |
| if (modifier == L_('E')) |
| { |
| -#if HAVE_STRUCT_ERA_ENTRY |
| +#if (! _LIBC || __OPTION_EGLIBC_LOCALE_CODE) && HAVE_STRUCT_ERA_ENTRY |
| struct era_entry *era = _nl_get_era_entry (tp HELPER_LOCALE_ARG); |
| if (era) |
| { |
| @@ -955,7 +959,7 @@ __strftime_internal (s, maxsize, format, tp, tzset_called ut_argument |
| |
| if (modifier == L_('O') && 0 <= number_value) |
| { |
| -#ifdef _NL_CURRENT |
| +#if (! _LIBC || __OPTION_EGLIBC_LOCALE_CODE) && defined (_NL_CURRENT) |
| /* Get the locale specific alternate representation of |
| the number NUMBER_VALUE. If none exist NULL is returned. */ |
| const CHAR_T *cp = nl_get_alt_digit (number_value |
| @@ -1260,7 +1264,7 @@ __strftime_internal (s, maxsize, format, tp, tzset_called ut_argument |
| case L_('Y'): |
| if (modifier == 'E') |
| { |
| -#if HAVE_STRUCT_ERA_ENTRY |
| +#if (! _LIBC || __OPTION_EGLIBC_LOCALE_CODE) && HAVE_STRUCT_ERA_ENTRY |
| struct era_entry *era = _nl_get_era_entry (tp HELPER_LOCALE_ARG); |
| if (era) |
| { |
| @@ -1285,7 +1289,7 @@ __strftime_internal (s, maxsize, format, tp, tzset_called ut_argument |
| 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) |
| { |
| diff --git a/time/strptime_l.c b/time/strptime_l.c |
| index 5640cce..784ccbc 100644 |
| --- a/time/strptime_l.c |
| +++ b/time/strptime_l.c |
| @@ -29,6 +29,7 @@ |
| |
| #ifdef _LIBC |
| # define HAVE_LOCALTIME_R 0 |
| +# include <gnu/option-groups.h> |
| # include "../locale/localeinfo.h" |
| #endif |
| |
| @@ -84,7 +85,7 @@ localtime_r (t, tp) |
| if (val < from || val > to) \ |
| return NULL; \ |
| } while (0) |
| -#ifdef _NL_CURRENT |
| +#if (! _LIBC || __OPTION_EGLIBC_LOCALE_CODE) && defined (_NL_CURRENT) |
| # define get_alt_number(from, to, n) \ |
| ({ \ |
| __label__ do_normal; \ |
| @@ -257,8 +258,10 @@ __strptime_internal (rp, fmt, tmp, statep LOCALE_PARAM) |
| int cnt; |
| int cnt_longest; |
| size_t val; |
| +#if ! _LIBC || __OPTION_EGLIBC_LOCALE_CODE |
| size_t num_eras; |
| struct era_entry *era = NULL; |
| +#endif |
| enum ptime_locale_status { not, loc, raw } decided_longest; |
| struct __strptime_state |
| { |
| @@ -820,6 +823,7 @@ __strptime_internal (rp, fmt, tmp, statep LOCALE_PARAM) |
| s.want_xday = 1; |
| break; |
| case 'C': |
| +#if ! _LIBC || __OPTION_EGLIBC_LOCALE_CODE |
| if (s.decided != raw) |
| { |
| if (s.era_cnt >= 0) |
| @@ -856,10 +860,12 @@ __strptime_internal (rp, fmt, tmp, statep LOCALE_PARAM) |
| |
| s.decided = raw; |
| } |
| +#endif |
| /* The C locale has no era information, so use the |
| normal representation. */ |
| goto match_century; |
| case 'y': |
| +#if ! _LIBC || __OPTION_EGLIBC_LOCALE_CODE |
| if (s.decided != raw) |
| { |
| get_number(0, 9999, 4); |
| @@ -918,9 +924,10 @@ __strptime_internal (rp, fmt, tmp, statep LOCALE_PARAM) |
| |
| s.decided = raw; |
| } |
| - |
| +#endif |
| goto match_year_in_century; |
| case 'Y': |
| +#if ! _LIBC || __OPTION_EGLIBC_LOCALE_CODE |
| if (s.decided != raw) |
| { |
| num_eras = _NL_CURRENT_WORD (LC_TIME, |
| @@ -948,6 +955,7 @@ __strptime_internal (rp, fmt, tmp, statep LOCALE_PARAM) |
| |
| s.decided = raw; |
| } |
| +#endif |
| get_number (0, 9999, 4); |
| tm->tm_year = val - 1900; |
| s.want_century = 0; |
| @@ -1118,6 +1126,7 @@ __strptime_internal (rp, fmt, tmp, statep LOCALE_PARAM) |
| tm->tm_year = (s.century - 19) * 100; |
| } |
| |
| +#if ! _LIBC || __OPTION_EGLIBC_LOCALE_CODE |
| if (s.era_cnt != -1) |
| { |
| era = _nl_select_era_entry (s.era_cnt HELPER_LOCALE_ARG); |
| @@ -1132,6 +1141,7 @@ __strptime_internal (rp, fmt, tmp, statep LOCALE_PARAM) |
| 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 |
| diff --git a/timezone/Makefile b/timezone/Makefile |
| index 886b06e..f922684 100644 |
| --- a/timezone/Makefile |
| +++ b/timezone/Makefile |
| @@ -127,7 +127,7 @@ $(testdata)/XT%: testdata/XT% |
| |
| $(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)"|' \ |
| diff --git a/wcsmbs/Makefile b/wcsmbs/Makefile |
| index 44a4494..db9fc24 100644 |
| --- a/wcsmbs/Makefile |
| +++ b/wcsmbs/Makefile |
| @@ -18,15 +18,21 @@ |
| # |
| # Sub-makefile for wcsmbs portion of the library. |
| # |
| +include ../option-groups.mak |
| + |
| subdir := wcsmbs |
| |
| include ../Makeconfig |
| |
| headers := wchar.h bits/wchar.h bits/wchar2.h bits/wchar-ldbl.h uchar.h |
| |
| -routines := wcscat wcschr wcscmp wcscpy wcscspn wcsdup wcslen wcsncat \ |
| +# These functions are used by printf_fp.c, even in the plain case; see |
| +# comments there for OPTION_EGLIBC_LOCALE_CODE. |
| +routines := wmemcpy wmemset |
| +routines-$(OPTION_POSIX_C_LANG_WIDE_CHAR) \ |
| + := wcscat wcschr wcscmp wcscpy wcscspn wcsdup wcslen wcsncat \ |
| wcsncmp wcsncpy wcspbrk wcsrchr wcsspn wcstok wcsstr wmemchr \ |
| - wmemcmp wmemcpy wmemmove wmemset wcpcpy wcpncpy wmempcpy \ |
| + wmemcmp wmemmove wcpcpy wcpncpy wmempcpy \ |
| btowc wctob mbsinit \ |
| mbrlen mbrtowc wcrtomb mbsrtowcs wcsrtombs \ |
| mbsnrtowcs wcsnrtombs wcsnlen wcschrnul \ |
| @@ -38,14 +44,21 @@ routines := wcscat wcschr wcscmp wcscpy wcscspn wcsdup wcslen wcsncat \ |
| 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 |
| |
| -strop-tests := wcscmp wcsncmp 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)) |
| +routines-$(OPTION_POSIX_WIDE_CHAR_DEVICE_IO) \ |
| + += isoc99_wscanf isoc99_vwscanf isoc99_fwscanf isoc99_vfwscanf |
| + |
| +strop-tests := wcscmp wmemcmp wmemcmp wcslen wcschr wcsrchr wcscpy |
| + |
| +tests := tst-wchar-h |
| +tests-$(OPTION_EGLIBC_LOCALE_CODE) \ |
| + += tst-btowc tst-mbrtowc tst-mbrtowc2 tst-wcrtomb tst-c16c32-1 |
| +tests-$(OPTION_POSIX_C_LANG_WIDE_CHAR) \ |
| + += tst-wcstof wcsmbs-tst1 tst-wcsnlen \ |
| + tst-wcpncpy tst-mbsrtowcs \ |
| + wcsatcliff $(addprefix test-,$(strop-tests)) |
| |
| include ../Rules |
| |
| diff --git a/wcsmbs/wcsmbsload.c b/wcsmbs/wcsmbsload.c |
| index 6bb49bc..2ab9d07 100644 |
| --- a/wcsmbs/wcsmbsload.c |
| +++ b/wcsmbs/wcsmbsload.c |
| @@ -21,6 +21,7 @@ |
| #include <limits.h> |
| #include <stdlib.h> |
| #include <string.h> |
| +#include <gnu/option-groups.h> |
| |
| #include <locale/localeinfo.h> |
| #include <wcsmbsload.h> |
| @@ -143,6 +144,7 @@ __wcsmbs_getfct (const char *to, const char *from, size_t *nstepsp) |
| }) |
| |
| |
| +#if __OPTION_EGLIBC_LOCALE_CODE |
| /* Some of the functions here must not be used while setlocale is called. */ |
| __libc_rwlock_define (extern, __libc_setlocale_lock attribute_hidden) |
| |
| @@ -211,6 +213,17 @@ __wcsmbs_load_conv (struct __locale_data *new_category) |
| |
| __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. */ |
| diff --git a/wctype/Makefile b/wctype/Makefile |
| index c56f07c..4e8af43 100644 |
| --- a/wctype/Makefile |
| +++ b/wctype/Makefile |
| @@ -18,14 +18,20 @@ |
| # |
| # Sub-makefile for wctype portion of the library. |
| # |
| +include ../option-groups.mak |
| + |
| subdir := wctype |
| |
| include ../Makeconfig |
| |
| headers := wctype.h |
| -routines := wcfuncs wctype iswctype wctrans towctrans \ |
| - wcfuncs_l wctype_l iswctype_l wctrans_l towctrans_l |
| - |
| -tests := test_wctype test_wcfuncs bug-wctypeh |
| +routines := wctrans towctrans towctrans_l |
| +routines-$(OPTION_POSIX_C_LANG_WIDE_CHAR) \ |
| + := wcfuncs wctype iswctype \ |
| + wcfuncs_l wctype_l iswctype_l wctrans_l |
| + |
| +tests := |
| +tests-$(OPTION_POSIX_C_LANG_WIDE_CHAR) \ |
| + += test_wctype test_wcfuncs bug-wctypeh |
| |
| include ../Rules |
| -- |
| 2.1.4 |
| |