[meta-freescale] [PATCH 09/18] glibc : add 2.20 version
Chunrong Guo
B40290 at freescale.com
Thu Dec 28 02:05:47 PST 2017
From: Chunrong Guo <chunrong.guo at nxp.com>
*ppc machine only support glibc 2.20 version
Signed-off-by: Chunrong Guo <chunrong.guo at nxp.com>
---
.../fix_for_centos_5.8.patch | 18 +
recipes-core/glibc/cross-localedef-native_2.20.bb | 57 +
recipes-core/glibc/cross-localedef-native_2.22.bb | 59 +
.../glibc/cross-localedef-native_2.22.bbappend | 7 +
.../cross-localedef/enable-host-aarch64.patch | 13 +
recipes-core/glibc/glibc-common.inc | 9 +
.../glibc/glibc-fsl/0001.glibc.fix_sqrt2.patch | 1692 ++
.../glibc-fsl/0002.glibc.fix_sqrt_finite.patch | 187 +
.../0003.glibc.fix_slow_ieee754_sqrt.patch | 410 +
.../glibc-fsl/0004.glibc.fsl-ppc-no-fsqrt.patch | 101 +
.../glibc/glibc-fsl/0005.glibc.fix_prof.patch | 47 +
.../glibc/glibc-fsl/0006.glibc.fsl-crosszic.patch | 76 +
.../0007.glibc.fix_MTWX51911-enable_8xx.patch | 530 +
.../glibc-fsl/0008.glibc.e500v2_lib_support.patch | 2542 +++
.../0009.glibc.fsl-mcpy-e500mc-e5500-e6500.patch | 1191 ++
.../0010.glibc.fsl-e500mc-e5500-mset.patch | 1337 ++
.../glibc-fsl/0011.glibc.fsl-mset-e6500.patch | 537 +
.../glibc-fsl/0012.glibc.fsl-mcmp-e6500.patch | 832 +
.../glibc-fsl/0013.glibc.fsl-stcmp-e5500.patch | 380 +
.../0014.glibc.fsl-strchr-e500mc-e5500.patch | 659 +
.../0015.glibc.fsl-strcpy-e500mc-e5500.patch | 627 +
...move-bash-dependency-for-nscd-init-script.patch | 75 +
.../0016.glibc.fsl-strlen-e500mc-e5500.patch | 407 +
.../0017.glibc.fsl-strrchr-e500mc-e5500.patch | 1072 ++
...0018.glibc.testsuite_remove-blocking-test.patch | 258 +
.../glibc/glibc-fsl/0019.glibc.readv_proto.patch | 61 +
...20.glibc.fsl-largemcpy-e500mc-e5500-e6500.patch | 932 +
.../glibc-fsl/0021.glibc.undefined_static.patch | 37 +
.../glibc-fsl/0022.glibc.use-option-groups.patch | 149 +
.../00xx.glibc.add-option-groups-support.patch | 1389 ++
.../00xx.glibc.rtld_debug_option_group.patch | 517 +
.../glibc-fsl/00xx.glibc.use-option-groups.patch | 16551 ++++++++++++++++++
recipes-core/glibc/glibc-initial.inc | 83 +
recipes-core/glibc/glibc-initial_2.20.bb | 11 +
recipes-core/glibc/glibc-ld.inc | 56 +
recipes-core/glibc/glibc-locale_2.20.bb | 1 +
recipes-core/glibc/glibc-mtrace_2.20.bb | 1 +
recipes-core/glibc/glibc-options.inc | 162 +
recipes-core/glibc/glibc-package.inc | 227 +
recipes-core/glibc/glibc-scripts_2.20.bb | 1 +
recipes-core/glibc/glibc-testing.inc | 79 +
.../glibc/glibc/0001-R_ARM_TLS_DTPOFF32.patch | 56 +
...n-libm-err-tab.pl-with-specific-dirs-in-S.patch | 33 +
...-timezone-re-written-tzselect-as-posix-sh.patch | 45 +
...c-Cross-building-and-testing-instructions.patch | 619 +
...g-Eglibc-option-group-infrastructure-to-g.patch | 1436 ++
...020-eglibc-Help-bootstrap-cross-toolchain.patch | 100 +
...ry-picked-from-http-www.eglibc.org-archiv.patch | 64 +
.../0022-eglibc-Clear-cache-lines-on-ppc8xx.patch | 81 +
...0023-eglibc-Resolve-__fpscr_values-on-SH4.patch | 56 +
...orward-port-eglibc-options-groups-support.patch | 16842 +++++++++++++++++++
.../glibc/0025-eglibc-Install-PIC-archives.patch | 123 +
...ebug_mask-is-controlled-by-__OPTION_EGLIB.patch | 556 +
...option-groups-Conditionally-exclude-c-tes.patch | 145 +
...-3406-Stack-overflow-in-vfprintf-BZ-16617.patch | 339 +
...4-7817-wordexp-fails-to-honour-WRDE_NOCMD.patch | 215 +
.../CVE-2014-9402_endless-loop-in-getaddr_r.patch | 65 +
...81-resolv-nss_dns-dns-host.c-buffer-overf.patch | 43 +
recipes-core/glibc/glibc/GLRO_dl_debug_mask.patch | 529 +
recipes-core/glibc/glibc/IO-acquire-lock-fix.patch | 17 +
.../glibc/glibc/add_resource_h_to_wait_h.patch | 20 +
.../glibc/glibc/eglibc-header-bootstrap.patch | 85 +
.../glibc/glibc/eglibc-install-pic-archives.patch | 109 +
.../eglibc-ppc8xx-cache-line-workaround.patch | 68 +
.../glibc/glibc/eglibc-resolv-dynamic.patch | 54 +
.../glibc/glibc/eglibc-sh4-fpscr_values.patch | 42 +
.../glibc/glibc/eglibc-use-option-groups.patch | 16546 ++++++++++++++++++
recipes-core/glibc/glibc/eglibc.patch | 602 +
recipes-core/glibc/glibc/etc/ld.so.conf | 0
.../glibc/glibc/fix-tibetian-locales.patch | 38 +
recipes-core/glibc/glibc/fix_am_rootsbindir.patch | 29 +
recipes-core/glibc/glibc/fsl-ppc-no-fsqrt.patch | 100 +
recipes-core/glibc/glibc/generate-supported.mk | 11 +
recipes-core/glibc/glibc/glibc.fix_sqrt2.patch | 1516 ++
recipes-core/glibc/glibc/grok_gold.patch | 34 +
recipes-core/glibc/glibc/initgroups_keys.patch | 20 +
.../intl-Merge-with-gettext-version-0.19.3.patch | 4797 ++++++
recipes-core/glibc/glibc/ld-search-order.patch | 56 +
recipes-core/glibc/glibc/mips-rld-map-check.patch | 27 +
recipes-core/glibc/glibc/multilib_readlib.patch | 19 +
recipes-core/glibc/glibc/option-groups.patch | 1397 ++
recipes-core/glibc/glibc/ppc-sqrt_finite.patch | 184 +
.../glibc/glibc/ppc_slow_ieee754_sqrt.patch | 365 +
.../glibc/ppce6500-32b_slow_ieee754_sqrt.patch | 47 +
recipes-core/glibc/glibc/relocatable_sdk.patch | 108 +
.../glibc/glibc/relocatable_sdk_fix_openpath.patch | 41 +
.../timezone-re-written-tzselect-as-posix-sh.patch | 38 +
recipes-core/glibc/glibc_2.20.bb | 193 +
.../glibc/ldconfig-native-2.12.1/32and64bit.patch | 331 +
recipes-core/glibc/ldconfig-native-2.12.1/README | 8 +
.../endian-ness_handling.patch | 454 +
.../endian-ness_handling_fix.patch | 47 +
.../ldconfig-native-2.12.1/endianess-header.patch | 113 +
.../glibc/ldconfig-native-2.12.1/flag_fix.patch | 24 +
.../ldconfig-default-to-all-multilib-dirs.patch | 37 +
.../ldconfig-native-2.12.1.tar.bz2 | Bin 0 -> 21491 bytes
.../glibc/ldconfig-native-2.12.1/ldconfig.patch | 471 +
.../ldconfig_aux-cache_path_fix.patch | 36 +
recipes-core/glibc/ldconfig-native_2.12.1.bb | 33 +
recipes-core/glibc/site_config/funcs | 474 +
recipes-core/glibc/site_config/headers | 156 +
recipes-core/glibc/site_config/types | 21 +
102 files changed, 83495 insertions(+)
create mode 100644 recipes-core/glibc/cross-localedef-native/fix_for_centos_5.8.patch
create mode 100644 recipes-core/glibc/cross-localedef-native_2.20.bb
create mode 100644 recipes-core/glibc/cross-localedef-native_2.22.bb
create mode 100644 recipes-core/glibc/cross-localedef-native_2.22.bbappend
create mode 100644 recipes-core/glibc/cross-localedef/enable-host-aarch64.patch
create mode 100644 recipes-core/glibc/glibc-common.inc
create mode 100755 recipes-core/glibc/glibc-fsl/0001.glibc.fix_sqrt2.patch
create mode 100755 recipes-core/glibc/glibc-fsl/0002.glibc.fix_sqrt_finite.patch
create mode 100755 recipes-core/glibc/glibc-fsl/0003.glibc.fix_slow_ieee754_sqrt.patch
create mode 100755 recipes-core/glibc/glibc-fsl/0004.glibc.fsl-ppc-no-fsqrt.patch
create mode 100755 recipes-core/glibc/glibc-fsl/0005.glibc.fix_prof.patch
create mode 100755 recipes-core/glibc/glibc-fsl/0006.glibc.fsl-crosszic.patch
create mode 100755 recipes-core/glibc/glibc-fsl/0007.glibc.fix_MTWX51911-enable_8xx.patch
create mode 100644 recipes-core/glibc/glibc-fsl/0008.glibc.e500v2_lib_support.patch
create mode 100644 recipes-core/glibc/glibc-fsl/0009.glibc.fsl-mcpy-e500mc-e5500-e6500.patch
create mode 100755 recipes-core/glibc/glibc-fsl/0010.glibc.fsl-e500mc-e5500-mset.patch
create mode 100755 recipes-core/glibc/glibc-fsl/0011.glibc.fsl-mset-e6500.patch
create mode 100755 recipes-core/glibc/glibc-fsl/0012.glibc.fsl-mcmp-e6500.patch
create mode 100755 recipes-core/glibc/glibc-fsl/0013.glibc.fsl-stcmp-e5500.patch
create mode 100755 recipes-core/glibc/glibc-fsl/0014.glibc.fsl-strchr-e500mc-e5500.patch
create mode 100755 recipes-core/glibc/glibc-fsl/0015.glibc.fsl-strcpy-e500mc-e5500.patch
create mode 100644 recipes-core/glibc/glibc-fsl/0016-Remove-bash-dependency-for-nscd-init-script.patch
create mode 100755 recipes-core/glibc/glibc-fsl/0016.glibc.fsl-strlen-e500mc-e5500.patch
create mode 100755 recipes-core/glibc/glibc-fsl/0017.glibc.fsl-strrchr-e500mc-e5500.patch
create mode 100755 recipes-core/glibc/glibc-fsl/0018.glibc.testsuite_remove-blocking-test.patch
create mode 100755 recipes-core/glibc/glibc-fsl/0019.glibc.readv_proto.patch
create mode 100755 recipes-core/glibc/glibc-fsl/0020.glibc.fsl-largemcpy-e500mc-e5500-e6500.patch
create mode 100755 recipes-core/glibc/glibc-fsl/0021.glibc.undefined_static.patch
create mode 100644 recipes-core/glibc/glibc-fsl/0022.glibc.use-option-groups.patch
create mode 100755 recipes-core/glibc/glibc-fsl/00xx.glibc.add-option-groups-support.patch
create mode 100755 recipes-core/glibc/glibc-fsl/00xx.glibc.rtld_debug_option_group.patch
create mode 100755 recipes-core/glibc/glibc-fsl/00xx.glibc.use-option-groups.patch
create mode 100644 recipes-core/glibc/glibc-initial.inc
create mode 100644 recipes-core/glibc/glibc-initial_2.20.bb
create mode 100644 recipes-core/glibc/glibc-ld.inc
create mode 100644 recipes-core/glibc/glibc-locale_2.20.bb
create mode 100644 recipes-core/glibc/glibc-mtrace_2.20.bb
create mode 100644 recipes-core/glibc/glibc-options.inc
create mode 100644 recipes-core/glibc/glibc-package.inc
create mode 100644 recipes-core/glibc/glibc-scripts_2.20.bb
create mode 100644 recipes-core/glibc/glibc-testing.inc
create mode 100644 recipes-core/glibc/glibc/0001-R_ARM_TLS_DTPOFF32.patch
create mode 100644 recipes-core/glibc/glibc/0001-eglibc-run-libm-err-tab.pl-with-specific-dirs-in-S.patch
create mode 100644 recipes-core/glibc/glibc/0017-timezone-re-written-tzselect-as-posix-sh.patch
create mode 100644 recipes-core/glibc/glibc/0018-eglibc-Cross-building-and-testing-instructions.patch
create mode 100644 recipes-core/glibc/glibc/0019-eglibc-Bring-Eglibc-option-group-infrastructure-to-g.patch
create mode 100644 recipes-core/glibc/glibc/0020-eglibc-Help-bootstrap-cross-toolchain.patch
create mode 100644 recipes-core/glibc/glibc/0021-eglibc-cherry-picked-from-http-www.eglibc.org-archiv.patch
create mode 100644 recipes-core/glibc/glibc/0022-eglibc-Clear-cache-lines-on-ppc8xx.patch
create mode 100644 recipes-core/glibc/glibc/0023-eglibc-Resolve-__fpscr_values-on-SH4.patch
create mode 100644 recipes-core/glibc/glibc/0024-eglibc-Forward-port-eglibc-options-groups-support.patch
create mode 100644 recipes-core/glibc/glibc/0025-eglibc-Install-PIC-archives.patch
create mode 100644 recipes-core/glibc/glibc/0026-eglibc-dl_debug_mask-is-controlled-by-__OPTION_EGLIB.patch
create mode 100644 recipes-core/glibc/glibc/0027-eglibc-use-option-groups-Conditionally-exclude-c-tes.patch
create mode 100644 recipes-core/glibc/glibc/CVE-2012-3406-Stack-overflow-in-vfprintf-BZ-16617.patch
create mode 100644 recipes-core/glibc/glibc/CVE-2014-7817-wordexp-fails-to-honour-WRDE_NOCMD.patch
create mode 100644 recipes-core/glibc/glibc/CVE-2014-9402_endless-loop-in-getaddr_r.patch
create mode 100644 recipes-core/glibc/glibc/CVE-2015-1781-resolv-nss_dns-dns-host.c-buffer-overf.patch
create mode 100644 recipes-core/glibc/glibc/GLRO_dl_debug_mask.patch
create mode 100644 recipes-core/glibc/glibc/IO-acquire-lock-fix.patch
create mode 100644 recipes-core/glibc/glibc/add_resource_h_to_wait_h.patch
create mode 100644 recipes-core/glibc/glibc/eglibc-header-bootstrap.patch
create mode 100644 recipes-core/glibc/glibc/eglibc-install-pic-archives.patch
create mode 100644 recipes-core/glibc/glibc/eglibc-ppc8xx-cache-line-workaround.patch
create mode 100644 recipes-core/glibc/glibc/eglibc-resolv-dynamic.patch
create mode 100644 recipes-core/glibc/glibc/eglibc-sh4-fpscr_values.patch
create mode 100644 recipes-core/glibc/glibc/eglibc-use-option-groups.patch
create mode 100644 recipes-core/glibc/glibc/eglibc.patch
create mode 100644 recipes-core/glibc/glibc/etc/ld.so.conf
create mode 100644 recipes-core/glibc/glibc/fix-tibetian-locales.patch
create mode 100644 recipes-core/glibc/glibc/fix_am_rootsbindir.patch
create mode 100644 recipes-core/glibc/glibc/fsl-ppc-no-fsqrt.patch
create mode 100644 recipes-core/glibc/glibc/generate-supported.mk
create mode 100644 recipes-core/glibc/glibc/glibc.fix_sqrt2.patch
create mode 100644 recipes-core/glibc/glibc/grok_gold.patch
create mode 100644 recipes-core/glibc/glibc/initgroups_keys.patch
create mode 100644 recipes-core/glibc/glibc/intl-Merge-with-gettext-version-0.19.3.patch
create mode 100644 recipes-core/glibc/glibc/ld-search-order.patch
create mode 100644 recipes-core/glibc/glibc/mips-rld-map-check.patch
create mode 100644 recipes-core/glibc/glibc/multilib_readlib.patch
create mode 100644 recipes-core/glibc/glibc/option-groups.patch
create mode 100644 recipes-core/glibc/glibc/ppc-sqrt_finite.patch
create mode 100644 recipes-core/glibc/glibc/ppc_slow_ieee754_sqrt.patch
create mode 100644 recipes-core/glibc/glibc/ppce6500-32b_slow_ieee754_sqrt.patch
create mode 100644 recipes-core/glibc/glibc/relocatable_sdk.patch
create mode 100644 recipes-core/glibc/glibc/relocatable_sdk_fix_openpath.patch
create mode 100644 recipes-core/glibc/glibc/timezone-re-written-tzselect-as-posix-sh.patch
create mode 100644 recipes-core/glibc/glibc_2.20.bb
create mode 100644 recipes-core/glibc/ldconfig-native-2.12.1/32and64bit.patch
create mode 100644 recipes-core/glibc/ldconfig-native-2.12.1/README
create mode 100644 recipes-core/glibc/ldconfig-native-2.12.1/endian-ness_handling.patch
create mode 100644 recipes-core/glibc/ldconfig-native-2.12.1/endian-ness_handling_fix.patch
create mode 100644 recipes-core/glibc/ldconfig-native-2.12.1/endianess-header.patch
create mode 100644 recipes-core/glibc/ldconfig-native-2.12.1/flag_fix.patch
create mode 100644 recipes-core/glibc/ldconfig-native-2.12.1/ldconfig-default-to-all-multilib-dirs.patch
create mode 100644 recipes-core/glibc/ldconfig-native-2.12.1/ldconfig-native-2.12.1.tar.bz2
create mode 100644 recipes-core/glibc/ldconfig-native-2.12.1/ldconfig.patch
create mode 100644 recipes-core/glibc/ldconfig-native-2.12.1/ldconfig_aux-cache_path_fix.patch
create mode 100644 recipes-core/glibc/ldconfig-native_2.12.1.bb
create mode 100644 recipes-core/glibc/site_config/funcs
create mode 100644 recipes-core/glibc/site_config/headers
create mode 100644 recipes-core/glibc/site_config/types
diff --git a/recipes-core/glibc/cross-localedef-native/fix_for_centos_5.8.patch b/recipes-core/glibc/cross-localedef-native/fix_for_centos_5.8.patch
new file mode 100644
index 0000000..186a480
--- /dev/null
+++ b/recipes-core/glibc/cross-localedef-native/fix_for_centos_5.8.patch
@@ -0,0 +1,18 @@
+Upstream-Status: Inappropriate [other]
+
+This is a hack to fix building the locale bits on an older
+CentOs 5.X machine
+
+Index: git/locale/programs/config.h
+===================================================================
+--- git/locale/programs/config.h
++++ git.orig/locale/programs/config.h
+@@ -19,6 +19,8 @@
+ #ifndef _LD_CONFIG_H
+ #define _LD_CONFIG_H 1
+
++#define DUMMY_LOCALE_T
++
+ /* Use the internal textdomain used for libc messages. */
+ #define PACKAGE _libc_intl_domainname
+ #ifndef VERSION
diff --git a/recipes-core/glibc/cross-localedef-native_2.20.bb b/recipes-core/glibc/cross-localedef-native_2.20.bb
new file mode 100644
index 0000000..c94501a
--- /dev/null
+++ b/recipes-core/glibc/cross-localedef-native_2.20.bb
@@ -0,0 +1,57 @@
+SUMMARY = "Cross locale generation tool for glibc"
+HOMEPAGE = "http://www.gnu.org/software/libc/libc.html"
+SECTION = "libs"
+LICENSE = "LGPL-2.1"
+
+LIC_FILES_CHKSUM = "file://LICENSES;md5=e9a558e243b36d3209f380deb394b213 \
+ file://COPYING;md5=b234ee4d69f5fce4486a80fdaf4a4263 \
+ file://posix/rxspencer/COPYRIGHT;md5=dc5485bb394a13b2332ec1c785f5d83a \
+ file://COPYING.LIB;md5=4fbd65380cdd255951079008b364516c"
+
+
+inherit native
+inherit autotools
+
+FILESEXTRAPATHS =. "${FILE_DIRNAME}/${PN}:${FILE_DIRNAME}/glibc:"
+
+PV = "2.20"
+
+SRC_URI = "git://sourceware.org/git/glibc.git;branch=release/${PV}/master;name=glibc \
+ git://github.com/kraj/localedef;branch=master;name=localedef;destsuffix=git/localedef \
+ file://fix_for_centos_5.8.patch \
+ ${EGLIBCPATCHES} \
+ "
+EGLIBCPATCHES = "\
+ file://intl-Merge-with-gettext-version-0.19.3.patch \
+ file://timezone-re-written-tzselect-as-posix-sh.patch \
+ file://eglibc.patch \
+ file://option-groups.patch \
+ file://GLRO_dl_debug_mask.patch \
+ file://eglibc-header-bootstrap.patch \
+ file://eglibc-resolv-dynamic.patch \
+ file://eglibc-ppc8xx-cache-line-workaround.patch \
+ file://eglibc-sh4-fpscr_values.patch \
+ file://eglibc-use-option-groups.patch \
+ "
+
+SRCREV_glibc = "b8079dd0d360648e4e8de48656c5c38972621072"
+SRCREV_localedef = "c833367348d39dad7ba018990bfdaffaec8e9ed3"
+
+# Makes for a rather long rev (22 characters), but...
+#
+SRCREV_FORMAT = "glibc__localedef"
+
+S = "${WORKDIR}/git"
+
+EXTRA_OECONF = "--with-glibc=${S}"
+CFLAGS += "-fgnu89-inline -std=gnu99 -DNOT_IN_libc=1"
+
+do_configure () {
+ ${S}/localedef/configure ${EXTRA_OECONF}
+}
+
+
+do_install() {
+ install -d ${D}${bindir}
+ install -m 0755 ${B}/localedef ${D}${bindir}/cross-localedef
+}
diff --git a/recipes-core/glibc/cross-localedef-native_2.22.bb b/recipes-core/glibc/cross-localedef-native_2.22.bb
new file mode 100644
index 0000000..03be9c0
--- /dev/null
+++ b/recipes-core/glibc/cross-localedef-native_2.22.bb
@@ -0,0 +1,59 @@
+SUMMARY = "Cross locale generation tool for glibc"
+HOMEPAGE = "http://www.gnu.org/software/libc/libc.html"
+SECTION = "libs"
+LICENSE = "LGPL-2.1"
+
+LIC_FILES_CHKSUM = "file://LICENSES;md5=e9a558e243b36d3209f380deb394b213 \
+ file://COPYING;md5=b234ee4d69f5fce4486a80fdaf4a4263 \
+ file://posix/rxspencer/COPYRIGHT;md5=dc5485bb394a13b2332ec1c785f5d83a \
+ file://COPYING.LIB;md5=4fbd65380cdd255951079008b364516c"
+
+
+inherit native
+inherit autotools
+
+FILESEXTRAPATHS =. "${FILE_DIRNAME}/${PN}:${FILE_DIRNAME}/glibc:"
+
+SRCBRANCH ?= "release/${PV}/master"
+GLIBC_GIT_URI ?= "git://sourceware.org/git/glibc.git"
+
+SRC_URI = "${GLIBC_GIT_URI};branch=${SRCBRANCH};name=glibc \
+ git://github.com/kraj/localedef;branch=master;name=localedef;destsuffix=git/localedef \
+ file://fix_for_centos_5.8.patch \
+ ${EGLIBCPATCHES} \
+"
+EGLIBCPATCHES = "\
+ file://0017-timezone-re-written-tzselect-as-posix-sh.patch \
+ file://0018-eglibc-Cross-building-and-testing-instructions.patch \
+ file://0019-eglibc-Bring-Eglibc-option-group-infrastructure-to-g.patch \
+ file://0020-eglibc-Help-bootstrap-cross-toolchain.patch \
+ file://0021-eglibc-cherry-picked-from-http-www.eglibc.org-archiv.patch \
+ file://0022-eglibc-Clear-cache-lines-on-ppc8xx.patch \
+ file://0023-eglibc-Resolve-__fpscr_values-on-SH4.patch \
+ file://0024-eglibc-Forward-port-eglibc-options-groups-support.patch \
+ file://0025-eglibc-Install-PIC-archives.patch \
+ file://0026-eglibc-dl_debug_mask-is-controlled-by-__OPTION_EGLIB.patch \
+ file://0027-eglibc-use-option-groups-Conditionally-exclude-c-tes.patch \
+"
+
+SRCREV_glibc ?= "a34d1c6afc86521d6ad17662a3b5362d8481514c"
+SRCREV_localedef ?= "c833367348d39dad7ba018990bfdaffaec8e9ed3"
+
+# Makes for a rather long rev (22 characters), but...
+#
+SRCREV_FORMAT = "glibc_localedef"
+
+S = "${WORKDIR}/git"
+
+EXTRA_OECONF = "--with-glibc=${S}"
+CFLAGS += "-fgnu89-inline -std=gnu99 -DIS_IN\(x\)='0'"
+
+do_configure () {
+ ${S}/localedef/configure ${EXTRA_OECONF}
+}
+
+
+do_install() {
+ install -d ${D}${bindir}
+ install -m 0755 ${B}/localedef ${D}${bindir}/cross-localedef
+}
diff --git a/recipes-core/glibc/cross-localedef-native_2.22.bbappend b/recipes-core/glibc/cross-localedef-native_2.22.bbappend
new file mode 100644
index 0000000..2fe775d
--- /dev/null
+++ b/recipes-core/glibc/cross-localedef-native_2.22.bbappend
@@ -0,0 +1,7 @@
+FILESEXTRAPATHS_prepend := "${THISDIR}/${BPN}:"
+
+# We need this patch to allow host side aarch64
+SRC_URI_append_fsl-qoriq = "\
+ file://enable-host-aarch64.patch \
+"
+
diff --git a/recipes-core/glibc/cross-localedef/enable-host-aarch64.patch b/recipes-core/glibc/cross-localedef/enable-host-aarch64.patch
new file mode 100644
index 0000000..c129a51
--- /dev/null
+++ b/recipes-core/glibc/cross-localedef/enable-host-aarch64.patch
@@ -0,0 +1,13 @@
+diff --git a/localedef/config.guess b/localedef/config.guess
+index 61f2e4c..9834a43 100644
+--- a/localedef/config.guess
++++ b/localedef/config.guess
+@@ -820,7 +820,7 @@ EOF
+ i*86:Minix:*:*)
+ echo ${UNAME_MACHINE}-pc-minix
+ exit 0 ;;
+- arm*:Linux:*:*)
++ arm*:Linux:*:* | aarch*:Linux:*:*)
+ echo ${UNAME_MACHINE}-unknown-linux-gnu
+ exit 0 ;;
+ cris:Linux:*:*)
diff --git a/recipes-core/glibc/glibc-common.inc b/recipes-core/glibc/glibc-common.inc
new file mode 100644
index 0000000..bba1568
--- /dev/null
+++ b/recipes-core/glibc/glibc-common.inc
@@ -0,0 +1,9 @@
+SUMMARY = "GLIBC (GNU C Library)"
+DESCRIPTION = "The GNU C Library is used as the system C library in most systems with the Linux kernel."
+HOMEPAGE = "http://www.gnu.org/software/libc/libc.html"
+SECTION = "libs"
+LICENSE = "GPLv2 & LGPLv2.1"
+LIC_FILES_CHKSUM ?= "file://LICENSES;md5=07a394b26e0902b9ffdec03765209770 \
+ file://COPYING;md5=393a5ca445f6965873eca0259a17f833 \
+ file://posix/rxspencer/COPYRIGHT;md5=dc5485bb394a13b2332ec1c785f5d83a \
+ file://COPYING.LIB;md5=bbb461211a33b134d42ed5ee802b37ff "
diff --git a/recipes-core/glibc/glibc-fsl/0001.glibc.fix_sqrt2.patch b/recipes-core/glibc/glibc-fsl/0001.glibc.fix_sqrt2.patch
new file mode 100755
index 0000000..16f742a
--- /dev/null
+++ b/recipes-core/glibc/glibc-fsl/0001.glibc.fix_sqrt2.patch
@@ -0,0 +1,1692 @@
+diff -ruN libc-orig/sysdeps/powerpc/powerpc32/603e/fpu/e_sqrt.c libc/sysdeps/powerpc/powerpc32/603e/fpu/e_sqrt.c
+--- libc-orig/sysdeps/powerpc/powerpc32/603e/fpu/e_sqrt.c 1969-12-31 18:00:00.000000000 -0600
++++ libc/sysdeps/powerpc/powerpc32/603e/fpu/e_sqrt.c 2012-06-14 14:51:50.452001745 -0500
+@@ -0,0 +1,134 @@
++/* Double-precision floating point square root.
++ Copyright (C) 2010 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 <math.h>
++#include <math_private.h>
++#include <fenv_libc.h>
++#include <inttypes.h>
++
++#include <sysdep.h>
++#include <ldsodefs.h>
++
++static const ieee_float_shape_type a_nan = {.word = 0x7fc00000 };
++static const ieee_float_shape_type a_inf = {.word = 0x7f800000 };
++static const float two108 = 3.245185536584267269e+32;
++static const float twom54 = 5.551115123125782702e-17;
++static const float half = 0.5;
++
++/* The method is based on the descriptions in:
++
++ _The Handbook of Floating-Pointer Arithmetic_ by Muller et al., chapter 5;
++ _IA-64 and Elementary Functions: Speed and Precision_ by Markstein, chapter 9
++
++ We find the actual square root and half of its reciprocal
++ simultaneously. */
++
++#ifdef __STDC__
++double
++__ieee754_sqrt (double b)
++#else
++double
++__ieee754_sqrt (b)
++ double b;
++#endif
++{
++ if (__builtin_expect (b > 0, 1))
++ {
++ double y, g, h, d, r;
++ ieee_double_shape_type u;
++
++ if (__builtin_expect (b != a_inf.value, 1))
++ {
++ fenv_t fe;
++
++ fe = fegetenv_register ();
++
++ u.value = b;
++
++ relax_fenv_state ();
++
++ __asm__ ("frsqrte %[estimate], %[x]\n"
++ : [estimate] "=f" (y) : [x] "f" (b));
++
++ /* Following Muller et al, page 168, equation 5.20.
++
++ h goes to 1/(2*sqrt(b))
++ g goes to sqrt(b).
++
++ We need three iterations to get within 1ulp. */
++
++ /* Indicate that these can be performed prior to the branch. GCC
++ insists on sinking them below the branch, however; it seems like
++ they'd be better before the branch so that we can cover any latency
++ from storing the argument and loading its high word. Oh well. */
++
++ g = b * y;
++ h = 0.5 * y;
++
++ /* Handle small numbers by scaling. */
++ if (__builtin_expect ((u.parts.msw & 0x7ff00000) <= 0x02000000, 0))
++ return __ieee754_sqrt (b * two108) * twom54;
++
++#define FMADD(a_, c_, b_) \
++ ({ double __r; \
++ __asm__ ("fmadd %[r], %[a], %[c], %[b]\n" \
++ : [r] "=f" (__r) : [a] "f" (a_), [c] "f" (c_), [b] "f" (b_)); \
++ __r;})
++#define FNMSUB(a_, c_, b_) \
++ ({ double __r; \
++ __asm__ ("fnmsub %[r], %[a], %[c], %[b]\n" \
++ : [r] "=f" (__r) : [a] "f" (a_), [c] "f" (c_), [b] "f" (b_)); \
++ __r;})
++
++ r = FNMSUB (g, h, half);
++ g = FMADD (g, r, g);
++ h = FMADD (h, r, h);
++
++ r = FNMSUB (g, h, half);
++ g = FMADD (g, r, g);
++ h = FMADD (h, r, h);
++
++ r = FNMSUB (g, h, half);
++ g = FMADD (g, r, g);
++ h = FMADD (h, r, h);
++
++ /* g is now +/- 1ulp, or exactly equal to, the square root of b. */
++
++ /* Final refinement. */
++ d = FNMSUB (g, g, b);
++
++ fesetenv_register (fe);
++ return FMADD (d, h, g);
++ }
++ }
++ else if (b < 0)
++ {
++ /* For some reason, some PowerPC32 processors don't implement
++ FE_INVALID_SQRT. */
++#ifdef FE_INVALID_SQRT
++ feraiseexcept (FE_INVALID_SQRT);
++
++ fenv_union_t u = { .fenv = fegetenv_register () };
++ if ((u.l[1] & FE_INVALID) == 0)
++#endif
++ feraiseexcept (FE_INVALID);
++ b = a_nan.value;
++ }
++ return f_wash (b);
++}
+diff -ruN libc-orig/sysdeps/powerpc/powerpc32/603e/fpu/e_sqrtf.c libc/sysdeps/powerpc/powerpc32/603e/fpu/e_sqrtf.c
+--- libc-orig/sysdeps/powerpc/powerpc32/603e/fpu/e_sqrtf.c 1969-12-31 18:00:00.000000000 -0600
++++ libc/sysdeps/powerpc/powerpc32/603e/fpu/e_sqrtf.c 2012-06-14 14:51:50.452001745 -0500
+@@ -0,0 +1,101 @@
++/* Single-precision floating point square root.
++ Copyright (C) 2010 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 <math.h>
++#include <math_private.h>
++#include <fenv_libc.h>
++#include <inttypes.h>
++
++#include <sysdep.h>
++#include <ldsodefs.h>
++
++static const ieee_float_shape_type a_nan = {.word = 0x7fc00000 };
++static const ieee_float_shape_type a_inf = {.word = 0x7f800000 };
++static const float threehalf = 1.5;
++
++/* The method is based on the descriptions in:
++
++ _The Handbook of Floating-Pointer Arithmetic_ by Muller et al., chapter 5;
++ _IA-64 and Elementary Functions: Speed and Precision_ by Markstein, chapter 9
++
++ We find the reciprocal square root and use that to compute the actual
++ square root. */
++
++#ifdef __STDC__
++float
++__ieee754_sqrtf (float b)
++#else
++float
++__ieee754_sqrtf (b)
++ float b;
++#endif
++{
++ if (__builtin_expect (b > 0, 1))
++ {
++#define FMSUB(a_, c_, b_) \
++ ({ double __r; \
++ __asm__ ("fmsub %[r], %[a], %[c], %[b]\n" \
++ : [r] "=f" (__r) : [a] "f" (a_), [c] "f" (c_), [b] "f" (b_)); \
++ __r;})
++#define FNMSUB(a_, c_, b_) \
++ ({ double __r; \
++ __asm__ ("fnmsub %[r], %[a], %[c], %[b]\n" \
++ : [r] "=f" (__r) : [a] "f" (a_), [c] "f" (c_), [b] "f" (b_)); \
++ __r;})
++
++ if (__builtin_expect (b != a_inf.value, 1))
++ {
++ double y, x;
++ fenv_t fe;
++
++ fe = fegetenv_register ();
++
++ relax_fenv_state ();
++
++ /* Compute y = 1.5 * b - b. Uses fewer constants than y = 0.5 * b. */
++ y = FMSUB (threehalf, b, b);
++
++ /* Initial estimate. */
++ __asm__ ("frsqrte %[x], %[b]\n" : [x] "=f" (x) : [b] "f" (b));
++
++ /* Iterate. x_{n+1} = x_n * (1.5 - y * (x_n * x_n)). */
++ x = x * FNMSUB (y, x * x, threehalf);
++ x = x * FNMSUB (y, x * x, threehalf);
++ x = x * FNMSUB (y, x * x, threehalf);
++
++ /* All done. */
++ fesetenv_register (fe);
++ return x * b;
++ }
++ }
++ else if (b < 0)
++ {
++ /* For some reason, some PowerPC32 processors don't implement
++ FE_INVALID_SQRT. */
++#ifdef FE_INVALID_SQRT
++ feraiseexcept (FE_INVALID_SQRT);
++
++ fenv_union_t u = { .fenv = fegetenv_register () };
++ if ((u.l[1] & FE_INVALID) == 0)
++#endif
++ feraiseexcept (FE_INVALID);
++ b = a_nan.value;
++ }
++ return f_washf (b);
++}
+diff -ruN libc-orig/sysdeps/powerpc/powerpc32/e500mc/fpu/e_sqrt.c libc/sysdeps/powerpc/powerpc32/e500mc/fpu/e_sqrt.c
+--- libc-orig/sysdeps/powerpc/powerpc32/e500mc/fpu/e_sqrt.c 1969-12-31 18:00:00.000000000 -0600
++++ libc/sysdeps/powerpc/powerpc32/e500mc/fpu/e_sqrt.c 2012-06-14 14:55:14.749001061 -0500
+@@ -0,0 +1,134 @@
++/* Double-precision floating point square root.
++ Copyright (C) 2010 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 <math.h>
++#include <math_private.h>
++#include <fenv_libc.h>
++#include <inttypes.h>
++
++#include <sysdep.h>
++#include <ldsodefs.h>
++
++static const ieee_float_shape_type a_nan = {.word = 0x7fc00000 };
++static const ieee_float_shape_type a_inf = {.word = 0x7f800000 };
++static const float two108 = 3.245185536584267269e+32;
++static const float twom54 = 5.551115123125782702e-17;
++static const float half = 0.5;
++
++/* The method is based on the descriptions in:
++
++ _The Handbook of Floating-Pointer Arithmetic_ by Muller et al., chapter 5;
++ _IA-64 and Elementary Functions: Speed and Precision_ by Markstein, chapter 9
++
++ We find the actual square root and half of its reciprocal
++ simultaneously. */
++
++#ifdef __STDC__
++double
++__ieee754_sqrt (double b)
++#else
++double
++__ieee754_sqrt (b)
++ double b;
++#endif
++{
++ if (__builtin_expect (b > 0, 1))
++ {
++ double y, g, h, d, r;
++ ieee_double_shape_type u;
++
++ if (__builtin_expect (b != a_inf.value, 1))
++ {
++ fenv_t fe;
++
++ fe = fegetenv_register ();
++
++ u.value = b;
++
++ relax_fenv_state ();
++
++ __asm__ ("frsqrte %[estimate], %[x]\n"
++ : [estimate] "=f" (y) : [x] "f" (b));
++
++ /* Following Muller et al, page 168, equation 5.20.
++
++ h goes to 1/(2*sqrt(b))
++ g goes to sqrt(b).
++
++ We need three iterations to get within 1ulp. */
++
++ /* Indicate that these can be performed prior to the branch. GCC
++ insists on sinking them below the branch, however; it seems like
++ they'd be better before the branch so that we can cover any latency
++ from storing the argument and loading its high word. Oh well. */
++
++ g = b * y;
++ h = 0.5 * y;
++
++ /* Handle small numbers by scaling. */
++ if (__builtin_expect ((u.parts.msw & 0x7ff00000) <= 0x02000000, 0))
++ return __ieee754_sqrt (b * two108) * twom54;
++
++#define FMADD(a_, c_, b_) \
++ ({ double __r; \
++ __asm__ ("fmadd %[r], %[a], %[c], %[b]\n" \
++ : [r] "=f" (__r) : [a] "f" (a_), [c] "f" (c_), [b] "f" (b_)); \
++ __r;})
++#define FNMSUB(a_, c_, b_) \
++ ({ double __r; \
++ __asm__ ("fnmsub %[r], %[a], %[c], %[b]\n" \
++ : [r] "=f" (__r) : [a] "f" (a_), [c] "f" (c_), [b] "f" (b_)); \
++ __r;})
++
++ r = FNMSUB (g, h, half);
++ g = FMADD (g, r, g);
++ h = FMADD (h, r, h);
++
++ r = FNMSUB (g, h, half);
++ g = FMADD (g, r, g);
++ h = FMADD (h, r, h);
++
++ r = FNMSUB (g, h, half);
++ g = FMADD (g, r, g);
++ h = FMADD (h, r, h);
++
++ /* g is now +/- 1ulp, or exactly equal to, the square root of b. */
++
++ /* Final refinement. */
++ d = FNMSUB (g, g, b);
++
++ fesetenv_register (fe);
++ return FMADD (d, h, g);
++ }
++ }
++ else if (b < 0)
++ {
++ /* For some reason, some PowerPC32 processors don't implement
++ FE_INVALID_SQRT. */
++#ifdef FE_INVALID_SQRT
++ feraiseexcept (FE_INVALID_SQRT);
++
++ fenv_union_t u = { .fenv = fegetenv_register () };
++ if ((u.l[1] & FE_INVALID) == 0)
++#endif
++ feraiseexcept (FE_INVALID);
++ b = a_nan.value;
++ }
++ return f_wash (b);
++}
+diff -ruN libc-orig/sysdeps/powerpc/powerpc32/e500mc/fpu/e_sqrtf.c libc/sysdeps/powerpc/powerpc32/e500mc/fpu/e_sqrtf.c
+--- libc-orig/sysdeps/powerpc/powerpc32/e500mc/fpu/e_sqrtf.c 1969-12-31 18:00:00.000000000 -0600
++++ libc/sysdeps/powerpc/powerpc32/e500mc/fpu/e_sqrtf.c 2012-06-14 14:55:14.749001061 -0500
+@@ -0,0 +1,101 @@
++/* Single-precision floating point square root.
++ Copyright (C) 2010 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 <math.h>
++#include <math_private.h>
++#include <fenv_libc.h>
++#include <inttypes.h>
++
++#include <sysdep.h>
++#include <ldsodefs.h>
++
++static const ieee_float_shape_type a_nan = {.word = 0x7fc00000 };
++static const ieee_float_shape_type a_inf = {.word = 0x7f800000 };
++static const float threehalf = 1.5;
++
++/* The method is based on the descriptions in:
++
++ _The Handbook of Floating-Pointer Arithmetic_ by Muller et al., chapter 5;
++ _IA-64 and Elementary Functions: Speed and Precision_ by Markstein, chapter 9
++
++ We find the reciprocal square root and use that to compute the actual
++ square root. */
++
++#ifdef __STDC__
++float
++__ieee754_sqrtf (float b)
++#else
++float
++__ieee754_sqrtf (b)
++ float b;
++#endif
++{
++ if (__builtin_expect (b > 0, 1))
++ {
++#define FMSUB(a_, c_, b_) \
++ ({ double __r; \
++ __asm__ ("fmsub %[r], %[a], %[c], %[b]\n" \
++ : [r] "=f" (__r) : [a] "f" (a_), [c] "f" (c_), [b] "f" (b_)); \
++ __r;})
++#define FNMSUB(a_, c_, b_) \
++ ({ double __r; \
++ __asm__ ("fnmsub %[r], %[a], %[c], %[b]\n" \
++ : [r] "=f" (__r) : [a] "f" (a_), [c] "f" (c_), [b] "f" (b_)); \
++ __r;})
++
++ if (__builtin_expect (b != a_inf.value, 1))
++ {
++ double y, x;
++ fenv_t fe;
++
++ fe = fegetenv_register ();
++
++ relax_fenv_state ();
++
++ /* Compute y = 1.5 * b - b. Uses fewer constants than y = 0.5 * b. */
++ y = FMSUB (threehalf, b, b);
++
++ /* Initial estimate. */
++ __asm__ ("frsqrte %[x], %[b]\n" : [x] "=f" (x) : [b] "f" (b));
++
++ /* Iterate. x_{n+1} = x_n * (1.5 - y * (x_n * x_n)). */
++ x = x * FNMSUB (y, x * x, threehalf);
++ x = x * FNMSUB (y, x * x, threehalf);
++ x = x * FNMSUB (y, x * x, threehalf);
++
++ /* All done. */
++ fesetenv_register (fe);
++ return x * b;
++ }
++ }
++ else if (b < 0)
++ {
++ /* For some reason, some PowerPC32 processors don't implement
++ FE_INVALID_SQRT. */
++#ifdef FE_INVALID_SQRT
++ feraiseexcept (FE_INVALID_SQRT);
++
++ fenv_union_t u = { .fenv = fegetenv_register () };
++ if ((u.l[1] & FE_INVALID) == 0)
++#endif
++ feraiseexcept (FE_INVALID);
++ b = a_nan.value;
++ }
++ return f_washf (b);
++}
+diff -ruN libc-orig/sysdeps/powerpc/powerpc32/e5500/fpu/e_sqrt.c libc/sysdeps/powerpc/powerpc32/e5500/fpu/e_sqrt.c
+--- libc-orig/sysdeps/powerpc/powerpc32/e5500/fpu/e_sqrt.c 1969-12-31 18:00:00.000000000 -0600
++++ libc/sysdeps/powerpc/powerpc32/e5500/fpu/e_sqrt.c 2012-06-14 14:55:21.812002270 -0500
+@@ -0,0 +1,134 @@
++/* Double-precision floating point square root.
++ Copyright (C) 2010 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 <math.h>
++#include <math_private.h>
++#include <fenv_libc.h>
++#include <inttypes.h>
++
++#include <sysdep.h>
++#include <ldsodefs.h>
++
++static const ieee_float_shape_type a_nan = {.word = 0x7fc00000 };
++static const ieee_float_shape_type a_inf = {.word = 0x7f800000 };
++static const float two108 = 3.245185536584267269e+32;
++static const float twom54 = 5.551115123125782702e-17;
++static const float half = 0.5;
++
++/* The method is based on the descriptions in:
++
++ _The Handbook of Floating-Pointer Arithmetic_ by Muller et al., chapter 5;
++ _IA-64 and Elementary Functions: Speed and Precision_ by Markstein, chapter 9
++
++ We find the actual square root and half of its reciprocal
++ simultaneously. */
++
++#ifdef __STDC__
++double
++__ieee754_sqrt (double b)
++#else
++double
++__ieee754_sqrt (b)
++ double b;
++#endif
++{
++ if (__builtin_expect (b > 0, 1))
++ {
++ double y, g, h, d, r;
++ ieee_double_shape_type u;
++
++ if (__builtin_expect (b != a_inf.value, 1))
++ {
++ fenv_t fe;
++
++ fe = fegetenv_register ();
++
++ u.value = b;
++
++ relax_fenv_state ();
++
++ __asm__ ("frsqrte %[estimate], %[x]\n"
++ : [estimate] "=f" (y) : [x] "f" (b));
++
++ /* Following Muller et al, page 168, equation 5.20.
++
++ h goes to 1/(2*sqrt(b))
++ g goes to sqrt(b).
++
++ We need three iterations to get within 1ulp. */
++
++ /* Indicate that these can be performed prior to the branch. GCC
++ insists on sinking them below the branch, however; it seems like
++ they'd be better before the branch so that we can cover any latency
++ from storing the argument and loading its high word. Oh well. */
++
++ g = b * y;
++ h = 0.5 * y;
++
++ /* Handle small numbers by scaling. */
++ if (__builtin_expect ((u.parts.msw & 0x7ff00000) <= 0x02000000, 0))
++ return __ieee754_sqrt (b * two108) * twom54;
++
++#define FMADD(a_, c_, b_) \
++ ({ double __r; \
++ __asm__ ("fmadd %[r], %[a], %[c], %[b]\n" \
++ : [r] "=f" (__r) : [a] "f" (a_), [c] "f" (c_), [b] "f" (b_)); \
++ __r;})
++#define FNMSUB(a_, c_, b_) \
++ ({ double __r; \
++ __asm__ ("fnmsub %[r], %[a], %[c], %[b]\n" \
++ : [r] "=f" (__r) : [a] "f" (a_), [c] "f" (c_), [b] "f" (b_)); \
++ __r;})
++
++ r = FNMSUB (g, h, half);
++ g = FMADD (g, r, g);
++ h = FMADD (h, r, h);
++
++ r = FNMSUB (g, h, half);
++ g = FMADD (g, r, g);
++ h = FMADD (h, r, h);
++
++ r = FNMSUB (g, h, half);
++ g = FMADD (g, r, g);
++ h = FMADD (h, r, h);
++
++ /* g is now +/- 1ulp, or exactly equal to, the square root of b. */
++
++ /* Final refinement. */
++ d = FNMSUB (g, g, b);
++
++ fesetenv_register (fe);
++ return FMADD (d, h, g);
++ }
++ }
++ else if (b < 0)
++ {
++ /* For some reason, some PowerPC32 processors don't implement
++ FE_INVALID_SQRT. */
++#ifdef FE_INVALID_SQRT
++ feraiseexcept (FE_INVALID_SQRT);
++
++ fenv_union_t u = { .fenv = fegetenv_register () };
++ if ((u.l[1] & FE_INVALID) == 0)
++#endif
++ feraiseexcept (FE_INVALID);
++ b = a_nan.value;
++ }
++ return f_wash (b);
++}
+diff -ruN libc-orig/sysdeps/powerpc/powerpc32/e5500/fpu/e_sqrtf.c libc/sysdeps/powerpc/powerpc32/e5500/fpu/e_sqrtf.c
+--- libc-orig/sysdeps/powerpc/powerpc32/e5500/fpu/e_sqrtf.c 1969-12-31 18:00:00.000000000 -0600
++++ libc/sysdeps/powerpc/powerpc32/e5500/fpu/e_sqrtf.c 2012-06-14 14:55:21.812002270 -0500
+@@ -0,0 +1,101 @@
++/* Single-precision floating point square root.
++ Copyright (C) 2010 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 <math.h>
++#include <math_private.h>
++#include <fenv_libc.h>
++#include <inttypes.h>
++
++#include <sysdep.h>
++#include <ldsodefs.h>
++
++static const ieee_float_shape_type a_nan = {.word = 0x7fc00000 };
++static const ieee_float_shape_type a_inf = {.word = 0x7f800000 };
++static const float threehalf = 1.5;
++
++/* The method is based on the descriptions in:
++
++ _The Handbook of Floating-Pointer Arithmetic_ by Muller et al., chapter 5;
++ _IA-64 and Elementary Functions: Speed and Precision_ by Markstein, chapter 9
++
++ We find the reciprocal square root and use that to compute the actual
++ square root. */
++
++#ifdef __STDC__
++float
++__ieee754_sqrtf (float b)
++#else
++float
++__ieee754_sqrtf (b)
++ float b;
++#endif
++{
++ if (__builtin_expect (b > 0, 1))
++ {
++#define FMSUB(a_, c_, b_) \
++ ({ double __r; \
++ __asm__ ("fmsub %[r], %[a], %[c], %[b]\n" \
++ : [r] "=f" (__r) : [a] "f" (a_), [c] "f" (c_), [b] "f" (b_)); \
++ __r;})
++#define FNMSUB(a_, c_, b_) \
++ ({ double __r; \
++ __asm__ ("fnmsub %[r], %[a], %[c], %[b]\n" \
++ : [r] "=f" (__r) : [a] "f" (a_), [c] "f" (c_), [b] "f" (b_)); \
++ __r;})
++
++ if (__builtin_expect (b != a_inf.value, 1))
++ {
++ double y, x;
++ fenv_t fe;
++
++ fe = fegetenv_register ();
++
++ relax_fenv_state ();
++
++ /* Compute y = 1.5 * b - b. Uses fewer constants than y = 0.5 * b. */
++ y = FMSUB (threehalf, b, b);
++
++ /* Initial estimate. */
++ __asm__ ("frsqrte %[x], %[b]\n" : [x] "=f" (x) : [b] "f" (b));
++
++ /* Iterate. x_{n+1} = x_n * (1.5 - y * (x_n * x_n)). */
++ x = x * FNMSUB (y, x * x, threehalf);
++ x = x * FNMSUB (y, x * x, threehalf);
++ x = x * FNMSUB (y, x * x, threehalf);
++
++ /* All done. */
++ fesetenv_register (fe);
++ return x * b;
++ }
++ }
++ else if (b < 0)
++ {
++ /* For some reason, some PowerPC32 processors don't implement
++ FE_INVALID_SQRT. */
++#ifdef FE_INVALID_SQRT
++ feraiseexcept (FE_INVALID_SQRT);
++
++ fenv_union_t u = { .fenv = fegetenv_register () };
++ if ((u.l[1] & FE_INVALID) == 0)
++#endif
++ feraiseexcept (FE_INVALID);
++ b = a_nan.value;
++ }
++ return f_washf (b);
++}
+diff -ruN libc-orig/sysdeps/powerpc/powerpc32/e6500/fpu/e_sqrt.c libc/sysdeps/powerpc/powerpc32/e6500/fpu/e_sqrt.c
+--- libc-orig/sysdeps/powerpc/powerpc32/e6500/fpu/e_sqrt.c 1969-12-31 18:00:00.000000000 -0600
++++ libc/sysdeps/powerpc/powerpc32/e6500/fpu/e_sqrt.c 2012-06-14 14:55:24.620001266 -0500
+@@ -0,0 +1,134 @@
++/* Double-precision floating point square root.
++ Copyright (C) 2010 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 <math.h>
++#include <math_private.h>
++#include <fenv_libc.h>
++#include <inttypes.h>
++
++#include <sysdep.h>
++#include <ldsodefs.h>
++
++static const ieee_float_shape_type a_nan = {.word = 0x7fc00000 };
++static const ieee_float_shape_type a_inf = {.word = 0x7f800000 };
++static const float two108 = 3.245185536584267269e+32;
++static const float twom54 = 5.551115123125782702e-17;
++static const float half = 0.5;
++
++/* The method is based on the descriptions in:
++
++ _The Handbook of Floating-Pointer Arithmetic_ by Muller et al., chapter 5;
++ _IA-64 and Elementary Functions: Speed and Precision_ by Markstein, chapter 9
++
++ We find the actual square root and half of its reciprocal
++ simultaneously. */
++
++#ifdef __STDC__
++double
++__ieee754_sqrt (double b)
++#else
++double
++__ieee754_sqrt (b)
++ double b;
++#endif
++{
++ if (__builtin_expect (b > 0, 1))
++ {
++ double y, g, h, d, r;
++ ieee_double_shape_type u;
++
++ if (__builtin_expect (b != a_inf.value, 1))
++ {
++ fenv_t fe;
++
++ fe = fegetenv_register ();
++
++ u.value = b;
++
++ relax_fenv_state ();
++
++ __asm__ ("frsqrte %[estimate], %[x]\n"
++ : [estimate] "=f" (y) : [x] "f" (b));
++
++ /* Following Muller et al, page 168, equation 5.20.
++
++ h goes to 1/(2*sqrt(b))
++ g goes to sqrt(b).
++
++ We need three iterations to get within 1ulp. */
++
++ /* Indicate that these can be performed prior to the branch. GCC
++ insists on sinking them below the branch, however; it seems like
++ they'd be better before the branch so that we can cover any latency
++ from storing the argument and loading its high word. Oh well. */
++
++ g = b * y;
++ h = 0.5 * y;
++
++ /* Handle small numbers by scaling. */
++ if (__builtin_expect ((u.parts.msw & 0x7ff00000) <= 0x02000000, 0))
++ return __ieee754_sqrt (b * two108) * twom54;
++
++#define FMADD(a_, c_, b_) \
++ ({ double __r; \
++ __asm__ ("fmadd %[r], %[a], %[c], %[b]\n" \
++ : [r] "=f" (__r) : [a] "f" (a_), [c] "f" (c_), [b] "f" (b_)); \
++ __r;})
++#define FNMSUB(a_, c_, b_) \
++ ({ double __r; \
++ __asm__ ("fnmsub %[r], %[a], %[c], %[b]\n" \
++ : [r] "=f" (__r) : [a] "f" (a_), [c] "f" (c_), [b] "f" (b_)); \
++ __r;})
++
++ r = FNMSUB (g, h, half);
++ g = FMADD (g, r, g);
++ h = FMADD (h, r, h);
++
++ r = FNMSUB (g, h, half);
++ g = FMADD (g, r, g);
++ h = FMADD (h, r, h);
++
++ r = FNMSUB (g, h, half);
++ g = FMADD (g, r, g);
++ h = FMADD (h, r, h);
++
++ /* g is now +/- 1ulp, or exactly equal to, the square root of b. */
++
++ /* Final refinement. */
++ d = FNMSUB (g, g, b);
++
++ fesetenv_register (fe);
++ return FMADD (d, h, g);
++ }
++ }
++ else if (b < 0)
++ {
++ /* For some reason, some PowerPC32 processors don't implement
++ FE_INVALID_SQRT. */
++#ifdef FE_INVALID_SQRT
++ feraiseexcept (FE_INVALID_SQRT);
++
++ fenv_union_t u = { .fenv = fegetenv_register () };
++ if ((u.l[1] & FE_INVALID) == 0)
++#endif
++ feraiseexcept (FE_INVALID);
++ b = a_nan.value;
++ }
++ return f_wash (b);
++}
+diff -ruN libc-orig/sysdeps/powerpc/powerpc32/e6500/fpu/e_sqrtf.c libc/sysdeps/powerpc/powerpc32/e6500/fpu/e_sqrtf.c
+--- libc-orig/sysdeps/powerpc/powerpc32/e6500/fpu/e_sqrtf.c 1969-12-31 18:00:00.000000000 -0600
++++ libc/sysdeps/powerpc/powerpc32/e6500/fpu/e_sqrtf.c 2012-06-14 14:55:24.620001266 -0500
+@@ -0,0 +1,101 @@
++/* Single-precision floating point square root.
++ Copyright (C) 2010 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 <math.h>
++#include <math_private.h>
++#include <fenv_libc.h>
++#include <inttypes.h>
++
++#include <sysdep.h>
++#include <ldsodefs.h>
++
++static const ieee_float_shape_type a_nan = {.word = 0x7fc00000 };
++static const ieee_float_shape_type a_inf = {.word = 0x7f800000 };
++static const float threehalf = 1.5;
++
++/* The method is based on the descriptions in:
++
++ _The Handbook of Floating-Pointer Arithmetic_ by Muller et al., chapter 5;
++ _IA-64 and Elementary Functions: Speed and Precision_ by Markstein, chapter 9
++
++ We find the reciprocal square root and use that to compute the actual
++ square root. */
++
++#ifdef __STDC__
++float
++__ieee754_sqrtf (float b)
++#else
++float
++__ieee754_sqrtf (b)
++ float b;
++#endif
++{
++ if (__builtin_expect (b > 0, 1))
++ {
++#define FMSUB(a_, c_, b_) \
++ ({ double __r; \
++ __asm__ ("fmsub %[r], %[a], %[c], %[b]\n" \
++ : [r] "=f" (__r) : [a] "f" (a_), [c] "f" (c_), [b] "f" (b_)); \
++ __r;})
++#define FNMSUB(a_, c_, b_) \
++ ({ double __r; \
++ __asm__ ("fnmsub %[r], %[a], %[c], %[b]\n" \
++ : [r] "=f" (__r) : [a] "f" (a_), [c] "f" (c_), [b] "f" (b_)); \
++ __r;})
++
++ if (__builtin_expect (b != a_inf.value, 1))
++ {
++ double y, x;
++ fenv_t fe;
++
++ fe = fegetenv_register ();
++
++ relax_fenv_state ();
++
++ /* Compute y = 1.5 * b - b. Uses fewer constants than y = 0.5 * b. */
++ y = FMSUB (threehalf, b, b);
++
++ /* Initial estimate. */
++ __asm__ ("frsqrte %[x], %[b]\n" : [x] "=f" (x) : [b] "f" (b));
++
++ /* Iterate. x_{n+1} = x_n * (1.5 - y * (x_n * x_n)). */
++ x = x * FNMSUB (y, x * x, threehalf);
++ x = x * FNMSUB (y, x * x, threehalf);
++ x = x * FNMSUB (y, x * x, threehalf);
++
++ /* All done. */
++ fesetenv_register (fe);
++ return x * b;
++ }
++ }
++ else if (b < 0)
++ {
++ /* For some reason, some PowerPC32 processors don't implement
++ FE_INVALID_SQRT. */
++#ifdef FE_INVALID_SQRT
++ feraiseexcept (FE_INVALID_SQRT);
++
++ fenv_union_t u = { .fenv = fegetenv_register () };
++ if ((u.l[1] & FE_INVALID) == 0)
++#endif
++ feraiseexcept (FE_INVALID);
++ b = a_nan.value;
++ }
++ return f_washf (b);
++}
+diff -ruN libc-orig/sysdeps/powerpc/powerpc64/e5500/fpu/e_sqrt.c libc/sysdeps/powerpc/powerpc64/e5500/fpu/e_sqrt.c
+--- libc-orig/sysdeps/powerpc/powerpc64/e5500/fpu/e_sqrt.c 1969-12-31 18:00:00.000000000 -0600
++++ libc/sysdeps/powerpc/powerpc64/e5500/fpu/e_sqrt.c 2012-06-14 14:51:50.452001745 -0500
+@@ -0,0 +1,134 @@
++/* Double-precision floating point square root.
++ Copyright (C) 2010 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 <math.h>
++#include <math_private.h>
++#include <fenv_libc.h>
++#include <inttypes.h>
++
++#include <sysdep.h>
++#include <ldsodefs.h>
++
++static const ieee_float_shape_type a_nan = {.word = 0x7fc00000 };
++static const ieee_float_shape_type a_inf = {.word = 0x7f800000 };
++static const float two108 = 3.245185536584267269e+32;
++static const float twom54 = 5.551115123125782702e-17;
++static const float half = 0.5;
++
++/* The method is based on the descriptions in:
++
++ _The Handbook of Floating-Pointer Arithmetic_ by Muller et al., chapter 5;
++ _IA-64 and Elementary Functions: Speed and Precision_ by Markstein, chapter 9
++
++ We find the actual square root and half of its reciprocal
++ simultaneously. */
++
++#ifdef __STDC__
++double
++__ieee754_sqrt (double b)
++#else
++double
++__ieee754_sqrt (b)
++ double b;
++#endif
++{
++ if (__builtin_expect (b > 0, 1))
++ {
++ double y, g, h, d, r;
++ ieee_double_shape_type u;
++
++ if (__builtin_expect (b != a_inf.value, 1))
++ {
++ fenv_t fe;
++
++ fe = fegetenv_register ();
++
++ u.value = b;
++
++ relax_fenv_state ();
++
++ __asm__ ("frsqrte %[estimate], %[x]\n"
++ : [estimate] "=f" (y) : [x] "f" (b));
++
++ /* Following Muller et al, page 168, equation 5.20.
++
++ h goes to 1/(2*sqrt(b))
++ g goes to sqrt(b).
++
++ We need three iterations to get within 1ulp. */
++
++ /* Indicate that these can be performed prior to the branch. GCC
++ insists on sinking them below the branch, however; it seems like
++ they'd be better before the branch so that we can cover any latency
++ from storing the argument and loading its high word. Oh well. */
++
++ g = b * y;
++ h = 0.5 * y;
++
++ /* Handle small numbers by scaling. */
++ if (__builtin_expect ((u.parts.msw & 0x7ff00000) <= 0x02000000, 0))
++ return __ieee754_sqrt (b * two108) * twom54;
++
++#define FMADD(a_, c_, b_) \
++ ({ double __r; \
++ __asm__ ("fmadd %[r], %[a], %[c], %[b]\n" \
++ : [r] "=f" (__r) : [a] "f" (a_), [c] "f" (c_), [b] "f" (b_)); \
++ __r;})
++#define FNMSUB(a_, c_, b_) \
++ ({ double __r; \
++ __asm__ ("fnmsub %[r], %[a], %[c], %[b]\n" \
++ : [r] "=f" (__r) : [a] "f" (a_), [c] "f" (c_), [b] "f" (b_)); \
++ __r;})
++
++ r = FNMSUB (g, h, half);
++ g = FMADD (g, r, g);
++ h = FMADD (h, r, h);
++
++ r = FNMSUB (g, h, half);
++ g = FMADD (g, r, g);
++ h = FMADD (h, r, h);
++
++ r = FNMSUB (g, h, half);
++ g = FMADD (g, r, g);
++ h = FMADD (h, r, h);
++
++ /* g is now +/- 1ulp, or exactly equal to, the square root of b. */
++
++ /* Final refinement. */
++ d = FNMSUB (g, g, b);
++
++ fesetenv_register (fe);
++ return FMADD (d, h, g);
++ }
++ }
++ else if (b < 0)
++ {
++ /* For some reason, some PowerPC32 processors don't implement
++ FE_INVALID_SQRT. */
++#ifdef FE_INVALID_SQRT
++ feraiseexcept (FE_INVALID_SQRT);
++
++ fenv_union_t u = { .fenv = fegetenv_register () };
++ if ((u.l[1] & FE_INVALID) == 0)
++#endif
++ feraiseexcept (FE_INVALID);
++ b = a_nan.value;
++ }
++ return f_wash (b);
++}
+diff -ruN libc-orig/sysdeps/powerpc/powerpc64/e5500/fpu/e_sqrtf.c libc/sysdeps/powerpc/powerpc64/e5500/fpu/e_sqrtf.c
+--- libc-orig/sysdeps/powerpc/powerpc64/e5500/fpu/e_sqrtf.c 1969-12-31 18:00:00.000000000 -0600
++++ libc/sysdeps/powerpc/powerpc64/e5500/fpu/e_sqrtf.c 2012-06-14 14:51:50.452001745 -0500
+@@ -0,0 +1,101 @@
++/* Single-precision floating point square root.
++ Copyright (C) 2010 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 <math.h>
++#include <math_private.h>
++#include <fenv_libc.h>
++#include <inttypes.h>
++
++#include <sysdep.h>
++#include <ldsodefs.h>
++
++static const ieee_float_shape_type a_nan = {.word = 0x7fc00000 };
++static const ieee_float_shape_type a_inf = {.word = 0x7f800000 };
++static const float threehalf = 1.5;
++
++/* The method is based on the descriptions in:
++
++ _The Handbook of Floating-Pointer Arithmetic_ by Muller et al., chapter 5;
++ _IA-64 and Elementary Functions: Speed and Precision_ by Markstein, chapter 9
++
++ We find the reciprocal square root and use that to compute the actual
++ square root. */
++
++#ifdef __STDC__
++float
++__ieee754_sqrtf (float b)
++#else
++float
++__ieee754_sqrtf (b)
++ float b;
++#endif
++{
++ if (__builtin_expect (b > 0, 1))
++ {
++#define FMSUB(a_, c_, b_) \
++ ({ double __r; \
++ __asm__ ("fmsub %[r], %[a], %[c], %[b]\n" \
++ : [r] "=f" (__r) : [a] "f" (a_), [c] "f" (c_), [b] "f" (b_)); \
++ __r;})
++#define FNMSUB(a_, c_, b_) \
++ ({ double __r; \
++ __asm__ ("fnmsub %[r], %[a], %[c], %[b]\n" \
++ : [r] "=f" (__r) : [a] "f" (a_), [c] "f" (c_), [b] "f" (b_)); \
++ __r;})
++
++ if (__builtin_expect (b != a_inf.value, 1))
++ {
++ double y, x;
++ fenv_t fe;
++
++ fe = fegetenv_register ();
++
++ relax_fenv_state ();
++
++ /* Compute y = 1.5 * b - b. Uses fewer constants than y = 0.5 * b. */
++ y = FMSUB (threehalf, b, b);
++
++ /* Initial estimate. */
++ __asm__ ("frsqrte %[x], %[b]\n" : [x] "=f" (x) : [b] "f" (b));
++
++ /* Iterate. x_{n+1} = x_n * (1.5 - y * (x_n * x_n)). */
++ x = x * FNMSUB (y, x * x, threehalf);
++ x = x * FNMSUB (y, x * x, threehalf);
++ x = x * FNMSUB (y, x * x, threehalf);
++
++ /* All done. */
++ fesetenv_register (fe);
++ return x * b;
++ }
++ }
++ else if (b < 0)
++ {
++ /* For some reason, some PowerPC32 processors don't implement
++ FE_INVALID_SQRT. */
++#ifdef FE_INVALID_SQRT
++ feraiseexcept (FE_INVALID_SQRT);
++
++ fenv_union_t u = { .fenv = fegetenv_register () };
++ if ((u.l[1] & FE_INVALID) == 0)
++#endif
++ feraiseexcept (FE_INVALID);
++ b = a_nan.value;
++ }
++ return f_washf (b);
++}
+diff -ruN libc-orig/sysdeps/powerpc/powerpc64/e6500/fpu/e_sqrt.c libc/sysdeps/powerpc/powerpc64/e6500/fpu/e_sqrt.c
+--- libc-orig/sysdeps/powerpc/powerpc64/e6500/fpu/e_sqrt.c 1969-12-31 18:00:00.000000000 -0600
++++ libc/sysdeps/powerpc/powerpc64/e6500/fpu/e_sqrt.c 2012-06-14 14:56:02.080000985 -0500
+@@ -0,0 +1,134 @@
++/* Double-precision floating point square root.
++ Copyright (C) 2010 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 <math.h>
++#include <math_private.h>
++#include <fenv_libc.h>
++#include <inttypes.h>
++
++#include <sysdep.h>
++#include <ldsodefs.h>
++
++static const ieee_float_shape_type a_nan = {.word = 0x7fc00000 };
++static const ieee_float_shape_type a_inf = {.word = 0x7f800000 };
++static const float two108 = 3.245185536584267269e+32;
++static const float twom54 = 5.551115123125782702e-17;
++static const float half = 0.5;
++
++/* The method is based on the descriptions in:
++
++ _The Handbook of Floating-Pointer Arithmetic_ by Muller et al., chapter 5;
++ _IA-64 and Elementary Functions: Speed and Precision_ by Markstein, chapter 9
++
++ We find the actual square root and half of its reciprocal
++ simultaneously. */
++
++#ifdef __STDC__
++double
++__ieee754_sqrt (double b)
++#else
++double
++__ieee754_sqrt (b)
++ double b;
++#endif
++{
++ if (__builtin_expect (b > 0, 1))
++ {
++ double y, g, h, d, r;
++ ieee_double_shape_type u;
++
++ if (__builtin_expect (b != a_inf.value, 1))
++ {
++ fenv_t fe;
++
++ fe = fegetenv_register ();
++
++ u.value = b;
++
++ relax_fenv_state ();
++
++ __asm__ ("frsqrte %[estimate], %[x]\n"
++ : [estimate] "=f" (y) : [x] "f" (b));
++
++ /* Following Muller et al, page 168, equation 5.20.
++
++ h goes to 1/(2*sqrt(b))
++ g goes to sqrt(b).
++
++ We need three iterations to get within 1ulp. */
++
++ /* Indicate that these can be performed prior to the branch. GCC
++ insists on sinking them below the branch, however; it seems like
++ they'd be better before the branch so that we can cover any latency
++ from storing the argument and loading its high word. Oh well. */
++
++ g = b * y;
++ h = 0.5 * y;
++
++ /* Handle small numbers by scaling. */
++ if (__builtin_expect ((u.parts.msw & 0x7ff00000) <= 0x02000000, 0))
++ return __ieee754_sqrt (b * two108) * twom54;
++
++#define FMADD(a_, c_, b_) \
++ ({ double __r; \
++ __asm__ ("fmadd %[r], %[a], %[c], %[b]\n" \
++ : [r] "=f" (__r) : [a] "f" (a_), [c] "f" (c_), [b] "f" (b_)); \
++ __r;})
++#define FNMSUB(a_, c_, b_) \
++ ({ double __r; \
++ __asm__ ("fnmsub %[r], %[a], %[c], %[b]\n" \
++ : [r] "=f" (__r) : [a] "f" (a_), [c] "f" (c_), [b] "f" (b_)); \
++ __r;})
++
++ r = FNMSUB (g, h, half);
++ g = FMADD (g, r, g);
++ h = FMADD (h, r, h);
++
++ r = FNMSUB (g, h, half);
++ g = FMADD (g, r, g);
++ h = FMADD (h, r, h);
++
++ r = FNMSUB (g, h, half);
++ g = FMADD (g, r, g);
++ h = FMADD (h, r, h);
++
++ /* g is now +/- 1ulp, or exactly equal to, the square root of b. */
++
++ /* Final refinement. */
++ d = FNMSUB (g, g, b);
++
++ fesetenv_register (fe);
++ return FMADD (d, h, g);
++ }
++ }
++ else if (b < 0)
++ {
++ /* For some reason, some PowerPC32 processors don't implement
++ FE_INVALID_SQRT. */
++#ifdef FE_INVALID_SQRT
++ feraiseexcept (FE_INVALID_SQRT);
++
++ fenv_union_t u = { .fenv = fegetenv_register () };
++ if ((u.l[1] & FE_INVALID) == 0)
++#endif
++ feraiseexcept (FE_INVALID);
++ b = a_nan.value;
++ }
++ return f_wash (b);
++}
+diff -ruN libc-orig/sysdeps/powerpc/powerpc64/e6500/fpu/e_sqrtf.c libc/sysdeps/powerpc/powerpc64/e6500/fpu/e_sqrtf.c
+--- libc-orig/sysdeps/powerpc/powerpc64/e6500/fpu/e_sqrtf.c 1969-12-31 18:00:00.000000000 -0600
++++ libc/sysdeps/powerpc/powerpc64/e6500/fpu/e_sqrtf.c 2012-06-14 14:56:02.080000985 -0500
+@@ -0,0 +1,101 @@
++/* Single-precision floating point square root.
++ Copyright (C) 2010 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 <math.h>
++#include <math_private.h>
++#include <fenv_libc.h>
++#include <inttypes.h>
++
++#include <sysdep.h>
++#include <ldsodefs.h>
++
++static const ieee_float_shape_type a_nan = {.word = 0x7fc00000 };
++static const ieee_float_shape_type a_inf = {.word = 0x7f800000 };
++static const float threehalf = 1.5;
++
++/* The method is based on the descriptions in:
++
++ _The Handbook of Floating-Pointer Arithmetic_ by Muller et al., chapter 5;
++ _IA-64 and Elementary Functions: Speed and Precision_ by Markstein, chapter 9
++
++ We find the reciprocal square root and use that to compute the actual
++ square root. */
++
++#ifdef __STDC__
++float
++__ieee754_sqrtf (float b)
++#else
++float
++__ieee754_sqrtf (b)
++ float b;
++#endif
++{
++ if (__builtin_expect (b > 0, 1))
++ {
++#define FMSUB(a_, c_, b_) \
++ ({ double __r; \
++ __asm__ ("fmsub %[r], %[a], %[c], %[b]\n" \
++ : [r] "=f" (__r) : [a] "f" (a_), [c] "f" (c_), [b] "f" (b_)); \
++ __r;})
++#define FNMSUB(a_, c_, b_) \
++ ({ double __r; \
++ __asm__ ("fnmsub %[r], %[a], %[c], %[b]\n" \
++ : [r] "=f" (__r) : [a] "f" (a_), [c] "f" (c_), [b] "f" (b_)); \
++ __r;})
++
++ if (__builtin_expect (b != a_inf.value, 1))
++ {
++ double y, x;
++ fenv_t fe;
++
++ fe = fegetenv_register ();
++
++ relax_fenv_state ();
++
++ /* Compute y = 1.5 * b - b. Uses fewer constants than y = 0.5 * b. */
++ y = FMSUB (threehalf, b, b);
++
++ /* Initial estimate. */
++ __asm__ ("frsqrte %[x], %[b]\n" : [x] "=f" (x) : [b] "f" (b));
++
++ /* Iterate. x_{n+1} = x_n * (1.5 - y * (x_n * x_n)). */
++ x = x * FNMSUB (y, x * x, threehalf);
++ x = x * FNMSUB (y, x * x, threehalf);
++ x = x * FNMSUB (y, x * x, threehalf);
++
++ /* All done. */
++ fesetenv_register (fe);
++ return x * b;
++ }
++ }
++ else if (b < 0)
++ {
++ /* For some reason, some PowerPC32 processors don't implement
++ FE_INVALID_SQRT. */
++#ifdef FE_INVALID_SQRT
++ feraiseexcept (FE_INVALID_SQRT);
++
++ fenv_union_t u = { .fenv = fegetenv_register () };
++ if ((u.l[1] & FE_INVALID) == 0)
++#endif
++ feraiseexcept (FE_INVALID);
++ b = a_nan.value;
++ }
++ return f_washf (b);
++}
+diff -ruN libc-orig/sysdeps/unix/sysv/linux/powerpc/powerpc32/603e/fpu/Implies libc/sysdeps/unix/sysv/linux/powerpc/powerpc32/603e/fpu/Implies
+--- libc-orig/sysdeps/unix/sysv/linux/powerpc/powerpc32/603e/fpu/Implies 1969-12-31 18:00:00.000000000 -0600
++++ libc/sysdeps/unix/sysv/linux/powerpc/powerpc32/603e/fpu/Implies 2012-06-14 14:51:50.452001745 -0500
+@@ -0,0 +1 @@
++powerpc/powerpc32/603e/fpu
+diff -ruN libc-orig/sysdeps/unix/sysv/linux/powerpc/powerpc32/e500mc/fpu/Implies libc/sysdeps/unix/sysv/linux/powerpc/powerpc32/e500mc/fpu/Implies
+--- libc-orig/sysdeps/unix/sysv/linux/powerpc/powerpc32/e500mc/fpu/Implies 1969-12-31 18:00:00.000000000 -0600
++++ libc/sysdeps/unix/sysv/linux/powerpc/powerpc32/e500mc/fpu/Implies 2012-06-14 14:54:00.481000876 -0500
+@@ -0,0 +1 @@
++powerpc/powerpc32/e500mc/fpu
+diff -ruN libc-orig/sysdeps/unix/sysv/linux/powerpc/powerpc32/e5500/fpu/Implies libc/sysdeps/unix/sysv/linux/powerpc/powerpc32/e5500/fpu/Implies
+--- libc-orig/sysdeps/unix/sysv/linux/powerpc/powerpc32/e5500/fpu/Implies 1969-12-31 18:00:00.000000000 -0600
++++ libc/sysdeps/unix/sysv/linux/powerpc/powerpc32/e5500/fpu/Implies 2012-06-14 14:54:17.000001007 -0500
+@@ -0,0 +1 @@
++powerpc/powerpc32/e5500/fpu
+diff -ruN libc-orig/sysdeps/unix/sysv/linux/powerpc/powerpc32/e6500/fpu/Implies libc/sysdeps/unix/sysv/linux/powerpc/powerpc32/e6500/fpu/Implies
+--- libc-orig/sysdeps/unix/sysv/linux/powerpc/powerpc32/e6500/fpu/Implies 1969-12-31 18:00:00.000000000 -0600
++++ libc/sysdeps/unix/sysv/linux/powerpc/powerpc32/e6500/fpu/Implies 2012-06-14 14:54:31.054001299 -0500
+@@ -0,0 +1 @@
++powerpc/powerpc32/e6500/fpu
+diff -ruN libc-orig/sysdeps/unix/sysv/linux/powerpc/powerpc64/e5500/fpu/Implies libc/sysdeps/unix/sysv/linux/powerpc/powerpc64/e5500/fpu/Implies
+--- libc-orig/sysdeps/unix/sysv/linux/powerpc/powerpc64/e5500/fpu/Implies 1969-12-31 18:00:00.000000000 -0600
++++ libc/sysdeps/unix/sysv/linux/powerpc/powerpc64/e5500/fpu/Implies 2012-06-14 14:51:50.453001709 -0500
+@@ -0,0 +1 @@
++powerpc/powerpc64/e5500/fpu
+diff -ruN libc-orig/sysdeps/unix/sysv/linux/powerpc/powerpc64/e6500/fpu/Implies libc/sysdeps/unix/sysv/linux/powerpc/powerpc64/e6500/fpu/Implies
+--- libc-orig/sysdeps/unix/sysv/linux/powerpc/powerpc64/e6500/fpu/Implies 1969-12-31 18:00:00.000000000 -0600
++++ libc/sysdeps/unix/sysv/linux/powerpc/powerpc64/e6500/fpu/Implies 2012-06-14 14:58:14.298001288 -0500
+@@ -0,0 +1 @@
++powerpc/powerpc64/e6500/fpu
+diff -Naur libc-sqrt-orig/sysdeps/powerpc/powerpc32/603e/fpu/e_sqrt.c libc-sqrt-patch/sysdeps/powerpc/powerpc32/603e/fpu/e_sqrt.c
+--- libc-sqrt-orig/sysdeps/powerpc/powerpc32/603e/fpu/e_sqrt.c 2014-07-24 04:42:30.366372001 -0500
++++ libc-sqrt-patch/sysdeps/powerpc/powerpc32/603e/fpu/e_sqrt.c 2014-07-24 04:42:46.249372001 -0500
+@@ -80,7 +80,7 @@
+
+ g = b * y;
+ h = 0.5 * y;
+-
++
+ /* Handle small numbers by scaling. */
+ if (__builtin_expect ((u.parts.msw & 0x7ff00000) <= 0x02000000, 0))
+ return __ieee754_sqrt (b * two108) * twom54;
+@@ -125,7 +125,7 @@
+ feraiseexcept (FE_INVALID_SQRT);
+
+ fenv_union_t u = { .fenv = fegetenv_register () };
+- if ((u.l[1] & FE_INVALID) == 0)
++ if ((u.l & FE_INVALID) == 0)
+ #endif
+ feraiseexcept (FE_INVALID);
+ b = a_nan.value;
+diff -Naur libc-sqrt-orig/sysdeps/powerpc/powerpc32/603e/fpu/e_sqrtf.c libc-sqrt-patch/sysdeps/powerpc/powerpc32/603e/fpu/e_sqrtf.c
+--- libc-sqrt-orig/sysdeps/powerpc/powerpc32/603e/fpu/e_sqrtf.c 2014-07-24 04:42:30.366372001 -0500
++++ libc-sqrt-patch/sysdeps/powerpc/powerpc32/603e/fpu/e_sqrtf.c 2014-07-24 04:42:46.249372001 -0500
+@@ -92,7 +92,7 @@
+ feraiseexcept (FE_INVALID_SQRT);
+
+ fenv_union_t u = { .fenv = fegetenv_register () };
+- if ((u.l[1] & FE_INVALID) == 0)
++ if ((u.l & FE_INVALID) == 0)
+ #endif
+ feraiseexcept (FE_INVALID);
+ b = a_nan.value;
+diff -Naur libc-sqrt-orig/sysdeps/powerpc/powerpc32/e500mc/fpu/e_sqrt.c libc-sqrt-patch/sysdeps/powerpc/powerpc32/e500mc/fpu/e_sqrt.c
+--- libc-sqrt-orig/sysdeps/powerpc/powerpc32/e500mc/fpu/e_sqrt.c 2014-07-24 04:42:30.366372001 -0500
++++ libc-sqrt-patch/sysdeps/powerpc/powerpc32/e500mc/fpu/e_sqrt.c 2014-07-24 04:42:46.249372001 -0500
+@@ -80,7 +80,7 @@
+
+ g = b * y;
+ h = 0.5 * y;
+-
++
+ /* Handle small numbers by scaling. */
+ if (__builtin_expect ((u.parts.msw & 0x7ff00000) <= 0x02000000, 0))
+ return __ieee754_sqrt (b * two108) * twom54;
+@@ -125,7 +125,7 @@
+ feraiseexcept (FE_INVALID_SQRT);
+
+ fenv_union_t u = { .fenv = fegetenv_register () };
+- if ((u.l[1] & FE_INVALID) == 0)
++ if ((u.l & FE_INVALID) == 0)
+ #endif
+ feraiseexcept (FE_INVALID);
+ b = a_nan.value;
+diff -Naur libc-sqrt-orig/sysdeps/powerpc/powerpc32/e500mc/fpu/e_sqrtf.c libc-sqrt-patch/sysdeps/powerpc/powerpc32/e500mc/fpu/e_sqrtf.c
+--- libc-sqrt-orig/sysdeps/powerpc/powerpc32/e500mc/fpu/e_sqrtf.c 2014-07-24 04:42:30.366372001 -0500
++++ libc-sqrt-patch/sysdeps/powerpc/powerpc32/e500mc/fpu/e_sqrtf.c 2014-07-24 04:42:46.249372001 -0500
+@@ -92,7 +92,7 @@
+ feraiseexcept (FE_INVALID_SQRT);
+
+ fenv_union_t u = { .fenv = fegetenv_register () };
+- if ((u.l[1] & FE_INVALID) == 0)
++ if ((u.l & FE_INVALID) == 0)
+ #endif
+ feraiseexcept (FE_INVALID);
+ b = a_nan.value;
+diff -Naur libc-sqrt-orig/sysdeps/powerpc/powerpc32/e5500/fpu/e_sqrt.c libc-sqrt-patch/sysdeps/powerpc/powerpc32/e5500/fpu/e_sqrt.c
+--- libc-sqrt-orig/sysdeps/powerpc/powerpc32/e5500/fpu/e_sqrt.c 2014-07-24 04:42:30.367372001 -0500
++++ libc-sqrt-patch/sysdeps/powerpc/powerpc32/e5500/fpu/e_sqrt.c 2014-07-24 04:42:46.250372001 -0500
+@@ -80,7 +80,7 @@
+
+ g = b * y;
+ h = 0.5 * y;
+-
++
+ /* Handle small numbers by scaling. */
+ if (__builtin_expect ((u.parts.msw & 0x7ff00000) <= 0x02000000, 0))
+ return __ieee754_sqrt (b * two108) * twom54;
+@@ -125,7 +125,7 @@
+ feraiseexcept (FE_INVALID_SQRT);
+
+ fenv_union_t u = { .fenv = fegetenv_register () };
+- if ((u.l[1] & FE_INVALID) == 0)
++ if ((u.l & FE_INVALID) == 0)
+ #endif
+ feraiseexcept (FE_INVALID);
+ b = a_nan.value;
+diff -Naur libc-sqrt-orig/sysdeps/powerpc/powerpc32/e5500/fpu/e_sqrtf.c libc-sqrt-patch/sysdeps/powerpc/powerpc32/e5500/fpu/e_sqrtf.c
+--- libc-sqrt-orig/sysdeps/powerpc/powerpc32/e5500/fpu/e_sqrtf.c 2014-07-24 04:42:30.367372001 -0500
++++ libc-sqrt-patch/sysdeps/powerpc/powerpc32/e5500/fpu/e_sqrtf.c 2014-07-24 04:42:46.250372001 -0500
+@@ -92,7 +92,7 @@
+ feraiseexcept (FE_INVALID_SQRT);
+
+ fenv_union_t u = { .fenv = fegetenv_register () };
+- if ((u.l[1] & FE_INVALID) == 0)
++ if ((u.l & FE_INVALID) == 0)
+ #endif
+ feraiseexcept (FE_INVALID);
+ b = a_nan.value;
+diff -Naur libc-sqrt-orig/sysdeps/powerpc/powerpc32/e6500/fpu/e_sqrt.c libc-sqrt-patch/sysdeps/powerpc/powerpc32/e6500/fpu/e_sqrt.c
+--- libc-sqrt-orig/sysdeps/powerpc/powerpc32/e6500/fpu/e_sqrt.c 2014-07-24 04:42:30.367372001 -0500
++++ libc-sqrt-patch/sysdeps/powerpc/powerpc32/e6500/fpu/e_sqrt.c 2014-07-24 04:42:46.250372001 -0500
+@@ -80,7 +80,7 @@
+
+ g = b * y;
+ h = 0.5 * y;
+-
++
+ /* Handle small numbers by scaling. */
+ if (__builtin_expect ((u.parts.msw & 0x7ff00000) <= 0x02000000, 0))
+ return __ieee754_sqrt (b * two108) * twom54;
+@@ -125,7 +125,7 @@
+ feraiseexcept (FE_INVALID_SQRT);
+
+ fenv_union_t u = { .fenv = fegetenv_register () };
+- if ((u.l[1] & FE_INVALID) == 0)
++ if ((u.l & FE_INVALID) == 0)
+ #endif
+ feraiseexcept (FE_INVALID);
+ b = a_nan.value;
+diff -Naur libc-sqrt-orig/sysdeps/powerpc/powerpc32/e6500/fpu/e_sqrtf.c libc-sqrt-patch/sysdeps/powerpc/powerpc32/e6500/fpu/e_sqrtf.c
+--- libc-sqrt-orig/sysdeps/powerpc/powerpc32/e6500/fpu/e_sqrtf.c 2014-07-24 04:42:30.367372001 -0500
++++ libc-sqrt-patch/sysdeps/powerpc/powerpc32/e6500/fpu/e_sqrtf.c 2014-07-24 04:42:46.250372001 -0500
+@@ -92,7 +92,7 @@
+ feraiseexcept (FE_INVALID_SQRT);
+
+ fenv_union_t u = { .fenv = fegetenv_register () };
+- if ((u.l[1] & FE_INVALID) == 0)
++ if ((u.l & FE_INVALID) == 0)
+ #endif
+ feraiseexcept (FE_INVALID);
+ b = a_nan.value;
+diff -Naur libc-sqrt-orig/sysdeps/powerpc/powerpc64/e5500/fpu/e_sqrt.c libc-sqrt-patch/sysdeps/powerpc/powerpc64/e5500/fpu/e_sqrt.c
+--- libc-sqrt-orig/sysdeps/powerpc/powerpc64/e5500/fpu/e_sqrt.c 2014-07-24 04:42:30.367372001 -0500
++++ libc-sqrt-patch/sysdeps/powerpc/powerpc64/e5500/fpu/e_sqrt.c 2014-07-24 04:42:46.250372001 -0500
+@@ -80,7 +80,7 @@
+
+ g = b * y;
+ h = 0.5 * y;
+-
++
+ /* Handle small numbers by scaling. */
+ if (__builtin_expect ((u.parts.msw & 0x7ff00000) <= 0x02000000, 0))
+ return __ieee754_sqrt (b * two108) * twom54;
+@@ -125,7 +125,7 @@
+ feraiseexcept (FE_INVALID_SQRT);
+
+ fenv_union_t u = { .fenv = fegetenv_register () };
+- if ((u.l[1] & FE_INVALID) == 0)
++ if ((u.l & FE_INVALID) == 0)
+ #endif
+ feraiseexcept (FE_INVALID);
+ b = a_nan.value;
+diff -Naur libc-sqrt-orig/sysdeps/powerpc/powerpc64/e5500/fpu/e_sqrtf.c libc-sqrt-patch/sysdeps/powerpc/powerpc64/e5500/fpu/e_sqrtf.c
+--- libc-sqrt-orig/sysdeps/powerpc/powerpc64/e5500/fpu/e_sqrtf.c 2014-07-24 04:42:30.367372001 -0500
++++ libc-sqrt-patch/sysdeps/powerpc/powerpc64/e5500/fpu/e_sqrtf.c 2014-07-24 04:42:46.250372001 -0500
+@@ -92,7 +92,7 @@
+ feraiseexcept (FE_INVALID_SQRT);
+
+ fenv_union_t u = { .fenv = fegetenv_register () };
+- if ((u.l[1] & FE_INVALID) == 0)
++ if ((u.l & FE_INVALID) == 0)
+ #endif
+ feraiseexcept (FE_INVALID);
+ b = a_nan.value;
+diff -Naur libc-sqrt-orig/sysdeps/powerpc/powerpc64/e6500/fpu/e_sqrt.c libc-sqrt-patch/sysdeps/powerpc/powerpc64/e6500/fpu/e_sqrt.c
+--- libc-sqrt-orig/sysdeps/powerpc/powerpc64/e6500/fpu/e_sqrt.c 2014-07-24 04:42:30.368372001 -0500
++++ libc-sqrt-patch/sysdeps/powerpc/powerpc64/e6500/fpu/e_sqrt.c 2014-07-24 04:42:46.251372001 -0500
+@@ -80,7 +80,7 @@
+
+ g = b * y;
+ h = 0.5 * y;
+-
++
+ /* Handle small numbers by scaling. */
+ if (__builtin_expect ((u.parts.msw & 0x7ff00000) <= 0x02000000, 0))
+ return __ieee754_sqrt (b * two108) * twom54;
+@@ -125,7 +125,7 @@
+ feraiseexcept (FE_INVALID_SQRT);
+
+ fenv_union_t u = { .fenv = fegetenv_register () };
+- if ((u.l[1] & FE_INVALID) == 0)
++ if ((u.l & FE_INVALID) == 0)
+ #endif
+ feraiseexcept (FE_INVALID);
+ b = a_nan.value;
+diff -Naur libc-sqrt-orig/sysdeps/powerpc/powerpc64/e6500/fpu/e_sqrtf.c libc-sqrt-patch/sysdeps/powerpc/powerpc64/e6500/fpu/e_sqrtf.c
+--- libc-sqrt-orig/sysdeps/powerpc/powerpc64/e6500/fpu/e_sqrtf.c 2014-07-24 04:42:30.368372001 -0500
++++ libc-sqrt-patch/sysdeps/powerpc/powerpc64/e6500/fpu/e_sqrtf.c 2014-07-24 04:42:46.251372001 -0500
+@@ -92,7 +92,7 @@
+ feraiseexcept (FE_INVALID_SQRT);
+
+ fenv_union_t u = { .fenv = fegetenv_register () };
+- if ((u.l[1] & FE_INVALID) == 0)
++ if ((u.l & FE_INVALID) == 0)
+ #endif
+ feraiseexcept (FE_INVALID);
+ b = a_nan.value;
+diff -Naur libc-sqrt-orig/sysdeps/unix/sysv/linux/powerpc/powerpc32/e300c3/fpu/Implies libc-sqrt-patch/sysdeps/unix/sysv/linux/powerpc/powerpc32/e300c3/fpu/Implies
+--- libc-sqrt-orig/sysdeps/unix/sysv/linux/powerpc/powerpc32/e300c3/fpu/Implies 1969-12-31 18:00:00.000000000 -0600
++++ libc-sqrt-patch/sysdeps/unix/sysv/linux/powerpc/powerpc32/e300c3/fpu/Implies 2014-07-24 04:42:46.251372001 -0500
+@@ -0,0 +1,2 @@
++# e300c3 is a variant of 603e so use the same optimizations for sqrt
++powerpc/powerpc32/603e/fpu
diff --git a/recipes-core/glibc/glibc-fsl/0002.glibc.fix_sqrt_finite.patch b/recipes-core/glibc/glibc-fsl/0002.glibc.fix_sqrt_finite.patch
new file mode 100755
index 0000000..d793774
--- /dev/null
+++ b/recipes-core/glibc/glibc-fsl/0002.glibc.fix_sqrt_finite.patch
@@ -0,0 +1,187 @@
+# Problem Statement:
+ on ppc fixes the errors like below
+ | ./.libs/libpulsecore-1.1.so: undefined reference to `__sqrt_finite'
+ | collect2: ld returned 1 exit status
+
+# Reference:
+ ppc-sqrt_finite.patch
+
+ChangeLog
+
+2012-01-06 Khem Raj <raj.khem at gmail.com>
+
+ * sysdeps/powerpc/powerpc64/e5500/fpu/e_sqrtf.c: Add __*_finite alias.
+ Remove cruft.
+ * sysdeps/powerpc/powerpc64/e5500/fpu/e_sqrt.c: Ditto.
+ * sysdeps/powerpc/powerpc32/603e/fpu/e_sqrt.c: Ditto.
+ * sysdeps/powerpc/powerpc32/603e/fpu/e_sqrtf.c: Ditto.
+
+Index: libc/sysdeps/powerpc/powerpc32/603e/fpu/e_sqrt.c
+===================================================================
+--- libc.orig/sysdeps/powerpc/powerpc32/603e/fpu/e_sqrt.c
++++ libc/sysdeps/powerpc/powerpc32/603e/fpu/e_sqrt.c
+@@ -39,14 +39,8 @@ static const float half = 0.5;
+ We find the actual square root and half of its reciprocal
+ simultaneously. */
+
+-#ifdef __STDC__
+ double
+ __ieee754_sqrt (double b)
+-#else
+-double
+-__ieee754_sqrt (b)
+- double b;
+-#endif
+ {
+ if (__builtin_expect (b > 0, 1))
+ {
+@@ -132,3 +126,4 @@ __ieee754_sqrt (b)
+ }
+ return f_wash (b);
+ }
++strong_alias (__ieee754_sqrt, __sqrt_finite)
+Index: libc/sysdeps/powerpc/powerpc32/603e/fpu/e_sqrtf.c
+===================================================================
+--- libc.orig/sysdeps/powerpc/powerpc32/603e/fpu/e_sqrtf.c
++++ libc/sysdeps/powerpc/powerpc32/603e/fpu/e_sqrtf.c
+@@ -37,14 +37,8 @@ static const float threehalf = 1.5;
+ We find the reciprocal square root and use that to compute the actual
+ square root. */
+
+-#ifdef __STDC__
+ float
+ __ieee754_sqrtf (float b)
+-#else
+-float
+-__ieee754_sqrtf (b)
+- float b;
+-#endif
+ {
+ if (__builtin_expect (b > 0, 1))
+ {
+@@ -99,3 +93,4 @@ __ieee754_sqrtf (b)
+ }
+ return f_washf (b);
+ }
++strong_alias (__ieee754_sqrtf, __sqrtf_finite)
+Index: libc/sysdeps/powerpc/powerpc64/e5500/fpu/e_sqrt.c
+===================================================================
+--- libc.orig/sysdeps/powerpc/powerpc64/e5500/fpu/e_sqrt.c
++++ libc/sysdeps/powerpc/powerpc64/e5500/fpu/e_sqrt.c
+@@ -39,14 +39,8 @@ static const float half = 0.5;
+ We find the actual square root and half of its reciprocal
+ simultaneously. */
+
+-#ifdef __STDC__
+ double
+ __ieee754_sqrt (double b)
+-#else
+-double
+-__ieee754_sqrt (b)
+- double b;
+-#endif
+ {
+ if (__builtin_expect (b > 0, 1))
+ {
+@@ -132,3 +126,4 @@ __ieee754_sqrt (b)
+ }
+ return f_wash (b);
+ }
++strong_alias (__ieee754_sqrt, __sqrt_finite)
+Index: libc/sysdeps/powerpc/powerpc64/e5500/fpu/e_sqrtf.c
+===================================================================
+--- libc.orig/sysdeps/powerpc/powerpc64/e5500/fpu/e_sqrtf.c
++++ libc/sysdeps/powerpc/powerpc64/e5500/fpu/e_sqrtf.c
+@@ -37,14 +37,8 @@ static const float threehalf = 1.5;
+ We find the reciprocal square root and use that to compute the actual
+ square root. */
+
+-#ifdef __STDC__
+ float
+ __ieee754_sqrtf (float b)
+-#else
+-float
+-__ieee754_sqrtf (b)
+- float b;
+-#endif
+ {
+ if (__builtin_expect (b > 0, 1))
+ {
+@@ -99,3 +93,4 @@ __ieee754_sqrtf (b)
+ }
+ return f_washf (b);
+ }
++strong_alias (__ieee754_sqrtf, __sqrtf_finite)
+Index: libc/sysdeps/powerpc/powerpc32/e500mc/fpu/e_sqrt.c
+===================================================================
+--- libc.orig/sysdeps/powerpc/powerpc32/e500mc/fpu/e_sqrt.c
++++ libc/sysdeps/powerpc/powerpc32/e500mc/fpu/e_sqrt.c
+@@ -132,3 +132,4 @@ __ieee754_sqrt (b)
+ }
+ return f_wash (b);
+ }
++strong_alias (__ieee754_sqrt, __sqrt_finite)
+Index: libc/sysdeps/powerpc/powerpc32/e500mc/fpu/e_sqrtf.c
+===================================================================
+--- libc.orig/sysdeps/powerpc/powerpc32/e500mc/fpu/e_sqrtf.c
++++ libc/sysdeps/powerpc/powerpc32/e500mc/fpu/e_sqrtf.c
+@@ -99,3 +99,4 @@ __ieee754_sqrtf (b)
+ }
+ return f_washf (b);
+ }
++strong_alias (__ieee754_sqrtf, __sqrtf_finite)
+Index: libc/sysdeps/powerpc/powerpc32/e5500/fpu/e_sqrt.c
+===================================================================
+--- libc.orig/sysdeps/powerpc/powerpc32/e5500/fpu/e_sqrt.c
++++ libc/sysdeps/powerpc/powerpc32/e5500/fpu/e_sqrt.c
+@@ -132,3 +132,4 @@ __ieee754_sqrt (b)
+ }
+ return f_wash (b);
+ }
++strong_alias (__ieee754_sqrt, __sqrt_finite)
+Index: libc/sysdeps/powerpc/powerpc32/e5500/fpu/e_sqrtf.c
+===================================================================
+--- libc.orig/sysdeps/powerpc/powerpc32/e5500/fpu/e_sqrtf.c
++++ libc/sysdeps/powerpc/powerpc32/e5500/fpu/e_sqrtf.c
+@@ -99,3 +99,4 @@ __ieee754_sqrtf (b)
+ }
+ return f_washf (b);
+ }
++strong_alias (__ieee754_sqrtf, __sqrtf_finite)
+Index: libc/sysdeps/powerpc/powerpc64/e6500/fpu/e_sqrt.c
+===================================================================
+--- libc.orig/sysdeps/powerpc/powerpc64/e6500/fpu/e_sqrt.c
++++ libc/sysdeps/powerpc/powerpc64/e6500/fpu/e_sqrt.c
+@@ -132,3 +132,4 @@ __ieee754_sqrt (b)
+ }
+ return f_wash (b);
+ }
++strong_alias (__ieee754_sqrt, __sqrt_finite)
+Index: libc/sysdeps/powerpc/powerpc64/e6500/fpu/e_sqrtf.c
+===================================================================
+--- libc.orig/sysdeps/powerpc/powerpc64/e6500/fpu/e_sqrtf.c
++++ libc/sysdeps/powerpc/powerpc64/e6500/fpu/e_sqrtf.c
+@@ -99,3 +99,4 @@ __ieee754_sqrtf (b)
+ }
+ return f_washf (b);
+ }
++strong_alias (__ieee754_sqrtf, __sqrtf_finite)
+Index: libc/sysdeps/powerpc/powerpc32/e6500/fpu/e_sqrt.c
+===================================================================
+--- libc.orig/sysdeps/powerpc/powerpc32/e6500/fpu/e_sqrt.c
++++ libc/sysdeps/powerpc/powerpc32/e6500/fpu/e_sqrt.c
+@@ -132,3 +132,4 @@ __ieee754_sqrt (b)
+ }
+ return f_wash (b);
+ }
++strong_alias (__ieee754_sqrt, __sqrt_finite)
+Index: libc/sysdeps/powerpc/powerpc32/e6500/fpu/e_sqrtf.c
+===================================================================
+--- libc.orig/sysdeps/powerpc/powerpc32/e6500/fpu/e_sqrtf.c
++++ libc/sysdeps/powerpc/powerpc32/e6500/fpu/e_sqrtf.c
+@@ -99,3 +99,4 @@ __ieee754_sqrtf (b)
+ }
+ return f_washf (b);
+ }
++strong_alias (__ieee754_sqrtf, __sqrtf_finite)
+
diff --git a/recipes-core/glibc/glibc-fsl/0003.glibc.fix_slow_ieee754_sqrt.patch b/recipes-core/glibc/glibc-fsl/0003.glibc.fix_slow_ieee754_sqrt.patch
new file mode 100755
index 0000000..b1fcaba
--- /dev/null
+++ b/recipes-core/glibc/glibc-fsl/0003.glibc.fix_slow_ieee754_sqrt.patch
@@ -0,0 +1,410 @@
+# Problem Statement:
+ __ieee754_sqrt{,f} are now inline functions and call out __slow versions
+
+# Reference
+ ppc_slow_ieee754_sqrt.patch
+
+
+Signed-off-by: Khem Raj <raj.khem at gmail.com>
+Upstream-Status: Pending
+Index: libc/sysdeps/powerpc/powerpc32/603e/fpu/e_sqrt.c
+===================================================================
+--- libc.orig/sysdeps/powerpc/powerpc32/603e/fpu/e_sqrt.c
++++ libc/sysdeps/powerpc/powerpc32/603e/fpu/e_sqrt.c
+@@ -40,7 +40,7 @@ static const float half = 0.5;
+ simultaneously. */
+
+ double
+-__ieee754_sqrt (double b)
++__slow_ieee754_sqrt (double b)
+ {
+ if (__builtin_expect (b > 0, 1))
+ {
+@@ -77,7 +77,7 @@ __ieee754_sqrt (double b)
+
+ /* Handle small numbers by scaling. */
+ if (__builtin_expect ((u.parts.msw & 0x7ff00000) <= 0x02000000, 0))
+- return __ieee754_sqrt (b * two108) * twom54;
++ return __slow_ieee754_sqrt (b * two108) * twom54;
+
+ #define FMADD(a_, c_, b_) \
+ ({ double __r; \
+@@ -126,4 +126,12 @@ __ieee754_sqrt (double b)
+ }
+ return f_wash (b);
+ }
++
++#undef __ieee754_sqrt
++double
++__ieee754_sqrt (double x)
++{
++ return __slow_ieee754_sqrt (x);
++}
++
+ strong_alias (__ieee754_sqrt, __sqrt_finite)
+Index: libc/sysdeps/powerpc/powerpc32/603e/fpu/e_sqrtf.c
+===================================================================
+--- libc.orig/sysdeps/powerpc/powerpc32/603e/fpu/e_sqrtf.c
++++ libc/sysdeps/powerpc/powerpc32/603e/fpu/e_sqrtf.c
+@@ -38,7 +38,7 @@ static const float threehalf = 1.5;
+ square root. */
+
+ float
+-__ieee754_sqrtf (float b)
++__slow_ieee754_sqrtf (float b)
+ {
+ if (__builtin_expect (b > 0, 1))
+ {
+@@ -93,4 +93,10 @@ __ieee754_sqrtf (float b)
+ }
+ return f_washf (b);
+ }
++#undef __ieee754_sqrtf
++float
++__ieee754_sqrtf (float x)
++{
++ return __slow_ieee754_sqrtf (x);
++}
+ strong_alias (__ieee754_sqrtf, __sqrtf_finite)
+Index: libc/sysdeps/powerpc/powerpc64/e5500/fpu/e_sqrt.c
+===================================================================
+--- libc.orig/sysdeps/powerpc/powerpc64/e5500/fpu/e_sqrt.c
++++ libc/sysdeps/powerpc/powerpc64/e5500/fpu/e_sqrt.c
+@@ -40,7 +40,7 @@ static const float half = 0.5;
+ simultaneously. */
+
+ double
+-__ieee754_sqrt (double b)
++__slow_ieee754_sqrt (double b)
+ {
+ if (__builtin_expect (b > 0, 1))
+ {
+@@ -77,7 +77,7 @@ __ieee754_sqrt (double b)
+
+ /* Handle small numbers by scaling. */
+ if (__builtin_expect ((u.parts.msw & 0x7ff00000) <= 0x02000000, 0))
+- return __ieee754_sqrt (b * two108) * twom54;
++ return __slow_ieee754_sqrt (b * two108) * twom54;
+
+ #define FMADD(a_, c_, b_) \
+ ({ double __r; \
+@@ -126,4 +126,12 @@ __ieee754_sqrt (double b)
+ }
+ return f_wash (b);
+ }
++
++#undef __ieee754_sqrt
++double
++__ieee754_sqrt (double x)
++{
++ return __slow_ieee754_sqrt (x);
++}
++
+ strong_alias (__ieee754_sqrt, __sqrt_finite)
+Index: libc/sysdeps/powerpc/powerpc64/e5500/fpu/e_sqrtf.c
+===================================================================
+--- libc.orig/sysdeps/powerpc/powerpc64/e5500/fpu/e_sqrtf.c
++++ libc/sysdeps/powerpc/powerpc64/e5500/fpu/e_sqrtf.c
+@@ -38,7 +38,7 @@ static const float threehalf = 1.5;
+ square root. */
+
+ float
+-__ieee754_sqrtf (float b)
++__slow_ieee754_sqrtf (float b)
+ {
+ if (__builtin_expect (b > 0, 1))
+ {
+@@ -93,4 +93,11 @@ __ieee754_sqrtf (float b)
+ }
+ return f_washf (b);
+ }
++#undef __ieee754_sqrtf
++float
++__ieee754_sqrtf (float x)
++{
++ return __slow_ieee754_sqrtf (x);
++}
++
+ strong_alias (__ieee754_sqrtf, __sqrtf_finite)
+Index: libc/sysdeps/powerpc/powerpc64/e6500/fpu/e_sqrt.c
+===================================================================
+--- libc.orig/sysdeps/powerpc/powerpc64/e6500/fpu/e_sqrt.c
++++ libc/sysdeps/powerpc/powerpc64/e6500/fpu/e_sqrt.c
+@@ -41,10 +41,10 @@ static const float half = 0.5;
+
+ #ifdef __STDC__
+ double
+-__ieee754_sqrt (double b)
++__slow_ieee754_sqrt (double b)
+ #else
+ double
+-__ieee754_sqrt (b)
++__slow_ieee754_sqrt (b)
+ double b;
+ #endif
+ {
+@@ -83,7 +83,7 @@ __ieee754_sqrt (b)
+
+ /* Handle small numbers by scaling. */
+ if (__builtin_expect ((u.parts.msw & 0x7ff00000) <= 0x02000000, 0))
+- return __ieee754_sqrt (b * two108) * twom54;
++ return __slow_ieee754_sqrt (b * two108) * twom54;
+
+ #define FMADD(a_, c_, b_) \
+ ({ double __r; \
+@@ -132,4 +132,12 @@ __ieee754_sqrt (b)
+ }
+ return f_wash (b);
+ }
++
++#undef __ieee754_sqrt
++double
++__ieee754_sqrt (double x)
++{
++ return __slow_ieee754_sqrt (x);
++}
++
+ strong_alias (__ieee754_sqrt, __sqrt_finite)
+Index: libc/sysdeps/powerpc/powerpc64/e6500/fpu/e_sqrtf.c
+===================================================================
+--- libc.orig/sysdeps/powerpc/powerpc64/e6500/fpu/e_sqrtf.c
++++ libc/sysdeps/powerpc/powerpc64/e6500/fpu/e_sqrtf.c
+@@ -39,10 +39,10 @@ static const float threehalf = 1.5;
+
+ #ifdef __STDC__
+ float
+-__ieee754_sqrtf (float b)
++__slow_ieee754_sqrtf (float b)
+ #else
+ float
+-__ieee754_sqrtf (b)
++__slow_ieee754_sqrtf (b)
+ float b;
+ #endif
+ {
+@@ -99,4 +99,12 @@ __ieee754_sqrtf (b)
+ }
+ return f_washf (b);
+ }
++
++#undef __ieee754_sqrtf
++float
++__ieee754_sqrtf (float x)
++{
++ return __slow_ieee754_sqrtf (x);
++}
++
+ strong_alias (__ieee754_sqrtf, __sqrtf_finite)
+Index: libc/sysdeps/powerpc/powerpc32/e500mc/fpu/e_sqrt.c
+===================================================================
+--- libc.orig/sysdeps/powerpc/powerpc32/e500mc/fpu/e_sqrt.c
++++ libc/sysdeps/powerpc/powerpc32/e500mc/fpu/e_sqrt.c
+@@ -41,10 +41,10 @@ static const float half = 0.5;
+
+ #ifdef __STDC__
+ double
+-__ieee754_sqrt (double b)
++__slow_ieee754_sqrt (double b)
+ #else
+ double
+-__ieee754_sqrt (b)
++__slow_ieee754_sqrt (b)
+ double b;
+ #endif
+ {
+@@ -83,7 +83,7 @@ __ieee754_sqrt (b)
+
+ /* Handle small numbers by scaling. */
+ if (__builtin_expect ((u.parts.msw & 0x7ff00000) <= 0x02000000, 0))
+- return __ieee754_sqrt (b * two108) * twom54;
++ return __slow_ieee754_sqrt (b * two108) * twom54;
+
+ #define FMADD(a_, c_, b_) \
+ ({ double __r; \
+@@ -132,4 +132,12 @@ __ieee754_sqrt (b)
+ }
+ return f_wash (b);
+ }
++
++#undef __ieee754_sqrt
++double
++__ieee754_sqrt (double x)
++{
++ return __slow_ieee754_sqrt (x);
++}
++
+ strong_alias (__ieee754_sqrt, __sqrt_finite)
+Index: libc/sysdeps/powerpc/powerpc32/e500mc/fpu/e_sqrtf.c
+===================================================================
+--- libc.orig/sysdeps/powerpc/powerpc32/e500mc/fpu/e_sqrtf.c
++++ libc/sysdeps/powerpc/powerpc32/e500mc/fpu/e_sqrtf.c
+@@ -39,10 +39,10 @@ static const float threehalf = 1.5;
+
+ #ifdef __STDC__
+ float
+-__ieee754_sqrtf (float b)
++__slow_ieee754_sqrtf (float b)
+ #else
+ float
+-__ieee754_sqrtf (b)
++__slow_ieee754_sqrtf (b)
+ float b;
+ #endif
+ {
+@@ -99,4 +99,12 @@ __ieee754_sqrtf (b)
+ }
+ return f_washf (b);
+ }
++
++#undef __ieee754_sqrtf
++float
++__ieee754_sqrtf (float x)
++{
++ return __slow_ieee754_sqrtf (x);
++}
++
+ strong_alias (__ieee754_sqrtf, __sqrtf_finite)
+Index: libc/sysdeps/powerpc/powerpc32/e5500/fpu/e_sqrt.c
+===================================================================
+--- libc.orig/sysdeps/powerpc/powerpc32/e5500/fpu/e_sqrt.c
++++ libc/sysdeps/powerpc/powerpc32/e5500/fpu/e_sqrt.c
+@@ -41,10 +41,10 @@ static const float half = 0.5;
+
+ #ifdef __STDC__
+ double
+-__ieee754_sqrt (double b)
++__slow_ieee754_sqrt (double b)
+ #else
+ double
+-__ieee754_sqrt (b)
++__slow_ieee754_sqrt (b)
+ double b;
+ #endif
+ {
+@@ -83,7 +83,7 @@ __ieee754_sqrt (b)
+
+ /* Handle small numbers by scaling. */
+ if (__builtin_expect ((u.parts.msw & 0x7ff00000) <= 0x02000000, 0))
+- return __ieee754_sqrt (b * two108) * twom54;
++ return __slow_ieee754_sqrt (b * two108) * twom54;
+
+ #define FMADD(a_, c_, b_) \
+ ({ double __r; \
+@@ -132,4 +132,12 @@ __ieee754_sqrt (b)
+ }
+ return f_wash (b);
+ }
++
++#undef __ieee754_sqrt
++double
++__ieee754_sqrt (double x)
++{
++ return __slow_ieee754_sqrt (x);
++}
++
+ strong_alias (__ieee754_sqrt, __sqrt_finite)
+Index: libc/sysdeps/powerpc/powerpc32/e5500/fpu/e_sqrtf.c
+===================================================================
+--- libc.orig/sysdeps/powerpc/powerpc32/e5500/fpu/e_sqrtf.c
++++ libc/sysdeps/powerpc/powerpc32/e5500/fpu/e_sqrtf.c
+@@ -39,10 +39,10 @@ static const float threehalf = 1.5;
+
+ #ifdef __STDC__
+ float
+-__ieee754_sqrtf (float b)
++__slow_ieee754_sqrtf (float b)
+ #else
+ float
+-__ieee754_sqrtf (b)
++__slow_ieee754_sqrtf (b)
+ float b;
+ #endif
+ {
+@@ -99,4 +99,12 @@ __ieee754_sqrtf (b)
+ }
+ return f_washf (b);
+ }
++
++#undef __ieee754_sqrtf
++float
++__ieee754_sqrtf (float x)
++{
++ return __slow_ieee754_sqrtf (x);
++}
++
+ strong_alias (__ieee754_sqrtf, __sqrtf_finite)
+Index: libc/sysdeps/powerpc/powerpc32/e6500/fpu/e_sqrt.c
+===================================================================
+--- libc.orig/sysdeps/powerpc/powerpc32/e6500/fpu/e_sqrt.c
++++ libc/sysdeps/powerpc/powerpc32/e6500/fpu/e_sqrt.c
+@@ -132,4 +132,12 @@ __ieee754_sqrt (b)
+ }
+ return f_wash (b);
+ }
++
++#undef __ieee754_sqrt
++double
++__ieee754_sqrt (double x)
++{
++ return __slow_ieee754_sqrt (x);
++}
++
+ strong_alias (__ieee754_sqrt, __sqrt_finite)
+Index: libc/sysdeps/powerpc/powerpc32/e6500/fpu/e_sqrtf.c
+===================================================================
+--- libc.orig/sysdeps/powerpc/powerpc32/e6500/fpu/e_sqrtf.c
++++ libc/sysdeps/powerpc/powerpc32/e6500/fpu/e_sqrtf.c
+@@ -99,4 +99,12 @@ __ieee754_sqrtf (b)
+ }
+ return f_washf (b);
+ }
++
++#undef __ieee754_sqrtf
++float
++__ieee754_sqrtf (float x)
++{
++ return __slow_ieee754_sqrtf (x);
++}
++
+ strong_alias (__ieee754_sqrtf, __sqrtf_finite)
+diff -rNu libc-orig/sysdeps/powerpc/powerpc32/e6500/fpu/e_sqrt.c libc/sysdeps/powerpc/powerpc32/e6500/fpu/e_sqrt.c
+--- libc-orig/sysdeps/powerpc/powerpc32/e6500/fpu/e_sqrt.c 2014-04-08 04:39:58.487229887 -0500
++++ libc/sysdeps/powerpc/powerpc32/e6500/fpu/e_sqrt.c 2014-04-08 04:40:52.643069198 -0500
+@@ -41,10 +41,10 @@
+
+ #ifdef __STDC__
+ double
+-__ieee754_sqrt (double b)
++__slow_ieee754_sqrt (double b)
+ #else
+ double
+-__ieee754_sqrt (b)
++__slow_ieee754_sqrt (b)
+ double b;
+ #endif
+ {
+@@ -83,7 +83,7 @@
+
+ /* Handle small numbers by scaling. */
+ if (__builtin_expect ((u.parts.msw & 0x7ff00000) <= 0x02000000, 0))
+- return __ieee754_sqrt (b * two108) * twom54;
++ return __slow_ieee754_sqrt (b * two108) * twom54;
+
+ #define FMADD(a_, c_, b_) \
+ ({ double __r; \
+diff -rNu libc-orig/sysdeps/powerpc/powerpc32/e6500/fpu/e_sqrtf.c libc/sysdeps/powerpc/powerpc32/e6500/fpu/e_sqrtf.c
+--- libc-orig/sysdeps/powerpc/powerpc32/e6500/fpu/e_sqrtf.c 2014-04-08 04:39:58.487229887 -0500
++++ libc/sysdeps/powerpc/powerpc32/e6500/fpu/e_sqrtf.c 2014-04-08 04:41:26.017067682 -0500
+@@ -39,10 +39,10 @@
+
+ #ifdef __STDC__
+ float
+-__ieee754_sqrtf (float b)
++__slow_ieee754_sqrtf (float b)
+ #else
+ float
+-__ieee754_sqrtf (b)
++__slow_ieee754_sqrtf (b)
+ float b;
+ #endif
+ {
diff --git a/recipes-core/glibc/glibc-fsl/0004.glibc.fsl-ppc-no-fsqrt.patch b/recipes-core/glibc/glibc-fsl/0004.glibc.fsl-ppc-no-fsqrt.patch
new file mode 100755
index 0000000..24a85b6
--- /dev/null
+++ b/recipes-core/glibc/glibc-fsl/0004.glibc.fsl-ppc-no-fsqrt.patch
@@ -0,0 +1,101 @@
+Create e5500 specific math_private.h and let it include when compiling for e5500/64bit core
+We prefefine __CPU_HAS_FSQRT to 0 and then in general ppc64 math_private.h we check if its
+already defined before redefining it. This way we can ensure that on e5500 builds it wont
+emit fsqrt intructions
+
+-Khem
+
+Upstream-Status: Pending
+
+Index: git/sysdeps/powerpc/fpu/math_private.h
+===================================================================
+--- git.orig/sysdeps/powerpc/fpu/math_private.h 2014-08-29 10:31:30.224070587 -0700
++++ git/sysdeps/powerpc/fpu/math_private.h 2014-08-29 10:31:30.212070587 -0700
+@@ -25,10 +25,12 @@
+ #include <fenv_private.h>
+ #include_next <math_private.h>
+
+-# if __WORDSIZE == 64 || defined _ARCH_PWR4
+-# define __CPU_HAS_FSQRT 1
+-# else
+-# define __CPU_HAS_FSQRT ((GLRO(dl_hwcap) & PPC_FEATURE_64) != 0)
++# ifndef __CPU_HAS_FSQRT
++# if __WORDSIZE == 64 || defined _ARCH_PWR4
++# define __CPU_HAS_FSQRT 1
++# else
++# define __CPU_HAS_FSQRT ((GLRO(dl_hwcap) & PPC_FEATURE_64) != 0)
++# endif
+ # endif
+
+ extern double __slow_ieee754_sqrt (double);
+Index: git/sysdeps/powerpc/powerpc64/e5500/fpu/math_private.h
+===================================================================
+--- /dev/null 1970-01-01 00:00:00.000000000 +0000
++++ git/sysdeps/powerpc/powerpc64/e5500/fpu/math_private.h 2014-08-29 10:31:30.212070587 -0700
+@@ -0,0 +1,9 @@
++#ifndef _E5500_MATH_PRIVATE_H_
++#define _E5500_MATH_PRIVATE_H_ 1
++/* E5500 core FPU does not implement
++ fsqrt */
++
++#define __CPU_HAS_FSQRT 0
++#include_next <math_private.h>
++
++#endif /* _E5500_MATH_PRIVATE_H_ */
+Index: git/sysdeps/powerpc/powerpc64/e6500/fpu/math_private.h
+===================================================================
+--- /dev/null 1970-01-01 00:00:00.000000000 +0000
++++ git/sysdeps/powerpc/powerpc64/e6500/fpu/math_private.h 2014-08-29 10:31:30.212070587 -0700
+@@ -0,0 +1,9 @@
++#ifndef _E6500_MATH_PRIVATE_H_
++#define _E6500_MATH_PRIVATE_H_ 1
++/* E6500 core FPU does not implement
++ fsqrt */
++
++#define __CPU_HAS_FSQRT 0
++#include_next <math_private.h>
++
++#endif /* _E6500_MATH_PRIVATE_H_ */
+Index: git/sysdeps/powerpc/powerpc32/e500mc/fpu/math_private.h
+===================================================================
+--- /dev/null 1970-01-01 00:00:00.000000000 +0000
++++ git/sysdeps/powerpc/powerpc32/e500mc/fpu/math_private.h 2014-08-29 10:31:30.212070587 -0700
+@@ -0,0 +1,9 @@
++#ifndef _E500MC_MATH_PRIVATE_H_
++#define _E500MC_MATH_PRIVATE_H_ 1
++/* E500MC core FPU does not implement
++ fsqrt */
++
++#define __CPU_HAS_FSQRT 0
++#include_next <math_private.h>
++
++#endif /* _E500MC_MATH_PRIVATE_H_ */
+Index: git/sysdeps/powerpc/powerpc32/e5500/fpu/math_private.h
+===================================================================
+--- /dev/null 1970-01-01 00:00:00.000000000 +0000
++++ git/sysdeps/powerpc/powerpc32/e5500/fpu/math_private.h 2014-08-29 10:31:30.216070587 -0700
+@@ -0,0 +1,9 @@
++#ifndef _E5500_MATH_PRIVATE_H_
++#define _E5500_MATH_PRIVATE_H_ 1
++/* E5500 core FPU does not implement
++ fsqrt */
++
++#define __CPU_HAS_FSQRT 0
++#include_next <math_private.h>
++
++#endif /* _E5500_MATH_PRIVATE_H_ */
+Index: git/sysdeps/powerpc/powerpc32/e6500/fpu/math_private.h
+===================================================================
+--- /dev/null 1970-01-01 00:00:00.000000000 +0000
++++ git/sysdeps/powerpc/powerpc32/e6500/fpu/math_private.h 2014-08-29 10:31:30.216070587 -0700
+@@ -0,0 +1,9 @@
++#ifndef _E6500_MATH_PRIVATE_H_
++#define _E6500_MATH_PRIVATE_H_ 1
++/* E6500 core FPU does not implement
++ fsqrt */
++
++#define __CPU_HAS_FSQRT 0
++#include_next <math_private.h>
++
++#endif /* _E6500_MATH_PRIVATE_H_ */
+
diff --git a/recipes-core/glibc/glibc-fsl/0005.glibc.fix_prof.patch b/recipes-core/glibc/glibc-fsl/0005.glibc.fix_prof.patch
new file mode 100755
index 0000000..43ba12b
--- /dev/null
+++ b/recipes-core/glibc/glibc-fsl/0005.glibc.fix_prof.patch
@@ -0,0 +1,47 @@
+# Problem Statement:
+ Modify Glibc so that gnu profiling is works with Glibc
+# Reported by:
+ James Yang
+# Owned by:
+ Srinivas
+# Action:
+ * Modify Glibc such that it can be built with profiling and gprof data is generated correctly for Glibc functions
+ * Added profiling fixes provided in 'powerpc-profiling-fix.diff' file to the latest sources and checked flat-profiling
+ data generated for Glibc functions.
+
+diff -ruN libc-orig/elf/dl-runtime.c libc/elf/dl-runtime.c
+--- libc-orig/elf/dl-runtime.c 2014-06-11 02:51:20.000000000 -0500
++++ libc/elf/dl-runtime.c 2014-07-25 00:36:20.743371998 -0500
+@@ -148,7 +148,6 @@
+ return elf_machine_fixup_plt (l, result, reloc, rel_addr, value);
+ }
+
+-#ifndef PROF
+ DL_FIXUP_VALUE_TYPE
+ __attribute ((noinline)) ARCH_FIXUP_ATTRIBUTE
+ _dl_profile_fixup (
+@@ -433,7 +432,6 @@
+ return value;
+ }
+
+-#endif /* PROF */
+
+
+ #include <stdio.h>
+diff -ruN libc-orig/sysdeps/powerpc/powerpc32/dl-trampoline.S libc/sysdeps/powerpc/powerpc32/dl-trampoline.S
+--- libc-orig/sysdeps/powerpc/powerpc32/dl-trampoline.S 2014-06-11 02:44:56.000000000 -0500
++++ libc/sysdeps/powerpc/powerpc32/dl-trampoline.S 2014-07-25 00:36:20.942372001 -0500
+@@ -70,7 +70,6 @@
+ cfi_endproc
+ .size _dl_runtime_resolve,.-_dl_runtime_resolve
+
+-#ifndef PROF
+ .align 2
+ .globl _dl_prof_resolve
+ .type _dl_prof_resolve, at function
+@@ -186,4 +185,4 @@
+ bctr
+ cfi_endproc
+ .size _dl_prof_resolve,.-_dl_prof_resolve
+-#endif
++
diff --git a/recipes-core/glibc/glibc-fsl/0006.glibc.fsl-crosszic.patch b/recipes-core/glibc/glibc-fsl/0006.glibc.fsl-crosszic.patch
new file mode 100755
index 0000000..5077771
--- /dev/null
+++ b/recipes-core/glibc/glibc-fsl/0006.glibc.fsl-crosszic.patch
@@ -0,0 +1,76 @@
+# Problem Statement:
+ Install timezone data while building glibc v2.20.
+
+# Owned by:
+ Rohit
+
+# Actions:
+ * Created a patch which updates the timezone/Makefile to build cross-zic.
+ * Updated build.sh script to build & install tzdata after glibc build is
+ complete.
+
+diff -Naur glibc-2.20/timezone/Makefile glibc-2.20-tzdata/timezone/Makefile
+--- glibc-2.20/timezone/Makefile 2014-09-07 03:09:09.000000000 -0500
++++ glibc-2.20-tzdata/timezone/Makefile 2015-02-18 08:02:49.041739203 -0600
+@@ -25,6 +25,9 @@
+ extra-objs := scheck.o ialloc.o
+
+ others := zdump zic
++ifneq ($(cross-compiling),no)
++others += cross-zic
++endif
+ tests := test-tz tst-timezone
+
+ # pacificnew doesn't compile; if it is to be used, it should be included in
+@@ -53,10 +56,21 @@
+
+ include ../Rules
+
++zic-objs = zic.o ialloc.o scheck.o
++
++$(addprefix $(objpfx)cross-,$(zic-objs)): $(objpfx)cross-%.o: %.c
++ $(BUILD_CC) $< -c $(OUTPUT_OPTION) $(CFLAGS-$*.c) $(CPPFLAGS-$*) \
++ -DREPORT_BUGS_TO='"$(REPORT_BUGS_TO)"' \
++ -DPKGVERSION='"$(PKGVERSION)"' \
++ $(compile-mkdep-flags) -iquote $(objpfx)
++
++$(objpfx)cross-zic: $(addprefix $(objpfx)cross-,$(zic-objs))
++ $(BUILD_CC) $(addprefix $(objpfx)cross-,$(zic-objs)) -o $@
+
+ $(objpfx)zic: $(objpfx)scheck.o $(objpfx)ialloc.o
+
+ $(objpfx)zic.o $(objpfx)zdump.o: $(objpfx)version.h
++$(objpfx)cross-zic.o $(objpfx)cross-zdump.o: $(objpfx)version.h
+
+ $(objpfx)version.h: $(common-objpfx)config.make
+ echo 'static char const TZVERSION[]="$(version)";' \
+@@ -77,10 +91,17 @@
+ # We have to make sure the data for testing the tz functions is available.
+ # Don't add leapseconds here since test-tz made checks that work only without
+ # leapseconds.
++ifeq (no,$(cross-compiling))
+ define build-testdata
+ $(built-program-cmd) -d $(testdata) -y ./yearistype $<; \
+ $(evaluate-test)
+ endef
++else
++define build-testdata
++LANGUAGE=C LC_ALL=C \
++ $(objpfx)cross-zic -d $(testdata) -y ./yearistype $<
++endef
++endif
+
+ $(objpfx)test-tz.out: $(addprefix $(testdata)/, America/New_York Etc/UTC UTC)
+ $(objpfx)tst-timezone.out: $(addprefix $(testdata)/, \
+@@ -93,7 +114,11 @@
+ tst-timezone-ENV = TZDIR=$(testdata)
+
+ # Note this must come second in the deps list for $(built-program-cmd) to work.
++ifeq (no,$(cross-compiling))
+ zic-deps = $(objpfx)zic $(leapseconds) yearistype
++else
++zic-deps = $(objpfx)cross-zic $(objpfx)zic $(leapseconds) yearistype
++endif
+
+ $(testdata)/America/New_York: northamerica $(zic-deps)
+ $(build-testdata)
diff --git a/recipes-core/glibc/glibc-fsl/0007.glibc.fix_MTWX51911-enable_8xx.patch b/recipes-core/glibc/glibc-fsl/0007.glibc.fix_MTWX51911-enable_8xx.patch
new file mode 100755
index 0000000..f4159a3
--- /dev/null
+++ b/recipes-core/glibc/glibc-fsl/0007.glibc.fix_MTWX51911-enable_8xx.patch
@@ -0,0 +1,530 @@
+# Problem Statement:
+ ENGR00215432:
+ The purpose of this patch is to disable the use of dcbz in the 32-bit memset.
+ However, this does not fix the root problem because any program
+ -- not just one using eglibc's memset -- can contain dcbz instruction,
+ so it is an incomplete fix anyway.
+
+ There is support in the Linux kernel as of 2.6.33 to emulate the correct
+ behavior (though it seems nobody really knows how well the workaround works),
+ so if the program that uses libc is running on this or a later kernel it does
+ not need to check for an 8xx.
+
+ Therefore one solution is to require kernel 2.6.33 or later.
+
+diff -Naur glibc-2.20/sysdeps/unix/sysv/linux/powerpc/powerpc32/801/dl-sysdep.c glibc-2.20-patch/sysdeps/unix/sysv/linux/powerpc/powerpc32/801/dl-sysdep.c
+--- glibc-2.20/sysdeps/unix/sysv/linux/powerpc/powerpc32/801/dl-sysdep.c 1969-12-31 18:00:00.000000000 -0600
++++ glibc-2.20-patch/sysdeps/unix/sysv/linux/powerpc/powerpc32/801/dl-sysdep.c 2015-02-24 13:57:36.709739425 -0600
+@@ -0,0 +1,35 @@
++/* Operating system support for run-time dynamic linker. Linux/PPC version.
++ Copyright (C) 1997-2014 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, see
++ <http://www.gnu.org/licenses/>. */
++
++#include <config.h>
++#include <ldsodefs.h>
++
++int __cache_line_size attribute_hidden;
++
++/* Scan the Aux Vector for the "Data Cache Block Size" entry. If found
++ verify that the static extern __cache_line_size is defined by checking
++ for not NULL. If it is defined then assign the cache block size
++ value to __cache_line_size. This is used by memset to
++ optimize setting to zero. We have to detect 8xx processors, which
++ have buggy dcbz implementations that cannot report page faults
++ correctly. */
++#define DL_PLATFORM_AUXV \
++ case AT_DCACHEBSIZE: \
++ break;
++
++#include <sysdeps/unix/sysv/linux/dl-sysdep.c>
+diff -Naur glibc-2.20/sysdeps/unix/sysv/linux/powerpc/powerpc32/801/libc-start.c glibc-2.20-patch/sysdeps/unix/sysv/linux/powerpc/powerpc32/801/libc-start.c
+--- glibc-2.20/sysdeps/unix/sysv/linux/powerpc/powerpc32/801/libc-start.c 1969-12-31 18:00:00.000000000 -0600
++++ glibc-2.20-patch/sysdeps/unix/sysv/linux/powerpc/powerpc32/801/libc-start.c 2015-02-24 13:53:49.721737701 -0600
+@@ -0,0 +1,86 @@
++/* Copyright (C) 1998-2014 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, see
++ <http://www.gnu.org/licenses/>. */
++
++#include <stdlib.h>
++#include <unistd.h>
++#include <ldsodefs.h>
++#include <sysdep.h>
++
++
++int __cache_line_size attribute_hidden;
++/* The main work is done in the generic function. */
++#define LIBC_START_MAIN generic_start_main
++#define LIBC_START_DISABLE_INLINE
++#define LIBC_START_MAIN_AUXVEC_ARG
++#define MAIN_AUXVEC_ARG
++#define INIT_MAIN_ARGS
++#include <csu/libc-start.c>
++
++struct startup_info
++ {
++ void *sda_base;
++ int (*main) (int, char **, char **, void *);
++ int (*init) (int, char **, char **, void *);
++ void (*fini) (void);
++ };
++
++int
++__libc_start_main (int argc, char **argv,
++ char **ev,
++ ElfW (auxv_t) * auxvec,
++ void (*rtld_fini) (void),
++ struct startup_info *stinfo,
++ char **stack_on_entry)
++{
++ /* the PPC SVR4 ABI says that the top thing on the stack will
++ be a NULL pointer, so if not we assume that we're being called
++ as a statically-linked program by Linux... */
++ if (*stack_on_entry != NULL)
++ {
++ char **temp;
++ /* ...in which case, we have argc as the top thing on the
++ stack, followed by argv (NULL-terminated), envp (likewise),
++ and the auxiliary vector. */
++ /* 32/64-bit agnostic load from stack */
++ argc = *(long int *) stack_on_entry;
++ argv = stack_on_entry + 1;
++ ev = argv + argc + 1;
++#ifdef HAVE_AUX_VECTOR
++ temp = ev;
++ while (*temp != NULL)
++ ++temp;
++ auxvec = (ElfW (auxv_t) *)++ temp;
++#endif
++ rtld_fini = NULL;
++ }
++
++ /* Initialize the __cache_line_size variable from the aux vector.
++ This is used by memset to optimize setting to zero. We have to
++ detect 8xx processors, which have buggy dcbz implementations that
++ cannot report page faults correctly. That requires reading SPR,
++ which is a privileged operation.*/
++ for (ElfW (auxv_t) * av = auxvec; av->a_type != AT_NULL; ++av)
++ switch (av->a_type)
++ {
++ case AT_DCACHEBSIZE:
++ break;
++ }
++
++ return generic_start_main (stinfo->main, argc, argv, auxvec,
++ stinfo->init, stinfo->fini, rtld_fini,
++ stack_on_entry);
++}
+diff -Naur glibc-2.20/sysdeps/unix/sysv/linux/powerpc/powerpc32/821/dl-sysdep.c glibc-2.20-patch/sysdeps/unix/sysv/linux/powerpc/powerpc32/821/dl-sysdep.c
+--- glibc-2.20/sysdeps/unix/sysv/linux/powerpc/powerpc32/821/dl-sysdep.c 1969-12-31 18:00:00.000000000 -0600
++++ glibc-2.20-patch/sysdeps/unix/sysv/linux/powerpc/powerpc32/821/dl-sysdep.c 2015-02-24 13:58:00.043738993 -0600
+@@ -0,0 +1,35 @@
++/* Operating system support for run-time dynamic linker. Linux/PPC version.
++ Copyright (C) 1997-2014 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, see
++ <http://www.gnu.org/licenses/>. */
++
++#include <config.h>
++#include <ldsodefs.h>
++
++int __cache_line_size attribute_hidden;
++
++/* Scan the Aux Vector for the "Data Cache Block Size" entry. If found
++ verify that the static extern __cache_line_size is defined by checking
++ for not NULL. If it is defined then assign the cache block size
++ value to __cache_line_size. This is used by memset to
++ optimize setting to zero. We have to detect 8xx processors, which
++ have buggy dcbz implementations that cannot report page faults
++ correctly. */
++#define DL_PLATFORM_AUXV \
++ case AT_DCACHEBSIZE: \
++ break;
++
++#include <sysdeps/unix/sysv/linux/dl-sysdep.c>
+diff -Naur glibc-2.20/sysdeps/unix/sysv/linux/powerpc/powerpc32/821/libc-start.c glibc-2.20-patch/sysdeps/unix/sysv/linux/powerpc/powerpc32/821/libc-start.c
+--- glibc-2.20/sysdeps/unix/sysv/linux/powerpc/powerpc32/821/libc-start.c 1969-12-31 18:00:00.000000000 -0600
++++ glibc-2.20-patch/sysdeps/unix/sysv/linux/powerpc/powerpc32/821/libc-start.c 2015-02-24 13:58:00.043738993 -0600
+@@ -0,0 +1,86 @@
++/* Copyright (C) 1998-2014 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, see
++ <http://www.gnu.org/licenses/>. */
++
++#include <stdlib.h>
++#include <unistd.h>
++#include <ldsodefs.h>
++#include <sysdep.h>
++
++
++int __cache_line_size attribute_hidden;
++/* The main work is done in the generic function. */
++#define LIBC_START_MAIN generic_start_main
++#define LIBC_START_DISABLE_INLINE
++#define LIBC_START_MAIN_AUXVEC_ARG
++#define MAIN_AUXVEC_ARG
++#define INIT_MAIN_ARGS
++#include <csu/libc-start.c>
++
++struct startup_info
++ {
++ void *sda_base;
++ int (*main) (int, char **, char **, void *);
++ int (*init) (int, char **, char **, void *);
++ void (*fini) (void);
++ };
++
++int
++__libc_start_main (int argc, char **argv,
++ char **ev,
++ ElfW (auxv_t) * auxvec,
++ void (*rtld_fini) (void),
++ struct startup_info *stinfo,
++ char **stack_on_entry)
++{
++ /* the PPC SVR4 ABI says that the top thing on the stack will
++ be a NULL pointer, so if not we assume that we're being called
++ as a statically-linked program by Linux... */
++ if (*stack_on_entry != NULL)
++ {
++ char **temp;
++ /* ...in which case, we have argc as the top thing on the
++ stack, followed by argv (NULL-terminated), envp (likewise),
++ and the auxiliary vector. */
++ /* 32/64-bit agnostic load from stack */
++ argc = *(long int *) stack_on_entry;
++ argv = stack_on_entry + 1;
++ ev = argv + argc + 1;
++#ifdef HAVE_AUX_VECTOR
++ temp = ev;
++ while (*temp != NULL)
++ ++temp;
++ auxvec = (ElfW (auxv_t) *)++ temp;
++#endif
++ rtld_fini = NULL;
++ }
++
++ /* Initialize the __cache_line_size variable from the aux vector.
++ This is used by memset to optimize setting to zero. We have to
++ detect 8xx processors, which have buggy dcbz implementations that
++ cannot report page faults correctly. That requires reading SPR,
++ which is a privileged operation.*/
++ for (ElfW (auxv_t) * av = auxvec; av->a_type != AT_NULL; ++av)
++ switch (av->a_type)
++ {
++ case AT_DCACHEBSIZE:
++ break;
++ }
++
++ return generic_start_main (stinfo->main, argc, argv, auxvec,
++ stinfo->init, stinfo->fini, rtld_fini,
++ stack_on_entry);
++}
+diff -Naur glibc-2.20/sysdeps/unix/sysv/linux/powerpc/powerpc32/823/dl-sysdep.c glibc-2.20-patch/sysdeps/unix/sysv/linux/powerpc/powerpc32/823/dl-sysdep.c
+--- glibc-2.20/sysdeps/unix/sysv/linux/powerpc/powerpc32/823/dl-sysdep.c 1969-12-31 18:00:00.000000000 -0600
++++ glibc-2.20-patch/sysdeps/unix/sysv/linux/powerpc/powerpc32/823/dl-sysdep.c 2015-02-24 13:58:03.323739026 -0600
+@@ -0,0 +1,35 @@
++/* Operating system support for run-time dynamic linker. Linux/PPC version.
++ Copyright (C) 1997-2014 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, see
++ <http://www.gnu.org/licenses/>. */
++
++#include <config.h>
++#include <ldsodefs.h>
++
++int __cache_line_size attribute_hidden;
++
++/* Scan the Aux Vector for the "Data Cache Block Size" entry. If found
++ verify that the static extern __cache_line_size is defined by checking
++ for not NULL. If it is defined then assign the cache block size
++ value to __cache_line_size. This is used by memset to
++ optimize setting to zero. We have to detect 8xx processors, which
++ have buggy dcbz implementations that cannot report page faults
++ correctly. */
++#define DL_PLATFORM_AUXV \
++ case AT_DCACHEBSIZE: \
++ break;
++
++#include <sysdeps/unix/sysv/linux/dl-sysdep.c>
+diff -Naur glibc-2.20/sysdeps/unix/sysv/linux/powerpc/powerpc32/823/libc-start.c glibc-2.20-patch/sysdeps/unix/sysv/linux/powerpc/powerpc32/823/libc-start.c
+--- glibc-2.20/sysdeps/unix/sysv/linux/powerpc/powerpc32/823/libc-start.c 1969-12-31 18:00:00.000000000 -0600
++++ glibc-2.20-patch/sysdeps/unix/sysv/linux/powerpc/powerpc32/823/libc-start.c 2015-02-24 13:58:03.323739026 -0600
+@@ -0,0 +1,86 @@
++/* Copyright (C) 1998-2014 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, see
++ <http://www.gnu.org/licenses/>. */
++
++#include <stdlib.h>
++#include <unistd.h>
++#include <ldsodefs.h>
++#include <sysdep.h>
++
++
++int __cache_line_size attribute_hidden;
++/* The main work is done in the generic function. */
++#define LIBC_START_MAIN generic_start_main
++#define LIBC_START_DISABLE_INLINE
++#define LIBC_START_MAIN_AUXVEC_ARG
++#define MAIN_AUXVEC_ARG
++#define INIT_MAIN_ARGS
++#include <csu/libc-start.c>
++
++struct startup_info
++ {
++ void *sda_base;
++ int (*main) (int, char **, char **, void *);
++ int (*init) (int, char **, char **, void *);
++ void (*fini) (void);
++ };
++
++int
++__libc_start_main (int argc, char **argv,
++ char **ev,
++ ElfW (auxv_t) * auxvec,
++ void (*rtld_fini) (void),
++ struct startup_info *stinfo,
++ char **stack_on_entry)
++{
++ /* the PPC SVR4 ABI says that the top thing on the stack will
++ be a NULL pointer, so if not we assume that we're being called
++ as a statically-linked program by Linux... */
++ if (*stack_on_entry != NULL)
++ {
++ char **temp;
++ /* ...in which case, we have argc as the top thing on the
++ stack, followed by argv (NULL-terminated), envp (likewise),
++ and the auxiliary vector. */
++ /* 32/64-bit agnostic load from stack */
++ argc = *(long int *) stack_on_entry;
++ argv = stack_on_entry + 1;
++ ev = argv + argc + 1;
++#ifdef HAVE_AUX_VECTOR
++ temp = ev;
++ while (*temp != NULL)
++ ++temp;
++ auxvec = (ElfW (auxv_t) *)++ temp;
++#endif
++ rtld_fini = NULL;
++ }
++
++ /* Initialize the __cache_line_size variable from the aux vector.
++ This is used by memset to optimize setting to zero. We have to
++ detect 8xx processors, which have buggy dcbz implementations that
++ cannot report page faults correctly. That requires reading SPR,
++ which is a privileged operation.*/
++ for (ElfW (auxv_t) * av = auxvec; av->a_type != AT_NULL; ++av)
++ switch (av->a_type)
++ {
++ case AT_DCACHEBSIZE:
++ break;
++ }
++
++ return generic_start_main (stinfo->main, argc, argv, auxvec,
++ stinfo->init, stinfo->fini, rtld_fini,
++ stack_on_entry);
++}
+diff -Naur glibc-2.20/sysdeps/unix/sysv/linux/powerpc/powerpc32/860/dl-sysdep.c glibc-2.20-patch/sysdeps/unix/sysv/linux/powerpc/powerpc32/860/dl-sysdep.c
+--- glibc-2.20/sysdeps/unix/sysv/linux/powerpc/powerpc32/860/dl-sysdep.c 1969-12-31 18:00:00.000000000 -0600
++++ glibc-2.20-patch/sysdeps/unix/sysv/linux/powerpc/powerpc32/860/dl-sysdep.c 2015-02-24 13:58:41.664736975 -0600
+@@ -0,0 +1,35 @@
++/* Operating system support for run-time dynamic linker. Linux/PPC version.
++ Copyright (C) 1997-2014 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, see
++ <http://www.gnu.org/licenses/>. */
++
++#include <config.h>
++#include <ldsodefs.h>
++
++int __cache_line_size attribute_hidden;
++
++/* Scan the Aux Vector for the "Data Cache Block Size" entry. If found
++ verify that the static extern __cache_line_size is defined by checking
++ for not NULL. If it is defined then assign the cache block size
++ value to __cache_line_size. This is used by memset to
++ optimize setting to zero. We have to detect 8xx processors, which
++ have buggy dcbz implementations that cannot report page faults
++ correctly. */
++#define DL_PLATFORM_AUXV \
++ case AT_DCACHEBSIZE: \
++ break;
++
++#include <sysdeps/unix/sysv/linux/dl-sysdep.c>
+diff -Naur glibc-2.20/sysdeps/unix/sysv/linux/powerpc/powerpc32/860/libc-start.c glibc-2.20-patch/sysdeps/unix/sysv/linux/powerpc/powerpc32/860/libc-start.c
+--- glibc-2.20/sysdeps/unix/sysv/linux/powerpc/powerpc32/860/libc-start.c 1969-12-31 18:00:00.000000000 -0600
++++ glibc-2.20-patch/sysdeps/unix/sysv/linux/powerpc/powerpc32/860/libc-start.c 2015-02-24 13:58:41.664736975 -0600
+@@ -0,0 +1,86 @@
++/* Copyright (C) 1998-2014 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, see
++ <http://www.gnu.org/licenses/>. */
++
++#include <stdlib.h>
++#include <unistd.h>
++#include <ldsodefs.h>
++#include <sysdep.h>
++
++
++int __cache_line_size attribute_hidden;
++/* The main work is done in the generic function. */
++#define LIBC_START_MAIN generic_start_main
++#define LIBC_START_DISABLE_INLINE
++#define LIBC_START_MAIN_AUXVEC_ARG
++#define MAIN_AUXVEC_ARG
++#define INIT_MAIN_ARGS
++#include <csu/libc-start.c>
++
++struct startup_info
++ {
++ void *sda_base;
++ int (*main) (int, char **, char **, void *);
++ int (*init) (int, char **, char **, void *);
++ void (*fini) (void);
++ };
++
++int
++__libc_start_main (int argc, char **argv,
++ char **ev,
++ ElfW (auxv_t) * auxvec,
++ void (*rtld_fini) (void),
++ struct startup_info *stinfo,
++ char **stack_on_entry)
++{
++ /* the PPC SVR4 ABI says that the top thing on the stack will
++ be a NULL pointer, so if not we assume that we're being called
++ as a statically-linked program by Linux... */
++ if (*stack_on_entry != NULL)
++ {
++ char **temp;
++ /* ...in which case, we have argc as the top thing on the
++ stack, followed by argv (NULL-terminated), envp (likewise),
++ and the auxiliary vector. */
++ /* 32/64-bit agnostic load from stack */
++ argc = *(long int *) stack_on_entry;
++ argv = stack_on_entry + 1;
++ ev = argv + argc + 1;
++#ifdef HAVE_AUX_VECTOR
++ temp = ev;
++ while (*temp != NULL)
++ ++temp;
++ auxvec = (ElfW (auxv_t) *)++ temp;
++#endif
++ rtld_fini = NULL;
++ }
++
++ /* Initialize the __cache_line_size variable from the aux vector.
++ This is used by memset to optimize setting to zero. We have to
++ detect 8xx processors, which have buggy dcbz implementations that
++ cannot report page faults correctly. That requires reading SPR,
++ which is a privileged operation.*/
++ for (ElfW (auxv_t) * av = auxvec; av->a_type != AT_NULL; ++av)
++ switch (av->a_type)
++ {
++ case AT_DCACHEBSIZE:
++ break;
++ }
++
++ return generic_start_main (stinfo->main, argc, argv, auxvec,
++ stinfo->init, stinfo->fini, rtld_fini,
++ stack_on_entry);
++}
diff --git a/recipes-core/glibc/glibc-fsl/0008.glibc.e500v2_lib_support.patch b/recipes-core/glibc/glibc-fsl/0008.glibc.e500v2_lib_support.patch
new file mode 100644
index 0000000..b2f04be
--- /dev/null
+++ b/recipes-core/glibc/glibc-fsl/0008.glibc.e500v2_lib_support.patch
@@ -0,0 +1,2542 @@
+# Problem Statement:
+ Optimized library functions for e500v2
+
+# Owned By:
+ Edmar Wienskoski
+
+diff -Naur libc/sysdeps/powerpc/powerpc32/e500/memcpy.S libc-e500v2-lib/sysdeps/powerpc/powerpc32/e500/memcpy.S
+--- libc/sysdeps/powerpc/powerpc32/e500/memcpy.S 1969-12-31 18:00:00.000000000 -0600
++++ libc-e500v2-lib/sysdeps/powerpc/powerpc32/e500/memcpy.S 2014-08-01 06:43:32.864371998 -0500
+@@ -0,0 +1,408 @@
++/*------------------------------------------------------------------
++ * memcpy.S
++ *
++ * Standard memcpy function optimized for e500 using SPE. This
++ * function does not handle overlap, as per spec. This file is
++ * identical to the memmove.S file. To get a memmove out of it,
++ * specify -D__MEMMOVE__ to the compiler
++ *
++ *------------------------------------------------------------------
++ * Copyright (c) 2005 Freescale Semiconductor, Inc
++ * ALL RIGHTS RESERVED
++ *
++ * Redistribution and use in source and binary forms, with or
++ * without modification, are permitted provided that the following
++ * conditions are met:
++ *
++ *
++ * Redistributions of source code must retain the above copyright
++ * notice, this list of conditions and the following disclaimer.
++ *
++ * Redistributions in binary form must reproduce the above copyright
++ * notice, this list of conditions and the following disclaimer in
++ * the documentation and/or other materials provided with the
++ * distribution.
++ *
++ * Neither the name of Freescale Semiconductor, Inc nor the names of
++ * its contributors may be used to endorse or promote products derived
++ * from this software without specific prior written permission.
++ *
++ *
++ *
++ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND
++ * CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
++ * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
++ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
++ * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS
++ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
++ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED
++ * TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
++ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
++ * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
++ * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
++ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
++ * POSSIBILITY OF SUCH DAMAGE.
++ *------------------------------------------------------------------
++ */
++
++#include <sysdep.h>
++
++/*------------------------------------------------------------------
++ * int memcpy(const unsigned char* dst,
++ * const unsigned char* src,
++ * long count);
++ * void * memmove(const unsigned char* dst,
++ * const unsigned char* src,
++ * long count);
++ * Returns:
++ * dst
++ *------------------------------------------------------------------
++ */
++
++#ifdef __MEMMOVE__
++ .file "memmove.S"
++#else /* memcpy */
++ .file "memcpy.S"
++#endif /* __MEMMOVE */
++ .section ".text"
++ .align 4
++#ifdef __MEMMOVE__
++ #define FUNCTION memmove
++#else /* memcpy */
++ #define FUNCTION memcpy
++#endif /* __MEMMOVE__ */
++EALIGN (FUNCTION, 5, 1)
++
++/* Prologs are different for memcpy and memmove. memmove needs
++ * to handle the case where the buffers overlap correctly.
++ * memcpy does not. In order to make the implementation simple,
++ * memmove ONLY copies backwards if it needs to, and only for as
++ * much as is necessary to remove the overlap.
++ */
++#ifdef __MEMMOVE__
++ or r0,r4,r3
++ subf r9,r4,r3
++ mr r6,r3
++ subf r11,r9,r5
++ andi. r0,r0,7
++ rlwinm r9,r9,0,0,0
++ xor r0,r4,r6
++ bne L(memcpy_unaligned)
++
++ or. r11,r9,r11
++ bgt L(Handle_Overlap)
++
++/* memcpy is simpler */
++#else /* memcpy */
++
++ or r0,r4,r3
++ mr r6,r3
++ andi. r0,r0,7
++ xor r0,r4,r6
++ bne L(memcpy_unaligned)
++
++#endif /* __MEMMOVE__ */
++
++L(aligned_copy):
++ srwi. r12,r5,5
++ mtcrf 0x2,r5
++ mtcrf 0x1,r5
++ bne L(big_loop)
++
++L(try_two_doubles):
++ bf 27,L(try_one_double)
++ evldd r7,0(r4)
++ evstdd r7,0(r6)
++ evldd r8,8(r4)
++ addi r4,r4,16
++ evstdd r8,8(r6)
++ addi r6,r6,16
++
++L(try_one_double):
++ bf 28,L(try_word)
++ evldd r7,0(r4)
++ addi r4,r4,8
++ evstdd r7,0(r6)
++ addi r6,r6,8
++
++L(try_word):
++ bf 29,L(try_half)
++ lwz r7,0(r4)
++ addi r4,r4,4
++ stw r7,0(r6)
++ addi r6,r6,4
++
++L(try_half):
++ bf 30,L(try_byte)
++ lhz r7,0(r4)
++ addi r4,r4,2
++ sth r7,0(r6)
++ addi r6,r6,2
++
++L(try_byte):
++ bf 31,L(finish)
++ lbz r7,0(r4)
++ stb r7,0(r6)
++
++L(finish):
++ blr
++
++L(big_loop):
++ evldd r7,0(r4)
++ addic. r12,r12,-1
++ evldd r8,8(r4)
++ evldd r9,16(r4)
++ evldd r10,24(r4)
++ addi r4,r4,32
++ evstdd r7,0(r6)
++ evstdd r8,8(r6)
++ evstdd r9,16(r6)
++ evstdd r10,24(r6)
++ addi r6,r6,32
++ bne L(big_loop)
++
++ b L(try_two_doubles)
++
++L(align_dest_word):
++L(align_dest_double):
++ /* First make sure there are at least 8 bytes left to
++ * copy. Otherwise, realignment could go out of bounds
++ */
++ cmpwi r5,8
++ neg r0,r6
++ blt L(small_copy)
++
++ andi. r7,r6,0x3
++ mtcrf 0x1,r0
++
++ bne L(more_alignment)
++
++/* Don't need to check if r6 needs another word to be aligned.
++ * We're here, therefore we must have only been off by a word.
++ * So we shorten the path a bit by taking 2 branches out from the
++ * more common path (ie things tend to be at least word-aligned)
++ */
++L(align_one_word):
++ lwz r7,0(r4)
++ addi r4,r4,4
++ stw r7,0(r6)
++ addi r6,r6,4
++ addi r5,r5,-4
++ bne cr6,L(unaligned_double_copy)
++ b L(aligned_copy)
++
++L(more_alignment):
++ bf 31, L(try_align_word)
++ lbz r7,0(r4)
++ addi r4,r4,1
++ stb r7,0(r6)
++ addi r6,r6,1
++ addi r5,r5,-1
++
++L(try_align_word):
++ bf 30, L(try_align_double)
++ lhz r7,0(r4)
++ addi r4,r4,2
++ sth r7,0(r6)
++ addi r6,r6,2
++ addi r5,r5,-2
++
++L(try_align_double):
++ bt 29, L(align_one_word)
++ beq cr6,L(aligned_copy)
++
++/* For each double word copied, we load the double words with
++ * each half from r4 (which starts at 0x*4 or 0x*c). Then we
++ * use evmergelohi to take the halves and rejoin them. Notice
++ * that any double load will necessarily be 4 bytes ahead.
++ * Invariant: at the start of any block (except the first) which
++ * loads a doubleword, r10 will hold the first half of the
++ * first doubleword
++ */
++L(unaligned_double_copy):
++ /* align r4 to a doubleword boundary */
++ rlwinm r4,r4,0,0,28
++ srwi. r12, r5,5
++
++ /* grab the first doubleword */
++ evldd r10,0(r4)
++
++ /* Set the CR to indicate how many bytes remain to be
++ * copied after the big loop is done */
++ mtcrf 0x2,r5
++ mtcrf 0x1,r5
++ bne L(unaligned_big_loop)
++
++/* There are less than 4 double words left, so we take care of
++ * them
++ */
++L(try_unaligned_2_doubles):
++ bf 27, L(try_unaligned_double)
++ evldd r9,8(r4)
++ evmergelohi r10,r10,r9
++ evstdd r10,0(r6)
++ evldd r10,16(r4)
++ addi r4,r4,16
++ evmergelohi r9,r9,r10
++ evstdd r9,8(r6)
++ addi r6,r6,16
++
++L(try_unaligned_double):
++ bf 28, L(try_unaligned_word)
++ evldd r9,8(r4)
++ addi r4,r4,8
++ evmergelohi r10,r10,r9
++ evstdd r10,0(r6)
++ addi r6,r6,8
++ evmr r10,r9
++
++L(try_unaligned_word):
++ addi r4,r4,4
++ bf 29, L(try_unaligned_half)
++ stw r10,0(r6)
++ addi r4,r4,4
++ addi r6,r6,4
++
++L(try_unaligned_half):
++ bf 30, L(try_unaligned_byte)
++ lhz r10,0(r4)
++ addi r4,r4,2
++ sth r10,0(r6)
++ addi r6,r6,2
++
++L(try_unaligned_byte):
++ bf 31, L(finish)
++ lbz r10,0(r4)
++ stb r10,0(r6)
++ blr
++
++L(unaligned_big_loop):
++ evldd r7,8(r4)
++ evldd r8,16(r4)
++ addic. r12,r12,-1
++ evldd r9,24(r4)
++ addi r4,r4,32
++ evmergelohi r10,r10,r7
++ evstdd r10,0(r6)
++ evmergelohi r7,r7,r8
++ evldd r10,0(r4)
++ evmergelohi r8,r8,r9
++ evstdd r7,8(r6)
++ evmergelohi r9,r9,r10
++ evstdd r8,16(r6)
++ evstdd r9,24(r6)
++ addi r6,r6,32
++ bne L(unaligned_big_loop)
++ b L(try_unaligned_2_doubles)
++
++
++L(small_copy):
++ mtcrf 0x1,r5
++ bf 29,L(try_small_half)
++ lbz r7,0(r4)
++ lbz r8,1(r4)
++ lbz r9,2(r4)
++ lbz r10,3(r4)
++ addi r4,r4,4
++ stb r7,0(r6)
++ stb r8,1(r6)
++ stb r9,2(r6)
++ stb r10,3(r6)
++ addi r6,r6,4
++
++L(try_small_half):
++ bf 30,L(try_small_byte)
++ lbz r7,0(r4)
++ lbz r8,1(r4)
++ addi r4,r4,2
++ stb r7,0(r6)
++ stb r8,1(r6)
++ addi r6,r6,2
++
++L(try_small_byte):
++ bf 31, L(finish)
++ lbz r7,0(r4)
++ stb r7,0(r6)
++ blr
++
++L(memcpy_unaligned):
++#ifdef __MEMMOVE__
++
++ or. r11,r9,r11
++ bgt L(Handle_Overlap)
++
++L(choose_alignment):
++#endif /* __MEMMOVE */
++ /* If both pointers can be double-aligned, align r6,
++ * setting eq6 to indicate "aligned
++ */
++ rlwinm. r0,r0,0,29,31
++ cmpw cr6,r31,r31 /* set eq6 */
++
++ /* Look at r6 to see if we're aligned already (but not
++ * both aligned, which is why we're here)
++ */
++ rlwinm r7,r6,0,29,31
++ beq L(align_dest_double)
++
++ /* Compare to find out if r6 is already doublealigned
++ * If both pointers can be word-aligned, align r6,
++ * clearing eq6 to indicate unaligned
++ */
++ rlwinm. r0,r0,0,30,31
++ cmpwi cr1,r7,0
++
++ /* Only skip to unaligned_double_copy if r6 is aligned,
++ * AND r0 indicates word-alignment
++ */
++ crand 6,6,2
++
++ crxor 26,26,26 /* clear eq6 */
++ beq cr1,L(unaligned_double_copy)
++ beq L(align_dest_word)
++
++ /* Before we hop into bytewise copying, make sure that
++ * there are bytes to copy (don't want to loop 4 billion+
++ * times!
++ */
++ cmpwi r5,0
++ beqlr
++
++ /* Well, alignment is just icky, copy bytewise */
++ mtctr r5
++L(byte_copy):
++ lbz r7,0(r4)
++ addi r4,r4,1
++ stb r7,0(r6)
++ addi r6,r6,1
++ bdnz L(byte_copy)
++ blr
++
++#ifdef __MEMMOVE__
++
++
++ /* If the regions being copied overlap, and r4 is lower
++ * in memory than r6, then we need to copy backward
++ * until the overlap is gone, then just do the normal
++ * copy
++ */
++L(Handle_Overlap):
++ /* r11 has the size of the overlap */
++ add r8,r6,r5
++ add r10,r4,r5
++
++ mtctr r11
++
++L(bkw_fix_loop):
++ lbzu r9,-1(r10)
++ stbu r9,-1(r8)
++ bdnz L(bkw_fix_loop)
++
++ /* We're done, correct r5, and return */
++ subf r5,r11,r5
++
++ b FUNCTION at local
++#endif /* __MEMMOVE */
++
++END (FUNCTION)
++libc_hidden_builtin_def (FUNCTION)
+diff -Naur libc/sysdeps/powerpc/powerpc32/e500/memmove.S libc-e500v2-lib/sysdeps/powerpc/powerpc32/e500/memmove.S
+--- libc/sysdeps/powerpc/powerpc32/e500/memmove.S 1969-12-31 18:00:00.000000000 -0600
++++ libc-e500v2-lib/sysdeps/powerpc/powerpc32/e500/memmove.S 2014-08-01 06:42:29.703372001 -0500
+@@ -0,0 +1,2 @@
++#define __MEMMOVE__ 1
++#include <memcpy.S>
+diff -Naur libc/sysdeps/powerpc/powerpc32/e500/memset.S libc-e500v2-lib/sysdeps/powerpc/powerpc32/e500/memset.S
+--- libc/sysdeps/powerpc/powerpc32/e500/memset.S 1969-12-31 18:00:00.000000000 -0600
++++ libc-e500v2-lib/sysdeps/powerpc/powerpc32/e500/memset.S 2014-08-01 06:44:25.470371998 -0500
+@@ -0,0 +1,393 @@
++/*------------------------------------------------------------------
++ * memset.S
++ *
++ * Standard memset function optimized for e500 using SPE
++ *
++ * Copyright (c) 2005 Freescale Semiconductor, Inc
++ * All rights reserved.
++ *
++ * Redistribution and use in source and binary forms, with or without
++ * modification, are permitted provided that the following conditions are met:
++ * * Redistributions of source code must retain the above copyright
++ * notice, this list of conditions and the following disclaimer.
++ * * Redistributions in binary form must reproduce the above copyright
++ * notice, this list of conditions and the following disclaimer in the
++ * documentation and/or other materials provided with the distribution.
++ * * Neither the name of Freescale Semiconductor nor the
++ * names of its contributors may be used to endorse or promote products
++ * derived from this software without specific prior written permission.
++ *
++ * THIS SOFTWARE IS PROVIDED BY Freescale Semiconductor ``AS IS'' AND ANY
++ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
++ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
++ * DISCLAIMED. IN NO EVENT SHALL Freescale Semiconductor BE LIABLE FOR ANY
++ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
++ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
++ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
++ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
++ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
++ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
++ *------------------------------------------------------------------
++ */
++
++#include <sysdep.h>
++
++/*------------------------------------------------------------------
++ * void * memset(void *origdest, int value, size_t len)
++ *
++ * returns dest
++ *
++ *------------------------------------------------------------------
++ */
++
++
++ .file "memset.S"
++ .section ".text"
++EALIGN (memset, 5, 0)
++ /* Find out whether the destination buffer is already
++ * aligned, and propagate the byte through the entire
++ * word.
++ */
++ andi. r0,r3,0x7
++ rlwimi r4,r4,8,16,23
++
++ /* Check if value (r4) is zero (most common case). If it
++ * is, we jump to bzero
++ */
++ cmpwi cr1,r4,0
++
++ rlwimi r4,r4,16,0,15
++
++ /* If r4 is 0, then we will jump to bzero. If so,
++ * we want the count to be in the right place for bzero (r4)
++ */
++ mr r11,r4
++ mr r4,r5
++
++ beq cr1, L(bzero_entry)
++
++ mr r6,r3
++ bne L(align_dest_double)
++
++L(aligned_set):
++ /* Get the number of doubles/4, since we write 4 at a
++ * time in the big loop.
++ */
++ srwi. r12,r5,5
++
++ /* Set the condition register so that each bit represents
++ * some number of bytes to set.
++ */
++ mtcrf 0x2,r5
++ mtcrf 0x1,r5
++
++ /* Copy r11 up into the hi word, so we can set 8 bytes
++ * at a time.
++ */
++ evmergelo r11,r11,r11
++
++ /* If there aren't at least 32 bytes to set, take care of
++ * the last 0-31
++ */
++ bne L(big_loop)
++
++/* We only store to memory that we are changing. No extra loads
++ * or stores are done.
++ */
++L(try_two_doubles):
++ bf 27,L(try_one_double)
++ evstdd r11,0(r6)
++ evstdd r11,8(r6)
++ addi r6,r6,16
++
++L(try_one_double):
++ bf 28,L(try_word)
++ evstdd r11,0(r6)
++ addi r6,r6,8
++ nop
++
++L(try_word):
++ bf 29,L(try_half)
++ stw r11,0(r6)
++ addi r6,r6,4
++ nop
++
++L(try_half):
++ bf 30,L(try_byte)
++ sth r11,0(r6)
++ addi r6,r6,2
++ nop
++
++L(try_byte):
++ bf 31,L(finish)
++ stb r11,0(r6)
++
++L(finish):
++ blr
++
++/* Write 32 bytes at a time */
++L(big_loop):
++ /* adjust r6 back by 8. We need to do this so we can
++ * hoist the pointer update above the last store in the
++ * loop. This means that a store can be done every cycle
++ */
++ addi r6,r6,-8
++L(loop):
++ evstdd r11,8(r6)
++ addic. r12,r12,-1
++ evstdd r11,16(r6)
++ evstdd r11,24(r6)
++ addi r6,r6,32
++ evstdd r11,0(r6)
++ bne L(loop)
++
++ /* Readjust r6 */
++ addi r6,r6,8
++ /* Jump back to take care of the last 0-31 bytes */
++ b L(try_two_doubles)
++
++L(align_dest_double):
++ /* First make sure there are at least 8 bytes left to
++ * set. Otherwise, realignment could go out of bounds
++ */
++ cmpwi cr1, r5,8
++
++ /* Find out how many bytes we need to set in order to
++ * align r6
++ */
++ neg r0,r6
++ andi. r7,r6,0x3
++
++ blt cr1, L(small_set)
++
++ /* Set the condition register so that each bit in cr7
++ * represents a number of bytes to write to align r6
++ */
++ mtcrf 0x1,r0
++
++ /* The most common case is that r6 is at least
++ * word-aligned, so that is the fall-through case.
++ * Otherwise, we skip ahead to align a bit more.
++ */
++ bne L(more_alignment)
++L(align_one_word):
++ addi r5,r5,-4
++ stw r11,0(r6)
++ addi r6,r6,4
++ b L(aligned_set)
++
++L(more_alignment):
++ bf 31, L(try_align_word)
++ addi r5,r5,-1
++ stb r11,0(r6)
++ addi r6,r6,1
++
++L(try_align_word):
++ bf 30, L(try_align_double)
++ addi r5,r5,-2
++ sth r11,0(r6)
++ addi r6,r6,2
++
++L(try_align_double):
++ bt 29, L(align_one_word)
++ b L(aligned_set)
++
++L(small_set):
++ mtcrf 0x1,r5
++ bf 29,L(try_small_half)
++ /* This may be better, but stw SHOULD do the same thing
++ * as fast or faster. It just has a chance of being
++ * unaligned
++ * stb r11,0(r6)
++ * stb r11,1(r6)
++ * stb r11,2(r6)
++ * stb r11,3(r6)
++ */
++
++ stw r11,0(r6)
++ addi r6,r6,4
++
++L(try_small_half):
++ bf 30,L(try_small_byte)
++
++ /* Storing half should take the same or less time than
++ * two stb, so we do that
++ */
++ sth r11,0(r6)
++ addi r6,r6,2
++
++L(try_small_byte):
++ bf 31, L(finish)
++ stb r11,0(r6)
++ blr
++
++END (memset)
++libc_hidden_builtin_def (memset)
++
++EALIGN (bzero, 5, 0)
++L(bzero_entry):
++ /* Check dest's alignment (within a cache-line) */
++ neg r8,r3
++
++ /* r12, here, is the number of 128 byte chunks to
++ * zero out.
++ */
++ srwi r12,r4,7
++
++ /* Find out the number of bytes needed to copy to align
++ * dest to a cacheline boundary
++ */
++ andi. r8, r8,0x1f
++ cmpwi cr1,r12,0
++
++ /* bzero can be called from memset, so we want it to
++ * return the same value memset would. This doesn't hurt
++ * anything, so we keep the old value of r3, and copy it
++ * into another register which we are free to change.
++ */
++ mr r6,r3
++
++ /* Jump to align r6 if it isn't already aligned */
++ bne L(align_dest_32)
++
++ /* r6 is aligned to a cache-line, so we can zero
++ * out using dcbz if the buffer is large enough
++ */
++L(zero_aligned):
++ /* set the cr bits for the last 0-127 bytes remaining */
++ mtcrf 0x1,r4
++ mtcrf 0x2,r4
++
++ li r10,-32
++ li r9,32
++ beq cr1,L(try_two_lines)
++
++ li r11,64
++
++L(zero_loop):
++ dcbz 0,r6
++ addic. r12,r12,-1
++ dcbz r9,r6
++ dcbz r11,r6
++ addi r6,r6,128
++ dcbz r10,r6
++ bne L(zero_loop)
++
++L(try_two_lines):
++ /* Put 0 into r11 such that memset can handle the last
++ * 0-31 bytes (yay, instruction savings!)
++ */
++ evsplati r11,0
++
++ rlwinm. r0, r4,0,27,31
++
++ bf 25, L(try_one_line)
++ dcbz 0,r6
++ dcbz r9,r6
++ addi r6,r6,64
++
++L(try_one_line):
++ bf 26, L(try_two_doubles)
++ dcbz 0,r6
++ addi r6,r6,32
++
++ bne L(try_two_doubles)
++ /* there weren't any bytes left, so we return */
++ blr
++
++L(align_dest_32):
++ /* move r8 into the crfields so that we can align
++ * easily
++ */
++ mtcrf 0x1,r8
++ mtcrf 0x2,r8
++
++ /* update the counter */
++ subf. r4,r8,r4
++
++ /* if r4 is not great enough to align r6, then we
++ * zero in small amounts
++ */
++ blt L(zero_small)
++
++ /* zero out a register to store to memory */
++ evsplati r8,0
++
++ bf 31,L(zero_one_half)
++ stb r8,0(r6)
++ addi r6,r6,1
++ nop
++
++L(zero_one_half):
++ bf 30, L(zero_word)
++ sth r8,0(r6)
++ addi r6,r6,2
++ nop
++
++L(zero_word):
++ bf 29, L(zero_double)
++ stw r8,0(r6)
++ addi r6,r6,4
++ nop
++
++L(zero_double):
++ bf 28, L(zero_two)
++ evstdd r8,0(r6)
++ addi r6,r6,8
++ nop
++
++L(zero_two):
++ bf 27,L(zero_finish)
++ evstdd r8,0(r6)
++ evstdd r8,8(r6)
++ addi r6,r6,16
++
++L(zero_finish):
++ srwi. r12,r4,7
++ li r9,32
++ li r11,64
++ li r10,-32
++
++ mtcrf 0x1,r4
++ mtcrf 0x2,r4
++ bne L(zero_loop)
++ b L(try_two_lines)
++
++L(zero_small):
++ add r4,r8,r4
++ mtcrf 0x1,r4
++ mtcrf 0x2,r4
++
++ evsplati r8,0
++
++ bf 27,L(zero_one_small)
++ stw r8,0(r6)
++ stw r8,4(r6)
++ stw r8,8(r6)
++ stw r8,12(r6)
++ addi r6,r6,16
++
++L(zero_one_small):
++ bf 28,L(zero_word_small)
++ stw r8,0(r6)
++ stw r8,4(r6)
++ addi r6,r6,8
++
++L(zero_word_small):
++ bf 29,L(zero_half_small)
++ stw r8,0(r6)
++ addi r6,r6,4
++
++L(zero_half_small):
++ bf 30,L(zero_byte_small)
++ sth r8,0(r6)
++ addi r6,r6,2
++
++L(zero_byte_small):
++ bf 31,L(finish)
++ stb r8,0(r6)
++
++ blr
++
++END (bzero)
++libc_hidden_builtin_def (bzero)
+diff -Naur libc/sysdeps/powerpc/powerpc32/e500/strcmp.S libc-e500v2-lib/sysdeps/powerpc/powerpc32/e500/strcmp.S
+--- libc/sysdeps/powerpc/powerpc32/e500/strcmp.S 1969-12-31 18:00:00.000000000 -0600
++++ libc-e500v2-lib/sysdeps/powerpc/powerpc32/e500/strcmp.S 2014-08-01 06:44:54.397372002 -0500
+@@ -0,0 +1,685 @@
++/*------------------------------------------------------------------
++ * strcmp.S
++ *
++ * Standard strcmp function optimized for e500 using SPE
++ *
++ * Copyright (c) 2005 Freescale Semiconductor, Inc
++ * All rights reserved.
++ *
++ * Redistribution and use in source and binary forms, with or without
++ * modification, are permitted provided that the following conditions are met:
++ * * Redistributions of source code must retain the above copyright
++ * notice, this list of conditions and the following disclaimer.
++ * * Redistributions in binary form must reproduce the above copyright
++ * notice, this list of conditions and the following disclaimer in the
++ * documentation and/or other materials provided with the distribution.
++ * * Neither the name of Freescale Semiconductor nor the
++ * names of its contributors may be used to endorse or promote products
++ * derived from this software without specific prior written permission.
++ *
++ * THIS SOFTWARE IS PROVIDED BY Freescale Semiconductor ``AS IS'' AND ANY
++ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
++ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
++ * DISCLAIMED. IN NO EVENT SHALL Freescale Semiconductor BE LIABLE FOR ANY
++ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
++ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
++ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
++ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
++ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
++ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
++ *------------------------------------------------------------------
++ */
++
++#include <sysdep.h>
++
++/*------------------------------------------------------------------
++ * int strcmp(const unsigned char* sourceA,
++ * const unsigned char* sourceB);
++ * Returns:
++ * value < 0 if source1 < source2
++ * value = 0 if source1 = source2
++ * value > 0 if source1 > source2
++ *------------------------------------------------------------------
++ */
++
++ .file "strcmp.S"
++ .section ".text"
++/* If sourceA and sourceB are aligned the same wrt doublewords,
++ * or aligned the same wrt words, we compare in doublewords.
++ * Otherwise, go byte by byte.
++ */
++EALIGN (strcmp, 5, 0)
++
++ /* Load constant 0x01010101 */
++ lis r11,0x0101
++ ori r11,r11,0x0101
++
++ /* r3 will be used for returning stuff, so lets move
++ * sourceA out of there
++ */
++ mr r10,r3
++
++ /* Load doubleword constant 0x01010101 */
++ evmergelo r12,r11,r11
++
++ /* generate a mask to set the unwanted bits to 1
++ * take the alignment of r10 * 8
++ */
++ rlwinm r6, r10, 3, 27,28
++
++ /* Load doubleword constant 0x80808080 */
++ evslwi r11,r12,7
++
++ /* start the mask with all Fs */
++ li r8, -1
++
++ or r0,r10,r4
++
++ subfic r6, r6, 32
++
++ andi. r0,r0,0x7
++
++ /* Shift r8 by r6 to mask off preceding bytes */
++ slw r8, r8, r6
++
++ /* Save the stack, cuz we need to save a reg */
++ stwu r1, -32(r1)
++
++ /* save r14 for counting. This is cheaper than bdnz */
++ stw r14, 8(r1)
++
++ beq L(Aligned_Double)
++
++/* load the first words (on word boundaries) and process them,
++ * setting bits preceding the first byte to 1.
++ */
++
++ /* If r10 and r4 can't be aligned to words, then jump
++ * to unaligned compare
++ */
++ xor r0,r10,r4
++ rlwinm. r0,r0,0,30,31
++ bne L(unaligned_compare)
++
++ /* align r10 to word */
++ rlwinm r10, r10, 0,0,29
++
++ /* process the first word, and word align r4 */
++ lwz r5, 0(r10)
++ rlwinm r4, r4, 0,0,29
++
++ /* Check whether r10 and r4 are both aligned double or not.
++ * Jump to Unaligned_Double if they are different.
++ */
++ xor r0,r10,r4
++ addi r10, r10, 4
++
++ /* Load the other first word (B), and set all the bits
++ * preceding the first real byte
++ */
++ lwz r7, 0(r4)
++ or r5, r5, r8
++
++ /* This will be 0b100 if the ptrs are only word aligned
++ * (not doubleword aligned)
++ */
++ rlwinm r0,r0,0,29,29
++
++ /* Look for nulls in the first (partial) word */
++ subfc r3, r12, r5
++ andc r9, r11, r5
++
++ /* Update r4, and find out if there were any nulls */
++ addi r4,r4,4
++ and. r9, r3, r9
++
++ /* Find out if we are doubleword aligned, and set all the
++ * bits preceding the first byte in word B
++ */
++ cmpwi 6, r0,0
++ or r7,r7,r8
++
++ /* jump out if we found a null, otherwise compare the two words */
++ bne L(find_null1)
++ subfc. r0, r5, r7
++
++ /* Set a condition bit if r10 is not yet doubleword
++ * aligned, and branch if the first words were different
++ */
++ mtcrf 0x01,r10
++ bne L(found_diff_early)
++
++ /* process another word if necessary to align to a doubleword
++ * boundary.
++ */
++ bf 29, L(Check_Aligned_Double)
++
++ /* Load another word from each string, to align r10 to a
++ * double word
++ */
++ lwz r5, 0(r10)
++ addi r10, r10, 4
++ lwz r7, 0(r4)
++ addi r4,r4,4
++
++
++ /* Check for nulls and differences in the words */
++ subfc r3, r12, r5
++ andc r9, r11, r5
++ and. r9, r3, r9
++ bne L(find_null1)
++ subfc. r0, r5, r7
++ bne L(found_diff_early)
++
++ /* r10 is now aligned to a doubleword boundary, but it
++ * may be that we are not both double aligned. We set a
++ * bit based on this earlier, so branch if it is set.
++ */
++L(Check_Aligned_Double):
++ bne 6, L(Unaligned_Double)
++
++ /* loop through 2 doublewords at once in this page, until one of
++ * these happens:
++ * 1) A null byte is found in r10
++ * 2) a byte is found which is different between r10 and r4
++ * 3) the end of the page is reached
++ *
++ * If 3 happens, then we finish processing the last doubleword in
++ * the page, and if it checks out, we jump to the next one. The
++ * hope is that no small strings are going to cross page
++ * boundaries. For large strings, the hit should be minimal
++ *
++ * If 1 happens, some extra checking goes on to see whether the
++ * strings are the same or not.
++ */
++L(Aligned_Double):
++ /* Start figuring out how far to the next page */
++ not r6,r10
++ not r8,r4
++
++ rlwinm r6,r6,29,23,31
++ rlwinm r8,r8,29,23,31
++
++ subfc. r0,r6,r8
++ evldd r5, 0(r10)
++
++ /* zero out a reg for comparison (the result of the final
++ * and is nonzero for any word with a null byte)
++ */
++ evsplati r0,0
++ evldd r7, 0(r4)
++
++ /* Select the shortest distance to the page */
++ isellt r14,r8,r6
++
++ evsubfw r3, r12, r5
++ addic. r14,r14,-6
++
++ evandc r9, r11, r5
++
++ blt L(aligned_double_loop_end)
++
++ /* The loop */
++L(aligned_double_loop):
++ evldd r6, 8(r10)
++ evand r9, r9, r3
++ addi r10,r10,16
++ evcmpgtu 1, r9, r0
++ evldd r8, 8(r4)
++ evcmpeq 6, r5, r7
++ bt 6, L(found_null1)
++ evsubfw r3,r12, r6
++ bf 27, L(found_diff1)
++ evandc r9, r11, r6
++ evldd r5, 0(r10)
++ evand r9,r9,r3
++ addi r4,r4,16
++ evcmpgtu 5, r9, r0
++ evldd r7, 0(r4)
++ evcmpeq 7, r6, r8
++ bt 22, L(found_null2)
++ evsubfw r3, r12, r5
++ bf 31, L(found_diff2)
++ evandc r9, r11, r5
++
++ evldd r6, 8(r10)
++ evand r9, r9, r3
++ addi r10,r10,16
++ evcmpgtu 1, r9, r0
++ evldd r8, 8(r4)
++ evcmpeq 6, r5, r7
++ bt 6, L(found_null1)
++ evsubfw r3,r12, r6
++ bf 27, L(found_diff1)
++ evandc r9, r11, r6
++ evldd r5, 0(r10)
++ evand r9,r9,r3
++ addi r4,r4,16
++ evcmpgtu 5, r9, r0
++ evldd r7, 0(r4)
++ evcmpeq 7, r6, r8
++ bt 22, L(found_null2)
++ evsubfw r3, r12, r5
++ bf 31, L(found_diff2)
++ addic. r14,r14,-4
++ evandc r9, r11, r5
++ bge L(aligned_double_loop)
++
++ /* we exited the loop, we must be at the end of a page.
++ * Finish the last one, and then see if we are done or
++ * not.
++ */
++L(aligned_double_loop_end):
++ evand r9, r9, r3
++ evcmpgtu 1, r9, r0
++ evcmpeq 6, r5, r7
++ bt 6, L(found_null1)
++ bf 27, L(found_diff1)
++ addi r10,r10,8
++ addi r4,r4,8
++
++ or r3, r10,r4
++ andi. r3, r3, 0xFFF
++ beq L(find_next_page)
++ /* We need to check the next doubleword, too. It may be
++ * in the next page, but it may be the last one in this
++ * page.
++ */
++ li r14,3
++L(find_page_end):
++ evldd r5, 0(r10)
++ addi r10,r10,8
++ evldd r7, 0(r4)
++ addi r4,r4,8
++ evsubfw r3, r12, r5
++ addic. r14,r14,-1
++ evandc r9, r11, r5
++ evand r9, r9, r3
++ evcmpgtu 1, r9, r0
++ evcmpeq 6, r5, r7
++ bt 6, L(found_null1)
++ bf 27, L(found_diff1)
++ bne L(find_page_end)
++
++
++ /* It is now safe to proceed to the next page. load the
++ * counter with the number of doublewords before the next
++ * page
++ */
++
++L(find_next_page):
++ not r6,r10
++ not r8,r4
++ rlwinm r6,r6,29,23,31
++ rlwinm r8,r8,29,23,31
++ subfc. r0,r6,r8
++ isellt r14,r8,r6
++ evldd r5, 0(r10)
++ addic. r14,r14,-6
++ evldd r7, 0(r4)
++ evsubfw r3, r12, r5
++ evandc r9, r11, r5
++ evsplati r0, 0
++ blt L(aligned_double_loop_end)
++ b L(aligned_double_loop)
++
++ /* The first doubleword had a null byte */
++L(found_unaligned_null1):
++ evmr r7,r15
++ evldd r15, 16(r1)
++L(found_null1):
++ /* If there was a null in the hi word, or if the hi words
++ * were not equal, we want to check the hi word, so move
++ * it down into the lo word
++ */
++ crorc 4,4,24
++ bf 4, L(find_null1)
++ evmergehi r5, r5, r5
++ evmergehi r7,r7,r7
++L(find_null1):
++ rlwinm. r11,r5,0,0,7
++ li r12,24
++ beq L(aligned_shift1)
++ rlwinm. r11,r5,0,8,15
++ li r12,16
++ beq L(aligned_shift1)
++ rlwinm. r11,r5,0,16,23
++ li r12,8
++ beq L(aligned_shift1)
++ li r12,0
++
++ /* If the signs are different for these words,
++ * then overflow can occur
++ */
++ xor. r0,r5,r7
++
++L(aligned_shift1):
++ srw r5,r5,r12
++ srw r7,r7,r12
++ lwz r14, 8(r1)
++ subfc r3,r7,r5
++ addi r1,r1,32
++
++ /* return now if the signs were the same (r3
++ * has the appropriate value). Otherwise, return
++ * r7. r7's sign matches that of the necessary
++ * return value, since the comparison is actually
++ * unsigned. This means that a negative number is
++ * actually large, and, if the signs are different,
++ * guaranteed to be larger than r5. The same is true
++ * for the opposite case. We also make sure it is
++ * non-zero.
++ */
++ bgelr
++ ori r3,r7,1
++ blr
++
++L(found_unaligned_null2):
++ evmr r8,r15
++ evldd r15, 16(r1)
++L(found_null2):
++ /* If there was a null in the hi word, move that word
++ * down into the lo word
++ */
++ evmr r5,r6
++ crorc 20, 20, 28
++ evmr r7,r8
++ bf 20, L(find_null1)
++ evmergehi r5, r5, r5
++ evmergehi r7, r7, r7
++ b L(find_null1)
++
++/* Now we know that there is a difference in one of the
++ two doublewords. We find the first different bit within
++ each word, and then rotate each word of B so that the sign
++ bit is that bit. When B is greater, that bit will be one, and
++ the sign of the return should be negative, and when B is less,
++ the bit will be zero, making the return positive. Also,
++ we need to OR the r3 with 1 to make sure it is non-zero
++ */
++L(found_unaligned1):
++ evmr r7,r15
++ evldd r15, 16(r1)
++L(found_diff1):
++ evxor r0,r5,r7
++ lwz r14,8(r1)
++ evcntlzw r0,r0
++ addi r1,r1,32
++ evrlw r3,r7,r0
++ evmergehi r4,r3,r3
++ isel r3,r3,r4,24
++ ori r3,r3,1
++ blr
++
++/* See found_diff1 description for explanation of this code */
++L(found_unaligned2):
++ evmr r8,r15
++ evldd r15, 16(r1)
++L(found_diff2):
++ evxor r0,r6,r8
++ lwz r14,8(r1)
++ evcntlzw r0,r0
++ addi r1,r1,32
++ evrlw r3,r8,r0
++ evmergehi r4,r3,r3
++ isel r3,r3,r4,28
++ ori r3,r3,1
++ blr
++
++L(Unaligned_Double):
++ /* Invert the pointers so that the last 12 bits hold the
++ * number of bytes to the end of the page (minus 1)
++ */
++ not r6,r10
++ not r8,r4
++
++ /* remove all but the last 12 bits from the nots, and
++ * shift the result right by 3, thus making it the number
++ * of doubles to the end of the page
++ */
++ rlwinm r6,r6,29,23,31
++ rlwinm r8,r8,29,23,31
++
++ /* align r4 to a doubleword boundary, and load the
++ * first double of r10 (prologue for loop)
++ */
++ rlwinm r4,r4,0,0,28
++ evldd r5, 0(r10)
++
++ /* subtract the distances from each other, setting the
++ * condition code so we know which was shorter.
++ * And load the first word of r4 into a doubleword
++ */
++ subfc. r0,r6,r8
++ evldd r7, 0(r4)
++
++ /* zero out a reg for comparison (the result of the final
++ * and is nonzero for any word with a null byte)
++ * Save off a register for merging into
++ */
++ evsplati r0,0
++ evstdd r15,16(r1)
++
++ /* And start looking for nulls in r10 */
++ evsubfw r3, r12, r5
++
++ /* Select the shortest distance to the page */
++ isellt r14,r8,r6
++
++ /* And continue looking for nulls */
++ evandc r9, r11, r5
++
++ /* We want to jump out early (before we load the next
++ * double) if this is the last double.
++ * Then update r14 so that it reflects the number of
++ * doublewords that will have been loaded by the end
++ * of the first iteration of the loop (4)
++ */
++ cmpwi cr1,r14,1
++
++ addic. r14,r14,-4
++
++ /* Can't do this load until we know the previous one is
++ * free of null bytes
++ */
++ blt cr1,L(unaligned_last_was_first)
++ evldd r8, 8(r4)
++
++ /* Align the first double, and branch over the loop if
++ * we are less than 3 doubles from the end of the page
++ */
++ evmergelohi r15,r7,r8
++ blt L(unaligned_double_loop_end)
++
++ /* And away we go! Loop as many times as we can before
++ * we hit the end of the page. This code is scheduled
++ * such that there are no stalls in execution. Because
++ * loads take 3 cycles, there could be stalls in
++ * completion.
++ * NOTE TO SELF:
++ *
++ * Issues:
++ * 1) evmergelohi must be before any connected branch.
++ * the exit cases (found_null1, etc) assume that the
++ * values are all properly lined up.
++ * 2) null case must branch before diff case. diff
++ * assumes it to be so
++ * 3) When near the end of the page, have to make sure
++ * that the hi word of r10, and the lo word of r4
++ * don't have any nulls before grabbing the next double
++ * for r4
++ */
++L(unaligned_loop):
++ evcmpeq 6, r5,r15
++ evldd r6, 8(r10)
++ evand r9,r9,r3
++ addi r10,r10,16
++ evcmpgtu 1,r9, r0
++ evldd r7, 16(r4)
++ evsubfw r3,r12,r6
++ bt 6,L(found_unaligned_null1)
++ evandc r9,r11,r6
++ bf 27,L(found_unaligned1)
++ evmergelohi r15,r8,r7
++ addi r4,r4,16
++ evcmpeq 7,r6,r15
++ evldd r5,0(r10)
++ evand r9,r9,r3
++ addic. r14,r14,-2
++ evcmpgtu 5,r9, r0
++ evldd r8,8(r4)
++ evsubfw r3,r12,r5
++ bt 22,L(found_unaligned_null2)
++ evandc r9,r11,r5
++ bf 31,L(found_unaligned2)
++ evmergelohi r15,r7,r8
++ bge L(unaligned_loop)
++
++ /* we exited the loop, we must be at the end of a page.
++ * Finish the last one, and then see if we are done or
++ * not.
++ */
++L(unaligned_double_loop_end):
++ evcmpeq 6, r5, r15
++ evand r9,r9,r3
++ evcmpgtu 1, r9, r0
++ addi r10,r10,8
++ bt 6, L(found_unaligned_null1)
++ addi r4,r4,8
++ bf 27, L(found_unaligned1)
++
++ /* We need to check the next doubleword, too. It may be
++ * in the next page, but it may be the last one in this
++ * page.
++ */
++L(unaligned_find_page_end):
++ evldd r6, 0(r10)
++ addi r10,r10,8
++ evsubfw r3, r12, r6
++ evandc r9, r11, r6
++ evand r9, r9, r3
++ evcmpgtu 5, r9, r0
++ bt 20,L(found_early_null2)
++
++ /* Check r8 */
++ evsubfw r3, r12,r8
++ evandc r9, r11,r8
++ evand r9,r9,r3
++ evcmpgtu 1,r9,r0
++ bt 6,L(found_early_null2)
++ evldd r7, 8(r4)
++ addi r4,r4,8
++ evmergelohi r15,r8,r7
++ evcmpeq 7, r6, r15
++ bt 22, L(found_unaligned_null2)
++ bf 31, L(found_unaligned2)
++
++
++ /* At this point, we will have crossed a page boundary in
++ * one of the strings safely. However, the other string
++ * could be near the end of the page. So we calculate
++ * which string is closest to the end of the page again,
++ * and redo the end of page code if it is less than 3
++ * doublewords from the end.
++ */
++L(unaligned_find_next_page):
++ not r6,r10
++ not r8,r4
++ rlwinm r6,r6,29,23,31
++ rlwinm r8,r8,29,23,31
++ subfc. r0,r6,r8
++ evldd r5, 0(r10)
++ evsplati r0,0
++ isellt r14,r8,r6
++ cmpwi cr1,r14,1
++ evsubfw r3, r12, r5
++ addic. r14,r14,-3
++ evandc r9, r11, r5
++ blt cr1,L(unaligned_last_was_first)
++ evldd r8, 8(r4)
++ evmergelohi r15,r7,r8
++ blt L(unaligned_double_loop_end)
++ b L(unaligned_loop)
++
++/* The end of the page happened so early, we couldn't load more
++ * than one doubleword safely.
++ * We need to make sure both CURRENTLY LOADED doublewords are
++ * null-free, since either one could be the one at the end of the
++ * page.
++ */
++L(unaligned_last_was_first):
++ evand r9,r9,r3
++ addi r10,r10,8
++ evcmpgtu 1,r9,r0
++ bt 4,L(found_early_null)
++
++ /* now check r7 */
++ evsubfw r3,r12,r7
++ evandc r9,r11,r7
++ evand r9,r3,r9
++ evcmpgtu 5,r9,r0
++ bt 22,L(found_early_null)
++
++ /* Now load the next 2 words of r4, and realign the
++ * data to r10. Then branch out if any of the bytes
++ * were null.
++ */
++ evldd r8,8(r4)
++ addi r4,r4,8
++ evmergelohi r15,r7,r8
++ evcmpeq 6,r5,r15
++ bt 6,L(found_unaligned_null1)
++ bf 27, L(found_unaligned1)
++
++ /* unaligned_find_next_page expects the previous
++ * doubleword to be in r7, so move r8 there
++ */
++ evmr r7,r8
++
++ /* find out where the next page is */
++ b L(unaligned_find_next_page)
++
++/* We found a null in the hi word of r5, near the end of the
++ * page. r7 has the value we want to deal with, but we want
++ * the important word in A to be in the lo word. So we merge
++ */
++L(found_early_null):
++ evmergehi r5,r5,r5
++ evldd r15,16(r1)
++ b L(find_null1)
++
++L(found_early_null2):
++ evmergehi r5,r6,r6
++ evldd r15,16(r1)
++ evmr r7,r8
++ b L(find_null1)
++
++L(unaligned_compare):
++ lbz r5, 0(r10)
++ lbz r7, 0(r4)
++ lwz r14, 8(r1)
++ addi r1,r1,32
++ subfc. r3, r7, r5
++ bnelr
++L(unaligned_byte_loop):
++ cmpwi cr1, r5,0
++ beq cr1, L(Null_Byte)
++ lbzu r5,1(r10)
++ lbzu r7,1(r4)
++ subfc. r3,r7,r5
++ beq L(unaligned_byte_loop)
++ blr
++L(Null_Byte):
++ li r3,0
++ blr
++
++L(found_diff_early):
++ subfe r3,r0,r0
++ not r3,r3
++ ori r3,r3,1
++ lwz r14, 8(r1)
++ addi r1,r1,32
++ blr
++
++END (strcmp)
++libc_hidden_builtin_def (strcmp)
+diff -Naur libc/sysdeps/powerpc/powerpc32/e500/strcpy.S libc-e500v2-lib/sysdeps/powerpc/powerpc32/e500/strcpy.S
+--- libc/sysdeps/powerpc/powerpc32/e500/strcpy.S 1969-12-31 18:00:00.000000000 -0600
++++ libc-e500v2-lib/sysdeps/powerpc/powerpc32/e500/strcpy.S 2014-08-01 06:45:17.052372002 -0500
+@@ -0,0 +1,665 @@
++/*------------------------------------------------------------------
++ * strcpy.S
++ *
++ * Standard strcpy function optimized for e500 using SPE
++ *
++ * Copyright (c) 2005 Freescale Semiconductor, Inc
++ * All rights reserved.
++ *
++ * Redistribution and use in source and binary forms, with or without
++ * modification, are permitted provided that the following conditions are met:
++ * * Redistributions of source code must retain the above copyright
++ * notice, this list of conditions and the following disclaimer.
++ * * Redistributions in binary form must reproduce the above copyright
++ * notice, this list of conditions and the following disclaimer in the
++ * documentation and/or other materials provided with the distribution.
++ * * Neither the name of Freescale Semiconductor nor the
++ * names of its contributors may be used to endorse or promote products
++ * derived from this software without specific prior written permission.
++ *
++ * THIS SOFTWARE IS PROVIDED BY Freescale Semiconductor ``AS IS'' AND ANY
++ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
++ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
++ * DISCLAIMED. IN NO EVENT SHALL Freescale Semiconductor BE LIABLE FOR ANY
++ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
++ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
++ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
++ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
++ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
++ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
++ *------------------------------------------------------------------
++ */
++
++#include <sysdep.h>
++
++/*------------------------------------------------------------------
++ * char * strcpy(char* dest, const char* src);
++ * Returns:
++ * dest
++ *------------------------------------------------------------------
++ */
++
++ .file "strcpy.S"
++ .section ".text"
++/* If dest and src are aligned the same wrt doublewords,
++ * or aligned the same wrt words, we copy in doublewords.
++ * Otherwise, go byte by byte.
++ */
++EALIGN (strcpy, 5, 0)
++
++ /* All of the string functions use an algorithm for null
++ * detection taken from the original libmoto:
++ *
++ * 1) load in a word
++ * 2a) subtract 0x01010101 from the word. This will cause
++ * all bytes with a null to be 0xff (unless it is right
++ * before another null, in which case it will be 0xfe)
++ *
++ * 3b) AND 0x80808080 with the complement of the word.
++ * The resulting bytes will only have their high bit set
++ * if the corresponding bit was 0 in the original word
++ *
++ * So now we (basically) have a word with the high bit of
++ * any byte set which was between 0x81 and 0xff, or 0x00.
++ * We also have a mask which will only select the high
++ * bits of bytes which were between 0x00 and 0x7f. There
++ * is only one overlap: a null byte (0x00). If we now:
++ *
++ * 4) and the two results
++ *
++ * The result will only have 1s in the high bits of bytes
++ * which had nulls. With one exception. If there is a
++ * byte with 0x01 before a byte with 0x00, then that
++ * byte, too, will have a 1 in the high bit. However,
++ * since this only happens when a byte with 0x00 occurs
++ * in the word, this technique is useful for detecting if
++ * there are any nulls in the word.
++ */
++
++ /* r3 needs to return the original dest, but r3 is used,
++ * so move r3 into the upper half of r10
++ */
++ evmergelo r10,r3,r3
++
++ /* Load constant 0x01010101 */
++ lis r11,0x0101
++ ori r11,r11,0x0101
++
++ /* Load doubleword constant 0x01010101 */
++ evmergelo r12,r11,r11
++
++ /* Determine whether r4 and r10 are doubleword-aligned */
++ or r0,r10,r4
++
++ /* Load doubleword constant 0x80808080 */
++ evslwi r11,r12,7
++
++ /* Save the stack, cuz we need to save a reg */
++ stwu r1, -16(r1)
++
++ andi. r0,r0,0x7
++
++ /* save r14. This is cheaper than bdnz */
++ stw r14, 8(r1)
++
++ beq L(Aligned_Double)
++
++/* load the first words (on word boundaries) and process them,
++ * setting bits preceding the first byte to 1.
++ */
++
++ /* If r10 and r4 are off by 4, we can handle that almost
++ * as fast as in the fully-aligned case, so we want to go
++ * there as soon as possible. If this is true, then
++ * r0 will be 4. The Unaligned_Double loop needs
++ * r10 to be double-aligned, so we move bit 29 of r10
++ * into bit 29 of r0, and if r0 is then zero,
++ * r10 is already properly aligned, and we jump to
++ * Unaligned_Double.
++ */
++ rlwimi. r0,r10,0,29,29
++ not r6, r10
++ xor r0,r10,r4
++ beq L(Unaligned_Double)
++
++ /* If the last two bits of r4 and r10 are
++ * different, then it is not efficient to copy
++ * them in chunks larger than a byte
++ */
++ andi. r14,r0,0x3
++ addi r6, r6, 1
++ bne L(unaligned_copy)
++
++ /* Check for double alignment */
++ rlwinm r0,r0,0,29,29
++
++ /* Move the alignment amount into the CR */
++ mtcrf 0x1, r6
++
++ /* Set the condition code for double alignment */
++ cmpwi 5, r0,0
++
++ /* Process a byte if r10 is only byte-aligned */
++ bf 31, L(try_halfword)
++ lbz r5, 0(r4)
++ addi r4,r4,1
++ cmpwi r5, 0
++ stb r5, 0(r10)
++ addi r10,r10,1
++ beq L(aligned_end1)
++
++ /* Process 2 bytes if r10 is only halfword aligned */
++L(try_halfword):
++ bf 30, L(try_word)
++ lbz r5, 0(r4)
++ lbz r6, 1(r4)
++ addi r4,r4,2
++ cmpwi r5, 0
++ stb r5, 0(r10)
++ beq L(aligned_end1)
++ cmpwi r6, 0
++ stb r6, 1(r10)
++ beq L(aligned_end1)
++ addi r10,r10,2
++
++ /* process another word if necessary to align to a doubleword
++ * boundary.
++ */
++L(try_word):
++ bf 29, L(Check_Aligned_Double)
++
++ /* Load the next word, to align r10 to a double word */
++ lwz r5, 0(r4)
++ addi r4,r4,4
++
++ /* Process it */
++ subfc r3, r12, r5
++ andc r9, r11, r5
++ and. r9, r3, r9
++
++ /* Need to have r5 in r0, because find_null1 assumes
++ * that r0 will have the word in which the first null was
++ * found. (found_null1 assumes that condition codes have
++ * been set by evcmpgtu, so we have to jump into that
++ * block of code after the logic which figures out the
++ * first word has been executed)
++ */
++ mr r0,r5
++ bne L(find_null1)
++
++ /* Store the word */
++ stw r5,0(r10)
++ addi r10, r10, 4
++
++ /* r10 is now doubleword aligned, but both strings may
++ * not be doubleword aligned. We set a bit earlier for
++ * this, so branch if it was set.
++ */
++L(Check_Aligned_Double):
++ bne 5, L(Unaligned_Double)
++
++ /* loop through 2 doublewords at once in this page, until one of
++ * these happens:
++ * 1) A null byte is found in r4
++ * 2) the end of the page is reached
++ *
++ * If 2 happens, then we finish processing the last doubleword in
++ * the page, and if it checks out, we jump to the next one. The
++ * hope is that no small strings are going to cross page
++ * boundaries. For large strings, the hit should be minimal
++ *
++ * If 1 happens, some extra checking goes on to see whether the
++ * strings are the same or not.
++ *
++ * The primary loop is capable of 2 IPC (it issues
++ * 2/cycle, but completion may stall). If it gets 2 IPC,
++ * then it is doing a load or store every other cycle.
++ * This means that a doubleword is stored every fourth
++ * cycle. So the code will approach copying 2
++ * bytes/cycle. This is 2x what the optimized scalar
++ * code can do.
++ */
++L(Aligned_Double):
++ /* Start figuring out how far to the next page */
++ not r8,r4
++
++ evldd r5, 0(r4)
++
++ /* zero out a reg for comparison (the result of the final
++ * and is nonzero for any word with a null byte)
++ */
++ evsplati r0,0
++
++ rlwinm r8,r8,29,23,31
++
++ evsubfw r3, r12, r5
++
++ /* We will load 2 doublewords, but it could be that the
++ * first null is in the the first double.
++ * If this double is also the last in the page, then
++ * loading the next double could cause a segmentation
++ * fault. So we check to see if this is the last, and if
++ * so we jump to a special case.
++ */
++ addic. r14, r8,-1
++ blt L(last_double_was_first)
++
++ evldd r6, 8(r4)
++ evandc r9, r11, r5
++
++ evand r9,r9,r3
++ addic. r14,r14,-5
++
++ evcmpgtu 1,r9,r0
++ evsubfw r3,r12, r6
++
++ blt L(aligned_double_loop_end)
++ /* The loop */
++L(aligned_double_loop):
++ evandc r9, r11, r6
++ evldd r7, 16(r4)
++ evand r9,r9,r3
++ bt 6, L(found_null1)
++ evcmpgtu 5, r9, r0
++ evstdd r5,0(r10)
++ evsubfw r3, r12, r7
++ evldd r8, 24(r4)
++ evandc r9, r11, r7
++ bt 22, L(found_null2)
++ evand r9, r9, r3
++ evstdd r6,8(r10)
++ evcmpgtu 6, r9, r0
++ addic. r14,r14,-4
++ evsubfw r3,r12, r8
++ addi r4,r4,32
++ evandc r9, r11, r8
++ evldd r5, 0(r4)
++ evand r9, r9, r3
++ bt 26, L(found_null3)
++ evcmpgtu 7, r9, r0
++ evstdd r7,16(r10)
++ evsubfw r3,r12, r5
++ evldd r6, 8(r4)
++ evandc r9, r11, r5
++ bt 30, L(found_null4)
++ evand r9, r9, r3
++ evstdd r8,24(r10)
++ evcmpgtu 1, r9, r0
++ addi r10,r10,32
++ evsubfw r3,r12, r6
++ bge L(aligned_double_loop)
++
++ /* we exited the loop, we must be at the end of a page.
++ * Finish the last one, and then see if we are done or
++ * not.
++ */
++L(aligned_double_loop_end):
++ bt 6, L(found_null1)
++ evstdd r5, 0(r10)
++ evandc r9,r11,r6
++ evand r9,r9,r3
++ evcmpgtu 5,r9,r0
++ bt 22, L(found_null2)
++ evstdd r6, 8(r10)
++
++ addi r4,r4,16
++ addi r10,r10,16
++
++ andi. r3,r4,0xFFF
++ beq L(start_new_loop)
++
++L(find_page_end):
++ evldd r5,0(r4)
++ addi r4,r4,8
++ evsubfw r3, r12, r5
++ evandc r9, r11, r5
++ evand r9, r3, r9
++ andi. r3,r4,0xFFF
++ evcmpgtu 1, r9, r0
++ bt 6, L(found_null1)
++ evstdd r5, 0(r10)
++ addi r10,r10,8
++ bne L(find_page_end)
++
++L(start_new_loop):
++ /* It is now safe to proceed to the next page. load the
++ * r14 with the number of doublewords in a page
++ * (-6 to account for the first loop)
++ */
++ evldd r5, 0(r4)
++ li r14, 505
++
++ /* Now we set up for the beginning of the loop */
++ evldd r6, 8(r4)
++ evsubfw r3, r12, r5
++ evandc r9, r11, r5
++ evand r9,r9,r3
++ evcmpgtu 1,r9,r0
++ evsubfw r3,r12,r6
++ b L(aligned_double_loop)
++
++L(last_double_was_first):
++ addi r4,r4,8
++ evandc r9,r11,r5
++ evand r9,r9,r3
++ evcmpgtu 1,r9,r0
++ bt 6, L(found_null1)
++ evstdd r5,0(r10)
++ addi r10,r10,8
++ b L(start_new_loop)
++
++
++ /* The first doubleword had a null byte */
++L(found_null1):
++ /* If there was a null in the hi word, move that word
++ * down into the lo word
++ */
++ evmergehi r0, r5, r5
++ bt 4, L(find_null1)
++ stw r0,0(r10)
++ addi r10,r10,4
++ mr r0,r5
++L(find_null1):
++ rlwinm. r11,r0,8,24,31
++ stb r11, 0(r10)
++ beq L(aligned_end1)
++ rlwinm. r11,r0,16,24,31
++ stb r11, 1(r10)
++ beq L(aligned_end1)
++ rlwinm. r11,r0,24,24,31
++ stb r11, 2(r10)
++ beq L(aligned_end1)
++ stb r0, 3(r10)
++
++L(aligned_end1):
++ evmergehi r3,r10,r10
++ lwz r14, 8(r1)
++ addi r1,r1,16
++ blr
++
++ /* The second doubleword had a null byte */
++L(found_null2):
++ /* If there was a null in the hi word, move that word
++ * down into the lo word
++ */
++ evmergehi r0, r6, r6
++ bt 20, L(find_null2)
++ stw r0,8(r10)
++ addi r10,r10,4
++ mr r0,r6
++L(find_null2):
++ rlwinm. r11,r0,8,24,31
++ stb r11, 8(r10)
++ beq L(aligned_end2)
++ rlwinm. r11,r0,16,24,31
++ stb r11, 9(r10)
++ beq L(aligned_end2)
++ rlwinm. r11,r0,24,24,31
++ stb r11, 10(r10)
++ beq L(aligned_end2)
++ stb r0, 11(r10)
++
++L(aligned_end2):
++ evmergehi r3,r10,r10
++ lwz r14, 8(r1)
++ addi r1,r1,16
++ blr
++
++ /* The third doubleword had a null byte */
++L(found_null3):
++ /* If there was a null in the hi word, move that word
++ * down into the lo word
++ */
++ evmergehi r0, r7, r7
++ bt 24, L(find_null3)
++ stw r0,16(r10)
++ addi r10,r10,4
++ mr r0,r7
++L(find_null3):
++ rlwinm. r11,r0,8,24,31
++ stb r11,16(r10)
++ beq L(aligned_shift3)
++ rlwinm. r11,r0,16,24,31
++ stb r11,17(r10)
++ beq L(aligned_shift3)
++ rlwinm. r11,r0,24,24,31
++ stb r11,18(r10)
++ beq L(aligned_shift3)
++ stb r0,19(r10)
++
++L(aligned_shift3):
++ evmergehi r3,r10,r10
++ lwz r14, 8(r1)
++ addi r1,r1,16
++ blr
++
++
++ /* The fourth doubleword had a null byte */
++L(found_null4):
++ /* If there was a null in the hi word, move that word
++ * down into the lo word
++ */
++ evmergehi r0, r8, r8
++ bt 28, L(find_null4)
++ stw r0,24(r10)
++ addi r10,r10,4
++ mr r0,r8
++L(find_null4):
++ rlwinm. r11,r0,8,24,31
++ stb r11,24(r10)
++ beq L(aligned_shift4)
++ rlwinm. r11,r0,16,24,31
++ stb r11,25(r10)
++ beq L(aligned_shift4)
++ rlwinm. r11,r0,24,24,31
++ stb r11,26(r10)
++ beq L(aligned_shift4)
++ stb r0,27(r10)
++
++L(aligned_shift4):
++ evmergehi r3,r10,r10
++ lwz r14, 8(r1)
++ addi r1,r1,16
++ blr
++
++L(found_unaligned_null1):
++ evmergehi r0,r7,r7
++ bt 24, L(find_unaligned_null1)
++ stw r0,0(r10)
++ addi r10,r10,4
++ mr r0,r7
++L(find_unaligned_null1):
++ rlwinm. r11,r0,8,24,31
++ stb r11, 0(r10)
++ beq L(unaligned_end1)
++ rlwinm. r11,r0,16,24,31
++ stb r11, 1(r10)
++ beq L(unaligned_end1)
++ rlwinm. r11,r0,24,24,31
++ stb r11, 2(r10)
++ beq L(unaligned_end1)
++ stb r0, 3(r10)
++
++L(unaligned_end1):
++ evmergehi r3,r10,r10
++ lwz r14, 8(r1)
++ addi r1,r1,16
++ blr
++
++L(found_unaligned_null2):
++ evmergehi r0,r8,r8
++ bt 28, L(find_unaligned_null2)
++ stw r0,8(r10)
++ addi r10,r10,4
++ mr r0,r8
++L(find_unaligned_null2):
++ rlwinm. r11,r0,8,24,31
++ stb r11, 8(r10)
++ beq L(unaligned_end2)
++ rlwinm. r11,r0,16,24,31
++ stb r11, 9(r10)
++ beq L(unaligned_end2)
++ rlwinm. r11,r0,24,24,31
++ stb r11, 10(r10)
++ beq L(unaligned_end2)
++ stb r0, 11(r10)
++
++L(unaligned_end2):
++ evmergehi r3,r10,r10
++ lwz r14, 8(r1)
++ addi r1,r1,16
++ blr
++
++L(Unaligned_Double):
++ /* Align r4 to doubleword.
++ * Get number of bytes before end of page
++ */
++ not r8,r4
++ rlwinm r4,r4,0,0,28
++
++ /* Load the first doubleword (only half of which is good) */
++ rlwinm r8,r8,29,23,31
++ evldd r6,0(r4)
++
++ /* We will load 2 doublewords, but it could be that the
++ * first null is in the lower word of the first double.
++ * If this double is also the last in the page, then
++ * loading the next double could cause a segmentation
++ * fault. So we check to see if the word has any
++ * nulls, and if so, we jump to a special case
++ * And zero a register for comparison
++ */
++ addic. r14,r8,-1
++ evsplati r0,0
++ addi r10,r10,-16 /* predecrement r10 */
++ blt L(unaligned_first_was_last)
++
++ evldd r5,8(r4)
++ addic. r14,r14,-5
++ evmergelohi r7,r6,r5
++ evsubfw r3,r12,r7
++ blt L(unaligned_loop_end)
++
++L(unaligned_double_loop):
++ evandc r9,r11,r7
++ evldd r6,16(r4)
++ evand r9,r9,r3
++ addi r4,r4,16
++ evcmpgtu 6,r9,r0
++ addi r10,r10,16
++ evmergelohi r8,r5,r6
++ bt 26, L(found_unaligned_null1)
++ evsubfw r3,r12,r8
++ evstdd r7,0(r10)
++ evandc r9,r11,r8
++ evldd r5,8(r4)
++ evand r9,r9,r3
++ addic. r14,r14,-4
++ evcmpgtu 7,r9,r0
++ evmergelohi r7,r6,r5
++ bt 30,L(found_unaligned_null2)
++ evsubfw r3,r12,r7
++ evstdd r8,8(r10)
++
++ evandc r9,r11,r7
++ evldd r6,16(r4)
++ evand r9,r9,r3
++ addi r4,r4,16
++ evcmpgtu 6,r9,r0
++ addi r10,r10,16
++ evmergelohi r8,r5,r6
++ bt 26,L(found_unaligned_null1)
++ evsubfw r3,r12,r8
++ evstdd r7,0(r10)
++ evandc r9,r11,r8
++ evldd r5,8(r4)
++ evand r9,r9,r3
++ evcmpgtu 7,r9,r0
++ bt 30,L(found_unaligned_null2)
++ evmergelohi r7,r6,r5
++ evstdd r8,8(r10)
++ evsubfw r3,r12,r7
++ bge L(unaligned_double_loop)
++
++/* Hit the end of the page, finish up the epilog of the loop, and
++ * then run the process without any special scheduling to get
++ * into the next page
++ */
++L(unaligned_loop_end):
++ evandc r9,r11,r7
++ addi r4,r4,16
++ evand r9,r9,r3
++ addi r10,r10,16
++ evcmpgtu 6,r9,r0
++ bt 26,L(found_unaligned_null1)
++ evstdd r7,0(r10)
++ addi r10,r10,8
++
++/* At this point, r4 and r10 point to the next place to load
++ * and store. We move forward, one word at a time, until r4
++ * has passed over into a new page.
++ */
++L(unaligned_find_next_page):
++ /* Check this word for null bytes */
++ subf r3,r12,r5
++ andc r9,r11,r5
++ and. r9,r9,r3
++ mr r0,r5
++ bne L(find_null1)
++ stw r5,0(r10)
++ addi r10,r10,4
++
++ lwz r0,0(r4)
++ addi r4,r4,4
++ subf r3,r12,r0
++ andc r9,r11,r0
++ and. r9,r9,r3
++ bne L(find_null1)
++
++ /* Calculate if r4 is on a new page */
++ andi. r6,r4,0x0f00
++
++ /* Store the 2nd word */
++ stw r0,0(r10)
++ addi r10,r10,4
++
++ beq L(Unaligned_Double)
++ lwz r5,0(r4)
++ addi r4,r4,4
++ b L(unaligned_find_next_page)
++
++L(unaligned_first_was_last):
++ addi r10,r10,16
++ addi r4,r4,8
++ mr r5,r6
++ b L(unaligned_find_next_page)
++
++L(unaligned_copy):
++ lbz r5, 0(r4)
++ addi r10, r10, -1
++ cmpwi cr1,r5,0
++ beq cr1,L(Null_Byte1)
++L(unaligned_byte_loop):
++ lbzu r6,1(r4)
++ stbu r5,1(r10)
++ cmpwi cr1,r6,0
++ beq cr1,L(Null_Byte2)
++ lbzu r5,1(r4)
++ stbu r6,1(r10)
++ cmpwi cr1,r5,0
++ bne cr1, L(unaligned_byte_loop)
++
++L(Null_Byte1):
++ stb r5,1(r10)
++ b L(Byte_End)
++L(Null_Byte2):
++ stb r6, 1(r10)
++
++L(Byte_End):
++ /* r3 still has original r10 value */
++ lwz r14, 8(r1)
++ addi r1,r1,16
++ blr
++
++END (strcpy)
++libc_hidden_builtin_def (strcpy)
+diff -Naur libc/sysdeps/powerpc/powerpc32/e500/strlen.S libc-e500v2-lib/sysdeps/powerpc/powerpc32/e500/strlen.S
+--- libc/sysdeps/powerpc/powerpc32/e500/strlen.S 1969-12-31 18:00:00.000000000 -0600
++++ libc-e500v2-lib/sysdeps/powerpc/powerpc32/e500/strlen.S 2014-08-01 06:45:39.755371998 -0500
+@@ -0,0 +1,342 @@
++/*------------------------------------------------------------------
++ * strlen.S
++ *
++ * Standard strlen function optimized for e500 using SPE
++ *
++ * Copyright (c) 2005 Freescale Semiconductor, Inc
++ * All rights reserved.
++ *
++ * Redistribution and use in source and binary forms, with or without
++ * modification, are permitted provided that the following conditions are met:
++ * * Redistributions of source code must retain the above copyright
++ * notice, this list of conditions and the following disclaimer.
++ * * Redistributions in binary form must reproduce the above copyright
++ * notice, this list of conditions and the following disclaimer in the
++ * documentation and/or other materials provided with the distribution.
++ * * Neither the name of Freescale Semiconductor nor the
++ * names of its contributors may be used to endorse or promote products
++ * derived from this software without specific prior written permission.
++ *
++ * THIS SOFTWARE IS PROVIDED BY Freescale Semiconductor ``AS IS'' AND ANY
++ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
++ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
++ * DISCLAIMED. IN NO EVENT SHALL Freescale Semiconductor BE LIABLE FOR ANY
++ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
++ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
++ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
++ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
++ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
++ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
++ *------------------------------------------------------------------
++ */
++
++#include <sysdep.h>
++
++/*------------------------------------------------------------------
++ * int strlen(const char *src)
++ *
++ * Returns:
++ * length of string up to first null byte
++ *------------------------------------------------------------------
++ */
++
++ .file "strlen.S"
++ .section ".text"
++ /* check enough bytes to align the src pointer to a
++ * doubleword boundary, and then run through the bytes
++ * until a null is detected, adding up the length as we
++ * go.
++ */
++EALIGN (strlen, 5, 0)
++
++ /* All of the string functions use an algorithm for null
++ * detection taken from the original libmoto:
++ *
++ * 1) load in a word
++ * 2a) subtract 0x01010101 from the word. This will cause
++ * all bytes with a null to be 0xff (unless it is right
++ * before another null, in which case it will be 0xfe)
++ *
++ * 3b) AND 0x80808080 with the complement of the word.
++ * The resulting bytes will only have their high bit set
++ * if the corresponding bit was 0 in the original word
++ *
++ * So now we (basically) have a word with the high bit of
++ * any byte set which was between 0x81 and 0xff, or 0x00.
++ * We also have a mask which will only select the high
++ * bits of bytes which were between 0x00 and 0x7f. There
++ * is only one overlap: a null byte (0x00). If we now:
++ *
++ * 4) and the two results
++ *
++ * The result will only have 1s in the high bits of bytes
++ * which had nulls. With one exception. If there is a
++ * byte with 0x01 before a byte with 0x00, then that
++ * byte, too, will have a 1 in the high bit. However,
++ * since this only happens when a byte with 0x00 occurs
++ * in the word, this technique is useful for detecting if
++ * there are any nulls in the word.
++ */
++
++ /* Load constant 0x01010101 */
++ lis r11,0x0101
++ ori r11,r11,0x0101
++
++ /* r3 will be used for returning length, so lets move src
++ * out of there to r10
++ */
++ mr r10,r3
++
++ /* Get src's alignment (within a doubleword), and check
++ * if it's zero
++ */
++ andi. r3,r3,0x7
++
++ /* Load doubleword constant 0x01010101 */
++ evmergelo r12,r11,r11
++
++ /* Clear r0 out */
++ evsplati r0,0
++
++ /* get (the word alignment of r10) * 8 to shift a mask by the
++ * number of bytes which are unused by r10
++ * This is: clrlslwi r6,r10,30,3
++ */
++ rlwinm r6, r10, 3, 27,28
++
++ /* Load doubleword constant 0x80808080 */
++ evslwi r11,r12,7
++
++ /* Skip out now if r10 was aligned. */
++ beq L(Aligned_Double)
++
++ subfic r6, r6, 32
++
++ /* start the mask with all Fs */
++ li r5, -1
++
++ /* Shift r8 by r6 to mask off preceding bytes */
++ slw r8, r5, r6
++
++ /* We want the result of r3+r10 to be a
++ * doubleword-aligned value, so r3 will be -1*(r10)
++ * alignment)
++ */
++ neg r3,r3
++
++/* load the first words (on word boundaries) and process them,
++ * setting bits preceding the first byte to 1.
++ */
++
++ /* Grab the first doubleword of r10 */
++ evlddx r4,r3,r10
++
++ /* The loop is usually ahead by 16, and if we detect a
++ * null, the exit code assumes that r3 is ahead by
++ * 16, so we add 16 now, and can subtract 8 if there was
++ * no null
++ */
++ addi r3,r3,16
++
++ mtcrf 0x01,r10
++
++ evmergelo r0,r8,r0
++ cror 28,29,29
++
++ evmergelo r5,r5,r8
++
++ evsel r8,r5,r0,cr7
++
++ evsplati r0,0
++
++ /* Set the unwanted bytes of the source */
++ evor r4, r4, r8
++
++ /* Process fist doubleword with fun algorithm */
++ evsubfw r7, r12, r4
++ evandc r9, r11, r4
++ evand r9, r7, r9
++ evcmpgtu 1,r9,r0
++
++ /* Skip out if there was a null */
++ bt 6, L(found_null1)
++
++ /* There was no null; correct the length */
++ addi r3,r3,-8
++
++ /* loop through 2 doublewords at once in this page, until one of
++ * these happens:
++ * 1) A null byte is found in src
++ * 2) the end of the page is reached
++ *
++ * If 2 happens, then we finish processing the last doubleword in
++ * the page, and if it checks out, we jump to the next one. The
++ * hope is that no small strings are going to cross page
++ * boundaries. For large strings, the hit should be minimal
++ */
++
++ /* The main loop is unrolled, and software pipelined to
++ * get as close to 2 IPC as possible. This means it has
++ * a prolog and epilog that need to be executed. Prolog
++ * is:
++ * load, subtract
++ */
++L(Aligned_Double):
++ /* Start figuring out how far to the next page */
++ not r8,r10
++ evlddx r4,r3,r10
++
++ /* Find the distance (in doublewords) from r10 to the end
++ * of the page
++ */
++ rlwinm r8,r8,29,23,31
++
++ /* Find out if this is the last double on the page */
++ addic. r6, r8,-1
++ addi r3,r3,8 /* increment the length */
++
++ /* start calculating now, since the loop needs this at
++ * the beginning.
++ */
++ evsubfw r7, r12, r4
++ beq L(aligned_double_loop_end)
++
++ /* decrement the counter to account for the first
++ * iteration of the loop, and skip to the end if it turns
++ * out we don't have enough doubles left for 1 iter.
++ */
++ addic. r6,r6,-2
++ blt L(aligned_double_loop_end)
++ /* The loop */
++L(aligned_double_loop):
++ evandc r9, r11, r4
++ evlddx r5,r3,r10
++ evand r9,r9,r7
++ addi r3,r3,8
++ evcmpgtu 1, r9, r0
++ addic. r6,r6,-2
++ evsubfw r7,r12,r5
++ bt 6, L(found_null1)
++ evandc r9, r11, r5
++ evlddx r4,r3,r10
++ evand r9, r9, r7
++ addi r3,r3,8
++ evcmpgtu 5, r9, r0
++ bt 22, L(found_null2)
++ evsubfw r7,r12, r4
++ bge L(aligned_double_loop)
++
++ /* we exited the loop, we must be at the end of a page.
++ * Finish the last one, and then see if we are done or
++ * not.
++ */
++L(aligned_double_loop_end):
++ evandc r9,r11,r4
++ evand r9,r9,r7
++ evcmpgtu 1,r9,r0
++
++ /* r3 has to be ahead by 16 in found_null, and is
++ * only ahead by 8 right now, so we add 8 here
++ */
++ addi r3,r3,8
++ bt 6, L(found_null1)
++
++ /* However, r3 needed to be only 8 ahead to load the
++ * next doubleword, so take 8 away again
++ */
++ addi r3,r3,-8
++
++ /* To make things nice, we finish off the remaining
++ * doublewords here, so that the next loop has exactly
++ * 512 iterations
++ */
++ addi r7, r10, r3
++ andi. r7,r7,0xFFF
++ beq L(start_new_loop)
++L(find_page_end):
++ evlddx r4,r3,r10
++ addi r3,r3,16 /* overadjust */
++ evsubfw r7, r12, r4
++ evandc r9, r11, r4
++ evand r9, r7, r9
++ evcmpgtu 1, r9, r0
++ bt 6, L(found_null1)
++ addi r3,r3,-8 /* readjust */
++ addi r7,r10,r3
++ andi. r7,r7,0xFFF
++ bne L(find_page_end)
++
++L(start_new_loop):
++ /* It is now safe to proceed to the next page. load the
++ * counter with the number of doublewords in a page
++ * (minus 4 to account for the first iteration)
++ */
++ evlddx r4,r3,r10
++ li r6, 508
++
++ evsubfw r7, r12, r4
++ addi r3,r3,8
++ b L(aligned_double_loop)
++
++L(last_double_was_first):
++ evandc r9,r11,r4
++ evand r9,r9,r7
++ evcmpgtu 1,r9,r0
++ addi r3,r3,8 /* adjust */
++ bt 6,L(found_null1)
++ addi r3,r3,-8 /*readjust */
++ b L(start_new_loop)
++
++
++ /* The first doubleword had a null byte */
++L(found_null1):
++ /* Compensate for the fact that r3 is 16 ahead */
++ addi r3,r3,-12
++
++ /* If there was a null in the hi word, move that word
++ * down into the lo word, and subtract 4 from r3
++ */
++ bf 4, L(find_null1)
++ evmergehi r4, r4, r4
++ addi r3,r3,-4
++L(find_null1):
++ rlwinm. r11,r4,0,0,7
++ beq L(finish1)
++ addi r3,r3,1
++ rlwinm. r11,r4,0,8,15
++ beq L(finish1)
++ addi r3,r3,1
++ rlwinm. r11,r4,0,16,23
++ beq L(finish1)
++ addi r3,r3,1
++
++L(finish1):
++ blr
++
++ /* The second doubleword had a null byte */
++L(found_null2):
++ /* Compensate for the fact that r3 is 16 ahead */
++ addi r3,r3,-12
++
++ /* If there was a null in the hi word, move that word
++ * down into the lo word, and subtract 4 from r3
++ */
++ bf 20, L(find_null2)
++ evmergehi r5, r5, r5
++ addi r3,r3,-4
++L(find_null2):
++ rlwinm. r11,r5,0,0,7
++ beq L(finish2)
++ addi r3,r3,1
++ rlwinm. r11,r5,0,8,15
++ beq L(finish2)
++ addi r3,r3,1
++ rlwinm. r11,r5,0,16,23
++ beq L(finish2)
++ addi r3,r3,1
++
++L(finish2):
++ blr
++
++END (strlen)
++libc_hidden_builtin_def (strlen)
+diff -Naur glibc-2.20/sysdeps/powerpc/powerpc32/e500/strcmp.S glibc-2.20-stcmp/sysdeps/powerpc/powerpc32/e500/strcmp.S
+--- glibc-2.20/sysdeps/powerpc/powerpc32/e500/strcmp.S 2015-08-27 04:27:44.436000785 -0500
++++ glibc-2.20-stcmp/sysdeps/powerpc/powerpc32/e500/strcmp.S 2015-08-27 04:33:45.417000790 -0500
+@@ -618,7 +618,7 @@
+ evandc r9,r11,r7
+ evand r9,r3,r9
+ evcmpgtu 5,r9,r0
+- bt 22,L(found_early_null)
++ bt 21,L(found_early_null)
+
+ /* Now load the next 2 words of r4, and realign the
+ * data to r10. Then branch out if any of the bytes
+diff -ruN glibc-2.20-orig/sysdeps/powerpc/powerpc32/e500/memcopy.h glibc-2.20-new/sysdeps/powerpc/powerpc32/e500/memcopy.h
+--- glibc-2.20-orig/sysdeps/powerpc/powerpc32/e500/memcopy.h 1969-12-31 18:00:00.000000000 -0600
++++ glibc-2.20-new/sysdeps/powerpc/powerpc32/e500/memcopy.h 2015-09-10 11:06:13.243187000 -0500
+@@ -0,0 +1 @@
++#include "../../powerpc32/power4/memcopy.h"
diff --git a/recipes-core/glibc/glibc-fsl/0009.glibc.fsl-mcpy-e500mc-e5500-e6500.patch b/recipes-core/glibc/glibc-fsl/0009.glibc.fsl-mcpy-e500mc-e5500-e6500.patch
new file mode 100644
index 0000000..97fc606
--- /dev/null
+++ b/recipes-core/glibc/glibc-fsl/0009.glibc.fsl-mcpy-e500mc-e5500-e6500.patch
@@ -0,0 +1,1191 @@
+diff -ruN glibc-2.20-orig/sysdeps/powerpc/powerpc32/e500mc/memcopy.h glibc-2.20-memcpy-fixed/sysdeps/powerpc/powerpc32/e500mc/memcopy.h
+--- glibc-2.20-orig/sysdeps/powerpc/powerpc32/e500mc/memcopy.h 1969-12-31 18:00:00.000000000 -0600
++++ glibc-2.20-memcpy-fixed/sysdeps/powerpc/powerpc32/e500mc/memcopy.h 2015-09-23 14:26:35.273121001 -0500
+@@ -0,0 +1 @@
++#include "../../powerpc32/power4/memcopy.h"
+diff -ruN glibc-2.20-orig/sysdeps/powerpc/powerpc32/e500mc/memcpy.S glibc-2.20-memcpy-fixed/sysdeps/powerpc/powerpc32/e500mc/memcpy.S
+--- glibc-2.20-orig/sysdeps/powerpc/powerpc32/e500mc/memcpy.S 1969-12-31 18:00:00.000000000 -0600
++++ glibc-2.20-memcpy-fixed/sysdeps/powerpc/powerpc32/e500mc/memcpy.S 2015-09-23 14:26:35.275121002 -0500
+@@ -0,0 +1,285 @@
++/* Optimized memcpy implementation for e500mc PowerPC.
++ Copyright (C) 2015 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 <sysdep.h>
++
++/* __ptr_t [r3] memcpy (__ptr_t dst [r3], __ptr_t src [r4], size_t len [r5]);
++ Returns 'dst'.
++
++ r3 = destination
++ r4 = source
++ r5 = byte count
++
++ volatile fixed point registers usable:
++ r0, r3-r12
++
++ volatile floating point registers usable:
++ f0-f13. */
++
++EALIGN (memcpy, 5, 0)
++ cmplw cr0, r4, r3 /* if source==destination, return. */
++ beqlr cr0
++ /* if number of bytes is less than 8, (optimal value TBD),
++ but greater than zero copy byte-by-byte. */
++ cmplwi r5, 8
++ mr r6, r3
++ blt L(copy_bytes)
++ neg r0, r4
++ andi. r11, r0, 7
++ beq L(src_aligned)
++ /* We have to align the src pointer by r11 bytes */
++ cmplwi cr1, r11, 4
++ cmplwi cr0, r11, 1
++ bgt cr1, L(src_567)
++ ble cr0, L(src_1)
++ /* 2, 3 or 4 bytes */
++ addi r0, r11, -2
++ lhz r9, 0(r4)
++ lhzx r12, r4, r0
++ sth r9, 0(r6)
++ sthx r12, r6, r0
++ b L(src_0)
++L(src_567):
++ addi r0, r11, -4
++ lwz r9, 0(r4)
++ lwzx r12, r4, r0
++ stw r9, 0(r6)
++ stwx r12, r6, r0
++ b L(src_0)
++L(src_1):
++ lbz r0, 0(r4)
++ stb r0, 0(r6)
++L(src_0):
++ subf r5, r11, r5
++ add r4, r4, r11
++ add r6, r6, r11
++L(src_aligned):
++ cmplwi 7, r5, 63
++ ble 7, L(copy_remaining)
++ srwi r11, r5, 6 /* No of 64 byte copy count. */
++ rlwinm r5, r5, 0, 26, 31 /* remaining bytes. */
++ rlwinm. r0, r6, 0, 29, 31
++ mtctr r11
++ bne 0, L(dst_naligned)
++L(copy_dalign):
++#ifndef _SOFT_FLOAT
++ lfd 0, 0(r4)
++ lfd 1, 8(r4)
++ lfd 2, 16(r4)
++ lfd 3, 24(r4)
++ stfd 0, 0(r6)
++ stfd 1, 8(r6)
++ stfd 2, 16(r6)
++ stfd 3, 24(r6)
++ lfd 0, 32(r4)
++ lfd 1, 40(r4)
++ lfd 2, 48(r4)
++ lfd 3, 56(r4)
++ addi r4, r4, 64
++ stfd 0, 32(r6)
++ stfd 1, 40(r6)
++ stfd 2, 48(r6)
++ stfd 3, 56(r6)
++#else
++ lwz r0, 0(r4)
++ lwz r8, 4(r4)
++ lwz r9, 8(r4)
++ stw r0, 0(r6)
++ stw r8, 4(r6)
++ stw r9, 8(r6)
++ lwz r0, 12(r4)
++ lwz r8, 16(r4)
++ lwz r9, 20(r4)
++ stw r0, 12(r6)
++ stw r8, 16(r6)
++ stw r9, 20(r6)
++ lwz r0, 24(r4)
++ lwz r8, 28(r4)
++ lwz r9, 32(r4)
++ stw r0, 24(r6)
++ stw r8, 28(r6)
++ stw r9, 32(r6)
++ lwz r0, 36(r4)
++ lwz r8, 40(r4)
++ lwz r9, 44(r4)
++ stw r0, 36(r6)
++ stw r8, 40(r6)
++ stw r9, 44(r6)
++ lwz r0, 48(r4)
++ lwz r8, 52(r4)
++ lwz r9, 56(r4)
++ stw r0, 48(r6)
++ lwz r0, 60(r4)
++ addi r4, r4, 64
++ stw r8, 52(r6)
++ stw r9, 56(r6)
++ stw r0, 60(r6)
++#endif
++ addi r6, r6, 64
++ bdnz L(copy_dalign)
++L(copy_remaining):
++ srwi. r11, r5, 3 /* No of 8 byte copy count. */
++ rlwinm r5, r5, 0, 29, 31 /* remaining bytes. */
++ beq 0, L(copy_bytes)
++ mtcrf 0x01, r11
++ bf cr7*4+1, L(cp16b)
++ lwz r0, 0(r4) /* copy 32 bytes. */
++ lwz r7, 4(r4)
++ lwz r8, 8(r4)
++ lwz r9, 12(r4)
++ stw r0, 0(r6)
++ stw r7, 4(r6)
++ stw r8, 8(r6)
++ stw r9, 12(r6)
++ lwz r0, 16(r4)
++ lwz r7, 20(r4)
++ lwz r8, 24(r4)
++ lwz r9, 28(r4)
++ addi r4, r4, 32
++ stw r0, 16(r6)
++ stw r7, 20(r6)
++ stw r8, 24(r6)
++ stw r9, 28(r6)
++ addi r6, r6, 32
++L(cp16b):
++ bf cr7*4+2, L(cp8b)
++ lwz r0, 0(r4) /* copy 16 bytes. */
++ lwz r7, 4(r4)
++ lwz r8, 8(r4)
++ lwz r9, 12(r4)
++ addi r4, r4, 16
++ stw r0, 0(r6)
++ stw r7, 4(r6)
++ stw r8, 8(r6)
++ stw r9, 12(r6)
++ addi r6, r6, 16
++L(cp8b):
++ bf cr7*4+3, L(copy_bytes)
++ lwz r0, 0(r4) /* copy 8 bytes. */
++ lwz r7, 4(r4)
++ addi r4, r4, 8
++ stw r0, 0(r6)
++ stw r7, 4(r6)
++ addi r6, r6, 8
++L(copy_bytes):
++ cmplwi cr1, r5, 4
++ cmplwi cr0, r5, 1
++ bgt cr1, L(gt4b) /* nb > 4? (5, 6, 7 bytes). */
++ ble cr0, L(lt1b) /* nb <= 1? (0, 1 bytes). */
++ addi r0, r5, -2 /* 2, 3, 4 bytes. */
++ lhz r9, 0(r4)
++ lhzx r11, r4, r0
++ sth r9, 0(r6)
++ sthx r11, r6, r0
++ blr
++L(gt4b):
++ addi r0, r5, -4 /* 5, 6, 7 bytes. */
++ lwz r9, 0(r4)
++ lwzx r11, r4, r0
++ stw r9, 0(r6)
++ stwx r11, r6, r0
++ blr
++L(lt1b):
++ mtocrf 0x1, r5 /* nb == 0 ? return. */
++ bflr 31
++ lbz r0, 0(r4) /* nb == 1. */
++ stb r0, 0(r6)
++ blr
++
++L(dst_naligned):
++ rlwinm. r0, r6, 0, 30, 31
++ beq 0, L(copy_dalign4)
++L(copy_dnalign):
++ lwz r0, 0(r4) /* copy 64 bytes. */
++ lwz r8, 4(r4)
++ lwz r9, 8(r4)
++ stw r0, 0(r6)
++ stw r8, 4(r6)
++ stw r9, 8(r6)
++ lwz r0, 12(r4)
++ lwz r8, 16(r4)
++ lwz r9, 20(r4)
++ stw r0, 12(r6)
++ stw r8, 16(r6)
++ stw r9, 20(r6)
++ lwz r0, 24(r4)
++ lwz r8, 28(r4)
++ lwz r9, 32(r4)
++ stw r0, 24(r6)
++ stw r8, 28(r6)
++ stw r9, 32(r6)
++ lwz r0, 36(r4)
++ lwz r8, 40(r4)
++ lwz r9, 44(r4)
++ stw r0, 36(r6)
++ stw r8, 40(r6)
++ stw r9, 44(r6)
++ lwz r0, 48(r4)
++ lwz r8, 52(r4)
++ lwz r9, 56(r4)
++ stw r0, 48(r6)
++ lwz r0, 60(r4)
++ addi r4, r4, 64
++ stw r8, 52(r6)
++ stw r9, 56(r6)
++ stw r0, 60(r6)
++ addi r6, r6, 64
++ bdnz L(copy_dnalign)
++ b L(copy_remaining)
++
++L(copy_dalign4):
++ lwz r0, 0(r4)
++ lwz r7, 4(r4)
++ lwz r8, 8(r4)
++ lwz r9, 12(r4)
++ stw r0, 0(r6)
++ stw r7, 4(r6)
++ stw r8, 8(r6)
++ stw r9, 12(r6)
++ lwz r0, 16(r4)
++ lwz r7, 20(r4)
++ lwz r8, 24(r4)
++ lwz r9, 28(r4)
++ stw r0, 16(r6)
++ stw r7, 20(r6)
++ stw r8, 24(r6)
++ stw r9, 28(r6)
++ lwz r0, 32(r4)
++ lwz r7, 36(r4)
++ lwz r8, 40(r4)
++ lwz r9, 44(r4)
++ stw r0, 32(r6)
++ stw r7, 36(r6)
++ stw r8, 40(r6)
++ stw r9, 44(r6)
++ lwz r0, 48(r4)
++ lwz r7, 52(r4)
++ lwz r8, 56(r4)
++ lwz r9, 60(r4)
++ addi r4, r4, 64
++ stw r0, 48(r6)
++ stw r7, 52(r6)
++ stw r8, 56(r6)
++ stw r9, 60(r6)
++ addi r6, r6, 64
++ bdnz L(copy_dalign4)
++ b L(copy_remaining)
++
++END (memcpy)
++libc_hidden_builtin_def (memcpy)
+diff -ruN glibc-2.20-orig/sysdeps/powerpc/powerpc32/e5500/memcopy.h glibc-2.20-memcpy-fixed/sysdeps/powerpc/powerpc32/e5500/memcopy.h
+--- glibc-2.20-orig/sysdeps/powerpc/powerpc32/e5500/memcopy.h 1969-12-31 18:00:00.000000000 -0600
++++ glibc-2.20-memcpy-fixed/sysdeps/powerpc/powerpc32/e5500/memcopy.h 2015-09-23 14:26:35.275121002 -0500
+@@ -0,0 +1 @@
++#include "../../powerpc32/power4/memcopy.h"
+diff -ruN glibc-2.20-orig/sysdeps/powerpc/powerpc32/e5500/memcpy.S glibc-2.20-memcpy-fixed/sysdeps/powerpc/powerpc32/e5500/memcpy.S
+--- glibc-2.20-orig/sysdeps/powerpc/powerpc32/e5500/memcpy.S 1969-12-31 18:00:00.000000000 -0600
++++ glibc-2.20-memcpy-fixed/sysdeps/powerpc/powerpc32/e5500/memcpy.S 2015-09-23 14:26:35.275121002 -0500
+@@ -0,0 +1,252 @@
++/* Optimized memcpy implementation for e5500 32-bit PowerPC.
++ Copyright (C) 2015 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 <sysdep.h>
++
++/* __ptr_t [r3] memcpy (__ptr_t dst [r3], __ptr_t src [r4], size_t len [r5]);
++ Returns 'dst'.
++
++ r3 = destination
++ r4 = source
++ r5 = byte count
++
++ volatile fixed point registers usable:
++ r0, r3-r12
++
++ volatile floating point registers usable:
++ f0-f13. */
++
++EALIGN (memcpy, 5, 0)
++ cmplw cr0, r4, r3 /* if source==destination, return. */
++ beqlr cr0
++ /* if number of bytes is less than 8, (optimal value TBD),
++ but greater than zero copy byte-by-byte. */
++ cmplwi r5, 8
++ mr r6, r3
++ blt L(copy_bytes)
++ neg r0, r4
++ andi. r11, r0, 3
++ beq L(src_align4)
++ /* We have to align the src pointer by r11 bytes */
++ cmplwi cr0, r11, 1
++ ble L(src_1)
++ /* 2 or 3 bytes */
++ addi r8, r11, -2
++ lhz r9, 0(r4)
++ lhzx r12, r4, r8
++ sth r9, 0(r6)
++ sthx r12, r6, r8
++ b L(src_0)
++L(src_1):
++ lbz r8, 0(r4)
++ stb r8, 0(r6)
++L(src_0):
++ subf r5, r11, r5
++ add r4, r4, r11
++ add r6, r6, r11
++L(src_align4):
++ /* Aligned by 4, now extend it to 16 */
++ cmplwi 7, r5, 63
++ ble 7, L(copy_remaining)
++ andi. r10, r0, 15
++ beq L(src_aligned16)
++ subf. r10, r11, r10
++ beq 0, L(src_aligned16)
++ srwi r11, r10, 2
++ subf r5, r10, r5
++ mtctr r11
++L(copy_salign16):
++ lwz 0, 0(r4)
++ addi r4, r4, 4
++ stw 0, 0(r6)
++ addi r6, r6, 4
++ bdnz L(copy_salign16)
++L(src_aligned16):
++ srwi. r11, r5, 6 /* No of 64 byte copy count. */
++ beq 0, L(copy_remaining)
++ rlwinm r5, r5, 0, 26, 31 /* remaining bytes. */
++ rlwinm. r0, r6, 0, 29, 31
++ mtctr r11
++ bne 0, L(copy_dnalign)
++L(copy_dalign):
++#ifndef _SOFT_FLOAT
++ lfd 0, 0(r4) /* copy 64 bytes. */
++ lfd 1, 8(r4)
++ lfd 2, 16(r4)
++ lfd 3, 24(r4)
++ stfd 0, 0(r6)
++ stfd 1, 8(r6)
++ stfd 2, 16(r6)
++ stfd 3, 24(r6)
++ lfd 0, 32(r4)
++ lfd 1, 40(r4)
++ lfd 2, 48(r4)
++ lfd 3, 56(r4)
++ addi r4, r4, 64
++ stfd 0, 32(r6)
++ stfd 1, 40(r6)
++ stfd 2, 48(r6)
++ stfd 3, 56(r6)
++ addi r6, r6, 64
++#else
++ lwz r0, 0(r4)
++ lwz r7, 4(r4)
++ lwz r8, 8(r4)
++ lwz r9, 12(r4)
++ stw r0, 0(r6)
++ stw r7, 4(r6)
++ stw r8, 8(r6)
++ stw r9, 12(r6)
++ lwz r0, 16(r4)
++ lwz r7, 20(r4)
++ lwz r8, 24(r4)
++ lwz r9, 28(r4)
++ stw r0, 16(r6)
++ stw r7, 20(r6)
++ stw r8, 24(r6)
++ stw r9, 28(r6)
++ lwz r0, 32(r4)
++ lwz r7, 36(r4)
++ lwz r8, 40(r4)
++ lwz r9, 44(r4)
++ stw r0, 32(r6)
++ stw r7, 36(r6)
++ stw r8, 40(r6)
++ stw r9, 44(r6)
++ lwz r0, 48(r4)
++ lwz r7, 52(r4)
++ lwz r8, 56(r4)
++ lwz r9, 60(r4)
++ addi r4, r4, 64
++ stw r0, 48(r6)
++ stw r7, 52(r6)
++ stw r8, 56(r6)
++ stw r9, 60(r6)
++ addi r6, r6, 64
++#endif
++ bdnz L(copy_dalign)
++L(copy_remaining):
++ srwi. r11, r5, 3 /* No of 8 byte copy count. */
++ rlwinm r5, r5, 0, 29, 31 /* remaining bytes. */
++ beq 0, L(copy_bytes)
++ mtcrf 0x01, r11
++ bf cr7*4+1, L(cp16b)
++ lwz r0, 0(r4) /* copy 32 bytes. */
++ lwz r7, 4(r4)
++ lwz r8, 8(r4)
++ lwz r9, 12(r4)
++ stw r0, 0(r6)
++ stw r7, 4(r6)
++ stw r8, 8(r6)
++ stw r9, 12(r6)
++ lwz r0, 16(r4)
++ lwz r7, 20(r4)
++ lwz r8, 24(r4)
++ lwz r9, 28(r4)
++ addi r4, r4, 32
++ stw r0, 16(r6)
++ stw r7, 20(r6)
++ stw r8, 24(r6)
++ stw r9, 28(r6)
++ addi r6, r6, 32
++L(cp16b):
++ bf cr7*4+2, L(cp8b)
++ lwz r0, 0(r4) /* copy 16 bytes. */
++ lwz r7, 4(r4)
++ lwz r8, 8(r4)
++ lwz r9, 12(r4)
++ addi r4, r4, 16
++ stw r0, 0(r6)
++ stw r7, 4(r6)
++ stw r8, 8(r6)
++ stw r9, 12(r6)
++ addi r6, r6, 16
++L(cp8b):
++ bf cr7*4+3, L(copy_bytes)
++ lwz r0, 0(r4) /* copy 8 bytes. */
++ lwz r7, 4(r4)
++ addi r4, r4, 8
++ stw r0, 0(r6)
++ stw r7, 4(r6)
++ addi r6, r6, 8
++L(copy_bytes):
++ cmplwi cr1, r5, 4
++ cmplwi cr0, r5, 1
++ bgt cr1, L(gt4b) /* nb > 4? (5, 6, 7 bytes). */
++ ble cr0, L(lt1b) /* nb <= 1? (0, 1 bytes). */
++ addi r0, r5, -2 /* 2, 3, 4 bytes. */
++ lhz r9, 0(r4)
++ lhzx r11, r4, r0
++ sth r9, 0(r6)
++ sthx r11, r6, r0
++ blr
++L(gt4b):
++ addi r0, r5, -4 /* 5, 6, 7 bytes. */
++ lwz r9, 0(r4)
++ lwzx r11, r4, r0
++ stw r9, 0(r6)
++ stwx r11, r6, r0
++ blr
++L(lt1b):
++ mtocrf 0x1, r5 /* nb == 0 ? return. */
++ bflr 31
++ lbz r0, 0(r4) /* nb == 1. */
++ stb r0, 0(r6)
++ blr
++
++L(copy_dnalign):
++ lwz r0, 0(r4) /* copy 64 bytes. */
++ lwz r7, 4(r4)
++ lwz r8, 8(r4)
++ lwz r9, 12(r4)
++ stw r0, 0(r6)
++ stw r7, 4(r6)
++ stw r8, 8(r6)
++ stw r9, 12(r6)
++ lwz r0, 16(r4)
++ lwz r7, 20(r4)
++ lwz r8, 24(r4)
++ lwz r9, 28(r4)
++ stw r0, 16(r6)
++ stw r7, 20(r6)
++ stw r8, 24(r6)
++ stw r9, 28(r6)
++ lwz r0, 32(r4)
++ lwz r7, 36(r4)
++ lwz r8, 40(r4)
++ lwz r9, 44(r4)
++ stw r0, 32(r6)
++ stw r7, 36(r6)
++ stw r8, 40(r6)
++ stw r9, 44(r6)
++ lwz r0, 48(r4)
++ lwz r7, 52(r4)
++ lwz r8, 56(r4)
++ lwz r9, 60(r4)
++ addi r4, r4, 64
++ stw r0, 48(r6)
++ stw r7, 52(r6)
++ stw r8, 56(r6)
++ stw r9, 60(r6)
++ addi r6, r6, 64
++ bdnz L(copy_dnalign)
++ b L(copy_remaining)
++
++END (memcpy)
++libc_hidden_builtin_def (memcpy)
+diff -ruN glibc-2.20-orig/sysdeps/powerpc/powerpc32/e6500/memcopy.h glibc-2.20-memcpy-fixed/sysdeps/powerpc/powerpc32/e6500/memcopy.h
+--- glibc-2.20-orig/sysdeps/powerpc/powerpc32/e6500/memcopy.h 1969-12-31 18:00:00.000000000 -0600
++++ glibc-2.20-memcpy-fixed/sysdeps/powerpc/powerpc32/e6500/memcopy.h 2015-09-23 14:26:35.275121002 -0500
+@@ -0,0 +1 @@
++#include "../../powerpc32/power4/memcopy.h"
+diff -ruN glibc-2.20-orig/sysdeps/powerpc/powerpc32/e6500/memcpy.S glibc-2.20-memcpy-fixed/sysdeps/powerpc/powerpc32/e6500/memcpy.S
+--- glibc-2.20-orig/sysdeps/powerpc/powerpc32/e6500/memcpy.S 1969-12-31 18:00:00.000000000 -0600
++++ glibc-2.20-memcpy-fixed/sysdeps/powerpc/powerpc32/e6500/memcpy.S 2015-09-25 19:05:12.776925259 -0500
+@@ -0,0 +1,241 @@
++/* Optimized memcpy implementation for e6500 32-bit PowerPC.
++ Copyright (C) 2015 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 <sysdep.h>
++
++/* __ptr_t [r3] memcpy (__ptr_t dst [r3], __ptr_t src [r4], size_t len [r5]);
++ Returns 'dst'.
++
++ r3 = destination
++ r4 = source
++ r5 = byte count
++
++ volatile fixed point registers usable:
++ r0, r3-r12
++
++ volatile floating point registers usable:
++ f0-f13. */
++
++EALIGN (memcpy, 5, 0)
++ cmplw cr0, r4, r3 /* if source==destination, return. */
++ beqlr cr0
++ /* if number of bytes is less than 16, (optimal value TBD),
++ but greater than zero copy byte-by-byte. */
++ cmplwi r5, 16
++ mr r6, r3
++ blt L(copy_remaining)
++ neg r0, r3
++ andi. r11, r0, 15
++ beq L(dst_align16)
++ cmplwi cr1, r11, 8
++ ble cr1, L(src_1_8)
++ addi r0, r11, -8
++ addi r10, r11, -4
++ lwz r9, 0(r4)
++ lwz r8, 4(r4)
++ lwzx r7, r4, r0
++ lwzx r6, r4, r10
++ stw r9, 0(r3)
++ stw r8, 4(r3)
++ stwx r7, r3, r0
++ stwx r6, r3, r10
++ mr r6, r3
++ b L(src_0)
++L(src_1_8):
++ cmplwi cr1, r11, 4
++ cmplwi cr0, r11, 1
++ bgt cr1, L(src_567)
++ ble cr0, L(src_1)
++ /* 2, 3 or 4 bytes */
++ addi r0, r11, -2
++ lhz r9, 0(r4)
++ lhzx r8, r4, r0
++ sth r9, 0(r6)
++ sthx r8, r6, r0
++ b L(src_0)
++L(src_567):
++ addi r0, r11, -4
++ lwz r9, 0(r4)
++ lwzx r8, r4, r0
++ stw r9, 0(r6)
++ stwx r8, r6, r0
++ b L(src_0)
++L(src_1):
++ lbz r0, 0(r4)
++ stb r0, 0(r6)
++L(src_0):
++ subf r5, r11, r5
++ add r4, r4, r11
++ add r6, r6, r11
++L(dst_align16):
++ cmplwi 7, r5, 63
++ ble 7, L(copy_remaining)
++ srwi r11, r5, 6 /* No of 64 byte copy count. */
++ rlwinm r5, r5, 0, 26, 31 /* remaining bytes. */
++ rlwinm. r0, r4, 0, 28, 31
++ mtctr r11
++ li r7, 16
++ li r8, 32
++ li r9, 48
++ bne 0, L(src_naligned)
++L(copy_salign16):
++ lvx v14, 0, r4 /* copy 64 bytes. */
++ lvx v15, r7, r4
++ lvx v16, r8, r4
++ lvx v17, r9, r4
++ addi r4, r4, 64
++ stvx v14, 0, r6
++ stvx v15, r7, r6
++ stvx v16, r8, r6
++ stvx v17, r9, r6
++ addi r6, r6, 64
++ bdnz L(copy_salign16)
++L(copy_remaining):
++ srwi. r11, r5, 3 /* No of 8 byte copy count. */
++ rlwinm r5, r5, 0, 29, 31 /* remaining bytes. */
++ beq 0, L(copy_bytes)
++ mtcrf 0x01, r11
++ bf cr7*4+1, L(cp16b)
++
++ lwz r0, 0(r4) /* copy 32 bytes */
++ lwz r7, 4(r4)
++ lwz r8, 8(r4)
++ lwz r9, 12(r4)
++
++ stw r0, 0(r6)
++ stw r7, 4(r6)
++ stw r8, 8(r6)
++ stw r9, 12(r6)
++
++ lwz r0, 16(r4)
++ lwz r7, 20(r4)
++ lwz r8, 24(r4)
++ lwz r9, 28(r4)
++ addi r4, r4, 32
++
++ stw r0, 16(r6)
++ stw r7, 20(r6)
++ stw r8, 24(r6)
++ stw r9, 28(r6)
++ addi r6, r6, 32
++L(cp16b):
++ bf cr7*4+2, L(cp8b)
++ lwz r0, 0(r4) /* copy 16 bytes */
++ lwz r7, 4(r4)
++ lwz r8, 8(r4)
++ lwz r9, 12(r4)
++
++ addi r4, r4, 16
++
++ stw r0, 0(r6)
++ stw r7, 4(r6)
++ stw r8, 8(r6)
++ stw r9, 12(r6)
++ addi r6, r6, 16
++L(cp8b):
++ bf cr7*4+3, L(copy_bytes)
++ lwz r0, 0(r4) /* copy 8 bytes */
++ lwz r7, 4(r4)
++ addi r4, r4, 8
++
++ stw r0, 0(r6)
++ stw r7, 4(r6)
++ addi r6, r6, 8
++L(copy_bytes):
++ cmplwi cr1, r5, 4
++ cmplwi cr0, r5, 1
++ bgt cr1, L(gt4b) /* nb > 4? (5, 6, 7 bytes). */
++ ble cr0, L(lt1b) /* nb <= 1? (0, 1 bytes). */
++ addi r0, r5, -2 /* 2, 3, 4 bytes. */
++ lhz r9, 0(r4)
++ lhzx r11, r4, r0
++ sth r9, 0(r6)
++ sthx r11, r6, r0
++ blr
++L(gt4b):
++ addi r0, r5, -4 /* 5, 6, 7 bytes. */
++ lwz r9, 0(r4)
++ lwzx r11, r4, r0
++ stw r9, 0(r6)
++ stwx r11, r6, r0
++ blr
++L(lt1b):
++ mtocrf 0x1, r5 /* nb == 0 ? return. */
++ bflr 31
++ lbz r0, 0(r4) /* nb == 1. */
++ stb r0, 0(r6)
++ blr
++
++L(src_naligned):
++#ifndef _SOFT_FLOAT
++ rlwinm. r0, r4, 0, 29, 31
++ beq 0, L(copy_salign8)
++#endif
++L(copy_snalign): /* copy 64 bytes. */
++ lvx v0, 0, r4 /* load MSQ. */
++ lvsl v18, 0, r4 /* set permute control vector. */
++ lvx v19, r7, r4 /* load LSQ. */
++ vperm v14, v0, v19, v18 /* align the data. */
++ lvx v0, r7, r4 /* load MSQ. */
++ lvsl v18, r7, r4 /* set permute control vector. */
++ lvx v19, r8, r4 /* load LSQ. */
++ vperm v15, v0, v19, v18 /* align the data. */
++ lvx v0, r8, r4 /* load MSQ. */
++ lvsl v18, r8, r4 /* set permute control vector. */
++ lvx v19, r9, r4 /* load LSQ. */
++ vperm v16, v0, v19, v18 /* align the data. */
++ lvx v0, r9, r4 /* load MSQ. */
++ lvsl v18, r9, r4 /* set permute control vector. */
++ addi r4, r4, 64
++ lvx v19, 0, r4 /* load LSQ. */
++ vperm v17, v0, v19, v18 /* align the data. */
++ stvx v14, 0, r6
++ stvx v15, r7, r6
++ stvx v16, r8, r6
++ stvx v17, r9, r6
++ addi r6, r6, 64
++ bdnz L(copy_snalign)
++ b L(copy_remaining)
++
++#ifndef _SOFT_FLOAT
++L(copy_salign8):
++ lfd 0, 0(r4) /* copy 64 bytes. */
++ lfd 1, 8(r4)
++ lfd 2, 16(r4)
++ lfd 3, 24(r4)
++ stfd 0, 0(r6)
++ stfd 1, 8(r6)
++ stfd 2, 16(r6)
++ stfd 3, 24(r6)
++ lfd 0, 32(r4)
++ lfd 1, 40(r4)
++ lfd 2, 48(r4)
++ lfd 3, 56(r4)
++ addi r4, r4, 64
++ stfd 0, 32(r6)
++ stfd 1, 40(r6)
++ stfd 2, 48(r6)
++ stfd 3, 56(r6)
++ addi r6, r6, 64
++ bdnz L(copy_salign8)
++ b L(copy_remaining)
++#endif
++
++END (memcpy)
++libc_hidden_builtin_def (memcpy)
+diff -ruN glibc-2.20-orig/sysdeps/powerpc/powerpc64/e5500/memcopy.h glibc-2.20-memcpy-fixed/sysdeps/powerpc/powerpc64/e5500/memcopy.h
+--- glibc-2.20-orig/sysdeps/powerpc/powerpc64/e5500/memcopy.h 1969-12-31 18:00:00.000000000 -0600
++++ glibc-2.20-memcpy-fixed/sysdeps/powerpc/powerpc64/e5500/memcopy.h 2015-09-23 14:26:35.275121002 -0500
+@@ -0,0 +1 @@
++#include "../../powerpc32/power4/memcopy.h"
+diff -ruN glibc-2.20-orig/sysdeps/powerpc/powerpc64/e5500/memcpy.S glibc-2.20-memcpy-fixed/sysdeps/powerpc/powerpc64/e5500/memcpy.S
+--- glibc-2.20-orig/sysdeps/powerpc/powerpc64/e5500/memcpy.S 1969-12-31 18:00:00.000000000 -0600
++++ glibc-2.20-memcpy-fixed/sysdeps/powerpc/powerpc64/e5500/memcpy.S 2015-09-23 14:26:35.276121001 -0500
+@@ -0,0 +1,155 @@
++/* Optimized memcpy implementation for e5500 64-bit PowerPC.
++ Copyright (C) 2015 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 <sysdep.h>
++
++/* __ptr_t [r3] memcpy (__ptr_t dst [r3], __ptr_t src [r4], size_t len [r5]);
++ Returns 'dst'.
++
++ r3 = destination
++ r4 = source
++ r5 = byte count
++
++ volatile fixed point registers usable:
++ r0, r3-r12
++
++ volatile floating point registers usable:
++ f0-f13. */
++
++EALIGN (memcpy, 5, 0)
++ CALL_MCOUNT 3
++ cmpld cr0, r4, r3 /* if source==destination, return. */
++ beqlr cr0
++ /* if number of bytes is less than 8 but greater than zero,
++ copy byte-by-byte. */
++ cmpldi r5, 8
++ mr r6, r3
++ blt L(copy_bytes)
++ neg r0, r4
++ andi. r11, r0, 7
++ beq L(src_aligned)
++ /* We have to align the src pointer by r11 bytes */
++ cmplwi cr1, r11, 4
++ cmplwi cr0, r11, 1
++ bgt cr1, L(src_567)
++ ble cr0, L(src_1)
++ /* 2, 3 or 4 bytes */
++ addi r0, r11, -2
++ lhz r9, 0(r4)
++ lhzx r12, r4, r0
++ sth r9, 0(r6)
++ sthx r12, r6, r0
++ b L(src_0)
++L(src_567):
++ addi r0, r11, -4
++ lwz r9, 0(r4)
++ lwzx r12, r4, r0
++ stw r9, 0(r6)
++ stwx r12, r6, r0
++ b L(src_0)
++L(src_1):
++ lbz r0, 0(r4)
++ stb r0, 0(r6)
++L(src_0):
++ subf r5, r11, r5
++ add r4, r4, r11
++ add r6, r6, r11
++L(src_aligned):
++ cmpldi 7, r5, 63
++ ble 7, L(copy_remaining)
++ srwi r11, r5, 6 /* No of 64 byte copy count. */
++ rlwinm. r5, r5, 0, 26, 31 /* remaining bytes. */
++ mtctr r11
++L(copy_salign):
++ ld r0, 0(r4) /* 64-byte copy. */
++ ld r7, 8(r4)
++ ld r8, 16(r4)
++ ld r9, 24(r4)
++ std r0, 0(r6)
++ std r7, 8(r6)
++ std r8, 16(r6)
++ std r9, 24(r6)
++ ld r0, 32(r4)
++ ld r7, 40(r4)
++ ld r8, 48(r4)
++ ld r9, 56(r4)
++ addi r4, r4, 64
++ std r0, 32(r6)
++ std r7, 40(r6)
++ std r8, 48(r6)
++ std r9, 56(r6)
++ addi r6, r6, 64
++ bdnz L(copy_salign)
++L(copy_remaining):
++ srwi. r11, r5, 3 /* No of 8 byte copy count. */
++ rlwinm r5, r5, 0, 29, 31 /* remaining bytes. */
++ beq 0, L(copy_bytes)
++ mtcrf 0x01, r11
++ bf cr7*4+1, L(cp16b)
++ ld r0, 0(r4) /* copy 32 bytes. */
++ ld r7, 8(r4)
++ ld r8, 16(r4)
++ ld r9, 24(r4)
++ addi r4, r4, 32
++ std r0, 0(r6)
++ std r7, 8(r6)
++ std r8, 16(r6)
++ std r9, 24(r6)
++ addi r6, r6, 32
++L(cp16b):
++ bf cr7*4+2, L(cp8b)
++ ld r7, 0(r4) /* copy 16 bytes. */
++ ld r8, 8(r4)
++ addi r4, r4, 16
++ std r7, 0(r6)
++ std r8, 8(r6)
++ addi r6, r6, 16
++L(cp8b):
++ bf cr7*4+3, L(copy_bytes)
++ ld r7, 0(r4) /* copy 8 bytes. */
++ addi r4, r4, 8
++ std r7, 0(r6)
++ addi r6, r6, 8
++L(copy_bytes):
++ cmpldi cr1, r5, 4
++ cmpldi cr0, r5, 1
++ bgt cr1, L(gt4b) /* nb > 4? (5, 6, 7 bytes). */
++ ble cr0, L(lt1b) /* nb <= 1? (0, 1 bytes). */
++ addi r0, r5, -2 /* 2, 3, 4 bytes. */
++ lhz r9, 0(r4)
++ lhzx r11, r4, r0
++ sth r9, 0(r6)
++ sthx r11, r6, r0
++ blr
++L(gt4b):
++ addi r0, r5, -4 /* 5, 6, 7 bytes. */
++ lwz r9, 0(r4)
++ lwzx r11, r4, r0
++ stw r9, 0(r6)
++ stwx r11, r6, r0
++ blr
++L(lt1b):
++ mtocrf 0x1, r5 /* nb == 0 ? return. */
++ bflr 31
++ lbz r0, 0(r4) /* nb == 1. */
++ stb r0, 0(r6)
++ blr
++
++END_GEN_TB (memcpy,TB_TOCLESS)
++libc_hidden_builtin_def (memcpy)
+diff -ruN glibc-2.20-orig/sysdeps/powerpc/powerpc64/e6500/memcopy.h glibc-2.20-memcpy-fixed/sysdeps/powerpc/powerpc64/e6500/memcopy.h
+--- glibc-2.20-orig/sysdeps/powerpc/powerpc64/e6500/memcopy.h 1969-12-31 18:00:00.000000000 -0600
++++ glibc-2.20-memcpy-fixed/sysdeps/powerpc/powerpc64/e6500/memcopy.h 2015-09-23 14:26:35.276121001 -0500
+@@ -0,0 +1 @@
++#include "../../powerpc32/power4/memcopy.h"
+diff -ruN glibc-2.20-orig/sysdeps/powerpc/powerpc64/e6500/memcpy.S glibc-2.20-memcpy-fixed/sysdeps/powerpc/powerpc64/e6500/memcpy.S
+--- glibc-2.20-orig/sysdeps/powerpc/powerpc64/e6500/memcpy.S 1969-12-31 18:00:00.000000000 -0600
++++ glibc-2.20-memcpy-fixed/sysdeps/powerpc/powerpc64/e6500/memcpy.S 2015-09-25 19:05:35.132924985 -0500
+@@ -0,0 +1,213 @@
++/* Optimized memcpy implementation for e6500 64-bit PowerPC.
++ Copyright (C) 2015 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 <sysdep.h>
++
++/* __ptr_t [r3] memcpy (__ptr_t dst [r3], __ptr_t src [r4], size_t len [r5]);
++ Returns 'dst'.
++
++ r3 = destination
++ r4 = source
++ r5 = byte count
++
++ volatile fixed point registers usable:
++ r0, r3-r12
++
++ volatile floating point registers usable:
++ f0-f13. */
++
++EALIGN (memcpy, 5, 0)
++ CALL_MCOUNT 3
++ cmpld cr0, r4, r3 /* if source==destination, return. */
++ beqlr cr0
++ /* if number of bytes is less than 16 but greater than zero,
++ copy byte-by-byte. */
++ cmpldi r5, 16
++ mr r6, r3
++ ble L(copy_remaining)
++ neg r0, r3
++ andi. r11, r0, 15
++ beq L(dst_align)
++ /* We have to align the src pointer by r11 bytes */
++ cmpldi cr1, r11, 8
++ ble cr1, L(src_1_8)
++ /* Take care of 8 bytes at once */
++ addi r0, r11, -8
++ ld r9, 0(r4)
++ ldx r8, r4, r0
++ std r9, 0(r6)
++ stdx r8, r6, r0
++ b L(src_0)
++L(src_1_8):
++ cmpldi cr1, r11, 4
++ cmpldi cr0, r11, 1
++ bgt cr1, L(src_567)
++ ble cr0, L(src_1)
++ /* 2, 3 or 4 bytes */
++ addi r0, r11, -2
++ lhz r9, 0(r4)
++ lhzx r8, r4, r0
++ sth r9, 0(r6)
++ sthx r8, r6, r0
++ b L(src_0)
++L(src_567):
++ addi r0, r11, -4
++ lwz r9, 0(r4)
++ lwzx r8, r4, r0
++ stw r9, 0(r6)
++ stwx r8, r6, r0
++ b L(src_0)
++L(src_1):
++ lbz r0, 0(r4)
++ stb r0, 0(r6)
++L(src_0):
++ subf r5, r11, r5
++ add r4, r4, r11
++ add r6, r6, r11
++L(dst_align):
++ cmpldi 7, r5, 63
++ ble 7, L(copy_remaining)
++ srwi r11, r5, 6 /* No of 64 byte copy count. */
++ rlwinm r5, r5, 0, 26, 31 /* remaining bytes. */
++ rlwinm. r0, r4, 0, 28, 31
++ mtctr r11
++ li r7, 16
++ li r8, 32
++ li r9, 48
++ bne 0, L(src_naligned)
++L(copy_salign):
++ lvx v14, 0, r4
++ lvx v15, r7, r4
++ lvx v16, r8, r4
++ lvx v17, r9, r4
++ addi r4, r4, 64
++ stvx v14, 0, r6
++ stvx v15, r7, r6
++ stvx v16, r8, r6
++ stvx v17, r9, r6
++ addi r6, r6, 64
++ bdnz L(copy_salign)
++L(copy_remaining):
++ srwi. r11, r5, 3 /* No of 8 byte copy count. */
++ rlwinm r5, r5, 0, 29, 31 /* remaining bytes. */
++ beq 0, L(copy_bytes)
++ mtcrf 0x01, r11
++ bf cr7*4+1, L(cp16b)
++ ld r0, 0(r4) /* copy 32 bytes. */
++ ld r7, 8(r4)
++ ld r8, 16(r4)
++ ld r9, 24(r4)
++ addi r4, r4, 32
++ std r0, 0(r6)
++ std r7, 8(r6)
++ std r8, 16(r6)
++ std r9, 24(r6)
++ addi r6, r6, 32
++L(cp16b):
++ bf cr7*4+2, L(cp8b)
++ ld r7, 0(r4) /* copy 16 bytes. */
++ ld r8, 8(r4)
++ addi r4, r4, 16
++ std r7, 0(r6)
++ std r8, 8(r6)
++ addi r6, r6, 16
++L(cp8b):
++ bf cr7*4+3, L(copy_bytes)
++ ld r7, 0(r4) /* copy 8 bytes. */
++ addi r4, r4, 8
++ std r7, 0(r6)
++ addi r6, r6, 8
++L(copy_bytes):
++ cmpldi cr1, r5, 4
++ cmpldi cr0, r5, 1
++ bgt cr1, L(gt4b) /* nb > 4? (5, 6, 7 bytes). */
++ ble cr0, L(lt1b) /* nb <= 1? (0, 1 bytes). */
++ addi r0, r5, -2 /* 2, 3, 4 bytes. */
++ lhz r9, 0(r4)
++ lhzx r11, r4, r0
++ sth r9, 0(r6)
++ sthx r11, r6, r0
++ blr
++L(gt4b):
++ addi r0, r5, -4 /* 5, 6, 7 bytes. */
++ lwz r9, 0(r4)
++ lwzx r11, r4, r0
++ stw r9, 0(r6)
++ stwx r11, r6, r0
++ blr
++L(lt1b):
++ mtocrf 0x1, r5 /* nb == 0 ? return. */
++ bflr 31
++ lbz r0, 0(r4) /* nb == 1. */
++ stb r0, 0(r6)
++ blr
++
++L(src_naligned):
++ rlwinm. r0, r4, 0, 29, 31
++ beq 0, L(copy_salign8)
++L(copy_snalign):
++ lvx v0, 0, r4 /* load MSQ. */
++ lvsl v18, 0, r4 /* set permute control vector. */
++ lvx v19, r7, r4 /* load LSQ. */
++ vperm v14, v0, v19, v18 /* align the data. */
++ lvx v0, r7, r4 /* load MSQ. */
++ lvsl v18, r7, r4 /* set permute control vector. */
++ lvx v19, r8, r4 /* load LSQ. */
++ vperm v15, v0, v19, v18 /* align the data. */
++ lvx v0, r8, r4 /* load MSQ. */
++ lvsl v18, r8, r4 /* set permute control vector. */
++ lvx v19, r9, r4 /* load LSQ. */
++ vperm v16, v0, v19, v18 /* align the data. */
++ lvx v0, r9, r4 /* load MSQ. */
++ lvsl v18, r9, r4 /* set permute control vector. */
++ addi r4, r4, 64
++ lvx v19, 0, r4 /* load LSQ. */
++ vperm v17, v0, v19, v18 /* align the data. */
++ stvx v14, 0, r6
++ stvx v15, r7, r6
++ stvx v16, r8, r6
++ stvx v17, r9, r6
++ addi r6, r6, 64
++ bdnz L(copy_snalign)
++ b L(copy_remaining)
++
++L(copy_salign8):
++ ld r0, 0(r4)
++ ld r7, 8(r4)
++ ld r8, 16(r4)
++ ld r9, 24(r4)
++ std r0, 0(r6)
++ std r7, 8(r6)
++ std r8, 16(r6)
++ std r9, 24(r6)
++ ld r0, 32(r4)
++ ld r7, 40(r4)
++ ld r8, 48(r4)
++ ld r9, 56(r4)
++ addi r4, r4, 64
++ std r0, 32(r6)
++ std r7, 40(r6)
++ std r8, 48(r6)
++ std r9, 56(r6)
++ addi r6, r6, 64
++ bdnz L(copy_salign8)
++ b L(copy_remaining)
++
++END_GEN_TB (memcpy,TB_TOCLESS)
++libc_hidden_builtin_def (memcpy)
diff --git a/recipes-core/glibc/glibc-fsl/0010.glibc.fsl-e500mc-e5500-mset.patch b/recipes-core/glibc/glibc-fsl/0010.glibc.fsl-e500mc-e5500-mset.patch
new file mode 100755
index 0000000..477c93a
--- /dev/null
+++ b/recipes-core/glibc/glibc-fsl/0010.glibc.fsl-e500mc-e5500-mset.patch
@@ -0,0 +1,1337 @@
+# Problem Statement:
+ Implement target specific optimized memset routine for e500mc,
+ e5500 32 bit & 64-bit target
+
+# Owned by:
+ Ram
+
+# Actions:
+ * For memset of non zero values, cache line size [64] bytes are
+ set at one go per iteration and along with this 'dcbzl' cache
+ management instruction is used to generate higher performance.
+
+ * For memset of zero value, cache management instruction 'dcbzl'
+ is used to generate higher performance.
+
+
+diff -Naur libc/sysdeps/powerpc/powerpc32/e500mc/memset.S libc_release/sysdeps/powerpc/powerpc32/e500mc/memset.S
+--- libc/sysdeps/powerpc/powerpc32/e500mc/memset.S 1969-12-31 18:00:00.000000000 -0600
++++ libc_release/sysdeps/powerpc/powerpc32/e500mc/memset.S 2015-06-29 07:31:28.885952000 -0500
+@@ -0,0 +1,415 @@
++/* Optimized memset implementation for PowerPC e500mc target.
++ Copyright (C) 1997-2015 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, see
++ <http://www.gnu.org/licenses/>. */
++
++/* This implementation is based on 'powerpc/powerpc32/memset.S'. */
++
++/* __ptr_t [r3] memset (__ptr_t s [r3], int c [r4], size_t n [r5]));
++ Returns 's'.
++
++ The memset is done in three sizes: byte (8 bits), word (32 bits),
++ 32-byte blocks (256 bits) and __cache_line_size (512 bits). There
++ is a special case for setting whole cache lines to 0, which takes
++ advantage of the dcbzl instruction. */
++
++#include <sysdep.h>
++
++ .section ".text"
++EALIGN (memset, 6, 1)
++
++#define rTMP r0
++#define rMEMP0 r3 /* original value of 1st arg. */
++#define rCHR r4 /* char to set in each byte. */
++#define rLEN r5 /* length of region to set. */
++#define rMEMP r6 /* address at which we are storing. */
++#define rALIGN r7 /* number of bytes we are setting
++ now (when aligning). */
++#define rTMP2 r8
++#define rMEMP2 r9
++#define rCNT r0
++
++#define rPOS64 r10 /* constant +64 for clearing with dcbz. */
++#define rCLS r11
++#define rGOT r12
++
++#ifndef _SOFT_FLOAT
++#define rFLD fp0 /* float double register with char(s) to set
++ in each byte. */
++#endif
++
++ /* For sizes <= 4 bytes, do byte by byte set. */
++ cmplwi cr1, rLEN, 4
++ mr rMEMP, rMEMP0
++ ble cr1, L(le_4bytes)
++ rlwimi rCHR, rCHR, 8, 16, 23
++ andi. rALIGN, rMEMP, 3
++ rlwimi rCHR, rCHR, 16, 0, 15
++ beq L(4b_aligned)
++ /* By now, we know that there are at least 5 bytes to memset
++ and the destination address is not word aligned. Do not bother
++ about non-alignment and do a one word store at once and word
++ align the destination address. The penalty for non-aligned
++ store is less compared to the if-else checks and related code. */
++ subfic rALIGN, rALIGN, 4
++ stw rCHR, 0(rMEMP0)
++ sub rLEN, rLEN, rALIGN
++ add rMEMP, rMEMP, rALIGN
++L(4b_aligned):
++ /* For sizes < 32 bytes, do it in a combination of word/half word/byte
++ stores. */
++ srwi. rALIGN, rLEN, 5
++ beq L(lt_32bytes)
++ /* For sizes where 128 > size >= 32, do the memset in a loop where
++ 32 bytes are set per each iteration. For this size range, the
++ overhead in getting the destination address cache aligned is more
++ compared to the advantage of setting cache line size (64) bytes
++ per iteration. */
++ srwi. rTMP2, rALIGN, 2
++ bne L(set_cache_lines)
++ mtctr rALIGN
++ /* By now, we know that there are at least 32 bytes to memset. Hence
++ no need to check for zero loop count. */
++L(32b_loop):
++ stw rCHR, 0(rMEMP)
++ stw rCHR, 4(rMEMP)
++ stw rCHR, 8(rMEMP)
++ stw rCHR, 12(rMEMP)
++ stw rCHR, 16(rMEMP)
++ stw rCHR, 20(rMEMP)
++ stw rCHR, 24(rMEMP)
++ stw rCHR, 28(rMEMP)
++ addi rMEMP, rMEMP, 32
++ bdnz L(32b_loop)
++ rlwinm. rLEN, rLEN, 0, 27, 31
++ beqlr
++ b L(lt_32bytes)
++
++L(set_cache_lines):
++ neg rTMP2, rMEMP
++ andi. rALIGN, rTMP2, 60
++ beq L(cache_aligned)
++ add rMEMP, rMEMP, rALIGN
++ /* The cr6 and cr7 fields together will hold the number of bytes to
++ set to make the destination address cache line aligned. */
++ mtcrf 0x03, rALIGN
++ sub rLEN, rLEN, rALIGN
++ cmplwi cr1, rALIGN, 32
++ mr rMEMP2, rMEMP
++ bf cr6*4+3, L(a1)
++ stw rCHR, -4(rMEMP2)
++ stw rCHR, -8(rMEMP2)
++ stw rCHR, -12(rMEMP2)
++ stwu rCHR, -16(rMEMP2)
++L(a1):
++ blt cr1, L(a2)
++ stw rCHR, -4(rMEMP2)
++ stw rCHR, -8(rMEMP2)
++ stw rCHR, -12(rMEMP2)
++ stw rCHR, -16(rMEMP2)
++ stw rCHR, -20(rMEMP2)
++ stw rCHR, -24(rMEMP2)
++ stw rCHR, -28(rMEMP2)
++ stwu rCHR, -32(rMEMP2)
++L(a2):
++ bf cr7*4, L(a3)
++ stw rCHR, -4(rMEMP2)
++ stwu rCHR, -8(rMEMP2)
++L(a3):
++ bf cr7*4+1, L(cache_aligned)
++ stw rCHR, -4(rMEMP2)
++
++L(cache_aligned):
++#ifdef SHARED
++ mflr rTMP
++ /* Establishes GOT addressability so we can load
++ __cache_line_size from static. This value was set from the aux
++ vector during startup. */
++ SETUP_GOT_ACCESS(rGOT, got_label_1)
++ addis rGOT, rGOT, __cache_line_size-got_label_1 at ha
++ lwz rCLS, __cache_line_size-got_label_1 at l(rGOT)
++ mtlr rTMP
++#else
++ /* Load __cache_line_size from static. This value was set from the
++ aux vector during startup. */
++ lis rCLS, __cache_line_size at ha
++ lwz rCLS, __cache_line_size at l(rCLS)
++#endif
++ /* If the cache line size is set and is 64 bytes, do the memset using
++ data cache block instructions i.e. dcbz etc. Otherwise do not use
++ the dcb* instructions. */
++ cmplwi cr5, rCLS, 64
++ cmplwi cr1, rCHR, 0
++ bne cr5, L(nondcbz_loop_start)
++ beq cr1, L(z_loop_start)
++L(nz_loop_start):
++#ifndef _SOFT_FLOAT
++ stw rCHR, 0(rMEMP)
++ srwi rALIGN, rLEN, 6 /* Number of cache line size
++ blocks = n / CACHE_LINE_SIZE. */
++ stw rCHR, 4(rMEMP)
++ rlwinm rLEN, rLEN, 0, 26, 31 /* n = n % CACHE_LINE_SIZE. */
++ subic. rCNT, rALIGN, 4
++ lfd rFLD, 0(rMEMP)
++#else
++ srwi rALIGN, rLEN, 6 /* Number of cache line size
++ blocks = n / CACHE_LINE_SIZE. */
++ rlwinm rLEN, rLEN, 0, 26, 31 /* n = n % CACHE_LINE_SIZE. */
++ subic. rCNT, rALIGN, 4
++#endif
++ li rPOS64, 64
++ ble L(nz_loop_big_done)
++ mtctr rCNT
++L(nz_loop_big):
++ dcbzl rPOS64, rMEMP
++#ifndef _SOFT_FLOAT
++ stfd rFLD, 0(rMEMP)
++ stfd rFLD, 8(rMEMP)
++ stfd rFLD, 16(rMEMP)
++ stfd rFLD, 24(rMEMP)
++ stfd rFLD, 32(rMEMP)
++ stfd rFLD, 40(rMEMP)
++ stfd rFLD, 48(rMEMP)
++ stfd rFLD, 56(rMEMP)
++#else
++ stw rCHR, 0(rMEMP)
++ stw rCHR, 4(rMEMP)
++ stw rCHR, 8(rMEMP)
++ stw rCHR, 12(rMEMP)
++ stw rCHR, 16(rMEMP)
++ stw rCHR, 20(rMEMP)
++ stw rCHR, 24(rMEMP)
++ stw rCHR, 28(rMEMP)
++ stw rCHR, 32(rMEMP)
++ stw rCHR, 36(rMEMP)
++ stw rCHR, 40(rMEMP)
++ stw rCHR, 44(rMEMP)
++ stw rCHR, 48(rMEMP)
++ stw rCHR, 52(rMEMP)
++ stw rCHR, 56(rMEMP)
++ stw rCHR, 60(rMEMP)
++#endif
++ addi rMEMP, rMEMP, 64
++ bdnz L(nz_loop_big)
++ li rALIGN, 4
++L(nz_loop_big_done):
++ cmplwi cr1, rALIGN, 0
++ beq cr1, L(nz_loop_small_done)
++ mtctr rALIGN
++L(nz_loop_small):
++#ifndef _SOFT_FLOAT
++ stfd rFLD, 0(rMEMP)
++ stfd rFLD, 8(rMEMP)
++ stfd rFLD, 16(rMEMP)
++ stfd rFLD, 24(rMEMP)
++ stfd rFLD, 32(rMEMP)
++ stfd rFLD, 40(rMEMP)
++ stfd rFLD, 48(rMEMP)
++ stfd rFLD, 56(rMEMP)
++#else
++ stw rCHR, 0(rMEMP)
++ stw rCHR, 4(rMEMP)
++ stw rCHR, 8(rMEMP)
++ stw rCHR, 12(rMEMP)
++ stw rCHR, 16(rMEMP)
++ stw rCHR, 20(rMEMP)
++ stw rCHR, 24(rMEMP)
++ stw rCHR, 28(rMEMP)
++ stw rCHR, 32(rMEMP)
++ stw rCHR, 36(rMEMP)
++ stw rCHR, 40(rMEMP)
++ stw rCHR, 44(rMEMP)
++ stw rCHR, 48(rMEMP)
++ stw rCHR, 52(rMEMP)
++ stw rCHR, 56(rMEMP)
++ stw rCHR, 60(rMEMP)
++#endif
++ addi rMEMP, rMEMP, 64
++ bdnz L(nz_loop_small)
++L(nz_loop_small_done):
++ srwi. rTMP2, rLEN, 5
++ beq L(lt_32bytes)
++#ifndef _SOFT_FLOAT
++ stfd rFLD, 0(rMEMP)
++ stfd rFLD, 8(rMEMP)
++ stfd rFLD, 16(rMEMP)
++ stfd rFLD, 24(rMEMP)
++#else
++ stw rCHR, 0(rMEMP)
++ stw rCHR, 4(rMEMP)
++ stw rCHR, 8(rMEMP)
++ stw rCHR, 12(rMEMP)
++ stw rCHR, 16(rMEMP)
++ stw rCHR, 20(rMEMP)
++ stw rCHR, 24(rMEMP)
++ stw rCHR, 28(rMEMP)
++#endif
++ andi. rLEN, rLEN, 31
++ addi rMEMP, rMEMP, 32
++ beqlr
++ b L(lt_32bytes)
++
++ .p2align 6
++L(nondcbz_loop_start):
++ srwi. rALIGN, rLEN, 6 /* Number of cache line size
++ blocks = n / CACHE_LINE_SIZE. */
++ beq L(nondcbz_loop_done)
++#ifndef _SOFT_FLOAT
++ stw rCHR, 0(rMEMP)
++ stw rCHR, 4(rMEMP)
++ rlwinm rLEN, rLEN, 0, 26, 31 /* n = n % CACHE_LINE_SIZE. */
++ lfd rFLD, 0(rMEMP)
++#else
++ rlwinm rLEN, rLEN, 0, 26, 31 /* n = n % CACHE_LINE_SIZE. */
++#endif
++ mtctr rALIGN
++L(nondcbz_loop):
++#ifndef _SOFT_FLOAT
++ stfd rFLD, 0(rMEMP)
++ stfd rFLD, 8(rMEMP)
++ stfd rFLD, 16(rMEMP)
++ stfd rFLD, 24(rMEMP)
++ stfd rFLD, 32(rMEMP)
++ stfd rFLD, 40(rMEMP)
++ stfd rFLD, 48(rMEMP)
++ stfd rFLD, 56(rMEMP)
++#else
++ stw rCHR, 0(rMEMP)
++ stw rCHR, 4(rMEMP)
++ stw rCHR, 8(rMEMP)
++ stw rCHR, 12(rMEMP)
++ stw rCHR, 16(rMEMP)
++ stw rCHR, 20(rMEMP)
++ stw rCHR, 24(rMEMP)
++ stw rCHR, 28(rMEMP)
++ stw rCHR, 32(rMEMP)
++ stw rCHR, 36(rMEMP)
++ stw rCHR, 40(rMEMP)
++ stw rCHR, 44(rMEMP)
++ stw rCHR, 48(rMEMP)
++ stw rCHR, 52(rMEMP)
++ stw rCHR, 56(rMEMP)
++ stw rCHR, 60(rMEMP)
++#endif
++ addi rMEMP, rMEMP, 64
++ bdnz L(nondcbz_loop)
++L(nondcbz_loop_done):
++ srwi. rTMP2, rLEN, 5
++ beq L(lt_32bytes)
++ stw rCHR, 0(rMEMP)
++ stw rCHR, 4(rMEMP)
++ stw rCHR, 8(rMEMP)
++ stw rCHR, 12(rMEMP)
++ stw rCHR, 16(rMEMP)
++ stw rCHR, 20(rMEMP)
++ stw rCHR, 24(rMEMP)
++ stw rCHR, 28(rMEMP)
++ andi. rLEN, rLEN, 31
++ addi rMEMP, rMEMP, 32
++ beqlr
++ b L(lt_32bytes)
++
++ /* Memset of 4 bytes or less. */
++ .p2align 6
++L(le_4bytes):
++ cmplwi cr5, rLEN, 0
++ beqlr cr5
++ cmplwi cr1, rLEN, 1
++ stb rCHR, 0(rMEMP)
++ beqlr cr1
++ cmplwi cr5, rLEN, 2
++ stb rCHR, 1(rMEMP)
++ beqlr cr5
++ cmplwi cr1, rLEN, 4
++ stb rCHR, 2(rMEMP)
++ bnelr cr1
++ stb rCHR, 3(rMEMP)
++ blr
++
++ /* Clear cache lines of memory in 128-byte chunks per iteration
++ using the data cache block zero line instruction. */
++ .p2align 6
++L(z_loop_start):
++ cmplwi cr1, rLEN, 128
++ li rPOS64, 64
++L(z_loop):
++ blt cr1, L(z_loop_done)
++ addi rLEN, rLEN, -128
++ dcbzl 0, rMEMP
++ dcbzl rPOS64, rMEMP
++ cmplwi cr1, rLEN, 128
++ addi rMEMP, rMEMP, 128
++ b L(z_loop)
++L(z_loop_done):
++ cmplwi cr5, rLEN, 64
++ andi. rTMP2, rLEN, 32
++ blt cr5, L(z0)
++ dcbzl 0, rMEMP
++ addi rLEN, rLEN, -64
++ addi rMEMP, rMEMP, 64
++L(z0):
++ beq L(lt_32bytes)
++ stw rCHR, 0(rMEMP)
++ stw rCHR, 4(rMEMP)
++ stw rCHR, 8(rMEMP)
++ stw rCHR, 12(rMEMP)
++ stw rCHR, 16(rMEMP)
++ stw rCHR, 20(rMEMP)
++ andi. rLEN, rLEN, 31
++ stw rCHR, 24(rMEMP)
++ stw rCHR, 28(rMEMP)
++ addi rMEMP, rMEMP, 32
++ beqlr
++
++ /* Memset of 0-31 bytes. */
++L(lt_32bytes):
++ mtcrf 0x01, rLEN
++ cmplwi cr1, rLEN, 16
++ add rMEMP, rMEMP, rLEN
++ bt 31, L(b31t)
++ bt 30, L(b30t)
++L(b30f):
++ bt 29, L(b29t)
++L(b29f):
++ bge cr1, L(b27t)
++ bflr 28
++ stw rCHR, -4(rMEMP)
++ stw rCHR, -8(rMEMP)
++ blr
++L(b31t):
++ stbu rCHR, -1(rMEMP)
++ bf 30, L(b30f)
++L(b30t):
++ sthu rCHR, -2(rMEMP)
++ bf 29, L(b29f)
++L(b29t):
++ stwu rCHR, -4(rMEMP)
++ blt cr1, L(b27f)
++L(b27t):
++ stw rCHR, -4(rMEMP)
++ stw rCHR, -8(rMEMP)
++ stw rCHR, -12(rMEMP)
++ stwu rCHR, -16(rMEMP)
++L(b27f):
++ bflr 28
++L(b28t):
++ stw rCHR, -4(rMEMP)
++ stw rCHR, -8(rMEMP)
++ blr
++
++END (memset)
++libc_hidden_builtin_def (memset)
++
+diff -Naur libc/sysdeps/powerpc/powerpc32/e5500/memset.S libc_release/sysdeps/powerpc/powerpc32/e5500/memset.S
+--- libc/sysdeps/powerpc/powerpc32/e5500/memset.S 1969-12-31 18:00:00.000000000 -0600
++++ libc_release/sysdeps/powerpc/powerpc32/e5500/memset.S 2015-06-29 09:33:17.564951999 -0500
+@@ -0,0 +1,477 @@
++/* Optimized memset implementation for PowerPC e5500 32-bit target.
++ Copyright (C) 2015 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, see
++ <http://www.gnu.org/licenses/>. */
++
++/* This implementation is based on 'powerpc/powerpc32/memset.S'. */
++
++/* __ptr_t [r3] memset (__ptr_t s [r3], int c [r4], size_t n [r5]));
++ Returns 's'.
++
++ The memset is done in different sizes: byte (8 bits), word (32 bits),
++ 32-byte blocks (256 bits) and __cache_line_size (512 bits). There
++ is a special case for setting whole cache lines to 0, which takes
++ advantage of the dcbzl instruction. */
++
++#include <sysdep.h>
++
++ .section ".text"
++EALIGN (memset, 6, 1)
++
++#define rTMP r0
++#define rMEMP0 r3 /* original value of 1st arg. */
++#define rCHR r4 /* char to set in each byte. */
++#define rLEN r5 /* length of region to set. */
++#define rMEMP r6 /* address at which we are storing. */
++#define rALIGN r7 /* number of bytes we are setting
++ now (when aligning). */
++#define rTMP2 r8
++#define rMEMP2 r9
++#define rCNT r0
++#define rNEG128 r10 /* constant -128 for clearing with dcbzl. */
++#define rNEG64 r11 /* constant -64 for clearing with dcbzl. */
++#define rCLS r11
++#define rGOT r12
++#ifndef _SOFT_FLOAT
++#define rFLD fp0 /* float double register with char(s) to set
++ in each byte. */
++#endif
++
++ cmplwi cr1, rLEN, 7
++ mtcrf 0x1, rLEN
++ add rMEMP2, rMEMP0, rLEN
++ ble cr1, L(Upto7Bytes)
++ cmplwi cr5, rLEN, 31
++ rlwimi rCHR, rCHR, 8, 16, 23 /* Replicate byte to halfword. */
++ rlwimi rCHR, rCHR, 16, 0, 15 /* Replicate half word to word. */
++ ble cr5, L(Upto31Bytes)
++ andi. rALIGN, rMEMP0, 3
++ cmplwi cr1, rCHR, 0
++ beq L(wAligned)
++ /* By now, we know that there are at least 4 bytes to memset
++ and the destination address is not word aligned. Do not bother
++ about non-alignment and do a one word store at once and word
++ align the destination address. The penalty for non-aligned
++ store is less compared to the if-else checks and related code. */
++ subfic rALIGN, rALIGN, 4
++ sub rLEN, rLEN, rALIGN
++ stw rCHR, 0(rMEMP0)
++L(wAligned):
++ /* For '128 > n >= 32' for zero fill value and for '256 > n >= 32'
++ for non-zero fill value, the overhead in getting the destination
++ address cache line aligned is more compared to the advantage of
++ caching data and/or using the dcbzl instruction. Hence, for
++ those sizes, do it without using any explicit cache mechanism. */
++ srwi. rTMP, rLEN, 7
++ add rMEMP, rMEMP0, rALIGN
++ beq L(Upto255Bytes)
++ srwi. rTMP, rLEN, 8
++ beq cr1, L(SetCacheLines)
++ bne L(SetCacheLines)
++L(Upto255Bytes):
++ mtcrf 0x2, rLEN
++ bf cr6*4+2, L(wA64b)
++ stw rCHR, 0(rMEMP)
++ stw rCHR, 4(rMEMP)
++ stw rCHR, 8(rMEMP)
++ stw rCHR, 12(rMEMP)
++ stw rCHR, 16(rMEMP)
++ stw rCHR, 20(rMEMP)
++ stw rCHR, 24(rMEMP)
++ stw rCHR, 28(rMEMP)
++ addi rMEMP, rMEMP, 32
++L(wA64b):
++ rlwinm. rLEN, rLEN, 0, 27, 31
++ bf cr6*4+1, L(wA128b)
++ stw rCHR, 0(rMEMP)
++ stw rCHR, 4(rMEMP)
++ stw rCHR, 8(rMEMP)
++ stw rCHR, 12(rMEMP)
++ stw rCHR, 16(rMEMP)
++ stw rCHR, 20(rMEMP)
++ stw rCHR, 24(rMEMP)
++ stw rCHR, 28(rMEMP)
++ stw rCHR, 32(rMEMP)
++ stw rCHR, 36(rMEMP)
++ stw rCHR, 40(rMEMP)
++ stw rCHR, 44(rMEMP)
++ stw rCHR, 48(rMEMP)
++ stw rCHR, 52(rMEMP)
++ stw rCHR, 56(rMEMP)
++ stw rCHR, 60(rMEMP)
++ addi rMEMP, rMEMP, 64
++L(wA128b):
++ bf cr6*4, L(tail31Bytes)
++ stw rCHR, 0(rMEMP)
++ stw rCHR, 4(rMEMP)
++ stw rCHR, 8(rMEMP)
++ stw rCHR, 12(rMEMP)
++ stw rCHR, 16(rMEMP)
++ stw rCHR, 20(rMEMP)
++ stw rCHR, 24(rMEMP)
++ stw rCHR, 28(rMEMP)
++ stw rCHR, 32(rMEMP)
++ stw rCHR, 36(rMEMP)
++ stw rCHR, 40(rMEMP)
++ stw rCHR, 44(rMEMP)
++ stw rCHR, 48(rMEMP)
++ stw rCHR, 52(rMEMP)
++ stw rCHR, 56(rMEMP)
++ stw rCHR, 60(rMEMP)
++ stw rCHR, 64(rMEMP)
++ stw rCHR, 68(rMEMP)
++ stw rCHR, 72(rMEMP)
++ stw rCHR, 76(rMEMP)
++ stw rCHR, 80(rMEMP)
++ stw rCHR, 84(rMEMP)
++ stw rCHR, 88(rMEMP)
++ stw rCHR, 92(rMEMP)
++ stw rCHR, 96(rMEMP)
++ stw rCHR, 100(rMEMP)
++ stw rCHR, 104(rMEMP)
++ stw rCHR, 108(rMEMP)
++ stw rCHR, 112(rMEMP)
++ stw rCHR, 116(rMEMP)
++ stw rCHR, 120(rMEMP)
++ stw rCHR, 124(rMEMP)
++ b L(tail31Bytes)
++
++L(SetCacheLines):
++ neg rTMP2, rMEMP
++ andi. rALIGN, rTMP2, 60
++ beq L(cAligned)
++ mtcrf 0x02, rALIGN
++ add rTMP2, rMEMP, rALIGN
++ rlwinm rTMP, rALIGN, 0, 0, 29
++ bf cr6*4+3, L(a1)
++ stw rCHR, -4(rTMP2)
++ stw rCHR, -8(rTMP2)
++ stw rCHR, -12(rTMP2)
++ stwu rCHR, -16(rTMP2)
++L(a1):
++ mtcrf 0x1, rALIGN
++ bf cr6*4+2, L(a2)
++ stw rCHR, -4(rTMP2)
++ stw rCHR, -8(rTMP2)
++ stw rCHR, -12(rTMP2)
++ stw rCHR, -16(rTMP2)
++ stw rCHR, -20(rTMP2)
++ stw rCHR, -24(rTMP2)
++ stw rCHR, -28(rTMP2)
++ stwu rCHR, -32(rTMP2)
++L(a2):
++ sub rLEN, rLEN, rTMP
++ bf cr7*4, L(a3)
++ stw rCHR, -4(rTMP2)
++ stwu rCHR, -8(rTMP2)
++L(a3):
++ bf cr7*4+1, L(cAligned)
++ stw rCHR, -4(rTMP2)
++
++L(cAligned):
++#ifdef SHARED
++ mflr rTMP
++ /* Establishes GOT addressability so we can load
++ __cache_line_size from static. This value was set from the aux
++ vector during startup. */
++ SETUP_GOT_ACCESS(rGOT, got_label_1)
++ addis rGOT, rGOT, __cache_line_size-got_label_1 at ha
++ lwz rCLS, __cache_line_size-got_label_1 at l(rGOT)
++ mtlr rTMP
++#else
++ /* Load __cache_line_size from static. This value was set from the
++ aux vector during startup. */
++ lis rCLS, __cache_line_size at ha
++ lwz rCLS, __cache_line_size at l(rCLS)
++#endif
++ /* If the cache line size is set and is 64 bytes, do the memset using
++ data cache block instructions i.e. dcbzl etc. Otherwise do not use
++ the dcb* instructions. */
++ cmplwi cr5, rCLS, 64
++ add rMEMP, rMEMP, rALIGN
++ rlwinm rTMP2, rLEN, 0, 0, 25
++ bne cr5, L(nondcbzLoopStart)
++ add rMEMP, rMEMP, rTMP2
++ beq cr1, L(zLoopStart)
++L(nzLoopStart):
++#ifndef _SOFT_FLOAT
++ srwi rALIGN, rLEN, 6 /* Number of cache line size
++ blocks = n / CACHE_LINE_SIZE. */
++ stw rCHR, -4(rMEMP)
++ stw rCHR, -8(rMEMP)
++ subic. rCNT, rALIGN, 32
++ mtcrf 0x2, rLEN
++ lfd rFLD, -8(rMEMP)
++ ble L(nzLoopBigDone)
++ li rNEG128, -128
++ mtctr rCNT
++#else
++ srwi rALIGN, rLEN, 6 /* Number of cache line size
++ blocks = n / CACHE_LINE_SIZE. */
++ subic. rCNT, rALIGN, 32
++ mtcrf 0x2, rLEN
++ ble L(nzLoopBigDone)
++ li rNEG128, -128
++ mtctr rCNT
++#endif
++L(nzLoopBig):
++ dcbzl rNEG128, rMEMP
++#ifndef _SOFT_FLOAT
++ stfd rFLD, -8(rMEMP)
++ stfd rFLD, -16(rMEMP)
++ stfd rFLD, -24(rMEMP)
++ stfd rFLD, -32(rMEMP)
++ stfd rFLD, -40(rMEMP)
++ stfd rFLD, -48(rMEMP)
++ stfd rFLD, -56(rMEMP)
++ stfdu rFLD, -64(rMEMP)
++#else
++ stw rCHR, -4(rMEMP)
++ stw rCHR, -8(rMEMP)
++ stw rCHR, -12(rMEMP)
++ stw rCHR, -16(rMEMP)
++ stw rCHR, -20(rMEMP)
++ stw rCHR, -24(rMEMP)
++ stw rCHR, -28(rMEMP)
++ stw rCHR, -32(rMEMP)
++ stw rCHR, -36(rMEMP)
++ stw rCHR, -40(rMEMP)
++ stw rCHR, -44(rMEMP)
++ stw rCHR, -48(rMEMP)
++ stw rCHR, -52(rMEMP)
++ stw rCHR, -56(rMEMP)
++ stw rCHR, -60(rMEMP)
++ stwu rCHR, -64(rMEMP)
++#endif
++ bdnz L(nzLoopBig)
++ li rALIGN, 32
++L(nzLoopBigDone):
++ cmplwi cr1, rALIGN, 0
++ beq cr1, L(nzLoopSmallDone)
++ mtctr rALIGN
++L(nzLoopSmall):
++#ifndef _SOFT_FLOAT
++ stfd rFLD, -8(rMEMP)
++ stfd rFLD, -16(rMEMP)
++ stfd rFLD, -24(rMEMP)
++ stfd rFLD, -32(rMEMP)
++ stfd rFLD, -40(rMEMP)
++ stfd rFLD, -48(rMEMP)
++ stfd rFLD, -56(rMEMP)
++ stfdu rFLD, -64(rMEMP)
++#else
++ stw rCHR, -4(rMEMP)
++ stw rCHR, -8(rMEMP)
++ stw rCHR, -12(rMEMP)
++ stw rCHR, -16(rMEMP)
++ stw rCHR, -20(rMEMP)
++ stw rCHR, -24(rMEMP)
++ stw rCHR, -28(rMEMP)
++ stw rCHR, -32(rMEMP)
++ stw rCHR, -36(rMEMP)
++ stw rCHR, -40(rMEMP)
++ stw rCHR, -44(rMEMP)
++ stw rCHR, -48(rMEMP)
++ stw rCHR, -52(rMEMP)
++ stw rCHR, -56(rMEMP)
++ stw rCHR, -60(rMEMP)
++ stwu rCHR, -64(rMEMP)
++#endif
++ bdnz L(nzLoopSmall)
++L(nzLoopSmallDone):
++ rlwinm. rLEN, rLEN, 0, 27, 31
++ bf cr6*4+2, L(tail31Bytes)
++ add rMEMP, rMEMP, rTMP2
++#ifndef _SOFT_FLOAT
++ stfd rFLD, 0(rMEMP)
++ stfd rFLD, 8(rMEMP)
++ stfd rFLD, 16(rMEMP)
++ stfd rFLD, 24(rMEMP)
++#else
++ stw rCHR, 0(rMEMP)
++ stw rCHR, 4(rMEMP)
++ stw rCHR, 8(rMEMP)
++ stw rCHR, 12(rMEMP)
++ stw rCHR, 16(rMEMP)
++ stw rCHR, 20(rMEMP)
++ stw rCHR, 24(rMEMP)
++ stw rCHR, 28(rMEMP)
++#endif
++ b L(tail31Bytes)
++
++ .p2align 6
++L(nondcbzLoopStart):
++ srwi. rALIGN, rLEN, 6 /* Number of cache line size
++ blocks = n / CACHE_LINE_SIZE. */
++ mtcrf 0x2, rLEN
++ beq L(nondcbzLoopDone)
++#ifndef _SOFT_FLOAT
++ stw rCHR, 0(rMEMP)
++ stw rCHR, 4(rMEMP)
++ lfd rFLD, 0(rMEMP)
++#endif
++ mtctr rALIGN
++L(nondcbzLoop):
++#ifndef _SOFT_FLOAT
++ stfd rFLD, 0(rMEMP)
++ stfd rFLD, 8(rMEMP)
++ stfd rFLD, 16(rMEMP)
++ stfd rFLD, 24(rMEMP)
++ stfd rFLD, 32(rMEMP)
++ stfd rFLD, 40(rMEMP)
++ stfd rFLD, 48(rMEMP)
++ stfd rFLD, 56(rMEMP)
++#else
++ stw rCHR, 0(rMEMP)
++ stw rCHR, 4(rMEMP)
++ stw rCHR, 8(rMEMP)
++ stw rCHR, 12(rMEMP)
++ stw rCHR, 16(rMEMP)
++ stw rCHR, 20(rMEMP)
++ stw rCHR, 24(rMEMP)
++ stw rCHR, 28(rMEMP)
++ stw rCHR, 32(rMEMP)
++ stw rCHR, 36(rMEMP)
++ stw rCHR, 40(rMEMP)
++ stw rCHR, 44(rMEMP)
++ stw rCHR, 48(rMEMP)
++ stw rCHR, 52(rMEMP)
++ stw rCHR, 56(rMEMP)
++ stw rCHR, 60(rMEMP)
++#endif
++ addi rMEMP, rMEMP, 64
++ bdnz L(nondcbzLoop)
++L(nondcbzLoopDone):
++ rlwinm. rLEN, rLEN, 0, 27, 31
++ bf cr6*4+2, L(tail31Bytes)
++#ifndef _SOFT_FLOAT
++ stfd rFLD, 0(rMEMP)
++ stfd rFLD, 8(rMEMP)
++ stfd rFLD, 16(rMEMP)
++ stfd rFLD, 24(rMEMP)
++#else
++ stw rCHR, 0(rMEMP)
++ stw rCHR, 4(rMEMP)
++ stw rCHR, 8(rMEMP)
++ stw rCHR, 12(rMEMP)
++ stw rCHR, 16(rMEMP)
++ stw rCHR, 20(rMEMP)
++ stw rCHR, 24(rMEMP)
++ stw rCHR, 28(rMEMP)
++#endif
++ b L(tail31Bytes)
++
++ /* Memset of 7 bytes or less. */
++ .p2align 6
++L(Upto7Bytes):
++ bf cr7*4+3, L(b1)
++ stbu rCHR, -1(rMEMP2)
++L(b1):
++ rlwimi rCHR, rCHR, 8, 16, 23 /* Replicate byte to halfword. */
++ bf cr7*4+2, L(b2)
++ sthu rCHR, -2(rMEMP2)
++L(b2):
++ bflr cr7*4+1
++ rlwimi rCHR, rCHR, 16, 0, 15 /* Replicate half word to word. */
++ stw rCHR, -4(rMEMP2)
++ blr
++
++ /* Memset of 31 bytes or less. By now we know that there are at
++ least 8 bytes to memset. */
++ .p2align 6
++L(Upto31Bytes):
++ cmplwi cr1, rLEN, 16
++ bf cr7*4+3, L(c1)
++ stbu rCHR, -1(rMEMP2)
++L(c1):
++ bf cr7*4+2, L(c2)
++ sthu rCHR, -2(rMEMP2)
++L(c2):
++ bf cr7*4+1, L(c3)
++ stwu rCHR, -4(rMEMP2)
++L(c3):
++ stw rCHR, -4(rMEMP2)
++ stw rCHR, -8(rMEMP2)
++ bltlr cr1
++ stw rCHR, -12(rMEMP2)
++ stw rCHR, -16(rMEMP2)
++ bflr cr7*4
++ stw rCHR, -20(rMEMP2)
++ stw rCHR, -24(rMEMP2)
++ blr
++
++ /* Memset of tail bytes upto 31 bytes or less. */
++ .p2align 6
++L(tail31Bytes):
++ beqlr
++ mtcrf 0x1, rLEN
++ bf cr7*4+3, L(tb2)
++ stbu rCHR, -1(rMEMP2)
++L(tb2):
++ bf cr7*4+2, L(tb4)
++ sthu rCHR, -2(rMEMP2)
++L(tb4):
++ bf cr7*4+1, L(tb8)
++ stwu rCHR, -4(rMEMP2)
++L(tb8):
++ bf cr7*4, L(tb16)
++ stw rCHR, -4(rMEMP2)
++ stwu rCHR, -8(rMEMP2)
++L(tb16):
++ bflr cr6*4+3
++ stw rCHR, -4(rMEMP2)
++ stw rCHR, -8(rMEMP2)
++ stw rCHR, -12(rMEMP2)
++ stw rCHR, -16(rMEMP2)
++ blr
++
++
++ /* Clear cache lines of memory in 128-byte chunks per iteration
++ using the data cache block zero line instruction. */
++ .p2align 6
++L(zLoopStart):
++ mtcrf 0x2, rLEN
++ srwi. rCNT, rLEN, 7
++ li rNEG64, -64
++ bf cr6*4+1, L(z1)
++ dcbzl rNEG64, rMEMP
++ addi rMEMP, rMEMP, -64
++L(z1):
++ beq L(zLoopDone)
++ mtctr rCNT
++ li rNEG128, -128
++L(zLoop):
++ dcbzl rNEG64, rMEMP
++ dcbzl rNEG128, rMEMP
++ addi rMEMP, rMEMP, -128
++ bdnz L(zLoop)
++L(zLoopDone):
++ rlwinm. rLEN, rLEN, 0, 27, 31
++ bf cr6*4+2, L(tail31Bytes)
++ add rMEMP, rMEMP, rTMP2
++ stw rCHR, 0(rMEMP)
++ stw rCHR, 4(rMEMP)
++ stw rCHR, 8(rMEMP)
++ stw rCHR, 12(rMEMP)
++ stw rCHR, 16(rMEMP)
++ stw rCHR, 20(rMEMP)
++ stw rCHR, 24(rMEMP)
++ stw rCHR, 28(rMEMP)
++ b L(tail31Bytes)
++
++END (memset)
++libc_hidden_builtin_def (memset)
++
+diff -Naur libc/sysdeps/powerpc/powerpc64/e5500/memset.S libc_release/sysdeps/powerpc/powerpc64/e5500/memset.S
+--- libc/sysdeps/powerpc/powerpc64/e5500/memset.S 1969-12-31 18:00:00.000000000 -0600
++++ libc_release/sysdeps/powerpc/powerpc64/e5500/memset.S 2015-06-29 07:31:28.886952000 -0500
+@@ -0,0 +1,417 @@
++/* Optimized memset implementation for PowerPC e5500 64-bit target
++ Copyright (C) 1997-2015 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, see
++ <http://www.gnu.org/licenses/>. */
++
++/* This implementation is based on 'powerpc/powerpc64/memset.S'. */
++
++/* __ptr_t [r3] memset (__ptr_t s [r3], int c [r4], size_t n [r5]));
++ Returns 's'.
++
++ The memset is done in four sizes: byte (8 bits), word (32 bits),
++ 32-byte blocks (256 bits) and __cache_line_size (512 bits).
++ There is a special case for setting whole cache lines to 0, which
++ takes advantage of the dcbz instruction. */
++
++#include <sysdep.h>
++
++ .section ".toc","aw"
++.LC0:
++ .tc __cache_line_size[TC],__cache_line_size
++ .section ".text"
++ .align 2
++
++ .section ".text"
++EALIGN (memset, 6, 0)
++ CALL_MCOUNT 3
++
++#define rTMP r0
++#define rCNT r0
++#define rMEMP0 r3 /* original value of 1st arg. */
++#define rCHR r4 /* char to set in each byte. */
++#define rLEN r5 /* length of region to set. */
++#define rMEMP r6 /* address at which we are storing. */
++#define rALIGN r7 /* number of bytes we are setting now
++ (when aligning). */
++#define rTMP2 r8
++#define rMEMP2 r9
++#define rPOS64 r10 /* constant +64 for clearing with dcbzl. */
++#define rPOS128 r11 /* constant +128 for clearing with dcbzl. */
++#define rNEG128 r11 /* constant -128 for clearing with dcbzl. */
++#define rPOS192 r12 /* constant +192 for clearing with dcbzl. */
++#define rNEG192 r12 /* constant -192 for clearing with dcbzl. */
++#define rCLS r11
++#define rGOT r12
++
++L(_memset):
++ /* For sizes < 8 bytes, do it in a combination of
++ word/half word/byte stores. */
++ cmpldi cr1, rLEN, 7
++ mtcrf 0x01, rLEN
++ add rMEMP2, rMEMP0, rLEN
++ ble cr1, L(upTo7Bytes)
++ /* For sizes < 32 bytes, do it in a combination of double word,
++ word, half word and byte stores. */
++ cmpldi cr5, rLEN, 31
++ rlwimi rCHR, rCHR, 8, 16, 23 /* Replicate byte to halfword. */
++ rlwimi rCHR, rCHR, 16, 0, 15 /* Replicate half word to word. */
++ ble cr5, L(nAupTo31Bytes)
++ /* Get the destination address double word aligned. */
++ mr rMEMP, rMEMP0
++ andi. rALIGN, rMEMP, 7
++ insrdi rCHR, rCHR, 32, 0 /* Replicate word to double word. */
++ beq L(DwAligned)
++ andi. rTMP, rMEMP, 4
++ subfic rALIGN, rALIGN, 8
++ /* By now, we know that there are at least 7 bytes to memset and
++ the destination address is not double word aligned. Do not
++ bother about non-alignment and do a one word store at once and
++ word align the destination address. The penalty for non-aligned
++ store is less compared to the if-else checks and related code. */
++ stw rCHR, 0(rMEMP0)
++ sub rLEN, rLEN, rALIGN
++ add rMEMP, rMEMP, rALIGN
++ bne L(DwAligned)
++ stw rCHR, -4(rMEMP)
++L(DwAligned):
++ /* Now the destination address is double word aligned. For sizes
++ 512 > size >= 32, do the memset in a combination of
++ 64 bytes/32 bytes. For this size range, the overhead in getting
++ the destination address cache aligned is more compared to the
++ advantage of setting cache line size (64) bytes per iteration.
++ But for the memset of zero value case, since we use 'dcbzl'
++ instruction to clear entire cache line, we can set cache lines for
++ sizes >= 128 bytes. */
++ cmpldi cr5, rLEN, 128
++ cmpldi cr1, rCHR, 0
++ blt cr5, L(Upto511Bytes)
++ srdi. rTMP, rLEN, 10
++ beq cr1, L(SetCacheLines)
++ bne L(SetCacheLines)
++L(Upto511Bytes):
++ srdi. rTMP2, rLEN, 6
++ mtcrf 0x02, rLEN
++ beq L(DwA8WordSet)
++ mtctr rTMP2
++ /* Store 64 bytes at one go. */
++L(DwA16WordSet):
++ std rCHR, 0(rMEMP)
++ std rCHR, 8(rMEMP)
++ std rCHR, 16(rMEMP)
++ std rCHR, 24(rMEMP)
++ std rCHR, 32(rMEMP)
++ std rCHR, 40(rMEMP)
++ std rCHR, 48(rMEMP)
++ std rCHR, 56(rMEMP)
++ addi rMEMP, rMEMP, 64
++ bdnz L(DwA16WordSet)
++ /* Store 32 bytes at one go. */
++L(DwA8WordSet):
++ rldicl. rLEN, rLEN, 0, 59
++ bf cr6*4+2, L(Upto31Bytes)
++ std rCHR, 0(rMEMP)
++ std rCHR, 8(rMEMP)
++ std rCHR, 16(rMEMP)
++ std rCHR, 24(rMEMP)
++ addi rMEMP, rMEMP, 32
++ beqlr
++ b L(Upto31Bytes)
++
++L(SetCacheLines):
++ neg rTMP2, rMEMP
++ andi. rALIGN, rTMP2, 60
++ beq L(CacheAligned)
++ add rMEMP, rMEMP, rALIGN
++ /* The cr6 and cr7 fields together will hold the number of bytes
++ to set to make the destination address cache line aligned. */
++ mtcrf 0x03, rALIGN
++ sub rLEN, rLEN, rALIGN
++ cmpldi cr1, rALIGN, 32
++ mr rMEMP2, rMEMP
++ bf cr6*4+3, L(a1)
++ std rCHR, -8(rMEMP2)
++ stdu rCHR, -16(rMEMP2)
++L(a1):
++ blt cr1, L(a2)
++ std rCHR, -8(rMEMP2)
++ std rCHR, -16(rMEMP2)
++ std rCHR, -24(rMEMP2)
++ stdu rCHR, -32(rMEMP2)
++L(a2):
++ bf cr7*4, L(CacheAligned)
++ std rCHR, -8(rMEMP2)
++ /* Now the address is aligned to cache line boundary. */
++L(CacheAligned):
++ ld rCLS, .LC0 at toc(r2)
++ lwz rCLS, 0(rCLS)
++ /* The data cache instructions should be used only if the cache
++ line size is 64 bytes. This check is required to not to break
++ the memset when this code is being verified on machines having
++ cache line size other than 64 bytes. */
++ cmpldi cr5, rCLS, 64
++ cmpldi cr1, rCHR, 0
++ bne cr5, L(NonDcbzLoopStart)
++ beq cr1, L(zLoopStart)
++L(nzLoopStart):
++ srdi rALIGN, rLEN, 6 /* Number of cache line size
++ blocks = n / CACHE_LINE_SIZE. */
++ rldicl rLEN, rLEN, 0, 58 /* n = n % CACHE_LINE_SIZE. */
++ sldi rMEMP2, rALIGN, 6
++ cmplwi cr1, rALIGN, 8192
++ add rMEMP, rMEMP, rMEMP2
++ li rNEG192, -0xc0
++ subic rCNT, rALIGN, 1024
++ ble cr1, L(nzLoopBigDone)
++ mtctr rCNT
++ b L(nzLoopBig)
++ .align 6
++ /* Memset 64 bytes per iteration. */
++L(nzLoopBig):
++ /* The 'dcbzl' here clears the entire cache line and hints the core
++ that the data in the <rNEG192+rMEMP> cache block is new and hence
++ no need to fetch the block from either L2 cache or main memory
++ and that will save us some cycles. */
++ dcbzl rNEG192, rMEMP
++ std rCHR, -8(rMEMP)
++ std rCHR, -16(rMEMP)
++ std rCHR, -24(rMEMP)
++ std rCHR, -32(rMEMP)
++ std rCHR, -40(rMEMP)
++ std rCHR, -48(rMEMP)
++ std rCHR, -56(rMEMP)
++ stdu rCHR, -64(rMEMP)
++ bdnz L(nzLoopBig)
++ li rALIGN, 1024
++L(nzLoopBigDone):
++ cmpldi cr5, rALIGN, 768
++ subic rCNT, rALIGN, 32
++ cmpldi cr1, rALIGN, 0
++ ble cr5, L(nzLoopMediumDone)
++ li rNEG128, -0x80
++ mtctr rCNT
++L(nzLoopMedium):
++ dcbtst rNEG128, rMEMP
++ std rCHR, -8(rMEMP)
++ std rCHR, -16(rMEMP)
++ std rCHR, -24(rMEMP)
++ std rCHR, -32(rMEMP)
++ std rCHR, -40(rMEMP)
++ std rCHR, -48(rMEMP)
++ std rCHR, -56(rMEMP)
++ stdu rCHR, -64(rMEMP)
++ bdnz L(nzLoopMedium)
++ li rALIGN, 32
++L(nzLoopMediumDone):
++ srdi. rTMP2, rLEN, 5
++ beq cr1, L(nzLoopSmallDone)
++ mtctr rALIGN
++ /* Like above, memset 64 bytes per iteration but do not use the
++ 'dcbzl' instruction because using it will cost more than cache
++ prefetching for small number of cache blocks. */
++L(nzLoopSmall):
++ std rCHR, -8(rMEMP)
++ std rCHR, -16(rMEMP)
++ std rCHR, -24(rMEMP)
++ std rCHR, -32(rMEMP)
++ std rCHR, -40(rMEMP)
++ std rCHR, -48(rMEMP)
++ std rCHR, -56(rMEMP)
++ stdu rCHR, -64(rMEMP)
++ bdnz L(nzLoopSmall)
++L(nzLoopSmallDone):
++ /* Memset the residual bytes. */
++ add rMEMP, rMEMP, rMEMP2
++ beq L(Upto31Bytes)
++ andi. rLEN, rLEN, 31
++ std rCHR, 0(rMEMP)
++ std rCHR, 8(rMEMP)
++ std rCHR, 16(rMEMP)
++ std rCHR, 24(rMEMP)
++ addi rMEMP, rMEMP, 32
++ beqlr
++ b L(Upto31Bytes)
++
++ /* We are here because the cache line size is not 64 bytes. Memset
++ 64 bytes per each iteration without using the data cache
++ instructions. */
++ .align 6
++L(NonDcbzLoopStart):
++ srdi. rALIGN, rLEN, 6 /* Number of cache line size
++ blocks = n / CACHE_LINE_SIZE. */
++ beq L(NonDcbzLoopDone)
++ rldicl rLEN, rLEN, 0, 58 /* n = n % CACHE_LINE_SIZE. */
++ mtctr rALIGN
++L(NonDcbzLoop):
++ std rCHR, 0(rMEMP)
++ std rCHR, 8(rMEMP)
++ std rCHR, 16(rMEMP)
++ std rCHR, 24(rMEMP)
++ std rCHR, 32(rMEMP)
++ std rCHR, 40(rMEMP)
++ std rCHR, 48(rMEMP)
++ std rCHR, 56(rMEMP)
++ addi rMEMP, rMEMP, 64
++ bdnz L(NonDcbzLoop)
++L(NonDcbzLoopDone):
++ /* Memset the residual bytes. */
++ srdi. rTMP2, rLEN, 5
++ beq L(Upto31Bytes)
++ andi. rLEN, rLEN, 31
++ std rCHR, 0(rMEMP)
++ std rCHR, 8(rMEMP)
++ std rCHR, 16(rMEMP)
++ std rCHR, 24(rMEMP)
++ addi rMEMP, rMEMP, 32
++ beqlr
++ b L(Upto31Bytes)
++
++ .align 6
++ /* Memset of 7 bytes or less. */
++L(upTo7Bytes):
++ cmpldi cr5, rLEN, 2
++ bf cr7*4+3, L(b1)
++ stbu rCHR, -1(rMEMP2)
++ bltlr cr5
++L(b1):
++ rlwimi rCHR, rCHR, 8, 16, 23 /* Replicate byte to halfword. */
++ bf cr7*4+2, L(b2)
++ sthu rCHR, -2(rMEMP2)
++ bflr cr7*4+1
++L(b2):
++ rlwimi rCHR, rCHR, 16, 0, 15 /* Replicate half word to word. */
++ bflr cr7*4+1
++ stw rCHR, -4(rMEMP2)
++ blr
++
++ .align 6
++ /* Memset of 0-31 bytes. This code gets invoked only when the
++ size, which is not the tail bytes size, is less than 32 bytes. */
++L(nAupTo31Bytes):
++ insrdi rCHR, rCHR, 32, 0 /* Replicate word to double word. */
++ cmplwi cr1, rLEN, 16
++ bf cr7*4+3, L(nA2)
++ stbu rCHR, -1(rMEMP2)
++L(nA2):
++ bf 30, L(nA4)
++ sthu rCHR, -2(rMEMP2)
++L(nA4):
++ bf 29, L(nA8)
++ stwu rCHR, -4(rMEMP2)
++L(nA8):
++ std rCHR, -8(rMEMP2)
++ bltlr cr1
++ std rCHR, -16(rMEMP2)
++ bflr 28
++ std rCHR, -24(rMEMP2)
++ blr
++
++ /* Clear cache lines of memory in 256-byte chunks per iteration
++ using the data cache block zero line instruction. */
++ .align 6
++L(zLoopStart):
++ cmpldi cr5, rLEN, 256
++ andi. rTMP, rLEN, 128
++ li rPOS64, 64
++ blt cr5, L(zLoopDone)
++ li rPOS128, 128
++ li rPOS192, 192
++L(zLoop):
++ subic rLEN, rLEN, 256
++ dcbzl 0, rMEMP
++ cmpldi cr1, rLEN, 256
++ dcbzl rPOS64, rMEMP
++ dcbzl rPOS128, rMEMP
++ dcbzl rPOS192, rMEMP
++ addi rMEMP, rMEMP, 256
++ bge cr1, L(zLoop)
++L(zLoopDone):
++ beq L(z1)
++ dcbzl 0, rMEMP
++ dcbzl rPOS64, rMEMP
++ addi rMEMP, rMEMP, 128
++L(z1):
++ andi. rTMP2, rLEN, 64
++ beq L(z0)
++ dcbzl 0, rMEMP
++ addi rMEMP, rMEMP, 64
++L(z0):
++ /* Memset the residual bytes. */
++ andi. rTMP2, rLEN, 32
++ rldicl rLEN, rLEN, 0, 59
++ beq L(Upto31Bytes)
++ rldicl. rLEN, rLEN, 0, 59
++ std rCHR, 0(rMEMP)
++ std rCHR, 8(rMEMP)
++ std rCHR, 16(rMEMP)
++ std rCHR, 24(rMEMP)
++ beqlr
++ addi rMEMP, rMEMP, 32
++ b L(Upto31Bytes)
++
++ /* Memset of 0-31 bytes. */
++ .align 6
++L(Upto31Bytes):
++ mtcrf 0x01, rLEN
++ cmpldi cr1, rLEN, 16
++ add rMEMP, rMEMP, rLEN
++ bt cr7*4+3, L(b31t)
++ bt cr7*4+2, L(b30t)
++L(b30f):
++ bt cr7*4+1, L(b29t)
++L(b29f):
++ bge cr1, L(b27t)
++ bflr cr7*4
++ stw rCHR, -4(rMEMP)
++ stw rCHR, -8(rMEMP)
++ blr
++
++L(b31t):
++ stbu rCHR, -1(rMEMP)
++ bf cr7*4+2, L(b30f)
++L(b30t):
++ sthu rCHR, -2(rMEMP)
++ bf cr7*4+1, L(b29f)
++L(b29t):
++ stwu rCHR, -4(rMEMP)
++ blt cr1, L(b27f)
++L(b27t):
++ stw rCHR, -4(rMEMP)
++ stw rCHR, -8(rMEMP)
++ stw rCHR, -12(rMEMP)
++ stwu rCHR, -16(rMEMP)
++L(b27f):
++ bflr cr7*4
++L(b28t):
++ stw rCHR, -4(rMEMP)
++ stw rCHR, -8(rMEMP)
++ blr
++
++END (memset)
++libc_hidden_builtin_def (memset)
++
++#ifndef NO_BZERO_IMPL
++ /* Copied from bzero.S to prevent the linker from inserting a stub
++ between bzero and memset. */
++ENTRY (__bzero)
++ CALL_MCOUNT 3
++ mr r5, r4
++ li r4, 0
++ b L(_memset)
++
++END_GEN_TB (__bzero, TB_TOCLESS)
++weak_alias (__bzero, bzero)
++#endif
++
diff --git a/recipes-core/glibc/glibc-fsl/0011.glibc.fsl-mset-e6500.patch b/recipes-core/glibc/glibc-fsl/0011.glibc.fsl-mset-e6500.patch
new file mode 100755
index 0000000..51a0a0a
--- /dev/null
+++ b/recipes-core/glibc/glibc-fsl/0011.glibc.fsl-mset-e6500.patch
@@ -0,0 +1,537 @@
+# Problem Statement:
+ Implement target specific optimized memset for e6500 [32 & 64 bit]
+
+# Owned by:
+ Rohit
+
+# Actions:
+ * Used altivec instructions to generate optimized performance.
+ * for memset zero, made use of 'dcbzl' cache management instruction.
+
+diff -Naur glibc-2.20/sysdeps/powerpc/powerpc32/e6500/memset.S glibc-2.20-mset/sysdeps/powerpc/powerpc32/e6500/memset.S
+--- glibc-2.20/sysdeps/powerpc/powerpc32/e6500/memset.S 1969-12-31 18:00:00.000000000 -0600
++++ glibc-2.20-mset/sysdeps/powerpc/powerpc32/e6500/memset.S 2015-07-08 04:33:07.395952006 -0500
+@@ -0,0 +1,257 @@
++/* Optimized memset implementation for e6500 32-bit PowerPC.
++
++ Copyright (C) 2015 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, see
++ <http://www.gnu.org/licenses/>. */
++
++#include <sysdep.h>
++
++/* __ptr_t [r3] memset (__ptr_t s [r3], int c [r4], size_t n [r5]));
++ Returns 's'. */
++
++#define rTMP r0
++#define rRTN r3 /* initial value of 1st argument. */
++#define rMEMP0 r3 /* original value of 1st arg. */
++#define rCHR r4 /* char to set in each byte. */
++#define rLEN r5 /* length of region to set. */
++#define rMEMP r6 /* address at which we are storing. */
++#define rALIGN r7 /* no. of bytes we are setting now (when aligning). */
++#define rPOS16 r7 /* constant +16. */
++#define rPOS32 r8 /* constant +32. */
++#define rPOS48 r9 /* constant +48. */
++#define rGOT r9 /* Address of the Global Offset Table. */
++#define rCLS r9 /* Cache line size obtained from static. */
++#define rCTR2 r7
++#define rCTR1 r11
++#define rTMP1 r12
++#define vCHR v14 /* char to set in each byte. */
++#define vTMP1 v15
++#define vTMP2 v16
++
++ .section ".text"
++EALIGN (memset, 5, 1)
++ cmplwi cr1, rLEN, 4
++ cmplwi cr5, rLEN, 32
++ mr rMEMP, rMEMP0
++ ble cr1, L(small)
++ rlwimi rCHR, rCHR, 8, 16, 23
++ rlwimi rCHR, rCHR, 16, 0, 15
++ blt cr5, L(medium)
++ neg rTMP, rMEMP
++ andi. rTMP, rTMP, 15
++ bne L(nalign16)
++L(align16):
++ cmplwi 7, rLEN, 63
++ rlwinm. rTMP1, rCHR, 28, 28, 3
++ li rPOS16, 16
++ ble 7, L(copy_remaining)
++ beq L(check_cache_line_size)
++L(vec_nz):
++ srwi rCTR1, rLEN, 6 /* No of 64 byte copy count. */
++ rlwinm rLEN, rLEN, 0, 26, 31 /* remaining bytes. */
++ vxor vCHR, vCHR, vCHR
++ mtctr rCTR1 /* move count. */
++ lvsl vCHR, 0, rTMP1 /* LSU Move upper
++ nibble to byte 0 of VR. */
++ vspltisb vTMP1, 4 /* VPU Splat 0x4 to every byte. */
++ lvsl vTMP2, 0, rCHR /* LSU Move lower
++ nibble to byte 0 of VR. */
++ vslb vCHR, vCHR, vTMP1 /* VIU Move upper nibble to VR[0:3]. */
++ vor vCHR, vCHR, vTMP2 /* VIU Form FILL byte in VR[0:7]. */
++ vspltb vCHR, vCHR, 0 /* VPU Splat the fill
++ byte to all bytes. */
++ li rPOS32, 32
++ li rPOS48, 48
++L(vnz_loop):
++ stvx vCHR, 0, rMEMP
++ stvx vCHR, rPOS16, rMEMP
++ stvx vCHR, rPOS32, rMEMP
++ stvx vCHR, rPOS48, rMEMP
++ addi rMEMP, rMEMP, 64
++ bdnz L(vnz_loop)
++L(copy_remaining):
++ srwi. rCTR1, rLEN, 3 /* No of 8 byte copy count. */
++ rlwinm rLEN, rLEN, 0, 29, 31 /* remaining bytes. */
++ cmplwi cr1, rLEN, 1
++ bne 0, L(copy_words)
++L(copy_bytes):
++ bltlr cr1
++ cmplwi cr0, rLEN, 4
++ beq cr1, 2f /* nb <= 1? (0, 1 bytes). */
++ bgt cr0, 1f /* nb > 4? (5, 6, 7 bytes). */
++ addi rTMP, rLEN, -2 /* 2, 3, 4 bytes. */
++ sth rCHR, 0(rMEMP)
++ sthx rCHR, rMEMP, rTMP
++ blr
++1:
++ addi rTMP, rLEN, -4 /* 5, 6, 7 bytes. */
++ stw rCHR, 0(rMEMP)
++ stwx rCHR, rMEMP, rTMP
++ blr
++2: stb rCHR, 0(rMEMP)
++ blr
++
++L(copy_words):
++ mtcrf 0x01, rCTR1
++ bf cr7*4+1, 16f
++ stw rCHR, 0(rMEMP)
++ stw rCHR, 4(rMEMP)
++ stw rCHR, 8(rMEMP)
++ stw rCHR, 12(rMEMP)
++ stw rCHR, 16(rMEMP)
++ stw rCHR, 20(rMEMP)
++ stw rCHR, 24(rMEMP)
++ stw rCHR, 28(rMEMP)
++ addi rMEMP, rMEMP, 32
++16:
++ bf cr7*4+2, 8f
++ stw rCHR, 0(rMEMP)
++ stw rCHR, 4(rMEMP)
++ stw rCHR, 8(rMEMP)
++ stw rCHR, 12(rMEMP)
++ addi rMEMP, rMEMP, 16
++8:
++ bf cr7*4+3, L(copy_bytes)
++ stw rCHR, 0(rMEMP)
++ stw rCHR, 4(rMEMP)
++ bltlr cr1
++ addi rMEMP, rMEMP, 8
++ b L(copy_bytes)
++
++ .align 5
++L(check_cache_line_size):
++#ifdef SHARED
++ mflr rTMP
++/* Establishes GOT addressability so we can load __cache_line_size
++ from static. This value was set from the aux vector during startup. */
++ SETUP_GOT_ACCESS(rGOT,got_label_1)
++ addis rGOT, rGOT, __cache_line_size-got_label_1 at ha
++ lwz rCLS, __cache_line_size-got_label_1 at l(rGOT)
++ mtlr rTMP
++#else
++/* Load __cache_line_size from static. This value was set from the
++ aux vector during startup. */
++ lis rCLS, __cache_line_size at ha
++ lwz rCLS, __cache_line_size at l(rCLS)
++#endif
++ cmplwi 5, rCLS, 64
++ neg rTMP, rMEMP
++ bne 5, L(vec_nz)
++ andi. rTMP, rTMP, 63
++ bne L(nalign64)
++L(align64):
++ srwi rCTR1, rLEN, 6
++ cmplwi 7, rCTR1, 32767
++ rlwinm rLEN, rLEN, 0, 26, 31
++ mtctr rCTR1
++ bgt 7, L(vec_zbig)
++L(vz_loop):
++ dcbzl 0, rMEMP
++ addi rMEMP, rMEMP, 64
++ bdnz L(vz_loop)
++ b L(copy_remaining)
++
++L(vec_zbig):
++ addi rCTR2, rCTR1, -32767
++ mtctr rCTR2
++L(vz_big_loop):
++ dcbzl 0, rMEMP
++ dcbf 0, rMEMP
++ addi rMEMP, rMEMP, 64
++ bdnz L(vz_big_loop)
++ li rCTR1, 32767
++ mtctr rCTR1
++ b L(vz_loop)
++
++L(nalign64):
++ vxor vCHR, vCHR, vCHR
++ subf rLEN, rTMP, rLEN
++ li rPOS48, 48
++ li rPOS32, 32
++ stvx vCHR, 0, rMEMP
++ stvx vCHR, rPOS16, rMEMP
++ cmplwi 7, rLEN, 64
++ stvx vCHR, rPOS32, rMEMP
++ stvx vCHR, rPOS48, rMEMP
++ add rMEMP, rMEMP, rTMP
++ blt 7, L(copy_remaining)
++ b L(align64)
++
++L(nalign16):
++ stw rCHR, 0(rMEMP)
++ stw rCHR, 4(rMEMP)
++ subf rLEN, rTMP, rLEN
++ stw rCHR, 8(rMEMP)
++ stw rCHR, 12(rMEMP)
++ add rMEMP, rMEMP, rTMP
++ b L(align16)
++
++ .align 5
++ /* Memset of 0-4 bytes. Taken from GLIBC default memset. */
++L(small):
++ cmplwi cr5, rLEN, 1
++ cmplwi cr1, rLEN, 3
++ bltlr cr5
++ stb rCHR, 0(rMEMP)
++ beqlr cr5
++ nop
++ stb rCHR, 1(rMEMP)
++ bltlr cr1
++ stb rCHR, 2(rMEMP)
++ beqlr cr1
++ nop
++ stb rCHR, 3(rMEMP)
++ blr
++
++ /* Memset of 0-31 bytes. Taken from GLIBC default memset. */
++ .align 5
++L(medium):
++ mtcrf 0x01, rLEN
++ cmplwi cr1, rLEN, 16
++ add rMEMP, rMEMP, rLEN
++ bt 31, L(medium_31t)
++ bt 30, L(medium_30t)
++L(medium_30f):
++ bt 29, L(medium_29t)
++L(medium_29f):
++ bge cr1, L(medium_27t)
++ bflr 28
++ stw rCHR, -4(rMEMP)
++ stw rCHR, -8(rMEMP)
++ blr
++L(medium_31t):
++ stbu rCHR, -1(rMEMP)
++ bf 30, L(medium_30f)
++L(medium_30t):
++ sthu rCHR, -2(rMEMP)
++ bf 29, L(medium_29f)
++L(medium_29t):
++ stwu rCHR, -4(rMEMP)
++ blt cr1, L(medium_27f)
++L(medium_27t):
++ stw rCHR, -4(rMEMP)
++ stw rCHR, -8(rMEMP)
++ stw rCHR, -12(rMEMP)
++ stwu rCHR, -16(rMEMP)
++L(medium_27f):
++ bflr 28
++L(medium_28t):
++ stw rCHR, -4(rMEMP)
++ stw rCHR, -8(rMEMP)
++ blr
++
++END (memset)
++libc_hidden_builtin_def (memset)
+diff -Naur glibc-2.20/sysdeps/powerpc/powerpc64/e6500/memset.S glibc-2.20-mset/sysdeps/powerpc/powerpc64/e6500/memset.S
+--- glibc-2.20/sysdeps/powerpc/powerpc64/e6500/memset.S 1969-12-31 18:00:00.000000000 -0600
++++ glibc-2.20-mset/sysdeps/powerpc/powerpc64/e6500/memset.S 2015-07-08 04:28:48.089952006 -0500
+@@ -0,0 +1,262 @@
++/* Optimized memset implementation for e6500 64-bit PowerPC.
++
++ Copyright (C) 2015 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, see
++ <http://www.gnu.org/licenses/>. */
++
++#define rTMP r0
++#define rRTN r3 /* initial value of 1st argument. */
++#define rMEMP0 r3 /* original value of 1st arg. */
++#define rCHR r4 /* char to set in each byte. */
++#define rLEN r5 /* length of region to set. */
++#define rMEMP r6 /* address at which we are storing. */
++#define rALIGN r7 /* no. of bytes we are setting now (when aligning). */
++#define rPOS16 r7 /* constant +16. */
++#define rPOS32 r8 /* constant +32. */
++#define rPOS48 r9 /* constant +48. */
++#define rGOT r9 /* Address of the Global Offset Table. */
++#define rCLS r9 /* Cache line size obtained from static. */
++#define rCTR2 r7
++#define rCTR1 r11
++#define rTMP1 r12
++#define vCHR v14 /* char to set in each byte. */
++#define vTMP1 v15
++#define vTMP2 v16
++
++#include <sysdep.h>
++
++ .section ".toc", "aw"
++.LC0:
++ .tc __cache_line_size[TC], __cache_line_size
++ .section ".text"
++ .align 2
++
++/* __ptr_t [r3] memset (__ptr_t s [r3], int c [r4], size_t n [r5]));
++ Returns 's'. */
++
++EALIGN (memset, 5, 0)
++ CALL_MCOUNT 3
++L(_memset):
++ cmpldi cr1, rLEN, 8
++ cmpldi cr5, rLEN, 32
++ mr rMEMP, rMEMP0
++ ble cr1, L(small)
++ rlwimi rCHR, rCHR, 8, 16, 23
++ rlwimi rCHR, rCHR, 16, 0, 15
++ blt cr5, L(medium)
++ neg rTMP, rMEMP
++ andi. rTMP, rTMP, 15
++ bne L(nalign16)
++L(align16):
++ cmpldi 7, rLEN, 63
++ rlwinm. rTMP1, rCHR, 28, 28, 3
++ li rPOS16, 16
++ ble 7, L(copy_remaining)
++ beq L(check_cache_line_size)
++L(vec_nz):
++ srwi rCTR1, rLEN, 6 /* No of 64 byte copy count. */
++ rlwinm rLEN, rLEN, 0, 26, 31 /* remaining bytes. */
++ vxor vCHR, vCHR, vCHR
++ mtctr rCTR1 /* move count. */
++ lvsl vCHR, 0, rTMP1 /* LSU Move upper nibble
++ to byte 0 of VR. */
++ vspltisb vTMP1, 4 /* VPU Splat 0x4 to every byte. */
++ lvsl vTMP2, 0, rCHR /* LSU Move lower nibble
++ to byte 0 of VR. */
++ vslb vCHR, vCHR, vTMP1 /* VIU Move upper nibble to VR[0:3]. */
++ vor vCHR, vCHR, vTMP2 /* VIU Form FILL byte in VR[0:7]. */
++ vspltb vCHR, vCHR, 0 /* VPU Splat the fill
++ byte to all bytes. */
++ li rPOS32, 32
++ li rPOS48, 48
++L(vnz_loop):
++ stvx vCHR, 0, rMEMP
++ stvx vCHR, rPOS16, rMEMP
++ stvx vCHR, rPOS32, rMEMP
++ stvx vCHR, rPOS48, rMEMP
++ addi rMEMP, rMEMP, 64
++ bdnz L(vnz_loop)
++L(copy_remaining):
++ srwi. rCTR1, rLEN, 3 /* No of 8 byte copy count. */
++ rlwinm rLEN, rLEN, 0, 29, 31 /* remaining bytes. */
++ cmpldi cr1, rLEN, 1
++ bne 0, L(copy_words)
++L(copy_bytes):
++ bltlr cr1
++ cmpldi cr0, rLEN, 4
++ beq cr1, 2f /* nb <= 1? (0, 1 bytes). */
++ bgt cr0, 1f /* nb > 4? (5, 6, 7 bytes). */
++ addi rTMP, rLEN, -2 /* 2, 3, 4 bytes. */
++ sth rCHR, 0(rMEMP)
++ sthx rCHR, rMEMP, rTMP
++ blr
++1:
++ addi rTMP, rLEN, -4 /* 5, 6, 7 bytes. */
++ stw rCHR, 0(rMEMP)
++ stwx rCHR, rMEMP, rTMP
++ blr
++2: stb rCHR, 0(rMEMP)
++ blr
++
++L(copy_words):
++ mtcrf 0x01, rCTR1
++ insrdi rCHR, rCHR, 32, 0 /* Replicate word to double word. */
++ bf cr7*4+1, 16f
++ std rCHR, 0(rMEMP)
++ std rCHR, 8(rMEMP)
++ std rCHR, 16(rMEMP)
++ std rCHR, 24(rMEMP)
++ addi rMEMP, rMEMP, 32
++16:
++ bf cr7*4+2, 8f
++ std rCHR, 0(rMEMP)
++ std rCHR, 8(rMEMP)
++ addi rMEMP, rMEMP, 16
++8:
++ bf cr7*4+3, L(copy_bytes)
++ std rCHR, 0(rMEMP)
++ addi rMEMP, rMEMP, 8
++ b L(copy_bytes)
++
++ .align 5
++L(check_cache_line_size):
++ ld rCLS, .LC0 at toc(r2)
++ lwz rCLS, 0(rCLS)
++ cmpldi 5, rCLS, 64
++ neg rTMP, rMEMP
++ bne 5, L(vec_nz)
++ andi. rTMP, rTMP, 63
++ bne L(nalign64)
++L(align64):
++ srwi rCTR1, rLEN, 6
++ cmpldi 7, rCTR1, 32767
++ rlwinm rLEN, rLEN, 0, 26, 31
++ mtctr rCTR1
++ bgt 7, L(vec_zbig)
++L(vz_loop):
++ dcbzl 0, rMEMP
++ addi rMEMP, rMEMP, 64
++ bdnz L(vz_loop)
++ b L(copy_remaining)
++
++L(vec_zbig):
++ addi rCTR2, rCTR1, -32767
++ mtctr rCTR2
++L(vz_big_loop):
++ dcbzl 0, rMEMP
++ dcbf 0, rMEMP
++ addi rMEMP, rMEMP, 64
++ bdnz L(vz_big_loop)
++ li rCTR1, 32767
++ mtctr rCTR1
++ b L(vz_loop)
++
++L(nalign64):
++ vxor vCHR, vCHR, vCHR
++ subf rLEN, rTMP, rLEN
++ li rPOS48, 48
++ li rPOS32, 32
++ stvx vCHR, 0, rMEMP
++ stvx vCHR, rPOS16, rMEMP
++ cmpldi 7, rLEN, 64
++ stvx vCHR, rPOS32, rMEMP
++ stvx vCHR, rPOS48, rMEMP
++ add rMEMP, rMEMP, rTMP
++ blt 7, L(copy_remaining)
++ b L(align64)
++
++L(nalign16):
++ insrdi rCHR, rCHR, 32, 0 /* Replicate word to double word. */
++ std rCHR, 0(rMEMP)
++ subf rLEN, rTMP, rLEN
++ std rCHR, 8(rMEMP)
++ add rMEMP, rMEMP, rTMP
++ b L(align16)
++
++ /* Memset of 8 bytes or less. Taken from GLIBC default memset. */
++ .align 5
++L(small):
++ cmpldi cr6, rLEN, 4
++ cmpldi cr5, rLEN, 1
++ ble cr6, L(le4)
++ subi rLEN, rLEN, 4
++ stb rCHR, 0(rMEMP)
++ stb rCHR, 1(rMEMP)
++ stb rCHR, 2(rMEMP)
++ stb rCHR, 3(rMEMP)
++ addi rMEMP, rMEMP, 4
++ cmpldi cr5, rLEN, 1
++L(le4):
++ cmpldi cr1, rLEN, 3
++ bltlr cr5
++ stb rCHR, 0(rMEMP)
++ beqlr cr5
++ stb rCHR, 1(rMEMP)
++ bltlr cr1
++ stb rCHR, 2(rMEMP)
++ beqlr cr1
++ stb rCHR, 3(rMEMP)
++ blr
++
++ /* Memset of 0-31 bytes. Taken from GLIBC default memset. */
++ .align 5
++L(medium):
++ mtcrf 0x01, rLEN
++ insrdi rCHR, rCHR, 32, 0 /* Replicate word to double word. */
++ cmpldi cr1, rLEN, 16
++L(medium_tail2):
++ add rMEMP, rMEMP, rLEN
++L(medium_tail):
++ bt 31, L(medium_31t)
++ bt 30, L(medium_30t)
++L(medium_30f):
++ bt 29, L(medium_29t)
++L(medium_29f):
++ bge cr1, L(medium_27t)
++ bflr 28
++ std rCHR, -8(rMEMP)
++ blr
++L(medium_31t):
++ stbu rCHR, -1(rMEMP)
++ bf 30, L(medium_30f)
++L(medium_30t):
++ sthu rCHR, -2(rMEMP)
++ bf 29, L(medium_29f)
++L(medium_29t):
++ stwu rCHR, -4(rMEMP)
++ blt cr1, L(medium_27f)
++L(medium_27t):
++ std rCHR, -8(rMEMP)
++ stdu rCHR, -16(rMEMP)
++L(medium_27f):
++ bflr 28
++L(medium_28t):
++ std rCHR, -8(rMEMP)
++ blr
++END_GEN_TB (memset,TB_TOCLESS)
++libc_hidden_builtin_def (memset)
++
++#ifndef NO_BZERO_IMPL
++/* Copied from bzero.S to prevent the linker from inserting a stub
++ between bzero and memset. */
++ENTRY (__bzero)
++ mr r5, r4
++ li r4, 0
++ b L(_memset)
++END_GEN_TB (__bzero,TB_TOCLESS)
++
++weak_alias (__bzero, bzero)
++#endif
diff --git a/recipes-core/glibc/glibc-fsl/0012.glibc.fsl-mcmp-e6500.patch b/recipes-core/glibc/glibc-fsl/0012.glibc.fsl-mcmp-e6500.patch
new file mode 100755
index 0000000..88e46e7
--- /dev/null
+++ b/recipes-core/glibc/glibc-fsl/0012.glibc.fsl-mcmp-e6500.patch
@@ -0,0 +1,832 @@
+# Problem Statement:
+ Implement target specific optimized memcmp for e6500 [32 & 64 bit]
+
+# Owned by:
+ Rohit
+
+# Actions:
+ * Use altivec instructions to generate optimized performance.
+
+diff -Naur glibc-2.20/sysdeps/powerpc/powerpc32/e6500/memcmp.S glibc-2.20-mcmp/sysdeps/powerpc/powerpc32/e6500/memcmp.S
+--- glibc-2.20/sysdeps/powerpc/powerpc32/e6500/memcmp.S 1969-12-31 18:00:00.000000000 -0600
++++ glibc-2.20-mcmp/sysdeps/powerpc/powerpc32/e6500/memcmp.S 2015-03-12 17:10:38.572951270 -0500
+@@ -0,0 +1,387 @@
++/* Optimized memcmp implementation for 32-bit e6500 PowerPC.
++
++ Copyright (C) 2015 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, see
++ <http://www.gnu.org/licenses/>. */
++
++#include <sysdep.h>
++
++/* int [r3] memcmp (const char *s1 [r3],
++ const char *s2 [r4],
++ size_t size [r5])
++ r3:source1 address, return equality
++ r4:source2 address
++ r5:byte count
++
++ volatile fixed point registers usable:
++ r0, r3-r12
++
++ volatile floating point registers usable:
++ f0-f13
++
++ v0-v1 General use Volatile (caller save)
++ v2-v13 Parameters, general volatile (caller save)
++ v14-v19 General Volatile (caller save)
++
++ CR0-CR1 Volatile condition code register fields
++ CR5-CR7 Volatile condition code register fields. */
++
++#define rTMP r0
++#define rRTN r3
++#define rSTR1 r3 /* first string arg. */
++#define rSTR2 r4 /* second string arg. */
++#define rS2OFF r7 /* second string arg + 16. */
++#define rN r5
++#define rWORD1 r6 /* current word in s1. */
++#define rWORD2 r7 /* current word in s2. */
++#define rWORD3 r8 /* next word in s1. */
++#define rWORD4 r9 /* next word in s2. */
++#define rWORD5 r10 /* next word in s1. */
++#define rWORD6 r11 /* next word in s2. */
++#define rWORD7 r5 /* next word in s1. */
++#define rWORD8 r12 /* next word in s2. */
++#define rCOUNT r11
++#define rINDEX r8
++#define rVR0 v0
++#define rVR1 v1
++#define rVR2 v2
++#define rVR3 v3
++#define rVR4 v4
++#define rVR5 v5
++#define rVR6 v6
++#define rVR7 v7
++#define rVR8 v8
++#define rVR9 v9
++#define rVR10 v10
++#define rVR11 v11
++#define rVR14 v14
++#define rVR15 v15
++#define rVR16 v16
++#define rVR17 v17
++#define rVR18 v18
++#define rVR19 v19
++
++EALIGN (memcmp, 5, 0)
++ cmplwi rN, 0
++ cmplwi cr1, rN, 32
++ beq L(zero)
++ ble cr1, L(medium)
++ neg rTMP, rSTR1
++ andi. rCOUNT, rTMP, 15 /* check src1 alignment. */
++ bne L(src1_nalign)
++L(src1align16):
++ rlwinm. rTMP, r4, 0, 28, 31 /* check src2 alignment. */
++ srwi rCOUNT, rN, 4 /* no. of bytes / 16. */
++ cmplwi cr5, rCOUNT, 0xFFF0 /* check for large data compares. */
++ rlwinm rN, rN, 0, 28, 31 /* remaining bytes. */
++ mtctr rCOUNT
++ li rINDEX, 0
++ bne L(src2_nalign)
++ bgt cr5, L(large_align)
++L(loop_align):
++ lvx rVR14, rSTR1, rINDEX
++ lvx rVR15, rSTR2, rINDEX
++ addi rINDEX, rINDEX, 16
++ vcmpequb. rVR16, rVR14, rVR15
++ vnor rVR17, rVR16, rVR16
++ bdnzt 4*cr6+lt, L(loop_align)
++ cmplwi cr1, rN, 0
++ bge cr6, L(Vwords_Differ)
++ beq cr1, L(zero)
++ add rSTR1, rSTR1, rINDEX
++ add rSTR2, rSTR2, rINDEX
++L(small):
++ srwi. rCOUNT, rN, 3
++ rlwinm rN, rN, 0, 29, 31
++ beq L(cmp_bytes)
++ lwz rWORD1, 0(rSTR1)
++ lwz rWORD2, 0(rSTR2)
++ lwz rWORD3, 4(rSTR1)
++ lwz rWORD4, 4(rSTR2)
++ cmplw cr0, rWORD1, rWORD2
++ addi rSTR1, rSTR1, 8
++ cmplwi cr5, rN, 0
++ bne cr0, L(bLcr0)
++ cmplw cr1, rWORD3, rWORD4
++ addi rSTR2, rSTR2, 8
++ bne cr1, L(bLcr1)
++ beq cr5, L(zero)
++ .align 4
++L(cmp_bytes):
++ mtctr rN
++ lbz rWORD1, 0(rSTR1)
++ lbz rWORD2, 0(rSTR2)
++ bdz L(b11)
++ lbz rWORD3, 1(rSTR1)
++ lbz rWORD4, 1(rSTR2)
++ cmplw cr0, rWORD1, rWORD2
++ bdz L(b12)
++ lbz rWORD5, 2(rSTR1)
++ lbz rWORD6, 2(rSTR2)
++ cmplw cr1, rWORD3, rWORD4
++ bdz L(b13)
++ lbz rWORD7, 3(rSTR1)
++ lbz rWORD8, 3(rSTR2)
++ bne cr0, L(bx11)
++ cmplw cr5, rWORD5, rWORD6
++ bdz L(b14)
++ cmplw cr6, rWORD7, rWORD8
++ lbz rWORD1, 4(rSTR1)
++ lbz rWORD2, 4(rSTR2)
++ bne cr1, L(bx12)
++ bdz L(b15)
++ lbz rWORD3, 5(rSTR1)
++ lbz rWORD4, 5(rSTR2)
++ cmplw cr0, rWORD1, rWORD2
++ bne cr5, L(bx13)
++ bdz L(b16)
++ lbz rWORD5, 6(rSTR1)
++ lbz rWORD6, 6(rSTR2)
++ cmplw cr1, rWORD3, rWORD4
++ bne cr6, L(bx14)
++ bne cr0, L(bx15)
++ bne cr1, L(bx16)
++ sub rRTN, rWORD5, rWORD6
++ blr
++L(b16):
++ bne cr6, L(bx14)
++ bne cr0, L(bx15)
++L(bx16):
++ sub rRTN, rWORD3, rWORD4
++ blr
++L(b15):
++ bne cr5, L(bx13)
++ bne cr6, L(bx14)
++L(bx15):
++ sub rRTN, rWORD1, rWORD2
++ blr
++L(b14):
++ bne cr1, L(bx12)
++ bne cr5, L(bx13)
++L(bx14):
++ sub rRTN, rWORD7, rWORD8
++ blr
++L(b13):
++ bne cr0, L(bx11)
++ bne cr1, L(bx12)
++L(bx13):
++ sub rRTN, rWORD5, rWORD6
++ blr
++L(b12):
++ bne cr0, L(bx11)
++L(bx12):
++ sub rRTN, rWORD3, rWORD4
++ blr
++L(b11):
++L(bx11):
++ sub rRTN, rWORD1, rWORD2
++ blr
++
++ .align 4
++L(medium):
++ srwi. rCOUNT, rN, 3
++ rlwinm rN, rN, 0, 29, 31
++ beq L(cmp_bytes)
++ mtctr rCOUNT
++ cmplwi cr5, rN, 0
++ lwz rWORD1, 0(rSTR1)
++ lwz rWORD2, 0(rSTR2)
++ lwz rWORD3, 4(rSTR1)
++ lwz rWORD4, 4(rSTR2)
++ cmplw cr0, rWORD1, rWORD2
++ addi rSTR1, rSTR1, 8
++ bne cr0, L(bLcr0)
++ cmplw cr1, rWORD3, rWORD4
++ addi rSTR2, rSTR2, 8
++ bne cr1, L(bLcr1)
++ bdz L(check_small)
++ lwz rWORD1, 0(rSTR1)
++ lwz rWORD2, 0(rSTR2)
++ lwz rWORD3, 4(rSTR1)
++ lwz rWORD4, 4(rSTR2)
++ cmplw cr0, rWORD1, rWORD2
++ addi rSTR1, rSTR1, 8
++ bne cr0, L(bLcr0)
++ cmplw cr1, rWORD3, rWORD4
++ addi rSTR2, rSTR2, 8
++ bne cr1, L(bLcr1)
++ bdz L(check_small)
++ lwz rWORD1, 0(rSTR1)
++ lwz rWORD2, 0(rSTR2)
++ lwz rWORD3, 4(rSTR1)
++ lwz rWORD4, 4(rSTR2)
++ cmplw cr0, rWORD1, rWORD2
++ addi rSTR1, rSTR1, 8
++ bne cr0, L(bLcr0)
++ cmplw cr1, rWORD3, rWORD4
++ addi rSTR2, rSTR2, 8
++ bne cr1, L(bLcr1)
++ bdz L(check_small)
++ lwz rWORD1, 0(rSTR1)
++ lwz rWORD2, 0(rSTR2)
++ lwz rWORD3, 4(rSTR1)
++ lwz rWORD4, 4(rSTR2)
++ cmplw cr0, rWORD1, rWORD2
++ addi rSTR1, rSTR1, 8
++ bne cr0, L(bLcr0)
++ cmplw cr1, rWORD3, rWORD4
++ addi rSTR2, rSTR2, 8
++ bne cr1, L(bLcr1)
++ li rRTN, 0
++ blr
++
++ .align 4
++L(check_small):
++ beq cr5, L(zero)
++ b L(cmp_bytes)
++
++ .align 4
++L(src1_nalign):
++ lwz rWORD1, 0(rSTR1)
++ lwz rWORD2, 0(rSTR2)
++ lwz rWORD3, 4(rSTR1)
++ lwz rWORD4, 4(rSTR2)
++ subfc. rWORD1, rWORD1, rWORD2
++ bne L(Words_Differ)
++ subfc. rWORD1, rWORD3, rWORD4
++ bne L(Words_Differ)
++ lwz rWORD1, 8(rSTR1)
++ lwz rWORD2, 8(rSTR2)
++ lwz rWORD3, 12(rSTR1)
++ lwz rWORD4, 12(rSTR2)
++ subfc. rWORD1, rWORD1, rWORD2
++ bne L(Words_Differ)
++ subfc. rWORD1, rWORD3, rWORD4
++ bne L(Words_Differ)
++ subf rN, rCOUNT, rN
++ cmplwi cr7, rN, 32
++ add rSTR1, rSTR1, rCOUNT
++ add rSTR2, rSTR2, rCOUNT
++ ble cr7, L(medium)
++ b L(src1align16)
++
++ .align 4
++L(bLcr0):
++ li rRTN, 1
++ bgtlr cr0
++ li rRTN, -1
++ blr
++
++ .align 4
++L(bLcr1):
++ li rRTN, 1
++ bgtlr cr1
++ li rRTN, -1
++ blr
++
++ .align 4
++L(src2_nalign):
++ addi rS2OFF, rSTR2, 16
++ bgt cr5, L(large_nalign)
++L(loop_nalign):
++ lvx rVR14, rSTR1, rINDEX
++ lvsl rVR3, 0, rSTR2 /* set permute control vector. */
++ lvx rVR4, rS2OFF, rINDEX /* load LSQ. */
++ lvx rVR2, rSTR2, rINDEX /* load MSQ. */
++ addi rINDEX, rINDEX, 16
++ vperm rVR15, rVR2, rVR4, rVR3 /* align the data. */
++ vcmpequb. rVR16, rVR14, rVR15
++ vnor rVR17, rVR16, rVR16
++ bdnzt 4*cr6+lt, L(loop_nalign)
++ cmplwi cr1, rN, 0
++ bge cr6, L(Vwords_Differ)
++ beq cr1, L(zero)
++ add rSTR1, rSTR1, rINDEX
++ add rSTR2, rSTR2, rINDEX
++ b L(small)
++
++ .align 4
++L(large_nalign):
++ lvxl rVR14, rSTR1, rINDEX
++ lvsl rVR3, 0, rSTR2 /* set permute control vector. */
++ lvxl rVR4, rS2OFF, rINDEX /* load LSQ. */
++ lvxl rVR2, rSTR2, rINDEX /* load MSQ. */
++ addi rINDEX, rINDEX, 16
++ vperm rVR15, rVR2, rVR4, rVR3 /* align the data. */
++ vcmpequb. rVR16, rVR14, rVR15
++ vnor rVR17, rVR16, rVR16
++ bdnzt 4*cr6+lt, L(large_nalign)
++ cmplwi cr1, rN, 0
++ bge cr6, L(Vwords_Differ)
++ beq cr1, L(zero)
++ add rSTR1, rSTR1, rINDEX
++ add rSTR2, rSTR2, rINDEX
++ b L(small)
++
++ .align 4
++L(large_align):
++ lvxl rVR14, rSTR1, rINDEX
++ lvxl rVR15, rSTR2, rINDEX
++ addi rINDEX, rINDEX, 16
++ vcmpequb. rVR16, rVR14, rVR15
++ vnor rVR17, rVR16, rVR16
++ bdnzt 4*cr6+lt, L(large_align)
++ cmplwi cr1, rN, 0
++ bge cr6, L(Vwords_Differ)
++ beq cr1, L(zero)
++ add rSTR1, rSTR1, rINDEX
++ add rSTR2, rSTR2, rINDEX
++ b L(small)
++
++ .align 4
++L(Words_Differ):
++ subfe rRTN, rWORD1, rWORD1
++ nand rRTN, rRTN, rRTN
++ ori rRTN, rRTN, 1
++ blr
++
++ .align 4
++L(Vwords_Differ):
++ vspltisb rVR18, 1
++ vspltisb rVR1, 8
++ vslb rVR0, rVR1, rVR18
++ vslb rVR19, rVR0, rVR18
++ vslb rVR18, rVR19, rVR18
++ vxor rVR5, rVR5, rVR5
++ vsum4ubs rVR2, rVR1, rVR18
++ vsro rVR9, rVR17, rVR19
++ vsrw rVR19, rVR17, rVR1
++ vsro rVR10, rVR17, rVR18
++ vsrw rVR18, rVR17, rVR0
++ vsro rVR0, rVR17, rVR2
++ vor rVR11, rVR9, rVR10
++ vsro rVR2, rVR18, rVR1
++ vor rVR11, rVR11, rVR0
++ vcmpgtuw rVR11, rVR11, rVR5
++ vor rVR11, rVR11, rVR19
++ vor rVR11, rVR11, rVR18
++ vor rVR11, rVR11, rVR2
++ vor rVR15, rVR15, rVR11
++ vor rVR14, rVR14, rVR11
++ li rRTN, -1
++ vcmpgtub. rVR8, rVR15, rVR14
++ bnelr cr6
++ li rRTN, 1
++ blr
++
++ .align 4
++L(zero):
++ li rRTN, 0
++ blr
++
++END (memcmp)
++libc_hidden_builtin_def (memcmp)
++weak_alias (memcmp, bcmp)
+diff -Naur glibc-2.20/sysdeps/powerpc/powerpc64/e6500/memcmp.S glibc-2.20-mcmp/sysdeps/powerpc/powerpc64/e6500/memcmp.S
+--- glibc-2.20/sysdeps/powerpc/powerpc64/e6500/memcmp.S 1969-12-31 18:00:00.000000000 -0600
++++ glibc-2.20-mcmp/sysdeps/powerpc/powerpc64/e6500/memcmp.S 2015-03-12 17:26:44.637951961 -0500
+@@ -0,0 +1,428 @@
++/* Optimized memcmp implementation for 64-bit e6500 PowerPC.
++
++ Copyright (C) 2015 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, see
++ <http://www.gnu.org/licenses/>. */
++
++#include <sysdep.h>
++
++/* int [r3] memcmp (const char *s1 [r3],
++ const char *s2 [r4],
++ size_t size [r5])
++ r3:source1 address, return equality
++ r4:source2 address
++ r5:byte count
++
++ volatile fixed point registers usable:
++ r0, r3-r12
++
++ volatile floating point registers usable:
++ f0-f13
++
++ v0-v1 General use volatile (caller save)
++ v2-v13 Parameters, general volatile (caller save)
++ v14-v19 General Volatile (caller save)
++
++ CR0-CR1 Volatile condition code register fields
++ CR5-CR7 Volatile condition code register fields. */
++
++#define rTMP r0
++#define rRTN r3
++#define rSTR1 r3 /* first string arg. */
++#define rSTR2 r4 /* second string arg. */
++#define rS2OFF r7 /* second string arg + 16. */
++#define rN r5
++#define rWORD1 r6 /* current word in s1. */
++#define rWORD2 r7 /* current word in s2. */
++#define rWORD3 r8 /* next word in s1. */
++#define rWORD4 r9 /* next word in s2. */
++#define rWORD5 r10 /* next word in s1. */
++#define rWORD6 r11 /* next word in s2. */
++#define rWORD7 r5 /* next word in s1. */
++#define rWORD8 r12 /* next word in s2. */
++#define rCOUNT r11
++#define rINDEX r8
++#define rVR0 v0
++#define rVR1 v1
++#define rVR2 v2
++#define rVR3 v3
++#define rVR4 v4
++#define rVR5 v5
++#define rVR6 v6
++#define rVR7 v7
++#define rVR8 v8
++#define rVR9 v9
++#define rVR10 v10
++#define rVR11 v11
++#define rVR14 v14
++#define rVR15 v15
++#define rVR16 v16
++#define rVR17 v17
++#define rVR18 v18
++#define rVR19 v19
++
++EALIGN (memcmp, 5, 0)
++ CALL_MCOUNT 3
++ cmpldi rN, 0
++ cmpldi cr1, rN, 16
++ cmpldi cr5, rN, 64
++ beq L(zero)
++ blt cr1, L(small)
++ ble cr5, L(medium)
++ neg rTMP, rSTR1
++ andi. rCOUNT, rTMP, 15 /* check src1 alignment. */
++ bne L(src1_nalign)
++L(src1align16):
++ rlwinm. rTMP, rSTR2, 0, 28, 31 /* check src2 alignment. */
++ bne L(src2_nalign)
++ srdi rCOUNT, rN, 4 /* nb / 16. */;
++ cmpldi cr5, rCOUNT, 0xFFF0 /* check for large data compares. */
++ rlwinm rN, rN, 0, 28, 31 /* remaining bytes. */
++ mtctr rCOUNT
++ li rINDEX, 0
++ bgt cr5, L(large_align)
++ .align 4
++L(loop_align):
++ lvx rVR14, rSTR1, rINDEX
++ lvx rVR15, rSTR2, rINDEX
++ addi rINDEX, rINDEX, 16
++ vcmpequb. rVR16, rVR14, rVR15
++ vnor rVR17, rVR16, rVR16
++ bdnzt 4*cr6+lt, L(loop_align)
++ cmpldi cr1, rN, 0
++ bge cr6, L(Vwords_Differ)
++ beq cr1, L(zero)
++ add rSTR1, rSTR1, rINDEX
++ add rSTR2, rSTR2, rINDEX
++ .align 4
++L(small):
++ srdi. rCOUNT, rN, 3
++ rlwinm rN, rN, 0, 29, 31
++ beq L(cmp_bytes)
++ ld rWORD1, 0(rSTR1)
++ ld rWORD2, 0(rSTR2)
++ cmpld cr0, rWORD1, rWORD2
++ cmpldi cr1, rN, 0
++ addi rSTR1, rSTR1, 8
++ addi rSTR2, rSTR2, 8
++ bne cr0, L(bLcr0)
++ beq cr1, L(zero)
++ .align 4
++L(cmp_bytes):
++ mtctr rN
++ lbz rWORD1, 0(rSTR1)
++ lbz rWORD2, 0(rSTR2)
++ bdz L(b11)
++ lbz rWORD3, 1(rSTR1)
++ lbz rWORD4, 1(rSTR2)
++ cmpld cr0, rWORD1, rWORD2
++ bdz L(b12)
++ lbz rWORD5, 2(rSTR1)
++ lbz rWORD6, 2(rSTR2)
++ cmpld cr1, rWORD3, rWORD4
++ bdz L(b13)
++ lbz rWORD7, 3(rSTR1)
++ lbz rWORD8, 3(rSTR2)
++ bne cr0, L(bx11)
++ cmpld cr5, rWORD5, rWORD6
++ bdz L(b14)
++ cmpld cr6, rWORD7, rWORD8
++ lbz rWORD1, 4(rSTR1)
++ lbz rWORD2, 4(rSTR2)
++ bne cr1, L(bx12)
++ bdz L(b15)
++ lbz rWORD3, 5(rSTR1)
++ lbz rWORD4, 5(rSTR2)
++ cmpld cr0, rWORD1, rWORD2
++ bne cr5, L(bx13)
++ bdz L(b16)
++ lbz rWORD5, 6(rSTR1)
++ lbz rWORD6, 6(rSTR2)
++ cmpld cr1, rWORD3, rWORD4
++ bne cr6, L(bx14)
++ bne cr0, L(bx15)
++ bne cr1, L(bx16)
++ sub rRTN, rWORD5, rWORD6
++ blr
++L(b16):
++ bne cr6, L(bx14)
++ bne cr0, L(bx15)
++L(bx16):
++ sub rRTN, rWORD3, rWORD4
++ blr
++L(b15):
++ bne cr5, L(bx13)
++ bne cr6, L(bx14)
++L(bx15):
++ sub rRTN, rWORD1, rWORD2
++ blr
++L(b14):
++ bne cr1, L(bx12)
++ bne cr5, L(bx13)
++L(bx14):
++ sub rRTN, rWORD7, rWORD8
++ blr
++L(b13):
++ bne cr0, L(bx11)
++ bne cr1, L(bx12)
++L(bx13):
++ sub rRTN, rWORD5, rWORD6
++ blr
++L(b12):
++ bne cr0, L(bx11)
++L(bx12):
++ sub rRTN, rWORD3, rWORD4
++ blr
++L(b11):
++L(bx11):
++ sub rRTN, rWORD1, rWORD2
++ blr
++
++ .align 4
++L(medium):
++ srwi rCOUNT, rN, 4
++ rlwinm rN, rN, 0, 28, 31
++ mtctr rCOUNT
++ cmpldi cr5, rN, 0
++ ld rWORD1, 0(rSTR1)
++ ld rWORD2, 0(rSTR2)
++ ld rWORD3, 8(rSTR1)
++ ld rWORD4, 8(rSTR2)
++ cmpld cr0, rWORD1, rWORD2
++ addi rSTR1, rSTR1, 16
++ bne cr0, L(bLcr0)
++ cmpld cr1, rWORD3, rWORD4
++ addi rSTR2, rSTR2, 16
++ bne cr1, L(bLcr1)
++ bdz L(check_small)
++ ld rWORD1, 0(rSTR1)
++ ld rWORD2, 0(rSTR2)
++ ld rWORD3, 8(rSTR1)
++ ld rWORD4, 8(rSTR2)
++ cmpld cr0, rWORD1, rWORD2
++ addi rSTR1, rSTR1, 16
++ bne cr0, L(bLcr0)
++ cmpld cr1, rWORD3, rWORD4
++ addi rSTR2, rSTR2, 16
++ bne cr1, L(bLcr1)
++ bdz L(check_small)
++ ld rWORD1, 0(rSTR1)
++ ld rWORD2, 0(rSTR2)
++ ld rWORD3, 8(rSTR1)
++ ld rWORD4, 8(rSTR2)
++ cmpld cr0, rWORD1, rWORD2
++ addi rSTR1, rSTR1, 16
++ bne cr0, L(bLcr0)
++ cmpld cr1, rWORD3, rWORD4
++ addi rSTR2, rSTR2, 16
++ bne cr1, L(bLcr1)
++ bdz L(check_small)
++ ld rWORD1, 0(rSTR1)
++ ld rWORD2, 0(rSTR2)
++ ld rWORD3, 8(rSTR1)
++ ld rWORD4, 8(rSTR2)
++ cmpld cr0, rWORD1, rWORD2
++ addi rSTR1, rSTR1, 16
++ bne cr0, L(bLcr0)
++ cmpld cr1, rWORD3, rWORD4
++ addi rSTR2, rSTR2, 16
++ bne cr1, L(bLcr1)
++ li rRTN, 0
++ blr
++
++ .align 4
++L(check_small):
++ beq cr5, L(zero)
++ b L(small)
++
++ .align 4
++L(src1_nalign):
++ ld rWORD1, 0(rSTR1)
++ ld rWORD2, 0(rSTR2)
++ ld rWORD3, 8(rSTR1)
++ ld rWORD4, 8(rSTR2)
++ cmpld cr0, rWORD1, rWORD2
++ add rSTR1, rSTR1, rCOUNT
++ bne cr0, L(bLcr0)
++ cmpld cr1, rWORD3, rWORD4
++ add rSTR2, rSTR2, rCOUNT
++ bne cr1, L(bLcr1)
++ subf rN, rCOUNT, rN
++ cmpldi cr7, rN, 64
++ ble cr7, L(medium)
++ b L(src1align16)
++
++ .align 4
++L(src2_nalign):
++ rlwinm. rTMP, rSTR2, 0, 29, 31
++ beq cr0, L(src2_dwalign)
++ srdi rCOUNT, rN, 4 /* n / 16. */;
++ cmpldi cr5, rCOUNT, 0xFFF0 /* check for large data compares. */
++ rlwinm rN, rN, 0, 28, 31 /* remaining bytes. */
++ mtctr rCOUNT
++ li rINDEX, 0
++ addi rS2OFF, rSTR2, 16
++ bgt cr5, L(large_nalign)
++ .align 4
++L(loop_nalign):
++ lvx rVR14, rSTR1, rINDEX
++ lvsl rVR3, 0, rSTR2 /* set permute control vector. */
++ lvx rVR4, rS2OFF, rINDEX /* load LSQ. */
++ lvx rVR2, rSTR2, rINDEX /* load MSQ. */
++ addi rINDEX, rINDEX, 16
++ vperm rVR15, rVR2, rVR4, rVR3 /* align the data. */
++ vcmpequb. rVR16, rVR14, rVR15
++ vnor rVR17, rVR16, rVR16
++ bdnzt 4*cr6+lt, L(loop_nalign)
++ cmpldi cr1, rN, 0
++ bge cr6, L(Vwords_Differ)
++ beq cr1, L(zero)
++ add rSTR1, rSTR1, rINDEX
++ add rSTR2, rSTR2, rINDEX
++ b L(small)
++
++ .align 4
++L(src2_dwalign):
++ srdi rCOUNT, rN, 6
++ rlwinm rN, rN, 0, 26, 31
++ mtctr rCOUNT
++ li rINDEX, 0
++ cmpldi cr5, rN, 0
++ cmpldi cr6, rN, 16
++L(dw_loop):
++ ld rWORD1, 0(rSTR1)
++ ld rWORD2, 0(rSTR2)
++ ld rWORD3, 8(rSTR1)
++ ld rWORD4, 8(rSTR2)
++ cmpld cr0, rWORD1, rWORD2
++ ld rWORD1, 16(rSTR1)
++ ld rWORD2, 16(rSTR2)
++ bne cr0, L(bLcr0)
++ cmpld cr1, rWORD3, rWORD4
++ ld rWORD3, 24(rSTR1)
++ ld rWORD4, 24(rSTR2)
++ bne cr1, L(bLcr1)
++ cmpld cr0, rWORD1, rWORD2
++ ld rWORD1, 32(rSTR1)
++ ld rWORD2, 32(rSTR2)
++ bne cr0, L(bLcr0)
++ cmpld cr1, rWORD3, rWORD4
++ ld rWORD3, 40(rSTR1)
++ ld rWORD4, 40(rSTR2)
++ bne cr1, L(bLcr1)
++ cmpld cr0, rWORD1, rWORD2
++ ld rWORD1, 48(rSTR1)
++ ld rWORD2, 48(rSTR2)
++ bne cr0, L(bLcr0)
++ cmpld cr1, rWORD3, rWORD4
++ ld rWORD3, 56(rSTR1)
++ ld rWORD4, 56(rSTR2)
++ bne cr1, L(bLcr1)
++ cmpld cr0, rWORD1, rWORD2
++ addi rSTR1, rSTR1, 64
++ bne cr0, L(bLcr0)
++ cmpld cr1, rWORD3, rWORD4
++ addi rSTR2, rSTR2, 64
++ bne cr1, L(bLcr1)
++ bdnz L(dw_loop)
++ beq cr5, L(zero)
++ blt cr6, L(small)
++ b L(medium)
++
++ .align 4
++L(bLcr0):
++ li rRTN, 1
++ bgtlr cr0
++ li rRTN, -1
++ blr
++
++ .align 4
++L(bLcr1):
++ li rRTN, 1
++ bgtlr cr1
++ li rRTN, -1
++ blr
++
++ .align 4
++L(large_nalign):
++ lvxl rVR14, rSTR1, rINDEX
++ lvsl rVR3, 0, rSTR2 /* set permute control vector. */
++ lvxl rVR4, rS2OFF, rINDEX /* load LSQ. */
++ lvxl rVR2, rSTR2, rINDEX /* load MSQ. */
++ addi rINDEX, rINDEX, 16
++ vperm rVR15, rVR2, rVR4, rVR3 /* align the data. */
++ vcmpequb. rVR16, rVR14, rVR15
++ vnor rVR17, rVR16, rVR16
++ bdnzt 4*cr6+lt, L(large_nalign)
++ cmpldi cr1, rN, 0
++ bge cr6, L(Vwords_Differ)
++ beq cr1, L(zero)
++ add rSTR1, rSTR1, rINDEX
++ add rSTR2, rSTR2, rINDEX
++ b L(small)
++
++ .align 4
++L(large_align):
++ lvxl rVR14, rSTR1, rINDEX
++ lvxl rVR15, rSTR2, rINDEX
++ addi rINDEX, rINDEX, 16
++ vcmpequb. rVR16, rVR14, rVR15
++ vnor rVR17, rVR16, rVR16
++ bdnzt 4*cr6+lt, L(large_align)
++ cmpldi cr1, rN, 0
++ bge cr6, L(Vwords_Differ)
++ beq cr1, L(zero)
++ add rSTR1, rSTR1, rINDEX
++ add rSTR2, rSTR2, rINDEX
++ b L(small)
++
++ .align 4
++L(Vwords_Differ):
++ vspltisb rVR18, 1
++ vspltisb rVR1, 8
++ vslb rVR0, rVR1, rVR18
++ vslb rVR19, rVR0, rVR18
++ vslb rVR18, rVR19, rVR18
++ vxor rVR5, rVR5, rVR5
++ vsum4ubs rVR2, rVR1, rVR18
++ vsro rVR9, rVR17, rVR19
++ vsrw rVR19, rVR17, rVR1
++ vsro rVR10, rVR17, rVR18
++ vsrw rVR18, rVR17, rVR0
++ vsro rVR0, rVR17, rVR2
++ vor rVR11, rVR9, rVR10
++ vsro rVR2, rVR18, rVR1
++ vor rVR11, rVR11, rVR0
++ vcmpgtuw rVR11, rVR11, rVR5
++ vor rVR11, rVR11, rVR19
++ vor rVR11, rVR11, rVR18
++ vor rVR11, rVR11, rVR2
++ vor rVR15, rVR15, rVR11
++ vor rVR14, rVR14, rVR11
++ li rRTN, -1
++ vcmpgtub. rVR8, rVR15, rVR14
++ bnelr cr6
++ li rRTN, 1
++ blr
++
++ .align 4
++L(zero):
++ li rRTN, 0
++ blr
++
++END (memcmp)
++libc_hidden_builtin_def (memcmp)
++weak_alias (memcmp, bcmp)
diff --git a/recipes-core/glibc/glibc-fsl/0013.glibc.fsl-stcmp-e5500.patch b/recipes-core/glibc/glibc-fsl/0013.glibc.fsl-stcmp-e5500.patch
new file mode 100755
index 0000000..511d88c
--- /dev/null
+++ b/recipes-core/glibc/glibc-fsl/0013.glibc.fsl-stcmp-e5500.patch
@@ -0,0 +1,380 @@
+# Problem Statement:
+ Dhrystone benchmark gave performance degradation due to
+ code alignment.
+ Target: e5500 (32 & 64-bit)
+
+ Note: This is not a library optimization patch but a performance fix.
+
+# Owned by:
+ Rohit
+
+# Actions:
+ * Aligned loop code of strcmp library to 16 bytes.
+ * Broke down lwzu/ldu to lwz/ld+addi.
+ This combination gives good performance numbers.
+
+diff -Naur libc/sysdeps/powerpc/powerpc32/e5500/strcmp.S libc-strcmp/sysdeps/powerpc/powerpc32/e5500/strcmp.S
+--- libc/sysdeps/powerpc/powerpc32/e5500/strcmp.S 1969-12-31 18:00:00.000000000 -0600
++++ libc-strcmp/sysdeps/powerpc/powerpc32/e5500/strcmp.S 2014-12-15 09:42:36.119952087 -0600
+@@ -0,0 +1,150 @@
++/* Optimized strcmp implementation for PowerPC.
++ Copyright (C) 1997-2014 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, see
++ <http://www.gnu.org/licenses/>. */
++
++#include <sysdep.h>
++
++/* See strlen.s for comments on how the end-of-string testing works. */
++
++/* int [r3] strcmp (const char *s1 [r3], const char *s2 [r4]) */
++
++EALIGN (strcmp, 4, 0)
++
++#define rTMP2 r0
++#define rRTN r3
++#define rSTR1 r3 /* first string arg */
++#define rSTR2 r4 /* second string arg */
++#define rWORD1 r5 /* current word in s1 */
++#define rWORD2 r6 /* current word in s2 */
++#define rFEFE r7 /* constant 0xfefefeff (-0x01010101) */
++#define r7F7F r8 /* constant 0x7f7f7f7f */
++#define rNEG r9 /* ~(word in s1 | 0x7f7f7f7f) */
++#define rBITDIF r10 /* bits that differ in s1 & s2 words */
++#define rTMP r11
++
++
++ or rTMP, rSTR2, rSTR1
++ clrlwi. rTMP, rTMP, 30
++ lis rFEFE, -0x101
++ bne L(unaligned)
++
++ lwz rWORD1, 0(rSTR1)
++ lwz rWORD2, 0(rSTR2)
++ lis r7F7F, 0x7f7f
++ addi rFEFE, rFEFE, -0x101
++ addi r7F7F, r7F7F, 0x7f7f
++ b L(g1)
++
++L(g0): lwzu rWORD1, 4(rSTR1)
++ bne cr1, L(different)
++ lwzu rWORD2, 4(rSTR2)
++L(g1): add rTMP, rFEFE, rWORD1
++ nor rNEG, r7F7F, rWORD1
++ and. rTMP, rTMP, rNEG
++ cmpw cr1, rWORD1, rWORD2
++ beq+ L(g0)
++
++/* OK. We've hit the end of the string. We need to be careful that
++ we don't compare two strings as different because of gunk beyond
++ the end of the strings... */
++#ifdef __LITTLE_ENDIAN__
++L(endstring):
++ addi rTMP2, rTMP, -1
++ andc rTMP2, rTMP2, rTMP
++ rlwimi rTMP2, rTMP2, 1, 0, 30
++ and rWORD2, rWORD2, rTMP2 /* Mask off gunk. */
++ and rWORD1, rWORD1, rTMP2
++ rlwinm rTMP2, rWORD2, 8, 0xffffffff /* Byte reverse word. */
++ rlwinm rTMP, rWORD1, 8, 0xffffffff
++ rlwimi rTMP2, rWORD2, 24, 0, 7
++ rlwimi rTMP, rWORD1, 24, 0, 7
++ rlwimi rTMP2, rWORD2, 24, 16, 23
++ rlwimi rTMP, rWORD1, 24, 16, 23
++ xor. rBITDIF, rTMP, rTMP2
++ sub rRTN, rTMP, rTMP2
++ bgelr+
++ ori rRTN, rTMP2, 1
++ blr
++
++L(different):
++ lwz rWORD1, -4(rSTR1)
++ rlwinm rTMP2, rWORD2, 8, 0xffffffff /* Byte reverse word. */
++ rlwinm rTMP, rWORD1, 8, 0xffffffff
++ rlwimi rTMP2, rWORD2, 24, 0, 7
++ rlwimi rTMP, rWORD1, 24, 0, 7
++ rlwimi rTMP2, rWORD2, 24, 16, 23
++ rlwimi rTMP, rWORD1, 24, 16, 23
++ xor. rBITDIF, rTMP, rTMP2
++ sub rRTN, rTMP, rTMP2
++ bgelr+
++ ori rRTN, rTMP2, 1
++ blr
++
++#else
++L(endstring):
++ and rTMP, r7F7F, rWORD1
++ beq cr1, L(equal)
++ add rTMP, rTMP, r7F7F
++ xor. rBITDIF, rWORD1, rWORD2
++ andc rNEG, rNEG, rTMP
++ blt- L(highbit)
++ cntlzw rBITDIF, rBITDIF
++ cntlzw rNEG, rNEG
++ addi rNEG, rNEG, 7
++ cmpw cr1, rNEG, rBITDIF
++ sub rRTN, rWORD1, rWORD2
++ bgelr+ cr1
++L(equal):
++ li rRTN, 0
++ blr
++
++L(different):
++ lwz rWORD1, -4(rSTR1)
++ xor. rBITDIF, rWORD1, rWORD2
++ sub rRTN, rWORD1, rWORD2
++ bgelr+
++L(highbit):
++ ori rRTN, rWORD2, 1
++ blr
++#endif
++
++/* Oh well. In this case, we just do a byte-by-byte comparison. */
++ .align 4
++L(unaligned):
++ lbz rWORD1, 0(rSTR1)
++ lbz rWORD2, 0(rSTR2)
++ b L(u1)
++
++L(u0): lbzu rWORD1, 1(rSTR1)
++ bne- L(u4)
++ lbzu rWORD2, 1(rSTR2)
++L(u1): cmpwi cr1, rWORD1, 0
++ beq- cr1, L(u3)
++ cmpw rWORD1, rWORD2
++ bne- L(u3)
++ lbzu rWORD1, 1(rSTR1)
++ lbzu rWORD2, 1(rSTR2)
++ cmpwi cr1, rWORD1, 0
++ cmpw rWORD1, rWORD2
++ bne+ cr1, L(u0)
++L(u3): sub rRTN, rWORD1, rWORD2
++ blr
++L(u4): lbz rWORD1, -1(rSTR1)
++ sub rRTN, rWORD1, rWORD2
++ blr
++END (strcmp)
++libc_hidden_builtin_def (strcmp)
+diff -Naur libc/sysdeps/powerpc/powerpc64/e5500/strcmp.S libc-strcmp/sysdeps/powerpc/powerpc64/e5500/strcmp.S
+--- libc/sysdeps/powerpc/powerpc64/e5500/strcmp.S 1969-12-31 18:00:00.000000000 -0600
++++ libc-strcmp/sysdeps/powerpc/powerpc64/e5500/strcmp.S 2014-12-15 09:42:46.247951902 -0600
+@@ -0,0 +1,176 @@
++/* Optimized strcmp implementation for PowerPC64.
++ Copyright (C) 1997-2014 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, see
++ <http://www.gnu.org/licenses/>. */
++
++#include <sysdep.h>
++
++/* See strlen.s for comments on how the end-of-string testing works. */
++
++/* int [r3] strcmp (const char *s1 [r3], const char *s2 [r4]) */
++
++EALIGN (strcmp, 4, 0)
++ CALL_MCOUNT 2
++
++#define rTMP2 r0
++#define rRTN r3
++#define rSTR1 r3 /* first string arg */
++#define rSTR2 r4 /* second string arg */
++#define rWORD1 r5 /* current word in s1 */
++#define rWORD2 r6 /* current word in s2 */
++#define rFEFE r7 /* constant 0xfefefefefefefeff (-0x0101010101010101) */
++#define r7F7F r8 /* constant 0x7f7f7f7f7f7f7f7f */
++#define rNEG r9 /* ~(word in s1 | 0x7f7f7f7f7f7f7f7f) */
++#define rBITDIF r10 /* bits that differ in s1 & s2 words */
++#define rTMP r11
++
++ dcbt 0,rSTR1
++ or rTMP, rSTR2, rSTR1
++ dcbt 0,rSTR2
++ clrldi. rTMP, rTMP, 61
++ lis rFEFE, -0x101
++ bne L(unaligned)
++
++ ld rWORD1, 0(rSTR1)
++ ld rWORD2, 0(rSTR2)
++ lis r7F7F, 0x7f7f
++ addi rFEFE, rFEFE, -0x101
++ addi r7F7F, r7F7F, 0x7f7f
++ sldi rTMP, rFEFE, 32
++ insrdi r7F7F, r7F7F, 32, 0
++ add rFEFE, rFEFE, rTMP
++ b L(g1)
++
++L(g0): ldu rWORD1, 8(rSTR1)
++ bne cr1, L(different)
++ ldu rWORD2, 8(rSTR2)
++L(g1): add rTMP, rFEFE, rWORD1
++ nor rNEG, r7F7F, rWORD1
++ and. rTMP, rTMP, rNEG
++ cmpd cr1, rWORD1, rWORD2
++ beq+ L(g0)
++
++/* OK. We've hit the end of the string. We need to be careful that
++ we don't compare two strings as different because of gunk beyond
++ the end of the strings... */
++#ifdef __LITTLE_ENDIAN__
++L(endstring):
++ addi rTMP2, rTMP, -1
++ beq cr1, L(equal)
++ andc rTMP2, rTMP2, rTMP
++ rldimi rTMP2, rTMP2, 1, 0
++ and rWORD2, rWORD2, rTMP2 /* Mask off gunk. */
++ and rWORD1, rWORD1, rTMP2
++ cmpd cr1, rWORD1, rWORD2
++ beq cr1, L(equal)
++ xor rBITDIF, rWORD1, rWORD2 /* rBITDIF has bits that differ. */
++ neg rNEG, rBITDIF
++ and rNEG, rNEG, rBITDIF /* rNEG has LS bit that differs. */
++ cntlzd rNEG, rNEG /* bitcount of the bit. */
++ andi. rNEG, rNEG, 56 /* bitcount to LS byte that differs. */
++ sld rWORD1, rWORD1, rNEG /* shift left to clear MS bytes. */
++ sld rWORD2, rWORD2, rNEG
++ xor. rBITDIF, rWORD1, rWORD2
++ sub rRTN, rWORD1, rWORD2
++ blt- L(highbit)
++ sradi rRTN, rRTN, 63 /* must return an int. */
++ ori rRTN, rRTN, 1
++ blr
++L(equal):
++ li rRTN, 0
++ blr
++
++L(different):
++ ld rWORD1, -8(rSTR1)
++ xor rBITDIF, rWORD1, rWORD2 /* rBITDIF has bits that differ. */
++ neg rNEG, rBITDIF
++ and rNEG, rNEG, rBITDIF /* rNEG has LS bit that differs. */
++ cntlzd rNEG, rNEG /* bitcount of the bit. */
++ andi. rNEG, rNEG, 56 /* bitcount to LS byte that differs. */
++ sld rWORD1, rWORD1, rNEG /* shift left to clear MS bytes. */
++ sld rWORD2, rWORD2, rNEG
++ xor. rBITDIF, rWORD1, rWORD2
++ sub rRTN, rWORD1, rWORD2
++ blt- L(highbit)
++ sradi rRTN, rRTN, 63
++ ori rRTN, rRTN, 1
++ blr
++L(highbit):
++ sradi rRTN, rWORD2, 63
++ ori rRTN, rRTN, 1
++ blr
++
++#else
++L(endstring):
++ and rTMP, r7F7F, rWORD1
++ beq cr1, L(equal)
++ add rTMP, rTMP, r7F7F
++ xor. rBITDIF, rWORD1, rWORD2
++ andc rNEG, rNEG, rTMP
++ blt- L(highbit)
++ cntlzd rBITDIF, rBITDIF
++ cntlzd rNEG, rNEG
++ addi rNEG, rNEG, 7
++ cmpd cr1, rNEG, rBITDIF
++ sub rRTN, rWORD1, rWORD2
++ blt- cr1, L(equal)
++ sradi rRTN, rRTN, 63 /* must return an int. */
++ ori rRTN, rRTN, 1
++ blr
++L(equal):
++ li rRTN, 0
++ blr
++
++L(different):
++ ld rWORD1, -8(rSTR1)
++ xor. rBITDIF, rWORD1, rWORD2
++ sub rRTN, rWORD1, rWORD2
++ blt- L(highbit)
++ sradi rRTN, rRTN, 63
++ ori rRTN, rRTN, 1
++ blr
++L(highbit):
++ sradi rRTN, rWORD2, 63
++ ori rRTN, rRTN, 1
++ blr
++#endif
++
++/* Oh well. In this case, we just do a byte-by-byte comparison. */
++ .align 4
++L(unaligned):
++ lbz rWORD1, 0(rSTR1)
++ lbz rWORD2, 0(rSTR2)
++ b L(u1)
++
++L(u0): lbzu rWORD1, 1(rSTR1)
++ bne- L(u4)
++ lbzu rWORD2, 1(rSTR2)
++L(u1): cmpwi cr1, rWORD1, 0
++ beq- cr1, L(u3)
++ cmpd rWORD1, rWORD2
++ bne- L(u3)
++ lbzu rWORD1, 1(rSTR1)
++ lbzu rWORD2, 1(rSTR2)
++ cmpdi cr1, rWORD1, 0
++ cmpd rWORD1, rWORD2
++ bne+ cr1, L(u0)
++L(u3): sub rRTN, rWORD1, rWORD2
++ blr
++L(u4): lbz rWORD1, -1(rSTR1)
++ sub rRTN, rWORD1, rWORD2
++ blr
++END (strcmp)
++libc_hidden_builtin_def (strcmp)
+diff -Naur libc-strcmp/sysdeps/powerpc/powerpc32/e5500/strcmp.S libc-strcmp-dhry/sysdeps/powerpc/powerpc32/e5500/strcmp.S
+--- libc-strcmp/sysdeps/powerpc/powerpc32/e5500/strcmp.S 2014-12-15 09:42:36.119952087 -0600
++++ libc-strcmp-dhry/sysdeps/powerpc/powerpc32/e5500/strcmp.S 2014-12-15 09:46:03.771951808 -0600
+@@ -49,9 +49,12 @@
+ addi r7F7F, r7F7F, 0x7f7f
+ b L(g1)
+
+-L(g0): lwzu rWORD1, 4(rSTR1)
++ .align 4
++L(g0): lwz rWORD1, 4(rSTR1)
++ addi rSTR1, rSTR1, 4
+ bne cr1, L(different)
+- lwzu rWORD2, 4(rSTR2)
++ lwz rWORD2, 4(rSTR2)
++ addi rSTR2, rSTR2, 4
+ L(g1): add rTMP, rFEFE, rWORD1
+ nor rNEG, r7F7F, rWORD1
+ and. rTMP, rTMP, rNEG
+diff -Naur libc/sysdeps/powerpc/powerpc64/e5500/strcmp.S libc-strcmp/sysdeps/powerpc/powerpc64/e5500/strcmp.S
+--- libc/sysdeps/powerpc/powerpc64/e5500/strcmp.S 2015-01-19 04:07:33.660173151 -0600
++++ libc-strcmp/sysdeps/powerpc/powerpc64/e5500/strcmp.S 2015-01-19 04:09:38.115175293 -0600
+@@ -56,7 +56,8 @@
+
+ L(g0): ldu rWORD1, 8(rSTR1)
+ bne cr1, L(different)
+- ldu rWORD2, 8(rSTR2)
++ ld rWORD2, 8(rSTR2)
++ addi rSTR2, rSTR2, 8
+ L(g1): add rTMP, rFEFE, rWORD1
+ nor rNEG, r7F7F, rWORD1
+ and. rTMP, rTMP, rNEG
diff --git a/recipes-core/glibc/glibc-fsl/0014.glibc.fsl-strchr-e500mc-e5500.patch b/recipes-core/glibc/glibc-fsl/0014.glibc.fsl-strchr-e500mc-e5500.patch
new file mode 100755
index 0000000..f864afc
--- /dev/null
+++ b/recipes-core/glibc/glibc-fsl/0014.glibc.fsl-strchr-e500mc-e5500.patch
@@ -0,0 +1,659 @@
+# Problem Statement:
+ Implement target specific optimized strchr for e500mc & e5500 32-bit.
+
+# Owned by:
+ Mahesh [based on existing 'asm' implementation of eglibc strchr]
+
+# Actions:
+ * For e500mc target, default glibc implementation was reading
+ two words at a time. Current implementation unrolls the loop to
+ read sixteen words.
+
+ * For e5500 [32-bit] target, use cmpb instruction to check the occurance
+ of NULL and expected character in a string.
+
+ * Reordered the instruction to get the better performance
+
+ * Got time out error with e5500 (32-bit) target on eglibc test suite.
+ Didn't find any degradation with our performance tests.
+ So updating TIMEOUT boundary to 10.
+
+diff -Naur vanilla/string/stratcliff.c patched/string/stratcliff.c
+--- vanilla/string/stratcliff.c 2015-03-12 05:07:11.970952217 -0500
++++ patched/string/stratcliff.c 2015-03-12 05:18:29.166952009 -0500
+@@ -18,6 +18,7 @@
+ <http://www.gnu.org/licenses/>. */
+
+ #define _GNU_SOURCE 1
++#define TIMEOUT 10
+
+ /* Make sure we don't test the optimized inline functions if we want to
+ test the real implementation. */
+diff -Naur vanilla/sysdeps/powerpc/powerpc32/e500mc/strchr.S patched/sysdeps/powerpc/powerpc32/e500mc/strchr.S
+--- vanilla/sysdeps/powerpc/powerpc32/e500mc/strchr.S 1969-12-31 18:00:00.000000000 -0600
++++ patched/sysdeps/powerpc/powerpc32/e500mc/strchr.S 2015-03-12 06:05:35.086952070 -0500
+@@ -0,0 +1,307 @@
++/* Optimized strchr implementation for 32-bit e500mc PowerPC target.
++ Based on generic 32-bit PowerPC strchr implementation.
++ Copyright (C) 1997-2015 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, see
++ <http://www.gnu.org/licenses/>. */
++
++#include <sysdep.h>
++
++/* See strlen.s for comments on how this works. */
++
++/* char * [r3] strchr (const char *s [r3] , int c [r4]) */
++
++ENTRY (strchr)
++
++#define rTMP1 r0
++#define rRTN r3 /* outgoing result. */
++#define rSTR r8 /* current word pointer. */
++#define rCHR r4 /* byte we are looking for, spread over the
++ whole word. */
++#define rWORD r5 /* the current word. */
++#define rCLZB rCHR /* leading zero byte count. */
++#define rFEFE r6 /* constant 0xfefefeff (-0x01010101). */
++#define r7F7F r7 /* constant 0x7f7f7f7f. */
++#define rTMP2 r9
++#define rIGN r10 /* the number of bits we should ignore in the
++ first word. */
++#define rMASK r11 /* mask with the bits to ignore set to rTMP1. */
++#define rTMP3 r12
++
++ andi. rTMP2, rRTN, 3
++ clrrwi rSTR, rRTN, 2
++ rlwimi rCHR, rCHR, 8, 16, 23
++ rlwimi rCHR, rCHR, 16, 0, 15
++ lis rFEFE, -0x101
++ lis r7F7F, 0x7f7f
++ addi rFEFE, rFEFE, -0x101
++ addi r7F7F, r7F7F, 0x7f7f
++ beq L(srcalign)
++ lwz rWORD, 0(rSTR)
++ li rMASK, -1
++ rlwinm rIGN, rRTN, 3, 27, 28
++ srw rMASK, rMASK, rIGN
++ orc rWORD, rWORD, rMASK
++ add rTMP1, rFEFE, rWORD
++ xor rTMP3, rCHR, rWORD
++ nor rTMP2, r7F7F, rWORD
++ orc rTMP3, rTMP3, rMASK
++ and. rTMP1, rTMP1, rTMP2
++ add rTMP1, rFEFE, rTMP3
++ bne L(missed)
++ b L(loop)
++L(srcalign):
++ /* Test the first (partial?) word. */
++ lwz rWORD, 0(rSTR)
++ add rTMP1, rFEFE, rWORD
++ xor rTMP3, rCHR, rWORD
++ nor rTMP2, r7F7F, rWORD
++ and. rTMP1, rTMP1, rTMP2
++ add rTMP1, rFEFE, rTMP3
++ bne L(missed)
++ /* The loop. */
++L(loop):
++ lwzu rWORD, 4(rSTR)
++ nor rTMP2, r7F7F, rTMP3
++ and. rTMP1, rTMP1, rTMP2
++ bne L(foundit)
++ add rTMP1, rFEFE, rWORD
++ /* Test for 0. */
++ nor rTMP2, r7F7F, rWORD
++ xor rTMP3, rCHR, rWORD
++ and. rTMP1, rTMP1, rTMP2
++ add rTMP1, rFEFE, rTMP3
++ bne L(missed)
++ /* Start test for the bytes we're looking for. */
++ nor rTMP2, r7F7F, rTMP3
++ lwzu rWORD, 4(rSTR)
++ and. rTMP1, rTMP1, rTMP2
++ bne L(foundit)
++ add rIGN, rFEFE, rWORD
++ /* Test for 0. */
++ nor rTMP2, r7F7F, rWORD
++ xor rTMP3, rCHR, rWORD
++ and. rTMP1, rIGN, rTMP2
++ add rTMP1, rFEFE, rTMP3
++ bne L(missed)
++ /* Start test for the bytes we're looking for. */
++ lwzu rWORD, 4(rSTR)
++ nor rTMP2, r7F7F, rTMP3
++ and. rTMP1, rTMP1, rTMP2
++ bne L(foundit)
++ add rTMP1, rFEFE, rWORD
++ /* Test for 0. */
++ nor rTMP2, r7F7F, rWORD
++ xor rTMP3, rCHR, rWORD
++ and. rTMP1, rTMP1, rTMP2
++ add rTMP1, rFEFE, rTMP3
++ bne L(missed)
++ /* Start test for the bytes we're looking for. */
++ nor rTMP2, r7F7F, rTMP3
++ lwzu rWORD, 4(rSTR)
++ and. rTMP1, rTMP1, rTMP2
++ bne L(foundit)
++ add rIGN, rFEFE, rWORD
++ /* Test for 0. */
++ nor rTMP2, r7F7F, rWORD
++ xor rTMP3, rCHR, rWORD
++ and. rTMP1, rIGN, rTMP2
++ add rTMP1, rFEFE, rTMP3
++ bne L(missed)
++ /* Start test for the bytes we're looking for. */
++ lwzu rWORD, 4(rSTR)
++ nor rTMP2, r7F7F, rTMP3
++ and. rTMP1, rTMP1, rTMP2
++ bne L(foundit)
++ add rTMP1, rFEFE, rWORD
++ /* Test for 0. */
++ nor rTMP2, r7F7F, rWORD
++ xor rTMP3, rCHR, rWORD
++ and. rTMP1, rTMP1, rTMP2
++ add rTMP1, rFEFE, rTMP3
++ bne L(missed)
++ /* Start test for the bytes we're looking for. */
++ nor rTMP2, r7F7F, rTMP3
++ lwzu rWORD, 4(rSTR)
++ and. rTMP1, rTMP1, rTMP2
++ bne L(foundit)
++ add rIGN, rFEFE, rWORD
++ /* Test for 0. */
++ nor rTMP2, r7F7F, rWORD
++ xor rTMP3, rCHR, rWORD
++ and. rTMP1, rIGN, rTMP2
++ add rTMP1, rFEFE, rTMP3
++ bne L(missed)
++ /* Start test for the bytes we're looking for. */
++ lwzu rWORD, 4(rSTR)
++ nor rTMP2, r7F7F, rTMP3
++ and. rTMP1, rTMP1, rTMP2
++ bne L(foundit)
++ add rTMP1, rFEFE, rWORD
++ /* Test for 0. */
++ nor rTMP2, r7F7F, rWORD
++ xor rTMP3, rCHR, rWORD
++ and. rTMP1, rTMP1, rTMP2
++ add rTMP1, rFEFE, rTMP3
++ bne L(missed)
++ /* Start test for the bytes we're looking for. */
++ nor rTMP2, r7F7F, rTMP3
++ lwzu rWORD, 4(rSTR)
++ and. rTMP1, rTMP1, rTMP2
++ bne L(foundit)
++ add rIGN, rFEFE, rWORD
++ /* Test for 0. */
++ nor rTMP2, r7F7F, rWORD
++ xor rTMP3, rCHR, rWORD
++ and. rTMP1, rIGN, rTMP2
++ add rTMP1, rFEFE, rTMP3
++ bne L(missed)
++ /* Start test for the bytes we're looking for. */
++ lwzu rWORD, 4(rSTR)
++ nor rTMP2, r7F7F, rTMP3
++ and. rTMP1, rTMP1, rTMP2
++ bne L(foundit)
++ add rTMP1, rFEFE, rWORD
++ /* Test for 0. */
++ nor rTMP2, r7F7F, rWORD
++ xor rTMP3, rCHR, rWORD
++ and. rTMP1, rTMP1, rTMP2
++ add rTMP1, rFEFE, rTMP3
++ bne L(missed)
++ /* Start test for the bytes we're looking for. */
++ nor rTMP2, r7F7F, rTMP3
++ lwzu rWORD, 4(rSTR)
++ and. rTMP1, rTMP1, rTMP2
++ bne L(foundit)
++ add rIGN, rFEFE, rWORD
++ /* Test for 0. */
++ nor rTMP2, r7F7F, rWORD
++ xor rTMP3, rCHR, rWORD
++ and. rTMP1, rIGN, rTMP2
++ add rTMP1, rFEFE, rTMP3
++ bne L(missed)
++ /* Start test for the bytes we're looking for. */
++ lwzu rWORD, 4(rSTR)
++ nor rTMP2, r7F7F, rTMP3
++ and. rTMP1, rTMP1, rTMP2
++ bne L(foundit)
++ add rTMP1, rFEFE, rWORD
++ /* Test for 0. */
++ nor rTMP2, r7F7F, rWORD
++ xor rTMP3, rCHR, rWORD
++ and. rTMP1, rTMP1, rTMP2
++ add rTMP1, rFEFE, rTMP3
++ bne L(missed)
++ /* Start test for the bytes we're looking for. */
++ nor rTMP2, r7F7F, rTMP3
++ lwzu rWORD, 4(rSTR)
++ and. rTMP1, rTMP1, rTMP2
++ bne L(foundit)
++ add rIGN, rFEFE, rWORD
++ /* Test for 0. */
++ nor rTMP2, r7F7F, rWORD
++ xor rTMP3, rCHR, rWORD
++ and. rTMP1, rIGN, rTMP2
++ add rTMP1, rFEFE, rTMP3
++ bne L(missed)
++ /* Start test for the bytes we're looking for. */
++ lwzu rWORD, 4(rSTR)
++ nor rTMP2, r7F7F, rTMP3
++ and. rTMP1, rTMP1, rTMP2
++ bne L(foundit)
++ add rTMP1, rFEFE, rWORD
++ /* Test for 0. */
++ nor rTMP2, r7F7F, rWORD
++ xor rTMP3, rCHR, rWORD
++ and. rTMP1, rTMP1, rTMP2
++ add rTMP1, rFEFE, rTMP3
++ bne L(missed)
++ /* Start test for the bytes we're looking for. */
++ nor rTMP2, r7F7F, rTMP3
++ lwzu rWORD, 4(rSTR)
++ and. rTMP1, rTMP1, rTMP2
++ bne L(foundit)
++ add rIGN, rFEFE, rWORD
++ /* Test for 0. */
++ nor rTMP2, r7F7F, rWORD
++ xor rTMP3, rCHR, rWORD
++ and. rTMP1, rIGN, rTMP2
++ add rTMP1, rFEFE, rTMP3
++ bne L(missed)
++ /* Start test for the bytes we're looking for. */
++ lwzu rWORD, 4(rSTR)
++ nor rTMP2, r7F7F, rTMP3
++ and. rTMP1, rTMP1, rTMP2
++ bne L(foundit)
++ add rTMP1, rFEFE, rWORD
++ /* Test for 0. */
++ nor rTMP2, r7F7F, rWORD
++ xor rTMP3, rCHR, rWORD
++ and. rTMP1, rTMP1, rTMP2
++ add rTMP1, rFEFE, rTMP3
++ bne L(missed)
++ /* Start test for the bytes we're looking for. */
++ nor rTMP2, r7F7F, rTMP3
++ lwzu rWORD, 4(rSTR)
++ and. rTMP1, rTMP1, rTMP2
++ bne L(foundit)
++ add rIGN, rFEFE, rWORD
++ /* Test for 0. */
++ nor rTMP2, r7F7F, rWORD
++ xor rTMP3, rCHR, rWORD
++ and. rTMP1, rIGN, rTMP2
++ add rTMP1, rFEFE, rTMP3
++ beq L(loop)
++ /* There is a zero byte in the word, but may also be a matching
++ byte (either before or after the zero byte). In fact, we may be
++ looking for a zero byte, in which case we return a match. We
++ guess that this hasn't happened, though. */
++L(missed):
++ nor rTMP2, r7F7F, rTMP3
++ and. rTMP1, rTMP1, rTMP2
++ li rRTN, 0
++ beqlr
++ /* It did happen. Decide which one was first...
++ I'm not sure if this is actually faster than a sequence of rotates,
++ compares, and branches (we use it anyway because it's shorter). */
++ and rFEFE, r7F7F, rWORD
++ or rMASK, r7F7F, rWORD
++ and rTMP1, r7F7F, rTMP3
++ or rIGN, r7F7F, rTMP3
++ add rFEFE, rFEFE, r7F7F
++ add rTMP1, rTMP1, r7F7F
++ nor rWORD, rMASK, rFEFE
++ nor rTMP2, rIGN, rTMP1
++ cmplw rWORD, rTMP2
++ cntlzw rCLZB, rTMP2
++ bgtlr
++ srwi rCLZB, rCLZB, 3
++ add rRTN, rSTR, rCLZB
++ blr
++L(foundit):
++ and rTMP1, r7F7F, rTMP3
++ or rIGN, r7F7F, rTMP3
++ add rTMP1, rTMP1, r7F7F
++ nor rTMP2, rIGN, rTMP1
++ cntlzw rCLZB, rTMP2
++ subi rSTR, rSTR, 4
++ srwi rCLZB, rCLZB, 3
++ add rRTN, rSTR, rCLZB
++ blr
++
++END (strchr)
++
++weak_alias (strchr, index)
++libc_hidden_builtin_def (strchr)
+diff -Naur vanilla/sysdeps/powerpc/powerpc32/e5500/strchr.S patched/sysdeps/powerpc/powerpc32/e5500/strchr.S
+--- vanilla/sysdeps/powerpc/powerpc32/e5500/strchr.S 1969-12-31 18:00:00.000000000 -0600
++++ patched/sysdeps/powerpc/powerpc32/e5500/strchr.S 2015-03-12 06:06:26.507951923 -0500
+@@ -0,0 +1,313 @@
++/* Optimized strchr implementation for 32-bit e5500 PowerPC target.
++ Based on POWER7 strchr implementation.
++
++ Copyright (C) 2010-2015 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, see
++ <http://www.gnu.org/licenses/>. */
++
++#include <sysdep.h>
++
++/* See strlen.s for comments on how this works. */
++
++/* char * [r3] strchr (const char *s [r3] , int c [r4]) */
++
++ENTRY (strchr)
++
++#define rTMP1 r0
++#define rRTN r3 /* outgoing result. */
++#define rSTR r8 /* current word pointer. */
++#define rCHR r4 /* byte we are looking for, spread over the
++ whole word. */
++#define rTMP2 r5
++#define rMASK r6 /* calculate padding bits. */
++#define rTMP3 r7
++#define rWORD r12 /* the current word. */
++#define rWORD2 r9 /* following word. */
++#define rTMP4 r10
++#define rTMP5 r11
++
++ dcbt 0, rRTN
++ andi. rTMP3, rRTN, 7 /* check for double word boundary. */
++ cmpwi cr7, rCHR, 0
++ li rTMP1, 0
++ /* Replicate byte to double word. */
++ rlwimi rCHR, rCHR, 8, 16, 23
++ rlwimi rCHR, rCHR, 16, 0, 15
++ beq L(dwalign)
++ subfic rTMP3, rTMP3, 8
++ cmplwi cr6, rTMP3, 4
++ clrrwi rSTR, rRTN, 2 /* Align the address to the word
++ boundary. */
++ beq cr6, L(word2)
++ blt cr6, L(LTword2)
++ lwz rWORD, 0(rSTR) /* Load word from memory. */
++ rlwinm rMASK, rRTN, 3, 27, 28 /* Calculate padding. */
++ /* Now rCHR has a word of c bytes and rTMP1 has
++ a word of null bytes. */
++ beq cr7, L(null_match)
++ cmpb rTMP4, rWORD, rCHR /* Compare each byte with c byte. */
++ cmpb rTMP5, rWORD, rTMP1 /* Compare each byte
++ against null byte. */
++ /* Move the words left and right to discard the bits that are not
++ part of the string and to bring them back as zeros. */
++ slw rTMP4, rTMP4, rMASK
++ slw rTMP5, rTMP5, rMASK
++ srw rTMP4, rTMP4, rMASK
++ srw rTMP5, rTMP5, rMASK
++ or rTMP2, rTMP4, rTMP5 /* OR results to speed things up. */
++ cmpwi cr7, rTMP2, 0 /* If rTMP2 == 0, no c or null bytes
++ have been found. */
++ bne cr7, L(done)
++ /* Handle WORD2 of pair. */
++ lwzu rWORD, 4(rSTR)
++ cmpb rTMP4, rWORD, rCHR
++ cmpb rTMP5, rWORD, rTMP1
++ or rTMP2, rTMP4, rTMP5
++ cmpwi cr7, rTMP2, 0
++ bne cr7, L(done)
++ b L(loop) /* We branch here (rather than falling
++ through) to skip the nops due to
++ heavy alignment of loop below. */
++L(LTword2):
++ lwz rWORD, 0(rSTR) /* Load word from memory. */
++ rlwinm rMASK, rRTN, 3, 27, 28 /* Calculate padding. */
++ /* Now rCHR has a word of c bytes and rTMP1 has
++ a word of null bytes. */
++ beq cr7, L(null_LTword2)
++ cmpb rTMP4, rWORD, rCHR /* Compare each byte with c byte. */
++ cmpb rTMP5, rWORD, rTMP1 /* Compare each byte
++ against null byte. */
++ /* Move the words left and right to discard the bits that are not
++ part of the string and to bring them back as zeros. */
++ slw rTMP4, rTMP4, rMASK
++ slw rTMP5, rTMP5, rMASK
++ srw rTMP4, rTMP4, rMASK
++ srw rTMP5, rTMP5, rMASK
++ or rTMP2, rTMP4, rTMP5 /* OR results to speed things up. */
++ cmpwi cr7, rTMP2, 0 /* If rTMP2 == 0, no c or null bytes
++ have been found. */
++ bne cr7, L(done)
++ lwz rWORD, 4(rSTR)
++ lwzu rWORD2, 8(rSTR)
++ cmpb rTMP4, rWORD, rCHR
++ cmpb rTMP5, rWORD, rTMP1
++ cmpb rMASK, rWORD2, rCHR
++ cmpb rTMP3, rWORD2, rTMP1
++ or rWORD, rTMP4, rTMP5
++ or rWORD2, rMASK, rTMP3
++ or rTMP2, rWORD, rWORD2
++ cmpwi cr7, rTMP2, 0
++ beq cr7, L(loop)
++ /* OK, one (or both) of the words contains a c/null byte. Check
++ the first word and decrement the address in case the first
++ word really contains a c/null byte. */
++ cmpwi cr6, rWORD, 0
++ addi rSTR, rSTR, -4
++ bne cr6, L(done)
++ /* The c/null byte must be in the second word. Adjust the address
++ again and move the result of cmpb to rTMP4 so we can calculate the
++ pointer. */
++ mr rTMP4, rMASK
++ mr rTMP5, rTMP3
++ addi rSTR, rSTR, 4
++ bne cr7, L(done)
++L(word2):
++ lwz rWORD, 0(rSTR)
++ beq cr7, L(null_word2)
++ cmpb rTMP4, rWORD, rCHR
++ cmpb rTMP5, rWORD, rTMP1
++ or rTMP2, rTMP4, rTMP5
++ cmpwi cr7, rTMP2, 0
++ bne cr7, L(done)
++ b L(loop)
++L(dwalign):
++ /* Load two words, compare and merge in a single register for speed.
++ This is an attempt to speed up the null-checking process for
++ bigger strings. */
++ mr rSTR, rRTN
++ lwz rWORD, 0(rSTR)
++ lwzu rWORD2, 4(rSTR)
++ beq cr7, L(dwalignnull)
++ cmpb rTMP4, rWORD, rCHR
++ cmpb rTMP5, rWORD, rTMP1
++ cmpb rMASK, rWORD2, rCHR
++ cmpb rTMP3, rWORD2, rTMP1
++ or rWORD, rTMP4, rTMP5
++ or rWORD2, rMASK, rTMP3
++ or rTMP2, rWORD, rWORD2
++ cmpwi cr7, rTMP2, 0
++ beq cr7, L(loop)
++ /* OK, one (or both) of the words contains a c/null byte. Check
++ the first word and decrement the address in case the first word
++ really contains a c/null byte. */
++ cmpwi cr6, rWORD, 0
++ addi rSTR, rSTR, -4
++ bne cr6, L(done)
++ /* The c/null byte must be in the second word. Adjust the address
++ again and move the result of cmpb to rTMP4 so we can calculate the
++ pointer. */
++ mr rTMP4, rMASK
++ mr rTMP5, rTMP3
++ addi rSTR, rSTR, 4
++ /* rTMP2 has the output of the cmpb instruction, that is, it contains
++ 0xff in the same position as the c/null byte in the original
++ word from the string. Use that to calculate the pointer. */
++ b L(done)
++L(loop):
++ /* Load two words, compare and merge in a single register for speed.
++ This is an attempt to speed up the null-checking process for
++ bigger strings. */
++ lwz rWORD, 4(rSTR)
++ lwzu rWORD2, 8(rSTR)
++ cmpb rTMP4, rWORD, rCHR
++ cmpb rTMP5, rWORD, rTMP1
++ cmpb rMASK, rWORD2, rCHR
++ cmpb rTMP3, rWORD2, rTMP1
++ or rWORD, rTMP4, rTMP5
++ or rWORD2, rMASK, rTMP3
++ or rTMP2, rWORD, rWORD2
++ cmpwi cr7, rTMP2, 0
++ beq cr7, L(loop)
++ /* OK, one (or both) of the words contains a c/null byte. Check
++ the first word and decrement the address in case the first word
++ really contains a c/null byte. */
++ cmpwi cr6, rWORD, 0
++ addi rSTR, rSTR, -4
++ bne cr6, L(done)
++ /* The c/null byte must be in the second word. Adjust the address
++ again and move the result of cmpb to rTMP4 so we can calculate the
++ pointer. */
++ mr rTMP4, rMASK
++ mr rTMP5, rTMP3
++ addi rSTR, rSTR, 4
++ /* rTMP2 has the output of the cmpb instruction, that is, it contains
++ 0xff in the same position as the c/null byte in the original word
++ from the string. Use that to calculate the pointer. */
++L(done):
++ cntlzw rCHR, rTMP4 /* Count leading zeroes until
++ the c matches. */
++ cntlzw rTMP1, rTMP5 /* Count leading zeroes until
++ the null matches. */
++ cmplw cr7, rCHR, rTMP1
++ bgt cr7, L(no_match)
++ srwi rTMP1, rCHR, 3 /* Convert leading zeroes to bytes. */
++ add rRTN, rSTR, rTMP1 /* Return addr of the matching c byte
++ or null in case c was not found. */
++ blr
++L(no_match):
++ li rRTN, 0
++ blr
++ /* We are here because strchr was called with a null byte. */
++L(null_match):
++ /* rTMP1 has a word of null bytes. */
++ cmpb rTMP2, rWORD, rTMP1 /* Compare each byte against null
++ bytes. */
++ /* Move the words left and right to discard the bits that are
++ not part of the string and to bring them back as zeros. */
++ slw rTMP2, rTMP2, rMASK
++ srw rTMP2, rTMP2, rMASK
++ cmpwi cr7, rTMP2, 0 /* If rTMP4 == 0, no c or null bytes
++ have been found. */
++ bne cr7, L(done_null)
++ /* Handle WORD2 of pair. */
++ lwzu rWORD, 4(rSTR)
++ cmpb rTMP2, rWORD, rTMP1
++ cmpwi cr7, rTMP2, 0
++ bne cr7, L(done_null)
++ b L(loop_null) /* We branch here (rather than falling
++ through) to skip the nops due to
++ heavy alignment of loop below. */
++L(null_LTword2):
++ /* rTMP1 has a word of null bytes. */
++ cmpb rTMP2, rWORD, rTMP1 /* Compare each byte against null
++ bytes. */
++ /* Move the words left and right to discard the bits that are
++ not part of the string and to bring them back as zeros. */
++ slw rTMP2, rTMP2, rMASK
++ srw rTMP2, rTMP2, rMASK
++ cmpwi cr7, rTMP2, 0 /* If rTMP4 == 0, no c or null bytes
++ have been found. */
++ bne cr7, L(done_null)
++ b L(loop_null)
++L(null_word2):
++ /* Handle WORD2 of pair. */
++ cmpb rTMP2, rWORD, rTMP1
++ cmpwi cr7, rTMP2, 0
++ bne cr7, L(done_null)
++ b L(loop_null) /* We branch here (rather than falling
++ through) to skip the nops due to
++ heavy alignment of loop below. */
++L(dwalignnull):
++ /* Load two words, compare and merge in a single register for speed.
++ This is an attempt to speed up the null-checking process for
++ bigger strings. */
++ cmpb rTMP2, rWORD, rTMP1
++ cmpb rTMP4, rWORD2, rTMP1
++ or rMASK, rTMP2, rTMP4
++ cmpwi cr7, rMASK, 0
++ beq cr7, L(loop_null)
++ /* OK, one (or both) of the words contains a null byte. Check the
++ first word and decrement the address in case the first word really
++ contains a null byte. */
++ cmpwi cr6, rTMP2, 0
++ addi rSTR, rSTR, -4
++ bne cr6, L(done_null)
++ /* The null byte must be in the second word. Adjust the address
++ again and move the result of cmpb to rTMP4 so we can calculate the
++ pointer. */
++ mr rTMP2, rTMP4
++ addi rSTR, rSTR, 4
++ /* rTMP2 has the output of the cmpb instruction, that is, it contains
++ 0xff in the same position as the null byte in the original
++ word from the string. Use that to calculate the pointer. */
++ b L(done_null)
++L(loop_null):
++ /* Load two words, compare and merge in a single register for speed.
++ This is an attempt to speed up the null-checking process for
++ bigger strings. */
++ lwz rWORD, 4(rSTR)
++ lwzu rTMP5, 8(rSTR)
++ cmpb rTMP2, rWORD, rTMP1
++ cmpb rTMP4, rTMP5, rTMP1
++ or rMASK, rTMP2, rTMP4
++ cmpwi cr7, rMASK, 0
++ beq cr7, L(loop_null)
++ /* OK, one (or both) of the words contains a null byte. Check the
++ first word and decrement the address in case the first word really
++ contains a null byte. */
++ cmpwi cr6, rTMP2, 0
++ addi rSTR, rSTR, -4
++ bne cr6, L(done_null)
++ /* The null byte must be in the second word. Adjust the address
++ again and move the result of cmpb to rTMP4 so we can calculate the
++ pointer. */
++ mr rTMP2, rTMP4
++ addi rSTR, rSTR, 4
++ /* rTMP2 has the output of the cmpb instruction, that is, it contains
++ 0xff in the same position as the null byte in the original word
++ from the string. Use that to calculate the pointer. */
++L(done_null):
++ cntlzw rTMP1, rTMP2 /* Count leading zeros before the
++ match. */
++ srwi rTMP1, rTMP1, 3 /* Convert leading zeros to bytes. */
++ add rRTN, rSTR, rTMP1 /* Return address of the matching
++ null byte. */
++ blr
++
++END (strchr)
++
++weak_alias (strchr, index)
++libc_hidden_builtin_def (strchr)
diff --git a/recipes-core/glibc/glibc-fsl/0015.glibc.fsl-strcpy-e500mc-e5500.patch b/recipes-core/glibc/glibc-fsl/0015.glibc.fsl-strcpy-e500mc-e5500.patch
new file mode 100755
index 0000000..17dd029
--- /dev/null
+++ b/recipes-core/glibc/glibc-fsl/0015.glibc.fsl-strcpy-e500mc-e5500.patch
@@ -0,0 +1,627 @@
+# Problem Statement:
+ Implement target specific optimized strcpy for e500mc,32-bit e5500,
+ 64-bit e5500
+
+# Owned by:
+ Ajay [based on existing 'asm' implementation of glibc]
+
+# Actions:
+ * For e500mc and e5500 [32-bit and 64-bit] targets, there is a slight
+ improvement in the performance for aligned data.
+
+ * For e500mc and e5500 [32-bit and 64-bit] targets, there is a appreciable
+ improvement in the performance [approx. 64% in case of e500mc and 32-bit
+ e5500 and 78% in case of 64-bit e5500] for non-aligned data.
+
+ * Rev2:
+ a) e5500 64-bit: Fixed "segmentation fault" issues for strcpy with eglibc
+ v2.15 test suite for unaligned data.
+
+diff -Naur vanilla/sysdeps/powerpc/powerpc32/e500mc/strcpy.S patched/sysdeps/powerpc/powerpc32/e500mc/strcpy.S
+--- vanilla/sysdeps/powerpc/powerpc32/e500mc/strcpy.S 1969-12-31 18:00:00.000000000 -0600
++++ patched/sysdeps/powerpc/powerpc32/e500mc/strcpy.S 2015-03-14 08:14:13.094951983 -0500
+@@ -0,0 +1,186 @@
++/* Optimized strcpy implementation for PowerPC e500mc target.
++ Based on generic 32-bit PowerPC strcpy implementation.
++ Copyright (C) 1997-2015 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, see
++ <http://www.gnu.org/licenses/>. */
++
++#include <sysdep.h>
++
++/* See strlen.s for comments on how the end-of-string testing works. */
++
++/* char * [r3] strcpy (char *dest [r3], const char *src [r4]) */
++
++EALIGN (strcpy, 4, 0)
++
++#define rTMP r0
++#define rRTN r3 /* incoming DEST arg preserved as result. */
++#define rSRC r4 /* pointer to previous word in src. */
++#define rDEST r5 /* pointer to previous word in dest. */
++#define rWORD1 r6 /* word from src. */
++#define rFEFE r7 /* constant 0xfefefeff (-0x01010101). */
++#define r7F7F r8 /* constant 0x7f7f7f7f. */
++#define rNEG r9 /* ~(word in s1 | 0x7f7f7f7f). */
++#define rTMP1 r9
++#define rWORD2 r10 /* word from src. */
++#define rWORD3 r11
++#define rWORD4 r12
++
++ andi. rTMP, rSRC, 0x03
++ bne L(src_unaligned)
++L(aligned):
++ addi rDEST, rRTN, -4
++ lis rFEFE, -0x101
++ lis r7F7F, 0x7f7f
++ lwz rWORD2, 0(rSRC)
++ addi rFEFE, rFEFE, -0x101
++ addi r7F7F, r7F7F, 0x7f7f
++ add rTMP, rFEFE, rWORD2
++ nor rNEG, r7F7F, rWORD2
++ and. rTMP, rTMP, rNEG
++ bne L(move_register_10)
++L(loop_for_aligned):
++ lwzu rWORD1, 4(rSRC)
++ stwu rWORD2, 4(rDEST)
++ add rTMP, rFEFE, rWORD1
++ nor rNEG, r7F7F, rWORD1
++ and. rTMP, rTMP, rNEG
++ bne L(copy_rest_bytes)
++ lwzu rWORD2, 4(rSRC)
++ stwu rWORD1, 4(rDEST)
++L(g2):
++ add rTMP, rFEFE, rWORD2
++ nor rNEG, r7F7F, rWORD2
++ and. rTMP, rTMP, rNEG
++ beq+ L(loop_for_aligned)
++
++L(move_register_10):
++ mr rWORD1, rWORD2
++ /* We've hit the end of the string. Do the rest byte-by-byte. */
++L(copy_rest_bytes):
++ rlwinm. rTMP, rWORD1, 8, 24, 31
++ stb rTMP, 4(rDEST)
++ beqlr
++ rlwinm. rTMP, rWORD1, 16, 24, 31
++ stb rTMP, 5(rDEST)
++ beqlr
++ rlwinm. rTMP, rWORD1, 24, 24, 31
++ stb rTMP, 6(rDEST)
++ beqlr
++ stb rWORD1, 7(rDEST)
++ blr
++ /* end of already aligned src. */
++L(src_got_aligned):
++ lis r7F7F, 0x7f7f
++ lwz rWORD1, 0(rSRC)
++ lis rFEFE, -0x101
++ addi rFEFE, rFEFE, -0x101
++ addi r7F7F, r7F7F, 0x7f7f
++ add rTMP, rFEFE, rWORD1
++ nor rNEG, r7F7F, rWORD1
++ and. rTMP, rTMP, rNEG
++ bne L(copy_rest_bytes_for_unaligned)
++ lwzu rWORD2, 4(rSRC)
++ stw rWORD1, 0(rDEST)
++ add rTMP, rFEFE, rWORD2
++ nor rNEG, r7F7F, rWORD2
++ and. rTMP, rTMP, rNEG
++ addi rDEST, rDEST, 4
++ bne L(move_register_10_for_unaligned)
++L(loop_for_nonaligned):
++ lwz rWORD1, 4(rSRC)
++ stw rWORD2, 0(rDEST)
++ add rTMP, rFEFE, rWORD1
++ nor rNEG, r7F7F, rWORD1
++ and. rTMP, rTMP, rNEG
++ addi rDEST, rDEST, 4
++ bne L(copy_rest_bytes_for_unaligned)
++ lwzu rWORD2, 8(rSRC)
++ stw rWORD1, 0(rDEST)
++ add rTMP, rFEFE, rWORD2
++ nor rNEG, r7F7F, rWORD2
++ and. rTMP, rTMP, rNEG
++ addi rDEST, rDEST, 4
++ bne L(move_register_10_for_unaligned)
++ lwz rWORD3, 4(rSRC)
++ stw rWORD2, 0(rDEST)
++ add rTMP, rFEFE, rWORD3
++ nor rNEG, r7F7F, rWORD3
++ and. rTMP, rTMP, rNEG
++ addi rDEST, rDEST, 4
++ bne L(move_register_11)
++ lwzu rWORD4, 8(rSRC)
++ stw rWORD3, 0(rDEST)
++ add rTMP, rFEFE, rWORD4
++ nor rNEG, r7F7F, rWORD4
++ and. rTMP, rTMP, rNEG
++ addi rDEST, rDEST, 4
++ bne L(move_register_12)
++ lwzu rWORD2, 4(rSRC)
++ stw rWORD4, 0(rDEST)
++ add rTMP, rFEFE, rWORD2
++ nor rNEG, r7F7F, rWORD2
++ and. rTMP, rTMP, rNEG
++ addi rDEST, rDEST, 4
++ beq L(loop_for_nonaligned)
++L(move_register_10_for_unaligned):
++ mr rWORD1, rWORD2
++L(copy_rest_bytes_for_unaligned):
++ rlwinm. rTMP, rWORD1, 8, 24, 31
++ stb rTMP, 0(rDEST)
++ beqlr
++ rlwinm. rTMP, rWORD1, 16, 24, 31
++ stb rTMP, 1(rDEST)
++ beqlr
++ rlwinm. rTMP, rWORD1, 24, 24, 31
++ stb rTMP, 2(rDEST)
++ beqlr
++ stb rWORD1, 3(rDEST)
++ blr
++L(move_register_11):
++ mr rWORD1, rWORD3
++ b L(copy_rest_bytes_for_unaligned)
++L(move_register_12):
++ mr rWORD1, rWORD4
++ b L(copy_rest_bytes_for_unaligned)
++L(src_unaligned):
++ lbz rWORD1, 0(rSRC)
++ addi rDEST, rRTN, 0
++ cmpwi rWORD1, 0x0
++ stb rWORD1, 0(rDEST)
++ beq L(endstrcpy)
++ lbz rWORD2, 1(rSRC)
++ cmpwi rWORD2, 0x0
++ stb rWORD2, 1(rDEST)
++ beq L(endstrcpy)
++ lbz rWORD3, 2(rSRC)
++ cmpwi rWORD3, 0x0
++ stb rWORD3, 2(rDEST)
++ beq L(endstrcpy)
++ lbz rWORD2, 3(rSRC)
++ cmpwi rWORD2, 0x0
++ beq L(endstrcpy1)
++ li rTMP1, 4
++ sub rTMP1, rTMP1, rTMP
++ add rSRC, rSRC, rTMP1
++ add rDEST, rDEST, rTMP1
++ b L(src_got_aligned)
++L(endstrcpy1):
++ stb rWORD2, 3(rDEST)
++L(endstrcpy):
++ blr
++
++END (strcpy)
++libc_hidden_builtin_def (strcpy)
+diff -Naur vanilla/sysdeps/powerpc/powerpc32/e5500/strcpy.S patched/sysdeps/powerpc/powerpc32/e5500/strcpy.S
+--- vanilla/sysdeps/powerpc/powerpc32/e5500/strcpy.S 1969-12-31 18:00:00.000000000 -0600
++++ patched/sysdeps/powerpc/powerpc32/e5500/strcpy.S 2015-03-14 08:14:52.103951985 -0500
+@@ -0,0 +1,180 @@
++/* Optimized strcpy implementation for 32-bit e5500 PowerPC target.
++ Based on generic 32-bit PowerPC strcpy implementation.
++ Copyright (C) 1997-2015 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, see
++ <http://www.gnu.org/licenses/>. */
++
++#include <sysdep.h>
++
++/* See strlen.s for comments on how the end-of-string testing works. */
++
++/* char * [r3] strcpy (char *dest [r3], const char *src [r4]) */
++
++EALIGN (strcpy, 4, 0)
++
++#define rTMP r0
++#define rRTN r3 /* incoming DEST arg preserved as result. */
++#define rSRC r4 /* pointer to previous word in src. */
++#define rDEST r5 /* pointer to previous word in dest. */
++#define rWORD1 r6 /* word from src. */
++#define rFEFE r7 /* constant 0xfefefeff (-0x01010101). */
++#define r7F7F r8 /* constant 0x7f7f7f7f. */
++#define rNEG r9 /* ~(word in s1 | 0x7f7f7f7f). */
++#define rTMP1 r9
++#define rWORD2 r10 /* word from src. */
++#define rWORD3 r11
++#define rWORD4 r12
++
++ andi. rTMP, rSRC, 0x03
++ bne L(src_unaligned)
++ addi rDEST, rRTN, -4
++ lis rFEFE, -0x101
++ lis r7F7F, 0x7f7f
++ lwz rWORD2, 0(rSRC)
++ addi rFEFE, rFEFE, -0x101
++ addi r7F7F, r7F7F, 0x7f7f
++ b L(g2)
++L(g0):
++ lwzu rWORD1, 4(rSRC)
++ stwu rWORD2, 4(rDEST)
++ add rTMP, rFEFE, rWORD1
++ nor rNEG, r7F7F, rWORD1
++ and. rTMP, rTMP, rNEG
++ bne L(g1)
++ lwzu rWORD2, 4(rSRC)
++ stwu rWORD1, 4(rDEST)
++L(g2):
++ add rTMP, rFEFE, rWORD2
++ nor rNEG, r7F7F, rWORD2
++ and. rTMP, rTMP, rNEG
++ beq L(g0)
++ mr rWORD1, rWORD2
++ /* We've hit the end of the string. Do the rest byte-by-byte. */
++L(g1):
++ rlwinm. rTMP, rWORD1, 8, 24, 31
++ stb rTMP, 4(rDEST)
++ beqlr
++ rlwinm. rTMP, rWORD1, 16, 24, 31
++ stb rTMP, 5(rDEST)
++ beqlr
++ rlwinm. rTMP, rWORD1, 24, 24, 31
++ stb rTMP, 6(rDEST)
++ beqlr
++ stb rWORD1, 7(rDEST)
++ blr
++ /* end of already aligned src. */
++L(src_got_aligned):
++ lis r7F7F, 0x7f7f
++ lwz rWORD1, 0(rSRC)
++ lis rFEFE, -0x101
++ addi rFEFE, rFEFE, -0x101
++ addi r7F7F, r7F7F, 0x7f7f
++ add rTMP, rFEFE, rWORD1
++ nor rNEG, r7F7F, rWORD1
++ and. rTMP, rTMP, rNEG
++ bne L(copy_rest_bytes_for_unaligned)
++ lwzu rWORD2, 4(rSRC)
++ stw rWORD1, 0(rDEST)
++ add rTMP, rFEFE, rWORD2
++ nor rNEG, r7F7F, rWORD2
++ and. rTMP, rTMP, rNEG
++ addi rDEST, rDEST, 4
++ bne L(move_register_10_for_unaligned)
++L(loop_for_nonaligned):
++ lwz rWORD1, 4(rSRC)
++ stw rWORD2, 0(rDEST)
++ add rTMP, rFEFE, rWORD1
++ nor rNEG, r7F7F, rWORD1
++ and. rTMP, rTMP, rNEG
++ addi rDEST, rDEST, 4
++ bne L(copy_rest_bytes_for_unaligned)
++ lwzu rWORD2, 8(rSRC)
++ stw rWORD1, 0(rDEST)
++ add rTMP, rFEFE, rWORD2
++ nor rNEG, r7F7F, rWORD2
++ and. rTMP, rTMP, rNEG
++ addi rDEST, rDEST, 4
++ bne L(move_register_10_for_unaligned)
++ lwz rWORD3, 4(rSRC)
++ stw rWORD2, 0(rDEST)
++ add rTMP, rFEFE, rWORD3
++ nor rNEG, r7F7F, rWORD3
++ and. rTMP, rTMP, rNEG
++ addi rDEST, rDEST, 4
++ bne L(move_register_11)
++ lwzu rWORD4, 8(rSRC)
++ stw rWORD3, 0(rDEST)
++ add rTMP, rFEFE, rWORD4
++ nor rNEG, r7F7F, rWORD4
++ and. rTMP, rTMP, rNEG
++ addi rDEST, rDEST, 4
++ bne L(move_register_12)
++ lwzu rWORD2, 4(rSRC)
++ stw rWORD4, 0(rDEST)
++ add rTMP, rFEFE, rWORD2
++ nor rNEG, r7F7F, rWORD2
++ and. rTMP, rTMP, rNEG
++ addi rDEST, rDEST, 4
++ beq L(loop_for_nonaligned)
++L(move_register_10_for_unaligned):
++ mr rWORD1, rWORD2
++L(copy_rest_bytes_for_unaligned):
++ rlwinm. rTMP, rWORD1, 8, 24, 31
++ stb rTMP, 0(rDEST)
++ beqlr
++ rlwinm. rTMP, rWORD1, 16, 24, 31
++ stb rTMP, 1(rDEST)
++ beqlr
++ rlwinm. rTMP, rWORD1, 24, 24, 31
++ stb rTMP, 2(rDEST)
++ beqlr
++ stb rWORD1, 3(rDEST)
++ blr
++L(move_register_11):
++ mr rWORD1, rWORD3
++ b L(copy_rest_bytes_for_unaligned)
++L(move_register_12):
++ mr rWORD1, rWORD4
++ b L(copy_rest_bytes_for_unaligned)
++L(src_unaligned):
++ lbz rWORD1, 0(rSRC)
++ addi rDEST, rRTN, 0
++ cmpwi rWORD1, 0x0
++ stb rWORD1, 0(rDEST)
++ beq L(endstrcpy)
++ lbz rWORD2, 1(rSRC)
++ cmpwi rWORD2, 0x0
++ stb rWORD2, 1(rDEST)
++ beq L(endstrcpy)
++ lbz rWORD3, 2(rSRC)
++ cmpwi rWORD3, 0x0
++ stb rWORD3, 2(rDEST)
++ beq L(endstrcpy)
++ lbz rWORD2, 3(rSRC)
++ cmpwi rWORD2, 0x0
++ beq L(endstrcpy1)
++ li rTMP1, 4
++ sub rTMP1, rTMP1, rTMP
++ add rSRC, rSRC, rTMP1
++ add rDEST, rDEST, rTMP1
++ b L(src_got_aligned)
++L(endstrcpy1):
++ stb rWORD2, 3(rDEST)
++L(endstrcpy):
++ blr
++
++END (strcpy)
++libc_hidden_builtin_def (strcpy)
+diff -Naur vanilla/sysdeps/powerpc/powerpc64/e5500/strcpy.S patched/sysdeps/powerpc/powerpc64/e5500/strcpy.S
+--- vanilla/sysdeps/powerpc/powerpc64/e5500/strcpy.S 1969-12-31 18:00:00.000000000 -0600
++++ patched/sysdeps/powerpc/powerpc64/e5500/strcpy.S 2015-03-14 08:16:17.828951956 -0500
+@@ -0,0 +1,230 @@
++/* Optimized strcpy implementation for 64-bit e5500 PowerPC target.
++ Based on generic 64-bit PowerPC strcpy implementation.
++ Copyright (C) 1997-2015 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, see
++ <http://www.gnu.org/licenses/>. */
++
++#include <sysdep.h>
++
++/* See strlen.s for comments on how the end-of-string testing works. */
++
++/* char * [r3] strcpy (char *dest [r3], const char *src [r4]) */
++
++EALIGN (strcpy, 4, 0)
++ CALL_MCOUNT 2
++
++#define rTMP r0
++#define rRTN r3
++#define rSRC r4 /* pointer to previous word in src. */
++#define rDEST r5 /* pointer to previous word in dest. */
++#define rWORD1 r6 /* word from src. */
++#define rFEFE r7 /* constant value 0xfefefefefefefeff
++ (-0x0101010101010101). */
++#define r7F7F r8 /* constant 0x7f7f7f7f7f7f7f7f. */
++#define rNEG r9 /* ~(word in s1 | 0x7f7f7f7f7f7f7f7f). */
++#define rTMP1 r9
++#define rWORD2 r10 /* word from src. */
++#define rWORD3 r11
++#define rWORD4 r12
++
++ dcbt 0, rSRC
++ andi. rTMP, rSRC, 0x07
++ dcbtst 0, rRTN
++ bne L(src_unaligned)
++ addi rDEST, rRTN, -8
++ lis rFEFE, -0x101
++ lis r7F7F, 0x7f7f
++ ld rWORD1, 0(rSRC)
++ addi rFEFE, rFEFE, -0x101
++ addi r7F7F, r7F7F, 0x7f7f
++ sldi rTMP, rFEFE, 32
++ insrdi r7F7F, r7F7F, 32, 0
++ add rFEFE, rFEFE, rTMP
++ b L(g2)
++L(g0):
++ ldu rWORD2, 8(rSRC)
++ stdu rWORD1, 8(rDEST)
++ add rTMP, rFEFE, rWORD2
++ nor rNEG, r7F7F, rWORD2
++ and. rTMP, rTMP, rNEG
++ bne- L(g1)
++ ldu rWORD1, 8(rSRC)
++ stdu rWORD2, 8(rDEST)
++L(g2):
++ add rTMP, rFEFE, rWORD1
++ nor rNEG, r7F7F, rWORD1
++ and. rTMP, rTMP, rNEG
++ beq+ L(g0)
++ mr rWORD2, rWORD1
++ /* We've hit the end of the string. Do the rest byte-by-byte. */
++L(g1):
++ extrdi. rTMP, rWORD2, 8, 0
++ stb rTMP, 8(rDEST)
++ beqlr
++ extrdi. rTMP, rWORD2, 8, 8
++ stb rTMP, 9(rDEST)
++ beqlr
++ extrdi. rTMP, rWORD2, 8, 16
++ stb rTMP, 10(rDEST)
++ beqlr
++ extrdi. rTMP, rWORD2, 8, 24
++ stb rTMP, 11(rDEST)
++ beqlr
++ extrdi. rTMP, rWORD2, 8, 32
++ stb rTMP, 12(rDEST)
++ beqlr
++ extrdi. rTMP, rWORD2, 8, 40
++ stb rTMP, 13(rDEST)
++ beqlr
++ extrdi. rTMP, rWORD2, 8, 48
++ stb rTMP, 14(rDEST)
++ beqlr
++ stb rWORD2, 15(rDEST)
++ blr
++ /* end of already aligned src. */
++L(src_got_aligned):
++ lis r7F7F, 0x7f7f
++ lis rFEFE, -0x101
++ addi rFEFE, rFEFE, -0x101
++ ld rWORD1, 0(rSRC)
++ addi r7F7F, r7F7F, 0x7f7f
++ sldi rTMP, rFEFE, 32
++ insrdi r7F7F, r7F7F, 32, 0
++ add rFEFE, rFEFE, rTMP
++ add rTMP, rFEFE, rWORD1
++ nor rNEG, r7F7F, rWORD1
++ and. rTMP, rTMP, rNEG
++ bne L(copy_rest_bytes_for_unaligned)
++ ldu rWORD2, 8(rSRC)
++ std rWORD1, 0(rDEST)
++ add rTMP, rFEFE, rWORD2
++ nor rNEG, r7F7F, rWORD2
++ and. rTMP, rTMP, rNEG
++ addi rDEST, rDEST, 8
++ bne L(move_register_10_for_unaligned)
++L(loop_for_nonaligned):
++ ld rWORD1, 8(rSRC)
++ std rWORD2, 0(rDEST)
++ add rTMP, rFEFE, rWORD1
++ nor rNEG, r7F7F, rWORD1
++ and. rTMP, rTMP, rNEG
++ addi rDEST, rDEST, 8
++ bne L(copy_rest_bytes_for_unaligned)
++ ldu rWORD2, 16(rSRC)
++ std rWORD1, 0(rDEST)
++ add rTMP, rFEFE, rWORD2
++ nor rNEG, r7F7F, rWORD2
++ and. rTMP, rTMP, rNEG
++ addi rDEST, rDEST, 8
++ bne L(move_register_10_for_unaligned)
++ ld rWORD3, 8(rSRC)
++ std rWORD2, 0(rDEST)
++ add rTMP, rFEFE, rWORD3
++ nor rNEG, r7F7F, rWORD3
++ and. rTMP, rTMP, rNEG
++ addi rDEST, rDEST, 8
++ bne L(move_register_11)
++ ldu rWORD4, 16(rSRC)
++ std rWORD3, 0(rDEST)
++ add rTMP, rFEFE, rWORD4
++ nor rNEG, r7F7F, rWORD4
++ and. rTMP, rTMP, rNEG
++ addi rDEST, rDEST, 8
++ bne L(move_register_12)
++ ldu rWORD2, 8(rSRC)
++ std rWORD4, 0(rDEST)
++ add rTMP, rFEFE, rWORD2
++ nor rNEG, r7F7F, rWORD2
++ and. rTMP, rTMP, rNEG
++ addi rDEST, rDEST, 8
++ beq L(loop_for_nonaligned)
++L(move_register_10_for_unaligned):
++ mr rWORD1, rWORD2
++L(copy_rest_bytes_for_unaligned):
++ extrdi. rTMP, rWORD1, 8, 0
++ stb rTMP, 0(rDEST)
++ beqlr
++ extrdi. rTMP, rWORD1, 8, 8
++ stb rTMP, 1(rDEST)
++ beqlr
++ extrdi. rTMP, rWORD1, 8, 16
++ stb rTMP, 2(rDEST)
++ beqlr
++ extrdi. rTMP, rWORD1, 8, 24
++ stb rTMP, 3(rDEST)
++ beqlr
++ extrdi. rTMP, rWORD1, 8, 32
++ stb rTMP, 4(rDEST)
++ beqlr
++ extrdi. rTMP, rWORD1, 8, 40
++ stb rTMP, 5(rDEST)
++ beqlr
++ extrdi. rTMP, rWORD1, 8, 48
++ stb rTMP, 6(rDEST)
++ beqlr
++ stb rWORD1, 7(rDEST)
++ blr
++L(move_register_11):
++ mr rWORD1, rWORD3
++ b L(copy_rest_bytes_for_unaligned)
++L(move_register_12):
++ mr rWORD1, rWORD4
++ b L(copy_rest_bytes_for_unaligned)
++L(src_unaligned):
++ lbz rWORD1, 0(rSRC)
++ addi rDEST, rRTN, 0
++ cmpwi rWORD1, 0
++ stb rWORD1, 0(rDEST)
++ beq L(endstrcpy)
++ lbz rWORD2, 1(rSRC)
++ cmpwi rWORD2, 0
++ stb rWORD2, 1(rDEST)
++ beq L(endstrcpy)
++ lbz rWORD3, 2(rSRC)
++ cmpwi rWORD3, 0
++ stb rWORD3, 2(rDEST)
++ beq L(endstrcpy)
++ lbz rWORD2, 3(rSRC)
++ cmpwi rWORD2, 0
++ stb rWORD2, 3(rDEST)
++ beq L(endstrcpy)
++ lbz rWORD1, 4(rSRC)
++ cmpwi rWORD1, 0
++ stb rWORD1, 4(rDEST)
++ beq L(endstrcpy)
++ lbz rWORD3, 5(rSRC)
++ cmpwi rWORD3, 0
++ stb rWORD3, 5(rDEST)
++ beq L(endstrcpy)
++ lbz rWORD3, 6(rSRC)
++ cmpwi rWORD3, 0
++ stb rWORD3, 6(rDEST)
++ beq L(endstrcpy)
++ lbz rWORD2, 7(rSRC)
++ cmpwi rWORD2, 0
++ beq L(endstrcpy1)
++ li rTMP1, 8
++ sub rTMP1, rTMP1, rTMP
++ add rSRC, rSRC, rTMP1
++ add rDEST, rDEST, rTMP1
++ b L(src_got_aligned)
++L(endstrcpy1):
++ stb rWORD2, 7(rDEST)
++L(endstrcpy):
++ blr
++
++END (strcpy)
++libc_hidden_builtin_def (strcpy)
diff --git a/recipes-core/glibc/glibc-fsl/0016-Remove-bash-dependency-for-nscd-init-script.patch b/recipes-core/glibc/glibc-fsl/0016-Remove-bash-dependency-for-nscd-init-script.patch
new file mode 100644
index 0000000..1d9983b
--- /dev/null
+++ b/recipes-core/glibc/glibc-fsl/0016-Remove-bash-dependency-for-nscd-init-script.patch
@@ -0,0 +1,75 @@
+From 69d378001adfe9a359d2f4b069c1ed2d36de4480 Mon Sep 17 00:00:00 2001
+From: Khem Raj <raj.khem at gmail.com>
+Date: Thu, 31 Dec 2015 14:33:02 -0800
+Subject: [PATCH 16/25] Remove bash dependency for nscd init script
+
+The nscd init script uses #! /bin/bash but only really uses one bashism
+(translated strings), so remove them and switch the shell to #!/bin/sh.
+
+Upstream-Status: Pending
+
+Signed-off-by: Ross Burton <ross.burton at intel.com>
+Signed-off-by: Khem Raj <raj.khem at gmail.com>
+---
+ nscd/nscd.init | 14 +++++++-------
+ 1 file changed, 7 insertions(+), 7 deletions(-)
+
+diff --git a/nscd/nscd.init b/nscd/nscd.init
+index a882da7d8b..b02986ec15 100644
+--- a/nscd/nscd.init
++++ b/nscd/nscd.init
+@@ -1,4 +1,4 @@
+-#!/bin/bash
++#!/bin/sh
+ #
+ # nscd: Starts the Name Switch Cache Daemon
+ #
+@@ -49,7 +49,7 @@ prog=nscd
+ start () {
+ [ -d /var/run/nscd ] || mkdir /var/run/nscd
+ [ -d /var/db/nscd ] || mkdir /var/db/nscd
+- echo -n $"Starting $prog: "
++ echo -n "Starting $prog: "
+ daemon /usr/sbin/nscd
+ RETVAL=$?
+ echo
+@@ -58,7 +58,7 @@ start () {
+ }
+
+ stop () {
+- echo -n $"Stopping $prog: "
++ echo -n "Stopping $prog: "
+ /usr/sbin/nscd -K
+ RETVAL=$?
+ if [ $RETVAL -eq 0 ]; then
+@@ -67,9 +67,9 @@ stop () {
+ # a non-privileged user
+ rm -f /var/run/nscd/nscd.pid
+ rm -f /var/run/nscd/socket
+- success $"$prog shutdown"
++ success "$prog shutdown"
+ else
+- failure $"$prog shutdown"
++ failure "$prog shutdown"
+ fi
+ echo
+ return $RETVAL
+@@ -103,13 +103,13 @@ case "$1" in
+ RETVAL=$?
+ ;;
+ force-reload | reload)
+- echo -n $"Reloading $prog: "
++ echo -n "Reloading $prog: "
+ killproc /usr/sbin/nscd -HUP
+ RETVAL=$?
+ echo
+ ;;
+ *)
+- echo $"Usage: $0 {start|stop|status|restart|reload|condrestart}"
++ echo "Usage: $0 {start|stop|status|restart|reload|condrestart}"
+ RETVAL=1
+ ;;
+ esac
+--
+2.13.2
+
diff --git a/recipes-core/glibc/glibc-fsl/0016.glibc.fsl-strlen-e500mc-e5500.patch b/recipes-core/glibc/glibc-fsl/0016.glibc.fsl-strlen-e500mc-e5500.patch
new file mode 100755
index 0000000..e8844c4
--- /dev/null
+++ b/recipes-core/glibc/glibc-fsl/0016.glibc.fsl-strlen-e500mc-e5500.patch
@@ -0,0 +1,407 @@
+# Problem Statement:
+ Implement target specific optimized strlen for e500mc,
+ 64-bit e5500
+
+# Owned by:
+ Ajay [based on existing 'asm' implementation of glibc]
+
+# Actions:
+ * For e500mc and e5500 [64-bit] targets,glibc implementation was reading
+ two words at a time,I have unrolled the loop to read four words at a time.
+
+ * Reordered the instruction to get the better performance.
+
+ * Rev2:
+ a) e500mc and e5500 64-bit: Fixed "segmentation fault" issues for strlen
+ with eglibc v2.15 test suite.
+ b) added e5500 32-bit strlen optimized library.
+ c) e5500 (32 & 64-bit) optimized strlen referenced from eglibc v2.19
+ power7 implementation
+
+diff -Naur vanilla/sysdeps/powerpc/powerpc32/e500mc/strlen.S patched/sysdeps/powerpc/powerpc32/e500mc/strlen.S
+--- vanilla/sysdeps/powerpc/powerpc32/e500mc/strlen.S 1969-12-31 18:00:00.000000000 -0600
++++ patched/sysdeps/powerpc/powerpc32/e500mc/strlen.S 2015-03-12 07:37:15.310952010 -0500
+@@ -0,0 +1,168 @@
++/* Optimized strlen implementation for 32-bit e500mc PowerPC target.
++ Based on generic 32-bit PowerPC strlen implementation.
++ Copyright (C) 1997-2015 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, see
++ <http://www.gnu.org/licenses/>. */
++
++#include <sysdep.h>
++
++/* The algorithm here uses the following techniques:
++
++ 1) Given a word 'x', we can test to see if it contains any 0 bytes
++ by subtracting 0x01010101, and seeing if any of the high bits of each
++ byte changed from 0 to 1. This works because the least significant
++ 0 byte must have had no incoming carry (otherwise it's not the least
++ significant), so it is 0x00 - 0x01 == 0xff. For all other
++ byte values, either they have the high bit set initially, or when
++ 1 is subtracted you get a value in the range 0x00-0x7f, none of which
++ have their high bit set. The expression here is
++ (x + 0xfefefeff) & ~(x | 0x7f7f7f7f), which gives 0x00000000 when
++ there were no 0x00 bytes in the word. You get 0x80 in bytes that
++ match, but possibly false 0x80 matches in the next more significant
++ byte to a true match due to carries. For little-endian this is
++ of no consequence since the least significant match is the one
++ we're interested in, but big-endian needs method 2 to find which
++ byte matches.
++
++ 2) Given a word 'x', we can test to see _which_ byte was zero by
++ calculating ~(((x & 0x7f7f7f7f) + 0x7f7f7f7f) | x | 0x7f7f7f7f).
++ This produces 0x80 in each byte that was zero, and 0x00 in all
++ the other bytes. The '| 0x7f7f7f7f' clears the low 7 bits in each
++ byte, and the '| x' part ensures that bytes with the high bit set
++ produce 0x00. The addition will carry into the high bit of each byte
++ iff that byte had one of its low 7 bits set. We can then just see
++ which was the most significant bit set and divide by 8 to find how
++ many to add to the index.
++ This is from the book 'The PowerPC Compiler Writer's Guide',
++ by Steve Hoxey, Faraydon Karim, Bill Hay and Hank Warren.
++
++ We deal with strings not aligned to a word boundary by taking the
++ first word and ensuring that bytes not part of the string
++ are treated as nonzero. To allow for memory latency, we unroll the
++ loop a few times, being careful to ensure that we do not read ahead
++ across cache line boundaries.
++
++ Questions to answer:
++ 1) How long are strings passed to strlen? If they're often really long,
++ we should probably use cache management instructions and/or unroll the
++ loop more. If they're often quite short, it might be better to use
++ fact (2) in the inner loop than have to recalculate it.
++ 2) How popular are bytes with the high bit set? If they are very rare,
++ on some processors it might be useful to use the simpler expression
++ ~((x - 0x01010101) | 0x7f7f7f7f) (that is, on processors with only one
++ ALU), but this fails when any character has its high bit set. */
++
++/* Some notes on register usage: Under the SVR4 ABI, we can use registers
++ 0 and 3 through 12 (so long as we don't call any procedures) without
++ saving them. We can also use registers 14 through 31 if we save them.
++ We can't use r1 (it's the stack pointer), r2 nor r13 because the user
++ program may expect them to hold their usual value if we get sent
++ a signal. Integer parameters are passed in r3 through r10.
++ We can use condition registers cr0, cr1, cr5, cr6, and cr7 without saving
++ them, the others we must save. */
++
++/* int [r3] strlen (char *s [r3]) */
++
++ENTRY (strlen)
++
++#define rTMP1 r0
++#define rRTN r3 /* incoming STR arg, outgoing result. */
++#define rSTR r4 /* current string position. */
++#define rPADN r5 /* number of padding bits we prepend to the
++ string to make it start at a word boundary. */
++#define rTMP3 r5
++#define rFEFE r6 /* constant 0xfefefeff (-0x01010101). */
++#define r7F7F r7 /* constant 0x7f7f7f7f. */
++#define rWORD1 r8 /* current string word. */
++#define rWORD2 r9 /* next string word. */
++#define rMASK r9 /* mask for first string word. */
++#define rTMP2 r10
++
++ clrrwi rSTR, rRTN, 2
++ lis r7F7F, 0x7f7f
++ rlwinm rPADN, rRTN, 3, 27, 28
++ lwz rWORD1, 0(rSTR)
++ li rMASK, -1
++ addi r7F7F, r7F7F, 0x7f7f
++ /* That's the setup done, now do the first pair of words.
++ We make an exception and use method (2) on the first two words, to
++ reduce overhead. */
++ srw rMASK, rMASK, rPADN
++ and rTMP1, r7F7F, rWORD1
++ or rTMP2, r7F7F, rWORD1
++ add rTMP1, rTMP1, r7F7F
++ nor rTMP1, rTMP2, rTMP1
++ and. rWORD1, rTMP1, rMASK
++ mtcrf 0x01, rRTN
++ bne L(done0)
++ lis rFEFE, -0x101
++ addi rFEFE, rFEFE, -0x101
++ /* Are we now aligned to a double word boundary? */
++ bt 29, L(loop)
++ /* Handle second word of pair. */
++ lwzu rWORD1, 4(rSTR)
++ and rTMP1, r7F7F, rWORD1
++ or rTMP2, r7F7F, rWORD1
++ add rTMP1, rTMP1, r7F7F
++ nor. rWORD1, rTMP2, rTMP1
++ bne L(done0)
++ /* The loop. */
++L(loop):
++ lwz rWORD1, 4(rSTR)
++ lwzu rWORD2, 8(rSTR)
++ add rTMP1, rFEFE, rWORD1
++ nor rTMP2, r7F7F, rWORD1
++ and. rTMP1, rTMP1, rTMP2
++ add rTMP1, rFEFE, rWORD2
++ bne L(done1)
++ nor rTMP2, r7F7F, rWORD2
++ and. rTMP1, rTMP1, rTMP2
++ bne L(address)
++ lwz rWORD1, 4(rSTR)
++ lwzu rWORD2, 8(rSTR)
++ add rTMP1, rFEFE, rWORD1
++ nor rTMP2, r7F7F, rWORD1
++ and. rTMP1, rTMP1, rTMP2
++ add rTMP1, rFEFE, rWORD2
++ bne L(done1)
++ nor rTMP2, r7F7F, rWORD2
++ and. rTMP1, rTMP1, rTMP2
++ beq L(loop)
++ and rTMP1, r7F7F, rWORD2
++ add rTMP1, rTMP1, r7F7F
++ andc rWORD1, rTMP2, rTMP1
++ b L(done0)
++L(address):
++ mr rWORD1, rWORD2
++ addi rSTR, rSTR, 4
++L(done1):
++ and rTMP1, r7F7F, rWORD1
++ subi rSTR, rSTR, 4
++ add rTMP1, rTMP1, r7F7F
++ andc rWORD1, rTMP2, rTMP1
++ /* When we get to here, rSTR points to the first word in the string
++ that contains a zero byte, and the most significant set bit in
++ rWORD1 is in that byte. */
++L(done0):
++ cntlzw rTMP3, rWORD1
++ subf rTMP1, rRTN, rSTR
++ srwi rTMP3, rTMP3, 3
++ add rRTN, rTMP1, rTMP3
++ /* GKM FIXME: check high bound. */
++ blr
++
++END (strlen)
++libc_hidden_builtin_def (strlen)
+diff -Naur vanilla/sysdeps/powerpc/powerpc32/e5500/strlen.S patched/sysdeps/powerpc/powerpc32/e5500/strlen.S
+--- vanilla/sysdeps/powerpc/powerpc32/e5500/strlen.S 1969-12-31 18:00:00.000000000 -0600
++++ patched/sysdeps/powerpc/powerpc32/e5500/strlen.S 2015-03-12 07:40:07.346952026 -0500
+@@ -0,0 +1,123 @@
++/* Optimized strlen implementation for 32-bit e5500 PowerPC target.
++ Based on POWER7 strlen implementation.
++ Copyright (C) 2010-2015 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, see
++ <http://www.gnu.org/licenses/>. */
++
++#include <sysdep.h>
++
++/* int [r3] strlen (char *s [r3]) */
++
++ENTRY (strlen)
++
++ clrrwi r4, r3, 2 /* Align the address to word boundary. */
++ rlwinm r6, r3, 3, 27, 28 /* Calculate padding. */
++ li r0, 0 /* Word with null chars to use with cmpb. */
++ li r5, -1 /* MASK = 0xffffffffffffffff. */
++ lwz r12, 0(r4) /* Load word from memory. */
++ srw r5, r5, r6 /* MASK = MASK >> padding. */
++ orc r9, r12, r5 /* Mask bits that are
++ not part of the string. */
++ cmpb r10, r9, r0 /* Check for null bytes in WORD1. */
++ cmpwi cr7, r10, 0 /* If r10 == 0, no null's have been found. */
++ bne cr7, L(done)
++ /* Are we now aligned to a four word boundary? If so, skip to the
++ main loop. Otherwise, go through the alignment code. */
++ mtcrf 0x01, r3
++ bt 28, L(if_source_aligned_by_8_or_12)
++ bt 29, L(if_source_aligned_by_4)
++ /* Handle WORD2,WORD3,WORD4 as source is aligned by 0. */
++ lwzu r12, 4(r4)
++ cmpb r10, r12, r0
++ cmpwi cr7, r10, 0
++ bne cr7, L(done)
++ lwzu r12, 4(r4)
++ cmpb r10, r12, r0
++ cmpwi cr7, r10, 0
++ bne cr7, L(done)
++ lwzu r12, 4(r4)
++ cmpb r10, r12, r0
++ cmpwi cr7, r10, 0
++ bne cr7, L(done)
++ b L(loop) /* We branch here (rather than falling through)
++ to skip the nops due to heavy alignment
++ of the loop below. */
++L(if_source_aligned_by_8_or_12):
++ bt 29, L(loop) /* if source address is aligned by 12 then only
++ one word needs to be handled to make source
++ address as 16 byte align which we have
++ already handled in the begining, so jump
++ directly to main loop. */
++ lwzu r12, 4(r4) /* else source is aligned by 8. */
++ cmpb r10, r12, r0
++ cmpwi cr7, r10, 0
++ bne cr7, L(done)
++L(loop):
++ lwz r8, 4(r4)
++ lwzu r9, 8(r4)
++ lwz r11, 4(r4)
++ lwzu r12, 8(r4)
++ cmpb r10, r8, r0
++ cmpwi cr7, r10, 0
++ bne cr7, L(done1)
++ cmpb r10, r9, r0
++ cmpwi cr7, r10, 0
++ bne cr7, L(done2)
++ cmpb r10, r11, r0
++ cmpwi cr7, r10, 0
++ bne cr7, L(done3)
++ cmpb r10, r12, r0
++ cmpwi cr7, r10, 0
++ beq cr7, L(loop)
++ /* r10 has the output of the cmpb instruction, that is, it contains
++ 0xff in the same position as the null byte in the original word
++ from the string. Use that to calculate the length. */
++ cntlzw r0, r10
++ subf r5, r3, r4
++ srwi r0, r0, 3
++ add r3, r5, r0
++ blr
++L(done1):
++ addi r4, r4, -12 /* Adjust the address. */
++L(done):
++ cntlzw r0, r10 /* Count leading zeroes before the match. */
++ subf r5, r3, r4
++ srwi r0, r0, 3 /* Convert leading zeroes to bytes. */
++ add r3, r5, r0 /* Compute final length. */
++ blr
++L(done2):
++ addi r4, r4, -8 /* Adjust the address. */
++ b L(done)
++L(done3):
++ addi r4, r4, -4 /* Adjust the address. */
++ b L(done)
++ /* if source address is aligned by 4 then total three words need to
++ be handled to make source address as 16 byte align in which we
++ have already handled one word in the begining, so now handle next
++ two words then jump to main loop. */
++L(if_source_aligned_by_4):
++ lwzu r12, 4(r4)
++ cmpb r10, r12, r0
++ cmpwi cr7, r10, 0
++ bne cr7, L(done)
++ lwzu r12, 4(r4)
++ cmpb r10, r12, r0
++ cmpwi cr7, r10, 0
++ bne cr7, L(done)
++ b L(loop)
++
++END (strlen)
++libc_hidden_builtin_def (strlen)
+diff -Naur vanilla/sysdeps/powerpc/powerpc64/e5500/strlen.S patched/sysdeps/powerpc/powerpc64/e5500/strlen.S
+--- vanilla/sysdeps/powerpc/powerpc64/e5500/strlen.S 1969-12-31 18:00:00.000000000 -0600
++++ patched/sysdeps/powerpc/powerpc64/e5500/strlen.S 2015-03-12 07:39:06.118952040 -0500
+@@ -0,0 +1,84 @@
++/* Optimized strlen implementation for 64-bit e5500 PowerPC target.
++ Based on POWER7 strlen implementation.
++ Copyright (C) 2010-2015 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, see
++ <http://www.gnu.org/licenses/>. */
++
++#include <sysdep.h>
++
++/* int [r3] strlen (char *s [r3]) */
++
++ENTRY (strlen)
++ CALL_MCOUNT 1
++
++ dcbt 0, r3
++ clrrdi r4, r3, 3 /* Align address to double word boundary. */
++ rlwinm r6, r3, 3, 26, 28 /* Calculate padding. */
++ li r0, 0 /* Doubleword with null chars to use
++ with cmpb. */
++ li r5, -1 /* MASK = 0xffffffffffffffff. */
++ ld r12, 0(r4) /* Load doubleword from memory. */
++ srd r5, r5, r6 /* MASK = MASK >> padding. */
++ orc r9, r12, r5 /* Mask bits that are not part of string. */
++ cmpb r10, r9, r0 /* Check for null bytes in DWORD1. */
++ cmpdi cr7, r10, 0 /* If r10 == 0, no null's have been found. */
++ bne cr7, L(done)
++ mtcrf 0x01, r4
++ /* Are we now aligned to a quad word boundary? If so, skip to the
++ main loop. Otherwise, go through the alignment code. */
++ bt 28, L(loop)
++/* Handle DWORD2 of pair. */
++ ldu r12, 8(r4)
++ cmpb r10, r12, r0
++ cmpdi cr7, r10, 0
++ bne cr7, L(done)
++ b L(loop) /* We branch here (rather than falling through)
++ to skip the nops due to heavy alignment of
++ the loop below. */
++L(loop):
++ /* Load two doublewords, compare and merge in a single register for
++ speed. This is an attempt to speed up the null-checking process
++ for bigger strings. */
++ ld r12, 8(r4)
++ ldu r11, 16(r4)
++ cmpb r10, r12, r0
++ cmpb r9, r11, r0
++ or r8, r9, r10 /* Merge everything in one doubleword. */
++ cmpdi cr7, r8, 0
++ beq cr7, L(loop)
++ /* OK, one (or both) of the doublewords contains a null byte. Check
++ the first doubleword and decrement the address in case the first
++ doubleword really contains a null byte. */
++ cmpdi cr6, r10, 0
++ addi r4, r4, -8
++ bne cr6, L(done)
++ /* The null byte must be in the second doubleword. Adjust the address
++ again and move the result of cmpb to r10 so we can calculate the
++ length. */
++ mr r10, r9
++ addi r4, r4, 8
++ /* r10 has the output of the cmpb instruction, that is, it contains
++ 0xff in the same position as the null byte in the original
++ doubleword from the string. Use that to calculate the length. */
++L(done):
++ cntlzd r0, r10 /* Count leading zeroes before the match. */
++ subf r5, r3, r4
++ srdi r0, r0, 3 /* Convert leading zeroes to bytes. */
++ add r3, r5, r0 /* Compute final length. */
++ blr
++
++END (strlen)
++libc_hidden_builtin_def (strlen)
diff --git a/recipes-core/glibc/glibc-fsl/0017.glibc.fsl-strrchr-e500mc-e5500.patch b/recipes-core/glibc/glibc-fsl/0017.glibc.fsl-strrchr-e500mc-e5500.patch
new file mode 100755
index 0000000..64cec3a
--- /dev/null
+++ b/recipes-core/glibc/glibc-fsl/0017.glibc.fsl-strrchr-e500mc-e5500.patch
@@ -0,0 +1,1072 @@
+# Problem Statement:
+ Implement target specific optimized strrchr for e500mc, 32-bit e5500 and
+ 64-bit e5500
+
+# Owned by:
+ Mahesh [based on existing 'asm' implementation of glibc strchr]
+
+# Actions:
+ * For e500mc target, default glibc implementation reads
+ two words at a time. Current implementation unrolls the loop to
+ read eight words.
+
+ * For e5500 [32-bit and 64-bit] targets, use 'cmpb' instruction to check
+ the occurance of NULL and expected character in a string.
+
+ * Reordered the instructions to get the better performance
+
+diff -Naur vanilla/sysdeps/powerpc/powerpc32/e500mc/strrchr.S patched/sysdeps/powerpc/powerpc32/e500mc/strrchr.S
+--- vanilla/sysdeps/powerpc/powerpc32/e500mc/strrchr.S 1969-12-31 18:00:00.000000000 -0600
++++ patched/sysdeps/powerpc/powerpc32/e500mc/strrchr.S 2015-03-13 03:18:38.082952006 -0500
+@@ -0,0 +1,344 @@
++/* Optimized strrchr implementation for PowerPC e500mc target.
++ Based on generic strchr implementation of 32-bit PowerPC.
++ Copyright (C) 1997-2015 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, see
++ <http://www.gnu.org/licenses/>. */
++
++#include <sysdep.h>
++
++/* See strlen.s for comments on how this works. */
++
++/* char * [r3] strrchr (const char *s [r3] , int c [r4]) */
++
++ENTRY (strrchr)
++
++#define rTMP1 r0
++#define rRTN r3 /* outgoing result. */
++#define rSTR r8 /* current word pointer. */
++#define rCHR r4 /* byte we are looking for, spread over the
++ whole word. */
++#define rWORD r5 /* the current word. */
++#define rFEFE r6 /* constant 0xfefefeff (-0x01010101). */
++#define r7F7F r7 /* constant 0x7f7f7f7f. */
++#define rTMP2 r9
++#define rIGN r10 /* number of bits we should ignore in first word. */
++#define rMASK r11 /* mask with the bits to ignore set to rTMP1
++ and to load preceding word. */
++#define rTMP3 r12
++
++ andi. rTMP2, rRTN, 3
++ cmplwi cr7, rCHR, 0
++ rlwimi rCHR, rCHR, 8, 16, 23
++ rlwimi rCHR, rCHR, 16, 0, 15
++ lis rFEFE, -0x101
++ lis r7F7F, 0x7f7f
++ clrrwi rSTR, rRTN, 2
++ addi rFEFE, rFEFE, -0x101
++ addi r7F7F, r7F7F, 0x7f7f
++ lwz rWORD, 0(rSTR)
++ li rIGN, -1
++ beq L(srcalign)
++ rlwinm rTMP1, rRTN, 3, 27, 28
++ srw rMASK, rIGN, rTMP1
++ orc rWORD, rWORD, rMASK
++ li rRTN, 0
++ beq cr7, L(null)
++ add rTMP1, rFEFE, rWORD
++ nor rTMP2, r7F7F, rWORD
++ and. rTMP1, rTMP1, rTMP2
++ xor rTMP3, rCHR, rWORD
++ orc rTMP3, rTMP3, rMASK
++ add rTMP1, rFEFE, rTMP3
++ bne L(missed)
++ b L(loop)
++L(srcalign):
++ li rRTN, 0
++ beq cr7, L(nullwordalign)
++L(srcalign2):
++ add rTMP1, rFEFE, rWORD
++ nor rTMP2, r7F7F, rWORD
++ and. rTMP1, rTMP1, rTMP2
++ xor rTMP3, rCHR, rWORD
++ add rTMP1, rFEFE, rTMP3
++ bne L(missed)
++L(loop):
++ lwzu rMASK, 4(rSTR)
++ nor rTMP2, r7F7F, rTMP3
++ and. rTMP1, rTMP1, rTMP2
++ bne L(foundit)
++ add rTMP1, rFEFE, rMASK
++ /* Test for rTMP1. */
++ nor rTMP2, r7F7F, rMASK
++ xor rTMP3, rCHR, rMASK
++ and. rTMP1, rTMP1, rTMP2
++ add rTMP1, rFEFE, rTMP3
++ bne L(missed1)
++ nor rTMP2, r7F7F, rTMP3
++ lwzu rWORD, 4(rSTR)
++ and. rTMP1, rTMP1, rTMP2
++ bne L(foundit1)
++ add rTMP1, rFEFE, rWORD
++ /* Test for rTMP1. */
++ nor rTMP2, r7F7F, rWORD
++ xor rTMP3, rCHR, rWORD
++ and. rTMP1, rTMP1, rTMP2
++ add rTMP1, rFEFE, rTMP3
++ bne L(missed)
++ lwzu rMASK, 4(rSTR)
++ nor rTMP2, r7F7F, rTMP3
++ and. rTMP1, rTMP1, rTMP2
++ bne L(foundit)
++ add rTMP1, rFEFE, rMASK
++ /* Test for rTMP1. */
++ nor rTMP2, r7F7F, rMASK
++ xor rTMP3, rCHR, rMASK
++ and. rTMP1, rTMP1, rTMP2
++ add rTMP1, rFEFE, rTMP3
++ bne L(missed1)
++ nor rTMP2, r7F7F, rTMP3
++ lwzu rWORD, 4(rSTR)
++ and. rTMP1, rTMP1, rTMP2
++ bne L(foundit1)
++ add rTMP1, rFEFE, rWORD
++ /* Test for rTMP1. */
++ nor rTMP2, r7F7F, rWORD
++ xor rTMP3, rCHR, rWORD
++ and. rTMP1, rTMP1, rTMP2
++ add rTMP1, rFEFE, rTMP3
++ bne L(missed)
++ lwzu rMASK, 4(rSTR)
++ nor rTMP2, r7F7F, rTMP3
++ and. rTMP1, rTMP1, rTMP2
++ bne L(foundit)
++ add rTMP1, rFEFE, rMASK
++ /* Test for rTMP1. */
++ nor rTMP2, r7F7F, rMASK
++ xor rTMP3, rCHR, rMASK
++ and. rTMP1, rTMP1, rTMP2
++ add rTMP1, rFEFE, rTMP3
++ bne L(missed1)
++ nor rTMP2, r7F7F, rTMP3
++ lwzu rWORD, 4(rSTR)
++ and. rTMP1, rTMP1, rTMP2
++ bne L(foundit1)
++ add rTMP1, rFEFE, rWORD
++ /* Test for rTMP1. */
++ nor rTMP2, r7F7F, rWORD
++ xor rTMP3, rCHR, rWORD
++ and. rTMP1, rTMP1, rTMP2
++ add rTMP1, rFEFE, rTMP3
++ bne L(missed)
++ lwzu rMASK, 4(rSTR)
++ nor rTMP2, r7F7F, rTMP3
++ and. rTMP1, rTMP1, rTMP2
++ bne L(foundit)
++ add rTMP1, rFEFE, rMASK
++ /* Test for rTMP1. */
++ nor rTMP2, r7F7F, rMASK
++ xor rTMP3, rCHR, rMASK
++ and. rTMP1, rTMP1, rTMP2
++ add rTMP1, rFEFE, rTMP3
++ bne L(missed1)
++ nor rTMP2, r7F7F, rTMP3
++ lwzu rWORD, 4(rSTR)
++ and. rTMP1, rTMP1, rTMP2
++ bne L(foundit1)
++ add rTMP1, rFEFE, rWORD
++ /* Test for rTMP1. */
++ nor rTMP2, r7F7F, rWORD
++ dcbt rTMP1, rSTR
++ xor rTMP3, rCHR, rWORD
++ and. rTMP1, rTMP1, rTMP2
++ add rTMP1, rFEFE, rTMP3
++ beq L(loop)
++L(missed):
++ nor rTMP2, r7F7F, rTMP3
++ and. rTMP1, rTMP1, rTMP2
++ beqlr
++ and rFEFE, r7F7F, rWORD
++ or rMASK, r7F7F, rWORD
++ and rTMP1, r7F7F, rTMP3
++ or rTMP2, r7F7F, rTMP3
++ add rFEFE, rFEFE, r7F7F
++ add rTMP1, rTMP1, r7F7F
++ nor rWORD, rMASK, rFEFE
++ nor rTMP2, rTMP2, rTMP1
++ cmplw rWORD, rTMP2
++ bgtlr
++ cntlzw rWORD, rTMP2
++ srwi rWORD, rWORD, 3
++ add rRTN, rSTR, rWORD
++ addi rSTR, rRTN, 1
++ andi. rTMP2, rSTR, 3
++ cmpwi rFEFE, rTMP2, 2
++ bgt rFEFE, L(b3l)
++ li rTMP1, 24
++ srw rCHR, rCHR, rTMP1
++ beq rFEFE, L(b2)
++ lbz rWORD, 0(rSTR)
++ cmpwi rFEFE, rWORD, 0
++ beq rFEFE, L(b3l)
++ lbzu rTMP3, 1(rSTR)
++ cmpw r7F7F, rWORD, rCHR
++ beq r7F7F, L(ret1)
++ cmpwi rFEFE, rTMP3, 0
++ beq rFEFE, L(b3l)
++ cmpw r7F7F, rTMP3, rCHR
++ beq r7F7F, L(ret2)
++ blr
++L(missed1):
++ mr rWORD,rMASK
++ nor rTMP2, r7F7F, rTMP3
++ and. rTMP1, rTMP1, rTMP2
++ beqlr
++ and rFEFE, r7F7F, rWORD
++ or rMASK, r7F7F, rWORD
++ and rTMP1, r7F7F, rTMP3
++ or rTMP2, r7F7F, rTMP3
++ add rFEFE, rFEFE, r7F7F
++ add rTMP1, rTMP1, r7F7F
++ nor rWORD, rMASK, rFEFE
++ nor rTMP2, rTMP2, rTMP1
++ cmplw rWORD, rTMP2
++ bgtlr
++ cntlzw rWORD, rTMP2
++ srwi rWORD, rWORD, 3
++ add rRTN, rSTR, rWORD
++ addi rSTR, rRTN, 1
++ andi. rTMP2, rSTR, 3
++ cmpwi rFEFE, rTMP2, 2
++ bgt rFEFE, L(b3l)
++ li rTMP1, 24
++ srw rCHR, rCHR, rTMP1
++ beq rFEFE, L(b2)
++ lbz rWORD, 0(rSTR)
++ cmpwi rFEFE, rWORD, 0
++ beq rFEFE, L(b3l)
++ lbzu rTMP3, 1(rSTR)
++ cmpw r7F7F, rWORD, rCHR
++ beq r7F7F, L(ret1)
++ cmpwi rFEFE, rTMP3, 0
++ beq rFEFE, L(b3l)
++ cmpw r7F7F, rTMP3, rCHR
++ beq r7F7F, L(ret2)
++ blr
++L(ret2):
++ mr rRTN, rSTR
++ blr
++L(ret1):
++ subi rRTN, rSTR, 1
++ blr
++L(b2):
++ lbz rWORD, 0(rSTR)
++ cmpwi rFEFE, rWORD, 0
++ beq rFEFE, L(b3l)
++ cmpw r7F7F, rWORD, rCHR
++ beq r7F7F, L(ret)
++ blr
++L(ret):
++ mr rRTN, rSTR
++ blr
++L(b3l):
++ blr
++L(foundit):
++ and rTMP1, r7F7F, rTMP3
++ or rTMP2, r7F7F, rTMP3
++ add rTMP1, rTMP1, r7F7F
++ nor rTMP2, rTMP2, rTMP1
++ cntlzw rTMP3, rTMP2
++ subi rSTR, rSTR, 4
++ srwi rTMP3, rTMP3, 3
++ add rRTN, rSTR, rTMP3
++ addi rTMP1, rRTN, 1
++L(Nextword):
++ andi. rTMP2, rTMP1, 3
++ clrrwi rSTR, rTMP1, 2
++ bne L(srcalign_make)
++ mr rWORD,rMASK
++ b L(srcalign2)
++L(srcalign_make):
++ rlwinm rTMP1, rTMP1, 3, 27, 28
++ slw rWORD, rWORD, rTMP1
++ srw rWORD, rWORD, rTMP1
++ srw rMASK, rIGN, rTMP1
++ orc rWORD, rWORD, rMASK
++ add rTMP1, rFEFE, rWORD
++ nor rTMP2, r7F7F, rWORD
++ and. rTMP1, rTMP1, rTMP2
++ xor rTMP3, rCHR, rWORD
++ orc rTMP3, rTMP3, rMASK
++ add rTMP1, rFEFE, rTMP3
++ bne L(missed)
++ b L(loop)
++L(foundit1):
++ and rTMP1, r7F7F, rTMP3
++ or rTMP2, r7F7F, rTMP3
++ add rTMP1, rTMP1, r7F7F
++ nor rTMP2, rTMP2, rTMP1
++ cntlzw rTMP3, rTMP2
++ subi rSTR, rSTR, 4
++ srwi rTMP3, rTMP3, 3
++ add rRTN, rSTR, rTMP3
++ addi rTMP1, rRTN, 1
++L(Nextword1):
++ andi. rTMP2, rTMP1, 3
++ clrrwi rSTR, rTMP1, 2
++ beq L(srcalign2)
++ mr rWORD, rMASK
++ rlwinm rTMP1, rTMP1, rRTN, 27, 28
++ slw rWORD, rWORD, rTMP1
++ srw rWORD, rWORD, rTMP1
++ srw rMASK, rIGN, rTMP1
++ orc rWORD, rWORD, rMASK
++ add rTMP1, rFEFE, rWORD
++ nor rTMP2, r7F7F, rWORD
++ and. rTMP1, rTMP1, rTMP2
++ xor rTMP3, rCHR, rWORD
++ orc rTMP3, rTMP3, rMASK
++ add rTMP1, rFEFE, rTMP3
++ bne L(missed)
++ b L(loop)
++
++L(nullwordalign):
++ add rTMP1, rFEFE, rWORD
++ nor rTMP2, r7F7F, rWORD
++ and. rTMP1, rTMP1, rTMP2
++ bne L(foundnull)
++ b L(loopnull)
++L(null):
++ add rTMP1, rFEFE, rWORD
++ nor rTMP2, r7F7F, rWORD
++ and. rTMP1, rTMP1, rTMP2
++ bne L(foundnull)
++L(loopnull):
++ lwzu rWORD, 4(rSTR)
++ add rTMP1, rFEFE, rWORD
++ nor rTMP2, r7F7F, rWORD
++ and. rTMP1, rTMP1, rTMP2
++ beq L(loopnull)
++L(foundnull):
++ and rTMP1, r7F7F, rWORD
++ or rIGN, r7F7F, rWORD
++ add rTMP1, rTMP1, r7F7F
++ nor rTMP2, rIGN, rTMP1
++ cntlzw rTMP3, rTMP2
++ srwi rTMP3, rTMP3, 3
++ add rRTN, rSTR, rTMP3
++ blr
++END (strrchr)
++
++weak_alias (strrchr, rindex)
++libc_hidden_builtin_def (strrchr)
+diff -Naur vanilla/sysdeps/powerpc/powerpc32/e5500/strrchr.S patched/sysdeps/powerpc/powerpc32/e5500/strrchr.S
+--- vanilla/sysdeps/powerpc/powerpc32/e5500/strrchr.S 1969-12-31 18:00:00.000000000 -0600
++++ patched/sysdeps/powerpc/powerpc32/e5500/strrchr.S 2015-03-13 03:19:56.365952010 -0500
+@@ -0,0 +1,348 @@
++/* Optimized strrchr implementation for 32-bit e5500 PowerPC target.
++ Based on POWER7 strchr implementation.
++ Copyright (C) 2010-2015 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, see
++ <http://www.gnu.org/licenses/>. */
++
++#include <sysdep.h>
++
++/* See strlen.s for comments on how this works. */
++
++/* char * [r3] strrchr (const char *s [r3] , int c [r4]) */
++
++ENTRY (strrchr)
++
++#define rTMP1 r0
++#define rRTN r3 /* outgoing result. */
++#define rSTR r8 /* current word pointer. */
++#define rCHR r4 /* byte we are looking for, spread over the
++ whole word. */
++#define rTMP2 r5
++#define rMASK r6 /* calculate padding bits. */
++#define rTMP3 r7
++#define rWORD r12 /* the current word. */
++#define rWORD2 r9 /* following word. */
++#define rTMP4 r10
++#define rTMP5 r11
++
++ dcbt 0, rRTN
++ andi. rTMP3, rRTN, 7 /* check for double word boundary. */
++ cmpwi cr7, rCHR, 0
++ li rTMP1, 0
++ /* Replicate byte to double word. */
++ rlwimi rCHR, rCHR, 8, 16, 23
++ rlwimi rCHR,rCHR, 16, 0, 15
++ beq L(dwalign)
++ subfic rTMP3, rTMP3, 8
++ cmplwi cr6, rTMP3, 4
++ clrrwi rSTR, rRTN, 2 /* Align address to word boundary. */
++ beq cr6, L(word2)
++ blt cr6, L(LTword2)
++ lwz rWORD, 0(rSTR) /* Load word from memory. */
++ rlwinm rMASK, rRTN, 3, 27, 28 /* Calculate padding. */
++ /* By now the rCHR has a word of c bytes and the rTMP1 has a word of
++ null bytes. */
++ li rRTN, 0
++ beq cr7, L(null_match)
++ cmpb rTMP4, rWORD, rCHR /* Compare each byte against c byte. */
++ cmpb rTMP5, rWORD, rTMP1 /* Compare each byte against the null
++ byte. */
++ /* Move the words left and right to discard the bits that are not
++ part of the string and to bring them back as zeros. */
++ slw rTMP4, rTMP4, rMASK
++ slw rTMP5, rTMP5, rMASK
++ srw rTMP4, rTMP4, rMASK
++ srw rTMP5, rTMP5, rMASK
++ or rTMP2, rTMP4, rTMP5 /* OR results to speed things up. */
++ cmpwi cr7, rTMP2, 0 /* If rTMP2 == 0, no c or null bytes
++ have been found. */
++ bne cr7, L(done)
++ /* Handle WORD2 of pair. */
++ lwzu rWORD, 4(rSTR)
++ cmpb rTMP4, rWORD, rCHR
++ cmpb rTMP5, rWORD, rTMP1
++ or rTMP2, rTMP4, rTMP5
++ cmpwi cr7, rTMP2, 0
++ bne cr7, L(done)
++ b L(loop) /* We branch here (rather than falling
++ through) to skip the nops due to
++ heavy alignment of loop below. */
++L(LTword2):
++ lwz rWORD, 0(rSTR) /* Load word from memory. */
++ rlwinm rMASK, rRTN, 3, 27, 28 /* Calculate padding. */
++ /* By now the rCHR has a word of c bytes and the rTMP1 has a word
++ of null bytes. */
++ li rRTN, 0
++ beq cr7, L(null_LTword2)
++ cmpb rTMP4, rWORD, rCHR /* Compare each byte with c byte. */
++ cmpb rTMP5, rWORD, rTMP1 /* Compare each byte against the null
++ byte. */
++ /* Move the words left and right to discard the bits that are not
++ part of the string and to bring them back as zeros. */
++ slw rTMP4, rTMP4, rMASK
++ slw rTMP5, rTMP5, rMASK
++ srw rTMP4, rTMP4, rMASK
++ srw rTMP5, rTMP5, rMASK
++ or rTMP2, rTMP4, rTMP5 /* OR results to speed things up. */
++ cmpwi cr7, rTMP2, 0 /* If rTMP2 == 0, no c or null bytes
++ have been found. */
++ bne cr7, L(done)
++ b L(loop)
++L(word2):
++ lwz rWORD, 0(rSTR)
++ li rRTN, 0
++ beq cr7, L(null_word2)
++ cmpb rTMP4, rWORD, rCHR
++ cmpb rTMP5, rWORD, rTMP1
++ or rTMP2, rTMP4, rTMP5
++ cmpwi cr7, rTMP2, 0
++ bne cr7, L(done)
++ b L(loop)
++L(dwalign):
++ /* Load two words, compare and merge in a single register for speed.
++ This is an attempt to speed up the null-checking process for
++ bigger strings. */
++ mr rSTR, rRTN
++ li rRTN, 0
++ lwz rWORD, 0(rSTR)
++ lwzu rWORD2, 4(rSTR)
++ beq cr7, L(dwalignnull)
++ cmpb rTMP4, rWORD, rCHR
++ cmpb rTMP5, rWORD, rTMP1
++ cmpb rMASK, rWORD2, rCHR
++ cmpb rTMP3, rWORD2, rTMP1
++ or rWORD, rTMP4, rTMP5
++ or rWORD2, rMASK, rTMP3
++ or rTMP2, rWORD, rWORD2
++ cmpwi cr7, rTMP2, 0
++ beq cr7, L(loop)
++ /* OK, one (or both) of the words contains a c/null byte. Check
++ the first word and decrement the address in case the first word
++ really contains a c/null byte. */
++ cmpwi cr6, rWORD, 0
++ addi rSTR, rSTR, -4
++ bne cr6, L(done)
++ /* The c/null byte must be in the second word. Adjust the address
++ again and move the result of cmpb to rTMP4 so we can calculate the
++ pointer. */
++ mr rTMP4, rMASK
++ mr rTMP5, rTMP3
++ addi rSTR, rSTR, 4
++ /* rTMP2 has the output of the cmpb instruction, that is, it contains
++ 0xff in the same position as the c/null byte in the original word
++ from the string. Use that to calculate the pointer. */
++ b L(done)
++L(loop):
++ /* Load two words, compare and merge in a single register for speed.
++ This is an attempt to speed up the null-checking process for
++ bigger strings. */
++ lwz rWORD, 4(rSTR)
++ lwzu rWORD2, 8(rSTR)
++ cmpb rTMP4, rWORD, rCHR
++ cmpb rTMP5, rWORD, rTMP1
++ cmpb rMASK, rWORD2, rCHR
++ cmpb rTMP3, rWORD2, rTMP1
++ or rWORD, rTMP4, rTMP5
++ or rWORD2, rMASK, rTMP3
++ or rTMP2, rWORD, rWORD2
++ cmpwi cr7, rTMP2, 0
++ beq cr7, L(loop)
++ /* OK, one (or both) of the words contains a c/null byte. Check the
++ first word and decrement the address in case the first word really
++ contains a c/null byte. */
++ cmpwi cr6, rWORD, 0
++ addi rSTR, rSTR, -4
++ bne cr6, L(done)
++ /* The c/null byte must be in the second word. Adjust the address
++ again and move the result of cmpb to rTMP4 so we can calculate the
++ pointer. */
++ mr rTMP4, rMASK
++ mr rTMP5, rTMP3
++ addi rSTR, rSTR, 4
++ /* rTMP2 has the output of the cmpb instruction, that is, it contains
++ 0xff in the same position as the c/null byte in the original word
++ from the string. Use that to calculate the pointer. */
++L(done):
++ cntlzw rTMP3, rTMP4 /* Count leading zeroes before c
++ matches. */
++ cntlzw rMASK, rTMP5 /* Count leading zeroes before null
++ matches. */
++ cmplw cr7, rTMP3, rMASK
++ bgt cr7, L(no_match)
++ srwi rMASK, rTMP3, 3 /* Convert leading zeroes to bytes. */
++ add rRTN, rSTR, rMASK /* Return addr of the matching c byte
++ or null in case c is not found. */
++ addi rTMP4, rRTN, 1
++L(loop_check):
++ andi. rTMP3, rTMP4, 7 /* check for double word boundary. */
++ beq L(loop)
++ subfic rTMP3, rTMP3, 8
++ cmpwi cr6, rTMP3, 4
++ clrrwi rSTR, rTMP4, 2 /* Align address to word boundary. */
++ lwz rWORD, 0(rSTR)
++ beq cr6, L(word2_check)
++ ble cr6, L(LTword2_check)
++ rlwinm rMASK, rTMP4, 3, 27, 28 /* Calculate padding. */
++ /* By now the rCHR has a word of c bytes and the rTMP1 has a word
++ of null bytes. */
++ cmpb rTMP4, rWORD, rCHR /* Compare each byte with c byte. */
++ cmpb rTMP5, rWORD, rTMP1 /* Compare each byte against null
++ byte. */
++ /* Move the words left and right to discard the bits that are not
++ part of the string and to bring them back as zeros. */
++ slw rTMP4, rTMP4, rMASK
++ slw rTMP5, rTMP5, rMASK
++ srw rTMP4, rTMP4, rMASK
++ srw rTMP5, rTMP5, rMASK
++ or rTMP2, rTMP4, rTMP5 /* OR results to speed things up. */
++ cmpwi cr7, rTMP2, 0 /* If rTMP2 == 0, no c or null bytes
++ have been found. */
++ bne cr7, L(done)
++ /* Handle WORD2 of pair. */
++ lwzu rWORD, 4(rSTR)
++ cmpb rTMP4, rWORD, rCHR
++ cmpb rTMP5, rWORD, rTMP1
++ or rTMP2, rTMP4, rTMP5
++ cmpwi cr7, rTMP2, 0
++ bne cr7, L(done)
++ b L(loop) /* We branch here (rather than falling
++ through) to skip the nops due to
++ heavy alignment of loop below. */
++L(LTword2_check):
++ rlwinm rMASK, rTMP4, 3, 27, 28 /* Calculate padding. */
++ cmpb rTMP4, rWORD, rCHR /* Compare each byte with c byte. */
++ cmpb rTMP5, rWORD, rTMP1 /* Compare each byte against null
++ byte. */
++ /* Move the words left and right to discard the bits that are not
++ part of the string and to bring them back as zeros. */
++ slw rTMP4, rTMP4, rMASK
++ slw rTMP5, rTMP5, rMASK
++ srw rTMP4, rTMP4, rMASK
++ srw rTMP5, rTMP5, rMASK
++ or rTMP2, rTMP4, rTMP5 /* OR results to speed things up. */
++ cmpwi cr7, rTMP2, 0 /* If rTMP2 == 0, no c or null bytes
++ have been found. */
++ bne cr7, L(done)
++ b L(loop)
++L(word2_check):
++ cmpb rTMP4, rWORD, rCHR
++ cmpb rTMP5, rWORD, rTMP1
++ or rTMP2, rTMP4, rTMP5
++ cmpwi cr7, rTMP2, 0
++ bne cr7, L(done)
++ b L(loop)
++L(no_match):
++ blr
++ /* We are here because strrchr was called with a null byte. */
++L(null_match):
++ /* rTMP1 has a word of null bytes. */
++ cmpb rTMP2, rWORD, rTMP1 /* Compare each byte against null
++ bytes. */
++ /* Move the words left and right to discard the bits that are not
++ part of the string and to bring them back as zeros. */
++ slw rTMP2, rTMP2, rMASK
++ srw rTMP2, rTMP2, rMASK
++ cmpwi cr7, rTMP2, 0 /* If rTMP4 == 0, no c or null bytes
++ have been found. */
++ bne cr7, L(done_null)
++ /* Handle WORD2 of pair. */
++ lwzu rWORD, 4(rSTR)
++ cmpb rTMP2, rWORD, rTMP1
++ cmpwi cr7, rTMP2, 0
++ bne cr7, L(done_null)
++ b L(loop_null) /* We branch here (rather than falling
++ through) to skip the nops due to
++ heavy alignment of loop below. */
++L(null_LTword2):
++ /* rTMP1 has a word of null bytes. */
++ cmpb rTMP2, rWORD, rTMP1 /* Compare each byte against null
++ bytes. */
++ /* Move the words left and right to discard the bits that are not
++ part of the string and to bring them back as zeros. */
++ slw rTMP2, rTMP2, rMASK
++ srw rTMP2, rTMP2, rMASK
++ cmpwi cr7, rTMP2, 0 /* If rTMP4 == 0, no c or null bytes
++ have been found. */
++ bne cr7, L(done_null)
++ b L(loop_null)
++L(null_word2):
++ /* Handle WORD2 of pair. */
++ cmpb rTMP2, rWORD, rTMP1
++ cmpwi cr7, rTMP2, 0
++ bne cr7, L(done_null)
++ b L(loop_null) /* We branch here (rather than falling
++ through) to skip the nops due to
++ heavy alignment of loop below. */
++L(dwalignnull):
++ /* Load two words, compare and merge in a single register for speed.
++ This is an attempt to speed up the null-checking process for
++ bigger strings. */
++ cmpb rTMP2, rWORD, rTMP1
++ cmpb rTMP4, rWORD2, rTMP1
++ or rMASK, rTMP2, rTMP4
++ cmpwi cr7, rMASK, 0
++ beq cr7, L(loop_null)
++ /* OK, one (or both) of the words contains a null byte. Check the
++ first word and decrement the address in case the first word really
++ contains a null byte. */
++ cmpwi cr6, rTMP2, 0
++ addi rSTR, rSTR, -4
++ bne cr6, L(done_null)
++ /* The null byte must be in the second word. Adjust the address
++ again and move the result of cmpb to rTMP4 so we can calculate the
++ pointer. */
++ mr rTMP2, rTMP4
++ addi rSTR, rSTR, 4
++ /* rTMP2 has the output of the cmpb instruction, that is, it contains
++ 0xff in the same position as the null byte in the original word
++ from the string. Use that to calculate the pointer. */
++ b L(done_null)
++L(loop_null):
++ /* Load two words, compare and merge in a single register for speed.
++ This is an attempt to speed up the null-checking process for bigger
++ strings. */
++ lwz rWORD, 4(rSTR)
++ lwzu rTMP5, 8(rSTR)
++ cmpb rTMP2, rWORD, rTMP1
++ cmpb rTMP4, rTMP5, rTMP1
++ or rMASK, rTMP2, rTMP4
++ cmpwi cr7, rMASK, 0
++ beq cr7, L(loop_null)
++ /* OK, one (or both) of the words contains a null byte. Check the
++ first word and decrement the address in case the first word really
++ contains a null byte. */
++ cmpwi cr6, rTMP2, 0
++ addi rSTR, rSTR, -4
++ bne cr6, L(done_null)
++ /* The null byte must be in the second word. Adjust the address
++ again and move the result of cmpb to rTMP4 so we can calculate the
++ pointer. */
++ mr rTMP2, rTMP4
++ addi rSTR, rSTR, 4
++ /* rTMP2 has the output of the cmpb instruction, that is, it contains
++ 0xff in the same position as the null byte in the original word
++ from the string. Use that to calculate the pointer. */
++L(done_null):
++ cntlzw rTMP1, rTMP2 /* Count leading zeros before match. */
++ srwi rTMP1, rTMP1, 3 /* Convert leading zeros to bytes. */
++ add rRTN, rSTR, rTMP1 /* Return address of the matching null
++ byte. */
++ blr
++
++END (strrchr)
++
++weak_alias (strrchr, rindex)
++libc_hidden_builtin_def (strrchr)
+diff -Naur vanilla/sysdeps/powerpc/powerpc64/e5500/strrchr.S patched/sysdeps/powerpc/powerpc64/e5500/strrchr.S
+--- vanilla/sysdeps/powerpc/powerpc64/e5500/strrchr.S 1969-12-31 18:00:00.000000000 -0600
++++ patched/sysdeps/powerpc/powerpc64/e5500/strrchr.S 2015-03-13 03:28:16.701951974 -0500
+@@ -0,0 +1,351 @@
++/* Optimized strrchr implementation for 64-bit e5500 PowerPC target.
++ Based on POWER7 strchr implementation.
++ Copyright (C) 2010-2015 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, see
++ <http://www.gnu.org/licenses/>. */
++
++#include <sysdep.h>
++
++/* See strlen.s for comments on how this works. */
++
++/* char * [r3] strrchr (const char *s [r3] , int c [r4]) */
++
++ENTRY (strrchr)
++ CALL_MCOUNT 2
++
++#define rTMP1 r0
++#define rRTN r3 /* outgoing result. */
++#define rSTR r8 /* current word pointer. */
++#define rCHR r4 /* byte we are looking for, spread over the whole
++ word. */
++#define rTMP2 r5
++#define rMASK r6 /* calculate padding bits. */
++#define rTMP3 r7
++#define rWORD r12 /* the current word. */
++#define rWORD2 r9 /* following word. */
++#define rTMP4 r10
++#define rTMP5 r11
++
++ dcbt 0, rRTN
++ andi. rTMP3, rRTN, 15 /* check for 4 word boundary. */
++ cmpwi cr7, rCHR, 0
++ li rTMP1, 0
++ /* Replicate byte to double word. */
++ rlwimi rCHR, rCHR, 8, 16, 23
++ rlwimi rCHR, rCHR, 16, 0, 15
++ insrdi rCHR, rCHR, 32, 0
++ beq L(qwalign)
++ subfic rTMP3, rTMP3, 16
++ cmpldi cr6, rTMP3, 8
++ clrrdi rSTR, rRTN, 3 /* Align the address to double word
++ boundary. */
++ beq cr6, L(doubleword2)
++ blt cr6, L(LTdoubleword2)
++ ld rWORD, 0(rSTR) /* Load word from memory. */
++ rlwinm rMASK, rRTN, 3, 26, 28 /* Calculate padding. */
++ /* By now the rCHR has a word of c bytes and the rTMP1 has a word of
++ null bytes. */
++ li rRTN, 0
++ beq cr7, L(null_match)
++ cmpb rTMP4, rWORD, rCHR /* Compare each byte with c byte. */
++ cmpb rTMP5, rWORD, rTMP1 /* Compare each byte against null
++ byte. */
++ /* Move the words left and right to discard the bits that are not part
++ of the string and to bring them back as zeros. */
++ sld rTMP4, rTMP4, rMASK
++ sld rTMP5, rTMP5, rMASK
++ srd rTMP4, rTMP4, rMASK
++ srd rTMP5, rTMP5, rMASK
++ or rTMP2, rTMP4, rTMP5 /* OR results to speed things up. */
++ cmpdi cr7, rTMP2, 0 /* If rTMP2==0,no c or null bytes
++ have been found. */
++ bne cr7, L(done)
++ /* Handle WORD2 of pair. */
++ ldu rWORD, 8(rSTR)
++ cmpb rTMP4, rWORD, rCHR
++ cmpb rTMP5, rWORD, rTMP1
++ or rTMP2, rTMP4, rTMP5
++ cmpdi cr7, rTMP2, 0
++ bne cr7, L(done)
++ b L(loop) /* We branch here (rather than falling
++ through) to skip the nops due to
++ heavy alignment of loop below. */
++L(LTdoubleword2):
++ ld rWORD, 0(rSTR) /* Load word from memory. */
++ rlwinm rMASK, rRTN, 3, 26, 28 /* Calculate padding. */
++ /* By now rCHR has a word of c bytes and rTMP1 has a word of null
++ bytes. */
++ li rRTN, 0
++ beq cr7, L(null_LTdoubleword2)
++ cmpb rTMP4, rWORD, rCHR /* Compare each byte with c byte. */
++ cmpb rTMP5, rWORD, rTMP1 /* Compare each byte against null
++ byte. */
++ /* Move the words left and right to discard the bits that are not
++ part of the string and to bring them back as zeros. */
++ sld rTMP4, rTMP4, rMASK
++ sld rTMP5, rTMP5, rMASK
++ srd rTMP4, rTMP4, rMASK
++ srd rTMP5, rTMP5, rMASK
++ or rTMP2, rTMP4, rTMP5 /* OR results to speed things up. */
++ cmpdi cr7, rTMP2, 0 /* If rTMP2==0,no c or null bytes
++ have been found. */
++ bne cr7, L(done)
++ b L(loop)
++L(doubleword2):
++ ld rWORD, 0(rSTR)
++ li rRTN, 0
++ beq cr7, L(null_doubleword2)
++ cmpb rTMP4, rWORD, rCHR
++ cmpb rTMP5, rWORD, rTMP1
++ or rTMP2, rTMP4, rTMP5
++ cmpdi cr7, rTMP2, 0
++ bne cr7, L(done)
++ b L(loop)
++L(qwalign):
++ /* Load two words, compare and merge in a single register for speed.
++ This is an attempt to speed up the null-checking process for bigger
++ strings. */
++ mr rSTR, rRTN
++ li rRTN, 0
++ ld rWORD, 0(rSTR)
++ ldu rWORD2, 8(rSTR)
++ beq cr7, L(qwalignnull)
++ cmpb rTMP4, rWORD, rCHR
++ cmpb rTMP5, rWORD, rTMP1
++ cmpb rMASK, rWORD2, rCHR
++ cmpb rTMP3, rWORD2, rTMP1
++ or rWORD, rTMP4, rTMP5
++ or rWORD2, rMASK, rTMP3
++ or rTMP2, rWORD, rWORD2
++ cmpdi cr7, rTMP2, 0
++ beq cr7, L(loop)
++ /* OK, one (or both) of the words contains a c/null byte. Check the
++ first word and decrement the address in case the first word really
++ contains a c/null byte. */
++ cmpdi cr6, rWORD, 0
++ addi rSTR, rSTR, -8
++ bne cr6, L(done)
++ /* The c/null byte must be in the second word. Adjust the address
++ again and move the result of cmpb to rTMP4 so we can calculate the
++ pointer. */
++ mr rTMP4, rMASK
++ mr rTMP5, rTMP3
++ addi rSTR, rSTR, 8
++ /* rTMP2 has the output of the cmpb instruction, that is, it contains
++ 0xff in the same position as the c/null byte in the original word
++ from the string. Use that to calculate the pointer. */
++ b L(done)
++L(loop):
++ /* Load two words, compare and merge in a single register for speed.
++ This is an attempt to speed up the null-checking process for bigger
++ strings. */
++ ld rWORD, 8(rSTR)
++ ldu rWORD2, 16(rSTR)
++ cmpb rTMP4, rWORD, rCHR
++ cmpb rTMP5, rWORD, rTMP1
++ cmpb rMASK, rWORD2, rCHR
++ cmpb rTMP3, rWORD2, rTMP1
++ or rWORD, rTMP4, rTMP5
++ or rWORD2, rMASK, rTMP3
++ or rTMP2, rWORD, rWORD2
++ cmpdi cr7, rTMP2, 0
++ beq cr7, L(loop)
++ /* OK, one (or both) of the words contains a c/null byte. Check the
++ first word and decrement the address in case the first word really
++ contains a c/null byte. */
++ cmpdi cr6, rWORD, 0
++ addi rSTR, rSTR, -8
++ bne cr6, L(done)
++ /* The c/null byte must be in the second word. Adjust the address
++ again and move the result of cmpb to rTMP4 so we can calculate the
++ pointer. */
++ mr rTMP4, rMASK
++ mr rTMP5, rTMP3
++ addi rSTR, rSTR, 8
++ /* rTMP2 has the output of the cmpb instruction, that is, it contains
++ 0xff in the same position as the c/null byte in the original word
++ from the string. Use that to calculate the pointer. */
++L(done):
++ cntlzd rTMP3, rTMP4 /* Count the leading zeroes before c
++ matches. */
++ cntlzd rMASK, rTMP5 /* Count the leading zeroes before
++ null matches. */
++ cmpld cr7, rTMP3, rMASK
++ bgt cr7, L(no_match)
++ srdi rMASK, rTMP3, 3 /* Convert leading zeroes to bytes. */
++ add rRTN, rSTR, rMASK /* Return addr of the matching c byte
++ or null in case c was not found. */
++ addi rTMP4, rRTN, 1
++L(loop_check):
++ andi. rTMP3, rTMP4, 15 /* check for 4 word boundary. */
++ beq L(loop)
++ subfic rTMP3, rTMP3, 16
++ cmpldi cr6, rTMP3, 8
++ clrrdi rSTR, rTMP4, 3 /* Align the address to double word
++ boundary. */
++ ld rWORD, 0(rSTR) /* Load double word from memory. */
++ beq cr6, L(doubleword2_check)
++ ble cr6, L(LTdoubleword2_check)
++ rlwinm rMASK, rTMP4, 3, 26, 28 /* Calculate padding. */
++ cmpb rTMP4, rWORD, rCHR /* Compare each byte with c byte. */
++ cmpb rTMP5, rWORD, rTMP1 /* Compare each byte against null
++ byte. */
++ /* Move the words left and right to discard the bits that are not
++ part of the string and to bring them back as zeros. */
++ sld rTMP4, rTMP4, rMASK
++ sld rTMP5, rTMP5, rMASK
++ srd rTMP4, rTMP4, rMASK
++ srd rTMP5, rTMP5, rMASK
++ or rTMP2, rTMP4, rTMP5 /* OR results to speed things up. */
++ cmpdi cr7, rTMP2, 0 /* If rTMP2==0,no c or null bytes
++ have been found. */
++ bne cr7, L(done)
++ /* Handle WORD2 of pair. */
++ ldu rWORD, 8(rSTR)
++ cmpb rTMP4, rWORD, rCHR
++ cmpb rTMP5, rWORD, rTMP1
++ or rTMP2, rTMP4, rTMP5
++ cmpdi cr7, rTMP2, 0
++ bne cr7, L(done)
++ b L(loop) /* We branch here (rather than falling
++ through) to skip the nops due to
++ heavy alignment of loop below. */
++L(LTdoubleword2_check):
++ rlwinm rMASK, rTMP4, 3, 26, 28 /* Calculate padding. */
++ cmpb rTMP4, rWORD, rCHR /* Compare each byte with c byte. */
++ cmpb rTMP5, rWORD, rTMP1 /* Compare each byte against null
++ byte. */
++ /* Move the words left and right to discard the bits that are not
++ part of the string and to bring them back as zeros. */
++ sld rTMP4, rTMP4, rMASK
++ sld rTMP5, rTMP5, rMASK
++ srd rTMP4, rTMP4, rMASK
++ srd rTMP5, rTMP5, rMASK
++ or rTMP2, rTMP4, rTMP5 /* OR results to speed things up. */
++ cmpdi cr7, rTMP2, 0 /* If rTMP2==0,no c or null bytes
++ have been found. */
++ bne cr7, L(done)
++ b L(loop)
++L(doubleword2_check):
++ cmpb rTMP4, rWORD, rCHR
++ cmpb rTMP5, rWORD, rTMP1
++ or rTMP2, rTMP4, rTMP5
++ cmpdi cr7, rTMP2, 0
++ bne cr7, L(done)
++ b L(loop)
++L(no_match):
++ blr
++ /* We are here because strrchr was called with a null byte. */
++L(null_match):
++ /* rTMP1 has a word of null bytes. */
++ cmpb rTMP2, rWORD, rTMP1 /* Compare each byte against null
++ bytes. */
++ /* Move the words left and right to discard the bits that are not
++ part of the string and to bring them back as zeros. */
++ sld rTMP2, rTMP2, rMASK
++ srd rTMP2, rTMP2, rMASK
++ cmpdi cr7, rTMP2, 0 /* If rTMP4 == 0, no c or null bytes
++ have been found. */
++ bne cr7, L(done_null)
++ /* Handle WORD2 of pair. */
++ ldu rWORD, 8(rSTR)
++ cmpb rTMP2, rWORD, rTMP1
++ cmpdi cr7, rTMP2, 0
++ bne cr7, L(done_null)
++ b L(loop_null) /* We branch here (rather than falling
++ through) to skip the nops due to
++ heavy alignment of loop below. */
++L(null_LTdoubleword2):
++ /* rTMP1 has a word of null bytes. */
++ cmpb rTMP2, rWORD, rTMP1 /* Compare each byte against null
++ bytes. */
++ /* Move the words left and right to discard the bits that are not
++ part of the string and to bring them back as zeros. */
++ sld rTMP2, rTMP2, rMASK
++ srd rTMP2, rTMP2, rMASK
++ cmpdi cr7, rTMP2, 0 /* If rTMP4 == 0, no c or null bytes
++ have been found. */
++ bne cr7, L(done_null)
++ b L(loop_null)
++L(null_doubleword2):
++ /* Handle WORD2 of pair. */
++ cmpb rTMP2, rWORD, rTMP1
++ cmpdi cr7, rTMP2, 0
++ bne cr7, L(done_null)
++ b L(loop_null) /* We branch here (rather than falling
++ through) to skip the nops due to
++ heavy alignment of loop below. */
++L(qwalignnull):
++ /* Load two words, compare and merge in a single register for speed.
++ This is an attempt to speed up the null-checking process for bigger
++ strings. */
++ cmpb rTMP2, rWORD, rTMP1
++ cmpb rTMP4, rWORD2, rTMP1
++ or rMASK, rTMP2, rTMP4
++ cmpdi cr7, rMASK, 0
++ beq cr7, L(loop_null)
++ /* OK, one (or both) of the words contains a null byte. Check the
++ first word and decrement the address in case the first word really
++ contains a null byte. */
++ cmpdi cr6, rTMP2, 0
++ addi rSTR, rSTR, -8
++ bne cr6, L(done_null)
++ /* The null byte must be in the second word. Adjust the address
++ again and move the result of cmpb to rTMP4 so we can calculate the
++ pointer. */
++ mr rTMP2, rTMP4
++ addi rSTR, rSTR, 8
++ /* rTMP2 has the output of the cmpb instruction, that is, it contains
++ 0xff in the same position as the null byte in the original word
++ from the string. Use that to calculate the pointer. */
++ b L(done_null)
++L(loop_null):
++ /* Load two words, compare and merge in a single register for speed.
++ This is an attempt to speed up the null-checking process for bigger
++ strings. */
++ ld rWORD, 8(rSTR)
++ ldu rTMP5, 16(rSTR)
++ cmpb rTMP2, rWORD, rTMP1
++ cmpb rTMP4, rTMP5, rTMP1
++ or rMASK, rTMP2, rTMP4
++ cmpdi cr7, rMASK, 0
++ beq cr7, L(loop_null)
++ /* OK, one (or both) of the words contains a null byte. Check the
++ first word and decrement the address in case the first word really
++ contains a null byte. */
++ cmpdi cr6, rTMP2, 0
++ addi rSTR, rSTR, -8
++ bne cr6, L(done_null)
++ /* The null byte must be in the second word. Adjust the address
++ again and move the result of cmpb to rTMP4 so we can calculate the
++ pointer. */
++ mr rTMP2, rTMP4
++ addi rSTR, rSTR, 8
++ /* rTMP2 has the output of the cmpb instruction, that is, it contains
++ 0xff in the same position as the null byte in the original word
++ from the string. Use that to calculate the pointer. */
++L(done_null):
++ cntlzd rTMP1, rTMP2 /* Count the leading zeros before the
++ match. */
++ srdi rTMP1, rTMP1, 3 /* Convert leading zeros to bytes. */
++ add rRTN, rSTR, rTMP1 /* Return address of the matching null
++ byte. */
++ blr
++
++END (strrchr)
++
++weak_alias (strrchr, rindex)
++libc_hidden_builtin_def (strrchr)
diff --git a/recipes-core/glibc/glibc-fsl/0018.glibc.testsuite_remove-blocking-test.patch b/recipes-core/glibc/glibc-fsl/0018.glibc.testsuite_remove-blocking-test.patch
new file mode 100755
index 0000000..920274f
--- /dev/null
+++ b/recipes-core/glibc/glibc-fsl/0018.glibc.testsuite_remove-blocking-test.patch
@@ -0,0 +1,258 @@
+# Problem Statement:
+ Temporary fix for the eglibc tests to continue running without getting hanged
+
+# Owned By:
+ Ram
+
+# Actions:
+ Remove the 'rt/tst-mqueue3.c' test case, which is blocking the tests to
+ continue, from the eglibc testsuite
+
+
+diff -Naur libc/rt/tst-mqueue3.c libc_eglibc_tests/rt/tst-mqueue3.c
+--- libc/rt/tst-mqueue3.c 2014-06-11 02:44:11.000000000 -0500
++++ libc_eglibc_tests/rt/tst-mqueue3.c 1969-12-31 18:00:00.000000000 -0600
+@@ -1,243 +0,0 @@
+-/* Test SIGEV_THREAD handling for POSIX message queues.
+- Copyright (C) 2004-2014 Free Software Foundation, Inc.
+- This file is part of the GNU C Library.
+- Contributed by Ulrich Drepper <drepper at redhat.com>, 2004.
+-
+- 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, see
+- <http://www.gnu.org/licenses/>. */
+-
+-#include <errno.h>
+-#include <mqueue.h>
+-#include <signal.h>
+-#include <stddef.h>
+-#include <stdint.h>
+-#include <stdio.h>
+-#include <stdlib.h>
+-#include <string.h>
+-#include <sys/mman.h>
+-#include <sys/wait.h>
+-#include <unistd.h>
+-
+-#if _POSIX_THREADS
+-# include <pthread.h>
+-
+-static pid_t pid;
+-static mqd_t m;
+-static const char message[] = "hello";
+-
+-# define MAXMSG 10
+-# define MSGSIZE 10
+-# define UNIQUE 42
+-
+-
+-static void
+-fct (union sigval s)
+-{
+- /* Put the mq in non-blocking mode. */
+- struct mq_attr attr;
+- if (mq_getattr (m, &attr) != 0)
+- {
+- printf ("%s: mq_getattr failed: %m\n", __FUNCTION__);
+- exit (1);
+- }
+- attr.mq_flags |= O_NONBLOCK;
+- if (mq_setattr (m, &attr, NULL) != 0)
+- {
+- printf ("%s: mq_setattr failed: %m\n", __FUNCTION__);
+- exit (1);
+- }
+-
+- /* Check the values. */
+- if (attr.mq_maxmsg != MAXMSG)
+- {
+- printf ("%s: mq_maxmsg wrong: is %ld, expecte %d\n",
+- __FUNCTION__, attr.mq_maxmsg, MAXMSG);
+- exit (1);
+- }
+- if (attr.mq_msgsize != MAXMSG)
+- {
+- printf ("%s: mq_msgsize wrong: is %ld, expecte %d\n",
+- __FUNCTION__, attr.mq_msgsize, MSGSIZE);
+- exit (1);
+- }
+-
+- /* Read the message. */
+- char buf[attr.mq_msgsize];
+- ssize_t n = TEMP_FAILURE_RETRY (mq_receive (m, buf, attr.mq_msgsize, NULL));
+- if (n != sizeof (message))
+- {
+- printf ("%s: length of message wrong: is %zd, expected %zu\n",
+- __FUNCTION__, n, sizeof (message));
+- exit (1);
+- }
+- if (memcmp (buf, message, sizeof (message)) != 0)
+- {
+- printf ("%s: message wrong: is \"%s\", expected \"%s\"\n",
+- __FUNCTION__, buf, message);
+- exit (1);
+- }
+-
+- exit (UNIQUE);
+-}
+-
+-
+-int
+-do_test (void)
+-{
+- char tmpfname[] = "/tmp/tst-mqueue3-barrier.XXXXXX";
+- int fd = mkstemp (tmpfname);
+- if (fd == -1)
+- {
+- printf ("cannot open temporary file: %m\n");
+- return 1;
+- }
+-
+- /* Make sure it is always removed. */
+- unlink (tmpfname);
+-
+- /* Create one page of data. */
+- size_t ps = sysconf (_SC_PAGESIZE);
+- char data[ps];
+- memset (data, '\0', ps);
+-
+- /* Write the data to the file. */
+- if (write (fd, data, ps) != (ssize_t) ps)
+- {
+- puts ("short write");
+- return 1;
+- }
+-
+- void *mem = mmap (NULL, ps, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0);
+- if (mem == MAP_FAILED)
+- {
+- printf ("mmap failed: %m\n");
+- return 1;
+- }
+-
+- pthread_barrier_t *b;
+- b = (pthread_barrier_t *) (((uintptr_t) mem + __alignof (pthread_barrier_t))
+- & ~(__alignof (pthread_barrier_t) - 1));
+-
+- pthread_barrierattr_t a;
+- if (pthread_barrierattr_init (&a) != 0)
+- {
+- puts ("barrierattr_init failed");
+- return 1;
+- }
+-
+- if (pthread_barrierattr_setpshared (&a, PTHREAD_PROCESS_SHARED) != 0)
+- {
+- puts ("barrierattr_setpshared failed, could not test");
+- return 0;
+- }
+-
+- if (pthread_barrier_init (b, &a, 2) != 0)
+- {
+- puts ("barrier_init failed");
+- return 1;
+- }
+-
+- if (pthread_barrierattr_destroy (&a) != 0)
+- {
+- puts ("barrierattr_destroy failed");
+- return 1;
+- }
+-
+- /* Name for the message queue. */
+- char mqname[sizeof ("/tst-mqueue3-") + 3 * sizeof (pid_t)];
+- snprintf (mqname, sizeof (mqname) - 1, "/tst-mqueue3-%ld",
+- (long int) getpid ());
+-
+- /* Create the message queue. */
+- struct mq_attr attr = { .mq_maxmsg = MAXMSG, .mq_msgsize = MSGSIZE };
+- m = mq_open (mqname, O_CREAT | O_EXCL | O_RDWR, 0600, &attr);
+- if (m == -1)
+- {
+- if (errno == ENOSYS)
+- {
+- puts ("not implemented");
+- return 0;
+- }
+-
+- puts ("mq_open failed");
+- return 1;
+- }
+-
+- /* Unlink the message queue right away. */
+- if (mq_unlink (mqname) != 0)
+- {
+- puts ("mq_unlink failed");
+- return 1;
+- }
+-
+- pid = fork ();
+- if (pid == -1)
+- {
+- puts ("fork failed");
+- return 1;
+- }
+- if (pid == 0)
+- {
+- /* Request notification via thread. */
+- struct sigevent ev;
+- ev.sigev_notify = SIGEV_THREAD;
+- ev.sigev_notify_function = fct;
+- ev.sigev_value.sival_ptr = NULL;
+- ev.sigev_notify_attributes = NULL;
+-
+- /* Tell the kernel. */
+- if (mq_notify (m,&ev) != 0)
+- {
+- puts ("mq_notify failed");
+- exit (1);
+- }
+-
+- /* Tell the parent we are ready. */
+- (void) pthread_barrier_wait (b);
+-
+- /* Make sure the process goes away eventually. */
+- alarm (10);
+-
+- /* Do nothing forever. */
+- while (1)
+- pause ();
+- }
+-
+- /* Wait for the child process to register to notification method. */
+- (void) pthread_barrier_wait (b);
+-
+- /* Send the message. */
+- if (mq_send (m, message, sizeof (message), 1) != 0)
+- {
+- kill (pid, SIGKILL);
+- puts ("mq_send failed");
+- return 1;
+- }
+-
+- int r;
+- if (TEMP_FAILURE_RETRY (waitpid (pid, &r, 0)) != pid)
+- {
+- kill (pid, SIGKILL);
+- puts ("waitpid failed");
+- return 1;
+- }
+-
+- return WIFEXITED (r) && WEXITSTATUS (r) == UNIQUE ? 0 : 1;
+-}
+-# define TEST_FUNCTION do_test ()
+-#else
+-# define TEST_FUNCTION 0
+-#endif
+-
+-#include "../test-skeleton.c"
diff --git a/recipes-core/glibc/glibc-fsl/0019.glibc.readv_proto.patch b/recipes-core/glibc/glibc-fsl/0019.glibc.readv_proto.patch
new file mode 100755
index 0000000..df9da4e
--- /dev/null
+++ b/recipes-core/glibc/glibc-fsl/0019.glibc.readv_proto.patch
@@ -0,0 +1,61 @@
+glibc.readv_proto
+
+Unfortunate choice of variable names. Causes syntax errors on Altivec
+enabled targets.
+
+diff -Naur glibc-2.20/sysdeps/unix/sysv/linux/readv.c glibc-2.20-patch/sysdeps/unix/sysv/linux/readv.c
+--- glibc-2.20/sysdeps/unix/sysv/linux/readv.c 2014-09-07 03:09:09.000000000 -0500
++++ glibc-2.20-patch/sysdeps/unix/sysv/linux/readv.c 2015-02-12 10:56:11.773738962 -0600
+@@ -27,20 +27,20 @@
+ /* Consider moving to syscalls.list. */
+
+ ssize_t
+-__libc_readv (fd, vector, count)
++__libc_readv (fd, vec_tor, count)
+ int fd;
+- const struct iovec *vector;
++ const struct iovec *vec_tor;
+ int count;
+ {
+ ssize_t result;
+
+ if (SINGLE_THREAD_P)
+- result = INLINE_SYSCALL (readv, 3, fd, vector, count);
++ result = INLINE_SYSCALL (readv, 3, fd, vec_tor, count);
+ else
+ {
+ int oldtype = LIBC_CANCEL_ASYNC ();
+
+- result = INLINE_SYSCALL (readv, 3, fd, vector, count);
++ result = INLINE_SYSCALL (readv, 3, fd, vec_tor, count);
+
+ LIBC_CANCEL_RESET (oldtype);
+ }
+diff -Naur glibc-2.20/sysdeps/unix/sysv/linux/writev.c glibc-2.20-patch/sysdeps/unix/sysv/linux/writev.c
+--- glibc-2.20/sysdeps/unix/sysv/linux/writev.c 2014-09-07 03:09:09.000000000 -0500
++++ glibc-2.20-patch/sysdeps/unix/sysv/linux/writev.c 2015-02-12 10:56:11.774738974 -0600
+@@ -28,20 +28,20 @@
+ /* Consider moving to syscalls.list. */
+
+ ssize_t
+-__libc_writev (fd, vector, count)
++__libc_writev (fd, vec_tor, count)
+ int fd;
+- const struct iovec *vector;
++ const struct iovec *vec_tor;
+ int count;
+ {
+ ssize_t result;
+
+ if (SINGLE_THREAD_P)
+- result = INLINE_SYSCALL (writev, 3, fd, vector, count);
++ result = INLINE_SYSCALL (writev, 3, fd, vec_tor, count);
+ else
+ {
+ int oldtype = LIBC_CANCEL_ASYNC ();
+
+- result = INLINE_SYSCALL (writev, 3, fd, vector, count);
++ result = INLINE_SYSCALL (writev, 3, fd, vec_tor, count);
+
+ LIBC_CANCEL_RESET (oldtype);
+ }
diff --git a/recipes-core/glibc/glibc-fsl/0020.glibc.fsl-largemcpy-e500mc-e5500-e6500.patch b/recipes-core/glibc/glibc-fsl/0020.glibc.fsl-largemcpy-e500mc-e5500-e6500.patch
new file mode 100755
index 0000000..b0097f7
--- /dev/null
+++ b/recipes-core/glibc/glibc-fsl/0020.glibc.fsl-largemcpy-e500mc-e5500-e6500.patch
@@ -0,0 +1,932 @@
+diff -ruN glibc-2.20-mcpy-new-large-original/include/string.h glibc-2.20-mcpy-new-large-mcpy-new/include/string.h
+--- glibc-2.20-mcpy-new-large-original/include/string.h 2015-09-02 14:28:58.404187000 -0500
++++ glibc-2.20-mcpy-new-large-mcpy-new/include/string.h 2015-09-02 14:30:49.773187000 -0500
+@@ -70,6 +70,9 @@
+ }))
+ #endif
+
++#if defined (__powerpc__)
++libc_hidden_proto (largememcpy)
++#endif
+ libc_hidden_proto (__mempcpy)
+ libc_hidden_proto (__stpcpy)
+ libc_hidden_proto (__stpncpy)
+diff -ruN glibc-2.20-mcpy-new-large-original/string/string.h glibc-2.20-mcpy-new-large-mcpy-new/string/string.h
+--- glibc-2.20-mcpy-new-large-original/string/string.h 2015-09-02 14:28:58.383187000 -0500
++++ glibc-2.20-mcpy-new-large-mcpy-new/string/string.h 2015-09-02 14:30:49.752187000 -0500
+@@ -45,6 +45,10 @@
+ /* Copy N bytes of SRC to DEST. */
+ extern void *memcpy (void *__restrict __dest, const void *__restrict __src,
+ size_t __n) __THROW __nonnull ((1, 2));
++#if defined (__powerpc__)
++extern void *largememcpy (void *__restrict __dest, const void *__restrict __src,
++ size_t __n) __THROW __nonnull ((1, 2));
++#endif
+ /* Copy N bytes of SRC to DEST, guaranteeing
+ correct behavior for overlapping strings. */
+ extern void *memmove (void *__dest, const void *__src, size_t __n)
+diff -ruN glibc-2.20-mcpy-new-large-original/sysdeps/powerpc/memcpy.c glibc-2.20-mcpy-new-large-mcpy-new/sysdeps/powerpc/memcpy.c
+--- glibc-2.20-mcpy-new-large-original/sysdeps/powerpc/memcpy.c 1969-12-31 18:00:00.000000000 -0600
++++ glibc-2.20-mcpy-new-large-mcpy-new/sysdeps/powerpc/memcpy.c 2015-09-02 14:30:49.590187000 -0500
+@@ -0,0 +1,4 @@
++#include <string/memcpy.c>
++
++weak_alias (memcpy, largememcpy)
++libc_hidden_def (largememcpy)
+diff -ruN glibc-2.20-mcpy-new-large-original/sysdeps/powerpc/powerpc32/405/memcpy.S glibc-2.20-mcpy-new-large-mcpy-new/sysdeps/powerpc/powerpc32/405/memcpy.S
+--- glibc-2.20-mcpy-new-large-original/sysdeps/powerpc/powerpc32/405/memcpy.S 2015-09-02 14:28:58.206187000 -0500
++++ glibc-2.20-mcpy-new-large-mcpy-new/sysdeps/powerpc/powerpc32/405/memcpy.S 2015-09-02 14:30:49.554187000 -0500
+@@ -128,3 +128,5 @@
+ blr
+ END (memcpy)
+ libc_hidden_builtin_def (memcpy)
++weak_alias (memcpy,largememcpy)
++libc_hidden_def (largememcpy)
+diff -ruN glibc-2.20-mcpy-new-large-original/sysdeps/powerpc/powerpc32/a2/memcpy.S glibc-2.20-mcpy-new-large-mcpy-new/sysdeps/powerpc/powerpc32/a2/memcpy.S
+--- glibc-2.20-mcpy-new-large-original/sysdeps/powerpc/powerpc32/a2/memcpy.S 2015-09-02 14:28:58.194187000 -0500
++++ glibc-2.20-mcpy-new-large-mcpy-new/sysdeps/powerpc/powerpc32/a2/memcpy.S 2015-09-02 14:30:49.541187000 -0500
+@@ -525,3 +525,5 @@
+
+ END (memcpy)
+ libc_hidden_builtin_def (memcpy)
++weak_alias (memcpy, largememcpy)
++libc_hidden_def (largememcpy)
+diff -ruN glibc-2.20-mcpy-new-large-original/sysdeps/powerpc/powerpc32/cell/memcpy.S glibc-2.20-mcpy-new-large-mcpy-new/sysdeps/powerpc/powerpc32/cell/memcpy.S
+--- glibc-2.20-mcpy-new-large-original/sysdeps/powerpc/powerpc32/cell/memcpy.S 2015-09-02 14:28:58.213187000 -0500
++++ glibc-2.20-mcpy-new-large-mcpy-new/sysdeps/powerpc/powerpc32/cell/memcpy.S 2015-09-02 14:30:49.561187000 -0500
+@@ -240,3 +240,5 @@
+
+ END (memcpy)
+ libc_hidden_builtin_def (memcpy)
++weak_alias (memcpy, largememcpy)
++libc_hidden_def (largememcpy)
+diff -ruN glibc-2.20-mcpy-new-large-original/sysdeps/powerpc/powerpc32/e500/memcpy.S glibc-2.20-mcpy-new-large-mcpy-new/sysdeps/powerpc/powerpc32/e500/memcpy.S
+--- glibc-2.20-mcpy-new-large-original/sysdeps/powerpc/powerpc32/e500/memcpy.S 2015-09-02 14:29:07.888186901 -0500
++++ glibc-2.20-mcpy-new-large-mcpy-new/sysdeps/powerpc/powerpc32/e500/memcpy.S 2015-09-02 14:30:49.539187000 -0500
+@@ -406,3 +406,8 @@
+
+ END (FUNCTION)
+ libc_hidden_builtin_def (FUNCTION)
++
++#ifndef __MEMMOVE__
++weak_alias (memcpy,largememcpy)
++libc_hidden_def (largememcpy)
++#endif
+diff -ruN glibc-2.20-mcpy-new-large-original/sysdeps/powerpc/powerpc32/e500mc/largememcpy.S glibc-2.20-mcpy-new-large-mcpy-new/sysdeps/powerpc/powerpc32/e500mc/largememcpy.S
+--- glibc-2.20-mcpy-new-large-original/sysdeps/powerpc/powerpc32/e500mc/largememcpy.S 1969-12-31 18:00:00.000000000 -0600
++++ glibc-2.20-mcpy-new-large-mcpy-new/sysdeps/powerpc/powerpc32/e500mc/largememcpy.S 2015-09-02 14:54:00.062186965 -0500
+@@ -0,0 +1,499 @@
++/* Optimized largememcpy implementation for e500mc 32-bit PowerPC.
++ This version uses cache management instructions.
++
++ Copyright (C) 2015 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 <sysdep.h>
++
++/* __ptr_t [r3]
++ largememcpy (__ptr_t dst [r3], __ptr_t src [r4], size_t len [r5]);
++ Returns 'dst'.
++
++ r3 = destination
++ r4 = source
++ r5 = byte count
++
++ volatile fixed point registers usable:
++ r0, r3-r12
++
++ volatile floating point registers usable:
++ f0-f13. */
++
++EALIGN (largememcpy, 5, 0)
++ cmplw cr0, r4, r3 /* if source==destination, return. */
++ beqlr cr0
++ /* if number of bytes is less than 8 (optimal value TBD),
++ but greater than zero, copy byte-by-byte. */
++ cmplwi r5, 8
++ mr r6, r3
++ blt L(copy_bytes)
++ neg r0, r4
++ andi. r11, r0, 3
++ beq L(src_aligned4)
++ /* We have to align the src pointer by r11 bytes */
++ cmplwi cr0, r11, 1
++ ble L(src_1)
++ /* 2 or 3 bytes */
++ addi r8, r11, -2
++ lhz r9, 0(r4)
++ lhzx r12, r4, r8
++ sth r9, 0(r6)
++ sthx r12, r6, r8
++ b L(src_0)
++L(src_1):
++ lbz r8, 0(r4)
++ stb r8, 0(r6)
++L(src_0):
++ subf r5, r11, r5
++ add r4, r4, r11
++ add r6, r6, r11
++L(src_aligned4):
++ cmplwi 7, r5, 63
++ ble 7, L(copy_remaining)
++ andi. r10, r0, 63
++ beq L(src_aligned64)
++ subf. r10, r11, r10
++ beq 0, L(src_aligned64)
++ srwi r11, r10, 2
++ subf r5, r10, r5
++ mtctr r11
++L(copy_salign4):
++ lwz 0, 0(r4)
++ addi r4, r4, 4
++ stw 0, 0(r6)
++ addi r6, r6, 4
++ bdnz L(copy_salign4)
++L(src_aligned64):
++ srwi. r11, r5, 6 /* No of 64 byte copy count. */
++ beq 0, L(copy_remaining)
++ rlwinm r5, r5, 0, 26, 31 /* remaining bytes. */
++ rlwinm. r0, r6, 0, 29, 31
++ bne 0, L(src_dnalign)
++ cmplwi 7, r11, 256
++ ble 7, L(label1)
++ addi r7, r11, -256
++ mtctr r7
++#ifdef SHARED
++ mflr r0
++ /* Establishes GOT addressability so we can load __cache_line_size from
++ static. This value was set from the aux vector during startup. */
++ SETUP_GOT_ACCESS(r9,got_label_1)
++ addis r9, r9, __cache_line_size-got_label_1 at ha
++ lwz r9, __cache_line_size-got_label_1 at l(r9)
++ mtlr r0
++#else
++ /* Load __cache_line_size from static. This value was set from the
++ aux vector during startup. */
++ lis r9, __cache_line_size at ha
++ lwz r9, __cache_line_size at l(r9)
++#endif
++ cmplwi 5, r9, 64
++ li r10, 256
++ li r12, 64
++ bne 5, L(lcopy_dalign_nc)
++L(lcopy_dalign):
++ dcbt r10, r4
++ dcbzl r12, r6
++#ifndef _SOFT_FLOAT
++ lfd 0, 0(r4)
++ lfd 1, 8(r4)
++ lfd 2, 16(r4)
++ lfd 3, 24(r4)
++ lfd 4, 32(r4)
++ lfd 5, 40(r4)
++ lfd 6, 48(r4)
++ lfd 7, 56(r4)
++ stfd 0, 0(r6)
++ stfd 1, 8(r6)
++ stfd 2, 16(r6)
++ stfd 3, 24(r6)
++ addi r4, r4, 64
++ stfd 4, 32(r6)
++ stfd 5, 40(r6)
++ stfd 6, 48(r6)
++ stfd 7, 56(r6)
++#else
++ lwz r0, 0(r4)
++ lwz r8, 4(r4)
++ lwz r9, 8(r4)
++ stw r0, 0(r6)
++ stw r8, 4(r6)
++ stw r9, 8(r6)
++ lwz r0, 12(r4)
++ lwz r8, 16(r4)
++ lwz r9, 20(r4)
++ stw r0, 12(r6)
++ stw r8, 16(r6)
++ stw r9, 20(r6)
++ lwz r0, 24(r4)
++ lwz r8, 28(r4)
++ lwz r9, 32(r4)
++ stw r0, 24(r6)
++ stw r8, 28(r6)
++ stw r9, 32(r6)
++ lwz r0, 36(r4)
++ lwz r8, 40(r4)
++ lwz r9, 44(r4)
++ stw r0, 36(r6)
++ stw r8, 40(r6)
++ stw r9, 44(r6)
++ lwz r0, 48(r4)
++ lwz r8, 52(r4)
++ lwz r9, 56(r4)
++ stw r0, 48(r6)
++ lwz r0, 60(r4)
++ addi r4, r4, 64
++ stw r8, 52(r6)
++ stw r9, 56(r6)
++ stw r0, 60(r6)
++#endif
++ dcbf 0, r6
++ addi r6, r6, 64
++ bdnz L(lcopy_dalign)
++ subf r11, r7, r11
++L(label1):
++ mtctr r11
++L(copy_dalign):
++#ifndef _SOFT_FLOAT
++ lfd 0, 0(r4)
++ lfd 1, 8(r4)
++ lfd 2, 16(r4)
++ lfd 3, 24(r4)
++ stfd 0, 0(r6)
++ stfd 1, 8(r6)
++ stfd 2, 16(r6)
++ stfd 3, 24(r6)
++ lfd 0, 32(r4)
++ lfd 1, 40(r4)
++ lfd 2, 48(r4)
++ lfd 3, 56(r4)
++ addi r4, r4, 64
++ stfd 0, 32(r6)
++ stfd 1, 40(r6)
++ stfd 2, 48(r6)
++ stfd 3, 56(r6)
++#else
++ lwz r0, 0(r4)
++ lwz r8, 4(r4)
++ lwz r9, 8(r4)
++ stw r0, 0(r6)
++ stw r8, 4(r6)
++ stw r9, 8(r6)
++ lwz r0, 12(r4)
++ lwz r8, 16(r4)
++ lwz r9, 20(r4)
++ stw r0, 12(r6)
++ stw r8, 16(r6)
++ stw r9, 20(r6)
++ lwz r0, 24(r4)
++ lwz r8, 28(r4)
++ lwz r9, 32(r4)
++ stw r0, 24(r6)
++ stw r8, 28(r6)
++ stw r9, 32(r6)
++ lwz r0, 36(r4)
++ lwz r8, 40(r4)
++ lwz r9, 44(r4)
++ stw r0, 36(r6)
++ stw r8, 40(r6)
++ stw r9, 44(r6)
++ lwz r0, 48(r4)
++ lwz r8, 52(r4)
++ lwz r9, 56(r4)
++ stw r0, 48(r6)
++ lwz r0, 60(r4)
++ addi r4, r4, 64
++ stw r8, 52(r6)
++ stw r9, 56(r6)
++ stw r0, 60(r6)
++#endif
++ addi r6, r6, 64
++ bdnz L(copy_dalign)
++L(copy_remaining):
++ srwi. r11, r5, 3 /* No of 8 byte copy count. */
++ rlwinm r5, r5, 0, 29, 31 /* remaining bytes. */
++ beq 0, L(copy_bytes)
++ mtcrf 0x01, r11
++ bf cr7*4+1, L(cp16b)
++ lwz r0, 0(r4) /* copy 32 bytes. */
++ lwz r8, 4(r4)
++ lwz r9, 8(r4)
++ stw r0, 0(r6)
++ stw r8, 4(r6)
++ stw r9, 8(r6)
++ lwz r0, 12(r4)
++ lwz r8, 16(r4)
++ lwz r9, 20(r4)
++ stw r0, 12(r6)
++ stw r8, 16(r6)
++ lwz r0, 24(r4)
++ lwz r8, 28(r4)
++ addi r4, r4, 32
++ stw r9, 20(r6)
++ stw r0, 24(r6)
++ stw r8, 28(r6)
++ addi r6, r6, 32
++L(cp16b):
++ bf cr7*4+2, L(cp8b)
++ lwz r0, 0(r4) /* copy 16 bytes. */
++ lwz r7, 4(r4)
++ lwz r8, 8(r4)
++ lwz r9, 12(r4)
++ addi r4, r4, 16
++ stw r0, 0(r6)
++ stw r7, 4(r6)
++ stw r8, 8(r6)
++ stw r9, 12(r6)
++ addi r6, r6, 16
++L(cp8b):
++ bf cr7*4+3, L(copy_bytes)
++ lwz r0, 0(r4) /* copy 8 bytes. */
++ lwz r7, 4(r4)
++ addi r4, r4, 8
++ stw r0, 0(r6)
++ stw r7, 4(r6)
++ addi r6, r6, 8
++L(copy_bytes):
++ cmplwi cr1, r5, 4
++ cmplwi cr0, r5, 1
++ bgt cr1, L(gt4b) /* nb > 4? (5, 6, 7 bytes). */
++ ble cr0, L(lt1b) /* nb <= 1? (0, 1 bytes). */
++ addi r0, r5, -2 /* 2, 3, 4 bytes. */
++ lhz r9, 0(r4)
++ lhzx r11, r4, r0
++ sth r9, 0(r6)
++ sthx r11, r6, r0
++ blr
++L(gt4b):
++ addi r0, r5, -4 /* 5, 6, 7 bytes. */
++ lwz r9, 0(r4)
++ lwzx r11, r4, r0
++ stw r9, 0(r6)
++ stwx r11, r6, r0
++ blr
++L(lt1b):
++ mtocrf 0x1, r5 /* nb == 0 ? return. */
++ bflr 31
++ lbz r0, 0(r4) /* nb == 1. */
++ stb r0, 0(r6)
++ blr
++
++L(src_dnalign):
++ cmplwi 7, r11, 256
++ ble 7, L(label2)
++ addi r7, r11, -256
++ mtctr r7
++#ifdef SHARED
++ mflr r0
++ /* Establishes GOT addressability so we can load __cache_line_size from
++ static. This value was set from the aux vector during startup. */
++ SETUP_GOT_ACCESS(r9,got_label_2)
++ addis r9, r9, __cache_line_size-got_label_2 at ha
++ lwz r9, __cache_line_size-got_label_2 at l(r9)
++ mtlr r0
++#else
++ /* Load __cache_line_size from static. This value was set from the
++ aux vector during startup. */
++ lis r9, __cache_line_size at ha
++ lwz r9, __cache_line_size at l(r9)
++#endif
++ cmplwi 5, r9, 64
++ li r10, 256
++ li r12, 64
++ bne 5, L(lcopy_dnalign_nc)
++L(lcopy_dnalign):
++ dcbt r10, r4
++ dcbzl r12, r6
++ lwz r0, 0(r4) /* copy 64 bytes. */
++ lwz r8, 4(r4)
++ lwz r9, 8(r4)
++ stw r0, 0(r6)
++ stw r8, 4(r6)
++ stw r9, 8(r6)
++ lwz r0, 12(r4)
++ lwz r8, 16(r4)
++ lwz r9, 20(r4)
++ stw r0, 12(r6)
++ stw r8, 16(r6)
++ stw r9, 20(r6)
++ lwz r0, 24(r4)
++ lwz r8, 28(r4)
++ lwz r9, 32(r4)
++ stw r0, 24(r6)
++ stw r8, 28(r6)
++ stw r9, 32(r6)
++ lwz r0, 36(r4)
++ lwz r8, 40(r4)
++ lwz r9, 44(r4)
++ stw r0, 36(r6)
++ stw r8, 40(r6)
++ stw r9, 44(r6)
++ lwz r0, 48(r4)
++ lwz r8, 52(r4)
++ lwz r9, 56(r4)
++ stw r0, 48(r6)
++ lwz r0, 60(r4)
++ addi r4, r4, 64
++ stw r8, 52(r6)
++ stw r9, 56(r6)
++ stw r0, 60(r6)
++ dcbf 0, r6
++ addi r6, r6, 64
++ bdnz L(lcopy_dnalign)
++ li r11, 256
++L(label2):
++ mtctr r11
++L(copy_dnalign):
++ lwz r0, 0(r4) /* copy 64 bytes. */
++ lwz r8, 4(r4)
++ lwz r9, 8(r4)
++ stw r0, 0(r6)
++ stw r8, 4(r6)
++ stw r9, 8(r6)
++ lwz r0, 12(r4)
++ lwz r8, 16(r4)
++ lwz r9, 20(r4)
++ stw r0, 12(r6)
++ stw r8, 16(r6)
++ stw r9, 20(r6)
++ lwz r0, 24(r4)
++ lwz r8, 28(r4)
++ lwz r9, 32(r4)
++ stw r0, 24(r6)
++ stw r8, 28(r6)
++ stw r9, 32(r6)
++ lwz r0, 36(r4)
++ lwz r8, 40(r4)
++ lwz r9, 44(r4)
++ stw r0, 36(r6)
++ stw r8, 40(r6)
++ stw r9, 44(r6)
++ lwz r0, 48(r4)
++ lwz r8, 52(r4)
++ lwz r9, 56(r4)
++ stw r0, 48(r6)
++ lwz r0, 60(r4)
++ addi r4, r4, 64
++ stw r8, 52(r6)
++ stw r9, 56(r6)
++ stw r0, 60(r6)
++ addi r6, r6, 64
++ bdnz L(copy_dnalign)
++ b L(copy_remaining)
++
++L(lcopy_dalign_nc):
++#ifndef _SOFT_FLOAT
++ lfd 0, 0(r4) /* copy 64 bytes. */
++ lfd 1, 8(r4)
++ lfd 2, 16(r4)
++ lfd 3, 24(r4)
++ lfd 4, 32(r4)
++ lfd 5, 40(r4)
++ lfd 6, 48(r4)
++ lfd 7, 56(r4)
++ stfd 0, 0(r6)
++ stfd 1, 8(r6)
++ stfd 2, 16(r6)
++ stfd 3, 24(r6)
++ addi r4, r4, 64
++ stfd 4, 32(r6)
++ stfd 5, 40(r6)
++ stfd 6, 48(r6)
++ stfd 7, 56(r6)
++#else
++ lwz r0, 0(r4) /* copy 64 bytes. */
++ lwz r8, 4(r4)
++ lwz r9, 8(r4)
++ stw r0, 0(r6)
++ stw r8, 4(r6)
++ stw r9, 8(r6)
++ lwz r0, 12(r4)
++ lwz r8, 16(r4)
++ lwz r9, 20(r4)
++ stw r0, 12(r6)
++ stw r8, 16(r6)
++ stw r9, 20(r6)
++ lwz r0, 24(r4)
++ lwz r8, 28(r4)
++ lwz r9, 32(r4)
++ stw r0, 24(r6)
++ stw r8, 28(r6)
++ stw r9, 32(r6)
++ lwz r0, 36(r4)
++ lwz r8, 40(r4)
++ lwz r9, 44(r4)
++ stw r0, 36(r6)
++ stw r8, 40(r6)
++ stw r9, 44(r6)
++ lwz r0, 48(r4)
++ lwz r8, 52(r4)
++ lwz r9, 56(r4)
++ stw r0, 48(r6)
++ lwz r0, 60(r4)
++ addi r4, r4, 64
++ stw r8, 52(r6)
++ stw r9, 56(r6)
++ stw r0, 60(r6)
++#endif
++ addi r6, r6, 64
++ bdnz L(lcopy_dalign_nc)
++ subf r11, r7, r11
++ b L(label1)
++
++L(lcopy_dnalign_nc):
++ lwz r0, 0(r4) /* copy 64 bytes. */
++ lwz r8, 4(r4)
++ lwz r9, 8(r4)
++ stw r0, 0(r6)
++ stw r8, 4(r6)
++ stw r9, 8(r6)
++ lwz r0, 12(r4)
++ lwz r8, 16(r4)
++ lwz r9, 20(r4)
++ stw r0, 12(r6)
++ stw r8, 16(r6)
++ stw r9, 20(r6)
++ lwz r0, 24(r4)
++ lwz r8, 28(r4)
++ lwz r9, 32(r4)
++ stw r0, 24(r6)
++ stw r8, 28(r6)
++ stw r9, 32(r6)
++ lwz r0, 36(r4)
++ lwz r8, 40(r4)
++ lwz r9, 44(r4)
++ stw r0, 36(r6)
++ stw r8, 40(r6)
++ stw r9, 44(r6)
++ lwz r0, 48(r4)
++ lwz r8, 52(r4)
++ lwz r9, 56(r4)
++ stw r0, 48(r6)
++ lwz r0, 60(r4)
++ addi r4, r4, 64
++ stw r8, 52(r6)
++ stw r9, 56(r6)
++ stw r0, 60(r6)
++ addi r6, r6, 64
++ bdnz L(lcopy_dnalign_nc)
++ li r11, 256
++ b L(label2)
++
++END (largememcpy)
++libc_hidden_def (largememcpy)
+diff -ruN glibc-2.20-mcpy-new-large-original/sysdeps/powerpc/powerpc32/e500mc/Makefile glibc-2.20-mcpy-new-large-mcpy-new/sysdeps/powerpc/powerpc32/e500mc/Makefile
+--- glibc-2.20-mcpy-new-large-original/sysdeps/powerpc/powerpc32/e500mc/Makefile 1969-12-31 18:00:00.000000000 -0600
++++ glibc-2.20-mcpy-new-large-mcpy-new/sysdeps/powerpc/powerpc32/e500mc/Makefile 2015-09-02 14:30:49.552187000 -0500
+@@ -0,0 +1,5 @@
++#Makefile fragment for PowerPC e500mc core
++
++ifeq ($(subdir),string)
++sysdep_routines += largememcpy
++endif
+diff -ruN glibc-2.20-mcpy-new-large-original/sysdeps/powerpc/powerpc32/e5500/memcpy.S glibc-2.20-mcpy-new-large-mcpy-new/sysdeps/powerpc/powerpc32/e5500/memcpy.S
+--- glibc-2.20-mcpy-new-large-original/sysdeps/powerpc/powerpc32/e5500/memcpy.S 2015-09-02 14:28:58.208187000 -0500
++++ glibc-2.20-mcpy-new-large-mcpy-new/sysdeps/powerpc/powerpc32/e5500/memcpy.S 2015-09-02 14:30:49.556187000 -0500
+@@ -249,4 +249,6 @@
+ b L(copy_remaining)
+
+ END (memcpy)
++weak_alias (memcpy, largememcpy)
+ libc_hidden_builtin_def (memcpy)
++libc_hidden_def (largememcpy)
+diff -ruN glibc-2.20-mcpy-new-large-original/sysdeps/powerpc/powerpc32/e6500/memcpy.S glibc-2.20-mcpy-new-large-mcpy-new/sysdeps/powerpc/powerpc32/e6500/memcpy.S
+--- glibc-2.20-mcpy-new-large-original/sysdeps/powerpc/powerpc32/e6500/memcpy.S 2015-09-02 14:28:58.214187000 -0500
++++ glibc-2.20-mcpy-new-large-mcpy-new/sysdeps/powerpc/powerpc32/e6500/memcpy.S 2015-09-02 14:30:49.562187000 -0500
+@@ -237,3 +237,5 @@
+
+ END (memcpy)
+ libc_hidden_builtin_def (memcpy)
++weak_alias (memcpy,largememcpy)
++libc_hidden_def (largememcpy)
+diff -ruN glibc-2.20-mcpy-new-large-original/sysdeps/powerpc/powerpc32/power4/memcpy.S glibc-2.20-mcpy-new-large-mcpy-new/sysdeps/powerpc/powerpc32/power4/memcpy.S
+--- glibc-2.20-mcpy-new-large-original/sysdeps/powerpc/powerpc32/power4/memcpy.S 2015-09-02 14:28:58.194187000 -0500
++++ glibc-2.20-mcpy-new-large-mcpy-new/sysdeps/powerpc/powerpc32/power4/memcpy.S 2015-09-02 14:30:49.541187000 -0500
+@@ -479,3 +479,5 @@
+ END (memcpy)
+
+ libc_hidden_builtin_def (memcpy)
++weak_alias (memcpy, largememcpy)
++libc_hidden_def (largememcpy)
+diff -ruN glibc-2.20-mcpy-new-large-original/sysdeps/powerpc/powerpc32/power6/memcpy.S glibc-2.20-mcpy-new-large-mcpy-new/sysdeps/powerpc/powerpc32/power6/memcpy.S
+--- glibc-2.20-mcpy-new-large-original/sysdeps/powerpc/powerpc32/power6/memcpy.S 2015-09-02 14:28:58.211187000 -0500
++++ glibc-2.20-mcpy-new-large-mcpy-new/sysdeps/powerpc/powerpc32/power6/memcpy.S 2015-09-02 14:30:49.559187000 -0500
+@@ -905,3 +905,5 @@
+ END (memcpy)
+
+ libc_hidden_builtin_def (memcpy)
++weak_alias (memcpy, largememcpy)
++libc_hidden_def (largememcpy)
+diff -ruN glibc-2.20-mcpy-new-large-original/sysdeps/powerpc/powerpc32/power7/memcpy.S glibc-2.20-mcpy-new-large-mcpy-new/sysdeps/powerpc/powerpc32/power7/memcpy.S
+--- glibc-2.20-mcpy-new-large-original/sysdeps/powerpc/powerpc32/power7/memcpy.S 2015-09-02 14:28:58.207187000 -0500
++++ glibc-2.20-mcpy-new-large-mcpy-new/sysdeps/powerpc/powerpc32/power7/memcpy.S 2015-09-02 14:30:49.555187000 -0500
+@@ -536,3 +536,5 @@
+
+ END (memcpy)
+ libc_hidden_builtin_def (memcpy)
++weak_alias (memcpy, largememcpy)
++libc_hidden_def (largememcpy)
+diff -ruN glibc-2.20-mcpy-new-large-original/sysdeps/powerpc/powerpc64/a2/memcpy.S glibc-2.20-mcpy-new-large-mcpy-new/sysdeps/powerpc/powerpc64/a2/memcpy.S
+--- glibc-2.20-mcpy-new-large-original/sysdeps/powerpc/powerpc64/a2/memcpy.S 2015-09-02 14:28:58.219187000 -0500
++++ glibc-2.20-mcpy-new-large-mcpy-new/sysdeps/powerpc/powerpc64/a2/memcpy.S 2015-09-02 14:30:49.567187000 -0500
+@@ -522,3 +522,5 @@
+
+ END_GEN_TB (memcpy,TB_TOCLESS)
+ libc_hidden_builtin_def (memcpy)
++weak_alias (memcpy, largememcpy)
++libc_hidden_def (largememcpy)
+diff -ruN glibc-2.20-mcpy-new-large-original/sysdeps/powerpc/powerpc64/cell/memcpy.S glibc-2.20-mcpy-new-large-mcpy-new/sysdeps/powerpc/powerpc64/cell/memcpy.S
+--- glibc-2.20-mcpy-new-large-original/sysdeps/powerpc/powerpc64/cell/memcpy.S 2015-09-02 14:28:58.239187000 -0500
++++ glibc-2.20-mcpy-new-large-mcpy-new/sysdeps/powerpc/powerpc64/cell/memcpy.S 2015-09-02 14:30:49.588187000 -0500
+@@ -240,3 +240,5 @@
+
+ END_GEN_TB (memcpy,TB_TOCLESS)
+ libc_hidden_builtin_def (memcpy)
++weak_alias (memcpy, largememcpy)
++libc_hidden_def (largememcpy)
+diff -ruN glibc-2.20-mcpy-new-large-original/sysdeps/powerpc/powerpc64/e5500/largememcpy.S glibc-2.20-mcpy-new-large-mcpy-new/sysdeps/powerpc/powerpc64/e5500/largememcpy.S
+--- glibc-2.20-mcpy-new-large-original/sysdeps/powerpc/powerpc64/e5500/largememcpy.S 1969-12-31 18:00:00.000000000 -0600
++++ glibc-2.20-mcpy-new-large-mcpy-new/sysdeps/powerpc/powerpc64/e5500/largememcpy.S 2015-09-02 14:56:08.056186467 -0500
+@@ -0,0 +1,221 @@
++/* Optimized largememcpy implementation for e5500 64-bit PowerPC64.
++ This version uses cache management instructions.
++
++ Copyright (C) 2015 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 <sysdep.h>
++
++/* __ptr_t [r3] largememcpy __ptr_t dst [r3], __ptr_t src [r4], size_t len [r5]
++ Returns 'dst'.
++
++ r3 = destination
++ r4 = source
++ r5 = byte count
++
++ volatile fixed point registers usable:
++ r0, r3-r12
++
++ volatile floating point registers usable:
++ f0-f13. */
++
++ .section ".toc", "aw"
++.LC0:
++ .tc __cache_line_size[TC], __cache_line_size
++ .section ".text"
++ .align 2
++
++EALIGN (largememcpy, 5, 0)
++ CALL_MCOUNT 3
++ cmpld cr0, r4, r3 /* if source==destination, return. */
++ beqlr cr0
++ /* if number of bytes is less than 8, (optimal value TBD),
++ but greater than zero copy byte-by-byte. */
++ cmpldi r5, 8
++ mr r6, r3
++ blt L(copy_bytes)
++ neg r0, r4
++ andi. r11, r0, 7
++ beq L(src_aligned)
++ /* We have to align the src pointer by r11 bytes */
++ cmplwi cr1, r11, 4
++ cmplwi cr0, r11, 1
++ bgt cr1, L(src_567)
++ ble cr0, L(src_1)
++ /* 2, 3 or 4 bytes */
++ addi r0, r11, -2
++ lhz r9, 0(r4)
++ lhzx r12, r4, r0
++ sth r9, 0(r6)
++ sthx r12, r6, r0
++ b L(src_0)
++L(src_567):
++ addi r0, r11, -4
++ lwz r9, 0(r4)
++ lwzx r12, r4, r0
++ stw r9, 0(r6)
++ stwx r12, r6, r0
++ b L(src_0)
++L(src_1):
++ lbz r0, 0(r4)
++ stb r0, 0(r6)
++L(src_0):
++ subf r5, r11, r5
++ add r4, r4, r11
++ add r6, r6, r11
++L(src_aligned):
++ cmpldi 7, r5, 63
++ ble 7, L(copy_remaining)
++ srwi r11, r5, 6 /* No of 64 byte copy count. */
++ rlwinm. r5, r5, 0, 26, 31 /* remaining bytes. */
++ cmpldi 7, r11, 256
++ ble 7, L(2)
++ rlwinm. r0, r6, 0, 28, 31
++ cmpldi r0, 8
++ addi r7, r11, -256
++ mtctr r7
++ ble L(copy_dnaligned)
++ ld r9, .LC0 at toc(r2) /* get cache line size. */
++ lwz r9, 0(r9)
++ cmpldi 5, r9, 64
++ li r10, 256
++ li r12, 64
++ bne 5, L(copy_dnaligned)
++L(lcopy_daligned):
++ dcbt r10, r4
++ dcbzl r12, r6
++ ld r0, 0(r4) /* 64-byte copy. */
++ ld r7, 8(r4)
++ ld r8, 16(r4)
++ ld r9, 24(r4)
++ std r0, 0(r6)
++ std r7, 8(r6)
++ std r8, 16(r6)
++ std r9, 24(r6)
++ ld r0, 32(r4)
++ ld r7, 40(r4)
++ ld r8, 48(r4)
++ ld r9, 56(r4)
++ addi r4, r4, 64
++ std r0, 32(r6)
++ std r7, 40(r6)
++ std r8, 48(r6)
++ std r9, 56(r6)
++ dcbf 0, r6
++ addi r6, r6, 64
++ bdnz L(lcopy_daligned)
++L(1): li r11, 256
++L(2): mtctr r11
++L(copy_daligned):
++ ld r0, 0(r4)
++ ld r7, 8(r4)
++ ld r8, 16(r4)
++ ld r9, 24(r4)
++ std r0, 0(r6)
++ std r7, 8(r6)
++ std r8, 16(r6)
++ std r9, 24(r6)
++ ld r0, 32(r4)
++ ld r7, 40(r4)
++ ld r8, 48(r4)
++ ld r9, 56(r4)
++ addi r4, r4, 64
++ std r0, 32(r6)
++ std r7, 40(r6)
++ std r8, 48(r6)
++ std r9, 56(r6)
++ addi r6, r6, 64
++ bdnz L(copy_daligned)
++L(copy_remaining):
++ srwi. r11, r5, 3 /* No of 8 byte copy count. */
++ rlwinm r5, r5, 0, 29, 31 /* remaining bytes. */
++ beq 0, L(copy_bytes)
++ mtcrf 0x01, r11
++ bf cr7*4+1, L(cp16b)
++ ld r0, 0(r4) /* copy 32 bytes. */
++ ld r7, 8(r4)
++ ld r8, 16(r4)
++ ld r9, 24(r4)
++ addi r4, r4, 32
++ std r0, 0(r6)
++ std r7, 8(r6)
++ std r8, 16(r6)
++ std r9, 24(r6)
++ addi r6, r6, 32
++L(cp16b):
++ bf cr7*4+2, L(cp8b) /* copy 16 bytes. */
++ ld r7, 0(r4)
++ ld r8, 8(r4)
++ addi r4, r4, 16
++ std r7, 0(r6)
++ std r8, 8(r6)
++ addi r6, r6, 16
++L(cp8b):
++ bf cr7*4+3, L(copy_bytes) /* copy 8 bytes. */
++ ld r7, 0(r4)
++ addi r4, r4, 8
++ std r7, 0(r6)
++ addi r6, r6, 8
++L(copy_bytes):
++ cmpldi cr1, r5, 4
++ cmpldi cr0, r5, 1
++ bgt cr1, L(gt4b) /* nb > 4? (5, 6, 7 bytes). */
++ ble cr0, L(lt1b) /* nb <= 1? (0, 1 bytes). */
++ addi r0, r5, -2 /* 2, 3, 4 bytes. */
++ lhz r9, 0(r4)
++ lhzx r11, r4, r0
++ sth r9, 0(r6)
++ sthx r11, r6, r0
++ blr
++L(gt4b):
++ addi r0, r5, -4 /* 5, 6, 7 bytes. */
++ lwz r9, 0(r4)
++ lwzx r11, r4, r0
++ stw r9, 0(r6)
++ stwx r11, r6, r0
++ blr
++L(lt1b):
++ mtocrf 0x1, r5 /* nb == 0 ? return. */
++ bflr 31
++ lbz r0, 0(r4) /* nb == 1. */
++ stb r0, 0(r6)
++ blr
++L(copy_dnaligned):
++ ld r0, 0(r4)
++ ld r7, 8(r4)
++ ld r8, 16(r4)
++ ld r9, 24(r4)
++ std r0, 0(r6)
++ std r7, 8(r6)
++ std r8, 16(r6)
++ std r9, 24(r6)
++ ld r0, 32(r4)
++ ld r7, 40(r4)
++ ld r8, 48(r4)
++ ld r9, 56(r4)
++ addi r4, r4, 64
++ std r0, 32(r6)
++ std r7, 40(r6)
++ std r8, 48(r6)
++ std r9, 56(r6)
++ addi r6, r6, 64
++ bdnz L(copy_dnaligned)
++ b L(1)
++
++END_GEN_TB (largememcpy,TB_TOCLESS)
++libc_hidden_def (largememcpy)
+diff -ruN glibc-2.20-mcpy-new-large-original/sysdeps/powerpc/powerpc64/e5500/Makefile glibc-2.20-mcpy-new-large-mcpy-new/sysdeps/powerpc/powerpc64/e5500/Makefile
+--- glibc-2.20-mcpy-new-large-original/sysdeps/powerpc/powerpc64/e5500/Makefile 1969-12-31 18:00:00.000000000 -0600
++++ glibc-2.20-mcpy-new-large-mcpy-new/sysdeps/powerpc/powerpc64/e5500/Makefile 2015-09-02 14:30:49.572187000 -0500
+@@ -0,0 +1,5 @@
++#Makefile fragment for PowerPC e5500 64-bit core
++
++ifeq ($(subdir),string)
++sysdep_routines += largememcpy
++endif
+diff -ruN glibc-2.20-mcpy-new-large-original/sysdeps/powerpc/powerpc64/e6500/memcpy.S glibc-2.20-mcpy-new-large-mcpy-new/sysdeps/powerpc/powerpc64/e6500/memcpy.S
+--- glibc-2.20-mcpy-new-large-original/sysdeps/powerpc/powerpc64/e6500/memcpy.S 2015-09-02 14:28:58.240187000 -0500
++++ glibc-2.20-mcpy-new-large-mcpy-new/sysdeps/powerpc/powerpc64/e6500/memcpy.S 2015-09-02 14:30:49.589187000 -0500
+@@ -210,4 +210,6 @@
+ b L(copy_remaining)
+
+ END_GEN_TB (memcpy,TB_TOCLESS)
++weak_alias (memcpy,largememcpy)
+ libc_hidden_builtin_def (memcpy)
++libc_hidden_def (largememcpy)
+diff -ruN glibc-2.20-mcpy-new-large-original/sysdeps/powerpc/powerpc64/power4/memcpy.S glibc-2.20-mcpy-new-large-mcpy-new/sysdeps/powerpc/powerpc64/power4/memcpy.S
+--- glibc-2.20-mcpy-new-large-original/sysdeps/powerpc/powerpc64/power4/memcpy.S 2015-09-02 14:28:58.219187000 -0500
++++ glibc-2.20-mcpy-new-large-mcpy-new/sysdeps/powerpc/powerpc64/power4/memcpy.S 2015-09-02 14:30:49.567187000 -0500
+@@ -472,3 +472,5 @@
+ blr
+ END_GEN_TB (memcpy,TB_TOCLESS)
+ libc_hidden_builtin_def (memcpy)
++weak_alias (memcpy,largememcpy)
++libc_hidden_def (largememcpy)
+diff -ruN glibc-2.20-mcpy-new-large-original/sysdeps/powerpc/powerpc64/power6/memcpy.S glibc-2.20-mcpy-new-large-mcpy-new/sysdeps/powerpc/powerpc64/power6/memcpy.S
+--- glibc-2.20-mcpy-new-large-original/sysdeps/powerpc/powerpc64/power6/memcpy.S 2015-09-02 14:28:58.238187000 -0500
++++ glibc-2.20-mcpy-new-large-mcpy-new/sysdeps/powerpc/powerpc64/power6/memcpy.S 2015-09-02 14:30:49.586187000 -0500
+@@ -1494,3 +1494,5 @@
+ blr
+ END_GEN_TB (memcpy,TB_TOCLESS)
+ libc_hidden_builtin_def (memcpy)
++weak_alias (memcpy,largememcpy)
++libc_hidden_def (largememcpy)
+diff -ruN glibc-2.20-mcpy-new-large-original/sysdeps/powerpc/powerpc64/power7/memcpy.S glibc-2.20-mcpy-new-large-mcpy-new/sysdeps/powerpc/powerpc64/power7/memcpy.S
+--- glibc-2.20-mcpy-new-large-original/sysdeps/powerpc/powerpc64/power7/memcpy.S 2015-09-02 14:28:58.222187000 -0500
++++ glibc-2.20-mcpy-new-large-mcpy-new/sysdeps/powerpc/powerpc64/power7/memcpy.S 2015-09-02 14:30:49.570187000 -0500
+@@ -424,3 +424,5 @@
+
+ END_GEN_TB (memcpy,TB_TOCLESS)
+ libc_hidden_builtin_def (memcpy)
++weak_alias (memcpy,largememcpy)
++libc_hidden_def (largememcpy)
+diff -ruN glibc-2.20-mcpy-new-large-original/sysdeps/powerpc/Versions glibc-2.20-mcpy-new-large-mcpy-new/sysdeps/powerpc/Versions
+--- glibc-2.20-mcpy-new-large-original/sysdeps/powerpc/Versions 2015-09-02 14:28:58.244187000 -0500
++++ glibc-2.20-mcpy-new-large-mcpy-new/sysdeps/powerpc/Versions 2015-09-02 14:30:49.593187000 -0500
+@@ -9,6 +9,7 @@
+ GLIBC_2.3.4 {
+ _longjmp; __sigsetjmp; _setjmp;
+ longjmp; setjmp;
++ largememcpy;
+ }
+ GLIBC_PRIVATE {
+ __novmx__libc_longjmp; __novmx__libc_siglongjmp;
diff --git a/recipes-core/glibc/glibc-fsl/0021.glibc.undefined_static.patch b/recipes-core/glibc/glibc-fsl/0021.glibc.undefined_static.patch
new file mode 100755
index 0000000..baad08f
--- /dev/null
+++ b/recipes-core/glibc/glibc-fsl/0021.glibc.undefined_static.patch
@@ -0,0 +1,37 @@
+glibc.undefined_static
+
+This works around an old binutils bug, which would delete static
+constants out of the code, thus causing undefined symbols. Not sure if
+this patch is still needed.
+
+diff -rc libc-orig/stdio-common/psiginfo-define.h libc-new/stdio-common/psiginfo-define.h
+*** libc-orig/stdio-common/psiginfo-define.h 2009-04-09 08:12:53.000000000 -0500
+--- libc-new/stdio-common/psiginfo-define.h 2009-04-09 08:20:36.000000000 -0500
+***************
+*** 1,4 ****
+! static const union C(codestrs_t_, NOW) {
+ struct {
+ #define P(n, s) char MF(__LINE__)[sizeof (s)];
+ #include "psiginfo-data.h"
+--- 1,4 ----
+! const union C(codestrs_t_, NOW) {
+ struct {
+ #define P(n, s) char MF(__LINE__)[sizeof (s)];
+ #include "psiginfo-data.h"
+***************
+*** 8,14 ****
+ #define P(n, s) s,
+ #include "psiginfo-data.h"
+ } };
+! static const uint8_t C(codes_, NOW)[] = {
+ #define P(n, s) [(n) - 1] = offsetof (union C(codestrs_t_, NOW), MF(__LINE__)),
+ #include "psiginfo-data.h"
+ };
+--- 8,14 ----
+ #define P(n, s) s,
+ #include "psiginfo-data.h"
+ } };
+! const uint8_t C(codes_, NOW)[] = {
+ #define P(n, s) [(n) - 1] = offsetof (union C(codestrs_t_, NOW), MF(__LINE__)),
+ #include "psiginfo-data.h"
+ };
diff --git a/recipes-core/glibc/glibc-fsl/0022.glibc.use-option-groups.patch b/recipes-core/glibc/glibc-fsl/0022.glibc.use-option-groups.patch
new file mode 100644
index 0000000..631013b
--- /dev/null
+++ b/recipes-core/glibc/glibc-fsl/0022.glibc.use-option-groups.patch
@@ -0,0 +1,149 @@
+From d6fe2c92acf68509ee00af1145ba0cfbd714426b Mon Sep 17 00:00:00 2001
+From: Ting Liu <ting.liu at freescale.com>
+Date: Fri, 14 Aug 2015 16:49:16 +0800
+Subject: [PATCH] 0024.glibc.use-option-groups.patch new updates
+
+Signed-off-by: Ting Liu <ting.liu at freescale.com>
+---
+ elf/Makefile | 10 +++++++---
+ include/libc-symbols.h | 3 +--
+ misc/sys/xattr.h | 2 --
+ sysdeps/ieee754/dbl-64/s_sin.c | 16 ++++++----------
+ 4 files changed, 14 insertions(+), 17 deletions(-)
+
+diff --git a/elf/Makefile b/elf/Makefile
+index 25012cc..dd6b330 100644
+--- a/elf/Makefile
++++ b/elf/Makefile
+@@ -17,6 +17,8 @@
+
+ # Makefile for elf subdirectory of GNU C Library.
+
++include ../option-groups.mak
++
+ subdir := elf
+
+ include ../Makeconfig
+@@ -144,10 +146,11 @@ tests += loadtest restest1 preloadtest loadfail multiload origtest resolvfail \
+ unload3 unload4 unload5 unload6 unload7 unload8 tst-global1 order2 \
+ tst-audit1 tst-audit2 tst-audit8 tst-audit9 \
+ tst-stackguard1 tst-addr1 tst-thrlock \
+- tst-unique1 tst-unique2 tst-unique3 tst-unique4 \
++ tst-unique1 tst-unique2 \
+ tst-initorder tst-initorder2 tst-relsort1 tst-null-argv \
+ tst-ptrguard1
+ # reldep9
++tests-$(OPTION_EGLIBC_CXX_TESTS) += tst-unique3 tst-unique4
+ ifeq ($(build-hardcoded-path-in-tests),yes)
+ tests += tst-dlopen-aout
+ endif
+@@ -205,8 +208,6 @@ modules-names = testobj1 testobj2 testobj3 testobj4 testobj5 testobj6 \
+ tst-unique1mod1 tst-unique1mod2 \
+ tst-unique2mod1 tst-unique2mod2 \
+ tst-auditmod9a tst-auditmod9b \
+- tst-unique3lib tst-unique3lib2 \
+- tst-unique4lib \
+ tst-initordera1 tst-initorderb1 \
+ tst-initordera2 tst-initorderb2 \
+ tst-initordera3 tst-initordera4 \
+@@ -214,6 +215,9 @@ modules-names = testobj1 testobj2 testobj3 testobj4 testobj5 testobj6 \
+ tst-initorder2d \
+ tst-relsort1mod1 tst-relsort1mod2 tst-array2dep \
+ tst-array5dep tst-null-argv-lib
++ifeq (y,$(OPTION_EGLIBC_CXX_TESTS))
++modules-names += tst-unique3lib tst-unique3lib2 tst-unique4lib
++endif
+ ifeq (yesyes,$(have-fpie)$(build-shared))
+ modules-names += tst-piemod1
+ tests += tst-pie1 tst-pie2
+diff --git a/include/libc-symbols.h b/include/libc-symbols.h
+index d4ab1f3..25662cb 100644
+--- a/include/libc-symbols.h
++++ b/include/libc-symbols.h
+@@ -60,8 +60,7 @@
+ /* Define these macros for the benefit of portable GNU code that wants to check
+ them. Of course, STDC_HEADERS is never false when building libc! */
+ #define STDC_HEADERS 1
+-#define HAVE_MBSTATE_T 1
+-#define HAVE_MBSRTOWCS 1
++
+ #define HAVE_LIBINTL_H 1
+ #define HAVE_WCTYPE_H 1
+ #define HAVE_ISWCTYPE 1
+diff --git a/misc/sys/xattr.h b/misc/sys/xattr.h
+index 796df90..929cd87 100644
+--- a/misc/sys/xattr.h
++++ b/misc/sys/xattr.h
+@@ -26,7 +26,6 @@ __BEGIN_DECLS
+
+ /* The following constants should be used for the fifth parameter of
+ `*setxattr'. */
+-#ifndef __USE_KERNEL_XATTR_DEFS
+ enum
+ {
+ XATTR_CREATE = 1, /* set value, fail if attr already exists. */
+@@ -34,7 +33,6 @@ enum
+ XATTR_REPLACE = 2 /* set value, fail if attr does not exist. */
+ #define XATTR_REPLACE XATTR_REPLACE
+ };
+-#endif
+
+ /* Set the attribute NAME of the file pointed to by PATH to VALUE (which
+ is SIZE bytes long). Return 0 on success, -1 for errors. */
+diff --git a/sysdeps/ieee754/dbl-64/s_sin.c b/sysdeps/ieee754/dbl-64/s_sin.c
+index 50109b8..6105e9f 100644
+--- a/sysdeps/ieee754/dbl-64/s_sin.c
++++ b/sysdeps/ieee754/dbl-64/s_sin.c
+@@ -447,21 +447,19 @@ __sin (double x)
+ }
+ else
+ {
+- double t;
+ if (a > 0)
+ {
+ m = 1;
+- t = a;
+ db = da;
+ }
+ else
+ {
+ m = 0;
+- t = -a;
++ a = -a;
+ db = -da;
+ }
+- u.x = big + t;
+- y = t - (u.x - big);
++ u.x = big + a;
++ y = a - (u.x - big);
+ res = do_sin (u, y, db, &cor);
+ cor = (cor > 0) ? 1.035 * cor + eps : 1.035 * cor - eps;
+ retval = ((res == res + cor) ? ((m) ? res : -res)
+@@ -673,21 +671,19 @@
+ }
+ else
+ {
+- double t;
+ if (a > 0)
+ {
+ m = 1;
+- t = a;
+ db = da;
+ }
+ else
+ {
+ m = 0;
+- t = -a;
++ a = -a;
+ db = -da;
+ }
+- u.x = big + t;
+- y = t - (u.x - big);
++ u.x = big + a;
++ y = a - (u.x - big);
+ res = do_sin (u, y, db, &cor);
+ cor = (cor > 0) ? 1.035 * cor + eps : 1.035 * cor - eps;
+ retval = ((res == res + cor) ? ((m) ? res : -res)
+--
+1.9.2
+
diff --git a/recipes-core/glibc/glibc-fsl/00xx.glibc.add-option-groups-support.patch b/recipes-core/glibc/glibc-fsl/00xx.glibc.add-option-groups-support.patch
new file mode 100755
index 0000000..eff2257
--- /dev/null
+++ b/recipes-core/glibc/glibc-fsl/00xx.glibc.add-option-groups-support.patch
@@ -0,0 +1,1389 @@
+# Problem Statement:
+ Port eglibc option group infrastructure to glibc v2.20.
+
+# Referred from patch by:
+ Yocto Project
+ http://git.yoctoproject.org/cgit.cgi/poky/plain/meta/recipes-core/glibc/glibc/option-groups.patch
+ Upstream-Status: Pending
+
+diff -Naur glibc-2.20/config.make.in glibc-2.20-patch/config.make.in
+--- glibc-2.20/config.make.in 2014-09-07 03:09:09.000000000 -0500
++++ glibc-2.20-patch/config.make.in 2015-02-19 03:54:24.155759769 -0600
+@@ -46,6 +46,8 @@
+ c++-sysincludes = @CXX_SYSINCLUDES@
+ all-warnings = @all_warnings@
+
++kconfig_tools = @KCONFIG_TOOLS@
++
+ have-z-combreloc = @libc_cv_z_combreloc@
+ have-z-execstack = @libc_cv_z_execstack@
+ have-Bgroup = @libc_cv_Bgroup@
+diff -Naur glibc-2.20/configure glibc-2.20-patch/configure
+--- glibc-2.20/configure 2014-09-07 03:09:09.000000000 -0500
++++ glibc-2.20-patch/configure 2015-02-19 03:54:24.157759768 -0600
+@@ -619,6 +619,7 @@
+ PERL
+ BASH_SHELL
+ libc_cv_gcc_static_libgcc
++KCONFIG_TOOLS
+ CXX_SYSINCLUDES
+ SYSINCLUDES
+ AUTOCONF
+@@ -733,6 +734,7 @@
+ with_binutils
+ with_selinux
+ with_headers
++with_kconfig
+ with_default_link
+ enable_sanity_checks
+ enable_shared
+@@ -1437,6 +1439,9 @@
+ --with-selinux if building with SELinux support
+ --with-headers=PATH location of system headers to use (for example
+ /usr/src/linux/include) [default=compiler default]
++ --with-kconfig=PATH location of kconfig tools to use (from Linux kernel
++ builds) to re-use for configuring EGLIBC option
++ groups
+ --with-default-link do not use explicit linker scripts
+ --with-cpu=CPU select code for CPU variant
+
+@@ -3400,6 +3405,14 @@
+
+
+
++# Check whether --with-kconfig was given.
++if test "${with_kconfig+set}" = set; then
++ withval=$with_kconfig; KCONFIG_TOOLS=$withval
++else
++ KCONFIG_TOOLS=''
++fi
++
++
+
+ # Check whether --with-default-link was given.
+ if test "${with_default_link+set}" = set; then :
+diff -Naur glibc-2.20/configure.ac glibc-2.20-patch/configure.ac
+--- glibc-2.20/configure.ac 2014-09-07 03:09:09.000000000 -0500
++++ glibc-2.20-patch/configure.ac 2015-02-19 03:54:24.155759769 -0600
+@@ -127,6 +127,16 @@
+ [sysheaders=''])
+ AC_SUBST(sysheaders)
+
++AC_ARG_WITH([kconfig],
++ AC_HELP_STRING([--with-kconfig=PATH],
++ [location of kconfig tools to use (from Linux
++ kernel builds) to re-use for configuring EGLIBC
++ option groups]),
++ [KCONFIG_TOOLS=$withval],
++ [KCONFIG_TOOLS=''])
++AC_SUBST(KCONFIG_TOOLS)
++
++
+ AC_SUBST(use_default_link)
+ AC_ARG_WITH([default-link],
+ AC_HELP_STRING([--with-default-link],
+diff -Naur glibc-2.20/EGLIBC.option-groups glibc-2.20-patch/EGLIBC.option-groups
+--- glibc-2.20/EGLIBC.option-groups 1969-12-31 18:00:00.000000000 -0600
++++ glibc-2.20-patch/EGLIBC.option-groups 2015-02-19 03:54:24.154759770 -0600
+@@ -0,0 +1,122 @@
++ -*- mode: text -*-
++
++ The EGLIBC Component Configuration System
++ Jim Blandy <jimb at codesourcery.com>
++
++Introduction
++
++The GNU C library (GLIBC) provides a broad range of functionality,
++ranging from internationalization support to transcendental
++mathematical functions. Its website boasts that "nearly all known and
++useful functions from any other C library are available." This
++exhaustive approach has been one of GLIBC's strengths on desktop and
++server systems, but it has also given GLIBC a large footprint, both in
++memory and on disk, making it a challenge to use in embedded systems
++with limited resources.
++
++The Embedded GNU C library (EGLIBC) is a variant of the GNU C library
++designed to work well on embedded systems. In particular, EGLIBC's
++component configuration system allows embedded developers to build
++customized versions of the library that include only the features
++their application uses, reducing its space requirements.
++
++EGLIBC's component configuration system categorizes the library's
++functions into "option groups", and allows you to include or exclude
++option groups individually. Some option groups depend on others;
++EGLIBC tracks these relationships, and ensures that the selected
++configuration yields a functioning library.
++
++
++Consistent and Predictable Behavior
++
++A flexible configuration system is a mixed blessing: if the options
++offered are poorly designed, it can be hard to see which choices will
++have the desired effects, and choices with obscure consequences can
++make debugging difficult. EGLIBC's configuration follows some general
++principles to reduce these risks:
++
++- EGLIBC has a single default configuration for each target
++ architecture.
++
++- In the default configuration, all option groups are enabled, and
++ EGLIBC is upwardly API- and ABI-compatible with GLIBC.
++
++- As much as possible, configurations only affect what functions are
++ present, not how they behave. If the system works with an option
++ group disabled, it will still work with it enabled.
++
++- As much as possible, configurations only select option groups ---
++ they do not describe characteristics of the target architecture.
++
++These rules mean that you have a simple debugging strategy available
++if you suspect that your EGLIBC configuration might be the source of a
++problem: fall back to the default configuration, re-test, and then
++disable option groups one by one, until the problem reappears.
++
++
++The Option Groups
++
++To see the current full list of implemented option groups, refer to the
++file 'option-groups.def' at the top of the source tree, or run
++'make menuconfig' from the top-level build directory.
++
++The POSIX.1-2001 specification includes a suggested partition of all
++the functions in the POSIX C API into option groups: math functions
++like 'sin' and 'cos'; networking functions like 'socket' and
++'connect'; and so on. EGLIBC could use this partitioning as the basis
++for future option groups.
++
++
++Implementation
++
++The EGLIBC component configuration system resembles the approach used
++by the Linux kernel to select device drivers, network protocols, and
++other features. A file named 'option-groups.config' in the top-level
++build directory contains assignments to Make variables, each of which
++enables or disables a particular option group. If the variable's
++value is set to 'y', then the option group is enabled; if it set to
++anything else, the option group is omitted. The file
++'option-groups.defaults', at the top of the source tree, establishes
++default values for all variables; all option groups are enabled by
++default.
++
++For example, the following 'option-groups.config' would omit locale
++data, but include mathematical functions, and everything else:
++
++ OPTION_EGLIBC_LOCALES = n
++ OPTION_EGLIBC_LIBM = y
++
++Like the Linux kernel, EGLIBC supports a similar set of '*config' make
++targets to make it easier to create 'option-groups.config', with all
++dependencies between option groups automatically satisfied. Run
++'make help' to see the list of supported make config targets. For
++example, 'make menuconfig' will update the current config utilising a
++menu based program.
++
++The option group names and their type (boolean, int, hex, string), help
++description, and dependencies with other option groups, are described by
++'option-groups.def' at the top of the source tree, analogous to the
++'Kconfig' files in the Linux kernel.
++
++In general, each option group variable controls whether a given set of
++object files in EGLIBC is compiled and included in the final
++libraries, or omitted from the build.
++
++Each subdirectory's Makefile categorizes its routines, libraries, and
++executables by option group. For example, EGLIBC's 'math/Makefile'
++places the 'libm' library in the OPTION_EGLIBC_LIBM group as follows:
++
++ extra-libs-$(OPTION_EGLIBC_LIBM) := libm
++
++Finally, common code in 'Makerules' cites the value of the variable
++'extra-libs-y', selecting only those libraries that belong to enabled
++option groups to be built.
++
++
++Current Status and Future Directions
++
++The EGLIBC component configuration system described here is still
++under development.
++
++We have used the system to subset some portions of EGLIBC's
++Index: libc/configure.ac
+diff -Naur glibc-2.20/Makefile glibc-2.20-patch/Makefile
+--- glibc-2.20/Makefile 2014-09-07 03:09:09.000000000 -0500
++++ glibc-2.20-patch/Makefile 2015-02-19 03:54:24.154759770 -0600
+@@ -24,6 +24,7 @@
+
+ include Makeconfig
+
++include options-config/Makefile
+
+ # This is the default target; it makes everything except the tests.
+ .PHONY: all
+diff -Naur glibc-2.20/option-groups.def glibc-2.20-patch/option-groups.def
+--- glibc-2.20/option-groups.def 1969-12-31 18:00:00.000000000 -0600
++++ glibc-2.20-patch/option-groups.def 2015-02-19 03:54:24.153759771 -0600
+@@ -0,0 +1,868 @@
++# This file documents the option groups EGLIBC currently supports, in
++# a format akin to the Linux Kconfig system's. The syntax may change
++# over time.
++#
++# An entry of the form:
++#
++# config GROUP_NAME
++# bool "one-line explanation of what this option group controls"
++# help
++# Multi-line help explaining the option group's meaning in
++# some detail, terminated by indentation level.
++#
++# defines an option group whose variable is GROUP_NAME, with
++# meaningful values 'y' (enabled) and 'n' (disabled). The
++# documentation is formatted to be consumed by some sort of
++# interactive configuration interface, but EGLIBC doesn't have such an
++# interface yet.
++#
++# An option may have a 'depends on' line, indicating which other options
++# must also be enabled if this option is. At present, EGLIBC doesn't
++# check that these dependencies are satisfied.
++#
++# Option group variables get their default values from the file
++# 'option-groups.defaults', in the top directory of the EGLIBC source
++# tree. By default, all EGLIBC option groups are enabled --- their
++# variables are set to 'y'.
++#
++# After including 'option-groups.defaults', the EGLIBC make machinery
++# includes the file 'option-groups.config' from the top of the build
++# tree, if it is present. Developers can place assignments to option
++# group variables in that file to override the defaults. For example,
++# to disable an option group, place a line of the form:
++#
++# OPTION_GROUP_NAME = n
++#
++# in 'option-groups.config' at the top of your build tree. To
++# explicitly enable an option group, you may also write:
++#
++# OPTION_GROUP_NAME = y
++#
++# although this simply reestablishes the value already set by
++# 'option-groups.defaults'.
++
++config EGLIBC_ADVANCED_INET6
++ bool "IPv6 Advanced Sockets API support (RFC3542)"
++ depends on EGLIBC_INET
++ help
++ This option group includes the functions specified by RFC 3542,
++ "Advanced Sockets Application Program Interface (API) for
++ IPv6".
++
++ This option group includes the following functions:
++
++ inet6_opt_append
++ inet6_opt_find
++ inet6_opt_finish
++ inet6_opt_get_val
++ inet6_opt_init
++ inet6_option_alloc
++ inet6_option_append
++ inet6_option_find
++ inet6_option_init
++ inet6_option_next
++ inet6_option_space
++ inet6_opt_next
++ inet6_opt_set_val
++ inet6_rth_add
++ inet6_rth_getaddr
++ inet6_rth_init
++ inet6_rth_reverse
++ inet6_rth_segments
++ inet6_rth_space
++
++config EGLIBC_BACKTRACE
++ bool "Functions for producing backtraces"
++ help
++ This option group includes functions for producing a list of
++ the function calls that are currently active in a thread, from
++ within the thread itself. These functions are often used
++ within signal handlers, to produce diagnostic output.
++
++ This option group includes the following functions:
++
++ backtrace
++ backtrace_symbols
++ backtrace_symbols_fd
++
++config EGLIBC_BIG_MACROS
++ bool "Use extensive inline code"
++ help
++ This option group specifies whether certain pieces of code
++ should be inlined to achieve maximum speed. If this option
++ group is not selected, function calls will be used instead,
++ hence reducing the library footprint.
++
++config EGLIBC_BSD
++ bool "BSD-specific functions, and their compatibility stubs"
++ help
++ This option group includes functions specific to BSD kernels.
++ A number of these functions have stub versions that are also
++ included in libraries built for non-BSD systems for
++ compatibility.
++
++ This option group includes the following functions:
++
++ chflags
++ fchflags
++ lchmod
++ revoke
++ setlogin
++
++config EGLIBC_CXX_TESTS
++ bool "Tests that link against the standard C++ library."
++ depends on POSIX_WIDE_CHAR_DEVICE_IO && EGLIBC_LIBM
++ help
++ This option group does not include any C library functions;
++ instead, it controls which EGLIBC tests an ordinary 'make
++ tests' runs. With this group disabled, tests that would
++ normally link against the standard C++ library are not
++ run.
++
++ The standard C++ library depends on the math library 'libm' and
++ the wide character I/O functions included in EGLIBC. So those
++ option groups must be enabled if this test is enabled.
++
++config EGLIBC_CATGETS
++ bool "Functions for accessing message catalogs"
++ depends on EGLIBC_LOCALE_CODE
++ help
++ This option group includes functions for accessing message
++ catalogs: catopen, catclose, and catgets.
++
++ This option group depends on the EGLIBC_LOCALE_CODE
++ option group.
++
++config EGLIBC_CHARSETS
++ bool "iconv/gconv character set conversion libraries"
++ help
++ This option group includes support for character sets other
++ than ASCII (ANSI_X3.4-1968) and Unicode and ISO-10646 in their
++ various encodings. This affects both the character sets
++ supported by the wide and multibyte character functions, and
++ those supported by the 'iconv' functions.
++
++ With this option group disabled, EGLIBC supports only the
++ following character sets:
++
++ ANSI_X3.4 - ASCII
++ ANSI_X3.4-1968
++ ANSI_X3.4-1986
++ ASCII
++ CP367
++ CSASCII
++ IBM367
++ ISO-IR-6
++ ISO646-US
++ ISO_646.IRV:1991
++ OSF00010020
++ US
++ US-ASCII
++
++ 10646-1:1993 - ISO 10646, in big-endian UCS4 form
++ 10646-1:1993/UCS4
++ CSUCS4
++ ISO-10646
++ ISO-10646/UCS4
++ OSF00010104
++ OSF00010105
++ OSF00010106
++ UCS-4
++ UCS-4BE
++ UCS4
++
++ UCS-4LE - ISO 10646, in little-endian UCS4 form
++
++ ISO-10646/UTF-8 - ISO 10646, in UTF-8 form
++ ISO-10646/UTF8
++ ISO-IR-193
++ OSF05010001
++ UTF-8
++ UTF8
++
++ ISO-10646/UCS2 - ISO 10646, in target-endian UCS2 form
++ OSF00010100
++ OSF00010101
++ OSF00010102
++ UCS-2
++ UCS2
++
++ UCS-2BE - ISO 10646, in big-endian UCS2 form
++ UNICODEBIG
++
++ UCS-2LE - ISO 10646, in little-endian UCS2 form
++ UNICODELITTLE
++
++ WCHAR_T - EGLIBC's internal form (target-endian,
++ 32-bit ISO 10646)
++
++config EGLIBC_CRYPT
++ bool "Encryption library"
++ help
++ This option group includes the `libcrypt' library which
++ provides functions for one-way encryption. Supported
++ encryption algorithms include MD5, SHA-256, SHA-512 and DES.
++
++config EGLIBC_CRYPT_UFC
++ bool "Ultra fast `crypt' implementation"
++ depends on EGLIBC_CRYPT
++ help
++ This option group provides ultra fast DES-based implementation of
++ the `crypt' function. When this option group is disabled,
++ (a) the library will not provide the setkey[_r] and encrypt[_r]
++ functions and (b) the crypt[_r] function will return NULL and set the
++ errno to ENOSYS if /salt/ passed does not correspond to either MD5,
++ SHA-256 or SHA-512 algorithm.
++
++config EGLIBC_DB_ALIASES
++ bool "Functions for accessing the mail aliases database"
++ help
++ This option group includues functions for looking up mail
++ aliases in '/etc/aliases' or using nsswitch. It includes the
++ following functions:
++
++ endaliasent
++ getaliasbyname
++ getaliasbyname_r
++ getaliasent
++ getaliasent_r
++ setaliasent
++
++ When this option group is disabled, the NSS service libraries
++ also lack support for querying their mail alias tables.
++
++config EGLIBC_ENVZ
++ bool "Functions for handling envz-style environment vectors."
++ help
++ This option group contains functions for creating and operating
++ on envz vectors. An "envz vector" is a vector of strings in a
++ contiguous block of memory, where each element is a name-value
++ pair, and elements are separated from their neighbors by null
++ characters.
++
++ This option group includes the following functions:
++
++ envz_add envz_merge
++ envz_entry envz_remove
++ envz_get envz_strip
++
++config EGLIBC_FCVT
++ bool "Functions for converting floating-point numbers to strings"
++ help
++ This option group includes functions for converting
++ floating-point numbers to strings.
++
++ This option group includes the following functions:
++
++ ecvt qecvt
++ ecvt_r qecvt_r
++ fcvt qfcvt
++ fcvt_r qfcvt_r
++ gcvt qgcvt
++
++config EGLIBC_FMTMSG
++ bool "Functions for formatting messages"
++ help
++ This option group includes the following functions:
++
++ addseverity fmtmsg
++
++config EGLIBC_FSTAB
++ bool "Access functions for 'fstab'"
++ help
++ This option group includes functions for reading the mount
++ point specification table, '/etc/fstab'. These functions are
++ not included in the POSIX standard, which provides the
++ 'getmntent' family of functions instead.
++
++ This option group includes the following functions:
++
++ endfsent getfsspec
++ getfsent setfsent
++ getfsfile
++
++config EGLIBC_FTRAVERSE
++ bool "Functions for traversing file hierarchies"
++ help
++ This option group includes functions for traversing file
++ UNIX file hierachies.
++
++ This option group includes the following functions:
++
++ fts_open ftw
++ fts_read nftw
++ fts_children ftw64
++ fts_set nftw64
++ fts_close
++
++config EGLIBC_GETLOGIN
++ bool "The getlogin function"
++ depends on EGLIBC_UTMP
++ help
++ This function group includes the 'getlogin' and 'getlogin_r'
++ functions, which return the user name associated by the login
++ activity with the current process's controlling terminal.
++
++ With this option group disabled, the 'glob' function will not
++ fall back on 'getlogin' to find the user's login name for tilde
++ expansion when the 'HOME' environment variable is not set.
++
++config EGLIBC_IDN
++ bool "International domain names support"
++ help
++ This option group includes the `libcidn' library which
++ provides support for international domain names.
++
++config EGLIBC_INET
++ bool "Networking support"
++ help
++ This option group includes networking-specific functions and
++ data. With EGLIBC_INET disabled, the EGLIBC
++ installation and API changes as follows:
++
++ - The following libraries are not installed:
++
++ libnsl
++ libnss_compat
++ libnss_dns
++ libnss_hesiod
++ libnss_nis
++ libnss_nisplus
++ libresolv
++
++ - The following functions and variables are omitted from libc:
++
++ authdes_create hstrerror svc_fdset
++ authdes_getucred htonl svc_getreq
++ authdes_pk_create htons svc_getreq_common
++ authnone_create if_freenameindex svc_getreq_poll
++ authunix_create if_indextoname svc_getreqset
++ authunix_create_default if_nameindex svc_max_pollfd
++ bindresvport if_nametoindex svc_pollfd
++ callrpc in6addr_any svcraw_create
++ cbc_crypt in6addr_loopback svc_register
++ clnt_broadcast inet6_opt_append svc_run
++ clnt_create inet6_opt_find svc_sendreply
++ clnt_pcreateerror inet6_opt_finish svctcp_create
++ clnt_perrno inet6_opt_get_val svcudp_bufcreate
++ clnt_perror inet6_opt_init svcudp_create
++ clntraw_create inet6_option_alloc svcudp_enablecache
++ clnt_spcreateerror inet6_option_append svcunix_create
++ clnt_sperrno inet6_option_find svcunixfd_create
++ clnt_sperror inet6_option_init svc_unregister
++ clnttcp_create inet6_option_next user2netname
++ clntudp_bufcreate inet6_option_space xdecrypt
++ clntudp_create inet6_opt_next xdr_accepted_reply
++ clntunix_create inet6_opt_set_val xdr_array
++ des_setparity inet6_rth_add xdr_authdes_cred
++ ecb_crypt inet6_rth_getaddr xdr_authdes_verf
++ endaliasent inet6_rth_init xdr_authunix_parms
++ endhostent inet6_rth_reverse xdr_bool
++ endnetent inet6_rth_segments xdr_bytes
++ endnetgrent inet6_rth_space xdr_callhdr
++ endprotoent inet_addr xdr_callmsg
++ endrpcent inet_aton xdr_char
++ endservent inet_lnaof xdr_cryptkeyarg
++ ether_aton inet_makeaddr xdr_cryptkeyarg2
++ ether_aton_r inet_netof xdr_cryptkeyres
++ ether_hostton inet_network xdr_des_block
++ ether_line inet_nsap_addr xdr_double
++ ether_ntoa inet_nsap_ntoa xdr_enum
++ ether_ntoa_r inet_ntoa xdr_float
++ ether_ntohost inet_ntop xdr_free
++ freeaddrinfo inet_pton xdr_getcredres
++ freeifaddrs innetgr xdr_hyper
++ gai_strerror iruserok xdr_int
++ getaddrinfo iruserok_af xdr_int16_t
++ getaliasbyname key_decryptsession xdr_int32_t
++ getaliasbyname_r key_decryptsession_pk xdr_int64_t
++ getaliasent key_encryptsession xdr_int8_t
++ getaliasent_r key_encryptsession_pk xdr_keybuf
++ gethostbyaddr key_gendes xdr_key_netstarg
++ gethostbyaddr_r key_get_conv xdr_key_netstres
++ gethostbyname key_secretkey_is_set xdr_keystatus
++ gethostbyname2 key_setnet xdr_long
++ gethostbyname2_r key_setsecret xdr_longlong_t
++ gethostbyname_r netname2host xdrmem_create
++ gethostent netname2user xdr_netnamestr
++ gethostent_r ntohl xdr_netobj
++ getifaddrs ntohs xdr_opaque
++ getipv4sourcefilter passwd2des xdr_opaque_auth
++ get_myaddress pmap_getmaps xdr_pmap
++ getnameinfo pmap_getport xdr_pmaplist
++ getnetbyaddr pmap_rmtcall xdr_pointer
++ getnetbyaddr_r pmap_set xdr_quad_t
++ getnetbyname pmap_unset xdrrec_create
++ getnetbyname_r rcmd xdrrec_endofrecord
++ getnetent rcmd_af xdrrec_eof
++ getnetent_r registerrpc xdrrec_skiprecord
++ getnetgrent res_init xdr_reference
++ getnetgrent_r rexec xdr_rejected_reply
++ getnetname rexec_af xdr_replymsg
++ getprotobyname rexecoptions xdr_rmtcall_args
++ getprotobyname_r rpc_createerr xdr_rmtcallres
++ getprotobynumber rresvport xdr_short
++ getprotobynumber_r rresvport_af xdr_sizeof
++ getprotoent rtime xdrstdio_create
++ getprotoent_r ruserok xdr_string
++ getpublickey ruserok_af xdr_u_char
++ getrpcbyname ruserpass xdr_u_hyper
++ getrpcbyname_r setaliasent xdr_u_int
++ getrpcbynumber sethostent xdr_uint16_t
++ getrpcbynumber_r setipv4sourcefilter xdr_uint32_t
++ getrpcent setnetent xdr_uint64_t
++ getrpcent_r setnetgrent xdr_uint8_t
++ getrpcport setprotoent xdr_u_long
++ getsecretkey setrpcent xdr_u_longlong_t
++ getservbyname setservent xdr_union
++ getservbyname_r setsourcefilter xdr_unixcred
++ getservbyport svcauthdes_stats xdr_u_quad_t
++ getservbyport_r svcerr_auth xdr_u_short
++ getservent svcerr_decode xdr_vector
++ getservent_r svcerr_noproc xdr_void
++ getsourcefilter svcerr_noprog xdr_wrapstring
++ h_errlist svcerr_progvers xencrypt
++ h_errno svcerr_systemerr xprt_register
++ herror svcerr_weakauth xprt_unregister
++ h_nerr svc_exit
++ host2netname svcfd_create
++
++ - The rpcgen, nscd, and rpcinfo commands are not installed.
++
++ - The 'rpc' file (a text file listing RPC services) is not installed.
++
++ Socket-related system calls do not fall in this option group,
++ because many are also used for other inter-process
++ communication mechanisms. For example, the 'syslog' routines
++ use Unix-domain sockets to communicate with the syslog daemon;
++ syslog is valuable in non-networked contexts.
++
++config EGLIBC_INET_ANL
++ bool "Asynchronous name lookup"
++ depends on EGLIBC_INET
++ help
++ This option group includes the `libanl' library which
++ provides support for asynchronous name lookup.
++
++config EGLIBC_LIBM
++ bool "libm (math library)"
++ help
++ This option group includes the 'libm' library, containing
++ mathematical functions. If this option group is omitted, then
++ an EGLIBC installation does not include shared or unshared versions
++ of the math library.
++
++ Note that this does not remove all floating-point related
++ functionality from EGLIBC; for example, 'printf' and 'scanf'
++ can still print and read floating-point values with this option
++ group disabled.
++
++ Note that the ISO Standard C++ library 'libstdc++' depends on
++ EGLIBC's math library 'libm'. If you disable this option
++ group, you will not be able to build 'libstdc++' against the
++ resulting EGLIBC installation.
++
++config EGLIBC_LOCALES
++ bool "Locale definitions"
++ help
++ This option group includes all locale definitions other than
++ that for the "C" locale. If this option group is omitted, then
++ only the "C" locale is supported.
++
++
++config EGLIBC_LOCALE_CODE
++ bool "Locale functions"
++ depends on POSIX_C_LANG_WIDE_CHAR
++ help
++ This option group includes locale support functions, programs,
++ and libraries. With EGLIBC_LOCALE_CODE disabled,
++ EGLIBC supports only the 'C' locale (also known as 'POSIX'),
++ and ignores the settings of the 'LANG' and 'LC_*' environment
++ variables.
++
++ With EGLIBC_LOCALE_CODE disabled, the following
++ functions are omitted from libc:
++
++ duplocale localeconv nl_langinfo rpmatch strfmon_l
++ freelocale newlocale nl_langinfo_l strfmon uselocale
++
++ Furthermore, only the LC_CTYPE and LC_TIME categories of the
++ standard "C" locale are available.
++
++ The EGLIBC_CATGETS option group depends on this option group.
++
++
++config EGLIBC_MEMUSAGE
++ bool "Memory profiling library"
++ help
++ This option group includes the `libmemusage' library and
++ the `memusage' and `memusagestat' utilities.
++ These components provide memory profiling functions.
++
++config EGLIBC_MEMUSAGE_DEFAULT_BUFFER_SIZE
++ int "Memory profiling library buffer size"
++ depends on EGLIBC_MEMUSAGE
++ default "32768"
++ help
++ Libmemusage library buffers the profiling data in memory
++ before writing it out to disk. By default, the library
++ allocates 1.5M buffer, which can be substantial for some
++ systems. EGLIBC_MEMUSAGE_DEFAULT_BUFFER_SIZE option
++ allows to change the default buffer size. It specifies
++ the number of entries the buffer should have.
++ On most architectures one buffer entry amounts to 48 bytes,
++ so setting this option to the value of 512 will reduce the size of
++ the memory buffer to 24K.
++
++config EGLIBC_NIS
++ bool "Support for NIS, NIS+, and the special 'compat' services."
++ depends on EGLIBC_INET && EGLIBC_SUNRPC
++ help
++ This option group includes the NIS, NIS+, and 'compat' Name
++ Service Switch service libraries. When it is disabled, those
++ services libraries are not installed; you should remove any
++ references to them from your 'nsswitch.conf' file.
++
++ This option group depends on the EGLIBC_INET option
++ group; you must enable that to enable this option group.
++
++config EGLIBC_NSSWITCH
++ bool "Name service switch (nsswitch) support"
++ help
++ This option group includes support for the 'nsswitch' facility.
++ With this option group enabled, all EGLIBC functions for
++ accessing various system databases (passwords and groups;
++ networking; aliases; public keys; and so on) consult the
++ '/etc/nsswitch.conf' configuration file to decide how to handle
++ queries.
++
++ With this option group disabled, EGLIBC uses a fixed list of
++ services to satisfy queries on each database, as requested by
++ configuration files specified when EGLIBC is built. Your
++ 'option-groups.config' file must set the following two
++ variables:
++
++config EGLIBC_NSSWITCH_FIXED_CONFIG
++ string "Nsswitch fixed config filename"
++ depends on !EGLIBC_NSSWITCH
++ default ""
++ help
++ Set this to the name of a file whose contents observe the
++ same syntax as an ordinary '/etc/nsswitch.conf' file. The
++ EGLIBC build process parses this file just as EGLIBC would
++ at run time if EGLIBC_NSSWITCH were enabled, and
++ produces a C library that uses the nsswitch service
++ libraries to search for database entries as this file
++ specifies, instead of consulting '/etc/nsswitch.conf' at run
++ time.
++
++ This should be an absolute filename. The EGLIBC build
++ process may use it from several different working
++ directories. It may include references to Makefile
++ variables like 'common-objpfx' (the top of the build tree,
++ with a trailing slash), or '..' (the top of the source tree,
++ with a trailing slash).
++
++ The EGLIBC source tree includes a sample configuration file
++ named 'nss/fixed-nsswitch.conf'; for simple configurations,
++ you will probably want to delete references to databases not
++ needed on your system.
++
++config EGLIBC_NSSWITCH_FIXED_FUNCTIONS
++ string "Nsswitch fixed functions filename"
++ depends on !EGLIBC_NSSWITCH
++ default ""
++ help
++ The EGLIBC build process uses this file to decide which
++ functions to make available from which service libraries.
++ The file 'nss/fixed-nsswitch.functions' serves as a sample
++ configuration file for this setting, and explains its syntax
++ and meaning in more detail.
++
++ This should be an absolute file name. The EGLIBC build
++ process may use it from several different working
++ directories. It may include references to Makefile
++ variables like 'common-objpfx' (the top of the build tree,
++ with a trailing slash), or '..' (the top of the source tree,
++ with a trailing slash).
++
++ Be sure to mention each function in each service you wish to
++ use. If you do not mention a service's function here, the
++ EGLIBC database access functions will not find it, even if
++ it is listed in the EGLIBC_NSSWITCH_FIXED_CONFIG
++ file.
++
++ In this arrangement, EGLIBC will not use the 'dlopen' and
++ 'dlsym' functions to find database access functions. Instead,
++ libc hard-codes references to the service libraries' database
++ access functions. You must explicitly link your program
++ against the name service libraries (those whose names start
++ with 'libnss_', in the sysroot's '/lib' directory) whose
++ functions you intend to use. This arrangement helps
++ system-wide static analysis tools decide which functions a
++ system actually uses.
++
++ Note that some nsswitch service libraries require other option
++ groups to be enabled; for example, the EGLIBC_INET
++ option group must be enabled to use the 'libnss_dns.so.2'
++ service library, which uses the Domain Name System network
++ protocol to answer queries.
++
++config EGLIBC_RCMD
++ bool "Support for 'rcmd' and related library functions"
++ depends on EGLIBC_INET
++ help
++ This option group includes functions for running commands on
++ remote machines via the 'rsh' protocol, and doing authentication
++ related to those functions. This also includes functions that
++ use the 'rexec' protocol.
++
++ This option group includes the following functions:
++
++ rcmd ruserok
++ rcmd_af ruserok_af
++ rexec iruserok
++ rexec_af iruserok_af
++ rresvport ruserpass
++ rresvport_af
++
++config EGLIBC_RTLD_DEBUG
++ bool "Runtime linker debug print outs"
++ help
++ This option group enables debug output of the runtime linker
++ which is activated via LD_DEBUG and LD_TRACE_PRELINKING
++ environment variables. Disabling this option group yields
++ a smaller runtime linker binary.
++ BEWARE: Disabling this option group is likely to break
++ the `ldd' utility which may also be used by the prelinker.
++ In particular, the `--unused' ldd option will not work correctly.
++
++config EGLIBC_SPAWN
++ bool "Support for POSIX posix_spawn functions"
++ help
++ This option group includes the POSIX functions for executing
++ programs in child processes without using 'fork' or 'vfork'.
++
++ This option group includes the following functions:
++
++ posix_spawn
++ posix_spawnattr_destroy
++ posix_spawnattr_getflags
++ posix_spawnattr_getpgroup
++ posix_spawnattr_getschedparam
++ posix_spawnattr_getschedpolicy
++ posix_spawnattr_getsigdefault
++ posix_spawnattr_getsigmask
++ posix_spawnattr_init
++ posix_spawnattr_setflags
++ posix_spawnattr_setpgroup
++ posix_spawnattr_setschedparam
++ posix_spawnattr_setschedpolicy
++ posix_spawnattr_setsigdefault
++ posix_spawnattr_setsigmask
++ posix_spawn_file_actions_addclose
++ posix_spawn_file_actions_adddup2
++ posix_spawn_file_actions_addopen
++ posix_spawn_file_actions_destroy
++ posix_spawn_file_actions_init
++ posix_spawnp
++
++ This option group also provides the ability for the iconv,
++ localedef, and locale programs to operate transparently on
++ compressed charset definitions. When this option group is
++ disabled, those programs will only operate on uncompressed
++ charmap files.
++
++config EGLIBC_STREAMS
++ bool "Support for accessing STREAMS."
++ help
++ This option group includes functions for reading and writing
++ messages to and from STREAMS. The STREAMS interface provides a
++ uniform mechanism for implementing networking services and other
++ character-based I/O. (STREAMS are not to be confused with
++ <stdio.h> FILE objects, also called 'streams'.)
++
++ This option group includes the following functions:
++
++ getmsg putpmsg
++ getpmsg fattach
++ isastream fdetach
++ putmsg
++
++config EGLIBC_SUNRPC
++ bool "Support for the Sun 'RPC' protocol."
++ depends on EGLIBC_INET
++ help
++ This option group includes support for the Sun RPC protocols,
++ including the 'rpcgen' and 'rpcinfo' programs.
++
++config EGLIBC_UTMP
++ bool "Older access functions for 'utmp' login records"
++ help
++ This option group includes the older 'utent' family of
++ functions for accessing user login records in the 'utmp' file.
++ POSIX omits these functions in favor of the 'utxent' family,
++ and they are obsolete on systems other than Linux.
++
++ This option group includes the following functions:
++
++ endutent
++ getutent
++ getutent_r
++ getutid
++ getutid_r
++ getutline
++ getutline_r
++ logwtmp
++ pututline
++ setutent
++ updwtmp
++ utmpname
++
++ This option group includes the following libraries:
++
++ libutil.so (and libutil.a)
++
++config EGLIBC_UTMPX
++ bool "POSIX access functions for 'utmp' login records"
++ depends on EGLIBC_UTMP
++ help
++ This option group includes the POSIX functions for reading and
++ writing user login records in the 'utmp' file (usually
++ '/var/run/utmp'). The POSIX functions operate on 'struct
++ utmpx' structures, as opposed to the family of older 'utent'
++ functions, which operate on 'struct utmp' structures.
++
++ This option group includes the following functions:
++
++ endutxent
++ getutmp
++ getutmpx
++ getutxent
++ getutxid
++ getutxline
++ pututxline
++ setutxent
++ updwtmpx
++ utmpxname
++
++config EGLIBC_WORDEXP
++ bool "Shell-style word expansion"
++ help
++ This option group includes the 'wordexp' function for
++ performing word expansion in the manner of the shell, and the
++ accompanying 'wordfree' function.
++
++config POSIX_C_LANG_WIDE_CHAR
++ bool "ISO C library wide character functions, excluding I/O"
++ help
++ This option group includes the functions defined by the ISO C
++ standard for working with wide and multibyte characters in
++ memory. Functions for reading and writing wide and multibyte
++ characters from and to files call in the
++ POSIX_WIDE_CHAR_DEVICE_IO option group.
++
++ This option group includes the following functions:
++
++ btowc mbsinit wcscspn wcstoll
++ iswalnum mbsrtowcs wcsftime wcstombs
++ iswalpha mbstowcs wcslen wcstoul
++ iswblank mbtowc wcsncat wcstoull
++ iswcntrl swprintf wcsncmp wcstoumax
++ iswctype swscanf wcsncpy wcsxfrm
++ iswdigit towctrans wcspbrk wctob
++ iswgraph towlower wcsrchr wctomb
++ iswlower towupper wcsrtombs wctrans
++ iswprint vswprintf wcsspn wctype
++ iswpunct vswscanf wcsstr wmemchr
++ iswspace wcrtomb wcstod wmemcmp
++ iswupper wcscat wcstof wmemcpy
++ iswxdigit wcschr wcstoimax wmemmove
++ mblen wcscmp wcstok wmemset
++ mbrlen wcscoll wcstol
++ mbrtowc wcscpy wcstold
++
++config POSIX_REGEXP
++ bool "Regular expressions"
++ help
++ This option group includes the POSIX regular expression
++ functions, and the associated non-POSIX extensions and
++ compatibility functions.
++
++ With POSIX_REGEXP disabled, the following functions are
++ omitted from libc:
++
++ re_comp re_max_failures regcomp
++ re_compile_fastmap re_search regerror
++ re_compile_pattern re_search_2 regexec
++ re_exec re_set_registers regfree
++ re_match re_set_syntax rpmatch
++ re_match_2 re_syntax_options
++
++ Furthermore, the compatibility regexp interface defined in the
++ <regexp.h> header file, 'compile', 'step', and 'advance', is
++ omitted.
++
++config POSIX_REGEXP_GLIBC
++ bool "Regular expressions from GLIBC"
++ depends on POSIX_REGEXP
++ help
++ This option group specifies which regular expression
++ library to use. The choice is between regex
++ implementation from GLIBC and regex implementation from
++ libiberty. The GLIBC variant is fully POSIX conformant and
++ optimized for speed; regex from libiberty is more than twice
++ as small while still is enough for most practical purposes.
++
++config POSIX_WIDE_CHAR_DEVICE_IO
++ bool "Input and output functions for wide characters"
++ depends on POSIX_C_LANG_WIDE_CHAR
++ help
++ This option group includes functions for reading and writing
++ wide characters to and from <stdio.h> streams.
++
++ This option group includes the following functions:
++
++ fgetwc fwprintf putwchar vwscanf
++ fgetws fwscanf ungetwc wprintf
++ fputwc getwc vfwprintf wscanf
++ fputws getwchar vfwscanf
++ fwide putwc vwprintf
++
++ This option group further includes the following unlocked
++ variants of the above functions:
++
++ fgetwc_unlocked getwc_unlocked
++ fgetws_unlocked getwchar_unlocked
++ fputwc_unlocked putwc_unlocked
++ fputws_unlocked putwchar_unlocked
++
++ Note that the GNU standard C++ library, 'libstdc++.so', uses
++ some of these functions; you will not be able to link or run
++ C++ programs if you disable this option group.
++
++ This option group also affects the behavior of the following
++ functions:
++
++ fdopen
++ fopen
++ fopen64
++ freopen
++ freopen64
++
++ These functions all take an OPENTYPE parameter which may
++ contain a string of the form ",ccs=CHARSET", indicating that
++ the underlying file uses the character set named CHARSET.
++ This produces a wide-oriented stream, which is only useful
++ when the functions included in this option group are present.
++ If the user attempts to open a file specifying a character set
++ in the OPENTYPE parameter, and EGLIBC was built with this
++ option group disabled, the function returns NULL, and sets
++ errno to EINVAL.
++
++
++# This helps Emacs users browse this file using the page motion commands
++# and commands like 'pages-directory'.
++# Local Variables:
++# page-delimiter: "^config\\s-"
++# End:
+diff -Naur glibc-2.20/option-groups.defaults glibc-2.20-patch/option-groups.defaults
+--- glibc-2.20/option-groups.defaults 1969-12-31 18:00:00.000000000 -0600
++++ glibc-2.20-patch/option-groups.defaults 2015-02-19 03:54:24.153759771 -0600
+@@ -0,0 +1,47 @@
++# This file sets default values for all option group variables
++# mentioned in option-groups.def; see that file for a description of
++# each option group.
++#
++# Subdirectory makefiles include this file before including the user's
++# settings from option-groups.config at the top of the build tree;
++# that file need only refer to those options whose default settings
++# are to be changed.
++#
++# By default, all option groups are enabled.
++OPTION_EGLIBC_ADVANCED_INET6 = y
++OPTION_EGLIBC_BACKTRACE = y
++OPTION_EGLIBC_BIG_MACROS = y
++OPTION_EGLIBC_BSD = y
++OPTION_EGLIBC_CXX_TESTS = y
++OPTION_EGLIBC_CATGETS = y
++OPTION_EGLIBC_CHARSETS = y
++OPTION_EGLIBC_CRYPT = y
++OPTION_EGLIBC_CRYPT_UFC = y
++OPTION_EGLIBC_DB_ALIASES = y
++OPTION_EGLIBC_ENVZ = y
++OPTION_EGLIBC_FCVT = y
++OPTION_EGLIBC_FMTMSG = y
++OPTION_EGLIBC_FSTAB = y
++OPTION_EGLIBC_FTRAVERSE = y
++OPTION_EGLIBC_GETLOGIN = y
++OPTION_EGLIBC_IDN = y
++OPTION_EGLIBC_INET = y
++OPTION_EGLIBC_INET_ANL = y
++OPTION_EGLIBC_LIBM = y
++OPTION_EGLIBC_LOCALES = y
++OPTION_EGLIBC_LOCALE_CODE = y
++OPTION_EGLIBC_MEMUSAGE = y
++OPTION_EGLIBC_NIS = y
++OPTION_EGLIBC_NSSWITCH = y
++OPTION_EGLIBC_RCMD = y
++OPTION_EGLIBC_RTLD_DEBUG = y
++OPTION_EGLIBC_SPAWN = y
++OPTION_EGLIBC_STREAMS = y
++OPTION_EGLIBC_SUNRPC = y
++OPTION_EGLIBC_UTMP = y
++OPTION_EGLIBC_UTMPX = y
++OPTION_EGLIBC_WORDEXP = y
++OPTION_POSIX_C_LANG_WIDE_CHAR = y
++OPTION_POSIX_REGEXP = y
++OPTION_POSIX_REGEXP_GLIBC = y
++OPTION_POSIX_WIDE_CHAR_DEVICE_IO = y
+diff -Naur glibc-2.20/option-groups.mak glibc-2.20-patch/option-groups.mak
+--- glibc-2.20/option-groups.mak 1969-12-31 18:00:00.000000000 -0600
++++ glibc-2.20-patch/option-groups.mak 2015-02-19 03:54:24.153759771 -0600
+@@ -0,0 +1,41 @@
++# Setup file for subdirectory Makefiles that define EGLIBC option groups.
++
++# EGLIBC shouldn't need to override this. However, the
++# cross-build-friendly localedef includes this makefile to get option
++# group variable definitions; it uses a single build tree for all the
++# multilibs, and needs to be able to specify a different option group
++# configuration file for each multilib.
++option_group_config_file ?= $(objdir)/option-groups.config
++
++# Read the default settings for all options.
++# We're included before ../Rules, so we can't assume $(..) is set.
++include $(firstword $(..) ../)option-groups.defaults
++
++# Read the developer's option group selections, overriding the
++# defaults from option-groups.defaults.
++-include $(option_group_config_file)
++
++# $(call option-disabled, VAR) is 'y' if VAR is not 'y', or 'n' otherwise.
++# VAR should be a variable name, not a variable reference; this is
++# less general, but more terse for the intended use.
++# You can use it to add a file to a list if an option group is
++# disabled, like this:
++# routines-$(call option-disabled, OPTION_POSIX_C_LANG_WIDE_CHAR) += ...
++define option-disabled
++$(firstword $(subst y,n,$(filter y,$($(strip $(1))))) y)
++endef
++
++# Establish 'routines-y', etc. as simply-expanded variables.
++aux-y :=
++extra-libs-others-y :=
++extra-libs-y :=
++extra-objs-y :=
++install-bin-y :=
++install-others-y :=
++install-sbin-y :=
++others-y :=
++others-pie-y :=
++routines-y :=
++test-srcs-y :=
++tests-y :=
++xtests-y :=
+diff -Naur glibc-2.20/options-config/config-postproc.pl glibc-2.20-patch/options-config/config-postproc.pl
+--- glibc-2.20/options-config/config-postproc.pl 1969-12-31 18:00:00.000000000 -0600
++++ glibc-2.20-patch/options-config/config-postproc.pl 2015-02-19 03:54:31.073759206 -0600
+@@ -0,0 +1,58 @@
++#!/usr/bin/perl
++
++$usage = "usage: $0 <default config file> <config file>\n";
++
++die "$usage" unless @ARGV;
++$defaults = shift @ARGV;
++die "$usage" unless @ARGV;
++die "Could not open $ARGV[0]" unless -T $ARGV[0];
++
++sub yank {
++ @option = grep(!($_ =~ /$_[0]\s*=/), @option);
++}
++
++open(DEFAULTS, $defaults) || die "Could not open $defaults\n";
++
++# get the full list of available options using the default config file
++$i = 0;
++while (<DEFAULTS>) {
++ if (/^\s*OPTION_(\w+\s*=.*$)/) {
++ $option[$i++] = $1;
++ }
++}
++
++# now go through the config file, making the necessary changes
++while (<>) {
++ if (/Linux Kernel Configuration/) {
++ # change title
++ s/Linux Kernel/Option Groups/;
++ print;
++ } elsif (/^\s*CONFIG_(\w+)\s*=/) {
++ # this is an explicit option set line, change CONFIG_ to OPTION_
++ # before printing and remove this option from option list
++ $opt = $1;
++ yank($opt);
++ s/CONFIG_/OPTION_/g;
++ print;
++ } elsif (/^\s*#\s+CONFIG_(\w+) is not set/) {
++ # this is a comment line for an unset boolean option, change CONFIG_
++ # to OPTION_, remove this option from option list, and convert to
++ # explicit OPTION_FOO=n
++ $opt = $1;
++ yank($opt);
++ s/CONFIG_/OPTION_/g;
++ print "OPTION_$opt=n\n";
++ } else {
++ print;
++ }
++}
++
++# any boolean options left in @options, are options that were not mentioned in
++# the config file, and implicitly that means the option must be set =n,
++# so do that here.
++foreach $opt (@option) {
++ if ($opt =~ /=\s*[yn]/) {
++ $opt =~ s/=\s*[yn]/=n/;
++ print "OPTION_$opt\n";
++ }
++}
+diff -Naur glibc-2.20/options-config/config-preproc.pl glibc-2.20-patch/options-config/config-preproc.pl
+--- glibc-2.20/options-config/config-preproc.pl 1969-12-31 18:00:00.000000000 -0600
++++ glibc-2.20-patch/options-config/config-preproc.pl 2015-02-19 03:54:31.073759206 -0600
+@@ -0,0 +1,8 @@
++#!/usr/bin/perl
++
++if (@ARGV) {
++ while (<>) {
++ s/OPTION_/CONFIG_/g;
++ print;
++ }
++}
+diff -Naur glibc-2.20/options-config/Makefile glibc-2.20-patch/options-config/Makefile
+--- glibc-2.20/options-config/Makefile 1969-12-31 18:00:00.000000000 -0600
++++ glibc-2.20-patch/options-config/Makefile 2015-02-19 03:54:26.748759537 -0600
+@@ -0,0 +1,55 @@
++# ===========================================================================
++# EGLIBC option-groups configuration targets
++# These targets are included from top-level makefile
++
++ifneq ($(kconfig_tools),)
++ifneq (no,$(PERL))
++
++ocdir := options-config
++
++OconfigDefaults := option-groups.defaults
++OconfigDefaults_tmp := $(common-objpfx).tmp.defconfig
++OconfigDef := option-groups.def
++Oconfig := $(common-objpfx)option-groups.config
++Oconfig_tmp := $(common-objpfx).tmp.config
++
++conf := $(kconfig_tools)/conf
++mconf := $(kconfig_tools)/mconf
++
++preproc := $(PERL) $(ocdir)/config-preproc.pl
++postproc := $(PERL) $(ocdir)/config-postproc.pl
++
++PHONY += defconfig config menuconfig
++
++defconfig: $(conf) $(OconfigDefaults) $(OconfigDef)
++ rm -f $(OconfigDefaults_tmp)
++ rm -f $(Oconfig_tmp)
++ $(preproc) $(OconfigDefaults) > $(OconfigDefaults_tmp)
++ KCONFIG_CONFIG=$(Oconfig_tmp) $< --defconfig=$(OconfigDefaults_tmp) \
++ $(OconfigDef)
++ $(postproc) $(OconfigDefaults) $(Oconfig_tmp) > $(Oconfig)
++ rm $(Oconfig_tmp)
++ rm $(OconfigDefaults_tmp)
++
++config: $(conf) $(OconfigDefaults) $(OconfigDef)
++ rm -f $(Oconfig_tmp)
++ $(preproc) $(wildcard $(Oconfig)) > $(Oconfig_tmp)
++ KCONFIG_CONFIG=$(Oconfig_tmp) $< --oldaskconfig $(OconfigDef)
++ $(postproc) $(OconfigDefaults) $(Oconfig_tmp) > $(Oconfig)
++ rm $(Oconfig_tmp)
++
++menuconfig: $(mconf) $(OconfigDefaults) $(OconfigDef)
++ rm -f $(Oconfig_tmp)
++ $(preproc) $(wildcard $(Oconfig)) > $(Oconfig_tmp)
++ KCONFIG_CONFIG=$(Oconfig_tmp) $< $(OconfigDef)
++ $(postproc) $(OconfigDefaults) $(Oconfig_tmp) > $(Oconfig)
++ rm $(Oconfig_tmp)
++
++# Help text used by make help
++help:
++ @echo ' defconfig - New config with default from default config'
++ @echo ' config - Update current config utilising a line-oriented program'
++ @echo ' menuconfig - Update current config utilising a menu based program'
++
++endif
++endif
+diff -Naur glibc-2.20/scripts/option-groups.awk glibc-2.20-patch/scripts/option-groups.awk
+--- glibc-2.20/scripts/option-groups.awk 1969-12-31 18:00:00.000000000 -0600
++++ glibc-2.20-patch/scripts/option-groups.awk 2015-02-19 03:54:31.073759206 -0600
+@@ -0,0 +1,63 @@
++# option-groups.awk --- generate option group header file
++# Given input files containing makefile-style assignments to variables,
++# print out a header file that #defines an appropriate preprocessor
++# symbol for each variable left set to 'y'.
++
++BEGIN { FS="=" }
++
++# Trim spaces.
++{ gsub (/[[:blank:]]/, "") }
++
++# Skip comments.
++/^#/ { next }
++
++# Process assignments.
++NF == 2 {
++ vars[$1] = $2
++}
++
++# Print final values.
++END {
++ print "/* This file is automatically generated by scripts/option-groups.awk"
++ print " in the EGLIBC source tree."
++ print ""
++ print " It defines macros that indicate which EGLIBC option groups were"
++ print " configured in 'option-groups.config' when this C library was"
++ print " built. For each option group named OPTION_foo, it #defines"
++ print " __OPTION_foo to be 1 if the group is enabled, or #defines that"
++ print " symbol to be 0 if the group is disabled. */"
++ print ""
++ print "#ifndef __GNU_OPTION_GROUPS_H"
++ print "#define __GNU_OPTION_GROUPS_H"
++ print ""
++
++ # Produce a sorted list of variable names.
++ i=0
++ for (var in vars)
++ names[i++] = var
++ n = asort (names)
++
++ for (i = 1; i <= n; i++)
++ {
++ var = names[i]
++ if (var ~ /^OPTION_/)
++ {
++ if (vars[var] == "y")
++ print "#define __" var " 1"
++ else if (vars[var] == "n")
++ print "#define __" var " 0"
++ else if (vars[var] ~ /^[0-9]+/ ||
++ vars[var] ~ /^0x[0-9aAbBcCdDeEfF]+/ ||
++ vars[var] ~ /^\"/)
++ print "#define __" var " " vars[var]
++ else
++ print "/* #undef __" var " */"
++ # Ignore variables that don't have boolean, int, hex, or
++ # string values. Ideally, this would be driven by the types
++ # given in option-groups.def.
++ }
++ }
++
++ print ""
++ print "#endif /* __GNU_OPTION_GROUPS_H */"
++}
diff --git a/recipes-core/glibc/glibc-fsl/00xx.glibc.rtld_debug_option_group.patch b/recipes-core/glibc/glibc-fsl/00xx.glibc.rtld_debug_option_group.patch
new file mode 100755
index 0000000..cb3deae
--- /dev/null
+++ b/recipes-core/glibc/glibc-fsl/00xx.glibc.rtld_debug_option_group.patch
@@ -0,0 +1,517 @@
+# Problem Statement:
+ Remove debug print outs from the run-time linker.
+ Its controlled by __OPTION_EGLIBC_RTLD_DEBUG,
+ so we should use GLRO_dl_debug_mask
+
+# Referred from patch by:
+ Yocto Project
+ http://git.yoctoproject.org/cgit.cgi/poky/plain/meta/recipes-core/glibc/glibc/GLRO_dl_debug_mask.patch
+ Singed-off-by: Khem Raj <raj.khem at gmail.com>
+
+diff -Naur glibc-2.20/csu/libc-start.c glibc-2.20-rtld-debug/csu/libc-start.c
+--- glibc-2.20/csu/libc-start.c 2014-09-07 03:09:09.000000000 -0500
++++ glibc-2.20-rtld-debug/csu/libc-start.c 2015-02-19 04:00:31.552729822 -0600
+@@ -238,7 +238,7 @@
+
+ /* Call the initializer of the program, if any. */
+ #ifdef SHARED
+- if (__builtin_expect (GLRO(dl_debug_mask) & DL_DEBUG_IMPCALLS, 0))
++ if (__builtin_expect (GLRO_dl_debug_mask & DL_DEBUG_IMPCALLS, 0))
+ GLRO(dl_debug_printf) ("\ninitialize program: %s\n\n", argv[0]);
+ #endif
+ if (init)
+@@ -261,7 +261,7 @@
+ #endif
+
+ #ifdef SHARED
+- if (__glibc_unlikely (GLRO(dl_debug_mask) & DL_DEBUG_IMPCALLS))
++ if (__glibc_unlikely (GLRO_dl_debug_mask & DL_DEBUG_IMPCALLS))
+ GLRO(dl_debug_printf) ("\ntransferring control: %s\n\n", argv[0]);
+ #endif
+
+diff -Naur glibc-2.20/elf/dl-cache.c glibc-2.20-rtld-debug/elf/dl-cache.c
+--- glibc-2.20/elf/dl-cache.c 2014-09-07 03:09:09.000000000 -0500
++++ glibc-2.20-rtld-debug/elf/dl-cache.c 2015-02-19 04:00:31.552729822 -0600
+@@ -187,7 +187,7 @@
+ const char *best;
+
+ /* Print a message if the loading of libs is traced. */
+- if (__glibc_unlikely (GLRO(dl_debug_mask) & DL_DEBUG_LIBS))
++ if (__glibc_unlikely (GLRO_dl_debug_mask & DL_DEBUG_LIBS))
+ _dl_debug_printf (" search cache=%s\n", LD_SO_CACHE);
+
+ if (cache == NULL)
+@@ -285,7 +285,7 @@
+ }
+
+ /* Print our result if wanted. */
+- if (__builtin_expect (GLRO(dl_debug_mask) & DL_DEBUG_LIBS, 0)
++ if (__builtin_expect (GLRO_dl_debug_mask & DL_DEBUG_LIBS, 0)
+ && best != NULL)
+ _dl_debug_printf (" trying file=%s\n", best);
+
+diff -Naur glibc-2.20/elf/dl-close.c glibc-2.20-rtld-debug/elf/dl-close.c
+--- glibc-2.20/elf/dl-close.c 2014-09-07 03:09:09.000000000 -0500
++++ glibc-2.20-rtld-debug/elf/dl-close.c 2015-02-19 04:00:31.553729819 -0600
+@@ -125,7 +125,7 @@
+ dl_close_state = rerun;
+
+ /* There are still references to this object. Do nothing more. */
+- if (__glibc_unlikely (GLRO(dl_debug_mask) & DL_DEBUG_FILES))
++ if (__glibc_unlikely (GLRO_dl_debug_mask & DL_DEBUG_FILES))
+ _dl_debug_printf ("\nclosing file=%s; direct_opencount=%u\n",
+ map->l_name, map->l_direct_opencount);
+
+@@ -257,7 +257,7 @@
+ if (imap->l_init_called)
+ {
+ /* When debugging print a message first. */
+- if (__builtin_expect (GLRO(dl_debug_mask) & DL_DEBUG_IMPCALLS,
++ if (__builtin_expect (GLRO_dl_debug_mask & DL_DEBUG_IMPCALLS,
+ 0))
+ _dl_debug_printf ("\ncalling fini: %s [%lu]\n\n",
+ imap->l_name, nsid);
+@@ -664,7 +664,7 @@
+ free (imap->l_reldeps);
+
+ /* Print debugging message. */
+- if (__glibc_unlikely (GLRO(dl_debug_mask) & DL_DEBUG_FILES))
++ if (__glibc_unlikely (GLRO_dl_debug_mask & DL_DEBUG_FILES))
+ _dl_debug_printf ("\nfile=%s [%lu]; destroying link map\n",
+ imap->l_name, imap->l_ns);
+
+diff -Naur glibc-2.20/elf/dl-conflict.c glibc-2.20-rtld-debug/elf/dl-conflict.c
+--- glibc-2.20/elf/dl-conflict.c 2014-09-07 03:09:09.000000000 -0500
++++ glibc-2.20-rtld-debug/elf/dl-conflict.c 2015-02-19 04:00:31.553729819 -0600
+@@ -32,7 +32,7 @@
+ ElfW(Rela) *conflictend)
+ {
+ #if ! ELF_MACHINE_NO_RELA
+- if (__glibc_unlikely (GLRO(dl_debug_mask) & DL_DEBUG_RELOC))
++ if (__glibc_unlikely (GLRO_dl_debug_mask & DL_DEBUG_RELOC))
+ _dl_debug_printf ("\nconflict processing: %s\n", DSO_FILENAME (l->l_name));
+
+ {
+diff -Naur glibc-2.20/elf/dl-deps.c glibc-2.20-rtld-debug/elf/dl-deps.c
+--- glibc-2.20/elf/dl-deps.c 2014-09-07 03:09:09.000000000 -0500
++++ glibc-2.20-rtld-debug/elf/dl-deps.c 2015-02-19 04:00:31.553729819 -0600
+@@ -127,7 +127,7 @@
+ else \
+ { \
+ /* This is for DT_AUXILIARY. */ \
+- if (__glibc_unlikely (GLRO(dl_debug_mask) & DL_DEBUG_LIBS)) \
++ if (__glibc_unlikely (GLRO_dl_debug_mask & DL_DEBUG_LIBS)) \
+ _dl_debug_printf (N_("\
+ cannot load auxiliary `%s' because of empty dynamic string token " \
+ "substitution\n"), __str); \
+@@ -303,7 +303,7 @@
+ args.name = name;
+
+ /* Say that we are about to load an auxiliary library. */
+- if (__builtin_expect (GLRO(dl_debug_mask) & DL_DEBUG_LIBS,
++ if (__builtin_expect (GLRO_dl_debug_mask & DL_DEBUG_LIBS,
+ 0))
+ _dl_debug_printf ("load auxiliary object=%s"
+ " requested by file=%s\n",
+@@ -520,7 +520,7 @@
+ runp->map->l_reserved = 0;
+ }
+
+- if (__builtin_expect (GLRO(dl_debug_mask) & DL_DEBUG_PRELINK, 0) != 0
++ if (__builtin_expect (GLRO_dl_debug_mask & DL_DEBUG_PRELINK, 0) != 0
+ && map == GL(dl_ns)[LM_ID_BASE]._ns_loaded)
+ {
+ /* If we are to compute conflicts, we have to build local scope
+diff -Naur glibc-2.20/elf/dl-error.c glibc-2.20-rtld-debug/elf/dl-error.c
+--- glibc-2.20/elf/dl-error.c 2014-09-07 03:09:09.000000000 -0500
++++ glibc-2.20-rtld-debug/elf/dl-error.c 2015-02-19 04:00:31.554729815 -0600
+@@ -139,7 +139,7 @@
+ _dl_signal_cerror (int errcode, const char *objname, const char *occation,
+ const char *errstring)
+ {
+- if (__builtin_expect (GLRO(dl_debug_mask)
++ if (__builtin_expect (GLRO_dl_debug_mask
+ & ~(DL_DEBUG_STATISTICS|DL_DEBUG_PRELINK), 0))
+ _dl_debug_printf ("%s: error: %s: %s (%s)\n", objname, occation,
+ errstring, receiver ? "continued" : "fatal");
+diff -Naur glibc-2.20/elf/dl-fini.c glibc-2.20-rtld-debug/elf/dl-fini.c
+--- glibc-2.20/elf/dl-fini.c 2014-09-07 03:09:09.000000000 -0500
++++ glibc-2.20-rtld-debug/elf/dl-fini.c 2015-02-19 04:00:31.554729815 -0600
+@@ -234,7 +234,7 @@
+ || l->l_info[DT_FINI] != NULL)
+ {
+ /* When debugging print a message first. */
+- if (__builtin_expect (GLRO(dl_debug_mask)
++ if (__builtin_expect (GLRO_dl_debug_mask
+ & DL_DEBUG_IMPCALLS, 0))
+ _dl_debug_printf ("\ncalling fini: %s [%lu]\n\n",
+ DSO_FILENAME (l->l_name),
+@@ -286,7 +286,7 @@
+ goto again;
+ }
+
+- if (__glibc_unlikely (GLRO(dl_debug_mask) & DL_DEBUG_STATISTICS))
++ if (__glibc_unlikely (GLRO_dl_debug_mask & DL_DEBUG_STATISTICS))
+ _dl_debug_printf ("\nruntime linker statistics:\n"
+ " final number of relocations: %lu\n"
+ "final number of relocations from cache: %lu\n",
+diff -Naur glibc-2.20/elf/dl-init.c glibc-2.20-rtld-debug/elf/dl-init.c
+--- glibc-2.20/elf/dl-init.c 2014-09-07 03:09:09.000000000 -0500
++++ glibc-2.20-rtld-debug/elf/dl-init.c 2015-02-19 04:00:31.554729815 -0600
+@@ -52,7 +52,7 @@
+ return;
+
+ /* Print a debug message if wanted. */
+- if (__glibc_unlikely (GLRO(dl_debug_mask) & DL_DEBUG_IMPCALLS))
++ if (__glibc_unlikely (GLRO_dl_debug_mask & DL_DEBUG_IMPCALLS))
+ _dl_debug_printf ("\ncalling init: %s\n\n",
+ DSO_FILENAME (l->l_name));
+
+@@ -102,7 +102,7 @@
+ ElfW(Addr) *addrs;
+ unsigned int cnt;
+
+- if (__glibc_unlikely (GLRO(dl_debug_mask) & DL_DEBUG_IMPCALLS))
++ if (__glibc_unlikely (GLRO_dl_debug_mask & DL_DEBUG_IMPCALLS))
+ _dl_debug_printf ("\ncalling preinit: %s\n\n",
+ DSO_FILENAME (main_map->l_name));
+
+diff -Naur glibc-2.20/elf/dl-load.c glibc-2.20-rtld-debug/elf/dl-load.c
+--- glibc-2.20/elf/dl-load.c 2014-09-07 03:09:09.000000000 -0500
++++ glibc-2.20-rtld-debug/elf/dl-load.c 2015-02-19 04:00:31.555729814 -0600
+@@ -957,7 +957,7 @@
+ }
+
+ /* Print debugging message. */
+- if (__glibc_unlikely (GLRO(dl_debug_mask) & DL_DEBUG_FILES))
++ if (__glibc_unlikely (GLRO_dl_debug_mask & DL_DEBUG_FILES))
+ _dl_debug_printf ("file=%s [%lu]; generating link map\n", name, nsid);
+
+ /* This is the ELF header. We read it in `open_verify'. */
+@@ -1361,7 +1361,7 @@
+
+ l->l_entry += l->l_addr;
+
+- if (__glibc_unlikely (GLRO(dl_debug_mask) & DL_DEBUG_FILES))
++ if (__glibc_unlikely (GLRO_dl_debug_mask & DL_DEBUG_FILES))
+ _dl_debug_printf ("\
+ dynamic: 0x%0*lx base: 0x%0*lx size: 0x%0*Zx\n\
+ entry: 0x%0*lx phdr: 0x%0*lx phnum: %*u\n\n",
+@@ -1787,7 +1787,7 @@
+
+ /* If we are debugging the search for libraries print the path
+ now if it hasn't happened now. */
+- if (__glibc_unlikely (GLRO(dl_debug_mask) & DL_DEBUG_LIBS)
++ if (__glibc_unlikely (GLRO_dl_debug_mask & DL_DEBUG_LIBS)
+ && current_what != this_dir->what)
+ {
+ current_what = this_dir->what;
+@@ -1808,7 +1808,7 @@
+ - buf);
+
+ /* Print name we try if this is wanted. */
+- if (__glibc_unlikely (GLRO(dl_debug_mask) & DL_DEBUG_LIBS))
++ if (__glibc_unlikely (GLRO_dl_debug_mask & DL_DEBUG_LIBS))
+ _dl_debug_printf (" trying file=%s\n", buf);
+
+ fd = open_verify (buf, fbp, loader, whatcode, mode,
+@@ -1953,7 +1953,7 @@
+ }
+
+ /* Display information if we are debugging. */
+- if (__glibc_unlikely (GLRO(dl_debug_mask) & DL_DEBUG_FILES)
++ if (__glibc_unlikely (GLRO_dl_debug_mask & DL_DEBUG_FILES)
+ && loader != NULL)
+ _dl_debug_printf ((mode & __RTLD_CALLMAP) == 0
+ ? "\nfile=%s [%lu]; needed by %s [%lu]\n"
+@@ -1995,7 +1995,7 @@
+
+ size_t namelen = strlen (name) + 1;
+
+- if (__glibc_unlikely (GLRO(dl_debug_mask) & DL_DEBUG_LIBS))
++ if (__glibc_unlikely (GLRO_dl_debug_mask & DL_DEBUG_LIBS))
+ _dl_debug_printf ("find library=%s [%lu]; searching\n", name, nsid);
+
+ fd = -1;
+@@ -2122,7 +2122,7 @@
+ &realname, &fb, l, LA_SER_DEFAULT, &found_other_class);
+
+ /* Add another newline when we are tracing the library loading. */
+- if (__glibc_unlikely (GLRO(dl_debug_mask) & DL_DEBUG_LIBS))
++ if (__glibc_unlikely (GLRO_dl_debug_mask & DL_DEBUG_LIBS))
+ _dl_debug_printf ("\n");
+ }
+ else
+@@ -2155,7 +2155,7 @@
+ if (__glibc_unlikely (fd == -1))
+ {
+ if (trace_mode
+- && __glibc_likely ((GLRO(dl_debug_mask) & DL_DEBUG_PRELINK) == 0))
++ && __glibc_likely ((GLRO_dl_debug_mask & DL_DEBUG_PRELINK) == 0))
+ {
+ /* We haven't found an appropriate library. But since we
+ are only interested in the list of libraries this isn't
+diff -Naur glibc-2.20/elf/dl-lookup.c glibc-2.20-rtld-debug/elf/dl-lookup.c
+--- glibc-2.20/elf/dl-lookup.c 2014-09-07 03:09:09.000000000 -0500
++++ glibc-2.20-rtld-debug/elf/dl-lookup.c 2015-02-19 04:00:31.551729823 -0600
+@@ -300,7 +300,7 @@
+ hash table. */
+ if (__glibc_unlikely (tab->size))
+ {
+- assert (GLRO(dl_debug_mask) & DL_DEBUG_PRELINK);
++ assert (GLRO_dl_debug_mask & DL_DEBUG_PRELINK);
+ goto success;
+ }
+ #endif
+@@ -375,7 +375,7 @@
+ continue;
+
+ /* Print some debugging info if wanted. */
+- if (__glibc_unlikely (GLRO(dl_debug_mask) & DL_DEBUG_SYMBOLS))
++ if (__glibc_unlikely (GLRO_dl_debug_mask & DL_DEBUG_SYMBOLS))
+ _dl_debug_printf ("symbol=%s; lookup in file=%s [%lu]\n",
+ undef_name, DSO_FILENAME (map->l_name),
+ map->l_ns);
+@@ -698,7 +698,7 @@
+ }
+
+ /* Display information if we are debugging. */
+- if (__glibc_unlikely (GLRO(dl_debug_mask) & DL_DEBUG_FILES))
++ if (__glibc_unlikely (GLRO_dl_debug_mask & DL_DEBUG_FILES))
+ _dl_debug_printf ("\
+ \nfile=%s [%lu]; needed by %s [%lu] (relocation dependency)\n\n",
+ DSO_FILENAME (map->l_name),
+@@ -802,7 +802,7 @@
+ {
+ if ((*ref == NULL || ELFW(ST_BIND) ((*ref)->st_info) != STB_WEAK)
+ && skip_map == NULL
+- && !(GLRO(dl_debug_mask) & DL_DEBUG_UNUSED))
++ && !(GLRO_dl_debug_mask & DL_DEBUG_UNUSED))
+ {
+ /* We could find no value for a strong reference. */
+ const char *reference_name = undef_map ? undef_map->l_name : "";
+@@ -873,7 +873,7 @@
+ if (__glibc_unlikely (current_value.m->l_used == 0))
+ current_value.m->l_used = 1;
+
+- if (__glibc_unlikely (GLRO(dl_debug_mask)
++ if (__glibc_unlikely (GLRO_dl_debug_mask
+ & (DL_DEBUG_BINDINGS|DL_DEBUG_PRELINK)))
+ _dl_debug_bindings (undef_name, undef_map, ref,
+ ¤t_value, version, type_class, protected);
+@@ -938,7 +938,7 @@
+ {
+ const char *reference_name = undef_map->l_name;
+
+- if (GLRO(dl_debug_mask) & DL_DEBUG_BINDINGS)
++ if (GLRO_dl_debug_mask & DL_DEBUG_BINDINGS)
+ {
+ _dl_debug_printf ("binding file %s [%lu] to %s [%lu]: %s symbol `%s'",
+ DSO_FILENAME (reference_name),
+@@ -952,7 +952,7 @@
+ _dl_debug_printf_c ("\n");
+ }
+ #ifdef SHARED
+- if (GLRO(dl_debug_mask) & DL_DEBUG_PRELINK)
++ if (GLRO_dl_debug_mask & DL_DEBUG_PRELINK)
+ {
+ int conflict = 0;
+ struct sym_val val = { NULL, NULL };
+diff -Naur glibc-2.20/elf/dl-object.c glibc-2.20-rtld-debug/elf/dl-object.c
+--- glibc-2.20/elf/dl-object.c 2014-09-07 03:09:09.000000000 -0500
++++ glibc-2.20-rtld-debug/elf/dl-object.c 2015-02-19 04:00:31.555729814 -0600
+@@ -98,7 +98,7 @@
+ new->l_type = type;
+ /* If we set the bit now since we know it is never used we avoid
+ dirtying the cache line later. */
+- if ((GLRO(dl_debug_mask) & DL_DEBUG_UNUSED) == 0)
++ if ((GLRO_dl_debug_mask & DL_DEBUG_UNUSED) == 0)
+ new->l_used = 1;
+ new->l_loader = loader;
+ #if NO_TLS_OFFSET != 0
+diff -Naur glibc-2.20/elf/dl-open.c glibc-2.20-rtld-debug/elf/dl-open.c
+--- glibc-2.20/elf/dl-open.c 2014-09-07 03:09:09.000000000 -0500
++++ glibc-2.20-rtld-debug/elf/dl-open.c 2015-02-19 04:00:31.549729817 -0600
+@@ -147,7 +147,7 @@
+ ns->_ns_main_searchlist->r_list[new_nlist++] = map;
+
+ /* We modify the global scope. Report this. */
+- if (__glibc_unlikely (GLRO(dl_debug_mask) & DL_DEBUG_SCOPES))
++ if (__glibc_unlikely (GLRO_dl_debug_mask & DL_DEBUG_SCOPES))
+ _dl_debug_printf ("\nadd %s [%lu] to global scope\n",
+ map->l_name, map->l_ns);
+ }
+@@ -243,7 +243,7 @@
+ if (__glibc_unlikely (new->l_searchlist.r_list != NULL))
+ {
+ /* Let the user know about the opencount. */
+- if (__glibc_unlikely (GLRO(dl_debug_mask) & DL_DEBUG_FILES))
++ if (__glibc_unlikely (GLRO_dl_debug_mask & DL_DEBUG_FILES))
+ _dl_debug_printf ("opening file=%s [%lu]; direct_opencount=%u\n\n",
+ new->l_name, new->l_ns, new->l_direct_opencount);
+
+@@ -294,7 +294,7 @@
+ LIBC_PROBE (map_complete, 3, args->nsid, r, new);
+
+ /* Print scope information. */
+- if (__glibc_unlikely (GLRO(dl_debug_mask) & DL_DEBUG_SCOPES))
++ if (__glibc_unlikely (GLRO_dl_debug_mask & DL_DEBUG_SCOPES))
+ _dl_show_scope (new, 0);
+
+ /* Only do lazy relocation if `LD_BIND_NOW' is not set. */
+@@ -511,7 +511,7 @@
+ }
+
+ /* Print scope information. */
+- if (__glibc_unlikely (GLRO(dl_debug_mask) & DL_DEBUG_SCOPES))
++ if (__glibc_unlikely (GLRO_dl_debug_mask & DL_DEBUG_SCOPES))
+ _dl_show_scope (imap, from_scope);
+ }
+
+@@ -584,7 +584,7 @@
+ #endif
+
+ /* Let the user know about the opencount. */
+- if (__glibc_unlikely (GLRO(dl_debug_mask) & DL_DEBUG_FILES))
++ if (__glibc_unlikely (GLRO_dl_debug_mask & DL_DEBUG_FILES))
+ _dl_debug_printf ("opening file=%s [%lu]; direct_opencount=%u\n\n",
+ new->l_name, new->l_ns, new->l_direct_opencount);
+ }
+diff -Naur glibc-2.20/elf/dl-reloc.c glibc-2.20-rtld-debug/elf/dl-reloc.c
+--- glibc-2.20/elf/dl-reloc.c 2014-09-07 03:09:09.000000000 -0500
++++ glibc-2.20-rtld-debug/elf/dl-reloc.c 2015-02-19 04:00:31.556729815 -0600
+@@ -183,7 +183,7 @@
+ && __builtin_expect (l->l_info[DT_BIND_NOW] != NULL, 0))
+ lazy = 0;
+
+- if (__glibc_unlikely (GLRO(dl_debug_mask) & DL_DEBUG_RELOC))
++ if (__glibc_unlikely (GLRO_dl_debug_mask & DL_DEBUG_RELOC))
+ _dl_debug_printf ("\nrelocation processing: %s%s\n",
+ DSO_FILENAME (l->l_name), lazy ? " (lazy)" : "");
+
+diff -Naur glibc-2.20/elf/dl-version.c glibc-2.20-rtld-debug/elf/dl-version.c
+--- glibc-2.20/elf/dl-version.c 2014-09-07 03:09:09.000000000 -0500
++++ glibc-2.20-rtld-debug/elf/dl-version.c 2015-02-19 04:00:31.556729815 -0600
+@@ -82,7 +82,7 @@
+ int result = 0;
+
+ /* Display information about what we are doing while debugging. */
+- if (__glibc_unlikely (GLRO(dl_debug_mask) & DL_DEBUG_VERSIONS))
++ if (__glibc_unlikely (GLRO_dl_debug_mask & DL_DEBUG_VERSIONS))
+ _dl_debug_printf ("\
+ checking for version `%s' in file %s [%lu] required by file %s [%lu]\n",
+ string, DSO_FILENAME (map->l_name),
+diff -Naur glibc-2.20/elf/get-dynamic-info.h glibc-2.20-rtld-debug/elf/get-dynamic-info.h
+--- glibc-2.20/elf/get-dynamic-info.h 2014-09-07 03:09:09.000000000 -0500
++++ glibc-2.20-rtld-debug/elf/get-dynamic-info.h 2015-02-19 04:00:31.551729823 -0600
+@@ -157,7 +157,7 @@
+ them. Therefore to avoid breaking existing applications the
+ best we can do is add a warning during debugging with the
+ intent of notifying the user of the problem. */
+- if (__builtin_expect (GLRO(dl_debug_mask) & DL_DEBUG_FILES, 0)
++ if (__builtin_expect (GLRO_dl_debug_mask & DL_DEBUG_FILES, 0)
+ && l->l_flags_1 & ~DT_1_SUPPORTED_MASK)
+ _dl_debug_printf ("\nWARNING: Unsupported flag value(s) of 0x%x in DT_FLAGS_1.\n",
+ l->l_flags_1 & ~DT_1_SUPPORTED_MASK);
+diff -Naur glibc-2.20/elf/rtld.c glibc-2.20-rtld-debug/elf/rtld.c
+--- glibc-2.20/elf/rtld.c 2015-02-19 04:00:03.365732116 -0600
++++ glibc-2.20-rtld-debug/elf/rtld.c 2015-02-19 04:00:31.550729821 -0600
+@@ -321,7 +321,7 @@
+ }
+ #endif
+
+- if (__glibc_unlikely (GLRO(dl_debug_mask) & DL_DEBUG_STATISTICS))
++ if (__glibc_unlikely (GLRO_dl_debug_mask & DL_DEBUG_STATISTICS))
+ {
+ #ifndef HP_TIMING_NONAVAIL
+ print_statistics (&rtld_total_time);
+@@ -1699,7 +1699,7 @@
+ after relocation. */
+ struct link_map *l;
+
+- if (GLRO(dl_debug_mask) & DL_DEBUG_PRELINK)
++ if (GLRO_dl_debug_mask & DL_DEBUG_PRELINK)
+ {
+ struct r_scope_elem *scope = &main_map->l_searchlist;
+
+@@ -1729,7 +1729,7 @@
+ _dl_printf ("\n");
+ }
+ }
+- else if (GLRO(dl_debug_mask) & DL_DEBUG_UNUSED)
++ else if (GLRO_dl_debug_mask & DL_DEBUG_UNUSED)
+ {
+ /* Look through the dependencies of the main executable
+ and determine which of them is not actually
+@@ -1837,7 +1837,7 @@
+ }
+ }
+
+- if ((GLRO(dl_debug_mask) & DL_DEBUG_PRELINK)
++ if ((GLRO_dl_debug_mask & DL_DEBUG_PRELINK)
+ && rtld_multiple_ref)
+ {
+ /* Mark the link map as not yet relocated again. */
+@@ -1970,7 +1970,7 @@
+ if (r_list == r_listend && liblist == liblistend)
+ prelinked = true;
+
+- if (__glibc_unlikely (GLRO(dl_debug_mask) & DL_DEBUG_LIBS))
++ if (__glibc_unlikely (GLRO_dl_debug_mask & DL_DEBUG_LIBS))
+ _dl_debug_printf ("\nprelink checking: %s\n",
+ prelinked ? "ok" : "failed");
+ }
+@@ -1988,7 +1988,7 @@
+ GLRO(dl_init_all_dirs) = GL(dl_all_dirs);
+
+ /* Print scope information. */
+- if (__glibc_unlikely (GLRO(dl_debug_mask) & DL_DEBUG_SCOPES))
++ if (__glibc_unlikely (GLRO_dl_debug_mask & DL_DEBUG_SCOPES))
+ {
+ _dl_debug_printf ("\nInitial object scopes\n");
+
+@@ -2262,7 +2262,7 @@
+ if (debopts[cnt].len == len
+ && memcmp (dl_debug, debopts[cnt].name, len) == 0)
+ {
+- GLRO(dl_debug_mask) |= debopts[cnt].mask;
++ GLRO_dl_debug_mask |= debopts[cnt].mask;
+ any_debug = 1;
+ break;
+ }
+@@ -2283,7 +2283,7 @@
+ ++dl_debug;
+ }
+
+- if (GLRO(dl_debug_mask) & DL_DEBUG_UNUSED)
++ if (GLRO_dl_debug_mask & DL_DEBUG_UNUSED)
+ {
+ /* In order to get an accurate picture of whether a particular
+ DT_NEEDED entry is actually used we have to process both
+@@ -2291,7 +2291,7 @@
+ GLRO(dl_lazy) = 0;
+ }
+
+- if (GLRO(dl_debug_mask) & DL_DEBUG_HELP)
++ if (GLRO_dl_debug_mask & DL_DEBUG_HELP)
+ {
+ size_t cnt;
+
+@@ -2490,7 +2490,7 @@
+ {
+ mode = trace;
+ GLRO(dl_verbose) = 1;
+- GLRO(dl_debug_mask) |= DL_DEBUG_PRELINK;
++ GLRO_dl_debug_mask |= DL_DEBUG_PRELINK;
+ GLRO(dl_trace_prelink) = &envline[17];
+ }
+ break;
+@@ -2537,7 +2537,7 @@
+ if (__access ("/etc/suid-debug", F_OK) != 0)
+ {
+ unsetenv ("MALLOC_CHECK_");
+- GLRO(dl_debug_mask) = 0;
++ GLRO_dl_debug_mask = 0;
+ }
+
+ if (mode != normal)
diff --git a/recipes-core/glibc/glibc-fsl/00xx.glibc.use-option-groups.patch b/recipes-core/glibc/glibc-fsl/00xx.glibc.use-option-groups.patch
new file mode 100755
index 0000000..9ba413e
--- /dev/null
+++ b/recipes-core/glibc/glibc-fsl/00xx.glibc.use-option-groups.patch
@@ -0,0 +1,16551 @@
+# Problem Statement:
+ Forward port eglibc options groups support to glibc v2.20
+
+# Referred from patch by:
+ Yocto Project
+ http://git.yoctoproject.org/cgit.cgi/poky/plain/meta/recipes-core/glibc/glibc/eglibc-use-option-groups.patch
+ Upstream-Status: Pending
+
+ * Updated patch to fix glibc test suite failures.
+
+diff -Naur glibc-2.20/argp/argp-fmtstream.c glibc-2.20-patch/argp/argp-fmtstream.c
+--- glibc-2.20/argp/argp-fmtstream.c 2014-09-07 03:09:09.000000000 -0500
++++ glibc-2.20-patch/argp/argp-fmtstream.c 2015-03-04 00:51:32.366952005 -0600
+@@ -42,6 +42,7 @@
+ #ifdef _LIBC
+ # include <wchar.h>
+ # include <libio/libioP.h>
++# include <gnu/option-groups.h>
+ # define __vsnprintf(s, l, f, a) _IO_vsnprintf (s, l, f, a)
+ #endif
+
+@@ -100,7 +101,11 @@
+ __argp_fmtstream_update (fs);
+ if (fs->p > fs->buf)
+ {
++#ifdef _LIBC
+ __fxprintf (fs->stream, "%.*s", (int) (fs->p - fs->buf), fs->buf);
++#else
++ fwrite_unlocked (fs->buf, 1, fs->p - fs->buf, fs->stream);
++#endif
+ }
+ free (fs->buf);
+ free (fs);
+@@ -145,9 +150,17 @@
+ size_t i;
+ for (i = 0; i < pad; i++)
+ {
++#ifdef _LIBC
+ if (_IO_fwide (fs->stream, 0) > 0)
+- putwc_unlocked (L' ', fs->stream);
++ {
++#if ! _LIBC || __OPTION_POSIX_WIDE_CHAR_DEVICE_IO
++ putwc_unlocked (L' ', fs->stream);
++#else
++ abort ();
++#endif
++ }
+ else
++#endif
+ putc_unlocked (' ', fs->stream);
+ }
+ }
+@@ -308,9 +321,17 @@
+ *nl++ = ' ';
+ else
+ for (i = 0; i < fs->wmargin; ++i)
++#ifdef _LIBC
+ if (_IO_fwide (fs->stream, 0) > 0)
+- putwc_unlocked (L' ', fs->stream);
++ {
++#ifdef OPTION_POSIX_WIDE_CHAR_DEVICE_IO
++ putwc_unlocked (L' ', fs->stream);
++#else
++ abort ();
++#endif
++ }
+ else
++#endif
+ putc_unlocked (' ', fs->stream);
+
+ /* Copy the tail of the original buffer into the current buffer
+diff -Naur glibc-2.20/argp/argp-help.c glibc-2.20-patch/argp/argp-help.c
+--- glibc-2.20/argp/argp-help.c 2014-09-07 03:09:09.000000000 -0500
++++ glibc-2.20-patch/argp/argp-help.c 2015-03-04 00:51:32.366952005 -0600
+@@ -51,6 +51,7 @@
+ #ifdef _LIBC
+ # include <../libio/libioP.h>
+ # include <wchar.h>
++# include <gnu/option-groups.h>
+ #endif
+
+ #ifndef _
+@@ -1702,7 +1703,7 @@
+ }
+
+ char *
+-__argp_short_program_name (void)
++(__argp_short_program_name) (void)
+ {
+ # if HAVE_DECL_PROGRAM_INVOCATION_SHORT_NAME
+ return program_invocation_short_name;
+@@ -1873,9 +1874,17 @@
+ #endif
+ }
+
++#ifdef _LIBC
+ if (_IO_fwide (stream, 0) > 0)
+- putwc_unlocked (L'\n', stream);
++ {
++#if ! _LIBC || __OPTION_POSIX_WIDE_CHAR_DEVICE_IO
++ putwc_unlocked (L'\n', stream);
++#else
++ abort ();
++#endif
++ }
+ else
++#endif
+ putc_unlocked ('\n', stream);
+
+ #if _LIBC || (HAVE_FLOCKFILE && HAVE_FUNLOCKFILE)
+diff -Naur glibc-2.20/argp/argp-namefrob.h glibc-2.20-patch/argp/argp-namefrob.h
+--- glibc-2.20/argp/argp-namefrob.h 2014-09-07 03:09:09.000000000 -0500
++++ glibc-2.20-patch/argp/argp-namefrob.h 2015-03-04 00:51:32.366952005 -0600
+@@ -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 -Naur glibc-2.20/argp/Makefile glibc-2.20-patch/argp/Makefile
+--- glibc-2.20/argp/Makefile 2014-09-07 03:09:09.000000000 -0500
++++ glibc-2.20-patch/argp/Makefile 2015-03-04 00:51:32.366952005 -0600
+@@ -18,6 +18,8 @@
+ #
+ # Makefile for argp.
+ #
++include ../option-groups.mak
++
+ subdir := argp
+
+ include ../Makeconfig
+diff -Naur glibc-2.20/catgets/Makefile glibc-2.20-patch/catgets/Makefile
+--- glibc-2.20/catgets/Makefile 2014-09-07 03:09:09.000000000 -0500
++++ glibc-2.20-patch/catgets/Makefile 2015-03-04 00:51:32.367952004 -0600
+@@ -22,20 +22,23 @@
+
+ include ../Makeconfig
+
++include ../option-groups.mak
++
+ headers = nl_types.h
+-routines = catgets open_catalog
+-others = gencat
+-install-bin = gencat
+-extra-objs = $(gencat-modules:=.o)
++routines-$(OPTION_EGLIBC_CATGETS) := catgets open_catalog
++others-$(OPTION_EGLIBC_CATGETS) := gencat
++install-bin-$(OPTION_EGLIBC_CATGETS) := gencat
++extra-objs-$(OPTION_EGLIBC_CATGETS) := $(gencat-modules:=.o)
+
+-tests = tst-catgets
+-test-srcs = test-gencat
++tests-$(OPTION_EGLIBC_CATGETS) := tst-catgets
++test-srcs-$(OPTION_EGLIBC_CATGETS) := test-gencat
+
++ifeq (y,$(OPTION_EGLIBC_CATGETS))
+ ifeq ($(run-built-tests),yes)
+ tests-special += $(objpfx)de/libc.cat $(objpfx)test1.cat $(objpfx)test2.cat \
+ $(objpfx)sample.SJIS.cat $(objpfx)test-gencat.out
+ endif
+-
++endif
+ gencat-modules = xmalloc
+
+ # To find xmalloc.c
+diff -Naur glibc-2.20/crypt/crypt_common.c glibc-2.20-patch/crypt/crypt_common.c
+--- glibc-2.20/crypt/crypt_common.c 1969-12-31 18:00:00.000000000 -0600
++++ glibc-2.20-patch/crypt/crypt_common.c 2015-03-04 00:51:32.367952004 -0600
+@@ -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 -Naur glibc-2.20/crypt/crypt-entry.c glibc-2.20-patch/crypt/crypt-entry.c
+--- glibc-2.20/crypt/crypt-entry.c 2014-09-07 03:09:09.000000000 -0500
++++ glibc-2.20-patch/crypt/crypt-entry.c 2015-03-04 00:51:32.367952004 -0600
+@@ -27,6 +27,7 @@
+ #include <stdio.h>
+ #endif
+ #include <string.h>
++#include <gnu/option-groups.h>
+ #include <errno.h>
+ #include <fips-private.h>
+
+@@ -76,9 +77,11 @@
+ const char *salt;
+ struct crypt_data * __restrict data;
+ {
++#if __OPTION_EGLIBC_CRYPT_UFC
+ ufc_long res[4];
+ char ktab[9];
+ ufc_long xx = 25; /* to cope with GCC long long compiler bugs */
++#endif /*__OPTION_EGLIBC_CRYPT_UFC*/
+
+ #ifdef _LIBC
+ /* Try to find out whether we have to use MD5 encryption replacement. */
+@@ -105,6 +108,7 @@
+ sizeof (struct crypt_data));
+ #endif
+
++#if __OPTION_EGLIBC_CRYPT_UFC
+ /*
+ * Hack DES tables according to salt
+ */
+@@ -144,6 +148,10 @@
+ */
+ _ufc_output_conversion_r (res[0], res[1], salt, data);
+ return data->crypt_3_buf;
++#else /* __OPTION_EGLIBC_CRYPT_UFC */
++ __set_errno (ENOSYS);
++ return NULL;
++#endif /* __OPTION_EGLIBC_CRYPT_UFC */
+ }
+ weak_alias (__crypt_r, crypt_r)
+
+@@ -168,7 +176,12 @@
+ return __sha512_crypt (key, salt);
+ #endif
+
++#if __OPTION_EGLIBC_CRYPT_UFC
+ return __crypt_r (key, salt, &_ufc_foobar);
++#else /* __OPTION_EGLIBC_CRYPT_UFC */
++ __set_errno (ENOSYS);
++ return NULL;
++#endif /* __OPTION_EGLIBC_CRYPT_UFC */
+ }
+
+
+diff -Naur glibc-2.20/crypt/crypt_util.c glibc-2.20-patch/crypt/crypt_util.c
+--- glibc-2.20/crypt/crypt_util.c 2014-09-07 03:09:09.000000000 -0500
++++ glibc-2.20-patch/crypt/crypt_util.c 2015-03-04 00:51:32.367952004 -0600
+@@ -242,10 +242,6 @@
+ */
+ static ufc_long efp[16][64][2];
+
+-/* Table with characters for base64 transformation. */
+-static const char b64t[64] =
+-"./0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz";
+-
+ /*
+ * For use by the old, non-reentrant routines
+ * (crypt/encrypt/setkey)
+@@ -949,17 +945,3 @@
+ {
+ __setkey_r(__key, &_ufc_foobar);
+ }
+-
+-void
+-__b64_from_24bit (char **cp, int *buflen,
+- unsigned int b2, unsigned int b1, unsigned int b0,
+- int n)
+-{
+- unsigned int w = (b2 << 16) | (b1 << 8) | b0;
+- while (n-- > 0 && (*buflen) > 0)
+- {
+- *(*cp)++ = b64t[w & 0x3f];
+- --(*buflen);
+- w >>= 6;
+- }
+-}
+diff -Naur glibc-2.20/crypt/Makefile glibc-2.20-patch/crypt/Makefile
+--- glibc-2.20/crypt/Makefile 2014-09-07 03:09:09.000000000 -0500
++++ glibc-2.20-patch/crypt/Makefile 2015-03-04 00:51:32.367952004 -0600
+@@ -18,21 +18,25 @@
+ #
+ # Sub-makefile for crypt() portion of the library.
+ #
++include ../option-groups.mak
++
+ subdir := crypt
+
+ include ../Makeconfig
+
+ headers := crypt.h
+
+-extra-libs := libcrypt
+-extra-libs-others := $(extra-libs)
++extra-libs-$(OPTION_EGLIBC_CRYPT) := libcrypt
++extra-libs-others-y := $(extra-libs-y)
+
+-libcrypt-routines := crypt-entry md5-crypt sha256-crypt sha512-crypt crypt \
+- crypt_util
++libcrypt-routines :=crypt-entry md5-crypt sha256-crypt sha512-crypt crypt_common
++libcrypt-routines-$(OPTION_EGLIBC_CRYPT_UFC) := crypt crypt_util
++libcrypt-routines += $(libcrypt-routines-y)
+
+-tests := cert md5c-test sha256c-test sha512c-test badsalttest
++tests-$(OPTION_EGLIBC_CRYPT) := md5c-test sha256c-test sha512c-test badsalttest
++tests-$(OPTION_EGLIBC_CRYPT_UFC) += cert
+
+-ifeq ($(crypt-in-libc),yes)
++ifeq ($(crypt-in-libc)$(OPTION_EGLIBC_CRYPT),yesy)
+ routines += $(libcrypt-routines)
+ endif
+
+@@ -44,7 +48,7 @@
+ else
+ libcrypt-routines += md5 sha256 sha512
+
+-tests += md5test sha256test sha512test
++tests-$(OPTION_EGLIBC_CRYPT) += md5test sha256test sha512test
+
+ # The test md5test-giant uses up to 400 MB of RSS and runs on a fast
+ # machine over a minute.
+@@ -64,8 +68,10 @@
+ $(objpfx)sha512test: $(patsubst %, $(objpfx)%.o,$(sha512-routines))
+ endif
+
++ifeq ($(OPTION_EGLIBC_CRYPT),y)
+ ifeq (yes,$(build-shared))
+ $(addprefix $(objpfx),$(tests)): $(objpfx)libcrypt.so
+ else
+ $(addprefix $(objpfx),$(tests)): $(objpfx)libcrypt.a
+ endif
++endif # eglibc: OPTION_EGLIBC_CRYPT
+diff -Naur glibc-2.20/csu/Makefile glibc-2.20-patch/csu/Makefile
+--- glibc-2.20/csu/Makefile 2014-09-07 03:09:09.000000000 -0500
++++ glibc-2.20-patch/csu/Makefile 2015-03-04 00:51:32.368952005 -0600
+@@ -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 -Naur glibc-2.20/debug/Makefile glibc-2.20-patch/debug/Makefile
+--- glibc-2.20/debug/Makefile 2014-09-07 03:09:09.000000000 -0500
++++ glibc-2.20-patch/debug/Makefile 2015-03-04 00:51:32.368952005 -0600
+@@ -18,6 +18,8 @@
+ #
+ # Sub-makefile for debug portion of the library.
+ #
++include ../option-groups.mak
++
+ subdir := debug
+
+ include ../Makeconfig
+@@ -27,7 +29,7 @@
+ # Note that ptsname_r_chk and getlogin_r are not here, but in
+ # login/Makefile instead. If that subdir is omitted from the
+ # build, its _FORTIFY_SOURCE support will be too.
+-routines = backtrace backtracesyms backtracesymsfd noophooks \
++routines = noophooks \
+ memcpy_chk memmove_chk mempcpy_chk memset_chk stpcpy_chk \
+ strcat_chk strcpy_chk strncat_chk strncpy_chk stpncpy_chk \
+ sprintf_chk vsprintf_chk snprintf_chk vsnprintf_chk \
+@@ -36,20 +38,27 @@
+ read_chk pread_chk pread64_chk recv_chk recvfrom_chk \
+ readlink_chk readlinkat_chk getwd_chk getcwd_chk \
+ realpath_chk fread_chk fread_u_chk \
+- wctomb_chk wcscpy_chk wmemcpy_chk wmemmove_chk wmempcpy_chk \
+- wcpcpy_chk wcsncpy_chk wcscat_chk wcsncat_chk wmemset_chk \
+- wcpncpy_chk \
+- swprintf_chk vswprintf_chk wprintf_chk fwprintf_chk \
+- vwprintf_chk vfwprintf_chk fgetws_chk fgetws_u_chk \
+ confstr_chk getgroups_chk ttyname_r_chk \
+- gethostname_chk getdomainname_chk wcrtomb_chk mbsnrtowcs_chk \
+- wcsnrtombs_chk mbsrtowcs_chk wcsrtombs_chk mbstowcs_chk \
+- wcstombs_chk asprintf_chk vasprintf_chk dprintf_chk \
++ gethostname_chk getdomainname_chk \
++ asprintf_chk vasprintf_chk dprintf_chk \
+ vdprintf_chk obprintf_chk \
+ longjmp_chk ____longjmp_chk \
+ fdelt_chk poll_chk ppoll_chk \
+ stack_chk_fail fortify_fail \
+ $(static-only-routines)
++routines-$(OPTION_EGLIBC_BACKTRACE) += backtrace backtracesyms backtracesymsfd
++routines-$(OPTION_POSIX_WIDE_CHAR_DEVICE_IO) \
++ += wprintf_chk fwprintf_chk \
++ vwprintf_chk vfwprintf_chk fgetws_chk fgetws_u_chk
++routines-$(OPTION_POSIX_C_LANG_WIDE_CHAR) \
++ += wctomb_chk wcscpy_chk wmemcpy_chk wmemmove_chk wmempcpy_chk \
++ wcpcpy_chk wcsncpy_chk wcscat_chk wcsncat_chk wmemset_chk \
++ wcpncpy_chk \
++ swprintf_chk vswprintf_chk \
++ wcrtomb_chk mbsnrtowcs_chk \
++ wcsnrtombs_chk mbsrtowcs_chk wcsrtombs_chk mbstowcs_chk \
++ wcstombs_chk
++
+ static-only-routines := warning-nop stack_chk_fail_local
+
+ CFLAGS-backtrace.c = -fno-omit-frame-pointer
+@@ -129,11 +138,15 @@
+ LDFLAGS-tst-backtrace5 = -rdynamic
+ LDFLAGS-tst-backtrace6 = -rdynamic
+
+-tests = backtrace-tst tst-longjmp_chk tst-chk1 tst-chk2 tst-chk3 \
+- tst-lfschk1 tst-lfschk2 tst-lfschk3 test-strcpy_chk test-stpcpy_chk \
+- tst-chk4 tst-chk5 tst-chk6 tst-lfschk4 tst-lfschk5 tst-lfschk6 \
+- tst-longjmp_chk2 tst-backtrace2 tst-backtrace3 tst-backtrace4 \
+- tst-backtrace5 tst-backtrace6
++tests = tst-longjmp_chk test-strcpy_chk test-stpcpy_chk tst-longjmp_chk2
++tests-$(OPTION_EGLIBC_LOCALE_CODE) \
++ += tst-chk1 tst-chk2 tst-chk3 tst-lfschk1 tst-lfschk2 tst-lfschk3
++tests-$(OPTION_EGLIBC_BACKTRACE) \
++ += backtrace-tst tst-backtrace2 tst-backtrace3 tst-backtrace4 \
++ tst-backtrace5 tst-backtrace6
++ifeq (yy,$(OPTION_EGLIBC_LOCALE_CODE)$(OPTION_EGLIBC_CXX_TESTS))
++tests += tst-chk4 tst-chk5 tst-chk6 tst-lfschk4 tst-lfschk5 tst-lfschk6
++endif
+
+ tests-ifunc := $(stpcpy_chk strcpy_chk:%=test-%-ifunc)
+ tests += $(tests-ifunc)
+diff -Naur glibc-2.20/debug/segfault.c glibc-2.20-patch/debug/segfault.c
+--- glibc-2.20/debug/segfault.c 2014-09-07 03:09:09.000000000 -0500
++++ glibc-2.20-patch/debug/segfault.c 2015-03-04 00:51:32.368952005 -0600
+@@ -30,6 +30,7 @@
+ #include <unistd.h>
+ #include <_itoa.h>
+ #include <ldsodefs.h>
++#include <gnu/option-groups.h>
+
+ /* This file defines macros to access the content of the sigcontext element
+ passed up by the signal handler. */
+@@ -91,6 +92,7 @@
+ REGISTER_DUMP;
+ #endif
+
++#if __OPTION_EGLIBC_BACKTRACE
+ WRITE_STRING ("\nBacktrace:\n");
+
+ /* Get the backtrace. */
+@@ -113,6 +115,7 @@
+
+ /* Now generate nicely formatted output. */
+ __backtrace_symbols_fd (arr + i, cnt - i, fd);
++#endif
+
+ #ifdef HAVE_PROC_SELF
+ /* Now the link map. */
+diff -Naur glibc-2.20/debug/tst-chk1.c glibc-2.20-patch/debug/tst-chk1.c
+--- glibc-2.20/debug/tst-chk1.c 2014-09-07 03:09:09.000000000 -0500
++++ glibc-2.20-patch/debug/tst-chk1.c 2015-03-04 00:51:32.368952005 -0600
+@@ -31,6 +31,7 @@
+ #include <sys/select.h>
+ #include <sys/socket.h>
+ #include <sys/un.h>
++#include <gnu/option-groups.h>
+
+
+ #define obstack_chunk_alloc malloc
+@@ -307,6 +308,7 @@
+ snprintf (buf + 8, l0 + 3, "%d", num2);
+ CHK_FAIL_END
+
++#if __OPTION_POSIX_C_LANG_WIDE_CHAR
+ CHK_FAIL_START
+ swprintf (wbuf + 8, 3, L"%d", num1);
+ CHK_FAIL_END
+@@ -314,6 +316,7 @@
+ CHK_FAIL_START
+ swprintf (wbuf + 8, l0 + 3, L"%d", num1);
+ CHK_FAIL_END
++#endif /* __OPTION_POSIX_C_LANG_WIDE_CHAR */
+ # endif
+
+ memcpy (buf, str1 + 2, l0 + 9);
+@@ -381,6 +384,7 @@
+ CHK_FAIL_END
+ #endif
+
++#if __OPTION_POSIX_C_LANG_WIDE_CHAR
+
+ /* These ops can be done without runtime checking of object size. */
+ wmemcpy (wbuf, L"abcdefghij", 10);
+@@ -605,6 +609,7 @@
+ CHK_FAIL_END
+ #endif
+
++#endif /* __OPTION_POSIX_C_LANG_WIDE_CHAR */
+
+ /* Now checks for %n protection. */
+
+@@ -1192,6 +1197,7 @@
+ # endif
+ #endif
+
++#if __OPTION_POSIX_C_LANG_WIDE_CHAR
+ if (setlocale (LC_ALL, "de_DE.UTF-8") != NULL)
+ {
+ assert (MB_CUR_MAX <= 10);
+@@ -1348,6 +1354,7 @@
+ puts ("cannot set locale");
+ ret = 1;
+ }
++#endif /* __OPTION_POSIX_C_LANG_WIDE_CHAR */
+
+ int fd = posix_openpt (O_RDWR);
+ if (fd != -1)
+diff -Naur glibc-2.20/dlfcn/Makefile glibc-2.20-patch/dlfcn/Makefile
+--- glibc-2.20/dlfcn/Makefile 2014-09-07 03:09:09.000000000 -0500
++++ glibc-2.20-patch/dlfcn/Makefile 2015-03-04 00:51:32.368952005 -0600
+@@ -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,14 +38,20 @@
+ ifeq (yes,$(build-shared))
+ tests = glrefmain failtest tst-dladdr default errmsg1 tstcxaatexit \
+ bug-dlopen1 bug-dlsym1 tst-dlinfo bug-atexit1 bug-atexit2 \
+- bug-atexit3 tstatexit bug-dl-leaf
++ tstatexit bug-dl-leaf
++
++tests-$(OPTION_EGLIBC_CXX_TESTS) += bug-atexit3
+ endif
+ modules-names = glreflib1 glreflib2 glreflib3 failtestmod defaultmod1 \
+ defaultmod2 errmsg1mod modatexit modcxaatexit \
+ bug-dlsym1-lib1 bug-dlsym1-lib2 bug-atexit1-lib \
+- bug-atexit2-lib bug-atexit3-lib bug-dl-leaf-lib \
++ bug-atexit2-lib bug-dl-leaf-lib \
+ bug-dl-leaf-lib-cb
+
++ifeq (y,$(OPTION_EGLIBC_CXX_TESTS))
++modules-names += bug-atexit3-lib
++endif
++
+ failtestmod.so-no-z-defs = yes
+ glreflib2.so-no-z-defs = yes
+ errmsg1mod.so-no-z-defs = yes
+diff -Naur glibc-2.20/elf/dl-support.c glibc-2.20-patch/elf/dl-support.c
+--- glibc-2.20/elf/dl-support.c 2014-09-07 03:09:09.000000000 -0500
++++ glibc-2.20-patch/elf/dl-support.c 2015-03-04 00:51:32.369952006 -0600
+@@ -19,6 +19,7 @@
+ /* This file defines some things that for the dynamic linker are defined in
+ rtld.c and dl-sysdep.c in ways appropriate to bootstrap dynamic linking. */
+
++#include <gnu/option-groups.h>
+ #include <errno.h>
+ #include <libintl.h>
+ #include <stdlib.h>
+@@ -42,7 +43,9 @@
+ const char *_dl_platform;
+ size_t _dl_platformlen;
+
++#if __OPTION_EGLIBC_RTLD_DEBUG
+ int _dl_debug_mask;
++#endif
+ int _dl_lazy;
+ ElfW(Addr) _dl_use_load_bias = -2;
+ int _dl_dynamic_weak;
+diff -Naur glibc-2.20/elf/Makefile glibc-2.20-patch/elf/Makefile
+--- glibc-2.20/elf/Makefile 2014-09-07 03:09:09.000000000 -0500
++++ glibc-2.20-patch/elf/Makefile 2015-03-04 00:51:32.369952006 -0600
+@@ -17,6 +17,8 @@
+
+ # Makefile for elf subdirectory of GNU C Library.
+
++include ../option-groups.mak
++
+ subdir := elf
+
+ include ../Makeconfig
+@@ -144,10 +146,11 @@
+ unload3 unload4 unload5 unload6 unload7 unload8 tst-global1 order2 \
+ tst-audit1 tst-audit2 tst-audit8 tst-audit9 \
+ tst-stackguard1 tst-addr1 tst-thrlock \
+- tst-unique1 tst-unique2 tst-unique3 tst-unique4 \
++ tst-unique1 tst-unique2 \
+ tst-initorder tst-initorder2 tst-relsort1 tst-null-argv \
+ tst-ptrguard1
+ # reldep9
++tests-$(OPTION_EGLIBC_CXX_TESTS) += tst-unique3 tst-unique4
+ ifeq ($(build-hardcoded-path-in-tests),yes)
+ tests += tst-dlopen-aout
+ endif
+@@ -205,8 +208,6 @@
+ tst-unique1mod1 tst-unique1mod2 \
+ tst-unique2mod1 tst-unique2mod2 \
+ tst-auditmod9a tst-auditmod9b \
+- tst-unique3lib tst-unique3lib2 \
+- tst-unique4lib \
+ tst-initordera1 tst-initorderb1 \
+ tst-initordera2 tst-initorderb2 \
+ tst-initordera3 tst-initordera4 \
+@@ -214,6 +215,9 @@
+ tst-initorder2d \
+ tst-relsort1mod1 tst-relsort1mod2 tst-array2dep \
+ tst-array5dep tst-null-argv-lib
++ifeq (y,$(OPTION_EGLIBC_CXX_TESTS))
++modules-names += tst-unique3lib tst-unique3lib2 tst-unique4lib
++endif
+ ifeq (yesyes,$(have-fpie)$(build-shared))
+ modules-names += tst-piemod1
+ tests += tst-pie1 tst-pie2
+diff -Naur glibc-2.20/elf/rtld.c glibc-2.20-patch/elf/rtld.c
+--- glibc-2.20/elf/rtld.c 2015-03-04 00:49:59.303952005 -0600
++++ glibc-2.20-patch/elf/rtld.c 2015-03-04 00:51:32.369952006 -0600
+@@ -16,6 +16,7 @@
+ License along with the GNU C Library; if not, see
+ <http://www.gnu.org/licenses/>. */
+
++#include <gnu/option-groups.h>
+ #include <errno.h>
+ #include <dlfcn.h>
+ #include <fcntl.h>
+@@ -2200,6 +2201,7 @@
+ objname, errstring);
+ }
+
++#if __OPTION_EGLIBC_RTLD_DEBUG
+ /* Nonzero if any of the debugging options is enabled. */
+ static int any_debug attribute_relro;
+
+@@ -2309,6 +2311,7 @@
+ _exit (0);
+ }
+ }
++#endif /* __OPTION_EGLIBC_RTLD_DEBUG */
+
+ static void
+ process_dl_audit (char *str)
+@@ -2376,12 +2379,14 @@
+ break;
+
+ case 5:
++#if __OPTION_EGLIBC_RTLD_DEBUG
+ /* Debugging of the dynamic linker? */
+ if (memcmp (envline, "DEBUG", 5) == 0)
+ {
+ process_dl_debug (&envline[6]);
+ break;
+ }
++#endif
+ if (memcmp (envline, "AUDIT", 5) == 0)
+ process_dl_audit (&envline[6]);
+ break;
+@@ -2490,7 +2495,9 @@
+ {
+ mode = trace;
+ GLRO(dl_verbose) = 1;
++#if __OPTION_EGLIBC_RTLD_DEBUG
+ GLRO_dl_debug_mask |= DL_DEBUG_PRELINK;
++#endif
+ GLRO(dl_trace_prelink) = &envline[17];
+ }
+ break;
+@@ -2537,12 +2544,15 @@
+ if (__access ("/etc/suid-debug", F_OK) != 0)
+ {
+ unsetenv ("MALLOC_CHECK_");
++#if __OPTION_EGLIBC_RTLD_DEBUG
+ GLRO_dl_debug_mask = 0;
++#endif
+ }
+
+ if (mode != normal)
+ _exit (5);
+ }
++#if __OPTION_EGLIBC_RTLD_DEBUG
+ /* If we have to run the dynamic linker in debugging mode and the
+ LD_DEBUG_OUTPUT environment variable is given, we write the debug
+ messages to this file. */
+@@ -2567,6 +2577,7 @@
+ /* We use standard output if opening the file failed. */
+ GLRO(dl_debug_fd) = STDOUT_FILENO;
+ }
++#endif /* __OPTION_EGLIBC_RTLD_DEBUG */
+ }
+
+
+diff -Naur glibc-2.20/extra-lib.mk glibc-2.20-patch/extra-lib.mk
+--- glibc-2.20/extra-lib.mk 2014-09-07 03:09:09.000000000 -0500
++++ glibc-2.20-patch/extra-lib.mk 2015-03-04 00:51:32.370952006 -0600
+@@ -25,7 +25,9 @@
+ extra-objs := $(extra-objs)
+
+ # The modules that go in $(lib).
+-all-$(lib)-routines := $($(lib)-routines) $($(lib)-sysdep_routines)
++all-$(lib)-routines := $($(lib)-routines) \
++ $($(lib)-routines-y) \
++ $($(lib)-sysdep_routines)
+
+ # Add each flavor of library to the lists of things to build and install.
+ install-lib += $(foreach o,$(object-suffixes-$(lib)),$(lib:lib%=$(libtype$o)))
+@@ -101,7 +103,7 @@
+ endif
+
+ # This will define `libof-ROUTINE := LIB' for each of the routines.
+-cpp-srcs-left := $($(lib)-routines) $($(lib)-sysdep_routines)
++cpp-srcs-left := $(all-$(lib)-routines)
+ ifneq (,$(cpp-srcs-left))
+ include $(patsubst %,$(..)cppflags-iterator.mk,$(cpp-srcs-left))
+ endif
+diff -Naur glibc-2.20/grp/Makefile glibc-2.20-patch/grp/Makefile
+--- glibc-2.20/grp/Makefile 2014-09-07 03:09:09.000000000 -0500
++++ glibc-2.20-patch/grp/Makefile 2015-03-04 00:51:32.370952006 -0600
+@@ -18,6 +18,8 @@
+ #
+ # Sub-makefile for grp portion of the library.
+ #
++include ../option-groups.mak
++
+ subdir := grp
+
+ include ../Makeconfig
+@@ -29,6 +31,9 @@
+ getgrent_r getgrgid_r getgrnam_r fgetgrent_r
+
+ tests := testgrp
++ifneq (y,$(OPTION_EGLIBC_NSSWITCH))
++LDLIBS-testgrp += $(shell cat $(common-objpfx)nss/fixed-nsswitch-libs)
++endif
+
+ ifeq (yes,$(build-shared))
+ test-srcs := tst_fgetgrent
+diff -Naur glibc-2.20/hesiod/Makefile glibc-2.20-patch/hesiod/Makefile
+--- glibc-2.20/hesiod/Makefile 2014-09-07 03:09:09.000000000 -0500
++++ glibc-2.20-patch/hesiod/Makefile 2015-03-04 00:51:32.370952006 -0600
+@@ -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 -Naur glibc-2.20/iconv/gconv_db.c glibc-2.20-patch/iconv/gconv_db.c
+--- glibc-2.20/iconv/gconv_db.c 2014-09-07 03:09:09.000000000 -0500
++++ glibc-2.20-patch/iconv/gconv_db.c 2015-03-04 00:51:32.370952006 -0600
+@@ -25,6 +25,7 @@
+ #include <sys/param.h>
+ #include <bits/libc-lock.h>
+ #include <locale/localeinfo.h>
++#include <gnu/option-groups.h>
+
+ #include <dlfcn.h>
+ #include <gconv_int.h>
+@@ -828,9 +829,11 @@
+ /* Free all resources if necessary. */
+ libc_freeres_fn (free_mem)
+ {
++#if __OPTION_EGLIBC_LOCALE_CODE
+ /* First free locale memory. This needs to be done before freeing derivations,
+ as ctype cleanup functions dereference steps arrays which we free below. */
+ _nl_locale_subfreeres ();
++#endif
+
+ /* finddomain.c has similar problem. */
+ extern void _nl_finddomain_subfreeres (void) attribute_hidden;
+diff -Naur glibc-2.20/iconv/gconv_trans.c glibc-2.20-patch/iconv/gconv_trans.c
+--- glibc-2.20/iconv/gconv_trans.c 2014-09-07 03:09:09.000000000 -0500
++++ glibc-2.20-patch/iconv/gconv_trans.c 2015-03-04 00:51:32.370952006 -0600
+@@ -23,6 +23,7 @@
+ #include <stdint.h>
+ #include <string.h>
+ #include <stdlib.h>
++#include <gnu/option-groups.h>
+
+ #include <bits/libc-lock.h>
+ #include "gconv_int.h"
+@@ -59,6 +60,7 @@
+ PTR_DEMANGLE (fct);
+ #endif
+
++#if __OPTION_EGLIBC_LOCALE_CODE
+ /* If there is no transliteration information in the locale don't do
+ anything and return the error. */
+ size = _NL_CURRENT_WORD (LC_CTYPE, _NL_CTYPE_TRANSLIT_TAB_SIZE);
+@@ -194,6 +196,7 @@
+ sorted. */
+ break;
+ }
++#endif
+
+ /* One last chance: use the default replacement. */
+ if (_NL_CURRENT_WORD (LC_CTYPE, _NL_CTYPE_TRANSLIT_DEFAULT_MISSING_LEN) != 0)
+diff -Naur glibc-2.20/iconv/iconv_prog.c glibc-2.20-patch/iconv/iconv_prog.c
+--- glibc-2.20/iconv/iconv_prog.c 2014-09-07 03:09:09.000000000 -0500
++++ glibc-2.20-patch/iconv/iconv_prog.c 2015-03-04 00:51:32.371952006 -0600
+@@ -35,6 +35,7 @@
+ #ifdef _POSIX_MAPPED_FILES
+ # include <sys/mman.h>
+ #endif
++#include <gnu/option-groups.h>
+ #include <charmap.h>
+ #include <gconv_int.h>
+ #include "iconv_prog.h"
+@@ -221,10 +222,17 @@
+ bool to_wrong =
+ (iconv_open (to_code, "UTF-8") == (iconv_t) -1
+ && errno == EINVAL);
++#if __OPTION_EGLIBC_LOCALE_CODE
+ const char *from_pretty =
+ (from_code[0] ? from_code : nl_langinfo (CODESET));
+ const char *to_pretty =
+ (orig_to_code[0] ? orig_to_code : nl_langinfo (CODESET));
++#else
++ const char *from_pretty =
++ (from_code[0] ? from_code : "ANSI_X3.4-1968");
++ const char *to_pretty =
++ (orig_to_code[0] ? orig_to_code : "ANSI_X3.4-1968");
++#endif
+
+ if (from_wrong)
+ {
+diff -Naur glibc-2.20/iconv/Makefile glibc-2.20-patch/iconv/Makefile
+--- glibc-2.20/iconv/Makefile 2014-09-07 03:09:09.000000000 -0500
++++ glibc-2.20-patch/iconv/Makefile 2015-03-04 00:51:32.371952006 -0600
+@@ -18,6 +18,8 @@
+ #
+ # Makefile for iconv.
+ #
++include ../option-groups.mak
++
+ subdir := iconv
+
+ include ../Makeconfig
+@@ -57,6 +59,9 @@
+ CPPFLAGS-strtab = -DNOT_IN_libc
+ CPPFLAGS-charmap = -DNOT_IN_libc
+ CPPFLAGS-charmap-dir = -DNOT_IN_libc
++ifneq (y,$(OPTION_EGLIBC_SPAWN))
++CPPFLAGS-charmap-dir.c += -DNO_UNCOMPRESS
++endif
+
+ ifeq ($(run-built-tests),yes)
+ xtests-special += $(objpfx)test-iconvconfig.out
+diff -Naur glibc-2.20/iconvdata/Makefile glibc-2.20-patch/iconvdata/Makefile
+--- glibc-2.20/iconvdata/Makefile 2014-09-07 03:09:09.000000000 -0500
++++ glibc-2.20-patch/iconvdata/Makefile 2015-03-04 00:51:32.371952006 -0600
+@@ -18,12 +18,15 @@
+ #
+ # Makefile for iconv data and code.
+ #
++include ../option-groups.mak
++
+ subdir := iconvdata
+
+ include ../Makeconfig
+
+ # Names of all the shared objects which implement the transformations.
+-modules := ISO8859-1 ISO8859-2 ISO8859-3 ISO8859-4 ISO8859-5 \
++modules-$(OPTION_EGLIBC_CHARSETS) \
++ := ISO8859-1 ISO8859-2 ISO8859-3 ISO8859-4 ISO8859-5 \
+ ISO8859-6 ISO8859-7 ISO8859-8 ISO8859-9 ISO8859-10 \
+ ISO8859-11 ISO8859-13 ISO8859-14 ISO8859-15 ISO8859-16 \
+ T.61 ISO_6937 SJIS KOI-8 HP-ROMAN8 HP-ROMAN9 EBCDIC-AT-DE \
+@@ -63,11 +66,13 @@
+ MAC-CENTRALEUROPE KOI8-RU ISO8859-9E \
+ CP770 CP771 CP772 CP773 CP774
+
+-modules.so := $(addsuffix .so, $(modules))
++modules.so := $(addsuffix .so, $(modules-y))
+
+ ifeq (yes,$(build-shared))
+ tests = bug-iconv1 bug-iconv2 tst-loading tst-e2big tst-iconv4 bug-iconv4 \
+- tst-iconv6 bug-iconv5 bug-iconv6 tst-iconv7 bug-iconv8 bug-iconv9
++ tst-iconv6 bug-iconv5 bug-iconv8 bug-iconv9
++tests-$(OPTION_EGLIBC_LOCALE_CODE) += bug-iconv6 tst-iconv7
++
+ ifeq ($(have-thread-library),yes)
+ tests += bug-iconv3
+ endif
+@@ -130,13 +135,13 @@
+ # Rule to generate the shared objects.
+ charmaps = ../localedata/charmaps
+ -include $(objpfx)iconv-rules
+-extra-modules-left := $(modules)
++extra-modules-left := $(modules-y)
+ include extra-module.mk
+
+
+ extra-objs += $(modules.so)
+-install-others = $(addprefix $(inst_gconvdir)/, $(modules.so)) \
+- $(inst_gconvdir)/gconv-modules
++install-others-y += $(addprefix $(inst_gconvdir)/, $(modules.so))
++install-others-$(OPTION_EGLIBC_CHARSETS) += $(inst_gconvdir)/gconv-modules
+
+ # We can build the conversion tables for numerous charsets automatically.
+
+@@ -204,7 +209,7 @@
+ ifndef avoid-generated
+ $(objpfx)iconv-rules: Makefile
+ $(make-target-directory)
+- { echo $(filter-out lib%, $(modules)); \
++ { echo $(filter-out lib%, $(modules-y)); \
+ echo 8bit $(gen-8bit-modules); \
+ echo 8bit-gap $(gen-8bit-gap-modules); } | \
+ LC_ALL=C \
+@@ -247,7 +252,7 @@
+ $(do-install-program)
+ $(inst_gconvdir)/gconv-modules: gconv-modules $(+force)
+ $(do-install)
+-ifeq (no,$(cross-compiling))
++# eglibc: ifeq (no,$(cross-compiling))
+ # Update the $(prefix)/lib/gconv/gconv-modules.cache file. This is necessary
+ # if this libc has more gconv modules than the previously installed one.
+ if test -f "$(inst_gconvdir)/gconv-modules.cache"; then \
+@@ -256,9 +261,9 @@
+ $(common-objpfx)iconv/iconvconfig \
+ $(addprefix --prefix=,$(install_root)); \
+ fi
+-else
+- @echo '*@*@*@ You should recreate $(inst_gconvdir)/gconv-modules.cache'
+-endif
++# eglibc: else
++# eglibc: @echo '*@*@*@ You should recreate $(inst_gconvdir)/gconv-modules.cache'
++# eglibc: endif
+
+ endif # build-shared = yes
+
+diff -Naur glibc-2.20/include/libc-symbols.h glibc-2.20-patch/include/libc-symbols.h
+--- glibc-2.20/include/libc-symbols.h 2014-09-07 03:09:09.000000000 -0500
++++ glibc-2.20-patch/include/libc-symbols.h 2015-03-04 00:51:32.371952006 -0600
+@@ -60,8 +60,7 @@
+ /* Define these macros for the benefit of portable GNU code that wants to check
+ them. Of course, STDC_HEADERS is never false when building libc! */
+ #define STDC_HEADERS 1
+-#define HAVE_MBSTATE_T 1
+-#define HAVE_MBSRTOWCS 1
++
+ #define HAVE_LIBINTL_H 1
+ #define HAVE_WCTYPE_H 1
+ #define HAVE_ISWCTYPE 1
+diff -Naur glibc-2.20/include/netdb.h glibc-2.20-patch/include/netdb.h
+--- glibc-2.20/include/netdb.h 2014-09-07 03:09:09.000000000 -0500
++++ glibc-2.20-patch/include/netdb.h 2015-03-04 00:51:32.372952006 -0600
+@@ -232,6 +232,10 @@
+ (const char *name, int af, struct hostent *host, \
+ char *buffer, size_t buflen, int *errnop, \
+ int *h_errnop); \
++extern enum nss_status _nss_ ## service ## _gethostbyname3_r \
++ (const char *name, int af, struct hostent *result, \
++ char *buffer, size_t buflen, int *errnop, \
++ int *h_errnop, int32_t *ttlp, char **canonp); \
+ extern enum nss_status _nss_ ## service ## _gethostbyname_r \
+ (const char *name, struct hostent *host, char *buffer, \
+ size_t buflen, int *errnop, int *h_errnop); \
+diff -Naur glibc-2.20/inet/Makefile glibc-2.20-patch/inet/Makefile
+--- glibc-2.20/inet/Makefile 2014-09-07 03:09:09.000000000 -0500
++++ glibc-2.20-patch/inet/Makefile 2015-03-04 00:51:32.372952006 -0600
+@@ -18,6 +18,8 @@
+ #
+ # Sub-makefile for inet portion of the library.
+ #
++include ../option-groups.mak
++
+ subdir := inet
+
+ include ../Makeconfig
+@@ -27,7 +29,8 @@
+ netinet/tcp.h netinet/ip.h $(wildcard arpa/*.h protocols/*.h) \
+ aliases.h ifaddrs.h netinet/ip6.h netinet/icmp6.h bits/in.h
+
+-routines := htonl htons \
++routines-$(OPTION_EGLIBC_INET) \
++ += htonl htons \
+ inet_lnaof inet_mkadr \
+ inet_netof inet_ntoa inet_net herrno herrno-loc \
+ gethstbyad gethstbyad_r gethstbynm gethstbynm2 gethstbynm2_r \
+@@ -41,18 +44,23 @@
+ getrpcent_r getrpcbyname_r getrpcbynumber_r \
+ ether_aton ether_aton_r ether_hton ether_line \
+ ether_ntoa ether_ntoa_r ether_ntoh \
+- rcmd rexec ruserpass \
+ getnetgrent_r getnetgrent \
+- getaliasent_r getaliasent getaliasname getaliasname_r \
+- in6_addr getnameinfo if_index ifaddrs inet6_option \
++ in6_addr getnameinfo if_index ifaddrs \
+ getipv4sourcefilter setipv4sourcefilter \
+- getsourcefilter setsourcefilter inet6_opt inet6_rth
++ getsourcefilter setsourcefilter
++routines-$(OPTION_EGLIBC_RCMD) \
++ += rcmd rexec ruserpass
++routines-$(OPTION_EGLIBC_DB_ALIASES) \
++ += getaliasent_r getaliasent getaliasname getaliasname_r
++routines-$(OPTION_EGLIBC_ADVANCED_INET6) \
++ += inet6_option inet6_opt inet6_rth
+
+-aux := check_pf check_native ifreq
++aux-$(OPTION_EGLIBC_INET) += check_pf check_native ifreq
+
+ tests := htontest test_ifindex tst-ntoa tst-ether_aton tst-network \
+- tst-gethnm test-ifaddrs bug-if1 test-inet6_opt tst-ether_line \
++ tst-gethnm test-ifaddrs bug-if1 tst-ether_line \
+ tst-getni1 tst-getni2 tst-inet6_rth tst-checks
++tests-$(OPTION_EGLIBC_ADVANCED_INET6) += test-inet6_opt
+
+ include ../Rules
+
+diff -Naur glibc-2.20/intl/dcigettext.c glibc-2.20-patch/intl/dcigettext.c
+--- glibc-2.20/intl/dcigettext.c 2014-09-07 03:09:09.000000000 -0500
++++ glibc-2.20-patch/intl/dcigettext.c 2015-03-04 00:51:32.372952006 -0600
+@@ -77,6 +77,10 @@
+ #endif
+ #include "hash-string.h"
+
++#ifdef _LIBC
++# include <gnu/option-groups.h>
++#endif
++
+ /* Thread safetyness. */
+ #ifdef _LIBC
+ # include <bits/libc-lock.h>
+@@ -449,9 +453,11 @@
+ #endif
+
+ #ifdef _LIBC
++#if __OPTION_EGLIBC_LOCALE_CODE
+ __libc_rwlock_define (extern, __libc_setlocale_lock attribute_hidden)
+ __libc_rwlock_rdlock (__libc_setlocale_lock);
+ #endif
++#endif
+
+ __libc_rwlock_rdlock (_nl_state_lock);
+
+@@ -470,7 +476,11 @@
+ search.category = category;
+ # ifdef HAVE_PER_THREAD_LOCALE
+ # ifdef _LIBC
++# if __OPTION_EGLIBC_LOCALE_CODE
+ localename = strdupa (__current_locale_name (category));
++# else
++ localename = "C";
++# endif
+ # endif
+ search.localename = localename;
+ # endif
+@@ -494,7 +504,9 @@
+ retval = (char *) (*foundp)->translation;
+
+ # ifdef _LIBC
++#if __OPTION_EGLIBC_LOCALE_CODE
+ __libc_rwlock_unlock (__libc_setlocale_lock);
++#endif
+ # endif
+ __libc_rwlock_unlock (_nl_state_lock);
+ return retval;
+@@ -611,7 +623,9 @@
+ {
+ no_translation:
+ FREE_BLOCKS (block_list);
++#if __OPTION_EGLIBC_LOCALE_CODE
+ __libc_rwlock_unlock (__libc_setlocale_lock);
++#endif
+ __libc_rwlock_unlock (_nl_state_lock);
+ __set_errno (saved_errno);
+ return (plural == 0
+@@ -730,7 +744,9 @@
+ if (plural)
+ retval = plural_lookup (domain, n, retval, retlen);
+
++#if __OPTION_EGLIBC_LOCALE_CODE
+ __libc_rwlock_unlock (__libc_setlocale_lock);
++#endif
+ __libc_rwlock_unlock (_nl_state_lock);
+ return retval;
+ }
+@@ -1361,7 +1377,11 @@
+ `LC_xxx', and `LANG'. On some systems this can be done by the
+ `setlocale' function itself. */
+ #ifdef _LIBC
++# if __OPTION_EGLIBC_LOCALE_CODE
+ retval = __current_locale_name (category);
++# else
++ retval = "C";
++# endif
+ #else
+ retval = _nl_locale_name (category, categoryname);
+ #endif
+diff -Naur glibc-2.20/intl/Makefile glibc-2.20-patch/intl/Makefile
+--- glibc-2.20/intl/Makefile 2014-09-07 03:09:09.000000000 -0500
++++ glibc-2.20-patch/intl/Makefile 2015-03-04 00:51:32.372952006 -0600
+@@ -16,6 +16,7 @@
+ # <http://www.gnu.org/licenses/>.
+
+ # Makefile for intl subdirectory: message handling code from GNU gettext.
++include ../option-groups.mak
+
+ subdir = intl
+
+@@ -48,7 +49,7 @@
+ $(objpfx)plural.o: plural.c
+
+ ifeq ($(run-built-tests),yes)
+-ifeq (yes,$(build-shared))
++ifeq (yyyes,$(OPTION_EGLIBC_LOCALES)$(OPTION_EGLIBC_LOCALE_CODE)$(build-shared))
+ ifneq ($(strip $(MSGFMT)),:)
+ tests-special += $(objpfx)tst-translit.out $(objpfx)tst-gettext.out \
+ $(objpfx)tst-gettext2.out $(objpfx)tst-codeset.out \
+diff -Naur glibc-2.20/io/Makefile glibc-2.20-patch/io/Makefile
+--- glibc-2.20/io/Makefile 2014-09-07 03:09:09.000000000 -0500
++++ glibc-2.20-patch/io/Makefile 2015-03-04 00:51:32.372952006 -0600
+@@ -18,6 +18,8 @@
+ #
+ # Sub-makefile for I/O portion of the library.
+ #
++include ../option-groups.mak
++
+ subdir := io
+
+ include ../Makeconfig
+@@ -36,7 +38,7 @@
+ fxstatat fxstatat64 \
+ statfs fstatfs statfs64 fstatfs64 \
+ statvfs fstatvfs statvfs64 fstatvfs64 \
+- umask chmod fchmod lchmod fchmodat \
++ umask chmod fchmod fchmodat \
+ mkdir mkdirat \
+ open open_2 open64 open64_2 openat openat_2 openat64 openat64_2 \
+ read write lseek lseek64 access euidaccess faccessat \
+@@ -49,11 +51,13 @@
+ ttyname ttyname_r isatty \
+ link linkat symlink symlinkat readlink readlinkat \
+ unlink unlinkat rmdir \
+- ftw ftw64 fts poll ppoll \
++ poll ppoll \
+ posix_fadvise posix_fadvise64 \
+ posix_fallocate posix_fallocate64 \
+ sendfile sendfile64 \
+ utimensat futimens
++routines-$(OPTION_EGLIBC_BSD) += lchmod
++routines-$(OPTION_EGLIBC_FTRAVERSE) += ftw ftw64 fts
+
+ aux := have_o_cloexec
+
+@@ -64,18 +68,22 @@
+ fstatat fstatat64 mknod mknodat
+
+ others := pwd
+-test-srcs := ftwtest
++test-srcs-$(OPTION_EGLIBC_FTRAVERSE) := ftwtest
+ tests := test-utime test-stat test-stat2 test-lfs tst-getcwd \
+- tst-fcntl bug-ftw1 bug-ftw2 bug-ftw3 bug-ftw4 tst-statvfs \
++ tst-fcntl tst-statvfs \
+ tst-openat tst-unlinkat tst-fstatat tst-futimesat \
+ tst-renameat tst-fchownat tst-fchmodat tst-faccessat \
+ tst-symlinkat tst-linkat tst-readlinkat tst-mkdirat \
+- tst-mknodat tst-mkfifoat tst-ttyname_r bug-ftw5 \
++ tst-mknodat tst-mkfifoat tst-ttyname_r \
+ tst-posix_fallocate
++tests-$(OPTION_EGLIBC_FTRAVERSE) += bug-ftw1 bug-ftw2 bug-ftw3 bug-ftw4 \
++ bug-ftw5
+
+ ifeq ($(run-built-tests),yes)
++ifeq (y,$(OPTION_EGLIBC_FTRAVERSE))
+ tests-special += $(objpfx)ftwtest.out
+ endif
++endif
+
+ include ../Rules
+
+diff -Naur glibc-2.20/libidn/Makefile glibc-2.20-patch/libidn/Makefile
+--- glibc-2.20/libidn/Makefile 2014-09-07 03:09:09.000000000 -0500
++++ glibc-2.20-patch/libidn/Makefile 2015-03-04 00:51:32.372952006 -0600
+@@ -16,6 +16,7 @@
+ # <http://www.gnu.org/licenses/>.
+
+ # Makefile for libidn subdirectory of GNU C Library.
++include ../option-groups.mak
+
+ subdir := libidn
+
+@@ -23,8 +24,8 @@
+
+ routines = idn-stub
+
+-extra-libs = libcidn
+-extra-libs-others = $(extra-libs)
++extra-libs-$(OPTION_EGLIBC_IDN) = libcidn
++extra-libs-others-y = $(extra-libs-y)
+
+ libcidn-routines := punycode toutf8 nfkc stringprep rfc3454 profiles idna \
+ iconvme
+diff -Naur glibc-2.20/libidn/toutf8.c glibc-2.20-patch/libidn/toutf8.c
+--- glibc-2.20/libidn/toutf8.c 2014-09-07 03:09:09.000000000 -0500
++++ glibc-2.20-patch/libidn/toutf8.c 2015-03-04 00:51:32.373952006 -0600
+@@ -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 -Naur glibc-2.20/libio/fileops.c glibc-2.20-patch/libio/fileops.c
+--- glibc-2.20/libio/fileops.c 2014-09-07 03:09:09.000000000 -0500
++++ glibc-2.20-patch/libio/fileops.c 2015-03-04 00:51:32.373952006 -0600
+@@ -38,6 +38,7 @@
+ #include <string.h>
+ #include <errno.h>
+ #include <unistd.h>
++#include <gnu/option-groups.h>
+ #include <stdlib.h>
+ #if _LIBC
+ # include "../wcsmbs/wcsmbsload.h"
+@@ -174,7 +175,7 @@
+
+ /* Free buffer. */
+ #if defined _LIBC || defined _GLIBCPP_USE_WCHAR_T
+- if (fp->_mode > 0)
++ if (_IO_is_wide (fp))
+ {
+ if (_IO_have_wbackup (fp))
+ _IO_free_wbackup_area (fp);
+@@ -359,6 +360,7 @@
+ cs = strstr (last_recognized + 1, ",ccs=");
+ if (cs != NULL)
+ {
++#if __OPTION_POSIX_WIDE_CHAR_DEVICE_IO
+ /* Yep. Load the appropriate conversions and set the orientation
+ to wide. */
+ struct gconv_fcts fcts;
+@@ -423,6 +425,12 @@
+
+ /* Set the mode now. */
+ result->_mode = 1;
++#else
++ /* Treat this as if we couldn't find the given character set. */
++ (void) _IO_file_close_it (fp);
++ __set_errno (EINVAL);
++ return NULL;
++#endif
+ }
+ }
+
+diff -Naur glibc-2.20/libio/__fpurge.c glibc-2.20-patch/libio/__fpurge.c
+--- glibc-2.20/libio/__fpurge.c 2014-09-07 03:09:09.000000000 -0500
++++ glibc-2.20-patch/libio/__fpurge.c 2015-03-04 00:51:32.373952006 -0600
+@@ -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 -Naur glibc-2.20/libio/iofwide.c glibc-2.20-patch/libio/iofwide.c
+--- glibc-2.20/libio/iofwide.c 2014-09-07 03:09:09.000000000 -0500
++++ glibc-2.20-patch/libio/iofwide.c 2015-03-04 00:51:32.373952006 -0600
+@@ -26,6 +26,7 @@
+
+ #include <libioP.h>
+ #ifdef _LIBC
++# include <gnu/option-groups.h>
+ # include <dlfcn.h>
+ # include <wchar.h>
+ #endif
+@@ -43,6 +44,8 @@
+ #endif
+
+
++#if ! defined _LIBC || __OPTION_POSIX_C_LANG_WIDE_CHAR
++
+ /* Prototypes of libio's codecvt functions. */
+ static enum __codecvt_result do_out (struct _IO_codecvt *codecvt,
+ __mbstate_t *statep,
+@@ -513,3 +516,26 @@
+ return MB_CUR_MAX;
+ #endif
+ }
++
++#else
++/* OPTION_POSIX_C_LANG_WIDE_CHAR is disabled. */
++
++#undef _IO_fwide
++int
++_IO_fwide (fp, mode)
++ _IO_FILE *fp;
++ int mode;
++{
++ /* Die helpfully if the user tries to create a wide stream; I
++ disbelieve that most users check the return value from
++ 'fwide (fp, 1)'. */
++ assert (mode <= 0);
++
++ /* We can only make streams byte-oriented, which is trivial. */
++ if (mode < 0)
++ fp->_mode = -1;
++
++ return fp->_mode;
++}
++
++#endif
+diff -Naur glibc-2.20/libio/ioseekoff.c glibc-2.20-patch/libio/ioseekoff.c
+--- glibc-2.20/libio/ioseekoff.c 2014-09-07 03:09:09.000000000 -0500
++++ glibc-2.20-patch/libio/ioseekoff.c 2015-03-04 00:51:32.373952006 -0600
+@@ -60,7 +60,7 @@
+ else
+ abort ();
+ }
+- if (_IO_fwide (fp, 0) < 0)
++ if (! _IO_is_wide (fp))
+ _IO_free_backup_area (fp);
+ else
+ _IO_free_wbackup_area (fp);
+diff -Naur glibc-2.20/libio/ioseekpos.c glibc-2.20-patch/libio/ioseekpos.c
+--- glibc-2.20/libio/ioseekpos.c 2014-09-07 03:09:09.000000000 -0500
++++ glibc-2.20-patch/libio/ioseekpos.c 2015-03-04 00:51:32.374952006 -0600
+@@ -35,7 +35,7 @@
+ /* If we have a backup buffer, get rid of it, since the __seekoff
+ callback may not know to do the right thing about it.
+ This may be over-kill, but it'll do for now. TODO */
+- if (_IO_fwide (fp, 0) <= 0)
++ if (! _IO_is_wide (fp))
+ {
+ if (_IO_have_backup (fp))
+ _IO_free_backup_area (fp);
+diff -Naur glibc-2.20/libio/iosetbuffer.c glibc-2.20-patch/libio/iosetbuffer.c
+--- glibc-2.20/libio/iosetbuffer.c 2014-09-07 03:09:09.000000000 -0500
++++ glibc-2.20-patch/libio/iosetbuffer.c 2015-03-04 00:51:32.374952006 -0600
+@@ -24,6 +24,8 @@
+ This exception applies to code released by its copyright holders
+ in files containing the exception. */
+
++#include <gnu/option-groups.h>
++
+ #include "libioP.h"
+
+ void
+@@ -38,9 +40,11 @@
+ if (!buf)
+ size = 0;
+ (void) _IO_SETBUF (fp, buf, size);
++#if __OPTION_POSIX_C_LANG_WIDE_CHAR
+ if (_IO_vtable_offset (fp) == 0 && fp->_mode == 0 && _IO_CHECK_WIDE (fp))
+ /* We also have to set the buffer using the wide char function. */
+ (void) _IO_WSETBUF (fp, buf, size);
++#endif /* __OPTION_POSIX_C_LANG_WIDE_CHAR */
+ _IO_release_lock (fp);
+ }
+ libc_hidden_def (_IO_setbuffer)
+diff -Naur glibc-2.20/libio/libioP.h glibc-2.20-patch/libio/libioP.h
+--- glibc-2.20/libio/libioP.h 2014-09-07 03:09:09.000000000 -0500
++++ glibc-2.20-patch/libio/libioP.h 2015-03-04 00:51:32.374952006 -0600
+@@ -42,6 +42,10 @@
+ /*# include <comthread.h>*/
+ #endif
+
++#if defined _LIBC
++# include <gnu/option-groups.h>
++#endif
++
+ #include <math_ldbl_opt.h>
+
+ #include "iolibio.h"
+@@ -508,8 +512,20 @@
+
+
+ #if defined _LIBC || defined _GLIBCPP_USE_WCHAR_T
++
++/* _IO_is_wide (fp) is roughly equivalent to '_IO_fwide (fp, 0) > 0',
++ except that when OPTION_POSIX_C_LANG_WIDE_CHAR is disabled, it
++ expands to a constant, allowing the compiler to realize that it can
++ eliminate code that references wide stream handling functions.
++ This, in turn, allows us to omit them. */
++#if __OPTION_POSIX_C_LANG_WIDE_CHAR
++# define _IO_is_wide(_f) ((_f)->_mode > 0)
++#else
++# define _IO_is_wide(_f) (0)
++#endif
++
+ # define _IO_do_flush(_f) \
+- ((_f)->_mode <= 0 \
++ (! _IO_is_wide (_f) \
+ ? _IO_do_write(_f, (_f)->_IO_write_base, \
+ (_f)->_IO_write_ptr-(_f)->_IO_write_base) \
+ : _IO_wdo_write(_f, (_f)->_wide_data->_IO_write_base, \
+diff -Naur glibc-2.20/libio/Makefile glibc-2.20-patch/libio/Makefile
+--- glibc-2.20/libio/Makefile 2014-09-07 03:09:09.000000000 -0500
++++ glibc-2.20-patch/libio/Makefile 2015-03-04 00:51:32.375952006 -0600
+@@ -18,6 +18,8 @@
+ #
+ # Specific makefile for libio.
+ #
++include ../option-groups.mak
++
+ subdir := libio
+
+ include ../Makeconfig
+@@ -27,16 +29,13 @@
+
+ routines := \
+ filedoalloc iofclose iofdopen iofflush iofgetpos iofgets iofopen \
+- iofopncook iofputs iofread iofsetpos ioftell wfiledoalloc \
++ iofopncook iofputs iofread iofsetpos ioftell \
+ iofwrite iogetdelim iogetline iogets iopadn iopopen ioputs \
+ ioseekoff ioseekpos iosetbuffer iosetvbuf ioungetc \
+ iovsprintf iovsscanf \
+ iofgetpos64 iofopen64 iofsetpos64 \
+- fputwc fputwc_u getwc getwc_u getwchar getwchar_u iofgetws iofgetws_u \
+- iofputws iofputws_u iogetwline iowpadn ioungetwc putwc putwc_u \
+- putwchar putwchar_u putchar putchar_u fwprintf swprintf vwprintf \
+- wprintf wscanf fwscanf vwscanf vswprintf iovswscanf swscanf wgenops \
+- wstrops wfileops iofwide fwide wmemstream \
++ putchar putchar_u \
++ iofwide \
+ \
+ clearerr feof ferror fileno fputc freopen fseek getc getchar \
+ memstream pclose putc putchar rewind setbuf setlinebuf vasprintf \
+@@ -47,25 +46,48 @@
+ __fpurge __fpending __fsetlocking \
+ \
+ libc_fatal fmemopen
+-
+-tests = tst_swprintf tst_wprintf tst_swscanf tst_wscanf tst_getwc tst_putwc \
+- tst_wprintf2 tst-widetext test-fmemopen tst-ext tst-ext2 \
+- tst-fgetws tst-ungetwc1 tst-ungetwc2 tst-swscanf tst-sscanf \
+- tst-mmap-setvbuf bug-ungetwc1 bug-ungetwc2 tst-atime tst-eof \
+- tst-freopen bug-rewind bug-rewind2 bug-ungetc bug-fseek \
+- tst-mmap-eofsync tst-mmap-fflushsync bug-mmap-fflush \
+- tst-mmap2-eofsync tst-mmap-offend bug-fopena+ bug-wfflush \
+- bug-ungetc2 bug-ftell bug-ungetc3 bug-ungetc4 tst-fopenloc2 \
+- tst-memstream1 tst-memstream2 \
+- tst-wmemstream1 tst-wmemstream2 \
+- bug-memstream1 bug-wmemstream1 \
+- tst-setvbuf1 tst-popen1 tst-fgetwc bug-wsetpos tst-fseek \
+- tst-fwrite-error tst-ftell-partial-wide tst-ftell-active-handler \
+- tst-ftell-append
++routines-$(OPTION_POSIX_C_LANG_WIDE_CHAR) += \
++ wfiledoalloc \
++ iowpadn \
++ swprintf \
++ vswprintf iovswscanf swscanf wgenops \
++ wstrops wfileops wmemstream
++routines-$(call option-disabled, OPTION_POSIX_C_LANG_WIDE_CHAR) += \
++ wdummyfileops
++routines-$(OPTION_POSIX_WIDE_CHAR_DEVICE_IO) += \
++ fputwc fputwc_u getwc getwc_u getwchar getwchar_u iofgetws iofgetws_u \
++ iofputws iofputws_u iogetwline ioungetwc putwc putwc_u \
++ putwchar putwchar_u fwprintf vwprintf \
++ wprintf wscanf fwscanf vwscanf \
++ fwide
++
++tests = test-fmemopen tst-ext tst-ext2 \
++ tst-mmap-setvbuf tst-atime tst-eof \
++ tst-freopen bug-ungetc bug-fseek \
++ tst-mmap-eofsync tst-mmap-fflushsync bug-mmap-fflush \
++ tst-mmap2-eofsync tst-mmap-offend bug-fopena+ \
++ bug-ungetc2 bug-ungetc3 bug-ungetc4 \
++ tst-memstream1 tst-memstream2 \
++ bug-memstream1 tst-popen1 tst-fwrite-error \
++ tst-ftell-active-handler tst-ftell-append
++tests-$(OPTION_EGLIBC_LOCALE_CODE) \
++ += tst-swscanf tst-fgetws tst-setvbuf1 \
++ tst-ungetwc1 tst-ungetwc2 bug-ftell bug-ungetwc2 \
++ tst-widetext
++tests-$(OPTION_POSIX_WIDE_CHAR_DEVICE_IO) \
++ += bug-rewind bug-rewind2 bug-ungetwc1 \
++ bug-wfflush bug-wmemstream1 tst-fopenloc2 \
++ tst_getwc \
++ tst_putwc tst_wprintf tst_wprintf2 tst_wscanf \
++ tst-fgetwc bug-wsetpos tst-fseek tst-ftell-partial-wide
++tests-$(OPTION_POSIX_C_LANG_WIDE_CHAR) \
++ += tst_swprintf tst_swscanf \
++ tst-sscanf \
++ tst-wmemstream1 tst-wmemstream2
+ ifeq (yes,$(build-shared))
+ # Add test-fopenloc only if shared library is enabled since it depends on
+ # shared localedata objects.
+-tests += tst-fopenloc
++tests-$(OPTION_EGLIBC_LOCALE_CODE) += tst-fopenloc
+ endif
+ test-srcs = test-freopen
+
+@@ -164,13 +186,17 @@
+ oldiofsetpos64
+
+ ifeq ($(run-built-tests),yes)
++ifeq (y,$(OPTION_POSIX_WIDE_CHAR_DEVICE_IO))
+ tests-special += $(objpfx)test-freopen.out
++endif
++ifeq (y,$(OPTION_EGLIBC_LOCALE_CODE))
+ ifeq (yes,$(build-shared))
+ # Run tst-fopenloc-cmp.out and tst-openloc-mem.out only if shared
+ # library is enabled since they depend on tst-fopenloc.out.
+ tests-special += $(objpfx)tst-fopenloc-cmp.out $(objpfx)tst-fopenloc-mem.out
+ endif
+ endif
++endif
+
+ include ../Rules
+
+diff -Naur glibc-2.20/libio/wdummyfileops.c glibc-2.20-patch/libio/wdummyfileops.c
+--- glibc-2.20/libio/wdummyfileops.c 1969-12-31 18:00:00.000000000 -0600
++++ glibc-2.20-patch/libio/wdummyfileops.c 2015-03-04 00:51:32.375952006 -0600
+@@ -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 -Naur glibc-2.20/locale/catnames.c glibc-2.20-patch/locale/catnames.c
+--- glibc-2.20/locale/catnames.c 1969-12-31 18:00:00.000000000 -0600
++++ glibc-2.20-patch/locale/catnames.c 2015-03-04 00:51:32.375952006 -0600
+@@ -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 -Naur glibc-2.20/locale/C-ctype.c glibc-2.20-patch/locale/C-ctype.c
+--- glibc-2.20/locale/C-ctype.c 2014-09-07 03:09:09.000000000 -0500
++++ glibc-2.20-patch/locale/C-ctype.c 2015-03-04 00:51:32.375952006 -0600
+@@ -19,8 +19,11 @@
+ #include "localeinfo.h"
+ #include <endian.h>
+ #include <stdint.h>
++#include <gnu/option-groups.h>
+
++#if __OPTION_EGLIBC_LOCALE_CODE
+ #include "C-translit.h"
++#endif
+
+ /* This table's entries are taken from POSIX.2 Table 2-6
+ ``LC_CTYPE Category Definition in the POSIX Locale''.
+@@ -647,6 +650,7 @@
+ { .word = L'7' },
+ { .word = L'8' },
+ { .word = L'9' },
++#if __OPTION_EGLIBC_LOCALE_CODE
+ /* _NL_CTYPE_TRANSLIT_TAB_SIZE */
+ { .word = NTRANSLIT },
+ /* _NL_CTYPE_TRANSLIT_FROM_IDX */
+@@ -657,6 +661,22 @@
+ { .wstr = translit_to_idx },
+ /* _NL_CTYPE_TRANSLIT_TO_TBL */
+ { .wstr = (uint32_t *) translit_to_tbl },
++#else
++ /* If the locale code isn't enabled, we don't have the
++ transliteration code in iconv/gconv_trans.c anyway, so there's
++ no need for the transliteration tables here. We'll fall back
++ on the default missing replacement, '?'. */
++ /* _NL_CTYPE_TRANSLIT_TAB_SIZE */
++ { .word = 0 },
++ /* _NL_CTYPE_TRANSLIT_FROM_IDX */
++ { .wstr = NULL },
++ /* _NL_CTYPE_TRANSLIT_FROM_TBL */
++ { .wstr = NULL },
++ /* _NL_CTYPE_TRANSLIT_TO_IDX */
++ { .wstr = NULL },
++ /* _NL_CTYPE_TRANSLIT_TO_TBL */
++ { .wstr = NULL },
++#endif
+ /* _NL_CTYPE_TRANSLIT_DEFAULT_MISSING_LEN */
+ { .word = 1 },
+ /* _NL_CTYPE_TRANSLIT_DEFAULT_MISSING */
+diff -Naur glibc-2.20/locale/dummy-setlocale.c glibc-2.20-patch/locale/dummy-setlocale.c
+--- glibc-2.20/locale/dummy-setlocale.c 1969-12-31 18:00:00.000000000 -0600
++++ glibc-2.20-patch/locale/dummy-setlocale.c 2015-03-04 00:51:32.375952006 -0600
+@@ -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 -Naur glibc-2.20/locale/localeinfo.h glibc-2.20-patch/locale/localeinfo.h
+--- glibc-2.20/locale/localeinfo.h 2014-09-07 03:09:09.000000000 -0500
++++ glibc-2.20-patch/locale/localeinfo.h 2015-03-04 00:51:32.375952006 -0600
+@@ -224,7 +224,7 @@
+ unused. We can manage this playing some tricks with weak references.
+ But with thread-local locale settings, it becomes quite ungainly unless
+ we can use __thread variables. So only in that case do we attempt this. */
+-#ifndef SHARED
++#if !defined SHARED && !defined IN_GLIBC_LOCALEDEF
+ # include <tls.h>
+ # define NL_CURRENT_INDIRECT 1
+ #endif
+diff -Naur glibc-2.20/locale/Makefile glibc-2.20-patch/locale/Makefile
+--- glibc-2.20/locale/Makefile 2014-09-07 03:09:09.000000000 -0500
++++ glibc-2.20-patch/locale/Makefile 2015-03-04 00:51:32.375952006 -0600
+@@ -18,27 +18,43 @@
+ #
+ # Makefile for locales.
+ #
++include ../option-groups.mak
++
+ subdir := locale
+
+ include ../Makeconfig
+
+ headers = locale.h bits/locale.h langinfo.h xlocale.h
+-routines = setlocale findlocale loadlocale loadarchive \
+- localeconv nl_langinfo nl_langinfo_l mb_cur_max \
+- newlocale duplocale freelocale uselocale
+-tests = tst-C-locale tst-locname tst-duplocale
++# catnames is needed by OPTION_EGLIBC_LOCALE_CODE and by the 'intl' code.
++# If we put the latter in an option group, too, we can omit catnames
++# when both option groups are disabled. libstdc++-v3 needs mb_cur_max.
++routines-y := catnames mb_cur_max
++routines-$(OPTION_EGLIBC_LOCALE_CODE) \
++ += setlocale findlocale loadlocale loadarchive \
++ localeconv nl_langinfo nl_langinfo_l \
++ newlocale duplocale freelocale uselocale
++ifneq (y,$(OPTION_EGLIBC_LOCALE_CODE))
++routines-y += dummy-setlocale
++endif
++tests-$(OPTION_EGLIBC_LOCALE_CODE) += tst-C-locale tst-locname tst-duplocale
+ categories = ctype messages monetary numeric time paper name \
+ address telephone measurement identification collate
+-aux = $(categories:%=lc-%) $(categories:%=C-%) SYS_libc C_name \
+- xlocale localename global-locale coll-lookup
+-others = localedef locale
++# C-messages belongs in an intl option group.
++aux-y := C-ctype C-time \
++ SYS_libc C_name xlocale global-locale coll-lookup
++aux-$(OPTION_EGLIBC_LOCALE_CODE) \
++ += $(filter-out $(aux-y), \
++ $(categories:%=lc-%) $(categories:%=C-%)) \
++ localename
++others-$(OPTION_EGLIBC_LOCALE_CODE) = localedef locale
+ #others-static = localedef locale
+-install-bin = localedef locale
+-extra-objs = $(localedef-modules:=.o) $(localedef-aux:=.o) \
++install-bin = $(others-y)
++extra-objs-$(OPTION_EGLIBC_LOCALE_CODE) \
++ = $(localedef-modules:=.o) $(localedef-aux:=.o) \
+ $(locale-modules:=.o) $(lib-modules:=.o)
+
+-extra-libs = libBrokenLocale
+-extra-libs-others = $(extra-libs)
++extra-libs-$(OPTION_EGLIBC_LOCALE_CODE) = libBrokenLocale
++extra-libs-others = $(extra-libs-y)
+
+ libBrokenLocale-routines = broken_cur_max
+
+@@ -94,6 +110,9 @@
+ CFLAGS-charmap.c = -Wno-write-strings -Wno-char-subscripts
+ CFLAGS-locfile.c = -Wno-write-strings -Wno-char-subscripts
+ CFLAGS-charmap-dir.c = -Wno-write-strings
++ifneq (y,$(OPTION_EGLIBC_SPAWN))
++CFLAGS-charmap-dir.c += -DNO_UNCOMPRESS
++endif
+
+ # This makes sure -DNOT_IN_libc et al are passed for all these modules.
+ cpp-srcs-left := $(addsuffix .c,$(localedef-modules) $(localedef-aux) \
+diff -Naur glibc-2.20/locale/programs/charmap-dir.c glibc-2.20-patch/locale/programs/charmap-dir.c
+--- glibc-2.20/locale/programs/charmap-dir.c 2014-09-07 03:09:09.000000000 -0500
++++ glibc-2.20-patch/locale/programs/charmap-dir.c 2015-03-04 00:51:32.376952006 -0600
+@@ -19,7 +19,9 @@
+ #include <error.h>
+ #include <fcntl.h>
+ #include <libintl.h>
++#ifndef NO_UNCOMPRESS
+ #include <spawn.h>
++#endif
+ #include <stdio.h>
+ #include <stdlib.h>
+ #include <string.h>
+@@ -156,6 +158,7 @@
+ return closedir (dir);
+ }
+
++#ifndef NO_UNCOMPRESS
+ /* Creates a subprocess decompressing the given pathname, and returns
+ a stream reading its output (the decompressed data). */
+ static
+@@ -204,6 +207,7 @@
+ }
+ return NULL;
+ }
++#endif
+
+ /* Opens a charmap for reading, given its name (not an alias name). */
+ FILE *
+@@ -226,6 +230,7 @@
+ if (stream != NULL)
+ return stream;
+
++#ifndef NO_UNCOMPRESS
+ memcpy (p, ".gz", 4);
+ stream = fopen_uncompressed (pathname, "gzip");
+ if (stream != NULL)
+@@ -235,6 +240,7 @@
+ stream = fopen_uncompressed (pathname, "bzip2");
+ if (stream != NULL)
+ return stream;
++#endif
+
+ return NULL;
+ }
+@@ -263,8 +269,8 @@
+ char *alias = NULL;
+ char junk[BUFSIZ];
+
+- if (fscanf (stream, " <code_set_name> %ms", &alias) == 1
+- || fscanf (stream, "%% alias %ms", &alias) == 1)
++ if (fscanf (stream, " <code_set_name> %as", &alias) == 1
++ || fscanf (stream, "%% alias %as", &alias) == 1)
+ {
+ aliases = (char **) xrealloc (aliases,
+ (naliases + 2) * sizeof (char *));
+diff -Naur glibc-2.20/locale/programs/ld-collate.c glibc-2.20-patch/locale/programs/ld-collate.c
+--- glibc-2.20/locale/programs/ld-collate.c 2014-09-07 03:09:09.000000000 -0500
++++ glibc-2.20-patch/locale/programs/ld-collate.c 2015-03-04 00:51:32.376952006 -0600
+@@ -350,7 +350,7 @@
+ }
+ if (wcs != NULL)
+ {
+- size_t nwcs = wcslen ((wchar_t *) wcs);
++ size_t nwcs = wcslen_uint32 (wcs);
+ uint32_t zero = 0;
+ /* Handle <U0000> as a single character. */
+ if (nwcs == 0)
+@@ -1776,8 +1776,7 @@
+
+ if ((*eptr)->nwcs == runp->nwcs)
+ {
+- int c = wmemcmp ((wchar_t *) (*eptr)->wcs,
+- (wchar_t *) runp->wcs, runp->nwcs);
++ int c = wmemcmp_uint32 ((*eptr)->wcs, runp->wcs, runp->nwcs);
+
+ if (c == 0)
+ {
+@@ -2010,9 +2009,9 @@
+ one consecutive entry. */
+ if (runp->wcnext != NULL
+ && runp->nwcs == runp->wcnext->nwcs
+- && wmemcmp ((wchar_t *) runp->wcs,
+- (wchar_t *)runp->wcnext->wcs,
+- runp->nwcs - 1) == 0
++ && wmemcmp_uint32 (runp->wcs,
++ runp->wcnext->wcs,
++ runp->nwcs - 1) == 0
+ && (runp->wcs[runp->nwcs - 1]
+ == runp->wcnext->wcs[runp->nwcs - 1] + 1))
+ {
+@@ -2036,9 +2035,9 @@
+ runp = runp->wcnext;
+ while (runp->wcnext != NULL
+ && runp->nwcs == runp->wcnext->nwcs
+- && wmemcmp ((wchar_t *) runp->wcs,
+- (wchar_t *)runp->wcnext->wcs,
+- runp->nwcs - 1) == 0
++ && wmemcmp_uint32 (runp->wcs,
++ runp->wcnext->wcs,
++ runp->nwcs - 1) == 0
+ && (runp->wcs[runp->nwcs - 1]
+ == runp->wcnext->wcs[runp->nwcs - 1] + 1));
+
+diff -Naur glibc-2.20/locale/programs/ld-ctype.c glibc-2.20-patch/locale/programs/ld-ctype.c
+--- glibc-2.20/locale/programs/ld-ctype.c 2014-09-07 03:09:09.000000000 -0500
++++ glibc-2.20-patch/locale/programs/ld-ctype.c 2015-03-04 00:51:32.377952006 -0600
+@@ -957,7 +957,7 @@
+ allocate_arrays (ctype, charmap, ctype->repertoire);
+
+ default_missing_len = (ctype->default_missing
+- ? wcslen ((wchar_t *) ctype->default_missing)
++ ? wcslen_uint32 (ctype->default_missing)
+ : 0);
+
+ init_locale_data (&file, nelems);
+@@ -1968,7 +1968,7 @@
+ ignore = 1;
+ else
+ /* This value is usable. */
+- obstack_grow (ob, to_wstr, wcslen ((wchar_t *) to_wstr) * 4);
++ obstack_grow (ob, to_wstr, wcslen_uint32 (to_wstr) * 4);
+
+ first = 0;
+ }
+@@ -2516,8 +2516,8 @@
+ }
+
+ handle_tok_digit:
+- class_bit = _ISwdigit;
+- class256_bit = _ISdigit;
++ class_bit = BITw (tok_digit);
++ class256_bit = BIT (tok_digit);
+ handle_digits = 1;
+ goto read_charclass;
+
+@@ -4001,8 +4001,7 @@
+
+ while (idx < number)
+ {
+- int res = wcscmp ((const wchar_t *) sorted[idx]->from,
+- (const wchar_t *) runp->from);
++ int res = wcscmp_uint32 (sorted[idx]->from, runp->from);
+ if (res == 0)
+ {
+ replace = 1;
+@@ -4039,11 +4038,11 @@
+ for (cnt = 0; cnt < number; ++cnt)
+ {
+ struct translit_to_t *srunp;
+- from_len += wcslen ((const wchar_t *) sorted[cnt]->from) + 1;
++ from_len += wcslen_uint32 (sorted[cnt]->from) + 1;
+ srunp = sorted[cnt]->to;
+ while (srunp != NULL)
+ {
+- to_len += wcslen ((const wchar_t *) srunp->str) + 1;
++ to_len += wcslen_uint32 (srunp->str) + 1;
+ srunp = srunp->next;
+ }
+ /* Plus one for the extra NUL character marking the end of
+@@ -4067,18 +4066,18 @@
+ ctype->translit_from_idx[cnt] = from_len;
+ ctype->translit_to_idx[cnt] = to_len;
+
+- len = wcslen ((const wchar_t *) sorted[cnt]->from) + 1;
+- wmemcpy ((wchar_t *) &ctype->translit_from_tbl[from_len],
+- (const wchar_t *) sorted[cnt]->from, len);
++ len = wcslen_uint32 (sorted[cnt]->from) + 1;
++ wmemcpy_uint32 (&ctype->translit_from_tbl[from_len],
++ sorted[cnt]->from, len);
+ from_len += len;
+
+ ctype->translit_to_idx[cnt] = to_len;
+ srunp = sorted[cnt]->to;
+ while (srunp != NULL)
+ {
+- len = wcslen ((const wchar_t *) srunp->str) + 1;
+- wmemcpy ((wchar_t *) &ctype->translit_to_tbl[to_len],
+- (const wchar_t *) srunp->str, len);
++ len = wcslen_uint32 (srunp->str) + 1;
++ wmemcpy_uint32 (&ctype->translit_to_tbl[to_len],
++ srunp->str, len);
+ to_len += len;
+ srunp = srunp->next;
+ }
+diff -Naur glibc-2.20/locale/programs/ld-messages.c glibc-2.20-patch/locale/programs/ld-messages.c
+--- glibc-2.20/locale/programs/ld-messages.c 2014-09-07 03:09:09.000000000 -0500
++++ glibc-2.20-patch/locale/programs/ld-messages.c 2015-03-04 00:51:32.377952006 -0600
+@@ -25,6 +25,7 @@
+ #include <string.h>
+ #include <stdint.h>
+ #include <sys/uio.h>
++#include <gnu/option-groups.h>
+
+ #include <assert.h>
+
+@@ -124,6 +125,7 @@
+ }
+ else
+ {
++#if __OPTION_POSIX_REGEXP
+ int result;
+ regex_t re;
+
+@@ -140,6 +142,7 @@
+ }
+ else if (result != 0)
+ regfree (&re);
++#endif
+ }
+
+ if (messages->noexpr == NULL)
+@@ -158,6 +161,7 @@
+ }
+ else
+ {
++#if __OPTION_POSIX_REGEXP
+ int result;
+ regex_t re;
+
+@@ -174,6 +178,7 @@
+ }
+ else if (result != 0)
+ regfree (&re);
++#endif
+ }
+ }
+
+diff -Naur glibc-2.20/locale/programs/ld-time.c glibc-2.20-patch/locale/programs/ld-time.c
+--- glibc-2.20/locale/programs/ld-time.c 2014-09-07 03:09:09.000000000 -0500
++++ glibc-2.20-patch/locale/programs/ld-time.c 2015-03-04 00:51:32.378952006 -0600
+@@ -215,8 +215,10 @@
+ }
+ else
+ {
++ static const uint32_t wt_fmt_ampm[]
++ = { '%','I',':','%','M',':','%','S',' ','%','p',0 };
+ time->t_fmt_ampm = "%I:%M:%S %p";
+- time->wt_fmt_ampm = (const uint32_t *) L"%I:%M:%S %p";
++ time->wt_fmt_ampm = wt_fmt_ampm;
+ }
+ }
+
+@@ -226,7 +228,7 @@
+ const int days_per_month[12] = { 31, 29, 31, 30, 31, 30,
+ 31, 31, 30, 31 ,30, 31 };
+ size_t idx;
+- wchar_t *wstr;
++ uint32_t *wstr;
+
+ time->era_entries =
+ (struct era_data *) xmalloc (time->num_era
+@@ -464,18 +466,18 @@
+ }
+
+ /* Now generate the wide character name and format. */
+- wstr = wcschr ((wchar_t *) time->wera[idx], L':');/* end direction */
+- wstr = wstr ? wcschr (wstr + 1, L':') : NULL; /* end offset */
+- wstr = wstr ? wcschr (wstr + 1, L':') : NULL; /* end start */
+- wstr = wstr ? wcschr (wstr + 1, L':') : NULL; /* end end */
++ wstr = wcschr_uint32 (time->wera[idx], L':'); /* end direction */
++ wstr = wstr ? wcschr_uint32 (wstr + 1, L':') : NULL; /* end offset */
++ wstr = wstr ? wcschr_uint32 (wstr + 1, L':') : NULL; /* end start */
++ wstr = wstr ? wcschr_uint32 (wstr + 1, L':') : NULL; /* end end */
+ if (wstr != NULL)
+ {
+- time->era_entries[idx].wname = (uint32_t *) wstr + 1;
+- wstr = wcschr (wstr + 1, L':'); /* end name */
++ time->era_entries[idx].wname = wstr + 1;
++ wstr = wcschr_uint32 (wstr + 1, L':'); /* end name */
+ if (wstr != NULL)
+ {
+ *wstr = L'\0';
+- time->era_entries[idx].wformat = (uint32_t *) wstr + 1;
++ time->era_entries[idx].wformat = wstr + 1;
+ }
+ else
+ time->era_entries[idx].wname =
+@@ -530,7 +532,16 @@
+ if (time->date_fmt == NULL)
+ time->date_fmt = "%a %b %e %H:%M:%S %Z %Y";
+ if (time->wdate_fmt == NULL)
+- time->wdate_fmt = (const uint32_t *) L"%a %b %e %H:%M:%S %Z %Y";
++ {
++ static const uint32_t wdate_fmt[] =
++ { '%','a',' ',
++ '%','b',' ',
++ '%','e',' ',
++ '%','H',':','%','M',':','%','S',' ',
++ '%','Z',' ',
++ '%','Y',0 };
++ time->wdate_fmt = wdate_fmt;
++ }
+ }
+
+
+diff -Naur glibc-2.20/locale/programs/linereader.c glibc-2.20-patch/locale/programs/linereader.c
+--- glibc-2.20/locale/programs/linereader.c 2014-09-07 03:09:09.000000000 -0500
++++ glibc-2.20-patch/locale/programs/linereader.c 2015-03-04 00:51:32.378952006 -0600
+@@ -595,7 +595,7 @@
+ {
+ int return_widestr = lr->return_widestr;
+ char *buf;
+- wchar_t *buf2 = NULL;
++ uint32_t *buf2 = NULL;
+ size_t bufact;
+ size_t bufmax = 56;
+
+diff -Naur glibc-2.20/locale/programs/localedef.c glibc-2.20-patch/locale/programs/localedef.c
+--- glibc-2.20/locale/programs/localedef.c 2014-09-07 03:09:09.000000000 -0500
++++ glibc-2.20-patch/locale/programs/localedef.c 2015-03-04 00:51:32.378952006 -0600
+@@ -114,6 +114,7 @@
+ #define OPT_LIST_ARCHIVE 309
+ #define OPT_LITTLE_ENDIAN 400
+ #define OPT_BIG_ENDIAN 401
++#define OPT_UINT32_ALIGN 402
+
+ /* Definitions of arguments for argp functions. */
+ static const struct argp_option options[] =
+@@ -150,6 +151,8 @@
+ N_("Generate little-endian output") },
+ { "big-endian", OPT_BIG_ENDIAN, NULL, 0,
+ N_("Generate big-endian output") },
++ { "uint32-align", OPT_UINT32_ALIGN, "ALIGNMENT", 0,
++ N_("Set the target's uint32_t alignment in bytes (default 4)") },
+ { NULL, 0, NULL, 0, NULL }
+ };
+
+@@ -239,12 +242,14 @@
+ ctype locale. (P1003.2 4.35.5.2) */
+ setlocale (LC_CTYPE, "POSIX");
+
++#ifndef NO_SYSCONF
+ /* Look whether the system really allows locale definitions. POSIX
+ defines error code 3 for this situation so I think it must be
+ a fatal error (see P1003.2 4.35.8). */
+ if (sysconf (_SC_2_LOCALEDEF) < 0)
+ WITH_CUR_LOCALE (error (3, 0, _("\
+ FATAL: system does not define `_POSIX2_LOCALEDEF'")));
++#endif
+
+ /* Process charmap file. */
+ charmap = charmap_read (charmap_file, verbose, 1, be_quiet, 1);
+@@ -338,6 +343,9 @@
+ case OPT_BIG_ENDIAN:
+ set_big_endian (true);
+ break;
++ case OPT_UINT32_ALIGN:
++ uint32_align_mask = strtol (arg, NULL, 0) - 1;
++ break;
+ case 'c':
+ force_output = 1;
+ break;
+diff -Naur glibc-2.20/locale/programs/locfile.c glibc-2.20-patch/locale/programs/locfile.c
+--- glibc-2.20/locale/programs/locfile.c 2014-09-07 03:09:09.000000000 -0500
++++ glibc-2.20-patch/locale/programs/locfile.c 2015-03-04 00:51:32.378952006 -0600
+@@ -544,6 +544,9 @@
+ machine running localedef. */
+ bool swap_endianness_p;
+
++/* The target's value of __align__(uint32_t) - 1. */
++unsigned int uint32_align_mask = 3;
++
+ /* When called outside a start_locale_structure/end_locale_structure
+ or start_locale_prelude/end_locale_prelude block, record that the
+ next byte in FILE's obstack will be the first byte of a new element.
+@@ -621,7 +624,7 @@
+ void
+ add_locale_wstring (struct locale_file *file, const uint32_t *string)
+ {
+- add_locale_uint32_array (file, string, wcslen ((const wchar_t *) string) + 1);
++ add_locale_uint32_array (file, string, wcslen_uint32 (string) + 1);
+ }
+
+ /* Record that FILE's next element is the 32-bit integer VALUE. */
+diff -Naur glibc-2.20/locale/programs/locfile.h glibc-2.20-patch/locale/programs/locfile.h
+--- glibc-2.20/locale/programs/locfile.h 2014-09-07 03:09:09.000000000 -0500
++++ glibc-2.20-patch/locale/programs/locfile.h 2015-03-04 00:51:32.379952006 -0600
+@@ -71,6 +71,8 @@
+
+ extern bool swap_endianness_p;
+
++extern unsigned int uint32_align_mask;
++
+ /* Change the output to be big-endian if BIG_ENDIAN is true and
+ little-endian otherwise. */
+ static inline void
+@@ -275,4 +277,49 @@
+ const struct charmap_t *charmap,
+ const char *output_path);
+
++static inline size_t
++wcslen_uint32 (const uint32_t *str)
++{
++ size_t len = 0;
++ while (str[len] != 0)
++ len++;
++ return len;
++}
++
++static inline int
++wmemcmp_uint32 (const uint32_t *s1, const uint32_t *s2, size_t n)
++{
++ while (n-- != 0)
++ {
++ int diff = *s1++ - *s2++;
++ if (diff != 0)
++ return diff;
++ }
++ return 0;
++}
++
++static inline int
++wcscmp_uint32 (const uint32_t *s1, const uint32_t *s2)
++{
++ while (*s1 != 0 && *s1 == *s2)
++ s1++, s2++;
++ return *s1 - *s2;
++}
++
++static inline uint32_t *
++wmemcpy_uint32 (uint32_t *s1, const uint32_t *s2, size_t n)
++{
++ return memcpy (s1, s2, n * sizeof (uint32_t));
++}
++
++static inline uint32_t *
++wcschr_uint32 (const uint32_t *s, uint32_t ch)
++{
++ do
++ if (*s == ch)
++ return (uint32_t *) s;
++ while (*s++ != 0);
++ return 0;
++}
++
+ #endif /* locfile.h */
+diff -Naur glibc-2.20/locale/setlocale.c glibc-2.20-patch/locale/setlocale.c
+--- glibc-2.20/locale/setlocale.c 2014-09-07 03:09:09.000000000 -0500
++++ glibc-2.20-patch/locale/setlocale.c 2015-03-04 00:51:32.379952006 -0600
+@@ -64,36 +64,6 @@
+ #endif
+
+
+-/* Define an array of category names (also the environment variable names). */
+-const union catnamestr_t _nl_category_names attribute_hidden =
+- {
+- {
+-#define DEFINE_CATEGORY(category, category_name, items, a) \
+- category_name,
+-#include "categories.def"
+-#undef DEFINE_CATEGORY
+- }
+- };
+-
+-const uint8_t _nl_category_name_idxs[__LC_LAST] attribute_hidden =
+- {
+-#define DEFINE_CATEGORY(category, category_name, items, a) \
+- [category] = offsetof (union catnamestr_t, CATNAMEMF (__LINE__)),
+-#include "categories.def"
+-#undef DEFINE_CATEGORY
+- };
+-
+-/* An array of their lengths, for convenience. */
+-const uint8_t _nl_category_name_sizes[] attribute_hidden =
+- {
+-#define DEFINE_CATEGORY(category, category_name, items, a) \
+- [category] = sizeof (category_name) - 1,
+-#include "categories.def"
+-#undef DEFINE_CATEGORY
+- [LC_ALL] = sizeof ("LC_ALL") - 1
+- };
+-
+-
+ #ifdef NL_CURRENT_INDIRECT
+ # define WEAK_POSTLOAD(postload) weak_extern (postload)
+ #else
+diff -Naur glibc-2.20/locale/xlocale.c glibc-2.20-patch/locale/xlocale.c
+--- glibc-2.20/locale/xlocale.c 2014-09-07 03:09:09.000000000 -0500
++++ glibc-2.20-patch/locale/xlocale.c 2015-03-04 00:51:32.379952006 -0600
+@@ -18,6 +18,7 @@
+ <http://www.gnu.org/licenses/>. */
+
+ #include <locale.h>
++#include <gnu/option-groups.h>
+ #include "localeinfo.h"
+
+ #define DEFINE_CATEGORY(category, category_name, items, a) \
+@@ -25,6 +26,19 @@
+ #include "categories.def"
+ #undef DEFINE_CATEGORY
+
++/* If the locale support code isn't enabled, don't generate strong
++ reference to the C locale_data structures here; let the Makefile
++ decide which ones to include. (In the static linking case, the
++ strong reference to the 'class', 'toupper', and 'tolower' tables
++ will cause C-ctype.o to be brought in, as it should be, even when
++ the reference to _nl_C_LC_CTYPE will be weak.) */
++#if ! __OPTION_EGLIBC_LOCALE_CODE
++# define DEFINE_CATEGORY(category, category_name, items, a) \
++ weak_extern (_nl_C_##category)
++# include "categories.def"
++# undef DEFINE_CATEGORY
++#endif
++
+ /* Defined in locale/C-ctype.c. */
+ extern const char _nl_C_LC_CTYPE_class[] attribute_hidden;
+ extern const char _nl_C_LC_CTYPE_toupper[] attribute_hidden;
+@@ -52,3 +66,26 @@
+ .__ctype_tolower = (const int *) _nl_C_LC_CTYPE_tolower + 128,
+ .__ctype_toupper = (const int *) _nl_C_LC_CTYPE_toupper + 128
+ };
++
++
++#if ! __OPTION_EGLIBC_LOCALE_CODE
++/* When locale code is enabled, these are each defined in the
++ appropriate lc-CATEGORY.c file, so that static links (when __thread
++ is supported) bring in only those lc-CATEGORY.o files for
++ categories the program actually uses; look for NL_CURRENT_INDIRECT
++ in localeinfo.h.
++
++ When locale code is disabled, the _nl_C_CATEGORY objects are the
++ only possible referents. At the moment, there isn't a way to get
++ __OPTION_EGLIBC_LOCALE_CODE defined in every compilation unit that
++ #includes localeinfo.h, so we can't just turn off
++ NL_CURRENT_INDIRECT. So we'll define the _nl_current_CATEGORY
++ pointers here. */
++#if defined (NL_CURRENT_INDIRECT)
++#define DEFINE_CATEGORY(category, category_name, items, a) \
++ __thread struct __locale_data * const *_nl_current_##category \
++ attribute_hidden = &_nl_C_locobj.__locales[category];
++#include "categories.def"
++#undef DEFINE_CATEGORY
++#endif
++#endif /* __OPTION_EGLIBC_LOCALE_CODE */
+diff -Naur glibc-2.20/localedata/Makefile glibc-2.20-patch/localedata/Makefile
+--- glibc-2.20/localedata/Makefile 2014-09-07 03:09:09.000000000 -0500
++++ glibc-2.20-patch/localedata/Makefile 2015-03-04 00:51:32.379952006 -0600
+@@ -21,12 +21,22 @@
+
+ include ../Makeconfig
+
+-# List with all available character set descriptions.
+-charmaps := $(wildcard charmaps/[A-I]*) $(wildcard charmaps/[J-Z]*)
++include ../option-groups.mak
+
+ # List with all available character set descriptions.
+-locales := $(wildcard locales/*)
++all-charmaps := $(wildcard charmaps/[A-I]*) $(wildcard charmaps/[J-Z]*)
++
++all-locales := $(wildcard locales/*)
+
++# If the EGLIBC_LOCALES option group is not enabled, trim the
++# list of charmap and locale source files.
++ifeq ($(OPTION_EGLIBC_LOCALES),y)
++charmaps := $(all-charmaps)
++locales := $(all-locales)
++else
++charmaps :=
++locales := locales/POSIX
++endif
+
+ subdir-dirs = tests-mbwc
+ vpath %.c tests-mbwc
+@@ -71,14 +81,20 @@
+ tst_wcsxfrm tst_wctob tst_wctomb tst_wctrans \
+ tst_wctype tst_wcwidth
+
+-tests = $(locale_test_suite) tst-digits tst-setlocale bug-iconv-trans \
++# Since these tests build their own locale files, they're not
++# dependent on the OPTION_EGLIBC_LOCALES option group. But they do
++# need the locale functions to be present.
++tests-$(OPTION_EGLIBC_LOCALE_CODE) \
++ += $(locale_test_suite) tst-digits tst-setlocale bug-iconv-trans \
+ tst-leaks tst-mbswcs1 tst-mbswcs2 tst-mbswcs3 tst-mbswcs4 tst-mbswcs5 \
+ tst-mbswcs6 tst-xlocale1 tst-xlocale2 bug-usesetlocale \
+ tst-strfmon1 tst-sscanf bug-setlocale1 tst-setlocale2 tst-setlocale3 \
+ tst-wctype
++ifeq (y,$(OPTION_EGLIBC_LOCALE_CODE))
+ tests-static = bug-setlocale1-static
+ tests += $(tests-static)
+-ifeq (yes,$(build-shared))
++endif
++ifeq (yesy,$(build-shared)$(OPTION_EGLIBC_LOCALE_CODE))
+ ifneq (no,$(PERL))
+ tests-special += $(objpfx)mtrace-tst-leaks.out
+ endif
+@@ -92,12 +108,14 @@
+
+ tests: $(objdir)/iconvdata/gconv-modules
+
++ifeq (y,$(OPTION_EGLIBC_LOCALE_CODE))
+ tests-special += $(objpfx)sort-test.out $(objpfx)tst-fmon.out \
+ $(objpfx)tst-locale.out $(objpfx)tst-rpmatch.out \
+ $(objpfx)tst-trans.out $(objpfx)tst-ctype.out \
+ $(objpfx)tst-langinfo.out $(objpfx)tst-langinfo-static.out \
+ $(objpfx)tst-numeric.out
+ tests-static += tst-langinfo-static
++endif
+
+ ifeq ($(run-built-tests),yes)
+ # We have to generate locales
+@@ -213,6 +231,11 @@
+
+ include SUPPORTED
+
++# Only install locale data if OPTION_EGLIBC_LOCALES is selected.
++ifneq ($(OPTION_EGLIBC_LOCALES),y)
++SUPPORTED-LOCALES :=
++endif
++
+ INSTALL-SUPPORTED-LOCALES=$(addprefix install-, $(SUPPORTED-LOCALES))
+
+ # Sometimes the whole collection of locale files should be installed.
+diff -Naur glibc-2.20/login/Makefile glibc-2.20-patch/login/Makefile
+--- glibc-2.20/login/Makefile 2014-09-07 03:09:09.000000000 -0500
++++ glibc-2.20-patch/login/Makefile 2015-03-04 00:51:32.379952006 -0600
+@@ -18,6 +18,7 @@
+ #
+ # Sub-makefile for login portion of the library.
+ #
++include ../option-groups.mak
+
+ subdir := login
+
+@@ -25,14 +26,16 @@
+
+ headers := utmp.h bits/utmp.h lastlog.h pty.h
+
+-routines := getlogin getlogin_r setlogin getlogin_r_chk \
+- getutent getutent_r getutid getutline getutid_r getutline_r \
+- utmp_file utmpname updwtmp getpt grantpt unlockpt ptsname \
+- ptsname_r_chk
++routines := getpt grantpt unlockpt ptsname ptsname_r_chk
++routines-$(OPTION_EGLIBC_UTMP) \
++ += getutent getutent_r getutid getutline getutid_r getutline_r \
++ utmp_file utmpname updwtmp
++routines-$(OPTION_EGLIBC_GETLOGIN) += getlogin getlogin_r getlogin_r_chk
++routines-$(OPTION_EGLIBC_BSD) += setlogin
+
+ CFLAGS-grantpt.c = -DLIBEXECDIR='"$(libexecdir)"'
+
+-others = utmpdump
++others-$(OPTION_EGLIBC_UTMP) += utmpdump
+
+ ifeq (yes,$(build-pt-chown))
+ others += pt_chown
+@@ -46,8 +49,8 @@
+ tests := tst-utmp tst-utmpx tst-grantpt tst-ptsname
+
+ # Build the -lutil library with these extra functions.
+-extra-libs := libutil
+-extra-libs-others := $(extra-libs)
++extra-libs-$(OPTION_EGLIBC_UTMP) := libutil
++extra-libs-others := $(extra-libs-y)
+
+ libutil-routines:= login login_tty logout logwtmp openpty forkpty
+
+diff -Naur glibc-2.20/Makeconfig glibc-2.20-patch/Makeconfig
+--- glibc-2.20/Makeconfig 2014-09-07 03:09:09.000000000 -0500
++++ glibc-2.20-patch/Makeconfig 2015-03-04 00:51:32.380952006 -0600
+@@ -582,7 +582,7 @@
+ # and run on the build system, causes that program with those
+ # arguments to be run on the host for which the library is built.
+ ifndef test-wrapper
+-test-wrapper =
++test-wrapper = $(cross-test-wrapper)
+ endif
+ # Likewise, but the name of the program is preceded by
+ # <variable>=<value> assignments for environment variables.
+@@ -1057,6 +1057,24 @@
+ libm = $(common-objpfx)math/libm.a
+ endif
+
++# Generate a header file that #defines preprocessor symbols indicating
++# which option groups are enabled. Note that the option-groups.config file
++# may not exist at all.
++before-compile += $(common-objpfx)gnu/option-groups.h
++common-generated += gnu/option-groups.h gnu/option-groups.stmp
++headers += gnu/option-groups.h
++$(common-objpfx)gnu/option-groups.h: $(common-objpfx)gnu/option-groups.stmp; @:
++$(common-objpfx)gnu/option-groups.stmp: \
++ $(..)scripts/option-groups.awk \
++ $(..)option-groups.defaults \
++ $(wildcard $(common-objpfx)option-groups.config)
++ $(make-target-directory)
++ @rm -f ${@:stmp=T} $@
++ LC_ALL=C $(AWK) -f $^ > ${@:stmp=T}
++ $(move-if-change) ${@:stmp=T} ${@:stmp=h}
++ touch $@
++
++
+ # These are the subdirectories containing the library source. The order
+ # is more or less arbitrary. The sorting step will take care of the
+ # dependencies.
+diff -Naur glibc-2.20/Makerules glibc-2.20-patch/Makerules
+--- glibc-2.20/Makerules 2014-09-07 03:09:09.000000000 -0500
++++ glibc-2.20-patch/Makerules 2015-03-04 00:51:32.380952006 -0600
+@@ -379,6 +379,25 @@
+ endef
+ endif
+
++# Include targets in the selected option groups.
++aux += $(aux-y)
++extra-libs += $(extra-libs-y)
++extra-libs-others += $(extra-libs-others-y)
++extra-objs += $(extra-objs-y)
++install-bin += $(install-bin-y)
++install-others += $(install-others-y)
++install-sbin += $(install-sbin-y)
++modules += $(modules-y)
++others += $(others-y)
++others-pie += $(others-pie-y)
++routines += $(routines-y)
++static-only-routines += $(static-only-routines-y)
++sysdep_routines += $(sysdep_routines-y)
++test-srcs += $(test-srcs-y)
++tests += $(tests-y)
++xtests += $(xtests-y)
++
++
+ # Modify the list of routines we build for different targets
+
+ ifeq (yes,$(build-shared))
+diff -Naur glibc-2.20/malloc/Makefile glibc-2.20-patch/malloc/Makefile
+--- glibc-2.20/malloc/Makefile 2014-09-07 03:09:09.000000000 -0500
++++ glibc-2.20-patch/malloc/Makefile 2015-03-04 00:51:32.380952006 -0600
+@@ -18,6 +18,8 @@
+ #
+ # Makefile for malloc routines
+ #
++include ../option-groups.mak
++
+ subdir := malloc
+
+ include ../Makeconfig
+@@ -36,9 +38,15 @@
+ non-lib.a := libmcheck.a
+
+ # Additional library.
++ifeq ($(OPTION_EGLIBC_MEMUSAGE),y)
+ extra-libs = libmemusage
+ extra-libs-others = $(extra-libs)
+
++ifdef OPTION_EGLIBC_MEMUSAGE_DEFAULT_BUFFER_SIZE
++CPPFLAGS-memusage += -D__OPTION_EGLIBC_MEMUSAGE_DEFAULT_BUFFER_SIZE=$(OPTION_EGLIBC_MEMUSAGE_DEFAULT_BUFFER_SIZE)
++endif
++endif
++
+ libmemusage-routines = memusage
+ libmemusage-inhibit-o = $(filter-out .os,$(object-suffixes))
+
+@@ -67,7 +75,7 @@
+ # Unless we get a test for the availability of libgd which also works
+ # for cross-compiling we disable the memusagestat generation in this
+ # situation.
+-ifneq ($(cross-compiling),yes)
++ifeq ($(cross-compiling)$(OPTION_EGLIBC_MEMUSAGE),noy)
+ # If the gd library is available we build the `memusagestat' program.
+ ifneq ($(LIBGD),no)
+ others: $(objpfx)memusage
+diff -Naur glibc-2.20/malloc/memusage.c glibc-2.20-patch/malloc/memusage.c
+--- glibc-2.20/malloc/memusage.c 2014-09-07 03:09:09.000000000 -0500
++++ glibc-2.20-patch/malloc/memusage.c 2015-03-04 00:51:32.380952006 -0600
+@@ -33,6 +33,7 @@
+ #include <stdint.h>
+ #include <sys/mman.h>
+ #include <sys/time.h>
++#include <gnu/option-groups.h>
+
+ #include <memusage.h>
+
+@@ -93,7 +94,11 @@
+ #define peak_stack peak_use[1]
+ #define peak_total peak_use[2]
+
+-#define DEFAULT_BUFFER_SIZE 32768
++#ifndef __OPTION_EGLIBC_MEMUSAGE_DEFAULT_BUFFER_SIZE
++# define DEFAULT_BUFFER_SIZE 32768
++#else
++# define DEFAULT_BUFFER_SIZE __OPTION_EGLIBC_MEMUSAGE_DEFAULT_BUFFER_SIZE
++#endif
+ static size_t buffer_size;
+
+ static int fd = -1;
+diff -Naur glibc-2.20/malloc/memusage.sh glibc-2.20-patch/malloc/memusage.sh
+--- glibc-2.20/malloc/memusage.sh 2014-09-07 03:09:09.000000000 -0500
++++ glibc-2.20-patch/malloc/memusage.sh 2015-03-04 00:51:32.381952006 -0600
+@@ -35,7 +35,7 @@
+
+ # Print help message
+ do_help() {
+- echo $"Usage: memusage [OPTION]... PROGRAM [PROGRAMOPTION]...
++ printf $"Usage: memusage [OPTION]... PROGRAM [PROGRAMOPTION]...
+ Profile memory usage of PROGRAM.
+
+ -n,--progname=NAME Name of the program file to profile
+diff -Naur glibc-2.20/math/Makefile glibc-2.20-patch/math/Makefile
+--- glibc-2.20/math/Makefile 2014-09-07 03:09:09.000000000 -0500
++++ glibc-2.20-patch/math/Makefile 2015-03-04 00:51:32.381952006 -0600
+@@ -21,6 +21,8 @@
+
+ include ../Makeconfig
+
++include ../option-groups.mak
++
+ # Installed header files.
+ headers := math.h bits/mathcalls.h bits/mathinline.h bits/huge_val.h \
+ bits/huge_valf.h bits/huge_vall.h bits/inf.h bits/nan.h \
+@@ -33,8 +35,8 @@
+
+ # Build the -lm library.
+
+-extra-libs := libm
+-extra-libs-others = $(extra-libs)
++extra-libs-$(OPTION_EGLIBC_LIBM) := libm
++extra-libs-others-$(OPTION_EGLIBC_LIBM) = $(extra-libs-$(OPTION_EGLIBC_LIBM))
+
+ libm-support = k_standard s_lib_version s_matherr s_signgam \
+ fclrexcpt fgetexcptflg fraiseexcpt fsetexcptflg \
+diff -Naur glibc-2.20/misc/err.c glibc-2.20-patch/misc/err.c
+--- glibc-2.20/misc/err.c 2014-09-07 03:09:09.000000000 -0500
++++ glibc-2.20-patch/misc/err.c 2015-03-04 00:51:32.381952006 -0600
+@@ -22,6 +22,7 @@
+ #include <errno.h>
+ #include <string.h>
+ #include <stdio.h>
++#include <gnu/option-groups.h>
+
+ #include <wchar.h>
+ #define flockfile(s) _IO_flockfile (s)
+@@ -37,6 +38,7 @@
+ va_end (ap); \
+ }
+
++#if __OPTION_POSIX_WIDE_CHAR_DEVICE_IO
+ static void
+ convert_and_print (const char *format, __gnuc_va_list ap)
+ {
+@@ -81,6 +83,7 @@
+
+ __vfwprintf (stderr, wformat, ap);
+ }
++#endif
+
+ void
+ vwarnx (const char *format, __gnuc_va_list ap)
+@@ -88,9 +91,13 @@
+ flockfile (stderr);
+ if (_IO_fwide (stderr, 0) > 0)
+ {
++#if __OPTION_POSIX_WIDE_CHAR_DEVICE_IO
+ __fwprintf (stderr, L"%s: ", __progname);
+ convert_and_print (format, ap);
+ putwc_unlocked (L'\n', stderr);
++#else
++ abort ();
++#endif
+ }
+ else
+ {
+@@ -111,6 +118,7 @@
+ flockfile (stderr);
+ if (_IO_fwide (stderr, 0) > 0)
+ {
++#if __OPTION_POSIX_WIDE_CHAR_DEVICE_IO
+ __fwprintf (stderr, L"%s: ", __progname);
+ if (format)
+ {
+@@ -119,6 +127,9 @@
+ }
+ __set_errno (error);
+ __fwprintf (stderr, L"%m\n");
++#else
++ abort ();
++#endif
+ }
+ else
+ {
+diff -Naur glibc-2.20/misc/error.c glibc-2.20-patch/misc/error.c
+--- glibc-2.20/misc/error.c 2014-09-07 03:09:09.000000000 -0500
++++ glibc-2.20-patch/misc/error.c 2015-03-04 00:51:32.381952006 -0600
+@@ -35,6 +35,7 @@
+ #endif
+
+ #ifdef _LIBC
++# include <gnu/option-groups.h>
+ # include <libintl.h>
+ # include <stdbool.h>
+ # include <stdint.h>
+@@ -205,6 +206,7 @@
+ #if _LIBC
+ if (_IO_fwide (stderr, 0) > 0)
+ {
++#if __OPTION_POSIX_WIDE_CHAR_DEVICE_IO
+ size_t len = strlen (message) + 1;
+ wchar_t *wmessage = NULL;
+ mbstate_t st;
+@@ -265,6 +267,9 @@
+
+ if (use_malloc)
+ free (wmessage);
++#else
++ abort ();
++#endif
+ }
+ else
+ #endif
+diff -Naur glibc-2.20/misc/Makefile glibc-2.20-patch/misc/Makefile
+--- glibc-2.20/misc/Makefile 2014-09-07 03:09:09.000000000 -0500
++++ glibc-2.20-patch/misc/Makefile 2015-03-04 00:51:32.381952006 -0600
+@@ -19,6 +19,10 @@
+ # Sub-makefile for misc portion of the library.
+ #
+
++# Some system-dependent implementations of these functions use option
++# groups (see sysdeps/unix/sysv/linux/Makefile, for example).
++include ../option-groups.mak
++
+ subdir := misc
+
+ include ../Makeconfig
+@@ -46,40 +50,47 @@
+ select pselect \
+ acct chroot fsync sync fdatasync syncfs reboot \
+ gethostid sethostid \
+- revoke vhangup \
++ vhangup \
+ swapon swapoff mktemp mkstemp mkstemp64 mkdtemp \
+ mkostemp mkostemp64 mkstemps mkstemps64 mkostemps mkostemps64 \
+ ualarm usleep \
+ gtty stty \
+ ptrace \
+- fstab mntent mntent_r \
++ mntent mntent_r \
+ utimes lutimes futimes futimesat \
+ truncate ftruncate truncate64 ftruncate64 \
+- chflags fchflags \
+ insremque getttyent getusershell getpass ttyslot \
+ syslog syscall daemon \
+ mmap mmap64 munmap mprotect msync madvise mincore remap_file_pages\
+ mlock munlock mlockall munlockall \
+- efgcvt efgcvt_r qefgcvt qefgcvt_r \
+ hsearch hsearch_r tsearch lsearch \
+ err error ustat \
+- getsysstats dirname regexp \
++ getsysstats dirname \
+ getloadavg getclktck \
+ fgetxattr flistxattr fremovexattr fsetxattr getxattr \
+ listxattr lgetxattr llistxattr lremovexattr lsetxattr \
+ removexattr setxattr getauxval ifunc-impl-list
+
++routines-$(OPTION_POSIX_REGEXP) += regexp
++routines-$(OPTION_EGLIBC_FSTAB) += fstab
++routines-$(OPTION_EGLIBC_BSD) += chflags fchflags revoke
++routines-$(OPTION_EGLIBC_FCVT) += efgcvt efgcvt_r qefgcvt qefgcvt_r
++
+ generated += tst-error1.mtrace tst-error1-mem.out
+
+ aux := init-misc
+ install-lib := libg.a
+ gpl2lgpl := error.c error.h
+
+-tests := tst-dirname tst-tsearch tst-fdset tst-efgcvt tst-mntent tst-hsearch \
+- tst-error1 tst-pselect tst-insremque tst-mntent2 bug-hsearch1
++tests := tst-dirname tst-tsearch tst-fdset tst-mntent tst-hsearch \
++ tst-pselect tst-insremque tst-mntent2 bug-hsearch1
++tests-$(OPTION_POSIX_WIDE_CHAR_DEVICE_IO) += tst-error1
++tests-$(OPTION_EGLIBC_FCVT) += tst-efgcvt
+ ifeq ($(run-built-tests),yes)
++ifeq (y,$(OPTION_POSIX_WIDE_CHAR_DEVICE_IO))
+ tests-special += $(objpfx)tst-error1-mem.out
+ endif
++endif
+
+ CFLAGS-select.c = -fexceptions -fasynchronous-unwind-tables
+ CFLAGS-tsearch.c = $(uses-callbacks)
+diff -Naur glibc-2.20/misc/sys/xattr.h glibc-2.20-patch/misc/sys/xattr.h
+--- glibc-2.20/misc/sys/xattr.h 2014-09-07 03:09:09.000000000 -0500
++++ glibc-2.20-patch/misc/sys/xattr.h 2015-03-04 00:51:32.382952006 -0600
+@@ -26,7 +26,6 @@
+
+ /* The following constants should be used for the fifth parameter of
+ `*setxattr'. */
+-#ifndef __USE_KERNEL_XATTR_DEFS
+ enum
+ {
+ XATTR_CREATE = 1, /* set value, fail if attr already exists. */
+@@ -34,7 +33,6 @@
+ XATTR_REPLACE = 2 /* set value, fail if attr does not exist. */
+ #define XATTR_REPLACE XATTR_REPLACE
+ };
+-#endif
+
+ /* Set the attribute NAME of the file pointed to by PATH to VALUE (which
+ is SIZE bytes long). Return 0 on success, -1 for errors. */
+diff -Naur glibc-2.20/misc/tst-efgcvt.c glibc-2.20-patch/misc/tst-efgcvt.c
+--- glibc-2.20/misc/tst-efgcvt.c 2014-09-07 03:09:09.000000000 -0500
++++ glibc-2.20-patch/misc/tst-efgcvt.c 2015-03-04 00:51:32.382952006 -0600
+@@ -59,7 +59,7 @@
+ { 123.01, -4, 3, "" },
+ { 126.71, -4, 3, "" },
+ { 0.0, 4, 1, "0000" },
+-#if DBL_MANT_DIG == 53
++#if DBL_MANT_DIG == 53 && !(defined __powerpc__ && defined __NO_FPRS__ && !defined _SOFT_FLOAT && !defined _SOFT_DOUBLE)
+ { 0x1p-1074, 3, -323, "494" },
+ { -0x1p-1074, 3, -323, "494" },
+ #endif
+diff -Naur glibc-2.20/nis/Makefile glibc-2.20-patch/nis/Makefile
+--- glibc-2.20/nis/Makefile 2014-09-07 03:09:09.000000000 -0500
++++ glibc-2.20-patch/nis/Makefile 2015-03-04 00:51:32.382952006 -0600
+@@ -18,6 +18,8 @@
+ #
+ # Makefile for NIS/NIS+ part.
+ #
++include ../option-groups.mak
++
+ subdir := nis
+
+ include ../Makeconfig
+@@ -30,19 +32,26 @@
+
+ # These are the databases available for the nis (and perhaps later nisplus)
+ # service. This must be a superset of the services in nss.
+-databases = proto service hosts network grp pwd rpc ethers \
+- spwd netgrp alias publickey
++databases-y := proto service hosts network grp pwd rpc ethers \
++ spwd netgrp publickey
++databases-$(OPTION_EGLIBC_DB_ALIASES) += alias
+
+ # Specify rules for the nss_* modules.
+-services := nis nisplus compat
++# The 'compat' module includes nis support, and the 'nss' directory
++# includes a bare-bones "files" library, so we'll include 'compat' in
++# OPTION_EGLIBC_NIS.
++services-y :=
++services-$(OPTION_EGLIBC_NIS) += nis nisplus compat
++
++extra-libs-$(OPTION_EGLIBC_NIS) += libnsl
++extra-libs-y += $(services-y:%=libnss_%)
+
+-extra-libs = libnsl $(services:%=libnss_%)
+ # These libraries will be built in the `others' pass rather than
+ # the `lib' pass, because they depend on libc.so being built already.
+-extra-libs-others = $(extra-libs)
++extra-libs-others-y += $(extra-libs-y)
+
+ # The sources are found in the appropriate subdir.
+-subdir-dirs = $(services:%=nss_%)
++subdir-dirs = $(services-y:%=nss_%)
+ vpath %.c $(subdir-dirs)
+
+ libnsl-routines = yp_xdr ypclnt ypupdate_xdr \
+@@ -60,11 +69,11 @@
+ libnss_compat-routines := $(addprefix compat-,grp pwd spwd initgroups)
+ libnss_compat-inhibit-o = $(filter-out .os,$(object-suffixes))
+
+-libnss_nis-routines := $(addprefix nis-,$(databases)) nis-initgroups \
++libnss_nis-routines := $(addprefix nis-,$(databases-y)) nis-initgroups \
+ nss-nis
+ libnss_nis-inhibit-o = $(filter-out .os,$(object-suffixes))
+
+-libnss_nisplus-routines := $(addprefix nisplus-,$(databases)) nisplus-parser \
++libnss_nisplus-routines := $(addprefix nisplus-,$(databases-y)) nisplus-parser \
+ nss-nisplus nisplus-initgroups
+ libnss_nisplus-inhibit-o = $(filter-out .os,$(object-suffixes))
+
+@@ -80,12 +89,12 @@
+ # Target-specific variable setting to link objects using deprecated
+ # RPC interfaces with the version of libc.so that makes them available
+ # for new links:
+-$(services:%=$(objpfx)libnss_%.so) $(objpfx)libnsl.so: \
++$(services-y:%=$(objpfx)libnss_%.so) $(objpfx)libnsl.so: \
+ libc-for-link = $(libnsl-libc)
+
+
+ ifeq ($(build-shared),yes)
+-$(others:%=$(objpfx)%): $(objpfx)libnsl.so$(libnsl.so-version)
++$(others-y:%=$(objpfx)%): $(objpfx)libnsl.so$(libnsl.so-version)
+ else
+-$(others:%=$(objpfx)%): $(objpfx)libnsl.a
++$(others-y:%=$(objpfx)%): $(objpfx)libnsl.a
+ endif
+diff -Naur glibc-2.20/nptl/Makefile glibc-2.20-patch/nptl/Makefile
+--- glibc-2.20/nptl/Makefile 2014-09-07 03:09:09.000000000 -0500
++++ glibc-2.20-patch/nptl/Makefile 2015-03-04 00:51:32.382952006 -0600
+@@ -18,6 +18,8 @@
+ #
+ # Sub-makefile for NPTL portion of the library.
+ #
++include ../option-groups.mak
++
+ subdir := nptl
+
+ include ../Makeconfig
+@@ -116,7 +118,7 @@
+ pt-raise pt-system \
+ flockfile ftrylockfile funlockfile \
+ sigaction \
+- herrno res pt-allocrtsig \
++ pt-allocrtsig \
+ pthread_kill_other_threads \
+ pthread_getaffinity pthread_setaffinity \
+ pthread_attr_getaffinity pthread_attr_setaffinity \
+@@ -136,6 +138,8 @@
+ # pthread_setgid pthread_setegid pthread_setregid \
+ # pthread_setresgid
+
++libpthread-routines-$(OPTION_EGLIBC_INET) := herrno res
++
+ libpthread-shared-only-routines = version pt-allocrtsig unwind-forcedunwind
+ libpthread-static-only-routines = pthread_atfork
+
+@@ -210,7 +214,7 @@
+ tst-mutexpi1 tst-mutexpi2 tst-mutexpi3 tst-mutexpi4 tst-mutexpi5 \
+ tst-mutexpi5a tst-mutexpi6 tst-mutexpi7 tst-mutexpi7a tst-mutexpi8 \
+ tst-mutexpi9 \
+- tst-spin1 tst-spin2 tst-spin3 tst-spin4 \
++ tst-spin1 tst-spin2 tst-spin3 \
+ tst-cond1 tst-cond2 tst-cond3 tst-cond4 tst-cond5 tst-cond6 tst-cond7 \
+ tst-cond8 tst-cond9 tst-cond10 tst-cond11 tst-cond12 tst-cond13 \
+ tst-cond14 tst-cond15 tst-cond16 tst-cond17 tst-cond18 tst-cond19 \
+@@ -244,14 +248,14 @@
+ tst-cancel6 tst-cancel7 tst-cancel8 tst-cancel9 tst-cancel10 \
+ tst-cancel11 tst-cancel12 tst-cancel13 tst-cancel14 tst-cancel15 \
+ tst-cancel16 tst-cancel17 tst-cancel18 tst-cancel19 tst-cancel20 \
+- tst-cancel21 tst-cancel22 tst-cancel23 tst-cancel24 tst-cancel25 \
++ tst-cancel21 tst-cancel22 tst-cancel23 tst-cancel25 \
+ tst-cancel-self tst-cancel-self-cancelstate \
+ tst-cancel-self-canceltype tst-cancel-self-testcancel \
+ tst-cleanup0 tst-cleanup1 tst-cleanup2 tst-cleanup3 tst-cleanup4 \
+ tst-flock1 tst-flock2 \
+ tst-signal1 tst-signal2 tst-signal3 tst-signal4 tst-signal5 \
+ tst-signal6 tst-signal7 \
+- tst-exec1 tst-exec2 tst-exec3 tst-exec4 \
++ tst-exec2 tst-exec3 tst-exec4 \
+ tst-exit1 tst-exit2 tst-exit3 \
+ tst-stdio1 tst-stdio2 \
+ tst-stack1 tst-stack2 tst-stack3 tst-pthread-getattr \
+@@ -259,13 +263,12 @@
+ tst-unload \
+ tst-dlsym1 \
+ tst-sysconf \
+- tst-locale1 tst-locale2 \
++ tst-locale2 \
+ tst-umask1 \
+ tst-popen1 \
+ tst-clock1 \
+ tst-context1 \
+ tst-sched1 \
+- tst-backtrace1 \
+ tst-abstime \
+ tst-vfork1 tst-vfork2 tst-vfork1x tst-vfork2x \
+ tst-getpid1 tst-getpid2 tst-getpid3 \
+@@ -275,6 +278,17 @@
+ tst-mutexpp1 tst-mutexpp6 tst-mutexpp10
+ test-srcs = tst-oddstacklimit
+
++# This test uses the posix_spawn functions.
++tests-$(OPTION_EGLIBC_SPAWN) += tst-exec1
++
++# This test uses the 'backtrace' functions.
++tests-$(OPTION_EGLIBC_BACKTRACE) += tst-backtrace1
++
++# This test is written in C++.
++tests-$(OPTION_EGLIBC_CXX_TESTS) += tst-cancel24
++
++tests-$(OPTION_EGLIBC_LOCALE_CODE) += tst-locale1
++
+ # Files which must not be linked with libpthread.
+ tests-nolibpthread = tst-unload
+
+@@ -363,12 +377,18 @@
+ $(common-objpfx)libc.a
+
+ tests-static += tst-locale1 tst-locale2 tst-stackguard1-static \
+- tst-cancel21-static tst-cancel24-static tst-cond8-static \
++ tst-cancel21-static tst-cond8-static \
+ tst-mutex8-static tst-mutexpi8-static tst-sem11-static \
+ tst-sem12-static
+-tests += tst-stackguard1-static tst-cancel21-static tst-cancel24-static \
++
++ifeq (y,$(OPTION_EGLIBC_CXX_TESTS))
++tests-static += tst-cancel24-static
++endif
++
++tests += tst-stackguard1-static tst-cancel21-static \
+ tst-cond8-static tst-mutex8-static tst-mutexpi8-static \
+ tst-sem11-static tst-sem12-static
++tests-$(OPTION_EGLIBC_CXX_TESTS) += tst-cancel24-static
+ xtests-static += tst-setuid1-static
+
+ # These tests are linked with libc before libpthread
+diff -Naur glibc-2.20/nptl/pthread_create.c glibc-2.20-patch/nptl/pthread_create.c
+--- glibc-2.20/nptl/pthread_create.c 2014-09-07 03:09:09.000000000 -0500
++++ glibc-2.20-patch/nptl/pthread_create.c 2015-03-04 00:51:32.382952006 -0600
+@@ -31,6 +31,7 @@
+ #include <kernel-features.h>
+ #include <exit-thread.h>
+
++#include <gnu/option-groups.h>
+ #include <shlib-compat.h>
+
+ #include <stap-probe.h>
+@@ -240,8 +241,10 @@
+ THREAD_SETMEM (pd, cpuclock_offset, now);
+ #endif
+
++#if __OPTION_EGLIBC_INET
+ /* Initialize resolver state pointer. */
+ __resp = &pd->res;
++#endif
+
+ /* Initialize pointers to locale data. */
+ __ctype_init ();
+@@ -322,8 +325,10 @@
+ /* Run the destructor for the thread-local data. */
+ __nptl_deallocate_tsd ();
+
++#if __OPTION_EGLIBC_INET
+ /* Clean up any state libc stored in thread-local variables. */
+ __libc_thread_freeres ();
++#endif
+
+ /* If this is the last thread we terminate the process now. We
+ do not notify the debugger, it might just irritate it if there
+diff -Naur glibc-2.20/nscd/Makefile glibc-2.20-patch/nscd/Makefile
+--- glibc-2.20/nscd/Makefile 2014-09-07 03:09:09.000000000 -0500
++++ glibc-2.20-patch/nscd/Makefile 2015-03-04 00:51:32.383952006 -0600
+@@ -18,14 +18,17 @@
+ #
+ # Sub-makefile for nscd portion of the library.
+ #
++include ../option-groups.mak
++
+ subdir := nscd
+
+ include ../Makeconfig
+
+ ifneq ($(use-nscd),no)
+-routines := nscd_getpw_r nscd_getgr_r nscd_gethst_r nscd_getai \
++routines-$(OPTION_EGLIBC_INET) += \
++ nscd_getpw_r nscd_getgr_r nscd_gethst_r nscd_getai \
+ nscd_initgroups nscd_getserv_r nscd_netgroup
+-aux := nscd_helper
++aux-$(OPTION_EGLIBC_INET) += nscd_helper
+ endif
+
+ # To find xmalloc.c
+@@ -37,14 +40,18 @@
+ dbg_log nscd_conf nscd_stat cache mem nscd_setup_thread \
+ xmalloc xstrdup aicache initgrcache gai res_hconf \
+ netgroupcache
+-
++ifneq (y,$(OPTION_EGLIBC_NIS))
++# If we haven't build libnsl.so, then we'll need to include our
++# own copy of nis_hash.
++nscd-modules += nis_hash
++endif
+ ifeq ($(build-nscd)$(have-thread-library),yesyes)
+
+-others += nscd
+-others-pie += nscd
+-install-sbin := nscd
++others-$(OPTION_EGLIBC_INET) += nscd
++others-pie-$(OPTION_EGLIBC_INET) += nscd
++install-sbin-$(OPTION_EGLIBC_INET) += nscd
+
+-extra-objs = $(nscd-modules:=.o)
++extra-objs-$(OPTION_EGLIBC_INET) += $(nscd-modules:=.o)
+
+ endif
+
+@@ -101,7 +108,15 @@
+ $(objpfx)nscd: $(nscd-modules:%=$(objpfx)%.o)
+
+ ifeq ($(build-shared),yes)
+-$(objpfx)nscd: $(shared-thread-library) $(common-objpfx)nis/libnsl.so
++$(objpfx)nscd: $(shared-thread-library)
++else
++$(objpfx)nscd: $(static-thread-library)
++endif
++
++ifeq (y,$(OPTION_EGLIBC_NIS))
++ifeq ($(build-shared),yes)
++$(objpfx)nscd: $(common-objpfx)nis/libnsl.so
+ else
+-$(objpfx)nscd: $(static-thread-library) $(common-objpfx)nis/libnsl.a
++$(objpfx)nscd: $(common-objpfx)nis/libnsl.a
++endif
+ endif
+diff -Naur glibc-2.20/nscd/nis_hash.c glibc-2.20-patch/nscd/nis_hash.c
+--- glibc-2.20/nscd/nis_hash.c 1969-12-31 18:00:00.000000000 -0600
++++ glibc-2.20-patch/nscd/nis_hash.c 2015-03-04 00:51:32.383952006 -0600
+@@ -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 -Naur glibc-2.20/nss/fixed-nsswitch.conf glibc-2.20-patch/nss/fixed-nsswitch.conf
+--- glibc-2.20/nss/fixed-nsswitch.conf 1969-12-31 18:00:00.000000000 -0600
++++ glibc-2.20-patch/nss/fixed-nsswitch.conf 2015-03-04 00:51:32.383952006 -0600
+@@ -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 -Naur glibc-2.20/nss/fixed-nsswitch.functions glibc-2.20-patch/nss/fixed-nsswitch.functions
+--- glibc-2.20/nss/fixed-nsswitch.functions 1969-12-31 18:00:00.000000000 -0600
++++ glibc-2.20-patch/nss/fixed-nsswitch.functions 2015-03-04 00:51:32.383952006 -0600
+@@ -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 -Naur glibc-2.20/nss/gen-fixed-nsswitch.c glibc-2.20-patch/nss/gen-fixed-nsswitch.c
+--- glibc-2.20/nss/gen-fixed-nsswitch.c 1969-12-31 18:00:00.000000000 -0600
++++ glibc-2.20-patch/nss/gen-fixed-nsswitch.c 2015-03-04 00:51:32.383952006 -0600
+@@ -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 -Naur glibc-2.20/nss/getent.c glibc-2.20-patch/nss/getent.c
+--- glibc-2.20/nss/getent.c 2014-09-07 03:09:09.000000000 -0500
++++ glibc-2.20-patch/nss/getent.c 2015-03-04 00:51:32.384952006 -0600
+@@ -39,6 +39,7 @@
+ #include <netinet/ether.h>
+ #include <netinet/in.h>
+ #include <sys/socket.h>
++#include <gnu/option-groups.h>
+
+ /* Get libc version number. */
+ #include <version.h>
+@@ -91,6 +92,7 @@
+ fprintf (stream, gettext ("Written by %s.\n"), "Thorsten Kukuk");
+ }
+
++#if __OPTION_EGLIBC_DB_ALIASES
+ /* This is for aliases */
+ static void
+ print_aliases (struct aliasent *alias)
+@@ -135,7 +137,9 @@
+
+ return result;
+ }
++#endif /* __OPTION_EGLIBC_DB_ALIASES */
+
++#if __OPTION_EGLIBC_INET
+ /* This is for ethers */
+ static int
+ ethers_keys (int number, char *key[])
+@@ -179,6 +183,7 @@
+
+ return result;
+ }
++#endif /* __OPTION_EGLIBC_INET */
+
+ /* This is for group */
+ static void
+@@ -301,6 +306,7 @@
+ return result;
+ }
+
++#if __OPTION_EGLIBC_INET
+ /* This is for hosts */
+ static void
+ print_hosts (struct hostent *host)
+@@ -598,6 +604,7 @@
+
+ return result;
+ }
++#endif /* __OPTION_EGLIBC_INET */
+
+ /* Now is all for passwd */
+ static void
+@@ -650,6 +657,7 @@
+ return result;
+ }
+
++#if __OPTION_EGLIBC_INET
+ /* This is for protocols */
+ static void
+ print_protocols (struct protoent *proto)
+@@ -805,6 +813,7 @@
+
+ return result;
+ }
++#endif /* __OPTION_EGLIBC_INET */
+
+ /* This is for shadow */
+ static void
+@@ -871,21 +880,34 @@
+ } databases[] =
+ {
+ #define D(name) { #name, name ## _keys },
+-D(ahosts)
+-D(ahostsv4)
+-D(ahostsv6)
+-D(aliases)
+-D(ethers)
++
++#if __OPTION_EGLIBC_INET
++#define DN(name) D(name)
++#else
++#define DN(name)
++#endif
++
++#if __OPTION_EGLIBC_DB_ALIASES
++#define DA(name) D(name)
++#else
++#define DA(name)
++#endif
++
++DN(ahosts)
++DN(ahostsv4)
++DN(ahostsv6)
++DA(aliases)
++DN(ethers)
+ D(group)
+ D(gshadow)
+-D(hosts)
++DN(hosts)
+ D(initgroups)
+-D(netgroup)
+-D(networks)
++DN(netgroup)
++DN(networks)
+ D(passwd)
+-D(protocols)
+-D(rpc)
+-D(services)
++DN(protocols)
++DN(rpc)
++DN(services)
+ D(shadow)
+ #undef D
+ { NULL, NULL }
+diff -Naur glibc-2.20/nss/getnssent_r.c glibc-2.20-patch/nss/getnssent_r.c
+--- glibc-2.20/nss/getnssent_r.c 2014-09-07 03:09:09.000000000 -0500
++++ glibc-2.20-patch/nss/getnssent_r.c 2015-03-04 00:51:32.384952006 -0600
+@@ -16,6 +16,7 @@
+ <http://www.gnu.org/licenses/>. */
+
+ #include <errno.h>
++#include <gnu/option-groups.h>
+ #include <netdb.h>
+ #include "nsswitch.h"
+
+@@ -59,11 +60,13 @@
+ } fct;
+ int no_more;
+
++#if __OPTION_EGLIBC_INET
+ if (res && __res_maybe_init (&_res, 0) == -1)
+ {
+ __set_h_errno (NETDB_INTERNAL);
+ return;
+ }
++#endif /* __OPTION_EGLIBC_INET */
+
+ /* Cycle through the services and run their `setXXent' functions until
+ we find an available service. */
+@@ -101,11 +104,13 @@
+ } fct;
+ int no_more;
+
++#if __OPTION_EGLIBC_INET
+ if (res && __res_maybe_init (&_res, 0) == -1)
+ {
+ __set_h_errno (NETDB_INTERNAL);
+ return;
+ }
++#endif /* __OPTION_EGLIBC_INET */
+
+ /* Cycle through all the services and run their endXXent functions. */
+ no_more = setup (func_name, lookup_fct, &fct.ptr, nip, startp, 1);
+@@ -141,12 +146,14 @@
+ int no_more;
+ enum nss_status status;
+
++#if __OPTION_EGLIBC_INET
+ if (res && __res_maybe_init (&_res, 0) == -1)
+ {
+ *h_errnop = NETDB_INTERNAL;
+ *result = NULL;
+ return errno;
+ }
++#endif /* __OPTION_EGLIBC_INET */
+
+ /* Initialize status to return if no more functions are found. */
+ status = NSS_STATUS_NOTFOUND;
+@@ -161,7 +168,7 @@
+ int is_last_nip = *nip == *last_nip;
+
+ status = DL_CALL_FCT (fct.f,
+- (resbuf, buffer, buflen, &errno, &h_errno));
++ (resbuf, buffer, buflen, &errno, h_errnop));
+
+ /* The status is NSS_STATUS_TRYAGAIN and errno is ERANGE the
+ provided buffer is too small. In this case we should give
+diff -Naur glibc-2.20/nss/Makefile glibc-2.20-patch/nss/Makefile
+--- glibc-2.20/nss/Makefile 2014-09-07 03:09:09.000000000 -0500
++++ glibc-2.20-patch/nss/Makefile 2015-03-04 00:51:32.384952006 -0600
+@@ -18,29 +18,36 @@
+ #
+ # Makefile for name service switch.
+ #
++include ../option-groups.mak
++
+ subdir := nss
+
+ include ../Makeconfig
+
+ headers := nss.h
+
+-# This is the trivial part which goes into libc itself.
+-routines = nsswitch getnssent getnssent_r digits_dots \
+- $(addsuffix -lookup,$(databases))
+-
+ # These are the databases that go through nss dispatch.
+ # Caution: if you add a database here, you must add its real name
+ # in databases.def, too.
+-databases = proto service hosts network grp pwd rpc ethers \
+- spwd netgrp key alias sgrp
++databases-y = grp pwd spwd sgrp
++databases-$(OPTION_EGLIBC_INET) \
++ += proto service hosts network rpc ethers \
++ netgrp key
++databases-$(OPTION_EGLIBC_DB_ALIASES) += alias
++
++# This is the trivial part which goes into libc itself.
++routines-y += nsswitch getnssent getnssent_r \
++ $(addsuffix -lookup,$(databases-y))
++routines-$(OPTION_EGLIBC_INET) += digits_dots
+
+ others := getent makedb
+ install-bin := getent makedb
+ makedb-modules = xmalloc hash-string
+ extra-objs += $(makedb-modules:=.o)
+
+-tests = test-netdb tst-nss-test1 test-digits-dots
+-xtests = bug-erange
++tests = tst-nss-test1
++tests-$(OPTION_EGLIBC_INET) += test-netdb test-digits-dots
++xtests-$(OPTION_EGLIBC_INET) += bug-erange
+
+ # Specify rules for the nss_* modules. We have some services.
+ services := files db
+@@ -55,7 +62,7 @@
+ vpath %.c $(subdir-dirs) ../locale/programs ../intl
+
+
+-libnss_files-routines := $(addprefix files-,$(databases)) \
++libnss_files-routines := $(addprefix files-,$(databases-y)) \
+ files-initgroups files-have_o_cloexec files-init
+
+ libnss_db-dbs := $(addprefix db-,\
+@@ -78,6 +85,45 @@
+ tests += $(tests-static)
+ endif
+
++ifneq ($(OPTION_EGLIBC_NSSWITCH),y)
++
++ifndef OPTION_EGLIBC_NSSWITCH_FIXED_CONFIG
++$(error OPTION_EGLIBC_NSSWITCH_FIXED_CONFIG variable left unset)
++endif
++
++ifndef OPTION_EGLIBC_NSSWITCH_FIXED_FUNCTIONS
++$(error OPTION_EGLIBC_NSSWITCH_FIXED_FUNCTIONS variable left unset)
++endif
++
++ifeq (,$(wildcard $(OPTION_EGLIBC_NSSWITCH_FIXED_CONFIG)))
++$(warning OPTION_EGLIBC_NSSWITCH is disabled, but fixed config file)
++$(error does not exist: $(OPTION_EGLIBC_NSSWITCH_FIXED_CONFIG))
++endif
++
++ifeq (,$(wildcard $(OPTION_EGLIBC_NSSWITCH_FIXED_FUNCTIONS)))
++$(warning OPTION_EGLIBC_NSSWITCH is disabled, but fixed functions file)
++$(error does not exist: $(OPTION_EGLIBC_NSSWITCH_FIXED_FUNCTIONS))
++endif
++
++before-compile := $(objpfx)fixed-nsswitch.h
++generated := fixed-nsswitch.h
++$(objpfx)fixed-nsswitch.h $(objfpx)fixed-nsswitch-libs: \
++ $(objpfx)gen-fixed-nsswitch \
++ $(OPTION_EGLIBC_NSSWITCH_FIXED_CONFIG)
++ $< $(objpfx)fixed-nsswitch.h \
++ $(objpfx)fixed-nsswitch-libs \
++ $(OPTION_EGLIBC_NSSWITCH_FIXED_CONFIG)
++
++$(objpfx)gen-fixed-nsswitch: gen-fixed-nsswitch.c \
++ $(common-objpfx)option-groups.config \
++ $(OPTION_EGLIBC_NSSWITCH_FIXED_FUNCTIONS)
++ $(native-compile)
++gen-fixed-nsswitch-CFLAGS = \
++ -g3 -O -Wall \
++ -I $(objpfx) \
++ -DFIXED_FUNCTIONS='"$(OPTION_EGLIBC_NSSWITCH_FIXED_FUNCTIONS)"'
++endif
++
+ include ../Rules
+
+ ifeq (yes,$(have-selinux))
+diff -Naur glibc-2.20/nss/nsswitch.c glibc-2.20-patch/nss/nsswitch.c
+--- glibc-2.20/nss/nsswitch.c 2014-09-07 03:09:09.000000000 -0500
++++ glibc-2.20-patch/nss/nsswitch.c 2015-03-04 00:51:32.384952006 -0600
+@@ -26,6 +26,7 @@
+ #include <stdio_ext.h>
+ #include <stdlib.h>
+ #include <string.h>
++#include <gnu/option-groups.h>
+
+ #include <aliases.h>
+ #include <grp.h>
+@@ -41,6 +42,15 @@
+ #include "../nscd/nscd_proto.h"
+ #include <sysdep.h>
+
++/* When OPTION_EGLIBC_NSSWITCH is disabled, we use fixed tables of
++ databases and services, generated at library build time. Thus:
++ - We can't reconfigure individual databases, so we don't need a
++ name-to-database map.
++ - We never add databases or service libraries, or look up functions
++ at runtime, so there's no need for a lock to protect our tables.
++ See ../option-groups.def for the details. */
++#if __OPTION_EGLIBC_NSSWITCH
++
+ /* Prototypes for the local functions. */
+ static name_database *nss_parse_file (const char *fname) internal_function;
+ static name_database_entry *nss_getline (char *line) internal_function;
+@@ -79,6 +89,9 @@
+
+ __libc_lock_define_initialized (static, lock)
+
++#define lock_nsswitch __libc_lock_lock (lock)
++#define unlock_nsswitch __libc_lock_unlock (lock)
++
+ #if !defined DO_STATIC_NSS || defined SHARED
+ /* String with revision number of the shared object files. */
+ static const char *const __nss_shlib_revision = LIBNSS_FILES_SO + 15;
+@@ -93,6 +106,20 @@
+ __libc_freeres. */
+ static name_database_entry *defconfig_entries;
+
++#else /* __OPTION_EGLIBC_NSSWITCH */
++
++/* Bring in the statically initialized service table we generated at
++ build time. */
++#include "fixed-nsswitch.h"
++
++const static name_database *service_table = &fixed_name_database;
++
++/* Nothing ever changes, so there's no need to lock anything. */
++#define lock_nsswitch (0)
++#define unlock_nsswitch (0)
++
++#endif /* __OPTION_EGLIBC_NSSWITCH */
++
+
+ #ifdef USE_NSCD
+ /* Nonzero if this is the nscd process. */
+@@ -109,20 +136,22 @@
+ const char *defconfig, service_user **ni)
+ {
+ /* Prevent multiple threads to change the service table. */
+- __libc_lock_lock (lock);
++ lock_nsswitch;
+
+ /* Reconsider database variable in case some other thread called
+ `__nss_configure_lookup' while we waited for the lock. */
+ if (*ni != NULL)
+ {
+- __libc_lock_unlock (lock);
++ unlock_nsswitch;
+ return 0;
+ }
+
++#if __OPTION_EGLIBC_NSSWITCH
+ /* Are we initialized yet? */
+ if (service_table == NULL)
+ /* Read config file. */
+ service_table = nss_parse_file (_PATH_NSSWITCH_CONF);
++#endif
+
+ /* Test whether configuration data is available. */
+ if (service_table != NULL)
+@@ -144,6 +173,7 @@
+ *ni = entry->service;
+ }
+
++#if __OPTION_EGLIBC_NSSWITCH
+ /* No configuration data is available, either because nsswitch.conf
+ doesn't exist or because it doesn't have a line for this database.
+
+@@ -166,13 +196,23 @@
+ {
+ entry->next = defconfig_entries;
+ entry->service = *ni;
+- entry->name[0] = '\0';
++ entry->name = "";
+ defconfig_entries = entry;
+ }
+ }
+ }
++#else
++ /* Without the dynamic behavior, we can't process defconfig. The
++ databases the user specified at library build time are all you
++ get. */
++ if (*ni == NULL)
++ {
++ unlock_nsswitch;
++ return -1;
++ }
++#endif
+
+- __libc_lock_unlock (lock);
++ unlock_nsswitch;
+
+ return *ni != NULL ? 0 : -1;
+ }
+@@ -252,6 +292,7 @@
+ libc_hidden_def (__nss_next2)
+
+
++#if __OPTION_EGLIBC_NSSWITCH
+ int
+ attribute_compat_text_section
+ __nss_next (service_user **ni, const char *fct_name, void **fctp, int status,
+@@ -300,13 +341,13 @@
+ }
+
+ /* Prevent multiple threads to change the service table. */
+- __libc_lock_lock (lock);
++ lock_nsswitch;
+
+ /* Install new rules. */
+ *databases[cnt].dbp = new_db;
+ __nss_database_custom[cnt] = true;
+
+- __libc_lock_unlock (lock);
++ unlock_nsswitch;
+
+ return 0;
+ }
+@@ -402,7 +443,7 @@
+ void **found, *result;
+
+ /* We now modify global data. Protect it. */
+- __libc_lock_lock (lock);
++ lock_nsswitch;
+
+ /* Search the tree of functions previously requested. Data in the
+ tree are `known_function' structures, whose first member is a
+@@ -413,7 +454,7 @@
+ enough to a pointer to our structure to use as a lookup key that
+ will be passed to `known_compare' (above). */
+
+- found = __tsearch (&fct_name, &ni->known, &known_compare);
++ found = __tsearch (&fct_name, &ni->known.tree, &known_compare);
+ if (found == NULL)
+ /* This means out-of-memory. */
+ result = NULL;
+@@ -440,7 +481,7 @@
+ #endif
+ /* Oops. We can't instantiate this node properly.
+ Remove it from the tree. */
+- __tdelete (&fct_name, &ni->known, &known_compare);
++ __tdelete (&fct_name, &ni->known.tree, &known_compare);
+ free (known);
+ result = NULL;
+ }
+@@ -520,13 +561,43 @@
+ }
+
+ /* Remove the lock. */
+- __libc_lock_unlock (lock);
++ unlock_nsswitch;
+
+ return result;
+ }
+ libc_hidden_def (__nss_lookup_function)
+
+
++#else /* below if ! __OPTION_EGLIBC_NSSWITCH */
++
++
++int
++__nss_configure_lookup (const char *dbname, const char *service_line)
++{
++ /* We can't dynamically configure lookup without
++ OPTION_EGLIBC_NSSWITCH. */
++ __set_errno (EINVAL);
++ return -1;
++}
++
++
++void *
++__nss_lookup_function (service_user *ni, const char *fct_name)
++{
++ int i;
++ const known_function **known = ni->known.array;
++
++ for (i = 0; known[i]; i++)
++ if (strcmp (fct_name, known[i]->fct_name) == 0)
++ return known[i]->fct_ptr;
++
++ return NULL;
++}
++libc_hidden_def (__nss_lookup_function)
++#endif
++
++
++#if __OPTION_EGLIBC_NSSWITCH
+ static name_database *
+ internal_function
+ nss_parse_file (const char *fname)
+@@ -632,8 +703,10 @@
+ + (line - name + 1));
+ if (new_service == NULL)
+ return result;
++ new_service->name = (char *) (new_service + 1);
+
+- *((char *) __mempcpy (new_service->name, name, line - name)) = '\0';
++ *((char *) __mempcpy ((char *) new_service->name, name, line - name))
++ = '\0';
+
+ /* Set default actions. */
+ new_service->actions[2 + NSS_STATUS_TRYAGAIN] = NSS_ACTION_CONTINUE;
+@@ -642,7 +715,7 @@
+ new_service->actions[2 + NSS_STATUS_SUCCESS] = NSS_ACTION_RETURN;
+ new_service->actions[2 + NSS_STATUS_RETURN] = NSS_ACTION_RETURN;
+ new_service->library = NULL;
+- new_service->known = NULL;
++ new_service->known.tree = NULL;
+ new_service->next = NULL;
+
+ while (isspace (line[0]))
+@@ -778,9 +851,10 @@
+ result = (name_database_entry *) malloc (sizeof (name_database_entry) + len);
+ if (result == NULL)
+ return NULL;
++ result->name = (char *) (result + 1);
+
+ /* Save the database name. */
+- memcpy (result->name, name, len);
++ memcpy ((char *) result->name, name, len);
+
+ /* Parse the list of services. */
+ result->service = nss_parse_service_list (line);
+@@ -816,6 +890,7 @@
+ return *currentp;
+ }
+ #endif
++#endif /* __OPTION_EGLIBC_NSSWITCH */
+
+
+ #if defined SHARED && defined USE_NSCD
+@@ -834,6 +909,7 @@
+ }
+
+
++#if __OPTION_EGLIBC_INET
+ /* Called by nscd and nscd alone. */
+ void
+ __nss_disable_nscd (void (*cb) (size_t, struct traced_file *))
+@@ -857,8 +933,10 @@
+ __nss_not_use_nscd_services = -1;
+ __nss_not_use_nscd_netgroup = -1;
+ }
++#endif /* __OPTION_EGLIBC_INET */
+ #endif
+
++#if __OPTION_EGLIBC_NSSWITCH
+ static void
+ free_database_entries (name_database_entry *entry)
+ {
+@@ -871,8 +949,8 @@
+ {
+ service_user *olds = service;
+
+- if (service->known != NULL)
+- __tdestroy (service->known, free);
++ if (service->known.tree != NULL)
++ __tdestroy (service->known.tree, free);
+
+ service = service->next;
+ free (olds);
+@@ -926,3 +1004,4 @@
+
+ free (top);
+ }
++#endif /* __OPTION_EGLIBC_NSSWITCH */
+diff -Naur glibc-2.20/nss/nsswitch.h glibc-2.20-patch/nss/nsswitch.h
+--- glibc-2.20/nss/nsswitch.h 2014-09-07 03:09:09.000000000 -0500
++++ glibc-2.20-patch/nss/nsswitch.h 2015-03-04 00:51:32.385952006 -0600
+@@ -65,10 +65,20 @@
+ lookup_actions actions[5];
+ /* Link to the underlying library object. */
+ service_library *library;
+- /* Collection of known functions. */
+- void *known;
++ /* Collection of known functions.
++
++ With OPTION_EGLIBC_NSSWITCH enabled, this is the root of a
++ 'tsearch'-style tree.
++
++ With OPTION_EGLIBC_NSSWITCH disabled, this is an array of
++ pointers to known_function structures, NULL-terminated. */
++ union
++ {
++ void *tree;
++ const known_function **array;
++ } known;
+ /* Name of the service (`files', `dns', `nis', ...). */
+- char name[0];
++ const char *name;
+ } service_user;
+
+ /* To access the action based on the status value use this macro. */
+@@ -82,7 +92,7 @@
+ /* List of service to be used. */
+ service_user *service;
+ /* Name of the database. */
+- char name[0];
++ const char *name;
+ } name_database_entry;
+
+
+diff -Naur glibc-2.20/posix/bug-regex1.c glibc-2.20-patch/posix/bug-regex1.c
+--- glibc-2.20/posix/bug-regex1.c 2014-09-07 03:09:09.000000000 -0500
++++ glibc-2.20-patch/posix/bug-regex1.c 2015-03-04 00:51:32.385952006 -0600
+@@ -4,6 +4,7 @@
+ #include <string.h>
+ #include <regex.h>
+ #include <wchar.h>
++#include <gnu/option-groups.h>
+
+ int
+ main (void)
+@@ -17,7 +18,9 @@
+ memset (®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 -Naur glibc-2.20/posix/bug-regex6.c glibc-2.20-patch/posix/bug-regex6.c
+--- glibc-2.20/posix/bug-regex6.c 2014-09-07 03:09:09.000000000 -0500
++++ glibc-2.20-patch/posix/bug-regex6.c 2015-03-04 00:51:32.385952006 -0600
+@@ -22,6 +22,7 @@
+ #include <string.h>
+ #include <sys/types.h>
+ #include <regex.h>
++#include <gnu/option-groups.h>
+
+
+ int
+@@ -30,7 +31,12 @@
+ regex_t re;
+ regmatch_t mat[10];
+ int i, j, ret = 0;
+- const char *locales[] = { "C", "de_DE.UTF-8" };
++ const char *locales[] = {
++ "C",
++#if __OPTION_EGLIBC_LOCALE_CODE
++ "de_DE.UTF-8"
++#endif
++ };
+ const char *string = "http://www.regex.com/pattern/matching.html#intro";
+ regmatch_t expect[10] = {
+ { 0, 48 }, { 0, 5 }, { 0, 4 }, { 5, 20 }, { 7, 20 }, { 20, 42 },
+diff -Naur glibc-2.20/posix/fnmatch.c glibc-2.20-patch/posix/fnmatch.c
+--- glibc-2.20/posix/fnmatch.c 2014-09-07 03:09:09.000000000 -0500
++++ glibc-2.20-patch/posix/fnmatch.c 2015-03-04 00:51:32.385952006 -0600
+@@ -30,6 +30,10 @@
+ #include <ctype.h>
+ #include <string.h>
+
++#if defined _LIBC
++# include <gnu/option-groups.h>
++#endif
++
+ #if defined STDC_HEADERS || defined _LIBC
+ # include <stdlib.h>
+ #endif
+@@ -131,7 +135,7 @@
+ # define ISWCTYPE(WC, WT) iswctype (WC, WT)
+ # endif
+
+-# if (HAVE_MBSTATE_T && HAVE_MBSRTOWCS) || _LIBC
++# if (HAVE_MBSTATE_T && HAVE_MBSRTOWCS) || (_LIBC && __OPTION_EGLIBC_LOCALE_CODE)
+ /* In this case we are implementing the multibyte character handling. */
+ # define HANDLE_MULTIBYTE 1
+ # endif
+diff -Naur glibc-2.20/posix/fnmatch_loop.c glibc-2.20-patch/posix/fnmatch_loop.c
+--- glibc-2.20/posix/fnmatch_loop.c 2014-09-07 03:09:09.000000000 -0500
++++ glibc-2.20-patch/posix/fnmatch_loop.c 2015-03-04 00:51:32.385952006 -0600
+@@ -15,6 +15,8 @@
+ License along with the GNU C Library; if not, see
+ <http://www.gnu.org/licenses/>. */
+
++#include <gnu/option-groups.h>
++
+ #include <stdint.h>
+
+ struct STRUCT
+@@ -54,10 +56,15 @@
+ const char *collseq = (const char *)
+ _NL_CURRENT(LC_COLLATE, _NL_COLLATE_COLLSEQWC);
+ # else
++# if __OPTION_EGLIBC_LOCALE_CODE
+ const UCHAR *collseq = (const UCHAR *)
+ _NL_CURRENT(LC_COLLATE, _NL_COLLATE_COLLSEQMB);
+-# endif
+-#endif
++# define COLLSEQ_BYTE_LOOKUP(ix) (collseq[(ix)])
++# else
++# define COLLSEQ_BYTE_LOOKUP(ix) (ix)
++# endif /* __OPTION_EGLIBC_LOCALE_CODE */
++# endif /* WIDE_CHAR_VERSION */
++#endif /* _LIBC */
+
+ while ((c = *p++) != L('\0'))
+ {
+@@ -277,7 +284,7 @@
+ /* Leave room for the null. */
+ CHAR str[CHAR_CLASS_MAX_LENGTH + 1];
+ size_t c1 = 0;
+-#if defined _LIBC || (defined HAVE_WCTYPE_H && defined HAVE_WCHAR_H)
++#if defined _LIBC ? __OPTION_POSIX_C_LANG_WIDE_CHAR : (defined HAVE_WCTYPE_H && defined HAVE_WCHAR_H)
+ wctype_t wt;
+ #endif
+ const CHAR *startp = p;
+@@ -307,7 +314,7 @@
+ }
+ str[c1] = L('\0');
+
+-#if defined _LIBC || (defined HAVE_WCTYPE_H && defined HAVE_WCHAR_H)
++#if defined _LIBC ? __OPTION_POSIX_C_LANG_WIDE_CHAR : (defined HAVE_WCTYPE_H && defined HAVE_WCHAR_H)
+ wt = IS_CHAR_CLASS (str);
+ if (wt == 0)
+ /* Invalid character class name. */
+@@ -681,8 +688,10 @@
+ else
+ lcollseq = __collseq_table_lookup (collseq, cold);
+ # else
+- fcollseq = collseq[fn];
+- lcollseq = is_seqval ? cold : collseq[(UCHAR) cold];
++ fcollseq = COLLSEQ_BYTE_LOOKUP (fn);
++ lcollseq = (is_seqval
++ ? cold
++ : COLLSEQ_BYTE_LOOKUP ((UCHAR) cold));
+ # endif
+
+ is_seqval = 0;
+@@ -858,7 +867,7 @@
+ goto matched;
+ }
+ # else
+- hcollseq = collseq[cend];
++ hcollseq = COLLSEQ_BYTE_LOOKUP (cend);
+ # endif
+ }
+
+diff -Naur glibc-2.20/posix/glob.c glibc-2.20-patch/posix/glob.c
+--- glibc-2.20/posix/glob.c 2014-09-07 03:09:09.000000000 -0500
++++ glibc-2.20-patch/posix/glob.c 2015-03-04 00:51:32.386952006 -0600
+@@ -25,6 +25,9 @@
+ #include <sys/types.h>
+ #include <sys/stat.h>
+ #include <stddef.h>
++#ifdef _LIBC
++# include <gnu/option-groups.h>
++#endif
+
+ /* Outcomment the following line for production quality code. */
+ /* #define NDEBUG 1 */
+@@ -607,6 +610,7 @@
+ if (home_dir == NULL || home_dir[0] == '\0')
+ home_dir = "c:/users/default"; /* poor default */
+ # else
++# if ! _LIBC || __OPTION_EGLIBC_GETLOGIN
+ if (home_dir == NULL || home_dir[0] == '\0')
+ {
+ int success;
+@@ -623,19 +627,19 @@
+ if (success)
+ {
+ struct passwd *p;
+-# if defined HAVE_GETPWNAM_R || defined _LIBC
++# if defined HAVE_GETPWNAM_R || defined _LIBC
+ long int pwbuflen = GETPW_R_SIZE_MAX ();
+ char *pwtmpbuf;
+ struct passwd pwbuf;
+ int malloc_pwtmpbuf = 0;
+ int save = errno;
+
+-# ifndef _LIBC
++# ifndef _LIBC
+ if (pwbuflen == -1)
+ /* `sysconf' does not support _SC_GETPW_R_SIZE_MAX.
+ Try a moderate value. */
+ pwbuflen = 1024;
+-# endif
++# endif
+ if (__libc_use_alloca (alloca_used + pwbuflen))
+ pwtmpbuf = alloca_account (pwbuflen, alloca_used);
+ else
+@@ -682,9 +686,9 @@
+ }
+ __set_errno (save);
+ }
+-# else
++# else
+ p = getpwnam (name);
+-# endif
++# endif
+ if (p != NULL)
+ {
+ if (!malloc_pwtmpbuf)
+@@ -713,6 +717,7 @@
+ }
+ }
+ }
++# endif /* ! _LIBC || __OPTION_EGLIBC_GETLOGIN */
+ if (home_dir == NULL || home_dir[0] == '\0')
+ {
+ if (flags & GLOB_TILDE_CHECK)
+diff -Naur glibc-2.20/posix/Makefile glibc-2.20-patch/posix/Makefile
+--- glibc-2.20/posix/Makefile 2014-09-07 03:09:09.000000000 -0500
++++ glibc-2.20-patch/posix/Makefile 2015-03-04 00:51:32.386952006 -0600
+@@ -18,6 +18,8 @@
+ #
+ # Sub-makefile for POSIX portion of the library.
+ #
++include ../option-groups.mak
++
+ subdir := posix
+
+ include ../Makeconfig
+@@ -43,13 +45,24 @@
+ getpgid setpgid getpgrp bsd-getpgrp setpgrp getsid setsid \
+ getresuid getresgid setresuid setresgid \
+ pathconf sysconf fpathconf \
+- glob glob64 fnmatch regex \
++ glob glob64 fnmatch \
+ confstr \
+ getopt getopt1 getopt_init \
+ sched_setp sched_getp sched_sets sched_gets sched_yield sched_primax \
+ sched_primin sched_rr_gi sched_getaffinity sched_setaffinity \
+- getaddrinfo gai_strerror wordexp \
+ pread pwrite pread64 pwrite64 \
++ posix_madvise \
++ get_child_max sched_cpucount sched_cpualloc sched_cpufree
++
++routines-$(OPTION_EGLIBC_INET) += getaddrinfo gai_strerror
++
++ifeq (y,$(OPTION_POSIX_REGEXP_GLIBC))
++routines-$(OPTION_POSIX_REGEXP) += regex
++else
++routines-$(OPTION_POSIX_REGEXP) += xregex
++endif
++
++routines-$(OPTION_EGLIBC_SPAWN) += \
+ spawn_faction_init spawn_faction_destroy spawn_faction_addclose \
+ spawn_faction_addopen spawn_faction_adddup2 \
+ spawnattr_init spawnattr_destroy \
+@@ -57,41 +70,53 @@
+ spawnattr_getflags spawnattr_setflags \
+ spawnattr_getpgroup spawnattr_setpgroup spawn spawnp spawni \
+ spawnattr_getsigmask spawnattr_getschedpolicy spawnattr_getschedparam \
+- spawnattr_setsigmask spawnattr_setschedpolicy spawnattr_setschedparam \
+- posix_madvise \
+- get_child_max sched_cpucount sched_cpualloc sched_cpufree
++ spawnattr_setsigmask spawnattr_setschedpolicy spawnattr_setschedparam
++routines-$(OPTION_EGLIBC_WORDEXP) += wordexp
+
+ aux := init-posix environ
+-tests := tstgetopt testfnm runtests runptests \
++tests := tstgetopt testfnm runtests \
+ tst-preadwrite tst-preadwrite64 test-vfork regexbug1 \
+- tst-getlogin tst-mmap tst-getaddrinfo tst-truncate \
+- tst-truncate64 tst-fork tst-fnmatch tst-regexloc tst-dir \
+- tst-chmod bug-regex1 bug-regex2 bug-regex3 bug-regex4 \
+- tst-gnuglob tst-regex bug-regex5 bug-regex6 bug-regex7 \
+- bug-regex8 bug-regex9 bug-regex10 bug-regex11 bug-regex12 \
+- bug-regex13 bug-regex14 bug-regex15 bug-regex16 \
+- bug-regex17 bug-regex18 bug-regex19 bug-regex20 \
+- bug-regex21 bug-regex22 bug-regex23 bug-regex24 \
+- bug-regex25 bug-regex26 bug-regex27 bug-regex28 \
+- bug-regex29 bug-regex30 bug-regex31 bug-regex32 \
+- bug-regex33 tst-nice tst-nanosleep tst-regex2 \
+- transbug tst-rxspencer tst-pcre tst-boost \
+- bug-ga1 tst-vfork1 tst-vfork2 tst-vfork3 tst-waitid \
+- tst-getaddrinfo2 bug-glob1 bug-glob2 bug-glob3 tst-sysconf \
++ tst-getlogin tst-mmap tst-truncate \
++ tst-truncate64 tst-fork tst-dir \
++ tst-chmod bug-regex2 bug-regex3 bug-regex4 \
++ tst-gnuglob bug-regex6 bug-regex7 \
++ bug-regex8 bug-regex9 bug-regex10 bug-regex12 \
++ bug-regex14 bug-regex15 \
++ bug-regex21 bug-regex24 \
++ bug-regex27 bug-regex28 bug-regex29 bug-regex30 \
++ bug-regex31 \
++ tst-nice tst-nanosleep \
++ transbug \
++ tst-vfork1 tst-vfork2 tst-vfork3 tst-waitid \
++ bug-glob1 bug-glob2 bug-glob3 tst-sysconf \
+ tst-execvp1 tst-execvp2 tst-execlp1 tst-execlp2 \
+ tst-execv1 tst-execv2 tst-execl1 tst-execl2 \
+ tst-execve1 tst-execve2 tst-execle1 tst-execle2 \
+- tst-execvp3 tst-execvp4 tst-rfc3484 tst-rfc3484-2 \
+- tst-rfc3484-3 \
+- tst-getaddrinfo3 tst-fnmatch2 tst-cpucount tst-cpuset \
++ tst-execvp3 tst-execvp4 \
++ tst-fnmatch2 tst-cpucount tst-cpuset \
+ bug-getopt1 bug-getopt2 bug-getopt3 bug-getopt4 \
+ bug-getopt5 tst-getopt_long1 bug-regex34 bug-regex35 \
+ tst-pathconf tst-getaddrinfo4 tst-rxspencer-no-utf8 \
+ tst-fnmatch3 bug-regex36
+-xtests := bug-ga2
++tests-$(OPTION_EGLIBC_LOCALE_CODE) \
++ += tst-fnmatch tst-regexloc bug-regex1 bug-regex5 \
++ bug-regex23 bug-regex25 bug-regex32 bug-regex33
++tests-$(OPTION_EGLIBC_INET) \
++ += tst-getaddrinfo bug-ga1 tst-getaddrinfo2 \
++ tst-rfc3484 tst-rfc3484-2 tst-rfc3484-3 tst-getaddrinfo3
++tests-$(OPTION_POSIX_REGEXP_GLIBC) \
++ += runptests bug-regex11 bug-regex13 bug-regex16 \
++ tst-regex2 tst-rxspencer tst-pcre tst-boost
++ifeq (yy,$(OPTION_EGLIBC_LOCALE_CODE)$(OPTION_POSIX_REGEXP_GLIBC))
++tests += tst-regex bug-regex17 bug-regex18 bug-regex19 bug-regex20 \
++ bug-regex22 bug-regex26
++endif
++xtests-$(OPTION_EGLIBC_INET) += bug-ga2
+ ifeq (yes,$(build-shared))
+ test-srcs := globtest
+-tests += wordexp-test tst-exec tst-spawn
++tests += tst-exec
++tests-$(OPTION_EGLIBC_SPAWN) += tst-spawn
++tests-$(OPTION_EGLIBC_WORDEXP) += wordexp-test
+ endif
+ tests-static = tst-exec-static tst-spawn-static
+ tests += $(tests-static)
+@@ -117,7 +142,10 @@
+
+ ifeq ($(run-built-tests),yes)
+ ifeq (yes,$(build-shared))
+-tests-special += $(objpfx)globtest.out $(objpfx)wordexp-tst.out
++tests-special += $(objpfx)globtest.out
++ifeq (y,$(OPTION_EGLIBC_WORDEXP))
++tests-special += $(objpfx)wordexp-tst.out
++endif
+ endif
+ endif
+
+@@ -125,12 +153,16 @@
+ # XXX Please note that for now we ignore the result of this test.
+ tests-special += $(objpfx)annexc.out
+ ifeq ($(run-built-tests),yes)
+-tests-special += $(objpfx)bug-regex2-mem.out $(objpfx)bug-regex14-mem.out \
++tests-special += $(objpfx)bug-regex2-mem.out \
+ $(objpfx)bug-regex21-mem.out $(objpfx)bug-regex31-mem.out \
+- $(objpfx)tst-rxspencer-no-utf8-mem.out $(objpfx)tst-pcre-mem.out \
+- $(objpfx)tst-boost-mem.out $(objpfx)tst-getconf.out \
++ $(objpfx)tst-getconf.out \
+ $(objpfx)bug-glob2-mem.out $(objpfx)tst-vfork3-mem.out \
+ $(objpfx)tst-fnmatch-mem.out $(objpfx)bug-regex36-mem.out
++ifeq (y,$(OPTION_POSIX_REGEXP_GLIBC))
++tests-special += $(objpfx)bug-regex14-mem.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 +175,8 @@
+ $(SHELL) $< $(common-objpfx) '$(test-via-rtld-prefix)' \
+ '$(test-program-prefix)' '$(test-wrapper-env)'; \
+ $(evaluate-test)
++LDLIBS-globtest += $(shell cat $(common-objpfx)nss/fixed-nsswitch-libs)
++
+ $(objpfx)wordexp-tst.out: wordexp-tst.sh $(objpfx)wordexp-test
+ $(SHELL) $< $(common-objpfx) '$(test-program-prefix-before-env)' \
+ '$(run-program-env)' '$(test-program-prefix-after-env)'; \
+@@ -205,7 +239,10 @@
+ tst-chmod-ARGS = $(objdir)
+ tst-vfork3-ARGS = --test-dir=$(objpfx)
+
+-tst-rxspencer-ARGS = --utf8 rxspencer/tests
++tst-rxspencer-ARGS = rxspencer/tests
++ifeq (y,$(OPTION_EGLIBC_LOCALE_CODE))
++tst-rxspencer-ARGS += --utf8
++endif
+ tst-rxspencer-no-utf8-ARGS = rxspencer/tests
+ tst-pcre-ARGS = PCRE.tests
+ tst-boost-ARGS = BOOST.tests
+diff -Naur glibc-2.20/posix/regcomp.c glibc-2.20-patch/posix/regcomp.c
+--- glibc-2.20/posix/regcomp.c 2014-09-07 03:09:09.000000000 -0500
++++ glibc-2.20-patch/posix/regcomp.c 2015-03-04 00:51:32.387952006 -0600
+@@ -18,6 +18,7 @@
+ <http://www.gnu.org/licenses/>. */
+
+ #include <stdint.h>
++#include <gnu/option-groups.h>
+
+ static reg_errcode_t re_compile_internal (regex_t *preg, const char * pattern,
+ size_t length, reg_syntax_t syntax);
+@@ -305,7 +306,7 @@
+ {
+ re_dfa_t *dfa = (re_dfa_t *) bufp->buffer;
+ int node_cnt;
+- int icase = (dfa->mb_cur_max == 1 && (bufp->syntax & RE_ICASE));
++ int icase = (dfa_mb_cur_max (dfa) == 1 && (bufp->syntax & RE_ICASE));
+ for (node_cnt = 0; node_cnt < init_state->nodes.nelem; ++node_cnt)
+ {
+ int node = init_state->nodes.elems[node_cnt];
+@@ -315,9 +316,9 @@
+ {
+ re_set_fastmap (fastmap, icase, dfa->nodes[node].opr.c);
+ #ifdef RE_ENABLE_I18N
+- if ((bufp->syntax & RE_ICASE) && dfa->mb_cur_max > 1)
++ if ((bufp->syntax & RE_ICASE) && dfa_mb_cur_max (dfa) > 1)
+ {
+- unsigned char *buf = alloca (dfa->mb_cur_max), *p;
++ unsigned char *buf = alloca (dfa_mb_cur_max (dfa)), *p;
+ wchar_t wc;
+ mbstate_t state;
+
+@@ -348,7 +349,11 @@
+ re_set_fastmap (fastmap, icase, ch);
+ }
+ }
+-#ifdef RE_ENABLE_I18N
++
++ /* When OPTION_EGLIBC_LOCALE_CODE is disabled, the current
++ locale is always C, which has no rules and no multi-byte
++ characters. */
++#if defined RE_ENABLE_I18N && __OPTION_EGLIBC_LOCALE_CODE
+ else if (type == COMPLEX_BRACKET)
+ {
+ re_charset_t *cset = dfa->nodes[node].opr.mbcset;
+@@ -376,7 +381,7 @@
+ i.e. where we would not find an invalid sequence. This only
+ applies to multibyte character sets; for single byte character
+ sets, the SIMPLE_BRACKET again suffices. */
+- if (dfa->mb_cur_max > 1
++ if (dfa_mb_cur_max (dfa) > 1
+ && (cset->nchar_classes || cset->non_match || cset->nranges
+ # ifdef _LIBC
+ || cset->nequiv_classes
+@@ -404,7 +409,7 @@
+ memset (&state, '\0', sizeof (state));
+ if (__wcrtomb (buf, cset->mbchars[i], &state) != (size_t) -1)
+ re_set_fastmap (fastmap, icase, *(unsigned char *) buf);
+- if ((bufp->syntax & RE_ICASE) && dfa->mb_cur_max > 1)
++ if ((bufp->syntax & RE_ICASE) && dfa_mb_cur_max (dfa) > 1)
+ {
+ if (__wcrtomb (buf, towlower (cset->mbchars[i]), &state)
+ != (size_t) -1)
+@@ -413,7 +418,7 @@
+ }
+ }
+ }
+-#endif /* RE_ENABLE_I18N */
++#endif /* RE_ENABLE_I18N && __OPTION_EGLIBC_LOCALE_CODE */
+ else if (type == OP_PERIOD
+ #ifdef RE_ENABLE_I18N
+ || type == OP_UTF8_PERIOD
+@@ -856,11 +861,15 @@
+
+ dfa->mb_cur_max = MB_CUR_MAX;
+ #ifdef _LIBC
+- if (dfa->mb_cur_max == 6
++ if (dfa_mb_cur_max (dfa) == 6
+ && strcmp (_NL_CURRENT (LC_CTYPE, _NL_CTYPE_CODESET_NAME), "UTF-8") == 0)
+ dfa->is_utf8 = 1;
++# if __OPTION_EGLIBC_LOCALE_CODE
+ dfa->map_notascii = (_NL_CURRENT_WORD (LC_CTYPE, _NL_CTYPE_MAP_TO_NONASCII)
+ != 0);
++# else
++ dfa->map_notascii = 0;
++# endif
+ #else
+ # ifdef HAVE_LANGINFO_CODESET
+ codeset_name = nl_langinfo (CODESET);
+@@ -886,7 +895,7 @@
+ #endif
+
+ #ifdef RE_ENABLE_I18N
+- if (dfa->mb_cur_max > 1)
++ if (dfa_mb_cur_max (dfa) > 1)
+ {
+ if (dfa->is_utf8)
+ dfa->sb_char = (re_bitset_ptr_t) utf8_sb_map;
+@@ -1784,7 +1793,7 @@
+ token->word_char = 0;
+ #ifdef RE_ENABLE_I18N
+ token->mb_partial = 0;
+- if (input->mb_cur_max > 1 &&
++ if (string_mb_cur_max (input) > 1 &&
+ !re_string_first_byte (input, re_string_cur_idx (input)))
+ {
+ token->type = CHARACTER;
+@@ -1805,7 +1814,7 @@
+ token->opr.c = c2;
+ token->type = CHARACTER;
+ #ifdef RE_ENABLE_I18N
+- if (input->mb_cur_max > 1)
++ if (string_mb_cur_max (input) > 1)
+ {
+ wint_t wc = re_string_wchar_at (input,
+ re_string_cur_idx (input) + 1);
+@@ -1919,7 +1928,7 @@
+
+ token->type = CHARACTER;
+ #ifdef RE_ENABLE_I18N
+- if (input->mb_cur_max > 1)
++ if (string_mb_cur_max (input) > 1)
+ {
+ wint_t wc = re_string_wchar_at (input, re_string_cur_idx (input));
+ token->word_char = IS_WIDE_WORD_CHAR (wc) != 0;
+@@ -2019,7 +2028,7 @@
+ token->opr.c = c;
+
+ #ifdef RE_ENABLE_I18N
+- if (input->mb_cur_max > 1 &&
++ if (string_mb_cur_max (input) > 1 &&
+ !re_string_first_byte (input, re_string_cur_idx (input)))
+ {
+ token->type = CHARACTER;
+@@ -2242,7 +2251,7 @@
+ return NULL;
+ }
+ #ifdef RE_ENABLE_I18N
+- if (dfa->mb_cur_max > 1)
++ if (dfa_mb_cur_max (dfa) > 1)
+ {
+ while (!re_string_eoi (regexp)
+ && !re_string_first_byte (regexp, re_string_cur_idx (regexp)))
+@@ -2380,7 +2389,7 @@
+ *err = REG_ESPACE;
+ return NULL;
+ }
+- if (dfa->mb_cur_max > 1)
++ if (dfa_mb_cur_max (dfa) > 1)
+ dfa->has_mb_node = 1;
+ break;
+ case OP_WORD:
+@@ -2686,7 +2695,7 @@
+ However, for !_LIBC we have no collation elements: if the
+ character set is single byte, the single byte character set
+ that we build below suffices. parse_bracket_exp passes
+- no MBCSET if dfa->mb_cur_max == 1. */
++ no MBCSET if dfa_mb_cur_max (dfa) == 1. */
+ if (mbcset)
+ {
+ /* Check the space of the arrays. */
+@@ -2782,7 +2791,13 @@
+ reg_syntax_t syntax, reg_errcode_t *err)
+ {
+ #ifdef _LIBC
++#if __OPTION_EGLIBC_LOCALE_CODE
+ const unsigned char *collseqmb;
++# define COLLSEQMB_LOOKUP(ix) (collseqmb[(ix)])
++#else
++# define COLLSEQMB_LOOKUP(ix) (ix)
++#endif
++
+ const char *collseqwc;
+ uint32_t nrules;
+ int32_t table_size;
+@@ -2830,18 +2845,20 @@
+ if (MB_CUR_MAX == 1)
+ */
+ if (nrules == 0)
+- return collseqmb[br_elem->opr.ch];
++ return COLLSEQMB_LOOKUP (br_elem->opr.ch);
+ else
+ {
+ wint_t wc = __btowc (br_elem->opr.ch);
+ return __collseq_table_lookup (collseqwc, wc);
+ }
+ }
++#if __OPTION_EGLIBC_LOCALE_CODE
+ else if (br_elem->type == MB_CHAR)
+ {
+ if (nrules != 0)
+ return __collseq_table_lookup (collseqwc, br_elem->opr.wch);
+ }
++#endif
+ else if (br_elem->type == COLL_SYM)
+ {
+ size_t sym_name_len = strlen ((char *) br_elem->opr.name);
+@@ -2872,11 +2889,11 @@
+ {
+ /* No valid character. Match it as a single byte
+ character. */
+- return collseqmb[br_elem->opr.name[0]];
++ return COLLSEQMB_LOOKUP (br_elem->opr.name[0]);
+ }
+ }
+ else if (sym_name_len == 1)
+- return collseqmb[br_elem->opr.name[0]];
++ return COLLSEQMB_LOOKUP (br_elem->opr.name[0]);
+ }
+ return UINT_MAX;
+ }
+@@ -2916,7 +2933,7 @@
+ However, if we have no collation elements, and the character set
+ is single byte, the single byte character set that we
+ build below suffices. */
+- if (nrules > 0 || dfa->mb_cur_max > 1)
++ if (nrules > 0 || dfa_mb_cur_max (dfa) > 1)
+ {
+ /* Check the space of the arrays. */
+ if (BE (*range_alloc == mbcset->nranges, 0))
+@@ -2953,7 +2970,7 @@
+ if (MB_CUR_MAX == 1)
+ */
+ if (nrules == 0)
+- ch_collseq = collseqmb[ch];
++ ch_collseq = COLLSEQMB_LOOKUP (ch);
+ else
+ ch_collseq = __collseq_table_lookup (collseqwc, __btowc (ch));
+ if (start_collseq <= ch_collseq && ch_collseq <= end_collseq)
+@@ -3031,7 +3048,10 @@
+ re_bitset_ptr_t sbcset;
+ #ifdef RE_ENABLE_I18N
+ re_charset_t *mbcset;
+- int coll_sym_alloc = 0, range_alloc = 0, mbchar_alloc = 0;
++ int coll_sym_alloc = 0, range_alloc = 0;
++#if __OPTION_EGLIBC_LOCALE_CODE
++ int mbchar_alloc = 0;
++#endif
+ int equiv_class_alloc = 0, char_class_alloc = 0;
+ #endif /* not RE_ENABLE_I18N */
+ int non_match = 0;
+@@ -3039,9 +3059,15 @@
+ int token_len;
+ int first_round = 1;
+ #ifdef _LIBC
++#if __OPTION_EGLIBC_LOCALE_CODE
+ collseqmb = (const unsigned char *)
+ _NL_CURRENT (LC_COLLATE, _NL_COLLATE_COLLSEQMB);
+ nrules = _NL_CURRENT_WORD (LC_COLLATE, _NL_COLLATE_NRULES);
++#else
++ /* This is true when OPTION_EGLIBC_LOCALE_CODE is disabled, but the
++ compiler can't figure that out. */
++ nrules = 0;
++#endif
+ if (nrules)
+ {
+ /*
+@@ -3169,7 +3195,7 @@
+ #else
+ # ifdef RE_ENABLE_I18N
+ *err = build_range_exp (sbcset,
+- dfa->mb_cur_max > 1 ? mbcset : NULL,
++ dfa_mb_cur_max (dfa) > 1 ? mbcset : NULL,
+ &range_alloc, &start_elem, &end_elem);
+ # else
+ *err = build_range_exp (sbcset, &start_elem, &end_elem);
+@@ -3185,7 +3211,7 @@
+ case SB_CHAR:
+ bitset_set (sbcset, start_elem.opr.ch);
+ break;
+-#ifdef RE_ENABLE_I18N
++#if defined RE_ENABLE_I18N && __OPTION_EGLIBC_LOCALE_CODE
+ case MB_CHAR:
+ /* Check whether the array has enough space. */
+ if (BE (mbchar_alloc == mbcset->nmbchars, 0))
+@@ -3203,7 +3229,7 @@
+ }
+ mbcset->mbchars[mbcset->nmbchars++] = start_elem.opr.wch;
+ break;
+-#endif /* RE_ENABLE_I18N */
++#endif /* RE_ENABLE_I18N && __OPTION_EGLIBC_LOCALE_CODE */
+ case EQUIV_CLASS:
+ *err = build_equiv_class (sbcset,
+ #ifdef RE_ENABLE_I18N
+@@ -3253,11 +3279,11 @@
+
+ #ifdef RE_ENABLE_I18N
+ /* Ensure only single byte characters are set. */
+- if (dfa->mb_cur_max > 1)
++ if (dfa_mb_cur_max (dfa) > 1)
+ bitset_mask (sbcset, dfa->sb_char);
+
+ if (mbcset->nmbchars || mbcset->ncoll_syms || mbcset->nequiv_classes
+- || mbcset->nranges || (dfa->mb_cur_max > 1 && (mbcset->nchar_classes
++ || mbcset->nranges || (dfa_mb_cur_max (dfa) > 1 && (mbcset->nchar_classes
+ || mbcset->non_match)))
+ {
+ bin_tree_t *mbc_tree;
+@@ -3326,7 +3352,7 @@
+ re_token_t *token, int token_len, re_dfa_t *dfa,
+ reg_syntax_t syntax, int accept_hyphen)
+ {
+-#ifdef RE_ENABLE_I18N
++#if defined RE_ENABLE_I18N && __OPTION_EGLIBC_LOCALE_CODE
+ int cur_char_size;
+ cur_char_size = re_string_char_size_at (regexp, re_string_cur_idx (regexp));
+ if (cur_char_size > 1)
+@@ -3336,7 +3362,7 @@
+ re_string_skip_bytes (regexp, cur_char_size);
+ return REG_NOERROR;
+ }
+-#endif /* RE_ENABLE_I18N */
++#endif /* RE_ENABLE_I18N && __OPTION_EGLIBC_LOCALE_CODE */
+ re_string_skip_bytes (regexp, token_len); /* Skip a token. */
+ if (token->type == OP_OPEN_COLL_ELEM || token->type == OP_OPEN_CHAR_CLASS
+ || token->type == OP_OPEN_EQUIV_CLASS)
+@@ -3416,7 +3442,9 @@
+ build_equiv_class (bitset_t sbcset, const unsigned char *name)
+ #endif /* not RE_ENABLE_I18N */
+ {
+-#ifdef _LIBC
++ /* When __OPTION_EGLIBC_LOCALE_CODE is disabled, only the C locale
++ is supported; it has no collation rules. */
++#if defined _LIBC && __OPTION_EGLIBC_LOCALE_CODE
+ uint32_t nrules = _NL_CURRENT_WORD (LC_COLLATE, _NL_COLLATE_NRULES);
+ if (nrules != 0)
+ {
+@@ -3488,7 +3516,7 @@
+ mbcset->equiv_classes[mbcset->nequiv_classes++] = idx1;
+ }
+ else
+-#endif /* _LIBC */
++#endif /* _LIBC && __OPTION_EGLIBC_LOCALE_CODE */
+ {
+ if (BE (strlen ((const char *) name) != 1, 0))
+ return REG_ECOLLATE;
+@@ -3522,7 +3550,7 @@
+ && (strcmp (name, "upper") == 0 || strcmp (name, "lower") == 0))
+ name = "alpha";
+
+-#ifdef RE_ENABLE_I18N
++#if defined RE_ENABLE_I18N && __OPTION_EGLIBC_LOCALE_CODE
+ /* Check the space of the arrays. */
+ if (BE (*char_class_alloc == mbcset->nchar_classes, 0))
+ {
+@@ -3538,7 +3566,7 @@
+ *char_class_alloc = new_char_class_alloc;
+ }
+ mbcset->char_classes[mbcset->nchar_classes++] = __wctype (name);
+-#endif /* RE_ENABLE_I18N */
++#endif /* RE_ENABLE_I18N && __OPTION_EGLIBC_LOCALE_CODE */
+
+ #define BUILD_CHARCLASS_LOOP(ctype_func) \
+ do { \
+@@ -3649,7 +3677,7 @@
+
+ #ifdef RE_ENABLE_I18N
+ /* Ensure only single byte characters are set. */
+- if (dfa->mb_cur_max > 1)
++ if (dfa_mb_cur_max (dfa) > 1)
+ bitset_mask (sbcset, dfa->sb_char);
+ #endif
+
+@@ -3661,7 +3689,7 @@
+ goto build_word_op_espace;
+
+ #ifdef RE_ENABLE_I18N
+- if (dfa->mb_cur_max > 1)
++ if (dfa_mb_cur_max (dfa) > 1)
+ {
+ bin_tree_t *mbc_tree;
+ /* Build a tree for complex bracket. */
+diff -Naur glibc-2.20/posix/regexec.c glibc-2.20-patch/posix/regexec.c
+--- glibc-2.20/posix/regexec.c 2014-09-07 03:09:09.000000000 -0500
++++ glibc-2.20-patch/posix/regexec.c 2015-03-04 00:51:32.387952006 -0600
+@@ -18,6 +18,7 @@
+ <http://www.gnu.org/licenses/>. */
+
+ #include <stdint.h>
++#include <gnu/option-groups.h>
+
+ static reg_errcode_t match_ctx_init (re_match_context_t *cache, int eflags,
+ int n) internal_function;
+@@ -186,11 +187,11 @@
+ static int check_node_accept_bytes (const re_dfa_t *dfa, int node_idx,
+ const re_string_t *input, int idx)
+ internal_function;
+-# ifdef _LIBC
++# if defined _LIBC && __OPTION_EGLIBC_LOCALE_CODE
+ static unsigned int find_collation_sequence_value (const unsigned char *mbs,
+ size_t name_len)
+ internal_function;
+-# endif /* _LIBC */
++# endif /* _LIBC && __OPTION_EGLIBC_LOCALE_CODE */
+ #endif /* RE_ENABLE_I18N */
+ static int group_nodes_into_DFAstates (const re_dfa_t *dfa,
+ const re_dfastate_t *state,
+@@ -255,25 +256,9 @@
+ return err != REG_NOERROR;
+ }
+
+-#ifdef _LIBC
+-# include <shlib-compat.h>
+-versioned_symbol (libc, __regexec, regexec, GLIBC_2_3_4);
+-
+-# if SHLIB_COMPAT (libc, GLIBC_2_0, GLIBC_2_3_4)
+-__typeof__ (__regexec) __compat_regexec;
+-
+-int
+-attribute_compat_text_section
+-__compat_regexec (const regex_t *__restrict preg,
+- const char *__restrict string, size_t nmatch,
+- regmatch_t pmatch[], int eflags)
+-{
+- return regexec (preg, string, nmatch, pmatch,
+- eflags & (REG_NOTBOL | REG_NOTEOL));
+-}
+-compat_symbol (libc, __compat_regexec, regexec, GLIBC_2_0);
+-# endif
+-#endif
++/* EGLIBC: The code that used to be here was move to a separate file
++ so that it can be shared with xregex.c. */
++#include "regexec-compat.c"
+
+ /* Entry points for GNU code. */
+
+@@ -728,7 +713,7 @@
+ incr = (range < 0) ? -1 : 1;
+ left_lim = (range < 0) ? start + range : start;
+ right_lim = (range < 0) ? start : start + range;
+- sb = dfa->mb_cur_max == 1;
++ sb = dfa_mb_cur_max (dfa) == 1;
+ match_kind =
+ (fastmap
+ ? ((sb || !(preg->syntax & RE_ICASE || t) ? 4 : 0)
+@@ -3448,7 +3433,7 @@
+ if (BE (dest_states_word[i] == NULL && err != REG_NOERROR, 0))
+ goto out_free;
+
+- if (dest_states[i] != dest_states_word[i] && dfa->mb_cur_max > 1)
++ if (dest_states[i] != dest_states_word[i] && dfa_mb_cur_max (dfa) > 1)
+ need_word_trtable = 1;
+
+ dest_states_nl[i] = re_acquire_state_context (&err, dfa, &follows,
+@@ -3590,7 +3575,7 @@
+ else if (type == OP_PERIOD)
+ {
+ #ifdef RE_ENABLE_I18N
+- if (dfa->mb_cur_max > 1)
++ if (dfa_mb_cur_max (dfa) > 1)
+ bitset_merge (accepts, dfa->sb_char);
+ else
+ #endif
+@@ -3641,7 +3626,7 @@
+ continue;
+ }
+ #ifdef RE_ENABLE_I18N
+- if (dfa->mb_cur_max > 1)
++ if (dfa_mb_cur_max (dfa) > 1)
+ for (j = 0; j < BITSET_WORDS; ++j)
+ any_set |= (accepts[j] &= (dfa->word_char[j] | ~dfa->sb_char[j]));
+ else
+@@ -3660,7 +3645,7 @@
+ continue;
+ }
+ #ifdef RE_ENABLE_I18N
+- if (dfa->mb_cur_max > 1)
++ if (dfa_mb_cur_max (dfa) > 1)
+ for (j = 0; j < BITSET_WORDS; ++j)
+ any_set |= (accepts[j] &= ~(dfa->word_char[j] & dfa->sb_char[j]));
+ else
+@@ -3832,12 +3817,6 @@
+ if (node->type == COMPLEX_BRACKET)
+ {
+ const re_charset_t *cset = node->opr.mbcset;
+-# ifdef _LIBC
+- const unsigned char *pin
+- = ((const unsigned char *) re_string_get_buffer (input) + str_idx);
+- int j;
+- uint32_t nrules;
+-# endif /* _LIBC */
+ int match_len = 0;
+ wchar_t wc = ((cset->nranges || cset->nchar_classes || cset->nmbchars)
+ ? re_string_wchar_at (input, str_idx) : 0);
+@@ -3849,6 +3828,7 @@
+ match_len = char_len;
+ goto check_node_accept_bytes_match;
+ }
++#if __OPTION_EGLIBC_LOCALE_CODE
+ /* match with character_class? */
+ for (i = 0; i < cset->nchar_classes; ++i)
+ {
+@@ -3859,8 +3839,16 @@
+ goto check_node_accept_bytes_match;
+ }
+ }
++#endif
++
++ /* When __OPTION_EGLIBC_LOCALE_CODE is disabled, only the C
++ locale is supported; it has no collation rules. */
++# if defined _LIBC && __OPTION_EGLIBC_LOCALE_CODE
++ const unsigned char *pin
++ = ((const unsigned char *) re_string_get_buffer (input) + str_idx);
++ int j;
++ uint32_t nrules;
+
+-# ifdef _LIBC
+ nrules = _NL_CURRENT_WORD (LC_COLLATE, _NL_COLLATE_NRULES);
+ if (nrules != 0)
+ {
+@@ -3953,8 +3941,12 @@
+ }
+ }
+ else
+-# endif /* _LIBC */
++# endif /* _LIBC && __OPTION_EGLIBC_LOCALE_CODE */
+ {
++ /* In the _LIBC version, if OPTION_EGLIBC_LOCALE_CODE is
++ disabled, there can be no multibyte range endpoints, and
++ cset->nranges is always zero. */
++#if __OPTION_EGLIBC_LOCALE_CODE
+ /* match with range expression? */
+ #if __GNUC__ >= 2
+ wchar_t cmp_buf[] = {L'\0', L'\0', wc, L'\0', L'\0', L'\0'};
+@@ -3973,6 +3965,7 @@
+ goto check_node_accept_bytes_match;
+ }
+ }
++#endif /* __OPTION_EGLIBC_LOCALE_CODE */
+ }
+ check_node_accept_bytes_match:
+ if (!cset->non_match)
+@@ -3988,7 +3981,7 @@
+ return 0;
+ }
+
+-# ifdef _LIBC
++# if defined _LIBC && __OPTION_EGLIBC_LOCALE_CODE
+ static unsigned int
+ internal_function
+ find_collation_sequence_value (const unsigned char *mbs, size_t mbs_len)
+@@ -4046,7 +4039,7 @@
+ return UINT_MAX;
+ }
+ }
+-# endif /* _LIBC */
++# endif /* _LIBC && __OPTION_EGLIBC_LOCALE_CODE */
+ #endif /* RE_ENABLE_I18N */
+
+ /* Check whether the node accepts the byte which is IDX-th
+@@ -4137,7 +4130,7 @@
+ if (pstr->icase)
+ {
+ #ifdef RE_ENABLE_I18N
+- if (pstr->mb_cur_max > 1)
++ if (string_mb_cur_max (pstr) > 1)
+ {
+ ret = build_wcs_upper_buffer (pstr);
+ if (BE (ret != REG_NOERROR, 0))
+@@ -4150,7 +4143,7 @@
+ else
+ {
+ #ifdef RE_ENABLE_I18N
+- if (pstr->mb_cur_max > 1)
++ if (string_mb_cur_max (pstr) > 1)
+ build_wcs_buffer (pstr);
+ else
+ #endif /* RE_ENABLE_I18N */
+diff -Naur glibc-2.20/posix/regexec-compat.c glibc-2.20-patch/posix/regexec-compat.c
+--- glibc-2.20/posix/regexec-compat.c 1969-12-31 18:00:00.000000000 -0600
++++ glibc-2.20-patch/posix/regexec-compat.c 2015-03-04 00:51:32.388952006 -0600
+@@ -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 at 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 -Naur glibc-2.20/posix/regex.h glibc-2.20-patch/posix/regex.h
+--- glibc-2.20/posix/regex.h 2014-09-07 03:09:09.000000000 -0500
++++ glibc-2.20-patch/posix/regex.h 2015-03-04 00:51:32.388952006 -0600
+@@ -21,6 +21,7 @@
+ #define _REGEX_H 1
+
+ #include <sys/types.h>
++#include <gnu/option-groups.h>
+
+ /* Allow the use in C++ code. */
+ #ifdef __cplusplus
+@@ -156,6 +157,8 @@
+ treated as 'a\{1'. */
+ # define RE_INVALID_INTERVAL_ORD (RE_DEBUG << 1)
+
++/* EGLIBC: Old regex implementation does not support these. */
++# ifdef __OPTION_POSIX_REGEXP_GLIBC
+ /* If this bit is set, then ignore case when matching.
+ If not set, then case is significant. */
+ # define RE_ICASE (RE_INVALID_INTERVAL_ORD << 1)
+@@ -172,6 +175,7 @@
+ /* If this bit is set, then no_sub will be set to 1 during
+ re_compile_pattern. */
+ # define RE_NO_SUB (RE_CONTEXT_INVALID_DUP << 1)
++# endif /* __OPTION_POSIX_REGEXP_GLIBC */
+ #endif
+
+ /* This global variable defines the particular regexp syntax to use (for
+@@ -231,8 +235,13 @@
+ (RE_CHAR_CLASSES | RE_DOT_NEWLINE | RE_DOT_NOT_NULL \
+ | RE_INTERVALS | RE_NO_EMPTY_RANGES)
+
++#ifdef __OPTION_POSIX_REGEXP_GLIBC
+ #define RE_SYNTAX_POSIX_BASIC \
+ (_RE_SYNTAX_POSIX_COMMON | RE_BK_PLUS_QM | RE_CONTEXT_INVALID_DUP)
++#else
++#define RE_SYNTAX_POSIX_BASIC \
++ (_RE_SYNTAX_POSIX_COMMON | RE_BK_PLUS_QM)
++#endif
+
+ /* Differs from ..._POSIX_BASIC only in that RE_BK_PLUS_QM becomes
+ RE_LIMITED_OPS, i.e., \? \+ \| are not recognized. Actually, this
+@@ -298,9 +307,11 @@
+ /* Like REG_NOTBOL, except for the end-of-line. */
+ #define REG_NOTEOL (1 << 1)
+
++#ifdef __OPTION_POSIX_REGEXP_GLIBC
+ /* Use PMATCH[0] to delimit the start and end of the search in the
+ buffer. */
+ #define REG_STARTEND (1 << 2)
++#endif
+
+
+ /* If any error codes are removed, changed, or added, update the
+diff -Naur glibc-2.20/posix/regex_internal.c glibc-2.20-patch/posix/regex_internal.c
+--- glibc-2.20/posix/regex_internal.c 2014-09-07 03:09:09.000000000 -0500
++++ glibc-2.20-patch/posix/regex_internal.c 2015-03-04 00:51:32.388952006 -0600
+@@ -43,8 +43,8 @@
+ int init_buf_len;
+
+ /* Ensure at least one character fits into the buffers. */
+- if (init_len < dfa->mb_cur_max)
+- init_len = dfa->mb_cur_max;
++ if (init_len < dfa_mb_cur_max (dfa))
++ init_len = dfa_mb_cur_max (dfa);
+ init_buf_len = (len + 1 < init_len) ? len + 1: init_len;
+ re_string_construct_common (str, len, pstr, trans, icase, dfa);
+
+@@ -55,7 +55,7 @@
+ pstr->word_char = dfa->word_char;
+ pstr->word_ops_used = dfa->word_ops_used;
+ pstr->mbs = pstr->mbs_allocated ? pstr->mbs : (unsigned char *) str;
+- pstr->valid_len = (pstr->mbs_allocated || dfa->mb_cur_max > 1) ? 0 : len;
++ pstr->valid_len = (pstr->mbs_allocated || dfa_mb_cur_max (dfa) > 1) ? 0 : len;
+ pstr->valid_raw_len = pstr->valid_len;
+ return REG_NOERROR;
+ }
+@@ -82,7 +82,7 @@
+ if (icase)
+ {
+ #ifdef RE_ENABLE_I18N
+- if (dfa->mb_cur_max > 1)
++ if (dfa_mb_cur_max (dfa) > 1)
+ {
+ while (1)
+ {
+@@ -91,7 +91,7 @@
+ return ret;
+ if (pstr->valid_raw_len >= len)
+ break;
+- if (pstr->bufs_len > pstr->valid_len + dfa->mb_cur_max)
++ if (pstr->bufs_len > pstr->valid_len + dfa_mb_cur_max (dfa))
+ break;
+ ret = re_string_realloc_buffers (pstr, pstr->bufs_len * 2);
+ if (BE (ret != REG_NOERROR, 0))
+@@ -105,7 +105,7 @@
+ else
+ {
+ #ifdef RE_ENABLE_I18N
+- if (dfa->mb_cur_max > 1)
++ if (dfa_mb_cur_max (dfa) > 1)
+ build_wcs_buffer (pstr);
+ else
+ #endif /* RE_ENABLE_I18N */
+@@ -130,7 +130,7 @@
+ re_string_realloc_buffers (re_string_t *pstr, int new_buf_len)
+ {
+ #ifdef RE_ENABLE_I18N
+- if (pstr->mb_cur_max > 1)
++ if (string_mb_cur_max (pstr) > 1)
+ {
+ wint_t *new_wcs;
+
+@@ -177,7 +177,7 @@
+ pstr->trans = trans;
+ pstr->icase = icase ? 1 : 0;
+ pstr->mbs_allocated = (trans != NULL || icase);
+- pstr->mb_cur_max = dfa->mb_cur_max;
++ pstr->mb_cur_max = dfa_mb_cur_max (dfa);
+ pstr->is_utf8 = dfa->is_utf8;
+ pstr->map_notascii = dfa->map_notascii;
+ pstr->stop = pstr->len;
+@@ -203,7 +203,7 @@
+ {
+ #ifdef _LIBC
+ unsigned char buf[MB_LEN_MAX];
+- assert (MB_LEN_MAX >= pstr->mb_cur_max);
++ assert (MB_LEN_MAX >= string_mb_cur_max (pstr));
+ #else
+ unsigned char buf[64];
+ #endif
+@@ -226,7 +226,7 @@
+ {
+ int i, ch;
+
+- for (i = 0; i < pstr->mb_cur_max && i < remain_len; ++i)
++ for (i = 0; i < string_mb_cur_max (pstr) && i < remain_len; ++i)
+ {
+ ch = pstr->raw_mbs [pstr->raw_mbs_idx + byte_idx + i];
+ buf[i] = pstr->mbs[byte_idx + i] = pstr->trans[ch];
+@@ -275,7 +275,7 @@
+ size_t mbclen;
+ #ifdef _LIBC
+ char buf[MB_LEN_MAX];
+- assert (MB_LEN_MAX >= pstr->mb_cur_max);
++ assert (MB_LEN_MAX >= string_mb_cur_max (pstr));
+ #else
+ char buf[64];
+ #endif
+@@ -369,7 +369,7 @@
+ {
+ int i, ch;
+
+- for (i = 0; i < pstr->mb_cur_max && i < remain_len; ++i)
++ for (i = 0; i < string_mb_cur_max (pstr) && i < remain_len; ++i)
+ {
+ ch = pstr->raw_mbs [pstr->raw_mbs_idx + src_idx + i];
+ buf[i] = pstr->trans[ch];
+@@ -567,8 +567,9 @@
+ }
+
+ /* This function re-construct the buffers.
+- Concretely, convert to wide character in case of pstr->mb_cur_max > 1,
+- convert to upper case in case of REG_ICASE, apply translation. */
++ Concretely, convert to wide character in case of
++ string_mb_cur_max (pstr) > 1, convert to upper case in case of
++ REG_ICASE, apply translation. */
+
+ static reg_errcode_t
+ internal_function __attribute_warn_unused_result__
+@@ -579,7 +580,7 @@
+ {
+ /* Reset buffer. */
+ #ifdef RE_ENABLE_I18N
+- if (pstr->mb_cur_max > 1)
++ if (string_mb_cur_max (pstr) > 1)
+ memset (&pstr->cur_state, '\0', sizeof (mbstate_t));
+ #endif /* RE_ENABLE_I18N */
+ pstr->len = pstr->raw_len;
+@@ -670,7 +671,7 @@
+ pstr->tip_context = re_string_context_at (pstr, offset - 1,
+ eflags);
+ #ifdef RE_ENABLE_I18N
+- if (pstr->mb_cur_max > 1)
++ if (string_mb_cur_max (pstr) > 1)
+ memmove (pstr->wcs, pstr->wcs + offset,
+ (pstr->valid_len - offset) * sizeof (wint_t));
+ #endif /* RE_ENABLE_I18N */
+@@ -699,7 +700,7 @@
+ #endif
+ pstr->valid_len = 0;
+ #ifdef RE_ENABLE_I18N
+- if (pstr->mb_cur_max > 1)
++ if (string_mb_cur_max (pstr) > 1)
+ {
+ int wcs_idx;
+ wint_t wc = WEOF;
+@@ -711,7 +712,7 @@
+ /* Special case UTF-8. Multi-byte chars start with any
+ byte other than 0x80 - 0xbf. */
+ raw = pstr->raw_mbs + pstr->raw_mbs_idx;
+- end = raw + (offset - pstr->mb_cur_max);
++ end = raw + (offset - string_mb_cur_max (pstr));
+ if (end < pstr->raw_mbs)
+ end = pstr->raw_mbs;
+ p = raw + offset - 1;
+@@ -803,7 +804,7 @@
+
+ /* Then build the buffers. */
+ #ifdef RE_ENABLE_I18N
+- if (pstr->mb_cur_max > 1)
++ if (string_mb_cur_max (pstr) > 1)
+ {
+ if (pstr->icase)
+ {
+@@ -841,7 +842,7 @@
+ return re_string_peek_byte (pstr, idx);
+
+ #ifdef RE_ENABLE_I18N
+- if (pstr->mb_cur_max > 1
++ if (string_mb_cur_max (pstr) > 1
+ && ! re_string_is_single_byte_char (pstr, pstr->cur_idx + idx))
+ return re_string_peek_byte (pstr, idx);
+ #endif
+@@ -930,7 +931,7 @@
+ return ((eflags & REG_NOTEOL) ? CONTEXT_ENDBUF
+ : CONTEXT_NEWLINE | CONTEXT_ENDBUF);
+ #ifdef RE_ENABLE_I18N
+- if (input->mb_cur_max > 1)
++ if (string_mb_cur_max (input) > 1)
+ {
+ wint_t wc;
+ int wc_idx = idx;
+@@ -1444,7 +1445,7 @@
+ dfa->nodes[dfa->nodes_len].constraint = 0;
+ #ifdef RE_ENABLE_I18N
+ dfa->nodes[dfa->nodes_len].accept_mb =
+- (type == OP_PERIOD && dfa->mb_cur_max > 1) || type == COMPLEX_BRACKET;
++ (type == OP_PERIOD && dfa_mb_cur_max (dfa) > 1) || type == COMPLEX_BRACKET;
+ #endif
+ dfa->nexts[dfa->nodes_len] = -1;
+ re_node_set_init_empty (dfa->edests + dfa->nodes_len);
+diff -Naur glibc-2.20/posix/regex_internal.h glibc-2.20-patch/posix/regex_internal.h
+--- glibc-2.20/posix/regex_internal.h 2014-09-07 03:09:09.000000000 -0500
++++ glibc-2.20-patch/posix/regex_internal.h 2015-03-04 00:51:32.388952006 -0600
+@@ -26,6 +26,10 @@
+ #include <stdlib.h>
+ #include <string.h>
+
++#if defined _LIBC
++# include <gnu/option-groups.h>
++#endif
++
+ #if defined HAVE_LANGINFO_H || defined HAVE_LANGINFO_CODESET || defined _LIBC
+ # include <langinfo.h>
+ #endif
+@@ -370,6 +374,13 @@
+ };
+ typedef struct re_string_t re_string_t;
+
++/* When OPTION_EGLIBC_LOCALE_CODE is disabled, this is always 1;
++ help the compiler make use of that fact. */
++#if __OPTION_EGLIBC_LOCALE_CODE
++# define string_mb_cur_max(str) ((str)->mb_cur_max + 0)
++#else
++# define string_mb_cur_max(str) (1)
++#endif
+
+ struct re_dfa_t;
+ typedef struct re_dfa_t re_dfa_t;
+@@ -655,6 +666,14 @@
+ __libc_lock_define (, lock)
+ };
+
++/* When OPTION_EGLIBC_LOCALE_CODE is disabled, this is always 1;
++ help the compiler make use of that fact. */
++#if __OPTION_EGLIBC_LOCALE_CODE
++# define dfa_mb_cur_max(dfa) ((dfa)->mb_cur_max + 0)
++#else
++# define dfa_mb_cur_max(dfa) (1)
++#endif
++
+ #define re_node_set_init_empty(set) memset (set, '\0', sizeof (re_node_set))
+ #define re_node_set_remove(set,id) \
+ (re_node_set_remove_at (set, re_node_set_contains (set, id) - 1))
+@@ -715,7 +734,7 @@
+ re_string_char_size_at (const re_string_t *pstr, int idx)
+ {
+ int byte_idx;
+- if (pstr->mb_cur_max == 1)
++ if (string_mb_cur_max (pstr) == 1)
+ return 1;
+ for (byte_idx = 1; idx + byte_idx < pstr->valid_len; ++byte_idx)
+ if (pstr->wcs[idx + byte_idx] != WEOF)
+@@ -727,7 +746,7 @@
+ internal_function __attribute__ ((pure, unused))
+ re_string_wchar_at (const re_string_t *pstr, int idx)
+ {
+- if (pstr->mb_cur_max == 1)
++ if (string_mb_cur_max (pstr) == 1)
+ return (wint_t) pstr->mbs[idx];
+ return (wint_t) pstr->wcs[idx];
+ }
+diff -Naur glibc-2.20/posix/xregex.c glibc-2.20-patch/posix/xregex.c
+--- glibc-2.20/posix/xregex.c 1969-12-31 18:00:00.000000000 -0600
++++ glibc-2.20-patch/posix/xregex.c 2015-03-04 00:51:32.416952006 -0600
+@@ -0,0 +1,8212 @@
++/* Extended regular expression matching and search library,
++ version 0.12.
++ (Implements POSIX draft P1003.2/D11.2, except for some of the
++ internationalization features.)
++
++ Copyright (C) 1993, 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001,
++ 2002, 2005 Free Software Foundation, Inc.
++ This file is part of the GNU C Library.
++
++ The GNU C Library is free software; you can redistribute it and/or
++ modify it under the terms of the GNU Lesser General Public
++ License as published by the Free Software Foundation; either
++ version 2.1 of the License, or (at your option) any later version.
++
++ The GNU C Library is distributed in the hope that it will be useful,
++ but WITHOUT ANY WARRANTY; without even the implied warranty of
++ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
++ Lesser General Public License for more details.
++
++ You should have received a copy of the GNU Lesser General Public
++ License along with the GNU C Library; if not, write to the Free
++ Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
++ 02110-1301 USA. */
++
++/* AIX requires this to be the first thing in the file. */
++#if defined _AIX && !defined __GNUC__ && !defined REGEX_MALLOC
++ #pragma alloca
++#endif
++
++#undef _GNU_SOURCE
++#define _GNU_SOURCE
++
++#ifndef INSIDE_RECURSION
++# ifdef HAVE_CONFIG_H
++# include <config.h>
++# endif
++#endif
++
++/*#include <ansidecl.h>*/
++
++#ifndef INSIDE_RECURSION
++
++# if defined STDC_HEADERS && !defined emacs
++# include <stddef.h>
++# else
++/* We need this for `regex.h', and perhaps for the Emacs include files. */
++# include <sys/types.h>
++# endif
++
++# define WIDE_CHAR_SUPPORT (HAVE_WCTYPE_H && HAVE_WCHAR_H && HAVE_BTOWC)
++
++/* For platform which support the ISO C amendement 1 functionality we
++ support user defined character classes. */
++# if WIDE_CHAR_SUPPORT
++/* Solaris 2.5 has a bug: <wchar.h> must be included before <wctype.h>. */
++# include <wchar.h>
++# include <wctype.h>
++# endif
++
++# ifdef _LIBC
++/* We have to keep the namespace clean. */
++# define regfree(preg) __regfree (preg)
++# define regexec(pr, st, nm, pm, ef) __regexec (pr, st, nm, pm, ef)
++# define regcomp(preg, pattern, cflags) __regcomp (preg, pattern, cflags)
++# define regerror(errcode, preg, errbuf, errbuf_size) \
++ __regerror(errcode, preg, errbuf, errbuf_size)
++# define re_set_registers(bu, re, nu, st, en) \
++ __re_set_registers (bu, re, nu, st, en)
++# define re_match_2(bufp, string1, size1, string2, size2, pos, regs, stop) \
++ __re_match_2 (bufp, string1, size1, string2, size2, pos, regs, stop)
++# define re_match(bufp, string, size, pos, regs) \
++ __re_match (bufp, string, size, pos, regs)
++# define re_search(bufp, string, size, startpos, range, regs) \
++ __re_search (bufp, string, size, startpos, range, regs)
++# define re_compile_pattern(pattern, length, bufp) \
++ __re_compile_pattern (pattern, length, bufp)
++# define re_set_syntax(syntax) __re_set_syntax (syntax)
++# define re_search_2(bufp, st1, s1, st2, s2, startpos, range, regs, stop) \
++ __re_search_2 (bufp, st1, s1, st2, s2, startpos, range, regs, stop)
++# define re_compile_fastmap(bufp) __re_compile_fastmap (bufp)
++
++# define btowc __btowc
++
++/* We are also using some library internals. */
++# include <locale/localeinfo.h>
++# include <locale/elem-hash.h>
++# include <langinfo.h>
++# include <locale/coll-lookup.h>
++# endif
++
++/* This is for other GNU distributions with internationalized messages. */
++# if (HAVE_LIBINTL_H && ENABLE_NLS) || defined _LIBC
++# include <libintl.h>
++# ifdef _LIBC
++# undef gettext
++# define gettext(msgid) __dcgettext ("libc", msgid, LC_MESSAGES)
++# endif
++# else
++# define gettext(msgid) (msgid)
++# endif
++
++# ifndef gettext_noop
++/* This define is so xgettext can find the internationalizable
++ strings. */
++# define gettext_noop(String) String
++# endif
++
++/* The `emacs' switch turns on certain matching commands
++ that make sense only in Emacs. */
++# ifdef emacs
++
++# include "lisp.h"
++# include "buffer.h"
++# include "syntax.h"
++
++# else /* not emacs */
++
++/* If we are not linking with Emacs proper,
++ we can't use the relocating allocator
++ even if config.h says that we can. */
++# undef REL_ALLOC
++
++# if defined STDC_HEADERS || defined _LIBC
++# include <stdlib.h>
++# else
++char *malloc ();
++char *realloc ();
++# endif
++
++/* When used in Emacs's lib-src, we need to get bzero and bcopy somehow.
++ If nothing else has been done, use the method below. */
++# ifdef INHIBIT_STRING_HEADER
++# if !(defined HAVE_BZERO && defined HAVE_BCOPY)
++# if !defined bzero && !defined bcopy
++# undef INHIBIT_STRING_HEADER
++# endif
++# endif
++# endif
++
++/* This is the normal way of making sure we have a bcopy and a bzero.
++ This is used in most programs--a few other programs avoid this
++ by defining INHIBIT_STRING_HEADER. */
++# ifndef INHIBIT_STRING_HEADER
++# if defined HAVE_STRING_H || defined STDC_HEADERS || defined _LIBC
++# include <string.h>
++# ifndef bzero
++# ifndef _LIBC
++# define bzero(s, n) (memset (s, '\0', n), (s))
++# else
++# define bzero(s, n) __bzero (s, n)
++# endif
++# endif
++# else
++# include <strings.h>
++# ifndef memcmp
++# define memcmp(s1, s2, n) bcmp (s1, s2, n)
++# endif
++# ifndef memcpy
++# define memcpy(d, s, n) (bcopy (s, d, n), (d))
++# endif
++# endif
++# endif
++
++/* Define the syntax stuff for \<, \>, etc. */
++
++/* This must be nonzero for the wordchar and notwordchar pattern
++ commands in re_match_2. */
++# ifndef Sword
++# define Sword 1
++# endif
++
++# ifdef SWITCH_ENUM_BUG
++# define SWITCH_ENUM_CAST(x) ((int)(x))
++# else
++# define SWITCH_ENUM_CAST(x) (x)
++# endif
++
++# endif /* not emacs */
++
++# if defined _LIBC || HAVE_LIMITS_H
++# include <limits.h>
++# endif
++
++# ifndef MB_LEN_MAX
++# define MB_LEN_MAX 1
++# endif
++
++/* Get the interface, including the syntax bits. */
++# include "regex.h"
++
++/* isalpha etc. are used for the character classes. */
++# include <ctype.h>
++
++/* Jim Meyering writes:
++
++ "... Some ctype macros are valid only for character codes that
++ isascii says are ASCII (SGI's IRIX-4.0.5 is one such system --when
++ using /bin/cc or gcc but without giving an ansi option). So, all
++ ctype uses should be through macros like ISPRINT... If
++ STDC_HEADERS is defined, then autoconf has verified that the ctype
++ macros don't need to be guarded with references to isascii. ...
++ Defining isascii to 1 should let any compiler worth its salt
++ eliminate the && through constant folding."
++ Solaris defines some of these symbols so we must undefine them first. */
++
++# undef ISASCII
++# if defined STDC_HEADERS || (!defined isascii && !defined HAVE_ISASCII)
++# define ISASCII(c) 1
++# else
++# define ISASCII(c) isascii(c)
++# endif
++
++# ifdef isblank
++# define ISBLANK(c) (ISASCII (c) && isblank (c))
++# else
++# define ISBLANK(c) ((c) == ' ' || (c) == '\t')
++# endif
++# ifdef isgraph
++# define ISGRAPH(c) (ISASCII (c) && isgraph (c))
++# else
++# define ISGRAPH(c) (ISASCII (c) && isprint (c) && !isspace (c))
++# endif
++
++# undef ISPRINT
++# define ISPRINT(c) (ISASCII (c) && isprint (c))
++# define ISDIGIT(c) (ISASCII (c) && isdigit (c))
++# define ISALNUM(c) (ISASCII (c) && isalnum (c))
++# define ISALPHA(c) (ISASCII (c) && isalpha (c))
++# define ISCNTRL(c) (ISASCII (c) && iscntrl (c))
++# define ISLOWER(c) (ISASCII (c) && islower (c))
++# define ISPUNCT(c) (ISASCII (c) && ispunct (c))
++# define ISSPACE(c) (ISASCII (c) && isspace (c))
++# define ISUPPER(c) (ISASCII (c) && isupper (c))
++# define ISXDIGIT(c) (ISASCII (c) && isxdigit (c))
++
++# ifdef _tolower
++# define TOLOWER(c) _tolower(c)
++# else
++# define TOLOWER(c) tolower(c)
++# endif
++
++# ifndef NULL
++# define NULL (void *)0
++# endif
++
++/* We remove any previous definition of `SIGN_EXTEND_CHAR',
++ since ours (we hope) works properly with all combinations of
++ machines, compilers, `char' and `unsigned char' argument types.
++ (Per Bothner suggested the basic approach.) */
++# undef SIGN_EXTEND_CHAR
++# if __STDC__
++# define SIGN_EXTEND_CHAR(c) ((signed char) (c))
++# else /* not __STDC__ */
++/* As in Harbison and Steele. */
++# define SIGN_EXTEND_CHAR(c) ((((unsigned char) (c)) ^ 128) - 128)
++# endif
++
++# ifndef emacs
++/* How many characters in the character set. */
++# define CHAR_SET_SIZE 256
++
++# ifdef SYNTAX_TABLE
++
++extern char *re_syntax_table;
++
++# else /* not SYNTAX_TABLE */
++
++static char re_syntax_table[CHAR_SET_SIZE];
++
++static void init_syntax_once (void);
++
++static void
++init_syntax_once (void)
++{
++ register int c;
++ static int done = 0;
++
++ if (done)
++ return;
++ bzero (re_syntax_table, sizeof re_syntax_table);
++
++ for (c = 0; c < CHAR_SET_SIZE; ++c)
++ if (ISALNUM (c))
++ re_syntax_table[c] = Sword;
++
++ re_syntax_table['_'] = Sword;
++
++ done = 1;
++}
++
++# endif /* not SYNTAX_TABLE */
++
++# define SYNTAX(c) re_syntax_table[(unsigned char) (c)]
++
++# endif /* emacs */
++
++/* Integer type for pointers. */
++# if !defined _LIBC && !defined HAVE_UINTPTR_T
++typedef unsigned long int uintptr_t;
++# endif
++
++/* Should we use malloc or alloca? If REGEX_MALLOC is not defined, we
++ use `alloca' instead of `malloc'. This is because using malloc in
++ re_search* or re_match* could cause memory leaks when C-g is used in
++ Emacs; also, malloc is slower and causes storage fragmentation. On
++ the other hand, malloc is more portable, and easier to debug.
++
++ Because we sometimes use alloca, some routines have to be macros,
++ not functions -- `alloca'-allocated space disappears at the end of the
++ function it is called in. */
++
++# ifdef REGEX_MALLOC
++
++# define REGEX_ALLOCATE malloc
++# define REGEX_REALLOCATE(source, osize, nsize) realloc (source, nsize)
++# define REGEX_FREE free
++
++# else /* not REGEX_MALLOC */
++
++/* Emacs already defines alloca, sometimes. */
++# ifndef alloca
++
++/* Make alloca work the best possible way. */
++# ifdef __GNUC__
++# define alloca __builtin_alloca
++# else /* not __GNUC__ */
++# if HAVE_ALLOCA_H
++# include <alloca.h>
++# endif /* HAVE_ALLOCA_H */
++# endif /* not __GNUC__ */
++
++# endif /* not alloca */
++
++# define REGEX_ALLOCATE alloca
++
++/* Assumes a `char *destination' variable. */
++# define REGEX_REALLOCATE(source, osize, nsize) \
++ (destination = (char *) alloca (nsize), \
++ memcpy (destination, source, osize))
++
++/* No need to do anything to free, after alloca. */
++# define REGEX_FREE(arg) ((void)0) /* Do nothing! But inhibit gcc warning. */
++
++# endif /* not REGEX_MALLOC */
++
++/* Define how to allocate the failure stack. */
++
++# if defined REL_ALLOC && defined REGEX_MALLOC
++
++# define REGEX_ALLOCATE_STACK(size) \
++ r_alloc (&failure_stack_ptr, (size))
++# define REGEX_REALLOCATE_STACK(source, osize, nsize) \
++ r_re_alloc (&failure_stack_ptr, (nsize))
++# define REGEX_FREE_STACK(ptr) \
++ r_alloc_free (&failure_stack_ptr)
++
++# else /* not using relocating allocator */
++
++# ifdef REGEX_MALLOC
++
++# define REGEX_ALLOCATE_STACK malloc
++# define REGEX_REALLOCATE_STACK(source, osize, nsize) realloc (source, nsize)
++# define REGEX_FREE_STACK free
++
++# else /* not REGEX_MALLOC */
++
++# define REGEX_ALLOCATE_STACK alloca
++
++# define REGEX_REALLOCATE_STACK(source, osize, nsize) \
++ REGEX_REALLOCATE (source, osize, nsize)
++/* No need to explicitly free anything. */
++# define REGEX_FREE_STACK(arg)
++
++# endif /* not REGEX_MALLOC */
++# endif /* not using relocating allocator */
++
++
++/* True if `size1' is non-NULL and PTR is pointing anywhere inside
++ `string1' or just past its end. This works if PTR is NULL, which is
++ a good thing. */
++# define FIRST_STRING_P(ptr) \
++ (size1 && string1 <= (ptr) && (ptr) <= string1 + size1)
++
++/* (Re)Allocate N items of type T using malloc, or fail. */
++# define TALLOC(n, t) ((t *) malloc ((n) * sizeof (t)))
++# define RETALLOC(addr, n, t) ((addr) = (t *) realloc (addr, (n) * sizeof (t)))
++# define RETALLOC_IF(addr, n, t) \
++ if (addr) RETALLOC((addr), (n), t); else (addr) = TALLOC ((n), t)
++# define REGEX_TALLOC(n, t) ((t *) REGEX_ALLOCATE ((n) * sizeof (t)))
++
++# define BYTEWIDTH 8 /* In bits. */
++
++# define STREQ(s1, s2) ((strcmp (s1, s2) == 0))
++
++# undef MAX
++# undef MIN
++# define MAX(a, b) ((a) > (b) ? (a) : (b))
++# define MIN(a, b) ((a) < (b) ? (a) : (b))
++
++typedef char boolean;
++# define false 0
++# define true 1
++
++static reg_errcode_t byte_regex_compile (const char *pattern, size_t size,
++ reg_syntax_t syntax,
++ struct re_pattern_buffer *bufp);
++
++static int byte_re_match_2_internal (struct re_pattern_buffer *bufp,
++ const char *string1, int size1,
++ const char *string2, int size2,
++ int pos,
++ struct re_registers *regs,
++ int stop);
++static int byte_re_search_2 (struct re_pattern_buffer *bufp,
++ const char *string1, int size1,
++ const char *string2, int size2,
++ int startpos, int range,
++ struct re_registers *regs, int stop);
++static int byte_re_compile_fastmap (struct re_pattern_buffer *bufp);
++
++#ifdef MBS_SUPPORT
++static reg_errcode_t wcs_regex_compile (const char *pattern, size_t size,
++ reg_syntax_t syntax,
++ struct re_pattern_buffer *bufp);
++
++
++static int wcs_re_match_2_internal (struct re_pattern_buffer *bufp,
++ const char *cstring1, int csize1,
++ const char *cstring2, int csize2,
++ int pos,
++ struct re_registers *regs,
++ int stop,
++ wchar_t *string1, int size1,
++ wchar_t *string2, int size2,
++ int *mbs_offset1, int *mbs_offset2);
++static int wcs_re_search_2 (struct re_pattern_buffer *bufp,
++ const char *string1, int size1,
++ const char *string2, int size2,
++ int startpos, int range,
++ struct re_registers *regs, int stop);
++static int wcs_re_compile_fastmap (struct re_pattern_buffer *bufp);
++#endif
++
++/* These are the command codes that appear in compiled regular
++ expressions. Some opcodes are followed by argument bytes. A
++ command code can specify any interpretation whatsoever for its
++ arguments. Zero bytes may appear in the compiled regular expression. */
++
++typedef enum
++{
++ no_op = 0,
++
++ /* Succeed right away--no more backtracking. */
++ succeed,
++
++ /* Followed by one byte giving n, then by n literal bytes. */
++ exactn,
++
++# ifdef MBS_SUPPORT
++ /* Same as exactn, but contains binary data. */
++ exactn_bin,
++# endif
++
++ /* Matches any (more or less) character. */
++ anychar,
++
++ /* Matches any one char belonging to specified set. First
++ following byte is number of bitmap bytes. Then come bytes
++ for a bitmap saying which chars are in. Bits in each byte
++ are ordered low-bit-first. A character is in the set if its
++ bit is 1. A character too large to have a bit in the map is
++ automatically not in the set. */
++ /* ifdef MBS_SUPPORT, following element is length of character
++ classes, length of collating symbols, length of equivalence
++ classes, length of character ranges, and length of characters.
++ Next, character class element, collating symbols elements,
++ equivalence class elements, range elements, and character
++ elements follow.
++ See regex_compile function. */
++ charset,
++
++ /* Same parameters as charset, but match any character that is
++ not one of those specified. */
++ charset_not,
++
++ /* Start remembering the text that is matched, for storing in a
++ register. Followed by one byte with the register number, in
++ the range 0 to one less than the pattern buffer's re_nsub
++ field. Then followed by one byte with the number of groups
++ inner to this one. (This last has to be part of the
++ start_memory only because we need it in the on_failure_jump
++ of re_match_2.) */
++ start_memory,
++
++ /* Stop remembering the text that is matched and store it in a
++ memory register. Followed by one byte with the register
++ number, in the range 0 to one less than `re_nsub' in the
++ pattern buffer, and one byte with the number of inner groups,
++ just like `start_memory'. (We need the number of inner
++ groups here because we don't have any easy way of finding the
++ corresponding start_memory when we're at a stop_memory.) */
++ stop_memory,
++
++ /* Match a duplicate of something remembered. Followed by one
++ byte containing the register number. */
++ duplicate,
++
++ /* Fail unless at beginning of line. */
++ begline,
++
++ /* Fail unless at end of line. */
++ endline,
++
++ /* Succeeds if at beginning of buffer (if emacs) or at beginning
++ of string to be matched (if not). */
++ begbuf,
++
++ /* Analogously, for end of buffer/string. */
++ endbuf,
++
++ /* Followed by two byte relative address to which to jump. */
++ jump,
++
++ /* Same as jump, but marks the end of an alternative. */
++ jump_past_alt,
++
++ /* Followed by two-byte relative address of place to resume at
++ in case of failure. */
++ /* ifdef MBS_SUPPORT, the size of address is 1. */
++ on_failure_jump,
++
++ /* Like on_failure_jump, but pushes a placeholder instead of the
++ current string position when executed. */
++ on_failure_keep_string_jump,
++
++ /* Throw away latest failure point and then jump to following
++ two-byte relative address. */
++ /* ifdef MBS_SUPPORT, the size of address is 1. */
++ pop_failure_jump,
++
++ /* Change to pop_failure_jump if know won't have to backtrack to
++ match; otherwise change to jump. This is used to jump
++ back to the beginning of a repeat. If what follows this jump
++ clearly won't match what the repeat does, such that we can be
++ sure that there is no use backtracking out of repetitions
++ already matched, then we change it to a pop_failure_jump.
++ Followed by two-byte address. */
++ /* ifdef MBS_SUPPORT, the size of address is 1. */
++ maybe_pop_jump,
++
++ /* Jump to following two-byte address, and push a dummy failure
++ point. This failure point will be thrown away if an attempt
++ is made to use it for a failure. A `+' construct makes this
++ before the first repeat. Also used as an intermediary kind
++ of jump when compiling an alternative. */
++ /* ifdef MBS_SUPPORT, the size of address is 1. */
++ dummy_failure_jump,
++
++ /* Push a dummy failure point and continue. Used at the end of
++ alternatives. */
++ push_dummy_failure,
++
++ /* Followed by two-byte relative address and two-byte number n.
++ After matching N times, jump to the address upon failure. */
++ /* ifdef MBS_SUPPORT, the size of address is 1. */
++ succeed_n,
++
++ /* Followed by two-byte relative address, and two-byte number n.
++ Jump to the address N times, then fail. */
++ /* ifdef MBS_SUPPORT, the size of address is 1. */
++ jump_n,
++
++ /* Set the following two-byte relative address to the
++ subsequent two-byte number. The address *includes* the two
++ bytes of number. */
++ /* ifdef MBS_SUPPORT, the size of address is 1. */
++ set_number_at,
++
++ wordchar, /* Matches any word-constituent character. */
++ notwordchar, /* Matches any char that is not a word-constituent. */
++
++ wordbeg, /* Succeeds if at word beginning. */
++ wordend, /* Succeeds if at word end. */
++
++ wordbound, /* Succeeds if at a word boundary. */
++ notwordbound /* Succeeds if not at a word boundary. */
++
++# ifdef emacs
++ ,before_dot, /* Succeeds if before point. */
++ at_dot, /* Succeeds if at point. */
++ after_dot, /* Succeeds if after point. */
++
++ /* Matches any character whose syntax is specified. Followed by
++ a byte which contains a syntax code, e.g., Sword. */
++ syntaxspec,
++
++ /* Matches any character whose syntax is not that specified. */
++ notsyntaxspec
++# endif /* emacs */
++} re_opcode_t;
++#endif /* not INSIDE_RECURSION */
++
++
++#ifdef BYTE
++# define CHAR_T char
++# define UCHAR_T unsigned char
++# define COMPILED_BUFFER_VAR bufp->buffer
++# define OFFSET_ADDRESS_SIZE 2
++# define PREFIX(name) byte_##name
++# define ARG_PREFIX(name) name
++# define PUT_CHAR(c) putchar (c)
++#else
++# ifdef WCHAR
++# define CHAR_T wchar_t
++# define UCHAR_T wchar_t
++# define COMPILED_BUFFER_VAR wc_buffer
++# define OFFSET_ADDRESS_SIZE 1 /* the size which STORE_NUMBER macro use */
++# define CHAR_CLASS_SIZE ((__alignof__(wctype_t)+sizeof(wctype_t))/sizeof(CHAR_T)+1)
++# define PREFIX(name) wcs_##name
++# define ARG_PREFIX(name) c##name
++/* Should we use wide stream?? */
++# define PUT_CHAR(c) printf ("%C", c);
++# define TRUE 1
++# define FALSE 0
++# else
++# ifdef MBS_SUPPORT
++# define WCHAR
++# define INSIDE_RECURSION
++# include "xregex.c"
++# undef INSIDE_RECURSION
++# endif
++# define BYTE
++# define INSIDE_RECURSION
++# include "xregex.c"
++# undef INSIDE_RECURSION
++# endif
++#endif
++
++#ifdef INSIDE_RECURSION
++/* Common operations on the compiled pattern. */
++
++/* Store NUMBER in two contiguous bytes starting at DESTINATION. */
++/* ifdef MBS_SUPPORT, we store NUMBER in 1 element. */
++
++# ifdef WCHAR
++# define STORE_NUMBER(destination, number) \
++ do { \
++ *(destination) = (UCHAR_T)(number); \
++ } while (0)
++# else /* BYTE */
++# define STORE_NUMBER(destination, number) \
++ do { \
++ (destination)[0] = (number) & 0377; \
++ (destination)[1] = (number) >> 8; \
++ } while (0)
++# endif /* WCHAR */
++
++/* Same as STORE_NUMBER, except increment DESTINATION to
++ the byte after where the number is stored. Therefore, DESTINATION
++ must be an lvalue. */
++/* ifdef MBS_SUPPORT, we store NUMBER in 1 element. */
++
++# define STORE_NUMBER_AND_INCR(destination, number) \
++ do { \
++ STORE_NUMBER (destination, number); \
++ (destination) += OFFSET_ADDRESS_SIZE; \
++ } while (0)
++
++/* Put into DESTINATION a number stored in two contiguous bytes starting
++ at SOURCE. */
++/* ifdef MBS_SUPPORT, we store NUMBER in 1 element. */
++
++# ifdef WCHAR
++# define EXTRACT_NUMBER(destination, source) \
++ do { \
++ (destination) = *(source); \
++ } while (0)
++# else /* BYTE */
++# define EXTRACT_NUMBER(destination, source) \
++ do { \
++ (destination) = *(source) & 0377; \
++ (destination) += SIGN_EXTEND_CHAR (*((source) + 1)) << 8; \
++ } while (0)
++# endif
++
++# ifdef DEBUG
++static void PREFIX(extract_number) (int *dest, UCHAR_T *source);
++static void
++PREFIX(extract_number) (int *dest, UCHAR_T *source)
++{
++# ifdef WCHAR
++ *dest = *source;
++# else /* BYTE */
++ int temp = SIGN_EXTEND_CHAR (*(source + 1));
++ *dest = *source & 0377;
++ *dest += temp << 8;
++# endif
++}
++
++# ifndef EXTRACT_MACROS /* To debug the macros. */
++# undef EXTRACT_NUMBER
++# define EXTRACT_NUMBER(dest, src) PREFIX(extract_number) (&dest, src)
++# endif /* not EXTRACT_MACROS */
++
++# endif /* DEBUG */
++
++/* Same as EXTRACT_NUMBER, except increment SOURCE to after the number.
++ SOURCE must be an lvalue. */
++
++# define EXTRACT_NUMBER_AND_INCR(destination, source) \
++ do { \
++ EXTRACT_NUMBER (destination, source); \
++ (source) += OFFSET_ADDRESS_SIZE; \
++ } while (0)
++
++# ifdef DEBUG
++static void PREFIX(extract_number_and_incr) (int *destination,
++ UCHAR_T **source);
++static void
++PREFIX(extract_number_and_incr) (int *destination, UCHAR_T **source)
++{
++ PREFIX(extract_number) (destination, *source);
++ *source += OFFSET_ADDRESS_SIZE;
++}
++
++# ifndef EXTRACT_MACROS
++# undef EXTRACT_NUMBER_AND_INCR
++# define EXTRACT_NUMBER_AND_INCR(dest, src) \
++ PREFIX(extract_number_and_incr) (&dest, &src)
++# endif /* not EXTRACT_MACROS */
++
++# endif /* DEBUG */
++
++
++
++/* If DEBUG is defined, Regex prints many voluminous messages about what
++ it is doing (if the variable `debug' is nonzero). If linked with the
++ main program in `iregex.c', you can enter patterns and strings
++ interactively. And if linked with the main program in `main.c' and
++ the other test files, you can run the already-written tests. */
++
++# ifdef DEBUG
++
++# ifndef DEFINED_ONCE
++
++/* We use standard I/O for debugging. */
++# include <stdio.h>
++
++/* It is useful to test things that ``must'' be true when debugging. */
++# include <assert.h>
++
++static int debug;
++
++# define DEBUG_STATEMENT(e) e
++# define DEBUG_PRINT1(x) if (debug) printf (x)
++# define DEBUG_PRINT2(x1, x2) if (debug) printf (x1, x2)
++# define DEBUG_PRINT3(x1, x2, x3) if (debug) printf (x1, x2, x3)
++# define DEBUG_PRINT4(x1, x2, x3, x4) if (debug) printf (x1, x2, x3, x4)
++# endif /* not DEFINED_ONCE */
++
++# define DEBUG_PRINT_COMPILED_PATTERN(p, s, e) \
++ if (debug) PREFIX(print_partial_compiled_pattern) (s, e)
++# define DEBUG_PRINT_DOUBLE_STRING(w, s1, sz1, s2, sz2) \
++ if (debug) PREFIX(print_double_string) (w, s1, sz1, s2, sz2)
++
++
++/* Print the fastmap in human-readable form. */
++
++# ifndef DEFINED_ONCE
++void
++print_fastmap (char *fastmap)
++{
++ unsigned was_a_range = 0;
++ unsigned i = 0;
++
++ while (i < (1 << BYTEWIDTH))
++ {
++ if (fastmap[i++])
++ {
++ was_a_range = 0;
++ putchar (i - 1);
++ while (i < (1 << BYTEWIDTH) && fastmap[i])
++ {
++ was_a_range = 1;
++ i++;
++ }
++ if (was_a_range)
++ {
++ printf ("-");
++ putchar (i - 1);
++ }
++ }
++ }
++ putchar ('\n');
++}
++# endif /* not DEFINED_ONCE */
++
++
++/* Print a compiled pattern string in human-readable form, starting at
++ the START pointer into it and ending just before the pointer END. */
++
++void
++PREFIX(print_partial_compiled_pattern) (UCHAR_T *start, UCHAR_T *end)
++{
++ int mcnt, mcnt2;
++ UCHAR_T *p1;
++ UCHAR_T *p = start;
++ UCHAR_T *pend = end;
++
++ if (start == NULL)
++ {
++ printf ("(null)\n");
++ return;
++ }
++
++ /* Loop over pattern commands. */
++ while (p < pend)
++ {
++# ifdef _LIBC
++ printf ("%td:\t", p - start);
++# else
++ printf ("%ld:\t", (long int) (p - start));
++# endif
++
++ switch ((re_opcode_t) *p++)
++ {
++ case no_op:
++ printf ("/no_op");
++ break;
++
++ case exactn:
++ mcnt = *p++;
++ printf ("/exactn/%d", mcnt);
++ do
++ {
++ putchar ('/');
++ PUT_CHAR (*p++);
++ }
++ while (--mcnt);
++ break;
++
++# ifdef MBS_SUPPORT
++ case exactn_bin:
++ mcnt = *p++;
++ printf ("/exactn_bin/%d", mcnt);
++ do
++ {
++ printf("/%lx", (long int) *p++);
++ }
++ while (--mcnt);
++ break;
++# endif /* MBS_SUPPORT */
++
++ case start_memory:
++ mcnt = *p++;
++ printf ("/start_memory/%d/%ld", mcnt, (long int) *p++);
++ break;
++
++ case stop_memory:
++ mcnt = *p++;
++ printf ("/stop_memory/%d/%ld", mcnt, (long int) *p++);
++ break;
++
++ case duplicate:
++ printf ("/duplicate/%ld", (long int) *p++);
++ break;
++
++ case anychar:
++ printf ("/anychar");
++ break;
++
++ case charset:
++ case charset_not:
++ {
++# ifdef WCHAR
++ int i, length;
++ wchar_t *workp = p;
++ printf ("/charset [%s",
++ (re_opcode_t) *(workp - 1) == charset_not ? "^" : "");
++ p += 5;
++ length = *workp++; /* the length of char_classes */
++ for (i=0 ; i<length ; i++)
++ printf("[:%lx:]", (long int) *p++);
++ length = *workp++; /* the length of collating_symbol */
++ for (i=0 ; i<length ;)
++ {
++ printf("[.");
++ while(*p != 0)
++ PUT_CHAR((i++,*p++));
++ i++,p++;
++ printf(".]");
++ }
++ length = *workp++; /* the length of equivalence_class */
++ for (i=0 ; i<length ;)
++ {
++ printf("[=");
++ while(*p != 0)
++ PUT_CHAR((i++,*p++));
++ i++,p++;
++ printf("=]");
++ }
++ length = *workp++; /* the length of char_range */
++ for (i=0 ; i<length ; i++)
++ {
++ wchar_t range_start = *p++;
++ wchar_t range_end = *p++;
++ printf("%C-%C", range_start, range_end);
++ }
++ length = *workp++; /* the length of char */
++ for (i=0 ; i<length ; i++)
++ printf("%C", *p++);
++ putchar (']');
++# else
++ register int c, last = -100;
++ register int in_range = 0;
++
++ printf ("/charset [%s",
++ (re_opcode_t) *(p - 1) == charset_not ? "^" : "");
++
++ assert (p + *p < pend);
++
++ for (c = 0; c < 256; c++)
++ if (c / 8 < *p
++ && (p[1 + (c/8)] & (1 << (c % 8))))
++ {
++ /* Are we starting a range? */
++ if (last + 1 == c && ! in_range)
++ {
++ putchar ('-');
++ in_range = 1;
++ }
++ /* Have we broken a range? */
++ else if (last + 1 != c && in_range)
++ {
++ putchar (last);
++ in_range = 0;
++ }
++
++ if (! in_range)
++ putchar (c);
++
++ last = c;
++ }
++
++ if (in_range)
++ putchar (last);
++
++ putchar (']');
++
++ p += 1 + *p;
++# endif /* WCHAR */
++ }
++ break;
++
++ case begline:
++ printf ("/begline");
++ break;
++
++ case endline:
++ printf ("/endline");
++ break;
++
++ case on_failure_jump:
++ PREFIX(extract_number_and_incr) (&mcnt, &p);
++# ifdef _LIBC
++ printf ("/on_failure_jump to %td", p + mcnt - start);
++# else
++ printf ("/on_failure_jump to %ld", (long int) (p + mcnt - start));
++# endif
++ break;
++
++ case on_failure_keep_string_jump:
++ PREFIX(extract_number_and_incr) (&mcnt, &p);
++# ifdef _LIBC
++ printf ("/on_failure_keep_string_jump to %td", p + mcnt - start);
++# else
++ printf ("/on_failure_keep_string_jump to %ld",
++ (long int) (p + mcnt - start));
++# endif
++ break;
++
++ case dummy_failure_jump:
++ PREFIX(extract_number_and_incr) (&mcnt, &p);
++# ifdef _LIBC
++ printf ("/dummy_failure_jump to %td", p + mcnt - start);
++# else
++ printf ("/dummy_failure_jump to %ld", (long int) (p + mcnt - start));
++# endif
++ break;
++
++ case push_dummy_failure:
++ printf ("/push_dummy_failure");
++ break;
++
++ case maybe_pop_jump:
++ PREFIX(extract_number_and_incr) (&mcnt, &p);
++# ifdef _LIBC
++ printf ("/maybe_pop_jump to %td", p + mcnt - start);
++# else
++ printf ("/maybe_pop_jump to %ld", (long int) (p + mcnt - start));
++# endif
++ break;
++
++ case pop_failure_jump:
++ PREFIX(extract_number_and_incr) (&mcnt, &p);
++# ifdef _LIBC
++ printf ("/pop_failure_jump to %td", p + mcnt - start);
++# else
++ printf ("/pop_failure_jump to %ld", (long int) (p + mcnt - start));
++# endif
++ break;
++
++ case jump_past_alt:
++ PREFIX(extract_number_and_incr) (&mcnt, &p);
++# ifdef _LIBC
++ printf ("/jump_past_alt to %td", p + mcnt - start);
++# else
++ printf ("/jump_past_alt to %ld", (long int) (p + mcnt - start));
++# endif
++ break;
++
++ case jump:
++ PREFIX(extract_number_and_incr) (&mcnt, &p);
++# ifdef _LIBC
++ printf ("/jump to %td", p + mcnt - start);
++# else
++ printf ("/jump to %ld", (long int) (p + mcnt - start));
++# endif
++ break;
++
++ case succeed_n:
++ PREFIX(extract_number_and_incr) (&mcnt, &p);
++ p1 = p + mcnt;
++ PREFIX(extract_number_and_incr) (&mcnt2, &p);
++# ifdef _LIBC
++ printf ("/succeed_n to %td, %d times", p1 - start, mcnt2);
++# else
++ printf ("/succeed_n to %ld, %d times",
++ (long int) (p1 - start), mcnt2);
++# endif
++ break;
++
++ case jump_n:
++ PREFIX(extract_number_and_incr) (&mcnt, &p);
++ p1 = p + mcnt;
++ PREFIX(extract_number_and_incr) (&mcnt2, &p);
++ printf ("/jump_n to %d, %d times", p1 - start, mcnt2);
++ break;
++
++ case set_number_at:
++ PREFIX(extract_number_and_incr) (&mcnt, &p);
++ p1 = p + mcnt;
++ PREFIX(extract_number_and_incr) (&mcnt2, &p);
++# ifdef _LIBC
++ printf ("/set_number_at location %td to %d", p1 - start, mcnt2);
++# else
++ printf ("/set_number_at location %ld to %d",
++ (long int) (p1 - start), mcnt2);
++# endif
++ break;
++
++ case wordbound:
++ printf ("/wordbound");
++ break;
++
++ case notwordbound:
++ printf ("/notwordbound");
++ break;
++
++ case wordbeg:
++ printf ("/wordbeg");
++ break;
++
++ case wordend:
++ printf ("/wordend");
++ break;
++
++# ifdef emacs
++ case before_dot:
++ printf ("/before_dot");
++ break;
++
++ case at_dot:
++ printf ("/at_dot");
++ break;
++
++ case after_dot:
++ printf ("/after_dot");
++ break;
++
++ case syntaxspec:
++ printf ("/syntaxspec");
++ mcnt = *p++;
++ printf ("/%d", mcnt);
++ break;
++
++ case notsyntaxspec:
++ printf ("/notsyntaxspec");
++ mcnt = *p++;
++ printf ("/%d", mcnt);
++ break;
++# endif /* emacs */
++
++ case wordchar:
++ printf ("/wordchar");
++ break;
++
++ case notwordchar:
++ printf ("/notwordchar");
++ break;
++
++ case begbuf:
++ printf ("/begbuf");
++ break;
++
++ case endbuf:
++ printf ("/endbuf");
++ break;
++
++ default:
++ printf ("?%ld", (long int) *(p-1));
++ }
++
++ putchar ('\n');
++ }
++
++# ifdef _LIBC
++ printf ("%td:\tend of pattern.\n", p - start);
++# else
++ printf ("%ld:\tend of pattern.\n", (long int) (p - start));
++# endif
++}
++
++
++void
++PREFIX(print_compiled_pattern) (struct re_pattern_buffer *bufp)
++{
++ UCHAR_T *buffer = (UCHAR_T*) bufp->buffer;
++
++ PREFIX(print_partial_compiled_pattern) (buffer, buffer
++ + bufp->used / sizeof(UCHAR_T));
++ printf ("%ld bytes used/%ld bytes allocated.\n",
++ bufp->used, bufp->allocated);
++
++ if (bufp->fastmap_accurate && bufp->fastmap)
++ {
++ printf ("fastmap: ");
++ print_fastmap (bufp->fastmap);
++ }
++
++# ifdef _LIBC
++ printf ("re_nsub: %Zd\t", bufp->re_nsub);
++# else
++ printf ("re_nsub: %ld\t", (long int) bufp->re_nsub);
++# endif
++ printf ("regs_alloc: %d\t", bufp->regs_allocated);
++ printf ("can_be_null: %d\t", bufp->can_be_null);
++ printf ("newline_anchor: %d\n", bufp->newline_anchor);
++ printf ("no_sub: %d\t", bufp->no_sub);
++ printf ("not_bol: %d\t", bufp->not_bol);
++ printf ("not_eol: %d\t", bufp->not_eol);
++ printf ("syntax: %lx\n", bufp->syntax);
++ /* Perhaps we should print the translate table? */
++}
++
++
++void
++PREFIX(print_double_string) (const CHAR_T *where, const CHAR_T *string1,
++ int size1, const CHAR_T *string2, int size2)
++{
++ int this_char;
++
++ if (where == NULL)
++ printf ("(null)");
++ else
++ {
++ int cnt;
++
++ if (FIRST_STRING_P (where))
++ {
++ for (this_char = where - string1; this_char < size1; this_char++)
++ PUT_CHAR (string1[this_char]);
++
++ where = string2;
++ }
++
++ cnt = 0;
++ for (this_char = where - string2; this_char < size2; this_char++)
++ {
++ PUT_CHAR (string2[this_char]);
++ if (++cnt > 100)
++ {
++ fputs ("...", stdout);
++ break;
++ }
++ }
++ }
++}
++
++# ifndef DEFINED_ONCE
++void
++printchar (int c)
++{
++ putc (c, stderr);
++}
++# endif
++
++# else /* not DEBUG */
++
++# ifndef DEFINED_ONCE
++# undef assert
++# define assert(e)
++
++# define DEBUG_STATEMENT(e)
++# define DEBUG_PRINT1(x)
++# define DEBUG_PRINT2(x1, x2)
++# define DEBUG_PRINT3(x1, x2, x3)
++# define DEBUG_PRINT4(x1, x2, x3, x4)
++# endif /* not DEFINED_ONCE */
++# define DEBUG_PRINT_COMPILED_PATTERN(p, s, e)
++# define DEBUG_PRINT_DOUBLE_STRING(w, s1, sz1, s2, sz2)
++
++# endif /* not DEBUG */
++
++
++
++# ifdef WCHAR
++/* This convert a multibyte string to a wide character string.
++ And write their correspondances to offset_buffer(see below)
++ and write whether each wchar_t is binary data to is_binary.
++ This assume invalid multibyte sequences as binary data.
++ We assume offset_buffer and is_binary is already allocated
++ enough space. */
++
++static size_t convert_mbs_to_wcs (CHAR_T *dest, const unsigned char* src,
++ size_t len, int *offset_buffer,
++ char *is_binary);
++static size_t
++convert_mbs_to_wcs (CHAR_T *dest, const unsigned char*src, size_t len,
++ int *offset_buffer, char *is_binary)
++ /* It hold correspondances between src(char string) and
++ dest(wchar_t string) for optimization.
++ e.g. src = "xxxyzz"
++ dest = {'X', 'Y', 'Z'}
++ (each "xxx", "y" and "zz" represent one multibyte character
++ corresponding to 'X', 'Y' and 'Z'.)
++ offset_buffer = {0, 0+3("xxx"), 0+3+1("y"), 0+3+1+2("zz")}
++ = {0, 3, 4, 6}
++ */
++{
++ wchar_t *pdest = dest;
++ const unsigned char *psrc = src;
++ size_t wc_count = 0;
++
++ mbstate_t mbs;
++ int i, consumed;
++ size_t mb_remain = len;
++ size_t mb_count = 0;
++
++ /* Initialize the conversion state. */
++ memset (&mbs, 0, sizeof (mbstate_t));
++
++ offset_buffer[0] = 0;
++ for( ; mb_remain > 0 ; ++wc_count, ++pdest, mb_remain -= consumed,
++ psrc += consumed)
++ {
++#ifdef _LIBC
++ consumed = __mbrtowc (pdest, psrc, mb_remain, &mbs);
++#else
++ consumed = mbrtowc (pdest, psrc, mb_remain, &mbs);
++#endif
++
++ if (consumed <= 0)
++ /* failed to convert. maybe src contains binary data.
++ So we consume 1 byte manualy. */
++ {
++ *pdest = *psrc;
++ consumed = 1;
++ is_binary[wc_count] = TRUE;
++ }
++ else
++ is_binary[wc_count] = FALSE;
++ /* In sjis encoding, we use yen sign as escape character in
++ place of reverse solidus. So we convert 0x5c(yen sign in
++ sjis) to not 0xa5(yen sign in UCS2) but 0x5c(reverse
++ solidus in UCS2). */
++ if (consumed == 1 && (int) *psrc == 0x5c && (int) *pdest == 0xa5)
++ *pdest = (wchar_t) *psrc;
++
++ offset_buffer[wc_count + 1] = mb_count += consumed;
++ }
++
++ /* Fill remain of the buffer with sentinel. */
++ for (i = wc_count + 1 ; i <= len ; i++)
++ offset_buffer[i] = mb_count + 1;
++
++ return wc_count;
++}
++
++# endif /* WCHAR */
++
++#else /* not INSIDE_RECURSION */
++
++/* Set by `re_set_syntax' to the current regexp syntax to recognize. Can
++ also be assigned to arbitrarily: each pattern buffer stores its own
++ syntax, so it can be changed between regex compilations. */
++/* This has no initializer because initialized variables in Emacs
++ become read-only after dumping. */
++reg_syntax_t re_syntax_options;
++
++
++/* Specify the precise syntax of regexps for compilation. This provides
++ for compatibility for various utilities which historically have
++ different, incompatible syntaxes.
++
++ The argument SYNTAX is a bit mask comprised of the various bits
++ defined in regex.h. We return the old syntax. */
++
++reg_syntax_t
++re_set_syntax (reg_syntax_t syntax)
++{
++ reg_syntax_t ret = re_syntax_options;
++
++ re_syntax_options = syntax;
++# ifdef DEBUG
++ if (syntax & RE_DEBUG)
++ debug = 1;
++ else if (debug) /* was on but now is not */
++ debug = 0;
++# endif /* DEBUG */
++ return ret;
++}
++# ifdef _LIBC
++weak_alias (__re_set_syntax, re_set_syntax)
++# endif
++
++/* This table gives an error message for each of the error codes listed
++ in regex.h. Obviously the order here has to be same as there.
++ POSIX doesn't require that we do anything for REG_NOERROR,
++ but why not be nice? */
++
++static const char *re_error_msgid[] =
++ {
++ gettext_noop ("Success"), /* REG_NOERROR */
++ gettext_noop ("No match"), /* REG_NOMATCH */
++ gettext_noop ("Invalid regular expression"), /* REG_BADPAT */
++ gettext_noop ("Invalid collation character"), /* REG_ECOLLATE */
++ gettext_noop ("Invalid character class name"), /* REG_ECTYPE */
++ gettext_noop ("Trailing backslash"), /* REG_EESCAPE */
++ gettext_noop ("Invalid back reference"), /* REG_ESUBREG */
++ gettext_noop ("Unmatched [ or [^"), /* REG_EBRACK */
++ gettext_noop ("Unmatched ( or \\("), /* REG_EPAREN */
++ gettext_noop ("Unmatched \\{"), /* REG_EBRACE */
++ gettext_noop ("Invalid content of \\{\\}"), /* REG_BADBR */
++ gettext_noop ("Invalid range end"), /* REG_ERANGE */
++ gettext_noop ("Memory exhausted"), /* REG_ESPACE */
++ gettext_noop ("Invalid preceding regular expression"), /* REG_BADRPT */
++ gettext_noop ("Premature end of regular expression"), /* REG_EEND */
++ gettext_noop ("Regular expression too big"), /* REG_ESIZE */
++ gettext_noop ("Unmatched ) or \\)") /* REG_ERPAREN */
++ };
++
++#endif /* INSIDE_RECURSION */
++
++#ifndef DEFINED_ONCE
++/* Avoiding alloca during matching, to placate r_alloc. */
++
++/* Define MATCH_MAY_ALLOCATE unless we need to make sure that the
++ searching and matching functions should not call alloca. On some
++ systems, alloca is implemented in terms of malloc, and if we're
++ using the relocating allocator routines, then malloc could cause a
++ relocation, which might (if the strings being searched are in the
++ ralloc heap) shift the data out from underneath the regexp
++ routines.
++
++ Here's another reason to avoid allocation: Emacs
++ processes input from X in a signal handler; processing X input may
++ call malloc; if input arrives while a matching routine is calling
++ malloc, then we're scrod. But Emacs can't just block input while
++ calling matching routines; then we don't notice interrupts when
++ they come in. So, Emacs blocks input around all regexp calls
++ except the matching calls, which it leaves unprotected, in the
++ faith that they will not malloc. */
++
++/* Normally, this is fine. */
++# define MATCH_MAY_ALLOCATE
++
++/* When using GNU C, we are not REALLY using the C alloca, no matter
++ what config.h may say. So don't take precautions for it. */
++# ifdef __GNUC__
++# undef C_ALLOCA
++# endif
++
++/* The match routines may not allocate if (1) they would do it with malloc
++ and (2) it's not safe for them to use malloc.
++ Note that if REL_ALLOC is defined, matching would not use malloc for the
++ failure stack, but we would still use it for the register vectors;
++ so REL_ALLOC should not affect this. */
++# if (defined C_ALLOCA || defined REGEX_MALLOC) && defined emacs
++# undef MATCH_MAY_ALLOCATE
++# endif
++#endif /* not DEFINED_ONCE */
++
++#ifdef INSIDE_RECURSION
++/* Failure stack declarations and macros; both re_compile_fastmap and
++ re_match_2 use a failure stack. These have to be macros because of
++ REGEX_ALLOCATE_STACK. */
++
++
++/* Number of failure points for which to initially allocate space
++ when matching. If this number is exceeded, we allocate more
++ space, so it is not a hard limit. */
++# ifndef INIT_FAILURE_ALLOC
++# define INIT_FAILURE_ALLOC 5
++# endif
++
++/* Roughly the maximum number of failure points on the stack. Would be
++ exactly that if always used MAX_FAILURE_ITEMS items each time we failed.
++ This is a variable only so users of regex can assign to it; we never
++ change it ourselves. */
++
++
++# ifndef DEFINED_ONCE
++
++# ifdef INT_IS_16BIT
++# define RE_M_F_TYPE long int
++# else
++# define RE_M_F_TYPE int
++# endif /* INT_IS_16BIT */
++
++# ifdef MATCH_MAY_ALLOCATE
++/* 4400 was enough to cause a crash on Alpha OSF/1,
++ whose default stack limit is 2mb. */
++# define RE_M_F_DEFAULT 4000
++# else
++# define RE_M_F_DEFAULT 2000
++# endif /* MATCH_MAY_ALLOCATE */
++
++# include <shlib-compat.h>
++
++# if SHLIB_COMPAT (libc, GLIBC_2_0, GLIBC_2_3)
++link_warning (re_max_failures, "the 're_max_failures' variable is obsolete and will go away.")
++RE_M_F_TYPE re_max_failures = RE_M_F_DEFAULT;
++# else
++RE_M_F_TYPE re_max_failures attribute_hidden = RE_M_F_DEFAULT;
++# endif /* SHLIB_COMPAT */
++
++# undef RE_M_F_TYPE
++# undef RE_M_F_DEFAULT
++
++# endif /* DEFINED_ONCE */
++
++# ifdef INT_IS_16BIT
++
++union PREFIX(fail_stack_elt)
++{
++ UCHAR_T *pointer;
++ long int integer;
++};
++
++typedef union PREFIX(fail_stack_elt) PREFIX(fail_stack_elt_t);
++
++typedef struct
++{
++ PREFIX(fail_stack_elt_t) *stack;
++ unsigned long int size;
++ unsigned long int avail; /* Offset of next open position. */
++} PREFIX(fail_stack_type);
++
++# else /* not INT_IS_16BIT */
++
++union PREFIX(fail_stack_elt)
++{
++ UCHAR_T *pointer;
++ int integer;
++};
++
++typedef union PREFIX(fail_stack_elt) PREFIX(fail_stack_elt_t);
++
++typedef struct
++{
++ PREFIX(fail_stack_elt_t) *stack;
++ unsigned size;
++ unsigned avail; /* Offset of next open position. */
++} PREFIX(fail_stack_type);
++
++# endif /* INT_IS_16BIT */
++
++# ifndef DEFINED_ONCE
++# define FAIL_STACK_EMPTY() (fail_stack.avail == 0)
++# define FAIL_STACK_PTR_EMPTY() (fail_stack_ptr->avail == 0)
++# define FAIL_STACK_FULL() (fail_stack.avail == fail_stack.size)
++# endif
++
++
++/* Define macros to initialize and free the failure stack.
++ Do `return -2' if the alloc fails. */
++
++# ifdef MATCH_MAY_ALLOCATE
++# define INIT_FAIL_STACK() \
++ do { \
++ fail_stack.stack = (PREFIX(fail_stack_elt_t) *) \
++ REGEX_ALLOCATE_STACK (INIT_FAILURE_ALLOC * sizeof (PREFIX(fail_stack_elt_t))); \
++ \
++ if (fail_stack.stack == NULL) \
++ return -2; \
++ \
++ fail_stack.size = INIT_FAILURE_ALLOC; \
++ fail_stack.avail = 0; \
++ } while (0)
++
++# define RESET_FAIL_STACK() REGEX_FREE_STACK (fail_stack.stack)
++# else
++# define INIT_FAIL_STACK() \
++ do { \
++ fail_stack.avail = 0; \
++ } while (0)
++
++# define RESET_FAIL_STACK()
++# endif
++
++
++/* Double the size of FAIL_STACK, up to approximately `re_max_failures' items.
++
++ Return 1 if succeeds, and 0 if either ran out of memory
++ allocating space for it or it was already too large.
++
++ REGEX_REALLOCATE_STACK requires `destination' be declared. */
++
++# define DOUBLE_FAIL_STACK(fail_stack) \
++ ((fail_stack).size > (unsigned) (re_max_failures * MAX_FAILURE_ITEMS) \
++ ? 0 \
++ : ((fail_stack).stack = (PREFIX(fail_stack_elt_t) *) \
++ REGEX_REALLOCATE_STACK ((fail_stack).stack, \
++ (fail_stack).size * sizeof (PREFIX(fail_stack_elt_t)), \
++ ((fail_stack).size << 1) * sizeof (PREFIX(fail_stack_elt_t))),\
++ \
++ (fail_stack).stack == NULL \
++ ? 0 \
++ : ((fail_stack).size <<= 1, \
++ 1)))
++
++
++/* Push pointer POINTER on FAIL_STACK.
++ Return 1 if was able to do so and 0 if ran out of memory allocating
++ space to do so. */
++# define PUSH_PATTERN_OP(POINTER, FAIL_STACK) \
++ ((FAIL_STACK_FULL () \
++ && !DOUBLE_FAIL_STACK (FAIL_STACK)) \
++ ? 0 \
++ : ((FAIL_STACK).stack[(FAIL_STACK).avail++].pointer = POINTER, \
++ 1))
++
++/* Push a pointer value onto the failure stack.
++ Assumes the variable `fail_stack'. Probably should only
++ be called from within `PUSH_FAILURE_POINT'. */
++# define PUSH_FAILURE_POINTER(item) \
++ fail_stack.stack[fail_stack.avail++].pointer = (UCHAR_T *) (item)
++
++/* This pushes an integer-valued item onto the failure stack.
++ Assumes the variable `fail_stack'. Probably should only
++ be called from within `PUSH_FAILURE_POINT'. */
++# define PUSH_FAILURE_INT(item) \
++ fail_stack.stack[fail_stack.avail++].integer = (item)
++
++/* Push a fail_stack_elt_t value onto the failure stack.
++ Assumes the variable `fail_stack'. Probably should only
++ be called from within `PUSH_FAILURE_POINT'. */
++# define PUSH_FAILURE_ELT(item) \
++ fail_stack.stack[fail_stack.avail++] = (item)
++
++/* These three POP... operations complement the three PUSH... operations.
++ All assume that `fail_stack' is nonempty. */
++# define POP_FAILURE_POINTER() fail_stack.stack[--fail_stack.avail].pointer
++# define POP_FAILURE_INT() fail_stack.stack[--fail_stack.avail].integer
++# define POP_FAILURE_ELT() fail_stack.stack[--fail_stack.avail]
++
++/* Used to omit pushing failure point id's when we're not debugging. */
++# ifdef DEBUG
++# define DEBUG_PUSH PUSH_FAILURE_INT
++# define DEBUG_POP(item_addr) *(item_addr) = POP_FAILURE_INT ()
++# else
++# define DEBUG_PUSH(item)
++# define DEBUG_POP(item_addr)
++# endif
++
++
++/* Push the information about the state we will need
++ if we ever fail back to it.
++
++ Requires variables fail_stack, regstart, regend, reg_info, and
++ num_regs_pushed be declared. DOUBLE_FAIL_STACK requires `destination'
++ be declared.
++
++ Does `return FAILURE_CODE' if runs out of memory. */
++
++# define PUSH_FAILURE_POINT(pattern_place, string_place, failure_code) \
++ do { \
++ char *destination; \
++ /* Must be int, so when we don't save any registers, the arithmetic \
++ of 0 + -1 isn't done as unsigned. */ \
++ /* Can't be int, since there is not a shred of a guarantee that int \
++ is wide enough to hold a value of something to which pointer can \
++ be assigned */ \
++ active_reg_t this_reg; \
++ \
++ DEBUG_STATEMENT (failure_id++); \
++ DEBUG_STATEMENT (nfailure_points_pushed++); \
++ DEBUG_PRINT2 ("\nPUSH_FAILURE_POINT #%u:\n", failure_id); \
++ DEBUG_PRINT2 (" Before push, next avail: %d\n", (fail_stack).avail);\
++ DEBUG_PRINT2 (" size: %d\n", (fail_stack).size);\
++ \
++ DEBUG_PRINT2 (" slots needed: %ld\n", NUM_FAILURE_ITEMS); \
++ DEBUG_PRINT2 (" available: %d\n", REMAINING_AVAIL_SLOTS); \
++ \
++ /* Ensure we have enough space allocated for what we will push. */ \
++ while (REMAINING_AVAIL_SLOTS < NUM_FAILURE_ITEMS) \
++ { \
++ if (!DOUBLE_FAIL_STACK (fail_stack)) \
++ return failure_code; \
++ \
++ DEBUG_PRINT2 ("\n Doubled stack; size now: %d\n", \
++ (fail_stack).size); \
++ DEBUG_PRINT2 (" slots available: %d\n", REMAINING_AVAIL_SLOTS);\
++ } \
++ \
++ /* Push the info, starting with the registers. */ \
++ DEBUG_PRINT1 ("\n"); \
++ \
++ if (1) \
++ for (this_reg = lowest_active_reg; this_reg <= highest_active_reg; \
++ this_reg++) \
++ { \
++ DEBUG_PRINT2 (" Pushing reg: %lu\n", this_reg); \
++ DEBUG_STATEMENT (num_regs_pushed++); \
++ \
++ DEBUG_PRINT2 (" start: %p\n", regstart[this_reg]); \
++ PUSH_FAILURE_POINTER (regstart[this_reg]); \
++ \
++ DEBUG_PRINT2 (" end: %p\n", regend[this_reg]); \
++ PUSH_FAILURE_POINTER (regend[this_reg]); \
++ \
++ DEBUG_PRINT2 (" info: %p\n ", \
++ reg_info[this_reg].word.pointer); \
++ DEBUG_PRINT2 (" match_null=%d", \
++ REG_MATCH_NULL_STRING_P (reg_info[this_reg])); \
++ DEBUG_PRINT2 (" active=%d", IS_ACTIVE (reg_info[this_reg])); \
++ DEBUG_PRINT2 (" matched_something=%d", \
++ MATCHED_SOMETHING (reg_info[this_reg])); \
++ DEBUG_PRINT2 (" ever_matched=%d", \
++ EVER_MATCHED_SOMETHING (reg_info[this_reg])); \
++ DEBUG_PRINT1 ("\n"); \
++ PUSH_FAILURE_ELT (reg_info[this_reg].word); \
++ } \
++ \
++ DEBUG_PRINT2 (" Pushing low active reg: %ld\n", lowest_active_reg);\
++ PUSH_FAILURE_INT (lowest_active_reg); \
++ \
++ DEBUG_PRINT2 (" Pushing high active reg: %ld\n", highest_active_reg);\
++ PUSH_FAILURE_INT (highest_active_reg); \
++ \
++ DEBUG_PRINT2 (" Pushing pattern %p:\n", pattern_place); \
++ DEBUG_PRINT_COMPILED_PATTERN (bufp, pattern_place, pend); \
++ PUSH_FAILURE_POINTER (pattern_place); \
++ \
++ DEBUG_PRINT2 (" Pushing string %p: `", string_place); \
++ DEBUG_PRINT_DOUBLE_STRING (string_place, string1, size1, string2, \
++ size2); \
++ DEBUG_PRINT1 ("'\n"); \
++ PUSH_FAILURE_POINTER (string_place); \
++ \
++ DEBUG_PRINT2 (" Pushing failure id: %u\n", failure_id); \
++ DEBUG_PUSH (failure_id); \
++ } while (0)
++
++# ifndef DEFINED_ONCE
++/* This is the number of items that are pushed and popped on the stack
++ for each register. */
++# define NUM_REG_ITEMS 3
++
++/* Individual items aside from the registers. */
++# ifdef DEBUG
++# define NUM_NONREG_ITEMS 5 /* Includes failure point id. */
++# else
++# define NUM_NONREG_ITEMS 4
++# endif
++
++/* We push at most this many items on the stack. */
++/* We used to use (num_regs - 1), which is the number of registers
++ this regexp will save; but that was changed to 5
++ to avoid stack overflow for a regexp with lots of parens. */
++# define MAX_FAILURE_ITEMS (5 * NUM_REG_ITEMS + NUM_NONREG_ITEMS)
++
++/* We actually push this many items. */
++# define NUM_FAILURE_ITEMS \
++ (((0 \
++ ? 0 : highest_active_reg - lowest_active_reg + 1) \
++ * NUM_REG_ITEMS) \
++ + NUM_NONREG_ITEMS)
++
++/* How many items can still be added to the stack without overflowing it. */
++# define REMAINING_AVAIL_SLOTS ((fail_stack).size - (fail_stack).avail)
++# endif /* not DEFINED_ONCE */
++
++
++/* Pops what PUSH_FAIL_STACK pushes.
++
++ We restore into the parameters, all of which should be lvalues:
++ STR -- the saved data position.
++ PAT -- the saved pattern position.
++ LOW_REG, HIGH_REG -- the highest and lowest active registers.
++ REGSTART, REGEND -- arrays of string positions.
++ REG_INFO -- array of information about each subexpression.
++
++ Also assumes the variables `fail_stack' and (if debugging), `bufp',
++ `pend', `string1', `size1', `string2', and `size2'. */
++# define POP_FAILURE_POINT(str, pat, low_reg, high_reg, regstart, regend, reg_info)\
++{ \
++ DEBUG_STATEMENT (unsigned failure_id;) \
++ active_reg_t this_reg; \
++ const UCHAR_T *string_temp; \
++ \
++ assert (!FAIL_STACK_EMPTY ()); \
++ \
++ /* Remove failure points and point to how many regs pushed. */ \
++ DEBUG_PRINT1 ("POP_FAILURE_POINT:\n"); \
++ DEBUG_PRINT2 (" Before pop, next avail: %d\n", fail_stack.avail); \
++ DEBUG_PRINT2 (" size: %d\n", fail_stack.size); \
++ \
++ assert (fail_stack.avail >= NUM_NONREG_ITEMS); \
++ \
++ DEBUG_POP (&failure_id); \
++ DEBUG_PRINT2 (" Popping failure id: %u\n", failure_id); \
++ \
++ /* If the saved string location is NULL, it came from an \
++ on_failure_keep_string_jump opcode, and we want to throw away the \
++ saved NULL, thus retaining our current position in the string. */ \
++ string_temp = POP_FAILURE_POINTER (); \
++ if (string_temp != NULL) \
++ str = (const CHAR_T *) string_temp; \
++ \
++ DEBUG_PRINT2 (" Popping string %p: `", str); \
++ DEBUG_PRINT_DOUBLE_STRING (str, string1, size1, string2, size2); \
++ DEBUG_PRINT1 ("'\n"); \
++ \
++ pat = (UCHAR_T *) POP_FAILURE_POINTER (); \
++ DEBUG_PRINT2 (" Popping pattern %p:\n", pat); \
++ DEBUG_PRINT_COMPILED_PATTERN (bufp, pat, pend); \
++ \
++ /* Restore register info. */ \
++ high_reg = (active_reg_t) POP_FAILURE_INT (); \
++ DEBUG_PRINT2 (" Popping high active reg: %ld\n", high_reg); \
++ \
++ low_reg = (active_reg_t) POP_FAILURE_INT (); \
++ DEBUG_PRINT2 (" Popping low active reg: %ld\n", low_reg); \
++ \
++ if (1) \
++ for (this_reg = high_reg; this_reg >= low_reg; this_reg--) \
++ { \
++ DEBUG_PRINT2 (" Popping reg: %ld\n", this_reg); \
++ \
++ reg_info[this_reg].word = POP_FAILURE_ELT (); \
++ DEBUG_PRINT2 (" info: %p\n", \
++ reg_info[this_reg].word.pointer); \
++ \
++ regend[this_reg] = (const CHAR_T *) POP_FAILURE_POINTER (); \
++ DEBUG_PRINT2 (" end: %p\n", regend[this_reg]); \
++ \
++ regstart[this_reg] = (const CHAR_T *) POP_FAILURE_POINTER (); \
++ DEBUG_PRINT2 (" start: %p\n", regstart[this_reg]); \
++ } \
++ else \
++ { \
++ for (this_reg = highest_active_reg; this_reg > high_reg; this_reg--) \
++ { \
++ reg_info[this_reg].word.integer = 0; \
++ regend[this_reg] = 0; \
++ regstart[this_reg] = 0; \
++ } \
++ highest_active_reg = high_reg; \
++ } \
++ \
++ set_regs_matched_done = 0; \
++ DEBUG_STATEMENT (nfailure_points_popped++); \
++} /* POP_FAILURE_POINT */
++
++/* Structure for per-register (a.k.a. per-group) information.
++ Other register information, such as the
++ starting and ending positions (which are addresses), and the list of
++ inner groups (which is a bits list) are maintained in separate
++ variables.
++
++ We are making a (strictly speaking) nonportable assumption here: that
++ the compiler will pack our bit fields into something that fits into
++ the type of `word', i.e., is something that fits into one item on the
++ failure stack. */
++
++
++/* Declarations and macros for re_match_2. */
++
++typedef union
++{
++ PREFIX(fail_stack_elt_t) word;
++ struct
++ {
++ /* This field is one if this group can match the empty string,
++ zero if not. If not yet determined, `MATCH_NULL_UNSET_VALUE'. */
++# define MATCH_NULL_UNSET_VALUE 3
++ unsigned match_null_string_p : 2;
++ unsigned is_active : 1;
++ unsigned matched_something : 1;
++ unsigned ever_matched_something : 1;
++ } bits;
++} PREFIX(register_info_type);
++
++# ifndef DEFINED_ONCE
++# define REG_MATCH_NULL_STRING_P(R) ((R).bits.match_null_string_p)
++# define IS_ACTIVE(R) ((R).bits.is_active)
++# define MATCHED_SOMETHING(R) ((R).bits.matched_something)
++# define EVER_MATCHED_SOMETHING(R) ((R).bits.ever_matched_something)
++
++
++/* Call this when have matched a real character; it sets `matched' flags
++ for the subexpressions which we are currently inside. Also records
++ that those subexprs have matched. */
++# define SET_REGS_MATCHED() \
++ do \
++ { \
++ if (!set_regs_matched_done) \
++ { \
++ active_reg_t r; \
++ set_regs_matched_done = 1; \
++ for (r = lowest_active_reg; r <= highest_active_reg; r++) \
++ { \
++ MATCHED_SOMETHING (reg_info[r]) \
++ = EVER_MATCHED_SOMETHING (reg_info[r]) \
++ = 1; \
++ } \
++ } \
++ } \
++ while (0)
++# endif /* not DEFINED_ONCE */
++
++/* Registers are set to a sentinel when they haven't yet matched. */
++static CHAR_T PREFIX(reg_unset_dummy);
++# define REG_UNSET_VALUE (&PREFIX(reg_unset_dummy))
++# define REG_UNSET(e) ((e) == REG_UNSET_VALUE)
++
++/* Subroutine declarations and macros for regex_compile. */
++static void PREFIX(store_op1) (re_opcode_t op, UCHAR_T *loc, int arg);
++static void PREFIX(store_op2) (re_opcode_t op, UCHAR_T *loc,
++ int arg1, int arg2);
++static void PREFIX(insert_op1) (re_opcode_t op, UCHAR_T *loc,
++ int arg, UCHAR_T *end);
++static void PREFIX(insert_op2) (re_opcode_t op, UCHAR_T *loc,
++ int arg1, int arg2, UCHAR_T *end);
++static boolean PREFIX(at_begline_loc_p) (const CHAR_T *pattern,
++ const CHAR_T *p,
++ reg_syntax_t syntax);
++static boolean PREFIX(at_endline_loc_p) (const CHAR_T *p,
++ const CHAR_T *pend,
++ reg_syntax_t syntax);
++# ifdef WCHAR
++static reg_errcode_t wcs_compile_range (CHAR_T range_start,
++ const CHAR_T **p_ptr,
++ const CHAR_T *pend,
++ char *translate,
++ reg_syntax_t syntax,
++ UCHAR_T *b,
++ CHAR_T *char_set);
++static void insert_space (int num, CHAR_T *loc, CHAR_T *end);
++# else /* BYTE */
++static reg_errcode_t byte_compile_range (unsigned int range_start,
++ const char **p_ptr,
++ const char *pend,
++ RE_TRANSLATE_TYPE translate,
++ reg_syntax_t syntax,
++ unsigned char *b);
++# endif /* WCHAR */
++
++/* Fetch the next character in the uncompiled pattern---translating it
++ if necessary. Also cast from a signed character in the constant
++ string passed to us by the user to an unsigned char that we can use
++ as an array index (in, e.g., `translate'). */
++/* ifdef MBS_SUPPORT, we translate only if character <= 0xff,
++ because it is impossible to allocate 4GB array for some encodings
++ which have 4 byte character_set like UCS4. */
++# ifndef PATFETCH
++# ifdef WCHAR
++# define PATFETCH(c) \
++ do {if (p == pend) return REG_EEND; \
++ c = (UCHAR_T) *p++; \
++ if (translate && (c <= 0xff)) c = (UCHAR_T) translate[c]; \
++ } while (0)
++# else /* BYTE */
++# define PATFETCH(c) \
++ do {if (p == pend) return REG_EEND; \
++ c = (unsigned char) *p++; \
++ if (translate) c = (unsigned char) translate[c]; \
++ } while (0)
++# endif /* WCHAR */
++# endif
++
++/* Fetch the next character in the uncompiled pattern, with no
++ translation. */
++# define PATFETCH_RAW(c) \
++ do {if (p == pend) return REG_EEND; \
++ c = (UCHAR_T) *p++; \
++ } while (0)
++
++/* Go backwards one character in the pattern. */
++# define PATUNFETCH p--
++
++
++/* If `translate' is non-null, return translate[D], else just D. We
++ cast the subscript to translate because some data is declared as
++ `char *', to avoid warnings when a string constant is passed. But
++ when we use a character as a subscript we must make it unsigned. */
++/* ifdef MBS_SUPPORT, we translate only if character <= 0xff,
++ because it is impossible to allocate 4GB array for some encodings
++ which have 4 byte character_set like UCS4. */
++
++# ifndef TRANSLATE
++# ifdef WCHAR
++# define TRANSLATE(d) \
++ ((translate && ((UCHAR_T) (d)) <= 0xff) \
++ ? (char) translate[(unsigned char) (d)] : (d))
++# else /* BYTE */
++# define TRANSLATE(d) \
++ (translate ? (char) translate[(unsigned char) (d)] : (char) (d))
++# endif /* WCHAR */
++# endif
++
++
++/* Macros for outputting the compiled pattern into `buffer'. */
++
++/* If the buffer isn't allocated when it comes in, use this. */
++# define INIT_BUF_SIZE (32 * sizeof(UCHAR_T))
++
++/* Make sure we have at least N more bytes of space in buffer. */
++# ifdef WCHAR
++# define GET_BUFFER_SPACE(n) \
++ while (((unsigned long)b - (unsigned long)COMPILED_BUFFER_VAR \
++ + (n)*sizeof(CHAR_T)) > bufp->allocated) \
++ EXTEND_BUFFER ()
++# else /* BYTE */
++# define GET_BUFFER_SPACE(n) \
++ while ((unsigned long) (b - bufp->buffer + (n)) > bufp->allocated) \
++ EXTEND_BUFFER ()
++# endif /* WCHAR */
++
++/* Make sure we have one more byte of buffer space and then add C to it. */
++# define BUF_PUSH(c) \
++ do { \
++ GET_BUFFER_SPACE (1); \
++ *b++ = (UCHAR_T) (c); \
++ } while (0)
++
++
++/* Ensure we have two more bytes of buffer space and then append C1 and C2. */
++# define BUF_PUSH_2(c1, c2) \
++ do { \
++ GET_BUFFER_SPACE (2); \
++ *b++ = (UCHAR_T) (c1); \
++ *b++ = (UCHAR_T) (c2); \
++ } while (0)
++
++
++/* As with BUF_PUSH_2, except for three bytes. */
++# define BUF_PUSH_3(c1, c2, c3) \
++ do { \
++ GET_BUFFER_SPACE (3); \
++ *b++ = (UCHAR_T) (c1); \
++ *b++ = (UCHAR_T) (c2); \
++ *b++ = (UCHAR_T) (c3); \
++ } while (0)
++
++/* Store a jump with opcode OP at LOC to location TO. We store a
++ relative address offset by the three bytes the jump itself occupies. */
++# define STORE_JUMP(op, loc, to) \
++ PREFIX(store_op1) (op, loc, (int) ((to) - (loc) - (1 + OFFSET_ADDRESS_SIZE)))
++
++/* Likewise, for a two-argument jump. */
++# define STORE_JUMP2(op, loc, to, arg) \
++ PREFIX(store_op2) (op, loc, (int) ((to) - (loc) - (1 + OFFSET_ADDRESS_SIZE)), arg)
++
++/* Like `STORE_JUMP', but for inserting. Assume `b' is the buffer end. */
++# define INSERT_JUMP(op, loc, to) \
++ PREFIX(insert_op1) (op, loc, (int) ((to) - (loc) - (1 + OFFSET_ADDRESS_SIZE)), b)
++
++/* Like `STORE_JUMP2', but for inserting. Assume `b' is the buffer end. */
++# define INSERT_JUMP2(op, loc, to, arg) \
++ PREFIX(insert_op2) (op, loc, (int) ((to) - (loc) - (1 + OFFSET_ADDRESS_SIZE)),\
++ arg, b)
++
++/* This is not an arbitrary limit: the arguments which represent offsets
++ into the pattern are two bytes long. So if 2^16 bytes turns out to
++ be too small, many things would have to change. */
++/* Any other compiler which, like MSC, has allocation limit below 2^16
++ bytes will have to use approach similar to what was done below for
++ MSC and drop MAX_BUF_SIZE a bit. Otherwise you may end up
++ reallocating to 0 bytes. Such thing is not going to work too well.
++ You have been warned!! */
++# ifndef DEFINED_ONCE
++# if defined _MSC_VER && !defined WIN32
++/* Microsoft C 16-bit versions limit malloc to approx 65512 bytes.
++ The REALLOC define eliminates a flurry of conversion warnings,
++ but is not required. */
++# define MAX_BUF_SIZE 65500L
++# define REALLOC(p,s) realloc ((p), (size_t) (s))
++# else
++# define MAX_BUF_SIZE (1L << 16)
++# define REALLOC(p,s) realloc ((p), (s))
++# endif
++
++/* Extend the buffer by twice its current size via realloc and
++ reset the pointers that pointed into the old block to point to the
++ correct places in the new one. If extending the buffer results in it
++ being larger than MAX_BUF_SIZE, then flag memory exhausted. */
++# if __BOUNDED_POINTERS__
++# define SET_HIGH_BOUND(P) (__ptrhigh (P) = __ptrlow (P) + bufp->allocated)
++# define MOVE_BUFFER_POINTER(P) \
++ (__ptrlow (P) += incr, SET_HIGH_BOUND (P), __ptrvalue (P) += incr)
++# define ELSE_EXTEND_BUFFER_HIGH_BOUND \
++ else \
++ { \
++ SET_HIGH_BOUND (b); \
++ SET_HIGH_BOUND (begalt); \
++ if (fixup_alt_jump) \
++ SET_HIGH_BOUND (fixup_alt_jump); \
++ if (laststart) \
++ SET_HIGH_BOUND (laststart); \
++ if (pending_exact) \
++ SET_HIGH_BOUND (pending_exact); \
++ }
++# else
++# define MOVE_BUFFER_POINTER(P) (P) += incr
++# define ELSE_EXTEND_BUFFER_HIGH_BOUND
++# endif
++# endif /* not DEFINED_ONCE */
++
++# ifdef WCHAR
++# define EXTEND_BUFFER() \
++ do { \
++ UCHAR_T *old_buffer = COMPILED_BUFFER_VAR; \
++ int wchar_count; \
++ if (bufp->allocated + sizeof(UCHAR_T) > MAX_BUF_SIZE) \
++ return REG_ESIZE; \
++ bufp->allocated <<= 1; \
++ if (bufp->allocated > MAX_BUF_SIZE) \
++ bufp->allocated = MAX_BUF_SIZE; \
++ /* How many characters the new buffer can have? */ \
++ wchar_count = bufp->allocated / sizeof(UCHAR_T); \
++ if (wchar_count == 0) wchar_count = 1; \
++ /* Truncate the buffer to CHAR_T align. */ \
++ bufp->allocated = wchar_count * sizeof(UCHAR_T); \
++ RETALLOC (COMPILED_BUFFER_VAR, wchar_count, UCHAR_T); \
++ bufp->buffer = (char*)COMPILED_BUFFER_VAR; \
++ if (COMPILED_BUFFER_VAR == NULL) \
++ return REG_ESPACE; \
++ /* If the buffer moved, move all the pointers into it. */ \
++ if (old_buffer != COMPILED_BUFFER_VAR) \
++ { \
++ int incr = COMPILED_BUFFER_VAR - old_buffer; \
++ MOVE_BUFFER_POINTER (b); \
++ MOVE_BUFFER_POINTER (begalt); \
++ if (fixup_alt_jump) \
++ MOVE_BUFFER_POINTER (fixup_alt_jump); \
++ if (laststart) \
++ MOVE_BUFFER_POINTER (laststart); \
++ if (pending_exact) \
++ MOVE_BUFFER_POINTER (pending_exact); \
++ } \
++ ELSE_EXTEND_BUFFER_HIGH_BOUND \
++ } while (0)
++# else /* BYTE */
++# define EXTEND_BUFFER() \
++ do { \
++ UCHAR_T *old_buffer = COMPILED_BUFFER_VAR; \
++ if (bufp->allocated == MAX_BUF_SIZE) \
++ return REG_ESIZE; \
++ bufp->allocated <<= 1; \
++ if (bufp->allocated > MAX_BUF_SIZE) \
++ bufp->allocated = MAX_BUF_SIZE; \
++ bufp->buffer = (UCHAR_T *) REALLOC (COMPILED_BUFFER_VAR, \
++ bufp->allocated); \
++ if (COMPILED_BUFFER_VAR == NULL) \
++ return REG_ESPACE; \
++ /* If the buffer moved, move all the pointers into it. */ \
++ if (old_buffer != COMPILED_BUFFER_VAR) \
++ { \
++ int incr = COMPILED_BUFFER_VAR - old_buffer; \
++ MOVE_BUFFER_POINTER (b); \
++ MOVE_BUFFER_POINTER (begalt); \
++ if (fixup_alt_jump) \
++ MOVE_BUFFER_POINTER (fixup_alt_jump); \
++ if (laststart) \
++ MOVE_BUFFER_POINTER (laststart); \
++ if (pending_exact) \
++ MOVE_BUFFER_POINTER (pending_exact); \
++ } \
++ ELSE_EXTEND_BUFFER_HIGH_BOUND \
++ } while (0)
++# endif /* WCHAR */
++
++# ifndef DEFINED_ONCE
++/* Since we have one byte reserved for the register number argument to
++ {start,stop}_memory, the maximum number of groups we can report
++ things about is what fits in that byte. */
++# define MAX_REGNUM 255
++
++/* But patterns can have more than `MAX_REGNUM' registers. We just
++ ignore the excess. */
++typedef unsigned regnum_t;
++
++
++/* Macros for the compile stack. */
++
++/* Since offsets can go either forwards or backwards, this type needs to
++ be able to hold values from -(MAX_BUF_SIZE - 1) to MAX_BUF_SIZE - 1. */
++/* int may be not enough when sizeof(int) == 2. */
++typedef long pattern_offset_t;
++
++typedef struct
++{
++ pattern_offset_t begalt_offset;
++ pattern_offset_t fixup_alt_jump;
++ pattern_offset_t inner_group_offset;
++ pattern_offset_t laststart_offset;
++ regnum_t regnum;
++} compile_stack_elt_t;
++
++
++typedef struct
++{
++ compile_stack_elt_t *stack;
++ unsigned size;
++ unsigned avail; /* Offset of next open position. */
++} compile_stack_type;
++
++
++# define INIT_COMPILE_STACK_SIZE 32
++
++# define COMPILE_STACK_EMPTY (compile_stack.avail == 0)
++# define COMPILE_STACK_FULL (compile_stack.avail == compile_stack.size)
++
++/* The next available element. */
++# define COMPILE_STACK_TOP (compile_stack.stack[compile_stack.avail])
++
++# endif /* not DEFINED_ONCE */
++
++/* Set the bit for character C in a list. */
++# ifndef DEFINED_ONCE
++# define SET_LIST_BIT(c) \
++ (b[((unsigned char) (c)) / BYTEWIDTH] \
++ |= 1 << (((unsigned char) c) % BYTEWIDTH))
++# endif /* DEFINED_ONCE */
++
++/* Get the next unsigned number in the uncompiled pattern. */
++# define GET_UNSIGNED_NUMBER(num) \
++ { \
++ while (p != pend) \
++ { \
++ PATFETCH (c); \
++ if (c < '0' || c > '9') \
++ break; \
++ if (num <= RE_DUP_MAX) \
++ { \
++ if (num < 0) \
++ num = 0; \
++ num = num * 10 + c - '0'; \
++ } \
++ } \
++ }
++
++# ifndef DEFINED_ONCE
++# if WIDE_CHAR_SUPPORT
++/* The GNU C library provides support for user-defined character classes
++ and the functions from ISO C amendement 1. */
++# ifdef CHARCLASS_NAME_MAX
++# define CHAR_CLASS_MAX_LENGTH CHARCLASS_NAME_MAX
++# else
++/* This shouldn't happen but some implementation might still have this
++ problem. Use a reasonable default value. */
++# define CHAR_CLASS_MAX_LENGTH 256
++# endif
++
++# ifdef _LIBC
++# define IS_CHAR_CLASS(string) __wctype (string)
++# else
++# define IS_CHAR_CLASS(string) wctype (string)
++# endif
++# else
++# define CHAR_CLASS_MAX_LENGTH 6 /* Namely, `xdigit'. */
++
++# define IS_CHAR_CLASS(string) \
++ (STREQ (string, "alpha") || STREQ (string, "upper") \
++ || STREQ (string, "lower") || STREQ (string, "digit") \
++ || STREQ (string, "alnum") || STREQ (string, "xdigit") \
++ || STREQ (string, "space") || STREQ (string, "print") \
++ || STREQ (string, "punct") || STREQ (string, "graph") \
++ || STREQ (string, "cntrl") || STREQ (string, "blank"))
++# endif
++# endif /* DEFINED_ONCE */
++
++# ifndef MATCH_MAY_ALLOCATE
++
++/* If we cannot allocate large objects within re_match_2_internal,
++ we make the fail stack and register vectors global.
++ The fail stack, we grow to the maximum size when a regexp
++ is compiled.
++ The register vectors, we adjust in size each time we
++ compile a regexp, according to the number of registers it needs. */
++
++static PREFIX(fail_stack_type) fail_stack;
++
++/* Size with which the following vectors are currently allocated.
++ That is so we can make them bigger as needed,
++ but never make them smaller. */
++# ifdef DEFINED_ONCE
++static int regs_allocated_size;
++
++static const char ** regstart, ** regend;
++static const char ** old_regstart, ** old_regend;
++static const char **best_regstart, **best_regend;
++static const char **reg_dummy;
++# endif /* DEFINED_ONCE */
++
++static PREFIX(register_info_type) *PREFIX(reg_info);
++static PREFIX(register_info_type) *PREFIX(reg_info_dummy);
++
++/* Make the register vectors big enough for NUM_REGS registers,
++ but don't make them smaller. */
++
++static void
++PREFIX(regex_grow_registers) (int num_regs)
++{
++ if (num_regs > regs_allocated_size)
++ {
++ RETALLOC_IF (regstart, num_regs, const char *);
++ RETALLOC_IF (regend, num_regs, const char *);
++ RETALLOC_IF (old_regstart, num_regs, const char *);
++ RETALLOC_IF (old_regend, num_regs, const char *);
++ RETALLOC_IF (best_regstart, num_regs, const char *);
++ RETALLOC_IF (best_regend, num_regs, const char *);
++ RETALLOC_IF (PREFIX(reg_info), num_regs, PREFIX(register_info_type));
++ RETALLOC_IF (reg_dummy, num_regs, const char *);
++ RETALLOC_IF (PREFIX(reg_info_dummy), num_regs, PREFIX(register_info_type));
++
++ regs_allocated_size = num_regs;
++ }
++}
++
++# endif /* not MATCH_MAY_ALLOCATE */
++
++# ifndef DEFINED_ONCE
++static boolean group_in_compile_stack (compile_stack_type compile_stack,
++ regnum_t regnum);
++# endif /* not DEFINED_ONCE */
++
++/* `regex_compile' compiles PATTERN (of length SIZE) according to SYNTAX.
++ Returns one of error codes defined in `regex.h', or zero for success.
++
++ Assumes the `allocated' (and perhaps `buffer') and `translate'
++ fields are set in BUFP on entry.
++
++ If it succeeds, results are put in BUFP (if it returns an error, the
++ contents of BUFP are undefined):
++ `buffer' is the compiled pattern;
++ `syntax' is set to SYNTAX;
++ `used' is set to the length of the compiled pattern;
++ `fastmap_accurate' is zero;
++ `re_nsub' is the number of subexpressions in PATTERN;
++ `not_bol' and `not_eol' are zero;
++
++ The `fastmap' and `newline_anchor' fields are neither
++ examined nor set. */
++
++/* Return, freeing storage we allocated. */
++# ifdef WCHAR
++# define FREE_STACK_RETURN(value) \
++ return (free(pattern), free(mbs_offset), free(is_binary), free (compile_stack.stack), value)
++# else
++# define FREE_STACK_RETURN(value) \
++ return (free (compile_stack.stack), value)
++# endif /* WCHAR */
++
++static reg_errcode_t
++PREFIX(regex_compile) (const char *ARG_PREFIX(pattern),
++ size_t ARG_PREFIX(size), reg_syntax_t syntax,
++ struct re_pattern_buffer *bufp)
++{
++ /* We fetch characters from PATTERN here. Even though PATTERN is
++ `char *' (i.e., signed), we declare these variables as unsigned, so
++ they can be reliably used as array indices. */
++ register UCHAR_T c, c1;
++
++#ifdef WCHAR
++ /* A temporary space to keep wchar_t pattern and compiled pattern. */
++ CHAR_T *pattern, *COMPILED_BUFFER_VAR;
++ size_t size;
++ /* offset buffer for optimization. See convert_mbs_to_wc. */
++ int *mbs_offset = NULL;
++ /* It hold whether each wchar_t is binary data or not. */
++ char *is_binary = NULL;
++ /* A flag whether exactn is handling binary data or not. */
++ char is_exactn_bin = FALSE;
++#endif /* WCHAR */
++
++ /* A random temporary spot in PATTERN. */
++ const CHAR_T *p1;
++
++ /* Points to the end of the buffer, where we should append. */
++ register UCHAR_T *b;
++
++ /* Keeps track of unclosed groups. */
++ compile_stack_type compile_stack;
++
++ /* Points to the current (ending) position in the pattern. */
++#ifdef WCHAR
++ const CHAR_T *p;
++ const CHAR_T *pend;
++#else /* BYTE */
++ const CHAR_T *p = pattern;
++ const CHAR_T *pend = pattern + size;
++#endif /* WCHAR */
++
++ /* How to translate the characters in the pattern. */
++ RE_TRANSLATE_TYPE translate = bufp->translate;
++
++ /* Address of the count-byte of the most recently inserted `exactn'
++ command. This makes it possible to tell if a new exact-match
++ character can be added to that command or if the character requires
++ a new `exactn' command. */
++ UCHAR_T *pending_exact = 0;
++
++ /* Address of start of the most recently finished expression.
++ This tells, e.g., postfix * where to find the start of its
++ operand. Reset at the beginning of groups and alternatives. */
++ UCHAR_T *laststart = 0;
++
++ /* Address of beginning of regexp, or inside of last group. */
++ UCHAR_T *begalt;
++
++ /* Address of the place where a forward jump should go to the end of
++ the containing expression. Each alternative of an `or' -- except the
++ last -- ends with a forward jump of this sort. */
++ UCHAR_T *fixup_alt_jump = 0;
++
++ /* Counts open-groups as they are encountered. Remembered for the
++ matching close-group on the compile stack, so the same register
++ number is put in the stop_memory as the start_memory. */
++ regnum_t regnum = 0;
++
++#ifdef WCHAR
++ /* Initialize the wchar_t PATTERN and offset_buffer. */
++ p = pend = pattern = TALLOC(csize + 1, CHAR_T);
++ mbs_offset = TALLOC(csize + 1, int);
++ is_binary = TALLOC(csize + 1, char);
++ if (pattern == NULL || mbs_offset == NULL || is_binary == NULL)
++ {
++ free(pattern);
++ free(mbs_offset);
++ free(is_binary);
++ return REG_ESPACE;
++ }
++ pattern[csize] = L'\0'; /* sentinel */
++ size = convert_mbs_to_wcs(pattern, cpattern, csize, mbs_offset, is_binary);
++ pend = p + size;
++ if (size < 0)
++ {
++ free(pattern);
++ free(mbs_offset);
++ free(is_binary);
++ return REG_BADPAT;
++ }
++#endif
++
++#ifdef DEBUG
++ DEBUG_PRINT1 ("\nCompiling pattern: ");
++ if (debug)
++ {
++ unsigned debug_count;
++
++ for (debug_count = 0; debug_count < size; debug_count++)
++ PUT_CHAR (pattern[debug_count]);
++ putchar ('\n');
++ }
++#endif /* DEBUG */
++
++ /* Initialize the compile stack. */
++ compile_stack.stack = TALLOC (INIT_COMPILE_STACK_SIZE, compile_stack_elt_t);
++ if (compile_stack.stack == NULL)
++ {
++#ifdef WCHAR
++ free(pattern);
++ free(mbs_offset);
++ free(is_binary);
++#endif
++ return REG_ESPACE;
++ }
++
++ compile_stack.size = INIT_COMPILE_STACK_SIZE;
++ compile_stack.avail = 0;
++
++ /* Initialize the pattern buffer. */
++ bufp->syntax = syntax;
++ bufp->fastmap_accurate = 0;
++ bufp->not_bol = bufp->not_eol = 0;
++
++ /* Set `used' to zero, so that if we return an error, the pattern
++ printer (for debugging) will think there's no pattern. We reset it
++ at the end. */
++ bufp->used = 0;
++
++ /* Always count groups, whether or not bufp->no_sub is set. */
++ bufp->re_nsub = 0;
++
++#if !defined emacs && !defined SYNTAX_TABLE
++ /* Initialize the syntax table. */
++ init_syntax_once ();
++#endif
++
++ if (bufp->allocated == 0)
++ {
++ if (bufp->buffer)
++ { /* If zero allocated, but buffer is non-null, try to realloc
++ enough space. This loses if buffer's address is bogus, but
++ that is the user's responsibility. */
++#ifdef WCHAR
++ /* Free bufp->buffer and allocate an array for wchar_t pattern
++ buffer. */
++ free(bufp->buffer);
++ COMPILED_BUFFER_VAR = TALLOC (INIT_BUF_SIZE/sizeof(UCHAR_T),
++ UCHAR_T);
++#else
++ RETALLOC (COMPILED_BUFFER_VAR, INIT_BUF_SIZE, UCHAR_T);
++#endif /* WCHAR */
++ }
++ else
++ { /* Caller did not allocate a buffer. Do it for them. */
++ COMPILED_BUFFER_VAR = TALLOC (INIT_BUF_SIZE / sizeof(UCHAR_T),
++ UCHAR_T);
++ }
++
++ if (!COMPILED_BUFFER_VAR) FREE_STACK_RETURN (REG_ESPACE);
++#ifdef WCHAR
++ bufp->buffer = (char*)COMPILED_BUFFER_VAR;
++#endif /* WCHAR */
++ bufp->allocated = INIT_BUF_SIZE;
++ }
++#ifdef WCHAR
++ else
++ COMPILED_BUFFER_VAR = (UCHAR_T*) bufp->buffer;
++#endif
++
++ begalt = b = COMPILED_BUFFER_VAR;
++
++ /* Loop through the uncompiled pattern until we're at the end. */
++ while (p != pend)
++ {
++ PATFETCH (c);
++
++ switch (c)
++ {
++ case '^':
++ {
++ if ( /* If at start of pattern, it's an operator. */
++ p == pattern + 1
++ /* If context independent, it's an operator. */
++ || syntax & RE_CONTEXT_INDEP_ANCHORS
++ /* Otherwise, depends on what's come before. */
++ || PREFIX(at_begline_loc_p) (pattern, p, syntax))
++ BUF_PUSH (begline);
++ else
++ goto normal_char;
++ }
++ break;
++
++
++ case '$':
++ {
++ if ( /* If at end of pattern, it's an operator. */
++ p == pend
++ /* If context independent, it's an operator. */
++ || syntax & RE_CONTEXT_INDEP_ANCHORS
++ /* Otherwise, depends on what's next. */
++ || PREFIX(at_endline_loc_p) (p, pend, syntax))
++ BUF_PUSH (endline);
++ else
++ goto normal_char;
++ }
++ break;
++
++
++ case '+':
++ case '?':
++ if ((syntax & RE_BK_PLUS_QM)
++ || (syntax & RE_LIMITED_OPS))
++ goto normal_char;
++ handle_plus:
++ case '*':
++ /* If there is no previous pattern... */
++ if (!laststart)
++ {
++ if (syntax & RE_CONTEXT_INVALID_OPS)
++ FREE_STACK_RETURN (REG_BADRPT);
++ else if (!(syntax & RE_CONTEXT_INDEP_OPS))
++ goto normal_char;
++ }
++
++ {
++ /* Are we optimizing this jump? */
++ boolean keep_string_p = false;
++
++ /* 1 means zero (many) matches is allowed. */
++ char zero_times_ok = 0, many_times_ok = 0;
++
++ /* If there is a sequence of repetition chars, collapse it
++ down to just one (the right one). We can't combine
++ interval operators with these because of, e.g., `a{2}*',
++ which should only match an even number of `a's. */
++
++ for (;;)
++ {
++ zero_times_ok |= c != '+';
++ many_times_ok |= c != '?';
++
++ if (p == pend)
++ break;
++
++ PATFETCH (c);
++
++ if (c == '*'
++ || (!(syntax & RE_BK_PLUS_QM) && (c == '+' || c == '?')))
++ ;
++
++ else if (syntax & RE_BK_PLUS_QM && c == '\\')
++ {
++ if (p == pend) FREE_STACK_RETURN (REG_EESCAPE);
++
++ PATFETCH (c1);
++ if (!(c1 == '+' || c1 == '?'))
++ {
++ PATUNFETCH;
++ PATUNFETCH;
++ break;
++ }
++
++ c = c1;
++ }
++ else
++ {
++ PATUNFETCH;
++ break;
++ }
++
++ /* If we get here, we found another repeat character. */
++ }
++
++ /* Star, etc. applied to an empty pattern is equivalent
++ to an empty pattern. */
++ if (!laststart)
++ break;
++
++ /* Now we know whether or not zero matches is allowed
++ and also whether or not two or more matches is allowed. */
++ if (many_times_ok)
++ { /* More than one repetition is allowed, so put in at the
++ end a backward relative jump from `b' to before the next
++ jump we're going to put in below (which jumps from
++ laststart to after this jump).
++
++ But if we are at the `*' in the exact sequence `.*\n',
++ insert an unconditional jump backwards to the .,
++ instead of the beginning of the loop. This way we only
++ push a failure point once, instead of every time
++ through the loop. */
++ assert (p - 1 > pattern);
++
++ /* Allocate the space for the jump. */
++ GET_BUFFER_SPACE (1 + OFFSET_ADDRESS_SIZE);
++
++ /* We know we are not at the first character of the pattern,
++ because laststart was nonzero. And we've already
++ incremented `p', by the way, to be the character after
++ the `*'. Do we have to do something analogous here
++ for null bytes, because of RE_DOT_NOT_NULL? */
++ if (TRANSLATE (*(p - 2)) == TRANSLATE ('.')
++ && zero_times_ok
++ && p < pend && TRANSLATE (*p) == TRANSLATE ('\n')
++ && !(syntax & RE_DOT_NEWLINE))
++ { /* We have .*\n. */
++ STORE_JUMP (jump, b, laststart);
++ keep_string_p = true;
++ }
++ else
++ /* Anything else. */
++ STORE_JUMP (maybe_pop_jump, b, laststart -
++ (1 + OFFSET_ADDRESS_SIZE));
++
++ /* We've added more stuff to the buffer. */
++ b += 1 + OFFSET_ADDRESS_SIZE;
++ }
++
++ /* On failure, jump from laststart to b + 3, which will be the
++ end of the buffer after this jump is inserted. */
++ /* ifdef WCHAR, 'b + 1 + OFFSET_ADDRESS_SIZE' instead of
++ 'b + 3'. */
++ GET_BUFFER_SPACE (1 + OFFSET_ADDRESS_SIZE);
++ INSERT_JUMP (keep_string_p ? on_failure_keep_string_jump
++ : on_failure_jump,
++ laststart, b + 1 + OFFSET_ADDRESS_SIZE);
++ pending_exact = 0;
++ b += 1 + OFFSET_ADDRESS_SIZE;
++
++ if (!zero_times_ok)
++ {
++ /* At least one repetition is required, so insert a
++ `dummy_failure_jump' before the initial
++ `on_failure_jump' instruction of the loop. This
++ effects a skip over that instruction the first time
++ we hit that loop. */
++ GET_BUFFER_SPACE (1 + OFFSET_ADDRESS_SIZE);
++ INSERT_JUMP (dummy_failure_jump, laststart, laststart +
++ 2 + 2 * OFFSET_ADDRESS_SIZE);
++ b += 1 + OFFSET_ADDRESS_SIZE;
++ }
++ }
++ break;
++
++
++ case '.':
++ laststart = b;
++ BUF_PUSH (anychar);
++ break;
++
++
++ case '[':
++ {
++ boolean had_char_class = false;
++#ifdef WCHAR
++ CHAR_T range_start = 0xffffffff;
++#else
++ unsigned int range_start = 0xffffffff;
++#endif
++ if (p == pend) FREE_STACK_RETURN (REG_EBRACK);
++
++#ifdef WCHAR
++ /* We assume a charset(_not) structure as a wchar_t array.
++ charset[0] = (re_opcode_t) charset(_not)
++ charset[1] = l (= length of char_classes)
++ charset[2] = m (= length of collating_symbols)
++ charset[3] = n (= length of equivalence_classes)
++ charset[4] = o (= length of char_ranges)
++ charset[5] = p (= length of chars)
++
++ charset[6] = char_class (wctype_t)
++ charset[6+CHAR_CLASS_SIZE] = char_class (wctype_t)
++ ...
++ charset[l+5] = char_class (wctype_t)
++
++ charset[l+6] = collating_symbol (wchar_t)
++ ...
++ charset[l+m+5] = collating_symbol (wchar_t)
++ ifdef _LIBC we use the index if
++ _NL_COLLATE_SYMB_EXTRAMB instead of
++ wchar_t string.
++
++ charset[l+m+6] = equivalence_classes (wchar_t)
++ ...
++ charset[l+m+n+5] = equivalence_classes (wchar_t)
++ ifdef _LIBC we use the index in
++ _NL_COLLATE_WEIGHT instead of
++ wchar_t string.
++
++ charset[l+m+n+6] = range_start
++ charset[l+m+n+7] = range_end
++ ...
++ charset[l+m+n+2o+4] = range_start
++ charset[l+m+n+2o+5] = range_end
++ ifdef _LIBC we use the value looked up
++ in _NL_COLLATE_COLLSEQ instead of
++ wchar_t character.
++
++ charset[l+m+n+2o+6] = char
++ ...
++ charset[l+m+n+2o+p+5] = char
++
++ */
++
++ /* We need at least 6 spaces: the opcode, the length of
++ char_classes, the length of collating_symbols, the length of
++ equivalence_classes, the length of char_ranges, the length of
++ chars. */
++ GET_BUFFER_SPACE (6);
++
++ /* Save b as laststart. And We use laststart as the pointer
++ to the first element of the charset here.
++ In other words, laststart[i] indicates charset[i]. */
++ laststart = b;
++
++ /* We test `*p == '^' twice, instead of using an if
++ statement, so we only need one BUF_PUSH. */
++ BUF_PUSH (*p == '^' ? charset_not : charset);
++ if (*p == '^')
++ p++;
++
++ /* Push the length of char_classes, the length of
++ collating_symbols, the length of equivalence_classes, the
++ length of char_ranges and the length of chars. */
++ BUF_PUSH_3 (0, 0, 0);
++ BUF_PUSH_2 (0, 0);
++
++ /* Remember the first position in the bracket expression. */
++ p1 = p;
++
++ /* charset_not matches newline according to a syntax bit. */
++ if ((re_opcode_t) b[-6] == charset_not
++ && (syntax & RE_HAT_LISTS_NOT_NEWLINE))
++ {
++ BUF_PUSH('\n');
++ laststart[5]++; /* Update the length of characters */
++ }
++
++ /* Read in characters and ranges, setting map bits. */
++ for (;;)
++ {
++ if (p == pend) FREE_STACK_RETURN (REG_EBRACK);
++
++ PATFETCH (c);
++
++ /* \ might escape characters inside [...] and [^...]. */
++ if ((syntax & RE_BACKSLASH_ESCAPE_IN_LISTS) && c == '\\')
++ {
++ if (p == pend) FREE_STACK_RETURN (REG_EESCAPE);
++
++ PATFETCH (c1);
++ BUF_PUSH(c1);
++ laststart[5]++; /* Update the length of chars */
++ range_start = c1;
++ continue;
++ }
++
++ /* Could be the end of the bracket expression. If it's
++ not (i.e., when the bracket expression is `[]' so
++ far), the ']' character bit gets set way below. */
++ if (c == ']' && p != p1 + 1)
++ break;
++
++ /* Look ahead to see if it's a range when the last thing
++ was a character class. */
++ if (had_char_class && c == '-' && *p != ']')
++ FREE_STACK_RETURN (REG_ERANGE);
++
++ /* Look ahead to see if it's a range when the last thing
++ was a character: if this is a hyphen not at the
++ beginning or the end of a list, then it's the range
++ operator. */
++ if (c == '-'
++ && !(p - 2 >= pattern && p[-2] == '[')
++ && !(p - 3 >= pattern && p[-3] == '[' && p[-2] == '^')
++ && *p != ']')
++ {
++ reg_errcode_t ret;
++ /* Allocate the space for range_start and range_end. */
++ GET_BUFFER_SPACE (2);
++ /* Update the pointer to indicate end of buffer. */
++ b += 2;
++ ret = wcs_compile_range (range_start, &p, pend, translate,
++ syntax, b, laststart);
++ if (ret != REG_NOERROR) FREE_STACK_RETURN (ret);
++ range_start = 0xffffffff;
++ }
++ else if (p[0] == '-' && p[1] != ']')
++ { /* This handles ranges made up of characters only. */
++ reg_errcode_t ret;
++
++ /* Move past the `-'. */
++ PATFETCH (c1);
++ /* Allocate the space for range_start and range_end. */
++ GET_BUFFER_SPACE (2);
++ /* Update the pointer to indicate end of buffer. */
++ b += 2;
++ ret = wcs_compile_range (c, &p, pend, translate, syntax, b,
++ laststart);
++ if (ret != REG_NOERROR) FREE_STACK_RETURN (ret);
++ range_start = 0xffffffff;
++ }
++
++ /* See if we're at the beginning of a possible character
++ class. */
++ else if (syntax & RE_CHAR_CLASSES && c == '[' && *p == ':')
++ { /* Leave room for the null. */
++ char str[CHAR_CLASS_MAX_LENGTH + 1];
++
++ PATFETCH (c);
++ c1 = 0;
++
++ /* If pattern is `[[:'. */
++ if (p == pend) FREE_STACK_RETURN (REG_EBRACK);
++
++ for (;;)
++ {
++ PATFETCH (c);
++ if ((c == ':' && *p == ']') || p == pend)
++ break;
++ if (c1 < CHAR_CLASS_MAX_LENGTH)
++ str[c1++] = c;
++ else
++ /* This is in any case an invalid class name. */
++ str[0] = '\0';
++ }
++ str[c1] = '\0';
++
++ /* If isn't a word bracketed by `[:' and `:]':
++ undo the ending character, the letters, and leave
++ the leading `:' and `[' (but store them as character). */
++ if (c == ':' && *p == ']')
++ {
++ wctype_t wt;
++ uintptr_t alignedp;
++
++ /* Query the character class as wctype_t. */
++ wt = IS_CHAR_CLASS (str);
++ if (wt == 0)
++ FREE_STACK_RETURN (REG_ECTYPE);
++
++ /* Throw away the ] at the end of the character
++ class. */
++ PATFETCH (c);
++
++ if (p == pend) FREE_STACK_RETURN (REG_EBRACK);
++
++ /* Allocate the space for character class. */
++ GET_BUFFER_SPACE(CHAR_CLASS_SIZE);
++ /* Update the pointer to indicate end of buffer. */
++ b += CHAR_CLASS_SIZE;
++ /* Move data which follow character classes
++ not to violate the data. */
++ insert_space(CHAR_CLASS_SIZE,
++ laststart + 6 + laststart[1],
++ b - 1);
++ alignedp = ((uintptr_t)(laststart + 6 + laststart[1])
++ + __alignof__(wctype_t) - 1)
++ & ~(uintptr_t)(__alignof__(wctype_t) - 1);
++ /* Store the character class. */
++ *((wctype_t*)alignedp) = wt;
++ /* Update length of char_classes */
++ laststart[1] += CHAR_CLASS_SIZE;
++
++ had_char_class = true;
++ }
++ else
++ {
++ c1++;
++ while (c1--)
++ PATUNFETCH;
++ BUF_PUSH ('[');
++ BUF_PUSH (':');
++ laststart[5] += 2; /* Update the length of characters */
++ range_start = ':';
++ had_char_class = false;
++ }
++ }
++ else if (syntax & RE_CHAR_CLASSES && c == '[' && (*p == '='
++ || *p == '.'))
++ {
++ CHAR_T str[128]; /* Should be large enough. */
++ CHAR_T delim = *p; /* '=' or '.' */
++# ifdef _LIBC
++ uint32_t nrules =
++ _NL_CURRENT_WORD (LC_COLLATE, _NL_COLLATE_NRULES);
++# endif
++ PATFETCH (c);
++ c1 = 0;
++
++ /* If pattern is `[[=' or '[[.'. */
++ if (p == pend) FREE_STACK_RETURN (REG_EBRACK);
++
++ for (;;)
++ {
++ PATFETCH (c);
++ if ((c == delim && *p == ']') || p == pend)
++ break;
++ if (c1 < sizeof (str) - 1)
++ str[c1++] = c;
++ else
++ /* This is in any case an invalid class name. */
++ str[0] = '\0';
++ }
++ str[c1] = '\0';
++
++ if (c == delim && *p == ']' && str[0] != '\0')
++ {
++ unsigned int i, offset;
++ /* If we have no collation data we use the default
++ collation in which each character is in a class
++ by itself. It also means that ASCII is the
++ character set and therefore we cannot have character
++ with more than one byte in the multibyte
++ representation. */
++
++ /* If not defined _LIBC, we push the name and
++ `\0' for the sake of matching performance. */
++ int datasize = c1 + 1;
++
++# ifdef _LIBC
++ int32_t idx = 0;
++ if (nrules == 0)
++# endif
++ {
++ if (c1 != 1)
++ FREE_STACK_RETURN (REG_ECOLLATE);
++ }
++# ifdef _LIBC
++ else
++ {
++ const int32_t *table;
++ const int32_t *weights;
++ const int32_t *extra;
++ const int32_t *indirect;
++ wint_t *cp;
++
++ /* This #include defines a local function! */
++# include <locale/weightwc.h>
++
++ if(delim == '=')
++ {
++ /* We push the index for equivalence class. */
++ cp = (wint_t*)str;
++
++ table = (const int32_t *)
++ _NL_CURRENT (LC_COLLATE,
++ _NL_COLLATE_TABLEWC);
++ weights = (const int32_t *)
++ _NL_CURRENT (LC_COLLATE,
++ _NL_COLLATE_WEIGHTWC);
++ extra = (const int32_t *)
++ _NL_CURRENT (LC_COLLATE,
++ _NL_COLLATE_EXTRAWC);
++ indirect = (const int32_t *)
++ _NL_CURRENT (LC_COLLATE,
++ _NL_COLLATE_INDIRECTWC);
++
++ idx = findidx ((const wint_t**)&cp, c1);
++ if (idx == 0 || cp < (wint_t*) str + c1)
++ /* This is no valid character. */
++ FREE_STACK_RETURN (REG_ECOLLATE);
++
++ str[0] = (wchar_t)idx;
++ }
++ else /* delim == '.' */
++ {
++ /* We push collation sequence value
++ for collating symbol. */
++ int32_t table_size;
++ const int32_t *symb_table;
++ const unsigned char *extra;
++ int32_t idx;
++ int32_t elem;
++ int32_t second;
++ int32_t hash;
++ char char_str[c1];
++
++ /* We have to convert the name to a single-byte
++ string. This is possible since the names
++ consist of ASCII characters and the internal
++ representation is UCS4. */
++ for (i = 0; i < c1; ++i)
++ char_str[i] = str[i];
++
++ table_size =
++ _NL_CURRENT_WORD (LC_COLLATE,
++ _NL_COLLATE_SYMB_HASH_SIZEMB);
++ symb_table = (const int32_t *)
++ _NL_CURRENT (LC_COLLATE,
++ _NL_COLLATE_SYMB_TABLEMB);
++ extra = (const unsigned char *)
++ _NL_CURRENT (LC_COLLATE,
++ _NL_COLLATE_SYMB_EXTRAMB);
++
++ /* Locate the character in the hashing table. */
++ hash = elem_hash (char_str, c1);
++
++ idx = 0;
++ elem = hash % table_size;
++ second = hash % (table_size - 2);
++ while (symb_table[2 * elem] != 0)
++ {
++ /* First compare the hashing value. */
++ if (symb_table[2 * elem] == hash
++ && c1 == extra[symb_table[2 * elem + 1]]
++ && memcmp (char_str,
++ &extra[symb_table[2 * elem + 1]
++ + 1], c1) == 0)
++ {
++ /* Yep, this is the entry. */
++ idx = symb_table[2 * elem + 1];
++ idx += 1 + extra[idx];
++ break;
++ }
++
++ /* Next entry. */
++ elem += second;
++ }
++
++ if (symb_table[2 * elem] != 0)
++ {
++ /* Compute the index of the byte sequence
++ in the table. */
++ idx += 1 + extra[idx];
++ /* Adjust for the alignment. */
++ idx = (idx + 3) & ~3;
++
++ str[0] = (wchar_t) idx + 4;
++ }
++ else if (symb_table[2 * elem] == 0 && c1 == 1)
++ {
++ /* No valid character. Match it as a
++ single byte character. */
++ had_char_class = false;
++ BUF_PUSH(str[0]);
++ /* Update the length of characters */
++ laststart[5]++;
++ range_start = str[0];
++
++ /* Throw away the ] at the end of the
++ collating symbol. */
++ PATFETCH (c);
++ /* exit from the switch block. */
++ continue;
++ }
++ else
++ FREE_STACK_RETURN (REG_ECOLLATE);
++ }
++ datasize = 1;
++ }
++# endif
++ /* Throw away the ] at the end of the equivalence
++ class (or collating symbol). */
++ PATFETCH (c);
++
++ /* Allocate the space for the equivalence class
++ (or collating symbol) (and '\0' if needed). */
++ GET_BUFFER_SPACE(datasize);
++ /* Update the pointer to indicate end of buffer. */
++ b += datasize;
++
++ if (delim == '=')
++ { /* equivalence class */
++ /* Calculate the offset of char_ranges,
++ which is next to equivalence_classes. */
++ offset = laststart[1] + laststart[2]
++ + laststart[3] +6;
++ /* Insert space. */
++ insert_space(datasize, laststart + offset, b - 1);
++
++ /* Write the equivalence_class and \0. */
++ for (i = 0 ; i < datasize ; i++)
++ laststart[offset + i] = str[i];
++
++ /* Update the length of equivalence_classes. */
++ laststart[3] += datasize;
++ had_char_class = true;
++ }
++ else /* delim == '.' */
++ { /* collating symbol */
++ /* Calculate the offset of the equivalence_classes,
++ which is next to collating_symbols. */
++ offset = laststart[1] + laststart[2] + 6;
++ /* Insert space and write the collationg_symbol
++ and \0. */
++ insert_space(datasize, laststart + offset, b-1);
++ for (i = 0 ; i < datasize ; i++)
++ laststart[offset + i] = str[i];
++
++ /* In re_match_2_internal if range_start < -1, we
++ assume -range_start is the offset of the
++ collating symbol which is specified as
++ the character of the range start. So we assign
++ -(laststart[1] + laststart[2] + 6) to
++ range_start. */
++ range_start = -(laststart[1] + laststart[2] + 6);
++ /* Update the length of collating_symbol. */
++ laststart[2] += datasize;
++ had_char_class = false;
++ }
++ }
++ else
++ {
++ c1++;
++ while (c1--)
++ PATUNFETCH;
++ BUF_PUSH ('[');
++ BUF_PUSH (delim);
++ laststart[5] += 2; /* Update the length of characters */
++ range_start = delim;
++ had_char_class = false;
++ }
++ }
++ else
++ {
++ had_char_class = false;
++ BUF_PUSH(c);
++ laststart[5]++; /* Update the length of characters */
++ range_start = c;
++ }
++ }
++
++#else /* BYTE */
++ /* Ensure that we have enough space to push a charset: the
++ opcode, the length count, and the bitset; 34 bytes in all. */
++ GET_BUFFER_SPACE (34);
++
++ laststart = b;
++
++ /* We test `*p == '^' twice, instead of using an if
++ statement, so we only need one BUF_PUSH. */
++ BUF_PUSH (*p == '^' ? charset_not : charset);
++ if (*p == '^')
++ p++;
++
++ /* Remember the first position in the bracket expression. */
++ p1 = p;
++
++ /* Push the number of bytes in the bitmap. */
++ BUF_PUSH ((1 << BYTEWIDTH) / BYTEWIDTH);
++
++ /* Clear the whole map. */
++ bzero (b, (1 << BYTEWIDTH) / BYTEWIDTH);
++
++ /* charset_not matches newline according to a syntax bit. */
++ if ((re_opcode_t) b[-2] == charset_not
++ && (syntax & RE_HAT_LISTS_NOT_NEWLINE))
++ SET_LIST_BIT ('\n');
++
++ /* Read in characters and ranges, setting map bits. */
++ for (;;)
++ {
++ if (p == pend) FREE_STACK_RETURN (REG_EBRACK);
++
++ PATFETCH (c);
++
++ /* \ might escape characters inside [...] and [^...]. */
++ if ((syntax & RE_BACKSLASH_ESCAPE_IN_LISTS) && c == '\\')
++ {
++ if (p == pend) FREE_STACK_RETURN (REG_EESCAPE);
++
++ PATFETCH (c1);
++ SET_LIST_BIT (c1);
++ range_start = c1;
++ continue;
++ }
++
++ /* Could be the end of the bracket expression. If it's
++ not (i.e., when the bracket expression is `[]' so
++ far), the ']' character bit gets set way below. */
++ if (c == ']' && p != p1 + 1)
++ break;
++
++ /* Look ahead to see if it's a range when the last thing
++ was a character class. */
++ if (had_char_class && c == '-' && *p != ']')
++ FREE_STACK_RETURN (REG_ERANGE);
++
++ /* Look ahead to see if it's a range when the last thing
++ was a character: if this is a hyphen not at the
++ beginning or the end of a list, then it's the range
++ operator. */
++ if (c == '-'
++ && !(p - 2 >= pattern && p[-2] == '[')
++ && !(p - 3 >= pattern && p[-3] == '[' && p[-2] == '^')
++ && *p != ']')
++ {
++ reg_errcode_t ret
++ = byte_compile_range (range_start, &p, pend, translate,
++ syntax, b);
++ if (ret != REG_NOERROR) FREE_STACK_RETURN (ret);
++ range_start = 0xffffffff;
++ }
++
++ else if (p[0] == '-' && p[1] != ']')
++ { /* This handles ranges made up of characters only. */
++ reg_errcode_t ret;
++
++ /* Move past the `-'. */
++ PATFETCH (c1);
++
++ ret = byte_compile_range (c, &p, pend, translate, syntax, b);
++ if (ret != REG_NOERROR) FREE_STACK_RETURN (ret);
++ range_start = 0xffffffff;
++ }
++
++ /* See if we're at the beginning of a possible character
++ class. */
++
++ else if (syntax & RE_CHAR_CLASSES && c == '[' && *p == ':')
++ { /* Leave room for the null. */
++ char str[CHAR_CLASS_MAX_LENGTH + 1];
++
++ PATFETCH (c);
++ c1 = 0;
++
++ /* If pattern is `[[:'. */
++ if (p == pend) FREE_STACK_RETURN (REG_EBRACK);
++
++ for (;;)
++ {
++ PATFETCH (c);
++ if ((c == ':' && *p == ']') || p == pend)
++ break;
++ if (((int) c1) < CHAR_CLASS_MAX_LENGTH)
++ str[c1++] = c;
++ else
++ /* This is in any case an invalid class name. */
++ str[0] = '\0';
++ }
++ str[c1] = '\0';
++
++ /* If isn't a word bracketed by `[:' and `:]':
++ undo the ending character, the letters, and leave
++ the leading `:' and `[' (but set bits for them). */
++ if (c == ':' && *p == ']')
++ {
++# if WIDE_CHAR_SUPPORT
++ boolean is_lower = STREQ (str, "lower");
++ boolean is_upper = STREQ (str, "upper");
++ wctype_t wt;
++ int ch;
++
++ wt = IS_CHAR_CLASS (str);
++ if (wt == 0)
++ FREE_STACK_RETURN (REG_ECTYPE);
++
++ /* Throw away the ] at the end of the character
++ class. */
++ PATFETCH (c);
++
++ if (p == pend) FREE_STACK_RETURN (REG_EBRACK);
++
++ for (ch = 0; ch < 1 << BYTEWIDTH; ++ch)
++ {
++# ifdef _LIBC
++ if (__iswctype (__btowc (ch), wt))
++ SET_LIST_BIT (ch);
++# else
++ if (iswctype (btowc (ch), wt))
++ SET_LIST_BIT (ch);
++# endif
++
++ if (translate && (is_upper || is_lower)
++ && (ISUPPER (ch) || ISLOWER (ch)))
++ SET_LIST_BIT (ch);
++ }
++
++ had_char_class = true;
++# else
++ int ch;
++ boolean is_alnum = STREQ (str, "alnum");
++ boolean is_alpha = STREQ (str, "alpha");
++ boolean is_blank = STREQ (str, "blank");
++ boolean is_cntrl = STREQ (str, "cntrl");
++ boolean is_digit = STREQ (str, "digit");
++ boolean is_graph = STREQ (str, "graph");
++ boolean is_lower = STREQ (str, "lower");
++ boolean is_print = STREQ (str, "print");
++ boolean is_punct = STREQ (str, "punct");
++ boolean is_space = STREQ (str, "space");
++ boolean is_upper = STREQ (str, "upper");
++ boolean is_xdigit = STREQ (str, "xdigit");
++
++ if (!IS_CHAR_CLASS (str))
++ FREE_STACK_RETURN (REG_ECTYPE);
++
++ /* Throw away the ] at the end of the character
++ class. */
++ PATFETCH (c);
++
++ if (p == pend) FREE_STACK_RETURN (REG_EBRACK);
++
++ for (ch = 0; ch < 1 << BYTEWIDTH; ch++)
++ {
++ /* This was split into 3 if's to
++ avoid an arbitrary limit in some compiler. */
++ if ( (is_alnum && ISALNUM (ch))
++ || (is_alpha && ISALPHA (ch))
++ || (is_blank && ISBLANK (ch))
++ || (is_cntrl && ISCNTRL (ch)))
++ SET_LIST_BIT (ch);
++ if ( (is_digit && ISDIGIT (ch))
++ || (is_graph && ISGRAPH (ch))
++ || (is_lower && ISLOWER (ch))
++ || (is_print && ISPRINT (ch)))
++ SET_LIST_BIT (ch);
++ if ( (is_punct && ISPUNCT (ch))
++ || (is_space && ISSPACE (ch))
++ || (is_upper && ISUPPER (ch))
++ || (is_xdigit && ISXDIGIT (ch)))
++ SET_LIST_BIT (ch);
++ if ( translate && (is_upper || is_lower)
++ && (ISUPPER (ch) || ISLOWER (ch)))
++ SET_LIST_BIT (ch);
++ }
++ had_char_class = true;
++# endif /* libc || wctype.h */
++ }
++ else
++ {
++ c1++;
++ while (c1--)
++ PATUNFETCH;
++ SET_LIST_BIT ('[');
++ SET_LIST_BIT (':');
++ range_start = ':';
++ had_char_class = false;
++ }
++ }
++ else if (syntax & RE_CHAR_CLASSES && c == '[' && *p == '=')
++ {
++ unsigned char str[MB_LEN_MAX + 1];
++# ifdef _LIBC
++ uint32_t nrules =
++ _NL_CURRENT_WORD (LC_COLLATE, _NL_COLLATE_NRULES);
++# endif
++
++ PATFETCH (c);
++ c1 = 0;
++
++ /* If pattern is `[[='. */
++ if (p == pend) FREE_STACK_RETURN (REG_EBRACK);
++
++ for (;;)
++ {
++ PATFETCH (c);
++ if ((c == '=' && *p == ']') || p == pend)
++ break;
++ if (c1 < MB_LEN_MAX)
++ str[c1++] = c;
++ else
++ /* This is in any case an invalid class name. */
++ str[0] = '\0';
++ }
++ str[c1] = '\0';
++
++ if (c == '=' && *p == ']' && str[0] != '\0')
++ {
++ /* If we have no collation data we use the default
++ collation in which each character is in a class
++ by itself. It also means that ASCII is the
++ character set and therefore we cannot have character
++ with more than one byte in the multibyte
++ representation. */
++# ifdef _LIBC
++ if (nrules == 0)
++# endif
++ {
++ if (c1 != 1)
++ FREE_STACK_RETURN (REG_ECOLLATE);
++
++ /* Throw away the ] at the end of the equivalence
++ class. */
++ PATFETCH (c);
++
++ /* Set the bit for the character. */
++ SET_LIST_BIT (str[0]);
++ }
++# ifdef _LIBC
++ else
++ {
++ /* Try to match the byte sequence in `str' against
++ those known to the collate implementation.
++ First find out whether the bytes in `str' are
++ actually from exactly one character. */
++ const int32_t *table;
++ const unsigned char *weights;
++ const unsigned char *extra;
++ const int32_t *indirect;
++ int32_t idx;
++ const unsigned char *cp = str;
++ int ch;
++
++ /* This #include defines a local function! */
++# include <locale/weight.h>
++
++ table = (const int32_t *)
++ _NL_CURRENT (LC_COLLATE, _NL_COLLATE_TABLEMB);
++ weights = (const unsigned char *)
++ _NL_CURRENT (LC_COLLATE, _NL_COLLATE_WEIGHTMB);
++ extra = (const unsigned char *)
++ _NL_CURRENT (LC_COLLATE, _NL_COLLATE_EXTRAMB);
++ indirect = (const int32_t *)
++ _NL_CURRENT (LC_COLLATE, _NL_COLLATE_INDIRECTMB);
++
++ idx = findidx (&cp, c1);
++ if (idx == 0 || cp < str + c1)
++ /* This is no valid character. */
++ FREE_STACK_RETURN (REG_ECOLLATE);
++
++ /* Throw away the ] at the end of the equivalence
++ class. */
++ PATFETCH (c);
++
++ /* Now we have to go throught the whole table
++ and find all characters which have the same
++ first level weight.
++
++ XXX Note that this is not entirely correct.
++ we would have to match multibyte sequences
++ but this is not possible with the current
++ implementation. */
++ for (ch = 1; ch < 256; ++ch)
++ /* XXX This test would have to be changed if we
++ would allow matching multibyte sequences. */
++ if (table[ch] > 0)
++ {
++ int32_t idx2 = table[ch];
++ size_t len = weights[idx2];
++
++ /* Test whether the lenghts match. */
++ if (weights[idx] == len)
++ {
++ /* They do. New compare the bytes of
++ the weight. */
++ size_t cnt = 0;
++
++ while (cnt < len
++ && (weights[idx + 1 + cnt]
++ == weights[idx2 + 1 + cnt]))
++ ++cnt;
++
++ if (cnt == len)
++ /* They match. Mark the character as
++ acceptable. */
++ SET_LIST_BIT (ch);
++ }
++ }
++ }
++# endif
++ had_char_class = true;
++ }
++ else
++ {
++ c1++;
++ while (c1--)
++ PATUNFETCH;
++ SET_LIST_BIT ('[');
++ SET_LIST_BIT ('=');
++ range_start = '=';
++ had_char_class = false;
++ }
++ }
++ else if (syntax & RE_CHAR_CLASSES && c == '[' && *p == '.')
++ {
++ unsigned char str[128]; /* Should be large enough. */
++# ifdef _LIBC
++ uint32_t nrules =
++ _NL_CURRENT_WORD (LC_COLLATE, _NL_COLLATE_NRULES);
++# endif
++
++ PATFETCH (c);
++ c1 = 0;
++
++ /* If pattern is `[[.'. */
++ if (p == pend) FREE_STACK_RETURN (REG_EBRACK);
++
++ for (;;)
++ {
++ PATFETCH (c);
++ if ((c == '.' && *p == ']') || p == pend)
++ break;
++ if (c1 < sizeof (str))
++ str[c1++] = c;
++ else
++ /* This is in any case an invalid class name. */
++ str[0] = '\0';
++ }
++ str[c1] = '\0';
++
++ if (c == '.' && *p == ']' && str[0] != '\0')
++ {
++ /* If we have no collation data we use the default
++ collation in which each character is the name
++ for its own class which contains only the one
++ character. It also means that ASCII is the
++ character set and therefore we cannot have character
++ with more than one byte in the multibyte
++ representation. */
++# ifdef _LIBC
++ if (nrules == 0)
++# endif
++ {
++ if (c1 != 1)
++ FREE_STACK_RETURN (REG_ECOLLATE);
++
++ /* Throw away the ] at the end of the equivalence
++ class. */
++ PATFETCH (c);
++
++ /* Set the bit for the character. */
++ SET_LIST_BIT (str[0]);
++ range_start = ((const unsigned char *) str)[0];
++ }
++# ifdef _LIBC
++ else
++ {
++ /* Try to match the byte sequence in `str' against
++ those known to the collate implementation.
++ First find out whether the bytes in `str' are
++ actually from exactly one character. */
++ int32_t table_size;
++ const int32_t *symb_table;
++ const unsigned char *extra;
++ int32_t idx;
++ int32_t elem;
++ int32_t second;
++ int32_t hash;
++
++ table_size =
++ _NL_CURRENT_WORD (LC_COLLATE,
++ _NL_COLLATE_SYMB_HASH_SIZEMB);
++ symb_table = (const int32_t *)
++ _NL_CURRENT (LC_COLLATE,
++ _NL_COLLATE_SYMB_TABLEMB);
++ extra = (const unsigned char *)
++ _NL_CURRENT (LC_COLLATE,
++ _NL_COLLATE_SYMB_EXTRAMB);
++
++ /* Locate the character in the hashing table. */
++ hash = elem_hash ((const char *) str, c1);
++
++ idx = 0;
++ elem = hash % table_size;
++ second = hash % (table_size - 2);
++ while (symb_table[2 * elem] != 0)
++ {
++ /* First compare the hashing value. */
++ if (symb_table[2 * elem] == hash
++ && c1 == extra[symb_table[2 * elem + 1]]
++ && memcmp (str,
++ &extra[symb_table[2 * elem + 1]
++ + 1],
++ c1) == 0)
++ {
++ /* Yep, this is the entry. */
++ idx = symb_table[2 * elem + 1];
++ idx += 1 + extra[idx];
++ break;
++ }
++
++ /* Next entry. */
++ elem += second;
++ }
++
++ if (symb_table[2 * elem] == 0)
++ /* This is no valid character. */
++ FREE_STACK_RETURN (REG_ECOLLATE);
++
++ /* Throw away the ] at the end of the equivalence
++ class. */
++ PATFETCH (c);
++
++ /* Now add the multibyte character(s) we found
++ to the accept list.
++
++ XXX Note that this is not entirely correct.
++ we would have to match multibyte sequences
++ but this is not possible with the current
++ implementation. Also, we have to match
++ collating symbols, which expand to more than
++ one file, as a whole and not allow the
++ individual bytes. */
++ c1 = extra[idx++];
++ if (c1 == 1)
++ range_start = extra[idx];
++ while (c1-- > 0)
++ {
++ SET_LIST_BIT (extra[idx]);
++ ++idx;
++ }
++ }
++# endif
++ had_char_class = false;
++ }
++ else
++ {
++ c1++;
++ while (c1--)
++ PATUNFETCH;
++ SET_LIST_BIT ('[');
++ SET_LIST_BIT ('.');
++ range_start = '.';
++ had_char_class = false;
++ }
++ }
++ else
++ {
++ had_char_class = false;
++ SET_LIST_BIT (c);
++ range_start = c;
++ }
++ }
++
++ /* Discard any (non)matching list bytes that are all 0 at the
++ end of the map. Decrease the map-length byte too. */
++ while ((int) b[-1] > 0 && b[b[-1] - 1] == 0)
++ b[-1]--;
++ b += b[-1];
++#endif /* WCHAR */
++ }
++ break;
++
++
++ case '(':
++ if (syntax & RE_NO_BK_PARENS)
++ goto handle_open;
++ else
++ goto normal_char;
++
++
++ case ')':
++ if (syntax & RE_NO_BK_PARENS)
++ goto handle_close;
++ else
++ goto normal_char;
++
++
++ case '\n':
++ if (syntax & RE_NEWLINE_ALT)
++ goto handle_alt;
++ else
++ goto normal_char;
++
++
++ case '|':
++ if (syntax & RE_NO_BK_VBAR)
++ goto handle_alt;
++ else
++ goto normal_char;
++
++
++ case '{':
++ if (syntax & RE_INTERVALS && syntax & RE_NO_BK_BRACES)
++ goto handle_interval;
++ else
++ goto normal_char;
++
++
++ case '\\':
++ if (p == pend) FREE_STACK_RETURN (REG_EESCAPE);
++
++ /* Do not translate the character after the \, so that we can
++ distinguish, e.g., \B from \b, even if we normally would
++ translate, e.g., B to b. */
++ PATFETCH_RAW (c);
++
++ switch (c)
++ {
++ case '(':
++ if (syntax & RE_NO_BK_PARENS)
++ goto normal_backslash;
++
++ handle_open:
++ bufp->re_nsub++;
++ regnum++;
++
++ if (COMPILE_STACK_FULL)
++ {
++ RETALLOC (compile_stack.stack, compile_stack.size << 1,
++ compile_stack_elt_t);
++ if (compile_stack.stack == NULL) return REG_ESPACE;
++
++ compile_stack.size <<= 1;
++ }
++
++ /* These are the values to restore when we hit end of this
++ group. They are all relative offsets, so that if the
++ whole pattern moves because of realloc, they will still
++ be valid. */
++ COMPILE_STACK_TOP.begalt_offset = begalt - COMPILED_BUFFER_VAR;
++ COMPILE_STACK_TOP.fixup_alt_jump
++ = fixup_alt_jump ? fixup_alt_jump - COMPILED_BUFFER_VAR + 1 : 0;
++ COMPILE_STACK_TOP.laststart_offset = b - COMPILED_BUFFER_VAR;
++ COMPILE_STACK_TOP.regnum = regnum;
++
++ /* We will eventually replace the 0 with the number of
++ groups inner to this one. But do not push a
++ start_memory for groups beyond the last one we can
++ represent in the compiled pattern. */
++ if (regnum <= MAX_REGNUM)
++ {
++ COMPILE_STACK_TOP.inner_group_offset = b
++ - COMPILED_BUFFER_VAR + 2;
++ BUF_PUSH_3 (start_memory, regnum, 0);
++ }
++
++ compile_stack.avail++;
++
++ fixup_alt_jump = 0;
++ laststart = 0;
++ begalt = b;
++ /* If we've reached MAX_REGNUM groups, then this open
++ won't actually generate any code, so we'll have to
++ clear pending_exact explicitly. */
++ pending_exact = 0;
++ break;
++
++
++ case ')':
++ if (syntax & RE_NO_BK_PARENS) goto normal_backslash;
++
++ if (COMPILE_STACK_EMPTY)
++ {
++ if (syntax & RE_UNMATCHED_RIGHT_PAREN_ORD)
++ goto normal_backslash;
++ else
++ FREE_STACK_RETURN (REG_ERPAREN);
++ }
++
++ handle_close:
++ if (fixup_alt_jump)
++ { /* Push a dummy failure point at the end of the
++ alternative for a possible future
++ `pop_failure_jump' to pop. See comments at
++ `push_dummy_failure' in `re_match_2'. */
++ BUF_PUSH (push_dummy_failure);
++
++ /* We allocated space for this jump when we assigned
++ to `fixup_alt_jump', in the `handle_alt' case below. */
++ STORE_JUMP (jump_past_alt, fixup_alt_jump, b - 1);
++ }
++
++ /* See similar code for backslashed left paren above. */
++ if (COMPILE_STACK_EMPTY)
++ {
++ if (syntax & RE_UNMATCHED_RIGHT_PAREN_ORD)
++ goto normal_char;
++ else
++ FREE_STACK_RETURN (REG_ERPAREN);
++ }
++
++ /* Since we just checked for an empty stack above, this
++ ``can't happen''. */
++ assert (compile_stack.avail != 0);
++ {
++ /* We don't just want to restore into `regnum', because
++ later groups should continue to be numbered higher,
++ as in `(ab)c(de)' -- the second group is #2. */
++ regnum_t this_group_regnum;
++
++ compile_stack.avail--;
++ begalt = COMPILED_BUFFER_VAR + COMPILE_STACK_TOP.begalt_offset;
++ fixup_alt_jump
++ = COMPILE_STACK_TOP.fixup_alt_jump
++ ? COMPILED_BUFFER_VAR + COMPILE_STACK_TOP.fixup_alt_jump - 1
++ : 0;
++ laststart = COMPILED_BUFFER_VAR + COMPILE_STACK_TOP.laststart_offset;
++ this_group_regnum = COMPILE_STACK_TOP.regnum;
++ /* If we've reached MAX_REGNUM groups, then this open
++ won't actually generate any code, so we'll have to
++ clear pending_exact explicitly. */
++ pending_exact = 0;
++
++ /* We're at the end of the group, so now we know how many
++ groups were inside this one. */
++ if (this_group_regnum <= MAX_REGNUM)
++ {
++ UCHAR_T *inner_group_loc
++ = COMPILED_BUFFER_VAR + COMPILE_STACK_TOP.inner_group_offset;
++
++ *inner_group_loc = regnum - this_group_regnum;
++ BUF_PUSH_3 (stop_memory, this_group_regnum,
++ regnum - this_group_regnum);
++ }
++ }
++ break;
++
++
++ case '|': /* `\|'. */
++ if (syntax & RE_LIMITED_OPS || syntax & RE_NO_BK_VBAR)
++ goto normal_backslash;
++ handle_alt:
++ if (syntax & RE_LIMITED_OPS)
++ goto normal_char;
++
++ /* Insert before the previous alternative a jump which
++ jumps to this alternative if the former fails. */
++ GET_BUFFER_SPACE (1 + OFFSET_ADDRESS_SIZE);
++ INSERT_JUMP (on_failure_jump, begalt,
++ b + 2 + 2 * OFFSET_ADDRESS_SIZE);
++ pending_exact = 0;
++ b += 1 + OFFSET_ADDRESS_SIZE;
++
++ /* The alternative before this one has a jump after it
++ which gets executed if it gets matched. Adjust that
++ jump so it will jump to this alternative's analogous
++ jump (put in below, which in turn will jump to the next
++ (if any) alternative's such jump, etc.). The last such
++ jump jumps to the correct final destination. A picture:
++ _____ _____
++ | | | |
++ | v | v
++ a | b | c
++
++ If we are at `b', then fixup_alt_jump right now points to a
++ three-byte space after `a'. We'll put in the jump, set
++ fixup_alt_jump to right after `b', and leave behind three
++ bytes which we'll fill in when we get to after `c'. */
++
++ if (fixup_alt_jump)
++ STORE_JUMP (jump_past_alt, fixup_alt_jump, b);
++
++ /* Mark and leave space for a jump after this alternative,
++ to be filled in later either by next alternative or
++ when know we're at the end of a series of alternatives. */
++ fixup_alt_jump = b;
++ GET_BUFFER_SPACE (1 + OFFSET_ADDRESS_SIZE);
++ b += 1 + OFFSET_ADDRESS_SIZE;
++
++ laststart = 0;
++ begalt = b;
++ break;
++
++
++ case '{':
++ /* If \{ is a literal. */
++ if (!(syntax & RE_INTERVALS)
++ /* If we're at `\{' and it's not the open-interval
++ operator. */
++ || (syntax & RE_NO_BK_BRACES))
++ goto normal_backslash;
++
++ handle_interval:
++ {
++ /* If got here, then the syntax allows intervals. */
++
++ /* At least (most) this many matches must be made. */
++ int lower_bound = -1, upper_bound = -1;
++
++ /* Place in the uncompiled pattern (i.e., just after
++ the '{') to go back to if the interval is invalid. */
++ const CHAR_T *beg_interval = p;
++
++ if (p == pend)
++ goto invalid_interval;
++
++ GET_UNSIGNED_NUMBER (lower_bound);
++
++ if (c == ',')
++ {
++ GET_UNSIGNED_NUMBER (upper_bound);
++ if (upper_bound < 0)
++ upper_bound = RE_DUP_MAX;
++ }
++ else
++ /* Interval such as `{1}' => match exactly once. */
++ upper_bound = lower_bound;
++
++ if (! (0 <= lower_bound && lower_bound <= upper_bound))
++ goto invalid_interval;
++
++ if (!(syntax & RE_NO_BK_BRACES))
++ {
++ if (c != '\\' || p == pend)
++ goto invalid_interval;
++ PATFETCH (c);
++ }
++
++ if (c != '}')
++ goto invalid_interval;
++
++ /* If it's invalid to have no preceding re. */
++ if (!laststart)
++ {
++ if (syntax & RE_CONTEXT_INVALID_OPS
++ && !(syntax & RE_INVALID_INTERVAL_ORD))
++ FREE_STACK_RETURN (REG_BADRPT);
++ else if (syntax & RE_CONTEXT_INDEP_OPS)
++ laststart = b;
++ else
++ goto unfetch_interval;
++ }
++
++ /* We just parsed a valid interval. */
++
++ if (RE_DUP_MAX < upper_bound)
++ FREE_STACK_RETURN (REG_BADBR);
++
++ /* If the upper bound is zero, don't want to succeed at
++ all; jump from `laststart' to `b + 3', which will be
++ the end of the buffer after we insert the jump. */
++ /* ifdef WCHAR, 'b + 1 + OFFSET_ADDRESS_SIZE'
++ instead of 'b + 3'. */
++ if (upper_bound == 0)
++ {
++ GET_BUFFER_SPACE (1 + OFFSET_ADDRESS_SIZE);
++ INSERT_JUMP (jump, laststart, b + 1
++ + OFFSET_ADDRESS_SIZE);
++ b += 1 + OFFSET_ADDRESS_SIZE;
++ }
++
++ /* Otherwise, we have a nontrivial interval. When
++ we're all done, the pattern will look like:
++ set_number_at <jump count> <upper bound>
++ set_number_at <succeed_n count> <lower bound>
++ succeed_n <after jump addr> <succeed_n count>
++ <body of loop>
++ jump_n <succeed_n addr> <jump count>
++ (The upper bound and `jump_n' are omitted if
++ `upper_bound' is 1, though.) */
++ else
++ { /* If the upper bound is > 1, we need to insert
++ more at the end of the loop. */
++ unsigned nbytes = 2 + 4 * OFFSET_ADDRESS_SIZE +
++ (upper_bound > 1) * (2 + 4 * OFFSET_ADDRESS_SIZE);
++
++ GET_BUFFER_SPACE (nbytes);
++
++ /* Initialize lower bound of the `succeed_n', even
++ though it will be set during matching by its
++ attendant `set_number_at' (inserted next),
++ because `re_compile_fastmap' needs to know.
++ Jump to the `jump_n' we might insert below. */
++ INSERT_JUMP2 (succeed_n, laststart,
++ b + 1 + 2 * OFFSET_ADDRESS_SIZE
++ + (upper_bound > 1) * (1 + 2 * OFFSET_ADDRESS_SIZE)
++ , lower_bound);
++ b += 1 + 2 * OFFSET_ADDRESS_SIZE;
++
++ /* Code to initialize the lower bound. Insert
++ before the `succeed_n'. The `5' is the last two
++ bytes of this `set_number_at', plus 3 bytes of
++ the following `succeed_n'. */
++ /* ifdef WCHAR, The '1+2*OFFSET_ADDRESS_SIZE'
++ is the 'set_number_at', plus '1+OFFSET_ADDRESS_SIZE'
++ of the following `succeed_n'. */
++ PREFIX(insert_op2) (set_number_at, laststart, 1
++ + 2 * OFFSET_ADDRESS_SIZE, lower_bound, b);
++ b += 1 + 2 * OFFSET_ADDRESS_SIZE;
++
++ if (upper_bound > 1)
++ { /* More than one repetition is allowed, so
++ append a backward jump to the `succeed_n'
++ that starts this interval.
++
++ When we've reached this during matching,
++ we'll have matched the interval once, so
++ jump back only `upper_bound - 1' times. */
++ STORE_JUMP2 (jump_n, b, laststart
++ + 2 * OFFSET_ADDRESS_SIZE + 1,
++ upper_bound - 1);
++ b += 1 + 2 * OFFSET_ADDRESS_SIZE;
++
++ /* The location we want to set is the second
++ parameter of the `jump_n'; that is `b-2' as
++ an absolute address. `laststart' will be
++ the `set_number_at' we're about to insert;
++ `laststart+3' the number to set, the source
++ for the relative address. But we are
++ inserting into the middle of the pattern --
++ so everything is getting moved up by 5.
++ Conclusion: (b - 2) - (laststart + 3) + 5,
++ i.e., b - laststart.
++
++ We insert this at the beginning of the loop
++ so that if we fail during matching, we'll
++ reinitialize the bounds. */
++ PREFIX(insert_op2) (set_number_at, laststart,
++ b - laststart,
++ upper_bound - 1, b);
++ b += 1 + 2 * OFFSET_ADDRESS_SIZE;
++ }
++ }
++ pending_exact = 0;
++ break;
++
++ invalid_interval:
++ if (!(syntax & RE_INVALID_INTERVAL_ORD))
++ FREE_STACK_RETURN (p == pend ? REG_EBRACE : REG_BADBR);
++ unfetch_interval:
++ /* Match the characters as literals. */
++ p = beg_interval;
++ c = '{';
++ if (syntax & RE_NO_BK_BRACES)
++ goto normal_char;
++ else
++ goto normal_backslash;
++ }
++
++#ifdef emacs
++ /* There is no way to specify the before_dot and after_dot
++ operators. rms says this is ok. --karl */
++ case '=':
++ BUF_PUSH (at_dot);
++ break;
++
++ case 's':
++ laststart = b;
++ PATFETCH (c);
++ BUF_PUSH_2 (syntaxspec, syntax_spec_code[c]);
++ break;
++
++ case 'S':
++ laststart = b;
++ PATFETCH (c);
++ BUF_PUSH_2 (notsyntaxspec, syntax_spec_code[c]);
++ break;
++#endif /* emacs */
++
++
++ case 'w':
++ if (syntax & RE_NO_GNU_OPS)
++ goto normal_char;
++ laststart = b;
++ BUF_PUSH (wordchar);
++ break;
++
++
++ case 'W':
++ if (syntax & RE_NO_GNU_OPS)
++ goto normal_char;
++ laststart = b;
++ BUF_PUSH (notwordchar);
++ break;
++
++
++ case '<':
++ if (syntax & RE_NO_GNU_OPS)
++ goto normal_char;
++ BUF_PUSH (wordbeg);
++ break;
++
++ case '>':
++ if (syntax & RE_NO_GNU_OPS)
++ goto normal_char;
++ BUF_PUSH (wordend);
++ break;
++
++ case 'b':
++ if (syntax & RE_NO_GNU_OPS)
++ goto normal_char;
++ BUF_PUSH (wordbound);
++ break;
++
++ case 'B':
++ if (syntax & RE_NO_GNU_OPS)
++ goto normal_char;
++ BUF_PUSH (notwordbound);
++ break;
++
++ case '`':
++ if (syntax & RE_NO_GNU_OPS)
++ goto normal_char;
++ BUF_PUSH (begbuf);
++ break;
++
++ case '\'':
++ if (syntax & RE_NO_GNU_OPS)
++ goto normal_char;
++ BUF_PUSH (endbuf);
++ break;
++
++ case '1': case '2': case '3': case '4': case '5':
++ case '6': case '7': case '8': case '9':
++ if (syntax & RE_NO_BK_REFS)
++ goto normal_char;
++
++ c1 = c - '0';
++
++ if (c1 > regnum)
++ FREE_STACK_RETURN (REG_ESUBREG);
++
++ /* Can't back reference to a subexpression if inside of it. */
++ if (group_in_compile_stack (compile_stack, (regnum_t) c1))
++ goto normal_char;
++
++ laststart = b;
++ BUF_PUSH_2 (duplicate, c1);
++ break;
++
++
++ case '+':
++ case '?':
++ if (syntax & RE_BK_PLUS_QM)
++ goto handle_plus;
++ else
++ goto normal_backslash;
++
++ default:
++ normal_backslash:
++ /* You might think it would be useful for \ to mean
++ not to translate; but if we don't translate it
++ it will never match anything. */
++ c = TRANSLATE (c);
++ goto normal_char;
++ }
++ break;
++
++
++ default:
++ /* Expects the character in `c'. */
++ normal_char:
++ /* If no exactn currently being built. */
++ if (!pending_exact
++#ifdef WCHAR
++ /* If last exactn handle binary(or character) and
++ new exactn handle character(or binary). */
++ || is_exactn_bin != is_binary[p - 1 - pattern]
++#endif /* WCHAR */
++
++ /* If last exactn not at current position. */
++ || pending_exact + *pending_exact + 1 != b
++
++ /* We have only one byte following the exactn for the count. */
++ || *pending_exact == (1 << BYTEWIDTH) - 1
++
++ /* If followed by a repetition operator. */
++ || *p == '*' || *p == '^'
++ || ((syntax & RE_BK_PLUS_QM)
++ ? *p == '\\' && (p[1] == '+' || p[1] == '?')
++ : (*p == '+' || *p == '?'))
++ || ((syntax & RE_INTERVALS)
++ && ((syntax & RE_NO_BK_BRACES)
++ ? *p == '{'
++ : (p[0] == '\\' && p[1] == '{'))))
++ {
++ /* Start building a new exactn. */
++
++ laststart = b;
++
++#ifdef WCHAR
++ /* Is this exactn binary data or character? */
++ is_exactn_bin = is_binary[p - 1 - pattern];
++ if (is_exactn_bin)
++ BUF_PUSH_2 (exactn_bin, 0);
++ else
++ BUF_PUSH_2 (exactn, 0);
++#else
++ BUF_PUSH_2 (exactn, 0);
++#endif /* WCHAR */
++ pending_exact = b - 1;
++ }
++
++ BUF_PUSH (c);
++ (*pending_exact)++;
++ break;
++ } /* switch (c) */
++ } /* while p != pend */
++
++
++ /* Through the pattern now. */
++
++ if (fixup_alt_jump)
++ STORE_JUMP (jump_past_alt, fixup_alt_jump, b);
++
++ if (!COMPILE_STACK_EMPTY)
++ FREE_STACK_RETURN (REG_EPAREN);
++
++ /* If we don't want backtracking, force success
++ the first time we reach the end of the compiled pattern. */
++ if (syntax & RE_NO_POSIX_BACKTRACKING)
++ BUF_PUSH (succeed);
++
++#ifdef WCHAR
++ free (pattern);
++ free (mbs_offset);
++ free (is_binary);
++#endif
++ free (compile_stack.stack);
++
++ /* We have succeeded; set the length of the buffer. */
++#ifdef WCHAR
++ bufp->used = (uintptr_t) b - (uintptr_t) COMPILED_BUFFER_VAR;
++#else
++ bufp->used = b - bufp->buffer;
++#endif
++
++#ifdef DEBUG
++ if (debug)
++ {
++ DEBUG_PRINT1 ("\nCompiled pattern: \n");
++ PREFIX(print_compiled_pattern) (bufp);
++ }
++#endif /* DEBUG */
++
++#ifndef MATCH_MAY_ALLOCATE
++ /* Initialize the failure stack to the largest possible stack. This
++ isn't necessary unless we're trying to avoid calling alloca in
++ the search and match routines. */
++ {
++ int num_regs = bufp->re_nsub + 1;
++
++ /* Since DOUBLE_FAIL_STACK refuses to double only if the current size
++ is strictly greater than re_max_failures, the largest possible stack
++ is 2 * re_max_failures failure points. */
++ if (fail_stack.size < (2 * re_max_failures * MAX_FAILURE_ITEMS))
++ {
++ fail_stack.size = (2 * re_max_failures * MAX_FAILURE_ITEMS);
++
++# ifdef emacs
++ if (! fail_stack.stack)
++ fail_stack.stack
++ = (PREFIX(fail_stack_elt_t) *) xmalloc (fail_stack.size
++ * sizeof (PREFIX(fail_stack_elt_t)));
++ else
++ fail_stack.stack
++ = (PREFIX(fail_stack_elt_t) *) xrealloc (fail_stack.stack,
++ (fail_stack.size
++ * sizeof (PREFIX(fail_stack_elt_t))));
++# else /* not emacs */
++ if (! fail_stack.stack)
++ fail_stack.stack
++ = (PREFIX(fail_stack_elt_t) *) malloc (fail_stack.size
++ * sizeof (PREFIX(fail_stack_elt_t)));
++ else
++ fail_stack.stack
++ = (PREFIX(fail_stack_elt_t) *) realloc (fail_stack.stack,
++ (fail_stack.size
++ * sizeof (PREFIX(fail_stack_elt_t))));
++# endif /* not emacs */
++ }
++
++ PREFIX(regex_grow_registers) (num_regs);
++ }
++#endif /* not MATCH_MAY_ALLOCATE */
++
++ return REG_NOERROR;
++} /* regex_compile */
++
++/* Subroutines for `regex_compile'. */
++
++/* Store OP at LOC followed by two-byte integer parameter ARG. */
++/* ifdef WCHAR, integer parameter is 1 wchar_t. */
++
++static void
++PREFIX(store_op1) (re_opcode_t op, UCHAR_T *loc, int arg)
++{
++ *loc = (UCHAR_T) op;
++ STORE_NUMBER (loc + 1, arg);
++}
++
++
++/* Like `store_op1', but for two two-byte parameters ARG1 and ARG2. */
++/* ifdef WCHAR, integer parameter is 1 wchar_t. */
++
++static void
++PREFIX(store_op2) (re_opcode_t op, UCHAR_T *loc, int arg1, int arg2)
++{
++ *loc = (UCHAR_T) op;
++ STORE_NUMBER (loc + 1, arg1);
++ STORE_NUMBER (loc + 1 + OFFSET_ADDRESS_SIZE, arg2);
++}
++
++
++/* Copy the bytes from LOC to END to open up three bytes of space at LOC
++ for OP followed by two-byte integer parameter ARG. */
++/* ifdef WCHAR, integer parameter is 1 wchar_t. */
++
++static void
++PREFIX(insert_op1) (re_opcode_t op, UCHAR_T *loc, int arg, UCHAR_T *end)
++{
++ register UCHAR_T *pfrom = end;
++ register UCHAR_T *pto = end + 1 + OFFSET_ADDRESS_SIZE;
++
++ while (pfrom != loc)
++ *--pto = *--pfrom;
++
++ PREFIX(store_op1) (op, loc, arg);
++}
++
++
++/* Like `insert_op1', but for two two-byte parameters ARG1 and ARG2. */
++/* ifdef WCHAR, integer parameter is 1 wchar_t. */
++
++static void
++PREFIX(insert_op2) (re_opcode_t op, UCHAR_T *loc, int arg1,
++ int arg2, UCHAR_T *end)
++{
++ register UCHAR_T *pfrom = end;
++ register UCHAR_T *pto = end + 1 + 2 * OFFSET_ADDRESS_SIZE;
++
++ while (pfrom != loc)
++ *--pto = *--pfrom;
++
++ PREFIX(store_op2) (op, loc, arg1, arg2);
++}
++
++
++/* P points to just after a ^ in PATTERN. Return true if that ^ comes
++ after an alternative or a begin-subexpression. We assume there is at
++ least one character before the ^. */
++
++static boolean
++PREFIX(at_begline_loc_p) (const CHAR_T *pattern, const CHAR_T *p,
++ reg_syntax_t syntax)
++{
++ const CHAR_T *prev = p - 2;
++ boolean prev_prev_backslash = prev > pattern && prev[-1] == '\\';
++
++ return
++ /* After a subexpression? */
++ (*prev == '(' && (syntax & RE_NO_BK_PARENS || prev_prev_backslash))
++ /* After an alternative? */
++ || (*prev == '|' && (syntax & RE_NO_BK_VBAR || prev_prev_backslash));
++}
++
++
++/* The dual of at_begline_loc_p. This one is for $. We assume there is
++ at least one character after the $, i.e., `P < PEND'. */
++
++static boolean
++PREFIX(at_endline_loc_p) (const CHAR_T *p, const CHAR_T *pend,
++ reg_syntax_t syntax)
++{
++ const CHAR_T *next = p;
++ boolean next_backslash = *next == '\\';
++ const CHAR_T *next_next = p + 1 < pend ? p + 1 : 0;
++
++ return
++ /* Before a subexpression? */
++ (syntax & RE_NO_BK_PARENS ? *next == ')'
++ : next_backslash && next_next && *next_next == ')')
++ /* Before an alternative? */
++ || (syntax & RE_NO_BK_VBAR ? *next == '|'
++ : next_backslash && next_next && *next_next == '|');
++}
++
++#else /* not INSIDE_RECURSION */
++
++/* Returns true if REGNUM is in one of COMPILE_STACK's elements and
++ false if it's not. */
++
++static boolean
++group_in_compile_stack (compile_stack_type compile_stack, regnum_t regnum)
++{
++ int this_element;
++
++ for (this_element = compile_stack.avail - 1;
++ this_element >= 0;
++ this_element--)
++ if (compile_stack.stack[this_element].regnum == regnum)
++ return true;
++
++ return false;
++}
++#endif /* not INSIDE_RECURSION */
++
++#ifdef INSIDE_RECURSION
++
++#ifdef WCHAR
++/* This insert space, which size is "num", into the pattern at "loc".
++ "end" must point the end of the allocated buffer. */
++static void
++insert_space (int num, CHAR_T *loc, CHAR_T *end)
++{
++ register CHAR_T *pto = end;
++ register CHAR_T *pfrom = end - num;
++
++ while (pfrom >= loc)
++ *pto-- = *pfrom--;
++}
++#endif /* WCHAR */
++
++#ifdef WCHAR
++static reg_errcode_t
++wcs_compile_range (CHAR_T range_start_char, const CHAR_T **p_ptr,
++ const CHAR_T *pend, RE_TRANSLATE_TYPE translate,
++ reg_syntax_t syntax, CHAR_T *b, CHAR_T *char_set)
++{
++ const CHAR_T *p = *p_ptr;
++ CHAR_T range_start, range_end;
++ reg_errcode_t ret;
++# ifdef _LIBC
++ uint32_t nrules;
++ uint32_t start_val, end_val;
++# endif
++ if (p == pend)
++ return REG_ERANGE;
++
++# ifdef _LIBC
++ nrules = _NL_CURRENT_WORD (LC_COLLATE, _NL_COLLATE_NRULES);
++ if (nrules != 0)
++ {
++ const char *collseq = (const char *) _NL_CURRENT(LC_COLLATE,
++ _NL_COLLATE_COLLSEQWC);
++ const unsigned char *extra = (const unsigned char *)
++ _NL_CURRENT (LC_COLLATE, _NL_COLLATE_SYMB_EXTRAMB);
++
++ if (range_start_char < -1)
++ {
++ /* range_start is a collating symbol. */
++ int32_t *wextra;
++ /* Retreive the index and get collation sequence value. */
++ wextra = (int32_t*)(extra + char_set[-range_start_char]);
++ start_val = wextra[1 + *wextra];
++ }
++ else
++ start_val = collseq_table_lookup(collseq, TRANSLATE(range_start_char));
++
++ end_val = collseq_table_lookup (collseq, TRANSLATE (p[0]));
++
++ /* Report an error if the range is empty and the syntax prohibits
++ this. */
++ ret = ((syntax & RE_NO_EMPTY_RANGES)
++ && (start_val > end_val))? REG_ERANGE : REG_NOERROR;
++
++ /* Insert space to the end of the char_ranges. */
++ insert_space(2, b - char_set[5] - 2, b - 1);
++ *(b - char_set[5] - 2) = (wchar_t)start_val;
++ *(b - char_set[5] - 1) = (wchar_t)end_val;
++ char_set[4]++; /* ranges_index */
++ }
++ else
++# endif
++ {
++ range_start = (range_start_char >= 0)? TRANSLATE (range_start_char):
++ range_start_char;
++ range_end = TRANSLATE (p[0]);
++ /* Report an error if the range is empty and the syntax prohibits
++ this. */
++ ret = ((syntax & RE_NO_EMPTY_RANGES)
++ && (range_start > range_end))? REG_ERANGE : REG_NOERROR;
++
++ /* Insert space to the end of the char_ranges. */
++ insert_space(2, b - char_set[5] - 2, b - 1);
++ *(b - char_set[5] - 2) = range_start;
++ *(b - char_set[5] - 1) = range_end;
++ char_set[4]++; /* ranges_index */
++ }
++ /* Have to increment the pointer into the pattern string, so the
++ caller isn't still at the ending character. */
++ (*p_ptr)++;
++
++ return ret;
++}
++#else /* BYTE */
++/* Read the ending character of a range (in a bracket expression) from the
++ uncompiled pattern *P_PTR (which ends at PEND). We assume the
++ starting character is in `P[-2]'. (`P[-1]' is the character `-'.)
++ Then we set the translation of all bits between the starting and
++ ending characters (inclusive) in the compiled pattern B.
++
++ Return an error code.
++
++ We use these short variable names so we can use the same macros as
++ `regex_compile' itself. */
++
++static reg_errcode_t
++byte_compile_range (unsigned int range_start_char, const char **p_ptr,
++ const char *pend, RE_TRANSLATE_TYPE translate,
++ reg_syntax_t syntax, unsigned char *b)
++{
++ unsigned this_char;
++ const char *p = *p_ptr;
++ reg_errcode_t ret;
++# if _LIBC
++ const unsigned char *collseq;
++ unsigned int start_colseq;
++ unsigned int end_colseq;
++# else
++ unsigned end_char;
++# endif
++
++ if (p == pend)
++ return REG_ERANGE;
++
++ /* Have to increment the pointer into the pattern string, so the
++ caller isn't still at the ending character. */
++ (*p_ptr)++;
++
++ /* Report an error if the range is empty and the syntax prohibits this. */
++ ret = syntax & RE_NO_EMPTY_RANGES ? REG_ERANGE : REG_NOERROR;
++
++# if _LIBC
++ collseq = (const unsigned char *) _NL_CURRENT (LC_COLLATE,
++ _NL_COLLATE_COLLSEQMB);
++
++ start_colseq = collseq[(unsigned char) TRANSLATE (range_start_char)];
++ end_colseq = collseq[(unsigned char) TRANSLATE (p[0])];
++ for (this_char = 0; this_char <= (unsigned char) -1; ++this_char)
++ {
++ unsigned int this_colseq = collseq[(unsigned char) TRANSLATE (this_char)];
++
++ if (start_colseq <= this_colseq && this_colseq <= end_colseq)
++ {
++ SET_LIST_BIT (TRANSLATE (this_char));
++ ret = REG_NOERROR;
++ }
++ }
++# else
++ /* Here we see why `this_char' has to be larger than an `unsigned
++ char' -- we would otherwise go into an infinite loop, since all
++ characters <= 0xff. */
++ range_start_char = TRANSLATE (range_start_char);
++ /* TRANSLATE(p[0]) is casted to char (not unsigned char) in TRANSLATE,
++ and some compilers cast it to int implicitly, so following for_loop
++ may fall to (almost) infinite loop.
++ e.g. If translate[p[0]] = 0xff, end_char may equals to 0xffffffff.
++ To avoid this, we cast p[0] to unsigned int and truncate it. */
++ end_char = ((unsigned)TRANSLATE(p[0]) & ((1 << BYTEWIDTH) - 1));
++
++ for (this_char = range_start_char; this_char <= end_char; ++this_char)
++ {
++ SET_LIST_BIT (TRANSLATE (this_char));
++ ret = REG_NOERROR;
++ }
++# endif
++
++ return ret;
++}
++#endif /* WCHAR */
++
++/* re_compile_fastmap computes a ``fastmap'' for the compiled pattern in
++ BUFP. A fastmap records which of the (1 << BYTEWIDTH) possible
++ characters can start a string that matches the pattern. This fastmap
++ is used by re_search to skip quickly over impossible starting points.
++
++ The caller must supply the address of a (1 << BYTEWIDTH)-byte data
++ area as BUFP->fastmap.
++
++ We set the `fastmap', `fastmap_accurate', and `can_be_null' fields in
++ the pattern buffer.
++
++ Returns 0 if we succeed, -2 if an internal error. */
++
++#ifdef WCHAR
++/* local function for re_compile_fastmap.
++ truncate wchar_t character to char. */
++static unsigned char truncate_wchar (CHAR_T c);
++
++static unsigned char
++truncate_wchar (CHAR_T c)
++{
++ unsigned char buf[MB_CUR_MAX];
++ mbstate_t state;
++ int retval;
++ memset (&state, '\0', sizeof (state));
++# ifdef _LIBC
++ retval = __wcrtomb (buf, c, &state);
++# else
++ retval = wcrtomb (buf, c, &state);
++# endif
++ return retval > 0 ? buf[0] : (unsigned char) c;
++}
++#endif /* WCHAR */
++
++static int
++PREFIX(re_compile_fastmap) (struct re_pattern_buffer *bufp)
++{
++ int j, k;
++#ifdef MATCH_MAY_ALLOCATE
++ PREFIX(fail_stack_type) fail_stack;
++#endif
++#ifndef REGEX_MALLOC
++ char *destination;
++#endif
++
++ register char *fastmap = bufp->fastmap;
++
++#ifdef WCHAR
++ /* We need to cast pattern to (wchar_t*), because we casted this compiled
++ pattern to (char*) in regex_compile. */
++ UCHAR_T *pattern = (UCHAR_T*)bufp->buffer;
++ register UCHAR_T *pend = (UCHAR_T*) (bufp->buffer + bufp->used);
++#else /* BYTE */
++ UCHAR_T *pattern = bufp->buffer;
++ register UCHAR_T *pend = pattern + bufp->used;
++#endif /* WCHAR */
++ UCHAR_T *p = pattern;
++
++#ifdef REL_ALLOC
++ /* This holds the pointer to the failure stack, when
++ it is allocated relocatably. */
++ fail_stack_elt_t *failure_stack_ptr;
++#endif
++
++ /* Assume that each path through the pattern can be null until
++ proven otherwise. We set this false at the bottom of switch
++ statement, to which we get only if a particular path doesn't
++ match the empty string. */
++ boolean path_can_be_null = true;
++
++ /* We aren't doing a `succeed_n' to begin with. */
++ boolean succeed_n_p = false;
++
++ assert (fastmap != NULL && p != NULL);
++
++ INIT_FAIL_STACK ();
++ bzero (fastmap, 1 << BYTEWIDTH); /* Assume nothing's valid. */
++ bufp->fastmap_accurate = 1; /* It will be when we're done. */
++ bufp->can_be_null = 0;
++
++ while (1)
++ {
++ if (p == pend || *p == (UCHAR_T) succeed)
++ {
++ /* We have reached the (effective) end of pattern. */
++ if (!FAIL_STACK_EMPTY ())
++ {
++ bufp->can_be_null |= path_can_be_null;
++
++ /* Reset for next path. */
++ path_can_be_null = true;
++
++ p = fail_stack.stack[--fail_stack.avail].pointer;
++
++ continue;
++ }
++ else
++ break;
++ }
++
++ /* We should never be about to go beyond the end of the pattern. */
++ assert (p < pend);
++
++ switch (SWITCH_ENUM_CAST ((re_opcode_t) *p++))
++ {
++
++ /* I guess the idea here is to simply not bother with a fastmap
++ if a backreference is used, since it's too hard to figure out
++ the fastmap for the corresponding group. Setting
++ `can_be_null' stops `re_search_2' from using the fastmap, so
++ that is all we do. */
++ case duplicate:
++ bufp->can_be_null = 1;
++ goto done;
++
++
++ /* Following are the cases which match a character. These end
++ with `break'. */
++
++#ifdef WCHAR
++ case exactn:
++ fastmap[truncate_wchar(p[1])] = 1;
++ break;
++#else /* BYTE */
++ case exactn:
++ fastmap[p[1]] = 1;
++ break;
++#endif /* WCHAR */
++#ifdef MBS_SUPPORT
++ case exactn_bin:
++ fastmap[p[1]] = 1;
++ break;
++#endif
++
++#ifdef WCHAR
++ /* It is hard to distinguish fastmap from (multi byte) characters
++ which depends on current locale. */
++ case charset:
++ case charset_not:
++ case wordchar:
++ case notwordchar:
++ bufp->can_be_null = 1;
++ goto done;
++#else /* BYTE */
++ case charset:
++ for (j = *p++ * BYTEWIDTH - 1; j >= 0; j--)
++ if (p[j / BYTEWIDTH] & (1 << (j % BYTEWIDTH)))
++ fastmap[j] = 1;
++ break;
++
++
++ case charset_not:
++ /* Chars beyond end of map must be allowed. */
++ for (j = *p * BYTEWIDTH; j < (1 << BYTEWIDTH); j++)
++ fastmap[j] = 1;
++
++ for (j = *p++ * BYTEWIDTH - 1; j >= 0; j--)
++ if (!(p[j / BYTEWIDTH] & (1 << (j % BYTEWIDTH))))
++ fastmap[j] = 1;
++ break;
++
++
++ case wordchar:
++ for (j = 0; j < (1 << BYTEWIDTH); j++)
++ if (SYNTAX (j) == Sword)
++ fastmap[j] = 1;
++ break;
++
++
++ case notwordchar:
++ for (j = 0; j < (1 << BYTEWIDTH); j++)
++ if (SYNTAX (j) != Sword)
++ fastmap[j] = 1;
++ break;
++#endif /* WCHAR */
++
++ case anychar:
++ {
++ int fastmap_newline = fastmap['\n'];
++
++ /* `.' matches anything ... */
++ for (j = 0; j < (1 << BYTEWIDTH); j++)
++ fastmap[j] = 1;
++
++ /* ... except perhaps newline. */
++ if (!(bufp->syntax & RE_DOT_NEWLINE))
++ fastmap['\n'] = fastmap_newline;
++
++ /* Return if we have already set `can_be_null'; if we have,
++ then the fastmap is irrelevant. Something's wrong here. */
++ else if (bufp->can_be_null)
++ goto done;
++
++ /* Otherwise, have to check alternative paths. */
++ break;
++ }
++
++#ifdef emacs
++ case syntaxspec:
++ k = *p++;
++ for (j = 0; j < (1 << BYTEWIDTH); j++)
++ if (SYNTAX (j) == (enum syntaxcode) k)
++ fastmap[j] = 1;
++ break;
++
++
++ case notsyntaxspec:
++ k = *p++;
++ for (j = 0; j < (1 << BYTEWIDTH); j++)
++ if (SYNTAX (j) != (enum syntaxcode) k)
++ fastmap[j] = 1;
++ break;
++
++
++ /* All cases after this match the empty string. These end with
++ `continue'. */
++
++
++ case before_dot:
++ case at_dot:
++ case after_dot:
++ continue;
++#endif /* emacs */
++
++
++ case no_op:
++ case begline:
++ case endline:
++ case begbuf:
++ case endbuf:
++ case wordbound:
++ case notwordbound:
++ case wordbeg:
++ case wordend:
++ case push_dummy_failure:
++ continue;
++
++
++ case jump_n:
++ case pop_failure_jump:
++ case maybe_pop_jump:
++ case jump:
++ case jump_past_alt:
++ case dummy_failure_jump:
++ EXTRACT_NUMBER_AND_INCR (j, p);
++ p += j;
++ if (j > 0)
++ continue;
++
++ /* Jump backward implies we just went through the body of a
++ loop and matched nothing. Opcode jumped to should be
++ `on_failure_jump' or `succeed_n'. Just treat it like an
++ ordinary jump. For a * loop, it has pushed its failure
++ point already; if so, discard that as redundant. */
++ if ((re_opcode_t) *p != on_failure_jump
++ && (re_opcode_t) *p != succeed_n)
++ continue;
++
++ p++;
++ EXTRACT_NUMBER_AND_INCR (j, p);
++ p += j;
++
++ /* If what's on the stack is where we are now, pop it. */
++ if (!FAIL_STACK_EMPTY ()
++ && fail_stack.stack[fail_stack.avail - 1].pointer == p)
++ fail_stack.avail--;
++
++ continue;
++
++
++ case on_failure_jump:
++ case on_failure_keep_string_jump:
++ handle_on_failure_jump:
++ EXTRACT_NUMBER_AND_INCR (j, p);
++
++ /* For some patterns, e.g., `(a?)?', `p+j' here points to the
++ end of the pattern. We don't want to push such a point,
++ since when we restore it above, entering the switch will
++ increment `p' past the end of the pattern. We don't need
++ to push such a point since we obviously won't find any more
++ fastmap entries beyond `pend'. Such a pattern can match
++ the null string, though. */
++ if (p + j < pend)
++ {
++ if (!PUSH_PATTERN_OP (p + j, fail_stack))
++ {
++ RESET_FAIL_STACK ();
++ return -2;
++ }
++ }
++ else
++ bufp->can_be_null = 1;
++
++ if (succeed_n_p)
++ {
++ EXTRACT_NUMBER_AND_INCR (k, p); /* Skip the n. */
++ succeed_n_p = false;
++ }
++
++ continue;
++
++
++ case succeed_n:
++ /* Get to the number of times to succeed. */
++ p += OFFSET_ADDRESS_SIZE;
++
++ /* Increment p past the n for when k != 0. */
++ EXTRACT_NUMBER_AND_INCR (k, p);
++ if (k == 0)
++ {
++ p -= 2 * OFFSET_ADDRESS_SIZE;
++ succeed_n_p = true; /* Spaghetti code alert. */
++ goto handle_on_failure_jump;
++ }
++ continue;
++
++
++ case set_number_at:
++ p += 2 * OFFSET_ADDRESS_SIZE;
++ continue;
++
++
++ case start_memory:
++ case stop_memory:
++ p += 2;
++ continue;
++
++
++ default:
++ abort (); /* We have listed all the cases. */
++ } /* switch *p++ */
++
++ /* Getting here means we have found the possible starting
++ characters for one path of the pattern -- and that the empty
++ string does not match. We need not follow this path further.
++ Instead, look at the next alternative (remembered on the
++ stack), or quit if no more. The test at the top of the loop
++ does these things. */
++ path_can_be_null = false;
++ p = pend;
++ } /* while p */
++
++ /* Set `can_be_null' for the last path (also the first path, if the
++ pattern is empty). */
++ bufp->can_be_null |= path_can_be_null;
++
++ done:
++ RESET_FAIL_STACK ();
++ return 0;
++}
++
++#else /* not INSIDE_RECURSION */
++
++int
++re_compile_fastmap (struct re_pattern_buffer *bufp)
++{
++# ifdef MBS_SUPPORT
++ if (MB_CUR_MAX != 1)
++ return wcs_re_compile_fastmap(bufp);
++ else
++# endif
++ return byte_re_compile_fastmap(bufp);
++} /* re_compile_fastmap */
++#ifdef _LIBC
++weak_alias (__re_compile_fastmap, re_compile_fastmap)
++#endif
++
++
++/* Set REGS to hold NUM_REGS registers, storing them in STARTS and
++ ENDS. Subsequent matches using PATTERN_BUFFER and REGS will use
++ this memory for recording register information. STARTS and ENDS
++ must be allocated using the malloc library routine, and must each
++ be at least NUM_REGS * sizeof (regoff_t) bytes long.
++
++ If NUM_REGS == 0, then subsequent matches should allocate their own
++ register data.
++
++ Unless this function is called, the first search or match using
++ PATTERN_BUFFER will allocate its own register data, without
++ freeing the old data. */
++
++void
++re_set_registers (struct re_pattern_buffer *bufp,
++ struct re_registers *regs, unsigned num_regs,
++ regoff_t *starts, regoff_t *ends)
++{
++ if (num_regs)
++ {
++ bufp->regs_allocated = REGS_REALLOCATE;
++ regs->num_regs = num_regs;
++ regs->start = starts;
++ regs->end = ends;
++ }
++ else
++ {
++ bufp->regs_allocated = REGS_UNALLOCATED;
++ regs->num_regs = 0;
++ regs->start = regs->end = (regoff_t *) 0;
++ }
++}
++#ifdef _LIBC
++weak_alias (__re_set_registers, re_set_registers)
++#endif
++
++/* Searching routines. */
++
++/* Like re_search_2, below, but only one string is specified, and
++ doesn't let you say where to stop matching. */
++
++int
++re_search (struct re_pattern_buffer *bufp, const char *string, int size,
++ int startpos, int range, struct re_registers *regs)
++{
++ return re_search_2 (bufp, NULL, 0, string, size, startpos, range,
++ regs, size);
++}
++#ifdef _LIBC
++weak_alias (__re_search, re_search)
++#endif
++
++
++/* Using the compiled pattern in BUFP->buffer, first tries to match the
++ virtual concatenation of STRING1 and STRING2, starting first at index
++ STARTPOS, then at STARTPOS + 1, and so on.
++
++ STRING1 and STRING2 have length SIZE1 and SIZE2, respectively.
++
++ RANGE is how far to scan while trying to match. RANGE = 0 means try
++ only at STARTPOS; in general, the last start tried is STARTPOS +
++ RANGE.
++
++ In REGS, return the indices of the virtual concatenation of STRING1
++ and STRING2 that matched the entire BUFP->buffer and its contained
++ subexpressions.
++
++ Do not consider matching one past the index STOP in the virtual
++ concatenation of STRING1 and STRING2.
++
++ We return either the position in the strings at which the match was
++ found, -1 if no match, or -2 if error (such as failure
++ stack overflow). */
++
++int
++re_search_2 (struct re_pattern_buffer *bufp, const char *string1, int size1,
++ const char *string2, int size2, int startpos, int range,
++ struct re_registers *regs, int stop)
++{
++# ifdef MBS_SUPPORT
++ if (MB_CUR_MAX != 1)
++ return wcs_re_search_2 (bufp, string1, size1, string2, size2, startpos,
++ range, regs, stop);
++ else
++# endif
++ return byte_re_search_2 (bufp, string1, size1, string2, size2, startpos,
++ range, regs, stop);
++} /* re_search_2 */
++#ifdef _LIBC
++weak_alias (__re_search_2, re_search_2)
++#endif
++
++#endif /* not INSIDE_RECURSION */
++
++#ifdef INSIDE_RECURSION
++
++#ifdef MATCH_MAY_ALLOCATE
++# define FREE_VAR(var) if (var) REGEX_FREE (var); var = NULL
++#else
++# define FREE_VAR(var) if (var) free (var); var = NULL
++#endif
++
++#ifdef WCHAR
++# define MAX_ALLOCA_SIZE 2000
++
++# define FREE_WCS_BUFFERS() \
++ do { \
++ if (size1 > MAX_ALLOCA_SIZE) \
++ { \
++ free (wcs_string1); \
++ free (mbs_offset1); \
++ } \
++ else \
++ { \
++ FREE_VAR (wcs_string1); \
++ FREE_VAR (mbs_offset1); \
++ } \
++ if (size2 > MAX_ALLOCA_SIZE) \
++ { \
++ free (wcs_string2); \
++ free (mbs_offset2); \
++ } \
++ else \
++ { \
++ FREE_VAR (wcs_string2); \
++ FREE_VAR (mbs_offset2); \
++ } \
++ } while (0)
++
++#endif
++
++
++static int
++PREFIX(re_search_2) (struct re_pattern_buffer *bufp, const char *string1,
++ int size1, const char *string2, int size2,
++ int startpos, int range,
++ struct re_registers *regs, int stop)
++{
++ int val;
++ register char *fastmap = bufp->fastmap;
++ register RE_TRANSLATE_TYPE translate = bufp->translate;
++ int total_size = size1 + size2;
++ int endpos = startpos + range;
++#ifdef WCHAR
++ /* We need wchar_t* buffers correspond to cstring1, cstring2. */
++ wchar_t *wcs_string1 = NULL, *wcs_string2 = NULL;
++ /* We need the size of wchar_t buffers correspond to csize1, csize2. */
++ int wcs_size1 = 0, wcs_size2 = 0;
++ /* offset buffer for optimizatoin. See convert_mbs_to_wc. */
++ int *mbs_offset1 = NULL, *mbs_offset2 = NULL;
++ /* They hold whether each wchar_t is binary data or not. */
++ char *is_binary = NULL;
++#endif /* WCHAR */
++
++ /* Check for out-of-range STARTPOS. */
++ if (startpos < 0 || startpos > total_size)
++ return -1;
++
++ /* Fix up RANGE if it might eventually take us outside
++ the virtual concatenation of STRING1 and STRING2.
++ Make sure we won't move STARTPOS below 0 or above TOTAL_SIZE. */
++ if (endpos < 0)
++ range = 0 - startpos;
++ else if (endpos > total_size)
++ range = total_size - startpos;
++
++ /* If the search isn't to be a backwards one, don't waste time in a
++ search for a pattern that must be anchored. */
++ if (bufp->used > 0 && range > 0
++ && ((re_opcode_t) bufp->buffer[0] == begbuf
++ /* `begline' is like `begbuf' if it cannot match at newlines. */
++ || ((re_opcode_t) bufp->buffer[0] == begline
++ && !bufp->newline_anchor)))
++ {
++ if (startpos > 0)
++ return -1;
++ else
++ range = 1;
++ }
++
++#ifdef emacs
++ /* In a forward search for something that starts with \=.
++ don't keep searching past point. */
++ if (bufp->used > 0 && (re_opcode_t) bufp->buffer[0] == at_dot && range > 0)
++ {
++ range = PT - startpos;
++ if (range <= 0)
++ return -1;
++ }
++#endif /* emacs */
++
++ /* Update the fastmap now if not correct already. */
++ if (fastmap && !bufp->fastmap_accurate)
++ if (re_compile_fastmap (bufp) == -2)
++ return -2;
++
++#ifdef WCHAR
++ /* Allocate wchar_t array for wcs_string1 and wcs_string2 and
++ fill them with converted string. */
++ if (size1 != 0)
++ {
++ if (size1 > MAX_ALLOCA_SIZE)
++ {
++ wcs_string1 = TALLOC (size1 + 1, CHAR_T);
++ mbs_offset1 = TALLOC (size1 + 1, int);
++ is_binary = TALLOC (size1 + 1, char);
++ }
++ else
++ {
++ wcs_string1 = REGEX_TALLOC (size1 + 1, CHAR_T);
++ mbs_offset1 = REGEX_TALLOC (size1 + 1, int);
++ is_binary = REGEX_TALLOC (size1 + 1, char);
++ }
++ if (!wcs_string1 || !mbs_offset1 || !is_binary)
++ {
++ if (size1 > MAX_ALLOCA_SIZE)
++ {
++ free (wcs_string1);
++ free (mbs_offset1);
++ free (is_binary);
++ }
++ else
++ {
++ FREE_VAR (wcs_string1);
++ FREE_VAR (mbs_offset1);
++ FREE_VAR (is_binary);
++ }
++ return -2;
++ }
++ wcs_size1 = convert_mbs_to_wcs(wcs_string1, string1, size1,
++ mbs_offset1, is_binary);
++ wcs_string1[wcs_size1] = L'\0'; /* for a sentinel */
++ if (size1 > MAX_ALLOCA_SIZE)
++ free (is_binary);
++ else
++ FREE_VAR (is_binary);
++ }
++ if (size2 != 0)
++ {
++ if (size2 > MAX_ALLOCA_SIZE)
++ {
++ wcs_string2 = TALLOC (size2 + 1, CHAR_T);
++ mbs_offset2 = TALLOC (size2 + 1, int);
++ is_binary = TALLOC (size2 + 1, char);
++ }
++ else
++ {
++ wcs_string2 = REGEX_TALLOC (size2 + 1, CHAR_T);
++ mbs_offset2 = REGEX_TALLOC (size2 + 1, int);
++ is_binary = REGEX_TALLOC (size2 + 1, char);
++ }
++ if (!wcs_string2 || !mbs_offset2 || !is_binary)
++ {
++ FREE_WCS_BUFFERS ();
++ if (size2 > MAX_ALLOCA_SIZE)
++ free (is_binary);
++ else
++ FREE_VAR (is_binary);
++ return -2;
++ }
++ wcs_size2 = convert_mbs_to_wcs(wcs_string2, string2, size2,
++ mbs_offset2, is_binary);
++ wcs_string2[wcs_size2] = L'\0'; /* for a sentinel */
++ if (size2 > MAX_ALLOCA_SIZE)
++ free (is_binary);
++ else
++ FREE_VAR (is_binary);
++ }
++#endif /* WCHAR */
++
++
++ /* Loop through the string, looking for a place to start matching. */
++ for (;;)
++ {
++ /* If a fastmap is supplied, skip quickly over characters that
++ cannot be the start of a match. If the pattern can match the
++ null string, however, we don't need to skip characters; we want
++ the first null string. */
++ if (fastmap && startpos < total_size && !bufp->can_be_null)
++ {
++ if (range > 0) /* Searching forwards. */
++ {
++ register const char *d;
++ register int lim = 0;
++ int irange = range;
++
++ if (startpos < size1 && startpos + range >= size1)
++ lim = range - (size1 - startpos);
++
++ d = (startpos >= size1 ? string2 - size1 : string1) + startpos;
++
++ /* Written out as an if-else to avoid testing `translate'
++ inside the loop. */
++ if (translate)
++ while (range > lim
++ && !fastmap[(unsigned char)
++ translate[(unsigned char) *d++]])
++ range--;
++ else
++ while (range > lim && !fastmap[(unsigned char) *d++])
++ range--;
++
++ startpos += irange - range;
++ }
++ else /* Searching backwards. */
++ {
++ register CHAR_T c = (size1 == 0 || startpos >= size1
++ ? string2[startpos - size1]
++ : string1[startpos]);
++
++ if (!fastmap[(unsigned char) TRANSLATE (c)])
++ goto advance;
++ }
++ }
++
++ /* If can't match the null string, and that's all we have left, fail. */
++ if (range >= 0 && startpos == total_size && fastmap
++ && !bufp->can_be_null)
++ {
++#ifdef WCHAR
++ FREE_WCS_BUFFERS ();
++#endif
++ return -1;
++ }
++
++#ifdef WCHAR
++ val = wcs_re_match_2_internal (bufp, string1, size1, string2,
++ size2, startpos, regs, stop,
++ wcs_string1, wcs_size1,
++ wcs_string2, wcs_size2,
++ mbs_offset1, mbs_offset2);
++#else /* BYTE */
++ val = byte_re_match_2_internal (bufp, string1, size1, string2,
++ size2, startpos, regs, stop);
++#endif /* BYTE */
++
++#ifndef REGEX_MALLOC
++# ifdef C_ALLOCA
++ alloca (0);
++# endif
++#endif
++
++ if (val >= 0)
++ {
++#ifdef WCHAR
++ FREE_WCS_BUFFERS ();
++#endif
++ return startpos;
++ }
++
++ if (val == -2)
++ {
++#ifdef WCHAR
++ FREE_WCS_BUFFERS ();
++#endif
++ return -2;
++ }
++
++ advance:
++ if (!range)
++ break;
++ else if (range > 0)
++ {
++ range--;
++ startpos++;
++ }
++ else
++ {
++ range++;
++ startpos--;
++ }
++ }
++#ifdef WCHAR
++ FREE_WCS_BUFFERS ();
++#endif
++ return -1;
++}
++
++#ifdef WCHAR
++/* This converts PTR, a pointer into one of the search wchar_t strings
++ `string1' and `string2' into an multibyte string offset from the
++ beginning of that string. We use mbs_offset to optimize.
++ See convert_mbs_to_wcs. */
++# define POINTER_TO_OFFSET(ptr) \
++ (FIRST_STRING_P (ptr) \
++ ? ((regoff_t)(mbs_offset1 != NULL? mbs_offset1[(ptr)-string1] : 0)) \
++ : ((regoff_t)((mbs_offset2 != NULL? mbs_offset2[(ptr)-string2] : 0) \
++ + csize1)))
++#else /* BYTE */
++/* This converts PTR, a pointer into one of the search strings `string1'
++ and `string2' into an offset from the beginning of that string. */
++# define POINTER_TO_OFFSET(ptr) \
++ (FIRST_STRING_P (ptr) \
++ ? ((regoff_t) ((ptr) - string1)) \
++ : ((regoff_t) ((ptr) - string2 + size1)))
++#endif /* WCHAR */
++
++/* Macros for dealing with the split strings in re_match_2. */
++
++#define MATCHING_IN_FIRST_STRING (dend == end_match_1)
++
++/* Call before fetching a character with *d. This switches over to
++ string2 if necessary. */
++#define PREFETCH() \
++ while (d == dend) \
++ { \
++ /* End of string2 => fail. */ \
++ if (dend == end_match_2) \
++ goto fail; \
++ /* End of string1 => advance to string2. */ \
++ d = string2; \
++ dend = end_match_2; \
++ }
++
++/* Test if at very beginning or at very end of the virtual concatenation
++ of `string1' and `string2'. If only one string, it's `string2'. */
++#define AT_STRINGS_BEG(d) ((d) == (size1 ? string1 : string2) || !size2)
++#define AT_STRINGS_END(d) ((d) == end2)
++
++
++/* Test if D points to a character which is word-constituent. We have
++ two special cases to check for: if past the end of string1, look at
++ the first character in string2; and if before the beginning of
++ string2, look at the last character in string1. */
++#ifdef WCHAR
++/* Use internationalized API instead of SYNTAX. */
++# define WORDCHAR_P(d) \
++ (iswalnum ((wint_t)((d) == end1 ? *string2 \
++ : (d) == string2 - 1 ? *(end1 - 1) : *(d))) != 0 \
++ || ((d) == end1 ? *string2 \
++ : (d) == string2 - 1 ? *(end1 - 1) : *(d)) == L'_')
++#else /* BYTE */
++# define WORDCHAR_P(d) \
++ (SYNTAX ((d) == end1 ? *string2 \
++ : (d) == string2 - 1 ? *(end1 - 1) : *(d)) \
++ == Sword)
++#endif /* WCHAR */
++
++/* Disabled due to a compiler bug -- see comment at case wordbound */
++#if 0
++/* Test if the character before D and the one at D differ with respect
++ to being word-constituent. */
++#define AT_WORD_BOUNDARY(d) \
++ (AT_STRINGS_BEG (d) || AT_STRINGS_END (d) \
++ || WORDCHAR_P (d - 1) != WORDCHAR_P (d))
++#endif
++
++/* Free everything we malloc. */
++#ifdef MATCH_MAY_ALLOCATE
++# ifdef WCHAR
++# define FREE_VARIABLES() \
++ do { \
++ REGEX_FREE_STACK (fail_stack.stack); \
++ FREE_VAR (regstart); \
++ FREE_VAR (regend); \
++ FREE_VAR (old_regstart); \
++ FREE_VAR (old_regend); \
++ FREE_VAR (best_regstart); \
++ FREE_VAR (best_regend); \
++ FREE_VAR (reg_info); \
++ FREE_VAR (reg_dummy); \
++ FREE_VAR (reg_info_dummy); \
++ if (!cant_free_wcs_buf) \
++ { \
++ FREE_VAR (string1); \
++ FREE_VAR (string2); \
++ FREE_VAR (mbs_offset1); \
++ FREE_VAR (mbs_offset2); \
++ } \
++ } while (0)
++# else /* BYTE */
++# define FREE_VARIABLES() \
++ do { \
++ REGEX_FREE_STACK (fail_stack.stack); \
++ FREE_VAR (regstart); \
++ FREE_VAR (regend); \
++ FREE_VAR (old_regstart); \
++ FREE_VAR (old_regend); \
++ FREE_VAR (best_regstart); \
++ FREE_VAR (best_regend); \
++ FREE_VAR (reg_info); \
++ FREE_VAR (reg_dummy); \
++ FREE_VAR (reg_info_dummy); \
++ } while (0)
++# endif /* WCHAR */
++#else
++# ifdef WCHAR
++# define FREE_VARIABLES() \
++ do { \
++ if (!cant_free_wcs_buf) \
++ { \
++ FREE_VAR (string1); \
++ FREE_VAR (string2); \
++ FREE_VAR (mbs_offset1); \
++ FREE_VAR (mbs_offset2); \
++ } \
++ } while (0)
++# else /* BYTE */
++# define FREE_VARIABLES() ((void)0) /* Do nothing! But inhibit gcc warning. */
++# endif /* WCHAR */
++#endif /* not MATCH_MAY_ALLOCATE */
++
++/* These values must meet several constraints. They must not be valid
++ register values; since we have a limit of 255 registers (because
++ we use only one byte in the pattern for the register number), we can
++ use numbers larger than 255. They must differ by 1, because of
++ NUM_FAILURE_ITEMS above. And the value for the lowest register must
++ be larger than the value for the highest register, so we do not try
++ to actually save any registers when none are active. */
++#define NO_HIGHEST_ACTIVE_REG (1 << BYTEWIDTH)
++#define NO_LOWEST_ACTIVE_REG (NO_HIGHEST_ACTIVE_REG + 1)
++
++#else /* not INSIDE_RECURSION */
++/* Matching routines. */
++
++#ifndef emacs /* Emacs never uses this. */
++/* re_match is like re_match_2 except it takes only a single string. */
++
++int
++re_match (struct re_pattern_buffer *bufp, const char *string,
++ int size, int pos, struct re_registers *regs)
++{
++ int result;
++# ifdef MBS_SUPPORT
++ if (MB_CUR_MAX != 1)
++ result = wcs_re_match_2_internal (bufp, NULL, 0, string, size,
++ pos, regs, size,
++ NULL, 0, NULL, 0, NULL, NULL);
++ else
++# endif
++ result = byte_re_match_2_internal (bufp, NULL, 0, string, size,
++ pos, regs, size);
++# ifndef REGEX_MALLOC
++# ifdef C_ALLOCA
++ alloca (0);
++# endif
++# endif
++ return result;
++}
++# ifdef _LIBC
++weak_alias (__re_match, re_match)
++# endif
++#endif /* not emacs */
++
++#endif /* not INSIDE_RECURSION */
++
++#ifdef INSIDE_RECURSION
++static boolean PREFIX(group_match_null_string_p) (UCHAR_T **p,
++ UCHAR_T *end,
++ PREFIX(register_info_type) *reg_info);
++static boolean PREFIX(alt_match_null_string_p) (UCHAR_T *p,
++ UCHAR_T *end,
++ PREFIX(register_info_type) *reg_info);
++static boolean PREFIX(common_op_match_null_string_p) (UCHAR_T **p,
++ UCHAR_T *end,
++ PREFIX(register_info_type) *reg_info);
++static int PREFIX(bcmp_translate) (const CHAR_T *s1, const CHAR_T *s2,
++ register int len,
++ RE_TRANSLATE_TYPE translate);
++#else /* not INSIDE_RECURSION */
++
++/* re_match_2 matches the compiled pattern in BUFP against the
++ the (virtual) concatenation of STRING1 and STRING2 (of length SIZE1
++ and SIZE2, respectively). We start matching at POS, and stop
++ matching at STOP.
++
++ If REGS is non-null and the `no_sub' field of BUFP is nonzero, we
++ store offsets for the substring each group matched in REGS. See the
++ documentation for exactly how many groups we fill.
++
++ We return -1 if no match, -2 if an internal error (such as the
++ failure stack overflowing). Otherwise, we return the length of the
++ matched substring. */
++
++int
++re_match_2 (struct re_pattern_buffer *bufp, const char *string1, int size1,
++ const char *string2, int size2, int pos,
++ struct re_registers *regs, int stop)
++{
++ int result;
++# ifdef MBS_SUPPORT
++ if (MB_CUR_MAX != 1)
++ result = wcs_re_match_2_internal (bufp, string1, size1, string2, size2,
++ pos, regs, stop,
++ NULL, 0, NULL, 0, NULL, NULL);
++ else
++# endif
++ result = byte_re_match_2_internal (bufp, string1, size1, string2, size2,
++ pos, regs, stop);
++
++#ifndef REGEX_MALLOC
++# ifdef C_ALLOCA
++ alloca (0);
++# endif
++#endif
++ return result;
++}
++#ifdef _LIBC
++weak_alias (__re_match_2, re_match_2)
++#endif
++
++#endif /* not INSIDE_RECURSION */
++
++#ifdef INSIDE_RECURSION
++
++#ifdef WCHAR
++static int count_mbs_length (int *, int);
++
++/* This check the substring (from 0, to length) of the multibyte string,
++ to which offset_buffer correspond. And count how many wchar_t_characters
++ the substring occupy. We use offset_buffer to optimization.
++ See convert_mbs_to_wcs. */
++
++static int
++count_mbs_length(int *offset_buffer, int length)
++{
++ int upper, lower;
++
++ /* Check whether the size is valid. */
++ if (length < 0)
++ return -1;
++
++ if (offset_buffer == NULL)
++ return 0;
++
++ /* If there are no multibyte character, offset_buffer[i] == i.
++ Optmize for this case. */
++ if (offset_buffer[length] == length)
++ return length;
++
++ /* Set up upper with length. (because for all i, offset_buffer[i] >= i) */
++ upper = length;
++ lower = 0;
++
++ while (true)
++ {
++ int middle = (lower + upper) / 2;
++ if (middle == lower || middle == upper)
++ break;
++ if (offset_buffer[middle] > length)
++ upper = middle;
++ else if (offset_buffer[middle] < length)
++ lower = middle;
++ else
++ return middle;
++ }
++
++ return -1;
++}
++#endif /* WCHAR */
++
++/* This is a separate function so that we can force an alloca cleanup
++ afterwards. */
++#ifdef WCHAR
++static int
++wcs_re_match_2_internal (struct re_pattern_buffer *bufp,
++ const char *cstring1, int csize1,
++ const char *cstring2, int csize2,
++ int pos,
++ struct re_registers *regs,
++ int stop,
++ /* string1 == string2 == NULL means string1/2, size1/2 and
++ mbs_offset1/2 need seting up in this function. */
++ /* We need wchar_t* buffers correspond to cstring1, cstring2. */
++ wchar_t *string1, int size1,
++ wchar_t *string2, int size2,
++ /* offset buffer for optimizatoin. See convert_mbs_to_wc. */
++ int *mbs_offset1, int *mbs_offset2)
++#else /* BYTE */
++static int
++byte_re_match_2_internal (struct re_pattern_buffer *bufp,
++ const char *string1, int size1,
++ const char *string2, int size2,
++ int pos,
++ struct re_registers *regs, int stop)
++#endif /* BYTE */
++{
++ /* General temporaries. */
++ int mcnt;
++ UCHAR_T *p1;
++#ifdef WCHAR
++ /* They hold whether each wchar_t is binary data or not. */
++ char *is_binary = NULL;
++ /* If true, we can't free string1/2, mbs_offset1/2. */
++ int cant_free_wcs_buf = 1;
++#endif /* WCHAR */
++
++ /* Just past the end of the corresponding string. */
++ const CHAR_T *end1, *end2;
++
++ /* Pointers into string1 and string2, just past the last characters in
++ each to consider matching. */
++ const CHAR_T *end_match_1, *end_match_2;
++
++ /* Where we are in the data, and the end of the current string. */
++ const CHAR_T *d, *dend;
++
++ /* Where we are in the pattern, and the end of the pattern. */
++#ifdef WCHAR
++ UCHAR_T *pattern, *p;
++ register UCHAR_T *pend;
++#else /* BYTE */
++ UCHAR_T *p = bufp->buffer;
++ register UCHAR_T *pend = p + bufp->used;
++#endif /* WCHAR */
++
++ /* Mark the opcode just after a start_memory, so we can test for an
++ empty subpattern when we get to the stop_memory. */
++ UCHAR_T *just_past_start_mem = 0;
++
++ /* We use this to map every character in the string. */
++ RE_TRANSLATE_TYPE translate = bufp->translate;
++
++ /* Failure point stack. Each place that can handle a failure further
++ down the line pushes a failure point on this stack. It consists of
++ restart, regend, and reg_info for all registers corresponding to
++ the subexpressions we're currently inside, plus the number of such
++ registers, and, finally, two char *'s. The first char * is where
++ to resume scanning the pattern; the second one is where to resume
++ scanning the strings. If the latter is zero, the failure point is
++ a ``dummy''; if a failure happens and the failure point is a dummy,
++ it gets discarded and the next next one is tried. */
++#ifdef MATCH_MAY_ALLOCATE /* otherwise, this is global. */
++ PREFIX(fail_stack_type) fail_stack;
++#endif
++#ifdef DEBUG
++ static unsigned failure_id;
++ unsigned nfailure_points_pushed = 0, nfailure_points_popped = 0;
++#endif
++
++#ifdef REL_ALLOC
++ /* This holds the pointer to the failure stack, when
++ it is allocated relocatably. */
++ fail_stack_elt_t *failure_stack_ptr;
++#endif
++
++ /* We fill all the registers internally, independent of what we
++ return, for use in backreferences. The number here includes
++ an element for register zero. */
++ size_t num_regs = bufp->re_nsub + 1;
++
++ /* The currently active registers. */
++ active_reg_t lowest_active_reg = NO_LOWEST_ACTIVE_REG;
++ active_reg_t highest_active_reg = NO_HIGHEST_ACTIVE_REG;
++
++ /* Information on the contents of registers. These are pointers into
++ the input strings; they record just what was matched (on this
++ attempt) by a subexpression part of the pattern, that is, the
++ regnum-th regstart pointer points to where in the pattern we began
++ matching and the regnum-th regend points to right after where we
++ stopped matching the regnum-th subexpression. (The zeroth register
++ keeps track of what the whole pattern matches.) */
++#ifdef MATCH_MAY_ALLOCATE /* otherwise, these are global. */
++ const CHAR_T **regstart, **regend;
++#endif
++
++ /* If a group that's operated upon by a repetition operator fails to
++ match anything, then the register for its start will need to be
++ restored because it will have been set to wherever in the string we
++ are when we last see its open-group operator. Similarly for a
++ register's end. */
++#ifdef MATCH_MAY_ALLOCATE /* otherwise, these are global. */
++ const CHAR_T **old_regstart, **old_regend;
++#endif
++
++ /* The is_active field of reg_info helps us keep track of which (possibly
++ nested) subexpressions we are currently in. The matched_something
++ field of reg_info[reg_num] helps us tell whether or not we have
++ matched any of the pattern so far this time through the reg_num-th
++ subexpression. These two fields get reset each time through any
++ loop their register is in. */
++#ifdef MATCH_MAY_ALLOCATE /* otherwise, this is global. */
++ PREFIX(register_info_type) *reg_info;
++#endif
++
++ /* The following record the register info as found in the above
++ variables when we find a match better than any we've seen before.
++ This happens as we backtrack through the failure points, which in
++ turn happens only if we have not yet matched the entire string. */
++ unsigned best_regs_set = false;
++#ifdef MATCH_MAY_ALLOCATE /* otherwise, these are global. */
++ const CHAR_T **best_regstart, **best_regend;
++#endif
++
++ /* Logically, this is `best_regend[0]'. But we don't want to have to
++ allocate space for that if we're not allocating space for anything
++ else (see below). Also, we never need info about register 0 for
++ any of the other register vectors, and it seems rather a kludge to
++ treat `best_regend' differently than the rest. So we keep track of
++ the end of the best match so far in a separate variable. We
++ initialize this to NULL so that when we backtrack the first time
++ and need to test it, it's not garbage. */
++ const CHAR_T *match_end = NULL;
++
++ /* This helps SET_REGS_MATCHED avoid doing redundant work. */
++ int set_regs_matched_done = 0;
++
++ /* Used when we pop values we don't care about. */
++#ifdef MATCH_MAY_ALLOCATE /* otherwise, these are global. */
++ const CHAR_T **reg_dummy;
++ PREFIX(register_info_type) *reg_info_dummy;
++#endif
++
++#ifdef DEBUG
++ /* Counts the total number of registers pushed. */
++ unsigned num_regs_pushed = 0;
++#endif
++
++ DEBUG_PRINT1 ("\n\nEntering re_match_2.\n");
++
++ INIT_FAIL_STACK ();
++
++#ifdef MATCH_MAY_ALLOCATE
++ /* Do not bother to initialize all the register variables if there are
++ no groups in the pattern, as it takes a fair amount of time. If
++ there are groups, we include space for register 0 (the whole
++ pattern), even though we never use it, since it simplifies the
++ array indexing. We should fix this. */
++ if (bufp->re_nsub)
++ {
++ regstart = REGEX_TALLOC (num_regs, const CHAR_T *);
++ regend = REGEX_TALLOC (num_regs, const CHAR_T *);
++ old_regstart = REGEX_TALLOC (num_regs, const CHAR_T *);
++ old_regend = REGEX_TALLOC (num_regs, const CHAR_T *);
++ best_regstart = REGEX_TALLOC (num_regs, const CHAR_T *);
++ best_regend = REGEX_TALLOC (num_regs, const CHAR_T *);
++ reg_info = REGEX_TALLOC (num_regs, PREFIX(register_info_type));
++ reg_dummy = REGEX_TALLOC (num_regs, const CHAR_T *);
++ reg_info_dummy = REGEX_TALLOC (num_regs, PREFIX(register_info_type));
++
++ if (!(regstart && regend && old_regstart && old_regend && reg_info
++ && best_regstart && best_regend && reg_dummy && reg_info_dummy))
++ {
++ FREE_VARIABLES ();
++ return -2;
++ }
++ }
++ else
++ {
++ /* We must initialize all our variables to NULL, so that
++ `FREE_VARIABLES' doesn't try to free them. */
++ regstart = regend = old_regstart = old_regend = best_regstart
++ = best_regend = reg_dummy = NULL;
++ reg_info = reg_info_dummy = (PREFIX(register_info_type) *) NULL;
++ }
++#endif /* MATCH_MAY_ALLOCATE */
++
++ /* The starting position is bogus. */
++#ifdef WCHAR
++ if (pos < 0 || pos > csize1 + csize2)
++#else /* BYTE */
++ if (pos < 0 || pos > size1 + size2)
++#endif
++ {
++ FREE_VARIABLES ();
++ return -1;
++ }
++
++#ifdef WCHAR
++ /* Allocate wchar_t array for string1 and string2 and
++ fill them with converted string. */
++ if (string1 == NULL && string2 == NULL)
++ {
++ /* We need seting up buffers here. */
++
++ /* We must free wcs buffers in this function. */
++ cant_free_wcs_buf = 0;
++
++ if (csize1 != 0)
++ {
++ string1 = REGEX_TALLOC (csize1 + 1, CHAR_T);
++ mbs_offset1 = REGEX_TALLOC (csize1 + 1, int);
++ is_binary = REGEX_TALLOC (csize1 + 1, char);
++ if (!string1 || !mbs_offset1 || !is_binary)
++ {
++ FREE_VAR (string1);
++ FREE_VAR (mbs_offset1);
++ FREE_VAR (is_binary);
++ return -2;
++ }
++ }
++ if (csize2 != 0)
++ {
++ string2 = REGEX_TALLOC (csize2 + 1, CHAR_T);
++ mbs_offset2 = REGEX_TALLOC (csize2 + 1, int);
++ is_binary = REGEX_TALLOC (csize2 + 1, char);
++ if (!string2 || !mbs_offset2 || !is_binary)
++ {
++ FREE_VAR (string1);
++ FREE_VAR (mbs_offset1);
++ FREE_VAR (string2);
++ FREE_VAR (mbs_offset2);
++ FREE_VAR (is_binary);
++ return -2;
++ }
++ size2 = convert_mbs_to_wcs(string2, cstring2, csize2,
++ mbs_offset2, is_binary);
++ string2[size2] = L'\0'; /* for a sentinel */
++ FREE_VAR (is_binary);
++ }
++ }
++
++ /* We need to cast pattern to (wchar_t*), because we casted this compiled
++ pattern to (char*) in regex_compile. */
++ p = pattern = (CHAR_T*)bufp->buffer;
++ pend = (CHAR_T*)(bufp->buffer + bufp->used);
++
++#endif /* WCHAR */
++
++ /* Initialize subexpression text positions to -1 to mark ones that no
++ start_memory/stop_memory has been seen for. Also initialize the
++ register information struct. */
++ for (mcnt = 1; (unsigned) mcnt < num_regs; mcnt++)
++ {
++ regstart[mcnt] = regend[mcnt]
++ = old_regstart[mcnt] = old_regend[mcnt] = REG_UNSET_VALUE;
++
++ REG_MATCH_NULL_STRING_P (reg_info[mcnt]) = MATCH_NULL_UNSET_VALUE;
++ IS_ACTIVE (reg_info[mcnt]) = 0;
++ MATCHED_SOMETHING (reg_info[mcnt]) = 0;
++ EVER_MATCHED_SOMETHING (reg_info[mcnt]) = 0;
++ }
++
++ /* We move `string1' into `string2' if the latter's empty -- but not if
++ `string1' is null. */
++ if (size2 == 0 && string1 != NULL)
++ {
++ string2 = string1;
++ size2 = size1;
++ string1 = 0;
++ size1 = 0;
++#ifdef WCHAR
++ mbs_offset2 = mbs_offset1;
++ csize2 = csize1;
++ mbs_offset1 = NULL;
++ csize1 = 0;
++#endif
++ }
++ end1 = string1 + size1;
++ end2 = string2 + size2;
++
++ /* Compute where to stop matching, within the two strings. */
++#ifdef WCHAR
++ if (stop <= csize1)
++ {
++ mcnt = count_mbs_length(mbs_offset1, stop);
++ end_match_1 = string1 + mcnt;
++ end_match_2 = string2;
++ }
++ else
++ {
++ if (stop > csize1 + csize2)
++ stop = csize1 + csize2;
++ end_match_1 = end1;
++ mcnt = count_mbs_length(mbs_offset2, stop-csize1);
++ end_match_2 = string2 + mcnt;
++ }
++ if (mcnt < 0)
++ { /* count_mbs_length return error. */
++ FREE_VARIABLES ();
++ return -1;
++ }
++#else
++ if (stop <= size1)
++ {
++ end_match_1 = string1 + stop;
++ end_match_2 = string2;
++ }
++ else
++ {
++ end_match_1 = end1;
++ end_match_2 = string2 + stop - size1;
++ }
++#endif /* WCHAR */
++
++ /* `p' scans through the pattern as `d' scans through the data.
++ `dend' is the end of the input string that `d' points within. `d'
++ is advanced into the following input string whenever necessary, but
++ this happens before fetching; therefore, at the beginning of the
++ loop, `d' can be pointing at the end of a string, but it cannot
++ equal `string2'. */
++#ifdef WCHAR
++ if (size1 > 0 && pos <= csize1)
++ {
++ mcnt = count_mbs_length(mbs_offset1, pos);
++ d = string1 + mcnt;
++ dend = end_match_1;
++ }
++ else
++ {
++ mcnt = count_mbs_length(mbs_offset2, pos-csize1);
++ d = string2 + mcnt;
++ dend = end_match_2;
++ }
++
++ if (mcnt < 0)
++ { /* count_mbs_length return error. */
++ FREE_VARIABLES ();
++ return -1;
++ }
++#else
++ if (size1 > 0 && pos <= size1)
++ {
++ d = string1 + pos;
++ dend = end_match_1;
++ }
++ else
++ {
++ d = string2 + pos - size1;
++ dend = end_match_2;
++ }
++#endif /* WCHAR */
++
++ DEBUG_PRINT1 ("The compiled pattern is:\n");
++ DEBUG_PRINT_COMPILED_PATTERN (bufp, p, pend);
++ DEBUG_PRINT1 ("The string to match is: `");
++ DEBUG_PRINT_DOUBLE_STRING (d, string1, size1, string2, size2);
++ DEBUG_PRINT1 ("'\n");
++
++ /* This loops over pattern commands. It exits by returning from the
++ function if the match is complete, or it drops through if the match
++ fails at this starting point in the input data. */
++ for (;;)
++ {
++#ifdef _LIBC
++ DEBUG_PRINT2 ("\n%p: ", p);
++#else
++ DEBUG_PRINT2 ("\n0x%x: ", p);
++#endif
++
++ if (p == pend)
++ { /* End of pattern means we might have succeeded. */
++ DEBUG_PRINT1 ("end of pattern ... ");
++
++ /* If we haven't matched the entire string, and we want the
++ longest match, try backtracking. */
++ if (d != end_match_2)
++ {
++ /* 1 if this match ends in the same string (string1 or string2)
++ as the best previous match. */
++ boolean same_str_p = (FIRST_STRING_P (match_end)
++ == MATCHING_IN_FIRST_STRING);
++ /* 1 if this match is the best seen so far. */
++ boolean best_match_p;
++
++ /* AIX compiler got confused when this was combined
++ with the previous declaration. */
++ if (same_str_p)
++ best_match_p = d > match_end;
++ else
++ best_match_p = !MATCHING_IN_FIRST_STRING;
++
++ DEBUG_PRINT1 ("backtracking.\n");
++
++ if (!FAIL_STACK_EMPTY ())
++ { /* More failure points to try. */
++
++ /* If exceeds best match so far, save it. */
++ if (!best_regs_set || best_match_p)
++ {
++ best_regs_set = true;
++ match_end = d;
++
++ DEBUG_PRINT1 ("\nSAVING match as best so far.\n");
++
++ for (mcnt = 1; (unsigned) mcnt < num_regs; mcnt++)
++ {
++ best_regstart[mcnt] = regstart[mcnt];
++ best_regend[mcnt] = regend[mcnt];
++ }
++ }
++ goto fail;
++ }
++
++ /* If no failure points, don't restore garbage. And if
++ last match is real best match, don't restore second
++ best one. */
++ else if (best_regs_set && !best_match_p)
++ {
++ restore_best_regs:
++ /* Restore best match. It may happen that `dend ==
++ end_match_1' while the restored d is in string2.
++ For example, the pattern `x.*y.*z' against the
++ strings `x-' and `y-z-', if the two strings are
++ not consecutive in memory. */
++ DEBUG_PRINT1 ("Restoring best registers.\n");
++
++ d = match_end;
++ dend = ((d >= string1 && d <= end1)
++ ? end_match_1 : end_match_2);
++
++ for (mcnt = 1; (unsigned) mcnt < num_regs; mcnt++)
++ {
++ regstart[mcnt] = best_regstart[mcnt];
++ regend[mcnt] = best_regend[mcnt];
++ }
++ }
++ } /* d != end_match_2 */
++
++ succeed_label:
++ DEBUG_PRINT1 ("Accepting match.\n");
++ /* If caller wants register contents data back, do it. */
++ if (regs && !bufp->no_sub)
++ {
++ /* Have the register data arrays been allocated? */
++ if (bufp->regs_allocated == REGS_UNALLOCATED)
++ { /* No. So allocate them with malloc. We need one
++ extra element beyond `num_regs' for the `-1' marker
++ GNU code uses. */
++ regs->num_regs = MAX (RE_NREGS, num_regs + 1);
++ regs->start = TALLOC (regs->num_regs, regoff_t);
++ regs->end = TALLOC (regs->num_regs, regoff_t);
++ if (regs->start == NULL || regs->end == NULL)
++ {
++ FREE_VARIABLES ();
++ return -2;
++ }
++ bufp->regs_allocated = REGS_REALLOCATE;
++ }
++ else if (bufp->regs_allocated == REGS_REALLOCATE)
++ { /* Yes. If we need more elements than were already
++ allocated, reallocate them. If we need fewer, just
++ leave it alone. */
++ if (regs->num_regs < num_regs + 1)
++ {
++ regs->num_regs = num_regs + 1;
++ RETALLOC (regs->start, regs->num_regs, regoff_t);
++ RETALLOC (regs->end, regs->num_regs, regoff_t);
++ if (regs->start == NULL || regs->end == NULL)
++ {
++ FREE_VARIABLES ();
++ return -2;
++ }
++ }
++ }
++ else
++ {
++ /* These braces fend off a "empty body in an else-statement"
++ warning under GCC when assert expands to nothing. */
++ assert (bufp->regs_allocated == REGS_FIXED);
++ }
++
++ /* Convert the pointer data in `regstart' and `regend' to
++ indices. Register zero has to be set differently,
++ since we haven't kept track of any info for it. */
++ if (regs->num_regs > 0)
++ {
++ regs->start[0] = pos;
++#ifdef WCHAR
++ if (MATCHING_IN_FIRST_STRING)
++ regs->end[0] = mbs_offset1 != NULL ?
++ mbs_offset1[d-string1] : 0;
++ else
++ regs->end[0] = csize1 + (mbs_offset2 != NULL ?
++ mbs_offset2[d-string2] : 0);
++#else
++ regs->end[0] = (MATCHING_IN_FIRST_STRING
++ ? ((regoff_t) (d - string1))
++ : ((regoff_t) (d - string2 + size1)));
++#endif /* WCHAR */
++ }
++
++ /* Go through the first `min (num_regs, regs->num_regs)'
++ registers, since that is all we initialized. */
++ for (mcnt = 1; (unsigned) mcnt < MIN (num_regs, regs->num_regs);
++ mcnt++)
++ {
++ if (REG_UNSET (regstart[mcnt]) || REG_UNSET (regend[mcnt]))
++ regs->start[mcnt] = regs->end[mcnt] = -1;
++ else
++ {
++ regs->start[mcnt]
++ = (regoff_t) POINTER_TO_OFFSET (regstart[mcnt]);
++ regs->end[mcnt]
++ = (regoff_t) POINTER_TO_OFFSET (regend[mcnt]);
++ }
++ }
++
++ /* If the regs structure we return has more elements than
++ were in the pattern, set the extra elements to -1. If
++ we (re)allocated the registers, this is the case,
++ because we always allocate enough to have at least one
++ -1 at the end. */
++ for (mcnt = num_regs; (unsigned) mcnt < regs->num_regs; mcnt++)
++ regs->start[mcnt] = regs->end[mcnt] = -1;
++ } /* regs && !bufp->no_sub */
++
++ DEBUG_PRINT4 ("%u failure points pushed, %u popped (%u remain).\n",
++ nfailure_points_pushed, nfailure_points_popped,
++ nfailure_points_pushed - nfailure_points_popped);
++ DEBUG_PRINT2 ("%u registers pushed.\n", num_regs_pushed);
++
++#ifdef WCHAR
++ if (MATCHING_IN_FIRST_STRING)
++ mcnt = mbs_offset1 != NULL ? mbs_offset1[d-string1] : 0;
++ else
++ mcnt = (mbs_offset2 != NULL ? mbs_offset2[d-string2] : 0) +
++ csize1;
++ mcnt -= pos;
++#else
++ mcnt = d - pos - (MATCHING_IN_FIRST_STRING
++ ? string1
++ : string2 - size1);
++#endif /* WCHAR */
++
++ DEBUG_PRINT2 ("Returning %d from re_match_2.\n", mcnt);
++
++ FREE_VARIABLES ();
++ return mcnt;
++ }
++
++ /* Otherwise match next pattern command. */
++ switch (SWITCH_ENUM_CAST ((re_opcode_t) *p++))
++ {
++ /* Ignore these. Used to ignore the n of succeed_n's which
++ currently have n == 0. */
++ case no_op:
++ DEBUG_PRINT1 ("EXECUTING no_op.\n");
++ break;
++
++ case succeed:
++ DEBUG_PRINT1 ("EXECUTING succeed.\n");
++ goto succeed_label;
++
++ /* Match the next n pattern characters exactly. The following
++ byte in the pattern defines n, and the n bytes after that
++ are the characters to match. */
++ case exactn:
++#ifdef MBS_SUPPORT
++ case exactn_bin:
++#endif
++ mcnt = *p++;
++ DEBUG_PRINT2 ("EXECUTING exactn %d.\n", mcnt);
++
++ /* This is written out as an if-else so we don't waste time
++ testing `translate' inside the loop. */
++ if (translate)
++ {
++ do
++ {
++ PREFETCH ();
++#ifdef WCHAR
++ if (*d <= 0xff)
++ {
++ if ((UCHAR_T) translate[(unsigned char) *d++]
++ != (UCHAR_T) *p++)
++ goto fail;
++ }
++ else
++ {
++ if (*d++ != (CHAR_T) *p++)
++ goto fail;
++ }
++#else
++ if ((UCHAR_T) translate[(unsigned char) *d++]
++ != (UCHAR_T) *p++)
++ goto fail;
++#endif /* WCHAR */
++ }
++ while (--mcnt);
++ }
++ else
++ {
++ do
++ {
++ PREFETCH ();
++ if (*d++ != (CHAR_T) *p++) goto fail;
++ }
++ while (--mcnt);
++ }
++ SET_REGS_MATCHED ();
++ break;
++
++
++ /* Match any character except possibly a newline or a null. */
++ case anychar:
++ DEBUG_PRINT1 ("EXECUTING anychar.\n");
++
++ PREFETCH ();
++
++ if ((!(bufp->syntax & RE_DOT_NEWLINE) && TRANSLATE (*d) == '\n')
++ || (bufp->syntax & RE_DOT_NOT_NULL && TRANSLATE (*d) == '\000'))
++ goto fail;
++
++ SET_REGS_MATCHED ();
++ DEBUG_PRINT2 (" Matched `%ld'.\n", (long int) *d);
++ d++;
++ break;
++
++
++ case charset:
++ case charset_not:
++ {
++ register UCHAR_T c;
++#ifdef WCHAR
++ unsigned int i, char_class_length, coll_symbol_length,
++ equiv_class_length, ranges_length, chars_length, length;
++ CHAR_T *workp, *workp2, *charset_top;
++#define WORK_BUFFER_SIZE 128
++ CHAR_T str_buf[WORK_BUFFER_SIZE];
++# ifdef _LIBC
++ uint32_t nrules;
++# endif /* _LIBC */
++#endif /* WCHAR */
++ boolean negate = (re_opcode_t) *(p - 1) == charset_not;
++
++ DEBUG_PRINT2 ("EXECUTING charset%s.\n", negate ? "_not" : "");
++ PREFETCH ();
++ c = TRANSLATE (*d); /* The character to match. */
++#ifdef WCHAR
++# ifdef _LIBC
++ nrules = _NL_CURRENT_WORD (LC_COLLATE, _NL_COLLATE_NRULES);
++# endif /* _LIBC */
++ charset_top = p - 1;
++ char_class_length = *p++;
++ coll_symbol_length = *p++;
++ equiv_class_length = *p++;
++ ranges_length = *p++;
++ chars_length = *p++;
++ /* p points charset[6], so the address of the next instruction
++ (charset[l+m+n+2o+k+p']) equals p[l+m+n+2*o+p'],
++ where l=length of char_classes, m=length of collating_symbol,
++ n=equivalence_class, o=length of char_range,
++ p'=length of character. */
++ workp = p;
++ /* Update p to indicate the next instruction. */
++ p += char_class_length + coll_symbol_length+ equiv_class_length +
++ 2*ranges_length + chars_length;
++
++ /* match with char_class? */
++ for (i = 0; i < char_class_length ; i += CHAR_CLASS_SIZE)
++ {
++ wctype_t wctype;
++ uintptr_t alignedp = ((uintptr_t)workp
++ + __alignof__(wctype_t) - 1)
++ & ~(uintptr_t)(__alignof__(wctype_t) - 1);
++ wctype = *((wctype_t*)alignedp);
++ workp += CHAR_CLASS_SIZE;
++# ifdef _LIBC
++ if (__iswctype((wint_t)c, wctype))
++ goto char_set_matched;
++# else
++ if (iswctype((wint_t)c, wctype))
++ goto char_set_matched;
++# endif
++ }
++
++ /* match with collating_symbol? */
++# ifdef _LIBC
++ if (nrules != 0)
++ {
++ const unsigned char *extra = (const unsigned char *)
++ _NL_CURRENT (LC_COLLATE, _NL_COLLATE_SYMB_EXTRAMB);
++
++ for (workp2 = workp + coll_symbol_length ; workp < workp2 ;
++ workp++)
++ {
++ int32_t *wextra;
++ wextra = (int32_t*)(extra + *workp++);
++ for (i = 0; i < *wextra; ++i)
++ if (TRANSLATE(d[i]) != wextra[1 + i])
++ break;
++
++ if (i == *wextra)
++ {
++ /* Update d, however d will be incremented at
++ char_set_matched:, we decrement d here. */
++ d += i - 1;
++ goto char_set_matched;
++ }
++ }
++ }
++ else /* (nrules == 0) */
++# endif
++ /* If we can't look up collation data, we use wcscoll
++ instead. */
++ {
++ for (workp2 = workp + coll_symbol_length ; workp < workp2 ;)
++ {
++ const CHAR_T *backup_d = d, *backup_dend = dend;
++# ifdef _LIBC
++ length = __wcslen (workp);
++# else
++ length = wcslen (workp);
++# endif
++
++ /* If wcscoll(the collating symbol, whole string) > 0,
++ any substring of the string never match with the
++ collating symbol. */
++# ifdef _LIBC
++ if (__wcscoll (workp, d) > 0)
++# else
++ if (wcscoll (workp, d) > 0)
++# endif
++ {
++ workp += length + 1;
++ continue;
++ }
++
++ /* First, we compare the collating symbol with
++ the first character of the string.
++ If it don't match, we add the next character to
++ the compare buffer in turn. */
++ for (i = 0 ; i < WORK_BUFFER_SIZE-1 ; i++, d++)
++ {
++ int match;
++ if (d == dend)
++ {
++ if (dend == end_match_2)
++ break;
++ d = string2;
++ dend = end_match_2;
++ }
++
++ /* add next character to the compare buffer. */
++ str_buf[i] = TRANSLATE(*d);
++ str_buf[i+1] = '\0';
++
++# ifdef _LIBC
++ match = __wcscoll (workp, str_buf);
++# else
++ match = wcscoll (workp, str_buf);
++# endif
++ if (match == 0)
++ goto char_set_matched;
++
++ if (match < 0)
++ /* (str_buf > workp) indicate (str_buf + X > workp),
++ because for all X (str_buf + X > str_buf).
++ So we don't need continue this loop. */
++ break;
++
++ /* Otherwise(str_buf < workp),
++ (str_buf+next_character) may equals (workp).
++ So we continue this loop. */
++ }
++ /* not matched */
++ d = backup_d;
++ dend = backup_dend;
++ workp += length + 1;
++ }
++ }
++ /* match with equivalence_class? */
++# ifdef _LIBC
++ if (nrules != 0)
++ {
++ const CHAR_T *backup_d = d, *backup_dend = dend;
++ /* Try to match the equivalence class against
++ those known to the collate implementation. */
++ const int32_t *table;
++ const int32_t *weights;
++ const int32_t *extra;
++ const int32_t *indirect;
++ int32_t idx, idx2;
++ wint_t *cp;
++ size_t len;
++
++ /* This #include defines a local function! */
++# include <locale/weightwc.h>
++
++ table = (const int32_t *)
++ _NL_CURRENT (LC_COLLATE, _NL_COLLATE_TABLEWC);
++ weights = (const wint_t *)
++ _NL_CURRENT (LC_COLLATE, _NL_COLLATE_WEIGHTWC);
++ extra = (const wint_t *)
++ _NL_CURRENT (LC_COLLATE, _NL_COLLATE_EXTRAWC);
++ indirect = (const int32_t *)
++ _NL_CURRENT (LC_COLLATE, _NL_COLLATE_INDIRECTWC);
++
++ /* Write 1 collating element to str_buf, and
++ get its index. */
++ idx2 = 0;
++
++ for (i = 0 ; idx2 == 0 && i < WORK_BUFFER_SIZE - 1; i++)
++ {
++ cp = (wint_t*)str_buf;
++ if (d == dend)
++ {
++ if (dend == end_match_2)
++ break;
++ d = string2;
++ dend = end_match_2;
++ }
++ str_buf[i] = TRANSLATE(*(d+i));
++ str_buf[i+1] = '\0'; /* sentinel */
++ idx2 = findidx ((const wint_t**)&cp, i);
++ }
++
++ /* Update d, however d will be incremented at
++ char_set_matched:, we decrement d here. */
++ d = backup_d + ((wchar_t*)cp - (wchar_t*)str_buf - 1);
++ if (d >= dend)
++ {
++ if (dend == end_match_2)
++ d = dend;
++ else
++ {
++ d = string2;
++ dend = end_match_2;
++ }
++ }
++
++ len = weights[idx2];
++
++ for (workp2 = workp + equiv_class_length ; workp < workp2 ;
++ workp++)
++ {
++ idx = (int32_t)*workp;
++ /* We already checked idx != 0 in regex_compile. */
++
++ if (idx2 != 0 && len == weights[idx])
++ {
++ int cnt = 0;
++ while (cnt < len && (weights[idx + 1 + cnt]
++ == weights[idx2 + 1 + cnt]))
++ ++cnt;
++
++ if (cnt == len)
++ goto char_set_matched;
++ }
++ }
++ /* not matched */
++ d = backup_d;
++ dend = backup_dend;
++ }
++ else /* (nrules == 0) */
++# endif
++ /* If we can't look up collation data, we use wcscoll
++ instead. */
++ {
++ for (workp2 = workp + equiv_class_length ; workp < workp2 ;)
++ {
++ const CHAR_T *backup_d = d, *backup_dend = dend;
++# ifdef _LIBC
++ length = __wcslen (workp);
++# else
++ length = wcslen (workp);
++# endif
++
++ /* If wcscoll(the collating symbol, whole string) > 0,
++ any substring of the string never match with the
++ collating symbol. */
++# ifdef _LIBC
++ if (__wcscoll (workp, d) > 0)
++# else
++ if (wcscoll (workp, d) > 0)
++# endif
++ {
++ workp += length + 1;
++ break;
++ }
++
++ /* First, we compare the equivalence class with
++ the first character of the string.
++ If it don't match, we add the next character to
++ the compare buffer in turn. */
++ for (i = 0 ; i < WORK_BUFFER_SIZE - 1 ; i++, d++)
++ {
++ int match;
++ if (d == dend)
++ {
++ if (dend == end_match_2)
++ break;
++ d = string2;
++ dend = end_match_2;
++ }
++
++ /* add next character to the compare buffer. */
++ str_buf[i] = TRANSLATE(*d);
++ str_buf[i+1] = '\0';
++
++# ifdef _LIBC
++ match = __wcscoll (workp, str_buf);
++# else
++ match = wcscoll (workp, str_buf);
++# endif
++
++ if (match == 0)
++ goto char_set_matched;
++
++ if (match < 0)
++ /* (str_buf > workp) indicate (str_buf + X > workp),
++ because for all X (str_buf + X > str_buf).
++ So we don't need continue this loop. */
++ break;
++
++ /* Otherwise(str_buf < workp),
++ (str_buf+next_character) may equals (workp).
++ So we continue this loop. */
++ }
++ /* not matched */
++ d = backup_d;
++ dend = backup_dend;
++ workp += length + 1;
++ }
++ }
++
++ /* match with char_range? */
++# ifdef _LIBC
++ if (nrules != 0)
++ {
++ uint32_t collseqval;
++ const char *collseq = (const char *)
++ _NL_CURRENT(LC_COLLATE, _NL_COLLATE_COLLSEQWC);
++
++ collseqval = collseq_table_lookup (collseq, c);
++
++ for (; workp < p - chars_length ;)
++ {
++ uint32_t start_val, end_val;
++
++ /* We already compute the collation sequence value
++ of the characters (or collating symbols). */
++ start_val = (uint32_t) *workp++; /* range_start */
++ end_val = (uint32_t) *workp++; /* range_end */
++
++ if (start_val <= collseqval && collseqval <= end_val)
++ goto char_set_matched;
++ }
++ }
++ else
++# endif
++ {
++ /* We set range_start_char at str_buf[0], range_end_char
++ at str_buf[4], and compared char at str_buf[2]. */
++ str_buf[1] = 0;
++ str_buf[2] = c;
++ str_buf[3] = 0;
++ str_buf[5] = 0;
++ for (; workp < p - chars_length ;)
++ {
++ wchar_t *range_start_char, *range_end_char;
++
++ /* match if (range_start_char <= c <= range_end_char). */
++
++ /* If range_start(or end) < 0, we assume -range_start(end)
++ is the offset of the collating symbol which is specified
++ as the character of the range start(end). */
++
++ /* range_start */
++ if (*workp < 0)
++ range_start_char = charset_top - (*workp++);
++ else
++ {
++ str_buf[0] = *workp++;
++ range_start_char = str_buf;
++ }
++
++ /* range_end */
++ if (*workp < 0)
++ range_end_char = charset_top - (*workp++);
++ else
++ {
++ str_buf[4] = *workp++;
++ range_end_char = str_buf + 4;
++ }
++
++# ifdef _LIBC
++ if (__wcscoll (range_start_char, str_buf+2) <= 0
++ && __wcscoll (str_buf+2, range_end_char) <= 0)
++# else
++ if (wcscoll (range_start_char, str_buf+2) <= 0
++ && wcscoll (str_buf+2, range_end_char) <= 0)
++# endif
++ goto char_set_matched;
++ }
++ }
++
++ /* match with char? */
++ for (; workp < p ; workp++)
++ if (c == *workp)
++ goto char_set_matched;
++
++ negate = !negate;
++
++ char_set_matched:
++ if (negate) goto fail;
++#else
++ /* Cast to `unsigned' instead of `unsigned char' in case the
++ bit list is a full 32 bytes long. */
++ if (c < (unsigned) (*p * BYTEWIDTH)
++ && p[1 + c / BYTEWIDTH] & (1 << (c % BYTEWIDTH)))
++ negate = !negate;
++
++ p += 1 + *p;
++
++ if (!negate) goto fail;
++#undef WORK_BUFFER_SIZE
++#endif /* WCHAR */
++ SET_REGS_MATCHED ();
++ d++;
++ break;
++ }
++
++
++ /* The beginning of a group is represented by start_memory.
++ The arguments are the register number in the next byte, and the
++ number of groups inner to this one in the next. The text
++ matched within the group is recorded (in the internal
++ registers data structure) under the register number. */
++ case start_memory:
++ DEBUG_PRINT3 ("EXECUTING start_memory %ld (%ld):\n",
++ (long int) *p, (long int) p[1]);
++
++ /* Find out if this group can match the empty string. */
++ p1 = p; /* To send to group_match_null_string_p. */
++
++ if (REG_MATCH_NULL_STRING_P (reg_info[*p]) == MATCH_NULL_UNSET_VALUE)
++ REG_MATCH_NULL_STRING_P (reg_info[*p])
++ = PREFIX(group_match_null_string_p) (&p1, pend, reg_info);
++
++ /* Save the position in the string where we were the last time
++ we were at this open-group operator in case the group is
++ operated upon by a repetition operator, e.g., with `(a*)*b'
++ against `ab'; then we want to ignore where we are now in
++ the string in case this attempt to match fails. */
++ old_regstart[*p] = REG_MATCH_NULL_STRING_P (reg_info[*p])
++ ? REG_UNSET (regstart[*p]) ? d : regstart[*p]
++ : regstart[*p];
++ DEBUG_PRINT2 (" old_regstart: %d\n",
++ POINTER_TO_OFFSET (old_regstart[*p]));
++
++ regstart[*p] = d;
++ DEBUG_PRINT2 (" regstart: %d\n", POINTER_TO_OFFSET (regstart[*p]));
++
++ IS_ACTIVE (reg_info[*p]) = 1;
++ MATCHED_SOMETHING (reg_info[*p]) = 0;
++
++ /* Clear this whenever we change the register activity status. */
++ set_regs_matched_done = 0;
++
++ /* This is the new highest active register. */
++ highest_active_reg = *p;
++
++ /* If nothing was active before, this is the new lowest active
++ register. */
++ if (lowest_active_reg == NO_LOWEST_ACTIVE_REG)
++ lowest_active_reg = *p;
++
++ /* Move past the register number and inner group count. */
++ p += 2;
++ just_past_start_mem = p;
++
++ break;
++
++
++ /* The stop_memory opcode represents the end of a group. Its
++ arguments are the same as start_memory's: the register
++ number, and the number of inner groups. */
++ case stop_memory:
++ DEBUG_PRINT3 ("EXECUTING stop_memory %ld (%ld):\n",
++ (long int) *p, (long int) p[1]);
++
++ /* We need to save the string position the last time we were at
++ this close-group operator in case the group is operated
++ upon by a repetition operator, e.g., with `((a*)*(b*)*)*'
++ against `aba'; then we want to ignore where we are now in
++ the string in case this attempt to match fails. */
++ old_regend[*p] = REG_MATCH_NULL_STRING_P (reg_info[*p])
++ ? REG_UNSET (regend[*p]) ? d : regend[*p]
++ : regend[*p];
++ DEBUG_PRINT2 (" old_regend: %d\n",
++ POINTER_TO_OFFSET (old_regend[*p]));
++
++ regend[*p] = d;
++ DEBUG_PRINT2 (" regend: %d\n", POINTER_TO_OFFSET (regend[*p]));
++
++ /* This register isn't active anymore. */
++ IS_ACTIVE (reg_info[*p]) = 0;
++
++ /* Clear this whenever we change the register activity status. */
++ set_regs_matched_done = 0;
++
++ /* If this was the only register active, nothing is active
++ anymore. */
++ if (lowest_active_reg == highest_active_reg)
++ {
++ lowest_active_reg = NO_LOWEST_ACTIVE_REG;
++ highest_active_reg = NO_HIGHEST_ACTIVE_REG;
++ }
++ else
++ { /* We must scan for the new highest active register, since
++ it isn't necessarily one less than now: consider
++ (a(b)c(d(e)f)g). When group 3 ends, after the f), the
++ new highest active register is 1. */
++ UCHAR_T r = *p - 1;
++ while (r > 0 && !IS_ACTIVE (reg_info[r]))
++ r--;
++
++ /* If we end up at register zero, that means that we saved
++ the registers as the result of an `on_failure_jump', not
++ a `start_memory', and we jumped to past the innermost
++ `stop_memory'. For example, in ((.)*) we save
++ registers 1 and 2 as a result of the *, but when we pop
++ back to the second ), we are at the stop_memory 1.
++ Thus, nothing is active. */
++ if (r == 0)
++ {
++ lowest_active_reg = NO_LOWEST_ACTIVE_REG;
++ highest_active_reg = NO_HIGHEST_ACTIVE_REG;
++ }
++ else
++ highest_active_reg = r;
++ }
++
++ /* If just failed to match something this time around with a
++ group that's operated on by a repetition operator, try to
++ force exit from the ``loop'', and restore the register
++ information for this group that we had before trying this
++ last match. */
++ if ((!MATCHED_SOMETHING (reg_info[*p])
++ || just_past_start_mem == p - 1)
++ && (p + 2) < pend)
++ {
++ boolean is_a_jump_n = false;
++
++ p1 = p + 2;
++ mcnt = 0;
++ switch ((re_opcode_t) *p1++)
++ {
++ case jump_n:
++ is_a_jump_n = true;
++ case pop_failure_jump:
++ case maybe_pop_jump:
++ case jump:
++ case dummy_failure_jump:
++ EXTRACT_NUMBER_AND_INCR (mcnt, p1);
++ if (is_a_jump_n)
++ p1 += OFFSET_ADDRESS_SIZE;
++ break;
++
++ default:
++ /* do nothing */ ;
++ }
++ p1 += mcnt;
++
++ /* If the next operation is a jump backwards in the pattern
++ to an on_failure_jump right before the start_memory
++ corresponding to this stop_memory, exit from the loop
++ by forcing a failure after pushing on the stack the
++ on_failure_jump's jump in the pattern, and d. */
++ if (mcnt < 0 && (re_opcode_t) *p1 == on_failure_jump
++ && (re_opcode_t) p1[1+OFFSET_ADDRESS_SIZE] == start_memory
++ && p1[2+OFFSET_ADDRESS_SIZE] == *p)
++ {
++ /* If this group ever matched anything, then restore
++ what its registers were before trying this last
++ failed match, e.g., with `(a*)*b' against `ab' for
++ regstart[1], and, e.g., with `((a*)*(b*)*)*'
++ against `aba' for regend[3].
++
++ Also restore the registers for inner groups for,
++ e.g., `((a*)(b*))*' against `aba' (register 3 would
++ otherwise get trashed). */
++
++ if (EVER_MATCHED_SOMETHING (reg_info[*p]))
++ {
++ unsigned r;
++
++ EVER_MATCHED_SOMETHING (reg_info[*p]) = 0;
++
++ /* Restore this and inner groups' (if any) registers. */
++ for (r = *p; r < (unsigned) *p + (unsigned) *(p + 1);
++ r++)
++ {
++ regstart[r] = old_regstart[r];
++
++ /* xx why this test? */
++ if (old_regend[r] >= regstart[r])
++ regend[r] = old_regend[r];
++ }
++ }
++ p1++;
++ EXTRACT_NUMBER_AND_INCR (mcnt, p1);
++ PUSH_FAILURE_POINT (p1 + mcnt, d, -2);
++
++ goto fail;
++ }
++ }
++
++ /* Move past the register number and the inner group count. */
++ p += 2;
++ break;
++
++
++ /* \<digit> has been turned into a `duplicate' command which is
++ followed by the numeric value of <digit> as the register number. */
++ case duplicate:
++ {
++ register const CHAR_T *d2, *dend2;
++ int regno = *p++; /* Get which register to match against. */
++ DEBUG_PRINT2 ("EXECUTING duplicate %d.\n", regno);
++
++ /* Can't back reference a group which we've never matched. */
++ if (REG_UNSET (regstart[regno]) || REG_UNSET (regend[regno]))
++ goto fail;
++
++ /* Where in input to try to start matching. */
++ d2 = regstart[regno];
++
++ /* Where to stop matching; if both the place to start and
++ the place to stop matching are in the same string, then
++ set to the place to stop, otherwise, for now have to use
++ the end of the first string. */
++
++ dend2 = ((FIRST_STRING_P (regstart[regno])
++ == FIRST_STRING_P (regend[regno]))
++ ? regend[regno] : end_match_1);
++ for (;;)
++ {
++ /* If necessary, advance to next segment in register
++ contents. */
++ while (d2 == dend2)
++ {
++ if (dend2 == end_match_2) break;
++ if (dend2 == regend[regno]) break;
++
++ /* End of string1 => advance to string2. */
++ d2 = string2;
++ dend2 = regend[regno];
++ }
++ /* At end of register contents => success */
++ if (d2 == dend2) break;
++
++ /* If necessary, advance to next segment in data. */
++ PREFETCH ();
++
++ /* How many characters left in this segment to match. */
++ mcnt = dend - d;
++
++ /* Want how many consecutive characters we can match in
++ one shot, so, if necessary, adjust the count. */
++ if (mcnt > dend2 - d2)
++ mcnt = dend2 - d2;
++
++ /* Compare that many; failure if mismatch, else move
++ past them. */
++ if (translate
++ ? PREFIX(bcmp_translate) (d, d2, mcnt, translate)
++ : memcmp (d, d2, mcnt*sizeof(UCHAR_T)))
++ goto fail;
++ d += mcnt, d2 += mcnt;
++
++ /* Do this because we've match some characters. */
++ SET_REGS_MATCHED ();
++ }
++ }
++ break;
++
++
++ /* begline matches the empty string at the beginning of the string
++ (unless `not_bol' is set in `bufp'), and, if
++ `newline_anchor' is set, after newlines. */
++ case begline:
++ DEBUG_PRINT1 ("EXECUTING begline.\n");
++
++ if (AT_STRINGS_BEG (d))
++ {
++ if (!bufp->not_bol) break;
++ }
++ else if (d[-1] == '\n' && bufp->newline_anchor)
++ {
++ break;
++ }
++ /* In all other cases, we fail. */
++ goto fail;
++
++
++ /* endline is the dual of begline. */
++ case endline:
++ DEBUG_PRINT1 ("EXECUTING endline.\n");
++
++ if (AT_STRINGS_END (d))
++ {
++ if (!bufp->not_eol) break;
++ }
++
++ /* We have to ``prefetch'' the next character. */
++ else if ((d == end1 ? *string2 : *d) == '\n'
++ && bufp->newline_anchor)
++ {
++ break;
++ }
++ goto fail;
++
++
++ /* Match at the very beginning of the data. */
++ case begbuf:
++ DEBUG_PRINT1 ("EXECUTING begbuf.\n");
++ if (AT_STRINGS_BEG (d))
++ break;
++ goto fail;
++
++
++ /* Match at the very end of the data. */
++ case endbuf:
++ DEBUG_PRINT1 ("EXECUTING endbuf.\n");
++ if (AT_STRINGS_END (d))
++ break;
++ goto fail;
++
++
++ /* on_failure_keep_string_jump is used to optimize `.*\n'. It
++ pushes NULL as the value for the string on the stack. Then
++ `pop_failure_point' will keep the current value for the
++ string, instead of restoring it. To see why, consider
++ matching `foo\nbar' against `.*\n'. The .* matches the foo;
++ then the . fails against the \n. But the next thing we want
++ to do is match the \n against the \n; if we restored the
++ string value, we would be back at the foo.
++
++ Because this is used only in specific cases, we don't need to
++ check all the things that `on_failure_jump' does, to make
++ sure the right things get saved on the stack. Hence we don't
++ share its code. The only reason to push anything on the
++ stack at all is that otherwise we would have to change
++ `anychar's code to do something besides goto fail in this
++ case; that seems worse than this. */
++ case on_failure_keep_string_jump:
++ DEBUG_PRINT1 ("EXECUTING on_failure_keep_string_jump");
++
++ EXTRACT_NUMBER_AND_INCR (mcnt, p);
++#ifdef _LIBC
++ DEBUG_PRINT3 (" %d (to %p):\n", mcnt, p + mcnt);
++#else
++ DEBUG_PRINT3 (" %d (to 0x%x):\n", mcnt, p + mcnt);
++#endif
++
++ PUSH_FAILURE_POINT (p + mcnt, NULL, -2);
++ break;
++
++
++ /* Uses of on_failure_jump:
++
++ Each alternative starts with an on_failure_jump that points
++ to the beginning of the next alternative. Each alternative
++ except the last ends with a jump that in effect jumps past
++ the rest of the alternatives. (They really jump to the
++ ending jump of the following alternative, because tensioning
++ these jumps is a hassle.)
++
++ Repeats start with an on_failure_jump that points past both
++ the repetition text and either the following jump or
++ pop_failure_jump back to this on_failure_jump. */
++ case on_failure_jump:
++ on_failure:
++ DEBUG_PRINT1 ("EXECUTING on_failure_jump");
++
++ EXTRACT_NUMBER_AND_INCR (mcnt, p);
++#ifdef _LIBC
++ DEBUG_PRINT3 (" %d (to %p)", mcnt, p + mcnt);
++#else
++ DEBUG_PRINT3 (" %d (to 0x%x)", mcnt, p + mcnt);
++#endif
++
++ /* If this on_failure_jump comes right before a group (i.e.,
++ the original * applied to a group), save the information
++ for that group and all inner ones, so that if we fail back
++ to this point, the group's information will be correct.
++ For example, in \(a*\)*\1, we need the preceding group,
++ and in \(zz\(a*\)b*\)\2, we need the inner group. */
++
++ /* We can't use `p' to check ahead because we push
++ a failure point to `p + mcnt' after we do this. */
++ p1 = p;
++
++ /* We need to skip no_op's before we look for the
++ start_memory in case this on_failure_jump is happening as
++ the result of a completed succeed_n, as in \(a\)\{1,3\}b\1
++ against aba. */
++ while (p1 < pend && (re_opcode_t) *p1 == no_op)
++ p1++;
++
++ if (p1 < pend && (re_opcode_t) *p1 == start_memory)
++ {
++ /* We have a new highest active register now. This will
++ get reset at the start_memory we are about to get to,
++ but we will have saved all the registers relevant to
++ this repetition op, as described above. */
++ highest_active_reg = *(p1 + 1) + *(p1 + 2);
++ if (lowest_active_reg == NO_LOWEST_ACTIVE_REG)
++ lowest_active_reg = *(p1 + 1);
++ }
++
++ DEBUG_PRINT1 (":\n");
++ PUSH_FAILURE_POINT (p + mcnt, d, -2);
++ break;
++
++
++ /* A smart repeat ends with `maybe_pop_jump'.
++ We change it to either `pop_failure_jump' or `jump'. */
++ case maybe_pop_jump:
++ EXTRACT_NUMBER_AND_INCR (mcnt, p);
++ DEBUG_PRINT2 ("EXECUTING maybe_pop_jump %d.\n", mcnt);
++ {
++ register UCHAR_T *p2 = p;
++
++ /* Compare the beginning of the repeat with what in the
++ pattern follows its end. If we can establish that there
++ is nothing that they would both match, i.e., that we
++ would have to backtrack because of (as in, e.g., `a*a')
++ then we can change to pop_failure_jump, because we'll
++ never have to backtrack.
++
++ This is not true in the case of alternatives: in
++ `(a|ab)*' we do need to backtrack to the `ab' alternative
++ (e.g., if the string was `ab'). But instead of trying to
++ detect that here, the alternative has put on a dummy
++ failure point which is what we will end up popping. */
++
++ /* Skip over open/close-group commands.
++ If what follows this loop is a ...+ construct,
++ look at what begins its body, since we will have to
++ match at least one of that. */
++ while (1)
++ {
++ if (p2 + 2 < pend
++ && ((re_opcode_t) *p2 == stop_memory
++ || (re_opcode_t) *p2 == start_memory))
++ p2 += 3;
++ else if (p2 + 2 + 2 * OFFSET_ADDRESS_SIZE < pend
++ && (re_opcode_t) *p2 == dummy_failure_jump)
++ p2 += 2 + 2 * OFFSET_ADDRESS_SIZE;
++ else
++ break;
++ }
++
++ p1 = p + mcnt;
++ /* p1[0] ... p1[2] are the `on_failure_jump' corresponding
++ to the `maybe_finalize_jump' of this case. Examine what
++ follows. */
++
++ /* If we're at the end of the pattern, we can change. */
++ if (p2 == pend)
++ {
++ /* Consider what happens when matching ":\(.*\)"
++ against ":/". I don't really understand this code
++ yet. */
++ p[-(1+OFFSET_ADDRESS_SIZE)] = (UCHAR_T)
++ pop_failure_jump;
++ DEBUG_PRINT1
++ (" End of pattern: change to `pop_failure_jump'.\n");
++ }
++
++ else if ((re_opcode_t) *p2 == exactn
++#ifdef MBS_SUPPORT
++ || (re_opcode_t) *p2 == exactn_bin
++#endif
++ || (bufp->newline_anchor && (re_opcode_t) *p2 == endline))
++ {
++ register UCHAR_T c
++ = *p2 == (UCHAR_T) endline ? '\n' : p2[2];
++
++ if (((re_opcode_t) p1[1+OFFSET_ADDRESS_SIZE] == exactn
++#ifdef MBS_SUPPORT
++ || (re_opcode_t) p1[1+OFFSET_ADDRESS_SIZE] == exactn_bin
++#endif
++ ) && p1[3+OFFSET_ADDRESS_SIZE] != c)
++ {
++ p[-(1+OFFSET_ADDRESS_SIZE)] = (UCHAR_T)
++ pop_failure_jump;
++#ifdef WCHAR
++ DEBUG_PRINT3 (" %C != %C => pop_failure_jump.\n",
++ (wint_t) c,
++ (wint_t) p1[3+OFFSET_ADDRESS_SIZE]);
++#else
++ DEBUG_PRINT3 (" %c != %c => pop_failure_jump.\n",
++ (char) c,
++ (char) p1[3+OFFSET_ADDRESS_SIZE]);
++#endif
++ }
++
++#ifndef WCHAR
++ else if ((re_opcode_t) p1[3] == charset
++ || (re_opcode_t) p1[3] == charset_not)
++ {
++ int negate = (re_opcode_t) p1[3] == charset_not;
++
++ if (c < (unsigned) (p1[4] * BYTEWIDTH)
++ && p1[5 + c / BYTEWIDTH] & (1 << (c % BYTEWIDTH)))
++ negate = !negate;
++
++ /* `negate' is equal to 1 if c would match, which means
++ that we can't change to pop_failure_jump. */
++ if (!negate)
++ {
++ p[-3] = (unsigned char) pop_failure_jump;
++ DEBUG_PRINT1 (" No match => pop_failure_jump.\n");
++ }
++ }
++#endif /* not WCHAR */
++ }
++#ifndef WCHAR
++ else if ((re_opcode_t) *p2 == charset)
++ {
++ /* We win if the first character of the loop is not part
++ of the charset. */
++ if ((re_opcode_t) p1[3] == exactn
++ && ! ((int) p2[1] * BYTEWIDTH > (int) p1[5]
++ && (p2[2 + p1[5] / BYTEWIDTH]
++ & (1 << (p1[5] % BYTEWIDTH)))))
++ {
++ p[-3] = (unsigned char) pop_failure_jump;
++ DEBUG_PRINT1 (" No match => pop_failure_jump.\n");
++ }
++
++ else if ((re_opcode_t) p1[3] == charset_not)
++ {
++ int idx;
++ /* We win if the charset_not inside the loop
++ lists every character listed in the charset after. */
++ for (idx = 0; idx < (int) p2[1]; idx++)
++ if (! (p2[2 + idx] == 0
++ || (idx < (int) p1[4]
++ && ((p2[2 + idx] & ~ p1[5 + idx]) == 0))))
++ break;
++
++ if (idx == p2[1])
++ {
++ p[-3] = (unsigned char) pop_failure_jump;
++ DEBUG_PRINT1 (" No match => pop_failure_jump.\n");
++ }
++ }
++ else if ((re_opcode_t) p1[3] == charset)
++ {
++ int idx;
++ /* We win if the charset inside the loop
++ has no overlap with the one after the loop. */
++ for (idx = 0;
++ idx < (int) p2[1] && idx < (int) p1[4];
++ idx++)
++ if ((p2[2 + idx] & p1[5 + idx]) != 0)
++ break;
++
++ if (idx == p2[1] || idx == p1[4])
++ {
++ p[-3] = (unsigned char) pop_failure_jump;
++ DEBUG_PRINT1 (" No match => pop_failure_jump.\n");
++ }
++ }
++ }
++#endif /* not WCHAR */
++ }
++ p -= OFFSET_ADDRESS_SIZE; /* Point at relative address again. */
++ if ((re_opcode_t) p[-1] != pop_failure_jump)
++ {
++ p[-1] = (UCHAR_T) jump;
++ DEBUG_PRINT1 (" Match => jump.\n");
++ goto unconditional_jump;
++ }
++ /* Note fall through. */
++
++
++ /* The end of a simple repeat has a pop_failure_jump back to
++ its matching on_failure_jump, where the latter will push a
++ failure point. The pop_failure_jump takes off failure
++ points put on by this pop_failure_jump's matching
++ on_failure_jump; we got through the pattern to here from the
++ matching on_failure_jump, so didn't fail. */
++ case pop_failure_jump:
++ {
++ /* We need to pass separate storage for the lowest and
++ highest registers, even though we don't care about the
++ actual values. Otherwise, we will restore only one
++ register from the stack, since lowest will == highest in
++ `pop_failure_point'. */
++ active_reg_t dummy_low_reg, dummy_high_reg;
++ UCHAR_T *pdummy = NULL;
++ const CHAR_T *sdummy = NULL;
++
++ DEBUG_PRINT1 ("EXECUTING pop_failure_jump.\n");
++ POP_FAILURE_POINT (sdummy, pdummy,
++ dummy_low_reg, dummy_high_reg,
++ reg_dummy, reg_dummy, reg_info_dummy);
++ }
++ /* Note fall through. */
++
++ unconditional_jump:
++#ifdef _LIBC
++ DEBUG_PRINT2 ("\n%p: ", p);
++#else
++ DEBUG_PRINT2 ("\n0x%x: ", p);
++#endif
++ /* Note fall through. */
++
++ /* Unconditionally jump (without popping any failure points). */
++ case jump:
++ EXTRACT_NUMBER_AND_INCR (mcnt, p); /* Get the amount to jump. */
++ DEBUG_PRINT2 ("EXECUTING jump %d ", mcnt);
++ p += mcnt; /* Do the jump. */
++#ifdef _LIBC
++ DEBUG_PRINT2 ("(to %p).\n", p);
++#else
++ DEBUG_PRINT2 ("(to 0x%x).\n", p);
++#endif
++ break;
++
++
++ /* We need this opcode so we can detect where alternatives end
++ in `group_match_null_string_p' et al. */
++ case jump_past_alt:
++ DEBUG_PRINT1 ("EXECUTING jump_past_alt.\n");
++ goto unconditional_jump;
++
++
++ /* Normally, the on_failure_jump pushes a failure point, which
++ then gets popped at pop_failure_jump. We will end up at
++ pop_failure_jump, also, and with a pattern of, say, `a+', we
++ are skipping over the on_failure_jump, so we have to push
++ something meaningless for pop_failure_jump to pop. */
++ case dummy_failure_jump:
++ DEBUG_PRINT1 ("EXECUTING dummy_failure_jump.\n");
++ /* It doesn't matter what we push for the string here. What
++ the code at `fail' tests is the value for the pattern. */
++ PUSH_FAILURE_POINT (NULL, NULL, -2);
++ goto unconditional_jump;
++
++
++ /* At the end of an alternative, we need to push a dummy failure
++ point in case we are followed by a `pop_failure_jump', because
++ we don't want the failure point for the alternative to be
++ popped. For example, matching `(a|ab)*' against `aab'
++ requires that we match the `ab' alternative. */
++ case push_dummy_failure:
++ DEBUG_PRINT1 ("EXECUTING push_dummy_failure.\n");
++ /* See comments just above at `dummy_failure_jump' about the
++ two zeroes. */
++ PUSH_FAILURE_POINT (NULL, NULL, -2);
++ break;
++
++ /* Have to succeed matching what follows at least n times.
++ After that, handle like `on_failure_jump'. */
++ case succeed_n:
++ EXTRACT_NUMBER (mcnt, p + OFFSET_ADDRESS_SIZE);
++ DEBUG_PRINT2 ("EXECUTING succeed_n %d.\n", mcnt);
++
++ assert (mcnt >= 0);
++ /* Originally, this is how many times we HAVE to succeed. */
++ if (mcnt > 0)
++ {
++ mcnt--;
++ p += OFFSET_ADDRESS_SIZE;
++ STORE_NUMBER_AND_INCR (p, mcnt);
++#ifdef _LIBC
++ DEBUG_PRINT3 (" Setting %p to %d.\n", p - OFFSET_ADDRESS_SIZE
++ , mcnt);
++#else
++ DEBUG_PRINT3 (" Setting 0x%x to %d.\n", p - OFFSET_ADDRESS_SIZE
++ , mcnt);
++#endif
++ }
++ else if (mcnt == 0)
++ {
++#ifdef _LIBC
++ DEBUG_PRINT2 (" Setting two bytes from %p to no_op.\n",
++ p + OFFSET_ADDRESS_SIZE);
++#else
++ DEBUG_PRINT2 (" Setting two bytes from 0x%x to no_op.\n",
++ p + OFFSET_ADDRESS_SIZE);
++#endif /* _LIBC */
++
++#ifdef WCHAR
++ p[1] = (UCHAR_T) no_op;
++#else
++ p[2] = (UCHAR_T) no_op;
++ p[3] = (UCHAR_T) no_op;
++#endif /* WCHAR */
++ goto on_failure;
++ }
++ break;
++
++ case jump_n:
++ EXTRACT_NUMBER (mcnt, p + OFFSET_ADDRESS_SIZE);
++ DEBUG_PRINT2 ("EXECUTING jump_n %d.\n", mcnt);
++
++ /* Originally, this is how many times we CAN jump. */
++ if (mcnt)
++ {
++ mcnt--;
++ STORE_NUMBER (p + OFFSET_ADDRESS_SIZE, mcnt);
++
++#ifdef _LIBC
++ DEBUG_PRINT3 (" Setting %p to %d.\n", p + OFFSET_ADDRESS_SIZE,
++ mcnt);
++#else
++ DEBUG_PRINT3 (" Setting 0x%x to %d.\n", p + OFFSET_ADDRESS_SIZE,
++ mcnt);
++#endif /* _LIBC */
++ goto unconditional_jump;
++ }
++ /* If don't have to jump any more, skip over the rest of command. */
++ else
++ p += 2 * OFFSET_ADDRESS_SIZE;
++ break;
++
++ case set_number_at:
++ {
++ DEBUG_PRINT1 ("EXECUTING set_number_at.\n");
++
++ EXTRACT_NUMBER_AND_INCR (mcnt, p);
++ p1 = p + mcnt;
++ EXTRACT_NUMBER_AND_INCR (mcnt, p);
++#ifdef _LIBC
++ DEBUG_PRINT3 (" Setting %p to %d.\n", p1, mcnt);
++#else
++ DEBUG_PRINT3 (" Setting 0x%x to %d.\n", p1, mcnt);
++#endif
++ STORE_NUMBER (p1, mcnt);
++ break;
++ }
++
++#if 0
++ /* The DEC Alpha C compiler 3.x generates incorrect code for the
++ test WORDCHAR_P (d - 1) != WORDCHAR_P (d) in the expansion of
++ AT_WORD_BOUNDARY, so this code is disabled. Expanding the
++ macro and introducing temporary variables works around the bug. */
++
++ case wordbound:
++ DEBUG_PRINT1 ("EXECUTING wordbound.\n");
++ if (AT_WORD_BOUNDARY (d))
++ break;
++ goto fail;
++
++ case notwordbound:
++ DEBUG_PRINT1 ("EXECUTING notwordbound.\n");
++ if (AT_WORD_BOUNDARY (d))
++ goto fail;
++ break;
++#else
++ case wordbound:
++ {
++ boolean prevchar, thischar;
++
++ DEBUG_PRINT1 ("EXECUTING wordbound.\n");
++ if (AT_STRINGS_BEG (d) || AT_STRINGS_END (d))
++ break;
++
++ prevchar = WORDCHAR_P (d - 1);
++ thischar = WORDCHAR_P (d);
++ if (prevchar != thischar)
++ break;
++ goto fail;
++ }
++
++ case notwordbound:
++ {
++ boolean prevchar, thischar;
++
++ DEBUG_PRINT1 ("EXECUTING notwordbound.\n");
++ if (AT_STRINGS_BEG (d) || AT_STRINGS_END (d))
++ goto fail;
++
++ prevchar = WORDCHAR_P (d - 1);
++ thischar = WORDCHAR_P (d);
++ if (prevchar != thischar)
++ goto fail;
++ break;
++ }
++#endif
++
++ case wordbeg:
++ DEBUG_PRINT1 ("EXECUTING wordbeg.\n");
++ if (!AT_STRINGS_END (d) && WORDCHAR_P (d)
++ && (AT_STRINGS_BEG (d) || !WORDCHAR_P (d - 1)))
++ break;
++ goto fail;
++
++ case wordend:
++ DEBUG_PRINT1 ("EXECUTING wordend.\n");
++ if (!AT_STRINGS_BEG (d) && WORDCHAR_P (d - 1)
++ && (AT_STRINGS_END (d) || !WORDCHAR_P (d)))
++ break;
++ goto fail;
++
++#ifdef emacs
++ case before_dot:
++ DEBUG_PRINT1 ("EXECUTING before_dot.\n");
++ if (PTR_CHAR_POS ((unsigned char *) d) >= point)
++ goto fail;
++ break;
++
++ case at_dot:
++ DEBUG_PRINT1 ("EXECUTING at_dot.\n");
++ if (PTR_CHAR_POS ((unsigned char *) d) != point)
++ goto fail;
++ break;
++
++ case after_dot:
++ DEBUG_PRINT1 ("EXECUTING after_dot.\n");
++ if (PTR_CHAR_POS ((unsigned char *) d) <= point)
++ goto fail;
++ break;
++
++ case syntaxspec:
++ DEBUG_PRINT2 ("EXECUTING syntaxspec %d.\n", mcnt);
++ mcnt = *p++;
++ goto matchsyntax;
++
++ case wordchar:
++ DEBUG_PRINT1 ("EXECUTING Emacs wordchar.\n");
++ mcnt = (int) Sword;
++ matchsyntax:
++ PREFETCH ();
++ /* Can't use *d++ here; SYNTAX may be an unsafe macro. */
++ d++;
++ if (SYNTAX (d[-1]) != (enum syntaxcode) mcnt)
++ goto fail;
++ SET_REGS_MATCHED ();
++ break;
++
++ case notsyntaxspec:
++ DEBUG_PRINT2 ("EXECUTING notsyntaxspec %d.\n", mcnt);
++ mcnt = *p++;
++ goto matchnotsyntax;
++
++ case notwordchar:
++ DEBUG_PRINT1 ("EXECUTING Emacs notwordchar.\n");
++ mcnt = (int) Sword;
++ matchnotsyntax:
++ PREFETCH ();
++ /* Can't use *d++ here; SYNTAX may be an unsafe macro. */
++ d++;
++ if (SYNTAX (d[-1]) == (enum syntaxcode) mcnt)
++ goto fail;
++ SET_REGS_MATCHED ();
++ break;
++
++#else /* not emacs */
++ case wordchar:
++ DEBUG_PRINT1 ("EXECUTING non-Emacs wordchar.\n");
++ PREFETCH ();
++ if (!WORDCHAR_P (d))
++ goto fail;
++ SET_REGS_MATCHED ();
++ d++;
++ break;
++
++ case notwordchar:
++ DEBUG_PRINT1 ("EXECUTING non-Emacs notwordchar.\n");
++ PREFETCH ();
++ if (WORDCHAR_P (d))
++ goto fail;
++ SET_REGS_MATCHED ();
++ d++;
++ break;
++#endif /* not emacs */
++
++ default:
++ abort ();
++ }
++ continue; /* Successfully executed one pattern command; keep going. */
++
++
++ /* We goto here if a matching operation fails. */
++ fail:
++ if (!FAIL_STACK_EMPTY ())
++ { /* A restart point is known. Restore to that state. */
++ DEBUG_PRINT1 ("\nFAIL:\n");
++ POP_FAILURE_POINT (d, p,
++ lowest_active_reg, highest_active_reg,
++ regstart, regend, reg_info);
++
++ /* If this failure point is a dummy, try the next one. */
++ if (!p)
++ goto fail;
++
++ /* If we failed to the end of the pattern, don't examine *p. */
++ assert (p <= pend);
++ if (p < pend)
++ {
++ boolean is_a_jump_n = false;
++
++ /* If failed to a backwards jump that's part of a repetition
++ loop, need to pop this failure point and use the next one. */
++ switch ((re_opcode_t) *p)
++ {
++ case jump_n:
++ is_a_jump_n = true;
++ case maybe_pop_jump:
++ case pop_failure_jump:
++ case jump:
++ p1 = p + 1;
++ EXTRACT_NUMBER_AND_INCR (mcnt, p1);
++ p1 += mcnt;
++
++ if ((is_a_jump_n && (re_opcode_t) *p1 == succeed_n)
++ || (!is_a_jump_n
++ && (re_opcode_t) *p1 == on_failure_jump))
++ goto fail;
++ break;
++ default:
++ /* do nothing */ ;
++ }
++ }
++
++ if (d >= string1 && d <= end1)
++ dend = end_match_1;
++ }
++ else
++ break; /* Matching at this starting point really fails. */
++ } /* for (;;) */
++
++ if (best_regs_set)
++ goto restore_best_regs;
++
++ FREE_VARIABLES ();
++
++ return -1; /* Failure to match. */
++} /* re_match_2 */
++
++/* Subroutine definitions for re_match_2. */
++
++
++/* We are passed P pointing to a register number after a start_memory.
++
++ Return true if the pattern up to the corresponding stop_memory can
++ match the empty string, and false otherwise.
++
++ If we find the matching stop_memory, sets P to point to one past its number.
++ Otherwise, sets P to an undefined byte less than or equal to END.
++
++ We don't handle duplicates properly (yet). */
++
++static boolean
++PREFIX(group_match_null_string_p) (UCHAR_T **p, UCHAR_T *end,
++ PREFIX(register_info_type) *reg_info)
++{
++ int mcnt;
++ /* Point to after the args to the start_memory. */
++ UCHAR_T *p1 = *p + 2;
++
++ while (p1 < end)
++ {
++ /* Skip over opcodes that can match nothing, and return true or
++ false, as appropriate, when we get to one that can't, or to the
++ matching stop_memory. */
++
++ switch ((re_opcode_t) *p1)
++ {
++ /* Could be either a loop or a series of alternatives. */
++ case on_failure_jump:
++ p1++;
++ EXTRACT_NUMBER_AND_INCR (mcnt, p1);
++
++ /* If the next operation is not a jump backwards in the
++ pattern. */
++
++ if (mcnt >= 0)
++ {
++ /* Go through the on_failure_jumps of the alternatives,
++ seeing if any of the alternatives cannot match nothing.
++ The last alternative starts with only a jump,
++ whereas the rest start with on_failure_jump and end
++ with a jump, e.g., here is the pattern for `a|b|c':
++
++ /on_failure_jump/0/6/exactn/1/a/jump_past_alt/0/6
++ /on_failure_jump/0/6/exactn/1/b/jump_past_alt/0/3
++ /exactn/1/c
++
++ So, we have to first go through the first (n-1)
++ alternatives and then deal with the last one separately. */
++
++
++ /* Deal with the first (n-1) alternatives, which start
++ with an on_failure_jump (see above) that jumps to right
++ past a jump_past_alt. */
++
++ while ((re_opcode_t) p1[mcnt-(1+OFFSET_ADDRESS_SIZE)] ==
++ jump_past_alt)
++ {
++ /* `mcnt' holds how many bytes long the alternative
++ is, including the ending `jump_past_alt' and
++ its number. */
++
++ if (!PREFIX(alt_match_null_string_p) (p1, p1 + mcnt -
++ (1 + OFFSET_ADDRESS_SIZE),
++ reg_info))
++ return false;
++
++ /* Move to right after this alternative, including the
++ jump_past_alt. */
++ p1 += mcnt;
++
++ /* Break if it's the beginning of an n-th alternative
++ that doesn't begin with an on_failure_jump. */
++ if ((re_opcode_t) *p1 != on_failure_jump)
++ break;
++
++ /* Still have to check that it's not an n-th
++ alternative that starts with an on_failure_jump. */
++ p1++;
++ EXTRACT_NUMBER_AND_INCR (mcnt, p1);
++ if ((re_opcode_t) p1[mcnt-(1+OFFSET_ADDRESS_SIZE)] !=
++ jump_past_alt)
++ {
++ /* Get to the beginning of the n-th alternative. */
++ p1 -= 1 + OFFSET_ADDRESS_SIZE;
++ break;
++ }
++ }
++
++ /* Deal with the last alternative: go back and get number
++ of the `jump_past_alt' just before it. `mcnt' contains
++ the length of the alternative. */
++ EXTRACT_NUMBER (mcnt, p1 - OFFSET_ADDRESS_SIZE);
++
++ if (!PREFIX(alt_match_null_string_p) (p1, p1 + mcnt, reg_info))
++ return false;
++
++ p1 += mcnt; /* Get past the n-th alternative. */
++ } /* if mcnt > 0 */
++ break;
++
++
++ case stop_memory:
++ assert (p1[1] == **p);
++ *p = p1 + 2;
++ return true;
++
++
++ default:
++ if (!PREFIX(common_op_match_null_string_p) (&p1, end, reg_info))
++ return false;
++ }
++ } /* while p1 < end */
++
++ return false;
++} /* group_match_null_string_p */
++
++
++/* Similar to group_match_null_string_p, but doesn't deal with alternatives:
++ It expects P to be the first byte of a single alternative and END one
++ byte past the last. The alternative can contain groups. */
++
++static boolean
++PREFIX(alt_match_null_string_p) (UCHAR_T *p, UCHAR_T *end,
++ PREFIX(register_info_type) *reg_info)
++{
++ int mcnt;
++ UCHAR_T *p1 = p;
++
++ while (p1 < end)
++ {
++ /* Skip over opcodes that can match nothing, and break when we get
++ to one that can't. */
++
++ switch ((re_opcode_t) *p1)
++ {
++ /* It's a loop. */
++ case on_failure_jump:
++ p1++;
++ EXTRACT_NUMBER_AND_INCR (mcnt, p1);
++ p1 += mcnt;
++ break;
++
++ default:
++ if (!PREFIX(common_op_match_null_string_p) (&p1, end, reg_info))
++ return false;
++ }
++ } /* while p1 < end */
++
++ return true;
++} /* alt_match_null_string_p */
++
++
++/* Deals with the ops common to group_match_null_string_p and
++ alt_match_null_string_p.
++
++ Sets P to one after the op and its arguments, if any. */
++
++static boolean
++PREFIX(common_op_match_null_string_p) (UCHAR_T **p, UCHAR_T *end,
++ PREFIX(register_info_type) *reg_info)
++{
++ int mcnt;
++ boolean ret;
++ int reg_no;
++ UCHAR_T *p1 = *p;
++
++ switch ((re_opcode_t) *p1++)
++ {
++ case no_op:
++ case begline:
++ case endline:
++ case begbuf:
++ case endbuf:
++ case wordbeg:
++ case wordend:
++ case wordbound:
++ case notwordbound:
++#ifdef emacs
++ case before_dot:
++ case at_dot:
++ case after_dot:
++#endif
++ break;
++
++ case start_memory:
++ reg_no = *p1;
++ assert (reg_no > 0 && reg_no <= MAX_REGNUM);
++ ret = PREFIX(group_match_null_string_p) (&p1, end, reg_info);
++
++ /* Have to set this here in case we're checking a group which
++ contains a group and a back reference to it. */
++
++ if (REG_MATCH_NULL_STRING_P (reg_info[reg_no]) == MATCH_NULL_UNSET_VALUE)
++ REG_MATCH_NULL_STRING_P (reg_info[reg_no]) = ret;
++
++ if (!ret)
++ return false;
++ break;
++
++ /* If this is an optimized succeed_n for zero times, make the jump. */
++ case jump:
++ EXTRACT_NUMBER_AND_INCR (mcnt, p1);
++ if (mcnt >= 0)
++ p1 += mcnt;
++ else
++ return false;
++ break;
++
++ case succeed_n:
++ /* Get to the number of times to succeed. */
++ p1 += OFFSET_ADDRESS_SIZE;
++ EXTRACT_NUMBER_AND_INCR (mcnt, p1);
++
++ if (mcnt == 0)
++ {
++ p1 -= 2 * OFFSET_ADDRESS_SIZE;
++ EXTRACT_NUMBER_AND_INCR (mcnt, p1);
++ p1 += mcnt;
++ }
++ else
++ return false;
++ break;
++
++ case duplicate:
++ if (!REG_MATCH_NULL_STRING_P (reg_info[*p1]))
++ return false;
++ break;
++
++ case set_number_at:
++ p1 += 2 * OFFSET_ADDRESS_SIZE;
++
++ default:
++ /* All other opcodes mean we cannot match the empty string. */
++ return false;
++ }
++
++ *p = p1;
++ return true;
++} /* common_op_match_null_string_p */
++
++
++/* Return zero if TRANSLATE[S1] and TRANSLATE[S2] are identical for LEN
++ bytes; nonzero otherwise. */
++
++static int
++PREFIX(bcmp_translate) (const CHAR_T *s1, const CHAR_T *s2, register int len,
++ RE_TRANSLATE_TYPE translate)
++{
++ register const UCHAR_T *p1 = (const UCHAR_T *) s1;
++ register const UCHAR_T *p2 = (const UCHAR_T *) s2;
++ while (len)
++ {
++#ifdef WCHAR
++ if (((*p1<=0xff)?translate[*p1++]:*p1++)
++ != ((*p2<=0xff)?translate[*p2++]:*p2++))
++ return 1;
++#else /* BYTE */
++ if (translate[*p1++] != translate[*p2++]) return 1;
++#endif /* WCHAR */
++ len--;
++ }
++ return 0;
++}
++
++
++#else /* not INSIDE_RECURSION */
++
++/* Entry points for GNU code. */
++
++/* re_compile_pattern is the GNU regular expression compiler: it
++ compiles PATTERN (of length SIZE) and puts the result in BUFP.
++ Returns 0 if the pattern was valid, otherwise an error string.
++
++ Assumes the `allocated' (and perhaps `buffer') and `translate' fields
++ are set in BUFP on entry.
++
++ We call regex_compile to do the actual compilation. */
++
++const char *
++re_compile_pattern (const char *pattern, size_t length,
++ struct re_pattern_buffer *bufp)
++{
++ reg_errcode_t ret;
++
++ /* GNU code is written to assume at least RE_NREGS registers will be set
++ (and at least one extra will be -1). */
++ bufp->regs_allocated = REGS_UNALLOCATED;
++
++ /* And GNU code determines whether or not to get register information
++ by passing null for the REGS argument to re_match, etc., not by
++ setting no_sub. */
++ bufp->no_sub = 0;
++
++ /* Match anchors at newline. */
++ bufp->newline_anchor = 1;
++
++# ifdef MBS_SUPPORT
++ if (MB_CUR_MAX != 1)
++ ret = wcs_regex_compile (pattern, length, re_syntax_options, bufp);
++ else
++# endif
++ ret = byte_regex_compile (pattern, length, re_syntax_options, bufp);
++
++ if (!ret)
++ return NULL;
++ return gettext (re_error_msgid[(int) ret]);
++}
++#ifdef _LIBC
++weak_alias (__re_compile_pattern, re_compile_pattern)
++#endif
++
++/* Entry points compatible with 4.2 BSD regex library. We don't define
++ them unless specifically requested. */
++
++#if defined _REGEX_RE_COMP || defined _LIBC
++
++/* BSD has one and only one pattern buffer. */
++static struct re_pattern_buffer re_comp_buf;
++
++char *
++#ifdef _LIBC
++/* Make these definitions weak in libc, so POSIX programs can redefine
++ these names if they don't use our functions, and still use
++ regcomp/regexec below without link errors. */
++weak_function
++#endif
++re_comp (const char *s)
++{
++ reg_errcode_t ret;
++
++ if (!s)
++ {
++ if (!re_comp_buf.buffer)
++ return (char *) gettext ("No previous regular expression");
++ return 0;
++ }
++
++ if (!re_comp_buf.buffer)
++ {
++ re_comp_buf.buffer = (unsigned char *) malloc (200);
++ if (re_comp_buf.buffer == NULL)
++ return (char *) gettext (re_error_msgid[(int) REG_ESPACE]);
++ re_comp_buf.allocated = 200;
++
++ re_comp_buf.fastmap = (char *) malloc (1 << BYTEWIDTH);
++ if (re_comp_buf.fastmap == NULL)
++ return (char *) gettext (re_error_msgid[(int) REG_ESPACE]);
++ }
++
++ /* Since `re_exec' always passes NULL for the `regs' argument, we
++ don't need to initialize the pattern buffer fields which affect it. */
++
++ /* Match anchors at newlines. */
++ re_comp_buf.newline_anchor = 1;
++
++# ifdef MBS_SUPPORT
++ if (MB_CUR_MAX != 1)
++ ret = wcs_regex_compile (s, strlen (s), re_syntax_options, &re_comp_buf);
++ else
++# endif
++ ret = byte_regex_compile (s, strlen (s), re_syntax_options, &re_comp_buf);
++
++ if (!ret)
++ return NULL;
++
++ /* Yes, we're discarding `const' here if !HAVE_LIBINTL. */
++ return (char *) gettext (re_error_msgid[(int) ret]);
++}
++
++
++int
++#ifdef _LIBC
++weak_function
++#endif
++re_exec (const char *s)
++{
++ const int len = strlen (s);
++ return
++ 0 <= re_search (&re_comp_buf, s, len, 0, len, (struct re_registers *) 0);
++}
++
++#endif /* _REGEX_RE_COMP */
++
++/* POSIX.2 functions. Don't define these for Emacs. */
++
++#ifndef emacs
++
++/* regcomp takes a regular expression as a string and compiles it.
++
++ PREG is a regex_t *. We do not expect any fields to be initialized,
++ since POSIX says we shouldn't. Thus, we set
++
++ `buffer' to the compiled pattern;
++ `used' to the length of the compiled pattern;
++ `syntax' to RE_SYNTAX_POSIX_EXTENDED if the
++ REG_EXTENDED bit in CFLAGS is set; otherwise, to
++ RE_SYNTAX_POSIX_BASIC;
++ `newline_anchor' to REG_NEWLINE being set in CFLAGS;
++ `fastmap' to an allocated space for the fastmap;
++ `fastmap_accurate' to zero;
++ `re_nsub' to the number of subexpressions in PATTERN.
++
++ PATTERN is the address of the pattern string.
++
++ CFLAGS is a series of bits which affect compilation.
++
++ If REG_EXTENDED is set, we use POSIX extended syntax; otherwise, we
++ use POSIX basic syntax.
++
++ If REG_NEWLINE is set, then . and [^...] don't match newline.
++ Also, regexec will try a match beginning after every newline.
++
++ If REG_ICASE is set, then we considers upper- and lowercase
++ versions of letters to be equivalent when matching.
++
++ If REG_NOSUB is set, then when PREG is passed to regexec, that
++ routine will report only success or failure, and nothing about the
++ registers.
++
++ It returns 0 if it succeeds, nonzero if it doesn't. (See regex.h for
++ the return codes and their meanings.) */
++
++int
++regcomp (regex_t *preg, const char *pattern, int cflags)
++{
++ reg_errcode_t ret;
++ reg_syntax_t syntax
++ = (cflags & REG_EXTENDED) ?
++ RE_SYNTAX_POSIX_EXTENDED : RE_SYNTAX_POSIX_BASIC;
++
++ /* regex_compile will allocate the space for the compiled pattern. */
++ preg->buffer = 0;
++ preg->allocated = 0;
++ preg->used = 0;
++
++ /* Try to allocate space for the fastmap. */
++ preg->fastmap = (char *) malloc (1 << BYTEWIDTH);
++
++ if (cflags & REG_ICASE)
++ {
++ int i;
++
++ preg->translate
++ = (RE_TRANSLATE_TYPE) malloc (CHAR_SET_SIZE
++ * sizeof (*(RE_TRANSLATE_TYPE)0));
++ if (preg->translate == NULL)
++ return (int) REG_ESPACE;
++
++ /* Map uppercase characters to corresponding lowercase ones. */
++ for (i = 0; i < CHAR_SET_SIZE; i++)
++ preg->translate[i] = ISUPPER (i) ? TOLOWER (i) : i;
++ }
++ else
++ preg->translate = NULL;
++
++ /* If REG_NEWLINE is set, newlines are treated differently. */
++ if (cflags & REG_NEWLINE)
++ { /* REG_NEWLINE implies neither . nor [^...] match newline. */
++ syntax &= ~RE_DOT_NEWLINE;
++ syntax |= RE_HAT_LISTS_NOT_NEWLINE;
++ /* It also changes the matching behavior. */
++ preg->newline_anchor = 1;
++ }
++ else
++ preg->newline_anchor = 0;
++
++ preg->no_sub = !!(cflags & REG_NOSUB);
++
++ /* POSIX says a null character in the pattern terminates it, so we
++ can use strlen here in compiling the pattern. */
++# ifdef MBS_SUPPORT
++ if (MB_CUR_MAX != 1)
++ ret = wcs_regex_compile (pattern, strlen (pattern), syntax, preg);
++ else
++# endif
++ ret = byte_regex_compile (pattern, strlen (pattern), syntax, preg);
++
++ /* POSIX doesn't distinguish between an unmatched open-group and an
++ unmatched close-group: both are REG_EPAREN. */
++ if (ret == REG_ERPAREN) ret = REG_EPAREN;
++
++ if (ret == REG_NOERROR && preg->fastmap)
++ {
++ /* Compute the fastmap now, since regexec cannot modify the pattern
++ buffer. */
++ if (re_compile_fastmap (preg) == -2)
++ {
++ /* Some error occurred while computing the fastmap, just forget
++ about it. */
++ free (preg->fastmap);
++ preg->fastmap = NULL;
++ }
++ }
++
++ return (int) ret;
++}
++#ifdef _LIBC
++weak_alias (__regcomp, regcomp)
++#endif
++
++
++/* regexec searches for a given pattern, specified by PREG, in the
++ string STRING.
++
++ If NMATCH is zero or REG_NOSUB was set in the cflags argument to
++ `regcomp', we ignore PMATCH. Otherwise, we assume PMATCH has at
++ least NMATCH elements, and we set them to the offsets of the
++ corresponding matched substrings.
++
++ EFLAGS specifies `execution flags' which affect matching: if
++ REG_NOTBOL is set, then ^ does not match at the beginning of the
++ string; if REG_NOTEOL is set, then $ does not match at the end.
++
++ We return 0 if we find a match and REG_NOMATCH if not. */
++
++int
++regexec (const regex_t *preg, const char *string, size_t nmatch,
++ regmatch_t pmatch[], int eflags)
++{
++ int ret;
++ struct re_registers regs;
++ regex_t private_preg;
++ int len = strlen (string);
++ boolean want_reg_info = !preg->no_sub && nmatch > 0;
++
++ private_preg = *preg;
++
++ private_preg.not_bol = !!(eflags & REG_NOTBOL);
++ private_preg.not_eol = !!(eflags & REG_NOTEOL);
++
++ /* The user has told us exactly how many registers to return
++ information about, via `nmatch'. We have to pass that on to the
++ matching routines. */
++ private_preg.regs_allocated = REGS_FIXED;
++
++ if (want_reg_info)
++ {
++ regs.num_regs = nmatch;
++ regs.start = TALLOC (nmatch * 2, regoff_t);
++ if (regs.start == NULL)
++ return (int) REG_NOMATCH;
++ regs.end = regs.start + nmatch;
++ }
++
++ /* Perform the searching operation. */
++ ret = re_search (&private_preg, string, len,
++ /* start: */ 0, /* range: */ len,
++ want_reg_info ? ®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 -Naur glibc-2.20/pwd/Makefile glibc-2.20-patch/pwd/Makefile
+--- glibc-2.20/pwd/Makefile 2014-09-07 03:09:09.000000000 -0500
++++ glibc-2.20-patch/pwd/Makefile 2015-03-04 00:51:32.416952006 -0600
+@@ -18,6 +18,8 @@
+ #
+ # Sub-makefile for pwd portion of the library.
+ #
++include ../option-groups.mak
++
+ subdir := pwd
+
+ include ../Makeconfig
+diff -Naur glibc-2.20/resolv/Makefile glibc-2.20-patch/resolv/Makefile
+--- glibc-2.20/resolv/Makefile 2014-09-07 03:09:09.000000000 -0500
++++ glibc-2.20-patch/resolv/Makefile 2015-03-04 00:51:32.416952006 -0600
+@@ -18,6 +18,8 @@
+ #
+ # Sub-makefile for resolv portion of the library.
+ #
++include ../option-groups.mak
++
+ subdir := resolv
+
+ include ../Makeconfig
+@@ -27,20 +29,21 @@
+ arpa/nameser.h arpa/nameser_compat.h \
+ sys/bitypes.h
+
+-routines := herror inet_addr inet_ntop inet_pton nsap_addr res_init \
+- res_hconf res_libc res-state
++routines-$(OPTION_EGLIBC_INET) \
++ += herror inet_addr inet_ntop inet_pton nsap_addr res_init \
++ res_hconf res_libc res-state
+
+-tests = tst-aton tst-leaks tst-inet_ntop
+-xtests = tst-leaks2
++tests-$(OPTION_EGLIBC_INET) += tst-aton tst-leaks tst-inet_ntop
++xtests-$(OPTION_EGLIBC_INET) += tst-leaks2
+
+ generate := mtrace-tst-leaks.out tst-leaks.mtrace tst-leaks2.mtrace
+
+-extra-libs := libresolv libnss_dns
++extra-libs-$(OPTION_EGLIBC_INET) += libresolv libnss_dns
+ ifeq ($(have-thread-library),yes)
+-extra-libs += libanl
+-routines += gai_sigqueue
++extra-libs-$(OPTION_EGLIBC_INET_ANL) += libanl
++routines-$(OPTION_EGLIBC_INET) += gai_sigqueue
+ endif
+-extra-libs-others = $(extra-libs)
++extra-libs-others-y += $(extra-libs-y)
+ libresolv-routines := gethnamaddr res_comp res_debug \
+ res_data res_mkquery res_query res_send \
+ inet_net_ntop inet_net_pton inet_neta base64 \
+@@ -60,7 +63,7 @@
+ static-only-routines += $(libnss_dns-routines) $(libresolv-routines)
+ endif
+
+-ifeq (yesyes,$(build-shared)$(have-thread-library))
++ifeq (yesyesy,$(build-shared)$(have-thread-library)$(OPTION_EGLIBC_INET_ANL))
+ tests: $(objpfx)ga_test
+ endif
+
+diff -Naur glibc-2.20/stdio-common/fxprintf.c glibc-2.20-patch/stdio-common/fxprintf.c
+--- glibc-2.20/stdio-common/fxprintf.c 2014-09-07 03:09:09.000000000 -0500
++++ glibc-2.20-patch/stdio-common/fxprintf.c 2015-03-04 00:51:32.416952006 -0600
+@@ -23,6 +23,7 @@
+ #include <wchar.h>
+ #include <string.h>
+ #include <libioP.h>
++#include <gnu/option-groups.h>
+
+
+ int
+@@ -37,6 +38,7 @@
+ int res;
+ if (_IO_fwide (fp, 0) > 0)
+ {
++#if __OPTION_POSIX_WIDE_CHAR_DEVICE_IO
+ size_t len = strlen (fmt) + 1;
+ wchar_t wfmt[len];
+ for (size_t i = 0; i < len; ++i)
+@@ -45,6 +47,9 @@
+ wfmt[i] = fmt[i];
+ }
+ res = __vfwprintf (fp, wfmt, ap);
++#else
++ abort();
++#endif
+ }
+ else
+ res = _IO_vfprintf (fp, fmt, ap);
+diff -Naur glibc-2.20/stdio-common/_i18n_number.h glibc-2.20-patch/stdio-common/_i18n_number.h
+--- glibc-2.20/stdio-common/_i18n_number.h 2014-09-07 03:09:09.000000000 -0500
++++ glibc-2.20-patch/stdio-common/_i18n_number.h 2015-03-04 00:51:32.417952006 -0600
+@@ -19,10 +19,13 @@
+ #include <stdbool.h>
+ #include <wchar.h>
+ #include <wctype.h>
++#include <gnu/option-groups.h>
+
+ #include "../locale/outdigits.h"
+ #include "../locale/outdigitswc.h"
+
++#if __OPTION_EGLIBC_LOCALE_CODE
++
+ static CHAR_T *
+ _i18n_number_rewrite (CHAR_T *w, CHAR_T *rear_ptr, CHAR_T *end)
+ {
+@@ -115,3 +118,13 @@
+
+ return w;
+ }
++
++#else
++
++static CHAR_T *
++_i18n_number_rewrite (CHAR_T *w, CHAR_T *rear_ptr, CHAR_T *end)
++{
++ return w;
++}
++
++#endif
+diff -Naur glibc-2.20/stdio-common/Makefile glibc-2.20-patch/stdio-common/Makefile
+--- glibc-2.20/stdio-common/Makefile 2014-09-07 03:09:09.000000000 -0500
++++ glibc-2.20-patch/stdio-common/Makefile 2015-03-04 00:51:32.417952006 -0600
+@@ -18,6 +18,8 @@
+ #
+ # Specific makefile for stdio-common.
+ #
++include ../option-groups.mak
++
+ subdir := stdio-common
+
+ include ../Makeconfig
+@@ -30,7 +32,7 @@
+ vfprintf vprintf printf_fp reg-printf printf-prs printf_fphex \
+ reg-modifier reg-type \
+ printf_size fprintf printf snprintf sprintf asprintf dprintf \
+- vfwprintf vfscanf vfwscanf \
++ vfscanf \
+ fscanf scanf sscanf \
+ perror psignal \
+ tmpfile tmpfile64 tmpnam tmpnam_r tempnam tempname \
+@@ -41,23 +43,37 @@
+ isoc99_vsscanf \
+ psiginfo
+
+-aux := errlist siglist printf-parsemb printf-parsewc fxprintf
++# Ideally, _itowa and itowa-digits would be in this option group as
++# well, but it is used unconditionally by printf_fp and printf_fphex,
++# and it didn't seem straightforward to disentangle it.
++routines-$(OPTION_POSIX_C_LANG_WIDE_CHAR) += \
++ vfwprintf vfwscanf
++
++aux := errlist siglist printf-parsemb fxprintf
++aux-$(OPTION_POSIX_C_LANG_WIDE_CHAR) += printf-parsewc
+
+ tests := tstscanf test_rdwr test-popen tstgetln test-fseek \
+ temptest tst-fileno test-fwrite tst-ungetc tst-ferror \
+ xbug errnobug \
+ bug1 bug2 bug3 bug4 bug5 bug6 bug7 bug8 bug9 bug10 bug11 bug12 bug13 \
+- tfformat tiformat tllformat tstdiomisc tst-printfsz tst-wc-printf \
++ tfformat tiformat tllformat tstdiomisc tst-printfsz \
+ scanf1 scanf2 scanf3 scanf4 scanf5 scanf7 scanf8 scanf9 scanf10 \
+- scanf11 scanf12 tst-tmpnam tst-cookie tst-obprintf tst-sscanf \
+- tst-swprintf tst-fseek tst-fmemopen test-vfprintf tst-gets \
+- tst-perror tst-sprintf tst-rndseek tst-fdopen tst-fphex bug14 \
++ scanf11 scanf12 tst-tmpnam tst-cookie tst-obprintf \
++ scanf11 scanf12 tst-tmpnam tst-cookie tst-obprintf \
++ tst-fseek tst-fmemopen tst-gets \
++ tst-sprintf tst-rndseek tst-fdopen tst-fphex \
+ tst-popen tst-unlockedio tst-fmemopen2 tst-put-error tst-fgets \
+- tst-fwrite bug16 bug17 tst-swscanf tst-sprintf2 bug18 bug18a \
+- bug19 bug19a tst-popen2 scanf13 scanf14 scanf15 bug20 bug21 bug22 \
+- scanf16 scanf17 tst-setvbuf1 tst-grouping bug23 bug24 \
+- bug-vfprintf-nargs tst-long-dbl-fphex tst-fphex-wide tst-sprintf3 \
+- bug25 tst-printf-round bug26
++ tst-fwrite bug16 bug17 tst-sprintf2 bug18 \
++ bug19 tst-popen2 scanf14 scanf15 bug21 bug22 scanf16 scanf17 \
++ tst-setvbuf1 bug23 bug24 bug-vfprintf-nargs tst-sprintf3 bug25 \
++ tst-printf-round bug26
++
++tests-$(OPTION_EGLIBC_LOCALE_CODE) \
++ += tst-sscanf tst-swprintf test-vfprintf bug14 scanf13 tst-grouping
++tests-$(OPTION_POSIX_WIDE_CHAR_DEVICE_IO) \
++ += tst-perror bug19a bug20 tst-long-dbl-fphex tst-fphex-wide
++tests-$(OPTION_POSIX_C_LANG_WIDE_CHAR) \
++ += bug18a tst-swscanf tst-wc-printf
+
+ test-srcs = tst-unbputc tst-printf
+
+diff -Naur glibc-2.20/stdio-common/printf_fp.c glibc-2.20-patch/stdio-common/printf_fp.c
+--- glibc-2.20/stdio-common/printf_fp.c 2014-09-07 03:09:09.000000000 -0500
++++ glibc-2.20-patch/stdio-common/printf_fp.c 2015-03-04 00:51:32.417952006 -0600
+@@ -39,6 +39,7 @@
+ #include <unistd.h>
+ #include <stdlib.h>
+ #include <wchar.h>
++#include <gnu/option-groups.h>
+ #include <stdbool.h>
+ #include <rounding-mode.h>
+
+@@ -148,6 +149,10 @@
+ wchar_t thousands_sep, int ngroups)
+ internal_function;
+
++/* Ideally, when OPTION_EGLIBC_LOCALE_CODE is disabled, this should do
++ all its work in ordinary characters, rather than doing it in wide
++ characters and then converting at the end. But that is a challenge
++ for another day. */
+
+ int
+ ___printf_fp (FILE *fp,
+@@ -206,7 +211,14 @@
+ mp_limb_t cy;
+
+ /* Nonzero if this is output on a wide character stream. */
++#if __OPTION_POSIX_C_LANG_WIDE_CHAR
+ int wide = info->wide;
++#else
++ /* This should never be called on a wide-oriented stream when
++ OPTION_POSIX_C_LANG_WIDE_CHAR is disabled, but the compiler can't
++ be trusted to figure that out. */
++ const int wide = 0;
++#endif
+
+ /* Buffer in which we produce the output. */
+ wchar_t *wbuffer = NULL;
+@@ -258,6 +270,7 @@
+
+
+ /* Figure out the decimal point character. */
++#if __OPTION_EGLIBC_LOCALE_CODE
+ if (info->extra == 0)
+ {
+ decimal = _NL_CURRENT (LC_NUMERIC, DECIMAL_POINT);
+@@ -277,7 +290,13 @@
+ /* The decimal point character must not be zero. */
+ assert (*decimal != '\0');
+ assert (decimalwc != L'\0');
++#else
++ /* Hard-code values from 'C' locale. */
++ decimal = ".";
++ decimalwc = L'.';
++#endif
+
++#if __OPTION_EGLIBC_LOCALE_CODE
+ if (info->group)
+ {
+ if (info->extra == 0)
+@@ -321,6 +340,9 @@
+ }
+ else
+ grouping = NULL;
++#else
++ grouping = NULL;
++#endif
+
+ /* Fetch the argument value. */
+ #ifndef __NO_LONG_DOUBLE_MATH
+diff -Naur glibc-2.20/stdio-common/printf_fphex.c glibc-2.20-patch/stdio-common/printf_fphex.c
+--- glibc-2.20/stdio-common/printf_fphex.c 2014-09-07 03:09:09.000000000 -0500
++++ glibc-2.20-patch/stdio-common/printf_fphex.c 2015-03-04 00:51:32.418952006 -0600
+@@ -28,6 +28,7 @@
+ #include <_itoa.h>
+ #include <_itowa.h>
+ #include <locale/localeinfo.h>
++#include <gnu/option-groups.h>
+ #include <stdbool.h>
+ #include <rounding-mode.h>
+
+@@ -139,10 +140,18 @@
+ int done = 0;
+
+ /* Nonzero if this is output on a wide character stream. */
++#if __OPTION_POSIX_C_LANG_WIDE_CHAR
+ int wide = info->wide;
++#else
++ /* This should never be called on a wide-oriented stream when
++ OPTION_POSIX_C_LANG_WIDE_CHAR is disabled, but the compiler can't
++ be trusted to figure that out. */
++ const int wide = 0;
++#endif
+
+
+ /* Figure out the decimal point character. */
++#if __OPTION_EGLIBC_LOCALE_CODE
+ if (info->extra == 0)
+ {
+ decimal = _NL_CURRENT (LC_NUMERIC, DECIMAL_POINT);
+@@ -156,6 +165,10 @@
+ }
+ /* The decimal point character must never be zero. */
+ assert (*decimal != '\0' && decimalwc != L'\0');
++#else
++ decimal = ".";
++ decimalwc = L'.';
++#endif
+
+
+ /* Fetch the argument value. */
+diff -Naur glibc-2.20/stdio-common/printf_size.c glibc-2.20-patch/stdio-common/printf_size.c
+--- glibc-2.20/stdio-common/printf_size.c 2014-09-07 03:09:09.000000000 -0500
++++ glibc-2.20-patch/stdio-common/printf_size.c 2015-03-04 00:51:32.418952006 -0600
+@@ -23,6 +23,7 @@
+ #include <math.h>
+ #include <printf.h>
+ #include <libioP.h>
++#include <gnu/option-groups.h>
+
+
+ /* This defines make it possible to use the same code for GNU C library and
+@@ -116,7 +117,14 @@
+
+ struct printf_info fp_info;
+ int done = 0;
++#if __OPTION_POSIX_C_LANG_WIDE_CHAR
+ int wide = info->wide;
++#else
++ /* This should never be called on a wide-oriented stream when
++ OPTION_POSIX_C_LANG_WIDE_CHAR is disabled, but the compiler can't
++ be trusted to figure that out. */
++ const int wide = 0;
++#endif
+ int res;
+
+ /* Fetch the argument value. */
+diff -Naur glibc-2.20/stdio-common/scanf14.c glibc-2.20-patch/stdio-common/scanf14.c
+--- glibc-2.20/stdio-common/scanf14.c 2014-09-07 03:09:09.000000000 -0500
++++ glibc-2.20-patch/stdio-common/scanf14.c 2015-03-04 00:51:32.418952006 -0600
+@@ -2,6 +2,7 @@
+ #include <stdlib.h>
+ #include <string.h>
+ #include <wchar.h>
++#include <gnu/option-groups.h>
+
+ #define FAIL() \
+ do { \
+@@ -36,6 +37,7 @@
+ FAIL ();
+ else if (d != 2.25 || memcmp (c, " x", 2) != 0)
+ FAIL ();
++#if __OPTION_EGLIBC_LOCALE_CODE
+ if (sscanf (" 3.25S x", "%4aS%3c", &lsp, c) != 2)
+ FAIL ();
+ else
+@@ -45,6 +47,7 @@
+ memset (lsp, 'x', sizeof L"3.25");
+ free (lsp);
+ }
++#endif
+ if (sscanf ("4.25[0-9.] x", "%a[0-9.]%8c", &sp, c) != 2)
+ FAIL ();
+ else
+diff -Naur glibc-2.20/stdio-common/tstdiomisc.c glibc-2.20-patch/stdio-common/tstdiomisc.c
+--- glibc-2.20/stdio-common/tstdiomisc.c 2014-09-07 03:09:09.000000000 -0500
++++ glibc-2.20-patch/stdio-common/tstdiomisc.c 2015-03-04 00:51:32.418952006 -0600
+@@ -3,6 +3,7 @@
+ #include <stdio.h>
+ #include <string.h>
+ #include <wchar.h>
++#include <gnu/option-groups.h>
+
+ static int
+ t1 (void)
+@@ -125,6 +126,7 @@
+ printf ("expected \"-inf -INF -inf -INF -inf -INF -inf -INF\", got \"%s\"\n",
+ buf);
+
++#if __OPTION_POSIX_C_LANG_WIDE_CHAR
+ swprintf (wbuf, sizeof wbuf / sizeof (wbuf[0]), L"%a %A %e %E %f %F %g %G",
+ qnanval, qnanval, qnanval, qnanval,
+ qnanval, qnanval, qnanval, qnanval);
+@@ -162,6 +164,7 @@
+ result |= wcscmp (wbuf, L"-inf -INF -inf -INF -inf -INF -inf -INF") != 0;
+ printf ("expected L\"-inf -INF -inf -INF -inf -INF -inf -INF\", got L\"%S\"\n",
+ wbuf);
++#endif /* __OPTION_POSIX_C_LANG_WIDE_CHAR */
+
+ lqnanval = NAN;
+
+@@ -206,6 +209,7 @@
+ printf ("expected \"-inf -INF -inf -INF -inf -INF -inf -INF\", got \"%s\"\n",
+ buf);
+
++#if __OPTION_POSIX_C_LANG_WIDE_CHAR
+ swprintf (wbuf, sizeof wbuf / sizeof (wbuf[0]),
+ L"%La %LA %Le %LE %Lf %LF %Lg %LG",
+ lqnanval, lqnanval, lqnanval, lqnanval,
+@@ -250,6 +254,7 @@
+ result |= wcscmp (wbuf, L"-inf -INF -inf -INF -inf -INF -inf -INF") != 0;
+ printf ("expected L\"-inf -INF -inf -INF -inf -INF -inf -INF\", got L\"%S\"\n",
+ wbuf);
++#endif /* __OPTION_POSIX_C_LANG_WIDE_CHAR */
+
+ return result;
+ }
+diff -Naur glibc-2.20/stdio-common/tst-popen.c glibc-2.20-patch/stdio-common/tst-popen.c
+--- glibc-2.20/stdio-common/tst-popen.c 2014-09-07 03:09:09.000000000 -0500
++++ glibc-2.20-patch/stdio-common/tst-popen.c 2015-03-04 00:51:32.419952006 -0600
+@@ -19,6 +19,7 @@
+ #include <stdio.h>
+ #include <string.h>
+ #include <wchar.h>
++#include <gnu/option-groups.h>
+
+ static int
+ do_test (void)
+@@ -34,12 +35,14 @@
+ return 1;
+ }
+
++#if __OPTION_POSIX_WIDE_CHAR_DEVICE_IO
+ /* POSIX says that pipe streams are byte-oriented. */
+ if (fwide (f, 0) >= 0)
+ {
+ puts ("popen did not return byte-oriented stream");
+ result = 1;
+ }
++#endif
+
+ if (getline (&line, &len, f) != 5)
+ {
+diff -Naur glibc-2.20/stdio-common/tst-sprintf.c glibc-2.20-patch/stdio-common/tst-sprintf.c
+--- glibc-2.20/stdio-common/tst-sprintf.c 2014-09-07 03:09:09.000000000 -0500
++++ glibc-2.20-patch/stdio-common/tst-sprintf.c 2015-03-04 00:51:32.419952006 -0600
+@@ -2,6 +2,7 @@
+ #include <stdlib.h>
+ #include <locale.h>
+ #include <string.h>
++#include <gnu/option-groups.h>
+
+
+ int
+@@ -10,12 +11,14 @@
+ char buf[100];
+ int result = 0;
+
++#if __OPTION_POSIX_C_LANG_WIDE_CHAR
+ if (sprintf (buf, "%.0ls", L"foo") != 0
+ || strlen (buf) != 0)
+ {
+ puts ("sprintf (buf, \"%.0ls\", L\"foo\") produced some output");
+ result = 1;
+ }
++#endif /* __OPTION_POSIX_C_LANG_WIDE_CHAR */
+
+ #define SIZE (1024*70000)
+ #define STR(x) #x
+diff -Naur glibc-2.20/stdio-common/vfprintf.c glibc-2.20-patch/stdio-common/vfprintf.c
+--- glibc-2.20/stdio-common/vfprintf.c 2014-09-07 03:09:09.000000000 -0500
++++ glibc-2.20-patch/stdio-common/vfprintf.c 2015-03-04 00:51:32.419952006 -0600
+@@ -29,6 +29,7 @@
+ #include <_itoa.h>
+ #include <locale/localeinfo.h>
+ #include <stdio.h>
++#include <gnu/option-groups.h>
+
+ /* This code is shared between the standard stdio implementation found
+ in GNU C library and the libio implementation originally found in
+@@ -138,6 +139,18 @@
+ # define EOF WEOF
+ #endif
+
++#if __OPTION_POSIX_C_LANG_WIDE_CHAR
++# define MULTIBYTE_SUPPORT (1)
++#else
++# define MULTIBYTE_SUPPORT (0)
++#endif
++
++#if __OPTION_EGLIBC_LOCALE_CODE
++# define LOCALE_SUPPORT (1)
++#else
++# define LOCALE_SUPPORT (0)
++#endif
++
+ #include "_i18n_number.h"
+
+ /* Include the shared code for parsing the format string. */
+@@ -1123,8 +1136,11 @@
+ # define process_string_arg(fspec) \
+ LABEL (form_character): \
+ /* Character. */ \
+- if (is_long) \
+- goto LABEL (form_wcharacter); \
++ if (is_long) \
++ { \
++ assert (MULTIBYTE_SUPPORT); \
++ goto LABEL (form_wcharacter); \
++ } \
+ --width; /* Account for the character itself. */ \
+ if (!left) \
+ PAD (' '); \
+@@ -1137,6 +1153,7 @@
+ break; \
+ \
+ LABEL (form_wcharacter): \
++ assert (MULTIBYTE_SUPPORT); \
+ { \
+ /* Wide character. */ \
+ char buf[MB_CUR_MAX]; \
+@@ -1203,6 +1220,7 @@
+ } \
+ else \
+ { \
++ assert (MULTIBYTE_SUPPORT); \
+ const wchar_t *s2 = (const wchar_t *) string; \
+ mbstate_t mbstate; \
+ \
+@@ -1403,7 +1421,9 @@
+ LABEL (flag_quote):
+ group = 1;
+
+- if (grouping == (const char *) -1)
++ if (! LOCALE_SUPPORT)
++ grouping = NULL;
++ else if (grouping == (const char *) -1)
+ {
+ #ifdef COMPILE_WPRINTF
+ thousands_sep = _NL_CURRENT_WORD (LC_NUMERIC,
+@@ -1702,7 +1722,9 @@
+ free (workstart);
+ workstart = NULL;
+
+- if (grouping == (const char *) -1)
++ if (! LOCALE_SUPPORT)
++ grouping = NULL;
++ else if (grouping == (const char *) -1)
+ {
+ #ifdef COMPILE_WPRINTF
+ thousands_sep = _NL_CURRENT_WORD (LC_NUMERIC,
+diff -Naur glibc-2.20/stdio-common/vfscanf.c glibc-2.20-patch/stdio-common/vfscanf.c
+--- glibc-2.20/stdio-common/vfscanf.c 2014-09-07 03:09:09.000000000 -0500
++++ glibc-2.20-patch/stdio-common/vfscanf.c 2015-03-04 00:51:32.420952006 -0600
+@@ -29,6 +29,7 @@
+ #include <wctype.h>
+ #include <bits/libc-lock.h>
+ #include <locale/localeinfo.h>
++#include <gnu/option-groups.h>
+
+ #ifdef __GNUC__
+ # define HAVE_LONGLONG
+@@ -133,6 +134,12 @@
+ # define WINT_T int
+ #endif
+
++#if __OPTION_POSIX_C_LANG_WIDE_CHAR
++# define MULTIBYTE_SUPPORT (1)
++#else
++# define MULTIBYTE_SUPPORT (0)
++#endif
++
+ #define encode_error() do { \
+ errval = 4; \
+ __set_errno (EILSEQ); \
+@@ -316,24 +323,35 @@
+ ARGCHECK (s, format);
+
+ {
+-#ifndef COMPILE_WSCANF
++#if __OPTION_EGLIBC_LOCALE_CODE && !defined (COMPILE_WSCANF)
+ struct __locale_data *const curnumeric = loc->__locales[LC_NUMERIC];
+ #endif
+
++#if __OPTION_EGLIBC_LOCALE_CODE
+ /* Figure out the decimal point character. */
+-#ifdef COMPILE_WSCANF
++# ifdef COMPILE_WSCANF
+ decimal = _NL_CURRENT_WORD (LC_NUMERIC, _NL_NUMERIC_DECIMAL_POINT_WC);
+-#else
++# else
+ decimal = curnumeric->values[_NL_ITEM_INDEX (DECIMAL_POINT)].string;
+-#endif
++# endif
+ /* Figure out the thousands separator character. */
+-#ifdef COMPILE_WSCANF
++# ifdef COMPILE_WSCANF
+ thousands = _NL_CURRENT_WORD (LC_NUMERIC, _NL_NUMERIC_THOUSANDS_SEP_WC);
+-#else
++# else
+ thousands = curnumeric->values[_NL_ITEM_INDEX (THOUSANDS_SEP)].string;
+ if (*thousands == '\0')
+ thousands = NULL;
+-#endif
++# endif
++#else /* if ! __OPTION_EGLIBC_LOCALE_CODE */
++ /* Hard-code values from the C locale. */
++# ifdef COMPILE_WSCANF
++ decimal = L'.';
++ thousands = L'\0';
++# else
++ decimal = ".";
++ thousands = NULL;
++# endif
++#endif /* __OPTION_EGLIBC_LOCALE_CODE */
+ }
+
+ /* Lock the stream. */
+@@ -385,6 +403,8 @@
+ #ifndef COMPILE_WSCANF
+ if (!isascii ((unsigned char) *f))
+ {
++ assert (MULTIBYTE_SUPPORT);
++
+ /* Non-ASCII, may be a multibyte. */
+ int len = __mbrlen (f, strlen (f), &state);
+ if (len > 0)
+@@ -830,6 +850,8 @@
+ }
+ /* FALLTHROUGH */
+ case L_('C'):
++ assert (MULTIBYTE_SUPPORT);
++
+ if (width == -1)
+ width = 1;
+
+@@ -1172,6 +1194,8 @@
+ /* FALLTHROUGH */
+
+ case L_('S'):
++ assert (MULTIBYTE_SUPPORT);
++
+ {
+ #ifndef COMPILE_WSCANF
+ mbstate_t cstate;
+@@ -1419,10 +1443,17 @@
+ const char *mbdigits[10];
+ const char *mbdigits_extended[10];
+ #endif
++#if __OPTION_EGLIBC_LOCALE_CODE
+ /* "to_inpunct" is a map from ASCII digits to their
+ equivalent in locale. This is defined for locales
+ which use an extra digits set. */
+ wctrans_t map = __wctrans ("to_inpunct");
++#else
++ /* This will always be the case when
++ OPTION_EGLIBC_LOCALE_CODE is disabled, but the
++ compiler can't figure that out. */
++ wctrans_t map = NULL;
++#endif
+ int n;
+
+ from_level = 0;
+@@ -2088,6 +2119,7 @@
+ --width;
+ }
+
++#if __OPTION_EGLIBC_LOCALE_CODE
+ wctrans_t map;
+ if (__builtin_expect ((flags & I18N) != 0, 0)
+ /* Hexadecimal floats make no sense, fixing localized
+@@ -2304,6 +2336,7 @@
+ ;
+ #endif
+ }
++#endif /* __OPTION_EGLIBC_LOCALE_CODE */
+
+ /* Have we read any character? If we try to read a number
+ in hexadecimal notation and we have read only the `0x'
+@@ -2343,7 +2376,10 @@
+
+ case L_('['): /* Character class. */
+ if (flags & LONG)
+- STRING_ARG (wstr, wchar_t, 100);
++ {
++ assert (MULTIBYTE_SUPPORT);
++ STRING_ARG (wstr, wchar_t, 100);
++ }
+ else
+ STRING_ARG (str, char, 100);
+
+@@ -2417,6 +2453,7 @@
+ if (flags & LONG)
+ {
+ size_t now = read_in;
++ assert (MULTIBYTE_SUPPORT);
+ #ifdef COMPILE_WSCANF
+ if (__glibc_unlikely (inchar () == WEOF))
+ input_error ();
+diff -Naur glibc-2.20/stdlib/Makefile glibc-2.20-patch/stdlib/Makefile
+--- glibc-2.20/stdlib/Makefile 2014-09-07 03:09:09.000000000 -0500
++++ glibc-2.20-patch/stdlib/Makefile 2015-03-04 00:51:32.420952006 -0600
+@@ -18,6 +18,8 @@
+ #
+ # Makefile for stdlib routines
+ #
++include ../option-groups.mak
++
+ subdir := stdlib
+
+ include ../Makeconfig
+@@ -30,7 +32,7 @@
+ alloca.h fmtmsg.h \
+ bits/stdlib-bsearch.h
+
+-routines := \
++routines-y := \
+ atof atoi atol atoll \
+ abort \
+ bsearch qsort msort \
+@@ -39,7 +41,6 @@
+ quick_exit at_quick_exit cxa_at_quick_exit cxa_thread_atexit_impl \
+ abs labs llabs \
+ div ldiv lldiv \
+- mblen mbstowcs mbtowc wcstombs wctomb \
+ random random_r rand rand_r \
+ drand48 erand48 lrand48 nrand48 mrand48 jrand48 \
+ srand48 seed48 lcong48 \
+@@ -52,9 +53,18 @@
+ strtof_l strtod_l strtold_l \
+ system canonicalize \
+ a64l l64a \
+- rpmatch strfmon strfmon_l getsubopt xpg_basename fmtmsg \
+- strtoimax strtoumax wcstoimax wcstoumax \
++ getsubopt xpg_basename \
++ strtoimax strtoumax \
+ getcontext setcontext makecontext swapcontext
++routines-$(OPTION_EGLIBC_LOCALE_CODE) += \
++ strfmon strfmon_l
++routines-$(OPTION_POSIX_C_LANG_WIDE_CHAR) += \
++ mblen mbstowcs mbtowc wcstombs wctomb \
++ wcstoimax wcstoumax
++ifeq (yy,$(OPTION_EGLIBC_LOCALE_CODE)$(OPTION_POSIX_REGEXP))
++routines-y += rpmatch
++endif
++routines-$(OPTION_EGLIBC_FMTMSG) += fmtmsg
+ aux = grouping groupingwc tens_in_limb
+
+ # These routines will be omitted from the libc shared object.
+@@ -62,20 +72,22 @@
+ # linked against when the shared library will be used.
+ static-only-routines = atexit at_quick_exit
+
+-test-srcs := tst-fmtmsg
+-tests := tst-strtol tst-strtod testmb testrand testsort testdiv \
++test-srcs-$(OPTION_EGLIBC_FMTMSG) := tst-fmtmsg
++tests := tst-strtol tst-strtod testrand testsort testdiv \
+ test-canon test-canon2 tst-strtoll tst-environ \
+ tst-xpg-basename tst-random tst-random2 tst-bsearch \
+ tst-limits tst-rand48 bug-strtod tst-setcontext \
+- test-a64l tst-qsort tst-system testmb2 bug-strtod2 \
+- tst-atof1 tst-atof2 tst-strtod2 tst-strtod3 tst-rand48-2 \
+- tst-makecontext tst-strtod4 tst-strtod5 tst-qsort2 \
+- tst-makecontext2 tst-strtod6 tst-unsetenv1 \
+- tst-makecontext3 bug-getcontext bug-fmtmsg1 \
++ test-a64l tst-qsort tst-system bug-strtod2 \
++ tst-atof1 tst-atof2 tst-strtod2 tst-rand48-2 \
++ tst-makecontext tst-qsort2 tst-makecontext2 tst-strtod6 \
++ tst-unsetenv1 tst-makecontext3 bug-getcontext bug-fmtmsg1 \
+ tst-secure-getenv tst-strtod-overflow tst-strtod-round \
+ tst-tininess tst-strtod-underflow tst-tls-atexit
+ tests-static := tst-secure-getenv
+-
++tests-$(OPTION_EGLIBC_LOCALE_CODE) \
++ += tst-strtod3 tst-strtod4 tst-strtod5 testmb2
++tests-$(OPTION_POSIX_C_LANG_WIDE_CHAR) \
++ += testmb
+ modules-names = tst-tls-atexit-lib
+
+ ifeq ($(build-shared),yes)
+@@ -115,8 +127,10 @@
+ tests-special += $(objpfx)isomac.out
+
+ ifeq ($(run-built-tests),yes)
++ifeq (y,$(OPTION_EGLIBC_FMTMSG))
+ tests-special += $(objpfx)tst-fmtmsg.out
+ endif
++endif
+
+ include ../Rules
+
+diff -Naur glibc-2.20/stdlib/strtod_l.c glibc-2.20-patch/stdlib/strtod_l.c
+--- glibc-2.20/stdlib/strtod_l.c 2014-09-07 03:09:09.000000000 -0500
++++ glibc-2.20-patch/stdlib/strtod_l.c 2015-03-04 00:51:32.420952006 -0600
+@@ -17,6 +17,7 @@
+ License along with the GNU C Library; if not, see
+ <http://www.gnu.org/licenses/>. */
+
++#include <gnu/option-groups.h>
+ #include <xlocale.h>
+
+ extern double ____strtod_l_internal (const char *, char **, int, __locale_t);
+@@ -548,6 +549,7 @@
+ /* Used in several places. */
+ int cnt;
+
++#if __OPTION_EGLIBC_LOCALE_CODE
+ struct __locale_data *current = loc->__locales[LC_NUMERIC];
+
+ if (__glibc_unlikely (group))
+@@ -586,6 +588,17 @@
+ decimal_len = strlen (decimal);
+ assert (decimal_len > 0);
+ #endif
++#else /* if ! __OPTION_EGLIBC_LOCALE_CODE */
++ /* Hard-code values from the 'C' locale. */
++ grouping = NULL;
++#ifdef USE_WIDE_CHAR
++ decimal = L'.';
++# define decimal_len 1
++#else
++ decimal = ".";
++ decimal_len = 1;
++#endif
++#endif /* __OPTION_EGLIBC_LOCALE_CODE */
+
+ /* Prepare number representation. */
+ exponent = 0;
+diff -Naur glibc-2.20/stdlib/tst-strtod.c glibc-2.20-patch/stdlib/tst-strtod.c
+--- glibc-2.20/stdlib/tst-strtod.c 2014-09-07 03:09:09.000000000 -0500
++++ glibc-2.20-patch/stdlib/tst-strtod.c 2015-03-04 00:51:32.420952006 -0600
+@@ -23,6 +23,7 @@
+ #include <errno.h>
+ #include <string.h>
+ #include <math.h>
++#include <gnu/option-groups.h>
+
+ struct ltest
+ {
+@@ -176,7 +177,9 @@
+
+ status |= long_dbl ();
+
++#if __OPTION_EGLIBC_LOCALE_CODE
+ status |= locale_test ();
++#endif
+
+ return status ? EXIT_FAILURE : EXIT_SUCCESS;
+ }
+@@ -219,6 +222,7 @@
+ return 0;
+ }
+
++#if __OPTION_EGLIBC_LOCALE_CODE
+ /* Perform a few tests in a locale with thousands separators. */
+ static int
+ locale_test (void)
+@@ -276,3 +280,4 @@
+
+ return result;
+ }
++#endif /* __OPTION_EGLIBC_LOCALE_CODE */
+diff -Naur glibc-2.20/streams/Makefile glibc-2.20-patch/streams/Makefile
+--- glibc-2.20/streams/Makefile 2014-09-07 03:09:09.000000000 -0500
++++ glibc-2.20-patch/streams/Makefile 2015-03-04 00:51:32.421952006 -0600
+@@ -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 -Naur glibc-2.20/string/Makefile glibc-2.20-patch/string/Makefile
+--- glibc-2.20/string/Makefile 2014-09-07 03:09:09.000000000 -0500
++++ glibc-2.20-patch/string/Makefile 2015-03-04 00:51:32.421952006 -0600
+@@ -18,6 +18,8 @@
+ #
+ # Sub-makefile for string portion of library.
+ #
++include ../option-groups.mak
++
+ subdir := string
+
+ include ../Makeconfig
+@@ -39,10 +41,12 @@
+ $(addprefix argz-,append count create ctsep next \
+ delete extract insert stringify \
+ addsep replace) \
+- envz basename \
++ basename \
+ strcoll_l strxfrm_l string-inlines memrchr \
+ xpg-strerror strerror_l
+
++routines-$(OPTION_EGLIBC_ENVZ) += envz
++
+ strop-tests := memchr memcmp memcpy memmove mempcpy memset memccpy \
+ stpcpy stpncpy strcat strchr strcmp strcpy strcspn \
+ strlen strncmp strncpy strpbrk strrchr strspn memmem \
+@@ -51,10 +55,12 @@
+ tests := tester inl-tester noinl-tester testcopy test-ffs \
+ tst-strlen stratcliff tst-svc tst-inlcall \
+ bug-strncat1 bug-strspn1 bug-strpbrk1 tst-bswap \
+- tst-strtok tst-strxfrm bug-strcoll1 tst-strfry \
++ tst-strtok tst-strfry \
+ bug-strtok1 $(addprefix test-,$(strop-tests)) \
+- bug-envz1 tst-strxfrm2 tst-endian tst-svc2 \
+- tst-strtok_r
++ tst-strxfrm2 tst-endian tst-svc2 tst-strtok_r
++tests-$(OPTION_EGLIBC_ENVZ) += bug-envz1
++tests-$(OPTION_EGLIBC_LOCALE_CODE) \
++ += tst-strxfrm bug-strcoll1
+
+ xtests = tst-strcoll-overflow
+
+diff -Naur glibc-2.20/string/strcoll_l.c glibc-2.20-patch/string/strcoll_l.c
+--- glibc-2.20/string/strcoll_l.c 2014-09-07 03:09:09.000000000 -0500
++++ glibc-2.20-patch/string/strcoll_l.c 2015-03-04 00:51:32.421952006 -0600
+@@ -25,6 +25,7 @@
+ #include <stdlib.h>
+ #include <string.h>
+ #include <sys/param.h>
++#include <gnu/option-groups.h>
+
+ #ifndef STRING_TYPE
+ # define STRING_TYPE char
+@@ -472,7 +473,11 @@
+ STRCOLL (const STRING_TYPE *s1, const STRING_TYPE *s2, __locale_t l)
+ {
+ struct __locale_data *current = l->__locales[LC_COLLATE];
++#if __OPTION_EGLIBC_LOCALE_CODE
+ uint_fast32_t nrules = current->values[_NL_ITEM_INDEX (_NL_COLLATE_NRULES)].word;
++#else
++ const uint_fast32_t nrules = 0;
++#endif
+ /* We don't assign the following values right away since it might be
+ unnecessary in case there are no rules. */
+ const unsigned char *rulesets;
+diff -Naur glibc-2.20/string/strerror_l.c glibc-2.20-patch/string/strerror_l.c
+--- glibc-2.20/string/strerror_l.c 2014-09-07 03:09:09.000000000 -0500
++++ glibc-2.20-patch/string/strerror_l.c 2015-03-04 00:51:32.421952006 -0600
+@@ -21,6 +21,7 @@
+ #include <stdlib.h>
+ #include <string.h>
+ #include <sys/param.h>
++#include <gnu/option-groups.h>
+
+
+ static __thread char *last_value;
+@@ -29,10 +30,14 @@
+ static const char *
+ translate (const char *str, locale_t loc)
+ {
++#if __OPTION_EGLIBC_LOCALE_CODE
+ locale_t oldloc = __uselocale (loc);
+ const char *res = _(str);
+ __uselocale (oldloc);
+ return res;
++#else
++ return str;
++#endif
+ }
+
+
+diff -Naur glibc-2.20/string/strxfrm_l.c glibc-2.20-patch/string/strxfrm_l.c
+--- glibc-2.20/string/strxfrm_l.c 2014-09-07 03:09:09.000000000 -0500
++++ glibc-2.20-patch/string/strxfrm_l.c 2015-03-04 00:51:32.421952006 -0600
+@@ -24,6 +24,7 @@
+ #include <stdlib.h>
+ #include <string.h>
+ #include <sys/param.h>
++#include <gnu/option-groups.h>
+
+ #ifndef STRING_TYPE
+ # define STRING_TYPE char
+@@ -85,7 +86,11 @@
+ STRXFRM (STRING_TYPE *dest, const STRING_TYPE *src, size_t n, __locale_t l)
+ {
+ struct __locale_data *current = l->__locales[LC_COLLATE];
++#if __OPTION_EGLIBC_LOCALE_CODE
+ uint_fast32_t nrules = current->values[_NL_ITEM_INDEX (_NL_COLLATE_NRULES)].word;
++#else
++ const uint_fast32_t nrules = 0;
++#endif
+ /* We don't assign the following values right away since it might be
+ unnecessary in case there are no rules. */
+ const unsigned char *rulesets;
+diff -Naur glibc-2.20/string/test-strcmp.c glibc-2.20-patch/string/test-strcmp.c
+--- glibc-2.20/string/test-strcmp.c 2014-09-07 03:09:09.000000000 -0500
++++ glibc-2.20-patch/string/test-strcmp.c 2015-03-04 00:51:32.422952006 -0600
+@@ -329,34 +329,6 @@
+ FOR_EACH_IMPL (impl, 0)
+ check_result (impl, s1 + i1, s2 + i2, exp_result);
+ }
+-
+- /* Test cases where there are multiple zero bytes after the first. */
+-
+- for (size_t i = 0; i < 16 + 1; i++)
+- {
+- s1[i] = 0x00;
+- s2[i] = 0x00;
+- }
+-
+- for (size_t i = 0; i < 16; i++)
+- {
+- int exp_result;
+-
+- for (int val = 0x01; val < 0x100; val++)
+- {
+- for (size_t j = 0; j < i; j++)
+- {
+- s1[j] = val;
+- s2[j] = val;
+- }
+-
+- s2[i] = val;
+-
+- exp_result = SIMPLE_STRCMP (s1, s2);
+- FOR_EACH_IMPL (impl, 0)
+- check_result (impl, s1, s2, exp_result);
+- }
+- }
+ }
+
+
+diff -Naur glibc-2.20/string/tst-strxfrm2.c glibc-2.20-patch/string/tst-strxfrm2.c
+--- glibc-2.20/string/tst-strxfrm2.c 2014-09-07 03:09:09.000000000 -0500
++++ glibc-2.20-patch/string/tst-strxfrm2.c 2015-03-04 00:51:32.422952006 -0600
+@@ -1,6 +1,7 @@
+ #include <locale.h>
+ #include <stdio.h>
+ #include <string.h>
++#include <gnu/option-groups.h>
+
+ static int
+ do_test (void)
+@@ -38,6 +39,7 @@
+ res = 1;
+ }
+
++#if __OPTION_EGLIBC_LOCALE_CODE
+ if (setlocale (LC_ALL, "de_DE.UTF-8") == NULL)
+ {
+ puts ("setlocale failed");
+@@ -75,6 +77,7 @@
+ res = 1;
+ }
+ }
++#endif
+
+ return res;
+ }
+diff -Naur glibc-2.20/string/tst-strxfrm.c glibc-2.20-patch/string/tst-strxfrm.c
+--- glibc-2.20/string/tst-strxfrm.c 2014-09-07 03:09:09.000000000 -0500
++++ glibc-2.20-patch/string/tst-strxfrm.c 2015-03-04 00:51:32.422952006 -0600
+@@ -3,6 +3,7 @@
+ #include <stdio.h>
+ #include <stdlib.h>
+ #include <string.h>
++#include <gnu/option-groups.h>
+
+
+ char const string[] = "";
+@@ -64,8 +65,10 @@
+ int result = 0;
+
+ result |= test ("C");
++#if __OPTION_EGLIBC_LOCALE_CODE
+ result |= test ("en_US.ISO-8859-1");
+ result |= test ("de_DE.UTF-8");
++#endif
+
+ return result;
+ }
+diff -Naur glibc-2.20/sunrpc/Makefile glibc-2.20-patch/sunrpc/Makefile
+--- glibc-2.20/sunrpc/Makefile 2014-09-07 03:09:09.000000000 -0500
++++ glibc-2.20-patch/sunrpc/Makefile 2015-03-04 00:51:32.422952006 -0600
+@@ -18,6 +18,8 @@
+ #
+ # Sub-makefile for sunrpc portion of the library.
+ #
++include ../option-groups.mak
++
+ subdir := sunrpc
+
+ include ../Makeconfig
+@@ -55,7 +57,6 @@
+ headers-not-in-tirpc = $(addprefix rpc/,key_prot.h rpc_des.h) \
+ $(rpcsvc:%=rpcsvc/%) rpcsvc/bootparam.h
+ headers = rpc/netdb.h
+-install-others = $(inst_sysconfdir)/rpc
+ generated += $(rpcsvc:%.x=rpcsvc/%.h) $(rpcsvc:%.x=x%.c) $(rpcsvc:%.x=x%.stmp) \
+ $(rpcsvc:%.x=rpcsvc/%.stmp) rpcgen
+ generated-dirs += rpcsvc
+@@ -65,18 +66,28 @@
+ endif
+
+ ifeq ($(build-shared),yes)
+-need-export-routines := auth_des auth_unix clnt_gen clnt_perr clnt_tcp \
++need-export-routines-$(OPTION_EGLIBC_SUNRPC) += \
++ auth_des auth_unix clnt_gen clnt_perr clnt_tcp \
+ clnt_udp get_myaddr key_call netname pm_getport \
+- rpc_thread svc svc_tcp svc_udp xcrypt xdr_array xdr \
++ rpc_thread svc svc_tcp svc_udp xdr_array xdr \
+ xdr_intXX_t xdr_mem xdr_ref xdr_sizeof xdr_stdio \
+ svc_run
+
+-routines := auth_none authuxprot bindrsvprt clnt_raw clnt_simp \
++need-export-routines-y += xcrypt
++
++need-export-routines := $(need-export-routines-y)
++
++routines-$(OPTION_EGLIBC_SUNRPC) \
++ += auth_none authuxprot bindrsvprt clnt_raw clnt_simp \
+ rpc_dtable getrpcport pmap_clnt pm_getmaps pmap_prot pmap_prot2 \
+ pmap_rmt rpc_prot rpc_common rpc_cmsg svc_auth svc_authux svc_raw \
+ svc_simple xdr_float xdr_rec publickey authdes_prot \
+- des_crypt des_impl des_soft key_prot openchild rtime svcauth_des \
+- clnt_unix svc_unix create_xid $(need-export-routines)
++ key_prot openchild rtime svcauth_des \
++ clnt_unix svc_unix create_xid
++
++# xdecrypt is also used by nss/nss_files/files-key.c.
++routines-y += des_crypt des_impl des_soft $(need-export-routines)
++
+ ifneq ($(link-obsolete-rpc),yes)
+ # We only add the RPC for compatibility to libc.so.
+ shared-only-routines = $(routines)
+@@ -85,25 +96,28 @@
+
+ # We do not build rpcinfo anymore. It is not needed for a bootstrap
+ # and not wanted on complete systems.
+-# others := rpcinfo
+-# install-sbin := rpcinfo
+-install-bin := rpcgen
++# others-$(OPTION_EGLIBC_SUNRPC) += rpcinfo
++# install-sbin-$(OPTION_EGLIBC_SUNRPC) += rpcinfo
++install-bin-$(OPTION_EGLIBC_SUNRPC) += rpcgen
+ rpcgen-objs = rpc_main.o rpc_hout.o rpc_cout.o rpc_parse.o \
+ rpc_scan.o rpc_util.o rpc_svcout.o rpc_clntout.o \
+ rpc_tblout.o rpc_sample.o
+-extra-objs = $(rpcgen-objs) $(addprefix cross-,$(rpcgen-objs))
+-others += rpcgen
++extra-objs-$(OPTION_EGLIBC_SUNRPC) = $(rpcgen-objs) $(addprefix cross-,$(rpcgen-objs))
++others-$(OPTION_EGLIBC_SUNRPC) += rpcgen
++
++install-others-$(OPTION_EGLIBC_SUNRPC) += $(inst_sysconfdir)/rpc
+
+-tests = tst-xdrmem tst-xdrmem2
+-xtests := tst-getmyaddr
++tests-$(OPTION_EGLIBC_SUNRPC) = tst-xdrmem tst-xdrmem2
++xtests-$(OPTION_EGLIBC_SUNRPC) := tst-getmyaddr
+
+ ifeq ($(have-thread-library),yes)
+-xtests += thrsvc
++xtests-$(OPTION_EGLIBC_SUNRPC) += thrsvc
+ endif
+
+ headers += $(rpcsvc:%.x=rpcsvc/%.h)
+-extra-libs := librpcsvc
+-extra-libs-others := librpcsvc # Make it in `others' pass, not `lib' pass.
++extra-libs-$(OPTION_EGLIBC_SUNRPC) += librpcsvc
++# Make it in `others' pass, not `lib' pass.
++extra-libs-others-y += $(extra-libs-y)
+ librpcsvc-routines = $(rpcsvc:%.x=x%)
+ librpcsvc-inhibit-o = .os # Build no shared rpcsvc library.
+ omit-deps = $(librpcsvc-routines)
+diff -Naur glibc-2.20/sysdeps/arm/Makefile glibc-2.20-patch/sysdeps/arm/Makefile
+--- glibc-2.20/sysdeps/arm/Makefile 2014-09-07 03:09:09.000000000 -0500
++++ glibc-2.20-patch/sysdeps/arm/Makefile 2015-03-04 00:51:32.422952006 -0600
+@@ -37,10 +37,13 @@
+ # get offset to rtld_global._dl_hwcap
+ gen-as-const-headers += rtld-global-offsets.sym tlsdesc.sym
+ aeabi_constants = aeabi_lcsts aeabi_sighandlers aeabi_math
+-aeabi_routines = aeabi_assert aeabi_localeconv aeabi_errno_addr \
++aeabi_routines = aeabi_assert aeabi_errno_addr \
+ aeabi_mb_cur_max aeabi_atexit aeabi_memclr aeabi_memcpy \
+ aeabi_memmove aeabi_memset \
+ aeabi_read_tp libc-aeabi_read_tp
++ifeq (y,$(OPTION_EGLIBC_LOCALE_CODE))
++aeabi_routines += aeabi_localeconv
++endif
+
+ sysdep_routines += $(aeabi_constants) $(aeabi_routines)
+ static-only-routines += $(aeabi_constants) aeabi_read_tp
+diff -Naur glibc-2.20/sysdeps/generic/ldsodefs.h glibc-2.20-patch/sysdeps/generic/ldsodefs.h
+--- glibc-2.20/sysdeps/generic/ldsodefs.h 2014-09-07 03:09:09.000000000 -0500
++++ glibc-2.20-patch/sysdeps/generic/ldsodefs.h 2015-03-04 00:51:32.423952006 -0600
+@@ -425,6 +425,12 @@
+ # undef __rtld_global_attribute__
+ #endif
+
++#if __OPTION_EGLIBC_RTLD_DEBUG
++# define GLRO_dl_debug_mask GLRO(dl_debug_mask)
++#else
++# define GLRO_dl_debug_mask 0
++#endif
++
+ #ifndef SHARED
+ # define GLRO(name) _##name
+ #else
+@@ -437,8 +443,10 @@
+ {
+ #endif
+
++#if __OPTION_EGLIBC_RTLD_DEBUG
+ /* If nonzero the appropriate debug information is printed. */
+ EXTERN int _dl_debug_mask;
++#endif
+ #define DL_DEBUG_LIBS (1 << 0)
+ #define DL_DEBUG_IMPCALLS (1 << 1)
+ #define DL_DEBUG_BINDINGS (1 << 2)
+diff -Naur glibc-2.20/sysdeps/gnu/Makefile glibc-2.20-patch/sysdeps/gnu/Makefile
+--- glibc-2.20/sysdeps/gnu/Makefile 2014-09-07 03:09:09.000000000 -0500
++++ glibc-2.20-patch/sysdeps/gnu/Makefile 2015-03-04 00:51:32.423952006 -0600
+@@ -57,7 +57,8 @@
+ endif
+
+ ifeq ($(subdir),login)
+-sysdep_routines += setutxent getutxent endutxent getutxid getutxline \
++sysdep_routines-$(OPTION_EGLIBC_UTMPX) \
++ += setutxent getutxent endutxent getutxid getutxline \
+ pututxline utmpxname updwtmpx getutmpx getutmp
+
+ sysdep_headers += utmpx.h bits/utmpx.h
+diff -Naur glibc-2.20/sysdeps/ieee754/dbl-64/s_sin.c glibc-2.20-patch/sysdeps/ieee754/dbl-64/s_sin.c
+--- glibc-2.20/sysdeps/ieee754/dbl-64/s_sin.c 2014-09-07 03:09:09.000000000 -0500
++++ glibc-2.20-patch/sysdeps/ieee754/dbl-64/s_sin.c 2015-03-04 00:51:32.423952006 -0600
+@@ -447,21 +447,19 @@
+ }
+ else
+ {
+- double t;
+ if (a > 0)
+ {
+ m = 1;
+- t = a;
+ db = da;
+ }
+ else
+ {
+ m = 0;
+- t = -a;
++ a = -a;
+ db = -da;
+ }
+- u.x = big + t;
+- y = t - (u.x - big);
++ u.x = big + a;
++ y = a - (u.x - big);
+ res = do_sin (u, y, db, &cor);
+ cor = (cor > 0) ? 1.035 * cor + eps : 1.035 * cor - eps;
+ retval = ((res == res + cor) ? ((m) ? res : -res)
+@@ -673,21 +671,19 @@
+ }
+ else
+ {
+- double t;
+ if (a > 0)
+ {
+ m = 1;
+- t = a;
+ db = da;
+ }
+ else
+ {
+ m = 0;
+- t = -a;
++ a = -a;
+ db = -da;
+ }
+- u.x = big + t;
+- y = t - (u.x - big);
++ u.x = big + a;
++ y = a - (u.x - big);
+ res = do_sin (u, y, db, &cor);
+ cor = (cor > 0) ? 1.035 * cor + eps : 1.035 * cor - eps;
+ retval = ((res == res + cor) ? ((m) ? res : -res)
+diff -Naur glibc-2.20/sysdeps/ieee754/ldbl-opt/Makefile glibc-2.20-patch/sysdeps/ieee754/ldbl-opt/Makefile
+--- glibc-2.20/sysdeps/ieee754/ldbl-opt/Makefile 2014-09-07 03:09:09.000000000 -0500
++++ glibc-2.20-patch/sysdeps/ieee754/ldbl-opt/Makefile 2015-03-04 00:51:32.423952006 -0600
+@@ -11,19 +11,18 @@
+ routines += math_ldbl_opt nldbl-compat
+
+ extra-libs += libnldbl
+-libnldbl-calls = asprintf dprintf fprintf fscanf fwprintf fwscanf iovfscanf \
++libnldbl-calls = asprintf dprintf fprintf fscanf iovfscanf \
+ obstack_printf obstack_vprintf printf scanf snprintf \
+- sprintf sscanf swprintf swscanf vasprintf vdprintf vfprintf \
+- vfscanf vfwprintf vfwscanf vprintf vscanf vsnprintf \
+- vsprintf vsscanf vswprintf vswscanf vwprintf vwscanf \
+- wprintf wscanf printf_fp printf_size \
+- fprintf_chk fwprintf_chk printf_chk snprintf_chk sprintf_chk \
+- swprintf_chk vfprintf_chk vfwprintf_chk vprintf_chk \
+- vsnprintf_chk vsprintf_chk vswprintf_chk vwprintf_chk \
+- wprintf_chk asprintf_chk vasprintf_chk dprintf_chk \
++ sprintf sscanf vasprintf vdprintf vfprintf \
++ vfscanf vprintf vscanf vsnprintf \
++ vsprintf vsscanf \
++ printf_fp printf_size \
++ fprintf_chk printf_chk snprintf_chk sprintf_chk \
++ vfprintf_chk vprintf_chk \
++ vsnprintf_chk vsprintf_chk \
++ asprintf_chk vasprintf_chk dprintf_chk \
+ vdprintf_chk obstack_printf_chk obstack_vprintf_chk \
+ syslog syslog_chk vsyslog vsyslog_chk \
+- strfmon strfmon_l \
+ strtold strtold_l strtoldint wcstold wcstold_l wcstoldint \
+ qecvt qfcvt qgcvt qecvt_r qfcvt_r \
+ isinf isnan finite signbit scalb log2 lgamma_r ceil \
+@@ -38,9 +37,15 @@
+ casinh cexp clog cproj csin csinh csqrt ctan ctanh cpow \
+ cabs carg cimag creal clog10 \
+ isoc99_scanf isoc99_fscanf isoc99_sscanf \
+- isoc99_vscanf isoc99_vfscanf isoc99_vsscanf \
++ isoc99_vscanf isoc99_vfscanf isoc99_vsscanf
++libnldbl-calls-$(OPTION_EGLIBC_LOCALE_CODE) += strfmon strfmon_l
++libnldbl-calls-$(OPTION_POSIX_WIDE_CHAR_DEVICE_IO) += fwprintf fwscanf \
++ swprintf swscanf vfwprintf vfwscanf vswprintf vswscanf \
++ vwprintf vwscanf wprintf wscanf fwprintf_chk swprintf_chk \
++ vfwprintf_chk vswprintf_chk vwprintf_chk wprintf_chk \
+ isoc99_wscanf isoc99_fwscanf isoc99_swscanf \
+ isoc99_vwscanf isoc99_vfwscanf isoc99_vswscanf
++libnldbl-calls += $(libnldbl-calls-y)
+ libnldbl-routines = $(libnldbl-calls:%=nldbl-%)
+ libnldbl-inhibit-o = $(object-suffixes)
+ libnldbl-static-only-routines = $(libnldbl-routines)
+diff -Naur glibc-2.20/sysdeps/ieee754/ldbl-opt/nldbl-compat.c glibc-2.20-patch/sysdeps/ieee754/ldbl-opt/nldbl-compat.c
+--- glibc-2.20/sysdeps/ieee754/ldbl-opt/nldbl-compat.c 2014-09-07 03:09:09.000000000 -0500
++++ glibc-2.20-patch/sysdeps/ieee754/ldbl-opt/nldbl-compat.c 2015-03-04 00:51:32.424952006 -0600
+@@ -26,6 +26,7 @@
+ #include <locale/localeinfo.h>
+ #include <sys/syslog.h>
+ #include <bits/libc-lock.h>
++#include <gnu/option-groups.h>
+
+ #include "nldbl-compat.h"
+
+@@ -33,20 +34,14 @@
+ libc_hidden_proto (__nldbl_vsscanf)
+ libc_hidden_proto (__nldbl_vsprintf)
+ libc_hidden_proto (__nldbl_vfscanf)
+-libc_hidden_proto (__nldbl_vfwscanf)
+ libc_hidden_proto (__nldbl_vdprintf)
+-libc_hidden_proto (__nldbl_vswscanf)
+-libc_hidden_proto (__nldbl_vfwprintf)
+-libc_hidden_proto (__nldbl_vswprintf)
+ libc_hidden_proto (__nldbl_vsnprintf)
+ libc_hidden_proto (__nldbl_vasprintf)
+ libc_hidden_proto (__nldbl_obstack_vprintf)
+-libc_hidden_proto (__nldbl___vfwprintf_chk)
+ libc_hidden_proto (__nldbl___vsnprintf_chk)
+ libc_hidden_proto (__nldbl___vfprintf_chk)
+ libc_hidden_proto (__nldbl___vsyslog_chk)
+ libc_hidden_proto (__nldbl___vsprintf_chk)
+-libc_hidden_proto (__nldbl___vswprintf_chk)
+ libc_hidden_proto (__nldbl___vasprintf_chk)
+ libc_hidden_proto (__nldbl___vdprintf_chk)
+ libc_hidden_proto (__nldbl___obstack_vprintf_chk)
+@@ -54,8 +49,17 @@
+ libc_hidden_proto (__nldbl___vstrfmon_l)
+ libc_hidden_proto (__nldbl___isoc99_vsscanf)
+ libc_hidden_proto (__nldbl___isoc99_vfscanf)
++
++#ifdef __OPTION_POSIX_WIDE_CHAR_DEVICE_IO
++libc_hidden_proto (__nldbl_vfwscanf)
++libc_hidden_proto (__nldbl_vswscanf)
++libc_hidden_proto (__nldbl_vfwprintf)
++libc_hidden_proto (__nldbl_vswprintf)
++libc_hidden_proto (__nldbl___vfwprintf_chk)
++libc_hidden_proto (__nldbl___vswprintf_chk)
+ libc_hidden_proto (__nldbl___isoc99_vswscanf)
+ libc_hidden_proto (__nldbl___isoc99_vfwscanf)
++#endif
+
+ static void
+ __nldbl_cleanup (void *arg)
+@@ -117,6 +121,7 @@
+ }
+ weak_alias (__nldbl_fprintf, __nldbl__IO_fprintf)
+
++#ifdef __OPTION_POSIX_WIDE_CHAR_DEVICE_IO
+ int
+ attribute_compat_text_section weak_function
+ __nldbl_fwprintf (FILE *stream, const wchar_t *fmt, ...)
+@@ -130,6 +135,7 @@
+
+ return done;
+ }
++#endif
+
+ int
+ attribute_compat_text_section
+@@ -226,6 +232,7 @@
+ return done;
+ }
+
++#ifdef __OPTION_POSIX_WIDE_CHAR_DEVICE_IO
+ int
+ attribute_compat_text_section
+ __nldbl_swprintf (wchar_t *s, size_t n, const wchar_t *fmt, ...)
+@@ -239,6 +246,7 @@
+
+ return done;
+ }
++#endif
+
+ int
+ attribute_compat_text_section weak_function
+@@ -264,6 +272,7 @@
+ }
+ libc_hidden_def (__nldbl_vdprintf)
+
++#ifdef __OPTION_POSIX_WIDE_CHAR_DEVICE_IO
+ int
+ attribute_compat_text_section weak_function
+ __nldbl_vfwprintf (FILE *s, const wchar_t *fmt, va_list ap)
+@@ -275,6 +284,7 @@
+ return res;
+ }
+ libc_hidden_def (__nldbl_vfwprintf)
++#endif
+
+ int
+ attribute_compat_text_section
+@@ -297,6 +307,7 @@
+ libc_hidden_def (__nldbl_vsnprintf)
+ weak_alias (__nldbl_vsnprintf, __nldbl___vsnprintf)
+
++#ifdef __OPTION_POSIX_WIDE_CHAR_DEVICE_IO
+ int
+ attribute_compat_text_section weak_function
+ __nldbl_vswprintf (wchar_t *string, size_t maxlen, const wchar_t *fmt,
+@@ -330,6 +341,7 @@
+
+ return done;
+ }
++#endif
+
+ int
+ attribute_compat_text_section
+@@ -419,6 +431,7 @@
+ return done;
+ }
+
++#ifdef __OPTION_POSIX_WIDE_CHAR_DEVICE_IO
+ int
+ attribute_compat_text_section
+ __nldbl_vfwscanf (FILE *s, const wchar_t *fmt, va_list ap)
+@@ -491,6 +504,7 @@
+
+ return done;
+ }
++#endif
+
+ int
+ attribute_compat_text_section
+@@ -506,6 +520,7 @@
+ return done;
+ }
+
++#ifdef __OPTION_POSIX_WIDE_CHAR_DEVICE_IO
+ int
+ attribute_compat_text_section
+ __nldbl___fwprintf_chk (FILE *stream, int flag, const wchar_t *fmt, ...)
+@@ -519,6 +534,7 @@
+
+ return done;
+ }
++#endif
+
+ int
+ attribute_compat_text_section
+@@ -563,6 +579,7 @@
+ return done;
+ }
+
++#ifdef __OPTION_POSIX_WIDE_CHAR_DEVICE_IO
+ int
+ attribute_compat_text_section
+ __nldbl___swprintf_chk (wchar_t *s, size_t n, int flag, size_t slen,
+@@ -577,6 +594,7 @@
+
+ return done;
+ }
++#endif
+
+ int
+ attribute_compat_text_section
+@@ -590,6 +608,7 @@
+ }
+ libc_hidden_def (__nldbl___vfprintf_chk)
+
++#ifdef __OPTION_POSIX_WIDE_CHAR_DEVICE_IO
+ int
+ attribute_compat_text_section
+ __nldbl___vfwprintf_chk (FILE *s, int flag, const wchar_t *fmt, va_list ap)
+@@ -601,6 +620,7 @@
+ return res;
+ }
+ libc_hidden_def (__nldbl___vfwprintf_chk)
++#endif
+
+ int
+ attribute_compat_text_section
+@@ -635,6 +655,7 @@
+ }
+ libc_hidden_def (__nldbl___vsprintf_chk)
+
++#ifdef __OPTION_POSIX_WIDE_CHAR_DEVICE_IO
+ int
+ attribute_compat_text_section
+ __nldbl___vswprintf_chk (wchar_t *string, size_t maxlen, int flag, size_t slen,
+@@ -668,6 +689,7 @@
+
+ return done;
+ }
++#endif
+
+ int
+ attribute_compat_text_section
+@@ -775,6 +797,7 @@
+ return ___printf_fp (fp, &info_no_ldbl, args);
+ }
+
++#if __OPTION_EGLIBC_LOCALE_CODE
+ ssize_t
+ attribute_compat_text_section
+ __nldbl_strfmon (char *s, size_t maxsize, const char *format, ...)
+@@ -829,6 +852,7 @@
+ return res;
+ }
+ libc_hidden_def (__nldbl___vstrfmon_l)
++#endif
+
+ void
+ attribute_compat_text_section
+@@ -941,6 +965,7 @@
+ return done;
+ }
+
++#ifdef __OPTION_POSIX_WIDE_CHAR_DEVICE_IO
+ int
+ attribute_compat_text_section
+ __nldbl___isoc99_vfwscanf (FILE *s, const wchar_t *fmt, va_list ap)
+@@ -1014,6 +1039,7 @@
+
+ return done;
+ }
++#endif
+
+ #if LONG_DOUBLE_COMPAT(libc, GLIBC_2_0)
+ compat_symbol (libc, __nldbl__IO_printf, _IO_printf, GLIBC_2_0);
+@@ -1057,6 +1083,7 @@
+ compat_symbol (libc, __nldbl___strfmon_l, __strfmon_l, GLIBC_2_1);
+ #endif
+ #if LONG_DOUBLE_COMPAT(libc, GLIBC_2_2)
++# ifdef __OPTION_POSIX_WIDE_CHAR_DEVICE_IO
+ compat_symbol (libc, __nldbl_swprintf, swprintf, GLIBC_2_2);
+ compat_symbol (libc, __nldbl_vwprintf, vwprintf, GLIBC_2_2);
+ compat_symbol (libc, __nldbl_wprintf, wprintf, GLIBC_2_2);
+@@ -1069,6 +1096,7 @@
+ compat_symbol (libc, __nldbl_vswscanf, vswscanf, GLIBC_2_2);
+ compat_symbol (libc, __nldbl_vwscanf, vwscanf, GLIBC_2_2);
+ compat_symbol (libc, __nldbl_wscanf, wscanf, GLIBC_2_2);
++# endif
+ #endif
+ #if LONG_DOUBLE_COMPAT(libc, GLIBC_2_3)
+ compat_symbol (libc, __nldbl_strfmon_l, strfmon_l, GLIBC_2_3);
+diff -Naur glibc-2.20/sysdeps/ieee754/ldbl-opt/nldbl-compat.h glibc-2.20-patch/sysdeps/ieee754/ldbl-opt/nldbl-compat.h
+--- glibc-2.20/sysdeps/ieee754/ldbl-opt/nldbl-compat.h 2014-09-07 03:09:09.000000000 -0500
++++ glibc-2.20-patch/sysdeps/ieee754/ldbl-opt/nldbl-compat.h 2015-03-04 00:51:32.424952006 -0600
+@@ -30,6 +30,7 @@
+ #include <math.h>
+ #include <monetary.h>
+ #include <sys/syslog.h>
++#include <gnu/option-groups.h>
+
+
+ /* Declare the __nldbl_NAME function the wrappers call that's in libc.so. */
+@@ -37,19 +38,15 @@
+
+ NLDBL_DECL (_IO_vfscanf);
+ NLDBL_DECL (vfscanf);
+-NLDBL_DECL (vfwscanf);
+ NLDBL_DECL (obstack_vprintf);
+ NLDBL_DECL (vasprintf);
+ NLDBL_DECL (dprintf);
+ NLDBL_DECL (vdprintf);
+ NLDBL_DECL (fprintf);
+ NLDBL_DECL (vfprintf);
+-NLDBL_DECL (vfwprintf);
+ NLDBL_DECL (vsnprintf);
+ NLDBL_DECL (vsprintf);
+ NLDBL_DECL (vsscanf);
+-NLDBL_DECL (vswprintf);
+-NLDBL_DECL (vswscanf);
+ NLDBL_DECL (__asprintf);
+ NLDBL_DECL (asprintf);
+ NLDBL_DECL (__printf_fp);
+@@ -66,12 +63,18 @@
+ NLDBL_DECL (__isoc99_vscanf);
+ NLDBL_DECL (__isoc99_vfscanf);
+ NLDBL_DECL (__isoc99_vsscanf);
++#ifdef __OPTION_POSIX_WIDE_CHAR_DEVICE_IO
++NLDBL_DECL (vfwscanf);
++NLDBL_DECL (vfwprintf);
++NLDBL_DECL (vswprintf);
++NLDBL_DECL (vswscanf);
+ NLDBL_DECL (__isoc99_wscanf);
+ NLDBL_DECL (__isoc99_fwscanf);
+ NLDBL_DECL (__isoc99_swscanf);
+ NLDBL_DECL (__isoc99_vwscanf);
+ NLDBL_DECL (__isoc99_vfwscanf);
+ NLDBL_DECL (__isoc99_vswscanf);
++#endif
+
+ /* This one does not exist in the normal interface, only
+ __nldbl___vstrfmon really exists. */
+@@ -82,22 +85,23 @@
+ since we don't compile with _FORTIFY_SOURCE. */
+ extern int __nldbl___vfprintf_chk (FILE *__restrict, int,
+ const char *__restrict, _G_va_list);
+-extern int __nldbl___vfwprintf_chk (FILE *__restrict, int,
+- const wchar_t *__restrict, __gnuc_va_list);
+ extern int __nldbl___vsprintf_chk (char *__restrict, int, size_t,
+ const char *__restrict, _G_va_list) __THROW;
+ extern int __nldbl___vsnprintf_chk (char *__restrict, size_t, int, size_t,
+ const char *__restrict, _G_va_list)
+ __THROW;
+-extern int __nldbl___vswprintf_chk (wchar_t *__restrict, size_t, int, size_t,
+- const wchar_t *__restrict, __gnuc_va_list)
+- __THROW;
+ extern int __nldbl___vasprintf_chk (char **, int, const char *, _G_va_list)
+ __THROW;
+ extern int __nldbl___vdprintf_chk (int, int, const char *, _G_va_list);
+ extern int __nldbl___obstack_vprintf_chk (struct obstack *, int, const char *,
+ _G_va_list) __THROW;
+ extern void __nldbl___vsyslog_chk (int, int, const char *, va_list);
+-
++#ifdef __OPTION_POSIX_WIDE_CHAR_DEVICE_IO
++extern int __nldbl___vfwprintf_chk (FILE *__restrict, int,
++ const wchar_t *__restrict, __gnuc_va_list);
++extern int __nldbl___vswprintf_chk (wchar_t *__restrict, size_t, int, size_t,
++ const wchar_t *__restrict, __gnuc_va_list)
++ __THROW;
++#endif
+
+ #endif /* __NLDBL_COMPAT_H */
+diff -Naur glibc-2.20/sysdeps/nptl/bits/libc-lock.h glibc-2.20-patch/sysdeps/nptl/bits/libc-lock.h
+--- glibc-2.20/sysdeps/nptl/bits/libc-lock.h 2014-09-07 03:09:09.000000000 -0500
++++ glibc-2.20-patch/sysdeps/nptl/bits/libc-lock.h 2015-03-04 00:51:32.424952006 -0600
+@@ -24,6 +24,14 @@
+ #include <stddef.h>
+
+
++#ifdef _LIBC
++# include <lowlevellock.h>
++# include <tls.h>
++# include <pthread-functions.h>
++# include <errno.h> /* For EBUSY. */
++# include <gnu/option-groups.h> /* For __OPTION_EGLIBC_BIG_MACROS. */
++#endif
++
+ /* Mutex type. */
+ #if defined _LIBC || defined _IO_MTSAFE_IO
+ # if (defined NOT_IN_libc && !defined IS_IN_libpthread) || !defined _LIBC
+@@ -87,6 +95,14 @@
+
+ /* Lock the recursive named lock variable. */
+ #if defined _LIBC && (!defined NOT_IN_libc || defined IS_IN_libpthread)
++# if __OPTION_EGLIBC_BIG_MACROS != 1
++/* EGLIBC: Declare wrapper function for a big macro if either
++ !__OPTION_EGLIBC_BIG_MACROS or we are using a back door from
++ small-macros-fns.c (__OPTION_EGLIBC_BIG_MACROS == 2). */
++extern void __libc_lock_lock_recursive_fn (__libc_lock_recursive_t *);
++libc_hidden_proto (__libc_lock_lock_recursive_fn);
++# endif /* __OPTION_EGLIBC_BIG_MACROS != 1 */
++# if __OPTION_EGLIBC_BIG_MACROS
+ # define __libc_lock_lock_recursive(NAME) \
+ do { \
+ void *self = THREAD_SELF; \
+@@ -97,6 +113,10 @@
+ } \
+ ++(NAME).cnt; \
+ } while (0)
++# else
++# define __libc_lock_lock_recursive(NAME) \
++ __libc_lock_lock_recursive_fn (&(NAME))
++# endif /* __OPTION_EGLIBC_BIG_MACROS */
+ #else
+ # define __libc_lock_lock_recursive(NAME) \
+ __libc_maybe_call (__pthread_mutex_lock, (&(NAME).mutex), 0)
+@@ -104,6 +124,14 @@
+
+ /* Try to lock the recursive named lock variable. */
+ #if defined _LIBC && (!defined NOT_IN_libc || defined IS_IN_libpthread)
++# if __OPTION_EGLIBC_BIG_MACROS != 1
++/* EGLIBC: Declare wrapper function for a big macro if either
++ !__OPTION_EGLIBC_BIG_MACROS or we are using a back door from
++ small-macros-fns.c (__OPTION_EGLIBC_BIG_MACROS == 2). */
++extern int __libc_lock_trylock_recursive_fn (__libc_lock_recursive_t *);
++libc_hidden_proto (__libc_lock_trylock_recursive_fn);
++# endif /* __OPTION_EGLIBC_BIG_MACROS != 1 */
++# if __OPTION_EGLIBC_BIG_MACROS
+ # define __libc_lock_trylock_recursive(NAME) \
+ ({ \
+ int result = 0; \
+@@ -122,6 +150,10 @@
+ ++(NAME).cnt; \
+ result; \
+ })
++# else
++# define __libc_lock_trylock_recursive(NAME) \
++ __libc_lock_trylock_recursive_fn (&(NAME))
++# endif /* __OPTION_EGLIBC_BIG_MACROS */
+ #else
+ # define __libc_lock_trylock_recursive(NAME) \
+ __libc_maybe_call (__pthread_mutex_trylock, (&(NAME).mutex), 0)
+@@ -129,6 +161,14 @@
+
+ /* Unlock the recursive named lock variable. */
+ #if defined _LIBC && (!defined NOT_IN_libc || defined IS_IN_libpthread)
++# if __OPTION_EGLIBC_BIG_MACROS != 1
++/* EGLIBC: Declare wrapper function for a big macro if either
++ !__OPTION_EGLIBC_BIG_MACROS, or we are using a back door from
++ small-macros-fns.c (__OPTION_EGLIBC_BIG_MACROS == 2). */
++extern void __libc_lock_unlock_recursive_fn (__libc_lock_recursive_t *);
++libc_hidden_proto (__libc_lock_unlock_recursive_fn);
++# endif /* __OPTION_EGLIBC_BIG_MACROS != 1 */
++# if __OPTION_EGLIBC_BIG_MACROS
+ /* We do no error checking here. */
+ # define __libc_lock_unlock_recursive(NAME) \
+ do { \
+@@ -138,6 +178,10 @@
+ lll_unlock ((NAME).lock, LLL_PRIVATE); \
+ } \
+ } while (0)
++# else
++# define __libc_lock_unlock_recursive(NAME) \
++ __libc_lock_unlock_recursive_fn (&(NAME))
++# endif /* __OPTION_EGLIBC_BIG_MACROS */
+ #else
+ # define __libc_lock_unlock_recursive(NAME) \
+ __libc_maybe_call (__pthread_mutex_unlock, (&(NAME).mutex), 0)
+diff -Naur glibc-2.20/sysdeps/nptl/bits/libc-lockP.h glibc-2.20-patch/sysdeps/nptl/bits/libc-lockP.h
+--- glibc-2.20/sysdeps/nptl/bits/libc-lockP.h 2014-09-07 03:09:09.000000000 -0500
++++ glibc-2.20-patch/sysdeps/nptl/bits/libc-lockP.h 2015-03-04 00:51:32.424952006 -0600
+@@ -33,6 +33,8 @@
+ #include <lowlevellock.h>
+ #include <tls.h>
+ #include <pthread-functions.h>
++#include <errno.h> /* For EBUSY. */
++#include <gnu/option-groups.h> /* For __OPTION_EGLIBC_BIG_MACROS. */
+
+ /* Mutex type. */
+ #if defined NOT_IN_libc && !defined IS_IN_libpthread
+@@ -159,10 +161,22 @@
+
+ /* Lock the named lock variable. */
+ #if !defined NOT_IN_libc || defined IS_IN_libpthread
+-# ifndef __libc_lock_lock
+-# define __libc_lock_lock(NAME) \
++# if __OPTION_EGLIBC_BIG_MACROS != 1
++/* EGLIBC: Declare wrapper function for a big macro if either
++ !__OPTION_EGLIBC_BIG_MACROS or we are using a back door from
++ small-macros-fns.c (__OPTION_EGLIBC_BIG_MACROS == 2). */
++extern void __libc_lock_lock_fn (__libc_lock_t *);
++libc_hidden_proto (__libc_lock_lock_fn);
++# endif /* __OPTION_EGLIBC_BIG_MACROS != 1 */
++# if __OPTION_EGLIBC_BIG_MACROS
++# ifndef __libc_lock_lock
++# define __libc_lock_lock(NAME) \
+ ({ lll_lock (NAME, LLL_PRIVATE); 0; })
+-# endif
++# endif
++# else
++# define __libc_lock_lock(NAME) \
++ __libc_lock_lock_fn (&(NAME))
++# endif /* __OPTION_EGLIBC_BIG_MACROS */
+ #else
+ # undef __libc_lock_lock
+ # define __libc_lock_lock(NAME) \
+@@ -175,10 +189,22 @@
+
+ /* Try to lock the named lock variable. */
+ #if !defined NOT_IN_libc || defined IS_IN_libpthread
+-# ifndef __libc_lock_trylock
+-# define __libc_lock_trylock(NAME) \
++# if __OPTION_EGLIBC_BIG_MACROS != 1
++/* EGLIBC: Declare wrapper function for a big macro if either
++ !__OPTION_EGLIBC_BIG_MACROS or we are using a back door from
++ small-macros-fns.c (__OPTION_EGLIBC_BIG_MACROS == 2). */
++extern int __libc_lock_trylock_fn (__libc_lock_t *);
++libc_hidden_proto (__libc_lock_trylock_fn);
++# endif /* __OPTION_EGLIBC_BIG_MACROS != 1 */
++# if __OPTION_EGLIBC_BIG_MACROS
++# ifndef __libc_lock_trylock
++# define __libc_lock_trylock(NAME) \
+ lll_trylock (NAME)
+-# endif
++# endif
++# else
++# define __libc_lock_trylock(NAME) \
++ __libc_lock_trylock_fn (&(NAME))
++# endif /* __OPTION_EGLIBC_BIG_MACROS */
+ #else
+ # undef __libc_lock_trylock
+ # define __libc_lock_trylock(NAME) \
+@@ -194,8 +220,20 @@
+
+ /* Unlock the named lock variable. */
+ #if !defined NOT_IN_libc || defined IS_IN_libpthread
++# if __OPTION_EGLIBC_BIG_MACROS != 1
++/* EGLIBC: Declare wrapper function for a big macro if either
++ !__OPTION_EGLIBC_BIG_MACROS, or we are using a back door from
++ small-macros-fns.c (__OPTION_EGLIBC_BIG_MACROS == 2). */
++extern void __libc_lock_unlock_fn (__libc_lock_t *);
++libc_hidden_proto (__libc_lock_unlock_fn);
++# endif /* __OPTION_EGLIBC_BIG_MACROS != 1 */
++# if __OPTION_EGLIBC_BIG_MACROS
+ # define __libc_lock_unlock(NAME) \
+ lll_unlock (NAME, LLL_PRIVATE)
++# else
++# define __libc_lock_unlock(NAME) \
++ __libc_lock_unlock_fn (&(NAME))
++# endif /* __OPTION_EGLIBC_BIG_MACROS */
+ #else
+ # define __libc_lock_unlock(NAME) \
+ __libc_maybe_call (__pthread_mutex_unlock, (&(NAME)), 0)
+diff -Naur glibc-2.20/sysdeps/nptl/Makefile glibc-2.20-patch/sysdeps/nptl/Makefile
+--- glibc-2.20/sysdeps/nptl/Makefile 2014-09-07 03:09:09.000000000 -0500
++++ glibc-2.20-patch/sysdeps/nptl/Makefile 2015-03-04 00:51:32.424952006 -0600
+@@ -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 -Naur glibc-2.20/sysdeps/nptl/small-macros-fns.c glibc-2.20-patch/sysdeps/nptl/small-macros-fns.c
+--- glibc-2.20/sysdeps/nptl/small-macros-fns.c 1969-12-31 18:00:00.000000000 -0600
++++ glibc-2.20-patch/sysdeps/nptl/small-macros-fns.c 2015-03-04 00:51:32.424952006 -0600
+@@ -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 -Naur glibc-2.20/sysdeps/unix/sysv/linux/gethostid.c glibc-2.20-patch/sysdeps/unix/sysv/linux/gethostid.c
+--- glibc-2.20/sysdeps/unix/sysv/linux/gethostid.c 2014-09-07 03:09:09.000000000 -0500
++++ glibc-2.20-patch/sysdeps/unix/sysv/linux/gethostid.c 2015-03-04 00:51:32.425952006 -0600
+@@ -21,6 +21,7 @@
+ #include <unistd.h>
+ #include <netdb.h>
+ #include <not-cancel.h>
++#include <gnu/option-groups.h>
+
+ #define HOSTIDFILE "/etc/hostid"
+
+@@ -89,6 +90,7 @@
+ return id;
+ }
+
++#if __OPTION_EGLIBC_INET
+ /* Getting from the file was not successful. An intelligent guess for
+ a unique number of a host is its IP address. Return this. */
+ if (__gethostname (hostname, MAXHOSTNAMELEN) < 0 || hostname[0] == '\0')
+@@ -115,5 +117,9 @@
+ /* For the return value to be not exactly the IP address we do some
+ bit fiddling. */
+ return (int32_t) (in.s_addr << 16 | in.s_addr >> 16);
++#else
++ /* Return an arbitrary value. */
++ return 0;
++#endif
+ }
+ #endif
+diff -Naur glibc-2.20/sysdeps/unix/sysv/linux/libc_fatal.c glibc-2.20-patch/sysdeps/unix/sysv/linux/libc_fatal.c
+--- glibc-2.20/sysdeps/unix/sysv/linux/libc_fatal.c 2014-09-07 03:09:09.000000000 -0500
++++ glibc-2.20-patch/sysdeps/unix/sysv/linux/libc_fatal.c 2015-03-04 00:51:32.425952006 -0600
+@@ -23,6 +23,7 @@
+ #include <string.h>
+ #include <sys/mman.h>
+ #include <sys/uio.h>
++#include <gnu/option-groups.h>
+
+ static bool
+ writev_for_fatal (int fd, const struct iovec *iov, size_t niov, size_t total)
+@@ -40,6 +41,7 @@
+ static void
+ backtrace_and_maps (int do_abort, bool written, int fd)
+ {
++#if __OPTION_EGLIBC_BACKTRACE
+ if (do_abort > 1 && written)
+ {
+ void *addrs[64];
+@@ -62,6 +64,7 @@
+ close_not_cancel_no_status (fd2);
+ }
+ }
++#endif /* __OPTION_EGLIBC_BACKTRACE */
+ }
+ #define BEFORE_ABORT backtrace_and_maps
+
+diff -Naur glibc-2.20/time/Makefile glibc-2.20-patch/time/Makefile
+--- glibc-2.20/time/Makefile 2014-09-07 03:09:09.000000000 -0500
++++ glibc-2.20-patch/time/Makefile 2015-03-04 00:51:32.425952006 -0600
+@@ -18,6 +18,8 @@
+ #
+ # Makefile for time routines
+ #
++include ../option-groups.mak
++
+ subdir := time
+
+ include ../Makeconfig
+@@ -30,14 +32,20 @@
+ tzfile getitimer setitimer \
+ stime dysize timegm ftime \
+ getdate strptime strptime_l \
+- strftime wcsftime strftime_l wcsftime_l \
++ strftime strftime_l \
+ timespec_get
+-aux := era alt_digit lc-time-cleanup
++routines-$(OPTION_POSIX_C_LANG_WIDE_CHAR) \
++ := wcsftime wcsftime_l
++aux-$(OPTION_EGLIBC_LOCALE_CODE) += alt_digit era lc-time-cleanup
+
+-tests := test_time clocktest tst-posixtz tst-strptime tst_wcsftime \
+- tst-getdate tst-mktime tst-mktime2 tst-ftime_l tst-strftime \
++tests := test_time clocktest tst-posixtz \
++ tst-getdate tst-mktime tst-mktime2 tst-strftime \
+ tst-mktime3 tst-strptime2 bug-asctime bug-asctime_r bug-mktime1 \
+ tst-strptime3 bug-getdate1 tst-strptime-whitespace
++tests-$(OPTION_EGLIBC_LOCALE_CODE) \
++ += tst-strptime tst-ftime_l
++tests-$(OPTION_POSIX_WIDE_CHAR_DEVICE_IO) \
++ += tst_wcsftime
+
+ include ../Rules
+
+diff -Naur glibc-2.20/time/strftime_l.c glibc-2.20-patch/time/strftime_l.c
+--- glibc-2.20/time/strftime_l.c 2014-09-07 03:09:09.000000000 -0500
++++ glibc-2.20-patch/time/strftime_l.c 2015-03-04 00:51:32.426952006 -0600
+@@ -35,6 +35,10 @@
+ # include "../locale/localeinfo.h"
+ #endif
+
++#ifdef _LIBC
++# include <gnu/option-groups.h>
++#endif
++
+ #if defined emacs && !defined HAVE_BCOPY
+ # define HAVE_MEMCPY 1
+ #endif
+@@ -882,7 +886,7 @@
+ case L_('C'):
+ if (modifier == L_('E'))
+ {
+-#if HAVE_STRUCT_ERA_ENTRY
++#if (! _LIBC || __OPTION_EGLIBC_LOCALE_CODE) && HAVE_STRUCT_ERA_ENTRY
+ struct era_entry *era = _nl_get_era_entry (tp HELPER_LOCALE_ARG);
+ if (era)
+ {
+@@ -955,7 +959,7 @@
+
+ if (modifier == L_('O') && 0 <= number_value)
+ {
+-#ifdef _NL_CURRENT
++#if (! _LIBC || __OPTION_EGLIBC_LOCALE_CODE) && defined (_NL_CURRENT)
+ /* Get the locale specific alternate representation of
+ the number NUMBER_VALUE. If none exist NULL is returned. */
+ const CHAR_T *cp = nl_get_alt_digit (number_value
+@@ -1260,7 +1264,7 @@
+ case L_('Y'):
+ if (modifier == 'E')
+ {
+-#if HAVE_STRUCT_ERA_ENTRY
++#if (! _LIBC || __OPTION_EGLIBC_LOCALE_CODE) && HAVE_STRUCT_ERA_ENTRY
+ struct era_entry *era = _nl_get_era_entry (tp HELPER_LOCALE_ARG);
+ if (era)
+ {
+@@ -1285,7 +1289,7 @@
+ case L_('y'):
+ if (modifier == L_('E'))
+ {
+-#if HAVE_STRUCT_ERA_ENTRY
++#if (! _LIBC || __OPTION_EGLIBC_LOCALE_CODE) && HAVE_STRUCT_ERA_ENTRY
+ struct era_entry *era = _nl_get_era_entry (tp HELPER_LOCALE_ARG);
+ if (era)
+ {
+diff -Naur glibc-2.20/time/strptime_l.c glibc-2.20-patch/time/strptime_l.c
+--- glibc-2.20/time/strptime_l.c 2014-09-07 03:09:09.000000000 -0500
++++ glibc-2.20-patch/time/strptime_l.c 2015-03-04 00:51:32.426952006 -0600
+@@ -29,6 +29,7 @@
+
+ #ifdef _LIBC
+ # define HAVE_LOCALTIME_R 0
++# include <gnu/option-groups.h>
+ # include "../locale/localeinfo.h"
+ #endif
+
+@@ -84,7 +85,7 @@
+ if (val < from || val > to) \
+ return NULL; \
+ } while (0)
+-#ifdef _NL_CURRENT
++#if (! _LIBC || __OPTION_EGLIBC_LOCALE_CODE) && defined (_NL_CURRENT)
+ # define get_alt_number(from, to, n) \
+ ({ \
+ __label__ do_normal; \
+@@ -820,6 +821,7 @@
+ s.want_xday = 1;
+ break;
+ case 'C':
++#if ! _LIBC || __OPTION_EGLIBC_LOCALE_CODE
+ if (s.decided != raw)
+ {
+ if (s.era_cnt >= 0)
+@@ -856,10 +858,12 @@
+
+ s.decided = raw;
+ }
++#endif
+ /* The C locale has no era information, so use the
+ normal representation. */
+ goto match_century;
+ case 'y':
++#if ! _LIBC || __OPTION_EGLIBC_LOCALE_CODE
+ if (s.decided != raw)
+ {
+ get_number(0, 9999, 4);
+@@ -918,9 +922,10 @@
+
+ s.decided = raw;
+ }
+-
++#endif
+ goto match_year_in_century;
+ case 'Y':
++#if ! _LIBC || __OPTION_EGLIBC_LOCALE_CODE
+ if (s.decided != raw)
+ {
+ num_eras = _NL_CURRENT_WORD (LC_TIME,
+@@ -948,6 +953,7 @@
+
+ s.decided = raw;
+ }
++#endif
+ get_number (0, 9999, 4);
+ tm->tm_year = val - 1900;
+ s.want_century = 0;
+@@ -1118,6 +1124,7 @@
+ tm->tm_year = (s.century - 19) * 100;
+ }
+
++#if ! _LIBC || __OPTION_EGLIBC_LOCALE_CODE
+ if (s.era_cnt != -1)
+ {
+ era = _nl_select_era_entry (s.era_cnt HELPER_LOCALE_ARG);
+@@ -1132,6 +1139,7 @@
+ tm->tm_year = era->start_date[0];
+ }
+ else
++#endif
+ if (s.want_era)
+ {
+ /* No era found but we have seen an E modifier. Rectify some
+diff -Naur glibc-2.20/timezone/Makefile glibc-2.20-patch/timezone/Makefile
+--- glibc-2.20/timezone/Makefile 2014-09-07 03:09:09.000000000 -0500
++++ glibc-2.20-patch/timezone/Makefile 2015-03-04 00:51:32.426952006 -0600
+@@ -115,7 +115,7 @@
+
+ $(objpfx)tzselect: tzselect.ksh $(common-objpfx)config.make
+ sed -e 's|/bin/bash|$(BASH)|' \
+- -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 -Naur glibc-2.20/wcsmbs/Makefile glibc-2.20-patch/wcsmbs/Makefile
+--- glibc-2.20/wcsmbs/Makefile 2014-09-07 03:09:09.000000000 -0500
++++ glibc-2.20-patch/wcsmbs/Makefile 2015-03-04 00:51:32.426952006 -0600
+@@ -18,15 +18,21 @@
+ #
+ # Sub-makefile for wcsmbs portion of the library.
+ #
++include ../option-groups.mak
++
+ subdir := wcsmbs
+
+ include ../Makeconfig
+
+ headers := wchar.h bits/wchar.h bits/wchar2.h bits/wchar-ldbl.h uchar.h
+
+-routines := wcscat wcschr wcscmp wcscpy wcscspn wcsdup wcslen wcsncat \
++# These functions are used by printf_fp.c, even in the plain case; see
++# comments there for OPTION_EGLIBC_LOCALE_CODE.
++routines := wmemcpy wmemset
++routines-$(OPTION_POSIX_C_LANG_WIDE_CHAR) \
++ := wcscat wcschr wcscmp wcscpy wcscspn wcsdup wcslen wcsncat \
+ wcsncmp wcsncpy wcspbrk wcsrchr wcsspn wcstok wcsstr wmemchr \
+- wmemcmp wmemcpy wmemmove wmemset wcpcpy wcpncpy wmempcpy \
++ wmemcmp wmemmove wcpcpy wcpncpy wmempcpy \
+ btowc wctob mbsinit \
+ mbrlen mbrtowc wcrtomb mbsrtowcs wcsrtombs \
+ mbsnrtowcs wcsnrtombs wcsnlen wcschrnul \
+@@ -38,14 +44,19 @@
+ wcscoll_l wcsxfrm_l \
+ wcscasecmp wcsncase wcscasecmp_l wcsncase_l \
+ wcsmbsload mbsrtowcs_l \
+- isoc99_wscanf isoc99_vwscanf isoc99_fwscanf isoc99_vfwscanf \
+ isoc99_swscanf isoc99_vswscanf \
+ mbrtoc16 c16rtomb
++routines-$(OPTION_POSIX_WIDE_CHAR_DEVICE_IO) \
++ += isoc99_wscanf isoc99_vwscanf isoc99_fwscanf isoc99_vfwscanf
+
+ strop-tests := wcscmp wmemcmp wcslen wcschr wcsrchr wcscpy
+-tests := tst-wcstof wcsmbs-tst1 tst-wcsnlen tst-btowc tst-mbrtowc \
+- tst-wcrtomb tst-wcpncpy tst-mbsrtowcs tst-wchar-h tst-mbrtowc2 \
+- tst-c16c32-1 wcsatcliff $(addprefix test-,$(strop-tests))
++tests := tst-wchar-h
++tests-$(OPTION_EGLIBC_LOCALE_CODE) \
++ += tst-btowc tst-mbrtowc tst-mbrtowc2 tst-wcrtomb tst-c16c32-1
++tests-$(OPTION_POSIX_C_LANG_WIDE_CHAR) \
++ += tst-wcstof wcsmbs-tst1 tst-wcsnlen \
++ tst-wcpncpy tst-mbsrtowcs \
++ wcsatcliff $(addprefix test-,$(strop-tests))
+ tests-ifunc := $(strop-tests:%=test-%-ifunc)
+ tests += $(tests-ifunc)
+
+diff -Naur glibc-2.20/wcsmbs/wcsmbsload.c glibc-2.20-patch/wcsmbs/wcsmbsload.c
+--- glibc-2.20/wcsmbs/wcsmbsload.c 2014-09-07 03:09:09.000000000 -0500
++++ glibc-2.20-patch/wcsmbs/wcsmbsload.c 2015-03-04 00:51:32.426952006 -0600
+@@ -21,6 +21,7 @@
+ #include <limits.h>
+ #include <stdlib.h>
+ #include <string.h>
++#include <gnu/option-groups.h>
+
+ #include <locale/localeinfo.h>
+ #include <wcsmbsload.h>
+@@ -143,6 +144,7 @@
+ })
+
+
++#if __OPTION_EGLIBC_LOCALE_CODE
+ /* Some of the functions here must not be used while setlocale is called. */
+ __libc_rwlock_define (extern, __libc_setlocale_lock attribute_hidden)
+
+@@ -211,6 +213,17 @@
+
+ __libc_rwlock_unlock (__libc_setlocale_lock);
+ }
++#else
++void
++internal_function
++__wcsmbs_load_conv (struct __locale_data *new_category)
++{
++ /* When OPTION_EGLIBC_LOCALE_CODE is disabled, we should never reach
++ this point: there is no way to change locales, so every locale
++ passed to get_gconv_fcts should be _nl_C_LC_CTYPE. */
++ abort ();
++}
++#endif
+
+
+ /* Clone the current conversion function set. */
+diff -Naur glibc-2.20/wctype/Makefile glibc-2.20-patch/wctype/Makefile
+--- glibc-2.20/wctype/Makefile 2014-09-07 03:09:09.000000000 -0500
++++ glibc-2.20-patch/wctype/Makefile 2015-03-04 00:51:32.427952006 -0600
+@@ -18,14 +18,20 @@
+ #
+ # Sub-makefile for wctype portion of the library.
+ #
++include ../option-groups.mak
++
+ subdir := wctype
+
+ include ../Makeconfig
+
+ headers := wctype.h
+-routines := wcfuncs wctype iswctype wctrans towctrans \
+- wcfuncs_l wctype_l iswctype_l wctrans_l towctrans_l
++routines := wctrans towctrans towctrans_l
++routines-$(OPTION_POSIX_C_LANG_WIDE_CHAR) \
++ := wcfuncs wctype iswctype \
++ wcfuncs_l wctype_l iswctype_l wctrans_l
+
+-tests := test_wctype test_wcfuncs bug-wctypeh
++tests :=
++tests-$(OPTION_POSIX_C_LANG_WIDE_CHAR) \
++ += test_wctype test_wcfuncs bug-wctypeh
+
+ include ../Rules
diff --git a/recipes-core/glibc/glibc-initial.inc b/recipes-core/glibc/glibc-initial.inc
new file mode 100644
index 0000000..9d3a736
--- /dev/null
+++ b/recipes-core/glibc/glibc-initial.inc
@@ -0,0 +1,83 @@
+DEPENDS = "linux-libc-headers virtual/${TARGET_PREFIX}gcc-initial libgcc-initial"
+PROVIDES = "virtual/${TARGET_PREFIX}libc-initial"
+
+PACKAGES = ""
+PACKAGES_DYNAMIC = ""
+
+STAGINGCC = "gcc-cross-initial-${TARGET_ARCH}"
+STAGINGCC_class-nativesdk = "gcc-crosssdk-initial-${SDK_SYS}"
+#TOOLCHAIN_OPTIONS = " --sysroot=${STAGING_DIR_TARGET}"
+
+do_configure () {
+ sed -ie 's,{ (exit 1); exit 1; }; },{ (exit 0); }; },g' ${S}/configure
+ chmod +x ${S}/configure
+ (cd ${S} && gnu-configize) || die "failure in running gnu-configize"
+ find ${S} -name "configure" | xargs touch
+ ${S}/configure --host=${TARGET_SYS} --build=${BUILD_SYS} \
+ --prefix=/usr \
+ --without-cvs --disable-sanity-checks \
+ --with-headers=${STAGING_DIR_TARGET}${includedir} \
+ --with-kconfig=${STAGING_BINDIR_NATIVE} \
+ --enable-hacker-mode --enable-addons
+}
+
+do_compile () {
+ :
+}
+
+do_install () {
+ oe_runmake cross-compiling=yes install_root=${D} \
+ includedir='${includedir}' prefix='${prefix}' \
+ install-bootstrap-headers=yes install-headers
+
+ oe_runmake csu/subdir_lib
+ mkdir -p ${D}${libdir}/
+ install -m 644 csu/crt[1in].o ${D}${libdir}
+
+ # Two headers -- stubs.h and features.h -- aren't installed by install-headers,
+ # so do them by hand. We can tolerate an empty stubs.h for the moment.
+ # See e.g. http://gcc.gnu.org/ml/gcc/2002-01/msg00900.html
+ mkdir -p ${D}${includedir}/gnu/
+ touch ${D}${includedir}/gnu/stubs.h
+ cp ${S}/include/features.h ${D}${includedir}/features.h
+
+ if [ -e ${B}/bits/stdio_lim.h ]; then
+ cp ${B}/bits/stdio_lim.h ${D}${includedir}/bits/
+ fi
+ # add links to linux-libc-headers: final glibc build need this.
+ #for t in linux asm asm-generic; do
+ # ln -s ${STAGING_DIR_TARGET}${includedir}/$t ${D}${includedir}/
+ #done
+}
+
+do_stash_locale() {
+ :
+}
+
+do_siteconfig () {
+ :
+}
+
+#SSTATEPOSTINSTFUNCS += "glibcinitial_sstate_postinst"
+#glibcinitial_sstate_postinst() {
+# if [ "${BB_CURRENTTASK}" = "populate_sysroot" -o "${BB_CURRENTTASK}" = "populate_sysroot_setscene" ]
+# then
+# # Recreate the symlinks to ensure they point to the correct location
+# for t in linux asm asm-generic; do
+# rm -f ${STAGING_DIR_TARGET}${includedir}/$t
+# # ln -s ${STAGING_DIR_TARGET}${includedir}/$t ${STAGING_DIR_TARGET}${includedir}/
+# done
+# fi
+#}
+
+#do_populate_sysroot[sstate-outputdirs] = "${STAGING_DIR_TARGET}/"
+
+# We don't install any scripts so there is nothing to evacuate
+#do_evacuate_scripts () {
+# :
+#}
+
+#inherit nopackages
+
+# We really only want this built by things that need it, not any recrdeptask
+#deltask do_build
diff --git a/recipes-core/glibc/glibc-initial_2.20.bb b/recipes-core/glibc/glibc-initial_2.20.bb
new file mode 100644
index 0000000..8ab01dc
--- /dev/null
+++ b/recipes-core/glibc/glibc-initial_2.20.bb
@@ -0,0 +1,11 @@
+require glibc_${PV}.bb
+require glibc-initial.inc
+
+DEPENDS += "kconfig-frontends-native"
+
+# main glibc recipes muck with TARGET_CPPFLAGS to point into
+# final target sysroot but we
+# are not there when building glibc-initial
+# so reset it here
+
+TARGET_CPPFLAGS = ""
diff --git a/recipes-core/glibc/glibc-ld.inc b/recipes-core/glibc/glibc-ld.inc
new file mode 100644
index 0000000..962d666
--- /dev/null
+++ b/recipes-core/glibc/glibc-ld.inc
@@ -0,0 +1,56 @@
+def ld_append_if_tune_exists(d, infos, dict):
+ tune = d.getVar("DEFAULTTUNE", True) or ""
+ libdir = d.getVar("base_libdir", True) or ""
+ if tune in dict:
+ infos['ldconfig'].add('{"' + libdir + '/' + dict[tune][0] + '",' + dict[tune][1] + ' }')
+ infos['lddrewrite'].add(libdir+'/'+dict[tune][0])
+
+def glibc_dl_info(d):
+ ld_info_all = {
+ "mips": ["ld.so.1", "FLAG_ELF_LIBC6"],
+ "mips64-n32": ["ld.so.1", "FLAG_ELF_LIBC6"],
+ "mips64": ["ld.so.1", "FLAG_ELF_LIBC6"],
+ "mipsel": ["ld.so.1", "FLAG_ELF_LIBC6"],
+ "mips64el-n32": ["ld.so.1", "FLAG_ELF_LIBC6"],
+ "mips64el": ["ld.so.1", "FLAG_ELF_LIBC6"],
+ "mips-nf": ["ld.so.1", "FLAG_ELF_LIBC6"],
+ "mips64-nf-n32": ["ld.so.1", "FLAG_ELF_LIBC6"],
+ "mips64-nf": ["ld.so.1", "FLAG_ELF_LIBC6"],
+ "mips64el-nf-n32": ["ld.so.1", "FLAG_ELF_LIBC6"],
+ "mips64el-nf": ["ld.so.1", "FLAG_ELF_LIBC6"],
+ "powerpc": ["ld.so.1", "FLAG_ELF_LIBC6"],
+ "powerpc-nf": ["ld.so.1", "FLAG_ELF_LIBC6"],
+ "powerpc64": ["ld64.so.1", "FLAG_ELF_LIBC6"],
+ "powerpc64-nf": ["ld64.so.1", "FLAG_ELF_LIBC6"],
+ "core2-32": ["ld-linux.so.2", "FLAG_ELF_LIBC6"],
+ "core2-64": ["ld-linux-x86-64.so.2", "FLAG_ELF_LIBC6"],
+ "x86": ["ld-linux.so.2", "FLAG_ELF_LIBC6"],
+ "x86-64": ["ld-linux-x86-64.so.2", "FLAG_ELF_LIBC6"],
+ "i586": ["ld-linux.so.2", "FLAG_ELF_LIBC6"],
+ "corei7-32": ["ld-linux.so.2", "FLAG_ELF_LIBC6"],
+ "corei7-64": ["ld-linux-x86-64.so.2", "FLAG_ELF_LIBC6"],
+ }
+
+ infos = {'ldconfig':set(), 'lddrewrite':set()}
+ ld_append_if_tune_exists(d, infos, ld_info_all)
+
+ #DEFAULTTUNE_MULTILIB_ORIGINAL
+ original_tune=d.getVar("DEFAULTTUNE_MULTILIB_ORIGINAL",True)
+ if original_tune:
+ localdata = bb.data.createCopy(d)
+ localdata.setVar("DEFAULTTUNE", original_tune)
+ ld_append_if_tune_exists(localdata, infos, ld_info_all)
+
+ variants = d.getVar("MULTILIB_VARIANTS", True) or ""
+ for item in variants.split():
+ localdata = bb.data.createCopy(d)
+ overrides = localdata.getVar("OVERRIDES", False) + ":virtclass-multilib-" + item
+ localdata.setVar("OVERRIDES", overrides)
+ bb.data.update_data(localdata)
+ ld_append_if_tune_exists(localdata, infos, ld_info_all)
+ infos['ldconfig'] = ','.join(infos['ldconfig'])
+ infos['lddrewrite'] = ' '.join(infos['lddrewrite'])
+ return infos
+
+EGLIBC_KNOWN_INTERPRETER_NAMES = "${@glibc_dl_info(d)['ldconfig']}"
+RTLDLIST = "${@glibc_dl_info(d)['lddrewrite']}"
diff --git a/recipes-core/glibc/glibc-locale_2.20.bb b/recipes-core/glibc/glibc-locale_2.20.bb
new file mode 100644
index 0000000..8d22aff
--- /dev/null
+++ b/recipes-core/glibc/glibc-locale_2.20.bb
@@ -0,0 +1 @@
+require recipes-core/glibc/glibc-locale.inc
diff --git a/recipes-core/glibc/glibc-mtrace_2.20.bb b/recipes-core/glibc/glibc-mtrace_2.20.bb
new file mode 100644
index 0000000..436605c
--- /dev/null
+++ b/recipes-core/glibc/glibc-mtrace_2.20.bb
@@ -0,0 +1 @@
+require recipes-core/glibc/glibc-mtrace.inc
diff --git a/recipes-core/glibc/glibc-options.inc b/recipes-core/glibc/glibc-options.inc
new file mode 100644
index 0000000..9fd27f3
--- /dev/null
+++ b/recipes-core/glibc/glibc-options.inc
@@ -0,0 +1,162 @@
+def glibc_cfg(feature, tokens, cnf):
+ if type(tokens) == type(""):
+ tokens = [tokens]
+ if feature:
+ cnf.extend([token + '=y' for token in tokens])
+ else:
+ for token in tokens:
+ cnf.extend([token + '=n'])
+ if token == 'OPTION_EGLIBC_NSSWITCH':
+ cnf.extend(["OPTION_EGLIBC_NSSWITCH_FIXED_CONFIG=\"${S}/nss/nsswitch.conf\""])
+ cnf.extend(["OPTION_EGLIBC_NSSWITCH_FIXED_FUNCTIONS=\"${S}/nss/fixed-nsswitch.functions\""])
+
+# Map distro features to glibc options settings
+def features_to_glibc_settings(d):
+ cnf = ([])
+
+ ipv4 = bb.utils.contains('DISTRO_FEATURES', 'ipv4', True, False, d)
+ ipv6 = bb.utils.contains('DISTRO_FEATURES', 'ipv6', True, False, d)
+ libc_backtrace = bb.utils.contains('DISTRO_FEATURES', 'libc-backtrace', True, False, d)
+ libc_big_macros = bb.utils.contains('DISTRO_FEATURES', 'libc-big-macros', True, False, d)
+ libc_bsd = bb.utils.contains('DISTRO_FEATURES', 'libc-bsd', True, False, d)
+ libc_cxx_tests = bb.utils.contains('DISTRO_FEATURES', 'libc-cxx-tests', True, False, d)
+ libc_catgets = bb.utils.contains('DISTRO_FEATURES', 'libc-catgets', True, False, d)
+ libc_charsets = bb.utils.contains('DISTRO_FEATURES', 'libc-charsets', True, False, d)
+ libc_crypt = bb.utils.contains('DISTRO_FEATURES', 'libc-crypt', True, False, d)
+ libc_crypt_ufc = bb.utils.contains('DISTRO_FEATURES', 'libc-crypt-ufc', True, False, d)
+ libc_db_aliases = bb.utils.contains('DISTRO_FEATURES', 'libc-db-aliases', True, False, d)
+ libc_envz = bb.utils.contains('DISTRO_FEATURES', 'libc-envz', True, False, d)
+ libc_fcvt = bb.utils.contains('DISTRO_FEATURES', 'libc-fcvt', True, False, d)
+ libc_fmtmsg = bb.utils.contains('DISTRO_FEATURES', 'libc-fmtmsg', True, False, d)
+ libc_fstab = bb.utils.contains('DISTRO_FEATURES', 'libc-fstab', True, False, d)
+ libc_ftraverse = bb.utils.contains('DISTRO_FEATURES', 'libc-ftraverse', True, False, d)
+ libc_getlogin = bb.utils.contains('DISTRO_FEATURES', 'libc-getlogin', True, False, d)
+ libc_idn = bb.utils.contains('DISTRO_FEATURES', 'libc-idn', True, False, d)
+ libc_inet_anl = bb.utils.contains('DISTRO_FEATURES', 'libc-inet-anl', True, False, d)
+ libc_libm = bb.utils.contains('DISTRO_FEATURES', 'libc-libm', True, False, d)
+ libc_locales = bb.utils.contains('DISTRO_FEATURES', 'libc-locales', True, False, d)
+ libc_locale_code = bb.utils.contains('DISTRO_FEATURES', 'libc-locale-code', True, False, d)
+ libc_memusage = bb.utils.contains('DISTRO_FEATURES', 'libc-memusage', True, False, d)
+ libc_nis = bb.utils.contains('DISTRO_FEATURES', 'libc-nis', True, False, d)
+ libc_nsswitch = bb.utils.contains('DISTRO_FEATURES', 'libc-nsswitch', True, False, d)
+ libc_rcmd = bb.utils.contains('DISTRO_FEATURES', 'libc-rcmd', True, False, d)
+ libc_rtld_debug = bb.utils.contains('DISTRO_FEATURES', 'libc-rtld-debug', True, False, d)
+ libc_spawn = bb.utils.contains('DISTRO_FEATURES', 'libc-spawn', True, False, d)
+ libc_streams = bb.utils.contains('DISTRO_FEATURES', 'libc-streams', True, False, d)
+ libc_sunrpc = bb.utils.contains('DISTRO_FEATURES', 'libc-sunrpc', True, False, d)
+ libc_utmp = bb.utils.contains('DISTRO_FEATURES', 'libc-utmp', True, False, d)
+ libc_utmpx = bb.utils.contains('DISTRO_FEATURES', 'libc-utmpx', True, False, d)
+ libc_wordexp = bb.utils.contains('DISTRO_FEATURES', 'libc-wordexp', True, False, d)
+ libc_posix_clang_wchar = bb.utils.contains('DISTRO_FEATURES', 'libc-posix-clang-wchar', True, False, d)
+ libc_posix_regexp = bb.utils.contains('DISTRO_FEATURES', 'libc-posix-regexp', True, False, d)
+ libc_posix_regexp_glibc = bb.utils.contains('DISTRO_FEATURES', 'libc-posix-regexp-glibc', True, False, d)
+ libc_posix_wchar_io = bb.utils.contains('DISTRO_FEATURES', 'libc-posix-wchar-io', True, False, d)
+
+ # arrange the dependencies among glibc configuable options according to file option-groups.def from glibc source code
+ new_dep = True
+ while new_dep:
+ new_dep = False
+
+ if ipv6 and not ipv4:
+ new_dep = True
+ ipv4 = True
+
+ if ipv4 and not libc_nsswitch:
+ new_dep = True
+ libc_nsswitch = True
+
+ if libc_cxx_tests:
+ if not libc_posix_wchar_io:
+ new_dep = True
+ libc_posix_wchar_io = True
+ if not libc_libm:
+ new_dep = True
+ libc_libm = True
+
+ if libc_catgets and not libc_locale_code:
+ new_dep = True
+ libc_locale_code = True
+
+ if libc_crypt_ufc and not libc_crypt:
+ new_dep = True
+ libc_crypt = True
+
+ if libc_getlogin and not libc_utmp:
+ new_dep = True
+ libc_utmp = True
+
+ if libc_inet_anl and not ipv4:
+ new_dep = True
+ ipv4 = True
+
+ if libc_locale_code and not libc_posix_clang_wchar:
+ new_dep = True
+ libc_posix_clang_wchar = True
+
+ if libc_nis:
+ if not ipv4:
+ new_dep = True
+ ipv4 = True
+ if not libc_sunrpc:
+ new_dep = True
+ libc_sunrpc = True
+
+ if libc_rcmd and not ipv4:
+ new_dep = True
+ ipv4 = True
+
+ if libc_sunrpc and not ipv4:
+ new_dep = True
+ ipv4 = True
+
+ if libc_utmpx and not libc_utmp:
+ new_dep = True
+ libc_utmp = True
+
+ if libc_posix_regexp_glibc and not libc_posix_regexp:
+ new_dep = True
+ libc_posix_regexp = True
+
+ if libc_posix_wchar_io and not libc_posix_clang_wchar:
+ new_dep = True
+ libc_posix_clang_wchar = True
+
+ glibc_cfg(ipv6, 'OPTION_EGLIBC_ADVANCED_INET6', cnf)
+ glibc_cfg(libc_backtrace, 'OPTION_EGLIBC_BACKTRACE', cnf)
+ glibc_cfg(libc_big_macros, 'OPTION_EGLIBC_BIG_MACROS', cnf)
+ glibc_cfg(libc_bsd, 'OPTION_EGLIBC_BSD', cnf)
+ glibc_cfg(libc_cxx_tests, 'OPTION_EGLIBC_CXX_TESTS', cnf)
+ glibc_cfg(libc_catgets, 'OPTION_EGLIBC_CATGETS', cnf)
+ glibc_cfg(libc_charsets, 'OPTION_EGLIBC_CHARSETS', cnf)
+ glibc_cfg(libc_crypt, 'OPTION_EGLIBC_CRYPT', cnf)
+ glibc_cfg(libc_crypt_ufc, 'OPTION_EGLIBC_CRYPT_UFC', cnf)
+ glibc_cfg(libc_db_aliases, 'OPTION_EGLIBC_DB_ALIASES', cnf)
+ glibc_cfg(libc_envz, 'OPTION_EGLIBC_ENVZ', cnf)
+ glibc_cfg(libc_fcvt, 'OPTION_EGLIBC_FCVT', cnf)
+ glibc_cfg(libc_fmtmsg, 'OPTION_EGLIBC_FMTMSG', cnf)
+ glibc_cfg(libc_fstab, 'OPTION_EGLIBC_FSTAB', cnf)
+ glibc_cfg(libc_ftraverse, 'OPTION_EGLIBC_FTRAVERSE', cnf)
+ glibc_cfg(libc_getlogin, 'OPTION_EGLIBC_GETLOGIN', cnf)
+ glibc_cfg(libc_idn, 'OPTION_EGLIBC_IDN', cnf)
+ glibc_cfg(ipv4, 'OPTION_EGLIBC_INET', cnf)
+ glibc_cfg(libc_inet_anl, 'OPTION_EGLIBC_INET_ANL', cnf)
+ glibc_cfg(libc_libm, 'OPTION_EGLIBC_LIBM', cnf)
+ glibc_cfg(libc_locales, 'OPTION_EGLIBC_LOCALES', cnf)
+ glibc_cfg(libc_locale_code, 'OPTION_EGLIBC_LOCALE_CODE', cnf)
+ glibc_cfg(libc_memusage, 'OPTION_EGLIBC_MEMUSAGE', cnf)
+ glibc_cfg(libc_nis, 'OPTION_EGLIBC_NIS', cnf)
+ glibc_cfg(libc_nsswitch, 'OPTION_EGLIBC_NSSWITCH', cnf)
+ glibc_cfg(libc_rcmd, 'OPTION_EGLIBC_RCMD', cnf)
+ glibc_cfg(libc_rtld_debug, 'OPTION_EGLIBC_RTLD_DEBUG', cnf)
+ glibc_cfg(libc_spawn, 'OPTION_EGLIBC_SPAWN', cnf)
+ glibc_cfg(libc_streams, 'OPTION_EGLIBC_STREAMS', cnf)
+ glibc_cfg(libc_sunrpc, 'OPTION_EGLIBC_SUNRPC', cnf)
+ glibc_cfg(libc_utmp, 'OPTION_EGLIBC_UTMP', cnf)
+ glibc_cfg(libc_utmpx, 'OPTION_EGLIBC_UTMPX', cnf)
+ glibc_cfg(libc_wordexp, 'OPTION_EGLIBC_WORDEXP', cnf)
+ glibc_cfg(libc_posix_clang_wchar, 'OPTION_POSIX_C_LANG_WIDE_CHAR', cnf)
+ glibc_cfg(libc_posix_regexp, 'OPTION_POSIX_REGEXP', cnf)
+ glibc_cfg(libc_posix_regexp_glibc, 'OPTION_POSIX_REGEXP_GLIBC', cnf)
+ glibc_cfg(libc_posix_wchar_io, 'OPTION_POSIX_WIDE_CHAR_DEVICE_IO', cnf)
+
+ return "\n".join(cnf)
diff --git a/recipes-core/glibc/glibc-package.inc b/recipes-core/glibc/glibc-package.inc
new file mode 100644
index 0000000..a2a70f4
--- /dev/null
+++ b/recipes-core/glibc/glibc-package.inc
@@ -0,0 +1,227 @@
+INHIBIT_SYSROOT_STRIP = "1"
+
+PACKAGES = "${PN}-dbg catchsegv sln nscd ldd tzcode glibc-thread-db ${PN}-pic libcidn libmemusage libsegfault ${PN}-pcprofile libsotruss ${PN} ${PN}-utils glibc-extra-nss ${PN}-dev ${PN}-staticdev ${PN}-doc"
+
+# The ld.so in this glibc supports the GNU_HASH
+RPROVIDES_${PN} = "eglibc rtld(GNU_HASH)"
+RPROVIDES_${PN}-utils = "eglibc-utils"
+RPROVIDES_${PN}-mtrace = "eglibc-mtrace libc-mtrace"
+RPROVIDES_${PN}-pic = "eglibc-pic"
+RPROVIDES_${PN}-dev = "eglibc-dev libc6-dev virtual-libc-dev"
+RPROVIDES_${PN}-staticdev = "eglibc-staticdev"
+RPROVIDES_${PN}-doc = "eglibc-doc"
+RPROVIDES_glibc-extra-nss = "eglibc-extra-nss"
+RPROVIDES_glibc-thread-db = "eglibc-thread-db"
+RPROVIDES_${PN}-pcprofile = "eglibc-pcprofile"
+RPROVIDES_${PN}-dbg = "eglibc-dbg"
+libc_baselibs = "${base_libdir}/libcrypt*.so.* ${base_libdir}/libcrypt-*.so ${base_libdir}/libc.so.* ${base_libdir}/libc-*.so ${base_libdir}/libm*.so.* ${base_libdir}/libm-*.so ${base_libdir}/libmvec-*.so ${base_libdir}/ld*.so.* ${base_libdir}/ld-*.so ${base_libdir}/libpthread*.so.* ${base_libdir}/libpthread-*.so ${base_libdir}/libresolv*.so.* ${base_libdir}/libresolv-*.so ${base_libdir}/librt*.so.* ${base_libdir}/librt-*.so ${base_libdir}/libutil*.so.* ${base_libdir}/libutil-*.so ${base_libdir}/libnsl*.so.* ${base_libdir}/libnsl-*.so ${base_libdir}/libnss_files*.so.* ${base_libdir}/libnss_files-*.so ${base_libdir}/libnss_compat*.so.* ${base_libdir}/libnss_compat-*.so ${base_libdir}/libnss_dns*.so.* ${base_libdir}/libnss_dns-*.so ${base_libdir}/libdl*.so.* ${base_libdir}/libdl-*.so ${base_libdir}/libanl*.so.* ${base_libdir}/libanl-*.so ${base_libdir}/libBrokenLocale*.so.* ${base_libdir}/libBrokenLocale-*.so"
+libc_baselibs_append_aarch64 = " /lib/ld-linux-aarch64*.so.1"
+INSANE_SKIP_${PN}_append_aarch64 = " libdir"
+
+FILES_${PN} = "${libc_baselibs} ${libexecdir}/* ${base_sbindir}/ldconfig ${sysconfdir}/ld.so.conf"
+FILES_ldd = "${bindir}/ldd"
+FILES_libsegfault = "${base_libdir}/libSegFault*"
+FILES_libcidn = "${base_libdir}/libcidn-*.so ${base_libdir}/libcidn.so.*"
+FILES_libmemusage = "${base_libdir}/libmemusage.so"
+FILES_glibc-extra-nss = "${base_libdir}/libnss_*-*.so ${base_libdir}/libnss_*.so.*"
+FILES_sln = "${base_sbindir}/sln"
+FILES_${PN}-pic = "${libdir}/*_pic.a ${libdir}/*_pic.map ${libdir}/libc_pic/*.o"
+FILES_libsotruss = "${libdir}/audit/sotruss-lib.so"
+FILES_SOLIBSDEV = "${libdir}/lib*${SOLIBSDEV}"
+FILES_${PN}-dev += "${bindir}/rpcgen ${libdir}/*_nonshared.a ${base_libdir}/*_nonshared.a ${base_libdir}/*.o ${datadir}/aclocal"
+FILES_${PN}-staticdev += "${libdir}/*.a ${base_libdir}/*.a"
+FILES_nscd = "${sbindir}/nscd* ${sysconfdir}/init.d/nscd ${systemd_unitdir}/system/nscd* ${sysconfdir}/tmpfiles.d/nscd.conf \
+ ${sysconfdir}/nscd.conf ${sysconfdir}/default/volatiles/98_nscd ${localstatedir}/db/nscd"
+FILES_${PN}-mtrace = "${bindir}/mtrace"
+FILES_tzcode = "${bindir}/tzselect ${sbindir}/zic ${sbindir}/zdump"
+FILES_${PN}-utils = "${bindir}/* ${sbindir}/*"
+FILES_catchsegv = "${bindir}/catchsegv"
+RDEPENDS_catchsegv = "libsegfault"
+FILES_${PN}-pcprofile = "${base_libdir}/libpcprofile.so"
+FILES_glibc-thread-db = "${base_libdir}/libthread_db.so.* ${base_libdir}/libthread_db-*.so"
+RPROVIDES_${PN}-dev += "libc-dev"
+RPROVIDES_${PN}-staticdev += "libc-staticdev"
+
+SUMMARY_sln = "The static ln"
+DESCRIPTION_sln = "Similar to the 'ln' utility, but statically linked. sln is useful to make symbolic links to dynamic libraries if the dynamic linking system, for some reason, is not functional."
+SUMMARY_nscd = "Name service cache daemon"
+DESCRIPTION_nscd = "nscd, name service cache daemon, caches name service lookups for the passwd, group and hosts information. It can damatically improvide performance with remote, such as NIS or NIS+, name services."
+SUMMARY_glibc-extra-nss = "hesiod, NIS and NIS+ nss libraries"
+DESCRIPTION_glibc-extra-nss = "glibc: nis, nisplus and hesiod search services."
+SUMMARY_ldd = "print shared library dependencies"
+DESCRIPTION_ldd = "${bindir}/ldd prints shared library dependencies for each program or shared library specified on the command line."
+SUMMARY_${PN}-utils = "Miscellaneous utilities provided by glibc"
+DESCRIPTION_${PN}-utils = "Miscellaneous utilities including getconf, iconv, locale, gencat, rpcgen, ..."
+DESCRIPTION_libsotruss = "Library to support sotruss which traces calls through PLTs"
+DESCRIPTION_tzcode = "tzcode, timezone zoneinfo utils -- zic, zdump, tzselect"
+
+inherit libc-common multilib_header
+
+do_install_append () {
+ rm -f ${D}${sysconfdir}/localtime
+ rm -rf ${D}${localstatedir}
+
+ # remove empty glibc dir
+ if [ -d ${D}${libexecdir} ]; then
+ rmdir --ignore-fail-on-non-empty ${D}${libexecdir}
+ fi
+
+ oe_multilib_header bits/syscall.h
+
+ if [ -f ${D}${bindir}/mtrace ]; then
+ sed -i -e '1s,#!.*perl,#! ${USRBINPATH}/env perl,' -e '2s,exec.*perl,exec ${USRBINPATH}/env perl,' ${D}${bindir}/mtrace
+ fi
+ rm -rf ${D}${includedir}/rpcsvc/rquota*
+ # Info dir listing isn't interesting at this point so remove it if it exists.
+ if [ -e "${D}${infodir}/dir" ]; then
+ rm -f ${D}${infodir}/dir
+ fi
+
+ if ! ${@bb.utils.contains('DISTRO_FEATURES', 'ldconfig', 'true', 'false', d)}; then
+ # The distro doesn't want these files so let's not install them
+ rm -f ${D}${sysconfdir}/ld.so.conf
+ rm -f ${D}${base_sbindir}/ldconfig
+ # This directory will be empty now so remove it too.
+ # But check whether it exists first, since it won't for glibc-initial.
+ if [ -d ${D}${sysconfdir} ]; then
+ rmdir ${D}${sysconfdir}
+ fi
+ fi
+
+ if echo ${PN}|grep -q "glibc-initial"; then
+ return
+ fi
+
+ install -d ${D}${sysconfdir}/init.d
+ install -d ${D}${localstatedir}/db/nscd
+ install -m 0755 ${S}/nscd/nscd.init ${D}${sysconfdir}/init.d/nscd
+ install -m 0755 ${S}/nscd/nscd.conf ${D}${sysconfdir}/nscd.conf
+ sed -i "s%daemon%start-stop-daemon --start --exec%g" ${D}${sysconfdir}/init.d/nscd
+
+ install -d ${D}${systemd_unitdir}/system
+ install -m 0644 ${S}/nscd/nscd.service ${D}${systemd_unitdir}/system/
+
+ if ${@bb.utils.contains('DISTRO_FEATURES', 'systemd', 'true', 'false', d)}; then
+ install -d ${D}${sysconfdir}/tmpfiles.d
+ echo "d /run/nscd 755 root root -" \
+ > ${D}${sysconfdir}/tmpfiles.d/nscd.conf
+ else
+ install -d ${D}${sysconfdir}/default/volatiles
+ echo "d root root 0755 /var/run/nscd none" \
+ > ${D}${sysconfdir}/default/volatiles/98_nscd
+ fi
+}
+
+do_install_append_aarch64 () {
+ if [ "${base_libdir}" != "/lib" ] ; then
+ # The aarch64 ABI says the dynamic linker -must- be /lib/ld-linux-aarch64[_be].so.1
+ install -d ${D}/lib
+ if [ -e ${D}${base_libdir}/ld-linux-aarch64.so.1 ]; then
+ ln -s ${@base_path_relative('/lib', '${base_libdir}')}/ld-linux-aarch64.so.1 \
+ ${D}/lib/ld-linux-aarch64.so.1
+ elif [ -e ${D}${base_libdir}/ld-linux-aarch64_be.so.1 ]; then
+ ln -s ${@base_path_relative('/lib', '${base_libdir}')}/ld-linux-aarch64_be.so.1 \
+ ${D}/lib/ld-linux-aarch64_be.so.1
+ fi
+ fi
+ do_install_armmultilib
+}
+
+do_install_append_arm () {
+ do_install_armmultilib
+}
+
+do_install_append_armeb () {
+ do_install_armmultilib
+}
+
+do_install_armmultilib () {
+
+ oe_multilib_header bits/endian.h bits/fcntl.h bits/fenv.h bits/fp-fast.h bits/hwcap.h bits/ipc.h bits/link.h bits/wordsize.h
+ oe_multilib_header bits/local_lim.h bits/mman.h bits/msq.h bits/pthreadtypes.h bits/pthreadtypes-arch.h bits/sem.h bits/semaphore.h bits/setjmp.h
+ oe_multilib_header bits/shm.h bits/sigstack.h bits/stat.h bits/statfs.h bits/typesizes.h
+
+ oe_multilib_header fpu_control.h gnu/lib-names.h gnu/stubs.h ieee754.h
+
+ oe_multilib_header sys/elf.h sys/procfs.h sys/ptrace.h sys/ucontext.h sys/user.h
+}
+
+
+LOCALESTASH = "${WORKDIR}/stashed-locale"
+bashscripts = "mtrace sotruss xtrace"
+
+do_stash_locale () {
+ dest=${LOCALESTASH}
+ install -d ${dest}${base_libdir} ${dest}${bindir} ${dest}${libdir} ${dest}${datadir}
+ if [ "${base_libdir}" != "${libdir}" ]; then
+ cp -fpPR ${D}${base_libdir}/* ${dest}${base_libdir}
+ fi
+ if [ -e ${D}${bindir}/localedef ]; then
+ mv -f ${D}${bindir}/localedef ${dest}${bindir}
+ fi
+ if [ -e ${D}${libdir}/gconv ]; then
+ mv -f ${D}${libdir}/gconv ${dest}${libdir}
+ fi
+ if [ -e ${D}${exec_prefix}/lib ]; then
+ cp -fpPR ${D}${exec_prefix}/lib ${dest}${exec_prefix}
+ fi
+ if [ -e ${D}${datadir}/i18n ]; then
+ mv ${D}${datadir}/i18n ${dest}${datadir}
+ fi
+ cp -fpPR ${D}${datadir}/* ${dest}${datadir}
+ rm -rf ${D}${datadir}/locale/
+ cp -fpPR ${WORKDIR}/SUPPORTED ${dest}
+
+ target=${dest}/scripts
+ mkdir -p $target
+ for i in ${bashscripts}; do
+ if [ -f ${D}${bindir}/$i ]; then
+ cp ${D}${bindir}/$i $target/
+ fi
+ done
+}
+
+addtask do_stash_locale after do_install before do_populate_sysroot do_package
+do_stash_locale[dirs] = "${B}"
+do_stash_locale[cleandirs] = "${LOCALESTASH}"
+SSTATETASKS += "do_stash_locale"
+do_stash_locale[sstate-inputdirs] = "${LOCALESTASH}"
+do_stash_locale[sstate-outputdirs] = "${COMPONENTS_DIR}/${PACKAGE_ARCH}/glibc-stash-locale"
+do_stash_locale[sstate-fixmedir] = "${COMPONENTS_DIR}/${PACKAGE_ARCH}/glibc-stash-locale"
+
+python do_stash_locale_setscene () {
+ sstate_setscene(d)
+}
+addtask do_stash_locale_setscene
+
+do_poststash_install_cleanup () {
+ # Remove all files which do_stash_locale would remove (mv)
+ # since that task could have come from sstate and not get run.
+ for i in ${bashscripts}; do
+ rm -f ${D}${bindir}/$i
+ done
+ rm -f ${D}${bindir}/localedef
+ rm -rf ${D}${datadir}/i18n
+ rm -rf ${D}${libdir}/gconv
+ rm -rf ${D}/${localedir}
+ rm -rf ${D}${datadir}/locale
+ if [ "${libdir}" != "${exec_prefix}/lib" ]; then
+ # This dir only exists to hold locales
+ rm -rf ${D}${exec_prefix}/lib
+ fi
+}
+addtask do_poststash_install_cleanup after do_stash_locale do_install before do_populate_sysroot do_package
+
+pkg_postinst_nscd () {
+ if [ -z "$D" ]; then
+ if command -v systemd-tmpfiles >/dev/null; then
+ systemd-tmpfiles --create ${sysconfdir}/tmpfiles.d/nscd.conf
+ elif [ -e ${sysconfdir}/init.d/populate-volatile.sh ]; then
+ ${sysconfdir}/init.d/populate-volatile.sh update
+ fi
+ fi
+}
+CONFFILES_nscd="${sysconfdir}/nscd.conf"
+
+SYSTEMD_PACKAGES = "nscd"
+SYSTEMD_SERVICE_nscd = "nscd.service"
diff --git a/recipes-core/glibc/glibc-scripts_2.20.bb b/recipes-core/glibc/glibc-scripts_2.20.bb
new file mode 100644
index 0000000..674cd80
--- /dev/null
+++ b/recipes-core/glibc/glibc-scripts_2.20.bb
@@ -0,0 +1 @@
+require recipes-core/glibc/glibc-scripts.inc
diff --git a/recipes-core/glibc/glibc-testing.inc b/recipes-core/glibc/glibc-testing.inc
new file mode 100644
index 0000000..ec16fe1
--- /dev/null
+++ b/recipes-core/glibc/glibc-testing.inc
@@ -0,0 +1,79 @@
+do_compile_append () {
+ # now generate script to drive testing
+ echo "#!/usr/bin/env sh" >${B}/${HOST_PREFIX}testglibc
+ set >> ${B}/${HOST_PREFIX}testglibc
+ # prune out the unneeded vars
+ sed -i -e "/^BASH/d" ${B}/${HOST_PREFIX}testglibc
+ sed -i -e "/^USER/d" ${B}/${HOST_PREFIX}testglibc
+ sed -i -e "/^OPT/d" ${B}/${HOST_PREFIX}testglibc
+ sed -i -e "/^DIRSTACK/d" ${B}/${HOST_PREFIX}testglibc
+ sed -i -e "/^EUID/d" ${B}/${HOST_PREFIX}testglibc
+ sed -i -e "/^FUNCNAME/d" ${B}/${HOST_PREFIX}testglibc
+ sed -i -e "/^GROUPS/d" ${B}/${HOST_PREFIX}testglibc
+ sed -i -e "/^HOST/d" ${B}/${HOST_PREFIX}testglibc
+ sed -i -e "/^HOME/d" ${B}/${HOST_PREFIX}testglibc
+ sed -i -e "/^IFS/d" ${B}/${HOST_PREFIX}testglibc
+ sed -i -e "/^LC_ALL/d" ${B}/${HOST_PREFIX}testglibc
+ sed -i -e "/^LOGNAME/d" ${B}/${HOST_PREFIX}testglibc
+ sed -i -e "/^MACHTYPE/d" ${B}/${HOST_PREFIX}testglibc
+ sed -i -e "/^OSTYPE/d" ${B}/${HOST_PREFIX}testglibc
+ sed -i -e "/^PIPE/d" ${B}/${HOST_PREFIX}testglibc
+ sed -i -e "/^SHELL/d" ${B}/${HOST_PREFIX}testglibc
+ sed -i -e "/^'/d" ${B}/${HOST_PREFIX}testglibc
+ sed -i -e "/^UID/d" ${B}/${HOST_PREFIX}testglibc
+ sed -i -e "/^TERM/d" ${B}/${HOST_PREFIX}testglibc
+ sed -i -e "/^PATCH_GET/d" ${B}/${HOST_PREFIX}testglibc
+ sed -i -e "/^PKG_/d" ${B}/${HOST_PREFIX}testglibc
+ sed -i -e "/^POSIXLY_/d" ${B}/${HOST_PREFIX}testglibc
+ sed -i -e "/^PPID/d" ${B}/${HOST_PREFIX}testglibc
+ sed -i -e "/^PS4/d" ${B}/${HOST_PREFIX}testglibc
+ sed -i -e "/^Q/d" ${B}/${HOST_PREFIX}testglibc
+ sed -i -e "/^SHLVL/d" ${B}/${HOST_PREFIX}testglibc
+ sed -i -e "/^STAGING/d" ${B}/${HOST_PREFIX}testglibc
+ sed -i -e "/^LD_LIBRARY_PATH/d" ${B}/${HOST_PREFIX}testglibc
+ sed -i -e "/^PSEUDO/d" ${B}/${HOST_PREFIX}testglibc
+
+ # point to real sysroot not the toolchain bootstrap sysroot
+ sed -i -e "s/\-tcbootstrap//g" ${B}/${HOST_PREFIX}testglibc
+
+ # use the final cross-gcc to test since some tests need libstdc++
+ sed -i -e "s/^PATH=.*\.gcc-cross-initial\:/PATH=/g" ${B}/${HOST_PREFIX}testglibc
+
+ # append execution part script
+cat >> ${B}/${HOST_PREFIX}testglibc << STOP
+target="\$1"
+if [ "x\$target" = "x" ]
+then
+ echo "Please specify the target machine and remote user in form of user at target"
+ exit 1;
+fi
+ssh \$target ls \$PWD\ 2>&1 > /dev/null
+if [ "x\$?" != "x0" ]
+then
+ echo "Failed connecting to \$target it could be because of:"
+ echo "1. You dont have passwordless ssh setup to access \$target"
+ echo "2. NFS share on \$target is not mounted or if mounted then not matching the build tree layout."
+ echo " The tree should be accessible at same location on build host and target"
+ echo " You can add nfs-server to IMAGE_FEATURES to get the nfs client on target"
+ echo "3. nfs server on build host is not running."
+ echo " Please make sure that you have 'no_root_squash' added in /etc/exports if you want"
+ echo " to test as root user on target (usually its recommended to create a non"
+ echo " root user."
+ echo " As a sanity check make sure that target can read/write to the glibc build tree"
+ echo " Please refer to ${S}/EGLIBC.cross-testing for further instructions on setup"
+ exit 1
+fi
+ echo "# we test using cross compiler from real sysroot therefore override the" > ${B}/configparms
+ echo "# definitions that come from ${B}/config.make" >> ${B}/configparms
+
+ fgrep tcbootstrap ${B}/config.make > ${B}/configparms
+ sed -i -e "s/\-tcbootstrap//g" ${B}/configparms
+wrapper="${S}/scripts/cross-test-ssh.sh \$target"
+localedef="${STAGING_BINDIR_NATIVE}/cross-localedef --little-endian --uint32-align=4"
+make tests-clean
+make cross-localedef="\$localedef" cross-test-wrapper="\$wrapper" -k check
+rm -rf ${B}/configparms
+STOP
+
+ chmod +x ${B}/${HOST_PREFIX}testglibc
+}
diff --git a/recipes-core/glibc/glibc/0001-R_ARM_TLS_DTPOFF32.patch b/recipes-core/glibc/glibc/0001-R_ARM_TLS_DTPOFF32.patch
new file mode 100644
index 0000000..3922cb8
--- /dev/null
+++ b/recipes-core/glibc/glibc/0001-R_ARM_TLS_DTPOFF32.patch
@@ -0,0 +1,56 @@
+
+Quote from bug 1443 which explains what the patch does :
+
+ We build some random program and link it with -lust. When we run it,
+ it dies with a SIGSEGV before reaching main().
+
+ Libust.so depends on liburcu-bp.so from the usermode-rcu package.
+ Although libust.so is not prelinked, liburcu-bp.so IS prelinked; this
+ is critical.
+
+ Libust.so uses a TLS / __thread variable that is defined in liburcu-
+ bp.so. There are special ARM-specific relocation types that allow two
+ shared libraries to share thread-specific data. This is critical too.
+
+ One more critical issue: although liburcu-bp.so is prelinked, we can't
+ load it at its prelinked address, because we also link against
+ librt.so, and librt.so uses that address.
+
+ The dynamic linker is forced to relink liburcu-bp.so at a different
+ address. In the course of relinking, it processes the special ARM
+ relocation record mentioned above. The prelinker has already filled
+ in the information, which is a short offset into a table of thread-
+ specific data that is allocated per-thread for each library that uses
+ TLS. Because the normal behavior of a relocation is to add the symbol
+ value to an addend stored at the address being relocated, we end up
+ adding the short offset to itself, doubling it.
+
+ Now we have an awkward situation. The libust.so library doesn't know
+ about the addend, so its TLS data for this element is correct. The
+ liburcu-bp.so library has a different offset for the element. When we
+ go to initialize the element for the first time in liburcu-bp.so, we
+ write the address of the result at the doubled (broken) offset.
+ Later, when we refer to the address from libust.so, we check the value
+ at the correct offset, but it's NULL, so we eat hot SIGSEGV.
+
+Upstream-Status: Pending
+
+Signed-off-by: Andrei Dinu <andrei.adrianx.dinu at intel.com>
+---
+ .../libc/ports/sysdeps/arm/dl-machine.h | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+ndex 8d905e8..dcfa71e 100644
+Index: git/sysdeps/arm/dl-machine.h
+===================================================================
+--- git.orig/sysdeps/arm/dl-machine.h 2014-08-27 05:30:47.748070587 +0000
++++ git/sysdeps/arm/dl-machine.h 2014-08-27 05:30:47.740070587 +0000
+@@ -495,7 +495,7 @@
+
+ case R_ARM_TLS_DTPOFF32:
+ if (sym != NULL)
+- *reloc_addr += sym->st_value;
++ *reloc_addr = sym->st_value;
+ break;
+
+ case R_ARM_TLS_TPOFF32:
diff --git a/recipes-core/glibc/glibc/0001-eglibc-run-libm-err-tab.pl-with-specific-dirs-in-S.patch b/recipes-core/glibc/glibc/0001-eglibc-run-libm-err-tab.pl-with-specific-dirs-in-S.patch
new file mode 100644
index 0000000..f341282
--- /dev/null
+++ b/recipes-core/glibc/glibc/0001-eglibc-run-libm-err-tab.pl-with-specific-dirs-in-S.patch
@@ -0,0 +1,33 @@
+From 713d822908d1b2ae8403af7f9375c7054ed3dd49 Mon Sep 17 00:00:00 2001
+From: Ting Liu <b28495 at freescale.com>
+Date: Wed, 19 Dec 2012 04:39:57 -0600
+Subject: [PATCH] eglibc: run libm-err-tab.pl with specific dirs in ${S}
+
+libm-err-tab.pl will parse all the files named "libm-test-ulps"
+in the given dir recursively. To avoid parsing the one in
+${S}/.pc/ (it does exist after eglibc adds aarch64 support,
+${S}/.pc/aarch64-0001-glibc-fsf-v1-eaf6f205.patch/ports/sysdeps/
+aarch64/libm-test-ulps), run libm-err-tab.pl with specific dirs
+in ${S}.
+
+Upstream-Status: inappropriate [OE specific]
+
+Signed-off-by: Ting Liu <b28495 at freescale.com>
+---
+ manual/Makefile | 3 ++-
+ 1 file changed, 2 insertions(+), 1 deletion(-)
+
+Index: git/manual/Makefile
+===================================================================
+--- git.orig/manual/Makefile 2014-08-29 10:35:18.728070587 -0700
++++ git/manual/Makefile 2014-08-29 10:35:18.720070587 -0700
+@@ -105,7 +105,8 @@
+ $(objpfx)stamp-libm-err: libm-err-tab.pl $(wildcard $(foreach dir,$(sysdirs),\
+ $(dir)/libm-test-ulps))
+ pwd=`pwd`; \
+- $(PERL) $< $$pwd/.. > $(objpfx)libm-err-tmp
++ $(PERL) $< $$pwd/../ports > $(objpfx)libm-err-tmp
++ $(PERL) $< $$pwd/../sysdeps >> $(objpfx)libm-err-tmp
+ $(move-if-change) $(objpfx)libm-err-tmp $(objpfx)libm-err.texi
+ touch $@
+
diff --git a/recipes-core/glibc/glibc/0017-timezone-re-written-tzselect-as-posix-sh.patch b/recipes-core/glibc/glibc/0017-timezone-re-written-tzselect-as-posix-sh.patch
new file mode 100644
index 0000000..0ce8230
--- /dev/null
+++ b/recipes-core/glibc/glibc/0017-timezone-re-written-tzselect-as-posix-sh.patch
@@ -0,0 +1,45 @@
+From c90306107fbbe2979012917e87747ce78c82ab88 Mon Sep 17 00:00:00 2001
+From: Khem Raj <raj.khem at gmail.com>
+Date: Wed, 18 Mar 2015 00:33:03 +0000
+Subject: [PATCH 17/27] timezone: re-written tzselect as posix sh
+
+To avoid the bash dependency.
+
+Upstream-Status: Pending
+
+Signed-off-by: Hongxu Jia <hongxu.jia at windriver.com>
+Signed-off-by: Khem Raj <raj.khem at gmail.com>
+---
+ timezone/Makefile | 2 +-
+ timezone/tzselect.ksh | 2 +-
+ 2 files changed, 2 insertions(+), 2 deletions(-)
+
+diff --git a/timezone/Makefile b/timezone/Makefile
+index 24c93c6..886b06e 100644
+--- a/timezone/Makefile
++++ b/timezone/Makefile
+@@ -126,7 +126,7 @@ $(testdata)/XT%: testdata/XT%
+ cp $< $@
+
+ $(objpfx)tzselect: tzselect.ksh $(common-objpfx)config.make
+- sed -e 's|/bin/bash|$(BASH)|' \
++ sed -e 's|/bin/bash|/bin/sh|' \
+ -e 's|TZDIR=[^}]*|TZDIR=$(zonedir)|' \
+ -e '/TZVERSION=/s|see_Makefile|"$(version)"|' \
+ -e '/PKGVERSION=/s|=.*|="$(PKGVERSION)"|' \
+diff --git a/timezone/tzselect.ksh b/timezone/tzselect.ksh
+index 9d70691..25f45a8 100755
+--- a/timezone/tzselect.ksh
++++ b/timezone/tzselect.ksh
+@@ -35,7 +35,7 @@ REPORT_BUGS_TO=tz at iana.org
+
+ # Specify default values for environment variables if they are unset.
+ : ${AWK=awk}
+-: ${TZDIR=`pwd`}
++: ${TZDIR=$(pwd)}
+
+ # Check for awk Posix compliance.
+ ($AWK -v x=y 'BEGIN { exit 123 }') </dev/null >/dev/null 2>&1
+--
+2.1.4
+
diff --git a/recipes-core/glibc/glibc/0018-eglibc-Cross-building-and-testing-instructions.patch b/recipes-core/glibc/glibc/0018-eglibc-Cross-building-and-testing-instructions.patch
new file mode 100644
index 0000000..8eacbc0
--- /dev/null
+++ b/recipes-core/glibc/glibc/0018-eglibc-Cross-building-and-testing-instructions.patch
@@ -0,0 +1,619 @@
+From eff048074ac7b5258bb615e5a5b221daa19b18ae Mon Sep 17 00:00:00 2001
+From: Khem Raj <raj.khem at gmail.com>
+Date: Wed, 18 Mar 2015 00:42:58 +0000
+Subject: [PATCH 18/27] eglibc: Cross building and testing instructions
+
+Ported from eglibc
+Upstream-Status: Pending
+
+Signed-off-by: Khem Raj <raj.khem at gmail.com>
+---
+ GLIBC.cross-building | 383 +++++++++++++++++++++++++++++++++++++++++++++++++++
+ GLIBC.cross-testing | 205 +++++++++++++++++++++++++++
+ 2 files changed, 588 insertions(+)
+ create mode 100644 GLIBC.cross-building
+ create mode 100644 GLIBC.cross-testing
+
+diff --git a/GLIBC.cross-building b/GLIBC.cross-building
+new file mode 100644
+index 0000000..e6e0da1
+--- /dev/null
++++ b/GLIBC.cross-building
+@@ -0,0 +1,383 @@
++ -*- mode: text -*-
++
++ Cross-Compiling GLIBC
++ Jim Blandy <jimb at codesourcery.com>
++
++
++Introduction
++
++Most GNU tools have a simple build procedure: you run their
++'configure' script, and then you run 'make'. Unfortunately, the
++process of cross-compiling the GNU C library is quite a bit more
++involved:
++
++1) Build a cross-compiler, with certain facilities disabled.
++
++2) Configure the C library using the compiler you built in step 1).
++ Build a few of the C run-time object files, but not the rest of the
++ library. Install the library's header files and the run-time
++ object files, and create a dummy libc.so.
++
++3) Build a second cross-compiler, using the header files and object
++ files you installed in step 2.
++
++4) Configure, build, and install a fresh C library, using the compiler
++ built in step 3.
++
++5) Build a third cross-compiler, based on the C library built in step 4.
++
++The reason for this complexity is that, although GCC and the GNU C
++library are distributed separately, they are not actually independent
++of each other: GCC requires the C library's headers and some object
++files to compile its own libraries, while the C library depends on
++GCC's libraries. GLIBC includes features and bug fixes to the stock
++GNU C library that simplify this process, but the fundamental
++interdependency stands.
++
++In this document, we explain how to cross-compile an GLIBC/GCC pair
++from source. Our intended audience is developers who are already
++familiar with the GNU toolchain and comfortable working with
++cross-development tools. While we do present a worked example to
++accompany the explanation, for clarity's sake we do not cover many of
++the options available to cross-toolchain users.
++
++
++Preparation
++
++GLIBC requires recent versions of the GNU binutils, GCC, and the
++Linux kernel. The web page <http://www.eglibc.org/prerequisites>
++documents the current requirements, and lists patches needed for
++certain target architectures. As of this writing, these build
++instructions have been tested with binutils 2.22.51, GCC 4.6.2,
++and Linux 3.1.
++
++First, let's set some variables, to simplify later commands. We'll
++build GLIBC and GCC for an ARM target, known to the Linux kernel
++as 'arm', and we'll do the build on an Intel x86_64 Linux box:
++
++ $ build=x86_64-pc-linux-gnu
++ $ host=$build
++ $ target=arm-none-linux-gnueabi
++ $ linux_arch=arm
++
++We're using the aforementioned versions of Binutils, GCC, and Linux:
++
++ $ binutilsv=binutils-2.22.51
++ $ gccv=gcc-4.6.2
++ $ linuxv=linux-3.1
++
++We're carrying out the entire process under '~/cross-build', which
++contains unpacked source trees for binutils, gcc, and linux kernel,
++along with GLIBC svn trunk (which can be checked-out with
++'svn co http://www.eglibc.org/svn/trunk eglibc'):
++
++ $ top=$HOME/cross-build/$target
++ $ src=$HOME/cross-build/src
++ $ ls $src
++ binutils-2.22.51 glibc gcc-4.6.2 linux-3.1
++
++We're going to place our build directories in a subdirectory 'obj',
++we'll install the cross-development toolchain in 'tools', and we'll
++place our sysroot (containing files to be installed on the target
++system) in 'sysroot':
++
++ $ obj=$top/obj
++ $ tools=$top/tools
++ $ sysroot=$top/sysroot
++
++
++Binutils
++
++Configuring and building binutils for the target is straightforward:
++
++ $ mkdir -p $obj/binutils
++ $ cd $obj/binutils
++ $ $src/$binutilsv/configure \
++ > --target=$target \
++ > --prefix=$tools \
++ > --with-sysroot=$sysroot
++ $ make
++ $ make install
++
++
++The First GCC
++
++For our work, we need a cross-compiler targeting an ARM Linux
++system. However, that configuration includes the shared library
++'libgcc_s.so', which is compiled against the GLIBC headers (which we
++haven't installed yet) and linked against 'libc.so' (which we haven't
++built yet).
++
++Fortunately, there are configuration options for GCC which tell it not
++to build 'libgcc_s.so'. The '--without-headers' option is supposed to
++take care of this, but its implementation is incomplete, so you must
++also configure with the '--with-newlib' option. While '--with-newlib'
++appears to mean "Use the Newlib C library", its effect is to tell the
++GCC build machinery, "Don't assume there is a C library available."
++
++We also need to disable some of the libraries that would normally be
++built along with GCC, and specify that only the compiler for the C
++language is needed.
++
++So, we create a build directory, configure, make, and install.
++
++ $ mkdir -p $obj/gcc1
++ $ cd $obj/gcc1
++ $ $src/$gccv/configure \
++ > --target=$target \
++ > --prefix=$tools \
++ > --without-headers --with-newlib \
++ > --disable-shared --disable-threads --disable-libssp \
++ > --disable-libgomp --disable-libmudflap --disable-libquadmath \
++ > --disable-decimal-float --disable-libffi \
++ > --enable-languages=c
++ $ PATH=$tools/bin:$PATH make
++ $ PATH=$tools/bin:$PATH make install
++
++
++Linux Kernel Headers
++
++To configure GLIBC, we also need Linux kernel headers in place.
++Fortunately, the Linux makefiles have a target that installs them for
++us. Since the process does modify the source tree a bit, we make a
++copy first:
++
++ $ cp -r $src/$linuxv $obj/linux
++ $ cd $obj/linux
++
++Now we're ready to install the headers into the sysroot:
++
++ $ PATH=$tools/bin:$PATH \
++ > make headers_install \
++ > ARCH=$linux_arch CROSS_COMPILE=$target- \
++ > INSTALL_HDR_PATH=$sysroot/usr
++
++
++GLIBC Headers and Preliminary Objects
++
++Using the cross-compiler we've just built, we can now configure GLIBC
++well enough to install the headers and build the object files that the
++full cross-compiler will need:
++
++ $ mkdir -p $obj/glibc-headers
++ $ cd $obj/glibc-headers
++ $ BUILD_CC=gcc \
++ > CC=$tools/bin/$target-gcc \
++ > CXX=$tools/bin/$target-g++ \
++ > AR=$tools/bin/$target-ar \
++ > RANLIB=$tools/bin/$target-ranlib \
++ > $src/glibc/libc/configure \
++ > --prefix=/usr \
++ > --with-headers=$sysroot/usr/include \
++ > --build=$build \
++ > --host=$target \
++ > --disable-profile --without-gd --without-cvs \
++ > --enable-add-ons=nptl,libidn,../ports
++
++The option '--prefix=/usr' may look strange, but you should never
++configure GLIBC with a prefix other than '/usr': in various places,
++GLIBC's build system checks whether the prefix is '/usr', and does
++special handling only if that is the case. Unless you use this
++prefix, you will get a sysroot that does not use the standard Linux
++directory layouts and cannot be used as a basis for the root
++filesystem on your target system compatibly with normal GLIBC
++installations.
++
++The '--with-headers' option tells GLIBC where the Linux headers have
++been installed.
++
++The '--enable-add-ons=nptl,libidn,../ports' option tells GLIBC to look
++for the listed glibc add-ons. Most notably the ports add-on (located
++just above the libc sources in the GLIBC svn tree) is required to
++support ARM targets.
++
++We can now use the 'install-headers' makefile target to install the
++headers:
++
++ $ make install-headers install_root=$sysroot \
++ > install-bootstrap-headers=yes
++
++The 'install_root' variable indicates where the files should actually
++be installed; its value is treated as the parent of the '--prefix'
++directory we passed to the configure script, so the headers will go in
++'$sysroot/usr/include'. The 'install-bootstrap-headers' variable
++requests special handling for certain tricky header files.
++
++Next, there are a few object files needed to link shared libraries,
++which we build and install by hand:
++
++ $ mkdir -p $sysroot/usr/lib
++ $ make csu/subdir_lib
++ $ cp csu/crt1.o csu/crti.o csu/crtn.o $sysroot/usr/lib
++
++Finally, 'libgcc_s.so' requires a 'libc.so' to link against. However,
++since we will never actually execute its code, it doesn't matter what
++it contains. So, treating '/dev/null' as a C source file, we produce
++a dummy 'libc.so' in one step:
++
++ $ $tools/bin/$target-gcc -nostdlib -nostartfiles -shared -x c /dev/null \
++ > -o $sysroot/usr/lib/libc.so
++
++
++The Second GCC
++
++With the GLIBC headers and selected object files installed, we can
++now build a GCC that is capable of compiling GLIBC. We configure,
++build, and install the second GCC, again building only the C compiler,
++and avoiding libraries we won't use:
++
++ $ mkdir -p $obj/gcc2
++ $ cd $obj/gcc2
++ $ $src/$gccv/configure \
++ > --target=$target \
++ > --prefix=$tools \
++ > --with-sysroot=$sysroot \
++ > --disable-libssp --disable-libgomp --disable-libmudflap \
++ > --disable-libffi --disable-libquadmath \
++ > --enable-languages=c
++ $ PATH=$tools/bin:$PATH make
++ $ PATH=$tools/bin:$PATH make install
++
++
++GLIBC, Complete
++
++With the second compiler built and installed, we're now ready for the
++full GLIBC build:
++
++ $ mkdir -p $obj/glibc
++ $ cd $obj/glibc
++ $ BUILD_CC=gcc \
++ > CC=$tools/bin/$target-gcc \
++ > CXX=$tools/bin/$target-g++ \
++ > AR=$tools/bin/$target-ar \
++ > RANLIB=$tools/bin/$target-ranlib \
++ > $src/glibc/libc/configure \
++ > --prefix=/usr \
++ > --with-headers=$sysroot/usr/include \
++ > --with-kconfig=$obj/linux/scripts/kconfig \
++ > --build=$build \
++ > --host=$target \
++ > --disable-profile --without-gd --without-cvs \
++ > --enable-add-ons=nptl,libidn,../ports
++
++Note the additional '--with-kconfig' option. This tells GLIBC where to
++find the host config tools used by the kernel 'make config' and 'make
++menuconfig'. These tools can be re-used by GLIBC for its own 'make
++*config' support, which will create 'option-groups.config' for you.
++But first make sure those tools have been built by running some
++dummy 'make *config' calls in the kernel directory:
++
++ $ cd $obj/linux
++ $ PATH=$tools/bin:$PATH make config \
++ > ARCH=$linux_arch CROSS_COMPILE=$target- \
++ $ PATH=$tools/bin:$PATH make menuconfig \
++ > ARCH=$linux_arch CROSS_COMPILE=$target- \
++
++Now we can configure and build the full GLIBC:
++
++ $ cd $obj/glibc
++ $ PATH=$tools/bin:$PATH make defconfig
++ $ PATH=$tools/bin:$PATH make menuconfig
++ $ PATH=$tools/bin:$PATH make
++ $ PATH=$tools/bin:$PATH make install install_root=$sysroot
++
++At this point, we have a complete GLIBC installation in '$sysroot',
++with header files, library files, and most of the C runtime startup
++files in place.
++
++
++The Third GCC
++
++Finally, we recompile GCC against this full installation, enabling
++whatever languages and libraries we would like to use:
++
++ $ mkdir -p $obj/gcc3
++ $ cd $obj/gcc3
++ $ $src/$gccv/configure \
++ > --target=$target \
++ > --prefix=$tools \
++ > --with-sysroot=$sysroot \
++ > --enable-__cxa_atexit \
++ > --disable-libssp --disable-libgomp --disable-libmudflap \
++ > --enable-languages=c,c++
++ $ PATH=$tools/bin:$PATH make
++ $ PATH=$tools/bin:$PATH make install
++
++The '--enable-__cxa_atexit' option tells GCC what sort of C++
++destructor support to expect from the C library; it's required with
++GLIBC.
++
++And since GCC's installation process isn't designed to help construct
++sysroot trees, we must manually copy certain libraries into place in
++the sysroot.
++
++ $ cp -d $tools/$target/lib/libgcc_s.so* $sysroot/lib
++ $ cp -d $tools/$target/lib/libstdc++.so* $sysroot/usr/lib
++
++
++Trying Things Out
++
++At this point, '$tools' contains a cross toolchain ready to use
++the GLIBC installation in '$sysroot':
++
++ $ cat > hello.c <<EOF
++ > #include <stdio.h>
++ > int
++ > main (int argc, char **argv)
++ > {
++ > puts ("Hello, world!");
++ > return 0;
++ > }
++ > EOF
++ $ $tools/bin/$target-gcc -Wall hello.c -o hello
++ $ cat > c++-hello.cc <<EOF
++ > #include <iostream>
++ > int
++ > main (int argc, char **argv)
++ > {
++ > std::cout << "Hello, C++ world!" << std::endl;
++ > return 0;
++ > }
++ > EOF
++ $ $tools/bin/$target-g++ -Wall c++-hello.cc -o c++-hello
++
++
++We can use 'readelf' to verify that these are indeed executables for
++our target, using our dynamic linker:
++
++ $ $tools/bin/$target-readelf -hl hello
++ ELF Header:
++ ...
++ Type: EXEC (Executable file)
++ Machine: ARM
++
++ ...
++ Program Headers:
++ Type Offset VirtAddr PhysAddr FileSiz MemSiz Flg Align
++ PHDR 0x000034 0x10000034 0x10000034 0x00100 0x00100 R E 0x4
++ INTERP 0x000134 0x00008134 0x00008134 0x00013 0x00013 R 0x1
++ [Requesting program interpreter: /lib/ld-linux.so.3]
++ LOAD 0x000000 0x00008000 0x00008000 0x0042c 0x0042c R E 0x8000
++ ...
++
++Looking at the dynamic section of the installed 'libgcc_s.so', we see
++that the 'NEEDED' entry for the C library does include the '.6'
++suffix, indicating that was linked against our fully build GLIBC, and
++not our dummy 'libc.so':
++
++ $ $tools/bin/$target-readelf -d $sysroot/lib/libgcc_s.so.1
++ Dynamic section at offset 0x1083c contains 24 entries:
++ Tag Type Name/Value
++ 0x00000001 (NEEDED) Shared library: [libc.so.6]
++ 0x0000000e (SONAME) Library soname: [libgcc_s.so.1]
++ ...
++
++
++And on the target machine, we can run our programs:
++
++ $ $sysroot/lib/ld.so.1 --library-path $sysroot/lib:$sysroot/usr/lib \
++ > ./hello
++ Hello, world!
++ $ $sysroot/lib/ld.so.1 --library-path $sysroot/lib:$sysroot/usr/lib \
++ > ./c++-hello
++ Hello, C++ world!
+diff --git a/GLIBC.cross-testing b/GLIBC.cross-testing
+new file mode 100644
+index 0000000..b67b468
+--- /dev/null
++++ b/GLIBC.cross-testing
+@@ -0,0 +1,205 @@
++ -*- mode: text -*-
++
++ Cross-Testing With GLIBC
++ Jim Blandy <jimb at codesourcery.com>
++
++
++Introduction
++
++Developers writing software for embedded systems often use a desktop
++or other similarly capable computer for development, but need to run
++tests on the embedded system, or perhaps on a simulator. When
++configured for cross-compilation, the stock GNU C library simply
++disables running tests altogether: the command 'make tests' builds
++test programs, but does not run them. GLIBC, however, provides
++facilities for compiling tests and generating data files on the build
++system, but running the test programs themselves on a remote system or
++simulator.
++
++
++Test environment requirements
++
++The test environment must meet certain conditions for GLIBC's
++cross-testing facilities to work:
++
++- Shared filesystems. The 'build' system, on which you configure and
++ compile GLIBC, and the 'host' system, on which you intend to run
++ GLIBC, must share a filesystem containing the GLIBC build and
++ source trees. Files must appear at the same paths on both systems.
++
++- Remote-shell like invocation. There must be a way to run a program
++ on the host system from the build system, passing it properly quoted
++ command-line arguments, setting environment variables, and
++ inheriting the caller's standard input and output.
++
++
++Usage
++
++To use GLIBC's cross-testing support, provide values for the
++following Make variables when you invoke 'make':
++
++- cross-test-wrapper
++
++ This should be the name of the cross-testing wrapper command, along
++ with any arguments.
++
++- cross-localedef
++
++ This should be the name of a cross-capable localedef program, like
++ that included in the GLIBC 'localedef' module, along with any
++ arguments needed.
++
++These are each explained in detail below.
++
++
++The Cross-Testing Wrapper
++
++To run test programs reliably, the stock GNU C library takes care to
++ensure that test programs use the newly compiled dynamic linker and
++shared libraries, and never the host system's installed libraries. To
++accomplish this, it runs the tests by explicitly invoking the dynamic
++linker from the build tree, passing it a list of build tree
++directories to search for shared libraries, followed by the name of
++the executable to run and its arguments.
++
++For example, where one might normally run a test program like this:
++
++ $ ./tst-foo arg1 arg2
++
++the GNU C library might run that program like this:
++
++ $ $objdir/elf/ld-linux.so.3 --library-path $objdir \
++ ./tst-foo arg1 arg2
++
++(where $objdir is the path to the top of the build tree, and the
++trailing backslash indicates a continuation of the command). In other
++words, each test program invocation is 'wrapped up' inside an explicit
++invocation of the dynamic linker, which must itself execute the test
++program, having loaded shared libraries from the appropriate
++directories.
++
++To support cross-testing, GLIBC allows the developer to optionally
++set the 'cross-test-wrapper' Make variable to another wrapper command,
++to which it passes the entire dynamic linker invocation shown above as
++arguments. For example, if the developer supplies a wrapper of
++'my-wrapper hostname', then GLIBC would run the test above as
++follows:
++
++ $ my-wrapper hostname \
++ $objdir/elf/ld-linux.so.3 --library-path $objdir \
++ ./tst-foo arg1 arg2
++
++The 'my-wrapper' command is responsible for executing the command
++given on the host system.
++
++Since tests are run in varying directories, the wrapper should either
++be in your command search path, or 'cross-test-wrapper' should give an
++absolute path for the wrapper.
++
++The wrapper must meet several requirements:
++
++- It must preserve the current directory. As explained above, the
++ build directory tree must be visible on both the build and host
++ systems, at the same path. The test wrapper must ensure that the
++ current directory it inherits is also inherited by the dynamic
++ linker (and thus the test program itself).
++
++- It must preserve environment variables' values. Many GLIBC tests
++ set environment variables for test runs; in native testing, it
++ invokes programs like this:
++
++ $ GCONV_PATH=$objdir/iconvdata \
++ $objdir/elf/ld-linux.so.3 --library-path $objdir \
++ ./tst-foo arg1 arg2
++
++ With the cross-testing wrapper, that invocation becomes:
++
++ $ GCONV_PATH=$objdir/iconvdata \
++ my-wrapper hostname \
++ $objdir/elf/ld-linux.so.3 --library-path $objdir \
++ ./tst-foo arg1 arg2
++
++ Here, 'my-wrapper' must ensure that the value it sees for
++ 'GCONV_PATH' will be seen by the dynamic linker, and thus 'tst-foo'
++ itself. (The wrapper supplied with GLIBC simply preserves the
++ values of *all* enviroment variables, with a fixed set of
++ exceptions.)
++
++ If your wrapper is a shell script, take care to correctly propagate
++ environment variables whose values contain spaces and shell
++ metacharacters.
++
++- It must pass the command's arguments, unmodified. The arguments
++ seen by the test program should be exactly those seen by the wrapper
++ (after whatever arguments are given to the wrapper itself). The
++ GLIBC test framework performs all needed shell word splitting and
++ expansion (wildcard expansion, parameter substitution, and so on)
++ before invoking the wrapper; further expansion may break the tests.
++
++
++The 'cross-test-ssh.sh' script
++
++If you want to use 'ssh' (or something sufficiently similar) to run
++test programs on your host system, GLIBC includes a shell script,
++'scripts/cross-test-ssh.sh', which you can use as your wrapper
++command. This script takes care of setting the test command's current
++directory, propagating environment variable values, and carrying
++command-line arguments, all across an 'ssh' connection. You may even
++supply an alternative to 'ssh' on the command line, if needed.
++
++For more details, pass 'cross-test-ssh.sh' the '--help' option.
++
++
++The Cross-Compiling Locale Definition Command
++
++Some GLIBC tests rely on locales generated especially for the test
++process. In a native configuration, these tests simply run the
++'localedef' command built by the normal GLIBC build process,
++'locale/localedef', to process and install their locales. However, in
++a cross-compiling configuration, this 'localedef' is built for the
++host system, not the build system, and since it requires quite a bit
++of memory to run (we have seen it fail on systems with 64MiB of
++memory), it may not be practical to run it on the host system.
++
++If set, GLIBC uses the 'cross-localedef' Make variable as the command
++to run on the build system to process and install locales. The
++localedef program built from the GLIBC 'localedef' module is
++suitable.
++
++The value of 'cross-localedef' may also include command-line arguments
++to be passed to the program; if you are using GLIBC's 'localedef',
++you may include endianness and 'uint32_t' alignment arguments here.
++
++
++Example
++
++In developing GLIBC's cross-testing facility, we invoked 'make' with
++the following script:
++
++ #!/bin/sh
++
++ srcdir=...
++ test_hostname=...
++ localedefdir=...
++ cross_gxx=...-g++
++
++ wrapper="$srcdir/scripts/cross-test-ssh.sh $test_hostname"
++ localedef="$localedefdir/localedef --little-endian --uint32-align=4"
++
++ make cross-test-wrapper="$wrapper" \
++ cross-localedef="$localedef" \
++ CXX="$cross_gxx" \
++ "$@"
++
++
++Other Cross-Testing Concerns
++
++Here are notes on some other issues which you may encounter in running
++the GLIBC tests in a cross-compiling environment:
++
++- Some tests require a C++ cross-compiler; you should set the 'CXX'
++ Make variable to the name of an appropriate cross-compiler.
++
++- Some tests require access to libstdc++.so.6 and libgcc_s.so.1; we
++ simply place copies of these libraries in the top GLIBC build
++ directory.
+--
+2.1.4
+
diff --git a/recipes-core/glibc/glibc/0019-eglibc-Bring-Eglibc-option-group-infrastructure-to-g.patch b/recipes-core/glibc/glibc/0019-eglibc-Bring-Eglibc-option-group-infrastructure-to-g.patch
new file mode 100644
index 0000000..dcb80f9
--- /dev/null
+++ b/recipes-core/glibc/glibc/0019-eglibc-Bring-Eglibc-option-group-infrastructure-to-g.patch
@@ -0,0 +1,1436 @@
+From aa7c5fe86d04584a9aed4dc40ba856c65a1ef9c4 Mon Sep 17 00:00:00 2001
+From: Khem Raj <raj.khem at gmail.com>
+Date: Wed, 18 Mar 2015 00:45:18 +0000
+Subject: [PATCH 19/27] eglibc: Bring Eglibc option group infrastructure to
+ glibc
+
+Upstream-Status: Pending
+
+Signed-off-by: Khem Raj <raj.khem at gmail.com>
+---
+ EGLIBC.option-groups | 122 ++++++
+ Makefile | 1 +
+ config.make.in | 2 +
+ configure | 13 +
+ configure.ac | 10 +
+ option-groups.def | 868 ++++++++++++++++++++++++++++++++++++++
+ option-groups.defaults | 47 +++
+ option-groups.mak | 41 ++
+ options-config/Makefile | 55 +++
+ options-config/config-postproc.pl | 58 +++
+ options-config/config-preproc.pl | 8 +
+ scripts/option-groups.awk | 63 +++
+ 12 files changed, 1288 insertions(+)
+ create mode 100644 EGLIBC.option-groups
+ create mode 100644 option-groups.def
+ create mode 100644 option-groups.defaults
+ create mode 100644 option-groups.mak
+ create mode 100644 options-config/Makefile
+ create mode 100644 options-config/config-postproc.pl
+ create mode 100644 options-config/config-preproc.pl
+ create mode 100644 scripts/option-groups.awk
+
+diff --git a/EGLIBC.option-groups b/EGLIBC.option-groups
+new file mode 100644
+index 0000000..6a50b8d
+--- /dev/null
++++ b/EGLIBC.option-groups
+@@ -0,0 +1,122 @@
++ -*- mode: text -*-
++
++ The EGLIBC Component Configuration System
++ Jim Blandy <jimb at codesourcery.com>
++
++Introduction
++
++The GNU C library (GLIBC) provides a broad range of functionality,
++ranging from internationalization support to transcendental
++mathematical functions. Its website boasts that "nearly all known and
++useful functions from any other C library are available." This
++exhaustive approach has been one of GLIBC's strengths on desktop and
++server systems, but it has also given GLIBC a large footprint, both in
++memory and on disk, making it a challenge to use in embedded systems
++with limited resources.
++
++The Embedded GNU C library (EGLIBC) is a variant of the GNU C library
++designed to work well on embedded systems. In particular, EGLIBC's
++component configuration system allows embedded developers to build
++customized versions of the library that include only the features
++their application uses, reducing its space requirements.
++
++EGLIBC's component configuration system categorizes the library's
++functions into "option groups", and allows you to include or exclude
++option groups individually. Some option groups depend on others;
++EGLIBC tracks these relationships, and ensures that the selected
++configuration yields a functioning library.
++
++
++Consistent and Predictable Behavior
++
++A flexible configuration system is a mixed blessing: if the options
++offered are poorly designed, it can be hard to see which choices will
++have the desired effects, and choices with obscure consequences can
++make debugging difficult. EGLIBC's configuration follows some general
++principles to reduce these risks:
++
++- EGLIBC has a single default configuration for each target
++ architecture.
++
++- In the default configuration, all option groups are enabled, and
++ EGLIBC is upwardly API- and ABI-compatible with GLIBC.
++
++- As much as possible, configurations only affect what functions are
++ present, not how they behave. If the system works with an option
++ group disabled, it will still work with it enabled.
++
++- As much as possible, configurations only select option groups ---
++ they do not describe characteristics of the target architecture.
++
++These rules mean that you have a simple debugging strategy available
++if you suspect that your EGLIBC configuration might be the source of a
++problem: fall back to the default configuration, re-test, and then
++disable option groups one by one, until the problem reappears.
++
++
++The Option Groups
++
++To see the current full list of implemented option groups, refer to the
++file 'option-groups.def' at the top of the source tree, or run
++'make menuconfig' from the top-level build directory.
++
++The POSIX.1-2001 specification includes a suggested partition of all
++the functions in the POSIX C API into option groups: math functions
++like 'sin' and 'cos'; networking functions like 'socket' and
++'connect'; and so on. EGLIBC could use this partitioning as the basis
++for future option groups.
++
++
++Implementation
++
++The EGLIBC component configuration system resembles the approach used
++by the Linux kernel to select device drivers, network protocols, and
++other features. A file named 'option-groups.config' in the top-level
++build directory contains assignments to Make variables, each of which
++enables or disables a particular option group. If the variable's
++value is set to 'y', then the option group is enabled; if it set to
++anything else, the option group is omitted. The file
++'option-groups.defaults', at the top of the source tree, establishes
++default values for all variables; all option groups are enabled by
++default.
++
++For example, the following 'option-groups.config' would omit locale
++data, but include mathematical functions, and everything else:
++
++ OPTION_EGLIBC_LOCALES = n
++ OPTION_EGLIBC_LIBM = y
++
++Like the Linux kernel, EGLIBC supports a similar set of '*config' make
++targets to make it easier to create 'option-groups.config', with all
++dependencies between option groups automatically satisfied. Run
++'make help' to see the list of supported make config targets. For
++example, 'make menuconfig' will update the current config utilising a
++menu based program.
++
++The option group names and their type (boolean, int, hex, string), help
++description, and dependencies with other option groups, are described by
++'option-groups.def' at the top of the source tree, analogous to the
++'Kconfig' files in the Linux kernel.
++
++In general, each option group variable controls whether a given set of
++object files in EGLIBC is compiled and included in the final
++libraries, or omitted from the build.
++
++Each subdirectory's Makefile categorizes its routines, libraries, and
++executables by option group. For example, EGLIBC's 'math/Makefile'
++places the 'libm' library in the OPTION_EGLIBC_LIBM group as follows:
++
++ extra-libs-$(OPTION_EGLIBC_LIBM) := libm
++
++Finally, common code in 'Makerules' cites the value of the variable
++'extra-libs-y', selecting only those libraries that belong to enabled
++option groups to be built.
++
++
++Current Status and Future Directions
++
++The EGLIBC component configuration system described here is still
++under development.
++
++We have used the system to subset some portions of EGLIBC's
++Index: libc/configure.ac
+diff --git a/Makefile b/Makefile
+index 658ccfa..f906391 100644
+--- a/Makefile
++++ b/Makefile
+@@ -24,6 +24,7 @@ endif
+
+ include Makeconfig
+
++include options-config/Makefile
+
+ # This is the default target; it makes everything except the tests.
+ .PHONY: all
+diff --git a/config.make.in b/config.make.in
+index a9f5696..294f8d1 100644
+--- a/config.make.in
++++ b/config.make.in
+@@ -47,6 +47,8 @@ c++-sysincludes = @CXX_SYSINCLUDES@
+ all-warnings = @all_warnings@
+ enable-werror = @enable_werror@
+
++kconfig_tools = @KCONFIG_TOOLS@
++
+ have-z-combreloc = @libc_cv_z_combreloc@
+ have-z-execstack = @libc_cv_z_execstack@
+ have-Bgroup = @libc_cv_Bgroup@
+diff --git a/configure b/configure
+index 7d7299a..4116404 100755
+--- a/configure
++++ b/configure
+@@ -641,6 +641,7 @@ INSTALL_INFO
+ PERL
+ BASH_SHELL
+ libc_cv_gcc_static_libgcc
++KCONFIG_TOOLS
+ CXX_SYSINCLUDES
+ SYSINCLUDES
+ AUTOCONF
+@@ -755,6 +756,7 @@ with_fp
+ with_binutils
+ with_selinux
+ with_headers
++with_kconfig
+ with_default_link
+ enable_sanity_checks
+ enable_shared
+@@ -1459,6 +1461,9 @@ Optional Packages:
+ --with-selinux if building with SELinux support
+ --with-headers=PATH location of system headers to use (for example
+ /usr/src/linux/include) [default=compiler default]
++ --with-kconfig=PATH location of kconfig tools to use (from Linux kernel
++ builds) to re-use for configuring EGLIBC option
++ groups
+ --with-default-link do not use explicit linker scripts
+ --with-cpu=CPU select code for CPU variant
+
+@@ -3517,6 +3522,14 @@ fi
+
+
+
++# Check whether --with-kconfig was given.
++if test "${with_kconfig+set}" = set; then
++ withval=$with_kconfig; KCONFIG_TOOLS=$withval
++else
++ KCONFIG_TOOLS=''
++fi
++
++
+
+ # Check whether --with-default-link was given.
+ if test "${with_default_link+set}" = set; then :
+diff --git a/configure.ac b/configure.ac
+index a467a69..fc0ed4d 100644
+--- a/configure.ac
++++ b/configure.ac
+@@ -136,6 +136,16 @@ AC_ARG_WITH([headers],
+ [sysheaders=''])
+ AC_SUBST(sysheaders)
+
++AC_ARG_WITH([kconfig],
++ AC_HELP_STRING([--with-kconfig=PATH],
++ [location of kconfig tools to use (from Linux
++ kernel builds) to re-use for configuring EGLIBC
++ option groups]),
++ [KCONFIG_TOOLS=$withval],
++ [KCONFIG_TOOLS=''])
++AC_SUBST(KCONFIG_TOOLS)
++
++
+ AC_SUBST(use_default_link)
+ AC_ARG_WITH([default-link],
+ AC_HELP_STRING([--with-default-link],
+diff --git a/option-groups.def b/option-groups.def
+new file mode 100644
+index 0000000..6aebd94
+--- /dev/null
++++ b/option-groups.def
+@@ -0,0 +1,868 @@
++# This file documents the option groups EGLIBC currently supports, in
++# a format akin to the Linux Kconfig system's. The syntax may change
++# over time.
++#
++# An entry of the form:
++#
++# config GROUP_NAME
++# bool "one-line explanation of what this option group controls"
++# help
++# Multi-line help explaining the option group's meaning in
++# some detail, terminated by indentation level.
++#
++# defines an option group whose variable is GROUP_NAME, with
++# meaningful values 'y' (enabled) and 'n' (disabled). The
++# documentation is formatted to be consumed by some sort of
++# interactive configuration interface, but EGLIBC doesn't have such an
++# interface yet.
++#
++# An option may have a 'depends on' line, indicating which other options
++# must also be enabled if this option is. At present, EGLIBC doesn't
++# check that these dependencies are satisfied.
++#
++# Option group variables get their default values from the file
++# 'option-groups.defaults', in the top directory of the EGLIBC source
++# tree. By default, all EGLIBC option groups are enabled --- their
++# variables are set to 'y'.
++#
++# After including 'option-groups.defaults', the EGLIBC make machinery
++# includes the file 'option-groups.config' from the top of the build
++# tree, if it is present. Developers can place assignments to option
++# group variables in that file to override the defaults. For example,
++# to disable an option group, place a line of the form:
++#
++# OPTION_GROUP_NAME = n
++#
++# in 'option-groups.config' at the top of your build tree. To
++# explicitly enable an option group, you may also write:
++#
++# OPTION_GROUP_NAME = y
++#
++# although this simply reestablishes the value already set by
++# 'option-groups.defaults'.
++
++config EGLIBC_ADVANCED_INET6
++ bool "IPv6 Advanced Sockets API support (RFC3542)"
++ depends on EGLIBC_INET
++ help
++ This option group includes the functions specified by RFC 3542,
++ "Advanced Sockets Application Program Interface (API) for
++ IPv6".
++
++ This option group includes the following functions:
++
++ inet6_opt_append
++ inet6_opt_find
++ inet6_opt_finish
++ inet6_opt_get_val
++ inet6_opt_init
++ inet6_option_alloc
++ inet6_option_append
++ inet6_option_find
++ inet6_option_init
++ inet6_option_next
++ inet6_option_space
++ inet6_opt_next
++ inet6_opt_set_val
++ inet6_rth_add
++ inet6_rth_getaddr
++ inet6_rth_init
++ inet6_rth_reverse
++ inet6_rth_segments
++ inet6_rth_space
++
++config EGLIBC_BACKTRACE
++ bool "Functions for producing backtraces"
++ help
++ This option group includes functions for producing a list of
++ the function calls that are currently active in a thread, from
++ within the thread itself. These functions are often used
++ within signal handlers, to produce diagnostic output.
++
++ This option group includes the following functions:
++
++ backtrace
++ backtrace_symbols
++ backtrace_symbols_fd
++
++config EGLIBC_BIG_MACROS
++ bool "Use extensive inline code"
++ help
++ This option group specifies whether certain pieces of code
++ should be inlined to achieve maximum speed. If this option
++ group is not selected, function calls will be used instead,
++ hence reducing the library footprint.
++
++config EGLIBC_BSD
++ bool "BSD-specific functions, and their compatibility stubs"
++ help
++ This option group includes functions specific to BSD kernels.
++ A number of these functions have stub versions that are also
++ included in libraries built for non-BSD systems for
++ compatibility.
++
++ This option group includes the following functions:
++
++ chflags
++ fchflags
++ lchmod
++ revoke
++ setlogin
++
++config EGLIBC_CXX_TESTS
++ bool "Tests that link against the standard C++ library."
++ depends on POSIX_WIDE_CHAR_DEVICE_IO && EGLIBC_LIBM
++ help
++ This option group does not include any C library functions;
++ instead, it controls which EGLIBC tests an ordinary 'make
++ tests' runs. With this group disabled, tests that would
++ normally link against the standard C++ library are not
++ run.
++
++ The standard C++ library depends on the math library 'libm' and
++ the wide character I/O functions included in EGLIBC. So those
++ option groups must be enabled if this test is enabled.
++
++config EGLIBC_CATGETS
++ bool "Functions for accessing message catalogs"
++ depends on EGLIBC_LOCALE_CODE
++ help
++ This option group includes functions for accessing message
++ catalogs: catopen, catclose, and catgets.
++
++ This option group depends on the EGLIBC_LOCALE_CODE
++ option group.
++
++config EGLIBC_CHARSETS
++ bool "iconv/gconv character set conversion libraries"
++ help
++ This option group includes support for character sets other
++ than ASCII (ANSI_X3.4-1968) and Unicode and ISO-10646 in their
++ various encodings. This affects both the character sets
++ supported by the wide and multibyte character functions, and
++ those supported by the 'iconv' functions.
++
++ With this option group disabled, EGLIBC supports only the
++ following character sets:
++
++ ANSI_X3.4 - ASCII
++ ANSI_X3.4-1968
++ ANSI_X3.4-1986
++ ASCII
++ CP367
++ CSASCII
++ IBM367
++ ISO-IR-6
++ ISO646-US
++ ISO_646.IRV:1991
++ OSF00010020
++ US
++ US-ASCII
++
++ 10646-1:1993 - ISO 10646, in big-endian UCS4 form
++ 10646-1:1993/UCS4
++ CSUCS4
++ ISO-10646
++ ISO-10646/UCS4
++ OSF00010104
++ OSF00010105
++ OSF00010106
++ UCS-4
++ UCS-4BE
++ UCS4
++
++ UCS-4LE - ISO 10646, in little-endian UCS4 form
++
++ ISO-10646/UTF-8 - ISO 10646, in UTF-8 form
++ ISO-10646/UTF8
++ ISO-IR-193
++ OSF05010001
++ UTF-8
++ UTF8
++
++ ISO-10646/UCS2 - ISO 10646, in target-endian UCS2 form
++ OSF00010100
++ OSF00010101
++ OSF00010102
++ UCS-2
++ UCS2
++
++ UCS-2BE - ISO 10646, in big-endian UCS2 form
++ UNICODEBIG
++
++ UCS-2LE - ISO 10646, in little-endian UCS2 form
++ UNICODELITTLE
++
++ WCHAR_T - EGLIBC's internal form (target-endian,
++ 32-bit ISO 10646)
++
++config EGLIBC_CRYPT
++ bool "Encryption library"
++ help
++ This option group includes the `libcrypt' library which
++ provides functions for one-way encryption. Supported
++ encryption algorithms include MD5, SHA-256, SHA-512 and DES.
++
++config EGLIBC_CRYPT_UFC
++ bool "Ultra fast `crypt' implementation"
++ depends on EGLIBC_CRYPT
++ help
++ This option group provides ultra fast DES-based implementation of
++ the `crypt' function. When this option group is disabled,
++ (a) the library will not provide the setkey[_r] and encrypt[_r]
++ functions and (b) the crypt[_r] function will return NULL and set the
++ errno to ENOSYS if /salt/ passed does not correspond to either MD5,
++ SHA-256 or SHA-512 algorithm.
++
++config EGLIBC_DB_ALIASES
++ bool "Functions for accessing the mail aliases database"
++ help
++ This option group includues functions for looking up mail
++ aliases in '/etc/aliases' or using nsswitch. It includes the
++ following functions:
++
++ endaliasent
++ getaliasbyname
++ getaliasbyname_r
++ getaliasent
++ getaliasent_r
++ setaliasent
++
++ When this option group is disabled, the NSS service libraries
++ also lack support for querying their mail alias tables.
++
++config EGLIBC_ENVZ
++ bool "Functions for handling envz-style environment vectors."
++ help
++ This option group contains functions for creating and operating
++ on envz vectors. An "envz vector" is a vector of strings in a
++ contiguous block of memory, where each element is a name-value
++ pair, and elements are separated from their neighbors by null
++ characters.
++
++ This option group includes the following functions:
++
++ envz_add envz_merge
++ envz_entry envz_remove
++ envz_get envz_strip
++
++config EGLIBC_FCVT
++ bool "Functions for converting floating-point numbers to strings"
++ help
++ This option group includes functions for converting
++ floating-point numbers to strings.
++
++ This option group includes the following functions:
++
++ ecvt qecvt
++ ecvt_r qecvt_r
++ fcvt qfcvt
++ fcvt_r qfcvt_r
++ gcvt qgcvt
++
++config EGLIBC_FMTMSG
++ bool "Functions for formatting messages"
++ help
++ This option group includes the following functions:
++
++ addseverity fmtmsg
++
++config EGLIBC_FSTAB
++ bool "Access functions for 'fstab'"
++ help
++ This option group includes functions for reading the mount
++ point specification table, '/etc/fstab'. These functions are
++ not included in the POSIX standard, which provides the
++ 'getmntent' family of functions instead.
++
++ This option group includes the following functions:
++
++ endfsent getfsspec
++ getfsent setfsent
++ getfsfile
++
++config EGLIBC_FTRAVERSE
++ bool "Functions for traversing file hierarchies"
++ help
++ This option group includes functions for traversing file
++ UNIX file hierachies.
++
++ This option group includes the following functions:
++
++ fts_open ftw
++ fts_read nftw
++ fts_children ftw64
++ fts_set nftw64
++ fts_close
++
++config EGLIBC_GETLOGIN
++ bool "The getlogin function"
++ depends on EGLIBC_UTMP
++ help
++ This function group includes the 'getlogin' and 'getlogin_r'
++ functions, which return the user name associated by the login
++ activity with the current process's controlling terminal.
++
++ With this option group disabled, the 'glob' function will not
++ fall back on 'getlogin' to find the user's login name for tilde
++ expansion when the 'HOME' environment variable is not set.
++
++config EGLIBC_IDN
++ bool "International domain names support"
++ help
++ This option group includes the `libcidn' library which
++ provides support for international domain names.
++
++config EGLIBC_INET
++ bool "Networking support"
++ help
++ This option group includes networking-specific functions and
++ data. With EGLIBC_INET disabled, the EGLIBC
++ installation and API changes as follows:
++
++ - The following libraries are not installed:
++
++ libnsl
++ libnss_compat
++ libnss_dns
++ libnss_hesiod
++ libnss_nis
++ libnss_nisplus
++ libresolv
++
++ - The following functions and variables are omitted from libc:
++
++ authdes_create hstrerror svc_fdset
++ authdes_getucred htonl svc_getreq
++ authdes_pk_create htons svc_getreq_common
++ authnone_create if_freenameindex svc_getreq_poll
++ authunix_create if_indextoname svc_getreqset
++ authunix_create_default if_nameindex svc_max_pollfd
++ bindresvport if_nametoindex svc_pollfd
++ callrpc in6addr_any svcraw_create
++ cbc_crypt in6addr_loopback svc_register
++ clnt_broadcast inet6_opt_append svc_run
++ clnt_create inet6_opt_find svc_sendreply
++ clnt_pcreateerror inet6_opt_finish svctcp_create
++ clnt_perrno inet6_opt_get_val svcudp_bufcreate
++ clnt_perror inet6_opt_init svcudp_create
++ clntraw_create inet6_option_alloc svcudp_enablecache
++ clnt_spcreateerror inet6_option_append svcunix_create
++ clnt_sperrno inet6_option_find svcunixfd_create
++ clnt_sperror inet6_option_init svc_unregister
++ clnttcp_create inet6_option_next user2netname
++ clntudp_bufcreate inet6_option_space xdecrypt
++ clntudp_create inet6_opt_next xdr_accepted_reply
++ clntunix_create inet6_opt_set_val xdr_array
++ des_setparity inet6_rth_add xdr_authdes_cred
++ ecb_crypt inet6_rth_getaddr xdr_authdes_verf
++ endaliasent inet6_rth_init xdr_authunix_parms
++ endhostent inet6_rth_reverse xdr_bool
++ endnetent inet6_rth_segments xdr_bytes
++ endnetgrent inet6_rth_space xdr_callhdr
++ endprotoent inet_addr xdr_callmsg
++ endrpcent inet_aton xdr_char
++ endservent inet_lnaof xdr_cryptkeyarg
++ ether_aton inet_makeaddr xdr_cryptkeyarg2
++ ether_aton_r inet_netof xdr_cryptkeyres
++ ether_hostton inet_network xdr_des_block
++ ether_line inet_nsap_addr xdr_double
++ ether_ntoa inet_nsap_ntoa xdr_enum
++ ether_ntoa_r inet_ntoa xdr_float
++ ether_ntohost inet_ntop xdr_free
++ freeaddrinfo inet_pton xdr_getcredres
++ freeifaddrs innetgr xdr_hyper
++ gai_strerror iruserok xdr_int
++ getaddrinfo iruserok_af xdr_int16_t
++ getaliasbyname key_decryptsession xdr_int32_t
++ getaliasbyname_r key_decryptsession_pk xdr_int64_t
++ getaliasent key_encryptsession xdr_int8_t
++ getaliasent_r key_encryptsession_pk xdr_keybuf
++ gethostbyaddr key_gendes xdr_key_netstarg
++ gethostbyaddr_r key_get_conv xdr_key_netstres
++ gethostbyname key_secretkey_is_set xdr_keystatus
++ gethostbyname2 key_setnet xdr_long
++ gethostbyname2_r key_setsecret xdr_longlong_t
++ gethostbyname_r netname2host xdrmem_create
++ gethostent netname2user xdr_netnamestr
++ gethostent_r ntohl xdr_netobj
++ getifaddrs ntohs xdr_opaque
++ getipv4sourcefilter passwd2des xdr_opaque_auth
++ get_myaddress pmap_getmaps xdr_pmap
++ getnameinfo pmap_getport xdr_pmaplist
++ getnetbyaddr pmap_rmtcall xdr_pointer
++ getnetbyaddr_r pmap_set xdr_quad_t
++ getnetbyname pmap_unset xdrrec_create
++ getnetbyname_r rcmd xdrrec_endofrecord
++ getnetent rcmd_af xdrrec_eof
++ getnetent_r registerrpc xdrrec_skiprecord
++ getnetgrent res_init xdr_reference
++ getnetgrent_r rexec xdr_rejected_reply
++ getnetname rexec_af xdr_replymsg
++ getprotobyname rexecoptions xdr_rmtcall_args
++ getprotobyname_r rpc_createerr xdr_rmtcallres
++ getprotobynumber rresvport xdr_short
++ getprotobynumber_r rresvport_af xdr_sizeof
++ getprotoent rtime xdrstdio_create
++ getprotoent_r ruserok xdr_string
++ getpublickey ruserok_af xdr_u_char
++ getrpcbyname ruserpass xdr_u_hyper
++ getrpcbyname_r setaliasent xdr_u_int
++ getrpcbynumber sethostent xdr_uint16_t
++ getrpcbynumber_r setipv4sourcefilter xdr_uint32_t
++ getrpcent setnetent xdr_uint64_t
++ getrpcent_r setnetgrent xdr_uint8_t
++ getrpcport setprotoent xdr_u_long
++ getsecretkey setrpcent xdr_u_longlong_t
++ getservbyname setservent xdr_union
++ getservbyname_r setsourcefilter xdr_unixcred
++ getservbyport svcauthdes_stats xdr_u_quad_t
++ getservbyport_r svcerr_auth xdr_u_short
++ getservent svcerr_decode xdr_vector
++ getservent_r svcerr_noproc xdr_void
++ getsourcefilter svcerr_noprog xdr_wrapstring
++ h_errlist svcerr_progvers xencrypt
++ h_errno svcerr_systemerr xprt_register
++ herror svcerr_weakauth xprt_unregister
++ h_nerr svc_exit
++ host2netname svcfd_create
++
++ - The rpcgen, nscd, and rpcinfo commands are not installed.
++
++ - The 'rpc' file (a text file listing RPC services) is not installed.
++
++ Socket-related system calls do not fall in this option group,
++ because many are also used for other inter-process
++ communication mechanisms. For example, the 'syslog' routines
++ use Unix-domain sockets to communicate with the syslog daemon;
++ syslog is valuable in non-networked contexts.
++
++config EGLIBC_INET_ANL
++ bool "Asynchronous name lookup"
++ depends on EGLIBC_INET
++ help
++ This option group includes the `libanl' library which
++ provides support for asynchronous name lookup.
++
++config EGLIBC_LIBM
++ bool "libm (math library)"
++ help
++ This option group includes the 'libm' library, containing
++ mathematical functions. If this option group is omitted, then
++ an EGLIBC installation does not include shared or unshared versions
++ of the math library.
++
++ Note that this does not remove all floating-point related
++ functionality from EGLIBC; for example, 'printf' and 'scanf'
++ can still print and read floating-point values with this option
++ group disabled.
++
++ Note that the ISO Standard C++ library 'libstdc++' depends on
++ EGLIBC's math library 'libm'. If you disable this option
++ group, you will not be able to build 'libstdc++' against the
++ resulting EGLIBC installation.
++
++config EGLIBC_LOCALES
++ bool "Locale definitions"
++ help
++ This option group includes all locale definitions other than
++ that for the "C" locale. If this option group is omitted, then
++ only the "C" locale is supported.
++
++
++config EGLIBC_LOCALE_CODE
++ bool "Locale functions"
++ depends on POSIX_C_LANG_WIDE_CHAR
++ help
++ This option group includes locale support functions, programs,
++ and libraries. With EGLIBC_LOCALE_CODE disabled,
++ EGLIBC supports only the 'C' locale (also known as 'POSIX'),
++ and ignores the settings of the 'LANG' and 'LC_*' environment
++ variables.
++
++ With EGLIBC_LOCALE_CODE disabled, the following
++ functions are omitted from libc:
++
++ duplocale localeconv nl_langinfo rpmatch strfmon_l
++ freelocale newlocale nl_langinfo_l strfmon uselocale
++
++ Furthermore, only the LC_CTYPE and LC_TIME categories of the
++ standard "C" locale are available.
++
++ The EGLIBC_CATGETS option group depends on this option group.
++
++
++config EGLIBC_MEMUSAGE
++ bool "Memory profiling library"
++ help
++ This option group includes the `libmemusage' library and
++ the `memusage' and `memusagestat' utilities.
++ These components provide memory profiling functions.
++
++config EGLIBC_MEMUSAGE_DEFAULT_BUFFER_SIZE
++ int "Memory profiling library buffer size"
++ depends on EGLIBC_MEMUSAGE
++ default "32768"
++ help
++ Libmemusage library buffers the profiling data in memory
++ before writing it out to disk. By default, the library
++ allocates 1.5M buffer, which can be substantial for some
++ systems. EGLIBC_MEMUSAGE_DEFAULT_BUFFER_SIZE option
++ allows to change the default buffer size. It specifies
++ the number of entries the buffer should have.
++ On most architectures one buffer entry amounts to 48 bytes,
++ so setting this option to the value of 512 will reduce the size of
++ the memory buffer to 24K.
++
++config EGLIBC_NIS
++ bool "Support for NIS, NIS+, and the special 'compat' services."
++ depends on EGLIBC_INET && EGLIBC_SUNRPC
++ help
++ This option group includes the NIS, NIS+, and 'compat' Name
++ Service Switch service libraries. When it is disabled, those
++ services libraries are not installed; you should remove any
++ references to them from your 'nsswitch.conf' file.
++
++ This option group depends on the EGLIBC_INET option
++ group; you must enable that to enable this option group.
++
++config EGLIBC_NSSWITCH
++ bool "Name service switch (nsswitch) support"
++ help
++ This option group includes support for the 'nsswitch' facility.
++ With this option group enabled, all EGLIBC functions for
++ accessing various system databases (passwords and groups;
++ networking; aliases; public keys; and so on) consult the
++ '/etc/nsswitch.conf' configuration file to decide how to handle
++ queries.
++
++ With this option group disabled, EGLIBC uses a fixed list of
++ services to satisfy queries on each database, as requested by
++ configuration files specified when EGLIBC is built. Your
++ 'option-groups.config' file must set the following two
++ variables:
++
++config EGLIBC_NSSWITCH_FIXED_CONFIG
++ string "Nsswitch fixed config filename"
++ depends on !EGLIBC_NSSWITCH
++ default ""
++ help
++ Set this to the name of a file whose contents observe the
++ same syntax as an ordinary '/etc/nsswitch.conf' file. The
++ EGLIBC build process parses this file just as EGLIBC would
++ at run time if EGLIBC_NSSWITCH were enabled, and
++ produces a C library that uses the nsswitch service
++ libraries to search for database entries as this file
++ specifies, instead of consulting '/etc/nsswitch.conf' at run
++ time.
++
++ This should be an absolute filename. The EGLIBC build
++ process may use it from several different working
++ directories. It may include references to Makefile
++ variables like 'common-objpfx' (the top of the build tree,
++ with a trailing slash), or '..' (the top of the source tree,
++ with a trailing slash).
++
++ The EGLIBC source tree includes a sample configuration file
++ named 'nss/fixed-nsswitch.conf'; for simple configurations,
++ you will probably want to delete references to databases not
++ needed on your system.
++
++config EGLIBC_NSSWITCH_FIXED_FUNCTIONS
++ string "Nsswitch fixed functions filename"
++ depends on !EGLIBC_NSSWITCH
++ default ""
++ help
++ The EGLIBC build process uses this file to decide which
++ functions to make available from which service libraries.
++ The file 'nss/fixed-nsswitch.functions' serves as a sample
++ configuration file for this setting, and explains its syntax
++ and meaning in more detail.
++
++ This should be an absolute file name. The EGLIBC build
++ process may use it from several different working
++ directories. It may include references to Makefile
++ variables like 'common-objpfx' (the top of the build tree,
++ with a trailing slash), or '..' (the top of the source tree,
++ with a trailing slash).
++
++ Be sure to mention each function in each service you wish to
++ use. If you do not mention a service's function here, the
++ EGLIBC database access functions will not find it, even if
++ it is listed in the EGLIBC_NSSWITCH_FIXED_CONFIG
++ file.
++
++ In this arrangement, EGLIBC will not use the 'dlopen' and
++ 'dlsym' functions to find database access functions. Instead,
++ libc hard-codes references to the service libraries' database
++ access functions. You must explicitly link your program
++ against the name service libraries (those whose names start
++ with 'libnss_', in the sysroot's '/lib' directory) whose
++ functions you intend to use. This arrangement helps
++ system-wide static analysis tools decide which functions a
++ system actually uses.
++
++ Note that some nsswitch service libraries require other option
++ groups to be enabled; for example, the EGLIBC_INET
++ option group must be enabled to use the 'libnss_dns.so.2'
++ service library, which uses the Domain Name System network
++ protocol to answer queries.
++
++config EGLIBC_RCMD
++ bool "Support for 'rcmd' and related library functions"
++ depends on EGLIBC_INET
++ help
++ This option group includes functions for running commands on
++ remote machines via the 'rsh' protocol, and doing authentication
++ related to those functions. This also includes functions that
++ use the 'rexec' protocol.
++
++ This option group includes the following functions:
++
++ rcmd ruserok
++ rcmd_af ruserok_af
++ rexec iruserok
++ rexec_af iruserok_af
++ rresvport ruserpass
++ rresvport_af
++
++config EGLIBC_RTLD_DEBUG
++ bool "Runtime linker debug print outs"
++ help
++ This option group enables debug output of the runtime linker
++ which is activated via LD_DEBUG and LD_TRACE_PRELINKING
++ environment variables. Disabling this option group yields
++ a smaller runtime linker binary.
++ BEWARE: Disabling this option group is likely to break
++ the `ldd' utility which may also be used by the prelinker.
++ In particular, the `--unused' ldd option will not work correctly.
++
++config EGLIBC_SPAWN
++ bool "Support for POSIX posix_spawn functions"
++ help
++ This option group includes the POSIX functions for executing
++ programs in child processes without using 'fork' or 'vfork'.
++
++ This option group includes the following functions:
++
++ posix_spawn
++ posix_spawnattr_destroy
++ posix_spawnattr_getflags
++ posix_spawnattr_getpgroup
++ posix_spawnattr_getschedparam
++ posix_spawnattr_getschedpolicy
++ posix_spawnattr_getsigdefault
++ posix_spawnattr_getsigmask
++ posix_spawnattr_init
++ posix_spawnattr_setflags
++ posix_spawnattr_setpgroup
++ posix_spawnattr_setschedparam
++ posix_spawnattr_setschedpolicy
++ posix_spawnattr_setsigdefault
++ posix_spawnattr_setsigmask
++ posix_spawn_file_actions_addclose
++ posix_spawn_file_actions_adddup2
++ posix_spawn_file_actions_addopen
++ posix_spawn_file_actions_destroy
++ posix_spawn_file_actions_init
++ posix_spawnp
++
++ This option group also provides the ability for the iconv,
++ localedef, and locale programs to operate transparently on
++ compressed charset definitions. When this option group is
++ disabled, those programs will only operate on uncompressed
++ charmap files.
++
++config EGLIBC_STREAMS
++ bool "Support for accessing STREAMS."
++ help
++ This option group includes functions for reading and writing
++ messages to and from STREAMS. The STREAMS interface provides a
++ uniform mechanism for implementing networking services and other
++ character-based I/O. (STREAMS are not to be confused with
++ <stdio.h> FILE objects, also called 'streams'.)
++
++ This option group includes the following functions:
++
++ getmsg putpmsg
++ getpmsg fattach
++ isastream fdetach
++ putmsg
++
++config EGLIBC_SUNRPC
++ bool "Support for the Sun 'RPC' protocol."
++ depends on EGLIBC_INET
++ help
++ This option group includes support for the Sun RPC protocols,
++ including the 'rpcgen' and 'rpcinfo' programs.
++
++config EGLIBC_UTMP
++ bool "Older access functions for 'utmp' login records"
++ help
++ This option group includes the older 'utent' family of
++ functions for accessing user login records in the 'utmp' file.
++ POSIX omits these functions in favor of the 'utxent' family,
++ and they are obsolete on systems other than Linux.
++
++ This option group includes the following functions:
++
++ endutent
++ getutent
++ getutent_r
++ getutid
++ getutid_r
++ getutline
++ getutline_r
++ logwtmp
++ pututline
++ setutent
++ updwtmp
++ utmpname
++
++ This option group includes the following libraries:
++
++ libutil.so (and libutil.a)
++
++config EGLIBC_UTMPX
++ bool "POSIX access functions for 'utmp' login records"
++ depends on EGLIBC_UTMP
++ help
++ This option group includes the POSIX functions for reading and
++ writing user login records in the 'utmp' file (usually
++ '/var/run/utmp'). The POSIX functions operate on 'struct
++ utmpx' structures, as opposed to the family of older 'utent'
++ functions, which operate on 'struct utmp' structures.
++
++ This option group includes the following functions:
++
++ endutxent
++ getutmp
++ getutmpx
++ getutxent
++ getutxid
++ getutxline
++ pututxline
++ setutxent
++ updwtmpx
++ utmpxname
++
++config EGLIBC_WORDEXP
++ bool "Shell-style word expansion"
++ help
++ This option group includes the 'wordexp' function for
++ performing word expansion in the manner of the shell, and the
++ accompanying 'wordfree' function.
++
++config POSIX_C_LANG_WIDE_CHAR
++ bool "ISO C library wide character functions, excluding I/O"
++ help
++ This option group includes the functions defined by the ISO C
++ standard for working with wide and multibyte characters in
++ memory. Functions for reading and writing wide and multibyte
++ characters from and to files call in the
++ POSIX_WIDE_CHAR_DEVICE_IO option group.
++
++ This option group includes the following functions:
++
++ btowc mbsinit wcscspn wcstoll
++ iswalnum mbsrtowcs wcsftime wcstombs
++ iswalpha mbstowcs wcslen wcstoul
++ iswblank mbtowc wcsncat wcstoull
++ iswcntrl swprintf wcsncmp wcstoumax
++ iswctype swscanf wcsncpy wcsxfrm
++ iswdigit towctrans wcspbrk wctob
++ iswgraph towlower wcsrchr wctomb
++ iswlower towupper wcsrtombs wctrans
++ iswprint vswprintf wcsspn wctype
++ iswpunct vswscanf wcsstr wmemchr
++ iswspace wcrtomb wcstod wmemcmp
++ iswupper wcscat wcstof wmemcpy
++ iswxdigit wcschr wcstoimax wmemmove
++ mblen wcscmp wcstok wmemset
++ mbrlen wcscoll wcstol
++ mbrtowc wcscpy wcstold
++
++config POSIX_REGEXP
++ bool "Regular expressions"
++ help
++ This option group includes the POSIX regular expression
++ functions, and the associated non-POSIX extensions and
++ compatibility functions.
++
++ With POSIX_REGEXP disabled, the following functions are
++ omitted from libc:
++
++ re_comp re_max_failures regcomp
++ re_compile_fastmap re_search regerror
++ re_compile_pattern re_search_2 regexec
++ re_exec re_set_registers regfree
++ re_match re_set_syntax rpmatch
++ re_match_2 re_syntax_options
++
++ Furthermore, the compatibility regexp interface defined in the
++ <regexp.h> header file, 'compile', 'step', and 'advance', is
++ omitted.
++
++config POSIX_REGEXP_GLIBC
++ bool "Regular expressions from GLIBC"
++ depends on POSIX_REGEXP
++ help
++ This option group specifies which regular expression
++ library to use. The choice is between regex
++ implementation from GLIBC and regex implementation from
++ libiberty. The GLIBC variant is fully POSIX conformant and
++ optimized for speed; regex from libiberty is more than twice
++ as small while still is enough for most practical purposes.
++
++config POSIX_WIDE_CHAR_DEVICE_IO
++ bool "Input and output functions for wide characters"
++ depends on POSIX_C_LANG_WIDE_CHAR
++ help
++ This option group includes functions for reading and writing
++ wide characters to and from <stdio.h> streams.
++
++ This option group includes the following functions:
++
++ fgetwc fwprintf putwchar vwscanf
++ fgetws fwscanf ungetwc wprintf
++ fputwc getwc vfwprintf wscanf
++ fputws getwchar vfwscanf
++ fwide putwc vwprintf
++
++ This option group further includes the following unlocked
++ variants of the above functions:
++
++ fgetwc_unlocked getwc_unlocked
++ fgetws_unlocked getwchar_unlocked
++ fputwc_unlocked putwc_unlocked
++ fputws_unlocked putwchar_unlocked
++
++ Note that the GNU standard C++ library, 'libstdc++.so', uses
++ some of these functions; you will not be able to link or run
++ C++ programs if you disable this option group.
++
++ This option group also affects the behavior of the following
++ functions:
++
++ fdopen
++ fopen
++ fopen64
++ freopen
++ freopen64
++
++ These functions all take an OPENTYPE parameter which may
++ contain a string of the form ",ccs=CHARSET", indicating that
++ the underlying file uses the character set named CHARSET.
++ This produces a wide-oriented stream, which is only useful
++ when the functions included in this option group are present.
++ If the user attempts to open a file specifying a character set
++ in the OPENTYPE parameter, and EGLIBC was built with this
++ option group disabled, the function returns NULL, and sets
++ errno to EINVAL.
++
++
++# This helps Emacs users browse this file using the page motion commands
++# and commands like 'pages-directory'.
++# Local Variables:
++# page-delimiter: "^config\\s-"
++# End:
+diff --git a/option-groups.defaults b/option-groups.defaults
+new file mode 100644
+index 0000000..8141201
+--- /dev/null
++++ b/option-groups.defaults
+@@ -0,0 +1,47 @@
++# This file sets default values for all option group variables
++# mentioned in option-groups.def; see that file for a description of
++# each option group.
++#
++# Subdirectory makefiles include this file before including the user's
++# settings from option-groups.config at the top of the build tree;
++# that file need only refer to those options whose default settings
++# are to be changed.
++#
++# By default, all option groups are enabled.
++OPTION_EGLIBC_ADVANCED_INET6 = y
++OPTION_EGLIBC_BACKTRACE = y
++OPTION_EGLIBC_BIG_MACROS = y
++OPTION_EGLIBC_BSD = y
++OPTION_EGLIBC_CXX_TESTS = y
++OPTION_EGLIBC_CATGETS = y
++OPTION_EGLIBC_CHARSETS = y
++OPTION_EGLIBC_CRYPT = y
++OPTION_EGLIBC_CRYPT_UFC = y
++OPTION_EGLIBC_DB_ALIASES = y
++OPTION_EGLIBC_ENVZ = y
++OPTION_EGLIBC_FCVT = y
++OPTION_EGLIBC_FMTMSG = y
++OPTION_EGLIBC_FSTAB = y
++OPTION_EGLIBC_FTRAVERSE = y
++OPTION_EGLIBC_GETLOGIN = y
++OPTION_EGLIBC_IDN = y
++OPTION_EGLIBC_INET = y
++OPTION_EGLIBC_INET_ANL = y
++OPTION_EGLIBC_LIBM = y
++OPTION_EGLIBC_LOCALES = y
++OPTION_EGLIBC_LOCALE_CODE = y
++OPTION_EGLIBC_MEMUSAGE = y
++OPTION_EGLIBC_NIS = y
++OPTION_EGLIBC_NSSWITCH = y
++OPTION_EGLIBC_RCMD = y
++OPTION_EGLIBC_RTLD_DEBUG = y
++OPTION_EGLIBC_SPAWN = y
++OPTION_EGLIBC_STREAMS = y
++OPTION_EGLIBC_SUNRPC = y
++OPTION_EGLIBC_UTMP = y
++OPTION_EGLIBC_UTMPX = y
++OPTION_EGLIBC_WORDEXP = y
++OPTION_POSIX_C_LANG_WIDE_CHAR = y
++OPTION_POSIX_REGEXP = y
++OPTION_POSIX_REGEXP_GLIBC = y
++OPTION_POSIX_WIDE_CHAR_DEVICE_IO = y
+diff --git a/option-groups.mak b/option-groups.mak
+new file mode 100644
+index 0000000..f83e0c1
+--- /dev/null
++++ b/option-groups.mak
+@@ -0,0 +1,41 @@
++# Setup file for subdirectory Makefiles that define EGLIBC option groups.
++
++# EGLIBC shouldn't need to override this. However, the
++# cross-build-friendly localedef includes this makefile to get option
++# group variable definitions; it uses a single build tree for all the
++# multilibs, and needs to be able to specify a different option group
++# configuration file for each multilib.
++option_group_config_file ?= $(objdir)/option-groups.config
++
++# Read the default settings for all options.
++# We're included before ../Rules, so we can't assume $(..) is set.
++include $(firstword $(..) ../)option-groups.defaults
++
++# Read the developer's option group selections, overriding the
++# defaults from option-groups.defaults.
++-include $(option_group_config_file)
++
++# $(call option-disabled, VAR) is 'y' if VAR is not 'y', or 'n' otherwise.
++# VAR should be a variable name, not a variable reference; this is
++# less general, but more terse for the intended use.
++# You can use it to add a file to a list if an option group is
++# disabled, like this:
++# routines-$(call option-disabled, OPTION_POSIX_C_LANG_WIDE_CHAR) += ...
++define option-disabled
++$(firstword $(subst y,n,$(filter y,$($(strip $(1))))) y)
++endef
++
++# Establish 'routines-y', etc. as simply-expanded variables.
++aux-y :=
++extra-libs-others-y :=
++extra-libs-y :=
++extra-objs-y :=
++install-bin-y :=
++install-others-y :=
++install-sbin-y :=
++others-y :=
++others-pie-y :=
++routines-y :=
++test-srcs-y :=
++tests-y :=
++xtests-y :=
+diff --git a/options-config/Makefile b/options-config/Makefile
+new file mode 100644
+index 0000000..db00708
+--- /dev/null
++++ b/options-config/Makefile
+@@ -0,0 +1,55 @@
++# ===========================================================================
++# EGLIBC option-groups configuration targets
++# These targets are included from top-level makefile
++
++ifneq ($(kconfig_tools),)
++ifneq (no,$(PERL))
++
++ocdir := options-config
++
++OconfigDefaults := option-groups.defaults
++OconfigDefaults_tmp := $(common-objpfx).tmp.defconfig
++OconfigDef := option-groups.def
++Oconfig := $(common-objpfx)option-groups.config
++Oconfig_tmp := $(common-objpfx).tmp.config
++
++conf := $(kconfig_tools)/conf
++mconf := $(kconfig_tools)/mconf
++
++preproc := $(PERL) $(ocdir)/config-preproc.pl
++postproc := $(PERL) $(ocdir)/config-postproc.pl
++
++PHONY += defconfig config menuconfig
++
++defconfig: $(conf) $(OconfigDefaults) $(OconfigDef)
++ rm -f $(OconfigDefaults_tmp)
++ rm -f $(Oconfig_tmp)
++ $(preproc) $(OconfigDefaults) > $(OconfigDefaults_tmp)
++ KCONFIG_CONFIG=$(Oconfig_tmp) $< --defconfig=$(OconfigDefaults_tmp) \
++ $(OconfigDef)
++ $(postproc) $(OconfigDefaults) $(Oconfig_tmp) > $(Oconfig)
++ rm $(Oconfig_tmp)
++ rm $(OconfigDefaults_tmp)
++
++config: $(conf) $(OconfigDefaults) $(OconfigDef)
++ rm -f $(Oconfig_tmp)
++ $(preproc) $(wildcard $(Oconfig)) > $(Oconfig_tmp)
++ KCONFIG_CONFIG=$(Oconfig_tmp) $< --oldaskconfig $(OconfigDef)
++ $(postproc) $(OconfigDefaults) $(Oconfig_tmp) > $(Oconfig)
++ rm $(Oconfig_tmp)
++
++menuconfig: $(mconf) $(OconfigDefaults) $(OconfigDef)
++ rm -f $(Oconfig_tmp)
++ $(preproc) $(wildcard $(Oconfig)) > $(Oconfig_tmp)
++ KCONFIG_CONFIG=$(Oconfig_tmp) $< $(OconfigDef)
++ $(postproc) $(OconfigDefaults) $(Oconfig_tmp) > $(Oconfig)
++ rm $(Oconfig_tmp)
++
++# Help text used by make help
++help:
++ @echo ' defconfig - New config with default from default config'
++ @echo ' config - Update current config utilising a line-oriented program'
++ @echo ' menuconfig - Update current config utilising a menu based program'
++
++endif
++endif
+diff --git a/options-config/config-postproc.pl b/options-config/config-postproc.pl
+new file mode 100644
+index 0000000..4dd1c63
+--- /dev/null
++++ b/options-config/config-postproc.pl
+@@ -0,0 +1,58 @@
++#!/usr/bin/perl
++
++$usage = "usage: $0 <default config file> <config file>\n";
++
++die "$usage" unless @ARGV;
++$defaults = shift @ARGV;
++die "$usage" unless @ARGV;
++die "Could not open $ARGV[0]" unless -T $ARGV[0];
++
++sub yank {
++ @option = grep(!($_ =~ /$_[0]\s*=/), @option);
++}
++
++open(DEFAULTS, $defaults) || die "Could not open $defaults\n";
++
++# get the full list of available options using the default config file
++$i = 0;
++while (<DEFAULTS>) {
++ if (/^\s*OPTION_(\w+\s*=.*$)/) {
++ $option[$i++] = $1;
++ }
++}
++
++# now go through the config file, making the necessary changes
++while (<>) {
++ if (/Linux Kernel Configuration/) {
++ # change title
++ s/Linux Kernel/Option Groups/;
++ print;
++ } elsif (/^\s*CONFIG_(\w+)\s*=/) {
++ # this is an explicit option set line, change CONFIG_ to OPTION_
++ # before printing and remove this option from option list
++ $opt = $1;
++ yank($opt);
++ s/CONFIG_/OPTION_/g;
++ print;
++ } elsif (/^\s*#\s+CONFIG_(\w+) is not set/) {
++ # this is a comment line for an unset boolean option, change CONFIG_
++ # to OPTION_, remove this option from option list, and convert to
++ # explicit OPTION_FOO=n
++ $opt = $1;
++ yank($opt);
++ s/CONFIG_/OPTION_/g;
++ print "OPTION_$opt=n\n";
++ } else {
++ print;
++ }
++}
++
++# any boolean options left in @options, are options that were not mentioned in
++# the config file, and implicitly that means the option must be set =n,
++# so do that here.
++foreach $opt (@option) {
++ if ($opt =~ /=\s*[yn]/) {
++ $opt =~ s/=\s*[yn]/=n/;
++ print "OPTION_$opt\n";
++ }
++}
+diff --git a/options-config/config-preproc.pl b/options-config/config-preproc.pl
+new file mode 100644
+index 0000000..b83bb85
+--- /dev/null
++++ b/options-config/config-preproc.pl
+@@ -0,0 +1,8 @@
++#!/usr/bin/perl
++
++if (@ARGV) {
++ while (<>) {
++ s/OPTION_/CONFIG_/g;
++ print;
++ }
++}
+diff --git a/scripts/option-groups.awk b/scripts/option-groups.awk
+new file mode 100644
+index 0000000..533af0c
+--- /dev/null
++++ b/scripts/option-groups.awk
+@@ -0,0 +1,63 @@
++# option-groups.awk --- generate option group header file
++# Given input files containing makefile-style assignments to variables,
++# print out a header file that #defines an appropriate preprocessor
++# symbol for each variable left set to 'y'.
++
++BEGIN { FS="=" }
++
++# Trim spaces.
++{ gsub (/[[:blank:]]/, "") }
++
++# Skip comments.
++/^#/ { next }
++
++# Process assignments.
++NF == 2 {
++ vars[$1] = $2
++}
++
++# Print final values.
++END {
++ print "/* This file is automatically generated by scripts/option-groups.awk"
++ print " in the EGLIBC source tree."
++ print ""
++ print " It defines macros that indicate which EGLIBC option groups were"
++ print " configured in 'option-groups.config' when this C library was"
++ print " built. For each option group named OPTION_foo, it #defines"
++ print " __OPTION_foo to be 1 if the group is enabled, or #defines that"
++ print " symbol to be 0 if the group is disabled. */"
++ print ""
++ print "#ifndef __GNU_OPTION_GROUPS_H"
++ print "#define __GNU_OPTION_GROUPS_H"
++ print ""
++
++ # Produce a sorted list of variable names.
++ i=0
++ for (var in vars)
++ names[i++] = var
++ n = asort (names)
++
++ for (i = 1; i <= n; i++)
++ {
++ var = names[i]
++ if (var ~ /^OPTION_/)
++ {
++ if (vars[var] == "y")
++ print "#define __" var " 1"
++ else if (vars[var] == "n")
++ print "#define __" var " 0"
++ else if (vars[var] ~ /^[0-9]+/ ||
++ vars[var] ~ /^0x[0-9aAbBcCdDeEfF]+/ ||
++ vars[var] ~ /^\"/)
++ print "#define __" var " " vars[var]
++ else
++ print "/* #undef __" var " */"
++ # Ignore variables that don't have boolean, int, hex, or
++ # string values. Ideally, this would be driven by the types
++ # given in option-groups.def.
++ }
++ }
++
++ print ""
++ print "#endif /* __GNU_OPTION_GROUPS_H */"
++}
+--
+2.1.4
+
diff --git a/recipes-core/glibc/glibc/0020-eglibc-Help-bootstrap-cross-toolchain.patch b/recipes-core/glibc/glibc/0020-eglibc-Help-bootstrap-cross-toolchain.patch
new file mode 100644
index 0000000..df93094
--- /dev/null
+++ b/recipes-core/glibc/glibc/0020-eglibc-Help-bootstrap-cross-toolchain.patch
@@ -0,0 +1,100 @@
+From 8fe0d29488b376011cdaaa462d557ffc0b31fb63 Mon Sep 17 00:00:00 2001
+From: Khem Raj <raj.khem at gmail.com>
+Date: Wed, 18 Mar 2015 00:49:28 +0000
+Subject: [PATCH 20/27] eglibc: Help bootstrap cross toolchain
+
+Taken from EGLIBC, r1484 + r1525
+
+ 2007-02-20 Jim Blandy <jimb at codesourcery.com>
+
+ * Makefile (install-headers): Preserve old behavior: depend on
+ $(inst_includedir)/gnu/stubs.h only if install-bootstrap-headers
+ is set; otherwise, place gnu/stubs.h on the 'install-others' list.
+
+ 2007-02-16 Jim Blandy <jimb at codesourcery.com>
+
+ * Makefile: Amend make install-headers to install everything
+ necessary for building a cross-compiler. Install gnu/stubs.h as
+ part of 'install-headers', not 'install-others'.
+ If install-bootstrap-headers is 'yes', install a dummy copy of
+ gnu/stubs.h, instead of computing the real thing.
+ * include/stubs-bootstrap.h: New file.
+
+Upstream-Status: Pending
+Signed-off-by: Khem Raj <raj.khem at gmail.com>
+---
+ Makefile | 22 +++++++++++++++++++++-
+ include/stubs-bootstrap.h | 12 ++++++++++++
+ 2 files changed, 33 insertions(+), 1 deletion(-)
+ create mode 100644 include/stubs-bootstrap.h
+
+diff --git a/Makefile b/Makefile
+index f906391..e4e149e 100644
+--- a/Makefile
++++ b/Makefile
+@@ -69,9 +69,18 @@ subdir-dirs = include
+ vpath %.h $(subdir-dirs)
+
+ # What to install.
+-install-others = $(inst_includedir)/gnu/stubs.h
+ install-bin-script =
+
++# If we're bootstrapping, install a dummy gnu/stubs.h along with the
++# other headers, so 'make install-headers' produces a useable include
++# tree. Otherwise, install gnu/stubs.h later, after the rest of the
++# build is done.
++ifeq ($(install-bootstrap-headers),yes)
++install-headers: $(inst_includedir)/gnu/stubs.h
++else
++install-others = $(inst_includedir)/gnu/stubs.h
++endif
++
+ ifeq (yes,$(build-shared))
+ headers += gnu/lib-names.h
+ endif
+@@ -151,6 +160,16 @@ others: $(common-objpfx)testrun.sh
+
+ subdir-stubs := $(foreach dir,$(subdirs),$(common-objpfx)$(dir)/stubs)
+
++# gnu/stubs.h depends (via the subdir 'stubs' targets) on all the .o
++# files in EGLIBC. For bootstrapping a GCC/EGLIBC pair, an empty
++# gnu/stubs.h is good enough.
++ifeq ($(install-bootstrap-headers),yes)
++$(inst_includedir)/gnu/stubs.h: include/stubs-bootstrap.h $(+force)
++ $(make-target-directory)
++ $(INSTALL_DATA) $< $@
++
++installed-stubs =
++else
+ ifndef abi-variants
+ installed-stubs = $(inst_includedir)/gnu/stubs.h
+ else
+@@ -177,6 +196,7 @@ $(inst_includedir)/gnu/stubs.h: $(+force)
+
+ install-others-nosubdir: $(installed-stubs)
+ endif
++endif
+
+
+ # Since stubs.h is never needed when building the library, we simplify the
+diff --git a/include/stubs-bootstrap.h b/include/stubs-bootstrap.h
+new file mode 100644
+index 0000000..1d2b669
+--- /dev/null
++++ b/include/stubs-bootstrap.h
+@@ -0,0 +1,12 @@
++/* Placeholder stubs.h file for bootstrapping.
++
++ When bootstrapping a GCC/EGLIBC pair, GCC requires that the EGLIBC
++ headers be installed, but we can't fully build EGLIBC without that
++ GCC. So we run the command:
++
++ make install-headers install-bootstrap-headers=yes
++
++ to install the headers GCC needs, but avoid building certain
++ difficult headers. The <gnu/stubs.h> header depends, via the
++ EGLIBC subdir 'stubs' make targets, on every .o file in EGLIBC, but
++ an empty stubs.h like this will do fine for GCC. */
+--
+2.1.4
+
diff --git a/recipes-core/glibc/glibc/0021-eglibc-cherry-picked-from-http-www.eglibc.org-archiv.patch b/recipes-core/glibc/glibc/0021-eglibc-cherry-picked-from-http-www.eglibc.org-archiv.patch
new file mode 100644
index 0000000..38bb8a1
--- /dev/null
+++ b/recipes-core/glibc/glibc/0021-eglibc-cherry-picked-from-http-www.eglibc.org-archiv.patch
@@ -0,0 +1,64 @@
+From fe2ae4f877928dd6bff5bac3f15bce4b50d2bd12 Mon Sep 17 00:00:00 2001
+From: Khem Raj <raj.khem at gmail.com>
+Date: Wed, 18 Mar 2015 00:51:16 +0000
+Subject: [PATCH 21/27] eglibc: cherry-picked from
+ http://www.eglibc.org/archives/patches/msg00772.html
+
+It hasn't yet been merged into glibc
+
+Upstream-Status: Pending
+
+Signed-off-by: Khem Raj <raj.khem at gmail.com>
+---
+ resolv/res_libc.c | 15 +++++++++++++--
+ 1 file changed, 13 insertions(+), 2 deletions(-)
+
+diff --git a/resolv/res_libc.c b/resolv/res_libc.c
+index ee3fa21..29e2340 100644
+--- a/resolv/res_libc.c
++++ b/resolv/res_libc.c
+@@ -22,12 +22,13 @@
+ #include <arpa/nameser.h>
+ #include <resolv.h>
+ #include <bits/libc-lock.h>
+-
++#include <sys/stat.h>
+
+ /* The following bit is copied from res_data.c (where it is #ifdef'ed
+ out) since res_init() should go into libc.so but the rest of that
+ file should not. */
+
++__libc_lock_define_initialized (static, lock);
+ extern unsigned long long int __res_initstamp attribute_hidden;
+ /* We have atomic increment operations on 64-bit platforms. */
+ #if __WORDSIZE == 64
+@@ -35,7 +36,6 @@ extern unsigned long long int __res_initstamp attribute_hidden;
+ # define atomicincunlock(lock) (void) 0
+ # define atomicinc(var) catomic_increment (&(var))
+ #else
+-__libc_lock_define_initialized (static, lock);
+ # define atomicinclock(lock) __libc_lock_lock (lock)
+ # define atomicincunlock(lock) __libc_lock_unlock (lock)
+ # define atomicinc(var) ++var
+@@ -94,7 +94,18 @@ res_init(void) {
+ int
+ __res_maybe_init (res_state resp, int preinit)
+ {
++ static time_t last_mtime;
++ struct stat statbuf;
++ int ret;
++
+ if (resp->options & RES_INIT) {
++ ret = stat (_PATH_RESCONF, &statbuf);
++ __libc_lock_lock (lock);
++ if ((ret == 0) && (last_mtime != statbuf.st_mtime)) {
++ last_mtime = statbuf.st_mtime;
++ atomicinc (__res_initstamp);
++ }
++ __libc_lock_unlock (lock);
+ if (__res_initstamp != resp->_u._ext.initstamp) {
+ if (resp->nscount > 0)
+ __res_iclose (resp, true);
+--
+2.1.4
+
diff --git a/recipes-core/glibc/glibc/0022-eglibc-Clear-cache-lines-on-ppc8xx.patch b/recipes-core/glibc/glibc/0022-eglibc-Clear-cache-lines-on-ppc8xx.patch
new file mode 100644
index 0000000..8a4c9c3
--- /dev/null
+++ b/recipes-core/glibc/glibc/0022-eglibc-Clear-cache-lines-on-ppc8xx.patch
@@ -0,0 +1,81 @@
+From be7273225698074347a71de58006977bb304d7f7 Mon Sep 17 00:00:00 2001
+From: Khem Raj <raj.khem at gmail.com>
+Date: Wed, 18 Mar 2015 00:53:47 +0000
+Subject: [PATCH 22/27] eglibc: Clear cache lines on ppc8xx
+
+2007-06-13 Nathan Sidwell <nathan at codesourcery.com>
+ Mark Shinwell <shinwell at codesourcery.com>
+
+ * sysdeps/unix/sysv/linux/powerpc/libc-start.c
+ (__libc_start_main): Detect 8xx parts and clear
+ __cache_line_size if detected.
+ * sysdeps/unix/sysv/linux/powerpc/dl-sysdep.c
+ (DL_PLATFORM_AUXV): Likewise.
+
+Upstream-Status: Pending
+Signed-off-by: Khem Raj <raj.khem at gmail.com>
+---
+ sysdeps/unix/sysv/linux/powerpc/dl-sysdep.c | 14 +++++++++++++-
+ sysdeps/unix/sysv/linux/powerpc/libc-start.c | 15 ++++++++++++++-
+ 2 files changed, 27 insertions(+), 2 deletions(-)
+
+diff --git a/sysdeps/unix/sysv/linux/powerpc/dl-sysdep.c b/sysdeps/unix/sysv/linux/powerpc/dl-sysdep.c
+index c2504ff..d50f1cb 100644
+--- a/sysdeps/unix/sysv/linux/powerpc/dl-sysdep.c
++++ b/sysdeps/unix/sysv/linux/powerpc/dl-sysdep.c
+@@ -24,9 +24,21 @@ int __cache_line_size attribute_hidden;
+ /* Scan the Aux Vector for the "Data Cache Block Size" entry. If found
+ verify that the static extern __cache_line_size is defined by checking
+ for not NULL. If it is defined then assign the cache block size
+- value to __cache_line_size. */
++ value to __cache_line_size. This is used by memset to
++ optimize setting to zero. We have to detect 8xx processors, which
++ have buggy dcbz implementations that cannot report page faults
++ correctly. That requires reading SPR, which is a privileged
++ operation. Fortunately 2.2.18 and later emulates PowerPC mfspr
++ reads from the PVR register. */
+ #define DL_PLATFORM_AUXV \
+ case AT_DCACHEBSIZE: \
++ if (__LINUX_KERNEL_VERSION >= 0x020218) \
++ { \
++ unsigned pvr = 0; \
++ asm ("mfspr %0, 287" : "=r" (pvr)); \
++ if ((pvr & 0xffff0000) == 0x00500000) \
++ break; \
++ } \
+ __cache_line_size = av->a_un.a_val; \
+ break;
+
+diff --git a/sysdeps/unix/sysv/linux/powerpc/libc-start.c b/sysdeps/unix/sysv/linux/powerpc/libc-start.c
+index a9364c7..a3ed1d4 100644
+--- a/sysdeps/unix/sysv/linux/powerpc/libc-start.c
++++ b/sysdeps/unix/sysv/linux/powerpc/libc-start.c
+@@ -68,11 +68,24 @@ __libc_start_main (int argc, char **argv,
+ rtld_fini = NULL;
+ }
+
+- /* Initialize the __cache_line_size variable from the aux vector. */
++ /* Initialize the __cache_line_size variable from the aux vector.
++ This is used by memset to optimize setting to zero. We have to
++ detect 8xx processors, which have buggy dcbz implementations that
++ cannot report page faults correctly. That requires reading SPR,
++ which is a privileged operation. Fortunately 2.2.18 and later
++ emulates PowerPC mfspr reads from the PVR register. */
+ for (ElfW (auxv_t) * av = auxvec; av->a_type != AT_NULL; ++av)
+ switch (av->a_type)
+ {
+ case AT_DCACHEBSIZE:
++ if (__LINUX_KERNEL_VERSION >= 0x020218)
++ {
++ unsigned pvr = 0;
++
++ asm ("mfspr %0, 287" : "=r" (pvr) :);
++ if ((pvr & 0xffff0000) == 0x00500000)
++ break;
++ }
+ __cache_line_size = av->a_un.a_val;
+ break;
+ }
+--
+2.1.4
+
diff --git a/recipes-core/glibc/glibc/0023-eglibc-Resolve-__fpscr_values-on-SH4.patch b/recipes-core/glibc/glibc/0023-eglibc-Resolve-__fpscr_values-on-SH4.patch
new file mode 100644
index 0000000..9f3d753
--- /dev/null
+++ b/recipes-core/glibc/glibc/0023-eglibc-Resolve-__fpscr_values-on-SH4.patch
@@ -0,0 +1,56 @@
+From 718e7e5db1c8b073adb9a79ec6f167238c2d8bda Mon Sep 17 00:00:00 2001
+From: Khem Raj <raj.khem at gmail.com>
+Date: Wed, 18 Mar 2015 00:55:53 +0000
+Subject: [PATCH 23/27] eglibc: Resolve __fpscr_values on SH4
+
+2010-09-29 Nobuhiro Iwamatsu <iwamatsu at nigauri.org>
+ Andrew Stubbs <ams at codesourcery.com>
+
+ Resolve SH's __fpscr_values to symbol in libc.so.
+
+ * sysdeps/sh/sh4/fpu/fpu_control.h: Add C++ __set_fpscr prototype.
+ * sysdeps/unix/sysv/linux/sh/Versions (GLIBC_2.2): Add __fpscr_values.
+ * sysdeps/unix/sysv/linux/sh/sysdep.S (___fpscr_values): New constant.
+
+Upstream-Status: Pending
+
+Signed-off-by: Khem Raj <raj.khem at gmail.com>
+---
+ sysdeps/unix/sysv/linux/sh/Versions | 1 +
+ sysdeps/unix/sysv/linux/sh/sysdep.S | 11 +++++++++++
+ 2 files changed, 12 insertions(+)
+
+diff --git a/sysdeps/unix/sysv/linux/sh/Versions b/sysdeps/unix/sysv/linux/sh/Versions
+index e0938c4..ca1d7da 100644
+--- a/sysdeps/unix/sysv/linux/sh/Versions
++++ b/sysdeps/unix/sysv/linux/sh/Versions
+@@ -2,6 +2,7 @@ libc {
+ GLIBC_2.2 {
+ # functions used in other libraries
+ __xstat64; __fxstat64; __lxstat64;
++ __fpscr_values;
+
+ # a*
+ alphasort64;
+diff --git a/sysdeps/unix/sysv/linux/sh/sysdep.S b/sysdeps/unix/sysv/linux/sh/sysdep.S
+index a02b7e2..b9be326 100644
+--- a/sysdeps/unix/sysv/linux/sh/sysdep.S
++++ b/sysdeps/unix/sysv/linux/sh/sysdep.S
+@@ -30,3 +30,14 @@ ENTRY (__syscall_error)
+
+ #define __syscall_error __syscall_error_1
+ #include <sysdeps/unix/sh/sysdep.S>
++
++ .data
++ .align 3
++ .globl ___fpscr_values
++ .type ___fpscr_values, @object
++ .size ___fpscr_values, 8
++___fpscr_values:
++ .long 0
++ .long 0x80000
++weak_alias (___fpscr_values, __fpscr_values)
++
+--
+2.1.4
+
diff --git a/recipes-core/glibc/glibc/0024-eglibc-Forward-port-eglibc-options-groups-support.patch b/recipes-core/glibc/glibc/0024-eglibc-Forward-port-eglibc-options-groups-support.patch
new file mode 100644
index 0000000..0514e28
--- /dev/null
+++ b/recipes-core/glibc/glibc/0024-eglibc-Forward-port-eglibc-options-groups-support.patch
@@ -0,0 +1,16842 @@
+From 2a5d7bcf0ff791c95ee1388772408a1bf4454694 Mon Sep 17 00:00:00 2001
+From: Khem Raj <raj.khem at 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 at 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 at 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
+
diff --git a/recipes-core/glibc/glibc/0025-eglibc-Install-PIC-archives.patch b/recipes-core/glibc/glibc/0025-eglibc-Install-PIC-archives.patch
new file mode 100644
index 0000000..c359cce
--- /dev/null
+++ b/recipes-core/glibc/glibc/0025-eglibc-Install-PIC-archives.patch
@@ -0,0 +1,123 @@
+From 5773417fa91a18cd39fb35c9907d72af0ed9ea33 Mon Sep 17 00:00:00 2001
+From: Khem Raj <raj.khem at gmail.com>
+Date: Wed, 18 Mar 2015 01:57:01 +0000
+Subject: [PATCH 25/27] eglibc: Install PIC archives
+
+Forward port from eglibc
+
+2008-02-07 Joseph Myers <joseph at codesourcery.com>
+
+ * Makerules (install-extras, install-map): New variables.
+ (installed-libcs): Add libc_pic.a.
+ (install-lib): Include _pic.a files for versioned shared
+ libraries.
+ (install-map-nosubdir, install-extras-nosubdir): Add rules for
+ installing extra files.
+ (install-no-libc.a-nosubdir): Depend on install-map-nosubdir and
+ install-extras-nosubdir.
+
+2008-04-01 Maxim Kuvyrkov <maxim at codesourcery.com>
+
+ * Makerules (install-lib): Don't install libpthread_pic.a.
+ (install-map): Don't install libpthread_pic.map.
+
+Upstream-Status: Pending
+
+Signed-off-by: Khem Raj <raj.khem at gmail.com>
+---
+ Makerules | 42 ++++++++++++++++++++++++++++++++++++++++--
+ 1 file changed, 40 insertions(+), 2 deletions(-)
+
+diff --git a/Makerules b/Makerules
+index 1dd41aa..41778e1 100644
+--- a/Makerules
++++ b/Makerules
+@@ -713,6 +713,9 @@ ifeq ($(build-shared),yes)
+ $(common-objpfx)libc.so: $(common-objpfx)libc.map
+ endif
+ common-generated += libc.so libc_pic.os
++ifndef subdir
++install-extras := soinit.o sofini.o
++endif
+ ifdef libc.so-version
+ $(common-objpfx)libc.so$(libc.so-version): $(common-objpfx)libc.so
+ $(make-link)
+@@ -955,6 +958,7 @@ endif
+
+ install: check-install-supported
+
++installed-libcs := $(installed-libcs) $(inst_libdir)/libc_pic.a
+ install: $(installed-libcs)
+ $(installed-libcs): $(inst_libdir)/lib$(libprefix)%: lib $(+force)
+ $(make-target-directory)
+@@ -983,6 +987,22 @@ versioned := $(strip $(foreach so,$(install-lib.so),\
+ install-lib.so-versioned := $(filter $(versioned), $(install-lib.so))
+ install-lib.so-unversioned := $(filter-out $(versioned), $(install-lib.so))
+
++# Install the _pic.a files for versioned libraries, and corresponding
++# .map files.
++# libpthread_pic.a breaks mklibs, so don't install it and its map.
++install-lib := $(install-lib) $(install-lib.so-versioned:%.so=%_pic.a)
++install-lib := $(filter-out libpthread_pic.a,$(install-lib))
++# Despite having a soname libhurduser and libmachuser do not use symbol
++# versioning, so don't install the corresponding .map files.
++ifeq ($(build-shared),yes)
++install-map := $(patsubst %.so,%.map,\
++ $(foreach L,$(install-lib.so-versioned),$(notdir $L)))
++install-map := $(filter-out libhurduser.map libmachuser.map libpthread.map,$(install-map))
++ifndef subdir
++install-map := $(install-map) libc.map
++endif
++endif
++
+ # For versioned libraries, we install three files:
+ # $(inst_libdir)/libfoo.so -- for linking, symlink or ld script
+ # $(inst_slibdir)/libfoo.so.NN -- for loading by SONAME, symlink
+@@ -1225,9 +1245,22 @@ $(addprefix $(inst_includedir)/,$(headers-nonh)): $(inst_includedir)/%: \
+ endif # headers-nonh
+ endif # headers
+
++ifdef install-map
++$(addprefix $(inst_libdir)/,$(patsubst lib%.map,lib%_pic.map,$(install-map))): \
++ $(inst_libdir)/lib%_pic.map: $(common-objpfx)lib%.map $(+force)
++ $(do-install)
++endif
++
++ifdef install-extras
++$(addprefix $(inst_libdir)/libc_pic/,$(install-extras)): \
++ $(inst_libdir)/libc_pic/%.o: $(elf-objpfx)%.os $(+force)
++ $(do-install)
++endif
++
+ .PHONY: install-bin-nosubdir install-bin-script-nosubdir \
+ install-rootsbin-nosubdir install-sbin-nosubdir install-lib-nosubdir \
+- install-data-nosubdir install-headers-nosubdir
++ install-data-nosubdir install-headers-nosubdir install-map-nosubdir \
++ install-extras-nosubdir
+ install-bin-nosubdir: $(addprefix $(inst_bindir)/,$(install-bin))
+ install-bin-script-nosubdir: $(addprefix $(inst_bindir)/,$(install-bin-script))
+ install-rootsbin-nosubdir: \
+@@ -1240,6 +1273,10 @@ install-data-nosubdir: $(addprefix $(inst_datadir)/,$(install-data))
+ install-headers-nosubdir: $(addprefix $(inst_includedir)/,$(headers))
+ install-others-nosubdir: $(install-others)
+ install-others-programs-nosubdir: $(install-others-programs)
++install-map-nosubdir: $(addprefix $(inst_libdir)/,\
++ $(patsubst lib%.map,lib%_pic.map,$(install-map)))
++install-extras-nosubdir: $(addprefix $(inst_libdir)/libc_pic/,\
++ $(install-extras))
+
+ # We need all the `-nosubdir' targets so that `install' in the parent
+ # doesn't depend on several things which each iterate over the subdirs.
+@@ -1249,7 +1286,8 @@ install-%:: install-%-nosubdir ;
+
+ .PHONY: install install-no-libc.a-nosubdir
+ install-no-libc.a-nosubdir: install-headers-nosubdir install-data-nosubdir \
+- install-lib-nosubdir install-others-nosubdir
++ install-lib-nosubdir install-others-nosubdir \
++ install-map-nosubdir install-extras-nosubdir
+ ifeq ($(build-programs),yes)
+ install-no-libc.a-nosubdir: install-bin-nosubdir install-bin-script-nosubdir \
+ install-rootsbin-nosubdir install-sbin-nosubdir \
+--
+2.1.4
+
diff --git a/recipes-core/glibc/glibc/0026-eglibc-dl_debug_mask-is-controlled-by-__OPTION_EGLIB.patch b/recipes-core/glibc/glibc/0026-eglibc-dl_debug_mask-is-controlled-by-__OPTION_EGLIB.patch
new file mode 100644
index 0000000..6b611db
--- /dev/null
+++ b/recipes-core/glibc/glibc/0026-eglibc-dl_debug_mask-is-controlled-by-__OPTION_EGLIB.patch
@@ -0,0 +1,556 @@
+From ba069b3107f5ad200c4ab95e69cf368e2353b00a Mon Sep 17 00:00:00 2001
+From: Khem Raj <raj.khem at gmail.com>
+Date: Wed, 18 Mar 2015 00:46:50 +0000
+Subject: [PATCH 26/27] eglibc: dl_debug_mask is controlled by
+ __OPTION_EGLIBC_RTLD_DEBUG
+
+use GLRO_dl_debug_mask
+
+Singed-off-by: Khem Raj <raj.khem at gmail.com>
+
+Upstream-Status: Pending
+---
+ csu/libc-start.c | 4 ++--
+ elf/dl-cache.c | 4 ++--
+ elf/dl-close.c | 6 +++---
+ elf/dl-conflict.c | 2 +-
+ elf/dl-deps.c | 6 +++---
+ elf/dl-error.c | 2 +-
+ elf/dl-fini.c | 4 ++--
+ elf/dl-init.c | 4 ++--
+ elf/dl-load.c | 16 ++++++++--------
+ elf/dl-lookup.c | 14 +++++++-------
+ elf/dl-object.c | 2 +-
+ elf/dl-open.c | 10 +++++-----
+ elf/dl-reloc.c | 2 +-
+ elf/dl-version.c | 2 +-
+ elf/get-dynamic-info.h | 2 +-
+ elf/rtld.c | 22 +++++++++++-----------
+ 16 files changed, 51 insertions(+), 51 deletions(-)
+
+diff --git a/csu/libc-start.c b/csu/libc-start.c
+index 0afa7c0..2151fb6 100644
+--- a/csu/libc-start.c
++++ b/csu/libc-start.c
+@@ -238,7 +238,7 @@ LIBC_START_MAIN (int (*main) (int, char **, char ** MAIN_AUXVEC_DECL),
+
+ /* Call the initializer of the program, if any. */
+ #ifdef SHARED
+- if (__builtin_expect (GLRO(dl_debug_mask) & DL_DEBUG_IMPCALLS, 0))
++ if (__builtin_expect (GLRO_dl_debug_mask & DL_DEBUG_IMPCALLS, 0))
+ GLRO(dl_debug_printf) ("\ninitialize program: %s\n\n", argv[0]);
+ #endif
+ if (init)
+@@ -261,7 +261,7 @@ LIBC_START_MAIN (int (*main) (int, char **, char ** MAIN_AUXVEC_DECL),
+ #endif
+
+ #ifdef SHARED
+- if (__glibc_unlikely (GLRO(dl_debug_mask) & DL_DEBUG_IMPCALLS))
++ if (__glibc_unlikely (GLRO_dl_debug_mask & DL_DEBUG_IMPCALLS))
+ GLRO(dl_debug_printf) ("\ntransferring control: %s\n\n", argv[0]);
+ #endif
+
+diff --git a/elf/dl-cache.c b/elf/dl-cache.c
+index 862f1d8..dab9c51 100644
+--- a/elf/dl-cache.c
++++ b/elf/dl-cache.c
+@@ -194,7 +194,7 @@ _dl_load_cache_lookup (const char *name)
+ const char *best;
+
+ /* Print a message if the loading of libs is traced. */
+- if (__glibc_unlikely (GLRO(dl_debug_mask) & DL_DEBUG_LIBS))
++ if (__glibc_unlikely (GLRO_dl_debug_mask & DL_DEBUG_LIBS))
+ _dl_debug_printf (" search cache=%s\n", LD_SO_CACHE);
+
+ if (cache == NULL)
+@@ -292,7 +292,7 @@ _dl_load_cache_lookup (const char *name)
+ }
+
+ /* Print our result if wanted. */
+- if (__builtin_expect (GLRO(dl_debug_mask) & DL_DEBUG_LIBS, 0)
++ if (__builtin_expect (GLRO_dl_debug_mask & DL_DEBUG_LIBS, 0)
+ && best != NULL)
+ _dl_debug_printf (" trying file=%s\n", best);
+
+diff --git a/elf/dl-close.c b/elf/dl-close.c
+index c897247..b1b4bd5 100644
+--- a/elf/dl-close.c
++++ b/elf/dl-close.c
+@@ -125,7 +125,7 @@ _dl_close_worker (struct link_map *map, bool force)
+ dl_close_state = rerun;
+
+ /* There are still references to this object. Do nothing more. */
+- if (__glibc_unlikely (GLRO(dl_debug_mask) & DL_DEBUG_FILES))
++ if (__glibc_unlikely (GLRO_dl_debug_mask & DL_DEBUG_FILES))
+ _dl_debug_printf ("\nclosing file=%s; direct_opencount=%u\n",
+ map->l_name, map->l_direct_opencount);
+
+@@ -269,7 +269,7 @@ _dl_close_worker (struct link_map *map, bool force)
+ if (imap->l_init_called)
+ {
+ /* When debugging print a message first. */
+- if (__builtin_expect (GLRO(dl_debug_mask) & DL_DEBUG_IMPCALLS,
++ if (__builtin_expect (GLRO_dl_debug_mask & DL_DEBUG_IMPCALLS,
+ 0))
+ _dl_debug_printf ("\ncalling fini: %s [%lu]\n\n",
+ imap->l_name, nsid);
+@@ -711,7 +711,7 @@ _dl_close_worker (struct link_map *map, bool force)
+ free (imap->l_reldeps);
+
+ /* Print debugging message. */
+- if (__glibc_unlikely (GLRO(dl_debug_mask) & DL_DEBUG_FILES))
++ if (__glibc_unlikely (GLRO_dl_debug_mask & DL_DEBUG_FILES))
+ _dl_debug_printf ("\nfile=%s [%lu]; destroying link map\n",
+ imap->l_name, imap->l_ns);
+
+diff --git a/elf/dl-conflict.c b/elf/dl-conflict.c
+index 47a946e..e6a3f21 100644
+--- a/elf/dl-conflict.c
++++ b/elf/dl-conflict.c
+@@ -32,7 +32,7 @@ _dl_resolve_conflicts (struct link_map *l, ElfW(Rela) *conflict,
+ ElfW(Rela) *conflictend)
+ {
+ #if ! ELF_MACHINE_NO_RELA
+- if (__glibc_unlikely (GLRO(dl_debug_mask) & DL_DEBUG_RELOC))
++ if (__glibc_unlikely (GLRO_dl_debug_mask & DL_DEBUG_RELOC))
+ _dl_debug_printf ("\nconflict processing: %s\n", DSO_FILENAME (l->l_name));
+
+ {
+diff --git a/elf/dl-deps.c b/elf/dl-deps.c
+index eee146a..1a4b004 100644
+--- a/elf/dl-deps.c
++++ b/elf/dl-deps.c
+@@ -127,7 +127,7 @@ empty dynamic string token substitution")); \
+ else \
+ { \
+ /* This is for DT_AUXILIARY. */ \
+- if (__glibc_unlikely (GLRO(dl_debug_mask) & DL_DEBUG_LIBS)) \
++ if (__glibc_unlikely (GLRO_dl_debug_mask & DL_DEBUG_LIBS)) \
+ _dl_debug_printf (N_("\
+ cannot load auxiliary `%s' because of empty dynamic string token " \
+ "substitution\n"), __str); \
+@@ -303,7 +303,7 @@ _dl_map_object_deps (struct link_map *map,
+ args.name = name;
+
+ /* Say that we are about to load an auxiliary library. */
+- if (__builtin_expect (GLRO(dl_debug_mask) & DL_DEBUG_LIBS,
++ if (__builtin_expect (GLRO_dl_debug_mask & DL_DEBUG_LIBS,
+ 0))
+ _dl_debug_printf ("load auxiliary object=%s"
+ " requested by file=%s\n",
+@@ -520,7 +520,7 @@ _dl_map_object_deps (struct link_map *map,
+ runp->map->l_reserved = 0;
+ }
+
+- if (__builtin_expect (GLRO(dl_debug_mask) & DL_DEBUG_PRELINK, 0) != 0
++ if (__builtin_expect (GLRO_dl_debug_mask & DL_DEBUG_PRELINK, 0) != 0
+ && map == GL(dl_ns)[LM_ID_BASE]._ns_loaded)
+ {
+ /* If we are to compute conflicts, we have to build local scope
+diff --git a/elf/dl-error.c b/elf/dl-error.c
+index 0fc3fd8..ea82f4d 100644
+--- a/elf/dl-error.c
++++ b/elf/dl-error.c
+@@ -139,7 +139,7 @@ internal_function
+ _dl_signal_cerror (int errcode, const char *objname, const char *occation,
+ const char *errstring)
+ {
+- if (__builtin_expect (GLRO(dl_debug_mask)
++ if (__builtin_expect (GLRO_dl_debug_mask
+ & ~(DL_DEBUG_STATISTICS|DL_DEBUG_PRELINK), 0))
+ _dl_debug_printf ("%s: error: %s: %s (%s)\n", objname, occation,
+ errstring, receiver ? "continued" : "fatal");
+diff --git a/elf/dl-fini.c b/elf/dl-fini.c
+index 6cfe651..f59f7fe 100644
+--- a/elf/dl-fini.c
++++ b/elf/dl-fini.c
+@@ -234,7 +234,7 @@ _dl_fini (void)
+ || l->l_info[DT_FINI] != NULL)
+ {
+ /* When debugging print a message first. */
+- if (__builtin_expect (GLRO(dl_debug_mask)
++ if (__builtin_expect (GLRO_dl_debug_mask
+ & DL_DEBUG_IMPCALLS, 0))
+ _dl_debug_printf ("\ncalling fini: %s [%lu]\n\n",
+ DSO_FILENAME (l->l_name),
+@@ -286,7 +286,7 @@ _dl_fini (void)
+ goto again;
+ }
+
+- if (__glibc_unlikely (GLRO(dl_debug_mask) & DL_DEBUG_STATISTICS))
++ if (__glibc_unlikely (GLRO_dl_debug_mask & DL_DEBUG_STATISTICS))
+ _dl_debug_printf ("\nruntime linker statistics:\n"
+ " final number of relocations: %lu\n"
+ "final number of relocations from cache: %lu\n",
+diff --git a/elf/dl-init.c b/elf/dl-init.c
+index 2f85731..e46e8b6 100644
+--- a/elf/dl-init.c
++++ b/elf/dl-init.c
+@@ -46,7 +46,7 @@ call_init (struct link_map *l, int argc, char **argv, char **env)
+ return;
+
+ /* Print a debug message if wanted. */
+- if (__glibc_unlikely (GLRO(dl_debug_mask) & DL_DEBUG_IMPCALLS))
++ if (__glibc_unlikely (GLRO_dl_debug_mask & DL_DEBUG_IMPCALLS))
+ _dl_debug_printf ("\ncalling init: %s\n\n",
+ DSO_FILENAME (l->l_name));
+
+@@ -96,7 +96,7 @@ _dl_init (struct link_map *main_map, int argc, char **argv, char **env)
+ ElfW(Addr) *addrs;
+ unsigned int cnt;
+
+- if (__glibc_unlikely (GLRO(dl_debug_mask) & DL_DEBUG_IMPCALLS))
++ if (__glibc_unlikely (GLRO_dl_debug_mask & DL_DEBUG_IMPCALLS))
+ _dl_debug_printf ("\ncalling preinit: %s\n\n",
+ DSO_FILENAME (main_map->l_name));
+
+diff --git a/elf/dl-load.c b/elf/dl-load.c
+index f664f50..8c28744 100644
+--- a/elf/dl-load.c
++++ b/elf/dl-load.c
+@@ -943,7 +943,7 @@ _dl_map_object_from_fd (const char *name, int fd, struct filebuf *fbp,
+ }
+
+ /* Print debugging message. */
+- if (__glibc_unlikely (GLRO(dl_debug_mask) & DL_DEBUG_FILES))
++ if (__glibc_unlikely (GLRO_dl_debug_mask & DL_DEBUG_FILES))
+ _dl_debug_printf ("file=%s [%lu]; generating link map\n", name, nsid);
+
+ /* This is the ELF header. We read it in `open_verify'. */
+@@ -1347,7 +1347,7 @@ cannot enable executable stack as shared object requires");
+
+ l->l_entry += l->l_addr;
+
+- if (__glibc_unlikely (GLRO(dl_debug_mask) & DL_DEBUG_FILES))
++ if (__glibc_unlikely (GLRO_dl_debug_mask & DL_DEBUG_FILES))
+ _dl_debug_printf ("\
+ dynamic: 0x%0*lx base: 0x%0*lx size: 0x%0*Zx\n\
+ entry: 0x%0*lx phdr: 0x%0*lx phnum: %*u\n\n",
+@@ -1789,7 +1789,7 @@ open_path (const char *name, size_t namelen, int mode,
+
+ /* If we are debugging the search for libraries print the path
+ now if it hasn't happened now. */
+- if (__glibc_unlikely (GLRO(dl_debug_mask) & DL_DEBUG_LIBS)
++ if (__glibc_unlikely (GLRO_dl_debug_mask & DL_DEBUG_LIBS)
+ && current_what != this_dir->what)
+ {
+ current_what = this_dir->what;
+@@ -1810,7 +1810,7 @@ open_path (const char *name, size_t namelen, int mode,
+ - buf);
+
+ /* Print name we try if this is wanted. */
+- if (__glibc_unlikely (GLRO(dl_debug_mask) & DL_DEBUG_LIBS))
++ if (__glibc_unlikely (GLRO_dl_debug_mask & DL_DEBUG_LIBS))
+ _dl_debug_printf (" trying file=%s\n", buf);
+
+ fd = open_verify (buf, fbp, loader, whatcode, mode,
+@@ -1955,7 +1955,7 @@ _dl_map_object (struct link_map *loader, const char *name,
+ }
+
+ /* Display information if we are debugging. */
+- if (__glibc_unlikely (GLRO(dl_debug_mask) & DL_DEBUG_FILES)
++ if (__glibc_unlikely (GLRO_dl_debug_mask & DL_DEBUG_FILES)
+ && loader != NULL)
+ _dl_debug_printf ((mode & __RTLD_CALLMAP) == 0
+ ? "\nfile=%s [%lu]; needed by %s [%lu]\n"
+@@ -1997,7 +1997,7 @@ _dl_map_object (struct link_map *loader, const char *name,
+
+ size_t namelen = strlen (name) + 1;
+
+- if (__glibc_unlikely (GLRO(dl_debug_mask) & DL_DEBUG_LIBS))
++ if (__glibc_unlikely (GLRO_dl_debug_mask & DL_DEBUG_LIBS))
+ _dl_debug_printf ("find library=%s [%lu]; searching\n", name, nsid);
+
+ fd = -1;
+@@ -2119,7 +2119,7 @@ _dl_map_object (struct link_map *loader, const char *name,
+ #endif
+
+ /* Add another newline when we are tracing the library loading. */
+- if (__glibc_unlikely (GLRO(dl_debug_mask) & DL_DEBUG_LIBS))
++ if (__glibc_unlikely (GLRO_dl_debug_mask & DL_DEBUG_LIBS))
+ _dl_debug_printf ("\n");
+ }
+ else
+@@ -2152,7 +2152,7 @@ _dl_map_object (struct link_map *loader, const char *name,
+ if (__glibc_unlikely (fd == -1))
+ {
+ if (trace_mode
+- && __glibc_likely ((GLRO(dl_debug_mask) & DL_DEBUG_PRELINK) == 0))
++ && __glibc_likely ((GLRO_dl_debug_mask & DL_DEBUG_PRELINK) == 0))
+ {
+ /* We haven't found an appropriate library. But since we
+ are only interested in the list of libraries this isn't
+diff --git a/elf/dl-lookup.c b/elf/dl-lookup.c
+index 11cb44b..588c3e4 100644
+--- a/elf/dl-lookup.c
++++ b/elf/dl-lookup.c
+@@ -302,7 +302,7 @@ do_lookup_unique (const char *undef_name, uint_fast32_t new_hash,
+ hash table. */
+ if (__glibc_unlikely (tab->size))
+ {
+- assert (GLRO(dl_debug_mask) & DL_DEBUG_PRELINK);
++ assert (GLRO_dl_debug_mask & DL_DEBUG_PRELINK);
+ goto success;
+ }
+ #endif
+@@ -378,7 +378,7 @@ do_lookup_x (const char *undef_name, uint_fast32_t new_hash,
+ continue;
+
+ /* Print some debugging info if wanted. */
+- if (__glibc_unlikely (GLRO(dl_debug_mask) & DL_DEBUG_SYMBOLS))
++ if (__glibc_unlikely (GLRO_dl_debug_mask & DL_DEBUG_SYMBOLS))
+ _dl_debug_printf ("symbol=%s; lookup in file=%s [%lu]\n",
+ undef_name, DSO_FILENAME (map->l_name),
+ map->l_ns);
+@@ -755,7 +755,7 @@ add_dependency (struct link_map *undef_map, struct link_map *map, int flags)
+ }
+
+ /* Display information if we are debugging. */
+- if (__glibc_unlikely (GLRO(dl_debug_mask) & DL_DEBUG_FILES))
++ if (__glibc_unlikely (GLRO_dl_debug_mask & DL_DEBUG_FILES))
+ _dl_debug_printf ("\
+ \nfile=%s [%lu]; needed by %s [%lu] (relocation dependency)\n\n",
+ DSO_FILENAME (map->l_name),
+@@ -859,7 +859,7 @@ _dl_lookup_symbol_x (const char *undef_name, struct link_map *undef_map,
+ {
+ if ((*ref == NULL || ELFW(ST_BIND) ((*ref)->st_info) != STB_WEAK)
+ && skip_map == NULL
+- && !(GLRO(dl_debug_mask) & DL_DEBUG_UNUSED))
++ && !(GLRO_dl_debug_mask & DL_DEBUG_UNUSED))
+ {
+ /* We could find no value for a strong reference. */
+ const char *reference_name = undef_map ? undef_map->l_name : "";
+@@ -935,7 +935,7 @@ _dl_lookup_symbol_x (const char *undef_name, struct link_map *undef_map,
+ if (__glibc_unlikely (current_value.m->l_used == 0))
+ current_value.m->l_used = 1;
+
+- if (__glibc_unlikely (GLRO(dl_debug_mask)
++ if (__glibc_unlikely (GLRO_dl_debug_mask
+ & (DL_DEBUG_BINDINGS|DL_DEBUG_PRELINK)))
+ _dl_debug_bindings (undef_name, undef_map, ref,
+ ¤t_value, version, type_class, protected);
+@@ -1000,7 +1000,7 @@ _dl_debug_bindings (const char *undef_name, struct link_map *undef_map,
+ {
+ const char *reference_name = undef_map->l_name;
+
+- if (GLRO(dl_debug_mask) & DL_DEBUG_BINDINGS)
++ if (GLRO_dl_debug_mask & DL_DEBUG_BINDINGS)
+ {
+ _dl_debug_printf ("binding file %s [%lu] to %s [%lu]: %s symbol `%s'",
+ DSO_FILENAME (reference_name),
+@@ -1014,7 +1014,7 @@ _dl_debug_bindings (const char *undef_name, struct link_map *undef_map,
+ _dl_debug_printf_c ("\n");
+ }
+ #ifdef SHARED
+- if (GLRO(dl_debug_mask) & DL_DEBUG_PRELINK)
++ if (GLRO_dl_debug_mask & DL_DEBUG_PRELINK)
+ {
+ int conflict = 0;
+ struct sym_val val = { NULL, NULL };
+diff --git a/elf/dl-object.c b/elf/dl-object.c
+index 1d58bbc..938a257 100644
+--- a/elf/dl-object.c
++++ b/elf/dl-object.c
+@@ -98,7 +98,7 @@ _dl_new_object (char *realname, const char *libname, int type,
+ new->l_type = type;
+ /* If we set the bit now since we know it is never used we avoid
+ dirtying the cache line later. */
+- if ((GLRO(dl_debug_mask) & DL_DEBUG_UNUSED) == 0)
++ if ((GLRO_dl_debug_mask & DL_DEBUG_UNUSED) == 0)
+ new->l_used = 1;
+ new->l_loader = loader;
+ #if NO_TLS_OFFSET != 0
+diff --git a/elf/dl-open.c b/elf/dl-open.c
+index 2db1c02..1288604 100644
+--- a/elf/dl-open.c
++++ b/elf/dl-open.c
+@@ -147,7 +147,7 @@ add_to_global (struct link_map *new)
+ ns->_ns_main_searchlist->r_list[new_nlist++] = map;
+
+ /* We modify the global scope. Report this. */
+- if (__glibc_unlikely (GLRO(dl_debug_mask) & DL_DEBUG_SCOPES))
++ if (__glibc_unlikely (GLRO_dl_debug_mask & DL_DEBUG_SCOPES))
+ _dl_debug_printf ("\nadd %s [%lu] to global scope\n",
+ map->l_name, map->l_ns);
+ }
+@@ -251,7 +251,7 @@ dl_open_worker (void *a)
+ if (__glibc_unlikely (new->l_searchlist.r_list != NULL))
+ {
+ /* Let the user know about the opencount. */
+- if (__glibc_unlikely (GLRO(dl_debug_mask) & DL_DEBUG_FILES))
++ if (__glibc_unlikely (GLRO_dl_debug_mask & DL_DEBUG_FILES))
+ _dl_debug_printf ("opening file=%s [%lu]; direct_opencount=%u\n\n",
+ new->l_name, new->l_ns, new->l_direct_opencount);
+
+@@ -302,7 +302,7 @@ dl_open_worker (void *a)
+ LIBC_PROBE (map_complete, 3, args->nsid, r, new);
+
+ /* Print scope information. */
+- if (__glibc_unlikely (GLRO(dl_debug_mask) & DL_DEBUG_SCOPES))
++ if (__glibc_unlikely (GLRO_dl_debug_mask & DL_DEBUG_SCOPES))
+ _dl_show_scope (new, 0);
+
+ /* Only do lazy relocation if `LD_BIND_NOW' is not set. */
+@@ -519,7 +519,7 @@ dl_open_worker (void *a)
+ }
+
+ /* Print scope information. */
+- if (__glibc_unlikely (GLRO(dl_debug_mask) & DL_DEBUG_SCOPES))
++ if (__glibc_unlikely (GLRO_dl_debug_mask & DL_DEBUG_SCOPES))
+ _dl_show_scope (imap, from_scope);
+ }
+
+@@ -577,7 +577,7 @@ TLS generation counter wrapped! Please report this."));
+ #endif
+
+ /* Let the user know about the opencount. */
+- if (__glibc_unlikely (GLRO(dl_debug_mask) & DL_DEBUG_FILES))
++ if (__glibc_unlikely (GLRO_dl_debug_mask & DL_DEBUG_FILES))
+ _dl_debug_printf ("opening file=%s [%lu]; direct_opencount=%u\n\n",
+ new->l_name, new->l_ns, new->l_direct_opencount);
+ }
+diff --git a/elf/dl-reloc.c b/elf/dl-reloc.c
+index 61252d7..4c83815 100644
+--- a/elf/dl-reloc.c
++++ b/elf/dl-reloc.c
+@@ -178,7 +178,7 @@ _dl_relocate_object (struct link_map *l, struct r_scope_elem *scope[],
+ && __builtin_expect (l->l_info[DT_BIND_NOW] != NULL, 0))
+ lazy = 0;
+
+- if (__glibc_unlikely (GLRO(dl_debug_mask) & DL_DEBUG_RELOC))
++ if (__glibc_unlikely (GLRO_dl_debug_mask & DL_DEBUG_RELOC))
+ _dl_debug_printf ("\nrelocation processing: %s%s\n",
+ DSO_FILENAME (l->l_name), lazy ? " (lazy)" : "");
+
+diff --git a/elf/dl-version.c b/elf/dl-version.c
+index f6e5cd9..320628c 100644
+--- a/elf/dl-version.c
++++ b/elf/dl-version.c
+@@ -82,7 +82,7 @@ match_symbol (const char *name, Lmid_t ns, ElfW(Word) hash, const char *string,
+ int result = 0;
+
+ /* Display information about what we are doing while debugging. */
+- if (__glibc_unlikely (GLRO(dl_debug_mask) & DL_DEBUG_VERSIONS))
++ if (__glibc_unlikely (GLRO_dl_debug_mask & DL_DEBUG_VERSIONS))
+ _dl_debug_printf ("\
+ checking for version `%s' in file %s [%lu] required by file %s [%lu]\n",
+ string, DSO_FILENAME (map->l_name),
+diff --git a/elf/get-dynamic-info.h b/elf/get-dynamic-info.h
+index dc8359d..7774fda 100644
+--- a/elf/get-dynamic-info.h
++++ b/elf/get-dynamic-info.h
+@@ -166,7 +166,7 @@ elf_get_dynamic_info (struct link_map *l, ElfW(Dyn) *temp)
+ them. Therefore to avoid breaking existing applications the
+ best we can do is add a warning during debugging with the
+ intent of notifying the user of the problem. */
+- if (__builtin_expect (GLRO(dl_debug_mask) & DL_DEBUG_FILES, 0)
++ if (__builtin_expect (GLRO_dl_debug_mask & DL_DEBUG_FILES, 0)
+ && l->l_flags_1 & ~DT_1_SUPPORTED_MASK)
+ _dl_debug_printf ("\nWARNING: Unsupported flag value(s) of 0x%x in DT_FLAGS_1.\n",
+ l->l_flags_1 & ~DT_1_SUPPORTED_MASK);
+diff --git a/elf/rtld.c b/elf/rtld.c
+index fc3a2db..59c4637 100644
+--- a/elf/rtld.c
++++ b/elf/rtld.c
+@@ -323,7 +323,7 @@ _dl_start_final (void *arg, struct dl_start_final_info *info)
+ }
+ #endif
+
+- if (__glibc_unlikely (GLRO(dl_debug_mask) & DL_DEBUG_STATISTICS))
++ if (__glibc_unlikely (GLRO_dl_debug_mask & DL_DEBUG_STATISTICS))
+ {
+ #ifndef HP_TIMING_NONAVAIL
+ print_statistics (&rtld_total_time);
+@@ -1701,7 +1701,7 @@ ERROR: ld.so: object '%s' cannot be loaded as audit interface: %s; ignored.\n",
+ after relocation. */
+ struct link_map *l;
+
+- if (GLRO(dl_debug_mask) & DL_DEBUG_PRELINK)
++ if (GLRO_dl_debug_mask & DL_DEBUG_PRELINK)
+ {
+ struct r_scope_elem *scope = &main_map->l_searchlist;
+
+@@ -1731,7 +1731,7 @@ ERROR: ld.so: object '%s' cannot be loaded as audit interface: %s; ignored.\n",
+ _dl_printf ("\n");
+ }
+ }
+- else if (GLRO(dl_debug_mask) & DL_DEBUG_UNUSED)
++ else if (GLRO_dl_debug_mask & DL_DEBUG_UNUSED)
+ {
+ /* Look through the dependencies of the main executable
+ and determine which of them is not actually
+@@ -1839,7 +1839,7 @@ ERROR: ld.so: object '%s' cannot be loaded as audit interface: %s; ignored.\n",
+ }
+ }
+
+- if ((GLRO(dl_debug_mask) & DL_DEBUG_PRELINK)
++ if ((GLRO_dl_debug_mask & DL_DEBUG_PRELINK)
+ && rtld_multiple_ref)
+ {
+ /* Mark the link map as not yet relocated again. */
+@@ -1972,7 +1972,7 @@ ERROR: ld.so: object '%s' cannot be loaded as audit interface: %s; ignored.\n",
+ if (r_list == r_listend && liblist == liblistend)
+ prelinked = true;
+
+- if (__glibc_unlikely (GLRO(dl_debug_mask) & DL_DEBUG_LIBS))
++ if (__glibc_unlikely (GLRO_dl_debug_mask & DL_DEBUG_LIBS))
+ _dl_debug_printf ("\nprelink checking: %s\n",
+ prelinked ? "ok" : "failed");
+ }
+@@ -1990,7 +1990,7 @@ ERROR: ld.so: object '%s' cannot be loaded as audit interface: %s; ignored.\n",
+ GLRO(dl_init_all_dirs) = GL(dl_all_dirs);
+
+ /* Print scope information. */
+- if (__glibc_unlikely (GLRO(dl_debug_mask) & DL_DEBUG_SCOPES))
++ if (__glibc_unlikely (GLRO_dl_debug_mask & DL_DEBUG_SCOPES))
+ {
+ _dl_debug_printf ("\nInitial object scopes\n");
+
+@@ -2265,7 +2265,7 @@ process_dl_debug (const char *dl_debug)
+ if (debopts[cnt].len == len
+ && memcmp (dl_debug, debopts[cnt].name, len) == 0)
+ {
+- GLRO(dl_debug_mask) |= debopts[cnt].mask;
++ GLRO_dl_debug_mask |= debopts[cnt].mask;
+ any_debug = 1;
+ break;
+ }
+@@ -2286,7 +2286,7 @@ warning: debug option `%s' unknown; try LD_DEBUG=help\n", copy);
+ ++dl_debug;
+ }
+
+- if (GLRO(dl_debug_mask) & DL_DEBUG_UNUSED)
++ if (GLRO_dl_debug_mask & DL_DEBUG_UNUSED)
+ {
+ /* In order to get an accurate picture of whether a particular
+ DT_NEEDED entry is actually used we have to process both
+@@ -2294,7 +2294,7 @@ warning: debug option `%s' unknown; try LD_DEBUG=help\n", copy);
+ GLRO(dl_lazy) = 0;
+ }
+
+- if (GLRO(dl_debug_mask) & DL_DEBUG_HELP)
++ if (GLRO_dl_debug_mask & DL_DEBUG_HELP)
+ {
+ size_t cnt;
+
+@@ -2499,7 +2499,7 @@ process_envvars (enum mode *modep)
+ mode = trace;
+ GLRO(dl_verbose) = 1;
+ #if __OPTION_EGLIBC_RTLD_DEBUG
+- GLRO(dl_debug_mask) |= DL_DEBUG_PRELINK;
++ GLRO_dl_debug_mask |= DL_DEBUG_PRELINK;
+ #endif
+ GLRO(dl_trace_prelink) = &envline[17];
+ }
+@@ -2548,7 +2548,7 @@ process_envvars (enum mode *modep)
+ {
+ unsetenv ("MALLOC_CHECK_");
+ #if __OPTION_EGLIBC_RTLD_DEBUG
+- GLRO(dl_debug_mask) = 0;
++ GLRO_dl_debug_mask = 0;
+ #endif
+ }
+
+--
+2.1.4
+
diff --git a/recipes-core/glibc/glibc/0027-eglibc-use-option-groups-Conditionally-exclude-c-tes.patch b/recipes-core/glibc/glibc/0027-eglibc-use-option-groups-Conditionally-exclude-c-tes.patch
new file mode 100644
index 0000000..4106167
--- /dev/null
+++ b/recipes-core/glibc/glibc/0027-eglibc-use-option-groups-Conditionally-exclude-c-tes.patch
@@ -0,0 +1,145 @@
+From e98779aa56fae0346dff2d0b72acadd0eaf01891 Mon Sep 17 00:00:00 2001
+From: Khem Raj <raj.khem at gmail.com>
+Date: Wed, 27 May 2015 16:10:50 -0700
+Subject: [PATCH 27/27] eglibc-use-option-groups: Conditionally exclude c++
+ tests
+
+ Some test programs written in c++ are still included in spite of
+ "libc-cxx-tests" being omitted from DISTRO_FEATURES_LIBC.
+ All .cc programs are compiled with g++.
+ g++ automatically specifies linking against the C++ library.
+ This patch conditionally excludes the following tests as well:
+
+ bug-atexit3-lib.cc
+ tst-cancel24.cc
+ tst-cancel24-static.cc
+ tst-unique3lib.cc
+ tst-unique3lib2.cc
+ tst-unique4lib.cc
+ tst-unique3.cc
+ tst-unique4.cc
+
+ Tested with DISTRO_FEATURES_LIBC_remove = " libc-cxx-tests"
+
+ [YOCTO #7003]
+
+Signed-off-by: Juro Bystricky <juro.bystricky at intel.com>
+Signed-off-by: Khem Raj <raj.khem at gmail.com>
+---
+ dlfcn/Makefile | 8 ++++++--
+ elf/Makefile | 19 ++++++++++++++-----
+ nptl/Makefile | 12 ++++++++++--
+ 3 files changed, 30 insertions(+), 9 deletions(-)
+
+diff --git a/dlfcn/Makefile b/dlfcn/Makefile
+index 3827607..920bd58 100644
+--- a/dlfcn/Makefile
++++ b/dlfcn/Makefile
+@@ -39,16 +39,20 @@ ifeq (yes,$(build-shared))
+ tests = glrefmain failtest tst-dladdr default errmsg1 tstcxaatexit \
+ bug-dlopen1 bug-dlsym1 tst-dlinfo bug-atexit1 bug-atexit2 \
+ tstatexit bug-dl-leaf tst-rec-dlopen
+-endif
+-
+ tests-$(OPTION_EGLIBC_CXX_TESTS) += bug-atexit3
+
++endif
++
+ modules-names = glreflib1 glreflib2 glreflib3 failtestmod defaultmod1 \
+ defaultmod2 errmsg1mod modatexit modcxaatexit \
+ bug-dlsym1-lib1 bug-dlsym1-lib2 bug-atexit1-lib \
+ bug-atexit2-lib bug-dl-leaf-lib \
+ bug-dl-leaf-lib-cb moddummy1 moddummy2
+
++ifeq (y,$(OPTION_EGLIBC_CXX_TESTS))
++modules-names += bug-atexit3-lib
++endif
++
+ failtestmod.so-no-z-defs = yes
+ glreflib2.so-no-z-defs = yes
+ errmsg1mod.so-no-z-defs = yes
+diff --git a/elf/Makefile b/elf/Makefile
+index 71a18a1..26fe3c5 100644
+--- a/elf/Makefile
++++ b/elf/Makefile
+@@ -17,6 +17,8 @@
+
+ # Makefile for elf subdirectory of GNU C Library.
+
++include ../option-groups.mak
++
+ subdir := elf
+
+ include ../Makeconfig
+@@ -145,12 +147,15 @@ tests += loadtest restest1 preloadtest loadfail multiload origtest resolvfail \
+ unload3 unload4 unload5 unload6 unload7 unload8 tst-global1 order2 \
+ tst-audit1 tst-audit2 tst-audit8 tst-audit9 \
+ tst-stackguard1 tst-addr1 tst-thrlock \
+- tst-unique1 tst-unique2 $(if $(CXX),tst-unique3 tst-unique4 \
+- tst-nodelete) \
++ tst-unique1 tst-unique2 \
+ tst-initorder tst-initorder2 tst-relsort1 tst-null-argv \
+ tst-ptrguard1 tst-tlsalign tst-tlsalign-extern tst-nodelete-opened \
+ tst-nodelete2
+ # reldep9
++ifeq (y,$(OPTION_EGLIBC_CXX_TESTS))
++tests += $(if $(CXX),tst-unique3 tst-unique4 tst-nodelete)
++endif
++
+ ifeq ($(build-hardcoded-path-in-tests),yes)
+ tests += tst-dlopen-aout
+ LDFLAGS-tst-dlopen-aout = $(no-pie-ldflag)
+@@ -209,9 +214,6 @@ modules-names = testobj1 testobj2 testobj3 testobj4 testobj5 testobj6 \
+ tst-unique1mod1 tst-unique1mod2 \
+ tst-unique2mod1 tst-unique2mod2 \
+ tst-auditmod9a tst-auditmod9b \
+- $(if $(CXX),tst-unique3lib tst-unique3lib2 tst-unique4lib \
+- tst-nodelete-uniquemod tst-nodelete-rtldmod \
+- tst-nodelete-zmod) \
+ tst-initordera1 tst-initorderb1 \
+ tst-initordera2 tst-initorderb2 \
+ tst-initordera3 tst-initordera4 \
+@@ -220,6 +222,13 @@ modules-names = testobj1 testobj2 testobj3 testobj4 testobj5 testobj6 \
+ tst-relsort1mod1 tst-relsort1mod2 tst-array2dep \
+ tst-array5dep tst-null-argv-lib \
+ tst-tlsalign-lib tst-nodelete-opened-lib tst-nodelete2mod
++
++ifeq (y,$(OPTION_EGLIBC_CXX_TESTS))
++modules-names += $(if $(CXX),tst-unique3lib tst-unique3lib2 tst-unique4lib \
++ tst-nodelete-uniquemod tst-nodelete-rtldmod \
++ tst-nodelete-zmod)
++endif
++
+ ifeq (yes,$(have-protected-data))
+ modules-names += tst-protected1moda tst-protected1modb
+ tests += tst-protected1a tst-protected1b
+diff --git a/nptl/Makefile b/nptl/Makefile
+index 596ca3c..50a708b 100644
+--- a/nptl/Makefile
++++ b/nptl/Makefile
+@@ -390,12 +390,20 @@ link-libc-static := $(common-objpfx)libc.a $(static-gnulib) \
+ $(common-objpfx)libc.a
+
+ tests-static += tst-locale1 tst-locale2 tst-stackguard1-static \
+- tst-cancel21-static tst-cancel24-static tst-cond8-static \
++ tst-cancel21-static tst-cond8-static \
+ tst-mutex8-static tst-mutexpi8-static tst-sem11-static \
+ tst-sem12-static
+-tests += tst-stackguard1-static tst-cancel21-static tst-cancel24-static \
++
++ifeq (y,$(OPTION_EGLIBC_CXX_TESTS))
++tests-static += tst-cancel24-static
++endif
++
++tests += tst-stackguard1-static tst-cancel21-static \
+ tst-cond8-static tst-mutex8-static tst-mutexpi8-static \
+ tst-sem11-static tst-sem12-static
++
++tests-$(OPTION_EGLIBC_CXX_TESTS) += tst-cancel24-static
++
+ xtests-static += tst-setuid1-static
+
+ # These tests are linked with libc before libpthread
+--
+2.1.4
+
diff --git a/recipes-core/glibc/glibc/CVE-2012-3406-Stack-overflow-in-vfprintf-BZ-16617.patch b/recipes-core/glibc/glibc/CVE-2012-3406-Stack-overflow-in-vfprintf-BZ-16617.patch
new file mode 100644
index 0000000..8cfdbea
--- /dev/null
+++ b/recipes-core/glibc/glibc/CVE-2012-3406-Stack-overflow-in-vfprintf-BZ-16617.patch
@@ -0,0 +1,339 @@
+From a5357b7ce2a2982c5778435704bcdb55ce3667a0 Mon Sep 17 00:00:00 2001
+From: Jeff Law <law at redhat.com>
+Date: Mon, 15 Dec 2014 10:09:32 +0100
+Subject: [PATCH] CVE-2012-3406: Stack overflow in vfprintf [BZ #16617]
+
+A larger number of format specifiers coudld cause a stack overflow,
+potentially allowing to bypass _FORTIFY_SOURCE format string
+protection.
+---
+ ChangeLog | 9 +++++++
+ NEWS | 13 +++++----
+ stdio-common/Makefile | 2 +-
+ stdio-common/bug23-2.c | 70 +++++++++++++++++++++++++++++++++++++++++++++++++
+ stdio-common/bug23-3.c | 50 +++++++++++++++++++++++++++++++++++
+ stdio-common/bug23-4.c | 31 ++++++++++++++++++++++
+ stdio-common/vfprintf.c | 40 ++++++++++++++++++++++++++--
+ 7 files changed, 207 insertions(+), 8 deletions(-)
+ create mode 100644 stdio-common/bug23-2.c
+ create mode 100644 stdio-common/bug23-3.c
+ create mode 100644 stdio-common/bug23-4.c
+
+Index: git/ChangeLog
+===================================================================
+--- git.orig/ChangeLog
++++ git/ChangeLog
+@@ -1,3 +1,12 @@
++2014-12-15 Jeff Law <law at redhat.com>
++
++ [BZ #16617]
++ * stdio-common/vfprintf.c (vfprintf): Allocate large specs array
++ on the heap. (CVE-2012-3406)
++ * stdio-common/bug23-2.c, stdio-common/bug23-3.c: New file.
++ * stdio-common/bug23-4.c: New file. Test case by Joseph Myers.
++ * stdio-common/Makefile (tests): Add bug23-2, bug23-3, bug23-4.
++
+ 2014-11-19 Carlos O'Donell <carlos at redhat.com>
+ Florian Weimer <fweimer at redhat.com>
+ Joseph Myers <joseph at codesourcery.com>
+Index: git/NEWS
+===================================================================
+--- git.orig/NEWS
++++ git/NEWS
+@@ -13,24 +13,28 @@ Version 2.20
+ 15698, 15804, 15894, 15946, 16002, 16064, 16095, 16194, 16198, 16275,
+ 16284, 16287, 16315, 16348, 16349, 16354, 16357, 16362, 16447, 16516,
+ 16532, 16539, 16545, 16561, 16562, 16564, 16574, 16599, 16600, 16609,
+- 16610, 16611, 16613, 16619, 16623, 16629, 16632, 16634, 16639, 16642,
+- 16648, 16649, 16670, 16674, 16677, 16680, 16681, 16683, 16689, 16695,
+- 16701, 16706, 16707, 16712, 16713, 16714, 16724, 16731, 16739, 16740,
+- 16743, 16754, 16758, 16759, 16760, 16770, 16786, 16789, 16791, 16796,
+- 16799, 16800, 16815, 16823, 16824, 16831, 16838, 16839, 16849, 16854,
+- 16876, 16877, 16878, 16882, 16885, 16888, 16890, 16892, 16912, 16915,
+- 16916, 16917, 16918, 16922, 16927, 16928, 16932, 16943, 16958, 16965,
+- 16966, 16967, 16977, 16978, 16984, 16990, 16996, 17009, 17022, 17031,
+- 17042, 17048, 17050, 17058, 17061, 17062, 17069, 17075, 17078, 17079,
+- 17084, 17086, 17088, 17092, 17097, 17125, 17135, 17137, 17150, 17153,
+- 17187, 17213, 17259, 17261, 17262, 17263, 17319, 17325, 17354, 17625.
+-
++ 16610, 16611, 16613, 16617, 16619, 16623, 16629, 16632, 16634, 16639,
++ 16642, 16648, 16649, 16670, 16674, 16677, 16680, 16681, 16683, 16689,
++ 16695, 16701, 16706, 16707, 16712, 16713, 16714, 16724, 16731, 16739,
++ 16740, 16743, 16754, 16758, 16759, 16760, 16770, 16786, 16789, 16791,
++ 16796, 16799, 16800, 16815, 16823, 16824, 16831, 16838, 16839, 16849,
++ 16854, 16876, 16877, 16878, 16882, 16885, 16888, 16890, 16892, 16912,
++ 16915, 16916, 16917, 16918, 16922, 16927, 16928, 16932, 16943, 16958,
++ 16965, 16966, 16967, 16977, 16978, 16984, 16990, 16996, 17009, 17022,
++ 17031, 17042, 17048, 17050, 17058, 17061, 17062, 17069, 17075, 17078,
++ 17079, 17084, 17086, 17088, 17092, 17097, 17125, 17135, 17137, 17150,
++ 17153, 17187, 17213, 17259, 17261, 17262, 17263, 17319, 17325, 17354,
++ 17625.
++
+ * CVE-2104-7817 The wordexp function could ignore the WRDE_NOCMD flag
+ under certain input conditions resulting in the execution of a shell for
+ command substitution when the applicaiton did not request it. The
+ implementation now checks WRDE_NOCMD immediately before executing the
+ shell and returns the error WRDE_CMDSUB as expected.
+
++* CVE-2012-3406 printf-style functions could run into a stack overflow when
++ processing format strings with a large number of format specifiers.
++
+ * Reverted change of ABI data structures for s390 and s390x:
+ On s390 and s390x the size of struct ucontext and jmp_buf was increased in
+ 2.19. This change is reverted in 2.20. The introduced 2.19 symbol versions
+Index: git/stdio-common/bug23-2.c
+===================================================================
+--- /dev/null
++++ git/stdio-common/bug23-2.c
+@@ -0,0 +1,70 @@
++#include <stdio.h>
++#include <string.h>
++#include <stdlib.h>
++
++static const char expected[] = "\
++\n\
++a\n\
++abbcd55\
++\n\
++a\n\
++abbcd55\
++\n\
++a\n\
++abbcd55\
++\n\
++a\n\
++abbcd55\
++\n\
++a\n\
++abbcd55\
++\n\
++a\n\
++abbcd55\
++\n\
++a\n\
++abbcd55\
++\n\
++a\n\
++abbcd55\
++\n\
++a\n\
++abbcd55\
++\n\
++a\n\
++abbcd55\
++\n\
++a\n\
++abbcd55\
++\n\
++a\n\
++abbcd55\
++\n\
++a\n\
++abbcd55%%%%%%%%%%%%%%%%%%%%%%%%%%\n";
++
++static int
++do_test (void)
++{
++ char *buf = malloc (strlen (expected) + 1);
++ snprintf (buf, strlen (expected) + 1,
++ "\n%1$s\n" "%1$s" "%2$s" "%2$s" "%3$s" "%4$s" "%5$d" "%5$d"
++ "\n%1$s\n" "%1$s" "%2$s" "%2$s" "%3$s" "%4$s" "%5$d" "%5$d"
++ "\n%1$s\n" "%1$s" "%2$s" "%2$s" "%3$s" "%4$s" "%5$d" "%5$d"
++ "\n%1$s\n" "%1$s" "%2$s" "%2$s" "%3$s" "%4$s" "%5$d" "%5$d"
++ "\n%1$s\n" "%1$s" "%2$s" "%2$s" "%3$s" "%4$s" "%5$d" "%5$d"
++ "\n%1$s\n" "%1$s" "%2$s" "%2$s" "%3$s" "%4$s" "%5$d" "%5$d"
++ "\n%1$s\n" "%1$s" "%2$s" "%2$s" "%3$s" "%4$s" "%5$d" "%5$d"
++ "\n%1$s\n" "%1$s" "%2$s" "%2$s" "%3$s" "%4$s" "%5$d" "%5$d"
++ "\n%1$s\n" "%1$s" "%2$s" "%2$s" "%3$s" "%4$s" "%5$d" "%5$d"
++ "\n%1$s\n" "%1$s" "%2$s" "%2$s" "%3$s" "%4$s" "%5$d" "%5$d"
++ "\n%1$s\n" "%1$s" "%2$s" "%2$s" "%3$s" "%4$s" "%5$d" "%5$d"
++ "\n%1$s\n" "%1$s" "%2$s" "%2$s" "%3$s" "%4$s" "%5$d" "%5$d"
++ "\n%1$s\n" "%1$s" "%2$s" "%2$s" "%3$s" "%4$s" "%5$d" "%5$d"
++ "%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%\n",
++ "a", "b", "c", "d", 5);
++ return strcmp (buf, expected) != 0;
++}
++
++#define TEST_FUNCTION do_test ()
++#include "../test-skeleton.c"
+Index: git/stdio-common/bug23-3.c
+===================================================================
+--- /dev/null
++++ git/stdio-common/bug23-3.c
+@@ -0,0 +1,50 @@
++#include <stdio.h>
++#include <string.h>
++#include <stdlib.h>
++
++int
++do_test (void)
++{
++ size_t instances = 16384;
++#define X0 "\n%1$s\n" "%1$s" "%2$s" "%2$s" "%3$s" "%4$s" "%5$d" "%5$d"
++ const char *item = "\na\nabbcd55";
++#define X3 X0 X0 X0 X0 X0 X0 X0 X0
++#define X6 X3 X3 X3 X3 X3 X3 X3 X3
++#define X9 X6 X6 X6 X6 X6 X6 X6 X6
++#define X12 X9 X9 X9 X9 X9 X9 X9 X9
++#define X14 X12 X12 X12 X12
++#define TRAILER "%%%%%%%%%%%%%%%%%%%%%%%%%%"
++#define TRAILER2 TRAILER TRAILER
++ size_t length = instances * strlen (item) + strlen (TRAILER) + 1;
++
++ char *buf = malloc (length + 1);
++ snprintf (buf, length + 1,
++ X14 TRAILER2 "\n",
++ "a", "b", "c", "d", 5);
++
++ const char *p = buf;
++ size_t i;
++ for (i = 0; i < instances; ++i)
++ {
++ const char *expected;
++ for (expected = item; *expected; ++expected)
++ {
++ if (*p != *expected)
++ {
++ printf ("mismatch at offset %zu (%zu): expected %d, got %d\n",
++ (size_t) (p - buf), i, *expected & 0xFF, *p & 0xFF);
++ return 1;
++ }
++ ++p;
++ }
++ }
++ if (strcmp (p, TRAILER "\n") != 0)
++ {
++ printf ("mismatch at trailer: [%s]\n", p);
++ return 1;
++ }
++ free (buf);
++ return 0;
++}
++#define TEST_FUNCTION do_test ()
++#include "../test-skeleton.c"
+Index: git/stdio-common/bug23-4.c
+===================================================================
+--- /dev/null
++++ git/stdio-common/bug23-4.c
+@@ -0,0 +1,31 @@
++#include <stdio.h>
++#include <stdlib.h>
++#include <string.h>
++#include <sys/resource.h>
++
++#define LIMIT 1000000
++
++int
++main (void)
++{
++ struct rlimit lim;
++ getrlimit (RLIMIT_STACK, &lim);
++ lim.rlim_cur = 1048576;
++ setrlimit (RLIMIT_STACK, &lim);
++ char *fmtstr = malloc (4 * LIMIT + 1);
++ if (fmtstr == NULL)
++ abort ();
++ char *output = malloc (LIMIT + 1);
++ if (output == NULL)
++ abort ();
++ for (size_t i = 0; i < LIMIT; i++)
++ memcpy (fmtstr + 4 * i, "%1$d", 4);
++ fmtstr[4 * LIMIT] = '\0';
++ int ret = snprintf (output, LIMIT + 1, fmtstr, 0);
++ if (ret != LIMIT)
++ abort ();
++ for (size_t i = 0; i < LIMIT; i++)
++ if (output[i] != '0')
++ abort ();
++ return 0;
++}
+Index: git/stdio-common/vfprintf.c
+===================================================================
+--- git.orig/stdio-common/vfprintf.c
++++ git/stdio-common/vfprintf.c
+@@ -276,6 +276,12 @@ vfprintf (FILE *s, const CHAR_T *format,
+ /* For the argument descriptions, which may be allocated on the heap. */
+ void *args_malloced = NULL;
+
++ /* For positional argument handling. */
++ struct printf_spec *specs;
++
++ /* Track if we malloced the SPECS array and thus must free it. */
++ bool specs_malloced = false;
++
+ /* This table maps a character into a number representing a
+ class. In each step there is a destination label for each
+ class. */
+@@ -1699,8 +1705,8 @@ do_positional:
+ size_t nspecs = 0;
+ /* A more or less arbitrary start value. */
+ size_t nspecs_size = 32 * sizeof (struct printf_spec);
+- struct printf_spec *specs = alloca (nspecs_size);
+
++ specs = alloca (nspecs_size);
+ /* The number of arguments the format string requests. This will
+ determine the size of the array needed to store the argument
+ attributes. */
+@@ -1743,11 +1749,39 @@ do_positional:
+ if (nspecs * sizeof (*specs) >= nspecs_size)
+ {
+ /* Extend the array of format specifiers. */
++ if (nspecs_size * 2 < nspecs_size)
++ {
++ __set_errno (ENOMEM);
++ done = -1;
++ goto all_done;
++ }
+ struct printf_spec *old = specs;
+- specs = extend_alloca (specs, nspecs_size, 2 * nspecs_size);
++ if (__libc_use_alloca (2 * nspecs_size))
++ specs = extend_alloca (specs, nspecs_size, 2 * nspecs_size);
++ else
++ {
++ nspecs_size *= 2;
++ specs = malloc (nspecs_size);
++ if (specs == NULL)
++ {
++ __set_errno (ENOMEM);
++ specs = old;
++ done = -1;
++ goto all_done;
++ }
++ }
+
+ /* Copy the old array's elements to the new space. */
+ memmove (specs, old, nspecs * sizeof (*specs));
++
++ /* If we had previously malloc'd space for SPECS, then
++ release it after the copy is complete. */
++ if (specs_malloced)
++ free (old);
++
++ /* Now set SPECS_MALLOCED if needed. */
++ if (!__libc_use_alloca (nspecs_size))
++ specs_malloced = true;
+ }
+
+ /* Parse the format specifier. */
+@@ -2068,6 +2102,8 @@ do_positional:
+ }
+
+ all_done:
++ if (specs_malloced)
++ free (specs);
+ if (__glibc_unlikely (args_malloced != NULL))
+ free (args_malloced);
+ if (__glibc_unlikely (workstart != NULL))
+Index: git/stdio-common/Makefile
+===================================================================
+--- git.orig/stdio-common/Makefile
++++ git/stdio-common/Makefile
+@@ -66,7 +66,7 @@ tests := tstscanf test_rdwr test-popen t
+ tst-fwrite bug16 bug17 tst-sprintf2 bug18 \
+ bug19 tst-popen2 scanf14 scanf15 bug21 bug22 scanf16 scanf17 \
+ tst-setvbuf1 bug23 bug24 bug-vfprintf-nargs tst-sprintf3 bug25 \
+- tst-printf-round bug26
++ tst-printf-round bug23-2 bug23-3 bug23-4
+
+ tests-$(OPTION_EGLIBC_LOCALE_CODE) \
+ += tst-sscanf tst-swprintf test-vfprintf bug14 scanf13 tst-grouping
diff --git a/recipes-core/glibc/glibc/CVE-2014-7817-wordexp-fails-to-honour-WRDE_NOCMD.patch b/recipes-core/glibc/glibc/CVE-2014-7817-wordexp-fails-to-honour-WRDE_NOCMD.patch
new file mode 100644
index 0000000..d95d182
--- /dev/null
+++ b/recipes-core/glibc/glibc/CVE-2014-7817-wordexp-fails-to-honour-WRDE_NOCMD.patch
@@ -0,0 +1,215 @@
+From a39208bd7fb76c1b01c127b4c61f9bfd915bfe7c Mon Sep 17 00:00:00 2001
+From: Carlos O'Donell <carlos at redhat.com>
+Date: Wed, 19 Nov 2014 11:44:12 -0500
+Subject: [PATCH] CVE-2014-7817: wordexp fails to honour WRDE_NOCMD.
+
+The function wordexp() fails to properly handle the WRDE_NOCMD
+flag when processing arithmetic inputs in the form of "$((... ``))"
+where "..." can be anything valid. The backticks in the arithmetic
+epxression are evaluated by in a shell even if WRDE_NOCMD forbade
+command substitution. This allows an attacker to attempt to pass
+dangerous commands via constructs of the above form, and bypass
+the WRDE_NOCMD flag. This patch fixes this by checking for WRDE_NOCMD
+in exec_comm(), the only place that can execute a shell. All other
+checks for WRDE_NOCMD are superfluous and removed.
+
+We expand the testsuite and add 3 new regression tests of roughly
+the same form but with a couple of nested levels.
+
+On top of the 3 new tests we add fork validation to the WRDE_NOCMD
+testing. If any forks are detected during the execution of a wordexp()
+call with WRDE_NOCMD, the test is marked as failed. This is slightly
+heuristic since vfork might be used in the future, but it provides a
+higher level of assurance that no shells were executed as part of
+command substitution with WRDE_NOCMD in effect. In addition it doesn't
+require libpthread or libdl, instead we use the public implementation
+namespace function __register_atfork (already part of the public ABI
+for libpthread).
+
+Tested on x86_64 with no regressions.
+---
+ ChangeLog | 22 ++++++++++++++++++++++
+ NEWS | 8 +++++++-
+ posix/wordexp-test.c | 44 ++++++++++++++++++++++++++++++++++++++++++++
+ posix/wordexp.c | 16 ++++------------
+ 4 files changed, 77 insertions(+), 13 deletions(-)
+
+Index: git/ChangeLog
+===================================================================
+--- git.orig/ChangeLog
++++ git/ChangeLog
+@@ -1,3 +1,24 @@
++2014-11-19 Carlos O'Donell <carlos at redhat.com>
++ Florian Weimer <fweimer at redhat.com>
++ Joseph Myers <joseph at codesourcery.com>
++ Adam Conrad <adconrad at 0c3.net>
++ Andreas Schwab <schwab at suse.de>
++ Brooks <bmoses at google.com>
++
++ [BZ #17625]
++ * wordexp-test.c (__dso_handle): Add prototype.
++ (__register_atfork): Likewise.
++ (__app_register_atfork): New function.
++ (registered_forks): New global.
++ (register_fork): New function.
++ (test_case): Add 3 new tests for WRDE_CMDSUB.
++ (main): Call __app_register_atfork.
++ (testit): If WRDE_NOCMD set registered_forks to zero, run test, and if
++ fork count is non-zero fail the test.
++ * posix/wordexp.c (exec_comm): Return WRDE_CMDSUB if WRDE_NOCMD flag
++ is set.
++ (parse_dollars): Remove check for WRDE_NOCMD.
++
+ 2014-09-07 Allan McRae <allan at archlinux.org
+
+ * version.h (RELEASE): Set to "stable".
+Index: git/NEWS
+===================================================================
+--- git.orig/NEWS
++++ git/NEWS
+@@ -23,7 +23,13 @@ Version 2.20
+ 16966, 16967, 16977, 16978, 16984, 16990, 16996, 17009, 17022, 17031,
+ 17042, 17048, 17050, 17058, 17061, 17062, 17069, 17075, 17078, 17079,
+ 17084, 17086, 17088, 17092, 17097, 17125, 17135, 17137, 17150, 17153,
+- 17187, 17213, 17259, 17261, 17262, 17263, 17319, 17325, 17354.
++ 17187, 17213, 17259, 17261, 17262, 17263, 17319, 17325, 17354, 17625.
++
++* CVE-2104-7817 The wordexp function could ignore the WRDE_NOCMD flag
++ under certain input conditions resulting in the execution of a shell for
++ command substitution when the applicaiton did not request it. The
++ implementation now checks WRDE_NOCMD immediately before executing the
++ shell and returns the error WRDE_CMDSUB as expected.
+
+ * Reverted change of ABI data structures for s390 and s390x:
+ On s390 and s390x the size of struct ucontext and jmp_buf was increased in
+Index: git/posix/wordexp-test.c
+===================================================================
+--- git.orig/posix/wordexp-test.c
++++ git/posix/wordexp-test.c
+@@ -27,6 +27,25 @@
+
+ #define IFS " \n\t"
+
++extern void *__dso_handle __attribute__ ((__weak__, __visibility__ ("hidden")));
++extern int __register_atfork (void (*) (void), void (*) (void), void (*) (void), void *);
++
++static int __app_register_atfork (void (*prepare) (void), void (*parent) (void), void (*child) (void))
++{
++ return __register_atfork (prepare, parent, child,
++ &__dso_handle == NULL ? NULL : __dso_handle);
++}
++
++/* Number of forks seen. */
++static int registered_forks;
++
++/* For each fork increment the fork count. */
++static void
++register_fork (void)
++{
++ registered_forks++;
++}
++
+ struct test_case_struct
+ {
+ int retval;
+@@ -206,6 +225,12 @@ struct test_case_struct
+ { WRDE_SYNTAX, NULL, "$((2+))", 0, 0, { NULL, }, IFS },
+ { WRDE_SYNTAX, NULL, "`", 0, 0, { NULL, }, IFS },
+ { WRDE_SYNTAX, NULL, "$((010+4+))", 0, 0, { NULL }, IFS },
++ /* Test for CVE-2014-7817. We test 3 combinations of command
++ substitution inside an arithmetic expression to make sure that
++ no commands are executed and error is returned. */
++ { WRDE_CMDSUB, NULL, "$((`echo 1`))", WRDE_NOCMD, 0, { NULL, }, IFS },
++ { WRDE_CMDSUB, NULL, "$((1+`echo 1`))", WRDE_NOCMD, 0, { NULL, }, IFS },
++ { WRDE_CMDSUB, NULL, "$((1+$((`echo 1`))))", WRDE_NOCMD, 0, { NULL, }, IFS },
+
+ { -1, NULL, NULL, 0, 0, { NULL, }, IFS },
+ };
+@@ -258,6 +283,15 @@ main (int argc, char *argv[])
+ return -1;
+ }
+
++ /* If we are not allowed to do command substitution, we install
++ fork handlers to verify that no forks happened. No forks should
++ happen at all if command substitution is disabled. */
++ if (__app_register_atfork (register_fork, NULL, NULL) != 0)
++ {
++ printf ("Failed to register fork handler.\n");
++ return -1;
++ }
++
+ for (test = 0; test_case[test].retval != -1; test++)
+ if (testit (&test_case[test]))
+ ++fail;
+@@ -367,6 +401,9 @@ testit (struct test_case_struct *tc)
+
+ printf ("Test %d (%s): ", ++tests, tc->words);
+
++ if (tc->flags & WRDE_NOCMD)
++ registered_forks = 0;
++
+ if (tc->flags & WRDE_APPEND)
+ {
+ /* initial wordexp() call, to be appended to */
+@@ -378,6 +415,13 @@ testit (struct test_case_struct *tc)
+ }
+ retval = wordexp (tc->words, &we, tc->flags);
+
++ if ((tc->flags & WRDE_NOCMD)
++ && (registered_forks > 0))
++ {
++ printf ("FAILED fork called for WRDE_NOCMD\n");
++ return 1;
++ }
++
+ if (tc->flags & WRDE_DOOFFS)
+ start_offs = sav_we.we_offs;
+
+Index: git/posix/wordexp.c
+===================================================================
+--- git.orig/posix/wordexp.c
++++ git/posix/wordexp.c
+@@ -893,6 +893,10 @@ exec_comm (char *comm, char **word, size
+ pid_t pid;
+ int noexec = 0;
+
++ /* Do nothing if command substitution should not succeed. */
++ if (flags & WRDE_NOCMD)
++ return WRDE_CMDSUB;
++
+ /* Don't fork() unless necessary */
+ if (!comm || !*comm)
+ return 0;
+@@ -2082,9 +2086,6 @@ parse_dollars (char **word, size_t *word
+ }
+ }
+
+- if (flags & WRDE_NOCMD)
+- return WRDE_CMDSUB;
+-
+ (*offset) += 2;
+ return parse_comm (word, word_length, max_length, words, offset, flags,
+ quoted? NULL : pwordexp, ifs, ifs_white);
+@@ -2196,9 +2197,6 @@ parse_dquote (char **word, size_t *word_
+ break;
+
+ case '`':
+- if (flags & WRDE_NOCMD)
+- return WRDE_CMDSUB;
+-
+ ++(*offset);
+ error = parse_backtick (word, word_length, max_length, words,
+ offset, flags, NULL, NULL, NULL);
+@@ -2357,12 +2355,6 @@ wordexp (const char *words, wordexp_t *p
+ break;
+
+ case '`':
+- if (flags & WRDE_NOCMD)
+- {
+- error = WRDE_CMDSUB;
+- goto do_error;
+- }
+-
+ ++words_offset;
+ error = parse_backtick (&word, &word_length, &max_length, words,
+ &words_offset, flags, pwordexp, ifs,
diff --git a/recipes-core/glibc/glibc/CVE-2014-9402_endless-loop-in-getaddr_r.patch b/recipes-core/glibc/glibc/CVE-2014-9402_endless-loop-in-getaddr_r.patch
new file mode 100644
index 0000000..ba1da67
--- /dev/null
+++ b/recipes-core/glibc/glibc/CVE-2014-9402_endless-loop-in-getaddr_r.patch
@@ -0,0 +1,65 @@
+CVE-2014-9402 endless loop in getaddr_r
+
+
+https://sourceware.org/git/gitweb.cgi?p=glibc.git;a=commit;h=11e3417af6e354f1942c68a271ae51e892b2814d
+
+Upstream-Status: Backport
+
+Signed-off-by: Armin Kuster <akuster at mvista.com>
+
+From 11e3417af6e354f1942c68a271ae51e892b2814d Mon Sep 17 00:00:00 2001
+From: Florian Weimer <fweimer at redhat.com>
+Date: Mon, 15 Dec 2014 17:41:13 +0100
+Subject: [PATCH] Avoid infinite loop in nss_dns getnetbyname [BZ #17630]
+
+---
+ ChangeLog | 6 ++++++
+ NEWS | 7 +++++--
+ resolv/nss_dns/dns-network.c | 4 ++--
+ 3 files changed, 13 insertions(+), 4 deletions(-)
+
+Index: git/NEWS
+===================================================================
+--- git.orig/NEWS
++++ git/NEWS
+@@ -24,7 +24,10 @@ Version 2.20
+ 17031, 17042, 17048, 17050, 17058, 17061, 17062, 17069, 17075, 17078,
+ 17079, 17084, 17086, 17088, 17092, 17097, 17125, 17135, 17137, 17150,
+ 17153, 17187, 17213, 17259, 17261, 17262, 17263, 17319, 17325, 17354,
+- 17625.
++ 17625, 17630.
++
++* The nss_dns implementation of getnetbyname could run into an infinite loop
++ if the DNS response contained a PTR record of an unexpected format.
+
+ * CVE-2104-7817 The wordexp function could ignore the WRDE_NOCMD flag
+ under certain input conditions resulting in the execution of a shell for
+Index: git/resolv/nss_dns/dns-network.c
+===================================================================
+--- git.orig/resolv/nss_dns/dns-network.c
++++ git/resolv/nss_dns/dns-network.c
+@@ -398,8 +398,8 @@ getanswer_r (const querybuf *answer, int
+
+ case BYNAME:
+ {
+- char **ap = result->n_aliases++;
+- while (*ap != NULL)
++ char **ap;
++ for (ap = result->n_aliases; *ap != NULL; ++ap)
+ {
+ /* Check each alias name for being of the forms:
+ 4.3.2.1.in-addr.arpa = net 1.2.3.4
+Index: git/ChangeLog
+===================================================================
+--- git.orig/ChangeLog
++++ git/ChangeLog
+@@ -1,3 +1,9 @@
++2014-12-16 Florian Weimer <fweimer at redhat.com>
++
++ [BZ #17630]
++ * resolv/nss_dns/dns-network.c (getanswer_r): Iterate over alias
++ names.
++
+ 2014-12-15 Jeff Law <law at redhat.com>
+
+ [BZ #16617]
diff --git a/recipes-core/glibc/glibc/CVE-2015-1781-resolv-nss_dns-dns-host.c-buffer-overf.patch b/recipes-core/glibc/glibc/CVE-2015-1781-resolv-nss_dns-dns-host.c-buffer-overf.patch
new file mode 100644
index 0000000..c02fa12
--- /dev/null
+++ b/recipes-core/glibc/glibc/CVE-2015-1781-resolv-nss_dns-dns-host.c-buffer-overf.patch
@@ -0,0 +1,43 @@
+From 2959eda9272a033863c271aff62095abd01bd4e3 Mon Sep 17 00:00:00 2001
+From: Arjun Shankar <arjun.is at lostca.se>
+Date: Tue, 21 Apr 2015 14:06:31 +0200
+Subject: [PATCH] CVE-2015-1781: resolv/nss_dns/dns-host.c buffer overflow
+ [BZ#18287]
+
+Upstream-Status: Backport
+https://sourceware.org/bugzilla/show_bug.cgi?id=18287
+---
+ resolv/nss_dns/dns-host.c | 3 ++-
+ 1 file changed, 2 insertions(+), 1 deletion(-)
+
+diff --git a/resolv/nss_dns/dns-host.c b/resolv/nss_dns/dns-host.c
+index b16b0ddf110907a0086b86612e544d3dc75182b8..d8c55791591750567f00e616e5d7b378dec934a0 100644
+--- a/resolv/nss_dns/dns-host.c
++++ b/resolv/nss_dns/dns-host.c
+@@ -608,21 +608,22 @@ getanswer_r (const querybuf *answer, int anslen, const char *qname, int qtype,
+ int n, ancount, qdcount;
+ int haveanswer, had_error;
+ char *bp, **ap, **hap;
+ char tbuf[MAXDNAME];
+ const char *tname;
+ int (*name_ok) (const char *);
+ u_char packtmp[NS_MAXCDNAME];
+ int have_to_map = 0;
+ uintptr_t pad = -(uintptr_t) buffer % __alignof__ (struct host_data);
+ buffer += pad;
+- if (__glibc_unlikely (buflen < sizeof (struct host_data) + pad))
++ buflen = buflen > pad ? buflen - pad : 0;
++ if (__glibc_unlikely (buflen < sizeof (struct host_data)))
+ {
+ /* The buffer is too small. */
+ too_small:
+ *errnop = ERANGE;
+ *h_errnop = NETDB_INTERNAL;
+ return NSS_STATUS_TRYAGAIN;
+ }
+ host_data = (struct host_data *) buffer;
+ linebuflen = buflen - sizeof (struct host_data);
+ if (buflen - sizeof (struct host_data) != linebuflen)
+--
+2.2.2
+
diff --git a/recipes-core/glibc/glibc/GLRO_dl_debug_mask.patch b/recipes-core/glibc/glibc/GLRO_dl_debug_mask.patch
new file mode 100644
index 0000000..e858bfa
--- /dev/null
+++ b/recipes-core/glibc/glibc/GLRO_dl_debug_mask.patch
@@ -0,0 +1,529 @@
+Its controlled by __OPTION_EGLIBC_RTLD_DEBUG
+so we should use GLRO_dl_debug_mask
+
+Singed-off-by: Khem Raj <raj.khem at gmail.com>
+
+Upstream-Status: Pending
+Index: git/elf/dl-open.c
+===================================================================
+--- git.orig/elf/dl-open.c 2014-08-27 05:03:59.732070587 +0000
++++ git/elf/dl-open.c 2014-08-27 05:05:25.656070587 +0000
+@@ -147,7 +147,7 @@
+ ns->_ns_main_searchlist->r_list[new_nlist++] = map;
+
+ /* We modify the global scope. Report this. */
+- if (__glibc_unlikely (GLRO(dl_debug_mask) & DL_DEBUG_SCOPES))
++ if (__glibc_unlikely (GLRO_dl_debug_mask & DL_DEBUG_SCOPES))
+ _dl_debug_printf ("\nadd %s [%lu] to global scope\n",
+ map->l_name, map->l_ns);
+ }
+@@ -243,7 +243,7 @@
+ if (__glibc_unlikely (new->l_searchlist.r_list != NULL))
+ {
+ /* Let the user know about the opencount. */
+- if (__glibc_unlikely (GLRO(dl_debug_mask) & DL_DEBUG_FILES))
++ if (__glibc_unlikely (GLRO_dl_debug_mask & DL_DEBUG_FILES))
+ _dl_debug_printf ("opening file=%s [%lu]; direct_opencount=%u\n\n",
+ new->l_name, new->l_ns, new->l_direct_opencount);
+
+@@ -294,7 +294,7 @@
+ LIBC_PROBE (map_complete, 3, args->nsid, r, new);
+
+ /* Print scope information. */
+- if (__glibc_unlikely (GLRO(dl_debug_mask) & DL_DEBUG_SCOPES))
++ if (__glibc_unlikely (GLRO_dl_debug_mask & DL_DEBUG_SCOPES))
+ _dl_show_scope (new, 0);
+
+ /* Only do lazy relocation if `LD_BIND_NOW' is not set. */
+@@ -511,7 +511,7 @@
+ }
+
+ /* Print scope information. */
+- if (__glibc_unlikely (GLRO(dl_debug_mask) & DL_DEBUG_SCOPES))
++ if (__glibc_unlikely (GLRO_dl_debug_mask & DL_DEBUG_SCOPES))
+ _dl_show_scope (imap, from_scope);
+ }
+
+@@ -584,7 +584,7 @@
+ #endif
+
+ /* Let the user know about the opencount. */
+- if (__glibc_unlikely (GLRO(dl_debug_mask) & DL_DEBUG_FILES))
++ if (__glibc_unlikely (GLRO_dl_debug_mask & DL_DEBUG_FILES))
+ _dl_debug_printf ("opening file=%s [%lu]; direct_opencount=%u\n\n",
+ new->l_name, new->l_ns, new->l_direct_opencount);
+ }
+Index: git/elf/rtld.c
+===================================================================
+--- git.orig/elf/rtld.c 2014-08-27 05:03:59.732070587 +0000
++++ git/elf/rtld.c 2014-08-27 05:12:33.812070587 +0000
+@@ -321,7 +321,7 @@
+ }
+ #endif
+
+- if (__glibc_unlikely (GLRO(dl_debug_mask) & DL_DEBUG_STATISTICS))
++ if (__glibc_unlikely (GLRO_dl_debug_mask & DL_DEBUG_STATISTICS))
+ {
+ #ifndef HP_TIMING_NONAVAIL
+ print_statistics (&rtld_total_time);
+@@ -1699,7 +1699,7 @@
+ after relocation. */
+ struct link_map *l;
+
+- if (GLRO(dl_debug_mask) & DL_DEBUG_PRELINK)
++ if (GLRO_dl_debug_mask & DL_DEBUG_PRELINK)
+ {
+ struct r_scope_elem *scope = &main_map->l_searchlist;
+
+@@ -1729,7 +1729,7 @@
+ _dl_printf ("\n");
+ }
+ }
+- else if (GLRO(dl_debug_mask) & DL_DEBUG_UNUSED)
++ else if (GLRO_dl_debug_mask & DL_DEBUG_UNUSED)
+ {
+ /* Look through the dependencies of the main executable
+ and determine which of them is not actually
+@@ -1837,7 +1837,7 @@
+ }
+ }
+
+- if ((GLRO(dl_debug_mask) & DL_DEBUG_PRELINK)
++ if ((GLRO_dl_debug_mask & DL_DEBUG_PRELINK)
+ && rtld_multiple_ref)
+ {
+ /* Mark the link map as not yet relocated again. */
+@@ -1970,7 +1970,7 @@
+ if (r_list == r_listend && liblist == liblistend)
+ prelinked = true;
+
+- if (__glibc_unlikely (GLRO(dl_debug_mask) & DL_DEBUG_LIBS))
++ if (__glibc_unlikely (GLRO_dl_debug_mask & DL_DEBUG_LIBS))
+ _dl_debug_printf ("\nprelink checking: %s\n",
+ prelinked ? "ok" : "failed");
+ }
+@@ -1988,7 +1988,7 @@
+ GLRO(dl_init_all_dirs) = GL(dl_all_dirs);
+
+ /* Print scope information. */
+- if (__glibc_unlikely (GLRO(dl_debug_mask) & DL_DEBUG_SCOPES))
++ if (__glibc_unlikely (GLRO_dl_debug_mask & DL_DEBUG_SCOPES))
+ {
+ _dl_debug_printf ("\nInitial object scopes\n");
+
+@@ -2262,7 +2262,7 @@
+ if (debopts[cnt].len == len
+ && memcmp (dl_debug, debopts[cnt].name, len) == 0)
+ {
+- GLRO(dl_debug_mask) |= debopts[cnt].mask;
++ GLRO_dl_debug_mask |= debopts[cnt].mask;
+ any_debug = 1;
+ break;
+ }
+@@ -2283,7 +2283,7 @@
+ ++dl_debug;
+ }
+
+- if (GLRO(dl_debug_mask) & DL_DEBUG_UNUSED)
++ if (GLRO_dl_debug_mask & DL_DEBUG_UNUSED)
+ {
+ /* In order to get an accurate picture of whether a particular
+ DT_NEEDED entry is actually used we have to process both
+@@ -2291,7 +2291,7 @@
+ GLRO(dl_lazy) = 0;
+ }
+
+- if (GLRO(dl_debug_mask) & DL_DEBUG_HELP)
++ if (GLRO_dl_debug_mask & DL_DEBUG_HELP)
+ {
+ size_t cnt;
+
+@@ -2490,7 +2490,7 @@
+ {
+ mode = trace;
+ GLRO(dl_verbose) = 1;
+- GLRO(dl_debug_mask) |= DL_DEBUG_PRELINK;
++ GLRO_dl_debug_mask |= DL_DEBUG_PRELINK;
+ GLRO(dl_trace_prelink) = &envline[17];
+ }
+ break;
+@@ -2537,7 +2537,7 @@
+ if (__access ("/etc/suid-debug", F_OK) != 0)
+ {
+ unsetenv ("MALLOC_CHECK_");
+- GLRO(dl_debug_mask) = 0;
++ GLRO_dl_debug_mask = 0;
+ }
+
+ if (mode != normal)
+Index: git/elf/dl-lookup.c
+===================================================================
+--- git.orig/elf/dl-lookup.c 2014-08-27 05:03:59.732070587 +0000
++++ git/elf/dl-lookup.c 2014-08-27 05:13:07.644070587 +0000
+@@ -300,7 +300,7 @@
+ hash table. */
+ if (__glibc_unlikely (tab->size))
+ {
+- assert (GLRO(dl_debug_mask) & DL_DEBUG_PRELINK);
++ assert (GLRO_dl_debug_mask & DL_DEBUG_PRELINK);
+ goto success;
+ }
+ #endif
+@@ -375,7 +375,7 @@
+ continue;
+
+ /* Print some debugging info if wanted. */
+- if (__glibc_unlikely (GLRO(dl_debug_mask) & DL_DEBUG_SYMBOLS))
++ if (__glibc_unlikely (GLRO_dl_debug_mask & DL_DEBUG_SYMBOLS))
+ _dl_debug_printf ("symbol=%s; lookup in file=%s [%lu]\n",
+ undef_name, DSO_FILENAME (map->l_name),
+ map->l_ns);
+@@ -698,7 +698,7 @@
+ }
+
+ /* Display information if we are debugging. */
+- if (__glibc_unlikely (GLRO(dl_debug_mask) & DL_DEBUG_FILES))
++ if (__glibc_unlikely (GLRO_dl_debug_mask & DL_DEBUG_FILES))
+ _dl_debug_printf ("\
+ \nfile=%s [%lu]; needed by %s [%lu] (relocation dependency)\n\n",
+ DSO_FILENAME (map->l_name),
+@@ -802,7 +802,7 @@
+ {
+ if ((*ref == NULL || ELFW(ST_BIND) ((*ref)->st_info) != STB_WEAK)
+ && skip_map == NULL
+- && !(GLRO(dl_debug_mask) & DL_DEBUG_UNUSED))
++ && !(GLRO_dl_debug_mask & DL_DEBUG_UNUSED))
+ {
+ /* We could find no value for a strong reference. */
+ const char *reference_name = undef_map ? undef_map->l_name : "";
+@@ -873,7 +873,7 @@
+ if (__glibc_unlikely (current_value.m->l_used == 0))
+ current_value.m->l_used = 1;
+
+- if (__glibc_unlikely (GLRO(dl_debug_mask)
++ if (__glibc_unlikely (GLRO_dl_debug_mask
+ & (DL_DEBUG_BINDINGS|DL_DEBUG_PRELINK)))
+ _dl_debug_bindings (undef_name, undef_map, ref,
+ ¤t_value, version, type_class, protected);
+@@ -938,7 +938,7 @@
+ {
+ const char *reference_name = undef_map->l_name;
+
+- if (GLRO(dl_debug_mask) & DL_DEBUG_BINDINGS)
++ if (GLRO_dl_debug_mask & DL_DEBUG_BINDINGS)
+ {
+ _dl_debug_printf ("binding file %s [%lu] to %s [%lu]: %s symbol `%s'",
+ DSO_FILENAME (reference_name),
+@@ -952,7 +952,7 @@
+ _dl_debug_printf_c ("\n");
+ }
+ #ifdef SHARED
+- if (GLRO(dl_debug_mask) & DL_DEBUG_PRELINK)
++ if (GLRO_dl_debug_mask & DL_DEBUG_PRELINK)
+ {
+ int conflict = 0;
+ struct sym_val val = { NULL, NULL };
+Index: git/elf/get-dynamic-info.h
+===================================================================
+--- git.orig/elf/get-dynamic-info.h 2014-08-27 05:03:59.732070587 +0000
++++ git/elf/get-dynamic-info.h 2014-08-27 05:03:59.728070587 +0000
+@@ -157,7 +157,7 @@
+ them. Therefore to avoid breaking existing applications the
+ best we can do is add a warning during debugging with the
+ intent of notifying the user of the problem. */
+- if (__builtin_expect (GLRO(dl_debug_mask) & DL_DEBUG_FILES, 0)
++ if (__builtin_expect (GLRO_dl_debug_mask & DL_DEBUG_FILES, 0)
+ && l->l_flags_1 & ~DT_1_SUPPORTED_MASK)
+ _dl_debug_printf ("\nWARNING: Unsupported flag value(s) of 0x%x in DT_FLAGS_1.\n",
+ l->l_flags_1 & ~DT_1_SUPPORTED_MASK);
+Index: git/csu/libc-start.c
+===================================================================
+--- git.orig/csu/libc-start.c 2014-08-27 04:59:01.412070587 +0000
++++ git/csu/libc-start.c 2014-08-27 05:09:28.936070587 +0000
+@@ -238,7 +238,7 @@
+
+ /* Call the initializer of the program, if any. */
+ #ifdef SHARED
+- if (__builtin_expect (GLRO(dl_debug_mask) & DL_DEBUG_IMPCALLS, 0))
++ if (__builtin_expect (GLRO_dl_debug_mask & DL_DEBUG_IMPCALLS, 0))
+ GLRO(dl_debug_printf) ("\ninitialize program: %s\n\n", argv[0]);
+ #endif
+ if (init)
+@@ -261,7 +261,7 @@
+ #endif
+
+ #ifdef SHARED
+- if (__glibc_unlikely (GLRO(dl_debug_mask) & DL_DEBUG_IMPCALLS))
++ if (__glibc_unlikely (GLRO_dl_debug_mask & DL_DEBUG_IMPCALLS))
+ GLRO(dl_debug_printf) ("\ntransferring control: %s\n\n", argv[0]);
+ #endif
+
+Index: git/elf/dl-cache.c
+===================================================================
+--- git.orig/elf/dl-cache.c 2014-08-27 04:59:01.568070587 +0000
++++ git/elf/dl-cache.c 2014-08-27 05:10:14.384070587 +0000
+@@ -187,7 +187,7 @@
+ const char *best;
+
+ /* Print a message if the loading of libs is traced. */
+- if (__glibc_unlikely (GLRO(dl_debug_mask) & DL_DEBUG_LIBS))
++ if (__glibc_unlikely (GLRO_dl_debug_mask & DL_DEBUG_LIBS))
+ _dl_debug_printf (" search cache=%s\n", LD_SO_CACHE);
+
+ if (cache == NULL)
+@@ -285,7 +285,7 @@
+ }
+
+ /* Print our result if wanted. */
+- if (__builtin_expect (GLRO(dl_debug_mask) & DL_DEBUG_LIBS, 0)
++ if (__builtin_expect (GLRO_dl_debug_mask & DL_DEBUG_LIBS, 0)
+ && best != NULL)
+ _dl_debug_printf (" trying file=%s\n", best);
+
+Index: git/elf/dl-close.c
+===================================================================
+--- git.orig/elf/dl-close.c 2014-08-27 04:59:01.568070587 +0000
++++ git/elf/dl-close.c 2014-08-27 05:10:26.456070587 +0000
+@@ -125,7 +125,7 @@
+ dl_close_state = rerun;
+
+ /* There are still references to this object. Do nothing more. */
+- if (__glibc_unlikely (GLRO(dl_debug_mask) & DL_DEBUG_FILES))
++ if (__glibc_unlikely (GLRO_dl_debug_mask & DL_DEBUG_FILES))
+ _dl_debug_printf ("\nclosing file=%s; direct_opencount=%u\n",
+ map->l_name, map->l_direct_opencount);
+
+@@ -257,7 +257,7 @@
+ if (imap->l_init_called)
+ {
+ /* When debugging print a message first. */
+- if (__builtin_expect (GLRO(dl_debug_mask) & DL_DEBUG_IMPCALLS,
++ if (__builtin_expect (GLRO_dl_debug_mask & DL_DEBUG_IMPCALLS,
+ 0))
+ _dl_debug_printf ("\ncalling fini: %s [%lu]\n\n",
+ imap->l_name, nsid);
+@@ -664,7 +664,7 @@
+ free (imap->l_reldeps);
+
+ /* Print debugging message. */
+- if (__glibc_unlikely (GLRO(dl_debug_mask) & DL_DEBUG_FILES))
++ if (__glibc_unlikely (GLRO_dl_debug_mask & DL_DEBUG_FILES))
+ _dl_debug_printf ("\nfile=%s [%lu]; destroying link map\n",
+ imap->l_name, imap->l_ns);
+
+Index: git/elf/dl-conflict.c
+===================================================================
+--- git.orig/elf/dl-conflict.c 2014-08-27 04:59:01.568070587 +0000
++++ git/elf/dl-conflict.c 2014-08-27 05:10:37.652070587 +0000
+@@ -32,7 +32,7 @@
+ ElfW(Rela) *conflictend)
+ {
+ #if ! ELF_MACHINE_NO_RELA
+- if (__glibc_unlikely (GLRO(dl_debug_mask) & DL_DEBUG_RELOC))
++ if (__glibc_unlikely (GLRO_dl_debug_mask & DL_DEBUG_RELOC))
+ _dl_debug_printf ("\nconflict processing: %s\n", DSO_FILENAME (l->l_name));
+
+ {
+Index: git/elf/dl-deps.c
+===================================================================
+--- git.orig/elf/dl-deps.c 2014-08-27 04:59:01.568070587 +0000
++++ git/elf/dl-deps.c 2014-08-27 05:10:48.260070587 +0000
+@@ -127,7 +127,7 @@
+ else \
+ { \
+ /* This is for DT_AUXILIARY. */ \
+- if (__glibc_unlikely (GLRO(dl_debug_mask) & DL_DEBUG_LIBS)) \
++ if (__glibc_unlikely (GLRO_dl_debug_mask & DL_DEBUG_LIBS)) \
+ _dl_debug_printf (N_("\
+ cannot load auxiliary `%s' because of empty dynamic string token " \
+ "substitution\n"), __str); \
+@@ -303,7 +303,7 @@
+ args.name = name;
+
+ /* Say that we are about to load an auxiliary library. */
+- if (__builtin_expect (GLRO(dl_debug_mask) & DL_DEBUG_LIBS,
++ if (__builtin_expect (GLRO_dl_debug_mask & DL_DEBUG_LIBS,
+ 0))
+ _dl_debug_printf ("load auxiliary object=%s"
+ " requested by file=%s\n",
+@@ -520,7 +520,7 @@
+ runp->map->l_reserved = 0;
+ }
+
+- if (__builtin_expect (GLRO(dl_debug_mask) & DL_DEBUG_PRELINK, 0) != 0
++ if (__builtin_expect (GLRO_dl_debug_mask & DL_DEBUG_PRELINK, 0) != 0
+ && map == GL(dl_ns)[LM_ID_BASE]._ns_loaded)
+ {
+ /* If we are to compute conflicts, we have to build local scope
+Index: git/elf/dl-error.c
+===================================================================
+--- git.orig/elf/dl-error.c 2014-08-27 04:59:01.568070587 +0000
++++ git/elf/dl-error.c 2014-08-27 05:11:06.752070587 +0000
+@@ -139,7 +139,7 @@
+ _dl_signal_cerror (int errcode, const char *objname, const char *occation,
+ const char *errstring)
+ {
+- if (__builtin_expect (GLRO(dl_debug_mask)
++ if (__builtin_expect (GLRO_dl_debug_mask
+ & ~(DL_DEBUG_STATISTICS|DL_DEBUG_PRELINK), 0))
+ _dl_debug_printf ("%s: error: %s: %s (%s)\n", objname, occation,
+ errstring, receiver ? "continued" : "fatal");
+Index: git/elf/dl-fini.c
+===================================================================
+--- git.orig/elf/dl-fini.c 2014-08-27 04:59:01.568070587 +0000
++++ git/elf/dl-fini.c 2014-08-27 05:11:17.544070587 +0000
+@@ -234,7 +234,7 @@
+ || l->l_info[DT_FINI] != NULL)
+ {
+ /* When debugging print a message first. */
+- if (__builtin_expect (GLRO(dl_debug_mask)
++ if (__builtin_expect (GLRO_dl_debug_mask
+ & DL_DEBUG_IMPCALLS, 0))
+ _dl_debug_printf ("\ncalling fini: %s [%lu]\n\n",
+ DSO_FILENAME (l->l_name),
+@@ -286,7 +286,7 @@
+ goto again;
+ }
+
+- if (__glibc_unlikely (GLRO(dl_debug_mask) & DL_DEBUG_STATISTICS))
++ if (__glibc_unlikely (GLRO_dl_debug_mask & DL_DEBUG_STATISTICS))
+ _dl_debug_printf ("\nruntime linker statistics:\n"
+ " final number of relocations: %lu\n"
+ "final number of relocations from cache: %lu\n",
+Index: git/elf/dl-init.c
+===================================================================
+--- git.orig/elf/dl-init.c 2014-08-27 04:59:01.568070587 +0000
++++ git/elf/dl-init.c 2014-08-27 05:11:28.372070587 +0000
+@@ -52,7 +52,7 @@
+ return;
+
+ /* Print a debug message if wanted. */
+- if (__glibc_unlikely (GLRO(dl_debug_mask) & DL_DEBUG_IMPCALLS))
++ if (__glibc_unlikely (GLRO_dl_debug_mask & DL_DEBUG_IMPCALLS))
+ _dl_debug_printf ("\ncalling init: %s\n\n",
+ DSO_FILENAME (l->l_name));
+
+@@ -102,7 +102,7 @@
+ ElfW(Addr) *addrs;
+ unsigned int cnt;
+
+- if (__glibc_unlikely (GLRO(dl_debug_mask) & DL_DEBUG_IMPCALLS))
++ if (__glibc_unlikely (GLRO_dl_debug_mask & DL_DEBUG_IMPCALLS))
+ _dl_debug_printf ("\ncalling preinit: %s\n\n",
+ DSO_FILENAME (main_map->l_name));
+
+Index: git/elf/dl-load.c
+===================================================================
+--- git.orig/elf/dl-load.c 2014-08-27 04:59:01.572070587 +0000
++++ git/elf/dl-load.c 2014-08-27 05:11:41.156070587 +0000
+@@ -957,7 +957,7 @@
+ }
+
+ /* Print debugging message. */
+- if (__glibc_unlikely (GLRO(dl_debug_mask) & DL_DEBUG_FILES))
++ if (__glibc_unlikely (GLRO_dl_debug_mask & DL_DEBUG_FILES))
+ _dl_debug_printf ("file=%s [%lu]; generating link map\n", name, nsid);
+
+ /* This is the ELF header. We read it in `open_verify'. */
+@@ -1361,7 +1361,7 @@
+
+ l->l_entry += l->l_addr;
+
+- if (__glibc_unlikely (GLRO(dl_debug_mask) & DL_DEBUG_FILES))
++ if (__glibc_unlikely (GLRO_dl_debug_mask & DL_DEBUG_FILES))
+ _dl_debug_printf ("\
+ dynamic: 0x%0*lx base: 0x%0*lx size: 0x%0*Zx\n\
+ entry: 0x%0*lx phdr: 0x%0*lx phnum: %*u\n\n",
+@@ -1787,7 +1787,7 @@
+
+ /* If we are debugging the search for libraries print the path
+ now if it hasn't happened now. */
+- if (__glibc_unlikely (GLRO(dl_debug_mask) & DL_DEBUG_LIBS)
++ if (__glibc_unlikely (GLRO_dl_debug_mask & DL_DEBUG_LIBS)
+ && current_what != this_dir->what)
+ {
+ current_what = this_dir->what;
+@@ -1808,7 +1808,7 @@
+ - buf);
+
+ /* Print name we try if this is wanted. */
+- if (__glibc_unlikely (GLRO(dl_debug_mask) & DL_DEBUG_LIBS))
++ if (__glibc_unlikely (GLRO_dl_debug_mask & DL_DEBUG_LIBS))
+ _dl_debug_printf (" trying file=%s\n", buf);
+
+ fd = open_verify (buf, fbp, loader, whatcode, mode,
+@@ -1953,7 +1953,7 @@
+ }
+
+ /* Display information if we are debugging. */
+- if (__glibc_unlikely (GLRO(dl_debug_mask) & DL_DEBUG_FILES)
++ if (__glibc_unlikely (GLRO_dl_debug_mask & DL_DEBUG_FILES)
+ && loader != NULL)
+ _dl_debug_printf ((mode & __RTLD_CALLMAP) == 0
+ ? "\nfile=%s [%lu]; needed by %s [%lu]\n"
+@@ -1995,7 +1995,7 @@
+
+ size_t namelen = strlen (name) + 1;
+
+- if (__glibc_unlikely (GLRO(dl_debug_mask) & DL_DEBUG_LIBS))
++ if (__glibc_unlikely (GLRO_dl_debug_mask & DL_DEBUG_LIBS))
+ _dl_debug_printf ("find library=%s [%lu]; searching\n", name, nsid);
+
+ fd = -1;
+@@ -2122,7 +2122,7 @@
+ &realname, &fb, l, LA_SER_DEFAULT, &found_other_class);
+
+ /* Add another newline when we are tracing the library loading. */
+- if (__glibc_unlikely (GLRO(dl_debug_mask) & DL_DEBUG_LIBS))
++ if (__glibc_unlikely (GLRO_dl_debug_mask & DL_DEBUG_LIBS))
+ _dl_debug_printf ("\n");
+ }
+ else
+@@ -2155,7 +2155,7 @@
+ if (__glibc_unlikely (fd == -1))
+ {
+ if (trace_mode
+- && __glibc_likely ((GLRO(dl_debug_mask) & DL_DEBUG_PRELINK) == 0))
++ && __glibc_likely ((GLRO_dl_debug_mask & DL_DEBUG_PRELINK) == 0))
+ {
+ /* We haven't found an appropriate library. But since we
+ are only interested in the list of libraries this isn't
+Index: git/elf/dl-object.c
+===================================================================
+--- git.orig/elf/dl-object.c 2014-08-27 04:59:01.572070587 +0000
++++ git/elf/dl-object.c 2014-08-27 05:11:51.756070587 +0000
+@@ -98,7 +98,7 @@
+ new->l_type = type;
+ /* If we set the bit now since we know it is never used we avoid
+ dirtying the cache line later. */
+- if ((GLRO(dl_debug_mask) & DL_DEBUG_UNUSED) == 0)
++ if ((GLRO_dl_debug_mask & DL_DEBUG_UNUSED) == 0)
+ new->l_used = 1;
+ new->l_loader = loader;
+ #if NO_TLS_OFFSET != 0
+Index: git/elf/dl-reloc.c
+===================================================================
+--- git.orig/elf/dl-reloc.c 2014-08-27 04:59:01.572070587 +0000
++++ git/elf/dl-reloc.c 2014-08-27 05:12:07.056070587 +0000
+@@ -183,7 +183,7 @@
+ && __builtin_expect (l->l_info[DT_BIND_NOW] != NULL, 0))
+ lazy = 0;
+
+- if (__glibc_unlikely (GLRO(dl_debug_mask) & DL_DEBUG_RELOC))
++ if (__glibc_unlikely (GLRO_dl_debug_mask & DL_DEBUG_RELOC))
+ _dl_debug_printf ("\nrelocation processing: %s%s\n",
+ DSO_FILENAME (l->l_name), lazy ? " (lazy)" : "");
+
+Index: git/elf/dl-version.c
+===================================================================
+--- git.orig/elf/dl-version.c 2014-08-27 04:59:01.608070587 +0000
++++ git/elf/dl-version.c 2014-08-27 05:12:19.568070587 +0000
+@@ -82,7 +82,7 @@
+ int result = 0;
+
+ /* Display information about what we are doing while debugging. */
+- if (__glibc_unlikely (GLRO(dl_debug_mask) & DL_DEBUG_VERSIONS))
++ if (__glibc_unlikely (GLRO_dl_debug_mask & DL_DEBUG_VERSIONS))
+ _dl_debug_printf ("\
+ checking for version `%s' in file %s [%lu] required by file %s [%lu]\n",
+ string, DSO_FILENAME (map->l_name),
diff --git a/recipes-core/glibc/glibc/IO-acquire-lock-fix.patch b/recipes-core/glibc/glibc/IO-acquire-lock-fix.patch
new file mode 100644
index 0000000..ffbaba1
--- /dev/null
+++ b/recipes-core/glibc/glibc/IO-acquire-lock-fix.patch
@@ -0,0 +1,17 @@
+import http://sourceware.org/ml/libc-ports/2007-12/msg00000.html
+
+Upstream-Status: Pending
+
+Index: git/bits/stdio-lock.h
+===================================================================
+--- git.orig/bits/stdio-lock.h 2014-08-29 10:33:57.960070587 -0700
++++ git/bits/stdio-lock.h 2014-08-29 10:33:57.952070587 -0700
+@@ -49,6 +49,8 @@
+ _IO_cleanup_region_start ((void (*) (void *)) _IO_funlockfile, (_fp)); \
+ _IO_flockfile (_fp)
+
++# define _IO_acquire_lock_clear_flags2(_fp) _IO_acquire_lock (_fp)
++
+ # define _IO_release_lock(_fp) \
+ _IO_funlockfile (_fp); \
+ _IO_cleanup_region_end (0)
diff --git a/recipes-core/glibc/glibc/add_resource_h_to_wait_h.patch b/recipes-core/glibc/glibc/add_resource_h_to_wait_h.patch
new file mode 100644
index 0000000..4559de7
--- /dev/null
+++ b/recipes-core/glibc/glibc/add_resource_h_to_wait_h.patch
@@ -0,0 +1,20 @@
+The older versions of perf still require sys/resource.h to be
+present in this header, the newer version of perf in 3.2 and
+beyond directly include sys/resource.h
+
+Upstream-Status: Inapproriate [older kernel/perf specific]
+
+Signed-off-by: Saul Wold <sgw at linux.intel.com>
+
+Index: git/posix/sys/wait.h
+===================================================================
+--- git.orig/posix/sys/wait.h 2014-08-29 10:35:10.432070587 -0700
++++ git/posix/sys/wait.h 2014-08-29 10:35:10.424070587 -0700
+@@ -27,6 +27,7 @@
+ __BEGIN_DECLS
+
+ #include <signal.h>
++#include <sys/resource.h>
+
+ /* These macros could also be defined in <stdlib.h>. */
+ #if !defined _STDLIB_H || (!defined __USE_XOPEN && !defined __USE_XOPEN2K8)
diff --git a/recipes-core/glibc/glibc/eglibc-header-bootstrap.patch b/recipes-core/glibc/glibc/eglibc-header-bootstrap.patch
new file mode 100644
index 0000000..e1aa139
--- /dev/null
+++ b/recipes-core/glibc/glibc/eglibc-header-bootstrap.patch
@@ -0,0 +1,85 @@
+Taken from EGLIBC, r1484 + r1525
+
+ 2007-02-20 Jim Blandy <jimb at codesourcery.com>
+
+ * Makefile (install-headers): Preserve old behavior: depend on
+ $(inst_includedir)/gnu/stubs.h only if install-bootstrap-headers
+ is set; otherwise, place gnu/stubs.h on the 'install-others' list.
+
+ 2007-02-16 Jim Blandy <jimb at codesourcery.com>
+
+ * Makefile: Amend make install-headers to install everything
+ necessary for building a cross-compiler. Install gnu/stubs.h as
+ part of 'install-headers', not 'install-others'.
+ If install-bootstrap-headers is 'yes', install a dummy copy of
+ gnu/stubs.h, instead of computing the real thing.
+ * include/stubs-bootstrap.h: New file.
+
+Upstream-Status: Pending
+
+Index: git/Makefile
+===================================================================
+--- git.orig/Makefile 2014-08-27 18:35:18.908070587 +0000
++++ git/Makefile 2014-08-27 18:35:19.340070587 +0000
+@@ -69,9 +69,18 @@
+ vpath %.h $(subdir-dirs)
+
+ # What to install.
+-install-others = $(inst_includedir)/gnu/stubs.h
+ install-bin-script =
+
++# If we're bootstrapping, install a dummy gnu/stubs.h along with the
++# other headers, so 'make install-headers' produces a useable include
++# tree. Otherwise, install gnu/stubs.h later, after the rest of the
++# build is done.
++ifeq ($(install-bootstrap-headers),yes)
++install-headers: $(inst_includedir)/gnu/stubs.h
++else
++install-others = $(inst_includedir)/gnu/stubs.h
++endif
++
+ ifeq (yes,$(build-shared))
+ headers += gnu/lib-names.h
+ endif
+@@ -151,6 +160,16 @@
+
+ subdir-stubs := $(foreach dir,$(subdirs),$(common-objpfx)$(dir)/stubs)
+
++# gnu/stubs.h depends (via the subdir 'stubs' targets) on all the .o
++# files in EGLIBC. For bootstrapping a GCC/EGLIBC pair, an empty
++# gnu/stubs.h is good enough.
++ifeq ($(install-bootstrap-headers),yes)
++$(inst_includedir)/gnu/stubs.h: include/stubs-bootstrap.h $(+force)
++ $(make-target-directory)
++ $(INSTALL_DATA) $< $@
++
++installed-stubs =
++else
+ ifndef abi-variants
+ installed-stubs = $(inst_includedir)/gnu/stubs.h
+ else
+@@ -177,6 +196,7 @@
+
+ install-others-nosubdir: $(installed-stubs)
+ endif
++endif
+
+
+ # Since stubs.h is never needed when building the library, we simplify the
+Index: git/include/stubs-bootstrap.h
+===================================================================
+--- /dev/null 1970-01-01 00:00:00.000000000 +0000
++++ git/include/stubs-bootstrap.h 2014-08-27 18:35:19.340070587 +0000
+@@ -0,0 +1,12 @@
++/* Placeholder stubs.h file for bootstrapping.
++
++ When bootstrapping a GCC/EGLIBC pair, GCC requires that the EGLIBC
++ headers be installed, but we can't fully build EGLIBC without that
++ GCC. So we run the command:
++
++ make install-headers install-bootstrap-headers=yes
++
++ to install the headers GCC needs, but avoid building certain
++ difficult headers. The <gnu/stubs.h> header depends, via the
++ EGLIBC subdir 'stubs' make targets, on every .o file in EGLIBC, but
++ an empty stubs.h like this will do fine for GCC. */
diff --git a/recipes-core/glibc/glibc/eglibc-install-pic-archives.patch b/recipes-core/glibc/glibc/eglibc-install-pic-archives.patch
new file mode 100644
index 0000000..9a31255
--- /dev/null
+++ b/recipes-core/glibc/glibc/eglibc-install-pic-archives.patch
@@ -0,0 +1,109 @@
+2008-02-07 Joseph Myers <joseph at codesourcery.com>
+
+ * Makerules (install-extras, install-map): New variables.
+ (installed-libcs): Add libc_pic.a.
+ (install-lib): Include _pic.a files for versioned shared
+ libraries.
+ (install-map-nosubdir, install-extras-nosubdir): Add rules for
+ installing extra files.
+ (install-no-libc.a-nosubdir): Depend on install-map-nosubdir and
+ install-extras-nosubdir.
+
+
+2008-04-01 Maxim Kuvyrkov <maxim at codesourcery.com>
+
+ * Makerules (install-lib): Don't install libpthread_pic.a.
+ (install-map): Don't install libpthread_pic.map.
+
+Upstream-Status: Pending
+
+Index: git/Makerules
+===================================================================
+--- git.orig/Makerules 2014-08-27 18:49:22.552070587 +0000
++++ git/Makerules 2014-08-27 18:49:27.308070587 +0000
+@@ -612,6 +631,9 @@
+ $(common-objpfx)libc.so: $(common-objpfx)libc.map
+ endif
+ common-generated += libc.so libc_pic.os
++ifndef subdir
++install-extras := soinit.o sofini.o
++endif
+ ifdef libc.so-version
+ $(common-objpfx)libc.so$(libc.so-version): $(common-objpfx)libc.so
+ $(make-link)
+@@ -834,6 +856,7 @@
+ installed-libcs := $(foreach o,$(filter-out .os,$(object-suffixes-for-libc)),\
+ $(inst_libdir)/$(patsubst %,$(libtype$o),\
+ $(libprefix)$(libc-name)))
++installed-libcs := $(installed-libcs) $(inst_libdir)/libc_pic.a
+ install: $(installed-libcs)
+ $(installed-libcs): $(inst_libdir)/lib$(libprefix)%: lib $(+force)
+ $(make-target-directory)
+@@ -862,6 +885,22 @@
+ install-lib.so-versioned := $(filter $(versioned), $(install-lib.so))
+ install-lib.so-unversioned := $(filter-out $(versioned), $(install-lib.so))
+
++# Install the _pic.a files for versioned libraries, and corresponding
++# .map files.
++# libpthread_pic.a breaks mklibs, so don't install it and its map.
++install-lib := $(install-lib) $(install-lib.so-versioned:%.so=%_pic.a)
++install-lib := $(filter-out libpthread_pic.a,$(install-lib))
++# Despite having a soname libhurduser and libmachuser do not use symbol
++# versioning, so don't install the corresponding .map files.
++ifeq ($(build-shared),yes)
++install-map := $(patsubst %.so,%.map,\
++ $(foreach L,$(install-lib.so-versioned),$(notdir $L)))
++install-map := $(filter-out libhurduser.map libmachuser.map libpthread.map,$(install-map))
++ifndef subdir
++install-map := $(install-map) libc.map
++endif
++endif
++
+ # For versioned libraries, we install three files:
+ # $(inst_libdir)/libfoo.so -- for linking, symlink or ld script
+ # $(inst_slibdir)/libfoo.so.NN -- for loading by SONAME, symlink
+@@ -1103,9 +1142,22 @@
+ endif # headers-nonh
+ endif # headers
+
++ifdef install-map
++$(addprefix $(inst_libdir)/,$(patsubst lib%.map,lib%_pic.map,$(install-map))): \
++ $(inst_libdir)/lib%_pic.map: $(common-objpfx)lib%.map $(+force)
++ $(do-install)
++endif
++
++ifdef install-extras
++$(addprefix $(inst_libdir)/libc_pic/,$(install-extras)): \
++ $(inst_libdir)/libc_pic/%.o: $(elfobjdir)/%.os $(+force)
++ $(do-install)
++endif
++
+ .PHONY: install-bin-nosubdir install-bin-script-nosubdir \
+ install-rootsbin-nosubdir install-sbin-nosubdir install-lib-nosubdir \
+- install-data-nosubdir install-headers-nosubdir
++ install-data-nosubdir install-headers-nosubdir install-map-nosubdir \
++ install-extras-nosubdir
+ install-bin-nosubdir: $(addprefix $(inst_bindir)/,$(install-bin))
+ install-bin-script-nosubdir: $(addprefix $(inst_bindir)/,$(install-bin-script))
+ install-rootsbin-nosubdir: \
+@@ -1118,6 +1170,10 @@
+ install-headers-nosubdir: $(addprefix $(inst_includedir)/,$(headers))
+ install-others-nosubdir: $(install-others)
+ install-others-programs-nosubdir: $(install-others-programs)
++install-map-nosubdir: $(addprefix $(inst_libdir)/,\
++ $(patsubst lib%.map,lib%_pic.map,$(install-map)))
++install-extras-nosubdir: $(addprefix $(inst_libdir)/libc_pic/,\
++ $(install-extras))
+
+ # We need all the `-nosubdir' targets so that `install' in the parent
+ # doesn't depend on several things which each iterate over the subdirs.
+@@ -1127,7 +1183,8 @@
+
+ .PHONY: install install-no-libc.a-nosubdir
+ install-no-libc.a-nosubdir: install-headers-nosubdir install-data-nosubdir \
+- install-lib-nosubdir install-others-nosubdir
++ install-lib-nosubdir install-others-nosubdir \
++ install-map-nosubdir install-extras-nosubdir
+ ifeq ($(build-programs),yes)
+ install-no-libc.a-nosubdir: install-bin-nosubdir install-bin-script-nosubdir \
+ install-rootsbin-nosubdir install-sbin-nosubdir \
diff --git a/recipes-core/glibc/glibc/eglibc-ppc8xx-cache-line-workaround.patch b/recipes-core/glibc/glibc/eglibc-ppc8xx-cache-line-workaround.patch
new file mode 100644
index 0000000..bb83d6d
--- /dev/null
+++ b/recipes-core/glibc/glibc/eglibc-ppc8xx-cache-line-workaround.patch
@@ -0,0 +1,68 @@
+2007-06-13 Nathan Sidwell <nathan at codesourcery.com>
+ Mark Shinwell <shinwell at codesourcery.com>
+
+ * sysdeps/unix/sysv/linux/powerpc/libc-start.c
+ (__libc_start_main): Detect 8xx parts and clear
+ __cache_line_size if detected.
+ * sysdeps/unix/sysv/linux/powerpc/dl-sysdep.c
+ (DL_PLATFORM_AUXV): Likewise.
+
+Upstream-Status: Pending
+
+Index: git/sysdeps/unix/sysv/linux/powerpc/dl-sysdep.c
+===================================================================
+--- git.orig/sysdeps/unix/sysv/linux/powerpc/dl-sysdep.c 2014-08-27 18:49:23.996070587 +0000
++++ git/sysdeps/unix/sysv/linux/powerpc/dl-sysdep.c 2014-08-27 18:49:27.332070587 +0000
+@@ -24,9 +24,21 @@
+ /* Scan the Aux Vector for the "Data Cache Block Size" entry. If found
+ verify that the static extern __cache_line_size is defined by checking
+ for not NULL. If it is defined then assign the cache block size
+- value to __cache_line_size. */
++ value to __cache_line_size. This is used by memset to
++ optimize setting to zero. We have to detect 8xx processors, which
++ have buggy dcbz implementations that cannot report page faults
++ correctly. That requires reading SPR, which is a privileged
++ operation. Fortunately 2.2.18 and later emulates PowerPC mfspr
++ reads from the PVR register. */
+ #define DL_PLATFORM_AUXV \
+ case AT_DCACHEBSIZE: \
++ if (__LINUX_KERNEL_VERSION >= 0x020218) \
++ { \
++ unsigned pvr = 0; \
++ asm ("mfspr %0, 287" : "=r" (pvr)); \
++ if ((pvr & 0xffff0000) == 0x00500000) \
++ break; \
++ } \
+ __cache_line_size = av->a_un.a_val; \
+ break;
+
+Index: git/sysdeps/unix/sysv/linux/powerpc/libc-start.c
+===================================================================
+--- git.orig/sysdeps/unix/sysv/linux/powerpc/libc-start.c 2014-08-27 18:49:23.996070587 +0000
++++ git/sysdeps/unix/sysv/linux/powerpc/libc-start.c 2014-08-27 18:49:27.332070587 +0000
+@@ -68,11 +68,24 @@
+ rtld_fini = NULL;
+ }
+
+- /* Initialize the __cache_line_size variable from the aux vector. */
++ /* Initialize the __cache_line_size variable from the aux vector.
++ This is used by memset to optimize setting to zero. We have to
++ detect 8xx processors, which have buggy dcbz implementations that
++ cannot report page faults correctly. That requires reading SPR,
++ which is a privileged operation. Fortunately 2.2.18 and later
++ emulates PowerPC mfspr reads from the PVR register. */
+ for (ElfW (auxv_t) * av = auxvec; av->a_type != AT_NULL; ++av)
+ switch (av->a_type)
+ {
+ case AT_DCACHEBSIZE:
++ if (__LINUX_KERNEL_VERSION >= 0x020218)
++ {
++ unsigned pvr = 0;
++
++ asm ("mfspr %0, 287" : "=r" (pvr) :);
++ if ((pvr & 0xffff0000) == 0x00500000)
++ break;
++ }
+ __cache_line_size = av->a_un.a_val;
+ break;
+ }
diff --git a/recipes-core/glibc/glibc/eglibc-resolv-dynamic.patch b/recipes-core/glibc/glibc/eglibc-resolv-dynamic.patch
new file mode 100644
index 0000000..a73bceb
--- /dev/null
+++ b/recipes-core/glibc/glibc/eglibc-resolv-dynamic.patch
@@ -0,0 +1,54 @@
+cherry-picked from http://www.eglibc.org/archives/patches/msg00772.html
+
+It hasnt yet been merged into glibc
+
+Signed-off-by: Khem Raj
+
+Upstream-Status: Pending
+
+Index: git/resolv/res_libc.c
+===================================================================
+--- git.orig/resolv/res_libc.c 2014-08-27 18:35:15.492070587 +0000
++++ git/resolv/res_libc.c 2014-08-27 18:35:19.204070587 +0000
+@@ -22,12 +22,13 @@
+ #include <arpa/nameser.h>
+ #include <resolv.h>
+ #include <bits/libc-lock.h>
+-
++#include <sys/stat.h>
+
+ /* The following bit is copied from res_data.c (where it is #ifdef'ed
+ out) since res_init() should go into libc.so but the rest of that
+ file should not. */
+
++__libc_lock_define_initialized (static, lock);
+ extern unsigned long long int __res_initstamp attribute_hidden;
+ /* We have atomic increment operations on 64-bit platforms. */
+ #if __WORDSIZE == 64
+@@ -35,7 +36,6 @@
+ # define atomicincunlock(lock) (void) 0
+ # define atomicinc(var) catomic_increment (&(var))
+ #else
+-__libc_lock_define_initialized (static, lock);
+ # define atomicinclock(lock) __libc_lock_lock (lock)
+ # define atomicincunlock(lock) __libc_lock_unlock (lock)
+ # define atomicinc(var) ++var
+@@ -94,7 +94,18 @@
+ int
+ __res_maybe_init (res_state resp, int preinit)
+ {
++ static time_t last_mtime;
++ struct stat statbuf;
++ int ret;
++
+ if (resp->options & RES_INIT) {
++ ret = stat (_PATH_RESCONF, &statbuf);
++ __libc_lock_lock (lock);
++ if ((ret == 0) && (last_mtime != statbuf.st_mtime)) {
++ last_mtime = statbuf.st_mtime;
++ atomicinc (__res_initstamp);
++ }
++ __libc_lock_unlock (lock);
+ if (__res_initstamp != resp->_u._ext.initstamp) {
+ if (resp->nscount > 0)
+ __res_iclose (resp, true);
diff --git a/recipes-core/glibc/glibc/eglibc-sh4-fpscr_values.patch b/recipes-core/glibc/glibc/eglibc-sh4-fpscr_values.patch
new file mode 100644
index 0000000..bfb813e
--- /dev/null
+++ b/recipes-core/glibc/glibc/eglibc-sh4-fpscr_values.patch
@@ -0,0 +1,42 @@
+2010-09-29 Nobuhiro Iwamatsu <iwamatsu at nigauri.org>
+ Andrew Stubbs <ams at codesourcery.com>
+
+ Resolve SH's __fpscr_values to symbol in libc.so.
+
+ * sysdeps/sh/sh4/fpu/fpu_control.h: Add C++ __set_fpscr prototype.
+ * sysdeps/unix/sysv/linux/sh/Versions (GLIBC_2.2): Add __fpscr_values.
+ * sysdeps/unix/sysv/linux/sh/sysdep.S (___fpscr_values): New constant.
+
+Upstream-Status: Pending
+
+Index: git/sysdeps/unix/sysv/linux/sh/sysdep.S
+===================================================================
+--- git.orig/sysdeps/unix/sysv/linux/sh/sysdep.S 2014-08-27 18:49:24.036070587 +0000
++++ git/sysdeps/unix/sysv/linux/sh/sysdep.S 2014-08-27 18:49:27.332070587 +0000
+@@ -30,3 +30,14 @@
+
+ #define __syscall_error __syscall_error_1
+ #include <sysdeps/unix/sh/sysdep.S>
++
++ .data
++ .align 3
++ .globl ___fpscr_values
++ .type ___fpscr_values, @object
++ .size ___fpscr_values, 8
++___fpscr_values:
++ .long 0
++ .long 0x80000
++weak_alias (___fpscr_values, __fpscr_values)
++
+Index: git/sysdeps/unix/sysv/linux/sh/Versions
+===================================================================
+--- git.orig/sysdeps/unix/sysv/linux/sh/Versions 2014-08-27 18:49:24.028070587 +0000
++++ git/sysdeps/unix/sysv/linux/sh/Versions 2014-08-27 18:49:27.332070587 +0000
+@@ -2,6 +2,7 @@
+ GLIBC_2.2 {
+ # functions used in other libraries
+ __xstat64; __fxstat64; __lxstat64;
++ __fpscr_values;
+
+ # a*
+ alphasort64;
diff --git a/recipes-core/glibc/glibc/eglibc-use-option-groups.patch b/recipes-core/glibc/glibc/eglibc-use-option-groups.patch
new file mode 100644
index 0000000..7390ab6
--- /dev/null
+++ b/recipes-core/glibc/glibc/eglibc-use-option-groups.patch
@@ -0,0 +1,16546 @@
+Forward port eglibc options groups support
+
+Upstream-Status: Pending
+
+Index: git/argp/argp-fmtstream.c
+===================================================================
+--- git.orig/argp/argp-fmtstream.c 2014-08-29 20:00:42.976070587 -0700
++++ git/argp/argp-fmtstream.c 2014-08-29 20:01:15.188070587 -0700
+@@ -42,6 +42,7 @@
+ #ifdef _LIBC
+ # include <wchar.h>
+ # include <libio/libioP.h>
++# include <gnu/option-groups.h>
+ # define __vsnprintf(s, l, f, a) _IO_vsnprintf (s, l, f, a)
+ #endif
+
+@@ -100,7 +101,11 @@
+ __argp_fmtstream_update (fs);
+ if (fs->p > fs->buf)
+ {
++#ifdef _LIBC
+ __fxprintf (fs->stream, "%.*s", (int) (fs->p - fs->buf), fs->buf);
++#else
++ fwrite_unlocked (fs->buf, 1, fs->p - fs->buf, fs->stream);
++#endif
+ }
+ free (fs->buf);
+ free (fs);
+@@ -145,9 +150,17 @@
+ size_t i;
+ for (i = 0; i < pad; i++)
+ {
++#ifdef _LIBC
+ if (_IO_fwide (fs->stream, 0) > 0)
+- putwc_unlocked (L' ', fs->stream);
++ {
++#if ! _LIBC || __OPTION_POSIX_WIDE_CHAR_DEVICE_IO
++ putwc_unlocked (L' ', fs->stream);
++#else
++ abort ();
++#endif
++ }
+ else
++#endif
+ putc_unlocked (' ', fs->stream);
+ }
+ }
+@@ -308,9 +321,17 @@
+ *nl++ = ' ';
+ else
+ for (i = 0; i < fs->wmargin; ++i)
++#ifdef _LIBC
+ if (_IO_fwide (fs->stream, 0) > 0)
+- putwc_unlocked (L' ', fs->stream);
++ {
++#ifdef OPTION_POSIX_WIDE_CHAR_DEVICE_IO
++ putwc_unlocked (L' ', fs->stream);
++#else
++ abort ();
++#endif
++ }
+ else
++#endif
+ putc_unlocked (' ', fs->stream);
+
+ /* Copy the tail of the original buffer into the current buffer
+Index: git/argp/argp-help.c
+===================================================================
+--- git.orig/argp/argp-help.c 2014-08-29 20:00:42.976070587 -0700
++++ git/argp/argp-help.c 2014-08-29 20:01:15.188070587 -0700
+@@ -51,6 +51,7 @@
+ #ifdef _LIBC
+ # include <../libio/libioP.h>
+ # include <wchar.h>
++# include <gnu/option-groups.h>
+ #endif
+
+ #ifndef _
+@@ -1702,7 +1703,7 @@
+ }
+
+ char *
+-__argp_short_program_name (void)
++(__argp_short_program_name) (void)
+ {
+ # if HAVE_DECL_PROGRAM_INVOCATION_SHORT_NAME
+ return program_invocation_short_name;
+@@ -1873,9 +1874,17 @@
+ #endif
+ }
+
++#ifdef _LIBC
+ if (_IO_fwide (stream, 0) > 0)
+- putwc_unlocked (L'\n', stream);
++ {
++#if ! _LIBC || __OPTION_POSIX_WIDE_CHAR_DEVICE_IO
++ putwc_unlocked (L'\n', stream);
++#else
++ abort ();
++#endif
++ }
+ else
++#endif
+ putc_unlocked ('\n', stream);
+
+ #if _LIBC || (HAVE_FLOCKFILE && HAVE_FUNLOCKFILE)
+Index: git/argp/argp-namefrob.h
+===================================================================
+--- git.orig/argp/argp-namefrob.h 2014-08-29 20:00:42.976070587 -0700
++++ git/argp/argp-namefrob.h 2014-08-29 20:01:15.192070587 -0700
+@@ -76,10 +76,12 @@
+ #undef __argp_fmtstream_wmargin
+ #define __argp_fmtstream_wmargin argp_fmtstream_wmargin
+
++#if 0
+ #include "mempcpy.h"
+ #include "strcase.h"
+ #include "strchrnul.h"
+ #include "strndup.h"
++#endif
+
+ /* normal libc functions we call */
+ #undef __flockfile
+Index: git/argp/Makefile
+===================================================================
+--- git.orig/argp/Makefile 2014-08-29 20:00:42.976070587 -0700
++++ git/argp/Makefile 2014-08-29 20:01:15.192070587 -0700
+@@ -18,6 +18,8 @@
+ #
+ # Makefile for argp.
+ #
++include ../option-groups.mak
++
+ subdir := argp
+
+ include ../Makeconfig
+Index: git/catgets/Makefile
+===================================================================
+--- git.orig/catgets/Makefile 2014-08-29 20:00:43.008070587 -0700
++++ git/catgets/Makefile 2014-08-29 20:01:15.192070587 -0700
+@@ -22,20 +22,23 @@
+
+ include ../Makeconfig
+
++include ../option-groups.mak
++
+ headers = nl_types.h
+-routines = catgets open_catalog
+-others = gencat
+-install-bin = gencat
+-extra-objs = $(gencat-modules:=.o)
++routines-$(OPTION_EGLIBC_CATGETS) := catgets open_catalog
++others-$(OPTION_EGLIBC_CATGETS) := gencat
++install-bin-$(OPTION_EGLIBC_CATGETS) := gencat
++extra-objs-$(OPTION_EGLIBC_CATGETS) := $(gencat-modules:=.o)
+
+-tests = tst-catgets
+-test-srcs = test-gencat
++tests-$(OPTION_EGLIBC_CATGETS) := tst-catgets
++test-srcs-$(OPTION_EGLIBC_CATGETS) := test-gencat
+
++ifeq (y,$(OPTION_EGLIBC_CATGETS))
+ ifeq ($(run-built-tests),yes)
+ tests-special += $(objpfx)de/libc.cat $(objpfx)test1.cat $(objpfx)test2.cat \
+ $(objpfx)sample.SJIS.cat $(objpfx)test-gencat.out
+ endif
+-
++endif
+ gencat-modules = xmalloc
+
+ # To find xmalloc.c
+Index: git/crypt/crypt-entry.c
+===================================================================
+--- git.orig/crypt/crypt-entry.c 2014-08-29 20:00:43.028070587 -0700
++++ git/crypt/crypt-entry.c 2014-08-29 20:01:15.192070587 -0700
+@@ -27,6 +27,7 @@
+ #include <stdio.h>
+ #endif
+ #include <string.h>
++#include <gnu/option-groups.h>
+ #include <errno.h>
+ #include <fips-private.h>
+
+@@ -76,9 +77,11 @@
+ const char *salt;
+ struct crypt_data * __restrict data;
+ {
++#if __OPTION_EGLIBC_CRYPT_UFC
+ ufc_long res[4];
+ char ktab[9];
+ ufc_long xx = 25; /* to cope with GCC long long compiler bugs */
++#endif /*__OPTION_EGLIBC_CRYPT_UFC*/
+
+ #ifdef _LIBC
+ /* Try to find out whether we have to use MD5 encryption replacement. */
+@@ -105,6 +108,7 @@
+ sizeof (struct crypt_data));
+ #endif
+
++#if __OPTION_EGLIBC_CRYPT_UFC
+ /*
+ * Hack DES tables according to salt
+ */
+@@ -144,6 +148,10 @@
+ */
+ _ufc_output_conversion_r (res[0], res[1], salt, data);
+ return data->crypt_3_buf;
++#else /* __OPTION_EGLIBC_CRYPT_UFC */
++ __set_errno (ENOSYS);
++ return NULL;
++#endif /* __OPTION_EGLIBC_CRYPT_UFC */
+ }
+ weak_alias (__crypt_r, crypt_r)
+
+@@ -168,7 +176,12 @@
+ return __sha512_crypt (key, salt);
+ #endif
+
++#if __OPTION_EGLIBC_CRYPT_UFC
+ return __crypt_r (key, salt, &_ufc_foobar);
++#else /* __OPTION_EGLIBC_CRYPT_UFC */
++ __set_errno (ENOSYS);
++ return NULL;
++#endif /* __OPTION_EGLIBC_CRYPT_UFC */
+ }
+
+
+Index: git/crypt/Makefile
+===================================================================
+--- git.orig/crypt/Makefile 2014-08-29 20:00:43.024070587 -0700
++++ git/crypt/Makefile 2014-08-29 20:01:15.192070587 -0700
+@@ -18,21 +18,25 @@
+ #
+ # Sub-makefile for crypt() portion of the library.
+ #
++include ../option-groups.mak
++
+ subdir := crypt
+
+ include ../Makeconfig
+
+ headers := crypt.h
+
+-extra-libs := libcrypt
+-extra-libs-others := $(extra-libs)
++extra-libs-$(OPTION_EGLIBC_CRYPT) := libcrypt
++extra-libs-others-y := $(extra-libs-y)
+
+-libcrypt-routines := crypt-entry md5-crypt sha256-crypt sha512-crypt crypt \
+- crypt_util
++libcrypt-routines :=crypt-entry md5-crypt sha256-crypt sha512-crypt crypt_common
++libcrypt-routines-$(OPTION_EGLIBC_CRYPT_UFC) := crypt crypt_util
++libcrypt-routines += $(libcrypt-routines-y)
+
+-tests := cert md5c-test sha256c-test sha512c-test badsalttest
++tests-$(OPTION_EGLIBC_CRYPT) := md5c-test sha256c-test sha512c-test badsalttest
++tests-$(OPTION_EGLIBC_CRYPT_UFC) += cert
+
+-ifeq ($(crypt-in-libc),yes)
++ifeq ($(crypt-in-libc)$(OPTION_EGLIBC_CRYPT),yesy)
+ routines += $(libcrypt-routines)
+ endif
+
+@@ -44,7 +48,7 @@
+ else
+ libcrypt-routines += md5 sha256 sha512
+
+-tests += md5test sha256test sha512test
++tests-$(OPTION_EGLIBC_CRYPT) += md5test sha256test sha512test
+
+ # The test md5test-giant uses up to 400 MB of RSS and runs on a fast
+ # machine over a minute.
+@@ -64,8 +68,10 @@
+ $(objpfx)sha512test: $(patsubst %, $(objpfx)%.o,$(sha512-routines))
+ endif
+
++ifeq ($(OPTION_EGLIBC_CRYPT),y)
+ ifeq (yes,$(build-shared))
+ $(addprefix $(objpfx),$(tests)): $(objpfx)libcrypt.so
+ else
+ $(addprefix $(objpfx),$(tests)): $(objpfx)libcrypt.a
+ endif
++endif # eglibc: OPTION_EGLIBC_CRYPT
+Index: git/csu/Makefile
+===================================================================
+--- git.orig/csu/Makefile 2014-08-29 20:00:43.032070587 -0700
++++ git/csu/Makefile 2014-08-29 20:01:15.192070587 -0700
+@@ -22,6 +22,8 @@
+ # crtn.o, special "initializer" and "finalizer" files used in the link
+ # to make the .init and .fini sections work right.
+
++include ../option-groups.mak
++
+ subdir := csu
+
+ include ../Makeconfig
+Index: git/debug/Makefile
+===================================================================
+--- git.orig/debug/Makefile 2014-08-29 20:00:43.036070587 -0700
++++ git/debug/Makefile 2014-08-29 20:01:15.192070587 -0700
+@@ -18,6 +18,8 @@
+ #
+ # Sub-makefile for debug portion of the library.
+ #
++include ../option-groups.mak
++
+ subdir := debug
+
+ include ../Makeconfig
+@@ -27,7 +29,7 @@
+ # Note that ptsname_r_chk and getlogin_r are not here, but in
+ # login/Makefile instead. If that subdir is omitted from the
+ # build, its _FORTIFY_SOURCE support will be too.
+-routines = backtrace backtracesyms backtracesymsfd noophooks \
++routines = noophooks \
+ memcpy_chk memmove_chk mempcpy_chk memset_chk stpcpy_chk \
+ strcat_chk strcpy_chk strncat_chk strncpy_chk stpncpy_chk \
+ sprintf_chk vsprintf_chk snprintf_chk vsnprintf_chk \
+@@ -36,20 +38,27 @@
+ read_chk pread_chk pread64_chk recv_chk recvfrom_chk \
+ readlink_chk readlinkat_chk getwd_chk getcwd_chk \
+ realpath_chk fread_chk fread_u_chk \
+- wctomb_chk wcscpy_chk wmemcpy_chk wmemmove_chk wmempcpy_chk \
+- wcpcpy_chk wcsncpy_chk wcscat_chk wcsncat_chk wmemset_chk \
+- wcpncpy_chk \
+- swprintf_chk vswprintf_chk wprintf_chk fwprintf_chk \
+- vwprintf_chk vfwprintf_chk fgetws_chk fgetws_u_chk \
+ confstr_chk getgroups_chk ttyname_r_chk \
+- gethostname_chk getdomainname_chk wcrtomb_chk mbsnrtowcs_chk \
+- wcsnrtombs_chk mbsrtowcs_chk wcsrtombs_chk mbstowcs_chk \
+- wcstombs_chk asprintf_chk vasprintf_chk dprintf_chk \
++ gethostname_chk getdomainname_chk \
++ asprintf_chk vasprintf_chk dprintf_chk \
+ vdprintf_chk obprintf_chk \
+ longjmp_chk ____longjmp_chk \
+ fdelt_chk poll_chk ppoll_chk \
+ stack_chk_fail fortify_fail \
+ $(static-only-routines)
++routines-$(OPTION_EGLIBC_BACKTRACE) += backtrace backtracesyms backtracesymsfd
++routines-$(OPTION_POSIX_WIDE_CHAR_DEVICE_IO) \
++ += wprintf_chk fwprintf_chk \
++ vwprintf_chk vfwprintf_chk fgetws_chk fgetws_u_chk
++routines-$(OPTION_POSIX_C_LANG_WIDE_CHAR) \
++ += wctomb_chk wcscpy_chk wmemcpy_chk wmemmove_chk wmempcpy_chk \
++ wcpcpy_chk wcsncpy_chk wcscat_chk wcsncat_chk wmemset_chk \
++ wcpncpy_chk \
++ swprintf_chk vswprintf_chk \
++ wcrtomb_chk mbsnrtowcs_chk \
++ wcsnrtombs_chk mbsrtowcs_chk wcsrtombs_chk mbstowcs_chk \
++ wcstombs_chk
++
+ static-only-routines := warning-nop stack_chk_fail_local
+
+ CFLAGS-backtrace.c = -fno-omit-frame-pointer
+@@ -129,11 +138,15 @@
+ LDFLAGS-tst-backtrace5 = -rdynamic
+ LDFLAGS-tst-backtrace6 = -rdynamic
+
+-tests = backtrace-tst tst-longjmp_chk tst-chk1 tst-chk2 tst-chk3 \
+- tst-lfschk1 tst-lfschk2 tst-lfschk3 test-strcpy_chk test-stpcpy_chk \
+- tst-chk4 tst-chk5 tst-chk6 tst-lfschk4 tst-lfschk5 tst-lfschk6 \
+- tst-longjmp_chk2 tst-backtrace2 tst-backtrace3 tst-backtrace4 \
+- tst-backtrace5 tst-backtrace6
++tests = tst-longjmp_chk test-strcpy_chk test-stpcpy_chk tst-longjmp_chk2
++tests-$(OPTION_EGLIBC_LOCALE_CODE) \
++ += tst-chk1 tst-chk2 tst-chk3 tst-lfschk1 tst-lfschk2 tst-lfschk3
++tests-$(OPTION_EGLIBC_BACKTRACE) \
++ += backtrace-tst tst-backtrace2 tst-backtrace3 tst-backtrace4 \
++ tst-backtrace5 tst-backtrace6
++ifeq (yy,$(OPTION_EGLIBC_LOCALE_CODE)$(OPTION_EGLIBC_CXX_TESTS))
++tests += tst-chk4 tst-chk5 tst-chk6 tst-lfschk4 tst-lfschk5 tst-lfschk6
++endif
+
+ tests-ifunc := $(stpcpy_chk strcpy_chk:%=test-%-ifunc)
+ tests += $(tests-ifunc)
+Index: git/debug/segfault.c
+===================================================================
+--- git.orig/debug/segfault.c 2014-08-29 20:00:46.280070587 -0700
++++ git/debug/segfault.c 2014-08-29 20:01:15.192070587 -0700
+@@ -30,6 +30,7 @@
+ #include <unistd.h>
+ #include <_itoa.h>
+ #include <ldsodefs.h>
++#include <gnu/option-groups.h>
+
+ /* This file defines macros to access the content of the sigcontext element
+ passed up by the signal handler. */
+@@ -91,6 +92,7 @@
+ REGISTER_DUMP;
+ #endif
+
++#if __OPTION_EGLIBC_BACKTRACE
+ WRITE_STRING ("\nBacktrace:\n");
+
+ /* Get the backtrace. */
+@@ -113,6 +115,7 @@
+
+ /* Now generate nicely formatted output. */
+ __backtrace_symbols_fd (arr + i, cnt - i, fd);
++#endif
+
+ #ifdef HAVE_PROC_SELF
+ /* Now the link map. */
+Index: git/debug/tst-chk1.c
+===================================================================
+--- git.orig/debug/tst-chk1.c 2014-08-29 20:00:46.288070587 -0700
++++ git/debug/tst-chk1.c 2014-08-29 20:01:15.192070587 -0700
+@@ -31,6 +31,7 @@
+ #include <sys/select.h>
+ #include <sys/socket.h>
+ #include <sys/un.h>
++#include <gnu/option-groups.h>
+
+
+ #define obstack_chunk_alloc malloc
+@@ -307,6 +308,7 @@
+ snprintf (buf + 8, l0 + 3, "%d", num2);
+ CHK_FAIL_END
+
++#if __OPTION_POSIX_C_LANG_WIDE_CHAR
+ CHK_FAIL_START
+ swprintf (wbuf + 8, 3, L"%d", num1);
+ CHK_FAIL_END
+@@ -314,6 +316,7 @@
+ CHK_FAIL_START
+ swprintf (wbuf + 8, l0 + 3, L"%d", num1);
+ CHK_FAIL_END
++#endif /* __OPTION_POSIX_C_LANG_WIDE_CHAR */
+ # endif
+
+ memcpy (buf, str1 + 2, l0 + 9);
+@@ -381,6 +384,7 @@
+ CHK_FAIL_END
+ #endif
+
++#if __OPTION_POSIX_C_LANG_WIDE_CHAR
+
+ /* These ops can be done without runtime checking of object size. */
+ wmemcpy (wbuf, L"abcdefghij", 10);
+@@ -605,6 +609,7 @@
+ CHK_FAIL_END
+ #endif
+
++#endif /* __OPTION_POSIX_C_LANG_WIDE_CHAR */
+
+ /* Now checks for %n protection. */
+
+@@ -1192,6 +1197,7 @@
+ # endif
+ #endif
+
++#if __OPTION_POSIX_C_LANG_WIDE_CHAR
+ if (setlocale (LC_ALL, "de_DE.UTF-8") != NULL)
+ {
+ assert (MB_CUR_MAX <= 10);
+@@ -1348,6 +1354,7 @@
+ puts ("cannot set locale");
+ ret = 1;
+ }
++#endif /* __OPTION_POSIX_C_LANG_WIDE_CHAR */
+
+ int fd = posix_openpt (O_RDWR);
+ if (fd != -1)
+Index: git/dlfcn/Makefile
+===================================================================
+--- git.orig/dlfcn/Makefile 2014-08-29 20:00:46.312070587 -0700
++++ git/dlfcn/Makefile 2014-08-29 20:01:15.192070587 -0700
+@@ -15,6 +15,8 @@
+ # License along with the GNU C Library; if not, see
+ # <http://www.gnu.org/licenses/>.
+
++include ../option-groups.mak
++
+ subdir := dlfcn
+
+ include ../Makeconfig
+@@ -36,7 +38,9 @@
+ ifeq (yes,$(build-shared))
+ tests = glrefmain failtest tst-dladdr default errmsg1 tstcxaatexit \
+ bug-dlopen1 bug-dlsym1 tst-dlinfo bug-atexit1 bug-atexit2 \
+- bug-atexit3 tstatexit bug-dl-leaf
++ tstatexit bug-dl-leaf
++
++tests-$(OPTION_EGLIBC_CXX_TESTS) += bug-atexit3
+ endif
+ modules-names = glreflib1 glreflib2 glreflib3 failtestmod defaultmod1 \
+ defaultmod2 errmsg1mod modatexit modcxaatexit \
+Index: git/elf/dl-support.c
+===================================================================
+--- git.orig/elf/dl-support.c 2014-08-29 20:00:46.384070587 -0700
++++ git/elf/dl-support.c 2014-08-29 20:01:15.192070587 -0700
+@@ -19,6 +19,7 @@
+ /* This file defines some things that for the dynamic linker are defined in
+ rtld.c and dl-sysdep.c in ways appropriate to bootstrap dynamic linking. */
+
++#include <gnu/option-groups.h>
+ #include <errno.h>
+ #include <libintl.h>
+ #include <stdlib.h>
+@@ -42,7 +43,9 @@
+ const char *_dl_platform;
+ size_t _dl_platformlen;
+
++#if __OPTION_EGLIBC_RTLD_DEBUG
+ int _dl_debug_mask;
++#endif
+ int _dl_lazy;
+ ElfW(Addr) _dl_use_load_bias = -2;
+ int _dl_dynamic_weak;
+Index: git/elf/rtld.c
+===================================================================
+--- git.orig/elf/rtld.c 2014-08-29 20:01:14.708070587 -0700
++++ git/elf/rtld.c 2014-08-29 20:01:15.196070587 -0700
+@@ -16,6 +16,7 @@
+ License along with the GNU C Library; if not, see
+ <http://www.gnu.org/licenses/>. */
+
++#include <gnu/option-groups.h>
+ #include <errno.h>
+ #include <dlfcn.h>
+ #include <fcntl.h>
+@@ -2200,6 +2201,7 @@
+ objname, errstring);
+ }
+
++#if __OPTION_EGLIBC_RTLD_DEBUG
+ /* Nonzero if any of the debugging options is enabled. */
+ static int any_debug attribute_relro;
+
+@@ -2309,6 +2311,7 @@
+ _exit (0);
+ }
+ }
++#endif /* __OPTION_EGLIBC_RTLD_DEBUG */
+
+ static void
+ process_dl_audit (char *str)
+@@ -2376,12 +2379,14 @@
+ break;
+
+ case 5:
++#if __OPTION_EGLIBC_RTLD_DEBUG
+ /* Debugging of the dynamic linker? */
+ if (memcmp (envline, "DEBUG", 5) == 0)
+ {
+ process_dl_debug (&envline[6]);
+ break;
+ }
++#endif
+ if (memcmp (envline, "AUDIT", 5) == 0)
+ process_dl_audit (&envline[6]);
+ break;
+@@ -2490,7 +2495,9 @@
+ {
+ mode = trace;
+ GLRO(dl_verbose) = 1;
++#if __OPTION_EGLIBC_RTLD_DEBUG
+ GLRO_dl_debug_mask |= DL_DEBUG_PRELINK;
++#endif
+ GLRO(dl_trace_prelink) = &envline[17];
+ }
+ break;
+@@ -2537,12 +2544,15 @@
+ if (__access ("/etc/suid-debug", F_OK) != 0)
+ {
+ unsetenv ("MALLOC_CHECK_");
++#if __OPTION_EGLIBC_RTLD_DEBUG
+ GLRO_dl_debug_mask = 0;
++#endif
+ }
+
+ if (mode != normal)
+ _exit (5);
+ }
++#if __OPTION_EGLIBC_RTLD_DEBUG
+ /* If we have to run the dynamic linker in debugging mode and the
+ LD_DEBUG_OUTPUT environment variable is given, we write the debug
+ messages to this file. */
+@@ -2567,6 +2577,7 @@
+ /* We use standard output if opening the file failed. */
+ GLRO(dl_debug_fd) = STDOUT_FILENO;
+ }
++#endif /* __OPTION_EGLIBC_RTLD_DEBUG */
+ }
+
+
+Index: git/extra-lib.mk
+===================================================================
+--- git.orig/extra-lib.mk 2014-08-29 20:00:46.544070587 -0700
++++ git/extra-lib.mk 2014-08-29 20:01:15.196070587 -0700
+@@ -25,7 +25,9 @@
+ extra-objs := $(extra-objs)
+
+ # The modules that go in $(lib).
+-all-$(lib)-routines := $($(lib)-routines) $($(lib)-sysdep_routines)
++all-$(lib)-routines := $($(lib)-routines) \
++ $($(lib)-routines-y) \
++ $($(lib)-sysdep_routines)
+
+ # Add each flavor of library to the lists of things to build and install.
+ install-lib += $(foreach o,$(object-suffixes-$(lib)),$(lib:lib%=$(libtype$o)))
+@@ -101,7 +103,7 @@
+ endif
+
+ # This will define `libof-ROUTINE := LIB' for each of the routines.
+-cpp-srcs-left := $($(lib)-routines) $($(lib)-sysdep_routines)
++cpp-srcs-left := $(all-$(lib)-routines)
+ ifneq (,$(cpp-srcs-left))
+ include $(patsubst %,$(..)cppflags-iterator.mk,$(cpp-srcs-left))
+ endif
+Index: git/grp/Makefile
+===================================================================
+--- git.orig/grp/Makefile 2014-08-29 20:00:46.556070587 -0700
++++ git/grp/Makefile 2014-08-29 20:01:15.196070587 -0700
+@@ -18,6 +18,8 @@
+ #
+ # Sub-makefile for grp portion of the library.
+ #
++include ../option-groups.mak
++
+ subdir := grp
+
+ include ../Makeconfig
+@@ -29,6 +31,9 @@
+ getgrent_r getgrgid_r getgrnam_r fgetgrent_r
+
+ tests := testgrp
++ifneq (y,$(OPTION_EGLIBC_NSSWITCH))
++LDLIBS-testgrp += $(shell cat $(common-objpfx)nss/fixed-nsswitch-libs)
++endif
+
+ ifeq (yes,$(build-shared))
+ test-srcs := tst_fgetgrent
+Index: git/hesiod/Makefile
+===================================================================
+--- git.orig/hesiod/Makefile 2014-08-29 20:00:46.580070587 -0700
++++ git/hesiod/Makefile 2014-08-29 20:01:15.196070587 -0700
+@@ -18,12 +18,14 @@
+ #
+ # Sub-makefile for hesiod portion of the library.
+ #
++include ../option-groups.mak
++
+ subdir := hesiod
+
+ include ../Makeconfig
+
+-extra-libs := libnss_hesiod
+-extra-libs-others = $(extra-libs)
++extra-libs-$(OPTION_EGLIBC_INET) += libnss_hesiod
++extra-libs-others-y += $(extra-libs-y)
+
+ subdir-dirs = nss_hesiod
+ vpath %.c nss_hesiod
+Index: git/iconv/gconv_db.c
+===================================================================
+--- git.orig/iconv/gconv_db.c 2014-08-29 20:00:46.604070587 -0700
++++ git/iconv/gconv_db.c 2014-08-29 20:01:15.196070587 -0700
+@@ -25,6 +25,7 @@
+ #include <sys/param.h>
+ #include <bits/libc-lock.h>
+ #include <locale/localeinfo.h>
++#include <gnu/option-groups.h>
+
+ #include <dlfcn.h>
+ #include <gconv_int.h>
+@@ -828,9 +829,11 @@
+ /* Free all resources if necessary. */
+ libc_freeres_fn (free_mem)
+ {
++#if __OPTION_EGLIBC_LOCALE_CODE
+ /* First free locale memory. This needs to be done before freeing derivations,
+ as ctype cleanup functions dereference steps arrays which we free below. */
+ _nl_locale_subfreeres ();
++#endif
+
+ /* finddomain.c has similar problem. */
+ extern void _nl_finddomain_subfreeres (void) attribute_hidden;
+Index: git/iconv/gconv_trans.c
+===================================================================
+--- git.orig/iconv/gconv_trans.c 2014-08-29 20:00:46.612070587 -0700
++++ git/iconv/gconv_trans.c 2014-08-29 20:01:15.196070587 -0700
+@@ -23,6 +23,7 @@
+ #include <stdint.h>
+ #include <string.h>
+ #include <stdlib.h>
++#include <gnu/option-groups.h>
+
+ #include <bits/libc-lock.h>
+ #include "gconv_int.h"
+@@ -59,6 +60,7 @@
+ PTR_DEMANGLE (fct);
+ #endif
+
++#if __OPTION_EGLIBC_LOCALE_CODE
+ /* If there is no transliteration information in the locale don't do
+ anything and return the error. */
+ size = _NL_CURRENT_WORD (LC_CTYPE, _NL_CTYPE_TRANSLIT_TAB_SIZE);
+@@ -194,6 +196,7 @@
+ sorted. */
+ break;
+ }
++#endif
+
+ /* One last chance: use the default replacement. */
+ if (_NL_CURRENT_WORD (LC_CTYPE, _NL_CTYPE_TRANSLIT_DEFAULT_MISSING_LEN) != 0)
+Index: git/iconv/iconv_prog.c
+===================================================================
+--- git.orig/iconv/iconv_prog.c 2014-08-29 20:00:46.612070587 -0700
++++ git/iconv/iconv_prog.c 2014-08-29 20:01:15.196070587 -0700
+@@ -35,6 +35,7 @@
+ #ifdef _POSIX_MAPPED_FILES
+ # include <sys/mman.h>
+ #endif
++#include <gnu/option-groups.h>
+ #include <charmap.h>
+ #include <gconv_int.h>
+ #include "iconv_prog.h"
+@@ -221,10 +222,17 @@
+ bool to_wrong =
+ (iconv_open (to_code, "UTF-8") == (iconv_t) -1
+ && errno == EINVAL);
++#if __OPTION_EGLIBC_LOCALE_CODE
+ const char *from_pretty =
+ (from_code[0] ? from_code : nl_langinfo (CODESET));
+ const char *to_pretty =
+ (orig_to_code[0] ? orig_to_code : nl_langinfo (CODESET));
++#else
++ const char *from_pretty =
++ (from_code[0] ? from_code : "ANSI_X3.4-1968");
++ const char *to_pretty =
++ (orig_to_code[0] ? orig_to_code : "ANSI_X3.4-1968");
++#endif
+
+ if (from_wrong)
+ {
+Index: git/iconv/Makefile
+===================================================================
+--- git.orig/iconv/Makefile 2014-08-29 20:00:46.600070587 -0700
++++ git/iconv/Makefile 2014-08-29 20:01:15.196070587 -0700
+@@ -18,6 +18,8 @@
+ #
+ # Makefile for iconv.
+ #
++include ../option-groups.mak
++
+ subdir := iconv
+
+ include ../Makeconfig
+@@ -57,6 +59,9 @@
+ CPPFLAGS-strtab = -DNOT_IN_libc
+ CPPFLAGS-charmap = -DNOT_IN_libc
+ CPPFLAGS-charmap-dir = -DNOT_IN_libc
++ifneq (y,$(OPTION_EGLIBC_SPAWN))
++CPPFLAGS-charmap-dir.c += -DNO_UNCOMPRESS
++endif
+
+ ifeq ($(run-built-tests),yes)
+ xtests-special += $(objpfx)test-iconvconfig.out
+Index: git/iconvdata/Makefile
+===================================================================
+--- git.orig/iconvdata/Makefile 2014-08-29 20:00:46.628070587 -0700
++++ git/iconvdata/Makefile 2014-08-29 20:01:15.196070587 -0700
+@@ -18,12 +18,15 @@
+ #
+ # Makefile for iconv data and code.
+ #
++include ../option-groups.mak
++
+ subdir := iconvdata
+
+ include ../Makeconfig
+
+ # Names of all the shared objects which implement the transformations.
+-modules := ISO8859-1 ISO8859-2 ISO8859-3 ISO8859-4 ISO8859-5 \
++modules-$(OPTION_EGLIBC_CHARSETS) \
++ := ISO8859-1 ISO8859-2 ISO8859-3 ISO8859-4 ISO8859-5 \
+ ISO8859-6 ISO8859-7 ISO8859-8 ISO8859-9 ISO8859-10 \
+ ISO8859-11 ISO8859-13 ISO8859-14 ISO8859-15 ISO8859-16 \
+ T.61 ISO_6937 SJIS KOI-8 HP-ROMAN8 HP-ROMAN9 EBCDIC-AT-DE \
+@@ -63,11 +66,13 @@
+ MAC-CENTRALEUROPE KOI8-RU ISO8859-9E \
+ CP770 CP771 CP772 CP773 CP774
+
+-modules.so := $(addsuffix .so, $(modules))
++modules.so := $(addsuffix .so, $(modules-y))
+
+ ifeq (yes,$(build-shared))
+ tests = bug-iconv1 bug-iconv2 tst-loading tst-e2big tst-iconv4 bug-iconv4 \
+- tst-iconv6 bug-iconv5 bug-iconv6 tst-iconv7 bug-iconv8 bug-iconv9
++ tst-iconv6 bug-iconv5 bug-iconv8 bug-iconv9
++tests-$(OPTION_EGLIBC_LOCALE_CODE) += bug-iconv6 tst-iconv7
++
+ ifeq ($(have-thread-library),yes)
+ tests += bug-iconv3
+ endif
+@@ -130,13 +135,13 @@
+ # Rule to generate the shared objects.
+ charmaps = ../localedata/charmaps
+ -include $(objpfx)iconv-rules
+-extra-modules-left := $(modules)
++extra-modules-left := $(modules-y)
+ include extra-module.mk
+
+
+ extra-objs += $(modules.so)
+-install-others = $(addprefix $(inst_gconvdir)/, $(modules.so)) \
+- $(inst_gconvdir)/gconv-modules
++install-others-y += $(addprefix $(inst_gconvdir)/, $(modules.so))
++install-others-$(OPTION_EGLIBC_CHARSETS) += $(inst_gconvdir)/gconv-modules
+
+ # We can build the conversion tables for numerous charsets automatically.
+
+@@ -204,7 +209,7 @@
+ ifndef avoid-generated
+ $(objpfx)iconv-rules: Makefile
+ $(make-target-directory)
+- { echo $(filter-out lib%, $(modules)); \
++ { echo $(filter-out lib%, $(modules-y)); \
+ echo 8bit $(gen-8bit-modules); \
+ echo 8bit-gap $(gen-8bit-gap-modules); } | \
+ LC_ALL=C \
+@@ -247,7 +252,7 @@
+ $(do-install-program)
+ $(inst_gconvdir)/gconv-modules: gconv-modules $(+force)
+ $(do-install)
+-ifeq (no,$(cross-compiling))
++# eglibc: ifeq (no,$(cross-compiling))
+ # Update the $(prefix)/lib/gconv/gconv-modules.cache file. This is necessary
+ # if this libc has more gconv modules than the previously installed one.
+ if test -f "$(inst_gconvdir)/gconv-modules.cache"; then \
+@@ -256,9 +261,9 @@
+ $(common-objpfx)iconv/iconvconfig \
+ $(addprefix --prefix=,$(install_root)); \
+ fi
+-else
+- @echo '*@*@*@ You should recreate $(inst_gconvdir)/gconv-modules.cache'
+-endif
++# eglibc: else
++# eglibc: @echo '*@*@*@ You should recreate $(inst_gconvdir)/gconv-modules.cache'
++# eglibc: endif
+
+ endif # build-shared = yes
+
+Index: git/include/netdb.h
+===================================================================
+--- git.orig/include/netdb.h 2014-08-29 20:00:47.152070587 -0700
++++ git/include/netdb.h 2014-08-29 20:01:15.196070587 -0700
+@@ -232,6 +232,10 @@
+ (const char *name, int af, struct hostent *host, \
+ char *buffer, size_t buflen, int *errnop, \
+ int *h_errnop); \
++extern enum nss_status _nss_ ## service ## _gethostbyname3_r \
++ (const char *name, int af, struct hostent *result, \
++ char *buffer, size_t buflen, int *errnop, \
++ int *h_errnop, int32_t *ttlp, char **canonp); \
+ extern enum nss_status _nss_ ## service ## _gethostbyname_r \
+ (const char *name, struct hostent *host, char *buffer, \
+ size_t buflen, int *errnop, int *h_errnop); \
+Index: git/inet/Makefile
+===================================================================
+--- git.orig/inet/Makefile 2014-08-29 20:00:47.176070587 -0700
++++ git/inet/Makefile 2014-08-29 20:01:15.200070587 -0700
+@@ -18,6 +18,8 @@
+ #
+ # Sub-makefile for inet portion of the library.
+ #
++include ../option-groups.mak
++
+ subdir := inet
+
+ include ../Makeconfig
+@@ -27,7 +29,8 @@
+ netinet/tcp.h netinet/ip.h $(wildcard arpa/*.h protocols/*.h) \
+ aliases.h ifaddrs.h netinet/ip6.h netinet/icmp6.h bits/in.h
+
+-routines := htonl htons \
++routines-$(OPTION_EGLIBC_INET) \
++ += htonl htons \
+ inet_lnaof inet_mkadr \
+ inet_netof inet_ntoa inet_net herrno herrno-loc \
+ gethstbyad gethstbyad_r gethstbynm gethstbynm2 gethstbynm2_r \
+@@ -41,18 +44,23 @@
+ getrpcent_r getrpcbyname_r getrpcbynumber_r \
+ ether_aton ether_aton_r ether_hton ether_line \
+ ether_ntoa ether_ntoa_r ether_ntoh \
+- rcmd rexec ruserpass \
+ getnetgrent_r getnetgrent \
+- getaliasent_r getaliasent getaliasname getaliasname_r \
+- in6_addr getnameinfo if_index ifaddrs inet6_option \
++ in6_addr getnameinfo if_index ifaddrs \
+ getipv4sourcefilter setipv4sourcefilter \
+- getsourcefilter setsourcefilter inet6_opt inet6_rth
++ getsourcefilter setsourcefilter
++routines-$(OPTION_EGLIBC_RCMD) \
++ += rcmd rexec ruserpass
++routines-$(OPTION_EGLIBC_DB_ALIASES) \
++ += getaliasent_r getaliasent getaliasname getaliasname_r
++routines-$(OPTION_EGLIBC_ADVANCED_INET6) \
++ += inet6_option inet6_opt inet6_rth
+
+-aux := check_pf check_native ifreq
++aux-$(OPTION_EGLIBC_INET) += check_pf check_native ifreq
+
+ tests := htontest test_ifindex tst-ntoa tst-ether_aton tst-network \
+- tst-gethnm test-ifaddrs bug-if1 test-inet6_opt tst-ether_line \
++ tst-gethnm test-ifaddrs bug-if1 tst-ether_line \
+ tst-getni1 tst-getni2 tst-inet6_rth tst-checks
++tests-$(OPTION_EGLIBC_ADVANCED_INET6) += test-inet6_opt
+
+ include ../Rules
+
+Index: git/intl/dcigettext.c
+===================================================================
+--- git.orig/intl/dcigettext.c
++++ git/intl/dcigettext.c
+@@ -100,11 +100,15 @@ extern int errno;
+ # include "libgnuintl.h"
+ #endif
+ #include "hash-string.h"
++#ifdef _LIBC
++# include <gnu/option-groups.h>
++#endif
+
+ /* Handle multi-threaded applications. */
+ #ifdef _LIBC
+ # include <bits/libc-lock.h>
+ # define gl_rwlock_define_initialized __libc_rwlock_define_initialized
++# define gl_rwlock_define __libc_rwlock_define
+ # define gl_rwlock_rdlock __libc_rwlock_rdlock
+ # define gl_rwlock_wrlock __libc_rwlock_wrlock
+ # define gl_rwlock_unlock __libc_rwlock_unlock
+@@ -523,8 +527,10 @@ DCIGETTEXT (const char *domainname, cons
+ saved_errno = errno;
+
+ #ifdef _LIBC
+- __libc_rwlock_define (extern, __libc_setlocale_lock attribute_hidden)
+- __libc_rwlock_rdlock (__libc_setlocale_lock);
++# if __OPTION_EGLIBC_LOCALE_CODE
++ gl_rwlock_define (extern, __libc_setlocale_lock attribute_hidden)
++ gl_rwlock_rdlock (__libc_setlocale_lock);
++# endif
+ #endif
+
+ gl_rwlock_rdlock (_nl_state_lock);
+@@ -550,7 +556,11 @@ DCIGETTEXT (const char *domainname, cons
+ #ifdef HAVE_PER_THREAD_LOCALE
+ # ifndef IN_LIBGLOCALE
+ # ifdef _LIBC
+- localename = strdupa (__current_locale_name (category));
++# if __OPTION_EGLIBC_LOCALE_CODE
++ localename = strdupa (__current_locale_name (category));
++# else
++ localename = "C";
++# endif
+ # else
+ categoryname = category_to_name (category);
+ # define CATEGORYNAME_INITIALIZED
+@@ -581,10 +591,12 @@ DCIGETTEXT (const char *domainname, cons
+ else
+ retval = (char *) (*foundp)->translation;
+
+- gl_rwlock_unlock (_nl_state_lock);
+ # ifdef _LIBC
+- __libc_rwlock_unlock (__libc_setlocale_lock);
++# if __OPTION_EGLIBC_LOCALE_CODE
++ gl_rwlock_unlock (__libc_setlocale_lock);
++# endif
+ # endif
++ gl_rwlock_unlock (_nl_state_lock);
+ __set_errno (saved_errno);
+ return retval;
+ }
+@@ -838,10 +850,13 @@ DCIGETTEXT (const char *domainname, cons
+ if (plural)
+ retval = plural_lookup (domain, n, retval, retlen);
+
+- gl_rwlock_unlock (_nl_state_lock);
+ #ifdef _LIBC
+- __libc_rwlock_unlock (__libc_setlocale_lock);
++# if __OPTION_EGLIBC_LOCALE_CODE
++
++ gl_rwlock_unlock (__libc_setlocale_lock);
++# endif
+ #endif
++ gl_rwlock_unlock (_nl_state_lock);
+ return retval;
+ }
+ }
+@@ -850,10 +865,12 @@ DCIGETTEXT (const char *domainname, cons
+ return_untranslated:
+ /* Return the untranslated MSGID. */
+ FREE_BLOCKS (block_list);
+- gl_rwlock_unlock (_nl_state_lock);
+ #ifdef _LIBC
+- __libc_rwlock_unlock (__libc_setlocale_lock);
++# if __OPTION_EGLIBC_LOCALE_CODE
++ gl_rwlock_unlock (__libc_setlocale_lock);
++# endif
+ #endif
++ gl_rwlock_unlock (_nl_state_lock);
+ #ifndef _LIBC
+ if (!ENABLE_SECURE)
+ {
+@@ -1550,7 +1567,11 @@ guess_category_value (int category, cons
+ `LC_xxx', and `LANG'. On some systems this can be done by the
+ `setlocale' function itself. */
+ # ifdef _LIBC
++# if __OPTION_EGLIBC_LOCALE_CODE
+ locale = __current_locale_name (category);
++# else
++ locale = "C";
++# endif
+ # else
+ locale_defaulted = 0;
+ # if HAVE_USELOCALE
+Index: git/intl/Makefile
+===================================================================
+--- git.orig/intl/Makefile 2014-08-29 20:00:47.220070587 -0700
++++ git/intl/Makefile 2014-08-29 20:01:15.200070587 -0700
+@@ -16,6 +16,7 @@
+ # <http://www.gnu.org/licenses/>.
+
+ # Makefile for intl subdirectory: message handling code from GNU gettext.
++include ../option-groups.mak
+
+ subdir = intl
+
+@@ -48,7 +49,7 @@
+ $(objpfx)plural.o: plural.c
+
+ ifeq ($(run-built-tests),yes)
+-ifeq (yes,$(build-shared))
++ifeq (yyyes,$(OPTION_EGLIBC_LOCALES)$(OPTION_EGLIBC_LOCALE_CODE)$(build-shared))
+ ifneq ($(strip $(MSGFMT)),:)
+ tests-special += $(objpfx)tst-translit.out $(objpfx)tst-gettext.out \
+ $(objpfx)tst-gettext2.out $(objpfx)tst-codeset.out \
+Index: git/io/Makefile
+===================================================================
+--- git.orig/io/Makefile 2014-08-29 20:00:47.244070587 -0700
++++ git/io/Makefile 2014-08-29 20:01:15.200070587 -0700
+@@ -18,6 +18,8 @@
+ #
+ # Sub-makefile for I/O portion of the library.
+ #
++include ../option-groups.mak
++
+ subdir := io
+
+ include ../Makeconfig
+@@ -36,7 +38,7 @@
+ fxstatat fxstatat64 \
+ statfs fstatfs statfs64 fstatfs64 \
+ statvfs fstatvfs statvfs64 fstatvfs64 \
+- umask chmod fchmod lchmod fchmodat \
++ umask chmod fchmod fchmodat \
+ mkdir mkdirat \
+ open open_2 open64 open64_2 openat openat_2 openat64 openat64_2 \
+ read write lseek lseek64 access euidaccess faccessat \
+@@ -49,11 +51,13 @@
+ ttyname ttyname_r isatty \
+ link linkat symlink symlinkat readlink readlinkat \
+ unlink unlinkat rmdir \
+- ftw ftw64 fts poll ppoll \
++ poll ppoll \
+ posix_fadvise posix_fadvise64 \
+ posix_fallocate posix_fallocate64 \
+ sendfile sendfile64 \
+ utimensat futimens
++routines-$(OPTION_EGLIBC_BSD) += lchmod
++routines-$(OPTION_EGLIBC_FTRAVERSE) += ftw ftw64 fts
+
+ aux := have_o_cloexec
+
+@@ -64,18 +68,22 @@
+ fstatat fstatat64 mknod mknodat
+
+ others := pwd
+-test-srcs := ftwtest
++test-srcs-$(OPTION_EGLIBC_FTRAVERSE) := ftwtest
+ tests := test-utime test-stat test-stat2 test-lfs tst-getcwd \
+- tst-fcntl bug-ftw1 bug-ftw2 bug-ftw3 bug-ftw4 tst-statvfs \
++ tst-fcntl tst-statvfs \
+ tst-openat tst-unlinkat tst-fstatat tst-futimesat \
+ tst-renameat tst-fchownat tst-fchmodat tst-faccessat \
+ tst-symlinkat tst-linkat tst-readlinkat tst-mkdirat \
+- tst-mknodat tst-mkfifoat tst-ttyname_r bug-ftw5 \
++ tst-mknodat tst-mkfifoat tst-ttyname_r \
+ tst-posix_fallocate
++tests-$(OPTION_EGLIBC_FTRAVERSE) += bug-ftw1 bug-ftw2 bug-ftw3 bug-ftw4 \
++ bug-ftw5
+
+ ifeq ($(run-built-tests),yes)
++ifeq (y,$(OPTION_EGLIBC_FTRAVERSE))
+ tests-special += $(objpfx)ftwtest.out
+ endif
++endif
+
+ include ../Rules
+
+Index: git/libidn/Makefile
+===================================================================
+--- git.orig/libidn/Makefile 2014-08-29 20:00:47.316070587 -0700
++++ git/libidn/Makefile 2014-08-29 20:01:15.200070587 -0700
+@@ -16,6 +16,7 @@
+ # <http://www.gnu.org/licenses/>.
+
+ # Makefile for libidn subdirectory of GNU C Library.
++include ../option-groups.mak
+
+ subdir := libidn
+
+@@ -23,8 +24,8 @@
+
+ routines = idn-stub
+
+-extra-libs = libcidn
+-extra-libs-others = $(extra-libs)
++extra-libs-$(OPTION_EGLIBC_IDN) = libcidn
++extra-libs-others-y = $(extra-libs-y)
+
+ libcidn-routines := punycode toutf8 nfkc stringprep rfc3454 profiles idna \
+ iconvme
+Index: git/libidn/toutf8.c
+===================================================================
+--- git.orig/libidn/toutf8.c 2014-08-29 20:00:47.332070587 -0700
++++ git/libidn/toutf8.c 2014-08-29 20:01:15.200070587 -0700
+@@ -33,6 +33,11 @@
+ /* Get strlen. */
+ #include <string.h>
+
++/* Get __OPTION_EGLIBC_LOCALE_CODE. */
++#ifdef _LIBC
++# include <gnu/option-groups.h>
++#endif
++
+ /* Get iconv_string. */
+ #include "iconvme.h"
+
+@@ -47,7 +52,11 @@
+ #endif
+
+ #ifdef _LIBC
+-# define stringprep_locale_charset() nl_langinfo (CODESET)
++# if __OPTION_EGLIBC_LOCALE_CODE
++# define stringprep_locale_charset() nl_langinfo (CODESET)
++# else
++# define stringprep_locale_charset() "ANSI_X3.4-1968"
++# endif
+ #else
+ /**
+ * stringprep_locale_charset - return charset used in current locale
+Index: git/libio/fileops.c
+===================================================================
+--- git.orig/libio/fileops.c 2014-08-29 20:00:47.352070587 -0700
++++ git/libio/fileops.c 2014-08-29 20:01:15.200070587 -0700
+@@ -38,6 +38,7 @@
+ #include <string.h>
+ #include <errno.h>
+ #include <unistd.h>
++#include <gnu/option-groups.h>
+ #include <stdlib.h>
+ #if _LIBC
+ # include "../wcsmbs/wcsmbsload.h"
+@@ -174,7 +175,7 @@
+
+ /* Free buffer. */
+ #if defined _LIBC || defined _GLIBCPP_USE_WCHAR_T
+- if (fp->_mode > 0)
++ if (_IO_is_wide (fp))
+ {
+ if (_IO_have_wbackup (fp))
+ _IO_free_wbackup_area (fp);
+@@ -359,6 +360,7 @@
+ cs = strstr (last_recognized + 1, ",ccs=");
+ if (cs != NULL)
+ {
++#if __OPTION_POSIX_WIDE_CHAR_DEVICE_IO
+ /* Yep. Load the appropriate conversions and set the orientation
+ to wide. */
+ struct gconv_fcts fcts;
+@@ -423,6 +425,12 @@
+
+ /* Set the mode now. */
+ result->_mode = 1;
++#else
++ /* Treat this as if we couldn't find the given character set. */
++ (void) _IO_file_close_it (fp);
++ __set_errno (EINVAL);
++ return NULL;
++#endif
+ }
+ }
+
+Index: git/libio/__fpurge.c
+===================================================================
+--- git.orig/libio/__fpurge.c 2014-08-29 20:00:47.336070587 -0700
++++ git/libio/__fpurge.c 2014-08-29 20:01:15.200070587 -0700
+@@ -21,7 +21,7 @@
+ void
+ __fpurge (FILE *fp)
+ {
+- if (fp->_mode > 0)
++ if (_IO_is_wide (fp))
+ {
+ /* Wide-char stream. */
+ if (_IO_in_backup (fp))
+Index: git/libio/iofwide.c
+===================================================================
+--- git.orig/libio/iofwide.c 2014-08-29 20:00:47.360070587 -0700
++++ git/libio/iofwide.c 2014-08-29 20:01:15.200070587 -0700
+@@ -26,6 +26,7 @@
+
+ #include <libioP.h>
+ #ifdef _LIBC
++# include <gnu/option-groups.h>
+ # include <dlfcn.h>
+ # include <wchar.h>
+ #endif
+@@ -43,6 +44,8 @@
+ #endif
+
+
++#if ! defined _LIBC || __OPTION_POSIX_C_LANG_WIDE_CHAR
++
+ /* Prototypes of libio's codecvt functions. */
+ static enum __codecvt_result do_out (struct _IO_codecvt *codecvt,
+ __mbstate_t *statep,
+@@ -513,3 +516,26 @@
+ return MB_CUR_MAX;
+ #endif
+ }
++
++#else
++/* OPTION_POSIX_C_LANG_WIDE_CHAR is disabled. */
++
++#undef _IO_fwide
++int
++_IO_fwide (fp, mode)
++ _IO_FILE *fp;
++ int mode;
++{
++ /* Die helpfully if the user tries to create a wide stream; I
++ disbelieve that most users check the return value from
++ 'fwide (fp, 1)'. */
++ assert (mode <= 0);
++
++ /* We can only make streams byte-oriented, which is trivial. */
++ if (mode < 0)
++ fp->_mode = -1;
++
++ return fp->_mode;
++}
++
++#endif
+Index: git/libio/ioseekoff.c
+===================================================================
+--- git.orig/libio/ioseekoff.c 2014-08-29 20:00:47.364070587 -0700
++++ git/libio/ioseekoff.c 2014-08-29 20:01:15.200070587 -0700
+@@ -60,7 +60,7 @@
+ else
+ abort ();
+ }
+- if (_IO_fwide (fp, 0) < 0)
++ if (! _IO_is_wide (fp))
+ _IO_free_backup_area (fp);
+ else
+ _IO_free_wbackup_area (fp);
+Index: git/libio/ioseekpos.c
+===================================================================
+--- git.orig/libio/ioseekpos.c 2014-08-29 20:00:47.364070587 -0700
++++ git/libio/ioseekpos.c 2014-08-29 20:01:15.200070587 -0700
+@@ -35,7 +35,7 @@
+ /* If we have a backup buffer, get rid of it, since the __seekoff
+ callback may not know to do the right thing about it.
+ This may be over-kill, but it'll do for now. TODO */
+- if (_IO_fwide (fp, 0) <= 0)
++ if (! _IO_is_wide (fp))
+ {
+ if (_IO_have_backup (fp))
+ _IO_free_backup_area (fp);
+Index: git/libio/iosetbuffer.c
+===================================================================
+--- git.orig/libio/iosetbuffer.c 2014-08-29 20:00:47.364070587 -0700
++++ git/libio/iosetbuffer.c 2014-08-29 20:01:15.204070587 -0700
+@@ -24,6 +24,8 @@
+ This exception applies to code released by its copyright holders
+ in files containing the exception. */
+
++#include <gnu/option-groups.h>
++
+ #include "libioP.h"
+
+ void
+@@ -38,9 +40,11 @@
+ if (!buf)
+ size = 0;
+ (void) _IO_SETBUF (fp, buf, size);
++#if __OPTION_POSIX_C_LANG_WIDE_CHAR
+ if (_IO_vtable_offset (fp) == 0 && fp->_mode == 0 && _IO_CHECK_WIDE (fp))
+ /* We also have to set the buffer using the wide char function. */
+ (void) _IO_WSETBUF (fp, buf, size);
++#endif /* __OPTION_POSIX_C_LANG_WIDE_CHAR */
+ _IO_release_lock (fp);
+ }
+ libc_hidden_def (_IO_setbuffer)
+Index: git/libio/libioP.h
+===================================================================
+--- git.orig/libio/libioP.h 2014-08-29 20:00:47.372070587 -0700
++++ git/libio/libioP.h 2014-08-29 20:01:15.204070587 -0700
+@@ -42,6 +42,10 @@
+ /*# include <comthread.h>*/
+ #endif
+
++#if defined _LIBC
++# include <gnu/option-groups.h>
++#endif
++
+ #include <math_ldbl_opt.h>
+
+ #include "iolibio.h"
+@@ -508,8 +512,20 @@
+
+
+ #if defined _LIBC || defined _GLIBCPP_USE_WCHAR_T
++
++/* _IO_is_wide (fp) is roughly equivalent to '_IO_fwide (fp, 0) > 0',
++ except that when OPTION_POSIX_C_LANG_WIDE_CHAR is disabled, it
++ expands to a constant, allowing the compiler to realize that it can
++ eliminate code that references wide stream handling functions.
++ This, in turn, allows us to omit them. */
++#if __OPTION_POSIX_C_LANG_WIDE_CHAR
++# define _IO_is_wide(_f) ((_f)->_mode > 0)
++#else
++# define _IO_is_wide(_f) (0)
++#endif
++
+ # define _IO_do_flush(_f) \
+- ((_f)->_mode <= 0 \
++ (! _IO_is_wide (_f) \
+ ? _IO_do_write(_f, (_f)->_IO_write_base, \
+ (_f)->_IO_write_ptr-(_f)->_IO_write_base) \
+ : _IO_wdo_write(_f, (_f)->_wide_data->_IO_write_base, \
+Index: git/libio/Makefile
+===================================================================
+--- git.orig/libio/Makefile 2014-08-29 20:00:47.332070587 -0700
++++ git/libio/Makefile 2014-08-29 20:01:15.204070587 -0700
+@@ -18,6 +18,8 @@
+ #
+ # Specific makefile for libio.
+ #
++include ../option-groups.mak
++
+ subdir := libio
+
+ include ../Makeconfig
+@@ -27,16 +29,13 @@
+
+ routines := \
+ filedoalloc iofclose iofdopen iofflush iofgetpos iofgets iofopen \
+- iofopncook iofputs iofread iofsetpos ioftell wfiledoalloc \
++ iofopncook iofputs iofread iofsetpos ioftell \
+ iofwrite iogetdelim iogetline iogets iopadn iopopen ioputs \
+ ioseekoff ioseekpos iosetbuffer iosetvbuf ioungetc \
+ iovsprintf iovsscanf \
+ iofgetpos64 iofopen64 iofsetpos64 \
+- fputwc fputwc_u getwc getwc_u getwchar getwchar_u iofgetws iofgetws_u \
+- iofputws iofputws_u iogetwline iowpadn ioungetwc putwc putwc_u \
+- putwchar putwchar_u putchar putchar_u fwprintf swprintf vwprintf \
+- wprintf wscanf fwscanf vwscanf vswprintf iovswscanf swscanf wgenops \
+- wstrops wfileops iofwide fwide wmemstream \
++ putchar putchar_u \
++ iofwide \
+ \
+ clearerr feof ferror fileno fputc freopen fseek getc getchar \
+ memstream pclose putc putchar rewind setbuf setlinebuf vasprintf \
+@@ -47,25 +46,48 @@
+ __fpurge __fpending __fsetlocking \
+ \
+ libc_fatal fmemopen
+-
+-tests = tst_swprintf tst_wprintf tst_swscanf tst_wscanf tst_getwc tst_putwc \
+- tst_wprintf2 tst-widetext test-fmemopen tst-ext tst-ext2 \
+- tst-fgetws tst-ungetwc1 tst-ungetwc2 tst-swscanf tst-sscanf \
+- tst-mmap-setvbuf bug-ungetwc1 bug-ungetwc2 tst-atime tst-eof \
+- tst-freopen bug-rewind bug-rewind2 bug-ungetc bug-fseek \
+- tst-mmap-eofsync tst-mmap-fflushsync bug-mmap-fflush \
+- tst-mmap2-eofsync tst-mmap-offend bug-fopena+ bug-wfflush \
+- bug-ungetc2 bug-ftell bug-ungetc3 bug-ungetc4 tst-fopenloc2 \
+- tst-memstream1 tst-memstream2 \
+- tst-wmemstream1 tst-wmemstream2 \
+- bug-memstream1 bug-wmemstream1 \
+- tst-setvbuf1 tst-popen1 tst-fgetwc bug-wsetpos tst-fseek \
+- tst-fwrite-error tst-ftell-partial-wide tst-ftell-active-handler \
+- tst-ftell-append
++routines-$(OPTION_POSIX_C_LANG_WIDE_CHAR) += \
++ wfiledoalloc \
++ iowpadn \
++ swprintf \
++ vswprintf iovswscanf swscanf wgenops \
++ wstrops wfileops wmemstream
++routines-$(call option-disabled, OPTION_POSIX_C_LANG_WIDE_CHAR) += \
++ wdummyfileops
++routines-$(OPTION_POSIX_WIDE_CHAR_DEVICE_IO) += \
++ fputwc fputwc_u getwc getwc_u getwchar getwchar_u iofgetws iofgetws_u \
++ iofputws iofputws_u iogetwline ioungetwc putwc putwc_u \
++ putwchar putwchar_u fwprintf vwprintf \
++ wprintf wscanf fwscanf vwscanf \
++ fwide
++
++tests = test-fmemopen tst-ext tst-ext2 \
++ tst-mmap-setvbuf tst-atime tst-eof \
++ tst-freopen bug-ungetc bug-fseek \
++ tst-mmap-eofsync tst-mmap-fflushsync bug-mmap-fflush \
++ tst-mmap2-eofsync tst-mmap-offend bug-fopena+ \
++ bug-ungetc2 bug-ungetc3 bug-ungetc4 \
++ tst-memstream1 tst-memstream2 \
++ bug-memstream1 tst-popen1 tst-fwrite-error \
++ tst-ftell-active-handler tst-ftell-append
++tests-$(OPTION_EGLIBC_LOCALE_CODE) \
++ += tst-swscanf tst-fgetws tst-setvbuf1 \
++ tst-ungetwc1 tst-ungetwc2 bug-ftell bug-ungetwc2 \
++ tst-widetext
++tests-$(OPTION_POSIX_WIDE_CHAR_DEVICE_IO) \
++ += bug-rewind bug-rewind2 bug-ungetwc1 \
++ bug-wfflush bug-wmemstream1 tst-fopenloc2 \
++ tst_getwc \
++ tst_putwc tst_wprintf tst_wprintf2 tst_wscanf \
++ tst-fgetwc bug-wsetpos tst-fseek tst-ftell-partial-wide
++tests-$(OPTION_POSIX_C_LANG_WIDE_CHAR) \
++ += tst_swprintf tst_swscanf \
++ tst-sscanf \
++ tst-wmemstream1 tst-wmemstream2
+ ifeq (yes,$(build-shared))
+ # Add test-fopenloc only if shared library is enabled since it depends on
+ # shared localedata objects.
+-tests += tst-fopenloc
++tests-$(OPTION_EGLIBC_LOCALE_CODE) += tst-fopenloc
+ endif
+ test-srcs = test-freopen
+
+@@ -164,13 +186,17 @@
+ oldiofsetpos64
+
+ ifeq ($(run-built-tests),yes)
++ifeq (y,$(OPTION_POSIX_WIDE_CHAR_DEVICE_IO))
+ tests-special += $(objpfx)test-freopen.out
++endif
++ifeq (y,$(OPTION_EGLIBC_LOCALE_CODE))
+ ifeq (yes,$(build-shared))
+ # Run tst-fopenloc-cmp.out and tst-openloc-mem.out only if shared
+ # library is enabled since they depend on tst-fopenloc.out.
+ tests-special += $(objpfx)tst-fopenloc-cmp.out $(objpfx)tst-fopenloc-mem.out
+ endif
+ endif
++endif
+
+ include ../Rules
+
+Index: git/libio/wdummyfileops.c
+===================================================================
+--- /dev/null 1970-01-01 00:00:00.000000000 +0000
++++ git/libio/wdummyfileops.c 2014-08-29 20:01:15.204070587 -0700
+@@ -0,0 +1,161 @@
++/* Copyright (C) 2007 Free Software Foundation, Inc.
++ This file is part of the GNU C Library.
++
++ The GNU C Library is free software; you can redistribute it and/or
++ modify it under the terms of the GNU Lesser General Public
++ License as published by the Free Software Foundation; either
++ version 2.1 of the License, or (at your option) any later version.
++
++ The GNU C Library is distributed in the hope that it will be useful,
++ but WITHOUT ANY WARRANTY; without even the implied warranty of
++ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
++ Lesser General Public License for more details.
++
++ You should have received a copy of the GNU Lesser General Public
++ License along with the GNU C Library; if not, write to the Free
++ Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
++ 02111-1307 USA.
++
++ As a special exception, if you link the code in this file with
++ files compiled with a GNU compiler to produce an executable,
++ that does not cause the resulting executable to be covered by
++ the GNU Lesser General Public License. This exception does not
++ however invalidate any other reasons why the executable file
++ might be covered by the GNU Lesser General Public License.
++ This exception applies to code released by its copyright holders
++ in files containing the exception. */
++
++#include <assert.h>
++#include <stdio.h>
++#include <stdlib.h>
++#include <libioP.h>
++
++static void __THROW __attribute__ ((__noreturn__))
++_IO_wfile_wide_char_support_disabled (void)
++{
++ static const char errstr[]
++ = ("The application tried to use wide character I/O, but libc.so"
++ " was compiled\n"
++ "with the OPTION_POSIX_C_LANG_WIDE_CHAR option group disabled.\n");
++ __libc_write (STDERR_FILENO, errstr, sizeof (errstr) - 1);
++ abort ();
++}
++
++static void
++_IO_wfile_disabled_void_int (_IO_FILE *fp, int x)
++{
++ _IO_wfile_wide_char_support_disabled ();
++}
++
++static int
++_IO_wfile_disabled_int_int (_IO_FILE *fp, int x)
++{
++ _IO_wfile_wide_char_support_disabled ();
++}
++
++static int
++_IO_wfile_disabled_int_none (_IO_FILE *fp)
++{
++ _IO_wfile_wide_char_support_disabled ();
++}
++
++static _IO_size_t
++_IO_wfile_disabled_xsputn (_IO_FILE *fp, const void *data, _IO_size_t n)
++{
++ _IO_wfile_wide_char_support_disabled ();
++}
++
++static _IO_size_t
++_IO_wfile_disabled_xsgetn (_IO_FILE *fp, void *data, _IO_size_t n)
++{
++ _IO_wfile_wide_char_support_disabled ();
++}
++
++static _IO_off64_t
++_IO_wfile_disabled_seekoff (_IO_FILE *fp, _IO_off64_t off, int dir, int mode)
++{
++ _IO_wfile_wide_char_support_disabled ();
++}
++
++static _IO_off64_t
++_IO_wfile_disabled_seekpos (_IO_FILE *fp, _IO_off64_t pos, int flags)
++{
++ _IO_wfile_wide_char_support_disabled ();
++}
++
++static _IO_FILE *
++_IO_wfile_disabled_setbuf (_IO_FILE *fp, char *buffer, _IO_ssize_t length)
++{
++ _IO_wfile_wide_char_support_disabled ();
++}
++
++static _IO_ssize_t
++_IO_wfile_disabled_read (_IO_FILE *fp, void *buffer, _IO_ssize_t length)
++{
++ _IO_wfile_wide_char_support_disabled ();
++}
++
++static _IO_ssize_t
++_IO_wfile_disabled_write (_IO_FILE *fp, const void *buffer, _IO_ssize_t length)
++{
++ _IO_wfile_wide_char_support_disabled ();
++}
++
++static _IO_off64_t
++_IO_wfile_disabled_seek (_IO_FILE *fp, _IO_off64_t offset, int mode)
++{
++ _IO_wfile_wide_char_support_disabled ();
++}
++
++static int
++_IO_wfile_disabled_close (_IO_FILE *fp)
++{
++ _IO_wfile_wide_char_support_disabled ();
++}
++
++static int
++_IO_wfile_disabled_stat (_IO_FILE *fp, void *buf)
++{
++ _IO_wfile_wide_char_support_disabled ();
++}
++
++static int
++_IO_wfile_disabled_showmanyc (_IO_FILE *fp)
++{
++ _IO_wfile_wide_char_support_disabled ();
++}
++
++static void
++_IO_wfile_disabled_imbue (_IO_FILE *fp, void *locale)
++{
++ _IO_wfile_wide_char_support_disabled ();
++}
++
++static const struct _IO_jump_t _IO_wfile_jumps_disabled =
++{
++ JUMP_INIT_DUMMY,
++ JUMP_INIT(finish, _IO_wfile_disabled_void_int),
++ JUMP_INIT(overflow, _IO_wfile_disabled_int_int),
++ JUMP_INIT(underflow, _IO_wfile_disabled_int_none),
++ JUMP_INIT(uflow, _IO_wfile_disabled_int_none),
++ JUMP_INIT(pbackfail, _IO_wfile_disabled_int_int),
++ JUMP_INIT(xsputn, _IO_wfile_disabled_xsputn),
++ JUMP_INIT(xsgetn, _IO_wfile_disabled_xsgetn),
++ JUMP_INIT(seekoff, _IO_wfile_disabled_seekoff),
++ JUMP_INIT(seekpos, _IO_wfile_disabled_seekpos),
++ JUMP_INIT(setbuf, _IO_wfile_disabled_setbuf),
++ JUMP_INIT(sync, _IO_wfile_disabled_int_none),
++ JUMP_INIT(doallocate, _IO_wfile_disabled_int_none),
++ JUMP_INIT(read, _IO_wfile_disabled_read),
++ JUMP_INIT(write, _IO_wfile_disabled_write),
++ JUMP_INIT(seek, _IO_wfile_disabled_seek),
++ JUMP_INIT(close, _IO_wfile_disabled_close),
++ JUMP_INIT(stat, _IO_wfile_disabled_stat),
++ JUMP_INIT(showmanyc, _IO_wfile_disabled_showmanyc),
++ JUMP_INIT(imbue, _IO_wfile_disabled_imbue)
++};
++
++strong_alias (_IO_wfile_jumps_disabled, _IO_wfile_jumps)
++libc_hidden_data_def (_IO_wfile_jumps)
++strong_alias (_IO_wfile_jumps_disabled, _IO_wfile_jumps_mmap)
++strong_alias (_IO_wfile_jumps_disabled, _IO_wfile_jumps_maybe_mmap)
+Index: git/locale/catnames.c
+===================================================================
+--- /dev/null 1970-01-01 00:00:00.000000000 +0000
++++ git/locale/catnames.c 2014-08-29 20:01:15.204070587 -0700
+@@ -0,0 +1,48 @@
++/* Copyright (C) 2006 Free Software Foundation, Inc.
++ This file is part of the GNU C Library.
++
++ The GNU C Library is free software; you can redistribute it and/or
++ modify it under the terms of the GNU Lesser General Public
++ License as published by the Free Software Foundation; either
++ version 2.1 of the License, or (at your option) any later version.
++
++ The GNU C Library is distributed in the hope that it will be useful,
++ but WITHOUT ANY WARRANTY; without even the implied warranty of
++ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
++ Lesser General Public License for more details.
++
++ You should have received a copy of the GNU Lesser General Public
++ License along with the GNU C Library; if not, write to the Free
++ Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
++ 02111-1307 USA. */
++
++#include "localeinfo.h"
++
++/* Define an array of category names (also the environment variable names). */
++const union catnamestr_t _nl_category_names attribute_hidden =
++ {
++ {
++#define DEFINE_CATEGORY(category, category_name, items, a) \
++ category_name,
++#include "categories.def"
++#undef DEFINE_CATEGORY
++ }
++ };
++
++const uint8_t _nl_category_name_idxs[__LC_LAST] attribute_hidden =
++ {
++#define DEFINE_CATEGORY(category, category_name, items, a) \
++ [category] = offsetof (union catnamestr_t, CATNAMEMF (__LINE__)),
++#include "categories.def"
++#undef DEFINE_CATEGORY
++ };
++
++/* An array of their lengths, for convenience. */
++const uint8_t _nl_category_name_sizes[] attribute_hidden =
++ {
++#define DEFINE_CATEGORY(category, category_name, items, a) \
++ [category] = sizeof (category_name) - 1,
++#include "categories.def"
++#undef DEFINE_CATEGORY
++ [LC_ALL] = sizeof ("LC_ALL") - 1
++ };
+Index: git/locale/C-ctype.c
+===================================================================
+--- git.orig/locale/C-ctype.c 2014-08-29 20:00:47.396070587 -0700
++++ git/locale/C-ctype.c 2014-08-29 20:01:15.204070587 -0700
+@@ -19,8 +19,11 @@
+ #include "localeinfo.h"
+ #include <endian.h>
+ #include <stdint.h>
++#include <gnu/option-groups.h>
+
++#if __OPTION_EGLIBC_LOCALE_CODE
+ #include "C-translit.h"
++#endif
+
+ /* This table's entries are taken from POSIX.2 Table 2-6
+ ``LC_CTYPE Category Definition in the POSIX Locale''.
+@@ -647,6 +650,7 @@
+ { .word = L'7' },
+ { .word = L'8' },
+ { .word = L'9' },
++#if __OPTION_EGLIBC_LOCALE_CODE
+ /* _NL_CTYPE_TRANSLIT_TAB_SIZE */
+ { .word = NTRANSLIT },
+ /* _NL_CTYPE_TRANSLIT_FROM_IDX */
+@@ -657,6 +661,22 @@
+ { .wstr = translit_to_idx },
+ /* _NL_CTYPE_TRANSLIT_TO_TBL */
+ { .wstr = (uint32_t *) translit_to_tbl },
++#else
++ /* If the locale code isn't enabled, we don't have the
++ transliteration code in iconv/gconv_trans.c anyway, so there's
++ no need for the transliteration tables here. We'll fall back
++ on the default missing replacement, '?'. */
++ /* _NL_CTYPE_TRANSLIT_TAB_SIZE */
++ { .word = 0 },
++ /* _NL_CTYPE_TRANSLIT_FROM_IDX */
++ { .wstr = NULL },
++ /* _NL_CTYPE_TRANSLIT_FROM_TBL */
++ { .wstr = NULL },
++ /* _NL_CTYPE_TRANSLIT_TO_IDX */
++ { .wstr = NULL },
++ /* _NL_CTYPE_TRANSLIT_TO_TBL */
++ { .wstr = NULL },
++#endif
+ /* _NL_CTYPE_TRANSLIT_DEFAULT_MISSING_LEN */
+ { .word = 1 },
+ /* _NL_CTYPE_TRANSLIT_DEFAULT_MISSING */
+Index: git/locale/dummy-setlocale.c
+===================================================================
+--- /dev/null 1970-01-01 00:00:00.000000000 +0000
++++ git/locale/dummy-setlocale.c 2014-08-29 20:01:15.204070587 -0700
+@@ -0,0 +1,33 @@
++/* Copyright (C) 2006 Free Software Foundation, Inc.
++ This file is part of the GNU C Library.
++
++ The GNU C Library is free software; you can redistribute it and/or
++ modify it under the terms of the GNU Lesser General Public
++ License as published by the Free Software Foundation; either
++ version 2.1 of the License, or (at your option) any later version.
++
++ The GNU C Library is distributed in the hope that it will be useful,
++ but WITHOUT ANY WARRANTY; without even the implied warranty of
++ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
++ Lesser General Public License for more details.
++
++ You should have received a copy of the GNU Lesser General Public
++ License along with the GNU C Library; if not, write to the Free
++ Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
++ 02111-1307 USA. */
++
++#include <string.h>
++#include <locale.h>
++
++char *
++setlocale (int category, const char *locale)
++{
++ if (! locale
++ || locale[0] == '\0'
++ || strcmp (locale, "C") == 0
++ || strcmp (locale, "POSIX") == 0)
++ return (char *) "C";
++ else
++ return NULL;
++}
++libc_hidden_def (setlocale)
+Index: git/locale/localeinfo.h
+===================================================================
+--- git.orig/locale/localeinfo.h 2014-08-29 20:00:47.404070587 -0700
++++ git/locale/localeinfo.h 2014-08-29 20:01:15.204070587 -0700
+@@ -224,7 +224,7 @@
+ unused. We can manage this playing some tricks with weak references.
+ But with thread-local locale settings, it becomes quite ungainly unless
+ we can use __thread variables. So only in that case do we attempt this. */
+-#ifndef SHARED
++#if !defined SHARED && !defined IN_GLIBC_LOCALEDEF
+ # include <tls.h>
+ # define NL_CURRENT_INDIRECT 1
+ #endif
+Index: git/locale/Makefile
+===================================================================
+--- git.orig/locale/Makefile 2014-08-29 20:00:47.400070587 -0700
++++ git/locale/Makefile 2014-08-29 20:01:15.204070587 -0700
+@@ -18,27 +18,43 @@
+ #
+ # Makefile for locales.
+ #
++include ../option-groups.mak
++
+ subdir := locale
+
+ include ../Makeconfig
+
+ headers = locale.h bits/locale.h langinfo.h xlocale.h
+-routines = setlocale findlocale loadlocale loadarchive \
+- localeconv nl_langinfo nl_langinfo_l mb_cur_max \
+- newlocale duplocale freelocale uselocale
+-tests = tst-C-locale tst-locname tst-duplocale
++# catnames is needed by OPTION_EGLIBC_LOCALE_CODE and by the 'intl' code.
++# If we put the latter in an option group, too, we can omit catnames
++# when both option groups are disabled. libstdc++-v3 needs mb_cur_max.
++routines-y := catnames mb_cur_max
++routines-$(OPTION_EGLIBC_LOCALE_CODE) \
++ += setlocale findlocale loadlocale loadarchive \
++ localeconv nl_langinfo nl_langinfo_l \
++ newlocale duplocale freelocale uselocale
++ifneq (y,$(OPTION_EGLIBC_LOCALE_CODE))
++routines-y += dummy-setlocale
++endif
++tests-$(OPTION_EGLIBC_LOCALE_CODE) += tst-C-locale tst-locname tst-duplocale
+ categories = ctype messages monetary numeric time paper name \
+ address telephone measurement identification collate
+-aux = $(categories:%=lc-%) $(categories:%=C-%) SYS_libc C_name \
+- xlocale localename global-locale coll-lookup
+-others = localedef locale
++# C-messages belongs in an intl option group.
++aux-y := C-ctype C-time \
++ SYS_libc C_name xlocale global-locale coll-lookup
++aux-$(OPTION_EGLIBC_LOCALE_CODE) \
++ += $(filter-out $(aux-y), \
++ $(categories:%=lc-%) $(categories:%=C-%)) \
++ localename
++others-$(OPTION_EGLIBC_LOCALE_CODE) = localedef locale
+ #others-static = localedef locale
+-install-bin = localedef locale
+-extra-objs = $(localedef-modules:=.o) $(localedef-aux:=.o) \
++install-bin = $(others-y)
++extra-objs-$(OPTION_EGLIBC_LOCALE_CODE) \
++ = $(localedef-modules:=.o) $(localedef-aux:=.o) \
+ $(locale-modules:=.o) $(lib-modules:=.o)
+
+-extra-libs = libBrokenLocale
+-extra-libs-others = $(extra-libs)
++extra-libs-$(OPTION_EGLIBC_LOCALE_CODE) = libBrokenLocale
++extra-libs-others = $(extra-libs-y)
+
+ libBrokenLocale-routines = broken_cur_max
+
+@@ -94,6 +110,9 @@
+ CFLAGS-charmap.c = -Wno-write-strings -Wno-char-subscripts
+ CFLAGS-locfile.c = -Wno-write-strings -Wno-char-subscripts
+ CFLAGS-charmap-dir.c = -Wno-write-strings
++ifneq (y,$(OPTION_EGLIBC_SPAWN))
++CFLAGS-charmap-dir.c += -DNO_UNCOMPRESS
++endif
+
+ # This makes sure -DNOT_IN_libc et al are passed for all these modules.
+ cpp-srcs-left := $(addsuffix .c,$(localedef-modules) $(localedef-aux) \
+Index: git/locale/programs/charmap-dir.c
+===================================================================
+--- git.orig/locale/programs/charmap-dir.c 2014-08-29 20:00:47.408070587 -0700
++++ git/locale/programs/charmap-dir.c 2014-08-29 20:01:15.204070587 -0700
+@@ -19,7 +19,9 @@
+ #include <error.h>
+ #include <fcntl.h>
+ #include <libintl.h>
++#ifndef NO_UNCOMPRESS
+ #include <spawn.h>
++#endif
+ #include <stdio.h>
+ #include <stdlib.h>
+ #include <string.h>
+@@ -156,6 +158,7 @@
+ return closedir (dir);
+ }
+
++#ifndef NO_UNCOMPRESS
+ /* Creates a subprocess decompressing the given pathname, and returns
+ a stream reading its output (the decompressed data). */
+ static
+@@ -204,6 +207,7 @@
+ }
+ return NULL;
+ }
++#endif
+
+ /* Opens a charmap for reading, given its name (not an alias name). */
+ FILE *
+@@ -226,6 +230,7 @@
+ if (stream != NULL)
+ return stream;
+
++#ifndef NO_UNCOMPRESS
+ memcpy (p, ".gz", 4);
+ stream = fopen_uncompressed (pathname, "gzip");
+ if (stream != NULL)
+@@ -235,6 +240,7 @@
+ stream = fopen_uncompressed (pathname, "bzip2");
+ if (stream != NULL)
+ return stream;
++#endif
+
+ return NULL;
+ }
+@@ -263,8 +269,8 @@
+ char *alias = NULL;
+ char junk[BUFSIZ];
+
+- if (fscanf (stream, " <code_set_name> %ms", &alias) == 1
+- || fscanf (stream, "%% alias %ms", &alias) == 1)
++ if (fscanf (stream, " <code_set_name> %as", &alias) == 1
++ || fscanf (stream, "%% alias %as", &alias) == 1)
+ {
+ aliases = (char **) xrealloc (aliases,
+ (naliases + 2) * sizeof (char *));
+Index: git/locale/programs/ld-collate.c
+===================================================================
+--- git.orig/locale/programs/ld-collate.c 2014-08-29 20:00:47.408070587 -0700
++++ git/locale/programs/ld-collate.c 2014-08-29 20:01:15.208070587 -0700
+@@ -350,7 +350,7 @@
+ }
+ if (wcs != NULL)
+ {
+- size_t nwcs = wcslen ((wchar_t *) wcs);
++ size_t nwcs = wcslen_uint32 (wcs);
+ uint32_t zero = 0;
+ /* Handle <U0000> as a single character. */
+ if (nwcs == 0)
+@@ -1776,8 +1776,7 @@
+
+ if ((*eptr)->nwcs == runp->nwcs)
+ {
+- int c = wmemcmp ((wchar_t *) (*eptr)->wcs,
+- (wchar_t *) runp->wcs, runp->nwcs);
++ int c = wmemcmp_uint32 ((*eptr)->wcs, runp->wcs, runp->nwcs);
+
+ if (c == 0)
+ {
+@@ -2010,9 +2009,9 @@
+ one consecutive entry. */
+ if (runp->wcnext != NULL
+ && runp->nwcs == runp->wcnext->nwcs
+- && wmemcmp ((wchar_t *) runp->wcs,
+- (wchar_t *)runp->wcnext->wcs,
+- runp->nwcs - 1) == 0
++ && wmemcmp_uint32 (runp->wcs,
++ runp->wcnext->wcs,
++ runp->nwcs - 1) == 0
+ && (runp->wcs[runp->nwcs - 1]
+ == runp->wcnext->wcs[runp->nwcs - 1] + 1))
+ {
+@@ -2036,9 +2035,9 @@
+ runp = runp->wcnext;
+ while (runp->wcnext != NULL
+ && runp->nwcs == runp->wcnext->nwcs
+- && wmemcmp ((wchar_t *) runp->wcs,
+- (wchar_t *)runp->wcnext->wcs,
+- runp->nwcs - 1) == 0
++ && wmemcmp_uint32 (runp->wcs,
++ runp->wcnext->wcs,
++ runp->nwcs - 1) == 0
+ && (runp->wcs[runp->nwcs - 1]
+ == runp->wcnext->wcs[runp->nwcs - 1] + 1));
+
+Index: git/locale/programs/ld-ctype.c
+===================================================================
+--- git.orig/locale/programs/ld-ctype.c 2014-08-29 20:00:47.408070587 -0700
++++ git/locale/programs/ld-ctype.c 2014-08-29 20:01:15.208070587 -0700
+@@ -957,7 +957,7 @@
+ allocate_arrays (ctype, charmap, ctype->repertoire);
+
+ default_missing_len = (ctype->default_missing
+- ? wcslen ((wchar_t *) ctype->default_missing)
++ ? wcslen_uint32 (ctype->default_missing)
+ : 0);
+
+ init_locale_data (&file, nelems);
+@@ -1968,7 +1968,7 @@
+ ignore = 1;
+ else
+ /* This value is usable. */
+- obstack_grow (ob, to_wstr, wcslen ((wchar_t *) to_wstr) * 4);
++ obstack_grow (ob, to_wstr, wcslen_uint32 (to_wstr) * 4);
+
+ first = 0;
+ }
+@@ -2516,8 +2516,8 @@
+ }
+
+ handle_tok_digit:
+- class_bit = _ISwdigit;
+- class256_bit = _ISdigit;
++ class_bit = BITw (tok_digit);
++ class256_bit = BIT (tok_digit);
+ handle_digits = 1;
+ goto read_charclass;
+
+@@ -4001,8 +4001,7 @@
+
+ while (idx < number)
+ {
+- int res = wcscmp ((const wchar_t *) sorted[idx]->from,
+- (const wchar_t *) runp->from);
++ int res = wcscmp_uint32 (sorted[idx]->from, runp->from);
+ if (res == 0)
+ {
+ replace = 1;
+@@ -4039,11 +4038,11 @@
+ for (cnt = 0; cnt < number; ++cnt)
+ {
+ struct translit_to_t *srunp;
+- from_len += wcslen ((const wchar_t *) sorted[cnt]->from) + 1;
++ from_len += wcslen_uint32 (sorted[cnt]->from) + 1;
+ srunp = sorted[cnt]->to;
+ while (srunp != NULL)
+ {
+- to_len += wcslen ((const wchar_t *) srunp->str) + 1;
++ to_len += wcslen_uint32 (srunp->str) + 1;
+ srunp = srunp->next;
+ }
+ /* Plus one for the extra NUL character marking the end of
+@@ -4067,18 +4066,18 @@
+ ctype->translit_from_idx[cnt] = from_len;
+ ctype->translit_to_idx[cnt] = to_len;
+
+- len = wcslen ((const wchar_t *) sorted[cnt]->from) + 1;
+- wmemcpy ((wchar_t *) &ctype->translit_from_tbl[from_len],
+- (const wchar_t *) sorted[cnt]->from, len);
++ len = wcslen_uint32 (sorted[cnt]->from) + 1;
++ wmemcpy_uint32 (&ctype->translit_from_tbl[from_len],
++ sorted[cnt]->from, len);
+ from_len += len;
+
+ ctype->translit_to_idx[cnt] = to_len;
+ srunp = sorted[cnt]->to;
+ while (srunp != NULL)
+ {
+- len = wcslen ((const wchar_t *) srunp->str) + 1;
+- wmemcpy ((wchar_t *) &ctype->translit_to_tbl[to_len],
+- (const wchar_t *) srunp->str, len);
++ len = wcslen_uint32 (srunp->str) + 1;
++ wmemcpy_uint32 (&ctype->translit_to_tbl[to_len],
++ srunp->str, len);
+ to_len += len;
+ srunp = srunp->next;
+ }
+Index: git/locale/programs/ld-messages.c
+===================================================================
+--- git.orig/locale/programs/ld-messages.c 2014-08-29 20:00:47.412070587 -0700
++++ git/locale/programs/ld-messages.c 2014-08-29 20:01:15.208070587 -0700
+@@ -25,6 +25,7 @@
+ #include <string.h>
+ #include <stdint.h>
+ #include <sys/uio.h>
++#include <gnu/option-groups.h>
+
+ #include <assert.h>
+
+@@ -124,6 +125,7 @@
+ }
+ else
+ {
++#if __OPTION_POSIX_REGEXP
+ int result;
+ regex_t re;
+
+@@ -140,6 +142,7 @@
+ }
+ else if (result != 0)
+ regfree (&re);
++#endif
+ }
+
+ if (messages->noexpr == NULL)
+@@ -158,6 +161,7 @@
+ }
+ else
+ {
++#if __OPTION_POSIX_REGEXP
+ int result;
+ regex_t re;
+
+@@ -174,6 +178,7 @@
+ }
+ else if (result != 0)
+ regfree (&re);
++#endif
+ }
+ }
+
+Index: git/locale/programs/ld-time.c
+===================================================================
+--- git.orig/locale/programs/ld-time.c 2014-08-29 20:00:47.412070587 -0700
++++ git/locale/programs/ld-time.c 2014-08-29 20:01:15.208070587 -0700
+@@ -215,8 +215,10 @@
+ }
+ else
+ {
++ static const uint32_t wt_fmt_ampm[]
++ = { '%','I',':','%','M',':','%','S',' ','%','p',0 };
+ time->t_fmt_ampm = "%I:%M:%S %p";
+- time->wt_fmt_ampm = (const uint32_t *) L"%I:%M:%S %p";
++ time->wt_fmt_ampm = wt_fmt_ampm;
+ }
+ }
+
+@@ -226,7 +228,7 @@
+ const int days_per_month[12] = { 31, 29, 31, 30, 31, 30,
+ 31, 31, 30, 31 ,30, 31 };
+ size_t idx;
+- wchar_t *wstr;
++ uint32_t *wstr;
+
+ time->era_entries =
+ (struct era_data *) xmalloc (time->num_era
+@@ -464,18 +466,18 @@
+ }
+
+ /* Now generate the wide character name and format. */
+- wstr = wcschr ((wchar_t *) time->wera[idx], L':');/* end direction */
+- wstr = wstr ? wcschr (wstr + 1, L':') : NULL; /* end offset */
+- wstr = wstr ? wcschr (wstr + 1, L':') : NULL; /* end start */
+- wstr = wstr ? wcschr (wstr + 1, L':') : NULL; /* end end */
++ wstr = wcschr_uint32 (time->wera[idx], L':'); /* end direction */
++ wstr = wstr ? wcschr_uint32 (wstr + 1, L':') : NULL; /* end offset */
++ wstr = wstr ? wcschr_uint32 (wstr + 1, L':') : NULL; /* end start */
++ wstr = wstr ? wcschr_uint32 (wstr + 1, L':') : NULL; /* end end */
+ if (wstr != NULL)
+ {
+- time->era_entries[idx].wname = (uint32_t *) wstr + 1;
+- wstr = wcschr (wstr + 1, L':'); /* end name */
++ time->era_entries[idx].wname = wstr + 1;
++ wstr = wcschr_uint32 (wstr + 1, L':'); /* end name */
+ if (wstr != NULL)
+ {
+ *wstr = L'\0';
+- time->era_entries[idx].wformat = (uint32_t *) wstr + 1;
++ time->era_entries[idx].wformat = wstr + 1;
+ }
+ else
+ time->era_entries[idx].wname =
+@@ -530,7 +532,16 @@
+ if (time->date_fmt == NULL)
+ time->date_fmt = "%a %b %e %H:%M:%S %Z %Y";
+ if (time->wdate_fmt == NULL)
+- time->wdate_fmt = (const uint32_t *) L"%a %b %e %H:%M:%S %Z %Y";
++ {
++ static const uint32_t wdate_fmt[] =
++ { '%','a',' ',
++ '%','b',' ',
++ '%','e',' ',
++ '%','H',':','%','M',':','%','S',' ',
++ '%','Z',' ',
++ '%','Y',0 };
++ time->wdate_fmt = wdate_fmt;
++ }
+ }
+
+
+Index: git/locale/programs/linereader.c
+===================================================================
+--- git.orig/locale/programs/linereader.c 2014-08-29 20:00:47.412070587 -0700
++++ git/locale/programs/linereader.c 2014-08-29 20:01:15.208070587 -0700
+@@ -595,7 +595,7 @@
+ {
+ int return_widestr = lr->return_widestr;
+ char *buf;
+- wchar_t *buf2 = NULL;
++ uint32_t *buf2 = NULL;
+ size_t bufact;
+ size_t bufmax = 56;
+
+Index: git/locale/programs/localedef.c
+===================================================================
+--- git.orig/locale/programs/localedef.c 2014-08-29 20:00:47.416070587 -0700
++++ git/locale/programs/localedef.c 2014-08-29 20:01:15.208070587 -0700
+@@ -114,6 +114,7 @@
+ #define OPT_LIST_ARCHIVE 309
+ #define OPT_LITTLE_ENDIAN 400
+ #define OPT_BIG_ENDIAN 401
++#define OPT_UINT32_ALIGN 402
+
+ /* Definitions of arguments for argp functions. */
+ static const struct argp_option options[] =
+@@ -150,6 +151,8 @@
+ N_("Generate little-endian output") },
+ { "big-endian", OPT_BIG_ENDIAN, NULL, 0,
+ N_("Generate big-endian output") },
++ { "uint32-align", OPT_UINT32_ALIGN, "ALIGNMENT", 0,
++ N_("Set the target's uint32_t alignment in bytes (default 4)") },
+ { NULL, 0, NULL, 0, NULL }
+ };
+
+@@ -239,12 +242,14 @@
+ ctype locale. (P1003.2 4.35.5.2) */
+ setlocale (LC_CTYPE, "POSIX");
+
++#ifndef NO_SYSCONF
+ /* Look whether the system really allows locale definitions. POSIX
+ defines error code 3 for this situation so I think it must be
+ a fatal error (see P1003.2 4.35.8). */
+ if (sysconf (_SC_2_LOCALEDEF) < 0)
+ WITH_CUR_LOCALE (error (3, 0, _("\
+ FATAL: system does not define `_POSIX2_LOCALEDEF'")));
++#endif
+
+ /* Process charmap file. */
+ charmap = charmap_read (charmap_file, verbose, 1, be_quiet, 1);
+@@ -338,6 +343,9 @@
+ case OPT_BIG_ENDIAN:
+ set_big_endian (true);
+ break;
++ case OPT_UINT32_ALIGN:
++ uint32_align_mask = strtol (arg, NULL, 0) - 1;
++ break;
+ case 'c':
+ force_output = 1;
+ break;
+Index: git/locale/programs/locfile.c
+===================================================================
+--- git.orig/locale/programs/locfile.c 2014-08-29 20:00:47.432070587 -0700
++++ git/locale/programs/locfile.c 2014-08-29 20:01:15.208070587 -0700
+@@ -544,6 +544,9 @@
+ machine running localedef. */
+ bool swap_endianness_p;
+
++/* The target's value of __align__(uint32_t) - 1. */
++unsigned int uint32_align_mask = 3;
++
+ /* When called outside a start_locale_structure/end_locale_structure
+ or start_locale_prelude/end_locale_prelude block, record that the
+ next byte in FILE's obstack will be the first byte of a new element.
+@@ -621,7 +624,7 @@
+ void
+ add_locale_wstring (struct locale_file *file, const uint32_t *string)
+ {
+- add_locale_uint32_array (file, string, wcslen ((const wchar_t *) string) + 1);
++ add_locale_uint32_array (file, string, wcslen_uint32 (string) + 1);
+ }
+
+ /* Record that FILE's next element is the 32-bit integer VALUE. */
+Index: git/locale/programs/locfile.h
+===================================================================
+--- git.orig/locale/programs/locfile.h 2014-08-29 20:00:47.432070587 -0700
++++ git/locale/programs/locfile.h 2014-08-29 20:01:15.208070587 -0700
+@@ -71,6 +71,8 @@
+
+ extern bool swap_endianness_p;
+
++extern unsigned int uint32_align_mask;
++
+ /* Change the output to be big-endian if BIG_ENDIAN is true and
+ little-endian otherwise. */
+ static inline void
+@@ -275,4 +277,49 @@
+ const struct charmap_t *charmap,
+ const char *output_path);
+
++static inline size_t
++wcslen_uint32 (const uint32_t *str)
++{
++ size_t len = 0;
++ while (str[len] != 0)
++ len++;
++ return len;
++}
++
++static inline int
++wmemcmp_uint32 (const uint32_t *s1, const uint32_t *s2, size_t n)
++{
++ while (n-- != 0)
++ {
++ int diff = *s1++ - *s2++;
++ if (diff != 0)
++ return diff;
++ }
++ return 0;
++}
++
++static inline int
++wcscmp_uint32 (const uint32_t *s1, const uint32_t *s2)
++{
++ while (*s1 != 0 && *s1 == *s2)
++ s1++, s2++;
++ return *s1 - *s2;
++}
++
++static inline uint32_t *
++wmemcpy_uint32 (uint32_t *s1, const uint32_t *s2, size_t n)
++{
++ return memcpy (s1, s2, n * sizeof (uint32_t));
++}
++
++static inline uint32_t *
++wcschr_uint32 (const uint32_t *s, uint32_t ch)
++{
++ do
++ if (*s == ch)
++ return (uint32_t *) s;
++ while (*s++ != 0);
++ return 0;
++}
++
+ #endif /* locfile.h */
+Index: git/locale/setlocale.c
+===================================================================
+--- git.orig/locale/setlocale.c 2014-08-29 20:00:47.432070587 -0700
++++ git/locale/setlocale.c 2014-08-29 20:01:15.208070587 -0700
+@@ -64,36 +64,6 @@
+ #endif
+
+
+-/* Define an array of category names (also the environment variable names). */
+-const union catnamestr_t _nl_category_names attribute_hidden =
+- {
+- {
+-#define DEFINE_CATEGORY(category, category_name, items, a) \
+- category_name,
+-#include "categories.def"
+-#undef DEFINE_CATEGORY
+- }
+- };
+-
+-const uint8_t _nl_category_name_idxs[__LC_LAST] attribute_hidden =
+- {
+-#define DEFINE_CATEGORY(category, category_name, items, a) \
+- [category] = offsetof (union catnamestr_t, CATNAMEMF (__LINE__)),
+-#include "categories.def"
+-#undef DEFINE_CATEGORY
+- };
+-
+-/* An array of their lengths, for convenience. */
+-const uint8_t _nl_category_name_sizes[] attribute_hidden =
+- {
+-#define DEFINE_CATEGORY(category, category_name, items, a) \
+- [category] = sizeof (category_name) - 1,
+-#include "categories.def"
+-#undef DEFINE_CATEGORY
+- [LC_ALL] = sizeof ("LC_ALL") - 1
+- };
+-
+-
+ #ifdef NL_CURRENT_INDIRECT
+ # define WEAK_POSTLOAD(postload) weak_extern (postload)
+ #else
+Index: git/locale/xlocale.c
+===================================================================
+--- git.orig/locale/xlocale.c 2014-08-29 20:00:47.436070587 -0700
++++ git/locale/xlocale.c 2014-08-29 20:01:15.208070587 -0700
+@@ -18,6 +18,7 @@
+ <http://www.gnu.org/licenses/>. */
+
+ #include <locale.h>
++#include <gnu/option-groups.h>
+ #include "localeinfo.h"
+
+ #define DEFINE_CATEGORY(category, category_name, items, a) \
+@@ -25,6 +26,19 @@
+ #include "categories.def"
+ #undef DEFINE_CATEGORY
+
++/* If the locale support code isn't enabled, don't generate strong
++ reference to the C locale_data structures here; let the Makefile
++ decide which ones to include. (In the static linking case, the
++ strong reference to the 'class', 'toupper', and 'tolower' tables
++ will cause C-ctype.o to be brought in, as it should be, even when
++ the reference to _nl_C_LC_CTYPE will be weak.) */
++#if ! __OPTION_EGLIBC_LOCALE_CODE
++# define DEFINE_CATEGORY(category, category_name, items, a) \
++ weak_extern (_nl_C_##category)
++# include "categories.def"
++# undef DEFINE_CATEGORY
++#endif
++
+ /* Defined in locale/C-ctype.c. */
+ extern const char _nl_C_LC_CTYPE_class[] attribute_hidden;
+ extern const char _nl_C_LC_CTYPE_toupper[] attribute_hidden;
+@@ -52,3 +66,26 @@
+ .__ctype_tolower = (const int *) _nl_C_LC_CTYPE_tolower + 128,
+ .__ctype_toupper = (const int *) _nl_C_LC_CTYPE_toupper + 128
+ };
++
++
++#if ! __OPTION_EGLIBC_LOCALE_CODE
++/* When locale code is enabled, these are each defined in the
++ appropriate lc-CATEGORY.c file, so that static links (when __thread
++ is supported) bring in only those lc-CATEGORY.o files for
++ categories the program actually uses; look for NL_CURRENT_INDIRECT
++ in localeinfo.h.
++
++ When locale code is disabled, the _nl_C_CATEGORY objects are the
++ only possible referents. At the moment, there isn't a way to get
++ __OPTION_EGLIBC_LOCALE_CODE defined in every compilation unit that
++ #includes localeinfo.h, so we can't just turn off
++ NL_CURRENT_INDIRECT. So we'll define the _nl_current_CATEGORY
++ pointers here. */
++#if defined (NL_CURRENT_INDIRECT)
++#define DEFINE_CATEGORY(category, category_name, items, a) \
++ __thread struct __locale_data * const *_nl_current_##category \
++ attribute_hidden = &_nl_C_locobj.__locales[category];
++#include "categories.def"
++#undef DEFINE_CATEGORY
++#endif
++#endif /* __OPTION_EGLIBC_LOCALE_CODE */
+Index: git/localedata/Makefile
+===================================================================
+--- git.orig/localedata/Makefile 2014-08-29 20:00:47.444070587 -0700
++++ git/localedata/Makefile 2014-08-29 20:01:15.212070587 -0700
+@@ -21,12 +21,22 @@
+
+ include ../Makeconfig
+
+-# List with all available character set descriptions.
+-charmaps := $(wildcard charmaps/[A-I]*) $(wildcard charmaps/[J-Z]*)
++include ../option-groups.mak
+
+ # List with all available character set descriptions.
+-locales := $(wildcard locales/*)
++all-charmaps := $(wildcard charmaps/[A-I]*) $(wildcard charmaps/[J-Z]*)
++
++all-locales := $(wildcard locales/*)
+
++# If the EGLIBC_LOCALES option group is not enabled, trim the
++# list of charmap and locale source files.
++ifeq ($(OPTION_EGLIBC_LOCALES),y)
++charmaps := $(all-charmaps)
++locales := $(all-locales)
++else
++charmaps :=
++locales := locales/POSIX
++endif
+
+ subdir-dirs = tests-mbwc
+ vpath %.c tests-mbwc
+@@ -71,14 +81,20 @@
+ tst_wcsxfrm tst_wctob tst_wctomb tst_wctrans \
+ tst_wctype tst_wcwidth
+
+-tests = $(locale_test_suite) tst-digits tst-setlocale bug-iconv-trans \
++# Since these tests build their own locale files, they're not
++# dependent on the OPTION_EGLIBC_LOCALES option group. But they do
++# need the locale functions to be present.
++tests-$(OPTION_EGLIBC_LOCALE_CODE) \
++ += $(locale_test_suite) tst-digits tst-setlocale bug-iconv-trans \
+ tst-leaks tst-mbswcs1 tst-mbswcs2 tst-mbswcs3 tst-mbswcs4 tst-mbswcs5 \
+ tst-mbswcs6 tst-xlocale1 tst-xlocale2 bug-usesetlocale \
+ tst-strfmon1 tst-sscanf bug-setlocale1 tst-setlocale2 tst-setlocale3 \
+ tst-wctype
++ifeq (y,$(OPTION_EGLIBC_LOCALE_CODE))
+ tests-static = bug-setlocale1-static
+ tests += $(tests-static)
+-ifeq (yes,$(build-shared))
++endif
++ifeq (yesy,$(build-shared)$(OPTION_EGLIBC_LOCALE_CODE))
+ ifneq (no,$(PERL))
+ tests-special += $(objpfx)mtrace-tst-leaks.out
+ endif
+@@ -92,12 +108,14 @@
+
+ tests: $(objdir)/iconvdata/gconv-modules
+
++ifeq (y,$(OPTION_EGLIBC_LOCALE_CODE))
+ tests-special += $(objpfx)sort-test.out $(objpfx)tst-fmon.out \
+ $(objpfx)tst-locale.out $(objpfx)tst-rpmatch.out \
+ $(objpfx)tst-trans.out $(objpfx)tst-ctype.out \
+ $(objpfx)tst-langinfo.out $(objpfx)tst-langinfo-static.out \
+ $(objpfx)tst-numeric.out
+ tests-static += tst-langinfo-static
++endif
+
+ ifeq ($(run-built-tests),yes)
+ # We have to generate locales
+@@ -213,6 +231,11 @@
+
+ include SUPPORTED
+
++# Only install locale data if OPTION_EGLIBC_LOCALES is selected.
++ifneq ($(OPTION_EGLIBC_LOCALES),y)
++SUPPORTED-LOCALES :=
++endif
++
+ INSTALL-SUPPORTED-LOCALES=$(addprefix install-, $(SUPPORTED-LOCALES))
+
+ # Sometimes the whole collection of locale files should be installed.
+Index: git/login/Makefile
+===================================================================
+--- git.orig/login/Makefile 2014-08-29 20:00:47.736070587 -0700
++++ git/login/Makefile 2014-08-29 20:01:15.212070587 -0700
+@@ -18,6 +18,7 @@
+ #
+ # Sub-makefile for login portion of the library.
+ #
++include ../option-groups.mak
+
+ subdir := login
+
+@@ -25,14 +26,16 @@
+
+ headers := utmp.h bits/utmp.h lastlog.h pty.h
+
+-routines := getlogin getlogin_r setlogin getlogin_r_chk \
+- getutent getutent_r getutid getutline getutid_r getutline_r \
+- utmp_file utmpname updwtmp getpt grantpt unlockpt ptsname \
+- ptsname_r_chk
++routines := getpt grantpt unlockpt ptsname ptsname_r_chk
++routines-$(OPTION_EGLIBC_UTMP) \
++ += getutent getutent_r getutid getutline getutid_r getutline_r \
++ utmp_file utmpname updwtmp
++routines-$(OPTION_EGLIBC_GETLOGIN) += getlogin getlogin_r getlogin_r_chk
++routines-$(OPTION_EGLIBC_BSD) += setlogin
+
+ CFLAGS-grantpt.c = -DLIBEXECDIR='"$(libexecdir)"'
+
+-others = utmpdump
++others-$(OPTION_EGLIBC_UTMP) += utmpdump
+
+ ifeq (yes,$(build-pt-chown))
+ others += pt_chown
+@@ -46,8 +49,8 @@
+ tests := tst-utmp tst-utmpx tst-grantpt tst-ptsname
+
+ # Build the -lutil library with these extra functions.
+-extra-libs := libutil
+-extra-libs-others := $(extra-libs)
++extra-libs-$(OPTION_EGLIBC_UTMP) := libutil
++extra-libs-others := $(extra-libs-y)
+
+ libutil-routines:= login login_tty logout logwtmp openpty forkpty
+
+Index: git/Makeconfig
+===================================================================
+--- git.orig/Makeconfig 2014-08-29 20:00:42.956070587 -0700
++++ git/Makeconfig 2014-08-29 20:01:15.212070587 -0700
+@@ -582,7 +582,7 @@
+ # and run on the build system, causes that program with those
+ # arguments to be run on the host for which the library is built.
+ ifndef test-wrapper
+-test-wrapper =
++test-wrapper = $(cross-test-wrapper)
+ endif
+ # Likewise, but the name of the program is preceded by
+ # <variable>=<value> assignments for environment variables.
+@@ -1057,6 +1057,24 @@
+ libm = $(common-objpfx)math/libm.a
+ endif
+
++# Generate a header file that #defines preprocessor symbols indicating
++# which option groups are enabled. Note that the option-groups.config file
++# may not exist at all.
++before-compile += $(common-objpfx)gnu/option-groups.h
++common-generated += gnu/option-groups.h gnu/option-groups.stmp
++headers += gnu/option-groups.h
++$(common-objpfx)gnu/option-groups.h: $(common-objpfx)gnu/option-groups.stmp; @:
++$(common-objpfx)gnu/option-groups.stmp: \
++ $(..)scripts/option-groups.awk \
++ $(..)option-groups.defaults \
++ $(wildcard $(common-objpfx)option-groups.config)
++ $(make-target-directory)
++ @rm -f ${@:stmp=T} $@
++ LC_ALL=C $(AWK) -f $^ > ${@:stmp=T}
++ $(move-if-change) ${@:stmp=T} ${@:stmp=h}
++ touch $@
++
++
+ # These are the subdirectories containing the library source. The order
+ # is more or less arbitrary. The sorting step will take care of the
+ # dependencies.
+Index: git/Makerules
+===================================================================
+--- git.orig/Makerules 2014-08-29 20:00:42.960070587 -0700
++++ git/Makerules 2014-08-29 20:01:15.212070587 -0700
+@@ -379,6 +379,25 @@
+ endef
+ endif
+
++# Include targets in the selected option groups.
++aux += $(aux-y)
++extra-libs += $(extra-libs-y)
++extra-libs-others += $(extra-libs-others-y)
++extra-objs += $(extra-objs-y)
++install-bin += $(install-bin-y)
++install-others += $(install-others-y)
++install-sbin += $(install-sbin-y)
++modules += $(modules-y)
++others += $(others-y)
++others-pie += $(others-pie-y)
++routines += $(routines-y)
++static-only-routines += $(static-only-routines-y)
++sysdep_routines += $(sysdep_routines-y)
++test-srcs += $(test-srcs-y)
++tests += $(tests-y)
++xtests += $(xtests-y)
++
++
+ # Modify the list of routines we build for different targets
+
+ ifeq (yes,$(build-shared))
+Index: git/malloc/Makefile
+===================================================================
+--- git.orig/malloc/Makefile 2014-08-29 20:00:47.760070587 -0700
++++ git/malloc/Makefile 2014-08-29 20:01:15.212070587 -0700
+@@ -18,6 +18,8 @@
+ #
+ # Makefile for malloc routines
+ #
++include ../option-groups.mak
++
+ subdir := malloc
+
+ include ../Makeconfig
+@@ -36,9 +38,15 @@
+ non-lib.a := libmcheck.a
+
+ # Additional library.
++ifeq ($(OPTION_EGLIBC_MEMUSAGE),y)
+ extra-libs = libmemusage
+ extra-libs-others = $(extra-libs)
+
++ifdef OPTION_EGLIBC_MEMUSAGE_DEFAULT_BUFFER_SIZE
++CPPFLAGS-memusage += -D__OPTION_EGLIBC_MEMUSAGE_DEFAULT_BUFFER_SIZE=$(OPTION_EGLIBC_MEMUSAGE_DEFAULT_BUFFER_SIZE)
++endif
++endif
++
+ libmemusage-routines = memusage
+ libmemusage-inhibit-o = $(filter-out .os,$(object-suffixes))
+
+@@ -67,7 +75,7 @@
+ # Unless we get a test for the availability of libgd which also works
+ # for cross-compiling we disable the memusagestat generation in this
+ # situation.
+-ifneq ($(cross-compiling),yes)
++ifeq ($(cross-compiling)$(OPTION_EGLIBC_MEMUSAGE),noy)
+ # If the gd library is available we build the `memusagestat' program.
+ ifneq ($(LIBGD),no)
+ others: $(objpfx)memusage
+Index: git/malloc/memusage.c
+===================================================================
+--- git.orig/malloc/memusage.c 2014-08-29 20:00:47.768070587 -0700
++++ git/malloc/memusage.c 2014-08-29 20:01:15.212070587 -0700
+@@ -33,6 +33,7 @@
+ #include <stdint.h>
+ #include <sys/mman.h>
+ #include <sys/time.h>
++#include <gnu/option-groups.h>
+
+ #include <memusage.h>
+
+@@ -93,7 +94,11 @@
+ #define peak_stack peak_use[1]
+ #define peak_total peak_use[2]
+
+-#define DEFAULT_BUFFER_SIZE 32768
++#ifndef __OPTION_EGLIBC_MEMUSAGE_DEFAULT_BUFFER_SIZE
++# define DEFAULT_BUFFER_SIZE 32768
++#else
++# define DEFAULT_BUFFER_SIZE __OPTION_EGLIBC_MEMUSAGE_DEFAULT_BUFFER_SIZE
++#endif
+ static size_t buffer_size;
+
+ static int fd = -1;
+Index: git/malloc/memusage.sh
+===================================================================
+--- git.orig/malloc/memusage.sh 2014-08-29 20:00:47.768070587 -0700
++++ git/malloc/memusage.sh 2014-08-29 20:01:15.212070587 -0700
+@@ -35,7 +35,7 @@
+
+ # Print help message
+ do_help() {
+- echo $"Usage: memusage [OPTION]... PROGRAM [PROGRAMOPTION]...
++ printf $"Usage: memusage [OPTION]... PROGRAM [PROGRAMOPTION]...
+ Profile memory usage of PROGRAM.
+
+ -n,--progname=NAME Name of the program file to profile
+Index: git/math/Makefile
+===================================================================
+--- git.orig/math/Makefile 2014-08-29 20:00:47.836070587 -0700
++++ git/math/Makefile 2014-08-29 20:01:15.212070587 -0700
+@@ -21,6 +21,8 @@
+
+ include ../Makeconfig
+
++include ../option-groups.mak
++
+ # Installed header files.
+ headers := math.h bits/mathcalls.h bits/mathinline.h bits/huge_val.h \
+ bits/huge_valf.h bits/huge_vall.h bits/inf.h bits/nan.h \
+@@ -33,8 +35,8 @@
+
+ # Build the -lm library.
+
+-extra-libs := libm
+-extra-libs-others = $(extra-libs)
++extra-libs-$(OPTION_EGLIBC_LIBM) := libm
++extra-libs-others-$(OPTION_EGLIBC_LIBM) = $(extra-libs-$(OPTION_EGLIBC_LIBM))
+
+ libm-support = k_standard s_lib_version s_matherr s_signgam \
+ fclrexcpt fgetexcptflg fraiseexcpt fsetexcptflg \
+Index: git/misc/err.c
+===================================================================
+--- git.orig/misc/err.c 2014-08-29 20:00:48.232070587 -0700
++++ git/misc/err.c 2014-08-29 20:01:15.212070587 -0700
+@@ -22,6 +22,7 @@
+ #include <errno.h>
+ #include <string.h>
+ #include <stdio.h>
++#include <gnu/option-groups.h>
+
+ #include <wchar.h>
+ #define flockfile(s) _IO_flockfile (s)
+@@ -37,6 +38,7 @@
+ va_end (ap); \
+ }
+
++#if __OPTION_POSIX_WIDE_CHAR_DEVICE_IO
+ static void
+ convert_and_print (const char *format, __gnuc_va_list ap)
+ {
+@@ -81,6 +83,7 @@
+
+ __vfwprintf (stderr, wformat, ap);
+ }
++#endif
+
+ void
+ vwarnx (const char *format, __gnuc_va_list ap)
+@@ -88,9 +91,13 @@
+ flockfile (stderr);
+ if (_IO_fwide (stderr, 0) > 0)
+ {
++#if __OPTION_POSIX_WIDE_CHAR_DEVICE_IO
+ __fwprintf (stderr, L"%s: ", __progname);
+ convert_and_print (format, ap);
+ putwc_unlocked (L'\n', stderr);
++#else
++ abort ();
++#endif
+ }
+ else
+ {
+@@ -111,6 +118,7 @@
+ flockfile (stderr);
+ if (_IO_fwide (stderr, 0) > 0)
+ {
++#if __OPTION_POSIX_WIDE_CHAR_DEVICE_IO
+ __fwprintf (stderr, L"%s: ", __progname);
+ if (format)
+ {
+@@ -119,6 +127,9 @@
+ }
+ __set_errno (error);
+ __fwprintf (stderr, L"%m\n");
++#else
++ abort ();
++#endif
+ }
+ else
+ {
+Index: git/misc/error.c
+===================================================================
+--- git.orig/misc/error.c 2014-08-29 20:00:48.232070587 -0700
++++ git/misc/error.c 2014-08-29 20:01:15.212070587 -0700
+@@ -35,6 +35,7 @@
+ #endif
+
+ #ifdef _LIBC
++# include <gnu/option-groups.h>
+ # include <libintl.h>
+ # include <stdbool.h>
+ # include <stdint.h>
+@@ -205,6 +206,7 @@
+ #if _LIBC
+ if (_IO_fwide (stderr, 0) > 0)
+ {
++#if __OPTION_POSIX_WIDE_CHAR_DEVICE_IO
+ size_t len = strlen (message) + 1;
+ wchar_t *wmessage = NULL;
+ mbstate_t st;
+@@ -265,6 +267,9 @@
+
+ if (use_malloc)
+ free (wmessage);
++#else
++ abort ();
++#endif
+ }
+ else
+ #endif
+Index: git/misc/Makefile
+===================================================================
+--- git.orig/misc/Makefile 2014-08-29 20:00:48.232070587 -0700
++++ git/misc/Makefile 2014-08-29 20:01:15.212070587 -0700
+@@ -19,6 +19,10 @@
+ # Sub-makefile for misc portion of the library.
+ #
+
++# Some system-dependent implementations of these functions use option
++# groups (see sysdeps/unix/sysv/linux/Makefile, for example).
++include ../option-groups.mak
++
+ subdir := misc
+
+ include ../Makeconfig
+@@ -46,40 +50,47 @@
+ select pselect \
+ acct chroot fsync sync fdatasync syncfs reboot \
+ gethostid sethostid \
+- revoke vhangup \
++ vhangup \
+ swapon swapoff mktemp mkstemp mkstemp64 mkdtemp \
+ mkostemp mkostemp64 mkstemps mkstemps64 mkostemps mkostemps64 \
+ ualarm usleep \
+ gtty stty \
+ ptrace \
+- fstab mntent mntent_r \
++ mntent mntent_r \
+ utimes lutimes futimes futimesat \
+ truncate ftruncate truncate64 ftruncate64 \
+- chflags fchflags \
+ insremque getttyent getusershell getpass ttyslot \
+ syslog syscall daemon \
+ mmap mmap64 munmap mprotect msync madvise mincore remap_file_pages\
+ mlock munlock mlockall munlockall \
+- efgcvt efgcvt_r qefgcvt qefgcvt_r \
+ hsearch hsearch_r tsearch lsearch \
+ err error ustat \
+- getsysstats dirname regexp \
++ getsysstats dirname \
+ getloadavg getclktck \
+ fgetxattr flistxattr fremovexattr fsetxattr getxattr \
+ listxattr lgetxattr llistxattr lremovexattr lsetxattr \
+ removexattr setxattr getauxval ifunc-impl-list
+
++routines-$(OPTION_POSIX_REGEXP) += regexp
++routines-$(OPTION_EGLIBC_FSTAB) += fstab
++routines-$(OPTION_EGLIBC_BSD) += chflags fchflags revoke
++routines-$(OPTION_EGLIBC_FCVT) += efgcvt efgcvt_r qefgcvt qefgcvt_r
++
+ generated += tst-error1.mtrace tst-error1-mem.out
+
+ aux := init-misc
+ install-lib := libg.a
+ gpl2lgpl := error.c error.h
+
+-tests := tst-dirname tst-tsearch tst-fdset tst-efgcvt tst-mntent tst-hsearch \
+- tst-error1 tst-pselect tst-insremque tst-mntent2 bug-hsearch1
++tests := tst-dirname tst-tsearch tst-fdset tst-mntent tst-hsearch \
++ tst-pselect tst-insremque tst-mntent2 bug-hsearch1
++tests-$(OPTION_POSIX_WIDE_CHAR_DEVICE_IO) += tst-error1
++tests-$(OPTION_EGLIBC_FCVT) += tst-efgcvt
+ ifeq ($(run-built-tests),yes)
++ifeq (y,$(OPTION_POSIX_WIDE_CHAR_DEVICE_IO))
+ tests-special += $(objpfx)tst-error1-mem.out
+ endif
++endif
+
+ CFLAGS-select.c = -fexceptions -fasynchronous-unwind-tables
+ CFLAGS-tsearch.c = $(uses-callbacks)
+Index: git/misc/tst-efgcvt.c
+===================================================================
+--- git.orig/misc/tst-efgcvt.c 2014-08-29 20:00:52.652070587 -0700
++++ git/misc/tst-efgcvt.c 2014-08-29 20:01:15.216070587 -0700
+@@ -59,7 +59,7 @@
+ { 123.01, -4, 3, "" },
+ { 126.71, -4, 3, "" },
+ { 0.0, 4, 1, "0000" },
+-#if DBL_MANT_DIG == 53
++#if DBL_MANT_DIG == 53 && !(defined __powerpc__ && defined __NO_FPRS__ && !defined _SOFT_FLOAT && !defined _SOFT_DOUBLE)
+ { 0x1p-1074, 3, -323, "494" },
+ { -0x1p-1074, 3, -323, "494" },
+ #endif
+Index: git/nis/Makefile
+===================================================================
+--- git.orig/nis/Makefile 2014-08-29 20:00:52.660070587 -0700
++++ git/nis/Makefile 2014-08-29 20:01:15.216070587 -0700
+@@ -18,6 +18,8 @@
+ #
+ # Makefile for NIS/NIS+ part.
+ #
++include ../option-groups.mak
++
+ subdir := nis
+
+ include ../Makeconfig
+@@ -30,19 +32,26 @@
+
+ # These are the databases available for the nis (and perhaps later nisplus)
+ # service. This must be a superset of the services in nss.
+-databases = proto service hosts network grp pwd rpc ethers \
+- spwd netgrp alias publickey
++databases-y := proto service hosts network grp pwd rpc ethers \
++ spwd netgrp publickey
++databases-$(OPTION_EGLIBC_DB_ALIASES) += alias
+
+ # Specify rules for the nss_* modules.
+-services := nis nisplus compat
++# The 'compat' module includes nis support, and the 'nss' directory
++# includes a bare-bones "files" library, so we'll include 'compat' in
++# OPTION_EGLIBC_NIS.
++services-y :=
++services-$(OPTION_EGLIBC_NIS) += nis nisplus compat
++
++extra-libs-$(OPTION_EGLIBC_NIS) += libnsl
++extra-libs-y += $(services-y:%=libnss_%)
+
+-extra-libs = libnsl $(services:%=libnss_%)
+ # These libraries will be built in the `others' pass rather than
+ # the `lib' pass, because they depend on libc.so being built already.
+-extra-libs-others = $(extra-libs)
++extra-libs-others-y += $(extra-libs-y)
+
+ # The sources are found in the appropriate subdir.
+-subdir-dirs = $(services:%=nss_%)
++subdir-dirs = $(services-y:%=nss_%)
+ vpath %.c $(subdir-dirs)
+
+ libnsl-routines = yp_xdr ypclnt ypupdate_xdr \
+@@ -60,11 +69,11 @@
+ libnss_compat-routines := $(addprefix compat-,grp pwd spwd initgroups)
+ libnss_compat-inhibit-o = $(filter-out .os,$(object-suffixes))
+
+-libnss_nis-routines := $(addprefix nis-,$(databases)) nis-initgroups \
++libnss_nis-routines := $(addprefix nis-,$(databases-y)) nis-initgroups \
+ nss-nis
+ libnss_nis-inhibit-o = $(filter-out .os,$(object-suffixes))
+
+-libnss_nisplus-routines := $(addprefix nisplus-,$(databases)) nisplus-parser \
++libnss_nisplus-routines := $(addprefix nisplus-,$(databases-y)) nisplus-parser \
+ nss-nisplus nisplus-initgroups
+ libnss_nisplus-inhibit-o = $(filter-out .os,$(object-suffixes))
+
+@@ -80,12 +89,12 @@
+ # Target-specific variable setting to link objects using deprecated
+ # RPC interfaces with the version of libc.so that makes them available
+ # for new links:
+-$(services:%=$(objpfx)libnss_%.so) $(objpfx)libnsl.so: \
++$(services-y:%=$(objpfx)libnss_%.so) $(objpfx)libnsl.so: \
+ libc-for-link = $(libnsl-libc)
+
+
+ ifeq ($(build-shared),yes)
+-$(others:%=$(objpfx)%): $(objpfx)libnsl.so$(libnsl.so-version)
++$(others-y:%=$(objpfx)%): $(objpfx)libnsl.so$(libnsl.so-version)
+ else
+-$(others:%=$(objpfx)%): $(objpfx)libnsl.a
++$(others-y:%=$(objpfx)%): $(objpfx)libnsl.a
+ endif
+Index: git/nptl/Makefile
+===================================================================
+--- git.orig/nptl/Makefile 2014-08-29 20:00:52.704070587 -0700
++++ git/nptl/Makefile 2014-08-29 20:01:15.216070587 -0700
+@@ -18,6 +18,8 @@
+ #
+ # Sub-makefile for NPTL portion of the library.
+ #
++include ../option-groups.mak
++
+ subdir := nptl
+
+ include ../Makeconfig
+@@ -116,7 +118,7 @@
+ pt-raise pt-system \
+ flockfile ftrylockfile funlockfile \
+ sigaction \
+- herrno res pt-allocrtsig \
++ pt-allocrtsig \
+ pthread_kill_other_threads \
+ pthread_getaffinity pthread_setaffinity \
+ pthread_attr_getaffinity pthread_attr_setaffinity \
+@@ -136,6 +138,8 @@
+ # pthread_setgid pthread_setegid pthread_setregid \
+ # pthread_setresgid
+
++libpthread-routines-$(OPTION_EGLIBC_INET) := herrno res
++
+ libpthread-shared-only-routines = version pt-allocrtsig unwind-forcedunwind
+ libpthread-static-only-routines = pthread_atfork
+
+@@ -210,7 +214,7 @@
+ tst-mutexpi1 tst-mutexpi2 tst-mutexpi3 tst-mutexpi4 tst-mutexpi5 \
+ tst-mutexpi5a tst-mutexpi6 tst-mutexpi7 tst-mutexpi7a tst-mutexpi8 \
+ tst-mutexpi9 \
+- tst-spin1 tst-spin2 tst-spin3 tst-spin4 \
++ tst-spin1 tst-spin2 tst-spin3 \
+ tst-cond1 tst-cond2 tst-cond3 tst-cond4 tst-cond5 tst-cond6 tst-cond7 \
+ tst-cond8 tst-cond9 tst-cond10 tst-cond11 tst-cond12 tst-cond13 \
+ tst-cond14 tst-cond15 tst-cond16 tst-cond17 tst-cond18 tst-cond19 \
+@@ -244,14 +248,14 @@
+ tst-cancel6 tst-cancel7 tst-cancel8 tst-cancel9 tst-cancel10 \
+ tst-cancel11 tst-cancel12 tst-cancel13 tst-cancel14 tst-cancel15 \
+ tst-cancel16 tst-cancel17 tst-cancel18 tst-cancel19 tst-cancel20 \
+- tst-cancel21 tst-cancel22 tst-cancel23 tst-cancel24 tst-cancel25 \
++ tst-cancel21 tst-cancel22 tst-cancel23 tst-cancel25 \
+ tst-cancel-self tst-cancel-self-cancelstate \
+ tst-cancel-self-canceltype tst-cancel-self-testcancel \
+ tst-cleanup0 tst-cleanup1 tst-cleanup2 tst-cleanup3 tst-cleanup4 \
+ tst-flock1 tst-flock2 \
+ tst-signal1 tst-signal2 tst-signal3 tst-signal4 tst-signal5 \
+ tst-signal6 tst-signal7 \
+- tst-exec1 tst-exec2 tst-exec3 tst-exec4 \
++ tst-exec2 tst-exec3 tst-exec4 \
+ tst-exit1 tst-exit2 tst-exit3 \
+ tst-stdio1 tst-stdio2 \
+ tst-stack1 tst-stack2 tst-stack3 tst-pthread-getattr \
+@@ -259,13 +263,12 @@
+ tst-unload \
+ tst-dlsym1 \
+ tst-sysconf \
+- tst-locale1 tst-locale2 \
++ tst-locale2 \
+ tst-umask1 \
+ tst-popen1 \
+ tst-clock1 \
+ tst-context1 \
+ tst-sched1 \
+- tst-backtrace1 \
+ tst-abstime \
+ tst-vfork1 tst-vfork2 tst-vfork1x tst-vfork2x \
+ tst-getpid1 tst-getpid2 tst-getpid3 \
+@@ -275,6 +278,17 @@
+ tst-mutexpp1 tst-mutexpp6 tst-mutexpp10
+ test-srcs = tst-oddstacklimit
+
++# This test uses the posix_spawn functions.
++tests-$(OPTION_EGLIBC_SPAWN) += tst-exec1
++
++# This test uses the 'backtrace' functions.
++tests-$(OPTION_EGLIBC_BACKTRACE) += tst-backtrace1
++
++# This test is written in C++.
++tests-$(OPTION_EGLIBC_CXX_TESTS) += tst-cancel24
++
++tests-$(OPTION_EGLIBC_LOCALE_CODE) += tst-locale1
++
+ # Files which must not be linked with libpthread.
+ tests-nolibpthread = tst-unload
+
+Index: git/nptl/pthread_create.c
+===================================================================
+--- git.orig/nptl/pthread_create.c 2014-08-29 20:00:52.764070587 -0700
++++ git/nptl/pthread_create.c 2014-08-29 20:01:15.216070587 -0700
+@@ -31,6 +31,7 @@
+ #include <kernel-features.h>
+ #include <exit-thread.h>
+
++#include <gnu/option-groups.h>
+ #include <shlib-compat.h>
+
+ #include <stap-probe.h>
+@@ -240,8 +241,10 @@
+ THREAD_SETMEM (pd, cpuclock_offset, now);
+ #endif
+
++#if __OPTION_EGLIBC_INET
+ /* Initialize resolver state pointer. */
+ __resp = &pd->res;
++#endif
+
+ /* Initialize pointers to locale data. */
+ __ctype_init ();
+@@ -322,8 +325,10 @@
+ /* Run the destructor for the thread-local data. */
+ __nptl_deallocate_tsd ();
+
++#if __OPTION_EGLIBC_INET
+ /* Clean up any state libc stored in thread-local variables. */
+ __libc_thread_freeres ();
++#endif
+
+ /* If this is the last thread we terminate the process now. We
+ do not notify the debugger, it might just irritate it if there
+Index: git/nscd/Makefile
+===================================================================
+--- git.orig/nscd/Makefile 2014-08-29 20:00:52.948070587 -0700
++++ git/nscd/Makefile 2014-08-29 20:01:15.216070587 -0700
+@@ -18,14 +18,17 @@
+ #
+ # Sub-makefile for nscd portion of the library.
+ #
++include ../option-groups.mak
++
+ subdir := nscd
+
+ include ../Makeconfig
+
+ ifneq ($(use-nscd),no)
+-routines := nscd_getpw_r nscd_getgr_r nscd_gethst_r nscd_getai \
++routines-$(OPTION_EGLIBC_INET) += \
++ nscd_getpw_r nscd_getgr_r nscd_gethst_r nscd_getai \
+ nscd_initgroups nscd_getserv_r nscd_netgroup
+-aux := nscd_helper
++aux-$(OPTION_EGLIBC_INET) += nscd_helper
+ endif
+
+ # To find xmalloc.c
+@@ -37,14 +40,18 @@
+ dbg_log nscd_conf nscd_stat cache mem nscd_setup_thread \
+ xmalloc xstrdup aicache initgrcache gai res_hconf \
+ netgroupcache
+-
++ifneq (y,$(OPTION_EGLIBC_NIS))
++# If we haven't build libnsl.so, then we'll need to include our
++# own copy of nis_hash.
++nscd-modules += nis_hash
++endif
+ ifeq ($(build-nscd)$(have-thread-library),yesyes)
+
+-others += nscd
+-others-pie += nscd
+-install-sbin := nscd
++others-$(OPTION_EGLIBC_INET) += nscd
++others-pie-$(OPTION_EGLIBC_INET) += nscd
++install-sbin-$(OPTION_EGLIBC_INET) += nscd
+
+-extra-objs = $(nscd-modules:=.o)
++extra-objs-$(OPTION_EGLIBC_INET) += $(nscd-modules:=.o)
+
+ endif
+
+@@ -101,7 +108,15 @@
+ $(objpfx)nscd: $(nscd-modules:%=$(objpfx)%.o)
+
+ ifeq ($(build-shared),yes)
+-$(objpfx)nscd: $(shared-thread-library) $(common-objpfx)nis/libnsl.so
++$(objpfx)nscd: $(shared-thread-library)
++else
++$(objpfx)nscd: $(static-thread-library)
++endif
++
++ifeq (y,$(OPTION_EGLIBC_NIS))
++ifeq ($(build-shared),yes)
++$(objpfx)nscd: $(common-objpfx)nis/libnsl.so
+ else
+-$(objpfx)nscd: $(static-thread-library) $(common-objpfx)nis/libnsl.a
++$(objpfx)nscd: $(common-objpfx)nis/libnsl.a
++endif
+ endif
+Index: git/nscd/nis_hash.c
+===================================================================
+--- /dev/null 1970-01-01 00:00:00.000000000 +0000
++++ git/nscd/nis_hash.c 2014-08-29 20:01:15.216070587 -0700
+@@ -0,0 +1,3 @@
++/* If OPTION_EGLIBC_NIS is disabled, nscd can't get this from libnsl.so;
++ we need our own copy. */
++#include "../nis/nis_hash.c"
+Index: git/nss/fixed-nsswitch.conf
+===================================================================
+--- /dev/null 1970-01-01 00:00:00.000000000 +0000
++++ git/nss/fixed-nsswitch.conf 2014-08-29 20:01:15.216070587 -0700
+@@ -0,0 +1,22 @@
++# /etc/nsswitch.conf
++#
++# Example configuration for fixed name service.
++# See the description of OPTION_EGLIBC_NSSWITCH in option-groups.def
++# for details.
++#
++
++aliases: files
++
++passwd: files
++group: files
++shadow: files
++
++hosts: files dns
++networks: files dns
++
++protocols: files
++services: files
++ethers: files
++rpc: files
++
++netgroup: files
+Index: git/nss/fixed-nsswitch.functions
+===================================================================
+--- /dev/null 1970-01-01 00:00:00.000000000 +0000
++++ git/nss/fixed-nsswitch.functions 2014-08-29 20:01:15.216070587 -0700
+@@ -0,0 +1,121 @@
++/* List of functions defined for fixed NSS in GNU C Library.
++ Copyright (C) 1996, 1997, 1998, 2005 Free Software Foundation, Inc.
++ This file is part of the GNU C Library.
++
++ The GNU C Library is free software; you can redistribute it and/or
++ modify it under the terms of the GNU Lesser General Public
++ License as published by the Free Software Foundation; either
++ version 2.1 of the License, or (at your option) any later version.
++
++ The GNU C Library is distributed in the hope that it will be useful,
++ but WITHOUT ANY WARRANTY; without even the implied warranty of
++ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
++ Lesser General Public License for more details.
++
++ You should have received a copy of the GNU Lesser General Public
++ License along with the GNU C Library; if not, write to the Free
++ Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
++ 02111-1307 USA. */
++
++/* When OPTION_EGLIBC_NSSWITCH is disabled (see option-groups.def),
++ EGLIBC does not use the 'dlopen' and 'dlsym' functions to look for
++ database query functions in the individual name service libraries.
++ Instead, it uses a set of functions chosen at compile time, as
++ directed by the OPTION_EGLIBC_NSSWITCH_FIXED_FUNCTIONS file. This
++ file is a sample of what you might use there.
++
++ This file is C source code; it should only contain invocations of
++ the following macros:
++
++ - DEFINE_ENT (DATABASE, SERVICE, X)
++
++ Declare the 'setXent', 'getXent_r', and 'endXent' functions that
++ query DATABASE using the service library 'libnss_SERVICE.so.2'.
++ DATABASE should be the full name of the database as it appears in
++ 'nsswitch.conf', like 'passwd' or 'aliases'.
++
++ (The non-reentrant 'getXent' functions are implemented in terms
++ of the reentrant 'getXent_r' functions, so there is no need to
++ refer to them explicitly here.)
++
++ - DEFINE_GETBY (DATABASE, SERVICE, X, KEY)
++
++ Declare the 'getXbyKEY_r' functions that query DATABASE using
++ SERVICE. DATABASE and SERVICE are as described above.
++
++ (The non-reentrant 'getXbyKEY' functions are implemented in terms
++ of the reentrant 'getXbyKEY_r' functions, so there is no need to
++ refer to them explicitly here.)
++
++ Use the special key 'name3' for the service library function that
++ implements the 'getaddrinfo' function.
++
++ - DEFINE_GET (DATABASE, SERVICE, QUERY)
++
++ Declare the 'getQUERY_r' functions that query DATABASE using
++ SERVICE. This is used for functions like 'getpwnam'.
++
++ (The non-reentrant 'getQUERY' functions are implemented in terms
++ of the reentrant 'getQUERY_r' functions, so there is no need to
++ refer to them explicitly here.)
++
++ This sample file only includes functions that consult the files in
++ '/etc', and the Domain Name System (DNS). */
++
++/* aliases */
++DEFINE_ENT (aliases, files, alias)
++DEFINE_GETBY (aliases, files, alias, name)
++
++/* ethers */
++DEFINE_ENT (ethers, files, ether)
++
++/* group */
++DEFINE_ENT (group, files, gr)
++DEFINE_GET (group, files, grgid)
++DEFINE_GET (group, files, grnam)
++
++/* hosts */
++DEFINE_ENT (hosts, files, host)
++DEFINE_GETBY (hosts, files, host, addr)
++DEFINE_GETBY (hosts, files, host, name)
++DEFINE_GETBY (hosts, files, host, name2)
++DEFINE_GET (hosts, files, hostton)
++DEFINE_GET (hosts, files, ntohost)
++DEFINE_GETBY (hosts, dns, host, addr)
++DEFINE_GETBY (hosts, dns, host, name)
++DEFINE_GETBY (hosts, dns, host, name2)
++DEFINE_GETBY (hosts, dns, host, name3)
++
++/* netgroup */
++DEFINE_ENT (netgroup, files, netgr)
++
++/* networks */
++DEFINE_ENT (networks, files, net)
++DEFINE_GETBY (networks, files, net, name)
++DEFINE_GETBY (networks, files, net, addr)
++DEFINE_GETBY (networks, dns, net, name)
++DEFINE_GETBY (networks, dns, net, addr)
++
++/* protocols */
++DEFINE_ENT (protocols, files, proto)
++DEFINE_GETBY (protocols, files, proto, name)
++DEFINE_GETBY (protocols, files, proto, number)
++
++/* passwd */
++DEFINE_ENT (passwd, files, pw)
++DEFINE_GET (passwd, files, pwnam)
++DEFINE_GET (passwd, files, pwuid)
++
++/* rpc */
++DEFINE_ENT (rpc, files, rpc)
++DEFINE_GETBY (rpc, files, rpc, name)
++DEFINE_GETBY (rpc, files, rpc, number)
++
++/* services */
++DEFINE_ENT (services, files, serv)
++DEFINE_GETBY (services, files, serv, name)
++DEFINE_GETBY (services, files, serv, port)
++
++/* shadow */
++DEFINE_ENT (shadow, files, sp)
++DEFINE_GET (shadow, files, spnam)
+Index: git/nss/gen-fixed-nsswitch.c
+===================================================================
+--- /dev/null 1970-01-01 00:00:00.000000000 +0000
++++ git/nss/gen-fixed-nsswitch.c 2014-08-29 20:01:15.216070587 -0700
+@@ -0,0 +1,803 @@
++/* gen-fixed-nsswitch.c --- generate fixed name service data structures
++ Copyright (C) 1996-1999, 2001-2006, 2007 Free Software Foundation, Inc.
++ This file is part of the GNU C Library.
++
++ The GNU C Library is free software; you can redistribute it and/or
++ modify it under the terms of the GNU Lesser General Public
++ License as published by the Free Software Foundation; either
++ version 2.1 of the License, or (at your option) any later version.
++
++ The GNU C Library is distributed in the hope that it will be useful,
++ but WITHOUT ANY WARRANTY; without even the implied warranty of
++ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
++ Lesser General Public License for more details.
++
++ You should have received a copy of the GNU Lesser General Public
++ License along with the GNU C Library; if not, write to the Free
++ Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
++ 02111-1307 USA. */
++
++#define _GNU_SOURCE
++
++#include <stdlib.h>
++#include <stdio.h>
++#include <errno.h>
++#include <string.h>
++#include <stdarg.h>
++#include <assert.h>
++#include <ctype.h>
++
++#include "gnu/lib-names.h"
++#include "nss.h"
++
++/* Provide a fallback definition to allow this file to be compiled outside
++ libc. */
++#ifndef internal_function
++# define internal_function
++#endif
++
++
++/* Simple utilities. */
++
++void __attribute__ ((noreturn))
++error (const char *message)
++{
++ fprintf (stderr, "%s\n", message);
++ exit (1);
++}
++
++
++void *
++check_alloc (void *p)
++{
++ if (p)
++ return p;
++ else
++ error ("out of memory");
++}
++
++void *
++xmalloc (size_t size)
++{
++ return check_alloc (malloc (size));
++}
++
++
++/* Format ARGS according to FORMAT, and return the result as a
++ malloc'ed string. */
++char *
++saprintf (const char *format, ...)
++{
++ va_list args;
++ size_t len;
++ char *buf;
++
++ va_start (args, format);
++ len = vsnprintf (NULL, 0, format, args);
++ va_end (args);
++
++ buf = xmalloc (len + 1);
++ va_start (args, format);
++ assert (len == vsnprintf (buf, len + 1, format, args));
++ va_end (args);
++
++ return buf;
++}
++
++
++
++/* Data structures representing the configuration file in memory. */
++
++/* These are copied from nsswitch.h.
++
++ We could simply #include that file, but this program runs on the
++ build machine and links against the build machine's libraries,
++ whereas that header is meant for use by target code; it uses
++ 'libc_hidden_proto', 'internal_function', and related hair. Since
++ we've copied the parsing code, we might as well copy the data
++ structure definitions as well. */
++
++/* Actions performed after lookup finished. */
++typedef enum
++{
++ NSS_ACTION_CONTINUE,
++ NSS_ACTION_RETURN
++} lookup_actions;
++
++
++typedef struct service_library
++{
++ /* Name of service (`files', `dns', `nis', ...). */
++ const char *name;
++ /* Pointer to the loaded shared library. */
++ void *lib_handle;
++ /* And the link to the next entry. */
++ struct service_library *next;
++} service_library;
++
++
++/* For mapping a function name to a function pointer. It is known in
++ nsswitch.c:nss_lookup_function that a string pointer for the lookup key
++ is the first member. */
++typedef struct
++{
++ const char *fct_name;
++ void *fct_ptr;
++} known_function;
++
++
++typedef struct service_user
++{
++ /* And the link to the next entry. */
++ struct service_user *next;
++ /* Action according to result. */
++ lookup_actions actions[5];
++ /* Link to the underlying library object. */
++ service_library *library;
++ /* Collection of known functions.
++
++ With OPTION_EGLIBC_NSSWITCH enabled, this is the root of a
++ 'tsearch'-style tree.
++
++ With OPTION_EGLIBC_NSSWITCH disabled, this is an array of
++ pointers to known_function structures, NULL-terminated. */
++ union
++ {
++ void *tree;
++ const known_function **array;
++ } known;
++ /* Name of the service (`files', `dns', `nis', ...). */
++ const char *name;
++} service_user;
++
++/* To access the action based on the status value use this macro. */
++#define nss_next_action(ni, status) ((ni)->actions[2 + status])
++
++
++typedef struct name_database_entry
++{
++ /* And the link to the next entry. */
++ struct name_database_entry *next;
++ /* List of service to be used. */
++ service_user *service;
++ /* Name of the database. */
++ const char *name;
++} name_database_entry;
++
++
++typedef struct name_database
++{
++ /* List of all known databases. */
++ name_database_entry *entry;
++ /* List of libraries with service implementation. */
++ service_library *library;
++} name_database;
++
++
++
++/* Gathering the contents of the FIXED_FUNCTIONS file. */
++
++/* It should be possible to generate this list automatically by
++ looking at the services and databases used in the nsswitch.conf
++ file, and having a hard-coded set of queries supported on each
++ database. */
++
++/* We #include the FIXED_FUNCTIONS file several times to build an
++ array of function structures holding its data. */
++enum function_kind {
++ fk_end = 0, /* Last entry. */
++ fk_setent, /* Like setpwent. */
++ fk_getent, /* Like getpwent. */
++ fk_endent, /* Like endpwent. */
++ fk_getby, /* Like gethostbyname. */
++ fk_get /* Like getpwnam. */
++};
++
++
++struct function {
++ /* What kind of function this is. */
++ enum function_kind kind;
++
++ /* The database and service of the function being hardwired in. */
++ char *database, *service;
++
++ /* The kind of entry being queried, for 'fk_setent', 'fk_getent',
++ 'fk_endent', and 'fk_getby' functions. */
++ char *entry;
++
++ /* The key, for 'fk_getby' entries. */
++ char *key;
++
++ /* The value and key, for 'fk_get' entries. */
++ char *value_and_key;
++};
++
++
++const struct function functions[] =
++ {
++
++#define DEFINE_ENT(database, service, entry) \
++ { fk_setent, #database, #service, #entry }, \
++ { fk_getent, #database, #service, #entry }, \
++ { fk_endent, #database, #service, #entry },
++#define DEFINE_GETBY(database, service, entry, key) \
++ { fk_getby, #database, #service, #entry, #key },
++#define DEFINE_GET(database, service, value_and_key) \
++ { fk_get, #database, #service, NULL, NULL, #value_and_key },
++
++#include FIXED_FUNCTIONS
++
++#undef DEFINE_ENT
++#undef DEFINE_GETBY
++#undef DEFINE_GET
++
++ { fk_end }
++ };
++
++
++/* Parsing the config file. Functions copied from nsswitch.c. */
++
++#define __strchrnul strchrnul
++#define __getline getline
++#define __strncasecmp strncasecmp
++
++/* Prototypes for the local functions. */
++static name_database *nss_parse_file (const char *fname) internal_function;
++static name_database_entry *nss_getline (char *line) internal_function;
++static service_user *nss_parse_service_list (const char *line)
++ internal_function;
++
++static name_database *
++internal_function
++nss_parse_file (const char *fname)
++{
++ FILE *fp;
++ name_database *result;
++ name_database_entry *last;
++ char *line;
++ size_t len;
++
++ /* Open the configuration file. */
++ fp = fopen (fname, "rc");
++ if (fp == NULL)
++ return NULL;
++
++ // /* No threads use this stream. */
++ // __fsetlocking (fp, FSETLOCKING_BYCALLER);
++
++ result = (name_database *) xmalloc (sizeof (name_database));
++
++ result->entry = NULL;
++ result->library = NULL;
++ last = NULL;
++ line = NULL;
++ len = 0;
++ do
++ {
++ name_database_entry *this;
++ ssize_t n;
++
++ n = __getline (&line, &len, fp);
++ if (n < 0)
++ break;
++ if (line[n - 1] == '\n')
++ line[n - 1] = '\0';
++
++ /* Because the file format does not know any form of quoting we
++ can search forward for the next '#' character and if found
++ make it terminating the line. */
++ *__strchrnul (line, '#') = '\0';
++
++ /* If the line is blank it is ignored. */
++ if (line[0] == '\0')
++ continue;
++
++ /* Each line completely specifies the actions for a database. */
++ this = nss_getline (line);
++ if (this != NULL)
++ {
++ if (last != NULL)
++ last->next = this;
++ else
++ result->entry = this;
++
++ last = this;
++ }
++ }
++ while (!feof_unlocked (fp));
++
++ /* Free the buffer. */
++ free (line);
++ /* Close configuration file. */
++ fclose (fp);
++
++ return result;
++}
++
++
++/* Read the source names:
++ `( <source> ( "[" "!"? (<status> "=" <action> )+ "]" )? )*'
++ */
++static service_user *
++internal_function
++nss_parse_service_list (const char *line)
++{
++ service_user *result = NULL, **nextp = &result;
++
++ while (1)
++ {
++ service_user *new_service;
++ const char *name;
++
++ while (isspace (line[0]))
++ ++line;
++ if (line[0] == '\0')
++ /* No source specified. */
++ return result;
++
++ /* Read <source> identifier. */
++ name = line;
++ while (line[0] != '\0' && !isspace (line[0]) && line[0] != '[')
++ ++line;
++ if (name == line)
++ return result;
++
++
++ new_service = (service_user *) xmalloc (sizeof (*new_service));
++ new_service->name = (char *) xmalloc (line - name + 1);
++
++ *((char *) __mempcpy ((char *) new_service->name, name, line - name))
++ = '\0';
++
++ /* Set default actions. */
++ new_service->actions[2 + NSS_STATUS_TRYAGAIN] = NSS_ACTION_CONTINUE;
++ new_service->actions[2 + NSS_STATUS_UNAVAIL] = NSS_ACTION_CONTINUE;
++ new_service->actions[2 + NSS_STATUS_NOTFOUND] = NSS_ACTION_CONTINUE;
++ new_service->actions[2 + NSS_STATUS_SUCCESS] = NSS_ACTION_RETURN;
++ new_service->actions[2 + NSS_STATUS_RETURN] = NSS_ACTION_RETURN;
++ new_service->library = NULL;
++ new_service->known.tree = NULL;
++ new_service->next = NULL;
++
++ while (isspace (line[0]))
++ ++line;
++
++ if (line[0] == '[')
++ {
++ /* Read criterions. */
++ do
++ ++line;
++ while (line[0] != '\0' && isspace (line[0]));
++
++ do
++ {
++ int not;
++ enum nss_status status;
++ lookup_actions action;
++
++ /* Grok ! before name to mean all statii but that one. */
++ not = line[0] == '!';
++ if (not)
++ ++line;
++
++ /* Read status name. */
++ name = line;
++ while (line[0] != '\0' && !isspace (line[0]) && line[0] != '='
++ && line[0] != ']')
++ ++line;
++
++ /* Compare with known statii. */
++ if (line - name == 7)
++ {
++ if (__strncasecmp (name, "SUCCESS", 7) == 0)
++ status = NSS_STATUS_SUCCESS;
++ else if (__strncasecmp (name, "UNAVAIL", 7) == 0)
++ status = NSS_STATUS_UNAVAIL;
++ else
++ return result;
++ }
++ else if (line - name == 8)
++ {
++ if (__strncasecmp (name, "NOTFOUND", 8) == 0)
++ status = NSS_STATUS_NOTFOUND;
++ else if (__strncasecmp (name, "TRYAGAIN", 8) == 0)
++ status = NSS_STATUS_TRYAGAIN;
++ else
++ return result;
++ }
++ else
++ return result;
++
++ while (isspace (line[0]))
++ ++line;
++ if (line[0] != '=')
++ return result;
++ do
++ ++line;
++ while (isspace (line[0]));
++
++ name = line;
++ while (line[0] != '\0' && !isspace (line[0]) && line[0] != '='
++ && line[0] != ']')
++ ++line;
++
++ if (line - name == 6 && __strncasecmp (name, "RETURN", 6) == 0)
++ action = NSS_ACTION_RETURN;
++ else if (line - name == 8
++ && __strncasecmp (name, "CONTINUE", 8) == 0)
++ action = NSS_ACTION_CONTINUE;
++ else
++ return result;
++
++ if (not)
++ {
++ /* Save the current action setting for this status,
++ set them all to the given action, and reset this one. */
++ const lookup_actions save = new_service->actions[2 + status];
++ new_service->actions[2 + NSS_STATUS_TRYAGAIN] = action;
++ new_service->actions[2 + NSS_STATUS_UNAVAIL] = action;
++ new_service->actions[2 + NSS_STATUS_NOTFOUND] = action;
++ new_service->actions[2 + NSS_STATUS_SUCCESS] = action;
++ new_service->actions[2 + status] = save;
++ }
++ else
++ new_service->actions[2 + status] = action;
++
++ /* Skip white spaces. */
++ while (isspace (line[0]))
++ ++line;
++ }
++ while (line[0] != ']');
++
++ /* Skip the ']'. */
++ ++line;
++ }
++
++ *nextp = new_service;
++ nextp = &new_service->next;
++ }
++}
++
++static name_database_entry *
++internal_function
++nss_getline (char *line)
++{
++ const char *name;
++ name_database_entry *result;
++ size_t len;
++
++ /* Ignore leading white spaces. ATTENTION: this is different from
++ what is implemented in Solaris. The Solaris man page says a line
++ beginning with a white space character is ignored. We regard
++ this as just another misfeature in Solaris. */
++ while (isspace (line[0]))
++ ++line;
++
++ /* Recognize `<database> ":"'. */
++ name = line;
++ while (line[0] != '\0' && !isspace (line[0]) && line[0] != ':')
++ ++line;
++ if (line[0] == '\0' || name == line)
++ /* Syntax error. */
++ return NULL;
++ *line++ = '\0';
++
++ len = strlen (name) + 1;
++
++ result = (name_database_entry *) xmalloc (sizeof (*result));
++ result->name = (char *) xmalloc (len);
++
++ /* Save the database name. */
++ memcpy ((char *) result->name, name, len);
++
++ /* Parse the list of services. */
++ result->service = nss_parse_service_list (line);
++
++ result->next = NULL;
++ return result;
++}
++
++
++
++/* Generating code for statically initialized nsswitch structures. */
++
++
++/* Return the service-neutral suffix of the name of the service
++ library function referred to by the function F. The result is
++ allocated with malloc. */
++char *
++known_function_suffix (const struct function *f)
++{
++ switch (f->kind)
++ {
++ case fk_setent:
++ return saprintf ("set%sent", f->entry);
++
++ case fk_getent:
++ return saprintf ("get%sent_r", f->entry);
++
++ case fk_endent:
++ return saprintf ("end%sent", f->entry);
++
++ case fk_getby:
++ return saprintf ("get%sby%s_r", f->entry, f->key);
++
++ case fk_get:
++ return saprintf ("get%s_r", f->value_and_key);
++
++ default:
++ abort ();
++ }
++}
++
++
++/* Return the name of the service library function referred to by the
++ function F. The result is allocated with malloc. */
++char *
++known_function_name (const struct function *f)
++{
++ return saprintf ("_nss_%s_%s", f->service, known_function_suffix (f));
++}
++
++
++/* Write initialized known_function structures to OUT for
++ all the functions we'll use. */
++void
++generate_known_functions (FILE *out)
++{
++ int i;
++
++ /* First, generate weak references to the functions. The service
++ libraries depend on libc, and if these references weren't weak,
++ we'd be making libc depend circularly on the service
++ libraries. */
++ for (i = 0; functions[i].kind; i++)
++ {
++ char *name = known_function_name (&functions[i]);
++ fprintf (out, "typeof (%s) %s __attribute__ ((weak));\n",
++ name, name);
++ }
++ fputs ("\n", out);
++
++ /* Then, a table mapping names to functions. */
++ fputs ("static const known_function fixed_known_functions[] = {\n",
++ out);
++ for (i = 0; functions[i].kind; i++)
++ {
++ const struct function *f = &functions[i];
++ char *suffix = known_function_suffix (f);
++
++ fprintf (out, " /* %2d */ { \"%s\", _nss_%s_%s },\n",
++ i, suffix, f->service, suffix);
++ }
++ fputs ("};\n", out);
++ fputs ("\n", out);
++}
++
++
++/* Print code to OUT for an initialized array of pointers to the
++ 'known_function' structures needed for USER, which is for
++ DATABASE. Return its name, allocated with malloc. */
++char *
++generate_known_function_list (FILE *out,
++ const name_database_entry *database,
++ const service_user *user)
++{
++ char *list_name = saprintf ("fixed_%s_%s_known_funcs",
++ database->name, user->name);
++ fprintf (out, "static const known_function *%s[] = {\n",
++ list_name);
++ int i;
++ for (i = 0; functions[i].kind; i++)
++ if (strcmp (functions[i].database, database->name) == 0
++ && strcmp (functions[i].service, user->name) == 0)
++ fprintf (out, " &fixed_known_functions[%d], /* %s */\n",
++ i, known_function_name (&functions[i]));
++ fputs (" NULL\n", out);
++ fputs ("};\n", out);
++ fputs ("\n", out);
++
++ return list_name;
++}
++
++
++/* Return the name of the status value STATUS, as a statically
++ allocated string. */
++const char *
++lookup_status_name (enum nss_status status)
++{
++ switch (status)
++ {
++ case NSS_STATUS_TRYAGAIN: return "NSS_STATUS_TRYAGAIN";
++ case NSS_STATUS_UNAVAIL: return "NSS_STATUS_UNAVAIL";
++ case NSS_STATUS_NOTFOUND: return "NSS_STATUS_NOTFOUND";
++ case NSS_STATUS_SUCCESS: return "NSS_STATUS_SUCCESS";
++ case NSS_STATUS_RETURN: return "NSS_STATUS_RETURN";
++ default: abort ();
++ };
++}
++
++
++/* Return the name of ACTION as a statically allocated string. */
++const char *
++lookup_action_name (lookup_actions action)
++{
++ switch (action)
++ {
++ case NSS_ACTION_CONTINUE: return "NSS_ACTION_CONTINUE";
++ case NSS_ACTION_RETURN: return "NSS_ACTION_RETURN";
++ default: abort ();
++ }
++}
++
++
++/* Print code to OUT for the list of service_user structures starting
++ with USER, which are all for DATABASE. Return the name of the
++ first structure in that list, or zero if USER is NULL. */
++char *
++generate_service_user_list (FILE *out,
++ name_database_entry *database,
++ service_user *user)
++{
++ if (user)
++ {
++ /* Generate the tail of the list. */
++ char *next_name = generate_service_user_list (out, database, user->next);
++ /* Generate our known function list. */
++ char *known_function_list_name =
++ generate_known_function_list (out, database, user);
++
++ char *name = saprintf ("fixed_%s_%s_user", database->name, user->name);
++
++ fprintf (out, "static const service_user %s = {\n", name);
++ if (next_name)
++ fprintf (out, " (service_user *) &%s,\n", next_name);
++ else
++ fprintf (out, " NULL, /* no next entry */\n");
++ fputs (" {\n", out);
++ int i;
++ for (i = 0; i < sizeof (user->actions) / sizeof (user->actions[0]); i++)
++ fprintf (out, " %s, /* %s */\n",
++ lookup_action_name (user->actions[i]),
++ lookup_status_name (i - 2));
++ fputs (" },\n", out);
++ fprintf (out, " NULL, /* we never need the service library */\n");
++ fprintf (out, " { .array = %s },\n", known_function_list_name);
++ fprintf (out, " \"%s\"\n", user->name);
++ fputs ("};\n", out);
++ fputs ("\n", out);
++
++ return name;
++ }
++ else
++ return NULL;
++}
++
++
++/* Print code to OUT for the list of name_database_entry structures
++ starting with DATABASE. Return the name of the first structure
++ in that list, or zero if DATABASE is NULL. */
++char *
++generate_name_database_entries (FILE *out, name_database_entry *database)
++{
++ if (database)
++ {
++ char *next_name = generate_name_database_entries (out, database->next);
++ char *service_user_name
++ = generate_service_user_list (out, database, database->service);
++ char *name = saprintf ("fixed_%s_name_database", database->name);
++
++ fprintf (out, "static const name_database_entry %s = {\n", name);
++
++ if (next_name)
++ fprintf (out, " (name_database_entry *) &%s,\n", next_name);
++ else
++ fprintf (out, " NULL,\n");
++
++ if (service_user_name)
++ fprintf (out, " (service_user *) &%s,\n", service_user_name);
++ else
++ fprintf (out, " NULL,\n");
++
++ fprintf (out, " \"%s\"\n", database->name);
++ fprintf (out, "};\n");
++ fputs ("\n", out);
++
++ return name;
++ }
++ else
++ return NULL;
++}
++
++
++void
++generate_name_database (FILE *out, name_database *service_table)
++{
++ /* Produce a linked list of the known name_database_entry
++ structures. */
++ char *entries = generate_name_database_entries (out, service_table->entry);
++
++ /* Now produce the main structure that points to them all. */
++ fprintf (out, "static const name_database fixed_name_database = {\n");
++ if (entries)
++ fprintf (out, " (name_database_entry *) &%s,\n", entries);
++ else
++ fprintf (out, " NULL,\n");
++ fputs (" NULL /* we don't need the libraries */\n"
++ "};\n",
++ out);
++}
++
++
++
++/* Generating the list of service libraries we generate references to. */
++
++/* String with revision number of the shared object files. */
++static const char *const nss_shlib_revision = LIBNSS_FILES_SO + 15;
++
++void
++generate_service_lib_list (FILE *out, name_database *service_table)
++{
++ int i, j;
++ int printed_any = 0;
++
++ for (i = 0; functions[i].kind; i++)
++ {
++ /* Mention each service library only once. */
++ for (j = 0; j < i; j++)
++ if (strcmp (functions[i].service, functions[j].service) == 0)
++ break;
++
++ if (j >= i)
++ {
++ if (printed_any)
++ putc (' ', out);
++ fprintf (out, "-lnss_%s",
++ functions[i].service,
++ nss_shlib_revision);
++ printed_any = 1;
++ }
++ }
++}
++
++
++/* Main. */
++
++int
++main (int argc, char **argv)
++{
++ if (argc != 4)
++ {
++ fprintf (stderr, "usage: gen-fixed-nsswitch HEADER SERVLIBS CONFIG\n");
++ exit (1);
++ }
++
++ name_database *service_table = nss_parse_file (argv[3]);
++
++ FILE *header = fopen (argv[1], "w");
++ if (! header)
++ {
++ fprintf (stderr,
++ "gen-fixed-nsswitch: couldn't open output file %s: %s\n",
++ argv[1], strerror (errno));
++ exit (1);
++ }
++ fputs ("/* Generated by nss/gen-fixed-nsswitch.c. */\n", header);
++ fputs ("\n", header);
++ generate_known_functions (header);
++ generate_name_database (header, service_table);
++ fclose (header);
++
++ FILE *service_lib_list = fopen (argv[2], "w");
++ if (! service_lib_list)
++ {
++ fprintf (stderr,
++ "gen-fixed-nsswitch: couldn't open output file %s: %s\n",
++ argv[2], strerror (errno));
++ exit (1);
++ }
++ generate_service_lib_list (service_lib_list, service_table);
++ fclose (service_lib_list);
++
++ return 0;
++}
+Index: git/nss/getent.c
+===================================================================
+--- git.orig/nss/getent.c 2014-08-29 20:00:52.976070587 -0700
++++ git/nss/getent.c 2014-08-29 20:01:15.216070587 -0700
+@@ -39,6 +39,7 @@
+ #include <netinet/ether.h>
+ #include <netinet/in.h>
+ #include <sys/socket.h>
++#include <gnu/option-groups.h>
+
+ /* Get libc version number. */
+ #include <version.h>
+@@ -91,6 +92,7 @@
+ fprintf (stream, gettext ("Written by %s.\n"), "Thorsten Kukuk");
+ }
+
++#if __OPTION_EGLIBC_DB_ALIASES
+ /* This is for aliases */
+ static void
+ print_aliases (struct aliasent *alias)
+@@ -135,7 +137,9 @@
+
+ return result;
+ }
++#endif /* __OPTION_EGLIBC_DB_ALIASES */
+
++#if __OPTION_EGLIBC_INET
+ /* This is for ethers */
+ static int
+ ethers_keys (int number, char *key[])
+@@ -179,6 +183,7 @@
+
+ return result;
+ }
++#endif /* __OPTION_EGLIBC_INET */
+
+ /* This is for group */
+ static void
+@@ -301,6 +306,7 @@
+ return result;
+ }
+
++#if __OPTION_EGLIBC_INET
+ /* This is for hosts */
+ static void
+ print_hosts (struct hostent *host)
+@@ -598,6 +604,7 @@
+
+ return result;
+ }
++#endif /* __OPTION_EGLIBC_INET */
+
+ /* Now is all for passwd */
+ static void
+@@ -650,6 +657,7 @@
+ return result;
+ }
+
++#if __OPTION_EGLIBC_INET
+ /* This is for protocols */
+ static void
+ print_protocols (struct protoent *proto)
+@@ -805,6 +813,7 @@
+
+ return result;
+ }
++#endif /* __OPTION_EGLIBC_INET */
+
+ /* This is for shadow */
+ static void
+@@ -871,21 +880,34 @@
+ } databases[] =
+ {
+ #define D(name) { #name, name ## _keys },
+-D(ahosts)
+-D(ahostsv4)
+-D(ahostsv6)
+-D(aliases)
+-D(ethers)
++
++#if __OPTION_EGLIBC_INET
++#define DN(name) D(name)
++#else
++#define DN(name)
++#endif
++
++#if __OPTION_EGLIBC_DB_ALIASES
++#define DA(name) D(name)
++#else
++#define DA(name)
++#endif
++
++DN(ahosts)
++DN(ahostsv4)
++DN(ahostsv6)
++DA(aliases)
++DN(ethers)
+ D(group)
+ D(gshadow)
+-D(hosts)
++DN(hosts)
+-D(initgroups)
++DN(initgroups)
+-D(netgroup)
+-D(networks)
++DN(netgroup)
++DN(networks)
+ D(passwd)
+-D(protocols)
+-D(rpc)
+-D(services)
++DN(protocols)
++DN(rpc)
++DN(services)
+ D(shadow)
+ #undef D
+ { NULL, NULL }
+Index: git/nss/getnssent_r.c
+===================================================================
+--- git.orig/nss/getnssent_r.c 2014-08-29 20:00:52.976070587 -0700
++++ git/nss/getnssent_r.c 2014-08-29 20:01:15.220070587 -0700
+@@ -16,6 +16,7 @@
+ <http://www.gnu.org/licenses/>. */
+
+ #include <errno.h>
++#include <gnu/option-groups.h>
+ #include <netdb.h>
+ #include "nsswitch.h"
+
+@@ -59,11 +60,13 @@
+ } fct;
+ int no_more;
+
++#if __OPTION_EGLIBC_INET
+ if (res && __res_maybe_init (&_res, 0) == -1)
+ {
+ __set_h_errno (NETDB_INTERNAL);
+ return;
+ }
++#endif /* __OPTION_EGLIBC_INET */
+
+ /* Cycle through the services and run their `setXXent' functions until
+ we find an available service. */
+@@ -101,11 +104,13 @@
+ } fct;
+ int no_more;
+
++#if __OPTION_EGLIBC_INET
+ if (res && __res_maybe_init (&_res, 0) == -1)
+ {
+ __set_h_errno (NETDB_INTERNAL);
+ return;
+ }
++#endif /* __OPTION_EGLIBC_INET */
+
+ /* Cycle through all the services and run their endXXent functions. */
+ no_more = setup (func_name, lookup_fct, &fct.ptr, nip, startp, 1);
+@@ -141,12 +146,14 @@
+ int no_more;
+ enum nss_status status;
+
++#if __OPTION_EGLIBC_INET
+ if (res && __res_maybe_init (&_res, 0) == -1)
+ {
+ *h_errnop = NETDB_INTERNAL;
+ *result = NULL;
+ return errno;
+ }
++#endif /* __OPTION_EGLIBC_INET */
+
+ /* Initialize status to return if no more functions are found. */
+ status = NSS_STATUS_NOTFOUND;
+@@ -161,7 +168,7 @@
+ int is_last_nip = *nip == *last_nip;
+
+ status = DL_CALL_FCT (fct.f,
+- (resbuf, buffer, buflen, &errno, &h_errno));
++ (resbuf, buffer, buflen, &errno, h_errnop));
+
+ /* The status is NSS_STATUS_TRYAGAIN and errno is ERANGE the
+ provided buffer is too small. In this case we should give
+Index: git/nss/Makefile
+===================================================================
+--- git.orig/nss/Makefile 2014-08-29 20:00:52.972070587 -0700
++++ git/nss/Makefile 2014-08-29 20:01:15.220070587 -0700
+@@ -18,29 +18,36 @@
+ #
+ # Makefile for name service switch.
+ #
++include ../option-groups.mak
++
+ subdir := nss
+
+ include ../Makeconfig
+
+ headers := nss.h
+
+-# This is the trivial part which goes into libc itself.
+-routines = nsswitch getnssent getnssent_r digits_dots \
+- $(addsuffix -lookup,$(databases))
+-
+ # These are the databases that go through nss dispatch.
+ # Caution: if you add a database here, you must add its real name
+ # in databases.def, too.
+-databases = proto service hosts network grp pwd rpc ethers \
+- spwd netgrp key alias sgrp
++databases-y = grp pwd spwd sgrp
++databases-$(OPTION_EGLIBC_INET) \
++ += proto service hosts network rpc ethers \
++ netgrp key
++databases-$(OPTION_EGLIBC_DB_ALIASES) += alias
++
++# This is the trivial part which goes into libc itself.
++routines-y += nsswitch getnssent getnssent_r \
++ $(addsuffix -lookup,$(databases-y))
++routines-$(OPTION_EGLIBC_INET) += digits_dots
+
+ others := getent makedb
+ install-bin := getent makedb
+ makedb-modules = xmalloc hash-string
+ extra-objs += $(makedb-modules:=.o)
+
+-tests = test-netdb tst-nss-test1 test-digits-dots
+-xtests = bug-erange
++tests = tst-nss-test1
++tests-$(OPTION_EGLIBC_INET) += test-netdb test-digits-dots
++xtests-$(OPTION_EGLIBC_INET) += bug-erange
+
+ # Specify rules for the nss_* modules. We have some services.
+ services := files db
+@@ -55,7 +62,7 @@
+ vpath %.c $(subdir-dirs) ../locale/programs ../intl
+
+
+-libnss_files-routines := $(addprefix files-,$(databases)) \
++libnss_files-routines := $(addprefix files-,$(databases-y)) \
+ files-initgroups files-have_o_cloexec files-init
+
+ libnss_db-dbs := $(addprefix db-,\
+@@ -78,6 +85,45 @@
+ tests += $(tests-static)
+ endif
+
++ifneq ($(OPTION_EGLIBC_NSSWITCH),y)
++
++ifndef OPTION_EGLIBC_NSSWITCH_FIXED_CONFIG
++$(error OPTION_EGLIBC_NSSWITCH_FIXED_CONFIG variable left unset)
++endif
++
++ifndef OPTION_EGLIBC_NSSWITCH_FIXED_FUNCTIONS
++$(error OPTION_EGLIBC_NSSWITCH_FIXED_FUNCTIONS variable left unset)
++endif
++
++ifeq (,$(wildcard $(OPTION_EGLIBC_NSSWITCH_FIXED_CONFIG)))
++$(warning OPTION_EGLIBC_NSSWITCH is disabled, but fixed config file)
++$(error does not exist: $(OPTION_EGLIBC_NSSWITCH_FIXED_CONFIG))
++endif
++
++ifeq (,$(wildcard $(OPTION_EGLIBC_NSSWITCH_FIXED_FUNCTIONS)))
++$(warning OPTION_EGLIBC_NSSWITCH is disabled, but fixed functions file)
++$(error does not exist: $(OPTION_EGLIBC_NSSWITCH_FIXED_FUNCTIONS))
++endif
++
++before-compile := $(objpfx)fixed-nsswitch.h
++generated := fixed-nsswitch.h
++$(objpfx)fixed-nsswitch.h $(objfpx)fixed-nsswitch-libs: \
++ $(objpfx)gen-fixed-nsswitch \
++ $(OPTION_EGLIBC_NSSWITCH_FIXED_CONFIG)
++ $< $(objpfx)fixed-nsswitch.h \
++ $(objpfx)fixed-nsswitch-libs \
++ $(OPTION_EGLIBC_NSSWITCH_FIXED_CONFIG)
++
++$(objpfx)gen-fixed-nsswitch: gen-fixed-nsswitch.c \
++ $(common-objpfx)option-groups.config \
++ $(OPTION_EGLIBC_NSSWITCH_FIXED_FUNCTIONS)
++ $(native-compile)
++gen-fixed-nsswitch-CFLAGS = \
++ -g3 -O -Wall \
++ -I $(objpfx) \
++ -DFIXED_FUNCTIONS='"$(OPTION_EGLIBC_NSSWITCH_FIXED_FUNCTIONS)"'
++endif
++
+ include ../Rules
+
+ ifeq (yes,$(have-selinux))
+Index: git/nss/nsswitch.c
+===================================================================
+--- git.orig/nss/nsswitch.c 2014-08-29 20:00:53.004070587 -0700
++++ git/nss/nsswitch.c 2014-08-29 20:01:15.220070587 -0700
+@@ -26,6 +26,7 @@
+ #include <stdio_ext.h>
+ #include <stdlib.h>
+ #include <string.h>
++#include <gnu/option-groups.h>
+
+ #include <aliases.h>
+ #include <grp.h>
+@@ -41,6 +42,15 @@
+ #include "../nscd/nscd_proto.h"
+ #include <sysdep.h>
+
++/* When OPTION_EGLIBC_NSSWITCH is disabled, we use fixed tables of
++ databases and services, generated at library build time. Thus:
++ - We can't reconfigure individual databases, so we don't need a
++ name-to-database map.
++ - We never add databases or service libraries, or look up functions
++ at runtime, so there's no need for a lock to protect our tables.
++ See ../option-groups.def for the details. */
++#if __OPTION_EGLIBC_NSSWITCH
++
+ /* Prototypes for the local functions. */
+ static name_database *nss_parse_file (const char *fname) internal_function;
+ static name_database_entry *nss_getline (char *line) internal_function;
+@@ -79,6 +89,9 @@
+
+ __libc_lock_define_initialized (static, lock)
+
++#define lock_nsswitch __libc_lock_lock (lock)
++#define unlock_nsswitch __libc_lock_unlock (lock)
++
+ #if !defined DO_STATIC_NSS || defined SHARED
+ /* String with revision number of the shared object files. */
+ static const char *const __nss_shlib_revision = LIBNSS_FILES_SO + 15;
+@@ -93,6 +106,20 @@
+ __libc_freeres. */
+ static name_database_entry *defconfig_entries;
+
++#else /* __OPTION_EGLIBC_NSSWITCH */
++
++/* Bring in the statically initialized service table we generated at
++ build time. */
++#include "fixed-nsswitch.h"
++
++const static name_database *service_table = &fixed_name_database;
++
++/* Nothing ever changes, so there's no need to lock anything. */
++#define lock_nsswitch (0)
++#define unlock_nsswitch (0)
++
++#endif /* __OPTION_EGLIBC_NSSWITCH */
++
+
+ #ifdef USE_NSCD
+ /* Nonzero if this is the nscd process. */
+@@ -109,20 +136,22 @@
+ const char *defconfig, service_user **ni)
+ {
+ /* Prevent multiple threads to change the service table. */
+- __libc_lock_lock (lock);
++ lock_nsswitch;
+
+ /* Reconsider database variable in case some other thread called
+ `__nss_configure_lookup' while we waited for the lock. */
+ if (*ni != NULL)
+ {
+- __libc_lock_unlock (lock);
++ unlock_nsswitch;
+ return 0;
+ }
+
++#if __OPTION_EGLIBC_NSSWITCH
+ /* Are we initialized yet? */
+ if (service_table == NULL)
+ /* Read config file. */
+ service_table = nss_parse_file (_PATH_NSSWITCH_CONF);
++#endif
+
+ /* Test whether configuration data is available. */
+ if (service_table != NULL)
+@@ -144,6 +173,7 @@
+ *ni = entry->service;
+ }
+
++#if __OPTION_EGLIBC_NSSWITCH
+ /* No configuration data is available, either because nsswitch.conf
+ doesn't exist or because it doesn't have a line for this database.
+
+@@ -166,13 +196,23 @@
+ {
+ entry->next = defconfig_entries;
+ entry->service = *ni;
+- entry->name[0] = '\0';
++ entry->name = "";
+ defconfig_entries = entry;
+ }
+ }
+ }
++#else
++ /* Without the dynamic behavior, we can't process defconfig. The
++ databases the user specified at library build time are all you
++ get. */
++ if (*ni == NULL)
++ {
++ unlock_nsswitch;
++ return -1;
++ }
++#endif
+
+- __libc_lock_unlock (lock);
++ unlock_nsswitch;
+
+ return *ni != NULL ? 0 : -1;
+ }
+@@ -252,6 +292,7 @@
+ libc_hidden_def (__nss_next2)
+
+
++#if __OPTION_EGLIBC_NSSWITCH
+ int
+ attribute_compat_text_section
+ __nss_next (service_user **ni, const char *fct_name, void **fctp, int status,
+@@ -300,13 +341,13 @@
+ }
+
+ /* Prevent multiple threads to change the service table. */
+- __libc_lock_lock (lock);
++ lock_nsswitch;
+
+ /* Install new rules. */
+ *databases[cnt].dbp = new_db;
+ __nss_database_custom[cnt] = true;
+
+- __libc_lock_unlock (lock);
++ unlock_nsswitch;
+
+ return 0;
+ }
+@@ -402,7 +443,7 @@
+ void **found, *result;
+
+ /* We now modify global data. Protect it. */
+- __libc_lock_lock (lock);
++ lock_nsswitch;
+
+ /* Search the tree of functions previously requested. Data in the
+ tree are `known_function' structures, whose first member is a
+@@ -413,7 +454,7 @@
+ enough to a pointer to our structure to use as a lookup key that
+ will be passed to `known_compare' (above). */
+
+- found = __tsearch (&fct_name, &ni->known, &known_compare);
++ found = __tsearch (&fct_name, &ni->known.tree, &known_compare);
+ if (found == NULL)
+ /* This means out-of-memory. */
+ result = NULL;
+@@ -440,7 +481,7 @@
+ #endif
+ /* Oops. We can't instantiate this node properly.
+ Remove it from the tree. */
+- __tdelete (&fct_name, &ni->known, &known_compare);
++ __tdelete (&fct_name, &ni->known.tree, &known_compare);
+ free (known);
+ result = NULL;
+ }
+@@ -520,13 +561,43 @@
+ }
+
+ /* Remove the lock. */
+- __libc_lock_unlock (lock);
++ unlock_nsswitch;
+
+ return result;
+ }
+ libc_hidden_def (__nss_lookup_function)
+
+
++#else /* below if ! __OPTION_EGLIBC_NSSWITCH */
++
++
++int
++__nss_configure_lookup (const char *dbname, const char *service_line)
++{
++ /* We can't dynamically configure lookup without
++ OPTION_EGLIBC_NSSWITCH. */
++ __set_errno (EINVAL);
++ return -1;
++}
++
++
++void *
++__nss_lookup_function (service_user *ni, const char *fct_name)
++{
++ int i;
++ const known_function **known = ni->known.array;
++
++ for (i = 0; known[i]; i++)
++ if (strcmp (fct_name, known[i]->fct_name) == 0)
++ return known[i]->fct_ptr;
++
++ return NULL;
++}
++libc_hidden_def (__nss_lookup_function)
++#endif
++
++
++#if __OPTION_EGLIBC_NSSWITCH
+ static name_database *
+ internal_function
+ nss_parse_file (const char *fname)
+@@ -632,8 +703,10 @@
+ + (line - name + 1));
+ if (new_service == NULL)
+ return result;
++ new_service->name = (char *) (new_service + 1);
+
+- *((char *) __mempcpy (new_service->name, name, line - name)) = '\0';
++ *((char *) __mempcpy ((char *) new_service->name, name, line - name))
++ = '\0';
+
+ /* Set default actions. */
+ new_service->actions[2 + NSS_STATUS_TRYAGAIN] = NSS_ACTION_CONTINUE;
+@@ -642,7 +715,7 @@
+ new_service->actions[2 + NSS_STATUS_SUCCESS] = NSS_ACTION_RETURN;
+ new_service->actions[2 + NSS_STATUS_RETURN] = NSS_ACTION_RETURN;
+ new_service->library = NULL;
+- new_service->known = NULL;
++ new_service->known.tree = NULL;
+ new_service->next = NULL;
+
+ while (isspace (line[0]))
+@@ -778,9 +851,10 @@
+ result = (name_database_entry *) malloc (sizeof (name_database_entry) + len);
+ if (result == NULL)
+ return NULL;
++ result->name = (char *) (result + 1);
+
+ /* Save the database name. */
+- memcpy (result->name, name, len);
++ memcpy ((char *) result->name, name, len);
+
+ /* Parse the list of services. */
+ result->service = nss_parse_service_list (line);
+@@ -816,6 +890,7 @@
+ return *currentp;
+ }
+ #endif
++#endif /* __OPTION_EGLIBC_NSSWITCH */
+
+
+ #if defined SHARED && defined USE_NSCD
+@@ -834,6 +909,7 @@
+ }
+
+
++#if __OPTION_EGLIBC_INET
+ /* Called by nscd and nscd alone. */
+ void
+ __nss_disable_nscd (void (*cb) (size_t, struct traced_file *))
+@@ -857,8 +933,10 @@
+ __nss_not_use_nscd_services = -1;
+ __nss_not_use_nscd_netgroup = -1;
+ }
++#endif /* __OPTION_EGLIBC_INET */
+ #endif
+
++#if __OPTION_EGLIBC_NSSWITCH
+ static void
+ free_database_entries (name_database_entry *entry)
+ {
+@@ -871,8 +949,8 @@
+ {
+ service_user *olds = service;
+
+- if (service->known != NULL)
+- __tdestroy (service->known, free);
++ if (service->known.tree != NULL)
++ __tdestroy (service->known.tree, free);
+
+ service = service->next;
+ free (olds);
+@@ -926,3 +1004,4 @@
+
+ free (top);
+ }
++#endif /* __OPTION_EGLIBC_NSSWITCH */
+Index: git/nss/nsswitch.h
+===================================================================
+--- git.orig/nss/nsswitch.h 2014-08-29 20:00:53.012070587 -0700
++++ git/nss/nsswitch.h 2014-08-29 20:01:15.220070587 -0700
+@@ -65,10 +65,20 @@
+ lookup_actions actions[5];
+ /* Link to the underlying library object. */
+ service_library *library;
+- /* Collection of known functions. */
+- void *known;
++ /* Collection of known functions.
++
++ With OPTION_EGLIBC_NSSWITCH enabled, this is the root of a
++ 'tsearch'-style tree.
++
++ With OPTION_EGLIBC_NSSWITCH disabled, this is an array of
++ pointers to known_function structures, NULL-terminated. */
++ union
++ {
++ void *tree;
++ const known_function **array;
++ } known;
+ /* Name of the service (`files', `dns', `nis', ...). */
+- char name[0];
++ const char *name;
+ } service_user;
+
+ /* To access the action based on the status value use this macro. */
+@@ -82,7 +92,7 @@
+ /* List of service to be used. */
+ service_user *service;
+ /* Name of the database. */
+- char name[0];
++ const char *name;
+ } name_database_entry;
+
+
+Index: git/posix/bug-regex1.c
+===================================================================
+--- git.orig/posix/bug-regex1.c 2014-08-29 20:00:53.184070587 -0700
++++ git/posix/bug-regex1.c 2014-08-29 20:01:15.220070587 -0700
+@@ -4,6 +4,7 @@
+ #include <string.h>
+ #include <regex.h>
+ #include <wchar.h>
++#include <gnu/option-groups.h>
+
+ int
+ main (void)
+@@ -17,7 +18,9 @@
+ memset (®ex, '\0', sizeof (regex));
+
+ setlocale (LC_ALL, "de_DE.ISO-8859-1");
++#if __OPTION_POSIX_WIDE_CHAR_DEVICE_IO
+ fwide (stdout, -1);
++#endif
+
+ re_set_syntax (RE_SYNTAX_POSIX_EGREP | RE_DEBUG);
+
+Index: git/posix/bug-regex6.c
+===================================================================
+--- git.orig/posix/bug-regex6.c 2014-08-29 20:00:53.204070587 -0700
++++ git/posix/bug-regex6.c 2014-08-29 20:01:15.220070587 -0700
+@@ -22,6 +22,7 @@
+ #include <string.h>
+ #include <sys/types.h>
+ #include <regex.h>
++#include <gnu/option-groups.h>
+
+
+ int
+@@ -30,7 +31,12 @@
+ regex_t re;
+ regmatch_t mat[10];
+ int i, j, ret = 0;
+- const char *locales[] = { "C", "de_DE.UTF-8" };
++ const char *locales[] = {
++ "C",
++#if __OPTION_EGLIBC_LOCALE_CODE
++ "de_DE.UTF-8"
++#endif
++ };
+ const char *string = "http://www.regex.com/pattern/matching.html#intro";
+ regmatch_t expect[10] = {
+ { 0, 48 }, { 0, 5 }, { 0, 4 }, { 5, 20 }, { 7, 20 }, { 20, 42 },
+Index: git/posix/fnmatch.c
+===================================================================
+--- git.orig/posix/fnmatch.c 2014-08-29 20:00:53.208070587 -0700
++++ git/posix/fnmatch.c 2014-08-29 20:01:15.220070587 -0700
+@@ -30,6 +30,10 @@
+ #include <ctype.h>
+ #include <string.h>
+
++#if defined _LIBC
++# include <gnu/option-groups.h>
++#endif
++
+ #if defined STDC_HEADERS || defined _LIBC
+ # include <stdlib.h>
+ #endif
+@@ -131,7 +135,7 @@
+ # define ISWCTYPE(WC, WT) iswctype (WC, WT)
+ # endif
+
+-# if (HAVE_MBSTATE_T && HAVE_MBSRTOWCS) || _LIBC
++# if (HAVE_MBSTATE_T && HAVE_MBSRTOWCS && _LIBC && __OPTION_EGLIBC_LOCALE_CODE)
+ /* In this case we are implementing the multibyte character handling. */
+ # define HANDLE_MULTIBYTE 1
+ # endif
+Index: git/posix/fnmatch_loop.c
+===================================================================
+--- git.orig/posix/fnmatch_loop.c 2014-08-29 20:00:53.220070587 -0700
++++ git/posix/fnmatch_loop.c 2014-08-29 20:01:15.220070587 -0700
+@@ -15,6 +15,8 @@
+ License along with the GNU C Library; if not, see
+ <http://www.gnu.org/licenses/>. */
+
++#include <gnu/option-groups.h>
++
+ #include <stdint.h>
+
+ struct STRUCT
+@@ -54,10 +56,15 @@
+ const char *collseq = (const char *)
+ _NL_CURRENT(LC_COLLATE, _NL_COLLATE_COLLSEQWC);
+ # else
++# if __OPTION_EGLIBC_LOCALE_CODE
+ const UCHAR *collseq = (const UCHAR *)
+ _NL_CURRENT(LC_COLLATE, _NL_COLLATE_COLLSEQMB);
+-# endif
+-#endif
++# define COLLSEQ_BYTE_LOOKUP(ix) (collseq[(ix)])
++# else
++# define COLLSEQ_BYTE_LOOKUP(ix) (ix)
++# endif /* __OPTION_EGLIBC_LOCALE_CODE */
++# endif /* WIDE_CHAR_VERSION */
++#endif /* _LIBC */
+
+ while ((c = *p++) != L('\0'))
+ {
+@@ -277,7 +284,7 @@
+ /* Leave room for the null. */
+ CHAR str[CHAR_CLASS_MAX_LENGTH + 1];
+ size_t c1 = 0;
+-#if defined _LIBC || (defined HAVE_WCTYPE_H && defined HAVE_WCHAR_H)
++#if defined _LIBC ? __OPTION_POSIX_C_LANG_WIDE_CHAR : (defined HAVE_WCTYPE_H && defined HAVE_WCHAR_H)
+ wctype_t wt;
+ #endif
+ const CHAR *startp = p;
+@@ -307,7 +314,7 @@
+ }
+ str[c1] = L('\0');
+
+-#if defined _LIBC || (defined HAVE_WCTYPE_H && defined HAVE_WCHAR_H)
++#if defined _LIBC ? __OPTION_POSIX_C_LANG_WIDE_CHAR : (defined HAVE_WCTYPE_H && defined HAVE_WCHAR_H)
+ wt = IS_CHAR_CLASS (str);
+ if (wt == 0)
+ /* Invalid character class name. */
+@@ -681,8 +688,10 @@
+ else
+ lcollseq = __collseq_table_lookup (collseq, cold);
+ # else
+- fcollseq = collseq[fn];
+- lcollseq = is_seqval ? cold : collseq[(UCHAR) cold];
++ fcollseq = COLLSEQ_BYTE_LOOKUP (fn);
++ lcollseq = (is_seqval
++ ? cold
++ : COLLSEQ_BYTE_LOOKUP ((UCHAR) cold));
+ # endif
+
+ is_seqval = 0;
+@@ -858,7 +867,7 @@
+ goto matched;
+ }
+ # else
+- hcollseq = collseq[cend];
++ hcollseq = COLLSEQ_BYTE_LOOKUP (cend);
+ # endif
+ }
+
+Index: git/posix/glob.c
+===================================================================
+--- git.orig/posix/glob.c 2014-08-29 20:00:53.232070587 -0700
++++ git/posix/glob.c 2014-08-29 20:01:15.220070587 -0700
+@@ -25,6 +25,9 @@
+ #include <sys/types.h>
+ #include <sys/stat.h>
+ #include <stddef.h>
++#ifdef _LIBC
++# include <gnu/option-groups.h>
++#endif
+
+ /* Outcomment the following line for production quality code. */
+ /* #define NDEBUG 1 */
+@@ -607,6 +610,7 @@
+ if (home_dir == NULL || home_dir[0] == '\0')
+ home_dir = "c:/users/default"; /* poor default */
+ # else
++# if ! _LIBC || __OPTION_EGLIBC_GETLOGIN
+ if (home_dir == NULL || home_dir[0] == '\0')
+ {
+ int success;
+@@ -623,19 +627,19 @@
+ if (success)
+ {
+ struct passwd *p;
+-# if defined HAVE_GETPWNAM_R || defined _LIBC
++# if defined HAVE_GETPWNAM_R || defined _LIBC
+ long int pwbuflen = GETPW_R_SIZE_MAX ();
+ char *pwtmpbuf;
+ struct passwd pwbuf;
+ int malloc_pwtmpbuf = 0;
+ int save = errno;
+
+-# ifndef _LIBC
++# ifndef _LIBC
+ if (pwbuflen == -1)
+ /* `sysconf' does not support _SC_GETPW_R_SIZE_MAX.
+ Try a moderate value. */
+ pwbuflen = 1024;
+-# endif
++# endif
+ if (__libc_use_alloca (alloca_used + pwbuflen))
+ pwtmpbuf = alloca_account (pwbuflen, alloca_used);
+ else
+@@ -682,9 +686,9 @@
+ }
+ __set_errno (save);
+ }
+-# else
++# else
+ p = getpwnam (name);
+-# endif
++# endif
+ if (p != NULL)
+ {
+ if (!malloc_pwtmpbuf)
+@@ -713,6 +717,7 @@
+ }
+ }
+ }
++# endif /* ! _LIBC || __OPTION_EGLIBC_GETLOGIN */
+ if (home_dir == NULL || home_dir[0] == '\0')
+ {
+ if (flags & GLOB_TILDE_CHECK)
+Index: git/posix/Makefile
+===================================================================
+--- git.orig/posix/Makefile 2014-08-29 20:00:53.160070587 -0700
++++ git/posix/Makefile 2014-08-29 20:01:15.220070587 -0700
+@@ -18,6 +18,8 @@
+ #
+ # Sub-makefile for POSIX portion of the library.
+ #
++include ../option-groups.mak
++
+ subdir := posix
+
+ include ../Makeconfig
+@@ -43,13 +45,24 @@
+ getpgid setpgid getpgrp bsd-getpgrp setpgrp getsid setsid \
+ getresuid getresgid setresuid setresgid \
+ pathconf sysconf fpathconf \
+- glob glob64 fnmatch regex \
++ glob glob64 fnmatch \
+ confstr \
+ getopt getopt1 getopt_init \
+ sched_setp sched_getp sched_sets sched_gets sched_yield sched_primax \
+ sched_primin sched_rr_gi sched_getaffinity sched_setaffinity \
+- getaddrinfo gai_strerror wordexp \
+ pread pwrite pread64 pwrite64 \
++ posix_madvise \
++ get_child_max sched_cpucount sched_cpualloc sched_cpufree
++
++routines-$(OPTION_EGLIBC_INET) += getaddrinfo gai_strerror
++
++ifeq (y,$(OPTION_POSIX_REGEXP_GLIBC))
++routines-$(OPTION_POSIX_REGEXP) += regex
++else
++routines-$(OPTION_POSIX_REGEXP) += xregex
++endif
++
++routines-$(OPTION_EGLIBC_SPAWN) += \
+ spawn_faction_init spawn_faction_destroy spawn_faction_addclose \
+ spawn_faction_addopen spawn_faction_adddup2 \
+ spawnattr_init spawnattr_destroy \
+@@ -57,41 +70,53 @@
+ spawnattr_getflags spawnattr_setflags \
+ spawnattr_getpgroup spawnattr_setpgroup spawn spawnp spawni \
+ spawnattr_getsigmask spawnattr_getschedpolicy spawnattr_getschedparam \
+- spawnattr_setsigmask spawnattr_setschedpolicy spawnattr_setschedparam \
+- posix_madvise \
+- get_child_max sched_cpucount sched_cpualloc sched_cpufree
++ spawnattr_setsigmask spawnattr_setschedpolicy spawnattr_setschedparam
++routines-$(OPTION_EGLIBC_WORDEXP) += wordexp
+
+ aux := init-posix environ
+-tests := tstgetopt testfnm runtests runptests \
++tests := tstgetopt testfnm runtests \
+ tst-preadwrite tst-preadwrite64 test-vfork regexbug1 \
+- tst-getlogin tst-mmap tst-getaddrinfo tst-truncate \
+- tst-truncate64 tst-fork tst-fnmatch tst-regexloc tst-dir \
+- tst-chmod bug-regex1 bug-regex2 bug-regex3 bug-regex4 \
+- tst-gnuglob tst-regex bug-regex5 bug-regex6 bug-regex7 \
+- bug-regex8 bug-regex9 bug-regex10 bug-regex11 bug-regex12 \
+- bug-regex13 bug-regex14 bug-regex15 bug-regex16 \
+- bug-regex17 bug-regex18 bug-regex19 bug-regex20 \
+- bug-regex21 bug-regex22 bug-regex23 bug-regex24 \
+- bug-regex25 bug-regex26 bug-regex27 bug-regex28 \
+- bug-regex29 bug-regex30 bug-regex31 bug-regex32 \
+- bug-regex33 tst-nice tst-nanosleep tst-regex2 \
+- transbug tst-rxspencer tst-pcre tst-boost \
+- bug-ga1 tst-vfork1 tst-vfork2 tst-vfork3 tst-waitid \
+- tst-getaddrinfo2 bug-glob1 bug-glob2 bug-glob3 tst-sysconf \
++ tst-getlogin tst-mmap tst-truncate \
++ tst-truncate64 tst-fork tst-dir \
++ tst-chmod bug-regex2 bug-regex3 bug-regex4 \
++ tst-gnuglob bug-regex6 bug-regex7 \
++ bug-regex8 bug-regex9 bug-regex10 bug-regex12 \
++ bug-regex14 bug-regex15 \
++ bug-regex21 bug-regex24 \
++ bug-regex27 bug-regex28 bug-regex29 bug-regex30 \
++ bug-regex31 \
++ tst-nice tst-nanosleep \
++ transbug \
++ tst-vfork1 tst-vfork2 tst-vfork3 tst-waitid \
++ bug-glob1 bug-glob2 bug-glob3 tst-sysconf \
+ tst-execvp1 tst-execvp2 tst-execlp1 tst-execlp2 \
+ tst-execv1 tst-execv2 tst-execl1 tst-execl2 \
+ tst-execve1 tst-execve2 tst-execle1 tst-execle2 \
+- tst-execvp3 tst-execvp4 tst-rfc3484 tst-rfc3484-2 \
+- tst-rfc3484-3 \
+- tst-getaddrinfo3 tst-fnmatch2 tst-cpucount tst-cpuset \
++ tst-execvp3 tst-execvp4 \
++ tst-fnmatch2 tst-cpucount tst-cpuset \
+ bug-getopt1 bug-getopt2 bug-getopt3 bug-getopt4 \
+ bug-getopt5 tst-getopt_long1 bug-regex34 bug-regex35 \
+ tst-pathconf tst-getaddrinfo4 tst-rxspencer-no-utf8 \
+ tst-fnmatch3 bug-regex36
+-xtests := bug-ga2
++tests-$(OPTION_EGLIBC_LOCALE_CODE) \
++ += tst-fnmatch tst-regexloc bug-regex1 bug-regex5 \
++ bug-regex23 bug-regex25 bug-regex32 bug-regex33
++tests-$(OPTION_EGLIBC_INET) \
++ += tst-getaddrinfo bug-ga1 tst-getaddrinfo2 \
++ tst-rfc3484 tst-rfc3484-2 tst-rfc3484-3 tst-getaddrinfo3
++tests-$(OPTION_POSIX_REGEXP_GLIBC) \
++ += runptests bug-regex11 bug-regex13 bug-regex16 \
++ tst-regex2 tst-rxspencer tst-pcre tst-boost
++ifeq (yy,$(OPTION_EGLIBC_LOCALE_CODE)$(OPTION_POSIX_REGEXP_GLIBC))
++tests += tst-regex bug-regex17 bug-regex18 bug-regex19 bug-regex20 \
++ bug-regex22 bug-regex26
++endif
++xtests-$(OPTION_EGLIBC_INET) += bug-ga2
+ ifeq (yes,$(build-shared))
+ test-srcs := globtest
+-tests += wordexp-test tst-exec tst-spawn
++tests += tst-exec
++tests-$(OPTION_EGLIBC_SPAWN) += tst-spawn
++tests-$(OPTION_EGLIBC_WORDEXP) += wordexp-test
+ endif
+ tests-static = tst-exec-static tst-spawn-static
+ tests += $(tests-static)
+@@ -117,7 +142,10 @@
+
+ ifeq ($(run-built-tests),yes)
+ ifeq (yes,$(build-shared))
+-tests-special += $(objpfx)globtest.out $(objpfx)wordexp-tst.out
++tests-special += $(objpfx)globtest.out
++ifeq (y,$(OPTION_EGLIBC_WORDEXP))
++tests-special += $(objpfx)wordexp-tst.out
++endif
+ endif
+ endif
+
+@@ -125,12 +153,16 @@
+ # XXX Please note that for now we ignore the result of this test.
+ tests-special += $(objpfx)annexc.out
+ ifeq ($(run-built-tests),yes)
+-tests-special += $(objpfx)bug-regex2-mem.out $(objpfx)bug-regex14-mem.out \
++tests-special += $(objpfx)bug-regex2-mem.out \
+ $(objpfx)bug-regex21-mem.out $(objpfx)bug-regex31-mem.out \
+- $(objpfx)tst-rxspencer-no-utf8-mem.out $(objpfx)tst-pcre-mem.out \
+- $(objpfx)tst-boost-mem.out $(objpfx)tst-getconf.out \
++ $(objpfx)tst-getconf.out \
+ $(objpfx)bug-glob2-mem.out $(objpfx)tst-vfork3-mem.out \
+ $(objpfx)tst-fnmatch-mem.out $(objpfx)bug-regex36-mem.out
++ifeq (y,$(OPTION_POSIX_REGEXP_GLIBC))
++tests-special += $(objpfx)bug-regex14-mem.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 +175,8 @@
+ $(SHELL) $< $(common-objpfx) '$(test-via-rtld-prefix)' \
+ '$(test-program-prefix)' '$(test-wrapper-env)'; \
+ $(evaluate-test)
++LDLIBS-globtest += $(shell cat $(common-objpfx)nss/fixed-nsswitch-libs)
++
+ $(objpfx)wordexp-tst.out: wordexp-tst.sh $(objpfx)wordexp-test
+ $(SHELL) $< $(common-objpfx) '$(test-program-prefix-before-env)' \
+ '$(run-program-env)' '$(test-program-prefix-after-env)'; \
+@@ -205,7 +239,10 @@
+ tst-chmod-ARGS = $(objdir)
+ tst-vfork3-ARGS = --test-dir=$(objpfx)
+
+-tst-rxspencer-ARGS = --utf8 rxspencer/tests
++tst-rxspencer-ARGS = rxspencer/tests
++ifeq (y,$(OPTION_EGLIBC_LOCALE_CODE))
++tst-rxspencer-ARGS += --utf8
++endif
+ tst-rxspencer-no-utf8-ARGS = rxspencer/tests
+ tst-pcre-ARGS = PCRE.tests
+ tst-boost-ARGS = BOOST.tests
+Index: git/posix/regcomp.c
+===================================================================
+--- git.orig/posix/regcomp.c 2014-08-29 20:00:53.264070587 -0700
++++ git/posix/regcomp.c 2014-08-29 20:01:15.224070587 -0700
+@@ -18,6 +18,7 @@
+ <http://www.gnu.org/licenses/>. */
+
+ #include <stdint.h>
++#include <gnu/option-groups.h>
+
+ static reg_errcode_t re_compile_internal (regex_t *preg, const char * pattern,
+ size_t length, reg_syntax_t syntax);
+@@ -305,7 +306,7 @@
+ {
+ re_dfa_t *dfa = (re_dfa_t *) bufp->buffer;
+ int node_cnt;
+- int icase = (dfa->mb_cur_max == 1 && (bufp->syntax & RE_ICASE));
++ int icase = (dfa_mb_cur_max (dfa) == 1 && (bufp->syntax & RE_ICASE));
+ for (node_cnt = 0; node_cnt < init_state->nodes.nelem; ++node_cnt)
+ {
+ int node = init_state->nodes.elems[node_cnt];
+@@ -315,9 +316,9 @@
+ {
+ re_set_fastmap (fastmap, icase, dfa->nodes[node].opr.c);
+ #ifdef RE_ENABLE_I18N
+- if ((bufp->syntax & RE_ICASE) && dfa->mb_cur_max > 1)
++ if ((bufp->syntax & RE_ICASE) && dfa_mb_cur_max (dfa) > 1)
+ {
+- unsigned char *buf = alloca (dfa->mb_cur_max), *p;
++ unsigned char *buf = alloca (dfa_mb_cur_max (dfa)), *p;
+ wchar_t wc;
+ mbstate_t state;
+
+@@ -348,7 +349,11 @@
+ re_set_fastmap (fastmap, icase, ch);
+ }
+ }
+-#ifdef RE_ENABLE_I18N
++
++ /* When OPTION_EGLIBC_LOCALE_CODE is disabled, the current
++ locale is always C, which has no rules and no multi-byte
++ characters. */
++#if defined RE_ENABLE_I18N && __OPTION_EGLIBC_LOCALE_CODE
+ else if (type == COMPLEX_BRACKET)
+ {
+ re_charset_t *cset = dfa->nodes[node].opr.mbcset;
+@@ -376,7 +381,7 @@
+ i.e. where we would not find an invalid sequence. This only
+ applies to multibyte character sets; for single byte character
+ sets, the SIMPLE_BRACKET again suffices. */
+- if (dfa->mb_cur_max > 1
++ if (dfa_mb_cur_max (dfa) > 1
+ && (cset->nchar_classes || cset->non_match || cset->nranges
+ # ifdef _LIBC
+ || cset->nequiv_classes
+@@ -404,7 +409,7 @@
+ memset (&state, '\0', sizeof (state));
+ if (__wcrtomb (buf, cset->mbchars[i], &state) != (size_t) -1)
+ re_set_fastmap (fastmap, icase, *(unsigned char *) buf);
+- if ((bufp->syntax & RE_ICASE) && dfa->mb_cur_max > 1)
++ if ((bufp->syntax & RE_ICASE) && dfa_mb_cur_max (dfa) > 1)
+ {
+ if (__wcrtomb (buf, towlower (cset->mbchars[i]), &state)
+ != (size_t) -1)
+@@ -413,7 +418,7 @@
+ }
+ }
+ }
+-#endif /* RE_ENABLE_I18N */
++#endif /* RE_ENABLE_I18N && __OPTION_EGLIBC_LOCALE_CODE */
+ else if (type == OP_PERIOD
+ #ifdef RE_ENABLE_I18N
+ || type == OP_UTF8_PERIOD
+@@ -856,11 +861,15 @@
+
+ dfa->mb_cur_max = MB_CUR_MAX;
+ #ifdef _LIBC
+- if (dfa->mb_cur_max == 6
++ if (dfa_mb_cur_max (dfa) == 6
+ && strcmp (_NL_CURRENT (LC_CTYPE, _NL_CTYPE_CODESET_NAME), "UTF-8") == 0)
+ dfa->is_utf8 = 1;
++# if __OPTION_EGLIBC_LOCALE_CODE
+ dfa->map_notascii = (_NL_CURRENT_WORD (LC_CTYPE, _NL_CTYPE_MAP_TO_NONASCII)
+ != 0);
++# else
++ dfa->map_notascii = 0;
++# endif
+ #else
+ # ifdef HAVE_LANGINFO_CODESET
+ codeset_name = nl_langinfo (CODESET);
+@@ -886,7 +895,7 @@
+ #endif
+
+ #ifdef RE_ENABLE_I18N
+- if (dfa->mb_cur_max > 1)
++ if (dfa_mb_cur_max (dfa) > 1)
+ {
+ if (dfa->is_utf8)
+ dfa->sb_char = (re_bitset_ptr_t) utf8_sb_map;
+@@ -1784,7 +1793,7 @@
+ token->word_char = 0;
+ #ifdef RE_ENABLE_I18N
+ token->mb_partial = 0;
+- if (input->mb_cur_max > 1 &&
++ if (string_mb_cur_max (input) > 1 &&
+ !re_string_first_byte (input, re_string_cur_idx (input)))
+ {
+ token->type = CHARACTER;
+@@ -1805,7 +1814,7 @@
+ token->opr.c = c2;
+ token->type = CHARACTER;
+ #ifdef RE_ENABLE_I18N
+- if (input->mb_cur_max > 1)
++ if (string_mb_cur_max (input) > 1)
+ {
+ wint_t wc = re_string_wchar_at (input,
+ re_string_cur_idx (input) + 1);
+@@ -1919,7 +1928,7 @@
+
+ token->type = CHARACTER;
+ #ifdef RE_ENABLE_I18N
+- if (input->mb_cur_max > 1)
++ if (string_mb_cur_max (input) > 1)
+ {
+ wint_t wc = re_string_wchar_at (input, re_string_cur_idx (input));
+ token->word_char = IS_WIDE_WORD_CHAR (wc) != 0;
+@@ -2019,7 +2028,7 @@
+ token->opr.c = c;
+
+ #ifdef RE_ENABLE_I18N
+- if (input->mb_cur_max > 1 &&
++ if (string_mb_cur_max (input) > 1 &&
+ !re_string_first_byte (input, re_string_cur_idx (input)))
+ {
+ token->type = CHARACTER;
+@@ -2242,7 +2251,7 @@
+ return NULL;
+ }
+ #ifdef RE_ENABLE_I18N
+- if (dfa->mb_cur_max > 1)
++ if (dfa_mb_cur_max (dfa) > 1)
+ {
+ while (!re_string_eoi (regexp)
+ && !re_string_first_byte (regexp, re_string_cur_idx (regexp)))
+@@ -2380,7 +2389,7 @@
+ *err = REG_ESPACE;
+ return NULL;
+ }
+- if (dfa->mb_cur_max > 1)
++ if (dfa_mb_cur_max (dfa) > 1)
+ dfa->has_mb_node = 1;
+ break;
+ case OP_WORD:
+@@ -2686,7 +2695,7 @@
+ However, for !_LIBC we have no collation elements: if the
+ character set is single byte, the single byte character set
+ that we build below suffices. parse_bracket_exp passes
+- no MBCSET if dfa->mb_cur_max == 1. */
++ no MBCSET if dfa_mb_cur_max (dfa) == 1. */
+ if (mbcset)
+ {
+ /* Check the space of the arrays. */
+@@ -2782,7 +2791,13 @@
+ reg_syntax_t syntax, reg_errcode_t *err)
+ {
+ #ifdef _LIBC
++#if __OPTION_EGLIBC_LOCALE_CODE
+ const unsigned char *collseqmb;
++# define COLLSEQMB_LOOKUP(ix) (collseqmb[(ix)])
++#else
++# define COLLSEQMB_LOOKUP(ix) (ix)
++#endif
++
+ const char *collseqwc;
+ uint32_t nrules;
+ int32_t table_size;
+@@ -2830,18 +2845,20 @@
+ if (MB_CUR_MAX == 1)
+ */
+ if (nrules == 0)
+- return collseqmb[br_elem->opr.ch];
++ return COLLSEQMB_LOOKUP (br_elem->opr.ch);
+ else
+ {
+ wint_t wc = __btowc (br_elem->opr.ch);
+ return __collseq_table_lookup (collseqwc, wc);
+ }
+ }
++#if __OPTION_EGLIBC_LOCALE_CODE
+ else if (br_elem->type == MB_CHAR)
+ {
+ if (nrules != 0)
+ return __collseq_table_lookup (collseqwc, br_elem->opr.wch);
+ }
++#endif
+ else if (br_elem->type == COLL_SYM)
+ {
+ size_t sym_name_len = strlen ((char *) br_elem->opr.name);
+@@ -2872,11 +2889,11 @@
+ {
+ /* No valid character. Match it as a single byte
+ character. */
+- return collseqmb[br_elem->opr.name[0]];
++ return COLLSEQMB_LOOKUP (br_elem->opr.name[0]);
+ }
+ }
+ else if (sym_name_len == 1)
+- return collseqmb[br_elem->opr.name[0]];
++ return COLLSEQMB_LOOKUP (br_elem->opr.name[0]);
+ }
+ return UINT_MAX;
+ }
+@@ -2916,7 +2933,7 @@
+ However, if we have no collation elements, and the character set
+ is single byte, the single byte character set that we
+ build below suffices. */
+- if (nrules > 0 || dfa->mb_cur_max > 1)
++ if (nrules > 0 || dfa_mb_cur_max (dfa) > 1)
+ {
+ /* Check the space of the arrays. */
+ if (BE (*range_alloc == mbcset->nranges, 0))
+@@ -2953,7 +2970,7 @@
+ if (MB_CUR_MAX == 1)
+ */
+ if (nrules == 0)
+- ch_collseq = collseqmb[ch];
++ ch_collseq = COLLSEQMB_LOOKUP (ch);
+ else
+ ch_collseq = __collseq_table_lookup (collseqwc, __btowc (ch));
+ if (start_collseq <= ch_collseq && ch_collseq <= end_collseq)
+@@ -3031,7 +3048,10 @@
+ re_bitset_ptr_t sbcset;
+ #ifdef RE_ENABLE_I18N
+ re_charset_t *mbcset;
+- int coll_sym_alloc = 0, range_alloc = 0, mbchar_alloc = 0;
++ int coll_sym_alloc = 0, range_alloc = 0;
++#if __OPTION_EGLIBC_LOCALE_CODE
++ int mbchar_alloc = 0;
++#endif
+ int equiv_class_alloc = 0, char_class_alloc = 0;
+ #endif /* not RE_ENABLE_I18N */
+ int non_match = 0;
+@@ -3039,9 +3059,15 @@
+ int token_len;
+ int first_round = 1;
+ #ifdef _LIBC
++#if __OPTION_EGLIBC_LOCALE_CODE
+ collseqmb = (const unsigned char *)
+ _NL_CURRENT (LC_COLLATE, _NL_COLLATE_COLLSEQMB);
+ nrules = _NL_CURRENT_WORD (LC_COLLATE, _NL_COLLATE_NRULES);
++#else
++ /* This is true when OPTION_EGLIBC_LOCALE_CODE is disabled, but the
++ compiler can't figure that out. */
++ nrules = 0;
++#endif
+ if (nrules)
+ {
+ /*
+@@ -3169,7 +3195,7 @@
+ #else
+ # ifdef RE_ENABLE_I18N
+ *err = build_range_exp (sbcset,
+- dfa->mb_cur_max > 1 ? mbcset : NULL,
++ dfa_mb_cur_max (dfa) > 1 ? mbcset : NULL,
+ &range_alloc, &start_elem, &end_elem);
+ # else
+ *err = build_range_exp (sbcset, &start_elem, &end_elem);
+@@ -3185,7 +3211,7 @@
+ case SB_CHAR:
+ bitset_set (sbcset, start_elem.opr.ch);
+ break;
+-#ifdef RE_ENABLE_I18N
++#if defined RE_ENABLE_I18N && __OPTION_EGLIBC_LOCALE_CODE
+ case MB_CHAR:
+ /* Check whether the array has enough space. */
+ if (BE (mbchar_alloc == mbcset->nmbchars, 0))
+@@ -3203,7 +3229,7 @@
+ }
+ mbcset->mbchars[mbcset->nmbchars++] = start_elem.opr.wch;
+ break;
+-#endif /* RE_ENABLE_I18N */
++#endif /* RE_ENABLE_I18N && __OPTION_EGLIBC_LOCALE_CODE */
+ case EQUIV_CLASS:
+ *err = build_equiv_class (sbcset,
+ #ifdef RE_ENABLE_I18N
+@@ -3253,11 +3279,11 @@
+
+ #ifdef RE_ENABLE_I18N
+ /* Ensure only single byte characters are set. */
+- if (dfa->mb_cur_max > 1)
++ if (dfa_mb_cur_max (dfa) > 1)
+ bitset_mask (sbcset, dfa->sb_char);
+
+ if (mbcset->nmbchars || mbcset->ncoll_syms || mbcset->nequiv_classes
+- || mbcset->nranges || (dfa->mb_cur_max > 1 && (mbcset->nchar_classes
++ || mbcset->nranges || (dfa_mb_cur_max (dfa) > 1 && (mbcset->nchar_classes
+ || mbcset->non_match)))
+ {
+ bin_tree_t *mbc_tree;
+@@ -3326,7 +3352,7 @@
+ re_token_t *token, int token_len, re_dfa_t *dfa,
+ reg_syntax_t syntax, int accept_hyphen)
+ {
+-#ifdef RE_ENABLE_I18N
++#if defined RE_ENABLE_I18N && __OPTION_EGLIBC_LOCALE_CODE
+ int cur_char_size;
+ cur_char_size = re_string_char_size_at (regexp, re_string_cur_idx (regexp));
+ if (cur_char_size > 1)
+@@ -3336,7 +3362,7 @@
+ re_string_skip_bytes (regexp, cur_char_size);
+ return REG_NOERROR;
+ }
+-#endif /* RE_ENABLE_I18N */
++#endif /* RE_ENABLE_I18N && __OPTION_EGLIBC_LOCALE_CODE */
+ re_string_skip_bytes (regexp, token_len); /* Skip a token. */
+ if (token->type == OP_OPEN_COLL_ELEM || token->type == OP_OPEN_CHAR_CLASS
+ || token->type == OP_OPEN_EQUIV_CLASS)
+@@ -3416,7 +3442,9 @@
+ build_equiv_class (bitset_t sbcset, const unsigned char *name)
+ #endif /* not RE_ENABLE_I18N */
+ {
+-#ifdef _LIBC
++ /* When __OPTION_EGLIBC_LOCALE_CODE is disabled, only the C locale
++ is supported; it has no collation rules. */
++#if defined _LIBC && __OPTION_EGLIBC_LOCALE_CODE
+ uint32_t nrules = _NL_CURRENT_WORD (LC_COLLATE, _NL_COLLATE_NRULES);
+ if (nrules != 0)
+ {
+@@ -3488,7 +3516,7 @@
+ mbcset->equiv_classes[mbcset->nequiv_classes++] = idx1;
+ }
+ else
+-#endif /* _LIBC */
++#endif /* _LIBC && __OPTION_EGLIBC_LOCALE_CODE */
+ {
+ if (BE (strlen ((const char *) name) != 1, 0))
+ return REG_ECOLLATE;
+@@ -3522,7 +3550,7 @@
+ && (strcmp (name, "upper") == 0 || strcmp (name, "lower") == 0))
+ name = "alpha";
+
+-#ifdef RE_ENABLE_I18N
++#if defined RE_ENABLE_I18N && __OPTION_EGLIBC_LOCALE_CODE
+ /* Check the space of the arrays. */
+ if (BE (*char_class_alloc == mbcset->nchar_classes, 0))
+ {
+@@ -3538,7 +3566,7 @@
+ *char_class_alloc = new_char_class_alloc;
+ }
+ mbcset->char_classes[mbcset->nchar_classes++] = __wctype (name);
+-#endif /* RE_ENABLE_I18N */
++#endif /* RE_ENABLE_I18N && __OPTION_EGLIBC_LOCALE_CODE */
+
+ #define BUILD_CHARCLASS_LOOP(ctype_func) \
+ do { \
+@@ -3649,7 +3677,7 @@
+
+ #ifdef RE_ENABLE_I18N
+ /* Ensure only single byte characters are set. */
+- if (dfa->mb_cur_max > 1)
++ if (dfa_mb_cur_max (dfa) > 1)
+ bitset_mask (sbcset, dfa->sb_char);
+ #endif
+
+@@ -3661,7 +3689,7 @@
+ goto build_word_op_espace;
+
+ #ifdef RE_ENABLE_I18N
+- if (dfa->mb_cur_max > 1)
++ if (dfa_mb_cur_max (dfa) > 1)
+ {
+ bin_tree_t *mbc_tree;
+ /* Build a tree for complex bracket. */
+Index: git/posix/regexec.c
+===================================================================
+--- git.orig/posix/regexec.c 2014-08-29 20:00:53.268070587 -0700
++++ git/posix/regexec.c 2014-08-29 20:01:15.224070587 -0700
+@@ -18,6 +18,7 @@
+ <http://www.gnu.org/licenses/>. */
+
+ #include <stdint.h>
++#include <gnu/option-groups.h>
+
+ static reg_errcode_t match_ctx_init (re_match_context_t *cache, int eflags,
+ int n) internal_function;
+@@ -186,11 +187,11 @@
+ static int check_node_accept_bytes (const re_dfa_t *dfa, int node_idx,
+ const re_string_t *input, int idx)
+ internal_function;
+-# ifdef _LIBC
++# if defined _LIBC && __OPTION_EGLIBC_LOCALE_CODE
+ static unsigned int find_collation_sequence_value (const unsigned char *mbs,
+ size_t name_len)
+ internal_function;
+-# endif /* _LIBC */
++# endif /* _LIBC && __OPTION_EGLIBC_LOCALE_CODE */
+ #endif /* RE_ENABLE_I18N */
+ static int group_nodes_into_DFAstates (const re_dfa_t *dfa,
+ const re_dfastate_t *state,
+@@ -255,25 +256,9 @@
+ return err != REG_NOERROR;
+ }
+
+-#ifdef _LIBC
+-# include <shlib-compat.h>
+-versioned_symbol (libc, __regexec, regexec, GLIBC_2_3_4);
+-
+-# if SHLIB_COMPAT (libc, GLIBC_2_0, GLIBC_2_3_4)
+-__typeof__ (__regexec) __compat_regexec;
+-
+-int
+-attribute_compat_text_section
+-__compat_regexec (const regex_t *__restrict preg,
+- const char *__restrict string, size_t nmatch,
+- regmatch_t pmatch[], int eflags)
+-{
+- return regexec (preg, string, nmatch, pmatch,
+- eflags & (REG_NOTBOL | REG_NOTEOL));
+-}
+-compat_symbol (libc, __compat_regexec, regexec, GLIBC_2_0);
+-# endif
+-#endif
++/* EGLIBC: The code that used to be here was move to a separate file
++ so that it can be shared with xregex.c. */
++#include "regexec-compat.c"
+
+ /* Entry points for GNU code. */
+
+@@ -728,7 +713,7 @@
+ incr = (range < 0) ? -1 : 1;
+ left_lim = (range < 0) ? start + range : start;
+ right_lim = (range < 0) ? start : start + range;
+- sb = dfa->mb_cur_max == 1;
++ sb = dfa_mb_cur_max (dfa) == 1;
+ match_kind =
+ (fastmap
+ ? ((sb || !(preg->syntax & RE_ICASE || t) ? 4 : 0)
+@@ -3448,7 +3433,7 @@
+ if (BE (dest_states_word[i] == NULL && err != REG_NOERROR, 0))
+ goto out_free;
+
+- if (dest_states[i] != dest_states_word[i] && dfa->mb_cur_max > 1)
++ if (dest_states[i] != dest_states_word[i] && dfa_mb_cur_max (dfa) > 1)
+ need_word_trtable = 1;
+
+ dest_states_nl[i] = re_acquire_state_context (&err, dfa, &follows,
+@@ -3590,7 +3575,7 @@
+ else if (type == OP_PERIOD)
+ {
+ #ifdef RE_ENABLE_I18N
+- if (dfa->mb_cur_max > 1)
++ if (dfa_mb_cur_max (dfa) > 1)
+ bitset_merge (accepts, dfa->sb_char);
+ else
+ #endif
+@@ -3641,7 +3626,7 @@
+ continue;
+ }
+ #ifdef RE_ENABLE_I18N
+- if (dfa->mb_cur_max > 1)
++ if (dfa_mb_cur_max (dfa) > 1)
+ for (j = 0; j < BITSET_WORDS; ++j)
+ any_set |= (accepts[j] &= (dfa->word_char[j] | ~dfa->sb_char[j]));
+ else
+@@ -3660,7 +3645,7 @@
+ continue;
+ }
+ #ifdef RE_ENABLE_I18N
+- if (dfa->mb_cur_max > 1)
++ if (dfa_mb_cur_max (dfa) > 1)
+ for (j = 0; j < BITSET_WORDS; ++j)
+ any_set |= (accepts[j] &= ~(dfa->word_char[j] & dfa->sb_char[j]));
+ else
+@@ -3832,12 +3817,6 @@
+ if (node->type == COMPLEX_BRACKET)
+ {
+ const re_charset_t *cset = node->opr.mbcset;
+-# ifdef _LIBC
+- const unsigned char *pin
+- = ((const unsigned char *) re_string_get_buffer (input) + str_idx);
+- int j;
+- uint32_t nrules;
+-# endif /* _LIBC */
+ int match_len = 0;
+ wchar_t wc = ((cset->nranges || cset->nchar_classes || cset->nmbchars)
+ ? re_string_wchar_at (input, str_idx) : 0);
+@@ -3849,6 +3828,7 @@
+ match_len = char_len;
+ goto check_node_accept_bytes_match;
+ }
++#if __OPTION_EGLIBC_LOCALE_CODE
+ /* match with character_class? */
+ for (i = 0; i < cset->nchar_classes; ++i)
+ {
+@@ -3859,8 +3839,16 @@
+ goto check_node_accept_bytes_match;
+ }
+ }
++#endif
++
++ /* When __OPTION_EGLIBC_LOCALE_CODE is disabled, only the C
++ locale is supported; it has no collation rules. */
++# if defined _LIBC && __OPTION_EGLIBC_LOCALE_CODE
++ const unsigned char *pin
++ = ((const unsigned char *) re_string_get_buffer (input) + str_idx);
++ int j;
++ uint32_t nrules;
+
+-# ifdef _LIBC
+ nrules = _NL_CURRENT_WORD (LC_COLLATE, _NL_COLLATE_NRULES);
+ if (nrules != 0)
+ {
+@@ -3953,8 +3941,12 @@
+ }
+ }
+ else
+-# endif /* _LIBC */
++# endif /* _LIBC && __OPTION_EGLIBC_LOCALE_CODE */
+ {
++ /* In the _LIBC version, if OPTION_EGLIBC_LOCALE_CODE is
++ disabled, there can be no multibyte range endpoints, and
++ cset->nranges is always zero. */
++#if __OPTION_EGLIBC_LOCALE_CODE
+ /* match with range expression? */
+ #if __GNUC__ >= 2
+ wchar_t cmp_buf[] = {L'\0', L'\0', wc, L'\0', L'\0', L'\0'};
+@@ -3973,6 +3965,7 @@
+ goto check_node_accept_bytes_match;
+ }
+ }
++#endif /* __OPTION_EGLIBC_LOCALE_CODE */
+ }
+ check_node_accept_bytes_match:
+ if (!cset->non_match)
+@@ -3988,7 +3981,7 @@
+ return 0;
+ }
+
+-# ifdef _LIBC
++# if defined _LIBC && __OPTION_EGLIBC_LOCALE_CODE
+ static unsigned int
+ internal_function
+ find_collation_sequence_value (const unsigned char *mbs, size_t mbs_len)
+@@ -4046,7 +4039,7 @@
+ return UINT_MAX;
+ }
+ }
+-# endif /* _LIBC */
++# endif /* _LIBC && __OPTION_EGLIBC_LOCALE_CODE */
+ #endif /* RE_ENABLE_I18N */
+
+ /* Check whether the node accepts the byte which is IDX-th
+@@ -4137,7 +4130,7 @@
+ if (pstr->icase)
+ {
+ #ifdef RE_ENABLE_I18N
+- if (pstr->mb_cur_max > 1)
++ if (string_mb_cur_max (pstr) > 1)
+ {
+ ret = build_wcs_upper_buffer (pstr);
+ if (BE (ret != REG_NOERROR, 0))
+@@ -4150,7 +4143,7 @@
+ else
+ {
+ #ifdef RE_ENABLE_I18N
+- if (pstr->mb_cur_max > 1)
++ if (string_mb_cur_max (pstr) > 1)
+ build_wcs_buffer (pstr);
+ else
+ #endif /* RE_ENABLE_I18N */
+Index: git/posix/regexec-compat.c
+===================================================================
+--- /dev/null 1970-01-01 00:00:00.000000000 +0000
++++ git/posix/regexec-compat.c 2014-08-29 20:01:15.224070587 -0700
+@@ -0,0 +1,39 @@
++/* Extended regular expression matching and search library.
++ Copyright (C) 2008 Free Software Foundation, Inc.
++ This file is part of the GNU C Library.
++ Contributed by Isamu Hasegawa <isamu at yamato.ibm.com>.
++
++ The GNU C Library is free software; you can redistribute it and/or
++ modify it under the terms of the GNU Lesser General Public
++ License as published by the Free Software Foundation; either
++ version 2.1 of the License, or (at your option) any later version.
++
++ The GNU C Library is distributed in the hope that it will be useful,
++ but WITHOUT ANY WARRANTY; without even the implied warranty of
++ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
++ Lesser General Public License for more details.
++
++ You should have received a copy of the GNU Lesser General Public
++ License along with the GNU C Library; if not, write to the Free
++ Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
++ 02111-1307 USA. */
++
++#ifdef _LIBC
++# include <shlib-compat.h>
++versioned_symbol (libc, __regexec, regexec, GLIBC_2_3_4);
++
++# if SHLIB_COMPAT (libc, GLIBC_2_0, GLIBC_2_3_4)
++__typeof__ (__regexec) __compat_regexec;
++
++int
++attribute_compat_text_section
++__compat_regexec (const regex_t *__restrict preg,
++ const char *__restrict string, size_t nmatch,
++ regmatch_t pmatch[], int eflags)
++{
++ return regexec (preg, string, nmatch, pmatch,
++ eflags & (REG_NOTBOL | REG_NOTEOL));
++}
++compat_symbol (libc, __compat_regexec, regexec, GLIBC_2_0);
++# endif
++#endif
+Index: git/posix/regex.h
+===================================================================
+--- git.orig/posix/regex.h 2014-08-29 20:00:53.264070587 -0700
++++ git/posix/regex.h 2014-08-29 20:01:15.224070587 -0700
+@@ -21,6 +21,7 @@
+ #define _REGEX_H 1
+
+ #include <sys/types.h>
++#include <gnu/option-groups.h>
+
+ /* Allow the use in C++ code. */
+ #ifdef __cplusplus
+@@ -156,6 +157,8 @@
+ treated as 'a\{1'. */
+ # define RE_INVALID_INTERVAL_ORD (RE_DEBUG << 1)
+
++/* EGLIBC: Old regex implementation does not support these. */
++# if __OPTION_POSIX_REGEXP_GLIBC
+ /* If this bit is set, then ignore case when matching.
+ If not set, then case is significant. */
+ # define RE_ICASE (RE_INVALID_INTERVAL_ORD << 1)
+@@ -172,6 +175,7 @@
+ /* If this bit is set, then no_sub will be set to 1 during
+ re_compile_pattern. */
+ # define RE_NO_SUB (RE_CONTEXT_INVALID_DUP << 1)
++# endif /* __OPTION_POSIX_REGEXP_GLIBC */
+ #endif
+
+ /* This global variable defines the particular regexp syntax to use (for
+@@ -231,8 +235,13 @@
+ (RE_CHAR_CLASSES | RE_DOT_NEWLINE | RE_DOT_NOT_NULL \
+ | RE_INTERVALS | RE_NO_EMPTY_RANGES)
+
++#if __OPTION_POSIX_REGEXP_GLIBC
+ #define RE_SYNTAX_POSIX_BASIC \
+ (_RE_SYNTAX_POSIX_COMMON | RE_BK_PLUS_QM | RE_CONTEXT_INVALID_DUP)
++#else
++#define RE_SYNTAX_POSIX_BASIC \
++ (_RE_SYNTAX_POSIX_COMMON | RE_BK_PLUS_QM)
++#endif
+
+ /* Differs from ..._POSIX_BASIC only in that RE_BK_PLUS_QM becomes
+ RE_LIMITED_OPS, i.e., \? \+ \| are not recognized. Actually, this
+@@ -298,9 +307,11 @@
+ /* Like REG_NOTBOL, except for the end-of-line. */
+ #define REG_NOTEOL (1 << 1)
+
++#if __OPTION_POSIX_REGEXP_GLIBC
+ /* Use PMATCH[0] to delimit the start and end of the search in the
+ buffer. */
+ #define REG_STARTEND (1 << 2)
++#endif
+
+
+ /* If any error codes are removed, changed, or added, update the
+Index: git/posix/regex_internal.c
+===================================================================
+--- git.orig/posix/regex_internal.c 2014-08-29 20:00:53.264070587 -0700
++++ git/posix/regex_internal.c 2014-08-29 20:01:15.224070587 -0700
+@@ -43,8 +43,8 @@
+ int init_buf_len;
+
+ /* Ensure at least one character fits into the buffers. */
+- if (init_len < dfa->mb_cur_max)
+- init_len = dfa->mb_cur_max;
++ if (init_len < dfa_mb_cur_max (dfa))
++ init_len = dfa_mb_cur_max (dfa);
+ init_buf_len = (len + 1 < init_len) ? len + 1: init_len;
+ re_string_construct_common (str, len, pstr, trans, icase, dfa);
+
+@@ -55,7 +55,7 @@
+ pstr->word_char = dfa->word_char;
+ pstr->word_ops_used = dfa->word_ops_used;
+ pstr->mbs = pstr->mbs_allocated ? pstr->mbs : (unsigned char *) str;
+- pstr->valid_len = (pstr->mbs_allocated || dfa->mb_cur_max > 1) ? 0 : len;
++ pstr->valid_len = (pstr->mbs_allocated || dfa_mb_cur_max (dfa) > 1) ? 0 : len;
+ pstr->valid_raw_len = pstr->valid_len;
+ return REG_NOERROR;
+ }
+@@ -82,7 +82,7 @@
+ if (icase)
+ {
+ #ifdef RE_ENABLE_I18N
+- if (dfa->mb_cur_max > 1)
++ if (dfa_mb_cur_max (dfa) > 1)
+ {
+ while (1)
+ {
+@@ -91,7 +91,7 @@
+ return ret;
+ if (pstr->valid_raw_len >= len)
+ break;
+- if (pstr->bufs_len > pstr->valid_len + dfa->mb_cur_max)
++ if (pstr->bufs_len > pstr->valid_len + dfa_mb_cur_max (dfa))
+ break;
+ ret = re_string_realloc_buffers (pstr, pstr->bufs_len * 2);
+ if (BE (ret != REG_NOERROR, 0))
+@@ -105,7 +105,7 @@
+ else
+ {
+ #ifdef RE_ENABLE_I18N
+- if (dfa->mb_cur_max > 1)
++ if (dfa_mb_cur_max (dfa) > 1)
+ build_wcs_buffer (pstr);
+ else
+ #endif /* RE_ENABLE_I18N */
+@@ -130,7 +130,7 @@
+ re_string_realloc_buffers (re_string_t *pstr, int new_buf_len)
+ {
+ #ifdef RE_ENABLE_I18N
+- if (pstr->mb_cur_max > 1)
++ if (string_mb_cur_max (pstr) > 1)
+ {
+ wint_t *new_wcs;
+
+@@ -177,7 +177,7 @@
+ pstr->trans = trans;
+ pstr->icase = icase ? 1 : 0;
+ pstr->mbs_allocated = (trans != NULL || icase);
+- pstr->mb_cur_max = dfa->mb_cur_max;
++ pstr->mb_cur_max = dfa_mb_cur_max (dfa);
+ pstr->is_utf8 = dfa->is_utf8;
+ pstr->map_notascii = dfa->map_notascii;
+ pstr->stop = pstr->len;
+@@ -203,7 +203,7 @@
+ {
+ #ifdef _LIBC
+ unsigned char buf[MB_LEN_MAX];
+- assert (MB_LEN_MAX >= pstr->mb_cur_max);
++ assert (MB_LEN_MAX >= string_mb_cur_max (pstr));
+ #else
+ unsigned char buf[64];
+ #endif
+@@ -226,7 +226,7 @@
+ {
+ int i, ch;
+
+- for (i = 0; i < pstr->mb_cur_max && i < remain_len; ++i)
++ for (i = 0; i < string_mb_cur_max (pstr) && i < remain_len; ++i)
+ {
+ ch = pstr->raw_mbs [pstr->raw_mbs_idx + byte_idx + i];
+ buf[i] = pstr->mbs[byte_idx + i] = pstr->trans[ch];
+@@ -275,7 +275,7 @@
+ size_t mbclen;
+ #ifdef _LIBC
+ char buf[MB_LEN_MAX];
+- assert (MB_LEN_MAX >= pstr->mb_cur_max);
++ assert (MB_LEN_MAX >= string_mb_cur_max (pstr));
+ #else
+ char buf[64];
+ #endif
+@@ -369,7 +369,7 @@
+ {
+ int i, ch;
+
+- for (i = 0; i < pstr->mb_cur_max && i < remain_len; ++i)
++ for (i = 0; i < string_mb_cur_max (pstr) && i < remain_len; ++i)
+ {
+ ch = pstr->raw_mbs [pstr->raw_mbs_idx + src_idx + i];
+ buf[i] = pstr->trans[ch];
+@@ -567,8 +567,9 @@
+ }
+
+ /* This function re-construct the buffers.
+- Concretely, convert to wide character in case of pstr->mb_cur_max > 1,
+- convert to upper case in case of REG_ICASE, apply translation. */
++ Concretely, convert to wide character in case of
++ string_mb_cur_max (pstr) > 1, convert to upper case in case of
++ REG_ICASE, apply translation. */
+
+ static reg_errcode_t
+ internal_function __attribute_warn_unused_result__
+@@ -579,7 +580,7 @@
+ {
+ /* Reset buffer. */
+ #ifdef RE_ENABLE_I18N
+- if (pstr->mb_cur_max > 1)
++ if (string_mb_cur_max (pstr) > 1)
+ memset (&pstr->cur_state, '\0', sizeof (mbstate_t));
+ #endif /* RE_ENABLE_I18N */
+ pstr->len = pstr->raw_len;
+@@ -670,7 +671,7 @@
+ pstr->tip_context = re_string_context_at (pstr, offset - 1,
+ eflags);
+ #ifdef RE_ENABLE_I18N
+- if (pstr->mb_cur_max > 1)
++ if (string_mb_cur_max (pstr) > 1)
+ memmove (pstr->wcs, pstr->wcs + offset,
+ (pstr->valid_len - offset) * sizeof (wint_t));
+ #endif /* RE_ENABLE_I18N */
+@@ -699,7 +700,7 @@
+ #endif
+ pstr->valid_len = 0;
+ #ifdef RE_ENABLE_I18N
+- if (pstr->mb_cur_max > 1)
++ if (string_mb_cur_max (pstr) > 1)
+ {
+ int wcs_idx;
+ wint_t wc = WEOF;
+@@ -711,7 +712,7 @@
+ /* Special case UTF-8. Multi-byte chars start with any
+ byte other than 0x80 - 0xbf. */
+ raw = pstr->raw_mbs + pstr->raw_mbs_idx;
+- end = raw + (offset - pstr->mb_cur_max);
++ end = raw + (offset - string_mb_cur_max (pstr));
+ if (end < pstr->raw_mbs)
+ end = pstr->raw_mbs;
+ p = raw + offset - 1;
+@@ -803,7 +804,7 @@
+
+ /* Then build the buffers. */
+ #ifdef RE_ENABLE_I18N
+- if (pstr->mb_cur_max > 1)
++ if (string_mb_cur_max (pstr) > 1)
+ {
+ if (pstr->icase)
+ {
+@@ -841,7 +842,7 @@
+ return re_string_peek_byte (pstr, idx);
+
+ #ifdef RE_ENABLE_I18N
+- if (pstr->mb_cur_max > 1
++ if (string_mb_cur_max (pstr) > 1
+ && ! re_string_is_single_byte_char (pstr, pstr->cur_idx + idx))
+ return re_string_peek_byte (pstr, idx);
+ #endif
+@@ -930,7 +931,7 @@
+ return ((eflags & REG_NOTEOL) ? CONTEXT_ENDBUF
+ : CONTEXT_NEWLINE | CONTEXT_ENDBUF);
+ #ifdef RE_ENABLE_I18N
+- if (input->mb_cur_max > 1)
++ if (string_mb_cur_max (input) > 1)
+ {
+ wint_t wc;
+ int wc_idx = idx;
+@@ -1444,7 +1445,7 @@
+ dfa->nodes[dfa->nodes_len].constraint = 0;
+ #ifdef RE_ENABLE_I18N
+ dfa->nodes[dfa->nodes_len].accept_mb =
+- (type == OP_PERIOD && dfa->mb_cur_max > 1) || type == COMPLEX_BRACKET;
++ (type == OP_PERIOD && dfa_mb_cur_max (dfa) > 1) || type == COMPLEX_BRACKET;
+ #endif
+ dfa->nexts[dfa->nodes_len] = -1;
+ re_node_set_init_empty (dfa->edests + dfa->nodes_len);
+Index: git/posix/regex_internal.h
+===================================================================
+--- git.orig/posix/regex_internal.h 2014-08-29 20:00:53.264070587 -0700
++++ git/posix/regex_internal.h 2014-08-29 20:01:15.224070587 -0700
+@@ -26,6 +26,10 @@
+ #include <stdlib.h>
+ #include <string.h>
+
++#if defined _LIBC
++# include <gnu/option-groups.h>
++#endif
++
+ #if defined HAVE_LANGINFO_H || defined HAVE_LANGINFO_CODESET || defined _LIBC
+ # include <langinfo.h>
+ #endif
+@@ -370,6 +374,13 @@
+ };
+ typedef struct re_string_t re_string_t;
+
++/* When OPTION_EGLIBC_LOCALE_CODE is disabled, this is always 1;
++ help the compiler make use of that fact. */
++#if __OPTION_EGLIBC_LOCALE_CODE
++# define string_mb_cur_max(str) ((str)->mb_cur_max + 0)
++#else
++# define string_mb_cur_max(str) (1)
++#endif
+
+ struct re_dfa_t;
+ typedef struct re_dfa_t re_dfa_t;
+@@ -655,6 +666,14 @@
+ __libc_lock_define (, lock)
+ };
+
++/* When OPTION_EGLIBC_LOCALE_CODE is disabled, this is always 1;
++ help the compiler make use of that fact. */
++#if __OPTION_EGLIBC_LOCALE_CODE
++# define dfa_mb_cur_max(dfa) ((dfa)->mb_cur_max + 0)
++#else
++# define dfa_mb_cur_max(dfa) (1)
++#endif
++
+ #define re_node_set_init_empty(set) memset (set, '\0', sizeof (re_node_set))
+ #define re_node_set_remove(set,id) \
+ (re_node_set_remove_at (set, re_node_set_contains (set, id) - 1))
+@@ -715,7 +734,7 @@
+ re_string_char_size_at (const re_string_t *pstr, int idx)
+ {
+ int byte_idx;
+- if (pstr->mb_cur_max == 1)
++ if (string_mb_cur_max (pstr) == 1)
+ return 1;
+ for (byte_idx = 1; idx + byte_idx < pstr->valid_len; ++byte_idx)
+ if (pstr->wcs[idx + byte_idx] != WEOF)
+@@ -727,7 +746,7 @@
+ internal_function __attribute__ ((pure, unused))
+ re_string_wchar_at (const re_string_t *pstr, int idx)
+ {
+- if (pstr->mb_cur_max == 1)
++ if (string_mb_cur_max (pstr) == 1)
+ return (wint_t) pstr->mbs[idx];
+ return (wint_t) pstr->wcs[idx];
+ }
+Index: git/posix/xregex.c
+===================================================================
+--- /dev/null 1970-01-01 00:00:00.000000000 +0000
++++ git/posix/xregex.c 2014-08-29 20:01:15.228070587 -0700
+@@ -0,0 +1,8212 @@
++/* Extended regular expression matching and search library,
++ version 0.12.
++ (Implements POSIX draft P1003.2/D11.2, except for some of the
++ internationalization features.)
++
++ Copyright (C) 1993, 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001,
++ 2002, 2005 Free Software Foundation, Inc.
++ This file is part of the GNU C Library.
++
++ The GNU C Library is free software; you can redistribute it and/or
++ modify it under the terms of the GNU Lesser General Public
++ License as published by the Free Software Foundation; either
++ version 2.1 of the License, or (at your option) any later version.
++
++ The GNU C Library is distributed in the hope that it will be useful,
++ but WITHOUT ANY WARRANTY; without even the implied warranty of
++ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
++ Lesser General Public License for more details.
++
++ You should have received a copy of the GNU Lesser General Public
++ License along with the GNU C Library; if not, write to the Free
++ Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
++ 02110-1301 USA. */
++
++/* AIX requires this to be the first thing in the file. */
++#if defined _AIX && !defined __GNUC__ && !defined REGEX_MALLOC
++ #pragma alloca
++#endif
++
++#undef _GNU_SOURCE
++#define _GNU_SOURCE
++
++#ifndef INSIDE_RECURSION
++# ifdef HAVE_CONFIG_H
++# include <config.h>
++# endif
++#endif
++
++/*#include <ansidecl.h>*/
++
++#ifndef INSIDE_RECURSION
++
++# if defined STDC_HEADERS && !defined emacs
++# include <stddef.h>
++# else
++/* We need this for `regex.h', and perhaps for the Emacs include files. */
++# include <sys/types.h>
++# endif
++
++# define WIDE_CHAR_SUPPORT (HAVE_WCTYPE_H && HAVE_WCHAR_H && HAVE_BTOWC)
++
++/* For platform which support the ISO C amendement 1 functionality we
++ support user defined character classes. */
++# if WIDE_CHAR_SUPPORT
++/* Solaris 2.5 has a bug: <wchar.h> must be included before <wctype.h>. */
++# include <wchar.h>
++# include <wctype.h>
++# endif
++
++# ifdef _LIBC
++/* We have to keep the namespace clean. */
++# define regfree(preg) __regfree (preg)
++# define regexec(pr, st, nm, pm, ef) __regexec (pr, st, nm, pm, ef)
++# define regcomp(preg, pattern, cflags) __regcomp (preg, pattern, cflags)
++# define regerror(errcode, preg, errbuf, errbuf_size) \
++ __regerror(errcode, preg, errbuf, errbuf_size)
++# define re_set_registers(bu, re, nu, st, en) \
++ __re_set_registers (bu, re, nu, st, en)
++# define re_match_2(bufp, string1, size1, string2, size2, pos, regs, stop) \
++ __re_match_2 (bufp, string1, size1, string2, size2, pos, regs, stop)
++# define re_match(bufp, string, size, pos, regs) \
++ __re_match (bufp, string, size, pos, regs)
++# define re_search(bufp, string, size, startpos, range, regs) \
++ __re_search (bufp, string, size, startpos, range, regs)
++# define re_compile_pattern(pattern, length, bufp) \
++ __re_compile_pattern (pattern, length, bufp)
++# define re_set_syntax(syntax) __re_set_syntax (syntax)
++# define re_search_2(bufp, st1, s1, st2, s2, startpos, range, regs, stop) \
++ __re_search_2 (bufp, st1, s1, st2, s2, startpos, range, regs, stop)
++# define re_compile_fastmap(bufp) __re_compile_fastmap (bufp)
++
++# define btowc __btowc
++
++/* We are also using some library internals. */
++# include <locale/localeinfo.h>
++# include <locale/elem-hash.h>
++# include <langinfo.h>
++# include <locale/coll-lookup.h>
++# endif
++
++/* This is for other GNU distributions with internationalized messages. */
++# if (HAVE_LIBINTL_H && ENABLE_NLS) || defined _LIBC
++# include <libintl.h>
++# ifdef _LIBC
++# undef gettext
++# define gettext(msgid) __dcgettext ("libc", msgid, LC_MESSAGES)
++# endif
++# else
++# define gettext(msgid) (msgid)
++# endif
++
++# ifndef gettext_noop
++/* This define is so xgettext can find the internationalizable
++ strings. */
++# define gettext_noop(String) String
++# endif
++
++/* The `emacs' switch turns on certain matching commands
++ that make sense only in Emacs. */
++# ifdef emacs
++
++# include "lisp.h"
++# include "buffer.h"
++# include "syntax.h"
++
++# else /* not emacs */
++
++/* If we are not linking with Emacs proper,
++ we can't use the relocating allocator
++ even if config.h says that we can. */
++# undef REL_ALLOC
++
++# if defined STDC_HEADERS || defined _LIBC
++# include <stdlib.h>
++# else
++char *malloc ();
++char *realloc ();
++# endif
++
++/* When used in Emacs's lib-src, we need to get bzero and bcopy somehow.
++ If nothing else has been done, use the method below. */
++# ifdef INHIBIT_STRING_HEADER
++# if !(defined HAVE_BZERO && defined HAVE_BCOPY)
++# if !defined bzero && !defined bcopy
++# undef INHIBIT_STRING_HEADER
++# endif
++# endif
++# endif
++
++/* This is the normal way of making sure we have a bcopy and a bzero.
++ This is used in most programs--a few other programs avoid this
++ by defining INHIBIT_STRING_HEADER. */
++# ifndef INHIBIT_STRING_HEADER
++# if defined HAVE_STRING_H || defined STDC_HEADERS || defined _LIBC
++# include <string.h>
++# ifndef bzero
++# ifndef _LIBC
++# define bzero(s, n) (memset (s, '\0', n), (s))
++# else
++# define bzero(s, n) __bzero (s, n)
++# endif
++# endif
++# else
++# include <strings.h>
++# ifndef memcmp
++# define memcmp(s1, s2, n) bcmp (s1, s2, n)
++# endif
++# ifndef memcpy
++# define memcpy(d, s, n) (bcopy (s, d, n), (d))
++# endif
++# endif
++# endif
++
++/* Define the syntax stuff for \<, \>, etc. */
++
++/* This must be nonzero for the wordchar and notwordchar pattern
++ commands in re_match_2. */
++# ifndef Sword
++# define Sword 1
++# endif
++
++# ifdef SWITCH_ENUM_BUG
++# define SWITCH_ENUM_CAST(x) ((int)(x))
++# else
++# define SWITCH_ENUM_CAST(x) (x)
++# endif
++
++# endif /* not emacs */
++
++# if defined _LIBC || HAVE_LIMITS_H
++# include <limits.h>
++# endif
++
++# ifndef MB_LEN_MAX
++# define MB_LEN_MAX 1
++# endif
++
++/* Get the interface, including the syntax bits. */
++# include "regex.h"
++
++/* isalpha etc. are used for the character classes. */
++# include <ctype.h>
++
++/* Jim Meyering writes:
++
++ "... Some ctype macros are valid only for character codes that
++ isascii says are ASCII (SGI's IRIX-4.0.5 is one such system --when
++ using /bin/cc or gcc but without giving an ansi option). So, all
++ ctype uses should be through macros like ISPRINT... If
++ STDC_HEADERS is defined, then autoconf has verified that the ctype
++ macros don't need to be guarded with references to isascii. ...
++ Defining isascii to 1 should let any compiler worth its salt
++ eliminate the && through constant folding."
++ Solaris defines some of these symbols so we must undefine them first. */
++
++# undef ISASCII
++# if defined STDC_HEADERS || (!defined isascii && !defined HAVE_ISASCII)
++# define ISASCII(c) 1
++# else
++# define ISASCII(c) isascii(c)
++# endif
++
++# ifdef isblank
++# define ISBLANK(c) (ISASCII (c) && isblank (c))
++# else
++# define ISBLANK(c) ((c) == ' ' || (c) == '\t')
++# endif
++# ifdef isgraph
++# define ISGRAPH(c) (ISASCII (c) && isgraph (c))
++# else
++# define ISGRAPH(c) (ISASCII (c) && isprint (c) && !isspace (c))
++# endif
++
++# undef ISPRINT
++# define ISPRINT(c) (ISASCII (c) && isprint (c))
++# define ISDIGIT(c) (ISASCII (c) && isdigit (c))
++# define ISALNUM(c) (ISASCII (c) && isalnum (c))
++# define ISALPHA(c) (ISASCII (c) && isalpha (c))
++# define ISCNTRL(c) (ISASCII (c) && iscntrl (c))
++# define ISLOWER(c) (ISASCII (c) && islower (c))
++# define ISPUNCT(c) (ISASCII (c) && ispunct (c))
++# define ISSPACE(c) (ISASCII (c) && isspace (c))
++# define ISUPPER(c) (ISASCII (c) && isupper (c))
++# define ISXDIGIT(c) (ISASCII (c) && isxdigit (c))
++
++# ifdef _tolower
++# define TOLOWER(c) _tolower(c)
++# else
++# define TOLOWER(c) tolower(c)
++# endif
++
++# ifndef NULL
++# define NULL (void *)0
++# endif
++
++/* We remove any previous definition of `SIGN_EXTEND_CHAR',
++ since ours (we hope) works properly with all combinations of
++ machines, compilers, `char' and `unsigned char' argument types.
++ (Per Bothner suggested the basic approach.) */
++# undef SIGN_EXTEND_CHAR
++# if __STDC__
++# define SIGN_EXTEND_CHAR(c) ((signed char) (c))
++# else /* not __STDC__ */
++/* As in Harbison and Steele. */
++# define SIGN_EXTEND_CHAR(c) ((((unsigned char) (c)) ^ 128) - 128)
++# endif
++
++# ifndef emacs
++/* How many characters in the character set. */
++# define CHAR_SET_SIZE 256
++
++# ifdef SYNTAX_TABLE
++
++extern char *re_syntax_table;
++
++# else /* not SYNTAX_TABLE */
++
++static char re_syntax_table[CHAR_SET_SIZE];
++
++static void init_syntax_once (void);
++
++static void
++init_syntax_once (void)
++{
++ register int c;
++ static int done = 0;
++
++ if (done)
++ return;
++ bzero (re_syntax_table, sizeof re_syntax_table);
++
++ for (c = 0; c < CHAR_SET_SIZE; ++c)
++ if (ISALNUM (c))
++ re_syntax_table[c] = Sword;
++
++ re_syntax_table['_'] = Sword;
++
++ done = 1;
++}
++
++# endif /* not SYNTAX_TABLE */
++
++# define SYNTAX(c) re_syntax_table[(unsigned char) (c)]
++
++# endif /* emacs */
++
++/* Integer type for pointers. */
++# if !defined _LIBC && !defined HAVE_UINTPTR_T
++typedef unsigned long int uintptr_t;
++# endif
++
++/* Should we use malloc or alloca? If REGEX_MALLOC is not defined, we
++ use `alloca' instead of `malloc'. This is because using malloc in
++ re_search* or re_match* could cause memory leaks when C-g is used in
++ Emacs; also, malloc is slower and causes storage fragmentation. On
++ the other hand, malloc is more portable, and easier to debug.
++
++ Because we sometimes use alloca, some routines have to be macros,
++ not functions -- `alloca'-allocated space disappears at the end of the
++ function it is called in. */
++
++# ifdef REGEX_MALLOC
++
++# define REGEX_ALLOCATE malloc
++# define REGEX_REALLOCATE(source, osize, nsize) realloc (source, nsize)
++# define REGEX_FREE free
++
++# else /* not REGEX_MALLOC */
++
++/* Emacs already defines alloca, sometimes. */
++# ifndef alloca
++
++/* Make alloca work the best possible way. */
++# ifdef __GNUC__
++# define alloca __builtin_alloca
++# else /* not __GNUC__ */
++# if HAVE_ALLOCA_H
++# include <alloca.h>
++# endif /* HAVE_ALLOCA_H */
++# endif /* not __GNUC__ */
++
++# endif /* not alloca */
++
++# define REGEX_ALLOCATE alloca
++
++/* Assumes a `char *destination' variable. */
++# define REGEX_REALLOCATE(source, osize, nsize) \
++ (destination = (char *) alloca (nsize), \
++ memcpy (destination, source, osize))
++
++/* No need to do anything to free, after alloca. */
++# define REGEX_FREE(arg) ((void)0) /* Do nothing! But inhibit gcc warning. */
++
++# endif /* not REGEX_MALLOC */
++
++/* Define how to allocate the failure stack. */
++
++# if defined REL_ALLOC && defined REGEX_MALLOC
++
++# define REGEX_ALLOCATE_STACK(size) \
++ r_alloc (&failure_stack_ptr, (size))
++# define REGEX_REALLOCATE_STACK(source, osize, nsize) \
++ r_re_alloc (&failure_stack_ptr, (nsize))
++# define REGEX_FREE_STACK(ptr) \
++ r_alloc_free (&failure_stack_ptr)
++
++# else /* not using relocating allocator */
++
++# ifdef REGEX_MALLOC
++
++# define REGEX_ALLOCATE_STACK malloc
++# define REGEX_REALLOCATE_STACK(source, osize, nsize) realloc (source, nsize)
++# define REGEX_FREE_STACK free
++
++# else /* not REGEX_MALLOC */
++
++# define REGEX_ALLOCATE_STACK alloca
++
++# define REGEX_REALLOCATE_STACK(source, osize, nsize) \
++ REGEX_REALLOCATE (source, osize, nsize)
++/* No need to explicitly free anything. */
++# define REGEX_FREE_STACK(arg)
++
++# endif /* not REGEX_MALLOC */
++# endif /* not using relocating allocator */
++
++
++/* True if `size1' is non-NULL and PTR is pointing anywhere inside
++ `string1' or just past its end. This works if PTR is NULL, which is
++ a good thing. */
++# define FIRST_STRING_P(ptr) \
++ (size1 && string1 <= (ptr) && (ptr) <= string1 + size1)
++
++/* (Re)Allocate N items of type T using malloc, or fail. */
++# define TALLOC(n, t) ((t *) malloc ((n) * sizeof (t)))
++# define RETALLOC(addr, n, t) ((addr) = (t *) realloc (addr, (n) * sizeof (t)))
++# define RETALLOC_IF(addr, n, t) \
++ if (addr) RETALLOC((addr), (n), t); else (addr) = TALLOC ((n), t)
++# define REGEX_TALLOC(n, t) ((t *) REGEX_ALLOCATE ((n) * sizeof (t)))
++
++# define BYTEWIDTH 8 /* In bits. */
++
++# define STREQ(s1, s2) ((strcmp (s1, s2) == 0))
++
++# undef MAX
++# undef MIN
++# define MAX(a, b) ((a) > (b) ? (a) : (b))
++# define MIN(a, b) ((a) < (b) ? (a) : (b))
++
++typedef char boolean;
++# define false 0
++# define true 1
++
++static reg_errcode_t byte_regex_compile (const char *pattern, size_t size,
++ reg_syntax_t syntax,
++ struct re_pattern_buffer *bufp);
++
++static int byte_re_match_2_internal (struct re_pattern_buffer *bufp,
++ const char *string1, int size1,
++ const char *string2, int size2,
++ int pos,
++ struct re_registers *regs,
++ int stop);
++static int byte_re_search_2 (struct re_pattern_buffer *bufp,
++ const char *string1, int size1,
++ const char *string2, int size2,
++ int startpos, int range,
++ struct re_registers *regs, int stop);
++static int byte_re_compile_fastmap (struct re_pattern_buffer *bufp);
++
++#ifdef MBS_SUPPORT
++static reg_errcode_t wcs_regex_compile (const char *pattern, size_t size,
++ reg_syntax_t syntax,
++ struct re_pattern_buffer *bufp);
++
++
++static int wcs_re_match_2_internal (struct re_pattern_buffer *bufp,
++ const char *cstring1, int csize1,
++ const char *cstring2, int csize2,
++ int pos,
++ struct re_registers *regs,
++ int stop,
++ wchar_t *string1, int size1,
++ wchar_t *string2, int size2,
++ int *mbs_offset1, int *mbs_offset2);
++static int wcs_re_search_2 (struct re_pattern_buffer *bufp,
++ const char *string1, int size1,
++ const char *string2, int size2,
++ int startpos, int range,
++ struct re_registers *regs, int stop);
++static int wcs_re_compile_fastmap (struct re_pattern_buffer *bufp);
++#endif
++
++/* These are the command codes that appear in compiled regular
++ expressions. Some opcodes are followed by argument bytes. A
++ command code can specify any interpretation whatsoever for its
++ arguments. Zero bytes may appear in the compiled regular expression. */
++
++typedef enum
++{
++ no_op = 0,
++
++ /* Succeed right away--no more backtracking. */
++ succeed,
++
++ /* Followed by one byte giving n, then by n literal bytes. */
++ exactn,
++
++# ifdef MBS_SUPPORT
++ /* Same as exactn, but contains binary data. */
++ exactn_bin,
++# endif
++
++ /* Matches any (more or less) character. */
++ anychar,
++
++ /* Matches any one char belonging to specified set. First
++ following byte is number of bitmap bytes. Then come bytes
++ for a bitmap saying which chars are in. Bits in each byte
++ are ordered low-bit-first. A character is in the set if its
++ bit is 1. A character too large to have a bit in the map is
++ automatically not in the set. */
++ /* ifdef MBS_SUPPORT, following element is length of character
++ classes, length of collating symbols, length of equivalence
++ classes, length of character ranges, and length of characters.
++ Next, character class element, collating symbols elements,
++ equivalence class elements, range elements, and character
++ elements follow.
++ See regex_compile function. */
++ charset,
++
++ /* Same parameters as charset, but match any character that is
++ not one of those specified. */
++ charset_not,
++
++ /* Start remembering the text that is matched, for storing in a
++ register. Followed by one byte with the register number, in
++ the range 0 to one less than the pattern buffer's re_nsub
++ field. Then followed by one byte with the number of groups
++ inner to this one. (This last has to be part of the
++ start_memory only because we need it in the on_failure_jump
++ of re_match_2.) */
++ start_memory,
++
++ /* Stop remembering the text that is matched and store it in a
++ memory register. Followed by one byte with the register
++ number, in the range 0 to one less than `re_nsub' in the
++ pattern buffer, and one byte with the number of inner groups,
++ just like `start_memory'. (We need the number of inner
++ groups here because we don't have any easy way of finding the
++ corresponding start_memory when we're at a stop_memory.) */
++ stop_memory,
++
++ /* Match a duplicate of something remembered. Followed by one
++ byte containing the register number. */
++ duplicate,
++
++ /* Fail unless at beginning of line. */
++ begline,
++
++ /* Fail unless at end of line. */
++ endline,
++
++ /* Succeeds if at beginning of buffer (if emacs) or at beginning
++ of string to be matched (if not). */
++ begbuf,
++
++ /* Analogously, for end of buffer/string. */
++ endbuf,
++
++ /* Followed by two byte relative address to which to jump. */
++ jump,
++
++ /* Same as jump, but marks the end of an alternative. */
++ jump_past_alt,
++
++ /* Followed by two-byte relative address of place to resume at
++ in case of failure. */
++ /* ifdef MBS_SUPPORT, the size of address is 1. */
++ on_failure_jump,
++
++ /* Like on_failure_jump, but pushes a placeholder instead of the
++ current string position when executed. */
++ on_failure_keep_string_jump,
++
++ /* Throw away latest failure point and then jump to following
++ two-byte relative address. */
++ /* ifdef MBS_SUPPORT, the size of address is 1. */
++ pop_failure_jump,
++
++ /* Change to pop_failure_jump if know won't have to backtrack to
++ match; otherwise change to jump. This is used to jump
++ back to the beginning of a repeat. If what follows this jump
++ clearly won't match what the repeat does, such that we can be
++ sure that there is no use backtracking out of repetitions
++ already matched, then we change it to a pop_failure_jump.
++ Followed by two-byte address. */
++ /* ifdef MBS_SUPPORT, the size of address is 1. */
++ maybe_pop_jump,
++
++ /* Jump to following two-byte address, and push a dummy failure
++ point. This failure point will be thrown away if an attempt
++ is made to use it for a failure. A `+' construct makes this
++ before the first repeat. Also used as an intermediary kind
++ of jump when compiling an alternative. */
++ /* ifdef MBS_SUPPORT, the size of address is 1. */
++ dummy_failure_jump,
++
++ /* Push a dummy failure point and continue. Used at the end of
++ alternatives. */
++ push_dummy_failure,
++
++ /* Followed by two-byte relative address and two-byte number n.
++ After matching N times, jump to the address upon failure. */
++ /* ifdef MBS_SUPPORT, the size of address is 1. */
++ succeed_n,
++
++ /* Followed by two-byte relative address, and two-byte number n.
++ Jump to the address N times, then fail. */
++ /* ifdef MBS_SUPPORT, the size of address is 1. */
++ jump_n,
++
++ /* Set the following two-byte relative address to the
++ subsequent two-byte number. The address *includes* the two
++ bytes of number. */
++ /* ifdef MBS_SUPPORT, the size of address is 1. */
++ set_number_at,
++
++ wordchar, /* Matches any word-constituent character. */
++ notwordchar, /* Matches any char that is not a word-constituent. */
++
++ wordbeg, /* Succeeds if at word beginning. */
++ wordend, /* Succeeds if at word end. */
++
++ wordbound, /* Succeeds if at a word boundary. */
++ notwordbound /* Succeeds if not at a word boundary. */
++
++# ifdef emacs
++ ,before_dot, /* Succeeds if before point. */
++ at_dot, /* Succeeds if at point. */
++ after_dot, /* Succeeds if after point. */
++
++ /* Matches any character whose syntax is specified. Followed by
++ a byte which contains a syntax code, e.g., Sword. */
++ syntaxspec,
++
++ /* Matches any character whose syntax is not that specified. */
++ notsyntaxspec
++# endif /* emacs */
++} re_opcode_t;
++#endif /* not INSIDE_RECURSION */
++
++
++#ifdef BYTE
++# define CHAR_T char
++# define UCHAR_T unsigned char
++# define COMPILED_BUFFER_VAR bufp->buffer
++# define OFFSET_ADDRESS_SIZE 2
++# define PREFIX(name) byte_##name
++# define ARG_PREFIX(name) name
++# define PUT_CHAR(c) putchar (c)
++#else
++# ifdef WCHAR
++# define CHAR_T wchar_t
++# define UCHAR_T wchar_t
++# define COMPILED_BUFFER_VAR wc_buffer
++# define OFFSET_ADDRESS_SIZE 1 /* the size which STORE_NUMBER macro use */
++# define CHAR_CLASS_SIZE ((__alignof__(wctype_t)+sizeof(wctype_t))/sizeof(CHAR_T)+1)
++# define PREFIX(name) wcs_##name
++# define ARG_PREFIX(name) c##name
++/* Should we use wide stream?? */
++# define PUT_CHAR(c) printf ("%C", c);
++# define TRUE 1
++# define FALSE 0
++# else
++# ifdef MBS_SUPPORT
++# define WCHAR
++# define INSIDE_RECURSION
++# include "xregex.c"
++# undef INSIDE_RECURSION
++# endif
++# define BYTE
++# define INSIDE_RECURSION
++# include "xregex.c"
++# undef INSIDE_RECURSION
++# endif
++#endif
++
++#ifdef INSIDE_RECURSION
++/* Common operations on the compiled pattern. */
++
++/* Store NUMBER in two contiguous bytes starting at DESTINATION. */
++/* ifdef MBS_SUPPORT, we store NUMBER in 1 element. */
++
++# ifdef WCHAR
++# define STORE_NUMBER(destination, number) \
++ do { \
++ *(destination) = (UCHAR_T)(number); \
++ } while (0)
++# else /* BYTE */
++# define STORE_NUMBER(destination, number) \
++ do { \
++ (destination)[0] = (number) & 0377; \
++ (destination)[1] = (number) >> 8; \
++ } while (0)
++# endif /* WCHAR */
++
++/* Same as STORE_NUMBER, except increment DESTINATION to
++ the byte after where the number is stored. Therefore, DESTINATION
++ must be an lvalue. */
++/* ifdef MBS_SUPPORT, we store NUMBER in 1 element. */
++
++# define STORE_NUMBER_AND_INCR(destination, number) \
++ do { \
++ STORE_NUMBER (destination, number); \
++ (destination) += OFFSET_ADDRESS_SIZE; \
++ } while (0)
++
++/* Put into DESTINATION a number stored in two contiguous bytes starting
++ at SOURCE. */
++/* ifdef MBS_SUPPORT, we store NUMBER in 1 element. */
++
++# ifdef WCHAR
++# define EXTRACT_NUMBER(destination, source) \
++ do { \
++ (destination) = *(source); \
++ } while (0)
++# else /* BYTE */
++# define EXTRACT_NUMBER(destination, source) \
++ do { \
++ (destination) = *(source) & 0377; \
++ (destination) += SIGN_EXTEND_CHAR (*((source) + 1)) << 8; \
++ } while (0)
++# endif
++
++# ifdef DEBUG
++static void PREFIX(extract_number) (int *dest, UCHAR_T *source);
++static void
++PREFIX(extract_number) (int *dest, UCHAR_T *source)
++{
++# ifdef WCHAR
++ *dest = *source;
++# else /* BYTE */
++ int temp = SIGN_EXTEND_CHAR (*(source + 1));
++ *dest = *source & 0377;
++ *dest += temp << 8;
++# endif
++}
++
++# ifndef EXTRACT_MACROS /* To debug the macros. */
++# undef EXTRACT_NUMBER
++# define EXTRACT_NUMBER(dest, src) PREFIX(extract_number) (&dest, src)
++# endif /* not EXTRACT_MACROS */
++
++# endif /* DEBUG */
++
++/* Same as EXTRACT_NUMBER, except increment SOURCE to after the number.
++ SOURCE must be an lvalue. */
++
++# define EXTRACT_NUMBER_AND_INCR(destination, source) \
++ do { \
++ EXTRACT_NUMBER (destination, source); \
++ (source) += OFFSET_ADDRESS_SIZE; \
++ } while (0)
++
++# ifdef DEBUG
++static void PREFIX(extract_number_and_incr) (int *destination,
++ UCHAR_T **source);
++static void
++PREFIX(extract_number_and_incr) (int *destination, UCHAR_T **source)
++{
++ PREFIX(extract_number) (destination, *source);
++ *source += OFFSET_ADDRESS_SIZE;
++}
++
++# ifndef EXTRACT_MACROS
++# undef EXTRACT_NUMBER_AND_INCR
++# define EXTRACT_NUMBER_AND_INCR(dest, src) \
++ PREFIX(extract_number_and_incr) (&dest, &src)
++# endif /* not EXTRACT_MACROS */
++
++# endif /* DEBUG */
++
++
++
++/* If DEBUG is defined, Regex prints many voluminous messages about what
++ it is doing (if the variable `debug' is nonzero). If linked with the
++ main program in `iregex.c', you can enter patterns and strings
++ interactively. And if linked with the main program in `main.c' and
++ the other test files, you can run the already-written tests. */
++
++# ifdef DEBUG
++
++# ifndef DEFINED_ONCE
++
++/* We use standard I/O for debugging. */
++# include <stdio.h>
++
++/* It is useful to test things that ``must'' be true when debugging. */
++# include <assert.h>
++
++static int debug;
++
++# define DEBUG_STATEMENT(e) e
++# define DEBUG_PRINT1(x) if (debug) printf (x)
++# define DEBUG_PRINT2(x1, x2) if (debug) printf (x1, x2)
++# define DEBUG_PRINT3(x1, x2, x3) if (debug) printf (x1, x2, x3)
++# define DEBUG_PRINT4(x1, x2, x3, x4) if (debug) printf (x1, x2, x3, x4)
++# endif /* not DEFINED_ONCE */
++
++# define DEBUG_PRINT_COMPILED_PATTERN(p, s, e) \
++ if (debug) PREFIX(print_partial_compiled_pattern) (s, e)
++# define DEBUG_PRINT_DOUBLE_STRING(w, s1, sz1, s2, sz2) \
++ if (debug) PREFIX(print_double_string) (w, s1, sz1, s2, sz2)
++
++
++/* Print the fastmap in human-readable form. */
++
++# ifndef DEFINED_ONCE
++void
++print_fastmap (char *fastmap)
++{
++ unsigned was_a_range = 0;
++ unsigned i = 0;
++
++ while (i < (1 << BYTEWIDTH))
++ {
++ if (fastmap[i++])
++ {
++ was_a_range = 0;
++ putchar (i - 1);
++ while (i < (1 << BYTEWIDTH) && fastmap[i])
++ {
++ was_a_range = 1;
++ i++;
++ }
++ if (was_a_range)
++ {
++ printf ("-");
++ putchar (i - 1);
++ }
++ }
++ }
++ putchar ('\n');
++}
++# endif /* not DEFINED_ONCE */
++
++
++/* Print a compiled pattern string in human-readable form, starting at
++ the START pointer into it and ending just before the pointer END. */
++
++void
++PREFIX(print_partial_compiled_pattern) (UCHAR_T *start, UCHAR_T *end)
++{
++ int mcnt, mcnt2;
++ UCHAR_T *p1;
++ UCHAR_T *p = start;
++ UCHAR_T *pend = end;
++
++ if (start == NULL)
++ {
++ printf ("(null)\n");
++ return;
++ }
++
++ /* Loop over pattern commands. */
++ while (p < pend)
++ {
++# ifdef _LIBC
++ printf ("%td:\t", p - start);
++# else
++ printf ("%ld:\t", (long int) (p - start));
++# endif
++
++ switch ((re_opcode_t) *p++)
++ {
++ case no_op:
++ printf ("/no_op");
++ break;
++
++ case exactn:
++ mcnt = *p++;
++ printf ("/exactn/%d", mcnt);
++ do
++ {
++ putchar ('/');
++ PUT_CHAR (*p++);
++ }
++ while (--mcnt);
++ break;
++
++# ifdef MBS_SUPPORT
++ case exactn_bin:
++ mcnt = *p++;
++ printf ("/exactn_bin/%d", mcnt);
++ do
++ {
++ printf("/%lx", (long int) *p++);
++ }
++ while (--mcnt);
++ break;
++# endif /* MBS_SUPPORT */
++
++ case start_memory:
++ mcnt = *p++;
++ printf ("/start_memory/%d/%ld", mcnt, (long int) *p++);
++ break;
++
++ case stop_memory:
++ mcnt = *p++;
++ printf ("/stop_memory/%d/%ld", mcnt, (long int) *p++);
++ break;
++
++ case duplicate:
++ printf ("/duplicate/%ld", (long int) *p++);
++ break;
++
++ case anychar:
++ printf ("/anychar");
++ break;
++
++ case charset:
++ case charset_not:
++ {
++# ifdef WCHAR
++ int i, length;
++ wchar_t *workp = p;
++ printf ("/charset [%s",
++ (re_opcode_t) *(workp - 1) == charset_not ? "^" : "");
++ p += 5;
++ length = *workp++; /* the length of char_classes */
++ for (i=0 ; i<length ; i++)
++ printf("[:%lx:]", (long int) *p++);
++ length = *workp++; /* the length of collating_symbol */
++ for (i=0 ; i<length ;)
++ {
++ printf("[.");
++ while(*p != 0)
++ PUT_CHAR((i++,*p++));
++ i++,p++;
++ printf(".]");
++ }
++ length = *workp++; /* the length of equivalence_class */
++ for (i=0 ; i<length ;)
++ {
++ printf("[=");
++ while(*p != 0)
++ PUT_CHAR((i++,*p++));
++ i++,p++;
++ printf("=]");
++ }
++ length = *workp++; /* the length of char_range */
++ for (i=0 ; i<length ; i++)
++ {
++ wchar_t range_start = *p++;
++ wchar_t range_end = *p++;
++ printf("%C-%C", range_start, range_end);
++ }
++ length = *workp++; /* the length of char */
++ for (i=0 ; i<length ; i++)
++ printf("%C", *p++);
++ putchar (']');
++# else
++ register int c, last = -100;
++ register int in_range = 0;
++
++ printf ("/charset [%s",
++ (re_opcode_t) *(p - 1) == charset_not ? "^" : "");
++
++ assert (p + *p < pend);
++
++ for (c = 0; c < 256; c++)
++ if (c / 8 < *p
++ && (p[1 + (c/8)] & (1 << (c % 8))))
++ {
++ /* Are we starting a range? */
++ if (last + 1 == c && ! in_range)
++ {
++ putchar ('-');
++ in_range = 1;
++ }
++ /* Have we broken a range? */
++ else if (last + 1 != c && in_range)
++ {
++ putchar (last);
++ in_range = 0;
++ }
++
++ if (! in_range)
++ putchar (c);
++
++ last = c;
++ }
++
++ if (in_range)
++ putchar (last);
++
++ putchar (']');
++
++ p += 1 + *p;
++# endif /* WCHAR */
++ }
++ break;
++
++ case begline:
++ printf ("/begline");
++ break;
++
++ case endline:
++ printf ("/endline");
++ break;
++
++ case on_failure_jump:
++ PREFIX(extract_number_and_incr) (&mcnt, &p);
++# ifdef _LIBC
++ printf ("/on_failure_jump to %td", p + mcnt - start);
++# else
++ printf ("/on_failure_jump to %ld", (long int) (p + mcnt - start));
++# endif
++ break;
++
++ case on_failure_keep_string_jump:
++ PREFIX(extract_number_and_incr) (&mcnt, &p);
++# ifdef _LIBC
++ printf ("/on_failure_keep_string_jump to %td", p + mcnt - start);
++# else
++ printf ("/on_failure_keep_string_jump to %ld",
++ (long int) (p + mcnt - start));
++# endif
++ break;
++
++ case dummy_failure_jump:
++ PREFIX(extract_number_and_incr) (&mcnt, &p);
++# ifdef _LIBC
++ printf ("/dummy_failure_jump to %td", p + mcnt - start);
++# else
++ printf ("/dummy_failure_jump to %ld", (long int) (p + mcnt - start));
++# endif
++ break;
++
++ case push_dummy_failure:
++ printf ("/push_dummy_failure");
++ break;
++
++ case maybe_pop_jump:
++ PREFIX(extract_number_and_incr) (&mcnt, &p);
++# ifdef _LIBC
++ printf ("/maybe_pop_jump to %td", p + mcnt - start);
++# else
++ printf ("/maybe_pop_jump to %ld", (long int) (p + mcnt - start));
++# endif
++ break;
++
++ case pop_failure_jump:
++ PREFIX(extract_number_and_incr) (&mcnt, &p);
++# ifdef _LIBC
++ printf ("/pop_failure_jump to %td", p + mcnt - start);
++# else
++ printf ("/pop_failure_jump to %ld", (long int) (p + mcnt - start));
++# endif
++ break;
++
++ case jump_past_alt:
++ PREFIX(extract_number_and_incr) (&mcnt, &p);
++# ifdef _LIBC
++ printf ("/jump_past_alt to %td", p + mcnt - start);
++# else
++ printf ("/jump_past_alt to %ld", (long int) (p + mcnt - start));
++# endif
++ break;
++
++ case jump:
++ PREFIX(extract_number_and_incr) (&mcnt, &p);
++# ifdef _LIBC
++ printf ("/jump to %td", p + mcnt - start);
++# else
++ printf ("/jump to %ld", (long int) (p + mcnt - start));
++# endif
++ break;
++
++ case succeed_n:
++ PREFIX(extract_number_and_incr) (&mcnt, &p);
++ p1 = p + mcnt;
++ PREFIX(extract_number_and_incr) (&mcnt2, &p);
++# ifdef _LIBC
++ printf ("/succeed_n to %td, %d times", p1 - start, mcnt2);
++# else
++ printf ("/succeed_n to %ld, %d times",
++ (long int) (p1 - start), mcnt2);
++# endif
++ break;
++
++ case jump_n:
++ PREFIX(extract_number_and_incr) (&mcnt, &p);
++ p1 = p + mcnt;
++ PREFIX(extract_number_and_incr) (&mcnt2, &p);
++ printf ("/jump_n to %d, %d times", p1 - start, mcnt2);
++ break;
++
++ case set_number_at:
++ PREFIX(extract_number_and_incr) (&mcnt, &p);
++ p1 = p + mcnt;
++ PREFIX(extract_number_and_incr) (&mcnt2, &p);
++# ifdef _LIBC
++ printf ("/set_number_at location %td to %d", p1 - start, mcnt2);
++# else
++ printf ("/set_number_at location %ld to %d",
++ (long int) (p1 - start), mcnt2);
++# endif
++ break;
++
++ case wordbound:
++ printf ("/wordbound");
++ break;
++
++ case notwordbound:
++ printf ("/notwordbound");
++ break;
++
++ case wordbeg:
++ printf ("/wordbeg");
++ break;
++
++ case wordend:
++ printf ("/wordend");
++ break;
++
++# ifdef emacs
++ case before_dot:
++ printf ("/before_dot");
++ break;
++
++ case at_dot:
++ printf ("/at_dot");
++ break;
++
++ case after_dot:
++ printf ("/after_dot");
++ break;
++
++ case syntaxspec:
++ printf ("/syntaxspec");
++ mcnt = *p++;
++ printf ("/%d", mcnt);
++ break;
++
++ case notsyntaxspec:
++ printf ("/notsyntaxspec");
++ mcnt = *p++;
++ printf ("/%d", mcnt);
++ break;
++# endif /* emacs */
++
++ case wordchar:
++ printf ("/wordchar");
++ break;
++
++ case notwordchar:
++ printf ("/notwordchar");
++ break;
++
++ case begbuf:
++ printf ("/begbuf");
++ break;
++
++ case endbuf:
++ printf ("/endbuf");
++ break;
++
++ default:
++ printf ("?%ld", (long int) *(p-1));
++ }
++
++ putchar ('\n');
++ }
++
++# ifdef _LIBC
++ printf ("%td:\tend of pattern.\n", p - start);
++# else
++ printf ("%ld:\tend of pattern.\n", (long int) (p - start));
++# endif
++}
++
++
++void
++PREFIX(print_compiled_pattern) (struct re_pattern_buffer *bufp)
++{
++ UCHAR_T *buffer = (UCHAR_T*) bufp->buffer;
++
++ PREFIX(print_partial_compiled_pattern) (buffer, buffer
++ + bufp->used / sizeof(UCHAR_T));
++ printf ("%ld bytes used/%ld bytes allocated.\n",
++ bufp->used, bufp->allocated);
++
++ if (bufp->fastmap_accurate && bufp->fastmap)
++ {
++ printf ("fastmap: ");
++ print_fastmap (bufp->fastmap);
++ }
++
++# ifdef _LIBC
++ printf ("re_nsub: %Zd\t", bufp->re_nsub);
++# else
++ printf ("re_nsub: %ld\t", (long int) bufp->re_nsub);
++# endif
++ printf ("regs_alloc: %d\t", bufp->regs_allocated);
++ printf ("can_be_null: %d\t", bufp->can_be_null);
++ printf ("newline_anchor: %d\n", bufp->newline_anchor);
++ printf ("no_sub: %d\t", bufp->no_sub);
++ printf ("not_bol: %d\t", bufp->not_bol);
++ printf ("not_eol: %d\t", bufp->not_eol);
++ printf ("syntax: %lx\n", bufp->syntax);
++ /* Perhaps we should print the translate table? */
++}
++
++
++void
++PREFIX(print_double_string) (const CHAR_T *where, const CHAR_T *string1,
++ int size1, const CHAR_T *string2, int size2)
++{
++ int this_char;
++
++ if (where == NULL)
++ printf ("(null)");
++ else
++ {
++ int cnt;
++
++ if (FIRST_STRING_P (where))
++ {
++ for (this_char = where - string1; this_char < size1; this_char++)
++ PUT_CHAR (string1[this_char]);
++
++ where = string2;
++ }
++
++ cnt = 0;
++ for (this_char = where - string2; this_char < size2; this_char++)
++ {
++ PUT_CHAR (string2[this_char]);
++ if (++cnt > 100)
++ {
++ fputs ("...", stdout);
++ break;
++ }
++ }
++ }
++}
++
++# ifndef DEFINED_ONCE
++void
++printchar (int c)
++{
++ putc (c, stderr);
++}
++# endif
++
++# else /* not DEBUG */
++
++# ifndef DEFINED_ONCE
++# undef assert
++# define assert(e)
++
++# define DEBUG_STATEMENT(e)
++# define DEBUG_PRINT1(x)
++# define DEBUG_PRINT2(x1, x2)
++# define DEBUG_PRINT3(x1, x2, x3)
++# define DEBUG_PRINT4(x1, x2, x3, x4)
++# endif /* not DEFINED_ONCE */
++# define DEBUG_PRINT_COMPILED_PATTERN(p, s, e)
++# define DEBUG_PRINT_DOUBLE_STRING(w, s1, sz1, s2, sz2)
++
++# endif /* not DEBUG */
++
++
++
++# ifdef WCHAR
++/* This convert a multibyte string to a wide character string.
++ And write their correspondances to offset_buffer(see below)
++ and write whether each wchar_t is binary data to is_binary.
++ This assume invalid multibyte sequences as binary data.
++ We assume offset_buffer and is_binary is already allocated
++ enough space. */
++
++static size_t convert_mbs_to_wcs (CHAR_T *dest, const unsigned char* src,
++ size_t len, int *offset_buffer,
++ char *is_binary);
++static size_t
++convert_mbs_to_wcs (CHAR_T *dest, const unsigned char*src, size_t len,
++ int *offset_buffer, char *is_binary)
++ /* It hold correspondances between src(char string) and
++ dest(wchar_t string) for optimization.
++ e.g. src = "xxxyzz"
++ dest = {'X', 'Y', 'Z'}
++ (each "xxx", "y" and "zz" represent one multibyte character
++ corresponding to 'X', 'Y' and 'Z'.)
++ offset_buffer = {0, 0+3("xxx"), 0+3+1("y"), 0+3+1+2("zz")}
++ = {0, 3, 4, 6}
++ */
++{
++ wchar_t *pdest = dest;
++ const unsigned char *psrc = src;
++ size_t wc_count = 0;
++
++ mbstate_t mbs;
++ int i, consumed;
++ size_t mb_remain = len;
++ size_t mb_count = 0;
++
++ /* Initialize the conversion state. */
++ memset (&mbs, 0, sizeof (mbstate_t));
++
++ offset_buffer[0] = 0;
++ for( ; mb_remain > 0 ; ++wc_count, ++pdest, mb_remain -= consumed,
++ psrc += consumed)
++ {
++#ifdef _LIBC
++ consumed = __mbrtowc (pdest, psrc, mb_remain, &mbs);
++#else
++ consumed = mbrtowc (pdest, psrc, mb_remain, &mbs);
++#endif
++
++ if (consumed <= 0)
++ /* failed to convert. maybe src contains binary data.
++ So we consume 1 byte manualy. */
++ {
++ *pdest = *psrc;
++ consumed = 1;
++ is_binary[wc_count] = TRUE;
++ }
++ else
++ is_binary[wc_count] = FALSE;
++ /* In sjis encoding, we use yen sign as escape character in
++ place of reverse solidus. So we convert 0x5c(yen sign in
++ sjis) to not 0xa5(yen sign in UCS2) but 0x5c(reverse
++ solidus in UCS2). */
++ if (consumed == 1 && (int) *psrc == 0x5c && (int) *pdest == 0xa5)
++ *pdest = (wchar_t) *psrc;
++
++ offset_buffer[wc_count + 1] = mb_count += consumed;
++ }
++
++ /* Fill remain of the buffer with sentinel. */
++ for (i = wc_count + 1 ; i <= len ; i++)
++ offset_buffer[i] = mb_count + 1;
++
++ return wc_count;
++}
++
++# endif /* WCHAR */
++
++#else /* not INSIDE_RECURSION */
++
++/* Set by `re_set_syntax' to the current regexp syntax to recognize. Can
++ also be assigned to arbitrarily: each pattern buffer stores its own
++ syntax, so it can be changed between regex compilations. */
++/* This has no initializer because initialized variables in Emacs
++ become read-only after dumping. */
++reg_syntax_t re_syntax_options;
++
++
++/* Specify the precise syntax of regexps for compilation. This provides
++ for compatibility for various utilities which historically have
++ different, incompatible syntaxes.
++
++ The argument SYNTAX is a bit mask comprised of the various bits
++ defined in regex.h. We return the old syntax. */
++
++reg_syntax_t
++re_set_syntax (reg_syntax_t syntax)
++{
++ reg_syntax_t ret = re_syntax_options;
++
++ re_syntax_options = syntax;
++# ifdef DEBUG
++ if (syntax & RE_DEBUG)
++ debug = 1;
++ else if (debug) /* was on but now is not */
++ debug = 0;
++# endif /* DEBUG */
++ return ret;
++}
++# ifdef _LIBC
++weak_alias (__re_set_syntax, re_set_syntax)
++# endif
++
++/* This table gives an error message for each of the error codes listed
++ in regex.h. Obviously the order here has to be same as there.
++ POSIX doesn't require that we do anything for REG_NOERROR,
++ but why not be nice? */
++
++static const char *re_error_msgid[] =
++ {
++ gettext_noop ("Success"), /* REG_NOERROR */
++ gettext_noop ("No match"), /* REG_NOMATCH */
++ gettext_noop ("Invalid regular expression"), /* REG_BADPAT */
++ gettext_noop ("Invalid collation character"), /* REG_ECOLLATE */
++ gettext_noop ("Invalid character class name"), /* REG_ECTYPE */
++ gettext_noop ("Trailing backslash"), /* REG_EESCAPE */
++ gettext_noop ("Invalid back reference"), /* REG_ESUBREG */
++ gettext_noop ("Unmatched [ or [^"), /* REG_EBRACK */
++ gettext_noop ("Unmatched ( or \\("), /* REG_EPAREN */
++ gettext_noop ("Unmatched \\{"), /* REG_EBRACE */
++ gettext_noop ("Invalid content of \\{\\}"), /* REG_BADBR */
++ gettext_noop ("Invalid range end"), /* REG_ERANGE */
++ gettext_noop ("Memory exhausted"), /* REG_ESPACE */
++ gettext_noop ("Invalid preceding regular expression"), /* REG_BADRPT */
++ gettext_noop ("Premature end of regular expression"), /* REG_EEND */
++ gettext_noop ("Regular expression too big"), /* REG_ESIZE */
++ gettext_noop ("Unmatched ) or \\)") /* REG_ERPAREN */
++ };
++
++#endif /* INSIDE_RECURSION */
++
++#ifndef DEFINED_ONCE
++/* Avoiding alloca during matching, to placate r_alloc. */
++
++/* Define MATCH_MAY_ALLOCATE unless we need to make sure that the
++ searching and matching functions should not call alloca. On some
++ systems, alloca is implemented in terms of malloc, and if we're
++ using the relocating allocator routines, then malloc could cause a
++ relocation, which might (if the strings being searched are in the
++ ralloc heap) shift the data out from underneath the regexp
++ routines.
++
++ Here's another reason to avoid allocation: Emacs
++ processes input from X in a signal handler; processing X input may
++ call malloc; if input arrives while a matching routine is calling
++ malloc, then we're scrod. But Emacs can't just block input while
++ calling matching routines; then we don't notice interrupts when
++ they come in. So, Emacs blocks input around all regexp calls
++ except the matching calls, which it leaves unprotected, in the
++ faith that they will not malloc. */
++
++/* Normally, this is fine. */
++# define MATCH_MAY_ALLOCATE
++
++/* When using GNU C, we are not REALLY using the C alloca, no matter
++ what config.h may say. So don't take precautions for it. */
++# ifdef __GNUC__
++# undef C_ALLOCA
++# endif
++
++/* The match routines may not allocate if (1) they would do it with malloc
++ and (2) it's not safe for them to use malloc.
++ Note that if REL_ALLOC is defined, matching would not use malloc for the
++ failure stack, but we would still use it for the register vectors;
++ so REL_ALLOC should not affect this. */
++# if (defined C_ALLOCA || defined REGEX_MALLOC) && defined emacs
++# undef MATCH_MAY_ALLOCATE
++# endif
++#endif /* not DEFINED_ONCE */
++
++#ifdef INSIDE_RECURSION
++/* Failure stack declarations and macros; both re_compile_fastmap and
++ re_match_2 use a failure stack. These have to be macros because of
++ REGEX_ALLOCATE_STACK. */
++
++
++/* Number of failure points for which to initially allocate space
++ when matching. If this number is exceeded, we allocate more
++ space, so it is not a hard limit. */
++# ifndef INIT_FAILURE_ALLOC
++# define INIT_FAILURE_ALLOC 5
++# endif
++
++/* Roughly the maximum number of failure points on the stack. Would be
++ exactly that if always used MAX_FAILURE_ITEMS items each time we failed.
++ This is a variable only so users of regex can assign to it; we never
++ change it ourselves. */
++
++
++# ifndef DEFINED_ONCE
++
++# ifdef INT_IS_16BIT
++# define RE_M_F_TYPE long int
++# else
++# define RE_M_F_TYPE int
++# endif /* INT_IS_16BIT */
++
++# ifdef MATCH_MAY_ALLOCATE
++/* 4400 was enough to cause a crash on Alpha OSF/1,
++ whose default stack limit is 2mb. */
++# define RE_M_F_DEFAULT 4000
++# else
++# define RE_M_F_DEFAULT 2000
++# endif /* MATCH_MAY_ALLOCATE */
++
++# include <shlib-compat.h>
++
++# if SHLIB_COMPAT (libc, GLIBC_2_0, GLIBC_2_3)
++link_warning (re_max_failures, "the 're_max_failures' variable is obsolete and will go away.")
++RE_M_F_TYPE re_max_failures = RE_M_F_DEFAULT;
++# else
++RE_M_F_TYPE re_max_failures attribute_hidden = RE_M_F_DEFAULT;
++# endif /* SHLIB_COMPAT */
++
++# undef RE_M_F_TYPE
++# undef RE_M_F_DEFAULT
++
++# endif /* DEFINED_ONCE */
++
++# ifdef INT_IS_16BIT
++
++union PREFIX(fail_stack_elt)
++{
++ UCHAR_T *pointer;
++ long int integer;
++};
++
++typedef union PREFIX(fail_stack_elt) PREFIX(fail_stack_elt_t);
++
++typedef struct
++{
++ PREFIX(fail_stack_elt_t) *stack;
++ unsigned long int size;
++ unsigned long int avail; /* Offset of next open position. */
++} PREFIX(fail_stack_type);
++
++# else /* not INT_IS_16BIT */
++
++union PREFIX(fail_stack_elt)
++{
++ UCHAR_T *pointer;
++ int integer;
++};
++
++typedef union PREFIX(fail_stack_elt) PREFIX(fail_stack_elt_t);
++
++typedef struct
++{
++ PREFIX(fail_stack_elt_t) *stack;
++ unsigned size;
++ unsigned avail; /* Offset of next open position. */
++} PREFIX(fail_stack_type);
++
++# endif /* INT_IS_16BIT */
++
++# ifndef DEFINED_ONCE
++# define FAIL_STACK_EMPTY() (fail_stack.avail == 0)
++# define FAIL_STACK_PTR_EMPTY() (fail_stack_ptr->avail == 0)
++# define FAIL_STACK_FULL() (fail_stack.avail == fail_stack.size)
++# endif
++
++
++/* Define macros to initialize and free the failure stack.
++ Do `return -2' if the alloc fails. */
++
++# ifdef MATCH_MAY_ALLOCATE
++# define INIT_FAIL_STACK() \
++ do { \
++ fail_stack.stack = (PREFIX(fail_stack_elt_t) *) \
++ REGEX_ALLOCATE_STACK (INIT_FAILURE_ALLOC * sizeof (PREFIX(fail_stack_elt_t))); \
++ \
++ if (fail_stack.stack == NULL) \
++ return -2; \
++ \
++ fail_stack.size = INIT_FAILURE_ALLOC; \
++ fail_stack.avail = 0; \
++ } while (0)
++
++# define RESET_FAIL_STACK() REGEX_FREE_STACK (fail_stack.stack)
++# else
++# define INIT_FAIL_STACK() \
++ do { \
++ fail_stack.avail = 0; \
++ } while (0)
++
++# define RESET_FAIL_STACK()
++# endif
++
++
++/* Double the size of FAIL_STACK, up to approximately `re_max_failures' items.
++
++ Return 1 if succeeds, and 0 if either ran out of memory
++ allocating space for it or it was already too large.
++
++ REGEX_REALLOCATE_STACK requires `destination' be declared. */
++
++# define DOUBLE_FAIL_STACK(fail_stack) \
++ ((fail_stack).size > (unsigned) (re_max_failures * MAX_FAILURE_ITEMS) \
++ ? 0 \
++ : ((fail_stack).stack = (PREFIX(fail_stack_elt_t) *) \
++ REGEX_REALLOCATE_STACK ((fail_stack).stack, \
++ (fail_stack).size * sizeof (PREFIX(fail_stack_elt_t)), \
++ ((fail_stack).size << 1) * sizeof (PREFIX(fail_stack_elt_t))),\
++ \
++ (fail_stack).stack == NULL \
++ ? 0 \
++ : ((fail_stack).size <<= 1, \
++ 1)))
++
++
++/* Push pointer POINTER on FAIL_STACK.
++ Return 1 if was able to do so and 0 if ran out of memory allocating
++ space to do so. */
++# define PUSH_PATTERN_OP(POINTER, FAIL_STACK) \
++ ((FAIL_STACK_FULL () \
++ && !DOUBLE_FAIL_STACK (FAIL_STACK)) \
++ ? 0 \
++ : ((FAIL_STACK).stack[(FAIL_STACK).avail++].pointer = POINTER, \
++ 1))
++
++/* Push a pointer value onto the failure stack.
++ Assumes the variable `fail_stack'. Probably should only
++ be called from within `PUSH_FAILURE_POINT'. */
++# define PUSH_FAILURE_POINTER(item) \
++ fail_stack.stack[fail_stack.avail++].pointer = (UCHAR_T *) (item)
++
++/* This pushes an integer-valued item onto the failure stack.
++ Assumes the variable `fail_stack'. Probably should only
++ be called from within `PUSH_FAILURE_POINT'. */
++# define PUSH_FAILURE_INT(item) \
++ fail_stack.stack[fail_stack.avail++].integer = (item)
++
++/* Push a fail_stack_elt_t value onto the failure stack.
++ Assumes the variable `fail_stack'. Probably should only
++ be called from within `PUSH_FAILURE_POINT'. */
++# define PUSH_FAILURE_ELT(item) \
++ fail_stack.stack[fail_stack.avail++] = (item)
++
++/* These three POP... operations complement the three PUSH... operations.
++ All assume that `fail_stack' is nonempty. */
++# define POP_FAILURE_POINTER() fail_stack.stack[--fail_stack.avail].pointer
++# define POP_FAILURE_INT() fail_stack.stack[--fail_stack.avail].integer
++# define POP_FAILURE_ELT() fail_stack.stack[--fail_stack.avail]
++
++/* Used to omit pushing failure point id's when we're not debugging. */
++# ifdef DEBUG
++# define DEBUG_PUSH PUSH_FAILURE_INT
++# define DEBUG_POP(item_addr) *(item_addr) = POP_FAILURE_INT ()
++# else
++# define DEBUG_PUSH(item)
++# define DEBUG_POP(item_addr)
++# endif
++
++
++/* Push the information about the state we will need
++ if we ever fail back to it.
++
++ Requires variables fail_stack, regstart, regend, reg_info, and
++ num_regs_pushed be declared. DOUBLE_FAIL_STACK requires `destination'
++ be declared.
++
++ Does `return FAILURE_CODE' if runs out of memory. */
++
++# define PUSH_FAILURE_POINT(pattern_place, string_place, failure_code) \
++ do { \
++ char *destination; \
++ /* Must be int, so when we don't save any registers, the arithmetic \
++ of 0 + -1 isn't done as unsigned. */ \
++ /* Can't be int, since there is not a shred of a guarantee that int \
++ is wide enough to hold a value of something to which pointer can \
++ be assigned */ \
++ active_reg_t this_reg; \
++ \
++ DEBUG_STATEMENT (failure_id++); \
++ DEBUG_STATEMENT (nfailure_points_pushed++); \
++ DEBUG_PRINT2 ("\nPUSH_FAILURE_POINT #%u:\n", failure_id); \
++ DEBUG_PRINT2 (" Before push, next avail: %d\n", (fail_stack).avail);\
++ DEBUG_PRINT2 (" size: %d\n", (fail_stack).size);\
++ \
++ DEBUG_PRINT2 (" slots needed: %ld\n", NUM_FAILURE_ITEMS); \
++ DEBUG_PRINT2 (" available: %d\n", REMAINING_AVAIL_SLOTS); \
++ \
++ /* Ensure we have enough space allocated for what we will push. */ \
++ while (REMAINING_AVAIL_SLOTS < NUM_FAILURE_ITEMS) \
++ { \
++ if (!DOUBLE_FAIL_STACK (fail_stack)) \
++ return failure_code; \
++ \
++ DEBUG_PRINT2 ("\n Doubled stack; size now: %d\n", \
++ (fail_stack).size); \
++ DEBUG_PRINT2 (" slots available: %d\n", REMAINING_AVAIL_SLOTS);\
++ } \
++ \
++ /* Push the info, starting with the registers. */ \
++ DEBUG_PRINT1 ("\n"); \
++ \
++ if (1) \
++ for (this_reg = lowest_active_reg; this_reg <= highest_active_reg; \
++ this_reg++) \
++ { \
++ DEBUG_PRINT2 (" Pushing reg: %lu\n", this_reg); \
++ DEBUG_STATEMENT (num_regs_pushed++); \
++ \
++ DEBUG_PRINT2 (" start: %p\n", regstart[this_reg]); \
++ PUSH_FAILURE_POINTER (regstart[this_reg]); \
++ \
++ DEBUG_PRINT2 (" end: %p\n", regend[this_reg]); \
++ PUSH_FAILURE_POINTER (regend[this_reg]); \
++ \
++ DEBUG_PRINT2 (" info: %p\n ", \
++ reg_info[this_reg].word.pointer); \
++ DEBUG_PRINT2 (" match_null=%d", \
++ REG_MATCH_NULL_STRING_P (reg_info[this_reg])); \
++ DEBUG_PRINT2 (" active=%d", IS_ACTIVE (reg_info[this_reg])); \
++ DEBUG_PRINT2 (" matched_something=%d", \
++ MATCHED_SOMETHING (reg_info[this_reg])); \
++ DEBUG_PRINT2 (" ever_matched=%d", \
++ EVER_MATCHED_SOMETHING (reg_info[this_reg])); \
++ DEBUG_PRINT1 ("\n"); \
++ PUSH_FAILURE_ELT (reg_info[this_reg].word); \
++ } \
++ \
++ DEBUG_PRINT2 (" Pushing low active reg: %ld\n", lowest_active_reg);\
++ PUSH_FAILURE_INT (lowest_active_reg); \
++ \
++ DEBUG_PRINT2 (" Pushing high active reg: %ld\n", highest_active_reg);\
++ PUSH_FAILURE_INT (highest_active_reg); \
++ \
++ DEBUG_PRINT2 (" Pushing pattern %p:\n", pattern_place); \
++ DEBUG_PRINT_COMPILED_PATTERN (bufp, pattern_place, pend); \
++ PUSH_FAILURE_POINTER (pattern_place); \
++ \
++ DEBUG_PRINT2 (" Pushing string %p: `", string_place); \
++ DEBUG_PRINT_DOUBLE_STRING (string_place, string1, size1, string2, \
++ size2); \
++ DEBUG_PRINT1 ("'\n"); \
++ PUSH_FAILURE_POINTER (string_place); \
++ \
++ DEBUG_PRINT2 (" Pushing failure id: %u\n", failure_id); \
++ DEBUG_PUSH (failure_id); \
++ } while (0)
++
++# ifndef DEFINED_ONCE
++/* This is the number of items that are pushed and popped on the stack
++ for each register. */
++# define NUM_REG_ITEMS 3
++
++/* Individual items aside from the registers. */
++# ifdef DEBUG
++# define NUM_NONREG_ITEMS 5 /* Includes failure point id. */
++# else
++# define NUM_NONREG_ITEMS 4
++# endif
++
++/* We push at most this many items on the stack. */
++/* We used to use (num_regs - 1), which is the number of registers
++ this regexp will save; but that was changed to 5
++ to avoid stack overflow for a regexp with lots of parens. */
++# define MAX_FAILURE_ITEMS (5 * NUM_REG_ITEMS + NUM_NONREG_ITEMS)
++
++/* We actually push this many items. */
++# define NUM_FAILURE_ITEMS \
++ (((0 \
++ ? 0 : highest_active_reg - lowest_active_reg + 1) \
++ * NUM_REG_ITEMS) \
++ + NUM_NONREG_ITEMS)
++
++/* How many items can still be added to the stack without overflowing it. */
++# define REMAINING_AVAIL_SLOTS ((fail_stack).size - (fail_stack).avail)
++# endif /* not DEFINED_ONCE */
++
++
++/* Pops what PUSH_FAIL_STACK pushes.
++
++ We restore into the parameters, all of which should be lvalues:
++ STR -- the saved data position.
++ PAT -- the saved pattern position.
++ LOW_REG, HIGH_REG -- the highest and lowest active registers.
++ REGSTART, REGEND -- arrays of string positions.
++ REG_INFO -- array of information about each subexpression.
++
++ Also assumes the variables `fail_stack' and (if debugging), `bufp',
++ `pend', `string1', `size1', `string2', and `size2'. */
++# define POP_FAILURE_POINT(str, pat, low_reg, high_reg, regstart, regend, reg_info)\
++{ \
++ DEBUG_STATEMENT (unsigned failure_id;) \
++ active_reg_t this_reg; \
++ const UCHAR_T *string_temp; \
++ \
++ assert (!FAIL_STACK_EMPTY ()); \
++ \
++ /* Remove failure points and point to how many regs pushed. */ \
++ DEBUG_PRINT1 ("POP_FAILURE_POINT:\n"); \
++ DEBUG_PRINT2 (" Before pop, next avail: %d\n", fail_stack.avail); \
++ DEBUG_PRINT2 (" size: %d\n", fail_stack.size); \
++ \
++ assert (fail_stack.avail >= NUM_NONREG_ITEMS); \
++ \
++ DEBUG_POP (&failure_id); \
++ DEBUG_PRINT2 (" Popping failure id: %u\n", failure_id); \
++ \
++ /* If the saved string location is NULL, it came from an \
++ on_failure_keep_string_jump opcode, and we want to throw away the \
++ saved NULL, thus retaining our current position in the string. */ \
++ string_temp = POP_FAILURE_POINTER (); \
++ if (string_temp != NULL) \
++ str = (const CHAR_T *) string_temp; \
++ \
++ DEBUG_PRINT2 (" Popping string %p: `", str); \
++ DEBUG_PRINT_DOUBLE_STRING (str, string1, size1, string2, size2); \
++ DEBUG_PRINT1 ("'\n"); \
++ \
++ pat = (UCHAR_T *) POP_FAILURE_POINTER (); \
++ DEBUG_PRINT2 (" Popping pattern %p:\n", pat); \
++ DEBUG_PRINT_COMPILED_PATTERN (bufp, pat, pend); \
++ \
++ /* Restore register info. */ \
++ high_reg = (active_reg_t) POP_FAILURE_INT (); \
++ DEBUG_PRINT2 (" Popping high active reg: %ld\n", high_reg); \
++ \
++ low_reg = (active_reg_t) POP_FAILURE_INT (); \
++ DEBUG_PRINT2 (" Popping low active reg: %ld\n", low_reg); \
++ \
++ if (1) \
++ for (this_reg = high_reg; this_reg >= low_reg; this_reg--) \
++ { \
++ DEBUG_PRINT2 (" Popping reg: %ld\n", this_reg); \
++ \
++ reg_info[this_reg].word = POP_FAILURE_ELT (); \
++ DEBUG_PRINT2 (" info: %p\n", \
++ reg_info[this_reg].word.pointer); \
++ \
++ regend[this_reg] = (const CHAR_T *) POP_FAILURE_POINTER (); \
++ DEBUG_PRINT2 (" end: %p\n", regend[this_reg]); \
++ \
++ regstart[this_reg] = (const CHAR_T *) POP_FAILURE_POINTER (); \
++ DEBUG_PRINT2 (" start: %p\n", regstart[this_reg]); \
++ } \
++ else \
++ { \
++ for (this_reg = highest_active_reg; this_reg > high_reg; this_reg--) \
++ { \
++ reg_info[this_reg].word.integer = 0; \
++ regend[this_reg] = 0; \
++ regstart[this_reg] = 0; \
++ } \
++ highest_active_reg = high_reg; \
++ } \
++ \
++ set_regs_matched_done = 0; \
++ DEBUG_STATEMENT (nfailure_points_popped++); \
++} /* POP_FAILURE_POINT */
++
++/* Structure for per-register (a.k.a. per-group) information.
++ Other register information, such as the
++ starting and ending positions (which are addresses), and the list of
++ inner groups (which is a bits list) are maintained in separate
++ variables.
++
++ We are making a (strictly speaking) nonportable assumption here: that
++ the compiler will pack our bit fields into something that fits into
++ the type of `word', i.e., is something that fits into one item on the
++ failure stack. */
++
++
++/* Declarations and macros for re_match_2. */
++
++typedef union
++{
++ PREFIX(fail_stack_elt_t) word;
++ struct
++ {
++ /* This field is one if this group can match the empty string,
++ zero if not. If not yet determined, `MATCH_NULL_UNSET_VALUE'. */
++# define MATCH_NULL_UNSET_VALUE 3
++ unsigned match_null_string_p : 2;
++ unsigned is_active : 1;
++ unsigned matched_something : 1;
++ unsigned ever_matched_something : 1;
++ } bits;
++} PREFIX(register_info_type);
++
++# ifndef DEFINED_ONCE
++# define REG_MATCH_NULL_STRING_P(R) ((R).bits.match_null_string_p)
++# define IS_ACTIVE(R) ((R).bits.is_active)
++# define MATCHED_SOMETHING(R) ((R).bits.matched_something)
++# define EVER_MATCHED_SOMETHING(R) ((R).bits.ever_matched_something)
++
++
++/* Call this when have matched a real character; it sets `matched' flags
++ for the subexpressions which we are currently inside. Also records
++ that those subexprs have matched. */
++# define SET_REGS_MATCHED() \
++ do \
++ { \
++ if (!set_regs_matched_done) \
++ { \
++ active_reg_t r; \
++ set_regs_matched_done = 1; \
++ for (r = lowest_active_reg; r <= highest_active_reg; r++) \
++ { \
++ MATCHED_SOMETHING (reg_info[r]) \
++ = EVER_MATCHED_SOMETHING (reg_info[r]) \
++ = 1; \
++ } \
++ } \
++ } \
++ while (0)
++# endif /* not DEFINED_ONCE */
++
++/* Registers are set to a sentinel when they haven't yet matched. */
++static CHAR_T PREFIX(reg_unset_dummy);
++# define REG_UNSET_VALUE (&PREFIX(reg_unset_dummy))
++# define REG_UNSET(e) ((e) == REG_UNSET_VALUE)
++
++/* Subroutine declarations and macros for regex_compile. */
++static void PREFIX(store_op1) (re_opcode_t op, UCHAR_T *loc, int arg);
++static void PREFIX(store_op2) (re_opcode_t op, UCHAR_T *loc,
++ int arg1, int arg2);
++static void PREFIX(insert_op1) (re_opcode_t op, UCHAR_T *loc,
++ int arg, UCHAR_T *end);
++static void PREFIX(insert_op2) (re_opcode_t op, UCHAR_T *loc,
++ int arg1, int arg2, UCHAR_T *end);
++static boolean PREFIX(at_begline_loc_p) (const CHAR_T *pattern,
++ const CHAR_T *p,
++ reg_syntax_t syntax);
++static boolean PREFIX(at_endline_loc_p) (const CHAR_T *p,
++ const CHAR_T *pend,
++ reg_syntax_t syntax);
++# ifdef WCHAR
++static reg_errcode_t wcs_compile_range (CHAR_T range_start,
++ const CHAR_T **p_ptr,
++ const CHAR_T *pend,
++ char *translate,
++ reg_syntax_t syntax,
++ UCHAR_T *b,
++ CHAR_T *char_set);
++static void insert_space (int num, CHAR_T *loc, CHAR_T *end);
++# else /* BYTE */
++static reg_errcode_t byte_compile_range (unsigned int range_start,
++ const char **p_ptr,
++ const char *pend,
++ RE_TRANSLATE_TYPE translate,
++ reg_syntax_t syntax,
++ unsigned char *b);
++# endif /* WCHAR */
++
++/* Fetch the next character in the uncompiled pattern---translating it
++ if necessary. Also cast from a signed character in the constant
++ string passed to us by the user to an unsigned char that we can use
++ as an array index (in, e.g., `translate'). */
++/* ifdef MBS_SUPPORT, we translate only if character <= 0xff,
++ because it is impossible to allocate 4GB array for some encodings
++ which have 4 byte character_set like UCS4. */
++# ifndef PATFETCH
++# ifdef WCHAR
++# define PATFETCH(c) \
++ do {if (p == pend) return REG_EEND; \
++ c = (UCHAR_T) *p++; \
++ if (translate && (c <= 0xff)) c = (UCHAR_T) translate[c]; \
++ } while (0)
++# else /* BYTE */
++# define PATFETCH(c) \
++ do {if (p == pend) return REG_EEND; \
++ c = (unsigned char) *p++; \
++ if (translate) c = (unsigned char) translate[c]; \
++ } while (0)
++# endif /* WCHAR */
++# endif
++
++/* Fetch the next character in the uncompiled pattern, with no
++ translation. */
++# define PATFETCH_RAW(c) \
++ do {if (p == pend) return REG_EEND; \
++ c = (UCHAR_T) *p++; \
++ } while (0)
++
++/* Go backwards one character in the pattern. */
++# define PATUNFETCH p--
++
++
++/* If `translate' is non-null, return translate[D], else just D. We
++ cast the subscript to translate because some data is declared as
++ `char *', to avoid warnings when a string constant is passed. But
++ when we use a character as a subscript we must make it unsigned. */
++/* ifdef MBS_SUPPORT, we translate only if character <= 0xff,
++ because it is impossible to allocate 4GB array for some encodings
++ which have 4 byte character_set like UCS4. */
++
++# ifndef TRANSLATE
++# ifdef WCHAR
++# define TRANSLATE(d) \
++ ((translate && ((UCHAR_T) (d)) <= 0xff) \
++ ? (char) translate[(unsigned char) (d)] : (d))
++# else /* BYTE */
++# define TRANSLATE(d) \
++ (translate ? (char) translate[(unsigned char) (d)] : (char) (d))
++# endif /* WCHAR */
++# endif
++
++
++/* Macros for outputting the compiled pattern into `buffer'. */
++
++/* If the buffer isn't allocated when it comes in, use this. */
++# define INIT_BUF_SIZE (32 * sizeof(UCHAR_T))
++
++/* Make sure we have at least N more bytes of space in buffer. */
++# ifdef WCHAR
++# define GET_BUFFER_SPACE(n) \
++ while (((unsigned long)b - (unsigned long)COMPILED_BUFFER_VAR \
++ + (n)*sizeof(CHAR_T)) > bufp->allocated) \
++ EXTEND_BUFFER ()
++# else /* BYTE */
++# define GET_BUFFER_SPACE(n) \
++ while ((unsigned long) (b - bufp->buffer + (n)) > bufp->allocated) \
++ EXTEND_BUFFER ()
++# endif /* WCHAR */
++
++/* Make sure we have one more byte of buffer space and then add C to it. */
++# define BUF_PUSH(c) \
++ do { \
++ GET_BUFFER_SPACE (1); \
++ *b++ = (UCHAR_T) (c); \
++ } while (0)
++
++
++/* Ensure we have two more bytes of buffer space and then append C1 and C2. */
++# define BUF_PUSH_2(c1, c2) \
++ do { \
++ GET_BUFFER_SPACE (2); \
++ *b++ = (UCHAR_T) (c1); \
++ *b++ = (UCHAR_T) (c2); \
++ } while (0)
++
++
++/* As with BUF_PUSH_2, except for three bytes. */
++# define BUF_PUSH_3(c1, c2, c3) \
++ do { \
++ GET_BUFFER_SPACE (3); \
++ *b++ = (UCHAR_T) (c1); \
++ *b++ = (UCHAR_T) (c2); \
++ *b++ = (UCHAR_T) (c3); \
++ } while (0)
++
++/* Store a jump with opcode OP at LOC to location TO. We store a
++ relative address offset by the three bytes the jump itself occupies. */
++# define STORE_JUMP(op, loc, to) \
++ PREFIX(store_op1) (op, loc, (int) ((to) - (loc) - (1 + OFFSET_ADDRESS_SIZE)))
++
++/* Likewise, for a two-argument jump. */
++# define STORE_JUMP2(op, loc, to, arg) \
++ PREFIX(store_op2) (op, loc, (int) ((to) - (loc) - (1 + OFFSET_ADDRESS_SIZE)), arg)
++
++/* Like `STORE_JUMP', but for inserting. Assume `b' is the buffer end. */
++# define INSERT_JUMP(op, loc, to) \
++ PREFIX(insert_op1) (op, loc, (int) ((to) - (loc) - (1 + OFFSET_ADDRESS_SIZE)), b)
++
++/* Like `STORE_JUMP2', but for inserting. Assume `b' is the buffer end. */
++# define INSERT_JUMP2(op, loc, to, arg) \
++ PREFIX(insert_op2) (op, loc, (int) ((to) - (loc) - (1 + OFFSET_ADDRESS_SIZE)),\
++ arg, b)
++
++/* This is not an arbitrary limit: the arguments which represent offsets
++ into the pattern are two bytes long. So if 2^16 bytes turns out to
++ be too small, many things would have to change. */
++/* Any other compiler which, like MSC, has allocation limit below 2^16
++ bytes will have to use approach similar to what was done below for
++ MSC and drop MAX_BUF_SIZE a bit. Otherwise you may end up
++ reallocating to 0 bytes. Such thing is not going to work too well.
++ You have been warned!! */
++# ifndef DEFINED_ONCE
++# if defined _MSC_VER && !defined WIN32
++/* Microsoft C 16-bit versions limit malloc to approx 65512 bytes.
++ The REALLOC define eliminates a flurry of conversion warnings,
++ but is not required. */
++# define MAX_BUF_SIZE 65500L
++# define REALLOC(p,s) realloc ((p), (size_t) (s))
++# else
++# define MAX_BUF_SIZE (1L << 16)
++# define REALLOC(p,s) realloc ((p), (s))
++# endif
++
++/* Extend the buffer by twice its current size via realloc and
++ reset the pointers that pointed into the old block to point to the
++ correct places in the new one. If extending the buffer results in it
++ being larger than MAX_BUF_SIZE, then flag memory exhausted. */
++# if __BOUNDED_POINTERS__
++# define SET_HIGH_BOUND(P) (__ptrhigh (P) = __ptrlow (P) + bufp->allocated)
++# define MOVE_BUFFER_POINTER(P) \
++ (__ptrlow (P) += incr, SET_HIGH_BOUND (P), __ptrvalue (P) += incr)
++# define ELSE_EXTEND_BUFFER_HIGH_BOUND \
++ else \
++ { \
++ SET_HIGH_BOUND (b); \
++ SET_HIGH_BOUND (begalt); \
++ if (fixup_alt_jump) \
++ SET_HIGH_BOUND (fixup_alt_jump); \
++ if (laststart) \
++ SET_HIGH_BOUND (laststart); \
++ if (pending_exact) \
++ SET_HIGH_BOUND (pending_exact); \
++ }
++# else
++# define MOVE_BUFFER_POINTER(P) (P) += incr
++# define ELSE_EXTEND_BUFFER_HIGH_BOUND
++# endif
++# endif /* not DEFINED_ONCE */
++
++# ifdef WCHAR
++# define EXTEND_BUFFER() \
++ do { \
++ UCHAR_T *old_buffer = COMPILED_BUFFER_VAR; \
++ int wchar_count; \
++ if (bufp->allocated + sizeof(UCHAR_T) > MAX_BUF_SIZE) \
++ return REG_ESIZE; \
++ bufp->allocated <<= 1; \
++ if (bufp->allocated > MAX_BUF_SIZE) \
++ bufp->allocated = MAX_BUF_SIZE; \
++ /* How many characters the new buffer can have? */ \
++ wchar_count = bufp->allocated / sizeof(UCHAR_T); \
++ if (wchar_count == 0) wchar_count = 1; \
++ /* Truncate the buffer to CHAR_T align. */ \
++ bufp->allocated = wchar_count * sizeof(UCHAR_T); \
++ RETALLOC (COMPILED_BUFFER_VAR, wchar_count, UCHAR_T); \
++ bufp->buffer = (char*)COMPILED_BUFFER_VAR; \
++ if (COMPILED_BUFFER_VAR == NULL) \
++ return REG_ESPACE; \
++ /* If the buffer moved, move all the pointers into it. */ \
++ if (old_buffer != COMPILED_BUFFER_VAR) \
++ { \
++ int incr = COMPILED_BUFFER_VAR - old_buffer; \
++ MOVE_BUFFER_POINTER (b); \
++ MOVE_BUFFER_POINTER (begalt); \
++ if (fixup_alt_jump) \
++ MOVE_BUFFER_POINTER (fixup_alt_jump); \
++ if (laststart) \
++ MOVE_BUFFER_POINTER (laststart); \
++ if (pending_exact) \
++ MOVE_BUFFER_POINTER (pending_exact); \
++ } \
++ ELSE_EXTEND_BUFFER_HIGH_BOUND \
++ } while (0)
++# else /* BYTE */
++# define EXTEND_BUFFER() \
++ do { \
++ UCHAR_T *old_buffer = COMPILED_BUFFER_VAR; \
++ if (bufp->allocated == MAX_BUF_SIZE) \
++ return REG_ESIZE; \
++ bufp->allocated <<= 1; \
++ if (bufp->allocated > MAX_BUF_SIZE) \
++ bufp->allocated = MAX_BUF_SIZE; \
++ bufp->buffer = (UCHAR_T *) REALLOC (COMPILED_BUFFER_VAR, \
++ bufp->allocated); \
++ if (COMPILED_BUFFER_VAR == NULL) \
++ return REG_ESPACE; \
++ /* If the buffer moved, move all the pointers into it. */ \
++ if (old_buffer != COMPILED_BUFFER_VAR) \
++ { \
++ int incr = COMPILED_BUFFER_VAR - old_buffer; \
++ MOVE_BUFFER_POINTER (b); \
++ MOVE_BUFFER_POINTER (begalt); \
++ if (fixup_alt_jump) \
++ MOVE_BUFFER_POINTER (fixup_alt_jump); \
++ if (laststart) \
++ MOVE_BUFFER_POINTER (laststart); \
++ if (pending_exact) \
++ MOVE_BUFFER_POINTER (pending_exact); \
++ } \
++ ELSE_EXTEND_BUFFER_HIGH_BOUND \
++ } while (0)
++# endif /* WCHAR */
++
++# ifndef DEFINED_ONCE
++/* Since we have one byte reserved for the register number argument to
++ {start,stop}_memory, the maximum number of groups we can report
++ things about is what fits in that byte. */
++# define MAX_REGNUM 255
++
++/* But patterns can have more than `MAX_REGNUM' registers. We just
++ ignore the excess. */
++typedef unsigned regnum_t;
++
++
++/* Macros for the compile stack. */
++
++/* Since offsets can go either forwards or backwards, this type needs to
++ be able to hold values from -(MAX_BUF_SIZE - 1) to MAX_BUF_SIZE - 1. */
++/* int may be not enough when sizeof(int) == 2. */
++typedef long pattern_offset_t;
++
++typedef struct
++{
++ pattern_offset_t begalt_offset;
++ pattern_offset_t fixup_alt_jump;
++ pattern_offset_t inner_group_offset;
++ pattern_offset_t laststart_offset;
++ regnum_t regnum;
++} compile_stack_elt_t;
++
++
++typedef struct
++{
++ compile_stack_elt_t *stack;
++ unsigned size;
++ unsigned avail; /* Offset of next open position. */
++} compile_stack_type;
++
++
++# define INIT_COMPILE_STACK_SIZE 32
++
++# define COMPILE_STACK_EMPTY (compile_stack.avail == 0)
++# define COMPILE_STACK_FULL (compile_stack.avail == compile_stack.size)
++
++/* The next available element. */
++# define COMPILE_STACK_TOP (compile_stack.stack[compile_stack.avail])
++
++# endif /* not DEFINED_ONCE */
++
++/* Set the bit for character C in a list. */
++# ifndef DEFINED_ONCE
++# define SET_LIST_BIT(c) \
++ (b[((unsigned char) (c)) / BYTEWIDTH] \
++ |= 1 << (((unsigned char) c) % BYTEWIDTH))
++# endif /* DEFINED_ONCE */
++
++/* Get the next unsigned number in the uncompiled pattern. */
++# define GET_UNSIGNED_NUMBER(num) \
++ { \
++ while (p != pend) \
++ { \
++ PATFETCH (c); \
++ if (c < '0' || c > '9') \
++ break; \
++ if (num <= RE_DUP_MAX) \
++ { \
++ if (num < 0) \
++ num = 0; \
++ num = num * 10 + c - '0'; \
++ } \
++ } \
++ }
++
++# ifndef DEFINED_ONCE
++# if WIDE_CHAR_SUPPORT
++/* The GNU C library provides support for user-defined character classes
++ and the functions from ISO C amendement 1. */
++# ifdef CHARCLASS_NAME_MAX
++# define CHAR_CLASS_MAX_LENGTH CHARCLASS_NAME_MAX
++# else
++/* This shouldn't happen but some implementation might still have this
++ problem. Use a reasonable default value. */
++# define CHAR_CLASS_MAX_LENGTH 256
++# endif
++
++# ifdef _LIBC
++# define IS_CHAR_CLASS(string) __wctype (string)
++# else
++# define IS_CHAR_CLASS(string) wctype (string)
++# endif
++# else
++# define CHAR_CLASS_MAX_LENGTH 6 /* Namely, `xdigit'. */
++
++# define IS_CHAR_CLASS(string) \
++ (STREQ (string, "alpha") || STREQ (string, "upper") \
++ || STREQ (string, "lower") || STREQ (string, "digit") \
++ || STREQ (string, "alnum") || STREQ (string, "xdigit") \
++ || STREQ (string, "space") || STREQ (string, "print") \
++ || STREQ (string, "punct") || STREQ (string, "graph") \
++ || STREQ (string, "cntrl") || STREQ (string, "blank"))
++# endif
++# endif /* DEFINED_ONCE */
++
++# ifndef MATCH_MAY_ALLOCATE
++
++/* If we cannot allocate large objects within re_match_2_internal,
++ we make the fail stack and register vectors global.
++ The fail stack, we grow to the maximum size when a regexp
++ is compiled.
++ The register vectors, we adjust in size each time we
++ compile a regexp, according to the number of registers it needs. */
++
++static PREFIX(fail_stack_type) fail_stack;
++
++/* Size with which the following vectors are currently allocated.
++ That is so we can make them bigger as needed,
++ but never make them smaller. */
++# ifdef DEFINED_ONCE
++static int regs_allocated_size;
++
++static const char ** regstart, ** regend;
++static const char ** old_regstart, ** old_regend;
++static const char **best_regstart, **best_regend;
++static const char **reg_dummy;
++# endif /* DEFINED_ONCE */
++
++static PREFIX(register_info_type) *PREFIX(reg_info);
++static PREFIX(register_info_type) *PREFIX(reg_info_dummy);
++
++/* Make the register vectors big enough for NUM_REGS registers,
++ but don't make them smaller. */
++
++static void
++PREFIX(regex_grow_registers) (int num_regs)
++{
++ if (num_regs > regs_allocated_size)
++ {
++ RETALLOC_IF (regstart, num_regs, const char *);
++ RETALLOC_IF (regend, num_regs, const char *);
++ RETALLOC_IF (old_regstart, num_regs, const char *);
++ RETALLOC_IF (old_regend, num_regs, const char *);
++ RETALLOC_IF (best_regstart, num_regs, const char *);
++ RETALLOC_IF (best_regend, num_regs, const char *);
++ RETALLOC_IF (PREFIX(reg_info), num_regs, PREFIX(register_info_type));
++ RETALLOC_IF (reg_dummy, num_regs, const char *);
++ RETALLOC_IF (PREFIX(reg_info_dummy), num_regs, PREFIX(register_info_type));
++
++ regs_allocated_size = num_regs;
++ }
++}
++
++# endif /* not MATCH_MAY_ALLOCATE */
++
++# ifndef DEFINED_ONCE
++static boolean group_in_compile_stack (compile_stack_type compile_stack,
++ regnum_t regnum);
++# endif /* not DEFINED_ONCE */
++
++/* `regex_compile' compiles PATTERN (of length SIZE) according to SYNTAX.
++ Returns one of error codes defined in `regex.h', or zero for success.
++
++ Assumes the `allocated' (and perhaps `buffer') and `translate'
++ fields are set in BUFP on entry.
++
++ If it succeeds, results are put in BUFP (if it returns an error, the
++ contents of BUFP are undefined):
++ `buffer' is the compiled pattern;
++ `syntax' is set to SYNTAX;
++ `used' is set to the length of the compiled pattern;
++ `fastmap_accurate' is zero;
++ `re_nsub' is the number of subexpressions in PATTERN;
++ `not_bol' and `not_eol' are zero;
++
++ The `fastmap' and `newline_anchor' fields are neither
++ examined nor set. */
++
++/* Return, freeing storage we allocated. */
++# ifdef WCHAR
++# define FREE_STACK_RETURN(value) \
++ return (free(pattern), free(mbs_offset), free(is_binary), free (compile_stack.stack), value)
++# else
++# define FREE_STACK_RETURN(value) \
++ return (free (compile_stack.stack), value)
++# endif /* WCHAR */
++
++static reg_errcode_t
++PREFIX(regex_compile) (const char *ARG_PREFIX(pattern),
++ size_t ARG_PREFIX(size), reg_syntax_t syntax,
++ struct re_pattern_buffer *bufp)
++{
++ /* We fetch characters from PATTERN here. Even though PATTERN is
++ `char *' (i.e., signed), we declare these variables as unsigned, so
++ they can be reliably used as array indices. */
++ register UCHAR_T c, c1;
++
++#ifdef WCHAR
++ /* A temporary space to keep wchar_t pattern and compiled pattern. */
++ CHAR_T *pattern, *COMPILED_BUFFER_VAR;
++ size_t size;
++ /* offset buffer for optimization. See convert_mbs_to_wc. */
++ int *mbs_offset = NULL;
++ /* It hold whether each wchar_t is binary data or not. */
++ char *is_binary = NULL;
++ /* A flag whether exactn is handling binary data or not. */
++ char is_exactn_bin = FALSE;
++#endif /* WCHAR */
++
++ /* A random temporary spot in PATTERN. */
++ const CHAR_T *p1;
++
++ /* Points to the end of the buffer, where we should append. */
++ register UCHAR_T *b;
++
++ /* Keeps track of unclosed groups. */
++ compile_stack_type compile_stack;
++
++ /* Points to the current (ending) position in the pattern. */
++#ifdef WCHAR
++ const CHAR_T *p;
++ const CHAR_T *pend;
++#else /* BYTE */
++ const CHAR_T *p = pattern;
++ const CHAR_T *pend = pattern + size;
++#endif /* WCHAR */
++
++ /* How to translate the characters in the pattern. */
++ RE_TRANSLATE_TYPE translate = bufp->translate;
++
++ /* Address of the count-byte of the most recently inserted `exactn'
++ command. This makes it possible to tell if a new exact-match
++ character can be added to that command or if the character requires
++ a new `exactn' command. */
++ UCHAR_T *pending_exact = 0;
++
++ /* Address of start of the most recently finished expression.
++ This tells, e.g., postfix * where to find the start of its
++ operand. Reset at the beginning of groups and alternatives. */
++ UCHAR_T *laststart = 0;
++
++ /* Address of beginning of regexp, or inside of last group. */
++ UCHAR_T *begalt;
++
++ /* Address of the place where a forward jump should go to the end of
++ the containing expression. Each alternative of an `or' -- except the
++ last -- ends with a forward jump of this sort. */
++ UCHAR_T *fixup_alt_jump = 0;
++
++ /* Counts open-groups as they are encountered. Remembered for the
++ matching close-group on the compile stack, so the same register
++ number is put in the stop_memory as the start_memory. */
++ regnum_t regnum = 0;
++
++#ifdef WCHAR
++ /* Initialize the wchar_t PATTERN and offset_buffer. */
++ p = pend = pattern = TALLOC(csize + 1, CHAR_T);
++ mbs_offset = TALLOC(csize + 1, int);
++ is_binary = TALLOC(csize + 1, char);
++ if (pattern == NULL || mbs_offset == NULL || is_binary == NULL)
++ {
++ free(pattern);
++ free(mbs_offset);
++ free(is_binary);
++ return REG_ESPACE;
++ }
++ pattern[csize] = L'\0'; /* sentinel */
++ size = convert_mbs_to_wcs(pattern, cpattern, csize, mbs_offset, is_binary);
++ pend = p + size;
++ if (size < 0)
++ {
++ free(pattern);
++ free(mbs_offset);
++ free(is_binary);
++ return REG_BADPAT;
++ }
++#endif
++
++#ifdef DEBUG
++ DEBUG_PRINT1 ("\nCompiling pattern: ");
++ if (debug)
++ {
++ unsigned debug_count;
++
++ for (debug_count = 0; debug_count < size; debug_count++)
++ PUT_CHAR (pattern[debug_count]);
++ putchar ('\n');
++ }
++#endif /* DEBUG */
++
++ /* Initialize the compile stack. */
++ compile_stack.stack = TALLOC (INIT_COMPILE_STACK_SIZE, compile_stack_elt_t);
++ if (compile_stack.stack == NULL)
++ {
++#ifdef WCHAR
++ free(pattern);
++ free(mbs_offset);
++ free(is_binary);
++#endif
++ return REG_ESPACE;
++ }
++
++ compile_stack.size = INIT_COMPILE_STACK_SIZE;
++ compile_stack.avail = 0;
++
++ /* Initialize the pattern buffer. */
++ bufp->syntax = syntax;
++ bufp->fastmap_accurate = 0;
++ bufp->not_bol = bufp->not_eol = 0;
++
++ /* Set `used' to zero, so that if we return an error, the pattern
++ printer (for debugging) will think there's no pattern. We reset it
++ at the end. */
++ bufp->used = 0;
++
++ /* Always count groups, whether or not bufp->no_sub is set. */
++ bufp->re_nsub = 0;
++
++#if !defined emacs && !defined SYNTAX_TABLE
++ /* Initialize the syntax table. */
++ init_syntax_once ();
++#endif
++
++ if (bufp->allocated == 0)
++ {
++ if (bufp->buffer)
++ { /* If zero allocated, but buffer is non-null, try to realloc
++ enough space. This loses if buffer's address is bogus, but
++ that is the user's responsibility. */
++#ifdef WCHAR
++ /* Free bufp->buffer and allocate an array for wchar_t pattern
++ buffer. */
++ free(bufp->buffer);
++ COMPILED_BUFFER_VAR = TALLOC (INIT_BUF_SIZE/sizeof(UCHAR_T),
++ UCHAR_T);
++#else
++ RETALLOC (COMPILED_BUFFER_VAR, INIT_BUF_SIZE, UCHAR_T);
++#endif /* WCHAR */
++ }
++ else
++ { /* Caller did not allocate a buffer. Do it for them. */
++ COMPILED_BUFFER_VAR = TALLOC (INIT_BUF_SIZE / sizeof(UCHAR_T),
++ UCHAR_T);
++ }
++
++ if (!COMPILED_BUFFER_VAR) FREE_STACK_RETURN (REG_ESPACE);
++#ifdef WCHAR
++ bufp->buffer = (char*)COMPILED_BUFFER_VAR;
++#endif /* WCHAR */
++ bufp->allocated = INIT_BUF_SIZE;
++ }
++#ifdef WCHAR
++ else
++ COMPILED_BUFFER_VAR = (UCHAR_T*) bufp->buffer;
++#endif
++
++ begalt = b = COMPILED_BUFFER_VAR;
++
++ /* Loop through the uncompiled pattern until we're at the end. */
++ while (p != pend)
++ {
++ PATFETCH (c);
++
++ switch (c)
++ {
++ case '^':
++ {
++ if ( /* If at start of pattern, it's an operator. */
++ p == pattern + 1
++ /* If context independent, it's an operator. */
++ || syntax & RE_CONTEXT_INDEP_ANCHORS
++ /* Otherwise, depends on what's come before. */
++ || PREFIX(at_begline_loc_p) (pattern, p, syntax))
++ BUF_PUSH (begline);
++ else
++ goto normal_char;
++ }
++ break;
++
++
++ case '$':
++ {
++ if ( /* If at end of pattern, it's an operator. */
++ p == pend
++ /* If context independent, it's an operator. */
++ || syntax & RE_CONTEXT_INDEP_ANCHORS
++ /* Otherwise, depends on what's next. */
++ || PREFIX(at_endline_loc_p) (p, pend, syntax))
++ BUF_PUSH (endline);
++ else
++ goto normal_char;
++ }
++ break;
++
++
++ case '+':
++ case '?':
++ if ((syntax & RE_BK_PLUS_QM)
++ || (syntax & RE_LIMITED_OPS))
++ goto normal_char;
++ handle_plus:
++ case '*':
++ /* If there is no previous pattern... */
++ if (!laststart)
++ {
++ if (syntax & RE_CONTEXT_INVALID_OPS)
++ FREE_STACK_RETURN (REG_BADRPT);
++ else if (!(syntax & RE_CONTEXT_INDEP_OPS))
++ goto normal_char;
++ }
++
++ {
++ /* Are we optimizing this jump? */
++ boolean keep_string_p = false;
++
++ /* 1 means zero (many) matches is allowed. */
++ char zero_times_ok = 0, many_times_ok = 0;
++
++ /* If there is a sequence of repetition chars, collapse it
++ down to just one (the right one). We can't combine
++ interval operators with these because of, e.g., `a{2}*',
++ which should only match an even number of `a's. */
++
++ for (;;)
++ {
++ zero_times_ok |= c != '+';
++ many_times_ok |= c != '?';
++
++ if (p == pend)
++ break;
++
++ PATFETCH (c);
++
++ if (c == '*'
++ || (!(syntax & RE_BK_PLUS_QM) && (c == '+' || c == '?')))
++ ;
++
++ else if (syntax & RE_BK_PLUS_QM && c == '\\')
++ {
++ if (p == pend) FREE_STACK_RETURN (REG_EESCAPE);
++
++ PATFETCH (c1);
++ if (!(c1 == '+' || c1 == '?'))
++ {
++ PATUNFETCH;
++ PATUNFETCH;
++ break;
++ }
++
++ c = c1;
++ }
++ else
++ {
++ PATUNFETCH;
++ break;
++ }
++
++ /* If we get here, we found another repeat character. */
++ }
++
++ /* Star, etc. applied to an empty pattern is equivalent
++ to an empty pattern. */
++ if (!laststart)
++ break;
++
++ /* Now we know whether or not zero matches is allowed
++ and also whether or not two or more matches is allowed. */
++ if (many_times_ok)
++ { /* More than one repetition is allowed, so put in at the
++ end a backward relative jump from `b' to before the next
++ jump we're going to put in below (which jumps from
++ laststart to after this jump).
++
++ But if we are at the `*' in the exact sequence `.*\n',
++ insert an unconditional jump backwards to the .,
++ instead of the beginning of the loop. This way we only
++ push a failure point once, instead of every time
++ through the loop. */
++ assert (p - 1 > pattern);
++
++ /* Allocate the space for the jump. */
++ GET_BUFFER_SPACE (1 + OFFSET_ADDRESS_SIZE);
++
++ /* We know we are not at the first character of the pattern,
++ because laststart was nonzero. And we've already
++ incremented `p', by the way, to be the character after
++ the `*'. Do we have to do something analogous here
++ for null bytes, because of RE_DOT_NOT_NULL? */
++ if (TRANSLATE (*(p - 2)) == TRANSLATE ('.')
++ && zero_times_ok
++ && p < pend && TRANSLATE (*p) == TRANSLATE ('\n')
++ && !(syntax & RE_DOT_NEWLINE))
++ { /* We have .*\n. */
++ STORE_JUMP (jump, b, laststart);
++ keep_string_p = true;
++ }
++ else
++ /* Anything else. */
++ STORE_JUMP (maybe_pop_jump, b, laststart -
++ (1 + OFFSET_ADDRESS_SIZE));
++
++ /* We've added more stuff to the buffer. */
++ b += 1 + OFFSET_ADDRESS_SIZE;
++ }
++
++ /* On failure, jump from laststart to b + 3, which will be the
++ end of the buffer after this jump is inserted. */
++ /* ifdef WCHAR, 'b + 1 + OFFSET_ADDRESS_SIZE' instead of
++ 'b + 3'. */
++ GET_BUFFER_SPACE (1 + OFFSET_ADDRESS_SIZE);
++ INSERT_JUMP (keep_string_p ? on_failure_keep_string_jump
++ : on_failure_jump,
++ laststart, b + 1 + OFFSET_ADDRESS_SIZE);
++ pending_exact = 0;
++ b += 1 + OFFSET_ADDRESS_SIZE;
++
++ if (!zero_times_ok)
++ {
++ /* At least one repetition is required, so insert a
++ `dummy_failure_jump' before the initial
++ `on_failure_jump' instruction of the loop. This
++ effects a skip over that instruction the first time
++ we hit that loop. */
++ GET_BUFFER_SPACE (1 + OFFSET_ADDRESS_SIZE);
++ INSERT_JUMP (dummy_failure_jump, laststart, laststart +
++ 2 + 2 * OFFSET_ADDRESS_SIZE);
++ b += 1 + OFFSET_ADDRESS_SIZE;
++ }
++ }
++ break;
++
++
++ case '.':
++ laststart = b;
++ BUF_PUSH (anychar);
++ break;
++
++
++ case '[':
++ {
++ boolean had_char_class = false;
++#ifdef WCHAR
++ CHAR_T range_start = 0xffffffff;
++#else
++ unsigned int range_start = 0xffffffff;
++#endif
++ if (p == pend) FREE_STACK_RETURN (REG_EBRACK);
++
++#ifdef WCHAR
++ /* We assume a charset(_not) structure as a wchar_t array.
++ charset[0] = (re_opcode_t) charset(_not)
++ charset[1] = l (= length of char_classes)
++ charset[2] = m (= length of collating_symbols)
++ charset[3] = n (= length of equivalence_classes)
++ charset[4] = o (= length of char_ranges)
++ charset[5] = p (= length of chars)
++
++ charset[6] = char_class (wctype_t)
++ charset[6+CHAR_CLASS_SIZE] = char_class (wctype_t)
++ ...
++ charset[l+5] = char_class (wctype_t)
++
++ charset[l+6] = collating_symbol (wchar_t)
++ ...
++ charset[l+m+5] = collating_symbol (wchar_t)
++ ifdef _LIBC we use the index if
++ _NL_COLLATE_SYMB_EXTRAMB instead of
++ wchar_t string.
++
++ charset[l+m+6] = equivalence_classes (wchar_t)
++ ...
++ charset[l+m+n+5] = equivalence_classes (wchar_t)
++ ifdef _LIBC we use the index in
++ _NL_COLLATE_WEIGHT instead of
++ wchar_t string.
++
++ charset[l+m+n+6] = range_start
++ charset[l+m+n+7] = range_end
++ ...
++ charset[l+m+n+2o+4] = range_start
++ charset[l+m+n+2o+5] = range_end
++ ifdef _LIBC we use the value looked up
++ in _NL_COLLATE_COLLSEQ instead of
++ wchar_t character.
++
++ charset[l+m+n+2o+6] = char
++ ...
++ charset[l+m+n+2o+p+5] = char
++
++ */
++
++ /* We need at least 6 spaces: the opcode, the length of
++ char_classes, the length of collating_symbols, the length of
++ equivalence_classes, the length of char_ranges, the length of
++ chars. */
++ GET_BUFFER_SPACE (6);
++
++ /* Save b as laststart. And We use laststart as the pointer
++ to the first element of the charset here.
++ In other words, laststart[i] indicates charset[i]. */
++ laststart = b;
++
++ /* We test `*p == '^' twice, instead of using an if
++ statement, so we only need one BUF_PUSH. */
++ BUF_PUSH (*p == '^' ? charset_not : charset);
++ if (*p == '^')
++ p++;
++
++ /* Push the length of char_classes, the length of
++ collating_symbols, the length of equivalence_classes, the
++ length of char_ranges and the length of chars. */
++ BUF_PUSH_3 (0, 0, 0);
++ BUF_PUSH_2 (0, 0);
++
++ /* Remember the first position in the bracket expression. */
++ p1 = p;
++
++ /* charset_not matches newline according to a syntax bit. */
++ if ((re_opcode_t) b[-6] == charset_not
++ && (syntax & RE_HAT_LISTS_NOT_NEWLINE))
++ {
++ BUF_PUSH('\n');
++ laststart[5]++; /* Update the length of characters */
++ }
++
++ /* Read in characters and ranges, setting map bits. */
++ for (;;)
++ {
++ if (p == pend) FREE_STACK_RETURN (REG_EBRACK);
++
++ PATFETCH (c);
++
++ /* \ might escape characters inside [...] and [^...]. */
++ if ((syntax & RE_BACKSLASH_ESCAPE_IN_LISTS) && c == '\\')
++ {
++ if (p == pend) FREE_STACK_RETURN (REG_EESCAPE);
++
++ PATFETCH (c1);
++ BUF_PUSH(c1);
++ laststart[5]++; /* Update the length of chars */
++ range_start = c1;
++ continue;
++ }
++
++ /* Could be the end of the bracket expression. If it's
++ not (i.e., when the bracket expression is `[]' so
++ far), the ']' character bit gets set way below. */
++ if (c == ']' && p != p1 + 1)
++ break;
++
++ /* Look ahead to see if it's a range when the last thing
++ was a character class. */
++ if (had_char_class && c == '-' && *p != ']')
++ FREE_STACK_RETURN (REG_ERANGE);
++
++ /* Look ahead to see if it's a range when the last thing
++ was a character: if this is a hyphen not at the
++ beginning or the end of a list, then it's the range
++ operator. */
++ if (c == '-'
++ && !(p - 2 >= pattern && p[-2] == '[')
++ && !(p - 3 >= pattern && p[-3] == '[' && p[-2] == '^')
++ && *p != ']')
++ {
++ reg_errcode_t ret;
++ /* Allocate the space for range_start and range_end. */
++ GET_BUFFER_SPACE (2);
++ /* Update the pointer to indicate end of buffer. */
++ b += 2;
++ ret = wcs_compile_range (range_start, &p, pend, translate,
++ syntax, b, laststart);
++ if (ret != REG_NOERROR) FREE_STACK_RETURN (ret);
++ range_start = 0xffffffff;
++ }
++ else if (p[0] == '-' && p[1] != ']')
++ { /* This handles ranges made up of characters only. */
++ reg_errcode_t ret;
++
++ /* Move past the `-'. */
++ PATFETCH (c1);
++ /* Allocate the space for range_start and range_end. */
++ GET_BUFFER_SPACE (2);
++ /* Update the pointer to indicate end of buffer. */
++ b += 2;
++ ret = wcs_compile_range (c, &p, pend, translate, syntax, b,
++ laststart);
++ if (ret != REG_NOERROR) FREE_STACK_RETURN (ret);
++ range_start = 0xffffffff;
++ }
++
++ /* See if we're at the beginning of a possible character
++ class. */
++ else if (syntax & RE_CHAR_CLASSES && c == '[' && *p == ':')
++ { /* Leave room for the null. */
++ char str[CHAR_CLASS_MAX_LENGTH + 1];
++
++ PATFETCH (c);
++ c1 = 0;
++
++ /* If pattern is `[[:'. */
++ if (p == pend) FREE_STACK_RETURN (REG_EBRACK);
++
++ for (;;)
++ {
++ PATFETCH (c);
++ if ((c == ':' && *p == ']') || p == pend)
++ break;
++ if (c1 < CHAR_CLASS_MAX_LENGTH)
++ str[c1++] = c;
++ else
++ /* This is in any case an invalid class name. */
++ str[0] = '\0';
++ }
++ str[c1] = '\0';
++
++ /* If isn't a word bracketed by `[:' and `:]':
++ undo the ending character, the letters, and leave
++ the leading `:' and `[' (but store them as character). */
++ if (c == ':' && *p == ']')
++ {
++ wctype_t wt;
++ uintptr_t alignedp;
++
++ /* Query the character class as wctype_t. */
++ wt = IS_CHAR_CLASS (str);
++ if (wt == 0)
++ FREE_STACK_RETURN (REG_ECTYPE);
++
++ /* Throw away the ] at the end of the character
++ class. */
++ PATFETCH (c);
++
++ if (p == pend) FREE_STACK_RETURN (REG_EBRACK);
++
++ /* Allocate the space for character class. */
++ GET_BUFFER_SPACE(CHAR_CLASS_SIZE);
++ /* Update the pointer to indicate end of buffer. */
++ b += CHAR_CLASS_SIZE;
++ /* Move data which follow character classes
++ not to violate the data. */
++ insert_space(CHAR_CLASS_SIZE,
++ laststart + 6 + laststart[1],
++ b - 1);
++ alignedp = ((uintptr_t)(laststart + 6 + laststart[1])
++ + __alignof__(wctype_t) - 1)
++ & ~(uintptr_t)(__alignof__(wctype_t) - 1);
++ /* Store the character class. */
++ *((wctype_t*)alignedp) = wt;
++ /* Update length of char_classes */
++ laststart[1] += CHAR_CLASS_SIZE;
++
++ had_char_class = true;
++ }
++ else
++ {
++ c1++;
++ while (c1--)
++ PATUNFETCH;
++ BUF_PUSH ('[');
++ BUF_PUSH (':');
++ laststart[5] += 2; /* Update the length of characters */
++ range_start = ':';
++ had_char_class = false;
++ }
++ }
++ else if (syntax & RE_CHAR_CLASSES && c == '[' && (*p == '='
++ || *p == '.'))
++ {
++ CHAR_T str[128]; /* Should be large enough. */
++ CHAR_T delim = *p; /* '=' or '.' */
++# ifdef _LIBC
++ uint32_t nrules =
++ _NL_CURRENT_WORD (LC_COLLATE, _NL_COLLATE_NRULES);
++# endif
++ PATFETCH (c);
++ c1 = 0;
++
++ /* If pattern is `[[=' or '[[.'. */
++ if (p == pend) FREE_STACK_RETURN (REG_EBRACK);
++
++ for (;;)
++ {
++ PATFETCH (c);
++ if ((c == delim && *p == ']') || p == pend)
++ break;
++ if (c1 < sizeof (str) - 1)
++ str[c1++] = c;
++ else
++ /* This is in any case an invalid class name. */
++ str[0] = '\0';
++ }
++ str[c1] = '\0';
++
++ if (c == delim && *p == ']' && str[0] != '\0')
++ {
++ unsigned int i, offset;
++ /* If we have no collation data we use the default
++ collation in which each character is in a class
++ by itself. It also means that ASCII is the
++ character set and therefore we cannot have character
++ with more than one byte in the multibyte
++ representation. */
++
++ /* If not defined _LIBC, we push the name and
++ `\0' for the sake of matching performance. */
++ int datasize = c1 + 1;
++
++# ifdef _LIBC
++ int32_t idx = 0;
++ if (nrules == 0)
++# endif
++ {
++ if (c1 != 1)
++ FREE_STACK_RETURN (REG_ECOLLATE);
++ }
++# ifdef _LIBC
++ else
++ {
++ const int32_t *table;
++ const int32_t *weights;
++ const int32_t *extra;
++ const int32_t *indirect;
++ wint_t *cp;
++
++ /* This #include defines a local function! */
++# include <locale/weightwc.h>
++
++ if(delim == '=')
++ {
++ /* We push the index for equivalence class. */
++ cp = (wint_t*)str;
++
++ table = (const int32_t *)
++ _NL_CURRENT (LC_COLLATE,
++ _NL_COLLATE_TABLEWC);
++ weights = (const int32_t *)
++ _NL_CURRENT (LC_COLLATE,
++ _NL_COLLATE_WEIGHTWC);
++ extra = (const int32_t *)
++ _NL_CURRENT (LC_COLLATE,
++ _NL_COLLATE_EXTRAWC);
++ indirect = (const int32_t *)
++ _NL_CURRENT (LC_COLLATE,
++ _NL_COLLATE_INDIRECTWC);
++
++ idx = findidx ((const wint_t**)&cp, c1);
++ if (idx == 0 || cp < (wint_t*) str + c1)
++ /* This is no valid character. */
++ FREE_STACK_RETURN (REG_ECOLLATE);
++
++ str[0] = (wchar_t)idx;
++ }
++ else /* delim == '.' */
++ {
++ /* We push collation sequence value
++ for collating symbol. */
++ int32_t table_size;
++ const int32_t *symb_table;
++ const unsigned char *extra;
++ int32_t idx;
++ int32_t elem;
++ int32_t second;
++ int32_t hash;
++ char char_str[c1];
++
++ /* We have to convert the name to a single-byte
++ string. This is possible since the names
++ consist of ASCII characters and the internal
++ representation is UCS4. */
++ for (i = 0; i < c1; ++i)
++ char_str[i] = str[i];
++
++ table_size =
++ _NL_CURRENT_WORD (LC_COLLATE,
++ _NL_COLLATE_SYMB_HASH_SIZEMB);
++ symb_table = (const int32_t *)
++ _NL_CURRENT (LC_COLLATE,
++ _NL_COLLATE_SYMB_TABLEMB);
++ extra = (const unsigned char *)
++ _NL_CURRENT (LC_COLLATE,
++ _NL_COLLATE_SYMB_EXTRAMB);
++
++ /* Locate the character in the hashing table. */
++ hash = elem_hash (char_str, c1);
++
++ idx = 0;
++ elem = hash % table_size;
++ second = hash % (table_size - 2);
++ while (symb_table[2 * elem] != 0)
++ {
++ /* First compare the hashing value. */
++ if (symb_table[2 * elem] == hash
++ && c1 == extra[symb_table[2 * elem + 1]]
++ && memcmp (char_str,
++ &extra[symb_table[2 * elem + 1]
++ + 1], c1) == 0)
++ {
++ /* Yep, this is the entry. */
++ idx = symb_table[2 * elem + 1];
++ idx += 1 + extra[idx];
++ break;
++ }
++
++ /* Next entry. */
++ elem += second;
++ }
++
++ if (symb_table[2 * elem] != 0)
++ {
++ /* Compute the index of the byte sequence
++ in the table. */
++ idx += 1 + extra[idx];
++ /* Adjust for the alignment. */
++ idx = (idx + 3) & ~3;
++
++ str[0] = (wchar_t) idx + 4;
++ }
++ else if (symb_table[2 * elem] == 0 && c1 == 1)
++ {
++ /* No valid character. Match it as a
++ single byte character. */
++ had_char_class = false;
++ BUF_PUSH(str[0]);
++ /* Update the length of characters */
++ laststart[5]++;
++ range_start = str[0];
++
++ /* Throw away the ] at the end of the
++ collating symbol. */
++ PATFETCH (c);
++ /* exit from the switch block. */
++ continue;
++ }
++ else
++ FREE_STACK_RETURN (REG_ECOLLATE);
++ }
++ datasize = 1;
++ }
++# endif
++ /* Throw away the ] at the end of the equivalence
++ class (or collating symbol). */
++ PATFETCH (c);
++
++ /* Allocate the space for the equivalence class
++ (or collating symbol) (and '\0' if needed). */
++ GET_BUFFER_SPACE(datasize);
++ /* Update the pointer to indicate end of buffer. */
++ b += datasize;
++
++ if (delim == '=')
++ { /* equivalence class */
++ /* Calculate the offset of char_ranges,
++ which is next to equivalence_classes. */
++ offset = laststart[1] + laststart[2]
++ + laststart[3] +6;
++ /* Insert space. */
++ insert_space(datasize, laststart + offset, b - 1);
++
++ /* Write the equivalence_class and \0. */
++ for (i = 0 ; i < datasize ; i++)
++ laststart[offset + i] = str[i];
++
++ /* Update the length of equivalence_classes. */
++ laststart[3] += datasize;
++ had_char_class = true;
++ }
++ else /* delim == '.' */
++ { /* collating symbol */
++ /* Calculate the offset of the equivalence_classes,
++ which is next to collating_symbols. */
++ offset = laststart[1] + laststart[2] + 6;
++ /* Insert space and write the collationg_symbol
++ and \0. */
++ insert_space(datasize, laststart + offset, b-1);
++ for (i = 0 ; i < datasize ; i++)
++ laststart[offset + i] = str[i];
++
++ /* In re_match_2_internal if range_start < -1, we
++ assume -range_start is the offset of the
++ collating symbol which is specified as
++ the character of the range start. So we assign
++ -(laststart[1] + laststart[2] + 6) to
++ range_start. */
++ range_start = -(laststart[1] + laststart[2] + 6);
++ /* Update the length of collating_symbol. */
++ laststart[2] += datasize;
++ had_char_class = false;
++ }
++ }
++ else
++ {
++ c1++;
++ while (c1--)
++ PATUNFETCH;
++ BUF_PUSH ('[');
++ BUF_PUSH (delim);
++ laststart[5] += 2; /* Update the length of characters */
++ range_start = delim;
++ had_char_class = false;
++ }
++ }
++ else
++ {
++ had_char_class = false;
++ BUF_PUSH(c);
++ laststart[5]++; /* Update the length of characters */
++ range_start = c;
++ }
++ }
++
++#else /* BYTE */
++ /* Ensure that we have enough space to push a charset: the
++ opcode, the length count, and the bitset; 34 bytes in all. */
++ GET_BUFFER_SPACE (34);
++
++ laststart = b;
++
++ /* We test `*p == '^' twice, instead of using an if
++ statement, so we only need one BUF_PUSH. */
++ BUF_PUSH (*p == '^' ? charset_not : charset);
++ if (*p == '^')
++ p++;
++
++ /* Remember the first position in the bracket expression. */
++ p1 = p;
++
++ /* Push the number of bytes in the bitmap. */
++ BUF_PUSH ((1 << BYTEWIDTH) / BYTEWIDTH);
++
++ /* Clear the whole map. */
++ bzero (b, (1 << BYTEWIDTH) / BYTEWIDTH);
++
++ /* charset_not matches newline according to a syntax bit. */
++ if ((re_opcode_t) b[-2] == charset_not
++ && (syntax & RE_HAT_LISTS_NOT_NEWLINE))
++ SET_LIST_BIT ('\n');
++
++ /* Read in characters and ranges, setting map bits. */
++ for (;;)
++ {
++ if (p == pend) FREE_STACK_RETURN (REG_EBRACK);
++
++ PATFETCH (c);
++
++ /* \ might escape characters inside [...] and [^...]. */
++ if ((syntax & RE_BACKSLASH_ESCAPE_IN_LISTS) && c == '\\')
++ {
++ if (p == pend) FREE_STACK_RETURN (REG_EESCAPE);
++
++ PATFETCH (c1);
++ SET_LIST_BIT (c1);
++ range_start = c1;
++ continue;
++ }
++
++ /* Could be the end of the bracket expression. If it's
++ not (i.e., when the bracket expression is `[]' so
++ far), the ']' character bit gets set way below. */
++ if (c == ']' && p != p1 + 1)
++ break;
++
++ /* Look ahead to see if it's a range when the last thing
++ was a character class. */
++ if (had_char_class && c == '-' && *p != ']')
++ FREE_STACK_RETURN (REG_ERANGE);
++
++ /* Look ahead to see if it's a range when the last thing
++ was a character: if this is a hyphen not at the
++ beginning or the end of a list, then it's the range
++ operator. */
++ if (c == '-'
++ && !(p - 2 >= pattern && p[-2] == '[')
++ && !(p - 3 >= pattern && p[-3] == '[' && p[-2] == '^')
++ && *p != ']')
++ {
++ reg_errcode_t ret
++ = byte_compile_range (range_start, &p, pend, translate,
++ syntax, b);
++ if (ret != REG_NOERROR) FREE_STACK_RETURN (ret);
++ range_start = 0xffffffff;
++ }
++
++ else if (p[0] == '-' && p[1] != ']')
++ { /* This handles ranges made up of characters only. */
++ reg_errcode_t ret;
++
++ /* Move past the `-'. */
++ PATFETCH (c1);
++
++ ret = byte_compile_range (c, &p, pend, translate, syntax, b);
++ if (ret != REG_NOERROR) FREE_STACK_RETURN (ret);
++ range_start = 0xffffffff;
++ }
++
++ /* See if we're at the beginning of a possible character
++ class. */
++
++ else if (syntax & RE_CHAR_CLASSES && c == '[' && *p == ':')
++ { /* Leave room for the null. */
++ char str[CHAR_CLASS_MAX_LENGTH + 1];
++
++ PATFETCH (c);
++ c1 = 0;
++
++ /* If pattern is `[[:'. */
++ if (p == pend) FREE_STACK_RETURN (REG_EBRACK);
++
++ for (;;)
++ {
++ PATFETCH (c);
++ if ((c == ':' && *p == ']') || p == pend)
++ break;
++ if (((int) c1) < CHAR_CLASS_MAX_LENGTH)
++ str[c1++] = c;
++ else
++ /* This is in any case an invalid class name. */
++ str[0] = '\0';
++ }
++ str[c1] = '\0';
++
++ /* If isn't a word bracketed by `[:' and `:]':
++ undo the ending character, the letters, and leave
++ the leading `:' and `[' (but set bits for them). */
++ if (c == ':' && *p == ']')
++ {
++# if WIDE_CHAR_SUPPORT
++ boolean is_lower = STREQ (str, "lower");
++ boolean is_upper = STREQ (str, "upper");
++ wctype_t wt;
++ int ch;
++
++ wt = IS_CHAR_CLASS (str);
++ if (wt == 0)
++ FREE_STACK_RETURN (REG_ECTYPE);
++
++ /* Throw away the ] at the end of the character
++ class. */
++ PATFETCH (c);
++
++ if (p == pend) FREE_STACK_RETURN (REG_EBRACK);
++
++ for (ch = 0; ch < 1 << BYTEWIDTH; ++ch)
++ {
++# ifdef _LIBC
++ if (__iswctype (__btowc (ch), wt))
++ SET_LIST_BIT (ch);
++# else
++ if (iswctype (btowc (ch), wt))
++ SET_LIST_BIT (ch);
++# endif
++
++ if (translate && (is_upper || is_lower)
++ && (ISUPPER (ch) || ISLOWER (ch)))
++ SET_LIST_BIT (ch);
++ }
++
++ had_char_class = true;
++# else
++ int ch;
++ boolean is_alnum = STREQ (str, "alnum");
++ boolean is_alpha = STREQ (str, "alpha");
++ boolean is_blank = STREQ (str, "blank");
++ boolean is_cntrl = STREQ (str, "cntrl");
++ boolean is_digit = STREQ (str, "digit");
++ boolean is_graph = STREQ (str, "graph");
++ boolean is_lower = STREQ (str, "lower");
++ boolean is_print = STREQ (str, "print");
++ boolean is_punct = STREQ (str, "punct");
++ boolean is_space = STREQ (str, "space");
++ boolean is_upper = STREQ (str, "upper");
++ boolean is_xdigit = STREQ (str, "xdigit");
++
++ if (!IS_CHAR_CLASS (str))
++ FREE_STACK_RETURN (REG_ECTYPE);
++
++ /* Throw away the ] at the end of the character
++ class. */
++ PATFETCH (c);
++
++ if (p == pend) FREE_STACK_RETURN (REG_EBRACK);
++
++ for (ch = 0; ch < 1 << BYTEWIDTH; ch++)
++ {
++ /* This was split into 3 if's to
++ avoid an arbitrary limit in some compiler. */
++ if ( (is_alnum && ISALNUM (ch))
++ || (is_alpha && ISALPHA (ch))
++ || (is_blank && ISBLANK (ch))
++ || (is_cntrl && ISCNTRL (ch)))
++ SET_LIST_BIT (ch);
++ if ( (is_digit && ISDIGIT (ch))
++ || (is_graph && ISGRAPH (ch))
++ || (is_lower && ISLOWER (ch))
++ || (is_print && ISPRINT (ch)))
++ SET_LIST_BIT (ch);
++ if ( (is_punct && ISPUNCT (ch))
++ || (is_space && ISSPACE (ch))
++ || (is_upper && ISUPPER (ch))
++ || (is_xdigit && ISXDIGIT (ch)))
++ SET_LIST_BIT (ch);
++ if ( translate && (is_upper || is_lower)
++ && (ISUPPER (ch) || ISLOWER (ch)))
++ SET_LIST_BIT (ch);
++ }
++ had_char_class = true;
++# endif /* libc || wctype.h */
++ }
++ else
++ {
++ c1++;
++ while (c1--)
++ PATUNFETCH;
++ SET_LIST_BIT ('[');
++ SET_LIST_BIT (':');
++ range_start = ':';
++ had_char_class = false;
++ }
++ }
++ else if (syntax & RE_CHAR_CLASSES && c == '[' && *p == '=')
++ {
++ unsigned char str[MB_LEN_MAX + 1];
++# ifdef _LIBC
++ uint32_t nrules =
++ _NL_CURRENT_WORD (LC_COLLATE, _NL_COLLATE_NRULES);
++# endif
++
++ PATFETCH (c);
++ c1 = 0;
++
++ /* If pattern is `[[='. */
++ if (p == pend) FREE_STACK_RETURN (REG_EBRACK);
++
++ for (;;)
++ {
++ PATFETCH (c);
++ if ((c == '=' && *p == ']') || p == pend)
++ break;
++ if (c1 < MB_LEN_MAX)
++ str[c1++] = c;
++ else
++ /* This is in any case an invalid class name. */
++ str[0] = '\0';
++ }
++ str[c1] = '\0';
++
++ if (c == '=' && *p == ']' && str[0] != '\0')
++ {
++ /* If we have no collation data we use the default
++ collation in which each character is in a class
++ by itself. It also means that ASCII is the
++ character set and therefore we cannot have character
++ with more than one byte in the multibyte
++ representation. */
++# ifdef _LIBC
++ if (nrules == 0)
++# endif
++ {
++ if (c1 != 1)
++ FREE_STACK_RETURN (REG_ECOLLATE);
++
++ /* Throw away the ] at the end of the equivalence
++ class. */
++ PATFETCH (c);
++
++ /* Set the bit for the character. */
++ SET_LIST_BIT (str[0]);
++ }
++# ifdef _LIBC
++ else
++ {
++ /* Try to match the byte sequence in `str' against
++ those known to the collate implementation.
++ First find out whether the bytes in `str' are
++ actually from exactly one character. */
++ const int32_t *table;
++ const unsigned char *weights;
++ const unsigned char *extra;
++ const int32_t *indirect;
++ int32_t idx;
++ const unsigned char *cp = str;
++ int ch;
++
++ /* This #include defines a local function! */
++# include <locale/weight.h>
++
++ table = (const int32_t *)
++ _NL_CURRENT (LC_COLLATE, _NL_COLLATE_TABLEMB);
++ weights = (const unsigned char *)
++ _NL_CURRENT (LC_COLLATE, _NL_COLLATE_WEIGHTMB);
++ extra = (const unsigned char *)
++ _NL_CURRENT (LC_COLLATE, _NL_COLLATE_EXTRAMB);
++ indirect = (const int32_t *)
++ _NL_CURRENT (LC_COLLATE, _NL_COLLATE_INDIRECTMB);
++
++ idx = findidx (&cp, c1);
++ if (idx == 0 || cp < str + c1)
++ /* This is no valid character. */
++ FREE_STACK_RETURN (REG_ECOLLATE);
++
++ /* Throw away the ] at the end of the equivalence
++ class. */
++ PATFETCH (c);
++
++ /* Now we have to go throught the whole table
++ and find all characters which have the same
++ first level weight.
++
++ XXX Note that this is not entirely correct.
++ we would have to match multibyte sequences
++ but this is not possible with the current
++ implementation. */
++ for (ch = 1; ch < 256; ++ch)
++ /* XXX This test would have to be changed if we
++ would allow matching multibyte sequences. */
++ if (table[ch] > 0)
++ {
++ int32_t idx2 = table[ch];
++ size_t len = weights[idx2];
++
++ /* Test whether the lenghts match. */
++ if (weights[idx] == len)
++ {
++ /* They do. New compare the bytes of
++ the weight. */
++ size_t cnt = 0;
++
++ while (cnt < len
++ && (weights[idx + 1 + cnt]
++ == weights[idx2 + 1 + cnt]))
++ ++cnt;
++
++ if (cnt == len)
++ /* They match. Mark the character as
++ acceptable. */
++ SET_LIST_BIT (ch);
++ }
++ }
++ }
++# endif
++ had_char_class = true;
++ }
++ else
++ {
++ c1++;
++ while (c1--)
++ PATUNFETCH;
++ SET_LIST_BIT ('[');
++ SET_LIST_BIT ('=');
++ range_start = '=';
++ had_char_class = false;
++ }
++ }
++ else if (syntax & RE_CHAR_CLASSES && c == '[' && *p == '.')
++ {
++ unsigned char str[128]; /* Should be large enough. */
++# ifdef _LIBC
++ uint32_t nrules =
++ _NL_CURRENT_WORD (LC_COLLATE, _NL_COLLATE_NRULES);
++# endif
++
++ PATFETCH (c);
++ c1 = 0;
++
++ /* If pattern is `[[.'. */
++ if (p == pend) FREE_STACK_RETURN (REG_EBRACK);
++
++ for (;;)
++ {
++ PATFETCH (c);
++ if ((c == '.' && *p == ']') || p == pend)
++ break;
++ if (c1 < sizeof (str))
++ str[c1++] = c;
++ else
++ /* This is in any case an invalid class name. */
++ str[0] = '\0';
++ }
++ str[c1] = '\0';
++
++ if (c == '.' && *p == ']' && str[0] != '\0')
++ {
++ /* If we have no collation data we use the default
++ collation in which each character is the name
++ for its own class which contains only the one
++ character. It also means that ASCII is the
++ character set and therefore we cannot have character
++ with more than one byte in the multibyte
++ representation. */
++# ifdef _LIBC
++ if (nrules == 0)
++# endif
++ {
++ if (c1 != 1)
++ FREE_STACK_RETURN (REG_ECOLLATE);
++
++ /* Throw away the ] at the end of the equivalence
++ class. */
++ PATFETCH (c);
++
++ /* Set the bit for the character. */
++ SET_LIST_BIT (str[0]);
++ range_start = ((const unsigned char *) str)[0];
++ }
++# ifdef _LIBC
++ else
++ {
++ /* Try to match the byte sequence in `str' against
++ those known to the collate implementation.
++ First find out whether the bytes in `str' are
++ actually from exactly one character. */
++ int32_t table_size;
++ const int32_t *symb_table;
++ const unsigned char *extra;
++ int32_t idx;
++ int32_t elem;
++ int32_t second;
++ int32_t hash;
++
++ table_size =
++ _NL_CURRENT_WORD (LC_COLLATE,
++ _NL_COLLATE_SYMB_HASH_SIZEMB);
++ symb_table = (const int32_t *)
++ _NL_CURRENT (LC_COLLATE,
++ _NL_COLLATE_SYMB_TABLEMB);
++ extra = (const unsigned char *)
++ _NL_CURRENT (LC_COLLATE,
++ _NL_COLLATE_SYMB_EXTRAMB);
++
++ /* Locate the character in the hashing table. */
++ hash = elem_hash ((const char *) str, c1);
++
++ idx = 0;
++ elem = hash % table_size;
++ second = hash % (table_size - 2);
++ while (symb_table[2 * elem] != 0)
++ {
++ /* First compare the hashing value. */
++ if (symb_table[2 * elem] == hash
++ && c1 == extra[symb_table[2 * elem + 1]]
++ && memcmp (str,
++ &extra[symb_table[2 * elem + 1]
++ + 1],
++ c1) == 0)
++ {
++ /* Yep, this is the entry. */
++ idx = symb_table[2 * elem + 1];
++ idx += 1 + extra[idx];
++ break;
++ }
++
++ /* Next entry. */
++ elem += second;
++ }
++
++ if (symb_table[2 * elem] == 0)
++ /* This is no valid character. */
++ FREE_STACK_RETURN (REG_ECOLLATE);
++
++ /* Throw away the ] at the end of the equivalence
++ class. */
++ PATFETCH (c);
++
++ /* Now add the multibyte character(s) we found
++ to the accept list.
++
++ XXX Note that this is not entirely correct.
++ we would have to match multibyte sequences
++ but this is not possible with the current
++ implementation. Also, we have to match
++ collating symbols, which expand to more than
++ one file, as a whole and not allow the
++ individual bytes. */
++ c1 = extra[idx++];
++ if (c1 == 1)
++ range_start = extra[idx];
++ while (c1-- > 0)
++ {
++ SET_LIST_BIT (extra[idx]);
++ ++idx;
++ }
++ }
++# endif
++ had_char_class = false;
++ }
++ else
++ {
++ c1++;
++ while (c1--)
++ PATUNFETCH;
++ SET_LIST_BIT ('[');
++ SET_LIST_BIT ('.');
++ range_start = '.';
++ had_char_class = false;
++ }
++ }
++ else
++ {
++ had_char_class = false;
++ SET_LIST_BIT (c);
++ range_start = c;
++ }
++ }
++
++ /* Discard any (non)matching list bytes that are all 0 at the
++ end of the map. Decrease the map-length byte too. */
++ while ((int) b[-1] > 0 && b[b[-1] - 1] == 0)
++ b[-1]--;
++ b += b[-1];
++#endif /* WCHAR */
++ }
++ break;
++
++
++ case '(':
++ if (syntax & RE_NO_BK_PARENS)
++ goto handle_open;
++ else
++ goto normal_char;
++
++
++ case ')':
++ if (syntax & RE_NO_BK_PARENS)
++ goto handle_close;
++ else
++ goto normal_char;
++
++
++ case '\n':
++ if (syntax & RE_NEWLINE_ALT)
++ goto handle_alt;
++ else
++ goto normal_char;
++
++
++ case '|':
++ if (syntax & RE_NO_BK_VBAR)
++ goto handle_alt;
++ else
++ goto normal_char;
++
++
++ case '{':
++ if (syntax & RE_INTERVALS && syntax & RE_NO_BK_BRACES)
++ goto handle_interval;
++ else
++ goto normal_char;
++
++
++ case '\\':
++ if (p == pend) FREE_STACK_RETURN (REG_EESCAPE);
++
++ /* Do not translate the character after the \, so that we can
++ distinguish, e.g., \B from \b, even if we normally would
++ translate, e.g., B to b. */
++ PATFETCH_RAW (c);
++
++ switch (c)
++ {
++ case '(':
++ if (syntax & RE_NO_BK_PARENS)
++ goto normal_backslash;
++
++ handle_open:
++ bufp->re_nsub++;
++ regnum++;
++
++ if (COMPILE_STACK_FULL)
++ {
++ RETALLOC (compile_stack.stack, compile_stack.size << 1,
++ compile_stack_elt_t);
++ if (compile_stack.stack == NULL) return REG_ESPACE;
++
++ compile_stack.size <<= 1;
++ }
++
++ /* These are the values to restore when we hit end of this
++ group. They are all relative offsets, so that if the
++ whole pattern moves because of realloc, they will still
++ be valid. */
++ COMPILE_STACK_TOP.begalt_offset = begalt - COMPILED_BUFFER_VAR;
++ COMPILE_STACK_TOP.fixup_alt_jump
++ = fixup_alt_jump ? fixup_alt_jump - COMPILED_BUFFER_VAR + 1 : 0;
++ COMPILE_STACK_TOP.laststart_offset = b - COMPILED_BUFFER_VAR;
++ COMPILE_STACK_TOP.regnum = regnum;
++
++ /* We will eventually replace the 0 with the number of
++ groups inner to this one. But do not push a
++ start_memory for groups beyond the last one we can
++ represent in the compiled pattern. */
++ if (regnum <= MAX_REGNUM)
++ {
++ COMPILE_STACK_TOP.inner_group_offset = b
++ - COMPILED_BUFFER_VAR + 2;
++ BUF_PUSH_3 (start_memory, regnum, 0);
++ }
++
++ compile_stack.avail++;
++
++ fixup_alt_jump = 0;
++ laststart = 0;
++ begalt = b;
++ /* If we've reached MAX_REGNUM groups, then this open
++ won't actually generate any code, so we'll have to
++ clear pending_exact explicitly. */
++ pending_exact = 0;
++ break;
++
++
++ case ')':
++ if (syntax & RE_NO_BK_PARENS) goto normal_backslash;
++
++ if (COMPILE_STACK_EMPTY)
++ {
++ if (syntax & RE_UNMATCHED_RIGHT_PAREN_ORD)
++ goto normal_backslash;
++ else
++ FREE_STACK_RETURN (REG_ERPAREN);
++ }
++
++ handle_close:
++ if (fixup_alt_jump)
++ { /* Push a dummy failure point at the end of the
++ alternative for a possible future
++ `pop_failure_jump' to pop. See comments at
++ `push_dummy_failure' in `re_match_2'. */
++ BUF_PUSH (push_dummy_failure);
++
++ /* We allocated space for this jump when we assigned
++ to `fixup_alt_jump', in the `handle_alt' case below. */
++ STORE_JUMP (jump_past_alt, fixup_alt_jump, b - 1);
++ }
++
++ /* See similar code for backslashed left paren above. */
++ if (COMPILE_STACK_EMPTY)
++ {
++ if (syntax & RE_UNMATCHED_RIGHT_PAREN_ORD)
++ goto normal_char;
++ else
++ FREE_STACK_RETURN (REG_ERPAREN);
++ }
++
++ /* Since we just checked for an empty stack above, this
++ ``can't happen''. */
++ assert (compile_stack.avail != 0);
++ {
++ /* We don't just want to restore into `regnum', because
++ later groups should continue to be numbered higher,
++ as in `(ab)c(de)' -- the second group is #2. */
++ regnum_t this_group_regnum;
++
++ compile_stack.avail--;
++ begalt = COMPILED_BUFFER_VAR + COMPILE_STACK_TOP.begalt_offset;
++ fixup_alt_jump
++ = COMPILE_STACK_TOP.fixup_alt_jump
++ ? COMPILED_BUFFER_VAR + COMPILE_STACK_TOP.fixup_alt_jump - 1
++ : 0;
++ laststart = COMPILED_BUFFER_VAR + COMPILE_STACK_TOP.laststart_offset;
++ this_group_regnum = COMPILE_STACK_TOP.regnum;
++ /* If we've reached MAX_REGNUM groups, then this open
++ won't actually generate any code, so we'll have to
++ clear pending_exact explicitly. */
++ pending_exact = 0;
++
++ /* We're at the end of the group, so now we know how many
++ groups were inside this one. */
++ if (this_group_regnum <= MAX_REGNUM)
++ {
++ UCHAR_T *inner_group_loc
++ = COMPILED_BUFFER_VAR + COMPILE_STACK_TOP.inner_group_offset;
++
++ *inner_group_loc = regnum - this_group_regnum;
++ BUF_PUSH_3 (stop_memory, this_group_regnum,
++ regnum - this_group_regnum);
++ }
++ }
++ break;
++
++
++ case '|': /* `\|'. */
++ if (syntax & RE_LIMITED_OPS || syntax & RE_NO_BK_VBAR)
++ goto normal_backslash;
++ handle_alt:
++ if (syntax & RE_LIMITED_OPS)
++ goto normal_char;
++
++ /* Insert before the previous alternative a jump which
++ jumps to this alternative if the former fails. */
++ GET_BUFFER_SPACE (1 + OFFSET_ADDRESS_SIZE);
++ INSERT_JUMP (on_failure_jump, begalt,
++ b + 2 + 2 * OFFSET_ADDRESS_SIZE);
++ pending_exact = 0;
++ b += 1 + OFFSET_ADDRESS_SIZE;
++
++ /* The alternative before this one has a jump after it
++ which gets executed if it gets matched. Adjust that
++ jump so it will jump to this alternative's analogous
++ jump (put in below, which in turn will jump to the next
++ (if any) alternative's such jump, etc.). The last such
++ jump jumps to the correct final destination. A picture:
++ _____ _____
++ | | | |
++ | v | v
++ a | b | c
++
++ If we are at `b', then fixup_alt_jump right now points to a
++ three-byte space after `a'. We'll put in the jump, set
++ fixup_alt_jump to right after `b', and leave behind three
++ bytes which we'll fill in when we get to after `c'. */
++
++ if (fixup_alt_jump)
++ STORE_JUMP (jump_past_alt, fixup_alt_jump, b);
++
++ /* Mark and leave space for a jump after this alternative,
++ to be filled in later either by next alternative or
++ when know we're at the end of a series of alternatives. */
++ fixup_alt_jump = b;
++ GET_BUFFER_SPACE (1 + OFFSET_ADDRESS_SIZE);
++ b += 1 + OFFSET_ADDRESS_SIZE;
++
++ laststart = 0;
++ begalt = b;
++ break;
++
++
++ case '{':
++ /* If \{ is a literal. */
++ if (!(syntax & RE_INTERVALS)
++ /* If we're at `\{' and it's not the open-interval
++ operator. */
++ || (syntax & RE_NO_BK_BRACES))
++ goto normal_backslash;
++
++ handle_interval:
++ {
++ /* If got here, then the syntax allows intervals. */
++
++ /* At least (most) this many matches must be made. */
++ int lower_bound = -1, upper_bound = -1;
++
++ /* Place in the uncompiled pattern (i.e., just after
++ the '{') to go back to if the interval is invalid. */
++ const CHAR_T *beg_interval = p;
++
++ if (p == pend)
++ goto invalid_interval;
++
++ GET_UNSIGNED_NUMBER (lower_bound);
++
++ if (c == ',')
++ {
++ GET_UNSIGNED_NUMBER (upper_bound);
++ if (upper_bound < 0)
++ upper_bound = RE_DUP_MAX;
++ }
++ else
++ /* Interval such as `{1}' => match exactly once. */
++ upper_bound = lower_bound;
++
++ if (! (0 <= lower_bound && lower_bound <= upper_bound))
++ goto invalid_interval;
++
++ if (!(syntax & RE_NO_BK_BRACES))
++ {
++ if (c != '\\' || p == pend)
++ goto invalid_interval;
++ PATFETCH (c);
++ }
++
++ if (c != '}')
++ goto invalid_interval;
++
++ /* If it's invalid to have no preceding re. */
++ if (!laststart)
++ {
++ if (syntax & RE_CONTEXT_INVALID_OPS
++ && !(syntax & RE_INVALID_INTERVAL_ORD))
++ FREE_STACK_RETURN (REG_BADRPT);
++ else if (syntax & RE_CONTEXT_INDEP_OPS)
++ laststart = b;
++ else
++ goto unfetch_interval;
++ }
++
++ /* We just parsed a valid interval. */
++
++ if (RE_DUP_MAX < upper_bound)
++ FREE_STACK_RETURN (REG_BADBR);
++
++ /* If the upper bound is zero, don't want to succeed at
++ all; jump from `laststart' to `b + 3', which will be
++ the end of the buffer after we insert the jump. */
++ /* ifdef WCHAR, 'b + 1 + OFFSET_ADDRESS_SIZE'
++ instead of 'b + 3'. */
++ if (upper_bound == 0)
++ {
++ GET_BUFFER_SPACE (1 + OFFSET_ADDRESS_SIZE);
++ INSERT_JUMP (jump, laststart, b + 1
++ + OFFSET_ADDRESS_SIZE);
++ b += 1 + OFFSET_ADDRESS_SIZE;
++ }
++
++ /* Otherwise, we have a nontrivial interval. When
++ we're all done, the pattern will look like:
++ set_number_at <jump count> <upper bound>
++ set_number_at <succeed_n count> <lower bound>
++ succeed_n <after jump addr> <succeed_n count>
++ <body of loop>
++ jump_n <succeed_n addr> <jump count>
++ (The upper bound and `jump_n' are omitted if
++ `upper_bound' is 1, though.) */
++ else
++ { /* If the upper bound is > 1, we need to insert
++ more at the end of the loop. */
++ unsigned nbytes = 2 + 4 * OFFSET_ADDRESS_SIZE +
++ (upper_bound > 1) * (2 + 4 * OFFSET_ADDRESS_SIZE);
++
++ GET_BUFFER_SPACE (nbytes);
++
++ /* Initialize lower bound of the `succeed_n', even
++ though it will be set during matching by its
++ attendant `set_number_at' (inserted next),
++ because `re_compile_fastmap' needs to know.
++ Jump to the `jump_n' we might insert below. */
++ INSERT_JUMP2 (succeed_n, laststart,
++ b + 1 + 2 * OFFSET_ADDRESS_SIZE
++ + (upper_bound > 1) * (1 + 2 * OFFSET_ADDRESS_SIZE)
++ , lower_bound);
++ b += 1 + 2 * OFFSET_ADDRESS_SIZE;
++
++ /* Code to initialize the lower bound. Insert
++ before the `succeed_n'. The `5' is the last two
++ bytes of this `set_number_at', plus 3 bytes of
++ the following `succeed_n'. */
++ /* ifdef WCHAR, The '1+2*OFFSET_ADDRESS_SIZE'
++ is the 'set_number_at', plus '1+OFFSET_ADDRESS_SIZE'
++ of the following `succeed_n'. */
++ PREFIX(insert_op2) (set_number_at, laststart, 1
++ + 2 * OFFSET_ADDRESS_SIZE, lower_bound, b);
++ b += 1 + 2 * OFFSET_ADDRESS_SIZE;
++
++ if (upper_bound > 1)
++ { /* More than one repetition is allowed, so
++ append a backward jump to the `succeed_n'
++ that starts this interval.
++
++ When we've reached this during matching,
++ we'll have matched the interval once, so
++ jump back only `upper_bound - 1' times. */
++ STORE_JUMP2 (jump_n, b, laststart
++ + 2 * OFFSET_ADDRESS_SIZE + 1,
++ upper_bound - 1);
++ b += 1 + 2 * OFFSET_ADDRESS_SIZE;
++
++ /* The location we want to set is the second
++ parameter of the `jump_n'; that is `b-2' as
++ an absolute address. `laststart' will be
++ the `set_number_at' we're about to insert;
++ `laststart+3' the number to set, the source
++ for the relative address. But we are
++ inserting into the middle of the pattern --
++ so everything is getting moved up by 5.
++ Conclusion: (b - 2) - (laststart + 3) + 5,
++ i.e., b - laststart.
++
++ We insert this at the beginning of the loop
++ so that if we fail during matching, we'll
++ reinitialize the bounds. */
++ PREFIX(insert_op2) (set_number_at, laststart,
++ b - laststart,
++ upper_bound - 1, b);
++ b += 1 + 2 * OFFSET_ADDRESS_SIZE;
++ }
++ }
++ pending_exact = 0;
++ break;
++
++ invalid_interval:
++ if (!(syntax & RE_INVALID_INTERVAL_ORD))
++ FREE_STACK_RETURN (p == pend ? REG_EBRACE : REG_BADBR);
++ unfetch_interval:
++ /* Match the characters as literals. */
++ p = beg_interval;
++ c = '{';
++ if (syntax & RE_NO_BK_BRACES)
++ goto normal_char;
++ else
++ goto normal_backslash;
++ }
++
++#ifdef emacs
++ /* There is no way to specify the before_dot and after_dot
++ operators. rms says this is ok. --karl */
++ case '=':
++ BUF_PUSH (at_dot);
++ break;
++
++ case 's':
++ laststart = b;
++ PATFETCH (c);
++ BUF_PUSH_2 (syntaxspec, syntax_spec_code[c]);
++ break;
++
++ case 'S':
++ laststart = b;
++ PATFETCH (c);
++ BUF_PUSH_2 (notsyntaxspec, syntax_spec_code[c]);
++ break;
++#endif /* emacs */
++
++
++ case 'w':
++ if (syntax & RE_NO_GNU_OPS)
++ goto normal_char;
++ laststart = b;
++ BUF_PUSH (wordchar);
++ break;
++
++
++ case 'W':
++ if (syntax & RE_NO_GNU_OPS)
++ goto normal_char;
++ laststart = b;
++ BUF_PUSH (notwordchar);
++ break;
++
++
++ case '<':
++ if (syntax & RE_NO_GNU_OPS)
++ goto normal_char;
++ BUF_PUSH (wordbeg);
++ break;
++
++ case '>':
++ if (syntax & RE_NO_GNU_OPS)
++ goto normal_char;
++ BUF_PUSH (wordend);
++ break;
++
++ case 'b':
++ if (syntax & RE_NO_GNU_OPS)
++ goto normal_char;
++ BUF_PUSH (wordbound);
++ break;
++
++ case 'B':
++ if (syntax & RE_NO_GNU_OPS)
++ goto normal_char;
++ BUF_PUSH (notwordbound);
++ break;
++
++ case '`':
++ if (syntax & RE_NO_GNU_OPS)
++ goto normal_char;
++ BUF_PUSH (begbuf);
++ break;
++
++ case '\'':
++ if (syntax & RE_NO_GNU_OPS)
++ goto normal_char;
++ BUF_PUSH (endbuf);
++ break;
++
++ case '1': case '2': case '3': case '4': case '5':
++ case '6': case '7': case '8': case '9':
++ if (syntax & RE_NO_BK_REFS)
++ goto normal_char;
++
++ c1 = c - '0';
++
++ if (c1 > regnum)
++ FREE_STACK_RETURN (REG_ESUBREG);
++
++ /* Can't back reference to a subexpression if inside of it. */
++ if (group_in_compile_stack (compile_stack, (regnum_t) c1))
++ goto normal_char;
++
++ laststart = b;
++ BUF_PUSH_2 (duplicate, c1);
++ break;
++
++
++ case '+':
++ case '?':
++ if (syntax & RE_BK_PLUS_QM)
++ goto handle_plus;
++ else
++ goto normal_backslash;
++
++ default:
++ normal_backslash:
++ /* You might think it would be useful for \ to mean
++ not to translate; but if we don't translate it
++ it will never match anything. */
++ c = TRANSLATE (c);
++ goto normal_char;
++ }
++ break;
++
++
++ default:
++ /* Expects the character in `c'. */
++ normal_char:
++ /* If no exactn currently being built. */
++ if (!pending_exact
++#ifdef WCHAR
++ /* If last exactn handle binary(or character) and
++ new exactn handle character(or binary). */
++ || is_exactn_bin != is_binary[p - 1 - pattern]
++#endif /* WCHAR */
++
++ /* If last exactn not at current position. */
++ || pending_exact + *pending_exact + 1 != b
++
++ /* We have only one byte following the exactn for the count. */
++ || *pending_exact == (1 << BYTEWIDTH) - 1
++
++ /* If followed by a repetition operator. */
++ || *p == '*' || *p == '^'
++ || ((syntax & RE_BK_PLUS_QM)
++ ? *p == '\\' && (p[1] == '+' || p[1] == '?')
++ : (*p == '+' || *p == '?'))
++ || ((syntax & RE_INTERVALS)
++ && ((syntax & RE_NO_BK_BRACES)
++ ? *p == '{'
++ : (p[0] == '\\' && p[1] == '{'))))
++ {
++ /* Start building a new exactn. */
++
++ laststart = b;
++
++#ifdef WCHAR
++ /* Is this exactn binary data or character? */
++ is_exactn_bin = is_binary[p - 1 - pattern];
++ if (is_exactn_bin)
++ BUF_PUSH_2 (exactn_bin, 0);
++ else
++ BUF_PUSH_2 (exactn, 0);
++#else
++ BUF_PUSH_2 (exactn, 0);
++#endif /* WCHAR */
++ pending_exact = b - 1;
++ }
++
++ BUF_PUSH (c);
++ (*pending_exact)++;
++ break;
++ } /* switch (c) */
++ } /* while p != pend */
++
++
++ /* Through the pattern now. */
++
++ if (fixup_alt_jump)
++ STORE_JUMP (jump_past_alt, fixup_alt_jump, b);
++
++ if (!COMPILE_STACK_EMPTY)
++ FREE_STACK_RETURN (REG_EPAREN);
++
++ /* If we don't want backtracking, force success
++ the first time we reach the end of the compiled pattern. */
++ if (syntax & RE_NO_POSIX_BACKTRACKING)
++ BUF_PUSH (succeed);
++
++#ifdef WCHAR
++ free (pattern);
++ free (mbs_offset);
++ free (is_binary);
++#endif
++ free (compile_stack.stack);
++
++ /* We have succeeded; set the length of the buffer. */
++#ifdef WCHAR
++ bufp->used = (uintptr_t) b - (uintptr_t) COMPILED_BUFFER_VAR;
++#else
++ bufp->used = b - bufp->buffer;
++#endif
++
++#ifdef DEBUG
++ if (debug)
++ {
++ DEBUG_PRINT1 ("\nCompiled pattern: \n");
++ PREFIX(print_compiled_pattern) (bufp);
++ }
++#endif /* DEBUG */
++
++#ifndef MATCH_MAY_ALLOCATE
++ /* Initialize the failure stack to the largest possible stack. This
++ isn't necessary unless we're trying to avoid calling alloca in
++ the search and match routines. */
++ {
++ int num_regs = bufp->re_nsub + 1;
++
++ /* Since DOUBLE_FAIL_STACK refuses to double only if the current size
++ is strictly greater than re_max_failures, the largest possible stack
++ is 2 * re_max_failures failure points. */
++ if (fail_stack.size < (2 * re_max_failures * MAX_FAILURE_ITEMS))
++ {
++ fail_stack.size = (2 * re_max_failures * MAX_FAILURE_ITEMS);
++
++# ifdef emacs
++ if (! fail_stack.stack)
++ fail_stack.stack
++ = (PREFIX(fail_stack_elt_t) *) xmalloc (fail_stack.size
++ * sizeof (PREFIX(fail_stack_elt_t)));
++ else
++ fail_stack.stack
++ = (PREFIX(fail_stack_elt_t) *) xrealloc (fail_stack.stack,
++ (fail_stack.size
++ * sizeof (PREFIX(fail_stack_elt_t))));
++# else /* not emacs */
++ if (! fail_stack.stack)
++ fail_stack.stack
++ = (PREFIX(fail_stack_elt_t) *) malloc (fail_stack.size
++ * sizeof (PREFIX(fail_stack_elt_t)));
++ else
++ fail_stack.stack
++ = (PREFIX(fail_stack_elt_t) *) realloc (fail_stack.stack,
++ (fail_stack.size
++ * sizeof (PREFIX(fail_stack_elt_t))));
++# endif /* not emacs */
++ }
++
++ PREFIX(regex_grow_registers) (num_regs);
++ }
++#endif /* not MATCH_MAY_ALLOCATE */
++
++ return REG_NOERROR;
++} /* regex_compile */
++
++/* Subroutines for `regex_compile'. */
++
++/* Store OP at LOC followed by two-byte integer parameter ARG. */
++/* ifdef WCHAR, integer parameter is 1 wchar_t. */
++
++static void
++PREFIX(store_op1) (re_opcode_t op, UCHAR_T *loc, int arg)
++{
++ *loc = (UCHAR_T) op;
++ STORE_NUMBER (loc + 1, arg);
++}
++
++
++/* Like `store_op1', but for two two-byte parameters ARG1 and ARG2. */
++/* ifdef WCHAR, integer parameter is 1 wchar_t. */
++
++static void
++PREFIX(store_op2) (re_opcode_t op, UCHAR_T *loc, int arg1, int arg2)
++{
++ *loc = (UCHAR_T) op;
++ STORE_NUMBER (loc + 1, arg1);
++ STORE_NUMBER (loc + 1 + OFFSET_ADDRESS_SIZE, arg2);
++}
++
++
++/* Copy the bytes from LOC to END to open up three bytes of space at LOC
++ for OP followed by two-byte integer parameter ARG. */
++/* ifdef WCHAR, integer parameter is 1 wchar_t. */
++
++static void
++PREFIX(insert_op1) (re_opcode_t op, UCHAR_T *loc, int arg, UCHAR_T *end)
++{
++ register UCHAR_T *pfrom = end;
++ register UCHAR_T *pto = end + 1 + OFFSET_ADDRESS_SIZE;
++
++ while (pfrom != loc)
++ *--pto = *--pfrom;
++
++ PREFIX(store_op1) (op, loc, arg);
++}
++
++
++/* Like `insert_op1', but for two two-byte parameters ARG1 and ARG2. */
++/* ifdef WCHAR, integer parameter is 1 wchar_t. */
++
++static void
++PREFIX(insert_op2) (re_opcode_t op, UCHAR_T *loc, int arg1,
++ int arg2, UCHAR_T *end)
++{
++ register UCHAR_T *pfrom = end;
++ register UCHAR_T *pto = end + 1 + 2 * OFFSET_ADDRESS_SIZE;
++
++ while (pfrom != loc)
++ *--pto = *--pfrom;
++
++ PREFIX(store_op2) (op, loc, arg1, arg2);
++}
++
++
++/* P points to just after a ^ in PATTERN. Return true if that ^ comes
++ after an alternative or a begin-subexpression. We assume there is at
++ least one character before the ^. */
++
++static boolean
++PREFIX(at_begline_loc_p) (const CHAR_T *pattern, const CHAR_T *p,
++ reg_syntax_t syntax)
++{
++ const CHAR_T *prev = p - 2;
++ boolean prev_prev_backslash = prev > pattern && prev[-1] == '\\';
++
++ return
++ /* After a subexpression? */
++ (*prev == '(' && (syntax & RE_NO_BK_PARENS || prev_prev_backslash))
++ /* After an alternative? */
++ || (*prev == '|' && (syntax & RE_NO_BK_VBAR || prev_prev_backslash));
++}
++
++
++/* The dual of at_begline_loc_p. This one is for $. We assume there is
++ at least one character after the $, i.e., `P < PEND'. */
++
++static boolean
++PREFIX(at_endline_loc_p) (const CHAR_T *p, const CHAR_T *pend,
++ reg_syntax_t syntax)
++{
++ const CHAR_T *next = p;
++ boolean next_backslash = *next == '\\';
++ const CHAR_T *next_next = p + 1 < pend ? p + 1 : 0;
++
++ return
++ /* Before a subexpression? */
++ (syntax & RE_NO_BK_PARENS ? *next == ')'
++ : next_backslash && next_next && *next_next == ')')
++ /* Before an alternative? */
++ || (syntax & RE_NO_BK_VBAR ? *next == '|'
++ : next_backslash && next_next && *next_next == '|');
++}
++
++#else /* not INSIDE_RECURSION */
++
++/* Returns true if REGNUM is in one of COMPILE_STACK's elements and
++ false if it's not. */
++
++static boolean
++group_in_compile_stack (compile_stack_type compile_stack, regnum_t regnum)
++{
++ int this_element;
++
++ for (this_element = compile_stack.avail - 1;
++ this_element >= 0;
++ this_element--)
++ if (compile_stack.stack[this_element].regnum == regnum)
++ return true;
++
++ return false;
++}
++#endif /* not INSIDE_RECURSION */
++
++#ifdef INSIDE_RECURSION
++
++#ifdef WCHAR
++/* This insert space, which size is "num", into the pattern at "loc".
++ "end" must point the end of the allocated buffer. */
++static void
++insert_space (int num, CHAR_T *loc, CHAR_T *end)
++{
++ register CHAR_T *pto = end;
++ register CHAR_T *pfrom = end - num;
++
++ while (pfrom >= loc)
++ *pto-- = *pfrom--;
++}
++#endif /* WCHAR */
++
++#ifdef WCHAR
++static reg_errcode_t
++wcs_compile_range (CHAR_T range_start_char, const CHAR_T **p_ptr,
++ const CHAR_T *pend, RE_TRANSLATE_TYPE translate,
++ reg_syntax_t syntax, CHAR_T *b, CHAR_T *char_set)
++{
++ const CHAR_T *p = *p_ptr;
++ CHAR_T range_start, range_end;
++ reg_errcode_t ret;
++# ifdef _LIBC
++ uint32_t nrules;
++ uint32_t start_val, end_val;
++# endif
++ if (p == pend)
++ return REG_ERANGE;
++
++# ifdef _LIBC
++ nrules = _NL_CURRENT_WORD (LC_COLLATE, _NL_COLLATE_NRULES);
++ if (nrules != 0)
++ {
++ const char *collseq = (const char *) _NL_CURRENT(LC_COLLATE,
++ _NL_COLLATE_COLLSEQWC);
++ const unsigned char *extra = (const unsigned char *)
++ _NL_CURRENT (LC_COLLATE, _NL_COLLATE_SYMB_EXTRAMB);
++
++ if (range_start_char < -1)
++ {
++ /* range_start is a collating symbol. */
++ int32_t *wextra;
++ /* Retreive the index and get collation sequence value. */
++ wextra = (int32_t*)(extra + char_set[-range_start_char]);
++ start_val = wextra[1 + *wextra];
++ }
++ else
++ start_val = collseq_table_lookup(collseq, TRANSLATE(range_start_char));
++
++ end_val = collseq_table_lookup (collseq, TRANSLATE (p[0]));
++
++ /* Report an error if the range is empty and the syntax prohibits
++ this. */
++ ret = ((syntax & RE_NO_EMPTY_RANGES)
++ && (start_val > end_val))? REG_ERANGE : REG_NOERROR;
++
++ /* Insert space to the end of the char_ranges. */
++ insert_space(2, b - char_set[5] - 2, b - 1);
++ *(b - char_set[5] - 2) = (wchar_t)start_val;
++ *(b - char_set[5] - 1) = (wchar_t)end_val;
++ char_set[4]++; /* ranges_index */
++ }
++ else
++# endif
++ {
++ range_start = (range_start_char >= 0)? TRANSLATE (range_start_char):
++ range_start_char;
++ range_end = TRANSLATE (p[0]);
++ /* Report an error if the range is empty and the syntax prohibits
++ this. */
++ ret = ((syntax & RE_NO_EMPTY_RANGES)
++ && (range_start > range_end))? REG_ERANGE : REG_NOERROR;
++
++ /* Insert space to the end of the char_ranges. */
++ insert_space(2, b - char_set[5] - 2, b - 1);
++ *(b - char_set[5] - 2) = range_start;
++ *(b - char_set[5] - 1) = range_end;
++ char_set[4]++; /* ranges_index */
++ }
++ /* Have to increment the pointer into the pattern string, so the
++ caller isn't still at the ending character. */
++ (*p_ptr)++;
++
++ return ret;
++}
++#else /* BYTE */
++/* Read the ending character of a range (in a bracket expression) from the
++ uncompiled pattern *P_PTR (which ends at PEND). We assume the
++ starting character is in `P[-2]'. (`P[-1]' is the character `-'.)
++ Then we set the translation of all bits between the starting and
++ ending characters (inclusive) in the compiled pattern B.
++
++ Return an error code.
++
++ We use these short variable names so we can use the same macros as
++ `regex_compile' itself. */
++
++static reg_errcode_t
++byte_compile_range (unsigned int range_start_char, const char **p_ptr,
++ const char *pend, RE_TRANSLATE_TYPE translate,
++ reg_syntax_t syntax, unsigned char *b)
++{
++ unsigned this_char;
++ const char *p = *p_ptr;
++ reg_errcode_t ret;
++# if _LIBC
++ const unsigned char *collseq;
++ unsigned int start_colseq;
++ unsigned int end_colseq;
++# else
++ unsigned end_char;
++# endif
++
++ if (p == pend)
++ return REG_ERANGE;
++
++ /* Have to increment the pointer into the pattern string, so the
++ caller isn't still at the ending character. */
++ (*p_ptr)++;
++
++ /* Report an error if the range is empty and the syntax prohibits this. */
++ ret = syntax & RE_NO_EMPTY_RANGES ? REG_ERANGE : REG_NOERROR;
++
++# if _LIBC
++ collseq = (const unsigned char *) _NL_CURRENT (LC_COLLATE,
++ _NL_COLLATE_COLLSEQMB);
++
++ start_colseq = collseq[(unsigned char) TRANSLATE (range_start_char)];
++ end_colseq = collseq[(unsigned char) TRANSLATE (p[0])];
++ for (this_char = 0; this_char <= (unsigned char) -1; ++this_char)
++ {
++ unsigned int this_colseq = collseq[(unsigned char) TRANSLATE (this_char)];
++
++ if (start_colseq <= this_colseq && this_colseq <= end_colseq)
++ {
++ SET_LIST_BIT (TRANSLATE (this_char));
++ ret = REG_NOERROR;
++ }
++ }
++# else
++ /* Here we see why `this_char' has to be larger than an `unsigned
++ char' -- we would otherwise go into an infinite loop, since all
++ characters <= 0xff. */
++ range_start_char = TRANSLATE (range_start_char);
++ /* TRANSLATE(p[0]) is casted to char (not unsigned char) in TRANSLATE,
++ and some compilers cast it to int implicitly, so following for_loop
++ may fall to (almost) infinite loop.
++ e.g. If translate[p[0]] = 0xff, end_char may equals to 0xffffffff.
++ To avoid this, we cast p[0] to unsigned int and truncate it. */
++ end_char = ((unsigned)TRANSLATE(p[0]) & ((1 << BYTEWIDTH) - 1));
++
++ for (this_char = range_start_char; this_char <= end_char; ++this_char)
++ {
++ SET_LIST_BIT (TRANSLATE (this_char));
++ ret = REG_NOERROR;
++ }
++# endif
++
++ return ret;
++}
++#endif /* WCHAR */
++
++/* re_compile_fastmap computes a ``fastmap'' for the compiled pattern in
++ BUFP. A fastmap records which of the (1 << BYTEWIDTH) possible
++ characters can start a string that matches the pattern. This fastmap
++ is used by re_search to skip quickly over impossible starting points.
++
++ The caller must supply the address of a (1 << BYTEWIDTH)-byte data
++ area as BUFP->fastmap.
++
++ We set the `fastmap', `fastmap_accurate', and `can_be_null' fields in
++ the pattern buffer.
++
++ Returns 0 if we succeed, -2 if an internal error. */
++
++#ifdef WCHAR
++/* local function for re_compile_fastmap.
++ truncate wchar_t character to char. */
++static unsigned char truncate_wchar (CHAR_T c);
++
++static unsigned char
++truncate_wchar (CHAR_T c)
++{
++ unsigned char buf[MB_CUR_MAX];
++ mbstate_t state;
++ int retval;
++ memset (&state, '\0', sizeof (state));
++# ifdef _LIBC
++ retval = __wcrtomb (buf, c, &state);
++# else
++ retval = wcrtomb (buf, c, &state);
++# endif
++ return retval > 0 ? buf[0] : (unsigned char) c;
++}
++#endif /* WCHAR */
++
++static int
++PREFIX(re_compile_fastmap) (struct re_pattern_buffer *bufp)
++{
++ int j, k;
++#ifdef MATCH_MAY_ALLOCATE
++ PREFIX(fail_stack_type) fail_stack;
++#endif
++#ifndef REGEX_MALLOC
++ char *destination;
++#endif
++
++ register char *fastmap = bufp->fastmap;
++
++#ifdef WCHAR
++ /* We need to cast pattern to (wchar_t*), because we casted this compiled
++ pattern to (char*) in regex_compile. */
++ UCHAR_T *pattern = (UCHAR_T*)bufp->buffer;
++ register UCHAR_T *pend = (UCHAR_T*) (bufp->buffer + bufp->used);
++#else /* BYTE */
++ UCHAR_T *pattern = bufp->buffer;
++ register UCHAR_T *pend = pattern + bufp->used;
++#endif /* WCHAR */
++ UCHAR_T *p = pattern;
++
++#ifdef REL_ALLOC
++ /* This holds the pointer to the failure stack, when
++ it is allocated relocatably. */
++ fail_stack_elt_t *failure_stack_ptr;
++#endif
++
++ /* Assume that each path through the pattern can be null until
++ proven otherwise. We set this false at the bottom of switch
++ statement, to which we get only if a particular path doesn't
++ match the empty string. */
++ boolean path_can_be_null = true;
++
++ /* We aren't doing a `succeed_n' to begin with. */
++ boolean succeed_n_p = false;
++
++ assert (fastmap != NULL && p != NULL);
++
++ INIT_FAIL_STACK ();
++ bzero (fastmap, 1 << BYTEWIDTH); /* Assume nothing's valid. */
++ bufp->fastmap_accurate = 1; /* It will be when we're done. */
++ bufp->can_be_null = 0;
++
++ while (1)
++ {
++ if (p == pend || *p == (UCHAR_T) succeed)
++ {
++ /* We have reached the (effective) end of pattern. */
++ if (!FAIL_STACK_EMPTY ())
++ {
++ bufp->can_be_null |= path_can_be_null;
++
++ /* Reset for next path. */
++ path_can_be_null = true;
++
++ p = fail_stack.stack[--fail_stack.avail].pointer;
++
++ continue;
++ }
++ else
++ break;
++ }
++
++ /* We should never be about to go beyond the end of the pattern. */
++ assert (p < pend);
++
++ switch (SWITCH_ENUM_CAST ((re_opcode_t) *p++))
++ {
++
++ /* I guess the idea here is to simply not bother with a fastmap
++ if a backreference is used, since it's too hard to figure out
++ the fastmap for the corresponding group. Setting
++ `can_be_null' stops `re_search_2' from using the fastmap, so
++ that is all we do. */
++ case duplicate:
++ bufp->can_be_null = 1;
++ goto done;
++
++
++ /* Following are the cases which match a character. These end
++ with `break'. */
++
++#ifdef WCHAR
++ case exactn:
++ fastmap[truncate_wchar(p[1])] = 1;
++ break;
++#else /* BYTE */
++ case exactn:
++ fastmap[p[1]] = 1;
++ break;
++#endif /* WCHAR */
++#ifdef MBS_SUPPORT
++ case exactn_bin:
++ fastmap[p[1]] = 1;
++ break;
++#endif
++
++#ifdef WCHAR
++ /* It is hard to distinguish fastmap from (multi byte) characters
++ which depends on current locale. */
++ case charset:
++ case charset_not:
++ case wordchar:
++ case notwordchar:
++ bufp->can_be_null = 1;
++ goto done;
++#else /* BYTE */
++ case charset:
++ for (j = *p++ * BYTEWIDTH - 1; j >= 0; j--)
++ if (p[j / BYTEWIDTH] & (1 << (j % BYTEWIDTH)))
++ fastmap[j] = 1;
++ break;
++
++
++ case charset_not:
++ /* Chars beyond end of map must be allowed. */
++ for (j = *p * BYTEWIDTH; j < (1 << BYTEWIDTH); j++)
++ fastmap[j] = 1;
++
++ for (j = *p++ * BYTEWIDTH - 1; j >= 0; j--)
++ if (!(p[j / BYTEWIDTH] & (1 << (j % BYTEWIDTH))))
++ fastmap[j] = 1;
++ break;
++
++
++ case wordchar:
++ for (j = 0; j < (1 << BYTEWIDTH); j++)
++ if (SYNTAX (j) == Sword)
++ fastmap[j] = 1;
++ break;
++
++
++ case notwordchar:
++ for (j = 0; j < (1 << BYTEWIDTH); j++)
++ if (SYNTAX (j) != Sword)
++ fastmap[j] = 1;
++ break;
++#endif /* WCHAR */
++
++ case anychar:
++ {
++ int fastmap_newline = fastmap['\n'];
++
++ /* `.' matches anything ... */
++ for (j = 0; j < (1 << BYTEWIDTH); j++)
++ fastmap[j] = 1;
++
++ /* ... except perhaps newline. */
++ if (!(bufp->syntax & RE_DOT_NEWLINE))
++ fastmap['\n'] = fastmap_newline;
++
++ /* Return if we have already set `can_be_null'; if we have,
++ then the fastmap is irrelevant. Something's wrong here. */
++ else if (bufp->can_be_null)
++ goto done;
++
++ /* Otherwise, have to check alternative paths. */
++ break;
++ }
++
++#ifdef emacs
++ case syntaxspec:
++ k = *p++;
++ for (j = 0; j < (1 << BYTEWIDTH); j++)
++ if (SYNTAX (j) == (enum syntaxcode) k)
++ fastmap[j] = 1;
++ break;
++
++
++ case notsyntaxspec:
++ k = *p++;
++ for (j = 0; j < (1 << BYTEWIDTH); j++)
++ if (SYNTAX (j) != (enum syntaxcode) k)
++ fastmap[j] = 1;
++ break;
++
++
++ /* All cases after this match the empty string. These end with
++ `continue'. */
++
++
++ case before_dot:
++ case at_dot:
++ case after_dot:
++ continue;
++#endif /* emacs */
++
++
++ case no_op:
++ case begline:
++ case endline:
++ case begbuf:
++ case endbuf:
++ case wordbound:
++ case notwordbound:
++ case wordbeg:
++ case wordend:
++ case push_dummy_failure:
++ continue;
++
++
++ case jump_n:
++ case pop_failure_jump:
++ case maybe_pop_jump:
++ case jump:
++ case jump_past_alt:
++ case dummy_failure_jump:
++ EXTRACT_NUMBER_AND_INCR (j, p);
++ p += j;
++ if (j > 0)
++ continue;
++
++ /* Jump backward implies we just went through the body of a
++ loop and matched nothing. Opcode jumped to should be
++ `on_failure_jump' or `succeed_n'. Just treat it like an
++ ordinary jump. For a * loop, it has pushed its failure
++ point already; if so, discard that as redundant. */
++ if ((re_opcode_t) *p != on_failure_jump
++ && (re_opcode_t) *p != succeed_n)
++ continue;
++
++ p++;
++ EXTRACT_NUMBER_AND_INCR (j, p);
++ p += j;
++
++ /* If what's on the stack is where we are now, pop it. */
++ if (!FAIL_STACK_EMPTY ()
++ && fail_stack.stack[fail_stack.avail - 1].pointer == p)
++ fail_stack.avail--;
++
++ continue;
++
++
++ case on_failure_jump:
++ case on_failure_keep_string_jump:
++ handle_on_failure_jump:
++ EXTRACT_NUMBER_AND_INCR (j, p);
++
++ /* For some patterns, e.g., `(a?)?', `p+j' here points to the
++ end of the pattern. We don't want to push such a point,
++ since when we restore it above, entering the switch will
++ increment `p' past the end of the pattern. We don't need
++ to push such a point since we obviously won't find any more
++ fastmap entries beyond `pend'. Such a pattern can match
++ the null string, though. */
++ if (p + j < pend)
++ {
++ if (!PUSH_PATTERN_OP (p + j, fail_stack))
++ {
++ RESET_FAIL_STACK ();
++ return -2;
++ }
++ }
++ else
++ bufp->can_be_null = 1;
++
++ if (succeed_n_p)
++ {
++ EXTRACT_NUMBER_AND_INCR (k, p); /* Skip the n. */
++ succeed_n_p = false;
++ }
++
++ continue;
++
++
++ case succeed_n:
++ /* Get to the number of times to succeed. */
++ p += OFFSET_ADDRESS_SIZE;
++
++ /* Increment p past the n for when k != 0. */
++ EXTRACT_NUMBER_AND_INCR (k, p);
++ if (k == 0)
++ {
++ p -= 2 * OFFSET_ADDRESS_SIZE;
++ succeed_n_p = true; /* Spaghetti code alert. */
++ goto handle_on_failure_jump;
++ }
++ continue;
++
++
++ case set_number_at:
++ p += 2 * OFFSET_ADDRESS_SIZE;
++ continue;
++
++
++ case start_memory:
++ case stop_memory:
++ p += 2;
++ continue;
++
++
++ default:
++ abort (); /* We have listed all the cases. */
++ } /* switch *p++ */
++
++ /* Getting here means we have found the possible starting
++ characters for one path of the pattern -- and that the empty
++ string does not match. We need not follow this path further.
++ Instead, look at the next alternative (remembered on the
++ stack), or quit if no more. The test at the top of the loop
++ does these things. */
++ path_can_be_null = false;
++ p = pend;
++ } /* while p */
++
++ /* Set `can_be_null' for the last path (also the first path, if the
++ pattern is empty). */
++ bufp->can_be_null |= path_can_be_null;
++
++ done:
++ RESET_FAIL_STACK ();
++ return 0;
++}
++
++#else /* not INSIDE_RECURSION */
++
++int
++re_compile_fastmap (struct re_pattern_buffer *bufp)
++{
++# ifdef MBS_SUPPORT
++ if (MB_CUR_MAX != 1)
++ return wcs_re_compile_fastmap(bufp);
++ else
++# endif
++ return byte_re_compile_fastmap(bufp);
++} /* re_compile_fastmap */
++#ifdef _LIBC
++weak_alias (__re_compile_fastmap, re_compile_fastmap)
++#endif
++
++
++/* Set REGS to hold NUM_REGS registers, storing them in STARTS and
++ ENDS. Subsequent matches using PATTERN_BUFFER and REGS will use
++ this memory for recording register information. STARTS and ENDS
++ must be allocated using the malloc library routine, and must each
++ be at least NUM_REGS * sizeof (regoff_t) bytes long.
++
++ If NUM_REGS == 0, then subsequent matches should allocate their own
++ register data.
++
++ Unless this function is called, the first search or match using
++ PATTERN_BUFFER will allocate its own register data, without
++ freeing the old data. */
++
++void
++re_set_registers (struct re_pattern_buffer *bufp,
++ struct re_registers *regs, unsigned num_regs,
++ regoff_t *starts, regoff_t *ends)
++{
++ if (num_regs)
++ {
++ bufp->regs_allocated = REGS_REALLOCATE;
++ regs->num_regs = num_regs;
++ regs->start = starts;
++ regs->end = ends;
++ }
++ else
++ {
++ bufp->regs_allocated = REGS_UNALLOCATED;
++ regs->num_regs = 0;
++ regs->start = regs->end = (regoff_t *) 0;
++ }
++}
++#ifdef _LIBC
++weak_alias (__re_set_registers, re_set_registers)
++#endif
++
++/* Searching routines. */
++
++/* Like re_search_2, below, but only one string is specified, and
++ doesn't let you say where to stop matching. */
++
++int
++re_search (struct re_pattern_buffer *bufp, const char *string, int size,
++ int startpos, int range, struct re_registers *regs)
++{
++ return re_search_2 (bufp, NULL, 0, string, size, startpos, range,
++ regs, size);
++}
++#ifdef _LIBC
++weak_alias (__re_search, re_search)
++#endif
++
++
++/* Using the compiled pattern in BUFP->buffer, first tries to match the
++ virtual concatenation of STRING1 and STRING2, starting first at index
++ STARTPOS, then at STARTPOS + 1, and so on.
++
++ STRING1 and STRING2 have length SIZE1 and SIZE2, respectively.
++
++ RANGE is how far to scan while trying to match. RANGE = 0 means try
++ only at STARTPOS; in general, the last start tried is STARTPOS +
++ RANGE.
++
++ In REGS, return the indices of the virtual concatenation of STRING1
++ and STRING2 that matched the entire BUFP->buffer and its contained
++ subexpressions.
++
++ Do not consider matching one past the index STOP in the virtual
++ concatenation of STRING1 and STRING2.
++
++ We return either the position in the strings at which the match was
++ found, -1 if no match, or -2 if error (such as failure
++ stack overflow). */
++
++int
++re_search_2 (struct re_pattern_buffer *bufp, const char *string1, int size1,
++ const char *string2, int size2, int startpos, int range,
++ struct re_registers *regs, int stop)
++{
++# ifdef MBS_SUPPORT
++ if (MB_CUR_MAX != 1)
++ return wcs_re_search_2 (bufp, string1, size1, string2, size2, startpos,
++ range, regs, stop);
++ else
++# endif
++ return byte_re_search_2 (bufp, string1, size1, string2, size2, startpos,
++ range, regs, stop);
++} /* re_search_2 */
++#ifdef _LIBC
++weak_alias (__re_search_2, re_search_2)
++#endif
++
++#endif /* not INSIDE_RECURSION */
++
++#ifdef INSIDE_RECURSION
++
++#ifdef MATCH_MAY_ALLOCATE
++# define FREE_VAR(var) if (var) REGEX_FREE (var); var = NULL
++#else
++# define FREE_VAR(var) if (var) free (var); var = NULL
++#endif
++
++#ifdef WCHAR
++# define MAX_ALLOCA_SIZE 2000
++
++# define FREE_WCS_BUFFERS() \
++ do { \
++ if (size1 > MAX_ALLOCA_SIZE) \
++ { \
++ free (wcs_string1); \
++ free (mbs_offset1); \
++ } \
++ else \
++ { \
++ FREE_VAR (wcs_string1); \
++ FREE_VAR (mbs_offset1); \
++ } \
++ if (size2 > MAX_ALLOCA_SIZE) \
++ { \
++ free (wcs_string2); \
++ free (mbs_offset2); \
++ } \
++ else \
++ { \
++ FREE_VAR (wcs_string2); \
++ FREE_VAR (mbs_offset2); \
++ } \
++ } while (0)
++
++#endif
++
++
++static int
++PREFIX(re_search_2) (struct re_pattern_buffer *bufp, const char *string1,
++ int size1, const char *string2, int size2,
++ int startpos, int range,
++ struct re_registers *regs, int stop)
++{
++ int val;
++ register char *fastmap = bufp->fastmap;
++ register RE_TRANSLATE_TYPE translate = bufp->translate;
++ int total_size = size1 + size2;
++ int endpos = startpos + range;
++#ifdef WCHAR
++ /* We need wchar_t* buffers correspond to cstring1, cstring2. */
++ wchar_t *wcs_string1 = NULL, *wcs_string2 = NULL;
++ /* We need the size of wchar_t buffers correspond to csize1, csize2. */
++ int wcs_size1 = 0, wcs_size2 = 0;
++ /* offset buffer for optimizatoin. See convert_mbs_to_wc. */
++ int *mbs_offset1 = NULL, *mbs_offset2 = NULL;
++ /* They hold whether each wchar_t is binary data or not. */
++ char *is_binary = NULL;
++#endif /* WCHAR */
++
++ /* Check for out-of-range STARTPOS. */
++ if (startpos < 0 || startpos > total_size)
++ return -1;
++
++ /* Fix up RANGE if it might eventually take us outside
++ the virtual concatenation of STRING1 and STRING2.
++ Make sure we won't move STARTPOS below 0 or above TOTAL_SIZE. */
++ if (endpos < 0)
++ range = 0 - startpos;
++ else if (endpos > total_size)
++ range = total_size - startpos;
++
++ /* If the search isn't to be a backwards one, don't waste time in a
++ search for a pattern that must be anchored. */
++ if (bufp->used > 0 && range > 0
++ && ((re_opcode_t) bufp->buffer[0] == begbuf
++ /* `begline' is like `begbuf' if it cannot match at newlines. */
++ || ((re_opcode_t) bufp->buffer[0] == begline
++ && !bufp->newline_anchor)))
++ {
++ if (startpos > 0)
++ return -1;
++ else
++ range = 1;
++ }
++
++#ifdef emacs
++ /* In a forward search for something that starts with \=.
++ don't keep searching past point. */
++ if (bufp->used > 0 && (re_opcode_t) bufp->buffer[0] == at_dot && range > 0)
++ {
++ range = PT - startpos;
++ if (range <= 0)
++ return -1;
++ }
++#endif /* emacs */
++
++ /* Update the fastmap now if not correct already. */
++ if (fastmap && !bufp->fastmap_accurate)
++ if (re_compile_fastmap (bufp) == -2)
++ return -2;
++
++#ifdef WCHAR
++ /* Allocate wchar_t array for wcs_string1 and wcs_string2 and
++ fill them with converted string. */
++ if (size1 != 0)
++ {
++ if (size1 > MAX_ALLOCA_SIZE)
++ {
++ wcs_string1 = TALLOC (size1 + 1, CHAR_T);
++ mbs_offset1 = TALLOC (size1 + 1, int);
++ is_binary = TALLOC (size1 + 1, char);
++ }
++ else
++ {
++ wcs_string1 = REGEX_TALLOC (size1 + 1, CHAR_T);
++ mbs_offset1 = REGEX_TALLOC (size1 + 1, int);
++ is_binary = REGEX_TALLOC (size1 + 1, char);
++ }
++ if (!wcs_string1 || !mbs_offset1 || !is_binary)
++ {
++ if (size1 > MAX_ALLOCA_SIZE)
++ {
++ free (wcs_string1);
++ free (mbs_offset1);
++ free (is_binary);
++ }
++ else
++ {
++ FREE_VAR (wcs_string1);
++ FREE_VAR (mbs_offset1);
++ FREE_VAR (is_binary);
++ }
++ return -2;
++ }
++ wcs_size1 = convert_mbs_to_wcs(wcs_string1, string1, size1,
++ mbs_offset1, is_binary);
++ wcs_string1[wcs_size1] = L'\0'; /* for a sentinel */
++ if (size1 > MAX_ALLOCA_SIZE)
++ free (is_binary);
++ else
++ FREE_VAR (is_binary);
++ }
++ if (size2 != 0)
++ {
++ if (size2 > MAX_ALLOCA_SIZE)
++ {
++ wcs_string2 = TALLOC (size2 + 1, CHAR_T);
++ mbs_offset2 = TALLOC (size2 + 1, int);
++ is_binary = TALLOC (size2 + 1, char);
++ }
++ else
++ {
++ wcs_string2 = REGEX_TALLOC (size2 + 1, CHAR_T);
++ mbs_offset2 = REGEX_TALLOC (size2 + 1, int);
++ is_binary = REGEX_TALLOC (size2 + 1, char);
++ }
++ if (!wcs_string2 || !mbs_offset2 || !is_binary)
++ {
++ FREE_WCS_BUFFERS ();
++ if (size2 > MAX_ALLOCA_SIZE)
++ free (is_binary);
++ else
++ FREE_VAR (is_binary);
++ return -2;
++ }
++ wcs_size2 = convert_mbs_to_wcs(wcs_string2, string2, size2,
++ mbs_offset2, is_binary);
++ wcs_string2[wcs_size2] = L'\0'; /* for a sentinel */
++ if (size2 > MAX_ALLOCA_SIZE)
++ free (is_binary);
++ else
++ FREE_VAR (is_binary);
++ }
++#endif /* WCHAR */
++
++
++ /* Loop through the string, looking for a place to start matching. */
++ for (;;)
++ {
++ /* If a fastmap is supplied, skip quickly over characters that
++ cannot be the start of a match. If the pattern can match the
++ null string, however, we don't need to skip characters; we want
++ the first null string. */
++ if (fastmap && startpos < total_size && !bufp->can_be_null)
++ {
++ if (range > 0) /* Searching forwards. */
++ {
++ register const char *d;
++ register int lim = 0;
++ int irange = range;
++
++ if (startpos < size1 && startpos + range >= size1)
++ lim = range - (size1 - startpos);
++
++ d = (startpos >= size1 ? string2 - size1 : string1) + startpos;
++
++ /* Written out as an if-else to avoid testing `translate'
++ inside the loop. */
++ if (translate)
++ while (range > lim
++ && !fastmap[(unsigned char)
++ translate[(unsigned char) *d++]])
++ range--;
++ else
++ while (range > lim && !fastmap[(unsigned char) *d++])
++ range--;
++
++ startpos += irange - range;
++ }
++ else /* Searching backwards. */
++ {
++ register CHAR_T c = (size1 == 0 || startpos >= size1
++ ? string2[startpos - size1]
++ : string1[startpos]);
++
++ if (!fastmap[(unsigned char) TRANSLATE (c)])
++ goto advance;
++ }
++ }
++
++ /* If can't match the null string, and that's all we have left, fail. */
++ if (range >= 0 && startpos == total_size && fastmap
++ && !bufp->can_be_null)
++ {
++#ifdef WCHAR
++ FREE_WCS_BUFFERS ();
++#endif
++ return -1;
++ }
++
++#ifdef WCHAR
++ val = wcs_re_match_2_internal (bufp, string1, size1, string2,
++ size2, startpos, regs, stop,
++ wcs_string1, wcs_size1,
++ wcs_string2, wcs_size2,
++ mbs_offset1, mbs_offset2);
++#else /* BYTE */
++ val = byte_re_match_2_internal (bufp, string1, size1, string2,
++ size2, startpos, regs, stop);
++#endif /* BYTE */
++
++#ifndef REGEX_MALLOC
++# ifdef C_ALLOCA
++ alloca (0);
++# endif
++#endif
++
++ if (val >= 0)
++ {
++#ifdef WCHAR
++ FREE_WCS_BUFFERS ();
++#endif
++ return startpos;
++ }
++
++ if (val == -2)
++ {
++#ifdef WCHAR
++ FREE_WCS_BUFFERS ();
++#endif
++ return -2;
++ }
++
++ advance:
++ if (!range)
++ break;
++ else if (range > 0)
++ {
++ range--;
++ startpos++;
++ }
++ else
++ {
++ range++;
++ startpos--;
++ }
++ }
++#ifdef WCHAR
++ FREE_WCS_BUFFERS ();
++#endif
++ return -1;
++}
++
++#ifdef WCHAR
++/* This converts PTR, a pointer into one of the search wchar_t strings
++ `string1' and `string2' into an multibyte string offset from the
++ beginning of that string. We use mbs_offset to optimize.
++ See convert_mbs_to_wcs. */
++# define POINTER_TO_OFFSET(ptr) \
++ (FIRST_STRING_P (ptr) \
++ ? ((regoff_t)(mbs_offset1 != NULL? mbs_offset1[(ptr)-string1] : 0)) \
++ : ((regoff_t)((mbs_offset2 != NULL? mbs_offset2[(ptr)-string2] : 0) \
++ + csize1)))
++#else /* BYTE */
++/* This converts PTR, a pointer into one of the search strings `string1'
++ and `string2' into an offset from the beginning of that string. */
++# define POINTER_TO_OFFSET(ptr) \
++ (FIRST_STRING_P (ptr) \
++ ? ((regoff_t) ((ptr) - string1)) \
++ : ((regoff_t) ((ptr) - string2 + size1)))
++#endif /* WCHAR */
++
++/* Macros for dealing with the split strings in re_match_2. */
++
++#define MATCHING_IN_FIRST_STRING (dend == end_match_1)
++
++/* Call before fetching a character with *d. This switches over to
++ string2 if necessary. */
++#define PREFETCH() \
++ while (d == dend) \
++ { \
++ /* End of string2 => fail. */ \
++ if (dend == end_match_2) \
++ goto fail; \
++ /* End of string1 => advance to string2. */ \
++ d = string2; \
++ dend = end_match_2; \
++ }
++
++/* Test if at very beginning or at very end of the virtual concatenation
++ of `string1' and `string2'. If only one string, it's `string2'. */
++#define AT_STRINGS_BEG(d) ((d) == (size1 ? string1 : string2) || !size2)
++#define AT_STRINGS_END(d) ((d) == end2)
++
++
++/* Test if D points to a character which is word-constituent. We have
++ two special cases to check for: if past the end of string1, look at
++ the first character in string2; and if before the beginning of
++ string2, look at the last character in string1. */
++#ifdef WCHAR
++/* Use internationalized API instead of SYNTAX. */
++# define WORDCHAR_P(d) \
++ (iswalnum ((wint_t)((d) == end1 ? *string2 \
++ : (d) == string2 - 1 ? *(end1 - 1) : *(d))) != 0 \
++ || ((d) == end1 ? *string2 \
++ : (d) == string2 - 1 ? *(end1 - 1) : *(d)) == L'_')
++#else /* BYTE */
++# define WORDCHAR_P(d) \
++ (SYNTAX ((d) == end1 ? *string2 \
++ : (d) == string2 - 1 ? *(end1 - 1) : *(d)) \
++ == Sword)
++#endif /* WCHAR */
++
++/* Disabled due to a compiler bug -- see comment at case wordbound */
++#if 0
++/* Test if the character before D and the one at D differ with respect
++ to being word-constituent. */
++#define AT_WORD_BOUNDARY(d) \
++ (AT_STRINGS_BEG (d) || AT_STRINGS_END (d) \
++ || WORDCHAR_P (d - 1) != WORDCHAR_P (d))
++#endif
++
++/* Free everything we malloc. */
++#ifdef MATCH_MAY_ALLOCATE
++# ifdef WCHAR
++# define FREE_VARIABLES() \
++ do { \
++ REGEX_FREE_STACK (fail_stack.stack); \
++ FREE_VAR (regstart); \
++ FREE_VAR (regend); \
++ FREE_VAR (old_regstart); \
++ FREE_VAR (old_regend); \
++ FREE_VAR (best_regstart); \
++ FREE_VAR (best_regend); \
++ FREE_VAR (reg_info); \
++ FREE_VAR (reg_dummy); \
++ FREE_VAR (reg_info_dummy); \
++ if (!cant_free_wcs_buf) \
++ { \
++ FREE_VAR (string1); \
++ FREE_VAR (string2); \
++ FREE_VAR (mbs_offset1); \
++ FREE_VAR (mbs_offset2); \
++ } \
++ } while (0)
++# else /* BYTE */
++# define FREE_VARIABLES() \
++ do { \
++ REGEX_FREE_STACK (fail_stack.stack); \
++ FREE_VAR (regstart); \
++ FREE_VAR (regend); \
++ FREE_VAR (old_regstart); \
++ FREE_VAR (old_regend); \
++ FREE_VAR (best_regstart); \
++ FREE_VAR (best_regend); \
++ FREE_VAR (reg_info); \
++ FREE_VAR (reg_dummy); \
++ FREE_VAR (reg_info_dummy); \
++ } while (0)
++# endif /* WCHAR */
++#else
++# ifdef WCHAR
++# define FREE_VARIABLES() \
++ do { \
++ if (!cant_free_wcs_buf) \
++ { \
++ FREE_VAR (string1); \
++ FREE_VAR (string2); \
++ FREE_VAR (mbs_offset1); \
++ FREE_VAR (mbs_offset2); \
++ } \
++ } while (0)
++# else /* BYTE */
++# define FREE_VARIABLES() ((void)0) /* Do nothing! But inhibit gcc warning. */
++# endif /* WCHAR */
++#endif /* not MATCH_MAY_ALLOCATE */
++
++/* These values must meet several constraints. They must not be valid
++ register values; since we have a limit of 255 registers (because
++ we use only one byte in the pattern for the register number), we can
++ use numbers larger than 255. They must differ by 1, because of
++ NUM_FAILURE_ITEMS above. And the value for the lowest register must
++ be larger than the value for the highest register, so we do not try
++ to actually save any registers when none are active. */
++#define NO_HIGHEST_ACTIVE_REG (1 << BYTEWIDTH)
++#define NO_LOWEST_ACTIVE_REG (NO_HIGHEST_ACTIVE_REG + 1)
++
++#else /* not INSIDE_RECURSION */
++/* Matching routines. */
++
++#ifndef emacs /* Emacs never uses this. */
++/* re_match is like re_match_2 except it takes only a single string. */
++
++int
++re_match (struct re_pattern_buffer *bufp, const char *string,
++ int size, int pos, struct re_registers *regs)
++{
++ int result;
++# ifdef MBS_SUPPORT
++ if (MB_CUR_MAX != 1)
++ result = wcs_re_match_2_internal (bufp, NULL, 0, string, size,
++ pos, regs, size,
++ NULL, 0, NULL, 0, NULL, NULL);
++ else
++# endif
++ result = byte_re_match_2_internal (bufp, NULL, 0, string, size,
++ pos, regs, size);
++# ifndef REGEX_MALLOC
++# ifdef C_ALLOCA
++ alloca (0);
++# endif
++# endif
++ return result;
++}
++# ifdef _LIBC
++weak_alias (__re_match, re_match)
++# endif
++#endif /* not emacs */
++
++#endif /* not INSIDE_RECURSION */
++
++#ifdef INSIDE_RECURSION
++static boolean PREFIX(group_match_null_string_p) (UCHAR_T **p,
++ UCHAR_T *end,
++ PREFIX(register_info_type) *reg_info);
++static boolean PREFIX(alt_match_null_string_p) (UCHAR_T *p,
++ UCHAR_T *end,
++ PREFIX(register_info_type) *reg_info);
++static boolean PREFIX(common_op_match_null_string_p) (UCHAR_T **p,
++ UCHAR_T *end,
++ PREFIX(register_info_type) *reg_info);
++static int PREFIX(bcmp_translate) (const CHAR_T *s1, const CHAR_T *s2,
++ register int len,
++ RE_TRANSLATE_TYPE translate);
++#else /* not INSIDE_RECURSION */
++
++/* re_match_2 matches the compiled pattern in BUFP against the
++ the (virtual) concatenation of STRING1 and STRING2 (of length SIZE1
++ and SIZE2, respectively). We start matching at POS, and stop
++ matching at STOP.
++
++ If REGS is non-null and the `no_sub' field of BUFP is nonzero, we
++ store offsets for the substring each group matched in REGS. See the
++ documentation for exactly how many groups we fill.
++
++ We return -1 if no match, -2 if an internal error (such as the
++ failure stack overflowing). Otherwise, we return the length of the
++ matched substring. */
++
++int
++re_match_2 (struct re_pattern_buffer *bufp, const char *string1, int size1,
++ const char *string2, int size2, int pos,
++ struct re_registers *regs, int stop)
++{
++ int result;
++# ifdef MBS_SUPPORT
++ if (MB_CUR_MAX != 1)
++ result = wcs_re_match_2_internal (bufp, string1, size1, string2, size2,
++ pos, regs, stop,
++ NULL, 0, NULL, 0, NULL, NULL);
++ else
++# endif
++ result = byte_re_match_2_internal (bufp, string1, size1, string2, size2,
++ pos, regs, stop);
++
++#ifndef REGEX_MALLOC
++# ifdef C_ALLOCA
++ alloca (0);
++# endif
++#endif
++ return result;
++}
++#ifdef _LIBC
++weak_alias (__re_match_2, re_match_2)
++#endif
++
++#endif /* not INSIDE_RECURSION */
++
++#ifdef INSIDE_RECURSION
++
++#ifdef WCHAR
++static int count_mbs_length (int *, int);
++
++/* This check the substring (from 0, to length) of the multibyte string,
++ to which offset_buffer correspond. And count how many wchar_t_characters
++ the substring occupy. We use offset_buffer to optimization.
++ See convert_mbs_to_wcs. */
++
++static int
++count_mbs_length(int *offset_buffer, int length)
++{
++ int upper, lower;
++
++ /* Check whether the size is valid. */
++ if (length < 0)
++ return -1;
++
++ if (offset_buffer == NULL)
++ return 0;
++
++ /* If there are no multibyte character, offset_buffer[i] == i.
++ Optmize for this case. */
++ if (offset_buffer[length] == length)
++ return length;
++
++ /* Set up upper with length. (because for all i, offset_buffer[i] >= i) */
++ upper = length;
++ lower = 0;
++
++ while (true)
++ {
++ int middle = (lower + upper) / 2;
++ if (middle == lower || middle == upper)
++ break;
++ if (offset_buffer[middle] > length)
++ upper = middle;
++ else if (offset_buffer[middle] < length)
++ lower = middle;
++ else
++ return middle;
++ }
++
++ return -1;
++}
++#endif /* WCHAR */
++
++/* This is a separate function so that we can force an alloca cleanup
++ afterwards. */
++#ifdef WCHAR
++static int
++wcs_re_match_2_internal (struct re_pattern_buffer *bufp,
++ const char *cstring1, int csize1,
++ const char *cstring2, int csize2,
++ int pos,
++ struct re_registers *regs,
++ int stop,
++ /* string1 == string2 == NULL means string1/2, size1/2 and
++ mbs_offset1/2 need seting up in this function. */
++ /* We need wchar_t* buffers correspond to cstring1, cstring2. */
++ wchar_t *string1, int size1,
++ wchar_t *string2, int size2,
++ /* offset buffer for optimizatoin. See convert_mbs_to_wc. */
++ int *mbs_offset1, int *mbs_offset2)
++#else /* BYTE */
++static int
++byte_re_match_2_internal (struct re_pattern_buffer *bufp,
++ const char *string1, int size1,
++ const char *string2, int size2,
++ int pos,
++ struct re_registers *regs, int stop)
++#endif /* BYTE */
++{
++ /* General temporaries. */
++ int mcnt;
++ UCHAR_T *p1;
++#ifdef WCHAR
++ /* They hold whether each wchar_t is binary data or not. */
++ char *is_binary = NULL;
++ /* If true, we can't free string1/2, mbs_offset1/2. */
++ int cant_free_wcs_buf = 1;
++#endif /* WCHAR */
++
++ /* Just past the end of the corresponding string. */
++ const CHAR_T *end1, *end2;
++
++ /* Pointers into string1 and string2, just past the last characters in
++ each to consider matching. */
++ const CHAR_T *end_match_1, *end_match_2;
++
++ /* Where we are in the data, and the end of the current string. */
++ const CHAR_T *d, *dend;
++
++ /* Where we are in the pattern, and the end of the pattern. */
++#ifdef WCHAR
++ UCHAR_T *pattern, *p;
++ register UCHAR_T *pend;
++#else /* BYTE */
++ UCHAR_T *p = bufp->buffer;
++ register UCHAR_T *pend = p + bufp->used;
++#endif /* WCHAR */
++
++ /* Mark the opcode just after a start_memory, so we can test for an
++ empty subpattern when we get to the stop_memory. */
++ UCHAR_T *just_past_start_mem = 0;
++
++ /* We use this to map every character in the string. */
++ RE_TRANSLATE_TYPE translate = bufp->translate;
++
++ /* Failure point stack. Each place that can handle a failure further
++ down the line pushes a failure point on this stack. It consists of
++ restart, regend, and reg_info for all registers corresponding to
++ the subexpressions we're currently inside, plus the number of such
++ registers, and, finally, two char *'s. The first char * is where
++ to resume scanning the pattern; the second one is where to resume
++ scanning the strings. If the latter is zero, the failure point is
++ a ``dummy''; if a failure happens and the failure point is a dummy,
++ it gets discarded and the next next one is tried. */
++#ifdef MATCH_MAY_ALLOCATE /* otherwise, this is global. */
++ PREFIX(fail_stack_type) fail_stack;
++#endif
++#ifdef DEBUG
++ static unsigned failure_id;
++ unsigned nfailure_points_pushed = 0, nfailure_points_popped = 0;
++#endif
++
++#ifdef REL_ALLOC
++ /* This holds the pointer to the failure stack, when
++ it is allocated relocatably. */
++ fail_stack_elt_t *failure_stack_ptr;
++#endif
++
++ /* We fill all the registers internally, independent of what we
++ return, for use in backreferences. The number here includes
++ an element for register zero. */
++ size_t num_regs = bufp->re_nsub + 1;
++
++ /* The currently active registers. */
++ active_reg_t lowest_active_reg = NO_LOWEST_ACTIVE_REG;
++ active_reg_t highest_active_reg = NO_HIGHEST_ACTIVE_REG;
++
++ /* Information on the contents of registers. These are pointers into
++ the input strings; they record just what was matched (on this
++ attempt) by a subexpression part of the pattern, that is, the
++ regnum-th regstart pointer points to where in the pattern we began
++ matching and the regnum-th regend points to right after where we
++ stopped matching the regnum-th subexpression. (The zeroth register
++ keeps track of what the whole pattern matches.) */
++#ifdef MATCH_MAY_ALLOCATE /* otherwise, these are global. */
++ const CHAR_T **regstart, **regend;
++#endif
++
++ /* If a group that's operated upon by a repetition operator fails to
++ match anything, then the register for its start will need to be
++ restored because it will have been set to wherever in the string we
++ are when we last see its open-group operator. Similarly for a
++ register's end. */
++#ifdef MATCH_MAY_ALLOCATE /* otherwise, these are global. */
++ const CHAR_T **old_regstart, **old_regend;
++#endif
++
++ /* The is_active field of reg_info helps us keep track of which (possibly
++ nested) subexpressions we are currently in. The matched_something
++ field of reg_info[reg_num] helps us tell whether or not we have
++ matched any of the pattern so far this time through the reg_num-th
++ subexpression. These two fields get reset each time through any
++ loop their register is in. */
++#ifdef MATCH_MAY_ALLOCATE /* otherwise, this is global. */
++ PREFIX(register_info_type) *reg_info;
++#endif
++
++ /* The following record the register info as found in the above
++ variables when we find a match better than any we've seen before.
++ This happens as we backtrack through the failure points, which in
++ turn happens only if we have not yet matched the entire string. */
++ unsigned best_regs_set = false;
++#ifdef MATCH_MAY_ALLOCATE /* otherwise, these are global. */
++ const CHAR_T **best_regstart, **best_regend;
++#endif
++
++ /* Logically, this is `best_regend[0]'. But we don't want to have to
++ allocate space for that if we're not allocating space for anything
++ else (see below). Also, we never need info about register 0 for
++ any of the other register vectors, and it seems rather a kludge to
++ treat `best_regend' differently than the rest. So we keep track of
++ the end of the best match so far in a separate variable. We
++ initialize this to NULL so that when we backtrack the first time
++ and need to test it, it's not garbage. */
++ const CHAR_T *match_end = NULL;
++
++ /* This helps SET_REGS_MATCHED avoid doing redundant work. */
++ int set_regs_matched_done = 0;
++
++ /* Used when we pop values we don't care about. */
++#ifdef MATCH_MAY_ALLOCATE /* otherwise, these are global. */
++ const CHAR_T **reg_dummy;
++ PREFIX(register_info_type) *reg_info_dummy;
++#endif
++
++#ifdef DEBUG
++ /* Counts the total number of registers pushed. */
++ unsigned num_regs_pushed = 0;
++#endif
++
++ DEBUG_PRINT1 ("\n\nEntering re_match_2.\n");
++
++ INIT_FAIL_STACK ();
++
++#ifdef MATCH_MAY_ALLOCATE
++ /* Do not bother to initialize all the register variables if there are
++ no groups in the pattern, as it takes a fair amount of time. If
++ there are groups, we include space for register 0 (the whole
++ pattern), even though we never use it, since it simplifies the
++ array indexing. We should fix this. */
++ if (bufp->re_nsub)
++ {
++ regstart = REGEX_TALLOC (num_regs, const CHAR_T *);
++ regend = REGEX_TALLOC (num_regs, const CHAR_T *);
++ old_regstart = REGEX_TALLOC (num_regs, const CHAR_T *);
++ old_regend = REGEX_TALLOC (num_regs, const CHAR_T *);
++ best_regstart = REGEX_TALLOC (num_regs, const CHAR_T *);
++ best_regend = REGEX_TALLOC (num_regs, const CHAR_T *);
++ reg_info = REGEX_TALLOC (num_regs, PREFIX(register_info_type));
++ reg_dummy = REGEX_TALLOC (num_regs, const CHAR_T *);
++ reg_info_dummy = REGEX_TALLOC (num_regs, PREFIX(register_info_type));
++
++ if (!(regstart && regend && old_regstart && old_regend && reg_info
++ && best_regstart && best_regend && reg_dummy && reg_info_dummy))
++ {
++ FREE_VARIABLES ();
++ return -2;
++ }
++ }
++ else
++ {
++ /* We must initialize all our variables to NULL, so that
++ `FREE_VARIABLES' doesn't try to free them. */
++ regstart = regend = old_regstart = old_regend = best_regstart
++ = best_regend = reg_dummy = NULL;
++ reg_info = reg_info_dummy = (PREFIX(register_info_type) *) NULL;
++ }
++#endif /* MATCH_MAY_ALLOCATE */
++
++ /* The starting position is bogus. */
++#ifdef WCHAR
++ if (pos < 0 || pos > csize1 + csize2)
++#else /* BYTE */
++ if (pos < 0 || pos > size1 + size2)
++#endif
++ {
++ FREE_VARIABLES ();
++ return -1;
++ }
++
++#ifdef WCHAR
++ /* Allocate wchar_t array for string1 and string2 and
++ fill them with converted string. */
++ if (string1 == NULL && string2 == NULL)
++ {
++ /* We need seting up buffers here. */
++
++ /* We must free wcs buffers in this function. */
++ cant_free_wcs_buf = 0;
++
++ if (csize1 != 0)
++ {
++ string1 = REGEX_TALLOC (csize1 + 1, CHAR_T);
++ mbs_offset1 = REGEX_TALLOC (csize1 + 1, int);
++ is_binary = REGEX_TALLOC (csize1 + 1, char);
++ if (!string1 || !mbs_offset1 || !is_binary)
++ {
++ FREE_VAR (string1);
++ FREE_VAR (mbs_offset1);
++ FREE_VAR (is_binary);
++ return -2;
++ }
++ }
++ if (csize2 != 0)
++ {
++ string2 = REGEX_TALLOC (csize2 + 1, CHAR_T);
++ mbs_offset2 = REGEX_TALLOC (csize2 + 1, int);
++ is_binary = REGEX_TALLOC (csize2 + 1, char);
++ if (!string2 || !mbs_offset2 || !is_binary)
++ {
++ FREE_VAR (string1);
++ FREE_VAR (mbs_offset1);
++ FREE_VAR (string2);
++ FREE_VAR (mbs_offset2);
++ FREE_VAR (is_binary);
++ return -2;
++ }
++ size2 = convert_mbs_to_wcs(string2, cstring2, csize2,
++ mbs_offset2, is_binary);
++ string2[size2] = L'\0'; /* for a sentinel */
++ FREE_VAR (is_binary);
++ }
++ }
++
++ /* We need to cast pattern to (wchar_t*), because we casted this compiled
++ pattern to (char*) in regex_compile. */
++ p = pattern = (CHAR_T*)bufp->buffer;
++ pend = (CHAR_T*)(bufp->buffer + bufp->used);
++
++#endif /* WCHAR */
++
++ /* Initialize subexpression text positions to -1 to mark ones that no
++ start_memory/stop_memory has been seen for. Also initialize the
++ register information struct. */
++ for (mcnt = 1; (unsigned) mcnt < num_regs; mcnt++)
++ {
++ regstart[mcnt] = regend[mcnt]
++ = old_regstart[mcnt] = old_regend[mcnt] = REG_UNSET_VALUE;
++
++ REG_MATCH_NULL_STRING_P (reg_info[mcnt]) = MATCH_NULL_UNSET_VALUE;
++ IS_ACTIVE (reg_info[mcnt]) = 0;
++ MATCHED_SOMETHING (reg_info[mcnt]) = 0;
++ EVER_MATCHED_SOMETHING (reg_info[mcnt]) = 0;
++ }
++
++ /* We move `string1' into `string2' if the latter's empty -- but not if
++ `string1' is null. */
++ if (size2 == 0 && string1 != NULL)
++ {
++ string2 = string1;
++ size2 = size1;
++ string1 = 0;
++ size1 = 0;
++#ifdef WCHAR
++ mbs_offset2 = mbs_offset1;
++ csize2 = csize1;
++ mbs_offset1 = NULL;
++ csize1 = 0;
++#endif
++ }
++ end1 = string1 + size1;
++ end2 = string2 + size2;
++
++ /* Compute where to stop matching, within the two strings. */
++#ifdef WCHAR
++ if (stop <= csize1)
++ {
++ mcnt = count_mbs_length(mbs_offset1, stop);
++ end_match_1 = string1 + mcnt;
++ end_match_2 = string2;
++ }
++ else
++ {
++ if (stop > csize1 + csize2)
++ stop = csize1 + csize2;
++ end_match_1 = end1;
++ mcnt = count_mbs_length(mbs_offset2, stop-csize1);
++ end_match_2 = string2 + mcnt;
++ }
++ if (mcnt < 0)
++ { /* count_mbs_length return error. */
++ FREE_VARIABLES ();
++ return -1;
++ }
++#else
++ if (stop <= size1)
++ {
++ end_match_1 = string1 + stop;
++ end_match_2 = string2;
++ }
++ else
++ {
++ end_match_1 = end1;
++ end_match_2 = string2 + stop - size1;
++ }
++#endif /* WCHAR */
++
++ /* `p' scans through the pattern as `d' scans through the data.
++ `dend' is the end of the input string that `d' points within. `d'
++ is advanced into the following input string whenever necessary, but
++ this happens before fetching; therefore, at the beginning of the
++ loop, `d' can be pointing at the end of a string, but it cannot
++ equal `string2'. */
++#ifdef WCHAR
++ if (size1 > 0 && pos <= csize1)
++ {
++ mcnt = count_mbs_length(mbs_offset1, pos);
++ d = string1 + mcnt;
++ dend = end_match_1;
++ }
++ else
++ {
++ mcnt = count_mbs_length(mbs_offset2, pos-csize1);
++ d = string2 + mcnt;
++ dend = end_match_2;
++ }
++
++ if (mcnt < 0)
++ { /* count_mbs_length return error. */
++ FREE_VARIABLES ();
++ return -1;
++ }
++#else
++ if (size1 > 0 && pos <= size1)
++ {
++ d = string1 + pos;
++ dend = end_match_1;
++ }
++ else
++ {
++ d = string2 + pos - size1;
++ dend = end_match_2;
++ }
++#endif /* WCHAR */
++
++ DEBUG_PRINT1 ("The compiled pattern is:\n");
++ DEBUG_PRINT_COMPILED_PATTERN (bufp, p, pend);
++ DEBUG_PRINT1 ("The string to match is: `");
++ DEBUG_PRINT_DOUBLE_STRING (d, string1, size1, string2, size2);
++ DEBUG_PRINT1 ("'\n");
++
++ /* This loops over pattern commands. It exits by returning from the
++ function if the match is complete, or it drops through if the match
++ fails at this starting point in the input data. */
++ for (;;)
++ {
++#ifdef _LIBC
++ DEBUG_PRINT2 ("\n%p: ", p);
++#else
++ DEBUG_PRINT2 ("\n0x%x: ", p);
++#endif
++
++ if (p == pend)
++ { /* End of pattern means we might have succeeded. */
++ DEBUG_PRINT1 ("end of pattern ... ");
++
++ /* If we haven't matched the entire string, and we want the
++ longest match, try backtracking. */
++ if (d != end_match_2)
++ {
++ /* 1 if this match ends in the same string (string1 or string2)
++ as the best previous match. */
++ boolean same_str_p = (FIRST_STRING_P (match_end)
++ == MATCHING_IN_FIRST_STRING);
++ /* 1 if this match is the best seen so far. */
++ boolean best_match_p;
++
++ /* AIX compiler got confused when this was combined
++ with the previous declaration. */
++ if (same_str_p)
++ best_match_p = d > match_end;
++ else
++ best_match_p = !MATCHING_IN_FIRST_STRING;
++
++ DEBUG_PRINT1 ("backtracking.\n");
++
++ if (!FAIL_STACK_EMPTY ())
++ { /* More failure points to try. */
++
++ /* If exceeds best match so far, save it. */
++ if (!best_regs_set || best_match_p)
++ {
++ best_regs_set = true;
++ match_end = d;
++
++ DEBUG_PRINT1 ("\nSAVING match as best so far.\n");
++
++ for (mcnt = 1; (unsigned) mcnt < num_regs; mcnt++)
++ {
++ best_regstart[mcnt] = regstart[mcnt];
++ best_regend[mcnt] = regend[mcnt];
++ }
++ }
++ goto fail;
++ }
++
++ /* If no failure points, don't restore garbage. And if
++ last match is real best match, don't restore second
++ best one. */
++ else if (best_regs_set && !best_match_p)
++ {
++ restore_best_regs:
++ /* Restore best match. It may happen that `dend ==
++ end_match_1' while the restored d is in string2.
++ For example, the pattern `x.*y.*z' against the
++ strings `x-' and `y-z-', if the two strings are
++ not consecutive in memory. */
++ DEBUG_PRINT1 ("Restoring best registers.\n");
++
++ d = match_end;
++ dend = ((d >= string1 && d <= end1)
++ ? end_match_1 : end_match_2);
++
++ for (mcnt = 1; (unsigned) mcnt < num_regs; mcnt++)
++ {
++ regstart[mcnt] = best_regstart[mcnt];
++ regend[mcnt] = best_regend[mcnt];
++ }
++ }
++ } /* d != end_match_2 */
++
++ succeed_label:
++ DEBUG_PRINT1 ("Accepting match.\n");
++ /* If caller wants register contents data back, do it. */
++ if (regs && !bufp->no_sub)
++ {
++ /* Have the register data arrays been allocated? */
++ if (bufp->regs_allocated == REGS_UNALLOCATED)
++ { /* No. So allocate them with malloc. We need one
++ extra element beyond `num_regs' for the `-1' marker
++ GNU code uses. */
++ regs->num_regs = MAX (RE_NREGS, num_regs + 1);
++ regs->start = TALLOC (regs->num_regs, regoff_t);
++ regs->end = TALLOC (regs->num_regs, regoff_t);
++ if (regs->start == NULL || regs->end == NULL)
++ {
++ FREE_VARIABLES ();
++ return -2;
++ }
++ bufp->regs_allocated = REGS_REALLOCATE;
++ }
++ else if (bufp->regs_allocated == REGS_REALLOCATE)
++ { /* Yes. If we need more elements than were already
++ allocated, reallocate them. If we need fewer, just
++ leave it alone. */
++ if (regs->num_regs < num_regs + 1)
++ {
++ regs->num_regs = num_regs + 1;
++ RETALLOC (regs->start, regs->num_regs, regoff_t);
++ RETALLOC (regs->end, regs->num_regs, regoff_t);
++ if (regs->start == NULL || regs->end == NULL)
++ {
++ FREE_VARIABLES ();
++ return -2;
++ }
++ }
++ }
++ else
++ {
++ /* These braces fend off a "empty body in an else-statement"
++ warning under GCC when assert expands to nothing. */
++ assert (bufp->regs_allocated == REGS_FIXED);
++ }
++
++ /* Convert the pointer data in `regstart' and `regend' to
++ indices. Register zero has to be set differently,
++ since we haven't kept track of any info for it. */
++ if (regs->num_regs > 0)
++ {
++ regs->start[0] = pos;
++#ifdef WCHAR
++ if (MATCHING_IN_FIRST_STRING)
++ regs->end[0] = mbs_offset1 != NULL ?
++ mbs_offset1[d-string1] : 0;
++ else
++ regs->end[0] = csize1 + (mbs_offset2 != NULL ?
++ mbs_offset2[d-string2] : 0);
++#else
++ regs->end[0] = (MATCHING_IN_FIRST_STRING
++ ? ((regoff_t) (d - string1))
++ : ((regoff_t) (d - string2 + size1)));
++#endif /* WCHAR */
++ }
++
++ /* Go through the first `min (num_regs, regs->num_regs)'
++ registers, since that is all we initialized. */
++ for (mcnt = 1; (unsigned) mcnt < MIN (num_regs, regs->num_regs);
++ mcnt++)
++ {
++ if (REG_UNSET (regstart[mcnt]) || REG_UNSET (regend[mcnt]))
++ regs->start[mcnt] = regs->end[mcnt] = -1;
++ else
++ {
++ regs->start[mcnt]
++ = (regoff_t) POINTER_TO_OFFSET (regstart[mcnt]);
++ regs->end[mcnt]
++ = (regoff_t) POINTER_TO_OFFSET (regend[mcnt]);
++ }
++ }
++
++ /* If the regs structure we return has more elements than
++ were in the pattern, set the extra elements to -1. If
++ we (re)allocated the registers, this is the case,
++ because we always allocate enough to have at least one
++ -1 at the end. */
++ for (mcnt = num_regs; (unsigned) mcnt < regs->num_regs; mcnt++)
++ regs->start[mcnt] = regs->end[mcnt] = -1;
++ } /* regs && !bufp->no_sub */
++
++ DEBUG_PRINT4 ("%u failure points pushed, %u popped (%u remain).\n",
++ nfailure_points_pushed, nfailure_points_popped,
++ nfailure_points_pushed - nfailure_points_popped);
++ DEBUG_PRINT2 ("%u registers pushed.\n", num_regs_pushed);
++
++#ifdef WCHAR
++ if (MATCHING_IN_FIRST_STRING)
++ mcnt = mbs_offset1 != NULL ? mbs_offset1[d-string1] : 0;
++ else
++ mcnt = (mbs_offset2 != NULL ? mbs_offset2[d-string2] : 0) +
++ csize1;
++ mcnt -= pos;
++#else
++ mcnt = d - pos - (MATCHING_IN_FIRST_STRING
++ ? string1
++ : string2 - size1);
++#endif /* WCHAR */
++
++ DEBUG_PRINT2 ("Returning %d from re_match_2.\n", mcnt);
++
++ FREE_VARIABLES ();
++ return mcnt;
++ }
++
++ /* Otherwise match next pattern command. */
++ switch (SWITCH_ENUM_CAST ((re_opcode_t) *p++))
++ {
++ /* Ignore these. Used to ignore the n of succeed_n's which
++ currently have n == 0. */
++ case no_op:
++ DEBUG_PRINT1 ("EXECUTING no_op.\n");
++ break;
++
++ case succeed:
++ DEBUG_PRINT1 ("EXECUTING succeed.\n");
++ goto succeed_label;
++
++ /* Match the next n pattern characters exactly. The following
++ byte in the pattern defines n, and the n bytes after that
++ are the characters to match. */
++ case exactn:
++#ifdef MBS_SUPPORT
++ case exactn_bin:
++#endif
++ mcnt = *p++;
++ DEBUG_PRINT2 ("EXECUTING exactn %d.\n", mcnt);
++
++ /* This is written out as an if-else so we don't waste time
++ testing `translate' inside the loop. */
++ if (translate)
++ {
++ do
++ {
++ PREFETCH ();
++#ifdef WCHAR
++ if (*d <= 0xff)
++ {
++ if ((UCHAR_T) translate[(unsigned char) *d++]
++ != (UCHAR_T) *p++)
++ goto fail;
++ }
++ else
++ {
++ if (*d++ != (CHAR_T) *p++)
++ goto fail;
++ }
++#else
++ if ((UCHAR_T) translate[(unsigned char) *d++]
++ != (UCHAR_T) *p++)
++ goto fail;
++#endif /* WCHAR */
++ }
++ while (--mcnt);
++ }
++ else
++ {
++ do
++ {
++ PREFETCH ();
++ if (*d++ != (CHAR_T) *p++) goto fail;
++ }
++ while (--mcnt);
++ }
++ SET_REGS_MATCHED ();
++ break;
++
++
++ /* Match any character except possibly a newline or a null. */
++ case anychar:
++ DEBUG_PRINT1 ("EXECUTING anychar.\n");
++
++ PREFETCH ();
++
++ if ((!(bufp->syntax & RE_DOT_NEWLINE) && TRANSLATE (*d) == '\n')
++ || (bufp->syntax & RE_DOT_NOT_NULL && TRANSLATE (*d) == '\000'))
++ goto fail;
++
++ SET_REGS_MATCHED ();
++ DEBUG_PRINT2 (" Matched `%ld'.\n", (long int) *d);
++ d++;
++ break;
++
++
++ case charset:
++ case charset_not:
++ {
++ register UCHAR_T c;
++#ifdef WCHAR
++ unsigned int i, char_class_length, coll_symbol_length,
++ equiv_class_length, ranges_length, chars_length, length;
++ CHAR_T *workp, *workp2, *charset_top;
++#define WORK_BUFFER_SIZE 128
++ CHAR_T str_buf[WORK_BUFFER_SIZE];
++# ifdef _LIBC
++ uint32_t nrules;
++# endif /* _LIBC */
++#endif /* WCHAR */
++ boolean negate = (re_opcode_t) *(p - 1) == charset_not;
++
++ DEBUG_PRINT2 ("EXECUTING charset%s.\n", negate ? "_not" : "");
++ PREFETCH ();
++ c = TRANSLATE (*d); /* The character to match. */
++#ifdef WCHAR
++# ifdef _LIBC
++ nrules = _NL_CURRENT_WORD (LC_COLLATE, _NL_COLLATE_NRULES);
++# endif /* _LIBC */
++ charset_top = p - 1;
++ char_class_length = *p++;
++ coll_symbol_length = *p++;
++ equiv_class_length = *p++;
++ ranges_length = *p++;
++ chars_length = *p++;
++ /* p points charset[6], so the address of the next instruction
++ (charset[l+m+n+2o+k+p']) equals p[l+m+n+2*o+p'],
++ where l=length of char_classes, m=length of collating_symbol,
++ n=equivalence_class, o=length of char_range,
++ p'=length of character. */
++ workp = p;
++ /* Update p to indicate the next instruction. */
++ p += char_class_length + coll_symbol_length+ equiv_class_length +
++ 2*ranges_length + chars_length;
++
++ /* match with char_class? */
++ for (i = 0; i < char_class_length ; i += CHAR_CLASS_SIZE)
++ {
++ wctype_t wctype;
++ uintptr_t alignedp = ((uintptr_t)workp
++ + __alignof__(wctype_t) - 1)
++ & ~(uintptr_t)(__alignof__(wctype_t) - 1);
++ wctype = *((wctype_t*)alignedp);
++ workp += CHAR_CLASS_SIZE;
++# ifdef _LIBC
++ if (__iswctype((wint_t)c, wctype))
++ goto char_set_matched;
++# else
++ if (iswctype((wint_t)c, wctype))
++ goto char_set_matched;
++# endif
++ }
++
++ /* match with collating_symbol? */
++# ifdef _LIBC
++ if (nrules != 0)
++ {
++ const unsigned char *extra = (const unsigned char *)
++ _NL_CURRENT (LC_COLLATE, _NL_COLLATE_SYMB_EXTRAMB);
++
++ for (workp2 = workp + coll_symbol_length ; workp < workp2 ;
++ workp++)
++ {
++ int32_t *wextra;
++ wextra = (int32_t*)(extra + *workp++);
++ for (i = 0; i < *wextra; ++i)
++ if (TRANSLATE(d[i]) != wextra[1 + i])
++ break;
++
++ if (i == *wextra)
++ {
++ /* Update d, however d will be incremented at
++ char_set_matched:, we decrement d here. */
++ d += i - 1;
++ goto char_set_matched;
++ }
++ }
++ }
++ else /* (nrules == 0) */
++# endif
++ /* If we can't look up collation data, we use wcscoll
++ instead. */
++ {
++ for (workp2 = workp + coll_symbol_length ; workp < workp2 ;)
++ {
++ const CHAR_T *backup_d = d, *backup_dend = dend;
++# ifdef _LIBC
++ length = __wcslen (workp);
++# else
++ length = wcslen (workp);
++# endif
++
++ /* If wcscoll(the collating symbol, whole string) > 0,
++ any substring of the string never match with the
++ collating symbol. */
++# ifdef _LIBC
++ if (__wcscoll (workp, d) > 0)
++# else
++ if (wcscoll (workp, d) > 0)
++# endif
++ {
++ workp += length + 1;
++ continue;
++ }
++
++ /* First, we compare the collating symbol with
++ the first character of the string.
++ If it don't match, we add the next character to
++ the compare buffer in turn. */
++ for (i = 0 ; i < WORK_BUFFER_SIZE-1 ; i++, d++)
++ {
++ int match;
++ if (d == dend)
++ {
++ if (dend == end_match_2)
++ break;
++ d = string2;
++ dend = end_match_2;
++ }
++
++ /* add next character to the compare buffer. */
++ str_buf[i] = TRANSLATE(*d);
++ str_buf[i+1] = '\0';
++
++# ifdef _LIBC
++ match = __wcscoll (workp, str_buf);
++# else
++ match = wcscoll (workp, str_buf);
++# endif
++ if (match == 0)
++ goto char_set_matched;
++
++ if (match < 0)
++ /* (str_buf > workp) indicate (str_buf + X > workp),
++ because for all X (str_buf + X > str_buf).
++ So we don't need continue this loop. */
++ break;
++
++ /* Otherwise(str_buf < workp),
++ (str_buf+next_character) may equals (workp).
++ So we continue this loop. */
++ }
++ /* not matched */
++ d = backup_d;
++ dend = backup_dend;
++ workp += length + 1;
++ }
++ }
++ /* match with equivalence_class? */
++# ifdef _LIBC
++ if (nrules != 0)
++ {
++ const CHAR_T *backup_d = d, *backup_dend = dend;
++ /* Try to match the equivalence class against
++ those known to the collate implementation. */
++ const int32_t *table;
++ const int32_t *weights;
++ const int32_t *extra;
++ const int32_t *indirect;
++ int32_t idx, idx2;
++ wint_t *cp;
++ size_t len;
++
++ /* This #include defines a local function! */
++# include <locale/weightwc.h>
++
++ table = (const int32_t *)
++ _NL_CURRENT (LC_COLLATE, _NL_COLLATE_TABLEWC);
++ weights = (const wint_t *)
++ _NL_CURRENT (LC_COLLATE, _NL_COLLATE_WEIGHTWC);
++ extra = (const wint_t *)
++ _NL_CURRENT (LC_COLLATE, _NL_COLLATE_EXTRAWC);
++ indirect = (const int32_t *)
++ _NL_CURRENT (LC_COLLATE, _NL_COLLATE_INDIRECTWC);
++
++ /* Write 1 collating element to str_buf, and
++ get its index. */
++ idx2 = 0;
++
++ for (i = 0 ; idx2 == 0 && i < WORK_BUFFER_SIZE - 1; i++)
++ {
++ cp = (wint_t*)str_buf;
++ if (d == dend)
++ {
++ if (dend == end_match_2)
++ break;
++ d = string2;
++ dend = end_match_2;
++ }
++ str_buf[i] = TRANSLATE(*(d+i));
++ str_buf[i+1] = '\0'; /* sentinel */
++ idx2 = findidx ((const wint_t**)&cp, i);
++ }
++
++ /* Update d, however d will be incremented at
++ char_set_matched:, we decrement d here. */
++ d = backup_d + ((wchar_t*)cp - (wchar_t*)str_buf - 1);
++ if (d >= dend)
++ {
++ if (dend == end_match_2)
++ d = dend;
++ else
++ {
++ d = string2;
++ dend = end_match_2;
++ }
++ }
++
++ len = weights[idx2];
++
++ for (workp2 = workp + equiv_class_length ; workp < workp2 ;
++ workp++)
++ {
++ idx = (int32_t)*workp;
++ /* We already checked idx != 0 in regex_compile. */
++
++ if (idx2 != 0 && len == weights[idx])
++ {
++ int cnt = 0;
++ while (cnt < len && (weights[idx + 1 + cnt]
++ == weights[idx2 + 1 + cnt]))
++ ++cnt;
++
++ if (cnt == len)
++ goto char_set_matched;
++ }
++ }
++ /* not matched */
++ d = backup_d;
++ dend = backup_dend;
++ }
++ else /* (nrules == 0) */
++# endif
++ /* If we can't look up collation data, we use wcscoll
++ instead. */
++ {
++ for (workp2 = workp + equiv_class_length ; workp < workp2 ;)
++ {
++ const CHAR_T *backup_d = d, *backup_dend = dend;
++# ifdef _LIBC
++ length = __wcslen (workp);
++# else
++ length = wcslen (workp);
++# endif
++
++ /* If wcscoll(the collating symbol, whole string) > 0,
++ any substring of the string never match with the
++ collating symbol. */
++# ifdef _LIBC
++ if (__wcscoll (workp, d) > 0)
++# else
++ if (wcscoll (workp, d) > 0)
++# endif
++ {
++ workp += length + 1;
++ break;
++ }
++
++ /* First, we compare the equivalence class with
++ the first character of the string.
++ If it don't match, we add the next character to
++ the compare buffer in turn. */
++ for (i = 0 ; i < WORK_BUFFER_SIZE - 1 ; i++, d++)
++ {
++ int match;
++ if (d == dend)
++ {
++ if (dend == end_match_2)
++ break;
++ d = string2;
++ dend = end_match_2;
++ }
++
++ /* add next character to the compare buffer. */
++ str_buf[i] = TRANSLATE(*d);
++ str_buf[i+1] = '\0';
++
++# ifdef _LIBC
++ match = __wcscoll (workp, str_buf);
++# else
++ match = wcscoll (workp, str_buf);
++# endif
++
++ if (match == 0)
++ goto char_set_matched;
++
++ if (match < 0)
++ /* (str_buf > workp) indicate (str_buf + X > workp),
++ because for all X (str_buf + X > str_buf).
++ So we don't need continue this loop. */
++ break;
++
++ /* Otherwise(str_buf < workp),
++ (str_buf+next_character) may equals (workp).
++ So we continue this loop. */
++ }
++ /* not matched */
++ d = backup_d;
++ dend = backup_dend;
++ workp += length + 1;
++ }
++ }
++
++ /* match with char_range? */
++# ifdef _LIBC
++ if (nrules != 0)
++ {
++ uint32_t collseqval;
++ const char *collseq = (const char *)
++ _NL_CURRENT(LC_COLLATE, _NL_COLLATE_COLLSEQWC);
++
++ collseqval = collseq_table_lookup (collseq, c);
++
++ for (; workp < p - chars_length ;)
++ {
++ uint32_t start_val, end_val;
++
++ /* We already compute the collation sequence value
++ of the characters (or collating symbols). */
++ start_val = (uint32_t) *workp++; /* range_start */
++ end_val = (uint32_t) *workp++; /* range_end */
++
++ if (start_val <= collseqval && collseqval <= end_val)
++ goto char_set_matched;
++ }
++ }
++ else
++# endif
++ {
++ /* We set range_start_char at str_buf[0], range_end_char
++ at str_buf[4], and compared char at str_buf[2]. */
++ str_buf[1] = 0;
++ str_buf[2] = c;
++ str_buf[3] = 0;
++ str_buf[5] = 0;
++ for (; workp < p - chars_length ;)
++ {
++ wchar_t *range_start_char, *range_end_char;
++
++ /* match if (range_start_char <= c <= range_end_char). */
++
++ /* If range_start(or end) < 0, we assume -range_start(end)
++ is the offset of the collating symbol which is specified
++ as the character of the range start(end). */
++
++ /* range_start */
++ if (*workp < 0)
++ range_start_char = charset_top - (*workp++);
++ else
++ {
++ str_buf[0] = *workp++;
++ range_start_char = str_buf;
++ }
++
++ /* range_end */
++ if (*workp < 0)
++ range_end_char = charset_top - (*workp++);
++ else
++ {
++ str_buf[4] = *workp++;
++ range_end_char = str_buf + 4;
++ }
++
++# ifdef _LIBC
++ if (__wcscoll (range_start_char, str_buf+2) <= 0
++ && __wcscoll (str_buf+2, range_end_char) <= 0)
++# else
++ if (wcscoll (range_start_char, str_buf+2) <= 0
++ && wcscoll (str_buf+2, range_end_char) <= 0)
++# endif
++ goto char_set_matched;
++ }
++ }
++
++ /* match with char? */
++ for (; workp < p ; workp++)
++ if (c == *workp)
++ goto char_set_matched;
++
++ negate = !negate;
++
++ char_set_matched:
++ if (negate) goto fail;
++#else
++ /* Cast to `unsigned' instead of `unsigned char' in case the
++ bit list is a full 32 bytes long. */
++ if (c < (unsigned) (*p * BYTEWIDTH)
++ && p[1 + c / BYTEWIDTH] & (1 << (c % BYTEWIDTH)))
++ negate = !negate;
++
++ p += 1 + *p;
++
++ if (!negate) goto fail;
++#undef WORK_BUFFER_SIZE
++#endif /* WCHAR */
++ SET_REGS_MATCHED ();
++ d++;
++ break;
++ }
++
++
++ /* The beginning of a group is represented by start_memory.
++ The arguments are the register number in the next byte, and the
++ number of groups inner to this one in the next. The text
++ matched within the group is recorded (in the internal
++ registers data structure) under the register number. */
++ case start_memory:
++ DEBUG_PRINT3 ("EXECUTING start_memory %ld (%ld):\n",
++ (long int) *p, (long int) p[1]);
++
++ /* Find out if this group can match the empty string. */
++ p1 = p; /* To send to group_match_null_string_p. */
++
++ if (REG_MATCH_NULL_STRING_P (reg_info[*p]) == MATCH_NULL_UNSET_VALUE)
++ REG_MATCH_NULL_STRING_P (reg_info[*p])
++ = PREFIX(group_match_null_string_p) (&p1, pend, reg_info);
++
++ /* Save the position in the string where we were the last time
++ we were at this open-group operator in case the group is
++ operated upon by a repetition operator, e.g., with `(a*)*b'
++ against `ab'; then we want to ignore where we are now in
++ the string in case this attempt to match fails. */
++ old_regstart[*p] = REG_MATCH_NULL_STRING_P (reg_info[*p])
++ ? REG_UNSET (regstart[*p]) ? d : regstart[*p]
++ : regstart[*p];
++ DEBUG_PRINT2 (" old_regstart: %d\n",
++ POINTER_TO_OFFSET (old_regstart[*p]));
++
++ regstart[*p] = d;
++ DEBUG_PRINT2 (" regstart: %d\n", POINTER_TO_OFFSET (regstart[*p]));
++
++ IS_ACTIVE (reg_info[*p]) = 1;
++ MATCHED_SOMETHING (reg_info[*p]) = 0;
++
++ /* Clear this whenever we change the register activity status. */
++ set_regs_matched_done = 0;
++
++ /* This is the new highest active register. */
++ highest_active_reg = *p;
++
++ /* If nothing was active before, this is the new lowest active
++ register. */
++ if (lowest_active_reg == NO_LOWEST_ACTIVE_REG)
++ lowest_active_reg = *p;
++
++ /* Move past the register number and inner group count. */
++ p += 2;
++ just_past_start_mem = p;
++
++ break;
++
++
++ /* The stop_memory opcode represents the end of a group. Its
++ arguments are the same as start_memory's: the register
++ number, and the number of inner groups. */
++ case stop_memory:
++ DEBUG_PRINT3 ("EXECUTING stop_memory %ld (%ld):\n",
++ (long int) *p, (long int) p[1]);
++
++ /* We need to save the string position the last time we were at
++ this close-group operator in case the group is operated
++ upon by a repetition operator, e.g., with `((a*)*(b*)*)*'
++ against `aba'; then we want to ignore where we are now in
++ the string in case this attempt to match fails. */
++ old_regend[*p] = REG_MATCH_NULL_STRING_P (reg_info[*p])
++ ? REG_UNSET (regend[*p]) ? d : regend[*p]
++ : regend[*p];
++ DEBUG_PRINT2 (" old_regend: %d\n",
++ POINTER_TO_OFFSET (old_regend[*p]));
++
++ regend[*p] = d;
++ DEBUG_PRINT2 (" regend: %d\n", POINTER_TO_OFFSET (regend[*p]));
++
++ /* This register isn't active anymore. */
++ IS_ACTIVE (reg_info[*p]) = 0;
++
++ /* Clear this whenever we change the register activity status. */
++ set_regs_matched_done = 0;
++
++ /* If this was the only register active, nothing is active
++ anymore. */
++ if (lowest_active_reg == highest_active_reg)
++ {
++ lowest_active_reg = NO_LOWEST_ACTIVE_REG;
++ highest_active_reg = NO_HIGHEST_ACTIVE_REG;
++ }
++ else
++ { /* We must scan for the new highest active register, since
++ it isn't necessarily one less than now: consider
++ (a(b)c(d(e)f)g). When group 3 ends, after the f), the
++ new highest active register is 1. */
++ UCHAR_T r = *p - 1;
++ while (r > 0 && !IS_ACTIVE (reg_info[r]))
++ r--;
++
++ /* If we end up at register zero, that means that we saved
++ the registers as the result of an `on_failure_jump', not
++ a `start_memory', and we jumped to past the innermost
++ `stop_memory'. For example, in ((.)*) we save
++ registers 1 and 2 as a result of the *, but when we pop
++ back to the second ), we are at the stop_memory 1.
++ Thus, nothing is active. */
++ if (r == 0)
++ {
++ lowest_active_reg = NO_LOWEST_ACTIVE_REG;
++ highest_active_reg = NO_HIGHEST_ACTIVE_REG;
++ }
++ else
++ highest_active_reg = r;
++ }
++
++ /* If just failed to match something this time around with a
++ group that's operated on by a repetition operator, try to
++ force exit from the ``loop'', and restore the register
++ information for this group that we had before trying this
++ last match. */
++ if ((!MATCHED_SOMETHING (reg_info[*p])
++ || just_past_start_mem == p - 1)
++ && (p + 2) < pend)
++ {
++ boolean is_a_jump_n = false;
++
++ p1 = p + 2;
++ mcnt = 0;
++ switch ((re_opcode_t) *p1++)
++ {
++ case jump_n:
++ is_a_jump_n = true;
++ case pop_failure_jump:
++ case maybe_pop_jump:
++ case jump:
++ case dummy_failure_jump:
++ EXTRACT_NUMBER_AND_INCR (mcnt, p1);
++ if (is_a_jump_n)
++ p1 += OFFSET_ADDRESS_SIZE;
++ break;
++
++ default:
++ /* do nothing */ ;
++ }
++ p1 += mcnt;
++
++ /* If the next operation is a jump backwards in the pattern
++ to an on_failure_jump right before the start_memory
++ corresponding to this stop_memory, exit from the loop
++ by forcing a failure after pushing on the stack the
++ on_failure_jump's jump in the pattern, and d. */
++ if (mcnt < 0 && (re_opcode_t) *p1 == on_failure_jump
++ && (re_opcode_t) p1[1+OFFSET_ADDRESS_SIZE] == start_memory
++ && p1[2+OFFSET_ADDRESS_SIZE] == *p)
++ {
++ /* If this group ever matched anything, then restore
++ what its registers were before trying this last
++ failed match, e.g., with `(a*)*b' against `ab' for
++ regstart[1], and, e.g., with `((a*)*(b*)*)*'
++ against `aba' for regend[3].
++
++ Also restore the registers for inner groups for,
++ e.g., `((a*)(b*))*' against `aba' (register 3 would
++ otherwise get trashed). */
++
++ if (EVER_MATCHED_SOMETHING (reg_info[*p]))
++ {
++ unsigned r;
++
++ EVER_MATCHED_SOMETHING (reg_info[*p]) = 0;
++
++ /* Restore this and inner groups' (if any) registers. */
++ for (r = *p; r < (unsigned) *p + (unsigned) *(p + 1);
++ r++)
++ {
++ regstart[r] = old_regstart[r];
++
++ /* xx why this test? */
++ if (old_regend[r] >= regstart[r])
++ regend[r] = old_regend[r];
++ }
++ }
++ p1++;
++ EXTRACT_NUMBER_AND_INCR (mcnt, p1);
++ PUSH_FAILURE_POINT (p1 + mcnt, d, -2);
++
++ goto fail;
++ }
++ }
++
++ /* Move past the register number and the inner group count. */
++ p += 2;
++ break;
++
++
++ /* \<digit> has been turned into a `duplicate' command which is
++ followed by the numeric value of <digit> as the register number. */
++ case duplicate:
++ {
++ register const CHAR_T *d2, *dend2;
++ int regno = *p++; /* Get which register to match against. */
++ DEBUG_PRINT2 ("EXECUTING duplicate %d.\n", regno);
++
++ /* Can't back reference a group which we've never matched. */
++ if (REG_UNSET (regstart[regno]) || REG_UNSET (regend[regno]))
++ goto fail;
++
++ /* Where in input to try to start matching. */
++ d2 = regstart[regno];
++
++ /* Where to stop matching; if both the place to start and
++ the place to stop matching are in the same string, then
++ set to the place to stop, otherwise, for now have to use
++ the end of the first string. */
++
++ dend2 = ((FIRST_STRING_P (regstart[regno])
++ == FIRST_STRING_P (regend[regno]))
++ ? regend[regno] : end_match_1);
++ for (;;)
++ {
++ /* If necessary, advance to next segment in register
++ contents. */
++ while (d2 == dend2)
++ {
++ if (dend2 == end_match_2) break;
++ if (dend2 == regend[regno]) break;
++
++ /* End of string1 => advance to string2. */
++ d2 = string2;
++ dend2 = regend[regno];
++ }
++ /* At end of register contents => success */
++ if (d2 == dend2) break;
++
++ /* If necessary, advance to next segment in data. */
++ PREFETCH ();
++
++ /* How many characters left in this segment to match. */
++ mcnt = dend - d;
++
++ /* Want how many consecutive characters we can match in
++ one shot, so, if necessary, adjust the count. */
++ if (mcnt > dend2 - d2)
++ mcnt = dend2 - d2;
++
++ /* Compare that many; failure if mismatch, else move
++ past them. */
++ if (translate
++ ? PREFIX(bcmp_translate) (d, d2, mcnt, translate)
++ : memcmp (d, d2, mcnt*sizeof(UCHAR_T)))
++ goto fail;
++ d += mcnt, d2 += mcnt;
++
++ /* Do this because we've match some characters. */
++ SET_REGS_MATCHED ();
++ }
++ }
++ break;
++
++
++ /* begline matches the empty string at the beginning of the string
++ (unless `not_bol' is set in `bufp'), and, if
++ `newline_anchor' is set, after newlines. */
++ case begline:
++ DEBUG_PRINT1 ("EXECUTING begline.\n");
++
++ if (AT_STRINGS_BEG (d))
++ {
++ if (!bufp->not_bol) break;
++ }
++ else if (d[-1] == '\n' && bufp->newline_anchor)
++ {
++ break;
++ }
++ /* In all other cases, we fail. */
++ goto fail;
++
++
++ /* endline is the dual of begline. */
++ case endline:
++ DEBUG_PRINT1 ("EXECUTING endline.\n");
++
++ if (AT_STRINGS_END (d))
++ {
++ if (!bufp->not_eol) break;
++ }
++
++ /* We have to ``prefetch'' the next character. */
++ else if ((d == end1 ? *string2 : *d) == '\n'
++ && bufp->newline_anchor)
++ {
++ break;
++ }
++ goto fail;
++
++
++ /* Match at the very beginning of the data. */
++ case begbuf:
++ DEBUG_PRINT1 ("EXECUTING begbuf.\n");
++ if (AT_STRINGS_BEG (d))
++ break;
++ goto fail;
++
++
++ /* Match at the very end of the data. */
++ case endbuf:
++ DEBUG_PRINT1 ("EXECUTING endbuf.\n");
++ if (AT_STRINGS_END (d))
++ break;
++ goto fail;
++
++
++ /* on_failure_keep_string_jump is used to optimize `.*\n'. It
++ pushes NULL as the value for the string on the stack. Then
++ `pop_failure_point' will keep the current value for the
++ string, instead of restoring it. To see why, consider
++ matching `foo\nbar' against `.*\n'. The .* matches the foo;
++ then the . fails against the \n. But the next thing we want
++ to do is match the \n against the \n; if we restored the
++ string value, we would be back at the foo.
++
++ Because this is used only in specific cases, we don't need to
++ check all the things that `on_failure_jump' does, to make
++ sure the right things get saved on the stack. Hence we don't
++ share its code. The only reason to push anything on the
++ stack at all is that otherwise we would have to change
++ `anychar's code to do something besides goto fail in this
++ case; that seems worse than this. */
++ case on_failure_keep_string_jump:
++ DEBUG_PRINT1 ("EXECUTING on_failure_keep_string_jump");
++
++ EXTRACT_NUMBER_AND_INCR (mcnt, p);
++#ifdef _LIBC
++ DEBUG_PRINT3 (" %d (to %p):\n", mcnt, p + mcnt);
++#else
++ DEBUG_PRINT3 (" %d (to 0x%x):\n", mcnt, p + mcnt);
++#endif
++
++ PUSH_FAILURE_POINT (p + mcnt, NULL, -2);
++ break;
++
++
++ /* Uses of on_failure_jump:
++
++ Each alternative starts with an on_failure_jump that points
++ to the beginning of the next alternative. Each alternative
++ except the last ends with a jump that in effect jumps past
++ the rest of the alternatives. (They really jump to the
++ ending jump of the following alternative, because tensioning
++ these jumps is a hassle.)
++
++ Repeats start with an on_failure_jump that points past both
++ the repetition text and either the following jump or
++ pop_failure_jump back to this on_failure_jump. */
++ case on_failure_jump:
++ on_failure:
++ DEBUG_PRINT1 ("EXECUTING on_failure_jump");
++
++ EXTRACT_NUMBER_AND_INCR (mcnt, p);
++#ifdef _LIBC
++ DEBUG_PRINT3 (" %d (to %p)", mcnt, p + mcnt);
++#else
++ DEBUG_PRINT3 (" %d (to 0x%x)", mcnt, p + mcnt);
++#endif
++
++ /* If this on_failure_jump comes right before a group (i.e.,
++ the original * applied to a group), save the information
++ for that group and all inner ones, so that if we fail back
++ to this point, the group's information will be correct.
++ For example, in \(a*\)*\1, we need the preceding group,
++ and in \(zz\(a*\)b*\)\2, we need the inner group. */
++
++ /* We can't use `p' to check ahead because we push
++ a failure point to `p + mcnt' after we do this. */
++ p1 = p;
++
++ /* We need to skip no_op's before we look for the
++ start_memory in case this on_failure_jump is happening as
++ the result of a completed succeed_n, as in \(a\)\{1,3\}b\1
++ against aba. */
++ while (p1 < pend && (re_opcode_t) *p1 == no_op)
++ p1++;
++
++ if (p1 < pend && (re_opcode_t) *p1 == start_memory)
++ {
++ /* We have a new highest active register now. This will
++ get reset at the start_memory we are about to get to,
++ but we will have saved all the registers relevant to
++ this repetition op, as described above. */
++ highest_active_reg = *(p1 + 1) + *(p1 + 2);
++ if (lowest_active_reg == NO_LOWEST_ACTIVE_REG)
++ lowest_active_reg = *(p1 + 1);
++ }
++
++ DEBUG_PRINT1 (":\n");
++ PUSH_FAILURE_POINT (p + mcnt, d, -2);
++ break;
++
++
++ /* A smart repeat ends with `maybe_pop_jump'.
++ We change it to either `pop_failure_jump' or `jump'. */
++ case maybe_pop_jump:
++ EXTRACT_NUMBER_AND_INCR (mcnt, p);
++ DEBUG_PRINT2 ("EXECUTING maybe_pop_jump %d.\n", mcnt);
++ {
++ register UCHAR_T *p2 = p;
++
++ /* Compare the beginning of the repeat with what in the
++ pattern follows its end. If we can establish that there
++ is nothing that they would both match, i.e., that we
++ would have to backtrack because of (as in, e.g., `a*a')
++ then we can change to pop_failure_jump, because we'll
++ never have to backtrack.
++
++ This is not true in the case of alternatives: in
++ `(a|ab)*' we do need to backtrack to the `ab' alternative
++ (e.g., if the string was `ab'). But instead of trying to
++ detect that here, the alternative has put on a dummy
++ failure point which is what we will end up popping. */
++
++ /* Skip over open/close-group commands.
++ If what follows this loop is a ...+ construct,
++ look at what begins its body, since we will have to
++ match at least one of that. */
++ while (1)
++ {
++ if (p2 + 2 < pend
++ && ((re_opcode_t) *p2 == stop_memory
++ || (re_opcode_t) *p2 == start_memory))
++ p2 += 3;
++ else if (p2 + 2 + 2 * OFFSET_ADDRESS_SIZE < pend
++ && (re_opcode_t) *p2 == dummy_failure_jump)
++ p2 += 2 + 2 * OFFSET_ADDRESS_SIZE;
++ else
++ break;
++ }
++
++ p1 = p + mcnt;
++ /* p1[0] ... p1[2] are the `on_failure_jump' corresponding
++ to the `maybe_finalize_jump' of this case. Examine what
++ follows. */
++
++ /* If we're at the end of the pattern, we can change. */
++ if (p2 == pend)
++ {
++ /* Consider what happens when matching ":\(.*\)"
++ against ":/". I don't really understand this code
++ yet. */
++ p[-(1+OFFSET_ADDRESS_SIZE)] = (UCHAR_T)
++ pop_failure_jump;
++ DEBUG_PRINT1
++ (" End of pattern: change to `pop_failure_jump'.\n");
++ }
++
++ else if ((re_opcode_t) *p2 == exactn
++#ifdef MBS_SUPPORT
++ || (re_opcode_t) *p2 == exactn_bin
++#endif
++ || (bufp->newline_anchor && (re_opcode_t) *p2 == endline))
++ {
++ register UCHAR_T c
++ = *p2 == (UCHAR_T) endline ? '\n' : p2[2];
++
++ if (((re_opcode_t) p1[1+OFFSET_ADDRESS_SIZE] == exactn
++#ifdef MBS_SUPPORT
++ || (re_opcode_t) p1[1+OFFSET_ADDRESS_SIZE] == exactn_bin
++#endif
++ ) && p1[3+OFFSET_ADDRESS_SIZE] != c)
++ {
++ p[-(1+OFFSET_ADDRESS_SIZE)] = (UCHAR_T)
++ pop_failure_jump;
++#ifdef WCHAR
++ DEBUG_PRINT3 (" %C != %C => pop_failure_jump.\n",
++ (wint_t) c,
++ (wint_t) p1[3+OFFSET_ADDRESS_SIZE]);
++#else
++ DEBUG_PRINT3 (" %c != %c => pop_failure_jump.\n",
++ (char) c,
++ (char) p1[3+OFFSET_ADDRESS_SIZE]);
++#endif
++ }
++
++#ifndef WCHAR
++ else if ((re_opcode_t) p1[3] == charset
++ || (re_opcode_t) p1[3] == charset_not)
++ {
++ int negate = (re_opcode_t) p1[3] == charset_not;
++
++ if (c < (unsigned) (p1[4] * BYTEWIDTH)
++ && p1[5 + c / BYTEWIDTH] & (1 << (c % BYTEWIDTH)))
++ negate = !negate;
++
++ /* `negate' is equal to 1 if c would match, which means
++ that we can't change to pop_failure_jump. */
++ if (!negate)
++ {
++ p[-3] = (unsigned char) pop_failure_jump;
++ DEBUG_PRINT1 (" No match => pop_failure_jump.\n");
++ }
++ }
++#endif /* not WCHAR */
++ }
++#ifndef WCHAR
++ else if ((re_opcode_t) *p2 == charset)
++ {
++ /* We win if the first character of the loop is not part
++ of the charset. */
++ if ((re_opcode_t) p1[3] == exactn
++ && ! ((int) p2[1] * BYTEWIDTH > (int) p1[5]
++ && (p2[2 + p1[5] / BYTEWIDTH]
++ & (1 << (p1[5] % BYTEWIDTH)))))
++ {
++ p[-3] = (unsigned char) pop_failure_jump;
++ DEBUG_PRINT1 (" No match => pop_failure_jump.\n");
++ }
++
++ else if ((re_opcode_t) p1[3] == charset_not)
++ {
++ int idx;
++ /* We win if the charset_not inside the loop
++ lists every character listed in the charset after. */
++ for (idx = 0; idx < (int) p2[1]; idx++)
++ if (! (p2[2 + idx] == 0
++ || (idx < (int) p1[4]
++ && ((p2[2 + idx] & ~ p1[5 + idx]) == 0))))
++ break;
++
++ if (idx == p2[1])
++ {
++ p[-3] = (unsigned char) pop_failure_jump;
++ DEBUG_PRINT1 (" No match => pop_failure_jump.\n");
++ }
++ }
++ else if ((re_opcode_t) p1[3] == charset)
++ {
++ int idx;
++ /* We win if the charset inside the loop
++ has no overlap with the one after the loop. */
++ for (idx = 0;
++ idx < (int) p2[1] && idx < (int) p1[4];
++ idx++)
++ if ((p2[2 + idx] & p1[5 + idx]) != 0)
++ break;
++
++ if (idx == p2[1] || idx == p1[4])
++ {
++ p[-3] = (unsigned char) pop_failure_jump;
++ DEBUG_PRINT1 (" No match => pop_failure_jump.\n");
++ }
++ }
++ }
++#endif /* not WCHAR */
++ }
++ p -= OFFSET_ADDRESS_SIZE; /* Point at relative address again. */
++ if ((re_opcode_t) p[-1] != pop_failure_jump)
++ {
++ p[-1] = (UCHAR_T) jump;
++ DEBUG_PRINT1 (" Match => jump.\n");
++ goto unconditional_jump;
++ }
++ /* Note fall through. */
++
++
++ /* The end of a simple repeat has a pop_failure_jump back to
++ its matching on_failure_jump, where the latter will push a
++ failure point. The pop_failure_jump takes off failure
++ points put on by this pop_failure_jump's matching
++ on_failure_jump; we got through the pattern to here from the
++ matching on_failure_jump, so didn't fail. */
++ case pop_failure_jump:
++ {
++ /* We need to pass separate storage for the lowest and
++ highest registers, even though we don't care about the
++ actual values. Otherwise, we will restore only one
++ register from the stack, since lowest will == highest in
++ `pop_failure_point'. */
++ active_reg_t dummy_low_reg, dummy_high_reg;
++ UCHAR_T *pdummy = NULL;
++ const CHAR_T *sdummy = NULL;
++
++ DEBUG_PRINT1 ("EXECUTING pop_failure_jump.\n");
++ POP_FAILURE_POINT (sdummy, pdummy,
++ dummy_low_reg, dummy_high_reg,
++ reg_dummy, reg_dummy, reg_info_dummy);
++ }
++ /* Note fall through. */
++
++ unconditional_jump:
++#ifdef _LIBC
++ DEBUG_PRINT2 ("\n%p: ", p);
++#else
++ DEBUG_PRINT2 ("\n0x%x: ", p);
++#endif
++ /* Note fall through. */
++
++ /* Unconditionally jump (without popping any failure points). */
++ case jump:
++ EXTRACT_NUMBER_AND_INCR (mcnt, p); /* Get the amount to jump. */
++ DEBUG_PRINT2 ("EXECUTING jump %d ", mcnt);
++ p += mcnt; /* Do the jump. */
++#ifdef _LIBC
++ DEBUG_PRINT2 ("(to %p).\n", p);
++#else
++ DEBUG_PRINT2 ("(to 0x%x).\n", p);
++#endif
++ break;
++
++
++ /* We need this opcode so we can detect where alternatives end
++ in `group_match_null_string_p' et al. */
++ case jump_past_alt:
++ DEBUG_PRINT1 ("EXECUTING jump_past_alt.\n");
++ goto unconditional_jump;
++
++
++ /* Normally, the on_failure_jump pushes a failure point, which
++ then gets popped at pop_failure_jump. We will end up at
++ pop_failure_jump, also, and with a pattern of, say, `a+', we
++ are skipping over the on_failure_jump, so we have to push
++ something meaningless for pop_failure_jump to pop. */
++ case dummy_failure_jump:
++ DEBUG_PRINT1 ("EXECUTING dummy_failure_jump.\n");
++ /* It doesn't matter what we push for the string here. What
++ the code at `fail' tests is the value for the pattern. */
++ PUSH_FAILURE_POINT (NULL, NULL, -2);
++ goto unconditional_jump;
++
++
++ /* At the end of an alternative, we need to push a dummy failure
++ point in case we are followed by a `pop_failure_jump', because
++ we don't want the failure point for the alternative to be
++ popped. For example, matching `(a|ab)*' against `aab'
++ requires that we match the `ab' alternative. */
++ case push_dummy_failure:
++ DEBUG_PRINT1 ("EXECUTING push_dummy_failure.\n");
++ /* See comments just above at `dummy_failure_jump' about the
++ two zeroes. */
++ PUSH_FAILURE_POINT (NULL, NULL, -2);
++ break;
++
++ /* Have to succeed matching what follows at least n times.
++ After that, handle like `on_failure_jump'. */
++ case succeed_n:
++ EXTRACT_NUMBER (mcnt, p + OFFSET_ADDRESS_SIZE);
++ DEBUG_PRINT2 ("EXECUTING succeed_n %d.\n", mcnt);
++
++ assert (mcnt >= 0);
++ /* Originally, this is how many times we HAVE to succeed. */
++ if (mcnt > 0)
++ {
++ mcnt--;
++ p += OFFSET_ADDRESS_SIZE;
++ STORE_NUMBER_AND_INCR (p, mcnt);
++#ifdef _LIBC
++ DEBUG_PRINT3 (" Setting %p to %d.\n", p - OFFSET_ADDRESS_SIZE
++ , mcnt);
++#else
++ DEBUG_PRINT3 (" Setting 0x%x to %d.\n", p - OFFSET_ADDRESS_SIZE
++ , mcnt);
++#endif
++ }
++ else if (mcnt == 0)
++ {
++#ifdef _LIBC
++ DEBUG_PRINT2 (" Setting two bytes from %p to no_op.\n",
++ p + OFFSET_ADDRESS_SIZE);
++#else
++ DEBUG_PRINT2 (" Setting two bytes from 0x%x to no_op.\n",
++ p + OFFSET_ADDRESS_SIZE);
++#endif /* _LIBC */
++
++#ifdef WCHAR
++ p[1] = (UCHAR_T) no_op;
++#else
++ p[2] = (UCHAR_T) no_op;
++ p[3] = (UCHAR_T) no_op;
++#endif /* WCHAR */
++ goto on_failure;
++ }
++ break;
++
++ case jump_n:
++ EXTRACT_NUMBER (mcnt, p + OFFSET_ADDRESS_SIZE);
++ DEBUG_PRINT2 ("EXECUTING jump_n %d.\n", mcnt);
++
++ /* Originally, this is how many times we CAN jump. */
++ if (mcnt)
++ {
++ mcnt--;
++ STORE_NUMBER (p + OFFSET_ADDRESS_SIZE, mcnt);
++
++#ifdef _LIBC
++ DEBUG_PRINT3 (" Setting %p to %d.\n", p + OFFSET_ADDRESS_SIZE,
++ mcnt);
++#else
++ DEBUG_PRINT3 (" Setting 0x%x to %d.\n", p + OFFSET_ADDRESS_SIZE,
++ mcnt);
++#endif /* _LIBC */
++ goto unconditional_jump;
++ }
++ /* If don't have to jump any more, skip over the rest of command. */
++ else
++ p += 2 * OFFSET_ADDRESS_SIZE;
++ break;
++
++ case set_number_at:
++ {
++ DEBUG_PRINT1 ("EXECUTING set_number_at.\n");
++
++ EXTRACT_NUMBER_AND_INCR (mcnt, p);
++ p1 = p + mcnt;
++ EXTRACT_NUMBER_AND_INCR (mcnt, p);
++#ifdef _LIBC
++ DEBUG_PRINT3 (" Setting %p to %d.\n", p1, mcnt);
++#else
++ DEBUG_PRINT3 (" Setting 0x%x to %d.\n", p1, mcnt);
++#endif
++ STORE_NUMBER (p1, mcnt);
++ break;
++ }
++
++#if 0
++ /* The DEC Alpha C compiler 3.x generates incorrect code for the
++ test WORDCHAR_P (d - 1) != WORDCHAR_P (d) in the expansion of
++ AT_WORD_BOUNDARY, so this code is disabled. Expanding the
++ macro and introducing temporary variables works around the bug. */
++
++ case wordbound:
++ DEBUG_PRINT1 ("EXECUTING wordbound.\n");
++ if (AT_WORD_BOUNDARY (d))
++ break;
++ goto fail;
++
++ case notwordbound:
++ DEBUG_PRINT1 ("EXECUTING notwordbound.\n");
++ if (AT_WORD_BOUNDARY (d))
++ goto fail;
++ break;
++#else
++ case wordbound:
++ {
++ boolean prevchar, thischar;
++
++ DEBUG_PRINT1 ("EXECUTING wordbound.\n");
++ if (AT_STRINGS_BEG (d) || AT_STRINGS_END (d))
++ break;
++
++ prevchar = WORDCHAR_P (d - 1);
++ thischar = WORDCHAR_P (d);
++ if (prevchar != thischar)
++ break;
++ goto fail;
++ }
++
++ case notwordbound:
++ {
++ boolean prevchar, thischar;
++
++ DEBUG_PRINT1 ("EXECUTING notwordbound.\n");
++ if (AT_STRINGS_BEG (d) || AT_STRINGS_END (d))
++ goto fail;
++
++ prevchar = WORDCHAR_P (d - 1);
++ thischar = WORDCHAR_P (d);
++ if (prevchar != thischar)
++ goto fail;
++ break;
++ }
++#endif
++
++ case wordbeg:
++ DEBUG_PRINT1 ("EXECUTING wordbeg.\n");
++ if (!AT_STRINGS_END (d) && WORDCHAR_P (d)
++ && (AT_STRINGS_BEG (d) || !WORDCHAR_P (d - 1)))
++ break;
++ goto fail;
++
++ case wordend:
++ DEBUG_PRINT1 ("EXECUTING wordend.\n");
++ if (!AT_STRINGS_BEG (d) && WORDCHAR_P (d - 1)
++ && (AT_STRINGS_END (d) || !WORDCHAR_P (d)))
++ break;
++ goto fail;
++
++#ifdef emacs
++ case before_dot:
++ DEBUG_PRINT1 ("EXECUTING before_dot.\n");
++ if (PTR_CHAR_POS ((unsigned char *) d) >= point)
++ goto fail;
++ break;
++
++ case at_dot:
++ DEBUG_PRINT1 ("EXECUTING at_dot.\n");
++ if (PTR_CHAR_POS ((unsigned char *) d) != point)
++ goto fail;
++ break;
++
++ case after_dot:
++ DEBUG_PRINT1 ("EXECUTING after_dot.\n");
++ if (PTR_CHAR_POS ((unsigned char *) d) <= point)
++ goto fail;
++ break;
++
++ case syntaxspec:
++ DEBUG_PRINT2 ("EXECUTING syntaxspec %d.\n", mcnt);
++ mcnt = *p++;
++ goto matchsyntax;
++
++ case wordchar:
++ DEBUG_PRINT1 ("EXECUTING Emacs wordchar.\n");
++ mcnt = (int) Sword;
++ matchsyntax:
++ PREFETCH ();
++ /* Can't use *d++ here; SYNTAX may be an unsafe macro. */
++ d++;
++ if (SYNTAX (d[-1]) != (enum syntaxcode) mcnt)
++ goto fail;
++ SET_REGS_MATCHED ();
++ break;
++
++ case notsyntaxspec:
++ DEBUG_PRINT2 ("EXECUTING notsyntaxspec %d.\n", mcnt);
++ mcnt = *p++;
++ goto matchnotsyntax;
++
++ case notwordchar:
++ DEBUG_PRINT1 ("EXECUTING Emacs notwordchar.\n");
++ mcnt = (int) Sword;
++ matchnotsyntax:
++ PREFETCH ();
++ /* Can't use *d++ here; SYNTAX may be an unsafe macro. */
++ d++;
++ if (SYNTAX (d[-1]) == (enum syntaxcode) mcnt)
++ goto fail;
++ SET_REGS_MATCHED ();
++ break;
++
++#else /* not emacs */
++ case wordchar:
++ DEBUG_PRINT1 ("EXECUTING non-Emacs wordchar.\n");
++ PREFETCH ();
++ if (!WORDCHAR_P (d))
++ goto fail;
++ SET_REGS_MATCHED ();
++ d++;
++ break;
++
++ case notwordchar:
++ DEBUG_PRINT1 ("EXECUTING non-Emacs notwordchar.\n");
++ PREFETCH ();
++ if (WORDCHAR_P (d))
++ goto fail;
++ SET_REGS_MATCHED ();
++ d++;
++ break;
++#endif /* not emacs */
++
++ default:
++ abort ();
++ }
++ continue; /* Successfully executed one pattern command; keep going. */
++
++
++ /* We goto here if a matching operation fails. */
++ fail:
++ if (!FAIL_STACK_EMPTY ())
++ { /* A restart point is known. Restore to that state. */
++ DEBUG_PRINT1 ("\nFAIL:\n");
++ POP_FAILURE_POINT (d, p,
++ lowest_active_reg, highest_active_reg,
++ regstart, regend, reg_info);
++
++ /* If this failure point is a dummy, try the next one. */
++ if (!p)
++ goto fail;
++
++ /* If we failed to the end of the pattern, don't examine *p. */
++ assert (p <= pend);
++ if (p < pend)
++ {
++ boolean is_a_jump_n = false;
++
++ /* If failed to a backwards jump that's part of a repetition
++ loop, need to pop this failure point and use the next one. */
++ switch ((re_opcode_t) *p)
++ {
++ case jump_n:
++ is_a_jump_n = true;
++ case maybe_pop_jump:
++ case pop_failure_jump:
++ case jump:
++ p1 = p + 1;
++ EXTRACT_NUMBER_AND_INCR (mcnt, p1);
++ p1 += mcnt;
++
++ if ((is_a_jump_n && (re_opcode_t) *p1 == succeed_n)
++ || (!is_a_jump_n
++ && (re_opcode_t) *p1 == on_failure_jump))
++ goto fail;
++ break;
++ default:
++ /* do nothing */ ;
++ }
++ }
++
++ if (d >= string1 && d <= end1)
++ dend = end_match_1;
++ }
++ else
++ break; /* Matching at this starting point really fails. */
++ } /* for (;;) */
++
++ if (best_regs_set)
++ goto restore_best_regs;
++
++ FREE_VARIABLES ();
++
++ return -1; /* Failure to match. */
++} /* re_match_2 */
++
++/* Subroutine definitions for re_match_2. */
++
++
++/* We are passed P pointing to a register number after a start_memory.
++
++ Return true if the pattern up to the corresponding stop_memory can
++ match the empty string, and false otherwise.
++
++ If we find the matching stop_memory, sets P to point to one past its number.
++ Otherwise, sets P to an undefined byte less than or equal to END.
++
++ We don't handle duplicates properly (yet). */
++
++static boolean
++PREFIX(group_match_null_string_p) (UCHAR_T **p, UCHAR_T *end,
++ PREFIX(register_info_type) *reg_info)
++{
++ int mcnt;
++ /* Point to after the args to the start_memory. */
++ UCHAR_T *p1 = *p + 2;
++
++ while (p1 < end)
++ {
++ /* Skip over opcodes that can match nothing, and return true or
++ false, as appropriate, when we get to one that can't, or to the
++ matching stop_memory. */
++
++ switch ((re_opcode_t) *p1)
++ {
++ /* Could be either a loop or a series of alternatives. */
++ case on_failure_jump:
++ p1++;
++ EXTRACT_NUMBER_AND_INCR (mcnt, p1);
++
++ /* If the next operation is not a jump backwards in the
++ pattern. */
++
++ if (mcnt >= 0)
++ {
++ /* Go through the on_failure_jumps of the alternatives,
++ seeing if any of the alternatives cannot match nothing.
++ The last alternative starts with only a jump,
++ whereas the rest start with on_failure_jump and end
++ with a jump, e.g., here is the pattern for `a|b|c':
++
++ /on_failure_jump/0/6/exactn/1/a/jump_past_alt/0/6
++ /on_failure_jump/0/6/exactn/1/b/jump_past_alt/0/3
++ /exactn/1/c
++
++ So, we have to first go through the first (n-1)
++ alternatives and then deal with the last one separately. */
++
++
++ /* Deal with the first (n-1) alternatives, which start
++ with an on_failure_jump (see above) that jumps to right
++ past a jump_past_alt. */
++
++ while ((re_opcode_t) p1[mcnt-(1+OFFSET_ADDRESS_SIZE)] ==
++ jump_past_alt)
++ {
++ /* `mcnt' holds how many bytes long the alternative
++ is, including the ending `jump_past_alt' and
++ its number. */
++
++ if (!PREFIX(alt_match_null_string_p) (p1, p1 + mcnt -
++ (1 + OFFSET_ADDRESS_SIZE),
++ reg_info))
++ return false;
++
++ /* Move to right after this alternative, including the
++ jump_past_alt. */
++ p1 += mcnt;
++
++ /* Break if it's the beginning of an n-th alternative
++ that doesn't begin with an on_failure_jump. */
++ if ((re_opcode_t) *p1 != on_failure_jump)
++ break;
++
++ /* Still have to check that it's not an n-th
++ alternative that starts with an on_failure_jump. */
++ p1++;
++ EXTRACT_NUMBER_AND_INCR (mcnt, p1);
++ if ((re_opcode_t) p1[mcnt-(1+OFFSET_ADDRESS_SIZE)] !=
++ jump_past_alt)
++ {
++ /* Get to the beginning of the n-th alternative. */
++ p1 -= 1 + OFFSET_ADDRESS_SIZE;
++ break;
++ }
++ }
++
++ /* Deal with the last alternative: go back and get number
++ of the `jump_past_alt' just before it. `mcnt' contains
++ the length of the alternative. */
++ EXTRACT_NUMBER (mcnt, p1 - OFFSET_ADDRESS_SIZE);
++
++ if (!PREFIX(alt_match_null_string_p) (p1, p1 + mcnt, reg_info))
++ return false;
++
++ p1 += mcnt; /* Get past the n-th alternative. */
++ } /* if mcnt > 0 */
++ break;
++
++
++ case stop_memory:
++ assert (p1[1] == **p);
++ *p = p1 + 2;
++ return true;
++
++
++ default:
++ if (!PREFIX(common_op_match_null_string_p) (&p1, end, reg_info))
++ return false;
++ }
++ } /* while p1 < end */
++
++ return false;
++} /* group_match_null_string_p */
++
++
++/* Similar to group_match_null_string_p, but doesn't deal with alternatives:
++ It expects P to be the first byte of a single alternative and END one
++ byte past the last. The alternative can contain groups. */
++
++static boolean
++PREFIX(alt_match_null_string_p) (UCHAR_T *p, UCHAR_T *end,
++ PREFIX(register_info_type) *reg_info)
++{
++ int mcnt;
++ UCHAR_T *p1 = p;
++
++ while (p1 < end)
++ {
++ /* Skip over opcodes that can match nothing, and break when we get
++ to one that can't. */
++
++ switch ((re_opcode_t) *p1)
++ {
++ /* It's a loop. */
++ case on_failure_jump:
++ p1++;
++ EXTRACT_NUMBER_AND_INCR (mcnt, p1);
++ p1 += mcnt;
++ break;
++
++ default:
++ if (!PREFIX(common_op_match_null_string_p) (&p1, end, reg_info))
++ return false;
++ }
++ } /* while p1 < end */
++
++ return true;
++} /* alt_match_null_string_p */
++
++
++/* Deals with the ops common to group_match_null_string_p and
++ alt_match_null_string_p.
++
++ Sets P to one after the op and its arguments, if any. */
++
++static boolean
++PREFIX(common_op_match_null_string_p) (UCHAR_T **p, UCHAR_T *end,
++ PREFIX(register_info_type) *reg_info)
++{
++ int mcnt;
++ boolean ret;
++ int reg_no;
++ UCHAR_T *p1 = *p;
++
++ switch ((re_opcode_t) *p1++)
++ {
++ case no_op:
++ case begline:
++ case endline:
++ case begbuf:
++ case endbuf:
++ case wordbeg:
++ case wordend:
++ case wordbound:
++ case notwordbound:
++#ifdef emacs
++ case before_dot:
++ case at_dot:
++ case after_dot:
++#endif
++ break;
++
++ case start_memory:
++ reg_no = *p1;
++ assert (reg_no > 0 && reg_no <= MAX_REGNUM);
++ ret = PREFIX(group_match_null_string_p) (&p1, end, reg_info);
++
++ /* Have to set this here in case we're checking a group which
++ contains a group and a back reference to it. */
++
++ if (REG_MATCH_NULL_STRING_P (reg_info[reg_no]) == MATCH_NULL_UNSET_VALUE)
++ REG_MATCH_NULL_STRING_P (reg_info[reg_no]) = ret;
++
++ if (!ret)
++ return false;
++ break;
++
++ /* If this is an optimized succeed_n for zero times, make the jump. */
++ case jump:
++ EXTRACT_NUMBER_AND_INCR (mcnt, p1);
++ if (mcnt >= 0)
++ p1 += mcnt;
++ else
++ return false;
++ break;
++
++ case succeed_n:
++ /* Get to the number of times to succeed. */
++ p1 += OFFSET_ADDRESS_SIZE;
++ EXTRACT_NUMBER_AND_INCR (mcnt, p1);
++
++ if (mcnt == 0)
++ {
++ p1 -= 2 * OFFSET_ADDRESS_SIZE;
++ EXTRACT_NUMBER_AND_INCR (mcnt, p1);
++ p1 += mcnt;
++ }
++ else
++ return false;
++ break;
++
++ case duplicate:
++ if (!REG_MATCH_NULL_STRING_P (reg_info[*p1]))
++ return false;
++ break;
++
++ case set_number_at:
++ p1 += 2 * OFFSET_ADDRESS_SIZE;
++
++ default:
++ /* All other opcodes mean we cannot match the empty string. */
++ return false;
++ }
++
++ *p = p1;
++ return true;
++} /* common_op_match_null_string_p */
++
++
++/* Return zero if TRANSLATE[S1] and TRANSLATE[S2] are identical for LEN
++ bytes; nonzero otherwise. */
++
++static int
++PREFIX(bcmp_translate) (const CHAR_T *s1, const CHAR_T *s2, register int len,
++ RE_TRANSLATE_TYPE translate)
++{
++ register const UCHAR_T *p1 = (const UCHAR_T *) s1;
++ register const UCHAR_T *p2 = (const UCHAR_T *) s2;
++ while (len)
++ {
++#ifdef WCHAR
++ if (((*p1<=0xff)?translate[*p1++]:*p1++)
++ != ((*p2<=0xff)?translate[*p2++]:*p2++))
++ return 1;
++#else /* BYTE */
++ if (translate[*p1++] != translate[*p2++]) return 1;
++#endif /* WCHAR */
++ len--;
++ }
++ return 0;
++}
++
++
++#else /* not INSIDE_RECURSION */
++
++/* Entry points for GNU code. */
++
++/* re_compile_pattern is the GNU regular expression compiler: it
++ compiles PATTERN (of length SIZE) and puts the result in BUFP.
++ Returns 0 if the pattern was valid, otherwise an error string.
++
++ Assumes the `allocated' (and perhaps `buffer') and `translate' fields
++ are set in BUFP on entry.
++
++ We call regex_compile to do the actual compilation. */
++
++const char *
++re_compile_pattern (const char *pattern, size_t length,
++ struct re_pattern_buffer *bufp)
++{
++ reg_errcode_t ret;
++
++ /* GNU code is written to assume at least RE_NREGS registers will be set
++ (and at least one extra will be -1). */
++ bufp->regs_allocated = REGS_UNALLOCATED;
++
++ /* And GNU code determines whether or not to get register information
++ by passing null for the REGS argument to re_match, etc., not by
++ setting no_sub. */
++ bufp->no_sub = 0;
++
++ /* Match anchors at newline. */
++ bufp->newline_anchor = 1;
++
++# ifdef MBS_SUPPORT
++ if (MB_CUR_MAX != 1)
++ ret = wcs_regex_compile (pattern, length, re_syntax_options, bufp);
++ else
++# endif
++ ret = byte_regex_compile (pattern, length, re_syntax_options, bufp);
++
++ if (!ret)
++ return NULL;
++ return gettext (re_error_msgid[(int) ret]);
++}
++#ifdef _LIBC
++weak_alias (__re_compile_pattern, re_compile_pattern)
++#endif
++
++/* Entry points compatible with 4.2 BSD regex library. We don't define
++ them unless specifically requested. */
++
++#if defined _REGEX_RE_COMP || defined _LIBC
++
++/* BSD has one and only one pattern buffer. */
++static struct re_pattern_buffer re_comp_buf;
++
++char *
++#ifdef _LIBC
++/* Make these definitions weak in libc, so POSIX programs can redefine
++ these names if they don't use our functions, and still use
++ regcomp/regexec below without link errors. */
++weak_function
++#endif
++re_comp (const char *s)
++{
++ reg_errcode_t ret;
++
++ if (!s)
++ {
++ if (!re_comp_buf.buffer)
++ return (char *) gettext ("No previous regular expression");
++ return 0;
++ }
++
++ if (!re_comp_buf.buffer)
++ {
++ re_comp_buf.buffer = (unsigned char *) malloc (200);
++ if (re_comp_buf.buffer == NULL)
++ return (char *) gettext (re_error_msgid[(int) REG_ESPACE]);
++ re_comp_buf.allocated = 200;
++
++ re_comp_buf.fastmap = (char *) malloc (1 << BYTEWIDTH);
++ if (re_comp_buf.fastmap == NULL)
++ return (char *) gettext (re_error_msgid[(int) REG_ESPACE]);
++ }
++
++ /* Since `re_exec' always passes NULL for the `regs' argument, we
++ don't need to initialize the pattern buffer fields which affect it. */
++
++ /* Match anchors at newlines. */
++ re_comp_buf.newline_anchor = 1;
++
++# ifdef MBS_SUPPORT
++ if (MB_CUR_MAX != 1)
++ ret = wcs_regex_compile (s, strlen (s), re_syntax_options, &re_comp_buf);
++ else
++# endif
++ ret = byte_regex_compile (s, strlen (s), re_syntax_options, &re_comp_buf);
++
++ if (!ret)
++ return NULL;
++
++ /* Yes, we're discarding `const' here if !HAVE_LIBINTL. */
++ return (char *) gettext (re_error_msgid[(int) ret]);
++}
++
++
++int
++#ifdef _LIBC
++weak_function
++#endif
++re_exec (const char *s)
++{
++ const int len = strlen (s);
++ return
++ 0 <= re_search (&re_comp_buf, s, len, 0, len, (struct re_registers *) 0);
++}
++
++#endif /* _REGEX_RE_COMP */
++
++/* POSIX.2 functions. Don't define these for Emacs. */
++
++#ifndef emacs
++
++/* regcomp takes a regular expression as a string and compiles it.
++
++ PREG is a regex_t *. We do not expect any fields to be initialized,
++ since POSIX says we shouldn't. Thus, we set
++
++ `buffer' to the compiled pattern;
++ `used' to the length of the compiled pattern;
++ `syntax' to RE_SYNTAX_POSIX_EXTENDED if the
++ REG_EXTENDED bit in CFLAGS is set; otherwise, to
++ RE_SYNTAX_POSIX_BASIC;
++ `newline_anchor' to REG_NEWLINE being set in CFLAGS;
++ `fastmap' to an allocated space for the fastmap;
++ `fastmap_accurate' to zero;
++ `re_nsub' to the number of subexpressions in PATTERN.
++
++ PATTERN is the address of the pattern string.
++
++ CFLAGS is a series of bits which affect compilation.
++
++ If REG_EXTENDED is set, we use POSIX extended syntax; otherwise, we
++ use POSIX basic syntax.
++
++ If REG_NEWLINE is set, then . and [^...] don't match newline.
++ Also, regexec will try a match beginning after every newline.
++
++ If REG_ICASE is set, then we considers upper- and lowercase
++ versions of letters to be equivalent when matching.
++
++ If REG_NOSUB is set, then when PREG is passed to regexec, that
++ routine will report only success or failure, and nothing about the
++ registers.
++
++ It returns 0 if it succeeds, nonzero if it doesn't. (See regex.h for
++ the return codes and their meanings.) */
++
++int
++regcomp (regex_t *preg, const char *pattern, int cflags)
++{
++ reg_errcode_t ret;
++ reg_syntax_t syntax
++ = (cflags & REG_EXTENDED) ?
++ RE_SYNTAX_POSIX_EXTENDED : RE_SYNTAX_POSIX_BASIC;
++
++ /* regex_compile will allocate the space for the compiled pattern. */
++ preg->buffer = 0;
++ preg->allocated = 0;
++ preg->used = 0;
++
++ /* Try to allocate space for the fastmap. */
++ preg->fastmap = (char *) malloc (1 << BYTEWIDTH);
++
++ if (cflags & REG_ICASE)
++ {
++ int i;
++
++ preg->translate
++ = (RE_TRANSLATE_TYPE) malloc (CHAR_SET_SIZE
++ * sizeof (*(RE_TRANSLATE_TYPE)0));
++ if (preg->translate == NULL)
++ return (int) REG_ESPACE;
++
++ /* Map uppercase characters to corresponding lowercase ones. */
++ for (i = 0; i < CHAR_SET_SIZE; i++)
++ preg->translate[i] = ISUPPER (i) ? TOLOWER (i) : i;
++ }
++ else
++ preg->translate = NULL;
++
++ /* If REG_NEWLINE is set, newlines are treated differently. */
++ if (cflags & REG_NEWLINE)
++ { /* REG_NEWLINE implies neither . nor [^...] match newline. */
++ syntax &= ~RE_DOT_NEWLINE;
++ syntax |= RE_HAT_LISTS_NOT_NEWLINE;
++ /* It also changes the matching behavior. */
++ preg->newline_anchor = 1;
++ }
++ else
++ preg->newline_anchor = 0;
++
++ preg->no_sub = !!(cflags & REG_NOSUB);
++
++ /* POSIX says a null character in the pattern terminates it, so we
++ can use strlen here in compiling the pattern. */
++# ifdef MBS_SUPPORT
++ if (MB_CUR_MAX != 1)
++ ret = wcs_regex_compile (pattern, strlen (pattern), syntax, preg);
++ else
++# endif
++ ret = byte_regex_compile (pattern, strlen (pattern), syntax, preg);
++
++ /* POSIX doesn't distinguish between an unmatched open-group and an
++ unmatched close-group: both are REG_EPAREN. */
++ if (ret == REG_ERPAREN) ret = REG_EPAREN;
++
++ if (ret == REG_NOERROR && preg->fastmap)
++ {
++ /* Compute the fastmap now, since regexec cannot modify the pattern
++ buffer. */
++ if (re_compile_fastmap (preg) == -2)
++ {
++ /* Some error occurred while computing the fastmap, just forget
++ about it. */
++ free (preg->fastmap);
++ preg->fastmap = NULL;
++ }
++ }
++
++ return (int) ret;
++}
++#ifdef _LIBC
++weak_alias (__regcomp, regcomp)
++#endif
++
++
++/* regexec searches for a given pattern, specified by PREG, in the
++ string STRING.
++
++ If NMATCH is zero or REG_NOSUB was set in the cflags argument to
++ `regcomp', we ignore PMATCH. Otherwise, we assume PMATCH has at
++ least NMATCH elements, and we set them to the offsets of the
++ corresponding matched substrings.
++
++ EFLAGS specifies `execution flags' which affect matching: if
++ REG_NOTBOL is set, then ^ does not match at the beginning of the
++ string; if REG_NOTEOL is set, then $ does not match at the end.
++
++ We return 0 if we find a match and REG_NOMATCH if not. */
++
++int
++regexec (const regex_t *preg, const char *string, size_t nmatch,
++ regmatch_t pmatch[], int eflags)
++{
++ int ret;
++ struct re_registers regs;
++ regex_t private_preg;
++ int len = strlen (string);
++ boolean want_reg_info = !preg->no_sub && nmatch > 0;
++
++ private_preg = *preg;
++
++ private_preg.not_bol = !!(eflags & REG_NOTBOL);
++ private_preg.not_eol = !!(eflags & REG_NOTEOL);
++
++ /* The user has told us exactly how many registers to return
++ information about, via `nmatch'. We have to pass that on to the
++ matching routines. */
++ private_preg.regs_allocated = REGS_FIXED;
++
++ if (want_reg_info)
++ {
++ regs.num_regs = nmatch;
++ regs.start = TALLOC (nmatch * 2, regoff_t);
++ if (regs.start == NULL)
++ return (int) REG_NOMATCH;
++ regs.end = regs.start + nmatch;
++ }
++
++ /* Perform the searching operation. */
++ ret = re_search (&private_preg, string, len,
++ /* start: */ 0, /* range: */ len,
++ want_reg_info ? ®s : (struct re_registers *) 0);
++
++ /* Copy the register information to the POSIX structure. */
++ if (want_reg_info)
++ {
++ if (ret >= 0)
++ {
++ unsigned r;
++
++ for (r = 0; r < nmatch; r++)
++ {
++ pmatch[r].rm_so = regs.start[r];
++ pmatch[r].rm_eo = regs.end[r];
++ }
++ }
++
++ /* If we needed the temporary register info, free the space now. */
++ free (regs.start);
++ }
++
++ /* We want zero return to mean success, unlike `re_search'. */
++ return ret >= 0 ? (int) REG_NOERROR : (int) REG_NOMATCH;
++}
++#ifdef _LIBC
++/* EGLIBC: This is handled in regexec-compat.c. */
++/*weak_alias (__regexec, regexec)*/
++#include "regexec-compat.c"
++#endif
++
++
++/* Returns a message corresponding to an error code, ERRCODE, returned
++ from either regcomp or regexec. We don't use PREG here. */
++
++size_t
++regerror (int errcode, const regex_t *preg __attribute__ ((unused)),
++ char *errbuf, size_t errbuf_size)
++{
++ const char *msg;
++ size_t msg_size;
++
++ if (errcode < 0
++ || errcode >= (int) (sizeof (re_error_msgid)
++ / sizeof (re_error_msgid[0])))
++ /* Only error codes returned by the rest of the code should be passed
++ to this routine. If we are given anything else, or if other regex
++ code generates an invalid error code, then the program has a bug.
++ Dump core so we can fix it. */
++ abort ();
++
++ msg = gettext (re_error_msgid[errcode]);
++
++ msg_size = strlen (msg) + 1; /* Includes the null. */
++
++ if (errbuf_size != 0)
++ {
++ if (msg_size > errbuf_size)
++ {
++#if defined HAVE_MEMPCPY || defined _LIBC
++ *((char *) mempcpy (errbuf, msg, errbuf_size - 1)) = '\0';
++#else
++ memcpy (errbuf, msg, errbuf_size - 1);
++ errbuf[errbuf_size - 1] = 0;
++#endif
++ }
++ else
++ memcpy (errbuf, msg, msg_size);
++ }
++
++ return msg_size;
++}
++#ifdef _LIBC
++weak_alias (__regerror, regerror)
++#endif
++
++
++/* Free dynamically allocated space used by PREG. */
++
++void
++regfree (regex_t *preg)
++{
++ if (preg->buffer != NULL)
++ free (preg->buffer);
++ preg->buffer = NULL;
++
++ preg->allocated = 0;
++ preg->used = 0;
++
++ if (preg->fastmap != NULL)
++ free (preg->fastmap);
++ preg->fastmap = NULL;
++ preg->fastmap_accurate = 0;
++
++ if (preg->translate != NULL)
++ free (preg->translate);
++ preg->translate = NULL;
++}
++#ifdef _LIBC
++weak_alias (__regfree, regfree)
++#endif
++
++#endif /* not emacs */
++
++#endif /* not INSIDE_RECURSION */
++
++
++#undef STORE_NUMBER
++#undef STORE_NUMBER_AND_INCR
++#undef EXTRACT_NUMBER
++#undef EXTRACT_NUMBER_AND_INCR
++
++#undef DEBUG_PRINT_COMPILED_PATTERN
++#undef DEBUG_PRINT_DOUBLE_STRING
++
++#undef INIT_FAIL_STACK
++#undef RESET_FAIL_STACK
++#undef DOUBLE_FAIL_STACK
++#undef PUSH_PATTERN_OP
++#undef PUSH_FAILURE_POINTER
++#undef PUSH_FAILURE_INT
++#undef PUSH_FAILURE_ELT
++#undef POP_FAILURE_POINTER
++#undef POP_FAILURE_INT
++#undef POP_FAILURE_ELT
++#undef DEBUG_PUSH
++#undef DEBUG_POP
++#undef PUSH_FAILURE_POINT
++#undef POP_FAILURE_POINT
++
++#undef REG_UNSET_VALUE
++#undef REG_UNSET
++
++#undef PATFETCH
++#undef PATFETCH_RAW
++#undef PATUNFETCH
++#undef TRANSLATE
++
++#undef INIT_BUF_SIZE
++#undef GET_BUFFER_SPACE
++#undef BUF_PUSH
++#undef BUF_PUSH_2
++#undef BUF_PUSH_3
++#undef STORE_JUMP
++#undef STORE_JUMP2
++#undef INSERT_JUMP
++#undef INSERT_JUMP2
++#undef EXTEND_BUFFER
++#undef GET_UNSIGNED_NUMBER
++#undef FREE_STACK_RETURN
++
++# undef POINTER_TO_OFFSET
++# undef MATCHING_IN_FRST_STRING
++# undef PREFETCH
++# undef AT_STRINGS_BEG
++# undef AT_STRINGS_END
++# undef WORDCHAR_P
++# undef FREE_VAR
++# undef FREE_VARIABLES
++# undef NO_HIGHEST_ACTIVE_REG
++# undef NO_LOWEST_ACTIVE_REG
++
++# undef CHAR_T
++# undef UCHAR_T
++# undef COMPILED_BUFFER_VAR
++# undef OFFSET_ADDRESS_SIZE
++# undef CHAR_CLASS_SIZE
++# undef PREFIX
++# undef ARG_PREFIX
++# undef PUT_CHAR
++# undef BYTE
++# undef WCHAR
++
++# define DEFINED_ONCE
+Index: git/pwd/Makefile
+===================================================================
+--- git.orig/pwd/Makefile 2014-08-29 20:00:53.316070587 -0700
++++ git/pwd/Makefile 2014-08-29 20:01:15.232070587 -0700
+@@ -18,6 +18,8 @@
+ #
+ # Sub-makefile for pwd portion of the library.
+ #
++include ../option-groups.mak
++
+ subdir := pwd
+
+ include ../Makeconfig
+Index: git/resolv/Makefile
+===================================================================
+--- git.orig/resolv/Makefile 2014-08-29 20:00:53.320070587 -0700
++++ git/resolv/Makefile 2014-08-29 20:01:15.232070587 -0700
+@@ -18,6 +18,8 @@
+ #
+ # Sub-makefile for resolv portion of the library.
+ #
++include ../option-groups.mak
++
+ subdir := resolv
+
+ include ../Makeconfig
+@@ -27,20 +29,21 @@
+ arpa/nameser.h arpa/nameser_compat.h \
+ sys/bitypes.h
+
+-routines := herror inet_addr inet_ntop inet_pton nsap_addr res_init \
+- res_hconf res_libc res-state
++routines-$(OPTION_EGLIBC_INET) \
++ += herror inet_addr inet_ntop inet_pton nsap_addr res_init \
++ res_hconf res_libc res-state
+
+-tests = tst-aton tst-leaks tst-inet_ntop
+-xtests = tst-leaks2
++tests-$(OPTION_EGLIBC_INET) += tst-aton tst-leaks tst-inet_ntop
++xtests-$(OPTION_EGLIBC_INET) += tst-leaks2
+
+ generate := mtrace-tst-leaks.out tst-leaks.mtrace tst-leaks2.mtrace
+
+-extra-libs := libresolv libnss_dns
++extra-libs-$(OPTION_EGLIBC_INET) += libresolv libnss_dns
+ ifeq ($(have-thread-library),yes)
+-extra-libs += libanl
+-routines += gai_sigqueue
++extra-libs-$(OPTION_EGLIBC_INET_ANL) += libanl
++routines-$(OPTION_EGLIBC_INET) += gai_sigqueue
+ endif
+-extra-libs-others = $(extra-libs)
++extra-libs-others-y += $(extra-libs-y)
+ libresolv-routines := gethnamaddr res_comp res_debug \
+ res_data res_mkquery res_query res_send \
+ inet_net_ntop inet_net_pton inet_neta base64 \
+@@ -60,7 +63,7 @@
+ static-only-routines += $(libnss_dns-routines) $(libresolv-routines)
+ endif
+
+-ifeq (yesyes,$(build-shared)$(have-thread-library))
++ifeq (yesyesy,$(build-shared)$(have-thread-library)$(OPTION_EGLIBC_INET_ANL))
+ tests: $(objpfx)ga_test
+ endif
+
+Index: git/stdio-common/fxprintf.c
+===================================================================
+--- git.orig/stdio-common/fxprintf.c 2014-08-29 20:00:53.544070587 -0700
++++ git/stdio-common/fxprintf.c 2014-08-29 20:01:15.232070587 -0700
+@@ -23,6 +23,7 @@
+ #include <wchar.h>
+ #include <string.h>
+ #include <libioP.h>
++#include <gnu/option-groups.h>
+
+
+ int
+@@ -37,6 +38,7 @@
+ int res;
+ if (_IO_fwide (fp, 0) > 0)
+ {
++#if __OPTION_POSIX_WIDE_CHAR_DEVICE_IO
+ size_t len = strlen (fmt) + 1;
+ wchar_t wfmt[len];
+ for (size_t i = 0; i < len; ++i)
+@@ -45,6 +47,9 @@
+ wfmt[i] = fmt[i];
+ }
+ res = __vfwprintf (fp, wfmt, ap);
++#else
++ abort();
++#endif
+ }
+ else
+ res = _IO_vfprintf (fp, fmt, ap);
+Index: git/stdio-common/_i18n_number.h
+===================================================================
+--- git.orig/stdio-common/_i18n_number.h 2014-08-29 20:00:53.500070587 -0700
++++ git/stdio-common/_i18n_number.h 2014-08-29 20:01:15.232070587 -0700
+@@ -19,10 +19,13 @@
+ #include <stdbool.h>
+ #include <wchar.h>
+ #include <wctype.h>
++#include <gnu/option-groups.h>
+
+ #include "../locale/outdigits.h"
+ #include "../locale/outdigitswc.h"
+
++#if __OPTION_EGLIBC_LOCALE_CODE
++
+ static CHAR_T *
+ _i18n_number_rewrite (CHAR_T *w, CHAR_T *rear_ptr, CHAR_T *end)
+ {
+@@ -115,3 +118,13 @@
+
+ return w;
+ }
++
++#else
++
++static CHAR_T *
++_i18n_number_rewrite (CHAR_T *w, CHAR_T *rear_ptr, CHAR_T *end)
++{
++ return w;
++}
++
++#endif
+Index: git/stdio-common/Makefile
+===================================================================
+--- git.orig/stdio-common/Makefile 2014-08-29 20:00:53.500070587 -0700
++++ git/stdio-common/Makefile 2014-08-29 20:01:15.232070587 -0700
+@@ -18,6 +18,8 @@
+ #
+ # Specific makefile for stdio-common.
+ #
++include ../option-groups.mak
++
+ subdir := stdio-common
+
+ include ../Makeconfig
+@@ -30,7 +32,7 @@
+ vfprintf vprintf printf_fp reg-printf printf-prs printf_fphex \
+ reg-modifier reg-type \
+ printf_size fprintf printf snprintf sprintf asprintf dprintf \
+- vfwprintf vfscanf vfwscanf \
++ vfscanf \
+ fscanf scanf sscanf \
+ perror psignal \
+ tmpfile tmpfile64 tmpnam tmpnam_r tempnam tempname \
+@@ -41,23 +43,37 @@
+ isoc99_vsscanf \
+ psiginfo
+
+-aux := errlist siglist printf-parsemb printf-parsewc fxprintf
++# Ideally, _itowa and itowa-digits would be in this option group as
++# well, but it is used unconditionally by printf_fp and printf_fphex,
++# and it didn't seem straightforward to disentangle it.
++routines-$(OPTION_POSIX_C_LANG_WIDE_CHAR) += \
++ vfwprintf vfwscanf
++
++aux := errlist siglist printf-parsemb fxprintf
++aux-$(OPTION_POSIX_C_LANG_WIDE_CHAR) += printf-parsewc
+
+ tests := tstscanf test_rdwr test-popen tstgetln test-fseek \
+ temptest tst-fileno test-fwrite tst-ungetc tst-ferror \
+ xbug errnobug \
+ bug1 bug2 bug3 bug4 bug5 bug6 bug7 bug8 bug9 bug10 bug11 bug12 bug13 \
+- tfformat tiformat tllformat tstdiomisc tst-printfsz tst-wc-printf \
++ tfformat tiformat tllformat tstdiomisc tst-printfsz \
+ scanf1 scanf2 scanf3 scanf4 scanf5 scanf7 scanf8 scanf9 scanf10 \
+- scanf11 scanf12 tst-tmpnam tst-cookie tst-obprintf tst-sscanf \
+- tst-swprintf tst-fseek tst-fmemopen test-vfprintf tst-gets \
+- tst-perror tst-sprintf tst-rndseek tst-fdopen tst-fphex bug14 \
++ scanf11 scanf12 tst-tmpnam tst-cookie tst-obprintf \
++ scanf11 scanf12 tst-tmpnam tst-cookie tst-obprintf \
++ tst-fseek tst-fmemopen tst-gets \
++ tst-sprintf tst-rndseek tst-fdopen tst-fphex \
+ tst-popen tst-unlockedio tst-fmemopen2 tst-put-error tst-fgets \
+- tst-fwrite bug16 bug17 tst-swscanf tst-sprintf2 bug18 bug18a \
+- bug19 bug19a tst-popen2 scanf13 scanf14 scanf15 bug20 bug21 bug22 \
+- scanf16 scanf17 tst-setvbuf1 tst-grouping bug23 bug24 \
+- bug-vfprintf-nargs tst-long-dbl-fphex tst-fphex-wide tst-sprintf3 \
+- bug25 tst-printf-round bug26
++ tst-fwrite bug16 bug17 tst-sprintf2 bug18 \
++ bug19 tst-popen2 scanf14 scanf15 bug21 bug22 scanf16 scanf17 \
++ tst-setvbuf1 bug23 bug24 bug-vfprintf-nargs tst-sprintf3 bug25 \
++ tst-printf-round bug26
++
++tests-$(OPTION_EGLIBC_LOCALE_CODE) \
++ += tst-sscanf tst-swprintf test-vfprintf bug14 scanf13 tst-grouping
++tests-$(OPTION_POSIX_WIDE_CHAR_DEVICE_IO) \
++ += tst-perror bug19a bug20 tst-long-dbl-fphex tst-fphex-wide
++tests-$(OPTION_POSIX_C_LANG_WIDE_CHAR) \
++ += bug18a tst-swscanf tst-wc-printf
+
+ test-srcs = tst-unbputc tst-printf
+
+Index: git/stdio-common/printf_fp.c
+===================================================================
+--- git.orig/stdio-common/printf_fp.c 2014-08-29 20:00:53.548070587 -0700
++++ git/stdio-common/printf_fp.c 2014-08-29 20:01:15.232070587 -0700
+@@ -39,6 +39,7 @@
+ #include <unistd.h>
+ #include <stdlib.h>
+ #include <wchar.h>
++#include <gnu/option-groups.h>
+ #include <stdbool.h>
+ #include <rounding-mode.h>
+
+@@ -148,6 +149,10 @@
+ wchar_t thousands_sep, int ngroups)
+ internal_function;
+
++/* Ideally, when OPTION_EGLIBC_LOCALE_CODE is disabled, this should do
++ all its work in ordinary characters, rather than doing it in wide
++ characters and then converting at the end. But that is a challenge
++ for another day. */
+
+ int
+ ___printf_fp (FILE *fp,
+@@ -206,7 +211,14 @@
+ mp_limb_t cy;
+
+ /* Nonzero if this is output on a wide character stream. */
++#if __OPTION_POSIX_C_LANG_WIDE_CHAR
+ int wide = info->wide;
++#else
++ /* This should never be called on a wide-oriented stream when
++ OPTION_POSIX_C_LANG_WIDE_CHAR is disabled, but the compiler can't
++ be trusted to figure that out. */
++ const int wide = 0;
++#endif
+
+ /* Buffer in which we produce the output. */
+ wchar_t *wbuffer = NULL;
+@@ -258,6 +270,7 @@
+
+
+ /* Figure out the decimal point character. */
++#if __OPTION_EGLIBC_LOCALE_CODE
+ if (info->extra == 0)
+ {
+ decimal = _NL_CURRENT (LC_NUMERIC, DECIMAL_POINT);
+@@ -277,7 +290,13 @@
+ /* The decimal point character must not be zero. */
+ assert (*decimal != '\0');
+ assert (decimalwc != L'\0');
++#else
++ /* Hard-code values from 'C' locale. */
++ decimal = ".";
++ decimalwc = L'.';
++#endif
+
++#if __OPTION_EGLIBC_LOCALE_CODE
+ if (info->group)
+ {
+ if (info->extra == 0)
+@@ -321,6 +340,9 @@
+ }
+ else
+ grouping = NULL;
++#else
++ grouping = NULL;
++#endif
+
+ /* Fetch the argument value. */
+ #ifndef __NO_LONG_DOUBLE_MATH
+Index: git/stdio-common/printf_fphex.c
+===================================================================
+--- git.orig/stdio-common/printf_fphex.c 2014-08-29 20:00:53.548070587 -0700
++++ git/stdio-common/printf_fphex.c 2014-08-29 20:01:15.232070587 -0700
+@@ -28,6 +28,7 @@
+ #include <_itoa.h>
+ #include <_itowa.h>
+ #include <locale/localeinfo.h>
++#include <gnu/option-groups.h>
+ #include <stdbool.h>
+ #include <rounding-mode.h>
+
+@@ -139,10 +140,18 @@
+ int done = 0;
+
+ /* Nonzero if this is output on a wide character stream. */
++#if __OPTION_POSIX_C_LANG_WIDE_CHAR
+ int wide = info->wide;
++#else
++ /* This should never be called on a wide-oriented stream when
++ OPTION_POSIX_C_LANG_WIDE_CHAR is disabled, but the compiler can't
++ be trusted to figure that out. */
++ const int wide = 0;
++#endif
+
+
+ /* Figure out the decimal point character. */
++#if __OPTION_EGLIBC_LOCALE_CODE
+ if (info->extra == 0)
+ {
+ decimal = _NL_CURRENT (LC_NUMERIC, DECIMAL_POINT);
+@@ -156,6 +165,10 @@
+ }
+ /* The decimal point character must never be zero. */
+ assert (*decimal != '\0' && decimalwc != L'\0');
++#else
++ decimal = ".";
++ decimalwc = L'.';
++#endif
+
+
+ /* Fetch the argument value. */
+Index: git/stdio-common/printf_size.c
+===================================================================
+--- git.orig/stdio-common/printf_size.c 2014-08-29 20:00:53.548070587 -0700
++++ git/stdio-common/printf_size.c 2014-08-29 20:01:15.232070587 -0700
+@@ -23,6 +23,7 @@
+ #include <math.h>
+ #include <printf.h>
+ #include <libioP.h>
++#include <gnu/option-groups.h>
+
+
+ /* This defines make it possible to use the same code for GNU C library and
+@@ -116,7 +117,14 @@
+
+ struct printf_info fp_info;
+ int done = 0;
++#if __OPTION_POSIX_C_LANG_WIDE_CHAR
+ int wide = info->wide;
++#else
++ /* This should never be called on a wide-oriented stream when
++ OPTION_POSIX_C_LANG_WIDE_CHAR is disabled, but the compiler can't
++ be trusted to figure that out. */
++ const int wide = 0;
++#endif
+ int res;
+
+ /* Fetch the argument value. */
+Index: git/stdio-common/scanf14.c
+===================================================================
+--- git.orig/stdio-common/scanf14.c 2014-08-29 20:00:53.548070587 -0700
++++ git/stdio-common/scanf14.c 2014-08-29 20:01:15.232070587 -0700
+@@ -2,6 +2,7 @@
+ #include <stdlib.h>
+ #include <string.h>
+ #include <wchar.h>
++#include <gnu/option-groups.h>
+
+ #define FAIL() \
+ do { \
+@@ -36,6 +37,7 @@
+ FAIL ();
+ else if (d != 2.25 || memcmp (c, " x", 2) != 0)
+ FAIL ();
++#if __OPTION_EGLIBC_LOCALE_CODE
+ if (sscanf (" 3.25S x", "%4aS%3c", &lsp, c) != 2)
+ FAIL ();
+ else
+@@ -45,6 +47,7 @@
+ memset (lsp, 'x', sizeof L"3.25");
+ free (lsp);
+ }
++#endif
+ if (sscanf ("4.25[0-9.] x", "%a[0-9.]%8c", &sp, c) != 2)
+ FAIL ();
+ else
+Index: git/stdio-common/tstdiomisc.c
+===================================================================
+--- git.orig/stdio-common/tstdiomisc.c 2014-08-29 20:00:53.584070587 -0700
++++ git/stdio-common/tstdiomisc.c 2014-08-29 20:01:15.232070587 -0700
+@@ -3,6 +3,7 @@
+ #include <stdio.h>
+ #include <string.h>
+ #include <wchar.h>
++#include <gnu/option-groups.h>
+
+ static int
+ t1 (void)
+@@ -125,6 +126,7 @@
+ printf ("expected \"-inf -INF -inf -INF -inf -INF -inf -INF\", got \"%s\"\n",
+ buf);
+
++#if __OPTION_POSIX_C_LANG_WIDE_CHAR
+ swprintf (wbuf, sizeof wbuf / sizeof (wbuf[0]), L"%a %A %e %E %f %F %g %G",
+ qnanval, qnanval, qnanval, qnanval,
+ qnanval, qnanval, qnanval, qnanval);
+@@ -162,6 +164,7 @@
+ result |= wcscmp (wbuf, L"-inf -INF -inf -INF -inf -INF -inf -INF") != 0;
+ printf ("expected L\"-inf -INF -inf -INF -inf -INF -inf -INF\", got L\"%S\"\n",
+ wbuf);
++#endif /* __OPTION_POSIX_C_LANG_WIDE_CHAR */
+
+ lqnanval = NAN;
+
+@@ -206,6 +209,7 @@
+ printf ("expected \"-inf -INF -inf -INF -inf -INF -inf -INF\", got \"%s\"\n",
+ buf);
+
++#if __OPTION_POSIX_C_LANG_WIDE_CHAR
+ swprintf (wbuf, sizeof wbuf / sizeof (wbuf[0]),
+ L"%La %LA %Le %LE %Lf %LF %Lg %LG",
+ lqnanval, lqnanval, lqnanval, lqnanval,
+@@ -250,6 +254,7 @@
+ result |= wcscmp (wbuf, L"-inf -INF -inf -INF -inf -INF -inf -INF") != 0;
+ printf ("expected L\"-inf -INF -inf -INF -inf -INF -inf -INF\", got L\"%S\"\n",
+ wbuf);
++#endif /* __OPTION_POSIX_C_LANG_WIDE_CHAR */
+
+ return result;
+ }
+Index: git/stdio-common/tst-popen.c
+===================================================================
+--- git.orig/stdio-common/tst-popen.c 2014-08-29 20:00:53.576070587 -0700
++++ git/stdio-common/tst-popen.c 2014-08-29 20:01:15.232070587 -0700
+@@ -19,6 +19,7 @@
+ #include <stdio.h>
+ #include <string.h>
+ #include <wchar.h>
++#include <gnu/option-groups.h>
+
+ static int
+ do_test (void)
+@@ -34,12 +35,14 @@
+ return 1;
+ }
+
++#if __OPTION_POSIX_WIDE_CHAR_DEVICE_IO
+ /* POSIX says that pipe streams are byte-oriented. */
+ if (fwide (f, 0) >= 0)
+ {
+ puts ("popen did not return byte-oriented stream");
+ result = 1;
+ }
++#endif
+
+ if (getline (&line, &len, f) != 5)
+ {
+Index: git/stdio-common/tst-sprintf.c
+===================================================================
+--- git.orig/stdio-common/tst-sprintf.c 2014-08-29 20:00:53.580070587 -0700
++++ git/stdio-common/tst-sprintf.c 2014-08-29 20:01:15.236070587 -0700
+@@ -2,6 +2,7 @@
+ #include <stdlib.h>
+ #include <locale.h>
+ #include <string.h>
++#include <gnu/option-groups.h>
+
+
+ int
+@@ -10,12 +11,14 @@
+ char buf[100];
+ int result = 0;
+
++#if __OPTION_POSIX_C_LANG_WIDE_CHAR
+ if (sprintf (buf, "%.0ls", L"foo") != 0
+ || strlen (buf) != 0)
+ {
+ puts ("sprintf (buf, \"%.0ls\", L\"foo\") produced some output");
+ result = 1;
+ }
++#endif /* __OPTION_POSIX_C_LANG_WIDE_CHAR */
+
+ #define SIZE (1024*70000)
+ #define STR(x) #x
+Index: git/stdio-common/vfprintf.c
+===================================================================
+--- git.orig/stdio-common/vfprintf.c 2014-08-29 20:00:53.588070587 -0700
++++ git/stdio-common/vfprintf.c 2014-08-29 20:01:15.236070587 -0700
+@@ -29,6 +29,7 @@
+ #include <_itoa.h>
+ #include <locale/localeinfo.h>
+ #include <stdio.h>
++#include <gnu/option-groups.h>
+
+ /* This code is shared between the standard stdio implementation found
+ in GNU C library and the libio implementation originally found in
+@@ -138,6 +139,18 @@
+ # define EOF WEOF
+ #endif
+
++#if __OPTION_POSIX_C_LANG_WIDE_CHAR
++# define MULTIBYTE_SUPPORT (1)
++#else
++# define MULTIBYTE_SUPPORT (0)
++#endif
++
++#if __OPTION_EGLIBC_LOCALE_CODE
++# define LOCALE_SUPPORT (1)
++#else
++# define LOCALE_SUPPORT (0)
++#endif
++
+ #include "_i18n_number.h"
+
+ /* Include the shared code for parsing the format string. */
+@@ -1123,8 +1136,11 @@
+ # define process_string_arg(fspec) \
+ LABEL (form_character): \
+ /* Character. */ \
+- if (is_long) \
+- goto LABEL (form_wcharacter); \
++ if (is_long) \
++ { \
++ assert (MULTIBYTE_SUPPORT); \
++ goto LABEL (form_wcharacter); \
++ } \
+ --width; /* Account for the character itself. */ \
+ if (!left) \
+ PAD (' '); \
+@@ -1137,6 +1153,7 @@
+ break; \
+ \
+ LABEL (form_wcharacter): \
++ assert (MULTIBYTE_SUPPORT); \
+ { \
+ /* Wide character. */ \
+ char buf[MB_CUR_MAX]; \
+@@ -1203,6 +1220,7 @@
+ } \
+ else \
+ { \
++ assert (MULTIBYTE_SUPPORT); \
+ const wchar_t *s2 = (const wchar_t *) string; \
+ mbstate_t mbstate; \
+ \
+@@ -1403,7 +1421,9 @@
+ LABEL (flag_quote):
+ group = 1;
+
+- if (grouping == (const char *) -1)
++ if (! LOCALE_SUPPORT)
++ grouping = NULL;
++ else if (grouping == (const char *) -1)
+ {
+ #ifdef COMPILE_WPRINTF
+ thousands_sep = _NL_CURRENT_WORD (LC_NUMERIC,
+@@ -1702,7 +1722,9 @@
+ free (workstart);
+ workstart = NULL;
+
+- if (grouping == (const char *) -1)
++ if (! LOCALE_SUPPORT)
++ grouping = NULL;
++ else if (grouping == (const char *) -1)
+ {
+ #ifdef COMPILE_WPRINTF
+ thousands_sep = _NL_CURRENT_WORD (LC_NUMERIC,
+Index: git/stdio-common/vfscanf.c
+===================================================================
+--- git.orig/stdio-common/vfscanf.c 2014-08-29 20:00:53.588070587 -0700
++++ git/stdio-common/vfscanf.c 2014-08-29 20:01:15.236070587 -0700
+@@ -29,6 +29,7 @@
+ #include <wctype.h>
+ #include <bits/libc-lock.h>
+ #include <locale/localeinfo.h>
++#include <gnu/option-groups.h>
+
+ #ifdef __GNUC__
+ # define HAVE_LONGLONG
+@@ -133,6 +134,12 @@
+ # define WINT_T int
+ #endif
+
++#if __OPTION_POSIX_C_LANG_WIDE_CHAR
++# define MULTIBYTE_SUPPORT (1)
++#else
++# define MULTIBYTE_SUPPORT (0)
++#endif
++
+ #define encode_error() do { \
+ errval = 4; \
+ __set_errno (EILSEQ); \
+@@ -316,24 +323,35 @@
+ ARGCHECK (s, format);
+
+ {
+-#ifndef COMPILE_WSCANF
++#if __OPTION_EGLIBC_LOCALE_CODE && !defined (COMPILE_WSCANF)
+ struct __locale_data *const curnumeric = loc->__locales[LC_NUMERIC];
+ #endif
+
++#if __OPTION_EGLIBC_LOCALE_CODE
+ /* Figure out the decimal point character. */
+-#ifdef COMPILE_WSCANF
++# ifdef COMPILE_WSCANF
+ decimal = _NL_CURRENT_WORD (LC_NUMERIC, _NL_NUMERIC_DECIMAL_POINT_WC);
+-#else
++# else
+ decimal = curnumeric->values[_NL_ITEM_INDEX (DECIMAL_POINT)].string;
+-#endif
++# endif
+ /* Figure out the thousands separator character. */
+-#ifdef COMPILE_WSCANF
++# ifdef COMPILE_WSCANF
+ thousands = _NL_CURRENT_WORD (LC_NUMERIC, _NL_NUMERIC_THOUSANDS_SEP_WC);
+-#else
++# else
+ thousands = curnumeric->values[_NL_ITEM_INDEX (THOUSANDS_SEP)].string;
+ if (*thousands == '\0')
+ thousands = NULL;
+-#endif
++# endif
++#else /* if ! __OPTION_EGLIBC_LOCALE_CODE */
++ /* Hard-code values from the C locale. */
++# ifdef COMPILE_WSCANF
++ decimal = L'.';
++ thousands = L'\0';
++# else
++ decimal = ".";
++ thousands = NULL;
++# endif
++#endif /* __OPTION_EGLIBC_LOCALE_CODE */
+ }
+
+ /* Lock the stream. */
+@@ -385,6 +403,8 @@
+ #ifndef COMPILE_WSCANF
+ if (!isascii ((unsigned char) *f))
+ {
++ assert (MULTIBYTE_SUPPORT);
++
+ /* Non-ASCII, may be a multibyte. */
+ int len = __mbrlen (f, strlen (f), &state);
+ if (len > 0)
+@@ -830,6 +850,8 @@
+ }
+ /* FALLTHROUGH */
+ case L_('C'):
++ assert (MULTIBYTE_SUPPORT);
++
+ if (width == -1)
+ width = 1;
+
+@@ -1172,6 +1194,8 @@
+ /* FALLTHROUGH */
+
+ case L_('S'):
++ assert (MULTIBYTE_SUPPORT);
++
+ {
+ #ifndef COMPILE_WSCANF
+ mbstate_t cstate;
+@@ -1419,10 +1443,17 @@
+ const char *mbdigits[10];
+ const char *mbdigits_extended[10];
+ #endif
++#if __OPTION_EGLIBC_LOCALE_CODE
+ /* "to_inpunct" is a map from ASCII digits to their
+ equivalent in locale. This is defined for locales
+ which use an extra digits set. */
+ wctrans_t map = __wctrans ("to_inpunct");
++#else
++ /* This will always be the case when
++ OPTION_EGLIBC_LOCALE_CODE is disabled, but the
++ compiler can't figure that out. */
++ wctrans_t map = NULL;
++#endif
+ int n;
+
+ from_level = 0;
+@@ -2088,6 +2119,7 @@
+ --width;
+ }
+
++#if __OPTION_EGLIBC_LOCALE_CODE
+ wctrans_t map;
+ if (__builtin_expect ((flags & I18N) != 0, 0)
+ /* Hexadecimal floats make no sense, fixing localized
+@@ -2304,6 +2336,7 @@
+ ;
+ #endif
+ }
++#endif /* __OPTION_EGLIBC_LOCALE_CODE */
+
+ /* Have we read any character? If we try to read a number
+ in hexadecimal notation and we have read only the `0x'
+@@ -2343,7 +2376,10 @@
+
+ case L_('['): /* Character class. */
+ if (flags & LONG)
+- STRING_ARG (wstr, wchar_t, 100);
++ {
++ assert (MULTIBYTE_SUPPORT);
++ STRING_ARG (wstr, wchar_t, 100);
++ }
+ else
+ STRING_ARG (str, char, 100);
+
+@@ -2417,6 +2453,7 @@
+ if (flags & LONG)
+ {
+ size_t now = read_in;
++ assert (MULTIBYTE_SUPPORT);
+ #ifdef COMPILE_WSCANF
+ if (__glibc_unlikely (inchar () == WEOF))
+ input_error ();
+Index: git/stdlib/Makefile
+===================================================================
+--- git.orig/stdlib/Makefile 2014-08-29 20:00:53.588070587 -0700
++++ git/stdlib/Makefile 2014-08-29 20:01:15.236070587 -0700
+@@ -18,6 +18,8 @@
+ #
+ # Makefile for stdlib routines
+ #
++include ../option-groups.mak
++
+ subdir := stdlib
+
+ include ../Makeconfig
+@@ -30,7 +32,7 @@
+ alloca.h fmtmsg.h \
+ bits/stdlib-bsearch.h
+
+-routines := \
++routines-y := \
+ atof atoi atol atoll \
+ abort \
+ bsearch qsort msort \
+@@ -39,7 +41,6 @@
+ quick_exit at_quick_exit cxa_at_quick_exit cxa_thread_atexit_impl \
+ abs labs llabs \
+ div ldiv lldiv \
+- mblen mbstowcs mbtowc wcstombs wctomb \
+ random random_r rand rand_r \
+ drand48 erand48 lrand48 nrand48 mrand48 jrand48 \
+ srand48 seed48 lcong48 \
+@@ -52,9 +53,18 @@
+ strtof_l strtod_l strtold_l \
+ system canonicalize \
+ a64l l64a \
+- rpmatch strfmon strfmon_l getsubopt xpg_basename fmtmsg \
+- strtoimax strtoumax wcstoimax wcstoumax \
++ getsubopt xpg_basename \
++ strtoimax strtoumax \
+ getcontext setcontext makecontext swapcontext
++routines-$(OPTION_EGLIBC_LOCALE_CODE) += \
++ strfmon strfmon_l
++routines-$(OPTION_POSIX_C_LANG_WIDE_CHAR) += \
++ mblen mbstowcs mbtowc wcstombs wctomb \
++ wcstoimax wcstoumax
++ifeq (yy,$(OPTION_EGLIBC_LOCALE_CODE)$(OPTION_POSIX_REGEXP))
++routines-y += rpmatch
++endif
++routines-$(OPTION_EGLIBC_FMTMSG) += fmtmsg
+ aux = grouping groupingwc tens_in_limb
+
+ # These routines will be omitted from the libc shared object.
+@@ -62,20 +72,22 @@
+ # linked against when the shared library will be used.
+ static-only-routines = atexit at_quick_exit
+
+-test-srcs := tst-fmtmsg
+-tests := tst-strtol tst-strtod testmb testrand testsort testdiv \
++test-srcs-$(OPTION_EGLIBC_FMTMSG) := tst-fmtmsg
++tests := tst-strtol tst-strtod testrand testsort testdiv \
+ test-canon test-canon2 tst-strtoll tst-environ \
+ tst-xpg-basename tst-random tst-random2 tst-bsearch \
+ tst-limits tst-rand48 bug-strtod tst-setcontext \
+- test-a64l tst-qsort tst-system testmb2 bug-strtod2 \
+- tst-atof1 tst-atof2 tst-strtod2 tst-strtod3 tst-rand48-2 \
+- tst-makecontext tst-strtod4 tst-strtod5 tst-qsort2 \
+- tst-makecontext2 tst-strtod6 tst-unsetenv1 \
+- tst-makecontext3 bug-getcontext bug-fmtmsg1 \
++ test-a64l tst-qsort tst-system bug-strtod2 \
++ tst-atof1 tst-atof2 tst-strtod2 tst-rand48-2 \
++ tst-makecontext tst-qsort2 tst-makecontext2 tst-strtod6 \
++ tst-unsetenv1 tst-makecontext3 bug-getcontext bug-fmtmsg1 \
+ tst-secure-getenv tst-strtod-overflow tst-strtod-round \
+ tst-tininess tst-strtod-underflow tst-tls-atexit
+ tests-static := tst-secure-getenv
+-
++tests-$(OPTION_EGLIBC_LOCALE_CODE) \
++ += tst-strtod3 tst-strtod4 tst-strtod5 testmb2
++tests-$(OPTION_POSIX_C_LANG_WIDE_CHAR) \
++ += testmb
+ modules-names = tst-tls-atexit-lib
+
+ ifeq ($(build-shared),yes)
+@@ -115,8 +127,10 @@
+ tests-special += $(objpfx)isomac.out
+
+ ifeq ($(run-built-tests),yes)
++ifeq (y,$(OPTION_EGLIBC_FMTMSG))
+ tests-special += $(objpfx)tst-fmtmsg.out
+ endif
++endif
+
+ include ../Rules
+
+Index: git/stdlib/strtod_l.c
+===================================================================
+--- git.orig/stdlib/strtod_l.c 2014-08-29 20:00:53.648070587 -0700
++++ git/stdlib/strtod_l.c 2014-08-29 20:01:15.236070587 -0700
+@@ -17,6 +17,7 @@
+ License along with the GNU C Library; if not, see
+ <http://www.gnu.org/licenses/>. */
+
++#include <gnu/option-groups.h>
+ #include <xlocale.h>
+
+ extern double ____strtod_l_internal (const char *, char **, int, __locale_t);
+@@ -548,6 +549,7 @@
+ /* Used in several places. */
+ int cnt;
+
++#if __OPTION_EGLIBC_LOCALE_CODE
+ struct __locale_data *current = loc->__locales[LC_NUMERIC];
+
+ if (__glibc_unlikely (group))
+@@ -586,6 +588,17 @@
+ decimal_len = strlen (decimal);
+ assert (decimal_len > 0);
+ #endif
++#else /* if ! __OPTION_EGLIBC_LOCALE_CODE */
++ /* Hard-code values from the 'C' locale. */
++ grouping = NULL;
++#ifdef USE_WIDE_CHAR
++ decimal = L'.';
++# define decimal_len 1
++#else
++ decimal = ".";
++ decimal_len = 1;
++#endif
++#endif /* __OPTION_EGLIBC_LOCALE_CODE */
+
+ /* Prepare number representation. */
+ exponent = 0;
+Index: git/stdlib/tst-strtod.c
+===================================================================
+--- git.orig/stdlib/tst-strtod.c 2014-08-29 20:00:53.700070587 -0700
++++ git/stdlib/tst-strtod.c 2014-08-29 20:01:15.236070587 -0700
+@@ -23,6 +23,7 @@
+ #include <errno.h>
+ #include <string.h>
+ #include <math.h>
++#include <gnu/option-groups.h>
+
+ struct ltest
+ {
+@@ -176,7 +177,9 @@
+
+ status |= long_dbl ();
+
++#if __OPTION_EGLIBC_LOCALE_CODE
+ status |= locale_test ();
++#endif
+
+ return status ? EXIT_FAILURE : EXIT_SUCCESS;
+ }
+@@ -219,6 +222,7 @@
+ return 0;
+ }
+
++#if __OPTION_EGLIBC_LOCALE_CODE
+ /* Perform a few tests in a locale with thousands separators. */
+ static int
+ locale_test (void)
+@@ -276,3 +280,4 @@
+
+ return result;
+ }
++#endif /* __OPTION_EGLIBC_LOCALE_CODE */
+Index: git/streams/Makefile
+===================================================================
+--- git.orig/streams/Makefile 2014-08-29 20:00:53.712070587 -0700
++++ git/streams/Makefile 2014-08-29 20:01:15.236070587 -0700
+@@ -18,11 +18,14 @@
+ #
+ # Makefile for streams.
+ #
++include ../option-groups.mak
++
+ subdir := streams
+
+ include ../Makeconfig
+
+ headers = stropts.h sys/stropts.h bits/stropts.h bits/xtitypes.h
+-routines = isastream getmsg getpmsg putmsg putpmsg fattach fdetach
++routines-$(OPTION_EGLIBC_STREAMS) \
++ += isastream getmsg getpmsg putmsg putpmsg fattach fdetach
+
+ include ../Rules
+Index: git/string/Makefile
+===================================================================
+--- git.orig/string/Makefile 2014-08-29 20:00:53.716070587 -0700
++++ git/string/Makefile 2014-08-29 20:01:15.236070587 -0700
+@@ -18,6 +18,8 @@
+ #
+ # Sub-makefile for string portion of library.
+ #
++include ../option-groups.mak
++
+ subdir := string
+
+ include ../Makeconfig
+@@ -39,10 +41,12 @@
+ $(addprefix argz-,append count create ctsep next \
+ delete extract insert stringify \
+ addsep replace) \
+- envz basename \
++ basename \
+ strcoll_l strxfrm_l string-inlines memrchr \
+ xpg-strerror strerror_l
+
++routines-$(OPTION_EGLIBC_ENVZ) += envz
++
+ strop-tests := memchr memcmp memcpy memmove mempcpy memset memccpy \
+ stpcpy stpncpy strcat strchr strcmp strcpy strcspn \
+ strlen strncmp strncpy strpbrk strrchr strspn memmem \
+@@ -51,10 +55,12 @@
+ tests := tester inl-tester noinl-tester testcopy test-ffs \
+ tst-strlen stratcliff tst-svc tst-inlcall \
+ bug-strncat1 bug-strspn1 bug-strpbrk1 tst-bswap \
+- tst-strtok tst-strxfrm bug-strcoll1 tst-strfry \
++ tst-strtok tst-strfry \
+ bug-strtok1 $(addprefix test-,$(strop-tests)) \
+- bug-envz1 tst-strxfrm2 tst-endian tst-svc2 \
+- tst-strtok_r
++ tst-strxfrm2 tst-endian tst-svc2 tst-strtok_r
++tests-$(OPTION_EGLIBC_ENVZ) += bug-envz1
++tests-$(OPTION_EGLIBC_LOCALE_CODE) \
++ += tst-strxfrm bug-strcoll1
+
+ xtests = tst-strcoll-overflow
+
+Index: git/string/strcoll_l.c
+===================================================================
+--- git.orig/string/strcoll_l.c 2014-08-29 20:00:53.744070587 -0700
++++ git/string/strcoll_l.c 2014-08-29 20:01:15.240070587 -0700
+@@ -25,6 +25,7 @@
+ #include <stdlib.h>
+ #include <string.h>
+ #include <sys/param.h>
++#include <gnu/option-groups.h>
+
+ #ifndef STRING_TYPE
+ # define STRING_TYPE char
+@@ -472,7 +473,11 @@
+ STRCOLL (const STRING_TYPE *s1, const STRING_TYPE *s2, __locale_t l)
+ {
+ struct __locale_data *current = l->__locales[LC_COLLATE];
++#if __OPTION_EGLIBC_LOCALE_CODE
+ uint_fast32_t nrules = current->values[_NL_ITEM_INDEX (_NL_COLLATE_NRULES)].word;
++#else
++ const uint_fast32_t nrules = 0;
++#endif
+ /* We don't assign the following values right away since it might be
+ unnecessary in case there are no rules. */
+ const unsigned char *rulesets;
+Index: git/string/strerror_l.c
+===================================================================
+--- git.orig/string/strerror_l.c 2014-08-29 20:00:53.744070587 -0700
++++ git/string/strerror_l.c 2014-08-29 20:01:15.240070587 -0700
+@@ -21,6 +21,7 @@
+ #include <stdlib.h>
+ #include <string.h>
+ #include <sys/param.h>
++#include <gnu/option-groups.h>
+
+
+ static __thread char *last_value;
+@@ -29,10 +30,14 @@
+ static const char *
+ translate (const char *str, locale_t loc)
+ {
++#if __OPTION_EGLIBC_LOCALE_CODE
+ locale_t oldloc = __uselocale (loc);
+ const char *res = _(str);
+ __uselocale (oldloc);
+ return res;
++#else
++ return str;
++#endif
+ }
+
+
+Index: git/string/strxfrm_l.c
+===================================================================
+--- git.orig/string/strxfrm_l.c 2014-08-29 20:00:53.748070587 -0700
++++ git/string/strxfrm_l.c 2014-08-29 20:01:15.240070587 -0700
+@@ -24,6 +24,7 @@
+ #include <stdlib.h>
+ #include <string.h>
+ #include <sys/param.h>
++#include <gnu/option-groups.h>
+
+ #ifndef STRING_TYPE
+ # define STRING_TYPE char
+@@ -85,7 +86,11 @@
+ STRXFRM (STRING_TYPE *dest, const STRING_TYPE *src, size_t n, __locale_t l)
+ {
+ struct __locale_data *current = l->__locales[LC_COLLATE];
++#if __OPTION_EGLIBC_LOCALE_CODE
+ uint_fast32_t nrules = current->values[_NL_ITEM_INDEX (_NL_COLLATE_NRULES)].word;
++#else
++ const uint_fast32_t nrules = 0;
++#endif
+ /* We don't assign the following values right away since it might be
+ unnecessary in case there are no rules. */
+ const unsigned char *rulesets;
+Index: git/string/test-strcmp.c
+===================================================================
+--- git.orig/string/test-strcmp.c 2014-08-29 20:00:53.752070587 -0700
++++ git/string/test-strcmp.c 2014-08-29 20:01:15.240070587 -0700
+@@ -329,34 +329,6 @@
+ FOR_EACH_IMPL (impl, 0)
+ check_result (impl, s1 + i1, s2 + i2, exp_result);
+ }
+-
+- /* Test cases where there are multiple zero bytes after the first. */
+-
+- for (size_t i = 0; i < 16 + 1; i++)
+- {
+- s1[i] = 0x00;
+- s2[i] = 0x00;
+- }
+-
+- for (size_t i = 0; i < 16; i++)
+- {
+- int exp_result;
+-
+- for (int val = 0x01; val < 0x100; val++)
+- {
+- for (size_t j = 0; j < i; j++)
+- {
+- s1[j] = val;
+- s2[j] = val;
+- }
+-
+- s2[i] = val;
+-
+- exp_result = SIMPLE_STRCMP (s1, s2);
+- FOR_EACH_IMPL (impl, 0)
+- check_result (impl, s1, s2, exp_result);
+- }
+- }
+ }
+
+
+Index: git/string/tst-strxfrm2.c
+===================================================================
+--- git.orig/string/tst-strxfrm2.c 2014-08-29 20:00:53.756070587 -0700
++++ git/string/tst-strxfrm2.c 2014-08-29 20:01:15.240070587 -0700
+@@ -1,6 +1,7 @@
+ #include <locale.h>
+ #include <stdio.h>
+ #include <string.h>
++#include <gnu/option-groups.h>
+
+ static int
+ do_test (void)
+@@ -38,6 +39,7 @@
+ res = 1;
+ }
+
++#if __OPTION_EGLIBC_LOCALE_CODE
+ if (setlocale (LC_ALL, "de_DE.UTF-8") == NULL)
+ {
+ puts ("setlocale failed");
+@@ -75,6 +77,7 @@
+ res = 1;
+ }
+ }
++#endif
+
+ return res;
+ }
+Index: git/string/tst-strxfrm.c
+===================================================================
+--- git.orig/string/tst-strxfrm.c 2014-08-29 20:00:53.756070587 -0700
++++ git/string/tst-strxfrm.c 2014-08-29 20:01:15.240070587 -0700
+@@ -3,6 +3,7 @@
+ #include <stdio.h>
+ #include <stdlib.h>
+ #include <string.h>
++#include <gnu/option-groups.h>
+
+
+ char const string[] = "";
+@@ -64,8 +65,10 @@
+ int result = 0;
+
+ result |= test ("C");
++#if __OPTION_EGLIBC_LOCALE_CODE
+ result |= test ("en_US.ISO-8859-1");
+ result |= test ("de_DE.UTF-8");
++#endif
+
+ return result;
+ }
+Index: git/sunrpc/Makefile
+===================================================================
+--- git.orig/sunrpc/Makefile 2014-08-29 20:00:53.760070587 -0700
++++ git/sunrpc/Makefile 2014-08-29 20:01:15.240070587 -0700
+@@ -18,6 +18,8 @@
+ #
+ # Sub-makefile for sunrpc portion of the library.
+ #
++include ../option-groups.mak
++
+ subdir := sunrpc
+
+ include ../Makeconfig
+@@ -55,7 +57,6 @@
+ headers-not-in-tirpc = $(addprefix rpc/,key_prot.h rpc_des.h) \
+ $(rpcsvc:%=rpcsvc/%) rpcsvc/bootparam.h
+ headers = rpc/netdb.h
+-install-others = $(inst_sysconfdir)/rpc
+ generated += $(rpcsvc:%.x=rpcsvc/%.h) $(rpcsvc:%.x=x%.c) $(rpcsvc:%.x=x%.stmp) \
+ $(rpcsvc:%.x=rpcsvc/%.stmp) rpcgen
+ generated-dirs += rpcsvc
+@@ -65,18 +66,28 @@
+ endif
+
+ ifeq ($(build-shared),yes)
+-need-export-routines := auth_des auth_unix clnt_gen clnt_perr clnt_tcp \
++need-export-routines-$(OPTION_EGLIBC_SUNRPC) += \
++ auth_des auth_unix clnt_gen clnt_perr clnt_tcp \
+ clnt_udp get_myaddr key_call netname pm_getport \
+- rpc_thread svc svc_tcp svc_udp xcrypt xdr_array xdr \
++ rpc_thread svc svc_tcp svc_udp xdr_array xdr \
+ xdr_intXX_t xdr_mem xdr_ref xdr_sizeof xdr_stdio \
+ svc_run
+
+-routines := auth_none authuxprot bindrsvprt clnt_raw clnt_simp \
++need-export-routines-y += xcrypt
++
++need-export-routines := $(need-export-routines-y)
++
++routines-$(OPTION_EGLIBC_SUNRPC) \
++ += auth_none authuxprot bindrsvprt clnt_raw clnt_simp \
+ rpc_dtable getrpcport pmap_clnt pm_getmaps pmap_prot pmap_prot2 \
+ pmap_rmt rpc_prot rpc_common rpc_cmsg svc_auth svc_authux svc_raw \
+ svc_simple xdr_float xdr_rec publickey authdes_prot \
+- des_crypt des_impl des_soft key_prot openchild rtime svcauth_des \
+- clnt_unix svc_unix create_xid $(need-export-routines)
++ key_prot openchild rtime svcauth_des \
++ clnt_unix svc_unix create_xid
++
++# xdecrypt is also used by nss/nss_files/files-key.c.
++routines-y += des_crypt des_impl des_soft $(need-export-routines)
++
+ ifneq ($(link-obsolete-rpc),yes)
+ # We only add the RPC for compatibility to libc.so.
+ shared-only-routines = $(routines)
+@@ -85,25 +96,28 @@
+
+ # We do not build rpcinfo anymore. It is not needed for a bootstrap
+ # and not wanted on complete systems.
+-# others := rpcinfo
+-# install-sbin := rpcinfo
+-install-bin := rpcgen
++# others-$(OPTION_EGLIBC_SUNRPC) += rpcinfo
++# install-sbin-$(OPTION_EGLIBC_SUNRPC) += rpcinfo
++install-bin-$(OPTION_EGLIBC_SUNRPC) += rpcgen
+ rpcgen-objs = rpc_main.o rpc_hout.o rpc_cout.o rpc_parse.o \
+ rpc_scan.o rpc_util.o rpc_svcout.o rpc_clntout.o \
+ rpc_tblout.o rpc_sample.o
+-extra-objs = $(rpcgen-objs) $(addprefix cross-,$(rpcgen-objs))
+-others += rpcgen
++extra-objs-$(OPTION_EGLIBC_SUNRPC) = $(rpcgen-objs) $(addprefix cross-,$(rpcgen-objs))
++others-$(OPTION_EGLIBC_SUNRPC) += rpcgen
++
++install-others-$(OPTION_EGLIBC_SUNRPC) += $(inst_sysconfdir)/rpc
+
+-tests = tst-xdrmem tst-xdrmem2
+-xtests := tst-getmyaddr
++tests-$(OPTION_EGLIBC_SUNRPC) = tst-xdrmem tst-xdrmem2
++xtests-$(OPTION_EGLIBC_SUNRPC) := tst-getmyaddr
+
+ ifeq ($(have-thread-library),yes)
+-xtests += thrsvc
++xtests-$(OPTION_EGLIBC_SUNRPC) += thrsvc
+ endif
+
+ headers += $(rpcsvc:%.x=rpcsvc/%.h)
+-extra-libs := librpcsvc
+-extra-libs-others := librpcsvc # Make it in `others' pass, not `lib' pass.
++extra-libs-$(OPTION_EGLIBC_SUNRPC) += librpcsvc
++# Make it in `others' pass, not `lib' pass.
++extra-libs-others-y += $(extra-libs-y)
+ librpcsvc-routines = $(rpcsvc:%.x=x%)
+ librpcsvc-inhibit-o = .os # Build no shared rpcsvc library.
+ omit-deps = $(librpcsvc-routines)
+Index: git/sysdeps/generic/ldsodefs.h
+===================================================================
+--- git.orig/sysdeps/generic/ldsodefs.h 2014-08-29 20:00:53.904070587 -0700
++++ git/sysdeps/generic/ldsodefs.h 2014-08-29 20:01:15.240070587 -0700
+@@ -425,6 +425,12 @@
+ # undef __rtld_global_attribute__
+ #endif
+
++#if __OPTION_EGLIBC_RTLD_DEBUG
++# define GLRO_dl_debug_mask GLRO(dl_debug_mask)
++#else
++# define GLRO_dl_debug_mask 0
++#endif
++
+ #ifndef SHARED
+ # define GLRO(name) _##name
+ #else
+@@ -437,8 +443,10 @@
+ {
+ #endif
+
++#if __OPTION_EGLIBC_RTLD_DEBUG
+ /* If nonzero the appropriate debug information is printed. */
+ EXTERN int _dl_debug_mask;
++#endif
+ #define DL_DEBUG_LIBS (1 << 0)
+ #define DL_DEBUG_IMPCALLS (1 << 1)
+ #define DL_DEBUG_BINDINGS (1 << 2)
+Index: git/sysdeps/gnu/Makefile
+===================================================================
+--- git.orig/sysdeps/gnu/Makefile 2014-08-29 20:00:53.924070587 -0700
++++ git/sysdeps/gnu/Makefile 2014-08-29 20:01:15.240070587 -0700
+@@ -57,7 +57,8 @@
+ endif
+
+ ifeq ($(subdir),login)
+-sysdep_routines += setutxent getutxent endutxent getutxid getutxline \
++sysdep_routines-$(OPTION_EGLIBC_UTMPX) \
++ += setutxent getutxent endutxent getutxid getutxline \
+ pututxline utmpxname updwtmpx getutmpx getutmp
+
+ sysdep_headers += utmpx.h bits/utmpx.h
+Index: git/sysdeps/ieee754/ldbl-opt/Makefile
+===================================================================
+--- git.orig/sysdeps/ieee754/ldbl-opt/Makefile 2014-08-29 20:00:54.452070587 -0700
++++ git/sysdeps/ieee754/ldbl-opt/Makefile 2014-08-29 20:01:15.244070587 -0700
+@@ -11,19 +11,18 @@
+ routines += math_ldbl_opt nldbl-compat
+
+ extra-libs += libnldbl
+-libnldbl-calls = asprintf dprintf fprintf fscanf fwprintf fwscanf iovfscanf \
++libnldbl-calls = asprintf dprintf fprintf fscanf iovfscanf \
+ obstack_printf obstack_vprintf printf scanf snprintf \
+- sprintf sscanf swprintf swscanf vasprintf vdprintf vfprintf \
+- vfscanf vfwprintf vfwscanf vprintf vscanf vsnprintf \
+- vsprintf vsscanf vswprintf vswscanf vwprintf vwscanf \
+- wprintf wscanf printf_fp printf_size \
+- fprintf_chk fwprintf_chk printf_chk snprintf_chk sprintf_chk \
+- swprintf_chk vfprintf_chk vfwprintf_chk vprintf_chk \
+- vsnprintf_chk vsprintf_chk vswprintf_chk vwprintf_chk \
+- wprintf_chk asprintf_chk vasprintf_chk dprintf_chk \
++ sprintf sscanf vasprintf vdprintf vfprintf \
++ vfscanf vprintf vscanf vsnprintf \
++ vsprintf vsscanf \
++ printf_fp printf_size \
++ fprintf_chk printf_chk snprintf_chk sprintf_chk \
++ vfprintf_chk vprintf_chk \
++ vsnprintf_chk vsprintf_chk \
++ asprintf_chk vasprintf_chk dprintf_chk \
+ vdprintf_chk obstack_printf_chk obstack_vprintf_chk \
+ syslog syslog_chk vsyslog vsyslog_chk \
+- strfmon strfmon_l \
+ strtold strtold_l strtoldint wcstold wcstold_l wcstoldint \
+ qecvt qfcvt qgcvt qecvt_r qfcvt_r \
+ isinf isnan finite signbit scalb log2 lgamma_r ceil \
+@@ -38,9 +37,15 @@
+ casinh cexp clog cproj csin csinh csqrt ctan ctanh cpow \
+ cabs carg cimag creal clog10 \
+ isoc99_scanf isoc99_fscanf isoc99_sscanf \
+- isoc99_vscanf isoc99_vfscanf isoc99_vsscanf \
++ isoc99_vscanf isoc99_vfscanf isoc99_vsscanf
++libnldbl-calls-$(OPTION_EGLIBC_LOCALE_CODE) += strfmon strfmon_l
++libnldbl-calls-$(OPTION_POSIX_WIDE_CHAR_DEVICE_IO) += fwprintf fwscanf \
++ swprintf swscanf vfwprintf vfwscanf vswprintf vswscanf \
++ vwprintf vwscanf wprintf wscanf fwprintf_chk swprintf_chk \
++ vfwprintf_chk vswprintf_chk vwprintf_chk wprintf_chk \
+ isoc99_wscanf isoc99_fwscanf isoc99_swscanf \
+ isoc99_vwscanf isoc99_vfwscanf isoc99_vswscanf
++libnldbl-calls += $(libnldbl-calls-y)
+ libnldbl-routines = $(libnldbl-calls:%=nldbl-%)
+ libnldbl-inhibit-o = $(object-suffixes)
+ libnldbl-static-only-routines = $(libnldbl-routines)
+Index: git/sysdeps/ieee754/ldbl-opt/nldbl-compat.c
+===================================================================
+--- git.orig/sysdeps/ieee754/ldbl-opt/nldbl-compat.c 2014-08-29 20:00:54.468070587 -0700
++++ git/sysdeps/ieee754/ldbl-opt/nldbl-compat.c 2014-08-29 20:01:15.244070587 -0700
+@@ -26,6 +26,7 @@
+ #include <locale/localeinfo.h>
+ #include <sys/syslog.h>
+ #include <bits/libc-lock.h>
++#include <gnu/option-groups.h>
+
+ #include "nldbl-compat.h"
+
+@@ -33,20 +34,14 @@
+ libc_hidden_proto (__nldbl_vsscanf)
+ libc_hidden_proto (__nldbl_vsprintf)
+ libc_hidden_proto (__nldbl_vfscanf)
+-libc_hidden_proto (__nldbl_vfwscanf)
+ libc_hidden_proto (__nldbl_vdprintf)
+-libc_hidden_proto (__nldbl_vswscanf)
+-libc_hidden_proto (__nldbl_vfwprintf)
+-libc_hidden_proto (__nldbl_vswprintf)
+ libc_hidden_proto (__nldbl_vsnprintf)
+ libc_hidden_proto (__nldbl_vasprintf)
+ libc_hidden_proto (__nldbl_obstack_vprintf)
+-libc_hidden_proto (__nldbl___vfwprintf_chk)
+ libc_hidden_proto (__nldbl___vsnprintf_chk)
+ libc_hidden_proto (__nldbl___vfprintf_chk)
+ libc_hidden_proto (__nldbl___vsyslog_chk)
+ libc_hidden_proto (__nldbl___vsprintf_chk)
+-libc_hidden_proto (__nldbl___vswprintf_chk)
+ libc_hidden_proto (__nldbl___vasprintf_chk)
+ libc_hidden_proto (__nldbl___vdprintf_chk)
+ libc_hidden_proto (__nldbl___obstack_vprintf_chk)
+@@ -54,8 +49,17 @@
+ libc_hidden_proto (__nldbl___vstrfmon_l)
+ libc_hidden_proto (__nldbl___isoc99_vsscanf)
+ libc_hidden_proto (__nldbl___isoc99_vfscanf)
++
++#if __OPTION_POSIX_WIDE_CHAR_DEVICE_IO
++libc_hidden_proto (__nldbl_vfwscanf)
++libc_hidden_proto (__nldbl_vswscanf)
++libc_hidden_proto (__nldbl_vfwprintf)
++libc_hidden_proto (__nldbl_vswprintf)
++libc_hidden_proto (__nldbl___vfwprintf_chk)
++libc_hidden_proto (__nldbl___vswprintf_chk)
+ libc_hidden_proto (__nldbl___isoc99_vswscanf)
+ libc_hidden_proto (__nldbl___isoc99_vfwscanf)
++#endif
+
+ static void
+ __nldbl_cleanup (void *arg)
+@@ -117,6 +121,7 @@
+ }
+ weak_alias (__nldbl_fprintf, __nldbl__IO_fprintf)
+
++#if __OPTION_POSIX_WIDE_CHAR_DEVICE_IO
+ int
+ attribute_compat_text_section weak_function
+ __nldbl_fwprintf (FILE *stream, const wchar_t *fmt, ...)
+@@ -130,6 +135,7 @@
+
+ return done;
+ }
++#endif
+
+ int
+ attribute_compat_text_section
+@@ -226,6 +232,7 @@
+ return done;
+ }
+
++#if __OPTION_POSIX_WIDE_CHAR_DEVICE_IO
+ int
+ attribute_compat_text_section
+ __nldbl_swprintf (wchar_t *s, size_t n, const wchar_t *fmt, ...)
+@@ -239,6 +246,7 @@
+
+ return done;
+ }
++#endif
+
+ int
+ attribute_compat_text_section weak_function
+@@ -264,6 +272,7 @@
+ }
+ libc_hidden_def (__nldbl_vdprintf)
+
++#if __OPTION_POSIX_WIDE_CHAR_DEVICE_IO
+ int
+ attribute_compat_text_section weak_function
+ __nldbl_vfwprintf (FILE *s, const wchar_t *fmt, va_list ap)
+@@ -275,6 +284,7 @@
+ return res;
+ }
+ libc_hidden_def (__nldbl_vfwprintf)
++#endif
+
+ int
+ attribute_compat_text_section
+@@ -297,6 +307,7 @@
+ libc_hidden_def (__nldbl_vsnprintf)
+ weak_alias (__nldbl_vsnprintf, __nldbl___vsnprintf)
+
++#if __OPTION_POSIX_WIDE_CHAR_DEVICE_IO
+ int
+ attribute_compat_text_section weak_function
+ __nldbl_vswprintf (wchar_t *string, size_t maxlen, const wchar_t *fmt,
+@@ -330,6 +341,7 @@
+
+ return done;
+ }
++#endif
+
+ int
+ attribute_compat_text_section
+@@ -419,6 +431,7 @@
+ return done;
+ }
+
++#if __OPTION_POSIX_WIDE_CHAR_DEVICE_IO
+ int
+ attribute_compat_text_section
+ __nldbl_vfwscanf (FILE *s, const wchar_t *fmt, va_list ap)
+@@ -491,6 +504,7 @@
+
+ return done;
+ }
++#endif
+
+ int
+ attribute_compat_text_section
+@@ -506,6 +520,7 @@
+ return done;
+ }
+
++#if __OPTION_POSIX_WIDE_CHAR_DEVICE_IO
+ int
+ attribute_compat_text_section
+ __nldbl___fwprintf_chk (FILE *stream, int flag, const wchar_t *fmt, ...)
+@@ -519,6 +534,7 @@
+
+ return done;
+ }
++#endif
+
+ int
+ attribute_compat_text_section
+@@ -563,6 +579,7 @@
+ return done;
+ }
+
++#if __OPTION_POSIX_WIDE_CHAR_DEVICE_IO
+ int
+ attribute_compat_text_section
+ __nldbl___swprintf_chk (wchar_t *s, size_t n, int flag, size_t slen,
+@@ -577,6 +594,7 @@
+
+ return done;
+ }
++#endif
+
+ int
+ attribute_compat_text_section
+@@ -590,6 +608,7 @@
+ }
+ libc_hidden_def (__nldbl___vfprintf_chk)
+
++#if __OPTION_POSIX_WIDE_CHAR_DEVICE_IO
+ int
+ attribute_compat_text_section
+ __nldbl___vfwprintf_chk (FILE *s, int flag, const wchar_t *fmt, va_list ap)
+@@ -601,6 +620,7 @@
+ return res;
+ }
+ libc_hidden_def (__nldbl___vfwprintf_chk)
++#endif
+
+ int
+ attribute_compat_text_section
+@@ -635,6 +655,7 @@
+ }
+ libc_hidden_def (__nldbl___vsprintf_chk)
+
++#if __OPTION_POSIX_WIDE_CHAR_DEVICE_IO
+ int
+ attribute_compat_text_section
+ __nldbl___vswprintf_chk (wchar_t *string, size_t maxlen, int flag, size_t slen,
+@@ -668,6 +689,7 @@
+
+ return done;
+ }
++#endif
+
+ int
+ attribute_compat_text_section
+@@ -775,6 +797,7 @@
+ return ___printf_fp (fp, &info_no_ldbl, args);
+ }
+
++#if __OPTION_EGLIBC_LOCALE_CODE
+ ssize_t
+ attribute_compat_text_section
+ __nldbl_strfmon (char *s, size_t maxsize, const char *format, ...)
+@@ -829,6 +852,7 @@
+ return res;
+ }
+ libc_hidden_def (__nldbl___vstrfmon_l)
++#endif
+
+ void
+ attribute_compat_text_section
+@@ -941,6 +965,7 @@
+ return done;
+ }
+
++#if __OPTION_POSIX_WIDE_CHAR_DEVICE_IO
+ int
+ attribute_compat_text_section
+ __nldbl___isoc99_vfwscanf (FILE *s, const wchar_t *fmt, va_list ap)
+@@ -1014,6 +1039,7 @@
+
+ return done;
+ }
++#endif
+
+ #if LONG_DOUBLE_COMPAT(libc, GLIBC_2_0)
+ compat_symbol (libc, __nldbl__IO_printf, _IO_printf, GLIBC_2_0);
+@@ -1057,6 +1083,7 @@
+ compat_symbol (libc, __nldbl___strfmon_l, __strfmon_l, GLIBC_2_1);
+ #endif
+ #if LONG_DOUBLE_COMPAT(libc, GLIBC_2_2)
++# if __OPTION_POSIX_WIDE_CHAR_DEVICE_IO
+ compat_symbol (libc, __nldbl_swprintf, swprintf, GLIBC_2_2);
+ compat_symbol (libc, __nldbl_vwprintf, vwprintf, GLIBC_2_2);
+ compat_symbol (libc, __nldbl_wprintf, wprintf, GLIBC_2_2);
+@@ -1069,6 +1096,7 @@
+ compat_symbol (libc, __nldbl_vswscanf, vswscanf, GLIBC_2_2);
+ compat_symbol (libc, __nldbl_vwscanf, vwscanf, GLIBC_2_2);
+ compat_symbol (libc, __nldbl_wscanf, wscanf, GLIBC_2_2);
++# endif
+ #endif
+ #if LONG_DOUBLE_COMPAT(libc, GLIBC_2_3)
+ compat_symbol (libc, __nldbl_strfmon_l, strfmon_l, GLIBC_2_3);
+Index: git/sysdeps/ieee754/ldbl-opt/nldbl-compat.h
+===================================================================
+--- git.orig/sysdeps/ieee754/ldbl-opt/nldbl-compat.h 2014-08-29 20:00:54.468070587 -0700
++++ git/sysdeps/ieee754/ldbl-opt/nldbl-compat.h 2014-08-29 20:01:15.244070587 -0700
+@@ -30,6 +30,7 @@
+ #include <math.h>
+ #include <monetary.h>
+ #include <sys/syslog.h>
++#include <gnu/option-groups.h>
+
+
+ /* Declare the __nldbl_NAME function the wrappers call that's in libc.so. */
+@@ -37,19 +38,15 @@
+
+ NLDBL_DECL (_IO_vfscanf);
+ NLDBL_DECL (vfscanf);
+-NLDBL_DECL (vfwscanf);
+ NLDBL_DECL (obstack_vprintf);
+ NLDBL_DECL (vasprintf);
+ NLDBL_DECL (dprintf);
+ NLDBL_DECL (vdprintf);
+ NLDBL_DECL (fprintf);
+ NLDBL_DECL (vfprintf);
+-NLDBL_DECL (vfwprintf);
+ NLDBL_DECL (vsnprintf);
+ NLDBL_DECL (vsprintf);
+ NLDBL_DECL (vsscanf);
+-NLDBL_DECL (vswprintf);
+-NLDBL_DECL (vswscanf);
+ NLDBL_DECL (__asprintf);
+ NLDBL_DECL (asprintf);
+ NLDBL_DECL (__printf_fp);
+@@ -66,12 +63,18 @@
+ NLDBL_DECL (__isoc99_vscanf);
+ NLDBL_DECL (__isoc99_vfscanf);
+ NLDBL_DECL (__isoc99_vsscanf);
++#if __OPTION_POSIX_WIDE_CHAR_DEVICE_IO
++NLDBL_DECL (vfwscanf);
++NLDBL_DECL (vfwprintf);
++NLDBL_DECL (vswprintf);
++NLDBL_DECL (vswscanf);
+ NLDBL_DECL (__isoc99_wscanf);
+ NLDBL_DECL (__isoc99_fwscanf);
+ NLDBL_DECL (__isoc99_swscanf);
+ NLDBL_DECL (__isoc99_vwscanf);
+ NLDBL_DECL (__isoc99_vfwscanf);
+ NLDBL_DECL (__isoc99_vswscanf);
++#endif
+
+ /* This one does not exist in the normal interface, only
+ __nldbl___vstrfmon really exists. */
+@@ -82,22 +85,23 @@
+ since we don't compile with _FORTIFY_SOURCE. */
+ extern int __nldbl___vfprintf_chk (FILE *__restrict, int,
+ const char *__restrict, _G_va_list);
+-extern int __nldbl___vfwprintf_chk (FILE *__restrict, int,
+- const wchar_t *__restrict, __gnuc_va_list);
+ extern int __nldbl___vsprintf_chk (char *__restrict, int, size_t,
+ const char *__restrict, _G_va_list) __THROW;
+ extern int __nldbl___vsnprintf_chk (char *__restrict, size_t, int, size_t,
+ const char *__restrict, _G_va_list)
+ __THROW;
+-extern int __nldbl___vswprintf_chk (wchar_t *__restrict, size_t, int, size_t,
+- const wchar_t *__restrict, __gnuc_va_list)
+- __THROW;
+ extern int __nldbl___vasprintf_chk (char **, int, const char *, _G_va_list)
+ __THROW;
+ extern int __nldbl___vdprintf_chk (int, int, const char *, _G_va_list);
+ extern int __nldbl___obstack_vprintf_chk (struct obstack *, int, const char *,
+ _G_va_list) __THROW;
+ extern void __nldbl___vsyslog_chk (int, int, const char *, va_list);
+-
++#if __OPTION_POSIX_WIDE_CHAR_DEVICE_IO
++extern int __nldbl___vfwprintf_chk (FILE *__restrict, int,
++ const wchar_t *__restrict, __gnuc_va_list);
++extern int __nldbl___vswprintf_chk (wchar_t *__restrict, size_t, int, size_t,
++ const wchar_t *__restrict, __gnuc_va_list)
++ __THROW;
++#endif
+
+ #endif /* __NLDBL_COMPAT_H */
+Index: git/sysdeps/unix/sysv/linux/gethostid.c
+===================================================================
+--- git.orig/sysdeps/unix/sysv/linux/gethostid.c 2014-08-29 20:00:58.840070587 -0700
++++ git/sysdeps/unix/sysv/linux/gethostid.c 2014-08-29 20:01:15.244070587 -0700
+@@ -21,6 +21,7 @@
+ #include <unistd.h>
+ #include <netdb.h>
+ #include <not-cancel.h>
++#include <gnu/option-groups.h>
+
+ #define HOSTIDFILE "/etc/hostid"
+
+@@ -89,6 +90,7 @@
+ return id;
+ }
+
++#if __OPTION_EGLIBC_INET
+ /* Getting from the file was not successful. An intelligent guess for
+ a unique number of a host is its IP address. Return this. */
+ if (__gethostname (hostname, MAXHOSTNAMELEN) < 0 || hostname[0] == '\0')
+@@ -115,5 +117,9 @@
+ /* For the return value to be not exactly the IP address we do some
+ bit fiddling. */
+ return (int32_t) (in.s_addr << 16 | in.s_addr >> 16);
++#else
++ /* Return an arbitrary value. */
++ return 0;
++#endif
+ }
+ #endif
+Index: git/sysdeps/unix/sysv/linux/libc_fatal.c
+===================================================================
+--- git.orig/sysdeps/unix/sysv/linux/libc_fatal.c 2014-08-29 20:00:58.980070587 -0700
++++ git/sysdeps/unix/sysv/linux/libc_fatal.c 2014-08-29 20:01:15.244070587 -0700
+@@ -23,6 +23,7 @@
+ #include <string.h>
+ #include <sys/mman.h>
+ #include <sys/uio.h>
++#include <gnu/option-groups.h>
+
+ static bool
+ writev_for_fatal (int fd, const struct iovec *iov, size_t niov, size_t total)
+@@ -40,6 +41,7 @@
+ static void
+ backtrace_and_maps (int do_abort, bool written, int fd)
+ {
++#if __OPTION_EGLIBC_BACKTRACE
+ if (do_abort > 1 && written)
+ {
+ void *addrs[64];
+@@ -62,6 +64,7 @@
+ close_not_cancel_no_status (fd2);
+ }
+ }
++#endif /* __OPTION_EGLIBC_BACKTRACE */
+ }
+ #define BEFORE_ABORT backtrace_and_maps
+
+Index: git/time/Makefile
+===================================================================
+--- git.orig/time/Makefile 2014-08-29 20:00:59.504070587 -0700
++++ git/time/Makefile 2014-08-29 20:01:15.244070587 -0700
+@@ -18,6 +18,8 @@
+ #
+ # Makefile for time routines
+ #
++include ../option-groups.mak
++
+ subdir := time
+
+ include ../Makeconfig
+@@ -30,14 +32,20 @@
+ tzfile getitimer setitimer \
+ stime dysize timegm ftime \
+ getdate strptime strptime_l \
+- strftime wcsftime strftime_l wcsftime_l \
++ strftime strftime_l \
+ timespec_get
+-aux := era alt_digit lc-time-cleanup
++routines-$(OPTION_POSIX_C_LANG_WIDE_CHAR) \
++ := wcsftime wcsftime_l
++aux-$(OPTION_EGLIBC_LOCALE_CODE) += alt_digit era lc-time-cleanup
+
+-tests := test_time clocktest tst-posixtz tst-strptime tst_wcsftime \
+- tst-getdate tst-mktime tst-mktime2 tst-ftime_l tst-strftime \
++tests := test_time clocktest tst-posixtz \
++ tst-getdate tst-mktime tst-mktime2 tst-strftime \
+ tst-mktime3 tst-strptime2 bug-asctime bug-asctime_r bug-mktime1 \
+ tst-strptime3 bug-getdate1 tst-strptime-whitespace
++tests-$(OPTION_EGLIBC_LOCALE_CODE) \
++ += tst-strptime tst-ftime_l
++tests-$(OPTION_POSIX_WIDE_CHAR_DEVICE_IO) \
++ += tst_wcsftime
+
+ include ../Rules
+
+Index: git/time/strftime_l.c
+===================================================================
+--- git.orig/time/strftime_l.c 2014-08-29 20:00:59.528070587 -0700
++++ git/time/strftime_l.c 2014-08-29 20:01:15.244070587 -0700
+@@ -35,6 +35,10 @@
+ # include "../locale/localeinfo.h"
+ #endif
+
++#ifdef _LIBC
++# include <gnu/option-groups.h>
++#endif
++
+ #if defined emacs && !defined HAVE_BCOPY
+ # define HAVE_MEMCPY 1
+ #endif
+@@ -882,7 +886,7 @@
+ case L_('C'):
+ if (modifier == L_('E'))
+ {
+-#if HAVE_STRUCT_ERA_ENTRY
++#if (! _LIBC || __OPTION_EGLIBC_LOCALE_CODE) && HAVE_STRUCT_ERA_ENTRY
+ struct era_entry *era = _nl_get_era_entry (tp HELPER_LOCALE_ARG);
+ if (era)
+ {
+@@ -955,7 +959,7 @@
+
+ if (modifier == L_('O') && 0 <= number_value)
+ {
+-#ifdef _NL_CURRENT
++#if (! _LIBC || __OPTION_EGLIBC_LOCALE_CODE) && defined (_NL_CURRENT)
+ /* Get the locale specific alternate representation of
+ the number NUMBER_VALUE. If none exist NULL is returned. */
+ const CHAR_T *cp = nl_get_alt_digit (number_value
+@@ -1260,7 +1264,7 @@
+ case L_('Y'):
+ if (modifier == 'E')
+ {
+-#if HAVE_STRUCT_ERA_ENTRY
++#if (! _LIBC || __OPTION_EGLIBC_LOCALE_CODE) && HAVE_STRUCT_ERA_ENTRY
+ struct era_entry *era = _nl_get_era_entry (tp HELPER_LOCALE_ARG);
+ if (era)
+ {
+@@ -1285,7 +1289,7 @@
+ case L_('y'):
+ if (modifier == L_('E'))
+ {
+-#if HAVE_STRUCT_ERA_ENTRY
++#if (! _LIBC || __OPTION_EGLIBC_LOCALE_CODE) && HAVE_STRUCT_ERA_ENTRY
+ struct era_entry *era = _nl_get_era_entry (tp HELPER_LOCALE_ARG);
+ if (era)
+ {
+Index: git/time/strptime_l.c
+===================================================================
+--- git.orig/time/strptime_l.c 2014-08-29 20:00:59.528070587 -0700
++++ git/time/strptime_l.c 2014-08-29 20:01:15.244070587 -0700
+@@ -29,6 +29,7 @@
+
+ #ifdef _LIBC
+ # define HAVE_LOCALTIME_R 0
++# include <gnu/option-groups.h>
+ # include "../locale/localeinfo.h"
+ #endif
+
+@@ -84,7 +85,7 @@
+ if (val < from || val > to) \
+ return NULL; \
+ } while (0)
+-#ifdef _NL_CURRENT
++#if (! _LIBC || __OPTION_EGLIBC_LOCALE_CODE) && defined (_NL_CURRENT)
+ # define get_alt_number(from, to, n) \
+ ({ \
+ __label__ do_normal; \
+@@ -820,6 +821,7 @@
+ s.want_xday = 1;
+ break;
+ case 'C':
++#if ! _LIBC || __OPTION_EGLIBC_LOCALE_CODE
+ if (s.decided != raw)
+ {
+ if (s.era_cnt >= 0)
+@@ -856,10 +858,12 @@
+
+ s.decided = raw;
+ }
++#endif
+ /* The C locale has no era information, so use the
+ normal representation. */
+ goto match_century;
+ case 'y':
++#if ! _LIBC || __OPTION_EGLIBC_LOCALE_CODE
+ if (s.decided != raw)
+ {
+ get_number(0, 9999, 4);
+@@ -918,9 +922,10 @@
+
+ s.decided = raw;
+ }
+-
++#endif
+ goto match_year_in_century;
+ case 'Y':
++#if ! _LIBC || __OPTION_EGLIBC_LOCALE_CODE
+ if (s.decided != raw)
+ {
+ num_eras = _NL_CURRENT_WORD (LC_TIME,
+@@ -948,6 +953,7 @@
+
+ s.decided = raw;
+ }
++#endif
+ get_number (0, 9999, 4);
+ tm->tm_year = val - 1900;
+ s.want_century = 0;
+@@ -1118,6 +1124,7 @@
+ tm->tm_year = (s.century - 19) * 100;
+ }
+
++#if ! _LIBC || __OPTION_EGLIBC_LOCALE_CODE
+ if (s.era_cnt != -1)
+ {
+ era = _nl_select_era_entry (s.era_cnt HELPER_LOCALE_ARG);
+@@ -1132,6 +1139,7 @@
+ tm->tm_year = era->start_date[0];
+ }
+ else
++#endif
+ if (s.want_era)
+ {
+ /* No era found but we have seen an E modifier. Rectify some
+Index: git/timezone/Makefile
+===================================================================
+--- git.orig/timezone/Makefile 2014-08-29 20:01:14.044070587 -0700
++++ git/timezone/Makefile 2014-08-29 20:01:15.244070587 -0700
+@@ -115,7 +115,7 @@
+
+ $(objpfx)tzselect: tzselect.ksh $(common-objpfx)config.make
+ sed -e 's|/bin/bash|/bin/sh|' \
+- -e 's|TZDIR=[^}]*|TZDIR=$(zonedir)|' \
++ -e '/TZDIR=/s|\$$(pwd)|$(zonedir)|' \
+ -e '/TZVERSION=/s|see_Makefile|"$(version)"|' \
+ -e '/PKGVERSION=/s|=.*|="$(PKGVERSION)"|' \
+ -e '/REPORT_BUGS_TO=/s|=.*|="$(REPORT_BUGS_TO)"|' \
+Index: git/wcsmbs/Makefile
+===================================================================
+--- git.orig/wcsmbs/Makefile 2014-08-29 20:00:59.548070587 -0700
++++ git/wcsmbs/Makefile 2014-08-29 20:01:15.244070587 -0700
+@@ -18,15 +18,21 @@
+ #
+ # Sub-makefile for wcsmbs portion of the library.
+ #
++include ../option-groups.mak
++
+ subdir := wcsmbs
+
+ include ../Makeconfig
+
+ headers := wchar.h bits/wchar.h bits/wchar2.h bits/wchar-ldbl.h uchar.h
+
+-routines := wcscat wcschr wcscmp wcscpy wcscspn wcsdup wcslen wcsncat \
++# These functions are used by printf_fp.c, even in the plain case; see
++# comments there for OPTION_EGLIBC_LOCALE_CODE.
++routines := wmemcpy wmemset
++routines-$(OPTION_POSIX_C_LANG_WIDE_CHAR) \
++ := wcscat wcschr wcscmp wcscpy wcscspn wcsdup wcslen wcsncat \
+ wcsncmp wcsncpy wcspbrk wcsrchr wcsspn wcstok wcsstr wmemchr \
+- wmemcmp wmemcpy wmemmove wmemset wcpcpy wcpncpy wmempcpy \
++ wmemcmp wmemmove wcpcpy wcpncpy wmempcpy \
+ btowc wctob mbsinit \
+ mbrlen mbrtowc wcrtomb mbsrtowcs wcsrtombs \
+ mbsnrtowcs wcsnrtombs wcsnlen wcschrnul \
+@@ -38,14 +44,19 @@
+ wcscoll_l wcsxfrm_l \
+ wcscasecmp wcsncase wcscasecmp_l wcsncase_l \
+ wcsmbsload mbsrtowcs_l \
+- isoc99_wscanf isoc99_vwscanf isoc99_fwscanf isoc99_vfwscanf \
+ isoc99_swscanf isoc99_vswscanf \
+ mbrtoc16 c16rtomb
++routines-$(OPTION_POSIX_WIDE_CHAR_DEVICE_IO) \
++ += isoc99_wscanf isoc99_vwscanf isoc99_fwscanf isoc99_vfwscanf
+
+ strop-tests := wcscmp wmemcmp wcslen wcschr wcsrchr wcscpy
+-tests := tst-wcstof wcsmbs-tst1 tst-wcsnlen tst-btowc tst-mbrtowc \
+- tst-wcrtomb tst-wcpncpy tst-mbsrtowcs tst-wchar-h tst-mbrtowc2 \
+- tst-c16c32-1 wcsatcliff $(addprefix test-,$(strop-tests))
++tests := tst-wchar-h
++tests-$(OPTION_EGLIBC_LOCALE_CODE) \
++ += tst-btowc tst-mbrtowc tst-mbrtowc2 tst-wcrtomb tst-c16c32-1
++tests-$(OPTION_POSIX_C_LANG_WIDE_CHAR) \
++ += tst-wcstof wcsmbs-tst1 tst-wcsnlen \
++ tst-wcpncpy tst-mbsrtowcs \
++ wcsatcliff $(addprefix test-,$(strop-tests))
+ tests-ifunc := $(strop-tests:%=test-%-ifunc)
+ tests += $(tests-ifunc)
+
+Index: git/wcsmbs/wcsmbsload.c
+===================================================================
+--- git.orig/wcsmbs/wcsmbsload.c 2014-08-29 20:00:59.580070587 -0700
++++ git/wcsmbs/wcsmbsload.c 2014-08-29 20:01:15.248070587 -0700
+@@ -21,6 +21,7 @@
+ #include <limits.h>
+ #include <stdlib.h>
+ #include <string.h>
++#include <gnu/option-groups.h>
+
+ #include <locale/localeinfo.h>
+ #include <wcsmbsload.h>
+@@ -143,6 +144,7 @@
+ })
+
+
++#if __OPTION_EGLIBC_LOCALE_CODE
+ /* Some of the functions here must not be used while setlocale is called. */
+ __libc_rwlock_define (extern, __libc_setlocale_lock attribute_hidden)
+
+@@ -211,6 +213,17 @@
+
+ __libc_rwlock_unlock (__libc_setlocale_lock);
+ }
++#else
++void
++internal_function
++__wcsmbs_load_conv (struct __locale_data *new_category)
++{
++ /* When OPTION_EGLIBC_LOCALE_CODE is disabled, we should never reach
++ this point: there is no way to change locales, so every locale
++ passed to get_gconv_fcts should be _nl_C_LC_CTYPE. */
++ abort ();
++}
++#endif
+
+
+ /* Clone the current conversion function set. */
+Index: git/wctype/Makefile
+===================================================================
+--- git.orig/wctype/Makefile 2014-08-29 20:00:59.584070587 -0700
++++ git/wctype/Makefile 2014-08-29 20:01:15.248070587 -0700
+@@ -18,14 +18,20 @@
+ #
+ # Sub-makefile for wctype portion of the library.
+ #
++include ../option-groups.mak
++
+ subdir := wctype
+
+ include ../Makeconfig
+
+ headers := wctype.h
+-routines := wcfuncs wctype iswctype wctrans towctrans \
+- wcfuncs_l wctype_l iswctype_l wctrans_l towctrans_l
++routines := wctrans towctrans towctrans_l
++routines-$(OPTION_POSIX_C_LANG_WIDE_CHAR) \
++ := wcfuncs wctype iswctype \
++ wcfuncs_l wctype_l iswctype_l wctrans_l
+
+-tests := test_wctype test_wcfuncs bug-wctypeh
++tests :=
++tests-$(OPTION_POSIX_C_LANG_WIDE_CHAR) \
++ += test_wctype test_wcfuncs bug-wctypeh
+
+ include ../Rules
+Index: git/sysdeps/nptl/Makefile
+===================================================================
+--- git.orig/sysdeps/nptl/Makefile 2014-08-29 20:00:58.036070587 -0700
++++ git/sysdeps/nptl/Makefile 2014-08-29 20:01:15.248070587 -0700
+@@ -18,6 +18,9 @@
+
+ ifeq ($(subdir),nptl)
+ libpthread-sysdep_routines += errno-loc
++ifeq ($(OPTION_EGLIBC_BIG_MACROS),n)
++sysdep_routines += small-macros-fns
++endif
+ endif
+
+ ifeq ($(subdir),rt)
+Index: git/sysdeps/nptl/bits/libc-lock.h
+===================================================================
+--- git.orig/sysdeps/nptl/bits/libc-lock.h 2014-08-29 20:00:58.036070587 -0700
++++ git/sysdeps/nptl/bits/libc-lock.h 2014-08-29 20:01:15.248070587 -0700
+@@ -24,6 +24,14 @@
+ #include <stddef.h>
+
+
++#ifdef _LIBC
++# include <lowlevellock.h>
++# include <tls.h>
++# include <pthread-functions.h>
++# include <errno.h> /* For EBUSY. */
++# include <gnu/option-groups.h> /* For __OPTION_EGLIBC_BIG_MACROS. */
++#endif
++
+ /* Mutex type. */
+ #if defined _LIBC || defined _IO_MTSAFE_IO
+ # if (defined NOT_IN_libc && !defined IS_IN_libpthread) || !defined _LIBC
+@@ -87,6 +95,14 @@
+
+ /* Lock the recursive named lock variable. */
+ #if defined _LIBC && (!defined NOT_IN_libc || defined IS_IN_libpthread)
++# if __OPTION_EGLIBC_BIG_MACROS != 1
++/* EGLIBC: Declare wrapper function for a big macro if either
++ !__OPTION_EGLIBC_BIG_MACROS or we are using a back door from
++ small-macros-fns.c (__OPTION_EGLIBC_BIG_MACROS == 2). */
++extern void __libc_lock_lock_recursive_fn (__libc_lock_recursive_t *);
++libc_hidden_proto (__libc_lock_lock_recursive_fn);
++# endif /* __OPTION_EGLIBC_BIG_MACROS != 1 */
++# if __OPTION_EGLIBC_BIG_MACROS
+ # define __libc_lock_lock_recursive(NAME) \
+ do { \
+ void *self = THREAD_SELF; \
+@@ -97,6 +113,10 @@
+ } \
+ ++(NAME).cnt; \
+ } while (0)
++# else
++# define __libc_lock_lock_recursive(NAME) \
++ __libc_lock_lock_recursive_fn (&(NAME))
++# endif /* __OPTION_EGLIBC_BIG_MACROS */
+ #else
+ # define __libc_lock_lock_recursive(NAME) \
+ __libc_maybe_call (__pthread_mutex_lock, (&(NAME).mutex), 0)
+@@ -104,6 +124,14 @@
+
+ /* Try to lock the recursive named lock variable. */
+ #if defined _LIBC && (!defined NOT_IN_libc || defined IS_IN_libpthread)
++# if __OPTION_EGLIBC_BIG_MACROS != 1
++/* EGLIBC: Declare wrapper function for a big macro if either
++ !__OPTION_EGLIBC_BIG_MACROS or we are using a back door from
++ small-macros-fns.c (__OPTION_EGLIBC_BIG_MACROS == 2). */
++extern int __libc_lock_trylock_recursive_fn (__libc_lock_recursive_t *);
++libc_hidden_proto (__libc_lock_trylock_recursive_fn);
++# endif /* __OPTION_EGLIBC_BIG_MACROS != 1 */
++# if __OPTION_EGLIBC_BIG_MACROS
+ # define __libc_lock_trylock_recursive(NAME) \
+ ({ \
+ int result = 0; \
+@@ -122,6 +150,10 @@
+ ++(NAME).cnt; \
+ result; \
+ })
++# else
++# define __libc_lock_trylock_recursive(NAME) \
++ __libc_lock_trylock_recursive_fn (&(NAME))
++# endif /* __OPTION_EGLIBC_BIG_MACROS */
+ #else
+ # define __libc_lock_trylock_recursive(NAME) \
+ __libc_maybe_call (__pthread_mutex_trylock, (&(NAME).mutex), 0)
+@@ -129,6 +161,14 @@
+
+ /* Unlock the recursive named lock variable. */
+ #if defined _LIBC && (!defined NOT_IN_libc || defined IS_IN_libpthread)
++# if __OPTION_EGLIBC_BIG_MACROS != 1
++/* EGLIBC: Declare wrapper function for a big macro if either
++ !__OPTION_EGLIBC_BIG_MACROS, or we are using a back door from
++ small-macros-fns.c (__OPTION_EGLIBC_BIG_MACROS == 2). */
++extern void __libc_lock_unlock_recursive_fn (__libc_lock_recursive_t *);
++libc_hidden_proto (__libc_lock_unlock_recursive_fn);
++# endif /* __OPTION_EGLIBC_BIG_MACROS != 1 */
++# if __OPTION_EGLIBC_BIG_MACROS
+ /* We do no error checking here. */
+ # define __libc_lock_unlock_recursive(NAME) \
+ do { \
+@@ -138,6 +178,10 @@
+ lll_unlock ((NAME).lock, LLL_PRIVATE); \
+ } \
+ } while (0)
++# else
++# define __libc_lock_unlock_recursive(NAME) \
++ __libc_lock_unlock_recursive_fn (&(NAME))
++# endif /* __OPTION_EGLIBC_BIG_MACROS */
+ #else
+ # define __libc_lock_unlock_recursive(NAME) \
+ __libc_maybe_call (__pthread_mutex_unlock, (&(NAME).mutex), 0)
+Index: git/sysdeps/nptl/bits/libc-lockP.h
+===================================================================
+--- git.orig/sysdeps/nptl/bits/libc-lockP.h 2014-08-29 20:00:58.044070587 -0700
++++ git/sysdeps/nptl/bits/libc-lockP.h 2014-08-29 20:01:15.248070587 -0700
+@@ -33,6 +33,8 @@
+ #include <lowlevellock.h>
+ #include <tls.h>
+ #include <pthread-functions.h>
++#include <errno.h> /* For EBUSY. */
++#include <gnu/option-groups.h> /* For __OPTION_EGLIBC_BIG_MACROS. */
+
+ /* Mutex type. */
+ #if defined NOT_IN_libc && !defined IS_IN_libpthread
+@@ -159,10 +161,22 @@
+
+ /* Lock the named lock variable. */
+ #if !defined NOT_IN_libc || defined IS_IN_libpthread
+-# ifndef __libc_lock_lock
+-# define __libc_lock_lock(NAME) \
++# if __OPTION_EGLIBC_BIG_MACROS != 1
++/* EGLIBC: Declare wrapper function for a big macro if either
++ !__OPTION_EGLIBC_BIG_MACROS or we are using a back door from
++ small-macros-fns.c (__OPTION_EGLIBC_BIG_MACROS == 2). */
++extern void __libc_lock_lock_fn (__libc_lock_t *);
++libc_hidden_proto (__libc_lock_lock_fn);
++# endif /* __OPTION_EGLIBC_BIG_MACROS != 1 */
++# if __OPTION_EGLIBC_BIG_MACROS
++# ifndef __libc_lock_lock
++# define __libc_lock_lock(NAME) \
+ ({ lll_lock (NAME, LLL_PRIVATE); 0; })
+-# endif
++# endif
++# else
++# define __libc_lock_lock(NAME) \
++ __libc_lock_lock_fn (&(NAME))
++# endif /* __OPTION_EGLIBC_BIG_MACROS */
+ #else
+ # undef __libc_lock_lock
+ # define __libc_lock_lock(NAME) \
+@@ -175,10 +189,22 @@
+
+ /* Try to lock the named lock variable. */
+ #if !defined NOT_IN_libc || defined IS_IN_libpthread
+-# ifndef __libc_lock_trylock
+-# define __libc_lock_trylock(NAME) \
++# if __OPTION_EGLIBC_BIG_MACROS != 1
++/* EGLIBC: Declare wrapper function for a big macro if either
++ !__OPTION_EGLIBC_BIG_MACROS or we are using a back door from
++ small-macros-fns.c (__OPTION_EGLIBC_BIG_MACROS == 2). */
++extern int __libc_lock_trylock_fn (__libc_lock_t *);
++libc_hidden_proto (__libc_lock_trylock_fn);
++# endif /* __OPTION_EGLIBC_BIG_MACROS != 1 */
++# if __OPTION_EGLIBC_BIG_MACROS
++# ifndef __libc_lock_trylock
++# define __libc_lock_trylock(NAME) \
+ lll_trylock (NAME)
+-# endif
++# endif
++# else
++# define __libc_lock_trylock(NAME) \
++ __libc_lock_trylock_fn (&(NAME))
++# endif /* __OPTION_EGLIBC_BIG_MACROS */
+ #else
+ # undef __libc_lock_trylock
+ # define __libc_lock_trylock(NAME) \
+@@ -194,8 +220,20 @@
+
+ /* Unlock the named lock variable. */
+ #if !defined NOT_IN_libc || defined IS_IN_libpthread
++# if __OPTION_EGLIBC_BIG_MACROS != 1
++/* EGLIBC: Declare wrapper function for a big macro if either
++ !__OPTION_EGLIBC_BIG_MACROS, or we are using a back door from
++ small-macros-fns.c (__OPTION_EGLIBC_BIG_MACROS == 2). */
++extern void __libc_lock_unlock_fn (__libc_lock_t *);
++libc_hidden_proto (__libc_lock_unlock_fn);
++# endif /* __OPTION_EGLIBC_BIG_MACROS != 1 */
++# if __OPTION_EGLIBC_BIG_MACROS
+ # define __libc_lock_unlock(NAME) \
+ lll_unlock (NAME, LLL_PRIVATE)
++# else
++# define __libc_lock_unlock(NAME) \
++ __libc_lock_unlock_fn (&(NAME))
++# endif /* __OPTION_EGLIBC_BIG_MACROS */
+ #else
+ # define __libc_lock_unlock(NAME) \
+ __libc_maybe_call (__pthread_mutex_unlock, (&(NAME)), 0)
+Index: git/sysdeps/nptl/small-macros-fns.c
+===================================================================
+--- /dev/null 1970-01-01 00:00:00.000000000 +0000
++++ git/sysdeps/nptl/small-macros-fns.c 2014-08-29 20:01:15.248070587 -0700
+@@ -0,0 +1,72 @@
++/* EGLIBC: function wrappers for big macros.
++ Copyright (C) 2009 Free Software Foundation, Inc.
++ This file is part of the GNU C Library.
++
++ The GNU C Library is free software; you can redistribute it and/or
++ modify it under the terms of the GNU Lesser General Public License as
++ published by the Free Software Foundation; either version 2.1 of the
++ License, or (at your option) any later version.
++
++ The GNU C Library is distributed in the hope that it will be useful,
++ but WITHOUT ANY WARRANTY; without even the implied warranty of
++ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
++ Lesser General Public License for more details.
++
++ You should have received a copy of the GNU Lesser General Public
++ License along with the GNU C Library; see the file COPYING.LIB. If not,
++ write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
++ Boston, MA 02111-1307, USA. */
++
++#include <gnu/option-groups.h>
++
++/* Handle macros from ./bits/libc-lock.h. */
++#if defined _LIBC && (!defined NOT_IN_libc || defined IS_IN_libpthread)
++
++/* Get the macros for function bodies through a back door. */
++# undef __OPTION_EGLIBC_BIG_MACROS
++# define __OPTION_EGLIBC_BIG_MACROS 2
++# include <bits/libc-lock.h>
++
++void
++__libc_lock_lock_fn (__libc_lock_t *name)
++{
++ __libc_lock_lock (*name);
++}
++libc_hidden_def (__libc_lock_lock_fn);
++
++void
++__libc_lock_lock_recursive_fn (__libc_lock_recursive_t *name)
++{
++ __libc_lock_lock_recursive (*name);
++}
++libc_hidden_def (__libc_lock_lock_recursive_fn);
++
++int
++__libc_lock_trylock_fn (__libc_lock_t *name)
++{
++ return __libc_lock_trylock (*name);
++}
++libc_hidden_def (__libc_lock_trylock_fn);
++
++int
++__libc_lock_trylock_recursive_fn (__libc_lock_recursive_t *name)
++{
++ return __libc_lock_trylock_recursive (*name);
++}
++libc_hidden_def (__libc_lock_trylock_recursive_fn);
++
++void
++__libc_lock_unlock_fn (__libc_lock_t *name)
++{
++ __libc_lock_unlock (*name);
++}
++libc_hidden_def (__libc_lock_unlock_fn);
++
++void
++__libc_lock_unlock_recursive_fn (__libc_lock_recursive_t *name)
++{
++ __libc_lock_unlock_recursive (*name);
++}
++libc_hidden_def (__libc_lock_unlock_recursive_fn);
++
++#endif /*defined _LIBC && (!defined NOT_IN_libc || defined IS_IN_libpthread)*/
+Index: git/crypt/crypt_common.c
+===================================================================
+--- /dev/null 1970-01-01 00:00:00.000000000 +0000
++++ git/crypt/crypt_common.c 2014-08-29 20:01:15.248070587 -0700
+@@ -0,0 +1,42 @@
++/*
++ * crypt: crypt(3) implementation
++ *
++ * Copyright (C) 1991-2014 Free Software Foundation, Inc.
++ *
++ * This library is free software; you can redistribute it and/or
++ * modify it under the terms of the GNU Lesser General Public
++ * License as published by the Free Software Foundation; either
++ * version 2.1 of the License, or (at your option) any later version.
++ *
++ * This library is distributed in the hope that it will be useful,
++ * but WITHOUT ANY WARRANTY; without even the implied warranty of
++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
++ * Lesser General Public License for more details.
++ *
++ * You should have received a copy of the GNU Lesser General Public
++ * License along with this library; see the file COPYING.LIB. If not,
++ * see <http://www.gnu.org/licenses/>.
++ *
++ * General Support routines
++ *
++ */
++
++#include "crypt-private.h"
++
++/* Table with characters for base64 transformation. */
++static const char b64t[64] =
++"./0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz";
++
++void
++__b64_from_24bit (char **cp, int *buflen,
++ unsigned int b2, unsigned int b1, unsigned int b0,
++ int n)
++{
++ unsigned int w = (b2 << 16) | (b1 << 8) | b0;
++ while (n-- > 0 && (*buflen) > 0)
++ {
++ *(*cp)++ = b64t[w & 0x3f];
++ --(*buflen);
++ w >>= 6;
++ }
++}
+Index: git/crypt/crypt_util.c
+===================================================================
+--- git.orig/crypt/crypt_util.c 2014-08-29 20:00:43.028070587 -0700
++++ git/crypt/crypt_util.c 2014-08-29 20:01:15.248070587 -0700
+@@ -242,10 +242,6 @@
+ */
+ static ufc_long efp[16][64][2];
+
+-/* Table with characters for base64 transformation. */
+-static const char b64t[64] =
+-"./0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz";
+-
+ /*
+ * For use by the old, non-reentrant routines
+ * (crypt/encrypt/setkey)
+@@ -949,17 +945,3 @@
+ {
+ __setkey_r(__key, &_ufc_foobar);
+ }
+-
+-void
+-__b64_from_24bit (char **cp, int *buflen,
+- unsigned int b2, unsigned int b1, unsigned int b0,
+- int n)
+-{
+- unsigned int w = (b2 << 16) | (b1 << 8) | b0;
+- while (n-- > 0 && (*buflen) > 0)
+- {
+- *(*cp)++ = b64t[w & 0x3f];
+- --(*buflen);
+- w >>= 6;
+- }
+-}
+Index: git/sysdeps/arm/Makefile
+===================================================================
+--- git.orig/sysdeps/arm/Makefile 2014-08-29 20:29:37.000000000 -0700
++++ git/sysdeps/arm/Makefile 2014-08-29 20:31:09.904070587 -0700
+@@ -37,10 +37,13 @@
+ # get offset to rtld_global._dl_hwcap
+ gen-as-const-headers += rtld-global-offsets.sym tlsdesc.sym
+ aeabi_constants = aeabi_lcsts aeabi_sighandlers aeabi_math
+-aeabi_routines = aeabi_assert aeabi_localeconv aeabi_errno_addr \
++aeabi_routines = aeabi_assert aeabi_errno_addr \
+ aeabi_mb_cur_max aeabi_atexit aeabi_memclr aeabi_memcpy \
+ aeabi_memmove aeabi_memset \
+ aeabi_read_tp libc-aeabi_read_tp
++ifeq (y,$(OPTION_EGLIBC_LOCALE_CODE))
++aeabi_routines += aeabi_localeconv
++endif
+
+ sysdep_routines += $(aeabi_constants) $(aeabi_routines)
+ static-only-routines += $(aeabi_constants) aeabi_read_tp
diff --git a/recipes-core/glibc/glibc/eglibc.patch b/recipes-core/glibc/glibc/eglibc.patch
new file mode 100644
index 0000000..fdfabc3
--- /dev/null
+++ b/recipes-core/glibc/glibc/eglibc.patch
@@ -0,0 +1,602 @@
+Instruction documents from eglibc
+
+Upstream-Status: Pending
+
+Index: git/EGLIBC.cross-building
+===================================================================
+--- /dev/null 1970-01-01 00:00:00.000000000 +0000
++++ git/EGLIBC.cross-building 2014-08-27 07:27:25.580070587 +0000
+@@ -0,0 +1,383 @@
++ -*- mode: text -*-
++
++ Cross-Compiling EGLIBC
++ Jim Blandy <jimb at codesourcery.com>
++
++
++Introduction
++
++Most GNU tools have a simple build procedure: you run their
++'configure' script, and then you run 'make'. Unfortunately, the
++process of cross-compiling the GNU C library is quite a bit more
++involved:
++
++1) Build a cross-compiler, with certain facilities disabled.
++
++2) Configure the C library using the compiler you built in step 1).
++ Build a few of the C run-time object files, but not the rest of the
++ library. Install the library's header files and the run-time
++ object files, and create a dummy libc.so.
++
++3) Build a second cross-compiler, using the header files and object
++ files you installed in step 2.
++
++4) Configure, build, and install a fresh C library, using the compiler
++ built in step 3.
++
++5) Build a third cross-compiler, based on the C library built in step 4.
++
++The reason for this complexity is that, although GCC and the GNU C
++library are distributed separately, they are not actually independent
++of each other: GCC requires the C library's headers and some object
++files to compile its own libraries, while the C library depends on
++GCC's libraries. EGLIBC includes features and bug fixes to the stock
++GNU C library that simplify this process, but the fundamental
++interdependency stands.
++
++In this document, we explain how to cross-compile an EGLIBC/GCC pair
++from source. Our intended audience is developers who are already
++familiar with the GNU toolchain and comfortable working with
++cross-development tools. While we do present a worked example to
++accompany the explanation, for clarity's sake we do not cover many of
++the options available to cross-toolchain users.
++
++
++Preparation
++
++EGLIBC requires recent versions of the GNU binutils, GCC, and the
++Linux kernel. The web page <http://www.eglibc.org/prerequisites>
++documents the current requirements, and lists patches needed for
++certain target architectures. As of this writing, these build
++instructions have been tested with binutils 2.22.51, GCC 4.6.2,
++and Linux 3.1.
++
++First, let's set some variables, to simplify later commands. We'll
++build EGLIBC and GCC for an ARM target, known to the Linux kernel
++as 'arm', and we'll do the build on an Intel x86_64 Linux box:
++
++ $ build=x86_64-pc-linux-gnu
++ $ host=$build
++ $ target=arm-none-linux-gnueabi
++ $ linux_arch=arm
++
++We're using the aforementioned versions of Binutils, GCC, and Linux:
++
++ $ binutilsv=binutils-2.22.51
++ $ gccv=gcc-4.6.2
++ $ linuxv=linux-3.1
++
++We're carrying out the entire process under '~/cross-build', which
++contains unpacked source trees for binutils, gcc, and linux kernel,
++along with EGLIBC svn trunk (which can be checked-out with
++'svn co http://www.eglibc.org/svn/trunk eglibc'):
++
++ $ top=$HOME/cross-build/$target
++ $ src=$HOME/cross-build/src
++ $ ls $src
++ binutils-2.22.51 eglibc gcc-4.6.2 linux-3.1
++
++We're going to place our build directories in a subdirectory 'obj',
++we'll install the cross-development toolchain in 'tools', and we'll
++place our sysroot (containing files to be installed on the target
++system) in 'sysroot':
++
++ $ obj=$top/obj
++ $ tools=$top/tools
++ $ sysroot=$top/sysroot
++
++
++Binutils
++
++Configuring and building binutils for the target is straightforward:
++
++ $ mkdir -p $obj/binutils
++ $ cd $obj/binutils
++ $ $src/$binutilsv/configure \
++ > --target=$target \
++ > --prefix=$tools \
++ > --with-sysroot=$sysroot
++ $ make
++ $ make install
++
++
++The First GCC
++
++For our work, we need a cross-compiler targeting an ARM Linux
++system. However, that configuration includes the shared library
++'libgcc_s.so', which is compiled against the EGLIBC headers (which we
++haven't installed yet) and linked against 'libc.so' (which we haven't
++built yet).
++
++Fortunately, there are configuration options for GCC which tell it not
++to build 'libgcc_s.so'. The '--without-headers' option is supposed to
++take care of this, but its implementation is incomplete, so you must
++also configure with the '--with-newlib' option. While '--with-newlib'
++appears to mean "Use the Newlib C library", its effect is to tell the
++GCC build machinery, "Don't assume there is a C library available."
++
++We also need to disable some of the libraries that would normally be
++built along with GCC, and specify that only the compiler for the C
++language is needed.
++
++So, we create a build directory, configure, make, and install.
++
++ $ mkdir -p $obj/gcc1
++ $ cd $obj/gcc1
++ $ $src/$gccv/configure \
++ > --target=$target \
++ > --prefix=$tools \
++ > --without-headers --with-newlib \
++ > --disable-shared --disable-threads --disable-libssp \
++ > --disable-libgomp --disable-libmudflap --disable-libquadmath \
++ > --disable-decimal-float --disable-libffi \
++ > --enable-languages=c
++ $ PATH=$tools/bin:$PATH make
++ $ PATH=$tools/bin:$PATH make install
++
++
++Linux Kernel Headers
++
++To configure EGLIBC, we also need Linux kernel headers in place.
++Fortunately, the Linux makefiles have a target that installs them for
++us. Since the process does modify the source tree a bit, we make a
++copy first:
++
++ $ cp -r $src/$linuxv $obj/linux
++ $ cd $obj/linux
++
++Now we're ready to install the headers into the sysroot:
++
++ $ PATH=$tools/bin:$PATH \
++ > make headers_install \
++ > ARCH=$linux_arch CROSS_COMPILE=$target- \
++ > INSTALL_HDR_PATH=$sysroot/usr
++
++
++EGLIBC Headers and Preliminary Objects
++
++Using the cross-compiler we've just built, we can now configure EGLIBC
++well enough to install the headers and build the object files that the
++full cross-compiler will need:
++
++ $ mkdir -p $obj/eglibc-headers
++ $ cd $obj/eglibc-headers
++ $ BUILD_CC=gcc \
++ > CC=$tools/bin/$target-gcc \
++ > CXX=$tools/bin/$target-g++ \
++ > AR=$tools/bin/$target-ar \
++ > RANLIB=$tools/bin/$target-ranlib \
++ > $src/eglibc/libc/configure \
++ > --prefix=/usr \
++ > --with-headers=$sysroot/usr/include \
++ > --build=$build \
++ > --host=$target \
++ > --disable-profile --without-gd --without-cvs \
++ > --enable-add-ons=nptl,libidn,../ports
++
++The option '--prefix=/usr' may look strange, but you should never
++configure EGLIBC with a prefix other than '/usr': in various places,
++EGLIBC's build system checks whether the prefix is '/usr', and does
++special handling only if that is the case. Unless you use this
++prefix, you will get a sysroot that does not use the standard Linux
++directory layouts and cannot be used as a basis for the root
++filesystem on your target system compatibly with normal GLIBC
++installations.
++
++The '--with-headers' option tells EGLIBC where the Linux headers have
++been installed.
++
++The '--enable-add-ons=nptl,libidn,../ports' option tells EGLIBC to look
++for the listed glibc add-ons. Most notably the ports add-on (located
++just above the libc sources in the EGLIBC svn tree) is required to
++support ARM targets.
++
++We can now use the 'install-headers' makefile target to install the
++headers:
++
++ $ make install-headers install_root=$sysroot \
++ > install-bootstrap-headers=yes
++
++The 'install_root' variable indicates where the files should actually
++be installed; its value is treated as the parent of the '--prefix'
++directory we passed to the configure script, so the headers will go in
++'$sysroot/usr/include'. The 'install-bootstrap-headers' variable
++requests special handling for certain tricky header files.
++
++Next, there are a few object files needed to link shared libraries,
++which we build and install by hand:
++
++ $ mkdir -p $sysroot/usr/lib
++ $ make csu/subdir_lib
++ $ cp csu/crt1.o csu/crti.o csu/crtn.o $sysroot/usr/lib
++
++Finally, 'libgcc_s.so' requires a 'libc.so' to link against. However,
++since we will never actually execute its code, it doesn't matter what
++it contains. So, treating '/dev/null' as a C source file, we produce
++a dummy 'libc.so' in one step:
++
++ $ $tools/bin/$target-gcc -nostdlib -nostartfiles -shared -x c /dev/null \
++ > -o $sysroot/usr/lib/libc.so
++
++
++The Second GCC
++
++With the EGLIBC headers and selected object files installed, we can
++now build a GCC that is capable of compiling EGLIBC. We configure,
++build, and install the second GCC, again building only the C compiler,
++and avoiding libraries we won't use:
++
++ $ mkdir -p $obj/gcc2
++ $ cd $obj/gcc2
++ $ $src/$gccv/configure \
++ > --target=$target \
++ > --prefix=$tools \
++ > --with-sysroot=$sysroot \
++ > --disable-libssp --disable-libgomp --disable-libmudflap \
++ > --disable-libffi --disable-libquadmath \
++ > --enable-languages=c
++ $ PATH=$tools/bin:$PATH make
++ $ PATH=$tools/bin:$PATH make install
++
++
++EGLIBC, Complete
++
++With the second compiler built and installed, we're now ready for the
++full EGLIBC build:
++
++ $ mkdir -p $obj/eglibc
++ $ cd $obj/eglibc
++ $ BUILD_CC=gcc \
++ > CC=$tools/bin/$target-gcc \
++ > CXX=$tools/bin/$target-g++ \
++ > AR=$tools/bin/$target-ar \
++ > RANLIB=$tools/bin/$target-ranlib \
++ > $src/eglibc/libc/configure \
++ > --prefix=/usr \
++ > --with-headers=$sysroot/usr/include \
++ > --with-kconfig=$obj/linux/scripts/kconfig \
++ > --build=$build \
++ > --host=$target \
++ > --disable-profile --without-gd --without-cvs \
++ > --enable-add-ons=nptl,libidn,../ports
++
++Note the additional '--with-kconfig' option. This tells EGLIBC where to
++find the host config tools used by the kernel 'make config' and 'make
++menuconfig'. These tools can be re-used by EGLIBC for its own 'make
++*config' support, which will create 'option-groups.config' for you.
++But first make sure those tools have been built by running some
++dummy 'make *config' calls in the kernel directory:
++
++ $ cd $obj/linux
++ $ PATH=$tools/bin:$PATH make config \
++ > ARCH=$linux_arch CROSS_COMPILE=$target- \
++ $ PATH=$tools/bin:$PATH make menuconfig \
++ > ARCH=$linux_arch CROSS_COMPILE=$target- \
++
++Now we can configure and build the full EGLIBC:
++
++ $ cd $obj/eglibc
++ $ PATH=$tools/bin:$PATH make defconfig
++ $ PATH=$tools/bin:$PATH make menuconfig
++ $ PATH=$tools/bin:$PATH make
++ $ PATH=$tools/bin:$PATH make install install_root=$sysroot
++
++At this point, we have a complete EGLIBC installation in '$sysroot',
++with header files, library files, and most of the C runtime startup
++files in place.
++
++
++The Third GCC
++
++Finally, we recompile GCC against this full installation, enabling
++whatever languages and libraries we would like to use:
++
++ $ mkdir -p $obj/gcc3
++ $ cd $obj/gcc3
++ $ $src/$gccv/configure \
++ > --target=$target \
++ > --prefix=$tools \
++ > --with-sysroot=$sysroot \
++ > --enable-__cxa_atexit \
++ > --disable-libssp --disable-libgomp --disable-libmudflap \
++ > --enable-languages=c,c++
++ $ PATH=$tools/bin:$PATH make
++ $ PATH=$tools/bin:$PATH make install
++
++The '--enable-__cxa_atexit' option tells GCC what sort of C++
++destructor support to expect from the C library; it's required with
++EGLIBC.
++
++And since GCC's installation process isn't designed to help construct
++sysroot trees, we must manually copy certain libraries into place in
++the sysroot.
++
++ $ cp -d $tools/$target/lib/libgcc_s.so* $sysroot/lib
++ $ cp -d $tools/$target/lib/libstdc++.so* $sysroot/usr/lib
++
++
++Trying Things Out
++
++At this point, '$tools' contains a cross toolchain ready to use
++the EGLIBC installation in '$sysroot':
++
++ $ cat > hello.c <<EOF
++ > #include <stdio.h>
++ > int
++ > main (int argc, char **argv)
++ > {
++ > puts ("Hello, world!");
++ > return 0;
++ > }
++ > EOF
++ $ $tools/bin/$target-gcc -Wall hello.c -o hello
++ $ cat > c++-hello.cc <<EOF
++ > #include <iostream>
++ > int
++ > main (int argc, char **argv)
++ > {
++ > std::cout << "Hello, C++ world!" << std::endl;
++ > return 0;
++ > }
++ > EOF
++ $ $tools/bin/$target-g++ -Wall c++-hello.cc -o c++-hello
++
++
++We can use 'readelf' to verify that these are indeed executables for
++our target, using our dynamic linker:
++
++ $ $tools/bin/$target-readelf -hl hello
++ ELF Header:
++ ...
++ Type: EXEC (Executable file)
++ Machine: ARM
++
++ ...
++ Program Headers:
++ Type Offset VirtAddr PhysAddr FileSiz MemSiz Flg Align
++ PHDR 0x000034 0x10000034 0x10000034 0x00100 0x00100 R E 0x4
++ INTERP 0x000134 0x00008134 0x00008134 0x00013 0x00013 R 0x1
++ [Requesting program interpreter: /lib/ld-linux.so.3]
++ LOAD 0x000000 0x00008000 0x00008000 0x0042c 0x0042c R E 0x8000
++ ...
++
++Looking at the dynamic section of the installed 'libgcc_s.so', we see
++that the 'NEEDED' entry for the C library does include the '.6'
++suffix, indicating that was linked against our fully build EGLIBC, and
++not our dummy 'libc.so':
++
++ $ $tools/bin/$target-readelf -d $sysroot/lib/libgcc_s.so.1
++ Dynamic section at offset 0x1083c contains 24 entries:
++ Tag Type Name/Value
++ 0x00000001 (NEEDED) Shared library: [libc.so.6]
++ 0x0000000e (SONAME) Library soname: [libgcc_s.so.1]
++ ...
++
++
++And on the target machine, we can run our programs:
++
++ $ $sysroot/lib/ld.so.1 --library-path $sysroot/lib:$sysroot/usr/lib \
++ > ./hello
++ Hello, world!
++ $ $sysroot/lib/ld.so.1 --library-path $sysroot/lib:$sysroot/usr/lib \
++ > ./c++-hello
++ Hello, C++ world!
+Index: git/EGLIBC.cross-testing
+===================================================================
+--- /dev/null 1970-01-01 00:00:00.000000000 +0000
++++ git/EGLIBC.cross-testing 2014-08-27 07:24:41.532070587 +0000
+@@ -0,0 +1,205 @@
++ -*- mode: text -*-
++
++ Cross-Testing With EGLIBC
++ Jim Blandy <jimb at codesourcery.com>
++
++
++Introduction
++
++Developers writing software for embedded systems often use a desktop
++or other similarly capable computer for development, but need to run
++tests on the embedded system, or perhaps on a simulator. When
++configured for cross-compilation, the stock GNU C library simply
++disables running tests altogether: the command 'make tests' builds
++test programs, but does not run them. EGLIBC, however, provides
++facilities for compiling tests and generating data files on the build
++system, but running the test programs themselves on a remote system or
++simulator.
++
++
++Test environment requirements
++
++The test environment must meet certain conditions for EGLIBC's
++cross-testing facilities to work:
++
++- Shared filesystems. The 'build' system, on which you configure and
++ compile EGLIBC, and the 'host' system, on which you intend to run
++ EGLIBC, must share a filesystem containing the EGLIBC build and
++ source trees. Files must appear at the same paths on both systems.
++
++- Remote-shell like invocation. There must be a way to run a program
++ on the host system from the build system, passing it properly quoted
++ command-line arguments, setting environment variables, and
++ inheriting the caller's standard input and output.
++
++
++Usage
++
++To use EGLIBC's cross-testing support, provide values for the
++following Make variables when you invoke 'make':
++
++- cross-test-wrapper
++
++ This should be the name of the cross-testing wrapper command, along
++ with any arguments.
++
++- cross-localedef
++
++ This should be the name of a cross-capable localedef program, like
++ that included in the EGLIBC 'localedef' module, along with any
++ arguments needed.
++
++These are each explained in detail below.
++
++
++The Cross-Testing Wrapper
++
++To run test programs reliably, the stock GNU C library takes care to
++ensure that test programs use the newly compiled dynamic linker and
++shared libraries, and never the host system's installed libraries. To
++accomplish this, it runs the tests by explicitly invoking the dynamic
++linker from the build tree, passing it a list of build tree
++directories to search for shared libraries, followed by the name of
++the executable to run and its arguments.
++
++For example, where one might normally run a test program like this:
++
++ $ ./tst-foo arg1 arg2
++
++the GNU C library might run that program like this:
++
++ $ $objdir/elf/ld-linux.so.3 --library-path $objdir \
++ ./tst-foo arg1 arg2
++
++(where $objdir is the path to the top of the build tree, and the
++trailing backslash indicates a continuation of the command). In other
++words, each test program invocation is 'wrapped up' inside an explicit
++invocation of the dynamic linker, which must itself execute the test
++program, having loaded shared libraries from the appropriate
++directories.
++
++To support cross-testing, EGLIBC allows the developer to optionally
++set the 'cross-test-wrapper' Make variable to another wrapper command,
++to which it passes the entire dynamic linker invocation shown above as
++arguments. For example, if the developer supplies a wrapper of
++'my-wrapper hostname', then EGLIBC would run the test above as
++follows:
++
++ $ my-wrapper hostname \
++ $objdir/elf/ld-linux.so.3 --library-path $objdir \
++ ./tst-foo arg1 arg2
++
++The 'my-wrapper' command is responsible for executing the command
++given on the host system.
++
++Since tests are run in varying directories, the wrapper should either
++be in your command search path, or 'cross-test-wrapper' should give an
++absolute path for the wrapper.
++
++The wrapper must meet several requirements:
++
++- It must preserve the current directory. As explained above, the
++ build directory tree must be visible on both the build and host
++ systems, at the same path. The test wrapper must ensure that the
++ current directory it inherits is also inherited by the dynamic
++ linker (and thus the test program itself).
++
++- It must preserve environment variables' values. Many EGLIBC tests
++ set environment variables for test runs; in native testing, it
++ invokes programs like this:
++
++ $ GCONV_PATH=$objdir/iconvdata \
++ $objdir/elf/ld-linux.so.3 --library-path $objdir \
++ ./tst-foo arg1 arg2
++
++ With the cross-testing wrapper, that invocation becomes:
++
++ $ GCONV_PATH=$objdir/iconvdata \
++ my-wrapper hostname \
++ $objdir/elf/ld-linux.so.3 --library-path $objdir \
++ ./tst-foo arg1 arg2
++
++ Here, 'my-wrapper' must ensure that the value it sees for
++ 'GCONV_PATH' will be seen by the dynamic linker, and thus 'tst-foo'
++ itself. (The wrapper supplied with GLIBC simply preserves the
++ values of *all* enviroment variables, with a fixed set of
++ exceptions.)
++
++ If your wrapper is a shell script, take care to correctly propagate
++ environment variables whose values contain spaces and shell
++ metacharacters.
++
++- It must pass the command's arguments, unmodified. The arguments
++ seen by the test program should be exactly those seen by the wrapper
++ (after whatever arguments are given to the wrapper itself). The
++ EGLIBC test framework performs all needed shell word splitting and
++ expansion (wildcard expansion, parameter substitution, and so on)
++ before invoking the wrapper; further expansion may break the tests.
++
++
++The 'cross-test-ssh.sh' script
++
++If you want to use 'ssh' (or something sufficiently similar) to run
++test programs on your host system, EGLIBC includes a shell script,
++'scripts/cross-test-ssh.sh', which you can use as your wrapper
++command. This script takes care of setting the test command's current
++directory, propagating environment variable values, and carrying
++command-line arguments, all across an 'ssh' connection. You may even
++supply an alternative to 'ssh' on the command line, if needed.
++
++For more details, pass 'cross-test-ssh.sh' the '--help' option.
++
++
++The Cross-Compiling Locale Definition Command
++
++Some EGLIBC tests rely on locales generated especially for the test
++process. In a native configuration, these tests simply run the
++'localedef' command built by the normal EGLIBC build process,
++'locale/localedef', to process and install their locales. However, in
++a cross-compiling configuration, this 'localedef' is built for the
++host system, not the build system, and since it requires quite a bit
++of memory to run (we have seen it fail on systems with 64MiB of
++memory), it may not be practical to run it on the host system.
++
++If set, EGLIBC uses the 'cross-localedef' Make variable as the command
++to run on the build system to process and install locales. The
++localedef program built from the EGLIBC 'localedef' module is
++suitable.
++
++The value of 'cross-localedef' may also include command-line arguments
++to be passed to the program; if you are using EGLIBC's 'localedef',
++you may include endianness and 'uint32_t' alignment arguments here.
++
++
++Example
++
++In developing EGLIBC's cross-testing facility, we invoked 'make' with
++the following script:
++
++ #!/bin/sh
++
++ srcdir=...
++ test_hostname=...
++ localedefdir=...
++ cross_gxx=...-g++
++
++ wrapper="$srcdir/scripts/cross-test-ssh.sh $test_hostname"
++ localedef="$localedefdir/localedef --little-endian --uint32-align=4"
++
++ make cross-test-wrapper="$wrapper" \
++ cross-localedef="$localedef" \
++ CXX="$cross_gxx" \
++ "$@"
++
++
++Other Cross-Testing Concerns
++
++Here are notes on some other issues which you may encounter in running
++the EGLIBC tests in a cross-compiling environment:
++
++- Some tests require a C++ cross-compiler; you should set the 'CXX'
++ Make variable to the name of an appropriate cross-compiler.
++
++- Some tests require access to libstdc++.so.6 and libgcc_s.so.1; we
++ simply place copies of these libraries in the top EGLIBC build
++ directory.
diff --git a/recipes-core/glibc/glibc/etc/ld.so.conf b/recipes-core/glibc/glibc/etc/ld.so.conf
new file mode 100644
index 0000000..e69de29
diff --git a/recipes-core/glibc/glibc/fix-tibetian-locales.patch b/recipes-core/glibc/glibc/fix-tibetian-locales.patch
new file mode 100644
index 0000000..9ab9fdc
--- /dev/null
+++ b/recipes-core/glibc/glibc/fix-tibetian-locales.patch
@@ -0,0 +1,38 @@
+cross localedef fails to compile these locales because name_fmt field is empty
+It is not acceptable for cross localedef and it errors out
+
+LC_NAME: field `name_fmt' not defined
+
+We therefore give a dummy string to the format, the real fix needs some native
+tibetian person to define proper name_fmt
+
+Upstream-Status: Pending
+
+Signed-off-by: Khem Raj <raj.khem at gmail.com>
+
+Index: git/localedata/locales/bo_CN
+===================================================================
+--- git.orig/localedata/locales/bo_CN 2014-08-29 10:35:22.464070587 -0700
++++ git/localedata/locales/bo_CN 2014-08-29 10:35:22.456070587 -0700
+@@ -146,7 +146,7 @@
+ LC_NAME
+ % FIXME
+
+-name_fmt ""
++name_fmt "FIXME"
+ % name_gen "FIXME"
+ % name_miss "FIXME"
+ % name_mr "FIXME"
+Index: git/localedata/locales/bo_IN
+===================================================================
+--- git.orig/localedata/locales/bo_IN 2014-08-29 10:35:22.464070587 -0700
++++ git/localedata/locales/bo_IN 2014-08-29 10:35:22.456070587 -0700
+@@ -71,7 +71,7 @@
+
+ LC_NAME
+ % FIXME
+-name_fmt ""
++name_fmt "FIXME"
+ % name_gen "FIXME"
+ % name_miss "FIXME"
+ % name_mr "FIXME"
diff --git a/recipes-core/glibc/glibc/fix_am_rootsbindir.patch b/recipes-core/glibc/glibc/fix_am_rootsbindir.patch
new file mode 100644
index 0000000..668e8bf
--- /dev/null
+++ b/recipes-core/glibc/glibc/fix_am_rootsbindir.patch
@@ -0,0 +1,29 @@
+sysdeps/gnu/configure.ac: handle correctly $libc_cv_rootsbindir
+
+Upstream-Status:Pending
+Signed-off-by: Matthieu Crapet <Matthieu.Crapet at ingenico.com>
+
+Index: git/sysdeps/gnu/configure
+===================================================================
+--- git.orig/sysdeps/gnu/configure 2014-08-27 07:24:38.572070587 +0000
++++ git/sysdeps/gnu/configure 2014-08-27 07:24:41.308070587 +0000
+@@ -32,6 +32,6 @@
+ else
+ libc_cv_localstatedir=$localstatedir
+ fi
+- libc_cv_rootsbindir=/sbin
++ test -n "$libc_cv_rootsbindir" || libc_cv_rootsbindir=/sbin
+ ;;
+ esac
+Index: git/sysdeps/gnu/configure.ac
+===================================================================
+--- git.orig/sysdeps/gnu/configure.ac 2014-08-27 07:24:38.572070587 +0000
++++ git/sysdeps/gnu/configure.ac 2014-08-27 07:24:41.308070587 +0000
+@@ -21,6 +21,6 @@
+ else
+ libc_cv_localstatedir=$localstatedir
+ fi
+- libc_cv_rootsbindir=/sbin
++ test -n "$libc_cv_rootsbindir" || libc_cv_rootsbindir=/sbin
+ ;;
+ esac
diff --git a/recipes-core/glibc/glibc/fsl-ppc-no-fsqrt.patch b/recipes-core/glibc/glibc/fsl-ppc-no-fsqrt.patch
new file mode 100644
index 0000000..f88eaf4
--- /dev/null
+++ b/recipes-core/glibc/glibc/fsl-ppc-no-fsqrt.patch
@@ -0,0 +1,100 @@
+Create e5500 specific math_private.h and let it include when compiling for e5500/64bit core
+We prefefine __CPU_HAS_FSQRT to 0 and then in general ppc64 math_private.h we check if its
+already defined before redefining it. This way we can ensure that on e5500 builds it wont
+emit fsqrt intructions
+
+-Khem
+
+Upstream-Status: Pending
+
+Index: git/sysdeps/powerpc/fpu/math_private.h
+===================================================================
+--- git.orig/sysdeps/powerpc/fpu/math_private.h 2014-08-29 10:31:30.224070587 -0700
++++ git/sysdeps/powerpc/fpu/math_private.h 2014-08-29 10:31:30.212070587 -0700
+@@ -25,10 +25,12 @@
+ #include <fenv_private.h>
+ #include_next <math_private.h>
+
+-# if __WORDSIZE == 64 || defined _ARCH_PWR4
+-# define __CPU_HAS_FSQRT 1
+-# else
+-# define __CPU_HAS_FSQRT ((GLRO(dl_hwcap) & PPC_FEATURE_64) != 0)
++# ifndef __CPU_HAS_FSQRT
++# if __WORDSIZE == 64 || defined _ARCH_PWR4
++# define __CPU_HAS_FSQRT 1
++# else
++# define __CPU_HAS_FSQRT ((GLRO(dl_hwcap) & PPC_FEATURE_64) != 0)
++# endif
+ # endif
+
+ extern double __slow_ieee754_sqrt (double);
+Index: git/sysdeps/powerpc/powerpc64/e5500/fpu/math_private.h
+===================================================================
+--- /dev/null 1970-01-01 00:00:00.000000000 +0000
++++ git/sysdeps/powerpc/powerpc64/e5500/fpu/math_private.h 2014-08-29 10:31:30.212070587 -0700
+@@ -0,0 +1,9 @@
++#ifndef _E5500_MATH_PRIVATE_H_
++#define _E5500_MATH_PRIVATE_H_ 1
++/* E5500 core FPU does not implement
++ fsqrt */
++
++#define __CPU_HAS_FSQRT 0
++#include_next <math_private.h>
++
++#endif /* _E5500_MATH_PRIVATE_H_ */
+Index: git/sysdeps/powerpc/powerpc64/e6500/fpu/math_private.h
+===================================================================
+--- /dev/null 1970-01-01 00:00:00.000000000 +0000
++++ git/sysdeps/powerpc/powerpc64/e6500/fpu/math_private.h 2014-08-29 10:31:30.212070587 -0700
+@@ -0,0 +1,9 @@
++#ifndef _E6500_MATH_PRIVATE_H_
++#define _E6500_MATH_PRIVATE_H_ 1
++/* E6500 core FPU does not implement
++ fsqrt */
++
++#define __CPU_HAS_FSQRT 0
++#include_next <math_private.h>
++
++#endif /* _E6500_MATH_PRIVATE_H_ */
+Index: git/sysdeps/powerpc/powerpc32/e500mc/fpu/math_private.h
+===================================================================
+--- /dev/null 1970-01-01 00:00:00.000000000 +0000
++++ git/sysdeps/powerpc/powerpc32/e500mc/fpu/math_private.h 2014-08-29 10:31:30.212070587 -0700
+@@ -0,0 +1,9 @@
++#ifndef _E500MC_MATH_PRIVATE_H_
++#define _E500MC_MATH_PRIVATE_H_ 1
++/* E500MC core FPU does not implement
++ fsqrt */
++
++#define __CPU_HAS_FSQRT 0
++#include_next <math_private.h>
++
++#endif /* _E500MC_MATH_PRIVATE_H_ */
+Index: git/sysdeps/powerpc/powerpc32/e5500/fpu/math_private.h
+===================================================================
+--- /dev/null 1970-01-01 00:00:00.000000000 +0000
++++ git/sysdeps/powerpc/powerpc32/e5500/fpu/math_private.h 2014-08-29 10:31:30.216070587 -0700
+@@ -0,0 +1,9 @@
++#ifndef _E5500_MATH_PRIVATE_H_
++#define _E5500_MATH_PRIVATE_H_ 1
++/* E5500 core FPU does not implement
++ fsqrt */
++
++#define __CPU_HAS_FSQRT 0
++#include_next <math_private.h>
++
++#endif /* _E5500_MATH_PRIVATE_H_ */
+Index: git/sysdeps/powerpc/powerpc32/e6500/fpu/math_private.h
+===================================================================
+--- /dev/null 1970-01-01 00:00:00.000000000 +0000
++++ git/sysdeps/powerpc/powerpc32/e6500/fpu/math_private.h 2014-08-29 10:31:30.216070587 -0700
+@@ -0,0 +1,9 @@
++#ifndef _E6500_MATH_PRIVATE_H_
++#define _E6500_MATH_PRIVATE_H_ 1
++/* E6500 core FPU does not implement
++ fsqrt */
++
++#define __CPU_HAS_FSQRT 0
++#include_next <math_private.h>
++
++#endif /* _E6500_MATH_PRIVATE_H_ */
diff --git a/recipes-core/glibc/glibc/generate-supported.mk b/recipes-core/glibc/glibc/generate-supported.mk
new file mode 100644
index 0000000..d2a28c2
--- /dev/null
+++ b/recipes-core/glibc/glibc/generate-supported.mk
@@ -0,0 +1,11 @@
+#!/usr/bin/make
+
+include $(IN)
+
+all:
+ rm -f $(OUT)
+ touch $(OUT)
+ for locale in $(SUPPORTED-LOCALES); do \
+ [ $$locale = true ] && continue; \
+ echo $$locale | sed 's,/, ,' >> $(OUT); \
+ done
diff --git a/recipes-core/glibc/glibc/glibc.fix_sqrt2.patch b/recipes-core/glibc/glibc/glibc.fix_sqrt2.patch
new file mode 100644
index 0000000..f5ed1bf
--- /dev/null
+++ b/recipes-core/glibc/glibc/glibc.fix_sqrt2.patch
@@ -0,0 +1,1516 @@
+Signed-of-by: Edmar Wienskoski <edmar at freescale.com>
+Upstream-Status: Pending
+
+Index: git/sysdeps/powerpc/powerpc32/603e/fpu/e_sqrt.c
+===================================================================
+--- /dev/null 1970-01-01 00:00:00.000000000 +0000
++++ git/sysdeps/powerpc/powerpc32/603e/fpu/e_sqrt.c 2014-08-29 10:34:07.768070587 -0700
+@@ -0,0 +1,134 @@
++/* Double-precision floating point square root.
++ Copyright (C) 2010 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 <math.h>
++#include <math_private.h>
++#include <fenv_libc.h>
++#include <inttypes.h>
++
++#include <sysdep.h>
++#include <ldsodefs.h>
++
++static const ieee_float_shape_type a_nan = {.word = 0x7fc00000 };
++static const ieee_float_shape_type a_inf = {.word = 0x7f800000 };
++static const float two108 = 3.245185536584267269e+32;
++static const float twom54 = 5.551115123125782702e-17;
++static const float half = 0.5;
++
++/* The method is based on the descriptions in:
++
++ _The Handbook of Floating-Pointer Arithmetic_ by Muller et al., chapter 5;
++ _IA-64 and Elementary Functions: Speed and Precision_ by Markstein, chapter 9
++
++ We find the actual square root and half of its reciprocal
++ simultaneously. */
++
++#ifdef __STDC__
++double
++__ieee754_sqrt (double b)
++#else
++double
++__ieee754_sqrt (b)
++ double b;
++#endif
++{
++ if (__builtin_expect (b > 0, 1))
++ {
++ double y, g, h, d, r;
++ ieee_double_shape_type u;
++
++ if (__builtin_expect (b != a_inf.value, 1))
++ {
++ fenv_t fe;
++
++ fe = fegetenv_register ();
++
++ u.value = b;
++
++ relax_fenv_state ();
++
++ __asm__ ("frsqrte %[estimate], %[x]\n"
++ : [estimate] "=f" (y) : [x] "f" (b));
++
++ /* Following Muller et al, page 168, equation 5.20.
++
++ h goes to 1/(2*sqrt(b))
++ g goes to sqrt(b).
++
++ We need three iterations to get within 1ulp. */
++
++ /* Indicate that these can be performed prior to the branch. GCC
++ insists on sinking them below the branch, however; it seems like
++ they'd be better before the branch so that we can cover any latency
++ from storing the argument and loading its high word. Oh well. */
++
++ g = b * y;
++ h = 0.5 * y;
++
++ /* Handle small numbers by scaling. */
++ if (__builtin_expect ((u.parts.msw & 0x7ff00000) <= 0x02000000, 0))
++ return __ieee754_sqrt (b * two108) * twom54;
++
++#define FMADD(a_, c_, b_) \
++ ({ double __r; \
++ __asm__ ("fmadd %[r], %[a], %[c], %[b]\n" \
++ : [r] "=f" (__r) : [a] "f" (a_), [c] "f" (c_), [b] "f" (b_)); \
++ __r;})
++#define FNMSUB(a_, c_, b_) \
++ ({ double __r; \
++ __asm__ ("fnmsub %[r], %[a], %[c], %[b]\n" \
++ : [r] "=f" (__r) : [a] "f" (a_), [c] "f" (c_), [b] "f" (b_)); \
++ __r;})
++
++ r = FNMSUB (g, h, half);
++ g = FMADD (g, r, g);
++ h = FMADD (h, r, h);
++
++ r = FNMSUB (g, h, half);
++ g = FMADD (g, r, g);
++ h = FMADD (h, r, h);
++
++ r = FNMSUB (g, h, half);
++ g = FMADD (g, r, g);
++ h = FMADD (h, r, h);
++
++ /* g is now +/- 1ulp, or exactly equal to, the square root of b. */
++
++ /* Final refinement. */
++ d = FNMSUB (g, g, b);
++
++ fesetenv_register (fe);
++ return FMADD (d, h, g);
++ }
++ }
++ else if (b < 0)
++ {
++ /* For some reason, some PowerPC32 processors don't implement
++ FE_INVALID_SQRT. */
++#ifdef FE_INVALID_SQRT
++ feraiseexcept (FE_INVALID_SQRT);
++
++ fenv_union_t u = { .fenv = fegetenv_register () };
++ if ((u.l & FE_INVALID) == 0)
++#endif
++ feraiseexcept (FE_INVALID);
++ b = a_nan.value;
++ }
++ return f_wash (b);
++}
+Index: git/sysdeps/powerpc/powerpc32/603e/fpu/e_sqrtf.c
+===================================================================
+--- /dev/null 1970-01-01 00:00:00.000000000 +0000
++++ git/sysdeps/powerpc/powerpc32/603e/fpu/e_sqrtf.c 2014-08-29 10:34:07.768070587 -0700
+@@ -0,0 +1,101 @@
++/* Single-precision floating point square root.
++ Copyright (C) 2010 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 <math.h>
++#include <math_private.h>
++#include <fenv_libc.h>
++#include <inttypes.h>
++
++#include <sysdep.h>
++#include <ldsodefs.h>
++
++static const ieee_float_shape_type a_nan = {.word = 0x7fc00000 };
++static const ieee_float_shape_type a_inf = {.word = 0x7f800000 };
++static const float threehalf = 1.5;
++
++/* The method is based on the descriptions in:
++
++ _The Handbook of Floating-Pointer Arithmetic_ by Muller et al., chapter 5;
++ _IA-64 and Elementary Functions: Speed and Precision_ by Markstein, chapter 9
++
++ We find the reciprocal square root and use that to compute the actual
++ square root. */
++
++#ifdef __STDC__
++float
++__ieee754_sqrtf (float b)
++#else
++float
++__ieee754_sqrtf (b)
++ float b;
++#endif
++{
++ if (__builtin_expect (b > 0, 1))
++ {
++#define FMSUB(a_, c_, b_) \
++ ({ double __r; \
++ __asm__ ("fmsub %[r], %[a], %[c], %[b]\n" \
++ : [r] "=f" (__r) : [a] "f" (a_), [c] "f" (c_), [b] "f" (b_)); \
++ __r;})
++#define FNMSUB(a_, c_, b_) \
++ ({ double __r; \
++ __asm__ ("fnmsub %[r], %[a], %[c], %[b]\n" \
++ : [r] "=f" (__r) : [a] "f" (a_), [c] "f" (c_), [b] "f" (b_)); \
++ __r;})
++
++ if (__builtin_expect (b != a_inf.value, 1))
++ {
++ double y, x;
++ fenv_t fe;
++
++ fe = fegetenv_register ();
++
++ relax_fenv_state ();
++
++ /* Compute y = 1.5 * b - b. Uses fewer constants than y = 0.5 * b. */
++ y = FMSUB (threehalf, b, b);
++
++ /* Initial estimate. */
++ __asm__ ("frsqrte %[x], %[b]\n" : [x] "=f" (x) : [b] "f" (b));
++
++ /* Iterate. x_{n+1} = x_n * (1.5 - y * (x_n * x_n)). */
++ x = x * FNMSUB (y, x * x, threehalf);
++ x = x * FNMSUB (y, x * x, threehalf);
++ x = x * FNMSUB (y, x * x, threehalf);
++
++ /* All done. */
++ fesetenv_register (fe);
++ return x * b;
++ }
++ }
++ else if (b < 0)
++ {
++ /* For some reason, some PowerPC32 processors don't implement
++ FE_INVALID_SQRT. */
++#ifdef FE_INVALID_SQRT
++ feraiseexcept (FE_INVALID_SQRT);
++
++ fenv_union_t u = { .fenv = fegetenv_register () };
++ if ((u.l & FE_INVALID) == 0)
++#endif
++ feraiseexcept (FE_INVALID);
++ b = a_nan.value;
++ }
++ return f_washf (b);
++}
+Index: git/sysdeps/powerpc/powerpc32/e500mc/fpu/e_sqrt.c
+===================================================================
+--- /dev/null 1970-01-01 00:00:00.000000000 +0000
++++ git/sysdeps/powerpc/powerpc32/e500mc/fpu/e_sqrt.c 2014-08-29 10:34:07.768070587 -0700
+@@ -0,0 +1,134 @@
++/* Double-precision floating point square root.
++ Copyright (C) 2010 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 <math.h>
++#include <math_private.h>
++#include <fenv_libc.h>
++#include <inttypes.h>
++
++#include <sysdep.h>
++#include <ldsodefs.h>
++
++static const ieee_float_shape_type a_nan = {.word = 0x7fc00000 };
++static const ieee_float_shape_type a_inf = {.word = 0x7f800000 };
++static const float two108 = 3.245185536584267269e+32;
++static const float twom54 = 5.551115123125782702e-17;
++static const float half = 0.5;
++
++/* The method is based on the descriptions in:
++
++ _The Handbook of Floating-Pointer Arithmetic_ by Muller et al., chapter 5;
++ _IA-64 and Elementary Functions: Speed and Precision_ by Markstein, chapter 9
++
++ We find the actual square root and half of its reciprocal
++ simultaneously. */
++
++#ifdef __STDC__
++double
++__ieee754_sqrt (double b)
++#else
++double
++__ieee754_sqrt (b)
++ double b;
++#endif
++{
++ if (__builtin_expect (b > 0, 1))
++ {
++ double y, g, h, d, r;
++ ieee_double_shape_type u;
++
++ if (__builtin_expect (b != a_inf.value, 1))
++ {
++ fenv_t fe;
++
++ fe = fegetenv_register ();
++
++ u.value = b;
++
++ relax_fenv_state ();
++
++ __asm__ ("frsqrte %[estimate], %[x]\n"
++ : [estimate] "=f" (y) : [x] "f" (b));
++
++ /* Following Muller et al, page 168, equation 5.20.
++
++ h goes to 1/(2*sqrt(b))
++ g goes to sqrt(b).
++
++ We need three iterations to get within 1ulp. */
++
++ /* Indicate that these can be performed prior to the branch. GCC
++ insists on sinking them below the branch, however; it seems like
++ they'd be better before the branch so that we can cover any latency
++ from storing the argument and loading its high word. Oh well. */
++
++ g = b * y;
++ h = 0.5 * y;
++
++ /* Handle small numbers by scaling. */
++ if (__builtin_expect ((u.parts.msw & 0x7ff00000) <= 0x02000000, 0))
++ return __ieee754_sqrt (b * two108) * twom54;
++
++#define FMADD(a_, c_, b_) \
++ ({ double __r; \
++ __asm__ ("fmadd %[r], %[a], %[c], %[b]\n" \
++ : [r] "=f" (__r) : [a] "f" (a_), [c] "f" (c_), [b] "f" (b_)); \
++ __r;})
++#define FNMSUB(a_, c_, b_) \
++ ({ double __r; \
++ __asm__ ("fnmsub %[r], %[a], %[c], %[b]\n" \
++ : [r] "=f" (__r) : [a] "f" (a_), [c] "f" (c_), [b] "f" (b_)); \
++ __r;})
++
++ r = FNMSUB (g, h, half);
++ g = FMADD (g, r, g);
++ h = FMADD (h, r, h);
++
++ r = FNMSUB (g, h, half);
++ g = FMADD (g, r, g);
++ h = FMADD (h, r, h);
++
++ r = FNMSUB (g, h, half);
++ g = FMADD (g, r, g);
++ h = FMADD (h, r, h);
++
++ /* g is now +/- 1ulp, or exactly equal to, the square root of b. */
++
++ /* Final refinement. */
++ d = FNMSUB (g, g, b);
++
++ fesetenv_register (fe);
++ return FMADD (d, h, g);
++ }
++ }
++ else if (b < 0)
++ {
++ /* For some reason, some PowerPC32 processors don't implement
++ FE_INVALID_SQRT. */
++#ifdef FE_INVALID_SQRT
++ feraiseexcept (FE_INVALID_SQRT);
++
++ fenv_union_t u = { .fenv = fegetenv_register () };
++ if ((u.l & FE_INVALID) == 0)
++#endif
++ feraiseexcept (FE_INVALID);
++ b = a_nan.value;
++ }
++ return f_wash (b);
++}
+Index: git/sysdeps/powerpc/powerpc32/e500mc/fpu/e_sqrtf.c
+===================================================================
+--- /dev/null 1970-01-01 00:00:00.000000000 +0000
++++ git/sysdeps/powerpc/powerpc32/e500mc/fpu/e_sqrtf.c 2014-08-29 10:34:07.772070587 -0700
+@@ -0,0 +1,101 @@
++/* Single-precision floating point square root.
++ Copyright (C) 2010 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 <math.h>
++#include <math_private.h>
++#include <fenv_libc.h>
++#include <inttypes.h>
++
++#include <sysdep.h>
++#include <ldsodefs.h>
++
++static const ieee_float_shape_type a_nan = {.word = 0x7fc00000 };
++static const ieee_float_shape_type a_inf = {.word = 0x7f800000 };
++static const float threehalf = 1.5;
++
++/* The method is based on the descriptions in:
++
++ _The Handbook of Floating-Pointer Arithmetic_ by Muller et al., chapter 5;
++ _IA-64 and Elementary Functions: Speed and Precision_ by Markstein, chapter 9
++
++ We find the reciprocal square root and use that to compute the actual
++ square root. */
++
++#ifdef __STDC__
++float
++__ieee754_sqrtf (float b)
++#else
++float
++__ieee754_sqrtf (b)
++ float b;
++#endif
++{
++ if (__builtin_expect (b > 0, 1))
++ {
++#define FMSUB(a_, c_, b_) \
++ ({ double __r; \
++ __asm__ ("fmsub %[r], %[a], %[c], %[b]\n" \
++ : [r] "=f" (__r) : [a] "f" (a_), [c] "f" (c_), [b] "f" (b_)); \
++ __r;})
++#define FNMSUB(a_, c_, b_) \
++ ({ double __r; \
++ __asm__ ("fnmsub %[r], %[a], %[c], %[b]\n" \
++ : [r] "=f" (__r) : [a] "f" (a_), [c] "f" (c_), [b] "f" (b_)); \
++ __r;})
++
++ if (__builtin_expect (b != a_inf.value, 1))
++ {
++ double y, x;
++ fenv_t fe;
++
++ fe = fegetenv_register ();
++
++ relax_fenv_state ();
++
++ /* Compute y = 1.5 * b - b. Uses fewer constants than y = 0.5 * b. */
++ y = FMSUB (threehalf, b, b);
++
++ /* Initial estimate. */
++ __asm__ ("frsqrte %[x], %[b]\n" : [x] "=f" (x) : [b] "f" (b));
++
++ /* Iterate. x_{n+1} = x_n * (1.5 - y * (x_n * x_n)). */
++ x = x * FNMSUB (y, x * x, threehalf);
++ x = x * FNMSUB (y, x * x, threehalf);
++ x = x * FNMSUB (y, x * x, threehalf);
++
++ /* All done. */
++ fesetenv_register (fe);
++ return x * b;
++ }
++ }
++ else if (b < 0)
++ {
++ /* For some reason, some PowerPC32 processors don't implement
++ FE_INVALID_SQRT. */
++#ifdef FE_INVALID_SQRT
++ feraiseexcept (FE_INVALID_SQRT);
++
++ fenv_union_t u = { .fenv = fegetenv_register () };
++ if ((u.l & FE_INVALID) == 0)
++#endif
++ feraiseexcept (FE_INVALID);
++ b = a_nan.value;
++ }
++ return f_washf (b);
++}
+Index: git/sysdeps/powerpc/powerpc32/e5500/fpu/e_sqrt.c
+===================================================================
+--- /dev/null 1970-01-01 00:00:00.000000000 +0000
++++ git/sysdeps/powerpc/powerpc32/e5500/fpu/e_sqrt.c 2014-08-29 10:34:07.772070587 -0700
+@@ -0,0 +1,134 @@
++/* Double-precision floating point square root.
++ Copyright (C) 2010 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 <math.h>
++#include <math_private.h>
++#include <fenv_libc.h>
++#include <inttypes.h>
++
++#include <sysdep.h>
++#include <ldsodefs.h>
++
++static const ieee_float_shape_type a_nan = {.word = 0x7fc00000 };
++static const ieee_float_shape_type a_inf = {.word = 0x7f800000 };
++static const float two108 = 3.245185536584267269e+32;
++static const float twom54 = 5.551115123125782702e-17;
++static const float half = 0.5;
++
++/* The method is based on the descriptions in:
++
++ _The Handbook of Floating-Pointer Arithmetic_ by Muller et al., chapter 5;
++ _IA-64 and Elementary Functions: Speed and Precision_ by Markstein, chapter 9
++
++ We find the actual square root and half of its reciprocal
++ simultaneously. */
++
++#ifdef __STDC__
++double
++__ieee754_sqrt (double b)
++#else
++double
++__ieee754_sqrt (b)
++ double b;
++#endif
++{
++ if (__builtin_expect (b > 0, 1))
++ {
++ double y, g, h, d, r;
++ ieee_double_shape_type u;
++
++ if (__builtin_expect (b != a_inf.value, 1))
++ {
++ fenv_t fe;
++
++ fe = fegetenv_register ();
++
++ u.value = b;
++
++ relax_fenv_state ();
++
++ __asm__ ("frsqrte %[estimate], %[x]\n"
++ : [estimate] "=f" (y) : [x] "f" (b));
++
++ /* Following Muller et al, page 168, equation 5.20.
++
++ h goes to 1/(2*sqrt(b))
++ g goes to sqrt(b).
++
++ We need three iterations to get within 1ulp. */
++
++ /* Indicate that these can be performed prior to the branch. GCC
++ insists on sinking them below the branch, however; it seems like
++ they'd be better before the branch so that we can cover any latency
++ from storing the argument and loading its high word. Oh well. */
++
++ g = b * y;
++ h = 0.5 * y;
++
++ /* Handle small numbers by scaling. */
++ if (__builtin_expect ((u.parts.msw & 0x7ff00000) <= 0x02000000, 0))
++ return __ieee754_sqrt (b * two108) * twom54;
++
++#define FMADD(a_, c_, b_) \
++ ({ double __r; \
++ __asm__ ("fmadd %[r], %[a], %[c], %[b]\n" \
++ : [r] "=f" (__r) : [a] "f" (a_), [c] "f" (c_), [b] "f" (b_)); \
++ __r;})
++#define FNMSUB(a_, c_, b_) \
++ ({ double __r; \
++ __asm__ ("fnmsub %[r], %[a], %[c], %[b]\n" \
++ : [r] "=f" (__r) : [a] "f" (a_), [c] "f" (c_), [b] "f" (b_)); \
++ __r;})
++
++ r = FNMSUB (g, h, half);
++ g = FMADD (g, r, g);
++ h = FMADD (h, r, h);
++
++ r = FNMSUB (g, h, half);
++ g = FMADD (g, r, g);
++ h = FMADD (h, r, h);
++
++ r = FNMSUB (g, h, half);
++ g = FMADD (g, r, g);
++ h = FMADD (h, r, h);
++
++ /* g is now +/- 1ulp, or exactly equal to, the square root of b. */
++
++ /* Final refinement. */
++ d = FNMSUB (g, g, b);
++
++ fesetenv_register (fe);
++ return FMADD (d, h, g);
++ }
++ }
++ else if (b < 0)
++ {
++ /* For some reason, some PowerPC32 processors don't implement
++ FE_INVALID_SQRT. */
++#ifdef FE_INVALID_SQRT
++ feraiseexcept (FE_INVALID_SQRT);
++
++ fenv_union_t u = { .fenv = fegetenv_register () };
++ if ((u.l & FE_INVALID) == 0)
++#endif
++ feraiseexcept (FE_INVALID);
++ b = a_nan.value;
++ }
++ return f_wash (b);
++}
+Index: git/sysdeps/powerpc/powerpc32/e5500/fpu/e_sqrtf.c
+===================================================================
+--- /dev/null 1970-01-01 00:00:00.000000000 +0000
++++ git/sysdeps/powerpc/powerpc32/e5500/fpu/e_sqrtf.c 2014-08-29 10:34:07.772070587 -0700
+@@ -0,0 +1,101 @@
++/* Single-precision floating point square root.
++ Copyright (C) 2010 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 <math.h>
++#include <math_private.h>
++#include <fenv_libc.h>
++#include <inttypes.h>
++
++#include <sysdep.h>
++#include <ldsodefs.h>
++
++static const ieee_float_shape_type a_nan = {.word = 0x7fc00000 };
++static const ieee_float_shape_type a_inf = {.word = 0x7f800000 };
++static const float threehalf = 1.5;
++
++/* The method is based on the descriptions in:
++
++ _The Handbook of Floating-Pointer Arithmetic_ by Muller et al., chapter 5;
++ _IA-64 and Elementary Functions: Speed and Precision_ by Markstein, chapter 9
++
++ We find the reciprocal square root and use that to compute the actual
++ square root. */
++
++#ifdef __STDC__
++float
++__ieee754_sqrtf (float b)
++#else
++float
++__ieee754_sqrtf (b)
++ float b;
++#endif
++{
++ if (__builtin_expect (b > 0, 1))
++ {
++#define FMSUB(a_, c_, b_) \
++ ({ double __r; \
++ __asm__ ("fmsub %[r], %[a], %[c], %[b]\n" \
++ : [r] "=f" (__r) : [a] "f" (a_), [c] "f" (c_), [b] "f" (b_)); \
++ __r;})
++#define FNMSUB(a_, c_, b_) \
++ ({ double __r; \
++ __asm__ ("fnmsub %[r], %[a], %[c], %[b]\n" \
++ : [r] "=f" (__r) : [a] "f" (a_), [c] "f" (c_), [b] "f" (b_)); \
++ __r;})
++
++ if (__builtin_expect (b != a_inf.value, 1))
++ {
++ double y, x;
++ fenv_t fe;
++
++ fe = fegetenv_register ();
++
++ relax_fenv_state ();
++
++ /* Compute y = 1.5 * b - b. Uses fewer constants than y = 0.5 * b. */
++ y = FMSUB (threehalf, b, b);
++
++ /* Initial estimate. */
++ __asm__ ("frsqrte %[x], %[b]\n" : [x] "=f" (x) : [b] "f" (b));
++
++ /* Iterate. x_{n+1} = x_n * (1.5 - y * (x_n * x_n)). */
++ x = x * FNMSUB (y, x * x, threehalf);
++ x = x * FNMSUB (y, x * x, threehalf);
++ x = x * FNMSUB (y, x * x, threehalf);
++
++ /* All done. */
++ fesetenv_register (fe);
++ return x * b;
++ }
++ }
++ else if (b < 0)
++ {
++ /* For some reason, some PowerPC32 processors don't implement
++ FE_INVALID_SQRT. */
++#ifdef FE_INVALID_SQRT
++ feraiseexcept (FE_INVALID_SQRT);
++
++ fenv_union_t u = { .fenv = fegetenv_register () };
++ if ((u.l & FE_INVALID) == 0)
++#endif
++ feraiseexcept (FE_INVALID);
++ b = a_nan.value;
++ }
++ return f_washf (b);
++}
+Index: git/sysdeps/powerpc/powerpc32/e6500/fpu/e_sqrt.c
+===================================================================
+--- /dev/null 1970-01-01 00:00:00.000000000 +0000
++++ git/sysdeps/powerpc/powerpc32/e6500/fpu/e_sqrt.c 2014-08-29 10:34:07.772070587 -0700
+@@ -0,0 +1,134 @@
++/* Double-precision floating point square root.
++ Copyright (C) 2010 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 <math.h>
++#include <math_private.h>
++#include <fenv_libc.h>
++#include <inttypes.h>
++
++#include <sysdep.h>
++#include <ldsodefs.h>
++
++static const ieee_float_shape_type a_nan = {.word = 0x7fc00000 };
++static const ieee_float_shape_type a_inf = {.word = 0x7f800000 };
++static const float two108 = 3.245185536584267269e+32;
++static const float twom54 = 5.551115123125782702e-17;
++static const float half = 0.5;
++
++/* The method is based on the descriptions in:
++
++ _The Handbook of Floating-Pointer Arithmetic_ by Muller et al., chapter 5;
++ _IA-64 and Elementary Functions: Speed and Precision_ by Markstein, chapter 9
++
++ We find the actual square root and half of its reciprocal
++ simultaneously. */
++
++#ifdef __STDC__
++double
++__ieee754_sqrt (double b)
++#else
++double
++__ieee754_sqrt (b)
++ double b;
++#endif
++{
++ if (__builtin_expect (b > 0, 1))
++ {
++ double y, g, h, d, r;
++ ieee_double_shape_type u;
++
++ if (__builtin_expect (b != a_inf.value, 1))
++ {
++ fenv_t fe;
++
++ fe = fegetenv_register ();
++
++ u.value = b;
++
++ relax_fenv_state ();
++
++ __asm__ ("frsqrte %[estimate], %[x]\n"
++ : [estimate] "=f" (y) : [x] "f" (b));
++
++ /* Following Muller et al, page 168, equation 5.20.
++
++ h goes to 1/(2*sqrt(b))
++ g goes to sqrt(b).
++
++ We need three iterations to get within 1ulp. */
++
++ /* Indicate that these can be performed prior to the branch. GCC
++ insists on sinking them below the branch, however; it seems like
++ they'd be better before the branch so that we can cover any latency
++ from storing the argument and loading its high word. Oh well. */
++
++ g = b * y;
++ h = 0.5 * y;
++
++ /* Handle small numbers by scaling. */
++ if (__builtin_expect ((u.parts.msw & 0x7ff00000) <= 0x02000000, 0))
++ return __ieee754_sqrt (b * two108) * twom54;
++
++#define FMADD(a_, c_, b_) \
++ ({ double __r; \
++ __asm__ ("fmadd %[r], %[a], %[c], %[b]\n" \
++ : [r] "=f" (__r) : [a] "f" (a_), [c] "f" (c_), [b] "f" (b_)); \
++ __r;})
++#define FNMSUB(a_, c_, b_) \
++ ({ double __r; \
++ __asm__ ("fnmsub %[r], %[a], %[c], %[b]\n" \
++ : [r] "=f" (__r) : [a] "f" (a_), [c] "f" (c_), [b] "f" (b_)); \
++ __r;})
++
++ r = FNMSUB (g, h, half);
++ g = FMADD (g, r, g);
++ h = FMADD (h, r, h);
++
++ r = FNMSUB (g, h, half);
++ g = FMADD (g, r, g);
++ h = FMADD (h, r, h);
++
++ r = FNMSUB (g, h, half);
++ g = FMADD (g, r, g);
++ h = FMADD (h, r, h);
++
++ /* g is now +/- 1ulp, or exactly equal to, the square root of b. */
++
++ /* Final refinement. */
++ d = FNMSUB (g, g, b);
++
++ fesetenv_register (fe);
++ return FMADD (d, h, g);
++ }
++ }
++ else if (b < 0)
++ {
++ /* For some reason, some PowerPC32 processors don't implement
++ FE_INVALID_SQRT. */
++#ifdef FE_INVALID_SQRT
++ feraiseexcept (FE_INVALID_SQRT);
++
++ fenv_union_t u = { .fenv = fegetenv_register () };
++ if ((u.l & FE_INVALID) == 0)
++#endif
++ feraiseexcept (FE_INVALID);
++ b = a_nan.value;
++ }
++ return f_wash (b);
++}
+Index: git/sysdeps/powerpc/powerpc32/e6500/fpu/e_sqrtf.c
+===================================================================
+--- /dev/null 1970-01-01 00:00:00.000000000 +0000
++++ git/sysdeps/powerpc/powerpc32/e6500/fpu/e_sqrtf.c 2014-08-29 10:34:07.772070587 -0700
+@@ -0,0 +1,101 @@
++/* Single-precision floating point square root.
++ Copyright (C) 2010 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 <math.h>
++#include <math_private.h>
++#include <fenv_libc.h>
++#include <inttypes.h>
++
++#include <sysdep.h>
++#include <ldsodefs.h>
++
++static const ieee_float_shape_type a_nan = {.word = 0x7fc00000 };
++static const ieee_float_shape_type a_inf = {.word = 0x7f800000 };
++static const float threehalf = 1.5;
++
++/* The method is based on the descriptions in:
++
++ _The Handbook of Floating-Pointer Arithmetic_ by Muller et al., chapter 5;
++ _IA-64 and Elementary Functions: Speed and Precision_ by Markstein, chapter 9
++
++ We find the reciprocal square root and use that to compute the actual
++ square root. */
++
++#ifdef __STDC__
++float
++__ieee754_sqrtf (float b)
++#else
++float
++__ieee754_sqrtf (b)
++ float b;
++#endif
++{
++ if (__builtin_expect (b > 0, 1))
++ {
++#define FMSUB(a_, c_, b_) \
++ ({ double __r; \
++ __asm__ ("fmsub %[r], %[a], %[c], %[b]\n" \
++ : [r] "=f" (__r) : [a] "f" (a_), [c] "f" (c_), [b] "f" (b_)); \
++ __r;})
++#define FNMSUB(a_, c_, b_) \
++ ({ double __r; \
++ __asm__ ("fnmsub %[r], %[a], %[c], %[b]\n" \
++ : [r] "=f" (__r) : [a] "f" (a_), [c] "f" (c_), [b] "f" (b_)); \
++ __r;})
++
++ if (__builtin_expect (b != a_inf.value, 1))
++ {
++ double y, x;
++ fenv_t fe;
++
++ fe = fegetenv_register ();
++
++ relax_fenv_state ();
++
++ /* Compute y = 1.5 * b - b. Uses fewer constants than y = 0.5 * b. */
++ y = FMSUB (threehalf, b, b);
++
++ /* Initial estimate. */
++ __asm__ ("frsqrte %[x], %[b]\n" : [x] "=f" (x) : [b] "f" (b));
++
++ /* Iterate. x_{n+1} = x_n * (1.5 - y * (x_n * x_n)). */
++ x = x * FNMSUB (y, x * x, threehalf);
++ x = x * FNMSUB (y, x * x, threehalf);
++ x = x * FNMSUB (y, x * x, threehalf);
++
++ /* All done. */
++ fesetenv_register (fe);
++ return x * b;
++ }
++ }
++ else if (b < 0)
++ {
++ /* For some reason, some PowerPC32 processors don't implement
++ FE_INVALID_SQRT. */
++#ifdef FE_INVALID_SQRT
++ feraiseexcept (FE_INVALID_SQRT);
++
++ fenv_union_t u = { .fenv = fegetenv_register () };
++ if ((u.l & FE_INVALID) == 0)
++#endif
++ feraiseexcept (FE_INVALID);
++ b = a_nan.value;
++ }
++ return f_washf (b);
++}
+Index: git/sysdeps/powerpc/powerpc64/e5500/fpu/e_sqrt.c
+===================================================================
+--- /dev/null 1970-01-01 00:00:00.000000000 +0000
++++ git/sysdeps/powerpc/powerpc64/e5500/fpu/e_sqrt.c 2014-08-29 10:34:07.772070587 -0700
+@@ -0,0 +1,134 @@
++/* Double-precision floating point square root.
++ Copyright (C) 2010 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 <math.h>
++#include <math_private.h>
++#include <fenv_libc.h>
++#include <inttypes.h>
++
++#include <sysdep.h>
++#include <ldsodefs.h>
++
++static const ieee_float_shape_type a_nan = {.word = 0x7fc00000 };
++static const ieee_float_shape_type a_inf = {.word = 0x7f800000 };
++static const float two108 = 3.245185536584267269e+32;
++static const float twom54 = 5.551115123125782702e-17;
++static const float half = 0.5;
++
++/* The method is based on the descriptions in:
++
++ _The Handbook of Floating-Pointer Arithmetic_ by Muller et al., chapter 5;
++ _IA-64 and Elementary Functions: Speed and Precision_ by Markstein, chapter 9
++
++ We find the actual square root and half of its reciprocal
++ simultaneously. */
++
++#ifdef __STDC__
++double
++__ieee754_sqrt (double b)
++#else
++double
++__ieee754_sqrt (b)
++ double b;
++#endif
++{
++ if (__builtin_expect (b > 0, 1))
++ {
++ double y, g, h, d, r;
++ ieee_double_shape_type u;
++
++ if (__builtin_expect (b != a_inf.value, 1))
++ {
++ fenv_t fe;
++
++ fe = fegetenv_register ();
++
++ u.value = b;
++
++ relax_fenv_state ();
++
++ __asm__ ("frsqrte %[estimate], %[x]\n"
++ : [estimate] "=f" (y) : [x] "f" (b));
++
++ /* Following Muller et al, page 168, equation 5.20.
++
++ h goes to 1/(2*sqrt(b))
++ g goes to sqrt(b).
++
++ We need three iterations to get within 1ulp. */
++
++ /* Indicate that these can be performed prior to the branch. GCC
++ insists on sinking them below the branch, however; it seems like
++ they'd be better before the branch so that we can cover any latency
++ from storing the argument and loading its high word. Oh well. */
++
++ g = b * y;
++ h = 0.5 * y;
++
++ /* Handle small numbers by scaling. */
++ if (__builtin_expect ((u.parts.msw & 0x7ff00000) <= 0x02000000, 0))
++ return __ieee754_sqrt (b * two108) * twom54;
++
++#define FMADD(a_, c_, b_) \
++ ({ double __r; \
++ __asm__ ("fmadd %[r], %[a], %[c], %[b]\n" \
++ : [r] "=f" (__r) : [a] "f" (a_), [c] "f" (c_), [b] "f" (b_)); \
++ __r;})
++#define FNMSUB(a_, c_, b_) \
++ ({ double __r; \
++ __asm__ ("fnmsub %[r], %[a], %[c], %[b]\n" \
++ : [r] "=f" (__r) : [a] "f" (a_), [c] "f" (c_), [b] "f" (b_)); \
++ __r;})
++
++ r = FNMSUB (g, h, half);
++ g = FMADD (g, r, g);
++ h = FMADD (h, r, h);
++
++ r = FNMSUB (g, h, half);
++ g = FMADD (g, r, g);
++ h = FMADD (h, r, h);
++
++ r = FNMSUB (g, h, half);
++ g = FMADD (g, r, g);
++ h = FMADD (h, r, h);
++
++ /* g is now +/- 1ulp, or exactly equal to, the square root of b. */
++
++ /* Final refinement. */
++ d = FNMSUB (g, g, b);
++
++ fesetenv_register (fe);
++ return FMADD (d, h, g);
++ }
++ }
++ else if (b < 0)
++ {
++ /* For some reason, some PowerPC32 processors don't implement
++ FE_INVALID_SQRT. */
++#ifdef FE_INVALID_SQRT
++ feraiseexcept (FE_INVALID_SQRT);
++
++ fenv_union_t u = { .fenv = fegetenv_register () };
++ if ((u.l & FE_INVALID) == 0)
++#endif
++ feraiseexcept (FE_INVALID);
++ b = a_nan.value;
++ }
++ return f_wash (b);
++}
+Index: git/sysdeps/powerpc/powerpc64/e5500/fpu/e_sqrtf.c
+===================================================================
+--- /dev/null 1970-01-01 00:00:00.000000000 +0000
++++ git/sysdeps/powerpc/powerpc64/e5500/fpu/e_sqrtf.c 2014-08-29 10:34:07.772070587 -0700
+@@ -0,0 +1,101 @@
++/* Single-precision floating point square root.
++ Copyright (C) 2010 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 <math.h>
++#include <math_private.h>
++#include <fenv_libc.h>
++#include <inttypes.h>
++
++#include <sysdep.h>
++#include <ldsodefs.h>
++
++static const ieee_float_shape_type a_nan = {.word = 0x7fc00000 };
++static const ieee_float_shape_type a_inf = {.word = 0x7f800000 };
++static const float threehalf = 1.5;
++
++/* The method is based on the descriptions in:
++
++ _The Handbook of Floating-Pointer Arithmetic_ by Muller et al., chapter 5;
++ _IA-64 and Elementary Functions: Speed and Precision_ by Markstein, chapter 9
++
++ We find the reciprocal square root and use that to compute the actual
++ square root. */
++
++#ifdef __STDC__
++float
++__ieee754_sqrtf (float b)
++#else
++float
++__ieee754_sqrtf (b)
++ float b;
++#endif
++{
++ if (__builtin_expect (b > 0, 1))
++ {
++#define FMSUB(a_, c_, b_) \
++ ({ double __r; \
++ __asm__ ("fmsub %[r], %[a], %[c], %[b]\n" \
++ : [r] "=f" (__r) : [a] "f" (a_), [c] "f" (c_), [b] "f" (b_)); \
++ __r;})
++#define FNMSUB(a_, c_, b_) \
++ ({ double __r; \
++ __asm__ ("fnmsub %[r], %[a], %[c], %[b]\n" \
++ : [r] "=f" (__r) : [a] "f" (a_), [c] "f" (c_), [b] "f" (b_)); \
++ __r;})
++
++ if (__builtin_expect (b != a_inf.value, 1))
++ {
++ double y, x;
++ fenv_t fe;
++
++ fe = fegetenv_register ();
++
++ relax_fenv_state ();
++
++ /* Compute y = 1.5 * b - b. Uses fewer constants than y = 0.5 * b. */
++ y = FMSUB (threehalf, b, b);
++
++ /* Initial estimate. */
++ __asm__ ("frsqrte %[x], %[b]\n" : [x] "=f" (x) : [b] "f" (b));
++
++ /* Iterate. x_{n+1} = x_n * (1.5 - y * (x_n * x_n)). */
++ x = x * FNMSUB (y, x * x, threehalf);
++ x = x * FNMSUB (y, x * x, threehalf);
++ x = x * FNMSUB (y, x * x, threehalf);
++
++ /* All done. */
++ fesetenv_register (fe);
++ return x * b;
++ }
++ }
++ else if (b < 0)
++ {
++ /* For some reason, some PowerPC32 processors don't implement
++ FE_INVALID_SQRT. */
++#ifdef FE_INVALID_SQRT
++ feraiseexcept (FE_INVALID_SQRT);
++
++ fenv_union_t u = { .fenv = fegetenv_register () };
++ if ((u.l & FE_INVALID) == 0)
++#endif
++ feraiseexcept (FE_INVALID);
++ b = a_nan.value;
++ }
++ return f_washf (b);
++}
+Index: git/sysdeps/powerpc/powerpc64/e6500/fpu/e_sqrt.c
+===================================================================
+--- /dev/null 1970-01-01 00:00:00.000000000 +0000
++++ git/sysdeps/powerpc/powerpc64/e6500/fpu/e_sqrt.c 2014-08-29 10:34:07.772070587 -0700
+@@ -0,0 +1,134 @@
++/* Double-precision floating point square root.
++ Copyright (C) 2010 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 <math.h>
++#include <math_private.h>
++#include <fenv_libc.h>
++#include <inttypes.h>
++
++#include <sysdep.h>
++#include <ldsodefs.h>
++
++static const ieee_float_shape_type a_nan = {.word = 0x7fc00000 };
++static const ieee_float_shape_type a_inf = {.word = 0x7f800000 };
++static const float two108 = 3.245185536584267269e+32;
++static const float twom54 = 5.551115123125782702e-17;
++static const float half = 0.5;
++
++/* The method is based on the descriptions in:
++
++ _The Handbook of Floating-Pointer Arithmetic_ by Muller et al., chapter 5;
++ _IA-64 and Elementary Functions: Speed and Precision_ by Markstein, chapter 9
++
++ We find the actual square root and half of its reciprocal
++ simultaneously. */
++
++#ifdef __STDC__
++double
++__ieee754_sqrt (double b)
++#else
++double
++__ieee754_sqrt (b)
++ double b;
++#endif
++{
++ if (__builtin_expect (b > 0, 1))
++ {
++ double y, g, h, d, r;
++ ieee_double_shape_type u;
++
++ if (__builtin_expect (b != a_inf.value, 1))
++ {
++ fenv_t fe;
++
++ fe = fegetenv_register ();
++
++ u.value = b;
++
++ relax_fenv_state ();
++
++ __asm__ ("frsqrte %[estimate], %[x]\n"
++ : [estimate] "=f" (y) : [x] "f" (b));
++
++ /* Following Muller et al, page 168, equation 5.20.
++
++ h goes to 1/(2*sqrt(b))
++ g goes to sqrt(b).
++
++ We need three iterations to get within 1ulp. */
++
++ /* Indicate that these can be performed prior to the branch. GCC
++ insists on sinking them below the branch, however; it seems like
++ they'd be better before the branch so that we can cover any latency
++ from storing the argument and loading its high word. Oh well. */
++
++ g = b * y;
++ h = 0.5 * y;
++
++ /* Handle small numbers by scaling. */
++ if (__builtin_expect ((u.parts.msw & 0x7ff00000) <= 0x02000000, 0))
++ return __ieee754_sqrt (b * two108) * twom54;
++
++#define FMADD(a_, c_, b_) \
++ ({ double __r; \
++ __asm__ ("fmadd %[r], %[a], %[c], %[b]\n" \
++ : [r] "=f" (__r) : [a] "f" (a_), [c] "f" (c_), [b] "f" (b_)); \
++ __r;})
++#define FNMSUB(a_, c_, b_) \
++ ({ double __r; \
++ __asm__ ("fnmsub %[r], %[a], %[c], %[b]\n" \
++ : [r] "=f" (__r) : [a] "f" (a_), [c] "f" (c_), [b] "f" (b_)); \
++ __r;})
++
++ r = FNMSUB (g, h, half);
++ g = FMADD (g, r, g);
++ h = FMADD (h, r, h);
++
++ r = FNMSUB (g, h, half);
++ g = FMADD (g, r, g);
++ h = FMADD (h, r, h);
++
++ r = FNMSUB (g, h, half);
++ g = FMADD (g, r, g);
++ h = FMADD (h, r, h);
++
++ /* g is now +/- 1ulp, or exactly equal to, the square root of b. */
++
++ /* Final refinement. */
++ d = FNMSUB (g, g, b);
++
++ fesetenv_register (fe);
++ return FMADD (d, h, g);
++ }
++ }
++ else if (b < 0)
++ {
++ /* For some reason, some PowerPC32 processors don't implement
++ FE_INVALID_SQRT. */
++#ifdef FE_INVALID_SQRT
++ feraiseexcept (FE_INVALID_SQRT);
++
++ fenv_union_t u = { .fenv = fegetenv_register () };
++ if ((u.l & FE_INVALID) == 0)
++#endif
++ feraiseexcept (FE_INVALID);
++ b = a_nan.value;
++ }
++ return f_wash (b);
++}
+Index: git/sysdeps/powerpc/powerpc64/e6500/fpu/e_sqrtf.c
+===================================================================
+--- /dev/null 1970-01-01 00:00:00.000000000 +0000
++++ git/sysdeps/powerpc/powerpc64/e6500/fpu/e_sqrtf.c 2014-08-29 10:34:07.776070587 -0700
+@@ -0,0 +1,101 @@
++/* Single-precision floating point square root.
++ Copyright (C) 2010 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 <math.h>
++#include <math_private.h>
++#include <fenv_libc.h>
++#include <inttypes.h>
++
++#include <sysdep.h>
++#include <ldsodefs.h>
++
++static const ieee_float_shape_type a_nan = {.word = 0x7fc00000 };
++static const ieee_float_shape_type a_inf = {.word = 0x7f800000 };
++static const float threehalf = 1.5;
++
++/* The method is based on the descriptions in:
++
++ _The Handbook of Floating-Pointer Arithmetic_ by Muller et al., chapter 5;
++ _IA-64 and Elementary Functions: Speed and Precision_ by Markstein, chapter 9
++
++ We find the reciprocal square root and use that to compute the actual
++ square root. */
++
++#ifdef __STDC__
++float
++__ieee754_sqrtf (float b)
++#else
++float
++__ieee754_sqrtf (b)
++ float b;
++#endif
++{
++ if (__builtin_expect (b > 0, 1))
++ {
++#define FMSUB(a_, c_, b_) \
++ ({ double __r; \
++ __asm__ ("fmsub %[r], %[a], %[c], %[b]\n" \
++ : [r] "=f" (__r) : [a] "f" (a_), [c] "f" (c_), [b] "f" (b_)); \
++ __r;})
++#define FNMSUB(a_, c_, b_) \
++ ({ double __r; \
++ __asm__ ("fnmsub %[r], %[a], %[c], %[b]\n" \
++ : [r] "=f" (__r) : [a] "f" (a_), [c] "f" (c_), [b] "f" (b_)); \
++ __r;})
++
++ if (__builtin_expect (b != a_inf.value, 1))
++ {
++ double y, x;
++ fenv_t fe;
++
++ fe = fegetenv_register ();
++
++ relax_fenv_state ();
++
++ /* Compute y = 1.5 * b - b. Uses fewer constants than y = 0.5 * b. */
++ y = FMSUB (threehalf, b, b);
++
++ /* Initial estimate. */
++ __asm__ ("frsqrte %[x], %[b]\n" : [x] "=f" (x) : [b] "f" (b));
++
++ /* Iterate. x_{n+1} = x_n * (1.5 - y * (x_n * x_n)). */
++ x = x * FNMSUB (y, x * x, threehalf);
++ x = x * FNMSUB (y, x * x, threehalf);
++ x = x * FNMSUB (y, x * x, threehalf);
++
++ /* All done. */
++ fesetenv_register (fe);
++ return x * b;
++ }
++ }
++ else if (b < 0)
++ {
++ /* For some reason, some PowerPC32 processors don't implement
++ FE_INVALID_SQRT. */
++#ifdef FE_INVALID_SQRT
++ feraiseexcept (FE_INVALID_SQRT);
++
++ fenv_union_t u = { .fenv = fegetenv_register () };
++ if ((u.l & FE_INVALID) == 0)
++#endif
++ feraiseexcept (FE_INVALID);
++ b = a_nan.value;
++ }
++ return f_washf (b);
++}
+Index: git/sysdeps/unix/sysv/linux/powerpc/powerpc32/603e/fpu/Implies
+===================================================================
+--- /dev/null 1970-01-01 00:00:00.000000000 +0000
++++ git/sysdeps/unix/sysv/linux/powerpc/powerpc32/603e/fpu/Implies 2014-08-29 10:34:07.776070587 -0700
+@@ -0,0 +1 @@
++powerpc/powerpc32/603e/fpu
+Index: git/sysdeps/unix/sysv/linux/powerpc/powerpc32/e300c3/fpu/Implies
+===================================================================
+--- /dev/null 1970-01-01 00:00:00.000000000 +0000
++++ git/sysdeps/unix/sysv/linux/powerpc/powerpc32/e300c3/fpu/Implies 2014-08-29 10:34:07.776070587 -0700
+@@ -0,0 +1,2 @@
++# e300c3 is a variant of 603e so use the same optimizations for sqrt
++powerpc/powerpc32/603e/fpu
+Index: git/sysdeps/unix/sysv/linux/powerpc/powerpc32/e500mc/fpu/Implies
+===================================================================
+--- /dev/null 1970-01-01 00:00:00.000000000 +0000
++++ git/sysdeps/unix/sysv/linux/powerpc/powerpc32/e500mc/fpu/Implies 2014-08-29 10:34:07.776070587 -0700
+@@ -0,0 +1 @@
++powerpc/powerpc32/e500mc/fpu
+Index: git/sysdeps/unix/sysv/linux/powerpc/powerpc32/e5500/fpu/Implies
+===================================================================
+--- /dev/null 1970-01-01 00:00:00.000000000 +0000
++++ git/sysdeps/unix/sysv/linux/powerpc/powerpc32/e5500/fpu/Implies 2014-08-29 10:34:07.776070587 -0700
+@@ -0,0 +1 @@
++powerpc/powerpc32/e5500/fpu
+Index: git/sysdeps/unix/sysv/linux/powerpc/powerpc32/e6500/fpu/Implies
+===================================================================
+--- /dev/null 1970-01-01 00:00:00.000000000 +0000
++++ git/sysdeps/unix/sysv/linux/powerpc/powerpc32/e6500/fpu/Implies 2014-08-29 10:34:07.776070587 -0700
+@@ -0,0 +1 @@
++powerpc/powerpc32/e6500/fpu
+Index: git/sysdeps/unix/sysv/linux/powerpc/powerpc64/e5500/fpu/Implies
+===================================================================
+--- /dev/null 1970-01-01 00:00:00.000000000 +0000
++++ git/sysdeps/unix/sysv/linux/powerpc/powerpc64/e5500/fpu/Implies 2014-08-29 10:34:07.780070587 -0700
+@@ -0,0 +1 @@
++powerpc/powerpc64/e5500/fpu
+Index: git/sysdeps/unix/sysv/linux/powerpc/powerpc64/e6500/fpu/Implies
+===================================================================
+--- /dev/null 1970-01-01 00:00:00.000000000 +0000
++++ git/sysdeps/unix/sysv/linux/powerpc/powerpc64/e6500/fpu/Implies 2014-08-29 10:34:07.780070587 -0700
+@@ -0,0 +1 @@
++powerpc/powerpc64/e6500/fpu
diff --git a/recipes-core/glibc/glibc/grok_gold.patch b/recipes-core/glibc/glibc/grok_gold.patch
new file mode 100644
index 0000000..26875c7
--- /dev/null
+++ b/recipes-core/glibc/glibc/grok_gold.patch
@@ -0,0 +1,34 @@
+Make ld --version output matching grok gold's output
+
+adapted from from upstream branch roland/gold-vs-libc
+
+Signed-off-by: Khem Raj <raj.khem at gmail.com>
+Upstream-Status: Backport
+
+
+Index: git/configure
+===================================================================
+--- git.orig/configure 2014-08-29 10:32:34.464070587 -0700
++++ git/configure 2014-08-29 10:32:34.456070587 -0700
+@@ -4592,7 +4592,7 @@
+ # Found it, now check the version.
+ { $as_echo "$as_me:${as_lineno-$LINENO}: checking version of $LD" >&5
+ $as_echo_n "checking version of $LD... " >&6; }
+- ac_prog_version=`$LD --version 2>&1 | sed -n 's/^.*GNU ld.* \([0-9][0-9]*\.[0-9.]*\).*$/\1/p'`
++ ac_prog_version=`$LD --version 2>&1 | sed -n 's/^.*GNU [Bbinutilsd][^.]* \([0-9][0-9]*\.[0-9.]*\).*$/\1/p'`
+ case $ac_prog_version in
+ '') ac_prog_version="v. ?.??, bad"; ac_verc_fail=yes;;
+ 2.1[0-9][0-9]*|2.[2-9][0-9]*|[3-9].*|[1-9][0-9]*)
+Index: git/configure.ac
+===================================================================
+--- git.orig/configure.ac 2014-08-29 10:32:34.464070587 -0700
++++ git/configure.ac 2014-08-29 10:32:34.460070587 -0700
+@@ -930,7 +930,7 @@
+ [GNU assembler.* \([0-9]*\.[0-9.]*\)],
+ [2.1[0-9][0-9]*|2.[2-9][0-9]*|[3-9].*|[1-9][0-9]*], AS=: critic_missing="$critic_missing as")
+ AC_CHECK_PROG_VER(LD, $LD, --version,
+- [GNU ld.* \([0-9][0-9]*\.[0-9.]*\)],
++ [GNU [Bbinutilsd][^.]* \([0-9][0-9]*\.[0-9.]*\)],
+ [2.1[0-9][0-9]*|2.[2-9][0-9]*|[3-9].*|[1-9][0-9]*], LD=: critic_missing="$critic_missing ld")
+
+ # These programs are version sensitive.
diff --git a/recipes-core/glibc/glibc/initgroups_keys.patch b/recipes-core/glibc/glibc/initgroups_keys.patch
new file mode 100644
index 0000000..32aa15a
--- /dev/null
+++ b/recipes-core/glibc/glibc/initgroups_keys.patch
@@ -0,0 +1,20 @@
+This is needed since initgroups belongs to NET group
+so when NET is disabled in eglibc build then it reports
+as undefined symbol
+
+Signed-off-by: Khem Raj <raj.khem at gmail.com>
+Upstream-Status: Pending
+
+Index: git/nss/getent.c
+===================================================================
+--- git.orig/nss/getent.c 2014-08-27 05:15:25.996070587 +0000
++++ git/nss/getent.c 2014-08-27 05:16:00.048070587 +0000
+@@ -879,7 +879,7 @@
+ D(group)
+ D(gshadow)
+ D(hosts)
+-D(initgroups)
++DN(initgroups)
+ D(netgroup)
+ D(networks)
+ D(passwd)
diff --git a/recipes-core/glibc/glibc/intl-Merge-with-gettext-version-0.19.3.patch b/recipes-core/glibc/glibc/intl-Merge-with-gettext-version-0.19.3.patch
new file mode 100644
index 0000000..f2eea97
--- /dev/null
+++ b/recipes-core/glibc/glibc/intl-Merge-with-gettext-version-0.19.3.patch
@@ -0,0 +1,4797 @@
+From 7c159401dd735baa3206eb3e3bd28ebe6b239b08 Mon Sep 17 00:00:00 2001
+From: Will Newton <will.newton at linaro.org>
+Date: Wed, 10 Dec 2014 12:03:53 +0000
+Subject: [PATCH] intl: Merge with gettext version 0.19.3
+
+This patch merges the latest release of gettext into the intl
+subdirectory. The initial motivation was to include the plural.y
+changes which enable building with bison 3.0, but the majority
+of the other changes are merely cosmetic so it seemed like merging
+the whole directory was simpler than trying to take it piecemeal.
+
+The merge was done by copying across the latext gettext code and
+adding in a few small glibc changes that have been added over the
+years that seemed beneficial, as well as a couple of small build
+fixes that should be merged back to gettext. I also reverted the
+gettext commit:
+
+commit 279b57fc367251666f00e8e2b599b83703451afb
+Author: Bruno Haible <bruno at clisp.org>
+Date: Fri Jun 14 12:03:49 2002 +0000
+
+ Make absolute pathnames inside $LANGUAGE work.
+
+As it caused localedata/tst-setlocale3 to fail and it wasn't clear
+that glibc wanted that behaviour.
+
+The merge has dropped many uses of __glibc_likely/unlikely. This is
+intentional given that it eases merging. It seems to me that the cost
+of continually rewriting these lines when merging and the risk of adding
+bugs when doing so outweighs the benefits of using these macros when
+code is shared with another project.
+
+Tested with make check on x86_64.
+
+ChangeLog:
+
+2014-12-11 Will Newton <will.newton at linaro.org>
+
+ Merge gettext 0.19.3 into intl/.
+
+ This involves a number of cosmetic changes to comments
+ and ANSI function definitions and prototypes throughout
+ all the files. The gettext copyright header is used but
+ with the date ranges taken from the glibc copy.
+
+ * NEWS: Add gettext merge to 2.21.
+ * intl/bindtextdom.c: Switch to gettext copyright.
+ Use ANSI definitions and prototypes.
+ Use gl_* locking primitives rather than __libc_* ones.
+ Use __builtin_expect rather than __glibc_likely/unlikely.
+ * intl/dcgettext.c: Switch to gettext copyright.
+ Use ANSI definitions and prototypes.
+ * intl/dcigettext.c: Switch to gettext copyright.
+ Use ANSI definitions and prototypes.
+ (INTDIV0_RAISES_SIGFPE): New define.
+ Use gl_* locking primitives rather than __libc_* ones.
+ Include eval-plural.h instead of plural-eval.c.
+ Use __builtin_expect rather than __glibc_likely/unlikely.
+ * intl/dcngettext.c: Switch to gettext copyright.
+ Use ANSI definitions and prototypes.
+ * intl/dgettext.c: Likewise.
+ * intl/dngettext.c: Likewise.
+ * intl/plural-eval.c: Renamed to...
+ * intl/eval-plural.h: ...this.
+ * intl/explodename.c: Switch to gettext copyright.
+ Use ANSI definitions and prototypes.
+ (_nl_explode_name): Use strchr instead of __rawmemchr.
+ * intl/finddomain.c: Switch to gettext copyright.
+ Use ANSI definitions and prototypes.
+ Use gl_* locking primitives rather than __libc_* ones.
+ (_nl_find_domain): Use malloc rather than alloca for
+ allocation of temporary locale name.
+ * intl/gettext.c: Switch to gettext copyright.
+ Use ANSI definitions and prototypes.
+ * intl/gettextP.h: Switch to gettext copyright.
+ Use ANSI definitions and prototypes.
+ Use gl_* locking primitives rather than __libc_* ones.
+ * intl/gmo.h: Switch to gettext copyright.
+ (struct sysdep_string): Move struct segment_pair outside of
+ struct definition.
+ * intl/hash-string.c: Use ANSI definitions and prototypes.
+ * intl/hash-string.h: Switch to gettext copyright.
+ Use ANSI definitions and prototypes.
+ * intl/l10nflist.c: Switch to gettext copyright.
+ Use ANSI definitions and prototypes.
+ (_nl_normalize_codeset): Avoid integer overflow.
+ * intl/loadinfo.h: Switch to gettext copyright.
+ Use ANSI definitions and prototypes.
+ (LIBINTL_DLL_EXPORTED): New define.
+ (PATH_SEPARATOR): New define.
+ * intl/loadmsgcat.c: Switch to gettext copyright.
+ * intl/localealias.c: Switch to gettext copyright.
+ Use ANSI definitions and prototypes.
+ (_nl_expand_alias): Use PATH_SEPARATOR.
+ * intl/ngettext.c: Switch to gettext copyright.
+ Use ANSI definitions and prototypes.
+ * intl/plural-exp.c: Likewise.
+ * intl/plural-exp.h: Switch to gettext copyright.
+ Use ANSI definitions and prototypes.
+ (struct expression): Move definition of enum operator outside
+ of struct definition.
+ * intl/plural.c: Regenerate.
+ * intl/plural.y: Switch to gettext copyright.
+ Use ANSI definitions and prototypes.
+ Port to bison 3.0.
+ * intl/textdomain.c: Switch to gettext copyright.
+ Use ANSI definitions and prototypes.
+ Use gl_* locking primitives rather than __libc_* ones.
+---
+ intl/bindtextdom.c | 92 ++----
+ intl/dcgettext.c | 25 +-
+ intl/dcigettext.c | 851 +++++++++++++++++++++++++++++++++--------------------
+ intl/dcngettext.c | 29 +-
+ intl/dgettext.c | 27 +-
+ intl/dngettext.c | 30 +-
+ intl/eval-plural.h | 106 +++++++
+ intl/explodename.c | 44 ++-
+ intl/finddomain.c | 75 +++--
+ intl/gettext.c | 23 +-
+ intl/gettextP.h | 235 +++++++++------
+ intl/gmo.h | 39 +--
+ intl/hash-string.c | 8 +-
+ intl/hash-string.h | 41 ++-
+ intl/l10nflist.c | 108 +++----
+ intl/loadinfo.h | 116 +++++---
+ intl/loadmsgcat.c | 20 +-
+ intl/localealias.c | 186 +++++++-----
+ intl/ngettext.c | 25 +-
+ intl/plural-eval.c | 100 -------
+ intl/plural-exp.c | 30 +-
+ intl/plural-exp.h | 104 +++----
+ intl/plural.c | 190 ++++++------
+ intl/plural.y | 98 +++---
+ intl/textdomain.c | 55 ++--
+ 25 files changed, 1447 insertions(+), 1210 deletions(-)
+ create mode 100644 intl/eval-plural.h
+ delete mode 100644 intl/plural-eval.c
+
+diff --git a/intl/bindtextdom.c b/intl/bindtextdom.c
+index c362496..29a1b12 100644
+--- a/intl/bindtextdom.c
++++ b/intl/bindtextdom.c
+@@ -1,20 +1,18 @@
+ /* Implementation of the bindtextdomain(3) function
+ Copyright (C) 1995-2014 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.
++ This program 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,
++ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+- Lesser General Public License for more details.
++ 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, see
+- <http://www.gnu.org/licenses/>. */
++ You should have received a copy of the GNU Lesser General Public License
++ along with this program. If not, see <http://www.gnu.org/licenses/>. */
+
+ #ifdef HAVE_CONFIG_H
+ # include <config.h>
+@@ -24,29 +22,21 @@
+ #include <stdlib.h>
+ #include <string.h>
+
++#include "gettextP.h"
+ #ifdef _LIBC
+ # include <libintl.h>
+ #else
+ # include "libgnuintl.h"
+ #endif
+-#include "gettextP.h"
+
++/* Handle multi-threaded applications. */
+ #ifdef _LIBC
+-/* We have to handle multi-threaded applications. */
+ # include <bits/libc-lock.h>
++# define gl_rwlock_define __libc_rwlock_define
++# define gl_rwlock_wrlock __libc_rwlock_wrlock
++# define gl_rwlock_unlock __libc_rwlock_unlock
+ #else
+-/* Provide dummy implementation if this is outside glibc. */
+-# define __libc_rwlock_define(CLASS, NAME)
+-# define __libc_rwlock_wrlock(NAME)
+-# define __libc_rwlock_unlock(NAME)
+-#endif
+-
+-/* The internal variables in the standalone libintl.a must have different
+- names than the internal variables in GNU libc, otherwise programs
+- using libintl.a cannot be linked statically. */
+-#if !defined _LIBC
+-# define _nl_default_dirname libintl_nl_default_dirname
+-# define _nl_domain_bindings libintl_nl_domain_bindings
++# include "lock.h"
+ #endif
+
+ /* Some compilers, like SunOS4 cc, don't have offsetof in <stddef.h>. */
+@@ -56,17 +46,8 @@
+
+ /* @@ end of prolog @@ */
+
+-/* Contains the default location of the message catalogs. */
+-extern const char _nl_default_dirname[];
+-#ifdef _LIBC
+-libc_hidden_proto (_nl_default_dirname)
+-#endif
+-
+-/* List with bindings of specific domains. */
+-extern struct binding *_nl_domain_bindings;
+-
+ /* Lock variable to protect the global data in the gettext implementation. */
+-__libc_rwlock_define (extern, _nl_state_lock attribute_hidden)
++gl_rwlock_define (extern, _nl_state_lock attribute_hidden)
+
+
+ /* Names for the libintl functions are a problem. They must not clash
+@@ -84,11 +65,6 @@ __libc_rwlock_define (extern, _nl_state_lock attribute_hidden)
+ # define BIND_TEXTDOMAIN_CODESET libintl_bind_textdomain_codeset
+ #endif
+
+-/* Prototypes for local functions. */
+-static void set_binding_values PARAMS ((const char *domainname,
+- const char **dirnamep,
+- const char **codesetp));
+-
+ /* Specifies the directory name *DIRNAMEP and the output codeset *CODESETP
+ to be used for the DOMAINNAME message catalog.
+ If *DIRNAMEP or *CODESETP is NULL, the corresponding attribute is not
+@@ -96,10 +72,8 @@ static void set_binding_values PARAMS ((const char *domainname,
+ If DIRNAMEP or CODESETP is NULL, the corresponding attribute is neither
+ modified nor returned. */
+ static void
+-set_binding_values (domainname, dirnamep, codesetp)
+- const char *domainname;
+- const char **dirnamep;
+- const char **codesetp;
++set_binding_values (const char *domainname,
++ const char **dirnamep, const char **codesetp)
+ {
+ struct binding *binding;
+ int modified;
+@@ -114,7 +88,7 @@ set_binding_values (domainname, dirnamep, codesetp)
+ return;
+ }
+
+- __libc_rwlock_wrlock (_nl_state_lock);
++ gl_rwlock_wrlock (_nl_state_lock);
+
+ modified = 0;
+
+@@ -158,12 +132,12 @@ set_binding_values (domainname, dirnamep, codesetp)
+ #else
+ size_t len = strlen (dirname) + 1;
+ result = (char *) malloc (len);
+- if (__glibc_likely (result != NULL))
++ if (__builtin_expect (result != NULL, 1))
+ memcpy (result, dirname, len);
+ #endif
+ }
+
+- if (__glibc_likely (result != NULL))
++ if (__builtin_expect (result != NULL, 1))
+ {
+ if (binding->dirname != _nl_default_dirname)
+ free (binding->dirname);
+@@ -196,11 +170,11 @@ set_binding_values (domainname, dirnamep, codesetp)
+ #else
+ size_t len = strlen (codeset) + 1;
+ result = (char *) malloc (len);
+- if (__glibc_likely (result != NULL))
++ if (__builtin_expect (result != NULL, 1))
+ memcpy (result, codeset, len);
+ #endif
+
+- if (__glibc_likely (result != NULL))
++ if (__builtin_expect (result != NULL, 1))
+ {
+ free (binding->codeset);
+
+@@ -228,7 +202,7 @@ set_binding_values (domainname, dirnamep, codesetp)
+ struct binding *new_binding =
+ (struct binding *) malloc (offsetof (struct binding, domainname) + len);
+
+- if (__glibc_unlikely (new_binding == NULL))
++ if (__builtin_expect (new_binding == NULL, 0))
+ goto failed;
+
+ memcpy (new_binding->domainname, domainname, len);
+@@ -249,12 +223,12 @@ set_binding_values (domainname, dirnamep, codesetp)
+ char *result;
+ #if defined _LIBC || defined HAVE_STRDUP
+ result = strdup (dirname);
+- if (__glibc_unlikely (result == NULL))
++ if (__builtin_expect (result == NULL, 0))
+ goto failed_dirname;
+ #else
+ size_t len = strlen (dirname) + 1;
+ result = (char *) malloc (len);
+- if (__glibc_unlikely (result == NULL))
++ if (__builtin_expect (result == NULL, 0))
+ goto failed_dirname;
+ memcpy (result, dirname, len);
+ #endif
+@@ -278,12 +252,12 @@ set_binding_values (domainname, dirnamep, codesetp)
+
+ #if defined _LIBC || defined HAVE_STRDUP
+ result = strdup (codeset);
+- if (__glibc_unlikely (result == NULL))
++ if (__builtin_expect (result == NULL, 0))
+ goto failed_codeset;
+ #else
+ size_t len = strlen (codeset) + 1;
+ result = (char *) malloc (len);
+- if (__glibc_unlikely (result == NULL))
++ if (__builtin_expect (result == NULL, 0))
+ goto failed_codeset;
+ memcpy (result, codeset, len);
+ #endif
+@@ -335,15 +309,13 @@ set_binding_values (domainname, dirnamep, codesetp)
+ if (modified)
+ ++_nl_msg_cat_cntr;
+
+- __libc_rwlock_unlock (_nl_state_lock);
++ gl_rwlock_unlock (_nl_state_lock);
+ }
+
+ /* Specify that the DOMAINNAME message catalog will be found
+ in DIRNAME rather than in the system locale data base. */
+ char *
+-BINDTEXTDOMAIN (domainname, dirname)
+- const char *domainname;
+- const char *dirname;
++BINDTEXTDOMAIN (const char *domainname, const char *dirname)
+ {
+ set_binding_values (domainname, &dirname, NULL);
+ return (char *) dirname;
+@@ -352,9 +324,7 @@ BINDTEXTDOMAIN (domainname, dirname)
+ /* Specify the character encoding in which the messages from the
+ DOMAINNAME message catalog will be returned. */
+ char *
+-BIND_TEXTDOMAIN_CODESET (domainname, codeset)
+- const char *domainname;
+- const char *codeset;
++BIND_TEXTDOMAIN_CODESET (const char *domainname, const char *codeset)
+ {
+ set_binding_values (domainname, NULL, &codeset);
+ return (char *) codeset;
+diff --git a/intl/dcgettext.c b/intl/dcgettext.c
+index 4daae55..95dccad 100644
+--- a/intl/dcgettext.c
++++ b/intl/dcgettext.c
+@@ -1,20 +1,18 @@
+ /* Implementation of the dcgettext(3) function.
+ Copyright (C) 1995-2014 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.
++ This program 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,
++ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+- Lesser General Public License for more details.
++ 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, see
+- <http://www.gnu.org/licenses/>. */
++ You should have received a copy of the GNU Lesser General Public License
++ along with this program. If not, see <http://www.gnu.org/licenses/>. */
+
+ #ifdef HAVE_CONFIG_H
+ # include <config.h>
+@@ -44,10 +42,7 @@
+ /* Look up MSGID in the DOMAINNAME message catalog for the current CATEGORY
+ locale. */
+ char *
+-DCGETTEXT (domainname, msgid, category)
+- const char *domainname;
+- const char *msgid;
+- int category;
++DCGETTEXT (const char *domainname, const char *msgid, int category)
+ {
+ return DCIGETTEXT (domainname, msgid, NULL, 0, 0, category);
+ }
+diff --git a/intl/dcigettext.c b/intl/dcigettext.c
+index 723dd7e..7af4a76 100644
+--- a/intl/dcigettext.c
++++ b/intl/dcigettext.c
+@@ -1,20 +1,18 @@
+ /* Implementation of the internal dcigettext function.
+ Copyright (C) 1995-2014 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.
++ This program 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,
++ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+- Lesser General Public License for more details.
++ 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, see
+- <http://www.gnu.org/licenses/>. */
++ You should have received a copy of the GNU Lesser General Public License
++ along with this program. If not, see <http://www.gnu.org/licenses/>. */
+
+ /* Tell glibc's <string.h> to provide a prototype for mempcpy().
+ This must come before <config.h> because <config.h> may include
+@@ -33,14 +31,19 @@
+ # define alloca __builtin_alloca
+ # define HAVE_ALLOCA 1
+ #else
+-# if defined HAVE_ALLOCA_H || defined _LIBC
+-# include <alloca.h>
++# ifdef _MSC_VER
++# include <malloc.h>
++# define alloca _alloca
+ # else
+-# ifdef _AIX
+- #pragma alloca
++# if defined HAVE_ALLOCA_H || defined _LIBC
++# include <alloca.h>
+ # else
+-# ifndef alloca
++# ifdef _AIX
++ #pragma alloca
++# else
++# ifndef alloca
+ char *alloca ();
++# endif
+ # endif
+ # endif
+ # endif
+@@ -64,30 +67,49 @@ extern int errno;
+
+ #include <locale.h>
+
++#ifdef _LIBC
++ /* Guess whether integer division by zero raises signal SIGFPE.
++ Set to 1 only if you know for sure. In case of doubt, set to 0. */
++# if defined __alpha__ || defined __arm__ || defined __i386__ \
++ || defined __m68k__ || defined __s390__
++# define INTDIV0_RAISES_SIGFPE 1
++# else
++# define INTDIV0_RAISES_SIGFPE 0
++# endif
++#endif
++#if !INTDIV0_RAISES_SIGFPE
++# include <signal.h>
++#endif
++
+ #if defined HAVE_SYS_PARAM_H || defined _LIBC
+ # include <sys/param.h>
+ #endif
+
++#if !defined _LIBC
++# include "localcharset.h"
++#endif
++
+ #include "gettextP.h"
+ #include "plural-exp.h"
+ #ifdef _LIBC
+ # include <libintl.h>
+ #else
++# ifdef IN_LIBGLOCALE
++# include <libintl.h>
++# endif
+ # include "libgnuintl.h"
+ #endif
+ #include "hash-string.h"
+
+-/* Thread safetyness. */
++/* Handle multi-threaded applications. */
+ #ifdef _LIBC
+ # include <bits/libc-lock.h>
++# define gl_rwlock_define_initialized __libc_rwlock_define_initialized
++# define gl_rwlock_rdlock __libc_rwlock_rdlock
++# define gl_rwlock_wrlock __libc_rwlock_wrlock
++# define gl_rwlock_unlock __libc_rwlock_unlock
+ #else
+-/* Provide dummy implementation if this is outside glibc. */
+-# define __libc_lock_define_initialized(CLASS, NAME)
+-# define __libc_lock_lock(NAME)
+-# define __libc_lock_unlock(NAME)
+-# define __libc_rwlock_define_initialized(CLASS, NAME)
+-# define __libc_rwlock_rdlock(NAME)
+-# define __libc_rwlock_unlock(NAME)
++# include "lock.h"
+ #endif
+
+ /* Alignment of types. */
+@@ -98,16 +120,6 @@ extern int errno;
+ ((int) &((struct { char dummy1; TYPE dummy2; } *) 0)->dummy2)
+ #endif
+
+-/* The internal variables in the standalone libintl.a must have different
+- names than the internal variables in GNU libc, otherwise programs
+- using libintl.a cannot be linked statically. */
+-#if !defined _LIBC
+-# define _nl_default_default_domain libintl_nl_default_default_domain
+-# define _nl_current_default_domain libintl_nl_current_default_domain
+-# define _nl_default_dirname libintl_nl_default_dirname
+-# define _nl_domain_bindings libintl_nl_domain_bindings
+-#endif
+-
+ /* Some compilers, like SunOS4 cc, don't have offsetof in <stddef.h>. */
+ #ifndef offsetof
+ # define offsetof(type,ident) ((size_t)&(((type*)0)->ident))
+@@ -129,16 +141,36 @@ extern int errno;
+ char *getwd ();
+ # define getcwd(buf, max) getwd (buf)
+ # else
++# if VMS
++# define getcwd(buf, max) (getcwd) (buf, max, 0)
++# else
+ char *getcwd ();
++# endif
+ # endif
+ # ifndef HAVE_STPCPY
+-static char *stpcpy PARAMS ((char *dest, const char *src));
++static char *stpcpy (char *dest, const char *src);
+ # endif
+ # ifndef HAVE_MEMPCPY
+-static void *mempcpy PARAMS ((void *dest, const void *src, size_t n));
++static void *mempcpy (void *dest, const void *src, size_t n);
+ # endif
+ #endif
+
++/* Use a replacement if the system does not provide the `tsearch' function
++ family. */
++#if defined HAVE_TSEARCH || defined _LIBC
++# include <search.h>
++#else
++# define tsearch libintl_tsearch
++# define tfind libintl_tfind
++# define tdelete libintl_tdelete
++# define twalk libintl_twalk
++# include "tsearch.h"
++#endif
++
++#ifdef _LIBC
++# define tsearch __tsearch
++#endif
++
+ /* Amount to increase buffer size by in each try. */
+ #define PATH_INCR 32
+
+@@ -171,8 +203,30 @@ static void *mempcpy PARAMS ((void *dest, const void *src, size_t n));
+ # define PATH_MAX _POSIX_PATH_MAX
+ #endif
+
++/* Pathname support.
++ ISSLASH(C) tests whether C is a directory separator character.
++ IS_ABSOLUTE_PATH(P) tests whether P is an absolute path. If it is not,
++ it may be concatenated to a directory pathname.
++ IS_PATH_WITH_DIR(P) tests whether P contains a directory specification.
++ */
++#if defined _WIN32 || defined __WIN32__ || defined __CYGWIN__ || defined __EMX__ || defined __DJGPP__
++ /* Win32, Cygwin, OS/2, DOS */
++# define ISSLASH(C) ((C) == '/' || (C) == '\\')
++# define HAS_DEVICE(P) \
++ ((((P)[0] >= 'A' && (P)[0] <= 'Z') || ((P)[0] >= 'a' && (P)[0] <= 'z')) \
++ && (P)[1] == ':')
++# define IS_ABSOLUTE_PATH(P) (ISSLASH ((P)[0]) || HAS_DEVICE (P))
++# define IS_PATH_WITH_DIR(P) \
++ (strchr (P, '/') != NULL || strchr (P, '\\') != NULL || HAS_DEVICE (P))
++#else
++ /* Unix */
++# define ISSLASH(C) ((C) == '/')
++# define IS_ABSOLUTE_PATH(P) ISSLASH ((P)[0])
++# define IS_PATH_WITH_DIR(P) (strchr (P, '/') != NULL)
++#endif
++
+ /* Whether to support different locales in different threads. */
+-#if defined _LIBC || HAVE_NL_LOCALE_NAME
++#if defined _LIBC || HAVE_USELOCALE || defined IN_LIBGLOCALE
+ # define HAVE_PER_THREAD_LOCALE
+ #endif
+
+@@ -191,6 +245,11 @@ struct known_translation_t
+ const char *localename;
+ #endif
+
++#ifdef IN_LIBGLOCALE
++ /* The character encoding. */
++ const char *encoding;
++#endif
++
+ /* State of the catalog counter at the point the string was found. */
+ int counter;
+
+@@ -210,23 +269,14 @@ struct known_translation_t
+ msgid;
+ };
+
+-/* Root of the search tree with known translations. We can use this
+- only if the system provides the `tsearch' function family. */
+-#if defined HAVE_TSEARCH || defined _LIBC
+-# include <search.h>
++gl_rwlock_define_initialized (static, tree_lock)
+
++/* Root of the search tree with known translations. */
+ static void *root;
+
+-# ifdef _LIBC
+-# define tsearch __tsearch
+-# endif
+-
+ /* Function to compare two entries in the table of known translations. */
+-static int transcmp PARAMS ((const void *p1, const void *p2));
+ static int
+-transcmp (p1, p2)
+- const void *p1;
+- const void *p2;
++transcmp (const void *p1, const void *p2)
+ {
+ const struct known_translation_t *s1;
+ const struct known_translation_t *s2;
+@@ -246,59 +296,83 @@ transcmp (p1, p2)
+ result = strcmp (s1->localename, s2->localename);
+ if (result == 0)
+ #endif
+- /* We compare the category last (though this is the cheapest
+- operation) since it is hopefully always the same (namely
+- LC_MESSAGES). */
+- result = s1->category - s2->category;
++ {
++#ifdef IN_LIBGLOCALE
++ result = strcmp (s1->encoding, s2->encoding);
++ if (result == 0)
++#endif
++ /* We compare the category last (though this is the cheapest
++ operation) since it is hopefully always the same (namely
++ LC_MESSAGES). */
++ result = s1->category - s2->category;
++ }
+ }
+ }
+
+ return result;
+ }
+-#endif
+
+ /* Name of the default domain used for gettext(3) prior any call to
+ textdomain(3). The default value for this is "messages". */
+ const char _nl_default_default_domain[] attribute_hidden = "messages";
+
++#ifndef IN_LIBGLOCALE
+ /* Value used as the default domain for gettext(3). */
+ const char *_nl_current_default_domain attribute_hidden
+ = _nl_default_default_domain;
++#endif
+
+ /* Contains the default location of the message catalogs. */
+-
+-#ifdef _LIBC
++#if defined __EMX__
++extern const char _nl_default_dirname[];
++#else
++# ifdef _LIBC
+ extern const char _nl_default_dirname[];
+ libc_hidden_proto (_nl_default_dirname)
+-#endif
++# endif
+ const char _nl_default_dirname[] = LOCALEDIR;
+-#ifdef _LIBC
++# ifdef _LIBC
+ libc_hidden_data_def (_nl_default_dirname)
++# endif
+ #endif
+
++#ifndef IN_LIBGLOCALE
+ /* List with bindings of specific domains created by bindtextdomain()
+ calls. */
+ struct binding *_nl_domain_bindings;
++#endif
+
+ /* Prototypes for local functions. */
+-static char *plural_lookup PARAMS ((struct loaded_l10nfile *domain,
+- unsigned long int n,
+- const char *translation,
+- size_t translation_len))
++static char *plural_lookup (struct loaded_l10nfile *domain,
++ unsigned long int n,
++ const char *translation, size_t translation_len)
++ internal_function;
++
++#ifdef IN_LIBGLOCALE
++static const char *guess_category_value (int category,
++ const char *categoryname,
++ const char *localename)
+ internal_function;
+-static const char *guess_category_value PARAMS ((int category,
+- const char *categoryname))
++#else
++static const char *guess_category_value (int category,
++ const char *categoryname)
+ internal_function;
++#endif
++
+ #ifdef _LIBC
+ # include "../locale/localeinfo.h"
+ # define category_to_name(category) \
+ _nl_category_names.str + _nl_category_name_idxs[category]
+ #else
+-static const char *category_to_name PARAMS ((int category)) internal_function;
++static const char *category_to_name (int category) internal_function;
++#endif
++#if (defined _LIBC || HAVE_ICONV) && !defined IN_LIBGLOCALE
++static const char *get_output_charset (struct binding *domainbinding)
++ internal_function;
+ #endif
+
+
+-/* For those loosing systems which don't have `alloca' we have to add
++/* For those losing systems which don't have `alloca' we have to add
+ some additional code emulating it. */
+ #ifdef HAVE_ALLOCA
+ /* Nothing has to be done. */
+@@ -348,10 +422,6 @@ static struct transmem_list *transmem_list;
+ #else
+ typedef unsigned char transmem_block_t;
+ #endif
+-#if defined _LIBC || HAVE_ICONV
+-static const char *get_output_charset PARAMS ((struct binding *domainbinding))
+- internal_function;
+-#endif
+
+
+ /* Names for the libintl functions are a problem. They must not clash
+@@ -365,9 +435,7 @@ static const char *get_output_charset PARAMS ((struct binding *domainbinding))
+ #endif
+
+ /* Lock variable to protect the global data in the gettext implementation. */
+-#ifdef _LIBC
+-__libc_rwlock_define_initialized (, _nl_state_lock attribute_hidden)
+-#endif
++gl_rwlock_define_initialized (, _nl_state_lock attribute_hidden)
+
+ /* Checking whether the binaries runs SUID must be done and glibc provides
+ easier methods therefore we make a difference here. */
+@@ -400,19 +468,23 @@ static int enable_secure;
+ #endif
+
+ /* Get the function to evaluate the plural expression. */
+-#include "plural-eval.c"
++#include "eval-plural.h"
+
+ /* Look up MSGID in the DOMAINNAME message catalog for the current
+ CATEGORY locale and, if PLURAL is nonzero, search over string
+ depending on the plural form determined by N. */
++#ifdef IN_LIBGLOCALE
+ char *
+-DCIGETTEXT (domainname, msgid1, msgid2, plural, n, category)
+- const char *domainname;
+- const char *msgid1;
+- const char *msgid2;
+- int plural;
+- unsigned long int n;
+- int category;
++gl_dcigettext (const char *domainname,
++ const char *msgid1, const char *msgid2,
++ int plural, unsigned long int n,
++ int category,
++ const char *localename, const char *encoding)
++#else
++char *
++DCIGETTEXT (const char *domainname, const char *msgid1, const char *msgid2,
++ int plural, unsigned long int n, int category)
++#endif
+ {
+ #ifndef HAVE_ALLOCA
+ struct block_list *block_list = NULL;
+@@ -421,17 +493,16 @@ DCIGETTEXT (domainname, msgid1, msgid2, plural, n, category)
+ struct binding *binding;
+ const char *categoryname;
+ const char *categoryvalue;
+- char *dirname, *xdomainname;
++ const char *dirname;
++ char *xdomainname;
+ char *single_locale;
+ char *retval;
+ size_t retlen;
+ int saved_errno;
+-#if defined HAVE_TSEARCH || defined _LIBC
+ struct known_translation_t search;
+ struct known_translation_t **foundp = NULL;
+-# ifdef HAVE_PER_THREAD_LOCALE
++#if defined HAVE_PER_THREAD_LOCALE && !defined IN_LIBGLOCALE
+ const char *localename;
+-# endif
+ #endif
+ size_t domainname_len;
+
+@@ -448,12 +519,15 @@ DCIGETTEXT (domainname, msgid1, msgid2, plural, n, category)
+ : n == 1 ? (char *) msgid1 : (char *) msgid2);
+ #endif
+
++ /* Preserve the `errno' value. */
++ saved_errno = errno;
++
+ #ifdef _LIBC
+ __libc_rwlock_define (extern, __libc_setlocale_lock attribute_hidden)
+ __libc_rwlock_rdlock (__libc_setlocale_lock);
+ #endif
+
+- __libc_rwlock_rdlock (_nl_state_lock);
++ gl_rwlock_rdlock (_nl_state_lock);
+
+ /* If DOMAINNAME is NULL, we are interested in the default domain. If
+ CATEGORY is not LC_MESSAGES this might not make much sense but the
+@@ -461,28 +535,42 @@ DCIGETTEXT (domainname, msgid1, msgid2, plural, n, category)
+ if (domainname == NULL)
+ domainname = _nl_current_default_domain;
+
+-#if defined HAVE_TSEARCH || defined _LIBC
++ /* OS/2 specific: backward compatibility with older libintl versions */
++#ifdef LC_MESSAGES_COMPAT
++ if (category == LC_MESSAGES_COMPAT)
++ category = LC_MESSAGES;
++#endif
++
+ /* Try to find the translation among those which we found at
+ some time. */
+ search.domain = NULL;
+ search.msgid.ptr = msgid1;
+ search.domainname = domainname;
+ search.category = category;
+-# ifdef HAVE_PER_THREAD_LOCALE
++#ifdef HAVE_PER_THREAD_LOCALE
++# ifndef IN_LIBGLOCALE
+ # ifdef _LIBC
+ localename = strdupa (__current_locale_name (category));
++# else
++ categoryname = category_to_name (category);
++# define CATEGORYNAME_INITIALIZED
++ localename = _nl_locale_name_thread_unsafe (category, categoryname);
++ if (localename == NULL)
++ localename = "";
+ # endif
++# endif
+ search.localename = localename;
++# ifdef IN_LIBGLOCALE
++ search.encoding = encoding;
+ # endif
+
+ /* Since tfind/tsearch manage a balanced tree, concurrent tfind and
+ tsearch calls can be fatal. */
+- __libc_rwlock_define_initialized (static, tree_lock);
+- __libc_rwlock_rdlock (tree_lock);
++ gl_rwlock_rdlock (tree_lock);
+
+ foundp = (struct known_translation_t **) tfind (&search, &root, transcmp);
+
+- __libc_rwlock_unlock (tree_lock);
++ gl_rwlock_unlock (tree_lock);
+
+ if (foundp != NULL && (*foundp)->counter == _nl_msg_cat_cntr)
+ {
+@@ -493,21 +581,25 @@ DCIGETTEXT (domainname, msgid1, msgid2, plural, n, category)
+ else
+ retval = (char *) (*foundp)->translation;
+
++ gl_rwlock_unlock (_nl_state_lock);
+ # ifdef _LIBC
+ __libc_rwlock_unlock (__libc_setlocale_lock);
+ # endif
+- __libc_rwlock_unlock (_nl_state_lock);
++ __set_errno (saved_errno);
+ return retval;
+ }
+ #endif
+
+- /* Preserve the `errno' value. */
+- saved_errno = errno;
+-
+ /* See whether this is a SUID binary or not. */
+ DETERMINE_SECURE;
+
+ /* First find matching binding. */
++#ifdef IN_LIBGLOCALE
++ /* We can use a trivial binding, since _nl_find_msg will ignore it anyway,
++ and _nl_load_domain and _nl_find_domain just pass it through. */
++ binding = NULL;
++ dirname = bindtextdomain (domainname, NULL);
++#else
+ for (binding = _nl_domain_bindings; binding != NULL; binding = binding->next)
+ {
+ int compare = strcmp (domainname, binding->domainname);
+@@ -523,50 +615,65 @@ DCIGETTEXT (domainname, msgid1, msgid2, plural, n, category)
+ }
+
+ if (binding == NULL)
+- dirname = (char *) _nl_default_dirname;
+- else if (binding->dirname[0] == '/')
+- dirname = binding->dirname;
++ dirname = _nl_default_dirname;
+ else
+ {
+- /* We have a relative path. Make it absolute now. */
+- size_t dirname_len = strlen (binding->dirname) + 1;
+- size_t path_max;
+- char *ret;
++ dirname = binding->dirname;
++#endif
++ if (!IS_ABSOLUTE_PATH (dirname))
++ {
++ /* We have a relative path. Make it absolute now. */
++ size_t dirname_len = strlen (dirname) + 1;
++ size_t path_max;
++ char *resolved_dirname;
++ char *ret;
+
+- path_max = (unsigned int) PATH_MAX;
+- path_max += 2; /* The getcwd docs say to do this. */
++ path_max = (unsigned int) PATH_MAX;
++ path_max += 2; /* The getcwd docs say to do this. */
+
+- for (;;)
+- {
+- dirname = (char *) alloca (path_max + dirname_len);
+- ADD_BLOCK (block_list, dirname);
++ for (;;)
++ {
++ resolved_dirname = (char *) alloca (path_max + dirname_len);
++ ADD_BLOCK (block_list, tmp_dirname);
+
+- __set_errno (0);
+- ret = getcwd (dirname, path_max);
+- if (ret != NULL || errno != ERANGE)
+- break;
++ __set_errno (0);
++ ret = getcwd (resolved_dirname, path_max);
++ if (ret != NULL || errno != ERANGE)
++ break;
+
+- path_max += path_max / 2;
+- path_max += PATH_INCR;
+- }
++ path_max += path_max / 2;
++ path_max += PATH_INCR;
++ }
+
+- if (ret == NULL)
+- goto no_translation;
++ if (ret == NULL)
++ /* We cannot get the current working directory. Don't signal an
++ error but simply return the default string. */
++ goto return_untranslated;
+
+- stpcpy (stpcpy (strchr (dirname, '\0'), "/"), binding->dirname);
++ stpcpy (stpcpy (strchr (resolved_dirname, '\0'), "/"), dirname);
++ dirname = resolved_dirname;
++ }
++#ifndef IN_LIBGLOCALE
+ }
++#endif
+
+ /* Now determine the symbolic name of CATEGORY and its value. */
++#ifndef CATEGORYNAME_INITIALIZED
+ categoryname = category_to_name (category);
++#endif
++#ifdef IN_LIBGLOCALE
++ categoryvalue = guess_category_value (category, categoryname, localename);
++#else
+ categoryvalue = guess_category_value (category, categoryname);
++#endif
+
+ domainname_len = strlen (domainname);
+ xdomainname = (char *) alloca (strlen (categoryname)
+ + domainname_len + 5);
+ ADD_BLOCK (block_list, xdomainname);
+
+- stpcpy (mempcpy (stpcpy (stpcpy (xdomainname, categoryname), "/"),
+- domainname, domainname_len),
++ stpcpy ((char *) mempcpy (stpcpy (stpcpy (xdomainname, categoryname), "/"),
++ domainname, domainname_len),
+ ".mo");
+
+ /* Creating working area. */
+@@ -599,7 +706,7 @@ DCIGETTEXT (domainname, msgid1, msgid2, plural, n, category)
+
+ /* When this is a SUID binary we must not allow accessing files
+ outside the dedicated directories. */
+- if (ENABLE_SECURE && strchr (single_locale, '/') != NULL)
++ if (ENABLE_SECURE && IS_PATH_WITH_DIR (single_locale))
+ /* Ingore this entry. */
+ continue;
+ }
+@@ -608,18 +715,7 @@ DCIGETTEXT (domainname, msgid1, msgid2, plural, n, category)
+ domain. Return the MSGID. */
+ if (strcmp (single_locale, "C") == 0
+ || strcmp (single_locale, "POSIX") == 0)
+- {
+- no_translation:
+- FREE_BLOCKS (block_list);
+- __libc_rwlock_unlock (__libc_setlocale_lock);
+- __libc_rwlock_unlock (_nl_state_lock);
+- __set_errno (saved_errno);
+- return (plural == 0
+- ? (char *) msgid1
+- /* Use the Germanic plural rule. */
+- : n == 1 ? (char *) msgid1 : (char *) msgid2);
+- }
+-
++ break;
+
+ /* Find structure describing the message catalog matching the
+ DOMAINNAME and CATEGORY. */
+@@ -627,7 +723,11 @@ DCIGETTEXT (domainname, msgid1, msgid2, plural, n, category)
+
+ if (domain != NULL)
+ {
++#if defined IN_LIBGLOCALE
++ retval = _nl_find_msg (domain, binding, encoding, msgid1, &retlen);
++#else
+ retval = _nl_find_msg (domain, binding, msgid1, 1, &retlen);
++#endif
+
+ if (retval == NULL)
+ {
+@@ -635,13 +735,18 @@ DCIGETTEXT (domainname, msgid1, msgid2, plural, n, category)
+
+ for (cnt = 0; domain->successor[cnt] != NULL; ++cnt)
+ {
++#if defined IN_LIBGLOCALE
++ retval = _nl_find_msg (domain->successor[cnt], binding,
++ encoding, msgid1, &retlen);
++#else
+ retval = _nl_find_msg (domain->successor[cnt], binding,
+ msgid1, 1, &retlen);
++#endif
+
+ /* Resource problems are not fatal, instead we return no
+ translation. */
+- if (__glibc_unlikely (retval == (char *) -1))
+- goto no_translation;
++ if (__builtin_expect (retval == (char *) -1, 0))
++ goto return_untranslated;
+
+ if (retval != NULL)
+ {
+@@ -654,15 +759,14 @@ DCIGETTEXT (domainname, msgid1, msgid2, plural, n, category)
+ /* Returning -1 means that some resource problem exists
+ (likely memory) and that the strings could not be
+ converted. Return the original strings. */
+- if (__glibc_unlikely (retval == (char *) -1))
+- goto no_translation;
++ if (__builtin_expect (retval == (char *) -1, 0))
++ break;
+
+ if (retval != NULL)
+ {
+ /* Found the translation of MSGID1 in domain DOMAIN:
+ starting at RETVAL, RETLEN bytes. */
+ FREE_BLOCKS (block_list);
+-#if defined HAVE_TSEARCH || defined _LIBC
+ if (foundp == NULL)
+ {
+ /* Create a new entry and add it to the search tree. */
+@@ -673,41 +777,45 @@ DCIGETTEXT (domainname, msgid1, msgid2, plural, n, category)
+ msgid_len = strlen (msgid1) + 1;
+ size = offsetof (struct known_translation_t, msgid)
+ + msgid_len + domainname_len + 1;
+-# ifdef HAVE_PER_THREAD_LOCALE
++#ifdef HAVE_PER_THREAD_LOCALE
+ size += strlen (localename) + 1;
+-# endif
++#endif
+ newp = (struct known_translation_t *) malloc (size);
+ if (newp != NULL)
+ {
+ char *new_domainname;
+-# ifdef HAVE_PER_THREAD_LOCALE
++#ifdef HAVE_PER_THREAD_LOCALE
+ char *new_localename;
+-# endif
++#endif
+
+ new_domainname =
+- mempcpy (newp->msgid.appended, msgid1, msgid_len);
++ (char *) mempcpy (newp->msgid.appended, msgid1,
++ msgid_len);
+ memcpy (new_domainname, domainname, domainname_len + 1);
+-# ifdef HAVE_PER_THREAD_LOCALE
++#ifdef HAVE_PER_THREAD_LOCALE
+ new_localename = new_domainname + domainname_len + 1;
+ strcpy (new_localename, localename);
+-# endif
++#endif
+ newp->domainname = new_domainname;
+ newp->category = category;
+-# ifdef HAVE_PER_THREAD_LOCALE
++#ifdef HAVE_PER_THREAD_LOCALE
+ newp->localename = new_localename;
+-# endif
++#endif
++#ifdef IN_LIBGLOCALE
++ newp->encoding = encoding;
++#endif
+ newp->counter = _nl_msg_cat_cntr;
+ newp->domain = domain;
+ newp->translation = retval;
+ newp->translation_length = retlen;
+
+- __libc_rwlock_wrlock (tree_lock);
++ gl_rwlock_wrlock (tree_lock);
+
+ /* Insert the entry in the search tree. */
+ foundp = (struct known_translation_t **)
+ tsearch (newp, &root, transcmp);
+
+- __libc_rwlock_unlock (tree_lock);
++ gl_rwlock_unlock (tree_lock);
+
+ if (foundp == NULL
+ || __builtin_expect (*foundp != newp, 0))
+@@ -723,31 +831,68 @@ DCIGETTEXT (domainname, msgid1, msgid2, plural, n, category)
+ (*foundp)->translation = retval;
+ (*foundp)->translation_length = retlen;
+ }
+-#endif
++
+ __set_errno (saved_errno);
+
+ /* Now deal with plural. */
+ if (plural)
+ retval = plural_lookup (domain, n, retval, retlen);
+
++ gl_rwlock_unlock (_nl_state_lock);
++#ifdef _LIBC
+ __libc_rwlock_unlock (__libc_setlocale_lock);
+- __libc_rwlock_unlock (_nl_state_lock);
++#endif
+ return retval;
+ }
+ }
+ }
+- /* NOTREACHED */
++
++ return_untranslated:
++ /* Return the untranslated MSGID. */
++ FREE_BLOCKS (block_list);
++ gl_rwlock_unlock (_nl_state_lock);
++#ifdef _LIBC
++ __libc_rwlock_unlock (__libc_setlocale_lock);
++#endif
++#ifndef _LIBC
++ if (!ENABLE_SECURE)
++ {
++ extern void _nl_log_untranslated (const char *logfilename,
++ const char *domainname,
++ const char *msgid1, const char *msgid2,
++ int plural);
++ const char *logfilename = getenv ("GETTEXT_LOG_UNTRANSLATED");
++
++ if (logfilename != NULL && logfilename[0] != '\0')
++ _nl_log_untranslated (logfilename, domainname, msgid1, msgid2, plural);
++ }
++#endif
++ __set_errno (saved_errno);
++ return (plural == 0
++ ? (char *) msgid1
++ /* Use the Germanic plural rule. */
++ : n == 1 ? (char *) msgid1 : (char *) msgid2);
+ }
+
+
++/* Look up the translation of msgid within DOMAIN_FILE and DOMAINBINDING.
++ Return it if found. Return NULL if not found or in case of a conversion
++ failure (problem in the particular message catalog). Return (char *) -1
++ in case of a memory allocation failure during conversion (only if
++ ENCODING != NULL resp. CONVERT == true). */
+ char *
+ internal_function
+-_nl_find_msg (domain_file, domainbinding, msgid, convert, lengthp)
+- struct loaded_l10nfile *domain_file;
+- struct binding *domainbinding;
+- const char *msgid;
+- int convert;
+- size_t *lengthp;
++#ifdef IN_LIBGLOCALE
++_nl_find_msg (struct loaded_l10nfile *domain_file,
++ struct binding *domainbinding, const char *encoding,
++ const char *msgid,
++ size_t *lengthp)
++#else
++_nl_find_msg (struct loaded_l10nfile *domain_file,
++ struct binding *domainbinding,
++ const char *msgid, int convert,
++ size_t *lengthp)
++#endif
+ {
+ struct loaded_domain *domain;
+ nls_uint32 nstrings;
+@@ -853,19 +998,27 @@ _nl_find_msg (domain_file, domainbinding, msgid, convert, lengthp)
+ }
+
+ #if defined _LIBC || HAVE_ICONV
++# ifdef IN_LIBGLOCALE
++ if (encoding != NULL)
++# else
+ if (convert)
++# endif
+ {
+ /* We are supposed to do a conversion. */
++# ifndef IN_LIBGLOCALE
+ const char *encoding = get_output_charset (domainbinding);
++# endif
++ size_t nconversions;
++ struct converted_domain *convd;
++ size_t i;
+
+ /* Protect against reallocation of the table. */
+- __libc_rwlock_rdlock (domain->conversions_lock);
++ gl_rwlock_rdlock (domain->conversions_lock);
+
+ /* Search whether a table with converted translations for this
+ encoding has already been allocated. */
+- size_t nconversions = domain->nconversions;
+- struct converted_domain *convd = NULL;
+- size_t i;
++ nconversions = domain->nconversions;
++ convd = NULL;
+
+ for (i = nconversions; i > 0; )
+ {
+@@ -877,12 +1030,12 @@ _nl_find_msg (domain_file, domainbinding, msgid, convert, lengthp)
+ }
+ }
+
+- __libc_rwlock_unlock (domain->conversions_lock);
++ gl_rwlock_unlock (domain->conversions_lock);
+
+ if (convd == NULL)
+ {
+ /* We have to allocate a new conversions table. */
+- __libc_rwlock_wrlock (domain->conversions_lock);
++ gl_rwlock_wrlock (domain->conversions_lock);
+ nconversions = domain->nconversions;
+
+ /* Maybe in the meantime somebody added the translation.
+@@ -897,140 +1050,151 @@ _nl_find_msg (domain_file, domainbinding, msgid, convert, lengthp)
+ }
+ }
+
+- /* Allocate a table for the converted translations for this
+- encoding. */
+- struct converted_domain *new_conversions =
+- (struct converted_domain *)
+- realloc (domain->conversions,
+- (nconversions + 1) * sizeof (struct converted_domain));
++ {
++ /* Allocate a table for the converted translations for this
++ encoding. */
++ struct converted_domain *new_conversions =
++ (struct converted_domain *)
++ (domain->conversions != NULL
++ ? realloc (domain->conversions,
++ (nconversions + 1) * sizeof (struct converted_domain))
++ : malloc ((nconversions + 1) * sizeof (struct converted_domain)));
++
++ if (__builtin_expect (new_conversions == NULL, 0))
++ {
++ /* Nothing we can do, no more memory. We cannot use the
++ translation because it might be encoded incorrectly. */
++ unlock_fail:
++ gl_rwlock_unlock (domain->conversions_lock);
++ return (char *) -1;
++ }
+
+- if (__glibc_unlikely (new_conversions == NULL))
+- {
++ domain->conversions = new_conversions;
++
++ /* Copy the 'encoding' string to permanent storage. */
++ encoding = strdup (encoding);
++ if (__builtin_expect (encoding == NULL, 0))
+ /* Nothing we can do, no more memory. We cannot use the
+ translation because it might be encoded incorrectly. */
+- unlock_fail:
+- __libc_rwlock_unlock (domain->conversions_lock);
+- return (char *) -1;
+- }
+-
+- domain->conversions = new_conversions;
+-
+- /* Copy the 'encoding' string to permanent storage. */
+- encoding = strdup (encoding);
+- if (__glibc_unlikely (encoding == NULL))
+- /* Nothing we can do, no more memory. We cannot use the
+- translation because it might be encoded incorrectly. */
+- goto unlock_fail;
++ goto unlock_fail;
+
+- convd = &new_conversions[nconversions];
+- convd->encoding = encoding;
++ convd = &new_conversions[nconversions];
++ convd->encoding = encoding;
+
+- /* Find out about the character set the file is encoded with.
+- This can be found (in textual form) in the entry "". If this
+- entry does not exist or if this does not contain the 'charset='
+- information, we will assume the charset matches the one the
+- current locale and we don't have to perform any conversion. */
++ /* Find out about the character set the file is encoded with.
++ This can be found (in textual form) in the entry "". If this
++ entry does not exist or if this does not contain the 'charset='
++ information, we will assume the charset matches the one the
++ current locale and we don't have to perform any conversion. */
+ # ifdef _LIBC
+- convd->conv = (__gconv_t) -1;
++ convd->conv = (__gconv_t) -1;
+ # else
+ # if HAVE_ICONV
+- convd->conv = (iconv_t) -1;
++ convd->conv = (iconv_t) -1;
+ # endif
+ # endif
+- {
+- char *nullentry;
+- size_t nullentrylen;
+-
+- /* Get the header entry. This is a recursion, but it doesn't
+- reallocate domain->conversions because we pass convert = 0. */
+- nullentry =
+- _nl_find_msg (domain_file, domainbinding, "", 0, &nullentrylen);
++ {
++ char *nullentry;
++ size_t nullentrylen;
++
++ /* Get the header entry. This is a recursion, but it doesn't
++ reallocate domain->conversions because we pass
++ encoding = NULL or convert = 0, respectively. */
++ nullentry =
++# ifdef IN_LIBGLOCALE
++ _nl_find_msg (domain_file, domainbinding, NULL, "",
++ &nullentrylen);
++# else
++ _nl_find_msg (domain_file, domainbinding, "", 0, &nullentrylen);
++# endif
+
+- /* Resource problems are fatal. If we continue onwards we will
+- only attempt to calloc a new conv_tab and fail later. */
+- if (__glibc_unlikely (nullentry == (char *) -1))
+- return (char *) -1;
++ /* Resource problems are fatal. If we continue onwards we will
++ only attempt to calloc a new conv_tab and fail later. */
++ if (__builtin_expect (nullentry == (char *) -1, 0))
++ return (char *) -1;
+
+- if (nullentry != NULL)
+- {
+- const char *charsetstr;
++ if (nullentry != NULL)
++ {
++ const char *charsetstr;
+
+- charsetstr = strstr (nullentry, "charset=");
+- if (charsetstr != NULL)
+- {
+- size_t len;
+- char *charset;
+- const char *outcharset;
++ charsetstr = strstr (nullentry, "charset=");
++ if (charsetstr != NULL)
++ {
++ size_t len;
++ char *charset;
++ const char *outcharset;
+
+- charsetstr += strlen ("charset=");
+- len = strcspn (charsetstr, " \t\n");
++ charsetstr += strlen ("charset=");
++ len = strcspn (charsetstr, " \t\n");
+
+- charset = (char *) alloca (len + 1);
++ charset = (char *) alloca (len + 1);
+ # if defined _LIBC || HAVE_MEMPCPY
+- *((char *) mempcpy (charset, charsetstr, len)) = '\0';
++ *((char *) mempcpy (charset, charsetstr, len)) = '\0';
+ # else
+- memcpy (charset, charsetstr, len);
+- charset[len] = '\0';
++ memcpy (charset, charsetstr, len);
++ charset[len] = '\0';
+ # endif
+
+- outcharset = encoding;
++ outcharset = encoding;
+
+ # ifdef _LIBC
+- /* We always want to use transliteration. */
+- outcharset = norm_add_slashes (outcharset, "TRANSLIT");
+- charset = norm_add_slashes (charset, "");
+- int r = __gconv_open (outcharset, charset, &convd->conv,
+- GCONV_AVOID_NOCONV);
+- if (__glibc_unlikely (r != __GCONV_OK))
+- {
+- /* If the output encoding is the same there is
+- nothing to do. Otherwise do not use the
+- translation at all. */
+- if (__glibc_likely (r != __GCONV_NULCONV))
+- {
+- __libc_rwlock_unlock (domain->conversions_lock);
+- free ((char *) encoding);
+- return NULL;
+- }
+-
+- convd->conv = (__gconv_t) -1;
+- }
++ /* We always want to use transliteration. */
++ outcharset = norm_add_slashes (outcharset, "TRANSLIT");
++ charset = norm_add_slashes (charset, "");
++ int r = __gconv_open (outcharset, charset, &convd->conv,
++ GCONV_AVOID_NOCONV);
++ if (__builtin_expect (r != __GCONV_OK, 0))
++ {
++ /* If the output encoding is the same there is
++ nothing to do. Otherwise do not use the
++ translation at all. */
++ if (__builtin_expect (r != __GCONV_NULCONV, 1))
++ {
++ gl_rwlock_unlock (domain->conversions_lock);
++ free ((char *) encoding);
++ return NULL;
++ }
++
++ convd->conv = (__gconv_t) -1;
++ }
+ # else
+ # if HAVE_ICONV
+- /* When using GNU libc >= 2.2 or GNU libiconv >= 1.5,
+- we want to use transliteration. */
+-# if (__GLIBC__ == 2 && __GLIBC_MINOR__ >= 2) || __GLIBC__ > 2 \
++ /* When using GNU libc >= 2.2 or GNU libiconv >= 1.5,
++ we want to use transliteration. */
++# if (((__GLIBC__ == 2 && __GLIBC_MINOR__ >= 2) || __GLIBC__ > 2) \
++ && !defined __UCLIBC__) \
+ || _LIBICONV_VERSION >= 0x0105
+- if (strchr (outcharset, '/') == NULL)
+- {
+- char *tmp;
++ if (strchr (outcharset, '/') == NULL)
++ {
++ char *tmp;
+
+- len = strlen (outcharset);
+- tmp = (char *) alloca (len + 10 + 1);
+- memcpy (tmp, outcharset, len);
+- memcpy (tmp + len, "//TRANSLIT", 10 + 1);
+- outcharset = tmp;
++ len = strlen (outcharset);
++ tmp = (char *) alloca (len + 10 + 1);
++ memcpy (tmp, outcharset, len);
++ memcpy (tmp + len, "//TRANSLIT", 10 + 1);
++ outcharset = tmp;
+
+- convd->conv = iconv_open (outcharset, charset);
++ convd->conv = iconv_open (outcharset, charset);
+
+- freea (outcharset);
+- }
+- else
++ freea (outcharset);
++ }
++ else
+ # endif
+- convd->conv = iconv_open (outcharset, charset);
++ convd->conv = iconv_open (outcharset, charset);
+ # endif
+ # endif
+
+- freea (charset);
+- }
+- }
++ freea (charset);
++ }
++ }
++ }
++ convd->conv_tab = NULL;
++ /* Here domain->conversions is still == new_conversions. */
++ domain->nconversions++;
+ }
+- convd->conv_tab = NULL;
+- /* Here domain->conversions is still == new_conversions. */
+- domain->nconversions++;
+
+ found_convd:
+- __libc_rwlock_unlock (domain->conversions_lock);
++ gl_rwlock_unlock (domain->conversions_lock);
+ }
+
+ if (
+@@ -1043,7 +1207,6 @@ _nl_find_msg (domain_file, domainbinding, msgid, convert, lengthp)
+ # endif
+ )
+ {
+- __libc_lock_define_initialized (static, lock)
+ /* We are supposed to do a conversion. First allocate an
+ appropriate table with the same structure as the table
+ of translations in the file, where we can put the pointers
+@@ -1053,14 +1216,22 @@ _nl_find_msg (domain_file, domainbinding, msgid, convert, lengthp)
+ handle this case by converting RESULTLEN bytes, including
+ NULs. */
+
+- if (__glibc_unlikely (convd->conv_tab == NULL))
++ /* This lock primarily protects the memory management variables
++ freemem, freemem_size. It also protects write accesses to
++ convd->conv_tab. It's not worth using a separate lock (such
++ as domain->conversions_lock) for this purpose, because when
++ modifying convd->conv_tab, we also need to lock freemem,
++ freemem_size for most of the time. */
++ __libc_lock_define_initialized (static, lock)
++
++ if (__builtin_expect (convd->conv_tab == NULL, 0))
+ {
+ __libc_lock_lock (lock);
+ if (convd->conv_tab == NULL)
+ {
+- convd->conv_tab
+- = calloc (nstrings + domain->n_sysdep_strings,
+- sizeof (char *));
++ convd->conv_tab =
++ (char **) calloc (nstrings + domain->n_sysdep_strings,
++ sizeof (char *));
+ if (convd->conv_tab != NULL)
+ goto not_translated_yet;
+ /* Mark that we didn't succeed allocating a table. */
+@@ -1069,16 +1240,13 @@ _nl_find_msg (domain_file, domainbinding, msgid, convert, lengthp)
+ __libc_lock_unlock (lock);
+ }
+
+- if (__glibc_unlikely (convd->conv_tab == (char **) -1))
++ if (__builtin_expect (convd->conv_tab == (char **) -1, 0))
+ /* Nothing we can do, no more memory. We cannot use the
+ translation because it might be encoded incorrectly. */
+ return (char *) -1;
+
+ if (convd->conv_tab[act] == NULL)
+ {
+- __libc_lock_lock (lock);
+- not_translated_yet:;
+-
+ /* We haven't used this string so far, so it is not
+ translated yet. Do this now. */
+ /* We use a bit more efficient memory handling.
+@@ -1092,11 +1260,17 @@ _nl_find_msg (domain_file, domainbinding, msgid, convert, lengthp)
+ unsigned char *outbuf;
+ int malloc_count;
+ # ifndef _LIBC
+- transmem_block_t *transmem_list = NULL;
++ transmem_block_t *transmem_list;
+ # endif
+
++ __libc_lock_lock (lock);
++ not_translated_yet:
++
+ inbuf = (const unsigned char *) result;
+ outbuf = freemem + sizeof (size_t);
++# ifndef _LIBC
++ transmem_list = NULL;
++# endif
+
+ malloc_count = 0;
+ while (1)
+@@ -1190,7 +1364,7 @@ _nl_find_msg (domain_file, domainbinding, msgid, convert, lengthp)
+ /* Fall through and return -1. */
+ # endif
+ }
+- if (__glibc_unlikely (newmem == NULL))
++ if (__builtin_expect (newmem == NULL, 0))
+ {
+ freemem = NULL;
+ freemem_size = 0;
+@@ -1241,11 +1415,8 @@ _nl_find_msg (domain_file, domainbinding, msgid, convert, lengthp)
+ /* Look up a plural variant. */
+ static char *
+ internal_function
+-plural_lookup (domain, n, translation, translation_len)
+- struct loaded_l10nfile *domain;
+- unsigned long int n;
+- const char *translation;
+- size_t translation_len;
++plural_lookup (struct loaded_l10nfile *domain, unsigned long int n,
++ const char *translation, size_t translation_len)
+ {
+ struct loaded_domain *domaindata = (struct loaded_domain *) domain->data;
+ unsigned long int index;
+@@ -1282,8 +1453,7 @@ plural_lookup (domain, n, translation, translation_len)
+ /* Return string representation of locale CATEGORY. */
+ static const char *
+ internal_function
+-category_to_name (category)
+- int category;
++category_to_name (int category)
+ {
+ const char *retval;
+
+@@ -1340,41 +1510,102 @@ category_to_name (category)
+ }
+ #endif
+
+-/* Guess value of current locale from value of the environment variables. */
++/* Guess value of current locale from value of the environment variables
++ or system-dependent defaults. */
+ static const char *
+ internal_function
+-guess_category_value (category, categoryname)
+- int category;
+- const char *categoryname;
++#ifdef IN_LIBGLOCALE
++guess_category_value (int category, const char *categoryname,
++ const char *locale)
++
++#else
++guess_category_value (int category, const char *categoryname)
++#endif
+ {
+ const char *language;
+- const char *retval;
+-
+- /* The highest priority value is the `LANGUAGE' environment
+- variable. But we don't use the value if the currently selected
+- locale is the C locale. This is a GNU extension. */
+- language = getenv ("LANGUAGE");
+- if (language != NULL && language[0] == '\0')
+- language = NULL;
++#ifndef IN_LIBGLOCALE
++ const char *locale;
++# ifndef _LIBC
++ const char *language_default;
++ int locale_defaulted;
++# endif
++#endif
+
+- /* We have to proceed with the POSIX methods of looking to `LC_ALL',
++ /* We use the settings in the following order:
++ 1. The value of the environment variable 'LANGUAGE'. This is a GNU
++ extension. Its value can be a colon-separated list of locale names.
++ 2. The value of the environment variable 'LC_ALL', 'LC_xxx', or 'LANG'.
++ More precisely, the first among these that is set to a non-empty value.
++ This is how POSIX specifies it. The value is a single locale name.
++ 3. A system-dependent preference list of languages. Its value can be a
++ colon-separated list of locale names.
++ 4. A system-dependent default locale name.
++ This way:
++ - System-dependent settings can be overridden by environment variables.
++ - If the system provides both a list of languages and a default locale,
++ the former is used. */
++
++#ifndef IN_LIBGLOCALE
++ /* Fetch the locale name, through the POSIX method of looking to `LC_ALL',
+ `LC_xxx', and `LANG'. On some systems this can be done by the
+ `setlocale' function itself. */
+-#ifdef _LIBC
+- retval = __current_locale_name (category);
+-#else
+- retval = _nl_locale_name (category, categoryname);
++# ifdef _LIBC
++ locale = __current_locale_name (category);
++# else
++ locale_defaulted = 0;
++# if HAVE_USELOCALE
++ locale = _nl_locale_name_thread_unsafe (category, categoryname);
++ if (locale == NULL)
++# endif
++ {
++ locale = _nl_locale_name_posix (category, categoryname);
++ if (locale == NULL)
++ {
++ locale = _nl_locale_name_default ();
++ locale_defaulted = 1;
++ }
++ }
++# endif
+ #endif
+
+- return language != NULL && strcmp (retval, "C") != 0 ? language : retval;
++ /* Ignore LANGUAGE and its system-dependent analogon if the locale is set
++ to "C" because
++ 1. "C" locale usually uses the ASCII encoding, and most international
++ messages use non-ASCII characters. These characters get displayed
++ as question marks (if using glibc's iconv()) or as invalid 8-bit
++ characters (because other iconv()s refuse to convert most non-ASCII
++ characters to ASCII). In any case, the output is ugly.
++ 2. The precise output of some programs in the "C" locale is specified
++ by POSIX and should not depend on environment variables like
++ "LANGUAGE" or system-dependent information. We allow such programs
++ to use gettext(). */
++ if (strcmp (locale, "C") == 0)
++ return locale;
++
++ /* The highest priority value is the value of the 'LANGUAGE' environment
++ variable. */
++ language = getenv ("LANGUAGE");
++ if (language != NULL && language[0] != '\0')
++ return language;
++#if !defined IN_LIBGLOCALE && !defined _LIBC
++ /* The next priority value is the locale name, if not defaulted. */
++ if (locale_defaulted)
++ {
++ /* The next priority value is the default language preferences list. */
++ language_default = _nl_language_preferences_default ();
++ if (language_default != NULL)
++ return language_default;
++ }
++ /* The least priority value is the locale name, if defaulted. */
++#endif
++ return locale;
+ }
+
+-#if defined _LIBC || HAVE_ICONV
++#if (defined _LIBC || HAVE_ICONV) && !defined IN_LIBGLOCALE
+ /* Returns the output charset. */
+ static const char *
+ internal_function
+-get_output_charset (domainbinding)
+- struct binding *domainbinding;
++get_output_charset (struct binding *domainbinding)
+ {
+ /* The output charset should normally be determined by the locale. But
+ sometimes the locale is not used or not correctly set up, so we provide
+@@ -1415,7 +1646,6 @@ get_output_charset (domainbinding)
+ return _NL_CURRENT (LC_CTYPE, CODESET);
+ # else
+ # if HAVE_ICONV
+- extern const char *locale_charset PARAMS ((void));
+ return locale_charset ();
+ # endif
+ # endif
+@@ -1432,9 +1662,7 @@ get_output_charset (domainbinding)
+ to be defined. */
+ #if !_LIBC && !HAVE_STPCPY
+ static char *
+-stpcpy (dest, src)
+- char *dest;
+- const char *src;
++stpcpy (char *dest, const char *src)
+ {
+ while ((*dest++ = *src++) != '\0')
+ /* Do nothing. */ ;
+@@ -1444,15 +1672,16 @@ stpcpy (dest, src)
+
+ #if !_LIBC && !HAVE_MEMPCPY
+ static void *
+-mempcpy (dest, src, n)
+- void *dest;
+- const void *src;
+- size_t n;
++mempcpy (void *dest, const void *src, size_t n)
+ {
+ return (void *) ((char *) memcpy (dest, src, n) + n);
+ }
+ #endif
+
++#if !_LIBC && !HAVE_TSEARCH
++# include "tsearch.c"
++#endif
++
+
+ #ifdef _LIBC
+ /* If we want to free all resources we have to do some work at
+diff --git a/intl/dcngettext.c b/intl/dcngettext.c
+index f3404f3..67dcbcf 100644
+--- a/intl/dcngettext.c
++++ b/intl/dcngettext.c
+@@ -1,20 +1,18 @@
+ /* Implementation of the dcngettext(3) function.
+ Copyright (C) 1995-2014 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.
++ This program 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,
++ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+- Lesser General Public License for more details.
++ 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, see
+- <http://www.gnu.org/licenses/>. */
++ You should have received a copy of the GNU Lesser General Public License
++ along with this program. If not, see <http://www.gnu.org/licenses/>. */
+
+ #ifdef HAVE_CONFIG_H
+ # include <config.h>
+@@ -44,12 +42,9 @@
+ /* Look up MSGID in the DOMAINNAME message catalog for the current CATEGORY
+ locale. */
+ char *
+-DCNGETTEXT (domainname, msgid1, msgid2, n, category)
+- const char *domainname;
+- const char *msgid1;
+- const char *msgid2;
+- unsigned long int n;
+- int category;
++DCNGETTEXT (const char *domainname,
++ const char *msgid1, const char *msgid2, unsigned long int n,
++ int category)
+ {
+ return DCIGETTEXT (domainname, msgid1, msgid2, 1, n, category);
+ }
+diff --git a/intl/dgettext.c b/intl/dgettext.c
+index d7c2331..c0e6cd0 100644
+--- a/intl/dgettext.c
++++ b/intl/dgettext.c
+@@ -1,28 +1,27 @@
+ /* Implementation of the dgettext(3) function.
+ Copyright (C) 1995-2014 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.
++ This program 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,
++ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+- Lesser General Public License for more details.
++ 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, see
+- <http://www.gnu.org/licenses/>. */
++ You should have received a copy of the GNU Lesser General Public License
++ along with this program. If not, see <http://www.gnu.org/licenses/>. */
+
+ #ifdef HAVE_CONFIG_H
+ # include <config.h>
+ #endif
+
++#include "gettextP.h"
++
+ #include <locale.h>
+
+-#include "gettextP.h"
+ #ifdef _LIBC
+ # include <libintl.h>
+ #else
+@@ -46,9 +45,7 @@
+ /* Look up MSGID in the DOMAINNAME message catalog of the current
+ LC_MESSAGES locale. */
+ char *
+-DGETTEXT (domainname, msgid)
+- const char *domainname;
+- const char *msgid;
++DGETTEXT (const char *domainname, const char *msgid)
+ {
+ return DCGETTEXT (domainname, msgid, LC_MESSAGES);
+ }
+diff --git a/intl/dngettext.c b/intl/dngettext.c
+index 38cfdac..4d900e7 100644
+--- a/intl/dngettext.c
++++ b/intl/dngettext.c
+@@ -1,28 +1,27 @@
+ /* Implementation of the dngettext(3) function.
+ Copyright (C) 1995-2014 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.
++ This program 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,
++ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+- Lesser General Public License for more details.
++ 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, see
+- <http://www.gnu.org/licenses/>. */
++ You should have received a copy of the GNU Lesser General Public License
++ along with this program. If not, see <http://www.gnu.org/licenses/>. */
+
+ #ifdef HAVE_CONFIG_H
+ # include <config.h>
+ #endif
+
++#include "gettextP.h"
++
+ #include <locale.h>
+
+-#include "gettextP.h"
+ #ifdef _LIBC
+ # include <libintl.h>
+ #else
+@@ -46,11 +45,8 @@
+ /* Look up MSGID in the DOMAINNAME message catalog of the current
+ LC_MESSAGES locale and skip message according to the plural form. */
+ char *
+-DNGETTEXT (domainname, msgid1, msgid2, n)
+- const char *domainname;
+- const char *msgid1;
+- const char *msgid2;
+- unsigned long int n;
++DNGETTEXT (const char *domainname,
++ const char *msgid1, const char *msgid2, unsigned long int n)
+ {
+ return DCNGETTEXT (domainname, msgid1, msgid2, n, LC_MESSAGES);
+ }
+diff --git a/intl/eval-plural.h b/intl/eval-plural.h
+new file mode 100644
+index 0000000..924c8c3
+--- /dev/null
++++ b/intl/eval-plural.h
+@@ -0,0 +1,106 @@
++/* Plural expression evaluation.
++ Copyright (C) 2000-2003, 2007 Free Software Foundation, Inc.
++
++ This program 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 program is distributed in the hope that it will be useful,
++ but WITHOUT ANY WARRANTY; without even the implied warranty of
++ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
++ GNU Lesser General Public License for more details.
++
++ You should have received a copy of the GNU Lesser General Public License
++ along with this program. If not, see <http://www.gnu.org/licenses/>. */
++
++#ifndef STATIC
++#define STATIC static
++#endif
++
++/* Evaluate the plural expression and return an index value. */
++STATIC
++unsigned long int
++internal_function
++plural_eval (const struct expression *pexp, unsigned long int n)
++{
++ switch (pexp->nargs)
++ {
++ case 0:
++ switch (pexp->operation)
++ {
++ case var:
++ return n;
++ case num:
++ return pexp->val.num;
++ default:
++ break;
++ }
++ /* NOTREACHED */
++ break;
++ case 1:
++ {
++ /* pexp->operation must be lnot. */
++ unsigned long int arg = plural_eval (pexp->val.args[0], n);
++ return ! arg;
++ }
++ case 2:
++ {
++ unsigned long int leftarg = plural_eval (pexp->val.args[0], n);
++ if (pexp->operation == lor)
++ return leftarg || plural_eval (pexp->val.args[1], n);
++ else if (pexp->operation == land)
++ return leftarg && plural_eval (pexp->val.args[1], n);
++ else
++ {
++ unsigned long int rightarg = plural_eval (pexp->val.args[1], n);
++
++ switch (pexp->operation)
++ {
++ case mult:
++ return leftarg * rightarg;
++ case divide:
++#if !INTDIV0_RAISES_SIGFPE
++ if (rightarg == 0)
++ raise (SIGFPE);
++#endif
++ return leftarg / rightarg;
++ case module:
++#if !INTDIV0_RAISES_SIGFPE
++ if (rightarg == 0)
++ raise (SIGFPE);
++#endif
++ return leftarg % rightarg;
++ case plus:
++ return leftarg + rightarg;
++ case minus:
++ return leftarg - rightarg;
++ case less_than:
++ return leftarg < rightarg;
++ case greater_than:
++ return leftarg > rightarg;
++ case less_or_equal:
++ return leftarg <= rightarg;
++ case greater_or_equal:
++ return leftarg >= rightarg;
++ case equal:
++ return leftarg == rightarg;
++ case not_equal:
++ return leftarg != rightarg;
++ default:
++ break;
++ }
++ }
++ /* NOTREACHED */
++ break;
++ }
++ case 3:
++ {
++ /* pexp->operation must be qmop. */
++ unsigned long int boolarg = plural_eval (pexp->val.args[0], n);
++ return plural_eval (pexp->val.args[boolarg ? 1 : 2], n);
++ }
++ }
++ /* NOTREACHED */
++ return 0;
++}
+diff --git a/intl/explodename.c b/intl/explodename.c
+index 31fcf3d..9e049c7 100644
+--- a/intl/explodename.c
++++ b/intl/explodename.c
+@@ -1,20 +1,18 @@
+ /* Copyright (C) 1995-2014 Free Software Foundation, Inc.
+- This file is part of the GNU C Library.
+ Contributed by Ulrich Drepper <drepper at gnu.ai.mit.edu>, 1995.
+
+- 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.
++ This program 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,
++ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+- Lesser General Public License for more details.
++ 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, see
+- <http://www.gnu.org/licenses/>. */
++ You should have received a copy of the GNU Lesser General Public License
++ along with this program. If not, see <http://www.gnu.org/licenses/>. */
+
+ #ifdef HAVE_CONFIG_H
+ # include <config.h>
+@@ -37,11 +35,13 @@
+
+ /* @@ end of prolog @@ */
+
+-static char *_nl_find_language PARAMS ((const char *name));
++/* Split a locale name NAME into a leading language part and all the
++ rest. Return a pointer to the first character after the language,
++ i.e. to the first byte of the rest. */
++static char *_nl_find_language (const char *name);
+
+ static char *
+-_nl_find_language (name)
+- const char *name;
++_nl_find_language (const char *name)
+ {
+ while (name[0] != '\0' && name[0] != '_' && name[0] != '@' && name[0] != '.')
+ ++name;
+@@ -51,14 +51,10 @@ _nl_find_language (name)
+
+
+ int
+-_nl_explode_name (name, language, modifier, territory, codeset,
+- normalized_codeset)
+- char *name;
+- const char **language;
+- const char **modifier;
+- const char **territory;
+- const char **codeset;
+- const char **normalized_codeset;
++_nl_explode_name (char *name,
++ const char **language, const char **modifier,
++ const char **territory, const char **codeset,
++ const char **normalized_codeset)
+ {
+ char *cp;
+ int mask;
+@@ -77,8 +73,8 @@ _nl_explode_name (name, language, modifier, territory, codeset,
+ if (*language == cp)
+ /* This does not make sense: language has to be specified. Use
+ this entry as it is without exploding. Perhaps it is an alias. */
+- cp = __rawmemchr (*language, '\0');
+- else if (cp[0] != '@')
++ cp = strchr (*language, '\0');
++ else
+ {
+ if (cp[0] == '_')
+ {
+diff --git a/intl/finddomain.c b/intl/finddomain.c
+index 8a588bc..b5a48a5 100644
+--- a/intl/finddomain.c
++++ b/intl/finddomain.c
+@@ -1,21 +1,19 @@
+ /* Handle list of needed message catalogs
+ Copyright (C) 1995-2014 Free Software Foundation, Inc.
+- This file is part of the GNU C Library.
+ Written by Ulrich Drepper <drepper at gnu.org>, 1995.
+
+- 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.
++ This program 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,
++ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+- Lesser General Public License for more details.
++ 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, see
+- <http://www.gnu.org/licenses/>. */
++ You should have received a copy of the GNU Lesser General Public License
++ along with this program. If not, see <http://www.gnu.org/licenses/>. */
+
+ #ifdef HAVE_CONFIG_H
+ # include <config.h>
+@@ -33,11 +31,21 @@
+ #include "gettextP.h"
+ #ifdef _LIBC
+ # include <libintl.h>
+-# include <bits/libc-lock.h>
+ #else
+ # include "libgnuintl.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_rdlock __libc_rwlock_rdlock
++# define gl_rwlock_wrlock __libc_rwlock_wrlock
++# define gl_rwlock_unlock __libc_rwlock_unlock
++#else
++# include "lock.h"
++#endif
++
+ /* @@ end of prolog @@ */
+ /* List of already loaded domains. */
+ static struct loaded_l10nfile *_nl_loaded_domains;
+@@ -48,11 +56,8 @@ static struct loaded_l10nfile *_nl_loaded_domains;
+ established bindings. */
+ struct loaded_l10nfile *
+ internal_function
+-_nl_find_domain (dirname, locale, domainname, domainbinding)
+- const char *dirname;
+- char *locale;
+- const char *domainname;
+- struct binding *domainbinding;
++_nl_find_domain (const char *dirname, char *locale,
++ const char *domainname, struct binding *domainbinding)
+ {
+ struct loaded_l10nfile *retval;
+ const char *language;
+@@ -65,7 +70,7 @@ _nl_find_domain (dirname, locale, domainname, domainbinding)
+
+ /* LOCALE can consist of up to four recognized parts for the XPG syntax:
+
+- language[_territory[.codeset]][@modifier]
++ language[_territory][.codeset][@modifier]
+
+ Beside the first part all of them are allowed to be missing. If
+ the full specified locale is not found, the less specific one are
+@@ -78,15 +83,16 @@ _nl_find_domain (dirname, locale, domainname, domainbinding)
+ */
+
+ /* We need to protect modifying the _NL_LOADED_DOMAINS data. */
+- __libc_rwlock_define_initialized (static, lock);
+- __libc_rwlock_rdlock (lock);
++ gl_rwlock_define_initialized (static, lock);
++ gl_rwlock_rdlock (lock);
+
+ /* If we have already tested for this locale entry there has to
+ be one data set in the list of loaded domains. */
+ retval = _nl_make_l10nflist (&_nl_loaded_domains, dirname,
+ strlen (dirname) + 1, 0, locale, NULL, NULL,
+ NULL, NULL, domainname, 0);
+- __libc_rwlock_unlock (lock);
++
++ gl_rwlock_unlock (lock);
+
+ if (retval != NULL)
+ {
+@@ -117,11 +123,23 @@ _nl_find_domain (dirname, locale, domainname, domainbinding)
+ done. */
+ alias_value = _nl_expand_alias (locale);
+ if (alias_value != NULL)
+- locale = strdupa (alias_value);
++ {
++#if defined _LIBC || defined HAVE_STRDUP
++ locale = strdup (alias_value);
++ if (locale == NULL)
++ return NULL;
++#else
++ size_t len = strlen (alias_value) + 1;
++ locale = (char *) malloc (len);
++ if (locale == NULL)
++ return NULL;
++
++ memcpy (locale, alias_value, len);
++#endif
++ }
+
+ /* Now we determine the single parts of the locale name. First
+- look for the language. Termination symbols are `_' and `@' if
+- we use XPG4 style, and `_', `+', and `,' if we use CEN syntax. */
++ look for the language. Termination symbols are `_', '.', and `@'. */
+ mask = _nl_explode_name (locale, &language, &modifier, &territory,
+ &codeset, &normalized_codeset);
+ if (mask == -1)
+@@ -129,7 +147,7 @@ _nl_find_domain (dirname, locale, domainname, domainbinding)
+ return NULL;
+
+ /* We need to protect modifying the _NL_LOADED_DOMAINS data. */
+- __libc_rwlock_wrlock (lock);
++ gl_rwlock_wrlock (lock);
+
+ /* Create all possible locale entries which might be interested in
+ generalization. */
+@@ -137,7 +155,8 @@ _nl_find_domain (dirname, locale, domainname, domainbinding)
+ strlen (dirname) + 1, mask, language, territory,
+ codeset, normalized_codeset, modifier,
+ domainname, 1);
+- __libc_rwlock_unlock (lock);
++
++ gl_rwlock_unlock (lock);
+
+ if (retval == NULL)
+ /* This means we are out of core. */
+@@ -157,6 +176,10 @@ _nl_find_domain (dirname, locale, domainname, domainbinding)
+ }
+ }
+
++ /* The room for an alias was dynamically allocated. Free it now. */
++ if (alias_value != NULL)
++ free (locale);
++
+ out:
+ /* The space for normalized_codeset is dynamically allocated. Free it. */
+ if (mask & XPG_NORM_CODESET)
+diff --git a/intl/gettext.c b/intl/gettext.c
+index 3864a03..4a1af7e 100644
+--- a/intl/gettext.c
++++ b/intl/gettext.c
+@@ -1,20 +1,18 @@
+ /* Implementation of gettext(3) function.
+ Copyright (C) 1995-2014 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.
++ This program 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,
++ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+- Lesser General Public License for more details.
++ 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, see
+- <http://www.gnu.org/licenses/>. */
++ You should have received a copy of the GNU Lesser General Public License
++ along with this program. If not, see <http://www.gnu.org/licenses/>. */
+
+ #ifdef HAVE_CONFIG_H
+ # include <config.h>
+@@ -52,8 +50,7 @@
+ LC_MESSAGES locale. If not found, returns MSGID itself (the default
+ text). */
+ char *
+-GETTEXT (msgid)
+- const char *msgid;
++GETTEXT (const char *msgid)
+ {
+ return DCGETTEXT (NULL, msgid, LC_MESSAGES);
+ }
+diff --git a/intl/gettextP.h b/intl/gettextP.h
+index 3da2322..6f4c684 100644
+--- a/intl/gettextP.h
++++ b/intl/gettextP.h
+@@ -1,21 +1,19 @@
+ /* Header describing internals of libintl library.
+ Copyright (C) 1995-2014 Free Software Foundation, Inc.
+- This file is part of the GNU C Library.
+ Written by Ulrich Drepper <drepper at cygnus.com>, 1995.
+
+- 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.
++ This program 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,
++ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+- Lesser General Public License for more details.
++ 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, see
+- <http://www.gnu.org/licenses/>. */
++ You should have received a copy of the GNU Lesser General Public License
++ along with this program. If not, see <http://www.gnu.org/licenses/>. */
+
+ #ifndef _GETTEXTP_H
+ #define _GETTEXTP_H
+@@ -30,20 +28,67 @@
+ # endif
+ #endif
+
++/* Handle multi-threaded applications. */
++#ifdef _LIBC
++# include <bits/libc-lock.h>
++# define gl_rwlock_define __libc_rwlock_define
++#else
++# include "lock.h"
++#endif
++
++#ifdef _LIBC
++struct loaded_domain;
++extern char *__gettext (const char *__msgid);
++extern char *__dgettext (const char *__domainname, const char *__msgid);
++extern char *__dcgettext (const char *__domainname, const char *__msgid,
++ int __category);
++extern char *__ngettext (const char *__msgid1, const char *__msgid2,
++ unsigned long int __n);
++extern char *__dngettext (const char *__domainname,
++ const char *__msgid1, const char *__msgid2,
++ unsigned long int n);
++extern char *__dcngettext (const char *__domainname,
++ const char *__msgid1, const char *__msgid2,
++ unsigned long int __n, int __category);
++extern char *__dcigettext (const char *__domainname,
++ const char *__msgid1, const char *__msgid2,
++ int __plural, unsigned long int __n,
++ int __category);
++extern char *__textdomain (const char *__domainname);
++extern char *__bindtextdomain (const char *__domainname,
++ const char *__dirname);
++extern char *__bind_textdomain_codeset (const char *__domainname,
++ const char *__codeset);
++extern void _nl_finddomain_subfreeres (void) attribute_hidden;
++extern void _nl_unload_domain (struct loaded_domain *__domain)
++ internal_function attribute_hidden;
++#else
++/* Declare the exported libintl_* functions, in a way that allows us to
++ call them under their real name. */
++# undef _INTL_REDIRECT_INLINE
++# undef _INTL_REDIRECT_MACROS
++# define _INTL_REDIRECT_MACROS
++# include "libgnuintl.h"
++# ifdef IN_LIBGLOCALE
++extern char *gl_dcigettext (const char *__domainname,
++ const char *__msgid1, const char *__msgid2,
++ int __plural, unsigned long int __n,
++ int __category,
++ const char *__localename, const char *__encoding);
++# else
++extern char *libintl_dcigettext (const char *__domainname,
++ const char *__msgid1, const char *__msgid2,
++ int __plural, unsigned long int __n,
++ int __category);
++# endif
++#endif
++
+ #include "loadinfo.h"
+
+ #include "gmo.h" /* Get nls_uint32. */
+
+ /* @@ end of prolog @@ */
+
+-#ifndef PARAMS
+-# if __STDC__ || defined __GNUC__ || defined __SUNPRO_C || defined __cplusplus || __PROTOTYPES
+-# define PARAMS(args) args
+-# else
+-# define PARAMS(args) ()
+-# endif
+-#endif
+-
+ #ifndef internal_function
+ # define internal_function
+ #endif
+@@ -52,6 +97,12 @@
+ # define attribute_hidden
+ #endif
+
++/* Tell the compiler when a conditional or integer expression is
++ almost always true or almost always false. */
++#ifndef HAVE_BUILTIN_EXPECT
++# define __builtin_expect(expr, val) (expr)
++#endif
++
+ #ifndef W
+ # define W(flag, data) ((flag) ? SWAP (data) : (data))
+ #endif
+@@ -61,11 +112,13 @@
+ # include <byteswap.h>
+ # define SWAP(i) bswap_32 (i)
+ #else
+-static nls_uint32 SWAP PARAMS ((nls_uint32 i));
+-
+ static inline nls_uint32
++# ifdef __cplusplus
++SWAP (nls_uint32 i)
++# else
+ SWAP (i)
+ nls_uint32 i;
++# endif
+ {
+ return (i << 24) | ((i & 0xff00) << 8) | ((i >> 8) & 0xff00) | (i >> 24);
+ }
+@@ -139,7 +192,7 @@ struct loaded_domain
+ /* Cache of charset conversions of the translated strings. */
+ struct converted_domain *conversions;
+ size_t nconversions;
+- __libc_rwlock_define (, conversions_lock);
++ gl_rwlock_define (, conversions_lock)
+
+ const struct expression *plural;
+ unsigned long int nplurals;
+@@ -166,82 +219,92 @@ struct binding
+ /* A counter which is incremented each time some previous translations
+ become invalid.
+ This variable is part of the external ABI of the GNU libintl. */
+-extern int _nl_msg_cat_cntr;
++#ifdef IN_LIBGLOCALE
++# include <glocale/config.h>
++extern LIBGLOCALE_DLL_EXPORTED int _nl_msg_cat_cntr;
++#else
++extern LIBINTL_DLL_EXPORTED int _nl_msg_cat_cntr;
++#endif
+
+ #ifndef _LIBC
+-const char *_nl_locale_name PARAMS ((int category, const char *categoryname));
++extern const char *_nl_language_preferences_default (void);
++# define gl_locale_name_canonicalize _nl_locale_name_canonicalize
++extern void _nl_locale_name_canonicalize (char *name);
++# define gl_locale_name_from_win32_LANGID _nl_locale_name_from_win32_LANGID
++/* extern const char *_nl_locale_name_from_win32_LANGID (LANGID langid); */
++# define gl_locale_name_from_win32_LCID _nl_locale_name_from_win32_LCID
++/* extern const char *_nl_locale_name_from_win32_LCID (LCID lcid); */
++# define gl_locale_name_thread_unsafe _nl_locale_name_thread_unsafe
++extern const char *_nl_locale_name_thread_unsafe (int category,
++ const char *categoryname);
++# define gl_locale_name_thread _nl_locale_name_thread
++/* extern const char *_nl_locale_name_thread (int category,
++ const char *categoryname); */
++# define gl_locale_name_posix _nl_locale_name_posix
++extern const char *_nl_locale_name_posix (int category,
++ const char *categoryname);
++# define gl_locale_name_environ _nl_locale_name_environ
++extern const char *_nl_locale_name_environ (int category,
++ const char *categoryname);
++# define gl_locale_name_default _nl_locale_name_default
++extern const char *_nl_locale_name_default (void);
++# define gl_locale_name _nl_locale_name
++/* extern const char *_nl_locale_name (int category,
++ const char *categoryname); */
+ #endif
+
+-struct loaded_l10nfile *_nl_find_domain PARAMS ((const char *__dirname,
+- char *__locale,
+- const char *__domainname,
+- struct binding *__domainbinding))
++struct loaded_l10nfile *_nl_find_domain (const char *__dirname, char *__locale,
++ const char *__domainname,
++ struct binding *__domainbinding)
+ internal_function;
+-void _nl_load_domain PARAMS ((struct loaded_l10nfile *__domain,
+- struct binding *__domainbinding))
++void _nl_load_domain (struct loaded_l10nfile *__domain,
++ struct binding *__domainbinding)
+ internal_function;
+
+-char *_nl_find_msg PARAMS ((struct loaded_l10nfile *domain_file,
+- struct binding *domainbinding, const char *msgid,
+- int convert, size_t *lengthp))
++#ifdef IN_LIBGLOCALE
++char *_nl_find_msg (struct loaded_l10nfile *domain_file,
++ struct binding *domainbinding, const char *encoding,
++ const char *msgid,
++ size_t *lengthp)
+ internal_function;
++#else
++char *_nl_find_msg (struct loaded_l10nfile *domain_file,
++ struct binding *domainbinding, const char *msgid,
++ int convert, size_t *lengthp)
++ internal_function;
++#endif
+
++/* The internal variables in the standalone libintl.a must have different
++ names than the internal variables in GNU libc, otherwise programs
++ using libintl.a cannot be linked statically. */
++#if !defined _LIBC
++# define _nl_default_dirname libintl_nl_default_dirname
++# define _nl_domain_bindings libintl_nl_domain_bindings
++#endif
++
++/* Contains the default location of the message catalogs. */
++extern const char _nl_default_dirname[];
+ #ifdef _LIBC
+-extern char *__gettext PARAMS ((const char *__msgid));
+-extern char *__dgettext PARAMS ((const char *__domainname,
+- const char *__msgid));
+-extern char *__dcgettext PARAMS ((const char *__domainname,
+- const char *__msgid, int __category));
+-extern char *__ngettext PARAMS ((const char *__msgid1, const char *__msgid2,
+- unsigned long int __n));
+-extern char *__dngettext PARAMS ((const char *__domainname,
+- const char *__msgid1, const char *__msgid2,
+- unsigned long int n));
+-extern char *__dcngettext PARAMS ((const char *__domainname,
+- const char *__msgid1, const char *__msgid2,
+- unsigned long int __n, int __category));
+-extern char *__dcigettext PARAMS ((const char *__domainname,
+- const char *__msgid1, const char *__msgid2,
+- int __plural, unsigned long int __n,
+- int __category));
+-extern char *__textdomain PARAMS ((const char *__domainname));
+-extern char *__bindtextdomain PARAMS ((const char *__domainname,
+- const char *__dirname));
+-extern char *__bind_textdomain_codeset PARAMS ((const char *__domainname,
+- const char *__codeset));
+-extern void _nl_finddomain_subfreeres PARAMS ((void)) attribute_hidden;
+-extern void _nl_unload_domain PARAMS ((struct loaded_domain *__domain))
+- internal_function attribute_hidden;
+-#else
+-extern char *libintl_gettext PARAMS ((const char *__msgid));
+-extern char *libintl_dgettext PARAMS ((const char *__domainname,
+- const char *__msgid));
+-extern char *libintl_dcgettext PARAMS ((const char *__domainname,
+- const char *__msgid, int __category));
+-extern char *libintl_ngettext PARAMS ((const char *__msgid1,
+- const char *__msgid2,
+- unsigned long int __n));
+-extern char *libintl_dngettext PARAMS ((const char *__domainname,
+- const char *__msgid1,
+- const char *__msgid2,
+- unsigned long int __n));
+-extern char *libintl_dcngettext PARAMS ((const char *__domainname,
+- const char *__msgid1,
+- const char *__msgid2,
+- unsigned long int __n,
+- int __category));
+-extern char *libintl_dcigettext PARAMS ((const char *__domainname,
+- const char *__msgid1,
+- const char *__msgid2,
+- int __plural, unsigned long int __n,
+- int __category));
+-extern char *libintl_textdomain PARAMS ((const char *__domainname));
+-extern char *libintl_bindtextdomain PARAMS ((const char *__domainname,
+- const char *__dirname));
+-extern char *libintl_bind_textdomain_codeset PARAMS ((const char *__domainname,
+- const char *__codeset));
++libc_hidden_proto (_nl_default_dirname)
++#endif
++
++/* List with bindings of specific domains. */
++extern struct binding *_nl_domain_bindings;
++
++/* The internal variables in the standalone libintl.a must have different
++ names than the internal variables in GNU libc, otherwise programs
++ using libintl.a cannot be linked statically. */
++#if !defined _LIBC
++# define _nl_default_default_domain libintl_nl_default_default_domain
++# define _nl_current_default_domain libintl_nl_current_default_domain
+ #endif
+
++/* Name of the default text domain. */
++extern const char _nl_default_default_domain[] attribute_hidden;
++
++/* Default text domain in which entries for gettext(3) are to be found. */
++extern const char *_nl_current_default_domain attribute_hidden;
++
+ /* @@ begin of epilog @@ */
+
+ #endif /* gettextP.h */
+diff --git a/intl/gmo.h b/intl/gmo.h
+index c9330db..4d18e9a 100644
+--- a/intl/gmo.h
++++ b/intl/gmo.h
+@@ -1,20 +1,18 @@
+-/* Internal header for GNU gettext internationalization functions.
++/* Description of GNU message catalog format: general file layout.
+ Copyright (C) 1995-2014 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.
++ This program 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,
++ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+- Lesser General Public License for more details.
++ 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, see
+- <http://www.gnu.org/licenses/>. */
++ You should have received a copy of the GNU Lesser General Public License
++ along with this program. If not, see <http://www.gnu.org/licenses/>. */
+
+ #ifndef _GETTEXT_H
+ #define _GETTEXT_H 1
+@@ -124,6 +122,15 @@ struct sysdep_segment
+ nls_uint32 offset;
+ };
+
++/* Pair of a static and a system dependent segment, in struct sysdep_string. */
++struct segment_pair
++{
++ /* Size of static segment. */
++ nls_uint32 segsize;
++ /* Reference to system dependent string segment, or ~0 at the end. */
++ nls_uint32 sysdepref;
++};
++
+ /* Descriptor for system dependent string. */
+ struct sysdep_string
+ {
+@@ -131,13 +138,7 @@ struct sysdep_string
+ nls_uint32 offset;
+ /* Alternating sequence of static and system dependent segments.
+ The last segment is a static segment, including the trailing NUL. */
+- struct segment_pair
+- {
+- /* Size of static segment. */
+- nls_uint32 segsize;
+- /* Reference to system dependent string segment, or ~0 at the end. */
+- nls_uint32 sysdepref;
+- } segments[1];
++ struct segment_pair segments[1];
+ };
+
+ /* Marker for the end of the segments[] array. This has the value 0xFFFFFFFF,
+diff --git a/intl/hash-string.c b/intl/hash-string.c
+index 3e53e2a..f44ebc0 100644
+--- a/intl/hash-string.c
++++ b/intl/hash-string.c
+@@ -16,6 +16,11 @@
+ License along with the GNU C Library; if not, see
+ <http://www.gnu.org/licenses/>. */
+
++#ifdef HAVE_CONFIG_H
++# include <config.h>
++#endif
++
++/* Specification. */
+ #include "hash-string.h"
+
+
+@@ -23,8 +28,7 @@
+ [see Aho/Sethi/Ullman, COMPILERS: Principles, Techniques and Tools,
+ 1986, 1987 Bell Telephone Laboratories, Inc.] */
+ unsigned long int
+-__hash_string (str_param)
+- const char *str_param;
++__hash_string (const char *str_param)
+ {
+ unsigned long int hval, g;
+ const char *str = str_param;
+diff --git a/intl/hash-string.h b/intl/hash-string.h
+index 646631f..339a4f8 100644
+--- a/intl/hash-string.h
++++ b/intl/hash-string.h
+@@ -1,37 +1,34 @@
+-/* Implements a string hashing function.
++/* Description of GNU message catalog format: string hashing function.
+ Copyright (C) 1995-2014 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.
++ This program 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,
++ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+- Lesser General Public License for more details.
++ 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, see
+- <http://www.gnu.org/licenses/>. */
++ You should have received a copy of the GNU Lesser General Public License
++ along with this program. If not, see <http://www.gnu.org/licenses/>. */
+
+ /* @@ end of prolog @@ */
+
+-#ifndef PARAMS
+-# if __STDC__ || defined __GNUC__ || defined __SUNPRO_C || defined __cplusplus || __PROTOTYPES
+-# define PARAMS(Args) Args
+-# else
+-# define PARAMS(Args) ()
+-# endif
+-#endif
+-
+ /* We assume to have `unsigned long int' value with at least 32 bits. */
+ #define HASHWORDBITS 32
+
+
++#ifndef _LIBC
++# ifdef IN_LIBINTL
++# define __hash_string libintl_hash_string
++# else
++# define __hash_string hash_string
++# endif
++#endif
++
+ /* Defines the so called `hashpjw' function by P.J. Weinberger
+ [see Aho/Sethi/Ullman, COMPILERS: Principles, Techniques and Tools,
+ 1986, 1987 Bell Telephone Laboratories, Inc.] */
+-extern unsigned long int __hash_string PARAMS ((const char *__str_param))
+- attribute_hidden;
++extern unsigned long int __hash_string (const char *str_param);
+diff --git a/intl/l10nflist.c b/intl/l10nflist.c
+index 428a3f1..5b7c2bd 100644
+--- a/intl/l10nflist.c
++++ b/intl/l10nflist.c
+@@ -1,20 +1,18 @@
+ /* Copyright (C) 1995-2014 Free Software Foundation, Inc.
+- This file is part of the GNU C Library.
+ Contributed by Ulrich Drepper <drepper at gnu.ai.mit.edu>, 1995.
+
+- 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.
++ This program 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,
++ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+- Lesser General Public License for more details.
++ 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, see
+- <http://www.gnu.org/licenses/>. */
++ You should have received a copy of the GNU Lesser General Public License
++ along with this program. If not, see <http://www.gnu.org/licenses/>. */
+
+ /* Tell glibc's <string.h> to provide a prototype for stpcpy().
+ This must come before <config.h> because <config.h> may include
+@@ -58,20 +56,19 @@
+ # endif
+ #else
+ # ifndef HAVE_STPCPY
+-static char *stpcpy PARAMS ((char *dest, const char *src));
++static char *stpcpy (char *dest, const char *src);
+ # endif
+ #endif
+
+ /* Define function which are usually not available. */
+
+-#if !defined _LIBC && !defined HAVE___ARGZ_COUNT
++#if defined HAVE_ARGZ_COUNT
++# undef __argz_count
++# define __argz_count argz_count
++#else
+ /* Returns the number of strings in ARGZ. */
+-static size_t argz_count__ PARAMS ((const char *argz, size_t len));
+-
+ static size_t
+-argz_count__ (argz, len)
+- const char *argz;
+- size_t len;
++argz_count__ (const char *argz, size_t len)
+ {
+ size_t count = 0;
+ while (len > 0)
+@@ -85,18 +82,16 @@ argz_count__ (argz, len)
+ }
+ # undef __argz_count
+ # define __argz_count(argz, len) argz_count__ (argz, len)
+-#endif /* !_LIBC && !HAVE___ARGZ_COUNT */
++#endif /* !_LIBC && !HAVE_ARGZ_COUNT */
+
+-#if !defined _LIBC && !defined HAVE___ARGZ_STRINGIFY
++#if defined HAVE_ARGZ_STRINGIFY
++# undef __argz_stringify
++# define __argz_stringify argz_stringify
++#else
+ /* Make '\0' separated arg vector ARGZ printable by converting all the '\0's
+ except the last into the character SEP. */
+-static void argz_stringify__ PARAMS ((char *argz, size_t len, int sep));
+-
+ static void
+-argz_stringify__ (argz, len, sep)
+- char *argz;
+- size_t len;
+- int sep;
++argz_stringify__ (char *argz, size_t len, int sep)
+ {
+ while (len > 0)
+ {
+@@ -109,22 +104,20 @@ argz_stringify__ (argz, len, sep)
+ }
+ # undef __argz_stringify
+ # define __argz_stringify(argz, len, sep) argz_stringify__ (argz, len, sep)
+-#endif /* !_LIBC && !HAVE___ARGZ_STRINGIFY */
+-
+-#if !defined _LIBC && !defined HAVE___ARGZ_NEXT
+-static char *argz_next__ PARAMS ((char *argz, size_t argz_len,
+- const char *entry));
++#endif /* !_LIBC && !HAVE_ARGZ_STRINGIFY */
+
++#ifdef _LIBC
++#elif defined HAVE_ARGZ_NEXT
++# undef __argz_next
++# define __argz_next argz_next
++#else
+ static char *
+-argz_next__ (argz, argz_len, entry)
+- char *argz;
+- size_t argz_len;
+- const char *entry;
++argz_next__ (char *argz, size_t argz_len, const char *entry)
+ {
+ if (entry)
+ {
+ if (entry < argz + argz_len)
+- entry = strchr (entry, '\0') + 1;
++ entry = strchr (entry, '\0') + 1;
+
+ return entry >= argz + argz_len ? NULL : (char *) entry;
+ }
+@@ -136,16 +129,12 @@ argz_next__ (argz, argz_len, entry)
+ }
+ # undef __argz_next
+ # define __argz_next(argz, len, entry) argz_next__ (argz, len, entry)
+-#endif /* !_LIBC && !HAVE___ARGZ_NEXT */
+-
++#endif /* !_LIBC && !HAVE_ARGZ_NEXT */
+
+ /* Return number of bits set in X. */
+ #ifndef ARCH_POP
+-static int pop PARAMS ((int x));
+-
+ static inline int
+-pop (x)
+- int x;
++pop (int x)
+ {
+ /* We assume that no more than 16 bits are used. */
+ x = ((x & ~0x5555) >> 1) + (x & 0x5555);
+@@ -159,20 +148,12 @@ pop (x)
+
+
+ struct loaded_l10nfile *
+-_nl_make_l10nflist (l10nfile_list, dirlist, dirlist_len, mask, language,
+- territory, codeset, normalized_codeset, modifier,
+- filename, do_allocate)
+- struct loaded_l10nfile **l10nfile_list;
+- const char *dirlist;
+- size_t dirlist_len;
+- int mask;
+- const char *language;
+- const char *territory;
+- const char *codeset;
+- const char *normalized_codeset;
+- const char *modifier;
+- const char *filename;
+- int do_allocate;
++_nl_make_l10nflist (struct loaded_l10nfile **l10nfile_list,
++ const char *dirlist, size_t dirlist_len,
++ int mask, const char *language, const char *territory,
++ const char *codeset, const char *normalized_codeset,
++ const char *modifier,
++ const char *filename, int do_allocate)
+ {
+ char *abs_filename;
+ struct loaded_l10nfile *last = NULL;
+@@ -315,11 +296,9 @@ _nl_make_l10nflist (l10nfile_list, dirlist, dirlist_len, mask, language,
+ names. The return value is dynamically allocated and has to be
+ freed by the caller. */
+ const char *
+-_nl_normalize_codeset (codeset, name_len)
+- const char *codeset;
+- size_t name_len;
++_nl_normalize_codeset (const char *codeset, size_t name_len)
+ {
+- int len = 0;
++ size_t len = 0;
+ int only_digit = 1;
+ char *retval;
+ char *wp;
+@@ -343,9 +322,10 @@ _nl_normalize_codeset (codeset, name_len)
+
+ if (retval != NULL)
+ {
+- wp = retval;
+ if (only_digit)
+- wp = stpcpy (wp, "iso");
++ wp = stpcpy (retval, "iso");
++ else
++ wp = retval;
+
+ for (cnt = 0; cnt < name_len; ++cnt)
+ if (__isalpha_l ((unsigned char) codeset[cnt], locale))
+@@ -368,9 +348,7 @@ _nl_normalize_codeset (codeset, name_len)
+ to be defined. */
+ #if !_LIBC && !HAVE_STPCPY
+ static char *
+-stpcpy (dest, src)
+- char *dest;
+- const char *src;
++stpcpy (char *dest, const char *src)
+ {
+ while ((*dest++ = *src++) != '\0')
+ /* Do nothing. */ ;
+diff --git a/intl/loadinfo.h b/intl/loadinfo.h
+index e11b2e8..adf5bc9 100644
+--- a/intl/loadinfo.h
++++ b/intl/loadinfo.h
+@@ -2,19 +2,18 @@
+ This file is part of the GNU C Library.
+ Contributed by Ulrich Drepper <drepper at cygnus.com>, 1996.
+
+- 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.
++ This program 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,
++ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+- Lesser General Public License for more details.
++ 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, see
+- <http://www.gnu.org/licenses/>. */
++ You should have received a copy of the GNU Lesser General Public License
++ along with this program. If not, see <http://www.gnu.org/licenses/>. */
+
+ #ifndef _LOADINFO_H
+ #define _LOADINFO_H 1
+@@ -31,18 +30,29 @@
+ in gettextP.h.
+ */
+
+-#ifndef PARAMS
+-# if __STDC__ || defined __GNUC__ || defined __SUNPRO_C || defined __cplusplus || __PROTOTYPES
+-# define PARAMS(args) args
+-# else
+-# define PARAMS(args) ()
+-# endif
+-#endif
+-
+ #ifndef internal_function
+ # define internal_function
+ #endif
+
++#ifndef LIBINTL_DLL_EXPORTED
++# define LIBINTL_DLL_EXPORTED
++#endif
++
++/* Tell the compiler when a conditional or integer expression is
++ almost always true or almost always false. */
++#ifndef HAVE_BUILTIN_EXPECT
++# define __builtin_expect(expr, val) (expr)
++#endif
++
++/* Separator in PATH like lists of pathnames. */
++#if ((defined _WIN32 || defined __WIN32__) && !defined __CYGWIN__) || defined __EMX__ || defined __DJGPP__
++ /* Win32, OS/2, DOS */
++# define PATH_SEPARATOR ';'
++#else
++ /* Unix */
++# define PATH_SEPARATOR ':'
++#endif
++
+ /* Encoding of locale name parts. */
+ #define XPG_NORM_CODESET 1
+ #define XPG_CODESET 2
+@@ -66,27 +76,55 @@ struct loaded_l10nfile
+ names. Normalization allows the user to use any of the common
+ names. The return value is dynamically allocated and has to be
+ freed by the caller. */
+-extern const char *_nl_normalize_codeset PARAMS ((const char *codeset,
+- size_t name_len));
+-
++extern const char *_nl_normalize_codeset (const char *codeset,
++ size_t name_len);
++
++/* Lookup a locale dependent file.
++ *L10NFILE_LIST denotes a pool of lookup results of locale dependent
++ files of the same kind, sorted in decreasing order of ->filename.
++ DIRLIST and DIRLIST_LEN are an argz list of directories in which to
++ look, containing at least one directory (i.e. DIRLIST_LEN > 0).
++ MASK, LANGUAGE, TERRITORY, CODESET, NORMALIZED_CODESET, MODIFIER
++ are the pieces of the locale name, as produced by _nl_explode_name().
++ FILENAME is the filename suffix.
++ The return value is the lookup result, either found in *L10NFILE_LIST,
++ or - if DO_ALLOCATE is nonzero - freshly allocated, or possibly NULL.
++ If the return value is non-NULL, it is added to *L10NFILE_LIST, and
++ its ->next field denotes the chaining inside *L10NFILE_LIST, and
++ furthermore its ->successor[] field contains a list of other lookup
++ results from which this lookup result inherits. */
+ extern struct loaded_l10nfile *
+-_nl_make_l10nflist PARAMS ((struct loaded_l10nfile **l10nfile_list,
+- const char *dirlist, size_t dirlist_len, int mask,
+- const char *language, const char *territory,
+- const char *codeset,
+- const char *normalized_codeset,
+- const char *modifier, const char *filename,
+- int do_allocate));
+-
+-
+-extern const char *_nl_expand_alias PARAMS ((const char *name));
+-
+-/* normalized_codeset is dynamically allocated and has to be freed by
+- the caller. */
+-extern int _nl_explode_name PARAMS ((char *name, const char **language,
+- const char **modifier,
+- const char **territory,
+- const char **codeset,
+- const char **normalized_codeset));
++_nl_make_l10nflist (struct loaded_l10nfile **l10nfile_list,
++ const char *dirlist, size_t dirlist_len, int mask,
++ const char *language, const char *territory,
++ const char *codeset, const char *normalized_codeset,
++ const char *modifier,
++ const char *filename, int do_allocate);
++
++/* Lookup the real locale name for a locale alias NAME, or NULL if
++ NAME is not a locale alias (but possibly a real locale name).
++ The return value is statically allocated and must not be freed. */
++/* Part of the libintl ABI only for the sake of the gettext.m4 macro. */
++extern LIBINTL_DLL_EXPORTED const char *_nl_expand_alias (const char *name);
++
++/* Split a locale name NAME into its pieces: language, modifier,
++ territory, codeset.
++ NAME gets destructively modified: NUL bytes are inserted here and
++ there. *LANGUAGE gets assigned NAME. Each of *MODIFIER, *TERRITORY,
++ *CODESET gets assigned either a pointer into the old NAME string, or
++ NULL. *NORMALIZED_CODESET gets assigned the expanded *CODESET, if it
++ is different from *CODESET; this one is dynamically allocated and has
++ to be freed by the caller.
++ The return value is a bitmask, where each bit corresponds to one
++ filled-in value:
++ XPG_MODIFIER for *MODIFIER,
++ XPG_TERRITORY for *TERRITORY,
++ XPG_CODESET for *CODESET,
++ XPG_NORM_CODESET for *NORMALIZED_CODESET.
++ */
++extern int _nl_explode_name (char *name, const char **language,
++ const char **modifier, const char **territory,
++ const char **codeset,
++ const char **normalized_codeset);
+
+ #endif /* loadinfo.h */
+diff --git a/intl/loadmsgcat.c b/intl/loadmsgcat.c
+index 2ea0f10..4074c4c 100644
+--- a/intl/loadmsgcat.c
++++ b/intl/loadmsgcat.c
+@@ -1,20 +1,18 @@
+ /* Load needed message catalogs.
+ Copyright (C) 1995-2014 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.
++ This program 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,
++ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+- Lesser General Public License for more details.
++ 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, see
+- <http://www.gnu.org/licenses/>. */
++ You should have received a copy of the GNU Lesser General Public License
++ along with this program. If not, see <http://www.gnu.org/licenses/>. */
+
+ /* Tell glibc's <string.h> to provide a prototype for mempcpy().
+ This must come before <config.h> because <config.h> may include
+diff --git a/intl/localealias.c b/intl/localealias.c
+index 9ab4328..e65b31b 100644
+--- a/intl/localealias.c
++++ b/intl/localealias.c
+@@ -1,20 +1,18 @@
+ /* Handle aliases for locale names.
+ Copyright (C) 1995-2014 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.
++ This program 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,
++ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+- Lesser General Public License for more details.
++ 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, see
+- <http://www.gnu.org/licenses/>. */
++ You should have received a copy of the GNU Lesser General Public License
++ along with this program. If not, see <http://www.gnu.org/licenses/>. */
+
+ /* Tell glibc's <string.h> to provide a prototype for mempcpy().
+ This must come before <config.h> because <config.h> may include
+@@ -39,14 +37,19 @@
+ # define alloca __builtin_alloca
+ # define HAVE_ALLOCA 1
+ #else
+-# if defined HAVE_ALLOCA_H || defined _LIBC
+-# include <alloca.h>
++# ifdef _MSC_VER
++# include <malloc.h>
++# define alloca _alloca
+ # else
+-# ifdef _AIX
+- #pragma alloca
++# if defined HAVE_ALLOCA_H || defined _LIBC
++# include <alloca.h>
+ # else
+-# ifndef alloca
++# ifdef _AIX
++ #pragma alloca
++# else
++# ifndef alloca
+ char *alloca ();
++# endif
+ # endif
+ # endif
+ # endif
+@@ -57,6 +60,12 @@ char *alloca ();
+
+ #include "gettextP.h"
+
++#ifdef ENABLE_RELOCATABLE
++# include "relocatable.h"
++#else
++# define relocate(pathname) (pathname)
++#endif
++
+ /* @@ end of prolog @@ */
+
+ #ifdef _LIBC
+@@ -70,11 +79,13 @@ char *alloca ();
+ # endif
+ # define HAVE_MEMPCPY 1
+ # define HAVE___FSETLOCKING 1
++#endif
+
+-/* We need locking here since we can be called from different places. */
++/* Handle multi-threaded applications. */
++#ifdef _LIBC
+ # include <bits/libc-lock.h>
+-
+-__libc_lock_define_initialized (static, lock);
++#else
++# include "lock.h"
+ #endif
+
+ #ifndef internal_function
+@@ -99,16 +110,19 @@ __libc_lock_define_initialized (static, lock);
+ # define freea(p) free (p)
+ #endif
+
+-#if defined _LIBC_REENTRANT || defined HAVE_FGETS_UNLOCKED
++#if defined _LIBC_REENTRANT || defined HAVE_DECL_FGETS_UNLOCKED
+ # undef fgets
+ # define fgets(buf, len, s) fgets_unlocked (buf, len, s)
+ #endif
+-#if defined _LIBC_REENTRANT || defined HAVE_FEOF_UNLOCKED
++#if defined _LIBC_REENTRANT || defined HAVE_DECL_FEOF_UNLOCKED
+ # undef feof
+ # define feof(s) feof_unlocked (s)
+ #endif
+
+
++__libc_lock_define_initialized (static, lock)
++
++
+ struct alias_map
+ {
+ const char *alias;
+@@ -129,25 +143,25 @@ static size_t maxmap;
+
+
+ /* Prototypes for local functions. */
+-static size_t read_alias_file PARAMS ((const char *fname, int fname_len))
++static size_t read_alias_file (const char *fname, int fname_len)
+ internal_function;
+-static int extend_alias_table PARAMS ((void));
+-static int alias_compare PARAMS ((const struct alias_map *map1,
+- const struct alias_map *map2));
++static int extend_alias_table (void);
++static int alias_compare (const struct alias_map *map1,
++ const struct alias_map *map2);
+
+
+ const char *
+-_nl_expand_alias (name)
+- const char *name;
++_nl_expand_alias (const char *name)
+ {
+- static const char *locale_alias_path = LOCALE_ALIAS_PATH;
++ static const char *locale_alias_path;
+ struct alias_map *retval;
+ const char *result = NULL;
+ size_t added;
+
+-#ifdef _LIBC
+ __libc_lock_lock (lock);
+-#endif
++
++ if (locale_alias_path == NULL)
++ locale_alias_path = LOCALE_ALIAS_PATH;
+
+ do
+ {
+@@ -158,8 +172,8 @@ _nl_expand_alias (name)
+ if (nmap > 0)
+ retval = (struct alias_map *) bsearch (&item, map, nmap,
+ sizeof (struct alias_map),
+- (int (*) PARAMS ((const void *,
+- const void *))
++ (int (*) (const void *,
++ const void *)
+ ) alias_compare);
+ else
+ retval = NULL;
+@@ -177,11 +191,12 @@ _nl_expand_alias (name)
+ {
+ const char *start;
+
+- while (locale_alias_path[0] == ':')
++ while (locale_alias_path[0] == PATH_SEPARATOR)
+ ++locale_alias_path;
+ start = locale_alias_path;
+
+- while (locale_alias_path[0] != '\0' && locale_alias_path[0] != ':')
++ while (locale_alias_path[0] != '\0'
++ && locale_alias_path[0] != PATH_SEPARATOR)
+ ++locale_alias_path;
+
+ if (start < locale_alias_path)
+@@ -190,9 +205,7 @@ _nl_expand_alias (name)
+ }
+ while (added != 0);
+
+-#ifdef _LIBC
+ __libc_lock_unlock (lock);
+-#endif
+
+ return result;
+ }
+@@ -200,9 +213,7 @@ _nl_expand_alias (name)
+
+ static size_t
+ internal_function
+-read_alias_file (fname, fname_len)
+- const char *fname;
+- int fname_len;
++read_alias_file (const char *fname, int fname_len)
+ {
+ FILE *fp;
+ char *full_fname;
+@@ -218,9 +229,13 @@ read_alias_file (fname, fname_len)
+ memcpy (&full_fname[fname_len], aliasfile, sizeof aliasfile);
+ #endif
+
++#ifdef _LIBC
+ /* Note the file is opened with cancellation in the I/O functions
+ disabled. */
+- fp = fopen (full_fname, "rce");
++ fp = fopen (relocate (full_fname), "rce");
++#else
++ fp = fopen (relocate (full_fname), "r");
++#endif
+ freea (full_fname);
+ if (fp == NULL)
+ return 0;
+@@ -274,9 +289,6 @@ read_alias_file (fname, fname_len)
+
+ if (cp[0] != '\0')
+ {
+- size_t alias_len;
+- size_t value_len;
+-
+ value = cp++;
+ while (cp[0] != '\0' && !isspace ((unsigned char) cp[0]))
+ ++cp;
+@@ -292,48 +304,62 @@ read_alias_file (fname, fname_len)
+ else if (cp[0] != '\0')
+ *cp++ = '\0';
+
+- if (nmap >= maxmap)
+- if (__glibc_unlikely (extend_alias_table ()))
+- goto out;
++#ifdef IN_LIBGLOCALE
++ /* glibc's locale.alias contains entries for ja_JP and ko_KR
++ that make it impossible to use a Japanese or Korean UTF-8
++ locale under the name "ja_JP" or "ko_KR". Ignore these
++ entries. */
++ if (strchr (alias, '_') == NULL)
++#endif
++ {
++ size_t alias_len;
++ size_t value_len;
+
+- alias_len = strlen (alias) + 1;
+- value_len = strlen (value) + 1;
++ if (nmap >= maxmap)
++ if (__builtin_expect (extend_alias_table (), 0))
++ goto out;
+
+- if (string_space_act + alias_len + value_len > string_space_max)
+- {
+- /* Increase size of memory pool. */
+- size_t new_size = (string_space_max
+- + (alias_len + value_len > 1024
+- ? alias_len + value_len : 1024));
+- char *new_pool = (char *) realloc (string_space, new_size);
+- if (new_pool == NULL)
+- goto out;
+-
+- if (__glibc_unlikely (string_space != new_pool))
+- {
+- size_t i;
++ alias_len = strlen (alias) + 1;
++ value_len = strlen (value) + 1;
+
+- for (i = 0; i < nmap; i++)
++ if (string_space_act + alias_len + value_len > string_space_max)
++ {
++ /* Increase size of memory pool. */
++ size_t new_size = (string_space_max
++ + (alias_len + value_len > 1024
++ ? alias_len + value_len : 1024));
++ char *new_pool = (char *) realloc (string_space, new_size);
++ if (new_pool == NULL)
++ goto out;
++
++ if (__builtin_expect (string_space != new_pool, 0))
+ {
+- map[i].alias += new_pool - string_space;
+- map[i].value += new_pool - string_space;
++ size_t i;
++
++ for (i = 0; i < nmap; i++)
++ {
++ map[i].alias += new_pool - string_space;
++ map[i].value += new_pool - string_space;
++ }
+ }
+- }
+
+- string_space = new_pool;
+- string_space_max = new_size;
+- }
++ string_space = new_pool;
++ string_space_max = new_size;
++ }
+
+- map[nmap].alias = memcpy (&string_space[string_space_act],
+- alias, alias_len);
+- string_space_act += alias_len;
++ map[nmap].alias =
++ (const char *) memcpy (&string_space[string_space_act],
++ alias, alias_len);
++ string_space_act += alias_len;
+
+- map[nmap].value = memcpy (&string_space[string_space_act],
+- value, value_len);
+- string_space_act += value_len;
++ map[nmap].value =
++ (const char *) memcpy (&string_space[string_space_act],
++ value, value_len);
++ string_space_act += value_len;
+
+- ++nmap;
+- ++added;
++ ++nmap;
++ ++added;
++ }
+ }
+ }
+
+@@ -348,14 +374,14 @@ read_alias_file (fname, fname_len)
+ while (strchr (buf, '\n') == NULL);
+ }
+
+-out:
++ out:
+ /* Should we test for ferror()? I think we have to silently ignore
+ errors. --drepper */
+ fclose (fp);
+
+ if (added > 0)
+ qsort (map, nmap, sizeof (struct alias_map),
+- (int (*) PARAMS ((const void *, const void *))) alias_compare);
++ (int (*) (const void *, const void *)) alias_compare);
+
+ return added;
+ }
+@@ -381,9 +407,7 @@ extend_alias_table (void)
+
+
+ static int
+-alias_compare (map1, map2)
+- const struct alias_map *map1;
+- const struct alias_map *map2;
++alias_compare (const struct alias_map *map1, const struct alias_map *map2)
+ {
+ #if defined _LIBC || defined HAVE_STRCASECMP
+ return strcasecmp (map1->alias, map2->alias);
+diff --git a/intl/ngettext.c b/intl/ngettext.c
+index 7bf8e21..7fe7e7f 100644
+--- a/intl/ngettext.c
++++ b/intl/ngettext.c
+@@ -1,20 +1,18 @@
+ /* Implementation of ngettext(3) function.
+ Copyright (C) 1995-2014 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.
++ This program 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,
++ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+- Lesser General Public License for more details.
++ 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, see
+- <http://www.gnu.org/licenses/>. */
++ You should have received a copy of the GNU Lesser General Public License
++ along with this program. If not, see <http://www.gnu.org/licenses/>. */
+
+ #ifdef HAVE_CONFIG_H
+ # include <config.h>
+@@ -54,10 +52,7 @@
+ LC_MESSAGES locale. If not found, returns MSGID itself (the default
+ text). */
+ char *
+-NGETTEXT (msgid1, msgid2, n)
+- const char *msgid1;
+- const char *msgid2;
+- unsigned long int n;
++NGETTEXT (const char *msgid1, const char *msgid2, unsigned long int n)
+ {
+ return DCNGETTEXT (NULL, msgid1, msgid2, n, LC_MESSAGES);
+ }
+diff --git a/intl/plural-eval.c b/intl/plural-eval.c
+deleted file mode 100644
+index 6fc2460..0000000
+--- a/intl/plural-eval.c
++++ /dev/null
+@@ -1,100 +0,0 @@
+-/* Plural expression evaluation.
+- Copyright (C) 2000-2014 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, see
+- <http://www.gnu.org/licenses/>. */
+-
+-static unsigned long int plural_eval (const struct expression *pexp,
+- unsigned long int n)
+- internal_function;
+-
+-static unsigned long int
+-internal_function
+-plural_eval (pexp, n)
+- const struct expression *pexp;
+- unsigned long int n;
+-{
+- switch (pexp->nargs)
+- {
+- case 0:
+- switch (pexp->operation)
+- {
+- case var:
+- return n;
+- case num:
+- return pexp->val.num;
+- default:
+- break;
+- }
+- /* NOTREACHED */
+- break;
+- case 1:
+- {
+- /* pexp->operation must be lnot. */
+- unsigned long int arg = plural_eval (pexp->val.args[0], n);
+- return ! arg;
+- }
+- case 2:
+- {
+- unsigned long int leftarg = plural_eval (pexp->val.args[0], n);
+- if (pexp->operation == lor)
+- return leftarg || plural_eval (pexp->val.args[1], n);
+- else if (pexp->operation == land)
+- return leftarg && plural_eval (pexp->val.args[1], n);
+- else
+- {
+- unsigned long int rightarg = plural_eval (pexp->val.args[1], n);
+-
+- switch (pexp->operation)
+- {
+- case mult:
+- return leftarg * rightarg;
+- case divide:
+- return leftarg / rightarg;
+- case module:
+- return leftarg % rightarg;
+- case plus:
+- return leftarg + rightarg;
+- case minus:
+- return leftarg - rightarg;
+- case less_than:
+- return leftarg < rightarg;
+- case greater_than:
+- return leftarg > rightarg;
+- case less_or_equal:
+- return leftarg <= rightarg;
+- case greater_or_equal:
+- return leftarg >= rightarg;
+- case equal:
+- return leftarg == rightarg;
+- case not_equal:
+- return leftarg != rightarg;
+- default:
+- break;
+- }
+- }
+- /* NOTREACHED */
+- break;
+- }
+- case 3:
+- {
+- /* pexp->operation must be qmop. */
+- unsigned long int boolarg = plural_eval (pexp->val.args[0], n);
+- return plural_eval (pexp->val.args[boolarg ? 1 : 2], n);
+- }
+- }
+- /* NOTREACHED */
+- return 0;
+-}
+diff --git a/intl/plural-exp.c b/intl/plural-exp.c
+index 9a536c7..97cd93a 100644
+--- a/intl/plural-exp.c
++++ b/intl/plural-exp.c
+@@ -1,21 +1,19 @@
+ /* Expression parsing for plural form selection.
+ Copyright (C) 2000-2014 Free Software Foundation, Inc.
+ Written by Ulrich Drepper <drepper at cygnus.com>, 2000.
+- 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.
++ This program 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,
++ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+- Lesser General Public License for more details.
++ 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, see
+- <http://www.gnu.org/licenses/>. */
++ You should have received a copy of the GNU Lesser General Public License
++ along with this program. If not, see <http://www.gnu.org/licenses/>. */
+
+ #ifdef HAVE_CONFIG_H
+ # include <config.h>
+@@ -27,7 +25,8 @@
+
+ #include "plural-exp.h"
+
+-#if (defined __GNUC__ && !defined __APPLE_CC__) \
++#if (defined __GNUC__ && !(defined __APPLE_CC_ && __APPLE_CC__ > 1) && \
++ !defined __cplusplus) \
+ || (defined __STDC_VERSION__ && __STDC_VERSION__ >= 199901L)
+
+ /* These structs are the constant expression for the germanic plural
+@@ -96,10 +95,9 @@ init_germanic_plural (void)
+
+ void
+ internal_function
+-EXTRACT_PLURAL_EXPRESSION (nullentry, pluralp, npluralsp)
+- const char *nullentry;
+- const struct expression **pluralp;
+- unsigned long int *npluralsp;
++EXTRACT_PLURAL_EXPRESSION (const char *nullentry,
++ const struct expression **pluralp,
++ unsigned long int *npluralsp)
+ {
+ if (nullentry != NULL)
+ {
+diff --git a/intl/plural-exp.h b/intl/plural-exp.h
+index 9ec8901..beaa326 100644
+--- a/intl/plural-exp.h
++++ b/intl/plural-exp.h
+@@ -1,33 +1,23 @@
+ /* Expression parsing and evaluation for plural form selection.
+ Copyright (C) 2000-2014 Free Software Foundation, Inc.
+ Written by Ulrich Drepper <drepper at cygnus.com>, 2000.
+- 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.
++ This program 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,
++ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+- Lesser General Public License for more details.
++ 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, see
+- <http://www.gnu.org/licenses/>. */
++ You should have received a copy of the GNU Lesser General Public License
++ along with this program. If not, see <http://www.gnu.org/licenses/>. */
+
+ #ifndef _PLURAL_EXP_H
+ #define _PLURAL_EXP_H
+
+-#ifndef PARAMS
+-# if __STDC__ || defined __GNUC__ || defined __SUNPRO_C || defined __cplusplus || __PROTOTYPES
+-# define PARAMS(args) args
+-# else
+-# define PARAMS(args) ()
+-# endif
+-#endif
+-
+ #ifndef internal_function
+ # define internal_function
+ #endif
+@@ -36,36 +26,42 @@
+ # define attribute_hidden
+ #endif
+
++#ifdef __cplusplus
++extern "C" {
++#endif
++
++
++enum expression_operator
++{
++ /* Without arguments: */
++ var, /* The variable "n". */
++ num, /* Decimal number. */
++ /* Unary operators: */
++ lnot, /* Logical NOT. */
++ /* Binary operators: */
++ mult, /* Multiplication. */
++ divide, /* Division. */
++ module, /* Modulo operation. */
++ plus, /* Addition. */
++ minus, /* Subtraction. */
++ less_than, /* Comparison. */
++ greater_than, /* Comparison. */
++ less_or_equal, /* Comparison. */
++ greater_or_equal, /* Comparison. */
++ equal, /* Comparison for equality. */
++ not_equal, /* Comparison for inequality. */
++ land, /* Logical AND. */
++ lor, /* Logical OR. */
++ /* Ternary operators: */
++ qmop /* Question mark operator. */
++};
+
+ /* This is the representation of the expressions to determine the
+ plural form. */
+ struct expression
+ {
+ int nargs; /* Number of arguments. */
+- enum operator
+- {
+- /* Without arguments: */
+- var, /* The variable "n". */
+- num, /* Decimal number. */
+- /* Unary operators: */
+- lnot, /* Logical NOT. */
+- /* Binary operators: */
+- mult, /* Multiplication. */
+- divide, /* Division. */
+- module, /* Modulo operation. */
+- plus, /* Addition. */
+- minus, /* Subtraction. */
+- less_than, /* Comparison. */
+- greater_than, /* Comparison. */
+- less_or_equal, /* Comparison. */
+- greater_or_equal, /* Comparison. */
+- equal, /* Comparison for equality. */
+- not_equal, /* Comparison for inequality. */
+- land, /* Logical AND. */
+- lor, /* Logical OR. */
+- /* Ternary operators: */
+- qmop /* Question mark operator. */
+- } operation;
++ enum expression_operator operation;
+ union
+ {
+ unsigned long int num; /* Number value for `num'. */
+@@ -109,17 +105,23 @@ struct parse_args
+ # define EXTRACT_PLURAL_EXPRESSION extract_plural_expression
+ #endif
+
+-extern void FREE_EXPRESSION PARAMS ((struct expression *exp))
++extern void FREE_EXPRESSION (struct expression *exp)
+ internal_function;
+-extern int PLURAL_PARSE PARAMS ((void *arg));
++extern int PLURAL_PARSE (struct parse_args *arg);
+ extern const struct expression GERMANIC_PLURAL attribute_hidden;
+-extern void EXTRACT_PLURAL_EXPRESSION PARAMS
+- ((const char *nullentry, const struct expression **pluralp,
+- unsigned long int *npluralsp)) internal_function;
++extern void EXTRACT_PLURAL_EXPRESSION (const char *nullentry,
++ const struct expression **pluralp,
++ unsigned long int *npluralsp)
++ internal_function;
++
++#if !defined (_LIBC) && !defined (IN_LIBINTL) && !defined (IN_LIBGLOCALE)
++extern unsigned long int plural_eval (const struct expression *pexp,
++ unsigned long int n);
++#endif
++
+
+-#if !defined (_LIBC) && !defined (IN_LIBINTL)
+-extern unsigned long int plural_eval PARAMS ((const struct expression *pexp,
+- unsigned long int n));
++#ifdef __cplusplus
++}
+ #endif
+
+ #endif /* _PLURAL_EXP_H */
+diff --git a/intl/plural.c b/intl/plural.c
+index 1bac3c0..31b0570 100644
+--- a/intl/plural.c
++++ b/intl/plural.c
+@@ -50,7 +50,7 @@
+ #define YYSKELETON_NAME "yacc.c"
+
+ /* Pure parsers. */
+-#define YYPURE 1
++#define YYPURE 2
+
+ /* Push parsers. */
+ #define YYPUSH 0
+@@ -74,30 +74,30 @@
+
+ /* Expression parsing for plural form selection.
+ Copyright (C) 2000-2014 Free Software Foundation, Inc.
+- This file is part of the GNU C Library.
+ Written by Ulrich Drepper <drepper at cygnus.com>, 2000.
+
+- 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.
++ This program 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,
++ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+- Lesser General Public License for more details.
++ 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, see
+- <http://www.gnu.org/licenses/>. */
++ You should have received a copy of the GNU Lesser General Public License
++ along with this program. If not, see <http://www.gnu.org/licenses/>. */
+
+-/* The bison generated parser uses alloca. AIX 3 forces us to put this
+- declaration at the beginning of the file. The declaration in bison's
+- skeleton file comes too late. This must come before <config.h>
+- because <config.h> may include arbitrary system headers. */
++/* For bison < 2.0, the bison generated parser uses alloca. AIX 3 forces us
++ to put this declaration at the beginning of the file. The declaration in
++ bison's skeleton file comes too late. This must come before <config.h>
++ because <config.h> may include arbitrary system headers.
++ This can go away once the AM_INTL_SUBDIR macro requires bison >= 2.0. */
+ #if defined _AIX && !defined __GNUC__
+ #pragma alloca
+ #endif
++
+ #ifdef HAVE_CONFIG_H
+ # include <config.h>
+ #endif
+@@ -113,11 +113,9 @@
+ # define __gettextparse PLURAL_PARSE
+ #endif
+
+-#define YYLEX_PARAM &((struct parse_args *) arg)->cp
+-#define YYPARSE_PARAM arg
+
+ /* Line 371 of yacc.c */
+-#line 121 "plural.c"
++#line 119 "plural.c"
+
+ # ifndef YY_NULL
+ # if defined __cplusplus && 201103L <= __cplusplus
+@@ -173,12 +171,12 @@ typedef union YYSTYPE
+ #line 49 "plural.y"
+
+ unsigned long int num;
+- enum operator op;
++ enum expression_operator op;
+ struct expression *exp;
+
+
+ /* Line 387 of yacc.c */
+-#line 182 "plural.c"
++#line 180 "plural.c"
+ } YYSTYPE;
+ # define YYSTYPE_IS_TRIVIAL 1
+ # define yystype YYSTYPE /* obsolescent; will be withdrawn */
+@@ -194,7 +192,7 @@ int __gettextparse ();
+ #endif
+ #else /* ! YYPARSE_PARAM */
+ #if defined __STDC__ || defined __cplusplus
+-int __gettextparse (void);
++int __gettextparse (struct parse_args *arg);
+ #else
+ int __gettextparse ();
+ #endif
+@@ -207,28 +205,14 @@ int __gettextparse ();
+ #line 55 "plural.y"
+
+ /* Prototypes for local functions. */
+-static struct expression *new_exp PARAMS ((int nargs, enum operator op,
+- struct expression * const *args));
+-static inline struct expression *new_exp_0 PARAMS ((enum operator op));
+-static inline struct expression *new_exp_1 PARAMS ((enum operator op,
+- struct expression *right));
+-static struct expression *new_exp_2 PARAMS ((enum operator op,
+- struct expression *left,
+- struct expression *right));
+-static inline struct expression *new_exp_3 PARAMS ((enum operator op,
+- struct expression *bexp,
+- struct expression *tbranch,
+- struct expression *fbranch));
+-static int yylex PARAMS ((YYSTYPE *lval, const char **pexp));
+-static void yyerror PARAMS ((const char *str));
++static int yylex (YYSTYPE *lval, struct parse_args *arg);
++static void yyerror (struct parse_args *arg, const char *str);
+
+ /* Allocation of expressions. */
+
+ static struct expression *
+-new_exp (nargs, op, args)
+- int nargs;
+- enum operator op;
+- struct expression * const *args;
++new_exp (int nargs, enum expression_operator op,
++ struct expression * const *args)
+ {
+ int i;
+ struct expression *newp;
+@@ -257,16 +241,13 @@ new_exp (nargs, op, args)
+ }
+
+ static inline struct expression *
+-new_exp_0 (op)
+- enum operator op;
++new_exp_0 (enum expression_operator op)
+ {
+ return new_exp (0, op, NULL);
+ }
+
+ static inline struct expression *
+-new_exp_1 (op, right)
+- enum operator op;
+- struct expression *right;
++new_exp_1 (enum expression_operator op, struct expression *right)
+ {
+ struct expression *args[1];
+
+@@ -275,10 +256,8 @@ new_exp_1 (op, right)
+ }
+
+ static struct expression *
+-new_exp_2 (op, left, right)
+- enum operator op;
+- struct expression *left;
+- struct expression *right;
++new_exp_2 (enum expression_operator op, struct expression *left,
++ struct expression *right)
+ {
+ struct expression *args[2];
+
+@@ -288,11 +267,8 @@ new_exp_2 (op, left, right)
+ }
+
+ static inline struct expression *
+-new_exp_3 (op, bexp, tbranch, fbranch)
+- enum operator op;
+- struct expression *bexp;
+- struct expression *tbranch;
+- struct expression *fbranch;
++new_exp_3 (enum expression_operator op, struct expression *bexp,
++ struct expression *tbranch, struct expression *fbranch)
+ {
+ struct expression *args[3];
+
+@@ -304,7 +280,7 @@ new_exp_3 (op, bexp, tbranch, fbranch)
+
+
+ /* Line 390 of yacc.c */
+-#line 308 "plural.c"
++#line 284 "plural.c"
+
+ #ifdef short
+ # undef short
+@@ -596,8 +572,8 @@ static const yytype_int8 yyrhs[] =
+ /* YYRLINE[YYN] -- source line where rule number YYN was defined. */
+ static const yytype_uint8 yyrline[] =
+ {
+- 0, 174, 174, 182, 186, 190, 194, 198, 202, 206,
+- 210, 214, 218, 223
++ 0, 152, 152, 160, 164, 168, 172, 176, 180, 184,
++ 188, 192, 196, 201
+ };
+ #endif
+
+@@ -746,7 +722,7 @@ do \
+ } \
+ else \
+ { \
+- yyerror (YY_("syntax error: cannot back up")); \
++ yyerror (arg, YY_("syntax error: cannot back up")); \
+ YYERROR; \
+ } \
+ while (YYID (0))
+@@ -766,7 +742,7 @@ while (YYID (0))
+ #ifdef YYLEX_PARAM
+ # define YYLEX yylex (&yylval, YYLEX_PARAM)
+ #else
+-# define YYLEX yylex (&yylval)
++# define YYLEX yylex (&yylval, arg)
+ #endif
+
+ /* Enable debugging if requested. */
+@@ -789,7 +765,7 @@ do { \
+ { \
+ YYFPRINTF (stderr, "%s ", Title); \
+ yy_symbol_print (stderr, \
+- Type, Value); \
++ Type, Value, arg); \
+ YYFPRINTF (stderr, "\n"); \
+ } \
+ } while (YYID (0))
+@@ -803,19 +779,21 @@ do { \
+ #if (defined __STDC__ || defined __C99__FUNC__ \
+ || defined __cplusplus || defined _MSC_VER)
+ static void
+-yy_symbol_value_print (FILE *yyoutput, int yytype, YYSTYPE const * const yyvaluep)
++yy_symbol_value_print (FILE *yyoutput, int yytype, YYSTYPE const * const yyvaluep, struct parse_args *arg)
+ #else
+ static void
+-yy_symbol_value_print (yyoutput, yytype, yyvaluep)
++yy_symbol_value_print (yyoutput, yytype, yyvaluep, arg)
+ FILE *yyoutput;
+ int yytype;
+ YYSTYPE const * const yyvaluep;
++ struct parse_args *arg;
+ #endif
+ {
+ FILE *yyo = yyoutput;
+ YYUSE (yyo);
+ if (!yyvaluep)
+ return;
++ YYUSE (arg);
+ # ifdef YYPRINT
+ if (yytype < YYNTOKENS)
+ YYPRINT (yyoutput, yytoknum[yytype], *yyvaluep);
+@@ -837,13 +815,14 @@ yy_symbol_value_print (yyoutput, yytype, yyvaluep)
+ #if (defined __STDC__ || defined __C99__FUNC__ \
+ || defined __cplusplus || defined _MSC_VER)
+ static void
+-yy_symbol_print (FILE *yyoutput, int yytype, YYSTYPE const * const yyvaluep)
++yy_symbol_print (FILE *yyoutput, int yytype, YYSTYPE const * const yyvaluep, struct parse_args *arg)
+ #else
+ static void
+-yy_symbol_print (yyoutput, yytype, yyvaluep)
++yy_symbol_print (yyoutput, yytype, yyvaluep, arg)
+ FILE *yyoutput;
+ int yytype;
+ YYSTYPE const * const yyvaluep;
++ struct parse_args *arg;
+ #endif
+ {
+ if (yytype < YYNTOKENS)
+@@ -851,7 +830,7 @@ yy_symbol_print (yyoutput, yytype, yyvaluep)
+ else
+ YYFPRINTF (yyoutput, "nterm %s (", yytname[yytype]);
+
+- yy_symbol_value_print (yyoutput, yytype, yyvaluep);
++ yy_symbol_value_print (yyoutput, yytype, yyvaluep, arg);
+ YYFPRINTF (yyoutput, ")");
+ }
+
+@@ -894,12 +873,13 @@ do { \
+ #if (defined __STDC__ || defined __C99__FUNC__ \
+ || defined __cplusplus || defined _MSC_VER)
+ static void
+-yy_reduce_print (YYSTYPE *yyvsp, int yyrule)
++yy_reduce_print (YYSTYPE *yyvsp, int yyrule, struct parse_args *arg)
+ #else
+ static void
+-yy_reduce_print (yyvsp, yyrule)
++yy_reduce_print (yyvsp, yyrule, arg)
+ YYSTYPE *yyvsp;
+ int yyrule;
++ struct parse_args *arg;
+ #endif
+ {
+ int yynrhs = yyr2[yyrule];
+@@ -913,7 +893,7 @@ yy_reduce_print (yyvsp, yyrule)
+ YYFPRINTF (stderr, " $%d = ", yyi + 1);
+ yy_symbol_print (stderr, yyrhs[yyprhs[yyrule] + yyi],
+ &(yyvsp[(yyi + 1) - (yynrhs)])
+- );
++ , arg);
+ YYFPRINTF (stderr, "\n");
+ }
+ }
+@@ -921,7 +901,7 @@ yy_reduce_print (yyvsp, yyrule)
+ # define YY_REDUCE_PRINT(Rule) \
+ do { \
+ if (yydebug) \
+- yy_reduce_print (yyvsp, Rule); \
++ yy_reduce_print (yyvsp, Rule, arg); \
+ } while (YYID (0))
+
+ /* Nonzero means print parse trace. It is left uninitialized so that
+@@ -1201,16 +1181,18 @@ yysyntax_error (YYSIZE_T *yymsg_alloc, char **yymsg,
+ #if (defined __STDC__ || defined __C99__FUNC__ \
+ || defined __cplusplus || defined _MSC_VER)
+ static void
+-yydestruct (const char *yymsg, int yytype, YYSTYPE *yyvaluep)
++yydestruct (const char *yymsg, int yytype, YYSTYPE *yyvaluep, struct parse_args *arg)
+ #else
+ static void
+-yydestruct (yymsg, yytype, yyvaluep)
++yydestruct (yymsg, yytype, yyvaluep, arg)
+ const char *yymsg;
+ int yytype;
+ YYSTYPE *yyvaluep;
++ struct parse_args *arg;
+ #endif
+ {
+ YYUSE (yyvaluep);
++ YYUSE (arg);
+
+ if (!yymsg)
+ yymsg = "Deleting";
+@@ -1245,11 +1227,11 @@ yyparse (YYPARSE_PARAM)
+ #if (defined __STDC__ || defined __C99__FUNC__ \
+ || defined __cplusplus || defined _MSC_VER)
+ int
+-yyparse (void)
++yyparse (struct parse_args *arg)
+ #else
+ int
+-yyparse ()
+-
++yyparse (arg)
++ struct parse_args *arg;
+ #endif
+ #endif
+ {
+@@ -1519,17 +1501,17 @@ yyreduce:
+ {
+ case 2:
+ /* Line 1792 of yacc.c */
+-#line 175 "plural.y"
++#line 153 "plural.y"
+ {
+ if ((yyvsp[(1) - (1)].exp) == NULL)
+ YYABORT;
+- ((struct parse_args *) arg)->res = (yyvsp[(1) - (1)].exp);
++ arg->res = (yyvsp[(1) - (1)].exp);
+ }
+ break;
+
+ case 3:
+ /* Line 1792 of yacc.c */
+-#line 183 "plural.y"
++#line 161 "plural.y"
+ {
+ (yyval.exp) = new_exp_3 (qmop, (yyvsp[(1) - (5)].exp), (yyvsp[(3) - (5)].exp), (yyvsp[(5) - (5)].exp));
+ }
+@@ -1537,7 +1519,7 @@ yyreduce:
+
+ case 4:
+ /* Line 1792 of yacc.c */
+-#line 187 "plural.y"
++#line 165 "plural.y"
+ {
+ (yyval.exp) = new_exp_2 (lor, (yyvsp[(1) - (3)].exp), (yyvsp[(3) - (3)].exp));
+ }
+@@ -1545,7 +1527,7 @@ yyreduce:
+
+ case 5:
+ /* Line 1792 of yacc.c */
+-#line 191 "plural.y"
++#line 169 "plural.y"
+ {
+ (yyval.exp) = new_exp_2 (land, (yyvsp[(1) - (3)].exp), (yyvsp[(3) - (3)].exp));
+ }
+@@ -1553,7 +1535,7 @@ yyreduce:
+
+ case 6:
+ /* Line 1792 of yacc.c */
+-#line 195 "plural.y"
++#line 173 "plural.y"
+ {
+ (yyval.exp) = new_exp_2 ((yyvsp[(2) - (3)].op), (yyvsp[(1) - (3)].exp), (yyvsp[(3) - (3)].exp));
+ }
+@@ -1561,7 +1543,7 @@ yyreduce:
+
+ case 7:
+ /* Line 1792 of yacc.c */
+-#line 199 "plural.y"
++#line 177 "plural.y"
+ {
+ (yyval.exp) = new_exp_2 ((yyvsp[(2) - (3)].op), (yyvsp[(1) - (3)].exp), (yyvsp[(3) - (3)].exp));
+ }
+@@ -1569,7 +1551,7 @@ yyreduce:
+
+ case 8:
+ /* Line 1792 of yacc.c */
+-#line 203 "plural.y"
++#line 181 "plural.y"
+ {
+ (yyval.exp) = new_exp_2 ((yyvsp[(2) - (3)].op), (yyvsp[(1) - (3)].exp), (yyvsp[(3) - (3)].exp));
+ }
+@@ -1577,7 +1559,7 @@ yyreduce:
+
+ case 9:
+ /* Line 1792 of yacc.c */
+-#line 207 "plural.y"
++#line 185 "plural.y"
+ {
+ (yyval.exp) = new_exp_2 ((yyvsp[(2) - (3)].op), (yyvsp[(1) - (3)].exp), (yyvsp[(3) - (3)].exp));
+ }
+@@ -1585,7 +1567,7 @@ yyreduce:
+
+ case 10:
+ /* Line 1792 of yacc.c */
+-#line 211 "plural.y"
++#line 189 "plural.y"
+ {
+ (yyval.exp) = new_exp_1 (lnot, (yyvsp[(2) - (2)].exp));
+ }
+@@ -1593,7 +1575,7 @@ yyreduce:
+
+ case 11:
+ /* Line 1792 of yacc.c */
+-#line 215 "plural.y"
++#line 193 "plural.y"
+ {
+ (yyval.exp) = new_exp_0 (var);
+ }
+@@ -1601,7 +1583,7 @@ yyreduce:
+
+ case 12:
+ /* Line 1792 of yacc.c */
+-#line 219 "plural.y"
++#line 197 "plural.y"
+ {
+ if (((yyval.exp) = new_exp_0 (num)) != NULL)
+ (yyval.exp)->val.num = (yyvsp[(1) - (1)].num);
+@@ -1610,7 +1592,7 @@ yyreduce:
+
+ case 13:
+ /* Line 1792 of yacc.c */
+-#line 224 "plural.y"
++#line 202 "plural.y"
+ {
+ (yyval.exp) = (yyvsp[(2) - (3)].exp);
+ }
+@@ -1618,7 +1600,7 @@ yyreduce:
+
+
+ /* Line 1792 of yacc.c */
+-#line 1622 "plural.c"
++#line 1604 "plural.c"
+ default: break;
+ }
+ /* User semantic actions sometimes alter yychar, and that requires
+@@ -1668,7 +1650,7 @@ yyerrlab:
+ {
+ ++yynerrs;
+ #if ! YYERROR_VERBOSE
+- yyerror (YY_("syntax error"));
++ yyerror (arg, YY_("syntax error"));
+ #else
+ # define YYSYNTAX_ERROR yysyntax_error (&yymsg_alloc, &yymsg, \
+ yyssp, yytoken)
+@@ -1695,7 +1677,7 @@ yyerrlab:
+ yymsgp = yymsg;
+ }
+ }
+- yyerror (yymsgp);
++ yyerror (arg, yymsgp);
+ if (yysyntax_error_status == 2)
+ goto yyexhaustedlab;
+ }
+@@ -1719,7 +1701,7 @@ yyerrlab:
+ else
+ {
+ yydestruct ("Error: discarding",
+- yytoken, &yylval);
++ yytoken, &yylval, arg);
+ yychar = YYEMPTY;
+ }
+ }
+@@ -1775,7 +1757,7 @@ yyerrlab1:
+
+
+ yydestruct ("Error: popping",
+- yystos[yystate], yyvsp);
++ yystos[yystate], yyvsp, arg);
+ YYPOPSTACK (1);
+ yystate = *yyssp;
+ YY_STACK_PRINT (yyss, yyssp);
+@@ -1812,7 +1794,7 @@ yyabortlab:
+ | yyexhaustedlab -- memory exhaustion comes here. |
+ `-------------------------------------------------*/
+ yyexhaustedlab:
+- yyerror (YY_("memory exhausted"));
++ yyerror (arg, YY_("memory exhausted"));
+ yyresult = 2;
+ /* Fall through. */
+ #endif
+@@ -1824,7 +1806,7 @@ yyreturn:
+ user semantic actions for why this is necessary. */
+ yytoken = YYTRANSLATE (yychar);
+ yydestruct ("Cleanup: discarding lookahead",
+- yytoken, &yylval);
++ yytoken, &yylval, arg);
+ }
+ /* Do not reclaim the symbols of the rule which action triggered
+ this YYABORT or YYACCEPT. */
+@@ -1833,7 +1815,7 @@ yyreturn:
+ while (yyssp != yyss)
+ {
+ yydestruct ("Cleanup: popping",
+- yystos[*yyssp], yyvsp);
++ yystos[*yyssp], yyvsp, arg);
+ YYPOPSTACK (1);
+ }
+ #ifndef yyoverflow
+@@ -1850,13 +1832,12 @@ yyreturn:
+
+
+ /* Line 2055 of yacc.c */
+-#line 229 "plural.y"
++#line 207 "plural.y"
+
+
+ void
+ internal_function
+-FREE_EXPRESSION (exp)
+- struct expression *exp;
++FREE_EXPRESSION (struct expression *exp)
+ {
+ if (exp == NULL)
+ return;
+@@ -1882,18 +1863,16 @@ FREE_EXPRESSION (exp)
+
+
+ static int
+-yylex (lval, pexp)
+- YYSTYPE *lval;
+- const char **pexp;
++yylex (YYSTYPE *lval, struct parse_args *arg)
+ {
+- const char *exp = *pexp;
++ const char *exp = arg->cp;
+ int result;
+
+ while (1)
+ {
+ if (exp[0] == '\0')
+ {
+- *pexp = exp;
++ arg->cp = exp;
+ return YYEOF;
+ }
+
+@@ -2020,15 +1999,14 @@ yylex (lval, pexp)
+ break;
+ }
+
+- *pexp = exp;
++ arg->cp = exp;
+
+ return result;
+ }
+
+
+ static void
+-yyerror (str)
+- const char *str;
++yyerror (struct parse_args *arg, const char *str)
+ {
+ /* Do nothing. We don't print error messages here. */
+ }
+diff --git a/intl/plural.y b/intl/plural.y
+index 105fe0d..d74de07 100644
+--- a/intl/plural.y
++++ b/intl/plural.y
+@@ -1,30 +1,30 @@
+ %{
+ /* Expression parsing for plural form selection.
+ Copyright (C) 2000-2014 Free Software Foundation, Inc.
+- This file is part of the GNU C Library.
+ Written by Ulrich Drepper <drepper at cygnus.com>, 2000.
+
+- 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.
++ This program 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,
++ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+- Lesser General Public License for more details.
++ 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, see
+- <http://www.gnu.org/licenses/>. */
++ You should have received a copy of the GNU Lesser General Public License
++ along with this program. If not, see <http://www.gnu.org/licenses/>. */
+
+-/* The bison generated parser uses alloca. AIX 3 forces us to put this
+- declaration at the beginning of the file. The declaration in bison's
+- skeleton file comes too late. This must come before <config.h>
+- because <config.h> may include arbitrary system headers. */
++/* For bison < 2.0, the bison generated parser uses alloca. AIX 3 forces us
++ to put this declaration at the beginning of the file. The declaration in
++ bison's skeleton file comes too late. This must come before <config.h>
++ because <config.h> may include arbitrary system headers.
++ This can go away once the AM_INTL_SUBDIR macro requires bison >= 2.0. */
+ #if defined _AIX && !defined __GNUC__
+ #pragma alloca
+ #endif
++
+ #ifdef HAVE_CONFIG_H
+ # include <config.h>
+ #endif
+@@ -40,42 +40,28 @@
+ # define __gettextparse PLURAL_PARSE
+ #endif
+
+-#define YYLEX_PARAM &((struct parse_args *) arg)->cp
+-#define YYPARSE_PARAM arg
+ %}
+-%pure_parser
++%parse-param {struct parse_args *arg}
++%lex-param {struct parse_args *arg}
++%define api.pure full
+ %expect 7
+
+ %union {
+ unsigned long int num;
+- enum operator op;
++ enum expression_operator op;
+ struct expression *exp;
+ }
+
+ %{
+ /* Prototypes for local functions. */
+-static struct expression *new_exp PARAMS ((int nargs, enum operator op,
+- struct expression * const *args));
+-static inline struct expression *new_exp_0 PARAMS ((enum operator op));
+-static inline struct expression *new_exp_1 PARAMS ((enum operator op,
+- struct expression *right));
+-static struct expression *new_exp_2 PARAMS ((enum operator op,
+- struct expression *left,
+- struct expression *right));
+-static inline struct expression *new_exp_3 PARAMS ((enum operator op,
+- struct expression *bexp,
+- struct expression *tbranch,
+- struct expression *fbranch));
+-static int yylex PARAMS ((YYSTYPE *lval, const char **pexp));
+-static void yyerror PARAMS ((const char *str));
++static int yylex (YYSTYPE *lval, struct parse_args *arg);
++static void yyerror (struct parse_args *arg, const char *str);
+
+ /* Allocation of expressions. */
+
+ static struct expression *
+-new_exp (nargs, op, args)
+- int nargs;
+- enum operator op;
+- struct expression * const *args;
++new_exp (int nargs, enum expression_operator op,
++ struct expression * const *args)
+ {
+ int i;
+ struct expression *newp;
+@@ -104,16 +90,13 @@ new_exp (nargs, op, args)
+ }
+
+ static inline struct expression *
+-new_exp_0 (op)
+- enum operator op;
++new_exp_0 (enum expression_operator op)
+ {
+ return new_exp (0, op, NULL);
+ }
+
+ static inline struct expression *
+-new_exp_1 (op, right)
+- enum operator op;
+- struct expression *right;
++new_exp_1 (enum expression_operator op, struct expression *right)
+ {
+ struct expression *args[1];
+
+@@ -122,10 +105,8 @@ new_exp_1 (op, right)
+ }
+
+ static struct expression *
+-new_exp_2 (op, left, right)
+- enum operator op;
+- struct expression *left;
+- struct expression *right;
++new_exp_2 (enum expression_operator op, struct expression *left,
++ struct expression *right)
+ {
+ struct expression *args[2];
+
+@@ -135,11 +116,8 @@ new_exp_2 (op, left, right)
+ }
+
+ static inline struct expression *
+-new_exp_3 (op, bexp, tbranch, fbranch)
+- enum operator op;
+- struct expression *bexp;
+- struct expression *tbranch;
+- struct expression *fbranch;
++new_exp_3 (enum expression_operator op, struct expression *bexp,
++ struct expression *tbranch, struct expression *fbranch)
+ {
+ struct expression *args[3];
+
+@@ -175,7 +153,7 @@ start: exp
+ {
+ if ($1 == NULL)
+ YYABORT;
+- ((struct parse_args *) arg)->res = $1;
++ arg->res = $1;
+ }
+ ;
+
+@@ -230,8 +208,7 @@ exp: exp '?' exp ':' exp
+
+ void
+ internal_function
+-FREE_EXPRESSION (exp)
+- struct expression *exp;
++FREE_EXPRESSION (struct expression *exp)
+ {
+ if (exp == NULL)
+ return;
+@@ -257,18 +234,16 @@ FREE_EXPRESSION (exp)
+
+
+ static int
+-yylex (lval, pexp)
+- YYSTYPE *lval;
+- const char **pexp;
++yylex (YYSTYPE *lval, struct parse_args *arg)
+ {
+- const char *exp = *pexp;
++ const char *exp = arg->cp;
+ int result;
+
+ while (1)
+ {
+ if (exp[0] == '\0')
+ {
+- *pexp = exp;
++ arg->cp = exp;
+ return YYEOF;
+ }
+
+@@ -395,15 +370,14 @@ yylex (lval, pexp)
+ break;
+ }
+
+- *pexp = exp;
++ arg->cp = exp;
+
+ return result;
+ }
+
+
+ static void
+-yyerror (str)
+- const char *str;
++yyerror (struct parse_args *arg, const char *str)
+ {
+ /* Do nothing. We don't print error messages here. */
+ }
+diff --git a/intl/textdomain.c b/intl/textdomain.c
+index 3b5a6c1..d1ab52a 100644
+--- a/intl/textdomain.c
++++ b/intl/textdomain.c
+@@ -1,20 +1,18 @@
+ /* Implementation of the textdomain(3) function.
+ Copyright (C) 1995-2014 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.
++ This program 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,
++ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+- Lesser General Public License for more details.
++ 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, see
+- <http://www.gnu.org/licenses/>. */
++ You should have received a copy of the GNU Lesser General Public License
++ along with this program. If not, see <http://www.gnu.org/licenses/>. */
+
+ #ifdef HAVE_CONFIG_H
+ # include <config.h>
+@@ -23,39 +21,25 @@
+ #include <stdlib.h>
+ #include <string.h>
+
++#include "gettextP.h"
+ #ifdef _LIBC
+ # include <libintl.h>
+ #else
+ # include "libgnuintl.h"
+ #endif
+-#include "gettextP.h"
+
++/* Handle multi-threaded applications. */
+ #ifdef _LIBC
+-/* We have to handle multi-threaded applications. */
+ # include <bits/libc-lock.h>
++# define gl_rwlock_define __libc_rwlock_define
++# define gl_rwlock_wrlock __libc_rwlock_wrlock
++# define gl_rwlock_unlock __libc_rwlock_unlock
+ #else
+-/* Provide dummy implementation if this is outside glibc. */
+-# define __libc_rwlock_define(CLASS, NAME)
+-# define __libc_rwlock_wrlock(NAME)
+-# define __libc_rwlock_unlock(NAME)
+-#endif
+-
+-/* The internal variables in the standalone libintl.a must have different
+- names than the internal variables in GNU libc, otherwise programs
+- using libintl.a cannot be linked statically. */
+-#if !defined _LIBC
+-# define _nl_default_default_domain libintl_nl_default_default_domain
+-# define _nl_current_default_domain libintl_nl_current_default_domain
++# include "lock.h"
+ #endif
+
+ /* @@ end of prolog @@ */
+
+-/* Name of the default text domain. */
+-extern const char _nl_default_default_domain[] attribute_hidden;
+-
+-/* Default text domain in which entries for gettext(3) are to be found. */
+-extern const char *_nl_current_default_domain attribute_hidden;
+-
+
+ /* Names for the libintl functions are a problem. They must not clash
+ with existing names and they should follow ANSI C. But this source
+@@ -71,14 +55,13 @@ extern const char *_nl_current_default_domain attribute_hidden;
+ #endif
+
+ /* Lock variable to protect the global data in the gettext implementation. */
+-__libc_rwlock_define (extern, _nl_state_lock attribute_hidden)
++gl_rwlock_define (extern, _nl_state_lock attribute_hidden)
+
+ /* Set the current default message catalog to DOMAINNAME.
+ If DOMAINNAME is null, return the current default.
+ If DOMAINNAME is "", reset to the default of "messages". */
+ char *
+-TEXTDOMAIN (domainname)
+- const char *domainname;
++TEXTDOMAIN (const char *domainname)
+ {
+ char *new_domain;
+ char *old_domain;
+@@ -87,7 +70,7 @@ TEXTDOMAIN (domainname)
+ if (domainname == NULL)
+ return (char *) _nl_current_default_domain;
+
+- __libc_rwlock_wrlock (_nl_state_lock);
++ gl_rwlock_wrlock (_nl_state_lock);
+
+ old_domain = (char *) _nl_current_default_domain;
+
+@@ -131,7 +114,7 @@ TEXTDOMAIN (domainname)
+ free (old_domain);
+ }
+
+- __libc_rwlock_unlock (_nl_state_lock);
++ gl_rwlock_unlock (_nl_state_lock);
+
+ return new_domain;
+ }
+--
+1.9.2
+
diff --git a/recipes-core/glibc/glibc/ld-search-order.patch b/recipes-core/glibc/glibc/ld-search-order.patch
new file mode 100644
index 0000000..f518bc7
--- /dev/null
+++ b/recipes-core/glibc/glibc/ld-search-order.patch
@@ -0,0 +1,56 @@
+Upstream-Status: Inappropriate [embedded specific]
+
+The default lib search path order is:
+
+ 1) LD_LIBRARY_PATH
+ 2) RPATH from the binary
+ 3) ld.so.cache
+ 4) default search paths embedded in the linker
+
+For nativesdk binaries which are being used alongside binaries on a host system, we
+need the search paths to firstly search the shipped nativesdk libs but then also
+cover the host system. For example we want the host system's libGL and this may be
+in a non-standard location like /usr/lib/mesa. The only place the location is know
+about is in the ld.so.cache of the host system.
+
+Since nativesdk has a simple structure and doesn't need to use a cache itself, we
+repurpose the cache for use as a last resort in finding host system binaries. This
+means we need to switch the order of 3 and 4 above to make this work effectively.
+
+RP 14/10/2010
+
+Index: git/elf/dl-load.c
+===================================================================
+--- git.orig/elf/dl-load.c 2014-08-28 17:32:46.292070587 -0700
++++ git/elf/dl-load.c 2014-08-28 17:33:56.048070587 -0700
+@@ -2050,7 +2050,14 @@
+ fd = open_path (name, namelen, mode,
+ &loader->l_runpath_dirs, &realname, &fb, loader,
+ LA_SER_RUNPATH, &found_other_class);
+-
++ /* try the default path. */
++ if (fd == -1
++ && ((l = loader ?: GL(dl_ns)[nsid]._ns_loaded) == NULL
++ || __builtin_expect (!(l->l_flags_1 & DF_1_NODEFLIB), 1))
++ && rtld_search_dirs.dirs != (void *) -1)
++ fd = open_path (name, namelen, mode & __RTLD_SECURE, &rtld_search_dirs,
++ &realname, &fb, l, LA_SER_DEFAULT, &found_other_class);
++ /* Finally try ld.so.cache */
+ #ifdef USE_LDCONFIG
+ if (fd == -1
+ && (__glibc_likely ((mode & __RTLD_SECURE) == 0)
+@@ -2113,14 +2120,6 @@
+ }
+ #endif
+
+- /* Finally, try the default path. */
+- if (fd == -1
+- && ((l = loader ?: GL(dl_ns)[nsid]._ns_loaded) == NULL
+- || __glibc_likely (!(l->l_flags_1 & DF_1_NODEFLIB)))
+- && rtld_search_dirs.dirs != (void *) -1)
+- fd = open_path (name, namelen, mode, &rtld_search_dirs,
+- &realname, &fb, l, LA_SER_DEFAULT, &found_other_class);
+-
+ /* Add another newline when we are tracing the library loading. */
+ if (__glibc_unlikely (GLRO_dl_debug_mask & DL_DEBUG_LIBS))
+ _dl_debug_printf ("\n");
diff --git a/recipes-core/glibc/glibc/mips-rld-map-check.patch b/recipes-core/glibc/glibc/mips-rld-map-check.patch
new file mode 100644
index 0000000..9f593d6
--- /dev/null
+++ b/recipes-core/glibc/glibc/mips-rld-map-check.patch
@@ -0,0 +1,27 @@
+
+On mips target, binutils currently sets DT_MIPS_RLD_MAP to 0 in dynamic
+section if a --version-script sets _RLD_MAP to local. This is apparently
+a binutils bug, but libc shouldn't segfault in this case.
+
+see also: http://sourceware.org/bugilla/show_bug.cgi?id=11615
+
+Upstream-Status: Pending
+
+9/19/2010 - added by Qing He <qing.he at intel.com>
+
+
+---
+Index: git/sysdeps/mips/dl-machine.h
+===================================================================
+--- git.orig/sysdeps/mips/dl-machine.h 2014-08-27 04:58:11.840070587 +0000
++++ git/sysdeps/mips/dl-machine.h 2014-08-27 04:58:11.832070587 +0000
+@@ -70,7 +70,8 @@
+ /* If there is a DT_MIPS_RLD_MAP entry in the dynamic section, fill it in
+ with the run-time address of the r_debug structure */
+ #define ELF_MACHINE_DEBUG_SETUP(l,r) \
+-do { if ((l)->l_info[DT_MIPS (RLD_MAP)]) \
++do { if ((l)->l_info[DT_MIPS (RLD_MAP)] && \
++ (l)->l_info[DT_MIPS (RLD_MAP)]->d_un.d_ptr) \
+ *(ElfW(Addr) *)((l)->l_info[DT_MIPS (RLD_MAP)]->d_un.d_ptr) = \
+ (ElfW(Addr)) (r); \
+ } while (0)
diff --git a/recipes-core/glibc/glibc/multilib_readlib.patch b/recipes-core/glibc/glibc/multilib_readlib.patch
new file mode 100644
index 0000000..13ffc46
--- /dev/null
+++ b/recipes-core/glibc/glibc/multilib_readlib.patch
@@ -0,0 +1,19 @@
+Upstream-Status: Inappropriate [embedded specific]
+
+Replace the OECORE_KNOWN_INTERPRETER_NAMES with the value of
+variable EGLIBC_KNOWN_INTERPRETER_NAMES.
+
+Lianhao Lu, 08/01/2011
+
+Index: git/elf/readlib.c
+===================================================================
+--- git.orig/elf/readlib.c 2014-08-29 10:34:16.824070587 -0700
++++ git/elf/readlib.c 2014-08-29 10:34:16.816070587 -0700
+@@ -51,6 +51,7 @@
+ #ifdef SYSDEP_KNOWN_INTERPRETER_NAMES
+ SYSDEP_KNOWN_INTERPRETER_NAMES
+ #endif
++ OECORE_KNOWN_INTERPRETER_NAMES
+ };
+
+ static struct known_names known_libs[] =
diff --git a/recipes-core/glibc/glibc/option-groups.patch b/recipes-core/glibc/glibc/option-groups.patch
new file mode 100644
index 0000000..198be73
--- /dev/null
+++ b/recipes-core/glibc/glibc/option-groups.patch
@@ -0,0 +1,1397 @@
+Eglibc option group infrastructure
+
+Upstream-Status: Pending
+
+Index: git/option-groups.def
+===================================================================
+--- /dev/null 1970-01-01 00:00:00.000000000 +0000
++++ git/option-groups.def 2014-08-27 07:26:51.652070587 +0000
+@@ -0,0 +1,868 @@
++# This file documents the option groups EGLIBC currently supports, in
++# a format akin to the Linux Kconfig system's. The syntax may change
++# over time.
++#
++# An entry of the form:
++#
++# config GROUP_NAME
++# bool "one-line explanation of what this option group controls"
++# help
++# Multi-line help explaining the option group's meaning in
++# some detail, terminated by indentation level.
++#
++# defines an option group whose variable is GROUP_NAME, with
++# meaningful values 'y' (enabled) and 'n' (disabled). The
++# documentation is formatted to be consumed by some sort of
++# interactive configuration interface, but EGLIBC doesn't have such an
++# interface yet.
++#
++# An option may have a 'depends on' line, indicating which other options
++# must also be enabled if this option is. At present, EGLIBC doesn't
++# check that these dependencies are satisfied.
++#
++# Option group variables get their default values from the file
++# 'option-groups.defaults', in the top directory of the EGLIBC source
++# tree. By default, all EGLIBC option groups are enabled --- their
++# variables are set to 'y'.
++#
++# After including 'option-groups.defaults', the EGLIBC make machinery
++# includes the file 'option-groups.config' from the top of the build
++# tree, if it is present. Developers can place assignments to option
++# group variables in that file to override the defaults. For example,
++# to disable an option group, place a line of the form:
++#
++# OPTION_GROUP_NAME = n
++#
++# in 'option-groups.config' at the top of your build tree. To
++# explicitly enable an option group, you may also write:
++#
++# OPTION_GROUP_NAME = y
++#
++# although this simply reestablishes the value already set by
++# 'option-groups.defaults'.
++
++config EGLIBC_ADVANCED_INET6
++ bool "IPv6 Advanced Sockets API support (RFC3542)"
++ depends on EGLIBC_INET
++ help
++ This option group includes the functions specified by RFC 3542,
++ "Advanced Sockets Application Program Interface (API) for
++ IPv6".
++
++ This option group includes the following functions:
++
++ inet6_opt_append
++ inet6_opt_find
++ inet6_opt_finish
++ inet6_opt_get_val
++ inet6_opt_init
++ inet6_option_alloc
++ inet6_option_append
++ inet6_option_find
++ inet6_option_init
++ inet6_option_next
++ inet6_option_space
++ inet6_opt_next
++ inet6_opt_set_val
++ inet6_rth_add
++ inet6_rth_getaddr
++ inet6_rth_init
++ inet6_rth_reverse
++ inet6_rth_segments
++ inet6_rth_space
++
++config EGLIBC_BACKTRACE
++ bool "Functions for producing backtraces"
++ help
++ This option group includes functions for producing a list of
++ the function calls that are currently active in a thread, from
++ within the thread itself. These functions are often used
++ within signal handlers, to produce diagnostic output.
++
++ This option group includes the following functions:
++
++ backtrace
++ backtrace_symbols
++ backtrace_symbols_fd
++
++config EGLIBC_BIG_MACROS
++ bool "Use extensive inline code"
++ help
++ This option group specifies whether certain pieces of code
++ should be inlined to achieve maximum speed. If this option
++ group is not selected, function calls will be used instead,
++ hence reducing the library footprint.
++
++config EGLIBC_BSD
++ bool "BSD-specific functions, and their compatibility stubs"
++ help
++ This option group includes functions specific to BSD kernels.
++ A number of these functions have stub versions that are also
++ included in libraries built for non-BSD systems for
++ compatibility.
++
++ This option group includes the following functions:
++
++ chflags
++ fchflags
++ lchmod
++ revoke
++ setlogin
++
++config EGLIBC_CXX_TESTS
++ bool "Tests that link against the standard C++ library."
++ depends on POSIX_WIDE_CHAR_DEVICE_IO && EGLIBC_LIBM
++ help
++ This option group does not include any C library functions;
++ instead, it controls which EGLIBC tests an ordinary 'make
++ tests' runs. With this group disabled, tests that would
++ normally link against the standard C++ library are not
++ run.
++
++ The standard C++ library depends on the math library 'libm' and
++ the wide character I/O functions included in EGLIBC. So those
++ option groups must be enabled if this test is enabled.
++
++config EGLIBC_CATGETS
++ bool "Functions for accessing message catalogs"
++ depends on EGLIBC_LOCALE_CODE
++ help
++ This option group includes functions for accessing message
++ catalogs: catopen, catclose, and catgets.
++
++ This option group depends on the EGLIBC_LOCALE_CODE
++ option group.
++
++config EGLIBC_CHARSETS
++ bool "iconv/gconv character set conversion libraries"
++ help
++ This option group includes support for character sets other
++ than ASCII (ANSI_X3.4-1968) and Unicode and ISO-10646 in their
++ various encodings. This affects both the character sets
++ supported by the wide and multibyte character functions, and
++ those supported by the 'iconv' functions.
++
++ With this option group disabled, EGLIBC supports only the
++ following character sets:
++
++ ANSI_X3.4 - ASCII
++ ANSI_X3.4-1968
++ ANSI_X3.4-1986
++ ASCII
++ CP367
++ CSASCII
++ IBM367
++ ISO-IR-6
++ ISO646-US
++ ISO_646.IRV:1991
++ OSF00010020
++ US
++ US-ASCII
++
++ 10646-1:1993 - ISO 10646, in big-endian UCS4 form
++ 10646-1:1993/UCS4
++ CSUCS4
++ ISO-10646
++ ISO-10646/UCS4
++ OSF00010104
++ OSF00010105
++ OSF00010106
++ UCS-4
++ UCS-4BE
++ UCS4
++
++ UCS-4LE - ISO 10646, in little-endian UCS4 form
++
++ ISO-10646/UTF-8 - ISO 10646, in UTF-8 form
++ ISO-10646/UTF8
++ ISO-IR-193
++ OSF05010001
++ UTF-8
++ UTF8
++
++ ISO-10646/UCS2 - ISO 10646, in target-endian UCS2 form
++ OSF00010100
++ OSF00010101
++ OSF00010102
++ UCS-2
++ UCS2
++
++ UCS-2BE - ISO 10646, in big-endian UCS2 form
++ UNICODEBIG
++
++ UCS-2LE - ISO 10646, in little-endian UCS2 form
++ UNICODELITTLE
++
++ WCHAR_T - EGLIBC's internal form (target-endian,
++ 32-bit ISO 10646)
++
++config EGLIBC_CRYPT
++ bool "Encryption library"
++ help
++ This option group includes the `libcrypt' library which
++ provides functions for one-way encryption. Supported
++ encryption algorithms include MD5, SHA-256, SHA-512 and DES.
++
++config EGLIBC_CRYPT_UFC
++ bool "Ultra fast `crypt' implementation"
++ depends on EGLIBC_CRYPT
++ help
++ This option group provides ultra fast DES-based implementation of
++ the `crypt' function. When this option group is disabled,
++ (a) the library will not provide the setkey[_r] and encrypt[_r]
++ functions and (b) the crypt[_r] function will return NULL and set the
++ errno to ENOSYS if /salt/ passed does not correspond to either MD5,
++ SHA-256 or SHA-512 algorithm.
++
++config EGLIBC_DB_ALIASES
++ bool "Functions for accessing the mail aliases database"
++ help
++ This option group includues functions for looking up mail
++ aliases in '/etc/aliases' or using nsswitch. It includes the
++ following functions:
++
++ endaliasent
++ getaliasbyname
++ getaliasbyname_r
++ getaliasent
++ getaliasent_r
++ setaliasent
++
++ When this option group is disabled, the NSS service libraries
++ also lack support for querying their mail alias tables.
++
++config EGLIBC_ENVZ
++ bool "Functions for handling envz-style environment vectors."
++ help
++ This option group contains functions for creating and operating
++ on envz vectors. An "envz vector" is a vector of strings in a
++ contiguous block of memory, where each element is a name-value
++ pair, and elements are separated from their neighbors by null
++ characters.
++
++ This option group includes the following functions:
++
++ envz_add envz_merge
++ envz_entry envz_remove
++ envz_get envz_strip
++
++config EGLIBC_FCVT
++ bool "Functions for converting floating-point numbers to strings"
++ help
++ This option group includes functions for converting
++ floating-point numbers to strings.
++
++ This option group includes the following functions:
++
++ ecvt qecvt
++ ecvt_r qecvt_r
++ fcvt qfcvt
++ fcvt_r qfcvt_r
++ gcvt qgcvt
++
++config EGLIBC_FMTMSG
++ bool "Functions for formatting messages"
++ help
++ This option group includes the following functions:
++
++ addseverity fmtmsg
++
++config EGLIBC_FSTAB
++ bool "Access functions for 'fstab'"
++ help
++ This option group includes functions for reading the mount
++ point specification table, '/etc/fstab'. These functions are
++ not included in the POSIX standard, which provides the
++ 'getmntent' family of functions instead.
++
++ This option group includes the following functions:
++
++ endfsent getfsspec
++ getfsent setfsent
++ getfsfile
++
++config EGLIBC_FTRAVERSE
++ bool "Functions for traversing file hierarchies"
++ help
++ This option group includes functions for traversing file
++ UNIX file hierachies.
++
++ This option group includes the following functions:
++
++ fts_open ftw
++ fts_read nftw
++ fts_children ftw64
++ fts_set nftw64
++ fts_close
++
++config EGLIBC_GETLOGIN
++ bool "The getlogin function"
++ depends on EGLIBC_UTMP
++ help
++ This function group includes the 'getlogin' and 'getlogin_r'
++ functions, which return the user name associated by the login
++ activity with the current process's controlling terminal.
++
++ With this option group disabled, the 'glob' function will not
++ fall back on 'getlogin' to find the user's login name for tilde
++ expansion when the 'HOME' environment variable is not set.
++
++config EGLIBC_IDN
++ bool "International domain names support"
++ help
++ This option group includes the `libcidn' library which
++ provides support for international domain names.
++
++config EGLIBC_INET
++ bool "Networking support"
++ help
++ This option group includes networking-specific functions and
++ data. With EGLIBC_INET disabled, the EGLIBC
++ installation and API changes as follows:
++
++ - The following libraries are not installed:
++
++ libnsl
++ libnss_compat
++ libnss_dns
++ libnss_hesiod
++ libnss_nis
++ libnss_nisplus
++ libresolv
++
++ - The following functions and variables are omitted from libc:
++
++ authdes_create hstrerror svc_fdset
++ authdes_getucred htonl svc_getreq
++ authdes_pk_create htons svc_getreq_common
++ authnone_create if_freenameindex svc_getreq_poll
++ authunix_create if_indextoname svc_getreqset
++ authunix_create_default if_nameindex svc_max_pollfd
++ bindresvport if_nametoindex svc_pollfd
++ callrpc in6addr_any svcraw_create
++ cbc_crypt in6addr_loopback svc_register
++ clnt_broadcast inet6_opt_append svc_run
++ clnt_create inet6_opt_find svc_sendreply
++ clnt_pcreateerror inet6_opt_finish svctcp_create
++ clnt_perrno inet6_opt_get_val svcudp_bufcreate
++ clnt_perror inet6_opt_init svcudp_create
++ clntraw_create inet6_option_alloc svcudp_enablecache
++ clnt_spcreateerror inet6_option_append svcunix_create
++ clnt_sperrno inet6_option_find svcunixfd_create
++ clnt_sperror inet6_option_init svc_unregister
++ clnttcp_create inet6_option_next user2netname
++ clntudp_bufcreate inet6_option_space xdecrypt
++ clntudp_create inet6_opt_next xdr_accepted_reply
++ clntunix_create inet6_opt_set_val xdr_array
++ des_setparity inet6_rth_add xdr_authdes_cred
++ ecb_crypt inet6_rth_getaddr xdr_authdes_verf
++ endaliasent inet6_rth_init xdr_authunix_parms
++ endhostent inet6_rth_reverse xdr_bool
++ endnetent inet6_rth_segments xdr_bytes
++ endnetgrent inet6_rth_space xdr_callhdr
++ endprotoent inet_addr xdr_callmsg
++ endrpcent inet_aton xdr_char
++ endservent inet_lnaof xdr_cryptkeyarg
++ ether_aton inet_makeaddr xdr_cryptkeyarg2
++ ether_aton_r inet_netof xdr_cryptkeyres
++ ether_hostton inet_network xdr_des_block
++ ether_line inet_nsap_addr xdr_double
++ ether_ntoa inet_nsap_ntoa xdr_enum
++ ether_ntoa_r inet_ntoa xdr_float
++ ether_ntohost inet_ntop xdr_free
++ freeaddrinfo inet_pton xdr_getcredres
++ freeifaddrs innetgr xdr_hyper
++ gai_strerror iruserok xdr_int
++ getaddrinfo iruserok_af xdr_int16_t
++ getaliasbyname key_decryptsession xdr_int32_t
++ getaliasbyname_r key_decryptsession_pk xdr_int64_t
++ getaliasent key_encryptsession xdr_int8_t
++ getaliasent_r key_encryptsession_pk xdr_keybuf
++ gethostbyaddr key_gendes xdr_key_netstarg
++ gethostbyaddr_r key_get_conv xdr_key_netstres
++ gethostbyname key_secretkey_is_set xdr_keystatus
++ gethostbyname2 key_setnet xdr_long
++ gethostbyname2_r key_setsecret xdr_longlong_t
++ gethostbyname_r netname2host xdrmem_create
++ gethostent netname2user xdr_netnamestr
++ gethostent_r ntohl xdr_netobj
++ getifaddrs ntohs xdr_opaque
++ getipv4sourcefilter passwd2des xdr_opaque_auth
++ get_myaddress pmap_getmaps xdr_pmap
++ getnameinfo pmap_getport xdr_pmaplist
++ getnetbyaddr pmap_rmtcall xdr_pointer
++ getnetbyaddr_r pmap_set xdr_quad_t
++ getnetbyname pmap_unset xdrrec_create
++ getnetbyname_r rcmd xdrrec_endofrecord
++ getnetent rcmd_af xdrrec_eof
++ getnetent_r registerrpc xdrrec_skiprecord
++ getnetgrent res_init xdr_reference
++ getnetgrent_r rexec xdr_rejected_reply
++ getnetname rexec_af xdr_replymsg
++ getprotobyname rexecoptions xdr_rmtcall_args
++ getprotobyname_r rpc_createerr xdr_rmtcallres
++ getprotobynumber rresvport xdr_short
++ getprotobynumber_r rresvport_af xdr_sizeof
++ getprotoent rtime xdrstdio_create
++ getprotoent_r ruserok xdr_string
++ getpublickey ruserok_af xdr_u_char
++ getrpcbyname ruserpass xdr_u_hyper
++ getrpcbyname_r setaliasent xdr_u_int
++ getrpcbynumber sethostent xdr_uint16_t
++ getrpcbynumber_r setipv4sourcefilter xdr_uint32_t
++ getrpcent setnetent xdr_uint64_t
++ getrpcent_r setnetgrent xdr_uint8_t
++ getrpcport setprotoent xdr_u_long
++ getsecretkey setrpcent xdr_u_longlong_t
++ getservbyname setservent xdr_union
++ getservbyname_r setsourcefilter xdr_unixcred
++ getservbyport svcauthdes_stats xdr_u_quad_t
++ getservbyport_r svcerr_auth xdr_u_short
++ getservent svcerr_decode xdr_vector
++ getservent_r svcerr_noproc xdr_void
++ getsourcefilter svcerr_noprog xdr_wrapstring
++ h_errlist svcerr_progvers xencrypt
++ h_errno svcerr_systemerr xprt_register
++ herror svcerr_weakauth xprt_unregister
++ h_nerr svc_exit
++ host2netname svcfd_create
++
++ - The rpcgen, nscd, and rpcinfo commands are not installed.
++
++ - The 'rpc' file (a text file listing RPC services) is not installed.
++
++ Socket-related system calls do not fall in this option group,
++ because many are also used for other inter-process
++ communication mechanisms. For example, the 'syslog' routines
++ use Unix-domain sockets to communicate with the syslog daemon;
++ syslog is valuable in non-networked contexts.
++
++config EGLIBC_INET_ANL
++ bool "Asynchronous name lookup"
++ depends on EGLIBC_INET
++ help
++ This option group includes the `libanl' library which
++ provides support for asynchronous name lookup.
++
++config EGLIBC_LIBM
++ bool "libm (math library)"
++ help
++ This option group includes the 'libm' library, containing
++ mathematical functions. If this option group is omitted, then
++ an EGLIBC installation does not include shared or unshared versions
++ of the math library.
++
++ Note that this does not remove all floating-point related
++ functionality from EGLIBC; for example, 'printf' and 'scanf'
++ can still print and read floating-point values with this option
++ group disabled.
++
++ Note that the ISO Standard C++ library 'libstdc++' depends on
++ EGLIBC's math library 'libm'. If you disable this option
++ group, you will not be able to build 'libstdc++' against the
++ resulting EGLIBC installation.
++
++config EGLIBC_LOCALES
++ bool "Locale definitions"
++ help
++ This option group includes all locale definitions other than
++ that for the "C" locale. If this option group is omitted, then
++ only the "C" locale is supported.
++
++
++config EGLIBC_LOCALE_CODE
++ bool "Locale functions"
++ depends on POSIX_C_LANG_WIDE_CHAR
++ help
++ This option group includes locale support functions, programs,
++ and libraries. With EGLIBC_LOCALE_CODE disabled,
++ EGLIBC supports only the 'C' locale (also known as 'POSIX'),
++ and ignores the settings of the 'LANG' and 'LC_*' environment
++ variables.
++
++ With EGLIBC_LOCALE_CODE disabled, the following
++ functions are omitted from libc:
++
++ duplocale localeconv nl_langinfo rpmatch strfmon_l
++ freelocale newlocale nl_langinfo_l strfmon uselocale
++
++ Furthermore, only the LC_CTYPE and LC_TIME categories of the
++ standard "C" locale are available.
++
++ The EGLIBC_CATGETS option group depends on this option group.
++
++
++config EGLIBC_MEMUSAGE
++ bool "Memory profiling library"
++ help
++ This option group includes the `libmemusage' library and
++ the `memusage' and `memusagestat' utilities.
++ These components provide memory profiling functions.
++
++config EGLIBC_MEMUSAGE_DEFAULT_BUFFER_SIZE
++ int "Memory profiling library buffer size"
++ depends on EGLIBC_MEMUSAGE
++ default "32768"
++ help
++ Libmemusage library buffers the profiling data in memory
++ before writing it out to disk. By default, the library
++ allocates 1.5M buffer, which can be substantial for some
++ systems. EGLIBC_MEMUSAGE_DEFAULT_BUFFER_SIZE option
++ allows to change the default buffer size. It specifies
++ the number of entries the buffer should have.
++ On most architectures one buffer entry amounts to 48 bytes,
++ so setting this option to the value of 512 will reduce the size of
++ the memory buffer to 24K.
++
++config EGLIBC_NIS
++ bool "Support for NIS, NIS+, and the special 'compat' services."
++ depends on EGLIBC_INET && EGLIBC_SUNRPC
++ help
++ This option group includes the NIS, NIS+, and 'compat' Name
++ Service Switch service libraries. When it is disabled, those
++ services libraries are not installed; you should remove any
++ references to them from your 'nsswitch.conf' file.
++
++ This option group depends on the EGLIBC_INET option
++ group; you must enable that to enable this option group.
++
++config EGLIBC_NSSWITCH
++ bool "Name service switch (nsswitch) support"
++ help
++ This option group includes support for the 'nsswitch' facility.
++ With this option group enabled, all EGLIBC functions for
++ accessing various system databases (passwords and groups;
++ networking; aliases; public keys; and so on) consult the
++ '/etc/nsswitch.conf' configuration file to decide how to handle
++ queries.
++
++ With this option group disabled, EGLIBC uses a fixed list of
++ services to satisfy queries on each database, as requested by
++ configuration files specified when EGLIBC is built. Your
++ 'option-groups.config' file must set the following two
++ variables:
++
++config EGLIBC_NSSWITCH_FIXED_CONFIG
++ string "Nsswitch fixed config filename"
++ depends on !EGLIBC_NSSWITCH
++ default ""
++ help
++ Set this to the name of a file whose contents observe the
++ same syntax as an ordinary '/etc/nsswitch.conf' file. The
++ EGLIBC build process parses this file just as EGLIBC would
++ at run time if EGLIBC_NSSWITCH were enabled, and
++ produces a C library that uses the nsswitch service
++ libraries to search for database entries as this file
++ specifies, instead of consulting '/etc/nsswitch.conf' at run
++ time.
++
++ This should be an absolute filename. The EGLIBC build
++ process may use it from several different working
++ directories. It may include references to Makefile
++ variables like 'common-objpfx' (the top of the build tree,
++ with a trailing slash), or '..' (the top of the source tree,
++ with a trailing slash).
++
++ The EGLIBC source tree includes a sample configuration file
++ named 'nss/fixed-nsswitch.conf'; for simple configurations,
++ you will probably want to delete references to databases not
++ needed on your system.
++
++config EGLIBC_NSSWITCH_FIXED_FUNCTIONS
++ string "Nsswitch fixed functions filename"
++ depends on !EGLIBC_NSSWITCH
++ default ""
++ help
++ The EGLIBC build process uses this file to decide which
++ functions to make available from which service libraries.
++ The file 'nss/fixed-nsswitch.functions' serves as a sample
++ configuration file for this setting, and explains its syntax
++ and meaning in more detail.
++
++ This should be an absolute file name. The EGLIBC build
++ process may use it from several different working
++ directories. It may include references to Makefile
++ variables like 'common-objpfx' (the top of the build tree,
++ with a trailing slash), or '..' (the top of the source tree,
++ with a trailing slash).
++
++ Be sure to mention each function in each service you wish to
++ use. If you do not mention a service's function here, the
++ EGLIBC database access functions will not find it, even if
++ it is listed in the EGLIBC_NSSWITCH_FIXED_CONFIG
++ file.
++
++ In this arrangement, EGLIBC will not use the 'dlopen' and
++ 'dlsym' functions to find database access functions. Instead,
++ libc hard-codes references to the service libraries' database
++ access functions. You must explicitly link your program
++ against the name service libraries (those whose names start
++ with 'libnss_', in the sysroot's '/lib' directory) whose
++ functions you intend to use. This arrangement helps
++ system-wide static analysis tools decide which functions a
++ system actually uses.
++
++ Note that some nsswitch service libraries require other option
++ groups to be enabled; for example, the EGLIBC_INET
++ option group must be enabled to use the 'libnss_dns.so.2'
++ service library, which uses the Domain Name System network
++ protocol to answer queries.
++
++config EGLIBC_RCMD
++ bool "Support for 'rcmd' and related library functions"
++ depends on EGLIBC_INET
++ help
++ This option group includes functions for running commands on
++ remote machines via the 'rsh' protocol, and doing authentication
++ related to those functions. This also includes functions that
++ use the 'rexec' protocol.
++
++ This option group includes the following functions:
++
++ rcmd ruserok
++ rcmd_af ruserok_af
++ rexec iruserok
++ rexec_af iruserok_af
++ rresvport ruserpass
++ rresvport_af
++
++config EGLIBC_RTLD_DEBUG
++ bool "Runtime linker debug print outs"
++ help
++ This option group enables debug output of the runtime linker
++ which is activated via LD_DEBUG and LD_TRACE_PRELINKING
++ environment variables. Disabling this option group yields
++ a smaller runtime linker binary.
++ BEWARE: Disabling this option group is likely to break
++ the `ldd' utility which may also be used by the prelinker.
++ In particular, the `--unused' ldd option will not work correctly.
++
++config EGLIBC_SPAWN
++ bool "Support for POSIX posix_spawn functions"
++ help
++ This option group includes the POSIX functions for executing
++ programs in child processes without using 'fork' or 'vfork'.
++
++ This option group includes the following functions:
++
++ posix_spawn
++ posix_spawnattr_destroy
++ posix_spawnattr_getflags
++ posix_spawnattr_getpgroup
++ posix_spawnattr_getschedparam
++ posix_spawnattr_getschedpolicy
++ posix_spawnattr_getsigdefault
++ posix_spawnattr_getsigmask
++ posix_spawnattr_init
++ posix_spawnattr_setflags
++ posix_spawnattr_setpgroup
++ posix_spawnattr_setschedparam
++ posix_spawnattr_setschedpolicy
++ posix_spawnattr_setsigdefault
++ posix_spawnattr_setsigmask
++ posix_spawn_file_actions_addclose
++ posix_spawn_file_actions_adddup2
++ posix_spawn_file_actions_addopen
++ posix_spawn_file_actions_destroy
++ posix_spawn_file_actions_init
++ posix_spawnp
++
++ This option group also provides the ability for the iconv,
++ localedef, and locale programs to operate transparently on
++ compressed charset definitions. When this option group is
++ disabled, those programs will only operate on uncompressed
++ charmap files.
++
++config EGLIBC_STREAMS
++ bool "Support for accessing STREAMS."
++ help
++ This option group includes functions for reading and writing
++ messages to and from STREAMS. The STREAMS interface provides a
++ uniform mechanism for implementing networking services and other
++ character-based I/O. (STREAMS are not to be confused with
++ <stdio.h> FILE objects, also called 'streams'.)
++
++ This option group includes the following functions:
++
++ getmsg putpmsg
++ getpmsg fattach
++ isastream fdetach
++ putmsg
++
++config EGLIBC_SUNRPC
++ bool "Support for the Sun 'RPC' protocol."
++ depends on EGLIBC_INET
++ help
++ This option group includes support for the Sun RPC protocols,
++ including the 'rpcgen' and 'rpcinfo' programs.
++
++config EGLIBC_UTMP
++ bool "Older access functions for 'utmp' login records"
++ help
++ This option group includes the older 'utent' family of
++ functions for accessing user login records in the 'utmp' file.
++ POSIX omits these functions in favor of the 'utxent' family,
++ and they are obsolete on systems other than Linux.
++
++ This option group includes the following functions:
++
++ endutent
++ getutent
++ getutent_r
++ getutid
++ getutid_r
++ getutline
++ getutline_r
++ logwtmp
++ pututline
++ setutent
++ updwtmp
++ utmpname
++
++ This option group includes the following libraries:
++
++ libutil.so (and libutil.a)
++
++config EGLIBC_UTMPX
++ bool "POSIX access functions for 'utmp' login records"
++ depends on EGLIBC_UTMP
++ help
++ This option group includes the POSIX functions for reading and
++ writing user login records in the 'utmp' file (usually
++ '/var/run/utmp'). The POSIX functions operate on 'struct
++ utmpx' structures, as opposed to the family of older 'utent'
++ functions, which operate on 'struct utmp' structures.
++
++ This option group includes the following functions:
++
++ endutxent
++ getutmp
++ getutmpx
++ getutxent
++ getutxid
++ getutxline
++ pututxline
++ setutxent
++ updwtmpx
++ utmpxname
++
++config EGLIBC_WORDEXP
++ bool "Shell-style word expansion"
++ help
++ This option group includes the 'wordexp' function for
++ performing word expansion in the manner of the shell, and the
++ accompanying 'wordfree' function.
++
++config POSIX_C_LANG_WIDE_CHAR
++ bool "ISO C library wide character functions, excluding I/O"
++ help
++ This option group includes the functions defined by the ISO C
++ standard for working with wide and multibyte characters in
++ memory. Functions for reading and writing wide and multibyte
++ characters from and to files call in the
++ POSIX_WIDE_CHAR_DEVICE_IO option group.
++
++ This option group includes the following functions:
++
++ btowc mbsinit wcscspn wcstoll
++ iswalnum mbsrtowcs wcsftime wcstombs
++ iswalpha mbstowcs wcslen wcstoul
++ iswblank mbtowc wcsncat wcstoull
++ iswcntrl swprintf wcsncmp wcstoumax
++ iswctype swscanf wcsncpy wcsxfrm
++ iswdigit towctrans wcspbrk wctob
++ iswgraph towlower wcsrchr wctomb
++ iswlower towupper wcsrtombs wctrans
++ iswprint vswprintf wcsspn wctype
++ iswpunct vswscanf wcsstr wmemchr
++ iswspace wcrtomb wcstod wmemcmp
++ iswupper wcscat wcstof wmemcpy
++ iswxdigit wcschr wcstoimax wmemmove
++ mblen wcscmp wcstok wmemset
++ mbrlen wcscoll wcstol
++ mbrtowc wcscpy wcstold
++
++config POSIX_REGEXP
++ bool "Regular expressions"
++ help
++ This option group includes the POSIX regular expression
++ functions, and the associated non-POSIX extensions and
++ compatibility functions.
++
++ With POSIX_REGEXP disabled, the following functions are
++ omitted from libc:
++
++ re_comp re_max_failures regcomp
++ re_compile_fastmap re_search regerror
++ re_compile_pattern re_search_2 regexec
++ re_exec re_set_registers regfree
++ re_match re_set_syntax rpmatch
++ re_match_2 re_syntax_options
++
++ Furthermore, the compatibility regexp interface defined in the
++ <regexp.h> header file, 'compile', 'step', and 'advance', is
++ omitted.
++
++config POSIX_REGEXP_GLIBC
++ bool "Regular expressions from GLIBC"
++ depends on POSIX_REGEXP
++ help
++ This option group specifies which regular expression
++ library to use. The choice is between regex
++ implementation from GLIBC and regex implementation from
++ libiberty. The GLIBC variant is fully POSIX conformant and
++ optimized for speed; regex from libiberty is more than twice
++ as small while still is enough for most practical purposes.
++
++config POSIX_WIDE_CHAR_DEVICE_IO
++ bool "Input and output functions for wide characters"
++ depends on POSIX_C_LANG_WIDE_CHAR
++ help
++ This option group includes functions for reading and writing
++ wide characters to and from <stdio.h> streams.
++
++ This option group includes the following functions:
++
++ fgetwc fwprintf putwchar vwscanf
++ fgetws fwscanf ungetwc wprintf
++ fputwc getwc vfwprintf wscanf
++ fputws getwchar vfwscanf
++ fwide putwc vwprintf
++
++ This option group further includes the following unlocked
++ variants of the above functions:
++
++ fgetwc_unlocked getwc_unlocked
++ fgetws_unlocked getwchar_unlocked
++ fputwc_unlocked putwc_unlocked
++ fputws_unlocked putwchar_unlocked
++
++ Note that the GNU standard C++ library, 'libstdc++.so', uses
++ some of these functions; you will not be able to link or run
++ C++ programs if you disable this option group.
++
++ This option group also affects the behavior of the following
++ functions:
++
++ fdopen
++ fopen
++ fopen64
++ freopen
++ freopen64
++
++ These functions all take an OPENTYPE parameter which may
++ contain a string of the form ",ccs=CHARSET", indicating that
++ the underlying file uses the character set named CHARSET.
++ This produces a wide-oriented stream, which is only useful
++ when the functions included in this option group are present.
++ If the user attempts to open a file specifying a character set
++ in the OPENTYPE parameter, and EGLIBC was built with this
++ option group disabled, the function returns NULL, and sets
++ errno to EINVAL.
++
++
++# This helps Emacs users browse this file using the page motion commands
++# and commands like 'pages-directory'.
++# Local Variables:
++# page-delimiter: "^config\\s-"
++# End:
+Index: git/option-groups.mak
+===================================================================
+--- /dev/null 1970-01-01 00:00:00.000000000 +0000
++++ git/option-groups.mak 2014-08-27 07:26:51.652070587 +0000
+@@ -0,0 +1,41 @@
++# Setup file for subdirectory Makefiles that define EGLIBC option groups.
++
++# EGLIBC shouldn't need to override this. However, the
++# cross-build-friendly localedef includes this makefile to get option
++# group variable definitions; it uses a single build tree for all the
++# multilibs, and needs to be able to specify a different option group
++# configuration file for each multilib.
++option_group_config_file ?= $(objdir)/option-groups.config
++
++# Read the default settings for all options.
++# We're included before ../Rules, so we can't assume $(..) is set.
++include $(firstword $(..) ../)option-groups.defaults
++
++# Read the developer's option group selections, overriding the
++# defaults from option-groups.defaults.
++-include $(option_group_config_file)
++
++# $(call option-disabled, VAR) is 'y' if VAR is not 'y', or 'n' otherwise.
++# VAR should be a variable name, not a variable reference; this is
++# less general, but more terse for the intended use.
++# You can use it to add a file to a list if an option group is
++# disabled, like this:
++# routines-$(call option-disabled, OPTION_POSIX_C_LANG_WIDE_CHAR) += ...
++define option-disabled
++$(firstword $(subst y,n,$(filter y,$($(strip $(1))))) y)
++endef
++
++# Establish 'routines-y', etc. as simply-expanded variables.
++aux-y :=
++extra-libs-others-y :=
++extra-libs-y :=
++extra-objs-y :=
++install-bin-y :=
++install-others-y :=
++install-sbin-y :=
++others-y :=
++others-pie-y :=
++routines-y :=
++test-srcs-y :=
++tests-y :=
++xtests-y :=
+Index: git/option-groups.defaults
+===================================================================
+--- /dev/null 1970-01-01 00:00:00.000000000 +0000
++++ git/option-groups.defaults 2014-08-27 07:24:41.652070587 +0000
+@@ -0,0 +1,47 @@
++# This file sets default values for all option group variables
++# mentioned in option-groups.def; see that file for a description of
++# each option group.
++#
++# Subdirectory makefiles include this file before including the user's
++# settings from option-groups.config at the top of the build tree;
++# that file need only refer to those options whose default settings
++# are to be changed.
++#
++# By default, all option groups are enabled.
++OPTION_EGLIBC_ADVANCED_INET6 = y
++OPTION_EGLIBC_BACKTRACE = y
++OPTION_EGLIBC_BIG_MACROS = y
++OPTION_EGLIBC_BSD = y
++OPTION_EGLIBC_CXX_TESTS = y
++OPTION_EGLIBC_CATGETS = y
++OPTION_EGLIBC_CHARSETS = y
++OPTION_EGLIBC_CRYPT = y
++OPTION_EGLIBC_CRYPT_UFC = y
++OPTION_EGLIBC_DB_ALIASES = y
++OPTION_EGLIBC_ENVZ = y
++OPTION_EGLIBC_FCVT = y
++OPTION_EGLIBC_FMTMSG = y
++OPTION_EGLIBC_FSTAB = y
++OPTION_EGLIBC_FTRAVERSE = y
++OPTION_EGLIBC_GETLOGIN = y
++OPTION_EGLIBC_IDN = y
++OPTION_EGLIBC_INET = y
++OPTION_EGLIBC_INET_ANL = y
++OPTION_EGLIBC_LIBM = y
++OPTION_EGLIBC_LOCALES = y
++OPTION_EGLIBC_LOCALE_CODE = y
++OPTION_EGLIBC_MEMUSAGE = y
++OPTION_EGLIBC_NIS = y
++OPTION_EGLIBC_NSSWITCH = y
++OPTION_EGLIBC_RCMD = y
++OPTION_EGLIBC_RTLD_DEBUG = y
++OPTION_EGLIBC_SPAWN = y
++OPTION_EGLIBC_STREAMS = y
++OPTION_EGLIBC_SUNRPC = y
++OPTION_EGLIBC_UTMP = y
++OPTION_EGLIBC_UTMPX = y
++OPTION_EGLIBC_WORDEXP = y
++OPTION_POSIX_C_LANG_WIDE_CHAR = y
++OPTION_POSIX_REGEXP = y
++OPTION_POSIX_REGEXP_GLIBC = y
++OPTION_POSIX_WIDE_CHAR_DEVICE_IO = y
+Index: git/Makefile
+===================================================================
+--- git.orig/Makefile 2014-08-27 07:24:37.540070587 +0000
++++ git/Makefile 2014-08-27 07:24:41.656070587 +0000
+@@ -24,6 +24,7 @@
+
+ include Makeconfig
+
++include options-config/Makefile
+
+ # This is the default target; it makes everything except the tests.
+ .PHONY: all
+Index: git/EGLIBC.option-groups
+===================================================================
+--- /dev/null 1970-01-01 00:00:00.000000000 +0000
++++ git/EGLIBC.option-groups 2014-08-27 07:24:41.656070587 +0000
+@@ -0,0 +1,122 @@
++ -*- mode: text -*-
++
++ The EGLIBC Component Configuration System
++ Jim Blandy <jimb at codesourcery.com>
++
++Introduction
++
++The GNU C library (GLIBC) provides a broad range of functionality,
++ranging from internationalization support to transcendental
++mathematical functions. Its website boasts that "nearly all known and
++useful functions from any other C library are available." This
++exhaustive approach has been one of GLIBC's strengths on desktop and
++server systems, but it has also given GLIBC a large footprint, both in
++memory and on disk, making it a challenge to use in embedded systems
++with limited resources.
++
++The Embedded GNU C library (EGLIBC) is a variant of the GNU C library
++designed to work well on embedded systems. In particular, EGLIBC's
++component configuration system allows embedded developers to build
++customized versions of the library that include only the features
++their application uses, reducing its space requirements.
++
++EGLIBC's component configuration system categorizes the library's
++functions into "option groups", and allows you to include or exclude
++option groups individually. Some option groups depend on others;
++EGLIBC tracks these relationships, and ensures that the selected
++configuration yields a functioning library.
++
++
++Consistent and Predictable Behavior
++
++A flexible configuration system is a mixed blessing: if the options
++offered are poorly designed, it can be hard to see which choices will
++have the desired effects, and choices with obscure consequences can
++make debugging difficult. EGLIBC's configuration follows some general
++principles to reduce these risks:
++
++- EGLIBC has a single default configuration for each target
++ architecture.
++
++- In the default configuration, all option groups are enabled, and
++ EGLIBC is upwardly API- and ABI-compatible with GLIBC.
++
++- As much as possible, configurations only affect what functions are
++ present, not how they behave. If the system works with an option
++ group disabled, it will still work with it enabled.
++
++- As much as possible, configurations only select option groups ---
++ they do not describe characteristics of the target architecture.
++
++These rules mean that you have a simple debugging strategy available
++if you suspect that your EGLIBC configuration might be the source of a
++problem: fall back to the default configuration, re-test, and then
++disable option groups one by one, until the problem reappears.
++
++
++The Option Groups
++
++To see the current full list of implemented option groups, refer to the
++file 'option-groups.def' at the top of the source tree, or run
++'make menuconfig' from the top-level build directory.
++
++The POSIX.1-2001 specification includes a suggested partition of all
++the functions in the POSIX C API into option groups: math functions
++like 'sin' and 'cos'; networking functions like 'socket' and
++'connect'; and so on. EGLIBC could use this partitioning as the basis
++for future option groups.
++
++
++Implementation
++
++The EGLIBC component configuration system resembles the approach used
++by the Linux kernel to select device drivers, network protocols, and
++other features. A file named 'option-groups.config' in the top-level
++build directory contains assignments to Make variables, each of which
++enables or disables a particular option group. If the variable's
++value is set to 'y', then the option group is enabled; if it set to
++anything else, the option group is omitted. The file
++'option-groups.defaults', at the top of the source tree, establishes
++default values for all variables; all option groups are enabled by
++default.
++
++For example, the following 'option-groups.config' would omit locale
++data, but include mathematical functions, and everything else:
++
++ OPTION_EGLIBC_LOCALES = n
++ OPTION_EGLIBC_LIBM = y
++
++Like the Linux kernel, EGLIBC supports a similar set of '*config' make
++targets to make it easier to create 'option-groups.config', with all
++dependencies between option groups automatically satisfied. Run
++'make help' to see the list of supported make config targets. For
++example, 'make menuconfig' will update the current config utilising a
++menu based program.
++
++The option group names and their type (boolean, int, hex, string), help
++description, and dependencies with other option groups, are described by
++'option-groups.def' at the top of the source tree, analogous to the
++'Kconfig' files in the Linux kernel.
++
++In general, each option group variable controls whether a given set of
++object files in EGLIBC is compiled and included in the final
++libraries, or omitted from the build.
++
++Each subdirectory's Makefile categorizes its routines, libraries, and
++executables by option group. For example, EGLIBC's 'math/Makefile'
++places the 'libm' library in the OPTION_EGLIBC_LIBM group as follows:
++
++ extra-libs-$(OPTION_EGLIBC_LIBM) := libm
++
++Finally, common code in 'Makerules' cites the value of the variable
++'extra-libs-y', selecting only those libraries that belong to enabled
++option groups to be built.
++
++
++Current Status and Future Directions
++
++The EGLIBC component configuration system described here is still
++under development.
++
++We have used the system to subset some portions of EGLIBC's
++Index: libc/configure.ac
+Index: git/configure.ac
+===================================================================
+--- git.orig/configure.ac 2014-08-27 07:24:41.196070587 +0000
++++ git/configure.ac 2014-08-27 07:24:41.656070587 +0000
+@@ -127,6 +127,16 @@
+ [sysheaders=''])
+ AC_SUBST(sysheaders)
+
++AC_ARG_WITH([kconfig],
++ AC_HELP_STRING([--with-kconfig=PATH],
++ [location of kconfig tools to use (from Linux
++ kernel builds) to re-use for configuring EGLIBC
++ option groups]),
++ [KCONFIG_TOOLS=$withval],
++ [KCONFIG_TOOLS=''])
++AC_SUBST(KCONFIG_TOOLS)
++
++
+ AC_SUBST(use_default_link)
+ AC_ARG_WITH([default-link],
+ AC_HELP_STRING([--with-default-link],
+Index: git/config.make.in
+===================================================================
+--- git.orig/config.make.in 2014-08-27 07:24:37.560070587 +0000
++++ git/config.make.in 2014-08-27 07:24:41.656070587 +0000
+@@ -46,6 +46,8 @@
+ c++-sysincludes = @CXX_SYSINCLUDES@
+ all-warnings = @all_warnings@
+
++kconfig_tools = @KCONFIG_TOOLS@
++
+ have-z-combreloc = @libc_cv_z_combreloc@
+ have-z-execstack = @libc_cv_z_execstack@
+ have-Bgroup = @libc_cv_Bgroup@
+Index: git/configure
+===================================================================
+--- git.orig/configure 2014-08-27 07:24:41.192070587 +0000
++++ git/configure 2014-08-27 07:24:41.660070587 +0000
+@@ -619,6 +619,7 @@
+ PERL
+ BASH_SHELL
+ libc_cv_gcc_static_libgcc
++KCONFIG_TOOLS
+ CXX_SYSINCLUDES
+ SYSINCLUDES
+ AUTOCONF
+@@ -733,6 +734,7 @@
+ with_binutils
+ with_selinux
+ with_headers
++with_kconfig
+ with_default_link
+ enable_sanity_checks
+ enable_shared
+@@ -1437,6 +1439,9 @@
+ --with-selinux if building with SELinux support
+ --with-headers=PATH location of system headers to use (for example
+ /usr/src/linux/include) [default=compiler default]
++ --with-kconfig=PATH location of kconfig tools to use (from Linux kernel
++ builds) to re-use for configuring EGLIBC option
++ groups
+ --with-default-link do not use explicit linker scripts
+ --with-cpu=CPU select code for CPU variant
+
+@@ -3400,6 +3405,14 @@
+
+
+
++# Check whether --with-kconfig was given.
++if test "${with_kconfig+set}" = set; then
++ withval=$with_kconfig; KCONFIG_TOOLS=$withval
++else
++ KCONFIG_TOOLS=''
++fi
++
++
+
+ # Check whether --with-default-link was given.
+ if test "${with_default_link+set}" = set; then :
+Index: git/options-config/Makefile
+===================================================================
+--- /dev/null 1970-01-01 00:00:00.000000000 +0000
++++ git/options-config/Makefile 2014-08-27 07:24:41.652070587 +0000
+@@ -0,0 +1,55 @@
++# ===========================================================================
++# EGLIBC option-groups configuration targets
++# These targets are included from top-level makefile
++
++ifneq ($(kconfig_tools),)
++ifneq (no,$(PERL))
++
++ocdir := options-config
++
++OconfigDefaults := option-groups.defaults
++OconfigDefaults_tmp := $(common-objpfx).tmp.defconfig
++OconfigDef := option-groups.def
++Oconfig := $(common-objpfx)option-groups.config
++Oconfig_tmp := $(common-objpfx).tmp.config
++
++conf := $(kconfig_tools)/conf
++mconf := $(kconfig_tools)/mconf
++
++preproc := $(PERL) $(ocdir)/config-preproc.pl
++postproc := $(PERL) $(ocdir)/config-postproc.pl
++
++PHONY += defconfig config menuconfig
++
++defconfig: $(conf) $(OconfigDefaults) $(OconfigDef)
++ rm -f $(OconfigDefaults_tmp)
++ rm -f $(Oconfig_tmp)
++ $(preproc) $(OconfigDefaults) > $(OconfigDefaults_tmp)
++ KCONFIG_CONFIG=$(Oconfig_tmp) $< --defconfig=$(OconfigDefaults_tmp) \
++ $(OconfigDef)
++ $(postproc) $(OconfigDefaults) $(Oconfig_tmp) > $(Oconfig)
++ rm $(Oconfig_tmp)
++ rm $(OconfigDefaults_tmp)
++
++config: $(conf) $(OconfigDefaults) $(OconfigDef)
++ rm -f $(Oconfig_tmp)
++ $(preproc) $(wildcard $(Oconfig)) > $(Oconfig_tmp)
++ KCONFIG_CONFIG=$(Oconfig_tmp) $< --oldaskconfig $(OconfigDef)
++ $(postproc) $(OconfigDefaults) $(Oconfig_tmp) > $(Oconfig)
++ rm $(Oconfig_tmp)
++
++menuconfig: $(mconf) $(OconfigDefaults) $(OconfigDef)
++ rm -f $(Oconfig_tmp)
++ $(preproc) $(wildcard $(Oconfig)) > $(Oconfig_tmp)
++ KCONFIG_CONFIG=$(Oconfig_tmp) $< $(OconfigDef)
++ $(postproc) $(OconfigDefaults) $(Oconfig_tmp) > $(Oconfig)
++ rm $(Oconfig_tmp)
++
++# Help text used by make help
++help:
++ @echo ' defconfig - New config with default from default config'
++ @echo ' config - Update current config utilising a line-oriented program'
++ @echo ' menuconfig - Update current config utilising a menu based program'
++
++endif
++endif
+Index: git/options-config/config-postproc.pl
+===================================================================
+--- /dev/null 1970-01-01 00:00:00.000000000 +0000
++++ git/options-config/config-postproc.pl 2014-08-27 07:24:41.652070587 +0000
+@@ -0,0 +1,58 @@
++#!/usr/bin/perl
++
++$usage = "usage: $0 <default config file> <config file>\n";
++
++die "$usage" unless @ARGV;
++$defaults = shift @ARGV;
++die "$usage" unless @ARGV;
++die "Could not open $ARGV[0]" unless -T $ARGV[0];
++
++sub yank {
++ @option = grep(!($_ =~ /$_[0]\s*=/), @option);
++}
++
++open(DEFAULTS, $defaults) || die "Could not open $defaults\n";
++
++# get the full list of available options using the default config file
++$i = 0;
++while (<DEFAULTS>) {
++ if (/^\s*OPTION_(\w+\s*=.*$)/) {
++ $option[$i++] = $1;
++ }
++}
++
++# now go through the config file, making the necessary changes
++while (<>) {
++ if (/Linux Kernel Configuration/) {
++ # change title
++ s/Linux Kernel/Option Groups/;
++ print;
++ } elsif (/^\s*CONFIG_(\w+)\s*=/) {
++ # this is an explicit option set line, change CONFIG_ to OPTION_
++ # before printing and remove this option from option list
++ $opt = $1;
++ yank($opt);
++ s/CONFIG_/OPTION_/g;
++ print;
++ } elsif (/^\s*#\s+CONFIG_(\w+) is not set/) {
++ # this is a comment line for an unset boolean option, change CONFIG_
++ # to OPTION_, remove this option from option list, and convert to
++ # explicit OPTION_FOO=n
++ $opt = $1;
++ yank($opt);
++ s/CONFIG_/OPTION_/g;
++ print "OPTION_$opt=n\n";
++ } else {
++ print;
++ }
++}
++
++# any boolean options left in @options, are options that were not mentioned in
++# the config file, and implicitly that means the option must be set =n,
++# so do that here.
++foreach $opt (@option) {
++ if ($opt =~ /=\s*[yn]/) {
++ $opt =~ s/=\s*[yn]/=n/;
++ print "OPTION_$opt\n";
++ }
++}
+Index: git/options-config/config-preproc.pl
+===================================================================
+--- /dev/null 1970-01-01 00:00:00.000000000 +0000
++++ git/options-config/config-preproc.pl 2014-08-27 07:24:41.652070587 +0000
+@@ -0,0 +1,8 @@
++#!/usr/bin/perl
++
++if (@ARGV) {
++ while (<>) {
++ s/OPTION_/CONFIG_/g;
++ print;
++ }
++}
+Index: git/scripts/option-groups.awk
+===================================================================
+--- /dev/null 1970-01-01 00:00:00.000000000 +0000
++++ git/scripts/option-groups.awk 2014-08-27 07:26:51.652070587 +0000
+@@ -0,0 +1,63 @@
++# option-groups.awk --- generate option group header file
++# Given input files containing makefile-style assignments to variables,
++# print out a header file that #defines an appropriate preprocessor
++# symbol for each variable left set to 'y'.
++
++BEGIN { FS="=" }
++
++# Trim spaces.
++{ gsub (/[[:blank:]]/, "") }
++
++# Skip comments.
++/^#/ { next }
++
++# Process assignments.
++NF == 2 {
++ vars[$1] = $2
++}
++
++# Print final values.
++END {
++ print "/* This file is automatically generated by scripts/option-groups.awk"
++ print " in the EGLIBC source tree."
++ print ""
++ print " It defines macros that indicate which EGLIBC option groups were"
++ print " configured in 'option-groups.config' when this C library was"
++ print " built. For each option group named OPTION_foo, it #defines"
++ print " __OPTION_foo to be 1 if the group is enabled, or #defines that"
++ print " symbol to be 0 if the group is disabled. */"
++ print ""
++ print "#ifndef __GNU_OPTION_GROUPS_H"
++ print "#define __GNU_OPTION_GROUPS_H"
++ print ""
++
++ # Produce a sorted list of variable names.
++ i=0
++ for (var in vars)
++ names[i++] = var
++ n = asort (names)
++
++ for (i = 1; i <= n; i++)
++ {
++ var = names[i]
++ if (var ~ /^OPTION_/)
++ {
++ if (vars[var] == "y")
++ print "#define __" var " 1"
++ else if (vars[var] == "n")
++ print "#define __" var " 0"
++ else if (vars[var] ~ /^[0-9]+/ ||
++ vars[var] ~ /^0x[0-9aAbBcCdDeEfF]+/ ||
++ vars[var] ~ /^\"/)
++ print "#define __" var " " vars[var]
++ else
++ print "/* #undef __" var " */"
++ # Ignore variables that don't have boolean, int, hex, or
++ # string values. Ideally, this would be driven by the types
++ # given in option-groups.def.
++ }
++ }
++
++ print ""
++ print "#endif /* __GNU_OPTION_GROUPS_H */"
++}
diff --git a/recipes-core/glibc/glibc/ppc-sqrt_finite.patch b/recipes-core/glibc/glibc/ppc-sqrt_finite.patch
new file mode 100644
index 0000000..6ea666b
--- /dev/null
+++ b/recipes-core/glibc/glibc/ppc-sqrt_finite.patch
@@ -0,0 +1,184 @@
+on ppc fixes the errors like below
+| ./.libs/libpulsecore-1.1.so: undefined reference to `__sqrt_finite'
+| collect2: ld returned 1 exit status
+
+Upstream-Status: Pending
+
+ChangeLog
+
+2012-01-06 Khem Raj <raj.khem at gmail.com>
+
+ * sysdeps/powerpc/powerpc64/e5500/fpu/e_sqrtf.c: Add __*_finite alias.
+ Remove cruft.
+ * sysdeps/powerpc/powerpc64/e5500/fpu/e_sqrt.c: Ditto.
+ * sysdeps/powerpc/powerpc32/603e/fpu/e_sqrt.c: Ditto.
+ * sysdeps/powerpc/powerpc32/603e/fpu/e_sqrtf.c: Ditto.
+
+Index: libc/sysdeps/powerpc/powerpc32/603e/fpu/e_sqrt.c
+===================================================================
+--- libc.orig/sysdeps/powerpc/powerpc32/603e/fpu/e_sqrt.c
++++ libc/sysdeps/powerpc/powerpc32/603e/fpu/e_sqrt.c
+@@ -39,14 +39,8 @@ static const float half = 0.5;
+ We find the actual square root and half of its reciprocal
+ simultaneously. */
+
+-#ifdef __STDC__
+ double
+ __ieee754_sqrt (double b)
+-#else
+-double
+-__ieee754_sqrt (b)
+- double b;
+-#endif
+ {
+ if (__builtin_expect (b > 0, 1))
+ {
+@@ -132,3 +126,4 @@ __ieee754_sqrt (b)
+ }
+ return f_wash (b);
+ }
++strong_alias (__ieee754_sqrt, __sqrt_finite)
+Index: libc/sysdeps/powerpc/powerpc32/603e/fpu/e_sqrtf.c
+===================================================================
+--- libc.orig/sysdeps/powerpc/powerpc32/603e/fpu/e_sqrtf.c
++++ libc/sysdeps/powerpc/powerpc32/603e/fpu/e_sqrtf.c
+@@ -37,14 +37,8 @@ static const float threehalf = 1.5;
+ We find the reciprocal square root and use that to compute the actual
+ square root. */
+
+-#ifdef __STDC__
+ float
+ __ieee754_sqrtf (float b)
+-#else
+-float
+-__ieee754_sqrtf (b)
+- float b;
+-#endif
+ {
+ if (__builtin_expect (b > 0, 1))
+ {
+@@ -99,3 +93,4 @@ __ieee754_sqrtf (b)
+ }
+ return f_washf (b);
+ }
++strong_alias (__ieee754_sqrtf, __sqrtf_finite)
+Index: libc/sysdeps/powerpc/powerpc64/e5500/fpu/e_sqrt.c
+===================================================================
+--- libc.orig/sysdeps/powerpc/powerpc64/e5500/fpu/e_sqrt.c
++++ libc/sysdeps/powerpc/powerpc64/e5500/fpu/e_sqrt.c
+@@ -39,14 +39,8 @@ static const float half = 0.5;
+ We find the actual square root and half of its reciprocal
+ simultaneously. */
+
+-#ifdef __STDC__
+ double
+ __ieee754_sqrt (double b)
+-#else
+-double
+-__ieee754_sqrt (b)
+- double b;
+-#endif
+ {
+ if (__builtin_expect (b > 0, 1))
+ {
+@@ -132,3 +126,4 @@ __ieee754_sqrt (b)
+ }
+ return f_wash (b);
+ }
++strong_alias (__ieee754_sqrt, __sqrt_finite)
+Index: libc/sysdeps/powerpc/powerpc64/e5500/fpu/e_sqrtf.c
+===================================================================
+--- libc.orig/sysdeps/powerpc/powerpc64/e5500/fpu/e_sqrtf.c
++++ libc/sysdeps/powerpc/powerpc64/e5500/fpu/e_sqrtf.c
+@@ -37,14 +37,8 @@ static const float threehalf = 1.5;
+ We find the reciprocal square root and use that to compute the actual
+ square root. */
+
+-#ifdef __STDC__
+ float
+ __ieee754_sqrtf (float b)
+-#else
+-float
+-__ieee754_sqrtf (b)
+- float b;
+-#endif
+ {
+ if (__builtin_expect (b > 0, 1))
+ {
+@@ -99,3 +93,4 @@ __ieee754_sqrtf (b)
+ }
+ return f_washf (b);
+ }
++strong_alias (__ieee754_sqrtf, __sqrtf_finite)
+Index: libc/sysdeps/powerpc/powerpc32/e500mc/fpu/e_sqrt.c
+===================================================================
+--- libc.orig/sysdeps/powerpc/powerpc32/e500mc/fpu/e_sqrt.c
++++ libc/sysdeps/powerpc/powerpc32/e500mc/fpu/e_sqrt.c
+@@ -132,3 +132,4 @@ __ieee754_sqrt (b)
+ }
+ return f_wash (b);
+ }
++strong_alias (__ieee754_sqrt, __sqrt_finite)
+Index: libc/sysdeps/powerpc/powerpc32/e500mc/fpu/e_sqrtf.c
+===================================================================
+--- libc.orig/sysdeps/powerpc/powerpc32/e500mc/fpu/e_sqrtf.c
++++ libc/sysdeps/powerpc/powerpc32/e500mc/fpu/e_sqrtf.c
+@@ -99,3 +99,4 @@ __ieee754_sqrtf (b)
+ }
+ return f_washf (b);
+ }
++strong_alias (__ieee754_sqrtf, __sqrtf_finite)
+Index: libc/sysdeps/powerpc/powerpc32/e5500/fpu/e_sqrt.c
+===================================================================
+--- libc.orig/sysdeps/powerpc/powerpc32/e5500/fpu/e_sqrt.c
++++ libc/sysdeps/powerpc/powerpc32/e5500/fpu/e_sqrt.c
+@@ -132,3 +132,4 @@ __ieee754_sqrt (b)
+ }
+ return f_wash (b);
+ }
++strong_alias (__ieee754_sqrt, __sqrt_finite)
+Index: libc/sysdeps/powerpc/powerpc32/e5500/fpu/e_sqrtf.c
+===================================================================
+--- libc.orig/sysdeps/powerpc/powerpc32/e5500/fpu/e_sqrtf.c
++++ libc/sysdeps/powerpc/powerpc32/e5500/fpu/e_sqrtf.c
+@@ -99,3 +99,4 @@ __ieee754_sqrtf (b)
+ }
+ return f_washf (b);
+ }
++strong_alias (__ieee754_sqrtf, __sqrtf_finite)
+Index: libc/sysdeps/powerpc/powerpc64/e6500/fpu/e_sqrt.c
+===================================================================
+--- libc.orig/sysdeps/powerpc/powerpc64/e6500/fpu/e_sqrt.c
++++ libc/sysdeps/powerpc/powerpc64/e6500/fpu/e_sqrt.c
+@@ -132,3 +132,4 @@ __ieee754_sqrt (b)
+ }
+ return f_wash (b);
+ }
++strong_alias (__ieee754_sqrt, __sqrt_finite)
+Index: libc/sysdeps/powerpc/powerpc64/e6500/fpu/e_sqrtf.c
+===================================================================
+--- libc.orig/sysdeps/powerpc/powerpc64/e6500/fpu/e_sqrtf.c
++++ libc/sysdeps/powerpc/powerpc64/e6500/fpu/e_sqrtf.c
+@@ -99,3 +99,4 @@ __ieee754_sqrtf (b)
+ }
+ return f_washf (b);
+ }
++strong_alias (__ieee754_sqrtf, __sqrtf_finite)
+Index: libc/sysdeps/powerpc/powerpc32/e6500/fpu/e_sqrt.c
+===================================================================
+--- libc.orig/sysdeps/powerpc/powerpc32/e6500/fpu/e_sqrt.c
++++ libc/sysdeps/powerpc/powerpc32/e6500/fpu/e_sqrt.c
+@@ -132,3 +132,4 @@ __ieee754_sqrt (b)
+ }
+ return f_wash (b);
+ }
++strong_alias (__ieee754_sqrt, __sqrt_finite)
+Index: libc/sysdeps/powerpc/powerpc32/e6500/fpu/e_sqrtf.c
+===================================================================
+--- libc.orig/sysdeps/powerpc/powerpc32/e6500/fpu/e_sqrtf.c
++++ libc/sysdeps/powerpc/powerpc32/e6500/fpu/e_sqrtf.c
+@@ -99,3 +99,4 @@ __ieee754_sqrtf (b)
+ }
+ return f_washf (b);
+ }
++strong_alias (__ieee754_sqrtf, __sqrtf_finite)
diff --git a/recipes-core/glibc/glibc/ppc_slow_ieee754_sqrt.patch b/recipes-core/glibc/glibc/ppc_slow_ieee754_sqrt.patch
new file mode 100644
index 0000000..5b819bc
--- /dev/null
+++ b/recipes-core/glibc/glibc/ppc_slow_ieee754_sqrt.patch
@@ -0,0 +1,365 @@
+ __ieee754_sqrt{,f} are now inline functions and call out __slow versions
+
+
+Signed-off-by: Khem Raj <raj.khem at gmail.com>
+Upstream-Status: Pending
+Index: git/sysdeps/powerpc/powerpc32/603e/fpu/e_sqrt.c
+===================================================================
+--- git.orig/sysdeps/powerpc/powerpc32/603e/fpu/e_sqrt.c 2014-08-29 10:35:02.616070587 -0700
++++ git/sysdeps/powerpc/powerpc32/603e/fpu/e_sqrt.c 2014-08-29 10:35:02.604070587 -0700
+@@ -40,7 +40,7 @@
+ simultaneously. */
+
+ double
+-__ieee754_sqrt (double b)
++__slow_ieee754_sqrt (double b)
+ {
+ if (__builtin_expect (b > 0, 1))
+ {
+@@ -77,7 +77,7 @@
+
+ /* Handle small numbers by scaling. */
+ if (__builtin_expect ((u.parts.msw & 0x7ff00000) <= 0x02000000, 0))
+- return __ieee754_sqrt (b * two108) * twom54;
++ return __slow_ieee754_sqrt (b * two108) * twom54;
+
+ #define FMADD(a_, c_, b_) \
+ ({ double __r; \
+@@ -126,4 +126,12 @@
+ }
+ return f_wash (b);
+ }
++
++#undef __ieee754_sqrt
++double
++__ieee754_sqrt (double x)
++{
++ return __slow_ieee754_sqrt (x);
++}
++
+ strong_alias (__ieee754_sqrt, __sqrt_finite)
+Index: git/sysdeps/powerpc/powerpc32/603e/fpu/e_sqrtf.c
+===================================================================
+--- git.orig/sysdeps/powerpc/powerpc32/603e/fpu/e_sqrtf.c 2014-08-29 10:35:02.616070587 -0700
++++ git/sysdeps/powerpc/powerpc32/603e/fpu/e_sqrtf.c 2014-08-29 10:35:02.604070587 -0700
+@@ -38,7 +38,7 @@
+ square root. */
+
+ float
+-__ieee754_sqrtf (float b)
++__slow_ieee754_sqrtf (float b)
+ {
+ if (__builtin_expect (b > 0, 1))
+ {
+@@ -93,4 +93,10 @@
+ }
+ return f_washf (b);
+ }
++#undef __ieee754_sqrtf
++float
++__ieee754_sqrtf (float x)
++{
++ return __slow_ieee754_sqrtf (x);
++}
+ strong_alias (__ieee754_sqrtf, __sqrtf_finite)
+Index: git/sysdeps/powerpc/powerpc64/e5500/fpu/e_sqrt.c
+===================================================================
+--- git.orig/sysdeps/powerpc/powerpc64/e5500/fpu/e_sqrt.c 2014-08-29 10:35:02.616070587 -0700
++++ git/sysdeps/powerpc/powerpc64/e5500/fpu/e_sqrt.c 2014-08-29 10:35:02.604070587 -0700
+@@ -40,7 +40,7 @@
+ simultaneously. */
+
+ double
+-__ieee754_sqrt (double b)
++__slow_ieee754_sqrt (double b)
+ {
+ if (__builtin_expect (b > 0, 1))
+ {
+@@ -77,7 +77,7 @@
+
+ /* Handle small numbers by scaling. */
+ if (__builtin_expect ((u.parts.msw & 0x7ff00000) <= 0x02000000, 0))
+- return __ieee754_sqrt (b * two108) * twom54;
++ return __slow_ieee754_sqrt (b * two108) * twom54;
+
+ #define FMADD(a_, c_, b_) \
+ ({ double __r; \
+@@ -126,4 +126,12 @@
+ }
+ return f_wash (b);
+ }
++
++#undef __ieee754_sqrt
++double
++__ieee754_sqrt (double x)
++{
++ return __slow_ieee754_sqrt (x);
++}
++
+ strong_alias (__ieee754_sqrt, __sqrt_finite)
+Index: git/sysdeps/powerpc/powerpc64/e5500/fpu/e_sqrtf.c
+===================================================================
+--- git.orig/sysdeps/powerpc/powerpc64/e5500/fpu/e_sqrtf.c 2014-08-29 10:35:02.616070587 -0700
++++ git/sysdeps/powerpc/powerpc64/e5500/fpu/e_sqrtf.c 2014-08-29 10:35:02.604070587 -0700
+@@ -38,7 +38,7 @@
+ square root. */
+
+ float
+-__ieee754_sqrtf (float b)
++__slow_ieee754_sqrtf (float b)
+ {
+ if (__builtin_expect (b > 0, 1))
+ {
+@@ -93,4 +93,11 @@
+ }
+ return f_washf (b);
+ }
++#undef __ieee754_sqrtf
++float
++__ieee754_sqrtf (float x)
++{
++ return __slow_ieee754_sqrtf (x);
++}
++
+ strong_alias (__ieee754_sqrtf, __sqrtf_finite)
+Index: git/sysdeps/powerpc/powerpc64/e6500/fpu/e_sqrt.c
+===================================================================
+--- git.orig/sysdeps/powerpc/powerpc64/e6500/fpu/e_sqrt.c 2014-08-29 10:35:02.616070587 -0700
++++ git/sysdeps/powerpc/powerpc64/e6500/fpu/e_sqrt.c 2014-08-29 10:35:02.604070587 -0700
+@@ -41,10 +41,10 @@
+
+ #ifdef __STDC__
+ double
+-__ieee754_sqrt (double b)
++__slow_ieee754_sqrt (double b)
+ #else
+ double
+-__ieee754_sqrt (b)
++__slow_ieee754_sqrt (b)
+ double b;
+ #endif
+ {
+@@ -83,7 +83,7 @@
+
+ /* Handle small numbers by scaling. */
+ if (__builtin_expect ((u.parts.msw & 0x7ff00000) <= 0x02000000, 0))
+- return __ieee754_sqrt (b * two108) * twom54;
++ return __slow_ieee754_sqrt (b * two108) * twom54;
+
+ #define FMADD(a_, c_, b_) \
+ ({ double __r; \
+@@ -132,4 +132,12 @@
+ }
+ return f_wash (b);
+ }
++
++#undef __ieee754_sqrt
++double
++__ieee754_sqrt (double x)
++{
++ return __slow_ieee754_sqrt (x);
++}
++
+ strong_alias (__ieee754_sqrt, __sqrt_finite)
+Index: git/sysdeps/powerpc/powerpc64/e6500/fpu/e_sqrtf.c
+===================================================================
+--- git.orig/sysdeps/powerpc/powerpc64/e6500/fpu/e_sqrtf.c 2014-08-29 10:35:02.616070587 -0700
++++ git/sysdeps/powerpc/powerpc64/e6500/fpu/e_sqrtf.c 2014-08-29 10:35:02.604070587 -0700
+@@ -39,10 +39,10 @@
+
+ #ifdef __STDC__
+ float
+-__ieee754_sqrtf (float b)
++__slow_ieee754_sqrtf (float b)
+ #else
+ float
+-__ieee754_sqrtf (b)
++__slow_ieee754_sqrtf (b)
+ float b;
+ #endif
+ {
+@@ -99,4 +99,12 @@
+ }
+ return f_washf (b);
+ }
++
++#undef __ieee754_sqrtf
++float
++__ieee754_sqrtf (float x)
++{
++ return __slow_ieee754_sqrtf (x);
++}
++
+ strong_alias (__ieee754_sqrtf, __sqrtf_finite)
+Index: git/sysdeps/powerpc/powerpc32/e500mc/fpu/e_sqrt.c
+===================================================================
+--- git.orig/sysdeps/powerpc/powerpc32/e500mc/fpu/e_sqrt.c 2014-08-29 10:35:02.616070587 -0700
++++ git/sysdeps/powerpc/powerpc32/e500mc/fpu/e_sqrt.c 2014-08-29 10:35:02.608070587 -0700
+@@ -41,10 +41,10 @@
+
+ #ifdef __STDC__
+ double
+-__ieee754_sqrt (double b)
++__slow_ieee754_sqrt (double b)
+ #else
+ double
+-__ieee754_sqrt (b)
++__slow_ieee754_sqrt (b)
+ double b;
+ #endif
+ {
+@@ -83,7 +83,7 @@
+
+ /* Handle small numbers by scaling. */
+ if (__builtin_expect ((u.parts.msw & 0x7ff00000) <= 0x02000000, 0))
+- return __ieee754_sqrt (b * two108) * twom54;
++ return __slow_ieee754_sqrt (b * two108) * twom54;
+
+ #define FMADD(a_, c_, b_) \
+ ({ double __r; \
+@@ -132,4 +132,12 @@
+ }
+ return f_wash (b);
+ }
++
++#undef __ieee754_sqrt
++double
++__ieee754_sqrt (double x)
++{
++ return __slow_ieee754_sqrt (x);
++}
++
+ strong_alias (__ieee754_sqrt, __sqrt_finite)
+Index: git/sysdeps/powerpc/powerpc32/e500mc/fpu/e_sqrtf.c
+===================================================================
+--- git.orig/sysdeps/powerpc/powerpc32/e500mc/fpu/e_sqrtf.c 2014-08-29 10:35:02.616070587 -0700
++++ git/sysdeps/powerpc/powerpc32/e500mc/fpu/e_sqrtf.c 2014-08-29 10:35:02.608070587 -0700
+@@ -39,10 +39,10 @@
+
+ #ifdef __STDC__
+ float
+-__ieee754_sqrtf (float b)
++__slow_ieee754_sqrtf (float b)
+ #else
+ float
+-__ieee754_sqrtf (b)
++__slow_ieee754_sqrtf (b)
+ float b;
+ #endif
+ {
+@@ -99,4 +99,12 @@
+ }
+ return f_washf (b);
+ }
++
++#undef __ieee754_sqrtf
++float
++__ieee754_sqrtf (float x)
++{
++ return __slow_ieee754_sqrtf (x);
++}
++
+ strong_alias (__ieee754_sqrtf, __sqrtf_finite)
+Index: git/sysdeps/powerpc/powerpc32/e5500/fpu/e_sqrt.c
+===================================================================
+--- git.orig/sysdeps/powerpc/powerpc32/e5500/fpu/e_sqrt.c 2014-08-29 10:35:02.616070587 -0700
++++ git/sysdeps/powerpc/powerpc32/e5500/fpu/e_sqrt.c 2014-08-29 10:35:02.608070587 -0700
+@@ -41,10 +41,10 @@
+
+ #ifdef __STDC__
+ double
+-__ieee754_sqrt (double b)
++__slow_ieee754_sqrt (double b)
+ #else
+ double
+-__ieee754_sqrt (b)
++__slow_ieee754_sqrt (b)
+ double b;
+ #endif
+ {
+@@ -83,7 +83,7 @@
+
+ /* Handle small numbers by scaling. */
+ if (__builtin_expect ((u.parts.msw & 0x7ff00000) <= 0x02000000, 0))
+- return __ieee754_sqrt (b * two108) * twom54;
++ return __slow_ieee754_sqrt (b * two108) * twom54;
+
+ #define FMADD(a_, c_, b_) \
+ ({ double __r; \
+@@ -132,4 +132,12 @@
+ }
+ return f_wash (b);
+ }
++
++#undef __ieee754_sqrt
++double
++__ieee754_sqrt (double x)
++{
++ return __slow_ieee754_sqrt (x);
++}
++
+ strong_alias (__ieee754_sqrt, __sqrt_finite)
+Index: git/sysdeps/powerpc/powerpc32/e5500/fpu/e_sqrtf.c
+===================================================================
+--- git.orig/sysdeps/powerpc/powerpc32/e5500/fpu/e_sqrtf.c 2014-08-29 10:35:02.616070587 -0700
++++ git/sysdeps/powerpc/powerpc32/e5500/fpu/e_sqrtf.c 2014-08-29 10:35:02.608070587 -0700
+@@ -39,10 +39,10 @@
+
+ #ifdef __STDC__
+ float
+-__ieee754_sqrtf (float b)
++__slow_ieee754_sqrtf (float b)
+ #else
+ float
+-__ieee754_sqrtf (b)
++__slow_ieee754_sqrtf (b)
+ float b;
+ #endif
+ {
+@@ -99,4 +99,12 @@
+ }
+ return f_washf (b);
+ }
++
++#undef __ieee754_sqrtf
++float
++__ieee754_sqrtf (float x)
++{
++ return __slow_ieee754_sqrtf (x);
++}
++
+ strong_alias (__ieee754_sqrtf, __sqrtf_finite)
+Index: git/sysdeps/powerpc/powerpc32/e6500/fpu/e_sqrt.c
+===================================================================
+--- git.orig/sysdeps/powerpc/powerpc32/e6500/fpu/e_sqrt.c 2014-08-29 10:35:02.616070587 -0700
++++ git/sysdeps/powerpc/powerpc32/e6500/fpu/e_sqrt.c 2014-08-29 10:35:02.608070587 -0700
+@@ -132,4 +132,12 @@
+ }
+ return f_wash (b);
+ }
++
++#undef __ieee754_sqrt
++double
++__ieee754_sqrt (double x)
++{
++ return __slow_ieee754_sqrt (x);
++}
++
+ strong_alias (__ieee754_sqrt, __sqrt_finite)
+Index: git/sysdeps/powerpc/powerpc32/e6500/fpu/e_sqrtf.c
+===================================================================
+--- git.orig/sysdeps/powerpc/powerpc32/e6500/fpu/e_sqrtf.c 2014-08-29 10:35:02.616070587 -0700
++++ git/sysdeps/powerpc/powerpc32/e6500/fpu/e_sqrtf.c 2014-08-29 10:35:02.608070587 -0700
+@@ -99,4 +99,12 @@
+ }
+ return f_washf (b);
+ }
++
++#undef __ieee754_sqrtf
++float
++__ieee754_sqrtf (float x)
++{
++ return __slow_ieee754_sqrtf (x);
++}
++
+ strong_alias (__ieee754_sqrtf, __sqrtf_finite)
diff --git a/recipes-core/glibc/glibc/ppce6500-32b_slow_ieee754_sqrt.patch b/recipes-core/glibc/glibc/ppce6500-32b_slow_ieee754_sqrt.patch
new file mode 100644
index 0000000..4c6c107
--- /dev/null
+++ b/recipes-core/glibc/glibc/ppce6500-32b_slow_ieee754_sqrt.patch
@@ -0,0 +1,47 @@
+ __ieee754_sqrt{,f} are now inline functions and call out __slow versions
+
+
+Signed-off-by: chunrong guo <B40290 at freescale.com>
+Upstream-Status: Pending
+
+diff -rNu libc-orig/sysdeps/powerpc/powerpc32/e6500/fpu/e_sqrt.c libc/sysdeps/powerpc/powerpc32/e6500/fpu/e_sqrt.c
+--- libc-orig/sysdeps/powerpc/powerpc32/e6500/fpu/e_sqrt.c 2014-04-08 04:39:58.487229887 -0500
++++ libc/sysdeps/powerpc/powerpc32/e6500/fpu/e_sqrt.c 2014-04-08 04:40:52.643069198 -0500
+@@ -41,10 +41,10 @@
+
+ #ifdef __STDC__
+ double
+-__ieee754_sqrt (double b)
++__slow_ieee754_sqrt (double b)
+ #else
+ double
+-__ieee754_sqrt (b)
++__slow_ieee754_sqrt (b)
+ double b;
+ #endif
+ {
+@@ -83,7 +83,7 @@
+
+ /* Handle small numbers by scaling. */
+ if (__builtin_expect ((u.parts.msw & 0x7ff00000) <= 0x02000000, 0))
+- return __ieee754_sqrt (b * two108) * twom54;
++ return __slow_ieee754_sqrt (b * two108) * twom54;
+
+ #define FMADD(a_, c_, b_) \
+ ({ double __r; \
+diff -rNu libc-orig/sysdeps/powerpc/powerpc32/e6500/fpu/e_sqrtf.c libc/sysdeps/powerpc/powerpc32/e6500/fpu/e_sqrtf.c
+--- libc-orig/sysdeps/powerpc/powerpc32/e6500/fpu/e_sqrtf.c 2014-04-08 04:39:58.487229887 -0500
++++ libc/sysdeps/powerpc/powerpc32/e6500/fpu/e_sqrtf.c 2014-04-08 04:41:26.017067682 -0500
+@@ -39,10 +39,10 @@
+
+ #ifdef __STDC__
+ float
+-__ieee754_sqrtf (float b)
++__slow_ieee754_sqrtf (float b)
+ #else
+ float
+-__ieee754_sqrtf (b)
++__slow_ieee754_sqrtf (b)
+ float b;
+ #endif
+ {
diff --git a/recipes-core/glibc/glibc/relocatable_sdk.patch b/recipes-core/glibc/glibc/relocatable_sdk.patch
new file mode 100644
index 0000000..ca5f17b
--- /dev/null
+++ b/recipes-core/glibc/glibc/relocatable_sdk.patch
@@ -0,0 +1,108 @@
+Upstream-Status: Inappropriate [SDK specific]
+
+This patch puts the dynamic loader path in the binaries, SYSTEM_DIRS strings
+and lengths as well as ld.so.cache path in the dynamic loader to specific
+sections in memory. The sections that contain paths have been allocated a 4096
+byte section, which is the maximum path length in linux. This will allow the
+relocating script to parse the ELF binary, detect the section and easily replace
+the strings in a certain path.
+
+Signed-off-by: Laurentiu Palcu <laurentiu.palcu at intel.com>
+
+Index: libc/elf/interp.c
+===================================================================
+--- libc.orig/elf/interp.c
++++ libc/elf/interp.c
+@@ -16,5 +16,5 @@
+ License along with the GNU C Library; if not, see
+ <http://www.gnu.org/licenses/>. */
+
+-const char __invoke_dynamic_linker__[] __attribute__ ((section (".interp")))
++const char __invoke_dynamic_linker__[4096] __attribute__ ((section (".interp")))
+ = RUNTIME_LINKER;
+Index: libc/elf/dl-load.c
+===================================================================
+--- libc.orig/elf/dl-load.c
++++ libc/elf/dl-load.c
+@@ -144,8 +144,8 @@ static size_t max_capstrlen attribute_re
+ /* Get the generated information about the trusted directories. */
+ #include "trusted-dirs.h"
+
+-static const char system_dirs[] = SYSTEM_DIRS;
+-static const size_t system_dirs_len[] =
++static const char system_dirs[4096] __attribute__ ((section (".sysdirs"))) = SYSTEM_DIRS;
++volatile static const size_t system_dirs_len[] __attribute__ ((section (".sysdirslen"))) =
+ {
+ SYSTEM_DIRS_LEN
+ };
+Index: libc/elf/dl-cache.c
+===================================================================
+--- libc.orig/elf/dl-cache.c
++++ libc/elf/dl-cache.c
+@@ -133,6 +133,10 @@ do \
+ while (0)
+
+
++const char LD_SO_CACHE[4096] __attribute__ ((section (".ldsocache"))) =
++ SYSCONFDIR "/ld.so.cache";
++
++
+ int
+ internal_function
+ _dl_cache_libcmp (const char *p1, const char *p2)
+Index: libc/elf/ldconfig.c
+===================================================================
+--- libc.orig/elf/ldconfig.c
++++ libc/elf/ldconfig.c
+@@ -166,6 +166,9 @@ static struct argp argp =
+ options, parse_opt, NULL, doc, NULL, more_help, NULL
+ };
+
++
++extern const char LD_SO_CACHE[4096] __attribute__ ((section (".ldsocache")));
++
+ /* Check if string corresponds to an important hardware capability or
+ a platform. */
+ static int
+Index: libc/sysdeps/generic/dl-cache.h
+===================================================================
+--- libc.orig/sysdeps/generic/dl-cache.h
++++ libc/sysdeps/generic/dl-cache.h
+@@ -27,10 +27,6 @@
+ ((flags) == 1 || (flags) == _DL_CACHE_DEFAULT_ID)
+ #endif
+
+-#ifndef LD_SO_CACHE
+-# define LD_SO_CACHE SYSCONFDIR "/ld.so.cache"
+-#endif
+-
+ #ifndef add_system_dir
+ # define add_system_dir(dir) add_dir (dir)
+ #endif
+Index: libc/elf/rtld.c
+===================================================================
+--- libc.orig/elf/rtld.c
++++ libc/elf/rtld.c
+@@ -99,6 +99,7 @@ uintptr_t __pointer_chk_guard_local
+ strong_alias (__pointer_chk_guard_local, __pointer_chk_guard)
+ #endif
+
++extern const char LD_SO_CACHE[4096] __attribute__ ((section (".ldsocache")));
+
+ /* List of auditing DSOs. */
+ static struct audit_list
+@@ -1031,12 +1032,12 @@ of this helper program; chances are you
+ --list list all dependencies and how they are resolved\n\
+ --verify verify that given object really is a dynamically linked\n\
+ object we can handle\n\
+- --inhibit-cache Do not use " LD_SO_CACHE "\n\
++ --inhibit-cache Do not use %s\n\
+ --library-path PATH use given PATH instead of content of the environment\n\
+ variable LD_LIBRARY_PATH\n\
+ --inhibit-rpath LIST ignore RUNPATH and RPATH information in object names\n\
+ in LIST\n\
+- --audit LIST use objects named in LIST as auditors\n");
++ --audit LIST use objects named in LIST as auditors\n", LD_SO_CACHE);
+
+ ++_dl_skip_args;
+ --_dl_argc;
diff --git a/recipes-core/glibc/glibc/relocatable_sdk_fix_openpath.patch b/recipes-core/glibc/glibc/relocatable_sdk_fix_openpath.patch
new file mode 100644
index 0000000..f164f8f
--- /dev/null
+++ b/recipes-core/glibc/glibc/relocatable_sdk_fix_openpath.patch
@@ -0,0 +1,41 @@
+Upstream-Status: Inappropriate [SDK specific]
+
+eglibc-nativesdk: Fix buffer overrun with a relocated SDK
+
+When ld-linux-*.so.2 is relocated to a path that is longer than the
+original fixed location, the dynamic loader will crash in open_path
+because it implicitly assumes that max_dirnamelen is a fixed size that
+never changes.
+
+The allocated buffer will not be large enough to contain the directory
+path string which is larger than the fixed location provided at build
+time.
+
+Signed-off-by: Jason Wessel <jason.wessel at windriver.com>
+
+---
+ elf/dl-load.c | 12 ++++++++++++
+ 1 file changed, 12 insertions(+)
+
+--- a/elf/dl-load.c
++++ b/elf/dl-load.c
+@@ -1919,7 +1919,19 @@ open_path (const char *name, size_t name
+ given on the command line when rtld is run directly. */
+ return -1;
+
++ do
++ {
++ struct r_search_path_elem *this_dir = *dirs;
++ if (this_dir->dirnamelen > max_dirnamelen)
++ {
++ max_dirnamelen = this_dir->dirnamelen;
++ }
++ }
++ while (*++dirs != NULL);
++
+ buf = alloca (max_dirnamelen + max_capstrlen + namelen);
++
++ dirs = sps->dirs;
+ do
+ {
+ struct r_search_path_elem *this_dir = *dirs;
diff --git a/recipes-core/glibc/glibc/timezone-re-written-tzselect-as-posix-sh.patch b/recipes-core/glibc/glibc/timezone-re-written-tzselect-as-posix-sh.patch
new file mode 100644
index 0000000..55547de
--- /dev/null
+++ b/recipes-core/glibc/glibc/timezone-re-written-tzselect-as-posix-sh.patch
@@ -0,0 +1,38 @@
+timezone: re-written tzselect as posix sh
+
+To avoid the bash dependency.
+
+Upstream-Status: Pending
+
+Signed-off-by: Hongxu Jia <hongxu.jia at windriver.com>
+---
+ timezone/Makefile | 2 +-
+ timezone/tzselect.ksh | 2 +-
+ 2 files changed, 2 insertions(+), 2 deletions(-)
+
+Index: git/timezone/Makefile
+===================================================================
+--- git.orig/timezone/Makefile 2014-08-27 05:35:58.008070587 +0000
++++ git/timezone/Makefile 2014-08-27 05:36:37.908070587 +0000
+@@ -114,7 +114,7 @@
+
+
+ $(objpfx)tzselect: tzselect.ksh $(common-objpfx)config.make
+- sed -e 's|/bin/bash|$(BASH)|' \
++ sed -e 's|/bin/bash|/bin/sh|' \
+ -e 's|TZDIR=[^}]*|TZDIR=$(zonedir)|' \
+ -e '/TZVERSION=/s|see_Makefile|"$(version)"|' \
+ -e '/PKGVERSION=/s|=.*|="$(PKGVERSION)"|' \
+Index: git/timezone/tzselect.ksh
+===================================================================
+--- git.orig/timezone/tzselect.ksh 2014-08-27 05:35:58.008070587 +0000
++++ git/timezone/tzselect.ksh 2014-08-27 05:35:58.000070587 +0000
+@@ -35,7 +35,7 @@
+
+ # Specify default values for environment variables if they are unset.
+ : ${AWK=awk}
+-: ${TZDIR=`pwd`}
++: ${TZDIR=$(pwd)}
+
+ # Check for awk Posix compliance.
+ ($AWK -v x=y 'BEGIN { exit 123 }') </dev/null >/dev/null 2>&1
diff --git a/recipes-core/glibc/glibc_2.20.bb b/recipes-core/glibc/glibc_2.20.bb
new file mode 100644
index 0000000..e733a49
--- /dev/null
+++ b/recipes-core/glibc/glibc_2.20.bb
@@ -0,0 +1,193 @@
+FILESEXTRAPATHS_prepend := "${THISDIR}/glibc-fsl:"
+
+require recipes-core/glibc/glibc.inc
+
+DEPENDS += "gperf-native kconfig-frontends-native"
+
+PV = "2.20"
+
+SRCREV = "b8079dd0d360648e4e8de48656c5c38972621072"
+
+SRC_URI = "git://sourceware.org/git/glibc.git;branch=release/${PV}/master \
+ file://IO-acquire-lock-fix.patch \
+ file://mips-rld-map-check.patch \
+ file://etc/ld.so.conf \
+ file://generate-supported.mk \
+ file://glibc.fix_sqrt2.patch \
+ file://multilib_readlib.patch \
+ file://ppc-sqrt_finite.patch \
+ file://ppc_slow_ieee754_sqrt.patch \
+ file://add_resource_h_to_wait_h.patch \
+ file://fsl-ppc-no-fsqrt.patch \
+ file://0001-R_ARM_TLS_DTPOFF32.patch \
+ file://0001-eglibc-run-libm-err-tab.pl-with-specific-dirs-in-S.patch \
+ file://fix-tibetian-locales.patch \
+ file://ppce6500-32b_slow_ieee754_sqrt.patch \
+ file://grok_gold.patch \
+ file://fix_am_rootsbindir.patch \
+ file://intl-Merge-with-gettext-version-0.19.3.patch \
+ file://0016-Remove-bash-dependency-for-nscd-init-script.patch \
+ ${EGLIBCPATCHES} \
+ ${CVEPATCHES} \
+ ${FSLPATCHES} \
+ "
+EGLIBCPATCHES = "\
+ file://timezone-re-written-tzselect-as-posix-sh.patch \
+ file://eglibc.patch \
+ file://option-groups.patch \
+ file://GLRO_dl_debug_mask.patch \
+ file://eglibc-header-bootstrap.patch \
+ file://eglibc-resolv-dynamic.patch \
+ file://eglibc-ppc8xx-cache-line-workaround.patch \
+ file://eglibc-sh4-fpscr_values.patch \
+ file://eglibc-use-option-groups.patch \
+ "
+# file://eglibc-install-pic-archives.patch \
+# file://initgroups_keys.patch \
+#
+
+CVEPATCHES = "\
+ file://CVE-2014-7817-wordexp-fails-to-honour-WRDE_NOCMD.patch \
+ file://CVE-2012-3406-Stack-overflow-in-vfprintf-BZ-16617.patch \
+ file://CVE-2014-9402_endless-loop-in-getaddr_r.patch \
+ file://CVE-2015-1781-resolv-nss_dns-dns-host.c-buffer-overf.patch \
+ "
+
+FSLPATCHES = "\
+ file://0005.glibc.fix_prof.patch \
+ file://0006.glibc.fsl-crosszic.patch \
+ file://0007.glibc.fix_MTWX51911-enable_8xx.patch \
+ file://0008.glibc.e500v2_lib_support.patch \
+ file://0009.glibc.fsl-mcpy-e500mc-e5500-e6500.patch \
+ file://0010.glibc.fsl-e500mc-e5500-mset.patch \
+ file://0011.glibc.fsl-mset-e6500.patch \
+ file://0012.glibc.fsl-mcmp-e6500.patch \
+ file://0013.glibc.fsl-stcmp-e5500.patch \
+ file://0014.glibc.fsl-strchr-e500mc-e5500.patch \
+ file://0015.glibc.fsl-strcpy-e500mc-e5500.patch \
+ file://0016.glibc.fsl-strlen-e500mc-e5500.patch \
+ file://0017.glibc.fsl-strrchr-e500mc-e5500.patch \
+ file://0018.glibc.testsuite_remove-blocking-test.patch \
+ file://0019.glibc.readv_proto.patch \
+ file://0020.glibc.fsl-largemcpy-e500mc-e5500-e6500.patch \
+ file://0021.glibc.undefined_static.patch \
+ file://0022.glibc.use-option-groups.patch \
+"
+
+LIC_FILES_CHKSUM = "file://LICENSES;md5=e9a558e243b36d3209f380deb394b213 \
+ file://COPYING;md5=b234ee4d69f5fce4486a80fdaf4a4263 \
+ file://posix/rxspencer/COPYRIGHT;md5=dc5485bb394a13b2332ec1c785f5d83a \
+ file://COPYING.LIB;md5=4fbd65380cdd255951079008b364516c"
+
+SRC_URI_append_class-nativesdk = " file://ld-search-order.patch \
+ file://relocatable_sdk.patch \
+ file://relocatable_sdk_fix_openpath.patch \
+ "
+S = "${WORKDIR}/git"
+B = "${WORKDIR}/build-${TARGET_SYS}"
+
+PACKAGES_DYNAMIC = ""
+
+# the -isystem in bitbake.conf screws up glibc do_stage
+BUILD_CPPFLAGS = "-I${STAGING_INCDIR_NATIVE}"
+TARGET_CPPFLAGS = "-I${STAGING_DIR_TARGET}${includedir}"
+
+GLIBC_BROKEN_LOCALES = " _ER _ET so_ET yn_ER sid_ET tr_TR mn_MN gez_ET gez_ER bn_BD te_IN es_CR.ISO-8859-1"
+
+#
+# For now, we will skip building of a gcc package if it is a uclibc one
+# and our build is not a uclibc one, and we skip a glibc one if our build
+# is a uclibc build.
+#
+# See the note in gcc/gcc_3.4.0.oe
+#
+
+python __anonymous () {
+ import re
+ uc_os = (re.match('.*uclibc$', d.getVar('TARGET_OS', True)) != None)
+ if uc_os:
+ raise bb.parse.SkipPackage("incompatible with target %s" %
+ d.getVar('TARGET_OS', True))
+}
+
+EXTRA_OECONF = "--enable-kernel=${OLDEST_KERNEL} \
+ --without-cvs --disable-profile \
+ --disable-debug --without-gd \
+ --enable-clocale=gnu \
+ --enable-add-ons \
+ --with-headers=${STAGING_INCDIR} \
+ --without-selinux \
+ --enable-obsolete-rpc \
+ --with-kconfig=${STAGING_BINDIR_NATIVE} \
+ --disable-nscd \
+ ${GLIBC_EXTRA_OECONF}"
+
+EXTRA_OECONF += "${@get_libc_fpu_setting(bb, d)}"
+EXTRA_OECONF += "${@bb.utils.contains('DISTRO_FEATURES', 'libc-inet-anl', '--enable-nscd', '--disable-nscd', d)}"
+EXTRA_OECONF += "--disable-multi-arch"
+
+do_patch_append() {
+ bb.build.exec_func('do_fix_readlib_c', d)
+}
+
+# for mips glibc now builds syscall tables for all abi's
+# so we make sure that we choose right march option which is
+# compatible with o32,n32 and n64 abi's
+# e.g. -march=mips32 is not compatible with n32 and n64 therefore
+# we filter it out in such case -march=from-abi which will be
+# mips1 when using o32 and mips3 when using n32/n64
+
+TUNE_CCARGS_mips := "${@oe_filter_out('-march=mips32', '${TUNE_CCARGS}', d)}"
+TUNE_CCARGS_mipsel := "${@oe_filter_out('-march=mips32', '${TUNE_CCARGS}', d)}"
+
+do_fix_readlib_c () {
+ sed -i -e 's#OECORE_KNOWN_INTERPRETER_NAMES#${EGLIBC_KNOWN_INTERPRETER_NAMES}#' ${S}/elf/readlib.c
+}
+
+do_configure () {
+# override this function to avoid the autoconf/automake/aclocal/autoheader
+# calls for now
+# don't pass CPPFLAGS into configure, since it upsets the kernel-headers
+# version check and doesn't really help with anything
+ if [ -z "`which rpcgen`" ]; then
+ echo "rpcgen not found. Install glibc-devel."
+ exit 1
+ fi
+ (cd ${S} && gnu-configize) || die "failure in running gnu-configize"
+ find ${S} -name "configure" | xargs touch
+ CPPFLAGS="" oe_runconf
+}
+
+rpcsvc = "bootparam_prot.x nlm_prot.x rstat.x \
+ yppasswd.x klm_prot.x rex.x sm_inter.x mount.x \
+ rusers.x spray.x nfs_prot.x rquota.x key_prot.x"
+
+do_compile () {
+ # -Wl,-rpath-link <staging>/lib in LDFLAGS can cause breakage if another glibc is in staging
+ unset LDFLAGS
+ base_do_compile
+ (
+ cd ${S}/sunrpc/rpcsvc
+ for r in ${rpcsvc}; do
+ h=`echo $r|sed -e's,\.x$,.h,'`
+ rpcgen -h $r -o $h || bbwarn "unable to generate header for $r"
+ done
+ )
+ echo "Adjust ldd script"
+ if [ -n "${RTLDLIST}" ]
+ then
+ prevrtld=`cat ${B}/elf/ldd | grep "^RTLDLIST=" | sed 's#^RTLDLIST="\?\([^"]*\)"\?$#\1#'`
+ if [ "${prevrtld}" != "${RTLDLIST}" ]
+ then
+ sed -i ${B}/elf/ldd -e "s#^RTLDLIST=.*\$#RTLDLIST=\"${prevrtld} ${RTLDLIST}\"#"
+ fi
+ fi
+
+}
+
+do_install_append () {
+ rm -rf ${D}/usr/include/gnu/lib-names.h
+}
+require glibc-package.inc
+
+BBCLASSEXTEND = "nativesdk"
diff --git a/recipes-core/glibc/ldconfig-native-2.12.1/32and64bit.patch b/recipes-core/glibc/ldconfig-native-2.12.1/32and64bit.patch
new file mode 100644
index 0000000..cdfeaea
--- /dev/null
+++ b/recipes-core/glibc/ldconfig-native-2.12.1/32and64bit.patch
@@ -0,0 +1,331 @@
+Upstream-Status: Inappropriate [embedded specific]
+
+We run the ldconfig in the cross fashion. make the code bitsize aware so that
+we can cross build ldconfig cache for various architectures.
+
+Richard Purdie <richard.purdie at linuxfoundation.org> 2009/05/19
+Nitin A Kamble <nitin.a.kamble at intel.com> 2009/03/29
+
+Index: ldconfig-native-2.12.1/readelflib.c
+===================================================================
+--- ldconfig-native-2.12.1.orig/readelflib.c
++++ ldconfig-native-2.12.1/readelflib.c
+@@ -40,39 +40,212 @@ do \
+
+ /* Returns 0 if everything is ok, != 0 in case of error. */
+ int
+-process_elf_file (const char *file_name, const char *lib, int *flag,
++process_elf_file32 (const char *file_name, const char *lib, int *flag,
+ unsigned int *osversion, char **soname, void *file_contents,
+ size_t file_length)
+ {
+ int i;
+ unsigned int j;
+- ElfW(Addr) loadaddr;
++ Elf32_Addr loadaddr;
+ unsigned int dynamic_addr;
+ size_t dynamic_size;
+ char *program_interpreter;
+
+- ElfW(Ehdr) *elf_header;
+- ElfW(Phdr) *elf_pheader, *segment;
+- ElfW(Dyn) *dynamic_segment, *dyn_entry;
++ Elf32_Ehdr *elf_header;
++ Elf32_Phdr *elf_pheader, *segment;
++ Elf32_Dyn *dynamic_segment, *dyn_entry;
+ char *dynamic_strings;
+
+- elf_header = (ElfW(Ehdr) *) file_contents;
++ elf_header = (Elf32_Ehdr *) file_contents;
+ *osversion = 0;
+
+- if (elf_header->e_ident [EI_CLASS] != ElfW (CLASS))
++ if (elf_header->e_type != ET_DYN)
+ {
+- if (opt_verbose)
++ error (0, 0, _("%s is not a shared object file (Type: %d).\n"), file_name,
++ elf_header->e_type);
++ return 1;
++ }
++
++ /* Get information from elf program header. */
++ elf_pheader = (Elf32_Phdr *) (elf_header->e_phoff + file_contents);
++ check_ptr (elf_pheader);
++
++ /* The library is an elf library, now search for soname and
++ libc5/libc6. */
++ *flag = FLAG_ELF;
++
++ loadaddr = -1;
++ dynamic_addr = 0;
++ dynamic_size = 0;
++ program_interpreter = NULL;
++ for (i = 0, segment = elf_pheader;
++ i < elf_header->e_phnum; i++, segment++)
++ {
++ check_ptr (segment);
++
++ switch (segment->p_type)
+ {
+- if (elf_header->e_ident [EI_CLASS] == ELFCLASS32)
+- error (0, 0, _("%s is a 32 bit ELF file.\n"), file_name);
+- else if (elf_header->e_ident [EI_CLASS] == ELFCLASS64)
+- error (0, 0, _("%s is a 64 bit ELF file.\n"), file_name);
+- else
+- error (0, 0, _("Unknown ELFCLASS in file %s.\n"), file_name);
++ case PT_LOAD:
++ if (loadaddr == (Elf32_Addr) -1)
++ loadaddr = segment->p_vaddr - segment->p_offset;
++ break;
++
++ case PT_DYNAMIC:
++ if (dynamic_addr)
++ error (0, 0, _("more than one dynamic segment\n"));
++
++ dynamic_addr = segment->p_offset;
++ dynamic_size = segment->p_filesz;
++ break;
++
++ case PT_INTERP:
++ program_interpreter = (char *) (file_contents + segment->p_offset);
++ check_ptr (program_interpreter);
++
++ /* Check if this is enough to classify the binary. */
++ for (j = 0; j < sizeof (interpreters) / sizeof (interpreters [0]);
++ ++j)
++ if (strcmp (program_interpreter, interpreters[j].soname) == 0)
++ {
++ *flag = interpreters[j].flag;
++ break;
++ }
++ break;
++
++ case PT_NOTE:
++ if (!*osversion && segment->p_filesz >= 32 && segment->p_align >= 4)
++ {
++ Elf32_Word *abi_note = (Elf32_Word *) (file_contents
++ + segment->p_offset);
++ Elf32_Addr size = segment->p_filesz;
++
++ while (abi_note [0] != 4 || abi_note [1] != 16
++ || abi_note [2] != 1
++ || memcmp (abi_note + 3, "GNU", 4) != 0)
++ {
++#define ROUND(len) (((len) + sizeof (Elf32_Word)) - 1) & -sizeof (Elf32_Word)))
++ Elf32_Addr) note_size = 3 * sizeof (Elf32_Word))
++ + ROUND (abi_note[0])
++ + ROUND (abi_note[1]);
++
++ if (size - 32 < note_size || note_size == 0)
++ {
++ size = 0;
++ break;
++ }
++ size -= note_size;
++ abi_note = (void *) abi_note + note_size;
++ }
++
++ if (size == 0)
++ break;
++
++ *osversion = (abi_note [4] << 24) |
++ ((abi_note [5] & 0xff) << 16) |
++ ((abi_note [6] & 0xff) << 8) |
++ (abi_note [7] & 0xff);
++ }
++ break;
++
++ default:
++ break;
++ }
++
++ }
++ if (loadaddr == (Elf32_Addr) -1)
++ {
++ /* Very strange. */
++ loadaddr = 0;
++ }
++
++ /* Now we can read the dynamic sections. */
++ if (dynamic_size == 0)
++ return 1;
++
++ dynamic_segment = (Elf32_Dyn *) (file_contents + dynamic_addr);
++ check_ptr (dynamic_segment);
++
++ /* Find the string table. */
++ dynamic_strings = NULL;
++ for (dyn_entry = dynamic_segment; dyn_entry->d_tag != DT_NULL;
++ ++dyn_entry)
++ {
++ check_ptr (dyn_entry);
++ if (dyn_entry->d_tag == DT_STRTAB)
++ {
++ dynamic_strings = (char *) (file_contents + dyn_entry->d_un.d_val - loadaddr);
++ check_ptr (dynamic_strings);
++ break;
+ }
+- return 1;
+ }
+
++ if (dynamic_strings == NULL)
++ return 1;
++
++ /* Now read the DT_NEEDED and DT_SONAME entries. */
++ for (dyn_entry = dynamic_segment; dyn_entry->d_tag != DT_NULL;
++ ++dyn_entry)
++ {
++ if (dyn_entry->d_tag == DT_NEEDED || dyn_entry->d_tag == DT_SONAME)
++ {
++ char *name = dynamic_strings + dyn_entry->d_un.d_val;
++ check_ptr (name);
++
++ if (dyn_entry->d_tag == DT_NEEDED)
++ {
++
++ if (*flag == FLAG_ELF)
++ {
++ /* Check if this is enough to classify the binary. */
++ for (j = 0;
++ j < sizeof (known_libs) / sizeof (known_libs [0]);
++ ++j)
++ if (strcmp (name, known_libs [j].soname) == 0)
++ {
++ *flag = known_libs [j].flag;
++ break;
++ }
++ }
++ }
++
++ else if (dyn_entry->d_tag == DT_SONAME)
++ *soname = xstrdup (name);
++
++ /* Do we have everything we need? */
++ if (*soname && *flag != FLAG_ELF)
++ return 0;
++ }
++ }
++
++ /* We reach this point only if the file doesn't contain a DT_SONAME
++ or if we can't classify the library. If it doesn't have a
++ soname, return the name of the library. */
++ if (*soname == NULL)
++ *soname = xstrdup (lib);
++
++ return 0;
++}
++
++int
++process_elf_file64 (const char *file_name, const char *lib, int *flag,
++ unsigned int *osversion, char **soname, void *file_contents,
++ size_t file_length)
++{
++ int i;
++ unsigned int j;
++ Elf64_Addr loadaddr;
++ unsigned int dynamic_addr;
++ size_t dynamic_size;
++ char *program_interpreter;
++
++ Elf64_Ehdr *elf_header;
++ Elf64_Phdr *elf_pheader, *segment;
++ Elf64_Dyn *dynamic_segment, *dyn_entry;
++ char *dynamic_strings;
++
++ elf_header = (Elf64_Ehdr *) file_contents;
++ *osversion = 0;
++
+ if (elf_header->e_type != ET_DYN)
+ {
+ error (0, 0, _("%s is not a shared object file (Type: %d).\n"), file_name,
+@@ -81,7 +254,7 @@ process_elf_file (const char *file_name,
+ }
+
+ /* Get information from elf program header. */
+- elf_pheader = (ElfW(Phdr) *) (elf_header->e_phoff + file_contents);
++ elf_pheader = (Elf64_Phdr *) (elf_header->e_phoff + file_contents);
+ check_ptr (elf_pheader);
+
+ /* The library is an elf library, now search for soname and
+@@ -100,7 +273,7 @@ process_elf_file (const char *file_name,
+ switch (segment->p_type)
+ {
+ case PT_LOAD:
+- if (loadaddr == (ElfW(Addr)) -1)
++ if (loadaddr == (Elf64_Addr) -1)
+ loadaddr = segment->p_vaddr - segment->p_offset;
+ break;
+
+@@ -129,16 +302,16 @@ process_elf_file (const char *file_name,
+ case PT_NOTE:
+ if (!*osversion && segment->p_filesz >= 32 && segment->p_align >= 4)
+ {
+- ElfW(Word) *abi_note = (ElfW(Word) *) (file_contents
++ Elf64_Word *abi_note = (Elf64_Word *) (file_contents
+ + segment->p_offset);
+- ElfW(Addr) size = segment->p_filesz;
++ Elf64_Addr size = segment->p_filesz;
+
+ while (abi_note [0] != 4 || abi_note [1] != 16
+ || abi_note [2] != 1
+ || memcmp (abi_note + 3, "GNU", 4) != 0)
+ {
+-#define ROUND(len) (((len) + sizeof (ElfW(Word)) - 1) & -sizeof (ElfW(Word)))
+- ElfW(Addr) note_size = 3 * sizeof (ElfW(Word))
++#define ROUND(len) (((len) + sizeof (Elf64_Word) - 1) & -sizeof (Elf64_Word))
++ Elf64_Addr note_size = 3 * sizeof (Elf64_Word)
+ + ROUND (abi_note[0])
+ + ROUND (abi_note[1]);
+
+@@ -166,7 +339,7 @@ process_elf_file (const char *file_name,
+ }
+
+ }
+- if (loadaddr == (ElfW(Addr)) -1)
++ if (loadaddr == (Elf64_Addr) -1)
+ {
+ /* Very strange. */
+ loadaddr = 0;
+@@ -176,7 +349,7 @@ process_elf_file (const char *file_name,
+ if (dynamic_size == 0)
+ return 1;
+
+- dynamic_segment = (ElfW(Dyn) *) (file_contents + dynamic_addr);
++ dynamic_segment = (Elf64_Dyn *) (file_contents + dynamic_addr);
+ check_ptr (dynamic_segment);
+
+ /* Find the string table. */
+@@ -233,3 +406,33 @@ process_elf_file (const char *file_name,
+
+ return 0;
+ }
++/* Returns 0 if everything is ok, != 0 in case of error. */
++int
++process_elf_file (const char *file_name, const char *lib, int *flag,
++ unsigned int *osversion, char **soname, void *file_contents,
++ size_t file_length)
++{
++ int i;
++ unsigned int j;
++ ElfW(Addr) loadaddr;
++ unsigned int dynamic_addr;
++ size_t dynamic_size;
++ char *program_interpreter;
++
++ ElfW(Ehdr) *elf_header;
++ ElfW(Phdr) *elf_pheader, *segment;
++ ElfW(Dyn) *dynamic_segment, *dyn_entry;
++ char *dynamic_strings;
++
++ elf_header = (ElfW(Ehdr) *) file_contents;
++ *osversion = 0;
++
++ if (elf_header->e_ident [EI_CLASS] == ELFCLASS32)
++ return process_elf_file32(file_name, lib,flag, osversion, soname, file_contents, file_length);
++ else if (elf_header->e_ident [EI_CLASS] == ELFCLASS64)
++ return process_elf_file64(file_name, lib,flag, osversion, soname, file_contents, file_length);
++ error (0, 0, _("Unknown ELFCLASS in file %s.\n"), file_name);
++ return 1;
++}
++
++
diff --git a/recipes-core/glibc/ldconfig-native-2.12.1/README b/recipes-core/glibc/ldconfig-native-2.12.1/README
new file mode 100644
index 0000000..43fb983
--- /dev/null
+++ b/recipes-core/glibc/ldconfig-native-2.12.1/README
@@ -0,0 +1,8 @@
+The files are pulled verbatim from glibc 2.5 and then patched to allow
+standalone compilation of ldconfig.
+
+Richard Purdie
+OpenedHand Ltd.
+
+Upgraded the ldconfig recipe to eglibc 2.12.1
+Nitin A Kamble <nitin.a.kamble at intel.com> 2011/03/29
diff --git a/recipes-core/glibc/ldconfig-native-2.12.1/endian-ness_handling.patch b/recipes-core/glibc/ldconfig-native-2.12.1/endian-ness_handling.patch
new file mode 100644
index 0000000..7f8e4db
--- /dev/null
+++ b/recipes-core/glibc/ldconfig-native-2.12.1/endian-ness_handling.patch
@@ -0,0 +1,454 @@
+Upstream-Status: Inappropriate [embedded specific]
+
+Do data input/output handling according to endien-ness of the library file. That
+enables use of ldconfig in the cross fashion for any architecture.
+
+2011/04/04
+Richard Purdie <richard.purdie at linuxfoundation.org>
+Nitin Kamble <nitin.a.kamble at intel.com>
+
+Index: ldconfig-native-2.12.1/readelflib.c
+===================================================================
+--- ldconfig-native-2.12.1.orig/readelflib.c
++++ ldconfig-native-2.12.1/readelflib.c
+@@ -38,6 +38,28 @@ do \
+ } \
+ while (0);
+
++int be;
++static uint16_t read16(uint16_t x, int be)
++{
++ if (be)
++ return be16toh(x);
++ return le16toh(x);
++}
++
++static uint32_t read32(uint32_t x, int be)
++{
++ if (be)
++ return be32toh(x);
++ return le32toh(x);
++}
++
++static uint64_t read64(uint64_t x, int be)
++{
++ if (be)
++ return be64toh(x);
++ return le64toh(x);
++}
++
+ /* Returns 0 if everything is ok, != 0 in case of error. */
+ int
+ process_elf_file32 (const char *file_name, const char *lib, int *flag,
+@@ -59,15 +81,17 @@ process_elf_file32 (const char *file_nam
+ elf_header = (Elf32_Ehdr *) file_contents;
+ *osversion = 0;
+
+- if (elf_header->e_type != ET_DYN)
++ be = (elf_header->e_ident[EI_DATA] == ELFDATA2MSB);
++
++ if (read16(elf_header->e_type, be) != ET_DYN)
+ {
+ error (0, 0, _("%s is not a shared object file (Type: %d).\n"), file_name,
+- elf_header->e_type);
++ read16(elf_header->e_type, be));
+ return 1;
+ }
+
+ /* Get information from elf program header. */
+- elf_pheader = (Elf32_Phdr *) (elf_header->e_phoff + file_contents);
++ elf_pheader = (Elf32_Phdr *) (read32(elf_header->e_phoff, be) + file_contents);
+ check_ptr (elf_pheader);
+
+ /* The library is an elf library, now search for soname and
+@@ -79,27 +103,27 @@ process_elf_file32 (const char *file_nam
+ dynamic_size = 0;
+ program_interpreter = NULL;
+ for (i = 0, segment = elf_pheader;
+- i < elf_header->e_phnum; i++, segment++)
++ i < read16(elf_header->e_phnum, be); i++, segment++)
+ {
+ check_ptr (segment);
+
+- switch (segment->p_type)
++ switch (read32(segment->p_type, be))
+ {
+ case PT_LOAD:
+ if (loadaddr == (Elf32_Addr) -1)
+- loadaddr = segment->p_vaddr - segment->p_offset;
++ loadaddr = read32(segment->p_vaddr, be) - read32(segment->p_offset, be);
+ break;
+
+ case PT_DYNAMIC:
+ if (dynamic_addr)
+ error (0, 0, _("more than one dynamic segment\n"));
+
+- dynamic_addr = segment->p_offset;
+- dynamic_size = segment->p_filesz;
++ dynamic_addr = read32(segment->p_offset, be);
++ dynamic_size = read32(segment->p_filesz, be);
+ break;
+
+ case PT_INTERP:
+- program_interpreter = (char *) (file_contents + segment->p_offset);
++ program_interpreter = (char *) (file_contents + read32(segment->p_offset, be));
+ check_ptr (program_interpreter);
+
+ /* Check if this is enough to classify the binary. */
+@@ -113,20 +137,20 @@ process_elf_file32 (const char *file_nam
+ break;
+
+ case PT_NOTE:
+- if (!*osversion && segment->p_filesz >= 32 && segment->p_align >= 4)
++ if (!*osversion && read32(segment->p_filesz, be) >= 32 && segment->p_align >= 4)
+ {
+ Elf32_Word *abi_note = (Elf32_Word *) (file_contents
+- + segment->p_offset);
+- Elf32_Addr size = segment->p_filesz;
++ + read32(segment->p_offset, be));
++ Elf32_Addr size = read32(segment->p_filesz, be);
+
+- while (abi_note [0] != 4 || abi_note [1] != 16
+- || abi_note [2] != 1
++ while (read32(abi_note [0], be) != 4 || read32(abi_note [1], be) != 16
++ || read32(abi_note [2], be) != 1
+ || memcmp (abi_note + 3, "GNU", 4) != 0)
+ {
+-#define ROUND(len) (((len) + sizeof (Elf32_Word)) - 1) & -sizeof (Elf32_Word)))
+- Elf32_Addr) note_size = 3 * sizeof (Elf32_Word))
+- + ROUND (abi_note[0])
+- + ROUND (abi_note[1]);
++#define ROUND(len) (((len) + sizeof (Elf32_Word) - 1) & -sizeof (Elf32_Word))
++ Elf32_Addr note_size = 3 * sizeof (Elf32_Word)
++ + ROUND (read32(abi_note[0], be))
++ + ROUND (read32(abi_note[1], be));
+
+ if (size - 32 < note_size || note_size == 0)
+ {
+@@ -140,10 +164,10 @@ process_elf_file32 (const char *file_nam
+ if (size == 0)
+ break;
+
+- *osversion = (abi_note [4] << 24) |
+- ((abi_note [5] & 0xff) << 16) |
+- ((abi_note [6] & 0xff) << 8) |
+- (abi_note [7] & 0xff);
++ *osversion = (read32(abi_note [4], be) << 24) |
++ ((read32(abi_note [5], be) & 0xff) << 16) |
++ ((read32(abi_note [6], be) & 0xff) << 8) |
++ (read32(abi_note [7], be) & 0xff);
+ }
+ break;
+
+@@ -167,13 +191,13 @@ process_elf_file32 (const char *file_nam
+
+ /* Find the string table. */
+ dynamic_strings = NULL;
+- for (dyn_entry = dynamic_segment; dyn_entry->d_tag != DT_NULL;
++ for (dyn_entry = dynamic_segment; read32(dyn_entry->d_tag, be) != DT_NULL;
+ ++dyn_entry)
+ {
+ check_ptr (dyn_entry);
+- if (dyn_entry->d_tag == DT_STRTAB)
++ if (read32(dyn_entry->d_tag, be) == DT_STRTAB)
+ {
+- dynamic_strings = (char *) (file_contents + dyn_entry->d_un.d_val - loadaddr);
++ dynamic_strings = (char *) (file_contents + read32(dyn_entry->d_un.d_val, be) - loadaddr);
+ check_ptr (dynamic_strings);
+ break;
+ }
+@@ -183,15 +207,15 @@ process_elf_file32 (const char *file_nam
+ return 1;
+
+ /* Now read the DT_NEEDED and DT_SONAME entries. */
+- for (dyn_entry = dynamic_segment; dyn_entry->d_tag != DT_NULL;
++ for (dyn_entry = dynamic_segment; read32(dyn_entry->d_tag, be) != DT_NULL;
+ ++dyn_entry)
+ {
+- if (dyn_entry->d_tag == DT_NEEDED || dyn_entry->d_tag == DT_SONAME)
++ if (read32(dyn_entry->d_tag, be) == DT_NEEDED || read32(dyn_entry->d_tag, be) == DT_SONAME)
+ {
+- char *name = dynamic_strings + dyn_entry->d_un.d_val;
++ char *name = dynamic_strings + read32(dyn_entry->d_un.d_val, be);
+ check_ptr (name);
+
+- if (dyn_entry->d_tag == DT_NEEDED)
++ if (read32(dyn_entry->d_tag, be) == DT_NEEDED)
+ {
+
+ if (*flag == FLAG_ELF)
+@@ -208,7 +232,7 @@ process_elf_file32 (const char *file_nam
+ }
+ }
+
+- else if (dyn_entry->d_tag == DT_SONAME)
++ else if (read32(dyn_entry->d_tag, be) == DT_SONAME)
+ *soname = xstrdup (name);
+
+ /* Do we have everything we need? */
+@@ -246,15 +270,17 @@ process_elf_file64 (const char *file_nam
+ elf_header = (Elf64_Ehdr *) file_contents;
+ *osversion = 0;
+
+- if (elf_header->e_type != ET_DYN)
++ be = (elf_header->e_ident[EI_DATA] == ELFDATA2MSB);
++
++ if (read16(elf_header->e_type, be) != ET_DYN)
+ {
+ error (0, 0, _("%s is not a shared object file (Type: %d).\n"), file_name,
+- elf_header->e_type);
++ read16(elf_header->e_type, be));
+ return 1;
+ }
+
+ /* Get information from elf program header. */
+- elf_pheader = (Elf64_Phdr *) (elf_header->e_phoff + file_contents);
++ elf_pheader = (Elf64_Phdr *) (read64(elf_header->e_phoff, be) + file_contents);
+ check_ptr (elf_pheader);
+
+ /* The library is an elf library, now search for soname and
+@@ -266,27 +292,27 @@ process_elf_file64 (const char *file_nam
+ dynamic_size = 0;
+ program_interpreter = NULL;
+ for (i = 0, segment = elf_pheader;
+- i < elf_header->e_phnum; i++, segment++)
++ i < read16(elf_header->e_phnum, be); i++, segment++)
+ {
+ check_ptr (segment);
+
+- switch (segment->p_type)
++ switch (read32(segment->p_type, be))
+ {
+ case PT_LOAD:
+ if (loadaddr == (Elf64_Addr) -1)
+- loadaddr = segment->p_vaddr - segment->p_offset;
++ loadaddr = read64(segment->p_vaddr, be) - read64(segment->p_offset, be);
+ break;
+
+ case PT_DYNAMIC:
+ if (dynamic_addr)
+ error (0, 0, _("more than one dynamic segment\n"));
+
+- dynamic_addr = segment->p_offset;
+- dynamic_size = segment->p_filesz;
++ dynamic_addr = read64(segment->p_offset, be);
++ dynamic_size = read32(segment->p_filesz, be);
+ break;
+
+ case PT_INTERP:
+- program_interpreter = (char *) (file_contents + segment->p_offset);
++ program_interpreter = (char *) (file_contents + read64(segment->p_offset, be));
+ check_ptr (program_interpreter);
+
+ /* Check if this is enough to classify the binary. */
+@@ -300,20 +326,21 @@ process_elf_file64 (const char *file_nam
+ break;
+
+ case PT_NOTE:
+- if (!*osversion && segment->p_filesz >= 32 && segment->p_align >= 4)
++ if (!*osversion && read32(segment->p_filesz, be) >= 32 && read32(segment->p_align, be) >= 4)
+ {
+ Elf64_Word *abi_note = (Elf64_Word *) (file_contents
+- + segment->p_offset);
+- Elf64_Addr size = segment->p_filesz;
++ + read64(segment->p_offset, be));
++ Elf64_Addr size = read32(segment->p_filesz, be);
+
+- while (abi_note [0] != 4 || abi_note [1] != 16
+- || abi_note [2] != 1
++ while (read32(abi_note [0], be) != 4 || read32(abi_note [1], be) != 16
++ || read32(abi_note [2], be) != 1
+ || memcmp (abi_note + 3, "GNU", 4) != 0)
+ {
++#undef ROUND
+ #define ROUND(len) (((len) + sizeof (Elf64_Word) - 1) & -sizeof (Elf64_Word))
+ Elf64_Addr note_size = 3 * sizeof (Elf64_Word)
+- + ROUND (abi_note[0])
+- + ROUND (abi_note[1]);
++ + ROUND (read32(abi_note[0], be))
++ + ROUND (read32(abi_note[1], be));
+
+ if (size - 32 < note_size || note_size == 0)
+ {
+@@ -327,10 +354,10 @@ process_elf_file64 (const char *file_nam
+ if (size == 0)
+ break;
+
+- *osversion = (abi_note [4] << 24) |
+- ((abi_note [5] & 0xff) << 16) |
+- ((abi_note [6] & 0xff) << 8) |
+- (abi_note [7] & 0xff);
++ *osversion = (read32(abi_note [4], be) << 24) |
++ ((read32(abi_note [5], be) & 0xff) << 16) |
++ ((read32(abi_note [6], be) & 0xff) << 8) |
++ (read32(abi_note [7], be) & 0xff);
+ }
+ break;
+
+@@ -354,13 +381,13 @@ process_elf_file64 (const char *file_nam
+
+ /* Find the string table. */
+ dynamic_strings = NULL;
+- for (dyn_entry = dynamic_segment; dyn_entry->d_tag != DT_NULL;
++ for (dyn_entry = dynamic_segment; read64(dyn_entry->d_tag, be) != DT_NULL;
+ ++dyn_entry)
+ {
+ check_ptr (dyn_entry);
+- if (dyn_entry->d_tag == DT_STRTAB)
++ if (read64(dyn_entry->d_tag, be) == DT_STRTAB)
+ {
+- dynamic_strings = (char *) (file_contents + dyn_entry->d_un.d_val - loadaddr);
++ dynamic_strings = (char *) (file_contents + read64(dyn_entry->d_un.d_val, be) - loadaddr);
+ check_ptr (dynamic_strings);
+ break;
+ }
+@@ -370,15 +397,15 @@ process_elf_file64 (const char *file_nam
+ return 1;
+
+ /* Now read the DT_NEEDED and DT_SONAME entries. */
+- for (dyn_entry = dynamic_segment; dyn_entry->d_tag != DT_NULL;
++ for (dyn_entry = dynamic_segment; read64(dyn_entry->d_tag, be) != DT_NULL;
+ ++dyn_entry)
+ {
+- if (dyn_entry->d_tag == DT_NEEDED || dyn_entry->d_tag == DT_SONAME)
++ if (read64(dyn_entry->d_tag, be) == DT_NEEDED || read64(dyn_entry->d_tag, be) == DT_SONAME)
+ {
+- char *name = dynamic_strings + dyn_entry->d_un.d_val;
++ char *name = dynamic_strings + read64(dyn_entry->d_un.d_val, be);
+ check_ptr (name);
+
+- if (dyn_entry->d_tag == DT_NEEDED)
++ if (read64(dyn_entry->d_tag, be) == DT_NEEDED)
+ {
+
+ if (*flag == FLAG_ELF)
+@@ -395,7 +422,7 @@ process_elf_file64 (const char *file_nam
+ }
+ }
+
+- else if (dyn_entry->d_tag == DT_SONAME)
++ else if (read64(dyn_entry->d_tag, be) == DT_SONAME)
+ *soname = xstrdup (name);
+
+ /* Do we have everything we need? */
+Index: ldconfig-native-2.12.1/readlib.c
+===================================================================
+--- ldconfig-native-2.12.1.orig/readlib.c
++++ ldconfig-native-2.12.1/readlib.c
+@@ -169,7 +169,8 @@ process_file (const char *real_file_name
+ ret = 1;
+ }
+ /* Libraries have to be shared object files. */
+- else if (elf_header->e_type != ET_DYN)
++ else if ((elf_header->e_ident[EI_DATA] == ELFDATA2MSB && be16toh(elf_header->e_type) != ET_DYN) ||
++ (elf_header->e_ident[EI_DATA] == ELFDATA2LSB && le16toh(elf_header->e_type) != ET_DYN))
+ ret = 1;
+ else if (process_elf_file (file_name, lib, flag, osversion, soname,
+ file_contents, statbuf.st_size))
+Index: ldconfig-native-2.12.1/cache.c
+===================================================================
+--- ldconfig-native-2.12.1.orig/cache.c
++++ ldconfig-native-2.12.1/cache.c
+@@ -39,6 +39,29 @@
+ # define N_(msgid) msgid
+ #define _(msg) msg
+
++extern int be;
++
++static uint16_t write16(uint16_t x, int be)
++{
++ if (be)
++ return htobe16(x);
++ return htole16(x);
++}
++
++static uint32_t write32(uint32_t x, int be)
++{
++ if (be)
++ return htobe32(x);
++ return htole32(x);
++}
++
++static uint64_t write64(uint64_t x, int be)
++{
++ if (be)
++ return htobe64(x);
++ return htole64(x);
++}
++
+ struct cache_entry
+ {
+ char *lib; /* Library name. */
+@@ -279,7 +302,12 @@ save_cache (const char *cache_name)
+ /* Number of normal cache entries. */
+ int cache_entry_old_count = 0;
+
+- for (entry = entries; entry != NULL; entry = entry->next)
++ if (be)
++ printf("saving cache in big endian encoding\n");
++ else
++ printf("saving cache in little endian encoding\n");
++
++ for (entry = entries; entry != NULL; entry = entry->next)
+ {
+ /* Account the final NULs. */
+ total_strlen += strlen (entry->lib) + strlen (entry->path) + 2;
+@@ -310,7 +338,7 @@ save_cache (const char *cache_name)
+ memset (file_entries, '\0', sizeof (struct cache_file));
+ memcpy (file_entries->magic, CACHEMAGIC, sizeof CACHEMAGIC - 1);
+
+- file_entries->nlibs = cache_entry_old_count;
++ file_entries->nlibs = write32(cache_entry_old_count, be);
+ }
+
+ struct cache_file_new *file_entries_new = NULL;
+@@ -330,8 +358,8 @@ save_cache (const char *cache_name)
+ memcpy (file_entries_new->version, CACHE_VERSION,
+ sizeof CACHE_VERSION - 1);
+
+- file_entries_new->nlibs = cache_entry_count;
+- file_entries_new->len_strings = total_strlen;
++ file_entries_new->nlibs = write32(cache_entry_count, be);
++ file_entries_new->len_strings = write32(total_strlen, be);
+ }
+
+ /* Pad for alignment of cache_file_new. */
+@@ -358,9 +386,9 @@ save_cache (const char *cache_name)
+ /* First the library. */
+ if (opt_format != 2 && entry->hwcap == 0)
+ {
+- file_entries->libs[idx_old].flags = entry->flags;
++ file_entries->libs[idx_old].flags = write32(entry->flags, be);
+ /* XXX: Actually we can optimize here and remove duplicates. */
+- file_entries->libs[idx_old].key = str_offset + pad;
++ file_entries->libs[idx_old].key = write32(str_offset + pad, be);
+ }
+ if (opt_format != 0)
+ {
+@@ -368,10 +396,10 @@ save_cache (const char *cache_name)
+ not doing so makes the code easier, the string table
+ always begins at the beginning of the the new cache
+ struct. */
+- file_entries_new->libs[idx_new].flags = entry->flags;
+- file_entries_new->libs[idx_new].osversion = entry->osversion;
+- file_entries_new->libs[idx_new].hwcap = entry->hwcap;
+- file_entries_new->libs[idx_new].key = str_offset;
++ file_entries_new->libs[idx_new].flags = write32(entry->flags, be);
++ file_entries_new->libs[idx_new].osversion = write32(entry->osversion, be);
++ file_entries_new->libs[idx_new].hwcap = write64(entry->hwcap, be);
++ file_entries_new->libs[idx_new].key = write32(str_offset, be);
+ }
+
+ size_t len = strlen (entry->lib) + 1;
+@@ -379,9 +407,9 @@ save_cache (const char *cache_name)
+ str_offset += len;
+ /* Then the path. */
+ if (opt_format != 2 && entry->hwcap == 0)
+- file_entries->libs[idx_old].value = str_offset + pad;
++ file_entries->libs[idx_old].value = write32(str_offset + pad, be);
+ if (opt_format != 0)
+- file_entries_new->libs[idx_new].value = str_offset;
++ file_entries_new->libs[idx_new].value = write32(str_offset, be);
+ len = strlen (entry->path) + 1;
+ str = mempcpy (str, entry->path, len);
+ str_offset += len;
diff --git a/recipes-core/glibc/ldconfig-native-2.12.1/endian-ness_handling_fix.patch b/recipes-core/glibc/ldconfig-native-2.12.1/endian-ness_handling_fix.patch
new file mode 100644
index 0000000..6aecfe5
--- /dev/null
+++ b/recipes-core/glibc/ldconfig-native-2.12.1/endian-ness_handling_fix.patch
@@ -0,0 +1,47 @@
+Upstream-Status: Inappropriate [embedded specific]
+
+Fix problem during parsing of ELF headers for 64bit on big-endian.
+Some header fields were read with wrong size.
+
+2014/10/24
+Par Olsson <Par.Olsson at windriver.com>
+Shan Hai <shan.hai at windriver.com>
+
+diff --git a/readelflib.c b/readelflib.c
+index 3f5b25b..0bf0de3 100644
+--- a/readelflib.c
++++ b/readelflib.c
+@@ -261,8 +261,8 @@ process_elf_file64 (const char *file_name, const char *lib, int *flag,
+ int i;
+ unsigned int j;
+ Elf64_Addr loadaddr;
+- unsigned int dynamic_addr;
+- size_t dynamic_size;
++ Elf64_Addr dynamic_addr;
++ Elf64_Xword dynamic_size;
+ char *program_interpreter;
+
+ Elf64_Ehdr *elf_header;
+@@ -311,7 +311,7 @@ process_elf_file64 (const char *file_name, const char *lib, int *flag,
+ error (0, 0, _("more than one dynamic segment\n"));
+
+ dynamic_addr = read64(segment->p_offset, be);
+- dynamic_size = read32(segment->p_filesz, be);
++ dynamic_size = read64(segment->p_filesz, be);
+ break;
+
+ case PT_INTERP:
+@@ -329,11 +329,11 @@ process_elf_file64 (const char *file_name, const char *lib, int *flag,
+ break;
+
+ case PT_NOTE:
+- if (!*osversion && read32(segment->p_filesz, be) >= 32 && read32(segment->p_align, be) >= 4)
++ if (!*osversion && read64(segment->p_filesz, be) >= 32 && read64(segment->p_align, be) >= 4)
+ {
+ Elf64_Word *abi_note = (Elf64_Word *) (file_contents
+ + read64(segment->p_offset, be));
+- Elf64_Addr size = read32(segment->p_filesz, be);
++ Elf64_Xword size = read64(segment->p_filesz, be);
+
+ while (read32(abi_note [0], be) != 4 || read32(abi_note [1], be) != 16
+ || read32(abi_note [2], be) != 1
diff --git a/recipes-core/glibc/ldconfig-native-2.12.1/endianess-header.patch b/recipes-core/glibc/ldconfig-native-2.12.1/endianess-header.patch
new file mode 100644
index 0000000..a18b2c2
--- /dev/null
+++ b/recipes-core/glibc/ldconfig-native-2.12.1/endianess-header.patch
@@ -0,0 +1,113 @@
+Upstream-Status: Inappropriate [fix poky patch]
+
+This patch fixes build issues with a previous endian-ness_handling.patch on
+distros that don't have macros referenced
+
+7/20/2011
+Matthew McClintock <msm at freescale.com>
+
+diff -purN ldconfig-native-2.12.1.orig/endian_extra.h ldconfig-native-2.12.1/endian_extra.h
+--- ldconfig-native-2.12.1.orig/endian_extra.h 1969-12-31 18:00:00.000000000 -0600
++++ ldconfig-native-2.12.1/endian_extra.h 2011-07-19 18:09:14.323048417 -0500
+@@ -0,0 +1,64 @@
++/* Copyright (C) 1992, 1996, 1997, 2000, 2008 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 <endian.h>
++
++#ifndef _ENDIAN_EXTRA_H
++#define _ENDIAN_EXTRA_H 1
++
++/* Don't redefine these macros if they already exist */
++#ifndef htobe16
++#ifdef __USE_BSD
++/* Conversion interfaces. */
++# include <byteswap.h>
++
++# if __BYTE_ORDER == __LITTLE_ENDIAN
++# define htobe16(x) __bswap_16 (x)
++# define htole16(x) (x)
++# define be16toh(x) __bswap_16 (x)
++# define le16toh(x) (x)
++
++# define htobe32(x) __bswap_32 (x)
++# define htole32(x) (x)
++# define be32toh(x) __bswap_32 (x)
++# define le32toh(x) (x)
++
++# define htobe64(x) __bswap_64 (x)
++# define htole64(x) (x)
++# define be64toh(x) __bswap_64 (x)
++# define le64toh(x) (x)
++# else
++# define htobe16(x) (x)
++# define htole16(x) __bswap_16 (x)
++# define be16toh(x) (x)
++# define le16toh(x) __bswap_16 (x)
++
++# define htobe32(x) (x)
++# define htole32(x) __bswap_32 (x)
++# define be32toh(x) (x)
++# define le32toh(x) __bswap_32 (x)
++
++# define htobe64(x) (x)
++# define htole64(x) __bswap_64 (x)
++# define be64toh(x) (x)
++# define le64toh(x) __bswap_64 (x)
++# endif
++#endif
++#endif
++
++#endif /* endian_extra.h */
+diff -purN ldconfig-native-2.12.1.orig/cache.c ldconfig-native-2.12.1/cache.c
+--- ldconfig-native-2.12.1.orig/cache.c 2011-07-19 18:21:28.347041301 -0500
++++ ldconfig-native-2.12.1/cache.c 2011-07-19 18:22:54.118048064 -0500
+@@ -39,6 +39,8 @@
+ # define N_(msgid) msgid
+ #define _(msg) msg
+
++#include "endian_extra.h"
++
+ extern int be;
+
+ static uint16_t write16(uint16_t x, int be)
+diff -purN ldconfig-native-2.12.1.orig/readelflib.c ldconfig-native-2.12.1/readelflib.c
+--- ldconfig-native-2.12.1.orig/readelflib.c 2011-07-19 18:21:28.346041593 -0500
++++ ldconfig-native-2.12.1/readelflib.c 2011-07-19 18:23:05.324059875 -0500
+@@ -25,6 +25,9 @@
+
+ /* check_ptr checks that a pointer is in the mmaped file and doesn't
+ point outside it. */
++
++#include "endian_extra.h"
++
+ #undef check_ptr
+ #define check_ptr(ptr) \
+ do \
+diff -purN ldconfig-native-2.12.1.orig/readlib.c ldconfig-native-2.12.1/readlib.c
+--- ldconfig-native-2.12.1.orig/readlib.c 2011-07-19 18:21:28.346041593 -0500
++++ ldconfig-native-2.12.1/readlib.c 2011-07-19 18:23:23.877046210 -0500
+@@ -40,6 +40,8 @@
+
+ #include "ldconfig.h"
+
++#include "endian_extra.h"
++
+ #define _(msg) msg
+
+ #define Elf32_CLASS ELFCLASS32
diff --git a/recipes-core/glibc/ldconfig-native-2.12.1/flag_fix.patch b/recipes-core/glibc/ldconfig-native-2.12.1/flag_fix.patch
new file mode 100644
index 0000000..4e9aab9
--- /dev/null
+++ b/recipes-core/glibc/ldconfig-native-2.12.1/flag_fix.patch
@@ -0,0 +1,24 @@
+Upstream-Status: Inappropriate [embedded specific]
+
+The native version of ldconfig was using native definition of LD_SO (i.e.
+ld-linux-x86-64.so.2 ) which is not correct for doing the cross ldconfig.
+This was causing libc.so on the target marked as ELF lib rather than
+FLAG_ELF_LIBC6 in the ld.so.cache.
+
+Nitin A Kamble <nitin.a.kamble at intel.com> 2011/04/4
+
+Index: ldconfig-native-2.12.1/readlib.c
+===================================================================
+--- ldconfig-native-2.12.1.orig/readlib.c
++++ ldconfig-native-2.12.1/readlib.c
+@@ -51,6 +51,10 @@ struct known_names
+ int flag;
+ };
+
++/* don't use host's definition of LD_SO */
++#undef LD_SO
++#define LD_SO "ld.so.1"
++
+ static struct known_names interpreters[] =
+ {
+ { "/lib/" LD_SO, FLAG_ELF_LIBC6 },
diff --git a/recipes-core/glibc/ldconfig-native-2.12.1/ldconfig-default-to-all-multilib-dirs.patch b/recipes-core/glibc/ldconfig-native-2.12.1/ldconfig-default-to-all-multilib-dirs.patch
new file mode 100644
index 0000000..5ed4f6f
--- /dev/null
+++ b/recipes-core/glibc/ldconfig-native-2.12.1/ldconfig-default-to-all-multilib-dirs.patch
@@ -0,0 +1,37 @@
+Upstream-Status: Inappropriate [embedded specific]
+
+make ldconfig default to both /lib+/usr/lib, /lib32+/usr/lib32 and
+/lib64+/usr/lib64 on bi-ABI architectures.
+
+---
+ ldconfig.c | 10 ++++++++++
+ 1 file changed, 10 insertions(+)
+
+diff -urpN a/ldconfig.c b/ldconfig.c
+--- a/ldconfig.c
++++ b/ldconfig.c
+@@ -52,7 +52,11 @@
+
+ #define SYSCONFDIR "/etc"
+ #define LIBDIR "/usr/lib"
++#define LIBDIR32 "/usr/lib32"
++#define LIBDIR64 "/usr/lib64"
+ #define SLIBDIR "/lib"
++#define SLIBDIR32 "/lib32"
++#define SLIBDIR64 "/lib64"
+ # define N_(msgid) msgid
+ #define _(msg) msg
+
+@@ -1373,6 +1377,12 @@ main (int argc, char **argv)
+ add_system_dir (SLIBDIR);
+ if (strcmp (SLIBDIR, LIBDIR))
+ add_system_dir (LIBDIR);
++ add_system_dir (SLIBDIR32);
++ if (strcmp (SLIBDIR32, LIBDIR32))
++ add_system_dir (LIBDIR32);
++ add_system_dir (SLIBDIR64);
++ if (strcmp (SLIBDIR64, LIBDIR64))
++ add_system_dir (LIBDIR64);
+ }
+
+ const char *aux_cache_file = _PATH_LDCONFIG_AUX_CACHE;
diff --git a/recipes-core/glibc/ldconfig-native-2.12.1/ldconfig-native-2.12.1.tar.bz2 b/recipes-core/glibc/ldconfig-native-2.12.1/ldconfig-native-2.12.1.tar.bz2
new file mode 100644
index 0000000000000000000000000000000000000000..dc1e79888e9bf28226cf18513ebd4478ec90175f
GIT binary patch
literal 21491
zcmV()K;OSYT4*^jL0KkKSzNplS^$e*|NsB+0D*h||NsC0|NsC0|Nj6$0t5gA00962
z004jx00>}o9{1DbKmvVzDYv|Oo at Idd)&QPl`WXNy6zLn^T+aJFJ at xJHcJ(j5^}OEz
z8{PFaqTAjmX}$Aq(Durg+s;0^QlCt=)lQn~!262meCXQ+o>U5bXs3 at iDt%-d-(Pv~
zKH2X0ci!{X_ulRAWG!S;gi;&5LVd*9)33dyT}f1d6e)Im&wI)?we`!~-S01U_15Z|
z*{;rZvtFJO<IZVZ4c)eOS6$CXU<cEy*{_G*<Z!PZ`+DuCmt&VKYwl$^t%^(A9p2sQ
znR&kZ$9o at l7V6h^w_Wb<eYZY#+?lQ at pmomK%b`x(aXRa=mpGlTuDyZjSAE*=c5r+t
z+P$8uJ9};1_Vvv1L(|i)*KGH9Ofy?Hw$c|px4gtL5GH^?35W>Mq|u6cnUOOpeu*}d
z%}Rc$>66lfAZYb81_3FcLI_O+CL(PDqx4hsru9eYBzlMHPt_h!+DE7W7>0lV2{ef!
zOp_A|dNN6<{HgeYPe^)Al)(eh1JnVdKzdCEngO6fk`W1lWK+{dO-G=ZihB`H$xVpV
z at uVivsp&L&BSwG#03t|&WHca5fJw4wCQ^RXdYWpU(KSC&<caD(RKjgfYMKCghol;L
zK at uV+flLEYrh!jNc~g3A6pvB)4JIk&1NA0=c}J)K004dH>->MK`=bcS=f9vIRwbb_
zMw%EY4A4NyLEaa=4n8~J4}kb<IOEWz2Tc4x^OSdMEZZ0J-wWZ4Rp$k1S at G3S;%^uX
z;zp6HBtghfOqE9z92Xr(4g(*^LMfz#Q&7+dtPBPs5V948BLHepAP1lEdXK2cew$63
z{8w_9Lc+hk)PIovTypfsCWHEahni-cz|_{XU>h8cS=XOF=sO>h&LBG`l_~{6D8=YY
zw`3F)Mhrn>kx?n3n4%gt%)f1$F__tidOwTN=>1z9blk{-B7%m5C<rK;D5Yr_sflI;
zf)R#^h=!^_kL>?uCx-YKe{MRC?Q+ooOj3mcQj}E%4HVHuRWU^oOw?5rG$}<T1rWp%
z4J}bZQZ$WFOq2xzP}4v$G!RuuQwE&I3MeFqsu-zou!M;q>x_#mT$apEim!g^`#(<y
z67s{Q)iOYnEmbiz(^S<{RRq*PL at Pl70+A39Ddzs!`aJ)h=ds7DqW%moJ%)b-CJ2Tn
z^3R)0HTbYT?w&k7{L}mCQPQP#&P at a3_FvPb6T(xj&Y3N2chvLll<S1M3cJHpF6wd@
zgmicgZXE?_0O&@XadyaWbXngg1WdK9y|7cHDixZ6K?2AWfq at c06oq?sc248&W{2*}
zp6yxcpw+2*y at mO2DY=7`Lw~*2atx`q=0?HxIP0ZzGT^;)n5McWT*&)Qc{JZ2`rg5#
z!3Cn=ZgHRDy7cSe{Q2LUZf8g=${~W%&ldfN4Pg&!!?0YXl`EFaNpjX{mgGC(ap8e&
zl<N$7<`*7i=3tDM4jHPv+}}?Oq|}dMAz|tZPAn-znFQ_bFuneqf6^Ys_ at nNB=MN2i
zkqHbls{lW?i_4r69K`Yl7DSb>ML-A;-PggxP(mIO?bi7J9vknneZDyjdZ{RZtWBqH
zZu+Gu0+yZ4!`z0cDk at r2vNC&PDnm0OQ&EjO#$Nt86uq)J2}=_<Ut*q^2SKr2_+mv1
zZ9E#Nj96n;Shm#_WI<-BqM(CTH563?6h#FBqNF=NAHwyIjrQ8_M-9xKuis7 at B~Z4v
zhYtj4(~MffP{Om0a<->*DGnt{0}fiphNl%en73woOd2%p;G!KNIQ4r$KUJ9z<<ok*
zN#mwr9*pjRBVtp7@{VvPnhcDP$#n*&QIaN9v;{FB(p6rZ4b(i66-5C;(83lFIs}3W
z7wEm at pPS{sUDIbBYwV-r_2a>KbzNcUuO3>f^xEfF0eUI#atfv`6kBcR_Gf>RmpR?u
z+K?70q|MyJS}CoD>0{uih>9v|6^07Bg=Z|(sPL*@VU_{`o4J>s!MeJbWR|L9$9oQ(
zX|=sH$5>l&>dx9 at oa0*V=PqGRHe-SbhRV!Lr#VM--6{y0(K{iJ9Ar1Hi=8rwH*qf<
zC^$l4{wfOJn at fmDP0<<Ya`nOcfoy*wIziSDbDt(7Uik6*)6^%4Oj9*A&nPXBclBaA
zBy<C#{`^N9tl17z1 at H3TGA0>aFZ^WEBMC}7#{@Jc7Eedr_+ch6!C5&FHC}F94bH}3
zrXTGY!vk?D<)MOQGSdjFD{eG085mV$u2H8-LX4)Q#%Q*RShcHzDq!|;!LraOS|hnw
zu2tNtjHFc_HMy80IMib8)n*e?<Sf*|Fd3yR8$@E!D$_9=Qp%ZS$9Cvo!mKMT%*bk4
zQ!<Hj5dwl#R}{FnFd7zXu5Dr<hEXY&;w(p8!)6`L?kONbL5w7rb$s9T>i>5SZdyFv
z*ynlk3)_<YUU%|#Bkn>9&syJS){g~#8zv!`Vi;)idOB|7^s7{)5Z|W?SJLZF`#Q&O
zICl0Qw{4<Fi{{Mn#MZH-AetW-%7Tt?21~5I;rDYw2j+#zM`@Y!bf?;T;r4QG`0&l_
zcg~W=*21SpB`{gmy0>YA5f)z_LZYaQk4>nwNU23d1jSUD?75u7+z+NUWA9Z#)_zXE
zk7VLFgML}GZ4 at 1ovTQ!GN>Q#gO#8Xqll9hRpFqE<6#+fSzz`5WQuxgkQ28?mU|N`B
zppk-#Xd-AL2!f(YXenBn0hJN~loEsWVT4r-Oau{0M3hiaP+U$(($G+fMS_G89{XS3
zKRWfBFYj;f?ME$Cyt{h5H!*p+onCcbvR3AolTMzt?5|BU+0m;xfdnH>0YpPcLsL;q
zEh5z|0YeZZO%%k`)RdGog$YAQP_ZpEQb{QlP|-0FKvfG6P^?8UK_L<pkwp~~5g}DE
z5i=Y~l0?xFBoO+!;H#)b>GWyP8$uXCLNvq#9!VI<bAdgO2l;AHK8O%Mo<~qbsuT;v
zJaTHN)&y8JGL)3DRS^`a6;f4+j*|hZIE6-HfMIC}%q at gq#uHN1Bc}`pq780jz+f1r
zAWcN#Qk4)TG!;=f0h1+0Sfx2-5d at I66F|$Dm^3+xVGa^w1r)Gm1Azrq6a@@XQv}pW
zOw`p8QB4yC08kXsNkIfzf`yS1treh+C5@<xqg1LM8F85rAj~wh1i at 5MNR)|`9}mf(
zO^IR~Wy-=sF~VgGz(_Dhr{H>#<cF$bF?X}BKj0!p0RvI at B#U>eLxXgmoR=|n)28ED
zR{87IXTzcnT+4mVuif}bJci_t(F4_fQ~gKR>-}c_d+$saXCLd<TVG6S2^vB4;qSbE
zO7!mFUQmqrBZ)sK_(*?;DM)Q(1gvX6Pbo}<qYk{gvFkl-FBXu}2_y7+`F5Z($M}%#
zAGArc5d!A at pO1^~9_z8+OI+P>fVpq3r7F!#Wnt^>1e;R=QW$~y0f&wqD&Z=E0M%7h
zRrq}bgHT^YixU%{>(Rpl5_lEa at 6cZf##q;x@{kfj>Z9EFN;A9gAh!CCf0XII*L0Eu
zEr<HyxaveT`#J6VaKs;z%Ggr`-w5yV73<95d6xoT5$l8 at 9eV?n at nU^dobcb?Aa`A0
zL_`*Vn;}dU;t}4%Bz+Jcd0(F~l&&iXTpr30zz2|BPVKJ1BD2N`>fzBHxqN|*z{rA8
z&H7kKdTjKT6(6=aEyGLG9hRNu7ZC>glfdlsIaYqz9up!}pk!d8lNdiWF%M<!ogC1s
z9QqR at hg{Q#1}U7VFuX{Vo<2pUht)U+pJ$-Ooz2I0Jy~AGdg|Hrou9YPS=}CKdN>rc
zhWk*?#vFb2>^UKn+m_fA9~8S8!NC?Fmak=%;ecw#?);wnp?4UWL$U{25YWbVMZ+7+
zJ^xJ%$31NfK)@}B9k3clu=K_Uz!7$E=M)m7Nbs4Qx2%pW<{j<XGPd=}0qOq-xzAp`
zbAiKvfS%?Y0y|`HGBe&r(9z0!oO=W;vUnK)T|PVO$E=3kITv>LJ(5lBCwSFKuwEVp
zoK$r<`K_TMRuGttaFz&dLPTXu`8SCaSIvKK5%K;Ta)&LS&TCRgcH#vS6qxIj7(E1)
zAp1SydSLi3au4FES`i494<rfvG8%!EKnW+aT{rNfI0uS~TG;NeyNLRE*P5F7&E5xZ
zZ|jmq5$Dw==yM};o=-rOE*4Lb++3kFgPqh=UL=7rxM|P0-f#MHTP|IGLqNitw5lM~
zOGdP4PIH~CJc8}Hl!q+jk}!rpKv|$J4V;4wt!#uOnG#+CL&f%w%1%UwG1B-?eZaxo
zWnzBp at OQc4L>!@amtsA%`rDZ~Gk_P1J!|XsJA}SQc2D!OsAFt}p}0m<P$!Ym at 9<`R
z7f9*7y?nk+ViL;C!xE-D^`UQa1tKB~S$~tqA|DQ(B0f?Ak^oUMKCpCO%kO)NwuCL|
z{FP*qMIzQzP*9~Rgi#X~u&L{T$N__;J at MCh`ga4uRQct^gz+8}ugBN%vL1(PvnM;G
zxCBVatgj2AO%8wG!KQh4^l0Xj44!_To3oy&s~nAJFkmRA31&DY1J6U>!dcs(P~C!L
zf#FsbeiIZ*0h+#9`K8;ekl!r>SP<w(QUKtsmbea>$}J9fGl*-yr{C<(5xp&}k-(sn
zN5}lh?vr`MsPtb&f97bw<A1@~mu%e1`8geFBS8IRsPj7DZ{GIeY3VJ{^!bi3<TfTc
z$o>8z#LMn#9Q)5`?JLi}d{p^wk3S*RJI`cxQrf3b^O!ilOyk2ayfg<Dw+XYuiP(I*
z$Mv2m$K`ztTi{fLB#*PRn|An2c3579j2n1&-vh^IdE`tSrrt<&(1$SG8`GwHWIa{x
zlQ|C1Oe9P^`N7qwHQ_AUZEbsX?L)(sX|`+<$7-_Vx)m1hJ1fT?5KptE^<>+}SBJR@
zt-?yqBF&n2#S!FTp$Nc=O|-sF2k_a_F_8_V8%&P0DeK9{r>9o&u3LfRa7rBUjnlEh
zZG=fh9>FA;x)|nSK_nd^)Ng8H5;5djZG<ymfnL#!OeK_MMXf?nZ<vRMC^oMd5#l(u
zc#DLWb8Q{+JE=QfTtsLv|I)IFhA2^4$IjOKKs~-6!?4HDNUIJn#MS!Z8$dkL0a|5C
zKX8qjh8m#zt)p0LG#YT<z5|gVDN at p3LDAOn53(|ekU391Ry=WI=A84Bc^(;5Cgt42
zFmH9Fs!NLuXE2;=F?z`+IfJe_G64b?MLpkb|Ec`ac`;KVj;6mYluX76z)ryknGVNP
z!QFJq0kV`ZX=)mcA31+c|Lbqxu~ols=FHoWm`eM^kOS=-NHHRrsdBsu9MsdlQM1!O
zwzN}hO~_;L-n~7Yne%#}>Xb~Q%Ckssq4%PwT3^evkdhx?6$;VDg3gCNoPRJjuA1lg
zszSU*1vjAe1FBMxU62jg-zkwXSFamjR at 3PFYm}HzVXL6oNRkBHff55n8|g7mq-g(o
zo1>LiJU&ZI(?q2}K>4muz|>C+hYWiS8!`Ko_Nhu at NCZ>SpCS%gF#fNbz{9V481tnH
zh%&cbHLBLSq$q=LCC at LccbE4kOZcRW&rz=j9T^I+^Ng)DP(YI<?fip{ne=biC2)R3
zj(DoIloK7z6!N3z7=)}$A$5-hV3wL_7YWn%PRvF3dmC(VtK)_%3EUNkI;`th2b(y_
zgv@=AeF`c{0(R;k-H(2CSVGtlKwcUI8Ahl(YB!Y8JSO(vZ2SdU{cDwt>c!95GDqh8
z`INAll6KgyTNH^D&*_HZMVCcmx=&)2ssJOn4ifhc4NDrRjJI2F*KYothT~qJ1yV=R
zSq;~V<euZ(*fsgEAPsv%6QvX+&f{2QfJ6JCK-Y~*88uTZlsDgQe52bU!C3`tNg5+D
zRP0-JS<)ua{XIUs#4CdfC?4$I;zUlCnQaUdzpr-DAux%6&*}MpQS|z>J3UQqbtv(5
zfYVGj3-wB6<kH3?T8Uc%4N$|HvTK;=32x<N at 0%BFnbX5Q?5s81ExeI<LIIiGi2XP*
znhecIxXk;=QcaUPwky3JWD-wZ*R=#A at v|O|-u?Amdmn$t1EzbMujai_9RcLBBsC{Y
za)Sk8MX3s+n9y5F3kD)Fh>9SnvLlUQ`a9>E*Wc~xACGu)dE at vk-rPL-GaPzq{s+=>
zbcd~vQYVsl`6?{;o%$XdzOOsb_!nt}_{peZVl>s{d2-YS at 2k7DPXg&vJX}~QYO7%j
zBVgw$04x2(4O<*c$pwX at lkKS^l3x?gOTPNpC75zPU5-yq7Xg&%{9D)O8!@{JnwF9`
z$e+Aog4H at Wu?J2OW^TqIwdwsDjN&axwdsEiVZNme0SYHykhsIP6^4<gfRBO{4_49;
zW?^=m{C?D#m at ELT<alt`XqveKOykFH1HO16Hr(vvp-5NK>cYZeo`*eQQXsZx#x7uO
z*%jErcmu(Vpjedz&Wc$XNKq?nclfIpQ&TV;*Q4#x?{NA|14*-<pA)wt*~$$3z`UcF
zi!c&fos+11+_Lo2_nlhdRs!{GSRz6}0R$Z-a7S`CBMTKATr{1J!ybJAUL1*{$P0r)
z4(UI9pfPka7DRlVB(HUECyq{J>ksI>h#-a`7;U}0UT{dJC>KOJA;OCr?j#LY*S;};
z<LWY<MMN5WC{UIMW*_GFW^&eeardEZDQ<D~TGo_wk<ghzgfETFF^0ooFdkA2xt`cD
zj^}r9efApc&@^Ap+n%D+(JpfE%bjn#WtR;VN3c<_tK+F4ny5Xn_s4vab5kAnP{e*S
z&_ at SsIoP<GI`Ng{(cV4l!Iw&iJYnm4W5#2}>vcmA1wll#hZF3o;K-o7p}$3|V}eMS
zlnP{sqFMrliAofuDWGCquyN1q6o%d#Ub#E1o~(%$*c6)dY!2a?8bcB_+rBWsj6!$x
z{<@g?BH5G#&{>;j0z!djc*;Ccf0XQxi($#nS{m)L5Yy9!BI*jX=^kfjEDa<}ARM9*
z5awH9W(^i&dBzSxCPAk$<({9p3!cP#Tl?I3-wwSGMJ*d2C4++kBVq{%ry>BrOx67o
z_vq*Bmo(|C+u~5oBPvb^;yzToT=En)+~}xCj>>p(o_gg#DR?;$#EC%&o1LKHE~c_7
zcL`tG9$?SBCgq|vfm}p at Yd|p6zoUiY)BAUasGpx>^zP0OnM5R+ChXE8#}VlvHSsU=
zMB?$!tnXzfN3?Bncs4fk)ALET3>-%-zgO?`XzaXk)pe*tEf*`}6`6TL(PlFe*K&W$
zRr=xF-I+%ZC!we^r1A(A<ySTX*<*b3vUFh8!ppn)J6MkylQ{amoNeemw;G40A6;?P
zXmpoGeD&{T(pu5W8jTbWNn(=EeZQb~q>;4b+a`?@80<zuyLts8bg*L<61WsXByE=K
zqI~LxA_N#Yon7^w)YNe+e{OouM`@XGo;~z*nMK1^&()L=H=+ at 4>Q;dYu#^C3WXw`l
z+1S*K(E at W7bQHW879?%o>c0-JuSKg1_&8VMHxe7EG@~*%2&Iz%k91o>sAo at 0<D&|$
zuR-(E7R+uoMocC at IN#G_XeiU*QKC%mKNR;P0I;&gkak!BWU_Wrh)gCq#yomcS=rms
z4d7H8S-j2M9D9&%mQ1+v2Zim>d!l}jcv~Jhc21j6ZemdhB-4356CPse^fd6sG-xM@
zJw$a;(T04Ro*s_)eexV29A<==L}EQs8l!Z#w{q-PQy0QR?d92=?x<F5j4fN2gU8j1
z>|<{vie6yL-j1*~<=go#Sf*le5q4RNMq$O`=7AikmB_+$ButTpoV?Ybd#}*p?#pHR
z=Nai#b!!|$u*JabId`?kv2S=6GTHW<#4QB|prREbXtl?u;TKx&x*7#VzF#Hqyl)td
z0|peIKOUidw~1rFQg_|<5;#J at tD{iD0;2A|LIya{OEi#`fVGu9e!REueZJ at PVv6*0
z3%QwiT+sRhgSN#@ntCGP_2rlcc7Y9+3p22DRvsHG<;(#c;fq4d2UCbu223%$iXQ;1
z9&jzj!N7GQ$WG86okh85->fhn7!o%jjX@)`&*>l=T+!c7%fo2n!uP{Ymbif9P8NuW
zkn%dI%To?$gos2hdj`uU4606kiK<sYEL9AIo{FnQD7#C~Y1LkTB{;yTkud3Ly`qN1
zH(1=kK>#~zfQ6 at P3(y7Uml`+s*Q%*YT6r+^W41#pY?Sh;f^$<OhzFir>6{q}tJ at S*
zn<HaZQB_sF=0mJm86zh&(tvJe?Ac#?lZ~n9)F$uKru=oDB*tbG^8V`*ifbbdKNz4|
zemYb>tH)G9T7Z$?OvWe9-V9#d-gd*rF}5FQs%}TmN2eO%FhLvNF@<4x{WHN&mw%<l
zjF^e+raLQ<(xWfuGEI3Jq7v3 at hXzf8D~~v}J2~$>m$>5j<3=Vt)W<vWCzMS{obV1X
zVPOdd;d4vp!)i6(eWG4^Fm_%xuww!ZZPN#f4XiE3 at n;yfa5j+7nDDSixKxqNrXHUA
z05?$#Kn{`<mo~JK!ULn6a2ypp_cr!Q)k?5ilQRSbZIGrt8YUc%pX_31efM_Vc_#c;
z?q(f(qIPME9*SP<YNR{c^3Bl5v*x=SPzB>cL`f9Wc_8Is_W!f`qff83|F5UzU0<ql
z&))6`Z>j9{V~6cXr|g0UNT3!=Mxh}XZRY$rO+*~{q<wdb1G^RgAVL5kUD^=%I`^*@
z?+F_#IEI&6=D~tOJ((d7W5N-LWL12g(eC$Cy1rW&K{BakK`>;35HM$EA(ANC9|Obn
zzDXg`=x5*Xvfkl`i$50V6?d!c`Tdfg!?xYMEB|R^SuEhm!Pc at iDhWsdsK>U+l7fWg
zVvP(H4J<;%ep~sVHD+dIm at v^@e{3Jd{z5;LjS8k>ieI5<wDy<zE}-=g3=#wp_lXbs
zh01milj!cVMfMNUhCxdpNV5tT_D_f5$_LF^nF&nEwCp;?i&8sJjX^a9ML`f`P&x4@
zXLa~94t?1 at f|Nlo#4)4vGl1|dR14Ga{y)R`eb)E?x7qOYWqBE^-vu?-UVHZA&zCNI
zm#PB}N(X5kFni#`-%1X&T^b~N<^AOWLlhw at 6s#~ZzWkpl8%j`62V9ASDqk*SAJmXN
zHWCbwx{<;eAUKrKJpQd|P{<U>nN%yrM<fsUtT_q^Kz8OJP_%u70DdiC4HQ at 4RUkT_
zaX<lbMFY|JakT>xKtc&12h at NbB{4;-c9=FlN|P&;7rKm>@AY~7u=swD&9_=2ZS~pn
z#>?zf9#)6iCFJ%`752h2t2W-gtD<eepYS{{x9DCg)6b`QjBmnnWkfT*{Y$L)Rk;00
zA|%c~3{@|i2g}*&?_}MozjXN9;i=$*tP>ofKEd_*VyU0E?H<nD!b0bR46VN*aFBiP
zz3IRE+`6qTt~w8*Z+AITa(A)gsSmnDieP~r$JddTc+~z9JtaXJc+SWOTLIBHDBSV!
z#eT7y#C(lK&nI-)O1JGob3<+Y7E;M{9S^P|t3yFmtV!Z;gW*|WAHwkm-x~fpyYIEl
zEJLEvXAjQk`r6Apw`xDPc-tzeVd1I^b8708bVada6&c620g!fTzNk~<qhEb#F3p!u
z<9BKn?rZc6ew%(@?9Jq`^nL%Hp2CpkJD45;Jp#r|8JO7)KPI;y9%(jcmK5SE2}HUR
z8-7OfLNme>$mGZd?*VTlO^rMKz0i(sIq>a{Z&zePIWfn!o8jAXrTsSNUdU`N_;z8~
zKI9lDB87%AbO?o8$o?+Q$iQs3J at w(2R4tcL)+_n-TKF!GaCrKww&`3D>!U~}Q&=oe
zu?vsSNmX`cH at XzL+bd(P6JVC7xepiNz4NTSCrBPi4fz42kn<wN7V5G)XvfL;u&Uq5
ztn6SbRu-?K=ED|+v8_6*F{(P=s3Bm~S9&}0Inilpel^hs+VJLbt#jI-p=Ep#^C9Q6
z5psZQsOIKv7LHfL(PO+tex9#2mdsySi}tAvFu5vUuiw4l1+iIMuIP#GToO}^9?bUX
z*sa55Ukw(9=|gjvXN&|Ps#%k-gG+L{tVM3N7ROPMV{lY<ZiW#?U(e9^r14dZ4e7sn
zTBm{RN{qj6WnKDAp2aC#!ynPFTn#SVF27IEm9e8<)7zW{y71AnL?kSWK?lmzHPV{Q
z#DiO|R%EiAD~>G;Fz at 4`Oi!J?nXjaQ?<j-_pikqRWC!eo5I at 5K`pJ0{a>b!sBX~<}
z2Sv(Kku4h1WFY?ivrz2>K@!Y^sRJU6jqWO%gNT8M1NVeMAq36nS^@kZ242qjI=ud(
zr{&jv^Yxc;8?vvIlw+LZYD7JdM}MEArA3*zx7_X3(EVZ(mwzbMJ$346)+=@QU3F#>
z6B1D-Z5dyU4+K_m#u&HD!u&&MZ>^Y&e$UbVHUd85x%Oc3TOrVXkF9z2mMK(q$1Bfs
zA9AusrS{vNu7hHTnAJhNVciU#XCxx*s(LqT9-R?LB&jM_I68&?Zg~gJdJ}#)LH&LD
zcoty^FpLd^0uVB`z66V5KeMAP?6?0Q2Ep}2-eu+!Ut3C1c4c5^XJ!{a-blTn8GHq#
ziZKaH at 8?f>Mo}OJZ)=h}&mOB^O!`-U3M|Mn8tNP>p8u+synUH3zat>V0FneGfJCKa
zUye6l8<$Hr9C34O+o(=1Q(34S8)pXyhJ(~N<+YPP3f2ijr#khI-?#le{vEbOy{RYW
zEeSFK4TN*oqkTRmSm7{}2M@!V at T8!EUE@}ZwD~Q@!yODT7lD99EE%A6>S`fXG%lMq
zVMX(toJ827*1()wUVJfS6K!zCtKo3g<c>o}D%;Tw8V;d)lg6S42x+OqU&&2Tt2JOS
zKhQ^=#BpT7vYZY0Zn$AFGI=vCzK&Z$yJ(Qu*5i<%V5_h`LTxu_MhyZ(-;ca at c~_Di
zXMVpgXiLnj4NxqVlbokB=tY071c;wR;}4+xXXW=7kZeTl_&F(LJCEL*quJu$!@=Y3
zT?TfNq3X=B3>qq8C0U5+^x!hsI8dBNgyH4*I30GrQfoy~TaF}{6<~5*n)-_%rZ#nu
z&6Lz6bjhK*_ZY+GBvsx(xDk`;3=nW8EIUPO!|E1%q-*V<4e1SUaRx+cZyQs;PA)TX
z^OqyX(Ga&l7I2bINI>UvsH+~qks~`{Do=rI(=YXYUHzJ>&LvMcd4m;K9`1-RgW8JV
zuUFgl?PmUuyaFGFitO#Uy7hX>hwMwgzBg=dW9~sx>%DxC(<^*Dj_LPAVJ$>h`geOA
zB)7xIGmo-<Pp`H&tm|~-Cxl-wI*5#5+{^JLc>+*=Dq at vs6!8KOv(-VgDVN&6v5P9+
zwBmkU^6pA8=TuYFvlEYw_*P@$-l#YJA9NX8A6z0zc59y9A at _BuWUquge>bPZNCY>f
zDDN!MDA$Rr5aGiX^lZku{CcczGInUjA}U1I(AJSLA{dWR2lf>Dxb?(pV_)UPMZL|m
zXB_H`<3z1_8$ld%HnTh$#-R8?w#@i6tbKcgVYm$S46vAPso3uKzJF5Y)-qrlk8#^{
zL1rgb7 at 0KF3x{{KRRiK2v?@Hr^P*eypP=*n_PywoN)n7}ZN?@wEl8jJg_SX~GR9WK
zM(fOlim`KZ8fC>oqPUnDM#RcxF|?ym8*>J^o0TxO7PDq?IL;ijXAA_+VqMEyPBeFs
z;2vsZPLT>49f2e%iaw)r)#~Z)L8FuIZii8m&-dPR4vIrUE-Bm(Eg&OHWT?fAa|hxz
z;-B0M61yOuQ7GJEn8L*xeuXRm*ho*F^4XR|ejVC;-;Yl}$DVNor1}2;*ZaS+-*vyf
zSf2Qg{o*;gXh;$YRU9RQHWMLz6V>aGwbE_t12nL<l at 8JutCyX1%cgjUznw=DA5b?L
z6u{COrgHDqj#c!ZMsDXfV>Ri~qgZ-zsA%IVqJ}9-Lj;J|8h)RuEcjrIaLh{v`>&A$
zrW(u$q3B*38vGdANMc64gc$VN38PYX5*n)LN|AeQ>cSv)^9e_Pi!OL}_j=u*!lI-`
z0q%XN+h4y2Bw|`=p``m%Sf1gQ8IacNv}dK{G&XJ-J`aIli-&<eMv8M0xiyG^2N{Qc
zC|`E$zUY&1z8ulHqz<_wX(dz|fSEhEr5y at uckG#t&t7-yykGG~B~Acz$CJlsCmNQf
zV995!M3ZG&t;UwRVTQ&~8AAv_D+vtnBvlM-f4}2tW at 6p{q=NXM4VAH7b`a%#l#50%
zmFBbHU}gtL>_a8S&j?^VP{g?4 at TC!;?(ZA&{SE=MS&p1L447%R*h{?D`=!N=ySdOz
z!w<{tdeqoyE`y^aH%JUbzWW3tFU-vh*Rz=PsKO4qW)a6gS=Kr!$~jEqj^Z#Egew=o
z<APyDasjWw%fJJ8Al|#k)uXqc>DlN*Q3Hph+N`IXt=p at YO}KGP4-e<*CV{=$A at oF<
z^?|Iizs3RJAq=wH#yZ0eQ<F(_5GP{;$oDXH<C^1LHpRVD^cZEuOzL_ZhWjHirHA14
z{^Od~d5v^tH$S4q;$@$5V}uPbbnZST2~;G?90;I92nSEutML8(V(;UB8$Y)O%v|&%
zT8^vcKymbYh8}MlZXRIXpJe06FK+ZdVl>gFRuc;Ze`nnv*3z}0?gNGvDhT;5rX%f9
z9`J<%HtUAEH@&bJe%J?uD#h)05ozoUqC>pa9&@fDl|LIqw^SGX$0ZYo4`sipaIH#-
zlLmO!8U73({!MD+xTB0Tz3QlFs|HtVTIA58B5-0g)G=86+f*pDAp|z~Qyio&n4T6&
z42B7*oLgmGeC85M3%%_Xp7Sy(Pnm<$jr}o9VcpU3Xg{vh7zhj{p~bV|2pHdnzv_<c
zLm%CPzu1dyVfc8U<3`tZK(*{(n at dwBIq!sF6+RJtw#QpA*ApZ-sG^WV!E?qCLwVbi
z+7>IRdy}jY6Hg%yC!#wyAte?4kq2YtDQ$-6P2$n~n~m`=BtY=C1jrEt59h6m{&#M_
z-^b5bSK;kbZsXS8nxK at E7LV2O!NMiVh%}oB`4-BP-p>WCbtCA%pIFnop&b;bL&G(u
zIr4L5D7HBHv_=nx at rLY;{$D?yT2_;xAo<pi+B1vea}jbIQ6H-bhXWl=q7fa^<snwZ
z$=ZQA1O+7bEtu5z^2Kvc{(Kqr at A!%7sgAMJibat9)a3)uRjXC!<o&xRH5^W8*4^OW
zwPac5*f=;h5yuoAR at Nm1A!Z#g5kTv`g|KZM*I|XPR4naSS#L|}ymCzJ7HkeG?J(1z
zP-l}+hAL368+FpLu-RP~4N<;~u6XFL46UR(`!KpzQUV|&)gZ$w5T2_rl3dUmR;d at P
zqXYv$HBh32{k53Tx4zgy?mbqogCPLJ35Uy-&PInsv>+bM~By0~6rMAlkR-p#B9c
zr|kUSqv-_xW at rKmgw%q+us^Pds)|4Ahasj5pcUFsoIuhr%Fr8$QCSfr%#}e+F#$vn
zF|j};px8tB8!?pSb4?8}VhAOog|Q25VuH4a*p#)3z(y*9f{F?VrGTV~6Ly-!WG1Gh
z0}z_Z$e<u9NNFV^Y9dtJhxp{)S~rj9fWl5>9N~^wF9a_-icsTx4dQ`1k9fOP1Il_)
zs3077;Wq?8?%9x(A&~%2H&<JX!8HTb^dB;O>H7#cgHVU&{YpZgb>Kg@{NGrMJ;D27
zgP?yb5Iuka^(y}TLsMU=9mn$n#Y{0$E+L@^FbKmycf8HopOH%kV>^`97;z{}tAmrl
z*msGz17Wc~WQZT82i4QK6r^HE9<MGOiQw~4;Qf(8V2{9g0n%)va0dQNLn(;}ff$Fy
z*a5 at 4kTfBPKocD<?+yWlVs%3r3QV=H1Np+FkWL`?7B}}vbUDP|3E&Vx5=AHaP=~<h
zrAkl=kCBuu%7_zq^LUnHkYH?4y8HqOL`B%I#}q8+ZeWzQ2aF_nlbU#Ls at 5iHdi&>$
zBM6o$)Ly!SetFUaFz&Owz*|I+*7<R1>v3_gaQ{PGoq*-{*({t$N(9S~C<^tEHw4?*
zH&0-VS at JLtP;~~$#B4~+j-gASUuQwq%jF9Y;W$s-jzmRd;B4;jg#jSRqOV&?VKKyp
z3eYHBJca|@J}`0(bKnzj(7yB;3ZK(7sg~!eisdvQX*#NzMcncSiIM%@9FW1zfoUp`
zxfC)GGKsJr2=>^r%Lriw0G-N2I(s%SfZ5qy2NoXRU;45-ksmULhCtA_J47VFJqYYO
zfrvRb9D}>MZp-1=ft^FvCvz7-;;cu_N(XR1sRvU4)$2~kNDCOZAe;{Es*;LWYwWAS
zU?pdGyy7X>6<$CAVD3j at JzDP`G#3dUQgee_>;chGvph<$H-}8Y-iO-|8^jp_3EE?t
zPUppa{0Vd}X6S>^J46mBsmcx=W4g+9hwrri3iJ?18B)~K(LmUBt<W?uu=%-~2bM#G
zPX}{}0?(|zWz#P#Z;jy{1BP6Z&rmR2tH30C$0=4Ab%&Z8X!S-Ts}#|DQCt*5!ZHJy
z6*0v^kT4DbSm=~}km(ibUAx{vV4df_A%}6L&4J83%ID)ZnN6`_yF+D9VbXF)4;=z(
zhNC_zY*6TAPD8wo#UJe`fuT=S$sU|@j6wtA#O at +s^)DC~kv+$&Ky2=!jD$aZI0%8j
z@&n7ZfUSa*%he8K5U2uhA(v#>9YOK4sLd2h164dq9D|~BI}l)am$|)(!q!vTWWljv
z#ZIN5@;7wqn~a7Y%nnA*z{2MBC=)ez?`{mD!D8n<2YeG?xMxDzG~iDqx)A0=ka1JA
zz=6QwxF1=)_IPjNfsmcj8<OB2LrORW$QYc#if}U_vcDT1x5zzZkcsxZ;bG}LITd<E
zN#-4t=hY5Zsk8 at Xi|oS-VDl~~MLG>DiHJB{z!~9g{RPp$?8qHdvYW4&o=D__lJjqj
zjD`lGN^$@XWKitb+=}=<ro7<9Jz)e#268odq+O792YR01&@!gvFnE#>+pykT2_BI&
z68geUbp198eVxB-0w_m;2scyk08vUrG&hBn(IRn9^MULj<XE851_Ty|6Zf9PJ3Hc@
zVAThS8&k{A&9x|adQJ*%C(H0ZTmJ#~{tACSEA7GWzrg(0fio;(VhMLj|9|*Nl_|A|
z>H2A`gY<+WY4n9FM5qCjlL9)K<Py*8-0kfL;DYHP6;Jj=+VyCcy$rQURe+3pgUBV^
zNIH7W&Y2+1smKlO+!+7OnzNKwmf;cik3dNT5dEy(eo at Ex{}1IakLoA+Ru<A#-6i*n
zExT-O6aDPuJM|)ElG_v4ne at 6?(j15T|5*Hf at 7)aP)J6zCojuc^-+}Th)11fZgOgo7
zUJ*3y)1oQo*nWY(NIIXdKC?@x9H4?=s)(6gd^z?0bGc8pd_O<vH at 7N_gkQD%;q!di
zKSLkRWcZMUnwWR&KcXOXfJl~Zy8`aANCX&zlDXWFEWD4i1M`q at FmfkDf+drqz2)J)
zqf}Y4{=iEOi#L>dIdS86F0S~4sD7V8HhG)mgpiLTw7a*8QM at _^r4(dbZkNxG*?>|Q
z9vrVjk<W3G<QRt8p`v17SJIppwnj-OkKIrEtxbMc=}*zn{?z)9RQ$o~_~eq;A#&k@
zesaYrNYJGL$$oxtY8#9TE0dwkvZ<n_GOCfOs}%|<ZpEava=^(7QcQ>RIziaZDT;~M
zHUZc_L0~@bmKhu2GHza2=hqLi1w`*VO1u(pG7g9Ilt7e0ARmhTy2r7NTE`Ot3av+f
zFyTb5?Q-j7fRGyrIX%bRHGFgq!@KUCB^bUiQ%F!WRO<|n6c_=c`yEg^WCOwIA+eSr
zA-Usz2LiaY4WT1CE~E$?gwQr%9TTYi*65T_5PAL0FG>eub|+h_!m!MF*0V!QJSSl*
zZN&@1nCx{281BWCSl)Fn1Vx*fxT!f(meFw~WJHymVC9z6T)C43Mo?CB3NZ~{b0oQ8
zJfeAJJTE0$wGL=8B&eXE)Jco at k=Zo^e4?R2lr>yBx#AnnH(VhjBFQ7x7?|M3=1moD
z&f*4v8dy~*7UmroJx%IkqiAmy at d`QUlJ=1~trHURT2h`8l&&6S)DfiVusHHjj6}7h
z35L at En|3wXS6tqNgoLDbhhNLYeX*|3vaGi#s02i|0wjotyv$c9rHCLisXgJ$sR6Qa
zmCf!;IPucWRn;Ttzfc}%<EYe%P?sWarG2&vLzG0K4NmNTvjD(C4_6;@$cAo^HW#{}
z_M3^Zu*E}Jat#Gj-- at 9i2)6l-mFb2#lW2U9?Tx`hVOcz+`o6p9am>EwS7>yfA9?eP
z_SVv0mMR9Yv{(EFyH3>@kO6^S@?@>WPk20%_?(o&_;@h5fWf`gkm>|)lQ^Gw at Z&h3
z9_i+5j92ip8POf;CKx$b0}qfMCOgj<W2ap^Devn5))jLwz~W;?rPR4m3yXw(5evq{
z2`p2y-$x}Zy8t;QNF9itFpEL>WywsOB~cCilJwL}(eRkBKIC(>HwUUxh%3;`@vwMA
z-uDKYM1+bYGt52$Ou^}2Lv`?>@Vy9ZF%Ty!A*!JOla9#25jYV$duaG41vo_^A?Lzm
za#%pSR5Y~EHq9b!ubJXz1}^}h|CfCjK_oFJL=3s_M&}Pv5Yz}PK*{n&s)3X}$rsOt
zK3QIU5#Tq0D;JeOvFb{f1=y?XozXd-uDplEfNq+=dI8l714`1jY2%U@?F#8r%^}sn
z4N7h(WQz9!eKHuPnLBzmjHd516Ek4Y<xoWV044<K1oJ>dD7&gUcEs5>RNZBiLe$-q
za^N)+m>Qf<tM>Hws&+~0?UATS`*E8@`XgRCSV<#gQAHHB0HP<^1 at dnM?)MU{7&43X
zcXgCQ)SkEDBjnBWsA^fXKrb%zj07~|4p2y>J}s-1&m-nRvqJ;r?mlV at KkG>{dt3VU
zM`#9VIf9v_0vyI at d-Zz3Fg2hGQ<I_B33BPE7SR<UfE3DY+21FOCx=E2n1iB*2(w)p
z$IKIo$m|F}UVu_RUs?&Fcs_8XP?21JXjK3`lzhy>j4=StM*<iq_Sskg6gspn{(NOT
z%TOu&Aw%e+7Ya6#C=h^oQB4>e5+5knyq_tgV|9YcWS;`4Uf)fjZXQ;G_1$nhV4Nvu
z0f?d~u>9)T2d|o%>L{bg*OpNgMyT5ptds$es^(N!m^j;p{QH~St7k14y=Ge0MpQhX
zRP{#Ay%MGcfiyKoJEt1JW)OtQnzpI<2n+&FAi9M<JU4`p3ZSE*<oSNuQ_o7(2?&)P
z6rmyYvx at haFgD!!2=&s#6EI66vhwNekBEwJB!&+x4J<-L6jBaA<WLPMKxdm5XiZ$v
zKxFW4B%yW8>BKB}pSL`h_fH}O-U{p~N+y=Fo%0DHdO4>d<dmgwq7hnwA~>6vabfI8
z^F&V+Bu%+S0p~Yf_ at fstp-lmNx^%6#k<YQC&UR@*_(eLMBk{P2@*~HybNXjTRGcjf
zAVvg%5- at X4H4zaqL1ZRWCqlsi5O%eI+*Fnt;?dLHF=MG12b^44hO$O`>F+zg9VHYK
z=r<2OR5qSozlV?zMJ3P`9I`;E!_FPwCRp?Ify<UKkF~T`&-!(_H~g%%wMq%X{q`xF
z$R5zVO*1bhLSjW^pB`QtVj;b8GgwQB@}_9DHJAx$x=yg>NMKyrSSSVvK&MH=3>^Q6
zhVy1Ha+#f+4vrY}a*T<Www-Efbz+-F14^nBX=+Z%)y}!W>=iNUFLKkjT+ at +GtqRI+
z=8tXxoIe!`$fKQRCt<TleQ-#2fsze6w)<@5w%TwoDq3EU+0OM1EU?OSFasx`2PA-Y
z*g)5E4^fc<DsP4N(*cTMB6gxDWWh{sTWE1k0nIV8bsglBNl at +C==1v1{h~V(kWDl)
zK>QFmY&q;5_DxiP9wG(i)yUlOo??1ARvu<*s;pf*PL&#}qLQsS2XPjlk2(&peE~fU
z8Sq_?#}{wEHal|XHN`lA-JDD8 at Y3B$G|C{kVfCT-5UdC5F9BevgpnbP#>Qmeq*FtA
zx58)>3Nlx50uYQ-CCFk-jzN$*<ekN+i6aR<3QM_deDTK^cklChzLSB_f;jn{aj6d%
z&M4|ha$Fq;fSp4IK%v^JpC3NnB at N*R0S%P$9|>+vM_f5JU}O=PdbxbX8o|?vM8B^8
z-%?<tz_o?S*N2kyyCo at +Ecl^qXvlTiwRr~ReY1=(ZX-!w$6)KGqYyiqX at xv_xk`nM
zn|kn*+Xft)-JP<aCw#aqL3_cahi#Dsrb|v(k!WagDfC-0Ff!8s#Y~d}moFQ*>0Zg=
z?)UNV?j2s)L=gm5OcKUUn`psB^VNadmtp6_3DT`fXtYb)%-chi at W^7Ss;Z)>(gB2p
zVk2aVO>&^PQk78PiyN#Ez|()f<Z}0&XLv;FHVa}(Te49OUtVrEe%Z?=V^&8A%S}kz
zH;bk;i$x|hk^UqJ&4%M{FOFASgNt;=;^&70hGV6Wmaq4)bk9r};lm28!=eqcR>Vs)
zaF}jfc1W}~_Uj^64dFSYPB!gTb=c~K16(^X!*|$Wx*FQL=JL!?yFM65%tZEeMF;}Z
zX_)P2chzdpj;BHlY0c72Y?-iwY|Zb*h7m)*S?1(sO at uzUM2M`CN+ at lRPBiN##om>o
zRlIF2Y{CI75w`Q$Dsb)$`@_c(r%%EuNP)NL+_Xa`d=AW7vb(byW-RMRLO9QEmBuqN
zXTxMzD+a=>CmZflqLNXD61<T}K5Dr>4v7^M`sYcl7smcIjbYb(!Aes*XT{*xCi&=-
z#gui!?o2~LE!rDtc_?>>jur|IP}KDr!?4QTg^KBPDDw4}Eh!KTEdgOMH%eou9grA{
zfh$I(+ey}4(h(`dwPVA?4EmVHLiySd;sZ-D+zJ#Qk{rG)9yCoN7DWheQ#NWq!zS%`
zqZM~x))$3RIU$9@!X$m1jjO at bPE&~{d#uIT!omdB$CHFFI6VZzxZ-2eo7mQ>PFsc7
z4(KlKJ86`zV$;dpTsO1T;aEH<Ac|ZaBs;ymz~pEeYr%!D14J3{Y=UgI<GO|b!mSbn
zL=uF^Qj4=60C at q~()0z!f`b5uBydS67>5Z1Di~#vh%wy5XsQV2is{mJhd<F8jD*1$
z=TeFh&)o(_5ep5BX+xC$Yvghdo$v6;PMeb;6Y{4UU*&X5f<1)SQTKZ at p`97vr;c1;
z^j?r{Fr|BMkI%ksYRs<a+QF)sfZmzfK{$>`IGq+!Fxx;h>=_X4n9A3^^_#dRp2eeE
z8|J-sn;42z03QV|q}d#o{QGZEG$0^$){+wVEgGrt9HjzT(Kqu_Hd(q%{v+ZTJ;5XN
z{0q9RL-iX0>N+RU{CdI#6s9Zlxmg7yO-UaK>EIye?SqZcJo36tnB83`*rqQD#=(0%
zSQ%9#NKg?98M~qDJ97i7Qa7`OA6Y1Q{EkE~U&q(rc;pjdkIQOx;3L_F$I-v)Kshj+
z7swnwuv5Fd?|RyS2DB(iZ3mOe^i*IMUSK6M7iEPt2oy3f111}AyNN#^YtE=q60kW0
z8%>ZI7!2!@CH{{_!w_jnE~Xe&5Edgtwq_{AMJjN>L@&Xk4bBo(8PM4md8rdng2E at r
zfE`b_yz&{bv;m^=h6{A1!1r<o<=#d&oYIYindBh|Dm+&H&^z;gQ9DhLva%jHRC)H~
z3x{OF+FthHaq(0ycqa7>!;op?l+hIB;?SKRUxbkQr^NW~(K8ISw54LXl*^7+D~>Wk
zK!hwmmj;(DwBumjs6C^}Kf1}=-_nX92#}ANH+WD(zZSX at Psr)Mt>@3iv4?!>&`+Mv
zA2mG877%#Sy&>X=!^-uW(|4^vq|!1qY><?IZ%m&khXB;v!)JU`WS?TN^4<`EBd^bP
z5)uc`u<Z8(l}r$PCQ(=4@|N2N>X#^^^<r)v3VlaLxD(3f1R7L62?8WZ<mECG836Tz
z(j~N at dg379FnkDyz@#euVF2Sr2 at BHHW&OaGD7Ze)f9m*f`n}{|xARILZBG1ffIAlw
z3=qJaVG0oIB>>4t%uPT<kqk&Wfm|doBw3shu$K+7_k&0rFZiPCVJg{D6i6v)WJT5#
z`Ir_(gjQI>i~=b+X;8M+g}wi5>USV2We!wx!5wJ9fgs^A1BMJ=SaMiLP$zRdj-a53
zLMJ6U^w}nV4gZyO=K|DX9MMik2kF=wkO>k)!bqNe?X>Y&qF~dJ5l&de1lD3C7D1e|
z0al~=E=(7g87J!HsoP7uaLR_}IayeZN;9&tL-muaC5r=4tp1a$nh7bHl~}5^SOp5b
zs?3qC)CP=0tq>p+%AMbtkTtk|t2QTgQJc)eBaN{7H(Fsw_R$@QGn*4lE at G}O2N6<O
zoerfifj7h+EH{YXcEjbG3MLxxEGkudlh%fP%tI5f8s4L@()r=nN*Ejx9x(D=mO1Bs
z*2OMnBE=9zjl$y~eg+<2842T^=E?bgaQG5KAvw_XZ at QF0GL5O1?Mwv^6%O?2Lb6O*
z0D;L`2i2?r6-Fp~B2=R`6H`cg>?#O51CuByf?*3dU{IylE0k!%&~^?Zk6q{xbq&Bd
zSDxFGMD;V#IGIm<y&5a}aqrj at hzs#z5 at +f2HT8P7wq4g~y<i7E!lGG<A%KZU35jZn
zI?a=c<e};hU)Sj&AWOI0PGp_ at t3wM2IAhtLhSd}q7ilOWh^90Jk)<)`?KB`9p-QeG
zHdPD^2<WKcbODG)>Gm512q}ZG!M~}(DRGeD6Xrf6bRBX(SMmj6sft+zk$#d40#c<4
zz*!q*N+2*w)+-RvQImi~GniH)#5n~eDAF{<20)Y{NhqLi%=(&?U|7_%$kY)ALU~9!
zX!IY}?v at jBQNY5PV_0?4lwfiP1SHIw4ak9l38G0LVQ|xiT+KORr?&$%YJstk(G@}*
zz-77;d~R)->~YUtR2;Mq=i!TmL#|m_n%I4tR=H*o<})MD9==%whs!(5Q9pp;3{FH4
zkH~@e`+M(d0G^@@l at F>>go;3vfs#Q at 0>F5}Y-TEbdNmdKL@*d3iY#0~ZA%3Bgf#T)
z?}lTaj`{+TJ=w&?H2eyku~<Ry at zY?BToc>tk`KvhtSm*~agZV$a8m6pw{UMi5-YDE
zgR2&rz}`<0zLJJw>chD^6q|O7;6N=U6smP9ebbtHs%m4^nU)m)B2g64X<clJtW;dI
zQl>d5ny89tB1niWSV>7vOtGd|nI%+IiVEW>R-&kc1i>;uLPT1?$eM<zii$OwHI!<|
zjo->*Qa=2z&k3bAPhrf3QE1Yh&Sxa_3J_lzBH5@!kWh)Td;7w*Tt7;EfcmhX%tUBd
zND(Mu5|ao417(piUzuGW03M)l3_Hvetk#byb7Cj54G!_6 at p?8#pnE7eVk26FBtk(3
z6ucf!US at GSy4ahb10YC=-~L-Z6U&E$KIvF|;{Efz%8LLX0RmSrT$*8`RUDTn^Bf13
zk3OGNsM2&CE#lqo4H|4cKh}n7lb&8SdS=bbxa0{j2?>JOkTMPA_ebFNzRwM2dAkG;
zno1NYLy_ViG4hdnBP==17qsExb=7rAP(bz3>&zvHPRV{a93Y4`2y%CZk<W!8L?cBQ
zCE}~B`Rt1#ErY*PL)XnTGjbL13zjlHr-B9tU~o$wC0L}8DS~AshDibfl98w=ib at 7j
zB82;|x at S}A-~fBs5c{6%5_{dEkqAH%voNqlO8IjdkVpuqh at wI7PnX>R(-SQ0Ph<JM
z4CgmyJ7x*)Phy<DjAX%V?|~roq|j3uL)`p2I3pD?A~;1X5iqJs$qSf<gR*t006Ce)
z=s$>VP&t~U5wLG6c{4Z at g)L&@<o64ro`lo5d}^k-RY&0=Vk(KRudw=y_ovhz^Rcus
z$|qXyAO}$psUaiqYQ6DMk(kkl=48T5W>GC+nM1G?lr13NEwVlTi+XKw%MOlBaqpjW
z at AgOC&f0A#fUDk5aecmGy-`BR#qxf9D<_a`df8C)3s##N)CN&eNN0!6d#$OD0VSTd
zbaw;aBaEe{h?yw_rqsl8LM3)F!O{jU0~x>KAEc7?pq~U4Ar))L8_r45<KS4ZCLo;f
zOh?2mBOt|`rN0yM)AkCRCqN)`hwA?~|37#9d4CW8e~<9}|HpaCPlzPl%|P<NUn>Yf
z2u|f7=Z+Vw!QmkZAdRzpICYboWi+U33aJ)NrH0%vixH4H5<ogd6Jzw7y*KU3*Tm^k
zXNScQzmaAA(+)M4a!?|guPxwd$(UtVElQV`e(D;jd;G`9Ts2l0G;ilfd@<XK|0twE
z>n^UJD&Ok)qq^wh(3P+|%8)`{%yda0qA?7>)@bwz2uEh4AG)1)A?h5a*4K>MK$in)
zS&M(Co8QBbhKz>gdea36zPK-wBGZ~|(qu$LeIJLp;o}qyZM(Q0gaODMpo6dAfDtt#
zN6qqQ5Y3S0pad2Vz&Rsd4NBnC<)r+S;#?%!!?m_dkg0_qlLG-tlT&ypi1}WCJJJSE
zzk!3{^kADHAAW6B$pG+xW+&qO+xofJo_mXZqwp1cue!vew|;Cj;-v=(-g;Hoq{^S_
z?KX;F5H1~Aj)NpTV-v?_ixgK_xq&|5;3}Jxx!Rgp<ZV3FL^h_G?Sq+Wk_2)1H^B7>
zXXei=xk6^8Y$-JGw<>~lNy(u}W-HKlN8ki?@|%Vi+If5|vZ&titNh7P7)11r{{8eA
zUFMLeOF2y;Eux7Sj1Io#J at Ld&{}KX*fQdk*2#Q|#B0_|NF;amMp<-GWQ at 1xp1cT9)
zRGy+KMDv`z;)FQ7BdBkTOp=sg at cO$r7yNSq9a&}uJxF^4tjIb;nR0n}34nYcI&|rK
zft<9lJ)k64co8I170ePPukEnPT43r%lXiDe#EpXN+%HCqEknxDBd9S*14Q>p-c73E
zOcztaicQd`F)rE<O=by=G8SE?PP_x>p!@U3Y0_Z*;WuW8cdB}JUL338k-0%;CQWlS
z(mRMg4F?TL$R&l?$Wl9|2E?VzpcX+Wg(6LGV>qC4!*Ba2?tpy<w`Xc9kLXZYYvyKF
zK0c2 at hmvvm#<|Ld1hTctUb7boy;MDBgvic35<teiThV%Q5bn=MRIC<y1n<R^lw$Z7
zvx}7hJ7zN(FvTpK!?!X(;;!}2P!TdR<TZDDW+$9xr&Th2o9*}6p|xl^xi?}ze+p$j
zlOcU=wwm`t%#Cl*-D{#19%3%0d8m|_qmXCqH5oh`;ojg>FI0^vp`$0A+`ZF?uHMYY
z!qC*GPGuG1Vh$~lP9`%3)Jja`u;RKih1ij1CkeM3Z+)g~Rl&@!Y_-HWO2WMy)N<q&
zN5NB{b<DA$t57OjFJ>QbTI~X`W?BX~h|5|S+elx5nJ$B7AjL8<K>Nih1G1Y4*DTx(
z4+F8Vt2DDo6%thSdzdg#+7gd;5u)HZO;rlVH3+1W;ZwE*tN`@<xFhtSe8Vu>V|yKH
z8lt9(_jAq#A;dF>kP+%12p1S&hLs6PK<@%TI}<_Ww0)+hzvbODhG&f*;El9mk`REh
zAefla1#t56p*dS-!;<koWEjFkr0&pl5<5J~Wm5DZY0{)Kj#L|)fE&P4Mk^wGqIO6G
zkRIe>W at _*KcEo-i?*lwa3doS;3Swtip{o#6LSqAJ3nmDP5IO<{pv_>J3qs&UYPE?m
zs}L$8MwD?foCjc__3wx}MI;D5A`BhW`RI{AZX|#Z$URX?K--rz{8i@%O?hq|umSTw
zf55{WUoIG=xfGO at kYCG*`u4!K#wGqc({Tp&Z;V2CU(p+cA<-O3x9R21r28_)9 at Y@3
zvbWLWNO6%3n=mX1GqM_vU^V-Hq at m~DYicHukyex=^`15%tOl at lAY_kXs~ANEj{<l2
z9>NX;Bq1aop#xBN at BltT>=k$WS9ggc7j<aBIz;(9u8+aV-Z$Aer(47<yX=YRd`Ki=
zW?~4Ft`w<{GI9;H&@w>LK%RvpG8#dM`%<|JBy=i|BcFym_`@QKB+_gE{yI0kp(2?k
zK=glRs%8oXW5YMYs;YGa-lCXyVy5 at 4f?{xc{!;WZ72Q7D7l~1#0Dd$lF&+r9&SqP3
zwUDssB=nLVkZFC%uE>OfmP!?`>k9*5dk?ai--~&OV(OuB)M7QMNK{-#+ at sNb|KTKZ
zF*JONMioRNQ#*+V*jy6Fze>BvgWNnGlgaG#;jb<X5zBz`RTV`N6AtcwXJxmykTPw;
z?x_N{{1oZw_5UP3(oo}sqlujUiqh<XPGFIP<I;PT_>dt>L=r}VfwCzO#U~&i5Og8j
zmk-Auh5G(m#PK#ikx%j|dbm0s_@}g<Y3_^FLIwcxpAd_;6*~RT(ANb%&&peU0jzre
zMYa=?`Xl<t at jE>oMi~?Bz;An{^2ziNbR`iFx}`$Imf1 at 5Qe2X?3r-2}{ZE%YFT?R?
zH}+%R?smNTv=}bY- at W2^@(9DuKQ`L>Fl+OW(k$RnCXuAyH)(ycJy~?ae1=yC-4u|z
zYb4grla at GQ658bYt}I}^YU-8^OS6<pv2uX(50_BwkHzwuI+8tK52HNl(tt2L!SL*R
zeLIg`_P)Lu1Fh83t%laYXj|6kRK%wyoZ%WK(z9p|20OPmR5s2<%@b|cuF{Q(l<W8@
z(MUY|6ZEfkKr;M>>Qjj4X{NUxn^q)&A%dP+Q;6`OPs6t}MXUqNB62$+uxNd&l*pZ&
z%=Xn>JkG(ynER{JJX^?u2q1k^zhW5&!3WmJpfj_TMQ!}4K(=zlo}Tl&rAUY}E1gJ;
z4QsOt=bB<M2QK2tStSw(<=<Q=PH9IleV`i%90!C=Wvq!3`*{lk7C@}Y at fd1I&_N~|
z)1)QVj5G^V5 at -;H%5(YINT7|63|I<bXz6faxDk?j=~aM;q0>;*n3E}CK?^M;7zn!|
zY;Bcdq+}5~Y7=Yf_Z#&ccRUxlm>DC%$0b3<aK=|%%PNZjkOmV6yF%@Qx-}@?W>)8s
zg#Z{%43OwfNC&(LVgqjQeTq1wK!gP`4g)fF==119lYu7p5eQSev<wJgD3~yTc`Xt$
z3yFb~&Wp23Itg<eC at NH`U~Ig%4`dHa{V}L at deqnv@9&R!<a-$=lyY1eTxjDn3o2*P
zLo}gHDngG*XcMS=#(ZysAtD!3xjY1WBiq|zNB5d3^(R3RAQE at bwfy+_>}*-*Fb1Df
zo+SjFBZ#025&#u}>R#P#({N=}>CKVf(F3zCG{s at j2lTt~F)l*T>Pk=MxaP at FxXB<@
z)xyxaG!vJjwG{N8K)3CzLPhvei9|+~B}oKPBC3Rjr^F8Z5YP+-13)Q+1vGQ^r{qYc
zrY0KX0PLzARHfn|WV1^ON<s_<Cy9iz^WH0Oo*n>?nr{zQK#LuM0+kgrMGiX_%*Ds9
zyOI_srWce%{z+VTiLkt$iFRE?XF`&rfH)M$6J#t6GeD$C6bo%+Wr0%w0PNj{;wvGR
zGLQ-+1q)b!AThOwN>bEX<*>%kN`Ns`MPf)mVNzBUYYS at HR8c@kl_Z%5>HGJ$T669B
zx1Ao|x_>*-cn7#m_ln*&nOIO?92<n*4LhhznISkN*?d6h2#0!?tn4;O*$y9G^&a6f
zqExJL#~;wRl+h1)@HU89M3KB&N90F_#Iq1`;p^z&9S$wd(}~=HgAil3d6}}{bbDc*
z<)BF$3BiwpVdVL{P)}8<<d~HKM>>u#fz0a6Kud6eupxt%W5Lbh&9zJKn1i4=Z5d4j
zaS+;w$<ECmF?s1b at gxg&FtPj at fVO0f4Azvmr)*8>*Q4Xg?7 at g%EMis$MuK3b8R#so
zXp$^D$a|^c at cKNA-S3~d<xGm4GeIViEc8rc7Y^9mONO3=>21f|yCQfpAaZ(yiXB4o
z<rSt|^0^p?siO-n&aJgEEe!x at lWu5O_Xl7dD}p+p7MlSf=k`@qWyn!EcOo2yCU|%$
z&Viy&*g+1=>Y8mzV-jOq!kOG7rd;Y3S;nLn43w*328_nZ9Tfc&dFrbAv9 at W#0kyQJ
z;;)TVfK>ceS9b12pG at ypY1Jd_4+U^wNCu5^md8L_4_cH`Gd=UN*qf6{kwTQ<!rn at Q
zkGQew*wR|y=|Ex*^Y!nX7U?e2sGz0PIU$f+kg!J)1oYZ`)Zw%`+L*8pET*KIMle4s
z7lpEyGvtS*B|RB at Lf=2krCPChGC>HR3kTMbdX64C2DD<zpHG$y>!R_3L8X(xiG_pm
zsY<HE<U2*tDXy(Ww&d4R?U_^>deHX1g9NX(!u+SO$i%cl$qV3@*b}x3wOc6xJSf(R
z%+4`P&O=0dZHQ%j^$p<&HpzsCmL(xFly*CaVi=Nx2^=Hm-Sk~($2+PA=FC`o;=aj#
z59@~Z*|@<>vQ&pveKAs^7zI%kQ$|pB<AzyfrXs15U=(>*vLc+*+>OEM#P^fC9_2AR
zP}f#E!>%$9O~JcrrQ2ougxbx_KBNmlxm(3N%2#71ZR$#+3nEl#CMhv(NN6PprVAA4
zHK+=S9{e&U$e~h&w$LqXVOc>XvY?H=Y?NHKTWvlJz|zGJj at jaetc*Wi9;gyf>i{^b
z#-M2Y$4z$b4{W-s{B_87BlTwh=tZUP4-;eYgQ;^vlkzRyg12XSyY$@)l`wLKt>Q=&
z*z*u*cXtv(NRu|5Zxa`x$oGo1g+|hmS~6^ske#e2+{{ByKzx>;E;`RzXQ>E-qIP3A
zmS{}FWY#gu;gGgBqg}#N1k4uB7r6m7lw(WboX0rbPW_bD91Rda^^OrZW+=l;gf=Dc
z=s+fM^iTwd+dOVe1>7VRr132&Vh*Tk5<(JTBYwJj)_I3nB>NJ}n9~@-W+QoHD{fmO
z#IqSw)>|5T>5$gk#^w;oHv8=XJyuvqqO=y}%`x6Msf=7mvDa}{&N`N+LdIk~W~L4w
zYcA9<7E2Sxc&$L~YGPpJP>ZJ)!^1JPOoX77RV>FaT{|(A{h at ZiL3c$P9euH=JEx+;
zF3Txm?d<E~dD;%l8MBJ%ODQasl131dL<>u#0fZ1nU_3E{iDob{Df}i}eFErT4%R(!
zZ=157qM*Z?D{3*3!ZraQgi+)<*e)7rTWga-9obbw#1C~il9rR<CdG<n4$(to0l5OK
z!aABOa1$VI=IR+3AW&GKzzq{{SQaJ%6fpwO&@$}hUCu>%k;}S+lA0-s8-c|)BuBT$
z-dGVFbyJzvIP4+a1EkV)n51O3dhENfn2JS(8ryKSBIJP*jyE-|jBb>nv1&I<CZ`?j
zBE|S#86fX^QPrngttp8NVO(?vO%Rbt28iICgC{2}LL3NW5^y2LdQgQ#D9U~!l_G$J
zNK(?HsX~D_RHaaRWf0cm4eYS_P*FG}rCgfPK*ow9hd78*bT(Wfc9#+8xb<xbaJH5}
z$g)Uf7*iCXT7-&ayCiD0z_|mH{8zmL#v#3Qq)K2dL_AR6%}e~Wavg{Xj-K2f80tIE
zKf$-Sc&CwqV2PxlCMuAbiV9#-R{=D9v87F<9F*@FNf2P|iXsJ9Mu9?=QK0jKCa&^3
z?|Mx#8lrLt4d+63h0dpTG?!3MAgQC6WTe$4b_vr8WNLcfDM8>D6!hf><E8#1kxZY+
zR65^k0nJM7^&+nkRNW1sa4dutS>gbk0w2o&If!}T=aL>}GIdiuCu%={qzev_djs92
zzJq7;P*n0u`n<m3c66uYlgI%6g9>o`Y4hLN+w^zxHztALM?j01OO(i$9te}e*m=Zl
zJ81qSh0nZ?Pf<2UpvU%mFWzL5)F_^hTY-_odU at j}<euUrBY3VKS=;(^ApVqk4}nf8
zPPTFkibU-&(wN8^76$%{ID)U&BrD^QAH+wQ0otFIThEm9(Dr`1DyhfkE5eE at A1<KS
zWO)=HU876_#B3Z>$W#)UbR51cGD0Qvv5Hc#2o8)!kTm!#h7m7WC1`1(c3<d(QBy=s
z+$VOvDK?q|W#L1d6a+yORWb@`>G{2a2ee>z2b_Ds+^g?J0JHVQO%f=4Fq3Apv1mw1
zVmm<Tuja5kwoXH2LszB%(UE?VBtXAI1}-)2ZGi%gzwHO|pSv7W6;X&86=SRDE}5(_
zS4l(t5Xdr_Fh2NkhmsYD7-M%B9N#tsPQ>`o at E?d}Jy7cS$f+0r%VE%fBQC>JAFp<4
z@~5jP2e~a1e_=KY4jX$`*HwD3o at jN{hIEWH?QF(@so^YJ6Ay$ql^A9$myjJXuuVkF
zl#R|Ts&FTZqekYG1gTt0w1UI+fbiaQ9G#J19gyT<Cdtd?rar$Ve#3&Y2-c#Tz&{8s
z;CTj7Hcb+qiX!&zJ?RKZB=?`hwP)?Rg~Useq*PDC;ELN8peODU5l8wD={g at 7^&hky
zr-MAJPbcu?E;TZiC at SqL`4fgZ7Rgc!Lja&_l0_t%lVm0Y)DJr<Lu8X$hw<+J at 9mg@
ezwiD%Is at _~HSRlblT`=*;_gVN3K9#Kf=fV+qBXz(
literal 0
HcmV?d00001
diff --git a/recipes-core/glibc/ldconfig-native-2.12.1/ldconfig.patch b/recipes-core/glibc/ldconfig-native-2.12.1/ldconfig.patch
new file mode 100644
index 0000000..52986e6
--- /dev/null
+++ b/recipes-core/glibc/ldconfig-native-2.12.1/ldconfig.patch
@@ -0,0 +1,471 @@
+Upstream-Status: Inappropriate [embedded specific]
+
+enable standalone building of ldconfig
+
+---
+ cache.c | 11 +-
+ chroot_canon.c | 7 +
+ dl-cache.c | 235 ---------------------------------------------------------
+ dl-cache.h | 3
+ ldconfig.c | 27 ++++--
+ readlib.c | 7 +
+ xstrdup.c | 11 --
+ 7 files changed, 45 insertions(+), 256 deletions(-)
+
+Index: ldconfig-native-2.12.1/cache.c
+===================================================================
+--- ldconfig-native-2.12.1.orig/cache.c
++++ ldconfig-native-2.12.1/cache.c
+@@ -16,6 +16,9 @@
+ along with this program; if not, write to the Free Software Foundation,
+ Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */
+
++#define _LARGEFILE64_SOURCE
++#define _GNU_SOURCE
++
+ #include <errno.h>
+ #include <error.h>
+ #include <dirent.h>
+@@ -31,8 +34,10 @@
+ #include <sys/stat.h>
+ #include <sys/types.h>
+
+-#include <ldconfig.h>
+-#include <dl-cache.h>
++#include "ldconfig.h"
++#include "dl-cache.h"
++# define N_(msgid) msgid
++#define _(msg) msg
+
+ struct cache_entry
+ {
+Index: ldconfig-native-2.12.1/chroot_canon.c
+===================================================================
+--- ldconfig-native-2.12.1.orig/chroot_canon.c
++++ ldconfig-native-2.12.1/chroot_canon.c
+@@ -17,6 +17,9 @@
+ along with this program; if not, write to the Free Software Foundation,
+ Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */
+
++#define _LARGEFILE64_SOURCE
++#define _GNU_SOURCE
++
+ #include <stdlib.h>
+ #include <string.h>
+ #include <unistd.h>
+@@ -27,7 +30,9 @@
+ #include <stddef.h>
+ #include <stdint.h>
+
+-#include <ldconfig.h>
++#include "ldconfig.h"
++
++#define __set_errno(Val) errno = (Val)
+
+ #ifndef PATH_MAX
+ #define PATH_MAX 1024
+Index: ldconfig-native-2.12.1/dl-cache.c
+===================================================================
+--- ldconfig-native-2.12.1.orig/dl-cache.c
++++ ldconfig-native-2.12.1/dl-cache.c
+@@ -20,12 +20,12 @@
+
+ #include <assert.h>
+ #include <unistd.h>
+-#include <ldsodefs.h>
++//#include "ldsodefs.h"
+ #include <sys/mman.h>
+ #include <dl-cache.h>
+ #include <dl-procinfo.h>
+
+-#include <stdio-common/_itoa.h>
++//#include "_itoa.h"
+
+ #ifndef _DL_PLATFORMS_COUNT
+ # define _DL_PLATFORMS_COUNT 0
+@@ -39,103 +39,7 @@ static size_t cachesize;
+ /* 1 if cache_data + PTR points into the cache. */
+ #define _dl_cache_verify_ptr(ptr) (ptr < cache_data_size)
+
+-#define SEARCH_CACHE(cache) \
+-/* We use binary search since the table is sorted in the cache file. \
+- The first matching entry in the table is returned. \
+- It is important to use the same algorithm as used while generating \
+- the cache file. */ \
+-do \
+- { \
+- left = 0; \
+- right = cache->nlibs - 1; \
+- \
+- while (left <= right) \
+- { \
+- __typeof__ (cache->libs[0].key) key; \
+- \
+- middle = (left + right) / 2; \
+- \
+- key = cache->libs[middle].key; \
+- \
+- /* Make sure string table indices are not bogus before using \
+- them. */ \
+- if (! _dl_cache_verify_ptr (key)) \
+- { \
+- cmpres = 1; \
+- break; \
+- } \
+- \
+- /* Actually compare the entry with the key. */ \
+- cmpres = _dl_cache_libcmp (name, cache_data + key); \
+- if (__builtin_expect (cmpres == 0, 0)) \
+- { \
+- /* Found it. LEFT now marks the last entry for which we \
+- know the name is correct. */ \
+- left = middle; \
+- \
+- /* There might be entries with this name before the one we \
+- found. So we have to find the beginning. */ \
+- while (middle > 0) \
+- { \
+- __typeof__ (cache->libs[0].key) key; \
+- \
+- key = cache->libs[middle - 1].key; \
+- /* Make sure string table indices are not bogus before \
+- using them. */ \
+- if (! _dl_cache_verify_ptr (key) \
+- /* Actually compare the entry. */ \
+- || _dl_cache_libcmp (name, cache_data + key) != 0) \
+- break; \
+- --middle; \
+- } \
+- \
+- do \
+- { \
+- int flags; \
+- __typeof__ (cache->libs[0]) *lib = &cache->libs[middle]; \
+- \
+- /* Only perform the name test if necessary. */ \
+- if (middle > left \
+- /* We haven't seen this string so far. Test whether the \
+- index is ok and whether the name matches. Otherwise \
+- we are done. */ \
+- && (! _dl_cache_verify_ptr (lib->key) \
+- || (_dl_cache_libcmp (name, cache_data + lib->key) \
+- != 0))) \
+- break; \
+- \
+- flags = lib->flags; \
+- if (_dl_cache_check_flags (flags) \
+- && _dl_cache_verify_ptr (lib->value)) \
+- { \
+- if (best == NULL || flags == GLRO(dl_correct_cache_id)) \
+- { \
+- HWCAP_CHECK; \
+- best = cache_data + lib->value; \
+- \
+- if (flags == GLRO(dl_correct_cache_id)) \
+- /* We've found an exact match for the shared \
+- object and no general `ELF' release. Stop \
+- searching. */ \
+- break; \
+- } \
+- } \
+- } \
+- while (++middle <= right); \
+- break; \
+- } \
+- \
+- if (cmpres < 0) \
+- left = middle + 1; \
+- else \
+- right = middle - 1; \
+- } \
+- } \
+-while (0)
+-
+-
+ int
+-internal_function
+ _dl_cache_libcmp (const char *p1, const char *p2)
+ {
+ while (*p1 != '\0')
+@@ -172,139 +76,3 @@ _dl_cache_libcmp (const char *p1, const
+ }
+ return *p1 - *p2;
+ }
+-
+-
+-/* Look up NAME in ld.so.cache and return the file name stored there,
+- or null if none is found. */
+-
+-const char *
+-internal_function
+-_dl_load_cache_lookup (const char *name)
+-{
+- int left, right, middle;
+- int cmpres;
+- const char *cache_data;
+- uint32_t cache_data_size;
+- const char *best;
+-
+- /* Print a message if the loading of libs is traced. */
+- if (__builtin_expect (GLRO_dl_debug_mask & DL_DEBUG_LIBS, 0))
+- _dl_debug_printf (" search cache=%s\n", LD_SO_CACHE);
+-
+- if (cache == NULL)
+- {
+- /* Read the contents of the file. */
+- void *file = _dl_sysdep_read_whole_file (LD_SO_CACHE, &cachesize,
+- PROT_READ);
+-
+- /* We can handle three different cache file formats here:
+- - the old libc5/glibc2.0/2.1 format
+- - the old format with the new format in it
+- - only the new format
+- The following checks if the cache contains any of these formats. */
+- if (file != MAP_FAILED && cachesize > sizeof *cache
+- && memcmp (file, CACHEMAGIC, sizeof CACHEMAGIC - 1) == 0)
+- {
+- size_t offset;
+- /* Looks ok. */
+- cache = file;
+-
+- /* Check for new version. */
+- offset = ALIGN_CACHE (sizeof (struct cache_file)
+- + cache->nlibs * sizeof (struct file_entry));
+-
+- cache_new = (struct cache_file_new *) ((void *) cache + offset);
+- if (cachesize < (offset + sizeof (struct cache_file_new))
+- || memcmp (cache_new->magic, CACHEMAGIC_VERSION_NEW,
+- sizeof CACHEMAGIC_VERSION_NEW - 1) != 0)
+- cache_new = (void *) -1;
+- }
+- else if (file != MAP_FAILED && cachesize > sizeof *cache_new
+- && memcmp (file, CACHEMAGIC_VERSION_NEW,
+- sizeof CACHEMAGIC_VERSION_NEW - 1) == 0)
+- {
+- cache_new = file;
+- cache = file;
+- }
+- else
+- {
+- if (file != MAP_FAILED)
+- __munmap (file, cachesize);
+- cache = (void *) -1;
+- }
+-
+- assert (cache != NULL);
+- }
+-
+- if (cache == (void *) -1)
+- /* Previously looked for the cache file and didn't find it. */
+- return NULL;
+-
+- best = NULL;
+-
+- if (cache_new != (void *) -1)
+- {
+- uint64_t platform;
+-
+- /* This is where the strings start. */
+- cache_data = (const char *) cache_new;
+-
+- /* Now we can compute how large the string table is. */
+- cache_data_size = (const char *) cache + cachesize - cache_data;
+-
+- platform = _dl_string_platform (GLRO(dl_platform));
+- if (platform != (uint64_t) -1)
+- platform = 1ULL << platform;
+-
+-#define _DL_HWCAP_TLS_MASK (1LL << 63)
+- uint64_t hwcap_exclude = ~((GLRO(dl_hwcap) & GLRO(dl_hwcap_mask))
+- | _DL_HWCAP_PLATFORM | _DL_HWCAP_TLS_MASK);
+-
+- /* Only accept hwcap if it's for the right platform. */
+-#define HWCAP_CHECK \
+- if (lib->hwcap & hwcap_exclude) \
+- continue; \
+- if (GLRO(dl_osversion) && lib->osversion > GLRO(dl_osversion)) \
+- continue; \
+- if (_DL_PLATFORMS_COUNT \
+- && (lib->hwcap & _DL_HWCAP_PLATFORM) != 0 \
+- && (lib->hwcap & _DL_HWCAP_PLATFORM) != platform) \
+- continue
+- SEARCH_CACHE (cache_new);
+- }
+- else
+- {
+- /* This is where the strings start. */
+- cache_data = (const char *) &cache->libs[cache->nlibs];
+-
+- /* Now we can compute how large the string table is. */
+- cache_data_size = (const char *) cache + cachesize - cache_data;
+-
+-#undef HWCAP_CHECK
+-#define HWCAP_CHECK do {} while (0)
+- SEARCH_CACHE (cache);
+- }
+-
+- /* Print our result if wanted. */
+- if (__builtin_expect (GLRO_dl_debug_mask & DL_DEBUG_LIBS, 0)
+- && best != NULL)
+- _dl_debug_printf (" trying file=%s\n", best);
+-
+- return best;
+-}
+-
+-#ifndef MAP_COPY
+-/* If the system does not support MAP_COPY we cannot leave the file open
+- all the time since this would create problems when the file is replaced.
+- Therefore we provide this function to close the file and open it again
+- once needed. */
+-void
+-_dl_unload_cache (void)
+-{
+- if (cache != NULL && cache != (struct cache_file *) -1)
+- {
+- __munmap (cache, cachesize);
+- cache = NULL;
+- }
+-}
+-#endif
+Index: ldconfig-native-2.12.1/dl-cache.h
+===================================================================
+--- ldconfig-native-2.12.1.orig/dl-cache.h
++++ ldconfig-native-2.12.1/dl-cache.h
+@@ -101,5 +101,4 @@ struct cache_file_new
+ (((addr) + __alignof__ (struct cache_file_new) -1) \
+ & (~(__alignof__ (struct cache_file_new) - 1)))
+
+-extern int _dl_cache_libcmp (const char *p1, const char *p2)
+- internal_function;
++extern int _dl_cache_libcmp (const char *p1, const char *p2);
+Index: ldconfig-native-2.12.1/ldconfig.c
+===================================================================
+--- ldconfig-native-2.12.1.orig/ldconfig.c
++++ ldconfig-native-2.12.1/ldconfig.c
+@@ -16,6 +16,9 @@
+ along with this program; if not, write to the Free Software Foundation,
+ Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */
+
++#define _LARGEFILE64_SOURCE
++#define _GNU_SOURCE
++
+ #define PROCINFO_CLASS static
+ #include <alloca.h>
+ #include <argp.h>
+@@ -39,10 +42,20 @@
+ #include <glob.h>
+ #include <libgen.h>
+
+-#include <ldconfig.h>
+-#include <dl-cache.h>
++#include "ldconfig.h"
++#include "dl-cache.h"
++
++#include "dl-procinfo.h"
++
++#include "argp.h"
++
++
++#define SYSCONFDIR "/etc"
++#define LIBDIR "/usr/lib"
++#define SLIBDIR "/lib"
++# define N_(msgid) msgid
++#define _(msg) msg
+
+-#include <dl-procinfo.h>
+
+ #ifdef _DL_FIRST_PLATFORM
+ # define _DL_FIRST_EXTRA (_DL_FIRST_PLATFORM + _DL_PLATFORMS_COUNT)
+@@ -55,7 +68,7 @@
+ #endif
+
+ /* Get libc version number. */
+-#include <version.h>
++#include "version.h"
+
+ #define PACKAGE _libc_intl_domainname
+
+@@ -152,8 +165,8 @@ static const struct argp_option options[
+ { NULL, 0, NULL, 0, NULL, 0 }
+ };
+
+-#define PROCINFO_CLASS static
+-#include <dl-procinfo.c>
++//#define PROCINFO_CLASS static
++//#include <dl-procinfo.c>
+
+ /* Short description of program. */
+ static const char doc[] = N_("Configure Dynamic Linker Run Time Bindings.");
+@@ -291,6 +304,7 @@ parse_opt (int key, char *arg, struct ar
+ return 0;
+ }
+
++#define REPORT_BUGS_TO "mailing list : poky at yoctoproject.org"
+ /* Print bug-reporting information in the help message. */
+ static char *
+ more_help (int key, const char *text, void *input)
+@@ -315,7 +329,7 @@ For bug reporting instructions, please s
+ static void
+ print_version (FILE *stream, struct argp_state *state)
+ {
+- fprintf (stream, "ldconfig %s%s\n", PKGVERSION, VERSION);
++ fprintf (stream, "ldconfig (Hacked Poky Version)\n");
+ fprintf (stream, gettext ("\
+ Copyright (C) %s Free Software Foundation, Inc.\n\
+ This is free software; see the source for copying conditions. There is NO\n\
+@@ -1233,6 +1247,7 @@ set_hwcap (void)
+ hwcap_mask = strtoul (mask, NULL, 0);
+ }
+
++const char _libc_intl_domainname[] = "libc";
+
+ int
+ main (int argc, char **argv)
+Index: ldconfig-native-2.12.1/readlib.c
+===================================================================
+--- ldconfig-native-2.12.1.orig/readlib.c
++++ ldconfig-native-2.12.1/readlib.c
+@@ -22,6 +22,9 @@
+ development version. Besides the simplification, it has also been
+ modified to read some other file formats. */
+
++#define _LARGEFILE64_SOURCE
++#define _GNU_SOURCE
++
+ #include <a.out.h>
+ #include <elf.h>
+ #include <error.h>
+@@ -35,7 +38,9 @@
+ #include <sys/stat.h>
+ #include <gnu/lib-names.h>
+
+-#include <ldconfig.h>
++#include "ldconfig.h"
++
++#define _(msg) msg
+
+ #define Elf32_CLASS ELFCLASS32
+ #define Elf64_CLASS ELFCLASS64
+Index: ldconfig-native-2.12.1/xstrdup.c
+===================================================================
+--- ldconfig-native-2.12.1.orig/xstrdup.c
++++ ldconfig-native-2.12.1/xstrdup.c
+@@ -16,15 +16,10 @@
+ along with this program; if not, write to the Free Software Foundation,
+ Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */
+
+-#ifdef HAVE_CONFIG_H
+-# include <config.h>
+-#endif
++#define _GNU_SOURCE
++
++#include <string.h>
+
+-#if defined STDC_HEADERS || defined HAVE_STRING_H || _LIBC
+-# include <string.h>
+-#else
+-# include <strings.h>
+-#endif
+ void *xmalloc (size_t n) __THROW;
+ char *xstrdup (char *string) __THROW;
+
diff --git a/recipes-core/glibc/ldconfig-native-2.12.1/ldconfig_aux-cache_path_fix.patch b/recipes-core/glibc/ldconfig-native-2.12.1/ldconfig_aux-cache_path_fix.patch
new file mode 100644
index 0000000..27bc411
--- /dev/null
+++ b/recipes-core/glibc/ldconfig-native-2.12.1/ldconfig_aux-cache_path_fix.patch
@@ -0,0 +1,36 @@
+Upstream-Status: Pending
+
+Coming from this bug: http://sourceware.org/bugzilla/show_bug.cgi?id=11149
+
+Nitin A Kamble <nitin.a.kamble at intel.com>2011/03/29
+
+--- ldconfig-native-2.12.1.orig/ldconfig.c
++++ ldconfig-native-2.12.1/ldconfig.c
+@@ -1359,14 +1359,9 @@ main (int argc, char **argv)
+
+ const char *aux_cache_file = _PATH_LDCONFIG_AUX_CACHE;
+ if (opt_chroot)
+- {
+- aux_cache_file = chroot_canon (opt_chroot, aux_cache_file);
+- if (aux_cache_file == NULL)
+- error (EXIT_FAILURE, errno, _("Can't open cache file %s\n"),
+- _PATH_LDCONFIG_AUX_CACHE);
+- }
++ aux_cache_file = chroot_canon (opt_chroot, aux_cache_file);
+
+- if (! opt_ignore_aux_cache)
++ if (! opt_ignore_aux_cache && aux_cache_file)
+ load_aux_cache (aux_cache_file);
+ else
+ init_aux_cache ();
+@@ -1376,7 +1371,8 @@ main (int argc, char **argv)
+ if (opt_build_cache)
+ {
+ save_cache (cache_file);
+- save_aux_cache (aux_cache_file);
++ if (aux_cache_file)
++ save_aux_cache (aux_cache_file);
+ }
+
+ return 0;
+
diff --git a/recipes-core/glibc/ldconfig-native_2.12.1.bb b/recipes-core/glibc/ldconfig-native_2.12.1.bb
new file mode 100644
index 0000000..1debf8e
--- /dev/null
+++ b/recipes-core/glibc/ldconfig-native_2.12.1.bb
@@ -0,0 +1,33 @@
+SUMMARY = "A standalone native ldconfig build"
+
+LICENSE = "GPLv2+"
+
+LIC_FILES_CHKSUM = "file://${S}/ldconfig.c;endline=17;md5=1d15f20937c055cb5de2329a4c054399"
+
+SRC_URI = "file://ldconfig-native-2.12.1.tar.bz2 \
+ file://ldconfig.patch \
+ file://ldconfig_aux-cache_path_fix.patch \
+ file://32and64bit.patch \
+ file://endian-ness_handling.patch \
+ file://flag_fix.patch \
+ file://endianess-header.patch \
+ file://ldconfig-default-to-all-multilib-dirs.patch \
+ file://endian-ness_handling_fix.patch \
+"
+
+PR = "r2"
+
+FILESEXTRAPATHS =. "${FILE_DIRNAME}/${P}:"
+
+inherit native
+
+S = "${WORKDIR}/${PN}-${PV}"
+
+do_compile () {
+ $CC ldconfig.c -std=gnu99 chroot_canon.c xmalloc.c xstrdup.c cache.c readlib.c -I. dl-cache.c -o ldconfig
+}
+
+do_install () {
+ install -d ${D}/${bindir}/
+ install ldconfig ${D}/${bindir}/
+}
diff --git a/recipes-core/glibc/site_config/funcs b/recipes-core/glibc/site_config/funcs
new file mode 100644
index 0000000..ccc8539
--- /dev/null
+++ b/recipes-core/glibc/site_config/funcs
@@ -0,0 +1,474 @@
+a64l
+abs
+access
+__adjtimex
+alarm
+alphasort
+argz_append
+__argz_count
+argz_create_sep
+argz_insert
+__argz_next
+argz_next
+__argz_stringify
+argz_stringify
+asprintf
+atexit
+atof
+atoi
+bcmp
+bcopy
+bindresvport
+bind_textdomain_codeset
+btowc
+bzero
+calloc
+canonicalize_file_name
+catgets
+cfgetospeed
+cfsetispeed
+cfsetspeed
+chmod
+chown
+chroot
+clock
+close
+closedir
+closelog
+confstr
+connect
+daemon
+dcgettext
+difftime
+dirfd
+dirname
+dngettext
+dup2
+ecvt
+endgrent
+endmntent
+endpwent
+endutent
+endutxent
+epoll_ctl
+err
+ether_hostton
+ether_ntohost
+euidaccess
+execv
+fchdir
+fchmod
+fchmodat
+fchown
+fchownat
+fcntl
+fcvt
+fdatasync
+fdopendir
+feof_unlocked
+fgets_unlocked
+fgetxattr
+finite
+flistxattr
+flock
+flockfile
+fnmatch
+fork
+fpathconf
+__fpending
+fprintf
+free
+freeaddrinfo
+freeifaddrs
+fseeko
+__fsetlocking
+fsetxattr
+fstat64
+fstat
+fstatfs
+fsync
+ftello
+ftime
+ftruncate
+funlockfile
+futimes
+futimesat
+gai_strerror
+gcvt
+getaddrinfo
+getc_unlocked
+getcwd
+getdelim
+getdomainname
+getdtablesize
+getegid
+getenv
+geteuid
+getgid
+getgrent
+getgrent_r
+getgrgid_r
+getgrnam
+getgrnam_r
+getgrouplist
+getgroups
+gethostbyaddr_r
+gethostbyname2
+gethostbyname
+gethostbyname_r
+gethostent
+gethostid
+gethostname
+getifaddrs
+getline
+getloadavg
+getmntent
+getmsg
+getnameinfo
+getnetbyaddr_r
+getnetgrent_r
+getopt
+getopt_long
+getopt_long_only
+getpagesize
+getpass
+getpeername
+getpgrp
+getpid
+getppid
+getprotoent_r
+getpwent
+getpwent_r
+getpwnam
+getpwnam_r
+getpwuid
+getpwuid_r
+getresuid
+getrlimit
+getrusage
+getservbyname
+getservbyname_r
+getservbyport_r
+getservent
+getservent_r
+getspnam
+getspnam_r
+gettimeofday
+getttyent
+getttynam
+getuid
+getusershell
+getutent
+getutid
+getutline
+getutmp
+getutmpx
+getutxent
+getutxid
+getutxline
+getwd
+getxattr
+glob
+gmtime
+gmtime_r
+grantpt
+group_member
+herror
+hstrerror
+iconv
+iconv_open
+if_freenameindex
+if_indextoname
+if_nameindex
+if_nametoindex
+index
+inet_addr
+inet_aton
+inet_ntoa
+inet_ntop
+inet_pton
+initgroups
+innetgr
+iruserok
+isascii
+isatty
+isblank
+isgraph
+isinf
+isnan
+isprint
+isspace
+iswalnum
+iswcntrl
+iswctype
+iswprint
+iswspace
+iswupper
+isxdigit
+kill
+killpg
+lchown
+lckpwdf
+lgetxattr
+link
+listxattr
+llistxattr
+localtime
+localtime_r
+lockf
+lrand48
+lsearch
+lseek64
+lsetxattr
+lstat
+mallinfo
+malloc
+mblen
+mbrlen
+mbrtowc
+mbsinit
+mbsrtowcs
+mbtowc
+memalign
+memchr
+memcmp
+memcpy
+memmove
+mempcpy
+memrchr
+memset
+mkdir
+mkdirat
+mkdtemp
+mkfifo
+mknod
+mkstemp64
+mkstemp
+mktime
+mlock
+mmap
+mtrace
+munlock
+munmap
+nanosleep
+nice
+nl_langinfo
+ntp_adjtime
+ntp_gettime
+_obstack_free
+on_exit
+open64
+open
+openat
+opendir
+openlog
+pathconf
+pipe
+poll
+popen
+posix_memalign
+prctl
+pread
+printf
+__progname
+pselect
+pthread_mutex_lock
+ptsname
+putenv
+putgrent
+putpwent
+putspent
+pututline
+pututxline
+putwc
+pwrite
+qsort
+raise
+rand
+random
+rand_r
+read
+readdir
+readdir_r
+readlink
+realloc
+realpath
+re_comp
+recvmsg
+re_exec
+regcomp
+regexec
+remove
+rename
+re_search
+rmdir
+rpmatch
+rresvport_af
+ruserok
+ruserok_af
+sbrk
+scandir
+sched_setscheduler
+sched_yield
+__secure_getenv
+select
+semctl
+semget
+sendmsg
+setbuf
+setbuffer
+setegid
+setenv
+seteuid
+setgid
+setgroups
+sethostname
+setitimer
+_setjmp
+setjmp
+setlinebuf
+setlocale
+setmntent
+setpgid
+setpgrp
+setpriority
+setregid
+setresgid
+setresuid
+setreuid
+setrlimit
+setsid
+setsockopt
+settimeofday
+setuid
+setutent
+setutxent
+setvbuf
+setxattr
+sgetspent
+shmat
+shmctl
+shmdt
+shmget
+shutdown
+sigaction
+sigaddset
+sigaltstack
+sigblock
+sigemptyset
+sighold
+siginterrupt
+signal
+sigprocmask
+sigset
+sigsetmask
+sigstack
+sigsuspend
+sigvec
+snprintf
+socket
+socketpair
+sprintf
+srand48
+srand
+srandom
+sscanf
+stat
+statfs
+statvfs
+stime
+stpcpy
+strcasecmp
+strcasestr
+strchr
+strchrnul
+strcmp
+strcspn
+strdup
+strerror
+strerror_r
+strftime
+strlen
+strncasecmp
+strncmp
+strndup
+strnlen
+strpbrk
+strptime
+strrchr
+strsep
+strsignal
+strspn
+strstr
+strtod
+strtoimax
+strtok_r
+strtol
+strtoll
+strtoul
+strtoull
+strtoumax
+strverscmp
+strxfrm
+symlink
+sync
+sysconf
+sysctl
+sysinfo
+syslog
+_sys_siglist
+sys_siglist
+system
+tcgetattr
+tcgetpgrp
+tcsetattr
+tcsetpgrp
+time
+timegm
+times
+timezone
+tmpnam
+towlower
+towupper
+truncate
+tsearch
+ttyname
+tzset
+ulimit
+umask
+uname
+unlink
+unsetenv
+unshare
+updwtmp
+updwtmpx
+usleep
+ustat
+utime
+utimes
+utmpname
+utmpxname
+valloc
+vasprintf
+verrx
+vfork
+vfprintf
+vfscanf
+vhangup
+vprintf
+vsnprintf
+vsprintf
+wait3
+wait4
+waitpid
+wcrtomb
+wcscoll
+wcsdup
+wcslen
+wctob
+wctomb
+wctype
+wcwidth
+wmemchr
+wmemcpy
+wmempcpy
diff --git a/recipes-core/glibc/site_config/headers b/recipes-core/glibc/site_config/headers
new file mode 100644
index 0000000..609ab53
--- /dev/null
+++ b/recipes-core/glibc/site_config/headers
@@ -0,0 +1,156 @@
+aio.h
+alloca.h
+argz.h
+arpa/inet.h
+arpa/nameser.h
+asm/byteorder.h
+asm/ioctls.h
+asm/page.h
+asm/types.h
+assert.h
+byteswap.h
+crypt.h
+ctype.h
+dirent.h
+dlfcn.h
+elf.h
+endian.h
+err.h
+errno.h
+execinfo.h
+fcntl.h
+features.h
+float.h
+fstab.h
+ftw.h
+getopt.h
+glob.h
+grp.h
+iconv.h
+ifaddrs.h
+inttypes.h
+langinfo.h
+lastlog.h
+libgen.h
+libintl.h
+limits.h
+linux/capability.h
+linux/fd.h
+linux/fs.h
+linux/hayesesp.h
+linux/hdreg.h
+linux/icmp.h
+linux/in6.h
+linux/joystick.h
+linux/ptrace.h
+linux/serial.h
+linux/sonypi.h
+linux/unistd.h
+linux/utsname.h
+linux/version.h
+locale.h
+malloc.h
+math.h
+mcheck.h
+memory.h
+mntent.h
+mqueue.h
+netdb.h
+net/if.h
+netinet/ether.h
+netinet/in.h
+netinet/ip6.h
+netinet/ip.h
+netinet/tcp.h
+netinet/udp.h
+netipx/ipx.h
+net/route.h
+paths.h
+poll.h
+pthread.h
+pty.h
+pwd.h
+regex.h
+resolv.h
+rpc/rpc.h
+rpc/types.h
+sched.h
+scsi/scsi.h
+search.h
+semaphore.h
+setjmp.h
+sgtty.h
+shadow.h
+signal.h
+stdarg.h
+stdbool.h
+stdc
+stddef.h
+stdint.h
+stdio.h
+stdlib.h
+string.h
+strings.h
+stropts.h
+sys/bitypes.h
+sys/cdefs.h
+sys/dir.h
+sys/epoll.h
+sysexits.h
+sys/fcntl.h
+sys/file.h
+sys/fsuid.h
+sys/ioctl.h
+sys/ipc.h
+syslog.h
+sys/mman.h
+sys/mount.h
+sys/mtio.h
+sys/param.h
+sys/poll.h
+sys/prctl.h
+sys/ptrace.h
+sys/queue.h
+sys/reg.h
+sys/resource.h
+sys/select.h
+sys/sem.h
+sys/shm.h
+sys/signal.h
+sys/socket.h
+sys/socketvar.h
+sys/soundcard.h
+sys/statfs.h
+sys/stat.h
+sys/statvfs.h
+sys/stropts.h
+sys/swap.h
+sys/sysctl.h
+sys/sysinfo.h
+sys/sysmacros.h
+sys/termios.h
+sys/timeb.h
+sys/time.h
+sys/times.h
+sys/timex.h
+sys/types.h
+sys/uio.h
+sys/un.h
+sys/unistd.h
+sys/user.h
+sys/utsname.h
+sys/vfs.h
+sys/wait.h
+termio.h
+termios.h
+time.h
+ttyent.h
+ulimit.h
+unistd.h
+ustat.h
+utime.h
+utmp.h
+utmpx.h
+values.h
+wchar.h
+wctype.h
diff --git a/recipes-core/glibc/site_config/types b/recipes-core/glibc/site_config/types
new file mode 100644
index 0000000..178bd85
--- /dev/null
+++ b/recipes-core/glibc/site_config/types
@@ -0,0 +1,21 @@
+char
+char *
+double
+float
+int
+long
+long double
+long int
+long long
+long long int
+short
+short int
+signed char
+unsigned char
+unsigned int
+unsigned long
+unsigned long int
+unsigned long long int
+unsigned short
+unsigned short int
+void *
--
1.9.0
More information about the meta-freescale
mailing list