[T106][ZXW-22]7520V3SCV2.01.01.02P42U09_VEC_V0.8_AP_VEC origin source commit
Change-Id: Ic6e05d89ecd62fc34f82b23dcf306c93764aec4b
diff --git a/ap/build/uClibc/libc/misc/Makefile b/ap/build/uClibc/libc/misc/Makefile
new file mode 100644
index 0000000..11f362a
--- /dev/null
+++ b/ap/build/uClibc/libc/misc/Makefile
@@ -0,0 +1,13 @@
+# Makefile for uClibc
+#
+# Copyright (C) 2000-2005 Erik Andersen <andersen@uclibc.org>
+#
+# Licensed under the LGPL v2.1, see the file COPYING.LIB in this tarball.
+#
+
+top_srcdir=../../
+top_builddir=../../
+all: objs
+include $(top_builddir)Rules.mak
+include Makefile.in
+include $(top_srcdir)Makerules
diff --git a/ap/build/uClibc/libc/misc/Makefile.in b/ap/build/uClibc/libc/misc/Makefile.in
new file mode 100644
index 0000000..e01b3dc
--- /dev/null
+++ b/ap/build/uClibc/libc/misc/Makefile.in
@@ -0,0 +1,36 @@
+# Makefile for uClibc
+#
+# Copyright (C) 2000-2006 Erik Andersen <andersen@uclibc.org>
+#
+# Licensed under the LGPL v2.1, see the file COPYING.LIB in this tarball.
+#
+
+#DIRS:=assert ctype dirent error file fnmatch ftw glob gnu internals intl locale mntent \
+# pthread regex search statfs syslog sysvipc time ttyent utmp wchar wctype wordexp
+
+include $(top_srcdir)libc/misc/assert/Makefile.in
+include $(top_srcdir)libc/misc/ctype/Makefile.in
+include $(top_srcdir)libc/misc/dirent/Makefile.in
+include $(top_srcdir)libc/misc/error/Makefile.in
+include $(top_srcdir)libc/misc/elf/Makefile.in
+include $(top_srcdir)libc/misc/file/Makefile.in
+include $(top_srcdir)libc/misc/fnmatch/Makefile.in
+include $(top_srcdir)libc/misc/ftw/Makefile.in
+include $(top_srcdir)libc/misc/fts/Makefile.in
+include $(top_srcdir)libc/misc/glob/Makefile.in
+include $(top_srcdir)libc/misc/gnu/Makefile.in
+include $(top_srcdir)libc/misc/internals/Makefile.in
+include $(top_srcdir)libc/misc/locale/Makefile.in
+include $(top_srcdir)libc/misc/mntent/Makefile.in
+include $(top_srcdir)libc/misc/pthread/Makefile.in
+include $(top_srcdir)libc/misc/regex/Makefile.in
+include $(top_srcdir)libc/misc/search/Makefile.in
+include $(top_srcdir)libc/misc/statfs/Makefile.in
+include $(top_srcdir)libc/misc/syslog/Makefile.in
+include $(top_srcdir)libc/misc/sysvipc/Makefile.in
+include $(top_srcdir)libc/misc/time/Makefile.in
+include $(top_srcdir)libc/misc/ttyent/Makefile.in
+include $(top_srcdir)libc/misc/utmp/Makefile.in
+include $(top_srcdir)libc/misc/wchar/Makefile.in
+include $(top_srcdir)libc/misc/wctype/Makefile.in
+include $(top_srcdir)libc/misc/wordexp/Makefile.in
diff --git a/ap/build/uClibc/libc/misc/assert/.indent.pro b/ap/build/uClibc/libc/misc/assert/.indent.pro
new file mode 100644
index 0000000..492ecf1
--- /dev/null
+++ b/ap/build/uClibc/libc/misc/assert/.indent.pro
@@ -0,0 +1,33 @@
+--blank-lines-after-declarations
+--blank-lines-after-procedures
+--break-before-boolean-operator
+--no-blank-lines-after-commas
+--braces-on-if-line
+--braces-on-struct-decl-line
+--comment-indentation25
+--declaration-comment-column25
+--no-comment-delimiters-on-blank-lines
+--cuddle-else
+--continuation-indentation4
+--case-indentation0
+--else-endif-column33
+--space-after-cast
+--line-comments-indentation0
+--declaration-indentation1
+--dont-format-first-column-comments
+--dont-format-comments
+--honour-newlines
+--indent-level4
+/* changed from 0 to 4 */
+--parameter-indentation4
+--line-length78 /* changed from 75 */
+--continue-at-parentheses
+--no-space-after-function-call-names
+--dont-break-procedure-type
+--dont-star-comments
+--leave-optional-blank-lines
+--dont-space-special-semicolon
+--tab-size4
+/* additions by Mark */
+--case-brace-indentation0
+--leave-preprocessor-space
diff --git a/ap/build/uClibc/libc/misc/assert/Makefile b/ap/build/uClibc/libc/misc/assert/Makefile
new file mode 100644
index 0000000..4a8f4a0
--- /dev/null
+++ b/ap/build/uClibc/libc/misc/assert/Makefile
@@ -0,0 +1,13 @@
+# Makefile for uClibc
+#
+# Copyright (C) 2000-2005 Erik Andersen <andersen@uclibc.org>
+#
+# Licensed under the LGPL v2.1, see the file COPYING.LIB in this tarball.
+#
+
+top_srcdir=../../../
+top_builddir=../../../
+all: objs
+include $(top_builddir)Rules.mak
+include Makefile.in
+include $(top_srcdir)Makerules
diff --git a/ap/build/uClibc/libc/misc/assert/Makefile.in b/ap/build/uClibc/libc/misc/assert/Makefile.in
new file mode 100644
index 0000000..a49e00d
--- /dev/null
+++ b/ap/build/uClibc/libc/misc/assert/Makefile.in
@@ -0,0 +1,23 @@
+# Makefile for uClibc
+#
+# Copyright (C) 2000-2008 Erik Andersen <andersen@uclibc.org>
+#
+# Licensed under the LGPL v2.1, see the file COPYING.LIB in this tarball.
+#
+
+subdirs += libc/misc/assert
+
+CSRC := __assert.c
+
+MISC_ASSERT_DIR := $(top_srcdir)libc/misc/assert
+MISC_ASSERT_OUT := $(top_builddir)libc/misc/assert
+
+MISC_ASSERT_SRC := $(MISC_ASSERT_DIR)/__assert.c
+MISC_ASSERT_OBJ := $(MISC_ASSERT_OUT)/__assert.o
+
+libc-y += $(MISC_ASSERT_OBJ)
+
+objclean-y += CLEAN_libc/misc/assert
+
+CLEAN_libc/misc/assert:
+ $(do_rm) $(addprefix $(MISC_ASSERT_OUT)/*., o os)
diff --git a/ap/build/uClibc/libc/misc/assert/__assert.c b/ap/build/uClibc/libc/misc/assert/__assert.c
new file mode 100644
index 0000000..8afde52
--- /dev/null
+++ b/ap/build/uClibc/libc/misc/assert/__assert.c
@@ -0,0 +1,66 @@
+/* Copyright (C) 2002 Manuel Novoa III
+ * An __assert() function compatible with the modified glibc assert.h
+ * that is used by uClibc.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 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
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the Free
+ * Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+/* Oct 28, 2002
+ *
+ * ANSI/ISO C99 requires assert() to write to stderr. This means that
+ * writing to STDERR_FILENO is insufficient, as the user could freopen
+ * stderr. It is also insufficient to output to fileno(stderr) since
+ * this would fail in the custom stream case. I didn't remove the
+ * old code though, as it doesn't use stdio stream functionality
+ * and is useful in debugging the stdio code.
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+
+/* Get the prototype from assert.h as a double-check. */
+#undef NDEBUG
+#include <assert.h>
+#undef assert
+
+
+#define ASSERT_SHOW_PROGNAME 1
+
+static smallint in_assert; /* bss inits to 0. */
+
+void __assert(const char *assertion, const char * filename,
+ unsigned int linenumber, register const char * function)
+{
+ if (!in_assert) {
+ in_assert = 1;
+
+ fprintf(stderr,
+#ifdef ASSERT_SHOW_PROGNAME
+ "%s: %s: %d: %s: Assertion `%s' failed.\n", __uclibc_progname,
+#else
+ "%s: %d: %s: Assertion `%s' failed.\n",
+#endif
+ filename,
+ linenumber,
+ /* Function name isn't available with some compilers. */
+ ((function == NULL) ? "?function?" : function),
+ assertion
+ );
+ }
+ /* shouldn't we? fflush(stderr); */
+ abort();
+}
+libc_hidden_def(__assert)
diff --git a/ap/build/uClibc/libc/misc/ctype/.indent.pro b/ap/build/uClibc/libc/misc/ctype/.indent.pro
new file mode 100644
index 0000000..492ecf1
--- /dev/null
+++ b/ap/build/uClibc/libc/misc/ctype/.indent.pro
@@ -0,0 +1,33 @@
+--blank-lines-after-declarations
+--blank-lines-after-procedures
+--break-before-boolean-operator
+--no-blank-lines-after-commas
+--braces-on-if-line
+--braces-on-struct-decl-line
+--comment-indentation25
+--declaration-comment-column25
+--no-comment-delimiters-on-blank-lines
+--cuddle-else
+--continuation-indentation4
+--case-indentation0
+--else-endif-column33
+--space-after-cast
+--line-comments-indentation0
+--declaration-indentation1
+--dont-format-first-column-comments
+--dont-format-comments
+--honour-newlines
+--indent-level4
+/* changed from 0 to 4 */
+--parameter-indentation4
+--line-length78 /* changed from 75 */
+--continue-at-parentheses
+--no-space-after-function-call-names
+--dont-break-procedure-type
+--dont-star-comments
+--leave-optional-blank-lines
+--dont-space-special-semicolon
+--tab-size4
+/* additions by Mark */
+--case-brace-indentation0
+--leave-preprocessor-space
diff --git a/ap/build/uClibc/libc/misc/ctype/Makefile b/ap/build/uClibc/libc/misc/ctype/Makefile
new file mode 100644
index 0000000..4a8f4a0
--- /dev/null
+++ b/ap/build/uClibc/libc/misc/ctype/Makefile
@@ -0,0 +1,13 @@
+# Makefile for uClibc
+#
+# Copyright (C) 2000-2005 Erik Andersen <andersen@uclibc.org>
+#
+# Licensed under the LGPL v2.1, see the file COPYING.LIB in this tarball.
+#
+
+top_srcdir=../../../
+top_builddir=../../../
+all: objs
+include $(top_builddir)Rules.mak
+include Makefile.in
+include $(top_srcdir)Makerules
diff --git a/ap/build/uClibc/libc/misc/ctype/Makefile.in b/ap/build/uClibc/libc/misc/ctype/Makefile.in
new file mode 100644
index 0000000..125d916
--- /dev/null
+++ b/ap/build/uClibc/libc/misc/ctype/Makefile.in
@@ -0,0 +1,42 @@
+# Makefile for uClibc
+#
+# Copyright (C) 2000-2008 Erik Andersen <andersen@uclibc.org>
+#
+# Licensed under the LGPL v2.1, see the file COPYING.LIB in this tarball.
+#
+
+subdirs += libc/misc/ctype
+
+# multi source ctype.c
+COM_SRC := \
+ isalnum.c isalpha.c iscntrl.c isdigit.c \
+ isgraph.c islower.c isprint.c ispunct.c isspace.c \
+ isupper.c isxdigit.c tolower.c toupper.c \
+ isblank.c
+ifeq ($(UCLIBC_SUSV4_LEGACY),y)
+COM_SRC += isascii.c toascii.c
+endif
+CSRC := $(COM_SRC)
+
+ifeq ($(UCLIBC_HAS_CTYPE_TABLES),y)
+CSRC += __C_ctype_b.c __C_ctype_tolower.c __C_ctype_toupper.c \
+ __ctype_b_loc.c __ctype_tolower_loc.c __ctype_toupper_loc.c \
+ __ctype_assert.c isctype.c
+endif
+
+ifeq ($(UCLIBC_HAS_XLOCALE),y)
+CSRC += $(patsubst %.c,%_l.c,$(COM_SRC))
+endif
+
+MISC_CTYPE_DIR := $(top_srcdir)libc/misc/ctype
+MISC_CTYPE_OUT := $(top_builddir)libc/misc/ctype
+
+MISC_CTYPE_SRC := $(patsubst %.c,$(MISC_CTYPE_DIR)/%.c,$(CSRC))
+MISC_CTYPE_OBJ := $(patsubst %.c,$(MISC_CTYPE_OUT)/%.o,$(CSRC))
+
+libc-y += $(MISC_CTYPE_OBJ)
+
+objclean-y += CLEAN_libc/misc/ctype
+
+CLEAN_libc/misc/ctype:
+ $(do_rm) $(addprefix $(MISC_CTYPE_OUT)/*., o os)
diff --git a/ap/build/uClibc/libc/misc/ctype/__C_ctype_b.c b/ap/build/uClibc/libc/misc/ctype/__C_ctype_b.c
new file mode 100644
index 0000000..d22359f
--- /dev/null
+++ b/ap/build/uClibc/libc/misc/ctype/__C_ctype_b.c
@@ -0,0 +1,8 @@
+/*
+ * Copyright (C) 2003-2006 Manuel Novoa III <mjn3@uclibc.org>
+ *
+ * Licensed under the LGPL v2.1, see the file COPYING.LIB in this tarball.
+ */
+
+#define L___C_ctype_b
+#include "ctype.c"
diff --git a/ap/build/uClibc/libc/misc/ctype/__C_ctype_tolower.c b/ap/build/uClibc/libc/misc/ctype/__C_ctype_tolower.c
new file mode 100644
index 0000000..fc6027f
--- /dev/null
+++ b/ap/build/uClibc/libc/misc/ctype/__C_ctype_tolower.c
@@ -0,0 +1,8 @@
+/*
+ * Copyright (C) 2003-2006 Manuel Novoa III <mjn3@uclibc.org>
+ *
+ * Licensed under the LGPL v2.1, see the file COPYING.LIB in this tarball.
+ */
+
+#define L___C_ctype_tolower
+#include "ctype.c"
diff --git a/ap/build/uClibc/libc/misc/ctype/__C_ctype_toupper.c b/ap/build/uClibc/libc/misc/ctype/__C_ctype_toupper.c
new file mode 100644
index 0000000..ec42fbf
--- /dev/null
+++ b/ap/build/uClibc/libc/misc/ctype/__C_ctype_toupper.c
@@ -0,0 +1,8 @@
+/*
+ * Copyright (C) 2003-2006 Manuel Novoa III <mjn3@uclibc.org>
+ *
+ * Licensed under the LGPL v2.1, see the file COPYING.LIB in this tarball.
+ */
+
+#define L___C_ctype_toupper
+#include "ctype.c"
diff --git a/ap/build/uClibc/libc/misc/ctype/__ctype_assert.c b/ap/build/uClibc/libc/misc/ctype/__ctype_assert.c
new file mode 100644
index 0000000..fe45945
--- /dev/null
+++ b/ap/build/uClibc/libc/misc/ctype/__ctype_assert.c
@@ -0,0 +1,8 @@
+/*
+ * Copyright (C) 2003-2006 Manuel Novoa III <mjn3@uclibc.org>
+ *
+ * Licensed under the LGPL v2.1, see the file COPYING.LIB in this tarball.
+ */
+
+#define L___ctype_assert
+#include "ctype.c"
diff --git a/ap/build/uClibc/libc/misc/ctype/__ctype_b_loc.c b/ap/build/uClibc/libc/misc/ctype/__ctype_b_loc.c
new file mode 100644
index 0000000..11d5046
--- /dev/null
+++ b/ap/build/uClibc/libc/misc/ctype/__ctype_b_loc.c
@@ -0,0 +1,8 @@
+/*
+ * Copyright (C) 2003-2006 Manuel Novoa III <mjn3@uclibc.org>
+ *
+ * Licensed under the LGPL v2.1, see the file COPYING.LIB in this tarball.
+ */
+
+#define L___ctype_b_loc
+#include "ctype.c"
diff --git a/ap/build/uClibc/libc/misc/ctype/__ctype_tolower_loc.c b/ap/build/uClibc/libc/misc/ctype/__ctype_tolower_loc.c
new file mode 100644
index 0000000..54037a5
--- /dev/null
+++ b/ap/build/uClibc/libc/misc/ctype/__ctype_tolower_loc.c
@@ -0,0 +1,8 @@
+/*
+ * Copyright (C) 2003-2006 Manuel Novoa III <mjn3@uclibc.org>
+ *
+ * Licensed under the LGPL v2.1, see the file COPYING.LIB in this tarball.
+ */
+
+#define L___ctype_tolower_loc
+#include "ctype.c"
diff --git a/ap/build/uClibc/libc/misc/ctype/__ctype_toupper_loc.c b/ap/build/uClibc/libc/misc/ctype/__ctype_toupper_loc.c
new file mode 100644
index 0000000..e511d0f
--- /dev/null
+++ b/ap/build/uClibc/libc/misc/ctype/__ctype_toupper_loc.c
@@ -0,0 +1,8 @@
+/*
+ * Copyright (C) 2003-2006 Manuel Novoa III <mjn3@uclibc.org>
+ *
+ * Licensed under the LGPL v2.1, see the file COPYING.LIB in this tarball.
+ */
+
+#define L___ctype_toupper_loc
+#include "ctype.c"
diff --git a/ap/build/uClibc/libc/misc/ctype/ctype.c b/ap/build/uClibc/libc/misc/ctype/ctype.c
new file mode 100644
index 0000000..1c40b24
--- /dev/null
+++ b/ap/build/uClibc/libc/misc/ctype/ctype.c
@@ -0,0 +1,1083 @@
+/* Copyright (C) 2003 Manuel Novoa III
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 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
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the Free
+ * Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+/* ATTENTION! ATTENTION! ATTENTION! ATTENTION! ATTENTION!
+ *
+ * Besides uClibc, I'm using this code in my libc for elks, which is
+ * a 16-bit environment with a fairly limited compiler. It would make
+ * things much easier for me if this file isn't modified unnecessarily.
+ * In particular, please put any new or replacement functions somewhere
+ * else, and modify the makefile to use your version instead.
+ * Thanks. Manuel
+ *
+ * ATTENTION! ATTENTION! ATTENTION! ATTENTION! ATTENTION! */
+
+#define __NO_CTYPE
+
+#include <ctype.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <limits.h>
+#include <stdint.h>
+#include <assert.h>
+#include <locale.h>
+
+#ifdef __UCLIBC_HAS_XLOCALE__
+# include <xlocale.h>
+#endif
+
+/**********************************************************************/
+#ifdef __UCLIBC_HAS_CTYPE_TABLES__
+
+#ifdef __UCLIBC_HAS_CTYPE_SIGNED__
+
+#if EOF >= CHAR_MIN
+#define CTYPE_DOMAIN_CHECK(C) \
+ (((unsigned int)((C) - CHAR_MIN)) <= (UCHAR_MAX - CHAR_MIN))
+#else
+#define CTYPE_DOMAIN_CHECK(C) \
+ ((((unsigned int)((C) - CHAR_MIN)) <= (UCHAR_MAX - CHAR_MIN)) || ((C) == EOF))
+#endif
+
+#else /* __UCLIBC_HAS_CTYPE_SIGNED__ */
+
+#if EOF == -1
+#define CTYPE_DOMAIN_CHECK(C) \
+ (((unsigned int)((C) - EOF)) <= (UCHAR_MAX - EOF))
+#else
+#define CTYPE_DOMAIN_CHECK(C) \
+ ((((unsigned int)(C)) <= UCHAR_MAX) || ((C) == EOF))
+#endif
+
+#endif /* __UCLIBC_HAS_CTYPE_SIGNED__ */
+
+#endif /* __UCLIBC_HAS_CTYPE_TABLES__ */
+/**********************************************************************/
+#ifdef __UCLIBC_MJN3_ONLY__
+#ifdef L_isspace
+/* emit only once */
+#warning CONSIDER: Should we assert when debugging and __UCLIBC_HAS_CTYPE_CHECKED?
+#warning TODO: Fix asserts in to{upper|lower}{_l}.
+#warning TODO: Optimize the isx*() funcs.
+#endif
+#endif /* __UCLIBC_MJN3_ONLY__ */
+/**********************************************************************/
+#undef PASTE2
+#define PASTE2(X,Y) X ## Y
+
+#ifdef __UCLIBC_HAS_CTYPE_TABLES__
+
+#undef CTYPE_NAME
+#undef ISCTYPE
+#undef CTYPE_ALIAS
+#undef CTYPE_DEF
+#ifdef __UCLIBC_DO_XLOCALE
+#define CTYPE_NAME(X) __is ## X ## _l
+#define ISCTYPE(C,F) __isctype_l( C, F, locale_arg)
+#define CTYPE_ALIAS(NAME) strong_alias( __is ## NAME ## _l , is ## NAME ## _l)
+#define CTYPE_DEF(NAME) libc_hidden_def(is ## NAME ## _l)
+#else
+#define CTYPE_NAME(X) is ## X
+#define ISCTYPE(C,F) __isctype( C, F )
+#define CTYPE_ALIAS(NAME)
+#define CTYPE_DEF(NAME) libc_hidden_def(is ## NAME)
+#endif
+
+
+#undef CTYPE_BODY
+
+#if defined(__UCLIBC_HAS_CTYPE_ENFORCED__)
+/* Make sure assert is active for to*() funcs below. */
+#undef NDEBUG
+#include <assert.h>
+
+extern void __isctype_assert(int c, int mask) __attribute__ ((__noreturn__)) attribute_hidden;
+
+#define CTYPE_BODY(NAME,C,MASK) \
+ if (CTYPE_DOMAIN_CHECK(C)) { \
+ return ISCTYPE(C, MASK); \
+ } \
+ __isctype_assert(C, MASK);
+
+#elif defined(__UCLIBC_HAS_CTYPE_CHECKED__)
+
+#define CTYPE_BODY(NAME,C,MASK) \
+ return CTYPE_DOMAIN_CHECK(C) \
+ ? ISCTYPE(C, MASK) \
+ : 0;
+
+#elif defined(__UCLIBC_HAS_CTYPE_UNSAFE__)
+
+#define CTYPE_BODY(NAME,C,MASK) \
+ return ISCTYPE(C, MASK);
+
+
+#else /* No checking done. */
+
+#error Unknown type of ctype checking!
+
+#endif
+
+
+
+#define IS_FUNC_BODY(NAME) \
+int CTYPE_NAME(NAME) (int c __LOCALE_PARAM ); \
+int CTYPE_NAME(NAME) (int c __LOCALE_PARAM ) \
+{ \
+ CTYPE_BODY(NAME,c,PASTE2(_IS,NAME)) \
+} \
+CTYPE_DEF(NAME) \
+CTYPE_ALIAS(NAME)
+
+#else /* __UCLIBC_HAS_CTYPE_TABLES__ */
+
+#define C_MACRO(X) PASTE2(__C_is,X)(c)
+#define CTYPE_NAME(X) is ## X
+#define CTYPE_DEF(NAME) libc_hidden_def(is ## NAME)
+
+#define IS_FUNC_BODY(NAME) \
+int CTYPE_NAME(NAME) (int c) \
+{ \
+ return C_MACRO(NAME); \
+}
+
+#endif /* __UCLIBC_HAS_CTYPE_TABLES__ */
+/**********************************************************************/
+#ifdef L___ctype_assert
+#ifdef __UCLIBC_HAS_CTYPE_ENFORCED__
+
+
+attribute_hidden void __isctype_assert(int c, int mask)
+{
+ fprintf(stderr, "%s: __is*{_l}(%d,%#x {locale})\n", __uclibc_progname, c, mask);
+ abort();
+}
+
+#endif
+#endif
+/**********************************************************************/
+#if defined(L_isalnum) || defined(L_isalnum_l)
+
+IS_FUNC_BODY(alnum);
+
+#endif
+/**********************************************************************/
+#if defined(L_isalpha) || defined(L_isalpha_l)
+
+IS_FUNC_BODY(alpha);
+
+#endif
+/**********************************************************************/
+#if defined(L_isblank) || defined(L_isblank_l)
+
+IS_FUNC_BODY(blank);
+
+#endif
+/**********************************************************************/
+#if defined(L_iscntrl) || defined(L_iscntrl_l)
+
+IS_FUNC_BODY(cntrl);
+
+#endif
+/**********************************************************************/
+#if defined(L_isdigit) || defined(L_isdigit_l)
+
+#ifdef __UCLIBC_HAS_CTYPE_TABLES__
+
+/* The standards require EOF < 0. */
+#if EOF >= CHAR_MIN
+#define __isdigit_char_or_EOF(C) __isdigit_char((C))
+#else
+#define __isdigit_char_or_EOF(C) __isdigit_int((C))
+#endif
+
+int CTYPE_NAME(digit) (int C __LOCALE_PARAM);
+int CTYPE_NAME(digit) (int C __LOCALE_PARAM)
+{
+#if defined(__UCLIBC_HAS_CTYPE_ENFORCED__)
+ if (CTYPE_DOMAIN_CHECK(C)) {
+ return __isdigit_char_or_EOF(C); /* C is (unsigned) char or EOF. */
+ }
+ __isctype_assert(C, _ISdigit);
+#else
+ return __isdigit_int(C); /* C could be invalid. */
+#endif
+}
+CTYPE_DEF(digit)
+CTYPE_ALIAS(digit)
+
+#else /* __UCLIBC_HAS_CTYPE_TABLES__ */
+
+IS_FUNC_BODY(digit);
+
+#endif /* __UCLIBC_HAS_CTYPE_TABLES__ */
+
+#endif
+/**********************************************************************/
+#if defined(L_isgraph) || defined(L_isgraph_l)
+
+IS_FUNC_BODY(graph);
+
+#endif
+/**********************************************************************/
+#if defined(L_islower) || defined(L_islower_l)
+
+IS_FUNC_BODY(lower);
+
+#endif
+/**********************************************************************/
+#if defined(L_isprint) || defined(L_isprint_l)
+
+IS_FUNC_BODY(print);
+
+#endif
+/**********************************************************************/
+#if defined(L_ispunct) || defined(L_ispunct_l)
+
+IS_FUNC_BODY(punct);
+
+#endif
+/**********************************************************************/
+#if defined(L_isspace) || defined(L_isspace_l)
+
+IS_FUNC_BODY(space);
+
+#endif
+/**********************************************************************/
+#if defined(L_isupper) || defined(L_isupper_l)
+
+IS_FUNC_BODY(upper);
+
+#endif
+/**********************************************************************/
+#if defined(L_isxdigit) || defined(L_isxdigit_l)
+
+IS_FUNC_BODY(xdigit);
+
+#endif
+/**********************************************************************/
+#ifdef L_tolower
+
+#undef tolower
+#ifdef __UCLIBC_HAS_CTYPE_TABLES__
+
+int tolower(int c)
+{
+#if defined(__UCLIBC_HAS_CTYPE_ENFORCED__)
+ assert(CTYPE_DOMAIN_CHECK(c));
+#endif
+ return __UCLIBC_CTYPE_IN_TO_DOMAIN(c) ? (__UCLIBC_CTYPE_TOLOWER)[c] : c;
+}
+
+#else /* __UCLIBC_HAS_CTYPE_TABLES__ */
+
+int tolower(int c)
+{
+ return __C_tolower(c);
+}
+
+#endif /* __UCLIBC_HAS_CTYPE_TABLES__ */
+libc_hidden_def(tolower)
+
+#endif
+/**********************************************************************/
+#ifdef L_tolower_l
+
+#undef tolower_l
+int tolower_l(int c, __locale_t l)
+{
+#if defined(__UCLIBC_HAS_CTYPE_ENFORCED__)
+ assert(CTYPE_DOMAIN_CHECK(c));
+#endif
+ return __UCLIBC_CTYPE_IN_TO_DOMAIN(c) ? l->__ctype_tolower[c] : c;
+}
+libc_hidden_def(tolower_l)
+
+#endif
+/**********************************************************************/
+#ifdef L_toupper
+
+#undef toupper
+#ifdef __UCLIBC_HAS_CTYPE_TABLES__
+
+int toupper(int c)
+{
+#if defined(__UCLIBC_HAS_CTYPE_ENFORCED__)
+ assert(CTYPE_DOMAIN_CHECK(c));
+#endif
+ return __UCLIBC_CTYPE_IN_TO_DOMAIN(c) ? (__UCLIBC_CTYPE_TOUPPER)[c] : c;
+}
+
+#else /* __UCLIBC_HAS_CTYPE_TABLES__ */
+
+int toupper(int c)
+{
+ return __C_toupper(c);
+}
+
+#endif /* __UCLIBC_HAS_CTYPE_TABLES__ */
+libc_hidden_def(toupper)
+
+#endif
+/**********************************************************************/
+#ifdef L_toupper_l
+
+#undef toupper_l
+int toupper_l(int c, __locale_t l)
+{
+#if defined(__UCLIBC_HAS_CTYPE_ENFORCED__)
+ assert(CTYPE_DOMAIN_CHECK(c));
+#endif
+ return __UCLIBC_CTYPE_IN_TO_DOMAIN(c) ? l->__ctype_toupper[c] : c;
+}
+
+#endif
+/**********************************************************************/
+#if defined(L_isascii) || defined(L_isascii_l)
+
+#ifdef __UCLIBC_HAS_CTYPE_TABLES__
+
+int __XL_NPP(isascii)(int c);
+int __XL_NPP(isascii)(int c)
+{
+ return __isascii(c); /* locale-independent */
+}
+
+#else /* __UCLIBC_HAS_CTYPE_TABLES__ */
+
+int isascii(int c)
+{
+ return __isascii(c); /* locale-independent */
+}
+
+#endif /* __UCLIBC_HAS_CTYPE_TABLES__ */
+CTYPE_DEF(ascii)
+
+
+#endif
+/**********************************************************************/
+#if defined(L_toascii) || defined(L_toascii_l)
+
+#ifdef __UCLIBC_HAS_CTYPE_TABLES__
+
+int __XL_NPP(toascii)(int c);
+int __XL_NPP(toascii)(int c)
+{
+ return __toascii(c); /* locale-independent */
+}
+
+#else /* __UCLIBC_HAS_CTYPE_TABLES__ */
+
+int toascii(int c)
+{
+ return __toascii(c); /* locale-independent */
+}
+
+#endif /* __UCLIBC_HAS_CTYPE_TABLES__ */
+
+#endif
+/**********************************************************************/
+/* glibc extensions */
+/**********************************************************************/
+#ifdef L_isctype
+
+int isctype(int c, int mask)
+{
+ CTYPE_BODY(NAME,c,mask)
+}
+
+#endif
+/**********************************************************************/
+#ifdef L___ctype_b_loc
+
+#ifdef __UCLIBC_HAS_XLOCALE__
+
+const __ctype_mask_t **__ctype_b_loc(void)
+{
+ return &(__UCLIBC_CURLOCALE->__ctype_b);
+}
+
+libc_hidden_def(__ctype_b_loc)
+#endif
+
+#endif
+/**********************************************************************/
+#ifdef L___ctype_tolower_loc
+
+#ifdef __UCLIBC_HAS_XLOCALE__
+
+const __ctype_touplow_t **__ctype_tolower_loc(void)
+{
+ return &(__UCLIBC_CURLOCALE->__ctype_tolower);
+}
+libc_hidden_def(__ctype_tolower_loc)
+
+#endif
+
+#endif
+/**********************************************************************/
+#ifdef L___ctype_toupper_loc
+
+#ifdef __UCLIBC_HAS_XLOCALE__
+
+const __ctype_touplow_t **__ctype_toupper_loc(void)
+{
+ return &(__UCLIBC_CURLOCALE->__ctype_toupper);
+}
+libc_hidden_def(__ctype_toupper_loc)
+
+#endif
+
+#endif
+/**********************************************************************/
+#ifdef L___C_ctype_b
+
+static const __ctype_mask_t __C_ctype_b_data[] = {
+#ifdef __UCLIBC_HAS_CTYPE_SIGNED__
+ /* -128 M-^@ */ 0,
+ /* -127 M-^A */ 0,
+ /* -126 M-^B */ 0,
+ /* -125 M-^C */ 0,
+ /* -124 M-^D */ 0,
+ /* -123 M-^E */ 0,
+ /* -122 M-^F */ 0,
+ /* -121 M-^G */ 0,
+ /* -120 M-^H */ 0,
+ /* -119 M-^I */ 0,
+ /* -118 M-^J */ 0,
+ /* -117 M-^K */ 0,
+ /* -116 M-^L */ 0,
+ /* -115 M-^M */ 0,
+ /* -114 M-^N */ 0,
+ /* -113 M-^O */ 0,
+ /* -112 M-^P */ 0,
+ /* -111 M-^Q */ 0,
+ /* -110 M-^R */ 0,
+ /* -109 M-^S */ 0,
+ /* -108 M-^T */ 0,
+ /* -107 M-^U */ 0,
+ /* -106 M-^V */ 0,
+ /* -105 M-^W */ 0,
+ /* -104 M-^X */ 0,
+ /* -103 M-^Y */ 0,
+ /* -102 M-^Z */ 0,
+ /* -101 M-^[ */ 0,
+ /* -100 M-^\ */ 0,
+ /* -99 M-^] */ 0,
+ /* -98 M-^^ */ 0,
+ /* -97 M-^_ */ 0,
+ /* -96 M- */ 0,
+ /* -95 M-! */ 0,
+ /* -94 M-" */ 0,
+ /* -93 M-# */ 0,
+ /* -92 M-$ */ 0,
+ /* -91 M-% */ 0,
+ /* -90 M-& */ 0,
+ /* -89 M-' */ 0,
+ /* -88 M-( */ 0,
+ /* -87 M-) */ 0,
+ /* -86 M-* */ 0,
+ /* -85 M-+ */ 0,
+ /* -84 M-, */ 0,
+ /* -83 M-- */ 0,
+ /* -82 M-. */ 0,
+ /* -81 M-/ */ 0,
+ /* -80 M-0 */ 0,
+ /* -79 M-1 */ 0,
+ /* -78 M-2 */ 0,
+ /* -77 M-3 */ 0,
+ /* -76 M-4 */ 0,
+ /* -75 M-5 */ 0,
+ /* -74 M-6 */ 0,
+ /* -73 M-7 */ 0,
+ /* -72 M-8 */ 0,
+ /* -71 M-9 */ 0,
+ /* -70 M-: */ 0,
+ /* -69 M-; */ 0,
+ /* -68 M-< */ 0,
+ /* -67 M-= */ 0,
+ /* -66 M-> */ 0,
+ /* -65 M-? */ 0,
+ /* -64 M-@ */ 0,
+ /* -63 M-A */ 0,
+ /* -62 M-B */ 0,
+ /* -61 M-C */ 0,
+ /* -60 M-D */ 0,
+ /* -59 M-E */ 0,
+ /* -58 M-F */ 0,
+ /* -57 M-G */ 0,
+ /* -56 M-H */ 0,
+ /* -55 M-I */ 0,
+ /* -54 M-J */ 0,
+ /* -53 M-K */ 0,
+ /* -52 M-L */ 0,
+ /* -51 M-M */ 0,
+ /* -50 M-N */ 0,
+ /* -49 M-O */ 0,
+ /* -48 M-P */ 0,
+ /* -47 M-Q */ 0,
+ /* -46 M-R */ 0,
+ /* -45 M-S */ 0,
+ /* -44 M-T */ 0,
+ /* -43 M-U */ 0,
+ /* -42 M-V */ 0,
+ /* -41 M-W */ 0,
+ /* -40 M-X */ 0,
+ /* -39 M-Y */ 0,
+ /* -38 M-Z */ 0,
+ /* -37 M-[ */ 0,
+ /* -36 M-\ */ 0,
+ /* -35 M-] */ 0,
+ /* -34 M-^ */ 0,
+ /* -33 M-_ */ 0,
+ /* -32 M-` */ 0,
+ /* -31 M-a */ 0,
+ /* -30 M-b */ 0,
+ /* -29 M-c */ 0,
+ /* -28 M-d */ 0,
+ /* -27 M-e */ 0,
+ /* -26 M-f */ 0,
+ /* -25 M-g */ 0,
+ /* -24 M-h */ 0,
+ /* -23 M-i */ 0,
+ /* -22 M-j */ 0,
+ /* -21 M-k */ 0,
+ /* -20 M-l */ 0,
+ /* -19 M-m */ 0,
+ /* -18 M-n */ 0,
+ /* -17 M-o */ 0,
+ /* -16 M-p */ 0,
+ /* -15 M-q */ 0,
+ /* -14 M-r */ 0,
+ /* -13 M-s */ 0,
+ /* -12 M-t */ 0,
+ /* -11 M-u */ 0,
+ /* -10 M-v */ 0,
+ /* -9 M-w */ 0,
+ /* -8 M-x */ 0,
+ /* -7 M-y */ 0,
+ /* -6 M-z */ 0,
+ /* -5 M-{ */ 0,
+ /* -4 M-| */ 0,
+ /* -3 M-} */ 0,
+ /* -2 M-~ */ 0,
+#endif /* __UCLIBC_HAS_CTYPE_SIGNED__*/
+ /* -1 M-^? */ 0,
+ /* 0 ^@ */ _IScntrl,
+ /* 1 ^A */ _IScntrl,
+ /* 2 ^B */ _IScntrl,
+ /* 3 ^C */ _IScntrl,
+ /* 4 ^D */ _IScntrl,
+ /* 5 ^E */ _IScntrl,
+ /* 6 ^F */ _IScntrl,
+ /* 7 ^G */ _IScntrl,
+ /* 8 ^H */ _IScntrl,
+ /* 9 ^I */ _ISspace|_ISblank|_IScntrl,
+ /* 10 ^J */ _ISspace|_IScntrl,
+ /* 11 ^K */ _ISspace|_IScntrl,
+ /* 12 ^L */ _ISspace|_IScntrl,
+ /* 13 ^M */ _ISspace|_IScntrl,
+ /* 14 ^N */ _IScntrl,
+ /* 15 ^O */ _IScntrl,
+ /* 16 ^P */ _IScntrl,
+ /* 17 ^Q */ _IScntrl,
+ /* 18 ^R */ _IScntrl,
+ /* 19 ^S */ _IScntrl,
+ /* 20 ^T */ _IScntrl,
+ /* 21 ^U */ _IScntrl,
+ /* 22 ^V */ _IScntrl,
+ /* 23 ^W */ _IScntrl,
+ /* 24 ^X */ _IScntrl,
+ /* 25 ^Y */ _IScntrl,
+ /* 26 ^Z */ _IScntrl,
+ /* 27 ^[ */ _IScntrl,
+ /* 28 ^\ */ _IScntrl,
+ /* 29 ^] */ _IScntrl,
+ /* 30 ^^ */ _IScntrl,
+ /* 31 ^_ */ _IScntrl,
+ /* 32 */ _ISspace|_ISprint|_ISblank,
+ /* 33 ! */ _ISprint|_ISgraph|_ISpunct,
+ /* 34 " */ _ISprint|_ISgraph|_ISpunct,
+ /* 35 # */ _ISprint|_ISgraph|_ISpunct,
+ /* 36 $ */ _ISprint|_ISgraph|_ISpunct,
+ /* 37 % */ _ISprint|_ISgraph|_ISpunct,
+ /* 38 & */ _ISprint|_ISgraph|_ISpunct,
+ /* 39 ' */ _ISprint|_ISgraph|_ISpunct,
+ /* 40 ( */ _ISprint|_ISgraph|_ISpunct,
+ /* 41 ) */ _ISprint|_ISgraph|_ISpunct,
+ /* 42 * */ _ISprint|_ISgraph|_ISpunct,
+ /* 43 + */ _ISprint|_ISgraph|_ISpunct,
+ /* 44 , */ _ISprint|_ISgraph|_ISpunct,
+ /* 45 - */ _ISprint|_ISgraph|_ISpunct,
+ /* 46 . */ _ISprint|_ISgraph|_ISpunct,
+ /* 47 / */ _ISprint|_ISgraph|_ISpunct,
+ /* 48 0 */ _ISdigit|_ISxdigit|_ISprint|_ISgraph|_ISalnum,
+ /* 49 1 */ _ISdigit|_ISxdigit|_ISprint|_ISgraph|_ISalnum,
+ /* 50 2 */ _ISdigit|_ISxdigit|_ISprint|_ISgraph|_ISalnum,
+ /* 51 3 */ _ISdigit|_ISxdigit|_ISprint|_ISgraph|_ISalnum,
+ /* 52 4 */ _ISdigit|_ISxdigit|_ISprint|_ISgraph|_ISalnum,
+ /* 53 5 */ _ISdigit|_ISxdigit|_ISprint|_ISgraph|_ISalnum,
+ /* 54 6 */ _ISdigit|_ISxdigit|_ISprint|_ISgraph|_ISalnum,
+ /* 55 7 */ _ISdigit|_ISxdigit|_ISprint|_ISgraph|_ISalnum,
+ /* 56 8 */ _ISdigit|_ISxdigit|_ISprint|_ISgraph|_ISalnum,
+ /* 57 9 */ _ISdigit|_ISxdigit|_ISprint|_ISgraph|_ISalnum,
+ /* 58 : */ _ISprint|_ISgraph|_ISpunct,
+ /* 59 ; */ _ISprint|_ISgraph|_ISpunct,
+ /* 60 < */ _ISprint|_ISgraph|_ISpunct,
+ /* 61 = */ _ISprint|_ISgraph|_ISpunct,
+ /* 62 > */ _ISprint|_ISgraph|_ISpunct,
+ /* 63 ? */ _ISprint|_ISgraph|_ISpunct,
+ /* 64 @ */ _ISprint|_ISgraph|_ISpunct,
+ /* 65 A */ _ISupper|_ISalpha|_ISxdigit|_ISprint|_ISgraph|_ISalnum,
+ /* 66 B */ _ISupper|_ISalpha|_ISxdigit|_ISprint|_ISgraph|_ISalnum,
+ /* 67 C */ _ISupper|_ISalpha|_ISxdigit|_ISprint|_ISgraph|_ISalnum,
+ /* 68 D */ _ISupper|_ISalpha|_ISxdigit|_ISprint|_ISgraph|_ISalnum,
+ /* 69 E */ _ISupper|_ISalpha|_ISxdigit|_ISprint|_ISgraph|_ISalnum,
+ /* 70 F */ _ISupper|_ISalpha|_ISxdigit|_ISprint|_ISgraph|_ISalnum,
+ /* 71 G */ _ISupper|_ISalpha|_ISprint|_ISgraph|_ISalnum,
+ /* 72 H */ _ISupper|_ISalpha|_ISprint|_ISgraph|_ISalnum,
+ /* 73 I */ _ISupper|_ISalpha|_ISprint|_ISgraph|_ISalnum,
+ /* 74 J */ _ISupper|_ISalpha|_ISprint|_ISgraph|_ISalnum,
+ /* 75 K */ _ISupper|_ISalpha|_ISprint|_ISgraph|_ISalnum,
+ /* 76 L */ _ISupper|_ISalpha|_ISprint|_ISgraph|_ISalnum,
+ /* 77 M */ _ISupper|_ISalpha|_ISprint|_ISgraph|_ISalnum,
+ /* 78 N */ _ISupper|_ISalpha|_ISprint|_ISgraph|_ISalnum,
+ /* 79 O */ _ISupper|_ISalpha|_ISprint|_ISgraph|_ISalnum,
+ /* 80 P */ _ISupper|_ISalpha|_ISprint|_ISgraph|_ISalnum,
+ /* 81 Q */ _ISupper|_ISalpha|_ISprint|_ISgraph|_ISalnum,
+ /* 82 R */ _ISupper|_ISalpha|_ISprint|_ISgraph|_ISalnum,
+ /* 83 S */ _ISupper|_ISalpha|_ISprint|_ISgraph|_ISalnum,
+ /* 84 T */ _ISupper|_ISalpha|_ISprint|_ISgraph|_ISalnum,
+ /* 85 U */ _ISupper|_ISalpha|_ISprint|_ISgraph|_ISalnum,
+ /* 86 V */ _ISupper|_ISalpha|_ISprint|_ISgraph|_ISalnum,
+ /* 87 W */ _ISupper|_ISalpha|_ISprint|_ISgraph|_ISalnum,
+ /* 88 X */ _ISupper|_ISalpha|_ISprint|_ISgraph|_ISalnum,
+ /* 89 Y */ _ISupper|_ISalpha|_ISprint|_ISgraph|_ISalnum,
+ /* 90 Z */ _ISupper|_ISalpha|_ISprint|_ISgraph|_ISalnum,
+ /* 91 [ */ _ISprint|_ISgraph|_ISpunct,
+ /* 92 \ */ _ISprint|_ISgraph|_ISpunct,
+ /* 93 ] */ _ISprint|_ISgraph|_ISpunct,
+ /* 94 ^ */ _ISprint|_ISgraph|_ISpunct,
+ /* 95 _ */ _ISprint|_ISgraph|_ISpunct,
+ /* 96 ` */ _ISprint|_ISgraph|_ISpunct,
+ /* 97 a */ _ISlower|_ISalpha|_ISxdigit|_ISprint|_ISgraph|_ISalnum,
+ /* 98 b */ _ISlower|_ISalpha|_ISxdigit|_ISprint|_ISgraph|_ISalnum,
+ /* 99 c */ _ISlower|_ISalpha|_ISxdigit|_ISprint|_ISgraph|_ISalnum,
+ /* 100 d */ _ISlower|_ISalpha|_ISxdigit|_ISprint|_ISgraph|_ISalnum,
+ /* 101 e */ _ISlower|_ISalpha|_ISxdigit|_ISprint|_ISgraph|_ISalnum,
+ /* 102 f */ _ISlower|_ISalpha|_ISxdigit|_ISprint|_ISgraph|_ISalnum,
+ /* 103 g */ _ISlower|_ISalpha|_ISprint|_ISgraph|_ISalnum,
+ /* 104 h */ _ISlower|_ISalpha|_ISprint|_ISgraph|_ISalnum,
+ /* 105 i */ _ISlower|_ISalpha|_ISprint|_ISgraph|_ISalnum,
+ /* 106 j */ _ISlower|_ISalpha|_ISprint|_ISgraph|_ISalnum,
+ /* 107 k */ _ISlower|_ISalpha|_ISprint|_ISgraph|_ISalnum,
+ /* 108 l */ _ISlower|_ISalpha|_ISprint|_ISgraph|_ISalnum,
+ /* 109 m */ _ISlower|_ISalpha|_ISprint|_ISgraph|_ISalnum,
+ /* 110 n */ _ISlower|_ISalpha|_ISprint|_ISgraph|_ISalnum,
+ /* 111 o */ _ISlower|_ISalpha|_ISprint|_ISgraph|_ISalnum,
+ /* 112 p */ _ISlower|_ISalpha|_ISprint|_ISgraph|_ISalnum,
+ /* 113 q */ _ISlower|_ISalpha|_ISprint|_ISgraph|_ISalnum,
+ /* 114 r */ _ISlower|_ISalpha|_ISprint|_ISgraph|_ISalnum,
+ /* 115 s */ _ISlower|_ISalpha|_ISprint|_ISgraph|_ISalnum,
+ /* 116 t */ _ISlower|_ISalpha|_ISprint|_ISgraph|_ISalnum,
+ /* 117 u */ _ISlower|_ISalpha|_ISprint|_ISgraph|_ISalnum,
+ /* 118 v */ _ISlower|_ISalpha|_ISprint|_ISgraph|_ISalnum,
+ /* 119 w */ _ISlower|_ISalpha|_ISprint|_ISgraph|_ISalnum,
+ /* 120 x */ _ISlower|_ISalpha|_ISprint|_ISgraph|_ISalnum,
+ /* 121 y */ _ISlower|_ISalpha|_ISprint|_ISgraph|_ISalnum,
+ /* 122 z */ _ISlower|_ISalpha|_ISprint|_ISgraph|_ISalnum,
+ /* 123 { */ _ISprint|_ISgraph|_ISpunct,
+ /* 124 | */ _ISprint|_ISgraph|_ISpunct,
+ /* 125 } */ _ISprint|_ISgraph|_ISpunct,
+ /* 126 ~ */ _ISprint|_ISgraph|_ISpunct,
+ /* 127 ^? */ _IScntrl,
+ /* 128 M-^@ */ 0,
+ /* 129 M-^A */ 0,
+ /* 130 M-^B */ 0,
+ /* 131 M-^C */ 0,
+ /* 132 M-^D */ 0,
+ /* 133 M-^E */ 0,
+ /* 134 M-^F */ 0,
+ /* 135 M-^G */ 0,
+ /* 136 M-^H */ 0,
+ /* 137 M-^I */ 0,
+ /* 138 M-^J */ 0,
+ /* 139 M-^K */ 0,
+ /* 140 M-^L */ 0,
+ /* 141 M-^M */ 0,
+ /* 142 M-^N */ 0,
+ /* 143 M-^O */ 0,
+ /* 144 M-^P */ 0,
+ /* 145 M-^Q */ 0,
+ /* 146 M-^R */ 0,
+ /* 147 M-^S */ 0,
+ /* 148 M-^T */ 0,
+ /* 149 M-^U */ 0,
+ /* 150 M-^V */ 0,
+ /* 151 M-^W */ 0,
+ /* 152 M-^X */ 0,
+ /* 153 M-^Y */ 0,
+ /* 154 M-^Z */ 0,
+ /* 155 M-^[ */ 0,
+ /* 156 M-^\ */ 0,
+ /* 157 M-^] */ 0,
+ /* 158 M-^^ */ 0,
+ /* 159 M-^_ */ 0,
+ /* 160 M- */ 0,
+ /* 161 M-! */ 0,
+ /* 162 M-" */ 0,
+ /* 163 M-# */ 0,
+ /* 164 M-$ */ 0,
+ /* 165 M-% */ 0,
+ /* 166 M-& */ 0,
+ /* 167 M-' */ 0,
+ /* 168 M-( */ 0,
+ /* 169 M-) */ 0,
+ /* 170 M-* */ 0,
+ /* 171 M-+ */ 0,
+ /* 172 M-, */ 0,
+ /* 173 M-- */ 0,
+ /* 174 M-. */ 0,
+ /* 175 M-/ */ 0,
+ /* 176 M-0 */ 0,
+ /* 177 M-1 */ 0,
+ /* 178 M-2 */ 0,
+ /* 179 M-3 */ 0,
+ /* 180 M-4 */ 0,
+ /* 181 M-5 */ 0,
+ /* 182 M-6 */ 0,
+ /* 183 M-7 */ 0,
+ /* 184 M-8 */ 0,
+ /* 185 M-9 */ 0,
+ /* 186 M-: */ 0,
+ /* 187 M-; */ 0,
+ /* 188 M-< */ 0,
+ /* 189 M-= */ 0,
+ /* 190 M-> */ 0,
+ /* 191 M-? */ 0,
+ /* 192 M-@ */ 0,
+ /* 193 M-A */ 0,
+ /* 194 M-B */ 0,
+ /* 195 M-C */ 0,
+ /* 196 M-D */ 0,
+ /* 197 M-E */ 0,
+ /* 198 M-F */ 0,
+ /* 199 M-G */ 0,
+ /* 200 M-H */ 0,
+ /* 201 M-I */ 0,
+ /* 202 M-J */ 0,
+ /* 203 M-K */ 0,
+ /* 204 M-L */ 0,
+ /* 205 M-M */ 0,
+ /* 206 M-N */ 0,
+ /* 207 M-O */ 0,
+ /* 208 M-P */ 0,
+ /* 209 M-Q */ 0,
+ /* 210 M-R */ 0,
+ /* 211 M-S */ 0,
+ /* 212 M-T */ 0,
+ /* 213 M-U */ 0,
+ /* 214 M-V */ 0,
+ /* 215 M-W */ 0,
+ /* 216 M-X */ 0,
+ /* 217 M-Y */ 0,
+ /* 218 M-Z */ 0,
+ /* 219 M-[ */ 0,
+ /* 220 M-\ */ 0,
+ /* 221 M-] */ 0,
+ /* 222 M-^ */ 0,
+ /* 223 M-_ */ 0,
+ /* 224 M-` */ 0,
+ /* 225 M-a */ 0,
+ /* 226 M-b */ 0,
+ /* 227 M-c */ 0,
+ /* 228 M-d */ 0,
+ /* 229 M-e */ 0,
+ /* 230 M-f */ 0,
+ /* 231 M-g */ 0,
+ /* 232 M-h */ 0,
+ /* 233 M-i */ 0,
+ /* 234 M-j */ 0,
+ /* 235 M-k */ 0,
+ /* 236 M-l */ 0,
+ /* 237 M-m */ 0,
+ /* 238 M-n */ 0,
+ /* 239 M-o */ 0,
+ /* 240 M-p */ 0,
+ /* 241 M-q */ 0,
+ /* 242 M-r */ 0,
+ /* 243 M-s */ 0,
+ /* 244 M-t */ 0,
+ /* 245 M-u */ 0,
+ /* 246 M-v */ 0,
+ /* 247 M-w */ 0,
+ /* 248 M-x */ 0,
+ /* 249 M-y */ 0,
+ /* 250 M-z */ 0,
+ /* 251 M-{ */ 0,
+ /* 252 M-| */ 0,
+ /* 253 M-} */ 0,
+ /* 254 M-~ */ 0,
+ /* 255 M-^? */ 0
+};
+
+const __ctype_mask_t *__C_ctype_b = __C_ctype_b_data + __UCLIBC_CTYPE_B_TBL_OFFSET;
+libc_hidden_data_def(__C_ctype_b)
+
+#ifndef __UCLIBC_HAS_XLOCALE__
+
+const __ctype_mask_t *__ctype_b = __C_ctype_b_data + __UCLIBC_CTYPE_B_TBL_OFFSET;
+libc_hidden_data_def(__ctype_b)
+
+#endif
+
+#endif
+/**********************************************************************/
+#ifdef L___C_ctype_tolower
+
+static const __ctype_touplow_t __C_ctype_tolower_data[] = {
+#ifdef __UCLIBC_HAS_CTYPE_SIGNED__
+ -128, -127, -126, -125,
+ -124, -123, -122, -121,
+ -120, -119, -118, -117,
+ -116, -115, -114, -113,
+ -112, -111, -110, -109,
+ -108, -107, -106, -105,
+ -104, -103, -102, -101,
+ -100, -99, -98, -97,
+ -96, -95, -94, -93,
+ -92, -91, -90, -89,
+ -88, -87, -86, -85,
+ -84, -83, -82, -81,
+ -80, -79, -78, -77,
+ -76, -75, -74, -73,
+ -72, -71, -70, -69,
+ -68, -67, -66, -65,
+ -64, -63, -62, -61,
+ -60, -59, -58, -57,
+ -56, -55, -54, -53,
+ -52, -51, -50, -49,
+ -48, -47, -46, -45,
+ -44, -43, -42, -41,
+ -40, -39, -38, -37,
+ -36, -35, -34, -33,
+ -32, -31, -30, -29,
+ -28, -27, -26, -25,
+ -24, -23, -22, -21,
+ -20, -19, -18, -17,
+ -16, -15, -14, -13,
+ -12, -11, -10, -9,
+ -8, -7, -6, -5,
+ -4, -3, -2, -1,
+#endif /* __UCLIBC_HAS_CTYPE_SIGNED__*/
+ 0, 1, 2, 3,
+ 4, 5, 6, 7,
+ 8, 9, 10, 11,
+ 12, 13, 14, 15,
+ 16, 17, 18, 19,
+ 20, 21, 22, 23,
+ 24, 25, 26, 27,
+ 28, 29, 30, 31,
+ 32, 33, 34, 35,
+ 36, 37, 38, 39,
+ 40, 41, 42, 43,
+ 44, 45, 46, 47,
+ 48, 49, 50, 51,
+ 52, 53, 54, 55,
+ 56, 57, 58, 59,
+ 60, 61, 62, 63,
+ 64, 97 /* a */, 98 /* b */, 99 /* c */,
+ 100 /* d */, 101 /* e */, 102 /* f */, 103 /* g */,
+ 104 /* h */, 105 /* i */, 106 /* j */, 107 /* k */,
+ 108 /* l */, 109 /* m */, 110 /* n */, 111 /* o */,
+ 112 /* p */, 113 /* q */, 114 /* r */, 115 /* s */,
+ 116 /* t */, 117 /* u */, 118 /* v */, 119 /* w */,
+ 120 /* x */, 121 /* y */, 122 /* z */, 91,
+ 92, 93, 94, 95,
+ 96, 97, 98, 99,
+ 100, 101, 102, 103,
+ 104, 105, 106, 107,
+ 108, 109, 110, 111,
+ 112, 113, 114, 115,
+ 116, 117, 118, 119,
+ 120, 121, 122, 123,
+ 124, 125, 126, 127,
+ 128, 129, 130, 131,
+ 132, 133, 134, 135,
+ 136, 137, 138, 139,
+ 140, 141, 142, 143,
+ 144, 145, 146, 147,
+ 148, 149, 150, 151,
+ 152, 153, 154, 155,
+ 156, 157, 158, 159,
+ 160, 161, 162, 163,
+ 164, 165, 166, 167,
+ 168, 169, 170, 171,
+ 172, 173, 174, 175,
+ 176, 177, 178, 179,
+ 180, 181, 182, 183,
+ 184, 185, 186, 187,
+ 188, 189, 190, 191,
+ 192, 193, 194, 195,
+ 196, 197, 198, 199,
+ 200, 201, 202, 203,
+ 204, 205, 206, 207,
+ 208, 209, 210, 211,
+ 212, 213, 214, 215,
+ 216, 217, 218, 219,
+ 220, 221, 222, 223,
+ 224, 225, 226, 227,
+ 228, 229, 230, 231,
+ 232, 233, 234, 235,
+ 236, 237, 238, 239,
+ 240, 241, 242, 243,
+ 244, 245, 246, 247,
+ 248, 249, 250, 251,
+ 252, 253, 254, 255
+};
+
+const __ctype_touplow_t *__C_ctype_tolower =
+ __C_ctype_tolower_data + __UCLIBC_CTYPE_TO_TBL_OFFSET;
+libc_hidden_data_def(__C_ctype_tolower)
+
+#ifndef __UCLIBC_HAS_XLOCALE__
+
+const __ctype_touplow_t *__ctype_tolower =
+ __C_ctype_tolower_data + __UCLIBC_CTYPE_TO_TBL_OFFSET;
+libc_hidden_data_def(__ctype_tolower)
+
+#endif
+
+#endif
+/**********************************************************************/
+#ifdef L___C_ctype_toupper
+
+static const __ctype_touplow_t __C_ctype_toupper_data[] = {
+#ifdef __UCLIBC_HAS_CTYPE_SIGNED__
+ -128, -127, -126, -125,
+ -124, -123, -122, -121,
+ -120, -119, -118, -117,
+ -116, -115, -114, -113,
+ -112, -111, -110, -109,
+ -108, -107, -106, -105,
+ -104, -103, -102, -101,
+ -100, -99, -98, -97,
+ -96, -95, -94, -93,
+ -92, -91, -90, -89,
+ -88, -87, -86, -85,
+ -84, -83, -82, -81,
+ -80, -79, -78, -77,
+ -76, -75, -74, -73,
+ -72, -71, -70, -69,
+ -68, -67, -66, -65,
+ -64, -63, -62, -61,
+ -60, -59, -58, -57,
+ -56, -55, -54, -53,
+ -52, -51, -50, -49,
+ -48, -47, -46, -45,
+ -44, -43, -42, -41,
+ -40, -39, -38, -37,
+ -36, -35, -34, -33,
+ -32, -31, -30, -29,
+ -28, -27, -26, -25,
+ -24, -23, -22, -21,
+ -20, -19, -18, -17,
+ -16, -15, -14, -13,
+ -12, -11, -10, -9,
+ -8, -7, -6, -5,
+ -4, -3, -2, -1,
+#endif /* __UCLIBC_HAS_CTYPE_SIGNED__*/
+ 0, 1, 2, 3,
+ 4, 5, 6, 7,
+ 8, 9, 10, 11,
+ 12, 13, 14, 15,
+ 16, 17, 18, 19,
+ 20, 21, 22, 23,
+ 24, 25, 26, 27,
+ 28, 29, 30, 31,
+ 32, 33, 34, 35,
+ 36, 37, 38, 39,
+ 40, 41, 42, 43,
+ 44, 45, 46, 47,
+ 48, 49, 50, 51,
+ 52, 53, 54, 55,
+ 56, 57, 58, 59,
+ 60, 61, 62, 63,
+ 64, 65, 66, 67,
+ 68, 69, 70, 71,
+ 72, 73, 74, 75,
+ 76, 77, 78, 79,
+ 80, 81, 82, 83,
+ 84, 85, 86, 87,
+ 88, 89, 90, 91,
+ 92, 93, 94, 95,
+ 96, 65 /* A */, 66 /* B */, 67 /* C */,
+ 68 /* D */, 69 /* E */, 70 /* F */, 71 /* G */,
+ 72 /* H */, 73 /* I */, 74 /* J */, 75 /* K */,
+ 76 /* L */, 77 /* M */, 78 /* N */, 79 /* O */,
+ 80 /* P */, 81 /* Q */, 82 /* R */, 83 /* S */,
+ 84 /* T */, 85 /* U */, 86 /* V */, 87 /* W */,
+ 88 /* X */, 89 /* Y */, 90 /* Z */, 123,
+ 124, 125, 126, 127,
+ 128, 129, 130, 131,
+ 132, 133, 134, 135,
+ 136, 137, 138, 139,
+ 140, 141, 142, 143,
+ 144, 145, 146, 147,
+ 148, 149, 150, 151,
+ 152, 153, 154, 155,
+ 156, 157, 158, 159,
+ 160, 161, 162, 163,
+ 164, 165, 166, 167,
+ 168, 169, 170, 171,
+ 172, 173, 174, 175,
+ 176, 177, 178, 179,
+ 180, 181, 182, 183,
+ 184, 185, 186, 187,
+ 188, 189, 190, 191,
+ 192, 193, 194, 195,
+ 196, 197, 198, 199,
+ 200, 201, 202, 203,
+ 204, 205, 206, 207,
+ 208, 209, 210, 211,
+ 212, 213, 214, 215,
+ 216, 217, 218, 219,
+ 220, 221, 222, 223,
+ 224, 225, 226, 227,
+ 228, 229, 230, 231,
+ 232, 233, 234, 235,
+ 236, 237, 238, 239,
+ 240, 241, 242, 243,
+ 244, 245, 246, 247,
+ 248, 249, 250, 251,
+ 252, 253, 254, 255
+};
+
+const __ctype_touplow_t *__C_ctype_toupper =
+ __C_ctype_toupper_data + __UCLIBC_CTYPE_TO_TBL_OFFSET;
+libc_hidden_data_def(__C_ctype_toupper)
+
+#ifndef __UCLIBC_HAS_XLOCALE__
+
+const __ctype_touplow_t *__ctype_toupper =
+ __C_ctype_toupper_data + __UCLIBC_CTYPE_TO_TBL_OFFSET;
+libc_hidden_data_def(__ctype_toupper)
+
+#endif
+
+#endif
+/**********************************************************************/
diff --git a/ap/build/uClibc/libc/misc/ctype/isalnum.c b/ap/build/uClibc/libc/misc/ctype/isalnum.c
new file mode 100644
index 0000000..8bc8ad6
--- /dev/null
+++ b/ap/build/uClibc/libc/misc/ctype/isalnum.c
@@ -0,0 +1,8 @@
+/*
+ * Copyright (C) 2003-2006 Manuel Novoa III <mjn3@uclibc.org>
+ *
+ * Licensed under the LGPL v2.1, see the file COPYING.LIB in this tarball.
+ */
+
+#define L_isalnum
+#include "ctype.c"
diff --git a/ap/build/uClibc/libc/misc/ctype/isalnum_l.c b/ap/build/uClibc/libc/misc/ctype/isalnum_l.c
new file mode 100644
index 0000000..8ecd9d5
--- /dev/null
+++ b/ap/build/uClibc/libc/misc/ctype/isalnum_l.c
@@ -0,0 +1,9 @@
+/*
+ * Copyright (C) 2003-2006 Manuel Novoa III <mjn3@uclibc.org>
+ *
+ * Licensed under the LGPL v2.1, see the file COPYING.LIB in this tarball.
+ */
+
+#define L_isalnum_l
+#define __UCLIBC_DO_XLOCALE
+#include "ctype.c"
diff --git a/ap/build/uClibc/libc/misc/ctype/isalpha.c b/ap/build/uClibc/libc/misc/ctype/isalpha.c
new file mode 100644
index 0000000..22f23d9
--- /dev/null
+++ b/ap/build/uClibc/libc/misc/ctype/isalpha.c
@@ -0,0 +1,8 @@
+/*
+ * Copyright (C) 2003-2006 Manuel Novoa III <mjn3@uclibc.org>
+ *
+ * Licensed under the LGPL v2.1, see the file COPYING.LIB in this tarball.
+ */
+
+#define L_isalpha
+#include "ctype.c"
diff --git a/ap/build/uClibc/libc/misc/ctype/isalpha_l.c b/ap/build/uClibc/libc/misc/ctype/isalpha_l.c
new file mode 100644
index 0000000..10a2ecf
--- /dev/null
+++ b/ap/build/uClibc/libc/misc/ctype/isalpha_l.c
@@ -0,0 +1,9 @@
+/*
+ * Copyright (C) 2003-2006 Manuel Novoa III <mjn3@uclibc.org>
+ *
+ * Licensed under the LGPL v2.1, see the file COPYING.LIB in this tarball.
+ */
+
+#define L_isalpha_l
+#define __UCLIBC_DO_XLOCALE
+#include "ctype.c"
diff --git a/ap/build/uClibc/libc/misc/ctype/isascii.c b/ap/build/uClibc/libc/misc/ctype/isascii.c
new file mode 100644
index 0000000..84f701f
--- /dev/null
+++ b/ap/build/uClibc/libc/misc/ctype/isascii.c
@@ -0,0 +1,8 @@
+/*
+ * Copyright (C) 2003-2006 Manuel Novoa III <mjn3@uclibc.org>
+ *
+ * Licensed under the LGPL v2.1, see the file COPYING.LIB in this tarball.
+ */
+
+#define L_isascii
+#include "ctype.c"
diff --git a/ap/build/uClibc/libc/misc/ctype/isascii_l.c b/ap/build/uClibc/libc/misc/ctype/isascii_l.c
new file mode 100644
index 0000000..7fe5545
--- /dev/null
+++ b/ap/build/uClibc/libc/misc/ctype/isascii_l.c
@@ -0,0 +1,9 @@
+/*
+ * Copyright (C) 2003-2006 Manuel Novoa III <mjn3@uclibc.org>
+ *
+ * Licensed under the LGPL v2.1, see the file COPYING.LIB in this tarball.
+ */
+
+#define L_isascii_l
+#define __UCLIBC_DO_XLOCALE
+#include "ctype.c"
diff --git a/ap/build/uClibc/libc/misc/ctype/isblank.c b/ap/build/uClibc/libc/misc/ctype/isblank.c
new file mode 100644
index 0000000..d11fe26
--- /dev/null
+++ b/ap/build/uClibc/libc/misc/ctype/isblank.c
@@ -0,0 +1,8 @@
+/*
+ * Copyright (C) 2003-2006 Manuel Novoa III <mjn3@uclibc.org>
+ *
+ * Licensed under the LGPL v2.1, see the file COPYING.LIB in this tarball.
+ */
+
+#define L_isblank
+#include "ctype.c"
diff --git a/ap/build/uClibc/libc/misc/ctype/isblank_l.c b/ap/build/uClibc/libc/misc/ctype/isblank_l.c
new file mode 100644
index 0000000..144cd93
--- /dev/null
+++ b/ap/build/uClibc/libc/misc/ctype/isblank_l.c
@@ -0,0 +1,9 @@
+/*
+ * Copyright (C) 2003-2006 Manuel Novoa III <mjn3@uclibc.org>
+ *
+ * Licensed under the LGPL v2.1, see the file COPYING.LIB in this tarball.
+ */
+
+#define L_isblank_l
+#define __UCLIBC_DO_XLOCALE
+#include "ctype.c"
diff --git a/ap/build/uClibc/libc/misc/ctype/iscntrl.c b/ap/build/uClibc/libc/misc/ctype/iscntrl.c
new file mode 100644
index 0000000..4a0c09d
--- /dev/null
+++ b/ap/build/uClibc/libc/misc/ctype/iscntrl.c
@@ -0,0 +1,8 @@
+/*
+ * Copyright (C) 2003-2006 Manuel Novoa III <mjn3@uclibc.org>
+ *
+ * Licensed under the LGPL v2.1, see the file COPYING.LIB in this tarball.
+ */
+
+#define L_iscntrl
+#include "ctype.c"
diff --git a/ap/build/uClibc/libc/misc/ctype/iscntrl_l.c b/ap/build/uClibc/libc/misc/ctype/iscntrl_l.c
new file mode 100644
index 0000000..fbee951
--- /dev/null
+++ b/ap/build/uClibc/libc/misc/ctype/iscntrl_l.c
@@ -0,0 +1,9 @@
+/*
+ * Copyright (C) 2003-2006 Manuel Novoa III <mjn3@uclibc.org>
+ *
+ * Licensed under the LGPL v2.1, see the file COPYING.LIB in this tarball.
+ */
+
+#define L_iscntrl_l
+#define __UCLIBC_DO_XLOCALE
+#include "ctype.c"
diff --git a/ap/build/uClibc/libc/misc/ctype/isctype.c b/ap/build/uClibc/libc/misc/ctype/isctype.c
new file mode 100644
index 0000000..a2d0b3d
--- /dev/null
+++ b/ap/build/uClibc/libc/misc/ctype/isctype.c
@@ -0,0 +1,8 @@
+/*
+ * Copyright (C) 2003-2006 Manuel Novoa III <mjn3@uclibc.org>
+ *
+ * Licensed under the LGPL v2.1, see the file COPYING.LIB in this tarball.
+ */
+
+#define L_isctype
+#include "ctype.c"
diff --git a/ap/build/uClibc/libc/misc/ctype/isdigit.c b/ap/build/uClibc/libc/misc/ctype/isdigit.c
new file mode 100644
index 0000000..e185c89
--- /dev/null
+++ b/ap/build/uClibc/libc/misc/ctype/isdigit.c
@@ -0,0 +1,8 @@
+/*
+ * Copyright (C) 2003-2006 Manuel Novoa III <mjn3@uclibc.org>
+ *
+ * Licensed under the LGPL v2.1, see the file COPYING.LIB in this tarball.
+ */
+
+#define L_isdigit
+#include "ctype.c"
diff --git a/ap/build/uClibc/libc/misc/ctype/isdigit_l.c b/ap/build/uClibc/libc/misc/ctype/isdigit_l.c
new file mode 100644
index 0000000..5b764f1
--- /dev/null
+++ b/ap/build/uClibc/libc/misc/ctype/isdigit_l.c
@@ -0,0 +1,9 @@
+/*
+ * Copyright (C) 2003-2006 Manuel Novoa III <mjn3@uclibc.org>
+ *
+ * Licensed under the LGPL v2.1, see the file COPYING.LIB in this tarball.
+ */
+
+#define L_isdigit_l
+#define __UCLIBC_DO_XLOCALE
+#include "ctype.c"
diff --git a/ap/build/uClibc/libc/misc/ctype/isgraph.c b/ap/build/uClibc/libc/misc/ctype/isgraph.c
new file mode 100644
index 0000000..c4ad1b7
--- /dev/null
+++ b/ap/build/uClibc/libc/misc/ctype/isgraph.c
@@ -0,0 +1,8 @@
+/*
+ * Copyright (C) 2003-2006 Manuel Novoa III <mjn3@uclibc.org>
+ *
+ * Licensed under the LGPL v2.1, see the file COPYING.LIB in this tarball.
+ */
+
+#define L_isgraph
+#include "ctype.c"
diff --git a/ap/build/uClibc/libc/misc/ctype/isgraph_l.c b/ap/build/uClibc/libc/misc/ctype/isgraph_l.c
new file mode 100644
index 0000000..005e19f
--- /dev/null
+++ b/ap/build/uClibc/libc/misc/ctype/isgraph_l.c
@@ -0,0 +1,9 @@
+/*
+ * Copyright (C) 2003-2006 Manuel Novoa III <mjn3@uclibc.org>
+ *
+ * Licensed under the LGPL v2.1, see the file COPYING.LIB in this tarball.
+ */
+
+#define L_isgraph_l
+#define __UCLIBC_DO_XLOCALE
+#include "ctype.c"
diff --git a/ap/build/uClibc/libc/misc/ctype/islower.c b/ap/build/uClibc/libc/misc/ctype/islower.c
new file mode 100644
index 0000000..aff65dd
--- /dev/null
+++ b/ap/build/uClibc/libc/misc/ctype/islower.c
@@ -0,0 +1,8 @@
+/*
+ * Copyright (C) 2003-2006 Manuel Novoa III <mjn3@uclibc.org>
+ *
+ * Licensed under the LGPL v2.1, see the file COPYING.LIB in this tarball.
+ */
+
+#define L_islower
+#include "ctype.c"
diff --git a/ap/build/uClibc/libc/misc/ctype/islower_l.c b/ap/build/uClibc/libc/misc/ctype/islower_l.c
new file mode 100644
index 0000000..dd08557
--- /dev/null
+++ b/ap/build/uClibc/libc/misc/ctype/islower_l.c
@@ -0,0 +1,9 @@
+/*
+ * Copyright (C) 2003-2006 Manuel Novoa III <mjn3@uclibc.org>
+ *
+ * Licensed under the LGPL v2.1, see the file COPYING.LIB in this tarball.
+ */
+
+#define L_islower_l
+#define __UCLIBC_DO_XLOCALE
+#include "ctype.c"
diff --git a/ap/build/uClibc/libc/misc/ctype/isprint.c b/ap/build/uClibc/libc/misc/ctype/isprint.c
new file mode 100644
index 0000000..b6f7d6c
--- /dev/null
+++ b/ap/build/uClibc/libc/misc/ctype/isprint.c
@@ -0,0 +1,8 @@
+/*
+ * Copyright (C) 2003-2006 Manuel Novoa III <mjn3@uclibc.org>
+ *
+ * Licensed under the LGPL v2.1, see the file COPYING.LIB in this tarball.
+ */
+
+#define L_isprint
+#include "ctype.c"
diff --git a/ap/build/uClibc/libc/misc/ctype/isprint_l.c b/ap/build/uClibc/libc/misc/ctype/isprint_l.c
new file mode 100644
index 0000000..32f9b3f
--- /dev/null
+++ b/ap/build/uClibc/libc/misc/ctype/isprint_l.c
@@ -0,0 +1,9 @@
+/*
+ * Copyright (C) 2003-2006 Manuel Novoa III <mjn3@uclibc.org>
+ *
+ * Licensed under the LGPL v2.1, see the file COPYING.LIB in this tarball.
+ */
+
+#define L_isprint_l
+#define __UCLIBC_DO_XLOCALE
+#include "ctype.c"
diff --git a/ap/build/uClibc/libc/misc/ctype/ispunct.c b/ap/build/uClibc/libc/misc/ctype/ispunct.c
new file mode 100644
index 0000000..08f7b19
--- /dev/null
+++ b/ap/build/uClibc/libc/misc/ctype/ispunct.c
@@ -0,0 +1,8 @@
+/*
+ * Copyright (C) 2003-2006 Manuel Novoa III <mjn3@uclibc.org>
+ *
+ * Licensed under the LGPL v2.1, see the file COPYING.LIB in this tarball.
+ */
+
+#define L_ispunct
+#include "ctype.c"
diff --git a/ap/build/uClibc/libc/misc/ctype/ispunct_l.c b/ap/build/uClibc/libc/misc/ctype/ispunct_l.c
new file mode 100644
index 0000000..513bb52
--- /dev/null
+++ b/ap/build/uClibc/libc/misc/ctype/ispunct_l.c
@@ -0,0 +1,9 @@
+/*
+ * Copyright (C) 2003-2006 Manuel Novoa III <mjn3@uclibc.org>
+ *
+ * Licensed under the LGPL v2.1, see the file COPYING.LIB in this tarball.
+ */
+
+#define L_ispunct_l
+#define __UCLIBC_DO_XLOCALE
+#include "ctype.c"
diff --git a/ap/build/uClibc/libc/misc/ctype/isspace.c b/ap/build/uClibc/libc/misc/ctype/isspace.c
new file mode 100644
index 0000000..c8ff567
--- /dev/null
+++ b/ap/build/uClibc/libc/misc/ctype/isspace.c
@@ -0,0 +1,8 @@
+/*
+ * Copyright (C) 2003-2006 Manuel Novoa III <mjn3@uclibc.org>
+ *
+ * Licensed under the LGPL v2.1, see the file COPYING.LIB in this tarball.
+ */
+
+#define L_isspace
+#include "ctype.c"
diff --git a/ap/build/uClibc/libc/misc/ctype/isspace_l.c b/ap/build/uClibc/libc/misc/ctype/isspace_l.c
new file mode 100644
index 0000000..97e0c99
--- /dev/null
+++ b/ap/build/uClibc/libc/misc/ctype/isspace_l.c
@@ -0,0 +1,9 @@
+/*
+ * Copyright (C) 2003-2006 Manuel Novoa III <mjn3@uclibc.org>
+ *
+ * Licensed under the LGPL v2.1, see the file COPYING.LIB in this tarball.
+ */
+
+#define L_isspace_l
+#define __UCLIBC_DO_XLOCALE
+#include "ctype.c"
diff --git a/ap/build/uClibc/libc/misc/ctype/isupper.c b/ap/build/uClibc/libc/misc/ctype/isupper.c
new file mode 100644
index 0000000..36d6e6e
--- /dev/null
+++ b/ap/build/uClibc/libc/misc/ctype/isupper.c
@@ -0,0 +1,8 @@
+/*
+ * Copyright (C) 2003-2006 Manuel Novoa III <mjn3@uclibc.org>
+ *
+ * Licensed under the LGPL v2.1, see the file COPYING.LIB in this tarball.
+ */
+
+#define L_isupper
+#include "ctype.c"
diff --git a/ap/build/uClibc/libc/misc/ctype/isupper_l.c b/ap/build/uClibc/libc/misc/ctype/isupper_l.c
new file mode 100644
index 0000000..8aa4dbd
--- /dev/null
+++ b/ap/build/uClibc/libc/misc/ctype/isupper_l.c
@@ -0,0 +1,9 @@
+/*
+ * Copyright (C) 2003-2006 Manuel Novoa III <mjn3@uclibc.org>
+ *
+ * Licensed under the LGPL v2.1, see the file COPYING.LIB in this tarball.
+ */
+
+#define L_isupper_l
+#define __UCLIBC_DO_XLOCALE
+#include "ctype.c"
diff --git a/ap/build/uClibc/libc/misc/ctype/isxdigit.c b/ap/build/uClibc/libc/misc/ctype/isxdigit.c
new file mode 100644
index 0000000..40919f7
--- /dev/null
+++ b/ap/build/uClibc/libc/misc/ctype/isxdigit.c
@@ -0,0 +1,8 @@
+/*
+ * Copyright (C) 2003-2006 Manuel Novoa III <mjn3@uclibc.org>
+ *
+ * Licensed under the LGPL v2.1, see the file COPYING.LIB in this tarball.
+ */
+
+#define L_isxdigit
+#include "ctype.c"
diff --git a/ap/build/uClibc/libc/misc/ctype/isxdigit_l.c b/ap/build/uClibc/libc/misc/ctype/isxdigit_l.c
new file mode 100644
index 0000000..5dce7f1
--- /dev/null
+++ b/ap/build/uClibc/libc/misc/ctype/isxdigit_l.c
@@ -0,0 +1,9 @@
+/*
+ * Copyright (C) 2003-2006 Manuel Novoa III <mjn3@uclibc.org>
+ *
+ * Licensed under the LGPL v2.1, see the file COPYING.LIB in this tarball.
+ */
+
+#define L_isxdigit_l
+#define __UCLIBC_DO_XLOCALE
+#include "ctype.c"
diff --git a/ap/build/uClibc/libc/misc/ctype/toascii.c b/ap/build/uClibc/libc/misc/ctype/toascii.c
new file mode 100644
index 0000000..a63b993
--- /dev/null
+++ b/ap/build/uClibc/libc/misc/ctype/toascii.c
@@ -0,0 +1,8 @@
+/*
+ * Copyright (C) 2003-2006 Manuel Novoa III <mjn3@uclibc.org>
+ *
+ * Licensed under the LGPL v2.1, see the file COPYING.LIB in this tarball.
+ */
+
+#define L_toascii
+#include "ctype.c"
diff --git a/ap/build/uClibc/libc/misc/ctype/toascii_l.c b/ap/build/uClibc/libc/misc/ctype/toascii_l.c
new file mode 100644
index 0000000..6179526
--- /dev/null
+++ b/ap/build/uClibc/libc/misc/ctype/toascii_l.c
@@ -0,0 +1,9 @@
+/*
+ * Copyright (C) 2003-2006 Manuel Novoa III <mjn3@uclibc.org>
+ *
+ * Licensed under the LGPL v2.1, see the file COPYING.LIB in this tarball.
+ */
+
+#define L_toascii_l
+#define __UCLIBC_DO_XLOCALE
+#include "ctype.c"
diff --git a/ap/build/uClibc/libc/misc/ctype/tolower.c b/ap/build/uClibc/libc/misc/ctype/tolower.c
new file mode 100644
index 0000000..3673642
--- /dev/null
+++ b/ap/build/uClibc/libc/misc/ctype/tolower.c
@@ -0,0 +1,8 @@
+/*
+ * Copyright (C) 2003-2006 Manuel Novoa III <mjn3@uclibc.org>
+ *
+ * Licensed under the LGPL v2.1, see the file COPYING.LIB in this tarball.
+ */
+
+#define L_tolower
+#include "ctype.c"
diff --git a/ap/build/uClibc/libc/misc/ctype/tolower_l.c b/ap/build/uClibc/libc/misc/ctype/tolower_l.c
new file mode 100644
index 0000000..327e63c
--- /dev/null
+++ b/ap/build/uClibc/libc/misc/ctype/tolower_l.c
@@ -0,0 +1,9 @@
+/*
+ * Copyright (C) 2003-2006 Manuel Novoa III <mjn3@uclibc.org>
+ *
+ * Licensed under the LGPL v2.1, see the file COPYING.LIB in this tarball.
+ */
+
+#define L_tolower_l
+#define __UCLIBC_DO_XLOCALE
+#include "ctype.c"
diff --git a/ap/build/uClibc/libc/misc/ctype/toupper.c b/ap/build/uClibc/libc/misc/ctype/toupper.c
new file mode 100644
index 0000000..a9d8aab
--- /dev/null
+++ b/ap/build/uClibc/libc/misc/ctype/toupper.c
@@ -0,0 +1,8 @@
+/*
+ * Copyright (C) 2003-2006 Manuel Novoa III <mjn3@uclibc.org>
+ *
+ * Licensed under the LGPL v2.1, see the file COPYING.LIB in this tarball.
+ */
+
+#define L_toupper
+#include "ctype.c"
diff --git a/ap/build/uClibc/libc/misc/ctype/toupper_l.c b/ap/build/uClibc/libc/misc/ctype/toupper_l.c
new file mode 100644
index 0000000..c91d791
--- /dev/null
+++ b/ap/build/uClibc/libc/misc/ctype/toupper_l.c
@@ -0,0 +1,9 @@
+/*
+ * Copyright (C) 2003-2006 Manuel Novoa III <mjn3@uclibc.org>
+ *
+ * Licensed under the LGPL v2.1, see the file COPYING.LIB in this tarball.
+ */
+
+#define L_toupper_l
+#define __UCLIBC_DO_XLOCALE
+#include "ctype.c"
diff --git a/ap/build/uClibc/libc/misc/dirent/Makefile b/ap/build/uClibc/libc/misc/dirent/Makefile
new file mode 100644
index 0000000..4a8f4a0
--- /dev/null
+++ b/ap/build/uClibc/libc/misc/dirent/Makefile
@@ -0,0 +1,13 @@
+# Makefile for uClibc
+#
+# Copyright (C) 2000-2005 Erik Andersen <andersen@uclibc.org>
+#
+# Licensed under the LGPL v2.1, see the file COPYING.LIB in this tarball.
+#
+
+top_srcdir=../../../
+top_builddir=../../../
+all: objs
+include $(top_builddir)Rules.mak
+include Makefile.in
+include $(top_srcdir)Makerules
diff --git a/ap/build/uClibc/libc/misc/dirent/Makefile.in b/ap/build/uClibc/libc/misc/dirent/Makefile.in
new file mode 100644
index 0000000..d42dfeb
--- /dev/null
+++ b/ap/build/uClibc/libc/misc/dirent/Makefile.in
@@ -0,0 +1,28 @@
+# Makefile for uClibc
+#
+# Copyright (C) 2000-2008 Erik Andersen <andersen@uclibc.org>
+#
+# Licensed under the LGPL v2.1, see the file COPYING.LIB in this tarball.
+#
+
+subdirs += libc/misc/dirent
+
+CSRC := alphasort.c closedir.c dirfd.c opendir.c readdir.c rewinddir.c \
+ scandir.c seekdir.c telldir.c readdir_r.c versionsort.c
+
+ifeq ($(UCLIBC_HAS_LFS),y)
+CSRC += readdir64.c alphasort64.c scandir64.c readdir64_r.c versionsort64.c
+endif
+
+MISC_DIRENT_DIR := $(top_srcdir)libc/misc/dirent
+MISC_DIRENT_OUT := $(top_builddir)libc/misc/dirent
+
+MISC_DIRENT_SRC := $(patsubst %.c,$(MISC_DIRENT_DIR)/%.c,$(CSRC))
+MISC_DIRENT_OBJ := $(patsubst %.c,$(MISC_DIRENT_OUT)/%.o,$(CSRC))
+
+libc-y += $(MISC_DIRENT_OBJ)
+
+objclean-y += CLEAN_libc/misc/dirent
+
+CLEAN_libc/misc/dirent:
+ $(do_rm) $(addprefix $(MISC_DIRENT_OUT)/*., o os)
diff --git a/ap/build/uClibc/libc/misc/dirent/alphasort.c b/ap/build/uClibc/libc/misc/dirent/alphasort.c
new file mode 100644
index 0000000..eb0dbf2
--- /dev/null
+++ b/ap/build/uClibc/libc/misc/dirent/alphasort.c
@@ -0,0 +1,15 @@
+/*
+ * Copyright (C) 2000-2006 Erik Andersen <andersen@uclibc.org>
+ *
+ * Licensed under the LGPL v2.1, see the file COPYING.LIB in this tarball.
+ */
+
+#include <dirent.h>
+#include <string.h>
+#include "dirstream.h"
+
+int alphasort(const struct dirent **a, const struct dirent **b)
+{
+ return strcmp((*a)->d_name, (*b)->d_name);
+}
+
diff --git a/ap/build/uClibc/libc/misc/dirent/alphasort64.c b/ap/build/uClibc/libc/misc/dirent/alphasort64.c
new file mode 100644
index 0000000..d65b596
--- /dev/null
+++ b/ap/build/uClibc/libc/misc/dirent/alphasort64.c
@@ -0,0 +1,16 @@
+/*
+ * Copyright (C) 2000-2006 Erik Andersen <andersen@uclibc.org>
+ *
+ * Licensed under the LGPL v2.1, see the file COPYING.LIB in this tarball.
+ */
+
+#include <_lfs_64.h>
+
+#include <dirent.h>
+#include <string.h>
+#include "dirstream.h"
+
+int alphasort64(const struct dirent64 **a, const struct dirent64 **b)
+{
+ return strcmp((*a)->d_name, (*b)->d_name);
+}
diff --git a/ap/build/uClibc/libc/misc/dirent/closedir.c b/ap/build/uClibc/libc/misc/dirent/closedir.c
new file mode 100644
index 0000000..dfb53f8
--- /dev/null
+++ b/ap/build/uClibc/libc/misc/dirent/closedir.c
@@ -0,0 +1,37 @@
+/*
+ * Copyright (C) 2000-2006 Erik Andersen <andersen@uclibc.org>
+ *
+ * Licensed under the LGPL v2.1, see the file COPYING.LIB in this tarball.
+ */
+
+#include <dirent.h>
+#include <errno.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include "dirstream.h"
+#include <not-cancel.h>
+
+
+int closedir(DIR * dir)
+{
+ int fd;
+
+ if (!dir) {
+ __set_errno(EBADF);
+ return -1;
+ }
+
+ /* We need to check dd_fd. */
+ if (dir->dd_fd == -1) {
+ __set_errno(EBADF);
+ return -1;
+ }
+ __UCLIBC_MUTEX_LOCK(dir->dd_lock);
+ fd = dir->dd_fd;
+ dir->dd_fd = -1;
+ __UCLIBC_MUTEX_UNLOCK(dir->dd_lock);
+ free(dir->dd_buf);
+ free(dir);
+ return close_not_cancel(fd);
+}
+libc_hidden_def(closedir)
diff --git a/ap/build/uClibc/libc/misc/dirent/dirfd.c b/ap/build/uClibc/libc/misc/dirent/dirfd.c
new file mode 100644
index 0000000..649dd4a
--- /dev/null
+++ b/ap/build/uClibc/libc/misc/dirent/dirfd.c
@@ -0,0 +1,21 @@
+/*
+ * Copyright (C) 2000-2006 Erik Andersen <andersen@uclibc.org>
+ *
+ * Licensed under the LGPL v2.1, see the file COPYING.LIB in this tarball.
+ */
+
+#include <dirent.h>
+#include <errno.h>
+#include "dirstream.h"
+
+
+int dirfd(DIR * dir)
+{
+ if (!dir || dir->dd_fd == -1) {
+ __set_errno(EBADF);
+ return -1;
+ }
+
+ return dir->dd_fd;
+}
+libc_hidden_def(dirfd)
diff --git a/ap/build/uClibc/libc/misc/dirent/dirstream.h b/ap/build/uClibc/libc/misc/dirent/dirstream.h
new file mode 100644
index 0000000..370886a
--- /dev/null
+++ b/ap/build/uClibc/libc/misc/dirent/dirstream.h
@@ -0,0 +1,74 @@
+/* Copyright (C) 1991, 1992 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 Library General Public License as
+published by the Free Software Foundation; either version 2 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
+Library General Public License for more details.
+
+You should have received a copy of the GNU Library General Public
+License along with the GNU C Library; see the file COPYING.LIB. If
+not, write to the, 1992 Free Software Foundation, Inc., 675 Mass Ave,
+Cambridge, MA 02139, USA. */
+
+/*
+ * POSIX Standard: 5.1.2 Directory Operations <dirent.h>
+ */
+
+#ifndef _DIRSTREAM_H
+
+#define _DIRSTREAM_H 1
+
+#include <features.h>
+#include <sys/types.h>
+
+#include <bits/uClibc_mutex.h>
+
+/* For now, syscall readdir () only supports one entry at a time. It
+ * will be changed in the future.
+#define NUMENT 3
+*/
+#ifndef NUMENT
+#define NUMENT 1
+#endif
+
+#define SINGLE_READDIR 11
+#define MULTI_READDIR 12
+#define NEW_READDIR 13
+
+/* Directory stream type. */
+struct __dirstream {
+ /* file descriptor */
+ int dd_fd;
+
+ /* offset of the next dir entry in buffer */
+ size_t dd_nextloc;
+
+ /* bytes of valid entries in buffer */
+ size_t dd_size;
+
+ /* -> directory buffer */
+ void *dd_buf;
+
+ /* offset of the next dir entry in directory. */
+ off_t dd_nextoff;
+
+ /* total size of buffer */
+ size_t dd_max;
+
+ /* lock */
+ __UCLIBC_MUTEX(dd_lock);
+}; /* stream data from opendir() */
+
+
+extern ssize_t __getdents(int fd, char *buf, size_t count) attribute_hidden;
+#ifdef __UCLIBC_HAS_LFS__
+extern ssize_t __getdents64 (int fd, char *buf, size_t count) attribute_hidden;
+#endif
+
+#endif /* dirent.h */
diff --git a/ap/build/uClibc/libc/misc/dirent/opendir.c b/ap/build/uClibc/libc/misc/dirent/opendir.c
new file mode 100644
index 0000000..66a5cc9
--- /dev/null
+++ b/ap/build/uClibc/libc/misc/dirent/opendir.c
@@ -0,0 +1,117 @@
+/*
+ * Copyright (C) 2000-2006 Erik Andersen <andersen@uclibc.org>
+ *
+ * Licensed under the LGPL v2.1, see the file COPYING.LIB in this tarball.
+ */
+
+#include <errno.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/types.h>
+#include <fcntl.h>
+#include <unistd.h>
+#include <sys/dir.h>
+#include <sys/stat.h>
+#include <not-cancel.h>
+#include <dirent.h>
+#include "dirstream.h"
+
+static DIR *fd_to_DIR(int fd, __blksize_t size)
+{
+ DIR *ptr;
+
+ ptr = malloc(sizeof(*ptr));
+ if (!ptr)
+ return NULL;
+
+ ptr->dd_fd = fd;
+ ptr->dd_nextloc = ptr->dd_size = ptr->dd_nextoff = 0;
+ ptr->dd_max = size;
+ if (ptr->dd_max < 512)
+ ptr->dd_max = 512;
+
+ ptr->dd_buf = calloc(1, ptr->dd_max);
+ if (!ptr->dd_buf) {
+ free(ptr);
+ return NULL;
+ }
+ __UCLIBC_MUTEX_INIT_VAR(ptr->dd_lock);
+
+ return ptr;
+}
+
+DIR *fdopendir(int fd)
+{
+ int flags;
+ struct stat st;
+
+ if (fstat(fd, &st))
+ return NULL;
+ if (!S_ISDIR(st.st_mode)) {
+ __set_errno(ENOTDIR);
+ return NULL;
+ }
+
+ flags = fcntl(fd, F_GETFL);
+ if (flags == -1)
+ return NULL;
+ if ((flags & O_ACCMODE) == O_WRONLY) {
+ __set_errno(EINVAL);
+ return NULL;
+ }
+
+ return fd_to_DIR(fd, st.st_blksize);
+}
+
+/* opendir just makes an open() call - it return NULL if it fails
+ * (open sets errno), otherwise it returns a DIR * pointer.
+ */
+DIR *opendir(const char *name)
+{
+ int fd;
+ struct stat statbuf;
+ DIR *ptr;
+
+#ifndef O_DIRECTORY
+ /* O_DIRECTORY is linux specific and has been around since like 2.1.x */
+ if (stat(name, &statbuf))
+ return NULL;
+ if (!S_ISDIR(statbuf.st_mode)) {
+ __set_errno(ENOTDIR);
+ return NULL;
+ }
+# define O_DIRECTORY 0
+#endif
+ fd = open_not_cancel_2(name, O_RDONLY|O_NDELAY|O_DIRECTORY|O_CLOEXEC);
+ if (fd < 0)
+ return NULL;
+ /* Note: we should check to make sure that between the stat() and open()
+ * call, 'name' didnt change on us, but that's only if O_DIRECTORY isnt
+ * defined and since Linux has supported it for like ever, i'm not going
+ * to worry about it right now (if ever). */
+
+ if (fstat(fd, &statbuf) < 0) {
+ /* this close() never fails
+ *int saved_errno;
+ *saved_errno = errno; */
+ close_not_cancel_no_status(fd);
+ /*__set_errno(saved_errno);*/
+ return NULL;
+ }
+
+ /* According to POSIX, directory streams should be closed when
+ * exec. From "Anna Pluzhnikov" <besp@midway.uchicago.edu>.
+ */
+#ifndef __ASSUME_O_CLOEXEC
+ fcntl_not_cancel(fd, F_SETFD, FD_CLOEXEC);
+#endif
+
+ ptr = fd_to_DIR(fd, statbuf.st_blksize);
+
+ if (!ptr) {
+ close_not_cancel_no_status(fd);
+ __set_errno(ENOMEM);
+ }
+ return ptr;
+}
+libc_hidden_def(opendir)
diff --git a/ap/build/uClibc/libc/misc/dirent/readdir.c b/ap/build/uClibc/libc/misc/dirent/readdir.c
new file mode 100644
index 0000000..4fcd1cc
--- /dev/null
+++ b/ap/build/uClibc/libc/misc/dirent/readdir.c
@@ -0,0 +1,56 @@
+/*
+ * Copyright (C) 2000-2006 Erik Andersen <andersen@uclibc.org>
+ *
+ * Licensed under the LGPL v2.1, see the file COPYING.LIB in this tarball.
+ */
+
+#include <features.h>
+
+#include <errno.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+#include <dirent.h>
+#include "dirstream.h"
+
+
+struct dirent *readdir(DIR * dir)
+{
+ ssize_t bytes;
+ struct dirent *de;
+
+ if (!dir) {
+ __set_errno(EBADF);
+ return NULL;
+ }
+
+ __UCLIBC_MUTEX_LOCK(dir->dd_lock);
+
+ do {
+ if (dir->dd_size <= dir->dd_nextloc) {
+ /* read dir->dd_max bytes of directory entries. */
+ bytes = __getdents(dir->dd_fd, dir->dd_buf, dir->dd_max);
+ if (bytes <= 0) {
+ de = NULL;
+ goto all_done;
+ }
+ dir->dd_size = bytes;
+ dir->dd_nextloc = 0;
+ }
+
+ de = (struct dirent *) (((char *) dir->dd_buf) + dir->dd_nextloc);
+
+ /* Am I right? H.J. */
+ dir->dd_nextloc += de->d_reclen;
+
+ /* We have to save the next offset here. */
+ dir->dd_nextoff = de->d_off;
+
+ /* Skip deleted files. */
+ } while (de->d_ino == 0);
+
+all_done:
+ __UCLIBC_MUTEX_UNLOCK(dir->dd_lock);
+ return de;
+}
+libc_hidden_def(readdir)
diff --git a/ap/build/uClibc/libc/misc/dirent/readdir64.c b/ap/build/uClibc/libc/misc/dirent/readdir64.c
new file mode 100644
index 0000000..1264c38
--- /dev/null
+++ b/ap/build/uClibc/libc/misc/dirent/readdir64.c
@@ -0,0 +1,56 @@
+/*
+ * Copyright (C) 2000-2006 Erik Andersen <andersen@uclibc.org>
+ *
+ * Licensed under the LGPL v2.1, see the file COPYING.LIB in this tarball.
+ */
+
+#include <_lfs_64.h>
+
+#include <errno.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+#include <dirent.h>
+#include "dirstream.h"
+
+struct dirent64 *readdir64(DIR * dir)
+{
+ ssize_t bytes;
+ struct dirent64 *de;
+
+ if (!dir) {
+ __set_errno(EBADF);
+ return NULL;
+ }
+
+ __UCLIBC_MUTEX_LOCK(dir->dd_lock);
+
+ do {
+ if (dir->dd_size <= dir->dd_nextloc) {
+ /* read dir->dd_max bytes of directory entries. */
+ bytes = __getdents64(dir->dd_fd, dir->dd_buf, dir->dd_max);
+ if (bytes <= 0) {
+ de = NULL;
+ goto all_done;
+ }
+ dir->dd_size = bytes;
+ dir->dd_nextloc = 0;
+ }
+
+ de = (struct dirent64 *) (((char *) dir->dd_buf) + dir->dd_nextloc);
+
+ /* Am I right? H.J. */
+ dir->dd_nextloc += de->d_reclen;
+
+ /* We have to save the next offset here. */
+ dir->dd_nextoff = de->d_off;
+
+ /* Skip deleted files. */
+ } while (de->d_ino == 0);
+
+all_done:
+ __UCLIBC_MUTEX_UNLOCK(dir->dd_lock);
+
+ return de;
+}
+libc_hidden_def(readdir64)
diff --git a/ap/build/uClibc/libc/misc/dirent/readdir64_r.c b/ap/build/uClibc/libc/misc/dirent/readdir64_r.c
new file mode 100644
index 0000000..ba72600
--- /dev/null
+++ b/ap/build/uClibc/libc/misc/dirent/readdir64_r.c
@@ -0,0 +1,66 @@
+/*
+ * Copyright (C) 2000-2006 Erik Andersen <andersen@uclibc.org>
+ *
+ * Licensed under the LGPL v2.1, see the file COPYING.LIB in this tarball.
+ */
+
+#include <_lfs_64.h>
+
+#include <errno.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+#include <dirent.h>
+#include "dirstream.h"
+
+
+int readdir64_r(DIR *dir, struct dirent64 *entry, struct dirent64 **result)
+{
+ int ret;
+ ssize_t bytes;
+ struct dirent64 *de;
+
+ if (!dir) {
+ __set_errno(EBADF);
+ return(EBADF);
+ }
+ de = NULL;
+
+ __UCLIBC_MUTEX_LOCK(dir->dd_lock);
+
+ do {
+ if (dir->dd_size <= dir->dd_nextloc) {
+ /* read dir->dd_max bytes of directory entries. */
+ bytes = __getdents64(dir->dd_fd, dir->dd_buf, dir->dd_max);
+ if (bytes <= 0) {
+ *result = NULL;
+ ret = (bytes==0)? 0 : errno;
+ goto all_done;
+ }
+ dir->dd_size = bytes;
+ dir->dd_nextloc = 0;
+ }
+
+ de = (struct dirent64 *) (((char *) dir->dd_buf) + dir->dd_nextloc);
+
+ /* Am I right? H.J. */
+ dir->dd_nextloc += de->d_reclen;
+
+ /* We have to save the next offset here. */
+ dir->dd_nextoff = de->d_off;
+ /* Skip deleted files. */
+ } while (de->d_ino == 0);
+
+ if (de == NULL) {
+ *result = NULL;
+ } else {
+ *result = memcpy (entry, de, de->d_reclen);
+ }
+ ret = 0;
+
+all_done:
+
+ __UCLIBC_MUTEX_UNLOCK(dir->dd_lock);
+ return((de != NULL)? 0 : ret);
+}
+libc_hidden_def(readdir64_r)
diff --git a/ap/build/uClibc/libc/misc/dirent/readdir_r.c b/ap/build/uClibc/libc/misc/dirent/readdir_r.c
new file mode 100644
index 0000000..d08997f
--- /dev/null
+++ b/ap/build/uClibc/libc/misc/dirent/readdir_r.c
@@ -0,0 +1,64 @@
+/*
+ * Copyright (C) 2000-2006 Erik Andersen <andersen@uclibc.org>
+ *
+ * Licensed under the LGPL v2.1, see the file COPYING.LIB in this tarball.
+ */
+
+#include <errno.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+#include <dirent.h>
+#include "dirstream.h"
+
+
+int readdir_r(DIR *dir, struct dirent *entry, struct dirent **result)
+{
+ int ret;
+ ssize_t bytes;
+ struct dirent *de;
+
+ if (!dir) {
+ __set_errno(EBADF);
+ return(EBADF);
+ }
+ de = NULL;
+
+ __UCLIBC_MUTEX_LOCK(dir->dd_lock);
+
+ do {
+ if (dir->dd_size <= dir->dd_nextloc) {
+ /* read dir->dd_max bytes of directory entries. */
+ bytes = __getdents(dir->dd_fd, dir->dd_buf, dir->dd_max);
+ if (bytes <= 0) {
+ *result = NULL;
+ ret = (bytes==0)? 0 : errno;
+ goto all_done;
+ }
+ dir->dd_size = bytes;
+ dir->dd_nextloc = 0;
+ }
+
+ de = (struct dirent *) (((char *) dir->dd_buf) + dir->dd_nextloc);
+
+ /* Am I right? H.J. */
+ dir->dd_nextloc += de->d_reclen;
+
+ /* We have to save the next offset here. */
+ dir->dd_nextoff = de->d_off;
+ /* Skip deleted files. */
+ } while (de->d_ino == 0);
+
+ if (de == NULL) {
+ *result = NULL;
+ } else {
+ *result = memcpy (entry, de, de->d_reclen);
+ }
+ ret = 0;
+
+all_done:
+
+ __UCLIBC_MUTEX_UNLOCK(dir->dd_lock);
+ return((de != NULL)? 0 : ret);
+}
+libc_hidden_def(readdir_r)
diff --git a/ap/build/uClibc/libc/misc/dirent/rewinddir.c b/ap/build/uClibc/libc/misc/dirent/rewinddir.c
new file mode 100644
index 0000000..0a8f147
--- /dev/null
+++ b/ap/build/uClibc/libc/misc/dirent/rewinddir.c
@@ -0,0 +1,24 @@
+/*
+ * Copyright (C) 2000-2006 Erik Andersen <andersen@uclibc.org>
+ *
+ * Licensed under the LGPL v2.1, see the file COPYING.LIB in this tarball.
+ */
+
+#include <dirent.h>
+#include <errno.h>
+#include <unistd.h>
+#include "dirstream.h"
+
+
+/* rewinddir() just does an lseek(fd,0,0) - see close for comments */
+void rewinddir(DIR * dir)
+{
+ if (!dir) {
+ __set_errno(EBADF);
+ return;
+ }
+ __UCLIBC_MUTEX_LOCK(dir->dd_lock);
+ lseek(dir->dd_fd, 0, SEEK_SET);
+ dir->dd_nextoff = dir->dd_nextloc = dir->dd_size = 0;
+ __UCLIBC_MUTEX_UNLOCK(dir->dd_lock);
+}
diff --git a/ap/build/uClibc/libc/misc/dirent/scandir.c b/ap/build/uClibc/libc/misc/dirent/scandir.c
new file mode 100644
index 0000000..bb42564
--- /dev/null
+++ b/ap/build/uClibc/libc/misc/dirent/scandir.c
@@ -0,0 +1,94 @@
+/*
+ * Copyright (C) 2000-2006 Erik Andersen <andersen@uclibc.org>
+ *
+ * Licensed under the LGPL v2.1, see the file COPYING.LIB in this tarball.
+ */
+
+#include <dirent.h>
+#include <stdio.h>
+#include <string.h>
+#include <stdlib.h>
+#include <errno.h>
+#include <sys/types.h>
+#include "dirstream.h"
+
+int scandir(const char *dir, struct dirent ***namelist,
+ int (*selector) (const struct dirent *),
+ int (*compar) (const struct dirent **, const struct dirent **))
+{
+ DIR *dp = opendir (dir);
+ struct dirent *current;
+ struct dirent **names = NULL;
+ size_t names_size = 0, pos;
+ int save;
+
+ if (dp == NULL)
+ return -1;
+
+ save = errno;
+ __set_errno (0);
+
+ pos = 0;
+ while ((current = readdir (dp)) != NULL) {
+ int use_it = selector == NULL;
+
+ if (! use_it)
+ {
+ use_it = (*selector) (current);
+ /* The selector function might have changed errno.
+ * It was zero before and it need to be again to make
+ * the latter tests work. */
+ if (! use_it)
+ __set_errno (0);
+ }
+ if (use_it)
+ {
+ struct dirent *vnew;
+ size_t dsize;
+
+ /* Ignore errors from selector or readdir */
+ __set_errno (0);
+
+ if (unlikely(pos == names_size))
+ {
+ struct dirent **new;
+ if (names_size == 0)
+ names_size = 10;
+ else
+ names_size *= 2;
+ new = (struct dirent **) realloc (names,
+ names_size * sizeof (struct dirent *));
+ if (new == NULL)
+ break;
+ names = new;
+ }
+
+ dsize = ¤t->d_name[_D_ALLOC_NAMLEN(current)] - (char*)current;
+ vnew = (struct dirent *) malloc (dsize);
+ if (vnew == NULL)
+ break;
+
+ names[pos++] = (struct dirent *) memcpy (vnew, current, dsize);
+ }
+ }
+
+ if (unlikely(errno != 0))
+ {
+ save = errno;
+ closedir (dp);
+ while (pos > 0)
+ free (names[--pos]);
+ free (names);
+ __set_errno (save);
+ return -1;
+ }
+
+ closedir (dp);
+ __set_errno (save);
+
+ /* Sort the list if we have a comparison function to sort with. */
+ if (compar != NULL)
+ qsort (names, pos, sizeof (struct dirent *), (comparison_fn_t) compar);
+ *namelist = names;
+ return pos;
+}
diff --git a/ap/build/uClibc/libc/misc/dirent/scandir64.c b/ap/build/uClibc/libc/misc/dirent/scandir64.c
new file mode 100644
index 0000000..3d2a250
--- /dev/null
+++ b/ap/build/uClibc/libc/misc/dirent/scandir64.c
@@ -0,0 +1,111 @@
+/* Copyright (C) 1992-1998, 2000 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.
+ */
+
+/* Modified for uClibc by Erik Andersen
+ */
+
+#include <_lfs_64.h>
+
+#include <dirent.h>
+#include <stdio.h>
+#include <string.h>
+#include <stdlib.h>
+#include <errno.h>
+#include <sys/types.h>
+#include "dirstream.h"
+
+int scandir64(const char *dir, struct dirent64 ***namelist,
+ int (*selector) (const struct dirent64 *),
+ int (*compar) (const struct dirent64 **, const struct dirent64 **))
+{
+ DIR *dp = opendir (dir);
+ struct dirent64 *current;
+ struct dirent64 **names = NULL;
+ size_t names_size = 0, pos;
+ int save;
+
+ if (dp == NULL)
+ return -1;
+
+ save = errno;
+ __set_errno (0);
+
+ pos = 0;
+ while ((current = readdir64 (dp)) != NULL) {
+ int use_it = selector == NULL;
+
+ if (! use_it)
+ {
+ use_it = (*selector) (current);
+ /* The selector function might have changed errno.
+ * It was zero before and it need to be again to make
+ * the latter tests work. */
+ if (! use_it)
+ __set_errno (0);
+ }
+ if (use_it)
+ {
+ struct dirent64 *vnew;
+ size_t dsize;
+
+ /* Ignore errors from selector or readdir64 */
+ __set_errno (0);
+
+ if (unlikely(pos == names_size))
+ {
+ struct dirent64 **new;
+ if (names_size == 0)
+ names_size = 10;
+ else
+ names_size *= 2;
+ new = (struct dirent64 **) realloc (names,
+ names_size * sizeof (struct dirent64 *));
+ if (new == NULL)
+ break;
+ names = new;
+ }
+
+ dsize = ¤t->d_name[_D_ALLOC_NAMLEN(current)] - (char*)current;
+ vnew = (struct dirent64 *) malloc (dsize);
+ if (vnew == NULL)
+ break;
+
+ names[pos++] = (struct dirent64 *) memcpy (vnew, current, dsize);
+ }
+ }
+ if (unlikely(errno != 0))
+ {
+ save = errno;
+ closedir (dp);
+ while (pos > 0)
+ free (names[--pos]);
+ free (names);
+ __set_errno (save);
+ return -1;
+ }
+
+ closedir (dp);
+ __set_errno (save);
+
+ /* Sort the list if we have a comparison function to sort with. */
+ if (compar != NULL)
+ qsort (names, pos, sizeof (struct dirent64 *), (comparison_fn_t) compar);
+ *namelist = names;
+ return pos;
+}
diff --git a/ap/build/uClibc/libc/misc/dirent/seekdir.c b/ap/build/uClibc/libc/misc/dirent/seekdir.c
new file mode 100644
index 0000000..eaf447e
--- /dev/null
+++ b/ap/build/uClibc/libc/misc/dirent/seekdir.c
@@ -0,0 +1,23 @@
+/*
+ * Copyright (C) 2000-2006 Erik Andersen <andersen@uclibc.org>
+ *
+ * Licensed under the LGPL v2.1, see the file COPYING.LIB in this tarball.
+ */
+
+#include <dirent.h>
+#include <errno.h>
+#include <unistd.h>
+#include "dirstream.h"
+
+
+void seekdir(DIR * dir, long int offset)
+{
+ if (!dir) {
+ __set_errno(EBADF);
+ return;
+ }
+ __UCLIBC_MUTEX_LOCK(dir->dd_lock);
+ dir->dd_nextoff = lseek(dir->dd_fd, offset, SEEK_SET);
+ dir->dd_size = dir->dd_nextloc = 0;
+ __UCLIBC_MUTEX_UNLOCK(dir->dd_lock);
+}
diff --git a/ap/build/uClibc/libc/misc/dirent/telldir.c b/ap/build/uClibc/libc/misc/dirent/telldir.c
new file mode 100644
index 0000000..3c5deca
--- /dev/null
+++ b/ap/build/uClibc/libc/misc/dirent/telldir.c
@@ -0,0 +1,22 @@
+/*
+ * Copyright (C) 2000-2006 Erik Andersen <andersen@uclibc.org>
+ *
+ * Licensed under the LGPL v2.1, see the file COPYING.LIB in this tarball.
+ */
+
+#include <dirent.h>
+#include <errno.h>
+#include <unistd.h>
+#include "dirstream.h"
+
+
+long int telldir(DIR * dir)
+{
+ if (!dir) {
+ __set_errno(EBADF);
+ return -1;
+ }
+
+ /* The next entry. */
+ return dir->dd_nextoff;
+}
diff --git a/ap/build/uClibc/libc/misc/dirent/versionsort.c b/ap/build/uClibc/libc/misc/dirent/versionsort.c
new file mode 100644
index 0000000..d84da1f
--- /dev/null
+++ b/ap/build/uClibc/libc/misc/dirent/versionsort.c
@@ -0,0 +1,14 @@
+/*
+ * Copyright (C) 2008-2009 Hai Zaar, Codefidence Ltd <haizaar@codefidence.com>
+ *
+ * Licensed under the LGPL v2.1, see the file COPYING.LIB in this tarball.
+ */
+
+#include <dirent.h>
+#include <string.h>
+#include "dirstream.h"
+
+int versionsort(const struct dirent **a, const struct dirent **b)
+{
+ return strverscmp((*a)->d_name, (*b)->d_name);
+}
diff --git a/ap/build/uClibc/libc/misc/dirent/versionsort64.c b/ap/build/uClibc/libc/misc/dirent/versionsort64.c
new file mode 100644
index 0000000..af9689e
--- /dev/null
+++ b/ap/build/uClibc/libc/misc/dirent/versionsort64.c
@@ -0,0 +1,16 @@
+/*
+ * Copyright (C) 2008-2009 Hai Zaar, Codefidence Ltd <haizaar@codefidence.com>
+ *
+ * Licensed under the LGPL v2.1, see the file COPYING.LIB in this tarball.
+ */
+
+#include <_lfs_64.h>
+
+#include <dirent.h>
+#include <string.h>
+#include "dirstream.h"
+
+int versionsort64(const struct dirent64 **a, const struct dirent64 **b)
+{
+ return strverscmp((*a)->d_name, (*b)->d_name);
+}
diff --git a/ap/build/uClibc/libc/misc/elf/Makefile b/ap/build/uClibc/libc/misc/elf/Makefile
new file mode 100644
index 0000000..4bb6872
--- /dev/null
+++ b/ap/build/uClibc/libc/misc/elf/Makefile
@@ -0,0 +1,12 @@
+# Copyright (C) 2008 STMicroelectronics Ltd.
+# Author: Carmelo Amoroso <carmelo.amoroso@st.com>
+
+# Licensed under the LGPL v2.1, see the file COPYING.LIB in this tarball.
+#
+
+top_srcdir=../../../
+top_builddir=../../../
+all: objs
+include $(top_builddir)Rules.mak
+include Makefile.in
+include $(top_srcdir)Makerules
diff --git a/ap/build/uClibc/libc/misc/elf/Makefile.in b/ap/build/uClibc/libc/misc/elf/Makefile.in
new file mode 100644
index 0000000..1b4bd8b
--- /dev/null
+++ b/ap/build/uClibc/libc/misc/elf/Makefile.in
@@ -0,0 +1,22 @@
+# Copyright (C) 2008 STMicroelectronics Ltd.
+# Author: Carmelo Amoroso <carmelo.amoroso@st.com>
+
+# Licensed under the LGPL v2.1, see the file COPYING.LIB in this tarball.
+#
+
+subdirs += libc/misc/elf
+
+libc_a_CSRC = dl-support.c dl-core.c dl-iterate-phdr.c
+CFLAGS-dl-iterate-phdr.c=-D_GNU_SOURCE -I$(top_srcdir)ldso/ldso/$(TARGET_ARCH) -I$(top_srcdir)ldso/include
+CFLAGS-dl-core.c=-I$(top_srcdir)ldso/ldso/$(TARGET_ARCH) -I$(top_srcdir)ldso/include
+
+MISC_ELF_OUT:=$(top_builddir)libc/misc/elf
+MISC_ELF_OBJ:=$(patsubst %.c,$(MISC_ELF_OUT)/%.o,$(libc_a_CSRC))
+
+libc-static-y += $(MISC_ELF_OBJ)
+libc-shared-y += $(MISC_ELF_OUT)/dl-iterate-phdr.oS
+
+objclean-y+= CLEAN_libc/misc/elf
+
+CLEAN_libc/misc/elf:
+ $(do_rm) $(addprefix $(MISC_ELF_OUT)/*., o os oS)
diff --git a/ap/build/uClibc/libc/misc/elf/dl-core.c b/ap/build/uClibc/libc/misc/elf/dl-core.c
new file mode 100644
index 0000000..b32dcf8
--- /dev/null
+++ b/ap/build/uClibc/libc/misc/elf/dl-core.c
@@ -0,0 +1,20 @@
+/*
+ * This contains all symbols and functions to support
+ * dynamic linking into static libc.
+
+ * Copyright (c) 2008 STMicroelectronics Ltd
+ * Author: Carmelo Amoroso <carmelo.amoroso@st.com>
+ *
+ * Based on draft work by Peter S. Mazinger <ps.m@gmx.net>
+ *
+ * Licensed under the LGPL v2.1, see the file COPYING.LIB in this tarball.
+ *
+ */
+
+#ifdef SHARED
+#error "This file is not suitable for linking into dynamic libc"
+#else
+/* Include ldso symbols and functions used into static libc */
+#include "../../../ldso/ldso/dl-symbols.c"
+#endif
+
diff --git a/ap/build/uClibc/libc/misc/elf/dl-iterate-phdr.c b/ap/build/uClibc/libc/misc/elf/dl-iterate-phdr.c
new file mode 100644
index 0000000..f0233ca
--- /dev/null
+++ b/ap/build/uClibc/libc/misc/elf/dl-iterate-phdr.c
@@ -0,0 +1,85 @@
+/* Get loaded objects program headers.
+
+ Based on GNU C library (file: libc/elf/dl-iteratephdr.c)
+
+ Copyright (C) 2001,2002,2003,2004,2006,2007 Free Software Foundation, Inc.
+ Contributed by Jakub Jelinek <jakub@redhat.com>, 2001.
+
+ Copyright (C) 2008 STMicroelectronics Ltd.
+ Author: Carmelo Amoroso <carmelo.amoroso@st.com>
+
+ Licensed under the LGPL v2.1, see the file COPYING.LIB in this tarball.
+*/
+
+
+#include <link.h>
+#include <ldso.h>
+
+/* we want this in libc but nowhere else */
+#ifdef __USE_GNU
+
+extern __typeof(dl_iterate_phdr) __dl_iterate_phdr;
+
+hidden_proto(__dl_iterate_phdr)
+int
+__dl_iterate_phdr (int (*callback) (struct dl_phdr_info *info, size_t size, void *data), void *data)
+{
+ int ret = 0;
+#ifndef __ARCH_HAS_NO_SHARED__
+ struct elf_resolve *l;
+ struct dl_phdr_info info;
+
+ for (l = _dl_loaded_modules; l != NULL; l = l->next) {
+ info.dlpi_addr = l->loadaddr;
+ info.dlpi_name = l->libname;
+ info.dlpi_phdr = l->ppnt;
+ info.dlpi_phnum = l->n_phent;
+ ret = callback (&info, sizeof (struct dl_phdr_info), data);
+ if (ret)
+ break;
+ }
+#endif
+ return ret;
+}
+hidden_def (__dl_iterate_phdr)
+
+# ifdef SHARED
+
+weak_alias(__dl_iterate_phdr, dl_iterate_phdr)
+
+# else
+
+/* dl-support.c defines these and initializes them early on. */
+extern ElfW(Phdr) *_dl_phdr;
+extern size_t _dl_phnum;
+
+int
+dl_iterate_phdr (int (*callback) (struct dl_phdr_info *info,
+ size_t size, void *data), void *data)
+{
+ if (_dl_phnum != 0)
+ {
+ /* This entry describes this statically-linked program itself. */
+ struct dl_phdr_info info;
+ int ret;
+#if defined(__FDPIC__)
+ info.dlpi_addr.map = NULL;
+ info.dlpi_addr.got_value = NULL;
+#elif defined(__DSBT__)
+ info.dlpi_addr.map = NULL;
+#else
+ info.dlpi_addr = 0;
+#endif
+ info.dlpi_name = "";
+ info.dlpi_phdr = _dl_phdr;
+ info.dlpi_phnum = _dl_phnum;
+ ret = (*callback) (&info, sizeof (struct dl_phdr_info), data);
+ if (ret)
+ return ret;
+ }
+ /* Then invoke callback on loaded modules, if any */
+ return __dl_iterate_phdr (callback, data);
+}
+
+# endif
+#endif
diff --git a/ap/build/uClibc/libc/misc/elf/dl-support.c b/ap/build/uClibc/libc/misc/elf/dl-support.c
new file mode 100644
index 0000000..f194692
--- /dev/null
+++ b/ap/build/uClibc/libc/misc/elf/dl-support.c
@@ -0,0 +1,70 @@
+/*
+ * Support for dynamic linking code in static libc.
+ * Copyright (C) 1996-2002, 2003, 2004, 2005 Free Software Foundation, Inc.
+ *
+ * Partially based on GNU C Library (file: libc/elf/dl-support.c)
+ *
+ * Copyright (C) 2008 STMicroelectronics Ltd.
+ * Author: Carmelo Amoroso <carmelo.amoroso@st.com>
+ *
+ * Licensed under the LGPL v2.1, see the file COPYING.LIB in this tarball.
+ *
+ */
+
+#include <link.h>
+#include <elf.h>
+#if defined(USE_TLS) && USE_TLS
+#include <assert.h>
+#include <tls.h>
+#include <ldsodefs.h>
+#include <string.h>
+#endif
+
+#if defined(USE_TLS) && USE_TLS
+
+void (*_dl_init_static_tls) (struct link_map *) = &_dl_nothread_init_static_tls;
+
+#endif
+
+ElfW(Phdr) *_dl_phdr;
+size_t _dl_phnum;
+
+void internal_function _dl_aux_init (ElfW(auxv_t) *av);
+void internal_function _dl_aux_init (ElfW(auxv_t) *av)
+{
+ /* Get the program headers base address from the aux vect */
+ _dl_phdr = (ElfW(Phdr) *) av[AT_PHDR].a_un.a_val;
+
+ /* Get the number of program headers from the aux vect */
+ _dl_phnum = (size_t) av[AT_PHNUM].a_un.a_val;
+}
+
+#if defined(USE_TLS) && USE_TLS
+/* Initialize static TLS area and DTV for current (only) thread.
+ libpthread implementations should provide their own hook
+ to handle all threads. */
+void
+attribute_hidden
+_dl_nothread_init_static_tls (struct link_map *map)
+{
+# if defined(TLS_TCB_AT_TP)
+ void *dest = (char *) THREAD_SELF - map->l_tls_offset;
+# elif defined(TLS_DTV_AT_TP)
+ void *dest = (char *) THREAD_SELF + map->l_tls_offset + TLS_PRE_TCB_SIZE;
+# else
+# error "Either TLS_TCB_AT_TP or TLS_DTV_AT_TP must be defined"
+# endif
+
+ /* Fill in the DTV slot so that a later LD/GD access will find it. */
+ dtv_t *dtv = THREAD_DTV ();
+ assert (map->l_tls_modid <= dtv[-1].counter);
+ dtv[map->l_tls_modid].pointer.val = dest;
+ dtv[map->l_tls_modid].pointer.is_static = true;
+
+ /* Initialize the memory. */
+ memset (mempcpy (dest, map->l_tls_initimage, map->l_tls_initimage_size),
+ '\0', map->l_tls_blocksize - map->l_tls_initimage_size);
+}
+
+#endif
+
diff --git a/ap/build/uClibc/libc/misc/error/Makefile b/ap/build/uClibc/libc/misc/error/Makefile
new file mode 100644
index 0000000..4a8f4a0
--- /dev/null
+++ b/ap/build/uClibc/libc/misc/error/Makefile
@@ -0,0 +1,13 @@
+# Makefile for uClibc
+#
+# Copyright (C) 2000-2005 Erik Andersen <andersen@uclibc.org>
+#
+# Licensed under the LGPL v2.1, see the file COPYING.LIB in this tarball.
+#
+
+top_srcdir=../../../
+top_builddir=../../../
+all: objs
+include $(top_builddir)Rules.mak
+include Makefile.in
+include $(top_srcdir)Makerules
diff --git a/ap/build/uClibc/libc/misc/error/Makefile.in b/ap/build/uClibc/libc/misc/error/Makefile.in
new file mode 100644
index 0000000..b76a0df
--- /dev/null
+++ b/ap/build/uClibc/libc/misc/error/Makefile.in
@@ -0,0 +1,29 @@
+# Makefile for uClibc
+#
+# Copyright (C) 2000-2008 Erik Andersen <andersen@uclibc.org>
+#
+# Licensed under the LGPL v2.1, see the file COPYING.LIB in this tarball.
+#
+
+subdirs += libc/misc/error
+
+CSRC :=
+ifeq ($(UCLIBC_HAS_BSD_ERR),y)
+CSRC += err.c
+endif
+ifeq ($(UCLIBC_HAS_GNU_ERROR),y)
+CSRC += error.c
+endif
+
+MISC_ERROR_DIR := $(top_srcdir)libc/misc/error
+MISC_ERROR_OUT := $(top_builddir)libc/misc/error
+
+MISC_ERROR_SRC := $(patsubst %.c,$(MISC_ERROR_DIR)/%.c,$(CSRC))
+MISC_ERROR_OBJ := $(patsubst %.c,$(MISC_ERROR_OUT)/%.o,$(CSRC))
+
+libc-y += $(MISC_ERROR_OBJ)
+
+objclean-y += CLEAN_libc/misc/error
+
+CLEAN_libc/misc/error:
+ $(do_rm) $(addprefix $(MISC_ERROR_OUT)/*., o os)
diff --git a/ap/build/uClibc/libc/misc/error/err.c b/ap/build/uClibc/libc/misc/error/err.c
new file mode 100644
index 0000000..9ddb596
--- /dev/null
+++ b/ap/build/uClibc/libc/misc/error/err.c
@@ -0,0 +1,120 @@
+/* Copyright (C) 2004 Manuel Novoa III <mjn3@codepoet.org>
+ *
+ * GNU Library General Public License (LGPL) version 2 or later.
+ *
+ * Dedicated to Toni. See uClibc/DEDICATION.mjn3 for details.
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <stdarg.h>
+#include <errno.h>
+#include <err.h>
+#ifdef __UCLIBC_HAS_THREADS__
+#include <pthread.h>
+#endif
+
+#ifdef __UCLIBC_MJN3_ONLY__
+#warning REMINDER: Deal with wide oriented stderr case.
+#endif
+
+#if defined __USE_BSD
+
+
+
+static void vwarn_work(const char *format, va_list args, int showerr)
+{
+ /* 0123 45678 9 a b*/
+ static const char fmt[] = "%s: \0: %s\n\0\n";
+ const char *f;
+ char buf[64];
+ __STDIO_AUTO_THREADLOCK_VAR;
+
+ /* Do this first, in case something below changes errno. */
+ f = fmt + 11; /* At 11. */
+ if (showerr) {
+ f -= 4; /* At 7. */
+ __xpg_strerror_r(errno, buf, sizeof(buf));
+ }
+
+ __STDIO_AUTO_THREADLOCK(stderr);
+
+ fprintf(stderr, fmt, __uclibc_progname);
+ if (format) {
+ vfprintf(stderr, format, args);
+ f -= 2; /* At 5 (showerr) or 9. */
+ }
+ fprintf(stderr, f, buf);
+
+ __STDIO_AUTO_THREADUNLOCK(stderr);
+}
+
+void vwarn(const char *format, va_list args)
+{
+ vwarn_work(format, args, 1);
+}
+libc_hidden_def(vwarn)
+
+void warn(const char *format, ...)
+{
+ va_list args;
+
+ va_start(args, format);
+ vwarn(format, args);
+ va_end(args);
+}
+
+void vwarnx(const char *format, va_list args)
+{
+ vwarn_work(format, args, 0);
+}
+libc_hidden_def(vwarnx)
+
+void warnx(const char *format, ...)
+{
+ va_list args;
+
+ va_start(args, format);
+ vwarnx(format, args);
+ va_end(args);
+}
+
+void verr(int status, const char *format, va_list args)
+{
+ vwarn(format, args);
+ exit(status);
+}
+libc_hidden_def(verr)
+
+void attribute_noreturn err(int status, const char *format, ...)
+{
+ va_list args;
+
+ va_start(args, format);
+ verr(status, format, args);
+ /* This should get optimized away. We'll leave it now for safety. */
+ /* The loop is added only to keep gcc happy. */
+ while(1)
+ va_end(args);
+}
+
+void verrx(int status, const char *format, va_list args)
+{
+ vwarnx(format, args);
+ exit(status);
+}
+libc_hidden_def(verrx)
+
+void attribute_noreturn errx(int status, const char *format, ...)
+{
+ va_list args;
+
+ va_start(args, format);
+ verrx(status, format, args);
+ /* This should get optimized away. We'll leave it now for safety. */
+ /* The loop is added only to keep gcc happy. */
+ while(1)
+ va_end(args);
+}
+#endif
diff --git a/ap/build/uClibc/libc/misc/error/error.c b/ap/build/uClibc/libc/misc/error/error.c
new file mode 100644
index 0000000..a30a4de
--- /dev/null
+++ b/ap/build/uClibc/libc/misc/error/error.c
@@ -0,0 +1,106 @@
+/* Error handler for noninteractive utilities
+ Copyright (C) 1990-1998, 2000-2004, 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. */
+
+/* Written by David MacKenzie <djm@gnu.ai.mit.edu>. */
+/* Adjusted slightly by Erik Andersen <andersen@uclibc.org> */
+
+#include <stdio.h>
+#include <stdarg.h>
+#include <stdlib.h>
+#include <string.h>
+#include <error.h>
+
+
+/* This variable is incremented each time `error' is called. */
+unsigned int error_message_count = 0;
+/* Sometimes we want to have at most one error per line. This
+ variable controls whether this mode is selected or not. */
+int error_one_per_line;
+/* If NULL, error will flush stdout, then print on stderr the program
+ name, a colon and a space. Otherwise, error will call this
+ function without parameters instead. */
+void (*error_print_progname) (void) = NULL;
+
+extern __typeof(error) __error attribute_hidden;
+void __error (int status, int errnum, const char *message, ...)
+{
+ va_list args;
+
+ fflush (stdout);
+
+ if (error_print_progname)
+ (*error_print_progname) ();
+ else
+ fprintf (stderr, "%s: ", __uclibc_progname);
+
+ va_start (args, message);
+ vfprintf (stderr, message, args);
+ va_end (args);
+ ++error_message_count;
+ if (errnum) {
+ fprintf (stderr, ": %s", strerror (errnum));
+ }
+ putc ('\n', stderr);
+ if (status)
+ exit (status);
+}
+weak_alias(__error,error)
+
+extern __typeof(error_at_line) __error_at_line attribute_hidden;
+void __error_at_line (int status, int errnum, const char *file_name,
+ unsigned int line_number, const char *message, ...)
+{
+ va_list args;
+
+ if (error_one_per_line) {
+ static const char *old_file_name;
+ static unsigned int old_line_number;
+
+ if (old_line_number == line_number &&
+ (file_name == old_file_name || !strcmp (old_file_name, file_name)))
+ /* Simply return and print nothing. */
+ return;
+
+ old_file_name = file_name;
+ old_line_number = line_number;
+ }
+
+ fflush (stdout);
+
+ if (error_print_progname)
+ (*error_print_progname) ();
+ else
+ fprintf (stderr, "%s:", __uclibc_progname);
+
+ if (file_name != NULL)
+ fprintf (stderr, "%s:%d: ", file_name, line_number);
+
+ va_start (args, message);
+ vfprintf (stderr, message, args);
+ va_end (args);
+
+ ++error_message_count;
+ if (errnum) {
+ fprintf (stderr, ": %s", strerror (errnum));
+ }
+ putc ('\n', stderr);
+ if (status)
+ exit (status);
+}
+weak_alias(__error_at_line,error_at_line)
diff --git a/ap/build/uClibc/libc/misc/file/Makefile b/ap/build/uClibc/libc/misc/file/Makefile
new file mode 100644
index 0000000..4a8f4a0
--- /dev/null
+++ b/ap/build/uClibc/libc/misc/file/Makefile
@@ -0,0 +1,13 @@
+# Makefile for uClibc
+#
+# Copyright (C) 2000-2005 Erik Andersen <andersen@uclibc.org>
+#
+# Licensed under the LGPL v2.1, see the file COPYING.LIB in this tarball.
+#
+
+top_srcdir=../../../
+top_builddir=../../../
+all: objs
+include $(top_builddir)Rules.mak
+include Makefile.in
+include $(top_srcdir)Makerules
diff --git a/ap/build/uClibc/libc/misc/file/Makefile.in b/ap/build/uClibc/libc/misc/file/Makefile.in
new file mode 100644
index 0000000..ace9db0
--- /dev/null
+++ b/ap/build/uClibc/libc/misc/file/Makefile.in
@@ -0,0 +1,26 @@
+# Makefile for uClibc
+#
+# Copyright (C) 2000-2008 Erik Andersen <andersen@uclibc.org>
+#
+# Licensed under the LGPL v2.1, see the file COPYING.LIB in this tarball.
+#
+
+subdirs += libc/misc/file
+
+MISC_FILE_DIR := $(top_srcdir)libc/misc/file
+MISC_FILE_OUT := $(top_builddir)libc/misc/file
+
+MISC_FILE_SRC := $(wildcard $(MISC_FILE_DIR)/*.c)
+ifneq ($(UCLIBC_HAS_LFS),y)
+MISC_FILE_SRC := $(filter-out $(MISC_FILE_DIR)/lockf64.c,$(MISC_FILE_SRC))
+endif
+MISC_FILE_OBJ := $(patsubst $(MISC_FILE_DIR)/%.c,$(MISC_FILE_OUT)/%.o,$(MISC_FILE_SRC))
+
+libc-y += $(MISC_FILE_OBJ)
+
+libc-nomulti-$(UCLIBC_HAS_LFS) += $(MISC_FILE_OUT)/lockf64.o
+
+objclean-y += CLEAN_libc/misc/file
+
+CLEAN_libc/misc/file:
+ $(do_rm) $(addprefix $(MISC_FILE_OUT)/*., o os oS)
diff --git a/ap/build/uClibc/libc/misc/file/lockf.c b/ap/build/uClibc/libc/misc/file/lockf.c
new file mode 100644
index 0000000..b37ace4
--- /dev/null
+++ b/ap/build/uClibc/libc/misc/file/lockf.c
@@ -0,0 +1,75 @@
+/* Copyright (C) 1994, 1996, 1997, 1998, 2000 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 Library General Public License as
+ published by the Free Software Foundation; either version 2 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
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library 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 <features.h>
+
+#include <sys/types.h>
+#include <unistd.h>
+#include <fcntl.h>
+#include <errno.h>
+#include <string.h>
+
+
+
+/* lockf is a simplified interface to fcntl's locking facilities. */
+
+int lockf (int fd, int cmd, off_t len)
+{
+ struct flock fl;
+
+ memset ((char *) &fl, '\0', sizeof (fl));
+
+ /* lockf is always relative to the current file position. */
+ fl.l_whence = SEEK_CUR;
+ fl.l_start = 0;
+ fl.l_len = len;
+
+ switch (cmd)
+ {
+ case F_TEST:
+ /* Test the lock: return 0 if FD is unlocked or locked by this process;
+ return -1, set errno to EACCES, if another process holds the lock. */
+ fl.l_type = F_RDLCK;
+ if (fcntl (fd, F_GETLK, &fl) < 0)
+ return -1;
+ if (fl.l_type == F_UNLCK || fl.l_pid == getpid ())
+ return 0;
+ __set_errno(EACCES);
+ return -1;
+
+ case F_ULOCK:
+ fl.l_type = F_UNLCK;
+ cmd = F_SETLK;
+ break;
+ case F_LOCK:
+ fl.l_type = F_WRLCK;
+ cmd = F_SETLKW;
+ break;
+ case F_TLOCK:
+ fl.l_type = F_WRLCK;
+ cmd = F_SETLK;
+ break;
+
+ default:
+ __set_errno(EINVAL);
+ return -1;
+ }
+
+ return fcntl(fd, cmd, &fl);
+}
+libc_hidden_def(lockf)
diff --git a/ap/build/uClibc/libc/misc/file/lockf64.c b/ap/build/uClibc/libc/misc/file/lockf64.c
new file mode 100644
index 0000000..1779424
--- /dev/null
+++ b/ap/build/uClibc/libc/misc/file/lockf64.c
@@ -0,0 +1,93 @@
+/* Copyright (C) 1994, 1996, 1997, 1998, 2000 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 Library General Public License as
+ published by the Free Software Foundation; either version 2 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
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library 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 <_lfs_64.h>
+
+#include <sys/types.h>
+#include <unistd.h>
+#include <fcntl.h>
+#include <errno.h>
+#include <string.h>
+#include <sys/syscall.h>
+
+#ifdef __NR_fcntl64
+#define flock flock64
+#define fcntl fcntl64
+#undef F_GETLK
+#define F_GETLK F_GETLK64
+#undef F_SETLK
+#define F_SETLK F_SETLK64
+#else
+#endif
+
+
+/* lockf is a simplified interface to fcntl's locking facilities. */
+
+int lockf64 (int fd, int cmd, off64_t len64)
+{
+ struct flock fl;
+ off_t len = (off_t) len64;
+
+ if (len64 != (off64_t) len)
+ {
+ /* We can't represent the length. */
+ __set_errno(EOVERFLOW);
+ return -1;
+ }
+
+ memset((char *) &fl, '\0', sizeof (fl));
+
+ /* lockf is always relative to the current file position. */
+ fl.l_whence = SEEK_CUR;
+ fl.l_start = 0;
+ fl.l_len = len;
+
+ switch (cmd)
+ {
+ case F_TEST:
+ /* Test the lock: return 0 if FD is unlocked or locked by this process;
+ return -1, set errno to EACCES, if another process holds the lock. */
+ fl.l_type = F_RDLCK;
+ if (fcntl (fd, F_GETLK, &fl) < 0)
+ return -1;
+ if (fl.l_type == F_UNLCK || fl.l_pid == getpid ())
+ return 0;
+ __set_errno(EACCES);
+ return -1;
+
+ case F_ULOCK:
+ fl.l_type = F_UNLCK;
+ cmd = F_SETLK;
+ break;
+ case F_LOCK:
+ fl.l_type = F_WRLCK;
+ cmd = F_SETLKW;
+ break;
+ case F_TLOCK:
+ fl.l_type = F_WRLCK;
+ cmd = F_SETLK;
+ break;
+
+ default:
+ __set_errno(EINVAL);
+ return -1;
+ }
+
+ return fcntl(fd, cmd, &fl);
+}
+libc_hidden_def(lockf64)
diff --git a/ap/build/uClibc/libc/misc/fnmatch/.indent.pro b/ap/build/uClibc/libc/misc/fnmatch/.indent.pro
new file mode 100644
index 0000000..492ecf1
--- /dev/null
+++ b/ap/build/uClibc/libc/misc/fnmatch/.indent.pro
@@ -0,0 +1,33 @@
+--blank-lines-after-declarations
+--blank-lines-after-procedures
+--break-before-boolean-operator
+--no-blank-lines-after-commas
+--braces-on-if-line
+--braces-on-struct-decl-line
+--comment-indentation25
+--declaration-comment-column25
+--no-comment-delimiters-on-blank-lines
+--cuddle-else
+--continuation-indentation4
+--case-indentation0
+--else-endif-column33
+--space-after-cast
+--line-comments-indentation0
+--declaration-indentation1
+--dont-format-first-column-comments
+--dont-format-comments
+--honour-newlines
+--indent-level4
+/* changed from 0 to 4 */
+--parameter-indentation4
+--line-length78 /* changed from 75 */
+--continue-at-parentheses
+--no-space-after-function-call-names
+--dont-break-procedure-type
+--dont-star-comments
+--leave-optional-blank-lines
+--dont-space-special-semicolon
+--tab-size4
+/* additions by Mark */
+--case-brace-indentation0
+--leave-preprocessor-space
diff --git a/ap/build/uClibc/libc/misc/fnmatch/Makefile b/ap/build/uClibc/libc/misc/fnmatch/Makefile
new file mode 100644
index 0000000..4a8f4a0
--- /dev/null
+++ b/ap/build/uClibc/libc/misc/fnmatch/Makefile
@@ -0,0 +1,13 @@
+# Makefile for uClibc
+#
+# Copyright (C) 2000-2005 Erik Andersen <andersen@uclibc.org>
+#
+# Licensed under the LGPL v2.1, see the file COPYING.LIB in this tarball.
+#
+
+top_srcdir=../../../
+top_builddir=../../../
+all: objs
+include $(top_builddir)Rules.mak
+include Makefile.in
+include $(top_srcdir)Makerules
diff --git a/ap/build/uClibc/libc/misc/fnmatch/Makefile.in b/ap/build/uClibc/libc/misc/fnmatch/Makefile.in
new file mode 100644
index 0000000..2557b5a
--- /dev/null
+++ b/ap/build/uClibc/libc/misc/fnmatch/Makefile.in
@@ -0,0 +1,27 @@
+# Makefile for uClibc
+#
+# Copyright (C) 2000-2008 Erik Andersen <andersen@uclibc.org>
+#
+# Licensed under the LGPL v2.1, see the file COPYING.LIB in this tarball.
+#
+
+subdirs += libc/misc/fnmatch
+
+ifeq ($(UCLIBC_HAS_FNMATCH_OLD),y)
+CSRC := fnmatch_old.c
+else
+CSRC := fnmatch.c
+endif
+
+MISC_FNMATCH_DIR := $(top_srcdir)libc/misc/fnmatch
+MISC_FNMATCH_OUT := $(top_builddir)libc/misc/fnmatch
+
+MISC_FNMATCH_SRC := $(patsubst %.c,$(MISC_FNMATCH_DIR)/%.c,$(CSRC))
+MISC_FNMATCH_OBJ := $(patsubst %.c,$(MISC_FNMATCH_OUT)/%.o,$(CSRC))
+
+libc-$(UCLIBC_HAS_FNMATCH) += $(MISC_FNMATCH_OBJ)
+
+objclean-y += CLEAN_libc/misc/fnmatch
+
+CLEAN_libc/misc/fnmatch:
+ $(do_rm) $(addprefix $(MISC_FNMATCH_OUT)/*., o os)
diff --git a/ap/build/uClibc/libc/misc/fnmatch/fnmatch.c b/ap/build/uClibc/libc/misc/fnmatch/fnmatch.c
new file mode 100644
index 0000000..2874413
--- /dev/null
+++ b/ap/build/uClibc/libc/misc/fnmatch/fnmatch.c
@@ -0,0 +1,435 @@
+/* Copyright (C) 1991,1992,1993,1996,1997,1998,1999,2000,2001,2002,2003
+ 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. */
+
+#ifdef HAVE_CONFIG_H
+# include <config.h>
+#endif
+
+/* unistd.h must be included with _LIBC defined: we need smallint */
+#include <unistd.h>
+#include <features.h>
+#ifdef __UCLIBC__
+# undef _LIBC
+# define HAVE_STRING_H 1
+# define STDC_HEADERS
+# define HAVE___STRCHRNUL 1
+# ifdef __UCLIBC_HAS_WCHAR__
+# define HAVE_WCHAR_H 1
+# define HAVE_WCTYPE_H 1
+# ifdef __UCLIBC_HAS_LOCALE__
+# define HAVE_MBSTATE_T 1
+# define HAVE_MBSRTOWCS 1
+# endif
+# endif
+#endif
+
+#include <assert.h>
+#include <errno.h>
+#include <fnmatch.h>
+#include <ctype.h>
+
+#if HAVE_STRING_H || defined _LIBC
+# include <string.h>
+#else
+# include <strings.h>
+#endif
+
+#if defined STDC_HEADERS || defined _LIBC
+# include <stdlib.h>
+#endif
+
+#ifdef __UCLIBC__
+# define __memset memset
+#endif
+
+/* For platform which support the ISO C amendement 1 functionality we
+ support user defined character classes. */
+#if defined _LIBC || (defined HAVE_WCTYPE_H && defined HAVE_WCHAR_H)
+/* Solaris 2.5 has a bug: <wchar.h> must be included before <wctype.h>. */
+# include <wchar.h>
+# include <wctype.h>
+#endif
+
+/* We need some of the locale data (the collation sequence information)
+ but there is no interface to get this information in general. Therefore
+ we support a correct implementation only in glibc. */
+#ifdef _LIBC
+# include "../locale/localeinfo.h"
+# include "../locale/elem-hash.h"
+# include "../locale/coll-lookup.h"
+# include <shlib-compat.h>
+
+# define CONCAT(a,b) __CONCAT(a,b)
+# define mbsrtowcs __mbsrtowcs
+# define fnmatch __fnmatch
+extern int fnmatch (const char *pattern, const char *string, int flags);
+#endif
+
+/* We often have to test for FNM_FILE_NAME and FNM_PERIOD being both set. */
+#define NO_LEADING_PERIOD(flags) \
+ ((flags & (FNM_FILE_NAME | FNM_PERIOD)) == (FNM_FILE_NAME | FNM_PERIOD))
+
+/* Comment out all this code if we are using the GNU C Library, and are not
+ actually compiling the library itself. This code is part of the GNU C
+ Library, but also included in many other GNU distributions. Compiling
+ and linking in this code is a waste when using the GNU C library
+ (especially if it is a shared library). Rather than having every GNU
+ program understand `configure --with-gnu-libc' and omit the object files,
+ it is simpler to just do this in the source for each such file. */
+
+#if defined _LIBC || !defined __GNU_LIBRARY__
+
+
+# if defined STDC_HEADERS || !defined 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
+
+# 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))
+
+# define STREQ(s1, s2) ((strcmp (s1, s2) == 0))
+
+# if defined _LIBC || (defined HAVE_WCTYPE_H && defined HAVE_WCHAR_H)
+/* 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
+
+# ifdef _LIBC
+# define ISWCTYPE(WC, WT) __iswctype (WC, WT)
+# else
+# define ISWCTYPE(WC, WT) iswctype (WC, WT)
+# endif
+
+# if (HAVE_MBSTATE_T && HAVE_MBSRTOWCS) || _LIBC
+/* In this case we are implementing the multibyte character handling. */
+# define HANDLE_MULTIBYTE 1
+# 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
+
+/* Avoid depending on library functions or files
+ whose names are inconsistent. */
+
+# if !defined _LIBC && !defined getenv && !defined __UCLIBC__
+extern char *getenv ();
+# endif
+
+# ifndef errno
+extern int errno;
+# endif
+
+/* Global variable. */
+static smallint posixly_correct;
+
+/* This function doesn't exist on most systems. */
+
+# if !defined HAVE___STRCHRNUL && !defined _LIBC
+static char *
+__strchrnul (s, c)
+ const char *s;
+ int c;
+{
+ char *result = strchr (s, c);
+ if (result == NULL)
+ result = strchr (s, '\0');
+ return result;
+}
+# endif
+
+# if HANDLE_MULTIBYTE && !defined HAVE___STRCHRNUL && !defined _LIBC
+static wchar_t *
+__wcschrnul (s, c)
+ const wchar_t *s;
+ wint_t c;
+{
+ wchar_t *result = wcschr (s, c);
+ if (result == NULL)
+ result = wcschr (s, '\0');
+ return result;
+}
+# endif
+
+# ifndef internal_function
+/* Inside GNU libc we mark some function in a special way. In other
+ environments simply ignore the marking. */
+# define internal_function
+# endif
+
+/* Note that this evaluates C many times. */
+# ifdef _LIBC
+# define FOLD(c) ((flags & FNM_CASEFOLD) ? tolower (c) : (c))
+# else
+# define FOLD(c) ((flags & FNM_CASEFOLD) && ISUPPER (c) ? tolower (c) : (c))
+# endif
+# define CHAR char
+# define UCHAR unsigned char
+# define INT int
+# define FCT internal_fnmatch
+# define EXT ext_match
+# define END end_pattern
+# define L(CS) CS
+# ifdef _LIBC
+# define BTOWC(C) __btowc (C)
+# else
+# define BTOWC(C) btowc (C)
+# endif
+# define STRLEN(S) strlen (S)
+# define STRCAT(D, S) strcat (D, S)
+# define MEMPCPY(D, S, N) mempcpy (D, S, N)
+# define MEMCHR(S, C, N) memchr (S, C, N)
+# define STRCOLL(S1, S2) strcoll (S1, S2)
+# include "fnmatch_loop.c"
+
+
+# if HANDLE_MULTIBYTE
+/* Note that this evaluates C many times. */
+# ifdef _LIBC
+# define FOLD(c) ((flags & FNM_CASEFOLD) ? towlower (c) : (c))
+# else
+# define FOLD(c) ((flags & FNM_CASEFOLD) && ISUPPER (c) ? towlower (c) : (c))
+# endif
+# define CHAR wchar_t
+# define UCHAR wint_t
+# define INT wint_t
+# define FCT internal_fnwmatch
+# define EXT ext_wmatch
+# define END end_wpattern
+# define L(CS) L##CS
+# define BTOWC(C) (C)
+# define STRLEN(S) wcslen (S)
+# define STRCAT(D, S) wcscat (D, S)
+# define MEMPCPY(D, S, N) wmempcpy (D, S, N)
+# define MEMCHR(S, C, N) wmemchr (S, C, N)
+# define STRCOLL(S1, S2) wcscoll (S1, S2)
+# ifndef __UCLIBC__
+# define WIDE_CHAR_VERSION 1
+# endif
+
+# undef IS_CHAR_CLASS
+/* We have to convert the wide character string in a multibyte string. But
+ we know that the character class names consist of alphanumeric characters
+ from the portable character set, and since the wide character encoding
+ for a member of the portable character set is the same code point as
+ its single-byte encoding, we can use a simplified method to convert the
+ string to a multibyte character string. */
+static wctype_t
+is_char_class (const wchar_t *wcs)
+{
+ char s[CHAR_CLASS_MAX_LENGTH + 1];
+ char *cp = s;
+
+ do
+ {
+ /* Test for a printable character from the portable character set. */
+# if defined _LIBC || defined __UCLIBC__
+ if (*wcs < 0x20 || *wcs > 0x7e
+ || *wcs == 0x24 || *wcs == 0x40 || *wcs == 0x60)
+ return (wctype_t) 0;
+# else
+ switch (*wcs)
+ {
+ case L' ': case L'!': case L'"': case L'#': case L'%':
+ case L'&': case L'\'': case L'(': case L')': case L'*':
+ case L'+': case L',': case L'-': case L'.': case L'/':
+ case L'0': case L'1': case L'2': case L'3': case L'4':
+ case L'5': case L'6': case L'7': case L'8': case L'9':
+ case L':': case L';': case L'<': case L'=': case L'>':
+ case L'?':
+ case L'A': case L'B': case L'C': case L'D': case L'E':
+ case L'F': case L'G': case L'H': case L'I': case L'J':
+ case L'K': case L'L': case L'M': case L'N': case L'O':
+ case L'P': case L'Q': case L'R': case L'S': case L'T':
+ case L'U': case L'V': case L'W': case L'X': case L'Y':
+ case L'Z':
+ case L'[': case L'\\': case L']': case L'^': case L'_':
+ case L'a': case L'b': case L'c': case L'd': case L'e':
+ case L'f': case L'g': case L'h': case L'i': case L'j':
+ case L'k': case L'l': case L'm': case L'n': case L'o':
+ case L'p': case L'q': case L'r': case L's': case L't':
+ case L'u': case L'v': case L'w': case L'x': case L'y':
+ case L'z': case L'{': case L'|': case L'}': case L'~':
+ break;
+ default:
+ return (wctype_t) 0;
+ }
+# endif
+
+ /* Avoid overrunning the buffer. */
+ if (cp == s + CHAR_CLASS_MAX_LENGTH)
+ return (wctype_t) 0;
+
+ *cp++ = (char) *wcs++;
+ }
+ while (*wcs != L'\0');
+
+ *cp = '\0';
+
+# ifdef _LIBC
+ return __wctype (s);
+# else
+ return wctype (s);
+# endif
+}
+# define IS_CHAR_CLASS(string) is_char_class (string)
+
+# include "fnmatch_loop.c"
+# endif
+
+int
+fnmatch (const char *pattern, const char *string, int flags)
+{
+# if HANDLE_MULTIBYTE
+ if (__builtin_expect (MB_CUR_MAX, 1) != 1)
+ {
+ mbstate_t ps;
+ size_t n;
+ const char *p;
+ wchar_t *wpattern = NULL;
+ wchar_t *wstring = NULL;
+
+ /* Convert the strings into wide characters. */
+ __memset (&ps, '\0', sizeof (ps));
+ p = pattern;
+#ifdef _LIBC
+ n = strnlen (pattern, 1024);
+#else
+ n = strlen (pattern);
+#endif
+ if (__builtin_expect (n < 1024, 1))
+ {
+ wpattern = (wchar_t *) alloca ((n + 1) * sizeof (wchar_t));
+ n = mbsrtowcs (wpattern, &p, n + 1, &ps);
+ if (__builtin_expect (n == (size_t) -1, 0))
+ /* Something wrong.
+ XXX Do we have to set `errno' to something which mbsrtows hasn't
+ already done? */
+ return -1;
+ if (p)
+ __memset (&ps, '\0', sizeof (ps));
+ }
+ if (__builtin_expect (p != NULL, 0))
+ {
+ n = mbsrtowcs (NULL, &pattern, 0, &ps);
+ if (__builtin_expect (n == (size_t) -1, 0))
+ /* Something wrong.
+ XXX Do we have to set `errno' to something which mbsrtows hasn't
+ already done? */
+ return -1;
+ wpattern = (wchar_t *) alloca ((n + 1) * sizeof (wchar_t));
+ assert (mbsinit (&ps));
+ (void) mbsrtowcs (wpattern, &pattern, n + 1, &ps);
+ }
+
+ assert (mbsinit (&ps));
+#ifdef _LIBC
+ n = strnlen (string, 1024);
+#else
+ n = strlen (string);
+#endif
+ p = string;
+ if (__builtin_expect (n < 1024, 1))
+ {
+ wstring = (wchar_t *) alloca ((n + 1) * sizeof (wchar_t));
+ n = mbsrtowcs (wstring, &p, n + 1, &ps);
+ if (__builtin_expect (n == (size_t) -1, 0))
+ /* Something wrong.
+ XXX Do we have to set `errno' to something which mbsrtows hasn't
+ already done? */
+ return -1;
+ if (p)
+ __memset (&ps, '\0', sizeof (ps));
+ }
+ if (__builtin_expect (p != NULL, 0))
+ {
+ n = mbsrtowcs (NULL, &string, 0, &ps);
+ if (__builtin_expect (n == (size_t) -1, 0))
+ /* Something wrong.
+ XXX Do we have to set `errno' to something which mbsrtows hasn't
+ already done? */
+ return -1;
+ wstring = (wchar_t *) alloca ((n + 1) * sizeof (wchar_t));
+ assert (mbsinit (&ps));
+ (void) mbsrtowcs (wstring, &string, n + 1, &ps);
+ }
+
+ return internal_fnwmatch (wpattern, wstring, wstring + n,
+ flags & FNM_PERIOD, flags);
+ }
+# endif /* mbstate_t and mbsrtowcs or _LIBC. */
+
+ return internal_fnmatch (pattern, string, string + strlen (string),
+ flags & FNM_PERIOD, flags);
+}
+
+# ifdef _LIBC
+# undef fnmatch
+versioned_symbol (libc, __fnmatch, fnmatch, GLIBC_2_2_3);
+# if SHLIB_COMPAT(libc, GLIBC_2_0, GLIBC_2_2_3)
+strong_alias (__fnmatch, __fnmatch_old)
+compat_symbol (libc, __fnmatch_old, fnmatch, GLIBC_2_0);
+# endif
+libc_hidden_ver (__fnmatch, fnmatch)
+# else
+libc_hidden_def(fnmatch)
+# endif
+
+#endif /* _LIBC or not __GNU_LIBRARY__. */
diff --git a/ap/build/uClibc/libc/misc/fnmatch/fnmatch_loop.c b/ap/build/uClibc/libc/misc/fnmatch/fnmatch_loop.c
new file mode 100644
index 0000000..af41727
--- /dev/null
+++ b/ap/build/uClibc/libc/misc/fnmatch/fnmatch_loop.c
@@ -0,0 +1,1205 @@
+/* Copyright (C) 1991,1992,1993,1996,1997,1998,1999,2000,2001,2003,2004,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. */
+
+/* Match STRING against the filename pattern PATTERN, returning zero if
+ it matches, nonzero if not. */
+static int FCT (const CHAR *pattern, const CHAR *string,
+ const CHAR *string_end, int no_leading_period, int flags)
+ internal_function;
+static int EXT (INT opt, const CHAR *pattern, const CHAR *string,
+ const CHAR *string_end, int no_leading_period, int flags)
+ internal_function;
+static const CHAR *END (const CHAR *patternp) internal_function;
+
+static int
+internal_function
+FCT (const CHAR *pattern, const CHAR *string, const CHAR *string_end,
+ int no_leading_period, int flags)
+{
+ register const CHAR *p = pattern, *n = string;
+ register UCHAR c;
+#ifdef _LIBC
+# if WIDE_CHAR_VERSION
+ const char *collseq = (const char *)
+ _NL_CURRENT(LC_COLLATE, _NL_COLLATE_COLLSEQWC);
+# else
+ const UCHAR *collseq = (const UCHAR *)
+ _NL_CURRENT(LC_COLLATE, _NL_COLLATE_COLLSEQMB);
+# endif
+#endif
+
+ while ((c = *p++) != L('\0'))
+ {
+ int new_no_leading_period = 0;
+ c = FOLD (c);
+
+ switch (c)
+ {
+ case L('?'):
+ if (__builtin_expect (flags & FNM_EXTMATCH, 0) && *p == '(')
+ {
+ int res;
+
+ res = EXT (c, p, n, string_end, no_leading_period,
+ flags);
+ if (res != -1)
+ return res;
+ }
+
+ if (n == string_end)
+ return FNM_NOMATCH;
+ else if (*n == L('/') && (flags & FNM_FILE_NAME))
+ return FNM_NOMATCH;
+ else if (*n == L('.') && no_leading_period)
+ return FNM_NOMATCH;
+ break;
+
+ case L('\\'):
+ if (!(flags & FNM_NOESCAPE))
+ {
+ c = *p++;
+ if (c == L('\0'))
+ /* Trailing \ loses. */
+ return FNM_NOMATCH;
+ c = FOLD (c);
+ }
+ if (n == string_end || FOLD ((UCHAR) *n) != c)
+ return FNM_NOMATCH;
+ break;
+
+ case L('*'):
+ if (__builtin_expect (flags & FNM_EXTMATCH, 0) && *p == '(')
+ {
+ int res;
+
+ res = EXT (c, p, n, string_end, no_leading_period,
+ flags);
+ if (res != -1)
+ return res;
+ }
+
+ if (n != string_end && *n == L('.') && no_leading_period)
+ return FNM_NOMATCH;
+
+ for (c = *p++; c == L('?') || c == L('*'); c = *p++)
+ {
+ if (*p == L('(') && (flags & FNM_EXTMATCH) != 0)
+ {
+ const CHAR *endp = END (p);
+ if (endp != p)
+ {
+ /* This is a pattern. Skip over it. */
+ p = endp;
+ continue;
+ }
+ }
+
+ if (c == L('?'))
+ {
+ /* A ? needs to match one character. */
+ if (n == string_end)
+ /* There isn't another character; no match. */
+ return FNM_NOMATCH;
+ else if (*n == L('/')
+ && __builtin_expect (flags & FNM_FILE_NAME, 0))
+ /* A slash does not match a wildcard under
+ FNM_FILE_NAME. */
+ return FNM_NOMATCH;
+ else
+ /* One character of the string is consumed in matching
+ this ? wildcard, so *??? won't match if there are
+ less than three characters. */
+ ++n;
+ }
+ }
+
+ if (c == L('\0'))
+ /* The wildcard(s) is/are the last element of the pattern.
+ If the name is a file name and contains another slash
+ this means it cannot match, unless the FNM_LEADING_DIR
+ flag is set. */
+ {
+ int result = (flags & FNM_FILE_NAME) == 0 ? 0 : FNM_NOMATCH;
+
+ if (flags & FNM_FILE_NAME)
+ {
+ if (flags & FNM_LEADING_DIR)
+ result = 0;
+ else
+ {
+ if (MEMCHR (n, L('/'), string_end - n) == NULL)
+ result = 0;
+ }
+ }
+
+ return result;
+ }
+ else
+ {
+ const CHAR *endp;
+
+ endp = MEMCHR (n, (flags & FNM_FILE_NAME) ? L('/') : L('\0'),
+ string_end - n);
+ if (endp == NULL)
+ endp = string_end;
+
+ if (c == L('[')
+ || (__builtin_expect (flags & FNM_EXTMATCH, 0) != 0
+ && (c == L('@') || c == L('+') || c == L('!'))
+ && *p == L('(')))
+ {
+ int flags2 = ((flags & FNM_FILE_NAME)
+ ? flags : (flags & ~FNM_PERIOD));
+ int no_leading_period2 = no_leading_period;
+
+ for (--p; n < endp; ++n, no_leading_period2 = 0)
+ if (FCT (p, n, string_end, no_leading_period2, flags2)
+ == 0)
+ return 0;
+ }
+ else if (c == L('/') && (flags & FNM_FILE_NAME))
+ {
+ while (n < string_end && *n != L('/'))
+ ++n;
+ if (n < string_end && *n == L('/')
+ && (FCT (p, n + 1, string_end, flags & FNM_PERIOD, flags)
+ == 0))
+ return 0;
+ }
+ else
+ {
+ int flags2 = ((flags & FNM_FILE_NAME)
+ ? flags : (flags & ~FNM_PERIOD));
+ int no_leading_period2 = no_leading_period;
+
+ if (c == L('\\') && !(flags & FNM_NOESCAPE))
+ c = *p;
+ c = FOLD (c);
+ for (--p; n < endp; ++n, no_leading_period2 = 0)
+ if (FOLD ((UCHAR) *n) == c
+ && (FCT (p, n, string_end, no_leading_period2, flags2)
+ == 0))
+ return 0;
+ }
+ }
+
+ /* If we come here no match is possible with the wildcard. */
+ return FNM_NOMATCH;
+
+ case L('['):
+ {
+ /* Nonzero if the sense of the character class is inverted. */
+ register int not;
+ CHAR cold;
+ UCHAR fn;
+
+ if (posixly_correct == 0)
+ posixly_correct = getenv ("POSIXLY_CORRECT") != NULL ? 1 : -1;
+
+ if (n == string_end)
+ return FNM_NOMATCH;
+
+ if (*n == L('.') && no_leading_period)
+ return FNM_NOMATCH;
+
+ if (*n == L('/') && (flags & FNM_FILE_NAME))
+ /* `/' cannot be matched. */
+ return FNM_NOMATCH;
+
+ not = (*p == L('!') || (posixly_correct < 0 && *p == L('^')));
+ if (not)
+ ++p;
+
+ fn = FOLD ((UCHAR) *n);
+
+ c = *p++;
+ for (;;)
+ {
+ if (!(flags & FNM_NOESCAPE) && c == L('\\'))
+ {
+ if (*p == L('\0'))
+ return FNM_NOMATCH;
+ c = FOLD ((UCHAR) *p);
+ ++p;
+
+ goto normal_bracket;
+ }
+ else if (c == L('[') && *p == L(':'))
+ {
+ /* 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)
+ wctype_t wt;
+#endif
+ const CHAR *startp = p;
+
+ for (;;)
+ {
+ if (c1 == CHAR_CLASS_MAX_LENGTH)
+ /* The name is too long and therefore the pattern
+ is ill-formed. */
+ return FNM_NOMATCH;
+
+ c = *++p;
+ if (c == L(':') && p[1] == L(']'))
+ {
+ p += 2;
+ break;
+ }
+ if (c < L('a') || c >= L('z'))
+ {
+ /* This cannot possibly be a character class name.
+ Match it as a normal range. */
+ p = startp;
+ c = L('[');
+ goto normal_bracket;
+ }
+ str[c1++] = c;
+ }
+ str[c1] = L('\0');
+
+#if defined _LIBC || (defined HAVE_WCTYPE_H && defined HAVE_WCHAR_H)
+ wt = IS_CHAR_CLASS (str);
+ if (wt == 0)
+ /* Invalid character class name. */
+ return FNM_NOMATCH;
+
+# if defined _LIBC && ! WIDE_CHAR_VERSION
+ /* The following code is glibc specific but does
+ there a good job in speeding up the code since
+ we can avoid the btowc() call. */
+ if (_ISCTYPE ((UCHAR) *n, wt))
+ goto matched;
+# else
+ if (ISWCTYPE (BTOWC ((UCHAR) *n), wt))
+ goto matched;
+# endif
+#else
+ if ((STREQ (str, L("alnum")) && ISALNUM ((UCHAR) *n))
+ || (STREQ (str, L("alpha")) && ISALPHA ((UCHAR) *n))
+ || (STREQ (str, L("blank")) && ISBLANK ((UCHAR) *n))
+ || (STREQ (str, L("cntrl")) && ISCNTRL ((UCHAR) *n))
+ || (STREQ (str, L("digit")) && ISDIGIT ((UCHAR) *n))
+ || (STREQ (str, L("graph")) && ISGRAPH ((UCHAR) *n))
+ || (STREQ (str, L("lower")) && ISLOWER ((UCHAR) *n))
+ || (STREQ (str, L("print")) && ISPRINT ((UCHAR) *n))
+ || (STREQ (str, L("punct")) && ISPUNCT ((UCHAR) *n))
+ || (STREQ (str, L("space")) && ISSPACE ((UCHAR) *n))
+ || (STREQ (str, L("upper")) && ISUPPER ((UCHAR) *n))
+ || (STREQ (str, L("xdigit")) && ISXDIGIT ((UCHAR) *n)))
+ goto matched;
+#endif
+ c = *p++;
+ }
+#ifdef _LIBC
+ else if (c == L('[') && *p == L('='))
+ {
+ UCHAR str[1];
+ uint32_t nrules =
+ _NL_CURRENT_WORD (LC_COLLATE, _NL_COLLATE_NRULES);
+ const CHAR *startp = p;
+
+ c = *++p;
+ if (c == L('\0'))
+ {
+ p = startp;
+ c = L('[');
+ goto normal_bracket;
+ }
+ str[0] = c;
+
+ c = *++p;
+ if (c != L('=') || p[1] != L(']'))
+ {
+ p = startp;
+ c = L('[');
+ goto normal_bracket;
+ }
+ p += 2;
+
+ if (nrules == 0)
+ {
+ if ((UCHAR) *n == str[0])
+ goto matched;
+ }
+ else
+ {
+ const int32_t *table;
+# if WIDE_CHAR_VERSION
+ const int32_t *weights;
+ const int32_t *extra;
+# else
+ const unsigned char *weights;
+ const unsigned char *extra;
+# endif
+ const int32_t *indirect;
+ int32_t idx;
+ const UCHAR *cp = (const UCHAR *) str;
+
+ /* This #include defines a local function! */
+# if WIDE_CHAR_VERSION
+# include <locale/weightwc.h>
+# else
+# include <locale/weight.h>
+# endif
+
+# if WIDE_CHAR_VERSION
+ 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);
+# else
+ 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);
+# endif
+
+ idx = findidx (&cp);
+ if (idx != 0)
+ {
+ /* We found a table entry. Now see whether the
+ character we are currently at has the same
+ equivalance class value. */
+ int len = weights[idx];
+ int32_t idx2;
+ const UCHAR *np = (const UCHAR *) n;
+
+ idx2 = findidx (&np);
+ if (idx2 != 0 && len == weights[idx2])
+ {
+ int cnt = 0;
+
+ while (cnt < len
+ && (weights[idx + 1 + cnt]
+ == weights[idx2 + 1 + cnt]))
+ ++cnt;
+
+ if (cnt == len)
+ goto matched;
+ }
+ }
+ }
+
+ c = *p++;
+ }
+#endif
+ else if (c == L('\0'))
+ /* [ (unterminated) loses. */
+ return FNM_NOMATCH;
+ else
+ {
+ int is_range = 0;
+
+#ifdef _LIBC
+ int is_seqval = 0;
+
+ if (c == L('[') && *p == L('.'))
+ {
+ uint32_t nrules =
+ _NL_CURRENT_WORD (LC_COLLATE, _NL_COLLATE_NRULES);
+ const CHAR *startp = p;
+ size_t c1 = 0;
+
+ while (1)
+ {
+ c = *++p;
+ if (c == L('.') && p[1] == L(']'))
+ {
+ p += 2;
+ break;
+ }
+ if (c == '\0')
+ return FNM_NOMATCH;
+ ++c1;
+ }
+
+ /* We have to handling the symbols differently in
+ ranges since then the collation sequence is
+ important. */
+ is_range = *p == L('-') && p[1] != L('\0');
+
+ if (nrules == 0)
+ {
+ /* There are no names defined in the collation
+ data. Therefore we only accept the trivial
+ names consisting of the character itself. */
+ if (c1 != 1)
+ return FNM_NOMATCH;
+
+ if (!is_range && *n == startp[1])
+ goto matched;
+
+ cold = startp[1];
+ c = *p++;
+ }
+ else
+ {
+ int32_t table_size;
+ const int32_t *symb_table;
+# ifdef WIDE_CHAR_VERSION
+ char str[c1];
+ unsigned int strcnt;
+# else
+# define str (startp + 1)
+# endif
+ const unsigned char *extra;
+ int32_t idx;
+ int32_t elem;
+ int32_t second;
+ int32_t hash;
+
+# ifdef WIDE_CHAR_VERSION
+ /* 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 (strcnt = 0; strcnt < c1; ++strcnt)
+ str[strcnt] = startp[1 + strcnt];
+#endif
+
+ 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 (str, c1);
+
+ idx = 0;
+ elem = hash % table_size;
+ if (symb_table[2 * elem] != 0)
+ {
+ second = hash % (table_size - 2) + 1;
+
+ do
+ {
+ /* 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;
+ }
+ while (symb_table[2 * elem] != 0);
+ }
+
+ if (symb_table[2 * elem] != 0)
+ {
+ /* Compare the byte sequence but only if
+ this is not part of a range. */
+# ifdef WIDE_CHAR_VERSION
+ int32_t *wextra;
+
+ idx += 1 + extra[idx];
+ /* Adjust for the alignment. */
+ idx = (idx + 3) & ~3;
+
+ wextra = (int32_t *) &extra[idx + 4];
+# endif
+
+ if (! is_range)
+ {
+# ifdef WIDE_CHAR_VERSION
+ for (c1 = 0;
+ (int32_t) c1 < wextra[idx];
+ ++c1)
+ if (n[c1] != wextra[1 + c1])
+ break;
+
+ if ((int32_t) c1 == wextra[idx])
+ goto matched;
+# else
+ for (c1 = 0; c1 < extra[idx]; ++c1)
+ if (n[c1] != extra[1 + c1])
+ break;
+
+ if (c1 == extra[idx])
+ goto matched;
+# endif
+ }
+
+ /* Get the collation sequence value. */
+ is_seqval = 1;
+# ifdef WIDE_CHAR_VERSION
+ cold = wextra[1 + wextra[idx]];
+# else
+ /* Adjust for the alignment. */
+ idx += 1 + extra[idx];
+ idx = (idx + 3) & ~4;
+ cold = *((int32_t *) &extra[idx]);
+# endif
+
+ c = *p++;
+ }
+ else if (c1 == 1)
+ {
+ /* No valid character. Match it as a
+ single byte. */
+ if (!is_range && *n == str[0])
+ goto matched;
+
+ cold = str[0];
+ c = *p++;
+ }
+ else
+ return FNM_NOMATCH;
+ }
+ }
+ else
+# undef str
+#endif
+ {
+ c = FOLD (c);
+ normal_bracket:
+
+ /* We have to handling the symbols differently in
+ ranges since then the collation sequence is
+ important. */
+ is_range = (*p == L('-') && p[1] != L('\0')
+ && p[1] != L(']'));
+
+ if (!is_range && c == fn)
+ goto matched;
+
+ /* This is needed if we goto normal_bracket; from
+ outside of is_seqval's scope. */
+#ifndef __UCLIBC__ /* this should be probably ifdef _LIBC*/
+ is_seqval = 0;
+#endif
+ cold = c;
+ c = *p++;
+ }
+
+ if (c == L('-') && *p != L(']'))
+ {
+#if _LIBC
+ /* We have to find the collation sequence
+ value for C. Collation sequence is nothing
+ we can regularly access. The sequence
+ value is defined by the order in which the
+ definitions of the collation values for the
+ various characters appear in the source
+ file. A strange concept, nowhere
+ documented. */
+ uint32_t fcollseq;
+ uint32_t lcollseq;
+ UCHAR cend = *p++;
+
+# ifdef WIDE_CHAR_VERSION
+ /* Search in the `names' array for the characters. */
+ fcollseq = __collseq_table_lookup (collseq, fn);
+ if (fcollseq == ~((uint32_t) 0))
+ /* XXX We don't know anything about the character
+ we are supposed to match. This means we are
+ failing. */
+ goto range_not_matched;
+
+ if (is_seqval)
+ lcollseq = cold;
+ else
+ lcollseq = __collseq_table_lookup (collseq, cold);
+# else
+ fcollseq = collseq[fn];
+ lcollseq = is_seqval ? cold : collseq[(UCHAR) cold];
+# endif
+
+ is_seqval = 0;
+ if (cend == L('[') && *p == L('.'))
+ {
+ uint32_t nrules =
+ _NL_CURRENT_WORD (LC_COLLATE,
+ _NL_COLLATE_NRULES);
+ const CHAR *startp = p;
+ size_t c1 = 0;
+
+ while (1)
+ {
+ c = *++p;
+ if (c == L('.') && p[1] == L(']'))
+ {
+ p += 2;
+ break;
+ }
+ if (c == '\0')
+ return FNM_NOMATCH;
+ ++c1;
+ }
+
+ if (nrules == 0)
+ {
+ /* There are no names defined in the
+ collation data. Therefore we only
+ accept the trivial names consisting
+ of the character itself. */
+ if (c1 != 1)
+ return FNM_NOMATCH;
+
+ cend = startp[1];
+ }
+ else
+ {
+ int32_t table_size;
+ const int32_t *symb_table;
+# ifdef WIDE_CHAR_VERSION
+ char str[c1];
+ unsigned int strcnt;
+# else
+# define str (startp + 1)
+# endif
+ const unsigned char *extra;
+ int32_t idx;
+ int32_t elem;
+ int32_t second;
+ int32_t hash;
+
+# ifdef WIDE_CHAR_VERSION
+ /* 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 (strcnt = 0; strcnt < c1; ++strcnt)
+ str[strcnt] = startp[1 + strcnt];
+# endif
+
+ 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 (str, c1);
+
+ idx = 0;
+ elem = hash % table_size;
+ if (symb_table[2 * elem] != 0)
+ {
+ second = hash % (table_size - 2) + 1;
+
+ do
+ {
+ /* 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;
+ }
+ while (symb_table[2 * elem] != 0);
+ }
+
+ if (symb_table[2 * elem] != 0)
+ {
+ /* Compare the byte sequence but only if
+ this is not part of a range. */
+# ifdef WIDE_CHAR_VERSION
+ int32_t *wextra;
+
+ idx += 1 + extra[idx];
+ /* Adjust for the alignment. */
+ idx = (idx + 3) & ~4;
+
+ wextra = (int32_t *) &extra[idx + 4];
+# endif
+ /* Get the collation sequence value. */
+ is_seqval = 1;
+# ifdef WIDE_CHAR_VERSION
+ cend = wextra[1 + wextra[idx]];
+# else
+ /* Adjust for the alignment. */
+ idx += 1 + extra[idx];
+ idx = (idx + 3) & ~4;
+ cend = *((int32_t *) &extra[idx]);
+# endif
+ }
+ else if (symb_table[2 * elem] != 0 && c1 == 1)
+ {
+ cend = str[0];
+ c = *p++;
+ }
+ else
+ return FNM_NOMATCH;
+ }
+# undef str
+ }
+ else
+ {
+ if (!(flags & FNM_NOESCAPE) && cend == L('\\'))
+ cend = *p++;
+ if (cend == L('\0'))
+ return FNM_NOMATCH;
+ cend = FOLD (cend);
+ }
+
+ /* XXX It is not entirely clear to me how to handle
+ characters which are not mentioned in the
+ collation specification. */
+ if (
+# ifdef WIDE_CHAR_VERSION
+ lcollseq == 0xffffffff ||
+# endif
+ lcollseq <= fcollseq)
+ {
+ /* We have to look at the upper bound. */
+ uint32_t hcollseq;
+
+ if (is_seqval)
+ hcollseq = cend;
+ else
+ {
+# ifdef WIDE_CHAR_VERSION
+ hcollseq =
+ __collseq_table_lookup (collseq, cend);
+ if (hcollseq == ~((uint32_t) 0))
+ {
+ /* Hum, no information about the upper
+ bound. The matching succeeds if the
+ lower bound is matched exactly. */
+ if (lcollseq != fcollseq)
+ goto range_not_matched;
+
+ goto matched;
+ }
+# else
+ hcollseq = collseq[cend];
+# endif
+ }
+
+ if (lcollseq <= hcollseq && fcollseq <= hcollseq)
+ goto matched;
+ }
+# ifdef WIDE_CHAR_VERSION
+ range_not_matched:
+# endif
+#else
+ /* We use a boring value comparison of the character
+ values. This is better than comparing using
+ `strcoll' since the latter would have surprising
+ and sometimes fatal consequences. */
+ UCHAR cend = *p++;
+
+ if (!(flags & FNM_NOESCAPE) && cend == L('\\'))
+ cend = *p++;
+ if (cend == L('\0'))
+ return FNM_NOMATCH;
+
+ /* It is a range. */
+ if (cold <= fn && fn <= cend)
+ goto matched;
+#endif
+
+ c = *p++;
+ }
+ }
+
+ if (c == L(']'))
+ break;
+ }
+
+ if (!not)
+ return FNM_NOMATCH;
+ break;
+
+ matched:
+ /* Skip the rest of the [...] that already matched. */
+ do
+ {
+ ignore_next:
+ c = *p++;
+
+ if (c == L('\0'))
+ /* [... (unterminated) loses. */
+ return FNM_NOMATCH;
+
+ if (!(flags & FNM_NOESCAPE) && c == L('\\'))
+ {
+ if (*p == L('\0'))
+ return FNM_NOMATCH;
+ /* XXX 1003.2d11 is unclear if this is right. */
+ ++p;
+ }
+ else if (c == L('[') && *p == L(':'))
+ {
+ int c1 = 0;
+ const CHAR *startp = p;
+
+ while (1)
+ {
+ c = *++p;
+ if (++c1 == CHAR_CLASS_MAX_LENGTH)
+ return FNM_NOMATCH;
+
+ if (*p == L(':') && p[1] == L(']'))
+ break;
+
+ if (c < L('a') || c >= L('z'))
+ {
+ p = startp;
+ goto ignore_next;
+ }
+ }
+ p += 2;
+ c = *p++;
+ }
+ else if (c == L('[') && *p == L('='))
+ {
+ c = *++p;
+ if (c == L('\0'))
+ return FNM_NOMATCH;
+ c = *++p;
+ if (c != L('=') || p[1] != L(']'))
+ return FNM_NOMATCH;
+ p += 2;
+ c = *p++;
+ }
+ else if (c == L('[') && *p == L('.'))
+ {
+ ++p;
+ while (1)
+ {
+ c = *++p;
+ if (c == '\0')
+ return FNM_NOMATCH;
+
+ if (*p == L('.') && p[1] == L(']'))
+ break;
+ }
+ p += 2;
+ c = *p++;
+ }
+ }
+ while (c != L(']'));
+ if (not)
+ return FNM_NOMATCH;
+ }
+ break;
+
+ case L('+'):
+ case L('@'):
+ case L('!'):
+ if (__builtin_expect (flags & FNM_EXTMATCH, 0) && *p == '(')
+ {
+ int res;
+
+ res = EXT (c, p, n, string_end, no_leading_period, flags);
+ if (res != -1)
+ return res;
+ }
+ goto normal_match;
+
+ case L('/'):
+ if (NO_LEADING_PERIOD (flags))
+ {
+ if (n == string_end || c != (UCHAR) *n)
+ return FNM_NOMATCH;
+
+ new_no_leading_period = 1;
+ break;
+ }
+ /* FALLTHROUGH */
+ default:
+ normal_match:
+ if (n == string_end || c != FOLD ((UCHAR) *n))
+ return FNM_NOMATCH;
+ }
+
+ no_leading_period = new_no_leading_period;
+ ++n;
+ }
+
+ if (n == string_end)
+ return 0;
+
+ if ((flags & FNM_LEADING_DIR) && n != string_end && *n == L('/'))
+ /* The FNM_LEADING_DIR flag says that "foo*" matches "foobar/frobozz". */
+ return 0;
+
+ return FNM_NOMATCH;
+}
+
+
+static const CHAR *
+internal_function
+END (const CHAR *pattern)
+{
+ const CHAR *p = pattern;
+
+ while (1)
+ if (*++p == L('\0'))
+ /* This is an invalid pattern. */
+ return pattern;
+ else if (*p == L('['))
+ {
+ /* Handle brackets special. */
+ if (posixly_correct == 0)
+ posixly_correct = getenv ("POSIXLY_CORRECT") != NULL ? 1 : -1;
+
+ /* Skip the not sign. We have to recognize it because of a possibly
+ following ']'. */
+ if (*++p == L('!') || (posixly_correct < 0 && *p == L('^')))
+ ++p;
+ /* A leading ']' is recognized as such. */
+ if (*p == L(']'))
+ ++p;
+ /* Skip over all characters of the list. */
+ while (*p != L(']'))
+ if (*p++ == L('\0'))
+ /* This is no valid pattern. */
+ return pattern;
+ }
+ else if ((*p == L('?') || *p == L('*') || *p == L('+') || *p == L('@')
+ || *p == L('!')) && p[1] == L('('))
+ p = END (p + 1);
+ else if (*p == L(')'))
+ break;
+
+ return p + 1;
+}
+
+
+static int
+internal_function
+EXT (INT opt, const CHAR *pattern, const CHAR *string, const CHAR *string_end,
+ int no_leading_period, int flags)
+{
+ const CHAR *startp;
+ int level;
+ struct patternlist
+ {
+ struct patternlist *next;
+ CHAR str[0];
+ } *list = NULL;
+ struct patternlist **lastp = &list;
+ size_t pattern_len = STRLEN (pattern);
+ const CHAR *p;
+ const CHAR *rs;
+
+ /* Parse the pattern. Store the individual parts in the list. */
+ level = 0;
+ for (startp = p = pattern + 1; level >= 0; ++p)
+ if (*p == L('\0'))
+ /* This is an invalid pattern. */
+ return -1;
+ else if (*p == L('['))
+ {
+ /* Handle brackets special. */
+ if (posixly_correct == 0)
+ posixly_correct = getenv ("POSIXLY_CORRECT") != NULL ? 1 : -1;
+
+ /* Skip the not sign. We have to recognize it because of a possibly
+ following ']'. */
+ if (*++p == L('!') || (posixly_correct < 0 && *p == L('^')))
+ ++p;
+ /* A leading ']' is recognized as such. */
+ if (*p == L(']'))
+ ++p;
+ /* Skip over all characters of the list. */
+ while (*p != L(']'))
+ if (*p++ == L('\0'))
+ /* This is no valid pattern. */
+ return -1;
+ }
+ else if ((*p == L('?') || *p == L('*') || *p == L('+') || *p == L('@')
+ || *p == L('!')) && p[1] == L('('))
+ /* Remember the nesting level. */
+ ++level;
+ else if (*p == L(')'))
+ {
+ if (level-- == 0)
+ {
+ /* This means we found the end of the pattern. */
+#define NEW_PATTERN \
+ struct patternlist *newp; \
+ \
+ if (opt == L('?') || opt == L('@')) \
+ newp = alloca (sizeof (struct patternlist) \
+ + (pattern_len * sizeof (CHAR))); \
+ else \
+ newp = alloca (sizeof (struct patternlist) \
+ + ((p - startp + 1) * sizeof (CHAR))); \
+ *((CHAR *) MEMPCPY (newp->str, startp, p - startp)) = L('\0'); \
+ newp->next = NULL; \
+ *lastp = newp; \
+ lastp = &newp->next
+ NEW_PATTERN;
+ }
+ }
+ else if (*p == L('|'))
+ {
+ if (level == 0)
+ {
+ NEW_PATTERN;
+ startp = p + 1;
+ }
+ }
+ assert (list != NULL);
+ assert (p[-1] == L(')'));
+#undef NEW_PATTERN
+
+ switch (opt)
+ {
+ case L('*'):
+ if (FCT (p, string, string_end, no_leading_period, flags) == 0)
+ return 0;
+ /* FALLTHROUGH */
+
+ case L('+'):
+ do
+ {
+ for (rs = string; rs <= string_end; ++rs)
+ /* First match the prefix with the current pattern with the
+ current pattern. */
+ if (FCT (list->str, string, rs, no_leading_period,
+ flags & FNM_FILE_NAME ? flags : flags & ~FNM_PERIOD) == 0
+ /* This was successful. Now match the rest with the rest
+ of the pattern. */
+ && (FCT (p, rs, string_end,
+ rs == string
+ ? no_leading_period
+ : rs[-1] == '/' && NO_LEADING_PERIOD (flags) ? 1 : 0,
+ flags & FNM_FILE_NAME
+ ? flags : flags & ~FNM_PERIOD) == 0
+ /* This didn't work. Try the whole pattern. */
+ || (rs != string
+ && FCT (pattern - 1, rs, string_end,
+ rs == string
+ ? no_leading_period
+ : (rs[-1] == '/' && NO_LEADING_PERIOD (flags)
+ ? 1 : 0),
+ flags & FNM_FILE_NAME
+ ? flags : flags & ~FNM_PERIOD) == 0)))
+ /* It worked. Signal success. */
+ return 0;
+ }
+ while ((list = list->next) != NULL);
+
+ /* None of the patterns lead to a match. */
+ return FNM_NOMATCH;
+
+ case L('?'):
+ if (FCT (p, string, string_end, no_leading_period, flags) == 0)
+ return 0;
+ /* FALLTHROUGH */
+
+ case L('@'):
+ do
+ /* I cannot believe it but `strcat' is actually acceptable
+ here. Match the entire string with the prefix from the
+ pattern list and the rest of the pattern following the
+ pattern list. */
+ if (FCT (STRCAT (list->str, p), string, string_end,
+ no_leading_period,
+ flags & FNM_FILE_NAME ? flags : flags & ~FNM_PERIOD) == 0)
+ /* It worked. Signal success. */
+ return 0;
+ while ((list = list->next) != NULL);
+
+ /* None of the patterns lead to a match. */
+ return FNM_NOMATCH;
+
+ case L('!'):
+ for (rs = string; rs <= string_end; ++rs)
+ {
+ struct patternlist *runp;
+
+ for (runp = list; runp != NULL; runp = runp->next)
+ if (FCT (runp->str, string, rs, no_leading_period,
+ flags & FNM_FILE_NAME ? flags : flags & ~FNM_PERIOD) == 0)
+ break;
+
+ /* If none of the patterns matched see whether the rest does. */
+ if (runp == NULL
+ && (FCT (p, rs, string_end,
+ rs == string
+ ? no_leading_period
+ : rs[-1] == '/' && NO_LEADING_PERIOD (flags) ? 1 : 0,
+ flags & FNM_FILE_NAME ? flags : flags & ~FNM_PERIOD)
+ == 0))
+ /* This is successful. */
+ return 0;
+ }
+
+ /* None of the patterns together with the rest of the pattern
+ lead to a match. */
+ return FNM_NOMATCH;
+
+ default:
+ assert (! "Invalid extended matching operator");
+ break;
+ }
+
+ return -1;
+}
+
+
+#undef FOLD
+#undef CHAR
+#undef UCHAR
+#undef INT
+#undef FCT
+#undef EXT
+#undef END
+#undef MEMPCPY
+#undef MEMCHR
+#undef STRCOLL
+#undef STRLEN
+#undef STRCAT
+#undef L
+#undef BTOWC
diff --git a/ap/build/uClibc/libc/misc/fnmatch/fnmatch_old.c b/ap/build/uClibc/libc/misc/fnmatch/fnmatch_old.c
new file mode 100644
index 0000000..2dece85
--- /dev/null
+++ b/ap/build/uClibc/libc/misc/fnmatch/fnmatch_old.c
@@ -0,0 +1,220 @@
+/* Copyright (C) 1991, 1992, 1993, 1996 Free Software Foundation, Inc.
+
+This library is free software; you can redistribute it and/or
+modify it under the terms of the GNU Library General Public License as
+published by the Free Software Foundation; either version 2 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
+Library General Public License for more details.
+
+You should have received a copy of the GNU Library General Public
+License along with this library; see the file COPYING.LIB. If
+not, write to the Free Software Foundation, Inc., 675 Mass Ave,
+Cambridge, MA 02139, USA. */
+
+#ifdef HAVE_CONFIG_H
+# include <config.h>
+#endif
+
+#include <errno.h>
+#include <fnmatch.h>
+#include <ctype.h>
+
+
+/* Comment out all this code if we are using the GNU C Library, and are not
+ actually compiling the library itself. This code is part of the GNU C
+ Library, but also included in many other GNU distributions. Compiling
+ and linking in this code is a waste when using the GNU C library
+ (especially if it is a shared library). Rather than having every GNU
+ program understand `configure --with-gnu-libc' and omit the object files,
+ it is simpler to just do this in the source for each such file. */
+
+#if defined (_LIBC) || !defined (__GNU_LIBRARY__)
+
+
+# if defined (STDC_HEADERS) || !defined (isascii)
+# define ISASCII(c) 1
+# else
+# define ISASCII(c) isascii(c)
+# endif
+
+# define ISUPPER(c) (ISASCII (c) && isupper (c))
+
+
+/* Match STRING against the filename pattern PATTERN, returning zero if
+ it matches, nonzero if not. */
+int fnmatch(const char *pattern, const char *string, int flags)
+{
+ register const char *p = pattern, *n = string;
+ register char c;
+
+/* Note that this evaluates C many times. */
+# define FOLD(c) ((flags & FNM_CASEFOLD) && ISUPPER (c) ? tolower (c) : (c))
+
+ while ((c = *p++) != '\0') {
+ c = FOLD(c);
+
+ switch (c) {
+ case '?':
+ if (*n == '\0')
+ return FNM_NOMATCH;
+ else if ((flags & FNM_FILE_NAME) && *n == '/')
+ return FNM_NOMATCH;
+ else if ((flags & FNM_PERIOD) && *n == '.' &&
+ (n == string
+ || ((flags & FNM_FILE_NAME)
+ && n[-1] == '/'))) return FNM_NOMATCH;
+ break;
+
+ case '\\':
+ if (!(flags & FNM_NOESCAPE)) {
+ c = *p++;
+ if (c == '\0')
+ /* Trailing \ loses. */
+ return FNM_NOMATCH;
+ c = FOLD(c);
+ }
+ if (FOLD(*n) != c)
+ return FNM_NOMATCH;
+ break;
+
+ case '*':
+ if ((flags & FNM_PERIOD) && *n == '.' &&
+ (n == string || ((flags & FNM_FILE_NAME) && n[-1] == '/')))
+ return FNM_NOMATCH;
+
+ for (c = *p++; c == '?' || c == '*'; c = *p++) {
+ if ((flags & FNM_FILE_NAME) && *n == '/')
+ /* A slash does not match a wildcard under FNM_FILE_NAME. */
+ return FNM_NOMATCH;
+ else if (c == '?') {
+ /* A ? needs to match one character. */
+ if (*n == '\0')
+ /* There isn't another character; no match. */
+ return FNM_NOMATCH;
+ else
+ /* One character of the string is consumed in matching
+ this ? wildcard, so *??? won't match if there are
+ less than three characters. */
+ ++n;
+ }
+ }
+
+ if (c == '\0')
+ return 0;
+
+ {
+ char c1 = (!(flags & FNM_NOESCAPE) && c == '\\') ? *p : c;
+
+ c1 = FOLD(c1);
+ for (--p; *n != '\0'; ++n)
+ if ((c == '[' || FOLD(*n) == c1) &&
+ fnmatch(p, n, flags & ~FNM_PERIOD) == 0)
+ return 0;
+ return FNM_NOMATCH;
+ }
+
+ case '[':
+ {
+ /* Nonzero if the sense of the character class is inverted. */
+ register int not;
+
+ if (*n == '\0')
+ return FNM_NOMATCH;
+
+ if ((flags & FNM_PERIOD) && *n == '.' &&
+ (n == string || ((flags & FNM_FILE_NAME) && n[-1] == '/')))
+ return FNM_NOMATCH;
+
+ not = (*p == '!' || *p == '^');
+ if (not)
+ ++p;
+
+ c = *p++;
+ for (;;) {
+ register char cstart = c, cend = c;
+
+ if (!(flags & FNM_NOESCAPE) && c == '\\') {
+ if (*p == '\0')
+ return FNM_NOMATCH;
+ cstart = cend = *p++;
+ }
+
+ cstart = cend = FOLD(cstart);
+
+ if (c == '\0')
+ /* [ (unterminated) loses. */
+ return FNM_NOMATCH;
+
+ c = *p++;
+ c = FOLD(c);
+
+ if ((flags & FNM_FILE_NAME) && c == '/')
+ /* [/] can never match. */
+ return FNM_NOMATCH;
+
+ if (c == '-' && *p != ']') {
+ cend = *p++;
+ if (!(flags & FNM_NOESCAPE) && cend == '\\')
+ cend = *p++;
+ if (cend == '\0')
+ return FNM_NOMATCH;
+ cend = FOLD(cend);
+
+ c = *p++;
+ }
+
+ if (FOLD(*n) >= cstart && FOLD(*n) <= cend)
+ goto matched;
+
+ if (c == ']')
+ break;
+ }
+ if (!not)
+ return FNM_NOMATCH;
+ break;
+
+ matched:;
+ /* Skip the rest of the [...] that already matched. */
+ while (c != ']') {
+ if (c == '\0')
+ /* [... (unterminated) loses. */
+ return FNM_NOMATCH;
+
+ c = *p++;
+ if (!(flags & FNM_NOESCAPE) && c == '\\') {
+ if (*p == '\0')
+ return FNM_NOMATCH;
+ /* XXX 1003.2d11 is unclear if this is right. */
+ ++p;
+ }
+ }
+ if (not)
+ return FNM_NOMATCH;
+ }
+ break;
+
+ default:
+ if (c != FOLD(*n))
+ return FNM_NOMATCH;
+ }
+
+ ++n;
+ }
+
+ if (*n == '\0')
+ return 0;
+
+ if ((flags & FNM_LEADING_DIR) && *n == '/')
+ /* The FNM_LEADING_DIR flag says that "foo*" matches "foobar/frobozz". */
+ return 0;
+
+ return FNM_NOMATCH;
+
+# undef FOLD
+}
+libc_hidden_def(fnmatch)
+#endif /* _LIBC or not __GNU_LIBRARY__. */
diff --git a/ap/build/uClibc/libc/misc/fts/Makefile b/ap/build/uClibc/libc/misc/fts/Makefile
new file mode 100644
index 0000000..1361db3
--- /dev/null
+++ b/ap/build/uClibc/libc/misc/fts/Makefile
@@ -0,0 +1,14 @@
+# Makefile for uClibc
+#
+# Copyright (C) 2009 STMicroelectronics Ltd.
+# Author: Salvatore Cro <salvatore.cro at st.com>
+#
+# Licensed under the LGPL v2.1, see the file COPYING.LIB in this tarball.
+#
+
+top_srcdir=../../../
+top_builddir=../../../
+all: objs
+include $(top_builddir)Rules.mak
+include Makefile.in
+include $(top_srcdir)Makerules
diff --git a/ap/build/uClibc/libc/misc/fts/Makefile.in b/ap/build/uClibc/libc/misc/fts/Makefile.in
new file mode 100644
index 0000000..a1d0efa
--- /dev/null
+++ b/ap/build/uClibc/libc/misc/fts/Makefile.in
@@ -0,0 +1,23 @@
+# FTS Makefile for uClibc
+#
+# Copyright (C) 2009 STMicroelectronics Ltd.
+# Author: Salvatore Cro <salvatore.cro at st.com>
+#
+# Licensed under the LGPL v2.1, see the file COPYING.LIB in this tarball.
+#
+
+subdirs += libc/misc/fts
+CSRC := fts.c
+
+MISC_FTS_DIR := $(top_srcdir)libc/misc/fts
+MISC_FTS_OUT := $(top_builddir)libc/misc/fts
+
+MISC_FTS_SRC := $(patsubst %.c,$(MISC_FTS_DIR)/%.c,$(CSRC))
+MISC_FTS_OBJ := $(patsubst %.c,$(MISC_FTS_OUT)/%.o,$(CSRC))
+
+libc-$(UCLIBC_HAS_FTS) += $(MISC_FTS_OBJ)
+
+objclean-y += CLEAN_libc/misc/fts
+
+CLEAN_libc/misc/fts:
+ $(do_rm) $(addprefix $(MISC_FTS_OUT)/*., o os)
diff --git a/ap/build/uClibc/libc/misc/fts/fts.c b/ap/build/uClibc/libc/misc/fts/fts.c
new file mode 100644
index 0000000..deb8f4a
--- /dev/null
+++ b/ap/build/uClibc/libc/misc/fts/fts.c
@@ -0,0 +1,1113 @@
+/*-
+ * Copyright (c) 1990, 1993, 1994
+ * The Regents of the University of California. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. 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.
+ * 4. Neither the name of the University 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 REGENTS 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 REGENTS 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 <sys/param.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <dirent.h>
+#include <errno.h>
+#include <fts.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+
+#ifdef __UCLIBC_HAS_LFS__
+# include <_lfs_64.h>
+#else
+# define stat64 stat
+# define fstat64 fstat
+#endif
+
+/* Largest alignment size needed, minus one.
+ Usually long double is the worst case. */
+#ifndef ALIGNBYTES
+#define ALIGNBYTES (__alignof__ (long double) - 1)
+#endif
+/* Align P to that size. */
+#ifndef ALIGN
+#define ALIGN(p) (((unsigned long int) (p) + ALIGNBYTES) & ~ALIGNBYTES)
+#endif
+
+
+static FTSENT *fts_alloc (FTS *, const char *, size_t) internal_function;
+static FTSENT *fts_build (FTS *, int) internal_function;
+static void fts_lfree (FTSENT *) internal_function;
+static void fts_load (FTS *, FTSENT *) internal_function;
+static size_t fts_maxarglen (char * const *) internal_function;
+static void fts_padjust (FTS *, FTSENT *) internal_function;
+static int fts_palloc (FTS *, size_t) internal_function;
+static FTSENT *fts_sort (FTS *, FTSENT *, int) internal_function;
+static u_short fts_stat (FTS *, FTSENT *, int) internal_function;
+static int fts_safe_changedir (FTS *, FTSENT *, int, const char *)
+ internal_function;
+
+#ifndef MAX
+#define MAX(a, b) ({ __typeof__ (a) _a = (a); \
+ __typeof__ (b) _b = (b); \
+ _a > _b ? _a : _b; })
+#endif
+
+#define ISDOT(a) (a[0] == '.' && (!a[1] || (a[1] == '.' && !a[2])))
+
+#define CLR(opt) (sp->fts_options &= ~(opt))
+#define ISSET(opt) (sp->fts_options & (opt))
+#define SET(opt) (sp->fts_options |= (opt))
+
+#define FCHDIR(sp, fd) (!ISSET(FTS_NOCHDIR) && fchdir(fd))
+
+/* fts_build flags */
+#define BCHILD 1 /* fts_children */
+#define BNAMES 2 /* fts_children, names only */
+#define BREAD 3 /* fts_read */
+
+FTS *
+fts_open( char * const *argv, register int options,
+ int (*compar) (const FTSENT **, const FTSENT **))
+{
+ register FTS *sp;
+ register FTSENT *p, *root;
+ register int nitems;
+ FTSENT *parent = NULL;
+ FTSENT *tmp = NULL;
+
+ /* Options check. */
+ if (options & ~FTS_OPTIONMASK) {
+ __set_errno (EINVAL);
+ return (NULL);
+ }
+
+ /* Allocate/initialize the stream */
+ if ((sp = malloc((u_int)sizeof(FTS))) == NULL)
+ return (NULL);
+ memset(sp, 0, sizeof(FTS));
+ sp->fts_compar = (int (*) (const void *, const void *)) compar;
+ sp->fts_options = options;
+
+ /* Logical walks turn on NOCHDIR; symbolic links are too hard. */
+ if (ISSET(FTS_LOGICAL))
+ SET(FTS_NOCHDIR);
+
+ /*
+ * Start out with 1K of path space, and enough, in any case,
+ * to hold the user's paths.
+ */
+#ifndef MAXPATHLEN
+#define MAXPATHLEN 1024
+#endif
+ size_t maxarglen = fts_maxarglen(argv);
+ if (fts_palloc(sp, MAX(maxarglen, MAXPATHLEN)))
+ goto mem1;
+
+ /* Allocate/initialize root's parent. */
+ if (*argv != NULL) {
+ if ((parent = fts_alloc(sp, "", 0)) == NULL)
+ goto mem2;
+ parent->fts_level = FTS_ROOTPARENTLEVEL;
+ }
+
+ /* Allocate/initialize root(s). */
+ for (root = NULL, nitems = 0; *argv != NULL; ++argv, ++nitems) {
+ /* Don't allow zero-length paths. */
+ size_t len = strlen(*argv);
+ if (len == 0) {
+ __set_errno (ENOENT);
+ goto mem3;
+ }
+
+ p = fts_alloc(sp, *argv, len);
+ p->fts_level = FTS_ROOTLEVEL;
+ p->fts_parent = parent;
+ p->fts_accpath = p->fts_name;
+ p->fts_info = fts_stat(sp, p, ISSET(FTS_COMFOLLOW));
+
+ /* Command-line "." and ".." are real directories. */
+ if (p->fts_info == FTS_DOT)
+ p->fts_info = FTS_D;
+
+ /*
+ * If comparison routine supplied, traverse in sorted
+ * order; otherwise traverse in the order specified.
+ */
+ if (compar) {
+ p->fts_link = root;
+ root = p;
+ } else {
+ p->fts_link = NULL;
+ if (root == NULL)
+ tmp = root = p;
+ else {
+ tmp->fts_link = p;
+ tmp = p;
+ }
+ }
+ }
+ if (compar && nitems > 1)
+ root = fts_sort(sp, root, nitems);
+
+ /*
+ * Allocate a dummy pointer and make fts_read think that we've just
+ * finished the node before the root(s); set p->fts_info to FTS_INIT
+ * so that everything about the "current" node is ignored.
+ */
+ if ((sp->fts_cur = fts_alloc(sp, "", 0)) == NULL)
+ goto mem3;
+ sp->fts_cur->fts_link = root;
+ sp->fts_cur->fts_info = FTS_INIT;
+
+ /*
+ * If using chdir(2), grab a file descriptor pointing to dot to ensure
+ * that we can get back here; this could be avoided for some paths,
+ * but almost certainly not worth the effort. Slashes, symbolic links,
+ * and ".." are all fairly nasty problems. Note, if we can't get the
+ * descriptor we run anyway, just more slowly.
+ */
+ if (!ISSET(FTS_NOCHDIR)
+ && (sp->fts_rfd = open(".", O_RDONLY, 0)) < 0)
+ SET(FTS_NOCHDIR);
+
+ return (sp);
+
+mem3: fts_lfree(root);
+ free(parent);
+mem2: free(sp->fts_path);
+mem1: free(sp);
+ return (NULL);
+}
+
+static void
+internal_function
+fts_load(FTS *sp, register FTSENT *p)
+{
+ register int len;
+ register char *cp;
+
+ /*
+ * Load the stream structure for the next traversal. Since we don't
+ * actually enter the directory until after the preorder visit, set
+ * the fts_accpath field specially so the chdir gets done to the right
+ * place and the user can access the first node. From fts_open it's
+ * known that the path will fit.
+ */
+ len = p->fts_pathlen = p->fts_namelen;
+ memmove(sp->fts_path, p->fts_name, len + 1);
+ if ((cp = strrchr(p->fts_name, '/')) && (cp != p->fts_name || cp[1])) {
+ len = strlen(++cp);
+ memmove(p->fts_name, cp, len + 1);
+ p->fts_namelen = len;
+ }
+ p->fts_accpath = p->fts_path = sp->fts_path;
+ sp->fts_dev = p->fts_dev;
+}
+
+int
+fts_close(FTS *sp)
+{
+ register FTSENT *freep, *p;
+ int saved_errno;
+
+ /*
+ * This still works if we haven't read anything -- the dummy structure
+ * points to the root list, so we step through to the end of the root
+ * list which has a valid parent pointer.
+ */
+ if (sp->fts_cur) {
+ for (p = sp->fts_cur; p->fts_level >= FTS_ROOTLEVEL;) {
+ freep = p;
+ p = p->fts_link != NULL ? p->fts_link : p->fts_parent;
+ free(freep);
+ }
+ free(p);
+ }
+
+ /* Free up child linked list, sort array, path buffer. */
+ if (sp->fts_child)
+ fts_lfree(sp->fts_child);
+ free(sp->fts_array);
+ free(sp->fts_path);
+
+ /* Return to original directory, save errno if necessary. */
+ if (!ISSET(FTS_NOCHDIR)) {
+ saved_errno = fchdir(sp->fts_rfd) ? errno : 0;
+ (void)close(sp->fts_rfd);
+
+ /* Set errno and return. */
+ if (saved_errno != 0) {
+ /* Free up the stream pointer. */
+ free(sp);
+ __set_errno (saved_errno);
+ return (-1);
+ }
+ }
+
+ /* Free up the stream pointer. */
+ free(sp);
+ return (0);
+}
+
+/*
+ * Special case of "/" at the end of the path so that slashes aren't
+ * appended which would cause paths to be written as "....//foo".
+ */
+#define NAPPEND(p) \
+ (p->fts_path[p->fts_pathlen - 1] == '/' \
+ ? p->fts_pathlen - 1 : p->fts_pathlen)
+
+FTSENT *
+fts_read(register FTS *sp)
+{
+ register FTSENT *p, *tmp;
+ register int instr;
+ register char *t;
+ int saved_errno;
+
+ /* If finished or unrecoverable error, return NULL. */
+ if (sp->fts_cur == NULL || ISSET(FTS_STOP))
+ return (NULL);
+
+ /* Set current node pointer. */
+ p = sp->fts_cur;
+
+ /* Save and zero out user instructions. */
+ instr = p->fts_instr;
+ p->fts_instr = FTS_NOINSTR;
+
+ /* Any type of file may be re-visited; re-stat and re-turn. */
+ if (instr == FTS_AGAIN) {
+ p->fts_info = fts_stat(sp, p, 0);
+ return (p);
+ }
+
+ /*
+ * Following a symlink -- SLNONE test allows application to see
+ * SLNONE and recover. If indirecting through a symlink, have
+ * keep a pointer to current location. If unable to get that
+ * pointer, follow fails.
+ */
+ if (instr == FTS_FOLLOW &&
+ (p->fts_info == FTS_SL || p->fts_info == FTS_SLNONE)) {
+ p->fts_info = fts_stat(sp, p, 1);
+ if (p->fts_info == FTS_D && !ISSET(FTS_NOCHDIR)) {
+ if ((p->fts_symfd = open(".", O_RDONLY, 0)) < 0) {
+ p->fts_errno = errno;
+ p->fts_info = FTS_ERR;
+ } else
+ p->fts_flags |= FTS_SYMFOLLOW;
+ }
+ return (p);
+ }
+
+ /* Directory in pre-order. */
+ if (p->fts_info == FTS_D) {
+ /* If skipped or crossed mount point, do post-order visit. */
+ if (instr == FTS_SKIP ||
+ (ISSET(FTS_XDEV) && p->fts_dev != sp->fts_dev)) {
+ if (p->fts_flags & FTS_SYMFOLLOW)
+ (void)close(p->fts_symfd);
+ if (sp->fts_child) {
+ fts_lfree(sp->fts_child);
+ sp->fts_child = NULL;
+ }
+ p->fts_info = FTS_DP;
+ return (p);
+ }
+
+ /* Rebuild if only read the names and now traversing. */
+ if (sp->fts_child != NULL && ISSET(FTS_NAMEONLY)) {
+ CLR(FTS_NAMEONLY);
+ fts_lfree(sp->fts_child);
+ sp->fts_child = NULL;
+ }
+
+ /*
+ * Cd to the subdirectory.
+ *
+ * If have already read and now fail to chdir, whack the list
+ * to make the names come out right, and set the parent errno
+ * so the application will eventually get an error condition.
+ * Set the FTS_DONTCHDIR flag so that when we logically change
+ * directories back to the parent we don't do a chdir.
+ *
+ * If haven't read do so. If the read fails, fts_build sets
+ * FTS_STOP or the fts_info field of the node.
+ */
+ if (sp->fts_child != NULL) {
+ if (fts_safe_changedir(sp, p, -1, p->fts_accpath)) {
+ p->fts_errno = errno;
+ p->fts_flags |= FTS_DONTCHDIR;
+ for (p = sp->fts_child; p != NULL;
+ p = p->fts_link)
+ p->fts_accpath =
+ p->fts_parent->fts_accpath;
+ }
+ } else if ((sp->fts_child = fts_build(sp, BREAD)) == NULL) {
+ if (ISSET(FTS_STOP))
+ return (NULL);
+ return (p);
+ }
+ p = sp->fts_child;
+ sp->fts_child = NULL;
+ sp->fts_cur = p;
+ goto name;
+ }
+
+ /* Move to the next node on this level. */
+next: tmp = p;
+ if ((p = p->fts_link) != NULL) {
+ sp->fts_cur = p;
+ free(tmp);
+
+ /*
+ * If reached the top, return to the original directory (or
+ * the root of the tree), and load the paths for the next root.
+ */
+ if (p->fts_level == FTS_ROOTLEVEL) {
+ if (FCHDIR(sp, sp->fts_rfd)) {
+ SET(FTS_STOP);
+ return (NULL);
+ }
+ fts_load(sp, p);
+ return p;
+ }
+
+ /*
+ * User may have called fts_set on the node. If skipped,
+ * ignore. If followed, get a file descriptor so we can
+ * get back if necessary.
+ */
+ if (p->fts_instr == FTS_SKIP)
+ goto next;
+ if (p->fts_instr == FTS_FOLLOW) {
+ p->fts_info = fts_stat(sp, p, 1);
+ if (p->fts_info == FTS_D && !ISSET(FTS_NOCHDIR)) {
+ if ((p->fts_symfd =
+ open(".", O_RDONLY, 0)) < 0) {
+ p->fts_errno = errno;
+ p->fts_info = FTS_ERR;
+ } else
+ p->fts_flags |= FTS_SYMFOLLOW;
+ }
+ p->fts_instr = FTS_NOINSTR;
+ }
+
+name: t = sp->fts_path + NAPPEND(p->fts_parent);
+ *t++ = '/';
+ memmove(t, p->fts_name, p->fts_namelen + 1);
+ return p;
+ }
+
+ /* Move up to the parent node. */
+ p = tmp->fts_parent;
+ sp->fts_cur = p;
+ free(tmp);
+
+ if (p->fts_level == FTS_ROOTPARENTLEVEL) {
+ /*
+ * Done; free everything up and set errno to 0 so the user
+ * can distinguish between error and EOF.
+ */
+ free(p);
+ __set_errno (0);
+ return (sp->fts_cur = NULL);
+ }
+
+ /* NUL terminate the pathname. */
+ sp->fts_path[p->fts_pathlen] = '\0';
+
+ /*
+ * Return to the parent directory. If at a root node or came through
+ * a symlink, go back through the file descriptor. Otherwise, cd up
+ * one directory.
+ */
+ if (p->fts_level == FTS_ROOTLEVEL) {
+ if (FCHDIR(sp, sp->fts_rfd)) {
+ SET(FTS_STOP);
+ return (NULL);
+ }
+ } else if (p->fts_flags & FTS_SYMFOLLOW) {
+ if (FCHDIR(sp, p->fts_symfd)) {
+ saved_errno = errno;
+ (void)close(p->fts_symfd);
+ __set_errno (saved_errno);
+ SET(FTS_STOP);
+ return (NULL);
+ }
+ (void)close(p->fts_symfd);
+ } else if (!(p->fts_flags & FTS_DONTCHDIR) &&
+ fts_safe_changedir(sp, p->fts_parent, -1, "..")) {
+ SET(FTS_STOP);
+ return (NULL);
+ }
+ p->fts_info = p->fts_errno ? FTS_ERR : FTS_DP;
+ return p;
+}
+
+/*
+ * Fts_set takes the stream as an argument although it's not used in this
+ * implementation; it would be necessary if anyone wanted to add global
+ * semantics to fts using fts_set. An error return is allowed for similar
+ * reasons.
+ */
+/* ARGSUSED */
+int
+fts_set(FTS *sp, FTSENT *p, int instr)
+{
+ if (instr != 0 && instr != FTS_AGAIN && instr != FTS_FOLLOW &&
+ instr != FTS_NOINSTR && instr != FTS_SKIP) {
+ __set_errno (EINVAL);
+ return (1);
+ }
+ p->fts_instr = instr;
+ return (0);
+}
+
+FTSENT *
+fts_children(register FTS *sp, int instr)
+{
+ register FTSENT *p;
+ int fd;
+
+ if (instr != 0 && instr != FTS_NAMEONLY) {
+ __set_errno (EINVAL);
+ return (NULL);
+ }
+
+ /* Set current node pointer. */
+ p = sp->fts_cur;
+
+ /*
+ * Errno set to 0 so user can distinguish empty directory from
+ * an error.
+ */
+ __set_errno (0);
+
+ /* Fatal errors stop here. */
+ if (ISSET(FTS_STOP))
+ return (NULL);
+
+ /* Return logical hierarchy of user's arguments. */
+ if (p->fts_info == FTS_INIT)
+ return (p->fts_link);
+
+ /*
+ * If not a directory being visited in pre-order, stop here. Could
+ * allow FTS_DNR, assuming the user has fixed the problem, but the
+ * same effect is available with FTS_AGAIN.
+ */
+ if (p->fts_info != FTS_D /* && p->fts_info != FTS_DNR */)
+ return (NULL);
+
+ /* Free up any previous child list. */
+ if (sp->fts_child != NULL)
+ fts_lfree(sp->fts_child);
+
+ if (instr == FTS_NAMEONLY) {
+ SET(FTS_NAMEONLY);
+ instr = BNAMES;
+ } else
+ instr = BCHILD;
+
+ /*
+ * If using chdir on a relative path and called BEFORE fts_read does
+ * its chdir to the root of a traversal, we can lose -- we need to
+ * chdir into the subdirectory, and we don't know where the current
+ * directory is, so we can't get back so that the upcoming chdir by
+ * fts_read will work.
+ */
+ if (p->fts_level != FTS_ROOTLEVEL || p->fts_accpath[0] == '/' ||
+ ISSET(FTS_NOCHDIR))
+ return (sp->fts_child = fts_build(sp, instr));
+
+ if ((fd = open(".", O_RDONLY, 0)) < 0)
+ return (NULL);
+ sp->fts_child = fts_build(sp, instr);
+ if (fchdir(fd))
+ return (NULL);
+ (void)close(fd);
+ return (sp->fts_child);
+}
+
+/*
+ * This is the tricky part -- do not casually change *anything* in here. The
+ * idea is to build the linked list of entries that are used by fts_children
+ * and fts_read. There are lots of special cases.
+ *
+ * The real slowdown in walking the tree is the stat calls. If FTS_NOSTAT is
+ * set and it's a physical walk (so that symbolic links can't be directories),
+ * we can do things quickly. First, if it's a 4.4BSD file system, the type
+ * of the file is in the directory entry. Otherwise, we assume that the number
+ * of subdirectories in a node is equal to the number of links to the parent.
+ * The former skips all stat calls. The latter skips stat calls in any leaf
+ * directories and for any files after the subdirectories in the directory have
+ * been found, cutting the stat calls by about 2/3.
+ */
+static FTSENT *
+internal_function
+fts_build(register FTS *sp, int type)
+{
+ register struct dirent *dp;
+ register FTSENT *p, *head;
+ register int nitems;
+ FTSENT *cur, *tail;
+ DIR *dirp;
+ void *oldaddr;
+ int cderrno, descend, len, level, nlinks, saved_errno,
+ nostat, doadjust;
+ size_t maxlen;
+ char *cp;
+
+ /* Set current node pointer. */
+ cur = sp->fts_cur;
+
+ /*
+ * Open the directory for reading. If this fails, we're done.
+ * If being called from fts_read, set the fts_info field.
+ */
+#if defined FTS_WHITEOUT && 0
+ if (ISSET(FTS_WHITEOUT))
+ oflag = DTF_NODUP|DTF_REWIND;
+ else
+ oflag = DTF_HIDEW|DTF_NODUP|DTF_REWIND;
+#else
+# define opendir2(path, flag) opendir(path)
+#endif
+ if ((dirp = opendir2(cur->fts_accpath, oflag)) == NULL) {
+ if (type == BREAD) {
+ cur->fts_info = FTS_DNR;
+ cur->fts_errno = errno;
+ }
+ return (NULL);
+ }
+
+ /*
+ * Nlinks is the number of possible entries of type directory in the
+ * directory if we're cheating on stat calls, 0 if we're not doing
+ * any stat calls at all, -1 if we're doing stats on everything.
+ */
+ if (type == BNAMES) {
+ nlinks = 0;
+ /* Be quiet about nostat, GCC. */
+ nostat = 0;
+ } else if (ISSET(FTS_NOSTAT) && ISSET(FTS_PHYSICAL)) {
+ nlinks = cur->fts_nlink - (ISSET(FTS_SEEDOT) ? 0 : 2);
+ nostat = 1;
+ } else {
+ nlinks = -1;
+ nostat = 0;
+ }
+
+#ifdef notdef
+ (void)printf("nlinks == %d (cur: %d)\n", nlinks, cur->fts_nlink);
+ (void)printf("NOSTAT %d PHYSICAL %d SEEDOT %d\n",
+ ISSET(FTS_NOSTAT), ISSET(FTS_PHYSICAL), ISSET(FTS_SEEDOT));
+#endif
+ /*
+ * If we're going to need to stat anything or we want to descend
+ * and stay in the directory, chdir. If this fails we keep going,
+ * but set a flag so we don't chdir after the post-order visit.
+ * We won't be able to stat anything, but we can still return the
+ * names themselves. Note, that since fts_read won't be able to
+ * chdir into the directory, it will have to return different path
+ * names than before, i.e. "a/b" instead of "b". Since the node
+ * has already been visited in pre-order, have to wait until the
+ * post-order visit to return the error. There is a special case
+ * here, if there was nothing to stat then it's not an error to
+ * not be able to stat. This is all fairly nasty. If a program
+ * needed sorted entries or stat information, they had better be
+ * checking FTS_NS on the returned nodes.
+ */
+ cderrno = 0;
+ if (nlinks || type == BREAD) {
+ if (fts_safe_changedir(sp, cur, dirfd(dirp), NULL)) {
+ if (nlinks && type == BREAD)
+ cur->fts_errno = errno;
+ cur->fts_flags |= FTS_DONTCHDIR;
+ descend = 0;
+ cderrno = errno;
+ (void)closedir(dirp);
+ dirp = NULL;
+ } else
+ descend = 1;
+ } else
+ descend = 0;
+
+ /*
+ * Figure out the max file name length that can be stored in the
+ * current path -- the inner loop allocates more path as necessary.
+ * We really wouldn't have to do the maxlen calculations here, we
+ * could do them in fts_read before returning the path, but it's a
+ * lot easier here since the length is part of the dirent structure.
+ *
+ * If not changing directories set a pointer so that can just append
+ * each new name into the path.
+ */
+ len = NAPPEND(cur);
+ if (ISSET(FTS_NOCHDIR)) {
+ cp = sp->fts_path + len;
+ *cp++ = '/';
+ } else {
+ /* GCC, you're too verbose. */
+ cp = NULL;
+ }
+ len++;
+ maxlen = sp->fts_pathlen - len;
+
+ level = cur->fts_level + 1;
+
+ /* Read the directory, attaching each entry to the `link' pointer. */
+ doadjust = 0;
+ for (head = tail = NULL, nitems = 0; dirp && (dp = readdir(dirp));) {
+ if (!ISSET(FTS_SEEDOT) && ISDOT(dp->d_name))
+ continue;
+
+ if ((p = fts_alloc(sp, dp->d_name, _D_EXACT_NAMLEN (dp))) == NULL)
+ goto mem1;
+ if (_D_EXACT_NAMLEN (dp) >= maxlen) {/* include space for NUL */
+ oldaddr = sp->fts_path;
+ if (fts_palloc(sp, _D_EXACT_NAMLEN (dp) + len + 1)) {
+ /*
+ * No more memory for path or structures. Save
+ * errno, free up the current structure and the
+ * structures already allocated.
+ */
+mem1: saved_errno = errno;
+ free(p);
+ fts_lfree(head);
+ (void)closedir(dirp);
+ cur->fts_info = FTS_ERR;
+ SET(FTS_STOP);
+ __set_errno (saved_errno);
+ return (NULL);
+ }
+ /* Did realloc() change the pointer? */
+ if (oldaddr != sp->fts_path) {
+ doadjust = 1;
+ if (ISSET(FTS_NOCHDIR))
+ cp = sp->fts_path + len;
+ }
+ maxlen = sp->fts_pathlen - len;
+ }
+
+ if (len + _D_EXACT_NAMLEN (dp) >= USHRT_MAX) {
+ /*
+ * In an FTSENT, fts_pathlen is a u_short so it is
+ * possible to wraparound here. If we do, free up
+ * the current structure and the structures already
+ * allocated, then error out with ENAMETOOLONG.
+ */
+ free(p);
+ fts_lfree(head);
+ (void)closedir(dirp);
+ cur->fts_info = FTS_ERR;
+ SET(FTS_STOP);
+ __set_errno (ENAMETOOLONG);
+ return (NULL);
+ }
+ p->fts_level = level;
+ p->fts_parent = sp->fts_cur;
+ p->fts_pathlen = len + _D_EXACT_NAMLEN (dp);
+
+#if defined FTS_WHITEOUT && 0
+ if (dp->d_type == DT_WHT)
+ p->fts_flags |= FTS_ISW;
+#endif
+
+#if 0
+ /* Unreachable code. cderrno is only ever set to a nonnull
+ value if dirp is closed at the same time. But then we
+ cannot enter this loop. */
+ if (cderrno) {
+ if (nlinks) {
+ p->fts_info = FTS_NS;
+ p->fts_errno = cderrno;
+ } else
+ p->fts_info = FTS_NSOK;
+ p->fts_accpath = cur->fts_accpath;
+ } else
+#endif
+ if (nlinks == 0
+#if defined DT_DIR && defined _DIRENT_HAVE_D_TYPE
+ || (nostat &&
+ dp->d_type != DT_DIR && dp->d_type != DT_UNKNOWN)
+#endif
+ ) {
+ p->fts_accpath =
+ ISSET(FTS_NOCHDIR) ? p->fts_path : p->fts_name;
+ p->fts_info = FTS_NSOK;
+ } else {
+ /* Build a file name for fts_stat to stat. */
+ if (ISSET(FTS_NOCHDIR)) {
+ p->fts_accpath = p->fts_path;
+ memmove(cp, p->fts_name, p->fts_namelen + 1);
+ } else
+ p->fts_accpath = p->fts_name;
+ /* Stat it. */
+ p->fts_info = fts_stat(sp, p, 0);
+
+ /* Decrement link count if applicable. */
+ if (nlinks > 0 && (p->fts_info == FTS_D ||
+ p->fts_info == FTS_DC || p->fts_info == FTS_DOT))
+ --nlinks;
+ }
+
+ /* We walk in directory order so "ls -f" doesn't get upset. */
+ p->fts_link = NULL;
+ if (head == NULL)
+ head = tail = p;
+ else {
+ tail->fts_link = p;
+ tail = p;
+ }
+ ++nitems;
+ }
+ if (dirp)
+ (void)closedir(dirp);
+
+ /*
+ * If realloc() changed the address of the path, adjust the
+ * addresses for the rest of the tree and the dir list.
+ */
+ if (doadjust)
+ fts_padjust(sp, head);
+
+ /*
+ * If not changing directories, reset the path back to original
+ * state.
+ */
+ if (ISSET(FTS_NOCHDIR)) {
+ if (len == sp->fts_pathlen || nitems == 0)
+ --cp;
+ *cp = '\0';
+ }
+
+ /*
+ * If descended after called from fts_children or after called from
+ * fts_read and nothing found, get back. At the root level we use
+ * the saved fd; if one of fts_open()'s arguments is a relative path
+ * to an empty directory, we wind up here with no other way back. If
+ * can't get back, we're done.
+ */
+ if (descend && (type == BCHILD || !nitems) &&
+ (cur->fts_level == FTS_ROOTLEVEL ?
+ FCHDIR(sp, sp->fts_rfd) :
+ fts_safe_changedir(sp, cur->fts_parent, -1, ".."))) {
+ cur->fts_info = FTS_ERR;
+ SET(FTS_STOP);
+ fts_lfree(head);
+ return (NULL);
+ }
+
+ /* If didn't find anything, return NULL. */
+ if (!nitems) {
+ if (type == BREAD)
+ cur->fts_info = FTS_DP;
+ fts_lfree(head);
+ return (NULL);
+ }
+
+ /* Sort the entries. */
+ if (sp->fts_compar && nitems > 1)
+ head = fts_sort(sp, head, nitems);
+ return (head);
+}
+
+static u_short
+internal_function
+fts_stat(FTS *sp, register FTSENT *p, int follow)
+{
+ register FTSENT *t;
+ register dev_t dev;
+ register ino_t ino;
+ struct stat *sbp, sb;
+ int saved_errno;
+
+ /* If user needs stat info, stat buffer already allocated. */
+ sbp = ISSET(FTS_NOSTAT) ? &sb : p->fts_statp;
+
+#if defined FTS_WHITEOUT && 0
+ /* check for whiteout */
+ if (p->fts_flags & FTS_ISW) {
+ if (sbp != &sb) {
+ memset(sbp, '\0', sizeof (*sbp));
+ sbp->st_mode = S_IFWHT;
+ }
+ return (FTS_W);
+ }
+#endif
+
+ /*
+ * If doing a logical walk, or application requested FTS_FOLLOW, do
+ * a stat(2). If that fails, check for a non-existent symlink. If
+ * fail, set the errno from the stat call.
+ */
+ if (ISSET(FTS_LOGICAL) || follow) {
+ if (stat(p->fts_accpath, sbp)) {
+ saved_errno = errno;
+ if (!lstat(p->fts_accpath, sbp)) {
+ __set_errno (0);
+ return (FTS_SLNONE);
+ }
+ p->fts_errno = saved_errno;
+ goto err;
+ }
+ } else if (lstat(p->fts_accpath, sbp)) {
+ p->fts_errno = errno;
+err: memset(sbp, 0, sizeof(struct stat));
+ return (FTS_NS);
+ }
+
+ if (S_ISDIR(sbp->st_mode)) {
+ /*
+ * Set the device/inode. Used to find cycles and check for
+ * crossing mount points. Also remember the link count, used
+ * in fts_build to limit the number of stat calls. It is
+ * understood that these fields are only referenced if fts_info
+ * is set to FTS_D.
+ */
+ dev = p->fts_dev = sbp->st_dev;
+ ino = p->fts_ino = sbp->st_ino;
+ p->fts_nlink = sbp->st_nlink;
+
+ if (ISDOT(p->fts_name))
+ return (FTS_DOT);
+
+ /*
+ * Cycle detection is done by brute force when the directory
+ * is first encountered. If the tree gets deep enough or the
+ * number of symbolic links to directories is high enough,
+ * something faster might be worthwhile.
+ */
+ for (t = p->fts_parent;
+ t->fts_level >= FTS_ROOTLEVEL; t = t->fts_parent)
+ if (ino == t->fts_ino && dev == t->fts_dev) {
+ p->fts_cycle = t;
+ return (FTS_DC);
+ }
+ return (FTS_D);
+ }
+ if (S_ISLNK(sbp->st_mode))
+ return (FTS_SL);
+ if (S_ISREG(sbp->st_mode))
+ return (FTS_F);
+ return (FTS_DEFAULT);
+}
+
+static FTSENT *
+internal_function
+fts_sort(FTS *sp, FTSENT *head, register int nitems)
+{
+ register FTSENT **ap, *p;
+
+ /*
+ * Construct an array of pointers to the structures and call qsort(3).
+ * Reassemble the array in the order returned by qsort. If unable to
+ * sort for memory reasons, return the directory entries in their
+ * current order. Allocate enough space for the current needs plus
+ * 40 so don't realloc one entry at a time.
+ */
+ if (nitems > sp->fts_nitems) {
+ struct _ftsent **a;
+
+ sp->fts_nitems = nitems + 40;
+ if ((a = realloc(sp->fts_array,
+ (size_t)(sp->fts_nitems * sizeof(FTSENT *)))) == NULL) {
+ free(sp->fts_array);
+ sp->fts_array = NULL;
+ sp->fts_nitems = 0;
+ return (head);
+ }
+ sp->fts_array = a;
+ }
+ for (ap = sp->fts_array, p = head; p; p = p->fts_link)
+ *ap++ = p;
+ qsort((void *)sp->fts_array, nitems, sizeof(FTSENT *), sp->fts_compar);
+ for (head = *(ap = sp->fts_array); --nitems; ++ap)
+ ap[0]->fts_link = ap[1];
+ ap[0]->fts_link = NULL;
+ return (head);
+}
+
+static FTSENT *
+internal_function
+fts_alloc(FTS *sp, const char *name, size_t namelen)
+{
+ register FTSENT *p;
+ size_t len;
+
+ /*
+ * The file name is a variable length array and no stat structure is
+ * necessary if the user has set the nostat bit. Allocate the FTSENT
+ * structure, the file name and the stat structure in one chunk, but
+ * be careful that the stat structure is reasonably aligned. Since the
+ * fts_name field is declared to be of size 1, the fts_name pointer is
+ * namelen + 2 before the first possible address of the stat structure.
+ */
+ len = sizeof(FTSENT) + namelen;
+ if (!ISSET(FTS_NOSTAT))
+ len += sizeof(struct stat) + ALIGNBYTES;
+ if ((p = malloc(len)) == NULL)
+ return (NULL);
+
+ /* Copy the name and guarantee NUL termination. */
+ memmove(p->fts_name, name, namelen);
+ p->fts_name[namelen] = '\0';
+
+ if (!ISSET(FTS_NOSTAT))
+ p->fts_statp = (struct stat *)ALIGN(p->fts_name + namelen + 2);
+ p->fts_namelen = namelen;
+ p->fts_path = sp->fts_path;
+ p->fts_errno = 0;
+ p->fts_flags = 0;
+ p->fts_instr = FTS_NOINSTR;
+ p->fts_number = 0;
+ p->fts_pointer = NULL;
+ return (p);
+}
+
+static void
+internal_function
+fts_lfree(register FTSENT *head)
+{
+ register FTSENT *p;
+
+ /* Free a linked list of structures. */
+ while ((p = head)) {
+ head = head->fts_link;
+ free(p);
+ }
+}
+
+/*
+ * Allow essentially unlimited paths; find, rm, ls should all work on any tree.
+ * Most systems will allow creation of paths much longer than MAXPATHLEN, even
+ * though the kernel won't resolve them. Add the size (not just what's needed)
+ * plus 256 bytes so don't realloc the path 2 bytes at a time.
+ */
+static int
+internal_function
+fts_palloc(FTS *sp, size_t more)
+{
+ char *p;
+
+ sp->fts_pathlen += more + 256;
+ /*
+ * Check for possible wraparound. In an FTS, fts_pathlen is
+ * a signed int but in an FTSENT it is an unsigned short.
+ * We limit fts_pathlen to USHRT_MAX to be safe in both cases.
+ */
+ if (sp->fts_pathlen < 0 || sp->fts_pathlen >= USHRT_MAX) {
+ free(sp->fts_path);
+ sp->fts_path = NULL;
+ __set_errno (ENAMETOOLONG);
+ return (1);
+ }
+ p = realloc(sp->fts_path, sp->fts_pathlen);
+ if (p == NULL) {
+ free(sp->fts_path);
+ sp->fts_path = NULL;
+ return 1;
+ }
+ sp->fts_path = p;
+ return 0;
+}
+
+/*
+ * When the path is realloc'd, have to fix all of the pointers in structures
+ * already returned.
+ */
+static void
+internal_function
+fts_padjust(FTS *sp, FTSENT *head)
+{
+ FTSENT *p;
+ char *addr = sp->fts_path;
+
+#define ADJUST(p) do { \
+ if ((p)->fts_accpath != (p)->fts_name) { \
+ (p)->fts_accpath = \
+ (char *)addr + ((p)->fts_accpath - (p)->fts_path); \
+ } \
+ (p)->fts_path = addr; \
+} while (0)
+ /* Adjust the current set of children. */
+ for (p = sp->fts_child; p; p = p->fts_link)
+ ADJUST(p);
+
+ /* Adjust the rest of the tree, including the current level. */
+ for (p = head; p->fts_level >= FTS_ROOTLEVEL;) {
+ ADJUST(p);
+ p = p->fts_link ? p->fts_link : p->fts_parent;
+ }
+}
+
+static size_t
+internal_function
+fts_maxarglen(char * const *argv)
+{
+ size_t len, max;
+
+ for (max = 0; *argv; ++argv)
+ if ((len = strlen(*argv)) > max)
+ max = len;
+ return (max + 1);
+}
+
+/*
+ * Change to dir specified by fd or p->fts_accpath without getting
+ * tricked by someone changing the world out from underneath us.
+ * Assumes p->fts_dev and p->fts_ino are filled in.
+ */
+static int
+internal_function
+fts_safe_changedir(FTS *sp, FTSENT *p, int fd, const char *path)
+{
+ int ret, oerrno, newfd;
+ struct stat64 sb;
+
+ newfd = fd;
+ if (ISSET(FTS_NOCHDIR))
+ return (0);
+ if (fd < 0 && (newfd = open(path, O_RDONLY, 0)) < 0)
+ return (-1);
+ if (fstat64(newfd, &sb)) {
+ ret = -1;
+ goto bail;
+ }
+ if (p->fts_dev != sb.st_dev || p->fts_ino != sb.st_ino) {
+ __set_errno (ENOENT); /* disinformation */
+ ret = -1;
+ goto bail;
+ }
+ ret = fchdir(newfd);
+bail:
+ oerrno = errno;
+ if (fd < 0)
+ (void)close(newfd);
+ __set_errno (oerrno);
+ return (ret);
+}
diff --git a/ap/build/uClibc/libc/misc/ftw/Makefile b/ap/build/uClibc/libc/misc/ftw/Makefile
new file mode 100644
index 0000000..4a8f4a0
--- /dev/null
+++ b/ap/build/uClibc/libc/misc/ftw/Makefile
@@ -0,0 +1,13 @@
+# Makefile for uClibc
+#
+# Copyright (C) 2000-2005 Erik Andersen <andersen@uclibc.org>
+#
+# Licensed under the LGPL v2.1, see the file COPYING.LIB in this tarball.
+#
+
+top_srcdir=../../../
+top_builddir=../../../
+all: objs
+include $(top_builddir)Rules.mak
+include Makefile.in
+include $(top_srcdir)Makerules
diff --git a/ap/build/uClibc/libc/misc/ftw/Makefile.in b/ap/build/uClibc/libc/misc/ftw/Makefile.in
new file mode 100644
index 0000000..2edd819
--- /dev/null
+++ b/ap/build/uClibc/libc/misc/ftw/Makefile.in
@@ -0,0 +1,26 @@
+# Makefile for uClibc
+#
+# Copyright (C) 2000-2008 Erik Andersen <andersen@uclibc.org>
+#
+# Licensed under the LGPL v2.1, see the file COPYING.LIB in this tarball.
+#
+
+subdirs += libc/misc/ftw
+
+CSRC := ftw.c
+ifeq ($(UCLIBC_HAS_LFS),y)
+CSRC += ftw64.c
+endif
+
+MISC_FTW_DIR := $(top_srcdir)libc/misc/ftw
+MISC_FTW_OUT := $(top_builddir)libc/misc/ftw
+
+MISC_FTW_SRC := $(patsubst %.c,$(MISC_FTW_DIR)/%.c,$(CSRC))
+MISC_FTW_OBJ := $(patsubst %.c,$(MISC_FTW_OUT)/%.o,$(CSRC))
+
+libc-$(findstring y,$(UCLIBC_HAS_FTW)$(UCLIBC_HAS_NFTW)) += $(MISC_FTW_OBJ)
+
+objclean-y += CLEAN_libc/misc/ftw
+
+CLEAN_libc/misc/ftw:
+ $(do_rm) $(addprefix $(MISC_FTW_OUT)/*., o os)
diff --git a/ap/build/uClibc/libc/misc/ftw/ftw.c b/ap/build/uClibc/libc/misc/ftw/ftw.c
new file mode 100644
index 0000000..9031e35
--- /dev/null
+++ b/ap/build/uClibc/libc/misc/ftw/ftw.c
@@ -0,0 +1,807 @@
+/* File tree walker functions.
+ Copyright (C) 1996-2003, 2004 Free Software Foundation, Inc.
+ This file is part of the GNU C Library.
+ Contributed by Ulrich Drepper <drepper@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.
+
+ 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 HAVE_CONFIG_H
+# include <config.h>
+#endif
+
+#include <features.h>
+#ifdef __UCLIBC__
+#undef _LIBC
+#define HAVE_DIRENT_H 1
+#define HAVE_SYS_PARAM_H 1
+#define HAVE_DECL_STPCPY 1
+#define HAVE_MEMPCPY 1
+#endif
+
+#if __GNUC__
+# define alloca __builtin_alloca
+#else
+# if HAVE_ALLOCA_H
+# include <alloca.h>
+# else
+# ifdef _AIX
+ # pragma alloca
+# else
+char *alloca ();
+# endif
+# endif
+#endif
+
+#if defined _LIBC
+# include <dirent.h>
+# define NAMLEN(dirent) _D_EXACT_NAMLEN (dirent)
+#else
+# if HAVE_DIRENT_H
+# include <dirent.h>
+# define NAMLEN(dirent) strlen ((dirent)->d_name)
+# else
+# define dirent direct
+# define NAMLEN(dirent) (dirent)->d_namlen
+# if HAVE_SYS_NDIR_H
+# include <sys/ndir.h>
+# endif
+# if HAVE_SYS_DIR_H
+# include <sys/dir.h>
+# endif
+# if HAVE_NDIR_H
+# include <ndir.h>
+# endif
+# endif
+#endif
+
+#include <errno.h>
+#include <ftw.h>
+#include <limits.h>
+#include <search.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+#if HAVE_SYS_PARAM_H || defined _LIBC
+# include <sys/param.h>
+#endif
+#ifdef _LIBC
+# include <include/sys/stat.h>
+#else
+# include <sys/stat.h>
+#endif
+
+#if !defined _LIBC && !HAVE_DECL_STPCPY && !defined stpcpy
+char *stpcpy ();
+#endif
+
+#if !defined _LIBC && ! defined HAVE_MEMPCPY && ! defined mempcpy
+/* Be CAREFUL that there are no side effects in N. */
+# define mempcpy(D, S, N) ((void *) ((char *) memcpy (D, S, N) + (N)))
+#endif
+
+/* #define NDEBUG 1 */
+#include <assert.h>
+
+#if !defined _LIBC
+# undef __chdir
+# define __chdir chdir
+# undef __closedir
+# define __closedir closedir
+# undef __fchdir
+# define __fchdir fchdir
+# undef __getcwd
+# ifndef __UCLIBC__
+# define __getcwd(P, N) xgetcwd ()
+extern char *xgetcwd (void);
+# else
+# define __getcwd getcwd
+# endif
+# undef __mempcpy
+# define __mempcpy mempcpy
+# undef __opendir
+# define __opendir opendir
+# undef __readdir64
+# ifndef __UCLIBC_HAS_LFS__
+# define __readdir64 readdir
+# else
+# define __readdir64 readdir64
+# endif
+# undef __stpcpy
+# define __stpcpy stpcpy
+# undef __tdestroy
+# define __tdestroy tdestroy
+# undef __tfind
+# define __tfind tfind
+# undef __tsearch
+# define __tsearch tsearch
+# undef internal_function
+# define internal_function /* empty */
+# ifndef __UCLIBC_HAS_LFS__
+# undef dirent64
+# define dirent64 dirent
+# endif
+# undef MAX
+# define MAX(a, b) ((a) > (b) ? (a) : (b))
+#endif
+
+/* Arrange to make lstat calls go through the wrapper function
+ on systems with an lstat function that does not dereference symlinks
+ that are specified with a trailing slash. */
+#if !defined _LIBC && !defined LSTAT_FOLLOWS_SLASHED_SYMLINK && !defined __UCLIBC__
+int rpl_lstat (const char *, struct stat *);
+# undef lstat
+# define lstat(Name, Stat_buf) rpl_lstat(Name, Stat_buf)
+#endif
+
+#ifndef __set_errno
+# define __set_errno(Val) errno = (Val)
+#endif
+
+/* Support for the LFS API version. */
+#ifndef FTW_NAME
+# define FTW_NAME ftw
+# define NFTW_NAME nftw
+# define NFTW_OLD_NAME __old_nftw
+# define NFTW_NEW_NAME __new_nftw
+# define INO_T ino_t
+# define STAT stat
+# ifdef _LIBC
+# define LXSTAT __lxstat
+# define XSTAT __xstat
+# else
+# define LXSTAT(V,f,sb) lstat (f,sb)
+# define XSTAT(V,f,sb) stat (f,sb)
+# endif
+# define FTW_FUNC_T __ftw_func_t
+# define NFTW_FUNC_T __nftw_func_t
+#endif
+
+/* We define PATH_MAX if the system does not provide a definition.
+ This does not artificially limit any operation. PATH_MAX is simply
+ used as a guesstimate for the expected maximal path length.
+ Buffers will be enlarged if necessary. */
+#ifndef PATH_MAX
+# define PATH_MAX 1024
+#endif
+
+struct dir_data
+{
+ DIR *stream;
+ char *content;
+};
+
+struct known_object
+{
+ dev_t dev;
+ INO_T ino;
+};
+
+struct ftw_data
+{
+ /* Array with pointers to open directory streams. */
+ struct dir_data **dirstreams;
+ size_t actdir;
+ size_t maxdir;
+
+ /* Buffer containing name of currently processed object. */
+ char *dirbuf;
+ size_t dirbufsize;
+
+ /* Passed as fourth argument to `nftw' callback. The `base' member
+ tracks the content of the `dirbuf'. */
+ struct FTW ftw;
+
+ /* Flags passed to `nftw' function. 0 for `ftw'. */
+ int flags;
+
+ /* Conversion array for flag values. It is the identity mapping for
+ `nftw' calls, otherwise it maps the values to those known by
+ `ftw'. */
+ const int *cvt_arr;
+
+ /* Callback function. We always use the `nftw' form. */
+ NFTW_FUNC_T func;
+
+ /* Device of starting point. Needed for FTW_MOUNT. */
+ dev_t dev;
+
+ /* Data structure for keeping fingerprints of already processed
+ object. This is needed when not using FTW_PHYS. */
+ void *known_objects;
+};
+
+
+/* Internally we use the FTW_* constants used for `nftw'. When invoked
+ as `ftw', map each flag to the subset of values used by `ftw'. */
+static const int nftw_arr[] =
+{
+ FTW_F, FTW_D, FTW_DNR, FTW_NS, FTW_SL, FTW_DP, FTW_SLN
+};
+
+static const int ftw_arr[] =
+{
+ FTW_F, FTW_D, FTW_DNR, FTW_NS, FTW_F, FTW_D, FTW_NS
+};
+
+
+/* Forward declarations of local functions. */
+static int ftw_dir (struct ftw_data *data, struct STAT *st,
+ struct dir_data *old_dir) internal_function;
+
+
+static int
+object_compare (const void *p1, const void *p2)
+{
+ /* We don't need a sophisticated and useful comparison. We are only
+ interested in equality. However, we must be careful not to
+ accidentally compare `holes' in the structure. */
+ const struct known_object *kp1 = p1, *kp2 = p2;
+ int cmp1;
+ cmp1 = (kp1->ino > kp2->ino) - (kp1->ino < kp2->ino);
+ if (cmp1 != 0)
+ return cmp1;
+ return (kp1->dev > kp2->dev) - (kp1->dev < kp2->dev);
+}
+
+
+static __inline__ int
+add_object (struct ftw_data *data, struct STAT *st)
+{
+ struct known_object *newp = malloc (sizeof (struct known_object));
+ if (newp == NULL)
+ return -1;
+ newp->dev = st->st_dev;
+ newp->ino = st->st_ino;
+ return __tsearch (newp, &data->known_objects, object_compare) ? 0 : -1;
+}
+
+
+static __inline__ int
+find_object (struct ftw_data *data, struct STAT *st)
+{
+ struct known_object obj;
+ obj.dev = st->st_dev;
+ obj.ino = st->st_ino;
+ return __tfind (&obj, &data->known_objects, object_compare) != NULL;
+}
+
+
+static __inline__ int
+__attribute ((always_inline))
+open_dir_stream (struct ftw_data *data, struct dir_data *dirp)
+{
+ int result = 0;
+
+ if (data->dirstreams[data->actdir] != NULL)
+ {
+ /* Oh, oh. We must close this stream. Get all remaining
+ entries and store them as a list in the `content' member of
+ the `struct dir_data' variable. */
+ size_t bufsize = 1024;
+ char *buf = malloc (bufsize);
+
+ if (buf == NULL)
+ result = -1;
+ else
+ {
+ DIR *st = data->dirstreams[data->actdir]->stream;
+ struct dirent64 *d;
+ size_t actsize = 0;
+
+ while ((d = __readdir64 (st)) != NULL)
+ {
+ size_t this_len = NAMLEN (d);
+ if (actsize + this_len + 2 >= bufsize)
+ {
+ char *newp;
+ bufsize += MAX (1024, 2 * this_len);
+ newp = (char *) realloc (buf, bufsize);
+ if (newp == NULL)
+ {
+ /* No more memory. */
+ int save_err = errno;
+ free (buf);
+ __set_errno (save_err);
+ result = -1;
+ break;
+ }
+ buf = newp;
+ }
+
+ *((char *) __mempcpy (buf + actsize, d->d_name, this_len))
+ = '\0';
+ actsize += this_len + 1;
+ }
+
+ /* Terminate the list with an additional NUL byte. */
+ buf[actsize++] = '\0';
+
+ /* Shrink the buffer to what we actually need. */
+ data->dirstreams[data->actdir]->content = realloc (buf, actsize);
+ if (data->dirstreams[data->actdir]->content == NULL)
+ {
+ int save_err = errno;
+ free (buf);
+ __set_errno (save_err);
+ result = -1;
+ }
+ else
+ {
+ __closedir (st);
+ data->dirstreams[data->actdir]->stream = NULL;
+ data->dirstreams[data->actdir] = NULL;
+ }
+ }
+ }
+
+ /* Open the new stream. */
+ if (result == 0)
+ {
+ const char *name = ((data->flags & FTW_CHDIR)
+ ? data->dirbuf + data->ftw.base: data->dirbuf);
+ assert (data->dirstreams[data->actdir] == NULL);
+
+ dirp->stream = __opendir (name);
+ if (dirp->stream == NULL)
+ result = -1;
+ else
+ {
+ dirp->content = NULL;
+ data->dirstreams[data->actdir] = dirp;
+
+ if (++data->actdir == data->maxdir)
+ data->actdir = 0;
+ }
+ }
+
+ return result;
+}
+
+
+static int
+internal_function
+process_entry (struct ftw_data *data, struct dir_data *dir, const char *name,
+ size_t namlen)
+{
+ struct STAT st;
+ int result = 0;
+ int flag = 0;
+ size_t new_buflen;
+
+ if (name[0] == '.' && (name[1] == '\0'
+ || (name[1] == '.' && name[2] == '\0')))
+ /* Don't process the "." and ".." entries. */
+ return 0;
+
+ new_buflen = data->ftw.base + namlen + 2;
+ if (data->dirbufsize < new_buflen)
+ {
+ /* Enlarge the buffer. */
+ char *newp;
+
+ data->dirbufsize = 2 * new_buflen;
+ newp = (char *) realloc (data->dirbuf, data->dirbufsize);
+ if (newp == NULL)
+ return -1;
+ data->dirbuf = newp;
+ }
+
+ *((char *) __mempcpy (data->dirbuf + data->ftw.base, name, namlen)) = '\0';
+
+ if ((data->flags & FTW_CHDIR) == 0)
+ name = data->dirbuf;
+
+ if (((data->flags & FTW_PHYS)
+ ? LXSTAT (_STAT_VER, name, &st)
+ : XSTAT (_STAT_VER, name, &st)) < 0)
+ {
+ if (errno != EACCES && errno != ENOENT)
+ result = -1;
+ else if (!(data->flags & FTW_PHYS)
+ && LXSTAT (_STAT_VER, name, &st) == 0
+ && S_ISLNK (st.st_mode))
+ flag = FTW_SLN;
+ else
+ flag = FTW_NS;
+ }
+ else
+ {
+ if (S_ISDIR (st.st_mode))
+ flag = FTW_D;
+ else if (S_ISLNK (st.st_mode))
+ flag = FTW_SL;
+ else
+ flag = FTW_F;
+ }
+
+ if (result == 0
+ && (flag == FTW_NS
+ || !(data->flags & FTW_MOUNT) || st.st_dev == data->dev))
+ {
+ if (flag == FTW_D)
+ {
+ if ((data->flags & FTW_PHYS)
+ || (!find_object (data, &st)
+ /* Remember the object. */
+ && (result = add_object (data, &st)) == 0))
+ result = ftw_dir (data, &st, dir);
+ }
+ else
+ result = (*data->func) (data->dirbuf, &st, data->cvt_arr[flag],
+ &data->ftw);
+ }
+
+ if ((data->flags & FTW_ACTIONRETVAL) && result == FTW_SKIP_SUBTREE)
+ result = 0;
+
+ return result;
+}
+
+
+static int
+__attribute ((noinline))
+internal_function
+ftw_dir (struct ftw_data *data, struct STAT *st, struct dir_data *old_dir)
+{
+ struct dir_data dir;
+ struct dirent64 *d;
+ int previous_base = data->ftw.base;
+ int result;
+ char *startp;
+
+ /* Open the stream for this directory. This might require that
+ another stream has to be closed. */
+ result = open_dir_stream (data, &dir);
+ if (result != 0)
+ {
+ if (errno == EACCES)
+ /* We cannot read the directory. Signal this with a special flag. */
+ result = (*data->func) (data->dirbuf, st, FTW_DNR, &data->ftw);
+
+ return result;
+ }
+
+ /* First, report the directory (if not depth-first). */
+ if (!(data->flags & FTW_DEPTH))
+ {
+ result = (*data->func) (data->dirbuf, st, FTW_D, &data->ftw);
+ if (result != 0)
+ {
+ int save_err;
+fail:
+ save_err = errno;
+ __closedir (dir.stream);
+ __set_errno (save_err);
+
+ if (data->actdir-- == 0)
+ data->actdir = data->maxdir - 1;
+ data->dirstreams[data->actdir] = NULL;
+ return result;
+ }
+ }
+
+ /* If necessary, change to this directory. */
+ if (data->flags & FTW_CHDIR)
+ {
+ if (__fchdir (dirfd (dir.stream)) < 0)
+ {
+ result = -1;
+ goto fail;
+ }
+ }
+
+ /* Next, update the `struct FTW' information. */
+ ++data->ftw.level;
+ startp = strchr (data->dirbuf, '\0');
+ /* There always must be a directory name. */
+ assert (startp != data->dirbuf);
+ if (startp[-1] != '/')
+ *startp++ = '/';
+ data->ftw.base = startp - data->dirbuf;
+
+ while (dir.stream != NULL && (d = __readdir64 (dir.stream)) != NULL)
+ {
+ result = process_entry (data, &dir, d->d_name, NAMLEN (d));
+ if (result != 0)
+ break;
+ }
+
+ if (dir.stream != NULL)
+ {
+ /* The stream is still open. I.e., we did not need more
+ descriptors. Simply close the stream now. */
+ int save_err = errno;
+
+ assert (dir.content == NULL);
+
+ __closedir (dir.stream);
+ __set_errno (save_err);
+
+ if (data->actdir-- == 0)
+ data->actdir = data->maxdir - 1;
+ data->dirstreams[data->actdir] = NULL;
+ }
+ else
+ {
+ int save_err;
+ char *runp = dir.content;
+
+ while (result == 0 && *runp != '\0')
+ {
+ char *endp = strchr (runp, '\0');
+
+ result = process_entry (data, &dir, runp, endp - runp);
+
+ runp = endp + 1;
+ }
+
+ save_err = errno;
+ free (dir.content);
+ __set_errno (save_err);
+ }
+
+ if ((data->flags & FTW_ACTIONRETVAL) && result == FTW_SKIP_SIBLINGS)
+ result = 0;
+
+ /* Prepare the return, revert the `struct FTW' information. */
+ data->dirbuf[data->ftw.base - 1] = '\0';
+ --data->ftw.level;
+ data->ftw.base = previous_base;
+
+ /* Finally, if we process depth-first report the directory. */
+ if (result == 0 && (data->flags & FTW_DEPTH))
+ result = (*data->func) (data->dirbuf, st, FTW_DP, &data->ftw);
+
+ if (old_dir
+ && (data->flags & FTW_CHDIR)
+ && (result == 0
+ || ((data->flags & FTW_ACTIONRETVAL)
+ && (result != -1 && result != FTW_STOP))))
+ {
+ /* Change back to the parent directory. */
+ int done = 0;
+ if (old_dir->stream != NULL)
+ if (__fchdir (dirfd (old_dir->stream)) == 0)
+ done = 1;
+
+ if (!done)
+ {
+ if (data->ftw.base == 1)
+ {
+ if (__chdir ("/") < 0)
+ result = -1;
+ }
+ else
+ if (__chdir ("..") < 0)
+ result = -1;
+ }
+ }
+
+ return result;
+}
+
+
+static int
+__attribute ((noinline))
+internal_function
+ftw_startup (const char *dir, int is_nftw, void *func, int descriptors,
+ int flags)
+{
+ struct ftw_data data;
+ struct STAT st;
+ int result = 0;
+ int save_err;
+ char *cwd = NULL;
+ char *cp;
+
+ /* First make sure the parameters are reasonable. */
+ if (dir[0] == '\0')
+ {
+ __set_errno (ENOENT);
+ return -1;
+ }
+
+ data.maxdir = descriptors < 1 ? 1 : descriptors;
+ data.actdir = 0;
+ data.dirstreams = (struct dir_data **) alloca (data.maxdir
+ * sizeof (struct dir_data *));
+ memset (data.dirstreams, '\0', data.maxdir * sizeof (struct dir_data *));
+
+ /* PATH_MAX is always defined when we get here. */
+ data.dirbufsize = MAX (2 * strlen (dir), PATH_MAX);
+ data.dirbuf = (char *) malloc (data.dirbufsize);
+ if (data.dirbuf == NULL)
+ return -1;
+ cp = __stpcpy (data.dirbuf, dir);
+ /* Strip trailing slashes. */
+ while (cp > data.dirbuf + 1 && cp[-1] == '/')
+ --cp;
+ *cp = '\0';
+
+ data.ftw.level = 0;
+
+ /* Find basename. */
+ while (cp > data.dirbuf && cp[-1] != '/')
+ --cp;
+ data.ftw.base = cp - data.dirbuf;
+
+ data.flags = flags;
+
+ /* This assignment might seem to be strange but it is what we want.
+ The trick is that the first three arguments to the `ftw' and
+ `nftw' callback functions are equal. Therefore we can call in
+ every case the callback using the format of the `nftw' version
+ and get the correct result since the stack layout for a function
+ call in C allows this. */
+ data.func = (NFTW_FUNC_T) func;
+
+ /* Since we internally use the complete set of FTW_* values we need
+ to reduce the value range before calling a `ftw' callback. */
+ data.cvt_arr = is_nftw ? nftw_arr : ftw_arr;
+
+ /* No object known so far. */
+ data.known_objects = NULL;
+
+ /* Now go to the directory containing the initial file/directory. */
+ if (flags & FTW_CHDIR)
+ {
+ /* GNU extension ahead. */
+ cwd = __getcwd (NULL, 0);
+ if (cwd == NULL)
+ result = -1;
+ else if (data.ftw.base > 0)
+ {
+ /* Change to the directory the file is in. In data.dirbuf
+ we have a writable copy of the file name. Just NUL
+ terminate it for now and change the directory. */
+ if (data.ftw.base == 1)
+ /* I.e., the file is in the root directory. */
+ result = __chdir ("/");
+ else
+ {
+ char ch = data.dirbuf[data.ftw.base - 1];
+ data.dirbuf[data.ftw.base - 1] = '\0';
+ result = __chdir (data.dirbuf);
+ data.dirbuf[data.ftw.base - 1] = ch;
+ }
+ }
+ }
+
+ /* Get stat info for start directory. */
+ if (result == 0)
+ {
+ const char *name = ((data.flags & FTW_CHDIR)
+ ? data.dirbuf + data.ftw.base
+ : data.dirbuf);
+
+ if (((flags & FTW_PHYS)
+ ? LXSTAT (_STAT_VER, name, &st)
+ : XSTAT (_STAT_VER, name, &st)) < 0)
+ {
+ if (!(flags & FTW_PHYS)
+ && errno == ENOENT
+ && LXSTAT (_STAT_VER, name, &st) == 0
+ && S_ISLNK (st.st_mode))
+ result = (*data.func) (data.dirbuf, &st, data.cvt_arr[FTW_SLN],
+ &data.ftw);
+ else
+ /* No need to call the callback since we cannot say anything
+ about the object. */
+ result = -1;
+ }
+ else
+ {
+ if (S_ISDIR (st.st_mode))
+ {
+ /* Remember the device of the initial directory in case
+ FTW_MOUNT is given. */
+ data.dev = st.st_dev;
+
+ /* We know this directory now. */
+ if (!(flags & FTW_PHYS))
+ result = add_object (&data, &st);
+
+ if (result == 0)
+ result = ftw_dir (&data, &st, NULL);
+ }
+ else
+ {
+ int flag = S_ISLNK (st.st_mode) ? FTW_SL : FTW_F;
+
+ result = (*data.func) (data.dirbuf, &st, data.cvt_arr[flag],
+ &data.ftw);
+ }
+ }
+
+ if ((flags & FTW_ACTIONRETVAL)
+ && (result == FTW_SKIP_SUBTREE || result == FTW_SKIP_SIBLINGS))
+ result = 0;
+ }
+
+ /* Return to the start directory (if necessary). */
+ if (cwd != NULL)
+ {
+ save_err = errno;
+ __chdir (cwd);
+ free (cwd);
+ __set_errno (save_err);
+ }
+
+ /* Free all memory. */
+ save_err = errno;
+ __tdestroy (data.known_objects, free);
+ free (data.dirbuf);
+ __set_errno (save_err);
+
+ return result;
+}
+
+
+
+/* Entry points. */
+#ifdef __UCLIBC_HAS_FTW__
+int
+FTW_NAME (const char *path, FTW_FUNC_T func, int descriptors)
+{
+ return ftw_startup (path, 0, func, descriptors, 0);
+}
+#endif
+
+#ifdef __UCLIBC_HAS_NFTW__
+#ifndef _LIBC
+int
+NFTW_NAME (const char *path, NFTW_FUNC_T func, int descriptors, int flags)
+{
+ return ftw_startup (path, 1, func, descriptors, flags);
+}
+#else
+
+#include <shlib-compat.h>
+
+int NFTW_NEW_NAME (const char *, NFTW_FUNC_T, int, int);
+
+int
+NFTW_NEW_NAME (const char *path, NFTW_FUNC_T func, int descriptors, int flags)
+{
+ if (flags
+ & ~(FTW_PHYS | FTW_MOUNT | FTW_CHDIR | FTW_DEPTH | FTW_ACTIONRETVAL))
+ {
+ __set_errno (EINVAL);
+ return -1;
+ }
+ return ftw_startup (path, 1, func, descriptors, flags);
+}
+
+versioned_symbol (libc, NFTW_NEW_NAME, NFTW_NAME, GLIBC_2_3_3);
+
+#if SHLIB_COMPAT(libc, GLIBC_2_1, GLIBC_2_3_3)
+
+/* Older nftw* version just ignored all unknown flags. */
+
+int NFTW_OLD_NAME (const char *, NFTW_FUNC_T, int, int);
+
+int
+attribute_compat_text_section
+NFTW_OLD_NAME (const char *path, NFTW_FUNC_T func, int descriptors, int flags)
+{
+ flags &= (FTW_PHYS | FTW_MOUNT | FTW_CHDIR | FTW_DEPTH);
+ return ftw_startup (path, 1, func, descriptors, flags);
+}
+
+compat_symbol (libc, NFTW_OLD_NAME, NFTW_NAME, GLIBC_2_1);
+#endif
+#endif
+#endif
diff --git a/ap/build/uClibc/libc/misc/ftw/ftw64.c b/ap/build/uClibc/libc/misc/ftw/ftw64.c
new file mode 100644
index 0000000..de2fe22
--- /dev/null
+++ b/ap/build/uClibc/libc/misc/ftw/ftw64.c
@@ -0,0 +1,32 @@
+/* File tree walker functions. LFS version.
+ Copyright (C) 1996, 1997, 1998, 2001 Free Software Foundation, Inc.
+ This file is part of the GNU C Library.
+ Contributed by Ulrich Drepper <drepper@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.
+
+ 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 FTW_NAME ftw64
+#define NFTW_NAME nftw64
+#define NFTW_OLD_NAME __old_nftw64
+#define NFTW_NEW_NAME __new_nftw64
+#define INO_T ino64_t
+#define STAT stat64
+#define LXSTAT(V,f,sb) lstat64(f,sb)
+#define XSTAT(V,f,sb) stat64(f,sb)
+#define FTW_FUNC_T __ftw64_func_t
+#define NFTW_FUNC_T __nftw64_func_t
+
+#include "ftw.c"
diff --git a/ap/build/uClibc/libc/misc/glob/.indent.pro b/ap/build/uClibc/libc/misc/glob/.indent.pro
new file mode 100644
index 0000000..492ecf1
--- /dev/null
+++ b/ap/build/uClibc/libc/misc/glob/.indent.pro
@@ -0,0 +1,33 @@
+--blank-lines-after-declarations
+--blank-lines-after-procedures
+--break-before-boolean-operator
+--no-blank-lines-after-commas
+--braces-on-if-line
+--braces-on-struct-decl-line
+--comment-indentation25
+--declaration-comment-column25
+--no-comment-delimiters-on-blank-lines
+--cuddle-else
+--continuation-indentation4
+--case-indentation0
+--else-endif-column33
+--space-after-cast
+--line-comments-indentation0
+--declaration-indentation1
+--dont-format-first-column-comments
+--dont-format-comments
+--honour-newlines
+--indent-level4
+/* changed from 0 to 4 */
+--parameter-indentation4
+--line-length78 /* changed from 75 */
+--continue-at-parentheses
+--no-space-after-function-call-names
+--dont-break-procedure-type
+--dont-star-comments
+--leave-optional-blank-lines
+--dont-space-special-semicolon
+--tab-size4
+/* additions by Mark */
+--case-brace-indentation0
+--leave-preprocessor-space
diff --git a/ap/build/uClibc/libc/misc/glob/Makefile b/ap/build/uClibc/libc/misc/glob/Makefile
new file mode 100644
index 0000000..4a8f4a0
--- /dev/null
+++ b/ap/build/uClibc/libc/misc/glob/Makefile
@@ -0,0 +1,13 @@
+# Makefile for uClibc
+#
+# Copyright (C) 2000-2005 Erik Andersen <andersen@uclibc.org>
+#
+# Licensed under the LGPL v2.1, see the file COPYING.LIB in this tarball.
+#
+
+top_srcdir=../../../
+top_builddir=../../../
+all: objs
+include $(top_builddir)Rules.mak
+include Makefile.in
+include $(top_srcdir)Makerules
diff --git a/ap/build/uClibc/libc/misc/glob/Makefile.in b/ap/build/uClibc/libc/misc/glob/Makefile.in
new file mode 100644
index 0000000..03bfcca
--- /dev/null
+++ b/ap/build/uClibc/libc/misc/glob/Makefile.in
@@ -0,0 +1,33 @@
+# Makefile for uClibc
+#
+# Copyright (C) 2000-2008 Erik Andersen <andersen@uclibc.org>
+#
+# Licensed under the LGPL v2.1, see the file COPYING.LIB in this tarball.
+#
+
+subdirs += libc/misc/glob
+
+ifeq ($(UCLIBC_HAS_GNU_GLOB),y)
+CSRC := glob.c
+ifeq ($(UCLIBC_HAS_LFS),y)
+CSRC += glob64.c
+endif
+else
+CSRC := glob-susv3.c
+ifeq ($(UCLIBC_HAS_LFS),y)
+CSRC += glob64-susv3.c
+endif
+endif
+
+MISC_GLOB_DIR := $(top_srcdir)libc/misc/glob
+MISC_GLOB_OUT := $(top_builddir)libc/misc/glob
+
+MISC_GLOB_SRC := $(patsubst %.c,$(MISC_GLOB_DIR)/%.c,$(CSRC))
+MISC_GLOB_OBJ := $(patsubst %.c,$(MISC_GLOB_OUT)/%.o,$(CSRC))
+
+libc-$(UCLIBC_HAS_GLOB) += $(MISC_GLOB_OBJ)
+
+objclean-y += CLEAN_libc/misc/glob
+
+CLEAN_libc/misc/glob:
+ $(do_rm) $(addprefix $(MISC_GLOB_OUT)/*., o os)
diff --git a/ap/build/uClibc/libc/misc/glob/glob-susv3.c b/ap/build/uClibc/libc/misc/glob/glob-susv3.c
new file mode 100644
index 0000000..59b4d8e
--- /dev/null
+++ b/ap/build/uClibc/libc/misc/glob/glob-susv3.c
@@ -0,0 +1,299 @@
+/*
+ * Copyright (C) 2006 Rich Felker <dalias@aerifal.cx>
+ *
+ * Licensed under the LGPL v2.1, see the file COPYING.LIB in this tarball.
+ */
+
+#include <features.h>
+
+#ifdef __UCLIBC_HAS_LFS__
+# define BUILD_GLOB64
+#endif
+
+#include <glob.h>
+#include <fnmatch.h>
+#include <sys/stat.h>
+#include <dirent.h>
+#include <limits.h>
+#include <string.h>
+#include <stdlib.h>
+#include <errno.h>
+#include <stddef.h>
+
+#include <unistd.h>
+#include <stdio.h>
+
+
+struct match
+{
+ struct match *next;
+ char name[1];
+};
+
+#ifdef BUILD_GLOB64
+extern int __glob_is_literal(const char *p, int useesc) attribute_hidden;
+extern int __glob_append(struct match **tail, const char *name, size_t len, int mark) attribute_hidden;
+extern int __glob_ignore_err(const char *path, int err) attribute_hidden;
+extern void __glob_freelist(struct match *head) attribute_hidden;
+extern int __glob_sort(const void *a, const void *b) attribute_hidden;
+extern int __glob_match_in_dir(const char *d, const char *p, int flags, int (*errfunc)(const char *path, int err), struct match **tail) attribute_hidden;
+#endif
+
+#ifdef __UCLIBC_HAS_LFS__
+# define stat stat64
+# define readdir_r readdir64_r
+# define dirent dirent64
+# define struct_stat struct stat64
+#else
+# define struct_stat struct stat
+#endif
+
+/* keep only one copy of these */
+#ifndef __GLOB64
+
+# ifndef BUILD_GLOB64
+static
+# endif
+int __glob_is_literal(const char *p, int useesc)
+{
+ int bracket = 0;
+ for (; *p; p++) {
+ switch (*p) {
+ case '\\':
+ if (!useesc) break;
+ case '?':
+ case '*':
+ return 0;
+ case '[':
+ bracket = 1;
+ break;
+ case ']':
+ if (bracket) return 0;
+ break;
+ }
+ }
+ return 1;
+}
+
+# ifndef BUILD_GLOB64
+static
+# endif
+int __glob_append(struct match **tail, const char *name, size_t len, int mark)
+{
+ struct match *new = malloc(sizeof(struct match) + len + 1);
+ if (!new) return -1;
+ (*tail)->next = new;
+ new->next = NULL;
+ strcpy(new->name, name);
+ if (mark) strcat(new->name, "/");
+ *tail = new;
+ return 0;
+}
+
+# ifndef BUILD_GLOB64
+static
+# endif
+int __glob_match_in_dir(const char *d, const char *p, int flags, int (*errfunc)(const char *path, int err), struct match **tail)
+{
+ DIR *dir;
+ long long de_buf[(sizeof(struct dirent) + NAME_MAX + sizeof(long long))/sizeof(long long)];
+ struct dirent *de;
+ char pat[strlen(p)+1];
+ char *p2;
+ size_t l = strlen(d);
+ int literal;
+ int fnm_flags= ((flags & GLOB_NOESCAPE) ? FNM_NOESCAPE : 0) | FNM_PERIOD;
+ int error;
+
+ if ((p2 = strchr(p, '/'))) {
+ strcpy(pat, p);
+ pat[p2-p] = 0;
+ for (; *p2 == '/'; p2++);
+ p = pat;
+ }
+ literal = __glob_is_literal(p, !(flags & GLOB_NOESCAPE));
+ if (*d == '/' && !*(d+1)) l = 0;
+
+ /* rely on opendir failing for nondirectory objects */
+ dir = opendir(*d ? d : ".");
+ error = errno;
+ if (!dir) {
+ /* this is not an error -- we let opendir call stat for us */
+ if (error == ENOTDIR) return 0;
+ if (error == EACCES && !*p) {
+ struct_stat st;
+ if (!stat(d, &st) && S_ISDIR(st.st_mode)) {
+ if (__glob_append(tail, d, l, l))
+ return GLOB_NOSPACE;
+ return 0;
+ }
+ }
+ if (errfunc(d, error) || (flags & GLOB_ERR))
+ return GLOB_ABORTED;
+ return 0;
+ }
+ if (!*p) {
+ error = __glob_append(tail, d, l, l) ? GLOB_NOSPACE : 0;
+ closedir(dir);
+ return error;
+ }
+ while (!(error = readdir_r(dir, (void *)de_buf, &de)) && de) {
+ char namebuf[l+de->d_reclen+2], *name = namebuf;
+ if (!literal && fnmatch(p, de->d_name, fnm_flags))
+ continue;
+ if (literal && strcmp(p, de->d_name))
+ continue;
+ if (p2 && de->d_type && !S_ISDIR(de->d_type<<12) && !S_ISLNK(de->d_type<<12))
+ continue;
+ if (*d) {
+ memcpy(name, d, l);
+ name[l] = '/';
+ strcpy(name+l+1, de->d_name);
+ } else {
+ name = de->d_name;
+ }
+ if (p2) {
+ if ((error = __glob_match_in_dir(name, p2, flags, errfunc, tail))) {
+ closedir(dir);
+ return error;
+ }
+ } else {
+ int mark = 0;
+ if (flags & GLOB_MARK) {
+ if (de->d_type)
+ mark = S_ISDIR(de->d_type<<12);
+ else {
+ struct_stat st;
+ stat(name, &st);
+ mark = S_ISDIR(st.st_mode);
+ }
+ }
+ if (__glob_append(tail, name, l+de->d_reclen+1, mark)) {
+ closedir(dir);
+ return GLOB_NOSPACE;
+ }
+ }
+ }
+ closedir(dir);
+ if (error && (errfunc(d, error) || (flags & GLOB_ERR)))
+ return GLOB_ABORTED;
+ return 0;
+}
+
+# ifndef BUILD_GLOB64
+static
+# endif
+int __glob_ignore_err(const char * path attribute_unused,
+ int err attribute_unused)
+{
+ return 0;
+}
+
+# ifndef BUILD_GLOB64
+static
+# endif
+void __glob_freelist(struct match *head)
+{
+ struct match *match, *next;
+ for (match=head->next; match; match=next) {
+ next = match->next;
+ free(match);
+ }
+}
+
+# ifndef BUILD_GLOB64
+static
+# endif
+int __glob_sort(const void *a, const void *b)
+{
+ return strcmp(*(const char **)a, *(const char **)b);
+}
+#endif /* !__GLOB64 */
+
+int glob(const char *pat, int flags, int (*errfunc)(const char *path, int err), glob_t *g)
+{
+ const char *p=pat, *d;
+ struct match head = { .next = NULL }, *tail = &head;
+ size_t cnt, i;
+ size_t offs = (flags & GLOB_DOOFFS) ? g->gl_offs : 0;
+ int error = 0;
+
+ if (*p == '/') {
+ for (; *p == '/'; p++);
+ d = "/";
+ } else {
+ d = "";
+ }
+
+ if (!errfunc) errfunc = __glob_ignore_err;
+
+ if (!(flags & GLOB_APPEND)) {
+ g->gl_offs = offs;
+ g->gl_pathc = 0;
+ g->gl_pathv = NULL;
+ }
+
+ if (*p) error = __glob_match_in_dir(d, p, flags, errfunc, &tail);
+ if (error == GLOB_NOSPACE) {
+ __glob_freelist(&head);
+ return error;
+ }
+
+ for (cnt=0, tail=head.next; tail; tail=tail->next, cnt++);
+ if (!cnt) {
+ if (flags & GLOB_NOCHECK) {
+ tail = &head;
+ if (__glob_append(&tail, pat, strlen(pat), 0))
+ return GLOB_NOSPACE;
+ cnt++;
+ } else
+ return GLOB_NOMATCH;
+ }
+
+ if (flags & GLOB_APPEND) {
+ char **pathv = realloc(g->gl_pathv, (offs + g->gl_pathc + cnt + 1) * sizeof(char *));
+ if (!pathv) {
+ __glob_freelist(&head);
+ return GLOB_NOSPACE;
+ }
+ g->gl_pathv = pathv;
+ offs += g->gl_pathc;
+ } else {
+ g->gl_pathv = malloc((offs + cnt + 1) * sizeof(char *));
+ if (!g->gl_pathv) {
+ __glob_freelist(&head);
+ return GLOB_NOSPACE;
+ }
+ for (i=0; i<offs; i++)
+ g->gl_pathv[i] = NULL;
+ }
+ for (i=0, tail=head.next; i<cnt; tail=tail->next, i++)
+ g->gl_pathv[offs + i] = tail->name;
+ g->gl_pathv[offs + i] = NULL;
+ g->gl_pathc += cnt;
+
+ if (!(flags & GLOB_NOSORT))
+ qsort(g->gl_pathv+offs, cnt, sizeof(char *), __glob_sort);
+
+ return error;
+}
+#ifdef __GLOB64
+libc_hidden_def(glob64)
+#else
+libc_hidden_def(glob)
+#endif
+
+void globfree(glob_t *g)
+{
+ size_t i;
+ for (i=0; i<g->gl_pathc; i++)
+ free(g->gl_pathv[g->gl_offs + i] - offsetof(struct match, name));
+ free(g->gl_pathv);
+ g->gl_pathc = 0;
+ g->gl_pathv = NULL;
+}
+#ifdef __GLOB64
+libc_hidden_def(globfree64)
+#else
+libc_hidden_def(globfree)
+#endif
diff --git a/ap/build/uClibc/libc/misc/glob/glob.c b/ap/build/uClibc/libc/misc/glob/glob.c
new file mode 100644
index 0000000..488f229
--- /dev/null
+++ b/ap/build/uClibc/libc/misc/glob/glob.c
@@ -0,0 +1,1067 @@
+/* Copyright (C) 1991-2002,2003,2004,2005,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. */
+
+#undef ENABLE_GLOB_BRACE_EXPANSION
+#undef ENABLE_GLOB_TILDE_EXPANSION
+
+#include <features.h>
+#include <stdlib.h>
+#include <string.h>
+#include <errno.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <unistd.h>
+#include <dirent.h>
+#include <malloc.h>
+#include <fnmatch.h>
+#include <glob.h>
+
+
+
+#ifdef ENABLE_GLOB_TILDE_EXPANSION
+#include <pwd.h>
+#endif
+
+#ifdef COMPILE_GLOB64
+#undef stat
+#define stat stat64
+#define struct_stat64 struct stat64
+#define __stat64(fname, buf) stat64 (fname, buf)
+#define dirent dirent64
+#define __readdir readdir64
+#define __readdir64 readdir64
+#define glob_t glob64_t
+#define glob(pattern, flags, errfunc, pglob) glob64 (pattern, flags, errfunc, pglob)
+#define globfree(pglob) globfree64 (pglob)
+#else
+#define __readdir readdir
+#ifdef __UCLIBC_HAS_LFS__
+#define __readdir64 readdir64
+#else
+#define __readdir64 readdir
+#endif
+#define struct_stat64 struct stat
+#define __stat64(fname, buf) stat (fname, buf)
+#endif
+
+
+/* When used in the GNU libc the symbol _DIRENT_HAVE_D_TYPE is available
+ if the `d_type' member for `struct dirent' is available.
+ HAVE_STRUCT_DIRENT_D_TYPE plays the same role in GNULIB. */
+#if defined _DIRENT_HAVE_D_TYPE
+/* True if the directory entry D must be of type T. */
+# define DIRENT_MUST_BE(d, t) ((d)->d_type == (t))
+
+/* True if the directory entry D might be a symbolic link. */
+# define DIRENT_MIGHT_BE_SYMLINK(d) \
+ ((d)->d_type == DT_UNKNOWN || (d)->d_type == DT_LNK)
+
+/* True if the directory entry D might be a directory. */
+# define DIRENT_MIGHT_BE_DIR(d) \
+ ((d)->d_type == DT_DIR || DIRENT_MIGHT_BE_SYMLINK (d))
+
+#else /* !HAVE_D_TYPE */
+# define DIRENT_MUST_BE(d, t) false
+# define DIRENT_MIGHT_BE_SYMLINK(d) true
+# define DIRENT_MIGHT_BE_DIR(d) true
+#endif /* HAVE_D_TYPE */
+
+
+# define NAMLEN(dirent) strlen((dirent)->d_name)
+#ifdef _D_NAMLEN
+# undef NAMLEN
+# define NAMLEN(d) _D_NAMLEN(d)
+#endif
+
+# if defined _DIRENT_HAVE_D_NAMLEN
+# define CONVERT_D_NAMLEN(d64, d32) (d64)->d_namlen = (d32)->d_namlen;
+# else
+# define CONVERT_D_NAMLEN(d64, d32)
+# endif
+
+# define CONVERT_D_INO(d64, d32) (d64)->d_ino = (d32)->d_ino;
+
+# ifdef _DIRENT_HAVE_D_TYPE
+# define CONVERT_D_TYPE(d64, d32) (d64)->d_type = (d32)->d_type;
+# else
+# define CONVERT_D_TYPE(d64, d32)
+# endif
+
+# define CONVERT_DIRENT_DIRENT64(d64, d32) \
+ memcpy ((d64)->d_name, (d32)->d_name, NAMLEN (d32) + 1); \
+ CONVERT_D_NAMLEN (d64, d32) \
+ CONVERT_D_INO (d64, d32) \
+ CONVERT_D_TYPE (d64, d32)
+
+extern int __collated_compare (const void *a, const void *b) attribute_hidden;
+extern int __prefix_array (const char *dirname, char **array, size_t n) attribute_hidden;
+#if defined ENABLE_GLOB_BRACE_EXPANSION
+extern const char *__next_brace_sub (const char *cp, int flags) attribute_hidden;
+#endif
+
+#ifndef COMPILE_GLOB64
+/* Return nonzero if PATTERN contains any metacharacters.
+ Metacharacters can be quoted with backslashes if QUOTE is nonzero. */
+int glob_pattern_p(const char *pattern, int quote)
+{
+ register const char *p;
+ int open = 0;
+
+ for (p = pattern; *p != '\0'; ++p)
+ switch (*p)
+ {
+ case '?':
+ case '*':
+ return 1;
+
+ case '\\':
+ if (quote && p[1] != '\0')
+ ++p;
+ break;
+
+ case '[':
+ open = 1;
+ break;
+
+ case ']':
+ if (open)
+ return 1;
+ break;
+ }
+
+ return 0;
+}
+libc_hidden_def(glob_pattern_p)
+
+
+/* Do a collated comparison of A and B. */
+int __collated_compare (const void *a, const void *b)
+{
+ const char *const s1 = *(const char *const * const) a;
+ const char *const s2 = *(const char *const * const) b;
+
+ if (s1 == s2)
+ return 0;
+ if (s1 == NULL)
+ return 1;
+ if (s2 == NULL)
+ return -1;
+ return strcoll (s1, s2);
+}
+
+
+/* Prepend DIRNAME to each of N members of ARRAY, replacing ARRAY's
+ elements in place. Return nonzero if out of memory, zero if successful.
+ A slash is inserted between DIRNAME and each elt of ARRAY,
+ unless DIRNAME is just "/". Each old element of ARRAY is freed.
+ If ADD_SLASH is non-zero, allocate one character more than
+ necessary, so that a slash can be appended later. */
+int __prefix_array (const char *dirname, char **array, size_t n)
+{
+ register size_t i;
+ size_t dirlen = strlen (dirname);
+# define DIRSEP_CHAR '/'
+
+ if (dirlen == 1 && dirname[0] == '/')
+ /* DIRNAME is just "/", so normal prepending would get us "//foo".
+ We want "/foo" instead, so don't prepend any chars from DIRNAME. */
+ dirlen = 0;
+
+ for (i = 0; i < n; ++i)
+ {
+ size_t eltlen = strlen (array[i]) + 1;
+ char *new = (char *) malloc (dirlen + 1 + eltlen);
+ if (new == NULL)
+ {
+ while (i > 0)
+ free (array[--i]);
+ return 1;
+ }
+
+ {
+ char *endp = mempcpy (new, dirname, dirlen);
+ *endp++ = DIRSEP_CHAR;
+ mempcpy (endp, array[i], eltlen);
+ }
+ free (array[i]);
+ array[i] = new;
+ }
+
+ return 0;
+}
+
+#if defined ENABLE_GLOB_BRACE_EXPANSION
+/* Find the end of the sub-pattern in a brace expression. */
+const char *
+__next_brace_sub (const char *cp, int flags)
+{
+ unsigned int depth = 0;
+ while (*cp != '\0')
+ if ((flags & GLOB_NOESCAPE) == 0 && *cp == '\\')
+ {
+ if (*++cp == '\0')
+ break;
+ ++cp;
+ }
+ else
+ {
+ if ((*cp == '}' && depth-- == 0) || (*cp == ',' && depth == 0))
+ break;
+
+ if (*cp++ == '{')
+ depth++;
+ }
+
+ return *cp != '\0' ? cp : NULL;
+}
+#endif
+#endif
+
+
+static int
+link_exists_p (const char *dir, size_t dirlen, const char *fname,
+ glob_t *pglob, int flags)
+{
+ size_t fnamelen = strlen (fname);
+ char *fullname = (char *) alloca (dirlen + 1 + fnamelen + 1);
+ struct stat st;
+ struct_stat64 st64;
+
+ mempcpy (mempcpy (mempcpy (fullname, dir, dirlen), "/", 1),
+ fname, fnamelen + 1);
+
+ return (((flags & GLOB_ALTDIRFUNC)
+ ? (*pglob->gl_stat) (fullname, &st)
+ : __stat64 (fullname, &st64)) == 0);
+}
+
+/* Like `glob', but PATTERN is a final pathname component,
+ and matches are searched for in DIRECTORY.
+ The GLOB_NOSORT bit in FLAGS is ignored. No sorting is ever done.
+ The GLOB_APPEND flag is assumed to be set (always appends). */
+static int glob_in_dir (const char *pattern, const char *directory, int flags,
+ int (*errfunc) (const char *, int),
+ glob_t *pglob)
+{
+ size_t dirlen = strlen (directory);
+ void *stream = NULL;
+ struct globlink
+ {
+ struct globlink *next;
+ char *name;
+ };
+ struct globlink *names = NULL;
+ size_t nfound;
+ int meta;
+ int save;
+
+ meta = glob_pattern_p (pattern, !(flags & GLOB_NOESCAPE));
+ if (meta == 0 && (flags & (GLOB_NOCHECK|GLOB_NOMAGIC)))
+ {
+ /* We need not do any tests. The PATTERN contains no meta
+ characters and we must not return an error therefore the
+ result will always contain exactly one name. */
+ flags |= GLOB_NOCHECK;
+ nfound = 0;
+ }
+ else if (meta == 0 &&
+ ((flags & GLOB_NOESCAPE) || strchr (pattern, '\\') == NULL))
+ {
+ /* Since we use the normal file functions we can also use stat()
+ to verify the file is there. */
+ struct stat st;
+ struct_stat64 st64;
+ size_t patlen = strlen (pattern);
+ char *fullname = (char *) alloca (dirlen + 1 + patlen + 1);
+
+ mempcpy (mempcpy (mempcpy (fullname, directory, dirlen),
+ "/", 1),
+ pattern, patlen + 1);
+ if (((flags & GLOB_ALTDIRFUNC)
+ ? (*pglob->gl_stat) (fullname, &st)
+ : __stat64 (fullname, &st64)) == 0)
+ /* We found this file to be existing. Now tell the rest
+ of the function to copy this name into the result. */
+ flags |= GLOB_NOCHECK;
+
+ nfound = 0;
+ }
+ else
+ {
+ if (pattern[0] == '\0')
+ {
+ /* This is a special case for matching directories like in
+ "*a/". */
+ names = (struct globlink *) alloca (sizeof (struct globlink));
+ names->name = (char *) malloc (1);
+ if (names->name == NULL)
+ goto memory_error;
+ names->name[0] = '\0';
+ names->next = NULL;
+ nfound = 1;
+ meta = 0;
+ }
+ else
+ {
+ stream = ((flags & GLOB_ALTDIRFUNC)
+ ? (*pglob->gl_opendir) (directory)
+ : opendir (directory));
+ if (stream == NULL)
+ {
+ if (errno != ENOTDIR
+ && ((errfunc != NULL && (*errfunc) (directory, errno))
+ || (flags & GLOB_ERR)))
+ return GLOB_ABORTED;
+ nfound = 0;
+ meta = 0;
+ }
+ else
+ {
+ int fnm_flags = ((!(flags & GLOB_PERIOD) ? FNM_PERIOD : 0)
+ | ((flags & GLOB_NOESCAPE) ? FNM_NOESCAPE : 0)
+ );
+ nfound = 0;
+ flags |= GLOB_MAGCHAR;
+
+ while (1)
+ {
+ const char *name;
+ size_t len;
+#if defined __UCLIBC_HAS_LFS__ && !defined COMPILE_GLOB64
+ struct dirent64 *d;
+ union
+ {
+ struct dirent64 d64;
+ char room [offsetof (struct dirent64, d_name[0])
+ + NAME_MAX + 1];
+ }
+ d64buf;
+
+ if (flags & GLOB_ALTDIRFUNC)
+ {
+ struct dirent *d32 = (*pglob->gl_readdir) (stream);
+ if (d32 != NULL)
+ {
+ CONVERT_DIRENT_DIRENT64 (&d64buf.d64, d32);
+ d = &d64buf.d64;
+ }
+ else
+ d = NULL;
+ }
+ else
+ d = __readdir64 (stream);
+#else
+ struct dirent *d = ((flags & GLOB_ALTDIRFUNC)
+ ? ((struct dirent *)
+ (*pglob->gl_readdir) (stream))
+ : __readdir (stream));
+#endif
+ if (d == NULL)
+ break;
+# define REAL_DIR_ENTRY(dp) (dp->d_ino != 0)
+ if (! REAL_DIR_ENTRY (d))
+ continue;
+
+ /* If we shall match only directories use the information
+ provided by the dirent call if possible. */
+ if ((flags & GLOB_ONLYDIR) && !DIRENT_MIGHT_BE_DIR (d))
+ continue;
+
+ name = d->d_name;
+
+ if (fnmatch (pattern, name, fnm_flags) == 0)
+ {
+ /* If the file we found is a symlink we have to
+ make sure the target file exists. */
+ if (!DIRENT_MIGHT_BE_SYMLINK (d)
+ || link_exists_p (directory, dirlen, name, pglob,
+ flags))
+ {
+ struct globlink *new = (struct globlink *)
+ alloca (sizeof (struct globlink));
+ len = NAMLEN (d);
+ new->name = (char *) malloc (len + 1);
+ if (new->name == NULL)
+ goto memory_error;
+ *((char *) mempcpy (new->name, name, len)) = '\0';
+ new->next = names;
+ names = new;
+ ++nfound;
+ }
+ }
+ }
+ }
+ }
+ }
+
+ if (nfound == 0 && (flags & GLOB_NOCHECK))
+ {
+ size_t len = strlen (pattern);
+ nfound = 1;
+ names = (struct globlink *) alloca (sizeof (struct globlink));
+ names->next = NULL;
+ names->name = (char *) malloc (len + 1);
+ if (names->name == NULL)
+ goto memory_error;
+ *((char *) mempcpy (names->name, pattern, len)) = '\0';
+ }
+
+ if (nfound != 0)
+ {
+ char **new_gl_pathv;
+
+ new_gl_pathv
+ = (char **) realloc (pglob->gl_pathv,
+ (pglob->gl_pathc + pglob->gl_offs + nfound + 1)
+ * sizeof (char *));
+ if (new_gl_pathv == NULL)
+ goto memory_error;
+ pglob->gl_pathv = new_gl_pathv;
+
+ for (; names != NULL; names = names->next)
+ pglob->gl_pathv[pglob->gl_offs + pglob->gl_pathc++] = names->name;
+ pglob->gl_pathv[pglob->gl_offs + pglob->gl_pathc] = NULL;
+
+ pglob->gl_flags = flags;
+ }
+
+ save = errno;
+ if (stream != NULL)
+ {
+ if (flags & GLOB_ALTDIRFUNC)
+ (*pglob->gl_closedir) (stream);
+ else
+ closedir (stream);
+ }
+ __set_errno (save);
+
+ return nfound == 0 ? GLOB_NOMATCH : 0;
+
+ memory_error:
+ {
+ int save2 = errno;
+ if (flags & GLOB_ALTDIRFUNC)
+ (*pglob->gl_closedir) (stream);
+ else
+ closedir (stream);
+ __set_errno (save2);
+ }
+ while (names != NULL)
+ {
+ free (names->name);
+ names = names->next;
+ }
+ return GLOB_NOSPACE;
+}
+
+/* Do glob searching for PATTERN, placing results in PGLOB.
+ The bits defined above may be set in FLAGS.
+ If a directory cannot be opened or read and ERRFUNC is not nil,
+ it is called with the pathname that caused the error, and the
+ `errno' value from the failing call; if it returns non-zero
+ `glob' returns GLOB_ABEND; if it returns zero, the error is ignored.
+ If memory cannot be allocated for PGLOB, GLOB_NOSPACE is returned.
+ Otherwise, `glob' returns zero. */
+int
+glob (
+ const char *pattern,
+ int flags,
+ int (*errfunc) (const char *, int),
+ glob_t *pglob)
+{
+ const char *filename;
+ const char *dirname;
+ size_t dirlen;
+ int status;
+ size_t oldcount;
+
+ if (pattern == NULL || pglob == NULL || (flags & ~__GLOB_FLAGS) != 0)
+ {
+ __set_errno (EINVAL);
+ return -1;
+ }
+
+
+ if (!(flags & GLOB_DOOFFS))
+ /* Have to do this so `globfree' knows where to start freeing. It
+ also makes all the code that uses gl_offs simpler. */
+ pglob->gl_offs = 0;
+
+#if defined ENABLE_GLOB_BRACE_EXPANSION
+ if (flags & GLOB_BRACE)
+ {
+ const char *begin;
+
+ if (flags & GLOB_NOESCAPE)
+ begin = strchr (pattern, '{');
+ else
+ {
+ begin = pattern;
+ while (1)
+ {
+ if (*begin == '\0')
+ {
+ begin = NULL;
+ break;
+ }
+
+ if (*begin == '\\' && begin[1] != '\0')
+ ++begin;
+ else if (*begin == '{')
+ break;
+
+ ++begin;
+ }
+ }
+
+ if (begin != NULL)
+ {
+ /* Allocate working buffer large enough for our work. Note that
+ we have at least an opening and closing brace. */
+ size_t firstc;
+ char *alt_start;
+ const char *p;
+ const char *next;
+ const char *rest;
+ size_t rest_len;
+ char onealt[strlen (pattern) - 1];
+
+ /* We know the prefix for all sub-patterns. */
+ alt_start = mempcpy (onealt, pattern, begin - pattern);
+
+ /* Find the first sub-pattern and at the same time find the
+ rest after the closing brace. */
+ next = __next_brace_sub (begin + 1, flags);
+ if (next == NULL)
+ {
+ /* It is an illegal expression. */
+ return glob (pattern, flags & ~GLOB_BRACE, errfunc, pglob);
+ }
+
+ /* Now find the end of the whole brace expression. */
+ rest = next;
+ while (*rest != '}')
+ {
+ rest = __next_brace_sub (rest + 1, flags);
+ if (rest == NULL)
+ {
+ /* It is an illegal expression. */
+ return glob (pattern, flags & ~GLOB_BRACE, errfunc, pglob);
+ }
+ }
+ /* Please note that we now can be sure the brace expression
+ is well-formed. */
+ rest_len = strlen (++rest) + 1;
+
+ /* We have a brace expression. BEGIN points to the opening {,
+ NEXT points past the terminator of the first element, and END
+ points past the final }. We will accumulate result names from
+ recursive runs for each brace alternative in the buffer using
+ GLOB_APPEND. */
+
+ if (!(flags & GLOB_APPEND))
+ {
+ /* This call is to set a new vector, so clear out the
+ vector so we can append to it. */
+ pglob->gl_pathc = 0;
+ pglob->gl_pathv = NULL;
+ }
+ firstc = pglob->gl_pathc;
+
+ p = begin + 1;
+ while (1)
+ {
+ int result;
+
+ /* Construct the new glob expression. */
+ mempcpy (mempcpy (alt_start, p, next - p), rest, rest_len);
+
+ result = glob (onealt,
+ ((flags & ~(GLOB_NOCHECK | GLOB_NOMAGIC))
+ | GLOB_APPEND), errfunc, pglob);
+
+ /* If we got an error, return it. */
+ if (result && result != GLOB_NOMATCH)
+ {
+ if (!(flags & GLOB_APPEND))
+ {
+ globfree (pglob);
+ pglob->gl_pathc = 0;
+ }
+ return result;
+ }
+
+ if (*next == '}')
+ /* We saw the last entry. */
+ break;
+
+ p = next + 1;
+ next = __next_brace_sub (p, flags);
+ /* assert (next != NULL); */
+ }
+
+
+ if (pglob->gl_pathc != firstc)
+ /* We found some entries. */
+ return 0;
+ else if (!(flags & (GLOB_NOCHECK|GLOB_NOMAGIC)))
+ return GLOB_NOMATCH;
+ }
+ }
+#endif
+
+ /* Find the filename. */
+ filename = strrchr (pattern, '/');
+ if (filename == NULL)
+ {
+ /* This can mean two things: a simple name or "~name". The latter
+ case is nothing but a notation for a directory. */
+ if ((flags & (GLOB_TILDE|GLOB_TILDE_CHECK)) && pattern[0] == '~')
+ {
+ dirname = pattern;
+ dirlen = strlen (pattern);
+
+ /* Set FILENAME to NULL as a special flag. This is ugly but
+ other solutions would require much more code. We test for
+ this special case below. */
+ filename = NULL;
+ }
+ else
+ {
+ filename = pattern;
+ dirname = ".";
+ dirlen = 0;
+ }
+ }
+ else if (filename == pattern)
+ {
+ /* "/pattern". */
+ dirname = "/";
+ dirlen = 1;
+ ++filename;
+ }
+ else
+ {
+ char *newp;
+ dirlen = filename - pattern;
+ newp = (char *) alloca (dirlen + 1);
+ *((char *) mempcpy (newp, pattern, dirlen)) = '\0';
+ dirname = newp;
+ ++filename;
+
+ if (filename[0] == '\0'
+ && dirlen > 1)
+ /* "pattern/". Expand "pattern", appending slashes. */
+ {
+ int val = glob (dirname, flags | GLOB_MARK, errfunc, pglob);
+ if (val == 0)
+ pglob->gl_flags = ((pglob->gl_flags & ~GLOB_MARK)
+ | (flags & GLOB_MARK));
+ return val;
+ }
+ }
+
+ if (!(flags & GLOB_APPEND))
+ {
+ pglob->gl_pathc = 0;
+ if (!(flags & GLOB_DOOFFS))
+ pglob->gl_pathv = NULL;
+ else
+ {
+ size_t i;
+ pglob->gl_pathv = (char **) malloc ((pglob->gl_offs + 1)
+ * sizeof (char *));
+ if (pglob->gl_pathv == NULL)
+ return GLOB_NOSPACE;
+
+ for (i = 0; i <= pglob->gl_offs; ++i)
+ pglob->gl_pathv[i] = NULL;
+ }
+ }
+
+ oldcount = pglob->gl_pathc + pglob->gl_offs;
+
+#if defined ENABLE_GLOB_TILDE_EXPANSION
+ if ((flags & (GLOB_TILDE|GLOB_TILDE_CHECK)) && dirname[0] == '~')
+ {
+ if (dirname[1] == '\0' || dirname[1] == '/')
+ {
+ /* Look up home directory. */
+ const char *home_dir = getenv ("HOME");
+ if (home_dir == NULL || home_dir[0] == '\0')
+ {
+ int success;
+ char *name;
+# define GET_LOGIN_NAME_MAX() sysconf (_SC_LOGIN_NAME_MAX)
+ size_t buflen = GET_LOGIN_NAME_MAX () + 1;
+
+ if (buflen == 0)
+ /* `sysconf' does not support _SC_LOGIN_NAME_MAX. Try
+ a moderate value. */
+ buflen = 20;
+ name = (char *) alloca (buflen);
+
+ success = getlogin_r (name, buflen) == 0;
+ if (success)
+ {
+ struct passwd *p;
+# define GETPW_R_SIZE_MAX() sysconf (_SC_GETPW_R_SIZE_MAX)
+ long int pwbuflen = GETPW_R_SIZE_MAX ();
+ char *pwtmpbuf;
+ struct passwd pwbuf;
+ int save = errno;
+
+ pwtmpbuf = (char *) alloca (pwbuflen);
+
+ while (getpwnam_r (name, &pwbuf, pwtmpbuf, pwbuflen, &p)
+ != 0)
+ {
+ if (errno != ERANGE)
+ {
+ p = NULL;
+ break;
+ }
+ pwtmpbuf = extend_alloca (pwtmpbuf, pwbuflen,
+ 2 * pwbuflen);
+ __set_errno (save);
+ }
+ if (p != NULL)
+ home_dir = p->pw_dir;
+ }
+ }
+ if (home_dir == NULL || home_dir[0] == '\0')
+ {
+ if (flags & GLOB_TILDE_CHECK)
+ return GLOB_NOMATCH;
+ else
+ home_dir = "~"; /* No luck. */
+ }
+ /* Now construct the full directory. */
+ if (dirname[1] == '\0')
+ dirname = home_dir;
+ else
+ {
+ char *newp;
+ size_t home_len = strlen (home_dir);
+ newp = (char *) alloca (home_len + dirlen);
+ mempcpy (mempcpy (newp, home_dir, home_len),
+ &dirname[1], dirlen);
+ dirname = newp;
+ }
+ }
+ else
+ {
+ char *end_name = strchr (dirname, '/');
+ const char *user_name;
+ const char *home_dir;
+
+ if (end_name == NULL)
+ user_name = dirname + 1;
+ else
+ {
+ char *newp;
+ newp = (char *) alloca (end_name - dirname);
+ *((char *) mempcpy (newp, dirname + 1, end_name - dirname))
+ = '\0';
+ user_name = newp;
+ }
+
+ /* Look up specific user's home directory. */
+ {
+ struct passwd *p;
+ long int buflen = GETPW_R_SIZE_MAX ();
+ char *pwtmpbuf;
+ struct passwd pwbuf;
+ int save = errno;
+
+ pwtmpbuf = (char *) alloca (buflen);
+
+ while (getpwnam_r (user_name, &pwbuf, pwtmpbuf, buflen, &p) != 0)
+ {
+ if (errno != ERANGE)
+ {
+ p = NULL;
+ break;
+ }
+ pwtmpbuf = extend_alloca (pwtmpbuf, buflen, 2 * buflen);
+ __set_errno (save);
+ }
+ if (p != NULL)
+ home_dir = p->pw_dir;
+ else
+ home_dir = NULL;
+ }
+ /* If we found a home directory use this. */
+ if (home_dir != NULL)
+ {
+ char *newp;
+ size_t home_len = strlen (home_dir);
+ size_t rest_len = end_name == NULL ? 0 : strlen (end_name);
+ newp = (char *) alloca (home_len + rest_len + 1);
+ *((char *) mempcpy (mempcpy (newp, home_dir, home_len),
+ end_name, rest_len)) = '\0';
+ dirname = newp;
+ }
+ else
+ if (flags & GLOB_TILDE_CHECK)
+ /* We have to regard it as an error if we cannot find the
+ home directory. */
+ return GLOB_NOMATCH;
+ }
+ }
+
+ /* Now test whether we looked for "~" or "~NAME". In this case we
+ can give the answer now. */
+ if (filename == NULL)
+ {
+ struct stat st;
+ struct_stat64 st64;
+
+ /* Return the directory if we don't check for error or if it exists. */
+ if ((flags & GLOB_NOCHECK)
+ || (((flags & GLOB_ALTDIRFUNC)
+ ? ((*pglob->gl_stat) (dirname, &st) == 0
+ && S_ISDIR (st.st_mode))
+ : (__stat64 (dirname, &st64) == 0 && S_ISDIR (st64.st_mode)))))
+ {
+ int newcount = pglob->gl_pathc + pglob->gl_offs;
+ char **new_gl_pathv;
+
+ new_gl_pathv
+ = (char **) realloc (pglob->gl_pathv,
+ (newcount + 1 + 1) * sizeof (char *));
+ if (new_gl_pathv == NULL)
+ {
+ nospace:
+ free (pglob->gl_pathv);
+ pglob->gl_pathv = NULL;
+ pglob->gl_pathc = 0;
+ return GLOB_NOSPACE;
+ }
+ pglob->gl_pathv = new_gl_pathv;
+
+ pglob->gl_pathv[newcount] = strdup (dirname);
+ if (pglob->gl_pathv[newcount] == NULL)
+ goto nospace;
+ pglob->gl_pathv[++newcount] = NULL;
+ ++pglob->gl_pathc;
+ pglob->gl_flags = flags;
+
+ return 0;
+ }
+
+ /* Not found. */
+ return GLOB_NOMATCH;
+ }
+#endif
+
+ if (glob_pattern_p (dirname, !(flags & GLOB_NOESCAPE)))
+ {
+ /* The directory name contains metacharacters, so we
+ have to glob for the directory, and then glob for
+ the pattern in each directory found. */
+ glob_t dirs;
+ size_t i;
+
+ if ((flags & GLOB_ALTDIRFUNC) != 0)
+ {
+ /* Use the alternative access functions also in the recursive
+ call. */
+ dirs.gl_opendir = pglob->gl_opendir;
+ dirs.gl_readdir = pglob->gl_readdir;
+ dirs.gl_closedir = pglob->gl_closedir;
+ dirs.gl_stat = pglob->gl_stat;
+ dirs.gl_lstat = pglob->gl_lstat;
+ }
+
+ status = glob (dirname,
+ ((flags & (GLOB_ERR | GLOB_NOCHECK | GLOB_NOESCAPE
+ | GLOB_ALTDIRFUNC))
+ | GLOB_NOSORT | GLOB_ONLYDIR),
+ errfunc, &dirs);
+ if (status != 0)
+ return status;
+
+ /* We have successfully globbed the preceding directory name.
+ For each name we found, call glob_in_dir on it and FILENAME,
+ appending the results to PGLOB. */
+ for (i = 0; i < dirs.gl_pathc; ++i)
+ {
+ int old_pathc;
+
+ old_pathc = pglob->gl_pathc;
+ status = glob_in_dir (filename, dirs.gl_pathv[i],
+ ((flags | GLOB_APPEND)
+ & ~(GLOB_NOCHECK | GLOB_NOMAGIC)),
+ errfunc, pglob);
+ if (status == GLOB_NOMATCH)
+ /* No matches in this directory. Try the next. */
+ continue;
+
+ if (status != 0)
+ {
+ globfree (&dirs);
+ globfree (pglob);
+ pglob->gl_pathc = 0;
+ return status;
+ }
+
+ /* Stick the directory on the front of each name. */
+ if (__prefix_array (dirs.gl_pathv[i],
+ &pglob->gl_pathv[old_pathc + pglob->gl_offs],
+ pglob->gl_pathc - old_pathc))
+ {
+ globfree (&dirs);
+ globfree (pglob);
+ pglob->gl_pathc = 0;
+ return GLOB_NOSPACE;
+ }
+ }
+
+ flags |= GLOB_MAGCHAR;
+
+ /* We have ignored the GLOB_NOCHECK flag in the `glob_in_dir' calls.
+ But if we have not found any matching entry and the GLOB_NOCHECK
+ flag was set we must return the input pattern itself. */
+ if (pglob->gl_pathc + pglob->gl_offs == oldcount)
+ {
+ /* No matches. */
+ if (flags & GLOB_NOCHECK)
+ {
+ int newcount = pglob->gl_pathc + pglob->gl_offs;
+ char **new_gl_pathv;
+
+ new_gl_pathv = (char **) realloc (pglob->gl_pathv,
+ (newcount + 2)
+ * sizeof (char *));
+ if (new_gl_pathv == NULL)
+ {
+ globfree (&dirs);
+ return GLOB_NOSPACE;
+ }
+ pglob->gl_pathv = new_gl_pathv;
+
+ pglob->gl_pathv[newcount] = strdup (pattern);
+ if (pglob->gl_pathv[newcount] == NULL)
+ {
+ globfree (&dirs);
+ globfree (pglob);
+ pglob->gl_pathc = 0;
+ return GLOB_NOSPACE;
+ }
+
+ ++pglob->gl_pathc;
+ ++newcount;
+
+ pglob->gl_pathv[newcount] = NULL;
+ pglob->gl_flags = flags;
+ }
+ else
+ {
+ globfree (&dirs);
+ return GLOB_NOMATCH;
+ }
+ }
+
+ globfree (&dirs);
+ }
+ else
+ {
+ int old_pathc = pglob->gl_pathc;
+
+ status = glob_in_dir (filename, dirname, flags, errfunc, pglob);
+ if (status != 0)
+ return status;
+
+ if (dirlen > 0)
+ {
+ /* Stick the directory on the front of each name. */
+ if (__prefix_array (dirname,
+ &pglob->gl_pathv[old_pathc + pglob->gl_offs],
+ pglob->gl_pathc - old_pathc))
+ {
+ globfree (pglob);
+ pglob->gl_pathc = 0;
+ return GLOB_NOSPACE;
+ }
+ }
+ }
+
+ if (flags & GLOB_MARK)
+ {
+ /* Append slashes to directory names. */
+ size_t i;
+ struct stat st;
+ struct_stat64 st64;
+
+ for (i = oldcount; i < pglob->gl_pathc + pglob->gl_offs; ++i)
+ if (((flags & GLOB_ALTDIRFUNC)
+ ? ((*pglob->gl_stat) (pglob->gl_pathv[i], &st) == 0
+ && S_ISDIR (st.st_mode))
+ : (__stat64 (pglob->gl_pathv[i], &st64) == 0
+ && S_ISDIR (st64.st_mode))))
+ {
+ size_t len = strlen (pglob->gl_pathv[i]) + 2;
+ char *new = realloc (pglob->gl_pathv[i], len);
+ if (new == NULL)
+ {
+ globfree (pglob);
+ pglob->gl_pathc = 0;
+ return GLOB_NOSPACE;
+ }
+ strcpy (&new[len - 2], "/");
+ pglob->gl_pathv[i] = new;
+ }
+ }
+
+ if (!(flags & GLOB_NOSORT))
+ {
+ /* Sort the vector. */
+ qsort (&pglob->gl_pathv[oldcount],
+ pglob->gl_pathc + pglob->gl_offs - oldcount,
+ sizeof (char *), __collated_compare);
+ }
+
+ return 0;
+}
+#ifdef COMPILE_GLOB64
+libc_hidden_def(glob64)
+#else
+libc_hidden_def(glob)
+#endif
+
+
+/* Free storage allocated in PGLOB by a previous `glob' call. */
+void
+globfree (register glob_t *pglob)
+{
+ if (pglob->gl_pathv != NULL)
+ {
+ size_t i;
+ for (i = 0; i < pglob->gl_pathc; ++i)
+ if (pglob->gl_pathv[pglob->gl_offs + i] != NULL)
+ free (pglob->gl_pathv[pglob->gl_offs + i]);
+ free (pglob->gl_pathv);
+ pglob->gl_pathv = NULL;
+ }
+}
+#ifdef COMPILE_GLOB64
+libc_hidden_def(globfree64)
+#else
+libc_hidden_def(globfree)
+#endif
diff --git a/ap/build/uClibc/libc/misc/glob/glob64-susv3.c b/ap/build/uClibc/libc/misc/glob/glob64-susv3.c
new file mode 100644
index 0000000..f73e2c3
--- /dev/null
+++ b/ap/build/uClibc/libc/misc/glob/glob64-susv3.c
@@ -0,0 +1,20 @@
+/*
+ * Copyright (C) 2006 Rich Felker <dalias@aerifal.cx>
+ *
+ * Licensed under the LGPL v2.1, see the file COPYING.LIB in this tarball.
+ */
+
+#include <_lfs_64.h>
+
+#include <dirent.h>
+#include <glob.h>
+#include <sys/stat.h>
+
+#define glob_t glob64_t
+#define glob(pattern, flags, errfunc, pglob) \
+ glob64 (pattern, flags, errfunc, pglob)
+#define globfree(pglob) globfree64 (pglob)
+
+#define __GLOB64 1
+
+#include "glob-susv3.c"
diff --git a/ap/build/uClibc/libc/misc/glob/glob64.c b/ap/build/uClibc/libc/misc/glob/glob64.c
new file mode 100644
index 0000000..b84af92
--- /dev/null
+++ b/ap/build/uClibc/libc/misc/glob/glob64.c
@@ -0,0 +1,15 @@
+/*
+ * Copyright (C) 2000-2006 Erik Andersen <andersen@uclibc.org>
+ *
+ * Licensed under the LGPL v2.1, see the file COPYING.LIB in this tarball.
+ */
+
+#include <_lfs_64.h>
+
+#include <dirent.h>
+#include <glob.h>
+#include <sys/stat.h>
+
+#define COMPILE_GLOB64 1
+
+#include "glob.c"
diff --git a/ap/build/uClibc/libc/misc/gnu/Makefile b/ap/build/uClibc/libc/misc/gnu/Makefile
new file mode 100644
index 0000000..4a8f4a0
--- /dev/null
+++ b/ap/build/uClibc/libc/misc/gnu/Makefile
@@ -0,0 +1,13 @@
+# Makefile for uClibc
+#
+# Copyright (C) 2000-2005 Erik Andersen <andersen@uclibc.org>
+#
+# Licensed under the LGPL v2.1, see the file COPYING.LIB in this tarball.
+#
+
+top_srcdir=../../../
+top_builddir=../../../
+all: objs
+include $(top_builddir)Rules.mak
+include Makefile.in
+include $(top_srcdir)Makerules
diff --git a/ap/build/uClibc/libc/misc/gnu/Makefile.in b/ap/build/uClibc/libc/misc/gnu/Makefile.in
new file mode 100644
index 0000000..3990e4e
--- /dev/null
+++ b/ap/build/uClibc/libc/misc/gnu/Makefile.in
@@ -0,0 +1,23 @@
+# Makefile for uClibc
+#
+# Copyright (C) 2000-2008 Erik Andersen <andersen@uclibc.org>
+#
+# Licensed under the LGPL v2.1, see the file COPYING.LIB in this tarball.
+#
+
+subdirs += libc/misc/gnu
+
+CSRC := obstack.c
+
+MISC_GNU_DIR := $(top_srcdir)libc/misc/gnu
+MISC_GNU_OUT := $(top_builddir)libc/misc/gnu
+
+MISC_GNU_SRC := $(MISC_GNU_DIR)/obstack.c
+MISC_GNU_OBJ := $(MISC_GNU_OUT)/obstack.o
+
+libc-y += $(MISC_GNU_OBJ)
+
+objclean-y += CLEAN_libc/misc/gnu
+
+CLEAN_libc/misc/gnu:
+ $(do_rm) $(addprefix $(MISC_GNU_OUT)/*., o os)
diff --git a/ap/build/uClibc/libc/misc/gnu/obstack.c b/ap/build/uClibc/libc/misc/gnu/obstack.c
new file mode 100644
index 0000000..2391463
--- /dev/null
+++ b/ap/build/uClibc/libc/misc/gnu/obstack.c
@@ -0,0 +1,456 @@
+/* obstack.c - subroutines used implicitly by object stack macros
+ Copyright (C) 1988, 1989, 1990, 1991, 1992, 1993, 1994, 1996, 1997, 1998,
+ 1999, 2000, 2001, 2002, 2003, 2004, 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. */
+
+
+#ifdef HAVE_CONFIG_H
+# include <config.h>
+#endif
+
+#ifdef _LIBC
+# include <obstack.h>
+#ifndef __UCLIBC__
+# include <shlib-compat.h>
+#else
+# define HAVE_INTTYPES_H 1
+# define HAVE_STDINT_H 1
+# define SHLIB_COMPAT(x,y,z) 0
+# undef libc_hidden_def
+# define libc_hidden_def(x)
+# undef strong_alias
+# define strong_alias(x,y)
+#endif
+#else
+# include "obstack.h"
+#endif
+
+/* NOTE BEFORE MODIFYING THIS FILE: This version number must be
+ incremented whenever callers compiled using an old obstack.h can no
+ longer properly call the functions in this obstack.c. */
+#define OBSTACK_INTERFACE_VERSION 1
+
+/* Comment out all this code if we are using the GNU C Library, and are not
+ actually compiling the library itself, and the installed library
+ supports the same library interface we do. This code is part of the GNU
+ C Library, but also included in many other GNU distributions. Compiling
+ and linking in this code is a waste when using the GNU C library
+ (especially if it is a shared library). Rather than having every GNU
+ program understand `configure --with-gnu-libc' and omit the object
+ files, it is simpler to just do this in the source for each such file. */
+
+#include <stdio.h> /* Random thing to get __GNU_LIBRARY__. */
+#if !defined _LIBC && defined __GNU_LIBRARY__ && __GNU_LIBRARY__ > 1
+# include <gnu-versions.h>
+# if _GNU_OBSTACK_INTERFACE_VERSION == OBSTACK_INTERFACE_VERSION
+# define ELIDE_CODE
+# endif
+#endif
+
+#include <stddef.h>
+
+#ifndef ELIDE_CODE
+
+
+# if HAVE_INTTYPES_H
+# include <inttypes.h>
+# endif
+# if HAVE_STDINT_H || defined _LIBC
+# include <stdint.h>
+# endif
+
+/* Determine default alignment. */
+union fooround
+{
+ uintmax_t i;
+ long double d;
+ void *p;
+};
+struct fooalign
+{
+ char c;
+ union fooround u;
+};
+/* If malloc were really smart, it would round addresses to DEFAULT_ALIGNMENT.
+ But in fact it might be less smart and round addresses to as much as
+ DEFAULT_ROUNDING. So we prepare for it to do that. */
+enum
+ {
+ DEFAULT_ALIGNMENT = offsetof (struct fooalign, u),
+ DEFAULT_ROUNDING = sizeof (union fooround)
+ };
+
+/* When we copy a long block of data, this is the unit to do it with.
+ On some machines, copying successive ints does not work;
+ in such a case, redefine COPYING_UNIT to `long' (if that works)
+ or `char' as a last resort. */
+# ifndef COPYING_UNIT
+# define COPYING_UNIT int
+# endif
+
+
+/* The functions allocating more room by calling `obstack_chunk_alloc'
+ jump to the handler pointed to by `obstack_alloc_failed_handler'.
+ This can be set to a user defined function which should either
+ abort gracefully or use longjump - but shouldn't return. This
+ variable by default points to the internal function
+ `print_and_abort'. */
+static void print_and_abort (void);
+static void (*__obstack_alloc_failed_handler) (void) = print_and_abort;
+weak_alias(__obstack_alloc_failed_handler,obstack_alloc_failed_handler)
+
+/* Exit value used when `print_and_abort' is used. */
+# include <stdlib.h>
+# ifdef _LIBC
+static int __obstack_exit_failure = EXIT_FAILURE;
+weak_alias(__obstack_exit_failure,obstack_exit_failure)
+# else
+# include "exitfail.h"
+# define __obstack_exit_failure exit_failure
+# endif
+
+# ifdef _LIBC
+# if SHLIB_COMPAT (libc, GLIBC_2_0, GLIBC_2_3_4)
+/* A looong time ago (before 1994, anyway; we're not sure) this global variable
+ was used by non-GNU-C macros to avoid multiple evaluation. The GNU C
+ library still exports it because somebody might use it. */
+struct obstack *_obstack_compat;
+compat_symbol (libc, _obstack_compat, _obstack, GLIBC_2_0);
+# endif
+# endif
+
+/* Define a macro that either calls functions with the traditional malloc/free
+ calling interface, or calls functions with the mmalloc/mfree interface
+ (that adds an extra first argument), based on the state of use_extra_arg.
+ For free, do not use ?:, since some compilers, like the MIPS compilers,
+ do not allow (expr) ? void : void. */
+
+# define CALL_CHUNKFUN(h, size) \
+ (((h) -> use_extra_arg) \
+ ? (*(h)->chunkfun) ((h)->extra_arg, (size)) \
+ : (*(struct _obstack_chunk *(*) (long)) (h)->chunkfun) ((size)))
+
+# define CALL_FREEFUN(h, old_chunk) \
+ do { \
+ if ((h) -> use_extra_arg) \
+ (*(h)->freefun) ((h)->extra_arg, (old_chunk)); \
+ else \
+ (*(void (*) (void *)) (h)->freefun) ((old_chunk)); \
+ } while (0)
+
+
+/* Initialize an obstack H for use. Specify chunk size SIZE (0 means default).
+ Objects start on multiples of ALIGNMENT (0 means use default).
+ CHUNKFUN is the function to use to allocate chunks,
+ and FREEFUN the function to free them.
+
+ Return nonzero if successful, calls obstack_alloc_failed_handler if
+ allocation fails. */
+
+int
+_obstack_begin (struct obstack *h,
+ int size, int alignment,
+ void *(*chunkfun) (long),
+ void (*freefun) (void *))
+{
+ register struct _obstack_chunk *chunk; /* points to new chunk */
+
+ if (alignment == 0)
+ alignment = DEFAULT_ALIGNMENT;
+ if (size == 0)
+ /* Default size is what GNU malloc can fit in a 4096-byte block. */
+ {
+ /* 12 is sizeof (mhead) and 4 is EXTRA from GNU malloc.
+ Use the values for range checking, because if range checking is off,
+ the extra bytes won't be missed terribly, but if range checking is on
+ and we used a larger request, a whole extra 4096 bytes would be
+ allocated.
+
+ These number are irrelevant to the new GNU malloc. I suspect it is
+ less sensitive to the size of the request. */
+ int extra = ((((12 + DEFAULT_ROUNDING - 1) & ~(DEFAULT_ROUNDING - 1))
+ + 4 + DEFAULT_ROUNDING - 1)
+ & ~(DEFAULT_ROUNDING - 1));
+ size = 4096 - extra;
+ }
+
+ h->chunkfun = (struct _obstack_chunk * (*)(void *, long)) chunkfun;
+ h->freefun = (void (*) (void *, struct _obstack_chunk *)) freefun;
+ h->chunk_size = size;
+ h->alignment_mask = alignment - 1;
+ h->use_extra_arg = 0;
+
+ chunk = h->chunk = CALL_CHUNKFUN (h, h -> chunk_size);
+ if (!chunk)
+ (*__obstack_alloc_failed_handler) ();
+ h->next_free = h->object_base = __PTR_ALIGN ((char *) chunk, chunk->contents,
+ alignment - 1);
+ h->chunk_limit = chunk->limit
+ = (char *) chunk + h->chunk_size;
+ chunk->prev = 0;
+ /* The initial chunk now contains no empty object. */
+ h->maybe_empty_object = 0;
+ h->alloc_failed = 0;
+ return 1;
+}
+
+int
+_obstack_begin_1 (struct obstack *h, int size, int alignment,
+ void *(*chunkfun) (void *, long),
+ void (*freefun) (void *, void *),
+ void *arg)
+{
+ register struct _obstack_chunk *chunk; /* points to new chunk */
+
+ if (alignment == 0)
+ alignment = DEFAULT_ALIGNMENT;
+ if (size == 0)
+ /* Default size is what GNU malloc can fit in a 4096-byte block. */
+ {
+ /* 12 is sizeof (mhead) and 4 is EXTRA from GNU malloc.
+ Use the values for range checking, because if range checking is off,
+ the extra bytes won't be missed terribly, but if range checking is on
+ and we used a larger request, a whole extra 4096 bytes would be
+ allocated.
+
+ These number are irrelevant to the new GNU malloc. I suspect it is
+ less sensitive to the size of the request. */
+ int extra = ((((12 + DEFAULT_ROUNDING - 1) & ~(DEFAULT_ROUNDING - 1))
+ + 4 + DEFAULT_ROUNDING - 1)
+ & ~(DEFAULT_ROUNDING - 1));
+ size = 4096 - extra;
+ }
+
+ h->chunkfun = (struct _obstack_chunk * (*)(void *,long)) chunkfun;
+ h->freefun = (void (*) (void *, struct _obstack_chunk *)) freefun;
+ h->chunk_size = size;
+ h->alignment_mask = alignment - 1;
+ h->extra_arg = arg;
+ h->use_extra_arg = 1;
+
+ chunk = h->chunk = CALL_CHUNKFUN (h, h -> chunk_size);
+ if (!chunk)
+ (*__obstack_alloc_failed_handler) ();
+ h->next_free = h->object_base = __PTR_ALIGN ((char *) chunk, chunk->contents,
+ alignment - 1);
+ h->chunk_limit = chunk->limit
+ = (char *) chunk + h->chunk_size;
+ chunk->prev = 0;
+ /* The initial chunk now contains no empty object. */
+ h->maybe_empty_object = 0;
+ h->alloc_failed = 0;
+ return 1;
+}
+
+/* Allocate a new current chunk for the obstack *H
+ on the assumption that LENGTH bytes need to be added
+ to the current object, or a new object of length LENGTH allocated.
+ Copies any partial object from the end of the old chunk
+ to the beginning of the new one. */
+
+void
+_obstack_newchunk (struct obstack *h, int length)
+{
+ register struct _obstack_chunk *old_chunk = h->chunk;
+ register struct _obstack_chunk *new_chunk;
+ register long new_size;
+ register long obj_size = h->next_free - h->object_base;
+ register long i;
+ long already;
+ char *object_base;
+
+ /* Compute size for new chunk. */
+ new_size = (obj_size + length) + (obj_size >> 3) + h->alignment_mask + 100;
+ if (new_size < h->chunk_size)
+ new_size = h->chunk_size;
+
+ /* Allocate and initialize the new chunk. */
+ new_chunk = CALL_CHUNKFUN (h, new_size);
+ if (!new_chunk)
+ (*__obstack_alloc_failed_handler) ();
+ h->chunk = new_chunk;
+ new_chunk->prev = old_chunk;
+ new_chunk->limit = h->chunk_limit = (char *) new_chunk + new_size;
+
+ /* Compute an aligned object_base in the new chunk */
+ object_base =
+ __PTR_ALIGN ((char *) new_chunk, new_chunk->contents, h->alignment_mask);
+
+ /* Move the existing object to the new chunk.
+ Word at a time is fast and is safe if the object
+ is sufficiently aligned. */
+ if (h->alignment_mask + 1 >= DEFAULT_ALIGNMENT)
+ {
+ for (i = obj_size / sizeof (COPYING_UNIT) - 1;
+ i >= 0; i--)
+ ((COPYING_UNIT *)object_base)[i]
+ = ((COPYING_UNIT *)h->object_base)[i];
+ /* We used to copy the odd few remaining bytes as one extra COPYING_UNIT,
+ but that can cross a page boundary on a machine
+ which does not do strict alignment for COPYING_UNITS. */
+ already = obj_size / sizeof (COPYING_UNIT) * sizeof (COPYING_UNIT);
+ }
+ else
+ already = 0;
+ /* Copy remaining bytes one by one. */
+ for (i = already; i < obj_size; i++)
+ object_base[i] = h->object_base[i];
+
+ /* If the object just copied was the only data in OLD_CHUNK,
+ free that chunk and remove it from the chain.
+ But not if that chunk might contain an empty object. */
+ if (! h->maybe_empty_object
+ && (h->object_base
+ == __PTR_ALIGN ((char *) old_chunk, old_chunk->contents,
+ h->alignment_mask)))
+ {
+ new_chunk->prev = old_chunk->prev;
+ CALL_FREEFUN (h, old_chunk);
+ }
+
+ h->object_base = object_base;
+ h->next_free = h->object_base + obj_size;
+ /* The new chunk certainly contains no empty object yet. */
+ h->maybe_empty_object = 0;
+}
+# ifdef _LIBC
+libc_hidden_def (_obstack_newchunk)
+# endif
+
+/* Return nonzero if object OBJ has been allocated from obstack H.
+ This is here for debugging.
+ If you use it in a program, you are probably losing. */
+
+/* Suppress -Wmissing-prototypes warning. We don't want to declare this in
+ obstack.h because it is just for debugging. */
+int _obstack_allocated_p (struct obstack *h, void *obj);
+
+int
+_obstack_allocated_p (struct obstack *h, void *obj)
+{
+ register struct _obstack_chunk *lp; /* below addr of any objects in this chunk */
+ register struct _obstack_chunk *plp; /* point to previous chunk if any */
+
+ lp = (h)->chunk;
+ /* We use >= rather than > since the object cannot be exactly at
+ the beginning of the chunk but might be an empty object exactly
+ at the end of an adjacent chunk. */
+ while (lp != 0 && ((void *) lp >= obj || (void *) (lp)->limit < obj))
+ {
+ plp = lp->prev;
+ lp = plp;
+ }
+ return lp != 0;
+}
+
+/* Free objects in obstack H, including OBJ and everything allocate
+ more recently than OBJ. If OBJ is zero, free everything in H. */
+
+# undef obstack_free
+
+void
+obstack_free (struct obstack *h, void *obj)
+{
+ register struct _obstack_chunk *lp; /* below addr of any objects in this chunk */
+ register struct _obstack_chunk *plp; /* point to previous chunk if any */
+
+ lp = h->chunk;
+ /* We use >= because there cannot be an object at the beginning of a chunk.
+ But there can be an empty object at that address
+ at the end of another chunk. */
+ while (lp != 0 && ((void *) lp >= obj || (void *) (lp)->limit < obj))
+ {
+ plp = lp->prev;
+ CALL_FREEFUN (h, lp);
+ lp = plp;
+ /* If we switch chunks, we can't tell whether the new current
+ chunk contains an empty object, so assume that it may. */
+ h->maybe_empty_object = 1;
+ }
+ if (lp)
+ {
+ h->object_base = h->next_free = (char *) (obj);
+ h->chunk_limit = lp->limit;
+ h->chunk = lp;
+ }
+ else if (obj != 0)
+ /* obj is not in any of the chunks! */
+ abort ();
+}
+
+# ifdef _LIBC
+/* Older versions of libc used a function _obstack_free intended to be
+ called by non-GCC compilers. */
+strong_alias (obstack_free, _obstack_free)
+# endif
+
+int
+_obstack_memory_used (struct obstack *h)
+{
+ register struct _obstack_chunk* lp;
+ register int nbytes = 0;
+
+ for (lp = h->chunk; lp != 0; lp = lp->prev)
+ {
+ nbytes += lp->limit - (char *) lp;
+ }
+ return nbytes;
+}
+
+/* Define the error handler. */
+# ifdef _LIBC
+# include <libintl.h>
+# else
+# include "gettext.h"
+# endif
+/* NLS: Disable gettext in obstack for now: */
+# undef _
+# define _(Str) (Str)
+# ifndef _
+# define _(msgid) gettext (msgid)
+# endif
+
+# if defined _LIBC && !defined __UCLIBC__
+# include <libio/iolibio.h>
+# endif
+
+# ifndef __attribute__
+/* This feature is available in gcc versions 2.5 and later. */
+# if __GNUC__ < 2 || (__GNUC__ == 2 && __GNUC_MINOR__ < 5)
+# define __attribute__(Spec) /* empty */
+# endif
+# endif
+
+static void
+attribute_noreturn
+print_and_abort (void)
+{
+ /* Don't change any of these strings. Yes, it would be possible to add
+ the newline to the string and use fputs or so. But this must not
+ happen because the "memory exhausted" message appears in other places
+ like this and the translation should be reused instead of creating
+ a very similar string which requires a separate translation. */
+# if defined _LIBC && !defined __UCLIBC__
+ (void) __fxprintf (NULL, "%s\n", _("memory exhausted"));
+# else
+ fprintf (stderr, "%s\n", _("memory exhausted"));
+# endif
+ exit (__obstack_exit_failure);
+}
+
+#endif /* !ELIDE_CODE */
diff --git a/ap/build/uClibc/libc/misc/internals/Makefile b/ap/build/uClibc/libc/misc/internals/Makefile
new file mode 100644
index 0000000..4a8f4a0
--- /dev/null
+++ b/ap/build/uClibc/libc/misc/internals/Makefile
@@ -0,0 +1,13 @@
+# Makefile for uClibc
+#
+# Copyright (C) 2000-2005 Erik Andersen <andersen@uclibc.org>
+#
+# Licensed under the LGPL v2.1, see the file COPYING.LIB in this tarball.
+#
+
+top_srcdir=../../../
+top_builddir=../../../
+all: objs
+include $(top_builddir)Rules.mak
+include Makefile.in
+include $(top_srcdir)Makerules
diff --git a/ap/build/uClibc/libc/misc/internals/Makefile.in b/ap/build/uClibc/libc/misc/internals/Makefile.in
new file mode 100644
index 0000000..354dfc9
--- /dev/null
+++ b/ap/build/uClibc/libc/misc/internals/Makefile.in
@@ -0,0 +1,43 @@
+# Makefile for uClibc
+#
+# Copyright (C) 2000-2008 Erik Andersen <andersen@uclibc.org>
+#
+# Licensed under the LGPL v2.1, see the file COPYING.LIB in this tarball.
+#
+
+subdirs += libc/misc/internals
+
+CSRC := tempname.c errno.c __errno_location.c __h_errno_location.c \
+ parse_config.c
+
+MISC_INTERNALS_DIR := $(top_srcdir)libc/misc/internals
+MISC_INTERNALS_OUT := $(top_builddir)libc/misc/internals
+
+MISC_INTERNALS_SRC := $(patsubst %.c,$(MISC_INTERNALS_DIR)/%.c,$(CSRC))
+MISC_INTERNALS_OBJ := $(patsubst %.c,$(MISC_INTERNALS_OUT)/%.o,$(CSRC))
+
+CFLAGS-__uClibc_main.c := $(SSP_DISABLE_FLAGS)
+
+
+libc-y += $(MISC_INTERNALS_OBJ)
+ifneq ($(UCLIBC_FORMAT_SHARED_FLAT),y)
+libc-shared-y += $(MISC_INTERNALS_OUT)/__uClibc_main.oS
+else
+libc-shared-y += $(MISC_INTERNALS_OUT)/__uClibc_main.os
+endif
+libc-static-y += $(MISC_INTERNALS_OUT)/__uClibc_main.o
+libc-static-$(UCLIBC_FORMAT_FLAT_SEP_DATA) += \
+ $(MISC_INTERNALS_OUT)/shared_flat_initfini.o \
+ $(MISC_INTERNALS_OUT)/shared_flat_add_library.o
+libc-static-$(UCLIBC_FORMAT_SHARED_FLAT) += \
+ $(MISC_INTERNALS_OUT)/shared_flat_initfini.o \
+ $(MISC_INTERNALS_OUT)/shared_flat_add_library.o
+libc-shared-$(UCLIBC_FORMAT_SHARED_FLAT) += \
+ $(MISC_INTERNALS_OUT)/shared_flat_initfini.os \
+ $(MISC_INTERNALS_OUT)/shared_flat_add_library.os
+libc-nomulti-y += $(MISC_INTERNALS_OUT)/__uClibc_main.o
+
+objclean-y += CLEAN_libc/misc/internals
+
+CLEAN_libc/misc/internals:
+ $(do_rm) $(addprefix $(MISC_INTERNALS_OUT)/*., o os oS)
diff --git a/ap/build/uClibc/libc/misc/internals/__errno_location.c b/ap/build/uClibc/libc/misc/internals/__errno_location.c
new file mode 100644
index 0000000..aec7641
--- /dev/null
+++ b/ap/build/uClibc/libc/misc/internals/__errno_location.c
@@ -0,0 +1,20 @@
+/*
+ * Copyright (C) 2000-2006 Erik Andersen <andersen@uclibc.org>
+ *
+ * Licensed under the LGPL v2.1, see the file COPYING.LIB in this tarball.
+ */
+
+#include "internal_errno.h"
+
+/* psm: moved to bits/errno.h: */
+int *
+#ifndef __UCLIBC_HAS_THREADS__
+weak_const_function
+#endif
+__errno_location (void)
+{
+ return &errno;
+}
+#ifdef IS_IN_libc /* not really need, only to keep in sync w/ libc_hidden_proto */
+libc_hidden_weak(__errno_location)
+#endif
diff --git a/ap/build/uClibc/libc/misc/internals/__h_errno_location.c b/ap/build/uClibc/libc/misc/internals/__h_errno_location.c
new file mode 100644
index 0000000..213d398
--- /dev/null
+++ b/ap/build/uClibc/libc/misc/internals/__h_errno_location.c
@@ -0,0 +1,13 @@
+/*
+ * Copyright (C) 2000-2006 Erik Andersen <andersen@uclibc.org>
+ *
+ * Licensed under the LGPL v2.1, see the file COPYING.LIB in this tarball.
+ */
+
+#include "internal_errno.h"
+
+int * weak_const_function __h_errno_location (void)
+{
+ return &h_errno;
+}
+libc_hidden_weak(__h_errno_location)
diff --git a/ap/build/uClibc/libc/misc/internals/__uClibc_main.c b/ap/build/uClibc/libc/misc/internals/__uClibc_main.c
new file mode 100644
index 0000000..71fdbd8
--- /dev/null
+++ b/ap/build/uClibc/libc/misc/internals/__uClibc_main.c
@@ -0,0 +1,518 @@
+/*
+ * Copyright (C) 2006 by Steven J. Hill <sjhill@realitydiluted.com>
+ * Copyright (C) 2001 by Manuel Novoa III <mjn3@uclibc.org>
+ * Copyright (C) 2000-2005 Erik Andersen <andersen@uclibc.org>
+ *
+ * Licensed under the LGPL v2.1, see the file COPYING.LIB in this tarball.
+ *
+ * __uClibc_main is the routine to be called by all the arch-specific
+ * versions of crt1.S in uClibc.
+ *
+ * It is meant to handle any special initialization needed by the library
+ * such as setting the global variable(s) __environ (environ) and
+ * initializing the stdio package. Using weak symbols, the latter is
+ * avoided in the static library case.
+ */
+
+#include <features.h>
+#ifndef __UCLIBC_HAS_THREADS_NATIVE__
+#define _ERRNO_H
+#endif
+#include <unistd.h>
+#include <stdlib.h>
+#include <string.h>
+#include <elf.h>
+#include <link.h>
+#include <bits/uClibc_page.h>
+#include <paths.h>
+#include <unistd.h>
+#include <asm/errno.h>
+#include <fcntl.h>
+#include <sys/stat.h>
+#include <sys/sysmacros.h>
+#ifdef __UCLIBC_HAS_THREADS_NATIVE__
+#include <errno.h>
+#include <pthread-functions.h>
+#include <not-cancel.h>
+#include <atomic.h>
+#endif
+#ifdef __UCLIBC_HAS_THREADS__
+#include <pthread.h>
+#endif
+
+#ifndef SHARED
+void *__libc_stack_end = NULL;
+
+# ifdef __UCLIBC_HAS_SSP__
+# include <dl-osinfo.h>
+static uintptr_t stack_chk_guard;
+# ifndef THREAD_SET_STACK_GUARD
+/* Only exported for architectures that don't store the stack guard canary
+ * in thread local area. */
+/* for gcc-4.1 non-TLS */
+uintptr_t __stack_chk_guard attribute_relro;
+# endif
+/* for gcc-3.x + Etoh ssp */
+# ifdef __UCLIBC_HAS_SSP_COMPAT__
+uintptr_t __guard attribute_relro;
+# endif
+# endif
+
+/*
+ * Needed to initialize _dl_phdr when statically linked
+ */
+
+void internal_function _dl_aux_init (ElfW(auxv_t) *av);
+
+#ifdef __UCLIBC_HAS_THREADS__
+/*
+ * uClibc internal locking requires that we have weak aliases
+ * for dummy functions in case libpthread.a is not linked in.
+ * This needs to be in compilation unit that is pulled always
+ * in or linker will disregard these weaks.
+ */
+
+static int __pthread_return_0 (pthread_mutex_t *unused) { return 0; }
+weak_alias (__pthread_return_0, __pthread_mutex_lock)
+weak_alias (__pthread_return_0, __pthread_mutex_trylock)
+weak_alias (__pthread_return_0, __pthread_mutex_unlock)
+
+int weak_function
+__pthread_mutex_init(pthread_mutex_t *mutex, const pthread_mutexattr_t *attr)
+{
+ return 0;
+}
+
+void weak_function
+_pthread_cleanup_push_defer(struct _pthread_cleanup_buffer *__buffer,
+ void (*__routine) (void *), void *__arg)
+{
+ __buffer->__routine = __routine;
+ __buffer->__arg = __arg;
+}
+
+void weak_function
+_pthread_cleanup_pop_restore(struct _pthread_cleanup_buffer *__buffer,
+ int __execute)
+{
+ if (__execute)
+ __buffer->__routine(__buffer->__arg);
+}
+#endif /* __UCLIBC_HAS_THREADS__ */
+
+#endif /* !SHARED */
+
+/* Defeat compiler optimization which assumes function addresses are never NULL */
+static __always_inline int not_null_ptr(const void *p)
+{
+ const void *q;
+ __asm__ (""
+ : "=r" (q) /* output */
+ : "0" (p) /* input */
+ );
+ return q != 0;
+}
+
+/*
+ * Prototypes.
+ */
+extern int *weak_const_function __errno_location(void);
+extern int *weak_const_function __h_errno_location(void);
+extern void weak_function _stdio_init(void) attribute_hidden;
+#ifdef __UCLIBC_HAS_LOCALE__
+extern void weak_function _locale_init(void) attribute_hidden;
+#endif
+#ifdef __UCLIBC_HAS_THREADS__
+#if !defined (__UCLIBC_HAS_THREADS_NATIVE__) || defined (SHARED)
+extern void weak_function __pthread_initialize_minimal(void);
+#else
+extern void __pthread_initialize_minimal(void);
+#endif
+#endif
+
+/* If __UCLIBC_FORMAT_SHARED_FLAT__, all array initialisation and finalisation
+ * is handled by the routines passed to __uClibc_main(). */
+#if defined (__UCLIBC_CTOR_DTOR__) && !defined (__UCLIBC_FORMAT_SHARED_FLAT__)
+extern void _dl_app_init_array(void);
+extern void _dl_app_fini_array(void);
+# ifndef SHARED
+/* These magic symbols are provided by the linker. */
+extern void (*__preinit_array_start []) (void) attribute_hidden;
+extern void (*__preinit_array_end []) (void) attribute_hidden;
+extern void (*__init_array_start []) (void) attribute_hidden;
+extern void (*__init_array_end []) (void) attribute_hidden;
+extern void (*__fini_array_start []) (void) attribute_hidden;
+extern void (*__fini_array_end []) (void) attribute_hidden;
+# endif
+#endif
+
+#if defined (__LDSO_STANDALONE_SUPPORT__) && defined (SHARED) && defined __sh__
+extern unsigned long _dl_skip_args;
+#endif
+
+attribute_hidden const char *__uclibc_progname = "";
+#ifdef __UCLIBC_HAS_PROGRAM_INVOCATION_NAME__
+const char *program_invocation_short_name = "";
+const char *program_invocation_name = "";
+#endif
+#ifdef __UCLIBC_HAS___PROGNAME__
+weak_alias (program_invocation_short_name, __progname)
+weak_alias (program_invocation_name, __progname_full)
+#endif
+
+/*
+ * Declare the __environ global variable and create a weak alias environ.
+ * This must be initialized; we cannot have a weak alias into bss.
+ */
+char **__environ = 0;
+weak_alias(__environ, environ)
+
+/* TODO: don't export __pagesize; we cant now because libpthread uses it */
+size_t __pagesize = 0;
+
+#ifndef O_NOFOLLOW
+# define O_NOFOLLOW 0
+#endif
+
+#ifndef __ARCH_HAS_NO_LDSO__
+static void __check_one_fd(int fd, int mode)
+{
+ /* Check if the specified fd is already open */
+ if (fcntl(fd, F_GETFD) == -1)
+ {
+ /* The descriptor is probably not open, so try to use /dev/null */
+ int nullfd = open(_PATH_DEVNULL, mode);
+ /* /dev/null is major=1 minor=3. Make absolutely certain
+ * that is in fact the device that we have opened and not
+ * some other wierd file... [removed in uclibc] */
+ if (nullfd!=fd)
+ {
+ abort();
+ }
+ }
+}
+
+static int __check_suid(void)
+{
+ uid_t uid, euid;
+ gid_t gid, egid;
+
+ uid = getuid();
+ euid = geteuid();
+ if (uid != euid)
+ return 1;
+ gid = getgid();
+ egid = getegid();
+ if (gid != egid)
+ return 1;
+ return 0; /* we are not suid */
+}
+#endif
+
+/* __uClibc_init completely initialize uClibc so it is ready to use.
+ *
+ * On ELF systems (with a dynamic loader) this function must be called
+ * from the dynamic loader (see TIS and ELF Specification), so that
+ * constructors of shared libraries (which depend on libc) can use all
+ * the libc code without restriction. For this we link the shared
+ * version of the uClibc with -init __uClibc_init so DT_INIT for
+ * uClibc is the address of __uClibc_init
+ *
+ * In all other cases we call it from the main stub
+ * __uClibc_main.
+ */
+
+extern void __uClibc_init(void);
+libc_hidden_proto(__uClibc_init)
+void __uClibc_init(void)
+{
+ /* Don't recurse */
+ if (__pagesize)
+ return;
+
+ /* Setup an initial value. This may not be perfect, but is
+ * better than malloc using __pagesize=0 for atexit, ctors, etc. */
+ __pagesize = PAGE_SIZE;
+
+#ifdef __UCLIBC_HAS_THREADS__
+ /* Before we start initializing uClibc we have to call
+ * __pthread_initialize_minimal so we can use pthread_locks
+ * whenever they are needed.
+ */
+#if !defined (__UCLIBC_HAS_THREADS_NATIVE__) || defined (SHARED)
+ if (likely(__pthread_initialize_minimal!=NULL))
+#endif
+ __pthread_initialize_minimal();
+#endif
+
+#ifndef SHARED
+# ifdef __UCLIBC_HAS_SSP__
+ /* Set up the stack checker's canary. */
+ stack_chk_guard = _dl_setup_stack_chk_guard();
+# ifdef THREAD_SET_STACK_GUARD
+ THREAD_SET_STACK_GUARD (stack_chk_guard);
+# else
+ __stack_chk_guard = stack_chk_guard;
+# endif
+# ifdef __UCLIBC_HAS_SSP_COMPAT__
+ __guard = stack_chk_guard;
+# endif
+# endif
+#endif
+
+#ifdef __UCLIBC_HAS_LOCALE__
+ /* Initialize the global locale structure. */
+ if (likely(not_null_ptr(_locale_init)))
+ _locale_init();
+#endif
+
+ /*
+ * Initialize stdio here. In the static library case, this will
+ * be bypassed if not needed because of the weak alias above.
+ * Thus we get a nice size savings because the stdio functions
+ * won't be pulled into the final static binary unless used.
+ */
+ if (likely(not_null_ptr(_stdio_init)))
+ _stdio_init();
+
+}
+libc_hidden_def(__uClibc_init)
+
+#ifdef __UCLIBC_CTOR_DTOR__
+void attribute_hidden (*__app_fini)(void) = NULL;
+#endif
+
+void attribute_hidden (*__rtld_fini)(void) = NULL;
+
+extern void __uClibc_fini(void);
+libc_hidden_proto(__uClibc_fini)
+void __uClibc_fini(void)
+{
+#ifdef __UCLIBC_CTOR_DTOR__
+ /* If __UCLIBC_FORMAT_SHARED_FLAT__, all array finalisation is handled
+ * by __app_fini. */
+# ifdef SHARED
+ _dl_app_fini_array();
+# elif !defined (__UCLIBC_FORMAT_SHARED_FLAT__)
+ size_t i = __fini_array_end - __fini_array_start;
+ while (i-- > 0)
+ (*__fini_array_start [i]) ();
+# endif
+ if (__app_fini != NULL)
+ (__app_fini)();
+#endif
+ if (__rtld_fini != NULL)
+ (__rtld_fini)();
+}
+libc_hidden_def(__uClibc_fini)
+
+#ifndef SHARED
+extern void __nptl_deallocate_tsd (void) __attribute ((weak));
+extern unsigned int __nptl_nthreads __attribute ((weak));
+#endif
+
+/* __uClibc_main is the new main stub for uClibc. This function is
+ * called from crt1 (version 0.9.28 or newer), after ALL shared libraries
+ * are initialized, just before we call the application's main function.
+ */
+void __uClibc_main(int (*main)(int, char **, char **), int argc,
+ char **argv, void (*app_init)(void), void (*app_fini)(void),
+ void (*rtld_fini)(void),
+ void *stack_end attribute_unused) attribute_noreturn;
+void __uClibc_main(int (*main)(int, char **, char **), int argc,
+ char **argv, void (*app_init)(void), void (*app_fini)(void),
+ void (*rtld_fini)(void), void *stack_end attribute_unused)
+{
+#ifndef __ARCH_HAS_NO_LDSO__
+ unsigned long *aux_dat;
+ ElfW(auxv_t) auxvt[AT_EGID + 1];
+#endif
+
+#ifdef __UCLIBC_HAS_THREADS_NATIVE__
+ /* Result of the 'main' function. */
+ int result;
+#endif
+
+#ifndef SHARED
+ __libc_stack_end = stack_end;
+#endif
+
+ __rtld_fini = rtld_fini;
+
+#if defined __LDSO_STANDALONE_SUPPORT__ && defined SHARED && defined __sh__
+ /*
+ * Skip ld.so and its arguments
+ * Other archs except for SH do this in _dl_start before passing
+ * control to the application.
+ * FIXME: align SH _dl_start to other archs and remove this from here,
+ * so that we can keep the visibility hidden.
+ */
+ argc -= _dl_skip_args;
+ argv += _dl_skip_args;
+#endif
+
+ /* The environment begins right after argv. */
+ __environ = &argv[argc + 1];
+
+ /* If the first thing after argv is the arguments
+ * then the environment is empty. */
+ if ((char *) __environ == *argv) {
+ /* Make __environ point to the NULL at argv[argc] */
+ __environ = &argv[argc];
+ }
+
+#ifndef __ARCH_HAS_NO_LDSO__
+ /* Pull stuff from the ELF header when possible */
+ memset(auxvt, 0x00, sizeof(auxvt));
+ aux_dat = (unsigned long*)__environ;
+ while (*aux_dat) {
+ aux_dat++;
+ }
+ aux_dat++;
+ while (*aux_dat) {
+ ElfW(auxv_t) *auxv_entry = (ElfW(auxv_t) *) aux_dat;
+ if (auxv_entry->a_type <= AT_EGID) {
+ memcpy(&(auxvt[auxv_entry->a_type]), auxv_entry, sizeof(ElfW(auxv_t)));
+ }
+ aux_dat += 2;
+ }
+#ifndef SHARED
+ /* Get the program headers (_dl_phdr) from the aux vector
+ It will be used into __libc_setup_tls. */
+
+ _dl_aux_init (auxvt);
+#endif
+#endif
+
+ /* We need to initialize uClibc. If we are dynamically linked this
+ * may have already been completed by the shared lib loader. We call
+ * __uClibc_init() regardless, to be sure the right thing happens. */
+ __uClibc_init();
+
+#ifndef __ARCH_HAS_NO_LDSO__
+ /* Make certain getpagesize() gives the correct answer */
+ __pagesize = (auxvt[AT_PAGESZ].a_un.a_val)? auxvt[AT_PAGESZ].a_un.a_val : PAGE_SIZE;
+
+ /* Prevent starting SUID binaries where the stdin. stdout, and
+ * stderr file descriptors are not already opened. */
+ if ((auxvt[AT_UID].a_un.a_val == (size_t)-1 && __check_suid()) ||
+ (auxvt[AT_UID].a_un.a_val != (size_t)-1 &&
+ (auxvt[AT_UID].a_un.a_val != auxvt[AT_EUID].a_un.a_val ||
+ auxvt[AT_GID].a_un.a_val != auxvt[AT_EGID].a_un.a_val)))
+ {
+ __check_one_fd (STDIN_FILENO, O_RDONLY | O_NOFOLLOW);
+ __check_one_fd (STDOUT_FILENO, O_RDWR | O_NOFOLLOW);
+ __check_one_fd (STDERR_FILENO, O_RDWR | O_NOFOLLOW);
+ }
+#endif
+
+ __uclibc_progname = *argv;
+#ifdef __UCLIBC_HAS_PROGRAM_INVOCATION_NAME__
+ if (*argv != NULL) {
+ program_invocation_name = *argv;
+ program_invocation_short_name = strrchr(*argv, '/');
+ if (program_invocation_short_name != NULL)
+ ++program_invocation_short_name;
+ else
+ program_invocation_short_name = program_invocation_name;
+ }
+#endif
+
+#ifdef __UCLIBC_CTOR_DTOR__
+ /* Arrange for the application's dtors to run before we exit. */
+ __app_fini = app_fini;
+
+ /* If __UCLIBC_FORMAT_SHARED_FLAT__, all array initialisation is handled
+ * by __app_init. */
+# if !defined (SHARED) && !defined (__UCLIBC_FORMAT_SHARED_FLAT__)
+ /* For dynamically linked executables the preinit array is executed by
+ the dynamic linker (before initializing any shared object).
+ For static executables, preinit happens rights before init. */
+ {
+ const size_t size = __preinit_array_end - __preinit_array_start;
+ size_t i;
+ for (i = 0; i < size; i++)
+ (*__preinit_array_start [i]) ();
+ }
+# endif
+ /* Run all the application's ctors now. */
+ if (app_init!=NULL) {
+ app_init();
+ }
+ /* If __UCLIBC_FORMAT_SHARED_FLAT__, all array initialisation is handled
+ * by __app_init. */
+# ifdef SHARED
+ _dl_app_init_array();
+# elif !defined (__UCLIBC_FORMAT_SHARED_FLAT__)
+ {
+ const size_t size = __init_array_end - __init_array_start;
+ size_t i;
+ for (i = 0; i < size; i++)
+ (*__init_array_start [i]) ();
+ }
+# endif
+#endif
+
+ /* Note: It is possible that any initialization done above could
+ * have resulted in errno being set nonzero, so set it to 0 before
+ * we call main.
+ */
+ if (likely(not_null_ptr(__errno_location)))
+ *(__errno_location()) = 0;
+
+ /* Set h_errno to 0 as well */
+ if (likely(not_null_ptr(__h_errno_location)))
+ *(__h_errno_location()) = 0;
+
+#if defined HAVE_CLEANUP_JMP_BUF && defined __UCLIBC_HAS_THREADS_NATIVE__
+ /* Memory for the cancellation buffer. */
+ struct pthread_unwind_buf unwind_buf;
+
+ int not_first_call;
+ not_first_call =
+ setjmp ((struct __jmp_buf_tag *) unwind_buf.cancel_jmp_buf);
+ if (__builtin_expect (! not_first_call, 1))
+ {
+ struct pthread *self = THREAD_SELF;
+
+ /* Store old info. */
+ unwind_buf.priv.data.prev = THREAD_GETMEM (self, cleanup_jmp_buf);
+ unwind_buf.priv.data.cleanup = THREAD_GETMEM (self, cleanup);
+
+ /* Store the new cleanup handler info. */
+ THREAD_SETMEM (self, cleanup_jmp_buf, &unwind_buf);
+
+ /* Run the program. */
+ result = main (argc, argv, __environ);
+ }
+ else
+ {
+ /* Remove the thread-local data. */
+# ifdef SHARED
+ __libc_pthread_functions.ptr__nptl_deallocate_tsd ();
+# else
+ __nptl_deallocate_tsd ();
+# endif
+
+ /* One less thread. Decrement the counter. If it is zero we
+ terminate the entire process. */
+ result = 0;
+# ifdef SHARED
+ unsigned int *const ptr = __libc_pthread_functions.ptr_nthreads;
+# else
+ unsigned int *const ptr = &__nptl_nthreads;
+# endif
+
+ if (! atomic_decrement_and_test (ptr))
+ /* Not much left to do but to exit the thread, not the process. */
+ __exit_thread_inline (0);
+ }
+
+ exit (result);
+#else
+ /*
+ * Finally, invoke application's main and then exit.
+ */
+ exit (main (argc, argv, __environ));
+#endif
+}
diff --git a/ap/build/uClibc/libc/misc/internals/errno.c b/ap/build/uClibc/libc/misc/internals/errno.c
new file mode 100644
index 0000000..11d19ee
--- /dev/null
+++ b/ap/build/uClibc/libc/misc/internals/errno.c
@@ -0,0 +1,21 @@
+#include <features.h>
+
+#ifdef __UCLIBC_HAS_TLS__
+__thread int errno;
+__thread int h_errno;
+
+extern __thread int __libc_errno __attribute__ ((alias ("errno"))) attribute_hidden;
+extern __thread int __libc_h_errno __attribute__ ((alias ("h_errno"))) attribute_hidden;
+#define h_errno __libc_h_errno
+
+#else
+#include "internal_errno.h"
+int errno = 0;
+int h_errno = 0;
+#ifdef __UCLIBC_HAS_THREADS__
+libc_hidden_def(errno)
+weak_alias(errno, _errno)
+libc_hidden_def(h_errno)
+weak_alias(h_errno, _h_errno)
+#endif
+#endif
diff --git a/ap/build/uClibc/libc/misc/internals/internal_errno.h b/ap/build/uClibc/libc/misc/internals/internal_errno.h
new file mode 100644
index 0000000..b491985
--- /dev/null
+++ b/ap/build/uClibc/libc/misc/internals/internal_errno.h
@@ -0,0 +1,21 @@
+/*
+ *
+ */
+
+#include <features.h>
+#include <errno.h>
+#include <netdb.h>
+
+#ifndef __UCLIBC_HAS_TLS__
+
+#undef errno
+#undef h_errno
+
+extern int h_errno;
+extern int errno;
+
+#ifdef __UCLIBC_HAS_THREADS__
+libc_hidden_proto(h_errno)
+libc_hidden_proto(errno)
+#endif
+#endif
diff --git a/ap/build/uClibc/libc/misc/internals/parse_config.c b/ap/build/uClibc/libc/misc/internals/parse_config.c
new file mode 100644
index 0000000..4d21b5e
--- /dev/null
+++ b/ap/build/uClibc/libc/misc/internals/parse_config.c
@@ -0,0 +1,278 @@
+/* vi: set sw=4 ts=4: */
+/*
+ * config file parser helper
+ *
+ * Copyright (C) 2008 by Vladimir Dronnikov <dronnikov@gmail.com>
+ *
+ * Licensed under GPLv2 or later, see file LICENSE in this tarball for details.
+ * Also for use in uClibc (http://uclibc.org/) licensed under LGPLv2.1 or later.
+ */
+
+#if !defined _LIBC
+#include "libbb.h"
+
+#if defined ENABLE_PARSE && ENABLE_PARSE
+int parse_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
+int parse_main(int argc UNUSED_PARAM, char **argv)
+{
+ const char *delims = "# \t";
+ unsigned flags = PARSE_NORMAL;
+ int mintokens = 0, ntokens = 128;
+
+ opt_complementary = "-1:n+:m+:f+";
+ getopt32(argv, "n:m:d:f:", &ntokens, &mintokens, &delims, &flags);
+ //argc -= optind;
+ argv += optind;
+ while (*argv) {
+ parser_t *p = config_open(*argv);
+ if (p) {
+ int n;
+ char **t = xmalloc(sizeof(char *) * ntokens);
+ while ((n = config_read(p, t, ntokens, mintokens, delims, flags)) != 0) {
+ for (int i = 0; i < n; ++i)
+ printf("[%s]", t[i]);
+ puts("");
+ }
+ config_close(p);
+ }
+ argv++;
+ }
+ return EXIT_SUCCESS;
+}
+#endif
+#else
+# include <unistd.h>
+# include <string.h>
+# include <malloc.h>
+# include <bits/uClibc_page.h>
+# include "internal/parse_config.h"
+# ifndef FAST_FUNC
+# define FAST_FUNC
+# endif
+# define fopen_or_warn_stdin fopen
+# define bb_error_msg(...)
+# define xstrdup strdup
+# define xfunc_die() return 0
+/* Read up to EOF or EOL, treat line-continuations as extending the line.
+ Return number of bytes read into .line, -1 otherwise */
+static off_t bb_get_chunk_with_continuation(parser_t* parsr)
+{
+ off_t pos = 0;
+ char *chp;
+
+ while (1) {
+ if (fgets(parsr->line + pos, parsr->line_len - pos, parsr->fp) == NULL) {
+ memset(parsr->line, 0, parsr->line_len);
+ pos = -1;
+ break;
+ }
+ pos += strlen(parsr->line + pos);
+ chp = strchr(parsr->line, '\n');
+ if (chp) {
+ --pos;
+ if (--*chp == '\\')
+ --pos;
+ else
+ break;
+ } else if (parsr->allocated) {
+ parsr->line_len += PAGE_SIZE;
+ parsr->data = realloc(parsr->data,
+ parsr->data_len + parsr->line_len);
+ parsr->line = parsr->data + parsr->data_len;
+ } else {
+ /* discard rest of line if not enough space in buffer */
+ int c;
+ do {
+ c = fgetc(parsr->fp);
+ } while (c != EOF && c != '\n');
+ break;
+ }
+ }
+ return pos;
+}
+#endif
+
+/*
+
+Typical usage:
+
+----- CUT -----
+ char *t[3]; // tokens placeholder
+ parser_t *p = config_open(filename);
+ if (p) {
+ // parse line-by-line
+ while (config_read(p, t, 3, 0, delimiters, flags)) { // 1..3 tokens
+ // use tokens
+ bb_error_msg("TOKENS: [%s][%s][%s]", t[0], t[1], t[2]);
+ }
+ ...
+ // free parser
+ config_close(p);
+ }
+----- CUT -----
+
+*/
+
+static __always_inline parser_t * FAST_FUNC config_open2(const char *filename,
+ FILE* FAST_FUNC (*fopen_func)(const char *path, const char *mode))
+{
+ parser_t *parser;
+ FILE* fp;
+
+ fp = fopen_func(filename, "r");
+ if (!fp)
+ return NULL;
+ parser = calloc(1, sizeof(*parser));
+ if (parser) {
+ parser->fp = fp;
+ }
+ return parser;
+}
+
+parser_t attribute_hidden * FAST_FUNC config_open(const char *filename)
+{
+ return config_open2(filename, fopen_or_warn_stdin);
+}
+
+#ifdef UNUSED
+static void config_free_data(parser_t *parser)
+{
+ free(parser->data);
+ parser->data = parser->line = NULL;
+}
+#endif
+
+void attribute_hidden FAST_FUNC config_close(parser_t *parser)
+{
+ if (parser) {
+ fclose(parser->fp);
+ if (parser->allocated)
+ free(parser->data);
+ free(parser);
+ }
+}
+
+/*
+0. If parser is NULL return 0.
+1. Read a line from config file. If nothing to read then return 0.
+ Handle continuation character. Advance lineno for each physical line.
+ Discard everything past comment character.
+2. if PARSE_TRIM is set (default), remove leading and trailing delimiters.
+3. If resulting line is empty goto 1.
+4. Look for first delimiter. If !PARSE_COLLAPSE or !PARSE_TRIM is set then
+ remember the token as empty.
+5. Else (default) if number of seen tokens is equal to max number of tokens
+ (token is the last one) and PARSE_GREEDY is set then the remainder
+ of the line is the last token.
+ Else (token is not last or PARSE_GREEDY is not set) just replace
+ first delimiter with '\0' thus delimiting the token.
+6. Advance line pointer past the end of token. If number of seen tokens
+ is less than required number of tokens then goto 4.
+7. Check the number of seen tokens is not less the min number of tokens.
+ Complain or die otherwise depending on PARSE_MIN_DIE.
+8. Return the number of seen tokens.
+
+mintokens > 0 make config_read() print error message if less than mintokens
+(but more than 0) are found. Empty lines are always skipped (not warned about).
+*/
+#undef config_read
+int attribute_hidden FAST_FUNC config_read(parser_t *parser, char ***tokens,
+ unsigned flags, const char *delims)
+{
+ char *line;
+ int ntokens, mintokens;
+ off_t len;
+ int t;
+
+ if (parser == NULL)
+ return 0;
+ ntokens = flags & 0xFF;
+ mintokens = (flags & 0xFF00) >> 8;
+again:
+ if (parser->data == NULL) {
+ if (parser->line_len == 0)
+ parser->line_len = 81;
+ if (parser->data_len == 0)
+ parser->data_len += 1 + ntokens * sizeof(char *);
+ parser->data = malloc(parser->data_len + parser->line_len);
+ if (parser->data == NULL)
+ return 0;
+ parser->allocated |= 1;
+ } /* else { assert(parser->data_len > 0); } */
+ parser->line = parser->data + parser->data_len;
+ /*config_free_data(parser);*/
+
+ /* Read one line (handling continuations with backslash) */
+ len = bb_get_chunk_with_continuation(parser);
+ if (len == -1)
+ return 0;
+ line = parser->line;
+
+ /* Skip multiple token-delimiters in the start of line? */
+ if (flags & PARSE_TRIM)
+ line += strspn(line, delims + 1);
+
+ if (line[0] == '\0' || line[0] == delims[0])
+ goto again;
+
+ *tokens = (char **) parser->data;
+ memset(*tokens, 0, sizeof(*tokens[0]) * ntokens);
+
+ /* Tokenize the line */
+ for (t = 0; *line && *line != delims[0] && t < ntokens; t++) {
+ /* Pin token */
+ *(*tokens + t) = line;
+
+ /* Combine remaining arguments? */
+ if ((t != ntokens-1) || !(flags & PARSE_GREEDY)) {
+ /* Vanilla token, find next delimiter */
+ line += strcspn(line, delims[0] ? delims : delims + 1);
+ } else {
+ /* Combining, find comment char if any */
+ line = strchrnul(line, delims[0]);
+
+ /* Trim any extra delimiters from the end */
+ if (flags & PARSE_TRIM) {
+ while (strchr(delims + 1, line[-1]) != NULL)
+ line--;
+ }
+ }
+
+ /* Token not terminated? */
+ if (line[0] == delims[0])
+ *line = '\0';
+ else if (line[0] != '\0')
+ *(line++) = '\0';
+
+#if 0 /* unused so far */
+ if (flags & PARSE_ESCAPE) {
+ const char *from;
+ char *to;
+
+ from = to = tokens[t];
+ while (*from) {
+ if (*from == '\\') {
+ from++;
+ *to++ = bb_process_escape_sequence(&from);
+ } else {
+ *to++ = *from++;
+ }
+ }
+ *to = '\0';
+ }
+#endif
+
+ /* Skip possible delimiters */
+ if (flags & PARSE_COLLAPSE)
+ line += strspn(line, delims + 1);
+ }
+
+ if (t < mintokens) {
+ bb_error_msg(/*"bad line %u: "*/"%d tokens found, %d needed",
+ /*parser->lineno, */t, mintokens);
+ if (flags & PARSE_MIN_DIE)
+ xfunc_die();
+ goto again;
+ }
+ return t;
+}
diff --git a/ap/build/uClibc/libc/misc/internals/shared_flat_add_library.c b/ap/build/uClibc/libc/misc/internals/shared_flat_add_library.c
new file mode 100644
index 0000000..f03480f
--- /dev/null
+++ b/ap/build/uClibc/libc/misc/internals/shared_flat_add_library.c
@@ -0,0 +1,46 @@
+/*
+ * Copyright (C) 2006 CodeSourcery Inc
+ *
+ * Licensed under the LGPL v2.1, see the file COPYING.LIB in this tarball.
+ *
+ * This file defines __shared_flat_add_library. If a library has
+ * initialistion and finalisation code, it should use this routine
+ * to register itself.
+ */
+#include "shared_flat_lib.h"
+
+/* The initialisation and finalisation symbols for this library. */
+extern void _init(void) attribute_hidden weak_function;
+extern void _fini(void) attribute_hidden weak_function;
+extern void (*__preinit_array_start[])(void) attribute_hidden;
+extern void (*__preinit_array_end[])(void) attribute_hidden;
+extern void (*__init_array_start[])(void) attribute_hidden;
+extern void (*__init_array_end[])(void) attribute_hidden;
+extern void (*__fini_array_start[])(void) attribute_hidden;
+extern void (*__fini_array_end[])(void) attribute_hidden;
+
+/* The shared_flat_lib structure that describes this library. */
+static struct shared_flat_lib this_lib = {
+ 0,
+ 0,
+ __preinit_array_start,
+ __preinit_array_end,
+ __init_array_start,
+ __init_array_end,
+ __fini_array_start,
+ __fini_array_end,
+ _init,
+ _fini
+};
+
+/* Add this_lib to the end of the global list. */
+void __shared_flat_add_library(void) attribute_hidden;
+void __shared_flat_add_library(void)
+{
+ this_lib.prev = __last_shared_lib;
+ if (this_lib.prev)
+ this_lib.prev->next = &this_lib;
+ else
+ __first_shared_lib = &this_lib;
+ __last_shared_lib = &this_lib;
+}
diff --git a/ap/build/uClibc/libc/misc/internals/shared_flat_initfini.c b/ap/build/uClibc/libc/misc/internals/shared_flat_initfini.c
new file mode 100644
index 0000000..81e5383
--- /dev/null
+++ b/ap/build/uClibc/libc/misc/internals/shared_flat_initfini.c
@@ -0,0 +1,53 @@
+/*
+ * Copyright (C) 2006 CodeSourcery Inc
+ *
+ * Licensed under the LGPL v2.1, see the file COPYING.LIB in this tarball.
+ *
+ * This file defines the main initialisation and finalisation code for
+ * shared flat libraries. It in turn calls the initialisation and
+ * finalisation code for each registered library.
+ */
+#include "shared_flat_lib.h"
+
+/* A doubly-linked list of shared libraries. Those nearer the head
+ * of the list should be initialised first and finalised last. */
+struct shared_flat_lib *__first_shared_lib;
+struct shared_flat_lib *__last_shared_lib;
+
+void __shared_flat_init(void)
+{
+ struct shared_flat_lib *lib;
+ void (**start)(void);
+ void (**end)(void);
+
+ for (lib = __first_shared_lib; lib; lib = lib->next) {
+ end = lib->preinit_array_end;
+ for (start = lib->preinit_array_start; start < end; start++)
+ (*start)();
+ }
+
+ for (lib = __first_shared_lib; lib; lib = lib->next) {
+ if (lib->init)
+ lib->init();
+
+ end = lib->init_array_end;
+ for (start = lib->init_array_start; start < end; start++)
+ (*start)();
+ }
+}
+
+void __shared_flat_fini(void)
+{
+ struct shared_flat_lib *lib;
+ void (**start)(void);
+ void (**end)(void);
+
+ for (lib = __last_shared_lib; lib; lib = lib->prev) {
+ start = lib->fini_array_start;
+ for (end = lib->fini_array_end; end > start;)
+ (*--end)();
+
+ if (lib->fini)
+ lib->fini();
+ }
+}
diff --git a/ap/build/uClibc/libc/misc/internals/shared_flat_lib.h b/ap/build/uClibc/libc/misc/internals/shared_flat_lib.h
new file mode 100644
index 0000000..e012135
--- /dev/null
+++ b/ap/build/uClibc/libc/misc/internals/shared_flat_lib.h
@@ -0,0 +1,35 @@
+/*
+ * Copyright (C) 2006 CodeSourcery Inc
+ *
+ * Licensed under the LGPL v2.1, see the file COPYING.LIB in this tarball.
+ *
+ * This file defines the shared_flat_lib structure and the global library
+ * list. The structure is used to provide something close to ELF-like
+ * initialisation and finalisation when using shared flat libraries.
+ */
+#ifndef __SHARED_FLAT_LIB__
+#define __SHARED_FLAT_LIB__
+
+struct shared_flat_lib {
+ struct shared_flat_lib *prev;
+ struct shared_flat_lib *next;
+ /* .preinit_array is usually only supported for executables.
+ * However, the distinction between the executable and its
+ * shared libraries isn't as pronounced for flat files; a shared
+ * library is really just a part of an executable that can be
+ * shared with other executables. We therefore allow
+ * .preinit_array to be used in libraries too. */
+ void (**preinit_array_start)(void);
+ void (**preinit_array_end)(void);
+ void (**init_array_start)(void);
+ void (**init_array_end)(void);
+ void (**fini_array_start)(void);
+ void (**fini_array_end)(void);
+ void (*init)(void);
+ void (*fini)(void);
+};
+
+extern struct shared_flat_lib *__first_shared_lib;
+extern struct shared_flat_lib *__last_shared_lib;
+
+#endif
diff --git a/ap/build/uClibc/libc/misc/internals/tempname.c b/ap/build/uClibc/libc/misc/internals/tempname.c
new file mode 100644
index 0000000..28c0098
--- /dev/null
+++ b/ap/build/uClibc/libc/misc/internals/tempname.c
@@ -0,0 +1,252 @@
+/* Copyright (C) 1991,92,93,94,95,96,97,98,99 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 Library General Public License as
+ published by the Free Software Foundation; either version 2 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
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library 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. */
+
+/* March 11, 2002 Manuel Novoa III
+ *
+ * Modify code to remove dependency on libgcc long long arith support funcs.
+ */
+
+/* June 6, 2004 Erik Andersen
+ *
+ * Don't use brain damaged getpid() based randomness.
+ */
+
+/* April 15, 2005 Mike Frysinger
+ *
+ * Use brain damaged getpid() if real random fails.
+ */
+
+#include <stddef.h>
+#include <stdint.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <unistd.h>
+#include <assert.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <sys/time.h>
+#include "tempname.h"
+
+/* Return nonzero if DIR is an existent directory. */
+static int direxists (const char *dir)
+{
+ struct stat buf;
+ return stat(dir, &buf) == 0 && S_ISDIR (buf.st_mode);
+}
+
+/* Path search algorithm, for tmpnam, tmpfile, etc. If DIR is
+ non-null and exists, uses it; otherwise uses the first of $TMPDIR,
+ P_tmpdir, /tmp that exists. Copies into TMPL a template suitable
+ for use with mk[s]temp. Will fail (-1) if DIR is non-null and
+ doesn't exist, none of the searched dirs exists, or there's not
+ enough space in TMPL. */
+int attribute_hidden ___path_search (char *tmpl, size_t tmpl_len, const char *dir,
+ const char *pfx /*, int try_tmpdir*/)
+{
+ /*const char *d; */
+ /* dir and pfx lengths should always fit into an int,
+ so don't bother using size_t here. Especially since
+ the printf func requires an int for precision (%*s). */
+ int dlen, plen;
+
+ if (!pfx || !pfx[0])
+ {
+ pfx = "file";
+ plen = 4;
+ }
+ else
+ {
+ plen = strlen (pfx);
+ if (plen > 5)
+ plen = 5;
+ }
+
+ /* Disable support for $TMPDIR */
+#if 0
+ if (try_tmpdir)
+ {
+ d = __secure_getenv ("TMPDIR");
+ if (d != NULL && direxists (d))
+ dir = d;
+ else if (dir != NULL && direxists (dir))
+ /* nothing */ ;
+ else
+ dir = NULL;
+ }
+#endif
+ if (dir == NULL)
+ {
+ if (direxists (P_tmpdir))
+ dir = P_tmpdir;
+ else if (strcmp (P_tmpdir, "/tmp") != 0 && direxists ("/tmp"))
+ dir = "/tmp";
+ else
+ {
+ __set_errno (ENOENT);
+ return -1;
+ }
+ }
+
+ dlen = strlen (dir);
+ while (dlen > 1 && dir[dlen - 1] == '/')
+ dlen--; /* remove trailing slashes */
+
+ /* check we have room for "${dir}/${pfx}XXXXXX\0" */
+ if (tmpl_len < (size_t)dlen + 1 + plen + 6 + 1)
+ {
+ __set_errno (EINVAL);
+ return -1;
+ }
+
+ sprintf (tmpl, "%.*s/%.*sXXXXXX", dlen, dir, plen, pfx);
+ return 0;
+}
+
+/* These are the characters used in temporary filenames. */
+static const char letters[] =
+"abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789";
+#define NUM_LETTERS (62)
+
+static unsigned int fillrand(unsigned char *buf, unsigned int len)
+{
+ int fd;
+ unsigned int result = -1;
+ fd = open("/dev/urandom", O_RDONLY);
+ if (fd < 0) {
+ fd = open("/dev/random", O_RDONLY | O_NONBLOCK);
+ }
+ if (fd >= 0) {
+ result = read(fd, buf, len);
+ close(fd);
+ }
+ return result;
+}
+
+static void brain_damaged_fillrand(unsigned char *buf, unsigned int len)
+{
+ unsigned int i, k;
+ struct timeval tv;
+ uint32_t high, low, rh;
+ static uint64_t value;
+ gettimeofday(&tv, NULL);
+ value += ((uint64_t) tv.tv_usec << 16) ^ tv.tv_sec ^ getpid();
+ low = value & UINT32_MAX;
+ high = value >> 32;
+ for (i = 0; i < len; ++i) {
+ rh = high % NUM_LETTERS;
+ high /= NUM_LETTERS;
+#define L ((UINT32_MAX % NUM_LETTERS + 1) % NUM_LETTERS)
+ k = (low % NUM_LETTERS) + (L * rh);
+#undef L
+#define H ((UINT32_MAX / NUM_LETTERS) + ((UINT32_MAX % NUM_LETTERS + 1) / NUM_LETTERS))
+ low = (low / NUM_LETTERS) + (H * rh) + (k / NUM_LETTERS);
+#undef H
+ k %= NUM_LETTERS;
+ buf[i] = letters[k];
+ }
+}
+
+/* Generate a temporary file name based on TMPL. TMPL must match the
+ rules for mk[s]temp (i.e. end in "XXXXXX"). The name constructed
+ does not exist at the time of the call to __gen_tempname. TMPL is
+ overwritten with the result.
+
+ KIND may be one of:
+ __GT_NOCREATE: simply verify that the name does not exist
+ at the time of the call. mode argument is ignored.
+ __GT_FILE: create the file using open(O_CREAT|O_EXCL)
+ and return a read-write fd with given mode.
+ __GT_BIGFILE: same as __GT_FILE but use open64().
+ __GT_DIR: create a directory with given mode.
+
+*/
+int attribute_hidden __gen_tempname (char *tmpl, int kind, mode_t mode)
+{
+ char *XXXXXX;
+ unsigned int i;
+ int fd, save_errno = errno;
+ unsigned char randomness[6];
+ size_t len;
+
+ len = strlen (tmpl);
+ /* This is where the Xs start. */
+ XXXXXX = tmpl + len - 6;
+ if (len < 6 || strcmp (XXXXXX, "XXXXXX"))
+ {
+ __set_errno (EINVAL);
+ return -1;
+ }
+
+ for (i = 0; i < TMP_MAX; ++i) {
+ unsigned char j;
+ /* Get some random data. */
+ if (fillrand(randomness, sizeof(randomness)) != sizeof(randomness)) {
+ /* if random device nodes failed us, lets use the braindamaged ver */
+ brain_damaged_fillrand(randomness, sizeof(randomness));
+ }
+ for (j = 0; j < sizeof(randomness); ++j)
+ XXXXXX[j] = letters[randomness[j] % NUM_LETTERS];
+
+ switch (kind) {
+ case __GT_NOCREATE:
+ {
+ struct stat st;
+ if (stat (tmpl, &st) < 0) {
+ if (errno == ENOENT) {
+ fd = 0;
+ goto restore_and_ret;
+ } else
+ /* Give up now. */
+ return -1;
+ } else
+ fd = 0;
+ }
+ case __GT_FILE:
+ fd = open (tmpl, O_RDWR | O_CREAT | O_EXCL, mode);
+ break;
+#if defined __UCLIBC_HAS_LFS__
+ case __GT_BIGFILE:
+ fd = open64 (tmpl, O_RDWR | O_CREAT | O_EXCL, mode);
+ break;
+#endif
+ case __GT_DIR:
+ fd = mkdir (tmpl, mode);
+ break;
+ default:
+ fd = -1;
+ assert (! "invalid KIND in __gen_tempname");
+ }
+
+ if (fd >= 0) {
+restore_and_ret:
+ __set_errno (save_errno);
+ return fd;
+ }
+ else if (errno != EEXIST)
+ /* Any other error will apply also to other names we might
+ try, and there are 2^32 or so of them, so give up now. */
+ return -1;
+ }
+
+ /* We got out of the loop because we ran out of combinations to try. */
+ __set_errno (EEXIST);
+ return -1;
+}
diff --git a/ap/build/uClibc/libc/misc/internals/tempname.h b/ap/build/uClibc/libc/misc/internals/tempname.h
new file mode 100644
index 0000000..e75b632
--- /dev/null
+++ b/ap/build/uClibc/libc/misc/internals/tempname.h
@@ -0,0 +1,21 @@
+#ifndef __TEMPNAME_H__
+#define __TEMPNAME_H__
+
+#define __need_size_t
+#include <stddef.h>
+#include <sys/types.h>
+
+/* Disable support for $TMPDIR */
+extern int ___path_search (char *tmpl, size_t tmpl_len, const char *dir,
+ const char *pfx /*, int try_tmpdir */) attribute_hidden;
+#define __path_search(tmpl, tmpl_len, dir, pfx, try_tmpdir) ___path_search(tmpl, tmpl_len, dir, pfx)
+
+extern int __gen_tempname (char *__tmpl, int __kind, mode_t mode) attribute_hidden;
+
+/* The __kind argument to __gen_tempname may be one of: */
+#define __GT_FILE 0 /* create a file */
+#define __GT_BIGFILE 1 /* create a file, using open64 */
+#define __GT_DIR 2 /* create a directory */
+#define __GT_NOCREATE 3 /* just find a name not currently in use */
+
+#endif
diff --git a/ap/build/uClibc/libc/misc/locale/Makefile b/ap/build/uClibc/libc/misc/locale/Makefile
new file mode 100644
index 0000000..4a8f4a0
--- /dev/null
+++ b/ap/build/uClibc/libc/misc/locale/Makefile
@@ -0,0 +1,13 @@
+# Makefile for uClibc
+#
+# Copyright (C) 2000-2005 Erik Andersen <andersen@uclibc.org>
+#
+# Licensed under the LGPL v2.1, see the file COPYING.LIB in this tarball.
+#
+
+top_srcdir=../../../
+top_builddir=../../../
+all: objs
+include $(top_builddir)Rules.mak
+include Makefile.in
+include $(top_srcdir)Makerules
diff --git a/ap/build/uClibc/libc/misc/locale/Makefile.in b/ap/build/uClibc/libc/misc/locale/Makefile.in
new file mode 100644
index 0000000..c12befd
--- /dev/null
+++ b/ap/build/uClibc/libc/misc/locale/Makefile.in
@@ -0,0 +1,30 @@
+# Makefile for uClibc
+#
+# Copyright (C) 2000-2008 Erik Andersen <andersen@uclibc.org>
+#
+# Licensed under the LGPL v2.1, see the file COPYING.LIB in this tarball.
+#
+
+subdirs += libc/misc/locale
+
+# multi source locale.c
+CSRC := setlocale.c localeconv.c _locale_init.c nl_langinfo.c
+ifeq ($(UCLIBC_HAS_LOCALE),y)
+CSRC += newlocale.c __locale_mbrtowc_l.c
+endif
+ifeq ($(UCLIBC_HAS_XLOCALE),y)
+CSRC += nl_langinfo_l.c duplocale.c freelocale.c uselocale.c __curlocale.c
+endif
+
+MISC_LOCALE_DIR := $(top_srcdir)libc/misc/locale
+MISC_LOCALE_OUT := $(top_builddir)libc/misc/locale
+
+MISC_LOCALE_SRC := $(patsubst %.c,$(MISC_LOCALE_DIR)/%.c,$(CSRC))
+MISC_LOCALE_OBJ := $(patsubst %.c,$(MISC_LOCALE_OUT)/%.o,$(CSRC))
+
+libc-y += $(MISC_LOCALE_OBJ)
+
+objclean-y += CLEAN_libc/misc/locale
+
+CLEAN_libc/misc/locale:
+ $(do_rm) $(addprefix $(MISC_LOCALE_OUT)/*., o os)
diff --git a/ap/build/uClibc/libc/misc/locale/__curlocale.c b/ap/build/uClibc/libc/misc/locale/__curlocale.c
new file mode 100644
index 0000000..aa38f43
--- /dev/null
+++ b/ap/build/uClibc/libc/misc/locale/__curlocale.c
@@ -0,0 +1,9 @@
+/*
+ * Copyright (C) 2004-2006 Manuel Novoa III <mjn3@uclibc.org>
+ *
+ * Licensed under the LGPL v2.1, see the file COPYING.LIB in this tarball.
+ */
+
+#define L___curlocale
+#define __UCLIBC_DO_XLOCALE
+#include "locale.c"
diff --git a/ap/build/uClibc/libc/misc/locale/__locale_mbrtowc_l.c b/ap/build/uClibc/libc/misc/locale/__locale_mbrtowc_l.c
new file mode 100644
index 0000000..ea7fbce
--- /dev/null
+++ b/ap/build/uClibc/libc/misc/locale/__locale_mbrtowc_l.c
@@ -0,0 +1,8 @@
+/*
+ * Copyright (C) 2004-2006 Manuel Novoa III <mjn3@uclibc.org>
+ *
+ * Licensed under the LGPL v2.1, see the file COPYING.LIB in this tarball.
+ */
+
+#define L___locale_mbrtowc_l
+#include "locale.c"
diff --git a/ap/build/uClibc/libc/misc/locale/_locale_init.c b/ap/build/uClibc/libc/misc/locale/_locale_init.c
new file mode 100644
index 0000000..9ced732
--- /dev/null
+++ b/ap/build/uClibc/libc/misc/locale/_locale_init.c
@@ -0,0 +1,8 @@
+/*
+ * Copyright (C) 2004-2006 Manuel Novoa III <mjn3@uclibc.org>
+ *
+ * Licensed under the LGPL v2.1, see the file COPYING.LIB in this tarball.
+ */
+
+#define L__locale_init
+#include "locale.c"
diff --git a/ap/build/uClibc/libc/misc/locale/duplocale.c b/ap/build/uClibc/libc/misc/locale/duplocale.c
new file mode 100644
index 0000000..db9c7a3
--- /dev/null
+++ b/ap/build/uClibc/libc/misc/locale/duplocale.c
@@ -0,0 +1,9 @@
+/*
+ * Copyright (C) 2004-2006 Manuel Novoa III <mjn3@uclibc.org>
+ *
+ * Licensed under the LGPL v2.1, see the file COPYING.LIB in this tarball.
+ */
+
+#define L_duplocale
+#define __UCLIBC_DO_XLOCALE
+#include "locale.c"
diff --git a/ap/build/uClibc/libc/misc/locale/freelocale.c b/ap/build/uClibc/libc/misc/locale/freelocale.c
new file mode 100644
index 0000000..c1ef8e1
--- /dev/null
+++ b/ap/build/uClibc/libc/misc/locale/freelocale.c
@@ -0,0 +1,9 @@
+/*
+ * Copyright (C) 2004-2006 Manuel Novoa III <mjn3@uclibc.org>
+ *
+ * Licensed under the LGPL v2.1, see the file COPYING.LIB in this tarball.
+ */
+
+#define L_freelocale
+#define __UCLIBC_DO_XLOCALE
+#include "locale.c"
diff --git a/ap/build/uClibc/libc/misc/locale/locale.c b/ap/build/uClibc/libc/misc/locale/locale.c
new file mode 100644
index 0000000..e8fddf6
--- /dev/null
+++ b/ap/build/uClibc/libc/misc/locale/locale.c
@@ -0,0 +1,1476 @@
+/* Copyright (C) 2002 Manuel Novoa III
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 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
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the Free
+ * Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+/* Nov. 1, 2002
+ * Reworked setlocale() return values and locale arg processing to
+ * be more like glibc. Applications expecting to be able to
+ * query locale settings should now work... at the cost of almost
+ * doubling the size of the setlocale object code.
+ * Fixed a bug in the internal fixed-size-string locale specifier code.
+ *
+ * Dec 20, 2002
+ * Added in collation support and updated stub nl_langinfo.
+ *
+ * Aug 1, 2003
+ * Added glibc-like extended locale stuff (newlocale, duplocale, etc).
+ *
+ * Aug 18, 2003
+ * Bug in duplocale... collation data wasn't copied.
+ * Bug in newlocale... translate 1<<LC_ALL to LC_ALL_MASK.
+ * Bug in _wchar_utf8sntowcs... fix cut-n-paste error.
+ *
+ * Aug 31, 2003
+ * Hack around bg_BG bug; grouping specified but no thousands separator.
+ * Also, disable the locale link_warnings for now, as they generate a
+ * lot of noise when using libstd++.
+ */
+
+
+/* TODO:
+ * Implement the shared mmap code so non-mmu platforms can use this.
+ * Add some basic collate functionality similar to what the previous
+ * locale support had (8-bit codesets only).
+ */
+
+#define __CTYPE_HAS_8_BIT_LOCALES 1
+
+#include <string.h>
+#include <stdlib.h>
+#include <stddef.h>
+#include <limits.h>
+#include <stdint.h>
+#include <assert.h>
+#include <errno.h>
+#include <ctype.h>
+#include <stdio.h>
+
+#ifdef __UCLIBC_MJN3_ONLY__
+#ifdef L_setlocale
+#warning TODO: Make the link_warning()s a config option?
+#endif
+#endif
+#undef link_warning
+#define link_warning(A,B)
+
+#undef __LOCALE_C_ONLY
+#ifndef __UCLIBC_HAS_LOCALE__
+#define __LOCALE_C_ONLY
+#endif /* __UCLIBC_HAS_LOCALE__ */
+
+
+#ifdef __LOCALE_C_ONLY
+
+#include <locale.h>
+
+#else /* __LOCALE_C_ONLY */
+
+#ifdef __UCLIBC_MJN3_ONLY__
+#ifdef L_setlocale
+#warning TODO: Fix the __CTYPE_HAS_8_BIT_LOCALES define at the top of the file.
+#warning TODO: Fix __WCHAR_ENABLED.
+#endif
+#endif
+
+/* Need to include this before locale.h and xlocale.h! */
+#include <bits/uClibc_locale.h>
+
+#undef CODESET_LIST
+#define CODESET_LIST (__locale_mmap->codeset_list)
+
+#ifdef __UCLIBC_HAS_XLOCALE__
+#include <xlocale.h>
+#include <locale.h>
+#else /* __UCLIBC_HAS_XLOCALE__ */
+/* We need this internally... */
+#define __UCLIBC_HAS_XLOCALE__ 1
+#include <xlocale.h>
+#include <locale.h>
+#undef __UCLIBC_HAS_XLOCALE__
+#endif /* __UCLIBC_HAS_XLOCALE__ */
+
+#include <wchar.h>
+
+#define LOCALE_NAMES (__locale_mmap->locale_names5)
+#define LOCALES (__locale_mmap->locales)
+#define LOCALE_AT_MODIFIERS (__locale_mmap->locale_at_modifiers)
+#define CATEGORY_NAMES (__locale_mmap->lc_names)
+
+#ifdef __UCLIBC_MJN3_ONLY__
+#warning REMINDER: redo the MAX_LOCALE_STR stuff...
+#endif
+#define MAX_LOCALE_STR 256 /* TODO: Only sufficient for current case. */
+#define MAX_LOCALE_CATEGORY_STR 32 /* TODO: Only sufficient for current case. */
+/* Note: Best if MAX_LOCALE_CATEGORY_STR is a power of 2. */
+
+extern int _locale_set_l(const unsigned char *p, __locale_t base) attribute_hidden;
+extern void _locale_init_l(__locale_t base) attribute_hidden;
+
+#endif /* __LOCALE_C_ONLY */
+
+#undef LOCALE_STRING_SIZE
+#define LOCALE_SELECTOR_SIZE (2 * __LC_ALL + 2)
+
+#ifdef __UCLIBC_MJN3_ONLY__
+#ifdef L_setlocale
+#warning TODO: Create a C locale selector string.
+#endif
+#endif
+#define C_LOCALE_SELECTOR "\x23\x80\x80\x80\x80\x80\x80\x80\x80\x80\x80\x80\x80"
+
+
+#include <langinfo.h>
+#include <nl_types.h>
+
+/**********************************************************************/
+#ifdef L_setlocale
+
+#ifdef __LOCALE_C_ONLY
+
+link_warning(setlocale,"REMINDER: The 'setlocale' function supports only C|POSIX locales.")
+
+static const char C_string[] = "C";
+
+char *setlocale(int category, register const char *locale)
+{
+ return ( (((unsigned int)(category)) <= LC_ALL)
+ && ( (!locale) /* Request for locale category string. */
+ || (!*locale) /* Implementation-defined default is C. */
+ || ((*locale == 'C') && !locale[1])
+ || (!strcmp(locale, "POSIX"))) )
+ ? (char *) C_string /* Always in C/POSIX locale. */
+ : NULL;
+}
+
+#else /* ---------------------------------------------- __LOCALE_C_ONLY */
+
+#ifdef __UCLIBC_HAS_THREADS__
+link_warning(setlocale,"REMINDER: The 'setlocale' function is _not_ threadsafe except for simple queries.")
+#endif
+
+#if !defined(__LOCALE_DATA_NUM_LOCALES) || (__LOCALE_DATA_NUM_LOCALES <= 1)
+#error locales enabled, but not data other than for C locale!
+#endif
+
+#ifdef __UCLIBC_MJN3_ONLY__
+#warning TODO: Move posix and utf8 strings.
+#endif
+static const char posix[] = "POSIX";
+static const char utf8[] = "UTF-8";
+
+#ifdef __UCLIBC_MJN3_ONLY__
+#warning TODO: Fix dimensions of hr_locale.
+#endif
+/* Individual category strings start at hr_locale + category * MAX_LOCALE_CATEGORY.
+ * This holds for LC_ALL as well.
+ */
+static char hr_locale[(MAX_LOCALE_CATEGORY_STR * LC_ALL) + MAX_LOCALE_STR];
+
+
+static void update_hr_locale(const unsigned char *spec)
+{
+ const unsigned char *loc;
+ const unsigned char *s;
+ char *n;
+ int i, category, done;
+
+ done = category = 0;
+ do {
+ s = spec + 1;
+ n = hr_locale + category * MAX_LOCALE_CATEGORY_STR;
+
+ if (category == LC_ALL) {
+ done = 1;
+ for (i = 0 ; i < LC_ALL-1 ; i += 2) {
+ if ((s[i] != s[i+2]) || (s[i+1] != s[i+3])) {
+ goto SKIP;
+ }
+ }
+ /* All categories the same, so simplify string by using a single
+ * category. */
+ category = LC_CTYPE;
+ }
+
+ SKIP:
+ i = (category == LC_ALL) ? 0 : category;
+ s += 2*i;
+
+ do {
+ if ((*s != 0xff) || (s[1] != 0xff)) {
+ loc = LOCALES
+ + __LOCALE_DATA_WIDTH_LOCALES * ((((int)(*s & 0x7f)) << 7)
+ + (s[1] & 0x7f));
+ if (category == LC_ALL) {
+ /* CATEGORY_NAMES is unsigned char* */
+ n = stpcpy(n, (char*) CATEGORY_NAMES + (int) CATEGORY_NAMES[i]);
+ *n++ = '=';
+ }
+ if (*loc == 0) {
+ *n++ = 'C';
+ *n = 0;
+ } else {
+ char at = 0;
+ memcpy(n, LOCALE_NAMES + 5*((*loc)-1), 5);
+ if (n[2] != '_') {
+ at = n[2];
+ n[2] = '_';
+ }
+ n += 5;
+ *n++ = '.';
+ if (loc[2] == 2) {
+ n = stpcpy(n, utf8);
+ } else if (loc[2] >= 3) {
+ n = stpcpy(n, (char*) CODESET_LIST + (int)(CODESET_LIST[loc[2] - 3]));
+ }
+ if (at) {
+ const char *q;
+ *n++ = '@';
+ q = (char*) LOCALE_AT_MODIFIERS;
+ do {
+ if (q[1] == at) {
+ n = stpcpy(n, q+2);
+ break;
+ }
+ q += 2 + *q;
+ } while (*q);
+ }
+ }
+ *n++ = ';';
+ }
+ s += 2;
+ } while (++i < category);
+ *--n = 0; /* Remove trailing ';' and nul-terminate. */
+
+ ++category;
+ } while (!done);
+}
+
+char *setlocale(int category, const char *locale)
+{
+ if (((unsigned int)(category)) > LC_ALL) {
+#if 0
+ __set_errno(EINVAL); /* glibc sets errno -- SUSv3 doesn't say. */
+#endif
+ return NULL; /* Illegal/unsupported category. */
+ }
+
+ if (locale != NULL) { /* Not just a query... */
+ if (!newlocale((1 << category), locale, __global_locale)) {
+ return NULL; /* Failed! */
+ }
+ update_hr_locale(__global_locale->cur_locale);
+ }
+
+ /* Either a query or a successful set, so return current locale string. */
+ return hr_locale + (category * MAX_LOCALE_CATEGORY_STR);
+}
+
+#endif /* __LOCALE_C_ONLY */
+
+#endif
+/**********************************************************************/
+#ifdef L_localeconv
+
+/* Note: We assume here that the compiler does the sane thing regarding
+ * placement of the fields in the struct. If necessary, we could ensure
+ * this usings an array of offsets but at some size cost. */
+
+
+#ifdef __LOCALE_C_ONLY
+
+link_warning(localeconv,"REMINDER: The 'localeconv' function is hardwired for C/POSIX locale only.")
+
+static struct lconv the_lconv;
+
+static const char decpt[] = ".";
+
+struct lconv *localeconv(void)
+{
+ register char *p = (char *)(&the_lconv);
+
+ *((char **)p) = (char *) decpt;
+ do {
+ p += sizeof(char **);
+ *((char **)p) = (char *) (decpt+1);
+ } while (p < (char *) &the_lconv.negative_sign);
+
+ p = (&the_lconv.int_frac_digits);
+ do {
+ *p = CHAR_MAX;
+ ++p;
+ } while (p <= &the_lconv.int_n_sign_posn);
+
+ return &the_lconv;
+}
+
+#else /* __LOCALE_C_ONLY */
+
+static struct lconv the_lconv;
+
+struct lconv *localeconv(void)
+{
+ register char *p = (char *) &the_lconv;
+ register char **q = (char **) &(__UCLIBC_CURLOCALE->decimal_point);
+
+ do {
+ *((char **)p) = *q;
+ p += sizeof(char **);
+ ++q;
+ } while (p < &the_lconv.int_frac_digits);
+
+ do {
+ *p = **q;
+ ++p;
+ ++q;
+ } while (p <= &the_lconv.int_n_sign_posn);
+
+ return &the_lconv;
+}
+
+#endif /* __LOCALE_C_ONLY */
+
+libc_hidden_def(localeconv)
+
+#endif
+/**********************************************************************/
+#if defined(L__locale_init) && !defined(__LOCALE_C_ONLY)
+
+struct __uclibc_locale_struct __global_locale_data;
+
+__locale_t __global_locale = &__global_locale_data;
+
+#ifdef __UCLIBC_HAS_XLOCALE__
+__locale_t __curlocale_var = &__global_locale_data;
+#endif
+
+/*----------------------------------------------------------------------*/
+#ifdef __UCLIBC_MJN3_ONLY__
+#warning TODO: Move utf8 and ascii strings.
+#endif
+static const char utf8[] = "UTF-8";
+static const char ascii[] = "ASCII";
+
+typedef struct {
+ uint16_t num_base;
+ uint16_t num_der;
+ uint16_t MAX_WEIGHTS;
+ uint16_t num_index2weight;
+#define num_index2ruleidx num_index2weight
+ uint16_t num_weightstr;
+ uint16_t num_multistart;
+ uint16_t num_override;
+ uint16_t num_ruletable;
+} coldata_header_t;
+
+typedef struct {
+ uint16_t num_weights;
+ uint16_t num_starters;
+ uint16_t ii_shift;
+ uint16_t ti_shift;
+ uint16_t ii_len;
+ uint16_t ti_len;
+ uint16_t max_weight;
+ uint16_t num_col_base;
+ uint16_t max_col_index;
+ uint16_t undefined_idx;
+ uint16_t range_low;
+ uint16_t range_count;
+ uint16_t range_base_weight;
+ uint16_t range_rule_offset;
+
+ uint16_t index2weight_offset;
+ uint16_t index2ruleidx_offset;
+ uint16_t multistart_offset;
+ uint16_t wcs2colidt_offset_low;
+ uint16_t wcs2colidt_offset_hi;
+} coldata_base_t;
+
+typedef struct {
+ uint16_t base_idx;
+ uint16_t undefined_idx;
+ uint16_t overrides_offset;
+ uint16_t multistart_offset;
+} coldata_der_t;
+
+static int init_cur_collate(int der_num, __collate_t *cur_collate)
+{
+ const uint16_t *__locale_collate_tbl = __locale_mmap->collate_data;
+ coldata_header_t *cdh;
+ coldata_base_t *cdb;
+ coldata_der_t *cdd;
+ const uint16_t *p;
+ size_t n;
+ uint16_t i, w;
+
+#ifdef __UCLIBC_MJN3_ONLY__
+#warning kill of x86-specific asserts
+#endif
+#if 0
+ assert(sizeof(coldata_base_t) == 19*2);
+ assert(sizeof(coldata_der_t) == 4*2);
+ assert(sizeof(coldata_header_t) == 8*2);
+#endif
+
+ if (!der_num) { /* C locale... special */
+ cur_collate->num_weights = 0;
+ return 1;
+ }
+
+ --der_num;
+
+ cdh = (coldata_header_t *) __locale_collate_tbl;
+
+#ifdef __UCLIBC_MJN3_ONLY__
+#warning CONSIDER: Should we assert here?
+#endif
+#if 0
+ if (der_num >= cdh->num_der) {
+ return 0;
+ }
+#else
+ assert((der_num < cdh->num_der));
+#endif
+
+ cdd = (coldata_der_t *)(__locale_collate_tbl
+ + (sizeof(coldata_header_t)
+ + cdh->num_base * sizeof(coldata_base_t)
+ + der_num * sizeof(coldata_der_t)
+ )/2 );
+
+ cdb = (coldata_base_t *)(__locale_collate_tbl
+ + (sizeof(coldata_header_t)
+ + cdd->base_idx * sizeof(coldata_base_t)
+ )/2 );
+
+ memcpy(cur_collate, cdb, offsetof(coldata_base_t,index2weight_offset));
+ cur_collate->undefined_idx = cdd->undefined_idx;
+
+ cur_collate->ti_mask = (1 << cur_collate->ti_shift)-1;
+ cur_collate->ii_mask = (1 << cur_collate->ii_shift)-1;
+
+/* fflush(stdout); */
+/* fprintf(stderr,"base=%d num_col_base: %d %d\n", cdd->base_idx ,cur_collate->num_col_base, cdb->num_col_base); */
+
+ n = (sizeof(coldata_header_t) + cdh->num_base * sizeof(coldata_base_t)
+ + cdh->num_der * sizeof(coldata_der_t))/2;
+
+/* fprintf(stderr,"n = %d\n", n); */
+ cur_collate->index2weight_tbl = __locale_collate_tbl + n + cdb->index2weight_offset;
+/* fprintf(stderr,"i2w = %d\n", n + cdb->index2weight_offset); */
+ n += cdh->num_index2weight;
+ cur_collate->index2ruleidx_tbl = __locale_collate_tbl + n + cdb->index2ruleidx_offset;
+/* fprintf(stderr,"i2r = %d\n", n + cdb->index2ruleidx_offset); */
+ n += cdh->num_index2ruleidx;
+ cur_collate->multistart_tbl = __locale_collate_tbl + n + cdd->multistart_offset;
+/* fprintf(stderr,"mts = %d\n", n + cdb->multistart_offset); */
+ n += cdh->num_multistart;
+ cur_collate->overrides_tbl = __locale_collate_tbl + n + cdd->overrides_offset;
+/* fprintf(stderr,"ovr = %d\n", n + cdd->overrides_offset); */
+ n += cdh->num_override;
+ cur_collate->ruletable = __locale_collate_tbl + n;
+/* fprintf(stderr, "rtb = %d\n", n); */
+ n += cdh->num_ruletable;
+ cur_collate->weightstr = __locale_collate_tbl + n;
+/* fprintf(stderr,"wts = %d\n", n); */
+ n += cdh->num_weightstr;
+ cur_collate->wcs2colidt_tbl = __locale_collate_tbl + n
+ + (((unsigned long)(cdb->wcs2colidt_offset_hi)) << 16)
+ + cdb->wcs2colidt_offset_low;
+/* fprintf(stderr,"wcs = %lu\n", n + (((unsigned long)(cdb->wcs2colidt_offset_hi)) << 16) */
+/* + cdb->wcs2colidt_offset_low); */
+
+ cur_collate->MAX_WEIGHTS = cdh->MAX_WEIGHTS;
+
+#ifdef __UCLIBC_MJN3_ONLY__
+#warning CONSIDER: Fix the +1 by increasing max_col_index?
+#warning CONSIDER: Since this collate info is dependent only on LC_COLLATE ll_cc and not on codeset, we could just globally allocate this for each in a table
+#endif
+
+ cur_collate->index2weight = calloc(2*cur_collate->max_col_index+2,
+ sizeof(uint16_t));
+ if (!cur_collate->index2weight) {
+ return 0;
+ }
+ cur_collate->index2ruleidx = cur_collate->index2weight
+ + cur_collate->max_col_index + 1;
+
+ memcpy(cur_collate->index2weight, cur_collate->index2weight_tbl,
+ cur_collate->num_col_base * sizeof(uint16_t));
+ memcpy(cur_collate->index2ruleidx, cur_collate->index2ruleidx_tbl,
+ cur_collate->num_col_base * sizeof(uint16_t));
+
+ /* now do the overrides */
+ p = cur_collate->overrides_tbl;
+ while (*p > 1) {
+/* fprintf(stderr, "processing override -- count = %d\n", *p); */
+ n = *p++;
+ w = *p++;
+ do {
+ i = *p++;
+/* fprintf(stderr, " i=%d (%#x) w=%d *p=%d\n", i, i, w, *p); */
+ cur_collate->index2weight[i-1] = w++;
+ cur_collate->index2ruleidx[i-1] = *p++;
+ } while (--n);
+ }
+ assert(*p == 1);
+ while (*++p) {
+ i = *p;
+/* fprintf(stderr, " i=%d (%#x) w=%d *p=%d\n", i, i, p[1], p[2]); */
+ cur_collate->index2weight[i-1] = *++p;
+ cur_collate->index2ruleidx[i-1] = *++p;
+ }
+
+
+ for (i=0 ; i < cur_collate->multistart_tbl[0] ; i++) {
+ p = cur_collate->multistart_tbl;
+/* fprintf(stderr, "%2d of %2d: %d ", i, cur_collate->multistart_tbl[0], p[i]); */
+ p += p[i];
+
+ do {
+ n = *p++;
+ do {
+ if (!*p) { /* found it */
+/* fprintf(stderr, "found: n=%d (%#lx) |%.*ls|\n", n, (int) *cs->s, n, cs->s); */
+/* fprintf(stderr, ": %d - single\n", n); */
+ goto FOUND;
+ }
+ /* the lookup check here is safe since we're assured that *p is a valid colidex */
+/* fprintf(stderr, "lookup(%lc)==%d *p==%d\n", cs->s[n], lookup(cs->s[n]), (int) *p); */
+/* fprintf(stderr, ": %d - ", n); */
+ do {
+/* fprintf(stderr, "%d|", *p); */
+ } while (*p++);
+ break;
+ } while (1);
+ } while (1);
+ FOUND:
+ continue;
+ }
+
+ return 1;
+}
+
+int attribute_hidden _locale_set_l(const unsigned char *p, __locale_t base)
+{
+ const char **x;
+ unsigned char *s = base->cur_locale + 1;
+ const size_t *stp;
+ const unsigned char *r;
+ const uint16_t *io;
+ const uint16_t *ii;
+ const unsigned char *d;
+ int row; /* locale row */
+ int crow; /* category row */
+ int len;
+ int c;
+ int i = 0;
+ __collate_t newcol;
+
+ ++p;
+
+ newcol.index2weight = NULL;
+ if ((p[2*LC_COLLATE] != s[2*LC_COLLATE])
+ || (p[2*LC_COLLATE + 1] != s[2*LC_COLLATE + 1])
+ ) {
+ row = (((int)(*p & 0x7f)) << 7) + (p[1] & 0x7f);
+ assert(row < __LOCALE_DATA_NUM_LOCALES);
+ if (!init_cur_collate(__locale_mmap->locales[ __LOCALE_DATA_WIDTH_LOCALES
+ * row + 3 + LC_COLLATE ],
+ &newcol)
+ ) {
+ return 0; /* calloc failed. */
+ }
+ free(base->collate.index2weight);
+ memcpy(&base->collate, &newcol, sizeof(__collate_t));
+ }
+
+ do {
+ if ((*p != *s) || (p[1] != s[1])) {
+ row = (((int)(*p & 0x7f)) << 7) + (p[1] & 0x7f);
+ assert(row < __LOCALE_DATA_NUM_LOCALES);
+
+ *s = *p;
+ s[1] = p[1];
+
+ if ((i != LC_COLLATE)
+ && ((len = __locale_mmap->lc_common_item_offsets_LEN[i]) != 0)
+ ) {
+ crow = __locale_mmap->locales[ __LOCALE_DATA_WIDTH_LOCALES * row
+ + 3 + i ]
+ * len;
+
+ x = (const char **)(((char *) base)
+ + base->category_offsets[i]);
+
+ stp = __locale_mmap->lc_common_tbl_offsets + 4*i;
+ r = (const unsigned char *)( ((char *)__locale_mmap) + *stp );
+ io = (const uint16_t *)( ((char *)__locale_mmap) + *++stp );
+ ii = (const uint16_t *)( ((char *)__locale_mmap) + *++stp );
+ d = (const unsigned char *)( ((char *)__locale_mmap) + *++stp );
+ for (c = 0; c < len; c++) {
+ x[c] = (char*)(d + ii[r[crow + c] + io[c]]);
+ }
+ }
+ if (i == LC_CTYPE) {
+ c = __locale_mmap->locales[ __LOCALE_DATA_WIDTH_LOCALES * row
+ + 2 ]; /* codeset */
+ if (c <= 2) {
+ if (c == 2) {
+ base->codeset = utf8;
+ base->encoding = __ctype_encoding_utf8;
+ /* TODO - fix for bcc */
+ base->mb_cur_max = 6;
+ } else {
+ assert(c == 1);
+ base->codeset = ascii;
+ base->encoding = __ctype_encoding_7_bit;
+ base->mb_cur_max = 1;
+ }
+ } else {
+ const __codeset_8_bit_t *c8b;
+ r = CODESET_LIST;
+ c -= 3;
+ base->codeset = (char *) (r + r[c]);
+ base->encoding = __ctype_encoding_8_bit;
+#ifdef __UCLIBC_MJN3_ONLY__
+#warning REMINDER: update 8 bit mb_cur_max when translit implemented!
+#endif
+ /* TODO - update when translit implemented! */
+ base->mb_cur_max = 1;
+ c8b = __locale_mmap->codeset_8_bit + c;
+#ifdef __CTYPE_HAS_8_BIT_LOCALES
+ base->idx8ctype = c8b->idx8ctype;
+ base->idx8uplow = c8b->idx8uplow;
+#ifdef __UCLIBC_HAS_WCHAR__
+ base->idx8c2wc = c8b->idx8c2wc;
+ base->idx8wc2c = c8b->idx8wc2c;
+ /* translit */
+#endif /* __UCLIBC_HAS_WCHAR__ */
+
+ /* What follows is fairly bloated, but it is just a hack
+ * to get the 8-bit codeset ctype stuff functioning.
+ * All of this will be replaced in the next generation
+ * of locale support anyway... */
+
+ memcpy(base->__ctype_b_data,
+ __C_ctype_b - __UCLIBC_CTYPE_B_TBL_OFFSET,
+ (256 + __UCLIBC_CTYPE_B_TBL_OFFSET)
+ * sizeof(__ctype_mask_t));
+ memcpy(base->__ctype_tolower_data,
+ __C_ctype_tolower - __UCLIBC_CTYPE_TO_TBL_OFFSET,
+ (256 + __UCLIBC_CTYPE_TO_TBL_OFFSET)
+ * sizeof(__ctype_touplow_t));
+ memcpy(base->__ctype_toupper_data,
+ __C_ctype_toupper - __UCLIBC_CTYPE_TO_TBL_OFFSET,
+ (256 + __UCLIBC_CTYPE_TO_TBL_OFFSET)
+ * sizeof(__ctype_touplow_t));
+
+#define Cctype_TBL_MASK ((1 << __LOCALE_DATA_Cctype_IDX_SHIFT) - 1)
+#define Cctype_IDX_OFFSET (128 >> __LOCALE_DATA_Cctype_IDX_SHIFT)
+
+ {
+ int u;
+ __ctype_mask_t m;
+
+ for (u=0 ; u < 128 ; u++) {
+#ifdef __LOCALE_DATA_Cctype_PACKED
+ c = base->tbl8ctype
+ [ ((int)(c8b->idx8ctype
+ [(u >> __LOCALE_DATA_Cctype_IDX_SHIFT) ])
+ << (__LOCALE_DATA_Cctype_IDX_SHIFT - 1))
+ + ((u & Cctype_TBL_MASK) >> 1)];
+ c = (u & 1) ? (c >> 4) : (c & 0xf);
+#else
+ c = base->tbl8ctype
+ [ ((int)(c8b->idx8ctype
+ [(u >> __LOCALE_DATA_Cctype_IDX_SHIFT) ])
+ << __LOCALE_DATA_Cctype_IDX_SHIFT)
+ + (u & Cctype_TBL_MASK) ];
+#endif
+
+ m = base->code2flag[c];
+
+ base->__ctype_b_data
+ [128 + __UCLIBC_CTYPE_B_TBL_OFFSET + u]
+ = m;
+
+#ifdef __UCLIBC_HAS_CTYPE_SIGNED__
+ if (((signed char)(128 + u)) != -1) {
+ base->__ctype_b_data[__UCLIBC_CTYPE_B_TBL_OFFSET
+ + ((signed char)(128 + u))]
+ = m;
+ }
+#endif
+
+ base->__ctype_tolower_data
+ [128 + __UCLIBC_CTYPE_TO_TBL_OFFSET + u]
+ = 128 + u;
+ base->__ctype_toupper_data
+ [128 + __UCLIBC_CTYPE_TO_TBL_OFFSET + u]
+ = 128 + u;
+
+ if (m & (_ISlower|_ISupper)) {
+ c = base->tbl8uplow
+ [ ((int)(c8b->idx8uplow
+ [u >> __LOCALE_DATA_Cuplow_IDX_SHIFT])
+ << __LOCALE_DATA_Cuplow_IDX_SHIFT)
+ + ((128 + u)
+ & ((1 << __LOCALE_DATA_Cuplow_IDX_SHIFT)
+ - 1)) ];
+ if (m & _ISlower) {
+ base->__ctype_toupper_data
+ [128 + __UCLIBC_CTYPE_TO_TBL_OFFSET + u]
+ = (unsigned char)(128 + u + c);
+#ifdef __UCLIBC_HAS_CTYPE_SIGNED__
+ if (((signed char)(128 + u)) != -1) {
+ base->__ctype_toupper_data
+ [__UCLIBC_CTYPE_TO_TBL_OFFSET
+ + ((signed char)(128 + u))]
+ = (unsigned char)(128 + u + c);
+ }
+#endif
+ } else {
+ base->__ctype_tolower_data
+ [128 + __UCLIBC_CTYPE_TO_TBL_OFFSET + u]
+ = (unsigned char)(128 + u - c);
+#ifdef __UCLIBC_HAS_CTYPE_SIGNED__
+ if (((signed char)(128 + u)) != -1) {
+ base->__ctype_tolower_data
+ [__UCLIBC_CTYPE_TO_TBL_OFFSET
+ + ((signed char)(128 + u))]
+ = (unsigned char)(128 + u - c);
+ }
+#endif
+ }
+ }
+ }
+ }
+
+#ifdef __UCLIBC_HAS_XLOCALE__
+ base->__ctype_b = base->__ctype_b_data
+ + __UCLIBC_CTYPE_B_TBL_OFFSET;
+ base->__ctype_tolower = base->__ctype_tolower_data
+ + __UCLIBC_CTYPE_TO_TBL_OFFSET;
+ base->__ctype_toupper = base->__ctype_toupper_data
+ + __UCLIBC_CTYPE_TO_TBL_OFFSET;
+#else /* __UCLIBC_HAS_XLOCALE__ */
+ __ctype_b = base->__ctype_b_data
+ + __UCLIBC_CTYPE_B_TBL_OFFSET;
+ __ctype_tolower = base->__ctype_tolower_data
+ + __UCLIBC_CTYPE_TO_TBL_OFFSET;
+ __ctype_toupper = base->__ctype_toupper_data
+ + __UCLIBC_CTYPE_TO_TBL_OFFSET;
+#endif /* __UCLIBC_HAS_XLOCALE__ */
+
+#endif /* __CTYPE_HAS_8_BIT_LOCALES */
+ }
+#ifdef __UCLIBC_MJN3_ONLY__
+#warning TODO: Put the outdigit string length in the locale_mmap object.
+#endif
+ d = base->outdigit_length;
+ x = &base->outdigit0_mb;
+ for (c = 0 ; c < 10 ; c++) {
+ ((unsigned char *)d)[c] = strlen(x[c]);
+ assert(d[c] > 0);
+ }
+ } else if (i == LC_NUMERIC) {
+ assert(LC_NUMERIC > LC_CTYPE); /* Need ctype initialized. */
+
+ base->decimal_point_len
+ = __locale_mbrtowc_l(&base->decimal_point_wc,
+ base->decimal_point, base);
+ assert(base->decimal_point_len > 0);
+ assert(base->decimal_point[base->decimal_point_len] == 0);
+
+ if (*base->grouping) {
+ base->thousands_sep_len
+ = __locale_mbrtowc_l(&base->thousands_sep_wc,
+ base->thousands_sep, base);
+#if 1
+#ifdef __UCLIBC_MJN3_ONLY__
+#warning TODO: Remove hack involving grouping without a thousep char (bg_BG).
+#endif
+ assert(base->thousands_sep_len >= 0);
+ if (base->thousands_sep_len == 0) {
+ base->grouping = base->thousands_sep; /* empty string */
+ }
+ assert(base->thousands_sep[base->thousands_sep_len] == 0);
+#else
+ assert(base->thousands_sep_len > 0);
+ assert(base->thousands_sep[base->thousands_sep_len] == 0);
+#endif
+ }
+
+/* } else if (i == LC_COLLATE) { */
+/* init_cur_collate(__locale_mmap->locales[ __LOCALE_DATA_WIDTH_LOCALES */
+/* * row + 3 + i ], */
+/* &base->collate); */
+ }
+ }
+ ++i;
+ p += 2;
+ s += 2;
+ } while (i < LC_ALL);
+
+ return 1;
+}
+
+static const uint16_t __code2flag[16] = {
+ 0, /* unclassified = 0 */
+ _ISprint|_ISgraph|_ISalnum|_ISalpha, /* alpha_nonupper_nonlower */
+ _ISprint|_ISgraph|_ISalnum|_ISalpha|_ISlower, /* alpha_lower */
+ _ISprint|_ISgraph|_ISalnum|_ISalpha|_ISlower|_ISupper, /* alpha_upper_lower */
+ _ISprint|_ISgraph|_ISalnum|_ISalpha|_ISupper, /* alpha_upper */
+ _ISprint|_ISgraph|_ISalnum|_ISdigit, /* digit */
+ _ISprint|_ISgraph|_ISpunct, /* punct */
+ _ISprint|_ISgraph, /* graph */
+ _ISprint|_ISspace, /* print_space_nonblank */
+ _ISprint|_ISspace|_ISblank, /* print_space_blank */
+ _ISspace, /* space_nonblank_noncntrl */
+ _ISspace|_ISblank, /* space_blank_noncntrl */
+ _IScntrl|_ISspace, /* cntrl_space_nonblank */
+ _IScntrl|_ISspace|_ISblank, /* cntrl_space_blank */
+ _IScntrl /* cntrl_nonspace */
+};
+
+void attribute_hidden _locale_init_l(__locale_t base)
+{
+ memset(base->cur_locale, 0, LOCALE_SELECTOR_SIZE);
+ base->cur_locale[0] = '#';
+
+ memcpy(base->category_item_count,
+ __locale_mmap->lc_common_item_offsets_LEN,
+ LC_ALL);
+
+ ++base->category_item_count[0]; /* Increment for codeset entry. */
+ base->category_offsets[0] = offsetof(struct __uclibc_locale_struct, outdigit0_mb);
+ base->category_offsets[1] = offsetof(struct __uclibc_locale_struct, decimal_point);
+ base->category_offsets[2] = offsetof(struct __uclibc_locale_struct, int_curr_symbol);
+ base->category_offsets[3] = offsetof(struct __uclibc_locale_struct, abday_1);
+/* base->category_offsets[4] = offsetof(struct __uclibc_locale_struct, collate???); */
+ base->category_offsets[5] = offsetof(struct __uclibc_locale_struct, yesexpr);
+
+#ifdef __CTYPE_HAS_8_BIT_LOCALES
+ base->tbl8ctype
+ = (const unsigned char *) &__locale_mmap->tbl8ctype;
+ base->tbl8uplow
+ = (const unsigned char *) &__locale_mmap->tbl8uplow;
+#ifdef __UCLIBC_HAS_WCHAR__
+ base->tbl8c2wc
+ = (const uint16_t *) &__locale_mmap->tbl8c2wc;
+ base->tbl8wc2c
+ = (const unsigned char *) &__locale_mmap->tbl8wc2c;
+ /* translit */
+#endif /* __UCLIBC_HAS_WCHAR__ */
+#endif /* __CTYPE_HAS_8_BIT_LOCALES */
+#ifdef __UCLIBC_HAS_WCHAR__
+ base->tblwctype
+ = (const unsigned char *) &__locale_mmap->tblwctype;
+ base->tblwuplow
+ = (const unsigned char *) &__locale_mmap->tblwuplow;
+ base->tblwuplow_diff
+ = (const int16_t *) &__locale_mmap->tblwuplow_diff;
+/* base->tblwcomb */
+/* = (const unsigned char *) &__locale_mmap->tblwcomb; */
+ /* width?? */
+#endif /* __UCLIBC_HAS_WCHAR__ */
+
+ /* Initially, set things up to use the global C ctype tables.
+ * This is correct for C (ASCII) and UTF-8 based locales (except tr_TR). */
+#ifdef __UCLIBC_HAS_XLOCALE__
+ base->__ctype_b = __C_ctype_b;
+ base->__ctype_tolower = __C_ctype_tolower;
+ base->__ctype_toupper = __C_ctype_toupper;
+#else /* __UCLIBC_HAS_XLOCALE__ */
+ __ctype_b = __C_ctype_b;
+ __ctype_tolower = __C_ctype_tolower;
+ __ctype_toupper = __C_ctype_toupper;
+#endif /* __UCLIBC_HAS_XLOCALE__ */
+
+#ifdef __UCLIBC_MJN3_ONLY__
+#warning TODO: Initialize code2flag correctly based on locale_mmap.
+#endif
+ base->code2flag = __code2flag;
+
+ _locale_set_l((unsigned char*) C_LOCALE_SELECTOR, base);
+}
+
+void _locale_init(void) attribute_hidden;
+void _locale_init(void)
+{
+ /* TODO: mmap the locale file */
+
+ /* TODO - ??? */
+ _locale_init_l(__global_locale);
+}
+
+#endif
+/**********************************************************************/
+#if defined(L_nl_langinfo) || defined(L_nl_langinfo_l)
+
+#ifdef __LOCALE_C_ONLY
+
+/* We need to index 320 bytes of data, so you might initially think we
+ * need to store the offsets in shorts. But since the offset of the
+ * 64th item is 182, we'll store "offset - 2*64" for all items >= 64
+ * and always calculate the data offset as "offset[i] + 2*(i & 64)".
+ * This allows us to pack the data offsets in an unsigned char while
+ * also avoiding an "if".
+ *
+ * Note: Category order is assumed to be:
+ * ctype, numeric, monetary, time, collate, messages, all
+ */
+
+#define C_LC_ALL 6
+
+/* Combine the data to avoid size penalty for seperate char arrays when
+ * compiler aligns objects. The original code is left in as documentation. */
+#define cat_start nl_data
+#define C_locale_data (nl_data + C_LC_ALL + 1 + 90)
+
+static const unsigned char nl_data[C_LC_ALL + 1 + 90 + 320] = {
+/* static const char cat_start[LC_ALL + 1] = { */
+ '\x00', '\x0b', '\x0e', '\x24', '\x56', '\x56', '\x5a',
+/* }; */
+/* static const char item_offset[90] = { */
+ '\x00', '\x02', '\x04', '\x06', '\x08', '\x0a', '\x0c', '\x0e',
+ '\x10', '\x12', '\x14', '\x1a', '\x1b', '\x1b', '\x1b', '\x1b',
+ '\x1b', '\x1b', '\x1b', '\x1b', '\x1b', '\x1c', '\x1c', '\x1c',
+ '\x1c', '\x1c', '\x1c', '\x1c', '\x1c', '\x1c', '\x1c', '\x1c',
+ '\x1c', '\x1c', '\x1c', '\x1e', '\x20', '\x24', '\x28', '\x2c',
+ '\x30', '\x34', '\x38', '\x3c', '\x43', '\x4a', '\x52', '\x5c',
+ '\x65', '\x6c', '\x75', '\x79', '\x7d', '\x81', '\x85', '\x89',
+ '\x8d', '\x91', '\x95', '\x99', '\x9d', '\xa1', '\xa5', '\xad',
+ '\x36', '\x3c', '\x42', '\x46', '\x4b', '\x50', '\x57', '\x61',
+ '\x69', '\x72', '\x7b', '\x7e', '\x81', '\x96', '\x9f', '\xa8',
+ '\xb3', '\xb3', '\xb3', '\xb3', '\xb3', '\xb3', '\xb4', '\xba',
+ '\xbf', '\xbf',
+/* }; */
+/* static const char C_locale_data[320] = { */
+ '0', '\x00', '1', '\x00', '2', '\x00', '3', '\x00',
+ '4', '\x00', '5', '\x00', '6', '\x00', '7', '\x00',
+ '8', '\x00', '9', '\x00', 'A', 'S', 'C', 'I',
+ 'I', '\x00', '.', '\x00', '\x7f', '\x00', '-', '\x00',
+ 'S', 'u', 'n', '\x00', 'M', 'o', 'n', '\x00',
+ 'T', 'u', 'e', '\x00', 'W', 'e', 'd', '\x00',
+ 'T', 'h', 'u', '\x00', 'F', 'r', 'i', '\x00',
+ 'S', 'a', 't', '\x00', 'S', 'u', 'n', 'd',
+ 'a', 'y', '\x00', 'M', 'o', 'n', 'd', 'a',
+ 'y', '\x00', 'T', 'u', 'e', 's', 'd', 'a',
+ 'y', '\x00', 'W', 'e', 'd', 'n', 'e', 's',
+ 'd', 'a', 'y', '\x00', 'T', 'h', 'u', 'r',
+ 's', 'd', 'a', 'y', '\x00', 'F', 'r', 'i',
+ 'd', 'a', 'y', '\x00', 'S', 'a', 't', 'u',
+ 'r', 'd', 'a', 'y', '\x00', 'J', 'a', 'n',
+ '\x00', 'F', 'e', 'b', '\x00', 'M', 'a', 'r',
+ '\x00', 'A', 'p', 'r', '\x00', 'M', 'a', 'y',
+ '\x00', 'J', 'u', 'n', '\x00', 'J', 'u', 'l',
+ '\x00', 'A', 'u', 'g', '\x00', 'S', 'e', 'p',
+ '\x00', 'O', 'c', 't', '\x00', 'N', 'o', 'v',
+ '\x00', 'D', 'e', 'c', '\x00', 'J', 'a', 'n',
+ 'u', 'a', 'r', 'y', '\x00', 'F', 'e', 'b',
+ 'r', 'u', 'a', 'r', 'y', '\x00', 'M', 'a',
+ 'r', 'c', 'h', '\x00', 'A', 'p', 'r', 'i',
+ 'l', '\x00', 'M', 'a', 'y', '\x00', 'J', 'u',
+ 'n', 'e', '\x00', 'J', 'u', 'l', 'y', '\x00',
+ 'A', 'u', 'g', 'u', 's', 't', '\x00', 'S',
+ 'e', 'p', 't', 'e', 'm', 'b', 'e', 'r',
+ '\x00', 'O', 'c', 't', 'o', 'b', 'e', 'r',
+ '\x00', 'N', 'o', 'v', 'e', 'm', 'b', 'e',
+ 'r', '\x00', 'D', 'e', 'c', 'e', 'm', 'b',
+ 'e', 'r', '\x00', 'A', 'M', '\x00', 'P', 'M',
+ '\x00', '%', 'a', ' ', '%', 'b', ' ', '%',
+ 'e', ' ', '%', 'H', ':', '%', 'M', ':',
+ '%', 'S', ' ', '%', 'Y', '\x00', '%', 'm',
+ '/', '%', 'd', '/', '%', 'y', '\x00', '%',
+ 'H', ':', '%', 'M', ':', '%', 'S', '\x00',
+ '%', 'I', ':', '%', 'M', ':', '%', 'S',
+ ' ', '%', 'p', '\x00', '^', '[', 'y', 'Y',
+ ']', '\x00', '^', '[', 'n', 'N', ']', '\x00',
+};
+
+char *nl_langinfo(nl_item item)
+{
+ unsigned int c;
+ unsigned int i;
+
+ if ((c = _NL_ITEM_CATEGORY(item)) < C_LC_ALL) {
+ if ((i = cat_start[c] + _NL_ITEM_INDEX(item)) < cat_start[c+1]) {
+/* return (char *) C_locale_data + item_offset[i] + (i & 64); */
+ return (char *) C_locale_data + nl_data[C_LC_ALL+1+i] + 2*(i & 64);
+ }
+ }
+ return (char *) cat_start; /* Conveniently, this is the empty string. */
+}
+libc_hidden_def(nl_langinfo)
+
+#else /* __LOCALE_C_ONLY */
+
+#if defined(__UCLIBC_HAS_XLOCALE__) && !defined(__UCLIBC_DO_XLOCALE)
+
+
+
+char *nl_langinfo(nl_item item)
+{
+ return nl_langinfo_l(item, __UCLIBC_CURLOCALE);
+}
+libc_hidden_def(nl_langinfo)
+
+#else /* defined(__UCLIBC_HAS_XLOCALE__) && !defined(__UCLIBC_DO_XLOCALE) */
+
+libc_hidden_proto(__XL_NPP(nl_langinfo))
+
+static const char empty[] = "";
+
+char *__XL_NPP(nl_langinfo)(nl_item item __LOCALE_PARAM )
+{
+ unsigned int c = _NL_ITEM_CATEGORY(item);
+ unsigned int i = _NL_ITEM_INDEX(item);
+
+ if ((c < LC_ALL) && (i < __LOCALE_PTR->category_item_count[c])) {
+ return ((char **)(((char *) __LOCALE_PTR)
+ + __LOCALE_PTR->category_offsets[c]))[i];
+ }
+
+ return (char *) empty;
+}
+libc_hidden_def(__XL_NPP(nl_langinfo))
+
+#endif /* defined(__UCLIBC_HAS_XLOCALE__) && !defined(__UCLIBC_DO_XLOCALE) */
+
+#endif /* __LOCALE_C_ONLY */
+
+#endif
+/**********************************************************************/
+#ifdef L_newlocale
+
+#warning mask defines for extra locale categories
+
+#ifdef __UCLIBC_MJN3_ONLY__
+#warning TODO: Move posix and utf8 strings.
+#endif
+static const char posix[] = "POSIX";
+static const char utf8[] = "UTF-8";
+
+static int find_locale(int category_mask, const char *p,
+ unsigned char *new_locale)
+{
+ int i;
+ const unsigned char *s;
+ uint16_t n;
+ unsigned char lang_cult, codeset;
+
+#if defined(__LOCALE_DATA_AT_MODIFIERS_LENGTH) && 1
+ /* Support standard locale handling for @-modifiers. */
+
+#ifdef __UCLIBC_MJN3_ONLY__
+#warning REMINDER: Fix buf size in find_locale.
+#endif
+ char buf[18]; /* TODO: 7+{max codeset name length} */
+ const char *q;
+
+ if ((q = strchr(p,'@')) != NULL) {
+ if ((((size_t)((q-p)-5)) > (sizeof(buf) - 5)) || (p[2] != '_')) {
+ return 0;
+ }
+ /* locale name at least 5 chars long and 3rd char is '_' */
+ s = LOCALE_AT_MODIFIERS;
+ do {
+ if (!strcmp((char*) (s + 2), q + 1)) {
+ break;
+ }
+ s += 2 + *s; /* TODO - fix this throughout */
+ } while (*s);
+ if (!*s) {
+ return 0;
+ }
+ assert(q - p < sizeof(buf));
+ memcpy(buf, p, q-p);
+ buf[q-p] = 0;
+ buf[2] = s[1];
+ p = buf;
+ }
+#endif
+
+ lang_cult = codeset = 0; /* Assume C and default codeset. */
+ if (((*p == 'C') && !p[1]) || !strcmp(p, posix)) {
+ goto FIND_LOCALE;
+ }
+
+ if ((strlen(p) > 5) && (p[5] == '.')) { /* Codeset in locale name? */
+ /* TODO: maybe CODESET_LIST + *s ??? */
+ /* 7bit is 1, UTF-8 is 2, 8-bit is >= 3 */
+ codeset = 2;
+ if (strcasecmp(utf8, p + 6) != 0) {/* TODO - fix! */
+ s = CODESET_LIST;
+ do {
+ ++codeset; /* Increment codeset first. */
+ if (!strcmp((char*) CODESET_LIST + *s, p + 6)) {
+ goto FIND_LANG_CULT;
+ }
+ } while (*++s);
+ return 0; /* No matching codeset! */
+ }
+ }
+
+ FIND_LANG_CULT: /* Find language_culture number. */
+ s = LOCALE_NAMES;
+ do { /* TODO -- do a binary search? */
+ /* TODO -- fix gen_mmap!*/
+ ++lang_cult; /* Increment first since C/POSIX is 0. */
+ if (!strncmp((char*) s, p, 5)) { /* Found a matching locale name; */
+ goto FIND_LOCALE;
+ }
+ s += 5;
+ } while (lang_cult < __LOCALE_DATA_NUM_LOCALE_NAMES);
+ return 0; /* No matching language_culture! */
+
+ FIND_LOCALE: /* Find locale row matching name and codeset */
+ s = LOCALES;
+ n = 0;
+ do { /* TODO -- do a binary search? */
+ if ((lang_cult == *s) && ((codeset == s[1]) || (codeset == s[2]))) {
+ i = 1;
+ s = new_locale + 1;
+ do {
+ if (category_mask & i) {
+ /* Encode current locale row number. */
+ ((unsigned char *) s)[0] = (n >> 7) | 0x80;
+ ((unsigned char *) s)[1] = (n & 0x7f) | 0x80;
+ }
+ s += 2;
+ i += i;
+ } while (i < (1 << LC_ALL));
+
+ return i; /* Return non-zero */
+ }
+ s += __LOCALE_DATA_WIDTH_LOCALES;
+ ++n;
+ } while (n <= __LOCALE_DATA_NUM_LOCALES); /* We started at 1!!! */
+
+ return 0; /* Unsupported locale. */
+}
+
+static unsigned char *composite_locale(int category_mask, const char *locale,
+ unsigned char *new_locale)
+{
+ char buf[MAX_LOCALE_STR];
+ char *t;
+ char *e;
+ int c;
+ int component_mask;
+
+ if (!strchr(locale,'=')) {
+ if (!find_locale(category_mask, locale, new_locale)) {
+ return NULL;
+ }
+ return new_locale;
+ }
+
+ if (strlen(locale) >= sizeof(buf)) {
+ return NULL;
+ }
+ stpcpy(buf, locale);
+
+ component_mask = 0;
+ t = strtok_r(buf, "=", &e); /* This can't fail because of strchr test above. */
+ do {
+ c = 0;
+ /* CATEGORY_NAMES is unsigned char* */
+ while (strcmp((char*) CATEGORY_NAMES + (int) CATEGORY_NAMES[c], t)) {
+ if (++c == LC_ALL) { /* Unknown category name! */
+ return NULL;
+ }
+ }
+ t = strtok_r(NULL, ";", &e);
+ c = (1 << c);
+ if (component_mask & c) { /* Multiple components for one category. */
+ return NULL;
+ }
+ component_mask |= c;
+ if ((category_mask & c) && (!t || !find_locale(c, t, new_locale))) {
+ return NULL;
+ }
+ } while ((t = strtok_r(NULL, "=", &e)) != NULL);
+
+ if (category_mask & ~component_mask) { /* Category component(s) missing. */
+ return NULL;
+ }
+
+ return new_locale;
+}
+
+__locale_t newlocale(int category_mask, const char *locale, __locale_t base)
+{
+ const char *p;
+ int i, j, k;
+ unsigned char new_selector[LOCALE_SELECTOR_SIZE];
+
+ if (category_mask == (1 << LC_ALL)) {
+ category_mask = LC_ALL_MASK;
+ }
+
+ if (!locale || ((unsigned)(category_mask) > LC_ALL_MASK)) {
+ INVALID:
+ __set_errno(EINVAL);
+ return NULL; /* No locale or illegal/unsupported category. */
+ }
+
+#ifdef __UCLIBC_MJN3_ONLY__
+#warning TODO: Rename cur_locale to locale_selector.
+#endif
+ strcpy((char *) new_selector,
+ (base ? (char *) base->cur_locale : C_LOCALE_SELECTOR));
+
+ if (!locale[0]) { /* locale == "", so check environment. */
+ const char *envstr[4];
+
+ envstr[0] = "LC_ALL";
+ envstr[1] = NULL;
+ envstr[2] = "LANG";
+ envstr[3] = posix;
+
+ i = 1;
+ k = 0;
+ do {
+ if (category_mask & i) {
+ /* Note: SUSv3 doesn't define a fallback mechanism here.
+ * So, if LC_ALL is invalid, we do _not_ continue trying
+ * the other environment vars. */
+ envstr[1] = (char*) CATEGORY_NAMES + CATEGORY_NAMES[k];
+ j = 0;
+ while (1) {
+ p = envstr[j];
+ if (++j >= 4)
+ break; /* now p == "POSIX" */
+ p = getenv(p);
+ if (p && p[0])
+ break;
+ };
+
+ /* The user set something... is it valid? */
+ /* Note: Since we don't support user-supplied locales and
+ * alternate paths, we don't need to worry about special
+ * handling for suid/sgid apps. */
+ if (!find_locale(i, p, new_selector)) {
+ goto INVALID;
+ }
+ }
+ i += i;
+ } while (++k < LC_ALL);
+ } else if (!composite_locale(category_mask, locale, new_selector)) {
+ goto INVALID;
+ }
+
+#ifdef __UCLIBC_MJN3_ONLY__
+#warning TODO: Do a compatible codeset check!
+#endif
+
+ /* If we get here, the new selector corresponds to a valid locale. */
+
+#ifdef __UCLIBC_MJN3_ONLY__
+#warning CONSIDER: Probably want a _locale_new func to allow for caching of locales.
+#endif
+#if 0
+ if (base) {
+ _locale_set_l(new_selector, base);
+ } else {
+ base = _locale_new(new_selector);
+ }
+#else
+ if (!base) {
+ base = calloc(1, sizeof(struct __uclibc_locale_struct));
+ if (base == NULL)
+ return base;
+ _locale_init_l(base);
+ }
+
+ _locale_set_l(new_selector, base);
+#endif
+
+ return base;
+}
+#ifdef __UCLIBC_HAS_XLOCALE__
+libc_hidden_def(newlocale)
+#endif
+
+#endif
+/**********************************************************************/
+#ifdef L_duplocale
+
+
+#ifdef __UCLIBC_MJN3_ONLY__
+#warning REMINDER: When we allocate ctype tables, remember to dup them.
+#endif
+
+__locale_t duplocale(__locale_t dataset)
+{
+ __locale_t r;
+ uint16_t * i2w;
+ size_t n;
+
+ assert(dataset != LC_GLOBAL_LOCALE);
+
+ r = malloc(sizeof(struct __uclibc_locale_struct));
+ if (r != NULL) {
+ n = 2 * dataset->collate.max_col_index + 2;
+ i2w = calloc(n, sizeof(uint16_t));
+ if (i2w != NULL) {
+ memcpy(r, dataset, sizeof(struct __uclibc_locale_struct));
+ r->collate.index2weight = i2w;
+ memcpy(i2w, dataset->collate.index2weight, n * sizeof(uint16_t));
+ } else {
+ free(r);
+ r = NULL;
+ }
+ }
+ return r;
+}
+
+#endif
+/**********************************************************************/
+#ifdef L_freelocale
+
+#ifdef __UCLIBC_MJN3_ONLY__
+#warning REMINDER: When we allocate ctype tables, remember to free them.
+#endif
+
+void freelocale(__locale_t dataset)
+{
+ assert(dataset != __global_locale);
+ assert(dataset != LC_GLOBAL_LOCALE);
+
+ free(dataset->collate.index2weight); /* Free collation data. */
+ free(dataset); /* Free locale */
+}
+
+#endif
+/**********************************************************************/
+#ifdef L_uselocale
+
+__locale_t uselocale(__locale_t dataset)
+{
+ __locale_t old;
+
+ if (!dataset) {
+ old = __UCLIBC_CURLOCALE;
+ } else {
+ if (dataset == LC_GLOBAL_LOCALE) {
+ dataset = __global_locale;
+ }
+#ifdef __UCLIBC_HAS_THREADS__
+ old = __curlocale_set(dataset);
+#else
+ old = __curlocale_var;
+ __curlocale_var = dataset;
+#endif
+ }
+
+ if (old == __global_locale) {
+ return LC_GLOBAL_LOCALE;
+ }
+ return old;
+}
+libc_hidden_def(uselocale)
+
+#endif
+/**********************************************************************/
+#ifdef L___curlocale
+
+#ifdef __UCLIBC_HAS_THREADS__
+
+__locale_t weak_const_function __curlocale(void)
+{
+ return __curlocale_var; /* This is overriden by the thread version. */
+}
+
+__locale_t weak_function __curlocale_set(__locale_t newloc)
+{
+ __locale_t oldloc = __curlocale_var;
+ assert(newloc != LC_GLOBAL_LOCALE);
+ __curlocale_var = newloc;
+ return oldloc;
+}
+
+#endif
+
+#endif
+/**********************************************************************/
+#ifdef L___locale_mbrtowc_l
+
+/* NOTE: This returns an int... not size_t. Also, it is not a general
+ * routine. It is actually a very stripped-down version of mbrtowc
+ * that takes a __locale_t arg. This is used by strcoll and strxfrm.
+ * It is also used above to generate wchar_t versions of the decimal point
+ * and thousands seperator. */
+
+
+#ifndef __CTYPE_HAS_UTF_8_LOCALES
+#warning __CTYPE_HAS_UTF_8_LOCALES not set!
+#endif
+#ifndef __CTYPE_HAS_8_BIT_LOCALES
+#warning __CTYPE_HAS_8_BIT_LOCALES not set!
+#endif
+
+#define Cc2wc_IDX_SHIFT __LOCALE_DATA_Cc2wc_IDX_SHIFT
+#define Cc2wc_ROW_LEN __LOCALE_DATA_Cc2wc_ROW_LEN
+
+extern size_t _wchar_utf8sntowcs(wchar_t *__restrict pwc, size_t wn,
+ const char **__restrict src, size_t n,
+ mbstate_t *ps, int allow_continuation) attribute_hidden;
+
+int attribute_hidden __locale_mbrtowc_l(wchar_t *__restrict dst,
+ const char *__restrict src,
+ __locale_t loc )
+{
+#ifdef __CTYPE_HAS_UTF_8_LOCALES
+ if (loc->encoding == __ctype_encoding_utf8) {
+ mbstate_t ps;
+ const char *p = src;
+ size_t r;
+ ps.__mask = 0;
+ r = _wchar_utf8sntowcs(dst, 1, &p, SIZE_MAX, &ps, 1);
+ return (r == 1) ? (p-src) : r; /* Need to return 0 if nul char. */
+ }
+#endif
+
+#ifdef __CTYPE_HAS_8_BIT_LOCALES
+ assert((loc->encoding == __ctype_encoding_7_bit) || (loc->encoding == __ctype_encoding_8_bit));
+#else
+ assert(loc->encoding == __ctype_encoding_7_bit);
+#endif
+
+ if ((*dst = ((unsigned char)(*src))) < 0x80) { /* ASCII... */
+ return (*src != 0);
+ }
+
+#ifdef __CTYPE_HAS_8_BIT_LOCALES
+ if (loc->encoding == __ctype_encoding_8_bit) {
+ wchar_t wc = *dst - 0x80;
+ *dst = loc->tbl8c2wc[
+ (loc->idx8c2wc[wc >> Cc2wc_IDX_SHIFT]
+ << Cc2wc_IDX_SHIFT) + (wc & (Cc2wc_ROW_LEN - 1))];
+ if (*dst) {
+ return 1;
+ }
+ }
+#endif
+
+ return -1;
+}
+
+#endif
+/**********************************************************************/
diff --git a/ap/build/uClibc/libc/misc/locale/localeconv.c b/ap/build/uClibc/libc/misc/locale/localeconv.c
new file mode 100644
index 0000000..7e67fb2
--- /dev/null
+++ b/ap/build/uClibc/libc/misc/locale/localeconv.c
@@ -0,0 +1,8 @@
+/*
+ * Copyright (C) 2004-2006 Manuel Novoa III <mjn3@uclibc.org>
+ *
+ * Licensed under the LGPL v2.1, see the file COPYING.LIB in this tarball.
+ */
+
+#define L_localeconv
+#include "locale.c"
diff --git a/ap/build/uClibc/libc/misc/locale/newlocale.c b/ap/build/uClibc/libc/misc/locale/newlocale.c
new file mode 100644
index 0000000..a986884
--- /dev/null
+++ b/ap/build/uClibc/libc/misc/locale/newlocale.c
@@ -0,0 +1,8 @@
+/*
+ * Copyright (C) 2004-2006 Manuel Novoa III <mjn3@uclibc.org>
+ *
+ * Licensed under the LGPL v2.1, see the file COPYING.LIB in this tarball.
+ */
+
+#define L_newlocale
+#include "locale.c"
diff --git a/ap/build/uClibc/libc/misc/locale/nl_langinfo.c b/ap/build/uClibc/libc/misc/locale/nl_langinfo.c
new file mode 100644
index 0000000..0bc0a00
--- /dev/null
+++ b/ap/build/uClibc/libc/misc/locale/nl_langinfo.c
@@ -0,0 +1,8 @@
+/*
+ * Copyright (C) 2004-2006 Manuel Novoa III <mjn3@uclibc.org>
+ *
+ * Licensed under the LGPL v2.1, see the file COPYING.LIB in this tarball.
+ */
+
+#define L_nl_langinfo
+#include "locale.c"
diff --git a/ap/build/uClibc/libc/misc/locale/nl_langinfo_l.c b/ap/build/uClibc/libc/misc/locale/nl_langinfo_l.c
new file mode 100644
index 0000000..7205cca
--- /dev/null
+++ b/ap/build/uClibc/libc/misc/locale/nl_langinfo_l.c
@@ -0,0 +1,9 @@
+/*
+ * Copyright (C) 2004-2006 Manuel Novoa III <mjn3@uclibc.org>
+ *
+ * Licensed under the LGPL v2.1, see the file COPYING.LIB in this tarball.
+ */
+
+#define L_nl_langinfo_l
+#define __UCLIBC_DO_XLOCALE
+#include "locale.c"
diff --git a/ap/build/uClibc/libc/misc/locale/setlocale.c b/ap/build/uClibc/libc/misc/locale/setlocale.c
new file mode 100644
index 0000000..1eae88a
--- /dev/null
+++ b/ap/build/uClibc/libc/misc/locale/setlocale.c
@@ -0,0 +1,8 @@
+/*
+ * Copyright (C) 2004-2006 Manuel Novoa III <mjn3@uclibc.org>
+ *
+ * Licensed under the LGPL v2.1, see the file COPYING.LIB in this tarball.
+ */
+
+#define L_setlocale
+#include "locale.c"
diff --git a/ap/build/uClibc/libc/misc/locale/uselocale.c b/ap/build/uClibc/libc/misc/locale/uselocale.c
new file mode 100644
index 0000000..2aecc54
--- /dev/null
+++ b/ap/build/uClibc/libc/misc/locale/uselocale.c
@@ -0,0 +1,9 @@
+/*
+ * Copyright (C) 2004-2006 Manuel Novoa III <mjn3@uclibc.org>
+ *
+ * Licensed under the LGPL v2.1, see the file COPYING.LIB in this tarball.
+ */
+
+#define L_uselocale
+#define __UCLIBC_DO_XLOCALE
+#include "locale.c"
diff --git a/ap/build/uClibc/libc/misc/mntent/.indent.pro b/ap/build/uClibc/libc/misc/mntent/.indent.pro
new file mode 100644
index 0000000..492ecf1
--- /dev/null
+++ b/ap/build/uClibc/libc/misc/mntent/.indent.pro
@@ -0,0 +1,33 @@
+--blank-lines-after-declarations
+--blank-lines-after-procedures
+--break-before-boolean-operator
+--no-blank-lines-after-commas
+--braces-on-if-line
+--braces-on-struct-decl-line
+--comment-indentation25
+--declaration-comment-column25
+--no-comment-delimiters-on-blank-lines
+--cuddle-else
+--continuation-indentation4
+--case-indentation0
+--else-endif-column33
+--space-after-cast
+--line-comments-indentation0
+--declaration-indentation1
+--dont-format-first-column-comments
+--dont-format-comments
+--honour-newlines
+--indent-level4
+/* changed from 0 to 4 */
+--parameter-indentation4
+--line-length78 /* changed from 75 */
+--continue-at-parentheses
+--no-space-after-function-call-names
+--dont-break-procedure-type
+--dont-star-comments
+--leave-optional-blank-lines
+--dont-space-special-semicolon
+--tab-size4
+/* additions by Mark */
+--case-brace-indentation0
+--leave-preprocessor-space
diff --git a/ap/build/uClibc/libc/misc/mntent/Makefile b/ap/build/uClibc/libc/misc/mntent/Makefile
new file mode 100644
index 0000000..4a8f4a0
--- /dev/null
+++ b/ap/build/uClibc/libc/misc/mntent/Makefile
@@ -0,0 +1,13 @@
+# Makefile for uClibc
+#
+# Copyright (C) 2000-2005 Erik Andersen <andersen@uclibc.org>
+#
+# Licensed under the LGPL v2.1, see the file COPYING.LIB in this tarball.
+#
+
+top_srcdir=../../../
+top_builddir=../../../
+all: objs
+include $(top_builddir)Rules.mak
+include Makefile.in
+include $(top_srcdir)Makerules
diff --git a/ap/build/uClibc/libc/misc/mntent/Makefile.in b/ap/build/uClibc/libc/misc/mntent/Makefile.in
new file mode 100644
index 0000000..daa888d
--- /dev/null
+++ b/ap/build/uClibc/libc/misc/mntent/Makefile.in
@@ -0,0 +1,23 @@
+# Makefile for uClibc
+#
+# Copyright (C) 2000-2008 Erik Andersen <andersen@uclibc.org>
+#
+# Licensed under the LGPL v2.1, see the file COPYING.LIB in this tarball.
+#
+
+subdirs += libc/misc/mntent
+
+CSRC := mntent.c
+
+MISC_MNTENT_DIR := $(top_srcdir)libc/misc/mntent
+MISC_MNTENT_OUT := $(top_builddir)libc/misc/mntent
+
+MISC_MNTENT_SRC := $(MISC_MNTENT_DIR)/mntent.c
+MISC_MNTENT_OBJ := $(MISC_MNTENT_OUT)/mntent.o
+
+libc-y += $(MISC_MNTENT_OBJ)
+
+objclean-y += CLEAN_libc/misc/mntent
+
+CLEAN_libc/misc/mntent:
+ $(do_rm) $(addprefix $(MISC_MNTENT_OUT)/*., o os)
diff --git a/ap/build/uClibc/libc/misc/mntent/mntent.c b/ap/build/uClibc/libc/misc/mntent/mntent.c
new file mode 100644
index 0000000..608f84c
--- /dev/null
+++ b/ap/build/uClibc/libc/misc/mntent/mntent.c
@@ -0,0 +1,112 @@
+/*
+ * Copyright (C) 2000-2006 Erik Andersen <andersen@uclibc.org>
+ *
+ * Licensed under the LGPL v2.1, see the file COPYING.LIB in this tarball.
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <mntent.h>
+#include <bits/uClibc_mutex.h>
+
+__UCLIBC_MUTEX_STATIC(mylock, PTHREAD_MUTEX_INITIALIZER);
+
+
+
+/* Reentrant version of getmntent. */
+struct mntent *getmntent_r (FILE *filep,
+ struct mntent *mnt, char *buff, int bufsize)
+{
+ static const char sep[] = " \t\n";
+
+ char *cp, *ptrptr;
+
+ if (!filep || !mnt || !buff)
+ return NULL;
+
+ /* Loop on the file, skipping comment lines. - FvK 03/07/93 */
+ while ((cp = fgets(buff, bufsize, filep)) != NULL) {
+ if (buff[0] == '#' || buff[0] == '\n')
+ continue;
+ break;
+ }
+
+ /* At the EOF, the buffer should be unchanged. We should
+ * check the return value from fgets ().
+ */
+ if (cp == NULL)
+ return NULL;
+
+ ptrptr = 0;
+ mnt->mnt_fsname = strtok_r(buff, sep, &ptrptr);
+ if (mnt->mnt_fsname == NULL)
+ return NULL;
+
+ mnt->mnt_dir = strtok_r(NULL, sep, &ptrptr);
+ if (mnt->mnt_dir == NULL)
+ return NULL;
+
+ mnt->mnt_type = strtok_r(NULL, sep, &ptrptr);
+ if (mnt->mnt_type == NULL)
+ return NULL;
+
+ mnt->mnt_opts = strtok_r(NULL, sep, &ptrptr);
+ if (mnt->mnt_opts == NULL)
+ mnt->mnt_opts = "";
+
+ cp = strtok_r(NULL, sep, &ptrptr);
+ mnt->mnt_freq = (cp != NULL) ? atoi(cp) : 0;
+
+ cp = strtok_r(NULL, sep, &ptrptr);
+ mnt->mnt_passno = (cp != NULL) ? atoi(cp) : 0;
+
+ return mnt;
+}
+libc_hidden_def(getmntent_r)
+
+struct mntent *getmntent(FILE * filep)
+{
+ struct mntent *tmp;
+ static char *buff = NULL;
+ static struct mntent mnt;
+ __UCLIBC_MUTEX_LOCK(mylock);
+
+ if (!buff) {
+ buff = malloc(BUFSIZ);
+ if (!buff)
+ abort();
+ }
+
+ tmp = getmntent_r(filep, &mnt, buff, BUFSIZ);
+ __UCLIBC_MUTEX_UNLOCK(mylock);
+ return(tmp);
+}
+
+int addmntent(FILE * filep, const struct mntent *mnt)
+{
+ if (fseek(filep, 0, SEEK_END) < 0)
+ return 1;
+
+ return (fprintf (filep, "%s %s %s %s %d %d\n", mnt->mnt_fsname, mnt->mnt_dir,
+ mnt->mnt_type, mnt->mnt_opts, mnt->mnt_freq, mnt->mnt_passno) < 0 ? 1 : 0);
+}
+
+char *hasmntopt(const struct mntent *mnt, const char *opt)
+{
+ return strstr(mnt->mnt_opts, opt);
+}
+
+FILE *setmntent(const char *name, const char *mode)
+{
+ return fopen(name, mode);
+}
+libc_hidden_def(setmntent)
+
+int endmntent(FILE * filep)
+{
+ if (filep != NULL)
+ fclose(filep);
+ return 1;
+}
+libc_hidden_def(endmntent)
diff --git a/ap/build/uClibc/libc/misc/pthread/Makefile b/ap/build/uClibc/libc/misc/pthread/Makefile
new file mode 100644
index 0000000..4a8f4a0
--- /dev/null
+++ b/ap/build/uClibc/libc/misc/pthread/Makefile
@@ -0,0 +1,13 @@
+# Makefile for uClibc
+#
+# Copyright (C) 2000-2005 Erik Andersen <andersen@uclibc.org>
+#
+# Licensed under the LGPL v2.1, see the file COPYING.LIB in this tarball.
+#
+
+top_srcdir=../../../
+top_builddir=../../../
+all: objs
+include $(top_builddir)Rules.mak
+include Makefile.in
+include $(top_srcdir)Makerules
diff --git a/ap/build/uClibc/libc/misc/pthread/Makefile.in b/ap/build/uClibc/libc/misc/pthread/Makefile.in
new file mode 100644
index 0000000..2f436ac
--- /dev/null
+++ b/ap/build/uClibc/libc/misc/pthread/Makefile.in
@@ -0,0 +1,18 @@
+# Makefile for uClibc
+#
+# Copyright (C) 2000-2008 Erik Andersen <andersen@uclibc.org>
+#
+# Licensed under the LGPL v2.1, see the file COPYING.LIB in this tarball.
+#
+
+subdirs += libc/misc/pthread
+
+MISC_PTHREAD_DIR := $(top_srcdir)libc/misc/pthread
+MISC_PTHREAD_OUT := $(top_builddir)libc/misc/pthread
+
+libc-shared-$(UCLIBC_HAS_TLS) += $(MISC_PTHREAD_OUT)/tsd.os
+
+objclean-y += CLEAN_libc/misc/pthread
+
+CLEAN_libc/misc/pthread:
+ $(do_rm) $(addprefix $(MISC_PTHREAD_OUT)/*., o os oS)
diff --git a/ap/build/uClibc/libc/misc/pthread/tsd.c b/ap/build/uClibc/libc/misc/pthread/tsd.c
new file mode 100644
index 0000000..0c222e8
--- /dev/null
+++ b/ap/build/uClibc/libc/misc/pthread/tsd.c
@@ -0,0 +1,11 @@
+/* libpthread sets _dl_error_catch_tsd to point to this function.
+ We define it here instead of in libpthread so t here instead of in libpthread so that it doesn't
+ need to have a TLS segment of its own just for this one pointer. */
+
+void **__libc_dl_error_tsd(void) __attribute__ ((const));
+void ** __attribute__ ((const))
+__libc_dl_error_tsd (void)
+{
+ static __thread void *data __attribute__ ((tls_model ("initial-exec")));
+ return &data;
+}
diff --git a/ap/build/uClibc/libc/misc/regex/.indent.pro b/ap/build/uClibc/libc/misc/regex/.indent.pro
new file mode 100644
index 0000000..492ecf1
--- /dev/null
+++ b/ap/build/uClibc/libc/misc/regex/.indent.pro
@@ -0,0 +1,33 @@
+--blank-lines-after-declarations
+--blank-lines-after-procedures
+--break-before-boolean-operator
+--no-blank-lines-after-commas
+--braces-on-if-line
+--braces-on-struct-decl-line
+--comment-indentation25
+--declaration-comment-column25
+--no-comment-delimiters-on-blank-lines
+--cuddle-else
+--continuation-indentation4
+--case-indentation0
+--else-endif-column33
+--space-after-cast
+--line-comments-indentation0
+--declaration-indentation1
+--dont-format-first-column-comments
+--dont-format-comments
+--honour-newlines
+--indent-level4
+/* changed from 0 to 4 */
+--parameter-indentation4
+--line-length78 /* changed from 75 */
+--continue-at-parentheses
+--no-space-after-function-call-names
+--dont-break-procedure-type
+--dont-star-comments
+--leave-optional-blank-lines
+--dont-space-special-semicolon
+--tab-size4
+/* additions by Mark */
+--case-brace-indentation0
+--leave-preprocessor-space
diff --git a/ap/build/uClibc/libc/misc/regex/Makefile b/ap/build/uClibc/libc/misc/regex/Makefile
new file mode 100644
index 0000000..4a8f4a0
--- /dev/null
+++ b/ap/build/uClibc/libc/misc/regex/Makefile
@@ -0,0 +1,13 @@
+# Makefile for uClibc
+#
+# Copyright (C) 2000-2005 Erik Andersen <andersen@uclibc.org>
+#
+# Licensed under the LGPL v2.1, see the file COPYING.LIB in this tarball.
+#
+
+top_srcdir=../../../
+top_builddir=../../../
+all: objs
+include $(top_builddir)Rules.mak
+include Makefile.in
+include $(top_srcdir)Makerules
diff --git a/ap/build/uClibc/libc/misc/regex/Makefile.in b/ap/build/uClibc/libc/misc/regex/Makefile.in
new file mode 100644
index 0000000..9471023
--- /dev/null
+++ b/ap/build/uClibc/libc/misc/regex/Makefile.in
@@ -0,0 +1,27 @@
+# Makefile for uClibc
+#
+# Copyright (C) 2000-2008 Erik Andersen <andersen@uclibc.org>
+#
+# Licensed under the LGPL v2.1, see the file COPYING.LIB in this tarball.
+#
+
+subdirs += libc/misc/regex
+
+ifeq ($(UCLIBC_HAS_REGEX_OLD),y)
+CSRC := regex_old.c
+else
+CSRC := regex.c
+endif
+
+MISC_REGEX_DIR := $(top_srcdir)libc/misc/regex
+MISC_REGEX_OUT := $(top_builddir)libc/misc/regex
+
+MISC_REGEX_SRC := $(patsubst %.c,$(MISC_REGEX_DIR)/%.c,$(CSRC))
+MISC_REGEX_OBJ := $(patsubst %.c,$(MISC_REGEX_OUT)/%.o,$(CSRC))
+
+libc-$(UCLIBC_HAS_REGEX) += $(MISC_REGEX_OBJ)
+
+objclean-y += CLEAN_libc/misc/regex
+
+CLEAN_libc/misc/regex:
+ $(do_rm) $(addprefix $(MISC_REGEX_OUT)/*., o os)
diff --git a/ap/build/uClibc/libc/misc/regex/regcomp.c b/ap/build/uClibc/libc/misc/regex/regcomp.c
new file mode 100644
index 0000000..b25850c
--- /dev/null
+++ b/ap/build/uClibc/libc/misc/regex/regcomp.c
@@ -0,0 +1,3779 @@
+/* Extended regular expression matching and search library.
+ Copyright (C) 2002,2003,2004,2005,2006 Free Software Foundation, Inc.
+ This file is part of the GNU C Library.
+ Contributed by Isamu Hasegawa <isamu@yamato.ibm.com>.
+
+ The GNU C Library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 2.1 of the License, or (at your option) any later version.
+
+ The GNU C Library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with the GNU C Library; if not, write to the Free
+ Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+ 02111-1307 USA. */
+
+static reg_errcode_t re_compile_internal (regex_t *preg, const char * pattern,
+ size_t length, reg_syntax_t syntax);
+static void re_compile_fastmap_iter (regex_t *bufp,
+ const re_dfastate_t *init_state,
+ char *fastmap);
+static reg_errcode_t init_dfa (re_dfa_t *dfa, size_t pat_len);
+#ifdef RE_ENABLE_I18N
+static void free_charset (re_charset_t *cset);
+#endif
+static void free_workarea_compile (regex_t *preg);
+static reg_errcode_t create_initial_state (re_dfa_t *dfa);
+#ifdef RE_ENABLE_I18N
+static void optimize_utf8 (re_dfa_t *dfa);
+#endif
+static reg_errcode_t analyze (regex_t *preg);
+static reg_errcode_t preorder (bin_tree_t *root,
+ reg_errcode_t (fn (void *, bin_tree_t *)),
+ void *extra);
+static reg_errcode_t postorder (bin_tree_t *root,
+ reg_errcode_t (fn (void *, bin_tree_t *)),
+ void *extra);
+static reg_errcode_t optimize_subexps (void *extra, bin_tree_t *node);
+static reg_errcode_t lower_subexps (void *extra, bin_tree_t *node);
+static bin_tree_t *lower_subexp (reg_errcode_t *err, regex_t *preg,
+ bin_tree_t *node);
+static reg_errcode_t calc_first (void *extra, bin_tree_t *node);
+static reg_errcode_t calc_next (void *extra, bin_tree_t *node);
+static reg_errcode_t link_nfa_nodes (void *extra, bin_tree_t *node);
+static int duplicate_node (re_dfa_t *dfa, int org_idx, unsigned int constraint);
+static int search_duplicated_node (const re_dfa_t *dfa, int org_node,
+ unsigned int constraint);
+static reg_errcode_t calc_eclosure (re_dfa_t *dfa);
+static reg_errcode_t calc_eclosure_iter (re_node_set *new_set, re_dfa_t *dfa,
+ int node, int root);
+static reg_errcode_t calc_inveclosure (re_dfa_t *dfa);
+static int fetch_number (re_string_t *input, re_token_t *token,
+ reg_syntax_t syntax);
+static int peek_token (re_token_t *token, re_string_t *input,
+ reg_syntax_t syntax) internal_function;
+static bin_tree_t *parse (re_string_t *regexp, regex_t *preg,
+ reg_syntax_t syntax, reg_errcode_t *err);
+static bin_tree_t *parse_reg_exp (re_string_t *regexp, regex_t *preg,
+ re_token_t *token, reg_syntax_t syntax,
+ int nest, reg_errcode_t *err);
+static bin_tree_t *parse_branch (re_string_t *regexp, regex_t *preg,
+ re_token_t *token, reg_syntax_t syntax,
+ int nest, reg_errcode_t *err);
+static bin_tree_t *parse_expression (re_string_t *regexp, regex_t *preg,
+ re_token_t *token, reg_syntax_t syntax,
+ int nest, reg_errcode_t *err);
+static bin_tree_t *parse_sub_exp (re_string_t *regexp, regex_t *preg,
+ re_token_t *token, reg_syntax_t syntax,
+ int nest, reg_errcode_t *err);
+static bin_tree_t *parse_dup_op (bin_tree_t *dup_elem, re_string_t *regexp,
+ re_dfa_t *dfa, re_token_t *token,
+ reg_syntax_t syntax, reg_errcode_t *err);
+static bin_tree_t *parse_bracket_exp (re_string_t *regexp, re_dfa_t *dfa,
+ re_token_t *token, reg_syntax_t syntax,
+ reg_errcode_t *err);
+static reg_errcode_t 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);
+static reg_errcode_t parse_bracket_symbol (bracket_elem_t *elem,
+ re_string_t *regexp,
+ re_token_t *token);
+#ifdef RE_ENABLE_I18N
+static reg_errcode_t build_equiv_class (bitset_t sbcset,
+ re_charset_t *mbcset,
+ int *equiv_class_alloc,
+ const unsigned char *name);
+static reg_errcode_t build_charclass (RE_TRANSLATE_TYPE trans,
+ bitset_t sbcset,
+ re_charset_t *mbcset,
+ int *char_class_alloc,
+ const unsigned char *class_name,
+ reg_syntax_t syntax);
+#else /* not RE_ENABLE_I18N */
+static reg_errcode_t build_equiv_class (bitset_t sbcset,
+ const unsigned char *name);
+static reg_errcode_t build_charclass (RE_TRANSLATE_TYPE trans,
+ bitset_t sbcset,
+ const unsigned char *class_name,
+ reg_syntax_t syntax);
+#endif /* not RE_ENABLE_I18N */
+static bin_tree_t *build_charclass_op (re_dfa_t *dfa,
+ RE_TRANSLATE_TYPE trans,
+ const unsigned char *class_name,
+ const unsigned char *extra,
+ int non_match, reg_errcode_t *err);
+static bin_tree_t *create_tree (re_dfa_t *dfa,
+ bin_tree_t *left, bin_tree_t *right,
+ re_token_type_t type);
+static bin_tree_t *create_token_tree (re_dfa_t *dfa,
+ bin_tree_t *left, bin_tree_t *right,
+ const re_token_t *token);
+static bin_tree_t *duplicate_tree (const bin_tree_t *src, re_dfa_t *dfa);
+static void free_token (re_token_t *node);
+static reg_errcode_t free_tree (void *extra, bin_tree_t *node);
+static reg_errcode_t mark_opt_subexp (void *extra, bin_tree_t *node);
+
+/* 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[] =
+ {
+#define REG_NOERROR_IDX 0
+ gettext_noop ("Success") /* REG_NOERROR */
+ "\0"
+#define REG_NOMATCH_IDX (REG_NOERROR_IDX + sizeof "Success")
+ gettext_noop ("No match") /* REG_NOMATCH */
+ "\0"
+#define REG_BADPAT_IDX (REG_NOMATCH_IDX + sizeof "No match")
+ gettext_noop ("Invalid regular expression") /* REG_BADPAT */
+ "\0"
+#define REG_ECOLLATE_IDX (REG_BADPAT_IDX + sizeof "Invalid regular expression")
+ gettext_noop ("Invalid collation character") /* REG_ECOLLATE */
+ "\0"
+#define REG_ECTYPE_IDX (REG_ECOLLATE_IDX + sizeof "Invalid collation character")
+ gettext_noop ("Invalid character class name") /* REG_ECTYPE */
+ "\0"
+#define REG_EESCAPE_IDX (REG_ECTYPE_IDX + sizeof "Invalid character class name")
+ gettext_noop ("Trailing backslash") /* REG_EESCAPE */
+ "\0"
+#define REG_ESUBREG_IDX (REG_EESCAPE_IDX + sizeof "Trailing backslash")
+ gettext_noop ("Invalid back reference") /* REG_ESUBREG */
+ "\0"
+#define REG_EBRACK_IDX (REG_ESUBREG_IDX + sizeof "Invalid back reference")
+ gettext_noop ("Unmatched [ or [^") /* REG_EBRACK */
+ "\0"
+#define REG_EPAREN_IDX (REG_EBRACK_IDX + sizeof "Unmatched [ or [^")
+ gettext_noop ("Unmatched ( or \\(") /* REG_EPAREN */
+ "\0"
+#define REG_EBRACE_IDX (REG_EPAREN_IDX + sizeof "Unmatched ( or \\(")
+ gettext_noop ("Unmatched \\{") /* REG_EBRACE */
+ "\0"
+#define REG_BADBR_IDX (REG_EBRACE_IDX + sizeof "Unmatched \\{")
+ gettext_noop ("Invalid content of \\{\\}") /* REG_BADBR */
+ "\0"
+#define REG_ERANGE_IDX (REG_BADBR_IDX + sizeof "Invalid content of \\{\\}")
+ gettext_noop ("Invalid range end") /* REG_ERANGE */
+ "\0"
+#define REG_ESPACE_IDX (REG_ERANGE_IDX + sizeof "Invalid range end")
+ gettext_noop ("Memory exhausted") /* REG_ESPACE */
+ "\0"
+#define REG_BADRPT_IDX (REG_ESPACE_IDX + sizeof "Memory exhausted")
+ gettext_noop ("Invalid preceding regular expression") /* REG_BADRPT */
+ "\0"
+#define REG_EEND_IDX (REG_BADRPT_IDX + sizeof "Invalid preceding regular expression")
+ gettext_noop ("Premature end of regular expression") /* REG_EEND */
+ "\0"
+#define REG_ESIZE_IDX (REG_EEND_IDX + sizeof "Premature end of regular expression")
+ gettext_noop ("Regular expression too big") /* REG_ESIZE */
+ "\0"
+#define REG_ERPAREN_IDX (REG_ESIZE_IDX + sizeof "Regular expression too big")
+ gettext_noop ("Unmatched ) or \\)") /* REG_ERPAREN */
+ };
+
+static const uint16_t __re_error_msgid_idx[] =
+ {
+ REG_NOERROR_IDX,
+ REG_NOMATCH_IDX,
+ REG_BADPAT_IDX,
+ REG_ECOLLATE_IDX,
+ REG_ECTYPE_IDX,
+ REG_EESCAPE_IDX,
+ REG_ESUBREG_IDX,
+ REG_EBRACK_IDX,
+ REG_EPAREN_IDX,
+ REG_EBRACE_IDX,
+ REG_BADBR_IDX,
+ REG_ERANGE_IDX,
+ REG_ESPACE_IDX,
+ REG_BADRPT_IDX,
+ REG_EEND_IDX,
+ REG_ESIZE_IDX,
+ REG_ERPAREN_IDX
+ };
+
+/* Entry points for GNU code. */
+
+/* re_compile_pattern is the GNU regular expression compiler: it
+ compiles PATTERN (of length LENGTH) 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. */
+
+const char *
+re_compile_pattern (const char *pattern,
+ size_t length,
+ struct re_pattern_buffer *bufp)
+{
+ reg_errcode_t ret;
+
+ /* 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, unless RE_NO_SUB is set. */
+ bufp->no_sub = !!(re_syntax_options & RE_NO_SUB);
+
+ /* Match anchors at newline. */
+ bufp->newline_anchor = 1;
+
+ ret = re_compile_internal (bufp, pattern, length, re_syntax_options);
+
+ if (!ret)
+ return NULL;
+ return gettext (__re_error_msgid + __re_error_msgid_idx[(int) ret]);
+}
+
+/* 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;
+ return ret;
+}
+
+int
+re_compile_fastmap (struct re_pattern_buffer *bufp)
+{
+ re_dfa_t *dfa = (re_dfa_t *) bufp->buffer;
+ char *fastmap = bufp->fastmap;
+
+ memset (fastmap, '\0', sizeof (char) * SBC_MAX);
+ re_compile_fastmap_iter (bufp, dfa->init_state, fastmap);
+ if (dfa->init_state != dfa->init_state_word)
+ re_compile_fastmap_iter (bufp, dfa->init_state_word, fastmap);
+ if (dfa->init_state != dfa->init_state_nl)
+ re_compile_fastmap_iter (bufp, dfa->init_state_nl, fastmap);
+ if (dfa->init_state != dfa->init_state_begbuf)
+ re_compile_fastmap_iter (bufp, dfa->init_state_begbuf, fastmap);
+ bufp->fastmap_accurate = 1;
+ return 0;
+}
+libc_hidden_def(re_compile_fastmap)
+
+static __inline__ void
+__attribute ((always_inline))
+re_set_fastmap (char *fastmap, int icase, int ch)
+{
+ fastmap[ch] = 1;
+ if (icase)
+ fastmap[tolower (ch)] = 1;
+}
+
+/* Helper function for re_compile_fastmap.
+ Compile fastmap for the initial_state INIT_STATE. */
+
+static void
+re_compile_fastmap_iter (regex_t *bufp, const re_dfastate_t *init_state,
+ char *fastmap)
+{
+ re_dfa_t *dfa = (re_dfa_t *) bufp->buffer;
+ int node_cnt;
+ int icase = (dfa->mb_cur_max == 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];
+ re_token_type_t type = dfa->nodes[node].type;
+
+ if (type == CHARACTER)
+ {
+ re_set_fastmap (fastmap, icase, dfa->nodes[node].opr.c);
+#ifdef RE_ENABLE_I18N
+ if ((bufp->syntax & RE_ICASE) && dfa->mb_cur_max > 1)
+ {
+ unsigned char *buf = alloca (dfa->mb_cur_max), *p;
+ wchar_t wc;
+ mbstate_t state;
+
+ p = buf;
+ *p++ = dfa->nodes[node].opr.c;
+ while (++node < dfa->nodes_len
+ && dfa->nodes[node].type == CHARACTER
+ && dfa->nodes[node].mb_partial)
+ *p++ = dfa->nodes[node].opr.c;
+ memset (&state, '\0', sizeof (state));
+ if (mbrtowc (&wc, (const char *) buf, p - buf,
+ &state) == p - buf
+ && (__wcrtomb ((char *) buf, towlower (wc), &state)
+ != (size_t) -1))
+ re_set_fastmap (fastmap, 0, buf[0]);
+ }
+#endif
+ }
+ else if (type == SIMPLE_BRACKET)
+ {
+ int i, ch;
+ for (i = 0, ch = 0; i < BITSET_WORDS; ++i)
+ {
+ int j;
+ bitset_word_t w = dfa->nodes[node].opr.sbcset[i];
+ for (j = 0; j < BITSET_WORD_BITS; ++j, ++ch)
+ if (w & ((bitset_word_t) 1 << j))
+ re_set_fastmap (fastmap, icase, ch);
+ }
+ }
+#ifdef RE_ENABLE_I18N
+ else if (type == COMPLEX_BRACKET)
+ {
+ int i;
+ re_charset_t *cset = dfa->nodes[node].opr.mbcset;
+ if (cset->non_match || cset->ncoll_syms || cset->nequiv_classes
+ || cset->nranges || cset->nchar_classes)
+ {
+# if 0
+ if (_NL_CURRENT_WORD (LC_COLLATE, _NL_COLLATE_NRULES) != 0)
+ {
+ /* In this case we want to catch the bytes which are
+ the first byte of any collation elements.
+ e.g. In da_DK, we want to catch 'a' since "aa"
+ is a valid collation element, and don't catch
+ 'b' since 'b' is the only collation element
+ which starts from 'b'. */
+ const int32_t *table = (const int32_t *)
+ _NL_CURRENT (LC_COLLATE, _NL_COLLATE_TABLEMB);
+ for (i = 0; i < SBC_MAX; ++i)
+ if (table[i] < 0)
+ re_set_fastmap (fastmap, icase, i);
+ }
+# else
+ if (dfa->mb_cur_max > 1)
+ for (i = 0; i < SBC_MAX; ++i)
+ if (__btowc (i) == WEOF)
+ re_set_fastmap (fastmap, icase, i);
+# endif
+ }
+ for (i = 0; i < cset->nmbchars; ++i)
+ {
+ char buf[256];
+ mbstate_t 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 (__wcrtomb (buf, towlower (cset->mbchars[i]), &state)
+ != (size_t) -1)
+ re_set_fastmap (fastmap, 0, *(unsigned char *) buf);
+ }
+ }
+ }
+#endif /* RE_ENABLE_I18N */
+ else if (type == OP_PERIOD
+#ifdef RE_ENABLE_I18N
+ || type == OP_UTF8_PERIOD
+#endif
+ || type == END_OF_RE)
+ {
+ memset (fastmap, '\1', sizeof (char) * SBC_MAX);
+ if (type == END_OF_RE)
+ bufp->can_be_null = 1;
+ return;
+ }
+ }
+}
+
+/* Entry point for POSIX code. */
+/* 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 *__restrict preg,
+ const char *__restrict pattern,
+ int cflags)
+{
+ reg_errcode_t ret;
+ reg_syntax_t syntax = ((cflags & REG_EXTENDED) ? RE_SYNTAX_POSIX_EXTENDED
+ : RE_SYNTAX_POSIX_BASIC);
+
+ preg->buffer = NULL;
+ preg->allocated = 0;
+ preg->used = 0;
+
+ /* Try to allocate space for the fastmap. */
+ preg->fastmap = re_malloc (char, SBC_MAX);
+ if (BE (preg->fastmap == NULL, 0))
+ return REG_ESPACE;
+
+ syntax |= (cflags & REG_ICASE) ? RE_ICASE : 0;
+
+ /* 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);
+ preg->translate = NULL;
+
+ ret = re_compile_internal (preg, pattern, strlen (pattern), syntax);
+
+ /* 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;
+
+ /* We have already checked preg->fastmap != NULL. */
+ if (BE (ret == REG_NOERROR, 1))
+ /* Compute the fastmap now, since regexec cannot modify the pattern
+ buffer. This function never fails in this implementation. */
+ (void) re_compile_fastmap (preg);
+ else
+ {
+ /* Some error occurred while compiling the expression. */
+ re_free (preg->fastmap);
+ preg->fastmap = NULL;
+ }
+
+ return (int) ret;
+}
+
+/* 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 *__restrict preg,
+ char *__restrict errbuf,
+ size_t errbuf_size)
+{
+ const char *msg;
+ size_t msg_size;
+
+ if (BE (errcode < 0
+ || errcode >= (int) (sizeof (__re_error_msgid_idx)
+ / sizeof (__re_error_msgid_idx[0])), 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 + __re_error_msgid_idx[errcode]);
+
+ msg_size = strlen (msg) + 1; /* Includes the null. */
+
+ if (BE (errbuf_size != 0, 1))
+ {
+ if (BE (msg_size > errbuf_size, 0))
+ {
+ memcpy (errbuf, msg, errbuf_size - 1);
+ errbuf[errbuf_size - 1] = 0;
+ }
+ else
+ memcpy (errbuf, msg, msg_size);
+ }
+
+ return msg_size;
+}
+
+
+#ifdef RE_ENABLE_I18N
+/* This static array is used for the map to single-byte characters when
+ UTF-8 is used. Otherwise we would allocate memory just to initialize
+ it the same all the time. UTF-8 is the preferred encoding so this is
+ a worthwhile optimization. */
+static const bitset_t utf8_sb_map =
+{
+ /* Set the first 128 bits. */
+ [0 ... 0x80 / BITSET_WORD_BITS - 1] = BITSET_WORD_MAX
+};
+#endif
+
+
+static void
+free_dfa_content (re_dfa_t *dfa)
+{
+ int i, j;
+
+ if (dfa->nodes)
+ for (i = 0; i < dfa->nodes_len; ++i)
+ free_token (dfa->nodes + i);
+ re_free (dfa->nexts);
+ for (i = 0; i < dfa->nodes_len; ++i)
+ {
+ if (dfa->eclosures != NULL)
+ re_node_set_free (dfa->eclosures + i);
+ if (dfa->inveclosures != NULL)
+ re_node_set_free (dfa->inveclosures + i);
+ if (dfa->edests != NULL)
+ re_node_set_free (dfa->edests + i);
+ }
+ re_free (dfa->edests);
+ re_free (dfa->eclosures);
+ re_free (dfa->inveclosures);
+ re_free (dfa->nodes);
+
+ if (dfa->state_table)
+ for (i = 0; i <= dfa->state_hash_mask; ++i)
+ {
+ struct re_state_table_entry *entry = dfa->state_table + i;
+ for (j = 0; j < entry->num; ++j)
+ {
+ re_dfastate_t *state = entry->array[j];
+ free_state (state);
+ }
+ re_free (entry->array);
+ }
+ re_free (dfa->state_table);
+#ifdef RE_ENABLE_I18N
+ if (dfa->sb_char != utf8_sb_map)
+ re_free (dfa->sb_char);
+#endif
+ re_free (dfa->subexp_map);
+#ifdef DEBUG
+ re_free (dfa->re_str);
+#endif
+
+ re_free (dfa);
+}
+
+
+/* Free dynamically allocated space used by PREG. */
+
+void
+regfree (regex_t *preg)
+{
+ re_dfa_t *dfa = (re_dfa_t *) preg->buffer;
+ if (BE (dfa != NULL, 1))
+ free_dfa_content (dfa);
+ preg->buffer = NULL;
+ preg->allocated = 0;
+
+ re_free (preg->fastmap);
+ preg->fastmap = NULL;
+
+ re_free (preg->translate);
+ preg->translate = NULL;
+}
+libc_hidden_def(regfree)
+
+/* Entry points compatible with 4.2 BSD regex library. We don't define
+ them unless specifically requested. */
+
+#if defined _REGEX_RE_COMP || defined __UCLIBC__
+
+/* BSD has one and only one pattern buffer. */
+static struct re_pattern_buffer *re_comp_buf;
+
+char *
+/* Make BCD definitions weak in libc, so POSIX programs can redefine
+ these names if they don't use our functions, and still use
+ regcomp/regexec above without link errors. */
+weak_function
+re_comp (const char *s)
+{
+ reg_errcode_t ret;
+
+ /* "If re_comp() is passed NULL or a null string, it returns
+ * without changing the currently compiled regular expression." */
+ if (!s || !s[0])
+ {
+ if (!re_comp_buf)
+ return gettext ("No previous regular expression");
+ return NULL;
+ }
+
+ if (!re_comp_buf)
+ {
+ re_comp_buf = calloc (1, sizeof(*re_comp_buf));
+ if (!re_comp_buf)
+ {
+ ret = REG_ESPACE;
+ goto err;
+ }
+ }
+
+ if (re_comp_buf->buffer)
+ {
+ regfree (re_comp_buf);
+ memset (re_comp_buf, '\0', sizeof(*re_comp_buf));
+ }
+
+ if (re_comp_buf->fastmap == NULL)
+ {
+ re_comp_buf->fastmap = malloc (SBC_MAX);
+ if (re_comp_buf->fastmap == NULL)
+ {
+ ret = REG_ESPACE;
+ goto err;
+ }
+ }
+
+ /* 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;
+
+ ret = re_compile_internal (re_comp_buf, s, strlen (s), re_syntax_options);
+
+ if (!ret)
+ return NULL;
+ free (re_comp_buf);
+ re_comp_buf = NULL;
+
+ err:
+ /* Yes, we're discarding `const' here if !HAVE_LIBINTL. */
+ return (char *) gettext (__re_error_msgid + __re_error_msgid_idx[(int) ret]);
+}
+
+#if 0
+libc_freeres_fn (free_mem)
+{
+ regfree (re_comp_buf);
+ free (re_comp_buf);
+ re_comp_buf = NULL;
+}
+#endif
+
+#endif /* _REGEX_RE_COMP */
+
+/* Internal entry point.
+ Compile the regular expression PATTERN, whose length is LENGTH.
+ SYNTAX indicate regular expression's syntax. */
+
+static reg_errcode_t
+re_compile_internal (regex_t *preg, const char * pattern, size_t length,
+ reg_syntax_t syntax)
+{
+ reg_errcode_t err = REG_NOERROR;
+ re_dfa_t *dfa;
+ re_string_t regexp;
+
+ /* Initialize the pattern buffer. */
+ preg->fastmap_accurate = 0;
+ preg->syntax = syntax;
+ preg->not_bol = preg->not_eol = 0;
+ preg->used = 0;
+ preg->re_nsub = 0;
+ preg->can_be_null = 0;
+ preg->regs_allocated = REGS_UNALLOCATED;
+
+ /* Initialize the dfa. */
+ dfa = (re_dfa_t *) preg->buffer;
+ if (BE (preg->allocated < sizeof (re_dfa_t), 0))
+ {
+ /* 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. If ->buffer is NULL this
+ is a simple allocation. */
+ dfa = re_realloc (preg->buffer, re_dfa_t, 1);
+ if (dfa == NULL)
+ return REG_ESPACE;
+ preg->allocated = sizeof (re_dfa_t);
+ preg->buffer = (unsigned char *) dfa;
+ }
+ preg->used = sizeof (re_dfa_t);
+
+ err = init_dfa (dfa, length);
+ if (BE (err != REG_NOERROR, 0))
+ {
+ free_dfa_content (dfa);
+ preg->buffer = NULL;
+ preg->allocated = 0;
+ return err;
+ }
+#ifdef DEBUG
+ /* Note: length+1 will not overflow since it is checked in init_dfa. */
+ dfa->re_str = re_malloc (char, length + 1);
+ strncpy (dfa->re_str, pattern, length + 1);
+#endif
+
+ __libc_lock_init (dfa->lock);
+
+ err = re_string_construct (®exp, pattern, length, preg->translate,
+ syntax & RE_ICASE, dfa);
+ if (BE (err != REG_NOERROR, 0))
+ {
+ re_compile_internal_free_return:
+ free_workarea_compile (preg);
+ re_string_destruct (®exp);
+ free_dfa_content (dfa);
+ preg->buffer = NULL;
+ preg->allocated = 0;
+ return err;
+ }
+
+ /* Parse the regular expression, and build a structure tree. */
+ preg->re_nsub = 0;
+ dfa->str_tree = parse (®exp, preg, syntax, &err);
+ if (BE (dfa->str_tree == NULL, 0))
+ goto re_compile_internal_free_return;
+
+ /* Analyze the tree and create the nfa. */
+ err = analyze (preg);
+ if (BE (err != REG_NOERROR, 0))
+ goto re_compile_internal_free_return;
+
+#ifdef RE_ENABLE_I18N
+ /* If possible, do searching in single byte encoding to speed things up. */
+ if (dfa->is_utf8 && !(syntax & RE_ICASE) && preg->translate == NULL)
+ optimize_utf8 (dfa);
+#endif
+
+ /* Then create the initial state of the dfa. */
+ err = create_initial_state (dfa);
+
+ /* Release work areas. */
+ free_workarea_compile (preg);
+ re_string_destruct (®exp);
+
+ if (BE (err != REG_NOERROR, 0))
+ {
+ free_dfa_content (dfa);
+ preg->buffer = NULL;
+ preg->allocated = 0;
+ }
+
+ return err;
+}
+
+/* Initialize DFA. We use the length of the regular expression PAT_LEN
+ as the initial length of some arrays. */
+
+static reg_errcode_t
+init_dfa (re_dfa_t *dfa, size_t pat_len)
+{
+ unsigned int table_size;
+#if 1
+ char *codeset_name;
+#endif
+
+ memset (dfa, '\0', sizeof (re_dfa_t));
+
+ /* Force allocation of str_tree_storage the first time. */
+ dfa->str_tree_storage_idx = BIN_TREE_STORAGE_SIZE;
+
+ /* Avoid overflows. */
+ if (pat_len == SIZE_MAX)
+ return REG_ESPACE;
+
+ dfa->nodes_alloc = pat_len + 1;
+ dfa->nodes = re_malloc (re_token_t, dfa->nodes_alloc);
+
+ /* table_size = 2 ^ ceil(log pat_len) */
+ for (table_size = 1; ; table_size <<= 1)
+ if (table_size > pat_len)
+ break;
+
+ dfa->state_table = calloc (sizeof (struct re_state_table_entry), table_size);
+ dfa->state_hash_mask = table_size - 1;
+
+ dfa->mb_cur_max = MB_CUR_MAX;
+#if 0
+ if (dfa->mb_cur_max == 6
+ && strcmp (_NL_CURRENT (LC_CTYPE, _NL_CTYPE_CODESET_NAME), "UTF-8") == 0)
+ dfa->is_utf8 = 1;
+ dfa->map_notascii = (_NL_CURRENT_WORD (LC_CTYPE, _NL_CTYPE_MAP_TO_NONASCII)
+ != 0);
+#else
+# ifdef HAVE_LANGINFO_CODESET
+ codeset_name = nl_langinfo (CODESET);
+# else
+ codeset_name = getenv ("LC_ALL");
+ if (codeset_name == NULL || codeset_name[0] == '\0')
+ codeset_name = getenv ("LC_CTYPE");
+ if (codeset_name == NULL || codeset_name[0] == '\0')
+ codeset_name = getenv ("LANG");
+ if (codeset_name == NULL)
+ codeset_name = "";
+ else if (strchr (codeset_name, '.') != NULL)
+ codeset_name = strchr (codeset_name, '.') + 1;
+# endif
+
+ if (strcasecmp (codeset_name, "UTF-8") == 0
+ || strcasecmp (codeset_name, "UTF8") == 0)
+ dfa->is_utf8 = 1;
+
+ /* We check exhaustively in the loop below if this charset is a
+ superset of ASCII. */
+ dfa->map_notascii = 0;
+#endif
+
+#ifdef RE_ENABLE_I18N
+ if (dfa->mb_cur_max > 1)
+ {
+ if (dfa->is_utf8)
+ dfa->sb_char = (re_bitset_ptr_t) utf8_sb_map;
+ else
+ {
+ int i, j, ch;
+
+ dfa->sb_char = calloc (sizeof (bitset_t), 1);
+ if (BE (dfa->sb_char == NULL, 0))
+ return REG_ESPACE;
+
+ /* Set the bits corresponding to single byte chars. */
+ for (i = 0, ch = 0; i < BITSET_WORDS; ++i)
+ for (j = 0; j < BITSET_WORD_BITS; ++j, ++ch)
+ {
+ wint_t wch = __btowc (ch);
+ if (wch != WEOF)
+ dfa->sb_char[i] |= (bitset_word_t) 1 << j;
+# if 1
+ if (isascii (ch) && wch != ch)
+ dfa->map_notascii = 1;
+# endif
+ }
+ }
+ }
+#endif
+
+ if (BE (dfa->nodes == NULL || dfa->state_table == NULL, 0))
+ return REG_ESPACE;
+ return REG_NOERROR;
+}
+
+/* Initialize WORD_CHAR table, which indicate which character is
+ "word". In this case "word" means that it is the word construction
+ character used by some operators like "\<", "\>", etc. */
+
+static void
+internal_function
+init_word_char (re_dfa_t *dfa)
+{
+ int i, j, ch;
+ dfa->word_ops_used = 1;
+ for (i = 0, ch = 0; i < BITSET_WORDS; ++i)
+ for (j = 0; j < BITSET_WORD_BITS; ++j, ++ch)
+ if (isalnum (ch) || ch == '_')
+ dfa->word_char[i] |= (bitset_word_t) 1 << j;
+}
+
+/* Free the work area which are only used while compiling. */
+
+static void
+free_workarea_compile (regex_t *preg)
+{
+ re_dfa_t *dfa = (re_dfa_t *) preg->buffer;
+ bin_tree_storage_t *storage, *next;
+ for (storage = dfa->str_tree_storage; storage; storage = next)
+ {
+ next = storage->next;
+ re_free (storage);
+ }
+ dfa->str_tree_storage = NULL;
+ dfa->str_tree_storage_idx = BIN_TREE_STORAGE_SIZE;
+ dfa->str_tree = NULL;
+ re_free (dfa->org_indices);
+ dfa->org_indices = NULL;
+}
+
+/* Create initial states for all contexts. */
+
+static reg_errcode_t
+create_initial_state (re_dfa_t *dfa)
+{
+ int first, i;
+ reg_errcode_t err;
+ re_node_set init_nodes;
+
+ /* Initial states have the epsilon closure of the node which is
+ the first node of the regular expression. */
+ first = dfa->str_tree->first->node_idx;
+ dfa->init_node = first;
+ err = re_node_set_init_copy (&init_nodes, dfa->eclosures + first);
+ if (BE (err != REG_NOERROR, 0))
+ return err;
+
+ /* The back-references which are in initial states can epsilon transit,
+ since in this case all of the subexpressions can be null.
+ Then we add epsilon closures of the nodes which are the next nodes of
+ the back-references. */
+ if (dfa->nbackref > 0)
+ for (i = 0; i < init_nodes.nelem; ++i)
+ {
+ int node_idx = init_nodes.elems[i];
+ re_token_type_t type = dfa->nodes[node_idx].type;
+
+ int clexp_idx;
+ if (type != OP_BACK_REF)
+ continue;
+ for (clexp_idx = 0; clexp_idx < init_nodes.nelem; ++clexp_idx)
+ {
+ re_token_t *clexp_node;
+ clexp_node = dfa->nodes + init_nodes.elems[clexp_idx];
+ if (clexp_node->type == OP_CLOSE_SUBEXP
+ && clexp_node->opr.idx == dfa->nodes[node_idx].opr.idx)
+ break;
+ }
+ if (clexp_idx == init_nodes.nelem)
+ continue;
+
+ if (type == OP_BACK_REF)
+ {
+ int dest_idx = dfa->edests[node_idx].elems[0];
+ if (!re_node_set_contains (&init_nodes, dest_idx))
+ {
+ re_node_set_merge (&init_nodes, dfa->eclosures + dest_idx);
+ i = 0;
+ }
+ }
+ }
+
+ /* It must be the first time to invoke acquire_state. */
+ dfa->init_state = re_acquire_state_context (&err, dfa, &init_nodes, 0);
+ /* We don't check ERR here, since the initial state must not be NULL. */
+ if (BE (dfa->init_state == NULL, 0))
+ return err;
+ if (dfa->init_state->has_constraint)
+ {
+ dfa->init_state_word = re_acquire_state_context (&err, dfa, &init_nodes,
+ CONTEXT_WORD);
+ dfa->init_state_nl = re_acquire_state_context (&err, dfa, &init_nodes,
+ CONTEXT_NEWLINE);
+ dfa->init_state_begbuf = re_acquire_state_context (&err, dfa,
+ &init_nodes,
+ CONTEXT_NEWLINE
+ | CONTEXT_BEGBUF);
+ if (BE (dfa->init_state_word == NULL || dfa->init_state_nl == NULL
+ || dfa->init_state_begbuf == NULL, 0))
+ return err;
+ }
+ else
+ dfa->init_state_word = dfa->init_state_nl
+ = dfa->init_state_begbuf = dfa->init_state;
+
+ re_node_set_free (&init_nodes);
+ return REG_NOERROR;
+}
+
+#ifdef RE_ENABLE_I18N
+/* If it is possible to do searching in single byte encoding instead of UTF-8
+ to speed things up, set dfa->mb_cur_max to 1, clear is_utf8 and change
+ DFA nodes where needed. */
+
+static void
+optimize_utf8 (re_dfa_t *dfa)
+{
+ int node, i, mb_chars = 0, has_period = 0;
+
+ for (node = 0; node < dfa->nodes_len; ++node)
+ switch (dfa->nodes[node].type)
+ {
+ case CHARACTER:
+ if (dfa->nodes[node].opr.c >= 0x80)
+ mb_chars = 1;
+ break;
+ case ANCHOR:
+ switch (dfa->nodes[node].opr.idx)
+ {
+ case LINE_FIRST:
+ case LINE_LAST:
+ case BUF_FIRST:
+ case BUF_LAST:
+ break;
+ default:
+ /* Word anchors etc. cannot be handled. */
+ return;
+ }
+ break;
+ case OP_PERIOD:
+ has_period = 1;
+ break;
+ case OP_BACK_REF:
+ case OP_ALT:
+ case END_OF_RE:
+ case OP_DUP_ASTERISK:
+ case OP_OPEN_SUBEXP:
+ case OP_CLOSE_SUBEXP:
+ break;
+ case COMPLEX_BRACKET:
+ return;
+ case SIMPLE_BRACKET:
+ /* Just double check. The non-ASCII range starts at 0x80. */
+ assert (0x80 % BITSET_WORD_BITS == 0);
+ for (i = 0x80 / BITSET_WORD_BITS; i < BITSET_WORDS; ++i)
+ if (dfa->nodes[node].opr.sbcset[i])
+ return;
+ break;
+ default:
+ abort ();
+ }
+
+ if (mb_chars || has_period)
+ for (node = 0; node < dfa->nodes_len; ++node)
+ {
+ if (dfa->nodes[node].type == CHARACTER
+ && dfa->nodes[node].opr.c >= 0x80)
+ dfa->nodes[node].mb_partial = 0;
+ else if (dfa->nodes[node].type == OP_PERIOD)
+ dfa->nodes[node].type = OP_UTF8_PERIOD;
+ }
+
+ /* The search can be in single byte locale. */
+ dfa->mb_cur_max = 1;
+ dfa->is_utf8 = 0;
+ dfa->has_mb_node = dfa->nbackref > 0 || has_period;
+}
+#endif
+
+/* Analyze the structure tree, and calculate "first", "next", "edest",
+ "eclosure", and "inveclosure". */
+
+static reg_errcode_t
+analyze (regex_t *preg)
+{
+ re_dfa_t *dfa = (re_dfa_t *) preg->buffer;
+ reg_errcode_t ret;
+
+ /* Allocate arrays. */
+ dfa->nexts = re_malloc (int, dfa->nodes_alloc);
+ dfa->org_indices = re_malloc (int, dfa->nodes_alloc);
+ dfa->edests = re_malloc (re_node_set, dfa->nodes_alloc);
+ dfa->eclosures = re_malloc (re_node_set, dfa->nodes_alloc);
+ if (BE (dfa->nexts == NULL || dfa->org_indices == NULL || dfa->edests == NULL
+ || dfa->eclosures == NULL, 0))
+ return REG_ESPACE;
+
+ dfa->subexp_map = re_malloc (int, preg->re_nsub);
+ if (dfa->subexp_map != NULL)
+ {
+ int i;
+ for (i = 0; i < preg->re_nsub; i++)
+ dfa->subexp_map[i] = i;
+ preorder (dfa->str_tree, optimize_subexps, dfa);
+ for (i = 0; i < preg->re_nsub; i++)
+ if (dfa->subexp_map[i] != i)
+ break;
+ if (i == preg->re_nsub)
+ {
+ free (dfa->subexp_map);
+ dfa->subexp_map = NULL;
+ }
+ }
+
+ ret = postorder (dfa->str_tree, lower_subexps, preg);
+ if (BE (ret != REG_NOERROR, 0))
+ return ret;
+ ret = postorder (dfa->str_tree, calc_first, dfa);
+ if (BE (ret != REG_NOERROR, 0))
+ return ret;
+ preorder (dfa->str_tree, calc_next, dfa);
+ ret = preorder (dfa->str_tree, link_nfa_nodes, dfa);
+ if (BE (ret != REG_NOERROR, 0))
+ return ret;
+ ret = calc_eclosure (dfa);
+ if (BE (ret != REG_NOERROR, 0))
+ return ret;
+
+ /* We only need this during the prune_impossible_nodes pass in regexec.c;
+ skip it if p_i_n will not run, as calc_inveclosure can be quadratic. */
+ if ((!preg->no_sub && preg->re_nsub > 0 && dfa->has_plural_match)
+ || dfa->nbackref)
+ {
+ dfa->inveclosures = re_malloc (re_node_set, dfa->nodes_len);
+ if (BE (dfa->inveclosures == NULL, 0))
+ return REG_ESPACE;
+ ret = calc_inveclosure (dfa);
+ }
+
+ return ret;
+}
+
+/* Our parse trees are very unbalanced, so we cannot use a stack to
+ implement parse tree visits. Instead, we use parent pointers and
+ some hairy code in these two functions. */
+static reg_errcode_t
+postorder (bin_tree_t *root, reg_errcode_t (fn (void *, bin_tree_t *)),
+ void *extra)
+{
+ bin_tree_t *node, *prev;
+
+ for (node = root; ; )
+ {
+ /* Descend down the tree, preferably to the left (or to the right
+ if that's the only child). */
+ while (node->left || node->right)
+ if (node->left)
+ node = node->left;
+ else
+ node = node->right;
+
+ do
+ {
+ reg_errcode_t err = fn (extra, node);
+ if (BE (err != REG_NOERROR, 0))
+ return err;
+ if (node->parent == NULL)
+ return REG_NOERROR;
+ prev = node;
+ node = node->parent;
+ }
+ /* Go up while we have a node that is reached from the right. */
+ while (node->right == prev || node->right == NULL);
+ node = node->right;
+ }
+}
+
+static reg_errcode_t
+preorder (bin_tree_t *root, reg_errcode_t (fn (void *, bin_tree_t *)),
+ void *extra)
+{
+ bin_tree_t *node;
+
+ for (node = root; ; )
+ {
+ reg_errcode_t err = fn (extra, node);
+ if (BE (err != REG_NOERROR, 0))
+ return err;
+
+ /* Go to the left node, or up and to the right. */
+ if (node->left)
+ node = node->left;
+ else
+ {
+ bin_tree_t *prev = NULL;
+ while (node->right == prev || node->right == NULL)
+ {
+ prev = node;
+ node = node->parent;
+ if (!node)
+ return REG_NOERROR;
+ }
+ node = node->right;
+ }
+ }
+}
+
+/* Optimization pass: if a SUBEXP is entirely contained, strip it and tell
+ re_search_internal to map the inner one's opr.idx to this one's. Adjust
+ backreferences as well. Requires a preorder visit. */
+static reg_errcode_t
+optimize_subexps (void *extra, bin_tree_t *node)
+{
+ re_dfa_t *dfa = (re_dfa_t *) extra;
+
+ if (node->token.type == OP_BACK_REF && dfa->subexp_map)
+ {
+ int idx = node->token.opr.idx;
+ node->token.opr.idx = dfa->subexp_map[idx];
+ dfa->used_bkref_map |= 1 << node->token.opr.idx;
+ }
+
+ else if (node->token.type == SUBEXP
+ && node->left && node->left->token.type == SUBEXP)
+ {
+ int other_idx = node->left->token.opr.idx;
+
+ node->left = node->left->left;
+ if (node->left)
+ node->left->parent = node;
+
+ dfa->subexp_map[other_idx] = dfa->subexp_map[node->token.opr.idx];
+ if (other_idx < BITSET_WORD_BITS)
+ dfa->used_bkref_map &= ~((bitset_word_t) 1 << other_idx);
+ }
+
+ return REG_NOERROR;
+}
+
+/* Lowering pass: Turn each SUBEXP node into the appropriate concatenation
+ of OP_OPEN_SUBEXP, the body of the SUBEXP (if any) and OP_CLOSE_SUBEXP. */
+static reg_errcode_t
+lower_subexps (void *extra, bin_tree_t *node)
+{
+ regex_t *preg = (regex_t *) extra;
+ reg_errcode_t err = REG_NOERROR;
+
+ if (node->left && node->left->token.type == SUBEXP)
+ {
+ node->left = lower_subexp (&err, preg, node->left);
+ if (node->left)
+ node->left->parent = node;
+ }
+ if (node->right && node->right->token.type == SUBEXP)
+ {
+ node->right = lower_subexp (&err, preg, node->right);
+ if (node->right)
+ node->right->parent = node;
+ }
+
+ return err;
+}
+
+static bin_tree_t *
+lower_subexp (reg_errcode_t *err, regex_t *preg, bin_tree_t *node)
+{
+ re_dfa_t *dfa = (re_dfa_t *) preg->buffer;
+ bin_tree_t *body = node->left;
+ bin_tree_t *op, *cls, *tree1, *tree;
+
+ if (preg->no_sub
+ /* We do not optimize empty subexpressions, because otherwise we may
+ have bad CONCAT nodes with NULL children. This is obviously not
+ very common, so we do not lose much. An example that triggers
+ this case is the sed "script" /\(\)/x. */
+ && node->left != NULL
+ && (node->token.opr.idx >= BITSET_WORD_BITS
+ || !(dfa->used_bkref_map
+ & ((bitset_word_t) 1 << node->token.opr.idx))))
+ return node->left;
+
+ /* Convert the SUBEXP node to the concatenation of an
+ OP_OPEN_SUBEXP, the contents, and an OP_CLOSE_SUBEXP. */
+ op = create_tree (dfa, NULL, NULL, OP_OPEN_SUBEXP);
+ cls = create_tree (dfa, NULL, NULL, OP_CLOSE_SUBEXP);
+ tree1 = body ? create_tree (dfa, body, cls, CONCAT) : cls;
+ tree = create_tree (dfa, op, tree1, CONCAT);
+ if (BE (tree == NULL || tree1 == NULL || op == NULL || cls == NULL, 0))
+ {
+ *err = REG_ESPACE;
+ return NULL;
+ }
+
+ op->token.opr.idx = cls->token.opr.idx = node->token.opr.idx;
+ op->token.opt_subexp = cls->token.opt_subexp = node->token.opt_subexp;
+ return tree;
+}
+
+/* Pass 1 in building the NFA: compute FIRST and create unlinked automaton
+ nodes. Requires a postorder visit. */
+static reg_errcode_t
+calc_first (void *extra, bin_tree_t *node)
+{
+ re_dfa_t *dfa = (re_dfa_t *) extra;
+ if (node->token.type == CONCAT)
+ {
+ node->first = node->left->first;
+ node->node_idx = node->left->node_idx;
+ }
+ else
+ {
+ node->first = node;
+ node->node_idx = re_dfa_add_node (dfa, node->token);
+ if (BE (node->node_idx == -1, 0))
+ return REG_ESPACE;
+ }
+ return REG_NOERROR;
+}
+
+/* Pass 2: compute NEXT on the tree. Preorder visit. */
+static reg_errcode_t
+calc_next (void *extra, bin_tree_t *node)
+{
+ switch (node->token.type)
+ {
+ case OP_DUP_ASTERISK:
+ node->left->next = node;
+ break;
+ case CONCAT:
+ node->left->next = node->right->first;
+ node->right->next = node->next;
+ break;
+ default:
+ if (node->left)
+ node->left->next = node->next;
+ if (node->right)
+ node->right->next = node->next;
+ break;
+ }
+ return REG_NOERROR;
+}
+
+/* Pass 3: link all DFA nodes to their NEXT node (any order will do). */
+static reg_errcode_t
+link_nfa_nodes (void *extra, bin_tree_t *node)
+{
+ re_dfa_t *dfa = (re_dfa_t *) extra;
+ int idx = node->node_idx;
+ reg_errcode_t err = REG_NOERROR;
+
+ switch (node->token.type)
+ {
+ case CONCAT:
+ break;
+
+ case END_OF_RE:
+ assert (node->next == NULL);
+ break;
+
+ case OP_DUP_ASTERISK:
+ case OP_ALT:
+ {
+ int left, right;
+ dfa->has_plural_match = 1;
+ if (node->left != NULL)
+ left = node->left->first->node_idx;
+ else
+ left = node->next->node_idx;
+ if (node->right != NULL)
+ right = node->right->first->node_idx;
+ else
+ right = node->next->node_idx;
+ assert (left > -1);
+ assert (right > -1);
+ err = re_node_set_init_2 (dfa->edests + idx, left, right);
+ }
+ break;
+
+ case ANCHOR:
+ case OP_OPEN_SUBEXP:
+ case OP_CLOSE_SUBEXP:
+ err = re_node_set_init_1 (dfa->edests + idx, node->next->node_idx);
+ break;
+
+ case OP_BACK_REF:
+ dfa->nexts[idx] = node->next->node_idx;
+ if (node->token.type == OP_BACK_REF)
+ re_node_set_init_1 (dfa->edests + idx, dfa->nexts[idx]);
+ break;
+
+ default:
+ assert (!IS_EPSILON_NODE (node->token.type));
+ dfa->nexts[idx] = node->next->node_idx;
+ break;
+ }
+
+ return err;
+}
+
+/* Duplicate the epsilon closure of the node ROOT_NODE.
+ Note that duplicated nodes have constraint INIT_CONSTRAINT in addition
+ to their own constraint. */
+
+static reg_errcode_t
+internal_function
+duplicate_node_closure (re_dfa_t *dfa, int top_org_node, int top_clone_node,
+ int root_node, unsigned int init_constraint)
+{
+ int org_node, clone_node, ret;
+ unsigned int constraint = init_constraint;
+ for (org_node = top_org_node, clone_node = top_clone_node;;)
+ {
+ int org_dest, clone_dest;
+ if (dfa->nodes[org_node].type == OP_BACK_REF)
+ {
+ /* If the back reference epsilon-transit, its destination must
+ also have the constraint. Then duplicate the epsilon closure
+ of the destination of the back reference, and store it in
+ edests of the back reference. */
+ org_dest = dfa->nexts[org_node];
+ re_node_set_empty (dfa->edests + clone_node);
+ clone_dest = duplicate_node (dfa, org_dest, constraint);
+ if (BE (clone_dest == -1, 0))
+ return REG_ESPACE;
+ dfa->nexts[clone_node] = dfa->nexts[org_node];
+ ret = re_node_set_insert (dfa->edests + clone_node, clone_dest);
+ if (BE (ret < 0, 0))
+ return REG_ESPACE;
+ }
+ else if (dfa->edests[org_node].nelem == 0)
+ {
+ /* In case of the node can't epsilon-transit, don't duplicate the
+ destination and store the original destination as the
+ destination of the node. */
+ dfa->nexts[clone_node] = dfa->nexts[org_node];
+ break;
+ }
+ else if (dfa->edests[org_node].nelem == 1)
+ {
+ /* In case of the node can epsilon-transit, and it has only one
+ destination. */
+ org_dest = dfa->edests[org_node].elems[0];
+ re_node_set_empty (dfa->edests + clone_node);
+ if (dfa->nodes[org_node].type == ANCHOR)
+ {
+ /* In case of the node has another constraint, append it. */
+ if (org_node == root_node && clone_node != org_node)
+ {
+ /* ...but if the node is root_node itself, it means the
+ epsilon closure have a loop, then tie it to the
+ destination of the root_node. */
+ ret = re_node_set_insert (dfa->edests + clone_node,
+ org_dest);
+ if (BE (ret < 0, 0))
+ return REG_ESPACE;
+ break;
+ }
+ constraint |= dfa->nodes[org_node].opr.ctx_type;
+ }
+ clone_dest = duplicate_node (dfa, org_dest, constraint);
+ if (BE (clone_dest == -1, 0))
+ return REG_ESPACE;
+ ret = re_node_set_insert (dfa->edests + clone_node, clone_dest);
+ if (BE (ret < 0, 0))
+ return REG_ESPACE;
+ }
+ else /* dfa->edests[org_node].nelem == 2 */
+ {
+ /* In case of the node can epsilon-transit, and it has two
+ destinations. In the bin_tree_t and DFA, that's '|' and '*'. */
+ org_dest = dfa->edests[org_node].elems[0];
+ re_node_set_empty (dfa->edests + clone_node);
+ /* Search for a duplicated node which satisfies the constraint. */
+ clone_dest = search_duplicated_node (dfa, org_dest, constraint);
+ if (clone_dest == -1)
+ {
+ /* There are no such a duplicated node, create a new one. */
+ reg_errcode_t err;
+ clone_dest = duplicate_node (dfa, org_dest, constraint);
+ if (BE (clone_dest == -1, 0))
+ return REG_ESPACE;
+ ret = re_node_set_insert (dfa->edests + clone_node, clone_dest);
+ if (BE (ret < 0, 0))
+ return REG_ESPACE;
+ err = duplicate_node_closure (dfa, org_dest, clone_dest,
+ root_node, constraint);
+ if (BE (err != REG_NOERROR, 0))
+ return err;
+ }
+ else
+ {
+ /* There are a duplicated node which satisfy the constraint,
+ use it to avoid infinite loop. */
+ ret = re_node_set_insert (dfa->edests + clone_node, clone_dest);
+ if (BE (ret < 0, 0))
+ return REG_ESPACE;
+ }
+
+ org_dest = dfa->edests[org_node].elems[1];
+ clone_dest = duplicate_node (dfa, org_dest, constraint);
+ if (BE (clone_dest == -1, 0))
+ return REG_ESPACE;
+ ret = re_node_set_insert (dfa->edests + clone_node, clone_dest);
+ if (BE (ret < 0, 0))
+ return REG_ESPACE;
+ }
+ org_node = org_dest;
+ clone_node = clone_dest;
+ }
+ return REG_NOERROR;
+}
+
+/* Search for a node which is duplicated from the node ORG_NODE, and
+ satisfies the constraint CONSTRAINT. */
+
+static int
+search_duplicated_node (const re_dfa_t *dfa, int org_node,
+ unsigned int constraint)
+{
+ int idx;
+ for (idx = dfa->nodes_len - 1; dfa->nodes[idx].duplicated && idx > 0; --idx)
+ {
+ if (org_node == dfa->org_indices[idx]
+ && constraint == dfa->nodes[idx].constraint)
+ return idx; /* Found. */
+ }
+ return -1; /* Not found. */
+}
+
+/* Duplicate the node whose index is ORG_IDX and set the constraint CONSTRAINT.
+ Return the index of the new node, or -1 if insufficient storage is
+ available. */
+
+static int
+duplicate_node (re_dfa_t *dfa, int org_idx, unsigned int constraint)
+{
+ int dup_idx = re_dfa_add_node (dfa, dfa->nodes[org_idx]);
+ if (BE (dup_idx != -1, 1))
+ {
+ dfa->nodes[dup_idx].constraint = constraint;
+ if (dfa->nodes[org_idx].type == ANCHOR)
+ dfa->nodes[dup_idx].constraint |= dfa->nodes[org_idx].opr.ctx_type;
+ dfa->nodes[dup_idx].duplicated = 1;
+
+ /* Store the index of the original node. */
+ dfa->org_indices[dup_idx] = org_idx;
+ }
+ return dup_idx;
+}
+
+static reg_errcode_t
+calc_inveclosure (re_dfa_t *dfa)
+{
+ int src, idx, ret;
+ for (idx = 0; idx < dfa->nodes_len; ++idx)
+ re_node_set_init_empty (dfa->inveclosures + idx);
+
+ for (src = 0; src < dfa->nodes_len; ++src)
+ {
+ int *elems = dfa->eclosures[src].elems;
+ for (idx = 0; idx < dfa->eclosures[src].nelem; ++idx)
+ {
+ ret = re_node_set_insert_last (dfa->inveclosures + elems[idx], src);
+ if (BE (ret == -1, 0))
+ return REG_ESPACE;
+ }
+ }
+
+ return REG_NOERROR;
+}
+
+/* Calculate "eclosure" for all the node in DFA. */
+
+static reg_errcode_t
+calc_eclosure (re_dfa_t *dfa)
+{
+ int node_idx, incomplete;
+#ifdef DEBUG
+ assert (dfa->nodes_len > 0);
+#endif
+ incomplete = 0;
+ /* For each nodes, calculate epsilon closure. */
+ for (node_idx = 0; ; ++node_idx)
+ {
+ reg_errcode_t err;
+ re_node_set eclosure_elem;
+ if (node_idx == dfa->nodes_len)
+ {
+ if (!incomplete)
+ break;
+ incomplete = 0;
+ node_idx = 0;
+ }
+
+#ifdef DEBUG
+ assert (dfa->eclosures[node_idx].nelem != -1);
+#endif
+
+ /* If we have already calculated, skip it. */
+ if (dfa->eclosures[node_idx].nelem != 0)
+ continue;
+ /* Calculate epsilon closure of `node_idx'. */
+ err = calc_eclosure_iter (&eclosure_elem, dfa, node_idx, 1);
+ if (BE (err != REG_NOERROR, 0))
+ return err;
+
+ if (dfa->eclosures[node_idx].nelem == 0)
+ {
+ incomplete = 1;
+ re_node_set_free (&eclosure_elem);
+ }
+ }
+ return REG_NOERROR;
+}
+
+/* Calculate epsilon closure of NODE. */
+
+static reg_errcode_t
+calc_eclosure_iter (re_node_set *new_set, re_dfa_t *dfa, int node, int root)
+{
+ reg_errcode_t err;
+ unsigned int constraint;
+ int i, incomplete;
+ re_node_set eclosure;
+ incomplete = 0;
+ err = re_node_set_alloc (&eclosure, dfa->edests[node].nelem + 1);
+ if (BE (err != REG_NOERROR, 0))
+ return err;
+
+ /* This indicates that we are calculating this node now.
+ We reference this value to avoid infinite loop. */
+ dfa->eclosures[node].nelem = -1;
+
+ constraint = ((dfa->nodes[node].type == ANCHOR)
+ ? dfa->nodes[node].opr.ctx_type : 0);
+ /* If the current node has constraints, duplicate all nodes.
+ Since they must inherit the constraints. */
+ if (constraint
+ && dfa->edests[node].nelem
+ && !dfa->nodes[dfa->edests[node].elems[0]].duplicated)
+ {
+ err = duplicate_node_closure (dfa, node, node, node, constraint);
+ if (BE (err != REG_NOERROR, 0))
+ return err;
+ }
+
+ /* Expand each epsilon destination nodes. */
+ if (IS_EPSILON_NODE(dfa->nodes[node].type))
+ for (i = 0; i < dfa->edests[node].nelem; ++i)
+ {
+ re_node_set eclosure_elem;
+ int edest = dfa->edests[node].elems[i];
+ /* If calculating the epsilon closure of `edest' is in progress,
+ return intermediate result. */
+ if (dfa->eclosures[edest].nelem == -1)
+ {
+ incomplete = 1;
+ continue;
+ }
+ /* If we haven't calculated the epsilon closure of `edest' yet,
+ calculate now. Otherwise use calculated epsilon closure. */
+ if (dfa->eclosures[edest].nelem == 0)
+ {
+ err = calc_eclosure_iter (&eclosure_elem, dfa, edest, 0);
+ if (BE (err != REG_NOERROR, 0))
+ return err;
+ }
+ else
+ eclosure_elem = dfa->eclosures[edest];
+ /* Merge the epsilon closure of `edest'. */
+ re_node_set_merge (&eclosure, &eclosure_elem);
+ /* If the epsilon closure of `edest' is incomplete,
+ the epsilon closure of this node is also incomplete. */
+ if (dfa->eclosures[edest].nelem == 0)
+ {
+ incomplete = 1;
+ re_node_set_free (&eclosure_elem);
+ }
+ }
+
+ /* Epsilon closures include itself. */
+ re_node_set_insert (&eclosure, node);
+ if (incomplete && !root)
+ dfa->eclosures[node].nelem = 0;
+ else
+ dfa->eclosures[node] = eclosure;
+ *new_set = eclosure;
+ return REG_NOERROR;
+}
+
+/* Functions for token which are used in the parser. */
+
+/* Fetch a token from INPUT.
+ We must not use this function inside bracket expressions. */
+
+static void
+internal_function
+fetch_token (re_token_t *result, re_string_t *input, reg_syntax_t syntax)
+{
+ re_string_skip_bytes (input, peek_token (result, input, syntax));
+}
+
+/* Peek a token from INPUT, and return the length of the token.
+ We must not use this function inside bracket expressions. */
+
+static int
+internal_function
+peek_token (re_token_t *token, re_string_t *input, reg_syntax_t syntax)
+{
+ unsigned char c;
+
+ if (re_string_eoi (input))
+ {
+ token->type = END_OF_RE;
+ return 0;
+ }
+
+ c = re_string_peek_byte (input, 0);
+ token->opr.c = c;
+
+ token->word_char = 0;
+#ifdef RE_ENABLE_I18N
+ token->mb_partial = 0;
+ if (input->mb_cur_max > 1 &&
+ !re_string_first_byte (input, re_string_cur_idx (input)))
+ {
+ token->type = CHARACTER;
+ token->mb_partial = 1;
+ return 1;
+ }
+#endif
+ if (c == '\\')
+ {
+ unsigned char c2;
+ if (re_string_cur_idx (input) + 1 >= re_string_length (input))
+ {
+ token->type = BACK_SLASH;
+ return 1;
+ }
+
+ c2 = re_string_peek_byte_case (input, 1);
+ token->opr.c = c2;
+ token->type = CHARACTER;
+#ifdef RE_ENABLE_I18N
+ if (input->mb_cur_max > 1)
+ {
+ wint_t wc = re_string_wchar_at (input,
+ re_string_cur_idx (input) + 1);
+ token->word_char = IS_WIDE_WORD_CHAR (wc) != 0;
+ }
+ else
+#endif
+ token->word_char = IS_WORD_CHAR (c2) != 0;
+
+ switch (c2)
+ {
+ case '|':
+ if (!(syntax & RE_LIMITED_OPS) && !(syntax & RE_NO_BK_VBAR))
+ token->type = OP_ALT;
+ 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))
+ {
+ token->type = OP_BACK_REF;
+ token->opr.idx = c2 - '1';
+ }
+ break;
+ case '<':
+ if (!(syntax & RE_NO_GNU_OPS))
+ {
+ token->type = ANCHOR;
+ token->opr.ctx_type = WORD_FIRST;
+ }
+ break;
+ case '>':
+ if (!(syntax & RE_NO_GNU_OPS))
+ {
+ token->type = ANCHOR;
+ token->opr.ctx_type = WORD_LAST;
+ }
+ break;
+ case 'b':
+ if (!(syntax & RE_NO_GNU_OPS))
+ {
+ token->type = ANCHOR;
+ token->opr.ctx_type = WORD_DELIM;
+ }
+ break;
+ case 'B':
+ if (!(syntax & RE_NO_GNU_OPS))
+ {
+ token->type = ANCHOR;
+ token->opr.ctx_type = NOT_WORD_DELIM;
+ }
+ break;
+ case 'w':
+ if (!(syntax & RE_NO_GNU_OPS))
+ token->type = OP_WORD;
+ break;
+ case 'W':
+ if (!(syntax & RE_NO_GNU_OPS))
+ token->type = OP_NOTWORD;
+ break;
+ case 's':
+ if (!(syntax & RE_NO_GNU_OPS))
+ token->type = OP_SPACE;
+ break;
+ case 'S':
+ if (!(syntax & RE_NO_GNU_OPS))
+ token->type = OP_NOTSPACE;
+ break;
+ case '`':
+ if (!(syntax & RE_NO_GNU_OPS))
+ {
+ token->type = ANCHOR;
+ token->opr.ctx_type = BUF_FIRST;
+ }
+ break;
+ case '\'':
+ if (!(syntax & RE_NO_GNU_OPS))
+ {
+ token->type = ANCHOR;
+ token->opr.ctx_type = BUF_LAST;
+ }
+ break;
+ case '(':
+ if (!(syntax & RE_NO_BK_PARENS))
+ token->type = OP_OPEN_SUBEXP;
+ break;
+ case ')':
+ if (!(syntax & RE_NO_BK_PARENS))
+ token->type = OP_CLOSE_SUBEXP;
+ break;
+ case '+':
+ if (!(syntax & RE_LIMITED_OPS) && (syntax & RE_BK_PLUS_QM))
+ token->type = OP_DUP_PLUS;
+ break;
+ case '?':
+ if (!(syntax & RE_LIMITED_OPS) && (syntax & RE_BK_PLUS_QM))
+ token->type = OP_DUP_QUESTION;
+ break;
+ case '{':
+ if ((syntax & RE_INTERVALS) && (!(syntax & RE_NO_BK_BRACES)))
+ token->type = OP_OPEN_DUP_NUM;
+ break;
+ case '}':
+ if ((syntax & RE_INTERVALS) && (!(syntax & RE_NO_BK_BRACES)))
+ token->type = OP_CLOSE_DUP_NUM;
+ break;
+ default:
+ break;
+ }
+ return 2;
+ }
+
+ token->type = CHARACTER;
+#ifdef RE_ENABLE_I18N
+ if (input->mb_cur_max > 1)
+ {
+ wint_t wc = re_string_wchar_at (input, re_string_cur_idx (input));
+ token->word_char = IS_WIDE_WORD_CHAR (wc) != 0;
+ }
+ else
+#endif
+ token->word_char = IS_WORD_CHAR (token->opr.c);
+
+ switch (c)
+ {
+ case '\n':
+ if (syntax & RE_NEWLINE_ALT)
+ token->type = OP_ALT;
+ break;
+ case '|':
+ if (!(syntax & RE_LIMITED_OPS) && (syntax & RE_NO_BK_VBAR))
+ token->type = OP_ALT;
+ break;
+ case '*':
+ token->type = OP_DUP_ASTERISK;
+ break;
+ case '+':
+ if (!(syntax & RE_LIMITED_OPS) && !(syntax & RE_BK_PLUS_QM))
+ token->type = OP_DUP_PLUS;
+ break;
+ case '?':
+ if (!(syntax & RE_LIMITED_OPS) && !(syntax & RE_BK_PLUS_QM))
+ token->type = OP_DUP_QUESTION;
+ break;
+ case '{':
+ if ((syntax & RE_INTERVALS) && (syntax & RE_NO_BK_BRACES))
+ token->type = OP_OPEN_DUP_NUM;
+ break;
+ case '}':
+ if ((syntax & RE_INTERVALS) && (syntax & RE_NO_BK_BRACES))
+ token->type = OP_CLOSE_DUP_NUM;
+ break;
+ case '(':
+ if (syntax & RE_NO_BK_PARENS)
+ token->type = OP_OPEN_SUBEXP;
+ break;
+ case ')':
+ if (syntax & RE_NO_BK_PARENS)
+ token->type = OP_CLOSE_SUBEXP;
+ break;
+ case '[':
+ token->type = OP_OPEN_BRACKET;
+ break;
+ case '.':
+ token->type = OP_PERIOD;
+ break;
+ case '^':
+ if (!(syntax & (RE_CONTEXT_INDEP_ANCHORS | RE_CARET_ANCHORS_HERE)) &&
+ re_string_cur_idx (input) != 0)
+ {
+ char prev = re_string_peek_byte (input, -1);
+ if (!(syntax & RE_NEWLINE_ALT) || prev != '\n')
+ break;
+ }
+ token->type = ANCHOR;
+ token->opr.ctx_type = LINE_FIRST;
+ break;
+ case '$':
+ if (!(syntax & RE_CONTEXT_INDEP_ANCHORS) &&
+ re_string_cur_idx (input) + 1 != re_string_length (input))
+ {
+ re_token_t next;
+ re_string_skip_bytes (input, 1);
+ peek_token (&next, input, syntax);
+ re_string_skip_bytes (input, -1);
+ if (next.type != OP_ALT && next.type != OP_CLOSE_SUBEXP)
+ break;
+ }
+ token->type = ANCHOR;
+ token->opr.ctx_type = LINE_LAST;
+ break;
+ default:
+ break;
+ }
+ return 1;
+}
+
+/* Peek a token from INPUT, and return the length of the token.
+ We must not use this function out of bracket expressions. */
+
+static int
+internal_function
+peek_token_bracket (re_token_t *token, re_string_t *input, reg_syntax_t syntax)
+{
+ unsigned char c;
+ if (re_string_eoi (input))
+ {
+ token->type = END_OF_RE;
+ return 0;
+ }
+ c = re_string_peek_byte (input, 0);
+ token->opr.c = c;
+
+#ifdef RE_ENABLE_I18N
+ if (input->mb_cur_max > 1 &&
+ !re_string_first_byte (input, re_string_cur_idx (input)))
+ {
+ token->type = CHARACTER;
+ return 1;
+ }
+#endif
+
+ if (c == '\\' && (syntax & RE_BACKSLASH_ESCAPE_IN_LISTS)
+ && re_string_cur_idx (input) + 1 < re_string_length (input))
+ {
+ /* In this case, '\' escape a character. */
+ unsigned char c2;
+ re_string_skip_bytes (input, 1);
+ c2 = re_string_peek_byte (input, 0);
+ token->opr.c = c2;
+ token->type = CHARACTER;
+ return 1;
+ }
+ if (c == '[') /* '[' is a special char in a bracket exps. */
+ {
+ unsigned char c2;
+ int token_len;
+ if (re_string_cur_idx (input) + 1 < re_string_length (input))
+ c2 = re_string_peek_byte (input, 1);
+ else
+ c2 = 0;
+ token->opr.c = c2;
+ token_len = 2;
+ switch (c2)
+ {
+ case '.':
+ token->type = OP_OPEN_COLL_ELEM;
+ break;
+ case '=':
+ token->type = OP_OPEN_EQUIV_CLASS;
+ break;
+ case ':':
+ if (syntax & RE_CHAR_CLASSES)
+ {
+ token->type = OP_OPEN_CHAR_CLASS;
+ break;
+ }
+ /* else fall through. */
+ default:
+ token->type = CHARACTER;
+ token->opr.c = c;
+ token_len = 1;
+ break;
+ }
+ return token_len;
+ }
+ switch (c)
+ {
+ case '-':
+ token->type = OP_CHARSET_RANGE;
+ break;
+ case ']':
+ token->type = OP_CLOSE_BRACKET;
+ break;
+ case '^':
+ token->type = OP_NON_MATCH_LIST;
+ break;
+ default:
+ token->type = CHARACTER;
+ }
+ return 1;
+}
+
+/* Functions for parser. */
+
+/* Entry point of the parser.
+ Parse the regular expression REGEXP and return the structure tree.
+ If an error is occured, ERR is set by error code, and return NULL.
+ This function build the following tree, from regular expression <reg_exp>:
+ CAT
+ / \
+ / \
+ <reg_exp> EOR
+
+ CAT means concatenation.
+ EOR means end of regular expression. */
+
+static bin_tree_t *
+parse (re_string_t *regexp, regex_t *preg, reg_syntax_t syntax,
+ reg_errcode_t *err)
+{
+ re_dfa_t *dfa = (re_dfa_t *) preg->buffer;
+ bin_tree_t *tree, *eor, *root;
+ re_token_t current_token;
+ dfa->syntax = syntax;
+ fetch_token (¤t_token, regexp, syntax | RE_CARET_ANCHORS_HERE);
+ tree = parse_reg_exp (regexp, preg, ¤t_token, syntax, 0, err);
+ if (BE (*err != REG_NOERROR && tree == NULL, 0))
+ return NULL;
+ eor = create_tree (dfa, NULL, NULL, END_OF_RE);
+ if (tree != NULL)
+ root = create_tree (dfa, tree, eor, CONCAT);
+ else
+ root = eor;
+ if (BE (eor == NULL || root == NULL, 0))
+ {
+ *err = REG_ESPACE;
+ return NULL;
+ }
+ return root;
+}
+
+/* This function build the following tree, from regular expression
+ <branch1>|<branch2>:
+ ALT
+ / \
+ / \
+ <branch1> <branch2>
+
+ ALT means alternative, which represents the operator `|'. */
+
+static bin_tree_t *
+parse_reg_exp (re_string_t *regexp, regex_t *preg, re_token_t *token,
+ reg_syntax_t syntax, int nest, reg_errcode_t *err)
+{
+ re_dfa_t *dfa = (re_dfa_t *) preg->buffer;
+ bin_tree_t *tree, *branch = NULL;
+ tree = parse_branch (regexp, preg, token, syntax, nest, err);
+ if (BE (*err != REG_NOERROR && tree == NULL, 0))
+ return NULL;
+
+ while (token->type == OP_ALT)
+ {
+ fetch_token (token, regexp, syntax | RE_CARET_ANCHORS_HERE);
+ if (token->type != OP_ALT && token->type != END_OF_RE
+ && (nest == 0 || token->type != OP_CLOSE_SUBEXP))
+ {
+ branch = parse_branch (regexp, preg, token, syntax, nest, err);
+ if (BE (*err != REG_NOERROR && branch == NULL, 0))
+ return NULL;
+ }
+ else
+ branch = NULL;
+ tree = create_tree (dfa, tree, branch, OP_ALT);
+ if (BE (tree == NULL, 0))
+ {
+ *err = REG_ESPACE;
+ return NULL;
+ }
+ }
+ return tree;
+}
+
+/* This function build the following tree, from regular expression
+ <exp1><exp2>:
+ CAT
+ / \
+ / \
+ <exp1> <exp2>
+
+ CAT means concatenation. */
+
+static bin_tree_t *
+parse_branch (re_string_t *regexp, regex_t *preg, re_token_t *token,
+ reg_syntax_t syntax, int nest, reg_errcode_t *err)
+{
+ bin_tree_t *tree, *exp;
+ re_dfa_t *dfa = (re_dfa_t *) preg->buffer;
+ tree = parse_expression (regexp, preg, token, syntax, nest, err);
+ if (BE (*err != REG_NOERROR && tree == NULL, 0))
+ return NULL;
+
+ while (token->type != OP_ALT && token->type != END_OF_RE
+ && (nest == 0 || token->type != OP_CLOSE_SUBEXP))
+ {
+ exp = parse_expression (regexp, preg, token, syntax, nest, err);
+ if (BE (*err != REG_NOERROR && exp == NULL, 0))
+ {
+ return NULL;
+ }
+ if (tree != NULL && exp != NULL)
+ {
+ tree = create_tree (dfa, tree, exp, CONCAT);
+ if (tree == NULL)
+ {
+ *err = REG_ESPACE;
+ return NULL;
+ }
+ }
+ else if (tree == NULL)
+ tree = exp;
+ /* Otherwise exp == NULL, we don't need to create new tree. */
+ }
+ return tree;
+}
+
+/* This function build the following tree, from regular expression a*:
+ *
+ |
+ a
+*/
+
+static bin_tree_t *
+parse_expression (re_string_t *regexp, regex_t *preg, re_token_t *token,
+ reg_syntax_t syntax, int nest, reg_errcode_t *err)
+{
+ re_dfa_t *dfa = (re_dfa_t *) preg->buffer;
+ bin_tree_t *tree;
+ switch (token->type)
+ {
+ case CHARACTER:
+ tree = create_token_tree (dfa, NULL, NULL, token);
+ if (BE (tree == NULL, 0))
+ {
+ *err = REG_ESPACE;
+ return NULL;
+ }
+#ifdef RE_ENABLE_I18N
+ if (dfa->mb_cur_max > 1)
+ {
+ while (!re_string_eoi (regexp)
+ && !re_string_first_byte (regexp, re_string_cur_idx (regexp)))
+ {
+ bin_tree_t *mbc_remain;
+ fetch_token (token, regexp, syntax);
+ mbc_remain = create_token_tree (dfa, NULL, NULL, token);
+ tree = create_tree (dfa, tree, mbc_remain, CONCAT);
+ if (BE (mbc_remain == NULL || tree == NULL, 0))
+ {
+ *err = REG_ESPACE;
+ return NULL;
+ }
+ }
+ }
+#endif
+ break;
+ case OP_OPEN_SUBEXP:
+ tree = parse_sub_exp (regexp, preg, token, syntax, nest + 1, err);
+ if (BE (*err != REG_NOERROR && tree == NULL, 0))
+ return NULL;
+ break;
+ case OP_OPEN_BRACKET:
+ tree = parse_bracket_exp (regexp, dfa, token, syntax, err);
+ if (BE (*err != REG_NOERROR && tree == NULL, 0))
+ return NULL;
+ break;
+ case OP_BACK_REF:
+ if (!BE (dfa->completed_bkref_map & (1 << token->opr.idx), 1))
+ {
+ *err = REG_ESUBREG;
+ return NULL;
+ }
+ dfa->used_bkref_map |= 1 << token->opr.idx;
+ tree = create_token_tree (dfa, NULL, NULL, token);
+ if (BE (tree == NULL, 0))
+ {
+ *err = REG_ESPACE;
+ return NULL;
+ }
+ ++dfa->nbackref;
+ dfa->has_mb_node = 1;
+ break;
+ case OP_OPEN_DUP_NUM:
+ if (syntax & RE_CONTEXT_INVALID_DUP)
+ {
+ *err = REG_BADRPT;
+ return NULL;
+ }
+ /* FALLTHROUGH */
+ case OP_DUP_ASTERISK:
+ case OP_DUP_PLUS:
+ case OP_DUP_QUESTION:
+ if (syntax & RE_CONTEXT_INVALID_OPS)
+ {
+ *err = REG_BADRPT;
+ return NULL;
+ }
+ else if (syntax & RE_CONTEXT_INDEP_OPS)
+ {
+ fetch_token (token, regexp, syntax);
+ return parse_expression (regexp, preg, token, syntax, nest, err);
+ }
+ /* else fall through */
+ case OP_CLOSE_SUBEXP:
+ if ((token->type == OP_CLOSE_SUBEXP) &&
+ !(syntax & RE_UNMATCHED_RIGHT_PAREN_ORD))
+ {
+ *err = REG_ERPAREN;
+ return NULL;
+ }
+ /* else fall through */
+ case OP_CLOSE_DUP_NUM:
+ /* We treat it as a normal character. */
+
+ /* Then we can these characters as normal characters. */
+ token->type = CHARACTER;
+ /* mb_partial and word_char bits should be initialized already
+ by peek_token. */
+ tree = create_token_tree (dfa, NULL, NULL, token);
+ if (BE (tree == NULL, 0))
+ {
+ *err = REG_ESPACE;
+ return NULL;
+ }
+ break;
+ case ANCHOR:
+ if ((token->opr.ctx_type
+ & (WORD_DELIM | NOT_WORD_DELIM | WORD_FIRST | WORD_LAST))
+ && dfa->word_ops_used == 0)
+ init_word_char (dfa);
+ if (token->opr.ctx_type == WORD_DELIM
+ || token->opr.ctx_type == NOT_WORD_DELIM)
+ {
+ bin_tree_t *tree_first, *tree_last;
+ if (token->opr.ctx_type == WORD_DELIM)
+ {
+ token->opr.ctx_type = WORD_FIRST;
+ tree_first = create_token_tree (dfa, NULL, NULL, token);
+ token->opr.ctx_type = WORD_LAST;
+ }
+ else
+ {
+ token->opr.ctx_type = INSIDE_WORD;
+ tree_first = create_token_tree (dfa, NULL, NULL, token);
+ token->opr.ctx_type = INSIDE_NOTWORD;
+ }
+ tree_last = create_token_tree (dfa, NULL, NULL, token);
+ tree = create_tree (dfa, tree_first, tree_last, OP_ALT);
+ if (BE (tree_first == NULL || tree_last == NULL || tree == NULL, 0))
+ {
+ *err = REG_ESPACE;
+ return NULL;
+ }
+ }
+ else
+ {
+ tree = create_token_tree (dfa, NULL, NULL, token);
+ if (BE (tree == NULL, 0))
+ {
+ *err = REG_ESPACE;
+ return NULL;
+ }
+ }
+ /* We must return here, since ANCHORs can't be followed
+ by repetition operators.
+ eg. RE"^*" is invalid or "<ANCHOR(^)><CHAR(*)>",
+ it must not be "<ANCHOR(^)><REPEAT(*)>". */
+ fetch_token (token, regexp, syntax);
+ return tree;
+ case OP_PERIOD:
+ tree = create_token_tree (dfa, NULL, NULL, token);
+ if (BE (tree == NULL, 0))
+ {
+ *err = REG_ESPACE;
+ return NULL;
+ }
+ if (dfa->mb_cur_max > 1)
+ dfa->has_mb_node = 1;
+ break;
+ case OP_WORD:
+ case OP_NOTWORD:
+ tree = build_charclass_op (dfa, regexp->trans,
+ (const unsigned char *) "alnum",
+ (const unsigned char *) "_",
+ token->type == OP_NOTWORD, err);
+ if (BE (*err != REG_NOERROR && tree == NULL, 0))
+ return NULL;
+ break;
+ case OP_SPACE:
+ case OP_NOTSPACE:
+ tree = build_charclass_op (dfa, regexp->trans,
+ (const unsigned char *) "space",
+ (const unsigned char *) "",
+ token->type == OP_NOTSPACE, err);
+ if (BE (*err != REG_NOERROR && tree == NULL, 0))
+ return NULL;
+ break;
+ case OP_ALT:
+ case END_OF_RE:
+ return NULL;
+ case BACK_SLASH:
+ *err = REG_EESCAPE;
+ return NULL;
+ default:
+ /* Must not happen? */
+#ifdef DEBUG
+ assert (0);
+#endif
+ return NULL;
+ }
+ fetch_token (token, regexp, syntax);
+
+ while (token->type == OP_DUP_ASTERISK || token->type == OP_DUP_PLUS
+ || token->type == OP_DUP_QUESTION || token->type == OP_OPEN_DUP_NUM)
+ {
+ tree = parse_dup_op (tree, regexp, dfa, token, syntax, err);
+ if (BE (*err != REG_NOERROR && tree == NULL, 0))
+ return NULL;
+ /* In BRE consecutive duplications are not allowed. */
+ if ((syntax & RE_CONTEXT_INVALID_DUP)
+ && (token->type == OP_DUP_ASTERISK
+ || token->type == OP_OPEN_DUP_NUM))
+ {
+ *err = REG_BADRPT;
+ return NULL;
+ }
+ }
+
+ return tree;
+}
+
+/* This function build the following tree, from regular expression
+ (<reg_exp>):
+ SUBEXP
+ |
+ <reg_exp>
+*/
+
+static bin_tree_t *
+parse_sub_exp (re_string_t *regexp, regex_t *preg, re_token_t *token,
+ reg_syntax_t syntax, int nest, reg_errcode_t *err)
+{
+ re_dfa_t *dfa = (re_dfa_t *) preg->buffer;
+ bin_tree_t *tree;
+ size_t cur_nsub;
+ cur_nsub = preg->re_nsub++;
+
+ fetch_token (token, regexp, syntax | RE_CARET_ANCHORS_HERE);
+
+ /* The subexpression may be a null string. */
+ if (token->type == OP_CLOSE_SUBEXP)
+ tree = NULL;
+ else
+ {
+ tree = parse_reg_exp (regexp, preg, token, syntax, nest, err);
+ if (BE (*err == REG_NOERROR && token->type != OP_CLOSE_SUBEXP, 0))
+ *err = REG_EPAREN;
+ if (BE (*err != REG_NOERROR, 0))
+ return NULL;
+ }
+
+ if (cur_nsub <= '9' - '1')
+ dfa->completed_bkref_map |= 1 << cur_nsub;
+
+ tree = create_tree (dfa, tree, NULL, SUBEXP);
+ if (BE (tree == NULL, 0))
+ {
+ *err = REG_ESPACE;
+ return NULL;
+ }
+ tree->token.opr.idx = cur_nsub;
+ return tree;
+}
+
+/* This function parse repetition operators like "*", "+", "{1,3}" etc. */
+
+static bin_tree_t *
+parse_dup_op (bin_tree_t *elem, re_string_t *regexp, re_dfa_t *dfa,
+ re_token_t *token, reg_syntax_t syntax, reg_errcode_t *err)
+{
+ bin_tree_t *tree = NULL, *old_tree = NULL;
+ int i, start, end, start_idx = re_string_cur_idx (regexp);
+ re_token_t start_token = *token;
+
+ if (token->type == OP_OPEN_DUP_NUM)
+ {
+ end = 0;
+ start = fetch_number (regexp, token, syntax);
+ if (start == -1)
+ {
+ if (token->type == CHARACTER && token->opr.c == ',')
+ start = 0; /* We treat "{,m}" as "{0,m}". */
+ else
+ {
+ *err = REG_BADBR; /* <re>{} is invalid. */
+ return NULL;
+ }
+ }
+ if (BE (start != -2, 1))
+ {
+ /* We treat "{n}" as "{n,n}". */
+ end = ((token->type == OP_CLOSE_DUP_NUM) ? start
+ : ((token->type == CHARACTER && token->opr.c == ',')
+ ? fetch_number (regexp, token, syntax) : -2));
+ }
+ if (BE (start == -2 || end == -2, 0))
+ {
+ /* Invalid sequence. */
+ if (BE (!(syntax & RE_INVALID_INTERVAL_ORD), 0))
+ {
+ if (token->type == END_OF_RE)
+ *err = REG_EBRACE;
+ else
+ *err = REG_BADBR;
+
+ return NULL;
+ }
+
+ /* If the syntax bit is set, rollback. */
+ re_string_set_index (regexp, start_idx);
+ *token = start_token;
+ token->type = CHARACTER;
+ /* mb_partial and word_char bits should be already initialized by
+ peek_token. */
+ return elem;
+ }
+
+ if (BE (end != -1 && start > end, 0))
+ {
+ /* First number greater than second. */
+ *err = REG_BADBR;
+ return NULL;
+ }
+ }
+ else
+ {
+ start = (token->type == OP_DUP_PLUS) ? 1 : 0;
+ end = (token->type == OP_DUP_QUESTION) ? 1 : -1;
+ }
+
+ fetch_token (token, regexp, syntax);
+
+ if (BE (elem == NULL, 0))
+ return NULL;
+ if (BE (start == 0 && end == 0, 0))
+ {
+ postorder (elem, free_tree, NULL);
+ return NULL;
+ }
+
+ /* Extract "<re>{n,m}" to "<re><re>...<re><re>{0,<m-n>}". */
+ if (BE (start > 0, 0))
+ {
+ tree = elem;
+ for (i = 2; i <= start; ++i)
+ {
+ elem = duplicate_tree (elem, dfa);
+ tree = create_tree (dfa, tree, elem, CONCAT);
+ if (BE (elem == NULL || tree == NULL, 0))
+ goto parse_dup_op_espace;
+ }
+
+ if (start == end)
+ return tree;
+
+ /* Duplicate ELEM before it is marked optional. */
+ elem = duplicate_tree (elem, dfa);
+ old_tree = tree;
+ }
+ else
+ old_tree = NULL;
+
+ if (elem->token.type == SUBEXP)
+ postorder (elem, mark_opt_subexp, (void *) (long) elem->token.opr.idx);
+
+ tree = create_tree (dfa, elem, NULL, (end == -1 ? OP_DUP_ASTERISK : OP_ALT));
+ if (BE (tree == NULL, 0))
+ goto parse_dup_op_espace;
+
+ /* This loop is actually executed only when end != -1,
+ to rewrite <re>{0,n} as (<re>(<re>...<re>?)?)?... We have
+ already created the start+1-th copy. */
+ for (i = start + 2; i <= end; ++i)
+ {
+ elem = duplicate_tree (elem, dfa);
+ tree = create_tree (dfa, tree, elem, CONCAT);
+ if (BE (elem == NULL || tree == NULL, 0))
+ goto parse_dup_op_espace;
+
+ tree = create_tree (dfa, tree, NULL, OP_ALT);
+ if (BE (tree == NULL, 0))
+ goto parse_dup_op_espace;
+ }
+
+ if (old_tree)
+ tree = create_tree (dfa, old_tree, tree, CONCAT);
+
+ return tree;
+
+ parse_dup_op_espace:
+ *err = REG_ESPACE;
+ return NULL;
+}
+
+/* Size of the names for collating symbol/equivalence_class/character_class.
+ I'm not sure, but maybe enough. */
+#define BRACKET_NAME_BUF_SIZE 32
+
+#if 1
+ /* Local function for parse_bracket_exp only used in case of NOT glibc.
+ Build the range expression which starts from START_ELEM, and ends
+ at END_ELEM. The result are written to MBCSET and SBCSET.
+ RANGE_ALLOC is the allocated size of mbcset->range_starts, and
+ mbcset->range_ends, is a pointer argument sinse we may
+ update it. */
+
+static reg_errcode_t
+internal_function
+# ifdef RE_ENABLE_I18N
+build_range_exp (bitset_t sbcset, re_charset_t *mbcset, int *range_alloc,
+ bracket_elem_t *start_elem, bracket_elem_t *end_elem)
+# else
+build_range_exp (bitset_t sbcset, bracket_elem_t *start_elem,
+ bracket_elem_t *end_elem)
+# endif
+{
+ unsigned int start_ch, end_ch;
+ /* Equivalence Classes and Character Classes can't be a range start/end. */
+ if (BE (start_elem->type == EQUIV_CLASS || start_elem->type == CHAR_CLASS
+ || end_elem->type == EQUIV_CLASS || end_elem->type == CHAR_CLASS,
+ 0))
+ return REG_ERANGE;
+
+ /* We can handle no multi character collating elements without libc
+ support. */
+ if (BE ((start_elem->type == COLL_SYM
+ && strlen ((char *) start_elem->opr.name) > 1)
+ || (end_elem->type == COLL_SYM
+ && strlen ((char *) end_elem->opr.name) > 1), 0))
+ return REG_ECOLLATE;
+
+# ifdef RE_ENABLE_I18N
+ {
+ wchar_t wc;
+ wint_t start_wc;
+ wint_t end_wc;
+ wchar_t cmp_buf[6] = {L'\0', L'\0', L'\0', L'\0', L'\0', L'\0'};
+
+ start_ch = ((start_elem->type == SB_CHAR) ? start_elem->opr.ch
+ : ((start_elem->type == COLL_SYM) ? start_elem->opr.name[0]
+ : 0));
+ end_ch = ((end_elem->type == SB_CHAR) ? end_elem->opr.ch
+ : ((end_elem->type == COLL_SYM) ? end_elem->opr.name[0]
+ : 0));
+ start_wc = ((start_elem->type == SB_CHAR || start_elem->type == COLL_SYM)
+ ? __btowc (start_ch) : start_elem->opr.wch);
+ end_wc = ((end_elem->type == SB_CHAR || end_elem->type == COLL_SYM)
+ ? __btowc (end_ch) : end_elem->opr.wch);
+ if (start_wc == WEOF || end_wc == WEOF)
+ return REG_ECOLLATE;
+ cmp_buf[0] = start_wc;
+ cmp_buf[4] = end_wc;
+ if (wcscoll (cmp_buf, cmp_buf + 4) > 0)
+ return REG_ERANGE;
+
+ /* Got valid collation sequence values, add them as a new entry.
+ However, for !glibc 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. */
+ if (mbcset)
+ {
+ /* Check the space of the arrays. */
+ if (BE (*range_alloc == mbcset->nranges, 0))
+ {
+ /* There is not enough space, need realloc. */
+ wchar_t *new_array_start, *new_array_end;
+ int new_nranges;
+
+ /* +1 in case of mbcset->nranges is 0. */
+ new_nranges = 2 * mbcset->nranges + 1;
+ /* Use realloc since mbcset->range_starts and mbcset->range_ends
+ are NULL if *range_alloc == 0. */
+ new_array_start = re_realloc (mbcset->range_starts, wchar_t,
+ new_nranges);
+ new_array_end = re_realloc (mbcset->range_ends, wchar_t,
+ new_nranges);
+
+ if (BE (new_array_start == NULL || new_array_end == NULL, 0))
+ return REG_ESPACE;
+
+ mbcset->range_starts = new_array_start;
+ mbcset->range_ends = new_array_end;
+ *range_alloc = new_nranges;
+ }
+
+ mbcset->range_starts[mbcset->nranges] = start_wc;
+ mbcset->range_ends[mbcset->nranges++] = end_wc;
+ }
+
+ /* Build the table for single byte characters. */
+ for (wc = 0; wc < SBC_MAX; ++wc)
+ {
+ cmp_buf[2] = wc;
+ if (wcscoll (cmp_buf, cmp_buf + 2) <= 0
+ && wcscoll (cmp_buf + 2, cmp_buf + 4) <= 0)
+ bitset_set (sbcset, wc);
+ }
+ }
+# else /* not RE_ENABLE_I18N */
+ {
+ unsigned int ch;
+ start_ch = ((start_elem->type == SB_CHAR ) ? start_elem->opr.ch
+ : ((start_elem->type == COLL_SYM) ? start_elem->opr.name[0]
+ : 0));
+ end_ch = ((end_elem->type == SB_CHAR ) ? end_elem->opr.ch
+ : ((end_elem->type == COLL_SYM) ? end_elem->opr.name[0]
+ : 0));
+ if (start_ch > end_ch)
+ return REG_ERANGE;
+ /* Build the table for single byte characters. */
+ for (ch = 0; ch < SBC_MAX; ++ch)
+ if (start_ch <= ch && ch <= end_ch)
+ bitset_set (sbcset, ch);
+ }
+# endif /* not RE_ENABLE_I18N */
+ return REG_NOERROR;
+}
+#endif
+
+#if 1
+/* Helper function for parse_bracket_exp only used in case of NOT glibc.
+ Build the collating element which is represented by NAME.
+ The result are written to MBCSET and SBCSET.
+ COLL_SYM_ALLOC is the allocated size of mbcset->coll_sym, is a
+ pointer argument since we may update it. */
+
+static reg_errcode_t
+internal_function
+# ifdef RE_ENABLE_I18N
+build_collating_symbol (bitset_t sbcset, re_charset_t *mbcset,
+ int *coll_sym_alloc, const unsigned char *name)
+# else
+build_collating_symbol (bitset_t sbcset, const unsigned char *name)
+# endif
+{
+ size_t name_len = strlen ((const char *) name);
+ if (BE (name_len != 1, 0))
+ return REG_ECOLLATE;
+ bitset_set (sbcset, name[0]);
+ return REG_NOERROR;
+}
+#endif
+
+/* This function parse bracket expression like "[abc]", "[a-c]",
+ "[[.a-a.]]" etc. */
+
+static bin_tree_t *
+parse_bracket_exp (re_string_t *regexp, re_dfa_t *dfa, re_token_t *token,
+ reg_syntax_t syntax, reg_errcode_t *err)
+{
+#if 0
+ const unsigned char *collseqmb;
+ const char *collseqwc;
+ uint32_t nrules;
+ int32_t table_size;
+ const int32_t *symb_table;
+ const unsigned char *extra;
+
+ /* Local function for parse_bracket_exp used in glibc.
+ Seek the collating symbol entry correspondings to NAME.
+ Return the index of the symbol in the SYMB_TABLE. */
+
+ auto __inline__ int32_t
+ __attribute ((always_inline))
+ seek_collating_symbol_entry (const unsigned char *name, size_t name_len)
+ {
+ int32_t hash = elem_hash ((const char *) name, name_len);
+ int32_t elem = hash % table_size;
+ if (symb_table[2 * elem] != 0)
+ {
+ int32_t second = hash % (table_size - 2) + 1;
+
+ do
+ {
+ /* First compare the hashing value. */
+ if (symb_table[2 * elem] == hash
+ /* Compare the length of the name. */
+ && name_len == extra[symb_table[2 * elem + 1]]
+ /* Compare the name. */
+ && memcmp (name, &extra[symb_table[2 * elem + 1] + 1],
+ name_len) == 0)
+ {
+ /* Yep, this is the entry. */
+ break;
+ }
+
+ /* Next entry. */
+ elem += second;
+ }
+ while (symb_table[2 * elem] != 0);
+ }
+ return elem;
+ }
+
+ /* Local function for parse_bracket_exp used in glibc.
+ Look up the collation sequence value of BR_ELEM.
+ Return the value if succeeded, UINT_MAX otherwise. */
+
+ auto __inline__ unsigned int
+ __attribute ((always_inline))
+ lookup_collation_sequence_value (bracket_elem_t *br_elem)
+ {
+ if (br_elem->type == SB_CHAR)
+ {
+ /*
+ if (MB_CUR_MAX == 1)
+ */
+ if (nrules == 0)
+ return collseqmb[br_elem->opr.ch];
+ else
+ {
+ wint_t wc = __btowc (br_elem->opr.ch);
+ return __collseq_table_lookup (collseqwc, wc);
+ }
+ }
+ else if (br_elem->type == MB_CHAR)
+ {
+ return __collseq_table_lookup (collseqwc, br_elem->opr.wch);
+ }
+ else if (br_elem->type == COLL_SYM)
+ {
+ size_t sym_name_len = strlen ((char *) br_elem->opr.name);
+ if (nrules != 0)
+ {
+ int32_t elem, idx;
+ elem = seek_collating_symbol_entry (br_elem->opr.name,
+ sym_name_len);
+ if (symb_table[2 * elem] != 0)
+ {
+ /* We found the entry. */
+ idx = symb_table[2 * elem + 1];
+ /* Skip the name of collating element name. */
+ idx += 1 + extra[idx];
+ /* Skip the byte sequence of the collating element. */
+ idx += 1 + extra[idx];
+ /* Adjust for the alignment. */
+ idx = (idx + 3) & ~3;
+ /* Skip the multibyte collation sequence value. */
+ idx += sizeof (unsigned int);
+ /* Skip the wide char sequence of the collating element. */
+ idx += sizeof (unsigned int) *
+ (1 + *(unsigned int *) (extra + idx));
+ /* Return the collation sequence value. */
+ return *(unsigned int *) (extra + idx);
+ }
+ else if (symb_table[2 * elem] == 0 && sym_name_len == 1)
+ {
+ /* No valid character. Match it as a single byte
+ character. */
+ return collseqmb[br_elem->opr.name[0]];
+ }
+ }
+ else if (sym_name_len == 1)
+ return collseqmb[br_elem->opr.name[0]];
+ }
+ return UINT_MAX;
+ }
+
+ /* Local function for parse_bracket_exp used in glibc.
+ Build the range expression which starts from START_ELEM, and ends
+ at END_ELEM. The result are written to MBCSET and SBCSET.
+ RANGE_ALLOC is the allocated size of mbcset->range_starts, and
+ mbcset->range_ends, is a pointer argument sinse we may
+ update it. */
+
+ auto __inline__ reg_errcode_t
+ __attribute ((always_inline))
+ build_range_exp (re_charset_t *mbcset,
+ int *range_alloc,
+ bitset_t sbcset,
+ bracket_elem_t *start_elem,
+ bracket_elem_t *end_elem)
+ {
+ unsigned int ch;
+ uint32_t start_collseq;
+ uint32_t end_collseq;
+
+ /* Equivalence Classes and Character Classes can't be a range
+ start/end. */
+ if (BE (start_elem->type == EQUIV_CLASS || start_elem->type == CHAR_CLASS
+ || end_elem->type == EQUIV_CLASS || end_elem->type == CHAR_CLASS,
+ 0))
+ return REG_ERANGE;
+
+ start_collseq = lookup_collation_sequence_value (start_elem);
+ end_collseq = lookup_collation_sequence_value (end_elem);
+ /* Check start/end collation sequence values. */
+ if (BE (start_collseq == UINT_MAX || end_collseq == UINT_MAX, 0))
+ return REG_ECOLLATE;
+ if (BE ((syntax & RE_NO_EMPTY_RANGES) && start_collseq > end_collseq, 0))
+ return REG_ERANGE;
+
+ /* Got valid collation sequence values, add them as a new entry.
+ 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)
+ {
+ /* Check the space of the arrays. */
+ if (BE (*range_alloc == mbcset->nranges, 0))
+ {
+ /* There is not enough space, need realloc. */
+ uint32_t *new_array_start;
+ uint32_t *new_array_end;
+ int new_nranges;
+
+ /* +1 in case of mbcset->nranges is 0. */
+ new_nranges = 2 * mbcset->nranges + 1;
+ new_array_start = re_realloc (mbcset->range_starts, uint32_t,
+ new_nranges);
+ new_array_end = re_realloc (mbcset->range_ends, uint32_t,
+ new_nranges);
+
+ if (BE (new_array_start == NULL || new_array_end == NULL, 0))
+ return REG_ESPACE;
+
+ mbcset->range_starts = new_array_start;
+ mbcset->range_ends = new_array_end;
+ *range_alloc = new_nranges;
+ }
+
+ mbcset->range_starts[mbcset->nranges] = start_collseq;
+ mbcset->range_ends[mbcset->nranges++] = end_collseq;
+ }
+
+ /* Build the table for single byte characters. */
+ for (ch = 0; ch < SBC_MAX; ch++)
+ {
+ uint32_t ch_collseq;
+ /*
+ if (MB_CUR_MAX == 1)
+ */
+ if (nrules == 0)
+ ch_collseq = collseqmb[ch];
+ else
+ ch_collseq = __collseq_table_lookup (collseqwc, __btowc (ch));
+ if (start_collseq <= ch_collseq && ch_collseq <= end_collseq)
+ bitset_set (sbcset, ch);
+ }
+ return REG_NOERROR;
+ }
+
+ /* Local function for parse_bracket_exp used in glibc.
+ Build the collating element which is represented by NAME.
+ The result are written to MBCSET and SBCSET.
+ COLL_SYM_ALLOC is the allocated size of mbcset->coll_sym, is a
+ pointer argument sinse we may update it. */
+
+ auto __inline__ reg_errcode_t
+ __attribute ((always_inline))
+ build_collating_symbol (re_charset_t *mbcset,
+ int *coll_sym_alloc,
+ bitset_t sbcset,
+ const unsigned char *name)
+ {
+ int32_t elem, idx;
+ size_t name_len = strlen ((const char *) name);
+ if (nrules != 0)
+ {
+ elem = seek_collating_symbol_entry (name, name_len);
+ if (symb_table[2 * elem] != 0)
+ {
+ /* We found the entry. */
+ idx = symb_table[2 * elem + 1];
+ /* Skip the name of collating element name. */
+ idx += 1 + extra[idx];
+ }
+ else if (symb_table[2 * elem] == 0 && name_len == 1)
+ {
+ /* No valid character, treat it as a normal
+ character. */
+ bitset_set (sbcset, name[0]);
+ return REG_NOERROR;
+ }
+ else
+ return REG_ECOLLATE;
+
+ /* Got valid collation sequence, add it as a new entry. */
+ /* Check the space of the arrays. */
+ if (BE (*coll_sym_alloc == mbcset->ncoll_syms, 0))
+ {
+ /* Not enough, realloc it. */
+ /* +1 in case of mbcset->ncoll_syms is 0. */
+ int new_coll_sym_alloc = 2 * mbcset->ncoll_syms + 1;
+ /* Use realloc since mbcset->coll_syms is NULL
+ if *alloc == 0. */
+ int32_t *new_coll_syms = re_realloc (mbcset->coll_syms, int32_t,
+ new_coll_sym_alloc);
+ if (BE (new_coll_syms == NULL, 0))
+ return REG_ESPACE;
+ mbcset->coll_syms = new_coll_syms;
+ *coll_sym_alloc = new_coll_sym_alloc;
+ }
+ mbcset->coll_syms[mbcset->ncoll_syms++] = idx;
+ return REG_NOERROR;
+ }
+ else
+ {
+ if (BE (name_len != 1, 0))
+ return REG_ECOLLATE;
+ else
+ {
+ bitset_set (sbcset, name[0]);
+ return REG_NOERROR;
+ }
+ }
+ }
+#endif
+
+ re_token_t br_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 equiv_class_alloc = 0, char_class_alloc = 0;
+#endif
+ int non_match = 0;
+ bin_tree_t *work_tree;
+ int token_len;
+ int first_round = 1;
+#if 0
+ collseqmb = (const unsigned char *)
+ _NL_CURRENT (LC_COLLATE, _NL_COLLATE_COLLSEQMB);
+ nrules = _NL_CURRENT_WORD (LC_COLLATE, _NL_COLLATE_NRULES);
+ if (nrules)
+ {
+ /*
+ if (MB_CUR_MAX > 1)
+ */
+ collseqwc = _NL_CURRENT (LC_COLLATE, _NL_COLLATE_COLLSEQWC);
+ 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);
+ }
+#endif
+ sbcset = calloc (sizeof (bitset_t), 1);
+#ifdef RE_ENABLE_I18N
+ mbcset = calloc (sizeof (re_charset_t), 1);
+#endif
+#ifdef RE_ENABLE_I18N
+ if (BE (sbcset == NULL || mbcset == NULL, 0))
+#else
+ if (BE (sbcset == NULL, 0))
+#endif
+ {
+ *err = REG_ESPACE;
+ return NULL;
+ }
+
+ token_len = peek_token_bracket (token, regexp, syntax);
+ if (BE (token->type == END_OF_RE, 0))
+ {
+ *err = REG_BADPAT;
+ goto parse_bracket_exp_free_return;
+ }
+ if (token->type == OP_NON_MATCH_LIST)
+ {
+#ifdef RE_ENABLE_I18N
+ mbcset->non_match = 1;
+#endif
+ non_match = 1;
+ if (syntax & RE_HAT_LISTS_NOT_NEWLINE)
+ bitset_set (sbcset, '\0');
+ re_string_skip_bytes (regexp, token_len); /* Skip a token. */
+ token_len = peek_token_bracket (token, regexp, syntax);
+ if (BE (token->type == END_OF_RE, 0))
+ {
+ *err = REG_BADPAT;
+ goto parse_bracket_exp_free_return;
+ }
+ }
+
+ /* We treat the first ']' as a normal character. */
+ if (token->type == OP_CLOSE_BRACKET)
+ token->type = CHARACTER;
+
+ while (1)
+ {
+ bracket_elem_t start_elem, end_elem;
+ unsigned char start_name_buf[BRACKET_NAME_BUF_SIZE];
+ unsigned char end_name_buf[BRACKET_NAME_BUF_SIZE];
+ reg_errcode_t ret;
+ int token_len2 = 0, is_range_exp = 0;
+ re_token_t token2;
+
+ start_elem.opr.name = start_name_buf;
+ ret = parse_bracket_element (&start_elem, regexp, token, token_len, dfa,
+ syntax, first_round);
+ if (BE (ret != REG_NOERROR, 0))
+ {
+ *err = ret;
+ goto parse_bracket_exp_free_return;
+ }
+ first_round = 0;
+
+ /* Get information about the next token. We need it in any case. */
+ token_len = peek_token_bracket (token, regexp, syntax);
+
+ /* Do not check for ranges if we know they are not allowed. */
+ if (start_elem.type != CHAR_CLASS && start_elem.type != EQUIV_CLASS)
+ {
+ if (BE (token->type == END_OF_RE, 0))
+ {
+ *err = REG_EBRACK;
+ goto parse_bracket_exp_free_return;
+ }
+ if (token->type == OP_CHARSET_RANGE)
+ {
+ re_string_skip_bytes (regexp, token_len); /* Skip '-'. */
+ token_len2 = peek_token_bracket (&token2, regexp, syntax);
+ if (BE (token2.type == END_OF_RE, 0))
+ {
+ *err = REG_EBRACK;
+ goto parse_bracket_exp_free_return;
+ }
+ if (token2.type == OP_CLOSE_BRACKET)
+ {
+ /* We treat the last '-' as a normal character. */
+ re_string_skip_bytes (regexp, -token_len);
+ token->type = CHARACTER;
+ }
+ else
+ is_range_exp = 1;
+ }
+ }
+
+ if (is_range_exp == 1)
+ {
+ end_elem.opr.name = end_name_buf;
+ ret = parse_bracket_element (&end_elem, regexp, &token2, token_len2,
+ dfa, syntax, 1);
+ if (BE (ret != REG_NOERROR, 0))
+ {
+ *err = ret;
+ goto parse_bracket_exp_free_return;
+ }
+
+ token_len = peek_token_bracket (token, regexp, syntax);
+
+#if 0
+ *err = build_range_exp (sbcset, mbcset, &range_alloc,
+ &start_elem, &end_elem);
+#else
+# ifdef RE_ENABLE_I18N
+ *err = build_range_exp (sbcset,
+ dfa->mb_cur_max > 1 ? mbcset : NULL,
+ &range_alloc, &start_elem, &end_elem);
+# else
+ *err = build_range_exp (sbcset, &start_elem, &end_elem);
+# endif
+#endif
+ if (BE (*err != REG_NOERROR, 0))
+ goto parse_bracket_exp_free_return;
+ }
+ else
+ {
+ switch (start_elem.type)
+ {
+ case SB_CHAR:
+ bitset_set (sbcset, start_elem.opr.ch);
+ break;
+#ifdef RE_ENABLE_I18N
+ case MB_CHAR:
+ /* Check whether the array has enough space. */
+ if (BE (mbchar_alloc == mbcset->nmbchars, 0))
+ {
+ wchar_t *new_mbchars;
+ /* Not enough, realloc it. */
+ /* +1 in case of mbcset->nmbchars is 0. */
+ mbchar_alloc = 2 * mbcset->nmbchars + 1;
+ /* Use realloc since array is NULL if *alloc == 0. */
+ new_mbchars = re_realloc (mbcset->mbchars, wchar_t,
+ mbchar_alloc);
+ if (BE (new_mbchars == NULL, 0))
+ goto parse_bracket_exp_espace;
+ mbcset->mbchars = new_mbchars;
+ }
+ mbcset->mbchars[mbcset->nmbchars++] = start_elem.opr.wch;
+ break;
+#endif /* RE_ENABLE_I18N */
+ case EQUIV_CLASS:
+ *err = build_equiv_class (sbcset,
+#ifdef RE_ENABLE_I18N
+ mbcset, &equiv_class_alloc,
+#endif
+ start_elem.opr.name);
+ if (BE (*err != REG_NOERROR, 0))
+ goto parse_bracket_exp_free_return;
+ break;
+ case COLL_SYM:
+ *err = build_collating_symbol (sbcset,
+#ifdef RE_ENABLE_I18N
+ mbcset, &coll_sym_alloc,
+#endif
+ start_elem.opr.name);
+ if (BE (*err != REG_NOERROR, 0))
+ goto parse_bracket_exp_free_return;
+ break;
+ case CHAR_CLASS:
+ *err = build_charclass (regexp->trans, sbcset,
+#ifdef RE_ENABLE_I18N
+ mbcset, &char_class_alloc,
+#endif
+ start_elem.opr.name, syntax);
+ if (BE (*err != REG_NOERROR, 0))
+ goto parse_bracket_exp_free_return;
+ break;
+ default:
+ assert (0);
+ break;
+ }
+ }
+ if (BE (token->type == END_OF_RE, 0))
+ {
+ *err = REG_EBRACK;
+ goto parse_bracket_exp_free_return;
+ }
+ if (token->type == OP_CLOSE_BRACKET)
+ break;
+ }
+
+ re_string_skip_bytes (regexp, token_len); /* Skip a token. */
+
+ /* If it is non-matching list. */
+ if (non_match)
+ bitset_not (sbcset);
+
+#ifdef RE_ENABLE_I18N
+ /* Ensure only single byte characters are set. */
+ if (dfa->mb_cur_max > 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->non_match)))
+ {
+ bin_tree_t *mbc_tree;
+ int sbc_idx;
+ /* Build a tree for complex bracket. */
+ dfa->has_mb_node = 1;
+ br_token.type = COMPLEX_BRACKET;
+ br_token.opr.mbcset = mbcset;
+ mbc_tree = create_token_tree (dfa, NULL, NULL, &br_token);
+ if (BE (mbc_tree == NULL, 0))
+ goto parse_bracket_exp_espace;
+ for (sbc_idx = 0; sbc_idx < BITSET_WORDS; ++sbc_idx)
+ if (sbcset[sbc_idx])
+ break;
+ /* If there are no bits set in sbcset, there is no point
+ of having both SIMPLE_BRACKET and COMPLEX_BRACKET. */
+ if (sbc_idx < BITSET_WORDS)
+ {
+ /* Build a tree for simple bracket. */
+ br_token.type = SIMPLE_BRACKET;
+ br_token.opr.sbcset = sbcset;
+ work_tree = create_token_tree (dfa, NULL, NULL, &br_token);
+ if (BE (work_tree == NULL, 0))
+ goto parse_bracket_exp_espace;
+
+ /* Then join them by ALT node. */
+ work_tree = create_tree (dfa, work_tree, mbc_tree, OP_ALT);
+ if (BE (work_tree == NULL, 0))
+ goto parse_bracket_exp_espace;
+ }
+ else
+ {
+ re_free (sbcset);
+ work_tree = mbc_tree;
+ }
+ }
+ else
+#endif /* not RE_ENABLE_I18N */
+ {
+#ifdef RE_ENABLE_I18N
+ free_charset (mbcset);
+#endif
+ /* Build a tree for simple bracket. */
+ br_token.type = SIMPLE_BRACKET;
+ br_token.opr.sbcset = sbcset;
+ work_tree = create_token_tree (dfa, NULL, NULL, &br_token);
+ if (BE (work_tree == NULL, 0))
+ goto parse_bracket_exp_espace;
+ }
+ return work_tree;
+
+ parse_bracket_exp_espace:
+ *err = REG_ESPACE;
+ parse_bracket_exp_free_return:
+ re_free (sbcset);
+#ifdef RE_ENABLE_I18N
+ free_charset (mbcset);
+#endif
+ return NULL;
+}
+
+/* Parse an element in the bracket expression. */
+
+static reg_errcode_t
+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
+ int cur_char_size;
+ cur_char_size = re_string_char_size_at (regexp, re_string_cur_idx (regexp));
+ if (cur_char_size > 1)
+ {
+ elem->type = MB_CHAR;
+ elem->opr.wch = re_string_wchar_at (regexp, re_string_cur_idx (regexp));
+ re_string_skip_bytes (regexp, cur_char_size);
+ return REG_NOERROR;
+ }
+#endif /* RE_ENABLE_I18N */
+ 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)
+ return parse_bracket_symbol (elem, regexp, token);
+ if (BE (token->type == OP_CHARSET_RANGE, 0) && !accept_hyphen)
+ {
+ /* A '-' must only appear as anything but a range indicator before
+ the closing bracket. Everything else is an error. */
+ re_token_t token2;
+ (void) peek_token_bracket (&token2, regexp, syntax);
+ if (token2.type != OP_CLOSE_BRACKET)
+ /* The actual error value is not standardized since this whole
+ case is undefined. But ERANGE makes good sense. */
+ return REG_ERANGE;
+ }
+ elem->type = SB_CHAR;
+ elem->opr.ch = token->opr.c;
+ return REG_NOERROR;
+}
+
+/* Parse a bracket symbol in the bracket expression. Bracket symbols are
+ such as [:<character_class>:], [.<collating_element>.], and
+ [=<equivalent_class>=]. */
+
+static reg_errcode_t
+parse_bracket_symbol (bracket_elem_t *elem, re_string_t *regexp,
+ re_token_t *token)
+{
+ unsigned char ch, delim = token->opr.c;
+ int i = 0;
+ if (re_string_eoi(regexp))
+ return REG_EBRACK;
+ for (;; ++i)
+ {
+ if (i >= BRACKET_NAME_BUF_SIZE)
+ return REG_EBRACK;
+ if (token->type == OP_OPEN_CHAR_CLASS)
+ ch = re_string_fetch_byte_case (regexp);
+ else
+ ch = re_string_fetch_byte (regexp);
+ if (re_string_eoi(regexp))
+ return REG_EBRACK;
+ if (ch == delim && re_string_peek_byte (regexp, 0) == ']')
+ break;
+ elem->opr.name[i] = ch;
+ }
+ re_string_skip_bytes (regexp, 1);
+ elem->opr.name[i] = '\0';
+ switch (token->type)
+ {
+ case OP_OPEN_COLL_ELEM:
+ elem->type = COLL_SYM;
+ break;
+ case OP_OPEN_EQUIV_CLASS:
+ elem->type = EQUIV_CLASS;
+ break;
+ case OP_OPEN_CHAR_CLASS:
+ elem->type = CHAR_CLASS;
+ break;
+ default:
+ break;
+ }
+ return REG_NOERROR;
+}
+
+ /* Helper function for parse_bracket_exp.
+ Build the equivalence class which is represented by NAME.
+ The result are written to MBCSET and SBCSET.
+ EQUIV_CLASS_ALLOC is the allocated size of mbcset->equiv_classes,
+ is a pointer argument sinse we may update it. */
+
+static reg_errcode_t
+#ifdef RE_ENABLE_I18N
+build_equiv_class (bitset_t sbcset, re_charset_t *mbcset,
+ int *equiv_class_alloc, const unsigned char *name)
+#else
+build_equiv_class (bitset_t sbcset, const unsigned char *name)
+#endif
+{
+#if 0
+ uint32_t nrules = _NL_CURRENT_WORD (LC_COLLATE, _NL_COLLATE_NRULES);
+ if (nrules != 0)
+ {
+ const int32_t *table, *indirect;
+ const unsigned char *weights, *extra, *cp;
+ unsigned char char_buf[2];
+ int32_t idx1, idx2;
+ unsigned int ch;
+ size_t len;
+ /* This #include defines a local function! */
+# include <locale/weight.h>
+ /* Calculate the index for equivalence class. */
+ cp = name;
+ 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);
+ idx1 = findidx (&cp);
+ if (BE (idx1 == 0 || cp < name + strlen ((const char *) name), 0))
+ /* This isn't a valid character. */
+ return REG_ECOLLATE;
+
+ /* Build single byte matcing table for this equivalence class. */
+ char_buf[1] = (unsigned char) '\0';
+ len = weights[idx1];
+ for (ch = 0; ch < SBC_MAX; ++ch)
+ {
+ char_buf[0] = ch;
+ cp = char_buf;
+ idx2 = findidx (&cp);
+/*
+ idx2 = table[ch];
+*/
+ if (idx2 == 0)
+ /* This isn't a valid character. */
+ continue;
+ if (len == weights[idx2])
+ {
+ int cnt = 0;
+ while (cnt <= len &&
+ weights[idx1 + 1 + cnt] == weights[idx2 + 1 + cnt])
+ ++cnt;
+
+ if (cnt > len)
+ bitset_set (sbcset, ch);
+ }
+ }
+ /* Check whether the array has enough space. */
+ if (BE (*equiv_class_alloc == mbcset->nequiv_classes, 0))
+ {
+ /* Not enough, realloc it. */
+ /* +1 in case of mbcset->nequiv_classes is 0. */
+ int new_equiv_class_alloc = 2 * mbcset->nequiv_classes + 1;
+ /* Use realloc since the array is NULL if *alloc == 0. */
+ int32_t *new_equiv_classes = re_realloc (mbcset->equiv_classes,
+ int32_t,
+ new_equiv_class_alloc);
+ if (BE (new_equiv_classes == NULL, 0))
+ return REG_ESPACE;
+ mbcset->equiv_classes = new_equiv_classes;
+ *equiv_class_alloc = new_equiv_class_alloc;
+ }
+ mbcset->equiv_classes[mbcset->nequiv_classes++] = idx1;
+ }
+ else
+#endif
+ {
+ if (BE (strlen ((const char *) name) != 1, 0))
+ return REG_ECOLLATE;
+ bitset_set (sbcset, *name);
+ }
+ return REG_NOERROR;
+}
+
+ /* Helper function for parse_bracket_exp.
+ Build the character class which is represented by NAME.
+ The result are written to MBCSET and SBCSET.
+ CHAR_CLASS_ALLOC is the allocated size of mbcset->char_classes,
+ is a pointer argument sinse we may update it. */
+
+static reg_errcode_t
+#ifdef RE_ENABLE_I18N
+build_charclass (RE_TRANSLATE_TYPE trans, bitset_t sbcset,
+ re_charset_t *mbcset, int *char_class_alloc,
+ const unsigned char *class_name, reg_syntax_t syntax)
+#else
+build_charclass (RE_TRANSLATE_TYPE trans, bitset_t sbcset,
+ const unsigned char *class_name, reg_syntax_t syntax)
+#endif
+{
+ int i;
+ const char *name = (const char *) class_name;
+
+ /* In case of REG_ICASE "upper" and "lower" match the both of
+ upper and lower cases. */
+ if ((syntax & RE_ICASE)
+ && (strcmp (name, "upper") == 0 || strcmp (name, "lower") == 0))
+ name = "alpha";
+
+#ifdef RE_ENABLE_I18N
+ /* Check the space of the arrays. */
+ if (BE (*char_class_alloc == mbcset->nchar_classes, 0))
+ {
+ /* Not enough, realloc it. */
+ /* +1 in case of mbcset->nchar_classes is 0. */
+ int new_char_class_alloc = 2 * mbcset->nchar_classes + 1;
+ /* Use realloc since array is NULL if *alloc == 0. */
+ wctype_t *new_char_classes = re_realloc (mbcset->char_classes, wctype_t,
+ new_char_class_alloc);
+ if (BE (new_char_classes == NULL, 0))
+ return REG_ESPACE;
+ mbcset->char_classes = new_char_classes;
+ *char_class_alloc = new_char_class_alloc;
+ }
+ mbcset->char_classes[mbcset->nchar_classes++] = __wctype (name);
+#endif /* RE_ENABLE_I18N */
+
+#define BUILD_CHARCLASS_LOOP(ctype_func) \
+ do { \
+ if (BE (trans != NULL, 0)) \
+ { \
+ for (i = 0; i < SBC_MAX; ++i) \
+ if (ctype_func (i)) \
+ bitset_set (sbcset, trans[i]); \
+ } \
+ else \
+ { \
+ for (i = 0; i < SBC_MAX; ++i) \
+ if (ctype_func (i)) \
+ bitset_set (sbcset, i); \
+ } \
+ } while (0)
+
+ if (strcmp (name, "alnum") == 0)
+ BUILD_CHARCLASS_LOOP (isalnum);
+ else if (strcmp (name, "cntrl") == 0)
+ BUILD_CHARCLASS_LOOP (iscntrl);
+ else if (strcmp (name, "lower") == 0)
+ BUILD_CHARCLASS_LOOP (islower);
+ else if (strcmp (name, "space") == 0)
+ BUILD_CHARCLASS_LOOP (isspace);
+ else if (strcmp (name, "alpha") == 0)
+ BUILD_CHARCLASS_LOOP (isalpha);
+ else if (strcmp (name, "digit") == 0)
+ BUILD_CHARCLASS_LOOP (isdigit);
+ else if (strcmp (name, "print") == 0)
+ BUILD_CHARCLASS_LOOP (isprint);
+ else if (strcmp (name, "upper") == 0)
+ BUILD_CHARCLASS_LOOP (isupper);
+ else if (strcmp (name, "blank") == 0)
+ BUILD_CHARCLASS_LOOP (isblank);
+ else if (strcmp (name, "graph") == 0)
+ BUILD_CHARCLASS_LOOP (isgraph);
+ else if (strcmp (name, "punct") == 0)
+ BUILD_CHARCLASS_LOOP (ispunct);
+ else if (strcmp (name, "xdigit") == 0)
+ BUILD_CHARCLASS_LOOP (isxdigit);
+ else
+ return REG_ECTYPE;
+
+ return REG_NOERROR;
+}
+
+static bin_tree_t *
+build_charclass_op (re_dfa_t *dfa, RE_TRANSLATE_TYPE trans,
+ const unsigned char *class_name,
+ const unsigned char *extra, int non_match,
+ reg_errcode_t *err)
+{
+ re_bitset_ptr_t sbcset;
+#ifdef RE_ENABLE_I18N
+ re_charset_t *mbcset;
+ int alloc = 0;
+#endif
+ reg_errcode_t ret;
+ re_token_t br_token;
+ bin_tree_t *tree;
+
+ sbcset = calloc (sizeof (bitset_t), 1);
+#ifdef RE_ENABLE_I18N
+ mbcset = calloc (sizeof (re_charset_t), 1);
+#endif
+
+#ifdef RE_ENABLE_I18N
+ if (BE (sbcset == NULL || mbcset == NULL, 0))
+#else
+ if (BE (sbcset == NULL, 0))
+#endif
+ {
+ *err = REG_ESPACE;
+ return NULL;
+ }
+
+ if (non_match)
+ {
+#ifdef RE_ENABLE_I18N
+ /*
+ if (syntax & RE_HAT_LISTS_NOT_NEWLINE)
+ bitset_set(cset->sbcset, '\0');
+ */
+ mbcset->non_match = 1;
+#endif
+ }
+
+ /* We don't care the syntax in this case. */
+ ret = build_charclass (trans, sbcset,
+#ifdef RE_ENABLE_I18N
+ mbcset, &alloc,
+#endif
+ class_name, 0);
+
+ if (BE (ret != REG_NOERROR, 0))
+ {
+ re_free (sbcset);
+#ifdef RE_ENABLE_I18N
+ free_charset (mbcset);
+#endif
+ *err = ret;
+ return NULL;
+ }
+ /* \w match '_' also. */
+ for (; *extra; extra++)
+ bitset_set (sbcset, *extra);
+
+ /* If it is non-matching list. */
+ if (non_match)
+ bitset_not (sbcset);
+
+#ifdef RE_ENABLE_I18N
+ /* Ensure only single byte characters are set. */
+ if (dfa->mb_cur_max > 1)
+ bitset_mask (sbcset, dfa->sb_char);
+#endif
+
+ /* Build a tree for simple bracket. */
+ br_token.type = SIMPLE_BRACKET;
+ br_token.opr.sbcset = sbcset;
+ tree = create_token_tree (dfa, NULL, NULL, &br_token);
+ if (BE (tree == NULL, 0))
+ goto build_word_op_espace;
+
+#ifdef RE_ENABLE_I18N
+ if (dfa->mb_cur_max > 1)
+ {
+ bin_tree_t *mbc_tree;
+ /* Build a tree for complex bracket. */
+ br_token.type = COMPLEX_BRACKET;
+ br_token.opr.mbcset = mbcset;
+ dfa->has_mb_node = 1;
+ mbc_tree = create_token_tree (dfa, NULL, NULL, &br_token);
+ if (BE (mbc_tree == NULL, 0))
+ goto build_word_op_espace;
+ /* Then join them by ALT node. */
+ tree = create_tree (dfa, tree, mbc_tree, OP_ALT);
+ if (BE (mbc_tree != NULL, 1))
+ return tree;
+ }
+ else
+ {
+ free_charset (mbcset);
+ return tree;
+ }
+#else /* not RE_ENABLE_I18N */
+ return tree;
+#endif
+
+ build_word_op_espace:
+ re_free (sbcset);
+#ifdef RE_ENABLE_I18N
+ free_charset (mbcset);
+#endif
+ *err = REG_ESPACE;
+ return NULL;
+}
+
+/* This is intended for the expressions like "a{1,3}".
+ Fetch a number from `input', and return the number.
+ Return -1, if the number field is empty like "{,1}".
+ Return -2, If an error is occured. */
+
+static int
+fetch_number (re_string_t *input, re_token_t *token, reg_syntax_t syntax)
+{
+ int num = -1;
+ unsigned char c;
+ while (1)
+ {
+ fetch_token (token, input, syntax);
+ c = token->opr.c;
+ if (BE (token->type == END_OF_RE, 0))
+ return -2;
+ if (token->type == OP_CLOSE_DUP_NUM || c == ',')
+ break;
+ num = ((token->type != CHARACTER || c < '0' || '9' < c || num == -2)
+ ? -2 : ((num == -1) ? c - '0' : num * 10 + c - '0'));
+ num = (num > RE_DUP_MAX) ? -2 : num;
+ }
+ return num;
+}
+
+#ifdef RE_ENABLE_I18N
+static void
+free_charset (re_charset_t *cset)
+{
+ re_free (cset->mbchars);
+# if 0
+ re_free (cset->coll_syms);
+ re_free (cset->equiv_classes);
+ re_free (cset->range_starts);
+ re_free (cset->range_ends);
+# endif
+ re_free (cset->char_classes);
+ re_free (cset);
+}
+#endif /* RE_ENABLE_I18N */
+
+/* Functions for binary tree operation. */
+
+/* Create a tree node. */
+
+static bin_tree_t *
+create_tree (re_dfa_t *dfa, bin_tree_t *left, bin_tree_t *right,
+ re_token_type_t type)
+{
+ re_token_t t;
+ t.type = type;
+ return create_token_tree (dfa, left, right, &t);
+}
+
+static bin_tree_t *
+create_token_tree (re_dfa_t *dfa, bin_tree_t *left, bin_tree_t *right,
+ const re_token_t *token)
+{
+ bin_tree_t *tree;
+ if (BE (dfa->str_tree_storage_idx == BIN_TREE_STORAGE_SIZE, 0))
+ {
+ bin_tree_storage_t *storage = re_malloc (bin_tree_storage_t, 1);
+
+ if (storage == NULL)
+ return NULL;
+ storage->next = dfa->str_tree_storage;
+ dfa->str_tree_storage = storage;
+ dfa->str_tree_storage_idx = 0;
+ }
+ tree = &dfa->str_tree_storage->data[dfa->str_tree_storage_idx++];
+
+ tree->parent = NULL;
+ tree->left = left;
+ tree->right = right;
+ tree->token = *token;
+ tree->token.duplicated = 0;
+ tree->token.opt_subexp = 0;
+ tree->first = NULL;
+ tree->next = NULL;
+ tree->node_idx = -1;
+
+ if (left != NULL)
+ left->parent = tree;
+ if (right != NULL)
+ right->parent = tree;
+ return tree;
+}
+
+/* Mark the tree SRC as an optional subexpression.
+ To be called from preorder or postorder. */
+
+static reg_errcode_t
+mark_opt_subexp (void *extra, bin_tree_t *node)
+{
+ int idx = (int) (long) extra;
+ if (node->token.type == SUBEXP && node->token.opr.idx == idx)
+ node->token.opt_subexp = 1;
+
+ return REG_NOERROR;
+}
+
+/* Free the allocated memory inside NODE. */
+
+static void
+free_token (re_token_t *node)
+{
+#ifdef RE_ENABLE_I18N
+ if (node->type == COMPLEX_BRACKET && node->duplicated == 0)
+ free_charset (node->opr.mbcset);
+ else
+#endif
+ if (node->type == SIMPLE_BRACKET && node->duplicated == 0)
+ re_free (node->opr.sbcset);
+}
+
+/* Worker function for tree walking. Free the allocated memory inside NODE
+ and its children. */
+
+static reg_errcode_t
+free_tree (void *extra, bin_tree_t *node)
+{
+ free_token (&node->token);
+ return REG_NOERROR;
+}
+
+
+/* Duplicate the node SRC, and return new node. This is a preorder
+ visit similar to the one implemented by the generic visitor, but
+ we need more infrastructure to maintain two parallel trees --- so,
+ it's easier to duplicate. */
+
+static bin_tree_t *
+duplicate_tree (const bin_tree_t *root, re_dfa_t *dfa)
+{
+ const bin_tree_t *node;
+ bin_tree_t *dup_root;
+ bin_tree_t **p_new = &dup_root, *dup_node = root->parent;
+
+ for (node = root; ; )
+ {
+ /* Create a new tree and link it back to the current parent. */
+ *p_new = create_token_tree (dfa, NULL, NULL, &node->token);
+ if (*p_new == NULL)
+ return NULL;
+ (*p_new)->parent = dup_node;
+ (*p_new)->token.duplicated = 1;
+ dup_node = *p_new;
+
+ /* Go to the left node, or up and to the right. */
+ if (node->left)
+ {
+ node = node->left;
+ p_new = &dup_node->left;
+ }
+ else
+ {
+ const bin_tree_t *prev = NULL;
+ while (node->right == prev || node->right == NULL)
+ {
+ prev = node;
+ node = node->parent;
+ dup_node = dup_node->parent;
+ if (!node)
+ return dup_root;
+ }
+ node = node->right;
+ p_new = &dup_node->right;
+ }
+ }
+}
diff --git a/ap/build/uClibc/libc/misc/regex/regex.c b/ap/build/uClibc/libc/misc/regex/regex.c
new file mode 100644
index 0000000..fa46f63
--- /dev/null
+++ b/ap/build/uClibc/libc/misc/regex/regex.c
@@ -0,0 +1,58 @@
+/* Extended regular expression matching and search library.
+ Copyright (C) 2002, 2003, 2005 Free Software Foundation, Inc.
+ This file is part of the GNU C Library.
+ Contributed by Isamu Hasegawa <isamu@yamato.ibm.com>.
+
+ The GNU C Library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 2.1 of the License, or (at your option) any later version.
+
+ The GNU C Library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with the GNU C Library; if not, write to the Free
+ Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+ 02111-1307 USA. */
+
+#include <features.h>
+
+#ifdef __UCLIBC__
+# define _REGEX_RE_COMP
+# define HAVE_LANGINFO
+# define HAVE_LANGINFO_CODESET
+# include <stdbool.h>
+# include <stdint.h>
+# include <string.h>
+# include <stdlib.h>
+# ifdef __UCLIBC_HAS_WCHAR__
+# define RE_ENABLE_I18N
+# include <wchar.h>
+# include <wctype.h>
+# define __iswctype iswctype
+# define __wcrtomb wcrtomb
+# define __btowc btowc
+# define __wctype wctype
+# endif
+# include <ctype.h>
+#endif
+
+/* Make sure noone compiles this code with a C++ compiler. */
+#ifdef __cplusplus
+# error "This is C code, use a C compiler"
+#endif
+
+/* On some systems, limits.h sets RE_DUP_MAX to a lower value than
+ GNU regex allows. Include it before <regex.h>, which correctly
+ #undefs RE_DUP_MAX and sets it to the right value. */
+#include <limits.h>
+
+#include <regex.h>
+
+#include "regex_internal.h"
+#include "regex_internal.c"
+#include "regcomp.c"
+#include "regexec.c"
diff --git a/ap/build/uClibc/libc/misc/regex/regex_internal.c b/ap/build/uClibc/libc/misc/regex/regex_internal.c
new file mode 100644
index 0000000..c6ac8dd
--- /dev/null
+++ b/ap/build/uClibc/libc/misc/regex/regex_internal.c
@@ -0,0 +1,1640 @@
+/* Extended regular expression matching and search library.
+ Copyright (C) 2002, 2003, 2004, 2005, 2006 Free Software Foundation, Inc.
+ This file is part of the GNU C Library.
+ Contributed by Isamu Hasegawa <isamu@yamato.ibm.com>.
+
+ The GNU C Library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 2.1 of the License, or (at your option) any later version.
+
+ The GNU C Library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with the GNU C Library; if not, write to the Free
+ Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+ 02111-1307 USA. */
+
+static void re_string_construct_common (const char *str, int len,
+ re_string_t *pstr,
+ RE_TRANSLATE_TYPE trans, int icase,
+ const re_dfa_t *dfa) internal_function;
+static re_dfastate_t *create_ci_newstate (const re_dfa_t *dfa,
+ const re_node_set *nodes,
+ unsigned int hash) internal_function;
+static re_dfastate_t *create_cd_newstate (const re_dfa_t *dfa,
+ const re_node_set *nodes,
+ unsigned int context,
+ unsigned int hash) internal_function;
+
+/* Functions for string operation. */
+
+/* This function allocate the buffers. It is necessary to call
+ re_string_reconstruct before using the object. */
+
+static reg_errcode_t
+internal_function
+re_string_allocate (re_string_t *pstr, const char *str, int len, int init_len,
+ RE_TRANSLATE_TYPE trans, int icase, const re_dfa_t *dfa)
+{
+ reg_errcode_t ret;
+ 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;
+ init_buf_len = (len + 1 < init_len) ? len + 1: init_len;
+ re_string_construct_common (str, len, pstr, trans, icase, dfa);
+
+ ret = re_string_realloc_buffers (pstr, init_buf_len);
+ if (BE (ret != REG_NOERROR, 0))
+ return ret;
+
+ 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_raw_len = pstr->valid_len;
+ return REG_NOERROR;
+}
+
+/* This function allocate the buffers, and initialize them. */
+
+static reg_errcode_t
+internal_function
+re_string_construct (re_string_t *pstr, const char *str, int len,
+ RE_TRANSLATE_TYPE trans, int icase, const re_dfa_t *dfa)
+{
+ reg_errcode_t ret;
+ memset (pstr, '\0', sizeof (re_string_t));
+ re_string_construct_common (str, len, pstr, trans, icase, dfa);
+
+ if (len > 0)
+ {
+ ret = re_string_realloc_buffers (pstr, len + 1);
+ if (BE (ret != REG_NOERROR, 0))
+ return ret;
+ }
+ pstr->mbs = pstr->mbs_allocated ? pstr->mbs : (unsigned char *) str;
+
+ if (icase)
+ {
+#ifdef RE_ENABLE_I18N
+ if (dfa->mb_cur_max > 1)
+ {
+ while (1)
+ {
+ ret = build_wcs_upper_buffer (pstr);
+ if (BE (ret != REG_NOERROR, 0))
+ return ret;
+ if (pstr->valid_raw_len >= len)
+ break;
+ if (pstr->bufs_len > pstr->valid_len + dfa->mb_cur_max)
+ break;
+ ret = re_string_realloc_buffers (pstr, pstr->bufs_len * 2);
+ if (BE (ret != REG_NOERROR, 0))
+ return ret;
+ }
+ }
+ else
+#endif /* RE_ENABLE_I18N */
+ build_upper_buffer (pstr);
+ }
+ else
+ {
+#ifdef RE_ENABLE_I18N
+ if (dfa->mb_cur_max > 1)
+ build_wcs_buffer (pstr);
+ else
+#endif
+ {
+ if (trans != NULL)
+ re_string_translate_buffer (pstr);
+ else
+ {
+ pstr->valid_len = pstr->bufs_len;
+ pstr->valid_raw_len = pstr->bufs_len;
+ }
+ }
+ }
+
+ return REG_NOERROR;
+}
+
+/* Helper functions for re_string_allocate, and re_string_construct. */
+
+static reg_errcode_t
+internal_function
+re_string_realloc_buffers (re_string_t *pstr, int new_buf_len)
+{
+#ifdef RE_ENABLE_I18N
+ if (pstr->mb_cur_max > 1)
+ {
+ wint_t *new_wcs = re_realloc (pstr->wcs, wint_t, new_buf_len);
+ if (BE (new_wcs == NULL, 0))
+ return REG_ESPACE;
+ pstr->wcs = new_wcs;
+ if (pstr->offsets != NULL)
+ {
+ int *new_offsets = re_realloc (pstr->offsets, int, new_buf_len);
+ if (BE (new_offsets == NULL, 0))
+ return REG_ESPACE;
+ pstr->offsets = new_offsets;
+ }
+ }
+#endif /* RE_ENABLE_I18N */
+ if (pstr->mbs_allocated)
+ {
+ unsigned char *new_mbs = re_realloc (pstr->mbs, unsigned char,
+ new_buf_len);
+ if (BE (new_mbs == NULL, 0))
+ return REG_ESPACE;
+ pstr->mbs = new_mbs;
+ }
+ pstr->bufs_len = new_buf_len;
+ return REG_NOERROR;
+}
+
+
+static void
+internal_function
+re_string_construct_common (const char *str, int len, re_string_t *pstr,
+ RE_TRANSLATE_TYPE trans, int icase,
+ const re_dfa_t *dfa)
+{
+ pstr->raw_mbs = (const unsigned char *) str;
+ pstr->len = len;
+ pstr->raw_len = len;
+ pstr->trans = trans;
+ pstr->icase = icase ? 1 : 0;
+ pstr->mbs_allocated = (trans != NULL || icase);
+ pstr->mb_cur_max = dfa->mb_cur_max;
+ pstr->is_utf8 = dfa->is_utf8;
+ pstr->map_notascii = dfa->map_notascii;
+ pstr->stop = pstr->len;
+ pstr->raw_stop = pstr->stop;
+}
+
+#ifdef RE_ENABLE_I18N
+
+/* Build wide character buffer PSTR->WCS.
+ If the byte sequence of the string are:
+ <mb1>(0), <mb1>(1), <mb2>(0), <mb2>(1), <sb3>
+ Then wide character buffer will be:
+ <wc1> , WEOF , <wc2> , WEOF , <wc3>
+ We use WEOF for padding, they indicate that the position isn't
+ a first byte of a multibyte character.
+
+ Note that this function assumes PSTR->VALID_LEN elements are already
+ built and starts from PSTR->VALID_LEN. */
+
+static void
+internal_function
+build_wcs_buffer (re_string_t *pstr)
+{
+#if defined __UCLIBC__
+ unsigned char buf[MB_LEN_MAX];
+ assert (MB_LEN_MAX >= pstr->mb_cur_max);
+#else
+ unsigned char buf[64];
+#endif
+ mbstate_t prev_st;
+ int byte_idx, end_idx, remain_len;
+ size_t mbclen;
+
+ /* Build the buffers from pstr->valid_len to either pstr->len or
+ pstr->bufs_len. */
+ end_idx = (pstr->bufs_len > pstr->len) ? pstr->len : pstr->bufs_len;
+ for (byte_idx = pstr->valid_len; byte_idx < end_idx;)
+ {
+ wchar_t wc;
+ const char *p;
+
+ remain_len = end_idx - byte_idx;
+ prev_st = pstr->cur_state;
+ /* Apply the translation if we need. */
+ if (BE (pstr->trans != NULL, 0))
+ {
+ int i, ch;
+
+ for (i = 0; i < pstr->mb_cur_max && 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];
+ }
+ p = (const char *) buf;
+ }
+ else
+ p = (const char *) pstr->raw_mbs + pstr->raw_mbs_idx + byte_idx;
+ mbclen = mbrtowc (&wc, p, remain_len, &pstr->cur_state);
+ if (BE (mbclen == (size_t) -2, 0))
+ {
+ /* The buffer doesn't have enough space, finish to build. */
+ pstr->cur_state = prev_st;
+ break;
+ }
+ else if (BE (mbclen == (size_t) -1 || mbclen == 0, 0))
+ {
+ /* We treat these cases as a singlebyte character. */
+ mbclen = 1;
+ wc = (wchar_t) pstr->raw_mbs[pstr->raw_mbs_idx + byte_idx];
+ if (BE (pstr->trans != NULL, 0))
+ wc = pstr->trans[wc];
+ pstr->cur_state = prev_st;
+ }
+
+ /* Write wide character and padding. */
+ pstr->wcs[byte_idx++] = wc;
+ /* Write paddings. */
+ for (remain_len = byte_idx + mbclen - 1; byte_idx < remain_len ;)
+ pstr->wcs[byte_idx++] = WEOF;
+ }
+ pstr->valid_len = byte_idx;
+ pstr->valid_raw_len = byte_idx;
+}
+
+/* Build wide character buffer PSTR->WCS like build_wcs_buffer,
+ but for REG_ICASE. */
+
+static reg_errcode_t
+internal_function
+build_wcs_upper_buffer (re_string_t *pstr)
+{
+ mbstate_t prev_st;
+ int src_idx, byte_idx, end_idx, remain_len;
+ size_t mbclen;
+#if defined __UCLIBC__
+ char buf[MB_LEN_MAX];
+ assert (MB_LEN_MAX >= pstr->mb_cur_max);
+#else
+ char buf[64];
+#endif
+
+ byte_idx = pstr->valid_len;
+ end_idx = (pstr->bufs_len > pstr->len) ? pstr->len : pstr->bufs_len;
+
+ /* The following optimization assumes that ASCII characters can be
+ mapped to wide characters with a simple cast. */
+ if (! pstr->map_notascii && pstr->trans == NULL && !pstr->offsets_needed)
+ {
+ while (byte_idx < end_idx)
+ {
+ wchar_t wc;
+
+ if (isascii (pstr->raw_mbs[pstr->raw_mbs_idx + byte_idx])
+ && mbsinit (&pstr->cur_state))
+ {
+ /* In case of a singlebyte character. */
+ pstr->mbs[byte_idx]
+ = toupper (pstr->raw_mbs[pstr->raw_mbs_idx + byte_idx]);
+ /* The next step uses the assumption that wchar_t is encoded
+ ASCII-safe: all ASCII values can be converted like this. */
+ pstr->wcs[byte_idx] = (wchar_t) pstr->mbs[byte_idx];
+ ++byte_idx;
+ continue;
+ }
+
+ remain_len = end_idx - byte_idx;
+ prev_st = pstr->cur_state;
+ mbclen = mbrtowc (&wc,
+ ((const char *) pstr->raw_mbs + pstr->raw_mbs_idx
+ + byte_idx), remain_len, &pstr->cur_state);
+ if (BE (mbclen + 2 > 2, 1))
+ {
+ wchar_t wcu = wc;
+ if (iswlower (wc))
+ {
+ size_t mbcdlen;
+
+ wcu = towupper (wc);
+ mbcdlen = wcrtomb (buf, wcu, &prev_st);
+ if (BE (mbclen == mbcdlen, 1))
+ memcpy (pstr->mbs + byte_idx, buf, mbclen);
+ else
+ {
+ src_idx = byte_idx;
+ goto offsets_needed;
+ }
+ }
+ else
+ memcpy (pstr->mbs + byte_idx,
+ pstr->raw_mbs + pstr->raw_mbs_idx + byte_idx, mbclen);
+ pstr->wcs[byte_idx++] = wcu;
+ /* Write paddings. */
+ for (remain_len = byte_idx + mbclen - 1; byte_idx < remain_len ;)
+ pstr->wcs[byte_idx++] = WEOF;
+ }
+ else if (mbclen == (size_t) -1 || mbclen == 0)
+ {
+ /* It is an invalid character or '\0'. Just use the byte. */
+ int ch = pstr->raw_mbs[pstr->raw_mbs_idx + byte_idx];
+ pstr->mbs[byte_idx] = ch;
+ /* And also cast it to wide char. */
+ pstr->wcs[byte_idx++] = (wchar_t) ch;
+ if (BE (mbclen == (size_t) -1, 0))
+ pstr->cur_state = prev_st;
+ }
+ else
+ {
+ /* The buffer doesn't have enough space, finish to build. */
+ pstr->cur_state = prev_st;
+ break;
+ }
+ }
+ pstr->valid_len = byte_idx;
+ pstr->valid_raw_len = byte_idx;
+ return REG_NOERROR;
+ }
+ else
+ for (src_idx = pstr->valid_raw_len; byte_idx < end_idx;)
+ {
+ wchar_t wc;
+ const char *p;
+ offsets_needed:
+ remain_len = end_idx - byte_idx;
+ prev_st = pstr->cur_state;
+ if (BE (pstr->trans != NULL, 0))
+ {
+ int i, ch;
+
+ for (i = 0; i < pstr->mb_cur_max && i < remain_len; ++i)
+ {
+ ch = pstr->raw_mbs [pstr->raw_mbs_idx + src_idx + i];
+ buf[i] = pstr->trans[ch];
+ }
+ p = (const char *) buf;
+ }
+ else
+ p = (const char *) pstr->raw_mbs + pstr->raw_mbs_idx + src_idx;
+ mbclen = mbrtowc (&wc, p, remain_len, &pstr->cur_state);
+ if (BE (mbclen + 2 > 2, 1))
+ {
+ wchar_t wcu = wc;
+ if (iswlower (wc))
+ {
+ size_t mbcdlen;
+
+ wcu = towupper (wc);
+ mbcdlen = wcrtomb ((char *) buf, wcu, &prev_st);
+ if (BE (mbclen == mbcdlen, 1))
+ memcpy (pstr->mbs + byte_idx, buf, mbclen);
+ else if (mbcdlen != (size_t) -1)
+ {
+ size_t i;
+
+ if (byte_idx + mbcdlen > pstr->bufs_len)
+ {
+ pstr->cur_state = prev_st;
+ break;
+ }
+
+ if (pstr->offsets == NULL)
+ {
+ pstr->offsets = re_malloc (int, pstr->bufs_len);
+
+ if (pstr->offsets == NULL)
+ return REG_ESPACE;
+ }
+ if (!pstr->offsets_needed)
+ {
+ for (i = 0; i < (size_t) byte_idx; ++i)
+ pstr->offsets[i] = i;
+ pstr->offsets_needed = 1;
+ }
+
+ memcpy (pstr->mbs + byte_idx, buf, mbcdlen);
+ pstr->wcs[byte_idx] = wcu;
+ pstr->offsets[byte_idx] = src_idx;
+ for (i = 1; i < mbcdlen; ++i)
+ {
+ pstr->offsets[byte_idx + i]
+ = src_idx + (i < mbclen ? i : mbclen - 1);
+ pstr->wcs[byte_idx + i] = WEOF;
+ }
+ pstr->len += mbcdlen - mbclen;
+ if (pstr->raw_stop > src_idx)
+ pstr->stop += mbcdlen - mbclen;
+ end_idx = (pstr->bufs_len > pstr->len)
+ ? pstr->len : pstr->bufs_len;
+ byte_idx += mbcdlen;
+ src_idx += mbclen;
+ continue;
+ }
+ else
+ memcpy (pstr->mbs + byte_idx, p, mbclen);
+ }
+ else
+ memcpy (pstr->mbs + byte_idx, p, mbclen);
+
+ if (BE (pstr->offsets_needed != 0, 0))
+ {
+ size_t i;
+ for (i = 0; i < mbclen; ++i)
+ pstr->offsets[byte_idx + i] = src_idx + i;
+ }
+ src_idx += mbclen;
+
+ pstr->wcs[byte_idx++] = wcu;
+ /* Write paddings. */
+ for (remain_len = byte_idx + mbclen - 1; byte_idx < remain_len ;)
+ pstr->wcs[byte_idx++] = WEOF;
+ }
+ else if (mbclen == (size_t) -1 || mbclen == 0)
+ {
+ /* It is an invalid character or '\0'. Just use the byte. */
+ int ch = pstr->raw_mbs[pstr->raw_mbs_idx + src_idx];
+
+ if (BE (pstr->trans != NULL, 0))
+ ch = pstr->trans [ch];
+ pstr->mbs[byte_idx] = ch;
+
+ if (BE (pstr->offsets_needed != 0, 0))
+ pstr->offsets[byte_idx] = src_idx;
+ ++src_idx;
+
+ /* And also cast it to wide char. */
+ pstr->wcs[byte_idx++] = (wchar_t) ch;
+ if (BE (mbclen == (size_t) -1, 0))
+ pstr->cur_state = prev_st;
+ }
+ else
+ {
+ /* The buffer doesn't have enough space, finish to build. */
+ pstr->cur_state = prev_st;
+ break;
+ }
+ }
+ pstr->valid_len = byte_idx;
+ pstr->valid_raw_len = src_idx;
+ return REG_NOERROR;
+}
+
+/* Skip characters until the index becomes greater than NEW_RAW_IDX.
+ Return the index. */
+
+static int
+internal_function
+re_string_skip_chars (re_string_t *pstr, int new_raw_idx, wint_t *last_wc)
+{
+ mbstate_t prev_st;
+ int rawbuf_idx;
+ size_t mbclen;
+ wchar_t wc = 0;
+
+ /* Skip the characters which are not necessary to check. */
+ for (rawbuf_idx = pstr->raw_mbs_idx + pstr->valid_raw_len;
+ rawbuf_idx < new_raw_idx;)
+ {
+ int remain_len;
+ remain_len = pstr->len - rawbuf_idx;
+ prev_st = pstr->cur_state;
+ mbclen = mbrtowc (&wc, (const char *) pstr->raw_mbs + rawbuf_idx,
+ remain_len, &pstr->cur_state);
+ if (BE (mbclen == (size_t) -2 || mbclen == (size_t) -1 || mbclen == 0, 0))
+ {
+ /* We treat these cases as a singlebyte character. */
+ mbclen = 1;
+ pstr->cur_state = prev_st;
+ }
+ /* Then proceed the next character. */
+ rawbuf_idx += mbclen;
+ }
+ *last_wc = (wint_t) wc;
+ return rawbuf_idx;
+}
+#endif /* RE_ENABLE_I18N */
+
+/* Build the buffer PSTR->MBS, and apply the translation if we need.
+ This function is used in case of REG_ICASE. */
+
+static void
+internal_function
+build_upper_buffer (re_string_t *pstr)
+{
+ int char_idx, end_idx;
+ end_idx = (pstr->bufs_len > pstr->len) ? pstr->len : pstr->bufs_len;
+
+ for (char_idx = pstr->valid_len; char_idx < end_idx; ++char_idx)
+ {
+ int ch = pstr->raw_mbs[pstr->raw_mbs_idx + char_idx];
+ if (BE (pstr->trans != NULL, 0))
+ ch = pstr->trans[ch];
+ if (islower (ch))
+ pstr->mbs[char_idx] = toupper (ch);
+ else
+ pstr->mbs[char_idx] = ch;
+ }
+ pstr->valid_len = char_idx;
+ pstr->valid_raw_len = char_idx;
+}
+
+/* Apply TRANS to the buffer in PSTR. */
+
+static void
+internal_function
+re_string_translate_buffer (re_string_t *pstr)
+{
+ int buf_idx, end_idx;
+ end_idx = (pstr->bufs_len > pstr->len) ? pstr->len : pstr->bufs_len;
+
+ for (buf_idx = pstr->valid_len; buf_idx < end_idx; ++buf_idx)
+ {
+ int ch = pstr->raw_mbs[pstr->raw_mbs_idx + buf_idx];
+ pstr->mbs[buf_idx] = pstr->trans[ch];
+ }
+
+ pstr->valid_len = buf_idx;
+ pstr->valid_raw_len = buf_idx;
+}
+
+/* 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. */
+
+static reg_errcode_t
+internal_function
+re_string_reconstruct (re_string_t *pstr, int idx, int eflags)
+{
+ int offset = idx - pstr->raw_mbs_idx;
+ if (BE (offset < 0, 0))
+ {
+ /* Reset buffer. */
+#ifdef RE_ENABLE_I18N
+ if (pstr->mb_cur_max > 1)
+ memset (&pstr->cur_state, '\0', sizeof (mbstate_t));
+#endif
+ pstr->len = pstr->raw_len;
+ pstr->stop = pstr->raw_stop;
+ pstr->valid_len = 0;
+ pstr->raw_mbs_idx = 0;
+ pstr->valid_raw_len = 0;
+ pstr->offsets_needed = 0;
+ pstr->tip_context = ((eflags & REG_NOTBOL) ? CONTEXT_BEGBUF
+ : CONTEXT_NEWLINE | CONTEXT_BEGBUF);
+ if (!pstr->mbs_allocated)
+ pstr->mbs = (unsigned char *) pstr->raw_mbs;
+ offset = idx;
+ }
+
+ if (BE (offset != 0, 1))
+ {
+ /* Are the characters which are already checked remain? */
+ if (BE (offset < pstr->valid_raw_len, 1)
+#ifdef RE_ENABLE_I18N
+ /* Handling this would enlarge the code too much.
+ Accept a slowdown in that case. */
+ && pstr->offsets_needed == 0
+#endif
+ )
+ {
+ /* Yes, move them to the front of the buffer. */
+ pstr->tip_context = re_string_context_at (pstr, offset - 1, eflags);
+#ifdef RE_ENABLE_I18N
+ if (pstr->mb_cur_max > 1)
+ memmove (pstr->wcs, pstr->wcs + offset,
+ (pstr->valid_len - offset) * sizeof (wint_t));
+#endif
+ if (BE (pstr->mbs_allocated, 0))
+ memmove (pstr->mbs, pstr->mbs + offset,
+ pstr->valid_len - offset);
+ pstr->valid_len -= offset;
+ pstr->valid_raw_len -= offset;
+#ifdef DEBUG
+ assert (pstr->valid_len > 0);
+#endif
+ }
+ else
+ {
+ /* No, skip all characters until IDX. */
+#ifdef RE_ENABLE_I18N
+ if (BE (pstr->offsets_needed, 0))
+ {
+ pstr->len = pstr->raw_len - idx + offset;
+ pstr->stop = pstr->raw_stop - idx + offset;
+ pstr->offsets_needed = 0;
+ }
+#endif
+ pstr->valid_len = 0;
+ pstr->valid_raw_len = 0;
+#ifdef RE_ENABLE_I18N
+ if (pstr->mb_cur_max > 1)
+ {
+ int wcs_idx;
+ wint_t wc = WEOF;
+
+ if (pstr->is_utf8)
+ {
+ const unsigned char *raw, *p, *end;
+
+ /* 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);
+ p = raw + offset - 1;
+#if 0
+ /* We know the wchar_t encoding is UCS4, so for the simple
+ case, ASCII characters, skip the conversion step. */
+ if (isascii (*p) && BE (pstr->trans == NULL, 1))
+ {
+ memset (&pstr->cur_state, '\0', sizeof (mbstate_t));
+ pstr->valid_len = 0;
+ wc = (wchar_t) *p;
+ }
+ else
+#endif
+ for (; p >= end; --p)
+ if ((*p & 0xc0) != 0x80)
+ {
+ mbstate_t cur_state;
+ wchar_t wc2;
+ int mlen = raw + pstr->len - p;
+ unsigned char buf[6];
+ size_t mbclen;
+
+ if (BE (pstr->trans != NULL, 0))
+ {
+ int i = mlen < 6 ? mlen : 6;
+ while (--i >= 0)
+ buf[i] = pstr->trans[p[i]];
+ }
+ /* XXX Don't use mbrtowc, we know which conversion
+ to use (UTF-8 -> UCS4). */
+ memset (&cur_state, 0, sizeof (cur_state));
+ mbclen = mbrtowc (&wc2, (const char *) p, mlen,
+ &cur_state);
+ if (raw + offset - p <= mbclen
+ && mbclen < (size_t) -2)
+ {
+ memset (&pstr->cur_state, '\0',
+ sizeof (mbstate_t));
+ pstr->valid_len = mbclen - (raw + offset - p);
+ wc = wc2;
+ }
+ break;
+ }
+ }
+
+ if (wc == WEOF)
+ pstr->valid_len = re_string_skip_chars (pstr, idx, &wc) - idx;
+ if (BE (pstr->valid_len, 0))
+ {
+ for (wcs_idx = 0; wcs_idx < pstr->valid_len; ++wcs_idx)
+ pstr->wcs[wcs_idx] = WEOF;
+ if (pstr->mbs_allocated)
+ memset (pstr->mbs, 255, pstr->valid_len);
+ }
+ pstr->valid_raw_len = pstr->valid_len;
+ pstr->tip_context = ((BE (pstr->word_ops_used != 0, 0)
+ && IS_WIDE_WORD_CHAR (wc))
+ ? CONTEXT_WORD
+ : ((IS_WIDE_NEWLINE (wc)
+ && pstr->newline_anchor)
+ ? CONTEXT_NEWLINE : 0));
+ }
+ else
+#endif /* RE_ENABLE_I18N */
+ {
+ int c = pstr->raw_mbs[pstr->raw_mbs_idx + offset - 1];
+ if (pstr->trans)
+ c = pstr->trans[c];
+ pstr->tip_context = (bitset_contain (pstr->word_char, c)
+ ? CONTEXT_WORD
+ : ((IS_NEWLINE (c) && pstr->newline_anchor)
+ ? CONTEXT_NEWLINE : 0));
+ }
+ }
+ if (!BE (pstr->mbs_allocated, 0))
+ pstr->mbs += offset;
+ }
+ pstr->raw_mbs_idx = idx;
+ pstr->len -= offset;
+ pstr->stop -= offset;
+
+ /* Then build the buffers. */
+#ifdef RE_ENABLE_I18N
+ if (pstr->mb_cur_max > 1)
+ {
+ if (pstr->icase)
+ {
+ reg_errcode_t ret = build_wcs_upper_buffer (pstr);
+ if (BE (ret != REG_NOERROR, 0))
+ return ret;
+ }
+ else
+ build_wcs_buffer (pstr);
+ }
+ else
+#endif
+ if (BE (pstr->mbs_allocated, 0))
+ {
+ if (pstr->icase)
+ build_upper_buffer (pstr);
+ else if (pstr->trans != NULL)
+ re_string_translate_buffer (pstr);
+ }
+ else
+ pstr->valid_len = pstr->len;
+
+ pstr->cur_idx = 0;
+ return REG_NOERROR;
+}
+
+static unsigned char
+internal_function __attribute ((pure))
+re_string_peek_byte_case (const re_string_t *pstr, int idx)
+{
+ int ch, off;
+
+ /* Handle the common (easiest) cases first. */
+ if (BE (!pstr->mbs_allocated, 1))
+ return re_string_peek_byte (pstr, idx);
+
+#ifdef RE_ENABLE_I18N
+ if (pstr->mb_cur_max > 1
+ && ! re_string_is_single_byte_char (pstr, pstr->cur_idx + idx))
+ return re_string_peek_byte (pstr, idx);
+#endif
+
+ off = pstr->cur_idx + idx;
+#ifdef RE_ENABLE_I18N
+ if (pstr->offsets_needed)
+ off = pstr->offsets[off];
+#endif
+
+ ch = pstr->raw_mbs[pstr->raw_mbs_idx + off];
+
+#ifdef RE_ENABLE_I18N
+ /* Ensure that e.g. for tr_TR.UTF-8 BACKSLASH DOTLESS SMALL LETTER I
+ this function returns CAPITAL LETTER I instead of first byte of
+ DOTLESS SMALL LETTER I. The latter would confuse the parser,
+ since peek_byte_case doesn't advance cur_idx in any way. */
+ if (pstr->offsets_needed && !isascii (ch))
+ return re_string_peek_byte (pstr, idx);
+#endif
+
+ return ch;
+}
+
+static unsigned char
+internal_function __attribute ((pure))
+re_string_fetch_byte_case (re_string_t *pstr)
+{
+ if (BE (!pstr->mbs_allocated, 1))
+ return re_string_fetch_byte (pstr);
+
+#ifdef RE_ENABLE_I18N
+ if (pstr->offsets_needed)
+ {
+ int off, ch;
+
+ /* For tr_TR.UTF-8 [[:islower:]] there is
+ [[: CAPITAL LETTER I WITH DOT lower:]] in mbs. Skip
+ in that case the whole multi-byte character and return
+ the original letter. On the other side, with
+ [[: DOTLESS SMALL LETTER I return [[:I, as doing
+ anything else would complicate things too much. */
+
+ if (!re_string_first_byte (pstr, pstr->cur_idx))
+ return re_string_fetch_byte (pstr);
+
+ off = pstr->offsets[pstr->cur_idx];
+ ch = pstr->raw_mbs[pstr->raw_mbs_idx + off];
+
+ if (! isascii (ch))
+ return re_string_fetch_byte (pstr);
+
+ re_string_skip_bytes (pstr,
+ re_string_char_size_at (pstr, pstr->cur_idx));
+ return ch;
+ }
+#endif
+
+ return pstr->raw_mbs[pstr->raw_mbs_idx + pstr->cur_idx++];
+}
+
+static void
+internal_function
+re_string_destruct (re_string_t *pstr)
+{
+#ifdef RE_ENABLE_I18N
+ re_free (pstr->wcs);
+ re_free (pstr->offsets);
+#endif /* RE_ENABLE_I18N */
+ if (pstr->mbs_allocated)
+ re_free (pstr->mbs);
+}
+
+/* Return the context at IDX in INPUT. */
+
+static unsigned int
+internal_function
+re_string_context_at (const re_string_t *input, int idx, int eflags)
+{
+ int c;
+ if (BE (idx < 0, 0))
+ /* In this case, we use the value stored in input->tip_context,
+ since we can't know the character in input->mbs[-1] here. */
+ return input->tip_context;
+ if (BE (idx == input->len, 0))
+ return ((eflags & REG_NOTEOL) ? CONTEXT_ENDBUF
+ : CONTEXT_NEWLINE | CONTEXT_ENDBUF);
+#ifdef RE_ENABLE_I18N
+ if (input->mb_cur_max > 1)
+ {
+ wint_t wc;
+ int wc_idx = idx;
+ while(input->wcs[wc_idx] == WEOF)
+ {
+#ifdef DEBUG
+ /* It must not happen. */
+ assert (wc_idx >= 0);
+#endif
+ --wc_idx;
+ if (wc_idx < 0)
+ return input->tip_context;
+ }
+ wc = input->wcs[wc_idx];
+ if (BE (input->word_ops_used != 0, 0) && IS_WIDE_WORD_CHAR (wc))
+ return CONTEXT_WORD;
+ return (IS_WIDE_NEWLINE (wc) && input->newline_anchor
+ ? CONTEXT_NEWLINE : 0);
+ }
+#endif
+ c = re_string_byte_at (input, idx);
+ if (bitset_contain (input->word_char, c))
+ return CONTEXT_WORD;
+ return IS_NEWLINE (c) && input->newline_anchor ? CONTEXT_NEWLINE : 0;
+}
+
+/* Functions for set operation. */
+
+static reg_errcode_t
+internal_function
+re_node_set_alloc (re_node_set *set, int size)
+{
+ set->alloc = size;
+ set->nelem = 0;
+ set->elems = re_malloc (int, size); /* can be NULL if size == 0
+ (see re_node_set_init_empty(set)) */
+ if (BE (set->elems == NULL && size != 0, 0))
+ return REG_ESPACE;
+ return REG_NOERROR;
+}
+
+static reg_errcode_t
+internal_function
+re_node_set_init_1 (re_node_set *set, int elem)
+{
+ set->alloc = 1;
+ set->nelem = 1;
+ set->elems = re_malloc (int, 1);
+ if (BE (set->elems == NULL, 0))
+ {
+ set->alloc = set->nelem = 0;
+ return REG_ESPACE;
+ }
+ set->elems[0] = elem;
+ return REG_NOERROR;
+}
+
+static reg_errcode_t
+internal_function
+re_node_set_init_2 (re_node_set *set, int elem1, int elem2)
+{
+ set->alloc = 2;
+ set->elems = re_malloc (int, 2);
+ if (BE (set->elems == NULL, 0))
+ return REG_ESPACE;
+ if (elem1 == elem2)
+ {
+ set->nelem = 1;
+ set->elems[0] = elem1;
+ }
+ else
+ {
+ set->nelem = 2;
+ if (elem1 < elem2)
+ {
+ set->elems[0] = elem1;
+ set->elems[1] = elem2;
+ }
+ else
+ {
+ set->elems[0] = elem2;
+ set->elems[1] = elem1;
+ }
+ }
+ return REG_NOERROR;
+}
+
+static reg_errcode_t
+internal_function
+re_node_set_init_copy (re_node_set *dest, const re_node_set *src)
+{
+ dest->nelem = src->nelem;
+ if (src->nelem > 0)
+ {
+ dest->alloc = dest->nelem;
+ dest->elems = re_malloc (int, dest->alloc);
+ if (BE (dest->elems == NULL, 0))
+ {
+ dest->alloc = dest->nelem = 0;
+ return REG_ESPACE;
+ }
+ memcpy (dest->elems, src->elems, src->nelem * sizeof (int));
+ }
+ else
+ re_node_set_init_empty (dest);
+ return REG_NOERROR;
+}
+
+/* Calculate the intersection of the sets SRC1 and SRC2. And merge it to
+ DEST. Return value indicate the error code or REG_NOERROR if succeeded.
+ Note: We assume dest->elems is NULL, when dest->alloc is 0. */
+
+static reg_errcode_t
+internal_function
+re_node_set_add_intersect (re_node_set *dest, const re_node_set *src1,
+ const re_node_set *src2)
+{
+ int i1, i2, is, id, delta, sbase;
+ if (src1->nelem == 0 || src2->nelem == 0)
+ return REG_NOERROR;
+
+ /* We need dest->nelem + 2 * elems_in_intersection; this is a
+ conservative estimate. */
+ if (src1->nelem + src2->nelem + dest->nelem > dest->alloc)
+ {
+ int new_alloc = src1->nelem + src2->nelem + dest->alloc;
+ int *new_elems = re_realloc (dest->elems, int, new_alloc);
+ if (BE (new_elems == NULL, 0))
+ return REG_ESPACE;
+ dest->elems = new_elems;
+ dest->alloc = new_alloc;
+ }
+
+ /* Find the items in the intersection of SRC1 and SRC2, and copy
+ into the top of DEST those that are not already in DEST itself. */
+ sbase = dest->nelem + src1->nelem + src2->nelem;
+ i1 = src1->nelem - 1;
+ i2 = src2->nelem - 1;
+ id = dest->nelem - 1;
+ for (;;)
+ {
+ if (src1->elems[i1] == src2->elems[i2])
+ {
+ /* Try to find the item in DEST. Maybe we could binary search? */
+ while (id >= 0 && dest->elems[id] > src1->elems[i1])
+ --id;
+
+ if (id < 0 || dest->elems[id] != src1->elems[i1])
+ dest->elems[--sbase] = src1->elems[i1];
+
+ if (--i1 < 0 || --i2 < 0)
+ break;
+ }
+
+ /* Lower the highest of the two items. */
+ else if (src1->elems[i1] < src2->elems[i2])
+ {
+ if (--i2 < 0)
+ break;
+ }
+ else
+ {
+ if (--i1 < 0)
+ break;
+ }
+ }
+
+ id = dest->nelem - 1;
+ is = dest->nelem + src1->nelem + src2->nelem - 1;
+ delta = is - sbase + 1;
+
+ /* Now copy. When DELTA becomes zero, the remaining
+ DEST elements are already in place; this is more or
+ less the same loop that is in re_node_set_merge. */
+ dest->nelem += delta;
+ if (delta > 0 && id >= 0)
+ for (;;)
+ {
+ if (dest->elems[is] > dest->elems[id])
+ {
+ /* Copy from the top. */
+ dest->elems[id + delta--] = dest->elems[is--];
+ if (delta == 0)
+ break;
+ }
+ else
+ {
+ /* Slide from the bottom. */
+ dest->elems[id + delta] = dest->elems[id];
+ if (--id < 0)
+ break;
+ }
+ }
+
+ /* Copy remaining SRC elements. */
+ memcpy (dest->elems, dest->elems + sbase, delta * sizeof (int));
+
+ return REG_NOERROR;
+}
+
+/* Calculate the union set of the sets SRC1 and SRC2. And store it to
+ DEST. Return value indicate the error code or REG_NOERROR if succeeded. */
+
+static reg_errcode_t
+internal_function
+re_node_set_init_union (re_node_set *dest, const re_node_set *src1,
+ const re_node_set *src2)
+{
+ int i1, i2, id;
+ if (src1 != NULL && src1->nelem > 0 && src2 != NULL && src2->nelem > 0)
+ {
+ dest->alloc = src1->nelem + src2->nelem;
+ dest->elems = re_malloc (int, dest->alloc);
+ if (BE (dest->elems == NULL, 0))
+ return REG_ESPACE;
+ }
+ else
+ {
+ if (src1 != NULL && src1->nelem > 0)
+ return re_node_set_init_copy (dest, src1);
+ if (src2 != NULL && src2->nelem > 0)
+ return re_node_set_init_copy (dest, src2);
+ re_node_set_init_empty (dest);
+ return REG_NOERROR;
+ }
+ for (i1 = i2 = id = 0 ; i1 < src1->nelem && i2 < src2->nelem ;)
+ {
+ if (src1->elems[i1] > src2->elems[i2])
+ {
+ dest->elems[id++] = src2->elems[i2++];
+ continue;
+ }
+ if (src1->elems[i1] == src2->elems[i2])
+ ++i2;
+ dest->elems[id++] = src1->elems[i1++];
+ }
+ if (i1 < src1->nelem)
+ {
+ memcpy (dest->elems + id, src1->elems + i1,
+ (src1->nelem - i1) * sizeof (int));
+ id += src1->nelem - i1;
+ }
+ else if (i2 < src2->nelem)
+ {
+ memcpy (dest->elems + id, src2->elems + i2,
+ (src2->nelem - i2) * sizeof (int));
+ id += src2->nelem - i2;
+ }
+ dest->nelem = id;
+ return REG_NOERROR;
+}
+
+/* Calculate the union set of the sets DEST and SRC. And store it to
+ DEST. Return value indicate the error code or REG_NOERROR if succeeded. */
+
+static reg_errcode_t
+internal_function
+re_node_set_merge (re_node_set *dest, const re_node_set *src)
+{
+ int is, id, sbase, delta;
+ if (src == NULL || src->nelem == 0)
+ return REG_NOERROR;
+ if (dest->alloc < 2 * src->nelem + dest->nelem)
+ {
+ int new_alloc = 2 * (src->nelem + dest->alloc);
+ int *new_buffer = re_realloc (dest->elems, int, new_alloc);
+ if (BE (new_buffer == NULL, 0))
+ return REG_ESPACE;
+ dest->elems = new_buffer;
+ dest->alloc = new_alloc;
+ }
+
+ if (BE (dest->nelem == 0, 0))
+ {
+ dest->nelem = src->nelem;
+ memcpy (dest->elems, src->elems, src->nelem * sizeof (int));
+ return REG_NOERROR;
+ }
+
+ /* Copy into the top of DEST the items of SRC that are not
+ found in DEST. Maybe we could binary search in DEST? */
+ for (sbase = dest->nelem + 2 * src->nelem,
+ is = src->nelem - 1, id = dest->nelem - 1; is >= 0 && id >= 0; )
+ {
+ if (dest->elems[id] == src->elems[is])
+ is--, id--;
+ else if (dest->elems[id] < src->elems[is])
+ dest->elems[--sbase] = src->elems[is--];
+ else /* if (dest->elems[id] > src->elems[is]) */
+ --id;
+ }
+
+ if (is >= 0)
+ {
+ /* If DEST is exhausted, the remaining items of SRC must be unique. */
+ sbase -= is + 1;
+ memcpy (dest->elems + sbase, src->elems, (is + 1) * sizeof (int));
+ }
+
+ id = dest->nelem - 1;
+ is = dest->nelem + 2 * src->nelem - 1;
+ delta = is - sbase + 1;
+ if (delta == 0)
+ return REG_NOERROR;
+
+ /* Now copy. When DELTA becomes zero, the remaining
+ DEST elements are already in place. */
+ dest->nelem += delta;
+ for (;;)
+ {
+ if (dest->elems[is] > dest->elems[id])
+ {
+ /* Copy from the top. */
+ dest->elems[id + delta--] = dest->elems[is--];
+ if (delta == 0)
+ break;
+ }
+ else
+ {
+ /* Slide from the bottom. */
+ dest->elems[id + delta] = dest->elems[id];
+ if (--id < 0)
+ {
+ /* Copy remaining SRC elements. */
+ memcpy (dest->elems, dest->elems + sbase,
+ delta * sizeof (int));
+ break;
+ }
+ }
+ }
+
+ return REG_NOERROR;
+}
+
+/* Insert the new element ELEM to the re_node_set* SET.
+ SET should not already have ELEM.
+ return -1 if an error is occured, return 1 otherwise. */
+
+static int
+internal_function
+re_node_set_insert (re_node_set *set, int elem)
+{
+ int idx;
+ /* In case the set is empty. */
+ if (set->alloc == 0)
+ {
+ if (BE (re_node_set_init_1 (set, elem) == REG_NOERROR, 1))
+ return 1;
+ return -1;
+ }
+
+ if (BE (set->nelem, 0) == 0)
+ {
+ /* We already guaranteed above that set->alloc != 0. */
+ set->elems[0] = elem;
+ ++set->nelem;
+ return 1;
+ }
+
+ /* Realloc if we need. */
+ if (set->alloc == set->nelem)
+ {
+ int *new_elems;
+ set->alloc = set->alloc * 2;
+ new_elems = re_realloc (set->elems, int, set->alloc);
+ if (BE (new_elems == NULL, 0))
+ return -1;
+ set->elems = new_elems;
+ }
+
+ /* Move the elements which follows the new element. Test the
+ first element separately to skip a check in the inner loop. */
+ if (elem < set->elems[0])
+ {
+ idx = 0;
+ for (idx = set->nelem; idx > 0; idx--)
+ set->elems[idx] = set->elems[idx - 1];
+ }
+ else
+ {
+ for (idx = set->nelem; set->elems[idx - 1] > elem; idx--)
+ set->elems[idx] = set->elems[idx - 1];
+ }
+
+ /* Insert the new element. */
+ set->elems[idx] = elem;
+ ++set->nelem;
+ return 1;
+}
+
+/* Insert the new element ELEM to the re_node_set* SET.
+ SET should not already have any element greater than or equal to ELEM.
+ Return -1 if an error is occured, return 1 otherwise. */
+
+static int
+internal_function
+re_node_set_insert_last (re_node_set *set, int elem)
+{
+ /* Realloc if we need. */
+ if (set->alloc == set->nelem)
+ {
+ int *new_elems;
+ set->alloc = (set->alloc + 1) * 2;
+ new_elems = re_realloc (set->elems, int, set->alloc);
+ if (BE (new_elems == NULL, 0))
+ return -1;
+ set->elems = new_elems;
+ }
+
+ /* Insert the new element. */
+ set->elems[set->nelem++] = elem;
+ return 1;
+}
+
+/* Compare two node sets SET1 and SET2.
+ return 1 if SET1 and SET2 are equivalent, return 0 otherwise. */
+
+static int
+internal_function __attribute ((pure))
+re_node_set_compare (const re_node_set *set1, const re_node_set *set2)
+{
+ int i;
+ if (set1 == NULL || set2 == NULL || set1->nelem != set2->nelem)
+ return 0;
+ for (i = set1->nelem ; --i >= 0 ; )
+ if (set1->elems[i] != set2->elems[i])
+ return 0;
+ return 1;
+}
+
+/* Return (idx + 1) if SET contains the element ELEM, return 0 otherwise. */
+
+static int
+internal_function __attribute ((pure))
+re_node_set_contains (const re_node_set *set, int elem)
+{
+ unsigned int idx, right, mid;
+ if (set->nelem <= 0)
+ return 0;
+
+ /* Binary search the element. */
+ idx = 0;
+ right = set->nelem - 1;
+ while (idx < right)
+ {
+ mid = (idx + right) / 2;
+ if (set->elems[mid] < elem)
+ idx = mid + 1;
+ else
+ right = mid;
+ }
+ return set->elems[idx] == elem ? idx + 1 : 0;
+}
+
+static void
+internal_function
+re_node_set_remove_at (re_node_set *set, int idx)
+{
+ if (idx < 0 || idx >= set->nelem)
+ return;
+ --set->nelem;
+ for (; idx < set->nelem; idx++)
+ set->elems[idx] = set->elems[idx + 1];
+}
+
+
+/* Add the token TOKEN to dfa->nodes, and return the index of the token.
+ Or return -1, if an error will be occured. */
+
+static int
+internal_function
+re_dfa_add_node (re_dfa_t *dfa, re_token_t token)
+{
+#ifdef RE_ENABLE_I18N
+ int type = token.type;
+#endif
+ if (BE (dfa->nodes_len >= dfa->nodes_alloc, 0))
+ {
+ size_t new_nodes_alloc = dfa->nodes_alloc * 2;
+ int *new_nexts, *new_indices;
+ re_node_set *new_edests, *new_eclosures;
+ re_token_t *new_nodes;
+
+ /* Avoid overflows. */
+ if (BE (new_nodes_alloc < dfa->nodes_alloc, 0))
+ return -1;
+
+ new_nodes = re_realloc (dfa->nodes, re_token_t, new_nodes_alloc);
+ if (BE (new_nodes == NULL, 0))
+ return -1;
+ dfa->nodes = new_nodes;
+ new_nexts = re_realloc (dfa->nexts, int, new_nodes_alloc);
+ new_indices = re_realloc (dfa->org_indices, int, new_nodes_alloc);
+ new_edests = re_realloc (dfa->edests, re_node_set, new_nodes_alloc);
+ new_eclosures = re_realloc (dfa->eclosures, re_node_set, new_nodes_alloc);
+ if (BE (new_nexts == NULL || new_indices == NULL
+ || new_edests == NULL || new_eclosures == NULL, 0))
+ return -1;
+ dfa->nexts = new_nexts;
+ dfa->org_indices = new_indices;
+ dfa->edests = new_edests;
+ dfa->eclosures = new_eclosures;
+ dfa->nodes_alloc = new_nodes_alloc;
+ }
+ dfa->nodes[dfa->nodes_len] = 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;
+#endif
+ dfa->nexts[dfa->nodes_len] = -1;
+ re_node_set_init_empty (dfa->edests + dfa->nodes_len);
+ re_node_set_init_empty (dfa->eclosures + dfa->nodes_len);
+ return dfa->nodes_len++;
+}
+
+static __inline__ unsigned int
+internal_function
+calc_state_hash (const re_node_set *nodes, unsigned int context)
+{
+ unsigned int hash = nodes->nelem + context;
+ int i;
+ for (i = 0 ; i < nodes->nelem ; i++)
+ hash += nodes->elems[i];
+ return hash;
+}
+
+/* Search for the state whose node_set is equivalent to NODES.
+ Return the pointer to the state, if we found it in the DFA.
+ Otherwise create the new one and return it. In case of an error
+ return NULL and set the error code in ERR.
+ Note: - We assume NULL as the invalid state, then it is possible that
+ return value is NULL and ERR is REG_NOERROR.
+ - We never return non-NULL value in case of any errors, it is for
+ optimization. */
+
+static re_dfastate_t *
+internal_function
+re_acquire_state (reg_errcode_t *err, const re_dfa_t *dfa,
+ const re_node_set *nodes)
+{
+ unsigned int hash;
+ re_dfastate_t *new_state;
+ struct re_state_table_entry *spot;
+ int i;
+ if (BE (nodes->nelem == 0, 0))
+ {
+ *err = REG_NOERROR;
+ return NULL;
+ }
+ hash = calc_state_hash (nodes, 0);
+ spot = dfa->state_table + (hash & dfa->state_hash_mask);
+
+ for (i = 0 ; i < spot->num ; i++)
+ {
+ re_dfastate_t *state = spot->array[i];
+ if (hash != state->hash)
+ continue;
+ if (re_node_set_compare (&state->nodes, nodes))
+ return state;
+ }
+
+ /* There are no appropriate state in the dfa, create the new one. */
+ new_state = create_ci_newstate (dfa, nodes, hash);
+ if (BE (new_state == NULL, 0))
+ *err = REG_ESPACE;
+
+ return new_state;
+}
+
+/* Search for the state whose node_set is equivalent to NODES and
+ whose context is equivalent to CONTEXT.
+ Return the pointer to the state, if we found it in the DFA.
+ Otherwise create the new one and return it. In case of an error
+ return NULL and set the error code in ERR.
+ Note: - We assume NULL as the invalid state, then it is possible that
+ return value is NULL and ERR is REG_NOERROR.
+ - We never return non-NULL value in case of any errors, it is for
+ optimization. */
+
+static re_dfastate_t *
+internal_function
+re_acquire_state_context (reg_errcode_t *err, const re_dfa_t *dfa,
+ const re_node_set *nodes, unsigned int context)
+{
+ unsigned int hash;
+ re_dfastate_t *new_state;
+ struct re_state_table_entry *spot;
+ int i;
+ if (nodes->nelem == 0)
+ {
+ *err = REG_NOERROR;
+ return NULL;
+ }
+ hash = calc_state_hash (nodes, context);
+ spot = dfa->state_table + (hash & dfa->state_hash_mask);
+
+ for (i = 0 ; i < spot->num ; i++)
+ {
+ re_dfastate_t *state = spot->array[i];
+ if (state->hash == hash
+ && state->context == context
+ && re_node_set_compare (state->entrance_nodes, nodes))
+ return state;
+ }
+ /* There are no appropriate state in `dfa', create the new one. */
+ new_state = create_cd_newstate (dfa, nodes, context, hash);
+ if (BE (new_state == NULL, 0))
+ *err = REG_ESPACE;
+
+ return new_state;
+}
+
+/* Finish initialization of the new state NEWSTATE, and using its hash value
+ HASH put in the appropriate bucket of DFA's state table. Return value
+ indicates the error code if failed. */
+
+static reg_errcode_t
+register_state (const re_dfa_t *dfa, re_dfastate_t *newstate,
+ unsigned int hash)
+{
+ struct re_state_table_entry *spot;
+ reg_errcode_t err;
+ int i;
+
+ newstate->hash = hash;
+ err = re_node_set_alloc (&newstate->non_eps_nodes, newstate->nodes.nelem);
+ if (BE (err != REG_NOERROR, 0))
+ return REG_ESPACE;
+ for (i = 0; i < newstate->nodes.nelem; i++)
+ {
+ int elem = newstate->nodes.elems[i];
+ if (!IS_EPSILON_NODE (dfa->nodes[elem].type))
+ re_node_set_insert_last (&newstate->non_eps_nodes, elem);
+ }
+
+ spot = dfa->state_table + (hash & dfa->state_hash_mask);
+ if (BE (spot->alloc <= spot->num, 0))
+ {
+ int new_alloc = 2 * spot->num + 2;
+ re_dfastate_t **new_array = re_realloc (spot->array, re_dfastate_t *,
+ new_alloc);
+ if (BE (new_array == NULL, 0))
+ return REG_ESPACE;
+ spot->array = new_array;
+ spot->alloc = new_alloc;
+ }
+ spot->array[spot->num++] = newstate;
+ return REG_NOERROR;
+}
+
+static void
+free_state (re_dfastate_t *state)
+{
+ re_node_set_free (&state->non_eps_nodes);
+ re_node_set_free (&state->inveclosure);
+ if (state->entrance_nodes != &state->nodes)
+ {
+ re_node_set_free (state->entrance_nodes);
+ re_free (state->entrance_nodes);
+ }
+ re_node_set_free (&state->nodes);
+ re_free (state->word_trtable);
+ re_free (state->trtable);
+ re_free (state);
+}
+
+/* Create the new state which is independ of contexts.
+ Return the new state if succeeded, otherwise return NULL. */
+
+static re_dfastate_t *
+internal_function
+create_ci_newstate (const re_dfa_t *dfa, const re_node_set *nodes,
+ unsigned int hash)
+{
+ int i;
+ reg_errcode_t err;
+ re_dfastate_t *newstate;
+
+ newstate = calloc (sizeof (re_dfastate_t), 1);
+ if (BE (newstate == NULL, 0))
+ return NULL;
+ err = re_node_set_init_copy (&newstate->nodes, nodes);
+ if (BE (err != REG_NOERROR, 0))
+ {
+ re_free (newstate);
+ return NULL;
+ }
+
+ newstate->entrance_nodes = &newstate->nodes;
+ for (i = 0 ; i < nodes->nelem ; i++)
+ {
+ re_token_t *node = dfa->nodes + nodes->elems[i];
+ re_token_type_t type = node->type;
+
+ if (type == CHARACTER && !node->constraint)
+ continue;
+#ifdef RE_ENABLE_I18N
+ newstate->accept_mb |= node->accept_mb;
+#endif
+
+ /* If the state has the halt node, the state is a halt state. */
+ if (type == END_OF_RE)
+ newstate->halt = 1;
+ else if (type == OP_BACK_REF)
+ newstate->has_backref = 1;
+ else if (type == ANCHOR || node->constraint)
+ newstate->has_constraint = 1;
+ }
+ err = register_state (dfa, newstate, hash);
+ if (BE (err != REG_NOERROR, 0))
+ {
+ free_state (newstate);
+ newstate = NULL;
+ }
+ return newstate;
+}
+
+/* Create the new state which is depend on the context CONTEXT.
+ Return the new state if succeeded, otherwise return NULL. */
+
+static re_dfastate_t *
+internal_function
+create_cd_newstate (const re_dfa_t *dfa, const re_node_set *nodes,
+ unsigned int context, unsigned int hash)
+{
+ int i, nctx_nodes = 0;
+ reg_errcode_t err;
+ re_dfastate_t *newstate;
+
+ newstate = calloc (sizeof (re_dfastate_t), 1);
+ if (BE (newstate == NULL, 0))
+ return NULL;
+ err = re_node_set_init_copy (&newstate->nodes, nodes);
+ if (BE (err != REG_NOERROR, 0))
+ {
+ re_free (newstate);
+ return NULL;
+ }
+
+ newstate->context = context;
+ newstate->entrance_nodes = &newstate->nodes;
+
+ for (i = 0 ; i < nodes->nelem ; i++)
+ {
+ unsigned int constraint = 0;
+ re_token_t *node = dfa->nodes + nodes->elems[i];
+ re_token_type_t type = node->type;
+ if (node->constraint)
+ constraint = node->constraint;
+
+ if (type == CHARACTER && !constraint)
+ continue;
+#ifdef RE_ENABLE_I18N
+ newstate->accept_mb |= node->accept_mb;
+#endif /* RE_ENABLE_I18N */
+
+ /* If the state has the halt node, the state is a halt state. */
+ if (type == END_OF_RE)
+ newstate->halt = 1;
+ else if (type == OP_BACK_REF)
+ newstate->has_backref = 1;
+ else if (type == ANCHOR)
+ constraint = node->opr.ctx_type;
+
+ if (constraint)
+ {
+ if (newstate->entrance_nodes == &newstate->nodes)
+ {
+ newstate->entrance_nodes = re_malloc (re_node_set, 1);
+ if (BE (newstate->entrance_nodes == NULL, 0))
+ {
+ free_state (newstate);
+ return NULL;
+ }
+ re_node_set_init_copy (newstate->entrance_nodes, nodes);
+ nctx_nodes = 0;
+ newstate->has_constraint = 1;
+ }
+
+ if (NOT_SATISFY_PREV_CONSTRAINT (constraint,context))
+ {
+ re_node_set_remove_at (&newstate->nodes, i - nctx_nodes);
+ ++nctx_nodes;
+ }
+ }
+ }
+ err = register_state (dfa, newstate, hash);
+ if (BE (err != REG_NOERROR, 0))
+ {
+ free_state (newstate);
+ newstate = NULL;
+ }
+ return newstate;
+}
diff --git a/ap/build/uClibc/libc/misc/regex/regex_internal.h b/ap/build/uClibc/libc/misc/regex/regex_internal.h
new file mode 100644
index 0000000..0a255e3
--- /dev/null
+++ b/ap/build/uClibc/libc/misc/regex/regex_internal.h
@@ -0,0 +1,708 @@
+/* Extended regular expression matching and search library.
+ Copyright (C) 2002, 2003, 2004, 2005 Free Software Foundation, Inc.
+ This file is part of the GNU C Library.
+ Contributed by Isamu Hasegawa <isamu@yamato.ibm.com>.
+
+ The GNU C Library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 2.1 of the License, or (at your option) any later version.
+
+ The GNU C Library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with the GNU C Library; if not, write to the Free
+ Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+ 02111-1307 USA. */
+
+#ifndef _REGEX_INTERNAL_H
+#define _REGEX_INTERNAL_H 1
+
+#include <assert.h>
+#include <ctype.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#if defined HAVE_LANGINFO_H || defined HAVE_LANGINFO_CODESET
+# include <langinfo.h>
+#endif
+#if defined HAVE_LOCALE_H
+# include <locale.h>
+#endif
+#if defined HAVE_WCHAR_H
+# include <wchar.h>
+#endif
+#if defined HAVE_WCTYPE_H
+# include <wctype.h>
+#endif
+#if defined HAVE_STDBOOL_H
+# include <stdbool.h>
+#endif
+#if defined HAVE_STDINT_H
+# include <stdint.h>
+#endif
+
+#ifdef __UCLIBC_HAS_THREADS__
+#include <bits/libc-lock.h>
+#else
+#define __libc_lock_define(CLASS, NAME)
+#define __libc_lock_init(NAME) do { } while (0)
+#define __libc_lock_lock(NAME) do { } while (0)
+#define __libc_lock_unlock(NAME) do { } while (0)
+#endif
+
+#undef gettext
+#undef gettext_noop
+#define gettext(msgid) (msgid)
+#define gettext_noop(String) String
+
+#if (defined MB_CUR_MAX && HAVE_LOCALE_H && HAVE_WCTYPE_H && HAVE_WCHAR_H && HAVE_WCRTOMB && HAVE_MBRTOWC && HAVE_WCSCOLL)
+# define RE_ENABLE_I18N
+#endif
+
+#if __GNUC__ >= 3
+/* uclibc: lean towards smaller size a bit:
+ * OFF: # define BE(expr, val) __builtin_expect (expr, val) */
+# define BE(expr, val) (expr)
+#else
+# define BE(expr, val) (expr)
+# define inline
+#endif
+
+/* Number of single byte character. */
+#define SBC_MAX 256
+
+#define COLL_ELEM_LEN_MAX 8
+
+/* The character which represents newline. */
+#define NEWLINE_CHAR '\n'
+#define WIDE_NEWLINE_CHAR L'\n'
+
+#ifdef __GNUC__
+# define __attribute(arg) __attribute__ (arg)
+#else
+# define __attribute(arg)
+#endif
+
+/* An integer used to represent a set of bits. It must be unsigned,
+ and must be at least as wide as unsigned int. */
+typedef unsigned long int bitset_word_t;
+/* All bits set in a bitset_word_t. */
+#define BITSET_WORD_MAX ULONG_MAX
+/* Number of bits in a bitset_word_t. */
+#define BITSET_WORD_BITS (sizeof (bitset_word_t) * CHAR_BIT)
+/* Number of bitset_word_t in a bit_set. */
+#define BITSET_WORDS (SBC_MAX / BITSET_WORD_BITS)
+typedef bitset_word_t bitset_t[BITSET_WORDS];
+typedef bitset_word_t *re_bitset_ptr_t;
+typedef const bitset_word_t *re_const_bitset_ptr_t;
+
+#define bitset_set(set,i) \
+ (set[i / BITSET_WORD_BITS] |= (bitset_word_t) 1 << i % BITSET_WORD_BITS)
+#define bitset_clear(set,i) \
+ (set[i / BITSET_WORD_BITS] &= ~((bitset_word_t) 1 << i % BITSET_WORD_BITS))
+#define bitset_contain(set,i) \
+ (set[i / BITSET_WORD_BITS] & ((bitset_word_t) 1 << i % BITSET_WORD_BITS))
+#define bitset_empty(set) memset (set, '\0', sizeof (bitset_t))
+#define bitset_set_all(set) memset (set, '\xff', sizeof (bitset_t))
+#define bitset_copy(dest,src) memcpy (dest, src, sizeof (bitset_t))
+
+#define PREV_WORD_CONSTRAINT 0x0001
+#define PREV_NOTWORD_CONSTRAINT 0x0002
+#define NEXT_WORD_CONSTRAINT 0x0004
+#define NEXT_NOTWORD_CONSTRAINT 0x0008
+#define PREV_NEWLINE_CONSTRAINT 0x0010
+#define NEXT_NEWLINE_CONSTRAINT 0x0020
+#define PREV_BEGBUF_CONSTRAINT 0x0040
+#define NEXT_ENDBUF_CONSTRAINT 0x0080
+#define WORD_DELIM_CONSTRAINT 0x0100
+#define NOT_WORD_DELIM_CONSTRAINT 0x0200
+
+typedef enum
+{
+ INSIDE_WORD = PREV_WORD_CONSTRAINT | NEXT_WORD_CONSTRAINT,
+ WORD_FIRST = PREV_NOTWORD_CONSTRAINT | NEXT_WORD_CONSTRAINT,
+ WORD_LAST = PREV_WORD_CONSTRAINT | NEXT_NOTWORD_CONSTRAINT,
+ INSIDE_NOTWORD = PREV_NOTWORD_CONSTRAINT | NEXT_NOTWORD_CONSTRAINT,
+ LINE_FIRST = PREV_NEWLINE_CONSTRAINT,
+ LINE_LAST = NEXT_NEWLINE_CONSTRAINT,
+ BUF_FIRST = PREV_BEGBUF_CONSTRAINT,
+ BUF_LAST = NEXT_ENDBUF_CONSTRAINT,
+ WORD_DELIM = WORD_DELIM_CONSTRAINT,
+ NOT_WORD_DELIM = NOT_WORD_DELIM_CONSTRAINT
+} re_context_type;
+
+typedef struct
+{
+ int alloc;
+ int nelem;
+ int *elems;
+} re_node_set;
+
+typedef enum
+{
+ NON_TYPE = 0,
+
+ /* Node type, These are used by token, node, tree. */
+ CHARACTER = 1,
+ END_OF_RE = 2,
+ SIMPLE_BRACKET = 3,
+ OP_BACK_REF = 4,
+ OP_PERIOD = 5,
+#ifdef RE_ENABLE_I18N
+ COMPLEX_BRACKET = 6,
+ OP_UTF8_PERIOD = 7,
+#endif /* RE_ENABLE_I18N */
+
+ /* We define EPSILON_BIT as a macro so that OP_OPEN_SUBEXP is used
+ when the debugger shows values of this enum type. */
+#define EPSILON_BIT 8
+ OP_OPEN_SUBEXP = EPSILON_BIT | 0,
+ OP_CLOSE_SUBEXP = EPSILON_BIT | 1,
+ OP_ALT = EPSILON_BIT | 2,
+ OP_DUP_ASTERISK = EPSILON_BIT | 3,
+ ANCHOR = EPSILON_BIT | 4,
+
+ /* Tree type, these are used only by tree. */
+ CONCAT = 16,
+ SUBEXP = 17,
+
+ /* Token type, these are used only by token. */
+ OP_DUP_PLUS = 18,
+ OP_DUP_QUESTION,
+ OP_OPEN_BRACKET,
+ OP_CLOSE_BRACKET,
+ OP_CHARSET_RANGE,
+ OP_OPEN_DUP_NUM,
+ OP_CLOSE_DUP_NUM,
+ OP_NON_MATCH_LIST,
+ OP_OPEN_COLL_ELEM,
+ OP_CLOSE_COLL_ELEM,
+ OP_OPEN_EQUIV_CLASS,
+ OP_CLOSE_EQUIV_CLASS,
+ OP_OPEN_CHAR_CLASS,
+ OP_CLOSE_CHAR_CLASS,
+ OP_WORD,
+ OP_NOTWORD,
+ OP_SPACE,
+ OP_NOTSPACE,
+ BACK_SLASH
+
+} re_token_type_t;
+
+#ifdef RE_ENABLE_I18N
+typedef struct
+{
+ /* Multibyte characters. */
+ wchar_t *mbchars;
+
+ /* Collating symbols. */
+# if 0
+ int32_t *coll_syms;
+# endif
+
+ /* Equivalence classes. */
+# if 0
+ int32_t *equiv_classes;
+# endif
+
+ /* Range expressions. */
+# if 0
+ uint32_t *range_starts;
+ uint32_t *range_ends;
+# else
+ wchar_t *range_starts;
+ wchar_t *range_ends;
+# endif
+
+ /* Character classes. */
+ wctype_t *char_classes;
+
+ /* If this character set is the non-matching list. */
+ unsigned int non_match : 1;
+
+ /* # of multibyte characters. */
+ int nmbchars;
+
+ /* # of collating symbols. */
+ int ncoll_syms;
+
+ /* # of equivalence classes. */
+ int nequiv_classes;
+
+ /* # of range expressions. */
+ int nranges;
+
+ /* # of character classes. */
+ int nchar_classes;
+} re_charset_t;
+#endif /* RE_ENABLE_I18N */
+
+typedef struct
+{
+ union
+ {
+ unsigned char c; /* for CHARACTER */
+ re_bitset_ptr_t sbcset; /* for SIMPLE_BRACKET */
+#ifdef RE_ENABLE_I18N
+ re_charset_t *mbcset; /* for COMPLEX_BRACKET */
+#endif /* RE_ENABLE_I18N */
+ int idx; /* for BACK_REF */
+ re_context_type ctx_type; /* for ANCHOR */
+ } opr;
+#if __GNUC__ >= 2
+ re_token_type_t type : 8;
+#else
+ re_token_type_t type;
+#endif
+ unsigned int constraint : 10; /* context constraint */
+ unsigned int duplicated : 1;
+ unsigned int opt_subexp : 1;
+#ifdef RE_ENABLE_I18N
+ unsigned int accept_mb : 1;
+ /* These 2 bits can be moved into the union if needed (e.g. if running out
+ of bits; move opr.c to opr.c.c and move the flags to opr.c.flags). */
+ unsigned int mb_partial : 1;
+#endif
+ unsigned int word_char : 1;
+} re_token_t;
+
+#define IS_EPSILON_NODE(type) ((type) & EPSILON_BIT)
+
+struct re_string_t
+{
+ /* Indicate the raw buffer which is the original string passed as an
+ argument of regexec(), re_search(), etc.. */
+ const unsigned char *raw_mbs;
+ /* Store the multibyte string. In case of "case insensitive mode" like
+ REG_ICASE, upper cases of the string are stored, otherwise MBS points
+ the same address that RAW_MBS points. */
+ unsigned char *mbs;
+#ifdef RE_ENABLE_I18N
+ /* Store the wide character string which is corresponding to MBS. */
+ wint_t *wcs;
+ int *offsets;
+ mbstate_t cur_state;
+#endif
+ /* Index in RAW_MBS. Each character mbs[i] corresponds to
+ raw_mbs[raw_mbs_idx + i]. */
+ int raw_mbs_idx;
+ /* The length of the valid characters in the buffers. */
+ int valid_len;
+ /* The corresponding number of bytes in raw_mbs array. */
+ int valid_raw_len;
+ /* The length of the buffers MBS and WCS. */
+ int bufs_len;
+ /* The index in MBS, which is updated by re_string_fetch_byte. */
+ int cur_idx;
+ /* length of RAW_MBS array. */
+ int raw_len;
+ /* This is RAW_LEN - RAW_MBS_IDX + VALID_LEN - VALID_RAW_LEN. */
+ int len;
+ /* End of the buffer may be shorter than its length in the cases such
+ as re_match_2, re_search_2. Then, we use STOP for end of the buffer
+ instead of LEN. */
+ int raw_stop;
+ /* This is RAW_STOP - RAW_MBS_IDX adjusted through OFFSETS. */
+ int stop;
+
+ /* The context of mbs[0]. We store the context independently, since
+ the context of mbs[0] may be different from raw_mbs[0], which is
+ the beginning of the input string. */
+ unsigned int tip_context;
+ /* The translation passed as a part of an argument of re_compile_pattern. */
+ RE_TRANSLATE_TYPE trans;
+ /* Copy of re_dfa_t's word_char. */
+ re_const_bitset_ptr_t word_char;
+ /* 1 if REG_ICASE. */
+ unsigned char icase;
+ unsigned char is_utf8;
+ unsigned char map_notascii;
+ unsigned char mbs_allocated;
+ unsigned char offsets_needed;
+ unsigned char newline_anchor;
+ unsigned char word_ops_used;
+ int mb_cur_max;
+};
+typedef struct re_string_t re_string_t;
+
+struct re_dfa_t;
+typedef struct re_dfa_t re_dfa_t;
+
+static reg_errcode_t re_string_realloc_buffers (re_string_t *pstr,
+ int new_buf_len)
+ internal_function;
+#ifdef RE_ENABLE_I18N
+static void build_wcs_buffer (re_string_t *pstr) internal_function;
+static reg_errcode_t build_wcs_upper_buffer (re_string_t *pstr) internal_function;
+#endif /* RE_ENABLE_I18N */
+static void build_upper_buffer (re_string_t *pstr) internal_function;
+static void re_string_translate_buffer (re_string_t *pstr) internal_function;
+static unsigned int re_string_context_at (const re_string_t *input, int idx,
+ int eflags)
+ internal_function __attribute ((pure));
+#define re_string_peek_byte(pstr, offset) \
+ ((pstr)->mbs[(pstr)->cur_idx + offset])
+#define re_string_fetch_byte(pstr) \
+ ((pstr)->mbs[(pstr)->cur_idx++])
+#define re_string_first_byte(pstr, idx) \
+ ((idx) == (pstr)->valid_len || (pstr)->wcs[idx] != WEOF)
+#define re_string_is_single_byte_char(pstr, idx) \
+ ((pstr)->wcs[idx] != WEOF && ((pstr)->valid_len == (idx) + 1 \
+ || (pstr)->wcs[(idx) + 1] != WEOF))
+#define re_string_eoi(pstr) ((pstr)->stop <= (pstr)->cur_idx)
+#define re_string_cur_idx(pstr) ((pstr)->cur_idx)
+#define re_string_get_buffer(pstr) ((pstr)->mbs)
+#define re_string_length(pstr) ((pstr)->len)
+#define re_string_byte_at(pstr,idx) ((pstr)->mbs[idx])
+#define re_string_skip_bytes(pstr,idx) ((pstr)->cur_idx += (idx))
+#define re_string_set_index(pstr,idx) ((pstr)->cur_idx = (idx))
+
+#include <alloca.h>
+
+#if 1
+# ifdef HAVE_ALLOCA
+/* The OS usually guarantees only one guard page at the bottom of the stack,
+ and a page size can be as small as 4096 bytes. So we cannot safely
+ allocate anything larger than 4096 bytes. Also care for the possibility
+ of a few compiler-allocated temporary stack slots. */
+# define __libc_use_alloca(n) ((n) < 4032)
+# else
+/* alloca is implemented with malloc, so just use malloc. */
+# define __libc_use_alloca(n) 0
+# endif
+#endif
+
+#define re_malloc(t,n) ((t *) malloc ((n) * sizeof (t)))
+#define re_realloc(p,t,n) ((t *) realloc (p, (n) * sizeof (t)))
+#define re_free(p) free (p)
+
+struct bin_tree_t
+{
+ struct bin_tree_t *parent;
+ struct bin_tree_t *left;
+ struct bin_tree_t *right;
+ struct bin_tree_t *first;
+ struct bin_tree_t *next;
+
+ re_token_t token;
+
+ /* `node_idx' is the index in dfa->nodes, if `type' == 0.
+ Otherwise `type' indicate the type of this node. */
+ int node_idx;
+};
+typedef struct bin_tree_t bin_tree_t;
+
+#define BIN_TREE_STORAGE_SIZE \
+ ((1024 - sizeof (void *)) / sizeof (bin_tree_t))
+
+struct bin_tree_storage_t
+{
+ struct bin_tree_storage_t *next;
+ bin_tree_t data[BIN_TREE_STORAGE_SIZE];
+};
+typedef struct bin_tree_storage_t bin_tree_storage_t;
+
+#define CONTEXT_WORD 1
+#define CONTEXT_NEWLINE (CONTEXT_WORD << 1)
+#define CONTEXT_BEGBUF (CONTEXT_NEWLINE << 1)
+#define CONTEXT_ENDBUF (CONTEXT_BEGBUF << 1)
+
+#define IS_WORD_CONTEXT(c) ((c) & CONTEXT_WORD)
+#define IS_NEWLINE_CONTEXT(c) ((c) & CONTEXT_NEWLINE)
+#define IS_BEGBUF_CONTEXT(c) ((c) & CONTEXT_BEGBUF)
+#define IS_ENDBUF_CONTEXT(c) ((c) & CONTEXT_ENDBUF)
+#define IS_ORDINARY_CONTEXT(c) ((c) == 0)
+
+#define IS_WORD_CHAR(ch) (isalnum (ch) || (ch) == '_')
+#define IS_NEWLINE(ch) ((ch) == NEWLINE_CHAR)
+#define IS_WIDE_WORD_CHAR(ch) (iswalnum (ch) || (ch) == L'_')
+#define IS_WIDE_NEWLINE(ch) ((ch) == WIDE_NEWLINE_CHAR)
+
+#define NOT_SATISFY_PREV_CONSTRAINT(constraint,context) \
+ ((((constraint) & PREV_WORD_CONSTRAINT) && !IS_WORD_CONTEXT (context)) \
+ || ((constraint & PREV_NOTWORD_CONSTRAINT) && IS_WORD_CONTEXT (context)) \
+ || ((constraint & PREV_NEWLINE_CONSTRAINT) && !IS_NEWLINE_CONTEXT (context))\
+ || ((constraint & PREV_BEGBUF_CONSTRAINT) && !IS_BEGBUF_CONTEXT (context)))
+
+#define NOT_SATISFY_NEXT_CONSTRAINT(constraint,context) \
+ ((((constraint) & NEXT_WORD_CONSTRAINT) && !IS_WORD_CONTEXT (context)) \
+ || (((constraint) & NEXT_NOTWORD_CONSTRAINT) && IS_WORD_CONTEXT (context)) \
+ || (((constraint) & NEXT_NEWLINE_CONSTRAINT) && !IS_NEWLINE_CONTEXT (context)) \
+ || (((constraint) & NEXT_ENDBUF_CONSTRAINT) && !IS_ENDBUF_CONTEXT (context)))
+
+struct re_dfastate_t
+{
+ unsigned int hash;
+ re_node_set nodes;
+ re_node_set non_eps_nodes;
+ re_node_set inveclosure;
+ re_node_set *entrance_nodes;
+ struct re_dfastate_t **trtable, **word_trtable;
+ unsigned int context : 4;
+ unsigned int halt : 1;
+ /* If this state can accept `multi byte'.
+ Note that we refer to multibyte characters, and multi character
+ collating elements as `multi byte'. */
+ unsigned int accept_mb : 1;
+ /* If this state has backreference node(s). */
+ unsigned int has_backref : 1;
+ unsigned int has_constraint : 1;
+};
+typedef struct re_dfastate_t re_dfastate_t;
+
+struct re_state_table_entry
+{
+ int num;
+ int alloc;
+ re_dfastate_t **array;
+};
+
+/* Array type used in re_sub_match_last_t and re_sub_match_top_t. */
+
+typedef struct
+{
+ int next_idx;
+ int alloc;
+ re_dfastate_t **array;
+} state_array_t;
+
+/* Store information about the node NODE whose type is OP_CLOSE_SUBEXP. */
+
+typedef struct
+{
+ int node;
+ int str_idx; /* The position NODE match at. */
+ state_array_t path;
+} re_sub_match_last_t;
+
+/* Store information about the node NODE whose type is OP_OPEN_SUBEXP.
+ And information about the node, whose type is OP_CLOSE_SUBEXP,
+ corresponding to NODE is stored in LASTS. */
+
+typedef struct
+{
+ int str_idx;
+ int node;
+ state_array_t *path;
+ int alasts; /* Allocation size of LASTS. */
+ int nlasts; /* The number of LASTS. */
+ re_sub_match_last_t **lasts;
+} re_sub_match_top_t;
+
+struct re_backref_cache_entry
+{
+ int node;
+ int str_idx;
+ int subexp_from;
+ int subexp_to;
+ char more;
+ char unused;
+ unsigned short int eps_reachable_subexps_map;
+};
+
+typedef struct
+{
+ /* The string object corresponding to the input string. */
+ re_string_t input;
+ const re_dfa_t *dfa;
+ /* EFLAGS of the argument of regexec. */
+ int eflags;
+ /* Where the matching ends. */
+ int match_last;
+ int last_node;
+ /* The state log used by the matcher. */
+ re_dfastate_t **state_log;
+ int state_log_top;
+ /* Back reference cache. */
+ int nbkref_ents;
+ int abkref_ents;
+ struct re_backref_cache_entry *bkref_ents;
+ int max_mb_elem_len;
+ int nsub_tops;
+ int asub_tops;
+ re_sub_match_top_t **sub_tops;
+} re_match_context_t;
+
+typedef struct
+{
+ re_dfastate_t **sifted_states;
+ re_dfastate_t **limited_states;
+ int last_node;
+ int last_str_idx;
+ re_node_set limits;
+} re_sift_context_t;
+
+struct re_fail_stack_ent_t
+{
+ int idx;
+ int node;
+ regmatch_t *regs;
+ re_node_set eps_via_nodes;
+};
+
+struct re_fail_stack_t
+{
+ int num;
+ int alloc;
+ struct re_fail_stack_ent_t *stack;
+};
+
+struct re_dfa_t
+{
+ re_token_t *nodes;
+ size_t nodes_alloc;
+ size_t nodes_len;
+ int *nexts;
+ int *org_indices;
+ re_node_set *edests;
+ re_node_set *eclosures;
+ re_node_set *inveclosures;
+ struct re_state_table_entry *state_table;
+ re_dfastate_t *init_state;
+ re_dfastate_t *init_state_word;
+ re_dfastate_t *init_state_nl;
+ re_dfastate_t *init_state_begbuf;
+ bin_tree_t *str_tree;
+ bin_tree_storage_t *str_tree_storage;
+ re_bitset_ptr_t sb_char;
+ int str_tree_storage_idx;
+
+ /* number of subexpressions `re_nsub' is in regex_t. */
+ unsigned int state_hash_mask;
+ int init_node;
+ int nbackref; /* The number of backreference in this dfa. */
+
+ /* Bitmap expressing which backreference is used. */
+ bitset_word_t used_bkref_map;
+ bitset_word_t completed_bkref_map;
+
+ unsigned int has_plural_match : 1;
+ /* If this dfa has "multibyte node", which is a backreference or
+ a node which can accept multibyte character or multi character
+ collating element. */
+ unsigned int has_mb_node : 1;
+ unsigned int is_utf8 : 1;
+ unsigned int map_notascii : 1;
+ unsigned int word_ops_used : 1;
+ int mb_cur_max;
+ bitset_t word_char;
+ reg_syntax_t syntax;
+ int *subexp_map;
+#ifdef DEBUG
+ char* re_str;
+#endif
+ __libc_lock_define (, lock)
+};
+
+#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))
+#define re_node_set_empty(p) ((p)->nelem = 0)
+#define re_node_set_free(set) re_free ((set)->elems)
+
+
+typedef enum
+{
+ SB_CHAR,
+ MB_CHAR,
+ EQUIV_CLASS,
+ COLL_SYM,
+ CHAR_CLASS
+} bracket_elem_type;
+
+typedef struct
+{
+ bracket_elem_type type;
+ union
+ {
+ unsigned char ch;
+ unsigned char *name;
+#ifdef __UCLIBC_HAS_WCHAR__
+ wchar_t wch;
+#endif
+ } opr;
+} bracket_elem_t;
+
+
+/* Inline functions for bitset operation. */
+static __inline__ void
+bitset_not (bitset_t set)
+{
+ int bitset_i;
+ for (bitset_i = 0; bitset_i < BITSET_WORDS; ++bitset_i)
+ set[bitset_i] = ~set[bitset_i];
+}
+
+static __inline__ void
+bitset_merge (bitset_t dest, const bitset_t src)
+{
+ int bitset_i;
+ for (bitset_i = 0; bitset_i < BITSET_WORDS; ++bitset_i)
+ dest[bitset_i] |= src[bitset_i];
+}
+
+static __inline__ void
+bitset_mask (bitset_t dest, const bitset_t src)
+{
+ int bitset_i;
+ for (bitset_i = 0; bitset_i < BITSET_WORDS; ++bitset_i)
+ dest[bitset_i] &= src[bitset_i];
+}
+
+#ifdef RE_ENABLE_I18N
+/* Inline functions for re_string. */
+static __inline__ int
+internal_function __attribute ((pure))
+re_string_char_size_at (const re_string_t *pstr, int idx)
+{
+ int byte_idx;
+ if (pstr->mb_cur_max == 1)
+ return 1;
+ for (byte_idx = 1; idx + byte_idx < pstr->valid_len; ++byte_idx)
+ if (pstr->wcs[idx + byte_idx] != WEOF)
+ break;
+ return byte_idx;
+}
+
+static __inline__ wint_t
+internal_function __attribute ((pure))
+re_string_wchar_at (const re_string_t *pstr, int idx)
+{
+ if (pstr->mb_cur_max == 1)
+ return (wint_t) pstr->mbs[idx];
+ return (wint_t) pstr->wcs[idx];
+}
+
+static int
+internal_function __attribute ((pure))
+re_string_elem_size_at (const re_string_t *pstr, int idx)
+{
+# if 0
+ const unsigned char *p, *extra;
+ const int32_t *table, *indirect;
+ int32_t tmp;
+# include <locale/weight.h>
+ uint_fast32_t nrules = _NL_CURRENT_WORD (LC_COLLATE, _NL_COLLATE_NRULES);
+
+ if (nrules != 0)
+ {
+ table = (const int32_t *) _NL_CURRENT (LC_COLLATE, _NL_COLLATE_TABLEMB);
+ extra = (const unsigned char *)
+ _NL_CURRENT (LC_COLLATE, _NL_COLLATE_EXTRAMB);
+ indirect = (const int32_t *) _NL_CURRENT (LC_COLLATE,
+ _NL_COLLATE_INDIRECTMB);
+ p = pstr->mbs + idx;
+ tmp = findidx (&p);
+ return p - pstr->mbs - idx;
+ }
+# endif
+ return 1;
+}
+#endif /* RE_ENABLE_I18N */
+
+#endif /* _REGEX_INTERNAL_H */
diff --git a/ap/build/uClibc/libc/misc/regex/regex_old.c b/ap/build/uClibc/libc/misc/regex/regex_old.c
new file mode 100644
index 0000000..acf81a3
--- /dev/null
+++ b/ap/build/uClibc/libc/misc/regex/regex_old.c
@@ -0,0 +1,8269 @@
+/* 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-1999, 2000, 2001 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. */
+
+/* To exclude some unwanted junk.... */
+#undef emacs
+#include <features.h>
+/* unistd.h must be included with _LIBC defined: we need smallint */
+#include <unistd.h>
+#ifdef __UCLIBC__
+# undef _LIBC
+# define _REGEX_RE_COMP
+# define STDC_HEADERS
+# define RE_TRANSLATE_TYPE char *
+#endif
+#include <stdlib.h>
+#include <stdint.h>
+#include <string.h>
+#include <stdio.h>
+
+/* AIX requires this to be the first thing in the file. */
+#if defined _AIX && !defined REGEX_MALLOC
+# pragma alloca
+#endif
+
+#ifdef HAVE_CONFIG_H
+# include <config.h>
+#endif
+
+#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
+
+
+/* For platform which support the ISO C amendement 1 functionality we
+ support user defined character classes. */
+# if defined __UCLIBC_HAS_WCHAR__
+# define WIDE_CHAR_SUPPORT 1
+/* Solaris 2.5 has a bug: <wchar.h> must be included before <wctype.h>. */
+# include <wchar.h>
+# include <wctype.h>
+# endif
+
+# if defined _LIBC || defined __UCLIBC__
+/* We have to keep the namespace clean. */
+
+# ifndef __UCLIBC__
+# 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
+# endif
+
+/* This is for other GNU distributions with internationalized messages. */
+# if defined HAVE_LIBINTL_H || 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 || defined 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 smallint 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 __intptr_t_defined
+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 "regex_old.c"
+# undef INSIDE_RECURSION
+# endif
+# define BYTE
+# define INSIDE_RECURSION
+# include "regex_old.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)
+{
+# 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)
+{
+ 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 smallint 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
+static 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. */
+
+static 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
+}
+
+
+static 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? */
+}
+
+
+static 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;
+ }
+ }
+ }
+}
+
+# if 0 /* ndef 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, /* the length of multibyte string. */
+
+ /* 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}
+ */
+ int *offset_buffer,
+ char *is_binary)
+{
+ 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;
+}
+
+/* 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[] =
+ {
+# define REG_NOERROR_IDX 0
+ gettext_noop ("Success") /* REG_NOERROR */
+ "\0"
+# define REG_NOMATCH_IDX (REG_NOERROR_IDX + sizeof "Success")
+ gettext_noop ("No match") /* REG_NOMATCH */
+ "\0"
+# define REG_BADPAT_IDX (REG_NOMATCH_IDX + sizeof "No match")
+ gettext_noop ("Invalid regular expression") /* REG_BADPAT */
+ "\0"
+# define REG_ECOLLATE_IDX (REG_BADPAT_IDX + sizeof "Invalid regular expression")
+ gettext_noop ("Invalid collation character") /* REG_ECOLLATE */
+ "\0"
+# define REG_ECTYPE_IDX (REG_ECOLLATE_IDX + sizeof "Invalid collation character")
+ gettext_noop ("Invalid character class name") /* REG_ECTYPE */
+ "\0"
+# define REG_EESCAPE_IDX (REG_ECTYPE_IDX + sizeof "Invalid character class name")
+ gettext_noop ("Trailing backslash") /* REG_EESCAPE */
+ "\0"
+# define REG_ESUBREG_IDX (REG_EESCAPE_IDX + sizeof "Trailing backslash")
+ gettext_noop ("Invalid back reference") /* REG_ESUBREG */
+ "\0"
+# define REG_EBRACK_IDX (REG_ESUBREG_IDX + sizeof "Invalid back reference")
+ gettext_noop ("Unmatched [ or [^") /* REG_EBRACK */
+ "\0"
+# define REG_EPAREN_IDX (REG_EBRACK_IDX + sizeof "Unmatched [ or [^")
+ gettext_noop ("Unmatched ( or \\(") /* REG_EPAREN */
+ "\0"
+# define REG_EBRACE_IDX (REG_EPAREN_IDX + sizeof "Unmatched ( or \\(")
+ gettext_noop ("Unmatched \\{") /* REG_EBRACE */
+ "\0"
+# define REG_BADBR_IDX (REG_EBRACE_IDX + sizeof "Unmatched \\{")
+ gettext_noop ("Invalid content of \\{\\}") /* REG_BADBR */
+ "\0"
+# define REG_ERANGE_IDX (REG_BADBR_IDX + sizeof "Invalid content of \\{\\}")
+ gettext_noop ("Invalid range end") /* REG_ERANGE */
+ "\0"
+# define REG_ESPACE_IDX (REG_ERANGE_IDX + sizeof "Invalid range end")
+ gettext_noop ("Memory exhausted") /* REG_ESPACE */
+ "\0"
+# define REG_BADRPT_IDX (REG_ESPACE_IDX + sizeof "Memory exhausted")
+ gettext_noop ("Invalid preceding regular expression") /* REG_BADRPT */
+ "\0"
+# define REG_EEND_IDX (REG_BADRPT_IDX + sizeof "Invalid preceding regular expression")
+ gettext_noop ("Premature end of regular expression") /* REG_EEND */
+ "\0"
+# define REG_ESIZE_IDX (REG_EEND_IDX + sizeof "Premature end of regular expression")
+ gettext_noop ("Regular expression too big") /* REG_ESIZE */
+ "\0"
+# define REG_ERPAREN_IDX (REG_ESIZE_IDX + sizeof "Regular expression too big")
+ gettext_noop ("Unmatched ) or \\)") /* REG_ERPAREN */
+ };
+
+static const uint16_t re_error_msgid_idx[] =
+ {
+ REG_NOERROR_IDX,
+ REG_NOMATCH_IDX,
+ REG_BADPAT_IDX,
+ REG_ECOLLATE_IDX,
+ REG_ECTYPE_IDX,
+ REG_EESCAPE_IDX,
+ REG_ESUBREG_IDX,
+ REG_EBRACK_IDX,
+ REG_EPAREN_IDX,
+ REG_EBRACE_IDX,
+ REG_BADBR_IDX,
+ REG_ERANGE_IDX,
+ REG_ESPACE_IDX,
+ REG_BADRPT_IDX,
+ REG_EEND_IDX,
+ REG_ESIZE_IDX,
+ REG_ERPAREN_IDX
+ };
+
+#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. */
+
+# ifdef INT_IS_16BIT
+
+# ifndef DEFINED_ONCE
+# if defined MATCH_MAY_ALLOCATE
+/* 4400 was enough to cause a crash on Alpha OSF/1,
+ whose default stack limit is 2mb. */
+long int re_max_failures = 4000;
+# else
+long int re_max_failures = 2000;
+# endif
+# endif
+
+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 */
+
+# ifndef DEFINED_ONCE
+# if defined MATCH_MAY_ALLOCATE
+/* 4400 was enough to cause a crash on Alpha OSF/1,
+ whose default stack limit is 2mb. */
+int re_max_failures = 4000;
+# else
+int re_max_failures = 2000;
+# endif
+# endif
+
+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,
+ char *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)] : (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
+# endif /* not DEFINED_ONCE */
+
+/* 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. */
+# 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; \
+ b += incr; \
+ begalt += incr; \
+ if (fixup_alt_jump) \
+ fixup_alt_jump += incr; \
+ if (laststart) \
+ laststart += incr; \
+ if (pending_exact) \
+ pending_exact += incr; \
+ } \
+ } 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; \
+ b += incr; \
+ begalt += incr; \
+ if (fixup_alt_jump) \
+ fixup_alt_jump += incr; \
+ if (laststart) \
+ laststart += incr; \
+ if (pending_exact) \
+ pending_exact += incr; \
+ } \
+ } 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 defined _LIBC || defined 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);
+ 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 CHAR_CLASS_MAX_LENGTH != 256
+ if (c1 < CHAR_CLASS_MAX_LENGTH)
+ str[c1++] = c;
+ else
+ /* This is in any case an invalid class name. */
+ str[0] = '\0';
+#else
+ str[c1++] = c;
+#endif
+ }
+ 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 defined _LIBC || defined 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);
+ 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 (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;
+# ifdef _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;
+
+# ifdef _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)
+{
+ 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 == 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);
+# endif
+ return byte_re_compile_fastmap(bufp);
+}
+libc_hidden_def(re_compile_fastmap)
+
+
+/* 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;
+ }
+}
+
+/* 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);
+}
+libc_hidden_def(re_search)
+
+
+/* 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);
+# endif
+ return byte_re_search_2 (bufp, string1, size1, string2, size2, startpos,
+ range, regs, stop);
+}
+libc_hidden_def(re_search_2)
+
+#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) 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 optimization. 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;
+}
+#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,
+ int len, char *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;
+}
+
+#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. */
+ /* We need the size of wchar_t buffers correspond to csize1, csize2. */
+ wchar_t *string1, int size1,
+ wchar_t *string2, int size2,
+ /* offset buffer for optimization. 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. */
+/* regex specs say:
+ * "If REGS_UNALLOCATED, allocate space in the regs structure
+ * for max(RE_NREGS, re_nsub + 1) groups"
+ * but real-world testsuites fail with contrived examples
+ * with lots of groups.
+ * I don't see why we can't just allocate exact needed number.
+ * Incidentally, it makes RE_NREGS unused.
+ *
+ * regs->num_regs = MAX (RE_NREGS, num_regs + 1); - VERY WRONG
+ * regs->num_regs = MIN (RE_NREGS, num_regs + 1); - slightly less wrong
+ * good one which passes uclibc test/regex/tst-regex2.c:
+ */
+ regs->num_regs = 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 not = (re_opcode_t) *(p - 1) == charset_not;
+
+ DEBUG_PRINT2 ("EXECUTING charset%s.\n", not ? "_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);
+ }
+
+ /* 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;
+
+ not = !not;
+
+ char_set_matched:
+ if (not) 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)))
+ not = !not;
+
+ p += 1 + *p;
+
+ if (!not) 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 not = (re_opcode_t) p1[3] == charset_not;
+
+ if (c < (unsigned) (p1[4] * BYTEWIDTH)
+ && p1[5 + c / BYTEWIDTH] & (1 << (c % BYTEWIDTH)))
+ not = !not;
+
+ /* `not' is equal to 1 if c would match, which means
+ that we can't change to pop_failure_jump. */
+ if (!not)
+ {
+ 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 + re_error_msgid_idx[(int) ret]);
+}
+
+/* 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 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
+ + re_error_msgid_idx[(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
+ + re_error_msgid_idx[(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 + re_error_msgid_idx[(int) ret]);
+}
+
+
+int
+#if defined _LIBC || defined __UCLIBC__
+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)
+ {
+ unsigned 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;
+}
+
+
+/* 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;
+
+ /* use hidden memcpy() ourselves rather than gcc calling public memcpy() */
+ memcpy(&private_preg, preg, sizeof(*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;
+}
+libc_hidden_def(regexec)
+
+
+/* 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_idx)
+ / sizeof (re_error_msgid_idx[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 + re_error_msgid_idx[errcode]);
+
+ msg_size = strlen (msg) + 1; /* Includes the null. */
+
+ if (errbuf_size != 0)
+ {
+ if (msg_size > errbuf_size)
+ {
+ memcpy (errbuf, msg, errbuf_size - 1);
+ errbuf[errbuf_size - 1] = 0;
+ }
+ else
+ memcpy (errbuf, msg, msg_size);
+ }
+
+ return msg_size;
+}
+
+
+/* Free dynamically allocated space used by PREG. */
+
+void
+regfree (regex_t *preg)
+{
+ free (preg->buffer);
+ preg->buffer = NULL;
+
+ preg->allocated = 0;
+ preg->used = 0;
+
+ free (preg->fastmap);
+ preg->fastmap = NULL;
+ preg->fastmap_accurate = 0;
+
+ free (preg->translate);
+ preg->translate = NULL;
+}
+libc_hidden_def(regfree)
+
+#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/ap/build/uClibc/libc/misc/regex/regexec.c b/ap/build/uClibc/libc/misc/regex/regexec.c
new file mode 100644
index 0000000..c13c64e
--- /dev/null
+++ b/ap/build/uClibc/libc/misc/regex/regexec.c
@@ -0,0 +1,4247 @@
+/* Extended regular expression matching and search library.
+ Copyright (C) 2002, 2003, 2004, 2005 Free Software Foundation, Inc.
+ This file is part of the GNU C Library.
+ Contributed by Isamu Hasegawa <isamu@yamato.ibm.com>.
+
+ The GNU C Library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 2.1 of the License, or (at your option) any later version.
+
+ The GNU C Library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with the GNU C Library; if not, write to the Free
+ Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+ 02111-1307 USA. */
+
+static reg_errcode_t match_ctx_init (re_match_context_t *cache, int eflags,
+ int n) internal_function;
+static void match_ctx_clean (re_match_context_t *mctx) internal_function;
+static void match_ctx_free (re_match_context_t *cache) internal_function;
+static reg_errcode_t match_ctx_add_entry (re_match_context_t *cache, int node,
+ int str_idx, int from, int to)
+ internal_function;
+static int search_cur_bkref_entry (const re_match_context_t *mctx, int str_idx)
+ internal_function;
+static reg_errcode_t match_ctx_add_subtop (re_match_context_t *mctx, int node,
+ int str_idx) internal_function;
+static re_sub_match_last_t * match_ctx_add_sublast (re_sub_match_top_t *subtop,
+ int node, int str_idx)
+ internal_function;
+static void sift_ctx_init (re_sift_context_t *sctx, re_dfastate_t **sifted_sts,
+ re_dfastate_t **limited_sts, int last_node,
+ int last_str_idx)
+ internal_function;
+static reg_errcode_t re_search_internal (const regex_t *preg,
+ const char *string, int length,
+ int start, int range, int stop,
+ size_t nmatch, regmatch_t pmatch[],
+ int eflags) internal_function;
+static int re_search_2_stub (struct re_pattern_buffer *bufp,
+ const char *string1, int length1,
+ const char *string2, int length2,
+ int start, int range, struct re_registers *regs,
+ int stop, int ret_len) internal_function;
+static int re_search_stub (struct re_pattern_buffer *bufp,
+ const char *string, int length, int start,
+ int range, int stop, struct re_registers *regs,
+ int ret_len) internal_function;
+static unsigned re_copy_regs (struct re_registers *regs, regmatch_t *pmatch,
+ int nregs, int regs_allocated) internal_function;
+static reg_errcode_t prune_impossible_nodes (re_match_context_t *mctx)
+ internal_function;
+static int check_matching (re_match_context_t *mctx, int fl_longest_match,
+ int *p_match_first) internal_function;
+static int check_halt_state_context (const re_match_context_t *mctx,
+ const re_dfastate_t *state, int idx)
+ internal_function;
+static void update_regs (const re_dfa_t *dfa, regmatch_t *pmatch,
+ regmatch_t *prev_idx_match, int cur_node,
+ int cur_idx, int nmatch) internal_function;
+static reg_errcode_t push_fail_stack (struct re_fail_stack_t *fs,
+ int str_idx, int dest_node, int nregs,
+ regmatch_t *regs,
+ re_node_set *eps_via_nodes)
+ internal_function;
+static reg_errcode_t set_regs (const regex_t *preg,
+ const re_match_context_t *mctx,
+ size_t nmatch, regmatch_t *pmatch,
+ int fl_backtrack) internal_function;
+static reg_errcode_t free_fail_stack_return (struct re_fail_stack_t *fs)
+ internal_function;
+
+#ifdef RE_ENABLE_I18N
+static int sift_states_iter_mb (const re_match_context_t *mctx,
+ re_sift_context_t *sctx,
+ int node_idx, int str_idx, int max_str_idx)
+ internal_function;
+#endif
+static reg_errcode_t sift_states_backward (const re_match_context_t *mctx,
+ re_sift_context_t *sctx)
+ internal_function;
+static reg_errcode_t build_sifted_states (const re_match_context_t *mctx,
+ re_sift_context_t *sctx, int str_idx,
+ re_node_set *cur_dest)
+ internal_function;
+static reg_errcode_t update_cur_sifted_state (const re_match_context_t *mctx,
+ re_sift_context_t *sctx,
+ int str_idx,
+ re_node_set *dest_nodes)
+ internal_function;
+static reg_errcode_t add_epsilon_src_nodes (const re_dfa_t *dfa,
+ re_node_set *dest_nodes,
+ const re_node_set *candidates)
+ internal_function;
+static int check_dst_limits (const re_match_context_t *mctx,
+ re_node_set *limits,
+ int dst_node, int dst_idx, int src_node,
+ int src_idx) internal_function;
+static int check_dst_limits_calc_pos_1 (const re_match_context_t *mctx,
+ int boundaries, int subexp_idx,
+ int from_node, int bkref_idx)
+ internal_function;
+static int check_dst_limits_calc_pos (const re_match_context_t *mctx,
+ int limit, int subexp_idx,
+ int node, int str_idx,
+ int bkref_idx) internal_function;
+static reg_errcode_t check_subexp_limits (const re_dfa_t *dfa,
+ re_node_set *dest_nodes,
+ const re_node_set *candidates,
+ re_node_set *limits,
+ struct re_backref_cache_entry *bkref_ents,
+ int str_idx) internal_function;
+static reg_errcode_t sift_states_bkref (const re_match_context_t *mctx,
+ re_sift_context_t *sctx,
+ int str_idx, const re_node_set *candidates)
+ internal_function;
+static reg_errcode_t merge_state_array (const re_dfa_t *dfa,
+ re_dfastate_t **dst,
+ re_dfastate_t **src, int num)
+ internal_function;
+static re_dfastate_t *find_recover_state (reg_errcode_t *err,
+ re_match_context_t *mctx) internal_function;
+static re_dfastate_t *transit_state (reg_errcode_t *err,
+ re_match_context_t *mctx,
+ re_dfastate_t *state) internal_function;
+static re_dfastate_t *merge_state_with_log (reg_errcode_t *err,
+ re_match_context_t *mctx,
+ re_dfastate_t *next_state)
+ internal_function;
+static reg_errcode_t check_subexp_matching_top (re_match_context_t *mctx,
+ re_node_set *cur_nodes,
+ int str_idx) internal_function;
+#if 0
+static re_dfastate_t *transit_state_sb (reg_errcode_t *err,
+ re_match_context_t *mctx,
+ re_dfastate_t *pstate)
+ internal_function;
+#endif
+#ifdef RE_ENABLE_I18N
+static reg_errcode_t transit_state_mb (re_match_context_t *mctx,
+ re_dfastate_t *pstate)
+ internal_function;
+#endif
+static reg_errcode_t transit_state_bkref (re_match_context_t *mctx,
+ const re_node_set *nodes)
+ internal_function;
+static reg_errcode_t get_subexp (re_match_context_t *mctx,
+ int bkref_node, int bkref_str_idx)
+ internal_function;
+static reg_errcode_t get_subexp_sub (re_match_context_t *mctx,
+ const re_sub_match_top_t *sub_top,
+ re_sub_match_last_t *sub_last,
+ int bkref_node, int bkref_str)
+ internal_function;
+static int find_subexp_node (const re_dfa_t *dfa, const re_node_set *nodes,
+ int subexp_idx, int type) internal_function;
+static reg_errcode_t check_arrival (re_match_context_t *mctx,
+ state_array_t *path, int top_node,
+ int top_str, int last_node, int last_str,
+ int type) internal_function;
+static reg_errcode_t check_arrival_add_next_nodes (re_match_context_t *mctx,
+ int str_idx,
+ re_node_set *cur_nodes,
+ re_node_set *next_nodes)
+ internal_function;
+static reg_errcode_t check_arrival_expand_ecl (const re_dfa_t *dfa,
+ re_node_set *cur_nodes,
+ int ex_subexp, int type)
+ internal_function;
+static reg_errcode_t check_arrival_expand_ecl_sub (const re_dfa_t *dfa,
+ re_node_set *dst_nodes,
+ int target, int ex_subexp,
+ int type) internal_function;
+static reg_errcode_t expand_bkref_cache (re_match_context_t *mctx,
+ re_node_set *cur_nodes, int cur_str,
+ int subexp_num, int type)
+ internal_function;
+static int build_trtable (const re_dfa_t *dfa,
+ re_dfastate_t *state) internal_function;
+#ifdef RE_ENABLE_I18N
+static int check_node_accept_bytes (const re_dfa_t *dfa, int node_idx,
+ const re_string_t *input, int idx)
+ internal_function;
+#endif
+static int group_nodes_into_DFAstates (const re_dfa_t *dfa,
+ const re_dfastate_t *state,
+ re_node_set *states_node,
+ bitset_t *states_ch) internal_function;
+static int check_node_accept (const re_match_context_t *mctx,
+ const re_token_t *node, int idx)
+ internal_function;
+static reg_errcode_t extend_buffers (re_match_context_t *mctx)
+ internal_function;
+
+/* Entry point for POSIX code. */
+
+/* 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 *__restrict preg, const char *__restrict string,
+ size_t nmatch, regmatch_t pmatch[], int eflags)
+{
+ reg_errcode_t err;
+ int start, length;
+#ifdef __UCLIBC_HAS_THREADS__
+ re_dfa_t *dfa = (re_dfa_t *) preg->buffer;
+#endif
+
+ if (eflags & ~(REG_NOTBOL | REG_NOTEOL | REG_STARTEND))
+ return REG_BADPAT;
+
+ if (eflags & REG_STARTEND)
+ {
+ start = pmatch[0].rm_so;
+ length = pmatch[0].rm_eo;
+ }
+ else
+ {
+ start = 0;
+ length = strlen (string);
+ }
+
+ __libc_lock_lock (dfa->lock);
+ if (preg->no_sub)
+ err = re_search_internal (preg, string, length, start, length - start,
+ length, 0, NULL, eflags);
+ else
+ err = re_search_internal (preg, string, length, start, length - start,
+ length, nmatch, pmatch, eflags);
+ __libc_lock_unlock (dfa->lock);
+ return err != REG_NOERROR;
+}
+libc_hidden_def(regexec)
+
+/* Entry points for GNU code. */
+
+/* re_match, re_search, re_match_2, re_search_2
+
+ The former two functions operate on STRING with length LENGTH,
+ while the later two operate on concatenation of STRING1 and STRING2
+ with lengths LENGTH1 and LENGTH2, respectively.
+
+ re_match() matches the compiled pattern in BUFP against the string,
+ starting at index START.
+
+ re_search() first tries matching at index START, then it tries to match
+ starting from index START + 1, and so on. The last start position tried
+ is START + RANGE. (Thus RANGE = 0 forces re_search to operate the same
+ way as re_match().)
+
+ The parameter STOP of re_{match,search}_2 specifies that no match exceeding
+ the first STOP characters of the concatenation of the strings should be
+ concerned.
+
+ If REGS is not NULL, and BUFP->no_sub is not set, the offsets of the match
+ and all groups is stroed in REGS. (For the "_2" variants, the offsets are
+ computed relative to the concatenation, not relative to the individual
+ strings.)
+
+ On success, re_match* functions return the length of the match, re_search*
+ return the position of the start of the match. Return value -1 means no
+ match was found and -2 indicates an internal error. */
+
+int
+re_match (struct re_pattern_buffer *bufp, const char *string, int length,
+ int start, struct re_registers *regs)
+{
+ return re_search_stub (bufp, string, length, start, 0, length, regs, 1);
+}
+
+int
+re_search (struct re_pattern_buffer *bufp, const char *string, int length,
+ int start, int range, struct re_registers *regs)
+{
+ return re_search_stub (bufp, string, length, start, range, length, regs, 0);
+}
+libc_hidden_def(re_search)
+
+int
+re_match_2 (struct re_pattern_buffer *bufp, const char *string1, int length1,
+ const char *string2, int length2, int start,
+ struct re_registers *regs, int stop)
+{
+ return re_search_2_stub (bufp, string1, length1, string2, length2,
+ start, 0, regs, stop, 1);
+}
+
+int
+re_search_2 (struct re_pattern_buffer *bufp, const char *string1, int lenght1,
+ const char *string2, int length2, int start, int range,
+ struct re_registers *regs, int stop)
+{
+ return re_search_2_stub (bufp, string1, lenght1, string2, length2,
+ start, range, regs, stop, 0);
+}
+libc_hidden_def(re_search_2)
+
+static int internal_function
+re_search_2_stub (struct re_pattern_buffer *bufp, const char *string1,
+ int length1, const char *string2, int length2, int start,
+ int range, struct re_registers *regs, int stop, int ret_len)
+{
+ const char *str;
+ int rval;
+ int len = length1 + length2;
+ int free_str = 0;
+
+ if (BE (length1 < 0 || length2 < 0 || stop < 0, 0))
+ return -2;
+
+ /* Concatenate the strings. */
+ if (length2 > 0)
+ if (length1 > 0)
+ {
+ char *s = re_malloc (char, len);
+
+ if (BE (s == NULL, 0))
+ return -2;
+ memcpy (s, string1, length1);
+ memcpy (s + length1, string2, length2);
+ str = s;
+ free_str = 1;
+ }
+ else
+ str = string2;
+ else
+ str = string1;
+
+ rval = re_search_stub (bufp, str, len, start, range, stop, regs,
+ ret_len);
+ if (free_str)
+ re_free ((char *) str);
+ return rval;
+}
+
+/* The parameters have the same meaning as those of re_search.
+ Additional parameters:
+ If RET_LEN is nonzero the length of the match is returned (re_match style);
+ otherwise the position of the match is returned. */
+
+static int internal_function
+re_search_stub (struct re_pattern_buffer *bufp, const char *string, int length,
+ int start, int range, int stop, struct re_registers *regs,
+ int ret_len)
+{
+ reg_errcode_t result;
+ regmatch_t *pmatch;
+ int nregs, rval;
+ int eflags = 0;
+#ifdef __UCLIBC_HAS_THREADS__
+ re_dfa_t *dfa = (re_dfa_t *) bufp->buffer;
+#endif
+ /* Check for out-of-range. */
+ if (BE (start < 0 || start > length, 0))
+ return -1;
+ if (BE (start + range > length, 0))
+ range = length - start;
+ else if (BE (start + range < 0, 0))
+ range = -start;
+
+ __libc_lock_lock (dfa->lock);
+
+ eflags |= (bufp->not_bol) ? REG_NOTBOL : 0;
+ eflags |= (bufp->not_eol) ? REG_NOTEOL : 0;
+
+ /* Compile fastmap if we haven't yet. */
+ if (range > 0 && bufp->fastmap != NULL && !bufp->fastmap_accurate)
+ re_compile_fastmap (bufp);
+
+ if (BE (bufp->no_sub, 0))
+ regs = NULL;
+
+ /* We need at least 1 register. */
+ if (regs == NULL)
+ nregs = 1;
+ else if (BE (bufp->regs_allocated == REGS_FIXED &&
+ regs->num_regs < bufp->re_nsub + 1, 0))
+ {
+ nregs = regs->num_regs;
+ if (BE (nregs < 1, 0))
+ {
+ /* Nothing can be copied to regs. */
+ regs = NULL;
+ nregs = 1;
+ }
+ }
+ else
+ nregs = bufp->re_nsub + 1;
+ pmatch = re_malloc (regmatch_t, nregs);
+ if (BE (pmatch == NULL, 0))
+ {
+ rval = -2;
+ goto out;
+ }
+
+ result = re_search_internal (bufp, string, length, start, range, stop,
+ nregs, pmatch, eflags);
+
+ rval = 0;
+
+ /* I hope we needn't fill ther regs with -1's when no match was found. */
+ if (result != REG_NOERROR)
+ rval = -1;
+ else if (regs != NULL)
+ {
+ /* If caller wants register contents data back, copy them. */
+ bufp->regs_allocated = re_copy_regs (regs, pmatch, nregs,
+ bufp->regs_allocated);
+ if (BE (bufp->regs_allocated == REGS_UNALLOCATED, 0))
+ rval = -2;
+ }
+
+ if (BE (rval == 0, 1))
+ {
+ if (ret_len)
+ {
+ assert (pmatch[0].rm_so == start);
+ rval = pmatch[0].rm_eo - start;
+ }
+ else
+ rval = pmatch[0].rm_so;
+ }
+ re_free (pmatch);
+ out:
+ __libc_lock_unlock (dfa->lock);
+ return rval;
+}
+
+static unsigned internal_function
+re_copy_regs (struct re_registers *regs, regmatch_t *pmatch, int nregs,
+ int regs_allocated)
+{
+ int rval = REGS_REALLOCATE;
+ int i;
+ int need_regs = nregs + 1;
+ /* We need one extra element beyond `num_regs' for the `-1' marker GNU code
+ uses. */
+
+ /* Have the register data arrays been allocated? */
+ if (regs_allocated == REGS_UNALLOCATED)
+ { /* No. So allocate them with malloc. */
+ regs->start = re_malloc (regoff_t, need_regs);
+ regs->end = re_malloc (regoff_t, need_regs);
+ if (BE (regs->start == NULL, 0) || BE (regs->end == NULL, 0))
+ return REGS_UNALLOCATED;
+ regs->num_regs = need_regs;
+ }
+ else if (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 (BE (need_regs > regs->num_regs, 0))
+ {
+ regoff_t *new_start = re_realloc (regs->start, regoff_t, need_regs);
+ regoff_t *new_end = re_realloc (regs->end, regoff_t, need_regs);
+ if (BE (new_start == NULL, 0) || BE (new_end == NULL, 0))
+ return REGS_UNALLOCATED;
+ regs->start = new_start;
+ regs->end = new_end;
+ regs->num_regs = need_regs;
+ }
+ }
+ else
+ {
+ assert (regs_allocated == REGS_FIXED);
+ /* This function may not be called with REGS_FIXED and nregs too big. */
+ assert (regs->num_regs >= nregs);
+ rval = REGS_FIXED;
+ }
+
+ /* Copy the regs. */
+ for (i = 0; i < nregs; ++i)
+ {
+ regs->start[i] = pmatch[i].rm_so;
+ regs->end[i] = pmatch[i].rm_eo;
+ }
+ for ( ; i < regs->num_regs; ++i)
+ regs->start[i] = regs->end[i] = -1;
+
+ return rval;
+}
+
+/* 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;
+ }
+}
+
+/* Entry points compatible with 4.2 BSD regex library. We don't define
+ them unless specifically requested. */
+
+#if defined _REGEX_RE_COMP || defined __UCLIBC__
+int
+weak_function
+re_exec (const char *s)
+{
+ return 0 == regexec (re_comp_buf, s, 0, NULL, 0);
+}
+#endif
+
+/* Internal entry point. */
+
+/* Searches for a compiled pattern PREG in the string STRING, whose
+ length is LENGTH. NMATCH, PMATCH, and EFLAGS have the same
+ mingings with regexec. START, and RANGE have the same meanings
+ with re_search.
+ Return REG_NOERROR if we find a match, and REG_NOMATCH if not,
+ otherwise return the error code.
+ Note: We assume front end functions already check ranges.
+ (START + RANGE >= 0 && START + RANGE <= LENGTH) */
+static reg_errcode_t internal_function
+re_search_internal (const regex_t *preg, const char *string, int length,
+ int start, int range, int stop, size_t nmatch,
+ regmatch_t pmatch[], int eflags)
+{
+ reg_errcode_t err;
+ const re_dfa_t *dfa = (const re_dfa_t *) preg->buffer;
+ int left_lim, right_lim, incr;
+ int fl_longest_match, match_first, match_kind, match_last = -1;
+ int extra_nmatch;
+ int sb, ch;
+ re_match_context_t mctx;
+ char *fastmap = (preg->fastmap != NULL && preg->fastmap_accurate
+ && range && !preg->can_be_null) ? preg->fastmap : NULL;
+ RE_TRANSLATE_TYPE t = preg->translate;
+
+ memset (&mctx, '\0', sizeof (re_match_context_t));
+ mctx.dfa = dfa;
+
+ extra_nmatch = (nmatch > preg->re_nsub) ? nmatch - (preg->re_nsub + 1) : 0;
+ nmatch -= extra_nmatch;
+
+ /* Check if the DFA haven't been compiled. */
+ if (BE (preg->used == 0 || dfa->init_state == NULL
+ || dfa->init_state_word == NULL || dfa->init_state_nl == NULL
+ || dfa->init_state_begbuf == NULL, 0))
+ return REG_NOMATCH;
+
+#ifdef DEBUG
+ /* We assume front-end functions already check them. */
+ assert (start + range >= 0 && start + range <= length);
+#endif
+
+ /* If initial states with non-begbuf contexts have no elements,
+ the regex must be anchored. If preg->newline_anchor is set,
+ we'll never use init_state_nl, so do not check it. */
+ if (dfa->init_state->nodes.nelem == 0
+ && dfa->init_state_word->nodes.nelem == 0
+ && (dfa->init_state_nl->nodes.nelem == 0
+ || !preg->newline_anchor))
+ {
+ if (start != 0 && start + range != 0)
+ return REG_NOMATCH;
+ start = range = 0;
+ }
+
+ /* We must check the longest matching, if nmatch > 0. */
+ fl_longest_match = (nmatch != 0 || dfa->nbackref);
+
+ err = re_string_allocate (&mctx.input, string, length, dfa->nodes_len + 1,
+ preg->translate, preg->syntax & RE_ICASE, dfa);
+ if (BE (err != REG_NOERROR, 0))
+ goto free_return;
+ mctx.input.stop = stop;
+ mctx.input.raw_stop = stop;
+ mctx.input.newline_anchor = preg->newline_anchor;
+
+ err = match_ctx_init (&mctx, eflags, dfa->nbackref * 2);
+ if (BE (err != REG_NOERROR, 0))
+ goto free_return;
+
+ /* We will log all the DFA states through which the dfa pass,
+ if nmatch > 1, or this dfa has "multibyte node", which is a
+ back-reference or a node which can accept multibyte character or
+ multi character collating element. */
+ if (nmatch > 1 || dfa->has_mb_node)
+ {
+ mctx.state_log = re_malloc (re_dfastate_t *, mctx.input.bufs_len + 1);
+ if (BE (mctx.state_log == NULL, 0))
+ {
+ err = REG_ESPACE;
+ goto free_return;
+ }
+ }
+ else
+ mctx.state_log = NULL;
+
+ match_first = start;
+ mctx.input.tip_context = (eflags & REG_NOTBOL) ? CONTEXT_BEGBUF
+ : CONTEXT_NEWLINE | CONTEXT_BEGBUF;
+
+ /* Check incrementally whether of not the input string match. */
+ 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;
+ match_kind =
+ (fastmap
+ ? ((sb || !(preg->syntax & RE_ICASE || t) ? 4 : 0)
+ | (range >= 0 ? 2 : 0)
+ | (t != NULL ? 1 : 0))
+ : 8);
+
+ for (;; match_first += incr)
+ {
+ err = REG_NOMATCH;
+ if (match_first < left_lim || right_lim < match_first)
+ goto free_return;
+
+ /* Advance as rapidly as possible through the string, until we
+ find a plausible place to start matching. This may be done
+ with varying efficiency, so there are various possibilities:
+ only the most common of them are specialized, in order to
+ save on code size. We use a switch statement for speed. */
+ switch (match_kind)
+ {
+ case 8:
+ /* No fastmap. */
+ break;
+
+ case 7:
+ /* Fastmap with single-byte translation, match forward. */
+ while (BE (match_first < right_lim, 1)
+ && !fastmap[t[(unsigned char) string[match_first]]])
+ ++match_first;
+ goto forward_match_found_start_or_reached_end;
+
+ case 6:
+ /* Fastmap without translation, match forward. */
+ while (BE (match_first < right_lim, 1)
+ && !fastmap[(unsigned char) string[match_first]])
+ ++match_first;
+
+ forward_match_found_start_or_reached_end:
+ if (BE (match_first == right_lim, 0))
+ {
+ ch = match_first >= length
+ ? 0 : (unsigned char) string[match_first];
+ if (!fastmap[t ? t[ch] : ch])
+ goto free_return;
+ }
+ break;
+
+ case 4:
+ case 5:
+ /* Fastmap without multi-byte translation, match backwards. */
+ while (match_first >= left_lim)
+ {
+ ch = match_first >= length
+ ? 0 : (unsigned char) string[match_first];
+ if (fastmap[t ? t[ch] : ch])
+ break;
+ --match_first;
+ }
+ if (match_first < left_lim)
+ goto free_return;
+ break;
+
+ default:
+ /* In this case, we can't determine easily the current byte,
+ since it might be a component byte of a multibyte
+ character. Then we use the constructed buffer instead. */
+ for (;;)
+ {
+ /* If MATCH_FIRST is out of the valid range, reconstruct the
+ buffers. */
+ unsigned int offset = match_first - mctx.input.raw_mbs_idx;
+ if (BE (offset >= (unsigned int) mctx.input.valid_raw_len, 0))
+ {
+ err = re_string_reconstruct (&mctx.input, match_first,
+ eflags);
+ if (BE (err != REG_NOERROR, 0))
+ goto free_return;
+
+ offset = match_first - mctx.input.raw_mbs_idx;
+ }
+ /* If MATCH_FIRST is out of the buffer, leave it as '\0'.
+ Note that MATCH_FIRST must not be smaller than 0. */
+ ch = (match_first >= length
+ ? 0 : re_string_byte_at (&mctx.input, offset));
+ if (fastmap[ch])
+ break;
+ match_first += incr;
+ if (match_first < left_lim || match_first > right_lim)
+ {
+ err = REG_NOMATCH;
+ goto free_return;
+ }
+ }
+ break;
+ }
+
+ /* Reconstruct the buffers so that the matcher can assume that
+ the matching starts from the beginning of the buffer. */
+ err = re_string_reconstruct (&mctx.input, match_first, eflags);
+ if (BE (err != REG_NOERROR, 0))
+ goto free_return;
+
+#ifdef RE_ENABLE_I18N
+ /* Don't consider this char as a possible match start if it part,
+ yet isn't the head, of a multibyte character. */
+ if (!sb && !re_string_first_byte (&mctx.input, 0))
+ continue;
+#endif
+
+ /* It seems to be appropriate one, then use the matcher. */
+ /* We assume that the matching starts from 0. */
+ mctx.state_log_top = mctx.nbkref_ents = mctx.max_mb_elem_len = 0;
+ match_last = check_matching (&mctx, fl_longest_match,
+ range >= 0 ? &match_first : NULL);
+ if (match_last != -1)
+ {
+ if (BE (match_last == -2, 0))
+ {
+ err = REG_ESPACE;
+ goto free_return;
+ }
+ else
+ {
+ mctx.match_last = match_last;
+ if ((!preg->no_sub && nmatch > 1) || dfa->nbackref)
+ {
+ re_dfastate_t *pstate = mctx.state_log[match_last];
+ mctx.last_node = check_halt_state_context (&mctx, pstate,
+ match_last);
+ }
+ if ((!preg->no_sub && nmatch > 1 && dfa->has_plural_match)
+ || dfa->nbackref)
+ {
+ err = prune_impossible_nodes (&mctx);
+ if (err == REG_NOERROR)
+ break;
+ if (BE (err != REG_NOMATCH, 0))
+ goto free_return;
+ match_last = -1;
+ }
+ else
+ break; /* We found a match. */
+ }
+ }
+
+ match_ctx_clean (&mctx);
+ }
+
+#ifdef DEBUG
+ assert (match_last != -1);
+ assert (err == REG_NOERROR);
+#endif
+
+ /* Set pmatch[] if we need. */
+ if (nmatch > 0)
+ {
+ int reg_idx;
+
+ /* Initialize registers. */
+ for (reg_idx = 1; reg_idx < nmatch; ++reg_idx)
+ pmatch[reg_idx].rm_so = pmatch[reg_idx].rm_eo = -1;
+
+ /* Set the points where matching start/end. */
+ pmatch[0].rm_so = 0;
+ pmatch[0].rm_eo = mctx.match_last;
+
+ if (!preg->no_sub && nmatch > 1)
+ {
+ err = set_regs (preg, &mctx, nmatch, pmatch,
+ dfa->has_plural_match && dfa->nbackref > 0);
+ if (BE (err != REG_NOERROR, 0))
+ goto free_return;
+ }
+
+ /* At last, add the offset to the each registers, since we slided
+ the buffers so that we could assume that the matching starts
+ from 0. */
+ for (reg_idx = 0; reg_idx < nmatch; ++reg_idx)
+ if (pmatch[reg_idx].rm_so != -1)
+ {
+#ifdef RE_ENABLE_I18N
+ if (BE (mctx.input.offsets_needed != 0, 0))
+ {
+ pmatch[reg_idx].rm_so =
+ (pmatch[reg_idx].rm_so == mctx.input.valid_len
+ ? mctx.input.valid_raw_len
+ : mctx.input.offsets[pmatch[reg_idx].rm_so]);
+ pmatch[reg_idx].rm_eo =
+ (pmatch[reg_idx].rm_eo == mctx.input.valid_len
+ ? mctx.input.valid_raw_len
+ : mctx.input.offsets[pmatch[reg_idx].rm_eo]);
+ }
+#else
+ assert (mctx.input.offsets_needed == 0);
+#endif
+ pmatch[reg_idx].rm_so += match_first;
+ pmatch[reg_idx].rm_eo += match_first;
+ }
+ for (reg_idx = 0; reg_idx < extra_nmatch; ++reg_idx)
+ {
+ pmatch[nmatch + reg_idx].rm_so = -1;
+ pmatch[nmatch + reg_idx].rm_eo = -1;
+ }
+
+ if (dfa->subexp_map)
+ for (reg_idx = 0; reg_idx + 1 < nmatch; reg_idx++)
+ if (dfa->subexp_map[reg_idx] != reg_idx)
+ {
+ pmatch[reg_idx + 1].rm_so
+ = pmatch[dfa->subexp_map[reg_idx] + 1].rm_so;
+ pmatch[reg_idx + 1].rm_eo
+ = pmatch[dfa->subexp_map[reg_idx] + 1].rm_eo;
+ }
+ }
+
+ free_return:
+ re_free (mctx.state_log);
+ if (dfa->nbackref)
+ match_ctx_free (&mctx);
+ re_string_destruct (&mctx.input);
+ return err;
+}
+
+static reg_errcode_t internal_function
+prune_impossible_nodes (re_match_context_t *mctx)
+{
+ const re_dfa_t *const dfa = mctx->dfa;
+ int halt_node, match_last;
+ reg_errcode_t ret;
+ re_dfastate_t **sifted_states;
+ re_dfastate_t **lim_states = NULL;
+ re_sift_context_t sctx;
+#ifdef DEBUG
+ assert (mctx->state_log != NULL);
+#endif
+ match_last = mctx->match_last;
+ halt_node = mctx->last_node;
+ sifted_states = re_malloc (re_dfastate_t *, match_last + 1);
+ if (BE (sifted_states == NULL, 0))
+ {
+ ret = REG_ESPACE;
+ goto free_return;
+ }
+ if (dfa->nbackref)
+ {
+ lim_states = re_malloc (re_dfastate_t *, match_last + 1);
+ if (BE (lim_states == NULL, 0))
+ {
+ ret = REG_ESPACE;
+ goto free_return;
+ }
+ while (1)
+ {
+ memset (lim_states, '\0',
+ sizeof (re_dfastate_t *) * (match_last + 1));
+ sift_ctx_init (&sctx, sifted_states, lim_states, halt_node,
+ match_last);
+ ret = sift_states_backward (mctx, &sctx);
+ re_node_set_free (&sctx.limits);
+ if (BE (ret != REG_NOERROR, 0))
+ goto free_return;
+ if (sifted_states[0] != NULL || lim_states[0] != NULL)
+ break;
+ do
+ {
+ --match_last;
+ if (match_last < 0)
+ {
+ ret = REG_NOMATCH;
+ goto free_return;
+ }
+ } while (mctx->state_log[match_last] == NULL
+ || !mctx->state_log[match_last]->halt);
+ halt_node = check_halt_state_context (mctx,
+ mctx->state_log[match_last],
+ match_last);
+ }
+ ret = merge_state_array (dfa, sifted_states, lim_states,
+ match_last + 1);
+ re_free (lim_states);
+ lim_states = NULL;
+ if (BE (ret != REG_NOERROR, 0))
+ goto free_return;
+ }
+ else
+ {
+ sift_ctx_init (&sctx, sifted_states, lim_states, halt_node, match_last);
+ ret = sift_states_backward (mctx, &sctx);
+ re_node_set_free (&sctx.limits);
+ if (BE (ret != REG_NOERROR, 0))
+ goto free_return;
+ }
+ re_free (mctx->state_log);
+ mctx->state_log = sifted_states;
+ sifted_states = NULL;
+ mctx->last_node = halt_node;
+ mctx->match_last = match_last;
+ ret = REG_NOERROR;
+ free_return:
+ re_free (sifted_states);
+ re_free (lim_states);
+ return ret;
+}
+
+/* Acquire an initial state and return it.
+ We must select appropriate initial state depending on the context,
+ since initial states may have constraints like "\<", "^", etc.. */
+
+static __inline__ re_dfastate_t *
+__attribute ((always_inline)) internal_function
+acquire_init_state_context (reg_errcode_t *err, const re_match_context_t *mctx,
+ int idx)
+{
+ const re_dfa_t *const dfa = mctx->dfa;
+ if (dfa->init_state->has_constraint)
+ {
+ unsigned int context;
+ context = re_string_context_at (&mctx->input, idx - 1, mctx->eflags);
+ if (IS_WORD_CONTEXT (context))
+ return dfa->init_state_word;
+ else if (IS_ORDINARY_CONTEXT (context))
+ return dfa->init_state;
+ else if (IS_BEGBUF_CONTEXT (context) && IS_NEWLINE_CONTEXT (context))
+ return dfa->init_state_begbuf;
+ else if (IS_NEWLINE_CONTEXT (context))
+ return dfa->init_state_nl;
+ else if (IS_BEGBUF_CONTEXT (context))
+ {
+ /* It is relatively rare case, then calculate on demand. */
+ return re_acquire_state_context (err, dfa,
+ dfa->init_state->entrance_nodes,
+ context);
+ }
+ else
+ /* Must not happen? */
+ return dfa->init_state;
+ }
+ else
+ return dfa->init_state;
+}
+
+/* Check whether the regular expression match input string INPUT or not,
+ and return the index where the matching end, return -1 if not match,
+ or return -2 in case of an error.
+ FL_LONGEST_MATCH means we want the POSIX longest matching.
+ If P_MATCH_FIRST is not NULL, and the match fails, it is set to the
+ next place where we may want to try matching.
+ Note that the matcher assume that the maching starts from the current
+ index of the buffer. */
+
+static int
+internal_function
+check_matching (re_match_context_t *mctx, int fl_longest_match,
+ int *p_match_first)
+{
+ const re_dfa_t *const dfa = mctx->dfa;
+ reg_errcode_t err;
+ int match = 0;
+ int match_last = -1;
+ int cur_str_idx = re_string_cur_idx (&mctx->input);
+ re_dfastate_t *cur_state;
+ int at_init_state = p_match_first != NULL;
+ int next_start_idx = cur_str_idx;
+
+ err = REG_NOERROR;
+ cur_state = acquire_init_state_context (&err, mctx, cur_str_idx);
+ /* An initial state must not be NULL (invalid). */
+ if (BE (cur_state == NULL, 0))
+ {
+ assert (err == REG_ESPACE);
+ return -2;
+ }
+
+ if (mctx->state_log != NULL)
+ {
+ mctx->state_log[cur_str_idx] = cur_state;
+
+ /* Check OP_OPEN_SUBEXP in the initial state in case that we use them
+ later. E.g. Processing back references. */
+ if (BE (dfa->nbackref, 0))
+ {
+ at_init_state = 0;
+ err = check_subexp_matching_top (mctx, &cur_state->nodes, 0);
+ if (BE (err != REG_NOERROR, 0))
+ return err;
+
+ if (cur_state->has_backref)
+ {
+ err = transit_state_bkref (mctx, &cur_state->nodes);
+ if (BE (err != REG_NOERROR, 0))
+ return err;
+ }
+ }
+ }
+
+ /* If the RE accepts NULL string. */
+ if (BE (cur_state->halt, 0))
+ {
+ if (!cur_state->has_constraint
+ || check_halt_state_context (mctx, cur_state, cur_str_idx))
+ {
+ if (!fl_longest_match)
+ return cur_str_idx;
+ else
+ {
+ match_last = cur_str_idx;
+ match = 1;
+ }
+ }
+ }
+
+ while (!re_string_eoi (&mctx->input))
+ {
+ re_dfastate_t *old_state = cur_state;
+ int next_char_idx = re_string_cur_idx (&mctx->input) + 1;
+
+ if (BE (next_char_idx >= mctx->input.bufs_len, 0)
+ || (BE (next_char_idx >= mctx->input.valid_len, 0)
+ && mctx->input.valid_len < mctx->input.len))
+ {
+ err = extend_buffers (mctx);
+ if (BE (err != REG_NOERROR, 0))
+ {
+ assert (err == REG_ESPACE);
+ return -2;
+ }
+ }
+
+ cur_state = transit_state (&err, mctx, cur_state);
+ if (mctx->state_log != NULL)
+ cur_state = merge_state_with_log (&err, mctx, cur_state);
+
+ if (cur_state == NULL)
+ {
+ /* Reached the invalid state or an error. Try to recover a valid
+ state using the state log, if available and if we have not
+ already found a valid (even if not the longest) match. */
+ if (BE (err != REG_NOERROR, 0))
+ return -2;
+
+ if (mctx->state_log == NULL
+ || (match && !fl_longest_match)
+ || (cur_state = find_recover_state (&err, mctx)) == NULL)
+ break;
+ }
+
+ if (BE (at_init_state, 0))
+ {
+ if (old_state == cur_state)
+ next_start_idx = next_char_idx;
+ else
+ at_init_state = 0;
+ }
+
+ if (cur_state->halt)
+ {
+ /* Reached a halt state.
+ Check the halt state can satisfy the current context. */
+ if (!cur_state->has_constraint
+ || check_halt_state_context (mctx, cur_state,
+ re_string_cur_idx (&mctx->input)))
+ {
+ /* We found an appropriate halt state. */
+ match_last = re_string_cur_idx (&mctx->input);
+ match = 1;
+
+ /* We found a match, do not modify match_first below. */
+ p_match_first = NULL;
+ if (!fl_longest_match)
+ break;
+ }
+ }
+ }
+
+ if (p_match_first)
+ *p_match_first += next_start_idx;
+
+ return match_last;
+}
+
+/* Check NODE match the current context. */
+
+static int
+internal_function
+check_halt_node_context (const re_dfa_t *dfa, int node, unsigned int context)
+{
+ re_token_type_t type = dfa->nodes[node].type;
+ unsigned int constraint = dfa->nodes[node].constraint;
+ if (type != END_OF_RE)
+ return 0;
+ if (!constraint)
+ return 1;
+ if (NOT_SATISFY_NEXT_CONSTRAINT (constraint, context))
+ return 0;
+ return 1;
+}
+
+/* Check the halt state STATE match the current context.
+ Return 0 if not match, if the node, STATE has, is a halt node and
+ match the context, return the node. */
+
+static int
+internal_function
+check_halt_state_context (const re_match_context_t *mctx,
+ const re_dfastate_t *state, int idx)
+{
+ int i;
+ unsigned int context;
+#ifdef DEBUG
+ assert (state->halt);
+#endif
+ context = re_string_context_at (&mctx->input, idx, mctx->eflags);
+ for (i = 0; i < state->nodes.nelem; ++i)
+ if (check_halt_node_context (mctx->dfa, state->nodes.elems[i], context))
+ return state->nodes.elems[i];
+ return 0;
+}
+
+/* Compute the next node to which "NFA" transit from NODE("NFA" is a NFA
+ corresponding to the DFA).
+ Return the destination node, and update EPS_VIA_NODES, return -1 in case
+ of errors. */
+
+static int
+internal_function
+proceed_next_node (const re_match_context_t *mctx, int nregs, regmatch_t *regs,
+ int *pidx, int node, re_node_set *eps_via_nodes,
+ struct re_fail_stack_t *fs)
+{
+ const re_dfa_t *const dfa = mctx->dfa;
+ int i, err;
+ if (IS_EPSILON_NODE (dfa->nodes[node].type))
+ {
+ re_node_set *cur_nodes = &mctx->state_log[*pidx]->nodes;
+ re_node_set *edests = &dfa->edests[node];
+ int dest_node;
+ err = re_node_set_insert (eps_via_nodes, node);
+ if (BE (err < 0, 0))
+ return -2;
+ /* Pick up a valid destination, or return -1 if none is found. */
+ for (dest_node = -1, i = 0; i < edests->nelem; ++i)
+ {
+ int candidate = edests->elems[i];
+ if (!re_node_set_contains (cur_nodes, candidate))
+ continue;
+ if (dest_node == -1)
+ dest_node = candidate;
+
+ else
+ {
+ /* In order to avoid infinite loop like "(a*)*", return the second
+ epsilon-transition if the first was already considered. */
+ if (re_node_set_contains (eps_via_nodes, dest_node))
+ return candidate;
+
+ /* Otherwise, push the second epsilon-transition on the fail stack. */
+ else if (fs != NULL
+ && push_fail_stack (fs, *pidx, candidate, nregs, regs,
+ eps_via_nodes))
+ return -2;
+
+ /* We know we are going to exit. */
+ break;
+ }
+ }
+ return dest_node;
+ }
+ else
+ {
+ int naccepted = 0;
+ re_token_type_t type = dfa->nodes[node].type;
+
+#ifdef RE_ENABLE_I18N
+ if (dfa->nodes[node].accept_mb)
+ naccepted = check_node_accept_bytes (dfa, node, &mctx->input, *pidx);
+ else
+#endif /* RE_ENABLE_I18N */
+ if (type == OP_BACK_REF)
+ {
+ int subexp_idx = dfa->nodes[node].opr.idx + 1;
+ naccepted = regs[subexp_idx].rm_eo - regs[subexp_idx].rm_so;
+ if (fs != NULL)
+ {
+ if (regs[subexp_idx].rm_so == -1 || regs[subexp_idx].rm_eo == -1)
+ return -1;
+ else if (naccepted)
+ {
+ char *buf = (char *) re_string_get_buffer (&mctx->input);
+ if (memcmp (buf + regs[subexp_idx].rm_so, buf + *pidx,
+ naccepted) != 0)
+ return -1;
+ }
+ }
+
+ if (naccepted == 0)
+ {
+ int dest_node;
+ err = re_node_set_insert (eps_via_nodes, node);
+ if (BE (err < 0, 0))
+ return -2;
+ dest_node = dfa->edests[node].elems[0];
+ if (re_node_set_contains (&mctx->state_log[*pidx]->nodes,
+ dest_node))
+ return dest_node;
+ }
+ }
+
+ if (naccepted != 0
+ || check_node_accept (mctx, dfa->nodes + node, *pidx))
+ {
+ int dest_node = dfa->nexts[node];
+ *pidx = (naccepted == 0) ? *pidx + 1 : *pidx + naccepted;
+ if (fs && (*pidx > mctx->match_last || mctx->state_log[*pidx] == NULL
+ || !re_node_set_contains (&mctx->state_log[*pidx]->nodes,
+ dest_node)))
+ return -1;
+ re_node_set_empty (eps_via_nodes);
+ return dest_node;
+ }
+ }
+ return -1;
+}
+
+static reg_errcode_t
+internal_function
+push_fail_stack (struct re_fail_stack_t *fs, int str_idx, int dest_node,
+ int nregs, regmatch_t *regs, re_node_set *eps_via_nodes)
+{
+ reg_errcode_t err;
+ int num = fs->num++;
+ if (fs->num == fs->alloc)
+ {
+ struct re_fail_stack_ent_t *new_array;
+ new_array = realloc (fs->stack, (sizeof (struct re_fail_stack_ent_t)
+ * fs->alloc * 2));
+ if (new_array == NULL)
+ return REG_ESPACE;
+ fs->alloc *= 2;
+ fs->stack = new_array;
+ }
+ fs->stack[num].idx = str_idx;
+ fs->stack[num].node = dest_node;
+ fs->stack[num].regs = re_malloc (regmatch_t, nregs);
+ if (fs->stack[num].regs == NULL)
+ return REG_ESPACE;
+ memcpy (fs->stack[num].regs, regs, sizeof (regmatch_t) * nregs);
+ err = re_node_set_init_copy (&fs->stack[num].eps_via_nodes, eps_via_nodes);
+ return err;
+}
+
+static int
+internal_function
+pop_fail_stack (struct re_fail_stack_t *fs, int *pidx, int nregs,
+ regmatch_t *regs, re_node_set *eps_via_nodes)
+{
+ int num = --fs->num;
+ assert (num >= 0);
+ *pidx = fs->stack[num].idx;
+ memcpy (regs, fs->stack[num].regs, sizeof (regmatch_t) * nregs);
+ re_node_set_free (eps_via_nodes);
+ re_free (fs->stack[num].regs);
+ *eps_via_nodes = fs->stack[num].eps_via_nodes;
+ return fs->stack[num].node;
+}
+
+/* Set the positions where the subexpressions are starts/ends to registers
+ PMATCH.
+ Note: We assume that pmatch[0] is already set, and
+ pmatch[i].rm_so == pmatch[i].rm_eo == -1 for 0 < i < nmatch. */
+
+static reg_errcode_t
+internal_function
+set_regs (const regex_t *preg, const re_match_context_t *mctx, size_t nmatch,
+ regmatch_t *pmatch, int fl_backtrack)
+{
+ const re_dfa_t *dfa = (const re_dfa_t *) preg->buffer;
+ int idx, cur_node;
+ re_node_set eps_via_nodes;
+ struct re_fail_stack_t *fs;
+ struct re_fail_stack_t fs_body = { 0, 2, NULL };
+ regmatch_t *prev_idx_match;
+ int prev_idx_match_malloced = 0;
+
+#ifdef DEBUG
+ assert (nmatch > 1);
+ assert (mctx->state_log != NULL);
+#endif
+ if (fl_backtrack)
+ {
+ fs = &fs_body;
+ fs->stack = re_malloc (struct re_fail_stack_ent_t, fs->alloc);
+ if (fs->stack == NULL)
+ return REG_ESPACE;
+ }
+ else
+ fs = NULL;
+
+ cur_node = dfa->init_node;
+ re_node_set_init_empty (&eps_via_nodes);
+
+ if (__libc_use_alloca (nmatch * sizeof (regmatch_t)))
+ prev_idx_match = (regmatch_t *) alloca (nmatch * sizeof (regmatch_t));
+ else
+ {
+ prev_idx_match = re_malloc (regmatch_t, nmatch);
+ if (prev_idx_match == NULL)
+ {
+ free_fail_stack_return (fs);
+ return REG_ESPACE;
+ }
+ prev_idx_match_malloced = 1;
+ }
+ memcpy (prev_idx_match, pmatch, sizeof (regmatch_t) * nmatch);
+
+ for (idx = pmatch[0].rm_so; idx <= pmatch[0].rm_eo ;)
+ {
+ update_regs (dfa, pmatch, prev_idx_match, cur_node, idx, nmatch);
+
+ if (idx == pmatch[0].rm_eo && cur_node == mctx->last_node)
+ {
+ int reg_idx;
+ if (fs)
+ {
+ for (reg_idx = 0; reg_idx < nmatch; ++reg_idx)
+ if (pmatch[reg_idx].rm_so > -1 && pmatch[reg_idx].rm_eo == -1)
+ break;
+ if (reg_idx == nmatch)
+ {
+ re_node_set_free (&eps_via_nodes);
+ if (prev_idx_match_malloced)
+ re_free (prev_idx_match);
+ return free_fail_stack_return (fs);
+ }
+ cur_node = pop_fail_stack (fs, &idx, nmatch, pmatch,
+ &eps_via_nodes);
+ }
+ else
+ {
+ re_node_set_free (&eps_via_nodes);
+ if (prev_idx_match_malloced)
+ re_free (prev_idx_match);
+ return REG_NOERROR;
+ }
+ }
+
+ /* Proceed to next node. */
+ cur_node = proceed_next_node (mctx, nmatch, pmatch, &idx, cur_node,
+ &eps_via_nodes, fs);
+
+ if (BE (cur_node < 0, 0))
+ {
+ if (BE (cur_node == -2, 0))
+ {
+ re_node_set_free (&eps_via_nodes);
+ if (prev_idx_match_malloced)
+ re_free (prev_idx_match);
+ free_fail_stack_return (fs);
+ return REG_ESPACE;
+ }
+ if (fs)
+ cur_node = pop_fail_stack (fs, &idx, nmatch, pmatch,
+ &eps_via_nodes);
+ else
+ {
+ re_node_set_free (&eps_via_nodes);
+ if (prev_idx_match_malloced)
+ re_free (prev_idx_match);
+ return REG_NOMATCH;
+ }
+ }
+ }
+ re_node_set_free (&eps_via_nodes);
+ if (prev_idx_match_malloced)
+ re_free (prev_idx_match);
+ return free_fail_stack_return (fs);
+}
+
+static reg_errcode_t
+internal_function
+free_fail_stack_return (struct re_fail_stack_t *fs)
+{
+ if (fs)
+ {
+ int fs_idx;
+ for (fs_idx = 0; fs_idx < fs->num; ++fs_idx)
+ {
+ re_node_set_free (&fs->stack[fs_idx].eps_via_nodes);
+ re_free (fs->stack[fs_idx].regs);
+ }
+ re_free (fs->stack);
+ }
+ return REG_NOERROR;
+}
+
+static void
+internal_function
+update_regs (const re_dfa_t *dfa, regmatch_t *pmatch,
+ regmatch_t *prev_idx_match, int cur_node, int cur_idx, int nmatch)
+{
+ int type = dfa->nodes[cur_node].type;
+ if (type == OP_OPEN_SUBEXP)
+ {
+ int reg_num = dfa->nodes[cur_node].opr.idx + 1;
+
+ /* We are at the first node of this sub expression. */
+ if (reg_num < nmatch)
+ {
+ pmatch[reg_num].rm_so = cur_idx;
+ pmatch[reg_num].rm_eo = -1;
+ }
+ }
+ else if (type == OP_CLOSE_SUBEXP)
+ {
+ int reg_num = dfa->nodes[cur_node].opr.idx + 1;
+ if (reg_num < nmatch)
+ {
+ /* We are at the last node of this sub expression. */
+ if (pmatch[reg_num].rm_so < cur_idx)
+ {
+ pmatch[reg_num].rm_eo = cur_idx;
+ /* This is a non-empty match or we are not inside an optional
+ subexpression. Accept this right away. */
+ memcpy (prev_idx_match, pmatch, sizeof (regmatch_t) * nmatch);
+ }
+ else
+ {
+ if (dfa->nodes[cur_node].opt_subexp
+ && prev_idx_match[reg_num].rm_so != -1)
+ /* We transited through an empty match for an optional
+ subexpression, like (a?)*, and this is not the subexp's
+ first match. Copy back the old content of the registers
+ so that matches of an inner subexpression are undone as
+ well, like in ((a?))*. */
+ memcpy (pmatch, prev_idx_match, sizeof (regmatch_t) * nmatch);
+ else
+ /* We completed a subexpression, but it may be part of
+ an optional one, so do not update PREV_IDX_MATCH. */
+ pmatch[reg_num].rm_eo = cur_idx;
+ }
+ }
+ }
+}
+
+/* This function checks the STATE_LOG from the SCTX->last_str_idx to 0
+ and sift the nodes in each states according to the following rules.
+ Updated state_log will be wrote to STATE_LOG.
+
+ Rules: We throw away the Node `a' in the STATE_LOG[STR_IDX] if...
+ 1. When STR_IDX == MATCH_LAST(the last index in the state_log):
+ If `a' isn't the LAST_NODE and `a' can't epsilon transit to
+ the LAST_NODE, we throw away the node `a'.
+ 2. When 0 <= STR_IDX < MATCH_LAST and `a' accepts
+ string `s' and transit to `b':
+ i. If 'b' isn't in the STATE_LOG[STR_IDX+strlen('s')], we throw
+ away the node `a'.
+ ii. If 'b' is in the STATE_LOG[STR_IDX+strlen('s')] but 'b' is
+ thrown away, we throw away the node `a'.
+ 3. When 0 <= STR_IDX < MATCH_LAST and 'a' epsilon transit to 'b':
+ i. If 'b' isn't in the STATE_LOG[STR_IDX], we throw away the
+ node `a'.
+ ii. If 'b' is in the STATE_LOG[STR_IDX] but 'b' is thrown away,
+ we throw away the node `a'. */
+
+#define STATE_NODE_CONTAINS(state,node) \
+ ((state) != NULL && re_node_set_contains (&(state)->nodes, node))
+
+static reg_errcode_t
+internal_function
+sift_states_backward (const re_match_context_t *mctx, re_sift_context_t *sctx)
+{
+ reg_errcode_t err;
+ int null_cnt = 0;
+ int str_idx = sctx->last_str_idx;
+ re_node_set cur_dest;
+
+#ifdef DEBUG
+ assert (mctx->state_log != NULL && mctx->state_log[str_idx] != NULL);
+#endif
+
+ /* Build sifted state_log[str_idx]. It has the nodes which can epsilon
+ transit to the last_node and the last_node itself. */
+ err = re_node_set_init_1 (&cur_dest, sctx->last_node);
+ if (BE (err != REG_NOERROR, 0))
+ return err;
+ err = update_cur_sifted_state (mctx, sctx, str_idx, &cur_dest);
+ if (BE (err != REG_NOERROR, 0))
+ goto free_return;
+
+ /* Then check each states in the state_log. */
+ while (str_idx > 0)
+ {
+ /* Update counters. */
+ null_cnt = (sctx->sifted_states[str_idx] == NULL) ? null_cnt + 1 : 0;
+ if (null_cnt > mctx->max_mb_elem_len)
+ {
+ memset (sctx->sifted_states, '\0',
+ sizeof (re_dfastate_t *) * str_idx);
+ re_node_set_free (&cur_dest);
+ return REG_NOERROR;
+ }
+ re_node_set_empty (&cur_dest);
+ --str_idx;
+
+ if (mctx->state_log[str_idx])
+ {
+ err = build_sifted_states (mctx, sctx, str_idx, &cur_dest);
+ if (BE (err != REG_NOERROR, 0))
+ goto free_return;
+ }
+
+ /* Add all the nodes which satisfy the following conditions:
+ - It can epsilon transit to a node in CUR_DEST.
+ - It is in CUR_SRC.
+ And update state_log. */
+ err = update_cur_sifted_state (mctx, sctx, str_idx, &cur_dest);
+ if (BE (err != REG_NOERROR, 0))
+ goto free_return;
+ }
+ err = REG_NOERROR;
+ free_return:
+ re_node_set_free (&cur_dest);
+ return err;
+}
+
+static reg_errcode_t
+internal_function
+build_sifted_states (const re_match_context_t *mctx, re_sift_context_t *sctx,
+ int str_idx, re_node_set *cur_dest)
+{
+ const re_dfa_t *const dfa = mctx->dfa;
+ const re_node_set *cur_src = &mctx->state_log[str_idx]->non_eps_nodes;
+ int i;
+
+ /* Then build the next sifted state.
+ We build the next sifted state on `cur_dest', and update
+ `sifted_states[str_idx]' with `cur_dest'.
+ Note:
+ `cur_dest' is the sifted state from `state_log[str_idx + 1]'.
+ `cur_src' points the node_set of the old `state_log[str_idx]'
+ (with the epsilon nodes pre-filtered out). */
+ for (i = 0; i < cur_src->nelem; i++)
+ {
+ int prev_node = cur_src->elems[i];
+ int naccepted = 0;
+ int ret;
+
+#ifdef DEBUG
+ re_token_type_t type = dfa->nodes[prev_node].type;
+ assert (!IS_EPSILON_NODE (type));
+#endif
+#ifdef RE_ENABLE_I18N
+ /* If the node may accept `multi byte'. */
+ if (dfa->nodes[prev_node].accept_mb)
+ naccepted = sift_states_iter_mb (mctx, sctx, prev_node,
+ str_idx, sctx->last_str_idx);
+#endif /* RE_ENABLE_I18N */
+
+ /* We don't check backreferences here.
+ See update_cur_sifted_state(). */
+ if (!naccepted
+ && check_node_accept (mctx, dfa->nodes + prev_node, str_idx)
+ && STATE_NODE_CONTAINS (sctx->sifted_states[str_idx + 1],
+ dfa->nexts[prev_node]))
+ naccepted = 1;
+
+ if (naccepted == 0)
+ continue;
+
+ if (sctx->limits.nelem)
+ {
+ int to_idx = str_idx + naccepted;
+ if (check_dst_limits (mctx, &sctx->limits,
+ dfa->nexts[prev_node], to_idx,
+ prev_node, str_idx))
+ continue;
+ }
+ ret = re_node_set_insert (cur_dest, prev_node);
+ if (BE (ret == -1, 0))
+ return REG_ESPACE;
+ }
+
+ return REG_NOERROR;
+}
+
+/* Helper functions. */
+
+static reg_errcode_t
+internal_function
+clean_state_log_if_needed (re_match_context_t *mctx, int next_state_log_idx)
+{
+ int top = mctx->state_log_top;
+
+ if (next_state_log_idx >= mctx->input.bufs_len
+ || (next_state_log_idx >= mctx->input.valid_len
+ && mctx->input.valid_len < mctx->input.len))
+ {
+ reg_errcode_t err;
+ err = extend_buffers (mctx);
+ if (BE (err != REG_NOERROR, 0))
+ return err;
+ }
+
+ if (top < next_state_log_idx)
+ {
+ memset (mctx->state_log + top + 1, '\0',
+ sizeof (re_dfastate_t *) * (next_state_log_idx - top));
+ mctx->state_log_top = next_state_log_idx;
+ }
+ return REG_NOERROR;
+}
+
+static reg_errcode_t
+internal_function
+merge_state_array (const re_dfa_t *dfa, re_dfastate_t **dst,
+ re_dfastate_t **src, int num)
+{
+ int st_idx;
+ reg_errcode_t err;
+ for (st_idx = 0; st_idx < num; ++st_idx)
+ {
+ if (dst[st_idx] == NULL)
+ dst[st_idx] = src[st_idx];
+ else if (src[st_idx] != NULL)
+ {
+ re_node_set merged_set;
+ err = re_node_set_init_union (&merged_set, &dst[st_idx]->nodes,
+ &src[st_idx]->nodes);
+ if (BE (err != REG_NOERROR, 0))
+ return err;
+ dst[st_idx] = re_acquire_state (&err, dfa, &merged_set);
+ re_node_set_free (&merged_set);
+ if (BE (err != REG_NOERROR, 0))
+ return err;
+ }
+ }
+ return REG_NOERROR;
+}
+
+static reg_errcode_t
+internal_function
+update_cur_sifted_state (const re_match_context_t *mctx,
+ re_sift_context_t *sctx, int str_idx,
+ re_node_set *dest_nodes)
+{
+ const re_dfa_t *const dfa = mctx->dfa;
+ reg_errcode_t err = REG_NOERROR;
+ const re_node_set *candidates;
+ candidates = ((mctx->state_log[str_idx] == NULL) ? NULL
+ : &mctx->state_log[str_idx]->nodes);
+
+ if (dest_nodes->nelem == 0)
+ sctx->sifted_states[str_idx] = NULL;
+ else
+ {
+ if (candidates)
+ {
+ /* At first, add the nodes which can epsilon transit to a node in
+ DEST_NODE. */
+ err = add_epsilon_src_nodes (dfa, dest_nodes, candidates);
+ if (BE (err != REG_NOERROR, 0))
+ return err;
+
+ /* Then, check the limitations in the current sift_context. */
+ if (sctx->limits.nelem)
+ {
+ err = check_subexp_limits (dfa, dest_nodes, candidates, &sctx->limits,
+ mctx->bkref_ents, str_idx);
+ if (BE (err != REG_NOERROR, 0))
+ return err;
+ }
+ }
+
+ sctx->sifted_states[str_idx] = re_acquire_state (&err, dfa, dest_nodes);
+ if (BE (err != REG_NOERROR, 0))
+ return err;
+ }
+
+ if (candidates && mctx->state_log[str_idx]->has_backref)
+ {
+ err = sift_states_bkref (mctx, sctx, str_idx, candidates);
+ if (BE (err != REG_NOERROR, 0))
+ return err;
+ }
+ return REG_NOERROR;
+}
+
+static reg_errcode_t
+internal_function
+add_epsilon_src_nodes (const re_dfa_t *dfa, re_node_set *dest_nodes,
+ const re_node_set *candidates)
+{
+ reg_errcode_t err = REG_NOERROR;
+ int i;
+
+ re_dfastate_t *state = re_acquire_state (&err, dfa, dest_nodes);
+ if (BE (err != REG_NOERROR, 0))
+ return err;
+
+ if (!state->inveclosure.alloc)
+ {
+ err = re_node_set_alloc (&state->inveclosure, dest_nodes->nelem);
+ if (BE (err != REG_NOERROR, 0))
+ return REG_ESPACE;
+ for (i = 0; i < dest_nodes->nelem; i++)
+ re_node_set_merge (&state->inveclosure,
+ dfa->inveclosures + dest_nodes->elems[i]);
+ }
+ return re_node_set_add_intersect (dest_nodes, candidates,
+ &state->inveclosure);
+}
+
+static reg_errcode_t
+internal_function
+sub_epsilon_src_nodes (const re_dfa_t *dfa, int node, re_node_set *dest_nodes,
+ const re_node_set *candidates)
+{
+ int ecl_idx;
+ reg_errcode_t err;
+ re_node_set *inv_eclosure = dfa->inveclosures + node;
+ re_node_set except_nodes;
+ re_node_set_init_empty (&except_nodes);
+ for (ecl_idx = 0; ecl_idx < inv_eclosure->nelem; ++ecl_idx)
+ {
+ int cur_node = inv_eclosure->elems[ecl_idx];
+ if (cur_node == node)
+ continue;
+ if (IS_EPSILON_NODE (dfa->nodes[cur_node].type))
+ {
+ int edst1 = dfa->edests[cur_node].elems[0];
+ int edst2 = ((dfa->edests[cur_node].nelem > 1)
+ ? dfa->edests[cur_node].elems[1] : -1);
+ if ((!re_node_set_contains (inv_eclosure, edst1)
+ && re_node_set_contains (dest_nodes, edst1))
+ || (edst2 > 0
+ && !re_node_set_contains (inv_eclosure, edst2)
+ && re_node_set_contains (dest_nodes, edst2)))
+ {
+ err = re_node_set_add_intersect (&except_nodes, candidates,
+ dfa->inveclosures + cur_node);
+ if (BE (err != REG_NOERROR, 0))
+ {
+ re_node_set_free (&except_nodes);
+ return err;
+ }
+ }
+ }
+ }
+ for (ecl_idx = 0; ecl_idx < inv_eclosure->nelem; ++ecl_idx)
+ {
+ int cur_node = inv_eclosure->elems[ecl_idx];
+ if (!re_node_set_contains (&except_nodes, cur_node))
+ {
+ int idx = re_node_set_contains (dest_nodes, cur_node) - 1;
+ re_node_set_remove_at (dest_nodes, idx);
+ }
+ }
+ re_node_set_free (&except_nodes);
+ return REG_NOERROR;
+}
+
+static int
+internal_function
+check_dst_limits (const re_match_context_t *mctx, re_node_set *limits,
+ int dst_node, int dst_idx, int src_node, int src_idx)
+{
+ const re_dfa_t *const dfa = mctx->dfa;
+ int lim_idx, src_pos, dst_pos;
+
+ int dst_bkref_idx = search_cur_bkref_entry (mctx, dst_idx);
+ int src_bkref_idx = search_cur_bkref_entry (mctx, src_idx);
+ for (lim_idx = 0; lim_idx < limits->nelem; ++lim_idx)
+ {
+ int subexp_idx;
+ struct re_backref_cache_entry *ent;
+ ent = mctx->bkref_ents + limits->elems[lim_idx];
+ subexp_idx = dfa->nodes[ent->node].opr.idx;
+
+ dst_pos = check_dst_limits_calc_pos (mctx, limits->elems[lim_idx],
+ subexp_idx, dst_node, dst_idx,
+ dst_bkref_idx);
+ src_pos = check_dst_limits_calc_pos (mctx, limits->elems[lim_idx],
+ subexp_idx, src_node, src_idx,
+ src_bkref_idx);
+
+ /* In case of:
+ <src> <dst> ( <subexp> )
+ ( <subexp> ) <src> <dst>
+ ( <subexp1> <src> <subexp2> <dst> <subexp3> ) */
+ if (src_pos == dst_pos)
+ continue; /* This is unrelated limitation. */
+ else
+ return 1;
+ }
+ return 0;
+}
+
+static int
+internal_function
+check_dst_limits_calc_pos_1 (const re_match_context_t *mctx, int boundaries,
+ int subexp_idx, int from_node, int bkref_idx)
+{
+ const re_dfa_t *const dfa = mctx->dfa;
+ const re_node_set *eclosures = dfa->eclosures + from_node;
+ int node_idx;
+
+ /* Else, we are on the boundary: examine the nodes on the epsilon
+ closure. */
+ for (node_idx = 0; node_idx < eclosures->nelem; ++node_idx)
+ {
+ int node = eclosures->elems[node_idx];
+ switch (dfa->nodes[node].type)
+ {
+ case OP_BACK_REF:
+ if (bkref_idx != -1)
+ {
+ struct re_backref_cache_entry *ent = mctx->bkref_ents + bkref_idx;
+ do
+ {
+ int dst, cpos;
+
+ if (ent->node != node)
+ continue;
+
+ if (subexp_idx < BITSET_WORD_BITS
+ && !(ent->eps_reachable_subexps_map
+ & ((bitset_word_t) 1 << subexp_idx)))
+ continue;
+
+ /* Recurse trying to reach the OP_OPEN_SUBEXP and
+ OP_CLOSE_SUBEXP cases below. But, if the
+ destination node is the same node as the source
+ node, don't recurse because it would cause an
+ infinite loop: a regex that exhibits this behavior
+ is ()\1*\1* */
+ dst = dfa->edests[node].elems[0];
+ if (dst == from_node)
+ {
+ if (boundaries & 1)
+ return -1;
+ else /* if (boundaries & 2) */
+ return 0;
+ }
+
+ cpos =
+ check_dst_limits_calc_pos_1 (mctx, boundaries, subexp_idx,
+ dst, bkref_idx);
+ if (cpos == -1 /* && (boundaries & 1) */)
+ return -1;
+ if (cpos == 0 && (boundaries & 2))
+ return 0;
+
+ if (subexp_idx < BITSET_WORD_BITS)
+ ent->eps_reachable_subexps_map
+ &= ~((bitset_word_t) 1 << subexp_idx);
+ }
+ while (ent++->more);
+ }
+ break;
+
+ case OP_OPEN_SUBEXP:
+ if ((boundaries & 1) && subexp_idx == dfa->nodes[node].opr.idx)
+ return -1;
+ break;
+
+ case OP_CLOSE_SUBEXP:
+ if ((boundaries & 2) && subexp_idx == dfa->nodes[node].opr.idx)
+ return 0;
+ break;
+
+ default:
+ break;
+ }
+ }
+
+ return (boundaries & 2) ? 1 : 0;
+}
+
+static int
+internal_function
+check_dst_limits_calc_pos (const re_match_context_t *mctx, int limit,
+ int subexp_idx, int from_node, int str_idx,
+ int bkref_idx)
+{
+ struct re_backref_cache_entry *lim = mctx->bkref_ents + limit;
+ int boundaries;
+
+ /* If we are outside the range of the subexpression, return -1 or 1. */
+ if (str_idx < lim->subexp_from)
+ return -1;
+
+ if (lim->subexp_to < str_idx)
+ return 1;
+
+ /* If we are within the subexpression, return 0. */
+ boundaries = (str_idx == lim->subexp_from);
+ boundaries |= (str_idx == lim->subexp_to) << 1;
+ if (boundaries == 0)
+ return 0;
+
+ /* Else, examine epsilon closure. */
+ return check_dst_limits_calc_pos_1 (mctx, boundaries, subexp_idx,
+ from_node, bkref_idx);
+}
+
+/* Check the limitations of sub expressions LIMITS, and remove the nodes
+ which are against limitations from DEST_NODES. */
+
+static reg_errcode_t
+internal_function
+check_subexp_limits (const re_dfa_t *dfa, re_node_set *dest_nodes,
+ const re_node_set *candidates, re_node_set *limits,
+ struct re_backref_cache_entry *bkref_ents, int str_idx)
+{
+ reg_errcode_t err;
+ int node_idx, lim_idx;
+
+ for (lim_idx = 0; lim_idx < limits->nelem; ++lim_idx)
+ {
+ int subexp_idx;
+ struct re_backref_cache_entry *ent;
+ ent = bkref_ents + limits->elems[lim_idx];
+
+ if (str_idx <= ent->subexp_from || ent->str_idx < str_idx)
+ continue; /* This is unrelated limitation. */
+
+ subexp_idx = dfa->nodes[ent->node].opr.idx;
+ if (ent->subexp_to == str_idx)
+ {
+ int ops_node = -1;
+ int cls_node = -1;
+ for (node_idx = 0; node_idx < dest_nodes->nelem; ++node_idx)
+ {
+ int node = dest_nodes->elems[node_idx];
+ re_token_type_t type = dfa->nodes[node].type;
+ if (type == OP_OPEN_SUBEXP
+ && subexp_idx == dfa->nodes[node].opr.idx)
+ ops_node = node;
+ else if (type == OP_CLOSE_SUBEXP
+ && subexp_idx == dfa->nodes[node].opr.idx)
+ cls_node = node;
+ }
+
+ /* Check the limitation of the open subexpression. */
+ /* Note that (ent->subexp_to = str_idx != ent->subexp_from). */
+ if (ops_node >= 0)
+ {
+ err = sub_epsilon_src_nodes (dfa, ops_node, dest_nodes,
+ candidates);
+ if (BE (err != REG_NOERROR, 0))
+ return err;
+ }
+
+ /* Check the limitation of the close subexpression. */
+ if (cls_node >= 0)
+ for (node_idx = 0; node_idx < dest_nodes->nelem; ++node_idx)
+ {
+ int node = dest_nodes->elems[node_idx];
+ if (!re_node_set_contains (dfa->inveclosures + node,
+ cls_node)
+ && !re_node_set_contains (dfa->eclosures + node,
+ cls_node))
+ {
+ /* It is against this limitation.
+ Remove it form the current sifted state. */
+ err = sub_epsilon_src_nodes (dfa, node, dest_nodes,
+ candidates);
+ if (BE (err != REG_NOERROR, 0))
+ return err;
+ --node_idx;
+ }
+ }
+ }
+ else /* (ent->subexp_to != str_idx) */
+ {
+ for (node_idx = 0; node_idx < dest_nodes->nelem; ++node_idx)
+ {
+ int node = dest_nodes->elems[node_idx];
+ re_token_type_t type = dfa->nodes[node].type;
+ if (type == OP_CLOSE_SUBEXP || type == OP_OPEN_SUBEXP)
+ {
+ if (subexp_idx != dfa->nodes[node].opr.idx)
+ continue;
+ /* It is against this limitation.
+ Remove it form the current sifted state. */
+ err = sub_epsilon_src_nodes (dfa, node, dest_nodes,
+ candidates);
+ if (BE (err != REG_NOERROR, 0))
+ return err;
+ }
+ }
+ }
+ }
+ return REG_NOERROR;
+}
+
+static reg_errcode_t
+internal_function
+sift_states_bkref (const re_match_context_t *mctx, re_sift_context_t *sctx,
+ int str_idx, const re_node_set *candidates)
+{
+ const re_dfa_t *const dfa = mctx->dfa;
+ reg_errcode_t err;
+ int node_idx, node;
+ re_sift_context_t local_sctx;
+ int first_idx = search_cur_bkref_entry (mctx, str_idx);
+
+ if (first_idx == -1)
+ return REG_NOERROR;
+
+ local_sctx.sifted_states = NULL; /* Mark that it hasn't been initialized. */
+
+ for (node_idx = 0; node_idx < candidates->nelem; ++node_idx)
+ {
+ int enabled_idx;
+ re_token_type_t type;
+ struct re_backref_cache_entry *entry;
+ node = candidates->elems[node_idx];
+ type = dfa->nodes[node].type;
+ /* Avoid infinite loop for the REs like "()\1+". */
+ if (node == sctx->last_node && str_idx == sctx->last_str_idx)
+ continue;
+ if (type != OP_BACK_REF)
+ continue;
+
+ entry = mctx->bkref_ents + first_idx;
+ enabled_idx = first_idx;
+ do
+ {
+ int subexp_len;
+ int to_idx;
+ int dst_node;
+ int ret;
+ re_dfastate_t *cur_state;
+
+ if (entry->node != node)
+ continue;
+ subexp_len = entry->subexp_to - entry->subexp_from;
+ to_idx = str_idx + subexp_len;
+ dst_node = (subexp_len ? dfa->nexts[node]
+ : dfa->edests[node].elems[0]);
+
+ if (to_idx > sctx->last_str_idx
+ || sctx->sifted_states[to_idx] == NULL
+ || !STATE_NODE_CONTAINS (sctx->sifted_states[to_idx], dst_node)
+ || check_dst_limits (mctx, &sctx->limits, node,
+ str_idx, dst_node, to_idx))
+ continue;
+
+ if (local_sctx.sifted_states == NULL)
+ {
+ local_sctx = *sctx;
+ err = re_node_set_init_copy (&local_sctx.limits, &sctx->limits);
+ if (BE (err != REG_NOERROR, 0))
+ goto free_return;
+ }
+ local_sctx.last_node = node;
+ local_sctx.last_str_idx = str_idx;
+ ret = re_node_set_insert (&local_sctx.limits, enabled_idx);
+ if (BE (ret < 0, 0))
+ {
+ err = REG_ESPACE;
+ goto free_return;
+ }
+ cur_state = local_sctx.sifted_states[str_idx];
+ err = sift_states_backward (mctx, &local_sctx);
+ if (BE (err != REG_NOERROR, 0))
+ goto free_return;
+ if (sctx->limited_states != NULL)
+ {
+ err = merge_state_array (dfa, sctx->limited_states,
+ local_sctx.sifted_states,
+ str_idx + 1);
+ if (BE (err != REG_NOERROR, 0))
+ goto free_return;
+ }
+ local_sctx.sifted_states[str_idx] = cur_state;
+ re_node_set_remove (&local_sctx.limits, enabled_idx);
+
+ /* mctx->bkref_ents may have changed, reload the pointer. */
+ entry = mctx->bkref_ents + enabled_idx;
+ }
+ while (enabled_idx++, entry++->more);
+ }
+ err = REG_NOERROR;
+ free_return:
+ if (local_sctx.sifted_states != NULL)
+ {
+ re_node_set_free (&local_sctx.limits);
+ }
+
+ return err;
+}
+
+
+#ifdef RE_ENABLE_I18N
+static int
+internal_function
+sift_states_iter_mb (const re_match_context_t *mctx, re_sift_context_t *sctx,
+ int node_idx, int str_idx, int max_str_idx)
+{
+ const re_dfa_t *const dfa = mctx->dfa;
+ int naccepted;
+ /* Check the node can accept `multi byte'. */
+ naccepted = check_node_accept_bytes (dfa, node_idx, &mctx->input, str_idx);
+ if (naccepted > 0 && str_idx + naccepted <= max_str_idx &&
+ !STATE_NODE_CONTAINS (sctx->sifted_states[str_idx + naccepted],
+ dfa->nexts[node_idx]))
+ /* The node can't accept the `multi byte', or the
+ destination was already thrown away, then the node
+ could't accept the current input `multi byte'. */
+ naccepted = 0;
+ /* Otherwise, it is sure that the node could accept
+ `naccepted' bytes input. */
+ return naccepted;
+}
+#endif /* RE_ENABLE_I18N */
+
+
+/* Functions for state transition. */
+
+/* Return the next state to which the current state STATE will transit by
+ accepting the current input byte, and update STATE_LOG if necessary.
+ If STATE can accept a multibyte char/collating element/back reference
+ update the destination of STATE_LOG. */
+
+static re_dfastate_t *
+internal_function
+transit_state (reg_errcode_t *err, re_match_context_t *mctx,
+ re_dfastate_t *state)
+{
+ re_dfastate_t **trtable;
+ unsigned char ch;
+
+#ifdef RE_ENABLE_I18N
+ /* If the current state can accept multibyte. */
+ if (BE (state->accept_mb, 0))
+ {
+ *err = transit_state_mb (mctx, state);
+ if (BE (*err != REG_NOERROR, 0))
+ return NULL;
+ }
+#endif /* RE_ENABLE_I18N */
+
+ /* Then decide the next state with the single byte. */
+#if 0
+ if (0)
+ /* don't use transition table */
+ return transit_state_sb (err, mctx, state);
+#endif
+
+ /* Use transition table */
+ ch = re_string_fetch_byte (&mctx->input);
+ for (;;)
+ {
+ trtable = state->trtable;
+ if (BE (trtable != NULL, 1))
+ return trtable[ch];
+
+ trtable = state->word_trtable;
+ if (BE (trtable != NULL, 1))
+ {
+ unsigned int context;
+ context
+ = re_string_context_at (&mctx->input,
+ re_string_cur_idx (&mctx->input) - 1,
+ mctx->eflags);
+ if (IS_WORD_CONTEXT (context))
+ return trtable[ch + SBC_MAX];
+ else
+ return trtable[ch];
+ }
+
+ if (!build_trtable (mctx->dfa, state))
+ {
+ *err = REG_ESPACE;
+ return NULL;
+ }
+
+ /* Retry, we now have a transition table. */
+ }
+}
+
+/* Update the state_log if we need */
+re_dfastate_t *
+internal_function
+merge_state_with_log (reg_errcode_t *err, re_match_context_t *mctx,
+ re_dfastate_t *next_state)
+{
+ const re_dfa_t *const dfa = mctx->dfa;
+ int cur_idx = re_string_cur_idx (&mctx->input);
+
+ if (cur_idx > mctx->state_log_top)
+ {
+ mctx->state_log[cur_idx] = next_state;
+ mctx->state_log_top = cur_idx;
+ }
+ else if (mctx->state_log[cur_idx] == 0)
+ {
+ mctx->state_log[cur_idx] = next_state;
+ }
+ else
+ {
+ re_dfastate_t *pstate;
+ unsigned int context;
+ re_node_set next_nodes, *log_nodes, *table_nodes = NULL;
+ /* If (state_log[cur_idx] != 0), it implies that cur_idx is
+ the destination of a multibyte char/collating element/
+ back reference. Then the next state is the union set of
+ these destinations and the results of the transition table. */
+ pstate = mctx->state_log[cur_idx];
+ log_nodes = pstate->entrance_nodes;
+ if (next_state != NULL)
+ {
+ table_nodes = next_state->entrance_nodes;
+ *err = re_node_set_init_union (&next_nodes, table_nodes,
+ log_nodes);
+ if (BE (*err != REG_NOERROR, 0))
+ return NULL;
+ }
+ else
+ next_nodes = *log_nodes;
+ /* Note: We already add the nodes of the initial state,
+ then we don't need to add them here. */
+
+ context = re_string_context_at (&mctx->input,
+ re_string_cur_idx (&mctx->input) - 1,
+ mctx->eflags);
+ next_state = mctx->state_log[cur_idx]
+ = re_acquire_state_context (err, dfa, &next_nodes, context);
+ /* We don't need to check errors here, since the return value of
+ this function is next_state and ERR is already set. */
+
+ if (table_nodes != NULL)
+ re_node_set_free (&next_nodes);
+ }
+
+ if (BE (dfa->nbackref, 0) && next_state != NULL)
+ {
+ /* Check OP_OPEN_SUBEXP in the current state in case that we use them
+ later. We must check them here, since the back references in the
+ next state might use them. */
+ *err = check_subexp_matching_top (mctx, &next_state->nodes,
+ cur_idx);
+ if (BE (*err != REG_NOERROR, 0))
+ return NULL;
+
+ /* If the next state has back references. */
+ if (next_state->has_backref)
+ {
+ *err = transit_state_bkref (mctx, &next_state->nodes);
+ if (BE (*err != REG_NOERROR, 0))
+ return NULL;
+ next_state = mctx->state_log[cur_idx];
+ }
+ }
+
+ return next_state;
+}
+
+/* Skip bytes in the input that correspond to part of a
+ multi-byte match, then look in the log for a state
+ from which to restart matching. */
+re_dfastate_t *
+internal_function
+find_recover_state (reg_errcode_t *err, re_match_context_t *mctx)
+{
+ re_dfastate_t *cur_state;
+ do
+ {
+ int max = mctx->state_log_top;
+ int cur_str_idx = re_string_cur_idx (&mctx->input);
+
+ do
+ {
+ if (++cur_str_idx > max)
+ return NULL;
+ re_string_skip_bytes (&mctx->input, 1);
+ }
+ while (mctx->state_log[cur_str_idx] == NULL);
+
+ cur_state = merge_state_with_log (err, mctx, NULL);
+ }
+ while (*err == REG_NOERROR && cur_state == NULL);
+ return cur_state;
+}
+
+/* Helper functions for transit_state. */
+
+/* From the node set CUR_NODES, pick up the nodes whose types are
+ OP_OPEN_SUBEXP and which have corresponding back references in the regular
+ expression. And register them to use them later for evaluating the
+ correspoding back references. */
+
+static reg_errcode_t
+internal_function
+check_subexp_matching_top (re_match_context_t *mctx, re_node_set *cur_nodes,
+ int str_idx)
+{
+ const re_dfa_t *const dfa = mctx->dfa;
+ int node_idx;
+ reg_errcode_t err;
+
+ /* TODO: This isn't efficient.
+ Because there might be more than one nodes whose types are
+ OP_OPEN_SUBEXP and whose index is SUBEXP_IDX, we must check all
+ nodes.
+ E.g. RE: (a){2} */
+ for (node_idx = 0; node_idx < cur_nodes->nelem; ++node_idx)
+ {
+ int node = cur_nodes->elems[node_idx];
+ if (dfa->nodes[node].type == OP_OPEN_SUBEXP
+ && dfa->nodes[node].opr.idx < BITSET_WORD_BITS
+ && (dfa->used_bkref_map
+ & ((bitset_word_t) 1 << dfa->nodes[node].opr.idx)))
+ {
+ err = match_ctx_add_subtop (mctx, node, str_idx);
+ if (BE (err != REG_NOERROR, 0))
+ return err;
+ }
+ }
+ return REG_NOERROR;
+}
+
+#if 0
+/* Return the next state to which the current state STATE will transit by
+ accepting the current input byte. */
+
+static re_dfastate_t *
+transit_state_sb (reg_errcode_t *err, re_match_context_t *mctx,
+ re_dfastate_t *state)
+{
+ const re_dfa_t *const dfa = mctx->dfa;
+ re_node_set next_nodes;
+ re_dfastate_t *next_state;
+ int node_cnt, cur_str_idx = re_string_cur_idx (&mctx->input);
+ unsigned int context;
+
+ *err = re_node_set_alloc (&next_nodes, state->nodes.nelem + 1);
+ if (BE (*err != REG_NOERROR, 0))
+ return NULL;
+ for (node_cnt = 0; node_cnt < state->nodes.nelem; ++node_cnt)
+ {
+ int cur_node = state->nodes.elems[node_cnt];
+ if (check_node_accept (mctx, dfa->nodes + cur_node, cur_str_idx))
+ {
+ *err = re_node_set_merge (&next_nodes,
+ dfa->eclosures + dfa->nexts[cur_node]);
+ if (BE (*err != REG_NOERROR, 0))
+ {
+ re_node_set_free (&next_nodes);
+ return NULL;
+ }
+ }
+ }
+ context = re_string_context_at (&mctx->input, cur_str_idx, mctx->eflags);
+ next_state = re_acquire_state_context (err, dfa, &next_nodes, context);
+ /* We don't need to check errors here, since the return value of
+ this function is next_state and ERR is already set. */
+
+ re_node_set_free (&next_nodes);
+ re_string_skip_bytes (&mctx->input, 1);
+ return next_state;
+}
+#endif
+
+#ifdef RE_ENABLE_I18N
+static reg_errcode_t
+internal_function
+transit_state_mb (re_match_context_t *mctx, re_dfastate_t *pstate)
+{
+ const re_dfa_t *const dfa = mctx->dfa;
+ reg_errcode_t err;
+ int i;
+
+ for (i = 0; i < pstate->nodes.nelem; ++i)
+ {
+ re_node_set dest_nodes, *new_nodes;
+ int cur_node_idx = pstate->nodes.elems[i];
+ int naccepted, dest_idx;
+ unsigned int context;
+ re_dfastate_t *dest_state;
+
+ if (!dfa->nodes[cur_node_idx].accept_mb)
+ continue;
+
+ if (dfa->nodes[cur_node_idx].constraint)
+ {
+ context = re_string_context_at (&mctx->input,
+ re_string_cur_idx (&mctx->input),
+ mctx->eflags);
+ if (NOT_SATISFY_NEXT_CONSTRAINT (dfa->nodes[cur_node_idx].constraint,
+ context))
+ continue;
+ }
+
+ /* How many bytes the node can accept? */
+ naccepted = check_node_accept_bytes (dfa, cur_node_idx, &mctx->input,
+ re_string_cur_idx (&mctx->input));
+ if (naccepted == 0)
+ continue;
+
+ /* The node can accepts `naccepted' bytes. */
+ dest_idx = re_string_cur_idx (&mctx->input) + naccepted;
+ mctx->max_mb_elem_len = ((mctx->max_mb_elem_len < naccepted) ? naccepted
+ : mctx->max_mb_elem_len);
+ err = clean_state_log_if_needed (mctx, dest_idx);
+ if (BE (err != REG_NOERROR, 0))
+ return err;
+#ifdef DEBUG
+ assert (dfa->nexts[cur_node_idx] != -1);
+#endif
+ new_nodes = dfa->eclosures + dfa->nexts[cur_node_idx];
+
+ dest_state = mctx->state_log[dest_idx];
+ if (dest_state == NULL)
+ dest_nodes = *new_nodes;
+ else
+ {
+ err = re_node_set_init_union (&dest_nodes,
+ dest_state->entrance_nodes, new_nodes);
+ if (BE (err != REG_NOERROR, 0))
+ return err;
+ }
+ context = re_string_context_at (&mctx->input, dest_idx - 1,
+ mctx->eflags);
+ mctx->state_log[dest_idx]
+ = re_acquire_state_context (&err, dfa, &dest_nodes, context);
+ if (dest_state != NULL)
+ re_node_set_free (&dest_nodes);
+ if (BE (mctx->state_log[dest_idx] == NULL && err != REG_NOERROR, 0))
+ return err;
+ }
+ return REG_NOERROR;
+}
+#endif /* RE_ENABLE_I18N */
+
+static reg_errcode_t
+internal_function
+transit_state_bkref (re_match_context_t *mctx, const re_node_set *nodes)
+{
+ const re_dfa_t *const dfa = mctx->dfa;
+ reg_errcode_t err;
+ int i;
+ int cur_str_idx = re_string_cur_idx (&mctx->input);
+
+ for (i = 0; i < nodes->nelem; ++i)
+ {
+ int dest_str_idx, prev_nelem, bkc_idx;
+ int node_idx = nodes->elems[i];
+ unsigned int context;
+ const re_token_t *node = dfa->nodes + node_idx;
+ re_node_set *new_dest_nodes;
+
+ /* Check whether `node' is a backreference or not. */
+ if (node->type != OP_BACK_REF)
+ continue;
+
+ if (node->constraint)
+ {
+ context = re_string_context_at (&mctx->input, cur_str_idx,
+ mctx->eflags);
+ if (NOT_SATISFY_NEXT_CONSTRAINT (node->constraint, context))
+ continue;
+ }
+
+ /* `node' is a backreference.
+ Check the substring which the substring matched. */
+ bkc_idx = mctx->nbkref_ents;
+ err = get_subexp (mctx, node_idx, cur_str_idx);
+ if (BE (err != REG_NOERROR, 0))
+ goto free_return;
+
+ /* And add the epsilon closures (which is `new_dest_nodes') of
+ the backreference to appropriate state_log. */
+#ifdef DEBUG
+ assert (dfa->nexts[node_idx] != -1);
+#endif
+ for (; bkc_idx < mctx->nbkref_ents; ++bkc_idx)
+ {
+ int subexp_len;
+ re_dfastate_t *dest_state;
+ struct re_backref_cache_entry *bkref_ent;
+ bkref_ent = mctx->bkref_ents + bkc_idx;
+ if (bkref_ent->node != node_idx || bkref_ent->str_idx != cur_str_idx)
+ continue;
+ subexp_len = bkref_ent->subexp_to - bkref_ent->subexp_from;
+ new_dest_nodes = (subexp_len == 0
+ ? dfa->eclosures + dfa->edests[node_idx].elems[0]
+ : dfa->eclosures + dfa->nexts[node_idx]);
+ dest_str_idx = (cur_str_idx + bkref_ent->subexp_to
+ - bkref_ent->subexp_from);
+ context = re_string_context_at (&mctx->input, dest_str_idx - 1,
+ mctx->eflags);
+ dest_state = mctx->state_log[dest_str_idx];
+ prev_nelem = ((mctx->state_log[cur_str_idx] == NULL) ? 0
+ : mctx->state_log[cur_str_idx]->nodes.nelem);
+ /* Add `new_dest_node' to state_log. */
+ if (dest_state == NULL)
+ {
+ mctx->state_log[dest_str_idx]
+ = re_acquire_state_context (&err, dfa, new_dest_nodes,
+ context);
+ if (BE (mctx->state_log[dest_str_idx] == NULL
+ && err != REG_NOERROR, 0))
+ goto free_return;
+ }
+ else
+ {
+ re_node_set dest_nodes;
+ err = re_node_set_init_union (&dest_nodes,
+ dest_state->entrance_nodes,
+ new_dest_nodes);
+ if (BE (err != REG_NOERROR, 0))
+ {
+ re_node_set_free (&dest_nodes);
+ goto free_return;
+ }
+ mctx->state_log[dest_str_idx]
+ = re_acquire_state_context (&err, dfa, &dest_nodes, context);
+ re_node_set_free (&dest_nodes);
+ if (BE (mctx->state_log[dest_str_idx] == NULL
+ && err != REG_NOERROR, 0))
+ goto free_return;
+ }
+ /* We need to check recursively if the backreference can epsilon
+ transit. */
+ if (subexp_len == 0
+ && mctx->state_log[cur_str_idx]->nodes.nelem > prev_nelem)
+ {
+ err = check_subexp_matching_top (mctx, new_dest_nodes,
+ cur_str_idx);
+ if (BE (err != REG_NOERROR, 0))
+ goto free_return;
+ err = transit_state_bkref (mctx, new_dest_nodes);
+ if (BE (err != REG_NOERROR, 0))
+ goto free_return;
+ }
+ }
+ }
+ err = REG_NOERROR;
+ free_return:
+ return err;
+}
+
+/* Enumerate all the candidates which the backreference BKREF_NODE can match
+ at BKREF_STR_IDX, and register them by match_ctx_add_entry().
+ Note that we might collect inappropriate candidates here.
+ However, the cost of checking them strictly here is too high, then we
+ delay these checking for prune_impossible_nodes(). */
+
+static reg_errcode_t
+internal_function
+get_subexp (re_match_context_t *mctx, int bkref_node, int bkref_str_idx)
+{
+ const re_dfa_t *const dfa = mctx->dfa;
+ int subexp_num, sub_top_idx;
+ const char *buf = (const char *) re_string_get_buffer (&mctx->input);
+ /* Return if we have already checked BKREF_NODE at BKREF_STR_IDX. */
+ int cache_idx = search_cur_bkref_entry (mctx, bkref_str_idx);
+ if (cache_idx != -1)
+ {
+ const struct re_backref_cache_entry *entry
+ = mctx->bkref_ents + cache_idx;
+ do
+ if (entry->node == bkref_node)
+ return REG_NOERROR; /* We already checked it. */
+ while (entry++->more);
+ }
+
+ subexp_num = dfa->nodes[bkref_node].opr.idx;
+
+ /* For each sub expression */
+ for (sub_top_idx = 0; sub_top_idx < mctx->nsub_tops; ++sub_top_idx)
+ {
+ reg_errcode_t err;
+ re_sub_match_top_t *sub_top = mctx->sub_tops[sub_top_idx];
+ re_sub_match_last_t *sub_last;
+ int sub_last_idx, sl_str, bkref_str_off;
+
+ if (dfa->nodes[sub_top->node].opr.idx != subexp_num)
+ continue; /* It isn't related. */
+
+ sl_str = sub_top->str_idx;
+ bkref_str_off = bkref_str_idx;
+ /* At first, check the last node of sub expressions we already
+ evaluated. */
+ for (sub_last_idx = 0; sub_last_idx < sub_top->nlasts; ++sub_last_idx)
+ {
+ int sl_str_diff;
+ sub_last = sub_top->lasts[sub_last_idx];
+ sl_str_diff = sub_last->str_idx - sl_str;
+ /* The matched string by the sub expression match with the substring
+ at the back reference? */
+ if (sl_str_diff > 0)
+ {
+ if (BE (bkref_str_off + sl_str_diff > mctx->input.valid_len, 0))
+ {
+ /* Not enough chars for a successful match. */
+ if (bkref_str_off + sl_str_diff > mctx->input.len)
+ break;
+
+ err = clean_state_log_if_needed (mctx,
+ bkref_str_off
+ + sl_str_diff);
+ if (BE (err != REG_NOERROR, 0))
+ return err;
+ buf = (const char *) re_string_get_buffer (&mctx->input);
+ }
+ if (memcmp (buf + bkref_str_off, buf + sl_str, sl_str_diff) != 0)
+ /* We don't need to search this sub expression any more. */
+ break;
+ }
+ bkref_str_off += sl_str_diff;
+ sl_str += sl_str_diff;
+ err = get_subexp_sub (mctx, sub_top, sub_last, bkref_node,
+ bkref_str_idx);
+
+ /* Reload buf, since the preceding call might have reallocated
+ the buffer. */
+ buf = (const char *) re_string_get_buffer (&mctx->input);
+
+ if (err == REG_NOMATCH)
+ continue;
+ if (BE (err != REG_NOERROR, 0))
+ return err;
+ }
+
+ if (sub_last_idx < sub_top->nlasts)
+ continue;
+ if (sub_last_idx > 0)
+ ++sl_str;
+ /* Then, search for the other last nodes of the sub expression. */
+ for (; sl_str <= bkref_str_idx; ++sl_str)
+ {
+ int cls_node, sl_str_off;
+ const re_node_set *nodes;
+ sl_str_off = sl_str - sub_top->str_idx;
+ /* The matched string by the sub expression match with the substring
+ at the back reference? */
+ if (sl_str_off > 0)
+ {
+ if (BE (bkref_str_off >= mctx->input.valid_len, 0))
+ {
+ /* If we are at the end of the input, we cannot match. */
+ if (bkref_str_off >= mctx->input.len)
+ break;
+
+ err = extend_buffers (mctx);
+ if (BE (err != REG_NOERROR, 0))
+ return err;
+
+ buf = (const char *) re_string_get_buffer (&mctx->input);
+ }
+ if (buf [bkref_str_off++] != buf[sl_str - 1])
+ break; /* We don't need to search this sub expression
+ any more. */
+ }
+ if (mctx->state_log[sl_str] == NULL)
+ continue;
+ /* Does this state have a ')' of the sub expression? */
+ nodes = &mctx->state_log[sl_str]->nodes;
+ cls_node = find_subexp_node (dfa, nodes, subexp_num,
+ OP_CLOSE_SUBEXP);
+ if (cls_node == -1)
+ continue; /* No. */
+ if (sub_top->path == NULL)
+ {
+ sub_top->path = calloc (sizeof (state_array_t),
+ sl_str - sub_top->str_idx + 1);
+ if (sub_top->path == NULL)
+ return REG_ESPACE;
+ }
+ /* Can the OP_OPEN_SUBEXP node arrive the OP_CLOSE_SUBEXP node
+ in the current context? */
+ err = check_arrival (mctx, sub_top->path, sub_top->node,
+ sub_top->str_idx, cls_node, sl_str,
+ OP_CLOSE_SUBEXP);
+ if (err == REG_NOMATCH)
+ continue;
+ if (BE (err != REG_NOERROR, 0))
+ return err;
+ sub_last = match_ctx_add_sublast (sub_top, cls_node, sl_str);
+ if (BE (sub_last == NULL, 0))
+ return REG_ESPACE;
+ err = get_subexp_sub (mctx, sub_top, sub_last, bkref_node,
+ bkref_str_idx);
+ if (err == REG_NOMATCH)
+ continue;
+ }
+ }
+ return REG_NOERROR;
+}
+
+/* Helper functions for get_subexp(). */
+
+/* Check SUB_LAST can arrive to the back reference BKREF_NODE at BKREF_STR.
+ If it can arrive, register the sub expression expressed with SUB_TOP
+ and SUB_LAST. */
+
+static reg_errcode_t
+internal_function
+get_subexp_sub (re_match_context_t *mctx, const re_sub_match_top_t *sub_top,
+ re_sub_match_last_t *sub_last, int bkref_node, int bkref_str)
+{
+ reg_errcode_t err;
+ int to_idx;
+ /* Can the subexpression arrive the back reference? */
+ err = check_arrival (mctx, &sub_last->path, sub_last->node,
+ sub_last->str_idx, bkref_node, bkref_str,
+ OP_OPEN_SUBEXP);
+ if (err != REG_NOERROR)
+ return err;
+ err = match_ctx_add_entry (mctx, bkref_node, bkref_str, sub_top->str_idx,
+ sub_last->str_idx);
+ if (BE (err != REG_NOERROR, 0))
+ return err;
+ to_idx = bkref_str + sub_last->str_idx - sub_top->str_idx;
+ return clean_state_log_if_needed (mctx, to_idx);
+}
+
+/* Find the first node which is '(' or ')' and whose index is SUBEXP_IDX.
+ Search '(' if FL_OPEN, or search ')' otherwise.
+ TODO: This function isn't efficient...
+ Because there might be more than one nodes whose types are
+ OP_OPEN_SUBEXP and whose index is SUBEXP_IDX, we must check all
+ nodes.
+ E.g. RE: (a){2} */
+
+static int
+internal_function
+find_subexp_node (const re_dfa_t *dfa, const re_node_set *nodes,
+ int subexp_idx, int type)
+{
+ int cls_idx;
+ for (cls_idx = 0; cls_idx < nodes->nelem; ++cls_idx)
+ {
+ int cls_node = nodes->elems[cls_idx];
+ const re_token_t *node = dfa->nodes + cls_node;
+ if (node->type == type
+ && node->opr.idx == subexp_idx)
+ return cls_node;
+ }
+ return -1;
+}
+
+/* Check whether the node TOP_NODE at TOP_STR can arrive to the node
+ LAST_NODE at LAST_STR. We record the path onto PATH since it will be
+ heavily reused.
+ Return REG_NOERROR if it can arrive, or REG_NOMATCH otherwise. */
+
+static reg_errcode_t
+internal_function
+check_arrival (re_match_context_t *mctx, state_array_t *path, int top_node,
+ int top_str, int last_node, int last_str, int type)
+{
+ const re_dfa_t *const dfa = mctx->dfa;
+ reg_errcode_t err = REG_NOERROR;
+ int subexp_num, backup_cur_idx, str_idx, null_cnt;
+ re_dfastate_t *cur_state = NULL;
+ re_node_set *cur_nodes, next_nodes;
+ re_dfastate_t **backup_state_log;
+ unsigned int context;
+
+ subexp_num = dfa->nodes[top_node].opr.idx;
+ /* Extend the buffer if we need. */
+ if (BE (path->alloc < last_str + mctx->max_mb_elem_len + 1, 0))
+ {
+ re_dfastate_t **new_array;
+ int old_alloc = path->alloc;
+ path->alloc += last_str + mctx->max_mb_elem_len + 1;
+ new_array = re_realloc (path->array, re_dfastate_t *, path->alloc);
+ if (BE (new_array == NULL, 0))
+ {
+ path->alloc = old_alloc;
+ return REG_ESPACE;
+ }
+ path->array = new_array;
+ memset (new_array + old_alloc, '\0',
+ sizeof (re_dfastate_t *) * (path->alloc - old_alloc));
+ }
+
+ str_idx = path->next_idx ?: top_str;
+
+ /* Temporary modify MCTX. */
+ backup_state_log = mctx->state_log;
+ backup_cur_idx = mctx->input.cur_idx;
+ mctx->state_log = path->array;
+ mctx->input.cur_idx = str_idx;
+
+ /* Setup initial node set. */
+ context = re_string_context_at (&mctx->input, str_idx - 1, mctx->eflags);
+ if (str_idx == top_str)
+ {
+ err = re_node_set_init_1 (&next_nodes, top_node);
+ if (BE (err != REG_NOERROR, 0))
+ return err;
+ err = check_arrival_expand_ecl (dfa, &next_nodes, subexp_num, type);
+ if (BE (err != REG_NOERROR, 0))
+ {
+ re_node_set_free (&next_nodes);
+ return err;
+ }
+ }
+ else
+ {
+ cur_state = mctx->state_log[str_idx];
+ if (cur_state && cur_state->has_backref)
+ {
+ err = re_node_set_init_copy (&next_nodes, &cur_state->nodes);
+ if (BE (err != REG_NOERROR, 0))
+ return err;
+ }
+ else
+ re_node_set_init_empty (&next_nodes);
+ }
+ if (str_idx == top_str || (cur_state && cur_state->has_backref))
+ {
+ if (next_nodes.nelem)
+ {
+ err = expand_bkref_cache (mctx, &next_nodes, str_idx,
+ subexp_num, type);
+ if (BE (err != REG_NOERROR, 0))
+ {
+ re_node_set_free (&next_nodes);
+ return err;
+ }
+ }
+ cur_state = re_acquire_state_context (&err, dfa, &next_nodes, context);
+ if (BE (cur_state == NULL && err != REG_NOERROR, 0))
+ {
+ re_node_set_free (&next_nodes);
+ return err;
+ }
+ mctx->state_log[str_idx] = cur_state;
+ }
+
+ for (null_cnt = 0; str_idx < last_str && null_cnt <= mctx->max_mb_elem_len;)
+ {
+ re_node_set_empty (&next_nodes);
+ if (mctx->state_log[str_idx + 1])
+ {
+ err = re_node_set_merge (&next_nodes,
+ &mctx->state_log[str_idx + 1]->nodes);
+ if (BE (err != REG_NOERROR, 0))
+ {
+ re_node_set_free (&next_nodes);
+ return err;
+ }
+ }
+ if (cur_state)
+ {
+ err = check_arrival_add_next_nodes (mctx, str_idx,
+ &cur_state->non_eps_nodes,
+ &next_nodes);
+ if (BE (err != REG_NOERROR, 0))
+ {
+ re_node_set_free (&next_nodes);
+ return err;
+ }
+ }
+ ++str_idx;
+ if (next_nodes.nelem)
+ {
+ err = check_arrival_expand_ecl (dfa, &next_nodes, subexp_num, type);
+ if (BE (err != REG_NOERROR, 0))
+ {
+ re_node_set_free (&next_nodes);
+ return err;
+ }
+ err = expand_bkref_cache (mctx, &next_nodes, str_idx,
+ subexp_num, type);
+ if (BE (err != REG_NOERROR, 0))
+ {
+ re_node_set_free (&next_nodes);
+ return err;
+ }
+ }
+ context = re_string_context_at (&mctx->input, str_idx - 1, mctx->eflags);
+ cur_state = re_acquire_state_context (&err, dfa, &next_nodes, context);
+ if (BE (cur_state == NULL && err != REG_NOERROR, 0))
+ {
+ re_node_set_free (&next_nodes);
+ return err;
+ }
+ mctx->state_log[str_idx] = cur_state;
+ null_cnt = cur_state == NULL ? null_cnt + 1 : 0;
+ }
+ re_node_set_free (&next_nodes);
+ cur_nodes = (mctx->state_log[last_str] == NULL ? NULL
+ : &mctx->state_log[last_str]->nodes);
+ path->next_idx = str_idx;
+
+ /* Fix MCTX. */
+ mctx->state_log = backup_state_log;
+ mctx->input.cur_idx = backup_cur_idx;
+
+ /* Then check the current node set has the node LAST_NODE. */
+ if (cur_nodes != NULL && re_node_set_contains (cur_nodes, last_node))
+ return REG_NOERROR;
+
+ return REG_NOMATCH;
+}
+
+/* Helper functions for check_arrival. */
+
+/* Calculate the destination nodes of CUR_NODES at STR_IDX, and append them
+ to NEXT_NODES.
+ TODO: This function is similar to the functions transit_state*(),
+ however this function has many additional works.
+ Can't we unify them? */
+
+static reg_errcode_t
+internal_function
+check_arrival_add_next_nodes (re_match_context_t *mctx, int str_idx,
+ re_node_set *cur_nodes, re_node_set *next_nodes)
+{
+ const re_dfa_t *const dfa = mctx->dfa;
+ int result;
+ int cur_idx;
+#ifdef RE_ENABLE_I18N
+ reg_errcode_t err = REG_NOERROR;
+#endif
+ re_node_set union_set;
+ re_node_set_init_empty (&union_set);
+ for (cur_idx = 0; cur_idx < cur_nodes->nelem; ++cur_idx)
+ {
+ int naccepted = 0;
+ int cur_node = cur_nodes->elems[cur_idx];
+#ifdef DEBUG
+ re_token_type_t type = dfa->nodes[cur_node].type;
+ assert (!IS_EPSILON_NODE (type));
+#endif
+#ifdef RE_ENABLE_I18N
+ /* If the node may accept `multi byte'. */
+ if (dfa->nodes[cur_node].accept_mb)
+ {
+ naccepted = check_node_accept_bytes (dfa, cur_node, &mctx->input,
+ str_idx);
+ if (naccepted > 1)
+ {
+ re_dfastate_t *dest_state;
+ int next_node = dfa->nexts[cur_node];
+ int next_idx = str_idx + naccepted;
+ dest_state = mctx->state_log[next_idx];
+ re_node_set_empty (&union_set);
+ if (dest_state)
+ {
+ err = re_node_set_merge (&union_set, &dest_state->nodes);
+ if (BE (err != REG_NOERROR, 0))
+ {
+ re_node_set_free (&union_set);
+ return err;
+ }
+ }
+ result = re_node_set_insert (&union_set, next_node);
+ if (BE (result < 0, 0))
+ {
+ re_node_set_free (&union_set);
+ return REG_ESPACE;
+ }
+ mctx->state_log[next_idx] = re_acquire_state (&err, dfa,
+ &union_set);
+ if (BE (mctx->state_log[next_idx] == NULL
+ && err != REG_NOERROR, 0))
+ {
+ re_node_set_free (&union_set);
+ return err;
+ }
+ }
+ }
+#endif /* RE_ENABLE_I18N */
+ if (naccepted
+ || check_node_accept (mctx, dfa->nodes + cur_node, str_idx))
+ {
+ result = re_node_set_insert (next_nodes, dfa->nexts[cur_node]);
+ if (BE (result < 0, 0))
+ {
+ re_node_set_free (&union_set);
+ return REG_ESPACE;
+ }
+ }
+ }
+ re_node_set_free (&union_set);
+ return REG_NOERROR;
+}
+
+/* For all the nodes in CUR_NODES, add the epsilon closures of them to
+ CUR_NODES, however exclude the nodes which are:
+ - inside the sub expression whose number is EX_SUBEXP, if FL_OPEN.
+ - out of the sub expression whose number is EX_SUBEXP, if !FL_OPEN.
+*/
+
+static reg_errcode_t
+internal_function
+check_arrival_expand_ecl (const re_dfa_t *dfa, re_node_set *cur_nodes,
+ int ex_subexp, int type)
+{
+ reg_errcode_t err;
+ int idx, outside_node;
+ re_node_set new_nodes;
+#ifdef DEBUG
+ assert (cur_nodes->nelem);
+#endif
+ err = re_node_set_alloc (&new_nodes, cur_nodes->nelem);
+ if (BE (err != REG_NOERROR, 0))
+ return err;
+ /* Create a new node set NEW_NODES with the nodes which are epsilon
+ closures of the node in CUR_NODES. */
+
+ for (idx = 0; idx < cur_nodes->nelem; ++idx)
+ {
+ int cur_node = cur_nodes->elems[idx];
+ const re_node_set *eclosure = dfa->eclosures + cur_node;
+ outside_node = find_subexp_node (dfa, eclosure, ex_subexp, type);
+ if (outside_node == -1)
+ {
+ /* There are no problematic nodes, just merge them. */
+ err = re_node_set_merge (&new_nodes, eclosure);
+ if (BE (err != REG_NOERROR, 0))
+ {
+ re_node_set_free (&new_nodes);
+ return err;
+ }
+ }
+ else
+ {
+ /* There are problematic nodes, re-calculate incrementally. */
+ err = check_arrival_expand_ecl_sub (dfa, &new_nodes, cur_node,
+ ex_subexp, type);
+ if (BE (err != REG_NOERROR, 0))
+ {
+ re_node_set_free (&new_nodes);
+ return err;
+ }
+ }
+ }
+ re_node_set_free (cur_nodes);
+ *cur_nodes = new_nodes;
+ return REG_NOERROR;
+}
+
+/* Helper function for check_arrival_expand_ecl.
+ Check incrementally the epsilon closure of TARGET, and if it isn't
+ problematic append it to DST_NODES. */
+
+static reg_errcode_t
+internal_function
+check_arrival_expand_ecl_sub (const re_dfa_t *dfa, re_node_set *dst_nodes,
+ int target, int ex_subexp, int type)
+{
+ int cur_node;
+ for (cur_node = target; !re_node_set_contains (dst_nodes, cur_node);)
+ {
+ int err;
+
+ if (dfa->nodes[cur_node].type == type
+ && dfa->nodes[cur_node].opr.idx == ex_subexp)
+ {
+ if (type == OP_CLOSE_SUBEXP)
+ {
+ err = re_node_set_insert (dst_nodes, cur_node);
+ if (BE (err == -1, 0))
+ return REG_ESPACE;
+ }
+ break;
+ }
+ err = re_node_set_insert (dst_nodes, cur_node);
+ if (BE (err == -1, 0))
+ return REG_ESPACE;
+ if (dfa->edests[cur_node].nelem == 0)
+ break;
+ if (dfa->edests[cur_node].nelem == 2)
+ {
+ err = check_arrival_expand_ecl_sub (dfa, dst_nodes,
+ dfa->edests[cur_node].elems[1],
+ ex_subexp, type);
+ if (BE (err != REG_NOERROR, 0))
+ return err;
+ }
+ cur_node = dfa->edests[cur_node].elems[0];
+ }
+ return REG_NOERROR;
+}
+
+
+/* For all the back references in the current state, calculate the
+ destination of the back references by the appropriate entry
+ in MCTX->BKREF_ENTS. */
+
+static reg_errcode_t
+internal_function
+expand_bkref_cache (re_match_context_t *mctx, re_node_set *cur_nodes,
+ int cur_str, int subexp_num, int type)
+{
+ const re_dfa_t *const dfa = mctx->dfa;
+ reg_errcode_t err;
+ int cache_idx_start = search_cur_bkref_entry (mctx, cur_str);
+ struct re_backref_cache_entry *ent;
+
+ if (cache_idx_start == -1)
+ return REG_NOERROR;
+
+ restart:
+ ent = mctx->bkref_ents + cache_idx_start;
+ do
+ {
+ int to_idx, next_node;
+
+ /* Is this entry ENT is appropriate? */
+ if (!re_node_set_contains (cur_nodes, ent->node))
+ continue; /* No. */
+
+ to_idx = cur_str + ent->subexp_to - ent->subexp_from;
+ /* Calculate the destination of the back reference, and append it
+ to MCTX->STATE_LOG. */
+ if (to_idx == cur_str)
+ {
+ /* The backreference did epsilon transit, we must re-check all the
+ node in the current state. */
+ re_node_set new_dests;
+ reg_errcode_t err2, err3;
+ next_node = dfa->edests[ent->node].elems[0];
+ if (re_node_set_contains (cur_nodes, next_node))
+ continue;
+ err = re_node_set_init_1 (&new_dests, next_node);
+ err2 = check_arrival_expand_ecl (dfa, &new_dests, subexp_num, type);
+ err3 = re_node_set_merge (cur_nodes, &new_dests);
+ re_node_set_free (&new_dests);
+ if (BE (err != REG_NOERROR || err2 != REG_NOERROR
+ || err3 != REG_NOERROR, 0))
+ {
+ err = (err != REG_NOERROR ? err
+ : (err2 != REG_NOERROR ? err2 : err3));
+ return err;
+ }
+ /* TODO: It is still inefficient... */
+ goto restart;
+ }
+ else
+ {
+ re_node_set union_set;
+ next_node = dfa->nexts[ent->node];
+ if (mctx->state_log[to_idx])
+ {
+ int ret;
+ if (re_node_set_contains (&mctx->state_log[to_idx]->nodes,
+ next_node))
+ continue;
+ err = re_node_set_init_copy (&union_set,
+ &mctx->state_log[to_idx]->nodes);
+ ret = re_node_set_insert (&union_set, next_node);
+ if (BE (err != REG_NOERROR || ret < 0, 0))
+ {
+ re_node_set_free (&union_set);
+ err = err != REG_NOERROR ? err : REG_ESPACE;
+ return err;
+ }
+ }
+ else
+ {
+ err = re_node_set_init_1 (&union_set, next_node);
+ if (BE (err != REG_NOERROR, 0))
+ return err;
+ }
+ mctx->state_log[to_idx] = re_acquire_state (&err, dfa, &union_set);
+ re_node_set_free (&union_set);
+ if (BE (mctx->state_log[to_idx] == NULL
+ && err != REG_NOERROR, 0))
+ return err;
+ }
+ }
+ while (ent++->more);
+ return REG_NOERROR;
+}
+
+/* Build transition table for the state.
+ Return 1 if succeeded, otherwise return NULL. */
+
+static int
+internal_function
+build_trtable (const re_dfa_t *dfa, re_dfastate_t *state)
+{
+ reg_errcode_t err;
+ int i, j, ch, need_word_trtable = 0;
+ bitset_word_t elem, mask;
+ bool dests_node_malloced = false;
+ bool dest_states_malloced = false;
+ int ndests; /* Number of the destination states from `state'. */
+ re_dfastate_t **trtable;
+ re_dfastate_t **dest_states = NULL, **dest_states_word, **dest_states_nl;
+ re_node_set follows, *dests_node;
+ bitset_t *dests_ch;
+ bitset_t acceptable;
+
+ struct dests_alloc
+ {
+ re_node_set dests_node[SBC_MAX];
+ bitset_t dests_ch[SBC_MAX];
+ } *dests_alloc;
+
+ /* We build DFA states which corresponds to the destination nodes
+ from `state'. `dests_node[i]' represents the nodes which i-th
+ destination state contains, and `dests_ch[i]' represents the
+ characters which i-th destination state accepts. */
+ if (__libc_use_alloca (sizeof (struct dests_alloc)))
+ dests_alloc = (struct dests_alloc *) alloca (sizeof (struct dests_alloc));
+ else
+ {
+ dests_alloc = re_malloc (struct dests_alloc, 1);
+ if (BE (dests_alloc == NULL, 0))
+ return 0;
+ dests_node_malloced = true;
+ }
+ dests_node = dests_alloc->dests_node;
+ dests_ch = dests_alloc->dests_ch;
+
+ /* Initialize transiton table. */
+ state->word_trtable = state->trtable = NULL;
+
+ /* At first, group all nodes belonging to `state' into several
+ destinations. */
+ ndests = group_nodes_into_DFAstates (dfa, state, dests_node, dests_ch);
+ if (BE (ndests <= 0, 0))
+ {
+ if (dests_node_malloced)
+ free (dests_alloc);
+ /* Return 0 in case of an error, 1 otherwise. */
+ if (ndests == 0)
+ {
+ state->trtable = (re_dfastate_t **)
+ calloc (sizeof (re_dfastate_t *), SBC_MAX);
+ return 1;
+ }
+ return 0;
+ }
+
+ err = re_node_set_alloc (&follows, ndests + 1);
+ if (BE (err != REG_NOERROR, 0))
+ goto out_free;
+
+ if (__libc_use_alloca ((sizeof (re_node_set) + sizeof (bitset_t)) * SBC_MAX
+ + ndests * 3 * sizeof (re_dfastate_t *)))
+ dest_states = (re_dfastate_t **)
+ alloca (ndests * 3 * sizeof (re_dfastate_t *));
+ else
+ {
+ dest_states = (re_dfastate_t **)
+ malloc (ndests * 3 * sizeof (re_dfastate_t *));
+ if (BE (dest_states == NULL, 0))
+ {
+out_free:
+ if (dest_states_malloced)
+ free (dest_states);
+ re_node_set_free (&follows);
+ for (i = 0; i < ndests; ++i)
+ re_node_set_free (dests_node + i);
+ if (dests_node_malloced)
+ free (dests_alloc);
+ return 0;
+ }
+ dest_states_malloced = true;
+ }
+ dest_states_word = dest_states + ndests;
+ dest_states_nl = dest_states_word + ndests;
+ bitset_empty (acceptable);
+
+ /* Then build the states for all destinations. */
+ for (i = 0; i < ndests; ++i)
+ {
+ int next_node;
+ re_node_set_empty (&follows);
+ /* Merge the follows of this destination states. */
+ for (j = 0; j < dests_node[i].nelem; ++j)
+ {
+ next_node = dfa->nexts[dests_node[i].elems[j]];
+ if (next_node != -1)
+ {
+ err = re_node_set_merge (&follows, dfa->eclosures + next_node);
+ if (BE (err != REG_NOERROR, 0))
+ goto out_free;
+ }
+ }
+ dest_states[i] = re_acquire_state_context (&err, dfa, &follows, 0);
+ if (BE (dest_states[i] == NULL && err != REG_NOERROR, 0))
+ goto out_free;
+ /* If the new state has context constraint,
+ build appropriate states for these contexts. */
+ if (dest_states[i]->has_constraint)
+ {
+ dest_states_word[i] = re_acquire_state_context (&err, dfa, &follows,
+ CONTEXT_WORD);
+ 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)
+ need_word_trtable = 1;
+
+ dest_states_nl[i] = re_acquire_state_context (&err, dfa, &follows,
+ CONTEXT_NEWLINE);
+ if (BE (dest_states_nl[i] == NULL && err != REG_NOERROR, 0))
+ goto out_free;
+ }
+ else
+ {
+ dest_states_word[i] = dest_states[i];
+ dest_states_nl[i] = dest_states[i];
+ }
+ bitset_merge (acceptable, dests_ch[i]);
+ }
+
+ if (!BE (need_word_trtable, 0))
+ {
+ /* We don't care about whether the following character is a word
+ character, or we are in a single-byte character set so we can
+ discern by looking at the character code: allocate a
+ 256-entry transition table. */
+ trtable = state->trtable = calloc (sizeof (re_dfastate_t *), SBC_MAX);
+ if (BE (trtable == NULL, 0))
+ goto out_free;
+
+ /* For all characters ch...: */
+ for (i = 0; i < BITSET_WORDS; ++i)
+ for (ch = i * BITSET_WORD_BITS, elem = acceptable[i], mask = 1;
+ elem;
+ mask <<= 1, elem >>= 1, ++ch)
+ if (BE (elem & 1, 0))
+ {
+ /* There must be exactly one destination which accepts
+ character ch. See group_nodes_into_DFAstates. */
+ for (j = 0; (dests_ch[j][i] & mask) == 0; ++j)
+ ;
+
+ /* j-th destination accepts the word character ch. */
+ if (dfa->word_char[i] & mask)
+ trtable[ch] = dest_states_word[j];
+ else
+ trtable[ch] = dest_states[j];
+ }
+ }
+ else
+ {
+ /* We care about whether the following character is a word
+ character, and we are in a multi-byte character set: discern
+ by looking at the character code: build two 256-entry
+ transition tables, one starting at trtable[0] and one
+ starting at trtable[SBC_MAX]. */
+ trtable = state->word_trtable = calloc (sizeof (re_dfastate_t *), 2 * SBC_MAX);
+ if (BE (trtable == NULL, 0))
+ goto out_free;
+
+ /* For all characters ch...: */
+ for (i = 0; i < BITSET_WORDS; ++i)
+ for (ch = i * BITSET_WORD_BITS, elem = acceptable[i], mask = 1;
+ elem;
+ mask <<= 1, elem >>= 1, ++ch)
+ if (BE (elem & 1, 0))
+ {
+ /* There must be exactly one destination which accepts
+ character ch. See group_nodes_into_DFAstates. */
+ for (j = 0; (dests_ch[j][i] & mask) == 0; ++j)
+ ;
+
+ /* j-th destination accepts the word character ch. */
+ trtable[ch] = dest_states[j];
+ trtable[ch + SBC_MAX] = dest_states_word[j];
+ }
+ }
+
+ /* new line */
+ if (bitset_contain (acceptable, NEWLINE_CHAR))
+ {
+ /* The current state accepts newline character. */
+ for (j = 0; j < ndests; ++j)
+ if (bitset_contain (dests_ch[j], NEWLINE_CHAR))
+ {
+ /* k-th destination accepts newline character. */
+ trtable[NEWLINE_CHAR] = dest_states_nl[j];
+ if (need_word_trtable)
+ trtable[NEWLINE_CHAR + SBC_MAX] = dest_states_nl[j];
+ /* There must be only one destination which accepts
+ newline. See group_nodes_into_DFAstates. */
+ break;
+ }
+ }
+
+ if (dest_states_malloced)
+ free (dest_states);
+
+ re_node_set_free (&follows);
+ for (i = 0; i < ndests; ++i)
+ re_node_set_free (dests_node + i);
+
+ if (dests_node_malloced)
+ free (dests_alloc);
+
+ return 1;
+}
+
+/* Group all nodes belonging to STATE into several destinations.
+ Then for all destinations, set the nodes belonging to the destination
+ to DESTS_NODE[i] and set the characters accepted by the destination
+ to DEST_CH[i]. This function return the number of destinations. */
+
+static int
+internal_function
+group_nodes_into_DFAstates (const re_dfa_t *dfa, const re_dfastate_t *state,
+ re_node_set *dests_node, bitset_t *dests_ch)
+{
+ reg_errcode_t err;
+ int result;
+ int i, j, k;
+ int ndests; /* Number of the destinations from `state'. */
+ bitset_t accepts; /* Characters a node can accept. */
+ const re_node_set *cur_nodes = &state->nodes;
+ bitset_empty (accepts);
+ ndests = 0;
+
+ /* For all the nodes belonging to `state', */
+ for (i = 0; i < cur_nodes->nelem; ++i)
+ {
+ re_token_t *node = &dfa->nodes[cur_nodes->elems[i]];
+ re_token_type_t type = node->type;
+ unsigned int constraint = node->constraint;
+
+ /* Enumerate all single byte character this node can accept. */
+ if (type == CHARACTER)
+ bitset_set (accepts, node->opr.c);
+ else if (type == SIMPLE_BRACKET)
+ {
+ bitset_merge (accepts, node->opr.sbcset);
+ }
+ else if (type == OP_PERIOD)
+ {
+#ifdef RE_ENABLE_I18N
+ if (dfa->mb_cur_max > 1)
+ bitset_merge (accepts, dfa->sb_char);
+ else
+#endif
+ bitset_set_all (accepts);
+ if (!(dfa->syntax & RE_DOT_NEWLINE))
+ bitset_clear (accepts, '\n');
+ if (dfa->syntax & RE_DOT_NOT_NULL)
+ bitset_clear (accepts, '\0');
+ }
+#ifdef RE_ENABLE_I18N
+ else if (type == OP_UTF8_PERIOD)
+ {
+ memset (accepts, '\xff', sizeof (bitset_t) / 2);
+ if (!(dfa->syntax & RE_DOT_NEWLINE))
+ bitset_clear (accepts, '\n');
+ if (dfa->syntax & RE_DOT_NOT_NULL)
+ bitset_clear (accepts, '\0');
+ }
+#endif
+ else
+ continue;
+
+ /* Check the `accepts' and sift the characters which are not
+ match it the context. */
+ if (constraint)
+ {
+ if (constraint & NEXT_NEWLINE_CONSTRAINT)
+ {
+ bool accepts_newline = bitset_contain (accepts, NEWLINE_CHAR);
+ bitset_empty (accepts);
+ if (accepts_newline)
+ bitset_set (accepts, NEWLINE_CHAR);
+ else
+ continue;
+ }
+ if (constraint & NEXT_ENDBUF_CONSTRAINT)
+ {
+ bitset_empty (accepts);
+ continue;
+ }
+
+ if (constraint & NEXT_WORD_CONSTRAINT)
+ {
+ bitset_word_t any_set = 0;
+ if (type == CHARACTER && !node->word_char)
+ {
+ bitset_empty (accepts);
+ continue;
+ }
+#ifdef RE_ENABLE_I18N
+ if (dfa->mb_cur_max > 1)
+ for (j = 0; j < BITSET_WORDS; ++j)
+ any_set |= (accepts[j] &= (dfa->word_char[j] | ~dfa->sb_char[j]));
+ else
+#endif
+ for (j = 0; j < BITSET_WORDS; ++j)
+ any_set |= (accepts[j] &= dfa->word_char[j]);
+ if (!any_set)
+ continue;
+ }
+ if (constraint & NEXT_NOTWORD_CONSTRAINT)
+ {
+ bitset_word_t any_set = 0;
+ if (type == CHARACTER && node->word_char)
+ {
+ bitset_empty (accepts);
+ continue;
+ }
+#ifdef RE_ENABLE_I18N
+ if (dfa->mb_cur_max > 1)
+ for (j = 0; j < BITSET_WORDS; ++j)
+ any_set |= (accepts[j] &= ~(dfa->word_char[j] & dfa->sb_char[j]));
+ else
+#endif
+ for (j = 0; j < BITSET_WORDS; ++j)
+ any_set |= (accepts[j] &= ~dfa->word_char[j]);
+ if (!any_set)
+ continue;
+ }
+ }
+
+ /* Then divide `accepts' into DFA states, or create a new
+ state. Above, we make sure that accepts is not empty. */
+ for (j = 0; j < ndests; ++j)
+ {
+ bitset_t intersec; /* Intersection sets, see below. */
+ bitset_t remains;
+ /* Flags, see below. */
+ bitset_word_t has_intersec, not_subset, not_consumed;
+
+ /* Optimization, skip if this state doesn't accept the character. */
+ if (type == CHARACTER && !bitset_contain (dests_ch[j], node->opr.c))
+ continue;
+
+ /* Enumerate the intersection set of this state and `accepts'. */
+ has_intersec = 0;
+ for (k = 0; k < BITSET_WORDS; ++k)
+ has_intersec |= intersec[k] = accepts[k] & dests_ch[j][k];
+ /* And skip if the intersection set is empty. */
+ if (!has_intersec)
+ continue;
+
+ /* Then check if this state is a subset of `accepts'. */
+ not_subset = not_consumed = 0;
+ for (k = 0; k < BITSET_WORDS; ++k)
+ {
+ not_subset |= remains[k] = ~accepts[k] & dests_ch[j][k];
+ not_consumed |= accepts[k] = accepts[k] & ~dests_ch[j][k];
+ }
+
+ /* If this state isn't a subset of `accepts', create a
+ new group state, which has the `remains'. */
+ if (not_subset)
+ {
+ bitset_copy (dests_ch[ndests], remains);
+ bitset_copy (dests_ch[j], intersec);
+ err = re_node_set_init_copy (dests_node + ndests, &dests_node[j]);
+ if (BE (err != REG_NOERROR, 0))
+ goto error_return;
+ ++ndests;
+ }
+
+ /* Put the position in the current group. */
+ result = re_node_set_insert (&dests_node[j], cur_nodes->elems[i]);
+ if (BE (result < 0, 0))
+ goto error_return;
+
+ /* If all characters are consumed, go to next node. */
+ if (!not_consumed)
+ break;
+ }
+ /* Some characters remain, create a new group. */
+ if (j == ndests)
+ {
+ bitset_copy (dests_ch[ndests], accepts);
+ err = re_node_set_init_1 (dests_node + ndests, cur_nodes->elems[i]);
+ if (BE (err != REG_NOERROR, 0))
+ goto error_return;
+ ++ndests;
+ bitset_empty (accepts);
+ }
+ }
+ return ndests;
+ error_return:
+ for (j = 0; j < ndests; ++j)
+ re_node_set_free (dests_node + j);
+ return -1;
+}
+
+#ifdef RE_ENABLE_I18N
+/* Check how many bytes the node `dfa->nodes[node_idx]' accepts.
+ Return the number of the bytes the node accepts.
+ STR_IDX is the current index of the input string.
+
+ This function handles the nodes which can accept one character, or
+ one collating element like '.', '[a-z]', opposite to the other nodes
+ can only accept one byte. */
+
+static int
+internal_function
+check_node_accept_bytes (const re_dfa_t *dfa, int node_idx,
+ const re_string_t *input, int str_idx)
+{
+ const re_token_t *node = dfa->nodes + node_idx;
+ int char_len, elem_len;
+ int i;
+
+ if (BE (node->type == OP_UTF8_PERIOD, 0))
+ {
+ unsigned char c = re_string_byte_at (input, str_idx), d;
+ if (BE (c < 0xc2, 1))
+ return 0;
+
+ if (str_idx + 2 > input->len)
+ return 0;
+
+ d = re_string_byte_at (input, str_idx + 1);
+ if (c < 0xe0)
+ return (d < 0x80 || d > 0xbf) ? 0 : 2;
+ else if (c < 0xf0)
+ {
+ char_len = 3;
+ if (c == 0xe0 && d < 0xa0)
+ return 0;
+ }
+ else if (c < 0xf8)
+ {
+ char_len = 4;
+ if (c == 0xf0 && d < 0x90)
+ return 0;
+ }
+ else if (c < 0xfc)
+ {
+ char_len = 5;
+ if (c == 0xf8 && d < 0x88)
+ return 0;
+ }
+ else if (c < 0xfe)
+ {
+ char_len = 6;
+ if (c == 0xfc && d < 0x84)
+ return 0;
+ }
+ else
+ return 0;
+
+ if (str_idx + char_len > input->len)
+ return 0;
+
+ for (i = 1; i < char_len; ++i)
+ {
+ d = re_string_byte_at (input, str_idx + i);
+ if (d < 0x80 || d > 0xbf)
+ return 0;
+ }
+ return char_len;
+ }
+
+ char_len = re_string_char_size_at (input, str_idx);
+ if (node->type == OP_PERIOD)
+ {
+ if (char_len <= 1)
+ return 0;
+ /* FIXME: I don't think this if is needed, as both '\n'
+ and '\0' are char_len == 1. */
+ /* '.' accepts any one character except the following two cases. */
+ if ((!(dfa->syntax & RE_DOT_NEWLINE) &&
+ re_string_byte_at (input, str_idx) == '\n') ||
+ ((dfa->syntax & RE_DOT_NOT_NULL) &&
+ re_string_byte_at (input, str_idx) == '\0'))
+ return 0;
+ return char_len;
+ }
+
+ elem_len = re_string_elem_size_at (input, str_idx);
+ if ((elem_len <= 1 && char_len <= 1) || char_len == 0)
+ return 0;
+
+ if (node->type == COMPLEX_BRACKET)
+ {
+ const re_charset_t *cset = node->opr.mbcset;
+# if 0
+ const unsigned char *pin
+ = ((const unsigned char *) re_string_get_buffer (input) + str_idx);
+ int j;
+ uint32_t nrules;
+# endif
+ int match_len = 0;
+ wchar_t wc = ((cset->nranges || cset->nchar_classes || cset->nmbchars)
+ ? re_string_wchar_at (input, str_idx) : 0);
+
+ /* match with multibyte character? */
+ for (i = 0; i < cset->nmbchars; ++i)
+ if (wc == cset->mbchars[i])
+ {
+ match_len = char_len;
+ goto check_node_accept_bytes_match;
+ }
+ /* match with character_class? */
+ for (i = 0; i < cset->nchar_classes; ++i)
+ {
+ wctype_t wt = cset->char_classes[i];
+ if (__iswctype (wc, wt))
+ {
+ match_len = char_len;
+ goto check_node_accept_bytes_match;
+ }
+ }
+
+# if 0
+ 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 char *collseqwc;
+ int32_t idx;
+ /* This #include defines a local function! */
+# include <locale/weight.h>
+
+ /* match with collating_symbol? */
+ if (cset->ncoll_syms)
+ extra = (const unsigned char *)
+ _NL_CURRENT (LC_COLLATE, _NL_COLLATE_SYMB_EXTRAMB);
+ for (i = 0; i < cset->ncoll_syms; ++i)
+ {
+ const unsigned char *coll_sym = extra + cset->coll_syms[i];
+ /* Compare the length of input collating element and
+ the length of current collating element. */
+ if (*coll_sym != elem_len)
+ continue;
+ /* Compare each bytes. */
+ for (j = 0; j < *coll_sym; j++)
+ if (pin[j] != coll_sym[1 + j])
+ break;
+ if (j == *coll_sym)
+ {
+ /* Match if every bytes is equal. */
+ match_len = j;
+ goto check_node_accept_bytes_match;
+ }
+ }
+
+ if (cset->nranges)
+ {
+ if (elem_len <= char_len)
+ {
+ collseqwc = _NL_CURRENT (LC_COLLATE, _NL_COLLATE_COLLSEQWC);
+ in_collseq = __collseq_table_lookup (collseqwc, wc);
+ }
+ else
+ in_collseq = find_collation_sequence_value (pin, elem_len);
+ }
+ /* match with range expression? */
+ for (i = 0; i < cset->nranges; ++i)
+ if (cset->range_starts[i] <= in_collseq
+ && in_collseq <= cset->range_ends[i])
+ {
+ match_len = elem_len;
+ goto check_node_accept_bytes_match;
+ }
+
+ /* match with equivalence_class? */
+ if (cset->nequiv_classes)
+ {
+ const unsigned char *cp = pin;
+ 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);
+ if (idx > 0)
+ for (i = 0; i < cset->nequiv_classes; ++i)
+ {
+ int32_t equiv_class_idx = cset->equiv_classes[i];
+ size_t weight_len = weights[idx];
+ if (weight_len == weights[equiv_class_idx])
+ {
+ int cnt = 0;
+ while (cnt <= weight_len
+ && (weights[equiv_class_idx + 1 + cnt]
+ == weights[idx + 1 + cnt]))
+ ++cnt;
+ if (cnt > weight_len)
+ {
+ match_len = elem_len;
+ goto check_node_accept_bytes_match;
+ }
+ }
+ }
+ }
+ }
+ else
+# endif
+ {
+ /* match with range expression? */
+ wchar_t cmp_buf[6];
+
+ memset (cmp_buf, 0, sizeof(cmp_buf));
+ cmp_buf[2] = wc;
+ for (i = 0; i < cset->nranges; ++i)
+ {
+ cmp_buf[0] = cset->range_starts[i];
+ cmp_buf[4] = cset->range_ends[i];
+ if (wcscoll (cmp_buf, cmp_buf + 2) <= 0
+ && wcscoll (cmp_buf + 2, cmp_buf + 4) <= 0)
+ {
+ match_len = char_len;
+ goto check_node_accept_bytes_match;
+ }
+ }
+ }
+
+ check_node_accept_bytes_match:
+ if (!cset->non_match)
+ return match_len;
+ if (match_len > 0)
+ return 0;
+ return (elem_len > char_len) ? elem_len : char_len;
+ }
+ return 0;
+}
+
+# if 0
+static unsigned int
+internal_function
+find_collation_sequence_value (const unsigned char *mbs, size_t mbs_len)
+{
+ uint32_t nrules = _NL_CURRENT_WORD (LC_COLLATE, _NL_COLLATE_NRULES);
+ if (nrules == 0)
+ {
+ if (mbs_len == 1)
+ {
+ /* No valid character. Match it as a single byte character. */
+ const unsigned char *collseq = (const unsigned char *)
+ _NL_CURRENT (LC_COLLATE, _NL_COLLATE_COLLSEQMB);
+ return collseq[mbs[0]];
+ }
+ return UINT_MAX;
+ }
+ else
+ {
+ int32_t idx;
+ const unsigned char *extra = (const unsigned char *)
+ _NL_CURRENT (LC_COLLATE, _NL_COLLATE_SYMB_EXTRAMB);
+ int32_t extrasize = (const unsigned char *)
+ _NL_CURRENT (LC_COLLATE, _NL_COLLATE_SYMB_EXTRAMB + 1) - extra;
+
+ for (idx = 0; idx < extrasize;)
+ {
+ int mbs_cnt, found = 0;
+ int32_t elem_mbs_len;
+ /* Skip the name of collating element name. */
+ idx = idx + extra[idx] + 1;
+ elem_mbs_len = extra[idx++];
+ if (mbs_len == elem_mbs_len)
+ {
+ for (mbs_cnt = 0; mbs_cnt < elem_mbs_len; ++mbs_cnt)
+ if (extra[idx + mbs_cnt] != mbs[mbs_cnt])
+ break;
+ if (mbs_cnt == elem_mbs_len)
+ /* Found the entry. */
+ found = 1;
+ }
+ /* Skip the byte sequence of the collating element. */
+ idx += elem_mbs_len;
+ /* Adjust for the alignment. */
+ idx = (idx + 3) & ~3;
+ /* Skip the collation sequence value. */
+ idx += sizeof (uint32_t);
+ /* Skip the wide char sequence of the collating element. */
+ idx = idx + sizeof (uint32_t) * (extra[idx] + 1);
+ /* If we found the entry, return the sequence value. */
+ if (found)
+ return *(uint32_t *) (extra + idx);
+ /* Skip the collation sequence value. */
+ idx += sizeof (uint32_t);
+ }
+ return UINT_MAX;
+ }
+}
+# endif
+#endif /* RE_ENABLE_I18N */
+
+/* Check whether the node accepts the byte which is IDX-th
+ byte of the INPUT. */
+
+static int
+internal_function
+check_node_accept (const re_match_context_t *mctx, const re_token_t *node,
+ int idx)
+{
+ unsigned char ch;
+ ch = re_string_byte_at (&mctx->input, idx);
+ switch (node->type)
+ {
+ case CHARACTER:
+ if (node->opr.c != ch)
+ return 0;
+ break;
+
+ case SIMPLE_BRACKET:
+ if (!bitset_contain (node->opr.sbcset, ch))
+ return 0;
+ break;
+
+#ifdef RE_ENABLE_I18N
+ case OP_UTF8_PERIOD:
+ if (ch >= 0x80)
+ return 0;
+ /* FALLTHROUGH */
+#endif
+ case OP_PERIOD:
+ if ((ch == '\n' && !(mctx->dfa->syntax & RE_DOT_NEWLINE))
+ || (ch == '\0' && (mctx->dfa->syntax & RE_DOT_NOT_NULL)))
+ return 0;
+ break;
+
+ default:
+ return 0;
+ }
+
+ if (node->constraint)
+ {
+ /* The node has constraints. Check whether the current context
+ satisfies the constraints. */
+ unsigned int context = re_string_context_at (&mctx->input, idx,
+ mctx->eflags);
+ if (NOT_SATISFY_NEXT_CONSTRAINT (node->constraint, context))
+ return 0;
+ }
+
+ return 1;
+}
+
+/* Extend the buffers, if the buffers have run out. */
+
+static reg_errcode_t
+internal_function
+extend_buffers (re_match_context_t *mctx)
+{
+ reg_errcode_t ret;
+ re_string_t *pstr = &mctx->input;
+
+ /* Double the lengthes of the buffers. */
+ ret = re_string_realloc_buffers (pstr, pstr->bufs_len * 2);
+ if (BE (ret != REG_NOERROR, 0))
+ return ret;
+
+ if (mctx->state_log != NULL)
+ {
+ /* And double the length of state_log. */
+ /* XXX We have no indication of the size of this buffer. If this
+ allocation fail we have no indication that the state_log array
+ does not have the right size. */
+ re_dfastate_t **new_array = re_realloc (mctx->state_log, re_dfastate_t *,
+ pstr->bufs_len + 1);
+ if (BE (new_array == NULL, 0))
+ return REG_ESPACE;
+ mctx->state_log = new_array;
+ }
+
+ /* Then reconstruct the buffers. */
+ if (pstr->icase)
+ {
+#ifdef RE_ENABLE_I18N
+ if (pstr->mb_cur_max > 1)
+ {
+ ret = build_wcs_upper_buffer (pstr);
+ if (BE (ret != REG_NOERROR, 0))
+ return ret;
+ }
+ else
+#endif /* RE_ENABLE_I18N */
+ build_upper_buffer (pstr);
+ }
+ else
+ {
+#ifdef RE_ENABLE_I18N
+ if (pstr->mb_cur_max > 1)
+ build_wcs_buffer (pstr);
+ else
+#endif /* RE_ENABLE_I18N */
+ {
+ if (pstr->trans != NULL)
+ re_string_translate_buffer (pstr);
+ }
+ }
+ return REG_NOERROR;
+}
+
+
+/* Functions for matching context. */
+
+/* Initialize MCTX. */
+
+static reg_errcode_t
+internal_function
+match_ctx_init (re_match_context_t *mctx, int eflags, int n)
+{
+ mctx->eflags = eflags;
+ mctx->match_last = -1;
+ if (n > 0)
+ {
+ mctx->bkref_ents = re_malloc (struct re_backref_cache_entry, n);
+ mctx->sub_tops = re_malloc (re_sub_match_top_t *, n);
+ if (BE (mctx->bkref_ents == NULL || mctx->sub_tops == NULL, 0))
+ return REG_ESPACE;
+ }
+ /* Already zero-ed by the caller.
+ else
+ mctx->bkref_ents = NULL;
+ mctx->nbkref_ents = 0;
+ mctx->nsub_tops = 0; */
+ mctx->abkref_ents = n;
+ mctx->max_mb_elem_len = 1;
+ mctx->asub_tops = n;
+ return REG_NOERROR;
+}
+
+/* Clean the entries which depend on the current input in MCTX.
+ This function must be invoked when the matcher changes the start index
+ of the input, or changes the input string. */
+
+static void
+internal_function
+match_ctx_clean (re_match_context_t *mctx)
+{
+ int st_idx;
+ for (st_idx = 0; st_idx < mctx->nsub_tops; ++st_idx)
+ {
+ int sl_idx;
+ re_sub_match_top_t *top = mctx->sub_tops[st_idx];
+ for (sl_idx = 0; sl_idx < top->nlasts; ++sl_idx)
+ {
+ re_sub_match_last_t *last = top->lasts[sl_idx];
+ re_free (last->path.array);
+ re_free (last);
+ }
+ re_free (top->lasts);
+ if (top->path)
+ {
+ re_free (top->path->array);
+ re_free (top->path);
+ }
+ free (top);
+ }
+
+ mctx->nsub_tops = 0;
+ mctx->nbkref_ents = 0;
+}
+
+/* Free all the memory associated with MCTX. */
+
+static void
+internal_function
+match_ctx_free (re_match_context_t *mctx)
+{
+ /* First, free all the memory associated with MCTX->SUB_TOPS. */
+ match_ctx_clean (mctx);
+ re_free (mctx->sub_tops);
+ re_free (mctx->bkref_ents);
+}
+
+/* Add a new backreference entry to MCTX.
+ Note that we assume that caller never call this function with duplicate
+ entry, and call with STR_IDX which isn't smaller than any existing entry.
+*/
+
+static reg_errcode_t
+internal_function
+match_ctx_add_entry (re_match_context_t *mctx, int node, int str_idx, int from,
+ int to)
+{
+ if (mctx->nbkref_ents >= mctx->abkref_ents)
+ {
+ struct re_backref_cache_entry* new_entry;
+ new_entry = re_realloc (mctx->bkref_ents, struct re_backref_cache_entry,
+ mctx->abkref_ents * 2);
+ if (BE (new_entry == NULL, 0))
+ {
+ re_free (mctx->bkref_ents);
+ return REG_ESPACE;
+ }
+ mctx->bkref_ents = new_entry;
+ memset (mctx->bkref_ents + mctx->nbkref_ents, '\0',
+ sizeof (struct re_backref_cache_entry) * mctx->abkref_ents);
+ mctx->abkref_ents *= 2;
+ }
+ if (mctx->nbkref_ents > 0
+ && mctx->bkref_ents[mctx->nbkref_ents - 1].str_idx == str_idx)
+ mctx->bkref_ents[mctx->nbkref_ents - 1].more = 1;
+
+ mctx->bkref_ents[mctx->nbkref_ents].node = node;
+ mctx->bkref_ents[mctx->nbkref_ents].str_idx = str_idx;
+ mctx->bkref_ents[mctx->nbkref_ents].subexp_from = from;
+ mctx->bkref_ents[mctx->nbkref_ents].subexp_to = to;
+
+ /* This is a cache that saves negative results of check_dst_limits_calc_pos.
+ If bit N is clear, means that this entry won't epsilon-transition to
+ an OP_OPEN_SUBEXP or OP_CLOSE_SUBEXP for the N+1-th subexpression. If
+ it is set, check_dst_limits_calc_pos_1 will recurse and try to find one
+ such node.
+
+ A backreference does not epsilon-transition unless it is empty, so set
+ to all zeros if FROM != TO. */
+ mctx->bkref_ents[mctx->nbkref_ents].eps_reachable_subexps_map
+ = (from == to ? ~0 : 0);
+
+ mctx->bkref_ents[mctx->nbkref_ents++].more = 0;
+ if (mctx->max_mb_elem_len < to - from)
+ mctx->max_mb_elem_len = to - from;
+ return REG_NOERROR;
+}
+
+/* Search for the first entry which has the same str_idx, or -1 if none is
+ found. Note that MCTX->BKREF_ENTS is already sorted by MCTX->STR_IDX. */
+
+static int
+internal_function
+search_cur_bkref_entry (const re_match_context_t *mctx, int str_idx)
+{
+ int left, right, mid, last;
+ last = right = mctx->nbkref_ents;
+ for (left = 0; left < right;)
+ {
+ mid = (left + right) / 2;
+ if (mctx->bkref_ents[mid].str_idx < str_idx)
+ left = mid + 1;
+ else
+ right = mid;
+ }
+ if (left < last && mctx->bkref_ents[left].str_idx == str_idx)
+ return left;
+ else
+ return -1;
+}
+
+/* Register the node NODE, whose type is OP_OPEN_SUBEXP, and which matches
+ at STR_IDX. */
+
+static reg_errcode_t
+internal_function
+match_ctx_add_subtop (re_match_context_t *mctx, int node, int str_idx)
+{
+#ifdef DEBUG
+ assert (mctx->sub_tops != NULL);
+ assert (mctx->asub_tops > 0);
+#endif
+ if (BE (mctx->nsub_tops == mctx->asub_tops, 0))
+ {
+ int new_asub_tops = mctx->asub_tops * 2;
+ re_sub_match_top_t **new_array = re_realloc (mctx->sub_tops,
+ re_sub_match_top_t *,
+ new_asub_tops);
+ if (BE (new_array == NULL, 0))
+ return REG_ESPACE;
+ mctx->sub_tops = new_array;
+ mctx->asub_tops = new_asub_tops;
+ }
+ mctx->sub_tops[mctx->nsub_tops] = calloc (1, sizeof (re_sub_match_top_t));
+ if (BE (mctx->sub_tops[mctx->nsub_tops] == NULL, 0))
+ return REG_ESPACE;
+ mctx->sub_tops[mctx->nsub_tops]->node = node;
+ mctx->sub_tops[mctx->nsub_tops++]->str_idx = str_idx;
+ return REG_NOERROR;
+}
+
+/* Register the node NODE, whose type is OP_CLOSE_SUBEXP, and which matches
+ at STR_IDX, whose corresponding OP_OPEN_SUBEXP is SUB_TOP. */
+
+static re_sub_match_last_t *
+internal_function
+match_ctx_add_sublast (re_sub_match_top_t *subtop, int node, int str_idx)
+{
+ re_sub_match_last_t *new_entry;
+ if (BE (subtop->nlasts == subtop->alasts, 0))
+ {
+ int new_alasts = 2 * subtop->alasts + 1;
+ re_sub_match_last_t **new_array = re_realloc (subtop->lasts,
+ re_sub_match_last_t *,
+ new_alasts);
+ if (BE (new_array == NULL, 0))
+ return NULL;
+ subtop->lasts = new_array;
+ subtop->alasts = new_alasts;
+ }
+ new_entry = calloc (1, sizeof (re_sub_match_last_t));
+ if (BE (new_entry != NULL, 1))
+ {
+ subtop->lasts[subtop->nlasts] = new_entry;
+ new_entry->node = node;
+ new_entry->str_idx = str_idx;
+ ++subtop->nlasts;
+ }
+ return new_entry;
+}
+
+static void
+internal_function
+sift_ctx_init (re_sift_context_t *sctx, re_dfastate_t **sifted_sts,
+ re_dfastate_t **limited_sts, int last_node, int last_str_idx)
+{
+ sctx->sifted_states = sifted_sts;
+ sctx->limited_states = limited_sts;
+ sctx->last_node = last_node;
+ sctx->last_str_idx = last_str_idx;
+ re_node_set_init_empty (&sctx->limits);
+}
diff --git a/ap/build/uClibc/libc/misc/search/Makefile b/ap/build/uClibc/libc/misc/search/Makefile
new file mode 100644
index 0000000..4a8f4a0
--- /dev/null
+++ b/ap/build/uClibc/libc/misc/search/Makefile
@@ -0,0 +1,13 @@
+# Makefile for uClibc
+#
+# Copyright (C) 2000-2005 Erik Andersen <andersen@uclibc.org>
+#
+# Licensed under the LGPL v2.1, see the file COPYING.LIB in this tarball.
+#
+
+top_srcdir=../../../
+top_builddir=../../../
+all: objs
+include $(top_builddir)Rules.mak
+include Makefile.in
+include $(top_srcdir)Makerules
diff --git a/ap/build/uClibc/libc/misc/search/Makefile.in b/ap/build/uClibc/libc/misc/search/Makefile.in
new file mode 100644
index 0000000..35dacb4
--- /dev/null
+++ b/ap/build/uClibc/libc/misc/search/Makefile.in
@@ -0,0 +1,35 @@
+# Makefile for uClibc
+#
+# Copyright (C) 2000-2008 Erik Andersen <andersen@uclibc.org>
+#
+# Licensed under the LGPL v2.1, see the file COPYING.LIB in this tarball.
+#
+
+subdirs += libc/misc/search
+
+CSRC := hsearch.c
+
+# multi source _tsearch.c
+CSRC += tsearch.c tfind.c tdelete.c twalk.c tdestroy.c
+
+# multi source _lsearch.c
+CSRC += lfind.c lsearch.c
+
+# multi source insremque.c
+CSRC += insque.c remque.c
+
+# multi source _hsearch_r.c
+CSRC += hcreate_r.c hdestroy_r.c hsearch_r.c
+
+MISC_SEARCH_DIR := $(top_srcdir)libc/misc/search
+MISC_SEARCH_OUT := $(top_builddir)libc/misc/search
+
+MISC_SEARCH_SRC := $(patsubst %.c,$(MISC_SEARCH_DIR)/%.c,$(CSRC))
+MISC_SEARCH_OBJ := $(patsubst %.c,$(MISC_SEARCH_OUT)/%.o,$(CSRC))
+
+libc-y += $(MISC_SEARCH_OBJ)
+
+objclean-y += CLEAN_libc/misc/search
+
+CLEAN_libc/misc/search:
+ $(do_rm) $(addprefix $(MISC_SEARCH_OUT)/*., o os)
diff --git a/ap/build/uClibc/libc/misc/search/_hsearch_r.c b/ap/build/uClibc/libc/misc/search/_hsearch_r.c
new file mode 100644
index 0000000..bfe3efe
--- /dev/null
+++ b/ap/build/uClibc/libc/misc/search/_hsearch_r.c
@@ -0,0 +1,226 @@
+/* Copyright (C) 1993, 1995, 1996, 1997, 2002 Free Software Foundation, Inc.
+ This file is part of the GNU C Library.
+ Contributed by Ulrich Drepper <drepper@gnu.ai.mit.edu>, 1993.
+
+ 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 <errno.h>
+#include <malloc.h>
+#include <string.h>
+
+#include <search.h>
+
+
+/* [Aho,Sethi,Ullman] Compilers: Principles, Techniques and Tools, 1986
+ [Knuth] The Art of Computer Programming, part 3 (6.4) */
+
+
+/* The reentrant version has no static variables to maintain the state.
+ Instead the interface of all functions is extended to take an argument
+ which describes the current status. */
+typedef struct _ENTRY
+{
+ unsigned int used;
+ ENTRY entry;
+}
+_ENTRY;
+
+
+#ifdef L_hcreate_r
+
+/* For the used double hash method the table size has to be a prime. To
+ correct the user given table size we need a prime test. This trivial
+ algorithm is adequate because
+ a) the code is (most probably) called a few times per program run and
+ b) the number is small because the table must fit in the core */
+static int isprime (unsigned int number)
+{
+ /* no even number will be passed */
+ unsigned int divisor = 3;
+
+ while (divisor * divisor < number && number % divisor != 0)
+ divisor += 2;
+
+ return number % divisor != 0;
+}
+
+
+/* Before using the hash table we must allocate memory for it.
+ Test for an existing table are done. We allocate one element
+ more as the found prime number says. This is done for more effective
+ indexing as explained in the comment for the hsearch function.
+ The contents of the table is zeroed, especially the field used
+ becomes zero. */
+int hcreate_r (size_t nel, struct hsearch_data *htab)
+{
+ /* Test for correct arguments. */
+ if (htab == NULL)
+ {
+ __set_errno (EINVAL);
+ return 0;
+ }
+
+ /* There is still another table active. Return with error. */
+ if (htab->table != NULL)
+ return 0;
+
+ /* Change nel to the first prime number not smaller as nel. */
+ nel |= 1; /* make odd */
+ while (!isprime (nel))
+ nel += 2;
+
+ htab->size = nel;
+ htab->filled = 0;
+
+ /* allocate memory and zero out */
+ htab->table = (_ENTRY *) calloc (htab->size + 1, sizeof (_ENTRY));
+ if (htab->table == NULL)
+ return 0;
+
+ /* everything went alright */
+ return 1;
+}
+libc_hidden_def(hcreate_r)
+#endif
+
+#ifdef L_hdestroy_r
+/* After using the hash table it has to be destroyed. The used memory can
+ be freed and the local static variable can be marked as not used. */
+void hdestroy_r (struct hsearch_data *htab)
+{
+ /* Test for correct arguments. */
+ if (htab == NULL)
+ {
+ __set_errno (EINVAL);
+ return;
+ }
+
+ /* free used memory */
+ free (htab->table);
+
+ /* the sign for an existing table is an value != NULL in htable */
+ htab->table = NULL;
+}
+libc_hidden_def(hdestroy_r)
+#endif
+
+#ifdef L_hsearch_r
+/* This is the search function. It uses double hashing with open addressing.
+ The argument item.key has to be a pointer to an zero terminated, most
+ probably strings of chars. The function for generating a number of the
+ strings is simple but fast. It can be replaced by a more complex function
+ like ajw (see [Aho,Sethi,Ullman]) if the needs are shown.
+
+ We use an trick to speed up the lookup. The table is created by hcreate
+ with one more element available. This enables us to use the index zero
+ special. This index will never be used because we store the first hash
+ index in the field used where zero means not used. Every other value
+ means used. The used field can be used as a first fast comparison for
+ equality of the stored and the parameter value. This helps to prevent
+ unnecessary expensive calls of strcmp. */
+
+
+int hsearch_r (ENTRY item, ACTION action, ENTRY **retval,
+ struct hsearch_data *htab)
+{
+ unsigned int hval;
+ unsigned int count;
+ unsigned int len = strlen (item.key);
+ unsigned int idx;
+
+ /* Compute an value for the given string. Perhaps use a better method. */
+ hval = len;
+ count = len;
+ while (count-- > 0)
+ {
+ hval <<= 4;
+ hval += item.key[count];
+ }
+
+ /* First hash function: simply take the modul but prevent zero. */
+ hval %= htab->size;
+ if (hval == 0)
+ ++hval;
+
+ /* The first index tried. */
+ idx = hval;
+
+ if (htab->table[idx].used)
+ {
+ /* Further action might be required according to the action value. */
+ unsigned hval2;
+
+ if (htab->table[idx].used == hval
+ && strcmp (item.key, htab->table[idx].entry.key) == 0)
+ {
+ *retval = &htab->table[idx].entry;
+ return 1;
+ }
+
+ /* Second hash function, as suggested in [Knuth] */
+ hval2 = 1 + hval % (htab->size - 2);
+
+ do
+ {
+ /* Because SIZE is prime this guarantees to step through all
+ available indeces. */
+ if (idx <= hval2)
+ idx = htab->size + idx - hval2;
+ else
+ idx -= hval2;
+
+ /* If we visited all entries leave the loop unsuccessfully. */
+ if (idx == hval)
+ break;
+
+ /* If entry is found use it. */
+ if (htab->table[idx].used == hval
+ && strcmp (item.key, htab->table[idx].entry.key) == 0)
+ {
+ *retval = &htab->table[idx].entry;
+ return 1;
+ }
+ }
+ while (htab->table[idx].used);
+ }
+
+ /* An empty bucket has been found. */
+ if (action == ENTER)
+ {
+ /* If table is full and another entry should be entered return
+ with error. */
+ if (htab->filled == htab->size)
+ {
+ __set_errno (ENOMEM);
+ *retval = NULL;
+ return 0;
+ }
+
+ htab->table[idx].used = hval;
+ htab->table[idx].entry = item;
+
+ ++htab->filled;
+
+ *retval = &htab->table[idx].entry;
+ return 1;
+ }
+
+ __set_errno (ESRCH);
+ *retval = NULL;
+ return 0;
+}
+libc_hidden_def(hsearch_r)
+#endif
diff --git a/ap/build/uClibc/libc/misc/search/_lsearch.c b/ap/build/uClibc/libc/misc/search/_lsearch.c
new file mode 100644
index 0000000..0cf496e
--- /dev/null
+++ b/ap/build/uClibc/libc/misc/search/_lsearch.c
@@ -0,0 +1,49 @@
+/*
+ * This file lifted in toto from 'Dlibs' on the atari ST (RdeBath)
+ *
+ *
+ * Dale Schumacher 399 Beacon Ave.
+ * (alias: Dalnefre') St. Paul, MN 55104
+ * dal@syntel.UUCP United States of America
+ * "It's not reality that's important, but how you perceive things."
+ */
+
+#include <string.h>
+#include <stdio.h>
+#include <search.h>
+
+
+#ifdef L_lfind
+
+void *lfind(const void *key, const void *base, size_t *nmemb,
+ size_t size, int (*compar)(const void *, const void *))
+{
+ register int n = *nmemb;
+
+ while (n--) {
+ if ((*compar) (key, base) == 0)
+ return ((void*)base);
+ base += size;
+ }
+ return (NULL);
+}
+libc_hidden_def(lfind)
+
+#endif
+
+#ifdef L_lsearch
+
+
+void *lsearch(const void *key, void *base, size_t *nmemb,
+ size_t size, int (*compar)(const void *, const void *))
+{
+ register char *p;
+
+ if ((p = lfind(key, base, nmemb, size, compar)) == NULL) {
+ p = memcpy((base + (size * (*nmemb))), key, size);
+ ++(*nmemb);
+ }
+ return (p);
+}
+
+#endif
diff --git a/ap/build/uClibc/libc/misc/search/_tsearch.c b/ap/build/uClibc/libc/misc/search/_tsearch.c
new file mode 100644
index 0000000..20b04af
--- /dev/null
+++ b/ap/build/uClibc/libc/misc/search/_tsearch.c
@@ -0,0 +1,220 @@
+/* Copyright (C) 1994 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 Library General Public License as
+published by the Free Software Foundation; either version 2 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
+Library General Public License for more details.
+
+You should have received a copy of the GNU Library General Public
+License along with the GNU C Library; see the file COPYING.LIB. If
+not, write to the Free Software Foundation, Inc., 675 Mass Ave,
+Cambridge, MA 02139, USA. */
+
+/*
+ * Tree search generalized from Knuth (6.2.2) Algorithm T just like
+ * the AT&T man page says.
+ *
+ * The node_t structure is for internal use only, lint doesn't grok it.
+ *
+ * Written by reading the System V Interface Definition, not the code.
+ *
+ * Totally public domain.
+ */
+/*LINTLIBRARY*/
+
+#include <search.h>
+#include <stdlib.h>
+
+/* This routine is not very bad. It makes many assumptions about
+ * the compiler. It assumpts that the first field in node must be
+ * the "key" field, which points to the datum. It is a very trick
+ * stuff. H.J.
+ */
+
+typedef struct node_t
+{
+ void *key;
+ struct node_t *left, *right;
+} node;
+
+#ifdef L_tsearch
+/* find or insert datum into search tree.
+char *key; key to be located
+register node **rootp; address of tree root
+int (*compar)(); ordering function
+*/
+
+void *tsearch(__const void *key, void **vrootp, __compar_fn_t compar)
+{
+ register node *q;
+ register node **rootp = (node **) vrootp;
+
+ if (rootp == (struct node_t **)0)
+ return ((struct node_t *)0);
+ while (*rootp != (struct node_t *)0) /* Knuth's T1: */
+ {
+ int r;
+
+ if ((r = (*compar)(key, (*rootp)->key)) == 0) /* T2: */
+ return (*rootp); /* we found it! */
+ rootp = (r < 0) ?
+ &(*rootp)->left : /* T3: follow left branch */
+ &(*rootp)->right; /* T4: follow right branch */
+ }
+ q = (node *) malloc(sizeof(node)); /* T5: key not found */
+ if (q != (struct node_t *)0) /* make new node */
+ {
+ *rootp = q; /* link new node to old */
+ q->key = (void *)key; /* initialize new node */
+ q->left = q->right = (struct node_t *)0;
+ }
+ return (q);
+}
+libc_hidden_def(tsearch)
+#endif
+
+#ifdef L_tfind
+void *tfind(__const void *key, void * __const *vrootp, __compar_fn_t compar)
+{
+ register node **rootp = (node **) vrootp;
+
+ if (rootp == (struct node_t **)0)
+ return ((struct node_t *)0);
+ while (*rootp != (struct node_t *)0) /* Knuth's T1: */
+ {
+ int r;
+
+ if ((r = (*compar)(key, (*rootp)->key)) == 0) /* T2: */
+ return (*rootp); /* we found it! */
+ rootp = (r < 0) ?
+ &(*rootp)->left : /* T3: follow left branch */
+ &(*rootp)->right; /* T4: follow right branch */
+ }
+ return NULL;
+}
+libc_hidden_def(tfind)
+#endif
+
+#ifdef L_tdelete
+/* delete node with given key
+char *key; key to be deleted
+register node **rootp; address of the root of tree
+int (*compar)(); comparison function
+*/
+void *tdelete(__const void *key, void ** vrootp, __compar_fn_t compar)
+{
+ node *p;
+ register node *q;
+ register node *r;
+ int cmp;
+ register node **rootp = (node **) vrootp;
+
+ if (rootp == (struct node_t **)0 || (p = *rootp) == (struct node_t *)0)
+ return ((struct node_t *)0);
+ while ((cmp = (*compar)(key, (*rootp)->key)) != 0)
+ {
+ p = *rootp;
+ rootp = (cmp < 0) ?
+ &(*rootp)->left : /* follow left branch */
+ &(*rootp)->right; /* follow right branch */
+ if (*rootp == (struct node_t *)0)
+ return ((struct node_t *)0); /* key not found */
+ }
+ r = (*rootp)->right; /* D1: */
+ if ((q = (*rootp)->left) == (struct node_t *)0) /* Left (struct node_t *)0? */
+ q = r;
+ else if (r != (struct node_t *)0) /* Right link is null? */
+ {
+ if (r->left == (struct node_t *)0) /* D2: Find successor */
+ {
+ r->left = q;
+ q = r;
+ }
+ else
+ { /* D3: Find (struct node_t *)0 link */
+ for (q = r->left; q->left != (struct node_t *)0; q = r->left)
+ r = q;
+ r->left = q->right;
+ q->left = (*rootp)->left;
+ q->right = (*rootp)->right;
+ }
+ }
+ free((struct node_t *) *rootp); /* D4: Free node */
+ *rootp = q; /* link parent to new node */
+ return(p);
+}
+#endif
+
+#ifdef L_twalk
+/* Walk the nodes of a tree
+register node *root; Root of the tree to be walked
+register void (*action)(); Function to be called at each node
+register int level;
+*/
+static void trecurse(__const void *vroot, __action_fn_t action, int level)
+{
+ register node *root = (node *) vroot;
+
+ if (root->left == (struct node_t *)0 && root->right == (struct node_t *)0)
+ (*action)(root, leaf, level);
+ else
+ {
+ (*action)(root, preorder, level);
+ if (root->left != (struct node_t *)0)
+ trecurse(root->left, action, level + 1);
+ (*action)(root, postorder, level);
+ if (root->right != (struct node_t *)0)
+ trecurse(root->right, action, level + 1);
+ (*action)(root, endorder, level);
+ }
+}
+
+/* void twalk(root, action) Walk the nodes of a tree
+node *root; Root of the tree to be walked
+void (*action)(); Function to be called at each node
+PTR
+*/
+void twalk(__const void *vroot, __action_fn_t action)
+{
+ register __const node *root = (node *) vroot;
+
+ if (root != (node *)0 && action != (__action_fn_t) 0)
+ trecurse(root, action, 0);
+}
+#endif
+
+#ifdef __USE_GNU
+#ifdef L_tdestroy
+/* The standardized functions miss an important functionality: the
+ tree cannot be removed easily. We provide a function to do this. */
+static void
+internal_function
+tdestroy_recurse (node *root, __free_fn_t freefct)
+{
+ if (root->left != NULL)
+ tdestroy_recurse (root->left, freefct);
+ if (root->right != NULL)
+ tdestroy_recurse (root->right, freefct);
+ (*freefct) ((void *) root->key);
+ /* Free the node itself. */
+ free (root);
+}
+
+void tdestroy (void *vroot, __free_fn_t freefct)
+{
+ node *root = (node *) vroot;
+ if (root != NULL) {
+ tdestroy_recurse (root, freefct);
+ }
+}
+libc_hidden_def(tdestroy)
+#endif
+#endif
+
+/* tsearch.c ends here */
diff --git a/ap/build/uClibc/libc/misc/search/hcreate_r.c b/ap/build/uClibc/libc/misc/search/hcreate_r.c
new file mode 100644
index 0000000..b62991e
--- /dev/null
+++ b/ap/build/uClibc/libc/misc/search/hcreate_r.c
@@ -0,0 +1,8 @@
+/*
+ * Copyright (C) 2000-2006 Erik Andersen <andersen@uclibc.org>
+ *
+ * Licensed under the LGPL v2.1, see the file COPYING.LIB in this tarball.
+ */
+
+#define L_hcreate_r
+#include "_hsearch_r.c"
diff --git a/ap/build/uClibc/libc/misc/search/hdestroy_r.c b/ap/build/uClibc/libc/misc/search/hdestroy_r.c
new file mode 100644
index 0000000..98e1ddb
--- /dev/null
+++ b/ap/build/uClibc/libc/misc/search/hdestroy_r.c
@@ -0,0 +1,8 @@
+/*
+ * Copyright (C) 2000-2006 Erik Andersen <andersen@uclibc.org>
+ *
+ * Licensed under the LGPL v2.1, see the file COPYING.LIB in this tarball.
+ */
+
+#define L_hdestroy_r
+#include "_hsearch_r.c"
diff --git a/ap/build/uClibc/libc/misc/search/hsearch.c b/ap/build/uClibc/libc/misc/search/hsearch.c
new file mode 100644
index 0000000..d011997
--- /dev/null
+++ b/ap/build/uClibc/libc/misc/search/hsearch.c
@@ -0,0 +1,52 @@
+/* Copyright (C) 1993, 1995, 1996, 1997, 1998 Free Software Foundation, Inc.
+ Contributed by Ulrich Drepper <drepper@gnu.ai.mit.edu>
+ 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 <search.h>
+
+
+/* The non-reentrant version use a global space for storing the table. */
+static struct hsearch_data htab;
+
+
+/* Define the non-reentrant function using the reentrant counterparts. */
+ENTRY *hsearch (ENTRY item, ACTION action)
+{
+ ENTRY *result;
+
+ (void) hsearch_r (item, action, &result, &htab);
+
+ return result;
+}
+
+
+int hcreate (size_t nel)
+{
+ return hcreate_r (nel, &htab);
+}
+
+
+/* void __hdestroy (void) */
+void hdestroy (void)
+{
+ hdestroy_r (&htab);
+}
+
+/* Make sure the table is freed if we want to free everything before
+ exiting. */
+/* text_set_element (__libc_subfreeres, __hdestroy); */
diff --git a/ap/build/uClibc/libc/misc/search/hsearch_r.c b/ap/build/uClibc/libc/misc/search/hsearch_r.c
new file mode 100644
index 0000000..48bdf2d
--- /dev/null
+++ b/ap/build/uClibc/libc/misc/search/hsearch_r.c
@@ -0,0 +1,8 @@
+/*
+ * Copyright (C) 2000-2006 Erik Andersen <andersen@uclibc.org>
+ *
+ * Licensed under the LGPL v2.1, see the file COPYING.LIB in this tarball.
+ */
+
+#define L_hsearch_r
+#include "_hsearch_r.c"
diff --git a/ap/build/uClibc/libc/misc/search/insque.c b/ap/build/uClibc/libc/misc/search/insque.c
new file mode 100644
index 0000000..fc5bf80
--- /dev/null
+++ b/ap/build/uClibc/libc/misc/search/insque.c
@@ -0,0 +1,8 @@
+/*
+ * Copyright (C) 2000-2006 Erik Andersen <andersen@uclibc.org>
+ *
+ * Licensed under the LGPL v2.1, see the file COPYING.LIB in this tarball.
+ */
+
+#define L_insque
+#include "insremque.c"
diff --git a/ap/build/uClibc/libc/misc/search/insremque.c b/ap/build/uClibc/libc/misc/search/insremque.c
new file mode 100644
index 0000000..32edf7a
--- /dev/null
+++ b/ap/build/uClibc/libc/misc/search/insremque.c
@@ -0,0 +1,54 @@
+/* Copyright (C) 1992, 1995, 1996 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 Library General Public License as
+ published by the Free Software Foundation; either version 2 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
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library 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 <features.h>
+#include <stddef.h>
+#include <search.h>
+
+#ifdef L_insque
+
+/* Insert ELEM into a doubly-linked list, after PREV. */
+
+void
+insque (void *elem, void *prev)
+{
+ struct qelem *next = ((struct qelem *) prev)->q_forw;
+ ((struct qelem *) prev)->q_forw = (struct qelem *) elem;
+ if (next != NULL)
+ next->q_back = (struct qelem *) elem;
+ ((struct qelem *) elem)->q_forw = next;
+ ((struct qelem *) elem)->q_back = (struct qelem *) prev;
+}
+
+#endif
+
+#ifdef L_remque
+/* Unlink ELEM from the doubly-linked list that it is in. */
+
+void
+remque (void *elem)
+{
+ struct qelem *next = ((struct qelem *) elem)->q_forw;
+ struct qelem *prev = ((struct qelem *) elem)->q_back;
+ if (next != NULL)
+ next->q_back = prev;
+ if (prev != NULL)
+ prev->q_forw = (struct qelem *) next;
+}
+
+#endif
diff --git a/ap/build/uClibc/libc/misc/search/lfind.c b/ap/build/uClibc/libc/misc/search/lfind.c
new file mode 100644
index 0000000..66111c5
--- /dev/null
+++ b/ap/build/uClibc/libc/misc/search/lfind.c
@@ -0,0 +1,8 @@
+/*
+ * Copyright (C) 2000-2006 Erik Andersen <andersen@uclibc.org>
+ *
+ * Licensed under the LGPL v2.1, see the file COPYING.LIB in this tarball.
+ */
+
+#define L_lfind
+#include "_lsearch.c"
diff --git a/ap/build/uClibc/libc/misc/search/lsearch.c b/ap/build/uClibc/libc/misc/search/lsearch.c
new file mode 100644
index 0000000..1e63297
--- /dev/null
+++ b/ap/build/uClibc/libc/misc/search/lsearch.c
@@ -0,0 +1,8 @@
+/*
+ * Copyright (C) 2000-2006 Erik Andersen <andersen@uclibc.org>
+ *
+ * Licensed under the LGPL v2.1, see the file COPYING.LIB in this tarball.
+ */
+
+#define L_lsearch
+#include "_lsearch.c"
diff --git a/ap/build/uClibc/libc/misc/search/remque.c b/ap/build/uClibc/libc/misc/search/remque.c
new file mode 100644
index 0000000..bab6985
--- /dev/null
+++ b/ap/build/uClibc/libc/misc/search/remque.c
@@ -0,0 +1,8 @@
+/*
+ * Copyright (C) 2000-2006 Erik Andersen <andersen@uclibc.org>
+ *
+ * Licensed under the LGPL v2.1, see the file COPYING.LIB in this tarball.
+ */
+
+#define L_remque
+#include "insremque.c"
diff --git a/ap/build/uClibc/libc/misc/search/tdelete.c b/ap/build/uClibc/libc/misc/search/tdelete.c
new file mode 100644
index 0000000..33d9fe8
--- /dev/null
+++ b/ap/build/uClibc/libc/misc/search/tdelete.c
@@ -0,0 +1,8 @@
+/*
+ * Copyright (C) 2000-2006 Erik Andersen <andersen@uclibc.org>
+ *
+ * Licensed under the LGPL v2.1, see the file COPYING.LIB in this tarball.
+ */
+
+#define L_tdelete
+#include "_tsearch.c"
diff --git a/ap/build/uClibc/libc/misc/search/tdestroy.c b/ap/build/uClibc/libc/misc/search/tdestroy.c
new file mode 100644
index 0000000..3e397ea
--- /dev/null
+++ b/ap/build/uClibc/libc/misc/search/tdestroy.c
@@ -0,0 +1,8 @@
+/*
+ * Copyright (C) 2000-2006 Erik Andersen <andersen@uclibc.org>
+ *
+ * Licensed under the LGPL v2.1, see the file COPYING.LIB in this tarball.
+ */
+
+#define L_tdestroy
+#include "_tsearch.c"
diff --git a/ap/build/uClibc/libc/misc/search/tfind.c b/ap/build/uClibc/libc/misc/search/tfind.c
new file mode 100644
index 0000000..e5a3161
--- /dev/null
+++ b/ap/build/uClibc/libc/misc/search/tfind.c
@@ -0,0 +1,8 @@
+/*
+ * Copyright (C) 2000-2006 Erik Andersen <andersen@uclibc.org>
+ *
+ * Licensed under the LGPL v2.1, see the file COPYING.LIB in this tarball.
+ */
+
+#define L_tfind
+#include "_tsearch.c"
diff --git a/ap/build/uClibc/libc/misc/search/tsearch.c b/ap/build/uClibc/libc/misc/search/tsearch.c
new file mode 100644
index 0000000..8984fc1
--- /dev/null
+++ b/ap/build/uClibc/libc/misc/search/tsearch.c
@@ -0,0 +1,8 @@
+/*
+ * Copyright (C) 2000-2006 Erik Andersen <andersen@uclibc.org>
+ *
+ * Licensed under the LGPL v2.1, see the file COPYING.LIB in this tarball.
+ */
+
+#define L_tsearch
+#include "_tsearch.c"
diff --git a/ap/build/uClibc/libc/misc/search/twalk.c b/ap/build/uClibc/libc/misc/search/twalk.c
new file mode 100644
index 0000000..f36d341
--- /dev/null
+++ b/ap/build/uClibc/libc/misc/search/twalk.c
@@ -0,0 +1,8 @@
+/*
+ * Copyright (C) 2000-2006 Erik Andersen <andersen@uclibc.org>
+ *
+ * Licensed under the LGPL v2.1, see the file COPYING.LIB in this tarball.
+ */
+
+#define L_twalk
+#include "_tsearch.c"
diff --git a/ap/build/uClibc/libc/misc/statfs/Makefile b/ap/build/uClibc/libc/misc/statfs/Makefile
new file mode 100644
index 0000000..4a8f4a0
--- /dev/null
+++ b/ap/build/uClibc/libc/misc/statfs/Makefile
@@ -0,0 +1,13 @@
+# Makefile for uClibc
+#
+# Copyright (C) 2000-2005 Erik Andersen <andersen@uclibc.org>
+#
+# Licensed under the LGPL v2.1, see the file COPYING.LIB in this tarball.
+#
+
+top_srcdir=../../../
+top_builddir=../../../
+all: objs
+include $(top_builddir)Rules.mak
+include Makefile.in
+include $(top_srcdir)Makerules
diff --git a/ap/build/uClibc/libc/misc/statfs/Makefile.in b/ap/build/uClibc/libc/misc/statfs/Makefile.in
new file mode 100644
index 0000000..aa92d1f
--- /dev/null
+++ b/ap/build/uClibc/libc/misc/statfs/Makefile.in
@@ -0,0 +1,31 @@
+# Makefile for uClibc
+#
+# Copyright (C) 2000-2008 Erik Andersen <andersen@uclibc.org>
+#
+# Licensed under the LGPL v2.1, see the file COPYING.LIB in this tarball.
+#
+
+subdirs += libc/misc/statfs
+
+CSRC := statvfs.c fstatvfs.c
+ifeq ($(UCLIBC_HAS_LFS),y)
+ifeq ($(UCLIBC_LINUX_SPECIFIC),y)
+CSRC += fstatfs64.c statfs64.c
+endif
+CSRC += statvfs64.c fstatvfs64.c
+endif
+
+MISC_STATFS_DIR := $(top_srcdir)libc/misc/statfs
+MISC_STATFS_OUT := $(top_builddir)libc/misc/statfs
+
+MISC_STATFS_SRC := $(patsubst %.c,$(MISC_STATFS_DIR)/%.c,$(CSRC))
+MISC_STATFS_OBJ := $(patsubst %.c,$(MISC_STATFS_OUT)/%.o,$(CSRC))
+
+libc-y += $(MISC_STATFS_OBJ)
+
+libc-nomulti-$(UCLIBC_HAS_LFS) += $(MISC_STATFS_OUT)/statvfs64.o $(MISC_STATFS_OUT)/fstatvfs64.o
+
+objclean-y += CLEAN_libc/misc/statfs
+
+CLEAN_libc/misc/statfs:
+ $(do_rm) $(addprefix $(MISC_STATFS_OUT)/*., o os oS)
diff --git a/ap/build/uClibc/libc/misc/statfs/fstatfs64.c b/ap/build/uClibc/libc/misc/statfs/fstatfs64.c
new file mode 100644
index 0000000..27bb8d6
--- /dev/null
+++ b/ap/build/uClibc/libc/misc/statfs/fstatfs64.c
@@ -0,0 +1,51 @@
+/* Return information about the filesystem on which FD resides.
+ Copyright (C) 1996, 1997, 1998, 1999, 2000 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 <_lfs_64.h>
+
+#include <errno.h>
+#include <string.h>
+#include <sys/statfs.h>
+#include <sys/statvfs.h>
+#include <stddef.h>
+
+extern __typeof(fstatfs) __libc_fstatfs;
+
+/* Return information about the filesystem on which FD resides. */
+int fstatfs64 (int fd, struct statfs64 *buf)
+{
+ struct statfs buf32;
+
+ if (__libc_fstatfs (fd, &buf32) < 0)
+ return -1;
+
+ buf->f_type = buf32.f_type;
+ buf->f_bsize = buf32.f_bsize;
+ buf->f_blocks = buf32.f_blocks;
+ buf->f_bfree = buf32.f_bfree;
+ buf->f_bavail = buf32.f_bavail;
+ buf->f_files = buf32.f_files;
+ buf->f_ffree = buf32.f_ffree;
+ buf->f_fsid = buf32.f_fsid;
+ buf->f_namelen = buf32.f_namelen;
+ memcpy (buf->f_spare, buf32.f_spare, sizeof (buf32.f_spare));
+
+ return 0;
+}
+libc_hidden_def(fstatfs64)
diff --git a/ap/build/uClibc/libc/misc/statfs/fstatvfs.c b/ap/build/uClibc/libc/misc/statfs/fstatvfs.c
new file mode 100644
index 0000000..63fce0f
--- /dev/null
+++ b/ap/build/uClibc/libc/misc/statfs/fstatvfs.c
@@ -0,0 +1,60 @@
+/* Copyright (C) 1998, 1999, 2000 Free Software Foundation, Inc.
+ This file is part of the GNU C Library.
+ Contributed by Ulrich Drepper <drepper@cygnus.com>, 1998.
+
+ 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 <features.h>
+#include <errno.h>
+#include <mntent.h>
+#include <paths.h>
+#include <string.h>
+#include <sys/mount.h>
+#include <sys/stat.h>
+#include <sys/statfs.h>
+#include <sys/statvfs.h>
+
+
+#ifndef __USE_FILE_OFFSET64
+extern int fstatfs (int __fildes, struct statfs *__buf)
+ __THROW __nonnull ((2));
+#else
+# ifdef __REDIRECT_NTH
+extern int __REDIRECT_NTH (fstatfs, (int __fildes, struct statfs *__buf),
+ fstatfs64) __nonnull ((2));
+# else
+# define fstatfs fstatfs64
+# endif
+#endif
+
+extern __typeof(fstatfs) __libc_fstatfs;
+
+int fstatvfs (int fd, struct statvfs *buf)
+{
+ struct statfs fsbuf;
+ struct stat st;
+
+ /* Get as much information as possible from the system. */
+ if (__libc_fstatfs (fd, &fsbuf) < 0)
+ return -1;
+
+#define STAT(st) fstat (fd, st)
+#include "internal_statvfs.c"
+
+ /* We signal success if the statfs call succeeded. */
+ return 0;
+}
+libc_hidden_def(fstatvfs)
diff --git a/ap/build/uClibc/libc/misc/statfs/fstatvfs64.c b/ap/build/uClibc/libc/misc/statfs/fstatvfs64.c
new file mode 100644
index 0000000..f57e9d9
--- /dev/null
+++ b/ap/build/uClibc/libc/misc/statfs/fstatvfs64.c
@@ -0,0 +1,68 @@
+/* Copyright (C) 1998, 1999, 2000 Free Software Foundation, Inc.
+ This file is part of the GNU C Library.
+ Contributed by Ulrich Drepper <drepper@cygnus.com>, 1998.
+
+ 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 <_lfs_64.h>
+
+#include <errno.h>
+#include <mntent.h>
+#include <paths.h>
+#include <string.h>
+#include <sys/mount.h>
+#include <sys/stat.h>
+#include <sys/statfs.h>
+#include <sys/statvfs.h>
+
+
+#undef stat
+#define stat stat64
+
+int fstatvfs64 (int fd, struct statvfs64 *buf)
+{
+ struct statfs64 fsbuf;
+ struct stat64 st;
+#if !defined __UCLIBC_LINUX_SPECIFIC__
+ int ret;
+ struct statvfs buf32;
+
+ ret = fstatvfs (fd, &buf32);
+ if (ret == 0) {
+ fsbuf.f_bsize = buf32.f_bsize;
+ fsbuf.f_frsize = buf32.f_frsize;
+ fsbuf.f_blocks = buf32.f_blocks;
+ fsbuf.f_bfree = buf32.f_bfree;
+ fsbuf.f_bavail = buf32.f_bavail;
+ fsbuf.f_files = buf32.f_files;
+ fsbuf.f_ffree = buf32.f_ffree;
+ if (sizeof (fsbuf.f_fsid) == sizeof(buf32.f_fsid))
+ memcpy (&fsbuf.f_fsid, &buf32.f_fsid, sizeof(fsbuf.f_fsid));
+ /* and if not, then you could approximate or whatever.. */
+ fsbuf.f_namelen = buf32.f_namemax;
+ } else
+ return ret;
+#else
+ /* Get as much information as possible from the system. */
+ if (fstatfs64 (fd, &fsbuf) < 0)
+ return -1;
+#endif
+#define STAT(st) fstat64 (fd, st)
+#include "internal_statvfs.c"
+
+ /* We signal success if the statfs call succeeded. */
+ return 0;
+}
diff --git a/ap/build/uClibc/libc/misc/statfs/internal_statvfs.c b/ap/build/uClibc/libc/misc/statfs/internal_statvfs.c
new file mode 100644
index 0000000..6075e9c
--- /dev/null
+++ b/ap/build/uClibc/libc/misc/statfs/internal_statvfs.c
@@ -0,0 +1,111 @@
+/* Copyright (C) 1998, 1999, 2000, 2001 Free Software Foundation, Inc.
+ This file is part of the GNU C Library.
+ Contributed by Ulrich Drepper <drepper@cygnus.com>, 1998.
+
+ 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. */
+
+ /* Now fill in the fields we have information for. */
+ buf->f_bsize = fsbuf.f_bsize;
+ /* Linux does not support f_frsize, so set it to the full block size. */
+ buf->f_frsize = fsbuf.f_bsize;
+ buf->f_blocks = fsbuf.f_blocks;
+ buf->f_bfree = fsbuf.f_bfree;
+ buf->f_bavail = fsbuf.f_bavail;
+ buf->f_files = fsbuf.f_files;
+ buf->f_ffree = fsbuf.f_ffree;
+ if (sizeof (buf->f_fsid) == sizeof (fsbuf.f_fsid))
+ buf->f_fsid = (fsbuf.f_fsid.__val[0]
+ | ((unsigned long int) fsbuf.f_fsid.__val[1]
+ << (8 * (sizeof (buf->f_fsid)
+ - sizeof (fsbuf.f_fsid.__val[0])))));
+ else
+ /* We cannot help here. The statvfs element is not large enough to
+ contain both words of the statfs f_fsid field. */
+ buf->f_fsid = fsbuf.f_fsid.__val[0];
+#ifdef _STATVFSBUF_F_UNUSED
+ buf->__f_unused = 0;
+#endif
+ buf->f_namemax = fsbuf.f_namelen;
+ memset (buf->__f_spare, '\0', 6 * sizeof (int));
+
+ /* What remains to do is to fill the fields f_favail and f_flag. */
+
+ /* XXX I have no idea how to compute f_favail. Any idea??? */
+ buf->f_favail = buf->f_ffree;
+
+ /* Determining the flags is tricky. We have to read /proc/mounts or
+ the /etc/mtab file and search for the entry which matches the given
+ file. The way we can test for matching filesystem is using the
+ device number. */
+ buf->f_flag = 0;
+ if (STAT (&st) >= 0)
+ {
+ int save_errno = errno;
+ struct mntent mntbuf;
+ FILE *mtab;
+
+ mtab = setmntent ("/proc/mounts", "r");
+ if (mtab == NULL)
+ mtab = setmntent (_PATH_MOUNTED, "r");
+
+ if (mtab != NULL)
+ {
+ char tmpbuf[1024];
+
+ while (getmntent_r (mtab, &mntbuf, tmpbuf, sizeof (tmpbuf)))
+ {
+ struct stat fsst;
+
+ /* Find out about the device the current entry is for. */
+ if (stat (mntbuf.mnt_dir, &fsst) >= 0
+ && st.st_dev == fsst.st_dev)
+ {
+ /* Bingo, we found the entry for the device FD is on.
+ Now interpret the option string. */
+ char *cp = mntbuf.mnt_opts;
+ char *opt;
+
+ while ((opt = strsep (&cp, ",")) != NULL)
+ if (strcmp (opt, "ro") == 0)
+ buf->f_flag |= ST_RDONLY;
+ else if (strcmp (opt, "nosuid") == 0)
+ buf->f_flag |= ST_NOSUID;
+#ifdef __USE_GNU
+ else if (strcmp (opt, "noexec") == 0)
+ buf->f_flag |= ST_NOEXEC;
+ else if (strcmp (opt, "nodev") == 0)
+ buf->f_flag |= ST_NODEV;
+ else if (strcmp (opt, "sync") == 0)
+ buf->f_flag |= ST_SYNCHRONOUS;
+ else if (strcmp (opt, "mand") == 0)
+ buf->f_flag |= ST_MANDLOCK;
+ else if (strcmp (opt, "noatime") == 0)
+ buf->f_flag |= ST_NOATIME;
+ else if (strcmp (opt, "nodiratime") == 0)
+ buf->f_flag |= ST_NODIRATIME;
+#endif
+
+ /* We can stop looking for more entries. */
+ break;
+ }
+ }
+
+ /* Close the file. */
+ endmntent (mtab);
+ }
+
+ __set_errno (save_errno);
+ }
diff --git a/ap/build/uClibc/libc/misc/statfs/statfs64.c b/ap/build/uClibc/libc/misc/statfs/statfs64.c
new file mode 100644
index 0000000..0cc8595
--- /dev/null
+++ b/ap/build/uClibc/libc/misc/statfs/statfs64.c
@@ -0,0 +1,49 @@
+/* Return information about the filesystem on which FILE resides.
+ Copyright (C) 1996, 1997, 1998, 1999, 2000 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 <_lfs_64.h>
+
+#include <string.h>
+#include <stddef.h>
+#include <sys/statfs.h>
+
+extern __typeof(statfs) __libc_statfs;
+
+/* Return information about the filesystem on which FILE resides. */
+int statfs64 (const char *file, struct statfs64 *buf)
+{
+ struct statfs buf32;
+
+ if (__libc_statfs (file, &buf32) < 0)
+ return -1;
+
+ buf->f_type = buf32.f_type;
+ buf->f_bsize = buf32.f_bsize;
+ buf->f_blocks = buf32.f_blocks;
+ buf->f_bfree = buf32.f_bfree;
+ buf->f_bavail = buf32.f_bavail;
+ buf->f_files = buf32.f_files;
+ buf->f_ffree = buf32.f_ffree;
+ buf->f_fsid = buf32.f_fsid;
+ buf->f_namelen = buf32.f_namelen;
+ memcpy (buf->f_spare, buf32.f_spare, sizeof (buf32.f_spare));
+
+ return 0;
+}
+libc_hidden_def(statfs64)
diff --git a/ap/build/uClibc/libc/misc/statfs/statvfs.c b/ap/build/uClibc/libc/misc/statfs/statvfs.c
new file mode 100644
index 0000000..5ac38ed
--- /dev/null
+++ b/ap/build/uClibc/libc/misc/statfs/statvfs.c
@@ -0,0 +1,48 @@
+/* Copyright (C) 1998, 2000 Free Software Foundation, Inc.
+ This file is part of the GNU C Library.
+ Contributed by Ulrich Drepper <drepper@cygnus.com>, 1998.
+
+ 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 <features.h>
+#include <errno.h>
+#include <mntent.h>
+#include <paths.h>
+#include <string.h>
+#include <sys/mount.h>
+#include <sys/stat.h>
+#include <sys/statfs.h>
+#include <sys/statvfs.h>
+
+
+extern __typeof(statfs) __libc_statfs;
+
+int statvfs (const char *file, struct statvfs *buf)
+{
+ struct statfs fsbuf;
+ struct stat st;
+
+ /* Get as much information as possible from the system. */
+ if (__libc_statfs (file, &fsbuf) < 0)
+ return -1;
+
+#define STAT(st) stat (file, st)
+#include "internal_statvfs.c"
+
+ /* We signal success if the statfs call succeeded. */
+ return 0;
+}
+libc_hidden_def(statvfs)
diff --git a/ap/build/uClibc/libc/misc/statfs/statvfs64.c b/ap/build/uClibc/libc/misc/statfs/statvfs64.c
new file mode 100644
index 0000000..9923e66
--- /dev/null
+++ b/ap/build/uClibc/libc/misc/statfs/statvfs64.c
@@ -0,0 +1,68 @@
+/* Copyright (C) 1998, 2000 Free Software Foundation, Inc.
+ This file is part of the GNU C Library.
+ Contributed by Ulrich Drepper <drepper@cygnus.com>, 1998.
+
+ 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 <_lfs_64.h>
+
+#include <errno.h>
+#include <mntent.h>
+#include <paths.h>
+#include <string.h>
+#include <sys/mount.h>
+#include <sys/stat.h>
+#include <sys/statfs.h>
+#include <sys/statvfs.h>
+
+
+#undef stat
+#define stat stat64
+
+int statvfs64 (const char *file, struct statvfs64 *buf)
+{
+ struct statfs64 fsbuf;
+ struct stat64 st;
+#if !defined __UCLIBC_LINUX_SPECIFIC__
+ int ret;
+ struct statvfs buf32;
+
+ ret = statvfs (file, &buf32);
+ if (ret == 0) {
+ fsbuf.f_bsize = buf32.f_bsize;
+ fsbuf.f_frsize = buf32.f_frsize;
+ fsbuf.f_blocks = buf32.f_blocks;
+ fsbuf.f_bfree = buf32.f_bfree;
+ fsbuf.f_bavail = buf32.f_bavail;
+ fsbuf.f_files = buf32.f_files;
+ fsbuf.f_ffree = buf32.f_ffree;
+ if (sizeof (fsbuf.f_fsid) == sizeof(buf32.f_fsid))
+ memcpy (&fsbuf.f_fsid, &buf32.f_fsid, sizeof(fsbuf.f_fsid));
+ /* and if not, then you could approximate or whatever.. */
+ fsbuf.f_namelen = buf32.f_namemax;
+ } else
+ return ret;
+#else
+ /* Get as much information as possible from the system. */
+ if (statfs64 (file, &fsbuf) < 0)
+ return -1;
+#endif
+#define STAT(st) stat (file, st)
+#include "internal_statvfs.c"
+
+ /* We signal success if the statfs call succeeded. */
+ return 0;
+}
diff --git a/ap/build/uClibc/libc/misc/syslog/Makefile b/ap/build/uClibc/libc/misc/syslog/Makefile
new file mode 100644
index 0000000..4a8f4a0
--- /dev/null
+++ b/ap/build/uClibc/libc/misc/syslog/Makefile
@@ -0,0 +1,13 @@
+# Makefile for uClibc
+#
+# Copyright (C) 2000-2005 Erik Andersen <andersen@uclibc.org>
+#
+# Licensed under the LGPL v2.1, see the file COPYING.LIB in this tarball.
+#
+
+top_srcdir=../../../
+top_builddir=../../../
+all: objs
+include $(top_builddir)Rules.mak
+include Makefile.in
+include $(top_srcdir)Makerules
diff --git a/ap/build/uClibc/libc/misc/syslog/Makefile.in b/ap/build/uClibc/libc/misc/syslog/Makefile.in
new file mode 100644
index 0000000..5cc4f52
--- /dev/null
+++ b/ap/build/uClibc/libc/misc/syslog/Makefile.in
@@ -0,0 +1,25 @@
+# Makefile for uClibc
+#
+# Copyright (C) 2000-2008 Erik Andersen <andersen@uclibc.org>
+#
+# Licensed under the LGPL v2.1, see the file COPYING.LIB in this tarball.
+#
+
+subdirs += libc/misc/syslog
+
+CSRC := syslog.c
+
+MISC_SYSLOG_DIR := $(top_srcdir)libc/misc/syslog
+MISC_SYSLOG_OUT := $(top_builddir)libc/misc/syslog
+
+MISC_SYSLOG_SRC := $(patsubst %.c,$(MISC_SYSLOG_DIR)/%.c,$(CSRC))
+MISC_SYSLOG_OBJ := $(patsubst %.c,$(MISC_SYSLOG_OUT)/%.o,$(CSRC))
+
+ifeq ($(UCLIBC_HAS_SYSLOG),y)
+libc-y += $(MISC_SYSLOG_OBJ)
+endif
+
+objclean-y += CLEAN_libc/misc/syslog
+
+CLEAN_libc/misc/syslog:
+ $(do_rm) $(addprefix $(MISC_SYSLOG_OUT)/*., o os)
diff --git a/ap/build/uClibc/libc/misc/syslog/syslog.c b/ap/build/uClibc/libc/misc/syslog/syslog.c
new file mode 100644
index 0000000..f1b848f
--- /dev/null
+++ b/ap/build/uClibc/libc/misc/syslog/syslog.c
@@ -0,0 +1,343 @@
+/*
+ * Copyright (c) 1983, 1988, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. 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.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the University of
+ * California, Berkeley and its contributors.
+ * 4. Neither the name of the University 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 REGENTS 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 REGENTS 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.
+ */
+
+/*
+ * SYSLOG -- print message on log file
+ *
+ * This routine looks a lot like printf, except that it outputs to the
+ * log file instead of the standard output. Also:
+ * adds a timestamp,
+ * prints the module name in front of the message,
+ * has some other formatting types (or will sometime),
+ * adds a newline on the end of the message.
+ *
+ * The output of this routine is intended to be read by syslogd(8).
+ *
+ * Author: Eric Allman
+ * Modified to use UNIX domain IPC by Ralph Campbell
+ * Patched March 12, 1996 by A. Ian Vogelesang <vogelesang@hdshq.com>
+ * - to correct the handling of message & format string truncation,
+ * - to visibly tag truncated records to facilitate
+ * investigation of such Bad Things with grep, and,
+ * - to correct the handling of case where "write"
+ * returns after writing only part of the message.
+ * Rewritten by Martin Mares <mj@atrey.karlin.mff.cuni.cz> on May 14, 1997
+ * - better buffer overrun checks.
+ * - special handling of "%m" removed as we use GNU sprintf which handles
+ * it automatically.
+ * - Major code cleanup.
+ */
+
+#define __FORCE_GLIBC
+#include <features.h>
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <sys/file.h>
+#include <sys/signal.h>
+#include <sys/syslog.h>
+
+#include <sys/uio.h>
+#include <sys/wait.h>
+#include <netdb.h>
+#include <string.h>
+#include <time.h>
+#include <unistd.h>
+#include <errno.h>
+#include <stdarg.h>
+#include <paths.h>
+#include <stdio.h>
+#include <ctype.h>
+#include <signal.h>
+
+
+#include <bits/uClibc_mutex.h>
+
+__UCLIBC_MUTEX_STATIC(mylock, PTHREAD_MUTEX_INITIALIZER);
+
+
+/* !glibc_compat: glibc uses argv[0] by default
+ * (default: if there was no openlog or if openlog passed NULL),
+ * not string "syslog"
+ */
+static const char *LogTag = "syslog"; /* string to tag the entry with */
+static int LogFile = -1; /* fd for log */
+static smalluint connected; /* have done connect */
+/* all bits in option argument for openlog fit in 8 bits */
+static smalluint LogStat = 0; /* status bits, set by openlog */
+/* default facility code if openlog is not called */
+/* (this fits in 8 bits even without >> 3 shift, but playing extra safe) */
+static smalluint LogFacility = LOG_USER >> 3;
+/* bits mask of priorities to be logged (eight prios - 8 bits is enough) */
+static smalluint LogMask = 0xff;
+/* AF_UNIX address of local logger (we use struct sockaddr
+ * instead of struct sockaddr_un since "/dev/log" is small enough) */
+static const struct sockaddr SyslogAddr = {
+ .sa_family = AF_UNIX, /* sa_family_t (usually a short) */
+ .sa_data = _PATH_LOG /* char [14] */
+};
+
+static void
+closelog_intern(int sig)
+{
+ /* mylock must be held by the caller */
+ if (LogFile != -1) {
+ (void) close(LogFile);
+ }
+ LogFile = -1;
+ connected = 0;
+ if (sig == 0) { /* called from closelog()? - reset to defaults */
+ LogStat = 0;
+ LogTag = "syslog";
+ LogFacility = LOG_USER >> 3;
+ LogMask = 0xff;
+ }
+}
+
+static void
+openlog_intern(const char *ident, int logstat, int logfac)
+{
+ int fd;
+ int logType = SOCK_DGRAM;
+
+ if (ident != NULL)
+ LogTag = ident;
+ LogStat = logstat;
+ /* (we were checking also for logfac != 0, but it breaks
+ * openlog(xx, LOG_KERN) since LOG_KERN == 0) */
+ if ((logfac & ~LOG_FACMASK) == 0) /* if we don't have invalid bits */
+ LogFacility = (unsigned)logfac >> 3;
+
+ fd = LogFile;
+ if (fd == -1) {
+ retry:
+ if (logstat & LOG_NDELAY) {
+ LogFile = fd = socket(AF_UNIX, logType, 0);
+ if (fd == -1) {
+ return;
+ }
+ fcntl(fd, F_SETFD, FD_CLOEXEC);
+ /* We don't want to block if e.g. syslogd is SIGSTOPed */
+ fcntl(fd, F_SETFL, O_NONBLOCK | fcntl(fd, F_GETFL));
+ }
+ }
+
+ if (fd != -1 && !connected) {
+ if (connect(fd, &SyslogAddr, sizeof(SyslogAddr)) != -1) {
+ connected = 1;
+ } else {
+ if (fd != -1) {
+ close(fd);
+ LogFile = fd = -1;
+ }
+ if (logType == SOCK_DGRAM) {
+ logType = SOCK_STREAM;
+ goto retry;
+ }
+ }
+ }
+}
+
+/*
+ * OPENLOG -- open system log
+ */
+void
+openlog(const char *ident, int logstat, int logfac)
+{
+ __UCLIBC_MUTEX_LOCK(mylock);
+ openlog_intern(ident, logstat, logfac);
+ __UCLIBC_MUTEX_UNLOCK(mylock);
+}
+libc_hidden_def(openlog)
+
+/*
+ * syslog, vsyslog --
+ * print message on log file; output is intended for syslogd(8).
+ */
+void
+vsyslog(int pri, const char *fmt, va_list ap)
+{
+ register char *p;
+ char *last_chr, *head_end, *end, *stdp;
+ time_t now;
+ int fd, saved_errno;
+ int rc;
+ char tbuf[1024]; /* syslogd is unable to handle longer messages */
+
+ /* Just throw out this message if pri has bad bits. */
+ if ((pri & ~(LOG_PRIMASK|LOG_FACMASK)) != 0)
+ return;
+
+ saved_errno = errno;
+
+ __UCLIBC_MUTEX_LOCK(mylock);
+
+ /* See if we should just throw out this message according to LogMask. */
+ if ((LogMask & LOG_MASK(LOG_PRI(pri))) == 0)
+ goto getout;
+ if (LogFile < 0 || !connected)
+ openlog_intern(NULL, LogStat | LOG_NDELAY, (int)LogFacility << 3);
+
+ /* Set default facility if none specified. */
+ if ((pri & LOG_FACMASK) == 0)
+ pri |= ((int)LogFacility << 3);
+
+ /* Build the message. We know the starting part of the message can take
+ * no longer than 64 characters plus length of the LogTag. So it's
+ * safe to test only LogTag and use normal sprintf everywhere else.
+ */
+ (void)time(&now);
+ stdp = p = tbuf + sprintf(tbuf, "<%d>%.15s ", pri, ctime(&now) + 4);
+ /*if (LogTag) - always true */ {
+ if (strlen(LogTag) < sizeof(tbuf) - 64)
+ p += sprintf(p, "%s", LogTag);
+ else
+ p += sprintf(p, "<BUFFER OVERRUN ATTEMPT>");
+ }
+ if (LogStat & LOG_PID)
+ p += sprintf(p, "[%d]", getpid());
+ /*if (LogTag) - always true */ {
+ *p++ = ':';
+ *p++ = ' ';
+ }
+ head_end = p;
+
+ /* We format the rest of the message. If the buffer becomes full, we mark
+ * the message as truncated. Note that we require at least 2 free bytes
+ * in the buffer as we might want to add "\r\n" there.
+ */
+
+ end = tbuf + sizeof(tbuf) - 1;
+ __set_errno(saved_errno);
+ p += vsnprintf(p, end - p, fmt, ap);
+ if (p >= end || p < head_end) { /* Returned -1 in case of error... */
+ static const char truncate_msg[12] = "[truncated] "; /* no NUL! */
+ memmove(head_end + sizeof(truncate_msg), head_end,
+ end - head_end - sizeof(truncate_msg));
+ memcpy(head_end, truncate_msg, sizeof(truncate_msg));
+ if (p < head_end) {
+ while (p < end && *p) {
+ p++;
+ }
+ }
+ else {
+ p = end - 1;
+ }
+
+ }
+ last_chr = p;
+
+ /* Output to stderr if requested. */
+ if (LogStat & LOG_PERROR) {
+ *last_chr = '\n';
+ (void)write(STDERR_FILENO, stdp, last_chr - stdp + 1);
+ }
+
+ /* Output the message to the local logger using NUL as a message delimiter. */
+ p = tbuf;
+ *last_chr = '\0';
+ if (LogFile >= 0) {
+ do {
+ /* can't just use write, it can result in SIGPIPE */
+ rc = send(LogFile, p, last_chr + 1 - p, MSG_NOSIGNAL);
+ if (rc < 0) {
+ /* I don't think looping forever on EAGAIN is a good idea.
+ * Imagine that syslogd is SIGSTOPed... */
+ if (/* (errno != EAGAIN) && */ (errno != EINTR)) {
+ closelog_intern(1); /* 1: do not reset LogXXX globals to default */
+ goto write_err;
+ }
+ rc = 0;
+ }
+ p += rc;
+ } while (p <= last_chr);
+ goto getout;
+ }
+
+ write_err:
+ /*
+ * Output the message to the console; don't worry about blocking,
+ * if console blocks everything will. Make sure the error reported
+ * is the one from the syslogd failure.
+ */
+ /* should mode be O_WRONLY | O_NOCTTY? -- Uli */
+ /* yes, but in Linux "/dev/console" never becomes ctty anyway -- vda */
+ if ((LogStat & LOG_CONS) &&
+ (fd = open(_PATH_CONSOLE, O_WRONLY | O_NOCTTY)) >= 0) {
+ p = strchr(tbuf, '>') + 1;
+ last_chr[0] = '\r';
+ last_chr[1] = '\n';
+ (void)write(fd, p, last_chr - p + 2);
+ (void)close(fd);
+ }
+
+ getout:
+ __UCLIBC_MUTEX_UNLOCK(mylock);
+}
+libc_hidden_def(vsyslog)
+
+void
+syslog(int pri, const char *fmt, ...)
+{
+ va_list ap;
+
+ va_start(ap, fmt);
+ vsyslog(pri, fmt, ap);
+ va_end(ap);
+}
+libc_hidden_def(syslog)
+
+/*
+ * CLOSELOG -- close the system log
+ */
+void
+closelog(void)
+{
+ __UCLIBC_MUTEX_LOCK(mylock);
+ closelog_intern(0); /* 0: reset LogXXX globals to default */
+ __UCLIBC_MUTEX_UNLOCK(mylock);
+}
+libc_hidden_def(closelog)
+
+/* setlogmask -- set the log mask level */
+int setlogmask(int pmask)
+{
+ int omask;
+
+ omask = LogMask;
+ if (pmask != 0) {
+ __UCLIBC_MUTEX_LOCK(mylock);
+ LogMask = pmask;
+ __UCLIBC_MUTEX_UNLOCK(mylock);
+ }
+ return omask;
+}
diff --git a/ap/build/uClibc/libc/misc/sysvipc/.indent.pro b/ap/build/uClibc/libc/misc/sysvipc/.indent.pro
new file mode 100644
index 0000000..492ecf1
--- /dev/null
+++ b/ap/build/uClibc/libc/misc/sysvipc/.indent.pro
@@ -0,0 +1,33 @@
+--blank-lines-after-declarations
+--blank-lines-after-procedures
+--break-before-boolean-operator
+--no-blank-lines-after-commas
+--braces-on-if-line
+--braces-on-struct-decl-line
+--comment-indentation25
+--declaration-comment-column25
+--no-comment-delimiters-on-blank-lines
+--cuddle-else
+--continuation-indentation4
+--case-indentation0
+--else-endif-column33
+--space-after-cast
+--line-comments-indentation0
+--declaration-indentation1
+--dont-format-first-column-comments
+--dont-format-comments
+--honour-newlines
+--indent-level4
+/* changed from 0 to 4 */
+--parameter-indentation4
+--line-length78 /* changed from 75 */
+--continue-at-parentheses
+--no-space-after-function-call-names
+--dont-break-procedure-type
+--dont-star-comments
+--leave-optional-blank-lines
+--dont-space-special-semicolon
+--tab-size4
+/* additions by Mark */
+--case-brace-indentation0
+--leave-preprocessor-space
diff --git a/ap/build/uClibc/libc/misc/sysvipc/Makefile b/ap/build/uClibc/libc/misc/sysvipc/Makefile
new file mode 100644
index 0000000..4a8f4a0
--- /dev/null
+++ b/ap/build/uClibc/libc/misc/sysvipc/Makefile
@@ -0,0 +1,13 @@
+# Makefile for uClibc
+#
+# Copyright (C) 2000-2005 Erik Andersen <andersen@uclibc.org>
+#
+# Licensed under the LGPL v2.1, see the file COPYING.LIB in this tarball.
+#
+
+top_srcdir=../../../
+top_builddir=../../../
+all: objs
+include $(top_builddir)Rules.mak
+include Makefile.in
+include $(top_srcdir)Makerules
diff --git a/ap/build/uClibc/libc/misc/sysvipc/Makefile.in b/ap/build/uClibc/libc/misc/sysvipc/Makefile.in
new file mode 100644
index 0000000..115cfc6
--- /dev/null
+++ b/ap/build/uClibc/libc/misc/sysvipc/Makefile.in
@@ -0,0 +1,32 @@
+# Makefile for uClibc
+#
+# Copyright (C) 2000-2008 Erik Andersen <andersen@uclibc.org>
+#
+# Licensed under the LGPL v2.1, see the file COPYING.LIB in this tarball.
+#
+
+subdirs += libc/misc/sysvipc
+
+CSRC := ftok.c __syscall_ipc.c
+
+# multi source sem.c
+CSRC += semget.c semctl.c semop.c semtimedop.c
+
+# multi source shm.c
+CSRC += shmat.c shmctl.c shmdt.c shmget.c
+
+# multi source msgq.c
+CSRC += msgctl.c msgget.c msgrcv.c msgsnd.c
+
+MISC_SYSVIPC_DIR := $(top_srcdir)libc/misc/sysvipc
+MISC_SYSVIPC_OUT := $(top_builddir)libc/misc/sysvipc
+
+MISC_SYSVIPC_SRC := $(patsubst %.c,$(MISC_SYSVIPC_DIR)/%.c,$(CSRC))
+MISC_SYSVIPC_OBJ := $(patsubst %.c,$(MISC_SYSVIPC_OUT)/%.o,$(CSRC))
+
+libc-y += $(MISC_SYSVIPC_OBJ)
+
+objclean-y += CLEAN_libc/misc/sysvipc
+
+CLEAN_libc/misc/sysvipc:
+ $(do_rm) $(addprefix $(MISC_SYSVIPC_OUT)/*., o os)
diff --git a/ap/build/uClibc/libc/misc/sysvipc/__syscall_ipc.c b/ap/build/uClibc/libc/misc/sysvipc/__syscall_ipc.c
new file mode 100644
index 0000000..304a42c
--- /dev/null
+++ b/ap/build/uClibc/libc/misc/sysvipc/__syscall_ipc.c
@@ -0,0 +1,17 @@
+/* vi: set sw=4 ts=4: */
+/*
+ * __syscall_ipc() for uClibc
+ *
+ * Copyright (C) 2000-2006 Erik Andersen <andersen@uclibc.org>
+ *
+ * Licensed under the LGPL v2.1, see the file COPYING.LIB in this tarball.
+ */
+
+#include <sys/syscall.h>
+
+#ifdef __NR_ipc
+#define __NR___syscall_ipc __NR_ipc
+#include "ipc.h"
+_syscall6(int, __syscall_ipc, unsigned int, call, long, first, long, second, long,
+ third, void *, ptr, void *, fifth)
+#endif
diff --git a/ap/build/uClibc/libc/misc/sysvipc/ftok.c b/ap/build/uClibc/libc/misc/sysvipc/ftok.c
new file mode 100644
index 0000000..cec2438
--- /dev/null
+++ b/ap/build/uClibc/libc/misc/sysvipc/ftok.c
@@ -0,0 +1,40 @@
+/* Copyright (C) 1995, 1996 Free Software Foundation, Inc.
+ This file is part of the GNU C Library.
+ Contributed by Ulrich Drepper <drepper@gnu.ai.mit.edu>, August 1995.
+
+ The GNU C Library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public License as
+ published by the Free Software Foundation; either version 2 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
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library 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 <sys/ipc.h>
+#include <sys/stat.h>
+#ifdef __UCLIBC_HAS_LFS__
+# include <_lfs_64.h>
+#else
+# define stat64 stat
+#endif
+
+key_t ftok (const char *pathname, int proj_id)
+{
+ struct stat64 st;
+ key_t key;
+
+ if (stat64(pathname, &st) < 0)
+ return (key_t) -1;
+
+ key = ((st.st_ino & 0xffff) | ((st.st_dev & 0xff) << 16)
+ | ((proj_id & 0xff) << 24));
+
+ return key;
+}
diff --git a/ap/build/uClibc/libc/misc/sysvipc/ipc.h b/ap/build/uClibc/libc/misc/sysvipc/ipc.h
new file mode 100644
index 0000000..339d136
--- /dev/null
+++ b/ap/build/uClibc/libc/misc/sysvipc/ipc.h
@@ -0,0 +1,35 @@
+#ifndef IPC_H
+#define IPC_H
+#include <syscall.h>
+#include <bits/wordsize.h>
+
+#if __WORDSIZE == 32 || defined __alpha__ || defined __mips__
+# define __IPC_64 0x100
+#else
+# define __IPC_64 0x0
+#endif
+
+#ifdef __NR_ipc
+
+/* The actual system call: all functions are multiplexed by this. */
+extern int __syscall_ipc (unsigned int __call, long __first, long __second,
+ long __third, void *__ptr, void *__fifth) attribute_hidden;
+
+
+/* The codes for the functions to use the multiplexer `__syscall_ipc'. */
+#define IPCOP_semop 1
+#define IPCOP_semget 2
+#define IPCOP_semctl 3
+#define IPCOP_semtimedop 4
+#define IPCOP_msgsnd 11
+#define IPCOP_msgrcv 12
+#define IPCOP_msgget 13
+#define IPCOP_msgctl 14
+#define IPCOP_shmat 21
+#define IPCOP_shmdt 22
+#define IPCOP_shmget 23
+#define IPCOP_shmctl 24
+
+#endif
+
+#endif /* IPC_H */
diff --git a/ap/build/uClibc/libc/misc/sysvipc/msgctl.c b/ap/build/uClibc/libc/misc/sysvipc/msgctl.c
new file mode 100644
index 0000000..480a54c
--- /dev/null
+++ b/ap/build/uClibc/libc/misc/sysvipc/msgctl.c
@@ -0,0 +1,8 @@
+/*
+ * Copyright (C) 2000-2006 Erik Andersen <andersen@uclibc.org>
+ *
+ * Licensed under the LGPL v2.1, see the file COPYING.LIB in this tarball.
+ */
+
+#define L_msgctl
+#include "msgq.c"
diff --git a/ap/build/uClibc/libc/misc/sysvipc/msgget.c b/ap/build/uClibc/libc/misc/sysvipc/msgget.c
new file mode 100644
index 0000000..f7e54d5
--- /dev/null
+++ b/ap/build/uClibc/libc/misc/sysvipc/msgget.c
@@ -0,0 +1,8 @@
+/*
+ * Copyright (C) 2000-2006 Erik Andersen <andersen@uclibc.org>
+ *
+ * Licensed under the LGPL v2.1, see the file COPYING.LIB in this tarball.
+ */
+
+#define L_msgget
+#include "msgq.c"
diff --git a/ap/build/uClibc/libc/misc/sysvipc/msgq.c b/ap/build/uClibc/libc/misc/sysvipc/msgq.c
new file mode 100644
index 0000000..185cd26
--- /dev/null
+++ b/ap/build/uClibc/libc/misc/sysvipc/msgq.c
@@ -0,0 +1,112 @@
+#include <errno.h>
+#include <sys/msg.h>
+#include "ipc.h"
+#ifdef __UCLIBC_HAS_THREADS_NATIVE__
+#include "sysdep-cancel.h"
+#else
+#define SINGLE_THREAD_P 1
+#endif
+
+
+#ifdef L_msgctl
+
+#ifdef __NR_msgctl
+#define __NR___libc_msgctl __NR_msgctl
+static __inline__ _syscall3(int, __libc_msgctl, int, msqid, int, cmd, struct msqid_ds *, buf)
+#endif
+/* Message queue control operation. */
+int msgctl(int msqid, int cmd, struct msqid_ds *buf)
+{
+#ifdef __NR_msgctl
+ return __libc_msgctl(msqid, cmd | __IPC_64, buf);
+#else
+ return __syscall_ipc(IPCOP_msgctl, msqid, cmd | __IPC_64, 0, buf, 0);
+#endif
+}
+#endif
+
+
+#ifdef L_msgget
+#ifdef __NR_msgget
+_syscall2(int, msgget, key_t, key, int, msgflg)
+#else
+/* Get messages queue. */
+int msgget (key_t key, int msgflg)
+{
+ return __syscall_ipc(IPCOP_msgget ,key ,msgflg ,0 ,0, 0);
+}
+#endif
+#endif
+
+
+struct new_msg_buf{
+ struct msgbuf * oldmsg;
+ long int r_msgtyp; /* the fifth arg of __syscall_ipc */
+};
+/* Receive message from message queue. */
+
+
+#ifdef L_msgrcv
+#ifdef __NR_msgrcv
+#define __NR___syscall_msgrcv __NR_msgrcv
+static inline _syscall5(ssize_t, __syscall_msgrcv, int, msqid, void *, msgp,
+ size_t, msgsz, long int, msgtyp, int, msgflg)
+#endif
+static inline ssize_t do_msgrcv (int msqid, void *msgp, size_t msgsz,
+ long int msgtyp, int msgflg)
+{
+#ifdef __NR_msgrcv
+ return __syscall_msgrcv(msqid, msgp, msgsz, msgtyp, msgflg);
+#else
+ struct new_msg_buf temp;
+
+ temp.r_msgtyp = msgtyp;
+ temp.oldmsg = msgp;
+ return __syscall_ipc(IPCOP_msgrcv ,msqid ,msgsz ,msgflg ,&temp, 0);
+#endif
+}
+ssize_t msgrcv (int msqid, void *msgp, size_t msgsz,
+ long int msgtyp, int msgflg)
+{
+ if (SINGLE_THREAD_P)
+ return do_msgrcv(msqid, msgp, msgsz, msgtyp, msgflg);
+#ifdef __UCLIBC_HAS_THREADS_NATIVE__
+ int oldtype = LIBC_CANCEL_ASYNC ();
+ int result = do_msgrcv(msqid, msgp, msgsz, msgtyp, msgflg);
+ LIBC_CANCEL_RESET (oldtype);
+ return result;
+#endif
+}
+#endif
+
+
+
+#ifdef L_msgsnd
+#ifdef __NR_msgsnd
+#define __NR___syscall_msgsnd __NR_msgsnd
+static inline _syscall4(int, __syscall_msgsnd, int, msqid, const void *, msgp,
+ size_t, msgsz, int, msgflg)
+#endif
+/* Send message to message queue. */
+static inline int do_msgsnd (int msqid, const void *msgp, size_t msgsz,
+ int msgflg)
+{
+#ifdef __NR_msgsnd
+ return __syscall_msgsnd(msqid, msgp, msgsz, msgflg);
+#else
+ return __syscall_ipc(IPCOP_msgsnd, msqid, msgsz, msgflg, (void *)msgp, 0);
+#endif
+}
+int msgsnd (int msqid, const void *msgp, size_t msgsz, int msgflg)
+{
+ if (SINGLE_THREAD_P)
+ return do_msgsnd(msqid, msgp, msgsz, msgflg);
+#ifdef __UCLIBC_HAS_THREADS_NATIVE__
+ int oldtype = LIBC_CANCEL_ASYNC ();
+ int result = do_msgsnd(msqid, msgp, msgsz, msgflg);
+ LIBC_CANCEL_RESET (oldtype);
+ return result;
+#endif
+}
+#endif
+
diff --git a/ap/build/uClibc/libc/misc/sysvipc/msgrcv.c b/ap/build/uClibc/libc/misc/sysvipc/msgrcv.c
new file mode 100644
index 0000000..a85e52a
--- /dev/null
+++ b/ap/build/uClibc/libc/misc/sysvipc/msgrcv.c
@@ -0,0 +1,8 @@
+/*
+ * Copyright (C) 2000-2006 Erik Andersen <andersen@uclibc.org>
+ *
+ * Licensed under the LGPL v2.1, see the file COPYING.LIB in this tarball.
+ */
+
+#define L_msgrcv
+#include "msgq.c"
diff --git a/ap/build/uClibc/libc/misc/sysvipc/msgsnd.c b/ap/build/uClibc/libc/misc/sysvipc/msgsnd.c
new file mode 100644
index 0000000..9f09d1f
--- /dev/null
+++ b/ap/build/uClibc/libc/misc/sysvipc/msgsnd.c
@@ -0,0 +1,8 @@
+/*
+ * Copyright (C) 2000-2006 Erik Andersen <andersen@uclibc.org>
+ *
+ * Licensed under the LGPL v2.1, see the file COPYING.LIB in this tarball.
+ */
+
+#define L_msgsnd
+#include "msgq.c"
diff --git a/ap/build/uClibc/libc/misc/sysvipc/sem.c b/ap/build/uClibc/libc/misc/sysvipc/sem.c
new file mode 100644
index 0000000..cca4cdf
--- /dev/null
+++ b/ap/build/uClibc/libc/misc/sysvipc/sem.c
@@ -0,0 +1,105 @@
+/* Copyright (C) 1995, 1997, 1998 Free Software Foundation, Inc.
+ This file is part of the GNU C Library.
+ Contributed by Ulrich Drepper <drepper@gnu.ai.mit.edu>, August 1995.
+
+ The GNU C Library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public License as
+ published by the Free Software Foundation; either version 2 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
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library 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 <errno.h>
+#include <sys/sem.h>
+#include <stddef.h>
+#include <stdlib.h> /* for NULL */
+
+#include "ipc.h"
+
+
+#ifdef L_semctl
+/* Return identifier for array of NSEMS semaphores associated with
+ KEY. */
+#include <stdarg.h>
+/* arg for semctl system calls. */
+union semun {
+ int val; /* value for SETVAL */
+ struct semid_ds *buf; /* buffer for IPC_STAT & IPC_SET */
+ unsigned short *array; /* array for GETALL & SETALL */
+ struct seminfo *__buf; /* buffer for IPC_INFO */
+ void *__pad;
+};
+
+
+#ifdef __NR_semctl
+#define __NR___semctl __NR_semctl
+static __inline__ _syscall4(int, __semctl, int, semid, int, semnum, int, cmd, void *, arg)
+#endif
+
+int semctl(int semid, int semnum, int cmd, ...)
+{
+ union semun arg;
+ va_list ap;
+
+ /* Get the argument. */
+ va_start (ap, cmd);
+ arg = va_arg (ap, union semun);
+ va_end (ap);
+#ifdef __NR_semctl
+ return __semctl(semid, semnum, cmd | __IPC_64, arg.__pad);
+#else
+ return __syscall_ipc(IPCOP_semctl, semid, semnum, cmd|__IPC_64, &arg, NULL);
+#endif
+}
+#endif
+
+#ifdef L_semget
+#ifdef __NR_semget
+_syscall3(int, semget, key_t, key, int, nsems, int, semflg)
+
+#else
+/* Return identifier for array of NSEMS semaphores associated
+ * with KEY. */
+int semget (key_t key, int nsems, int semflg)
+{
+ return __syscall_ipc(IPCOP_semget, key, nsems, semflg, NULL, 0);
+}
+#endif
+#endif
+
+#ifdef L_semop
+
+#ifdef __NR_semop
+_syscall3(int, semop, int, semid, struct sembuf *, sops, size_t, nsops)
+
+#else
+/* Perform user-defined atomical operation of array of semaphores. */
+int semop (int semid, struct sembuf *sops, size_t nsops)
+{
+ return __syscall_ipc(IPCOP_semop, semid, (int) nsops, 0, sops, NULL);
+}
+#endif
+#endif
+
+#ifdef L_semtimedop
+
+#ifdef __NR_semtimedop
+_syscall4(int, semtimedop, int, semid, struct sembuf *, sops, size_t, nsops, const struct timespec *, timeout)
+
+#else
+
+int semtimedop(int semid, struct sembuf *sops, size_t nsops,
+ const struct timespec *timeout)
+{
+ return __syscall_ipc(IPCOP_semtimedop, semid, nsops, 0, sops, (void *) timeout);
+}
+#endif
+#endif
diff --git a/ap/build/uClibc/libc/misc/sysvipc/semctl.c b/ap/build/uClibc/libc/misc/sysvipc/semctl.c
new file mode 100644
index 0000000..df62a76
--- /dev/null
+++ b/ap/build/uClibc/libc/misc/sysvipc/semctl.c
@@ -0,0 +1,8 @@
+/*
+ * Copyright (C) 2000-2006 Erik Andersen <andersen@uclibc.org>
+ *
+ * Licensed under the LGPL v2.1, see the file COPYING.LIB in this tarball.
+ */
+
+#define L_semctl
+#include "sem.c"
diff --git a/ap/build/uClibc/libc/misc/sysvipc/semget.c b/ap/build/uClibc/libc/misc/sysvipc/semget.c
new file mode 100644
index 0000000..94d0b5d
--- /dev/null
+++ b/ap/build/uClibc/libc/misc/sysvipc/semget.c
@@ -0,0 +1,8 @@
+/*
+ * Copyright (C) 2000-2006 Erik Andersen <andersen@uclibc.org>
+ *
+ * Licensed under the LGPL v2.1, see the file COPYING.LIB in this tarball.
+ */
+
+#define L_semget
+#include "sem.c"
diff --git a/ap/build/uClibc/libc/misc/sysvipc/semop.c b/ap/build/uClibc/libc/misc/sysvipc/semop.c
new file mode 100644
index 0000000..0c67f62
--- /dev/null
+++ b/ap/build/uClibc/libc/misc/sysvipc/semop.c
@@ -0,0 +1,8 @@
+/*
+ * Copyright (C) 2000-2006 Erik Andersen <andersen@uclibc.org>
+ *
+ * Licensed under the LGPL v2.1, see the file COPYING.LIB in this tarball.
+ */
+
+#define L_semop
+#include "sem.c"
diff --git a/ap/build/uClibc/libc/misc/sysvipc/semtimedop.c b/ap/build/uClibc/libc/misc/sysvipc/semtimedop.c
new file mode 100644
index 0000000..ecd0438
--- /dev/null
+++ b/ap/build/uClibc/libc/misc/sysvipc/semtimedop.c
@@ -0,0 +1,8 @@
+/*
+ * Copyright (C) 2000-2006 Erik Andersen <andersen@uclibc.org>
+ *
+ * Licensed under the LGPL v2.1, see the file COPYING.LIB in this tarball.
+ */
+
+#define L_semtimedop
+#include "sem.c"
diff --git a/ap/build/uClibc/libc/misc/sysvipc/shm.c b/ap/build/uClibc/libc/misc/sysvipc/shm.c
new file mode 100644
index 0000000..27e871f
--- /dev/null
+++ b/ap/build/uClibc/libc/misc/sysvipc/shm.c
@@ -0,0 +1,95 @@
+/* Copyright (C) 1995, 1997, 1998 Free Software Foundation, Inc.
+ This file is part of the GNU C Library.
+ Contributed by Ulrich Drepper <drepper@gnu.ai.mit.edu>, August 1995.
+
+ The GNU C Library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public License as
+ published by the Free Software Foundation; either version 2 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
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library 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. */
+
+/* SHMLBA uses it on most of the archs (not mips) */
+#define __getpagesize getpagesize
+
+#include <stdlib.h>
+#include <errno.h>
+#include <sys/shm.h>
+#include <syscall.h>
+#include "ipc.h"
+
+#ifdef L_shmat
+/* Attach the shared memory segment associated with SHMID to the data
+ segment of the calling process. SHMADDR and SHMFLG determine how
+ and where the segment is attached. */
+#if defined(__NR_osf_shmat)
+# define __NR_shmat __NR_osf_shmat
+#endif
+#ifdef __NR_shmat
+_syscall3(void *, shmat, int, shmid, const void *,shmaddr, int, shmflg)
+#else
+/* psm: don't remove this, else mips will fail */
+#include <unistd.h>
+
+void * shmat (int shmid, const void *shmaddr, int shmflg)
+{
+ int retval;
+ unsigned long raddr;
+
+ retval = __syscall_ipc(IPCOP_shmat, shmid, shmflg, (int) &raddr, (void *) shmaddr, 0);
+ return ((unsigned long int) retval > -(unsigned long int) SHMLBA
+ ? (void *) retval : (void *) raddr);
+}
+#endif
+#endif
+
+#ifdef L_shmctl
+/* Provide operations to control over shared memory segments. */
+#ifdef __NR_shmctl
+#define __NR___libc_shmctl __NR_shmctl
+static __inline__ _syscall3(int, __libc_shmctl, int, shmid, int, cmd, struct shmid_ds *, buf)
+#endif
+int shmctl(int shmid, int cmd, struct shmid_ds *buf)
+{
+#ifdef __NR_shmctl
+ return __libc_shmctl(shmid, cmd | __IPC_64, buf);
+#else
+ return __syscall_ipc(IPCOP_shmctl, shmid, cmd | __IPC_64, 0, buf, 0);
+#endif
+}
+#endif
+
+
+#ifdef L_shmdt
+/* Detach shared memory segment starting at address specified by SHMADDR
+ from the caller's data segment. */
+#ifdef __NR_shmdt
+_syscall1(int, shmdt, const void *, shmaddr)
+#else
+int shmdt (const void *shmaddr)
+{
+ return __syscall_ipc(IPCOP_shmdt, 0, 0, 0, (void *) shmaddr, 0);
+}
+#endif
+#endif
+
+#ifdef L_shmget
+/* Return an identifier for an shared memory segment of at least size SIZE
+ which is associated with KEY. */
+#ifdef __NR_shmget
+_syscall3(int, shmget, key_t, key, size_t, size, int, shmflg)
+#else
+int shmget (key_t key, size_t size, int shmflg)
+{
+ return __syscall_ipc(IPCOP_shmget, key, size, shmflg, NULL, 0);
+}
+#endif
+#endif
diff --git a/ap/build/uClibc/libc/misc/sysvipc/shmat.c b/ap/build/uClibc/libc/misc/sysvipc/shmat.c
new file mode 100644
index 0000000..d6cd22a
--- /dev/null
+++ b/ap/build/uClibc/libc/misc/sysvipc/shmat.c
@@ -0,0 +1,8 @@
+/*
+ * Copyright (C) 2000-2006 Erik Andersen <andersen@uclibc.org>
+ *
+ * Licensed under the LGPL v2.1, see the file COPYING.LIB in this tarball.
+ */
+
+#define L_shmat
+#include "shm.c"
diff --git a/ap/build/uClibc/libc/misc/sysvipc/shmctl.c b/ap/build/uClibc/libc/misc/sysvipc/shmctl.c
new file mode 100644
index 0000000..90fab5a
--- /dev/null
+++ b/ap/build/uClibc/libc/misc/sysvipc/shmctl.c
@@ -0,0 +1,8 @@
+/*
+ * Copyright (C) 2000-2006 Erik Andersen <andersen@uclibc.org>
+ *
+ * Licensed under the LGPL v2.1, see the file COPYING.LIB in this tarball.
+ */
+
+#define L_shmctl
+#include "shm.c"
diff --git a/ap/build/uClibc/libc/misc/sysvipc/shmdt.c b/ap/build/uClibc/libc/misc/sysvipc/shmdt.c
new file mode 100644
index 0000000..0783341
--- /dev/null
+++ b/ap/build/uClibc/libc/misc/sysvipc/shmdt.c
@@ -0,0 +1,8 @@
+/*
+ * Copyright (C) 2000-2006 Erik Andersen <andersen@uclibc.org>
+ *
+ * Licensed under the LGPL v2.1, see the file COPYING.LIB in this tarball.
+ */
+
+#define L_shmdt
+#include "shm.c"
diff --git a/ap/build/uClibc/libc/misc/sysvipc/shmget.c b/ap/build/uClibc/libc/misc/sysvipc/shmget.c
new file mode 100644
index 0000000..4778e36
--- /dev/null
+++ b/ap/build/uClibc/libc/misc/sysvipc/shmget.c
@@ -0,0 +1,8 @@
+/*
+ * Copyright (C) 2000-2006 Erik Andersen <andersen@uclibc.org>
+ *
+ * Licensed under the LGPL v2.1, see the file COPYING.LIB in this tarball.
+ */
+
+#define L_shmget
+#include "shm.c"
diff --git a/ap/build/uClibc/libc/misc/time/.indent.pro b/ap/build/uClibc/libc/misc/time/.indent.pro
new file mode 100644
index 0000000..492ecf1
--- /dev/null
+++ b/ap/build/uClibc/libc/misc/time/.indent.pro
@@ -0,0 +1,33 @@
+--blank-lines-after-declarations
+--blank-lines-after-procedures
+--break-before-boolean-operator
+--no-blank-lines-after-commas
+--braces-on-if-line
+--braces-on-struct-decl-line
+--comment-indentation25
+--declaration-comment-column25
+--no-comment-delimiters-on-blank-lines
+--cuddle-else
+--continuation-indentation4
+--case-indentation0
+--else-endif-column33
+--space-after-cast
+--line-comments-indentation0
+--declaration-indentation1
+--dont-format-first-column-comments
+--dont-format-comments
+--honour-newlines
+--indent-level4
+/* changed from 0 to 4 */
+--parameter-indentation4
+--line-length78 /* changed from 75 */
+--continue-at-parentheses
+--no-space-after-function-call-names
+--dont-break-procedure-type
+--dont-star-comments
+--leave-optional-blank-lines
+--dont-space-special-semicolon
+--tab-size4
+/* additions by Mark */
+--case-brace-indentation0
+--leave-preprocessor-space
diff --git a/ap/build/uClibc/libc/misc/time/Makefile b/ap/build/uClibc/libc/misc/time/Makefile
new file mode 100644
index 0000000..4a8f4a0
--- /dev/null
+++ b/ap/build/uClibc/libc/misc/time/Makefile
@@ -0,0 +1,13 @@
+# Makefile for uClibc
+#
+# Copyright (C) 2000-2005 Erik Andersen <andersen@uclibc.org>
+#
+# Licensed under the LGPL v2.1, see the file COPYING.LIB in this tarball.
+#
+
+top_srcdir=../../../
+top_builddir=../../../
+all: objs
+include $(top_builddir)Rules.mak
+include Makefile.in
+include $(top_srcdir)Makerules
diff --git a/ap/build/uClibc/libc/misc/time/Makefile.in b/ap/build/uClibc/libc/misc/time/Makefile.in
new file mode 100644
index 0000000..78f01ad
--- /dev/null
+++ b/ap/build/uClibc/libc/misc/time/Makefile.in
@@ -0,0 +1,43 @@
+# Makefile for uClibc
+#
+# Copyright (C) 2000-2008 Erik Andersen <andersen@uclibc.org>
+#
+# Licensed under the LGPL v2.1, see the file COPYING.LIB in this tarball.
+#
+
+subdirs += libc/misc/time
+
+CSRC := adjtime.c
+ifeq ($(UCLIBC_SUSV3_LEGACY),y)
+CSRC += ftime.c
+endif
+# multi source time.c
+CSRC += asctime.c asctime_r.c clock.c ctime.c ctime_r.c gmtime.c gmtime_r.c \
+ localtime.c localtime_r.c mktime.c strftime.c strptime.c tzset.c \
+ _time_t2tm.c __time_tm.c _time_mktime.c dysize.c timegm.c \
+ _time_mktime_tzi.c _time_localtime_tzi.c
+ifeq ($(UCLIBC_HAS_FLOATS),y)
+CSRC += difftime.c
+endif
+ifeq ($(UCLIBC_HAS_XLOCALE),y)
+CSRC += strftime_l.c strptime_l.c
+endif
+ifeq ($(UCLIBC_HAS_WCHAR),y)
+CSRC += wcsftime.c
+ifeq ($(UCLIBC_HAS_XLOCALE),y)
+CSRC += wcsftime_l.c
+endif
+endif
+
+MISC_TIME_DIR := $(top_srcdir)libc/misc/time
+MISC_TIME_OUT := $(top_builddir)libc/misc/time
+
+MISC_TIME_SRC := $(patsubst %.c,$(MISC_TIME_DIR)/%.c,$(CSRC))
+MISC_TIME_OBJ := $(patsubst %.c,$(MISC_TIME_OUT)/%.o,$(CSRC))
+
+libc-y += $(MISC_TIME_OBJ)
+
+objclean-y += CLEAN_libc/misc/time
+
+CLEAN_libc/misc/time:
+ $(do_rm) $(addprefix $(MISC_TIME_OUT)/*., o os)
diff --git a/ap/build/uClibc/libc/misc/time/__time_tm.c b/ap/build/uClibc/libc/misc/time/__time_tm.c
new file mode 100644
index 0000000..59b7d8a
--- /dev/null
+++ b/ap/build/uClibc/libc/misc/time/__time_tm.c
@@ -0,0 +1,8 @@
+/*
+ * Copyright (C) 2000-2006 Erik Andersen <andersen@uclibc.org>
+ *
+ * Licensed under the LGPL v2.1, see the file COPYING.LIB in this tarball.
+ */
+
+#define L___time_tm
+#include "time.c"
diff --git a/ap/build/uClibc/libc/misc/time/_time_localtime_tzi.c b/ap/build/uClibc/libc/misc/time/_time_localtime_tzi.c
new file mode 100644
index 0000000..32728a4
--- /dev/null
+++ b/ap/build/uClibc/libc/misc/time/_time_localtime_tzi.c
@@ -0,0 +1,8 @@
+/*
+ * Copyright (C) 2000-2006 Erik Andersen <andersen@uclibc.org>
+ *
+ * Licensed under the LGPL v2.1, see the file COPYING.LIB in this tarball.
+ */
+
+#define L__time_localtime_tzi
+#include "time.c"
diff --git a/ap/build/uClibc/libc/misc/time/_time_mktime.c b/ap/build/uClibc/libc/misc/time/_time_mktime.c
new file mode 100644
index 0000000..1fd9200
--- /dev/null
+++ b/ap/build/uClibc/libc/misc/time/_time_mktime.c
@@ -0,0 +1,8 @@
+/*
+ * Copyright (C) 2000-2006 Erik Andersen <andersen@uclibc.org>
+ *
+ * Licensed under the LGPL v2.1, see the file COPYING.LIB in this tarball.
+ */
+
+#define L__time_mktime
+#include "time.c"
diff --git a/ap/build/uClibc/libc/misc/time/_time_mktime_tzi.c b/ap/build/uClibc/libc/misc/time/_time_mktime_tzi.c
new file mode 100644
index 0000000..543893e
--- /dev/null
+++ b/ap/build/uClibc/libc/misc/time/_time_mktime_tzi.c
@@ -0,0 +1,8 @@
+/*
+ * Copyright (C) 2000-2006 Erik Andersen <andersen@uclibc.org>
+ *
+ * Licensed under the LGPL v2.1, see the file COPYING.LIB in this tarball.
+ */
+
+#define L__time_mktime_tzi
+#include "time.c"
diff --git a/ap/build/uClibc/libc/misc/time/_time_t2tm.c b/ap/build/uClibc/libc/misc/time/_time_t2tm.c
new file mode 100644
index 0000000..903651f
--- /dev/null
+++ b/ap/build/uClibc/libc/misc/time/_time_t2tm.c
@@ -0,0 +1,8 @@
+/*
+ * Copyright (C) 2000-2006 Erik Andersen <andersen@uclibc.org>
+ *
+ * Licensed under the LGPL v2.1, see the file COPYING.LIB in this tarball.
+ */
+
+#define L__time_t2tm
+#include "time.c"
diff --git a/ap/build/uClibc/libc/misc/time/adjtime.c b/ap/build/uClibc/libc/misc/time/adjtime.c
new file mode 100644
index 0000000..1e80871
--- /dev/null
+++ b/ap/build/uClibc/libc/misc/time/adjtime.c
@@ -0,0 +1,58 @@
+/*
+ * Copyright (C) 2000-2006 Erik Andersen <andersen@uclibc.org>
+ *
+ * Licensed under the LGPL v2.1, see the file COPYING.LIB in this tarball.
+ */
+
+#include <limits.h>
+#include <sys/time.h>
+#include <sys/timex.h>
+#include <errno.h>
+
+
+#define MAX_SEC (LONG_MAX / 1000000L - 2)
+#define MIN_SEC (LONG_MIN / 1000000L + 2)
+
+#ifndef MOD_OFFSET
+#define modes mode
+#endif
+
+int
+adjtime(const struct timeval * itv, struct timeval * otv)
+{
+ struct timex tntx;
+
+ if (itv)
+ {
+ struct timeval tmp;
+
+ /* We will do some check here. */
+ tmp.tv_sec = itv->tv_sec + itv->tv_usec / 1000000L;
+ tmp.tv_usec = itv->tv_usec % 1000000L;
+ if (tmp.tv_sec > MAX_SEC || tmp.tv_sec < MIN_SEC)
+ {
+ __set_errno(EINVAL);
+ return -1;
+ }
+ tntx.offset = tmp.tv_usec + tmp.tv_sec * 1000000L;
+ tntx.modes = ADJ_OFFSET_SINGLESHOT;
+ }
+ else
+ {
+ tntx.modes = 0;
+ }
+ if (adjtimex(&tntx) < 0) return -1;
+ if (otv) {
+ if (tntx.offset < 0)
+ {
+ otv->tv_usec = -(-tntx.offset % 1000000);
+ otv->tv_sec = -(-tntx.offset / 1000000);
+ }
+ else
+ {
+ otv->tv_usec = tntx.offset % 1000000;
+ otv->tv_sec = tntx.offset / 1000000;
+ }
+ }
+ return 0;
+}
diff --git a/ap/build/uClibc/libc/misc/time/asctime.c b/ap/build/uClibc/libc/misc/time/asctime.c
new file mode 100644
index 0000000..d80c017
--- /dev/null
+++ b/ap/build/uClibc/libc/misc/time/asctime.c
@@ -0,0 +1,8 @@
+/*
+ * Copyright (C) 2000-2006 Erik Andersen <andersen@uclibc.org>
+ *
+ * Licensed under the LGPL v2.1, see the file COPYING.LIB in this tarball.
+ */
+
+#define L_asctime
+#include "time.c"
diff --git a/ap/build/uClibc/libc/misc/time/asctime_r.c b/ap/build/uClibc/libc/misc/time/asctime_r.c
new file mode 100644
index 0000000..aec38b1
--- /dev/null
+++ b/ap/build/uClibc/libc/misc/time/asctime_r.c
@@ -0,0 +1,8 @@
+/*
+ * Copyright (C) 2000-2006 Erik Andersen <andersen@uclibc.org>
+ *
+ * Licensed under the LGPL v2.1, see the file COPYING.LIB in this tarball.
+ */
+
+#define L_asctime_r
+#include "time.c"
diff --git a/ap/build/uClibc/libc/misc/time/clock.c b/ap/build/uClibc/libc/misc/time/clock.c
new file mode 100644
index 0000000..9cc4254
--- /dev/null
+++ b/ap/build/uClibc/libc/misc/time/clock.c
@@ -0,0 +1,8 @@
+/*
+ * Copyright (C) 2000-2006 Erik Andersen <andersen@uclibc.org>
+ *
+ * Licensed under the LGPL v2.1, see the file COPYING.LIB in this tarball.
+ */
+
+#define L_clock
+#include "time.c"
diff --git a/ap/build/uClibc/libc/misc/time/ctime.c b/ap/build/uClibc/libc/misc/time/ctime.c
new file mode 100644
index 0000000..4bd09a8
--- /dev/null
+++ b/ap/build/uClibc/libc/misc/time/ctime.c
@@ -0,0 +1,8 @@
+/*
+ * Copyright (C) 2000-2006 Erik Andersen <andersen@uclibc.org>
+ *
+ * Licensed under the LGPL v2.1, see the file COPYING.LIB in this tarball.
+ */
+
+#define L_ctime
+#include "time.c"
diff --git a/ap/build/uClibc/libc/misc/time/ctime_r.c b/ap/build/uClibc/libc/misc/time/ctime_r.c
new file mode 100644
index 0000000..c03f5c9
--- /dev/null
+++ b/ap/build/uClibc/libc/misc/time/ctime_r.c
@@ -0,0 +1,8 @@
+/*
+ * Copyright (C) 2000-2006 Erik Andersen <andersen@uclibc.org>
+ *
+ * Licensed under the LGPL v2.1, see the file COPYING.LIB in this tarball.
+ */
+
+#define L_ctime_r
+#include "time.c"
diff --git a/ap/build/uClibc/libc/misc/time/difftime.c b/ap/build/uClibc/libc/misc/time/difftime.c
new file mode 100644
index 0000000..4bcec2c
--- /dev/null
+++ b/ap/build/uClibc/libc/misc/time/difftime.c
@@ -0,0 +1,8 @@
+/*
+ * Copyright (C) 2000-2006 Erik Andersen <andersen@uclibc.org>
+ *
+ * Licensed under the LGPL v2.1, see the file COPYING.LIB in this tarball.
+ */
+
+#define L_difftime
+#include "time.c"
diff --git a/ap/build/uClibc/libc/misc/time/dysize.c b/ap/build/uClibc/libc/misc/time/dysize.c
new file mode 100644
index 0000000..b1bf84b
--- /dev/null
+++ b/ap/build/uClibc/libc/misc/time/dysize.c
@@ -0,0 +1,8 @@
+/*
+ * Copyright (C) 2000-2006 Erik Andersen <andersen@uclibc.org>
+ *
+ * Licensed under the LGPL v2.1, see the file COPYING.LIB in this tarball.
+ */
+
+#define L_dysize
+#include "time.c"
diff --git a/ap/build/uClibc/libc/misc/time/ftime.c b/ap/build/uClibc/libc/misc/time/ftime.c
new file mode 100644
index 0000000..ff78d41
--- /dev/null
+++ b/ap/build/uClibc/libc/misc/time/ftime.c
@@ -0,0 +1,38 @@
+/* Copyright (C) 1994, 1997 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 <sys/timeb.h>
+#include <sys/time.h>
+
+
+int ftime(struct timeb *timebuf)
+{
+ struct timeval tv;
+ struct timezone tz;
+
+ /* In Linux, gettimeofday fails only on bad parameter.
+ * We know that here parameters aren't bad.
+ */
+ gettimeofday (&tv, &tz);
+
+ timebuf->time = tv.tv_sec;
+ timebuf->millitm = (tv.tv_usec + 999) / 1000;
+ timebuf->timezone = tz.tz_minuteswest;
+ timebuf->dstflag = tz.tz_dsttime;
+ return 0;
+}
diff --git a/ap/build/uClibc/libc/misc/time/gmtime.c b/ap/build/uClibc/libc/misc/time/gmtime.c
new file mode 100644
index 0000000..24a512c
--- /dev/null
+++ b/ap/build/uClibc/libc/misc/time/gmtime.c
@@ -0,0 +1,8 @@
+/*
+ * Copyright (C) 2000-2006 Erik Andersen <andersen@uclibc.org>
+ *
+ * Licensed under the LGPL v2.1, see the file COPYING.LIB in this tarball.
+ */
+
+#define L_gmtime
+#include "time.c"
diff --git a/ap/build/uClibc/libc/misc/time/gmtime_r.c b/ap/build/uClibc/libc/misc/time/gmtime_r.c
new file mode 100644
index 0000000..8677dd2
--- /dev/null
+++ b/ap/build/uClibc/libc/misc/time/gmtime_r.c
@@ -0,0 +1,8 @@
+/*
+ * Copyright (C) 2000-2006 Erik Andersen <andersen@uclibc.org>
+ *
+ * Licensed under the LGPL v2.1, see the file COPYING.LIB in this tarball.
+ */
+
+#define L_gmtime_r
+#include "time.c"
diff --git a/ap/build/uClibc/libc/misc/time/localtime.c b/ap/build/uClibc/libc/misc/time/localtime.c
new file mode 100644
index 0000000..e4bffbd
--- /dev/null
+++ b/ap/build/uClibc/libc/misc/time/localtime.c
@@ -0,0 +1,8 @@
+/*
+ * Copyright (C) 2000-2006 Erik Andersen <andersen@uclibc.org>
+ *
+ * Licensed under the LGPL v2.1, see the file COPYING.LIB in this tarball.
+ */
+
+#define L_localtime
+#include "time.c"
diff --git a/ap/build/uClibc/libc/misc/time/localtime_r.c b/ap/build/uClibc/libc/misc/time/localtime_r.c
new file mode 100644
index 0000000..5351834
--- /dev/null
+++ b/ap/build/uClibc/libc/misc/time/localtime_r.c
@@ -0,0 +1,8 @@
+/*
+ * Copyright (C) 2000-2006 Erik Andersen <andersen@uclibc.org>
+ *
+ * Licensed under the LGPL v2.1, see the file COPYING.LIB in this tarball.
+ */
+
+#define L_localtime_r
+#include "time.c"
diff --git a/ap/build/uClibc/libc/misc/time/mktime.c b/ap/build/uClibc/libc/misc/time/mktime.c
new file mode 100644
index 0000000..2b2c8e4
--- /dev/null
+++ b/ap/build/uClibc/libc/misc/time/mktime.c
@@ -0,0 +1,8 @@
+/*
+ * Copyright (C) 2000-2006 Erik Andersen <andersen@uclibc.org>
+ *
+ * Licensed under the LGPL v2.1, see the file COPYING.LIB in this tarball.
+ */
+
+#define L_mktime
+#include "time.c"
diff --git a/ap/build/uClibc/libc/misc/time/strftime.c b/ap/build/uClibc/libc/misc/time/strftime.c
new file mode 100644
index 0000000..2eb827d
--- /dev/null
+++ b/ap/build/uClibc/libc/misc/time/strftime.c
@@ -0,0 +1,8 @@
+/*
+ * Copyright (C) 2000-2006 Erik Andersen <andersen@uclibc.org>
+ *
+ * Licensed under the LGPL v2.1, see the file COPYING.LIB in this tarball.
+ */
+
+#define L_strftime
+#include "time.c"
diff --git a/ap/build/uClibc/libc/misc/time/strftime_l.c b/ap/build/uClibc/libc/misc/time/strftime_l.c
new file mode 100644
index 0000000..e1d34ad
--- /dev/null
+++ b/ap/build/uClibc/libc/misc/time/strftime_l.c
@@ -0,0 +1,9 @@
+/*
+ * Copyright (C) 2000-2006 Erik Andersen <andersen@uclibc.org>
+ *
+ * Licensed under the LGPL v2.1, see the file COPYING.LIB in this tarball.
+ */
+
+#define L_strftime_l
+#define __UCLIBC_DO_XLOCALE
+#include "time.c"
diff --git a/ap/build/uClibc/libc/misc/time/strptime.c b/ap/build/uClibc/libc/misc/time/strptime.c
new file mode 100644
index 0000000..771633f
--- /dev/null
+++ b/ap/build/uClibc/libc/misc/time/strptime.c
@@ -0,0 +1,8 @@
+/*
+ * Copyright (C) 2000-2006 Erik Andersen <andersen@uclibc.org>
+ *
+ * Licensed under the LGPL v2.1, see the file COPYING.LIB in this tarball.
+ */
+
+#define L_strptime
+#include "time.c"
diff --git a/ap/build/uClibc/libc/misc/time/strptime_l.c b/ap/build/uClibc/libc/misc/time/strptime_l.c
new file mode 100644
index 0000000..16ee7e1
--- /dev/null
+++ b/ap/build/uClibc/libc/misc/time/strptime_l.c
@@ -0,0 +1,9 @@
+/*
+ * Copyright (C) 2000-2006 Erik Andersen <andersen@uclibc.org>
+ *
+ * Licensed under the LGPL v2.1, see the file COPYING.LIB in this tarball.
+ */
+
+#define L_strptime_l
+#define __UCLIBC_DO_XLOCALE
+#include "time.c"
diff --git a/ap/build/uClibc/libc/misc/time/time.c b/ap/build/uClibc/libc/misc/time/time.c
new file mode 100644
index 0000000..8e2ebf1
--- /dev/null
+++ b/ap/build/uClibc/libc/misc/time/time.c
@@ -0,0 +1,2485 @@
+/* Copyright (C) 2002-2004 Manuel Novoa III <mjn3@codepoet.org>
+ *
+ * GNU Library General Public License (LGPL) version 2 or later.
+ *
+ * Dedicated to Toni. See uClibc/DEDICATION.mjn3 for details.
+ */
+
+/* June 15, 2002 Initial Notes:
+ *
+ * Note: It is assumed throught that time_t is either long or unsigned long.
+ * Similarly, clock_t is assumed to be long int.
+ *
+ * Warning: Assumptions are made about the layout of struct tm! It is
+ * assumed that the initial fields of struct tm are (in order):
+ * tm_sec, tm_min, tm_hour, tm_mday, tm_mon, tm_year, tm_wday, tm_yday
+ *
+ * Reached the inital goal of supporting the ANSI/ISO C99 time functions
+ * as well as SUSv3's strptime. All timezone info is obtained from the
+ * TZ env variable.
+ *
+ * Differences from glibc worth noting:
+ *
+ * Leap seconds are not considered here.
+ *
+ * glibc stores additional timezone info the struct tm, whereas we don't.
+ *
+ * Alternate digits and era handling are not currently implemented.
+ * The modifiers are accepted, and tested for validity with the following
+ * specifier, but are ignored otherwise.
+ *
+ * strftime does not implement glibc extension modifiers or widths for
+ * conversion specifiers. However it does implement the glibc
+ * extension specifiers %l, %k, and %s. It also recognizes %P, but
+ * treats it as a synonym for %p; i.e. doesn't convert to lower case.
+ *
+ * strptime implements the glibc extension specifiers. However, it follows
+ * SUSv3 in requiring at least one non-alphanumeric char between
+ * conversion specifiers. Also, strptime only sets struct tm fields
+ * for which format specifiers appear and does not try to infer other
+ * fields (such as wday) as glibc's version does.
+ *
+ * TODO - Since glibc's %l and %k can space-pad their output in strftime,
+ * it might be reasonable to eat whitespace first for those specifiers.
+ * This could be done by pushing " %I" and " %H" respectively so that
+ * leading whitespace is consumed. This is really only an issue if %l
+ * or %k occurs at the start of the format string.
+ *
+ * TODO - Implement getdate? tzfile? struct tm extensions?
+ *
+ * TODO - Rework _time_mktime to remove the dependency on long long.
+ */
+
+/* Oct 28, 2002
+ *
+ * Fixed allowed char check for std and dst TZ fields.
+ *
+ * Added several options concerned with timezone support. The names will
+ * probably change once Erik gets the new config system in place.
+ *
+ * Defining __TIME_TZ_FILE causes tzset() to attempt to read the TZ value
+ * from the file /etc/TZ if the TZ env variable isn't set. The file contents
+ * must be the intended value of TZ, followed by a newline. No other chars,
+ * spacing, etc is allowed. As an example, an easy way for me to init
+ * /etc/TZ appropriately would be: echo CST6CDT > /etc/TZ
+ *
+ * Defining __TIME_TZ_FILE_ONCE will cause all further accesses of /etc/TZ
+ * to be skipped once a legal value has been read.
+ *
+ * Defining __TIME_TZ_OPT_SPEED will cause a tzset() to keep a copy of the
+ * last TZ setting string and do a "fast out" if the current string is the
+ * same.
+ *
+ * Nov 21, 2002 Fix an error return case in _time_mktime.
+ *
+ * Nov 26, 2002 Fix bug in setting daylight and timezone when no (valid) TZ.
+ * Bug reported by Arne Bernin <arne@alamut.de> in regards to freeswan.
+ *
+ * July 27, 2003 Adjust the struct tm extension field support.
+ * Change __tm_zone back to a ptr and add the __tm_tzname[] buffer for
+ * __tm_zone to point to. This gets around complaints from g++.
+ * Who knows... it might even fix the PPC timezone init problem.
+ *
+ * July 29, 2003 Fix a bug in mktime behavior when tm_isdst was -1.
+ * Bug reported by "Sid Wade" <sid@vivato.net> in regards to busybox.
+ *
+ * NOTE: uClibc mktime behavior is different than glibc's when
+ * the struct tm has tm_isdst == -1 and also had fields outside of
+ * the normal ranges.
+ *
+ * Apparently, glibc examines (at least) tm_sec and guesses the app's
+ * intention of assuming increasing or decreasing time when entering an
+ * ambiguous time period at the dst<->st boundaries.
+ *
+ * The uClibc behavior is to always normalize the struct tm and then
+ * try to determing the dst setting.
+ *
+ * As long as tm_isdst != -1 or the time specifiec by struct tm is
+ * unambiguous (not falling in the dst<->st transition region) both
+ * uClibc and glibc should produce the same result for mktime.
+ *
+ * Oct 31, 2003 Kill the seperate __tm_zone and __tm_tzname[] and which
+ * doesn't work if you want the memcpy the struct. Sigh... I didn't
+ * think about that. So now, when the extensions are enabled, we
+ * malloc space when necessary and keep the timezone names in a linked
+ * list.
+ *
+ * Fix a dst-related bug which resulted in use of uninitialized data.
+ *
+ * Nov 15, 2003 I forgot to update the thread locking in the last dst fix.
+ *
+ * Dec 14, 2003 Fix some dst issues in _time_mktime().
+ * Normalize the tm_isdst value to -1, 0, or 1.
+ * If no dst for this timezone, then reset tm_isdst to 0.
+ *
+ * May 7, 2004
+ * Change clock() to allow wrapping.
+ * Add timegm() function.
+ * Make lookup_tzname() static (as it should have been).
+ * Have strftime() get timezone information from the passed struct
+ * for the %z and %Z conversions when using struct tm extensions.
+ *
+ * Jul 24, 2004
+ * Fix 2 bugs in strftime related to glibc struct tm extensions.
+ * 1) Need to negate tm_gmtoff field value when used. (bug 336).
+ * 2) Deal with NULL ptr case for tm_zone field, which was causing
+ * segfaults in both the NIST/PCTS tests and the Python 2.4.1
+ * self-test suite.
+ * NOTE: We set uninitialized timezone names to "???", and this
+ * differs (intentionally) from glibc's behavior.
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <stddef.h>
+#include <string.h>
+#include <time.h>
+#include <sys/time.h>
+#include <limits.h>
+#include <assert.h>
+#include <errno.h>
+#include <ctype.h>
+#include <langinfo.h>
+#include <locale.h>
+#include <fcntl.h>
+#include <unistd.h>
+#include <bits/uClibc_uintmaxtostr.h>
+#include <bits/uClibc_mutex.h>
+
+#ifdef __UCLIBC_HAS_WCHAR__
+#include <wchar.h>
+#endif
+#ifdef __UCLIBC_HAS_XLOCALE__
+#include <xlocale.h>
+#endif
+
+
+#ifndef __isleap
+#define __isleap(y) ( !((y) % 4) && ( ((y) % 100) || !((y) % 400) ) )
+#endif
+
+#ifndef TZNAME_MAX
+#define TZNAME_MAX _POSIX_TZNAME_MAX
+#endif
+
+#if defined (L_tzset) || defined (L_localtime_r) || defined(L_strftime) || \
+ defined(L__time_mktime) || defined(L__time_mktime_tzi) || \
+ ((defined(L_strftime) || defined(L_strftime_l)) && \
+ defined(__UCLIBC_HAS_XLOCALE__))
+
+void _time_tzset(int use_old_rules) attribute_hidden;
+
+#ifndef L__time_mktime
+
+ /* Jan 1, 2007 Z - tm = 0,0,0,1,0,107,1,0,0 */
+
+static const time_t new_rule_starts = 1167609600;
+
+#endif
+#endif
+
+/**********************************************************************/
+/* The era code is currently unfinished. */
+/* #define ENABLE_ERA_CODE */
+
+#define TZ_BUFLEN (2*TZNAME_MAX + 56)
+
+#ifdef __UCLIBC_HAS_TZ_FILE__
+
+#include <sys/stat.h>
+#include "paths.h"
+/* ":<tzname>+hh:mm:ss<tzname>+hh:mm:ss,Mmm.w.d/hh:mm:ss,Mmm.w.d/hh:mm:ss" + nul */
+/* 1 + 2*(1+TZNAME_MAX+1 + 9 + 7 + 9) + 1 = 2*TZNAME_MAX + 56 */
+
+#else /* __UCLIBC_HAS_TZ_FILE__ */
+
+/* Probably no longer needed. */
+#undef __UCLIBC_HAS_TZ_FILE_READ_MANY__
+
+#endif /* __UCLIBC_HAS_TZ_FILE__ */
+
+/**********************************************************************/
+
+extern struct tm __time_tm attribute_hidden;
+
+typedef struct {
+ long gmt_offset;
+ long dst_offset;
+ short day; /* for J or normal */
+ short week;
+ short month;
+ short rule_type; /* J, M, \0 */
+ char tzname[TZNAME_MAX+1];
+} rule_struct;
+
+__UCLIBC_MUTEX_EXTERN(_time_tzlock);
+
+extern rule_struct _time_tzinfo[2] attribute_hidden;
+
+extern struct tm *_time_t2tm(const time_t *__restrict timer,
+ int offset, struct tm *__restrict result) attribute_hidden;
+
+extern time_t _time_mktime(struct tm *timeptr, int store_on_success) attribute_hidden;
+
+extern struct tm *__time_localtime_tzi(const time_t *__restrict timer,
+ struct tm *__restrict result,
+ rule_struct *tzi) attribute_hidden;
+
+extern time_t _time_mktime_tzi(struct tm *timeptr, int store_on_success,
+ rule_struct *tzi) attribute_hidden;
+
+/**********************************************************************/
+#ifdef L_asctime
+
+static char __time_str[26];
+
+char *asctime(const struct tm *ptm)
+{
+ return asctime_r(ptm, __time_str);
+}
+libc_hidden_def(asctime)
+
+#endif
+/**********************************************************************/
+#ifdef L_asctime_r
+
+/* Strictly speaking, this implementation isn't correct. ANSI/ISO specifies
+ * that the implementation of asctime() be equivalent to
+ *
+ * char *asctime(const struct tm *timeptr)
+ * {
+ * static char wday_name[7][3] = {
+ * "Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat"
+ * };
+ * static char mon_name[12][3] = {
+ * "Jan", "Feb", "Mar", "Apr", "May", "Jun",
+ * "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"
+ * };
+ * static char result[26];
+ *
+ * sprintf(result, "%.3s %.3s%3d %.2d:%.2d:%.2d %d\n",
+ * wday_name[timeptr->tm_wday],
+ * mon_name[timeptr->tm_mon],
+ * timeptr->tm_mday, timeptr->tm_hour,
+ * timeptr->tm_min, timeptr->tm_sec,
+ * 1900 + timeptr->tm_year);
+ * return result;
+ * }
+ *
+ * but the above is either inherently unsafe, or carries with it the implicit
+ * assumption that all fields of timeptr fall within their usual ranges, and
+ * that the tm_year value falls in the range [-2899,8099] to avoid overflowing
+ * the static buffer.
+ *
+ * If we take the implicit assumption as given, then the implementation below
+ * is still incorrect for tm_year values < -900, as there will be either
+ * 0-padding and/or a missing negative sign for the year conversion . But given
+ * the usual use of asctime(), I think it isn't unreasonable to restrict correct
+ * operation to the domain of years between 1000 and 9999.
+ */
+
+/* This is generally a good thing, but if you're _sure_ any data passed will be
+ * in range, you can #undef this. */
+#define SAFE_ASCTIME_R 1
+
+static const unsigned char at_data[] = {
+ 'S', 'u', 'n', 'M', 'o', 'n', 'T', 'u', 'e', 'W', 'e', 'd',
+ 'T', 'h', 'u', 'F', 'r', 'i', 'S', 'a', 't',
+
+ 'J', 'a', 'n', 'F', 'e', 'b', 'M', 'a', 'r', 'A', 'p', 'r',
+ 'M', 'a', 'y', 'J', 'u', 'n', 'J', 'u', 'l', 'A', 'u', 'g',
+ 'S', 'e', 'p', 'O', 'c', 't', 'N', 'o', 'v', 'D', 'e', 'c',
+
+#ifdef SAFE_ASCTIME_R
+ '?', '?', '?',
+#endif
+ ' ', '?', '?', '?',
+ ' ', '0',
+ offsetof(struct tm, tm_mday),
+ ' ', '0',
+ offsetof(struct tm, tm_hour),
+ ':', '0',
+ offsetof(struct tm, tm_min),
+ ':', '0',
+ offsetof(struct tm, tm_sec),
+ ' ', '?', '?', '?', '?', '\n', 0
+};
+
+char *asctime_r(register const struct tm *__restrict ptm,
+ register char *__restrict buffer)
+{
+ int tmp;
+
+ assert(ptm);
+ assert(buffer);
+
+#ifdef SAFE_ASCTIME_R
+ memcpy(buffer, at_data + 3*(7 + 12), sizeof(at_data) - 3*(7 + 12));
+
+ if (((unsigned int)(ptm->tm_wday)) <= 6) {
+ memcpy(buffer, at_data + 3 * ptm->tm_wday, 3);
+ }
+
+ if (((unsigned int)(ptm->tm_mon)) <= 11) {
+ memcpy(buffer + 4, at_data + 3*7 + 3 * ptm->tm_mon, 3);
+ }
+#else
+ assert(((unsigned int)(ptm->tm_wday)) <= 6);
+ assert(((unsigned int)(ptm->tm_mon)) <= 11);
+
+ memcpy(buffer, at_data + 3*(7 + 12) - 3, sizeof(at_data) + 3 - 3*(7 + 12));
+
+ memcpy(buffer, at_data + 3 * ptm->tm_wday, 3);
+ memcpy(buffer + 4, at_data + 3*7 + 3 * ptm->tm_mon, 3);
+#endif
+
+#ifdef SAFE_ASCTIME_R
+ buffer += 19;
+ tmp = ptm->tm_year + 1900;
+ if (((unsigned int) tmp) < 10000) {
+ buffer += 4;
+ do {
+ *buffer = '0' + (tmp % 10);
+ tmp /= 10;
+ } while (*--buffer == '?');
+ }
+/* Not sure if we should even bother ...
+ } else {
+ __set_errno(EOVERFLOW);
+ return NULL;
+ }
+*/
+#else /* SAFE_ASCTIME_R */
+ buffer += 23;
+ tmp = ptm->tm_year + 1900;
+ assert( ((unsigned int) tmp) < 10000 );
+/* Not sure if we should even bother ...
+ if ( ((unsigned int) tmp) >= 10000 ) {
+ __set_errno(EOVERFLOW);
+ return NULL;
+ }
+*/
+ do {
+ *buffer = '0' + (tmp % 10);
+ tmp /= 10;
+ } while (*--buffer == '?');
+#endif /* SAFE_ASCTIME_R */
+
+ do {
+ --buffer;
+ tmp = *((int *)(((const char *) ptm) + (int) *buffer));
+#ifdef SAFE_ASCTIME_R
+ if (((unsigned int) tmp) >= 100) { /* Just check 2 digit non-neg. */
+ buffer[-1] = *buffer = '?';
+ } else
+#else
+ assert(((unsigned int) tmp) < 100); /* Just check 2 digit non-neg. */
+#endif
+ {
+ *buffer = '0' + (tmp % 10);
+#ifdef __BCC__
+ buffer[-1] = '0' + (tmp/10);
+#else
+ buffer[-1] += (tmp/10);
+#endif
+ }
+ } while ((buffer -= 2)[-2] == '0');
+
+ if (*++buffer == '0') { /* Space-pad day of month. */
+ *buffer = ' ';
+ }
+
+ return buffer - 8;
+}
+libc_hidden_def(asctime_r)
+
+#endif
+/**********************************************************************/
+#ifdef L_clock
+
+#include <sys/times.h>
+
+#ifndef __BCC__
+#if CLOCKS_PER_SEC != 1000000L
+#error unexpected value for CLOCKS_PER_SEC!
+#endif
+#endif
+
+#ifdef __UCLIBC_CLK_TCK_CONST
+# if __UCLIBC_CLK_TCK_CONST > CLOCKS_PER_SEC
+# error __UCLIBC_CLK_TCK_CONST > CLOCKS_PER_SEC!
+# elif __UCLIBC_CLK_TCK_CONST < 1
+# error __UCLIBC_CLK_TCK_CONST < 1!
+# endif
+#endif
+
+/* Note: SUSv3 notes
+ *
+ * On XSI-conformant systems, CLOCKS_PER_SEC is defined to be one million.
+ *
+ * The value returned by clock() may wrap around on some implementations.
+ * For example, on a machine with 32-bit values for clock_t, it wraps
+ * after 2147 seconds.
+ *
+ * This implies that we should bitwise and with LONG_MAX.
+ */
+
+clock_t clock(void)
+{
+ struct tms xtms;
+ unsigned long t;
+
+ times(&xtms);
+
+ t = ((unsigned long) xtms.tms_utime) + xtms.tms_stime;
+
+#ifndef __UCLIBC_CLK_TCK_CONST
+
+# error __UCLIBC_CLK_TCK_CONST not defined!
+
+#elif ((CLOCKS_PER_SEC % __UCLIBC_CLK_TCK_CONST) == 0)
+
+ /* CLOCKS_PER_SEC == k * __UCLIBC_CLK_TCK_CONST for some integer k >= 1. */
+ return ((t * (CLOCKS_PER_SEC/__UCLIBC_CLK_TCK_CONST)) & LONG_MAX);
+
+#else
+
+ /* Unlike the previous case, the scaling factor is not an integer.
+ * So when tms_utime, tms_stime, or their sum wraps, some of the
+ * "visible" bits in the return value are affected. Nothing we
+ * can really do about this though other than handle tms_utime and
+ * tms_stime seperately and then sum. But since that doesn't really
+ * buy us much, we don't bother. */
+
+ return ((((t / __UCLIBC_CLK_TCK_CONST) * CLOCKS_PER_SEC)
+ + ((((t % __UCLIBC_CLK_TCK_CONST) * CLOCKS_PER_SEC)
+ / __UCLIBC_CLK_TCK_CONST))
+ ) & LONG_MAX);
+
+#endif
+}
+
+#endif
+/**********************************************************************/
+#ifdef L_ctime
+
+char *ctime(const time_t *t)
+{
+ /* ANSI/ISO/SUSv3 say that ctime is equivalent to the following:
+ * return asctime(localtime(t));
+ * I don't think "equivalent" means "it uses the same internal buffer",
+ * it means "gives the same resultant string".
+ *
+ * I doubt anyone ever uses weird code like:
+ * struct tm *ptm = localtime(t1); ...; ctime(t2); use(ptm);
+ * which relies on the assumption that ctime's and localtime's
+ * internal static struct tm is the same.
+ *
+ * Using localtime_r instead of localtime avoids linking in
+ * localtime's static buffer:
+ */
+ struct tm xtm;
+ memset(&xtm, 0, sizeof(xtm));
+
+ return asctime(localtime_r(t, &xtm));
+}
+libc_hidden_def(ctime)
+#endif
+/**********************************************************************/
+#ifdef L_ctime_r
+
+char *ctime_r(const time_t *t, char *buf)
+{
+ struct tm xtm;
+
+ return asctime_r(localtime_r(t, &xtm), buf);
+}
+
+#endif
+/**********************************************************************/
+#ifdef L_difftime
+
+#include <float.h>
+
+#if FLT_RADIX != 2
+#error difftime implementation assumptions violated for you arch!
+#endif
+
+double difftime(time_t time1, time_t time0)
+{
+#if (LONG_MAX >> DBL_MANT_DIG) == 0
+
+ /* time_t fits in the mantissa of a double. */
+ return (double)time1 - (double)time0;
+
+#elif ((LONG_MAX >> DBL_MANT_DIG) >> DBL_MANT_DIG) == 0
+
+ /* time_t can overflow the mantissa of a double. */
+ time_t t1, t0, d;
+
+ d = ((time_t) 1) << DBL_MANT_DIG;
+ t1 = time1 / d;
+ time1 -= (t1 * d);
+ t0 = time0 / d;
+ time0 -= (t0*d);
+
+ /* Since FLT_RADIX==2 and d is a power of 2, the only possible
+ * rounding error in the expression below would occur from the
+ * addition. */
+ return (((double) t1) - t0) * d + (((double) time1) - time0);
+
+#else
+#error difftime needs special implementation on your arch.
+#endif
+}
+
+#endif
+/**********************************************************************/
+#ifdef L_gmtime
+
+struct tm *gmtime(const time_t *timer)
+{
+ register struct tm *ptm = &__time_tm;
+
+ _time_t2tm(timer, 0, ptm); /* Can return NULL... */
+
+ return ptm;
+}
+
+#endif
+/**********************************************************************/
+#ifdef L_gmtime_r
+
+struct tm *gmtime_r(const time_t *__restrict timer,
+ struct tm *__restrict result)
+{
+ return _time_t2tm(timer, 0, result);
+}
+
+#endif
+/**********************************************************************/
+#ifdef L_localtime
+
+struct tm *localtime(const time_t *timer)
+{
+ register struct tm *ptm = &__time_tm;
+
+ /* In this implementation, tzset() is called by localtime_r(). */
+
+ localtime_r(timer, ptm); /* Can return NULL... */
+
+ return ptm;
+}
+libc_hidden_def(localtime)
+
+#endif
+/**********************************************************************/
+#ifdef L_localtime_r
+
+struct tm *localtime_r(register const time_t *__restrict timer,
+ register struct tm *__restrict result)
+{
+ __UCLIBC_MUTEX_LOCK(_time_tzlock);
+
+ _time_tzset(*timer < new_rule_starts);
+
+ __time_localtime_tzi(timer, result, _time_tzinfo);
+
+ __UCLIBC_MUTEX_UNLOCK(_time_tzlock);
+
+ return result;
+}
+libc_hidden_def(localtime_r)
+
+#endif
+/**********************************************************************/
+#ifdef L__time_localtime_tzi
+
+#ifdef __UCLIBC_HAS_TM_EXTENSIONS__
+
+struct ll_tzname_item;
+
+typedef struct ll_tzname_item {
+ struct ll_tzname_item *next;
+ char tzname[1];
+} ll_tzname_item_t;
+
+/* Structures form a list "UTC" -> "???" -> "tzname1" -> "tzname2"... */
+struct {
+ struct ll_tzname_item *next;
+ char tzname[4];
+} ll_tzname_UNKNOWN = { NULL, "???" };
+const struct {
+ struct ll_tzname_item *next;
+ char tzname[4];
+} ll_tzname_UTC = { (void*)&ll_tzname_UNKNOWN, "UTC" };
+
+static const char *lookup_tzname(const char *key)
+{
+ int len;
+ ll_tzname_item_t *p = (void*) &ll_tzname_UTC;
+
+ do {
+ if (strcmp(p->tzname, key) == 0)
+ return p->tzname;
+ p = p->next;
+ } while (p != NULL);
+
+ /* Hmm... a new name. */
+ len = strnlen(key, TZNAME_MAX+1);
+ if (len < TZNAME_MAX+1) { /* Verify legal length */
+ p = malloc(sizeof(ll_tzname_item_t) + len);
+ if (p != NULL) {
+ /* Insert as 3rd item in the list. */
+ p->next = ll_tzname_UNKNOWN.next;
+ ll_tzname_UNKNOWN.next = p;
+ return strcpy(p->tzname, key);
+ }
+ }
+
+ /* Either invalid or couldn't alloc. */
+ return ll_tzname_UNKNOWN.tzname;
+}
+
+#endif /* __UCLIBC_HAS_TM_EXTENSIONS__ */
+
+static const unsigned char day_cor[] = { /* non-leap */
+ 31, 31, 34, 34, 35, 35, 36, 36, 36, 37, 37, 38, 38
+/* 0, 0, 3, 3, 4, 4, 5, 5, 5, 6, 6, 7, 7 */
+/* 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 */
+};
+
+/* Note: timezone locking is done by localtime_r. */
+
+static int tm_isdst(register const struct tm *__restrict ptm,
+ register rule_struct *r)
+{
+ long sec;
+ int i, isdst, isleap, day, day0, monlen, mday;
+ int oday = oday; /* ok to be uninitialized, shutting up compiler warning */
+
+ isdst = 0;
+ if (r[1].tzname[0] != 0) {
+ /* First, get the current seconds offset from the start of the year.
+ * Fields of ptm are assumed to be in their normal ranges. */
+ sec = ptm->tm_sec
+ + 60 * (ptm->tm_min
+ + 60 * (long)(ptm->tm_hour
+ + 24 * ptm->tm_yday));
+ /* Do some prep work. */
+ i = (ptm->tm_year % 400) + 1900; /* Make sure we don't overflow. */
+ isleap = __isleap(i);
+ --i;
+ day0 = (1
+ + i /* Normal years increment 1 wday. */
+ + (i/4)
+ - (i/100)
+ + (i/400) ) % 7;
+ i = 0;
+ do {
+ day = r->day; /* Common for 'J' and # case. */
+ if (r->rule_type == 'J') {
+ if (!isleap || (day < (31+29))) {
+ --day;
+ }
+ } else if (r->rule_type == 'M') {
+ /* Find 0-based day number for 1st of the month. */
+ day = 31*r->month - day_cor[r->month -1];
+ if (isleap && (day >= 59)) {
+ ++day;
+ }
+ monlen = 31 + day_cor[r->month -1] - day_cor[r->month];
+ if (isleap && (r->month == 2)) {
+ ++monlen;
+ }
+ /* Wweekday (0 is Sunday) of 1st of the month
+ * is (day0 + day) % 7. */
+ if ((mday = r->day - ((day0 + day) % 7)) >= 0) {
+ mday -= 7; /* Back up into prev month since r->week>0. */
+ }
+ if ((mday += 7 * r->week) >= monlen) {
+ mday -= 7;
+ }
+ /* So, 0-based day number is... */
+ day += mday;
+ }
+
+ if (i != 0) {
+ /* Adjust sec since dst->std change time is in dst. */
+ sec += (r[-1].gmt_offset - r->gmt_offset);
+ if (oday > day) {
+ ++isdst; /* Year starts in dst. */
+ }
+ }
+ oday = day;
+
+ /* Now convert day to seconds and add offset and compare. */
+ if (sec >= (day * 86400L) + r->dst_offset) {
+ ++isdst;
+ }
+ ++r;
+ } while (++i < 2);
+ }
+
+ return (isdst & 1);
+}
+
+struct tm attribute_hidden *__time_localtime_tzi(register const time_t *__restrict timer,
+ register struct tm *__restrict result,
+ rule_struct *tzi)
+{
+ time_t x[1];
+ long offset;
+ int days, dst;
+
+ dst = 0;
+ do {
+ days = -7;
+ offset = 604800L - tzi[dst].gmt_offset;
+ if (*timer > (LONG_MAX - 604800L)) {
+ days = -days;
+ offset = -offset;
+ }
+ *x = *timer + offset;
+
+ _time_t2tm(x, days, result);
+ result->tm_isdst = dst;
+#ifdef __UCLIBC_HAS_TM_EXTENSIONS__
+# ifdef __USE_BSD
+ result->tm_gmtoff = - tzi[dst].gmt_offset;
+ result->tm_zone = lookup_tzname(tzi[dst].tzname);
+# else
+ result->__tm_gmtoff = - tzi[dst].gmt_offset;
+ result->__tm_zone = lookup_tzname(tzi[dst].tzname);
+# endif
+#endif /* __UCLIBC_HAS_TM_EXTENSIONS__ */
+ } while ((++dst < 2)
+ && ((result->tm_isdst = tm_isdst(result, tzi)) != 0));
+
+ return result;
+}
+
+#endif
+/**********************************************************************/
+#ifdef L_mktime
+
+time_t mktime(struct tm *timeptr)
+{
+ return _time_mktime(timeptr, 1);
+}
+
+/* Another name for `mktime'. */
+/* time_t timelocal(struct tm *tp) */
+strong_alias(mktime,timelocal)
+
+#endif
+/**********************************************************************/
+#ifdef L_timegm
+/* Like `mktime' but timeptr represents Universal Time, not local time. */
+
+time_t timegm(struct tm *timeptr)
+{
+ rule_struct gmt_tzinfo[2];
+
+ memset(gmt_tzinfo, 0, sizeof(gmt_tzinfo));
+ strcpy(gmt_tzinfo[0].tzname, "GMT"); /* Match glibc behavior here. */
+
+ return _time_mktime_tzi(timeptr, 1, gmt_tzinfo);
+}
+
+#endif
+/**********************************************************************/
+#if defined(L_strftime) || defined(L_strftime_l)
+
+#if defined(__UCLIBC_HAS_XLOCALE__) && !defined(__UCLIBC_DO_XLOCALE)
+
+size_t strftime(char *__restrict s, size_t maxsize,
+ const char *__restrict format,
+ const struct tm *__restrict timeptr)
+{
+ return strftime_l(s, maxsize, format, timeptr, __UCLIBC_CURLOCALE);
+}
+
+#else /* defined(__UCLIBC_HAS_XLOCALE__) && !defined(__UCLIBC_DO_XLOCALE) */
+
+#define NO_E_MOD 0x80
+#define NO_O_MOD 0x40
+
+#define ILLEGAL_SPEC 0x3f
+
+#define INT_SPEC 0x00 /* must be 0x00!! */
+#define STRING_SPEC 0x10 /* must be 0x10!! */
+#define CALC_SPEC 0x20
+#define STACKED_SPEC 0x30
+
+#define MASK_SPEC 0x30
+
+/* Compatibility:
+ *
+ * No alternate digit (%O?) handling. Always uses 0-9.
+ * Alternate locale format (%E?) handling is broken for nontrivial ERAs.
+ * glibc's %P is currently faked by %p. This means it doesn't do lower case.
+ * glibc's %k, %l, and %s are handled.
+ * glibc apparently allows (and ignores) extraneous 'E' and 'O' modifiers,
+ * while they are flagged as illegal conversions here.
+ */
+
+/* Warning: Assumes ASCII values! (as do lots of other things in the lib...) */
+static const unsigned char spec[] = {
+ /* A */ 0x03 | STRING_SPEC | NO_E_MOD | NO_O_MOD,
+ /* B */ 0x04 | STRING_SPEC | NO_E_MOD | NO_O_MOD,
+ /* C */ 0x0a | INT_SPEC | NO_O_MOD,
+ /* D */ 0x02 | STACKED_SPEC | NO_E_MOD | NO_O_MOD,
+ /* E */ ILLEGAL_SPEC | NO_E_MOD | NO_O_MOD,
+ /* F */ 0x03 | STACKED_SPEC | NO_E_MOD | NO_O_MOD,
+ /* G */ 0x03 | CALC_SPEC | NO_E_MOD | NO_O_MOD,
+ /* H */ 0x0b | INT_SPEC | NO_E_MOD,
+ /* I */ 0x0c | INT_SPEC | NO_E_MOD,
+ /* J */ ILLEGAL_SPEC | NO_E_MOD | NO_O_MOD,
+ /* K */ ILLEGAL_SPEC | NO_E_MOD | NO_O_MOD,
+ /* L */ ILLEGAL_SPEC | NO_E_MOD | NO_O_MOD,
+ /* M */ 0x0d | INT_SPEC | NO_E_MOD,
+ /* N */ ILLEGAL_SPEC | NO_E_MOD | NO_O_MOD,
+ /* O */ ILLEGAL_SPEC | NO_E_MOD | NO_O_MOD,
+ /* P */ 0x05 | STRING_SPEC | NO_E_MOD | NO_O_MOD, /* glibc ; use %p */
+ /* Q */ ILLEGAL_SPEC | NO_E_MOD | NO_O_MOD,
+ /* R */ 0x04 | STACKED_SPEC | NO_E_MOD | NO_O_MOD,
+ /* S */ 0x0e | INT_SPEC | NO_E_MOD,
+ /* T */ 0x05 | STACKED_SPEC | NO_E_MOD | NO_O_MOD,
+ /* U */ 0x04 | CALC_SPEC | NO_E_MOD,
+ /* V */ 0x05 | CALC_SPEC | NO_E_MOD,
+ /* W */ 0x06 | CALC_SPEC | NO_E_MOD,
+ /* X */ 0x0a | STACKED_SPEC | NO_O_MOD,
+ /* Y */ 0x0f | INT_SPEC | NO_O_MOD,
+ /* Z */ 0x01 | CALC_SPEC | NO_E_MOD | NO_O_MOD,
+ '?', /* 26 */
+ '?', /* 27 */
+ '?', /* 28 */
+ '?', /* 29 */
+ 0, /* 30 */
+ 0, /* 31 */
+ /* a */ 0x00 | STRING_SPEC | NO_E_MOD | NO_O_MOD,
+ /* b */ 0x01 | STRING_SPEC | NO_E_MOD | NO_O_MOD,
+ /* c */ 0x08 | STACKED_SPEC | NO_O_MOD,
+ /* d */ 0x00 | INT_SPEC | NO_E_MOD,
+ /* e */ 0x01 | INT_SPEC | NO_E_MOD,
+ /* f */ ILLEGAL_SPEC | NO_E_MOD | NO_O_MOD,
+ /* g */ 0x02 | CALC_SPEC | NO_E_MOD | NO_O_MOD,
+ /* h */ 0x01 | STRING_SPEC | NO_E_MOD | NO_O_MOD, /* same as b */
+ /* i */ ILLEGAL_SPEC | NO_E_MOD | NO_O_MOD,
+ /* j */ 0x08 | INT_SPEC | NO_E_MOD | NO_O_MOD,
+ /* k */ 0x03 | INT_SPEC | NO_E_MOD | NO_O_MOD, /* glibc */
+ /* l */ 0x04 | INT_SPEC | NO_E_MOD | NO_O_MOD, /* glibc */
+ /* m */ 0x05 | INT_SPEC | NO_E_MOD,
+ /* n */ 0x00 | STACKED_SPEC | NO_E_MOD | NO_O_MOD,
+ /* o */ ILLEGAL_SPEC | NO_E_MOD | NO_O_MOD,
+ /* p */ 0x02 | STRING_SPEC | NO_E_MOD | NO_O_MOD,
+ /* q */ ILLEGAL_SPEC | NO_E_MOD | NO_O_MOD,
+ /* r */ 0x0b | STACKED_SPEC | NO_E_MOD | NO_O_MOD,
+ /* s */ 0x07 | CALC_SPEC | NO_E_MOD | NO_O_MOD, /* glibc */
+ /* t */ 0x01 | STACKED_SPEC | NO_E_MOD | NO_O_MOD,
+ /* u */ 0x07 | INT_SPEC | NO_E_MOD,
+ /* v */ ILLEGAL_SPEC | NO_E_MOD | NO_O_MOD,
+ /* w */ 0x02 | INT_SPEC | NO_E_MOD,
+ /* x */ 0x09 | STACKED_SPEC | NO_O_MOD,
+ /* y */ 0x09 | INT_SPEC,
+ /* z */ 0x00 | CALC_SPEC | NO_E_MOD | NO_O_MOD,
+
+
+ /* WARNING!!! These are dependent on the layout of struct tm!!! */
+#define FIELD_MAX (26+6+26)
+ 60 /* 61? */, 59, 23, 31, 11, 0 /* 9999 */, 6, 0 /* 365 */,
+
+#define TP_OFFSETS (FIELD_MAX+8)
+ 3, /* d */
+ 3, /* e */
+ 6, /* w */
+ 2, /* k */
+ 2, /* l */
+ 4, /* m */
+ 0, /* CURRENTLY UNUSED */
+ /* NOTE: u,j,y order must be preserved as 6,7,5 seq is used in the code! */
+#define CALC_OFFSETS (TP_OFFSETS + 7)
+ 6, /* u */
+ 7, /* j */
+ 5, /* y */
+ 5, /* C */
+ 2, /* H */
+ 2, /* I */
+ 1, /* M */
+ 0, /* S */
+ 5, /* Y */
+ 6, /* a */
+ 4, /* b, h */
+ 2, /* p */
+ 6, /* A */
+ 4, /* B */
+ 2, /* P */
+
+#define TP_CODES (TP_OFFSETS + 16 + 6)
+ 2 | 16, /* d */
+ 2, /* e */
+ 0 | 16, /* w */
+ 2, /* k */
+ 2 | 32 | 0, /* l */
+ 2 | 16 | 1, /* m */
+ 0, /* CURRENTLY UNUSED */
+ 0 | 16 | 8 , /* u */
+ 4 | 16 | 1, /* j */
+ 2 | 128 | 32 | 16 , /* y */
+ 2 | 128 | 64 | 32 | 16 , /* C */
+ 2 | 16, /* H */
+ 2 | 32 | 16 | 0, /* I */
+ 2 | 16, /* M */
+ 2 | 16, /* S */
+ 6 | 16, /* Y */
+ 2, /* a */
+ 2, /* b, h */
+ 2 | 64, /* p */
+ 2, /* A */
+ 2, /* B */
+ 2 | 64, /* P */
+
+#define STRINGS_NL_ITEM_START (TP_CODES + 16 + 6)
+ _NL_ITEM_INDEX(ABDAY_1), /* a */
+ _NL_ITEM_INDEX(ABMON_1), /* b, h */
+ _NL_ITEM_INDEX(AM_STR), /* p */
+ _NL_ITEM_INDEX(DAY_1), /* A */
+ _NL_ITEM_INDEX(MON_1), /* B */
+ _NL_ITEM_INDEX(AM_STR), /* P -- wrong! need lower case */
+
+#define STACKED_STRINGS_START (STRINGS_NL_ITEM_START+6)
+ 6, 7, 8, 16, 24, 29, /* 6 - offsets from offset-count to strings */
+ '\n', 0, /* 2 */
+ '\t', 0, /* 2 */
+ '%', 'm', '/', '%', 'd', '/', '%', 'y', 0, /* 9 - %D */
+ '%', 'Y', '-', '%', 'm', '-', '%', 'd', 0, /* 9 - %F (glibc extension) */
+ '%', 'H', ':', '%', 'M', 0, /* 6 - %R*/
+ '%', 'H', ':', '%', 'M', ':', '%', 'S', 0, /* 9 - %T */
+
+#define STACKED_STRINGS_NL_ITEM_START (STACKED_STRINGS_START + 43)
+ _NL_ITEM_INDEX(D_T_FMT), /* c */
+ _NL_ITEM_INDEX(D_FMT), /* x */
+ _NL_ITEM_INDEX(T_FMT), /* X */
+ _NL_ITEM_INDEX(T_FMT_AMPM), /* r */
+#ifdef ENABLE_ERA_CODE
+ _NL_ITEM_INDEX(ERA_D_T_FMT), /* Ec */
+ _NL_ITEM_INDEX(ERA_D_FMT), /* Ex */
+ _NL_ITEM_INDEX(ERA_T_FMT), /* EX */
+#endif
+};
+
+static int load_field(int k, const struct tm *__restrict timeptr)
+{
+ int r;
+ int r_max;
+
+ r = ((int *) timeptr)[k];
+
+ r_max = spec[FIELD_MAX + k];
+
+ if (k == 7) {
+ r_max = 365;
+ } else if (k == 5) {
+ r += 1900;
+ r_max = 9999;
+ }
+
+ if ((((unsigned int) r) > r_max) || ((k == 3) && !r)) {
+ r = -1;
+ }
+
+ return r;
+}
+
+#define MAX_PUSH 4
+
+#ifdef __UCLIBC_MJN3_ONLY__
+#warning TODO: Check multibyte format string validity.
+#endif
+
+size_t __XL_NPP(strftime)(char *__restrict s, size_t maxsize,
+ const char *__restrict format,
+ const struct tm *__restrict timeptr __LOCALE_PARAM )
+{
+ long tzo;
+ register const char *p;
+ register const char *o;
+#ifndef __UCLIBC_HAS_TM_EXTENSIONS__
+ const rule_struct *rsp;
+#endif
+ const char *stack[MAX_PUSH];
+ size_t count;
+ size_t o_count;
+ int field_val = 0, i = 0, j, lvl;
+ int x[3]; /* wday, yday, year */
+ int isofm, days;
+ char buf[__UIM_BUFLEN_LONG];
+ unsigned char mod;
+ unsigned char code;
+
+ /* We'll, let's get this out of the way. */
+ _time_tzset(_time_mktime((struct tm *) timeptr, 0) < new_rule_starts);
+
+ lvl = 0;
+ p = format;
+ count = maxsize;
+
+LOOP:
+ if (!count) {
+ return 0;
+ }
+ if (!*p) {
+ if (lvl == 0) {
+ *s = 0; /* nul-terminate */
+ return maxsize - count;
+ }
+ p = stack[--lvl];
+ goto LOOP;
+ }
+
+ o_count = 1;
+ if ((*(o = p) == '%') && (*++p != '%')) {
+ o_count = 2;
+ mod = ILLEGAL_SPEC;
+ if ((*p == 'O') || (*p == 'E')) { /* modifier */
+ mod |= ((*p == 'O') ? NO_O_MOD : NO_E_MOD);
+ ++o_count;
+ ++p;
+ }
+ if ((((unsigned char)(((*p) | 0x20) - 'a')) >= 26)
+ || (((code = spec[(int)(*p - 'A')]) & mod) >= ILLEGAL_SPEC)
+ ) {
+ if (!*p) {
+ --p;
+ --o_count;
+ }
+ goto OUTPUT;
+ }
+ code &= ILLEGAL_SPEC; /* modifiers are preserved in mod var. */
+
+ if ((code & MASK_SPEC) == STACKED_SPEC) {
+ if (lvl == MAX_PUSH) {
+ goto OUTPUT; /* Stack full so treat as illegal spec. */
+ }
+ stack[lvl++] = ++p;
+ if ((code &= 0xf) < 8) {
+ p = ((const char *) spec) + STACKED_STRINGS_START + code;
+ p += *((unsigned char *)p);
+ goto LOOP;
+ }
+ p = ((const char *) spec) + STACKED_STRINGS_NL_ITEM_START
+ + (code & 7);
+#ifdef ENABLE_ERA_CODE
+ if ((mod & NO_E_MOD) /* Actually, this means E modifier present. */
+ && (*(o = __XL_NPP(nl_langinfo)(_NL_ITEM(LC_TIME,
+ (int)(((unsigned char *)p)[4]))
+ __LOCALE_ARG
+ )))
+ ) {
+ p = o;
+ goto LOOP;
+ }
+#endif
+ p = __XL_NPP(nl_langinfo)(_NL_ITEM(LC_TIME,
+ (int)(*((unsigned char *)p)))
+ __LOCALE_ARG
+ );
+ goto LOOP;
+ }
+
+ o = ((const char *) spec) + 26; /* set to "????" */
+ if ((code & MASK_SPEC) == CALC_SPEC) {
+
+ if (*p == 's') {
+ time_t t;
+
+ /* Use a cast to silence the warning since *timeptr won't
+ * be changed. */
+ if ((t = _time_mktime((struct tm *) timeptr, 0))
+ == ((time_t) -1)
+ ) {
+ o_count = 1;
+ goto OUTPUT;
+ }
+#ifdef TIME_T_IS_UNSIGNED
+ o = _uintmaxtostr(buf + sizeof(buf) - 1,
+ (uintmax_t) t,
+ 10, __UIM_DECIMAL);
+#else
+ o = _uintmaxtostr(buf + sizeof(buf) - 1,
+ (uintmax_t) t,
+ -10, __UIM_DECIMAL);
+#endif
+ o_count = sizeof(buf);
+ goto OUTPUT;
+ } else if (((*p) | 0x20) == 'z') { /* 'z' or 'Z' */
+
+ if (timeptr->tm_isdst < 0) {
+ /* SUSv3 specifies this behavior for 'z', but we'll also
+ * treat it as "no timezone info" for 'Z' too. */
+ o_count = 0;
+ goto OUTPUT;
+ }
+
+#ifdef __UCLIBC_HAS_TM_EXTENSIONS__
+
+# ifdef __USE_BSD
+# define RSP_TZNAME timeptr->tm_zone
+# define RSP_GMT_OFFSET (-timeptr->tm_gmtoff)
+# else
+# define RSP_TZNAME timeptr->__tm_zone
+# define RSP_GMT_OFFSET (-timeptr->__tm_gmtoff)
+# endif
+
+#else
+
+#define RSP_TZNAME rsp->tzname
+#define RSP_GMT_OFFSET rsp->gmt_offset
+
+ __UCLIBC_MUTEX_LOCK(_time_tzlock);
+
+ rsp = _time_tzinfo;
+ if (timeptr->tm_isdst > 0) {
+ ++rsp;
+ }
+#endif
+
+ if (*p == 'Z') {
+ o = RSP_TZNAME;
+#ifdef __UCLIBC_HAS_TM_EXTENSIONS__
+ /* Sigh... blasted glibc extensions. Of course we can't
+ * count on the pointer being valid. Best we can do is
+ * handle NULL, which looks to be all that glibc does.
+ * At least that catches the memset() with 0 case.
+ * NOTE: We handle this case differently than glibc!
+ * It uses system timezone name (based on tm_isdst) in this
+ * case... although it always seems to use the embedded
+ * tm_gmtoff value. What we'll do instead is treat the
+ * timezone name as unknown/invalid and return "???". */
+ if (!o) {
+ o = "???";
+ }
+#endif
+ assert(o != NULL);
+#if 0
+ if (!o) { /* PARANOIA */
+ o = spec+30; /* empty string */
+ }
+#endif
+ o_count = SIZE_MAX;
+#ifdef __UCLIBC_HAS_TM_EXTENSIONS__
+ goto OUTPUT;
+#endif
+ } else { /* z */
+ *s = '+';
+ if ((tzo = -RSP_GMT_OFFSET) < 0) {
+ tzo = -tzo;
+ *s = '-';
+ }
+ ++s;
+ --count;
+
+ i = tzo / 60;
+ field_val = ((i / 60) * 100) + (i % 60);
+
+ i = 16 + 6; /* 0-fill, width = 4 */
+ }
+#ifndef __UCLIBC_HAS_TM_EXTENSIONS__
+ __UCLIBC_MUTEX_UNLOCK(_time_tzlock);
+ if (*p == 'Z') {
+ goto OUTPUT;
+ }
+#endif
+ } else {
+ /* TODO: don't need year for U, W */
+ for (i=0 ; i < 3 ; i++) {
+ if ((x[i] = load_field(spec[CALC_OFFSETS+i],timeptr)) < 0) {
+ goto OUTPUT;
+ }
+ }
+
+ i = 16 + 2; /* 0-fill, width = 2 */
+
+ if ((*p == 'U') || (*p == 'W')) {
+ field_val = ((x[1] - x[0]) + 7);
+ if (*p == 'W') {
+ ++field_val;
+ }
+ field_val /= 7;
+ if ((*p == 'W') && !x[0]) {
+ --field_val;
+ }
+ } else { /* ((*p == 'g') || (*p == 'G') || (*p == 'V')) */
+ISO_LOOP:
+ isofm = (((x[1] - x[0]) + 11) % 7) - 3; /* [-3,3] */
+
+ if (x[1] < isofm) { /* belongs to previous year */
+ --x[2];
+ x[1] += 365 + __isleap(x[2]);
+ goto ISO_LOOP;
+ }
+
+ field_val = ((x[1] - isofm) / 7) + 1; /* week # */
+ days = 365 + __isleap(x[2]);
+ isofm = ((isofm + 7*53 + 3 - days)) % 7 + days - 3; /* next year */
+ if (x[1] >= isofm) { /* next year */
+ x[1] -= days;
+ ++x[2];
+ goto ISO_LOOP;
+ }
+
+ if (*p != 'V') { /* need year */
+ field_val = x[2]; /* TODO: what if x[2] now 10000 ?? */
+ if (*p == 'g') {
+ field_val %= 100;
+ } else {
+ i = 16 + 6; /* 0-fill, width = 4 */
+ }
+ }
+ }
+ }
+ } else {
+ i = TP_OFFSETS + (code & 0x1f);
+ if ((field_val = load_field(spec[i], timeptr)) < 0) {
+ goto OUTPUT;
+ }
+
+ i = spec[i+(TP_CODES - TP_OFFSETS)];
+
+ j = (i & 128) ? 100: 12;
+ if (i & 64) {
+ field_val /= j;;
+ }
+ if (i & 32) {
+ field_val %= j;
+ if (((i & 128) + field_val) == 0) { /* mod 12? == 0 */
+ field_val = j; /* set to 12 */
+ }
+ }
+ field_val += (i & 1);
+ if ((i & 8) && !field_val) {
+ field_val += 7;
+ }
+ }
+
+ if ((code & MASK_SPEC) == STRING_SPEC) {
+ o_count = SIZE_MAX;
+ field_val += spec[STRINGS_NL_ITEM_START + (code & 0xf)];
+ o = __XL_NPP(nl_langinfo)(_NL_ITEM(LC_TIME, field_val) __LOCALE_ARG);
+ } else {
+ o_count = ((i >> 1) & 3) + 1;
+ o = buf + o_count;
+ do {
+ *(char *)(--o) = '0' + (field_val % 10);
+ field_val /= 10;
+ } while (o > buf);
+ if (*buf == '0') {
+ *buf = ' ' + (i & 16);
+ }
+ }
+ }
+
+OUTPUT:
+ ++p;
+ while (o_count && count && *o) {
+ *s++ = *o++;
+ --o_count;
+ --count;
+ }
+ goto LOOP;
+}
+# ifdef L_strftime_l
+libc_hidden_def(strftime_l)
+# endif
+
+#endif /* defined(__UCLIBC_HAS_XLOCALE__) && !defined(__UCLIBC_DO_XLOCALE) */
+
+#endif
+/**********************************************************************/
+#if defined(L_strptime) || defined(L_strptime_l)
+
+#define ISDIGIT(C) __isdigit_char((C))
+
+#ifdef __UCLIBC_DO_XLOCALE
+#define ISSPACE(C) isspace_l((C), locale_arg)
+#else
+#define ISSPACE(C) isspace((C))
+#endif
+
+#if defined(__UCLIBC_HAS_XLOCALE__) && !defined(__UCLIBC_DO_XLOCALE)
+
+char *strptime(const char *__restrict buf, const char *__restrict format,
+ struct tm *__restrict tm)
+{
+ return strptime_l(buf, format, tm, __UCLIBC_CURLOCALE);
+}
+
+#else /* defined(__UCLIBC_HAS_XLOCALE__) && !defined(__UCLIBC_DO_XLOCALE) */
+
+/* TODO:
+ * 1) %l and %k are space-padded, so "%l" by itself fails while " %l" succeeds.
+ * Both work for glibc. So, should we always strip spaces?
+ * 2) %Z
+ */
+
+/* Notes:
+ * There are several differences between this strptime and glibc's strptime.
+ * 1) glibc strips leading space before numeric conversions.
+ * 2) glibc will read fields without whitespace in between. SUSv3 states
+ * that you must have whitespace between conversion operators. Besides,
+ * how do you know how long a number should be if there are leading 0s?
+ * 3) glibc attempts to compute some the struct tm fields based on the
+ * data retrieved; tm_wday in particular. I don't as I consider it
+ * another glibc attempt at mind-reading...
+ */
+
+#define NO_E_MOD 0x80
+#define NO_O_MOD 0x40
+
+#define ILLEGAL_SPEC 0x3f
+
+#define INT_SPEC 0x00 /* must be 0x00!! */
+#define STRING_SPEC 0x10 /* must be 0x10!! */
+#define CALC_SPEC 0x20
+#define STACKED_SPEC 0x30
+
+#define MASK_SPEC 0x30
+
+/* Warning: Assumes ASCII values! (as do lots of other things in the lib...) */
+static const unsigned char spec[] = {
+ /* A */ 0x02 | STRING_SPEC | NO_E_MOD | NO_O_MOD,
+ /* B */ 0x01 | STRING_SPEC | NO_E_MOD | NO_O_MOD,
+ /* C */ 0x08 | INT_SPEC | NO_O_MOD,
+ /* D */ 0x01 | STACKED_SPEC | NO_E_MOD | NO_O_MOD,
+ /* E */ ILLEGAL_SPEC | NO_E_MOD | NO_O_MOD,
+ /* F */ 0x02 | STACKED_SPEC | NO_E_MOD | NO_O_MOD, /* glibc */
+ /* G */ 0x0f | INT_SPEC | NO_E_MOD | NO_O_MOD, /* glibc */
+ /* H */ 0x06 | INT_SPEC | NO_E_MOD,
+ /* I */ 0x07 | INT_SPEC | NO_E_MOD,
+ /* J */ ILLEGAL_SPEC | NO_E_MOD | NO_O_MOD,
+ /* K */ ILLEGAL_SPEC | NO_E_MOD | NO_O_MOD,
+ /* L */ ILLEGAL_SPEC | NO_E_MOD | NO_O_MOD,
+ /* M */ 0x04 | INT_SPEC | NO_E_MOD,
+ /* N */ ILLEGAL_SPEC | NO_E_MOD | NO_O_MOD,
+ /* O */ ILLEGAL_SPEC | NO_E_MOD | NO_O_MOD,
+ /* P */ 0x00 | STRING_SPEC | NO_E_MOD | NO_O_MOD, /* glibc */
+ /* Q */ ILLEGAL_SPEC | NO_E_MOD | NO_O_MOD,
+ /* R */ 0x03 | STACKED_SPEC | NO_E_MOD | NO_O_MOD,
+ /* S */ 0x05 | INT_SPEC | NO_E_MOD,
+ /* T */ 0x04 | STACKED_SPEC | NO_E_MOD | NO_O_MOD,
+ /* U */ 0x0c | INT_SPEC | NO_E_MOD,
+ /* V */ 0x0d | INT_SPEC | NO_E_MOD | NO_O_MOD, /* glibc */
+ /* W */ 0x0c | INT_SPEC | NO_E_MOD,
+ /* X */ 0x0a | STACKED_SPEC | NO_O_MOD,
+ /* Y */ 0x0a | INT_SPEC | NO_O_MOD,
+ /* Z */ 0x02 | CALC_SPEC | NO_E_MOD | NO_O_MOD, /* glibc */
+
+ /* WARNING! This assumes orderings:
+ * AM,PM
+ * ABDAY_1-ABDAY-7,DAY_1-DAY_7
+ * ABMON_1-ABMON_12,MON_1-MON12
+ * Also, there are exactly 6 bytes between 'Z' and 'a'.
+ */
+#define STRINGS_NL_ITEM_START (26)
+ _NL_ITEM_INDEX(AM_STR), /* p (P) */
+ _NL_ITEM_INDEX(ABMON_1), /* B, b */
+ _NL_ITEM_INDEX(ABDAY_1), /* A, a */
+ 2,
+ 24,
+ 14,
+
+ /* a */ 0x02 | STRING_SPEC | NO_E_MOD | NO_O_MOD,
+ /* b */ 0x01 | STRING_SPEC | NO_E_MOD | NO_O_MOD,
+ /* c */ 0x08 | STACKED_SPEC | NO_O_MOD,
+ /* d */ 0x00 | INT_SPEC | NO_E_MOD,
+ /* e */ 0x00 | INT_SPEC | NO_E_MOD,
+ /* f */ ILLEGAL_SPEC | NO_E_MOD | NO_O_MOD,
+ /* g */ 0x0e | INT_SPEC | NO_E_MOD | NO_O_MOD, /* glibc */
+ /* h */ 0x01 | STRING_SPEC | NO_E_MOD | NO_O_MOD,
+ /* i */ ILLEGAL_SPEC | NO_E_MOD | NO_O_MOD,
+ /* j */ 0x01 | INT_SPEC | NO_E_MOD | NO_O_MOD,
+ /* k */ 0x06 | INT_SPEC | NO_E_MOD, /* glibc */
+ /* l */ 0x07 | INT_SPEC | NO_E_MOD, /* glibc */
+ /* m */ 0x02 | INT_SPEC | NO_E_MOD,
+ /* n */ 0x00 | STACKED_SPEC | NO_E_MOD | NO_O_MOD,
+ /* o */ ILLEGAL_SPEC | NO_E_MOD | NO_O_MOD,
+ /* p */ 0x00 | STRING_SPEC | NO_E_MOD | NO_O_MOD,
+ /* q */ ILLEGAL_SPEC | NO_E_MOD | NO_O_MOD,
+ /* r */ 0x0b | STACKED_SPEC | NO_E_MOD | NO_O_MOD,
+ /* s */ 0x00 | CALC_SPEC | NO_E_MOD | NO_O_MOD, /* glibc */
+ /* t */ 0x00 | STACKED_SPEC | NO_E_MOD | NO_O_MOD,
+ /* u */ 0x0b | INT_SPEC | NO_E_MOD | NO_O_MOD, /* glibc */
+ /* v */ ILLEGAL_SPEC | NO_E_MOD | NO_O_MOD,
+ /* w */ 0x03 | INT_SPEC | NO_E_MOD,
+ /* x */ 0x09 | STACKED_SPEC | NO_O_MOD,
+ /* y */ 0x09 | INT_SPEC,
+ /* z */ 0x01 | CALC_SPEC | NO_E_MOD | NO_O_MOD, /* glibc */
+
+#define INT_FIELD_START (26+6+26)
+ /* (field #) << 3 + lower bound (0|1) + correction 0:none, 2:-1, 4:-1900
+ * followed by upper bound prior to correction with 1=>366 and 2=>9999. */
+ /* d, e */ (3 << 3) + 1 + 0, 31,
+ /* j */ (7 << 3) + 1 + 2, /* 366 */ 1,
+ /* m */ (4 << 3) + 1 + 2, 12,
+ /* w */ (6 << 3) + 0 + 0, 6,
+ /* M */ (1 << 3) + 0 + 0, 59,
+ /* S */ 0 + 0 + 0, 60,
+ /* H (k) */ (2 << 3) + 0 + 0, 23,
+ /* I (l) */ (9 << 3) + 1 + 0, 12, /* goes with 8 -- am/pm */
+ /* C */ (10<< 3) + 0 + 0, 99,
+ /* y */ (11<< 3) + 0 + 0, 99,
+ /* Y */ (5 << 3) + 0 + 4, /* 9999 */ 2,
+ /* u */ (6 << 3) + 1 + 0, 7,
+ /* The following are processed and range-checked, but ignored otherwise. */
+ /* U, W */ (12<< 3) + 0 + 0, 53,
+ /* V */ (12<< 3) + 1 + 0, 53,
+ /* g */ (12<< 3) + 0 + 0, 99,
+ /* G */ (12<< 3) + 0 /*+ 4*/, /* 9999 */ 2, /* Note: -1 or 10000? */
+
+#define STACKED_STRINGS_START (INT_FIELD_START+32)
+ 5, 6, 14, 22, 27, /* 5 - offsets from offset-count to strings */
+ ' ', 0, /* 2 - %n or %t */
+ '%', 'm', '/', '%', 'd', '/', '%', 'y', 0, /* 9 - %D */
+ '%', 'Y', '-', '%', 'm', '-', '%', 'd', 0, /* 9 - %F (glibc extension) */
+ '%', 'H', ':', '%', 'M', 0, /* 6 - %R*/
+ '%', 'H', ':', '%', 'M', ':', '%', 'S', 0, /* 9 - %T */
+
+#define STACKED_STRINGS_NL_ITEM_START (STACKED_STRINGS_START + 40)
+ _NL_ITEM_INDEX(D_T_FMT), /* c */
+ _NL_ITEM_INDEX(D_FMT), /* x */
+ _NL_ITEM_INDEX(T_FMT), /* X */
+ _NL_ITEM_INDEX(T_FMT_AMPM), /* r */
+#ifdef ENABLE_ERA_CODE
+ _NL_ITEM_INDEX(ERA_D_T_FMT), /* Ec */
+ _NL_ITEM_INDEX(ERA_D_FMT), /* Ex */
+ _NL_ITEM_INDEX(ERA_T_FMT), /* EX */
+#endif
+};
+
+#define MAX_PUSH 4
+
+char *__XL_NPP(strptime)(const char *__restrict buf, const char *__restrict format,
+ struct tm *__restrict tm __LOCALE_PARAM)
+{
+ register const char *p;
+ char *o;
+ const char *stack[MAX_PUSH];
+ int i, j, lvl;
+ int fields[13];
+ unsigned char mod;
+ unsigned char code;
+
+ i = 0;
+ do {
+ fields[i] = INT_MIN;
+ } while (++i < 13);
+
+ lvl = 0;
+ p = format;
+
+LOOP:
+ if (!*p) {
+ if (lvl == 0) { /* Done. */
+ if (fields[6] == 7) { /* Cleanup for %u here since just once. */
+ fields[6] = 0; /* Don't use mod in case unset. */
+ }
+
+ i = 0;
+ do { /* Store the values into tm. */
+ if (fields[i] != INT_MIN) {
+ ((int *) tm)[i] = fields[i];
+ }
+ } while (++i < 8);
+
+ return (char *) buf; /* Success. */
+ }
+ p = stack[--lvl];
+ goto LOOP;
+ }
+
+ if ((*p == '%') && (*++p != '%')) {
+ mod = ILLEGAL_SPEC;
+ if ((*p == 'O') || (*p == 'E')) { /* Modifier? */
+ mod |= ((*p == 'O') ? NO_O_MOD : NO_E_MOD);
+ ++p;
+ }
+
+ if (!*p
+ || (((unsigned char)(((*p) | 0x20) - 'a')) >= 26)
+ || (((code = spec[(int)(*p - 'A')]) & mod) >= ILLEGAL_SPEC)
+ ) {
+ return NULL; /* Illegal spec. */
+ }
+
+ if ((code & MASK_SPEC) == STACKED_SPEC) {
+ if (lvl == MAX_PUSH) {
+ return NULL; /* Stack full so treat as illegal spec. */
+ }
+ stack[lvl++] = ++p;
+ if ((code &= 0xf) < 8) {
+ p = ((const char *) spec) + STACKED_STRINGS_START + code;
+ p += *((unsigned char *)p);
+ goto LOOP;
+ }
+
+ p = ((const char *) spec) + STACKED_STRINGS_NL_ITEM_START
+ + (code & 7);
+#ifdef ENABLE_ERA_CODE
+ if ((mod & NO_E_MOD) /* Actually, this means E modifier present. */
+ && (*(o = __XL_NPP(nl_langinfo)(_NL_ITEM(LC_TIME,
+ (int)(((unsigned char *)p)[4]))
+ __LOCALE_ARG
+ )))
+ ) {
+ p = o;
+ goto LOOP;
+ }
+#endif
+ p = __XL_NPP(nl_langinfo)(_NL_ITEM(LC_TIME,
+ (int)(*((unsigned char *)p)))
+ __LOCALE_ARG
+ );
+ goto LOOP;
+ }
+
+ ++p;
+
+ if ((code & MASK_SPEC) == STRING_SPEC) {
+ code &= 0xf;
+ j = spec[STRINGS_NL_ITEM_START + 3 + code];
+ i = _NL_ITEM(LC_TIME, spec[STRINGS_NL_ITEM_START + code]);
+ /* Go backwards to check full names before abreviations. */
+ do {
+ --j;
+ o = __XL_NPP(nl_langinfo)(i+j __LOCALE_ARG);
+ if (!__XL_NPP(strncasecmp)(buf, o, strlen(o) __LOCALE_ARG) && *o) {
+ do { /* Found a match. */
+ ++buf;
+ } while (*++o);
+ if (!code) { /* am/pm */
+ fields[8] = j * 12;
+ if (fields[9] >= 0) { /* We have a previous %I or %l. */
+ fields[2] = fields[9] + fields[8];
+ }
+ } else { /* day (4) or month (6) */
+ fields[2 + (code << 1)]
+ = j % (spec[STRINGS_NL_ITEM_START + 3 + code] >> 1);
+ }
+ goto LOOP;
+ }
+ } while (j);
+ return NULL; /* Failed to match. */
+ }
+
+ if ((code & MASK_SPEC) == CALC_SPEC) {
+ if ((code &= 0xf) < 1) { /* s or z*/
+ time_t t;
+
+ o = (char *) buf;
+ i = errno;
+ __set_errno(0);
+ if (!ISSPACE(*buf)) { /* Signal an error if whitespace. */
+#ifdef TIME_T_IS_UNSIGNED
+ t = __XL_NPP(strtoul)(buf, &o, 10 __LOCALE_ARG);
+#else
+ t = __XL_NPP(strtol)(buf, &o, 10 __LOCALE_ARG);
+#endif
+ }
+ if ((o == buf) || errno) { /* Not a number or overflow. */
+ return NULL;
+ }
+ __set_errno(i); /* Restore errno. */
+ buf = o;
+
+ if (!code) { /* s */
+ localtime_r(&t, tm); /* TODO: check for failure? */
+ i = 0;
+ do { /* Now copy values from tm to fields. */
+ fields[i] = ((int *) tm)[i];
+ } while (++i < 8);
+ }
+ }
+ /* TODO: glibc treats %Z as a nop. For now, do the same. */
+ goto LOOP;
+ }
+
+ assert((code & MASK_SPEC) == INT_SPEC);
+ {
+ register const unsigned char *x;
+ code &= 0xf;
+ x = spec + INT_FIELD_START + (code << 1);
+ if ((j = x[1]) < 3) { /* upper bound (inclusive) */
+ j = ((j==1) ? 366 : 9999);
+ }
+ i = -1;
+ while (ISDIGIT(*buf)) {
+ if (i < 0) {
+ i = 0;
+ }
+ if ((i = 10*i + (*buf - '0')) > j) { /* Overflow. */
+ return NULL;
+ }
+ ++buf;
+ }
+ if (i < (*x & 1)) { /* This catches no-digit case too. */
+ return NULL;
+ }
+ if (*x & 2) {
+ --i;
+ }
+ if (*x & 4) {
+ i -= 1900;
+ }
+
+ if (*x == (9 << 3) + 1 + 0) { /* %I or %l */
+ if (i == 12) {
+ i = 0;
+ }
+ if (fields[8] >= 0) { /* We have a previous %p or %P. */
+ fields[2] = i + fields[8];
+ }
+ }
+
+ fields[(*x) >> 3] = i;
+
+ if (((unsigned char)(*x - (10 << 3) + 0 + 0)) <= 8) { /* %C or %y */
+ if ((j = fields[10]) < 0) { /* No %C, so i must be %y data. */
+ if (i <= 68) { /* Map [0-68] to 2000+i */
+ i += 100;
+ }
+ } else { /* Have %C data, but what about %y? */
+ if ((i = fields[11]) < 0) { /* No %y data. */
+ i = 0; /* Treat %y val as 0 following glibc's example. */
+ }
+ i += 100*(j - 19);
+ }
+ fields[5] = i;
+ }
+ }
+ goto LOOP;
+ } else if (ISSPACE(*p)) {
+ ++p;
+ while (ISSPACE(*buf)) {
+ ++buf;
+ }
+ goto LOOP;
+ } else if (*buf++ == *p++) {
+ goto LOOP;
+ }
+ return NULL;
+}
+# ifdef L_strptime_l
+libc_hidden_def(strptime_l)
+# endif
+
+#endif /* defined(__UCLIBC_HAS_XLOCALE__) && !defined(__UCLIBC_DO_XLOCALE) */
+
+#endif
+/**********************************************************************/
+#ifdef L_time
+
+#ifndef __BCC__
+#error The uClibc version of time is in sysdeps/linux/common.
+#endif
+
+time_t time(register time_t *tloc)
+{
+ struct timeval tv;
+ register struct timeval *p = &tv;
+
+ gettimeofday(p, NULL); /* This should never fail... */
+
+ if (tloc) {
+ *tloc = p->tv_sec;
+ }
+
+ return p->tv_sec;
+}
+
+#endif
+/**********************************************************************/
+#ifdef L_tzset
+
+static const char vals[] = {
+ 'T', 'Z', 0, /* 3 */
+ 'U', 'T', 'C', 0, /* 4 */
+ 25, 60, 60, 1, /* 4 */
+ '.', 1, /* M */
+ 5, '.', 1,
+ 6, 0, 0, /* Note: overloaded for non-M non-J case... */
+ 0, 1, 0, /* J */
+ ',', 'M', '4', '.', '1', '.', '0',
+ ',', 'M', '1', '0', '.', '5', '.', '0', 0,
+ ',', 'M', '3', '.', '2', '.', '0',
+ ',', 'M', '1', '1', '.', '1', '.', '0', 0
+};
+
+#define TZ vals
+#define UTC (vals + 3)
+#define RANGE (vals + 7)
+#define RULE (vals + 11 - 1)
+#define DEFAULT_RULES (vals + 22)
+#define DEFAULT_2007_RULES (vals + 38)
+
+/* Initialize to UTC. */
+int daylight = 0;
+long timezone = 0;
+char *tzname[2] = { (char *) UTC, (char *) (UTC-1) };
+
+__UCLIBC_MUTEX_INIT(_time_tzlock, PTHREAD_RECURSIVE_MUTEX_INITIALIZER_NP);
+
+rule_struct _time_tzinfo[2];
+
+static const char *getoffset(register const char *e, long *pn)
+{
+ register const char *s = RANGE-1;
+ long n;
+ int f;
+
+ n = 0;
+ f = -1;
+ do {
+ ++s;
+ if (__isdigit_char(*e)) {
+ f = *e++ - '0';
+ }
+ if (__isdigit_char(*e)) {
+ f = 10 * f + (*e++ - '0');
+ }
+ if (((unsigned int)f) >= *s) {
+ return NULL;
+ }
+ n = (*s) * n + f;
+ f = 0;
+ if (*e == ':') {
+ ++e;
+ --f;
+ }
+ } while (*s > 1);
+
+ *pn = n;
+ return e;
+}
+
+static const char *getnumber(register const char *e, int *pn)
+{
+#ifdef __BCC__
+ /* bcc can optimize the counter if it thinks it is a pointer... */
+ register const char *n = (const char *) 3;
+ int f;
+
+ f = 0;
+ while (n && __isdigit_char(*e)) {
+ f = 10 * f + (*e++ - '0');
+ --n;
+ }
+
+ *pn = f;
+ return (n == (const char *) 3) ? NULL : e;
+#else /* __BCC__ */
+ int n, f;
+
+ n = 3;
+ f = 0;
+ while (n && __isdigit_char(*e)) {
+ f = 10 * f + (*e++ - '0');
+ --n;
+ }
+
+ *pn = f;
+ return (n == 3) ? NULL : e;
+#endif /* __BCC__ */
+}
+
+
+#ifdef __UCLIBC_MJN3_ONLY__
+#warning CONSIDER: Should we preserve errno from open/read/close errors re TZ file?
+#endif
+
+#ifdef __UCLIBC_HAS_TZ_FILE__
+
+#ifndef __UCLIBC_HAS_TZ_FILE_READ_MANY__
+static smallint TZ_file_read; /* Let BSS initialization set this to 0. */
+#endif
+
+static char *read_TZ_file(char *buf)
+{
+ int r;
+ int fd;
+ char *p = NULL;
+
+ fd = open(__UCLIBC_TZ_FILE_PATH__, O_RDONLY);
+ if (fd >= 0) {
+#if 0
+ /* TZ are small *files*. On files, short reads
+ * only occur on EOF (unlike, say, pipes).
+ * The code below is pedanticallly more correct,
+ * but this way we always read at least twice:
+ * 1st read is short, 2nd one is zero bytes.
+ */
+ size_t todo = TZ_BUFLEN;
+ p = buf;
+ do {
+ r = read(fd, p, todo);
+ if (r < 0)
+ goto ERROR;
+ if (r == 0)
+ break;
+ p += r;
+ todo -= r;
+ } while (todo);
+#else
+ /* Shorter, and does one fewer read syscall */
+ r = read(fd, buf, TZ_BUFLEN);
+ if (r < 0)
+ goto ERROR;
+ p = buf + r;
+#endif
+ if ((p > buf) && (p[-1] == '\n')) { /* Must end with newline */
+ p[-1] = 0;
+ p = buf;
+#ifndef __UCLIBC_HAS_TZ_FILE_READ_MANY__
+ TZ_file_read = 1;
+#endif
+ } else {
+ERROR:
+ p = NULL;
+ }
+ close(fd);
+ }
+#ifdef __UCLIBC_FALLBACK_TO_ETC_LOCALTIME__
+ else {
+ fd = open("/etc/localtime", O_RDONLY);
+ if (fd >= 0) {
+ r = read(fd, buf, TZ_BUFLEN);
+ if (r != TZ_BUFLEN
+ || strncmp(buf, "TZif", 4) != 0
+ || (unsigned char)buf[4] < 2
+ || lseek(fd, -TZ_BUFLEN, SEEK_END) < 0
+ ) {
+ goto ERROR;
+ }
+ /* tzfile.h from tzcode database says about TZif2+ files:
+ **
+ ** If tzh_version is '2' or greater, the above is followed by a second instance
+ ** of tzhead and a second instance of the data in which each coded transition
+ ** time uses 8 rather than 4 chars,
+ ** then a POSIX-TZ-environment-variable-style string for use in handling
+ ** instants after the last transition time stored in the file
+ ** (with nothing between the newlines if there is no POSIX representation for
+ ** such instants).
+ */
+ r = read(fd, buf, TZ_BUFLEN);
+ if (r <= 0 || buf[--r] != '\n')
+ goto ERROR;
+ buf[r] = 0;
+ while (r != 0) {
+ if (buf[--r] == '\n') {
+ p = buf + r + 1;
+#ifndef __UCLIBC_HAS_TZ_FILE_READ_MANY__
+ TZ_file_read = 1;
+#endif
+ break;
+ }
+ } /* else ('\n' not found): p remains NULL */
+ close(fd);
+ }
+ }
+#endif /* __UCLIBC_FALLBACK_TO_ETC_LOCALTIME__ */
+ return p;
+}
+
+#endif /* __UCLIBC_HAS_TZ_FILE__ */
+
+void tzset(void)
+{
+ _time_tzset((time(NULL)) < new_rule_starts);
+}
+
+void _time_tzset(int use_old_rules)
+{
+ register const char *e;
+ register char *s;
+ long off = 0;
+ short *p;
+ rule_struct new_rules[2];
+ int n, count, f;
+ char c;
+#ifdef __UCLIBC_HAS_TZ_FILE__
+ char buf[TZ_BUFLEN];
+#endif
+#ifdef __UCLIBC_HAS_TZ_CACHING__
+ static char oldval[TZ_BUFLEN]; /* BSS-zero'd. */
+#endif
+
+ /* Put this inside the lock to prevent the possibility of two different
+ * timezones being used in a threaded app. */
+ __UCLIBC_MUTEX_LOCK(_time_tzlock);
+
+ e = getenv(TZ); /* TZ env var always takes precedence. */
+
+#if defined(__UCLIBC_HAS_TZ_FILE__) && !defined(__UCLIBC_HAS_TZ_FILE_READ_MANY__)
+ if (e) {
+ /* Never use TZfile if TZ env var is set. */
+ TZ_file_read = 0;
+ }
+ if (TZ_file_read) {
+ /* We already parsed TZfile before, skip everything. */
+ goto FAST_DONE;
+ }
+#endif
+
+ /* Warning!!! Since uClibc doesn't do lib locking, the following is
+ * potentially unsafe in a multi-threaded program since it is remotely
+ * possible that another thread could call setenv() for TZ and overwrite
+ * the string being parsed. So, don't do that... */
+
+#ifdef __UCLIBC_HAS_TZ_FILE__
+ if (!e)
+ e = read_TZ_file(buf);
+#endif
+ if (!e /* TZ env var not set and no TZfile (or bad TZfile) */
+ || !*e /* or set to empty string. */
+ ) {
+ goto ILLEGAL;
+ }
+
+ if (*e == ':') { /* Ignore leading ':'. */
+ ++e;
+ }
+
+#ifdef __UCLIBC_HAS_TZ_CACHING__
+ if (strcmp(e, oldval) == 0) {
+ /* Same string as last time... nothing to do. */
+ goto FAST_DONE;
+ }
+ /* Make a copy of the TZ env string. It won't be nul-terminated if
+ * it is too long, but it that case it will be illegal and will be reset
+ * to the empty string anyway. */
+ strncpy(oldval, e, TZ_BUFLEN);
+#endif
+
+ count = 0;
+ new_rules[1].tzname[0] = 0;
+LOOP:
+ /* Get std or dst name. */
+ c = 0;
+ if (*e == '<') {
+ ++e;
+ c = '>';
+ }
+
+ s = new_rules[count].tzname;
+ n = 0;
+ while (*e
+ && isascii(*e) /* SUSv3 requires char in portable char set. */
+ && (isalpha(*e)
+ || (c && (isalnum(*e) || (*e == '+') || (*e == '-')))
+ )
+ ) {
+ *s++ = *e++;
+ if (++n > TZNAME_MAX) {
+ goto ILLEGAL;
+ }
+ }
+ *s = 0;
+
+ if ((n < 3) /* Check for minimum length. */
+ || (c && (*e++ != c)) /* Match any quoting '<'. */
+ ) {
+ goto ILLEGAL;
+ }
+
+ /* Get offset */
+ s = (char *) e;
+ if ((*e != '-') && (*e != '+')) {
+ if (count && !__isdigit_char(*e)) {
+ off -= 3600; /* Default to 1 hour ahead of std. */
+ goto SKIP_OFFSET;
+ }
+ --e;
+ }
+
+ ++e;
+ e = getoffset(e, &off);
+ if (!e) {
+ goto ILLEGAL;
+ }
+
+ if (*s == '-') {
+ off = -off; /* Save off in case needed for dst default. */
+ }
+SKIP_OFFSET:
+ new_rules[count].gmt_offset = off;
+
+ if (!count) {
+ new_rules[1].gmt_offset = off; /* Shouldn't be needed... */
+ if (*e) {
+ ++count;
+ goto LOOP;
+ }
+ } else { /* OK, we have dst, so get some rules. */
+ count = 0;
+ if (!*e) { /* No rules so default to US rules. */
+ e = use_old_rules ? DEFAULT_RULES : DEFAULT_2007_RULES;
+#ifdef DEBUG_TZSET
+ if (e == DEFAULT_RULES)
+ printf("tzset: Using old rules.\n");
+ else if (e == DEFAULT_2007_RULES)
+ printf("tzset: Using new rules\n");
+ else
+ printf("tzset: Using undefined rules\n");
+#endif
+ }
+
+ do {
+ if (*e++ != ',') {
+ goto ILLEGAL;
+ }
+
+ n = 365;
+ s = (char *) RULE;
+ c = *e++;
+ if (c == 'M') {
+ n = 12;
+ } else if (c == 'J') {
+ s += 8;
+ } else {
+ --e;
+ c = 0;
+ s += 6;
+ }
+
+ p = &new_rules[count].rule_type;
+ *p = c;
+ if (c != 'M') {
+ p -= 2;
+ }
+
+ do {
+ ++s;
+ e = getnumber(e, &f);
+ if (!e
+ || ((unsigned int)(f - s[1]) > n)
+ || (*s && (*e++ != *s))
+ ) {
+ goto ILLEGAL;
+ }
+ *--p = f;
+ s += 2;
+ n = *s;
+ } while (n > 0);
+
+ off = 2 * 60 * 60; /* Default to 2:00:00 */
+ if (*e == '/') {
+ ++e;
+ e = getoffset(e, &off);
+ if (!e) {
+ goto ILLEGAL;
+ }
+ }
+ new_rules[count].dst_offset = off;
+ } while (++count < 2);
+
+ if (*e) {
+ILLEGAL:
+#ifdef __UCLIBC_HAS_TZ_CACHING__
+ oldval[0] = 0; /* oldval = "" */
+#endif
+ memset(_time_tzinfo, 0, sizeof(_time_tzinfo));
+ strcpy(_time_tzinfo[0].tzname, UTC);
+ goto DONE;
+ }
+ }
+
+ memcpy(_time_tzinfo, new_rules, sizeof(new_rules));
+DONE:
+ tzname[0] = _time_tzinfo[0].tzname;
+ tzname[1] = _time_tzinfo[1].tzname;
+ daylight = !!_time_tzinfo[1].tzname[0];
+ timezone = _time_tzinfo[0].gmt_offset;
+
+#if defined(__UCLIBC_HAS_TZ_FILE__) || defined(__UCLIBC_HAS_TZ_CACHING__)
+FAST_DONE:
+#endif
+ __UCLIBC_MUTEX_UNLOCK(_time_tzlock);
+}
+libc_hidden_def(tzset)
+#endif
+/**********************************************************************/
+/* #ifdef L_utime */
+
+/* utime is a syscall in both linux and elks. */
+/* int utime(const char *path, const struct utimbuf *times) */
+
+/* #endif */
+/**********************************************************************/
+/* Non-SUSv3 */
+/**********************************************************************/
+#ifdef L_utimes
+
+#ifndef __BCC__
+#error The uClibc version of utimes is in sysdeps/linux/common.
+#endif
+
+#include <utime.h>
+
+int utimes(const char *filename, register const struct timeval *tvp)
+{
+ register struct utimbuf *p = NULL;
+ struct utimbuf utb;
+
+ if (tvp) {
+ p = &utb;
+ p->actime = tvp[0].tv_sec;
+ p->modtime = tvp[1].tv_sec;
+ }
+ return utime(filename, p);
+}
+
+#endif
+/**********************************************************************/
+#ifdef L__time_t2tm
+
+static const uint16_t _vals[] = {
+ 60, 60, 24, 7 /* special */, 36524, 1461, 365, 0
+};
+
+static const unsigned char days[] = {
+ 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31, /* non-leap */
+ 29,
+};
+
+#ifdef __UCLIBC_HAS_TM_EXTENSIONS__
+static const char utc_string[] = "UTC";
+#endif
+
+/* Notes:
+ * If time_t is 32 bits, then no overflow is possible.
+ * It time_t is > 32 bits, this needs to be adjusted to deal with overflow.
+ */
+
+/* Note: offset is the correction in _days_ to *timer! */
+
+struct tm attribute_hidden *_time_t2tm(const time_t *__restrict timer,
+ int offset, struct tm *__restrict result)
+{
+ register int *p;
+ time_t t1, t, v;
+ int wday = wday; /* ok to be uninitialized, shutting up warning */
+
+ {
+ register const uint16_t *vp;
+ t = *timer;
+ p = (int *) result;
+ p[7] = 0;
+ vp = _vals;
+ do {
+ if ((v = *vp) == 7) {
+ /* Overflow checking, assuming time_t is long int... */
+#if (LONG_MAX > INT_MAX) && (LONG_MAX > 2147483647L)
+#if (INT_MAX == 2147483647L) && (LONG_MAX == 9223372036854775807L)
+ /* Valid range for t is [-784223472856L, 784223421720L].
+ * Outside of this range, the tm_year field will overflow. */
+ if (((unsigned long)(t + offset- -784223472856L))
+ > (784223421720L - -784223472856L)
+ ) {
+ return NULL;
+ }
+#else
+#error overflow conditions unknown
+#endif
+#endif
+
+ /* We have days since the epoch, so caluclate the weekday. */
+#if defined(__BCC__) && TIME_T_IS_UNSIGNED
+ wday = (t + 4) % (*vp); /* t is unsigned */
+#else
+ wday = ((int)((t % (*vp)) + 11)) % ((int)(*vp)); /* help bcc */
+#endif
+ /* Set divisor to days in 400 years. Be kind to bcc... */
+ v = ((time_t)(vp[1])) << 2;
+ ++v;
+ /* Change to days since 1/1/1601 so that for 32 bit time_t
+ * values, we'll have t >= 0. This should be changed for
+ * archs with larger time_t types.
+ * Also, correct for offset since a multiple of 7. */
+
+ /* TODO: Does this still work on archs with time_t > 32 bits? */
+ t += (135140L - 366) + offset; /* 146097 - (365*30 + 7) -366 */
+ }
+#if defined(__BCC__) && TIME_T_IS_UNSIGNED
+ t -= ((t1 = t / v) * v);
+#else
+ if ((t -= ((t1 = t / v) * v)) < 0) {
+ t += v;
+ --t1;
+ }
+#endif
+
+ if ((*vp == 7) && (t == v-1)) {
+ --t; /* Correct for 400th year leap case */
+ ++p[4]; /* Stash the extra day... */
+ }
+
+#if defined(__BCC__) && 0
+ *p = t1;
+ if (v <= 60) {
+ *p = t;
+ t = t1;
+ }
+ ++p;
+#else
+ if (v <= 60) {
+ *p++ = t;
+ t = t1;
+ } else {
+ *p++ = t1;
+ }
+#endif
+ } while (*++vp);
+ }
+
+ if (p[-1] == 4) {
+ --p[-1];
+ t = 365;
+ }
+
+ *p += ((int) t); /* result[7] .. tm_yday */
+
+ p -= 2; /* at result[5] */
+
+#if (LONG_MAX > INT_MAX) && (LONG_MAX > 2147483647L)
+ /* Protect against overflow. TODO: Unecessary if int arith wraps? */
+ *p = ((((p[-2]<<2) + p[-1])*25 + p[0])<< 2) + (p[1] - 299); /* tm_year */
+#else
+ *p = ((((p[-2]<<2) + p[-1])*25 + p[0])<< 2) + p[1] - 299; /* tm_year */
+#endif
+
+ p[1] = wday; /* result[6] .. tm_wday */
+
+ {
+ register const unsigned char *d = days;
+
+ wday = 1900 + *p;
+ if (__isleap(wday)) {
+ d += 11;
+ }
+
+ wday = p[2] + 1; /* result[7] .. tm_yday */
+ *--p = 0; /* at result[4] .. tm_mon */
+ while (wday > *d) {
+ wday -= *d;
+ if (*d == 29) {
+ d -= 11; /* Backup to non-leap Feb. */
+ }
+ ++d;
+ ++*p; /* Increment tm_mon. */
+ }
+ p[-1] = wday; /* result[3] .. tm_mday */
+ }
+ /* TODO -- should this be 0? */
+ p[4] = 0; /* result[8] .. tm_isdst */
+#ifdef __UCLIBC_HAS_TM_EXTENSIONS__
+# ifdef __USE_BSD
+ result->tm_gmtoff = 0;
+ result->tm_zone = utc_string;
+# else
+ result->__tm_gmtoff = 0;
+ result->__tm_zone = utc_string;
+# endif
+#endif /* __UCLIBC_HAS_TM_EXTENSIONS__ */
+
+ return result;
+}
+
+#endif
+/**********************************************************************/
+#ifdef L___time_tm
+
+struct tm __time_tm; /* Global shared by gmtime() and localtime(). */
+
+#endif
+/**********************************************************************/
+#ifdef L__time_mktime
+
+time_t attribute_hidden _time_mktime(struct tm *timeptr, int store_on_success)
+{
+ time_t t;
+
+ __UCLIBC_MUTEX_LOCK(_time_tzlock);
+
+ tzset();
+
+ t = _time_mktime_tzi(timeptr, store_on_success, _time_tzinfo);
+
+ __UCLIBC_MUTEX_UNLOCK(_time_tzlock);
+
+ return t;
+}
+
+#endif
+/**********************************************************************/
+#ifdef L__time_mktime_tzi
+
+static const unsigned char __vals[] = {
+ 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31, /* non-leap */
+ 29,
+};
+
+time_t attribute_hidden _time_mktime_tzi(struct tm *timeptr, int store_on_success,
+ rule_struct *tzi)
+{
+#ifdef __BCC__
+ long days, secs;
+#else
+ long long secs;
+#endif
+ time_t t;
+ struct tm x;
+ /* 0:sec 1:min 2:hour 3:mday 4:mon 5:year 6:wday 7:yday 8:isdst */
+ register int *p = (int *) &x;
+ register const unsigned char *s;
+ int d, default_dst;
+
+ memcpy(p, timeptr, sizeof(struct tm));
+
+ if (!tzi[1].tzname[0]) { /* No dst in this timezone, */
+ p[8] = 0; /* so set tm_isdst to 0. */
+ }
+
+ default_dst = 0;
+ if (p[8]) { /* Either dst or unknown? */
+ default_dst = 1; /* Assume advancing (even if unknown). */
+ p[8] = ((p[8] > 0) ? 1 : -1); /* Normalize so abs() <= 1. */
+ }
+
+ d = 400;
+ p[5] = (p[5] - ((p[6] = p[5]/d) * d)) + (p[7] = p[4]/12);
+ if ((p[4] -= 12 * p[7]) < 0) {
+ p[4] += 12;
+ --p[5];
+ }
+
+ s = __vals;
+ d = (p[5] += 1900); /* Correct year. Now between 1900 and 2300. */
+ if (__isleap(d)) {
+ s += 11;
+ }
+
+ p[7] = 0;
+ d = p[4];
+ while (d) {
+ p[7] += *s;
+ if (*s == 29) {
+ s -= 11; /* Backup to non-leap Feb. */
+ }
+ ++s;
+ --d;
+ }
+
+ _time_tzset (x.tm_year < 2007); /* tm_year was expanded above */
+
+#ifdef __BCC__
+ d = p[5] - 1;
+ days = -719163L + ((long)d)*365 + ((d/4) - (d/100) + (d/400) + p[3] + p[7]);
+ secs = p[0] + 60*( p[1] + 60*((long)(p[2])) )
+ + tzi[default_dst].gmt_offset;
+DST_CORRECT:
+ if (secs < 0) {
+ secs += 120009600L;
+ days -= 1389;
+ }
+ if ( ((unsigned long)(days + secs/86400L)) > 49710L) {
+ t = ((time_t)(-1));
+ goto DONE;
+ }
+ secs += (days * 86400L);
+#else
+ d = p[5] - 1;
+ d = -719163L + d*365 + (d/4) - (d/100) + (d/400);
+ secs = p[0]
+ + tzi[default_dst].gmt_offset
+ + 60*( p[1]
+ + 60*(p[2]
+ + 24*(((146073L * ((long long)(p[6])) + d)
+ + p[3]) + p[7])));
+
+DST_CORRECT:
+ if (((unsigned long long)(secs - LONG_MIN))
+ > (((unsigned long long)LONG_MAX) - LONG_MIN)
+ ) {
+ t = ((time_t)(-1));
+ goto DONE;
+ }
+#endif
+
+ d = ((struct tm *)p)->tm_isdst;
+ t = secs;
+
+ __time_localtime_tzi(&t, (struct tm *)p, tzi);
+
+ if (t == ((time_t)(-1))) { /* Remember, time_t can be unsigned. */
+ goto DONE;
+ }
+
+ if ((d < 0) && (((struct tm *)p)->tm_isdst != default_dst)) {
+#ifdef __BCC__
+ secs -= (days * 86400L);
+#endif
+ secs += (tzi[1-default_dst].gmt_offset
+ - tzi[default_dst].gmt_offset);
+ goto DST_CORRECT;
+ }
+
+
+ if (store_on_success) {
+ memcpy(timeptr, p, sizeof(struct tm));
+ }
+
+
+DONE:
+ return t;
+}
+
+#endif
+/**********************************************************************/
+#if defined(L_wcsftime) || defined(L_wcsftime_l)
+
+#if defined(__UCLIBC_HAS_XLOCALE__) && !defined(__UCLIBC_DO_XLOCALE)
+
+size_t wcsftime(wchar_t *__restrict s, size_t maxsize,
+ const wchar_t *__restrict format,
+ const struct tm *__restrict timeptr)
+{
+ return wcsftime_l(s, maxsize, format, timeptr, __UCLIBC_CURLOCALE);
+}
+
+#else /* defined(__UCLIBC_HAS_XLOCALE__) && !defined(__UCLIBC_DO_XLOCALE) */
+
+size_t __XL_NPP(wcsftime)(wchar_t *__restrict s, size_t maxsize,
+ const wchar_t *__restrict format,
+ const struct tm *__restrict timeptr __LOCALE_PARAM )
+{
+#warning wcsftime always fails
+ return 0; /* always fail */
+}
+#ifdef L_wcsftime_l
+libc_hidden_def(wcsftime_l)
+#endif
+
+#endif /* defined(__UCLIBC_HAS_XLOCALE__) && !defined(__UCLIBC_DO_XLOCALE) */
+
+#endif
+/**********************************************************************/
+#ifdef L_dysize
+/* Return the number of days in YEAR. */
+
+int dysize(int year)
+{
+ return __isleap(year) ? 366 : 365;
+}
+
+#endif
+/**********************************************************************/
diff --git a/ap/build/uClibc/libc/misc/time/timegm.c b/ap/build/uClibc/libc/misc/time/timegm.c
new file mode 100644
index 0000000..ae2fc7d
--- /dev/null
+++ b/ap/build/uClibc/libc/misc/time/timegm.c
@@ -0,0 +1,8 @@
+/*
+ * Copyright (C) 2000-2006 Erik Andersen <andersen@uclibc.org>
+ *
+ * Licensed under the LGPL v2.1, see the file COPYING.LIB in this tarball.
+ */
+
+#define L_timegm
+#include "time.c"
diff --git a/ap/build/uClibc/libc/misc/time/tzset.c b/ap/build/uClibc/libc/misc/time/tzset.c
new file mode 100644
index 0000000..e5607a5
--- /dev/null
+++ b/ap/build/uClibc/libc/misc/time/tzset.c
@@ -0,0 +1,8 @@
+/*
+ * Copyright (C) 2000-2006 Erik Andersen <andersen@uclibc.org>
+ *
+ * Licensed under the LGPL v2.1, see the file COPYING.LIB in this tarball.
+ */
+
+#define L_tzset
+#include "time.c"
diff --git a/ap/build/uClibc/libc/misc/time/wcsftime.c b/ap/build/uClibc/libc/misc/time/wcsftime.c
new file mode 100644
index 0000000..e4b25c0
--- /dev/null
+++ b/ap/build/uClibc/libc/misc/time/wcsftime.c
@@ -0,0 +1,8 @@
+/*
+ * Copyright (C) 2000-2006 Erik Andersen <andersen@uclibc.org>
+ *
+ * Licensed under the LGPL v2.1, see the file COPYING.LIB in this tarball.
+ */
+
+#define L_wcsftime
+#include "time.c"
diff --git a/ap/build/uClibc/libc/misc/time/wcsftime_l.c b/ap/build/uClibc/libc/misc/time/wcsftime_l.c
new file mode 100644
index 0000000..68c2954
--- /dev/null
+++ b/ap/build/uClibc/libc/misc/time/wcsftime_l.c
@@ -0,0 +1,9 @@
+/*
+ * Copyright (C) 2000-2006 Erik Andersen <andersen@uclibc.org>
+ *
+ * Licensed under the LGPL v2.1, see the file COPYING.LIB in this tarball.
+ */
+
+#define L_wcsftime_l
+#define __UCLIBC_DO_XLOCALE
+#include "time.c"
diff --git a/ap/build/uClibc/libc/misc/ttyent/Makefile b/ap/build/uClibc/libc/misc/ttyent/Makefile
new file mode 100644
index 0000000..4a8f4a0
--- /dev/null
+++ b/ap/build/uClibc/libc/misc/ttyent/Makefile
@@ -0,0 +1,13 @@
+# Makefile for uClibc
+#
+# Copyright (C) 2000-2005 Erik Andersen <andersen@uclibc.org>
+#
+# Licensed under the LGPL v2.1, see the file COPYING.LIB in this tarball.
+#
+
+top_srcdir=../../../
+top_builddir=../../../
+all: objs
+include $(top_builddir)Rules.mak
+include Makefile.in
+include $(top_srcdir)Makerules
diff --git a/ap/build/uClibc/libc/misc/ttyent/Makefile.in b/ap/build/uClibc/libc/misc/ttyent/Makefile.in
new file mode 100644
index 0000000..bfa80be
--- /dev/null
+++ b/ap/build/uClibc/libc/misc/ttyent/Makefile.in
@@ -0,0 +1,23 @@
+# Makefile for uClibc
+#
+# Copyright (C) 2000-2008 Erik Andersen <andersen@uclibc.org>
+#
+# Licensed under the LGPL v2.1, see the file COPYING.LIB in this tarball.
+#
+
+subdirs += libc/misc/ttyent
+
+CSRC := getttyent.c
+
+MISC_TTYENT_DIR := $(top_srcdir)libc/misc/ttyent
+MISC_TTYENT_OUT := $(top_builddir)libc/misc/ttyent
+
+MISC_TTYENT_SRC := $(patsubst %.c,$(MISC_TTYENT_DIR)/%.c,$(CSRC))
+MISC_TTYENT_OBJ := $(patsubst %.c,$(MISC_TTYENT_OUT)/%.o,$(CSRC))
+
+libc-y += $(MISC_TTYENT_OBJ)
+
+objclean-y += CLEAN_libc/misc/ttyent
+
+CLEAN_libc/misc/ttyent:
+ $(do_rm) $(addprefix $(MISC_TTYENT_OUT)/*., o os)
diff --git a/ap/build/uClibc/libc/misc/ttyent/getttyent.c b/ap/build/uClibc/libc/misc/ttyent/getttyent.c
new file mode 100644
index 0000000..474f7f0
--- /dev/null
+++ b/ap/build/uClibc/libc/misc/ttyent/getttyent.c
@@ -0,0 +1,208 @@
+/*
+ * Copyright (c) 1989, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. 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.
+ * 4. Neither the name of the University 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 REGENTS 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 REGENTS 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 <features.h>
+#include <ttyent.h>
+#include <stdio.h>
+#include <stdio_ext.h>
+#include <ctype.h>
+#include <string.h>
+#include <stdlib.h>
+#ifdef __UCLIBC_HAS_THREADS__
+# include <pthread.h>
+#endif
+
+static char zapchar;
+static FILE *tf;
+static struct ttyent tty;
+
+
+/* Skip over the current field, removing quotes, and return
+ * a pointer to the next field.
+ */
+#define QUOTED 1
+static char * skip(register char *p)
+{
+ register char *t;
+ register int c, q;
+
+ for (q = 0, t = p; (c = *p) != '\0'; p++) {
+ if (c == '"') {
+ q ^= QUOTED; /* obscure, but nice */
+ continue;
+ }
+ if (q == QUOTED && *p == '\\' && *(p+1) == '"')
+ p++;
+ *t++ = *p;
+ if (q == QUOTED)
+ continue;
+ if (c == '#') {
+ zapchar = c;
+ *p = 0;
+ break;
+ }
+ if (c == '\t' || c == ' ' || c == '\n') {
+ zapchar = c;
+ *p++ = 0;
+ while ((c = *p) == '\t' || c == ' ' || c == '\n')
+ p++;
+ break;
+ }
+ }
+ *--t = '\0';
+ return (p);
+}
+
+static char * value(register char *p)
+{
+
+ return ((p = strchr(p, '=')) ? ++p : NULL);
+}
+
+int setttyent(void)
+{
+
+ if (tf) {
+ rewind(tf);
+ return (1);
+ } else if ((tf = fopen(_PATH_TTYS, "r"))) {
+ /* We do the locking ourselves. */
+#ifdef __UCLIBC_HAS_THREADS__
+ __fsetlocking (tf, FSETLOCKING_BYCALLER);
+#endif
+ return (1);
+ }
+ return (0);
+}
+libc_hidden_def(setttyent)
+
+struct ttyent * getttyent(void)
+{
+ register int c;
+ register char *p;
+ static char *line = NULL;
+ struct ttyent *retval = NULL;
+
+ if (!tf && !setttyent())
+ return (NULL);
+
+ if (!line) {
+ line = malloc(BUFSIZ);
+ if (!line)
+ abort();
+ }
+
+ __STDIO_ALWAYS_THREADLOCK(tf);
+
+ for (;;) {
+ if (!fgets_unlocked(p = line, BUFSIZ, tf)) {
+ goto DONE;
+ }
+ /* skip lines that are too big */
+ if (!strchr(p, '\n')) {
+ while ((c = getc_unlocked(tf)) != '\n' && c != EOF)
+ ;
+ continue;
+ }
+ while (isspace(*p))
+ ++p;
+ if (*p && *p != '#')
+ break;
+ }
+
+ zapchar = 0;
+ tty.ty_name = p;
+ p = skip(p);
+ if (!*(tty.ty_getty = p))
+ tty.ty_getty = tty.ty_type = NULL;
+ else {
+ p = skip(p);
+ if (!*(tty.ty_type = p))
+ tty.ty_type = NULL;
+ else
+ p = skip(p);
+ }
+ tty.ty_status = 0;
+ tty.ty_window = NULL;
+
+#define scmp(e) !strncmp(p, e, sizeof(e) - 1) && isspace(p[sizeof(e) - 1])
+#define vcmp(e) !strncmp(p, e, sizeof(e) - 1) && p[sizeof(e) - 1] == '='
+ for (; *p; p = skip(p)) {
+ if (scmp(_TTYS_OFF))
+ tty.ty_status &= ~TTY_ON;
+ else if (scmp(_TTYS_ON))
+ tty.ty_status |= TTY_ON;
+ else if (scmp(_TTYS_SECURE))
+ tty.ty_status |= TTY_SECURE;
+ else if (vcmp(_TTYS_WINDOW))
+ tty.ty_window = value(p);
+ else
+ break;
+ }
+
+ if (zapchar == '#' || *p == '#')
+ while ((c = *++p) == ' ' || c == '\t')
+ ;
+ tty.ty_comment = p;
+ if (*p == 0)
+ tty.ty_comment = 0;
+ if ((p = strchr(p, '\n')))
+ *p = '\0';
+ retval = &tty;
+
+ DONE:
+ __STDIO_ALWAYS_THREADUNLOCK(tf);
+ return retval;
+}
+libc_hidden_def(getttyent)
+
+int endttyent(void)
+{
+ int rval;
+
+ if (tf) {
+ rval = !(fclose(tf) == EOF);
+ tf = NULL;
+ return (rval);
+ }
+ return (1);
+}
+libc_hidden_def(endttyent)
+
+struct ttyent * getttynam(const char *_tty)
+{
+ register struct ttyent *t;
+
+ setttyent();
+ while ((t = getttyent()))
+ if (!strcmp(_tty, t->ty_name))
+ break;
+ endttyent();
+ return (t);
+}
diff --git a/ap/build/uClibc/libc/misc/utmp/Makefile b/ap/build/uClibc/libc/misc/utmp/Makefile
new file mode 100644
index 0000000..4a8f4a0
--- /dev/null
+++ b/ap/build/uClibc/libc/misc/utmp/Makefile
@@ -0,0 +1,13 @@
+# Makefile for uClibc
+#
+# Copyright (C) 2000-2005 Erik Andersen <andersen@uclibc.org>
+#
+# Licensed under the LGPL v2.1, see the file COPYING.LIB in this tarball.
+#
+
+top_srcdir=../../../
+top_builddir=../../../
+all: objs
+include $(top_builddir)Rules.mak
+include Makefile.in
+include $(top_srcdir)Makerules
diff --git a/ap/build/uClibc/libc/misc/utmp/Makefile.in b/ap/build/uClibc/libc/misc/utmp/Makefile.in
new file mode 100644
index 0000000..49ae5a5
--- /dev/null
+++ b/ap/build/uClibc/libc/misc/utmp/Makefile.in
@@ -0,0 +1,27 @@
+# Makefile for uClibc
+#
+# Copyright (C) 2000-2008 Erik Andersen <andersen@uclibc.org>
+#
+# Licensed under the LGPL v2.1, see the file COPYING.LIB in this tarball.
+#
+
+subdirs += libc/misc/utmp
+
+CSRC := utent.c wtent.c
+
+ifeq ($(UCLIBC_HAS_UTMPX),y)
+CSRC += utxent.c
+endif
+
+MISC_UTMP_DIR := $(top_srcdir)libc/misc/utmp
+MISC_UTMP_OUT := $(top_builddir)libc/misc/utmp
+
+MISC_UTMP_SRC := $(patsubst %.c,$(MISC_UTMP_DIR)/%.c,$(CSRC))
+MISC_UTMP_OBJ := $(patsubst %.c,$(MISC_UTMP_OUT)/%.o,$(CSRC))
+
+libc-y += $(MISC_UTMP_OBJ)
+
+objclean-y += CLEAN_libc/misc/utmp
+
+CLEAN_libc/misc/utmp:
+ $(do_rm) $(addprefix $(MISC_UTMP_OUT)/*., o os)
diff --git a/ap/build/uClibc/libc/misc/utmp/utent.c b/ap/build/uClibc/libc/misc/utmp/utent.c
new file mode 100644
index 0000000..f97cad3
--- /dev/null
+++ b/ap/build/uClibc/libc/misc/utmp/utent.c
@@ -0,0 +1,208 @@
+/* utent.c <ndf@linux.mit.edu> */
+/* Let it be known that this is very possibly the worst standard ever. HP-UX
+ does one thing, someone else does another, linux another... If anyone
+ actually has the standard, please send it to me.
+
+ Note that because of the way this stupid stupid standard works, you
+ have to call endutent() to close the file even if you've not called
+ setutent -- getutid and family use the same file descriptor.
+
+ Modified by Erik Andersen for uClibc...
+*/
+
+#include <features.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <fcntl.h>
+#include <paths.h>
+#include <errno.h>
+#include <string.h>
+#include <utmp.h>
+#include <not-cancel.h>
+
+#include <bits/uClibc_mutex.h>
+__UCLIBC_MUTEX_STATIC(utmplock, PTHREAD_MUTEX_INITIALIZER);
+
+
+/* Do not create extra unlocked functions if no locking is needed */
+#if defined __UCLIBC_HAS_THREADS__
+# define static_if_threaded static
+#else
+# define static_if_threaded /* nothing */
+# define __setutent setutent
+# define __getutent getutent
+# define __getutid getutid
+#endif
+
+
+/* Some global crap */
+static int static_fd = -1;
+static struct utmp static_utmp;
+static const char default_file_name[] = _PATH_UTMP;
+static const char *static_ut_name = default_file_name;
+
+
+/* This function must be called with the LOCK held */
+static_if_threaded void __setutent(void)
+{
+ if (static_fd < 0) {
+ static_fd = open_not_cancel_2(static_ut_name, O_RDWR | O_CLOEXEC);
+ if (static_fd < 0) {
+ static_fd = open_not_cancel_2(static_ut_name, O_RDONLY | O_CLOEXEC);
+ if (static_fd < 0) {
+ return; /* static_fd remains < 0 */
+ }
+ }
+#ifndef __ASSUME_O_CLOEXEC
+ /* Make sure the file will be closed on exec() */
+ fcntl_not_cancel(static_fd, F_SETFD, FD_CLOEXEC);
+#endif
+ return;
+ }
+ lseek(static_fd, 0, SEEK_SET);
+}
+#if defined __UCLIBC_HAS_THREADS__
+void setutent(void)
+{
+ __UCLIBC_MUTEX_LOCK(utmplock);
+ __setutent();
+ __UCLIBC_MUTEX_UNLOCK(utmplock);
+}
+#endif
+libc_hidden_def(setutent)
+
+/* This function must be called with the LOCK held */
+static_if_threaded struct utmp *__getutent(void)
+{
+ if (static_fd < 0) {
+ __setutent();
+ if (static_fd < 0) {
+ return NULL;
+ }
+ }
+
+ if (read_not_cancel(static_fd, &static_utmp, sizeof(static_utmp)) == sizeof(static_utmp)) {
+ return &static_utmp;
+ }
+
+ return NULL;
+}
+#if defined __UCLIBC_HAS_THREADS__
+struct utmp *getutent(void)
+{
+ struct utmp *ret;
+
+ __UCLIBC_MUTEX_LOCK(utmplock);
+ ret = __getutent();
+ __UCLIBC_MUTEX_UNLOCK(utmplock);
+ return ret;
+}
+#endif
+libc_hidden_def(getutent)
+
+void endutent(void)
+{
+ __UCLIBC_MUTEX_LOCK(utmplock);
+ if (static_fd >= 0)
+ close_not_cancel_no_status(static_fd);
+ static_fd = -1;
+ __UCLIBC_MUTEX_UNLOCK(utmplock);
+}
+libc_hidden_def(endutent)
+
+/* This function must be called with the LOCK held */
+static_if_threaded struct utmp *__getutid(const struct utmp *utmp_entry)
+{
+ struct utmp *lutmp;
+ unsigned type;
+
+ /* We use the fact that constants we are interested in are: */
+ /* RUN_LVL=1, ... OLD_TIME=4; INIT_PROCESS=5, ... USER_PROCESS=8 */
+ type = utmp_entry->ut_type - 1;
+ type /= 4;
+
+ while ((lutmp = __getutent()) != NULL) {
+ if (type == 0 && lutmp->ut_type == utmp_entry->ut_type) {
+ /* one of RUN_LVL, BOOT_TIME, NEW_TIME, OLD_TIME */
+ return lutmp;
+ }
+ if (type == 1 && strncmp(lutmp->ut_id, utmp_entry->ut_id, sizeof(lutmp->ut_id)) == 0) {
+ /* INIT_PROCESS, LOGIN_PROCESS, USER_PROCESS, DEAD_PROCESS */
+ return lutmp;
+ }
+ }
+
+ return NULL;
+}
+#if defined __UCLIBC_HAS_THREADS__
+struct utmp *getutid(const struct utmp *utmp_entry)
+{
+ struct utmp *ret;
+
+ __UCLIBC_MUTEX_LOCK(utmplock);
+ ret = __getutid(utmp_entry);
+ __UCLIBC_MUTEX_UNLOCK(utmplock);
+ return ret;
+}
+#endif
+libc_hidden_def(getutid)
+
+struct utmp *getutline(const struct utmp *utmp_entry)
+{
+ struct utmp *lutmp;
+
+ __UCLIBC_MUTEX_LOCK(utmplock);
+ while ((lutmp = __getutent()) != NULL) {
+ if (lutmp->ut_type == USER_PROCESS || lutmp->ut_type == LOGIN_PROCESS) {
+ if (strncmp(lutmp->ut_line, utmp_entry->ut_line, sizeof(lutmp->ut_line)) == 0) {
+ break;
+ }
+ }
+ }
+ __UCLIBC_MUTEX_UNLOCK(utmplock);
+ return lutmp;
+}
+libc_hidden_def(getutline)
+
+struct utmp *pututline(const struct utmp *utmp_entry)
+{
+ __UCLIBC_MUTEX_LOCK(utmplock);
+ /* Ignore the return value. That way, if they've already positioned
+ the file pointer where they want it, everything will work out. */
+ lseek(static_fd, (off_t) - sizeof(struct utmp), SEEK_CUR);
+
+ if (__getutid(utmp_entry) != NULL)
+ lseek(static_fd, (off_t) - sizeof(struct utmp), SEEK_CUR);
+ else
+ lseek(static_fd, (off_t) 0, SEEK_END);
+ if (write(static_fd, utmp_entry, sizeof(struct utmp)) != sizeof(struct utmp))
+ utmp_entry = NULL;
+
+ __UCLIBC_MUTEX_UNLOCK(utmplock);
+ return (struct utmp *)utmp_entry;
+}
+libc_hidden_def(pututline)
+
+int utmpname(const char *new_ut_name)
+{
+ __UCLIBC_MUTEX_LOCK(utmplock);
+ if (new_ut_name != NULL) {
+ if (static_ut_name != default_file_name)
+ free((char *)static_ut_name);
+ static_ut_name = strdup(new_ut_name);
+ if (static_ut_name == NULL) {
+ /* We should probably whine about out-of-memory
+ * errors here... Instead just reset to the default */
+ static_ut_name = default_file_name;
+ }
+ }
+
+ if (static_fd >= 0) {
+ close_not_cancel_no_status(static_fd);
+ static_fd = -1;
+ }
+ __UCLIBC_MUTEX_UNLOCK(utmplock);
+ return 0; /* or maybe return -(static_ut_name != new_ut_name)? */
+}
+libc_hidden_def(utmpname)
diff --git a/ap/build/uClibc/libc/misc/utmp/utxent.c b/ap/build/uClibc/libc/misc/utmp/utxent.c
new file mode 100644
index 0000000..a0e80a6
--- /dev/null
+++ b/ap/build/uClibc/libc/misc/utmp/utxent.c
@@ -0,0 +1,107 @@
+/*
+ * utexent.c : Support for accessing user accounting database.
+ * Copyright (C) 2010 STMicroelectronics Ltd.
+ *
+ * Author: Salvatore Cro <salvatore.cro@st.com>
+ *
+ * Licensed under the LGPL v2.1, see the file COPYING.LIB in this tarball.
+ *
+ */
+
+#include <features.h>
+#include <string.h>
+#include <utmpx.h>
+#include <utmp.h>
+
+void setutxent(void)
+{
+ setutent ();
+}
+
+void endutxent(void)
+{
+ endutent ();
+}
+
+struct utmpx *getutxent(void)
+{
+ return (struct utmpx *) getutent ();
+}
+
+struct utmpx *getutxid(const struct utmpx *utmp_entry)
+{
+ return (struct utmpx *) getutid ((const struct utmp *) utmp_entry);
+}
+
+struct utmpx *getutxline(const struct utmpx *utmp_entry)
+{
+ return (struct utmpx *) getutline ((const struct utmp *) utmp_entry);
+}
+
+struct utmpx *pututxline (const struct utmpx *utmp_entry)
+{
+ return (struct utmpx *) pututline ((const struct utmp *) utmp_entry);
+}
+
+int utmpxname (const char *new_ut_name)
+{
+ return utmpname (new_ut_name);
+}
+
+void updwtmpx (const char *wtmpx_file, const struct utmpx *utmpx)
+{
+ updwtmp (wtmpx_file, (const struct utmp *) utmpx);
+}
+
+/* Copy the information in UTMPX to UTMP. */
+void getutmp (const struct utmpx *utmpx, struct utmp *utmp)
+{
+#if _HAVE_UT_TYPE - 0
+ utmp->ut_type = utmpx->ut_type;
+#endif
+#if _HAVE_UT_PID - 0
+ utmp->ut_pid = utmpx->ut_pid;
+#endif
+ memcpy (utmp->ut_line, utmpx->ut_line, sizeof (utmp->ut_line));
+ memcpy (utmp->ut_user, utmpx->ut_user, sizeof (utmp->ut_user));
+#if _HAVE_UT_ID - 0
+ memcpy (utmp->ut_id, utmpx->ut_id, sizeof (utmp->ut_id));
+#endif
+#if _HAVE_UT_HOST - 0
+ memcpy (utmp->ut_host, utmpx->ut_host, sizeof (utmp->ut_host));
+#endif
+#if _HAVE_UT_TV - 0
+ utmp->ut_tv.tv_sec = utmpx->ut_tv.tv_sec;
+ utmp->ut_tv.tv_usec = utmpx->ut_tv.tv_usec;
+#else
+ utmp->ut_time = utmpx->ut_time;
+#endif
+}
+
+/* Copy the information in UTMP to UTMPX. */
+void getutmpx (const struct utmp *utmp, struct utmpx *utmpx)
+{
+ memset (utmpx, 0, sizeof (struct utmpx));
+
+#if _HAVE_UT_TYPE - 0
+ utmpx->ut_type = utmp->ut_type;
+#endif
+#if _HAVE_UT_PID - 0
+ utmpx->ut_pid = utmp->ut_pid;
+#endif
+ memcpy (utmpx->ut_line, utmp->ut_line, sizeof (utmp->ut_line));
+ memcpy (utmpx->ut_user, utmp->ut_user, sizeof (utmp->ut_user));
+#if _HAVE_UT_ID - 0
+ memcpy (utmpx->ut_id, utmp->ut_id, sizeof (utmp->ut_id));
+#endif
+#if _HAVE_UT_HOST - 0
+ memcpy (utmpx->ut_host, utmp->ut_host, sizeof (utmp->ut_host));
+#endif
+#if _HAVE_UT_TV - 0
+ utmpx->ut_tv.tv_sec = utmp->ut_tv.tv_sec;
+ utmpx->ut_tv.tv_usec = utmp->ut_tv.tv_usec;
+#else
+ utmpx->ut_time = utmp->ut_time;
+#endif
+}
+
diff --git a/ap/build/uClibc/libc/misc/utmp/wtent.c b/ap/build/uClibc/libc/misc/utmp/wtent.c
new file mode 100644
index 0000000..c97f89c
--- /dev/null
+++ b/ap/build/uClibc/libc/misc/utmp/wtent.c
@@ -0,0 +1,49 @@
+/*
+ * Copyright (C) 2000-2006 Erik Andersen <andersen@uclibc.org>
+ *
+ * Licensed under the LGPL v2.1, see the file COPYING.LIB in this tarball.
+ */
+
+/* wtmp support rubbish (i.e. complete crap) */
+
+#include <string.h>
+#include <sys/time.h>
+#include <time.h>
+#include <unistd.h>
+#include <utmp.h>
+#include <fcntl.h>
+#include <sys/file.h>
+#include <not-cancel.h>
+
+#if 0
+/* This is enabled in uClibc/libutil/logwtmp.c */
+void logwtmp (const char *line, const char *name, const char *host)
+{
+ struct utmp lutmp;
+ memset(&lutmp, 0, sizeof(lutmp));
+
+ lutmp.ut_type = (name && *name) ? USER_PROCESS : DEAD_PROCESS;
+ lutmp.ut_pid = getpid();
+ strncpy(lutmp.ut_line, line, sizeof(lutmp.ut_line)-1);
+ strncpy(lutmp.ut_name, name, sizeof(lutmp.ut_name)-1);
+ strncpy(lutmp.ut_host, host, sizeof(lutmp.ut_host)-1);
+ gettimeofday(&(lutmp.ut_tv), NULL);
+
+ updwtmp(_PATH_WTMP, &lutmp);
+}
+#endif
+
+void updwtmp(const char *wtmp_file, const struct utmp *lutmp)
+{
+ int fd;
+
+ fd = open_not_cancel(wtmp_file, O_APPEND | O_WRONLY, 0);
+ if (fd >= 0) {
+ if (lockf(fd, F_LOCK, 0) == 0) {
+ write_not_cancel(fd, lutmp, sizeof(struct utmp));
+ lockf(fd, F_ULOCK, 0);
+ close_not_cancel_no_status(fd);
+ }
+ }
+}
+libc_hidden_def(updwtmp)
diff --git a/ap/build/uClibc/libc/misc/wchar/Makefile b/ap/build/uClibc/libc/misc/wchar/Makefile
new file mode 100644
index 0000000..4a8f4a0
--- /dev/null
+++ b/ap/build/uClibc/libc/misc/wchar/Makefile
@@ -0,0 +1,13 @@
+# Makefile for uClibc
+#
+# Copyright (C) 2000-2005 Erik Andersen <andersen@uclibc.org>
+#
+# Licensed under the LGPL v2.1, see the file COPYING.LIB in this tarball.
+#
+
+top_srcdir=../../../
+top_builddir=../../../
+all: objs
+include $(top_builddir)Rules.mak
+include Makefile.in
+include $(top_srcdir)Makerules
diff --git a/ap/build/uClibc/libc/misc/wchar/Makefile.in b/ap/build/uClibc/libc/misc/wchar/Makefile.in
new file mode 100644
index 0000000..be95a18
--- /dev/null
+++ b/ap/build/uClibc/libc/misc/wchar/Makefile.in
@@ -0,0 +1,41 @@
+# Makefile for uClibc
+#
+# Copyright (C) 2000-2008 Erik Andersen <andersen@uclibc.org>
+#
+# Licensed under the LGPL v2.1, see the file COPYING.LIB in this tarball.
+#
+
+# The stdio and time related wide functions are now built in the normal
+# directories.
+#
+# stdio:
+# fwide fgetwc getwchar fgetws fputwc putwchar fputws ungetwc
+# getwc (fgetwc alias) getwc_unlocked (fgetwc_unlocked alias)
+# putwc (fputwc alias) putwc_unlocked (fputwc_unlocked alias)
+# time:
+# wcsftime
+#
+
+subdirs += libc/misc/wchar
+
+# multi source wchar.c
+CSRC := btowc.c wctob.c mbsinit.c mbrlen.c mbrtowc.c wcrtomb.c mbsrtowcs.c \
+ wcsrtombs.c _wchar_utf8sntowcs.c _wchar_wcsntoutf8s.c \
+ mbsnrtowcs.c wcsnrtombs.c wcwidth.c wcswidth.c
+
+ifeq ($(UCLIBC_HAS_LOCALE),y)
+CSRC += iconv.c
+endif
+
+MISC_WCHAR_DIR := $(top_srcdir)libc/misc/wchar
+MISC_WCHAR_OUT := $(top_builddir)libc/misc/wchar
+
+MISC_WCHAR_SRC := $(patsubst %.c,$(MISC_WCHAR_DIR)/%.c,$(CSRC))
+MISC_WCHAR_OBJ := $(patsubst %.c,$(MISC_WCHAR_OUT)/%.o,$(CSRC))
+
+libc-$(UCLIBC_HAS_WCHAR) += $(MISC_WCHAR_OBJ)
+
+objclean-y += CLEAN_libc/misc/wchar
+
+CLEAN_libc/misc/wchar:
+ $(do_rm) $(addprefix $(MISC_WCHAR_OUT)/*., o os)
diff --git a/ap/build/uClibc/libc/misc/wchar/_wchar_utf8sntowcs.c b/ap/build/uClibc/libc/misc/wchar/_wchar_utf8sntowcs.c
new file mode 100644
index 0000000..a01990e
--- /dev/null
+++ b/ap/build/uClibc/libc/misc/wchar/_wchar_utf8sntowcs.c
@@ -0,0 +1,8 @@
+/*
+ * Copyright (C) 2004-2006 Manuel Novoa III <mjn3@uclibc.org>
+ *
+ * Licensed under the LGPL v2.1, see the file COPYING.LIB in this tarball.
+ */
+
+#define L__wchar_utf8sntowcs
+#include "wchar.c"
diff --git a/ap/build/uClibc/libc/misc/wchar/_wchar_wcsntoutf8s.c b/ap/build/uClibc/libc/misc/wchar/_wchar_wcsntoutf8s.c
new file mode 100644
index 0000000..a63aa91
--- /dev/null
+++ b/ap/build/uClibc/libc/misc/wchar/_wchar_wcsntoutf8s.c
@@ -0,0 +1,8 @@
+/*
+ * Copyright (C) 2004-2006 Manuel Novoa III <mjn3@uclibc.org>
+ *
+ * Licensed under the LGPL v2.1, see the file COPYING.LIB in this tarball.
+ */
+
+#define L__wchar_wcsntoutf8s
+#include "wchar.c"
diff --git a/ap/build/uClibc/libc/misc/wchar/btowc.c b/ap/build/uClibc/libc/misc/wchar/btowc.c
new file mode 100644
index 0000000..d5e60ce
--- /dev/null
+++ b/ap/build/uClibc/libc/misc/wchar/btowc.c
@@ -0,0 +1,8 @@
+/*
+ * Copyright (C) 2004-2006 Manuel Novoa III <mjn3@uclibc.org>
+ *
+ * Licensed under the LGPL v2.1, see the file COPYING.LIB in this tarball.
+ */
+
+#define L_btowc
+#include "wchar.c"
diff --git a/ap/build/uClibc/libc/misc/wchar/iconv.c b/ap/build/uClibc/libc/misc/wchar/iconv.c
new file mode 100644
index 0000000..e6e8ea8
--- /dev/null
+++ b/ap/build/uClibc/libc/misc/wchar/iconv.c
@@ -0,0 +1,8 @@
+/*
+ * Copyright (C) 2004-2006 Manuel Novoa III <mjn3@uclibc.org>
+ *
+ * Licensed under the LGPL v2.1, see the file COPYING.LIB in this tarball.
+ */
+
+#define L_iconv
+#include "wchar.c"
diff --git a/ap/build/uClibc/libc/misc/wchar/mbrlen.c b/ap/build/uClibc/libc/misc/wchar/mbrlen.c
new file mode 100644
index 0000000..01bd31e
--- /dev/null
+++ b/ap/build/uClibc/libc/misc/wchar/mbrlen.c
@@ -0,0 +1,8 @@
+/*
+ * Copyright (C) 2004-2006 Manuel Novoa III <mjn3@uclibc.org>
+ *
+ * Licensed under the LGPL v2.1, see the file COPYING.LIB in this tarball.
+ */
+
+#define L_mbrlen
+#include "wchar.c"
diff --git a/ap/build/uClibc/libc/misc/wchar/mbrtowc.c b/ap/build/uClibc/libc/misc/wchar/mbrtowc.c
new file mode 100644
index 0000000..76ce28a
--- /dev/null
+++ b/ap/build/uClibc/libc/misc/wchar/mbrtowc.c
@@ -0,0 +1,8 @@
+/*
+ * Copyright (C) 2004-2006 Manuel Novoa III <mjn3@uclibc.org>
+ *
+ * Licensed under the LGPL v2.1, see the file COPYING.LIB in this tarball.
+ */
+
+#define L_mbrtowc
+#include "wchar.c"
diff --git a/ap/build/uClibc/libc/misc/wchar/mbsinit.c b/ap/build/uClibc/libc/misc/wchar/mbsinit.c
new file mode 100644
index 0000000..23aaac5
--- /dev/null
+++ b/ap/build/uClibc/libc/misc/wchar/mbsinit.c
@@ -0,0 +1,8 @@
+/*
+ * Copyright (C) 2004-2006 Manuel Novoa III <mjn3@uclibc.org>
+ *
+ * Licensed under the LGPL v2.1, see the file COPYING.LIB in this tarball.
+ */
+
+#define L_mbsinit
+#include "wchar.c"
diff --git a/ap/build/uClibc/libc/misc/wchar/mbsnrtowcs.c b/ap/build/uClibc/libc/misc/wchar/mbsnrtowcs.c
new file mode 100644
index 0000000..9b407c1
--- /dev/null
+++ b/ap/build/uClibc/libc/misc/wchar/mbsnrtowcs.c
@@ -0,0 +1,8 @@
+/*
+ * Copyright (C) 2004-2006 Manuel Novoa III <mjn3@uclibc.org>
+ *
+ * Licensed under the LGPL v2.1, see the file COPYING.LIB in this tarball.
+ */
+
+#define L_mbsnrtowcs
+#include "wchar.c"
diff --git a/ap/build/uClibc/libc/misc/wchar/mbsrtowcs.c b/ap/build/uClibc/libc/misc/wchar/mbsrtowcs.c
new file mode 100644
index 0000000..dd47a91
--- /dev/null
+++ b/ap/build/uClibc/libc/misc/wchar/mbsrtowcs.c
@@ -0,0 +1,8 @@
+/*
+ * Copyright (C) 2004-2006 Manuel Novoa III <mjn3@uclibc.org>
+ *
+ * Licensed under the LGPL v2.1, see the file COPYING.LIB in this tarball.
+ */
+
+#define L_mbsrtowcs
+#include "wchar.c"
diff --git a/ap/build/uClibc/libc/misc/wchar/wchar.c b/ap/build/uClibc/libc/misc/wchar/wchar.c
new file mode 100644
index 0000000..412c557
--- /dev/null
+++ b/ap/build/uClibc/libc/misc/wchar/wchar.c
@@ -0,0 +1,1565 @@
+
+/* Copyright (C) 2002, 2003, 2004 Manuel Novoa III
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 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
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the Free
+ * Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+/* ATTENTION! ATTENTION! ATTENTION! ATTENTION! ATTENTION!
+ *
+ * Besides uClibc, I'm using this code in my libc for elks, which is
+ * a 16-bit environment with a fairly limited compiler. It would make
+ * things much easier for me if this file isn't modified unnecessarily.
+ * In particular, please put any new or replacement functions somewhere
+ * else, and modify the makefile to use your version instead.
+ * Thanks. Manuel
+ *
+ * ATTENTION! ATTENTION! ATTENTION! ATTENTION! ATTENTION! */
+
+
+/* May 23, 2002 Initial Notes:
+ *
+ * I'm still tweaking this stuff, but it passes the tests I've thrown
+ * at it, and Erik needs it for the gcc port. The glibc extension
+ * __wcsnrtombs() hasn't been tested, as I didn't find a test for it
+ * in the glibc source. I also need to fix the behavior of
+ * _wchar_utf8sntowcs() if the max number of wchars to convert is 0.
+ *
+ * UTF-8 -> wchar -> UTF-8 conversion tests on Markus Kuhn's UTF-8-demo.txt
+ * file on my platform (x86) show about 5-10% faster conversion speed than
+ * glibc with mbsrtowcs()/wcsrtombs() and almost twice as fast as glibc with
+ * individual mbrtowc()/wcrtomb() calls.
+ *
+ * If 'DECODER' is defined, then _wchar_utf8sntowcs() will be compiled
+ * as a fail-safe UTF-8 decoder appropriate for a terminal, etc. which
+ * needs to deal gracefully with whatever is sent to it. In that mode,
+ * it passes Markus Kuhn's UTF-8-test.txt stress test. I plan to add
+ * an arg to force that behavior, so the interface will be changing.
+ *
+ * I need to fix the error checking for 16-bit wide chars. This isn't
+ * an issue for uClibc, but may be for ELKS. I'm currently not sure
+ * if I'll use 16-bit, 32-bit, or configureable wchars in ELKS.
+ *
+ * July 1, 2002
+ *
+ * Fixed _wchar_utf8sntowcs() for the max number of wchars == 0 case.
+ * Fixed nul-char bug in btowc(), and another in __mbsnrtowcs() for 8-bit
+ * locales.
+ * Enabled building of a C/POSIX-locale-only version, so full locale support
+ * no longer needs to be enabled.
+ *
+ * Nov 4, 2002
+ *
+ * Fixed a bug in _wchar_wcsntoutf8s(). Don't store wcs position if dst is NULL.
+ * Also, introduce an awful hack into _wchar_wcsntoutf8s() and wcsrtombs() in
+ * order to support %ls in printf. See comments below for details.
+ * Change behaviour of wc<->mb functions when in the C locale. Now they do
+ * a 1-1 map for the range 0x80-UCHAR_MAX. This is for backwards compatibility
+ * and consistency with the stds requirements that a printf format string by
+ * a valid multibyte string beginning and ending in it's initial shift state.
+ *
+ * Nov 5, 2002
+ *
+ * Forgot to change btowc and wctob when I changed the wc<->mb functions yesterday.
+ *
+ * Nov 7, 2002
+ *
+ * Add wcwidth and wcswidth, based on Markus Kuhn's wcwidth of 2002-05-08.
+ * Added some size/speed optimizations and integrated it into my locale
+ * framework. Minimally tested at the moment, but the stub C-locale
+ * version (which most people would probably be using) should be fine.
+ *
+ * Nov 21, 2002
+ *
+ * Revert the wc<->mb changes from earlier this month involving the C-locale.
+ * Add a couple of ugly hacks to support *wprintf.
+ * Add a mini iconv() and iconv implementation (requires locale support).
+ *
+ * Aug 1, 2003
+ * Bug fix for mbrtowc.
+ *
+ * Aug 18, 2003
+ * Bug fix: _wchar_utf8sntowcs and _wchar_wcsntoutf8s now set errno if EILSEQ.
+ *
+ * Feb 11, 2004
+ * Bug fix: Fix size check for remaining output space in iconv().
+ *
+ * Manuel
+ */
+#ifdef _LIBC
+#include <errno.h>
+#include <stddef.h>
+#include <limits.h>
+#include <stdint.h>
+#include <inttypes.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <assert.h>
+#include <locale.h>
+#include <wchar.h>
+#include <bits/uClibc_uwchar.h>
+
+/**********************************************************************/
+#ifdef __UCLIBC_HAS_LOCALE__
+#ifdef __UCLIBC_MJN3_ONLY__
+#ifdef L_iswspace
+/* generates one warning */
+#warning TODO: Fix Cc2wc* and Cwc2c* defines!
+#endif
+#endif /* __UCLIBC_MJN3_ONLY__ */
+
+#define ENCODING (__UCLIBC_CURLOCALE->encoding)
+
+#define Cc2wc_IDX_SHIFT __LOCALE_DATA_Cc2wc_IDX_SHIFT
+#define Cc2wc_ROW_LEN __LOCALE_DATA_Cc2wc_ROW_LEN
+#define Cwc2c_DOMAIN_MAX __LOCALE_DATA_Cwc2c_DOMAIN_MAX
+#define Cwc2c_TI_SHIFT __LOCALE_DATA_Cwc2c_TI_SHIFT
+#define Cwc2c_TT_SHIFT __LOCALE_DATA_Cwc2c_TT_SHIFT
+#define Cwc2c_TI_LEN __LOCALE_DATA_Cwc2c_TI_LEN
+
+#ifndef __CTYPE_HAS_UTF_8_LOCALES
+#warning __CTYPE_HAS_UTF_8_LOCALES not set!
+#endif
+
+#else /* __UCLIBC_HAS_LOCALE__ */
+
+#ifdef __UCLIBC_MJN3_ONLY__
+#ifdef L_btowc
+/* emit only once */
+#warning fix preprocessor logic testing locale settings
+#endif
+#endif
+
+#define ENCODING (__ctype_encoding_7_bit)
+#ifdef __CTYPE_HAS_8_BIT_LOCALES
+#error __CTYPE_HAS_8_BIT_LOCALES is defined!
+#endif
+#ifdef __CTYPE_HAS_UTF_8_LOCALES
+#error __CTYPE_HAS_UTF_8_LOCALES is defined!
+#endif
+#undef L__wchar_utf8sntowcs
+#undef L__wchar_wcsntoutf8s
+
+#endif /* __UCLIBC_HAS_LOCALE__ */
+/**********************************************************************/
+
+#if WCHAR_MAX > 0xffffUL
+#define UTF_8_MAX_LEN 6
+#else
+#define UTF_8_MAX_LEN 3
+#endif
+
+#define KUHN 1
+
+/* Implementation-specific work functions. */
+
+extern size_t _wchar_utf8sntowcs(wchar_t *__restrict pwc, size_t wn,
+ const char **__restrict src, size_t n,
+ mbstate_t *ps, int allow_continuation) attribute_hidden;
+
+extern size_t _wchar_wcsntoutf8s(char *__restrict s, size_t n,
+ const wchar_t **__restrict src, size_t wn) attribute_hidden;
+#endif
+/**********************************************************************/
+#ifdef L_btowc
+
+
+wint_t btowc(int c)
+{
+#ifdef __CTYPE_HAS_8_BIT_LOCALES
+
+ wchar_t wc;
+ unsigned char buf[1];
+ mbstate_t mbstate;
+
+ if (c != EOF) {
+ *buf = (unsigned char) c;
+ mbstate.__mask = 0; /* Initialize the mbstate. */
+ if (mbrtowc(&wc, (char*) buf, 1, &mbstate) <= 1) {
+ return wc;
+ }
+ }
+ return WEOF;
+
+#else /* !__CTYPE_HAS_8_BIT_LOCALES */
+
+#ifdef __UCLIBC_HAS_LOCALE__
+ assert((ENCODING == __ctype_encoding_7_bit)
+ || (ENCODING == __ctype_encoding_utf8));
+#endif
+
+ /* If we don't have 8-bit locale support, then this is trivial since
+ * anything outside of 0-0x7f is illegal in C/POSIX and UTF-8 locales. */
+ return (((unsigned int)c) < 0x80) ? c : WEOF;
+
+#endif /* !__CTYPE_HAS_8_BIT_LOCALES */
+}
+libc_hidden_def(btowc)
+
+#endif
+/**********************************************************************/
+#ifdef L_wctob
+
+/* Note: We completely ignore ps in all currently supported conversions. */
+
+
+int wctob(wint_t c)
+{
+#ifdef __CTYPE_HAS_8_BIT_LOCALES
+
+ unsigned char buf[MB_LEN_MAX];
+
+ return (wcrtomb((char*) buf, c, NULL) == 1) ? *buf : EOF;
+
+#else /* __CTYPE_HAS_8_BIT_LOCALES */
+
+#ifdef __UCLIBC_HAS_LOCALE__
+ assert((ENCODING == __ctype_encoding_7_bit)
+ || (ENCODING == __ctype_encoding_utf8));
+#endif /* __UCLIBC_HAS_LOCALE__ */
+
+ /* If we don't have 8-bit locale support, then this is trivial since
+ * anything outside of 0-0x7f is illegal in C/POSIX and UTF-8 locales. */
+
+ /* TODO: need unsigned version of wint_t... */
+/* return (((unsigned int)c) < 0x80) ? c : WEOF; */
+ return ((c >= 0) && (c < 0x80)) ? c : EOF;
+
+#endif /* __CTYPE_HAS_8_BIT_LOCALES */
+}
+
+#endif
+/**********************************************************************/
+#ifdef L_mbsinit
+
+int mbsinit(const mbstate_t *ps)
+{
+ return !ps || !ps->__mask;
+}
+libc_hidden_def(mbsinit)
+
+#endif
+/**********************************************************************/
+#ifdef L_mbrlen
+
+
+size_t mbrlen(const char *__restrict s, size_t n, mbstate_t *__restrict ps)
+{
+ static mbstate_t mbstate; /* Rely on bss 0-init. */
+
+ return mbrtowc(NULL, s, n, (ps != NULL) ? ps : &mbstate);
+}
+libc_hidden_def(mbrlen)
+
+#endif
+/**********************************************************************/
+#ifdef L_mbrtowc
+
+
+size_t mbrtowc(wchar_t *__restrict pwc, const char *__restrict s,
+ size_t n, mbstate_t *__restrict ps)
+{
+ static mbstate_t mbstate; /* Rely on bss 0-init. */
+ wchar_t wcbuf[1];
+ const char *p;
+ size_t r;
+ char empty_string[1]; /* Avoid static to be fPIC friendly. */
+
+ if (!ps) {
+ ps = &mbstate;
+ }
+
+ if (!s) {
+ pwc = (wchar_t *) s; /* NULL */
+ empty_string[0] = 0; /* Init the empty string when necessary. */
+ s = empty_string;
+ n = 1;
+ } else if (*s == '\0') {
+ if (pwc)
+ *pwc = '\0';
+ /* According to the ISO C 89 standard this is the expected behaviour. */
+ return 0;
+ } else if (!n) {
+ /* TODO: change error code? */
+#if 0
+ return (ps->__mask && (ps->__wc == 0xffffU))
+ ? ((size_t) -1) : ((size_t) -2);
+#else
+ return 0;
+#endif
+ }
+
+ p = s;
+
+#ifdef __CTYPE_HAS_UTF_8_LOCALES
+ /* Need to do this here since mbsrtowcs doesn't allow incompletes. */
+ if (ENCODING == __ctype_encoding_utf8) {
+ if (!pwc) {
+ pwc = wcbuf;
+ }
+ r = _wchar_utf8sntowcs(pwc, 1, &p, n, ps, 1);
+ return (r == 1) ? (p-s) : r; /* Need to return 0 if nul char. */
+ }
+#endif
+
+#ifdef __UCLIBC_MJN3_ONLY__
+#warning TODO: This adds a trailing nul!
+#endif /* __UCLIBC_MJN3_ONLY__ */
+
+ r = mbsnrtowcs(wcbuf, &p, SIZE_MAX, 1, ps);
+
+ if (((ssize_t) r) >= 0) {
+ if (pwc) {
+ *pwc = *wcbuf;
+ }
+ }
+ return (size_t) r;
+}
+libc_hidden_def(mbrtowc)
+
+#endif
+/**********************************************************************/
+#ifdef L_wcrtomb
+
+
+/* Note: We completely ignore ps in all currently supported conversions. */
+/* TODO: Check for valid state anyway? */
+
+size_t wcrtomb(register char *__restrict s, wchar_t wc,
+ mbstate_t *__restrict ps)
+{
+#ifdef __UCLIBC_MJN3_ONLY__
+#warning TODO: Should wcsnrtombs nul-terminate unconditionally? Check glibc.
+#endif /* __UCLIBC_MJN3_ONLY__ */
+ wchar_t wcbuf[1];
+ const wchar_t *pwc;
+ size_t r;
+ char buf[MB_LEN_MAX];
+
+ if (!s) {
+ s = buf;
+ wc = 0;
+ }
+
+ pwc = wcbuf;
+ wcbuf[0] = wc;
+
+ r = wcsnrtombs(s, &pwc, 1, MB_LEN_MAX, ps);
+ return (r != 0) ? r : 1;
+}
+libc_hidden_def(wcrtomb)
+
+#endif
+/**********************************************************************/
+#ifdef L_mbsrtowcs
+
+
+size_t mbsrtowcs(wchar_t *__restrict dst, const char **__restrict src,
+ size_t len, mbstate_t *__restrict ps)
+{
+ static mbstate_t mbstate; /* Rely on bss 0-init. */
+
+ return mbsnrtowcs(dst, src, SIZE_MAX, len,
+ ((ps != NULL) ? ps : &mbstate));
+}
+libc_hidden_def(mbsrtowcs)
+
+#endif
+/**********************************************************************/
+#ifdef L_wcsrtombs
+
+/* Note: We completely ignore ps in all currently supported conversions.
+
+ * TODO: Check for valid state anyway? */
+
+
+size_t wcsrtombs(char *__restrict dst, const wchar_t **__restrict src,
+ size_t len, mbstate_t *__restrict ps)
+{
+ return wcsnrtombs(dst, src, SIZE_MAX, len, ps);
+}
+libc_hidden_def(wcsrtombs)
+
+#endif
+/**********************************************************************/
+#ifdef L__wchar_utf8sntowcs
+
+/* Define DECODER to generate a UTF-8 decoder which passes Markus Kuhn's
+ * UTF-8-test.txt strss test.
+ */
+/* #define DECODER */
+
+#ifdef DECODER
+#ifndef KUHN
+#define KUHN
+#endif
+#endif
+
+size_t attribute_hidden _wchar_utf8sntowcs(wchar_t *__restrict pwc, size_t wn,
+ const char **__restrict src, size_t n,
+ mbstate_t *ps, int allow_continuation)
+{
+ register const char *s;
+ __uwchar_t mask;
+ __uwchar_t wc;
+ wchar_t wcbuf[1];
+ size_t count;
+ int incr;
+
+ s = *src;
+
+ assert(s != NULL);
+ assert(ps != NULL);
+
+ incr = 1;
+ /* NOTE: The following is an AWFUL HACK! In order to support %s in
+ * wprintf, we need to be able to compute the number of wchars needed
+ * for the mbs conversion, not to exceed the precision specified.
+ * But if dst is NULL, the return value is the length assuming a
+ * sufficiently sized buffer. So, we allow passing of (wchar_t *) ps
+ * as pwc in order to flag that we really want the length, subject
+ * to the restricted buffer size and no partial conversions.
+ * See mbsnrtowcs() as well. */
+ if (!pwc || (pwc == ((wchar_t *)ps))) {
+ if (!pwc) {
+ wn = SIZE_MAX;
+ }
+ pwc = wcbuf;
+ incr = 0;
+ }
+
+ /* This is really here only to support the glibc extension function
+ * __mbsnrtowcs which apparently returns 0 if wn == 0 without any
+ * check on the validity of the mbstate. */
+ if (!(count = wn)) {
+ return 0;
+ }
+
+ if ((mask = (__uwchar_t) ps->__mask) != 0) { /* A continuation... */
+#ifdef DECODER
+ wc = (__uwchar_t) ps->__wc;
+ if (n) {
+ goto CONTINUE;
+ }
+ goto DONE;
+#else
+ if ((wc = (__uwchar_t) ps->__wc) != 0xffffU) {
+ /* TODO: change error code here and below? */
+ if (n) {
+ goto CONTINUE;
+ }
+ goto DONE;
+ }
+ __set_errno(EILSEQ);
+ return (size_t) -1; /* We're in an error state. */
+#endif
+ }
+
+ do {
+ if (!n) {
+ goto DONE;
+ }
+ --n;
+ if ((wc = ((unsigned char) *s++)) >= 0x80) { /* Not ASCII... */
+ mask = 0x40;
+#ifdef __UCLIBC_MJN3_ONLY__
+#warning TODO: Fix range for 16 bit wchar_t case.
+#endif
+ if (( ((unsigned char)(s[-1] - 0xc0)) < (0xfe - 0xc0) ) &&
+ (((unsigned char)s[-1] != 0xc0 ) && ((unsigned char)s[-1] != 0xc1 ))) {
+ goto START;
+ }
+ BAD:
+#ifdef DECODER
+ wc = 0xfffdU;
+ goto COMPLETE;
+#else
+ ps->__mask = mask;
+ ps->__wc = 0xffffU;
+ __set_errno(EILSEQ);
+ return (size_t) -1; /* Illegal start byte! */
+#endif
+
+ CONTINUE:
+ while (n) {
+ --n;
+ if ((*s & 0xc0) != 0x80) {
+ goto BAD;
+ }
+ mask <<= 5;
+ wc <<= 6;
+ wc += (*s & 0x3f); /* keep seperate for bcc (smaller code) */
+ ++s;
+ START:
+ wc &= ~(mask << 1);
+
+ if ((wc & mask) == 0) { /* Character completed. */
+ if ((mask >>= 5) == 0x40) {
+ mask += mask;
+ }
+ /* Check for invalid sequences (longer than necessary)
+ * and invalid chars. */
+ if ( (wc < mask) /* Sequence not minimal length. */
+#ifdef KUHN
+#if UTF_8_MAX_LEN == 3
+#error broken since mask can overflow!!
+ /* For plane 0, these are the only defined values.*/
+ || (wc > 0xfffdU)
+#else
+ /* Note that we don't need to worry about exceeding */
+ /* 31 bits as that is the most that UTF-8 provides. */
+ || ( ((__uwchar_t)(wc - 0xfffeU)) < 2)
+#endif
+ || ( ((__uwchar_t)(wc - 0xd800U)) < (0xe000U - 0xd800U) )
+#endif /* KUHN */
+ ) {
+ goto BAD;
+ }
+ goto COMPLETE;
+ }
+ }
+ /* Character potentially valid but incomplete. */
+ if (!allow_continuation) {
+ if (count != wn) {
+ return 0;
+ }
+ /* NOTE: The following can fail if you allow and then disallow
+ * continuation!!! */
+#if UTF_8_MAX_LEN == 3
+#error broken since mask can overflow!!
+#endif
+ /* Need to back up... */
+ do {
+ --s;
+ } while ((mask >>= 5) >= 0x40);
+ goto DONE;
+ }
+ ps->__mask = (wchar_t) mask;
+ ps->__wc = (wchar_t) wc;
+ *src = s;
+ return (size_t) -2;
+ }
+ COMPLETE:
+ *pwc = wc;
+ pwc += incr;
+ }
+#ifdef DECODER
+ while (--count);
+#else
+ while (wc && --count);
+
+ if (!wc) {
+ s = NULL;
+ }
+#endif
+
+ DONE:
+ /* ps->__wc is irrelavent here. */
+ ps->__mask = 0;
+ if (pwc != wcbuf) {
+ *src = s;
+ }
+
+ return wn - count;
+}
+
+#endif
+/**********************************************************************/
+#ifdef L__wchar_wcsntoutf8s
+
+size_t attribute_hidden _wchar_wcsntoutf8s(char *__restrict s, size_t n,
+ const wchar_t **__restrict src, size_t wn)
+{
+ register char *p;
+ size_t len, t;
+ __uwchar_t wc;
+ const __uwchar_t *swc;
+ int store;
+ char buf[MB_LEN_MAX];
+ char m;
+
+ store = 1;
+ /* NOTE: The following is an AWFUL HACK! In order to support %ls in
+ * printf, we need to be able to compute the number of bytes needed
+ * for the mbs conversion, not to exceed the precision specified.
+ * But if dst is NULL, the return value is the length assuming a
+ * sufficiently sized buffer. So, we allow passing of (char *) src
+ * as dst in order to flag that we really want the length, subject
+ * to the restricted buffer size and no partial conversions.
+ * See wcsnrtombs() as well. */
+ if (!s || (s == ((char *) src))) {
+ if (!s) {
+ n = SIZE_MAX;
+ }
+ s = buf;
+ store = 0;
+ }
+
+ t = n;
+ swc = (const __uwchar_t *) *src;
+
+ assert(swc != NULL);
+
+ while (wn && t) {
+ wc = *swc;
+
+ *s = wc;
+ len = 1;
+
+ if (wc >= 0x80) {
+#ifdef KUHN
+ if (
+#if UTF_8_MAX_LEN == 3
+ /* For plane 0, these are the only defined values.*/
+ /* Note that we don't need to worry about exceeding */
+ /* 31 bits as that is the most that UTF-8 provides. */
+ (wc > 0xfffdU)
+#else
+ /* UTF_8_MAX_LEN == 6 */
+ (wc > 0x7fffffffUL)
+ || ( ((__uwchar_t)(wc - 0xfffeU)) < 2)
+#endif
+ || ( ((__uwchar_t)(wc - 0xd800U)) < (0xe000U - 0xd800U) )
+ ) {
+ __set_errno(EILSEQ);
+ return (size_t) -1;
+ }
+#else /* KUHN */
+#if UTF_8_MAX_LEN != 3
+ if (wc > 0x7fffffffUL) { /* Value too large. */
+ __set_errno(EILSEQ);
+ return (size_t) -1;
+ }
+#endif
+#endif /* KUHN */
+
+ wc >>= 1;
+ p = s;
+ do {
+ ++p;
+ } while (wc >>= 5);
+ wc = *swc;
+ if ((len = p - s) > t) { /* Not enough space. */
+ break;
+ }
+
+ m = 0x80;
+ while( p>s ) {
+ m = (m >> 1) | 0x80;
+ *--p = (wc & 0x3f) | 0x80;
+ wc >>= 6;
+ }
+ *s |= (m << 1);
+ } else if (wc == 0) { /* End of string. */
+ swc = NULL;
+ break;
+ }
+
+ ++swc;
+ --wn;
+ t -= len;
+ if (store) {
+ s += len;
+ }
+ }
+
+ if (store) {
+ *src = (const wchar_t *) swc;
+ }
+
+ return n - t;
+}
+
+
+#endif
+/**********************************************************************/
+#ifdef L_mbsnrtowcs
+
+/* WARNING: We treat len as SIZE_MAX when dst is NULL! */
+
+size_t mbsnrtowcs(wchar_t *__restrict dst, const char **__restrict src,
+ size_t NMC, size_t len, mbstate_t *__restrict ps)
+{
+ static mbstate_t mbstate; /* Rely on bss 0-init. */
+ wchar_t wcbuf[1];
+ const char *s;
+ size_t count;
+ int incr;
+
+ if (!ps) {
+ ps = &mbstate;
+ }
+
+#ifdef __CTYPE_HAS_UTF_8_LOCALES
+ if (ENCODING == __ctype_encoding_utf8) {
+ size_t r;
+ return ((r = _wchar_utf8sntowcs(dst, len, src, NMC, ps, 1))
+ != (size_t) -2) ? r : 0;
+ }
+#endif
+ incr = 1;
+ /* NOTE: The following is an AWFUL HACK! In order to support %s in
+ * wprintf, we need to be able to compute the number of wchars needed
+ * for the mbs conversion, not to exceed the precision specified.
+ * But if dst is NULL, the return value is the length assuming a
+ * sufficiently sized buffer. So, we allow passing of ((wchar_t *)ps)
+ * as dst in order to flag that we really want the length, subject
+ * to the restricted buffer size and no partial conversions.
+ * See _wchar_utf8sntowcs() as well. */
+ if (!dst || (dst == ((wchar_t *)ps))) {
+ if (!dst) {
+ len = SIZE_MAX;
+ }
+ dst = wcbuf;
+ incr = 0;
+ }
+
+ /* Since all the following encodings are single-byte encodings... */
+ if (len > NMC) {
+ len = NMC;
+ }
+
+ count = len;
+ s = *src;
+
+#ifdef __CTYPE_HAS_8_BIT_LOCALES
+ if (ENCODING == __ctype_encoding_8_bit) {
+ wchar_t wc;
+ while (count) {
+ if ((wc = ((unsigned char)(*s))) >= 0x80) { /* Non-ASCII... */
+ wc -= 0x80;
+ wc = __UCLIBC_CURLOCALE->tbl8c2wc[
+ (__UCLIBC_CURLOCALE->idx8c2wc[wc >> Cc2wc_IDX_SHIFT]
+ << Cc2wc_IDX_SHIFT) + (wc & (Cc2wc_ROW_LEN - 1))];
+ if (!wc) {
+ goto BAD;
+ }
+ }
+ if (!(*dst = wc)) {
+ s = NULL;
+ break;
+ }
+ dst += incr;
+ ++s;
+ --count;
+ }
+ if (dst != wcbuf) {
+ *src = s;
+ }
+ return len - count;
+ }
+#endif
+
+#ifdef __UCLIBC_HAS_LOCALE__
+ assert(ENCODING == __ctype_encoding_7_bit);
+#endif
+
+ while (count) {
+ if ((*dst = (unsigned char) *s) == 0) {
+ s = NULL;
+ break;
+ }
+ if (*dst >= 0x80) {
+#ifdef __CTYPE_HAS_8_BIT_LOCALES
+ BAD:
+#endif
+ __set_errno(EILSEQ);
+ return (size_t) -1;
+ }
+ ++s;
+ dst += incr;
+ --count;
+ }
+ if (dst != wcbuf) {
+ *src = s;
+ }
+ return len - count;
+}
+libc_hidden_def(mbsnrtowcs)
+
+#endif
+/**********************************************************************/
+#ifdef L_wcsnrtombs
+
+/* WARNING: We treat len as SIZE_MAX when dst is NULL! */
+
+/* Note: We completely ignore ps in all currently supported conversions.
+ * TODO: Check for valid state anyway? */
+
+size_t wcsnrtombs(char *__restrict dst, const wchar_t **__restrict src,
+ size_t NWC, size_t len, mbstate_t *__restrict ps)
+{
+ const __uwchar_t *s;
+ size_t count;
+ int incr;
+ char buf[MB_LEN_MAX];
+
+#ifdef __CTYPE_HAS_UTF_8_LOCALES
+ if (ENCODING == __ctype_encoding_utf8) {
+ return _wchar_wcsntoutf8s(dst, len, src, NWC);
+ }
+#endif /* __CTYPE_HAS_UTF_8_LOCALES */
+
+ incr = 1;
+ /* NOTE: The following is an AWFUL HACK! In order to support %ls in
+ * printf, we need to be able to compute the number of bytes needed
+ * for the mbs conversion, not to exceed the precision specified.
+ * But if dst is NULL, the return value is the length assuming a
+ * sufficiently sized buffer. So, we allow passing of (char *) src
+ * as dst in order to flag that we really want the length, subject
+ * to the restricted buffer size and no partial conversions.
+ * See _wchar_wcsntoutf8s() as well. */
+ if (!dst || (dst == ((char *) src))) {
+ if (!dst) {
+ len = SIZE_MAX;
+ }
+ dst = buf;
+ incr = 0;
+ }
+
+ /* Since all the following encodings are single-byte encodings... */
+ if (len > NWC) {
+ len = NWC;
+ }
+
+ count = len;
+ s = (const __uwchar_t *) *src;
+
+#ifdef __CTYPE_HAS_8_BIT_LOCALES
+ if (ENCODING == __ctype_encoding_8_bit) {
+ __uwchar_t wc;
+ __uwchar_t u;
+ while (count) {
+ if ((wc = *s) <= 0x7f) {
+ if (!(*dst = (unsigned char) wc)) {
+ s = NULL;
+ break;
+ }
+ } else {
+ u = 0;
+ if (wc <= Cwc2c_DOMAIN_MAX) {
+ u = __UCLIBC_CURLOCALE->idx8wc2c[wc >> (Cwc2c_TI_SHIFT
+ + Cwc2c_TT_SHIFT)];
+ u = __UCLIBC_CURLOCALE->tbl8wc2c[(u << Cwc2c_TI_SHIFT)
+ + ((wc >> Cwc2c_TT_SHIFT)
+ & ((1 << Cwc2c_TI_SHIFT)-1))];
+ u = __UCLIBC_CURLOCALE->tbl8wc2c[Cwc2c_TI_LEN
+ + (u << Cwc2c_TT_SHIFT)
+ + (wc & ((1 << Cwc2c_TT_SHIFT)-1))];
+ }
+
+#ifdef __WCHAR_REPLACEMENT_CHAR
+ *dst = (unsigned char) ( u ? u : __WCHAR_REPLACEMENT_CHAR );
+#else /* __WCHAR_REPLACEMENT_CHAR */
+ if (!u) {
+ goto BAD;
+ }
+ *dst = (unsigned char) u;
+#endif /* __WCHAR_REPLACEMENT_CHAR */
+ }
+ ++s;
+ dst += incr;
+ --count;
+ }
+ if (dst != buf) {
+ *src = (const wchar_t *) s;
+ }
+ return len - count;
+ }
+#endif /* __CTYPE_HAS_8_BIT_LOCALES */
+
+#ifdef __UCLIBC_HAS_LOCALE__
+ assert(ENCODING == __ctype_encoding_7_bit);
+#endif
+
+ while (count) {
+ if (*s >= 0x80) {
+#if defined(__CTYPE_HAS_8_BIT_LOCALES) && !defined(__WCHAR_REPLACEMENT_CHAR)
+ BAD:
+#endif
+ __set_errno(EILSEQ);
+ return (size_t) -1;
+ }
+ if ((*dst = (unsigned char) *s) == 0) {
+ s = NULL;
+ break;
+ }
+ ++s;
+ dst += incr;
+ --count;
+ }
+ if (dst != buf) {
+ *src = (const wchar_t *) s;
+ }
+ return len - count;
+}
+libc_hidden_def(wcsnrtombs)
+
+#endif
+/**********************************************************************/
+#ifdef L_wcswidth
+
+
+#ifdef __UCLIBC_MJN3_ONLY__
+#warning REMINDER: If we start doing translit, wcwidth and wcswidth will need updating.
+#warning TODO: Update wcwidth to match latest by Kuhn.
+#endif
+
+#if defined(__UCLIBC_HAS_LOCALE__) && \
+( defined(__CTYPE_HAS_8_BIT_LOCALES) || defined(__CTYPE_HAS_UTF_8_LOCALES) )
+
+static const unsigned char new_idx[] = {
+ 0, 5, 5, 6, 10, 15, 28, 39,
+ 48, 48, 71, 94, 113, 128, 139, 154,
+ 175, 186, 188, 188, 188, 188, 188, 188,
+ 203, 208, 208, 208, 208, 208, 208, 208,
+ 208, 219, 219, 219, 222, 222, 222, 222,
+ 222, 222, 222, 222, 222, 222, 222, 224,
+ 224, 231, 231, 231, 231, 231, 231, 231,
+ 231, 231, 231, 231, 231, 231, 231, 231,
+ 231, 231, 231, 231, 231, 231, 231, 231,
+ 231, 231, 231, 231, 231, 231, 231, 231,
+ 231, 231, 231, 231, 231, 231, 231, 231,
+ 231, 231, 231, 231, 231, 231, 231, 231,
+ 231, 231, 231, 231, 231, 231, 231, 231,
+ 231, 231, 231, 231, 231, 231, 231, 231,
+ 231, 231, 231, 231, 231, 231, 231, 231,
+ 231, 231, 231, 231, 231, 231, 231, 231,
+ 231, 231, 231, 231, 231, 231, 231, 231,
+ 231, 231, 231, 231, 231, 231, 231, 231,
+ 231, 231, 231, 231, 231, 231, 231, 231,
+ 231, 231, 231, 231, 231, 231, 231, 231,
+ 231, 231, 231, 231, 231, 233, 233, 233,
+ 233, 233, 233, 233, 234, 234, 234, 234,
+ 234, 234, 234, 234, 234, 234, 234, 234,
+ 234, 234, 234, 234, 234, 234, 234, 234,
+ 234, 234, 234, 234, 234, 234, 234, 234,
+ 234, 234, 234, 234, 234, 234, 234, 234,
+ 234, 234, 234, 234, 234, 234, 234, 234,
+ 236, 236, 236, 236, 236, 236, 236, 236,
+ 236, 236, 236, 236, 236, 236, 236, 236,
+ 236, 236, 236, 236, 236, 236, 236, 236,
+ 236, 236, 236, 236, 236, 236, 236, 236,
+ 236, 237, 237, 238, 241, 241, 242, 249,
+ 255,
+};
+
+static const unsigned char new_tbl[] = {
+ 0x00, 0x01, 0x20, 0x7f, 0xa0, 0x00, 0x00, 0x50,
+ 0x60, 0x70, 0x00, 0x83, 0x87, 0x88, 0x8a, 0x00,
+ 0x91, 0xa2, 0xa3, 0xba, 0xbb, 0xbe, 0xbf, 0xc0,
+ 0xc1, 0xc3, 0xc4, 0xc5, 0x00, 0x4b, 0x56, 0x70,
+ 0x71, 0xd6, 0xe5, 0xe7, 0xe9, 0xea, 0xee, 0x00,
+ 0x0f, 0x10, 0x11, 0x12, 0x30, 0x4b, 0xa6, 0xb1,
+ 0x00, 0x01, 0x03, 0x3c, 0x3d, 0x41, 0x49, 0x4d,
+ 0x4e, 0x51, 0x55, 0x62, 0x64, 0x81, 0x82, 0xbc,
+ 0xbd, 0xc1, 0xc5, 0xcd, 0xce, 0xe2, 0xe4, 0x00,
+ 0x02, 0x03, 0x3c, 0x3d, 0x41, 0x43, 0x47, 0x49,
+ 0x4b, 0x4e, 0x70, 0x72, 0x81, 0x83, 0xbc, 0xbd,
+ 0xc1, 0xc6, 0xc7, 0xc9, 0xcd, 0xce, 0x00, 0x01,
+ 0x02, 0x3c, 0x3d, 0x3f, 0x40, 0x41, 0x44, 0x4d,
+ 0x4e, 0x56, 0x57, 0x82, 0x83, 0xc0, 0xc1, 0xcd,
+ 0xce, 0x00, 0x3e, 0x41, 0x46, 0x49, 0x4a, 0x4e,
+ 0x55, 0x57, 0xbf, 0xc0, 0xc6, 0xc7, 0xcc, 0xce,
+ 0x00, 0x41, 0x44, 0x4d, 0x4e, 0xca, 0xcb, 0xd2,
+ 0xd5, 0xd6, 0xd7, 0x00, 0x31, 0x32, 0x34, 0x3b,
+ 0x47, 0x4f, 0xb1, 0xb2, 0xb4, 0xba, 0xbb, 0xbd,
+ 0xc8, 0xce, 0x00, 0x18, 0x1a, 0x35, 0x36, 0x37,
+ 0x38, 0x39, 0x3a, 0x71, 0x7f, 0x80, 0x85, 0x86,
+ 0x88, 0x90, 0x98, 0x99, 0xbd, 0xc6, 0xc7, 0x00,
+ 0x2d, 0x31, 0x32, 0x33, 0x36, 0x38, 0x39, 0x3a,
+ 0x58, 0x5a, 0x00, 0x60, 0x00, 0x12, 0x15, 0x32,
+ 0x35, 0x52, 0x54, 0x72, 0x74, 0xb7, 0xbe, 0xc6,
+ 0xc7, 0xc9, 0xd4, 0x00, 0x0b, 0x0f, 0xa9, 0xaa,
+ 0x00, 0x0b, 0x10, 0x2a, 0x2f, 0x60, 0x64, 0x6a,
+ 0x70, 0xd0, 0xeb, 0x00, 0x29, 0x2b, 0x00, 0x80,
+ 0x00, 0x2a, 0x30, 0x3f, 0x40, 0x99, 0x9b, 0x00,
+ 0xd0, 0x00, 0x00, 0xa4, 0x00, 0x00, 0x00, 0x1e,
+ 0x1f, 0x00, 0x00, 0x10, 0x20, 0x24, 0x30, 0x70,
+ 0xff, 0x00, 0x61, 0xe0, 0xe7, 0xf9, 0xfc,
+};
+
+static const signed char new_wtbl[] = {
+ 0, -1, 1, -1, 1, 1, 0, 1,
+ 0, 1, 1, 0, 1, 0, 1, 1,
+ 0, 1, 0, 1, 0, 1, 0, 1,
+ 0, 1, 0, 1, 1, 0, 1, 0,
+ 1, 0, 1, 0, 1, 0, 1, 1,
+ 0, 1, 0, 1, 0, 1, 0, 1,
+ 1, 0, 1, 0, 1, 0, 1, 0,
+ 1, 0, 1, 0, 1, 0, 1, 0,
+ 1, 0, 1, 0, 1, 0, 1, 1,
+ 0, 1, 0, 1, 0, 1, 0, 1,
+ 0, 1, 0, 1, 0, 1, 0, 1,
+ 0, 1, 0, 1, 0, 1, 1, 0,
+ 1, 0, 1, 0, 1, 0, 1, 0,
+ 1, 0, 1, 0, 1, 0, 1, 0,
+ 1, 1, 0, 1, 0, 1, 0, 1,
+ 0, 1, 0, 1, 0, 1, 0, 1,
+ 1, 0, 1, 0, 1, 0, 1, 0,
+ 1, 0, 1, 1, 0, 1, 0, 1,
+ 0, 1, 0, 1, 0, 1, 0, 1,
+ 0, 1, 1, 0, 1, 0, 1, 0,
+ 1, 0, 1, 0, 1, 0, 1, 0,
+ 1, 0, 1, 0, 1, 0, 1, 1,
+ 0, 1, 0, 1, 0, 1, 0, 1,
+ 0, 1, 2, 0, 1, 0, 1, 0,
+ 1, 0, 1, 0, 1, 0, 1, 0,
+ 1, 0, 1, 1, 0, 1, 0, 1,
+ 1, 0, 1, 0, 1, 0, 1, 0,
+ 1, 0, 1, 1, 2, 1, 1, 2,
+ 2, 0, 2, 1, 2, 0, 2, 2,
+ 1, 1, 2, 1, 1, 2, 1, 0,
+ 1, 1, 0, 1, 0, 1, 2, 1,
+ 0, 2, 1, 2, 1, 0, 1,
+};
+
+
+int wcswidth(const wchar_t *pwcs, size_t n)
+{
+ int h, l, m, count;
+ wchar_t wc;
+ unsigned char b;
+
+ if (ENCODING == __ctype_encoding_7_bit) {
+ size_t i;
+
+ for (i = 0 ; (i < n) && pwcs[i] ; i++) {
+ if (pwcs[i] != (pwcs[i] & 0x7f)) {
+ return -1;
+ }
+ }
+ }
+#ifdef __CTYPE_HAS_8_BIT_LOCALES
+ else if (ENCODING == __ctype_encoding_8_bit) {
+ mbstate_t mbstate;
+
+ mbstate.__mask = 0; /* Initialize the mbstate. */
+ if (wcsnrtombs(NULL, &pwcs, n, SIZE_MAX, &mbstate) == ((size_t) - 1)) {
+ return -1;
+ }
+ }
+#endif /* __CTYPE_HAS_8_BIT_LOCALES */
+#if defined(__CTYPE_HAS_UTF_8_LOCALES) && defined(KUHN)
+ /* For stricter handling of allowed unicode values... see comments above. */
+ else if (ENCODING == __ctype_encoding_utf8) {
+ size_t i;
+
+ for (i = 0 ; (i < n) && pwcs[i] ; i++) {
+ if ( (((__uwchar_t)((pwcs[i]) - 0xfffeU)) < 2)
+ || (((__uwchar_t)((pwcs[i]) - 0xd800U)) < (0xe000U - 0xd800U))
+ ) {
+ return -1;
+ }
+ }
+ }
+#endif /* __CTYPE_HAS_UTF_8_LOCALES */
+
+ for (count = 0 ; n && (wc = *pwcs++) ; n--) {
+ if (wc <= 0xff) {
+ /* If we're here, wc != 0. */
+ if ((wc < 32) || ((wc >= 0x7f) && (wc < 0xa0))) {
+ return -1;
+ }
+ ++count;
+ continue;
+ }
+ if (((unsigned int) wc) <= 0xffff) {
+ b = wc & 0xff;
+ h = (wc >> 8);
+ l = new_idx[h];
+ h = new_idx[h+1];
+ while ((m = (l+h) >> 1) != l) {
+ if (b >= new_tbl[m]) {
+ l = m;
+ } else { /* wc < tbl[m] */
+ h = m;
+ }
+ }
+ count += new_wtbl[l]; /* none should be -1. */
+ continue;
+ }
+
+ /* Redo this to minimize average number of compares?*/
+ if (wc >= 0x1d167) {
+ if (wc <= 0x1d1ad) {
+ if ((wc <= 0x1d169
+ || (wc >= 0x1d173
+ && (wc <= 0x1d182
+ || (wc >= 0x1d185
+ && (wc <= 0x1d18b
+ || (wc >= 0x1d1aa))))))
+ ) {
+ continue;
+ }
+ } else if (((wc >= 0xe0020) && (wc <= 0xe007f)) || (wc == 0xe0001)) {
+ continue;
+ } else if ((wc >= 0x20000) && (wc <= 0x2ffff)) {
+ ++count; /* need 2.. add one here */
+ }
+#if (WCHAR_MAX > 0x7fffffffL)
+ else if (wc > 0x7fffffffL) {
+ return -1;
+ }
+#endif /* (WCHAR_MAX > 0x7fffffffL) */
+ }
+
+ ++count;
+ }
+
+ return count;
+}
+
+#else /* __UCLIBC_HAS_LOCALE__ */
+
+int wcswidth(const wchar_t *pwcs, size_t n)
+{
+ int count;
+ wchar_t wc;
+ size_t i;
+
+ for (i = 0 ; (i < n) && pwcs[i] ; i++) {
+ if (pwcs[i] != (pwcs[i] & 0x7f)) {
+ return -1;
+ }
+ }
+
+ for (count = 0 ; n && (wc = *pwcs++) ; n--) {
+ if (wc <= 0xff) {
+ /* If we're here, wc != 0. */
+ if ((wc < 32) || ((wc >= 0x7f) && (wc < 0xa0))) {
+ return -1;
+ }
+ ++count;
+ continue;
+ } else {
+ return -1;
+ }
+ }
+
+ return count;
+}
+
+#endif /* __UCLIBC_HAS_LOCALE__ */
+
+libc_hidden_def(wcswidth)
+
+#endif
+/**********************************************************************/
+#ifdef L_wcwidth
+
+
+int wcwidth(wchar_t wc)
+{
+ return wcswidth(&wc, 1);
+}
+
+#endif
+/**********************************************************************/
+
+
+typedef struct {
+ mbstate_t tostate;
+ mbstate_t fromstate;
+ int tocodeset;
+ int fromcodeset;
+ int frombom;
+ int tobom;
+ int fromcodeset0;
+ int frombom0;
+ int tobom0;
+ int skip_invalid_input; /* To support iconv -c option. */
+} _UC_iconv_t;
+
+/* For the multibyte
+ * bit 0 means swap endian
+ * bit 1 means 2 byte
+ * bit 2 means 4 byte
+ *
+ */
+
+#if defined L_iconv && defined _LIBC
+/* Used externally only by iconv utility */
+extern const unsigned char __iconv_codesets[];
+libc_hidden_proto(__iconv_codesets)
+#endif
+
+#if defined L_iconv || defined L_iconv_main
+const unsigned char __iconv_codesets[] =
+ "\x0a\xe0""WCHAR_T\x00" /* superset of UCS-4 but platform-endian */
+#if __BYTE_ORDER == __BIG_ENDIAN
+ "\x08\xec""UCS-4\x00" /* always BE */
+ "\x0a\xec""UCS-4BE\x00"
+ "\x0a\xed""UCS-4LE\x00"
+ "\x09\xe4""UTF-32\x00" /* platform endian with BOM */
+ "\x0b\xe4""UTF-32BE\x00"
+ "\x0b\xe5""UTF-32LE\x00"
+ "\x08\xe2""UCS-2\x00" /* always BE */
+ "\x0a\xe2""UCS-2BE\x00"
+ "\x0a\xe3""UCS-2LE\x00"
+ "\x09\xea""UTF-16\x00" /* platform endian with BOM */
+ "\x0b\xea""UTF-16BE\x00"
+ "\x0b\xeb""UTF-16LE\x00"
+#elif __BYTE_ORDER == __LITTLE_ENDIAN
+ "\x08\xed""UCS-4\x00" /* always BE */
+ "\x0a\xed""UCS-4BE\x00"
+ "\x0a\xec""UCS-4LE\x00"
+ "\x09\xf4""UTF-32\x00" /* platform endian with BOM */
+ "\x0b\xe5""UTF-32BE\x00"
+ "\x0b\xe4""UTF-32LE\x00"
+ "\x08\xe3""UCS-2\x00" /* always BE */
+ "\x0a\xe3""UCS-2BE\x00"
+ "\x0a\xe2""UCS-2LE\x00"
+ "\x09\xfa""UTF-16\x00" /* platform endian with BOM */
+ "\x0b\xeb""UTF-16BE\x00"
+ "\x0b\xea""UTF-16LE\x00"
+#endif
+ "\x08\x02""UTF-8\x00"
+ "\x0b\x01""US-ASCII\x00"
+ "\x07\x01""ASCII"; /* Must be last! (special case to save a nul) */
+#endif
+#if defined L_iconv && defined _LIBC
+libc_hidden_data_def(__iconv_codesets)
+#endif
+
+
+#ifdef L_iconv
+
+#include <iconv.h>
+#include <string.h>
+#include <endian.h>
+#include <byteswap.h>
+
+#if (__BYTE_ORDER != __BIG_ENDIAN) && (__BYTE_ORDER != __LITTLE_ENDIAN)
+#error unsupported endianness for iconv
+#endif
+
+#ifndef __CTYPE_HAS_8_BIT_LOCALES
+#error currently iconv requires 8 bit locales
+#endif
+#ifndef __CTYPE_HAS_UTF_8_LOCALES
+#error currently iconv requires UTF-8 locales
+#endif
+
+
+enum {
+ IC_WCHAR_T = 0xe0,
+ IC_MULTIBYTE = 0xe0,
+#if __BYTE_ORDER == __BIG_ENDIAN
+ IC_UCS_4 = 0xec,
+ IC_UTF_32 = 0xe4,
+ IC_UCS_2 = 0xe2,
+ IC_UTF_16 = 0xea,
+#else
+ IC_UCS_4 = 0xed,
+ IC_UTF_32 = 0xe5,
+ IC_UCS_2 = 0xe3,
+ IC_UTF_16 = 0xeb,
+#endif
+ IC_UTF_8 = 2,
+ IC_ASCII = 1
+};
+
+
+static int find_codeset(const char *name)
+{
+ const unsigned char *s;
+ int codeset;
+
+ for (s = __iconv_codesets; *s; s += *s) {
+ if (!strcasecmp((char*) (s + 2), name)) {
+ return s[1];
+ }
+ }
+
+ /* The following is ripped from find_locale in locale.c. */
+
+ /* TODO: maybe CODESET_LIST + *s ??? */
+ /* 7bit is 1, UTF-8 is 2, 8-bit is >= 3 */
+ codeset = 2;
+ s = (const unsigned char *) __LOCALE_DATA_CODESET_LIST;
+ do {
+ ++codeset; /* Increment codeset first. */
+ if (!strcasecmp(__LOCALE_DATA_CODESET_LIST+*s, name)) {
+ return codeset;
+ }
+ } while (*++s);
+
+ return 0; /* No matching codeset! */
+}
+
+iconv_t weak_function iconv_open(const char *tocode, const char *fromcode)
+{
+ register _UC_iconv_t *px;
+ int tocodeset, fromcodeset;
+
+ if (((tocodeset = find_codeset(tocode)) != 0)
+ && ((fromcodeset = find_codeset(fromcode)) != 0)) {
+ if ((px = malloc(sizeof(_UC_iconv_t))) != NULL) {
+ px->tocodeset = tocodeset;
+ px->tobom0 = px->tobom = (tocodeset >= 0xe0) ? (tocodeset & 0x10) >> 4 : 0;
+ px->fromcodeset0 = px->fromcodeset = fromcodeset;
+ px->frombom0 = px->frombom = (fromcodeset >= 0xe0) ? (fromcodeset & 0x10) >> 4 : 0;
+ px->skip_invalid_input = px->tostate.__mask
+ = px->fromstate.__mask = 0;
+ return (iconv_t) px;
+ }
+ } else {
+ __set_errno(EINVAL);
+ }
+ return (iconv_t)(-1);
+}
+
+int weak_function iconv_close(iconv_t cd)
+{
+ free(cd);
+
+ return 0;
+}
+
+size_t weak_function iconv(iconv_t cd, char **__restrict inbuf,
+ size_t *__restrict inbytesleft,
+ char **__restrict outbuf,
+ size_t *__restrict outbytesleft)
+{
+ _UC_iconv_t *px = (_UC_iconv_t *) cd;
+ size_t nrcount, r;
+ wchar_t wc, wc2;
+ int inci, inco;
+
+ assert(px != (_UC_iconv_t *)(-1));
+ assert(sizeof(wchar_t) == 4);
+
+ if (!inbuf || !*inbuf) { /* Need to reinitialze conversion state. */
+ /* Note: For shift-state encodings we possibly need to output the
+ * shift sequence to return to initial state! */
+ if ((px->fromcodeset & 0xf0) == 0xe0) {
+ }
+ px->tostate.__mask = px->fromstate.__mask = 0;
+ px->fromcodeset = px->fromcodeset0;
+ px->tobom = px->tobom0;
+ px->frombom = px->frombom0;
+ return 0;
+ }
+
+ nrcount = 0;
+ while (*inbytesleft) {
+ if (!*outbytesleft) {
+ TOO_BIG:
+ __set_errno(E2BIG);
+ return (size_t) -1;
+ }
+
+ inci = inco = 1;
+ if (px->fromcodeset >= IC_MULTIBYTE) {
+ inci = (px->fromcodeset == IC_WCHAR_T) ? 4: (px->fromcodeset & 6);
+ if (*inbytesleft < inci) goto INVALID;
+ wc = (((unsigned int)((unsigned char)((*inbuf)[0]))) << 8)
+ + ((unsigned char)((*inbuf)[1]));
+ if (inci == 4) {
+ wc = (((unsigned int)((unsigned char)((*inbuf)[2]))) << 8)
+ + ((unsigned char)((*inbuf)[3])) + (wc << 16);
+ if (!(px->fromcodeset & 1)) wc = bswap_32(wc);
+ } else {
+ if (!(px->fromcodeset & 1)) wc = bswap_16(wc);
+ if (((px->fromcodeset & IC_UTF_16) == IC_UTF_16)
+ && (((__uwchar_t)(wc - 0xd800U)) < (0xdc00U - 0xd800U))
+ ) { /* surrogate */
+ wc =- 0xd800U;
+ if (*inbytesleft < 4) goto INVALID;
+ wc2 = (((unsigned int)((unsigned char)((*inbuf)[2]))) << 8)
+ + ((unsigned char)((*inbuf)[3]));
+ if (!(px->fromcodeset & 1)) wc = bswap_16(wc2);
+ if (((__uwchar_t)(wc2 -= 0xdc00U)) < (0xe0000U - 0xdc00U)) {
+ goto ILLEGAL;
+ }
+ inci = 4; /* Change inci here in case skipping illegals. */
+ wc = 0x10000UL + (wc << 10) + wc2;
+ }
+ }
+
+ if (px->frombom) {
+ px->frombom = 0;
+ if ((wc == 0xfeffU)
+ || (wc == ((inci == 4)
+ ? (((wchar_t) 0xfffe0000UL))
+ : ((wchar_t)(0xfffeUL))))
+ ) {
+ if (wc != 0xfeffU) {
+ px->fromcodeset ^= 1; /* toggle endianness */
+ wc = 0xfeffU;
+ }
+ if (!px->frombom) {
+ goto BOM_SKIP_OUTPUT;
+ }
+ goto GOT_BOM;
+ }
+ }
+
+ if (px->fromcodeset != IC_WCHAR_T) {
+ if (((__uwchar_t) wc) > (((px->fromcodeset & IC_UCS_4) == IC_UCS_4)
+ ? 0x7fffffffUL : 0x10ffffUL)
+#ifdef KUHN
+ || (((__uwchar_t)(wc - 0xfffeU)) < 2)
+ || (((__uwchar_t)(wc - 0xd800U)) < (0xe000U - 0xd800U))
+#endif
+ ) {
+ goto ILLEGAL;
+ }
+ }
+ } else if (px->fromcodeset == IC_UTF_8) {
+ const char *p = *inbuf;
+ r = _wchar_utf8sntowcs(&wc, 1, &p, *inbytesleft, &px->fromstate, 0);
+ if (((ssize_t) r) <= 0) { /* either EILSEQ or incomplete or nul */
+ if (((ssize_t) r) < 0) { /* either EILSEQ or incomplete or nul */
+ assert((r == (size_t)(-1)) || (r == (size_t)(-2)));
+ if (r == (size_t)(-2)) {
+ INVALID:
+ __set_errno(EINVAL);
+ } else {
+ px->fromstate.__mask = 0;
+ inci = 1;
+ ILLEGAL:
+ if (px->skip_invalid_input) {
+ px->skip_invalid_input = 2; /* flag for iconv utility */
+ goto BOM_SKIP_OUTPUT;
+ }
+ __set_errno(EILSEQ);
+ }
+ return (size_t)(-1);
+ }
+#ifdef __UCLIBC_MJN3_ONLY__
+#warning TODO: optimize this.
+#endif
+ if (p != NULL) { /* incomplete char case */
+ goto INVALID;
+ }
+ p = *inbuf + 1; /* nul */
+ }
+ inci = p - *inbuf;
+ } else if ((wc = ((unsigned char)(**inbuf))) >= 0x80) { /* Non-ASCII... */
+ if (px->fromcodeset == IC_ASCII) { /* US-ASCII codeset */
+ goto ILLEGAL;
+ } else { /* some other 8-bit ascii-extension codeset */
+ const __codeset_8_bit_t *c8b
+ = __locale_mmap->codeset_8_bit + px->fromcodeset - 3;
+ wc -= 0x80;
+ wc = __UCLIBC_CURLOCALE->tbl8c2wc[
+ (c8b->idx8c2wc[wc >> Cc2wc_IDX_SHIFT]
+ << Cc2wc_IDX_SHIFT) + (wc & (Cc2wc_ROW_LEN - 1))];
+ if (!wc) {
+ goto ILLEGAL;
+ }
+ }
+ }
+
+
+ if (px->tobom) {
+ inci = 0;
+ wc = 0xfeffU;
+ GOT_BOM:
+ px->tobom = 0;
+ }
+
+ if (px->tocodeset >= IC_MULTIBYTE) {
+ inco = (px->tocodeset == IC_WCHAR_T) ? 4: (px->tocodeset & 6);
+ if (*outbytesleft < inco) goto TOO_BIG;
+ if (px->tocodeset != IC_WCHAR_T) {
+ if (((__uwchar_t) wc) > (((px->tocodeset & IC_UCS_4) == IC_UCS_4)
+ ? 0x7fffffffUL : 0x10ffffUL)
+#ifdef KUHN
+ || (((__uwchar_t)(wc - 0xfffeU)) < 2)
+ || (((__uwchar_t)(wc - 0xd800U)) < (0xe000U - 0xd800U))
+#endif
+ ) {
+ REPLACE_32:
+ wc = 0xfffd;
+ ++nrcount;
+ }
+ }
+ if (inco == 4) {
+ if (px->tocodeset & 1) wc = bswap_32(wc);
+ } else {
+ if (((__uwchar_t)wc ) > 0xffffU) {
+ if ((px->tocodeset & IC_UTF_16) != IC_UTF_16) {
+ goto REPLACE_32;
+ }
+ if (*outbytesleft < (inco = 4)) goto TOO_BIG;
+ wc2 = 0xdc00U + (wc & 0x3ff);
+ wc = 0xd800U + ((wc >> 10) & 0x3ff);
+ if (px->tocodeset & 1) {
+ wc = bswap_16(wc);
+ wc2 = bswap_16(wc2);
+ }
+ wc += (wc2 << 16);
+ } else if (px->tocodeset & 1) wc = bswap_16(wc);
+ }
+ (*outbuf)[0] = (char)((unsigned char)(wc));
+ (*outbuf)[1] = (char)((unsigned char)(wc >> 8));
+ if (inco == 4) {
+ (*outbuf)[2] = (char)((unsigned char)(wc >> 16));
+ (*outbuf)[3] = (char)((unsigned char)(wc >> 24));
+ }
+ } else if (px->tocodeset == IC_UTF_8) {
+ const wchar_t *pw = &wc;
+ do {
+ r = _wchar_wcsntoutf8s(*outbuf, *outbytesleft, &pw, 1);
+ if (r != (size_t)(-1)) {
+#ifdef __UCLIBC_MJN3_ONLY__
+#warning TODO: What happens for a nul?
+#endif
+ if (r == 0) {
+ if (wc != 0) {
+ goto TOO_BIG;
+ }
+ ++r;
+ }
+ break;
+ }
+ wc = 0xfffdU;
+ ++nrcount;
+ } while (1);
+ inco = r;
+ } else if (((__uwchar_t)(wc)) < 0x80) {
+ CHAR_GOOD:
+ **outbuf = wc;
+ } else {
+ if ((px->tocodeset != 0x01) && (wc <= Cwc2c_DOMAIN_MAX)) {
+ const __codeset_8_bit_t *c8b
+ = __locale_mmap->codeset_8_bit + px->tocodeset - 3;
+ __uwchar_t u;
+ u = c8b->idx8wc2c[wc >> (Cwc2c_TI_SHIFT + Cwc2c_TT_SHIFT)];
+ u = __UCLIBC_CURLOCALE->tbl8wc2c[(u << Cwc2c_TI_SHIFT)
+ + ((wc >> Cwc2c_TT_SHIFT)
+ & ((1 << Cwc2c_TI_SHIFT)-1))];
+ wc = __UCLIBC_CURLOCALE->tbl8wc2c[Cwc2c_TI_LEN
+ + (u << Cwc2c_TT_SHIFT)
+ + (wc & ((1 << Cwc2c_TT_SHIFT)-1))];
+ if (wc) {
+ goto CHAR_GOOD;
+ }
+ }
+ **outbuf = '?';
+ ++nrcount;
+ }
+
+ *outbuf += inco;
+ *outbytesleft -= inco;
+ BOM_SKIP_OUTPUT:
+ *inbuf += inci;
+ *inbytesleft -= inci;
+ }
+ return nrcount;
+}
+#endif
diff --git a/ap/build/uClibc/libc/misc/wchar/wcrtomb.c b/ap/build/uClibc/libc/misc/wchar/wcrtomb.c
new file mode 100644
index 0000000..91eb306
--- /dev/null
+++ b/ap/build/uClibc/libc/misc/wchar/wcrtomb.c
@@ -0,0 +1,8 @@
+/*
+ * Copyright (C) 2004-2006 Manuel Novoa III <mjn3@uclibc.org>
+ *
+ * Licensed under the LGPL v2.1, see the file COPYING.LIB in this tarball.
+ */
+
+#define L_wcrtomb
+#include "wchar.c"
diff --git a/ap/build/uClibc/libc/misc/wchar/wcsnrtombs.c b/ap/build/uClibc/libc/misc/wchar/wcsnrtombs.c
new file mode 100644
index 0000000..af9d6c3
--- /dev/null
+++ b/ap/build/uClibc/libc/misc/wchar/wcsnrtombs.c
@@ -0,0 +1,8 @@
+/*
+ * Copyright (C) 2004-2006 Manuel Novoa III <mjn3@uclibc.org>
+ *
+ * Licensed under the LGPL v2.1, see the file COPYING.LIB in this tarball.
+ */
+
+#define L_wcsnrtombs
+#include "wchar.c"
diff --git a/ap/build/uClibc/libc/misc/wchar/wcsrtombs.c b/ap/build/uClibc/libc/misc/wchar/wcsrtombs.c
new file mode 100644
index 0000000..e5b6c0b
--- /dev/null
+++ b/ap/build/uClibc/libc/misc/wchar/wcsrtombs.c
@@ -0,0 +1,8 @@
+/*
+ * Copyright (C) 2004-2006 Manuel Novoa III <mjn3@uclibc.org>
+ *
+ * Licensed under the LGPL v2.1, see the file COPYING.LIB in this tarball.
+ */
+
+#define L_wcsrtombs
+#include "wchar.c"
diff --git a/ap/build/uClibc/libc/misc/wchar/wcswidth.c b/ap/build/uClibc/libc/misc/wchar/wcswidth.c
new file mode 100644
index 0000000..3d955a2
--- /dev/null
+++ b/ap/build/uClibc/libc/misc/wchar/wcswidth.c
@@ -0,0 +1,8 @@
+/*
+ * Copyright (C) 2004-2006 Manuel Novoa III <mjn3@uclibc.org>
+ *
+ * Licensed under the LGPL v2.1, see the file COPYING.LIB in this tarball.
+ */
+
+#define L_wcswidth
+#include "wchar.c"
diff --git a/ap/build/uClibc/libc/misc/wchar/wctob.c b/ap/build/uClibc/libc/misc/wchar/wctob.c
new file mode 100644
index 0000000..88d31f5
--- /dev/null
+++ b/ap/build/uClibc/libc/misc/wchar/wctob.c
@@ -0,0 +1,8 @@
+/*
+ * Copyright (C) 2004-2006 Manuel Novoa III <mjn3@uclibc.org>
+ *
+ * Licensed under the LGPL v2.1, see the file COPYING.LIB in this tarball.
+ */
+
+#define L_wctob
+#include "wchar.c"
diff --git a/ap/build/uClibc/libc/misc/wchar/wcwidth.c b/ap/build/uClibc/libc/misc/wchar/wcwidth.c
new file mode 100644
index 0000000..6c4a344
--- /dev/null
+++ b/ap/build/uClibc/libc/misc/wchar/wcwidth.c
@@ -0,0 +1,8 @@
+/*
+ * Copyright (C) 2004-2006 Manuel Novoa III <mjn3@uclibc.org>
+ *
+ * Licensed under the LGPL v2.1, see the file COPYING.LIB in this tarball.
+ */
+
+#define L_wcwidth
+#include "wchar.c"
diff --git a/ap/build/uClibc/libc/misc/wctype/Makefile b/ap/build/uClibc/libc/misc/wctype/Makefile
new file mode 100644
index 0000000..4a8f4a0
--- /dev/null
+++ b/ap/build/uClibc/libc/misc/wctype/Makefile
@@ -0,0 +1,13 @@
+# Makefile for uClibc
+#
+# Copyright (C) 2000-2005 Erik Andersen <andersen@uclibc.org>
+#
+# Licensed under the LGPL v2.1, see the file COPYING.LIB in this tarball.
+#
+
+top_srcdir=../../../
+top_builddir=../../../
+all: objs
+include $(top_builddir)Rules.mak
+include Makefile.in
+include $(top_srcdir)Makerules
diff --git a/ap/build/uClibc/libc/misc/wctype/Makefile.in b/ap/build/uClibc/libc/misc/wctype/Makefile.in
new file mode 100644
index 0000000..4eacc11
--- /dev/null
+++ b/ap/build/uClibc/libc/misc/wctype/Makefile.in
@@ -0,0 +1,36 @@
+# Makefile for uClibc
+#
+# Copyright (C) 2000-2008 Erik Andersen <andersen@uclibc.org>
+#
+# Licensed under the LGPL v2.1, see the file COPYING.LIB in this tarball.
+#
+
+subdirs += libc/misc/wctype
+
+# multi source _wctype.c
+COM_SRC := \
+ iswalnum.c iswalpha.c iswcntrl.c iswdigit.c iswgraph.c \
+ iswlower.c iswprint.c iswpunct.c iswspace.c iswupper.c \
+ iswxdigit.c iswblank.c wctrans.c towctrans.c \
+ wctype.c iswctype.c towlower.c towupper.c
+
+CSRC :=
+ifeq ($(UCLIBC_HAS_WCHAR),y)
+CSRC += $(COM_SRC)
+endif
+ifeq ($(UCLIBC_HAS_XLOCALE),y)
+CSRC += $(patsubst %.c,%_l.c,$(COM_SRC))
+endif
+
+MISC_WCTYPE_DIR := $(top_srcdir)libc/misc/wctype
+MISC_WCTYPE_OUT := $(top_builddir)libc/misc/wctype
+
+MISC_WCTYPE_SRC := $(patsubst %.c,$(MISC_WCTYPE_DIR)/%.c,$(CSRC))
+MISC_WCTYPE_OBJ := $(patsubst %.c,$(MISC_WCTYPE_OUT)/%.o,$(CSRC))
+
+libc-y += $(MISC_WCTYPE_OBJ)
+
+objclean-y += CLEAN_libc/misc/wctype
+
+CLEAN_libc/misc/wctype:
+ $(do_rm) $(addprefix $(MISC_WCTYPE_OUT)/*., o os)
diff --git a/ap/build/uClibc/libc/misc/wctype/_wctype.c b/ap/build/uClibc/libc/misc/wctype/_wctype.c
new file mode 100644
index 0000000..89269f4
--- /dev/null
+++ b/ap/build/uClibc/libc/misc/wctype/_wctype.c
@@ -0,0 +1,860 @@
+/* Copyright (C) 2002, 2003 Manuel Novoa III
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 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
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the Free
+ * Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+/* ATTENTION! ATTENTION! ATTENTION! ATTENTION! ATTENTION!
+ *
+ * Besides uClibc, I'm using this code in my libc for elks, which is
+ * a 16-bit environment with a fairly limited compiler. It would make
+ * things much easier for me if this file isn't modified unnecessarily.
+ * In particular, please put any new or replacement functions somewhere
+ * else, and modify the makefile to use your version instead.
+ * Thanks. Manuel
+ *
+ * ATTENTION! ATTENTION! ATTENTION! ATTENTION! ATTENTION! */
+
+#define __NO_CTYPE
+
+#include <wctype.h>
+#include <assert.h>
+#include <string.h>
+#include <errno.h>
+#include <locale.h>
+#include <ctype.h>
+#include <stdint.h>
+#include <bits/uClibc_uwchar.h>
+
+#if defined(__LOCALE_C_ONLY) && defined(__UCLIBC_DO_XLOCALE)
+# error xlocale functionality is not supported in stub locale mode.
+#endif
+
+#ifdef __UCLIBC_HAS_XLOCALE__
+# include <xlocale.h>
+#endif
+
+/* We know wide char support is enabled. We wouldn't be here otherwise. */
+
+/* Define this if you want to unify the towupper and towlower code in the
+ * towctrans function. */
+/* #define SMALL_UPLOW */
+
+
+/* Pull in __CTYPE_xxx constants */
+#include <bits/uClibc_charclass.h>
+
+
+/* The following is used to implement wctype(), but it is defined
+ * here because the ordering must agree with that of the enumeration
+ * below (ignoring unclassified). */
+#define __CTYPE_TYPESTRING \
+ "\6alnum\0\6alpha\0\6blank\0\6cntrl\0\6digit\0\6graph\0\6lower\0" \
+ "\6print\0\6punct\0\6space\0\6upper\0\7xdigit\0\0"
+
+
+/* The values for wctype_t. */
+enum {
+ _CTYPE_unclassified = 0,
+ _CTYPE_isalnum,
+ _CTYPE_isalpha,
+ _CTYPE_isblank,
+ _CTYPE_iscntrl,
+ _CTYPE_isdigit,
+ _CTYPE_isgraph,
+ _CTYPE_islower,
+ _CTYPE_isprint,
+ _CTYPE_ispunct,
+ _CTYPE_isspace,
+ _CTYPE_isupper,
+ _CTYPE_isxdigit /* _MUST_ be last of the standard classes! */
+};
+
+/* The following is used to implement wctrans(). */
+
+#define __CTYPE_TRANSTRING "\10tolower\0\10toupper\0\10totitle\0\0"
+
+enum {
+ _CTYPE_tolower = 1,
+ _CTYPE_toupper,
+ _CTYPE_totitle
+};
+
+/*--------------------------------------------------------------------*/
+
+#define _CTYPE_iswxdigit (_CTYPE_isxdigit)
+
+/*--------------------------------------------------------------------*/
+
+#ifdef __UCLIBC_MJN3_ONLY__
+# ifdef L_iswspace
+/* generates one warning */
+# warning TODO: Fix WC* defines!
+# endif
+#endif
+
+#define ENCODING (__UCLIBC_CURLOCALE->encoding)
+
+#define WCctype (__UCLIBC_CURLOCALE->tblwctype)
+#define WCuplow (__UCLIBC_CURLOCALE->tblwuplow)
+#define WCcmob (__UCLIBC_CURLOCALE->tblwcomb)
+#define WCuplow_diff (__UCLIBC_CURLOCALE->tblwuplow_diff)
+
+
+#define WC_TABLE_DOMAIN_MAX __LOCALE_DATA_WC_TABLE_DOMAIN_MAX
+
+#define WCctype_II_LEN __LOCALE_DATA_WCctype_II_LEN
+#define WCctype_TI_LEN __LOCALE_DATA_WCctype_TI_LEN
+#define WCctype_UT_LEN __LOCALE_DATA_WCctype_UT_LEN
+#define WCctype_II_SHIFT __LOCALE_DATA_WCctype_II_SHIFT
+#define WCctype_TI_SHIFT __LOCALE_DATA_WCctype_TI_SHIFT
+
+#define WCuplow_II_LEN __LOCALE_DATA_WCuplow_II_LEN
+#define WCuplow_TI_LEN __LOCALE_DATA_WCuplow_TI_LEN
+#define WCuplow_UT_LEN __LOCALE_DATA_WCuplow_UT_LEN
+#define WCuplow_II_SHIFT __LOCALE_DATA_WCuplow_II_SHIFT
+#define WCuplow_TI_SHIFT __LOCALE_DATA_WCuplow_TI_SHIFT
+
+
+#define WCctype_TI_MASK ((1 << (WCctype_TI_SHIFT)) - 1)
+#define WCctype_II_MASK ((1 << (WCctype_II_SHIFT)) - 1)
+
+/**********************************************************************/
+
+#undef __PASTE2
+#undef __PASTE3
+#define __PASTE2(X,Y) X ## Y
+#define __PASTE3(X,Y,Z) X ## Y ## Z
+
+#ifdef __UCLIBC_DO_XLOCALE
+
+#define ISW_FUNC_BODY(NAME) \
+int __PASTE3(isw,NAME,_l) (wint_t wc, __locale_t l) \
+{ \
+ return iswctype_l(wc, __PASTE2(_CTYPE_is,NAME), l); \
+}
+
+#else /* __UCLIBC_DO_XLOCALE */
+
+#define ISW_FUNC_BODY(NAME) \
+int __PASTE2(isw,NAME) (wint_t wc) \
+{ \
+ return iswctype(wc, __PASTE2(_CTYPE_is,NAME)); \
+}
+
+#endif /* __UCLIBC_DO_XLOCALE */
+/**********************************************************************/
+#if defined(L_iswalnum) || defined(L_iswalnum_l)
+
+ISW_FUNC_BODY(alnum);
+# ifdef L_iswalnum
+libc_hidden_def(iswalnum)
+# endif
+
+#endif
+/**********************************************************************/
+#if defined(L_iswalpha) || defined(L_iswalpha_l)
+
+ISW_FUNC_BODY(alpha);
+
+#endif
+/**********************************************************************/
+#if defined(L_iswblank) || defined(L_iswblank_l)
+
+ISW_FUNC_BODY(blank);
+
+#endif
+/**********************************************************************/
+#if defined(L_iswcntrl) || defined(L_iswcntrl_l)
+
+ISW_FUNC_BODY(cntrl);
+
+#endif
+/**********************************************************************/
+#if defined(L_iswdigit) || defined(L_iswdigit_l)
+
+ISW_FUNC_BODY(digit);
+
+#endif
+/**********************************************************************/
+#if defined(L_iswgraph) || defined(L_iswgraph_l)
+
+ISW_FUNC_BODY(graph);
+
+#endif
+/**********************************************************************/
+#if defined(L_iswlower) || defined(L_iswlower_l)
+
+ISW_FUNC_BODY(lower);
+# ifdef L_iswlower
+libc_hidden_def(iswlower)
+# endif
+
+#endif
+/**********************************************************************/
+#if defined(L_iswprint) || defined(L_iswprint_l)
+
+ISW_FUNC_BODY(print);
+
+#endif
+/**********************************************************************/
+#if defined(L_iswpunct) || defined(L_iswpunct_l)
+
+ISW_FUNC_BODY(punct);
+
+#endif
+/**********************************************************************/
+#if defined(L_iswspace) || defined(L_iswspace_l)
+
+ISW_FUNC_BODY(space);
+# ifdef L_iswspace
+libc_hidden_def(iswspace)
+# else
+libc_hidden_def(iswspace_l)
+# endif
+
+#endif
+/**********************************************************************/
+#if defined(L_iswupper) || defined(L_iswupper_l)
+
+ISW_FUNC_BODY(upper);
+# ifdef L_iswupper
+libc_hidden_def(iswupper)
+# endif
+
+#endif
+/**********************************************************************/
+#if defined(L_iswxdigit) || defined(L_iswxdigit_l)
+
+ISW_FUNC_BODY(xdigit);
+
+#endif
+/**********************************************************************/
+#if defined(L_towlower) || defined(L_towlower_l)
+
+# ifdef L_towlower
+# define TOWLOWER(w) towlower(w)
+# else
+# define TOWLOWER(w) towlower_l(w, __locale_t locale)
+# undef __UCLIBC_CURLOCALE
+# define __UCLIBC_CURLOCALE (locale)
+# endif
+
+# ifdef __UCLIBC_HAS_XLOCALE__
+# define TOWCTRANS(w,d) towctrans_l(w,d, __UCLIBC_CURLOCALE)
+# else
+# define TOWCTRANS(w,d) towctrans(w,d)
+# endif
+
+# define __C_towlower(wc) \
+ (((__uwchar_t)(wc) <= 0x7f) ? (__C_ctype_tolower)[(wc)] : (wc))
+
+# ifdef __LOCALE_C_ONLY
+
+wint_t towlower(wint_t wc)
+{
+# ifdef __UCLIBC_HAS_CTYPE_TABLES__
+ return __C_towlower(wc);
+# else
+ return (wc == (unsigned)wc)
+ ? __C_tolower((unsigned)wc)
+ : 0;
+# endif
+}
+
+# else /* __LOCALE_C_ONLY */
+
+# ifdef SMALL_UPLOW
+
+# if defined(L_towlower) && defined(__UCLIBC_HAS_XLOCALE__)
+wint_t towlower(wint_t wc)
+{
+ return towctrans_l(wc, _CTYPE_tolower, __UCLIBC_CURLOCALE);
+}
+# else /* defined(L_towlower) && defined(__UCLIBC_HAS_XLOCALE__) */
+wint_t TOWLOWER(wint_t wc)
+{
+ return TOWCTRANS(wc, _CTYPE_tolower);
+}
+# endif /* defined(L_towlower) && defined(__UCLIBC_HAS_XLOCALE__) */
+
+# else /* SMALL_UPLOW */
+
+# if defined(L_towlower) && defined(__UCLIBC_HAS_XLOCALE__)
+
+wint_t towlower(wint_t wc)
+{
+ return towlower_l(wc, __UCLIBC_CURLOCALE);
+}
+
+# else /* defined(L_towlower) && defined(__UCLIBC_HAS_XLOCALE__) */
+
+wint_t TOWLOWER(wint_t wc)
+{
+ unsigned sc, n, i;
+ __uwchar_t u = wc;
+
+ if (ENCODING == __ctype_encoding_7_bit) {
+ /* We're in the C/POSIX locale, so ignore the tables. */
+ return __C_towlower(wc);
+ }
+
+ if (u <= WC_TABLE_DOMAIN_MAX) {
+ sc = u & ((1 << WCuplow_TI_SHIFT) - 1);
+ u >>= WCuplow_TI_SHIFT;
+ n = u & ((1 << WCuplow_II_SHIFT) - 1);
+ u >>= WCuplow_II_SHIFT;
+
+ i = ((unsigned) WCuplow[u]) << WCuplow_II_SHIFT;
+ i = ((unsigned) WCuplow[WCuplow_II_LEN + i + n]) << WCuplow_TI_SHIFT;
+ i = ((unsigned) WCuplow[WCuplow_II_LEN + WCuplow_TI_LEN + i + sc]) << 1;
+ wc += WCuplow_diff[i + 1];
+ }
+ return wc;
+}
+
+# endif /* defined(L_towlower) && defined(__UCLIBC_HAS_XLOCALE__) */
+
+# endif /* SMALL_UPLOW */
+
+# ifdef L_towlower_l
+libc_hidden_def(towlower_l)
+# endif
+
+# endif /* __LOCALE_C_ONLY */
+
+# ifndef L_towlower_l
+libc_hidden_def(towlower)
+# endif
+
+#endif
+/**********************************************************************/
+#if defined(L_towupper) || defined(L_towupper_l)
+
+# ifdef L_towupper
+# define TOWUPPER(w) towupper(w)
+# else
+# define TOWUPPER(w) towupper_l(w, __locale_t locale)
+# undef __UCLIBC_CURLOCALE
+# define __UCLIBC_CURLOCALE (locale)
+# endif
+
+# ifdef __UCLIBC_HAS_XLOCALE__
+# define TOWCTRANS(w,d) towctrans_l(w,d, __UCLIBC_CURLOCALE)
+# else
+# define TOWCTRANS(w,d) towctrans(w,d)
+# endif
+
+# define __C_towupper(wc) \
+ (((__uwchar_t)(wc) <= 0x7f) ? (__C_ctype_toupper)[(wc)] : (wc))
+
+# ifdef __LOCALE_C_ONLY
+
+wint_t towupper(wint_t wc)
+{
+# ifdef __UCLIBC_HAS_CTYPE_TABLES__
+ return __C_towupper(wc);
+# else
+ return (wc == (unsigned)wc)
+ ? __C_toupper((unsigned)wc)
+ : 0;
+# endif
+}
+
+# else /* __LOCALE_C_ONLY */
+
+# ifdef SMALL_UPLOW
+
+# if defined(L_towupper) && defined(__UCLIBC_HAS_XLOCALE__)
+wint_t towupper(wint_t wc)
+{
+ return towctrans_l(wc, _CTYPE_toupper, __UCLIBC_CURLOCALE);
+}
+# else
+wint_t TOWUPPER(wint_t wc)
+{
+ return TOWCTRANS(wc, _CTYPE_toupper);
+}
+# endif
+
+# else /* SMALL_UPLOW */
+
+# if defined(L_towupper) && defined(__UCLIBC_HAS_XLOCALE__)
+wint_t towupper(wint_t wc)
+{
+ return towupper_l(wc, __UCLIBC_CURLOCALE);
+}
+# else /* defined(L_towupper) && defined(__UCLIBC_HAS_XLOCALE__) */
+wint_t TOWUPPER(wint_t wc)
+{
+ unsigned sc, n, i;
+ __uwchar_t u = wc;
+
+ if (ENCODING == __ctype_encoding_7_bit) {
+ /* We're in the C/POSIX locale, so ignore the tables. */
+ return __C_towupper(wc);
+ }
+
+ if (u <= WC_TABLE_DOMAIN_MAX) {
+ sc = u & ((1 << WCuplow_TI_SHIFT) - 1);
+ u >>= WCuplow_TI_SHIFT;
+ n = u & ((1 << WCuplow_II_SHIFT) - 1);
+ u >>= WCuplow_II_SHIFT;
+
+ i = ((unsigned) WCuplow[u]) << WCuplow_II_SHIFT;
+ i = ((unsigned) WCuplow[WCuplow_II_LEN + i + n]) << WCuplow_TI_SHIFT;
+ i = ((unsigned) WCuplow[WCuplow_II_LEN + WCuplow_TI_LEN + i + sc]) << 1;
+ wc += WCuplow_diff[i];
+ }
+ return wc;
+}
+# endif /* defined(L_towupper) && defined(__UCLIBC_HAS_XLOCALE__) */
+
+# endif /* SMALL_UPLOW */
+
+# ifdef L_towupper_l
+libc_hidden_def(towupper_l)
+# endif
+
+# endif /* __LOCALE_C_ONLY */
+
+# ifndef L_towupper_l
+libc_hidden_def(towupper)
+# endif
+
+#endif
+/**********************************************************************/
+#ifdef L_wctype
+
+static const unsigned char typestring[] = __CTYPE_TYPESTRING;
+
+wctype_t wctype(const char *property)
+{
+ const unsigned char *p;
+ int i;
+
+ p = typestring;
+ i = 1;
+ do {
+ if (!strcmp(property, (const char *) ++p)) {
+ return i;
+ }
+ ++i;
+ p += p[-1];
+ } while (*p);
+
+ /* TODO - Add locale-specific classifications. */
+ return 0;
+}
+libc_hidden_def(wctype)
+
+#endif
+/**********************************************************************/
+#ifdef L_wctype_l
+
+#ifdef __UCLIBC_MJN3_ONLY__
+# warning REMINDER: Currently wctype_l simply calls wctype.
+#endif
+
+wctype_t wctype_l (const char *property, __locale_t locale)
+{
+ return wctype(property);
+}
+
+#endif
+/**********************************************************************/
+#if defined(L_iswctype) || defined(L_iswctype_l)
+
+#define __C_iswdigit(c) \
+ ((sizeof(c) == sizeof(char)) \
+ ? ((unsigned char)((c) - '0') < 10) \
+ : ((__uwchar_t)((c) - '0') < 10) \
+ )
+#define __C_iswxdigit(c) \
+ (__C_iswdigit(c) \
+ || ((sizeof(c) == sizeof(char)) \
+ ? ((unsigned char)(((c) | 0x20) - 'a') < 6) \
+ : ((__uwchar_t)(((c) | 0x20) - 'a') < 6) \
+ ) \
+ )
+
+#ifdef __UCLIBC_MJN3_ONLY__
+# ifdef L_iswctype
+# warning CONSIDER: Change to bit shift? would need to sync with wctype.h
+# endif
+#endif
+
+#ifdef __UCLIBC_HAS_CTYPE_TABLES__
+# if !defined(__UCLIBC_HAS_XLOCALE__) || defined(L_iswctype_l)
+static const unsigned short int desc2flag[] = {
+ [_CTYPE_unclassified] = 0,
+ [_CTYPE_isalnum] = (unsigned short int) _ISwalnum,
+ [_CTYPE_isalpha] = (unsigned short int) _ISwalpha,
+ [_CTYPE_isblank] = (unsigned short int) _ISwblank,
+ [_CTYPE_iscntrl] = (unsigned short int) _ISwcntrl,
+ [_CTYPE_isdigit] = (unsigned short int) _ISwdigit,
+ [_CTYPE_isgraph] = (unsigned short int) _ISwgraph,
+ [_CTYPE_islower] = (unsigned short int) _ISwlower,
+ [_CTYPE_isprint] = (unsigned short int) _ISwprint,
+ [_CTYPE_ispunct] = (unsigned short int) _ISwpunct,
+ [_CTYPE_isspace] = (unsigned short int) _ISwspace,
+ [_CTYPE_isupper] = (unsigned short int) _ISwupper,
+ [_CTYPE_isxdigit] = (unsigned short int) _ISwxdigit,
+};
+# endif
+#endif
+
+#ifdef __LOCALE_C_ONLY
+
+#ifdef __UCLIBC_HAS_CTYPE_TABLES__
+
+int iswctype(wint_t wc, wctype_t desc)
+{
+ /* Note... wctype_t is unsigned. */
+
+ if ((__uwchar_t) wc <= 0x7f
+ && desc < (sizeof(desc2flag) / sizeof(desc2flag[0]))
+ ) {
+ return __isctype(wc, desc2flag[desc]);
+ }
+ return 0;
+}
+
+#else /* __UCLIBC_HAS_CTYPE_TABLES__ */
+
+int iswctype(wint_t wc, wctype_t desc)
+{
+ /* This is lame, but it is here just to get it working for now. */
+
+ if (wc == (unsigned)wc) {
+ switch (desc) {
+ case _CTYPE_isupper:
+ return __C_isupper((unsigned)wc);
+ case _CTYPE_islower:
+ return __C_islower((unsigned)wc);
+ case _CTYPE_isalpha:
+ return __C_isalpha((unsigned)wc);
+ case _CTYPE_isdigit:
+ return __C_isdigit((unsigned)wc);
+ case _CTYPE_isxdigit:
+ return __C_isxdigit((unsigned)wc);
+ case _CTYPE_isspace:
+ return __C_isspace((unsigned)wc);
+ case _CTYPE_isprint:
+ return __C_isprint((unsigned)wc);
+ case _CTYPE_isgraph:
+ return __C_isgraph((unsigned)wc);
+ case _CTYPE_isblank:
+ return __C_isblank((unsigned)wc);
+ case _CTYPE_iscntrl:
+ return __C_iscntrl((unsigned)wc);
+ case _CTYPE_ispunct:
+ return __C_ispunct((unsigned)wc);
+ case _CTYPE_isalnum:
+ return __C_isalnum((unsigned)wc);
+ default:
+ break;
+ }
+ }
+ return 0;
+}
+
+#endif /* __UCLIBC_HAS_CTYPE_TABLES__ */
+
+#else /* __LOCALE_C_ONLY */
+
+#ifdef __UCLIBC_MJN3_ONLY__
+# ifdef L_iswctype
+# warning CONSIDER: Handle combining class?
+# endif
+#endif
+
+#ifdef L_iswctype
+# define ISWCTYPE(w,d) iswctype(w,d)
+#else
+# define ISWCTYPE(w,d) iswctype_l(w,d, __locale_t locale)
+# undef __UCLIBC_CURLOCALE
+# define __UCLIBC_CURLOCALE (locale)
+#endif
+
+#if defined(L_iswctype) && defined(__UCLIBC_HAS_XLOCALE__)
+
+int iswctype(wint_t wc, wctype_t desc)
+{
+ return iswctype_l(wc, desc, __UCLIBC_CURLOCALE);
+}
+
+#else /* defined(L_iswctype) && defined(__UCLIBC_HAS_XLOCALE__) */
+
+int ISWCTYPE(wint_t wc, wctype_t desc)
+{
+ unsigned sc, n, i0, i1;
+ unsigned char d = __CTYPE_unclassified;
+
+ if ((ENCODING != __ctype_encoding_7_bit) || ((__uwchar_t)wc <= 0x7f)) {
+ if (desc < _CTYPE_iswxdigit) {
+ if ((__uwchar_t)wc <= WC_TABLE_DOMAIN_MAX) {
+ /* From here on, we know wc > 0. */
+ sc = wc & WCctype_TI_MASK;
+ wc >>= WCctype_TI_SHIFT;
+ n = wc & WCctype_II_MASK;
+ wc >>= WCctype_II_SHIFT;
+
+ i0 = WCctype[wc];
+ i0 <<= WCctype_II_SHIFT;
+ i1 = WCctype[WCctype_II_LEN + i0 + n];
+ i1 <<= (WCctype_TI_SHIFT-1);
+ d = WCctype[WCctype_II_LEN + WCctype_TI_LEN + i1 + (sc >> 1)];
+
+ d = (sc & 1) ? (d >> 4) : (d & 0xf);
+ } else if ((__uwchar_t)(wc - 0xe0020UL) <= 0x5f
+ || wc == 0xe0001UL
+ || (((__uwchar_t)(wc - 0xf0000UL) < 0x20000UL) && ((wc & 0xffffU) <= 0xfffdU))
+ ) {
+ d = __CTYPE_punct;
+ }
+
+#if 0
+ return ((unsigned char)(d - ctype_range[2*desc]) <= ctype_range[2*desc + 1])
+ && ((desc != _CTYPE_iswblank) || (d & 1));
+#else
+ return __UCLIBC_CURLOCALE->code2flag[d] & desc2flag[desc];
+#endif
+ }
+
+#ifdef __UCLIBC_MJN3_ONLY__
+# warning TODO: xdigit really needs to be handled better. Remember only for ascii!
+#endif
+ /* TODO - Add locale-specific classifications. */
+ return (desc == _CTYPE_iswxdigit) ? __C_iswxdigit(wc) : 0;
+ }
+ return 0;
+}
+
+#endif /* defined(L_iswctype) && defined(__UCLIBC_HAS_XLOCALE__) */
+
+#ifdef L_iswctype_l
+libc_hidden_def(iswctype_l)
+#endif
+
+#endif /* __LOCALE_C_ONLY */
+
+#ifdef L_iswctype
+libc_hidden_def(iswctype)
+#endif
+
+#endif
+/**********************************************************************/
+#if defined(L_towctrans) || defined(L_towctrans_l)
+
+#ifdef __LOCALE_C_ONLY
+
+/* Minimal support for C/POSIX locale. */
+
+wint_t towctrans(wint_t wc, wctrans_t desc)
+{
+ if ((unsigned)(desc - _CTYPE_tolower) <= (_CTYPE_toupper - _CTYPE_tolower)) {
+ /* Transliteration is either tolower or toupper. */
+#if 0
+/* I think it's wrong: _toupper(c) assumes that c is a *lowercase* *letter* -
+ * it is defined as ((c) ^ 0x20)! */
+ if ((__uwchar_t) wc <= 0x7f) {
+ return (desc == _CTYPE_tolower) ? _tolower(wc) : _toupper(wc);
+ }
+#endif
+ __uwchar_t c = wc | 0x20; /* lowercase if it's a letter */
+ if (c >= 'a' && c <= 'z') {
+ if (desc == _CTYPE_toupper)
+ c &= ~0x20; /* uppercase */
+ return c;
+ }
+ } else {
+ __set_errno(EINVAL); /* Invalid transliteration. */
+ }
+ return wc;
+}
+
+#else /* __LOCALE_C_ONLY */
+
+#ifdef L_towctrans
+# define TOWCTRANS(w,d) towctrans(w,d)
+#else
+# define TOWCTRANS(w,d) towctrans_l(w,d, __locale_t locale)
+# undef __UCLIBC_CURLOCALE
+# define __UCLIBC_CURLOCALE (locale)
+#endif
+
+#ifdef __UCLIBC_HAS_XLOCALE__
+# define TOWLOWER(w,l) towlower_l(w,l)
+# define TOWUPPER(w,l) towupper_l(w,l)
+#else
+# define TOWLOWER(w,l) towlower(w)
+# define TOWUPPER(w,l) towupper(w)
+#endif
+
+#if defined(L_towctrans) && defined(__UCLIBC_HAS_XLOCALE__)
+
+wint_t towctrans(wint_t wc, wctrans_t desc)
+{
+ return towctrans_l(wc, desc, __UCLIBC_CURLOCALE);
+}
+
+#else /* defined(L_towctrans) && defined(__UCLIBC_HAS_XLOCALE__) */
+
+#ifdef SMALL_UPLOW
+
+wint_t TOWCTRANS(wint_t wc, wctrans_t desc)
+{
+ unsigned sc, n, i;
+ __uwchar_t u = wc;
+
+ /* TODO - clean up */
+ if (ENCODING == __ctype_encoding_7_bit) {
+ if ((__uwchar_t)wc > 0x7f
+ || (unsigned)(desc - _CTYPE_tolower) > (_CTYPE_toupper - _CTYPE_tolower)
+ ) {
+ /* We're in the C/POSIX locale, so ignore non-ASCII values
+ * as well an any mappings other than toupper or tolower. */
+ return wc;
+ }
+ }
+
+ if ((unsigned)(desc - _CTYPE_tolower) <= (_CTYPE_totitle - _CTYPE_tolower)) {
+ if (u <= WC_TABLE_DOMAIN_MAX) {
+ sc = u & ((1 << WCuplow_TI_SHIFT) - 1);
+ u >>= WCuplow_TI_SHIFT;
+ n = u & ((1 << WCuplow_II_SHIFT) - 1);
+ u >>= WCuplow_II_SHIFT;
+
+ i = ((unsigned) WCuplow[u]) << WCuplow_II_SHIFT;
+ i = ((unsigned) WCuplow[WCuplow_II_LEN + i + n]) << WCuplow_TI_SHIFT;
+ i = ((unsigned) WCuplow[WCuplow_II_LEN + WCuplow_TI_LEN + i + sc]) << 1;
+ if (desc == _CTYPE_tolower) {
+ ++i;
+ }
+ wc += WCuplow_diff[i];
+ if (desc == _CTYPE_totitle) {
+#ifdef __UCLIBC_MJN3_ONLY__
+# warning TODO: Verify totitle special cases!
+#endif
+ /* WARNING! These special cases work for glibc 2.2.4. Changes
+ * may be needed if the glibc locale tables are updated. */
+ if ((__uwchar_t)(wc - 0x1c4) <= (0x1cc - 0x1c4)
+ || wc == 0x1f1
+ ) {
+ ++wc;
+ }
+ }
+ }
+ } else {
+ /* TODO - Deal with other transliterations. */
+ __set_errno(EINVAL);
+ }
+
+ return wc;
+}
+
+#else /* SMALL_UPLOW */
+
+wint_t TOWCTRANS(wint_t wc, wctrans_t desc)
+{
+ if (ENCODING == __ctype_encoding_7_bit) {
+ if ((__uwchar_t)wc > 0x7f
+ || (unsigned)(desc - _CTYPE_tolower) > (_CTYPE_toupper - _CTYPE_tolower)
+ ) {
+ /* We're in the C/POSIX locale, so ignore non-ASCII values
+ * as well an any mappings other than toupper or tolower. */
+ return wc;
+ }
+ }
+
+ if (desc == _CTYPE_tolower) {
+ return TOWLOWER(wc, __UCLIBC_CURLOCALE);
+ }
+ if ((unsigned)(desc - _CTYPE_toupper) <= (_CTYPE_totitle - _CTYPE_toupper)) {
+ wc = TOWUPPER(wc, __UCLIBC_CURLOCALE);
+ if (desc == _CTYPE_totitle) {
+#ifdef __UCLIBC_MJN3_ONLY__
+# warning TODO: Verify totitle special cases!
+#endif
+ /* WARNING! These special cases work for glibc 2.2.4. Changes
+ * may be needed if the glibc locale tables are updated. */
+ if ((__uwchar_t)(wc - 0x1c4) <= (0x1cc - 0x1c4)
+ || wc == 0x1f1
+ ) {
+ ++wc;
+ }
+ }
+ } else {
+ /* TODO - Deal with other transliterations. */
+ __set_errno(EINVAL);
+ }
+ return wc;
+}
+
+#endif /* SMALL_UPLOW */
+
+#endif /* defined(L_towctrans) && defined(__UCLIBC_HAS_XLOCALE__) */
+
+#ifdef L_towctrans_l
+libc_hidden_def(towctrans_l)
+#endif
+
+#endif /* __LOCALE_C_ONLY */
+
+#ifndef L_towctrans_l
+libc_hidden_def(towctrans)
+#endif
+
+#endif
+/**********************************************************************/
+#ifdef L_wctrans
+
+static const char transstring[] = __CTYPE_TRANSTRING;
+
+wctrans_t wctrans(const char *property)
+{
+ const unsigned char *p;
+ int i;
+
+ p = (const unsigned char *) transstring;
+ i = 1;
+ do {
+ if (!strcmp(property, (const char*) ++p)) {
+ return i;
+ }
+ ++i;
+ p += p[-1];
+ } while (*p);
+
+ /* TODO - Add locale-specific translations. */
+ return 0;
+}
+libc_hidden_def(wctrans)
+
+#endif
+/**********************************************************************/
+#ifdef L_wctrans_l
+
+# ifdef __UCLIBC_MJN3_ONLY__
+# warning REMINDER: Currently wctrans_l simply calls wctrans.
+# endif
+
+wctrans_t wctrans_l(const char *property, __locale_t locale)
+{
+ return wctrans(property);
+}
+
+#endif
+/**********************************************************************/
diff --git a/ap/build/uClibc/libc/misc/wctype/iswalnum.c b/ap/build/uClibc/libc/misc/wctype/iswalnum.c
new file mode 100644
index 0000000..a85a03d
--- /dev/null
+++ b/ap/build/uClibc/libc/misc/wctype/iswalnum.c
@@ -0,0 +1,8 @@
+/*
+ * Copyright (C) 2002-2006 Manuel Novoa III <mjn3@uclibc.org>
+ *
+ * Licensed under the LGPL v2.1, see the file COPYING.LIB in this tarball.
+ */
+
+#define L_iswalnum
+#include "_wctype.c"
diff --git a/ap/build/uClibc/libc/misc/wctype/iswalnum_l.c b/ap/build/uClibc/libc/misc/wctype/iswalnum_l.c
new file mode 100644
index 0000000..6e3cd77
--- /dev/null
+++ b/ap/build/uClibc/libc/misc/wctype/iswalnum_l.c
@@ -0,0 +1,9 @@
+/*
+ * Copyright (C) 2002-2006 Manuel Novoa III <mjn3@uclibc.org>
+ *
+ * Licensed under the LGPL v2.1, see the file COPYING.LIB in this tarball.
+ */
+
+#define L_iswalnum_l
+#define __UCLIBC_DO_XLOCALE
+#include "_wctype.c"
diff --git a/ap/build/uClibc/libc/misc/wctype/iswalpha.c b/ap/build/uClibc/libc/misc/wctype/iswalpha.c
new file mode 100644
index 0000000..6b829eb
--- /dev/null
+++ b/ap/build/uClibc/libc/misc/wctype/iswalpha.c
@@ -0,0 +1,8 @@
+/*
+ * Copyright (C) 2002-2006 Manuel Novoa III <mjn3@uclibc.org>
+ *
+ * Licensed under the LGPL v2.1, see the file COPYING.LIB in this tarball.
+ */
+
+#define L_iswalpha
+#include "_wctype.c"
diff --git a/ap/build/uClibc/libc/misc/wctype/iswalpha_l.c b/ap/build/uClibc/libc/misc/wctype/iswalpha_l.c
new file mode 100644
index 0000000..79b11cf
--- /dev/null
+++ b/ap/build/uClibc/libc/misc/wctype/iswalpha_l.c
@@ -0,0 +1,9 @@
+/*
+ * Copyright (C) 2002-2006 Manuel Novoa III <mjn3@uclibc.org>
+ *
+ * Licensed under the LGPL v2.1, see the file COPYING.LIB in this tarball.
+ */
+
+#define L_iswalpha_l
+#define __UCLIBC_DO_XLOCALE
+#include "_wctype.c"
diff --git a/ap/build/uClibc/libc/misc/wctype/iswblank.c b/ap/build/uClibc/libc/misc/wctype/iswblank.c
new file mode 100644
index 0000000..67862d5
--- /dev/null
+++ b/ap/build/uClibc/libc/misc/wctype/iswblank.c
@@ -0,0 +1,8 @@
+/*
+ * Copyright (C) 2002-2006 Manuel Novoa III <mjn3@uclibc.org>
+ *
+ * Licensed under the LGPL v2.1, see the file COPYING.LIB in this tarball.
+ */
+
+#define L_iswblank
+#include "_wctype.c"
diff --git a/ap/build/uClibc/libc/misc/wctype/iswblank_l.c b/ap/build/uClibc/libc/misc/wctype/iswblank_l.c
new file mode 100644
index 0000000..4c5709c
--- /dev/null
+++ b/ap/build/uClibc/libc/misc/wctype/iswblank_l.c
@@ -0,0 +1,9 @@
+/*
+ * Copyright (C) 2002-2006 Manuel Novoa III <mjn3@uclibc.org>
+ *
+ * Licensed under the LGPL v2.1, see the file COPYING.LIB in this tarball.
+ */
+
+#define L_iswblank_l
+#define __UCLIBC_DO_XLOCALE
+#include "_wctype.c"
diff --git a/ap/build/uClibc/libc/misc/wctype/iswcntrl.c b/ap/build/uClibc/libc/misc/wctype/iswcntrl.c
new file mode 100644
index 0000000..50d72b4
--- /dev/null
+++ b/ap/build/uClibc/libc/misc/wctype/iswcntrl.c
@@ -0,0 +1,8 @@
+/*
+ * Copyright (C) 2002-2006 Manuel Novoa III <mjn3@uclibc.org>
+ *
+ * Licensed under the LGPL v2.1, see the file COPYING.LIB in this tarball.
+ */
+
+#define L_iswcntrl
+#include "_wctype.c"
diff --git a/ap/build/uClibc/libc/misc/wctype/iswcntrl_l.c b/ap/build/uClibc/libc/misc/wctype/iswcntrl_l.c
new file mode 100644
index 0000000..2fe64d7
--- /dev/null
+++ b/ap/build/uClibc/libc/misc/wctype/iswcntrl_l.c
@@ -0,0 +1,9 @@
+/*
+ * Copyright (C) 2002-2006 Manuel Novoa III <mjn3@uclibc.org>
+ *
+ * Licensed under the LGPL v2.1, see the file COPYING.LIB in this tarball.
+ */
+
+#define L_iswcntrl_l
+#define __UCLIBC_DO_XLOCALE
+#include "_wctype.c"
diff --git a/ap/build/uClibc/libc/misc/wctype/iswctype.c b/ap/build/uClibc/libc/misc/wctype/iswctype.c
new file mode 100644
index 0000000..777d410
--- /dev/null
+++ b/ap/build/uClibc/libc/misc/wctype/iswctype.c
@@ -0,0 +1,8 @@
+/*
+ * Copyright (C) 2002-2006 Manuel Novoa III <mjn3@uclibc.org>
+ *
+ * Licensed under the LGPL v2.1, see the file COPYING.LIB in this tarball.
+ */
+
+#define L_iswctype
+#include "_wctype.c"
diff --git a/ap/build/uClibc/libc/misc/wctype/iswctype_l.c b/ap/build/uClibc/libc/misc/wctype/iswctype_l.c
new file mode 100644
index 0000000..71bce18
--- /dev/null
+++ b/ap/build/uClibc/libc/misc/wctype/iswctype_l.c
@@ -0,0 +1,9 @@
+/*
+ * Copyright (C) 2002-2006 Manuel Novoa III <mjn3@uclibc.org>
+ *
+ * Licensed under the LGPL v2.1, see the file COPYING.LIB in this tarball.
+ */
+
+#define L_iswctype_l
+#define __UCLIBC_DO_XLOCALE
+#include "_wctype.c"
diff --git a/ap/build/uClibc/libc/misc/wctype/iswdigit.c b/ap/build/uClibc/libc/misc/wctype/iswdigit.c
new file mode 100644
index 0000000..b2aa5d0
--- /dev/null
+++ b/ap/build/uClibc/libc/misc/wctype/iswdigit.c
@@ -0,0 +1,8 @@
+/*
+ * Copyright (C) 2002-2006 Manuel Novoa III <mjn3@uclibc.org>
+ *
+ * Licensed under the LGPL v2.1, see the file COPYING.LIB in this tarball.
+ */
+
+#define L_iswdigit
+#include "_wctype.c"
diff --git a/ap/build/uClibc/libc/misc/wctype/iswdigit_l.c b/ap/build/uClibc/libc/misc/wctype/iswdigit_l.c
new file mode 100644
index 0000000..4832c9c
--- /dev/null
+++ b/ap/build/uClibc/libc/misc/wctype/iswdigit_l.c
@@ -0,0 +1,9 @@
+/*
+ * Copyright (C) 2002-2006 Manuel Novoa III <mjn3@uclibc.org>
+ *
+ * Licensed under the LGPL v2.1, see the file COPYING.LIB in this tarball.
+ */
+
+#define L_iswdigit_l
+#define __UCLIBC_DO_XLOCALE
+#include "_wctype.c"
diff --git a/ap/build/uClibc/libc/misc/wctype/iswgraph.c b/ap/build/uClibc/libc/misc/wctype/iswgraph.c
new file mode 100644
index 0000000..8113054
--- /dev/null
+++ b/ap/build/uClibc/libc/misc/wctype/iswgraph.c
@@ -0,0 +1,8 @@
+/*
+ * Copyright (C) 2002-2006 Manuel Novoa III <mjn3@uclibc.org>
+ *
+ * Licensed under the LGPL v2.1, see the file COPYING.LIB in this tarball.
+ */
+
+#define L_iswgraph
+#include "_wctype.c"
diff --git a/ap/build/uClibc/libc/misc/wctype/iswgraph_l.c b/ap/build/uClibc/libc/misc/wctype/iswgraph_l.c
new file mode 100644
index 0000000..db68315
--- /dev/null
+++ b/ap/build/uClibc/libc/misc/wctype/iswgraph_l.c
@@ -0,0 +1,9 @@
+/*
+ * Copyright (C) 2002-2006 Manuel Novoa III <mjn3@uclibc.org>
+ *
+ * Licensed under the LGPL v2.1, see the file COPYING.LIB in this tarball.
+ */
+
+#define L_iswgraph_l
+#define __UCLIBC_DO_XLOCALE
+#include "_wctype.c"
diff --git a/ap/build/uClibc/libc/misc/wctype/iswlower.c b/ap/build/uClibc/libc/misc/wctype/iswlower.c
new file mode 100644
index 0000000..016d8cc
--- /dev/null
+++ b/ap/build/uClibc/libc/misc/wctype/iswlower.c
@@ -0,0 +1,8 @@
+/*
+ * Copyright (C) 2002-2006 Manuel Novoa III <mjn3@uclibc.org>
+ *
+ * Licensed under the LGPL v2.1, see the file COPYING.LIB in this tarball.
+ */
+
+#define L_iswlower
+#include "_wctype.c"
diff --git a/ap/build/uClibc/libc/misc/wctype/iswlower_l.c b/ap/build/uClibc/libc/misc/wctype/iswlower_l.c
new file mode 100644
index 0000000..5b9f821
--- /dev/null
+++ b/ap/build/uClibc/libc/misc/wctype/iswlower_l.c
@@ -0,0 +1,9 @@
+/*
+ * Copyright (C) 2002-2006 Manuel Novoa III <mjn3@uclibc.org>
+ *
+ * Licensed under the LGPL v2.1, see the file COPYING.LIB in this tarball.
+ */
+
+#define L_iswlower_l
+#define __UCLIBC_DO_XLOCALE
+#include "_wctype.c"
diff --git a/ap/build/uClibc/libc/misc/wctype/iswprint.c b/ap/build/uClibc/libc/misc/wctype/iswprint.c
new file mode 100644
index 0000000..8e47e88
--- /dev/null
+++ b/ap/build/uClibc/libc/misc/wctype/iswprint.c
@@ -0,0 +1,8 @@
+/*
+ * Copyright (C) 2002-2006 Manuel Novoa III <mjn3@uclibc.org>
+ *
+ * Licensed under the LGPL v2.1, see the file COPYING.LIB in this tarball.
+ */
+
+#define L_iswprint
+#include "_wctype.c"
diff --git a/ap/build/uClibc/libc/misc/wctype/iswprint_l.c b/ap/build/uClibc/libc/misc/wctype/iswprint_l.c
new file mode 100644
index 0000000..148414c
--- /dev/null
+++ b/ap/build/uClibc/libc/misc/wctype/iswprint_l.c
@@ -0,0 +1,9 @@
+/*
+ * Copyright (C) 2002-2006 Manuel Novoa III <mjn3@uclibc.org>
+ *
+ * Licensed under the LGPL v2.1, see the file COPYING.LIB in this tarball.
+ */
+
+#define L_iswprint_l
+#define __UCLIBC_DO_XLOCALE
+#include "_wctype.c"
diff --git a/ap/build/uClibc/libc/misc/wctype/iswpunct.c b/ap/build/uClibc/libc/misc/wctype/iswpunct.c
new file mode 100644
index 0000000..1175e1a
--- /dev/null
+++ b/ap/build/uClibc/libc/misc/wctype/iswpunct.c
@@ -0,0 +1,8 @@
+/*
+ * Copyright (C) 2002-2006 Manuel Novoa III <mjn3@uclibc.org>
+ *
+ * Licensed under the LGPL v2.1, see the file COPYING.LIB in this tarball.
+ */
+
+#define L_iswpunct
+#include "_wctype.c"
diff --git a/ap/build/uClibc/libc/misc/wctype/iswpunct_l.c b/ap/build/uClibc/libc/misc/wctype/iswpunct_l.c
new file mode 100644
index 0000000..a6d3616
--- /dev/null
+++ b/ap/build/uClibc/libc/misc/wctype/iswpunct_l.c
@@ -0,0 +1,9 @@
+/*
+ * Copyright (C) 2002-2006 Manuel Novoa III <mjn3@uclibc.org>
+ *
+ * Licensed under the LGPL v2.1, see the file COPYING.LIB in this tarball.
+ */
+
+#define L_iswpunct_l
+#define __UCLIBC_DO_XLOCALE
+#include "_wctype.c"
diff --git a/ap/build/uClibc/libc/misc/wctype/iswspace.c b/ap/build/uClibc/libc/misc/wctype/iswspace.c
new file mode 100644
index 0000000..603f5cf
--- /dev/null
+++ b/ap/build/uClibc/libc/misc/wctype/iswspace.c
@@ -0,0 +1,8 @@
+/*
+ * Copyright (C) 2002-2006 Manuel Novoa III <mjn3@uclibc.org>
+ *
+ * Licensed under the LGPL v2.1, see the file COPYING.LIB in this tarball.
+ */
+
+#define L_iswspace
+#include "_wctype.c"
diff --git a/ap/build/uClibc/libc/misc/wctype/iswspace_l.c b/ap/build/uClibc/libc/misc/wctype/iswspace_l.c
new file mode 100644
index 0000000..e389f89
--- /dev/null
+++ b/ap/build/uClibc/libc/misc/wctype/iswspace_l.c
@@ -0,0 +1,9 @@
+/*
+ * Copyright (C) 2002-2006 Manuel Novoa III <mjn3@uclibc.org>
+ *
+ * Licensed under the LGPL v2.1, see the file COPYING.LIB in this tarball.
+ */
+
+#define L_iswspace_l
+#define __UCLIBC_DO_XLOCALE
+#include "_wctype.c"
diff --git a/ap/build/uClibc/libc/misc/wctype/iswupper.c b/ap/build/uClibc/libc/misc/wctype/iswupper.c
new file mode 100644
index 0000000..4cfdebb
--- /dev/null
+++ b/ap/build/uClibc/libc/misc/wctype/iswupper.c
@@ -0,0 +1,8 @@
+/*
+ * Copyright (C) 2002-2006 Manuel Novoa III <mjn3@uclibc.org>
+ *
+ * Licensed under the LGPL v2.1, see the file COPYING.LIB in this tarball.
+ */
+
+#define L_iswupper
+#include "_wctype.c"
diff --git a/ap/build/uClibc/libc/misc/wctype/iswupper_l.c b/ap/build/uClibc/libc/misc/wctype/iswupper_l.c
new file mode 100644
index 0000000..359aef9
--- /dev/null
+++ b/ap/build/uClibc/libc/misc/wctype/iswupper_l.c
@@ -0,0 +1,9 @@
+/*
+ * Copyright (C) 2002-2006 Manuel Novoa III <mjn3@uclibc.org>
+ *
+ * Licensed under the LGPL v2.1, see the file COPYING.LIB in this tarball.
+ */
+
+#define L_iswupper_l
+#define __UCLIBC_DO_XLOCALE
+#include "_wctype.c"
diff --git a/ap/build/uClibc/libc/misc/wctype/iswxdigit.c b/ap/build/uClibc/libc/misc/wctype/iswxdigit.c
new file mode 100644
index 0000000..568f253
--- /dev/null
+++ b/ap/build/uClibc/libc/misc/wctype/iswxdigit.c
@@ -0,0 +1,8 @@
+/*
+ * Copyright (C) 2002-2006 Manuel Novoa III <mjn3@uclibc.org>
+ *
+ * Licensed under the LGPL v2.1, see the file COPYING.LIB in this tarball.
+ */
+
+#define L_iswxdigit
+#include "_wctype.c"
diff --git a/ap/build/uClibc/libc/misc/wctype/iswxdigit_l.c b/ap/build/uClibc/libc/misc/wctype/iswxdigit_l.c
new file mode 100644
index 0000000..1d543ab
--- /dev/null
+++ b/ap/build/uClibc/libc/misc/wctype/iswxdigit_l.c
@@ -0,0 +1,9 @@
+/*
+ * Copyright (C) 2002-2006 Manuel Novoa III <mjn3@uclibc.org>
+ *
+ * Licensed under the LGPL v2.1, see the file COPYING.LIB in this tarball.
+ */
+
+#define L_iswxdigit_l
+#define __UCLIBC_DO_XLOCALE
+#include "_wctype.c"
diff --git a/ap/build/uClibc/libc/misc/wctype/towctrans.c b/ap/build/uClibc/libc/misc/wctype/towctrans.c
new file mode 100644
index 0000000..9ad0468
--- /dev/null
+++ b/ap/build/uClibc/libc/misc/wctype/towctrans.c
@@ -0,0 +1,8 @@
+/*
+ * Copyright (C) 2002-2006 Manuel Novoa III <mjn3@uclibc.org>
+ *
+ * Licensed under the LGPL v2.1, see the file COPYING.LIB in this tarball.
+ */
+
+#define L_towctrans
+#include "_wctype.c"
diff --git a/ap/build/uClibc/libc/misc/wctype/towctrans_l.c b/ap/build/uClibc/libc/misc/wctype/towctrans_l.c
new file mode 100644
index 0000000..e179b50
--- /dev/null
+++ b/ap/build/uClibc/libc/misc/wctype/towctrans_l.c
@@ -0,0 +1,9 @@
+/*
+ * Copyright (C) 2002-2006 Manuel Novoa III <mjn3@uclibc.org>
+ *
+ * Licensed under the LGPL v2.1, see the file COPYING.LIB in this tarball.
+ */
+
+#define L_towctrans_l
+#define __UCLIBC_DO_XLOCALE
+#include "_wctype.c"
diff --git a/ap/build/uClibc/libc/misc/wctype/towlower.c b/ap/build/uClibc/libc/misc/wctype/towlower.c
new file mode 100644
index 0000000..dffbff3
--- /dev/null
+++ b/ap/build/uClibc/libc/misc/wctype/towlower.c
@@ -0,0 +1,8 @@
+/*
+ * Copyright (C) 2002-2006 Manuel Novoa III <mjn3@uclibc.org>
+ *
+ * Licensed under the LGPL v2.1, see the file COPYING.LIB in this tarball.
+ */
+
+#define L_towlower
+#include "_wctype.c"
diff --git a/ap/build/uClibc/libc/misc/wctype/towlower_l.c b/ap/build/uClibc/libc/misc/wctype/towlower_l.c
new file mode 100644
index 0000000..f1aa7e6
--- /dev/null
+++ b/ap/build/uClibc/libc/misc/wctype/towlower_l.c
@@ -0,0 +1,9 @@
+/*
+ * Copyright (C) 2002-2006 Manuel Novoa III <mjn3@uclibc.org>
+ *
+ * Licensed under the LGPL v2.1, see the file COPYING.LIB in this tarball.
+ */
+
+#define L_towlower_l
+#define __UCLIBC_DO_XLOCALE
+#include "_wctype.c"
diff --git a/ap/build/uClibc/libc/misc/wctype/towupper.c b/ap/build/uClibc/libc/misc/wctype/towupper.c
new file mode 100644
index 0000000..1dab8fe
--- /dev/null
+++ b/ap/build/uClibc/libc/misc/wctype/towupper.c
@@ -0,0 +1,8 @@
+/*
+ * Copyright (C) 2002-2006 Manuel Novoa III <mjn3@uclibc.org>
+ *
+ * Licensed under the LGPL v2.1, see the file COPYING.LIB in this tarball.
+ */
+
+#define L_towupper
+#include "_wctype.c"
diff --git a/ap/build/uClibc/libc/misc/wctype/towupper_l.c b/ap/build/uClibc/libc/misc/wctype/towupper_l.c
new file mode 100644
index 0000000..cf05d5c
--- /dev/null
+++ b/ap/build/uClibc/libc/misc/wctype/towupper_l.c
@@ -0,0 +1,9 @@
+/*
+ * Copyright (C) 2002-2006 Manuel Novoa III <mjn3@uclibc.org>
+ *
+ * Licensed under the LGPL v2.1, see the file COPYING.LIB in this tarball.
+ */
+
+#define L_towupper_l
+#define __UCLIBC_DO_XLOCALE
+#include "_wctype.c"
diff --git a/ap/build/uClibc/libc/misc/wctype/wctrans.c b/ap/build/uClibc/libc/misc/wctype/wctrans.c
new file mode 100644
index 0000000..f99d9cd
--- /dev/null
+++ b/ap/build/uClibc/libc/misc/wctype/wctrans.c
@@ -0,0 +1,8 @@
+/*
+ * Copyright (C) 2002-2006 Manuel Novoa III <mjn3@uclibc.org>
+ *
+ * Licensed under the LGPL v2.1, see the file COPYING.LIB in this tarball.
+ */
+
+#define L_wctrans
+#include "_wctype.c"
diff --git a/ap/build/uClibc/libc/misc/wctype/wctrans_l.c b/ap/build/uClibc/libc/misc/wctype/wctrans_l.c
new file mode 100644
index 0000000..79854c2
--- /dev/null
+++ b/ap/build/uClibc/libc/misc/wctype/wctrans_l.c
@@ -0,0 +1,9 @@
+/*
+ * Copyright (C) 2002-2006 Manuel Novoa III <mjn3@uclibc.org>
+ *
+ * Licensed under the LGPL v2.1, see the file COPYING.LIB in this tarball.
+ */
+
+#define L_wctrans_l
+#define __UCLIBC_DO_XLOCALE
+#include "_wctype.c"
diff --git a/ap/build/uClibc/libc/misc/wctype/wctype.c b/ap/build/uClibc/libc/misc/wctype/wctype.c
new file mode 100644
index 0000000..0dc1e6d
--- /dev/null
+++ b/ap/build/uClibc/libc/misc/wctype/wctype.c
@@ -0,0 +1,8 @@
+/*
+ * Copyright (C) 2002-2006 Manuel Novoa III <mjn3@uclibc.org>
+ *
+ * Licensed under the LGPL v2.1, see the file COPYING.LIB in this tarball.
+ */
+
+#define L_wctype
+#include "_wctype.c"
diff --git a/ap/build/uClibc/libc/misc/wctype/wctype_l.c b/ap/build/uClibc/libc/misc/wctype/wctype_l.c
new file mode 100644
index 0000000..65f82e2
--- /dev/null
+++ b/ap/build/uClibc/libc/misc/wctype/wctype_l.c
@@ -0,0 +1,9 @@
+/*
+ * Copyright (C) 2002-2006 Manuel Novoa III <mjn3@uclibc.org>
+ *
+ * Licensed under the LGPL v2.1, see the file COPYING.LIB in this tarball.
+ */
+
+#define L_wctype_l
+#define __UCLIBC_DO_XLOCALE
+#include "_wctype.c"
diff --git a/ap/build/uClibc/libc/misc/wordexp/Makefile b/ap/build/uClibc/libc/misc/wordexp/Makefile
new file mode 100644
index 0000000..4a8f4a0
--- /dev/null
+++ b/ap/build/uClibc/libc/misc/wordexp/Makefile
@@ -0,0 +1,13 @@
+# Makefile for uClibc
+#
+# Copyright (C) 2000-2005 Erik Andersen <andersen@uclibc.org>
+#
+# Licensed under the LGPL v2.1, see the file COPYING.LIB in this tarball.
+#
+
+top_srcdir=../../../
+top_builddir=../../../
+all: objs
+include $(top_builddir)Rules.mak
+include Makefile.in
+include $(top_srcdir)Makerules
diff --git a/ap/build/uClibc/libc/misc/wordexp/Makefile.in b/ap/build/uClibc/libc/misc/wordexp/Makefile.in
new file mode 100644
index 0000000..981db64
--- /dev/null
+++ b/ap/build/uClibc/libc/misc/wordexp/Makefile.in
@@ -0,0 +1,23 @@
+# Makefile for uClibc
+#
+# Copyright (C) 2000-2008 Erik Andersen <andersen@uclibc.org>
+#
+# Licensed under the LGPL v2.1, see the file COPYING.LIB in this tarball.
+#
+
+subdirs += libc/misc/wordexp
+
+CSRC := wordexp.c
+
+MISC_WORDEXP_DIR := $(top_srcdir)libc/misc/wordexp
+MISC_WORDEXP_OUT := $(top_builddir)libc/misc/wordexp
+
+MISC_WORDEXP_SRC := $(patsubst %.c,$(MISC_WORDEXP_DIR)/%.c,$(CSRC))
+MISC_WORDEXP_OBJ := $(patsubst %.c,$(MISC_WORDEXP_OUT)/%.o,$(CSRC))
+
+libc-$(UCLIBC_HAS_WORDEXP) += $(MISC_WORDEXP_OBJ)
+
+objclean-y += CLEAN_libc/misc/wordexp
+
+CLEAN_libc/misc/wordexp:
+ $(do_rm) $(addprefix $(MISC_WORDEXP_OUT)/*., o os)
diff --git a/ap/build/uClibc/libc/misc/wordexp/wordexp.c b/ap/build/uClibc/libc/misc/wordexp/wordexp.c
new file mode 100644
index 0000000..700ea2c
--- /dev/null
+++ b/ap/build/uClibc/libc/misc/wordexp/wordexp.c
@@ -0,0 +1,2250 @@
+/* vi: set sw=4 ts=4: */
+/* POSIX.2 wordexp implementation.
+ Copyright (C) 1997, 1998, 1999 Free Software Foundation, Inc.
+ This file is part of the GNU C Library.
+ Contributed by Tim Waugh <tim@cyberelk.demon.co.uk>.
+
+ The GNU C Library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public License as
+ published by the Free Software Foundation; either version 2 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
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library 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 <features.h>
+#include <bits/kernel-features.h>
+#include <sys/types.h>
+#include <sys/wait.h>
+#include <fcntl.h>
+#include <paths.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+#include <pwd.h>
+#include <errno.h>
+#include <assert.h>
+#include <fnmatch.h>
+#include <glob.h>
+#include <wordexp.h>
+
+#define __WORDEXP_FULL
+
+/*
+ * This is a recursive-descent-style word expansion routine.
+ */
+
+/* These variables are defined and initialized in the startup code. */
+/*extern int __libc_argc;*/
+/*extern char **__libc_argv;*/
+
+/* FIXME!!!! */
+int attribute_hidden __libc_argc;
+char attribute_hidden **__libc_argv;
+
+/* Some forward declarations */
+static int parse_dollars(char **word, size_t * word_length,
+ size_t * max_length, const char *words,
+ size_t * offset, int flags, wordexp_t * pwordexp,
+ const char *ifs, const char *ifs_white,
+ int quoted);
+static int parse_backtick(char **word, size_t * word_length,
+ size_t * max_length, const char *words,
+ size_t * offset, int flags, wordexp_t * pwordexp,
+ const char *ifs, const char *ifs_white);
+static int parse_dquote(char **word, size_t * word_length,
+ size_t * max_length, const char *words,
+ size_t * offset, int flags, wordexp_t * pwordexp,
+ const char *ifs, const char *ifs_white);
+
+
+
+/* The w_*() functions manipulate word lists. */
+#define W_CHUNK (100)
+
+/* Result of w_newword will be ignored if it's the last word. */
+static __inline__ char *w_newword(size_t * actlen, size_t * maxlen)
+{
+ *actlen = *maxlen = 0;
+ return NULL;
+}
+
+/* Add a character to the buffer, allocating room for it if needed. */
+static __inline__ char *w_addchar(char *buffer, size_t * actlen,
+ size_t * maxlen, char ch)
+ /* (lengths exclude trailing zero) */
+{
+
+ if (*actlen == *maxlen) {
+ char *old_buffer = buffer;
+ assert(buffer == NULL || *maxlen != 0);
+ *maxlen += W_CHUNK;
+ buffer = realloc(buffer, 1 + *maxlen);
+ if (buffer == NULL)
+ free(old_buffer);
+ }
+
+ if (buffer != NULL) {
+ buffer[*actlen] = ch;
+ buffer[++(*actlen)] = '\0';
+ }
+
+ return buffer;
+}
+#ifndef MAX
+#define MAX( a, b ) ( ( ( a ) > ( b ) ) ? ( a ) : ( b ) )
+#endif
+static char *w_addmem(char *buffer, size_t * actlen, size_t * maxlen,
+ const char *str, size_t len)
+{
+ /* Add a string to the buffer, allocating room for it if needed.
+ */
+ if (*actlen + len > *maxlen) {
+ char *old_buffer = buffer;
+ assert(buffer == NULL || *maxlen != 0);
+ *maxlen += MAX(2 * len, W_CHUNK);
+ buffer = realloc(old_buffer, 1 + *maxlen);
+ if (buffer == NULL)
+ free(old_buffer);
+ }
+
+ if (buffer != NULL) {
+ *((char *) mempcpy(&buffer[*actlen], str, len)) = '\0';
+ *actlen += len;
+ }
+ return buffer;
+}
+
+/* Add a string to the buffer, allocating room for it if needed. */
+static char *w_addstr(char *buffer, size_t * actlen, size_t * maxlen,
+ const char *str)
+ /* (lengths exclude trailing zero) */
+{
+ size_t len;
+ assert(str != NULL); /* w_addstr only called from this file */
+ len = strlen(str);
+
+ return w_addmem(buffer, actlen, maxlen, str, len);
+}
+
+/* Add a word to the wordlist */
+static int w_addword(wordexp_t * pwordexp, char *word)
+{
+ size_t num_p;
+ char **new_wordv;
+
+ /* Internally, NULL acts like "". Convert NULLs to "" before
+ * the caller sees them.
+ */
+ if (word == NULL) {
+ word = strdup("");
+ if (word == NULL)
+ goto no_space;
+ }
+
+ num_p = 2 + pwordexp->we_wordc + pwordexp->we_offs;
+ new_wordv = realloc(pwordexp->we_wordv, sizeof(char *) * num_p);
+ if (new_wordv != NULL) {
+ pwordexp->we_wordv = new_wordv;
+ pwordexp->we_wordv[pwordexp->we_offs + pwordexp->we_wordc++] = word;
+ pwordexp->we_wordv[pwordexp->we_offs + pwordexp->we_wordc] = NULL;
+ return 0;
+ }
+
+ no_space:
+ return WRDE_NOSPACE;
+}
+
+/* The parse_*() functions should leave *offset being the offset in 'words'
+ * to the last character processed.
+ */
+static int
+parse_backslash(char **word, size_t * word_length, size_t * max_length,
+ const char *words, size_t * offset)
+{
+ /* We are poised _at_ a backslash, not in quotes */
+
+ switch (words[1 + *offset]) {
+ case 0:
+ /* Backslash is last character of input words */
+ return WRDE_SYNTAX;
+
+ case '\n':
+ ++(*offset);
+ break;
+
+ default:
+ *word = w_addchar(*word, word_length, max_length, words[1 + *offset]);
+ if (*word == NULL)
+ return WRDE_NOSPACE;
+
+ ++(*offset);
+ break;
+ }
+
+ return 0;
+}
+
+static int
+parse_qtd_backslash(char **word, size_t * word_length, size_t * max_length,
+ const char *words, size_t * offset)
+{
+ /* We are poised _at_ a backslash, inside quotes */
+
+ switch (words[1 + *offset]) {
+ case 0:
+ /* Backslash is last character of input words */
+ return WRDE_SYNTAX;
+
+ case '\n':
+ ++(*offset);
+ break;
+
+ case '$':
+ case '`':
+ case '"':
+ case '\\':
+ *word =
+ w_addchar(*word, word_length, max_length, words[1 + *offset]);
+ if (*word == NULL)
+ return WRDE_NOSPACE;
+
+ ++(*offset);
+ break;
+
+ default:
+ *word = w_addchar(*word, word_length, max_length, words[*offset]);
+ if (*word != NULL)
+ *word =
+ w_addchar(*word, word_length, max_length,
+ words[1 + *offset]);
+
+ if (*word == NULL)
+ return WRDE_NOSPACE;
+
+ ++(*offset);
+ break;
+ }
+
+ return 0;
+}
+
+static int
+parse_tilde(char **word, size_t * word_length, size_t * max_length,
+ const char *words, size_t * offset, size_t wordc)
+{
+ /* We are poised _at_ a tilde */
+ size_t i;
+
+ if (*word_length != 0) {
+ if (!((*word)[*word_length - 1] == '=' && wordc == 0)) {
+ if (!((*word)[*word_length - 1] == ':'
+ && strchr(*word, '=') && wordc == 0)) {
+ *word = w_addchar(*word, word_length, max_length, '~');
+ return *word ? 0 : WRDE_NOSPACE;
+ }
+ }
+ }
+
+ for (i = 1 + *offset; words[i]; i++) {
+ if (words[i] == ':' || words[i] == '/' || words[i] == ' ' ||
+ words[i] == '\t' || words[i] == 0)
+ break;
+
+ if (words[i] == '\\') {
+ *word = w_addchar(*word, word_length, max_length, '~');
+ return *word ? 0 : WRDE_NOSPACE;
+ }
+ }
+
+ if (i == 1 + *offset) {
+ /* Tilde appears on its own */
+ uid_t uid;
+ struct passwd pwd, *tpwd;
+ int buflen = 1000;
+ char *home;
+ char *buffer;
+ int result;
+
+ /* POSIX.2 says ~ expands to $HOME and if HOME is unset the
+ results are unspecified. We do a lookup on the uid if
+ HOME is unset. */
+
+ home = getenv("HOME");
+ if (home != NULL) {
+ *word = w_addstr(*word, word_length, max_length, home);
+ if (*word == NULL)
+ return WRDE_NOSPACE;
+ } else {
+ uid = getuid();
+ buffer = alloca(buflen);
+
+ while ((result = getpwuid_r(uid, &pwd, buffer, buflen, &tpwd))
+ != 0 && errno == ERANGE)
+ {
+ buflen += 1000;
+ buffer = alloca(buflen);
+ }
+
+ if (result == 0 && tpwd != NULL && pwd.pw_dir != NULL) {
+ *word = w_addstr(*word, word_length, max_length, pwd.pw_dir);
+ if (*word == NULL)
+ return WRDE_NOSPACE;
+ } else {
+ *word = w_addchar(*word, word_length, max_length, '~');
+ if (*word == NULL)
+ return WRDE_NOSPACE;
+ }
+ }
+ } else {
+ /* Look up user name in database to get home directory */
+ char *user = strndup(&words[1 + *offset], i - (1 + *offset));
+ struct passwd pwd, *tpwd;
+ int buflen = 1000;
+ char *buffer = alloca(buflen);
+ int result;
+
+ while ((result = getpwnam_r(user, &pwd, buffer, buflen, &tpwd)) != 0
+ && errno == ERANGE) {
+ buflen += 1000;
+ buffer = alloca(buflen);
+ }
+
+ if (result == 0 && tpwd != NULL && pwd.pw_dir)
+ *word = w_addstr(*word, word_length, max_length, pwd.pw_dir);
+ else {
+ /* (invalid login name) */
+ *word = w_addchar(*word, word_length, max_length, '~');
+ if (*word != NULL)
+ *word = w_addstr(*word, word_length, max_length, user);
+ }
+
+ *offset = i - 1;
+ }
+ return *word ? 0 : WRDE_NOSPACE;
+}
+
+
+static int
+do_parse_glob(const char *glob_word, char **word, size_t * word_length,
+ size_t * max_length, wordexp_t * pwordexp, const char *ifs
+ /*, const char *ifs_white*/)
+{
+ int error;
+ int match;
+ glob_t globbuf;
+
+ error = glob(glob_word, GLOB_NOCHECK, NULL, &globbuf);
+
+ if (error != 0) {
+ /* We can only run into memory problems. */
+ assert(error == GLOB_NOSPACE);
+ return WRDE_NOSPACE;
+ }
+
+ if (ifs && !*ifs) {
+ /* No field splitting allowed. */
+ assert(globbuf.gl_pathv[0] != NULL);
+ *word = w_addstr(*word, word_length, max_length, globbuf.gl_pathv[0]);
+ for (match = 1; match < globbuf.gl_pathc && *word != NULL; ++match) {
+ *word = w_addchar(*word, word_length, max_length, ' ');
+ if (*word != NULL)
+ *word = w_addstr(*word, word_length, max_length,
+ globbuf.gl_pathv[match]);
+ }
+
+ globfree(&globbuf);
+ return *word ? 0 : WRDE_NOSPACE;
+ }
+
+ assert(ifs == NULL || *ifs != '\0');
+ if (*word != NULL) {
+ free(*word);
+ *word = w_newword(word_length, max_length);
+ }
+
+ for (match = 0; match < globbuf.gl_pathc; ++match) {
+ char *matching_word = strdup(globbuf.gl_pathv[match]);
+
+ if (matching_word == NULL || w_addword(pwordexp, matching_word)) {
+ globfree(&globbuf);
+ return WRDE_NOSPACE;
+ }
+ }
+
+ globfree(&globbuf);
+ return 0;
+}
+
+static int
+parse_glob(char **word, size_t * word_length, size_t * max_length,
+ const char *words, size_t * offset, int flags,
+ wordexp_t * pwordexp, const char *ifs, const char *ifs_white)
+{
+ /* We are poised just after a '*', a '[' or a '?'. */
+ int error = WRDE_NOSPACE;
+ int quoted = 0; /* 1 if singly-quoted, 2 if doubly */
+ int i;
+ wordexp_t glob_list; /* List of words to glob */
+
+ glob_list.we_wordc = 0;
+ glob_list.we_wordv = NULL;
+ glob_list.we_offs = 0;
+ for (; words[*offset] != '\0'; ++*offset) {
+ if ((ifs && strchr(ifs, words[*offset])) ||
+ (!ifs && strchr(" \t\n", words[*offset])))
+ /* Reached IFS */
+ break;
+
+ /* Sort out quoting */
+ if (words[*offset] == '\'') {
+ if (quoted == 0) {
+ quoted = 1;
+ continue;
+ } else if (quoted == 1) {
+ quoted = 0;
+ continue;
+ }
+ } else if (words[*offset] == '"') {
+ if (quoted == 0) {
+ quoted = 2;
+ continue;
+ } else if (quoted == 2) {
+ quoted = 0;
+ continue;
+ }
+ }
+
+ /* Sort out other special characters */
+ if (quoted != 1 && words[*offset] == '$') {
+ error = parse_dollars(word, word_length, max_length, words,
+ offset, flags, &glob_list, ifs,
+ ifs_white, quoted == 2);
+ if (error)
+ goto tidy_up;
+
+ continue;
+ } else if (words[*offset] == '\\') {
+ if (quoted)
+ error = parse_qtd_backslash(word, word_length, max_length,
+ words, offset);
+ else
+ error = parse_backslash(word, word_length, max_length,
+ words, offset);
+
+ if (error)
+ goto tidy_up;
+
+ continue;
+ }
+
+ *word = w_addchar(*word, word_length, max_length, words[*offset]);
+ if (*word == NULL)
+ goto tidy_up;
+ }
+
+ /* Don't forget to re-parse the character we stopped at. */
+ --*offset;
+
+ /* Glob the words */
+ error = w_addword(&glob_list, *word);
+ *word = w_newword(word_length, max_length);
+ for (i = 0; error == 0 && i < glob_list.we_wordc; i++)
+ error = do_parse_glob(glob_list.we_wordv[i], word, word_length,
+ max_length, pwordexp, ifs /*, ifs_white*/);
+
+ /* Now tidy up */
+ tidy_up:
+ wordfree(&glob_list);
+ return error;
+}
+
+static int
+parse_squote(char **word, size_t * word_length, size_t * max_length,
+ const char *words, size_t * offset)
+{
+ /* We are poised just after a single quote */
+ for (; words[*offset]; ++(*offset)) {
+ if (words[*offset] != '\'') {
+ *word = w_addchar(*word, word_length, max_length, words[*offset]);
+ if (*word == NULL)
+ return WRDE_NOSPACE;
+ } else
+ return 0;
+ }
+
+ /* Unterminated string */
+ return WRDE_SYNTAX;
+}
+
+#ifdef __WORDEXP_FULL
+static int eval_expr(char *expr, long int *result);
+
+static char *_itoa(unsigned long long int value, char *buflim)
+{
+ sprintf(buflim, "%llu", value);
+ return buflim;
+}
+
+/* Functions to evaluate an arithmetic expression */
+static int eval_expr_val(char **expr, long int *result)
+{
+ int sgn = +1;
+ char *digit;
+
+ /* Skip white space */
+ for (digit = *expr; digit && *digit && isspace(*digit); ++digit);
+
+ switch (*digit) {
+ case '(':
+
+ /* Scan for closing paren */
+ for (++digit; **expr && **expr != ')'; ++(*expr));
+
+ /* Is there one? */
+ if (!**expr)
+ return WRDE_SYNTAX;
+
+ *(*expr)++ = 0;
+
+ if (eval_expr(digit, result))
+ return WRDE_SYNTAX;
+
+ return 0;
+
+ case '+': /* Positive value */
+ ++digit;
+ break;
+
+ case '-': /* Negative value */
+ ++digit;
+ sgn = -1;
+ break;
+
+ default:
+ if (!isdigit(*digit))
+ return WRDE_SYNTAX;
+ }
+
+ *result = 0;
+ for (; *digit && isdigit(*digit); ++digit)
+ *result = (*result * 10) + (*digit - '0');
+
+ *expr = digit;
+ *result *= sgn;
+ return 0;
+}
+
+static int eval_expr_multdiv(char **expr, long int *result)
+{
+ long int arg;
+
+ /* Read a Value */
+ if (eval_expr_val(expr, result) != 0)
+ return WRDE_SYNTAX;
+
+ while (**expr) {
+ /* Skip white space */
+ for (; *expr && **expr && isspace(**expr); ++(*expr));
+
+ if (**expr == '*') {
+ ++(*expr);
+ if (eval_expr_val(expr, &arg) != 0)
+ return WRDE_SYNTAX;
+
+ *result *= arg;
+ } else if (**expr == '/') {
+ ++(*expr);
+ if (eval_expr_val(expr, &arg) != 0)
+ return WRDE_SYNTAX;
+
+ *result /= arg;
+ } else
+ break;
+ }
+
+ return 0;
+}
+
+static int eval_expr(char *expr, long int *result)
+{
+ long int arg;
+
+ /* Read a Multdiv */
+ if (eval_expr_multdiv(&expr, result) != 0)
+ return WRDE_SYNTAX;
+
+ while (*expr) {
+ /* Skip white space */
+ for (; expr && *expr && isspace(*expr); ++expr);
+
+ if (*expr == '+') {
+ ++expr;
+ if (eval_expr_multdiv(&expr, &arg) != 0)
+ return WRDE_SYNTAX;
+
+ *result += arg;
+ } else if (*expr == '-') {
+ ++expr;
+ if (eval_expr_multdiv(&expr, &arg) != 0)
+ return WRDE_SYNTAX;
+
+ *result -= arg;
+ } else
+ break;
+ }
+
+ return 0;
+}
+
+static int
+parse_arith(char **word, size_t * word_length, size_t * max_length,
+ const char *words, size_t * offset, int flags, int bracket)
+{
+ /* We are poised just after "$((" or "$[" */
+ int error;
+ int paren_depth = 1;
+ size_t expr_length;
+ size_t expr_maxlen;
+ char *expr;
+
+ expr = w_newword(&expr_length, &expr_maxlen);
+ for (; words[*offset]; ++(*offset)) {
+ switch (words[*offset]) {
+ case '$':
+ error = parse_dollars(&expr, &expr_length, &expr_maxlen,
+ words, offset, flags, NULL, NULL, NULL,
+ 1);
+ /* The ``1'' here is to tell parse_dollars not to
+ * split the fields.
+ */
+ if (error) {
+ free(expr);
+ return error;
+ }
+ break;
+
+ case '`':
+ (*offset)++;
+ error = parse_backtick(&expr, &expr_length, &expr_maxlen,
+ words, offset, flags, NULL, NULL, NULL);
+ /* The first NULL here is to tell parse_backtick not to
+ * split the fields.
+ */
+ if (error) {
+ free(expr);
+ return error;
+ }
+ break;
+
+ case '\\':
+ error = parse_qtd_backslash(&expr, &expr_length, &expr_maxlen,
+ words, offset);
+ if (error) {
+ free(expr);
+ return error;
+ }
+ /* I think that a backslash within an
+ * arithmetic expansion is bound to
+ * cause an error sooner or later anyway though.
+ */
+ break;
+
+ case ')':
+ if (--paren_depth == 0) {
+ char result[21]; /* 21 = ceil(log10(2^64)) + 1 */
+ long int numresult = 0;
+ long long int convertme;
+
+ if (bracket || words[1 + *offset] != ')') {
+ free(expr);
+ return WRDE_SYNTAX;
+ }
+
+ ++(*offset);
+
+ /* Go - evaluate. */
+ if (*expr && eval_expr(expr, &numresult) != 0) {
+ free(expr);
+ return WRDE_SYNTAX;
+ }
+
+ if (numresult < 0) {
+ convertme = -numresult;
+ *word = w_addchar(*word, word_length, max_length, '-');
+ if (!*word) {
+ free(expr);
+ return WRDE_NOSPACE;
+ }
+ } else
+ convertme = numresult;
+
+ result[20] = '\0';
+ *word = w_addstr(*word, word_length, max_length,
+ _itoa(convertme, &result[20]));
+ free(expr);
+ return *word ? 0 : WRDE_NOSPACE;
+ }
+ expr =
+ w_addchar(expr, &expr_length, &expr_maxlen,
+ words[*offset]);
+ if (expr == NULL)
+ return WRDE_NOSPACE;
+
+ break;
+
+ case ']':
+ if (bracket && paren_depth == 1) {
+ char result[21]; /* 21 = ceil(log10(2^64)) + 1 */
+ long int numresult = 0;
+
+ /* Go - evaluate. */
+ if (*expr && eval_expr(expr, &numresult) != 0) {
+ free(expr);
+ return WRDE_SYNTAX;
+ }
+
+ result[20] = '\0';
+ *word = w_addstr(*word, word_length, max_length,
+ _itoa(numresult, &result[20]));
+ free(expr);
+ return *word ? 0 : WRDE_NOSPACE;
+ }
+
+ free(expr);
+ return WRDE_SYNTAX;
+
+ case '\n':
+ case ';':
+ case '{':
+ case '}':
+ free(expr);
+ return WRDE_BADCHAR;
+
+ case '(':
+ ++paren_depth;
+ default:
+ expr =
+ w_addchar(expr, &expr_length, &expr_maxlen,
+ words[*offset]);
+ if (expr == NULL)
+ return WRDE_NOSPACE;
+ }
+ }
+
+ /* Premature end */
+ free(expr);
+ return WRDE_SYNTAX;
+}
+
+/* Function called by child process in exec_comm() */
+static void attribute_noreturn
+exec_comm_child(char *comm, int *fildes, int showerr, int noexec)
+{
+ int fd;
+ const char *args[4] = { _PATH_BSHELL, "-c", comm, NULL };
+
+ /* Execute the command, or just check syntax? */
+ if (noexec)
+ args[1] = "-nc";
+
+ /* Redirect output. */
+ fd = fildes[1];
+ if (likely(fd != STDOUT_FILENO)) {
+ dup2(fd, STDOUT_FILENO);
+ close(fd);
+ }
+#if defined O_CLOEXEC && defined __UCLIBC_LINUX_SPECIFIC__ && defined __ASSUME_PIPE2
+ else {
+ /* Reset the close-on-exec flag (if necessary). */
+ fcntl (fd, F_SETFD, 0);
+ }
+#endif
+ /* Redirect stderr to /dev/null if we have to. */
+ if (showerr == 0) {
+ close(STDERR_FILENO);
+ fd = open(_PATH_DEVNULL, O_WRONLY);
+ if (fd >= 0 && fd != STDERR_FILENO) {
+ dup2(fd, 2);
+ close(fd);
+ }
+ }
+
+ /* Make sure the subshell doesn't field-split on our behalf. */
+ unsetenv("IFS");
+
+ if (fildes[0] != 1)
+ close(fildes[0]);
+ execve(_PATH_BSHELL, (char *const *) args, __environ);
+
+ /* Bad. What now? */
+ abort();
+}
+
+/* Function to execute a command and retrieve the results */
+/* pwordexp contains NULL if field-splitting is forbidden */
+static int
+exec_comm(char *comm, char **word, size_t * word_length,
+ size_t * max_length, int flags, wordexp_t * pwordexp,
+ const char *ifs, const char *ifs_white)
+{
+ int fildes[2];
+ int bufsize = 128;
+ int buflen;
+ int i;
+ int status = 0;
+ size_t maxnewlines = 0;
+ char *buffer;
+ pid_t pid;
+
+ /* Don't fork() unless necessary */
+ if (!comm || !*comm)
+ return 0;
+#if defined O_CLOEXEC && defined __UCLIBC_LINUX_SPECIFIC__ && defined __ASSUME_PIPE2
+ if (pipe2(fildes, O_CLOEXEC) < 0)
+ /* Bad */
+ return WRDE_NOSPACE;
+#else
+ if (pipe(fildes) < 0)
+ /* Bad */
+ return WRDE_NOSPACE;
+#endif
+
+ if ((pid = fork()) < 0) {
+ /* Bad */
+ close(fildes[0]);
+ close(fildes[1]);
+ return WRDE_NOSPACE;
+ }
+
+ if (pid == 0)
+ exec_comm_child(comm, fildes, (flags & WRDE_SHOWERR), 0);
+
+ /* Parent */
+
+ close(fildes[1]);
+ buffer = alloca(bufsize);
+
+ if (!pwordexp)
+ /* Quoted - no field splitting */
+ {
+ while (1) {
+ if ((buflen = read(fildes[0], buffer, bufsize)) < 1) {
+ if (waitpid(pid, &status, WNOHANG) == 0)
+ continue;
+ if ((buflen = read(fildes[0], buffer, bufsize)) < 1)
+ break;
+ }
+
+ maxnewlines += buflen;
+
+ *word = w_addmem(*word, word_length, max_length, buffer, buflen);
+ if (*word == NULL)
+ goto no_space;
+ }
+ } else
+ /* Not quoted - split fields */
+ {
+ int copying = 0;
+
+ /* 'copying' is:
+ * 0 when searching for first character in a field not IFS white space
+ * 1 when copying the text of a field
+ * 2 when searching for possible non-whitespace IFS
+ * 3 when searching for non-newline after copying field
+ */
+
+ while (1) {
+ if ((buflen = read(fildes[0], buffer, bufsize)) < 1) {
+ if (waitpid(pid, &status, WNOHANG) == 0)
+ continue;
+ if ((buflen = read(fildes[0], buffer, bufsize)) < 1)
+ break;
+ }
+
+ for (i = 0; i < buflen; ++i) {
+ if (strchr(ifs, buffer[i]) != NULL) {
+ /* Current character is IFS */
+ if (strchr(ifs_white, buffer[i]) == NULL) {
+ /* Current character is IFS but not whitespace */
+ if (copying == 2) {
+ /* current character
+ * |
+ * V
+ * eg: text<space><comma><space>moretext
+ *
+ * So, strip whitespace IFS (like at the start)
+ */
+ copying = 0;
+ continue;
+ }
+
+ copying = 0;
+ /* fall through and delimit field.. */
+ } else {
+ if (buffer[i] == '\n') {
+ /* Current character is (IFS) newline */
+
+ /* If copying a field, this is the end of it,
+ but maybe all that's left is trailing newlines.
+ So start searching for a non-newline. */
+ if (copying == 1)
+ copying = 3;
+
+ continue;
+ } else {
+ /* Current character is IFS white space, but
+ not a newline */
+
+ /* If not either copying a field or searching
+ for non-newline after a field, ignore it */
+ if (copying != 1 && copying != 3)
+ continue;
+
+ /* End of field (search for non-ws IFS afterwards) */
+ copying = 2;
+ }
+ }
+
+ /* First IFS white space (non-newline), or IFS non-whitespace.
+ * Delimit the field. Nulls are converted by w_addword. */
+ if (w_addword(pwordexp, *word) == WRDE_NOSPACE)
+ goto no_space;
+
+ *word = w_newword(word_length, max_length);
+
+ maxnewlines = 0;
+ /* fall back round the loop.. */
+ } else {
+ /* Not IFS character */
+
+ if (copying == 3) {
+ /* Nothing but (IFS) newlines since the last field,
+ so delimit it here before starting new word */
+ if (w_addword(pwordexp, *word) == WRDE_NOSPACE)
+ goto no_space;
+
+ *word = w_newword(word_length, max_length);
+ }
+
+ copying = 1;
+
+ if (buffer[i] == '\n') /* happens if newline not in IFS */
+ maxnewlines++;
+ else
+ maxnewlines = 0;
+
+ *word = w_addchar(*word, word_length, max_length,
+ buffer[i]);
+ if (*word == NULL)
+ goto no_space;
+ }
+ }
+ }
+ }
+
+ /* Chop off trailing newlines (required by POSIX.2) */
+ /* Ensure we don't go back further than the beginning of the
+ substitution (i.e. remove maxnewlines bytes at most) */
+ while (maxnewlines-- != 0 &&
+ *word_length > 0 && (*word)[*word_length - 1] == '\n') {
+ (*word)[--*word_length] = '\0';
+
+ /* If the last word was entirely newlines, turn it into a new word
+ * which can be ignored if there's nothing following it. */
+ if (*word_length == 0) {
+ free(*word);
+ *word = w_newword(word_length, max_length);
+ break;
+ }
+ }
+
+ close(fildes[0]);
+
+ /* Check for syntax error (re-execute but with "-n" flag) */
+ if (buflen < 1 && status != 0) {
+ if ((pid = fork()) < 0) {
+ /* Bad */
+ return WRDE_NOSPACE;
+ }
+
+ if (pid == 0) {
+ fildes[0] = fildes[1] = -1;
+ exec_comm_child(comm, fildes, 0, 1);
+ }
+
+ if (waitpid(pid, &status, 0) == pid && status != 0)
+ return WRDE_SYNTAX;
+ }
+
+ return 0;
+
+ no_space:
+ kill(pid, SIGKILL);
+ waitpid(pid, NULL, 0);
+ close(fildes[0]);
+ return WRDE_NOSPACE;
+}
+
+static int
+parse_comm(char **word, size_t * word_length, size_t * max_length,
+ const char *words, size_t * offset, int flags,
+ wordexp_t * pwordexp, const char *ifs, const char *ifs_white)
+{
+ /* We are poised just after "$(" */
+ int paren_depth = 1;
+ int error = 0;
+ int quoted = 0; /* 1 for singly-quoted, 2 for doubly-quoted */
+ size_t comm_length;
+ size_t comm_maxlen;
+ char *comm = w_newword(&comm_length, &comm_maxlen);
+
+ for (; words[*offset]; ++(*offset)) {
+ switch (words[*offset]) {
+ case '\'':
+ if (quoted == 0)
+ quoted = 1;
+ else if (quoted == 1)
+ quoted = 0;
+
+ break;
+
+ case '"':
+ if (quoted == 0)
+ quoted = 2;
+ else if (quoted == 2)
+ quoted = 0;
+
+ break;
+
+ case ')':
+ if (!quoted && --paren_depth == 0) {
+ /* Go -- give script to the shell */
+ if (comm) {
+ error = exec_comm(comm, word, word_length, max_length,
+ flags, pwordexp, ifs, ifs_white);
+ free(comm);
+ }
+
+ return error;
+ }
+
+ /* This is just part of the script */
+ break;
+
+ case '(':
+ if (!quoted)
+ ++paren_depth;
+ }
+
+ comm = w_addchar(comm, &comm_length, &comm_maxlen, words[*offset]);
+ if (comm == NULL)
+ return WRDE_NOSPACE;
+ }
+
+ /* Premature end */
+ free(comm);
+
+ return WRDE_SYNTAX;
+}
+
+static int
+parse_backtick(char **word, size_t * word_length, size_t * max_length,
+ const char *words, size_t * offset, int flags,
+ wordexp_t * pwordexp, const char *ifs,
+ const char *ifs_white)
+{
+ /* We are poised just after "`" */
+ int error;
+ int squoting = 0;
+ size_t comm_length;
+ size_t comm_maxlen;
+ char *comm = w_newword(&comm_length, &comm_maxlen);
+
+ for (; words[*offset]; ++(*offset)) {
+ switch (words[*offset]) {
+ case '`':
+ /* Go -- give the script to the shell */
+ error = exec_comm(comm, word, word_length, max_length, flags,
+ pwordexp, ifs, ifs_white);
+ free(comm);
+ return error;
+
+ case '\\':
+ if (squoting) {
+ error = parse_qtd_backslash(&comm, &comm_length, &comm_maxlen,
+ words, offset);
+
+ if (error) {
+ free(comm);
+ return error;
+ }
+
+ break;
+ }
+
+ ++(*offset);
+ error = parse_backslash(&comm, &comm_length, &comm_maxlen, words,
+ offset);
+
+ if (error) {
+ free(comm);
+ return error;
+ }
+
+ break;
+
+ case '\'':
+ squoting = 1 - squoting;
+ default:
+ comm = w_addchar(comm, &comm_length, &comm_maxlen,
+ words[*offset]);
+ if (comm == NULL)
+ return WRDE_NOSPACE;
+ }
+ }
+
+ /* Premature end */
+ free(comm);
+ return WRDE_SYNTAX;
+}
+
+static int
+parse_param(char **word, size_t * word_length, size_t * max_length,
+ const char *words, size_t * offset, int flags,
+ wordexp_t * pwordexp, const char *ifs, const char *ifs_white,
+ int quoted)
+{
+ /* We are poised just after "$" */
+ enum action {
+ ACT_NONE,
+ ACT_RP_SHORT_LEFT = '#',
+ ACT_RP_LONG_LEFT = 'L',
+ ACT_RP_SHORT_RIGHT = '%',
+ ACT_RP_LONG_RIGHT = 'R',
+ ACT_NULL_ERROR = '?',
+ ACT_NULL_SUBST = '-',
+ ACT_NONNULL_SUBST = '+',
+ ACT_NULL_ASSIGN = '='
+ };
+ size_t env_length;
+ size_t env_maxlen;
+ size_t pat_length;
+ size_t pat_maxlen;
+ size_t start = *offset;
+ char *env;
+ char *pattern;
+ char *value = NULL;
+ enum action action = ACT_NONE;
+ int depth = 0;
+ int colon_seen = 0;
+ int seen_hash = 0;
+ int free_value = 0;
+ int pattern_is_quoted = 0; /* 1 for singly-quoted, 2 for doubly-quoted */
+ int error;
+ int special = 0;
+ char buffer[21];
+ int brace = words[*offset] == '{';
+
+ env = w_newword(&env_length, &env_maxlen);
+ pattern = w_newword(&pat_length, &pat_maxlen);
+
+ if (brace)
+ ++ * offset;
+
+ /* First collect the parameter name. */
+
+ if (words[*offset] == '#') {
+ seen_hash = 1;
+ if (!brace)
+ goto envsubst;
+ ++*offset;
+ }
+
+ if (isalpha(words[*offset]) || words[*offset] == '_') {
+ /* Normal parameter name. */
+ do {
+ env = w_addchar(env, &env_length, &env_maxlen, words[*offset]);
+ if (env == NULL)
+ goto no_space;
+ }
+ while (isalnum(words[++*offset]) || words[*offset] == '_');
+ } else if (isdigit(words[*offset])) {
+ /* Numeric parameter name. */
+ special = 1;
+ do {
+ env = w_addchar(env, &env_length, &env_maxlen, words[*offset]);
+ if (env == NULL)
+ goto no_space;
+ if (!brace)
+ goto envsubst;
+ }
+ while (isdigit(words[++*offset]));
+ } else if (strchr("*@$", words[*offset]) != NULL) {
+ /* Special parameter. */
+ special = 1;
+ env = w_addchar(env, &env_length, &env_maxlen, words[*offset]);
+ if (env == NULL)
+ goto no_space;
+ ++*offset;
+ } else {
+ if (brace)
+ goto syntax;
+ }
+
+ if (brace) {
+ /* Check for special action to be applied to the value. */
+ switch (words[*offset]) {
+ case '}':
+ /* Evaluate. */
+ goto envsubst;
+
+ case '#':
+ action = ACT_RP_SHORT_LEFT;
+ if (words[1 + *offset] == '#') {
+ ++*offset;
+ action = ACT_RP_LONG_LEFT;
+ }
+ break;
+
+ case '%':
+ action = ACT_RP_SHORT_RIGHT;
+ if (words[1 + *offset] == '%') {
+ ++*offset;
+ action = ACT_RP_LONG_RIGHT;
+ }
+ break;
+
+ case ':':
+ if (strchr("-=?+", words[1 + *offset]) == NULL)
+ goto syntax;
+
+ colon_seen = 1;
+ action = words[++*offset];
+ break;
+
+ case '-':
+ case '=':
+ case '?':
+ case '+':
+ action = words[*offset];
+ break;
+
+ default:
+ goto syntax;
+ }
+
+ /* Now collect the pattern, but don't expand it yet. */
+ ++*offset;
+ for (; words[*offset]; ++(*offset)) {
+ switch (words[*offset]) {
+ case '{':
+ if (!pattern_is_quoted)
+ ++depth;
+ break;
+
+ case '}':
+ if (!pattern_is_quoted) {
+ if (depth == 0)
+ goto envsubst;
+ --depth;
+ }
+ break;
+
+ case '\\':
+ if (pattern_is_quoted)
+ /* Quoted; treat as normal character. */
+ break;
+
+ /* Otherwise, it's an escape: next character is literal. */
+ if (words[++*offset] == '\0')
+ goto syntax;
+
+ pattern = w_addchar(pattern, &pat_length, &pat_maxlen, '\\');
+ if (pattern == NULL)
+ goto no_space;
+
+ break;
+
+ case '\'':
+ if (pattern_is_quoted == 0)
+ pattern_is_quoted = 1;
+ else if (pattern_is_quoted == 1)
+ pattern_is_quoted = 0;
+
+ break;
+
+ case '"':
+ if (pattern_is_quoted == 0)
+ pattern_is_quoted = 2;
+ else if (pattern_is_quoted == 2)
+ pattern_is_quoted = 0;
+
+ break;
+ }
+
+ pattern = w_addchar(pattern, &pat_length, &pat_maxlen,
+ words[*offset]);
+ if (pattern == NULL)
+ goto no_space;
+ }
+ }
+
+ /* End of input string -- remember to reparse the character that we
+ * stopped at. */
+ --(*offset);
+
+ envsubst:
+ if (words[start] == '{' && words[*offset] != '}')
+ goto syntax;
+
+ if (env == NULL) {
+ if (seen_hash) {
+ /* $# expands to the number of positional parameters */
+ buffer[20] = '\0';
+ value = _itoa(__libc_argc - 1, &buffer[20]);
+ seen_hash = 0;
+ } else {
+ /* Just $ on its own */
+ *offset = start - 1;
+ *word = w_addchar(*word, word_length, max_length, '$');
+ return *word ? 0 : WRDE_NOSPACE;
+ }
+ }
+ /* Is it a numeric parameter? */
+ else if (isdigit(env[0])) {
+ int n = atoi(env);
+
+ if (n >= __libc_argc)
+ /* Substitute NULL. */
+ value = NULL;
+ else
+ /* Replace with appropriate positional parameter. */
+ value = __libc_argv[n];
+ }
+ /* Is it a special parameter? */
+ else if (special) {
+ /* Is it `$$'? */
+ if (*env == '$') {
+ buffer[20] = '\0';
+ value = _itoa(getpid(), &buffer[20]);
+ }
+ /* Is it `${#*}' or `${#@}'? */
+ else if ((*env == '*' || *env == '@') && seen_hash) {
+ buffer[20] = '\0';
+ value = _itoa(__libc_argc > 0 ? __libc_argc - 1 : 0,
+ &buffer[20]);
+ *word = w_addstr(*word, word_length, max_length, value);
+ free(env);
+ free(pattern);
+ return *word ? 0 : WRDE_NOSPACE;
+ }
+ /* Is it `$*' or `$@' (unquoted) ? */
+ else if (*env == '*' || (*env == '@' && !quoted)) {
+ size_t plist_len = 0;
+ int p;
+ char *end;
+
+ /* Build up value parameter by parameter (copy them) */
+ for (p = 1; __libc_argv[p]; ++p)
+ plist_len += strlen(__libc_argv[p]) + 1; /* for space */
+ value = malloc(plist_len);
+ if (value == NULL)
+ goto no_space;
+ end = value;
+ *end = 0;
+ for (p = 1; __libc_argv[p]; ++p) {
+ if (p > 1)
+ *end++ = ' ';
+ end = stpcpy(end, __libc_argv[p]);
+ }
+
+ free_value = 1;
+ } else {
+ /* Must be a quoted `$@' */
+ assert(*env == '@' && quoted);
+
+ /* Each parameter is a separate word ("$@") */
+ if (__libc_argc == 2)
+ value = __libc_argv[1];
+ else if (__libc_argc > 2) {
+ int p;
+
+ /* Append first parameter to current word. */
+ value = w_addstr(*word, word_length, max_length,
+ __libc_argv[1]);
+ if (value == NULL || w_addword(pwordexp, value))
+ goto no_space;
+
+ for (p = 2; __libc_argv[p + 1]; p++) {
+ char *newword = strdup(__libc_argv[p]);
+
+ if (newword == NULL || w_addword(pwordexp, newword))
+ goto no_space;
+ }
+
+ /* Start a new word with the last parameter. */
+ *word = w_newword(word_length, max_length);
+ value = __libc_argv[p];
+ } else {
+ free(env);
+ free(pattern);
+ return 0;
+ }
+ }
+ } else
+ value = getenv(env);
+
+ if (value == NULL && (flags & WRDE_UNDEF)) {
+ /* Variable not defined. */
+ error = WRDE_BADVAL;
+ goto do_error;
+ }
+
+ if (action != ACT_NONE) {
+ int expand_pattern = 0;
+
+ /* First, find out if we need to expand pattern (i.e. if we will
+ * use it). */
+ switch (action) {
+ case ACT_RP_SHORT_LEFT:
+ case ACT_RP_LONG_LEFT:
+ case ACT_RP_SHORT_RIGHT:
+ case ACT_RP_LONG_RIGHT:
+ /* Always expand for these. */
+ expand_pattern = 1;
+ break;
+
+ case ACT_NULL_ERROR:
+ case ACT_NULL_SUBST:
+ case ACT_NULL_ASSIGN:
+ if (!value || (!*value && colon_seen))
+ /* If param is unset, or set but null and a colon has been seen,
+ the expansion of the pattern will be needed. */
+ expand_pattern = 1;
+
+ break;
+
+ case ACT_NONNULL_SUBST:
+ /* Expansion of word will be needed if parameter is set and not null,
+ or set null but no colon has been seen. */
+ if (value && (*value || !colon_seen))
+ expand_pattern = 1;
+
+ break;
+
+ default:
+ assert(!"Unrecognised action!");
+ }
+
+ if (expand_pattern) {
+ /* We need to perform tilde expansion, parameter expansion,
+ command substitution, and arithmetic expansion. We also
+ have to be a bit careful with wildcard characters, as
+ pattern might be given to fnmatch soon. To do this, we
+ convert quotes to escapes. */
+
+ char *expanded;
+ size_t exp_len;
+ size_t exp_maxl;
+ char *p;
+ int quotes = 0; /* 1: single quotes; 2: double */
+
+ expanded = w_newword(&exp_len, &exp_maxl);
+ for (p = pattern; p && *p; p++) {
+ size_t _offset;
+
+ switch (*p) {
+ case '"':
+ if (quotes == 2)
+ quotes = 0;
+ else if (quotes == 0)
+ quotes = 2;
+ else
+ break;
+
+ continue;
+
+ case '\'':
+ if (quotes == 1)
+ quotes = 0;
+ else if (quotes == 0)
+ quotes = 1;
+ else
+ break;
+
+ continue;
+
+ case '*':
+ case '?':
+ if (quotes) {
+ /* Convert quoted wildchar to escaped wildchar. */
+ expanded = w_addchar(expanded, &exp_len,
+ &exp_maxl, '\\');
+
+ if (expanded == NULL)
+ goto no_space;
+ }
+ break;
+
+ case '$':
+ _offset = 0;
+ error = parse_dollars(&expanded, &exp_len, &exp_maxl, p,
+ &_offset, flags, NULL, NULL, NULL, 1);
+ if (error) {
+ if (free_value)
+ free(value);
+
+ free(expanded);
+
+ goto do_error;
+ }
+
+ p += _offset;
+ continue;
+
+ case '~':
+ if (quotes || exp_len)
+ break;
+
+ _offset = 0;
+ error = parse_tilde(&expanded, &exp_len, &exp_maxl, p,
+ &_offset, 0);
+ if (error) {
+ if (free_value)
+ free(value);
+
+ free(expanded);
+
+ goto do_error;
+ }
+
+ p += _offset;
+ continue;
+
+ case '\\':
+ expanded = w_addchar(expanded, &exp_len, &exp_maxl, '\\');
+ ++p;
+ assert(*p); /* checked when extracted initially */
+ if (expanded == NULL)
+ goto no_space;
+ }
+
+ expanded = w_addchar(expanded, &exp_len, &exp_maxl, *p);
+
+ if (expanded == NULL)
+ goto no_space;
+ }
+
+ free(pattern);
+
+ pattern = expanded;
+ }
+
+ switch (action) {
+ case ACT_RP_SHORT_LEFT:
+ case ACT_RP_LONG_LEFT:
+ case ACT_RP_SHORT_RIGHT:
+ case ACT_RP_LONG_RIGHT:
+ {
+ char *p;
+ char c;
+ char *end;
+
+ if (value == NULL || pattern == NULL || *pattern == '\0')
+ break;
+
+ end = value + strlen(value);
+
+ switch (action) {
+ case ACT_RP_SHORT_LEFT:
+ for (p = value; p <= end; ++p) {
+ c = *p;
+ *p = '\0';
+ if (fnmatch(pattern, value, 0) != FNM_NOMATCH) {
+ *p = c;
+ if (free_value) {
+ char *newval = strdup(p);
+
+ if (newval == NULL) {
+ free(value);
+ goto no_space;
+ }
+ free(value);
+ value = newval;
+ } else
+ value = p;
+ break;
+ }
+ *p = c;
+ }
+
+ break;
+
+ case ACT_RP_LONG_LEFT:
+ for (p = end; p >= value; --p) {
+ c = *p;
+ *p = '\0';
+ if (fnmatch(pattern, value, 0) != FNM_NOMATCH) {
+ *p = c;
+ if (free_value) {
+ char *newval = strdup(p);
+
+ if (newval == NULL) {
+ free(value);
+ goto no_space;
+ }
+ free(value);
+ value = newval;
+ } else
+ value = p;
+ break;
+ }
+ *p = c;
+ }
+
+ break;
+
+ case ACT_RP_SHORT_RIGHT:
+ for (p = end; p >= value; --p) {
+ if (fnmatch(pattern, p, 0) != FNM_NOMATCH) {
+ char *newval;
+
+ newval = malloc(p - value + 1);
+
+ if (newval == NULL) {
+ if (free_value)
+ free(value);
+ goto no_space;
+ }
+
+ *(char *) mempcpy(newval, value, p - value) = '\0';
+ if (free_value)
+ free(value);
+ value = newval;
+ free_value = 1;
+ break;
+ }
+ }
+
+ break;
+
+ case ACT_RP_LONG_RIGHT:
+ for (p = value; p <= end; ++p) {
+ if (fnmatch(pattern, p, 0) != FNM_NOMATCH) {
+ char *newval;
+
+ newval = malloc(p - value + 1);
+
+ if (newval == NULL) {
+ if (free_value)
+ free(value);
+ goto no_space;
+ }
+
+ *(char *) mempcpy(newval, value, p - value) = '\0';
+ if (free_value)
+ free(value);
+ value = newval;
+ free_value = 1;
+ break;
+ }
+ }
+
+ break;
+
+ default:
+ break;
+ }
+
+ break;
+ }
+
+ case ACT_NULL_ERROR:
+ if (value && *value)
+ /* Substitute parameter */
+ break;
+
+ error = 0;
+ if (!colon_seen && value)
+ /* Substitute NULL */
+ ;
+ else if (*pattern)
+ fprintf(stderr, "%s: %s\n", env, pattern);
+ else {
+ fprintf(stderr, "%s: parameter null or not set\n", env);
+ error = WRDE_BADVAL;
+ }
+
+ if (free_value)
+ free(value);
+ goto do_error;
+
+ case ACT_NULL_SUBST:
+ if (value && *value)
+ /* Substitute parameter */
+ break;
+
+ if (free_value)
+ free(value);
+
+ if (!colon_seen && value)
+ /* Substitute NULL */
+ goto success;
+
+ value = pattern ? strdup(pattern) : pattern;
+ free_value = 1;
+
+ if (pattern && !value)
+ goto no_space;
+
+ break;
+
+ case ACT_NONNULL_SUBST:
+ if (value && (*value || !colon_seen)) {
+ if (free_value)
+ free(value);
+
+ value = pattern ? strdup(pattern) : pattern;
+ free_value = 1;
+
+ if (pattern && !value)
+ goto no_space;
+
+ break;
+ }
+
+ /* Substitute NULL */
+ if (free_value)
+ free(value);
+ goto success;
+
+ case ACT_NULL_ASSIGN:
+ if (value && *value)
+ /* Substitute parameter */
+ break;
+
+ if (!colon_seen && value) {
+ /* Substitute NULL */
+ if (free_value)
+ free(value);
+ goto success;
+ }
+
+ if (free_value)
+ free(value);
+
+ value = pattern ? strdup(pattern) : pattern;
+ free_value = 1;
+
+ if (pattern && !value)
+ goto no_space;
+
+ setenv(env, value, 1);
+ break;
+
+ default:
+ assert(!"Unrecognised action!");
+ }
+ }
+
+ free(env);
+ env = NULL;
+ free(pattern);
+ pattern = NULL;
+
+ if (seen_hash) {
+ char param_length[21];
+
+ param_length[20] = '\0';
+ *word = w_addstr(*word, word_length, max_length,
+ _itoa(value ? strlen(value) : 0,
+ ¶m_length[20]));
+ if (free_value) {
+ assert(value != NULL);
+ free(value);
+ }
+
+ return *word ? 0 : WRDE_NOSPACE;
+ }
+
+ if (value == NULL)
+ return 0;
+
+ if (quoted || !pwordexp) {
+ /* Quoted - no field split */
+ *word = w_addstr(*word, word_length, max_length, value);
+ if (free_value)
+ free(value);
+
+ return *word ? 0 : WRDE_NOSPACE;
+ } else {
+ /* Need to field-split */
+ char *value_copy = strdup(value); /* Don't modify value */
+ char *field_begin = value_copy;
+ int seen_nonws_ifs = 0;
+
+ if (free_value)
+ free(value);
+
+ if (value_copy == NULL)
+ goto no_space;
+
+ do {
+ char *field_end = field_begin;
+ char *next_field;
+
+ /* If this isn't the first field, start a new word */
+ if (field_begin != value_copy) {
+ if (w_addword(pwordexp, *word) == WRDE_NOSPACE) {
+ free(value_copy);
+ goto no_space;
+ }
+
+ *word = w_newword(word_length, max_length);
+ }
+
+ /* Skip IFS whitespace before the field */
+ field_begin += strspn(field_begin, ifs_white);
+
+ if (!seen_nonws_ifs && *field_begin == 0)
+ /* Nothing but whitespace */
+ break;
+
+ /* Search for the end of the field */
+ field_end = field_begin + strcspn(field_begin, ifs);
+
+ /* Set up pointer to the character after end of field and
+ skip whitespace IFS after it. */
+ next_field = field_end + strspn(field_end, ifs_white);
+
+ /* Skip at most one non-whitespace IFS character after the field */
+ seen_nonws_ifs = 0;
+ if (*next_field && strchr(ifs, *next_field)) {
+ seen_nonws_ifs = 1;
+ next_field++;
+ }
+
+ /* Null-terminate it */
+ *field_end = 0;
+
+ /* Tag a copy onto the current word */
+ *word = w_addstr(*word, word_length, max_length, field_begin);
+
+ if (*word == NULL && *field_begin != '\0') {
+ free(value_copy);
+ goto no_space;
+ }
+
+ field_begin = next_field;
+ }
+ while (seen_nonws_ifs || *field_begin);
+
+ free(value_copy);
+ }
+
+ return 0;
+
+ success:
+ error = 0;
+ goto do_error;
+
+ no_space:
+ error = WRDE_NOSPACE;
+ goto do_error;
+
+ syntax:
+ error = WRDE_SYNTAX;
+
+ do_error:
+ free(env);
+
+ free(pattern);
+
+ return error;
+}
+#else
+static __inline__ int
+parse_backtick(char **word, size_t * word_length, size_t * max_length,
+ const char *words, size_t * offset, int flags,
+ wordexp_t * pwordexp, const char *ifs,
+ const char *ifs_white)
+{
+ return 0;
+}
+#endif
+
+static int
+parse_dollars(char **word, size_t * word_length, size_t * max_length,
+ const char *words, size_t * offset, int flags,
+ wordexp_t * pwordexp, const char *ifs, const char *ifs_white,
+ int quoted)
+{
+ /* We are poised _at_ "$" */
+ switch (words[1 + *offset]) {
+ case '"':
+ case '\'':
+ case 0:
+ *word = w_addchar(*word, word_length, max_length, '$');
+ return *word ? 0 : WRDE_NOSPACE;
+
+#ifdef __WORDEXP_FULL
+ case '(':
+ if (words[2 + *offset] == '(') {
+ /* Differentiate between $((1+3)) and $((echo);(ls)) */
+ int i = 3 + *offset;
+ int depth = 0;
+
+ while (words[i] && !(depth == 0 && words[i] == ')')) {
+ if (words[i] == '(')
+ ++depth;
+ else if (words[i] == ')')
+ --depth;
+
+ ++i;
+ }
+
+ if (words[i] == ')' && words[i + 1] == ')') {
+ (*offset) += 3;
+ /* Call parse_arith -- 0 is for "no brackets" */
+ return parse_arith(word, word_length, max_length, words,
+ offset, flags, 0);
+ }
+ }
+
+ 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);
+
+ case '[':
+ (*offset) += 2;
+ /* Call parse_arith -- 1 is for "brackets" */
+ return parse_arith(word, word_length, max_length, words, offset,
+ flags, 1);
+
+ case '{':
+ default:
+ ++(*offset); /* parse_param needs to know if "{" is there */
+ return parse_param(word, word_length, max_length, words, offset,
+ flags, pwordexp, ifs, ifs_white, quoted);
+#else
+ default:
+ ++(*offset); /* parse_param needs to know if "{" is there */
+ return 0;
+#endif
+ }
+}
+
+static int
+parse_dquote(char **word, size_t * word_length, size_t * max_length,
+ const char *words, size_t * offset, int flags,
+ wordexp_t * pwordexp, const char *ifs, const char *ifs_white)
+{
+ /* We are poised just after a double-quote */
+ int error;
+
+ for (; words[*offset]; ++(*offset)) {
+ switch (words[*offset]) {
+ case '"':
+ return 0;
+
+ case '$':
+ error = parse_dollars(word, word_length, max_length, words, offset,
+ flags, pwordexp, ifs, ifs_white, 1);
+ /* The ``1'' here is to tell parse_dollars not to
+ * split the fields. It may need to, however ("$@").
+ */
+ if (error)
+ return error;
+
+ break;
+
+ case '`':
+ if (flags & WRDE_NOCMD)
+ return WRDE_CMDSUB;
+
+ ++(*offset);
+ error = parse_backtick(word, word_length, max_length, words,
+ offset, flags, NULL, NULL, NULL);
+ /* The first NULL here is to tell parse_backtick not to
+ * split the fields.
+ */
+ if (error)
+ return error;
+
+ break;
+
+ case '\\':
+ error = parse_qtd_backslash(word, word_length, max_length, words,
+ offset);
+
+ if (error)
+ return error;
+
+ break;
+
+ default:
+ *word = w_addchar(*word, word_length, max_length, words[*offset]);
+ if (*word == NULL)
+ return WRDE_NOSPACE;
+ }
+ }
+
+ /* Unterminated string */
+ return WRDE_SYNTAX;
+}
+
+/*
+ * wordfree() is to be called after pwordexp is finished with.
+ */
+
+void wordfree(wordexp_t * pwordexp)
+{
+
+ /* wordexp can set pwordexp to NULL */
+ if (pwordexp && pwordexp->we_wordv) {
+ char **wordv = pwordexp->we_wordv;
+
+ for (wordv += pwordexp->we_offs; *wordv; ++wordv)
+ free(*wordv);
+
+ free(pwordexp->we_wordv);
+ pwordexp->we_wordv = NULL;
+ }
+}
+libc_hidden_def(wordfree)
+
+/*
+ * wordexp()
+ */
+
+int wordexp(const char *words, wordexp_t * we, int flags)
+{
+ size_t words_offset;
+ size_t word_length;
+ size_t max_length;
+ char *word = w_newword(&word_length, &max_length);
+ int error;
+ char *ifs;
+ char ifs_white[4];
+ wordexp_t old_word = *we;
+
+ if (flags & WRDE_REUSE) {
+ /* Minimal implementation of WRDE_REUSE for now */
+ wordfree(we);
+ old_word.we_wordv = NULL;
+ }
+
+ if ((flags & WRDE_APPEND) == 0) {
+ we->we_wordc = 0;
+
+ if (flags & WRDE_DOOFFS) {
+ we->we_wordv = calloc(1 + we->we_offs, sizeof(char *));
+ if (we->we_wordv == NULL) {
+ error = WRDE_NOSPACE;
+ goto do_error;
+ }
+ } else {
+ we->we_wordv = calloc(1, sizeof(char *));
+ if (we->we_wordv == NULL) {
+ error = WRDE_NOSPACE;
+ goto do_error;
+ }
+
+ we->we_offs = 0;
+ }
+ }
+
+ /* Find out what the field separators are.
+ * There are two types: whitespace and non-whitespace.
+ */
+ ifs = getenv("IFS");
+
+ if (!ifs)
+ /* IFS unset - use <space><tab><newline>. */
+ ifs = strcpy(ifs_white, " \t\n");
+ else {
+ char *ifsch = ifs;
+ char *whch = ifs_white;
+
+ /* Start off with no whitespace IFS characters */
+ ifs_white[0] = '\0';
+
+ while (*ifsch != '\0') {
+ if ((*ifsch == ' ') || (*ifsch == '\t') || (*ifsch == '\n')) {
+ /* Whitespace IFS. See first whether it is already in our
+ collection. */
+ char *runp = ifs_white;
+
+ while (runp < whch && *runp != '\0' && *runp != *ifsch)
+ ++runp;
+
+ if (runp == whch)
+ *whch++ = *ifsch;
+ }
+
+ ++ifsch;
+ }
+ *whch = '\0';
+ }
+
+ for (words_offset = 0; words[words_offset]; ++words_offset)
+ switch (words[words_offset]) {
+ case '\\':
+ error = parse_backslash(&word, &word_length, &max_length, words,
+ &words_offset);
+
+ if (error)
+ goto do_error;
+
+ break;
+
+ case '$':
+ error = parse_dollars(&word, &word_length, &max_length, words,
+ &words_offset, flags, we, ifs, ifs_white,
+ 0);
+
+ if (error)
+ goto do_error;
+
+ 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, we, ifs,
+ ifs_white);
+
+ if (error)
+ goto do_error;
+
+ break;
+
+ case '"':
+ ++words_offset;
+ error = parse_dquote(&word, &word_length, &max_length, words,
+ &words_offset, flags, we, ifs, ifs_white);
+
+ if (error)
+ goto do_error;
+
+ if (!word_length) {
+ error = w_addword(we, NULL);
+
+ if (error)
+ return error;
+ }
+
+ break;
+
+ case '\'':
+ ++words_offset;
+ error = parse_squote(&word, &word_length, &max_length, words,
+ &words_offset);
+
+ if (error)
+ goto do_error;
+
+ if (!word_length) {
+ error = w_addword(we, NULL);
+
+ if (error)
+ return error;
+ }
+
+ break;
+
+ case '~':
+ error = parse_tilde(&word, &word_length, &max_length, words,
+ &words_offset, we->we_wordc);
+
+ if (error)
+ goto do_error;
+
+ break;
+
+ case '*':
+ case '[':
+ case '?':
+ error = parse_glob(&word, &word_length, &max_length, words,
+ &words_offset, flags, we, ifs, ifs_white);
+
+ if (error)
+ goto do_error;
+
+ break;
+
+ default:
+ /* Is it a word separator? */
+ if (strchr(" \t", words[words_offset]) == NULL) {
+ char ch = words[words_offset];
+
+ /* Not a word separator -- but is it a valid word char? */
+ if (strchr("\n|&;<>(){}", ch)) {
+ /* Fail */
+ error = WRDE_BADCHAR;
+ goto do_error;
+ }
+
+ /* "Ordinary" character -- add it to word */
+ word = w_addchar(word, &word_length, &max_length, ch);
+ if (word == NULL) {
+ error = WRDE_NOSPACE;
+ goto do_error;
+ }
+
+ break;
+ }
+
+ /* If a word has been delimited, add it to the list. */
+ if (word != NULL) {
+ error = w_addword(we, word);
+ if (error)
+ goto do_error;
+ }
+
+ word = w_newword(&word_length, &max_length);
+ }
+
+ /* End of string */
+
+ /* There was a word separator at the end */
+ if (word == NULL) /* i.e. w_newword */
+ return 0;
+
+ /* There was no field separator at the end */
+ return w_addword(we, word);
+
+ do_error:
+ /* Error:
+ * free memory used (unless error is WRDE_NOSPACE), and
+ * set we members back to what they were.
+ */
+
+ free(word);
+
+ if (error == WRDE_NOSPACE)
+ return WRDE_NOSPACE;
+
+ if ((flags & WRDE_APPEND) == 0)
+ wordfree(we);
+
+ *we = old_word;
+ return error;
+}