From mboxrd@z Thu Jan 1 00:00:00 1970 Path: news.gmane.org!.POSTED!not-for-mail From: Paul Eggert Newsgroups: gmane.emacs.bugs Subject: bug#32194: [PATCH] Use Gnulib regex for lib-src Date: Tue, 17 Jul 2018 16:47:29 -0700 Message-ID: <20180717234729.15507-1-eggert@cs.ucla.edu> NNTP-Posting-Host: blaine.gmane.org Mime-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: quoted-printable X-Trace: blaine.gmane.org 1531871700 29841 195.159.176.226 (17 Jul 2018 23:55:00 GMT) X-Complaints-To: usenet@blaine.gmane.org NNTP-Posting-Date: Tue, 17 Jul 2018 23:55:00 +0000 (UTC) Cc: Paul Eggert To: 32194@debbugs.gnu.org Original-X-From: bug-gnu-emacs-bounces+geb-bug-gnu-emacs=m.gmane.org@gnu.org Wed Jul 18 01:51:59 2018 Return-path: Envelope-to: geb-bug-gnu-emacs@m.gmane.org Original-Received: from lists.gnu.org ([208.118.235.17]) by blaine.gmane.org with esmtp (Exim 4.84_2) (envelope-from ) id 1ffZl6-0004ay-EE for geb-bug-gnu-emacs@m.gmane.org; Wed, 18 Jul 2018 01:51:59 +0200 Original-Received: from localhost ([::1]:33985 helo=lists.gnu.org) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1ffZnD-0005Vl-9j for geb-bug-gnu-emacs@m.gmane.org; Tue, 17 Jul 2018 19:54:07 -0400 Original-Received: from eggs.gnu.org ([2001:4830:134:3::10]:34915) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1ffZm8-0005NL-JK for bug-gnu-emacs@gnu.org; Tue, 17 Jul 2018 19:53:54 -0400 Original-Received: from Debian-exim by eggs.gnu.org with spam-scanned (Exim 4.71) (envelope-from ) id 1ffZlD-0002gG-Kq for bug-gnu-emacs@gnu.org; Tue, 17 Jul 2018 19:53:00 -0400 Original-Received: from debbugs.gnu.org ([208.118.235.43]:40957) by eggs.gnu.org with esmtps (TLS1.0:RSA_AES_128_CBC_SHA1:16) (Exim 4.71) (envelope-from ) id 1ffZlC-0002g0-ST for bug-gnu-emacs@gnu.org; Tue, 17 Jul 2018 19:52:03 -0400 Original-Received: from Debian-debbugs by debbugs.gnu.org with local (Exim 4.84_2) (envelope-from ) id 1ffZlC-0004Hq-KJ for bug-gnu-emacs@gnu.org; Tue, 17 Jul 2018 19:52:02 -0400 X-Loop: help-debbugs@gnu.org Resent-From: Paul Eggert Original-Sender: "Debbugs-submit" Resent-CC: bug-gnu-emacs@gnu.org Resent-Date: Tue, 17 Jul 2018 23:52:02 +0000 Resent-Message-ID: Resent-Sender: help-debbugs@gnu.org X-GNU-PR-Message: report 32194 X-GNU-PR-Package: emacs X-GNU-PR-Keywords: patch X-Debbugs-Original-To: bug-gnu-emacs@gnu.org Original-Received: via spool by submit@debbugs.gnu.org id=B.153187146516409 (code B ref -1); Tue, 17 Jul 2018 23:52:02 +0000 Original-Received: (at submit) by debbugs.gnu.org; 17 Jul 2018 23:51:05 +0000 Original-Received: from localhost ([127.0.0.1]:45976 helo=debbugs.gnu.org) by debbugs.gnu.org with esmtp (Exim 4.84_2) (envelope-from ) id 1ffZkH-0004Gb-Nt for submit@debbugs.gnu.org; Tue, 17 Jul 2018 19:51:05 -0400 Original-Received: from eggs.gnu.org ([208.118.235.92]:43571) by debbugs.gnu.org with esmtp (Exim 4.84_2) (envelope-from ) id 1ffZkG-0004G7-8Q for submit@debbugs.gnu.org; Tue, 17 Jul 2018 19:51:04 -0400 Original-Received: from Debian-exim by eggs.gnu.org with spam-scanned (Exim 4.71) (envelope-from ) id 1ffZjF-0001KV-R4 for submit@debbugs.gnu.org; Tue, 17 Jul 2018 19:50:59 -0400 Original-Received: from lists.gnu.org ([2001:4830:134:3::11]:53736) by eggs.gnu.org with esmtps (TLS1.0:RSA_AES_256_CBC_SHA1:32) (Exim 4.71) (envelope-from ) id 1ffZjF-0001KJ-Ae for submit@debbugs.gnu.org; Tue, 17 Jul 2018 19:50:01 -0400 Original-Received: from eggs.gnu.org ([2001:4830:134:3::10]:34295) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1ffZiN-0004Ws-JC for bug-gnu-emacs@gnu.org; Tue, 17 Jul 2018 19:50:00 -0400 Original-Received: from Debian-exim by eggs.gnu.org with spam-scanned (Exim 4.71) (envelope-from ) id 1ffZhU-0000K8-4P for bug-gnu-emacs@gnu.org; Tue, 17 Jul 2018 19:49:07 -0400 Original-Received: from zimbra.cs.ucla.edu ([131.179.128.68]:50826) by eggs.gnu.org with esmtps (TLS1.0:DHE_RSA_AES_256_CBC_SHA1:32) (Exim 4.71) (envelope-from ) id 1ffZhR-0000J4-Sa for bug-gnu-emacs@gnu.org; Tue, 17 Jul 2018 19:48:12 -0400 Original-Received: from localhost (localhost [127.0.0.1]) by zimbra.cs.ucla.edu (Postfix) with ESMTP id D7CC0160844 for ; Tue, 17 Jul 2018 16:48:08 -0700 (PDT) Original-Received: from zimbra.cs.ucla.edu ([127.0.0.1]) by localhost (zimbra.cs.ucla.edu [127.0.0.1]) (amavisd-new, port 10032) with ESMTP id KyotSLX2Bi4y; Tue, 17 Jul 2018 16:47:39 -0700 (PDT) Original-Received: from localhost (localhost [127.0.0.1]) by zimbra.cs.ucla.edu (Postfix) with ESMTP id 4FFA9160825; Tue, 17 Jul 2018 16:47:39 -0700 (PDT) X-Virus-Scanned: amavisd-new at zimbra.cs.ucla.edu Original-Received: from zimbra.cs.ucla.edu ([127.0.0.1]) by localhost (zimbra.cs.ucla.edu [127.0.0.1]) (amavisd-new, port 10026) with ESMTP id t3L4O-SQWA_5; Tue, 17 Jul 2018 16:47:38 -0700 (PDT) Original-Received: from Penguin.CS.UCLA.EDU (Penguin.CS.UCLA.EDU [131.179.64.200]) by zimbra.cs.ucla.edu (Postfix) with ESMTPSA id E64D31605B7; Tue, 17 Jul 2018 16:47:37 -0700 (PDT) X-Mailer: git-send-email 2.17.1 X-detected-operating-system: by eggs.gnu.org: GNU/Linux 3.x [fuzzy] X-detected-operating-system: by eggs.gnu.org: GNU/Linux 2.6.x X-BeenThere: debbugs-submit@debbugs.gnu.org X-Mailman-Version: 2.1.18 Precedence: list X-detected-operating-system: by eggs.gnu.org: GNU/Linux 2.2.x-3.x [generic] X-Received-From: 208.118.235.43 X-BeenThere: bug-gnu-emacs@gnu.org List-Id: "Bug reports for GNU Emacs, the Swiss army knife of text editors" List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: bug-gnu-emacs-bounces+geb-bug-gnu-emacs=m.gmane.org@gnu.org Original-Sender: "bug-gnu-emacs" Xref: news.gmane.org gmane.emacs.bugs:148624 Archived-At: Emacs regular expressions forked from everyone else long ago. This makes it official and should allow simplification later. etags.c now uses the glibc regex API, falling back on a Gnulib-supplied substitute lib/regex.c if necessary. Emacs proper now uses its own regular expression module. Although this patch may look dauntingly large, most of it was generated automatically by admin/merge-gnulib and contains an exact copy of the glibc regex source, and the by-hand changes do not grow the Emacs source code. * .gitignore: Add .h files that the Gnulib regex code might generate. * admin/merge-gnulib (GNULIB_MODULES): Add regex. (AVOIDED_MODULES): Add 'lock'. Do not remove m4/wint_t.m4, since Gnulib regex uses it. * configure.ac (gt_TYPE_WINT_T, HAVE_LANGINFO_CODESET): Remove. * lib-src/Makefile.in (regex.o): Remove; Gnulib does this for us now. (etags_deps, etags_libs): Remove regex.o. * lib-src/etags.c (add_regex): Use unsigned char translation array, since glibc regex requires that. * lib/Makefile.in (not_emacs_OBJECTS, for_emacs_OBJECTS): New macros. (libegnu_a_OBJECTS): Use them, to avoid building e-regex.o. * lib/gnulib.mk.in, m4/gnulib-comp.m4: Regenerate. * lib/btowc.c, lib/hard-locale.c, lib/hard-locale.h, lib/langinfo.in.h: * lib/localcharset.c, lib/localcharset.h, lib/locale.in.h: * lib/localeconv.c, lib/mbrtowc.c, lib/mbsinit.c, lib/mbtowc-impl.h: * lib/mbtowc.c, lib/nl_langinfo.c, lib/regcomp.c, lib/regex.c: * lib/regex.h, lib/regex_internal.c, lib/regex_internal.h: * lib/regexec.c, lib/streq.h, lib/wchar.in.h, lib/wcrtomb.c: * lib/wctype-h.c, lib/wctype.in.h: * m4/btowc.m4, m4/builtin-expect.m4, m4/codeset.m4: * m4/eealloc.m4, m4/glibc21.m4: * m4/langinfo_h.m4, m4/localcharset.m4, m4/locale-fr.m4: * m4/locale-ja.m4, m4/locale-zh.m4, m4/locale_h.m4: * m4/localeconv.m4, m4/mbrtowc.m4, m4/mbsinit.m4: * m4/mbstate_t.m4, m4/mbtowc.m4, m4/nl_langinfo.m4: * m4/regex.m4, m4/wchar_h.m4, m4/wcrtomb.m4, m4/wctype_h.m4: * m4/wint_t.m4: New files, copied from Gnulib. * src/regex-emacs.c, src/regex-emacs.h: Rename from src/regex.c and src/regex.h, to avoid confusion with lib/regex.c. All references changed. * src/regex-emacs.h, src/conf_post.h: (RE_TRANSLATE_TYPE, RE_TRANSLATE, RE_TRANSLATE_P): Move from src/conf_post.h to src/regex-emacs.h, so that they don=E2=80=99t interfere with compiling lib/regex.c. * test/src/regex-emacs-tests.el: Rename from test/src/regex-tests.el, for consistency. --- .gitignore | 4 + admin/MAINTAINERS | 2 +- admin/find-gc.el | 2 +- admin/merge-gnulib | 6 +- configure.ac | 16 - etc/NEWS | 7 + lib-src/Makefile.in | 8 +- lib-src/etags.c | 2 +- lib/Makefile.in | 8 +- lib/btowc.c | 39 + lib/gnulib.mk.in | 549 +++ lib/hard-locale.c | 72 + lib/hard-locale.h | 25 + lib/langinfo.in.h | 222 + lib/localcharset.c | 996 ++++ lib/localcharset.h | 134 + lib/locale.in.h | 219 + lib/localeconv.c | 103 + lib/mbrtowc.c | 458 ++ lib/mbsinit.c | 73 + lib/mbtowc-impl.h | 44 + lib/mbtowc.c | 26 + lib/nl_langinfo.c | 366 ++ lib/regcomp.c | 3944 +++++++++++++++ lib/regex.c | 81 + lib/regex.h | 658 +++ lib/regex_internal.c | 1740 +++++++ lib/regex_internal.h | 911 ++++ lib/regexec.c | 4324 +++++++++++++++++ lib/streq.h | 176 + lib/wchar.in.h | 1072 ++++ lib/wcrtomb.c | 53 + lib/wctype-h.c | 4 + lib/wctype.in.h | 533 ++ lisp/char-fold.el | 2 +- m4/btowc.m4 | 120 + m4/builtin-expect.m4 | 49 + m4/codeset.m4 | 24 + m4/eealloc.m4 | 31 + m4/glibc21.m4 | 34 + m4/gnulib-comp.m4 | 299 ++ m4/langinfo_h.m4 | 120 + m4/localcharset.m4 | 11 + m4/locale-fr.m4 | 257 + m4/locale-ja.m4 | 145 + m4/locale-zh.m4 | 139 + m4/locale_h.m4 | 122 + m4/localeconv.m4 | 22 + m4/mbrtowc.m4 | 672 +++ m4/mbsinit.m4 | 51 + m4/mbstate_t.m4 | 41 + m4/mbtowc.m4 | 19 + m4/nl_langinfo.m4 | 53 + m4/regex.m4 | 300 ++ m4/wchar_h.m4 | 240 + m4/wcrtomb.m4 | 114 + m4/wctype_h.m4 | 212 + m4/wint_t.m4 | 74 + src/Makefile.in | 2 +- src/casetab.c | 2 +- src/conf_post.h | 7 - src/deps.mk | 10 +- src/emacs.c | 8 +- src/{regex.c =3D> regex-emacs.c} | 54 +- src/{regex.h =3D> regex-emacs.h} | 15 +- src/search.c | 8 +- src/syntax.c | 6 +- src/thread.h | 2 +- .../{regex-tests.el =3D> regex-emacs-tests.el} | 6 +- 69 files changed, 20057 insertions(+), 91 deletions(-) create mode 100644 lib/btowc.c create mode 100644 lib/hard-locale.c create mode 100644 lib/hard-locale.h create mode 100644 lib/langinfo.in.h create mode 100644 lib/localcharset.c create mode 100644 lib/localcharset.h create mode 100644 lib/locale.in.h create mode 100644 lib/localeconv.c create mode 100644 lib/mbrtowc.c create mode 100644 lib/mbsinit.c create mode 100644 lib/mbtowc-impl.h create mode 100644 lib/mbtowc.c create mode 100644 lib/nl_langinfo.c create mode 100644 lib/regcomp.c create mode 100644 lib/regex.c create mode 100644 lib/regex.h create mode 100644 lib/regex_internal.c create mode 100644 lib/regex_internal.h create mode 100644 lib/regexec.c create mode 100644 lib/streq.h create mode 100644 lib/wchar.in.h create mode 100644 lib/wcrtomb.c create mode 100644 lib/wctype-h.c create mode 100644 lib/wctype.in.h create mode 100644 m4/btowc.m4 create mode 100644 m4/builtin-expect.m4 create mode 100644 m4/codeset.m4 create mode 100644 m4/eealloc.m4 create mode 100644 m4/glibc21.m4 create mode 100644 m4/langinfo_h.m4 create mode 100644 m4/localcharset.m4 create mode 100644 m4/locale-fr.m4 create mode 100644 m4/locale-ja.m4 create mode 100644 m4/locale-zh.m4 create mode 100644 m4/locale_h.m4 create mode 100644 m4/localeconv.m4 create mode 100644 m4/mbrtowc.m4 create mode 100644 m4/mbsinit.m4 create mode 100644 m4/mbstate_t.m4 create mode 100644 m4/mbtowc.m4 create mode 100644 m4/nl_langinfo.m4 create mode 100644 m4/regex.m4 create mode 100644 m4/wchar_h.m4 create mode 100644 m4/wcrtomb.m4 create mode 100644 m4/wctype_h.m4 create mode 100644 m4/wint_t.m4 rename src/{regex.c =3D> regex-emacs.c} (99%) rename src/{regex.h =3D> regex-emacs.h} (98%) rename test/src/{regex-tests.el =3D> regex-emacs-tests.el} (99%) diff --git a/.gitignore b/.gitignore index d3712b0d6c..2f94169e85 100644 --- a/.gitignore +++ b/.gitignore @@ -58,8 +58,10 @@ lib/fcntl.h lib/getopt.h lib/getopt-cdefs.h lib/inttypes.h +lib/langinfo.h lib/libgnu.a lib/limits.h +lib/locale.h lib/signal.h lib/std*.h !lib/std*.in.h @@ -68,6 +70,8 @@ lib/string.h lib/sys/ lib/time.h lib/unistd.h +lib/wchar.h +lib/wctype.h src/buildobj.h src/globals.h src/lisp.mk diff --git a/admin/MAINTAINERS b/admin/MAINTAINERS index 753a676e81..3ceff6585b 100644 --- a/admin/MAINTAINERS +++ b/admin/MAINTAINERS @@ -37,7 +37,7 @@ Kenichi Handa Mule =20 Stefan Monnier - src/regex.c + src/regex-emacs.c src/syntax.c src/keymap.c font-lock/jit-lock/syntax diff --git a/admin/find-gc.el b/admin/find-gc.el index fb564039c7..e8cc113650 100644 --- a/admin/find-gc.el +++ b/admin/find-gc.el @@ -57,7 +57,7 @@ find-gc-source-files "keymap.c" "sysdep.c" "buffer.c" "filelock.c" "insdel.c" "marker.c" "minibuf.c" "fileio.c" "dired.c" "cmds.c" "casefiddle.c" - "indent.c" "search.c" "regex.c" "undo.c" + "indent.c" "search.c" "regex-emacs.c" "undo.c" "alloc.c" "data.c" "doc.c" "editfns.c" "callint.c" "eval.c" "fns.c" "print.c" "lread.c" "syntax.c" "unexcoff.c" diff --git a/admin/merge-gnulib b/admin/merge-gnulib index 39dfaee8f4..5814bd0ecf 100755 --- a/admin/merge-gnulib +++ b/admin/merge-gnulib @@ -37,7 +37,7 @@ GNULIB_MODULES=3D getloadavg getopt-gnu gettime gettimeofday gitlog-to-changelog ignore-value intprops largefile lstat manywarnings memrchr minmax mkostemp mktime nstrftime - pipe2 pselect pthread_sigmask putenv qcopy-acl readlink readlinkat + pipe2 pselect pthread_sigmask putenv qcopy-acl readlink readlinkat reg= ex sig2str socklen stat-time std-gnu11 stdalign stddef stdio stpcpy strtoimax symlink sys_stat sys_time tempname time time_r time_rz timegm timer-time timespec-add timespec-s= ub @@ -46,7 +46,7 @@ GNULIB_MODULES=3D ' =20 AVOIDED_MODULES=3D' - close dup fchdir fstat + close dup fchdir fstat lock malloc-posix msvc-inval msvc-nothrow openat-die opendir raise save-cwd select setenv sigprocmask stat stdarg stdbool @@ -107,7 +107,7 @@ avoided_flags=3D "$src"m4/gl-openssl.m4 \ "$src"m4/gnulib-cache.m4 "$src"m4/gnulib-tool.m4 \ "$src"m4/manywarnings-c++.m4 \ - "$src"m4/warn-on-use.m4 "$src"m4/wint_t.m4 && + "$src"m4/warn-on-use.m4 && cp -- "$gnulib_srcdir"/build-aux/texinfo.tex "$src"doc/misc && cp -- "$gnulib_srcdir"/build-aux/config.guess \ "$gnulib_srcdir"/build-aux/config.sub \ diff --git a/configure.ac b/configure.ac index b6918671e4..3bc843c5e3 100644 --- a/configure.ac +++ b/configure.ac @@ -807,10 +807,6 @@ AC_DEFUN AC_CHECK_FUNCS_ONCE([putenv]) AC_DEFUN([gl_FUNC_PUTENV], [test "$ac_cv_func_putenv" =3D yes || REPLACE_PUTENV=3D1]) -# Emacs does not use the wchar or wctype-h modules. -AC_DEFUN([gt_TYPE_WINT_T], - [GNULIB_OVERRIDES_WINT_T=3D0 - AC_SUBST([GNULIB_OVERRIDES_WINT_T])]) =20 # Initialize gnulib right after choosing the compiler. dnl Amongst other things, this sets AR and ARFLAGS. @@ -4358,18 +4354,6 @@ AC_DEFUN fi AC_SUBST(XGSELOBJ) =20 -dnl Adapted from Haible's version. -AC_CACHE_CHECK([for nl_langinfo and CODESET], emacs_cv_langinfo_codeset, - [AC_LINK_IFELSE([AC_LANG_PROGRAM([[#include ]], - [[char* cs =3D nl_langinfo(CODESET);]])], - emacs_cv_langinfo_codeset=3Dyes, - emacs_cv_langinfo_codeset=3Dno) - ]) -if test $emacs_cv_langinfo_codeset =3D yes; then - AC_DEFINE(HAVE_LANGINFO_CODESET, 1, - [Define if you have and nl_langinfo(CODESET).]) -fi - AC_TYPE_MBSTATE_T =20 dnl Fixme: AC_SYS_POSIX_TERMIOS should probably be used, but it's not cl= ear diff --git a/etc/NEWS b/etc/NEWS index c0f380614a..3d9c930198 100644 --- a/etc/NEWS +++ b/etc/NEWS @@ -31,6 +31,13 @@ functions 'json-serialize', 'json-insert', 'json-parse= -string', and 'json-parse-buffer' are typically much faster than their Lisp counterparts from json.el. =20 +** The etags program now uses the C library's regular expression matcher +when possible, and a compatible regex substitute otherwise. This will +let developers maintain Emacs's own regex code without having to also +support other programs. The new configure option '--without-included-re= gex' +forces etags to use the C library's regex matcher even if the regex +substitute ordinarily would be used to work around compatibility problem= s. + ** Emacs has been ported to the -fcheck-pointer-bounds option of GCC. This causes Emacs to check bounds of some arrays addressed by its internal pointers, which can be helpful when debugging the Emacs diff --git a/lib-src/Makefile.in b/lib-src/Makefile.in index fa37d8ed85..b2b901788a 100644 --- a/lib-src/Makefile.in +++ b/lib-src/Makefile.in @@ -361,13 +361,9 @@ TAGS: ../lib/libgnu.a: $(config_h) $(MAKE) -C ../lib all =20 -regex.o: $(srcdir)/../src/regex.c $(srcdir)/../src/regex.h $(config_h) - $(AM_V_CC)$(CC) -c $(CPP_CFLAGS) $< - - -etags_deps =3D ${srcdir}/etags.c regex.o $(NTLIB) $(config_h) +etags_deps =3D ${srcdir}/etags.c $(NTLIB) $(config_h) etags_cflags =3D -DEMACS_NAME=3D"\"GNU Emacs\"" -DVERSION=3D"\"${version= }\"" -o $@ -etags_libs =3D regex.o $(NTLIB) $(LOADLIBES) +etags_libs =3D $(NTLIB) $(LOADLIBES) =20 etags${EXEEXT}: ${etags_deps} $(AM_V_CCLD)$(CC) ${ALL_CFLAGS} $(etags_cflags) $< $(etags_libs) diff --git a/lib-src/etags.c b/lib-src/etags.c index b3b4575e0a..ee50670343 100644 --- a/lib-src/etags.c +++ b/lib-src/etags.c @@ -6401,7 +6401,7 @@ add_regex (char *regexp_pattern, language *lang) *patbuf =3D zeropattern; if (ignore_case) { - static char lc_trans[UCHAR_MAX + 1]; + static unsigned char lc_trans[UCHAR_MAX + 1]; int i; for (i =3D 0; i < UCHAR_MAX + 1; i++) lc_trans[i] =3D c_tolower (i); diff --git a/lib/Makefile.in b/lib/Makefile.in index 201f4b5383..b26db27423 100644 --- a/lib/Makefile.in +++ b/lib/Makefile.in @@ -79,9 +79,15 @@ ../config.status: Makefile: ../config.status $(srcdir)/Makefile.in $(MAKE) -C .. src/$@ =20 +# Object modules that need not be built for Emacs. +# Emacs does not need e-regex.o (it has its own regex-emacs.c), +# and building it would just waste time. +not_emacs_OBJECTS =3D regex.o + libgnu_a_OBJECTS =3D $(gl_LIBOBJS) \ $(patsubst %.c,%.o,$(filter %.c,$(libgnu_a_SOURCES))) -libegnu_a_OBJECTS =3D $(patsubst %.o,e-%.o,$(libgnu_a_OBJECTS)) +for_emacs_OBJECTS =3D $(filter-out $(not_emacs_OBJECTS),$(libgnu_a_OBJEC= TS)) +libegnu_a_OBJECTS =3D $(patsubst %.o,e-%.o,$(for_emacs_OBJECTS)) =20 $(libegnu_a_OBJECTS) $(libgnu_a_OBJECTS): $(BUILT_SOURCES) =20 diff --git a/lib/btowc.c b/lib/btowc.c new file mode 100644 index 0000000000..54124b28ac --- /dev/null +++ b/lib/btowc.c @@ -0,0 +1,39 @@ +/* Convert unibyte character to wide character. + Copyright (C) 2008, 2010-2018 Free Software Foundation, Inc. + Written by Bruno Haible , 2008. + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see = . */ + +#include + +/* Specification. */ +#include + +#include +#include + +wint_t +btowc (int c) +{ + if (c !=3D EOF) + { + char buf[1]; + wchar_t wc; + + buf[0] =3D c; + if (mbtowc (&wc, buf, 1) >=3D 0) + return wc; + } + return WEOF; +} diff --git a/lib/gnulib.mk.in b/lib/gnulib.mk.in index e623921091..5fe9317766 100644 --- a/lib/gnulib.mk.in +++ b/lib/gnulib.mk.in @@ -38,6 +38,7 @@ # --avoid=3Ddup \ # --avoid=3Dfchdir \ # --avoid=3Dfstat \ +# --avoid=3Dlock \ # --avoid=3Dmalloc-posix \ # --avoid=3Dmsvc-inval \ # --avoid=3Dmsvc-nothrow \ @@ -112,6 +113,7 @@ # qcopy-acl \ # readlink \ # readlinkat \ +# regex \ # sig2str \ # socklen \ # stat-time \ @@ -215,6 +217,7 @@ GETOPT_CDEFS_H =3D @GETOPT_CDEFS_H@ GETOPT_H =3D @GETOPT_H@ GFILENOTIFY_CFLAGS =3D @GFILENOTIFY_CFLAGS@ GFILENOTIFY_LIBS =3D @GFILENOTIFY_LIBS@ +GLIBC21 =3D @GLIBC21@ GL_COND_LIBTOOL =3D @GL_COND_LIBTOOL@ GL_GENERATE_ALLOCA_H =3D @GL_GENERATE_ALLOCA_H@ GL_GENERATE_BYTESWAP_H =3D @GL_GENERATE_BYTESWAP_H@ @@ -227,6 +230,7 @@ GL_GENERATE_STDINT_H =3D @GL_GENERATE_STDINT_H@ GMALLOC_OBJ =3D @GMALLOC_OBJ@ GNULIB_ALPHASORT =3D @GNULIB_ALPHASORT@ GNULIB_ATOLL =3D @GNULIB_ATOLL@ +GNULIB_BTOWC =3D @GNULIB_BTOWC@ GNULIB_CALLOC_POSIX =3D @GNULIB_CALLOC_POSIX@ GNULIB_CANONICALIZE_FILE_NAME =3D @GNULIB_CANONICALIZE_FILE_NAME@ GNULIB_CHDIR =3D @GNULIB_CHDIR@ @@ -239,6 +243,7 @@ GNULIB_DPRINTF =3D @GNULIB_DPRINTF@ GNULIB_DUP =3D @GNULIB_DUP@ GNULIB_DUP2 =3D @GNULIB_DUP2@ GNULIB_DUP3 =3D @GNULIB_DUP3@ +GNULIB_DUPLOCALE =3D @GNULIB_DUPLOCALE@ GNULIB_ENVIRON =3D @GNULIB_ENVIRON@ GNULIB_EUIDACCESS =3D @GNULIB_EUIDACCESS@ GNULIB_EXPLICIT_BZERO =3D @GNULIB_EXPLICIT_BZERO@ @@ -297,24 +302,32 @@ GNULIB_GROUP_MEMBER =3D @GNULIB_GROUP_MEMBER@ GNULIB_IMAXABS =3D @GNULIB_IMAXABS@ GNULIB_IMAXDIV =3D @GNULIB_IMAXDIV@ GNULIB_ISATTY =3D @GNULIB_ISATTY@ +GNULIB_ISWBLANK =3D @GNULIB_ISWBLANK@ +GNULIB_ISWCTYPE =3D @GNULIB_ISWCTYPE@ GNULIB_LCHMOD =3D @GNULIB_LCHMOD@ GNULIB_LCHOWN =3D @GNULIB_LCHOWN@ GNULIB_LINK =3D @GNULIB_LINK@ GNULIB_LINKAT =3D @GNULIB_LINKAT@ +GNULIB_LOCALECONV =3D @GNULIB_LOCALECONV@ GNULIB_LOCALTIME =3D @GNULIB_LOCALTIME@ GNULIB_LSEEK =3D @GNULIB_LSEEK@ GNULIB_LSTAT =3D @GNULIB_LSTAT@ GNULIB_MALLOC_POSIX =3D @GNULIB_MALLOC_POSIX@ +GNULIB_MBRLEN =3D @GNULIB_MBRLEN@ +GNULIB_MBRTOWC =3D @GNULIB_MBRTOWC@ GNULIB_MBSCASECMP =3D @GNULIB_MBSCASECMP@ GNULIB_MBSCASESTR =3D @GNULIB_MBSCASESTR@ GNULIB_MBSCHR =3D @GNULIB_MBSCHR@ GNULIB_MBSCSPN =3D @GNULIB_MBSCSPN@ +GNULIB_MBSINIT =3D @GNULIB_MBSINIT@ GNULIB_MBSLEN =3D @GNULIB_MBSLEN@ GNULIB_MBSNCASECMP =3D @GNULIB_MBSNCASECMP@ GNULIB_MBSNLEN =3D @GNULIB_MBSNLEN@ +GNULIB_MBSNRTOWCS =3D @GNULIB_MBSNRTOWCS@ GNULIB_MBSPBRK =3D @GNULIB_MBSPBRK@ GNULIB_MBSPCASECMP =3D @GNULIB_MBSPCASECMP@ GNULIB_MBSRCHR =3D @GNULIB_MBSRCHR@ +GNULIB_MBSRTOWCS =3D @GNULIB_MBSRTOWCS@ GNULIB_MBSSEP =3D @GNULIB_MBSSEP@ GNULIB_MBSSPN =3D @GNULIB_MBSSPN@ GNULIB_MBSSTR =3D @GNULIB_MBSSTR@ @@ -336,6 +349,7 @@ GNULIB_MKSTEMP =3D @GNULIB_MKSTEMP@ GNULIB_MKSTEMPS =3D @GNULIB_MKSTEMPS@ GNULIB_MKTIME =3D @GNULIB_MKTIME@ GNULIB_NANOSLEEP =3D @GNULIB_NANOSLEEP@ +GNULIB_NL_LANGINFO =3D @GNULIB_NL_LANGINFO@ GNULIB_NONBLOCKING =3D @GNULIB_NONBLOCKING@ GNULIB_OBSTACK_PRINTF =3D @GNULIB_OBSTACK_PRINTF@ GNULIB_OBSTACK_PRINTF_POSIX =3D @GNULIB_OBSTACK_PRINTF_POSIX@ @@ -386,6 +400,7 @@ GNULIB_SECURE_GETENV =3D @GNULIB_SECURE_GETENV@ GNULIB_SELECT =3D @GNULIB_SELECT@ GNULIB_SETENV =3D @GNULIB_SETENV@ GNULIB_SETHOSTNAME =3D @GNULIB_SETHOSTNAME@ +GNULIB_SETLOCALE =3D @GNULIB_SETLOCALE@ GNULIB_SIGACTION =3D @GNULIB_SIGACTION@ GNULIB_SIGNAL_H_SIGPIPE =3D @GNULIB_SIGNAL_H_SIGPIPE@ GNULIB_SIGPROCMASK =3D @GNULIB_SIGPROCMASK@ @@ -425,6 +440,7 @@ GNULIB_TIMEGM =3D @GNULIB_TIMEGM@ GNULIB_TIME_R =3D @GNULIB_TIME_R@ GNULIB_TIME_RZ =3D @GNULIB_TIME_RZ@ GNULIB_TMPFILE =3D @GNULIB_TMPFILE@ +GNULIB_TOWCTRANS =3D @GNULIB_TOWCTRANS@ GNULIB_TRUNCATE =3D @GNULIB_TRUNCATE@ GNULIB_TTYNAME_R =3D @GNULIB_TTYNAME_R@ GNULIB_TZSET =3D @GNULIB_TZSET@ @@ -447,7 +463,43 @@ GNULIB_VSCANF =3D @GNULIB_VSCANF@ GNULIB_VSNPRINTF =3D @GNULIB_VSNPRINTF@ GNULIB_VSPRINTF_POSIX =3D @GNULIB_VSPRINTF_POSIX@ GNULIB_WARN_CFLAGS =3D @GNULIB_WARN_CFLAGS@ +GNULIB_WCPCPY =3D @GNULIB_WCPCPY@ +GNULIB_WCPNCPY =3D @GNULIB_WCPNCPY@ +GNULIB_WCRTOMB =3D @GNULIB_WCRTOMB@ +GNULIB_WCSCASECMP =3D @GNULIB_WCSCASECMP@ +GNULIB_WCSCAT =3D @GNULIB_WCSCAT@ +GNULIB_WCSCHR =3D @GNULIB_WCSCHR@ +GNULIB_WCSCMP =3D @GNULIB_WCSCMP@ +GNULIB_WCSCOLL =3D @GNULIB_WCSCOLL@ +GNULIB_WCSCPY =3D @GNULIB_WCSCPY@ +GNULIB_WCSCSPN =3D @GNULIB_WCSCSPN@ +GNULIB_WCSDUP =3D @GNULIB_WCSDUP@ +GNULIB_WCSFTIME =3D @GNULIB_WCSFTIME@ +GNULIB_WCSLEN =3D @GNULIB_WCSLEN@ +GNULIB_WCSNCASECMP =3D @GNULIB_WCSNCASECMP@ +GNULIB_WCSNCAT =3D @GNULIB_WCSNCAT@ +GNULIB_WCSNCMP =3D @GNULIB_WCSNCMP@ +GNULIB_WCSNCPY =3D @GNULIB_WCSNCPY@ +GNULIB_WCSNLEN =3D @GNULIB_WCSNLEN@ +GNULIB_WCSNRTOMBS =3D @GNULIB_WCSNRTOMBS@ +GNULIB_WCSPBRK =3D @GNULIB_WCSPBRK@ +GNULIB_WCSRCHR =3D @GNULIB_WCSRCHR@ +GNULIB_WCSRTOMBS =3D @GNULIB_WCSRTOMBS@ +GNULIB_WCSSPN =3D @GNULIB_WCSSPN@ +GNULIB_WCSSTR =3D @GNULIB_WCSSTR@ +GNULIB_WCSTOK =3D @GNULIB_WCSTOK@ +GNULIB_WCSWIDTH =3D @GNULIB_WCSWIDTH@ +GNULIB_WCSXFRM =3D @GNULIB_WCSXFRM@ +GNULIB_WCTOB =3D @GNULIB_WCTOB@ GNULIB_WCTOMB =3D @GNULIB_WCTOMB@ +GNULIB_WCTRANS =3D @GNULIB_WCTRANS@ +GNULIB_WCTYPE =3D @GNULIB_WCTYPE@ +GNULIB_WCWIDTH =3D @GNULIB_WCWIDTH@ +GNULIB_WMEMCHR =3D @GNULIB_WMEMCHR@ +GNULIB_WMEMCMP =3D @GNULIB_WMEMCMP@ +GNULIB_WMEMCPY =3D @GNULIB_WMEMCPY@ +GNULIB_WMEMMOVE =3D @GNULIB_WMEMMOVE@ +GNULIB_WMEMSET =3D @GNULIB_WMEMSET@ GNULIB_WRITE =3D @GNULIB_WRITE@ GNULIB__EXIT =3D @GNULIB__EXIT@ GNUSTEP_CFLAGS =3D @GNUSTEP_CFLAGS@ @@ -463,10 +515,12 @@ GTK_OBJ =3D @GTK_OBJ@ GZIP_PROG =3D @GZIP_PROG@ HAVE_ALPHASORT =3D @HAVE_ALPHASORT@ HAVE_ATOLL =3D @HAVE_ATOLL@ +HAVE_BTOWC =3D @HAVE_BTOWC@ HAVE_C99_STDINT_H =3D @HAVE_C99_STDINT_H@ HAVE_CANONICALIZE_FILE_NAME =3D @HAVE_CANONICALIZE_FILE_NAME@ HAVE_CHOWN =3D @HAVE_CHOWN@ HAVE_CLOSEDIR =3D @HAVE_CLOSEDIR@ +HAVE_CRTDEFS_H =3D @HAVE_CRTDEFS_H@ HAVE_DECL_DIRFD =3D @HAVE_DECL_DIRFD@ HAVE_DECL_ENVIRON =3D @HAVE_DECL_ENVIRON@ HAVE_DECL_FCHDIR =3D @HAVE_DECL_FCHDIR@ @@ -506,10 +560,13 @@ HAVE_DECL_TRUNCATE =3D @HAVE_DECL_TRUNCATE@ HAVE_DECL_TTYNAME_R =3D @HAVE_DECL_TTYNAME_R@ HAVE_DECL_UNSETENV =3D @HAVE_DECL_UNSETENV@ HAVE_DECL_VSNPRINTF =3D @HAVE_DECL_VSNPRINTF@ +HAVE_DECL_WCTOB =3D @HAVE_DECL_WCTOB@ +HAVE_DECL_WCWIDTH =3D @HAVE_DECL_WCWIDTH@ HAVE_DIRENT_H =3D @HAVE_DIRENT_H@ HAVE_DPRINTF =3D @HAVE_DPRINTF@ HAVE_DUP2 =3D @HAVE_DUP2@ HAVE_DUP3 =3D @HAVE_DUP3@ +HAVE_DUPLOCALE =3D @HAVE_DUPLOCALE@ HAVE_EUIDACCESS =3D @HAVE_EUIDACCESS@ HAVE_EXPLICIT_BZERO =3D @HAVE_EXPLICIT_BZERO@ HAVE_FACCESSAT =3D @HAVE_FACCESSAT@ @@ -519,6 +576,7 @@ HAVE_FCHOWNAT =3D @HAVE_FCHOWNAT@ HAVE_FCNTL =3D @HAVE_FCNTL@ HAVE_FDATASYNC =3D @HAVE_FDATASYNC@ HAVE_FDOPENDIR =3D @HAVE_FDOPENDIR@ +HAVE_FEATURES_H =3D @HAVE_FEATURES_H@ HAVE_FFSL =3D @HAVE_FFSL@ HAVE_FFSLL =3D @HAVE_FFSLL@ HAVE_FSEEKO =3D @HAVE_FSEEKO@ @@ -539,6 +597,14 @@ HAVE_GRANTPT =3D @HAVE_GRANTPT@ HAVE_GROUP_MEMBER =3D @HAVE_GROUP_MEMBER@ HAVE_IMAXDIV_T =3D @HAVE_IMAXDIV_T@ HAVE_INTTYPES_H =3D @HAVE_INTTYPES_H@ +HAVE_ISWBLANK =3D @HAVE_ISWBLANK@ +HAVE_ISWCNTRL =3D @HAVE_ISWCNTRL@ +HAVE_LANGINFO_ALTMON =3D @HAVE_LANGINFO_ALTMON@ +HAVE_LANGINFO_CODESET =3D @HAVE_LANGINFO_CODESET@ +HAVE_LANGINFO_ERA =3D @HAVE_LANGINFO_ERA@ +HAVE_LANGINFO_H =3D @HAVE_LANGINFO_H@ +HAVE_LANGINFO_T_FMT_AMPM =3D @HAVE_LANGINFO_T_FMT_AMPM@ +HAVE_LANGINFO_YESEXPR =3D @HAVE_LANGINFO_YESEXPR@ HAVE_LCHMOD =3D @HAVE_LCHMOD@ HAVE_LCHOWN =3D @HAVE_LCHOWN@ HAVE_LINK =3D @HAVE_LINK@ @@ -547,7 +613,12 @@ HAVE_LONG_LONG_INT =3D @HAVE_LONG_LONG_INT@ HAVE_LSTAT =3D @HAVE_LSTAT@ HAVE_MAKEINFO =3D @HAVE_MAKEINFO@ HAVE_MAX_ALIGN_T =3D @HAVE_MAX_ALIGN_T@ +HAVE_MBRLEN =3D @HAVE_MBRLEN@ +HAVE_MBRTOWC =3D @HAVE_MBRTOWC@ +HAVE_MBSINIT =3D @HAVE_MBSINIT@ HAVE_MBSLEN =3D @HAVE_MBSLEN@ +HAVE_MBSNRTOWCS =3D @HAVE_MBSNRTOWCS@ +HAVE_MBSRTOWCS =3D @HAVE_MBSRTOWCS@ HAVE_MEMCHR =3D @HAVE_MEMCHR@ HAVE_MEMPCPY =3D @HAVE_MEMPCPY@ HAVE_MKDIRAT =3D @HAVE_MKDIRAT@ @@ -562,6 +633,7 @@ HAVE_MKSTEMP =3D @HAVE_MKSTEMP@ HAVE_MKSTEMPS =3D @HAVE_MKSTEMPS@ HAVE_MODULES =3D @HAVE_MODULES@ HAVE_NANOSLEEP =3D @HAVE_NANOSLEEP@ +HAVE_NL_LANGINFO =3D @HAVE_NL_LANGINFO@ HAVE_OPENAT =3D @HAVE_OPENAT@ HAVE_OPENDIR =3D @HAVE_OPENDIR@ HAVE_OS_H =3D @HAVE_OS_H@ @@ -642,7 +714,44 @@ HAVE_VASPRINTF =3D @HAVE_VASPRINTF@ HAVE_VDPRINTF =3D @HAVE_VDPRINTF@ HAVE_WCHAR_H =3D @HAVE_WCHAR_H@ HAVE_WCHAR_T =3D @HAVE_WCHAR_T@ +HAVE_WCPCPY =3D @HAVE_WCPCPY@ +HAVE_WCPNCPY =3D @HAVE_WCPNCPY@ +HAVE_WCRTOMB =3D @HAVE_WCRTOMB@ +HAVE_WCSCASECMP =3D @HAVE_WCSCASECMP@ +HAVE_WCSCAT =3D @HAVE_WCSCAT@ +HAVE_WCSCHR =3D @HAVE_WCSCHR@ +HAVE_WCSCMP =3D @HAVE_WCSCMP@ +HAVE_WCSCOLL =3D @HAVE_WCSCOLL@ +HAVE_WCSCPY =3D @HAVE_WCSCPY@ +HAVE_WCSCSPN =3D @HAVE_WCSCSPN@ +HAVE_WCSDUP =3D @HAVE_WCSDUP@ +HAVE_WCSFTIME =3D @HAVE_WCSFTIME@ +HAVE_WCSLEN =3D @HAVE_WCSLEN@ +HAVE_WCSNCASECMP =3D @HAVE_WCSNCASECMP@ +HAVE_WCSNCAT =3D @HAVE_WCSNCAT@ +HAVE_WCSNCMP =3D @HAVE_WCSNCMP@ +HAVE_WCSNCPY =3D @HAVE_WCSNCPY@ +HAVE_WCSNLEN =3D @HAVE_WCSNLEN@ +HAVE_WCSNRTOMBS =3D @HAVE_WCSNRTOMBS@ +HAVE_WCSPBRK =3D @HAVE_WCSPBRK@ +HAVE_WCSRCHR =3D @HAVE_WCSRCHR@ +HAVE_WCSRTOMBS =3D @HAVE_WCSRTOMBS@ +HAVE_WCSSPN =3D @HAVE_WCSSPN@ +HAVE_WCSSTR =3D @HAVE_WCSSTR@ +HAVE_WCSTOK =3D @HAVE_WCSTOK@ +HAVE_WCSWIDTH =3D @HAVE_WCSWIDTH@ +HAVE_WCSXFRM =3D @HAVE_WCSXFRM@ +HAVE_WCTRANS_T =3D @HAVE_WCTRANS_T@ +HAVE_WCTYPE_H =3D @HAVE_WCTYPE_H@ +HAVE_WCTYPE_T =3D @HAVE_WCTYPE_T@ HAVE_WINSOCK2_H =3D @HAVE_WINSOCK2_H@ +HAVE_WINT_T =3D @HAVE_WINT_T@ +HAVE_WMEMCHR =3D @HAVE_WMEMCHR@ +HAVE_WMEMCMP =3D @HAVE_WMEMCMP@ +HAVE_WMEMCPY =3D @HAVE_WMEMCPY@ +HAVE_WMEMMOVE =3D @HAVE_WMEMMOVE@ +HAVE_WMEMSET =3D @HAVE_WMEMSET@ +HAVE_XLOCALE_H =3D @HAVE_XLOCALE_H@ HAVE_XSERVER =3D @HAVE_XSERVER@ HAVE__EXIT =3D @HAVE__EXIT@ HYBRID_MALLOC =3D @HYBRID_MALLOC@ @@ -719,6 +828,11 @@ LIB_TIMER_TIME =3D @LIB_TIMER_TIME@ LIB_WSOCK32 =3D @LIB_WSOCK32@ LIMITS_H =3D @LIMITS_H@ LN_S_FILEONLY =3D @LN_S_FILEONLY@ +LOCALCHARSET_TESTS_ENVIRONMENT =3D @LOCALCHARSET_TESTS_ENVIRONMENT@ +LOCALE_FR =3D @LOCALE_FR@ +LOCALE_FR_UTF8 =3D @LOCALE_FR_UTF8@ +LOCALE_JA =3D @LOCALE_JA@ +LOCALE_ZH_CN =3D @LOCALE_ZH_CN@ LTLIBINTL =3D @LTLIBINTL@ LTLIBOBJS =3D @LTLIBOBJS@ M17N_FLT_CFLAGS =3D @M17N_FLT_CFLAGS@ @@ -733,7 +847,9 @@ NEXT_AS_FIRST_DIRECTIVE_ERRNO_H =3D @NEXT_AS_FIRST_DI= RECTIVE_ERRNO_H@ NEXT_AS_FIRST_DIRECTIVE_FCNTL_H =3D @NEXT_AS_FIRST_DIRECTIVE_FCNTL_H@ NEXT_AS_FIRST_DIRECTIVE_GETOPT_H =3D @NEXT_AS_FIRST_DIRECTIVE_GETOPT_H@ NEXT_AS_FIRST_DIRECTIVE_INTTYPES_H =3D @NEXT_AS_FIRST_DIRECTIVE_INTTYPES= _H@ +NEXT_AS_FIRST_DIRECTIVE_LANGINFO_H =3D @NEXT_AS_FIRST_DIRECTIVE_LANGINFO= _H@ NEXT_AS_FIRST_DIRECTIVE_LIMITS_H =3D @NEXT_AS_FIRST_DIRECTIVE_LIMITS_H@ +NEXT_AS_FIRST_DIRECTIVE_LOCALE_H =3D @NEXT_AS_FIRST_DIRECTIVE_LOCALE_H@ NEXT_AS_FIRST_DIRECTIVE_SIGNAL_H =3D @NEXT_AS_FIRST_DIRECTIVE_SIGNAL_H@ NEXT_AS_FIRST_DIRECTIVE_STDDEF_H =3D @NEXT_AS_FIRST_DIRECTIVE_STDDEF_H@ NEXT_AS_FIRST_DIRECTIVE_STDINT_H =3D @NEXT_AS_FIRST_DIRECTIVE_STDINT_H@ @@ -746,12 +862,16 @@ NEXT_AS_FIRST_DIRECTIVE_SYS_TIME_H =3D @NEXT_AS_FIR= ST_DIRECTIVE_SYS_TIME_H@ NEXT_AS_FIRST_DIRECTIVE_SYS_TYPES_H =3D @NEXT_AS_FIRST_DIRECTIVE_SYS_TYP= ES_H@ NEXT_AS_FIRST_DIRECTIVE_TIME_H =3D @NEXT_AS_FIRST_DIRECTIVE_TIME_H@ NEXT_AS_FIRST_DIRECTIVE_UNISTD_H =3D @NEXT_AS_FIRST_DIRECTIVE_UNISTD_H@ +NEXT_AS_FIRST_DIRECTIVE_WCHAR_H =3D @NEXT_AS_FIRST_DIRECTIVE_WCHAR_H@ +NEXT_AS_FIRST_DIRECTIVE_WCTYPE_H =3D @NEXT_AS_FIRST_DIRECTIVE_WCTYPE_H@ NEXT_DIRENT_H =3D @NEXT_DIRENT_H@ NEXT_ERRNO_H =3D @NEXT_ERRNO_H@ NEXT_FCNTL_H =3D @NEXT_FCNTL_H@ NEXT_GETOPT_H =3D @NEXT_GETOPT_H@ NEXT_INTTYPES_H =3D @NEXT_INTTYPES_H@ +NEXT_LANGINFO_H =3D @NEXT_LANGINFO_H@ NEXT_LIMITS_H =3D @NEXT_LIMITS_H@ +NEXT_LOCALE_H =3D @NEXT_LOCALE_H@ NEXT_SIGNAL_H =3D @NEXT_SIGNAL_H@ NEXT_STDDEF_H =3D @NEXT_STDDEF_H@ NEXT_STDINT_H =3D @NEXT_STDINT_H@ @@ -764,6 +884,8 @@ NEXT_SYS_TIME_H =3D @NEXT_SYS_TIME_H@ NEXT_SYS_TYPES_H =3D @NEXT_SYS_TYPES_H@ NEXT_TIME_H =3D @NEXT_TIME_H@ NEXT_UNISTD_H =3D @NEXT_UNISTD_H@ +NEXT_WCHAR_H =3D @NEXT_WCHAR_H@ +NEXT_WCTYPE_H =3D @NEXT_WCTYPE_H@ NOTIFY_CFLAGS =3D @NOTIFY_CFLAGS@ NOTIFY_LIBS =3D @NOTIFY_LIBS@ NOTIFY_OBJ =3D @NOTIFY_OBJ@ @@ -801,6 +923,7 @@ PTHREAD_H_DEFINES_STRUCT_TIMESPEC =3D @PTHREAD_H_DEFI= NES_STRUCT_TIMESPEC@ PTRDIFF_T_SUFFIX =3D @PTRDIFF_T_SUFFIX@ RALLOC_OBJ =3D @RALLOC_OBJ@ RANLIB =3D @RANLIB@ +REPLACE_BTOWC =3D @REPLACE_BTOWC@ REPLACE_CALLOC =3D @REPLACE_CALLOC@ REPLACE_CANONICALIZE_FILE_NAME =3D @REPLACE_CANONICALIZE_FILE_NAME@ REPLACE_CHOWN =3D @REPLACE_CHOWN@ @@ -811,6 +934,7 @@ REPLACE_DIRFD =3D @REPLACE_DIRFD@ REPLACE_DPRINTF =3D @REPLACE_DPRINTF@ REPLACE_DUP =3D @REPLACE_DUP@ REPLACE_DUP2 =3D @REPLACE_DUP2@ +REPLACE_DUPLOCALE =3D @REPLACE_DUPLOCALE@ REPLACE_FACCESSAT =3D @REPLACE_FACCESSAT@ REPLACE_FCHOWNAT =3D @REPLACE_FCHOWNAT@ REPLACE_FCLOSE =3D @REPLACE_FCLOSE@ @@ -841,14 +965,23 @@ REPLACE_GETPAGESIZE =3D @REPLACE_GETPAGESIZE@ REPLACE_GETTIMEOFDAY =3D @REPLACE_GETTIMEOFDAY@ REPLACE_GMTIME =3D @REPLACE_GMTIME@ REPLACE_ISATTY =3D @REPLACE_ISATTY@ +REPLACE_ISWBLANK =3D @REPLACE_ISWBLANK@ +REPLACE_ISWCNTRL =3D @REPLACE_ISWCNTRL@ REPLACE_LCHOWN =3D @REPLACE_LCHOWN@ REPLACE_LINK =3D @REPLACE_LINK@ REPLACE_LINKAT =3D @REPLACE_LINKAT@ +REPLACE_LOCALECONV =3D @REPLACE_LOCALECONV@ REPLACE_LOCALTIME =3D @REPLACE_LOCALTIME@ REPLACE_LOCALTIME_R =3D @REPLACE_LOCALTIME_R@ REPLACE_LSEEK =3D @REPLACE_LSEEK@ REPLACE_LSTAT =3D @REPLACE_LSTAT@ REPLACE_MALLOC =3D @REPLACE_MALLOC@ +REPLACE_MBRLEN =3D @REPLACE_MBRLEN@ +REPLACE_MBRTOWC =3D @REPLACE_MBRTOWC@ +REPLACE_MBSINIT =3D @REPLACE_MBSINIT@ +REPLACE_MBSNRTOWCS =3D @REPLACE_MBSNRTOWCS@ +REPLACE_MBSRTOWCS =3D @REPLACE_MBSRTOWCS@ +REPLACE_MBSTATE_T =3D @REPLACE_MBSTATE_T@ REPLACE_MBTOWC =3D @REPLACE_MBTOWC@ REPLACE_MEMCHR =3D @REPLACE_MEMCHR@ REPLACE_MEMMEM =3D @REPLACE_MEMMEM@ @@ -858,6 +991,7 @@ REPLACE_MKNOD =3D @REPLACE_MKNOD@ REPLACE_MKSTEMP =3D @REPLACE_MKSTEMP@ REPLACE_MKTIME =3D @REPLACE_MKTIME@ REPLACE_NANOSLEEP =3D @REPLACE_NANOSLEEP@ +REPLACE_NL_LANGINFO =3D @REPLACE_NL_LANGINFO@ REPLACE_NULL =3D @REPLACE_NULL@ REPLACE_OBSTACK_PRINTF =3D @REPLACE_OBSTACK_PRINTF@ REPLACE_OPEN =3D @REPLACE_OPEN@ @@ -887,6 +1021,7 @@ REPLACE_RENAMEAT =3D @REPLACE_RENAMEAT@ REPLACE_RMDIR =3D @REPLACE_RMDIR@ REPLACE_SELECT =3D @REPLACE_SELECT@ REPLACE_SETENV =3D @REPLACE_SETENV@ +REPLACE_SETLOCALE =3D @REPLACE_SETLOCALE@ REPLACE_SLEEP =3D @REPLACE_SLEEP@ REPLACE_SNPRINTF =3D @REPLACE_SNPRINTF@ REPLACE_SPRINTF =3D @REPLACE_SPRINTF@ @@ -909,11 +1044,13 @@ REPLACE_STRTOD =3D @REPLACE_STRTOD@ REPLACE_STRTOIMAX =3D @REPLACE_STRTOIMAX@ REPLACE_STRTOK_R =3D @REPLACE_STRTOK_R@ REPLACE_STRTOUMAX =3D @REPLACE_STRTOUMAX@ +REPLACE_STRUCT_LCONV =3D @REPLACE_STRUCT_LCONV@ REPLACE_STRUCT_TIMEVAL =3D @REPLACE_STRUCT_TIMEVAL@ REPLACE_SYMLINK =3D @REPLACE_SYMLINK@ REPLACE_SYMLINKAT =3D @REPLACE_SYMLINKAT@ REPLACE_TIMEGM =3D @REPLACE_TIMEGM@ REPLACE_TMPFILE =3D @REPLACE_TMPFILE@ +REPLACE_TOWLOWER =3D @REPLACE_TOWLOWER@ REPLACE_TRUNCATE =3D @REPLACE_TRUNCATE@ REPLACE_TTYNAME_R =3D @REPLACE_TTYNAME_R@ REPLACE_TZSET =3D @REPLACE_TZSET@ @@ -928,7 +1065,14 @@ REPLACE_VFPRINTF =3D @REPLACE_VFPRINTF@ REPLACE_VPRINTF =3D @REPLACE_VPRINTF@ REPLACE_VSNPRINTF =3D @REPLACE_VSNPRINTF@ REPLACE_VSPRINTF =3D @REPLACE_VSPRINTF@ +REPLACE_WCRTOMB =3D @REPLACE_WCRTOMB@ +REPLACE_WCSFTIME =3D @REPLACE_WCSFTIME@ +REPLACE_WCSNRTOMBS =3D @REPLACE_WCSNRTOMBS@ +REPLACE_WCSRTOMBS =3D @REPLACE_WCSRTOMBS@ +REPLACE_WCSWIDTH =3D @REPLACE_WCSWIDTH@ +REPLACE_WCTOB =3D @REPLACE_WCTOB@ REPLACE_WCTOMB =3D @REPLACE_WCTOMB@ +REPLACE_WCWIDTH =3D @REPLACE_WCWIDTH@ REPLACE_WRITE =3D @REPLACE_WRITE@ RSVG_CFLAGS =3D @RSVG_CFLAGS@ RSVG_LIBS =3D @RSVG_LIBS@ @@ -1021,19 +1165,34 @@ gameuser =3D @gameuser@ gl_GNULIB_ENABLED_03e0aaad4cb89ca757653bd367a6ccb7 =3D @gl_GNULIB_ENABLE= D_03e0aaad4cb89ca757653bd367a6ccb7@ gl_GNULIB_ENABLED_2049e887c7e5308faad27b3f894bb8c9 =3D @gl_GNULIB_ENABLE= D_2049e887c7e5308faad27b3f894bb8c9@ gl_GNULIB_ENABLED_260941c0e5dc67ec9e87d1fb321c300b =3D @gl_GNULIB_ENABLE= D_260941c0e5dc67ec9e87d1fb321c300b@ +gl_GNULIB_ENABLED_30838f5439487421042f2225bed3af76 =3D @gl_GNULIB_ENABLE= D_30838f5439487421042f2225bed3af76@ +gl_GNULIB_ENABLED_37f71b604aa9c54446783d80f42fe547 =3D @gl_GNULIB_ENABLE= D_37f71b604aa9c54446783d80f42fe547@ +gl_GNULIB_ENABLED_3dcce957eadc896e63ab5f137947b410 =3D @gl_GNULIB_ENABLE= D_3dcce957eadc896e63ab5f137947b410@ gl_GNULIB_ENABLED_5264294aa0a5557541b53c8c741f7f31 =3D @gl_GNULIB_ENABLE= D_5264294aa0a5557541b53c8c741f7f31@ gl_GNULIB_ENABLED_6099e9737f757db36c47fa9d9f02e88c =3D @gl_GNULIB_ENABLE= D_6099e9737f757db36c47fa9d9f02e88c@ gl_GNULIB_ENABLED_682e609604ccaac6be382e4ee3a4eaec =3D @gl_GNULIB_ENABLE= D_682e609604ccaac6be382e4ee3a4eaec@ gl_GNULIB_ENABLED_a9786850e999ae65a836a6041e8e5ed1 =3D @gl_GNULIB_ENABLE= D_a9786850e999ae65a836a6041e8e5ed1@ gl_GNULIB_ENABLED_be453cec5eecf5731a274f2de7f2db36 =3D @gl_GNULIB_ENABLE= D_be453cec5eecf5731a274f2de7f2db36@ +gl_GNULIB_ENABLED_btowc =3D @gl_GNULIB_ENABLED_btowc@ gl_GNULIB_ENABLED_cloexec =3D @gl_GNULIB_ENABLED_cloexec@ gl_GNULIB_ENABLED_dirfd =3D @gl_GNULIB_ENABLED_dirfd@ gl_GNULIB_ENABLED_dosname =3D @gl_GNULIB_ENABLED_dosname@ gl_GNULIB_ENABLED_euidaccess =3D @gl_GNULIB_ENABLED_euidaccess@ gl_GNULIB_ENABLED_getdtablesize =3D @gl_GNULIB_ENABLED_getdtablesize@ gl_GNULIB_ENABLED_getgroups =3D @gl_GNULIB_ENABLED_getgroups@ +gl_GNULIB_ENABLED_langinfo =3D @gl_GNULIB_ENABLED_langinfo@ +gl_GNULIB_ENABLED_localcharset =3D @gl_GNULIB_ENABLED_localcharset@ +gl_GNULIB_ENABLED_locale =3D @gl_GNULIB_ENABLED_locale@ +gl_GNULIB_ENABLED_localeconv =3D @gl_GNULIB_ENABLED_localeconv@ +gl_GNULIB_ENABLED_mbrtowc =3D @gl_GNULIB_ENABLED_mbrtowc@ +gl_GNULIB_ENABLED_mbsinit =3D @gl_GNULIB_ENABLED_mbsinit@ +gl_GNULIB_ENABLED_mbtowc =3D @gl_GNULIB_ENABLED_mbtowc@ +gl_GNULIB_ENABLED_nl_langinfo =3D @gl_GNULIB_ENABLED_nl_langinfo@ gl_GNULIB_ENABLED_open =3D @gl_GNULIB_ENABLED_open@ +gl_GNULIB_ENABLED_streq =3D @gl_GNULIB_ENABLED_streq@ gl_GNULIB_ENABLED_strtoll =3D @gl_GNULIB_ENABLED_strtoll@ +gl_GNULIB_ENABLED_wchar =3D @gl_GNULIB_ENABLED_wchar@ +gl_GNULIB_ENABLED_wcrtomb =3D @gl_GNULIB_ENABLED_wcrtomb@ gl_LIBOBJS =3D @gl_LIBOBJS@ gl_LTLIBOBJS =3D @gl_LTLIBOBJS@ gltests_LIBOBJS =3D @gltests_LIBOBJS@ @@ -1164,6 +1323,19 @@ libgnu_a_SOURCES +=3D binary-io.h binary-io.c endif ## end gnulib module binary-io =20 +## begin gnulib module btowc +ifeq (,$(OMIT_GNULIB_MODULE_btowc)) + +ifneq (,$(gl_GNULIB_ENABLED_btowc)) + +endif +EXTRA_DIST +=3D btowc.c + +EXTRA_libgnu_a_SOURCES +=3D btowc.c + +endif +## end gnulib module btowc + ## begin gnulib module byteswap ifeq (,$(OMIT_GNULIB_MODULE_byteswap)) =20 @@ -1787,6 +1959,18 @@ EXTRA_libgnu_a_SOURCES +=3D group-member.c endif ## end gnulib module group-member =20 +## begin gnulib module hard-locale +ifeq (,$(OMIT_GNULIB_MODULE_hard-locale)) + +ifneq (,$(gl_GNULIB_ENABLED_30838f5439487421042f2225bed3af76)) +libgnu_a_SOURCES +=3D hard-locale.c + +endif +EXTRA_DIST +=3D hard-locale.h + +endif +## end gnulib module hard-locale + ## begin gnulib module ignore-value ifeq (,$(OMIT_GNULIB_MODULE_ignore-value)) =20 @@ -1853,6 +2037,44 @@ EXTRA_DIST +=3D inttypes.in.h endif ## end gnulib module inttypes-incomplete =20 +## begin gnulib module langinfo +ifeq (,$(OMIT_GNULIB_MODULE_langinfo)) + +ifneq (,$(gl_GNULIB_ENABLED_langinfo)) +BUILT_SOURCES +=3D langinfo.h + +# We need the following in order to create an empty placeholder for +# when the system doesn't have one. +langinfo.h: langinfo.in.h $(top_builddir)/config.status $(CXXDEFS_H) $(W= ARN_ON_USE_H) + $(AM_V_GEN)rm -f $@-t $@ && \ + { echo '/* DO NOT EDIT! GENERATED AUTOMATICALLY! */'; \ + sed -e 's|@''GUARD_PREFIX''@|GL|g' \ + -e 's|@''HAVE_LANGINFO_H''@|$(HAVE_LANGINFO_H)|g' \ + -e 's|@''INCLUDE_NEXT''@|$(INCLUDE_NEXT)|g' \ + -e 's|@''PRAGMA_SYSTEM_HEADER''@|@PRAGMA_SYSTEM_HEADER@|g' \ + -e 's|@''PRAGMA_COLUMNS''@|@PRAGMA_COLUMNS@|g' \ + -e 's|@''NEXT_LANGINFO_H''@|$(NEXT_LANGINFO_H)|g' \ + -e 's/@''GNULIB_NL_LANGINFO''@/$(GNULIB_NL_LANGINFO)/g' \ + -e 's|@''HAVE_LANGINFO_CODESET''@|$(HAVE_LANGINFO_CODESET)|g' \ + -e 's|@''HAVE_LANGINFO_T_FMT_AMPM''@|$(HAVE_LANGINFO_T_FMT_AMPM)|= g' \ + -e 's|@''HAVE_LANGINFO_ALTMON''@|$(HAVE_LANGINFO_ALTMON)|g' \ + -e 's|@''HAVE_LANGINFO_ERA''@|$(HAVE_LANGINFO_ERA)|g' \ + -e 's|@''HAVE_LANGINFO_YESEXPR''@|$(HAVE_LANGINFO_YESEXPR)|g' \ + -e 's|@''HAVE_NL_LANGINFO''@|$(HAVE_NL_LANGINFO)|g' \ + -e 's|@''REPLACE_NL_LANGINFO''@|$(REPLACE_NL_LANGINFO)|g' \ + -e '/definitions of _GL_FUNCDECL_RPL/r $(CXXDEFS_H)' \ + -e '/definition of _GL_WARN_ON_USE/r $(WARN_ON_USE_H)' \ + < $(srcdir)/langinfo.in.h; \ + } > $@-t && \ + mv $@-t $@ +MOSTLYCLEANFILES +=3D langinfo.h langinfo.h-t + +endif +EXTRA_DIST +=3D langinfo.in.h + +endif +## end gnulib module langinfo + ## begin gnulib module limits-h ifeq (,$(OMIT_GNULIB_MODULE_limits-h)) =20 @@ -1883,6 +2105,70 @@ EXTRA_DIST +=3D limits.in.h endif ## end gnulib module limits-h =20 +## begin gnulib module localcharset +ifeq (,$(OMIT_GNULIB_MODULE_localcharset)) + +ifneq (,$(gl_GNULIB_ENABLED_localcharset)) +libgnu_a_SOURCES +=3D localcharset.c + +endif +EXTRA_DIST +=3D localcharset.h + +endif +## end gnulib module localcharset + +## begin gnulib module locale +ifeq (,$(OMIT_GNULIB_MODULE_locale)) + +ifneq (,$(gl_GNULIB_ENABLED_locale)) +BUILT_SOURCES +=3D locale.h + +# We need the following in order to create when the system +# doesn't have one that provides all definitions. +locale.h: locale.in.h $(top_builddir)/config.status $(CXXDEFS_H) $(ARG_N= ONNULL_H) $(WARN_ON_USE_H) + $(AM_V_GEN)rm -f $@-t $@ && \ + { echo '/* DO NOT EDIT! GENERATED AUTOMATICALLY! */' && \ + sed -e 's|@''GUARD_PREFIX''@|GL|g' \ + -e 's|@''INCLUDE_NEXT''@|$(INCLUDE_NEXT)|g' \ + -e 's|@''PRAGMA_SYSTEM_HEADER''@|@PRAGMA_SYSTEM_HEADER@|g' \ + -e 's|@''PRAGMA_COLUMNS''@|@PRAGMA_COLUMNS@|g' \ + -e 's|@''NEXT_LOCALE_H''@|$(NEXT_LOCALE_H)|g' \ + -e 's/@''GNULIB_LOCALECONV''@/$(GNULIB_LOCALECONV)/g' \ + -e 's/@''GNULIB_SETLOCALE''@/$(GNULIB_SETLOCALE)/g' \ + -e 's/@''GNULIB_DUPLOCALE''@/$(GNULIB_DUPLOCALE)/g' \ + -e 's|@''HAVE_DUPLOCALE''@|$(HAVE_DUPLOCALE)|g' \ + -e 's|@''HAVE_XLOCALE_H''@|$(HAVE_XLOCALE_H)|g' \ + -e 's|@''REPLACE_LOCALECONV''@|$(REPLACE_LOCALECONV)|g' \ + -e 's|@''REPLACE_SETLOCALE''@|$(REPLACE_SETLOCALE)|g' \ + -e 's|@''REPLACE_DUPLOCALE''@|$(REPLACE_DUPLOCALE)|g' \ + -e 's|@''REPLACE_STRUCT_LCONV''@|$(REPLACE_STRUCT_LCONV)|g' \ + -e '/definitions of _GL_FUNCDECL_RPL/r $(CXXDEFS_H)' \ + -e '/definition of _GL_ARG_NONNULL/r $(ARG_NONNULL_H)' \ + -e '/definition of _GL_WARN_ON_USE/r $(WARN_ON_USE_H)' \ + < $(srcdir)/locale.in.h; \ + } > $@-t && \ + mv $@-t $@ +MOSTLYCLEANFILES +=3D locale.h locale.h-t + +endif +EXTRA_DIST +=3D locale.in.h + +endif +## end gnulib module locale + +## begin gnulib module localeconv +ifeq (,$(OMIT_GNULIB_MODULE_localeconv)) + +ifneq (,$(gl_GNULIB_ENABLED_localeconv)) + +endif +EXTRA_DIST +=3D localeconv.c + +EXTRA_libgnu_a_SOURCES +=3D localeconv.c + +endif +## end gnulib module localeconv + ## begin gnulib module localtime-buffer ifeq (,$(OMIT_GNULIB_MODULE_localtime-buffer)) =20 @@ -1907,6 +2193,45 @@ EXTRA_libgnu_a_SOURCES +=3D lstat.c endif ## end gnulib module lstat =20 +## begin gnulib module mbrtowc +ifeq (,$(OMIT_GNULIB_MODULE_mbrtowc)) + +ifneq (,$(gl_GNULIB_ENABLED_mbrtowc)) + +endif +EXTRA_DIST +=3D mbrtowc.c + +EXTRA_libgnu_a_SOURCES +=3D mbrtowc.c + +endif +## end gnulib module mbrtowc + +## begin gnulib module mbsinit +ifeq (,$(OMIT_GNULIB_MODULE_mbsinit)) + +ifneq (,$(gl_GNULIB_ENABLED_mbsinit)) + +endif +EXTRA_DIST +=3D mbsinit.c + +EXTRA_libgnu_a_SOURCES +=3D mbsinit.c + +endif +## end gnulib module mbsinit + +## begin gnulib module mbtowc +ifeq (,$(OMIT_GNULIB_MODULE_mbtowc)) + +ifneq (,$(gl_GNULIB_ENABLED_mbtowc)) + +endif +EXTRA_DIST +=3D mbtowc-impl.h mbtowc.c + +EXTRA_libgnu_a_SOURCES +=3D mbtowc.c + +endif +## end gnulib module mbtowc + ## begin gnulib module memrchr ifeq (,$(OMIT_GNULIB_MODULE_memrchr)) =20 @@ -1961,6 +2286,19 @@ EXTRA_libgnu_a_SOURCES +=3D mktime.c endif ## end gnulib module mktime-internal =20 +## begin gnulib module nl_langinfo +ifeq (,$(OMIT_GNULIB_MODULE_nl_langinfo)) + +ifneq (,$(gl_GNULIB_ENABLED_nl_langinfo)) + +endif +EXTRA_DIST +=3D nl_langinfo.c + +EXTRA_libgnu_a_SOURCES +=3D nl_langinfo.c + +endif +## end gnulib module nl_langinfo + ## begin gnulib module nstrftime ifeq (,$(OMIT_GNULIB_MODULE_nstrftime)) =20 @@ -2066,6 +2404,17 @@ EXTRA_libgnu_a_SOURCES +=3D at-func.c readlinkat.c endif ## end gnulib module readlinkat =20 +## begin gnulib module regex +ifeq (,$(OMIT_GNULIB_MODULE_regex)) + + +EXTRA_DIST +=3D regcomp.c regex.c regex.h regex_internal.c regex_interna= l.h regexec.c + +EXTRA_libgnu_a_SOURCES +=3D regcomp.c regex.c regex_internal.c regexec.c + +endif +## end gnulib module regex + ## begin gnulib module root-uid ifeq (,$(OMIT_GNULIB_MODULE_root-uid)) =20 @@ -2563,6 +2912,17 @@ EXTRA_libgnu_a_SOURCES +=3D stpcpy.c endif ## end gnulib module stpcpy =20 +## begin gnulib module streq +ifeq (,$(OMIT_GNULIB_MODULE_streq)) + +ifneq (,$(gl_GNULIB_ENABLED_streq)) + +endif +EXTRA_DIST +=3D streq.h + +endif +## end gnulib module streq + ## begin gnulib module string ifeq (,$(OMIT_GNULIB_MODULE_string)) =20 @@ -3210,6 +3570,195 @@ EXTRA_DIST +=3D vla.h endif ## end gnulib module vla =20 +## begin gnulib module wchar +ifeq (,$(OMIT_GNULIB_MODULE_wchar)) + +ifneq (,$(gl_GNULIB_ENABLED_wchar)) +BUILT_SOURCES +=3D wchar.h + +# We need the following in order to create when the system +# version does not work standalone. +wchar.h: wchar.in.h $(top_builddir)/config.status $(CXXDEFS_H) $(ARG_NON= NULL_H) $(WARN_ON_USE_H) + $(AM_V_GEN)rm -f $@-t $@ && \ + { echo '/* DO NOT EDIT! GENERATED AUTOMATICALLY! */'; \ + sed -e 's|@''GUARD_PREFIX''@|GL|g' \ + -e 's|@''INCLUDE_NEXT''@|$(INCLUDE_NEXT)|g' \ + -e 's|@''PRAGMA_SYSTEM_HEADER''@|@PRAGMA_SYSTEM_HEADER@|g' \ + -e 's|@''PRAGMA_COLUMNS''@|@PRAGMA_COLUMNS@|g' \ + -e 's|@''HAVE_FEATURES_H''@|$(HAVE_FEATURES_H)|g' \ + -e 's|@''NEXT_WCHAR_H''@|$(NEXT_WCHAR_H)|g' \ + -e 's|@''HAVE_WCHAR_H''@|$(HAVE_WCHAR_H)|g' \ + -e 's/@''HAVE_CRTDEFS_H''@/$(HAVE_CRTDEFS_H)/g' \ + -e 's/@''GNULIB_OVERRIDES_WINT_T''@/$(GNULIB_OVERRIDES_WINT_T)/g'= \ + -e 's/@''GNULIB_BTOWC''@/$(GNULIB_BTOWC)/g' \ + -e 's/@''GNULIB_WCTOB''@/$(GNULIB_WCTOB)/g' \ + -e 's/@''GNULIB_MBSINIT''@/$(GNULIB_MBSINIT)/g' \ + -e 's/@''GNULIB_MBRTOWC''@/$(GNULIB_MBRTOWC)/g' \ + -e 's/@''GNULIB_MBRLEN''@/$(GNULIB_MBRLEN)/g' \ + -e 's/@''GNULIB_MBSRTOWCS''@/$(GNULIB_MBSRTOWCS)/g' \ + -e 's/@''GNULIB_MBSNRTOWCS''@/$(GNULIB_MBSNRTOWCS)/g' \ + -e 's/@''GNULIB_WCRTOMB''@/$(GNULIB_WCRTOMB)/g' \ + -e 's/@''GNULIB_WCSRTOMBS''@/$(GNULIB_WCSRTOMBS)/g' \ + -e 's/@''GNULIB_WCSNRTOMBS''@/$(GNULIB_WCSNRTOMBS)/g' \ + -e 's/@''GNULIB_WCWIDTH''@/$(GNULIB_WCWIDTH)/g' \ + -e 's/@''GNULIB_WMEMCHR''@/$(GNULIB_WMEMCHR)/g' \ + -e 's/@''GNULIB_WMEMCMP''@/$(GNULIB_WMEMCMP)/g' \ + -e 's/@''GNULIB_WMEMCPY''@/$(GNULIB_WMEMCPY)/g' \ + -e 's/@''GNULIB_WMEMMOVE''@/$(GNULIB_WMEMMOVE)/g' \ + -e 's/@''GNULIB_WMEMSET''@/$(GNULIB_WMEMSET)/g' \ + -e 's/@''GNULIB_WCSLEN''@/$(GNULIB_WCSLEN)/g' \ + -e 's/@''GNULIB_WCSNLEN''@/$(GNULIB_WCSNLEN)/g' \ + -e 's/@''GNULIB_WCSCPY''@/$(GNULIB_WCSCPY)/g' \ + -e 's/@''GNULIB_WCPCPY''@/$(GNULIB_WCPCPY)/g' \ + -e 's/@''GNULIB_WCSNCPY''@/$(GNULIB_WCSNCPY)/g' \ + -e 's/@''GNULIB_WCPNCPY''@/$(GNULIB_WCPNCPY)/g' \ + -e 's/@''GNULIB_WCSCAT''@/$(GNULIB_WCSCAT)/g' \ + -e 's/@''GNULIB_WCSNCAT''@/$(GNULIB_WCSNCAT)/g' \ + -e 's/@''GNULIB_WCSCMP''@/$(GNULIB_WCSCMP)/g' \ + -e 's/@''GNULIB_WCSNCMP''@/$(GNULIB_WCSNCMP)/g' \ + -e 's/@''GNULIB_WCSCASECMP''@/$(GNULIB_WCSCASECMP)/g' \ + -e 's/@''GNULIB_WCSNCASECMP''@/$(GNULIB_WCSNCASECMP)/g' \ + -e 's/@''GNULIB_WCSCOLL''@/$(GNULIB_WCSCOLL)/g' \ + -e 's/@''GNULIB_WCSXFRM''@/$(GNULIB_WCSXFRM)/g' \ + -e 's/@''GNULIB_WCSDUP''@/$(GNULIB_WCSDUP)/g' \ + -e 's/@''GNULIB_WCSCHR''@/$(GNULIB_WCSCHR)/g' \ + -e 's/@''GNULIB_WCSRCHR''@/$(GNULIB_WCSRCHR)/g' \ + -e 's/@''GNULIB_WCSCSPN''@/$(GNULIB_WCSCSPN)/g' \ + -e 's/@''GNULIB_WCSSPN''@/$(GNULIB_WCSSPN)/g' \ + -e 's/@''GNULIB_WCSPBRK''@/$(GNULIB_WCSPBRK)/g' \ + -e 's/@''GNULIB_WCSSTR''@/$(GNULIB_WCSSTR)/g' \ + -e 's/@''GNULIB_WCSTOK''@/$(GNULIB_WCSTOK)/g' \ + -e 's/@''GNULIB_WCSWIDTH''@/$(GNULIB_WCSWIDTH)/g' \ + -e 's/@''GNULIB_WCSFTIME''@/$(GNULIB_WCSFTIME)/g' \ + < $(srcdir)/wchar.in.h | \ + sed -e 's|@''HAVE_WINT_T''@|$(HAVE_WINT_T)|g' \ + -e 's|@''HAVE_BTOWC''@|$(HAVE_BTOWC)|g' \ + -e 's|@''HAVE_MBSINIT''@|$(HAVE_MBSINIT)|g' \ + -e 's|@''HAVE_MBRTOWC''@|$(HAVE_MBRTOWC)|g' \ + -e 's|@''HAVE_MBRLEN''@|$(HAVE_MBRLEN)|g' \ + -e 's|@''HAVE_MBSRTOWCS''@|$(HAVE_MBSRTOWCS)|g' \ + -e 's|@''HAVE_MBSNRTOWCS''@|$(HAVE_MBSNRTOWCS)|g' \ + -e 's|@''HAVE_WCRTOMB''@|$(HAVE_WCRTOMB)|g' \ + -e 's|@''HAVE_WCSRTOMBS''@|$(HAVE_WCSRTOMBS)|g' \ + -e 's|@''HAVE_WCSNRTOMBS''@|$(HAVE_WCSNRTOMBS)|g' \ + -e 's|@''HAVE_WMEMCHR''@|$(HAVE_WMEMCHR)|g' \ + -e 's|@''HAVE_WMEMCMP''@|$(HAVE_WMEMCMP)|g' \ + -e 's|@''HAVE_WMEMCPY''@|$(HAVE_WMEMCPY)|g' \ + -e 's|@''HAVE_WMEMMOVE''@|$(HAVE_WMEMMOVE)|g' \ + -e 's|@''HAVE_WMEMSET''@|$(HAVE_WMEMSET)|g' \ + -e 's|@''HAVE_WCSLEN''@|$(HAVE_WCSLEN)|g' \ + -e 's|@''HAVE_WCSNLEN''@|$(HAVE_WCSNLEN)|g' \ + -e 's|@''HAVE_WCSCPY''@|$(HAVE_WCSCPY)|g' \ + -e 's|@''HAVE_WCPCPY''@|$(HAVE_WCPCPY)|g' \ + -e 's|@''HAVE_WCSNCPY''@|$(HAVE_WCSNCPY)|g' \ + -e 's|@''HAVE_WCPNCPY''@|$(HAVE_WCPNCPY)|g' \ + -e 's|@''HAVE_WCSCAT''@|$(HAVE_WCSCAT)|g' \ + -e 's|@''HAVE_WCSNCAT''@|$(HAVE_WCSNCAT)|g' \ + -e 's|@''HAVE_WCSCMP''@|$(HAVE_WCSCMP)|g' \ + -e 's|@''HAVE_WCSNCMP''@|$(HAVE_WCSNCMP)|g' \ + -e 's|@''HAVE_WCSCASECMP''@|$(HAVE_WCSCASECMP)|g' \ + -e 's|@''HAVE_WCSNCASECMP''@|$(HAVE_WCSNCASECMP)|g' \ + -e 's|@''HAVE_WCSCOLL''@|$(HAVE_WCSCOLL)|g' \ + -e 's|@''HAVE_WCSXFRM''@|$(HAVE_WCSXFRM)|g' \ + -e 's|@''HAVE_WCSDUP''@|$(HAVE_WCSDUP)|g' \ + -e 's|@''HAVE_WCSCHR''@|$(HAVE_WCSCHR)|g' \ + -e 's|@''HAVE_WCSRCHR''@|$(HAVE_WCSRCHR)|g' \ + -e 's|@''HAVE_WCSCSPN''@|$(HAVE_WCSCSPN)|g' \ + -e 's|@''HAVE_WCSSPN''@|$(HAVE_WCSSPN)|g' \ + -e 's|@''HAVE_WCSPBRK''@|$(HAVE_WCSPBRK)|g' \ + -e 's|@''HAVE_WCSSTR''@|$(HAVE_WCSSTR)|g' \ + -e 's|@''HAVE_WCSTOK''@|$(HAVE_WCSTOK)|g' \ + -e 's|@''HAVE_WCSWIDTH''@|$(HAVE_WCSWIDTH)|g' \ + -e 's|@''HAVE_WCSFTIME''@|$(HAVE_WCSFTIME)|g' \ + -e 's|@''HAVE_DECL_WCTOB''@|$(HAVE_DECL_WCTOB)|g' \ + -e 's|@''HAVE_DECL_WCWIDTH''@|$(HAVE_DECL_WCWIDTH)|g' \ + | \ + sed -e 's|@''REPLACE_MBSTATE_T''@|$(REPLACE_MBSTATE_T)|g' \ + -e 's|@''REPLACE_BTOWC''@|$(REPLACE_BTOWC)|g' \ + -e 's|@''REPLACE_WCTOB''@|$(REPLACE_WCTOB)|g' \ + -e 's|@''REPLACE_MBSINIT''@|$(REPLACE_MBSINIT)|g' \ + -e 's|@''REPLACE_MBRTOWC''@|$(REPLACE_MBRTOWC)|g' \ + -e 's|@''REPLACE_MBRLEN''@|$(REPLACE_MBRLEN)|g' \ + -e 's|@''REPLACE_MBSRTOWCS''@|$(REPLACE_MBSRTOWCS)|g' \ + -e 's|@''REPLACE_MBSNRTOWCS''@|$(REPLACE_MBSNRTOWCS)|g' \ + -e 's|@''REPLACE_WCRTOMB''@|$(REPLACE_WCRTOMB)|g' \ + -e 's|@''REPLACE_WCSRTOMBS''@|$(REPLACE_WCSRTOMBS)|g' \ + -e 's|@''REPLACE_WCSNRTOMBS''@|$(REPLACE_WCSNRTOMBS)|g' \ + -e 's|@''REPLACE_WCWIDTH''@|$(REPLACE_WCWIDTH)|g' \ + -e 's|@''REPLACE_WCSWIDTH''@|$(REPLACE_WCSWIDTH)|g' \ + -e 's|@''REPLACE_WCSFTIME''@|$(REPLACE_WCSFTIME)|g' \ + -e '/definitions of _GL_FUNCDECL_RPL/r $(CXXDEFS_H)' \ + -e '/definition of _GL_ARG_NONNULL/r $(ARG_NONNULL_H)' \ + -e '/definition of _GL_WARN_ON_USE/r $(WARN_ON_USE_H)'; \ + } > $@-t && \ + mv $@-t $@ +MOSTLYCLEANFILES +=3D wchar.h wchar.h-t + +endif +EXTRA_DIST +=3D wchar.in.h + +endif +## end gnulib module wchar + +## begin gnulib module wcrtomb +ifeq (,$(OMIT_GNULIB_MODULE_wcrtomb)) + +ifneq (,$(gl_GNULIB_ENABLED_wcrtomb)) + +endif +EXTRA_DIST +=3D wcrtomb.c + +EXTRA_libgnu_a_SOURCES +=3D wcrtomb.c + +endif +## end gnulib module wcrtomb + +## begin gnulib module wctype-h +ifeq (,$(OMIT_GNULIB_MODULE_wctype-h)) + +ifneq (,$(gl_GNULIB_ENABLED_3dcce957eadc896e63ab5f137947b410)) +BUILT_SOURCES +=3D wctype.h +libgnu_a_SOURCES +=3D wctype-h.c + +# We need the following in order to create when the system +# doesn't have one that works with the given compiler. +wctype.h: wctype.in.h $(top_builddir)/config.status $(CXXDEFS_H) $(WARN_= ON_USE_H) + $(AM_V_GEN)rm -f $@-t $@ && \ + { echo '/* DO NOT EDIT! GENERATED AUTOMATICALLY! */'; \ + sed -e 's|@''GUARD_PREFIX''@|GL|g' \ + -e 's/@''HAVE_WCTYPE_H''@/$(HAVE_WCTYPE_H)/g' \ + -e 's|@''INCLUDE_NEXT''@|$(INCLUDE_NEXT)|g' \ + -e 's|@''PRAGMA_SYSTEM_HEADER''@|@PRAGMA_SYSTEM_HEADER@|g' \ + -e 's|@''PRAGMA_COLUMNS''@|@PRAGMA_COLUMNS@|g' \ + -e 's|@''NEXT_WCTYPE_H''@|$(NEXT_WCTYPE_H)|g' \ + -e 's/@''HAVE_CRTDEFS_H''@/$(HAVE_CRTDEFS_H)/g' \ + -e 's/@''GNULIB_OVERRIDES_WINT_T''@/$(GNULIB_OVERRIDES_WINT_T)/g'= \ + -e 's/@''GNULIB_ISWBLANK''@/$(GNULIB_ISWBLANK)/g' \ + -e 's/@''GNULIB_WCTYPE''@/$(GNULIB_WCTYPE)/g' \ + -e 's/@''GNULIB_ISWCTYPE''@/$(GNULIB_ISWCTYPE)/g' \ + -e 's/@''GNULIB_WCTRANS''@/$(GNULIB_WCTRANS)/g' \ + -e 's/@''GNULIB_TOWCTRANS''@/$(GNULIB_TOWCTRANS)/g' \ + -e 's/@''HAVE_ISWBLANK''@/$(HAVE_ISWBLANK)/g' \ + -e 's/@''HAVE_ISWCNTRL''@/$(HAVE_ISWCNTRL)/g' \ + -e 's/@''HAVE_WCTYPE_T''@/$(HAVE_WCTYPE_T)/g' \ + -e 's/@''HAVE_WCTRANS_T''@/$(HAVE_WCTRANS_T)/g' \ + -e 's/@''HAVE_WINT_T''@/$(HAVE_WINT_T)/g' \ + -e 's/@''REPLACE_ISWBLANK''@/$(REPLACE_ISWBLANK)/g' \ + -e 's/@''REPLACE_ISWCNTRL''@/$(REPLACE_ISWCNTRL)/g' \ + -e 's/@''REPLACE_TOWLOWER''@/$(REPLACE_TOWLOWER)/g' \ + -e '/definitions of _GL_FUNCDECL_RPL/r $(CXXDEFS_H)' \ + -e '/definition of _GL_WARN_ON_USE/r $(WARN_ON_USE_H)' \ + < $(srcdir)/wctype.in.h; \ + } > $@-t && \ + mv $@-t $@ +MOSTLYCLEANFILES +=3D wctype.h wctype.h-t + +endif +EXTRA_DIST +=3D wctype.in.h + +endif +## end gnulib module wctype-h + ## begin gnulib module xalloc-oversized ifeq (,$(OMIT_GNULIB_MODULE_xalloc-oversized)) =20 diff --git a/lib/hard-locale.c b/lib/hard-locale.c new file mode 100644 index 0000000000..49bc6caff4 --- /dev/null +++ b/lib/hard-locale.c @@ -0,0 +1,72 @@ +/* hard-locale.c -- Determine whether a locale is hard. + + Copyright (C) 1997-1999, 2002-2004, 2006-2007, 2009-2018 Free Softwar= e + Foundation, Inc. + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see = . */ + +#include + +#include "hard-locale.h" + +#include +#include +#include + +#ifdef __GLIBC__ +# define GLIBC_VERSION __GLIBC__ +#elif defined __UCLIBC__ +# define GLIBC_VERSION 2 +#else +# define GLIBC_VERSION 0 +#endif + +/* Return true if the current CATEGORY locale is hard, i.e. if you + can't get away with assuming traditional C or POSIX behavior. */ +bool +hard_locale (int category) +{ + bool hard =3D true; + char const *p =3D setlocale (category, NULL); + + if (p) + { + if (2 <=3D GLIBC_VERSION) + { + if (strcmp (p, "C") =3D=3D 0 || strcmp (p, "POSIX") =3D=3D 0) + hard =3D false; + } + else + { + char *locale =3D strdup (p); + if (locale) + { + /* Temporarily set the locale to the "C" and "POSIX" local= es + to find their names, so that we can determine whether o= ne + or the other is the caller's locale. */ + if (((p =3D setlocale (category, "C")) + && strcmp (p, locale) =3D=3D 0) + || ((p =3D setlocale (category, "POSIX")) + && strcmp (p, locale) =3D=3D 0)) + hard =3D false; + + /* Restore the caller's locale. */ + setlocale (category, locale); + free (locale); + } + } + } + + return hard; +} diff --git a/lib/hard-locale.h b/lib/hard-locale.h new file mode 100644 index 0000000000..22eecc5ed8 --- /dev/null +++ b/lib/hard-locale.h @@ -0,0 +1,25 @@ +/* Determine whether a locale is hard. + + Copyright (C) 1999, 2003-2004, 2009-2018 Free Software Foundation, In= c. + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see = . */ + +#ifndef HARD_LOCALE_H_ +# define HARD_LOCALE_H_ 1 + +# include + +bool hard_locale (int); + +#endif /* HARD_LOCALE_H_ */ diff --git a/lib/langinfo.in.h b/lib/langinfo.in.h new file mode 100644 index 0000000000..96c237ae32 --- /dev/null +++ b/lib/langinfo.in.h @@ -0,0 +1,222 @@ +/* Substitute for and wrapper around . + Copyright (C) 2009-2018 Free Software Foundation, Inc. + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 3, or (at your option) + any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, see .= */ + +/* + * POSIX for platforms that lack it or have an incomplete o= ne. + * + */ + +#ifndef _@GUARD_PREFIX@_LANGINFO_H + +#if __GNUC__ >=3D 3 +@PRAGMA_SYSTEM_HEADER@ +#endif +@PRAGMA_COLUMNS@ + +/* The include_next requires a split double-inclusion guard. */ +#if @HAVE_LANGINFO_H@ +# @INCLUDE_NEXT@ @NEXT_LANGINFO_H@ +#endif + +#ifndef _@GUARD_PREFIX@_LANGINFO_H +#define _@GUARD_PREFIX@_LANGINFO_H + + +#if !@HAVE_LANGINFO_H@ + +/* A platform that lacks . */ + +/* Assume that it also lacks and the nl_item type. */ +# if !GNULIB_defined_nl_item +typedef int nl_item; +# define GNULIB_defined_nl_item 1 +# endif + +/* nl_langinfo items of the LC_CTYPE category */ +# define CODESET 10000 +/* nl_langinfo items of the LC_NUMERIC category */ +# define RADIXCHAR 10001 +# define DECIMAL_POINT RADIXCHAR +# define THOUSEP 10002 +# define THOUSANDS_SEP THOUSEP +# define GROUPING 10114 +/* nl_langinfo items of the LC_TIME category */ +# define D_T_FMT 10003 +# define D_FMT 10004 +# define T_FMT 10005 +# define T_FMT_AMPM 10006 +# define AM_STR 10007 +# define PM_STR 10008 +# define DAY_1 10009 +# define DAY_2 (DAY_1 + 1) +# define DAY_3 (DAY_1 + 2) +# define DAY_4 (DAY_1 + 3) +# define DAY_5 (DAY_1 + 4) +# define DAY_6 (DAY_1 + 5) +# define DAY_7 (DAY_1 + 6) +# define ABDAY_1 10016 +# define ABDAY_2 (ABDAY_1 + 1) +# define ABDAY_3 (ABDAY_1 + 2) +# define ABDAY_4 (ABDAY_1 + 3) +# define ABDAY_5 (ABDAY_1 + 4) +# define ABDAY_6 (ABDAY_1 + 5) +# define ABDAY_7 (ABDAY_1 + 6) +# define MON_1 10023 +# define MON_2 (MON_1 + 1) +# define MON_3 (MON_1 + 2) +# define MON_4 (MON_1 + 3) +# define MON_5 (MON_1 + 4) +# define MON_6 (MON_1 + 5) +# define MON_7 (MON_1 + 6) +# define MON_8 (MON_1 + 7) +# define MON_9 (MON_1 + 8) +# define MON_10 (MON_1 + 9) +# define MON_11 (MON_1 + 10) +# define MON_12 (MON_1 + 11) +# define ALTMON_1 10200 +# define ALTMON_2 (ALTMON_1 + 1) +# define ALTMON_3 (ALTMON_1 + 2) +# define ALTMON_4 (ALTMON_1 + 3) +# define ALTMON_5 (ALTMON_1 + 4) +# define ALTMON_6 (ALTMON_1 + 5) +# define ALTMON_7 (ALTMON_1 + 6) +# define ALTMON_8 (ALTMON_1 + 7) +# define ALTMON_9 (ALTMON_1 + 8) +# define ALTMON_10 (ALTMON_1 + 9) +# define ALTMON_11 (ALTMON_1 + 10) +# define ALTMON_12 (ALTMON_1 + 11) +# define ABMON_1 10035 +# define ABMON_2 (ABMON_1 + 1) +# define ABMON_3 (ABMON_1 + 2) +# define ABMON_4 (ABMON_1 + 3) +# define ABMON_5 (ABMON_1 + 4) +# define ABMON_6 (ABMON_1 + 5) +# define ABMON_7 (ABMON_1 + 6) +# define ABMON_8 (ABMON_1 + 7) +# define ABMON_9 (ABMON_1 + 8) +# define ABMON_10 (ABMON_1 + 9) +# define ABMON_11 (ABMON_1 + 10) +# define ABMON_12 (ABMON_1 + 11) +# define ERA 10047 +# define ERA_D_FMT 10048 +# define ERA_D_T_FMT 10049 +# define ERA_T_FMT 10050 +# define ALT_DIGITS 10051 +/* nl_langinfo items of the LC_MONETARY category */ +# define CRNCYSTR 10052 +# define CURRENCY_SYMBOL CRNCYSTR +# define INT_CURR_SYMBOL 10100 +# define MON_DECIMAL_POINT 10101 +# define MON_THOUSANDS_SEP 10102 +# define MON_GROUPING 10103 +# define POSITIVE_SIGN 10104 +# define NEGATIVE_SIGN 10105 +# define FRAC_DIGITS 10106 +# define INT_FRAC_DIGITS 10107 +# define P_CS_PRECEDES 10108 +# define N_CS_PRECEDES 10109 +# define P_SEP_BY_SPACE 10110 +# define N_SEP_BY_SPACE 10111 +# define P_SIGN_POSN 10112 +# define N_SIGN_POSN 10113 +/* nl_langinfo items of the LC_MESSAGES category */ +# define YESEXPR 10053 +# define NOEXPR 10054 + +#else + +/* A platform that has . */ + +# if !@HAVE_LANGINFO_CODESET@ +# define CODESET 10000 +# define GNULIB_defined_CODESET 1 +# endif + +# if !@HAVE_LANGINFO_T_FMT_AMPM@ +# define T_FMT_AMPM 10006 +# define GNULIB_defined_T_FMT_AMPM 1 +# endif + +# if !@HAVE_LANGINFO_ALTMON@ +# define ALTMON_1 10200 +# define ALTMON_2 (ALTMON_1 + 1) +# define ALTMON_3 (ALTMON_1 + 2) +# define ALTMON_4 (ALTMON_1 + 3) +# define ALTMON_5 (ALTMON_1 + 4) +# define ALTMON_6 (ALTMON_1 + 5) +# define ALTMON_7 (ALTMON_1 + 6) +# define ALTMON_8 (ALTMON_1 + 7) +# define ALTMON_9 (ALTMON_1 + 8) +# define ALTMON_10 (ALTMON_1 + 9) +# define ALTMON_11 (ALTMON_1 + 10) +# define ALTMON_12 (ALTMON_1 + 11) +# define GNULIB_defined_ALTMON 1 +# endif + +# if !@HAVE_LANGINFO_ERA@ +# define ERA 10047 +# define ERA_D_FMT 10048 +# define ERA_D_T_FMT 10049 +# define ERA_T_FMT 10050 +# define ALT_DIGITS 10051 +# define GNULIB_defined_ERA 1 +# endif + +# if !@HAVE_LANGINFO_YESEXPR@ +# define YESEXPR 10053 +# define NOEXPR 10054 +# define GNULIB_defined_YESEXPR 1 +# endif + +#endif + +/* The definitions of _GL_FUNCDECL_RPL etc. are copied here. */ + +/* The definition of _GL_WARN_ON_USE is copied here. */ + +/* Declare overridden functions. */ + + +/* Return a piece of locale dependent information. + Note: The difference between nl_langinfo (CODESET) and locale_charset= () + is that the latter normalizes the encoding names to GNU conventions. = */ + +#if @GNULIB_NL_LANGINFO@ +# if @REPLACE_NL_LANGINFO@ +# if !(defined __cplusplus && defined GNULIB_NAMESPACE) +# undef nl_langinfo +# define nl_langinfo rpl_nl_langinfo +# endif +_GL_FUNCDECL_RPL (nl_langinfo, char *, (nl_item item)); +_GL_CXXALIAS_RPL (nl_langinfo, char *, (nl_item item)); +# else +# if !@HAVE_NL_LANGINFO@ +_GL_FUNCDECL_SYS (nl_langinfo, char *, (nl_item item)); +# endif +_GL_CXXALIAS_SYS (nl_langinfo, char *, (nl_item item)); +# endif +_GL_CXXALIASWARN (nl_langinfo); +#elif defined GNULIB_POSIXCHECK +# undef nl_langinfo +# if HAVE_RAW_DECL_NL_LANGINFO +_GL_WARN_ON_USE (nl_langinfo, "nl_langinfo is not portable - " + "use gnulib module nl_langinfo for portability"); +# endif +#endif + + +#endif /* _@GUARD_PREFIX@_LANGINFO_H */ +#endif /* _@GUARD_PREFIX@_LANGINFO_H */ diff --git a/lib/localcharset.c b/lib/localcharset.c new file mode 100644 index 0000000000..58c5718c3e --- /dev/null +++ b/lib/localcharset.c @@ -0,0 +1,996 @@ +/* Determine a canonical name for the current locale's character encodin= g. + + Copyright (C) 2000-2006, 2008-2018 Free Software Foundation, Inc. + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 3, or (at your option) + any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License alo= ng + with this program; if not, see . */ + +/* Written by Bruno Haible . */ + +#include + +/* Specification. */ +#include "localcharset.h" + +#include +#include +#include +#include + +#if defined __APPLE__ && defined __MACH__ && HAVE_LANGINFO_CODESET +# define DARWIN7 /* Darwin 7 or newer, i.e. Mac OS X 10.3 or newer */ +#endif + +#if defined _WIN32 && !defined __CYGWIN__ +# define WINDOWS_NATIVE +# include +#endif + +#if defined __EMX__ +/* Assume EMX program runs on OS/2, even if compiled under DOS. */ +# ifndef OS2 +# define OS2 +# endif +#endif + +#if !defined WINDOWS_NATIVE +# if HAVE_LANGINFO_CODESET +# include +# else +# if 0 /* see comment regarding use of setlocale(), below */ +# include +# endif +# endif +# ifdef __CYGWIN__ +# define WIN32_LEAN_AND_MEAN +# include +# endif +#elif defined WINDOWS_NATIVE +# define WIN32_LEAN_AND_MEAN +# include +#endif +#if defined OS2 +# define INCL_DOS +# include +#endif + +/* For MB_CUR_MAX_L */ +#if defined DARWIN7 +# include +#endif + + +#if HAVE_LANGINFO_CODESET || defined WINDOWS_NATIVE || defined OS2 + +/* On these platforms, we use a mapping from non-canonical encoding name + to GNU canonical encoding name. */ + +/* With glibc-2.1 or newer, we don't need any canonicalization, + because glibc has iconv and both glibc and libiconv support all + GNU canonical names directly. */ +# if !((defined __GNU_LIBRARY__ && __GLIBC__ >=3D 2) || defined __UCLIBC= __) + +struct table_entry +{ + const char alias[11+1]; + const char canonical[11+1]; +}; + +/* Table of platform-dependent mappings, sorted in ascending order. */ +static const struct table_entry alias_table[] =3D + { +# if defined __FreeBSD__ /* FreeBSD *= / + /*{ "ARMSCII-8", "ARMSCII-8" },*/ + { "Big5", "BIG5" }, + { "C", "ASCII" }, + /*{ "CP1131", "CP1131" },*/ + /*{ "CP1251", "CP1251" },*/ + /*{ "CP866", "CP866" },*/ + /*{ "GB18030", "GB18030" },*/ + /*{ "GB2312", "GB2312" },*/ + /*{ "GBK", "GBK" },*/ + /*{ "ISCII-DEV", "?" },*/ + { "ISO8859-1", "ISO-8859-1" }, + { "ISO8859-13", "ISO-8859-13" }, + { "ISO8859-15", "ISO-8859-15" }, + { "ISO8859-2", "ISO-8859-2" }, + { "ISO8859-5", "ISO-8859-5" }, + { "ISO8859-7", "ISO-8859-7" }, + { "ISO8859-9", "ISO-8859-9" }, + /*{ "KOI8-R", "KOI8-R" },*/ + /*{ "KOI8-U", "KOI8-U" },*/ + { "SJIS", "SHIFT_JIS" }, + { "US-ASCII", "ASCII" }, + { "eucCN", "GB2312" }, + { "eucJP", "EUC-JP" }, + { "eucKR", "EUC-KR" } +# define alias_table_defined +# endif +# if defined __NetBSD__ /* NetBSD */ + { "646", "ASCII" }, + /*{ "ARMSCII-8", "ARMSCII-8" },*/ + /*{ "BIG5", "BIG5" },*/ + { "Big5-HKSCS", "BIG5-HKSCS" }, + /*{ "CP1251", "CP1251" },*/ + /*{ "CP866", "CP866" },*/ + /*{ "GB18030", "GB18030" },*/ + /*{ "GB2312", "GB2312" },*/ + { "ISO8859-1", "ISO-8859-1" }, + { "ISO8859-13", "ISO-8859-13" }, + { "ISO8859-15", "ISO-8859-15" }, + { "ISO8859-2", "ISO-8859-2" }, + { "ISO8859-4", "ISO-8859-4" }, + { "ISO8859-5", "ISO-8859-5" }, + { "ISO8859-7", "ISO-8859-7" }, + /*{ "KOI8-R", "KOI8-R" },*/ + /*{ "KOI8-U", "KOI8-U" },*/ + /*{ "PT154", "PT154" },*/ + { "SJIS", "SHIFT_JIS" }, + { "eucCN", "GB2312" }, + { "eucJP", "EUC-JP" }, + { "eucKR", "EUC-KR" }, + { "eucTW", "EUC-TW" } +# define alias_table_defined +# endif +# if defined __OpenBSD__ /* OpenBSD *= / + { "646", "ASCII" }, + { "ISO8859-1", "ISO-8859-1" }, + { "ISO8859-13", "ISO-8859-13" }, + { "ISO8859-15", "ISO-8859-15" }, + { "ISO8859-2", "ISO-8859-2" }, + { "ISO8859-4", "ISO-8859-4" }, + { "ISO8859-5", "ISO-8859-5" }, + { "ISO8859-7", "ISO-8859-7" } +# define alias_table_defined +# endif +# if defined __APPLE__ && defined __MACH__ /* Mac OS X = */ + /* Darwin 7.5 has nl_langinfo(CODESET), but sometimes its value is + useless: + - It returns the empty string when LANG is set to a locale of the + form ll_CC, although ll_CC/LC_CTYPE is a symlink to an UTF-8 + LC_CTYPE file. + - The environment variables LANG, LC_CTYPE, LC_ALL are not set by + the system; nl_langinfo(CODESET) returns "US-ASCII" in this cas= e. + - The documentation says: + "... all code that calls BSD system routines should ensure + that the const *char parameters of these routines are in UTF= -8 + encoding. All BSD system functions expect their string + parameters to be in UTF-8 encoding and nothing else." + It also says + "An additional caveat is that string parameters for files, + paths, and other file-system entities must be in canonical + UTF-8. In a canonical UTF-8 Unicode string, all decomposable + characters are decomposed ..." + but this is not true: You can pass non-decomposed UTF-8 strings + to file system functions, and it is the OS which will convert + them to decomposed UTF-8 before accessing the file system. + - The Apple Terminal application displays UTF-8 by default. + - However, other applications are free to use different encodings= : + - xterm uses ISO-8859-1 by default. + - TextEdit uses MacRoman by default. + We prefer UTF-8 over decomposed UTF-8-MAC because one should + minimize the use of decomposed Unicode. Unfortunately, through th= e + Darwin file system, decomposed UTF-8 strings are leaked into user + space nevertheless. + Then there are also the locales with encodings other than US-ASCI= I + and UTF-8. These locales can be occasionally useful to users (e.g= . + when grepping through ISO-8859-1 encoded text files), when all th= eir + file names are in US-ASCII. + */ + { "ARMSCII-8", "ARMSCII-8" }, + { "Big5", "BIG5" }, + { "Big5HKSCS", "BIG5-HKSCS" }, + { "CP1131", "CP1131" }, + { "CP1251", "CP1251" }, + { "CP866", "CP866" }, + { "CP949", "CP949" }, + { "GB18030", "GB18030" }, + { "GB2312", "GB2312" }, + { "GBK", "GBK" }, + /*{ "ISCII-DEV", "?" },*/ + { "ISO8859-1", "ISO-8859-1" }, + { "ISO8859-13", "ISO-8859-13" }, + { "ISO8859-15", "ISO-8859-15" }, + { "ISO8859-2", "ISO-8859-2" }, + { "ISO8859-4", "ISO-8859-4" }, + { "ISO8859-5", "ISO-8859-5" }, + { "ISO8859-7", "ISO-8859-7" }, + { "ISO8859-9", "ISO-8859-9" }, + { "KOI8-R", "KOI8-R" }, + { "KOI8-U", "KOI8-U" }, + { "PT154", "PT154" }, + { "SJIS", "SHIFT_JIS" }, + { "eucCN", "GB2312" }, + { "eucJP", "EUC-JP" }, + { "eucKR", "EUC-KR" } +# define alias_table_defined +# endif +# if defined _AIX /* AIX */ + /*{ "GBK", "GBK" },*/ + { "IBM-1046", "CP1046" }, + { "IBM-1124", "CP1124" }, + { "IBM-1129", "CP1129" }, + { "IBM-1252", "CP1252" }, + { "IBM-850", "CP850" }, + { "IBM-856", "CP856" }, + { "IBM-921", "ISO-8859-13" }, + { "IBM-922", "CP922" }, + { "IBM-932", "CP932" }, + { "IBM-943", "CP943" }, + { "IBM-eucCN", "GB2312" }, + { "IBM-eucJP", "EUC-JP" }, + { "IBM-eucKR", "EUC-KR" }, + { "IBM-eucTW", "EUC-TW" }, + { "ISO8859-1", "ISO-8859-1" }, + { "ISO8859-15", "ISO-8859-15" }, + { "ISO8859-2", "ISO-8859-2" }, + { "ISO8859-5", "ISO-8859-5" }, + { "ISO8859-6", "ISO-8859-6" }, + { "ISO8859-7", "ISO-8859-7" }, + { "ISO8859-8", "ISO-8859-8" }, + { "ISO8859-9", "ISO-8859-9" }, + { "TIS-620", "TIS-620" }, + /*{ "UTF-8", "UTF-8" },*/ + { "big5", "BIG5" } +# define alias_table_defined +# endif +# if defined __hpux /* HP-UX */ + { "SJIS", "SHIFT_JIS" }, + { "arabic8", "HP-ARABIC8" }, + { "big5", "BIG5" }, + { "cp1251", "CP1251" }, + { "eucJP", "EUC-JP" }, + { "eucKR", "EUC-KR" }, + { "eucTW", "EUC-TW" }, + { "gb18030", "GB18030" }, + { "greek8", "HP-GREEK8" }, + { "hebrew8", "HP-HEBREW8" }, + { "hkbig5", "BIG5-HKSCS" }, + { "hp15CN", "GB2312" }, + { "iso88591", "ISO-8859-1" }, + { "iso885913", "ISO-8859-13" }, + { "iso885915", "ISO-8859-15" }, + { "iso88592", "ISO-8859-2" }, + { "iso88594", "ISO-8859-4" }, + { "iso88595", "ISO-8859-5" }, + { "iso88596", "ISO-8859-6" }, + { "iso88597", "ISO-8859-7" }, + { "iso88598", "ISO-8859-8" }, + { "iso88599", "ISO-8859-9" }, + { "kana8", "HP-KANA8" }, + { "koi8r", "KOI8-R" }, + { "roman8", "HP-ROMAN8" }, + { "tis620", "TIS-620" }, + { "turkish8", "HP-TURKISH8" }, + { "utf8", "UTF-8" } +# define alias_table_defined +# endif +# if defined __sgi /* IRIX */ + { "ISO8859-1", "ISO-8859-1" }, + { "ISO8859-15", "ISO-8859-15" }, + { "ISO8859-2", "ISO-8859-2" }, + { "ISO8859-5", "ISO-8859-5" }, + { "ISO8859-7", "ISO-8859-7" }, + { "ISO8859-9", "ISO-8859-9" }, + { "eucCN", "GB2312" }, + { "eucJP", "EUC-JP" }, + { "eucKR", "EUC-KR" }, + { "eucTW", "EUC-TW" } +# define alias_table_defined +# endif +# if defined __osf__ /* OSF/1 */ + /*{ "GBK", "GBK" },*/ + { "ISO8859-1", "ISO-8859-1" }, + { "ISO8859-15", "ISO-8859-15" }, + { "ISO8859-2", "ISO-8859-2" }, + { "ISO8859-4", "ISO-8859-4" }, + { "ISO8859-5", "ISO-8859-5" }, + { "ISO8859-7", "ISO-8859-7" }, + { "ISO8859-8", "ISO-8859-8" }, + { "ISO8859-9", "ISO-8859-9" }, + { "KSC5601", "CP949" }, + { "SJIS", "SHIFT_JIS" }, + { "TACTIS", "TIS-620" }, + /*{ "UTF-8", "UTF-8" },*/ + { "big5", "BIG5" }, + { "cp850", "CP850" }, + { "dechanyu", "DEC-HANYU" }, + { "dechanzi", "GB2312" }, + { "deckanji", "DEC-KANJI" }, + { "deckorean", "EUC-KR" }, + { "eucJP", "EUC-JP" }, + { "eucKR", "EUC-KR" }, + { "eucTW", "EUC-TW" }, + { "sdeckanji", "EUC-JP" } +# define alias_table_defined +# endif +# if defined __sun /* Solaris *= / + { "5601", "EUC-KR" }, + { "646", "ASCII" }, + /*{ "BIG5", "BIG5" },*/ + { "Big5-HKSCS", "BIG5-HKSCS" }, + { "GB18030", "GB18030" }, + /*{ "GBK", "GBK" },*/ + { "ISO8859-1", "ISO-8859-1" }, + { "ISO8859-11", "TIS-620" }, + { "ISO8859-13", "ISO-8859-13" }, + { "ISO8859-15", "ISO-8859-15" }, + { "ISO8859-2", "ISO-8859-2" }, + { "ISO8859-3", "ISO-8859-3" }, + { "ISO8859-4", "ISO-8859-4" }, + { "ISO8859-5", "ISO-8859-5" }, + { "ISO8859-6", "ISO-8859-6" }, + { "ISO8859-7", "ISO-8859-7" }, + { "ISO8859-8", "ISO-8859-8" }, + { "ISO8859-9", "ISO-8859-9" }, + { "PCK", "SHIFT_JIS" }, + { "TIS620.2533", "TIS-620" }, + /*{ "UTF-8", "UTF-8" },*/ + { "ansi-1251", "CP1251" }, + { "cns11643", "EUC-TW" }, + { "eucJP", "EUC-JP" }, + { "gb2312", "GB2312" }, + { "koi8-r", "KOI8-R" } +# define alias_table_defined +# endif +# if defined __minix /* Minix */ + { "646", "ASCII" } +# define alias_table_defined +# endif +# if defined WINDOWS_NATIVE || defined __CYGWIN__ /* Windows *= / + { "CP1361", "JOHAB" }, + { "CP20127", "ASCII" }, + { "CP20866", "KOI8-R" }, + { "CP20936", "GB2312" }, + { "CP21866", "KOI8-RU" }, + { "CP28591", "ISO-8859-1" }, + { "CP28592", "ISO-8859-2" }, + { "CP28593", "ISO-8859-3" }, + { "CP28594", "ISO-8859-4" }, + { "CP28595", "ISO-8859-5" }, + { "CP28596", "ISO-8859-6" }, + { "CP28597", "ISO-8859-7" }, + { "CP28598", "ISO-8859-8" }, + { "CP28599", "ISO-8859-9" }, + { "CP28605", "ISO-8859-15" }, + { "CP38598", "ISO-8859-8" }, + { "CP51932", "EUC-JP" }, + { "CP51936", "GB2312" }, + { "CP51949", "EUC-KR" }, + { "CP51950", "EUC-TW" }, + { "CP54936", "GB18030" }, + { "CP65001", "UTF-8" }, + { "CP936", "GBK" } +# define alias_table_defined +# endif +# if defined OS2 /* OS/2 */ + /* The list of encodings is taken from "List of OS/2 Codepages" + by Alex Taylor: + . + See also "IBM Globalization - Code page identifiers": + .= */ + { "CP1089", "ISO-8859-6" }, + { "CP1208", "UTF-8" }, + { "CP1381", "GB2312" }, + { "CP1386", "GBK" }, + { "CP3372", "EUC-JP" }, + { "CP813", "ISO-8859-7" }, + { "CP819", "ISO-8859-1" }, + { "CP878", "KOI8-R" }, + { "CP912", "ISO-8859-2" }, + { "CP913", "ISO-8859-3" }, + { "CP914", "ISO-8859-4" }, + { "CP915", "ISO-8859-5" }, + { "CP916", "ISO-8859-8" }, + { "CP920", "ISO-8859-9" }, + { "CP921", "ISO-8859-13" }, + { "CP923", "ISO-8859-15" }, + { "CP954", "EUC-JP" }, + { "CP964", "EUC-TW" }, + { "CP970", "EUC-KR" } +# define alias_table_defined +# endif +# if defined VMS /* OpenVMS *= / + /* The list of encodings is taken from the OpenVMS 7.3-1 documentati= on + "Compaq C Run-Time Library Reference Manual for OpenVMS systems" + section 10.7 "Handling Different Character Sets". */ + { "DECHANYU", "DEC-HANYU" }, + { "DECHANZI", "GB2312" }, + { "DECKANJI", "DEC-KANJI" }, + { "DECKOREAN", "EUC-KR" }, + { "ISO8859-1", "ISO-8859-1" }, + { "ISO8859-2", "ISO-8859-2" }, + { "ISO8859-5", "ISO-8859-5" }, + { "ISO8859-7", "ISO-8859-7" }, + { "ISO8859-8", "ISO-8859-8" }, + { "ISO8859-9", "ISO-8859-9" }, + { "SDECKANJI", "EUC-JP" }, + { "SJIS", "SHIFT_JIS" }, + { "eucJP", "EUC-JP" }, + { "eucTW", "EUC-TW" } +# define alias_table_defined +# endif +# ifndef alias_table_defined + /* Just a dummy entry, to avoid a C syntax error. */ + { "", "" } +# endif + }; + +# endif + +#else + +/* On these platforms, we use a mapping from locale name to GNU canonica= l + encoding name. */ + +struct table_entry +{ + const char locale[17+1]; + const char canonical[11+1]; +}; + +/* Table of platform-dependent mappings, sorted in ascending order. */ +static const struct table_entry locale_table[] =3D + { +# if defined __FreeBSD__ /* FreeBSD 4= .2 */ + { "cs_CZ.ISO_8859-2", "ISO-8859-2" }, + { "da_DK.DIS_8859-15", "ISO-8859-15" }, + { "da_DK.ISO_8859-1", "ISO-8859-1" }, + { "de_AT.DIS_8859-15", "ISO-8859-15" }, + { "de_AT.ISO_8859-1", "ISO-8859-1" }, + { "de_CH.DIS_8859-15", "ISO-8859-15" }, + { "de_CH.ISO_8859-1", "ISO-8859-1" }, + { "de_DE.DIS_8859-15", "ISO-8859-15" }, + { "de_DE.ISO_8859-1", "ISO-8859-1" }, + { "en_AU.DIS_8859-15", "ISO-8859-15" }, + { "en_AU.ISO_8859-1", "ISO-8859-1" }, + { "en_CA.DIS_8859-15", "ISO-8859-15" }, + { "en_CA.ISO_8859-1", "ISO-8859-1" }, + { "en_GB.DIS_8859-15", "ISO-8859-15" }, + { "en_GB.ISO_8859-1", "ISO-8859-1" }, + { "en_US.DIS_8859-15", "ISO-8859-15" }, + { "en_US.ISO_8859-1", "ISO-8859-1" }, + { "es_ES.DIS_8859-15", "ISO-8859-15" }, + { "es_ES.ISO_8859-1", "ISO-8859-1" }, + { "fi_FI.DIS_8859-15", "ISO-8859-15" }, + { "fi_FI.ISO_8859-1", "ISO-8859-1" }, + { "fr_BE.DIS_8859-15", "ISO-8859-15" }, + { "fr_BE.ISO_8859-1", "ISO-8859-1" }, + { "fr_CA.DIS_8859-15", "ISO-8859-15" }, + { "fr_CA.ISO_8859-1", "ISO-8859-1" }, + { "fr_CH.DIS_8859-15", "ISO-8859-15" }, + { "fr_CH.ISO_8859-1", "ISO-8859-1" }, + { "fr_FR.DIS_8859-15", "ISO-8859-15" }, + { "fr_FR.ISO_8859-1", "ISO-8859-1" }, + { "hr_HR.ISO_8859-2", "ISO-8859-2" }, + { "hu_HU.ISO_8859-2", "ISO-8859-2" }, + { "is_IS.DIS_8859-15", "ISO-8859-15" }, + { "is_IS.ISO_8859-1", "ISO-8859-1" }, + { "it_CH.DIS_8859-15", "ISO-8859-15" }, + { "it_CH.ISO_8859-1", "ISO-8859-1" }, + { "it_IT.DIS_8859-15", "ISO-8859-15" }, + { "it_IT.ISO_8859-1", "ISO-8859-1" }, + { "ja_JP.EUC", "EUC-JP" }, + { "ja_JP.SJIS", "SHIFT_JIS" }, + { "ja_JP.Shift_JIS", "SHIFT_JIS" }, + { "ko_KR.EUC", "EUC-KR" }, + { "la_LN.ASCII", "ASCII" }, + { "la_LN.DIS_8859-15", "ISO-8859-15" }, + { "la_LN.ISO_8859-1", "ISO-8859-1" }, + { "la_LN.ISO_8859-2", "ISO-8859-2" }, + { "la_LN.ISO_8859-4", "ISO-8859-4" }, + { "lt_LN.ASCII", "ASCII" }, + { "lt_LN.DIS_8859-15", "ISO-8859-15" }, + { "lt_LN.ISO_8859-1", "ISO-8859-1" }, + { "lt_LN.ISO_8859-2", "ISO-8859-2" }, + { "lt_LT.ISO_8859-4", "ISO-8859-4" }, + { "nl_BE.DIS_8859-15", "ISO-8859-15" }, + { "nl_BE.ISO_8859-1", "ISO-8859-1" }, + { "nl_NL.DIS_8859-15", "ISO-8859-15" }, + { "nl_NL.ISO_8859-1", "ISO-8859-1" }, + { "no_NO.DIS_8859-15", "ISO-8859-15" }, + { "no_NO.ISO_8859-1", "ISO-8859-1" }, + { "pl_PL.ISO_8859-2", "ISO-8859-2" }, + { "pt_PT.DIS_8859-15", "ISO-8859-15" }, + { "pt_PT.ISO_8859-1", "ISO-8859-1" }, + { "ru_RU.CP866", "CP866" }, + { "ru_RU.ISO_8859-5", "ISO-8859-5" }, + { "ru_RU.KOI8-R", "KOI8-R" }, + { "ru_SU.CP866", "CP866" }, + { "ru_SU.ISO_8859-5", "ISO-8859-5" }, + { "ru_SU.KOI8-R", "KOI8-R" }, + { "sl_SI.ISO_8859-2", "ISO-8859-2" }, + { "sv_SE.DIS_8859-15", "ISO-8859-15" }, + { "sv_SE.ISO_8859-1", "ISO-8859-1" }, + { "uk_UA.KOI8-U", "KOI8-U" }, + { "zh_CN.EUC", "GB2312" }, + { "zh_TW.BIG5", "BIG5" }, + { "zh_TW.Big5", "BIG5" } +# define locale_table_defined +# endif +# if defined __DJGPP__ /* DOS / DJG= PP 2.03 */ + /* The encodings given here may not all be correct. + If you find that the encoding given for your language and + country is not the one your DOS machine actually uses, just + correct it in this file, and send a mail to + Juan Manuel Guerrero + and . */ + { "C", "ASCII" }, + { "ar", "CP864" }, + { "ar_AE", "CP864" }, + { "ar_DZ", "CP864" }, + { "ar_EG", "CP864" }, + { "ar_IQ", "CP864" }, + { "ar_IR", "CP864" }, + { "ar_JO", "CP864" }, + { "ar_KW", "CP864" }, + { "ar_MA", "CP864" }, + { "ar_OM", "CP864" }, + { "ar_QA", "CP864" }, + { "ar_SA", "CP864" }, + { "ar_SY", "CP864" }, + { "be", "CP866" }, + { "be_BE", "CP866" }, + { "bg", "CP866" }, /* not CP855 ?? */ + { "bg_BG", "CP866" }, /* not CP855 ?? */ + { "ca", "CP850" }, + { "ca_ES", "CP850" }, + { "cs", "CP852" }, + { "cs_CZ", "CP852" }, + { "da", "CP865" }, /* not CP850 ?? */ + { "da_DK", "CP865" }, /* not CP850 ?? */ + { "de", "CP850" }, + { "de_AT", "CP850" }, + { "de_CH", "CP850" }, + { "de_DE", "CP850" }, + { "el", "CP869" }, + { "el_GR", "CP869" }, + { "en", "CP850" }, + { "en_AU", "CP850" }, /* not CP437 ?? */ + { "en_CA", "CP850" }, + { "en_GB", "CP850" }, + { "en_NZ", "CP437" }, + { "en_US", "CP437" }, + { "en_ZA", "CP850" }, /* not CP437 ?? */ + { "eo", "CP850" }, + { "eo_EO", "CP850" }, + { "es", "CP850" }, + { "es_AR", "CP850" }, + { "es_BO", "CP850" }, + { "es_CL", "CP850" }, + { "es_CO", "CP850" }, + { "es_CR", "CP850" }, + { "es_CU", "CP850" }, + { "es_DO", "CP850" }, + { "es_EC", "CP850" }, + { "es_ES", "CP850" }, + { "es_GT", "CP850" }, + { "es_HN", "CP850" }, + { "es_MX", "CP850" }, + { "es_NI", "CP850" }, + { "es_PA", "CP850" }, + { "es_PE", "CP850" }, + { "es_PY", "CP850" }, + { "es_SV", "CP850" }, + { "es_UY", "CP850" }, + { "es_VE", "CP850" }, + { "et", "CP850" }, + { "et_EE", "CP850" }, + { "eu", "CP850" }, + { "eu_ES", "CP850" }, + { "fi", "CP850" }, + { "fi_FI", "CP850" }, + { "fr", "CP850" }, + { "fr_BE", "CP850" }, + { "fr_CA", "CP850" }, + { "fr_CH", "CP850" }, + { "fr_FR", "CP850" }, + { "ga", "CP850" }, + { "ga_IE", "CP850" }, + { "gd", "CP850" }, + { "gd_GB", "CP850" }, + { "gl", "CP850" }, + { "gl_ES", "CP850" }, + { "he", "CP862" }, + { "he_IL", "CP862" }, + { "hr", "CP852" }, + { "hr_HR", "CP852" }, + { "hu", "CP852" }, + { "hu_HU", "CP852" }, + { "id", "CP850" }, /* not CP437 ?? */ + { "id_ID", "CP850" }, /* not CP437 ?? */ + { "is", "CP861" }, /* not CP850 ?? */ + { "is_IS", "CP861" }, /* not CP850 ?? */ + { "it", "CP850" }, + { "it_CH", "CP850" }, + { "it_IT", "CP850" }, + { "ja", "CP932" }, + { "ja_JP", "CP932" }, + { "kr", "CP949" }, /* not CP934 ?? */ + { "kr_KR", "CP949" }, /* not CP934 ?? */ + { "lt", "CP775" }, + { "lt_LT", "CP775" }, + { "lv", "CP775" }, + { "lv_LV", "CP775" }, + { "mk", "CP866" }, /* not CP855 ?? */ + { "mk_MK", "CP866" }, /* not CP855 ?? */ + { "mt", "CP850" }, + { "mt_MT", "CP850" }, + { "nb", "CP865" }, /* not CP850 ?? */ + { "nb_NO", "CP865" }, /* not CP850 ?? */ + { "nl", "CP850" }, + { "nl_BE", "CP850" }, + { "nl_NL", "CP850" }, + { "nn", "CP865" }, /* not CP850 ?? */ + { "nn_NO", "CP865" }, /* not CP850 ?? */ + { "no", "CP865" }, /* not CP850 ?? */ + { "no_NO", "CP865" }, /* not CP850 ?? */ + { "pl", "CP852" }, + { "pl_PL", "CP852" }, + { "pt", "CP850" }, + { "pt_BR", "CP850" }, + { "pt_PT", "CP850" }, + { "ro", "CP852" }, + { "ro_RO", "CP852" }, + { "ru", "CP866" }, + { "ru_RU", "CP866" }, + { "sk", "CP852" }, + { "sk_SK", "CP852" }, + { "sl", "CP852" }, + { "sl_SI", "CP852" }, + { "sq", "CP852" }, + { "sq_AL", "CP852" }, + { "sr", "CP852" }, /* CP852 or CP866 or CP855 ?? */ + { "sr_CS", "CP852" }, /* CP852 or CP866 or CP855 ?? */ + { "sr_YU", "CP852" }, /* CP852 or CP866 or CP855 ?? */ + { "sv", "CP850" }, + { "sv_SE", "CP850" }, + { "th", "CP874" }, + { "th_TH", "CP874" }, + { "tr", "CP857" }, + { "tr_TR", "CP857" }, + { "uk", "CP1125" }, + { "uk_UA", "CP1125" }, + { "zh_CN", "GBK" }, + { "zh_TW", "CP950" } /* not CP938 ?? */ +# define locale_table_defined +# endif +# ifndef locale_table_defined + /* Just a dummy entry, to avoid a C syntax error. */ + { "", "" } +# endif + }; + +#endif + + +/* Determine the current locale's character encoding, and canonicalize i= t + into one of the canonical names listed in localcharset.h. + The result must not be freed; it is statically allocated. + If the canonical name cannot be determined, the result is a non-canon= ical + name. */ + +#ifdef STATIC +STATIC +#endif +const char * +locale_charset (void) +{ + const char *codeset; + +#if HAVE_LANGINFO_CODESET || defined WINDOWS_NATIVE || defined OS2 + +# if HAVE_LANGINFO_CODESET + + /* Most systems support nl_langinfo (CODESET) nowadays. */ + codeset =3D nl_langinfo (CODESET); + +# ifdef __CYGWIN__ + /* Cygwin < 1.7 does not have locales. nl_langinfo (CODESET) always + returns "US-ASCII". Return the suffix of the locale name from the + environment variables (if present) or the codepage as a number. */ + if (codeset !=3D NULL && strcmp (codeset, "US-ASCII") =3D=3D 0) + { + const char *locale; + static char buf[2 + 10 + 1]; + + locale =3D getenv ("LC_ALL"); + if (locale =3D=3D NULL || locale[0] =3D=3D '\0') + { + locale =3D getenv ("LC_CTYPE"); + if (locale =3D=3D NULL || locale[0] =3D=3D '\0') + locale =3D getenv ("LANG"); + } + if (locale !=3D NULL && locale[0] !=3D '\0') + { + /* If the locale name contains an encoding after the dot, retu= rn + it. */ + const char *dot =3D strchr (locale, '.'); + + if (dot !=3D NULL) + { + const char *modifier; + + dot++; + /* Look for the possible @... trailer and remove it, if an= y. */ + modifier =3D strchr (dot, '@'); + if (modifier =3D=3D NULL) + return dot; + if (modifier - dot < sizeof (buf)) + { + memcpy (buf, dot, modifier - dot); + buf [modifier - dot] =3D '\0'; + return buf; + } + } + } + + /* The Windows API has a function returning the locale's codepage = as a + number: GetACP(). This encoding is used by Cygwin, unless the = user + has set the environment variable CYGWIN=3Dcodepage:oem (which v= ery few + people do). + Output directed to console windows needs to be converted (to + GetOEMCP() if the console is using a raster font, or to + GetConsoleOutputCP() if it is using a TrueType font). Cygwin d= oes + this conversion transparently (see winsup/cygwin/fhandler_conso= le.cc), + converting to GetConsoleOutputCP(). This leads to correct resu= lts, + except when SetConsoleOutputCP has been called and a raster fon= t is + in use. */ + sprintf (buf, "CP%u", GetACP ()); + codeset =3D buf; + } +# endif + + if (codeset =3D=3D NULL) + /* The canonical name cannot be determined. */ + codeset =3D ""; + +# elif defined WINDOWS_NATIVE + + static char buf[2 + 10 + 1]; + + /* The Windows API has a function returning the locale's codepage as + a number, but the value doesn't change according to what the + 'setlocale' call specified. So we use it as a last resort, in + case the string returned by 'setlocale' doesn't specify the + codepage. */ + char *current_locale =3D setlocale (LC_ALL, NULL); + char *pdot; + + /* If they set different locales for different categories, + 'setlocale' will return a semi-colon separated list of locale + values. To make sure we use the correct one, we choose LC_CTYPE. = */ + if (strchr (current_locale, ';')) + current_locale =3D setlocale (LC_CTYPE, NULL); + + pdot =3D strrchr (current_locale, '.'); + if (pdot && 2 + strlen (pdot + 1) + 1 <=3D sizeof (buf)) + sprintf (buf, "CP%s", pdot + 1); + else + { + /* The Windows API has a function returning the locale's codepage = as a + number: GetACP(). + When the output goes to a console window, it needs to be provide= d in + GetOEMCP() encoding if the console is using a raster font, or in + GetConsoleOutputCP() encoding if it is using a TrueType font. + But in GUI programs and for output sent to files and pipes, GetA= CP() + encoding is the best bet. */ + sprintf (buf, "CP%u", GetACP ()); + } + codeset =3D buf; + +# elif defined OS2 + + const char *locale; + static char buf[2 + 10 + 1]; + ULONG cp[3]; + ULONG cplen; + + codeset =3D NULL; + + /* Allow user to override the codeset, as set in the operating system, + with standard language environment variables. */ + locale =3D getenv ("LC_ALL"); + if (locale =3D=3D NULL || locale[0] =3D=3D '\0') + { + locale =3D getenv ("LC_CTYPE"); + if (locale =3D=3D NULL || locale[0] =3D=3D '\0') + locale =3D getenv ("LANG"); + } + if (locale !=3D NULL && locale[0] !=3D '\0') + { + /* If the locale name contains an encoding after the dot, return i= t. */ + const char *dot =3D strchr (locale, '.'); + + if (dot !=3D NULL) + { + const char *modifier; + + dot++; + /* Look for the possible @... trailer and remove it, if any. = */ + modifier =3D strchr (dot, '@'); + if (modifier =3D=3D NULL) + return dot; + if (modifier - dot < sizeof (buf)) + { + memcpy (buf, dot, modifier - dot); + buf [modifier - dot] =3D '\0'; + return buf; + } + } + + /* For the POSIX locale, don't use the system's codepage. */ + if (strcmp (locale, "C") =3D=3D 0 || strcmp (locale, "POSIX") =3D=3D= 0) + codeset =3D ""; + } + + if (codeset =3D=3D NULL) + { + /* OS/2 has a function returning the locale's codepage as a number= . */ + if (DosQueryCp (sizeof (cp), cp, &cplen)) + codeset =3D ""; + else + { + sprintf (buf, "CP%u", cp[0]); + codeset =3D buf; + } + } + +# else + +# error "Add code for other platforms here." + +# endif + + /* Resolve alias. */ + { +# ifdef alias_table_defined + /* On some platforms, UTF-8 locales are the most frequently used one= s. + Speed up the common case and slow down the less common cases by + testing for this case first. */ +# if defined __OpenBSD__ || (defined __APPLE__ && defined __MACH__) || = defined __sun || defined __CYGWIN__ + if (strcmp (codeset, "UTF-8") =3D=3D 0) + goto done_table_lookup; + else +# endif + { + const struct table_entry * const table =3D alias_table; + size_t const table_size =3D + sizeof (alias_table) / sizeof (struct table_entry); + /* The table is sorted. Perform a binary search. */ + size_t hi =3D table_size; + size_t lo =3D 0; + while (lo < hi) + { + /* Invariant: + for i < lo, strcmp (table[i].alias, codeset) < 0, + for i >=3D hi, strcmp (table[i].alias, codeset) > 0. */ + size_t mid =3D (hi + lo) >> 1; /* >=3D lo, < hi */ + int cmp =3D strcmp (table[mid].alias, codeset); + if (cmp < 0) + lo =3D mid + 1; + else if (cmp > 0) + hi =3D mid; + else + { + /* Found an i with + strcmp (table[i].alias, codeset) =3D=3D 0. */ + codeset =3D table[mid].canonical; + goto done_table_lookup; + } + } + } + if (0) + done_table_lookup: ; + else +# endif + { + /* Did not find it in the table. */ + /* On Mac OS X, all modern locales use the UTF-8 encoding. + BeOS and Haiku have a single locale, and it has UTF-8 encodin= g. */ +# if (defined __APPLE__ && defined __MACH__) || defined __BEOS__ || defi= ned __HAIKU__ + codeset =3D "UTF-8"; +# else + /* Don't return an empty string. GNU libc and GNU libiconv inte= rpret + the empty string as denoting "the locale's character encoding= ", + thus GNU libiconv would call this function a second time. */ + if (codeset[0] =3D=3D '\0') + codeset =3D "ASCII"; +# endif + } + } + +#else + + /* On old systems which lack it, use setlocale or getenv. */ + const char *locale =3D NULL; + + /* But most old systems don't have a complete set of locales. Some + (like DJGPP) have only the C locale. Therefore we don't use setloc= ale + here; it would return "C" when it doesn't support the locale name t= he + user has set. */ +# if 0 + locale =3D setlocale (LC_CTYPE, NULL); +# endif + if (locale =3D=3D NULL || locale[0] =3D=3D '\0') + { + locale =3D getenv ("LC_ALL"); + if (locale =3D=3D NULL || locale[0] =3D=3D '\0') + { + locale =3D getenv ("LC_CTYPE"); + if (locale =3D=3D NULL || locale[0] =3D=3D '\0') + locale =3D getenv ("LANG"); + if (locale =3D=3D NULL) + locale =3D ""; + } + } + + /* Map locale name to canonical encoding name. */ + { +# ifdef locale_table_defined + const struct table_entry * const table =3D locale_table; + size_t const table_size =3D + sizeof (locale_table) / sizeof (struct table_entry); + /* The table is sorted. Perform a binary search. */ + size_t hi =3D table_size; + size_t lo =3D 0; + while (lo < hi) + { + /* Invariant: + for i < lo, strcmp (table[i].locale, locale) < 0, + for i >=3D hi, strcmp (table[i].locale, locale) > 0. */ + size_t mid =3D (hi + lo) >> 1; /* >=3D lo, < hi */ + int cmp =3D strcmp (table[mid].locale, locale); + if (cmp < 0) + lo =3D mid + 1; + else if (cmp > 0) + hi =3D mid; + else + { + /* Found an i with + strcmp (table[i].locale, locale) =3D=3D 0. */ + codeset =3D table[mid].canonical; + goto done_table_lookup; + } + } + if (0) + done_table_lookup: ; + else +# endif + { + /* Did not find it in the table. */ + /* On Mac OS X, all modern locales use the UTF-8 encoding. + BeOS and Haiku have a single locale, and it has UTF-8 encodin= g. */ +# if (defined __APPLE__ && defined __MACH__) || defined __BEOS__ || defi= ned __HAIKU__ + codeset =3D "UTF-8"; +# else + /* The canonical name cannot be determined. */ + /* Don't return an empty string. GNU libc and GNU libiconv inte= rpret + the empty string as denoting "the locale's character encoding= ", + thus GNU libiconv would call this function a second time. */ + codeset =3D "ASCII"; +# endif + } + } + +#endif + +#ifdef DARWIN7 + /* Mac OS X sets MB_CUR_MAX to 1 when LC_ALL=3DC, and "UTF-8" + (the default codeset) does not work when MB_CUR_MAX is 1. */ + if (strcmp (codeset, "UTF-8") =3D=3D 0 && MB_CUR_MAX_L (uselocale (NUL= L)) <=3D 1) + codeset =3D "ASCII"; +#endif + + return codeset; +} diff --git a/lib/localcharset.h b/lib/localcharset.h new file mode 100644 index 0000000000..e4ba2960ba --- /dev/null +++ b/lib/localcharset.h @@ -0,0 +1,134 @@ +/* Determine a canonical name for the current locale's character encodin= g. + Copyright (C) 2000-2003, 2009-2018 Free Software Foundation, Inc. + This file is part of the GNU CHARSET Library. + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 3, or (at your option) + any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License alo= ng + with this program; if not, see . */ + +#ifndef _LOCALCHARSET_H +#define _LOCALCHARSET_H + + +#ifdef __cplusplus +extern "C" { +#endif + + +/* Determine the current locale's character encoding, and canonicalize i= t + into one of the canonical names listed below. + The result must not be freed; it is statically allocated. + If the canonical name cannot be determined, the result is a non-canon= ical + name. */ +extern const char * locale_charset (void); + +/* About GNU canonical names for character encodings: + + Every canonical name must be supported by GNU libiconv. Support by G= NU libc + is also desirable. + + The name is case insensitive. Usually an upper case MIME charset nam= e is + preferred. + + The current list of these GNU canonical names is: + + name MIME? used by which systems + (darwin =3D Mac OS X, windows =3D na= tive Windows) + + ASCII, ANSI_X3.4-1968 glibc solaris freebsd netbsd darwin minix= cygwin + ISO-8859-1 Y glibc aix hpux irix osf solaris freebsd n= etbsd openbsd darwin cygwin + ISO-8859-2 Y glibc aix hpux irix osf solaris freebsd n= etbsd openbsd darwin cygwin + ISO-8859-3 Y glibc solaris cygwin + ISO-8859-4 Y hpux osf solaris freebsd netbsd openbsd d= arwin + ISO-8859-5 Y glibc aix hpux irix osf solaris freebsd n= etbsd openbsd darwin cygwin + ISO-8859-6 Y glibc aix hpux solaris cygwin + ISO-8859-7 Y glibc aix hpux irix osf solaris freebsd n= etbsd openbsd darwin cygwin + ISO-8859-8 Y glibc aix hpux osf solaris cygwin + ISO-8859-9 Y glibc aix hpux irix osf solaris freebsd d= arwin cygwin + ISO-8859-13 glibc hpux solaris freebsd netbsd openbsd= darwin cygwin + ISO-8859-14 glibc cygwin + ISO-8859-15 glibc aix irix osf solaris freebsd netbsd= openbsd darwin cygwin + KOI8-R Y glibc hpux solaris freebsd netbsd openbsd= darwin + KOI8-U Y glibc freebsd netbsd openbsd darwin cygwi= n + KOI8-T glibc + CP437 dos + CP775 dos + CP850 aix osf dos + CP852 dos + CP855 dos + CP856 aix + CP857 dos + CP861 dos + CP862 dos + CP864 dos + CP865 dos + CP866 freebsd netbsd openbsd darwin dos + CP869 dos + CP874 windows dos + CP922 aix + CP932 aix cygwin windows dos + CP943 aix + CP949 osf darwin windows dos + CP950 windows dos + CP1046 aix + CP1124 aix + CP1125 dos + CP1129 aix + CP1131 freebsd darwin + CP1250 windows + CP1251 glibc hpux solaris freebsd netbsd openbsd= darwin cygwin windows + CP1252 aix windows + CP1253 windows + CP1254 windows + CP1255 glibc windows + CP1256 windows + CP1257 windows + GB2312 Y glibc aix hpux irix solaris freebsd netbs= d darwin cygwin + EUC-JP Y glibc aix hpux irix osf solaris freebsd n= etbsd darwin cygwin + EUC-KR Y glibc aix hpux irix osf solaris freebsd n= etbsd darwin cygwin + EUC-TW glibc aix hpux irix osf solaris netbsd + BIG5 Y glibc aix hpux osf solaris freebsd netbsd= darwin cygwin + BIG5-HKSCS glibc hpux solaris netbsd darwin + GBK glibc aix osf solaris freebsd darwin cygw= in windows dos + GB18030 glibc hpux solaris freebsd netbsd darwin + SHIFT_JIS Y hpux osf solaris freebsd netbsd darwin + JOHAB glibc solaris windows + TIS-620 glibc aix hpux osf solaris cygwin + VISCII Y glibc + TCVN5712-1 glibc + ARMSCII-8 glibc freebsd netbsd darwin + GEORGIAN-PS glibc cygwin + PT154 glibc netbsd cygwin + HP-ROMAN8 hpux + HP-ARABIC8 hpux + HP-GREEK8 hpux + HP-HEBREW8 hpux + HP-TURKISH8 hpux + HP-KANA8 hpux + DEC-KANJI osf + DEC-HANYU osf + UTF-8 Y glibc aix hpux osf solaris netbsd darwin = cygwin + + Note: Names which are not marked as being a MIME name should not be u= sed in + Internet protocols for information interchange (mail, news, etc.). + + Note: ASCII and ANSI_X3.4-1968 are synonymous canonical names. Appli= cations + must understand both names and treat them as equivalent. + */ + + +#ifdef __cplusplus +} +#endif + + +#endif /* _LOCALCHARSET_H */ diff --git a/lib/locale.in.h b/lib/locale.in.h new file mode 100644 index 0000000000..804261dcad --- /dev/null +++ b/lib/locale.in.h @@ -0,0 +1,219 @@ +/* A POSIX . + Copyright (C) 2007-2018 Free Software Foundation, Inc. + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see = . */ + +#if __GNUC__ >=3D 3 +@PRAGMA_SYSTEM_HEADER@ +#endif +@PRAGMA_COLUMNS@ + +#if (defined _WIN32 && !defined __CYGWIN__ && defined __need_locale_t) \ + || defined _GL_ALREADY_INCLUDING_LOCALE_H + +/* Special invocation convention: + - Inside mingw header files, + - To handle Solaris header files (through Solaris 10) when combined + with gettext's libintl.h. */ + +#@INCLUDE_NEXT@ @NEXT_LOCALE_H@ + +#else +/* Normal invocation convention. */ + +#ifndef _@GUARD_PREFIX@_LOCALE_H + +#define _GL_ALREADY_INCLUDING_LOCALE_H + +/* The include_next requires a split double-inclusion guard. */ +#@INCLUDE_NEXT@ @NEXT_LOCALE_H@ + +#undef _GL_ALREADY_INCLUDING_LOCALE_H + +#ifndef _@GUARD_PREFIX@_LOCALE_H +#define _@GUARD_PREFIX@_LOCALE_H + +/* NetBSD 5.0 mis-defines NULL. */ +#include + +/* Mac OS X 10.5 defines the locale_t type in . */ +#if @HAVE_XLOCALE_H@ +# include +#endif + +/* The definitions of _GL_FUNCDECL_RPL etc. are copied here. */ + +/* The definition of _GL_ARG_NONNULL is copied here. */ + +/* The definition of _GL_WARN_ON_USE is copied here. */ + +/* The LC_MESSAGES locale category is specified in POSIX, but not in ISO= C. + On systems that don't define it, use the same value as GNU libintl. = */ +#if !defined LC_MESSAGES +# define LC_MESSAGES 1729 +#endif + +/* Bionic libc's 'struct lconv' is just a dummy. */ +#if @REPLACE_STRUCT_LCONV@ +# define lconv rpl_lconv +struct lconv +{ + /* All 'char *' are actually 'const char *'. */ + + /* Members that depend on the LC_NUMERIC category of the locale. See + */ + + /* Symbol used as decimal point. */ + char *decimal_point; + /* Symbol used to separate groups of digits to the left of the decimal + point. */ + char *thousands_sep; + /* Definition of the size of groups of digits to the left of the decim= al + point. */ + char *grouping; + + /* Members that depend on the LC_MONETARY category of the locale. See + */ + + /* Symbol used as decimal point. */ + char *mon_decimal_point; + /* Symbol used to separate groups of digits to the left of the decimal + point. */ + char *mon_thousands_sep; + /* Definition of the size of groups of digits to the left of the decim= al + point. */ + char *mon_grouping; + /* Sign used to indicate a value >=3D 0. */ + char *positive_sign; + /* Sign used to indicate a value < 0. */ + char *negative_sign; + + /* For formatting local currency. */ + /* Currency symbol (3 characters) followed by separator (1 character).= */ + char *currency_symbol; + /* Number of digits after the decimal point. */ + char frac_digits; + /* For values >=3D 0: 1 if the currency symbol precedes the number, 0 = if it + comes after the number. */ + char p_cs_precedes; + /* For values >=3D 0: Position of the sign. */ + char p_sign_posn; + /* For values >=3D 0: Placement of spaces between currency symbol, sig= n, and + number. */ + char p_sep_by_space; + /* For values < 0: 1 if the currency symbol precedes the number, 0 if = it + comes after the number. */ + char n_cs_precedes; + /* For values < 0: Position of the sign. */ + char n_sign_posn; + /* For values < 0: Placement of spaces between currency symbol, sign, = and + number. */ + char n_sep_by_space; + + /* For formatting international currency. */ + /* Currency symbol (3 characters) followed by separator (1 character).= */ + char *int_curr_symbol; + /* Number of digits after the decimal point. */ + char int_frac_digits; + /* For values >=3D 0: 1 if the currency symbol precedes the number, 0 = if it + comes after the number. */ + char int_p_cs_precedes; + /* For values >=3D 0: Position of the sign. */ + char int_p_sign_posn; + /* For values >=3D 0: Placement of spaces between currency symbol, sig= n, and + number. */ + char int_p_sep_by_space; + /* For values < 0: 1 if the currency symbol precedes the number, 0 if = it + comes after the number. */ + char int_n_cs_precedes; + /* For values < 0: Position of the sign. */ + char int_n_sign_posn; + /* For values < 0: Placement of spaces between currency symbol, sign, = and + number. */ + char int_n_sep_by_space; +}; +#endif + +#if @GNULIB_LOCALECONV@ +# if @REPLACE_LOCALECONV@ +# if !(defined __cplusplus && defined GNULIB_NAMESPACE) +# undef localeconv +# define localeconv rpl_localeconv +# endif +_GL_FUNCDECL_RPL (localeconv, struct lconv *, (void)); +_GL_CXXALIAS_RPL (localeconv, struct lconv *, (void)); +# else +_GL_CXXALIAS_SYS (localeconv, struct lconv *, (void)); +# endif +_GL_CXXALIASWARN (localeconv); +#elif @REPLACE_STRUCT_LCONV@ +# undef localeconv +# define localeconv localeconv_used_without_requesting_gnulib_module_loc= aleconv +#elif defined GNULIB_POSIXCHECK +# undef localeconv +# if HAVE_RAW_DECL_LOCALECONV +_GL_WARN_ON_USE (localeconv, + "localeconv returns too few information on some platfor= ms - " + "use gnulib module localeconv for portability"); +# endif +#endif + +#if @GNULIB_SETLOCALE@ +# if @REPLACE_SETLOCALE@ +# if !(defined __cplusplus && defined GNULIB_NAMESPACE) +# undef setlocale +# define setlocale rpl_setlocale +# define GNULIB_defined_setlocale 1 +# endif +_GL_FUNCDECL_RPL (setlocale, char *, (int category, const char *locale))= ; +_GL_CXXALIAS_RPL (setlocale, char *, (int category, const char *locale))= ; +# else +_GL_CXXALIAS_SYS (setlocale, char *, (int category, const char *locale))= ; +# endif +_GL_CXXALIASWARN (setlocale); +#elif defined GNULIB_POSIXCHECK +# undef setlocale +# if HAVE_RAW_DECL_SETLOCALE +_GL_WARN_ON_USE (setlocale, "setlocale works differently on native Windo= ws - " + "use gnulib module setlocale for portability"); +# endif +#endif + +#if @GNULIB_DUPLOCALE@ +# if @REPLACE_DUPLOCALE@ +# if !(defined __cplusplus && defined GNULIB_NAMESPACE) +# undef duplocale +# define duplocale rpl_duplocale +# endif +_GL_FUNCDECL_RPL (duplocale, locale_t, (locale_t locale) _GL_ARG_NONNULL= ((1))); +_GL_CXXALIAS_RPL (duplocale, locale_t, (locale_t locale)); +# else +# if @HAVE_DUPLOCALE@ +_GL_CXXALIAS_SYS (duplocale, locale_t, (locale_t locale)); +# endif +# endif +# if @HAVE_DUPLOCALE@ +_GL_CXXALIASWARN (duplocale); +# endif +#elif defined GNULIB_POSIXCHECK +# undef duplocale +# if HAVE_RAW_DECL_DUPLOCALE +_GL_WARN_ON_USE (duplocale, "duplocale is buggy on some glibc systems - = " + "use gnulib module duplocale for portability"); +# endif +#endif + +#endif /* _@GUARD_PREFIX@_LOCALE_H */ +#endif /* _@GUARD_PREFIX@_LOCALE_H */ +#endif /* !(__need_locale_t || _GL_ALREADY_INCLUDING_LOCALE_H) */ diff --git a/lib/localeconv.c b/lib/localeconv.c new file mode 100644 index 0000000000..87cfaceeae --- /dev/null +++ b/lib/localeconv.c @@ -0,0 +1,103 @@ +/* Query locale dependent information for formatting numbers. + Copyright (C) 2012-2018 Free Software Foundation, Inc. + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see = . */ + +#include + +/* Specification. */ +#include + +#if HAVE_STRUCT_LCONV_DECIMAL_POINT + +/* Override for platforms where 'struct lconv' lacks the int_p_*, int_n_= * + members. */ + +struct lconv * +localeconv (void) +{ + static struct lconv result; +# undef lconv +# undef localeconv + struct lconv *sys_result =3D localeconv (); + + result.decimal_point =3D sys_result->decimal_point; + result.thousands_sep =3D sys_result->thousands_sep; + result.grouping =3D sys_result->grouping; + result.mon_decimal_point =3D sys_result->mon_decimal_point; + result.mon_thousands_sep =3D sys_result->mon_thousands_sep; + result.mon_grouping =3D sys_result->mon_grouping; + result.positive_sign =3D sys_result->positive_sign; + result.negative_sign =3D sys_result->negative_sign; + result.currency_symbol =3D sys_result->currency_symbol; + result.frac_digits =3D sys_result->frac_digits; + result.p_cs_precedes =3D sys_result->p_cs_precedes; + result.p_sign_posn =3D sys_result->p_sign_posn; + result.p_sep_by_space =3D sys_result->p_sep_by_space; + result.n_cs_precedes =3D sys_result->n_cs_precedes; + result.n_sign_posn =3D sys_result->n_sign_posn; + result.n_sep_by_space =3D sys_result->n_sep_by_space; + result.int_curr_symbol =3D sys_result->int_curr_symbol; + result.int_frac_digits =3D sys_result->int_frac_digits; + result.int_p_cs_precedes =3D sys_result->p_cs_precedes; + result.int_p_sign_posn =3D sys_result->p_sign_posn; + result.int_p_sep_by_space =3D sys_result->p_sep_by_space; + result.int_n_cs_precedes =3D sys_result->n_cs_precedes; + result.int_n_sign_posn =3D sys_result->n_sign_posn; + result.int_n_sep_by_space =3D sys_result->n_sep_by_space; + + return &result; +} + +#else + +/* Override for platforms where 'struct lconv' is a dummy. */ + +# include + +struct lconv * +localeconv (void) +{ + static /*const*/ struct lconv result =3D + { + /* decimal_point */ ".", + /* thousands_sep */ "", + /* grouping */ "", + /* mon_decimal_point */ "", + /* mon_thousands_sep */ "", + /* mon_grouping */ "", + /* positive_sign */ "", + /* negative_sign */ "", + /* currency_symbol */ "", + /* frac_digits */ CHAR_MAX, + /* p_cs_precedes */ CHAR_MAX, + /* p_sign_posn */ CHAR_MAX, + /* p_sep_by_space */ CHAR_MAX, + /* n_cs_precedes */ CHAR_MAX, + /* n_sign_posn */ CHAR_MAX, + /* n_sep_by_space */ CHAR_MAX, + /* int_curr_symbol */ "", + /* int_frac_digits */ CHAR_MAX, + /* int_p_cs_precedes */ CHAR_MAX, + /* int_p_sign_posn */ CHAR_MAX, + /* int_p_sep_by_space */ CHAR_MAX, + /* int_n_cs_precedes */ CHAR_MAX, + /* int_n_sign_posn */ CHAR_MAX, + /* int_n_sep_by_space */ CHAR_MAX + }; + + return &result; +} + +#endif diff --git a/lib/mbrtowc.c b/lib/mbrtowc.c new file mode 100644 index 0000000000..2f6df287a5 --- /dev/null +++ b/lib/mbrtowc.c @@ -0,0 +1,458 @@ +/* Convert multibyte character to wide character. + Copyright (C) 1999-2002, 2005-2018 Free Software Foundation, Inc. + Written by Bruno Haible , 2008. + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see = . */ + +#include + +/* Specification. */ +#include + +#if C_LOCALE_MAYBE_EILSEQ +# include "hard-locale.h" +# include +#endif + +#if GNULIB_defined_mbstate_t +/* Implement mbrtowc() on top of mbtowc(). */ + +# include +# include + +# include "localcharset.h" +# include "streq.h" +# include "verify.h" + +# ifndef FALLTHROUGH +# if __GNUC__ < 7 +# define FALLTHROUGH ((void) 0) +# else +# define FALLTHROUGH __attribute__ ((__fallthrough__)) +# endif +# endif + +/* Returns a classification of special values of the encoding of the cur= rent + locale. */ +typedef enum { + enc_other, /* other */ + enc_utf8, /* UTF-8 */ + enc_eucjp, /* EUC-JP */ + enc_94, /* EUC-KR, GB2312, BIG5 */ + enc_euctw, /* EUC-TW */ + enc_gb18030, /* GB18030 */ + enc_sjis /* SJIS */ +} enc_t; +static inline enc_t +locale_enc (void) +{ + const char *encoding =3D locale_charset (); + if (STREQ_OPT (encoding, "UTF-8", 'U', 'T', 'F', '-', '8', 0, 0, 0, 0)= ) + return enc_utf8; + if (STREQ_OPT (encoding, "EUC-JP", 'E', 'U', 'C', '-', 'J', 'P', 0, 0,= 0)) + return enc_eucjp; + if (STREQ_OPT (encoding, "EUC-KR", 'E', 'U', 'C', '-', 'K', 'R', 0, 0,= 0) + || STREQ_OPT (encoding, "GB2312", 'G', 'B', '2', '3', '1', '2', 0,= 0, 0) + || STREQ_OPT (encoding, "BIG5", 'B', 'I', 'G', '5', 0, 0, 0, 0, 0)= ) + return enc_94; + if (STREQ_OPT (encoding, "EUC-TW", 'E', 'U', 'C', '-', 'T', 'W', 0, 0,= 0)) + return enc_euctw; + if (STREQ_OPT (encoding, "GB18030", 'G', 'B', '1', '8', '0', '3', '0',= 0, 0)) + return enc_gb18030; + if (STREQ_OPT (encoding, "SJIS", 'S', 'J', 'I', 'S', 0, 0, 0, 0, 0)) + return enc_sjis; + return enc_other; +} + +#if GNULIB_WCHAR_SINGLE +/* When we know that the locale does not change, provide a speedup by + caching the value of locale_enc. */ +static int cached_locale_enc =3D -1; +static inline enc_t +locale_enc_cached (void) +{ + if (cached_locale_enc < 0) + cached_locale_enc =3D locale_enc (); + return cached_locale_enc; +} +#else +/* By default, don't make assumptions, hence no caching. */ +# define locale_enc_cached locale_enc +#endif + +verify (sizeof (mbstate_t) >=3D 4); + +static char internal_state[4]; + +size_t +mbrtowc (wchar_t *pwc, const char *s, size_t n, mbstate_t *ps) +{ + char *pstate =3D (char *)ps; + + if (s =3D=3D NULL) + { + pwc =3D NULL; + s =3D ""; + n =3D 1; + } + + if (n =3D=3D 0) + return (size_t)(-2); + + /* Here n > 0. */ + + if (pstate =3D=3D NULL) + pstate =3D internal_state; + + { + size_t nstate =3D pstate[0]; + char buf[4]; + const char *p; + size_t m; + + switch (nstate) + { + case 0: + p =3D s; + m =3D n; + break; + case 3: + buf[2] =3D pstate[3]; + FALLTHROUGH; + case 2: + buf[1] =3D pstate[2]; + FALLTHROUGH; + case 1: + buf[0] =3D pstate[1]; + p =3D buf; + m =3D nstate; + buf[m++] =3D s[0]; + if (n >=3D 2 && m < 4) + { + buf[m++] =3D s[1]; + if (n >=3D 3 && m < 4) + buf[m++] =3D s[2]; + } + break; + default: + errno =3D EINVAL; + return (size_t)(-1); + } + + /* Here m > 0. */ + +# if __GLIBC__ || defined __UCLIBC__ + /* Work around bug */ + mbtowc (NULL, NULL, 0); +# endif + { + int res =3D mbtowc (pwc, p, m); + + if (res >=3D 0) + { + if (pwc !=3D NULL && ((*pwc =3D=3D 0) !=3D (res =3D=3D 0))) + abort (); + if (nstate >=3D (res > 0 ? res : 1)) + abort (); + res -=3D nstate; + pstate[0] =3D 0; + return res; + } + + /* mbtowc does not distinguish between invalid and incomplete mult= ibyte + sequences. But mbrtowc needs to make this distinction. + There are two possible approaches: + - Use iconv() and its return value. + - Use built-in knowledge about the possible encodings. + Given the low quality of implementation of iconv() on the syste= ms that + lack mbrtowc(), we use the second approach. + The possible encodings are: + - 8-bit encodings, + - EUC-JP, EUC-KR, GB2312, EUC-TW, BIG5, GB18030, SJIS, + - UTF-8. + Use specialized code for each. */ + if (m >=3D 4 || m >=3D MB_CUR_MAX) + goto invalid; + /* Here MB_CUR_MAX > 1 and 0 < m < 4. */ + switch (locale_enc_cached ()) + { + case enc_utf8: /* UTF-8 */ + { + /* Cf. unistr/u8-mblen.c. */ + unsigned char c =3D (unsigned char) p[0]; + + if (c >=3D 0xc2) + { + if (c < 0xe0) + { + if (m =3D=3D 1) + goto incomplete; + } + else if (c < 0xf0) + { + if (m =3D=3D 1) + goto incomplete; + if (m =3D=3D 2) + { + unsigned char c2 =3D (unsigned char) p[1]; + + if ((c2 ^ 0x80) < 0x40 + && (c >=3D 0xe1 || c2 >=3D 0xa0) + && (c !=3D 0xed || c2 < 0xa0)) + goto incomplete; + } + } + else if (c <=3D 0xf4) + { + if (m =3D=3D 1) + goto incomplete; + else /* m =3D=3D 2 || m =3D=3D 3 */ + { + unsigned char c2 =3D (unsigned char) p[1]; + + if ((c2 ^ 0x80) < 0x40 + && (c >=3D 0xf1 || c2 >=3D 0x90) + && (c < 0xf4 || (c =3D=3D 0xf4 && c2 < 0x90)= )) + { + if (m =3D=3D 2) + goto incomplete; + else /* m =3D=3D 3 */ + { + unsigned char c3 =3D (unsigned char) p[2= ]; + + if ((c3 ^ 0x80) < 0x40) + goto incomplete; + } + } + } + } + } + goto invalid; + } + + /* As a reference for this code, you can use the GNU libiconv + implementation. Look for uses of the RET_TOOFEW macro. */ + + case enc_eucjp: /* EUC-JP */ + { + if (m =3D=3D 1) + { + unsigned char c =3D (unsigned char) p[0]; + + if ((c >=3D 0xa1 && c < 0xff) || c =3D=3D 0x8e || c =3D=3D= 0x8f) + goto incomplete; + } + if (m =3D=3D 2) + { + unsigned char c =3D (unsigned char) p[0]; + + if (c =3D=3D 0x8f) + { + unsigned char c2 =3D (unsigned char) p[1]; + + if (c2 >=3D 0xa1 && c2 < 0xff) + goto incomplete; + } + } + goto invalid; + } + + case enc_94: /* EUC-KR, GB2312, BIG5 */ + { + if (m =3D=3D 1) + { + unsigned char c =3D (unsigned char) p[0]; + + if (c >=3D 0xa1 && c < 0xff) + goto incomplete; + } + goto invalid; + } + + case enc_euctw: /* EUC-TW */ + { + if (m =3D=3D 1) + { + unsigned char c =3D (unsigned char) p[0]; + + if ((c >=3D 0xa1 && c < 0xff) || c =3D=3D 0x8e) + goto incomplete; + } + else /* m =3D=3D 2 || m =3D=3D 3 */ + { + unsigned char c =3D (unsigned char) p[0]; + + if (c =3D=3D 0x8e) + goto incomplete; + } + goto invalid; + } + + case enc_gb18030: /* GB18030 */ + { + if (m =3D=3D 1) + { + unsigned char c =3D (unsigned char) p[0]; + + if ((c >=3D 0x90 && c <=3D 0xe3) || (c >=3D 0xf8 && c <=3D= 0xfe)) + goto incomplete; + } + else /* m =3D=3D 2 || m =3D=3D 3 */ + { + unsigned char c =3D (unsigned char) p[0]; + + if (c >=3D 0x90 && c <=3D 0xe3) + { + unsigned char c2 =3D (unsigned char) p[1]; + + if (c2 >=3D 0x30 && c2 <=3D 0x39) + { + if (m =3D=3D 2) + goto incomplete; + else /* m =3D=3D 3 */ + { + unsigned char c3 =3D (unsigned char) p[2]; + + if (c3 >=3D 0x81 && c3 <=3D 0xfe) + goto incomplete; + } + } + } + } + goto invalid; + } + + case enc_sjis: /* SJIS */ + { + if (m =3D=3D 1) + { + unsigned char c =3D (unsigned char) p[0]; + + if ((c >=3D 0x81 && c <=3D 0x9f) || (c >=3D 0xe0 && c <=3D= 0xea) + || (c >=3D 0xf0 && c <=3D 0xf9)) + goto incomplete; + } + goto invalid; + } + + default: + /* An unknown multibyte encoding. */ + goto incomplete; + } + + incomplete: + { + size_t k =3D nstate; + /* Here 0 <=3D k < m < 4. */ + pstate[++k] =3D s[0]; + if (k < m) + { + pstate[++k] =3D s[1]; + if (k < m) + pstate[++k] =3D s[2]; + } + if (k !=3D m) + abort (); + } + pstate[0] =3D m; + return (size_t)(-2); + + invalid: + errno =3D EILSEQ; + /* The conversion state is undefined, says POSIX. */ + return (size_t)(-1); + } + } +} + +#else +/* Override the system's mbrtowc() function. */ + +# undef mbrtowc + +size_t +rpl_mbrtowc (wchar_t *pwc, const char *s, size_t n, mbstate_t *ps) +{ + size_t ret; + wchar_t wc; + +# if MBRTOWC_NULL_ARG2_BUG || MBRTOWC_RETVAL_BUG || MBRTOWC_EMPTY_INPUT_= BUG + if (s =3D=3D NULL) + { + pwc =3D NULL; + s =3D ""; + n =3D 1; + } +# endif + +# if MBRTOWC_EMPTY_INPUT_BUG + if (n =3D=3D 0) + return (size_t) -2; +# endif + + if (! pwc) + pwc =3D &wc; + +# if MBRTOWC_RETVAL_BUG + { + static mbstate_t internal_state; + + /* Override mbrtowc's internal state. We cannot call mbsinit() on t= he + hidden internal state, but we can call it on our variable. */ + if (ps =3D=3D NULL) + ps =3D &internal_state; + + if (!mbsinit (ps)) + { + /* Parse the rest of the multibyte character byte for byte. */ + size_t count =3D 0; + for (; n > 0; s++, n--) + { + ret =3D mbrtowc (&wc, s, 1, ps); + + if (ret =3D=3D (size_t)(-1)) + return (size_t)(-1); + count++; + if (ret !=3D (size_t)(-2)) + { + /* The multibyte character has been completed. */ + *pwc =3D wc; + return (wc =3D=3D 0 ? 0 : count); + } + } + return (size_t)(-2); + } + } +# endif + + ret =3D mbrtowc (pwc, s, n, ps); + +# if MBRTOWC_NUL_RETVAL_BUG + if (ret < (size_t) -2 && !*pwc) + return 0; +# endif + +# if C_LOCALE_MAYBE_EILSEQ + if ((size_t) -2 <=3D ret && n !=3D 0 && ! hard_locale (LC_CTYPE)) + { + unsigned char uc =3D *s; + *pwc =3D uc; + return 1; + } +# endif + + return ret; +} + +#endif diff --git a/lib/mbsinit.c b/lib/mbsinit.c new file mode 100644 index 0000000000..e23a5ad318 --- /dev/null +++ b/lib/mbsinit.c @@ -0,0 +1,73 @@ +/* Test for initial conversion state. + Copyright (C) 2008-2018 Free Software Foundation, Inc. + Written by Bruno Haible , 2008. + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see = . */ + +#include + +/* Specification. */ +#include + +#include "verify.h" + +#if GNULIB_defined_mbstate_t + +/* Platforms that lack mbsinit() also lack mbrlen(), mbrtowc(), mbsrtowc= s() + and wcrtomb(), wcsrtombs(). + We assume that + - sizeof (mbstate_t) >=3D 4, + - only stateless encodings are supported (such as UTF-8 and EUC-JP,= but + not ISO-2022 variants), + - for each encoding, the number of bytes for a wide character is <=3D= 4. + (This maximum is attained for UTF-8, GB18030, EUC-TW.) + We define the meaning of mbstate_t as follows: + - In mb -> wc direction, mbstate_t's first byte contains the number= of + buffered bytes (in the range 0..3), followed by up to 3 buffered = bytes. + See mbrtowc.c. + - In wc -> mb direction, mbstate_t contains no information. In othe= r + words, it is always in the initial state. */ + +verify (sizeof (mbstate_t) >=3D 4); + +int +mbsinit (const mbstate_t *ps) +{ + const char *pstate =3D (const char *)ps; + + return pstate =3D=3D NULL || pstate[0] =3D=3D 0; +} + +#else + +int +mbsinit (const mbstate_t *ps) +{ +# if defined _WIN32 && !defined __CYGWIN__ + /* Native Windows. */ +# ifdef __MINGW32__ + /* On mingw, 'mbstate_t' is defined as 'int'. */ + return ps =3D=3D NULL || *ps =3D=3D 0; +# else + /* MSVC defines 'mbstate_t' as an 8-byte struct; the first 4-bytes mat= ter. */ + return ps =3D=3D NULL || *(const unsigned int *)ps =3D=3D 0; +# endif +# else + /* Minix, HP-UX 11.00, Solaris 2.6, Interix, ... */ + /* Maybe this definition works, maybe not... */ + return ps =3D=3D NULL || *(const char *)ps =3D=3D 0; +# endif +} + +#endif diff --git a/lib/mbtowc-impl.h b/lib/mbtowc-impl.h new file mode 100644 index 0000000000..633832f5fe --- /dev/null +++ b/lib/mbtowc-impl.h @@ -0,0 +1,44 @@ +/* Convert multibyte character to wide character. + Copyright (C) 2011-2018 Free Software Foundation, Inc. + Written by Bruno Haible , 2011. + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see = . */ + +/* We don't need a static internal state, because the encoding is not st= ate + dependent, and when mbrtowc returns (size_t)(-2). we throw the result + away. */ + +int +mbtowc (wchar_t *pwc, const char *s, size_t n) +{ + if (s =3D=3D NULL) + return 0; + else + { + mbstate_t state; + wchar_t wc; + size_t result; + + memset (&state, 0, sizeof (mbstate_t)); + result =3D mbrtowc (&wc, s, n, &state); + if (result =3D=3D (size_t)-1 || result =3D=3D (size_t)-2) + { + errno =3D EILSEQ; + return -1; + } + if (pwc !=3D NULL) + *pwc =3D wc; + return (wc =3D=3D 0 ? 0 : result); + } +} diff --git a/lib/mbtowc.c b/lib/mbtowc.c new file mode 100644 index 0000000000..a212b221fe --- /dev/null +++ b/lib/mbtowc.c @@ -0,0 +1,26 @@ +/* Convert multibyte character to wide character. + Copyright (C) 2011-2018 Free Software Foundation, Inc. + Written by Bruno Haible , 2011. + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see = . */ + +#include + +#include + +#include +#include +#include + +#include "mbtowc-impl.h" diff --git a/lib/nl_langinfo.c b/lib/nl_langinfo.c new file mode 100644 index 0000000000..ea26730ecc --- /dev/null +++ b/lib/nl_langinfo.c @@ -0,0 +1,366 @@ +/* nl_langinfo() replacement: query locale dependent information. + + Copyright (C) 2007-2018 Free Software Foundation, Inc. + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see = . */ + +#include + +/* Specification. */ +#include + +#include +#include +#if defined _WIN32 && ! defined __CYGWIN__ +# define WIN32_LEAN_AND_MEAN /* avoid including junk */ +# include +# include +#endif + +#if !REPLACE_NL_LANGINFO || GNULIB_defined_CODESET +/* Return the codeset of the current locale, if this is easily deducible= . + Otherwise, return "". */ +static char * +ctype_codeset (void) +{ + static char buf[2 + 10 + 1]; + char const *locale =3D setlocale (LC_CTYPE, NULL); + char *codeset =3D buf; + size_t codesetlen; + codeset[0] =3D '\0'; + + if (locale && locale[0]) + { + /* If the locale name contains an encoding after the dot, return i= t. */ + char *dot =3D strchr (locale, '.'); + + if (dot) + { + /* Look for the possible @... trailer and remove it, if any. = */ + char *codeset_start =3D dot + 1; + char const *modifier =3D strchr (codeset_start, '@'); + + if (! modifier) + codeset =3D codeset_start; + else + { + codesetlen =3D modifier - codeset_start; + if (codesetlen < sizeof buf) + { + codeset =3D memcpy (buf, codeset_start, codesetlen); + codeset[codesetlen] =3D '\0'; + } + } + } + } + +# if defined _WIN32 && ! defined __CYGWIN__ + /* If setlocale is successful, it returns the number of the + codepage, as a string. Otherwise, fall back on Windows API + GetACP, which returns the locale's codepage as a number (although + this doesn't change according to what the 'setlocale' call specifie= d). + Either way, prepend "CP" to make it a valid codeset name. */ + codesetlen =3D strlen (codeset); + if (0 < codesetlen && codesetlen < sizeof buf - 2) + memmove (buf + 2, codeset, codesetlen + 1); + else + sprintf (buf + 2, "%u", GetACP ()); + codeset =3D memcpy (buf, "CP", 2); +# endif + return codeset; +} +#endif + + +#if REPLACE_NL_LANGINFO + +/* Override nl_langinfo with support for added nl_item values. */ + +# undef nl_langinfo + +char * +rpl_nl_langinfo (nl_item item) +{ + switch (item) + { +# if GNULIB_defined_CODESET + case CODESET: + return ctype_codeset (); +# endif +# if GNULIB_defined_T_FMT_AMPM + case T_FMT_AMPM: + return (char *) "%I:%M:%S %p"; +# endif +# if GNULIB_defined_ALTMON + case ALTMON_1: + case ALTMON_2: + case ALTMON_3: + case ALTMON_4: + case ALTMON_5: + case ALTMON_6: + case ALTMON_7: + case ALTMON_8: + case ALTMON_9: + case ALTMON_10: + case ALTMON_11: + case ALTMON_12: + /* We don't ship the appropriate localizations with gnulib. There= fore, + treat ALTMON_i like MON_i. */ + item =3D item - ALTMON_1 + MON_1; + break; +# endif +# if GNULIB_defined_ERA + case ERA: + /* The format is not standardized. In glibc it is a sequence of s= trings + of the form "direction:offset:start_date:end_date:era_name:era_= format" + with an empty string at the end. */ + return (char *) ""; + case ERA_D_FMT: + /* The %Ex conversion in strftime behaves like %x if the locale do= es not + have an alternative time format. */ + item =3D D_FMT; + break; + case ERA_D_T_FMT: + /* The %Ec conversion in strftime behaves like %c if the locale do= es not + have an alternative time format. */ + item =3D D_T_FMT; + break; + case ERA_T_FMT: + /* The %EX conversion in strftime behaves like %X if the locale do= es not + have an alternative time format. */ + item =3D T_FMT; + break; + case ALT_DIGITS: + /* The format is not standardized. In glibc it is a sequence of 1= 0 + strings, appended in memory. */ + return (char *) "\0\0\0\0\0\0\0\0\0\0"; +# endif +# if GNULIB_defined_YESEXPR || !FUNC_NL_LANGINFO_YESEXPR_WORKS + case YESEXPR: + return (char *) "^[yY]"; + case NOEXPR: + return (char *) "^[nN]"; +# endif + default: + break; + } + return nl_langinfo (item); +} + +#else + +/* Provide nl_langinfo from scratch, either for native MS-Windows, or + for old Unix platforms without locales, such as Linux libc5 or + BeOS. */ + +# include + +char * +nl_langinfo (nl_item item) +{ + static char nlbuf[100]; + struct tm tmm =3D { 0 }; + + switch (item) + { + /* nl_langinfo items of the LC_CTYPE category */ + case CODESET: + { + char *codeset =3D ctype_codeset (); + if (*codeset) + return codeset; + } +# ifdef __BEOS__ + return (char *) "UTF-8"; +# else + return (char *) "ISO-8859-1"; +# endif + /* nl_langinfo items of the LC_NUMERIC category */ + case RADIXCHAR: + return localeconv () ->decimal_point; + case THOUSEP: + return localeconv () ->thousands_sep; +# ifdef GROUPING + case GROUPING: + return localeconv () ->grouping; +# endif + /* nl_langinfo items of the LC_TIME category. + TODO: Really use the locale. */ + case D_T_FMT: + case ERA_D_T_FMT: + return (char *) "%a %b %e %H:%M:%S %Y"; + case D_FMT: + case ERA_D_FMT: + return (char *) "%m/%d/%y"; + case T_FMT: + case ERA_T_FMT: + return (char *) "%H:%M:%S"; + case T_FMT_AMPM: + return (char *) "%I:%M:%S %p"; + case AM_STR: + if (!strftime (nlbuf, sizeof nlbuf, "%p", &tmm)) + return (char *) "AM"; + return nlbuf; + case PM_STR: + tmm.tm_hour =3D 12; + if (!strftime (nlbuf, sizeof nlbuf, "%p", &tmm)) + return (char *) "PM"; + return nlbuf; + case DAY_1: + case DAY_2: + case DAY_3: + case DAY_4: + case DAY_5: + case DAY_6: + case DAY_7: + { + static char const days[][sizeof "Wednesday"] =3D { + "Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", + "Friday", "Saturday" + }; + tmm.tm_wday =3D item - DAY_1; + if (!strftime (nlbuf, sizeof nlbuf, "%A", &tmm)) + return (char *) days[item - DAY_1]; + return nlbuf; + } + case ABDAY_1: + case ABDAY_2: + case ABDAY_3: + case ABDAY_4: + case ABDAY_5: + case ABDAY_6: + case ABDAY_7: + { + static char const abdays[][sizeof "Sun"] =3D { + "Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat" + }; + tmm.tm_wday =3D item - ABDAY_1; + if (!strftime (nlbuf, sizeof nlbuf, "%a", &tmm)) + return (char *) abdays[item - ABDAY_1]; + return nlbuf; + } + { + static char const months[][sizeof "September"] =3D { + "January", "February", "March", "April", "May", "June", "July", + "September", "October", "November", "December" + }; + case MON_1: + case MON_2: + case MON_3: + case MON_4: + case MON_5: + case MON_6: + case MON_7: + case MON_8: + case MON_9: + case MON_10: + case MON_11: + case MON_12: + tmm.tm_mon =3D item - MON_1; + if (!strftime (nlbuf, sizeof nlbuf, "%B", &tmm)) + return (char *) months[item - MON_1]; + return nlbuf; + case ALTMON_1: + case ALTMON_2: + case ALTMON_3: + case ALTMON_4: + case ALTMON_5: + case ALTMON_6: + case ALTMON_7: + case ALTMON_8: + case ALTMON_9: + case ALTMON_10: + case ALTMON_11: + case ALTMON_12: + tmm.tm_mon =3D item - ALTMON_1; + /* The platforms without nl_langinfo() don't support strftime wi= th %OB. + We don't even need to try. */ + #if 0 + if (!strftime (nlbuf, sizeof nlbuf, "%OB", &tmm)) + #endif + if (!strftime (nlbuf, sizeof nlbuf, "%B", &tmm)) + return (char *) months[item - ALTMON_1]; + return nlbuf; + } + case ABMON_1: + case ABMON_2: + case ABMON_3: + case ABMON_4: + case ABMON_5: + case ABMON_6: + case ABMON_7: + case ABMON_8: + case ABMON_9: + case ABMON_10: + case ABMON_11: + case ABMON_12: + { + static char const abmonths[][sizeof "Jan"] =3D { + "Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", + "Sep", "Oct", "Nov", "Dec" + }; + tmm.tm_mon =3D item - ABMON_1; + if (!strftime (nlbuf, sizeof nlbuf, "%b", &tmm)) + return (char *) abmonths[item - ABMON_1]; + return nlbuf; + } + case ERA: + return (char *) ""; + case ALT_DIGITS: + return (char *) "\0\0\0\0\0\0\0\0\0\0"; + /* nl_langinfo items of the LC_MONETARY category. */ + case CRNCYSTR: + return localeconv () ->currency_symbol; +# ifdef INT_CURR_SYMBOL + case INT_CURR_SYMBOL: + return localeconv () ->int_curr_symbol; + case MON_DECIMAL_POINT: + return localeconv () ->mon_decimal_point; + case MON_THOUSANDS_SEP: + return localeconv () ->mon_thousands_sep; + case MON_GROUPING: + return localeconv () ->mon_grouping; + case POSITIVE_SIGN: + return localeconv () ->positive_sign; + case NEGATIVE_SIGN: + return localeconv () ->negative_sign; + case FRAC_DIGITS: + return & localeconv () ->frac_digits; + case INT_FRAC_DIGITS: + return & localeconv () ->int_frac_digits; + case P_CS_PRECEDES: + return & localeconv () ->p_cs_precedes; + case N_CS_PRECEDES: + return & localeconv () ->n_cs_precedes; + case P_SEP_BY_SPACE: + return & localeconv () ->p_sep_by_space; + case N_SEP_BY_SPACE: + return & localeconv () ->n_sep_by_space; + case P_SIGN_POSN: + return & localeconv () ->p_sign_posn; + case N_SIGN_POSN: + return & localeconv () ->n_sign_posn; +# endif + /* nl_langinfo items of the LC_MESSAGES category + TODO: Really use the locale. */ + case YESEXPR: + return (char *) "^[yY]"; + case NOEXPR: + return (char *) "^[nN]"; + default: + return (char *) ""; + } +} + +#endif diff --git a/lib/regcomp.c b/lib/regcomp.c new file mode 100644 index 0000000000..53eb226374 --- /dev/null +++ b/lib/regcomp.c @@ -0,0 +1,3944 @@ +/* Extended regular expression matching and search library. + Copyright (C) 2002-2018 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Isamu Hasegawa . + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU General Public + License as published by the Free Software Foundation; either + version 3 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 + General Public License for more details. + + You should have received a copy of the GNU General Public + License along with the GNU C Library; if not, see + . */ + +#ifdef _LIBC +# include +#endif + +static reg_errcode_t re_compile_internal (regex_t *preg, const char * pa= ttern, + 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 /* RE_ENABLE_I18N */ +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 Idx duplicate_node (re_dfa_t *dfa, Idx org_idx, unsigned int cons= traint); +static Idx search_duplicated_node (const re_dfa_t *dfa, Idx 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, + Idx node, bool root); +static reg_errcode_t calc_inveclosure (re_dfa_t *dfa); +static Idx 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); +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, + Idx 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, + Idx 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, + Idx 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, + Idx nest, reg_errcode_t *err); +static bin_tree_t *parse_dup_op (bin_tree_t *dup_elem, re_string_t *rege= xp, + 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, + bool 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, + Idx *equiv_class_alloc, + const unsigned char *name); +static reg_errcode_t build_charclass (RE_TRANSLATE_TYPE trans, + bitset_t sbcset, + re_charset_t *mbcset, + Idx *char_class_alloc, + const 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 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 char *class_name, + const char *extra, + bool 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); +=0C +/* 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[] =3D + { +#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 expre= ssion") + gettext_noop ("Invalid collation character") /* REG_ECOLLATE */ + "\0" +#define REG_ECTYPE_IDX (REG_ECOLLATE_IDX + sizeof "Invalid collation cha= racter") + gettext_noop ("Invalid character class name") /* REG_ECTYPE */ + "\0" +#define REG_EESCAPE_IDX (REG_ECTYPE_IDX + sizeof "Invalid character clas= s 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 [=3D") /* REG_EBRACK */ + "\0" +#define REG_EPAREN_IDX (REG_EBRACK_IDX + sizeof "Unmatched [, [^, [:, [.= , or [=3D") + 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 e= xpression") + 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 size_t __re_error_msgid_idx[] =3D + { + 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 + }; +=0C +/* 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 =3D !!(re_syntax_options & RE_NO_SUB); + + /* Match anchors at newline. */ + bufp->newline_anchor =3D 1; + + ret =3D re_compile_internal (bufp, pattern, length, re_syntax_options)= ; + + if (!ret) + return NULL; + return gettext (__re_error_msgid + __re_error_msgid_idx[(int) ret]); +} +#ifdef _LIBC +weak_alias (__re_compile_pattern, re_compile_pattern) +#endif + +/* Set by 're_set_syntax' to the current regexp syntax to recognize. Ca= n + 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 =3D re_syntax_options; + + re_syntax_options =3D syntax; + return ret; +} +#ifdef _LIBC +weak_alias (__re_set_syntax, re_set_syntax) +#endif + +int +re_compile_fastmap (struct re_pattern_buffer *bufp) +{ + re_dfa_t *dfa =3D bufp->buffer; + char *fastmap =3D bufp->fastmap; + + memset (fastmap, '\0', sizeof (char) * SBC_MAX); + re_compile_fastmap_iter (bufp, dfa->init_state, fastmap); + if (dfa->init_state !=3D dfa->init_state_word) + re_compile_fastmap_iter (bufp, dfa->init_state_word, fastmap); + if (dfa->init_state !=3D dfa->init_state_nl) + re_compile_fastmap_iter (bufp, dfa->init_state_nl, fastmap); + if (dfa->init_state !=3D dfa->init_state_begbuf) + re_compile_fastmap_iter (bufp, dfa->init_state_begbuf, fastmap); + bufp->fastmap_accurate =3D 1; + return 0; +} +#ifdef _LIBC +weak_alias (__re_compile_fastmap, re_compile_fastmap) +#endif + +static inline void +__attribute__ ((always_inline)) +re_set_fastmap (char *fastmap, bool icase, int ch) +{ + fastmap[ch] =3D 1; + if (icase) + fastmap[tolower (ch)] =3D 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 =3D bufp->buffer; + Idx node_cnt; + bool icase =3D (dfa->mb_cur_max =3D=3D 1 && (bufp->syntax & RE_ICASE))= ; + for (node_cnt =3D 0; node_cnt < init_state->nodes.nelem; ++node_cnt) + { + Idx node =3D init_state->nodes.elems[node_cnt]; + re_token_type_t type =3D dfa->nodes[node].type; + + if (type =3D=3D 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[MB_LEN_MAX]; + unsigned char *p; + wchar_t wc; + mbstate_t state; + + p =3D buf; + *p++ =3D dfa->nodes[node].opr.c; + while (++node < dfa->nodes_len + && dfa->nodes[node].type =3D=3D CHARACTER + && dfa->nodes[node].mb_partial) + *p++ =3D dfa->nodes[node].opr.c; + memset (&state, '\0', sizeof (state)); + if (__mbrtowc (&wc, (const char *) buf, p - buf, + &state) =3D=3D p - buf + && (__wcrtomb ((char *) buf, __towlower (wc), &state) + !=3D (size_t) -1)) + re_set_fastmap (fastmap, false, buf[0]); + } +#endif + } + else if (type =3D=3D SIMPLE_BRACKET) + { + int i, ch; + for (i =3D 0, ch =3D 0; i < BITSET_WORDS; ++i) + { + int j; + bitset_word_t w =3D dfa->nodes[node].opr.sbcset[i]; + for (j =3D 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 =3D=3D COMPLEX_BRACKET) + { + re_charset_t *cset =3D dfa->nodes[node].opr.mbcset; + Idx i; + +# ifdef _LIBC + /* See if we have to try all bytes which start multiple 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' (and + it is caught by SIMPLE_BRACKET). */ + if (_NL_CURRENT_WORD (LC_COLLATE, _NL_COLLATE_NRULES) !=3D 0 + && (cset->ncoll_syms || cset->nranges)) + { + const int32_t *table =3D (const int32_t *) + _NL_CURRENT (LC_COLLATE, _NL_COLLATE_TABLEMB); + for (i =3D 0; i < SBC_MAX; ++i) + if (table[i] < 0) + re_set_fastmap (fastmap, icase, i); + } +# endif /* _LIBC */ + + /* See if we have to start the match at all multibyte characters, + i.e. where we would not find an invalid sequence. This only + applies to multibyte character sets; for single byte character + sets, the SIMPLE_BRACKET again suffices. */ + if (dfa->mb_cur_max > 1 + && (cset->nchar_classes || cset->non_match || cset->nranges +# ifdef _LIBC + || cset->nequiv_classes +# endif /* _LIBC */ + )) + { + unsigned char c =3D 0; + do + { + mbstate_t mbs; + memset (&mbs, 0, sizeof (mbs)); + if (__mbrtowc (NULL, (char *) &c, 1, &mbs) =3D=3D (size_t) -2) + re_set_fastmap (fastmap, false, (int) c); + } + while (++c !=3D 0); + } + + else + { + /* ... Else catch all bytes which can start the mbchars. */ + for (i =3D 0; i < cset->nmbchars; ++i) + { + char buf[256]; + mbstate_t state; + memset (&state, '\0', sizeof (state)); + if (__wcrtomb (buf, cset->mbchars[i], &state) !=3D (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) + !=3D (size_t) -1) + re_set_fastmap (fastmap, false, *(unsigned char *) buf); + } + } + } + } +#endif /* RE_ENABLE_I18N */ + else if (type =3D=3D OP_PERIOD +#ifdef RE_ENABLE_I18N + || type =3D=3D OP_UTF8_PERIOD +#endif /* RE_ENABLE_I18N */ + || type =3D=3D END_OF_RE) + { + memset (fastmap, '\1', sizeof (char) * SBC_MAX); + if (type =3D=3D END_OF_RE) + bufp->can_be_null =3D 1; + return; + } + } +} +=0C +/* 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 c= flags) +{ + reg_errcode_t ret; + reg_syntax_t syntax =3D ((cflags & REG_EXTENDED) ? RE_SYNTAX_POSIX_EXT= ENDED + : RE_SYNTAX_POSIX_BASIC); + + preg->buffer =3D NULL; + preg->allocated =3D 0; + preg->used =3D 0; + + /* Try to allocate space for the fastmap. */ + preg->fastmap =3D re_malloc (char, SBC_MAX); + if (BE (preg->fastmap =3D=3D NULL, 0)) + return REG_ESPACE; + + syntax |=3D (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 &=3D ~RE_DOT_NEWLINE; + syntax |=3D RE_HAT_LISTS_NOT_NEWLINE; + /* It also changes the matching behavior. */ + preg->newline_anchor =3D 1; + } + else + preg->newline_anchor =3D 0; + preg->no_sub =3D !!(cflags & REG_NOSUB); + preg->translate =3D NULL; + + ret =3D 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 =3D=3D REG_ERPAREN) + ret =3D REG_EPAREN; + + /* We have already checked preg->fastmap !=3D NULL. */ + if (BE (ret =3D=3D 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 =3D NULL; + } + + return (int) ret; +} +#ifdef _LIBC +libc_hidden_def (__regcomp) +weak_alias (__regcomp, regcomp) +#endif + +/* Returns a message corresponding to an error code, ERRCODE, returned + from either regcomp or regexec. We don't use PREG here. */ + +size_t +regerror (int errcode, const regex_t *_Restrict_ preg, char *_Restrict_ = errbuf, + size_t errbuf_size) +{ + const char *msg; + size_t msg_size; + + if (BE (errcode < 0 + || errcode >=3D (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 passe= d + to this routine. If we are given anything else, or if other rege= x + code generates an invalid error code, then the program has a bug. + Dump core so we can fix it. */ + abort (); + + msg =3D gettext (__re_error_msgid + __re_error_msgid_idx[errcode]); + + msg_size =3D strlen (msg) + 1; /* Includes the null. */ + + if (BE (errbuf_size !=3D 0, 1)) + { + size_t cpy_size =3D msg_size; + if (BE (msg_size > errbuf_size, 0)) + { + cpy_size =3D errbuf_size - 1; + errbuf[cpy_size] =3D '\0'; + } + memcpy (errbuf, msg, cpy_size); + } + + return msg_size; +} +#ifdef _LIBC +weak_alias (__regerror, regerror) +#endif + + +#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 =3D +{ + /* Set the first 128 bits. */ +# if defined __GNUC__ && !defined __STRICT_ANSI__ + [0 ... 0x80 / BITSET_WORD_BITS - 1] =3D BITSET_WORD_MAX +# else +# if 4 * BITSET_WORD_BITS < ASCII_CHARS +# error "bitset_word_t is narrower than 32 bits" +# elif 3 * BITSET_WORD_BITS < ASCII_CHARS + BITSET_WORD_MAX, BITSET_WORD_MAX, BITSET_WORD_MAX, +# elif 2 * BITSET_WORD_BITS < ASCII_CHARS + BITSET_WORD_MAX, BITSET_WORD_MAX, +# elif 1 * BITSET_WORD_BITS < ASCII_CHARS + BITSET_WORD_MAX, +# endif + (BITSET_WORD_MAX + >> (SBC_MAX % BITSET_WORD_BITS =3D=3D 0 + ? 0 + : BITSET_WORD_BITS - SBC_MAX % BITSET_WORD_BITS)) +# endif +}; +#endif + + +static void +free_dfa_content (re_dfa_t *dfa) +{ + Idx i, j; + + if (dfa->nodes) + for (i =3D 0; i < dfa->nodes_len; ++i) + free_token (dfa->nodes + i); + re_free (dfa->nexts); + for (i =3D 0; i < dfa->nodes_len; ++i) + { + if (dfa->eclosures !=3D NULL) + re_node_set_free (dfa->eclosures + i); + if (dfa->inveclosures !=3D NULL) + re_node_set_free (dfa->inveclosures + i); + if (dfa->edests !=3D 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 =3D 0; i <=3D dfa->state_hash_mask; ++i) + { + struct re_state_table_entry *entry =3D dfa->state_table + i; + for (j =3D 0; j < entry->num; ++j) + { + re_dfastate_t *state =3D entry->array[j]; + free_state (state); + } + re_free (entry->array); + } + re_free (dfa->state_table); +#ifdef RE_ENABLE_I18N + if (dfa->sb_char !=3D 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 =3D preg->buffer; + if (BE (dfa !=3D NULL, 1)) + { + lock_fini (dfa->lock); + free_dfa_content (dfa); + } + preg->buffer =3D NULL; + preg->allocated =3D 0; + + re_free (preg->fastmap); + preg->fastmap =3D NULL; + + re_free (preg->translate); + preg->translate =3D NULL; +} +#ifdef _LIBC +libc_hidden_def (__regfree) +weak_alias (__regfree, regfree) +#endif +=0C +/* 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 above without link errors. */ +weak_function +# endif +re_comp (const char *s) +{ + reg_errcode_t ret; + char *fastmap; + + if (!s) + { + if (!re_comp_buf.buffer) + return gettext ("No previous regular expression"); + return 0; + } + + if (re_comp_buf.buffer) + { + fastmap =3D re_comp_buf.fastmap; + re_comp_buf.fastmap =3D NULL; + __regfree (&re_comp_buf); + memset (&re_comp_buf, '\0', sizeof (re_comp_buf)); + re_comp_buf.fastmap =3D fastmap; + } + + if (re_comp_buf.fastmap =3D=3D NULL) + { + re_comp_buf.fastmap =3D re_malloc (char, SBC_MAX); + if (re_comp_buf.fastmap =3D=3D 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 =3D 1; + + ret =3D re_compile_internal (&re_comp_buf, s, strlen (s), re_syntax_op= tions); + + 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]); +} + +#ifdef _LIBC +libc_freeres_fn (free_mem) +{ + __regfree (&re_comp_buf); +} +#endif + +#endif /* _REGEX_RE_COMP */ +=0C +/* 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 =3D REG_NOERROR; + re_dfa_t *dfa; + re_string_t regexp; + + /* Initialize the pattern buffer. */ + preg->fastmap_accurate =3D 0; + preg->syntax =3D syntax; + preg->not_bol =3D preg->not_eol =3D 0; + preg->used =3D 0; + preg->re_nsub =3D 0; + preg->can_be_null =3D 0; + preg->regs_allocated =3D REGS_UNALLOCATED; + + /* Initialize the dfa. */ + dfa =3D 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 =3D re_realloc (preg->buffer, re_dfa_t, 1); + if (dfa =3D=3D NULL) + return REG_ESPACE; + preg->allocated =3D sizeof (re_dfa_t); + preg->buffer =3D dfa; + } + preg->used =3D sizeof (re_dfa_t); + + err =3D init_dfa (dfa, length); + if (BE (err =3D=3D REG_NOERROR && lock_init (dfa->lock) !=3D 0, 0)) + err =3D REG_ESPACE; + if (BE (err !=3D REG_NOERROR, 0)) + { + free_dfa_content (dfa); + preg->buffer =3D NULL; + preg->allocated =3D 0; + return err; + } +#ifdef DEBUG + /* Note: length+1 will not overflow since it is checked in init_dfa. = */ + dfa->re_str =3D re_malloc (char, length + 1); + strncpy (dfa->re_str, pattern, length + 1); +#endif + + err =3D re_string_construct (®exp, pattern, length, preg->translate= , + (syntax & RE_ICASE) !=3D 0, dfa); + if (BE (err !=3D REG_NOERROR, 0)) + { + re_compile_internal_free_return: + free_workarea_compile (preg); + re_string_destruct (®exp); + lock_fini (dfa->lock); + free_dfa_content (dfa); + preg->buffer =3D NULL; + preg->allocated =3D 0; + return err; + } + + /* Parse the regular expression, and build a structure tree. */ + preg->re_nsub =3D 0; + dfa->str_tree =3D parse (®exp, preg, syntax, &err); + if (BE (dfa->str_tree =3D=3D NULL, 0)) + goto re_compile_internal_free_return; + + /* Analyze the tree and create the nfa. */ + err =3D analyze (preg); + if (BE (err !=3D REG_NOERROR, 0)) + goto re_compile_internal_free_return; + +#ifdef RE_ENABLE_I18N + /* If possible, do searching in single byte encoding to speed things u= p. */ + if (dfa->is_utf8 && !(syntax & RE_ICASE) && preg->translate =3D=3D NUL= L) + optimize_utf8 (dfa); +#endif + + /* Then create the initial state of the dfa. */ + err =3D create_initial_state (dfa); + + /* Release work areas. */ + free_workarea_compile (preg); + re_string_destruct (®exp); + + if (BE (err !=3D REG_NOERROR, 0)) + { + lock_fini (dfa->lock); + free_dfa_content (dfa); + preg->buffer =3D NULL; + preg->allocated =3D 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) +{ + __re_size_t table_size; +#ifndef _LIBC + const char *codeset_name; +#endif +#ifdef RE_ENABLE_I18N + size_t max_i18n_object_size =3D MAX (sizeof (wchar_t), sizeof (wctype_= t)); +#else + size_t max_i18n_object_size =3D 0; +#endif + size_t max_object_size =3D + MAX (sizeof (struct re_state_table_entry), + MAX (sizeof (re_token_t), + MAX (sizeof (re_node_set), + MAX (sizeof (regmatch_t), + max_i18n_object_size)))); + + memset (dfa, '\0', sizeof (re_dfa_t)); + + /* Force allocation of str_tree_storage the first time. */ + dfa->str_tree_storage_idx =3D BIN_TREE_STORAGE_SIZE; + + /* Avoid overflows. The extra "/ 2" is for the table_size doubling + calculation below, and for similar doubling calculations + elsewhere. And it's <=3D rather than <, because some of the + doubling calculations add 1 afterwards. */ + if (BE (MIN (IDX_MAX, SIZE_MAX / max_object_size) / 2 <=3D pat_len, 0)= ) + return REG_ESPACE; + + dfa->nodes_alloc =3D pat_len + 1; + dfa->nodes =3D re_malloc (re_token_t, dfa->nodes_alloc); + + /* table_size =3D 2 ^ ceil(log pat_len) */ + for (table_size =3D 1; ; table_size <<=3D 1) + if (table_size > pat_len) + break; + + dfa->state_table =3D calloc (sizeof (struct re_state_table_entry), tab= le_size); + dfa->state_hash_mask =3D table_size - 1; + + dfa->mb_cur_max =3D MB_CUR_MAX; +#ifdef _LIBC + if (dfa->mb_cur_max =3D=3D 6 + && strcmp (_NL_CURRENT (LC_CTYPE, _NL_CTYPE_CODESET_NAME), "UTF-8"= ) =3D=3D 0) + dfa->is_utf8 =3D 1; + dfa->map_notascii =3D (_NL_CURRENT_WORD (LC_CTYPE, _NL_CTYPE_MAP_TO_NO= NASCII) + !=3D 0); +#else + codeset_name =3D nl_langinfo (CODESET); + if ((codeset_name[0] =3D=3D 'U' || codeset_name[0] =3D=3D 'u') + && (codeset_name[1] =3D=3D 'T' || codeset_name[1] =3D=3D 't') + && (codeset_name[2] =3D=3D 'F' || codeset_name[2] =3D=3D 'f') + && strcmp (codeset_name + 3 + (codeset_name[3] =3D=3D '-'), "8") =3D= =3D 0) + dfa->is_utf8 =3D 1; + + /* We check exhaustively in the loop below if this charset is a + superset of ASCII. */ + dfa->map_notascii =3D 0; +#endif + +#ifdef RE_ENABLE_I18N + if (dfa->mb_cur_max > 1) + { + if (dfa->is_utf8) + dfa->sb_char =3D (re_bitset_ptr_t) utf8_sb_map; + else + { + int i, j, ch; + + dfa->sb_char =3D (re_bitset_ptr_t) calloc (sizeof (bitset_t), 1); + if (BE (dfa->sb_char =3D=3D NULL, 0)) + return REG_ESPACE; + + /* Set the bits corresponding to single byte chars. */ + for (i =3D 0, ch =3D 0; i < BITSET_WORDS; ++i) + for (j =3D 0; j < BITSET_WORD_BITS; ++j, ++ch) + { + wint_t wch =3D __btowc (ch); + if (wch !=3D WEOF) + dfa->sb_char[i] |=3D (bitset_word_t) 1 << j; +# ifndef _LIBC + if (isascii (ch) && wch !=3D ch) + dfa->map_notascii =3D 1; +# endif + } + } + } +#endif + + if (BE (dfa->nodes =3D=3D NULL || dfa->state_table =3D=3D 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 +init_word_char (re_dfa_t *dfa) +{ + int i =3D 0; + int j; + int ch =3D 0; + dfa->word_ops_used =3D 1; + if (BE (dfa->map_notascii =3D=3D 0, 1)) + { + /* Avoid uint32_t and uint64_t as some non-GCC platforms lack + them, an issue when this code is used in Gnulib. */ + bitset_word_t bits0 =3D 0x00000000; + bitset_word_t bits1 =3D 0x03ff0000; + bitset_word_t bits2 =3D 0x87fffffe; + bitset_word_t bits3 =3D 0x07fffffe; + if (BITSET_WORD_BITS =3D=3D 64) + { + /* Pacify gcc -Woverflow on 32-bit platformns. */ + dfa->word_char[0] =3D bits1 << 31 << 1 | bits0; + dfa->word_char[1] =3D bits3 << 31 << 1 | bits2; + i =3D 2; + } + else if (BITSET_WORD_BITS =3D=3D 32) + { + dfa->word_char[0] =3D bits0; + dfa->word_char[1] =3D bits1; + dfa->word_char[2] =3D bits2; + dfa->word_char[3] =3D bits3; + i =3D 4; + } + else + goto general_case; + ch =3D 128; + + if (BE (dfa->is_utf8, 1)) + { + memset (&dfa->word_char[i], '\0', (SBC_MAX - ch) / 8); + return; + } + } + + general_case: + for (; i < BITSET_WORDS; ++i) + for (j =3D 0; j < BITSET_WORD_BITS; ++j, ++ch) + if (isalnum (ch) || ch =3D=3D '_') + dfa->word_char[i] |=3D (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 =3D preg->buffer; + bin_tree_storage_t *storage, *next; + for (storage =3D dfa->str_tree_storage; storage; storage =3D next) + { + next =3D storage->next; + re_free (storage); + } + dfa->str_tree_storage =3D NULL; + dfa->str_tree_storage_idx =3D BIN_TREE_STORAGE_SIZE; + dfa->str_tree =3D NULL; + re_free (dfa->org_indices); + dfa->org_indices =3D NULL; +} + +/* Create initial states for all contexts. */ + +static reg_errcode_t +create_initial_state (re_dfa_t *dfa) +{ + Idx 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 =3D dfa->str_tree->first->node_idx; + dfa->init_node =3D first; + err =3D re_node_set_init_copy (&init_nodes, dfa->eclosures + first); + if (BE (err !=3D 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 =3D 0; i < init_nodes.nelem; ++i) + { + Idx node_idx =3D init_nodes.elems[i]; + re_token_type_t type =3D dfa->nodes[node_idx].type; + + Idx clexp_idx; + if (type !=3D OP_BACK_REF) + continue; + for (clexp_idx =3D 0; clexp_idx < init_nodes.nelem; ++clexp_idx) + { + re_token_t *clexp_node; + clexp_node =3D dfa->nodes + init_nodes.elems[clexp_idx]; + if (clexp_node->type =3D=3D OP_CLOSE_SUBEXP + && clexp_node->opr.idx =3D=3D dfa->nodes[node_idx].opr.idx) + break; + } + if (clexp_idx =3D=3D init_nodes.nelem) + continue; + + if (type =3D=3D OP_BACK_REF) + { + Idx dest_idx =3D dfa->edests[node_idx].elems[0]; + if (!re_node_set_contains (&init_nodes, dest_idx)) + { + reg_errcode_t merge_err + =3D re_node_set_merge (&init_nodes, dfa->eclosures + d= est_idx); + if (merge_err !=3D REG_NOERROR) + return merge_err; + i =3D 0; + } + } + } + + /* It must be the first time to invoke acquire_state. */ + dfa->init_state =3D 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 =3D=3D NULL, 0)) + return err; + if (dfa->init_state->has_constraint) + { + dfa->init_state_word =3D re_acquire_state_context (&err, dfa, &ini= t_nodes, + CONTEXT_WORD); + dfa->init_state_nl =3D re_acquire_state_context (&err, dfa, &init_= nodes, + CONTEXT_NEWLINE); + dfa->init_state_begbuf =3D re_acquire_state_context (&err, dfa, + &init_nodes, + CONTEXT_NEWLINE + | CONTEXT_BEGBUF); + if (BE (dfa->init_state_word =3D=3D NULL || dfa->init_state_nl =3D= =3D NULL + || dfa->init_state_begbuf =3D=3D NULL, 0)) + return err; + } + else + dfa->init_state_word =3D dfa->init_state_nl + =3D dfa->init_state_begbuf =3D dfa->init_state; + + re_node_set_free (&init_nodes); + return REG_NOERROR; +} +=0C +#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 chang= e + DFA nodes where needed. */ + +static void +optimize_utf8 (re_dfa_t *dfa) +{ + Idx node; + int i; + bool mb_chars =3D false; + bool has_period =3D false; + + for (node =3D 0; node < dfa->nodes_len; ++node) + switch (dfa->nodes[node].type) + { + case CHARACTER: + if (dfa->nodes[node].opr.c >=3D ASCII_CHARS) + mb_chars =3D true; + break; + case ANCHOR: + switch (dfa->nodes[node].opr.ctx_type) + { + case LINE_FIRST: + case LINE_LAST: + case BUF_FIRST: + case BUF_LAST: + break; + default: + /* Word anchors etc. cannot be handled. It's okay to test + opr.ctx_type since constraints (for all DFA nodes) are + created by ORing one or more opr.ctx_type values. */ + return; + } + break; + case OP_PERIOD: + has_period =3D true; + 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. */ + { + int rshift =3D (ASCII_CHARS % BITSET_WORD_BITS =3D=3D 0 + ? 0 + : BITSET_WORD_BITS - ASCII_CHARS % BITSET_WORD_BITS); + for (i =3D ASCII_CHARS / BITSET_WORD_BITS; i < BITSET_WORDS; ++i) + { + if (dfa->nodes[node].opr.sbcset[i] >> rshift !=3D 0) + return; + rshift =3D 0; + } + } + break; + default: + abort (); + } + + if (mb_chars || has_period) + for (node =3D 0; node < dfa->nodes_len; ++node) + { + if (dfa->nodes[node].type =3D=3D CHARACTER + && dfa->nodes[node].opr.c >=3D ASCII_CHARS) + dfa->nodes[node].mb_partial =3D 0; + else if (dfa->nodes[node].type =3D=3D OP_PERIOD) + dfa->nodes[node].type =3D OP_UTF8_PERIOD; + } + + /* The search can be in single byte locale. */ + dfa->mb_cur_max =3D 1; + dfa->is_utf8 =3D 0; + dfa->has_mb_node =3D dfa->nbackref > 0 || has_period; +} +#endif +=0C +/* Analyze the structure tree, and calculate "first", "next", "edest", + "eclosure", and "inveclosure". */ + +static reg_errcode_t +analyze (regex_t *preg) +{ + re_dfa_t *dfa =3D preg->buffer; + reg_errcode_t ret; + + /* Allocate arrays. */ + dfa->nexts =3D re_malloc (Idx, dfa->nodes_alloc); + dfa->org_indices =3D re_malloc (Idx, dfa->nodes_alloc); + dfa->edests =3D re_malloc (re_node_set, dfa->nodes_alloc); + dfa->eclosures =3D re_malloc (re_node_set, dfa->nodes_alloc); + if (BE (dfa->nexts =3D=3D NULL || dfa->org_indices =3D=3D NULL || dfa-= >edests =3D=3D NULL + || dfa->eclosures =3D=3D NULL, 0)) + return REG_ESPACE; + + dfa->subexp_map =3D re_malloc (Idx, preg->re_nsub); + if (dfa->subexp_map !=3D NULL) + { + Idx i; + for (i =3D 0; i < preg->re_nsub; i++) + dfa->subexp_map[i] =3D i; + preorder (dfa->str_tree, optimize_subexps, dfa); + for (i =3D 0; i < preg->re_nsub; i++) + if (dfa->subexp_map[i] !=3D i) + break; + if (i =3D=3D preg->re_nsub) + { + re_free (dfa->subexp_map); + dfa->subexp_map =3D NULL; + } + } + + ret =3D postorder (dfa->str_tree, lower_subexps, preg); + if (BE (ret !=3D REG_NOERROR, 0)) + return ret; + ret =3D postorder (dfa->str_tree, calc_first, dfa); + if (BE (ret !=3D REG_NOERROR, 0)) + return ret; + preorder (dfa->str_tree, calc_next, dfa); + ret =3D preorder (dfa->str_tree, link_nfa_nodes, dfa); + if (BE (ret !=3D REG_NOERROR, 0)) + return ret; + ret =3D calc_eclosure (dfa); + if (BE (ret !=3D 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 =3D re_malloc (re_node_set, dfa->nodes_len); + if (BE (dfa->inveclosures =3D=3D NULL, 0)) + return REG_ESPACE; + ret =3D 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 =3D 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 =3D node->left; + else + node =3D node->right; + + do + { + reg_errcode_t err =3D fn (extra, node); + if (BE (err !=3D REG_NOERROR, 0)) + return err; + if (node->parent =3D=3D NULL) + return REG_NOERROR; + prev =3D node; + node =3D node->parent; + } + /* Go up while we have a node that is reached from the right. */ + while (node->right =3D=3D prev || node->right =3D=3D NULL); + node =3D 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 =3D root; ; ) + { + reg_errcode_t err =3D fn (extra, node); + if (BE (err !=3D REG_NOERROR, 0)) + return err; + + /* Go to the left node, or up and to the right. */ + if (node->left) + node =3D node->left; + else + { + bin_tree_t *prev =3D NULL; + while (node->right =3D=3D prev || node->right =3D=3D NULL) + { + prev =3D node; + node =3D node->parent; + if (!node) + return REG_NOERROR; + } + node =3D node->right; + } + } +} + +/* Optimization pass: if a SUBEXP is entirely contained, strip it and te= ll + re_search_internal to map the inner one's opr.idx to this one's. Adj= ust + backreferences as well. Requires a preorder visit. */ +static reg_errcode_t +optimize_subexps (void *extra, bin_tree_t *node) +{ + re_dfa_t *dfa =3D (re_dfa_t *) extra; + + if (node->token.type =3D=3D OP_BACK_REF && dfa->subexp_map) + { + int idx =3D node->token.opr.idx; + node->token.opr.idx =3D dfa->subexp_map[idx]; + dfa->used_bkref_map |=3D 1 << node->token.opr.idx; + } + + else if (node->token.type =3D=3D SUBEXP + && node->left && node->left->token.type =3D=3D SUBEXP) + { + Idx other_idx =3D node->left->token.opr.idx; + + node->left =3D node->left->left; + if (node->left) + node->left->parent =3D node; + + dfa->subexp_map[other_idx] =3D dfa->subexp_map[node->token.opr.idx= ]; + if (other_idx < BITSET_WORD_BITS) + dfa->used_bkref_map &=3D ~((bitset_word_t) 1 << other_idx); + } + + return REG_NOERROR; +} + +/* Lowering pass: Turn each SUBEXP node into the appropriate concatenati= on + of OP_OPEN_SUBEXP, the body of the SUBEXP (if any) and OP_CLOSE_SUBEX= P. */ +static reg_errcode_t +lower_subexps (void *extra, bin_tree_t *node) +{ + regex_t *preg =3D (regex_t *) extra; + reg_errcode_t err =3D REG_NOERROR; + + if (node->left && node->left->token.type =3D=3D SUBEXP) + { + node->left =3D lower_subexp (&err, preg, node->left); + if (node->left) + node->left->parent =3D node; + } + if (node->right && node->right->token.type =3D=3D SUBEXP) + { + node->right =3D lower_subexp (&err, preg, node->right); + if (node->right) + node->right->parent =3D node; + } + + return err; +} + +static bin_tree_t * +lower_subexp (reg_errcode_t *err, regex_t *preg, bin_tree_t *node) +{ + re_dfa_t *dfa =3D preg->buffer; + bin_tree_t *body =3D node->left; + bin_tree_t *op, *cls, *tree1, *tree; + + if (preg->no_sub + /* We do not optimize empty subexpressions, because otherwise we m= ay + 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 !=3D NULL + && (node->token.opr.idx >=3D 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 =3D create_tree (dfa, NULL, NULL, OP_OPEN_SUBEXP); + cls =3D create_tree (dfa, NULL, NULL, OP_CLOSE_SUBEXP); + tree1 =3D body ? create_tree (dfa, body, cls, CONCAT) : cls; + tree =3D create_tree (dfa, op, tree1, CONCAT); + if (BE (tree =3D=3D NULL || tree1 =3D=3D NULL || op =3D=3D NULL || cls= =3D=3D NULL, 0)) + { + *err =3D REG_ESPACE; + return NULL; + } + + op->token.opr.idx =3D cls->token.opr.idx =3D node->token.opr.idx; + op->token.opt_subexp =3D cls->token.opt_subexp =3D node->token.opt_sub= exp; + return tree; +} + +/* Pass 1 in building the NFA: compute FIRST and create unlinked automat= on + nodes. Requires a postorder visit. */ +static reg_errcode_t +calc_first (void *extra, bin_tree_t *node) +{ + re_dfa_t *dfa =3D (re_dfa_t *) extra; + if (node->token.type =3D=3D CONCAT) + { + node->first =3D node->left->first; + node->node_idx =3D node->left->node_idx; + } + else + { + node->first =3D node; + node->node_idx =3D re_dfa_add_node (dfa, node->token); + if (BE (node->node_idx =3D=3D -1, 0)) + return REG_ESPACE; + if (node->token.type =3D=3D ANCHOR) + dfa->nodes[node->node_idx].constraint =3D node->token.opr.ctx_type; + } + 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 =3D node; + break; + case CONCAT: + node->left->next =3D node->right->first; + node->right->next =3D node->next; + break; + default: + if (node->left) + node->left->next =3D node->next; + if (node->right) + node->right->next =3D 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 =3D (re_dfa_t *) extra; + Idx idx =3D node->node_idx; + reg_errcode_t err =3D REG_NOERROR; + + switch (node->token.type) + { + case CONCAT: + break; + + case END_OF_RE: + assert (node->next =3D=3D NULL); + break; + + case OP_DUP_ASTERISK: + case OP_ALT: + { + Idx left, right; + dfa->has_plural_match =3D 1; + if (node->left !=3D NULL) + left =3D node->left->first->node_idx; + else + left =3D node->next->node_idx; + if (node->right !=3D NULL) + right =3D node->right->first->node_idx; + else + right =3D node->next->node_idx; + assert (left > -1); + assert (right > -1); + err =3D re_node_set_init_2 (dfa->edests + idx, left, right); + } + break; + + case ANCHOR: + case OP_OPEN_SUBEXP: + case OP_CLOSE_SUBEXP: + err =3D re_node_set_init_1 (dfa->edests + idx, node->next->node_id= x); + break; + + case OP_BACK_REF: + dfa->nexts[idx] =3D node->next->node_idx; + if (node->token.type =3D=3D OP_BACK_REF) + err =3D re_node_set_init_1 (dfa->edests + idx, dfa->nexts[idx]); + break; + + default: + assert (!IS_EPSILON_NODE (node->token.type)); + dfa->nexts[idx] =3D 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 additio= n + to their own constraint. */ + +static reg_errcode_t +duplicate_node_closure (re_dfa_t *dfa, Idx top_org_node, Idx top_clone_n= ode, + Idx root_node, unsigned int init_constraint) +{ + Idx org_node, clone_node; + bool ok; + unsigned int constraint =3D init_constraint; + for (org_node =3D top_org_node, clone_node =3D top_clone_node;;) + { + Idx org_dest, clone_dest; + if (dfa->nodes[org_node].type =3D=3D 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 =3D dfa->nexts[org_node]; + re_node_set_empty (dfa->edests + clone_node); + clone_dest =3D duplicate_node (dfa, org_dest, constraint); + if (BE (clone_dest =3D=3D -1, 0)) + return REG_ESPACE; + dfa->nexts[clone_node] =3D dfa->nexts[org_node]; + ok =3D re_node_set_insert (dfa->edests + clone_node, clone_dest); + if (BE (! ok, 0)) + return REG_ESPACE; + } + else if (dfa->edests[org_node].nelem =3D=3D 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] =3D dfa->nexts[org_node]; + break; + } + else if (dfa->edests[org_node].nelem =3D=3D 1) + { + /* In case of the node can epsilon-transit, and it has only one + destination. */ + org_dest =3D dfa->edests[org_node].elems[0]; + re_node_set_empty (dfa->edests + clone_node); + /* If the node is root_node itself, it means the epsilon closure + has a loop. Then tie it to the destination of the root_node. */ + if (org_node =3D=3D root_node && clone_node !=3D org_node) + { + ok =3D re_node_set_insert (dfa->edests + clone_node, org_dest); + if (BE (! ok, 0)) + return REG_ESPACE; + break; + } + /* In case the node has another constraint, append it. */ + constraint |=3D dfa->nodes[org_node].constraint; + clone_dest =3D duplicate_node (dfa, org_dest, constraint); + if (BE (clone_dest =3D=3D -1, 0)) + return REG_ESPACE; + ok =3D re_node_set_insert (dfa->edests + clone_node, clone_dest); + if (BE (! ok, 0)) + return REG_ESPACE; + } + else /* dfa->edests[org_node].nelem =3D=3D 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 =3D 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 =3D search_duplicated_node (dfa, org_dest, constraint); + if (clone_dest =3D=3D -1) + { + /* There is no such duplicated node, create a new one. */ + reg_errcode_t err; + clone_dest =3D duplicate_node (dfa, org_dest, constraint); + if (BE (clone_dest =3D=3D -1, 0)) + return REG_ESPACE; + ok =3D re_node_set_insert (dfa->edests + clone_node, clone_dest); + if (BE (! ok, 0)) + return REG_ESPACE; + err =3D duplicate_node_closure (dfa, org_dest, clone_dest, + root_node, constraint); + if (BE (err !=3D REG_NOERROR, 0)) + return err; + } + else + { + /* There is a duplicated node which satisfies the constraint, + use it to avoid infinite loop. */ + ok =3D re_node_set_insert (dfa->edests + clone_node, clone_dest); + if (BE (! ok, 0)) + return REG_ESPACE; + } + + org_dest =3D dfa->edests[org_node].elems[1]; + clone_dest =3D duplicate_node (dfa, org_dest, constraint); + if (BE (clone_dest =3D=3D -1, 0)) + return REG_ESPACE; + ok =3D re_node_set_insert (dfa->edests + clone_node, clone_dest); + if (BE (! ok, 0)) + return REG_ESPACE; + } + org_node =3D org_dest; + clone_node =3D clone_dest; + } + return REG_NOERROR; +} + +/* Search for a node which is duplicated from the node ORG_NODE, and + satisfies the constraint CONSTRAINT. */ + +static Idx +search_duplicated_node (const re_dfa_t *dfa, Idx org_node, + unsigned int constraint) +{ + Idx idx; + for (idx =3D dfa->nodes_len - 1; dfa->nodes[idx].duplicated && idx > 0= ; --idx) + { + if (org_node =3D=3D dfa->org_indices[idx] + && constraint =3D=3D dfa->nodes[idx].constraint) + return idx; /* Found. */ + } + return -1; /* Not found. */ +} + +/* Duplicate the node whose index is ORG_IDX and set the constraint CONS= TRAINT. + Return the index of the new node, or -1 if insufficient storage is + available. */ + +static Idx +duplicate_node (re_dfa_t *dfa, Idx org_idx, unsigned int constraint) +{ + Idx dup_idx =3D re_dfa_add_node (dfa, dfa->nodes[org_idx]); + if (BE (dup_idx !=3D -1, 1)) + { + dfa->nodes[dup_idx].constraint =3D constraint; + dfa->nodes[dup_idx].constraint |=3D dfa->nodes[org_idx].constraint= ; + dfa->nodes[dup_idx].duplicated =3D 1; + + /* Store the index of the original node. */ + dfa->org_indices[dup_idx] =3D org_idx; + } + return dup_idx; +} + +static reg_errcode_t +calc_inveclosure (re_dfa_t *dfa) +{ + Idx src, idx; + bool ok; + for (idx =3D 0; idx < dfa->nodes_len; ++idx) + re_node_set_init_empty (dfa->inveclosures + idx); + + for (src =3D 0; src < dfa->nodes_len; ++src) + { + Idx *elems =3D dfa->eclosures[src].elems; + for (idx =3D 0; idx < dfa->eclosures[src].nelem; ++idx) + { + ok =3D re_node_set_insert_last (dfa->inveclosures + elems[idx], src); + if (BE (! ok, 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) +{ + Idx node_idx; + bool incomplete; +#ifdef DEBUG + assert (dfa->nodes_len > 0); +#endif + incomplete =3D false; + /* For each nodes, calculate epsilon closure. */ + for (node_idx =3D 0; ; ++node_idx) + { + reg_errcode_t err; + re_node_set eclosure_elem; + if (node_idx =3D=3D dfa->nodes_len) + { + if (!incomplete) + break; + incomplete =3D false; + node_idx =3D 0; + } + +#ifdef DEBUG + assert (dfa->eclosures[node_idx].nelem !=3D -1); +#endif + + /* If we have already calculated, skip it. */ + if (dfa->eclosures[node_idx].nelem !=3D 0) + continue; + /* Calculate epsilon closure of 'node_idx'. */ + err =3D calc_eclosure_iter (&eclosure_elem, dfa, node_idx, true); + if (BE (err !=3D REG_NOERROR, 0)) + return err; + + if (dfa->eclosures[node_idx].nelem =3D=3D 0) + { + incomplete =3D true; + 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, Idx node, bool = root) +{ + reg_errcode_t err; + Idx i; + re_node_set eclosure; + bool ok; + bool incomplete =3D false; + err =3D re_node_set_alloc (&eclosure, dfa->edests[node].nelem + 1); + if (BE (err !=3D 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 =3D -1; + + /* If the current node has constraints, duplicate all nodes + since they must inherit the constraints. */ + if (dfa->nodes[node].constraint + && dfa->edests[node].nelem + && !dfa->nodes[dfa->edests[node].elems[0]].duplicated) + { + err =3D duplicate_node_closure (dfa, node, node, node, + dfa->nodes[node].constraint); + if (BE (err !=3D REG_NOERROR, 0)) + return err; + } + + /* Expand each epsilon destination nodes. */ + if (IS_EPSILON_NODE(dfa->nodes[node].type)) + for (i =3D 0; i < dfa->edests[node].nelem; ++i) + { + re_node_set eclosure_elem; + Idx edest =3D dfa->edests[node].elems[i]; + /* If calculating the epsilon closure of 'edest' is in progress, + return intermediate result. */ + if (dfa->eclosures[edest].nelem =3D=3D -1) + { + incomplete =3D true; + continue; + } + /* If we haven't calculated the epsilon closure of 'edest' yet, + calculate now. Otherwise use calculated epsilon closure. */ + if (dfa->eclosures[edest].nelem =3D=3D 0) + { + err =3D calc_eclosure_iter (&eclosure_elem, dfa, edest, false); + if (BE (err !=3D REG_NOERROR, 0)) + return err; + } + else + eclosure_elem =3D dfa->eclosures[edest]; + /* Merge the epsilon closure of 'edest'. */ + err =3D re_node_set_merge (&eclosure, &eclosure_elem); + if (BE (err !=3D REG_NOERROR, 0)) + return err; + /* If the epsilon closure of 'edest' is incomplete, + the epsilon closure of this node is also incomplete. */ + if (dfa->eclosures[edest].nelem =3D=3D 0) + { + incomplete =3D true; + re_node_set_free (&eclosure_elem); + } + } + + /* An epsilon closure includes itself. */ + ok =3D re_node_set_insert (&eclosure, node); + if (BE (! ok, 0)) + return REG_ESPACE; + if (incomplete && !root) + dfa->eclosures[node].nelem =3D 0; + else + dfa->eclosures[node] =3D eclosure; + *new_set =3D eclosure; + return REG_NOERROR; +} +=0C +/* 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 +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 +peek_token (re_token_t *token, re_string_t *input, reg_syntax_t syntax) +{ + unsigned char c; + + if (re_string_eoi (input)) + { + token->type =3D END_OF_RE; + return 0; + } + + c =3D re_string_peek_byte (input, 0); + token->opr.c =3D c; + + token->word_char =3D 0; +#ifdef RE_ENABLE_I18N + token->mb_partial =3D 0; + if (input->mb_cur_max > 1 && + !re_string_first_byte (input, re_string_cur_idx (input))) + { + token->type =3D CHARACTER; + token->mb_partial =3D 1; + return 1; + } +#endif + if (c =3D=3D '\\') + { + unsigned char c2; + if (re_string_cur_idx (input) + 1 >=3D re_string_length (input)) + { + token->type =3D BACK_SLASH; + return 1; + } + + c2 =3D re_string_peek_byte_case (input, 1); + token->opr.c =3D c2; + token->type =3D CHARACTER; +#ifdef RE_ENABLE_I18N + if (input->mb_cur_max > 1) + { + wint_t wc =3D re_string_wchar_at (input, + re_string_cur_idx (input) + 1); + token->word_char =3D IS_WIDE_WORD_CHAR (wc) !=3D 0; + } + else +#endif + token->word_char =3D IS_WORD_CHAR (c2) !=3D 0; + + switch (c2) + { + case '|': + if (!(syntax & RE_LIMITED_OPS) && !(syntax & RE_NO_BK_VBAR)) + token->type =3D 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 =3D OP_BACK_REF; + token->opr.idx =3D c2 - '1'; + } + break; + case '<': + if (!(syntax & RE_NO_GNU_OPS)) + { + token->type =3D ANCHOR; + token->opr.ctx_type =3D WORD_FIRST; + } + break; + case '>': + if (!(syntax & RE_NO_GNU_OPS)) + { + token->type =3D ANCHOR; + token->opr.ctx_type =3D WORD_LAST; + } + break; + case 'b': + if (!(syntax & RE_NO_GNU_OPS)) + { + token->type =3D ANCHOR; + token->opr.ctx_type =3D WORD_DELIM; + } + break; + case 'B': + if (!(syntax & RE_NO_GNU_OPS)) + { + token->type =3D ANCHOR; + token->opr.ctx_type =3D NOT_WORD_DELIM; + } + break; + case 'w': + if (!(syntax & RE_NO_GNU_OPS)) + token->type =3D OP_WORD; + break; + case 'W': + if (!(syntax & RE_NO_GNU_OPS)) + token->type =3D OP_NOTWORD; + break; + case 's': + if (!(syntax & RE_NO_GNU_OPS)) + token->type =3D OP_SPACE; + break; + case 'S': + if (!(syntax & RE_NO_GNU_OPS)) + token->type =3D OP_NOTSPACE; + break; + case '`': + if (!(syntax & RE_NO_GNU_OPS)) + { + token->type =3D ANCHOR; + token->opr.ctx_type =3D BUF_FIRST; + } + break; + case '\'': + if (!(syntax & RE_NO_GNU_OPS)) + { + token->type =3D ANCHOR; + token->opr.ctx_type =3D BUF_LAST; + } + break; + case '(': + if (!(syntax & RE_NO_BK_PARENS)) + token->type =3D OP_OPEN_SUBEXP; + break; + case ')': + if (!(syntax & RE_NO_BK_PARENS)) + token->type =3D OP_CLOSE_SUBEXP; + break; + case '+': + if (!(syntax & RE_LIMITED_OPS) && (syntax & RE_BK_PLUS_QM)) + token->type =3D OP_DUP_PLUS; + break; + case '?': + if (!(syntax & RE_LIMITED_OPS) && (syntax & RE_BK_PLUS_QM)) + token->type =3D OP_DUP_QUESTION; + break; + case '{': + if ((syntax & RE_INTERVALS) && (!(syntax & RE_NO_BK_BRACES))) + token->type =3D OP_OPEN_DUP_NUM; + break; + case '}': + if ((syntax & RE_INTERVALS) && (!(syntax & RE_NO_BK_BRACES))) + token->type =3D OP_CLOSE_DUP_NUM; + break; + default: + break; + } + return 2; + } + + token->type =3D CHARACTER; +#ifdef RE_ENABLE_I18N + if (input->mb_cur_max > 1) + { + wint_t wc =3D re_string_wchar_at (input, re_string_cur_idx (input)= ); + token->word_char =3D IS_WIDE_WORD_CHAR (wc) !=3D 0; + } + else +#endif + token->word_char =3D IS_WORD_CHAR (token->opr.c); + + switch (c) + { + case '\n': + if (syntax & RE_NEWLINE_ALT) + token->type =3D OP_ALT; + break; + case '|': + if (!(syntax & RE_LIMITED_OPS) && (syntax & RE_NO_BK_VBAR)) + token->type =3D OP_ALT; + break; + case '*': + token->type =3D OP_DUP_ASTERISK; + break; + case '+': + if (!(syntax & RE_LIMITED_OPS) && !(syntax & RE_BK_PLUS_QM)) + token->type =3D OP_DUP_PLUS; + break; + case '?': + if (!(syntax & RE_LIMITED_OPS) && !(syntax & RE_BK_PLUS_QM)) + token->type =3D OP_DUP_QUESTION; + break; + case '{': + if ((syntax & RE_INTERVALS) && (syntax & RE_NO_BK_BRACES)) + token->type =3D OP_OPEN_DUP_NUM; + break; + case '}': + if ((syntax & RE_INTERVALS) && (syntax & RE_NO_BK_BRACES)) + token->type =3D OP_CLOSE_DUP_NUM; + break; + case '(': + if (syntax & RE_NO_BK_PARENS) + token->type =3D OP_OPEN_SUBEXP; + break; + case ')': + if (syntax & RE_NO_BK_PARENS) + token->type =3D OP_CLOSE_SUBEXP; + break; + case '[': + token->type =3D OP_OPEN_BRACKET; + break; + case '.': + token->type =3D OP_PERIOD; + break; + case '^': + if (!(syntax & (RE_CONTEXT_INDEP_ANCHORS | RE_CARET_ANCHORS_HERE))= && + re_string_cur_idx (input) !=3D 0) + { + char prev =3D re_string_peek_byte (input, -1); + if (!(syntax & RE_NEWLINE_ALT) || prev !=3D '\n') + break; + } + token->type =3D ANCHOR; + token->opr.ctx_type =3D LINE_FIRST; + break; + case '$': + if (!(syntax & RE_CONTEXT_INDEP_ANCHORS) && + re_string_cur_idx (input) + 1 !=3D 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 !=3D OP_ALT && next.type !=3D OP_CLOSE_SUBEXP) + break; + } + token->type =3D ANCHOR; + token->opr.ctx_type =3D 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 +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 =3D END_OF_RE; + return 0; + } + c =3D re_string_peek_byte (input, 0); + token->opr.c =3D c; + +#ifdef RE_ENABLE_I18N + if (input->mb_cur_max > 1 && + !re_string_first_byte (input, re_string_cur_idx (input))) + { + token->type =3D CHARACTER; + return 1; + } +#endif /* RE_ENABLE_I18N */ + + if (c =3D=3D '\\' && (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 =3D re_string_peek_byte (input, 0); + token->opr.c =3D c2; + token->type =3D CHARACTER; + return 1; + } + if (c =3D=3D '[') /* '[' 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 =3D re_string_peek_byte (input, 1); + else + c2 =3D 0; + token->opr.c =3D c2; + token_len =3D 2; + switch (c2) + { + case '.': + token->type =3D OP_OPEN_COLL_ELEM; + break; + + case '=3D': + token->type =3D OP_OPEN_EQUIV_CLASS; + break; + + case ':': + if (syntax & RE_CHAR_CLASSES) + { + token->type =3D OP_OPEN_CHAR_CLASS; + break; + } + FALLTHROUGH; + default: + token->type =3D CHARACTER; + token->opr.c =3D c; + token_len =3D 1; + break; + } + return token_len; + } + switch (c) + { + case '-': + token->type =3D OP_CHARSET_RANGE; + break; + case ']': + token->type =3D OP_CLOSE_BRACKET; + break; + case '^': + token->type =3D OP_NON_MATCH_LIST; + break; + default: + token->type =3D CHARACTER; + } + return 1; +} +=0C +/* Functions for parser. */ + +/* Entry point of the parser. + Parse the regular expression REGEXP and return the structure tree. + If an error occurs, ERR is set by error code, and return NULL. + This function build the following tree, from regular expression : + CAT + / \ + / \ + 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 =3D preg->buffer; + bin_tree_t *tree, *eor, *root; + re_token_t current_token; + dfa->syntax =3D syntax; + fetch_token (¤t_token, regexp, syntax | RE_CARET_ANCHORS_HERE); + tree =3D parse_reg_exp (regexp, preg, ¤t_token, syntax, 0, err); + if (BE (*err !=3D REG_NOERROR && tree =3D=3D NULL, 0)) + return NULL; + eor =3D create_tree (dfa, NULL, NULL, END_OF_RE); + if (tree !=3D NULL) + root =3D create_tree (dfa, tree, eor, CONCAT); + else + root =3D eor; + if (BE (eor =3D=3D NULL || root =3D=3D NULL, 0)) + { + *err =3D REG_ESPACE; + return NULL; + } + return root; +} + +/* This function build the following tree, from regular expression + |: + ALT + / \ + / \ + + + 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, Idx nest, reg_errcode_t *err) +{ + re_dfa_t *dfa =3D preg->buffer; + bin_tree_t *tree, *branch =3D NULL; + bitset_word_t initial_bkref_map =3D dfa->completed_bkref_map; + tree =3D parse_branch (regexp, preg, token, syntax, nest, err); + if (BE (*err !=3D REG_NOERROR && tree =3D=3D NULL, 0)) + return NULL; + + while (token->type =3D=3D OP_ALT) + { + fetch_token (token, regexp, syntax | RE_CARET_ANCHORS_HERE); + if (token->type !=3D OP_ALT && token->type !=3D END_OF_RE + && (nest =3D=3D 0 || token->type !=3D OP_CLOSE_SUBEXP)) + { + bitset_word_t accumulated_bkref_map =3D dfa->completed_bkref_map; + dfa->completed_bkref_map =3D initial_bkref_map; + branch =3D parse_branch (regexp, preg, token, syntax, nest, err); + if (BE (*err !=3D REG_NOERROR && branch =3D=3D NULL, 0)) + { + if (tree !=3D NULL) + postorder (tree, free_tree, NULL); + return NULL; + } + dfa->completed_bkref_map |=3D accumulated_bkref_map; + } + else + branch =3D NULL; + tree =3D create_tree (dfa, tree, branch, OP_ALT); + if (BE (tree =3D=3D NULL, 0)) + { + *err =3D REG_ESPACE; + return NULL; + } + } + return tree; +} + +/* This function build the following tree, from regular expression + : + CAT + / \ + / \ + + + CAT means concatenation. */ + +static bin_tree_t * +parse_branch (re_string_t *regexp, regex_t *preg, re_token_t *token, + reg_syntax_t syntax, Idx nest, reg_errcode_t *err) +{ + bin_tree_t *tree, *expr; + re_dfa_t *dfa =3D preg->buffer; + tree =3D parse_expression (regexp, preg, token, syntax, nest, err); + if (BE (*err !=3D REG_NOERROR && tree =3D=3D NULL, 0)) + return NULL; + + while (token->type !=3D OP_ALT && token->type !=3D END_OF_RE + && (nest =3D=3D 0 || token->type !=3D OP_CLOSE_SUBEXP)) + { + expr =3D parse_expression (regexp, preg, token, syntax, nest, err)= ; + if (BE (*err !=3D REG_NOERROR && expr =3D=3D NULL, 0)) + { + if (tree !=3D NULL) + postorder (tree, free_tree, NULL); + return NULL; + } + if (tree !=3D NULL && expr !=3D NULL) + { + bin_tree_t *newtree =3D create_tree (dfa, tree, expr, CONCAT); + if (newtree =3D=3D NULL) + { + postorder (expr, free_tree, NULL); + postorder (tree, free_tree, NULL); + *err =3D REG_ESPACE; + return NULL; + } + tree =3D newtree; + } + else if (tree =3D=3D NULL) + tree =3D expr; + /* Otherwise expr =3D=3D 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, Idx nest, reg_errcode_t *err) +{ + re_dfa_t *dfa =3D preg->buffer; + bin_tree_t *tree; + switch (token->type) + { + case CHARACTER: + tree =3D create_token_tree (dfa, NULL, NULL, token); + if (BE (tree =3D=3D NULL, 0)) + { + *err =3D 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 =3D create_token_tree (dfa, NULL, NULL, token); + tree =3D create_tree (dfa, tree, mbc_remain, CONCAT); + if (BE (mbc_remain =3D=3D NULL || tree =3D=3D NULL, 0)) + { + *err =3D REG_ESPACE; + return NULL; + } + } + } +#endif + break; + + case OP_OPEN_SUBEXP: + tree =3D parse_sub_exp (regexp, preg, token, syntax, nest + 1, err= ); + if (BE (*err !=3D REG_NOERROR && tree =3D=3D NULL, 0)) + return NULL; + break; + + case OP_OPEN_BRACKET: + tree =3D parse_bracket_exp (regexp, dfa, token, syntax, err); + if (BE (*err !=3D REG_NOERROR && tree =3D=3D NULL, 0)) + return NULL; + break; + + case OP_BACK_REF: + if (!BE (dfa->completed_bkref_map & (1 << token->opr.idx), 1)) + { + *err =3D REG_ESUBREG; + return NULL; + } + dfa->used_bkref_map |=3D 1 << token->opr.idx; + tree =3D create_token_tree (dfa, NULL, NULL, token); + if (BE (tree =3D=3D NULL, 0)) + { + *err =3D REG_ESPACE; + return NULL; + } + ++dfa->nbackref; + dfa->has_mb_node =3D 1; + break; + + case OP_OPEN_DUP_NUM: + if (syntax & RE_CONTEXT_INVALID_DUP) + { + *err =3D REG_BADRPT; + return NULL; + } + FALLTHROUGH; + case OP_DUP_ASTERISK: + case OP_DUP_PLUS: + case OP_DUP_QUESTION: + if (syntax & RE_CONTEXT_INVALID_OPS) + { + *err =3D 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); + } + FALLTHROUGH; + case OP_CLOSE_SUBEXP: + if ((token->type =3D=3D OP_CLOSE_SUBEXP) && + !(syntax & RE_UNMATCHED_RIGHT_PAREN_ORD)) + { + *err =3D REG_ERPAREN; + return NULL; + } + FALLTHROUGH; + case OP_CLOSE_DUP_NUM: + /* We treat it as a normal character. */ + + /* Then we can these characters as normal characters. */ + token->type =3D CHARACTER; + /* mb_partial and word_char bits should be initialized already + by peek_token. */ + tree =3D create_token_tree (dfa, NULL, NULL, token); + if (BE (tree =3D=3D NULL, 0)) + { + *err =3D 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 =3D=3D 0) + init_word_char (dfa); + if (token->opr.ctx_type =3D=3D WORD_DELIM + || token->opr.ctx_type =3D=3D NOT_WORD_DELIM) + { + bin_tree_t *tree_first, *tree_last; + if (token->opr.ctx_type =3D=3D WORD_DELIM) + { + token->opr.ctx_type =3D WORD_FIRST; + tree_first =3D create_token_tree (dfa, NULL, NULL, token); + token->opr.ctx_type =3D WORD_LAST; + } + else + { + token->opr.ctx_type =3D INSIDE_WORD; + tree_first =3D create_token_tree (dfa, NULL, NULL, token); + token->opr.ctx_type =3D INSIDE_NOTWORD; + } + tree_last =3D create_token_tree (dfa, NULL, NULL, token); + tree =3D create_tree (dfa, tree_first, tree_last, OP_ALT); + if (BE (tree_first =3D=3D NULL || tree_last =3D=3D NULL || tree =3D=3D= NULL, 0)) + { + *err =3D REG_ESPACE; + return NULL; + } + } + else + { + tree =3D create_token_tree (dfa, NULL, NULL, token); + if (BE (tree =3D=3D NULL, 0)) + { + *err =3D REG_ESPACE; + return NULL; + } + } + /* We must return here, since ANCHORs can't be followed + by repetition operators. + eg. RE"^*" is invalid or "", + it must not be "". */ + fetch_token (token, regexp, syntax); + return tree; + + case OP_PERIOD: + tree =3D create_token_tree (dfa, NULL, NULL, token); + if (BE (tree =3D=3D NULL, 0)) + { + *err =3D REG_ESPACE; + return NULL; + } + if (dfa->mb_cur_max > 1) + dfa->has_mb_node =3D 1; + break; + + case OP_WORD: + case OP_NOTWORD: + tree =3D build_charclass_op (dfa, regexp->trans, + "alnum", + "_", + token->type =3D=3D OP_NOTWORD, err); + if (BE (*err !=3D REG_NOERROR && tree =3D=3D NULL, 0)) + return NULL; + break; + + case OP_SPACE: + case OP_NOTSPACE: + tree =3D build_charclass_op (dfa, regexp->trans, + "space", + "", + token->type =3D=3D OP_NOTSPACE, err); + if (BE (*err !=3D REG_NOERROR && tree =3D=3D NULL, 0)) + return NULL; + break; + + case OP_ALT: + case END_OF_RE: + return NULL; + + case BACK_SLASH: + *err =3D REG_EESCAPE; + return NULL; + + default: + /* Must not happen? */ +#ifdef DEBUG + assert (0); +#endif + return NULL; + } + fetch_token (token, regexp, syntax); + + while (token->type =3D=3D OP_DUP_ASTERISK || token->type =3D=3D OP_DUP= _PLUS + || token->type =3D=3D OP_DUP_QUESTION || token->type =3D=3D OP_OPEN_DU= P_NUM) + { + bin_tree_t *dup_tree =3D parse_dup_op (tree, regexp, dfa, token, + syntax, err); + if (BE (*err !=3D REG_NOERROR && dup_tree =3D=3D NULL, 0)) + { + if (tree !=3D NULL) + postorder (tree, free_tree, NULL); + return NULL; + } + tree =3D dup_tree; + /* In BRE consecutive duplications are not allowed. */ + if ((syntax & RE_CONTEXT_INVALID_DUP) + && (token->type =3D=3D OP_DUP_ASTERISK + || token->type =3D=3D OP_OPEN_DUP_NUM)) + { + if (tree !=3D NULL) + postorder (tree, free_tree, NULL); + *err =3D REG_BADRPT; + return NULL; + } + } + + return tree; +} + +/* This function build the following tree, from regular expression + (): + SUBEXP + | + +*/ + +static bin_tree_t * +parse_sub_exp (re_string_t *regexp, regex_t *preg, re_token_t *token, + reg_syntax_t syntax, Idx nest, reg_errcode_t *err) +{ + re_dfa_t *dfa =3D preg->buffer; + bin_tree_t *tree; + size_t cur_nsub; + cur_nsub =3D preg->re_nsub++; + + fetch_token (token, regexp, syntax | RE_CARET_ANCHORS_HERE); + + /* The subexpression may be a null string. */ + if (token->type =3D=3D OP_CLOSE_SUBEXP) + tree =3D NULL; + else + { + tree =3D parse_reg_exp (regexp, preg, token, syntax, nest, err); + if (BE (*err =3D=3D REG_NOERROR && token->type !=3D OP_CLOSE_SUBEX= P, 0)) + { + if (tree !=3D NULL) + postorder (tree, free_tree, NULL); + *err =3D REG_EPAREN; + } + if (BE (*err !=3D REG_NOERROR, 0)) + return NULL; + } + + if (cur_nsub <=3D '9' - '1') + dfa->completed_bkref_map |=3D 1 << cur_nsub; + + tree =3D create_tree (dfa, tree, NULL, SUBEXP); + if (BE (tree =3D=3D NULL, 0)) + { + *err =3D REG_ESPACE; + return NULL; + } + tree->token.opr.idx =3D 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 =3D NULL, *old_tree =3D NULL; + Idx i, start, end, start_idx =3D re_string_cur_idx (regexp); + re_token_t start_token =3D *token; + + if (token->type =3D=3D OP_OPEN_DUP_NUM) + { + end =3D 0; + start =3D fetch_number (regexp, token, syntax); + if (start =3D=3D -1) + { + if (token->type =3D=3D CHARACTER && token->opr.c =3D=3D ',') + start =3D 0; /* We treat "{,m}" as "{0,m}". */ + else + { + *err =3D REG_BADBR; /* {} is invalid. */ + return NULL; + } + } + if (BE (start !=3D -2, 1)) + { + /* We treat "{n}" as "{n,n}". */ + end =3D ((token->type =3D=3D OP_CLOSE_DUP_NUM) ? start + : ((token->type =3D=3D CHARACTER && token->opr.c =3D=3D ',') + ? fetch_number (regexp, token, syntax) : -2)); + } + if (BE (start =3D=3D -2 || end =3D=3D -2, 0)) + { + /* Invalid sequence. */ + if (BE (!(syntax & RE_INVALID_INTERVAL_ORD), 0)) + { + if (token->type =3D=3D END_OF_RE) + *err =3D REG_EBRACE; + else + *err =3D REG_BADBR; + + return NULL; + } + + /* If the syntax bit is set, rollback. */ + re_string_set_index (regexp, start_idx); + *token =3D start_token; + token->type =3D CHARACTER; + /* mb_partial and word_char bits should be already initialized by + peek_token. */ + return elem; + } + + if (BE ((end !=3D -1 && start > end) + || token->type !=3D OP_CLOSE_DUP_NUM, 0)) + { + /* First number greater than second. */ + *err =3D REG_BADBR; + return NULL; + } + + if (BE (RE_DUP_MAX < (end =3D=3D -1 ? start : end), 0)) + { + *err =3D REG_ESIZE; + return NULL; + } + } + else + { + start =3D (token->type =3D=3D OP_DUP_PLUS) ? 1 : 0; + end =3D (token->type =3D=3D OP_DUP_QUESTION) ? 1 : -1; + } + + fetch_token (token, regexp, syntax); + + if (BE (elem =3D=3D NULL, 0)) + return NULL; + if (BE (start =3D=3D 0 && end =3D=3D 0, 0)) + { + postorder (elem, free_tree, NULL); + return NULL; + } + + /* Extract "{n,m}" to "...{0,}". */ + if (BE (start > 0, 0)) + { + tree =3D elem; + for (i =3D 2; i <=3D start; ++i) + { + elem =3D duplicate_tree (elem, dfa); + tree =3D create_tree (dfa, tree, elem, CONCAT); + if (BE (elem =3D=3D NULL || tree =3D=3D NULL, 0)) + goto parse_dup_op_espace; + } + + if (start =3D=3D end) + return tree; + + /* Duplicate ELEM before it is marked optional. */ + elem =3D duplicate_tree (elem, dfa); + if (BE (elem =3D=3D NULL, 0)) + goto parse_dup_op_espace; + old_tree =3D tree; + } + else + old_tree =3D NULL; + + if (elem->token.type =3D=3D SUBEXP) + { + uintptr_t subidx =3D elem->token.opr.idx; + postorder (elem, mark_opt_subexp, (void *) subidx); + } + + tree =3D create_tree (dfa, elem, NULL, + (end =3D=3D -1 ? OP_DUP_ASTERISK : OP_ALT)); + if (BE (tree =3D=3D NULL, 0)) + goto parse_dup_op_espace; + + /* This loop is actually executed only when end !=3D -1, + to rewrite {0,n} as ((...?)?)?... We have + already created the start+1-th copy. */ + if (TYPE_SIGNED (Idx) || end !=3D -1) + for (i =3D start + 2; i <=3D end; ++i) + { + elem =3D duplicate_tree (elem, dfa); + tree =3D create_tree (dfa, tree, elem, CONCAT); + if (BE (elem =3D=3D NULL || tree =3D=3D NULL, 0)) + goto parse_dup_op_espace; + + tree =3D create_tree (dfa, tree, NULL, OP_ALT); + if (BE (tree =3D=3D NULL, 0)) + goto parse_dup_op_espace; + } + + if (old_tree) + tree =3D create_tree (dfa, old_tree, tree, CONCAT); + + return tree; + + parse_dup_op_espace: + *err =3D REG_ESPACE; + return NULL; +} + +/* Size of the names for collating symbol/equivalence_class/character_cl= ass. + I'm not sure, but maybe enough. */ +#define BRACKET_NAME_BUF_SIZE 32 + +#ifndef _LIBC + +# ifdef RE_ENABLE_I18N +/* Convert the byte B to the corresponding wide character. In a + unibyte locale, treat B as itself if it is an encoding error. + In a multibyte locale, return WEOF if B is an encoding error. */ +static wint_t +parse_byte (unsigned char b, re_charset_t *mbcset) +{ + wint_t wc =3D __btowc (b); + return wc =3D=3D WEOF && !mbcset ? b : wc; +} +#endif + + /* Local function for parse_bracket_exp only used in case of NOT _LIBC= . + 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 since we may + update it. */ + +static reg_errcode_t +# ifdef RE_ENABLE_I18N +build_range_exp (const reg_syntax_t syntax, + bitset_t sbcset, + re_charset_t *mbcset, + Idx *range_alloc, + const bracket_elem_t *start_elem, + const bracket_elem_t *end_elem) +# else /* not RE_ENABLE_I18N */ +build_range_exp (const reg_syntax_t syntax, + bitset_t sbcset, + const bracket_elem_t *start_elem, + const bracket_elem_t *end_elem) +# endif /* not RE_ENABLE_I18N */ +{ + unsigned int start_ch, end_ch; + /* Equivalence Classes and Character Classes can't be a range start/en= d. */ + if (BE (start_elem->type =3D=3D EQUIV_CLASS || start_elem->type =3D=3D= CHAR_CLASS + || end_elem->type =3D=3D EQUIV_CLASS || end_elem->type =3D=3D CHAR_CL= ASS, + 0)) + return REG_ERANGE; + + /* We can handle no multi character collating elements without libc + support. */ + if (BE ((start_elem->type =3D=3D COLL_SYM + && strlen ((char *) start_elem->opr.name) > 1) + || (end_elem->type =3D=3D 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; + + start_ch =3D ((start_elem->type =3D=3D SB_CHAR) ? start_elem->opr.ch + : ((start_elem->type =3D=3D COLL_SYM) ? start_elem->opr.name[0] + : 0)); + end_ch =3D ((end_elem->type =3D=3D SB_CHAR) ? end_elem->opr.ch + : ((end_elem->type =3D=3D COLL_SYM) ? end_elem->opr.name[0] + : 0)); + start_wc =3D ((start_elem->type =3D=3D SB_CHAR || start_elem->type =3D= =3D COLL_SYM) + ? parse_byte (start_ch, mbcset) : start_elem->opr.wch); + end_wc =3D ((end_elem->type =3D=3D SB_CHAR || end_elem->type =3D=3D = COLL_SYM) + ? parse_byte (end_ch, mbcset) : end_elem->opr.wch); + if (start_wc =3D=3D WEOF || end_wc =3D=3D WEOF) + return REG_ECOLLATE; + else if (BE ((syntax & RE_NO_EMPTY_RANGES) && start_wc > end_wc, 0)) + return REG_ERANGE; + + /* Got valid collation sequence values, add them as a new entry. + However, for !_LIBC we have no collation elements: if the + character set is single byte, the single byte character set + that we build below suffices. parse_bracket_exp passes + no MBCSET if dfa->mb_cur_max =3D=3D 1. */ + if (mbcset) + { + /* Check the space of the arrays. */ + if (BE (*range_alloc =3D=3D mbcset->nranges, 0)) + { + /* There is not enough space, need realloc. */ + wchar_t *new_array_start, *new_array_end; + Idx new_nranges; + + /* +1 in case of mbcset->nranges is 0. */ + new_nranges =3D 2 * mbcset->nranges + 1; + /* Use realloc since mbcset->range_starts and mbcset->range_ends + are NULL if *range_alloc =3D=3D 0. */ + new_array_start =3D re_realloc (mbcset->range_starts, wchar_t, + new_nranges); + new_array_end =3D re_realloc (mbcset->range_ends, wchar_t, + new_nranges); + + if (BE (new_array_start =3D=3D NULL || new_array_end =3D=3D NULL, 0= )) + { + re_free (new_array_start); + re_free (new_array_end); + return REG_ESPACE; + } + + mbcset->range_starts =3D new_array_start; + mbcset->range_ends =3D new_array_end; + *range_alloc =3D new_nranges; + } + + mbcset->range_starts[mbcset->nranges] =3D start_wc; + mbcset->range_ends[mbcset->nranges++] =3D end_wc; + } + + /* Build the table for single byte characters. */ + for (wc =3D 0; wc < SBC_MAX; ++wc) + { + if (start_wc <=3D wc && wc <=3D end_wc) + bitset_set (sbcset, wc); + } + } +# else /* not RE_ENABLE_I18N */ + { + unsigned int ch; + start_ch =3D ((start_elem->type =3D=3D SB_CHAR ) ? start_elem->opr.c= h + : ((start_elem->type =3D=3D COLL_SYM) ? start_elem->opr.name[0] + : 0)); + end_ch =3D ((end_elem->type =3D=3D SB_CHAR ) ? end_elem->opr.ch + : ((end_elem->type =3D=3D 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 =3D 0; ch < SBC_MAX; ++ch) + if (start_ch <=3D ch && ch <=3D end_ch) + bitset_set (sbcset, ch); + } +# endif /* not RE_ENABLE_I18N */ + return REG_NOERROR; +} +#endif /* not _LIBC */ + +#ifndef _LIBC +/* Helper function for parse_bracket_exp only used in case of NOT _LIBC.= . + 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 +# ifdef RE_ENABLE_I18N +build_collating_symbol (bitset_t sbcset, re_charset_t *mbcset, + Idx *coll_sym_alloc, const unsigned char *name) +# else /* not RE_ENABLE_I18N */ +build_collating_symbol (bitset_t sbcset, const unsigned char *name) +# endif /* not RE_ENABLE_I18N */ +{ + size_t name_len =3D strlen ((const char *) name); + if (BE (name_len !=3D 1, 0)) + return REG_ECOLLATE; + else + { + bitset_set (sbcset, name[0]); + return REG_NOERROR; + } +} +#endif /* not _LIBC */ + +/* 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) +{ +#ifdef _LIBC + 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 _LIBC environment. + Seek the collating symbol entry corresponding to NAME. + Return the index of the symbol in the SYMB_TABLE, + or -1 if not found. */ + + auto inline int32_t + __attribute__ ((always_inline)) + seek_collating_symbol_entry (const unsigned char *name, size_t name_le= n) + { + int32_t elem; + + for (elem =3D 0; elem < table_size; elem++) + if (symb_table[2 * elem] !=3D 0) + { + int32_t idx =3D symb_table[2 * elem + 1]; + /* Skip the name of collating element name. */ + idx +=3D 1 + extra[idx]; + if (/* Compare the length of the name. */ + name_len =3D=3D extra[idx] + /* Compare the name. */ + && memcmp (name, &extra[idx + 1], name_len) =3D=3D 0) + /* Yep, this is the entry. */ + return elem; + } + return -1; + } + + /* Local function for parse_bracket_exp used in _LIBC environment. + 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 =3D=3D SB_CHAR) + { + /* + if (MB_CUR_MAX =3D=3D 1) + */ + if (nrules =3D=3D 0) + return collseqmb[br_elem->opr.ch]; + else + { + wint_t wc =3D __btowc (br_elem->opr.ch); + return __collseq_table_lookup (collseqwc, wc); + } + } + else if (br_elem->type =3D=3D MB_CHAR) + { + if (nrules !=3D 0) + return __collseq_table_lookup (collseqwc, br_elem->opr.wch); + } + else if (br_elem->type =3D=3D COLL_SYM) + { + size_t sym_name_len =3D strlen ((char *) br_elem->opr.name); + if (nrules !=3D 0) + { + int32_t elem, idx; + elem =3D seek_collating_symbol_entry (br_elem->opr.name, + sym_name_len); + if (elem !=3D -1) + { + /* We found the entry. */ + idx =3D symb_table[2 * elem + 1]; + /* Skip the name of collating element name. */ + idx +=3D 1 + extra[idx]; + /* Skip the byte sequence of the collating element. */ + idx +=3D 1 + extra[idx]; + /* Adjust for the alignment. */ + idx =3D (idx + 3) & ~3; + /* Skip the multibyte collation sequence value. */ + idx +=3D sizeof (unsigned int); + /* Skip the wide char sequence of the collating element. */ + idx +=3D sizeof (unsigned int) * + (1 + *(unsigned int *) (extra + idx)); + /* Return the collation sequence value. */ + return *(unsigned int *) (extra + idx); + } + else if (sym_name_len =3D=3D 1) + { + /* No valid character. Match it as a single byte + character. */ + return collseqmb[br_elem->opr.name[0]]; + } + } + else if (sym_name_len =3D=3D 1) + return collseqmb[br_elem->opr.name[0]]; + } + return UINT_MAX; + } + + /* Local function for parse_bracket_exp used in _LIBC environment. + 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 since we may + update it. */ + + auto inline reg_errcode_t + __attribute__ ((always_inline)) + build_range_exp (bitset_t sbcset, re_charset_t *mbcset, int *range_all= oc, + 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 =3D=3D EQUIV_CLASS || start_elem->type =3D= =3D CHAR_CLASS + || end_elem->type =3D=3D EQUIV_CLASS || end_elem->type =3D=3D CHA= R_CLASS, + 0)) + return REG_ERANGE; + + /* FIXME: Implement rational ranges here, too. */ + start_collseq =3D lookup_collation_sequence_value (start_elem); + end_collseq =3D lookup_collation_sequence_value (end_elem); + /* Check start/end collation sequence values. */ + if (BE (start_collseq =3D=3D UINT_MAX || end_collseq =3D=3D UINT_M= AX, 0)) + return REG_ECOLLATE; + if (BE ((syntax & RE_NO_EMPTY_RANGES) && start_collseq > end_colls= eq, 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 =3D=3D mbcset->nranges, 0)) + { + /* There is not enough space, need realloc. */ + uint32_t *new_array_start; + uint32_t *new_array_end; + Idx new_nranges; + + /* +1 in case of mbcset->nranges is 0. */ + new_nranges =3D 2 * mbcset->nranges + 1; + new_array_start =3D re_realloc (mbcset->range_starts, uint32_t, + new_nranges); + new_array_end =3D re_realloc (mbcset->range_ends, uint32_t, + new_nranges); + + if (BE (new_array_start =3D=3D NULL || new_array_end =3D=3D NULL,= 0)) + return REG_ESPACE; + + mbcset->range_starts =3D new_array_start; + mbcset->range_ends =3D new_array_end; + *range_alloc =3D new_nranges; + } + + mbcset->range_starts[mbcset->nranges] =3D start_collseq; + mbcset->range_ends[mbcset->nranges++] =3D end_collseq; + } + + /* Build the table for single byte characters. */ + for (ch =3D 0; ch < SBC_MAX; ch++) + { + uint32_t ch_collseq; + /* + if (MB_CUR_MAX =3D=3D 1) + */ + if (nrules =3D=3D 0) + ch_collseq =3D collseqmb[ch]; + else + ch_collseq =3D __collseq_table_lookup (collseqwc, __btowc (ch)); + if (start_collseq <=3D ch_collseq && ch_collseq <=3D end_collseq) + bitset_set (sbcset, ch); + } + return REG_NOERROR; + } + + /* Local function for parse_bracket_exp used in _LIBC environment. + 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. */ + + auto inline reg_errcode_t + __attribute__ ((always_inline)) + build_collating_symbol (bitset_t sbcset, re_charset_t *mbcset, + Idx *coll_sym_alloc, const unsigned char *name) + { + int32_t elem, idx; + size_t name_len =3D strlen ((const char *) name); + if (nrules !=3D 0) + { + elem =3D seek_collating_symbol_entry (name, name_len); + if (elem !=3D -1) + { + /* We found the entry. */ + idx =3D symb_table[2 * elem + 1]; + /* Skip the name of collating element name. */ + idx +=3D 1 + extra[idx]; + } + else if (name_len =3D=3D 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 =3D=3D mbcset->ncoll_syms, 0)) + { + /* Not enough, realloc it. */ + /* +1 in case of mbcset->ncoll_syms is 0. */ + Idx new_coll_sym_alloc =3D 2 * mbcset->ncoll_syms + 1; + /* Use realloc since mbcset->coll_syms is NULL + if *alloc =3D=3D 0. */ + int32_t *new_coll_syms =3D re_realloc (mbcset->coll_syms, int32_t= , + new_coll_sym_alloc); + if (BE (new_coll_syms =3D=3D NULL, 0)) + return REG_ESPACE; + mbcset->coll_syms =3D new_coll_syms; + *coll_sym_alloc =3D new_coll_sym_alloc; + } + mbcset->coll_syms[mbcset->ncoll_syms++] =3D idx; + return REG_NOERROR; + } + else + { + if (BE (name_len !=3D 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; + Idx coll_sym_alloc =3D 0, range_alloc =3D 0, mbchar_alloc =3D 0; + Idx equiv_class_alloc =3D 0, char_class_alloc =3D 0; +#endif /* not RE_ENABLE_I18N */ + bool non_match =3D false; + bin_tree_t *work_tree; + int token_len; + bool first_round =3D true; +#ifdef _LIBC + collseqmb =3D (const unsigned char *) + _NL_CURRENT (LC_COLLATE, _NL_COLLATE_COLLSEQMB); + nrules =3D _NL_CURRENT_WORD (LC_COLLATE, _NL_COLLATE_NRULES); + if (nrules) + { + /* + if (MB_CUR_MAX > 1) + */ + collseqwc =3D _NL_CURRENT (LC_COLLATE, _NL_COLLATE_COLLSEQWC); + table_size =3D _NL_CURRENT_WORD (LC_COLLATE, _NL_COLLATE_SYMB_HASH= _SIZEMB); + symb_table =3D (const int32_t *) _NL_CURRENT (LC_COLLATE, + _NL_COLLATE_SYMB_TABLEMB); + extra =3D (const unsigned char *) _NL_CURRENT (LC_COLLATE, + _NL_COLLATE_SYMB_EXTRAMB); + } +#endif + sbcset =3D (re_bitset_ptr_t) calloc (sizeof (bitset_t), 1); +#ifdef RE_ENABLE_I18N + mbcset =3D (re_charset_t *) calloc (sizeof (re_charset_t), 1); +#endif /* RE_ENABLE_I18N */ +#ifdef RE_ENABLE_I18N + if (BE (sbcset =3D=3D NULL || mbcset =3D=3D NULL, 0)) +#else + if (BE (sbcset =3D=3D NULL, 0)) +#endif /* RE_ENABLE_I18N */ + { + re_free (sbcset); +#ifdef RE_ENABLE_I18N + re_free (mbcset); +#endif + *err =3D REG_ESPACE; + return NULL; + } + + token_len =3D peek_token_bracket (token, regexp, syntax); + if (BE (token->type =3D=3D END_OF_RE, 0)) + { + *err =3D REG_BADPAT; + goto parse_bracket_exp_free_return; + } + if (token->type =3D=3D OP_NON_MATCH_LIST) + { +#ifdef RE_ENABLE_I18N + mbcset->non_match =3D 1; +#endif /* not RE_ENABLE_I18N */ + non_match =3D true; + if (syntax & RE_HAT_LISTS_NOT_NEWLINE) + bitset_set (sbcset, '\n'); + re_string_skip_bytes (regexp, token_len); /* Skip a token. */ + token_len =3D peek_token_bracket (token, regexp, syntax); + if (BE (token->type =3D=3D END_OF_RE, 0)) + { + *err =3D REG_BADPAT; + goto parse_bracket_exp_free_return; + } + } + + /* We treat the first ']' as a normal character. */ + if (token->type =3D=3D OP_CLOSE_BRACKET) + token->type =3D 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 =3D 0; + bool is_range_exp =3D false; + re_token_t token2; + + start_elem.opr.name =3D start_name_buf; + start_elem.type =3D COLL_SYM; + ret =3D parse_bracket_element (&start_elem, regexp, token, token_l= en, dfa, + syntax, first_round); + if (BE (ret !=3D REG_NOERROR, 0)) + { + *err =3D ret; + goto parse_bracket_exp_free_return; + } + first_round =3D false; + + /* Get information about the next token. We need it in any case. = */ + token_len =3D peek_token_bracket (token, regexp, syntax); + + /* Do not check for ranges if we know they are not allowed. */ + if (start_elem.type !=3D CHAR_CLASS && start_elem.type !=3D EQUIV_= CLASS) + { + if (BE (token->type =3D=3D END_OF_RE, 0)) + { + *err =3D REG_EBRACK; + goto parse_bracket_exp_free_return; + } + if (token->type =3D=3D OP_CHARSET_RANGE) + { + re_string_skip_bytes (regexp, token_len); /* Skip '-'. */ + token_len2 =3D peek_token_bracket (&token2, regexp, syntax); + if (BE (token2.type =3D=3D END_OF_RE, 0)) + { + *err =3D REG_EBRACK; + goto parse_bracket_exp_free_return; + } + if (token2.type =3D=3D OP_CLOSE_BRACKET) + { + /* We treat the last '-' as a normal character. */ + re_string_skip_bytes (regexp, -token_len); + token->type =3D CHARACTER; + } + else + is_range_exp =3D true; + } + } + + if (is_range_exp =3D=3D true) + { + end_elem.opr.name =3D end_name_buf; + end_elem.type =3D COLL_SYM; + ret =3D parse_bracket_element (&end_elem, regexp, &token2, token_len2= , + dfa, syntax, true); + if (BE (ret !=3D REG_NOERROR, 0)) + { + *err =3D ret; + goto parse_bracket_exp_free_return; + } + + token_len =3D peek_token_bracket (token, regexp, syntax); + +#ifdef _LIBC + *err =3D build_range_exp (sbcset, mbcset, &range_alloc, + &start_elem, &end_elem); +#else +# ifdef RE_ENABLE_I18N + *err =3D build_range_exp (syntax, sbcset, + dfa->mb_cur_max > 1 ? mbcset : NULL, + &range_alloc, &start_elem, &end_elem); +# else + *err =3D build_range_exp (syntax, sbcset, &start_elem, &end_elem); +# endif +#endif /* RE_ENABLE_I18N */ + if (BE (*err !=3D 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 =3D=3D mbcset->nmbchars, 0)) + { + wchar_t *new_mbchars; + /* Not enough, realloc it. */ + /* +1 in case of mbcset->nmbchars is 0. */ + mbchar_alloc =3D 2 * mbcset->nmbchars + 1; + /* Use realloc since array is NULL if *alloc =3D=3D 0. */ + new_mbchars =3D re_realloc (mbcset->mbchars, wchar_t, + mbchar_alloc); + if (BE (new_mbchars =3D=3D NULL, 0)) + goto parse_bracket_exp_espace; + mbcset->mbchars =3D new_mbchars; + } + mbcset->mbchars[mbcset->nmbchars++] =3D start_elem.opr.wch; + break; +#endif /* RE_ENABLE_I18N */ + case EQUIV_CLASS: + *err =3D build_equiv_class (sbcset, +#ifdef RE_ENABLE_I18N + mbcset, &equiv_class_alloc, +#endif /* RE_ENABLE_I18N */ + start_elem.opr.name); + if (BE (*err !=3D REG_NOERROR, 0)) + goto parse_bracket_exp_free_return; + break; + case COLL_SYM: + *err =3D build_collating_symbol (sbcset, +#ifdef RE_ENABLE_I18N + mbcset, &coll_sym_alloc, +#endif /* RE_ENABLE_I18N */ + start_elem.opr.name); + if (BE (*err !=3D REG_NOERROR, 0)) + goto parse_bracket_exp_free_return; + break; + case CHAR_CLASS: + *err =3D build_charclass (regexp->trans, sbcset, +#ifdef RE_ENABLE_I18N + mbcset, &char_class_alloc, +#endif /* RE_ENABLE_I18N */ + (const char *) start_elem.opr.name, + syntax); + if (BE (*err !=3D REG_NOERROR, 0)) + goto parse_bracket_exp_free_return; + break; + default: + assert (0); + break; + } + } + if (BE (token->type =3D=3D END_OF_RE, 0)) + { + *err =3D REG_EBRACK; + goto parse_bracket_exp_free_return; + } + if (token->type =3D=3D 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_class= es + || mbcset->non_match))) + { + bin_tree_t *mbc_tree; + int sbc_idx; + /* Build a tree for complex bracket. */ + dfa->has_mb_node =3D 1; + br_token.type =3D COMPLEX_BRACKET; + br_token.opr.mbcset =3D mbcset; + mbc_tree =3D create_token_tree (dfa, NULL, NULL, &br_token); + if (BE (mbc_tree =3D=3D NULL, 0)) + goto parse_bracket_exp_espace; + for (sbc_idx =3D 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 =3D SIMPLE_BRACKET; + br_token.opr.sbcset =3D sbcset; + work_tree =3D create_token_tree (dfa, NULL, NULL, &br_token); + if (BE (work_tree =3D=3D NULL, 0)) + goto parse_bracket_exp_espace; + + /* Then join them by ALT node. */ + work_tree =3D create_tree (dfa, work_tree, mbc_tree, OP_ALT); + if (BE (work_tree =3D=3D NULL, 0)) + goto parse_bracket_exp_espace; + } + else + { + re_free (sbcset); + work_tree =3D 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 =3D SIMPLE_BRACKET; + br_token.opr.sbcset =3D sbcset; + work_tree =3D create_token_tree (dfa, NULL, NULL, &br_token); + if (BE (work_tree =3D=3D NULL, 0)) + goto parse_bracket_exp_espace; + } + return work_tree; + + parse_bracket_exp_espace: + *err =3D REG_ESPACE; + parse_bracket_exp_free_return: + re_free (sbcset); +#ifdef RE_ENABLE_I18N + free_charset (mbcset); +#endif /* RE_ENABLE_I18N */ + 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, bool accept_hyphen) +{ +#ifdef RE_ENABLE_I18N + int cur_char_size; + cur_char_size =3D re_string_char_size_at (regexp, re_string_cur_idx (r= egexp)); + if (cur_char_size > 1) + { + elem->type =3D MB_CHAR; + elem->opr.wch =3D re_string_wchar_at (regexp, re_string_cur_idx (r= egexp)); + 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 =3D=3D OP_OPEN_COLL_ELEM || token->type =3D=3D OP_OPEN= _CHAR_CLASS + || token->type =3D=3D OP_OPEN_EQUIV_CLASS) + return parse_bracket_symbol (elem, regexp, token); + if (BE (token->type =3D=3D 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 !=3D 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 =3D SB_CHAR; + elem->opr.ch =3D token->opr.c; + return REG_NOERROR; +} + +/* Parse a bracket symbol in the bracket expression. Bracket symbols ar= e + such as [::], [..], and + [=3D=3D]. */ + +static reg_errcode_t +parse_bracket_symbol (bracket_elem_t *elem, re_string_t *regexp, + re_token_t *token) +{ + unsigned char ch, delim =3D token->opr.c; + int i =3D 0; + if (re_string_eoi(regexp)) + return REG_EBRACK; + for (;; ++i) + { + if (i >=3D BRACKET_NAME_BUF_SIZE) + return REG_EBRACK; + if (token->type =3D=3D OP_OPEN_CHAR_CLASS) + ch =3D re_string_fetch_byte_case (regexp); + else + ch =3D re_string_fetch_byte (regexp); + if (re_string_eoi(regexp)) + return REG_EBRACK; + if (ch =3D=3D delim && re_string_peek_byte (regexp, 0) =3D=3D ']') + break; + elem->opr.name[i] =3D ch; + } + re_string_skip_bytes (regexp, 1); + elem->opr.name[i] =3D '\0'; + switch (token->type) + { + case OP_OPEN_COLL_ELEM: + elem->type =3D COLL_SYM; + break; + case OP_OPEN_EQUIV_CLASS: + elem->type =3D EQUIV_CLASS; + break; + case OP_OPEN_CHAR_CLASS: + elem->type =3D 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 since we may update it. */ + +static reg_errcode_t +#ifdef RE_ENABLE_I18N +build_equiv_class (bitset_t sbcset, re_charset_t *mbcset, + Idx *equiv_class_alloc, const unsigned char *name) +#else /* not RE_ENABLE_I18N */ +build_equiv_class (bitset_t sbcset, const unsigned char *name) +#endif /* not RE_ENABLE_I18N */ +{ +#ifdef _LIBC + uint32_t nrules =3D _NL_CURRENT_WORD (LC_COLLATE, _NL_COLLATE_NRULES); + if (nrules !=3D 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; + /* Calculate the index for equivalence class. */ + cp =3D name; + table =3D (const int32_t *) _NL_CURRENT (LC_COLLATE, _NL_COLLATE_T= ABLEMB); + weights =3D (const unsigned char *) _NL_CURRENT (LC_COLLATE, + _NL_COLLATE_WEIGHTMB); + extra =3D (const unsigned char *) _NL_CURRENT (LC_COLLATE, + _NL_COLLATE_EXTRAMB); + indirect =3D (const int32_t *) _NL_CURRENT (LC_COLLATE, + _NL_COLLATE_INDIRECTMB); + idx1 =3D findidx (table, indirect, extra, &cp, -1); + if (BE (idx1 =3D=3D 0 || *cp !=3D '\0', 0)) + /* This isn't a valid character. */ + return REG_ECOLLATE; + + /* Build single byte matching table for this equivalence class. *= / + len =3D weights[idx1 & 0xffffff]; + for (ch =3D 0; ch < SBC_MAX; ++ch) + { + char_buf[0] =3D ch; + cp =3D char_buf; + idx2 =3D findidx (table, indirect, extra, &cp, 1); +/* + idx2 =3D table[ch]; +*/ + if (idx2 =3D=3D 0) + /* This isn't a valid character. */ + continue; + /* Compare only if the length matches and the collation rule + index is the same. */ + if (len =3D=3D weights[idx2 & 0xffffff] && (idx1 >> 24) =3D=3D (idx2 = >> 24)) + { + int cnt =3D 0; + + while (cnt <=3D len && + weights[(idx1 & 0xffffff) + 1 + cnt] + =3D=3D weights[(idx2 & 0xffffff) + 1 + cnt]) + ++cnt; + + if (cnt > len) + bitset_set (sbcset, ch); + } + } + /* Check whether the array has enough space. */ + if (BE (*equiv_class_alloc =3D=3D mbcset->nequiv_classes, 0)) + { + /* Not enough, realloc it. */ + /* +1 in case of mbcset->nequiv_classes is 0. */ + Idx new_equiv_class_alloc =3D 2 * mbcset->nequiv_classes + 1; + /* Use realloc since the array is NULL if *alloc =3D=3D 0. */ + int32_t *new_equiv_classes =3D re_realloc (mbcset->equiv_classes, + int32_t, + new_equiv_class_alloc); + if (BE (new_equiv_classes =3D=3D NULL, 0)) + return REG_ESPACE; + mbcset->equiv_classes =3D new_equiv_classes; + *equiv_class_alloc =3D new_equiv_class_alloc; + } + mbcset->equiv_classes[mbcset->nequiv_classes++] =3D idx1; + } + else +#endif /* _LIBC */ + { + if (BE (strlen ((const char *) name) !=3D 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 since 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, Idx *char_class_alloc, + const char *class_name, reg_syntax_t syntax) +#else /* not RE_ENABLE_I18N */ +build_charclass (RE_TRANSLATE_TYPE trans, bitset_t sbcset, + const char *class_name, reg_syntax_t syntax) +#endif /* not RE_ENABLE_I18N */ +{ + int i; + const char *name =3D 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") =3D=3D 0 || strcmp (name, "lower") =3D=3D= 0)) + name =3D "alpha"; + +#ifdef RE_ENABLE_I18N + /* Check the space of the arrays. */ + if (BE (*char_class_alloc =3D=3D mbcset->nchar_classes, 0)) + { + /* Not enough, realloc it. */ + /* +1 in case of mbcset->nchar_classes is 0. */ + Idx new_char_class_alloc =3D 2 * mbcset->nchar_classes + 1; + /* Use realloc since array is NULL if *alloc =3D=3D 0. */ + wctype_t *new_char_classes =3D re_realloc (mbcset->char_classes, w= ctype_t, + new_char_class_alloc); + if (BE (new_char_classes =3D=3D NULL, 0)) + return REG_ESPACE; + mbcset->char_classes =3D new_char_classes; + *char_class_alloc =3D new_char_class_alloc; + } + mbcset->char_classes[mbcset->nchar_classes++] =3D __wctype (name); +#endif /* RE_ENABLE_I18N */ + +#define BUILD_CHARCLASS_LOOP(ctype_func) \ + do { \ + if (BE (trans !=3D NULL, 0)) \ + { \ + for (i =3D 0; i < SBC_MAX; ++i) \ + if (ctype_func (i)) \ + bitset_set (sbcset, trans[i]); \ + } \ + else \ + { \ + for (i =3D 0; i < SBC_MAX; ++i) \ + if (ctype_func (i)) \ + bitset_set (sbcset, i); \ + } \ + } while (0) + + if (strcmp (name, "alnum") =3D=3D 0) + BUILD_CHARCLASS_LOOP (isalnum); + else if (strcmp (name, "cntrl") =3D=3D 0) + BUILD_CHARCLASS_LOOP (iscntrl); + else if (strcmp (name, "lower") =3D=3D 0) + BUILD_CHARCLASS_LOOP (islower); + else if (strcmp (name, "space") =3D=3D 0) + BUILD_CHARCLASS_LOOP (isspace); + else if (strcmp (name, "alpha") =3D=3D 0) + BUILD_CHARCLASS_LOOP (isalpha); + else if (strcmp (name, "digit") =3D=3D 0) + BUILD_CHARCLASS_LOOP (isdigit); + else if (strcmp (name, "print") =3D=3D 0) + BUILD_CHARCLASS_LOOP (isprint); + else if (strcmp (name, "upper") =3D=3D 0) + BUILD_CHARCLASS_LOOP (isupper); + else if (strcmp (name, "blank") =3D=3D 0) + BUILD_CHARCLASS_LOOP (isblank); + else if (strcmp (name, "graph") =3D=3D 0) + BUILD_CHARCLASS_LOOP (isgraph); + else if (strcmp (name, "punct") =3D=3D 0) + BUILD_CHARCLASS_LOOP (ispunct); + else if (strcmp (name, "xdigit") =3D=3D 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 char *class_name, + const char *extra, bool non_match, + reg_errcode_t *err) +{ + re_bitset_ptr_t sbcset; +#ifdef RE_ENABLE_I18N + re_charset_t *mbcset; + Idx alloc =3D 0; +#endif /* not RE_ENABLE_I18N */ + reg_errcode_t ret; + re_token_t br_token; + bin_tree_t *tree; + + sbcset =3D (re_bitset_ptr_t) calloc (sizeof (bitset_t), 1); + if (BE (sbcset =3D=3D NULL, 0)) + { + *err =3D REG_ESPACE; + return NULL; + } +#ifdef RE_ENABLE_I18N + mbcset =3D (re_charset_t *) calloc (sizeof (re_charset_t), 1); + if (BE (mbcset =3D=3D NULL, 0)) + { + re_free (sbcset); + *err =3D REG_ESPACE; + return NULL; + } + mbcset->non_match =3D non_match; +#endif /* RE_ENABLE_I18N */ + + /* We don't care the syntax in this case. */ + ret =3D build_charclass (trans, sbcset, +#ifdef RE_ENABLE_I18N + mbcset, &alloc, +#endif /* RE_ENABLE_I18N */ + class_name, 0); + + if (BE (ret !=3D REG_NOERROR, 0)) + { + re_free (sbcset); +#ifdef RE_ENABLE_I18N + free_charset (mbcset); +#endif /* RE_ENABLE_I18N */ + *err =3D 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. */ +#if defined GCC_LINT || defined lint + memset (&br_token, 0, sizeof br_token); +#endif + br_token.type =3D SIMPLE_BRACKET; + br_token.opr.sbcset =3D sbcset; + tree =3D create_token_tree (dfa, NULL, NULL, &br_token); + if (BE (tree =3D=3D 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 =3D COMPLEX_BRACKET; + br_token.opr.mbcset =3D mbcset; + dfa->has_mb_node =3D 1; + mbc_tree =3D create_token_tree (dfa, NULL, NULL, &br_token); + if (BE (mbc_tree =3D=3D NULL, 0)) + goto build_word_op_espace; + /* Then join them by ALT node. */ + tree =3D create_tree (dfa, tree, mbc_tree, OP_ALT); + if (BE (mbc_tree !=3D NULL, 1)) + return tree; + } + else + { + free_charset (mbcset); + return tree; + } +#else /* not RE_ENABLE_I18N */ + return tree; +#endif /* not RE_ENABLE_I18N */ + + build_word_op_espace: + re_free (sbcset); +#ifdef RE_ENABLE_I18N + free_charset (mbcset); +#endif /* RE_ENABLE_I18N */ + *err =3D 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 RE_DUP_MAX + 1 if the number field is too large. + Return -2 if an error occurred. */ + +static Idx +fetch_number (re_string_t *input, re_token_t *token, reg_syntax_t syntax= ) +{ + Idx num =3D -1; + unsigned char c; + while (1) + { + fetch_token (token, input, syntax); + c =3D token->opr.c; + if (BE (token->type =3D=3D END_OF_RE, 0)) + return -2; + if (token->type =3D=3D OP_CLOSE_DUP_NUM || c =3D=3D ',') + break; + num =3D ((token->type !=3D CHARACTER || c < '0' || '9' < c || num = =3D=3D -2) + ? -2 + : num =3D=3D -1 + ? c - '0' + : MIN (RE_DUP_MAX + 1, num * 10 + c - '0')); + } + return num; +} +=0C +#ifdef RE_ENABLE_I18N +static void +free_charset (re_charset_t *cset) +{ + re_free (cset->mbchars); +# ifdef _LIBC + 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 */ +=0C +/* 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; +#if defined GCC_LINT || defined lint + memset (&t, 0, sizeof t); +#endif + t.type =3D 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 =3D=3D BIN_TREE_STORAGE_SIZE, 0)) + { + bin_tree_storage_t *storage =3D re_malloc (bin_tree_storage_t, 1); + + if (storage =3D=3D NULL) + return NULL; + storage->next =3D dfa->str_tree_storage; + dfa->str_tree_storage =3D storage; + dfa->str_tree_storage_idx =3D 0; + } + tree =3D &dfa->str_tree_storage->data[dfa->str_tree_storage_idx++]; + + tree->parent =3D NULL; + tree->left =3D left; + tree->right =3D right; + tree->token =3D *token; + tree->token.duplicated =3D 0; + tree->token.opt_subexp =3D 0; + tree->first =3D NULL; + tree->next =3D NULL; + tree->node_idx =3D -1; + + if (left !=3D NULL) + left->parent =3D tree; + if (right !=3D NULL) + right->parent =3D 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) +{ + Idx idx =3D (uintptr_t) extra; + if (node->token.type =3D=3D SUBEXP && node->token.opr.idx =3D=3D idx) + node->token.opt_subexp =3D 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 =3D=3D COMPLEX_BRACKET && node->duplicated =3D=3D 0) + free_charset (node->opr.mbcset); + else +#endif /* RE_ENABLE_I18N */ + if (node->type =3D=3D SIMPLE_BRACKET && node->duplicated =3D=3D 0) + re_free (node->opr.sbcset); +} + +/* Worker function for tree walking. Free the allocated memory inside N= ODE + 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 =3D &dup_root, *dup_node =3D root->parent; + + for (node =3D root; ; ) + { + /* Create a new tree and link it back to the current parent. */ + *p_new =3D create_token_tree (dfa, NULL, NULL, &node->token); + if (*p_new =3D=3D NULL) + return NULL; + (*p_new)->parent =3D dup_node; + (*p_new)->token.duplicated =3D 1; + dup_node =3D *p_new; + + /* Go to the left node, or up and to the right. */ + if (node->left) + { + node =3D node->left; + p_new =3D &dup_node->left; + } + else + { + const bin_tree_t *prev =3D NULL; + while (node->right =3D=3D prev || node->right =3D=3D NULL) + { + prev =3D node; + node =3D node->parent; + dup_node =3D dup_node->parent; + if (!node) + return dup_root; + } + node =3D node->right; + p_new =3D &dup_node->right; + } + } +} diff --git a/lib/regex.c b/lib/regex.c new file mode 100644 index 0000000000..499e1f0e03 --- /dev/null +++ b/lib/regex.c @@ -0,0 +1,81 @@ +/* Extended regular expression matching and search library. + Copyright (C) 2002-2018 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Isamu Hasegawa . + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU General Public + License as published by the Free Software Foundation; either + version 3 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 + General Public License for more details. + + You should have received a copy of the GNU General Public + License along with the GNU C Library; if not, see + . */ + +#ifndef _LIBC +# include + +# if (__GNUC__ =3D=3D 4 && 6 <=3D __GNUC_MINOR__) || 4 < __GNUC__ +# pragma GCC diagnostic ignored "-Wsuggest-attribute=3Dpure" +# endif +# if (__GNUC__ =3D=3D 4 && 3 <=3D __GNUC_MINOR__) || 4 < __GNUC__ +# pragma GCC diagnostic ignored "-Wold-style-definition" +# pragma GCC diagnostic ignored "-Wtype-limits" +# endif +#endif + +/* Make sure no one compiles this code with a C++ compiler. */ +#if defined __cplusplus && defined _LIBC +# error "This is C code, use a C compiler" +#endif + +#ifdef _LIBC +/* We have to keep the namespace clean. */ +# define regfree(preg) __regfree (preg) +# define regexec(pr, st, nm, pm, ef) __regexec (pr, st, nm, pm, ef) +# define regcomp(preg, pattern, cflags) __regcomp (preg, pattern, cflags= ) +# define regerror(errcode, preg, errbuf, errbuf_size) \ + __regerror(errcode, preg, errbuf, errbuf_size) +# define re_set_registers(bu, re, nu, st, en) \ + __re_set_registers (bu, re, nu, st, en) +# define re_match_2(bufp, string1, size1, string2, size2, pos, regs, sto= p) \ + __re_match_2 (bufp, string1, size1, string2, size2, pos, regs, stop) +# define re_match(bufp, string, size, pos, regs) \ + __re_match (bufp, string, size, pos, regs) +# define re_search(bufp, string, size, startpos, range, regs) \ + __re_search (bufp, string, size, startpos, range, regs) +# define re_compile_pattern(pattern, length, bufp) \ + __re_compile_pattern (pattern, length, bufp) +# define re_set_syntax(syntax) __re_set_syntax (syntax) +# define re_search_2(bufp, st1, s1, st2, s2, startpos, range, regs, stop= ) \ + __re_search_2 (bufp, st1, s1, st2, s2, startpos, range, regs, stop) +# define re_compile_fastmap(bufp) __re_compile_fastmap (bufp) + +# include "../locale/localeinfo.h" +#endif + +/* On some systems, limits.h sets RE_DUP_MAX to a lower value than + GNU regex allows. Include it before , which correctly + #undefs RE_DUP_MAX and sets it to the right value. */ +#include + +#include +#include "regex_internal.h" + +#include "regex_internal.c" +#include "regcomp.c" +#include "regexec.c" + +/* Binary backward compatibility. */ +#if _LIBC +# include +# if SHLIB_COMPAT (libc, GLIBC_2_0, GLIBC_2_3) +link_warning (re_max_failures, "the 're_max_failures' variable is obsole= te and will go away.") +int re_max_failures =3D 2000; +# endif +#endif diff --git a/lib/regex.h b/lib/regex.h new file mode 100644 index 0000000000..f2ac9507ad --- /dev/null +++ b/lib/regex.h @@ -0,0 +1,658 @@ +/* Definitions for data structures and routines for the regular + expression library. + Copyright (C) 1985, 1989-2018 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 General Public + License as published by the Free Software Foundation; either + version 3 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 + General Public License for more details. + + You should have received a copy of the GNU General Public + License along with the GNU C Library; if not, see + . */ + +#ifndef _REGEX_H +#define _REGEX_H 1 + +#include + +/* Allow the use in C++ code. */ +#ifdef __cplusplus +extern "C" { +#endif + +/* Define __USE_GNU to declare GNU extensions that violate the + POSIX name space rules. */ +#ifdef _GNU_SOURCE +# define __USE_GNU 1 +#endif + +#ifdef _REGEX_LARGE_OFFSETS + +/* Use types and values that are wide enough to represent signed and + unsigned byte offsets in memory. This currently works only when + the regex code is used outside of the GNU C library; it is not yet + supported within glibc itself, and glibc users should not define + _REGEX_LARGE_OFFSETS. */ + +/* The type of object sizes. */ +typedef size_t __re_size_t; + +/* The type of object sizes, in places where the traditional code + uses unsigned long int. */ +typedef size_t __re_long_size_t; + +#else + +/* The traditional GNU regex implementation mishandles strings longer + than INT_MAX. */ +typedef unsigned int __re_size_t; +typedef unsigned long int __re_long_size_t; + +#endif + +/* The following two types have to be signed and unsigned integer type + wide enough to hold a value of a pointer. For most ANSI compilers + ptrdiff_t and size_t should be likely OK. Still size of these two + types is 2 for Microsoft C. Ugh... */ +typedef long int s_reg_t; +typedef unsigned long int active_reg_t; + +/* The following bits are used to determine the regexp syntax we + recognize. The set/not-set meanings are chosen so that Emacs syntax + remains the value 0. The bits are given in alphabetical order, and + the definitions shifted by one from the previous bit; thus, when we + add or remove a bit, only one other definition need change. */ +typedef unsigned long int reg_syntax_t; + +#ifdef __USE_GNU +/* If this bit is not set, then \ inside a bracket expression is literal= . + If set, then such a \ quotes the following character. */ +# define RE_BACKSLASH_ESCAPE_IN_LISTS ((unsigned long int) 1) + +/* If this bit is not set, then + and ? are operators, and \+ and \? are + literals. + If set, then \+ and \? are operators and + and ? are literals. */ +# define RE_BK_PLUS_QM (RE_BACKSLASH_ESCAPE_IN_LISTS << 1) + +/* If this bit is set, then character classes are supported. They are: + [:alpha:], [:upper:], [:lower:], [:digit:], [:alnum:], [:xdigit:], + [:space:], [:print:], [:punct:], [:graph:], and [:cntrl:]. + If not set, then character classes are not supported. */ +# define RE_CHAR_CLASSES (RE_BK_PLUS_QM << 1) + +/* If this bit is set, then ^ and $ are always anchors (outside bracket + expressions, of course). + If this bit is not set, then it depends: + ^ is an anchor if it is at the beginning of a regular + expression or after an open-group or an alternation operator; + $ is an anchor if it is at the end of a regular expression, or + before a close-group or an alternation operator. + + This bit could be (re)combined with RE_CONTEXT_INDEP_OPS, because + POSIX draft 11.2 says that * etc. in leading positions is undefined. + We already implemented a previous draft which made those constructs + invalid, though, so we haven't changed the code back. */ +# define RE_CONTEXT_INDEP_ANCHORS (RE_CHAR_CLASSES << 1) + +/* If this bit is set, then special characters are always special + regardless of where they are in the pattern. + If this bit is not set, then special characters are special only in + some contexts; otherwise they are ordinary. Specifically, + * + ? and intervals are only special when not after the beginning, + open-group, or alternation operator. */ +# define RE_CONTEXT_INDEP_OPS (RE_CONTEXT_INDEP_ANCHORS << 1) + +/* If this bit is set, then *, +, ?, and { cannot be first in an re or + immediately after an alternation or begin-group operator. */ +# define RE_CONTEXT_INVALID_OPS (RE_CONTEXT_INDEP_OPS << 1) + +/* If this bit is set, then . matches newline. + If not set, then it doesn't. */ +# define RE_DOT_NEWLINE (RE_CONTEXT_INVALID_OPS << 1) + +/* If this bit is set, then . doesn't match NUL. + If not set, then it does. */ +# define RE_DOT_NOT_NULL (RE_DOT_NEWLINE << 1) + +/* If this bit is set, nonmatching lists [^...] do not match newline. + If not set, they do. */ +# define RE_HAT_LISTS_NOT_NEWLINE (RE_DOT_NOT_NULL << 1) + +/* If this bit is set, either \{...\} or {...} defines an + interval, depending on RE_NO_BK_BRACES. + If not set, \{, \}, {, and } are literals. */ +# define RE_INTERVALS (RE_HAT_LISTS_NOT_NEWLINE << 1) + +/* If this bit is set, +, ? and | aren't recognized as operators. + If not set, they are. */ +# define RE_LIMITED_OPS (RE_INTERVALS << 1) + +/* If this bit is set, newline is an alternation operator. + If not set, newline is literal. */ +# define RE_NEWLINE_ALT (RE_LIMITED_OPS << 1) + +/* If this bit is set, then '{...}' defines an interval, and \{ and \} + are literals. + If not set, then '\{...\}' defines an interval. */ +# define RE_NO_BK_BRACES (RE_NEWLINE_ALT << 1) + +/* If this bit is set, (...) defines a group, and \( and \) are literals= . + If not set, \(...\) defines a group, and ( and ) are literals. */ +# define RE_NO_BK_PARENS (RE_NO_BK_BRACES << 1) + +/* If this bit is set, then \ matches . + If not set, then \ is a back-reference. */ +# define RE_NO_BK_REFS (RE_NO_BK_PARENS << 1) + +/* If this bit is set, then | is an alternation operator, and \| is lite= ral. + If not set, then \| is an alternation operator, and | is literal. */ +# define RE_NO_BK_VBAR (RE_NO_BK_REFS << 1) + +/* If this bit is set, then an ending range point collating higher + than the starting range point, as in [z-a], is invalid. + If not set, then when ending range point collates higher than the + starting range point, the range is ignored. */ +# define RE_NO_EMPTY_RANGES (RE_NO_BK_VBAR << 1) + +/* If this bit is set, then an unmatched ) is ordinary. + If not set, then an unmatched ) is invalid. */ +# define RE_UNMATCHED_RIGHT_PAREN_ORD (RE_NO_EMPTY_RANGES << 1) + +/* If this bit is set, succeed as soon as we match the whole pattern, + without further backtracking. */ +# define RE_NO_POSIX_BACKTRACKING (RE_UNMATCHED_RIGHT_PAREN_ORD << 1) + +/* If this bit is set, do not process the GNU regex operators. + If not set, then the GNU regex operators are recognized. */ +# define RE_NO_GNU_OPS (RE_NO_POSIX_BACKTRACKING << 1) + +/* If this bit is set, turn on internal regex debugging. + If not set, and debugging was on, turn it off. + This only works if regex.c is compiled -DDEBUG. + We define this bit always, so that all that's needed to turn on + debugging is to recompile regex.c; the calling code can always have + this bit set, and it won't affect anything in the normal case. */ +# define RE_DEBUG (RE_NO_GNU_OPS << 1) + +/* If this bit is set, a syntactically invalid interval is treated as + a string of ordinary characters. For example, the ERE 'a{1' is + treated as 'a\{1'. */ +# define RE_INVALID_INTERVAL_ORD (RE_DEBUG << 1) + +/* If this bit is set, then ignore case when matching. + If not set, then case is significant. */ +# define RE_ICASE (RE_INVALID_INTERVAL_ORD << 1) + +/* This bit is used internally like RE_CONTEXT_INDEP_ANCHORS but only + for ^, because it is difficult to scan the regex backwards to find + whether ^ should be special. */ +# define RE_CARET_ANCHORS_HERE (RE_ICASE << 1) + +/* If this bit is set, then \{ cannot be first in a regex or + immediately after an alternation, open-group or \} operator. */ +# define RE_CONTEXT_INVALID_DUP (RE_CARET_ANCHORS_HERE << 1) + +/* If this bit is set, then no_sub will be set to 1 during + re_compile_pattern. */ +# define RE_NO_SUB (RE_CONTEXT_INVALID_DUP << 1) +#endif + +/* This global variable defines the particular regexp syntax to use (for + some interfaces). When a regexp is compiled, the syntax used is + stored in the pattern buffer, so changing this does not affect + already-compiled regexps. */ +extern reg_syntax_t re_syntax_options; +=0C +#ifdef __USE_GNU +/* Define combinations of the above bits for the standard possibilities. + (The [[[ comments delimit what gets put into the Texinfo file, so + don't delete them!) */ +/* [[[begin syntaxes]]] */ +# define RE_SYNTAX_EMACS 0 + +# define RE_SYNTAX_AWK \ + (RE_BACKSLASH_ESCAPE_IN_LISTS | RE_DOT_NOT_NULL \ + | RE_NO_BK_PARENS | RE_NO_BK_REFS \ + | RE_NO_BK_VBAR | RE_NO_EMPTY_RANGES \ + | RE_DOT_NEWLINE | RE_CONTEXT_INDEP_ANCHORS \ + | RE_CHAR_CLASSES \ + | RE_UNMATCHED_RIGHT_PAREN_ORD | RE_NO_GNU_OPS) + +# define RE_SYNTAX_GNU_AWK \ + ((RE_SYNTAX_POSIX_EXTENDED | RE_BACKSLASH_ESCAPE_IN_LISTS \ + | RE_INVALID_INTERVAL_ORD) \ + & ~(RE_DOT_NOT_NULL | RE_CONTEXT_INDEP_OPS \ + | RE_CONTEXT_INVALID_OPS )) + +# define RE_SYNTAX_POSIX_AWK \ + (RE_SYNTAX_POSIX_EXTENDED | RE_BACKSLASH_ESCAPE_IN_LISTS \ + | RE_INTERVALS | RE_NO_GNU_OPS \ + | RE_INVALID_INTERVAL_ORD) + +# define RE_SYNTAX_GREP \ + ((RE_SYNTAX_POSIX_BASIC | RE_NEWLINE_ALT) \ + & ~(RE_CONTEXT_INVALID_DUP | RE_DOT_NOT_NULL)) + +# define RE_SYNTAX_EGREP \ + ((RE_SYNTAX_POSIX_EXTENDED | RE_INVALID_INTERVAL_ORD | RE_NEWLINE_ALT)= \ + & ~(RE_CONTEXT_INVALID_OPS | RE_DOT_NOT_NULL)) + +/* POSIX grep -E behavior is no longer incompatible with GNU. */ +# define RE_SYNTAX_POSIX_EGREP \ + RE_SYNTAX_EGREP + +/* P1003.2/D11.2, section 4.20.7.1, lines 5078ff. */ +# define RE_SYNTAX_ED RE_SYNTAX_POSIX_BASIC + +# define RE_SYNTAX_SED RE_SYNTAX_POSIX_BASIC + +/* Syntax bits common to both basic and extended POSIX regex syntax. */ +# define _RE_SYNTAX_POSIX_COMMON \ + (RE_CHAR_CLASSES | RE_DOT_NEWLINE | RE_DOT_NOT_NULL \ + | RE_INTERVALS | RE_NO_EMPTY_RANGES) + +# define RE_SYNTAX_POSIX_BASIC \ + (_RE_SYNTAX_POSIX_COMMON | RE_BK_PLUS_QM | RE_CONTEXT_INVALID_DUP) + +/* Differs from ..._POSIX_BASIC only in that RE_BK_PLUS_QM becomes + RE_LIMITED_OPS, i.e., \? \+ \| are not recognized. Actually, this + isn't minimal, since other operators, such as \`, aren't disabled. *= / +# define RE_SYNTAX_POSIX_MINIMAL_BASIC \ + (_RE_SYNTAX_POSIX_COMMON | RE_LIMITED_OPS) + +# define RE_SYNTAX_POSIX_EXTENDED \ + (_RE_SYNTAX_POSIX_COMMON | RE_CONTEXT_INDEP_ANCHORS \ + | RE_CONTEXT_INDEP_OPS | RE_NO_BK_BRACES \ + | RE_NO_BK_PARENS | RE_NO_BK_VBAR \ + | RE_CONTEXT_INVALID_OPS | RE_UNMATCHED_RIGHT_PAREN_ORD) + +/* Differs from ..._POSIX_EXTENDED in that RE_CONTEXT_INDEP_OPS is + removed and RE_NO_BK_REFS is added. */ +# define RE_SYNTAX_POSIX_MINIMAL_EXTENDED \ + (_RE_SYNTAX_POSIX_COMMON | RE_CONTEXT_INDEP_ANCHORS \ + | RE_CONTEXT_INVALID_OPS | RE_NO_BK_BRACES \ + | RE_NO_BK_PARENS | RE_NO_BK_REFS \ + | RE_NO_BK_VBAR | RE_UNMATCHED_RIGHT_PAREN_ORD) +/* [[[end syntaxes]]] */ + +/* Maximum number of duplicates an interval can allow. POSIX-conforming + systems might define this in , but we want our + value, so remove any previous define. */ +# ifdef _REGEX_INCLUDE_LIMITS_H +# include +# endif +# ifdef RE_DUP_MAX +# undef RE_DUP_MAX +# endif + +/* RE_DUP_MAX is 2**15 - 1 because an earlier implementation stored + the counter as a 2-byte signed integer. This is no longer true, so + RE_DUP_MAX could be increased to (INT_MAX / 10 - 1), or to + ((SIZE_MAX - 9) / 10) if _REGEX_LARGE_OFFSETS is defined. + However, there would be a huge performance problem if someone + actually used a pattern like a\{214748363\}, so RE_DUP_MAX retains + its historical value. */ +# define RE_DUP_MAX (0x7fff) +#endif + + +/* POSIX 'cflags' bits (i.e., information for 'regcomp'). */ + +/* If this bit is set, then use extended regular expression syntax. + If not set, then use basic regular expression syntax. */ +#define REG_EXTENDED 1 + +/* If this bit is set, then ignore case when matching. + If not set, then case is significant. */ +#define REG_ICASE (1 << 1) + +/* If this bit is set, then anchors do not match at newline + characters in the string. + If not set, then anchors do match at newlines. */ +#define REG_NEWLINE (1 << 2) + +/* If this bit is set, then report only success or fail in regexec. + If not set, then returns differ between not matching and errors. */ +#define REG_NOSUB (1 << 3) + + +/* POSIX 'eflags' bits (i.e., information for regexec). */ + +/* If this bit is set, then the beginning-of-line operator doesn't match + the beginning of the string (presumably because it's not the + beginning of a line). + If not set, then the beginning-of-line operator does match the + beginning of the string. */ +#define REG_NOTBOL 1 + +/* Like REG_NOTBOL, except for the end-of-line. */ +#define REG_NOTEOL (1 << 1) + +/* Use PMATCH[0] to delimit the start and end of the search in the + buffer. */ +#define REG_STARTEND (1 << 2) + + +/* If any error codes are removed, changed, or added, update the + '__re_error_msgid' table in regcomp.c. */ + +typedef enum +{ + _REG_ENOSYS =3D -1, /* This will never happen for this implementation.= */ + _REG_NOERROR =3D 0, /* Success. */ + _REG_NOMATCH, /* Didn't find a match (for regexec). */ + + /* POSIX regcomp return error codes. (In the order listed in the + standard.) */ + _REG_BADPAT, /* Invalid pattern. */ + _REG_ECOLLATE, /* Invalid collating element. */ + _REG_ECTYPE, /* Invalid character class name. */ + _REG_EESCAPE, /* Trailing backslash. */ + _REG_ESUBREG, /* Invalid back reference. */ + _REG_EBRACK, /* Unmatched left bracket. */ + _REG_EPAREN, /* Parenthesis imbalance. */ + _REG_EBRACE, /* Unmatched \{. */ + _REG_BADBR, /* Invalid contents of \{\}. */ + _REG_ERANGE, /* Invalid range end. */ + _REG_ESPACE, /* Ran out of memory. */ + _REG_BADRPT, /* No preceding re for repetition op. */ + + /* Error codes we've added. */ + _REG_EEND, /* Premature end. */ + _REG_ESIZE, /* Too large (e.g., repeat count too large). */ + _REG_ERPAREN /* Unmatched ) or \); not returned from regcomp. */ +} reg_errcode_t; + +#if defined _XOPEN_SOURCE || defined __USE_XOPEN2K +# define REG_ENOSYS _REG_ENOSYS +#endif +#define REG_NOERROR _REG_NOERROR +#define REG_NOMATCH _REG_NOMATCH +#define REG_BADPAT _REG_BADPAT +#define REG_ECOLLATE _REG_ECOLLATE +#define REG_ECTYPE _REG_ECTYPE +#define REG_EESCAPE _REG_EESCAPE +#define REG_ESUBREG _REG_ESUBREG +#define REG_EBRACK _REG_EBRACK +#define REG_EPAREN _REG_EPAREN +#define REG_EBRACE _REG_EBRACE +#define REG_BADBR _REG_BADBR +#define REG_ERANGE _REG_ERANGE +#define REG_ESPACE _REG_ESPACE +#define REG_BADRPT _REG_BADRPT +#define REG_EEND _REG_EEND +#define REG_ESIZE _REG_ESIZE +#define REG_ERPAREN _REG_ERPAREN +=0C +/* This data structure represents a compiled pattern. Before calling + the pattern compiler, the fields 'buffer', 'allocated', 'fastmap', + and 'translate' can be set. After the pattern has been compiled, + the fields 're_nsub', 'not_bol' and 'not_eol' are available. All + other fields are private to the regex routines. */ + +#ifndef RE_TRANSLATE_TYPE +# define __RE_TRANSLATE_TYPE unsigned char * +# ifdef __USE_GNU +# define RE_TRANSLATE_TYPE __RE_TRANSLATE_TYPE +# endif +#endif + +#ifdef __USE_GNU +# define __REPB_PREFIX(name) name +#else +# define __REPB_PREFIX(name) __##name +#endif + +struct re_pattern_buffer +{ + /* Space that holds the compiled pattern. The type + 'struct re_dfa_t' is private and is not declared here. */ + struct re_dfa_t *__REPB_PREFIX(buffer); + + /* Number of bytes to which 'buffer' points. */ + __re_long_size_t __REPB_PREFIX(allocated); + + /* Number of bytes actually used in 'buffer'. */ + __re_long_size_t __REPB_PREFIX(used); + + /* Syntax setting with which the pattern was compiled. */ + reg_syntax_t __REPB_PREFIX(syntax); + + /* Pointer to a fastmap, if any, otherwise zero. re_search uses the + fastmap, if there is one, to skip over impossible starting points + for matches. */ + char *__REPB_PREFIX(fastmap); + + /* Either a translate table to apply to all characters before + comparing them, or zero for no translation. The translation is + applied to a pattern when it is compiled and to a string when it + is matched. */ + __RE_TRANSLATE_TYPE __REPB_PREFIX(translate); + + /* Number of subexpressions found by the compiler. */ + size_t re_nsub; + + /* Zero if this pattern cannot match the empty string, one else. + Well, in truth it's used only in 're_search_2', to see whether or + not we should use the fastmap, so we don't set this absolutely + perfectly; see 're_compile_fastmap' (the "duplicate" case). */ + unsigned __REPB_PREFIX(can_be_null) : 1; + + /* If REGS_UNALLOCATED, allocate space in the 'regs' structure + for 'max (RE_NREGS, re_nsub + 1)' groups. + If REGS_REALLOCATE, reallocate space if necessary. + If REGS_FIXED, use what's there. */ +#ifdef __USE_GNU +# define REGS_UNALLOCATED 0 +# define REGS_REALLOCATE 1 +# define REGS_FIXED 2 +#endif + unsigned __REPB_PREFIX(regs_allocated) : 2; + + /* Set to zero when 're_compile_pattern' compiles a pattern; set to + one by 're_compile_fastmap' if it updates the fastmap. */ + unsigned __REPB_PREFIX(fastmap_accurate) : 1; + + /* If set, 're_match_2' does not return information about + subexpressions. */ + unsigned __REPB_PREFIX(no_sub) : 1; + + /* If set, a beginning-of-line anchor doesn't match at the beginning + of the string. */ + unsigned __REPB_PREFIX(not_bol) : 1; + + /* Similarly for an end-of-line anchor. */ + unsigned __REPB_PREFIX(not_eol) : 1; + + /* If true, an anchor at a newline matches. */ + unsigned __REPB_PREFIX(newline_anchor) : 1; +}; + +typedef struct re_pattern_buffer regex_t; +=0C +/* Type for byte offsets within the string. POSIX mandates this. */ +#ifdef _REGEX_LARGE_OFFSETS +/* POSIX 1003.1-2008 requires that regoff_t be at least as wide as + ptrdiff_t and ssize_t. We don't know of any hosts where ptrdiff_t + is wider than ssize_t, so ssize_t is safe. ptrdiff_t is not + visible here, so use ssize_t. */ +typedef ssize_t regoff_t; +#else +/* The traditional GNU regex implementation mishandles strings longer + than INT_MAX. */ +typedef int regoff_t; +#endif + + +#ifdef __USE_GNU +/* This is the structure we store register match data in. See + regex.texinfo for a full description of what registers match. */ +struct re_registers +{ + __re_size_t num_regs; + regoff_t *start; + regoff_t *end; +}; + + +/* If 'regs_allocated' is REGS_UNALLOCATED in the pattern buffer, + 're_match_2' returns information about at least this many registers + the first time a 'regs' structure is passed. */ +# ifndef RE_NREGS +# define RE_NREGS 30 +# endif +#endif + + +/* POSIX specification for registers. Aside from the different names th= an + 're_registers', POSIX uses an array of structures, instead of a + structure of arrays. */ +typedef struct +{ + regoff_t rm_so; /* Byte offset from string's start to substring's sta= rt. */ + regoff_t rm_eo; /* Byte offset from string's start to substring's end= . */ +} regmatch_t; +=0C +/* Declarations for routines. */ + +#ifdef __USE_GNU +/* Sets the current default syntax to SYNTAX, and return the old syntax. + You can also simply assign to the 're_syntax_options' variable. */ +extern reg_syntax_t re_set_syntax (reg_syntax_t __syntax); + +/* Compile the regular expression PATTERN, with length LENGTH + and syntax given by the global 're_syntax_options', into the buffer + BUFFER. Return NULL if successful, and an error string if not. + + To free the allocated storage, you must call 'regfree' on BUFFER. + Note that the translate table must either have been initialized by + 'regcomp', with a malloc'ed value, or set to NULL before calling + 'regfree'. */ +extern const char *re_compile_pattern (const char *__pattern, size_t __l= ength, + struct re_pattern_buffer *__buffer); + + +/* Compile a fastmap for the compiled pattern in BUFFER; used to + accelerate searches. Return 0 if successful and -2 if was an + internal error. */ +extern int re_compile_fastmap (struct re_pattern_buffer *__buffer); + + +/* Search in the string STRING (with length LENGTH) for the pattern + compiled into BUFFER. Start searching at position START, for RANGE + characters. Return the starting position of the match, -1 for no + match, or -2 for an internal error. Also return register + information in REGS (if REGS and BUFFER->no_sub are nonzero). */ +extern regoff_t re_search (struct re_pattern_buffer *__buffer, + const char *__String, regoff_t __length, + regoff_t __start, regoff_t __range, + struct re_registers *__regs); + + +/* Like 're_search', but search in the concatenation of STRING1 and + STRING2. Also, stop searching at index START + STOP. */ +extern regoff_t re_search_2 (struct re_pattern_buffer *__buffer, + const char *__string1, regoff_t __length1, + const char *__string2, regoff_t __length2, + regoff_t __start, regoff_t __range, + struct re_registers *__regs, + regoff_t __stop); + + +/* Like 're_search', but return how many characters in STRING the regexp + in BUFFER matched, starting at position START. */ +extern regoff_t re_match (struct re_pattern_buffer *__buffer, + const char *__String, regoff_t __length, + regoff_t __start, struct re_registers *__regs); + + +/* Relates to 're_match' as 're_search_2' relates to 're_search'. */ +extern regoff_t re_match_2 (struct re_pattern_buffer *__buffer, + const char *__string1, regoff_t __length1, + const char *__string2, regoff_t __length2, + regoff_t __start, struct re_registers *__regs, + regoff_t __stop); + + +/* Set REGS to hold NUM_REGS registers, storing them in STARTS and + ENDS. Subsequent matches using BUFFER and REGS will use this memory + for recording register information. STARTS and ENDS must be + allocated with malloc, and must each be at least 'NUM_REGS * sizeof + (regoff_t)' bytes long. + + If NUM_REGS =3D=3D 0, then subsequent matches should allocate their o= wn + register data. + + Unless this function is called, the first search or match using + BUFFER will allocate its own register data, without + freeing the old data. */ +extern void re_set_registers (struct re_pattern_buffer *__buffer, + struct re_registers *__regs, + __re_size_t __num_regs, + regoff_t *__starts, regoff_t *__ends); +#endif /* Use GNU */ + +#if defined _REGEX_RE_COMP || (defined _LIBC && defined __USE_MISC) +# ifndef _CRAY +/* 4.2 bsd compatibility. */ +extern char *re_comp (const char *); +extern int re_exec (const char *); +# endif +#endif + +/* For plain 'restrict', use glibc's __restrict if defined. + Otherwise, GCC 2.95 and later have "__restrict"; C99 compilers have + "restrict", and "configure" may have defined "restrict". + Other compilers use __restrict, __restrict__, and _Restrict, and + 'configure' might #define 'restrict' to those words, so pick a + different name. */ +#ifndef _Restrict_ +# if defined __restrict || 2 < __GNUC__ + (95 <=3D __GNUC_MINOR__) +# define _Restrict_ __restrict +# elif 199901L <=3D __STDC_VERSION__ || defined restrict +# define _Restrict_ restrict +# else +# define _Restrict_ +# endif +#endif +/* For [restrict], use glibc's __restrict_arr if available. + Otherwise, GCC 3.1 (not in C++ mode) and C99 support [restrict]. */ +#ifndef _Restrict_arr_ +# ifdef __restrict_arr +# define _Restrict_arr_ __restrict_arr +# elif ((199901L <=3D __STDC_VERSION__ || 3 < __GNUC__ + (1 <=3D __GNUC_= MINOR__)) \ + && !defined __GNUG__) +# define _Restrict_arr_ _Restrict_ +# else +# define _Restrict_arr_ +# endif +#endif + +/* POSIX compatibility. */ +extern int regcomp (regex_t *_Restrict_ __preg, + const char *_Restrict_ __pattern, + int __cflags); + +extern int regexec (const regex_t *_Restrict_ __preg, + const char *_Restrict_ __String, size_t __nmatch, + regmatch_t __pmatch[_Restrict_arr_], + int __eflags); + +extern size_t regerror (int __errcode, const regex_t *_Restrict_ __preg, + char *_Restrict_ __errbuf, size_t __errbuf_size); + +extern void regfree (regex_t *__preg); + + +#ifdef __cplusplus +} +#endif /* C++ */ + +#endif /* regex.h */ diff --git a/lib/regex_internal.c b/lib/regex_internal.c new file mode 100644 index 0000000000..32373565e6 --- /dev/null +++ b/lib/regex_internal.c @@ -0,0 +1,1740 @@ +/* Extended regular expression matching and search library. + Copyright (C) 2002-2018 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Isamu Hasegawa . + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU General Public + License as published by the Free Software Foundation; either + version 3 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 + General Public License for more details. + + You should have received a copy of the GNU General Public + License along with the GNU C Library; if not, see + . */ + +static void re_string_construct_common (const char *str, Idx len, + re_string_t *pstr, + RE_TRANSLATE_TYPE trans, bool icase, + const re_dfa_t *dfa); +static re_dfastate_t *create_ci_newstate (const re_dfa_t *dfa, + const re_node_set *nodes, + re_hashval_t hash); +static re_dfastate_t *create_cd_newstate (const re_dfa_t *dfa, + const re_node_set *nodes, + unsigned int context, + re_hashval_t hash); +static reg_errcode_t re_string_realloc_buffers (re_string_t *pstr, + Idx new_buf_len); +#ifdef RE_ENABLE_I18N +static void build_wcs_buffer (re_string_t *pstr); +static reg_errcode_t build_wcs_upper_buffer (re_string_t *pstr); +#endif /* RE_ENABLE_I18N */ +static void build_upper_buffer (re_string_t *pstr); +static void re_string_translate_buffer (re_string_t *pstr); +static unsigned int re_string_context_at (const re_string_t *input, Idx = idx, + int eflags) __attribute__ ((pure)); +=0C +/* 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 +__attribute_warn_unused_result__ +re_string_allocate (re_string_t *pstr, const char *str, Idx len, Idx ini= t_len, + RE_TRANSLATE_TYPE trans, bool icase, const re_dfa_t *dfa) +{ + reg_errcode_t ret; + Idx init_buf_len; + + /* Ensure at least one character fits into the buffers. */ + if (init_len < dfa->mb_cur_max) + init_len =3D dfa->mb_cur_max; + init_buf_len =3D (len + 1 < init_len) ? len + 1: init_len; + re_string_construct_common (str, len, pstr, trans, icase, dfa); + + ret =3D re_string_realloc_buffers (pstr, init_buf_len); + if (BE (ret !=3D REG_NOERROR, 0)) + return ret; + + pstr->word_char =3D dfa->word_char; + pstr->word_ops_used =3D dfa->word_ops_used; + pstr->mbs =3D pstr->mbs_allocated ? pstr->mbs : (unsigned char *) str; + pstr->valid_len =3D (pstr->mbs_allocated || dfa->mb_cur_max > 1) ? 0 := len; + pstr->valid_raw_len =3D pstr->valid_len; + return REG_NOERROR; +} + +/* This function allocate the buffers, and initialize them. */ + +static reg_errcode_t +__attribute_warn_unused_result__ +re_string_construct (re_string_t *pstr, const char *str, Idx len, + RE_TRANSLATE_TYPE trans, bool 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 =3D re_string_realloc_buffers (pstr, len + 1); + if (BE (ret !=3D REG_NOERROR, 0)) + return ret; + } + pstr->mbs =3D pstr->mbs_allocated ? pstr->mbs : (unsigned char *) str; + + if (icase) + { +#ifdef RE_ENABLE_I18N + if (dfa->mb_cur_max > 1) + { + while (1) + { + ret =3D build_wcs_upper_buffer (pstr); + if (BE (ret !=3D REG_NOERROR, 0)) + return ret; + if (pstr->valid_raw_len >=3D len) + break; + if (pstr->bufs_len > pstr->valid_len + dfa->mb_cur_max) + break; + ret =3D re_string_realloc_buffers (pstr, pstr->bufs_len * 2); + if (BE (ret !=3D 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 /* RE_ENABLE_I18N */ + { + if (trans !=3D NULL) + re_string_translate_buffer (pstr); + else + { + pstr->valid_len =3D pstr->bufs_len; + pstr->valid_raw_len =3D pstr->bufs_len; + } + } + } + + return REG_NOERROR; +} + +/* Helper functions for re_string_allocate, and re_string_construct. */ + +static reg_errcode_t +__attribute_warn_unused_result__ +re_string_realloc_buffers (re_string_t *pstr, Idx new_buf_len) +{ +#ifdef RE_ENABLE_I18N + if (pstr->mb_cur_max > 1) + { + wint_t *new_wcs; + + /* Avoid overflow in realloc. */ + const size_t max_object_size =3D MAX (sizeof (wint_t), sizeof (Idx= )); + if (BE (MIN (IDX_MAX, SIZE_MAX / max_object_size) < new_buf_len, 0= )) + return REG_ESPACE; + + new_wcs =3D re_realloc (pstr->wcs, wint_t, new_buf_len); + if (BE (new_wcs =3D=3D NULL, 0)) + return REG_ESPACE; + pstr->wcs =3D new_wcs; + if (pstr->offsets !=3D NULL) + { + Idx *new_offsets =3D re_realloc (pstr->offsets, Idx, new_buf_len); + if (BE (new_offsets =3D=3D NULL, 0)) + return REG_ESPACE; + pstr->offsets =3D new_offsets; + } + } +#endif /* RE_ENABLE_I18N */ + if (pstr->mbs_allocated) + { + unsigned char *new_mbs =3D re_realloc (pstr->mbs, unsigned char, + new_buf_len); + if (BE (new_mbs =3D=3D NULL, 0)) + return REG_ESPACE; + pstr->mbs =3D new_mbs; + } + pstr->bufs_len =3D new_buf_len; + return REG_NOERROR; +} + + +static void +re_string_construct_common (const char *str, Idx len, re_string_t *pstr, + RE_TRANSLATE_TYPE trans, bool icase, + const re_dfa_t *dfa) +{ + pstr->raw_mbs =3D (const unsigned char *) str; + pstr->len =3D len; + pstr->raw_len =3D len; + pstr->trans =3D trans; + pstr->icase =3D icase; + pstr->mbs_allocated =3D (trans !=3D NULL || icase); + pstr->mb_cur_max =3D dfa->mb_cur_max; + pstr->is_utf8 =3D dfa->is_utf8; + pstr->map_notascii =3D dfa->map_notascii; + pstr->stop =3D pstr->len; + pstr->raw_stop =3D pstr->stop; +} + +#ifdef RE_ENABLE_I18N + +/* Build wide character buffer PSTR->WCS. + If the byte sequence of the string are: + (0), (1), (0), (1), + Then wide character buffer will be: + , WEOF , , WEOF , + 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 +build_wcs_buffer (re_string_t *pstr) +{ +#ifdef _LIBC + unsigned char buf[MB_LEN_MAX]; + assert (MB_LEN_MAX >=3D pstr->mb_cur_max); +#else + unsigned char buf[64]; +#endif + mbstate_t prev_st; + Idx 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 =3D (pstr->bufs_len > pstr->len) ? pstr->len : pstr->bufs_len; + for (byte_idx =3D pstr->valid_len; byte_idx < end_idx;) + { + wchar_t wc; + const char *p; + + remain_len =3D end_idx - byte_idx; + prev_st =3D pstr->cur_state; + /* Apply the translation if we need. */ + if (BE (pstr->trans !=3D NULL, 0)) + { + int i, ch; + + for (i =3D 0; i < pstr->mb_cur_max && i < remain_len; ++i) + { + ch =3D pstr->raw_mbs [pstr->raw_mbs_idx + byte_idx + i]; + buf[i] =3D pstr->mbs[byte_idx + i] =3D pstr->trans[ch]; + } + p =3D (const char *) buf; + } + else + p =3D (const char *) pstr->raw_mbs + pstr->raw_mbs_idx + byte_idx; + mbclen =3D __mbrtowc (&wc, p, remain_len, &pstr->cur_state); + if (BE (mbclen =3D=3D (size_t) -1 || mbclen =3D=3D 0 + || (mbclen =3D=3D (size_t) -2 && pstr->bufs_len >=3D pstr->len), = 0)) + { + /* We treat these cases as a singlebyte character. */ + mbclen =3D 1; + wc =3D (wchar_t) pstr->raw_mbs[pstr->raw_mbs_idx + byte_idx]; + if (BE (pstr->trans !=3D NULL, 0)) + wc =3D pstr->trans[wc]; + pstr->cur_state =3D prev_st; + } + else if (BE (mbclen =3D=3D (size_t) -2, 0)) + { + /* The buffer doesn't have enough space, finish to build. */ + pstr->cur_state =3D prev_st; + break; + } + + /* Write wide character and padding. */ + pstr->wcs[byte_idx++] =3D wc; + /* Write paddings. */ + for (remain_len =3D byte_idx + mbclen - 1; byte_idx < remain_len ;= ) + pstr->wcs[byte_idx++] =3D WEOF; + } + pstr->valid_len =3D byte_idx; + pstr->valid_raw_len =3D byte_idx; +} + +/* Build wide character buffer PSTR->WCS like build_wcs_buffer, + but for REG_ICASE. */ + +static reg_errcode_t +__attribute_warn_unused_result__ +build_wcs_upper_buffer (re_string_t *pstr) +{ + mbstate_t prev_st; + Idx src_idx, byte_idx, end_idx, remain_len; + size_t mbclen; +#ifdef _LIBC + char buf[MB_LEN_MAX]; + assert (MB_LEN_MAX >=3D pstr->mb_cur_max); +#else + char buf[64]; +#endif + + byte_idx =3D pstr->valid_len; + end_idx =3D (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 =3D=3D 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] + =3D 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] =3D (wchar_t) pstr->mbs[byte_idx]; + ++byte_idx; + continue; + } + + remain_len =3D end_idx - byte_idx; + prev_st =3D pstr->cur_state; + mbclen =3D __mbrtowc (&wc, + ((const char *) pstr->raw_mbs + pstr->raw_mbs_idx + + byte_idx), remain_len, &pstr->cur_state); + if (BE (mbclen < (size_t) -2, 1)) + { + wchar_t wcu =3D __towupper (wc); + if (wcu !=3D wc) + { + size_t mbcdlen; + + mbcdlen =3D __wcrtomb (buf, wcu, &prev_st); + if (BE (mbclen =3D=3D mbcdlen, 1)) + memcpy (pstr->mbs + byte_idx, buf, mbclen); + else + { + src_idx =3D 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++] =3D wcu; + /* Write paddings. */ + for (remain_len =3D byte_idx + mbclen - 1; byte_idx < remain_len = ;) + pstr->wcs[byte_idx++] =3D WEOF; + } + else if (mbclen =3D=3D (size_t) -1 || mbclen =3D=3D 0 + || (mbclen =3D=3D (size_t) -2 && pstr->bufs_len >=3D pstr->len)) + { + /* It is an invalid character, an incomplete character + at the end of the string, or '\0'. Just use the byte. */ + int ch =3D pstr->raw_mbs[pstr->raw_mbs_idx + byte_idx]; + pstr->mbs[byte_idx] =3D ch; + /* And also cast it to wide char. */ + pstr->wcs[byte_idx++] =3D (wchar_t) ch; + if (BE (mbclen =3D=3D (size_t) -1, 0)) + pstr->cur_state =3D prev_st; + } + else + { + /* The buffer doesn't have enough space, finish to build. */ + pstr->cur_state =3D prev_st; + break; + } + } + pstr->valid_len =3D byte_idx; + pstr->valid_raw_len =3D byte_idx; + return REG_NOERROR; + } + else + for (src_idx =3D pstr->valid_raw_len; byte_idx < end_idx;) + { + wchar_t wc; + const char *p; + offsets_needed: + remain_len =3D end_idx - byte_idx; + prev_st =3D pstr->cur_state; + if (BE (pstr->trans !=3D NULL, 0)) + { + int i, ch; + + for (i =3D 0; i < pstr->mb_cur_max && i < remain_len; ++i) + { + ch =3D pstr->raw_mbs [pstr->raw_mbs_idx + src_idx + i]; + buf[i] =3D pstr->trans[ch]; + } + p =3D (const char *) buf; + } + else + p =3D (const char *) pstr->raw_mbs + pstr->raw_mbs_idx + src_idx; + mbclen =3D __mbrtowc (&wc, p, remain_len, &pstr->cur_state); + if (BE (mbclen < (size_t) -2, 1)) + { + wchar_t wcu =3D __towupper (wc); + if (wcu !=3D wc) + { + size_t mbcdlen; + + mbcdlen =3D __wcrtomb ((char *) buf, wcu, &prev_st); + if (BE (mbclen =3D=3D mbcdlen, 1)) + memcpy (pstr->mbs + byte_idx, buf, mbclen); + else if (mbcdlen !=3D (size_t) -1) + { + size_t i; + + if (byte_idx + mbcdlen > pstr->bufs_len) + { + pstr->cur_state =3D prev_st; + break; + } + + if (pstr->offsets =3D=3D NULL) + { + pstr->offsets =3D re_malloc (Idx, pstr->bufs_len); + + if (pstr->offsets =3D=3D NULL) + return REG_ESPACE; + } + if (!pstr->offsets_needed) + { + for (i =3D 0; i < (size_t) byte_idx; ++i) + pstr->offsets[i] =3D i; + pstr->offsets_needed =3D 1; + } + + memcpy (pstr->mbs + byte_idx, buf, mbcdlen); + pstr->wcs[byte_idx] =3D wcu; + pstr->offsets[byte_idx] =3D src_idx; + for (i =3D 1; i < mbcdlen; ++i) + { + pstr->offsets[byte_idx + i] + =3D src_idx + (i < mbclen ? i : mbclen - 1); + pstr->wcs[byte_idx + i] =3D WEOF; + } + pstr->len +=3D mbcdlen - mbclen; + if (pstr->raw_stop > src_idx) + pstr->stop +=3D mbcdlen - mbclen; + end_idx =3D (pstr->bufs_len > pstr->len) + ? pstr->len : pstr->bufs_len; + byte_idx +=3D mbcdlen; + src_idx +=3D mbclen; + continue; + } + else + memcpy (pstr->mbs + byte_idx, p, mbclen); + } + else + memcpy (pstr->mbs + byte_idx, p, mbclen); + + if (BE (pstr->offsets_needed !=3D 0, 0)) + { + size_t i; + for (i =3D 0; i < mbclen; ++i) + pstr->offsets[byte_idx + i] =3D src_idx + i; + } + src_idx +=3D mbclen; + + pstr->wcs[byte_idx++] =3D wcu; + /* Write paddings. */ + for (remain_len =3D byte_idx + mbclen - 1; byte_idx < remain_len ;) + pstr->wcs[byte_idx++] =3D WEOF; + } + else if (mbclen =3D=3D (size_t) -1 || mbclen =3D=3D 0 + || (mbclen =3D=3D (size_t) -2 && pstr->bufs_len >=3D pstr->len)) + { + /* It is an invalid character or '\0'. Just use the byte. */ + int ch =3D pstr->raw_mbs[pstr->raw_mbs_idx + src_idx]; + + if (BE (pstr->trans !=3D NULL, 0)) + ch =3D pstr->trans [ch]; + pstr->mbs[byte_idx] =3D ch; + + if (BE (pstr->offsets_needed !=3D 0, 0)) + pstr->offsets[byte_idx] =3D src_idx; + ++src_idx; + + /* And also cast it to wide char. */ + pstr->wcs[byte_idx++] =3D (wchar_t) ch; + if (BE (mbclen =3D=3D (size_t) -1, 0)) + pstr->cur_state =3D prev_st; + } + else + { + /* The buffer doesn't have enough space, finish to build. */ + pstr->cur_state =3D prev_st; + break; + } + } + pstr->valid_len =3D byte_idx; + pstr->valid_raw_len =3D src_idx; + return REG_NOERROR; +} + +/* Skip characters until the index becomes greater than NEW_RAW_IDX. + Return the index. */ + +static Idx +re_string_skip_chars (re_string_t *pstr, Idx new_raw_idx, wint_t *last_w= c) +{ + mbstate_t prev_st; + Idx rawbuf_idx; + size_t mbclen; + wint_t wc =3D WEOF; + + /* Skip the characters which are not necessary to check. */ + for (rawbuf_idx =3D pstr->raw_mbs_idx + pstr->valid_raw_len; + rawbuf_idx < new_raw_idx;) + { + wchar_t wc2; + Idx remain_len =3D pstr->raw_len - rawbuf_idx; + prev_st =3D pstr->cur_state; + mbclen =3D __mbrtowc (&wc2, (const char *) pstr->raw_mbs + rawbuf_= idx, + remain_len, &pstr->cur_state); + if (BE (mbclen =3D=3D (size_t) -2 || mbclen =3D=3D (size_t) -1 || = mbclen =3D=3D 0, 0)) + { + /* We treat these cases as a single byte character. */ + if (mbclen =3D=3D 0 || remain_len =3D=3D 0) + wc =3D L'\0'; + else + wc =3D *(unsigned char *) (pstr->raw_mbs + rawbuf_idx); + mbclen =3D 1; + pstr->cur_state =3D prev_st; + } + else + wc =3D wc2; + /* Then proceed the next character. */ + rawbuf_idx +=3D mbclen; + } + *last_wc =3D 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 +build_upper_buffer (re_string_t *pstr) +{ + Idx char_idx, end_idx; + end_idx =3D (pstr->bufs_len > pstr->len) ? pstr->len : pstr->bufs_len; + + for (char_idx =3D pstr->valid_len; char_idx < end_idx; ++char_idx) + { + int ch =3D pstr->raw_mbs[pstr->raw_mbs_idx + char_idx]; + if (BE (pstr->trans !=3D NULL, 0)) + ch =3D pstr->trans[ch]; + pstr->mbs[char_idx] =3D toupper (ch); + } + pstr->valid_len =3D char_idx; + pstr->valid_raw_len =3D char_idx; +} + +/* Apply TRANS to the buffer in PSTR. */ + +static void +re_string_translate_buffer (re_string_t *pstr) +{ + Idx buf_idx, end_idx; + end_idx =3D (pstr->bufs_len > pstr->len) ? pstr->len : pstr->bufs_len; + + for (buf_idx =3D pstr->valid_len; buf_idx < end_idx; ++buf_idx) + { + int ch =3D pstr->raw_mbs[pstr->raw_mbs_idx + buf_idx]; + pstr->mbs[buf_idx] =3D pstr->trans[ch]; + } + + pstr->valid_len =3D buf_idx; + pstr->valid_raw_len =3D 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 +__attribute_warn_unused_result__ +re_string_reconstruct (re_string_t *pstr, Idx idx, int eflags) +{ + Idx offset; + + if (BE (pstr->raw_mbs_idx <=3D idx, 0)) + offset =3D idx - pstr->raw_mbs_idx; + else + { + /* Reset buffer. */ +#ifdef RE_ENABLE_I18N + if (pstr->mb_cur_max > 1) + memset (&pstr->cur_state, '\0', sizeof (mbstate_t)); +#endif /* RE_ENABLE_I18N */ + pstr->len =3D pstr->raw_len; + pstr->stop =3D pstr->raw_stop; + pstr->valid_len =3D 0; + pstr->raw_mbs_idx =3D 0; + pstr->valid_raw_len =3D 0; + pstr->offsets_needed =3D 0; + pstr->tip_context =3D ((eflags & REG_NOTBOL) ? CONTEXT_BEGBUF + : CONTEXT_NEWLINE | CONTEXT_BEGBUF); + if (!pstr->mbs_allocated) + pstr->mbs =3D (unsigned char *) pstr->raw_mbs; + offset =3D idx; + } + + if (BE (offset !=3D 0, 1)) + { + /* Should the already checked characters be kept? */ + if (BE (offset < pstr->valid_raw_len, 1)) + { + /* Yes, move them to the front of the buffer. */ +#ifdef RE_ENABLE_I18N + if (BE (pstr->offsets_needed, 0)) + { + Idx low =3D 0, high =3D pstr->valid_len, mid; + do + { + mid =3D (high + low) / 2; + if (pstr->offsets[mid] > offset) + high =3D mid; + else if (pstr->offsets[mid] < offset) + low =3D mid + 1; + else + break; + } + while (low < high); + if (pstr->offsets[mid] < offset) + ++mid; + pstr->tip_context =3D re_string_context_at (pstr, mid - 1, + eflags); + /* This can be quite complicated, so handle specially + only the common and easy case where the character with + different length representation of lower and upper + case is present at or after offset. */ + if (pstr->valid_len > offset + && mid =3D=3D offset && pstr->offsets[mid] =3D=3D offset) + { + memmove (pstr->wcs, pstr->wcs + offset, + (pstr->valid_len - offset) * sizeof (wint_t)); + memmove (pstr->mbs, pstr->mbs + offset, pstr->valid_len - offset); + pstr->valid_len -=3D offset; + pstr->valid_raw_len -=3D offset; + for (low =3D 0; low < pstr->valid_len; low++) + pstr->offsets[low] =3D pstr->offsets[low + offset] - offset; + } + else + { + /* Otherwise, just find out how long the partial multibyte + character at offset is and fill it with WEOF/255. */ + pstr->len =3D pstr->raw_len - idx + offset; + pstr->stop =3D pstr->raw_stop - idx + offset; + pstr->offsets_needed =3D 0; + while (mid > 0 && pstr->offsets[mid - 1] =3D=3D offset) + --mid; + while (mid < pstr->valid_len) + if (pstr->wcs[mid] !=3D WEOF) + break; + else + ++mid; + if (mid =3D=3D pstr->valid_len) + pstr->valid_len =3D 0; + else + { + pstr->valid_len =3D pstr->offsets[mid] - offset; + if (pstr->valid_len) + { + for (low =3D 0; low < pstr->valid_len; ++low) + pstr->wcs[low] =3D WEOF; + memset (pstr->mbs, 255, pstr->valid_len); + } + } + pstr->valid_raw_len =3D pstr->valid_len; + } + } + else +#endif + { + pstr->tip_context =3D 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 /* RE_ENABLE_I18N */ + if (BE (pstr->mbs_allocated, 0)) + memmove (pstr->mbs, pstr->mbs + offset, + pstr->valid_len - offset); + pstr->valid_len -=3D offset; + pstr->valid_raw_len -=3D offset; +#if defined DEBUG && DEBUG + assert (pstr->valid_len > 0); +#endif + } + } + else + { +#ifdef RE_ENABLE_I18N + /* No, skip all characters until IDX. */ + Idx prev_valid_len =3D pstr->valid_len; + + if (BE (pstr->offsets_needed, 0)) + { + pstr->len =3D pstr->raw_len - idx + offset; + pstr->stop =3D pstr->raw_stop - idx + offset; + pstr->offsets_needed =3D 0; + } +#endif + pstr->valid_len =3D 0; +#ifdef RE_ENABLE_I18N + if (pstr->mb_cur_max > 1) + { + Idx wcs_idx; + wint_t wc =3D 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 =3D pstr->raw_mbs + pstr->raw_mbs_idx; + end =3D raw + (offset - pstr->mb_cur_max); + if (end < pstr->raw_mbs) + end =3D pstr->raw_mbs; + p =3D raw + offset - 1; +#ifdef _LIBC + /* 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 =3D=3D NULL, 1)) + { + memset (&pstr->cur_state, '\0', sizeof (mbstate_t)); + /* pstr->valid_len =3D 0; */ + wc =3D (wchar_t) *p; + } + else +#endif + for (; p >=3D end; --p) + if ((*p & 0xc0) !=3D 0x80) + { + mbstate_t cur_state; + wchar_t wc2; + Idx mlen =3D raw + pstr->len - p; + unsigned char buf[6]; + size_t mbclen; + + const unsigned char *pp =3D p; + if (BE (pstr->trans !=3D NULL, 0)) + { + int i =3D mlen < 6 ? mlen : 6; + while (--i >=3D 0) + buf[i] =3D pstr->trans[p[i]]; + pp =3D buf; + } + /* XXX Don't use mbrtowc, we know which conversion + to use (UTF-8 -> UCS4). */ + memset (&cur_state, 0, sizeof (cur_state)); + mbclen =3D __mbrtowc (&wc2, (const char *) pp, mlen, + &cur_state); + if (raw + offset - p <=3D mbclen + && mbclen < (size_t) -2) + { + memset (&pstr->cur_state, '\0', + sizeof (mbstate_t)); + pstr->valid_len =3D mbclen - (raw + offset - p); + wc =3D wc2; + } + break; + } + } + + if (wc =3D=3D WEOF) + pstr->valid_len =3D re_string_skip_chars (pstr, idx, &wc) - idx; + if (wc =3D=3D WEOF) + pstr->tip_context + =3D re_string_context_at (pstr, prev_valid_len - 1, eflags); + else + pstr->tip_context =3D ((BE (pstr->word_ops_used !=3D 0, 0) + && IS_WIDE_WORD_CHAR (wc)) + ? CONTEXT_WORD + : ((IS_WIDE_NEWLINE (wc) + && pstr->newline_anchor) + ? CONTEXT_NEWLINE : 0)); + if (BE (pstr->valid_len, 0)) + { + for (wcs_idx =3D 0; wcs_idx < pstr->valid_len; ++wcs_idx) + pstr->wcs[wcs_idx] =3D WEOF; + if (pstr->mbs_allocated) + memset (pstr->mbs, 255, pstr->valid_len); + } + pstr->valid_raw_len =3D pstr->valid_len; + } + else +#endif /* RE_ENABLE_I18N */ + { + int c =3D pstr->raw_mbs[pstr->raw_mbs_idx + offset - 1]; + pstr->valid_raw_len =3D 0; + if (pstr->trans) + c =3D pstr->trans[c]; + pstr->tip_context =3D (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 +=3D offset; + } + pstr->raw_mbs_idx =3D idx; + pstr->len -=3D offset; + pstr->stop -=3D offset; + + /* Then build the buffers. */ +#ifdef RE_ENABLE_I18N + if (pstr->mb_cur_max > 1) + { + if (pstr->icase) + { + reg_errcode_t ret =3D build_wcs_upper_buffer (pstr); + if (BE (ret !=3D REG_NOERROR, 0)) + return ret; + } + else + build_wcs_buffer (pstr); + } + else +#endif /* RE_ENABLE_I18N */ + if (BE (pstr->mbs_allocated, 0)) + { + if (pstr->icase) + build_upper_buffer (pstr); + else if (pstr->trans !=3D NULL) + re_string_translate_buffer (pstr); + } + else + pstr->valid_len =3D pstr->len; + + pstr->cur_idx =3D 0; + return REG_NOERROR; +} + +static unsigned char +__attribute__ ((pure)) +re_string_peek_byte_case (const re_string_t *pstr, Idx idx) +{ + int ch; + Idx 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 =3D pstr->cur_idx + idx; +#ifdef RE_ENABLE_I18N + if (pstr->offsets_needed) + off =3D pstr->offsets[off]; +#endif + + ch =3D 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 +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) + { + Idx off; + int 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 =3D pstr->offsets[pstr->cur_idx]; + ch =3D 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 +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 +re_string_context_at (const re_string_t *input, Idx 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 =3D=3D 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; + Idx wc_idx =3D idx; + while(input->wcs[wc_idx] =3D=3D WEOF) + { +#if defined DEBUG && DEBUG + /* It must not happen. */ + assert (wc_idx >=3D 0); +#endif + --wc_idx; + if (wc_idx < 0) + return input->tip_context; + } + wc =3D input->wcs[wc_idx]; + if (BE (input->word_ops_used !=3D 0, 0) && IS_WIDE_WORD_CHAR (wc)) + return CONTEXT_WORD; + return (IS_WIDE_NEWLINE (wc) && input->newline_anchor + ? CONTEXT_NEWLINE : 0); + } + else +#endif + { + c =3D 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; + } +} +=0C +/* Functions for set operation. */ + +static reg_errcode_t +__attribute_warn_unused_result__ +re_node_set_alloc (re_node_set *set, Idx size) +{ + set->alloc =3D size; + set->nelem =3D 0; + set->elems =3D re_malloc (Idx, size); + if (BE (set->elems =3D=3D NULL, 0) && (MALLOC_0_IS_NONNULL || size !=3D= 0)) + return REG_ESPACE; + return REG_NOERROR; +} + +static reg_errcode_t +__attribute_warn_unused_result__ +re_node_set_init_1 (re_node_set *set, Idx elem) +{ + set->alloc =3D 1; + set->nelem =3D 1; + set->elems =3D re_malloc (Idx, 1); + if (BE (set->elems =3D=3D NULL, 0)) + { + set->alloc =3D set->nelem =3D 0; + return REG_ESPACE; + } + set->elems[0] =3D elem; + return REG_NOERROR; +} + +static reg_errcode_t +__attribute_warn_unused_result__ +re_node_set_init_2 (re_node_set *set, Idx elem1, Idx elem2) +{ + set->alloc =3D 2; + set->elems =3D re_malloc (Idx, 2); + if (BE (set->elems =3D=3D NULL, 0)) + return REG_ESPACE; + if (elem1 =3D=3D elem2) + { + set->nelem =3D 1; + set->elems[0] =3D elem1; + } + else + { + set->nelem =3D 2; + if (elem1 < elem2) + { + set->elems[0] =3D elem1; + set->elems[1] =3D elem2; + } + else + { + set->elems[0] =3D elem2; + set->elems[1] =3D elem1; + } + } + return REG_NOERROR; +} + +static reg_errcode_t +__attribute_warn_unused_result__ +re_node_set_init_copy (re_node_set *dest, const re_node_set *src) +{ + dest->nelem =3D src->nelem; + if (src->nelem > 0) + { + dest->alloc =3D dest->nelem; + dest->elems =3D re_malloc (Idx, dest->alloc); + if (BE (dest->elems =3D=3D NULL, 0)) + { + dest->alloc =3D dest->nelem =3D 0; + return REG_ESPACE; + } + memcpy (dest->elems, src->elems, src->nelem * sizeof (Idx)); + } + 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 succeede= d. + Note: We assume dest->elems is NULL, when dest->alloc is 0. */ + +static reg_errcode_t +__attribute_warn_unused_result__ +re_node_set_add_intersect (re_node_set *dest, const re_node_set *src1, + const re_node_set *src2) +{ + Idx i1, i2, is, id, delta, sbase; + if (src1->nelem =3D=3D 0 || src2->nelem =3D=3D 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) + { + Idx new_alloc =3D src1->nelem + src2->nelem + dest->alloc; + Idx *new_elems =3D re_realloc (dest->elems, Idx, new_alloc); + if (BE (new_elems =3D=3D NULL, 0)) + return REG_ESPACE; + dest->elems =3D new_elems; + dest->alloc =3D 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 =3D dest->nelem + src1->nelem + src2->nelem; + i1 =3D src1->nelem - 1; + i2 =3D src2->nelem - 1; + id =3D dest->nelem - 1; + for (;;) + { + if (src1->elems[i1] =3D=3D src2->elems[i2]) + { + /* Try to find the item in DEST. Maybe we could binary search? */ + while (id >=3D 0 && dest->elems[id] > src1->elems[i1]) + --id; + + if (id < 0 || dest->elems[id] !=3D src1->elems[i1]) + dest->elems[--sbase] =3D 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 =3D dest->nelem - 1; + is =3D dest->nelem + src1->nelem + src2->nelem - 1; + delta =3D 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 +=3D delta; + if (delta > 0 && id >=3D 0) + for (;;) + { + if (dest->elems[is] > dest->elems[id]) + { + /* Copy from the top. */ + dest->elems[id + delta--] =3D dest->elems[is--]; + if (delta =3D=3D 0) + break; + } + else + { + /* Slide from the bottom. */ + dest->elems[id + delta] =3D dest->elems[id]; + if (--id < 0) + break; + } + } + + /* Copy remaining SRC elements. */ + memcpy (dest->elems, dest->elems + sbase, delta * sizeof (Idx)); + + 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 succeede= d. */ + +static reg_errcode_t +__attribute_warn_unused_result__ +re_node_set_init_union (re_node_set *dest, const re_node_set *src1, + const re_node_set *src2) +{ + Idx i1, i2, id; + if (src1 !=3D NULL && src1->nelem > 0 && src2 !=3D NULL && src2->nelem= > 0) + { + dest->alloc =3D src1->nelem + src2->nelem; + dest->elems =3D re_malloc (Idx, dest->alloc); + if (BE (dest->elems =3D=3D NULL, 0)) + return REG_ESPACE; + } + else + { + if (src1 !=3D NULL && src1->nelem > 0) + return re_node_set_init_copy (dest, src1); + else if (src2 !=3D NULL && src2->nelem > 0) + return re_node_set_init_copy (dest, src2); + else + re_node_set_init_empty (dest); + return REG_NOERROR; + } + for (i1 =3D i2 =3D id =3D 0 ; i1 < src1->nelem && i2 < src2->nelem ;) + { + if (src1->elems[i1] > src2->elems[i2]) + { + dest->elems[id++] =3D src2->elems[i2++]; + continue; + } + if (src1->elems[i1] =3D=3D src2->elems[i2]) + ++i2; + dest->elems[id++] =3D src1->elems[i1++]; + } + if (i1 < src1->nelem) + { + memcpy (dest->elems + id, src1->elems + i1, + (src1->nelem - i1) * sizeof (Idx)); + id +=3D src1->nelem - i1; + } + else if (i2 < src2->nelem) + { + memcpy (dest->elems + id, src2->elems + i2, + (src2->nelem - i2) * sizeof (Idx)); + id +=3D src2->nelem - i2; + } + dest->nelem =3D 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 succeede= d. */ + +static reg_errcode_t +__attribute_warn_unused_result__ +re_node_set_merge (re_node_set *dest, const re_node_set *src) +{ + Idx is, id, sbase, delta; + if (src =3D=3D NULL || src->nelem =3D=3D 0) + return REG_NOERROR; + if (dest->alloc < 2 * src->nelem + dest->nelem) + { + Idx new_alloc =3D 2 * (src->nelem + dest->alloc); + Idx *new_buffer =3D re_realloc (dest->elems, Idx, new_alloc); + if (BE (new_buffer =3D=3D NULL, 0)) + return REG_ESPACE; + dest->elems =3D new_buffer; + dest->alloc =3D new_alloc; + } + + if (BE (dest->nelem =3D=3D 0, 0)) + { + dest->nelem =3D src->nelem; + memcpy (dest->elems, src->elems, src->nelem * sizeof (Idx)); + 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 =3D dest->nelem + 2 * src->nelem, + is =3D src->nelem - 1, id =3D dest->nelem - 1; is >=3D 0 && id >=3D= 0; ) + { + if (dest->elems[id] =3D=3D src->elems[is]) + is--, id--; + else if (dest->elems[id] < src->elems[is]) + dest->elems[--sbase] =3D src->elems[is--]; + else /* if (dest->elems[id] > src->elems[is]) */ + --id; + } + + if (is >=3D 0) + { + /* If DEST is exhausted, the remaining items of SRC must be unique= . */ + sbase -=3D is + 1; + memcpy (dest->elems + sbase, src->elems, (is + 1) * sizeof (Idx)); + } + + id =3D dest->nelem - 1; + is =3D dest->nelem + 2 * src->nelem - 1; + delta =3D is - sbase + 1; + if (delta =3D=3D 0) + return REG_NOERROR; + + /* Now copy. When DELTA becomes zero, the remaining + DEST elements are already in place. */ + dest->nelem +=3D delta; + for (;;) + { + if (dest->elems[is] > dest->elems[id]) + { + /* Copy from the top. */ + dest->elems[id + delta--] =3D dest->elems[is--]; + if (delta =3D=3D 0) + break; + } + else + { + /* Slide from the bottom. */ + dest->elems[id + delta] =3D dest->elems[id]; + if (--id < 0) + { + /* Copy remaining SRC elements. */ + memcpy (dest->elems, dest->elems + sbase, + delta * sizeof (Idx)); + break; + } + } + } + + return REG_NOERROR; +} + +/* Insert the new element ELEM to the re_node_set* SET. + SET should not already have ELEM. + Return true if successful. */ + +static bool +__attribute_warn_unused_result__ +re_node_set_insert (re_node_set *set, Idx elem) +{ + Idx idx; + /* In case the set is empty. */ + if (set->alloc =3D=3D 0) + return BE (re_node_set_init_1 (set, elem) =3D=3D REG_NOERROR, 1); + + if (BE (set->nelem, 0) =3D=3D 0) + { + /* We already guaranteed above that set->alloc !=3D 0. */ + set->elems[0] =3D elem; + ++set->nelem; + return true; + } + + /* Realloc if we need. */ + if (set->alloc =3D=3D set->nelem) + { + Idx *new_elems; + set->alloc =3D set->alloc * 2; + new_elems =3D re_realloc (set->elems, Idx, set->alloc); + if (BE (new_elems =3D=3D NULL, 0)) + return false; + set->elems =3D 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 =3D 0; + for (idx =3D set->nelem; idx > 0; idx--) + set->elems[idx] =3D set->elems[idx - 1]; + } + else + { + for (idx =3D set->nelem; set->elems[idx - 1] > elem; idx--) + set->elems[idx] =3D set->elems[idx - 1]; + } + + /* Insert the new element. */ + set->elems[idx] =3D elem; + ++set->nelem; + return true; +} + +/* 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 true if successful. */ + +static bool +__attribute_warn_unused_result__ +re_node_set_insert_last (re_node_set *set, Idx elem) +{ + /* Realloc if we need. */ + if (set->alloc =3D=3D set->nelem) + { + Idx *new_elems; + set->alloc =3D (set->alloc + 1) * 2; + new_elems =3D re_realloc (set->elems, Idx, set->alloc); + if (BE (new_elems =3D=3D NULL, 0)) + return false; + set->elems =3D new_elems; + } + + /* Insert the new element. */ + set->elems[set->nelem++] =3D elem; + return true; +} + +/* Compare two node sets SET1 and SET2. + Return true if SET1 and SET2 are equivalent. */ + +static bool +__attribute__ ((pure)) +re_node_set_compare (const re_node_set *set1, const re_node_set *set2) +{ + Idx i; + if (set1 =3D=3D NULL || set2 =3D=3D NULL || set1->nelem !=3D set2->nel= em) + return false; + for (i =3D set1->nelem ; --i >=3D 0 ; ) + if (set1->elems[i] !=3D set2->elems[i]) + return false; + return true; +} + +/* Return (idx + 1) if SET contains the element ELEM, return 0 otherwise= . */ + +static Idx +__attribute__ ((pure)) +re_node_set_contains (const re_node_set *set, Idx elem) +{ + __re_size_t idx, right, mid; + if (set->nelem <=3D 0) + return 0; + + /* Binary search the element. */ + idx =3D 0; + right =3D set->nelem - 1; + while (idx < right) + { + mid =3D (idx + right) / 2; + if (set->elems[mid] < elem) + idx =3D mid + 1; + else + right =3D mid; + } + return set->elems[idx] =3D=3D elem ? idx + 1 : 0; +} + +static void +re_node_set_remove_at (re_node_set *set, Idx idx) +{ + if (idx < 0 || idx >=3D set->nelem) + return; + --set->nelem; + for (; idx < set->nelem; idx++) + set->elems[idx] =3D set->elems[idx + 1]; +} +=0C + +/* Add the token TOKEN to dfa->nodes, and return the index of the token. + Or return -1 if an error occurred. */ + +static Idx +re_dfa_add_node (re_dfa_t *dfa, re_token_t token) +{ + if (BE (dfa->nodes_len >=3D dfa->nodes_alloc, 0)) + { + size_t new_nodes_alloc =3D dfa->nodes_alloc * 2; + Idx *new_nexts, *new_indices; + re_node_set *new_edests, *new_eclosures; + re_token_t *new_nodes; + + /* Avoid overflows in realloc. */ + const size_t max_object_size =3D MAX (sizeof (re_token_t), + MAX (sizeof (re_node_set), + sizeof (Idx))); + if (BE (MIN (IDX_MAX, SIZE_MAX / max_object_size) < new_nodes_allo= c, 0)) + return -1; + + new_nodes =3D re_realloc (dfa->nodes, re_token_t, new_nodes_alloc)= ; + if (BE (new_nodes =3D=3D NULL, 0)) + return -1; + dfa->nodes =3D new_nodes; + new_nexts =3D re_realloc (dfa->nexts, Idx, new_nodes_alloc); + new_indices =3D re_realloc (dfa->org_indices, Idx, new_nodes_alloc= ); + new_edests =3D re_realloc (dfa->edests, re_node_set, new_nodes_all= oc); + new_eclosures =3D re_realloc (dfa->eclosures, re_node_set, new_nod= es_alloc); + if (BE (new_nexts =3D=3D NULL || new_indices =3D=3D NULL + || new_edests =3D=3D NULL || new_eclosures =3D=3D NULL, 0)) + { + re_free (new_nexts); + re_free (new_indices); + re_free (new_edests); + re_free (new_eclosures); + return -1; + } + dfa->nexts =3D new_nexts; + dfa->org_indices =3D new_indices; + dfa->edests =3D new_edests; + dfa->eclosures =3D new_eclosures; + dfa->nodes_alloc =3D new_nodes_alloc; + } + dfa->nodes[dfa->nodes_len] =3D token; + dfa->nodes[dfa->nodes_len].constraint =3D 0; +#ifdef RE_ENABLE_I18N + dfa->nodes[dfa->nodes_len].accept_mb =3D + ((token.type =3D=3D OP_PERIOD && dfa->mb_cur_max > 1) + || token.type =3D=3D COMPLEX_BRACKET); +#endif + dfa->nexts[dfa->nodes_len] =3D -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 re_hashval_t +calc_state_hash (const re_node_set *nodes, unsigned int context) +{ + re_hashval_t hash =3D nodes->nelem + context; + Idx i; + for (i =3D 0 ; i < nodes->nelem ; i++) + hash +=3D 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 * +__attribute_warn_unused_result__ +re_acquire_state (reg_errcode_t *err, const re_dfa_t *dfa, + const re_node_set *nodes) +{ + re_hashval_t hash; + re_dfastate_t *new_state; + struct re_state_table_entry *spot; + Idx i; +#if defined GCC_LINT || defined lint + /* Suppress bogus uninitialized-variable warnings. */ + *err =3D REG_NOERROR; +#endif + if (BE (nodes->nelem =3D=3D 0, 0)) + { + *err =3D REG_NOERROR; + return NULL; + } + hash =3D calc_state_hash (nodes, 0); + spot =3D dfa->state_table + (hash & dfa->state_hash_mask); + + for (i =3D 0 ; i < spot->num ; i++) + { + re_dfastate_t *state =3D spot->array[i]; + if (hash !=3D 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 =3D create_ci_newstate (dfa, nodes, hash); + if (BE (new_state =3D=3D NULL, 0)) + *err =3D 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 * +__attribute_warn_unused_result__ +re_acquire_state_context (reg_errcode_t *err, const re_dfa_t *dfa, + const re_node_set *nodes, unsigned int context) +{ + re_hashval_t hash; + re_dfastate_t *new_state; + struct re_state_table_entry *spot; + Idx i; +#if defined GCC_LINT || defined lint + /* Suppress bogus uninitialized-variable warnings. */ + *err =3D REG_NOERROR; +#endif + if (nodes->nelem =3D=3D 0) + { + *err =3D REG_NOERROR; + return NULL; + } + hash =3D calc_state_hash (nodes, context); + spot =3D dfa->state_table + (hash & dfa->state_hash_mask); + + for (i =3D 0 ; i < spot->num ; i++) + { + re_dfastate_t *state =3D spot->array[i]; + if (state->hash =3D=3D hash + && state->context =3D=3D context + && re_node_set_compare (state->entrance_nodes, nodes)) + return state; + } + /* There are no appropriate state in 'dfa', create the new one. */ + new_state =3D create_cd_newstate (dfa, nodes, context, hash); + if (BE (new_state =3D=3D NULL, 0)) + *err =3D REG_ESPACE; + + return new_state; +} + +/* Finish initialization of the new state NEWSTATE, and using its hash v= alue + HASH put in the appropriate bucket of DFA's state table. Return valu= e + indicates the error code if failed. */ + +static reg_errcode_t +__attribute_warn_unused_result__ +register_state (const re_dfa_t *dfa, re_dfastate_t *newstate, + re_hashval_t hash) +{ + struct re_state_table_entry *spot; + reg_errcode_t err; + Idx i; + + newstate->hash =3D hash; + err =3D re_node_set_alloc (&newstate->non_eps_nodes, newstate->nodes.n= elem); + if (BE (err !=3D REG_NOERROR, 0)) + return REG_ESPACE; + for (i =3D 0; i < newstate->nodes.nelem; i++) + { + Idx elem =3D newstate->nodes.elems[i]; + if (!IS_EPSILON_NODE (dfa->nodes[elem].type)) + if (! re_node_set_insert_last (&newstate->non_eps_nodes, elem)) + return REG_ESPACE; + } + + spot =3D dfa->state_table + (hash & dfa->state_hash_mask); + if (BE (spot->alloc <=3D spot->num, 0)) + { + Idx new_alloc =3D 2 * spot->num + 2; + re_dfastate_t **new_array =3D re_realloc (spot->array, re_dfastate= _t *, + new_alloc); + if (BE (new_array =3D=3D NULL, 0)) + return REG_ESPACE; + spot->array =3D new_array; + spot->alloc =3D new_alloc; + } + spot->array[spot->num++] =3D 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 !=3D &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 independent of contexts. + Return the new state if succeeded, otherwise return NULL. */ + +static re_dfastate_t * +__attribute_warn_unused_result__ +create_ci_newstate (const re_dfa_t *dfa, const re_node_set *nodes, + re_hashval_t hash) +{ + Idx i; + reg_errcode_t err; + re_dfastate_t *newstate; + + newstate =3D (re_dfastate_t *) calloc (sizeof (re_dfastate_t), 1); + if (BE (newstate =3D=3D NULL, 0)) + return NULL; + err =3D re_node_set_init_copy (&newstate->nodes, nodes); + if (BE (err !=3D REG_NOERROR, 0)) + { + re_free (newstate); + return NULL; + } + + newstate->entrance_nodes =3D &newstate->nodes; + for (i =3D 0 ; i < nodes->nelem ; i++) + { + re_token_t *node =3D dfa->nodes + nodes->elems[i]; + re_token_type_t type =3D node->type; + if (type =3D=3D CHARACTER && !node->constraint) + continue; +#ifdef RE_ENABLE_I18N + newstate->accept_mb |=3D node->accept_mb; +#endif /* RE_ENABLE_I18N */ + + /* If the state has the halt node, the state is a halt state. */ + if (type =3D=3D END_OF_RE) + newstate->halt =3D 1; + else if (type =3D=3D OP_BACK_REF) + newstate->has_backref =3D 1; + else if (type =3D=3D ANCHOR || node->constraint) + newstate->has_constraint =3D 1; + } + err =3D register_state (dfa, newstate, hash); + if (BE (err !=3D REG_NOERROR, 0)) + { + free_state (newstate); + newstate =3D 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 * +__attribute_warn_unused_result__ +create_cd_newstate (const re_dfa_t *dfa, const re_node_set *nodes, + unsigned int context, re_hashval_t hash) +{ + Idx i, nctx_nodes =3D 0; + reg_errcode_t err; + re_dfastate_t *newstate; + + newstate =3D (re_dfastate_t *) calloc (sizeof (re_dfastate_t), 1); + if (BE (newstate =3D=3D NULL, 0)) + return NULL; + err =3D re_node_set_init_copy (&newstate->nodes, nodes); + if (BE (err !=3D REG_NOERROR, 0)) + { + re_free (newstate); + return NULL; + } + + newstate->context =3D context; + newstate->entrance_nodes =3D &newstate->nodes; + + for (i =3D 0 ; i < nodes->nelem ; i++) + { + re_token_t *node =3D dfa->nodes + nodes->elems[i]; + re_token_type_t type =3D node->type; + unsigned int constraint =3D node->constraint; + + if (type =3D=3D CHARACTER && !constraint) + continue; +#ifdef RE_ENABLE_I18N + newstate->accept_mb |=3D node->accept_mb; +#endif /* RE_ENABLE_I18N */ + + /* If the state has the halt node, the state is a halt state. */ + if (type =3D=3D END_OF_RE) + newstate->halt =3D 1; + else if (type =3D=3D OP_BACK_REF) + newstate->has_backref =3D 1; + + if (constraint) + { + if (newstate->entrance_nodes =3D=3D &newstate->nodes) + { + newstate->entrance_nodes =3D re_malloc (re_node_set, 1); + if (BE (newstate->entrance_nodes =3D=3D NULL, 0)) + { + free_state (newstate); + return NULL; + } + if (re_node_set_init_copy (newstate->entrance_nodes, nodes) + !=3D REG_NOERROR) + return NULL; + nctx_nodes =3D 0; + newstate->has_constraint =3D 1; + } + + if (NOT_SATISFY_PREV_CONSTRAINT (constraint,context)) + { + re_node_set_remove_at (&newstate->nodes, i - nctx_nodes); + ++nctx_nodes; + } + } + } + err =3D register_state (dfa, newstate, hash); + if (BE (err !=3D REG_NOERROR, 0)) + { + free_state (newstate); + newstate =3D NULL; + } + return newstate; +} diff --git a/lib/regex_internal.h b/lib/regex_internal.h new file mode 100644 index 0000000000..7bbe802bc5 --- /dev/null +++ b/lib/regex_internal.h @@ -0,0 +1,911 @@ +/* Extended regular expression matching and search library. + Copyright (C) 2002-2018 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Isamu Hasegawa . + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU General Public + License as published by the Free Software Foundation; either + version 3 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 + General Public License for more details. + + You should have received a copy of the GNU General Public + License along with the GNU C Library; if not, see + . */ + +#ifndef _REGEX_INTERNAL_H +#define _REGEX_INTERNAL_H 1 + +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include + +/* Properties of integers. Although Gnulib has intprops.h, glibc does + without for now. */ +#ifndef _LIBC +# include "intprops.h" +#else +/* True if the real type T is signed. */ +# define TYPE_SIGNED(t) (! ((t) 0 < (t) -1)) + +/* True if adding the nonnegative Idx values A and B would overflow. + If false, set *R to A + B. A, B, and R may be evaluated more than + once, or zero times. Although this is not a full implementation of + Gnulib INT_ADD_WRAPV, it is good enough for glibc regex code. + FIXME: This implementation is a fragile stopgap, and this file would + be simpler and more robust if intprops.h were migrated into glibc. *= / +# define INT_ADD_WRAPV(a, b, r) \ + (IDX_MAX - (a) < (b) ? true : (*(r) =3D (a) + (b), false)) +#endif + +#ifdef _LIBC +# include +# define lock_define(name) __libc_lock_define (, name) +# define lock_init(lock) (__libc_lock_init (lock), 0) +# define lock_fini(lock) ((void) 0) +# define lock_lock(lock) __libc_lock_lock (lock) +# define lock_unlock(lock) __libc_lock_unlock (lock) +#elif defined GNULIB_LOCK && !defined USE_UNLOCKED_IO +# include "glthread/lock.h" + /* Use gl_lock_define if empty macro arguments are known to work. + Otherwise, fall back on less-portable substitutes. */ +# if ((defined __GNUC__ && !defined __STRICT_ANSI__) \ + || (defined __STDC_VERSION__ && 199901L <=3D __STDC_VERSION__)) +# define lock_define(name) gl_lock_define (, name) +# elif USE_POSIX_THREADS +# define lock_define(name) pthread_mutex_t name; +# elif USE_PTH_THREADS +# define lock_define(name) pth_mutex_t name; +# elif USE_SOLARIS_THREADS +# define lock_define(name) mutex_t name; +# elif USE_WINDOWS_THREADS +# define lock_define(name) gl_lock_t name; +# else +# define lock_define(name) +# endif +# define lock_init(lock) glthread_lock_init (&(lock)) +# define lock_fini(lock) glthread_lock_destroy (&(lock)) +# define lock_lock(lock) glthread_lock_lock (&(lock)) +# define lock_unlock(lock) glthread_lock_unlock (&(lock)) +#elif defined GNULIB_PTHREAD && !defined USE_UNLOCKED_IO +# include +# define lock_define(name) pthread_mutex_t name; +# define lock_init(lock) pthread_mutex_init (&(lock), 0) +# define lock_fini(lock) pthread_mutex_destroy (&(lock)) +# define lock_lock(lock) pthread_mutex_lock (&(lock)) +# define lock_unlock(lock) pthread_mutex_unlock (&(lock)) +#else +# define lock_define(name) +# define lock_init(lock) 0 +# define lock_fini(lock) ((void) 0) + /* The 'dfa' avoids an "unused variable 'dfa'" warning from GCC. */ +# define lock_lock(lock) ((void) dfa) +# define lock_unlock(lock) ((void) 0) +#endif + +/* In case that the system doesn't have isblank(). */ +#if !defined _LIBC && ! (defined isblank || (HAVE_ISBLANK && HAVE_DECL_I= SBLANK)) +# define isblank(ch) ((ch) =3D=3D ' ' || (ch) =3D=3D '\t') +#endif + +#ifdef _LIBC +# ifndef _RE_DEFINE_LOCALE_FUNCTIONS +# define _RE_DEFINE_LOCALE_FUNCTIONS 1 +# include +# include +# endif +#endif + +/* This is for other GNU distributions with internationalized messages. = */ +#if (HAVE_LIBINTL_H && ENABLE_NLS) || defined _LIBC +# include +# ifdef _LIBC +# undef gettext +# define gettext(msgid) \ + __dcgettext (_libc_intl_domainname, msgid, LC_MESSAGES) +# endif +#else +# undef gettext +# define gettext(msgid) (msgid) +#endif + +#ifndef gettext_noop +/* This define is so xgettext can find the internationalizable + strings. */ +# define gettext_noop(String) String +#endif + +#if (defined MB_CUR_MAX && HAVE_WCTYPE_H && HAVE_ISWCTYPE) || _LIBC +# define RE_ENABLE_I18N +#endif + +#define BE(expr, val) __builtin_expect (expr, val) + +/* Number of ASCII characters. */ +#define ASCII_CHARS 0x80 + +/* Number of single byte characters. */ +#define SBC_MAX (UCHAR_MAX + 1) + +#define COLL_ELEM_LEN_MAX 8 + +/* The character which represents newline. */ +#define NEWLINE_CHAR '\n' +#define WIDE_NEWLINE_CHAR L'\n' + +/* Rename to standard API for using out of glibc. */ +#ifndef _LIBC +# undef __wctype +# undef __iswctype +# define __wctype wctype +# define __iswalnum iswalnum +# define __iswctype iswctype +# define __towlower towlower +# define __towupper towupper +# define __btowc btowc +# define __mbrtowc mbrtowc +# define __wcrtomb wcrtomb +# define __regfree regfree +# define attribute_hidden +#endif /* not _LIBC */ + +#if __GNUC__ < 3 + (__GNUC_MINOR__ < 1) +# define __attribute__(arg) +#endif + +#ifndef SSIZE_MAX +# define SSIZE_MAX ((ssize_t) (SIZE_MAX / 2)) +#endif + +/* The type of indexes into strings. This is signed, not size_t, + since the API requires indexes to fit in regoff_t anyway, and using + signed integers makes the code a bit smaller and presumably faster. + The traditional GNU regex implementation uses int for indexes. + The POSIX-compatible implementation uses a possibly-wider type. + The name 'Idx' is three letters to minimize the hassle of + reindenting a lot of regex code that formerly used 'int'. */ +typedef regoff_t Idx; +#ifdef _REGEX_LARGE_OFFSETS +# define IDX_MAX SSIZE_MAX +#else +# define IDX_MAX INT_MAX +#endif + +/* A hash value, suitable for computing hash tables. */ +typedef __re_size_t re_hashval_t; + +/* 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. For portability to hosts with + padding bits, do not use '(sizeof (bitset_word_t) * CHAR_BIT)'; + instead, deduce it directly from BITSET_WORD_MAX. Avoid + greater-than-32-bit integers and unconditional shifts by more than + 31 bits, as they're not portable. */ +#if BITSET_WORD_MAX =3D=3D 0xffffffffUL +# define BITSET_WORD_BITS 32 +#elif BITSET_WORD_MAX >> 31 >> 4 =3D=3D 1 +# define BITSET_WORD_BITS 36 +#elif BITSET_WORD_MAX >> 31 >> 16 =3D=3D 1 +# define BITSET_WORD_BITS 48 +#elif BITSET_WORD_MAX >> 31 >> 28 =3D=3D 1 +# define BITSET_WORD_BITS 60 +#elif BITSET_WORD_MAX >> 31 >> 31 >> 1 =3D=3D 1 +# define BITSET_WORD_BITS 64 +#elif BITSET_WORD_MAX >> 31 >> 31 >> 9 =3D=3D 1 +# define BITSET_WORD_BITS 72 +#elif BITSET_WORD_MAX >> 31 >> 31 >> 31 >> 31 >> 3 =3D=3D 1 +# define BITSET_WORD_BITS 128 +#elif BITSET_WORD_MAX >> 31 >> 31 >> 31 >> 31 >> 31 >> 31 >> 31 >> 31 >>= 7 =3D=3D 1 +# define BITSET_WORD_BITS 256 +#elif BITSET_WORD_MAX >> 31 >> 31 >> 31 >> 31 >> 31 >> 31 >> 31 >> 31 >>= 7 > 1 +# define BITSET_WORD_BITS 257 /* any value > SBC_MAX will do here */ +# if BITSET_WORD_BITS <=3D SBC_MAX +# error "Invalid SBC_MAX" +# endif +#else +# error "Add case for new bitset_word_t size" +#endif + +/* Number of bitset_word_t values in a bitset_t. */ +#define BITSET_WORDS ((SBC_MAX + BITSET_WORD_BITS - 1) / BITSET_WORD_BIT= S) + +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 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 =3D PREV_WORD_CONSTRAINT | NEXT_WORD_CONSTRAINT, + WORD_FIRST =3D PREV_NOTWORD_CONSTRAINT | NEXT_WORD_CONSTRAINT, + WORD_LAST =3D PREV_WORD_CONSTRAINT | NEXT_NOTWORD_CONSTRAINT, + INSIDE_NOTWORD =3D PREV_NOTWORD_CONSTRAINT | NEXT_NOTWORD_CONSTRAINT, + LINE_FIRST =3D PREV_NEWLINE_CONSTRAINT, + LINE_LAST =3D NEXT_NEWLINE_CONSTRAINT, + BUF_FIRST =3D PREV_BEGBUF_CONSTRAINT, + BUF_LAST =3D NEXT_ENDBUF_CONSTRAINT, + WORD_DELIM =3D WORD_DELIM_CONSTRAINT, + NOT_WORD_DELIM =3D NOT_WORD_DELIM_CONSTRAINT +} re_context_type; + +typedef struct +{ + Idx alloc; + Idx nelem; + Idx *elems; +} re_node_set; + +typedef enum +{ + NON_TYPE =3D 0, + + /* Node type, These are used by token, node, tree. */ + CHARACTER =3D 1, + END_OF_RE =3D 2, + SIMPLE_BRACKET =3D 3, + OP_BACK_REF =3D 4, + OP_PERIOD =3D 5, +#ifdef RE_ENABLE_I18N + COMPLEX_BRACKET =3D 6, + OP_UTF8_PERIOD =3D 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 =3D EPSILON_BIT | 0, + OP_CLOSE_SUBEXP =3D EPSILON_BIT | 1, + OP_ALT =3D EPSILON_BIT | 2, + OP_DUP_ASTERISK =3D EPSILON_BIT | 3, + ANCHOR =3D EPSILON_BIT | 4, + + /* Tree type, these are used only by tree. */ + CONCAT =3D 16, + SUBEXP =3D 17, + + /* Token type, these are used only by token. */ + OP_DUP_PLUS =3D 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. */ +# ifdef _LIBC + int32_t *coll_syms; +# endif + + /* Equivalence classes. */ +# ifdef _LIBC + int32_t *equiv_classes; +# endif + + /* Range expressions. */ +# ifdef _LIBC + uint32_t *range_starts; + uint32_t *range_ends; +# else /* not _LIBC */ + wchar_t *range_starts; + wchar_t *range_ends; +# endif /* not _LIBC */ + + /* Character classes. */ + wctype_t *char_classes; + + /* If this character set is the non-matching list. */ + unsigned int non_match : 1; + + /* # of multibyte characters. */ + Idx nmbchars; + + /* # of collating symbols. */ + Idx ncoll_syms; + + /* # of equivalence classes. */ + Idx nequiv_classes; + + /* # of range expressions. */ + Idx nranges; + + /* # of character classes. */ + Idx 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 */ + Idx idx; /* for BACK_REF */ + re_context_type ctx_type; /* for ANCHOR */ + } opr; +#if __GNUC__ >=3D 2 && !defined __STRICT_ANSI__ + 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" lik= e + REG_ICASE, upper cases of the string are stored, otherwise MBS poin= ts + 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; + Idx *offsets; + mbstate_t cur_state; +#endif + /* Index in RAW_MBS. Each character mbs[i] corresponds to + raw_mbs[raw_mbs_idx + i]. */ + Idx raw_mbs_idx; + /* The length of the valid characters in the buffers. */ + Idx valid_len; + /* The corresponding number of bytes in raw_mbs array. */ + Idx valid_raw_len; + /* The length of the buffers MBS and WCS. */ + Idx bufs_len; + /* The index in MBS, which is updated by re_string_fetch_byte. */ + Idx cur_idx; + /* length of RAW_MBS array. */ + Idx raw_len; + /* This is RAW_LEN - RAW_MBS_IDX + VALID_LEN - VALID_RAW_LEN. */ + Idx 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 buffe= r + instead of LEN. */ + Idx raw_stop; + /* This is RAW_STOP - RAW_MBS_IDX adjusted through OFFSETS. */ + Idx 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_patte= rn. */ + RE_TRANSLATE_TYPE trans; + /* Copy of re_dfa_t's word_char. */ + re_const_bitset_ptr_t word_char; + /* true 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; + +#ifndef _LIBC +# define IS_IN(libc) false +#endif + +#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) =3D=3D (pstr)->valid_len || (pstr)->wcs[idx] !=3D WEOF) +#define re_string_is_single_byte_char(pstr, idx) \ + ((pstr)->wcs[idx] !=3D WEOF && ((pstr)->valid_len =3D=3D (idx) + 1 \ + || (pstr)->wcs[(idx) + 1] !=3D WEOF)) +#define re_string_eoi(pstr) ((pstr)->stop <=3D (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 +=3D (idx)) +#define re_string_set_index(pstr,idx) ((pstr)->cur_idx =3D (idx)) + +#if defined _LIBC || HAVE_ALLOCA +# include +#endif + +#ifndef _LIBC +# if HAVE_ALLOCA +/* The OS usually guarantees only one guard page at the bottom of the st= ack, + 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 possibil= ity + 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 +# undef alloca +# define alloca(n) malloc (n) +# endif +#endif + +#ifdef _LIBC +# define MALLOC_0_IS_NONNULL 1 +#elif !defined MALLOC_0_IS_NONNULL +# define MALLOC_0_IS_NONNULL 0 +#endif + +#ifndef MAX +# define MAX(a,b) ((a) < (b) ? (b) : (a)) +#endif +#ifndef MIN +# define MIN(a,b) ((a) < (b) ? (a) : (b)) +#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' =3D=3D 0. + Otherwise 'type' indicate the type of this node. */ + Idx 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) =3D=3D 0) + +#define IS_WORD_CHAR(ch) (isalnum (ch) || (ch) =3D=3D '_') +#define IS_NEWLINE(ch) ((ch) =3D=3D NEWLINE_CHAR) +#define IS_WIDE_WORD_CHAR(ch) (__iswalnum (ch) || (ch) =3D=3D L'_') +#define IS_WIDE_NEWLINE(ch) ((ch) =3D=3D 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 (con= text))\ + || ((constraint & PREV_BEGBUF_CONSTRAINT) && !IS_BEGBUF_CONTEXT (conte= xt))) + +#define NOT_SATISFY_NEXT_CONSTRAINT(constraint,context) \ + ((((constraint) & NEXT_WORD_CONSTRAINT) && !IS_WORD_CONTEXT (context)) = \ + || (((constraint) & NEXT_NOTWORD_CONSTRAINT) && IS_WORD_CONTEXT (conte= xt)) \ + || (((constraint) & NEXT_NEWLINE_CONSTRAINT) && !IS_NEWLINE_CONTEXT (c= ontext)) \ + || (((constraint) & NEXT_ENDBUF_CONSTRAINT) && !IS_ENDBUF_CONTEXT (con= text))) + +struct re_dfastate_t +{ + re_hashval_t 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 +{ + Idx num; + Idx alloc; + re_dfastate_t **array; +}; + +/* Array type used in re_sub_match_last_t and re_sub_match_top_t. */ + +typedef struct +{ + Idx next_idx; + Idx alloc; + re_dfastate_t **array; +} state_array_t; + +/* Store information about the node NODE whose type is OP_CLOSE_SUBEXP. = */ + +typedef struct +{ + Idx node; + Idx 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 +{ + Idx str_idx; + Idx node; + state_array_t *path; + Idx alasts; /* Allocation size of LASTS. */ + Idx nlasts; /* The number of LASTS. */ + re_sub_match_last_t **lasts; +} re_sub_match_top_t; + +struct re_backref_cache_entry +{ + Idx node; + Idx str_idx; + Idx subexp_from; + Idx 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; +#if defined _LIBC || (defined __STDC_VERSION__ && __STDC_VERSION__ >=3D = 199901L) + const re_dfa_t *const dfa; +#else + const re_dfa_t *dfa; +#endif + /* EFLAGS of the argument of regexec. */ + int eflags; + /* Where the matching ends. */ + Idx match_last; + Idx last_node; + /* The state log used by the matcher. */ + re_dfastate_t **state_log; + Idx state_log_top; + /* Back reference cache. */ + Idx nbkref_ents; + Idx abkref_ents; + struct re_backref_cache_entry *bkref_ents; + int max_mb_elem_len; + Idx nsub_tops; + Idx 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; + Idx last_node; + Idx last_str_idx; + re_node_set limits; +} re_sift_context_t; + +struct re_fail_stack_ent_t +{ + Idx idx; + Idx node; + regmatch_t *regs; + re_node_set eps_via_nodes; +}; + +struct re_fail_stack_t +{ + Idx num; + Idx alloc; + struct re_fail_stack_ent_t *stack; +}; + +struct re_dfa_t +{ + re_token_t *nodes; + size_t nodes_alloc; + size_t nodes_len; + Idx *nexts; + Idx *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. */ + re_hashval_t state_hash_mask; + Idx init_node; + Idx 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; + Idx *subexp_map; +#ifdef DEBUG + char* re_str; +#endif + lock_define (lock) +}; + +#define re_node_set_init_empty(set) memset (set, '\0', sizeof (re_node_s= et)) +#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 =3D 0) +#define re_node_set_free(set) re_free ((set)->elems) +=0C + +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; + wchar_t wch; + } opr; +} bracket_elem_t; + + +/* Functions for bitset_t operation. */ + +static inline void +bitset_set (bitset_t set, Idx i) +{ + set[i / BITSET_WORD_BITS] |=3D (bitset_word_t) 1 << i % BITSET_WORD_BI= TS; +} + +static inline void +bitset_clear (bitset_t set, Idx i) +{ + set[i / BITSET_WORD_BITS] &=3D ~ ((bitset_word_t) 1 << i % BITSET_WORD= _BITS); +} + +static inline bool +bitset_contain (const bitset_t set, Idx i) +{ + return (set[i / BITSET_WORD_BITS] >> i % BITSET_WORD_BITS) & 1; +} + +static inline void +bitset_empty (bitset_t set) +{ + memset (set, '\0', sizeof (bitset_t)); +} + +static inline void +bitset_set_all (bitset_t set) +{ + memset (set, -1, sizeof (bitset_word_t) * (SBC_MAX / BITSET_WORD_BITS)= ); + if (SBC_MAX % BITSET_WORD_BITS !=3D 0) + set[BITSET_WORDS - 1] =3D + ((bitset_word_t) 1 << SBC_MAX % BITSET_WORD_BITS) - 1; +} + +static inline void +bitset_copy (bitset_t dest, const bitset_t src) +{ + memcpy (dest, src, sizeof (bitset_t)); +} + +static inline void +bitset_not (bitset_t set) +{ + int bitset_i; + for (bitset_i =3D 0; bitset_i < SBC_MAX / BITSET_WORD_BITS; ++bitset_i= ) + set[bitset_i] =3D ~set[bitset_i]; + if (SBC_MAX % BITSET_WORD_BITS !=3D 0) + set[BITSET_WORDS - 1] =3D + ((((bitset_word_t) 1 << SBC_MAX % BITSET_WORD_BITS) - 1) + & ~set[BITSET_WORDS - 1]); +} + +static inline void +bitset_merge (bitset_t dest, const bitset_t src) +{ + int bitset_i; + for (bitset_i =3D 0; bitset_i < BITSET_WORDS; ++bitset_i) + dest[bitset_i] |=3D src[bitset_i]; +} + +static inline void +bitset_mask (bitset_t dest, const bitset_t src) +{ + int bitset_i; + for (bitset_i =3D 0; bitset_i < BITSET_WORDS; ++bitset_i) + dest[bitset_i] &=3D src[bitset_i]; +} + +#ifdef RE_ENABLE_I18N +/* Functions for re_string. */ +static int +__attribute__ ((pure, unused)) +re_string_char_size_at (const re_string_t *pstr, Idx idx) +{ + int byte_idx; + if (pstr->mb_cur_max =3D=3D 1) + return 1; + for (byte_idx =3D 1; idx + byte_idx < pstr->valid_len; ++byte_idx) + if (pstr->wcs[idx + byte_idx] !=3D WEOF) + break; + return byte_idx; +} + +static wint_t +__attribute__ ((pure, unused)) +re_string_wchar_at (const re_string_t *pstr, Idx idx) +{ + if (pstr->mb_cur_max =3D=3D 1) + return (wint_t) pstr->mbs[idx]; + return (wint_t) pstr->wcs[idx]; +} + +# ifdef _LIBC +# include +# endif + +static int +__attribute__ ((pure, unused)) +re_string_elem_size_at (const re_string_t *pstr, Idx idx) +{ +# ifdef _LIBC + const unsigned char *p, *extra; + const int32_t *table, *indirect; + uint_fast32_t nrules =3D _NL_CURRENT_WORD (LC_COLLATE, _NL_COLLATE_NRU= LES); + + if (nrules !=3D 0) + { + table =3D (const int32_t *) _NL_CURRENT (LC_COLLATE, _NL_COLLATE_T= ABLEMB); + extra =3D (const unsigned char *) + _NL_CURRENT (LC_COLLATE, _NL_COLLATE_EXTRAMB); + indirect =3D (const int32_t *) _NL_CURRENT (LC_COLLATE, + _NL_COLLATE_INDIRECTMB); + p =3D pstr->mbs + idx; + findidx (table, indirect, extra, &p, pstr->len - idx); + return p - pstr->mbs - idx; + } + else +# endif /* _LIBC */ + return 1; +} +#endif /* RE_ENABLE_I18N */ + +#ifndef __GNUC_PREREQ +# if defined __GNUC__ && defined __GNUC_MINOR__ +# define __GNUC_PREREQ(maj, min) \ + ((__GNUC__ << 16) + __GNUC_MINOR__ >=3D ((maj) << 16) + (min)) +# else +# define __GNUC_PREREQ(maj, min) 0 +# endif +#endif + +#if __GNUC_PREREQ (3,4) +# undef __attribute_warn_unused_result__ +# define __attribute_warn_unused_result__ \ + __attribute__ ((__warn_unused_result__)) +#else +# define __attribute_warn_unused_result__ /* empty */ +#endif + +#ifndef FALLTHROUGH +# if __GNUC__ < 7 +# define FALLTHROUGH ((void) 0) +# else +# define FALLTHROUGH __attribute__ ((__fallthrough__)) +# endif +#endif + +#endif /* _REGEX_INTERNAL_H */ diff --git a/lib/regexec.c b/lib/regexec.c new file mode 100644 index 0000000000..6591311164 --- /dev/null +++ b/lib/regexec.c @@ -0,0 +1,4324 @@ +/* Extended regular expression matching and search library. + Copyright (C) 2002-2018 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Isamu Hasegawa . + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU General Public + License as published by the Free Software Foundation; either + version 3 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 + General Public License for more details. + + You should have received a copy of the GNU General Public + License along with the GNU C Library; if not, see + . */ + +static reg_errcode_t match_ctx_init (re_match_context_t *cache, int efla= gs, + Idx n); +static void match_ctx_clean (re_match_context_t *mctx); +static void match_ctx_free (re_match_context_t *cache); +static reg_errcode_t match_ctx_add_entry (re_match_context_t *cache, Idx= node, + Idx str_idx, Idx from, Idx to); +static Idx search_cur_bkref_entry (const re_match_context_t *mctx, Idx s= tr_idx); +static reg_errcode_t match_ctx_add_subtop (re_match_context_t *mctx, Idx= node, + Idx str_idx); +static re_sub_match_last_t * match_ctx_add_sublast (re_sub_match_top_t *= subtop, + Idx node, Idx str_idx); +static void sift_ctx_init (re_sift_context_t *sctx, re_dfastate_t **sift= ed_sts, + re_dfastate_t **limited_sts, Idx last_node, + Idx last_str_idx); +static reg_errcode_t re_search_internal (const regex_t *preg, + const char *string, Idx length, + Idx start, Idx last_start, Idx stop, + size_t nmatch, regmatch_t pmatch[], + int eflags); +static regoff_t re_search_2_stub (struct re_pattern_buffer *bufp, + const char *string1, Idx length1, + const char *string2, Idx length2, + Idx start, regoff_t range, + struct re_registers *regs, + Idx stop, bool ret_len); +static regoff_t re_search_stub (struct re_pattern_buffer *bufp, + const char *string, Idx length, Idx start, + regoff_t range, Idx stop, + struct re_registers *regs, + bool ret_len); +static unsigned re_copy_regs (struct re_registers *regs, regmatch_t *pma= tch, + Idx nregs, int regs_allocated); +static reg_errcode_t prune_impossible_nodes (re_match_context_t *mctx); +static Idx check_matching (re_match_context_t *mctx, bool fl_longest_mat= ch, + Idx *p_match_first); +static Idx check_halt_state_context (const re_match_context_t *mctx, + const re_dfastate_t *state, Idx idx); +static void update_regs (const re_dfa_t *dfa, regmatch_t *pmatch, + regmatch_t *prev_idx_match, Idx cur_node, + Idx cur_idx, Idx nmatch); +static reg_errcode_t push_fail_stack (struct re_fail_stack_t *fs, + Idx str_idx, Idx dest_node, Idx nregs, + regmatch_t *regs, + re_node_set *eps_via_nodes); +static reg_errcode_t set_regs (const regex_t *preg, + const re_match_context_t *mctx, + size_t nmatch, regmatch_t *pmatch, + bool fl_backtrack); +static reg_errcode_t free_fail_stack_return (struct re_fail_stack_t *fs)= ; + +#ifdef RE_ENABLE_I18N +static int sift_states_iter_mb (const re_match_context_t *mctx, + re_sift_context_t *sctx, + Idx node_idx, Idx str_idx, Idx max_str_idx); +#endif /* RE_ENABLE_I18N */ +static reg_errcode_t sift_states_backward (const re_match_context_t *mct= x, + re_sift_context_t *sctx); +static reg_errcode_t build_sifted_states (const re_match_context_t *mctx= , + re_sift_context_t *sctx, Idx str_idx, + re_node_set *cur_dest); +static reg_errcode_t update_cur_sifted_state (const re_match_context_t *= mctx, + re_sift_context_t *sctx, + Idx str_idx, + re_node_set *dest_nodes); +static reg_errcode_t add_epsilon_src_nodes (const re_dfa_t *dfa, + re_node_set *dest_nodes, + const re_node_set *candidates); +static bool check_dst_limits (const re_match_context_t *mctx, + const re_node_set *limits, + Idx dst_node, Idx dst_idx, Idx src_node, + Idx src_idx); +static int check_dst_limits_calc_pos_1 (const re_match_context_t *mctx, + int boundaries, Idx subexp_idx, + Idx from_node, Idx bkref_idx); +static int check_dst_limits_calc_pos (const re_match_context_t *mctx, + Idx limit, Idx subexp_idx, + Idx node, Idx str_idx, + Idx bkref_idx); +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, + Idx str_idx); +static reg_errcode_t sift_states_bkref (const re_match_context_t *mctx, + re_sift_context_t *sctx, + Idx str_idx, const re_node_set *candidates); +static reg_errcode_t merge_state_array (const re_dfa_t *dfa, + re_dfastate_t **dst, + re_dfastate_t **src, Idx num); +static re_dfastate_t *find_recover_state (reg_errcode_t *err, + re_match_context_t *mctx); +static re_dfastate_t *transit_state (reg_errcode_t *err, + re_match_context_t *mctx, + re_dfastate_t *state); +static re_dfastate_t *merge_state_with_log (reg_errcode_t *err, + re_match_context_t *mctx, + re_dfastate_t *next_state); +static reg_errcode_t check_subexp_matching_top (re_match_context_t *mctx= , + re_node_set *cur_nodes, + Idx str_idx); +#if 0 +static re_dfastate_t *transit_state_sb (reg_errcode_t *err, + re_match_context_t *mctx, + re_dfastate_t *pstate); +#endif +#ifdef RE_ENABLE_I18N +static reg_errcode_t transit_state_mb (re_match_context_t *mctx, + re_dfastate_t *pstate); +#endif /* RE_ENABLE_I18N */ +static reg_errcode_t transit_state_bkref (re_match_context_t *mctx, + const re_node_set *nodes); +static reg_errcode_t get_subexp (re_match_context_t *mctx, + Idx bkref_node, Idx bkref_str_idx); +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, + Idx bkref_node, Idx bkref_str); +static Idx find_subexp_node (const re_dfa_t *dfa, const re_node_set *nod= es, + Idx subexp_idx, int type); +static reg_errcode_t check_arrival (re_match_context_t *mctx, + state_array_t *path, Idx top_node, + Idx top_str, Idx last_node, Idx last_str, + int type); +static reg_errcode_t check_arrival_add_next_nodes (re_match_context_t *m= ctx, + Idx str_idx, + re_node_set *cur_nodes, + re_node_set *next_nodes); +static reg_errcode_t check_arrival_expand_ecl (const re_dfa_t *dfa, + re_node_set *cur_nodes, + Idx ex_subexp, int type); +static reg_errcode_t check_arrival_expand_ecl_sub (const re_dfa_t *dfa, + re_node_set *dst_nodes, + Idx target, Idx ex_subexp, + int type); +static reg_errcode_t expand_bkref_cache (re_match_context_t *mctx, + re_node_set *cur_nodes, Idx cur_str, + Idx subexp_num, int type); +static bool build_trtable (const re_dfa_t *dfa, re_dfastate_t *state); +#ifdef RE_ENABLE_I18N +static int check_node_accept_bytes (const re_dfa_t *dfa, Idx node_idx, + const re_string_t *input, Idx idx); +# ifdef _LIBC +static unsigned int find_collation_sequence_value (const unsigned char *= mbs, + size_t name_len); +# endif /* _LIBC */ +#endif /* RE_ENABLE_I18N */ +static Idx group_nodes_into_DFAstates (const re_dfa_t *dfa, + const re_dfastate_t *state, + re_node_set *states_node, + bitset_t *states_ch); +static bool check_node_accept (const re_match_context_t *mctx, + const re_token_t *node, Idx idx); +static reg_errcode_t extend_buffers (re_match_context_t *mctx, int min_l= en); +=0C +/* 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; + Idx start, length; + re_dfa_t *dfa =3D preg->buffer; + + if (eflags & ~(REG_NOTBOL | REG_NOTEOL | REG_STARTEND)) + return REG_BADPAT; + + if (eflags & REG_STARTEND) + { + start =3D pmatch[0].rm_so; + length =3D pmatch[0].rm_eo; + } + else + { + start =3D 0; + length =3D strlen (string); + } + + lock_lock (dfa->lock); + if (preg->no_sub) + err =3D re_search_internal (preg, string, length, start, length, + length, 0, NULL, eflags); + else + err =3D re_search_internal (preg, string, length, start, length, + length, nmatch, pmatch, eflags); + lock_unlock (dfa->lock); + return err !=3D REG_NOERROR; +} + +#ifdef _LIBC +libc_hidden_def (__regexec) + +# include +versioned_symbol (libc, __regexec, regexec, GLIBC_2_3_4); + +# if SHLIB_COMPAT (libc, GLIBC_2_0, GLIBC_2_3_4) +__typeof__ (__regexec) __compat_regexec; + +int +attribute_compat_text_section +__compat_regexec (const regex_t *_Restrict_ preg, + const char *_Restrict_ string, size_t nmatch, + regmatch_t pmatch[], int eflags) +{ + return regexec (preg, string, nmatch, pmatch, + eflags & (REG_NOTBOL | REG_NOTEOL)); +} +compat_symbol (libc, __compat_regexec, regexec, GLIBC_2_0); +# endif +#endif + +/* 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 mat= ch + starting from index START + 1, and so on. The last start position tr= ied + is START + RANGE. (Thus RANGE =3D 0 forces re_search to operate the = same + way as re_match().) + + The parameter STOP of re_{match,search}_2 specifies that no match exc= eeding + 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 stored in REGS. (For the "_2" variants, the offset= s are + computed relative to the concatenation, not relative to the individua= l + strings.) + + On success, re_match* functions return the length of the match, re_se= arch* + return the position of the start of the match. Return value -1 means= no + match was found and -2 indicates an internal error. */ + +regoff_t +re_match (struct re_pattern_buffer *bufp, const char *string, Idx length= , + Idx start, struct re_registers *regs) +{ + return re_search_stub (bufp, string, length, start, 0, length, regs, t= rue); +} +#ifdef _LIBC +weak_alias (__re_match, re_match) +#endif + +regoff_t +re_search (struct re_pattern_buffer *bufp, const char *string, Idx lengt= h, + Idx start, regoff_t range, struct re_registers *regs) +{ + return re_search_stub (bufp, string, length, start, range, length, reg= s, + false); +} +#ifdef _LIBC +weak_alias (__re_search, re_search) +#endif + +regoff_t +re_match_2 (struct re_pattern_buffer *bufp, const char *string1, Idx len= gth1, + const char *string2, Idx length2, Idx start, + struct re_registers *regs, Idx stop) +{ + return re_search_2_stub (bufp, string1, length1, string2, length2, + start, 0, regs, stop, true); +} +#ifdef _LIBC +weak_alias (__re_match_2, re_match_2) +#endif + +regoff_t +re_search_2 (struct re_pattern_buffer *bufp, const char *string1, Idx le= ngth1, + const char *string2, Idx length2, Idx start, regoff_t range, + struct re_registers *regs, Idx stop) +{ + return re_search_2_stub (bufp, string1, length1, string2, length2, + start, range, regs, stop, false); +} +#ifdef _LIBC +weak_alias (__re_search_2, re_search_2) +#endif + +static regoff_t +re_search_2_stub (struct re_pattern_buffer *bufp, const char *string1, + Idx length1, const char *string2, Idx length2, Idx start, + regoff_t range, struct re_registers *regs, + Idx stop, bool ret_len) +{ + const char *str; + regoff_t rval; + Idx len; + char *s =3D NULL; + + if (BE ((length1 < 0 || length2 < 0 || stop < 0 + || INT_ADD_WRAPV (length1, length2, &len)), + 0)) + return -2; + + /* Concatenate the strings. */ + if (length2 > 0) + if (length1 > 0) + { + s =3D re_malloc (char, len); + + if (BE (s =3D=3D NULL, 0)) + return -2; +#ifdef _LIBC + memcpy (__mempcpy (s, string1, length1), string2, length2); +#else + memcpy (s, string1, length1); + memcpy (s + length1, string2, length2); +#endif + str =3D s; + } + else + str =3D string2; + else + str =3D string1; + + rval =3D re_search_stub (bufp, str, len, start, range, stop, regs, + ret_len); + re_free (s); + return rval; +} + +/* The parameters have the same meaning as those of re_search. + Additional parameters: + If RET_LEN is true the length of the match is returned (re_match styl= e); + otherwise the position of the match is returned. */ + +static regoff_t +re_search_stub (struct re_pattern_buffer *bufp, const char *string, Idx = length, + Idx start, regoff_t range, Idx stop, struct re_registers *regs, + bool ret_len) +{ + reg_errcode_t result; + regmatch_t *pmatch; + Idx nregs; + regoff_t rval; + int eflags =3D 0; + re_dfa_t *dfa =3D bufp->buffer; + Idx last_start =3D start + range; + + /* Check for out-of-range. */ + if (BE (start < 0 || start > length, 0)) + return -1; + if (BE (length < last_start || (0 <=3D range && last_start < start), 0= )) + last_start =3D length; + else if (BE (last_start < 0 || (range < 0 && start <=3D last_start), 0= )) + last_start =3D 0; + + lock_lock (dfa->lock); + + eflags |=3D (bufp->not_bol) ? REG_NOTBOL : 0; + eflags |=3D (bufp->not_eol) ? REG_NOTEOL : 0; + + /* Compile fastmap if we haven't yet. */ + if (start < last_start && bufp->fastmap !=3D NULL && !bufp->fastmap_ac= curate) + re_compile_fastmap (bufp); + + if (BE (bufp->no_sub, 0)) + regs =3D NULL; + + /* We need at least 1 register. */ + if (regs =3D=3D NULL) + nregs =3D 1; + else if (BE (bufp->regs_allocated =3D=3D REGS_FIXED + && regs->num_regs <=3D bufp->re_nsub, 0)) + { + nregs =3D regs->num_regs; + if (BE (nregs < 1, 0)) + { + /* Nothing can be copied to regs. */ + regs =3D NULL; + nregs =3D 1; + } + } + else + nregs =3D bufp->re_nsub + 1; + pmatch =3D re_malloc (regmatch_t, nregs); + if (BE (pmatch =3D=3D NULL, 0)) + { + rval =3D -2; + goto out; + } + + result =3D re_search_internal (bufp, string, length, start, last_start= , stop, + nregs, pmatch, eflags); + + rval =3D 0; + + /* I hope we needn't fill their regs with -1's when no match was found= . */ + if (result !=3D REG_NOERROR) + rval =3D result =3D=3D REG_NOMATCH ? -1 : -2; + else if (regs !=3D NULL) + { + /* If caller wants register contents data back, copy them. */ + bufp->regs_allocated =3D re_copy_regs (regs, pmatch, nregs, + bufp->regs_allocated); + if (BE (bufp->regs_allocated =3D=3D REGS_UNALLOCATED, 0)) + rval =3D -2; + } + + if (BE (rval =3D=3D 0, 1)) + { + if (ret_len) + { + assert (pmatch[0].rm_so =3D=3D start); + rval =3D pmatch[0].rm_eo - start; + } + else + rval =3D pmatch[0].rm_so; + } + re_free (pmatch); + out: + lock_unlock (dfa->lock); + return rval; +} + +static unsigned +re_copy_regs (struct re_registers *regs, regmatch_t *pmatch, Idx nregs, + int regs_allocated) +{ + int rval =3D REGS_REALLOCATE; + Idx i; + Idx need_regs =3D 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 =3D=3D REGS_UNALLOCATED) + { /* No. So allocate them with malloc. */ + regs->start =3D re_malloc (regoff_t, need_regs); + if (BE (regs->start =3D=3D NULL, 0)) + return REGS_UNALLOCATED; + regs->end =3D re_malloc (regoff_t, need_regs); + if (BE (regs->end =3D=3D NULL, 0)) + { + re_free (regs->start); + return REGS_UNALLOCATED; + } + regs->num_regs =3D need_regs; + } + else if (regs_allocated =3D=3D 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 =3D re_realloc (regs->start, regoff_t, need_regs)= ; + regoff_t *new_end; + if (BE (new_start =3D=3D NULL, 0)) + return REGS_UNALLOCATED; + new_end =3D re_realloc (regs->end, regoff_t, need_regs); + if (BE (new_end =3D=3D NULL, 0)) + { + re_free (new_start); + return REGS_UNALLOCATED; + } + regs->start =3D new_start; + regs->end =3D new_end; + regs->num_regs =3D need_regs; + } + } + else + { + assert (regs_allocated =3D=3D REGS_FIXED); + /* This function may not be called with REGS_FIXED and nregs too b= ig. */ + assert (regs->num_regs >=3D nregs); + rval =3D REGS_FIXED; + } + + /* Copy the regs. */ + for (i =3D 0; i < nregs; ++i) + { + regs->start[i] =3D pmatch[i].rm_so; + regs->end[i] =3D pmatch[i].rm_eo; + } + for ( ; i < regs->num_regs; ++i) + regs->start[i] =3D regs->end[i] =3D -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 =3D=3D 0, then subsequent matches should allocate their o= wn + 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 *r= egs, + __re_size_t num_regs, regoff_t *starts, regoff_t *ends) +{ + if (num_regs) + { + bufp->regs_allocated =3D REGS_REALLOCATE; + regs->num_regs =3D num_regs; + regs->start =3D starts; + regs->end =3D ends; + } + else + { + bufp->regs_allocated =3D REGS_UNALLOCATED; + regs->num_regs =3D 0; + regs->start =3D regs->end =3D NULL; + } +} +#ifdef _LIBC +weak_alias (__re_set_registers, re_set_registers) +#endif +=0C +/* Entry points compatible with 4.2 BSD regex library. We don't define + them unless specifically requested. */ + +#if defined _REGEX_RE_COMP || defined _LIBC +int +# ifdef _LIBC +weak_function +# endif +re_exec (const char *s) +{ + return 0 =3D=3D regexec (&re_comp_buf, s, 0, NULL, 0); +} +#endif /* _REGEX_RE_COMP */ +=0C +/* Internal entry point. */ + +/* Searches for a compiled pattern PREG in the string STRING, whose + length is LENGTH. NMATCH, PMATCH, and EFLAGS have the same + meaning as with regexec. LAST_START is START + RANGE, where + START and RANGE have the same meaning as 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. + (0 <=3D LAST_START && LAST_START <=3D LENGTH) */ + +static reg_errcode_t +__attribute_warn_unused_result__ +re_search_internal (const regex_t *preg, const char *string, Idx length, + Idx start, Idx last_start, Idx stop, size_t nmatch, + regmatch_t pmatch[], int eflags) +{ + reg_errcode_t err; + const re_dfa_t *dfa =3D preg->buffer; + Idx left_lim, right_lim; + int incr; + bool fl_longest_match; + int match_kind; + Idx match_first; + Idx match_last =3D -1; + Idx extra_nmatch; + bool sb; + int ch; +#if defined _LIBC || (defined __STDC_VERSION__ && __STDC_VERSION__ >=3D = 199901L) + re_match_context_t mctx =3D { .dfa =3D dfa }; +#else + re_match_context_t mctx; +#endif + char *fastmap =3D ((preg->fastmap !=3D NULL && preg->fastmap_accurate + && start !=3D last_start && !preg->can_be_null) + ? preg->fastmap : NULL); + RE_TRANSLATE_TYPE t =3D preg->translate; + +#if !(defined _LIBC || (defined __STDC_VERSION__ && __STDC_VERSION__ >=3D= 199901L)) + memset (&mctx, '\0', sizeof (re_match_context_t)); + mctx.dfa =3D dfa; +#endif + + extra_nmatch =3D (nmatch > preg->re_nsub) ? nmatch - (preg->re_nsub + = 1) : 0; + nmatch -=3D extra_nmatch; + + /* Check if the DFA haven't been compiled. */ + if (BE (preg->used =3D=3D 0 || dfa->init_state =3D=3D NULL + || dfa->init_state_word =3D=3D NULL || dfa->init_state_nl =3D=3D NULL + || dfa->init_state_begbuf =3D=3D NULL, 0)) + return REG_NOMATCH; + +#ifdef DEBUG + /* We assume front-end functions already check them. */ + assert (0 <=3D last_start && last_start <=3D 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 =3D=3D 0 + && dfa->init_state_word->nodes.nelem =3D=3D 0 + && (dfa->init_state_nl->nodes.nelem =3D=3D 0 + || !preg->newline_anchor)) + { + if (start !=3D 0 && last_start !=3D 0) + return REG_NOMATCH; + start =3D last_start =3D 0; + } + + /* We must check the longest matching, if nmatch > 0. */ + fl_longest_match =3D (nmatch !=3D 0 || dfa->nbackref); + + err =3D re_string_allocate (&mctx.input, string, length, dfa->nodes_le= n + 1, + preg->translate, (preg->syntax & RE_ICASE) !=3D 0, + dfa); + if (BE (err !=3D REG_NOERROR, 0)) + goto free_return; + mctx.input.stop =3D stop; + mctx.input.raw_stop =3D stop; + mctx.input.newline_anchor =3D preg->newline_anchor; + + err =3D match_ctx_init (&mctx, eflags, dfa->nbackref * 2); + if (BE (err !=3D 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) + { + /* Avoid overflow. */ + if (BE ((MIN (IDX_MAX, SIZE_MAX / sizeof (re_dfastate_t *)) + <=3D mctx.input.bufs_len), 0)) + { + err =3D REG_ESPACE; + goto free_return; + } + + mctx.state_log =3D re_malloc (re_dfastate_t *, mctx.input.bufs_len= + 1); + if (BE (mctx.state_log =3D=3D NULL, 0)) + { + err =3D REG_ESPACE; + goto free_return; + } + } + else + mctx.state_log =3D NULL; + + match_first =3D start; + mctx.input.tip_context =3D (eflags & REG_NOTBOL) ? CONTEXT_BEGBUF + : CONTEXT_NEWLINE | CONTEXT_BEGBUF; + + /* Check incrementally whether the input string matches. */ + incr =3D (last_start < start) ? -1 : 1; + left_lim =3D (last_start < start) ? last_start : start; + right_lim =3D (last_start < start) ? start : last_start; + sb =3D dfa->mb_cur_max =3D=3D 1; + match_kind =3D + (fastmap + ? ((sb || !(preg->syntax & RE_ICASE || t) ? 4 : 0) + | (start <=3D last_start ? 2 : 0) + | (t !=3D NULL ? 1 : 0)) + : 8); + + for (;; match_first +=3D incr) + { + err =3D 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 =3D=3D right_lim, 0)) + { + ch =3D match_first >=3D 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 >=3D left_lim) + { + ch =3D match_first >=3D 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. */ + __re_size_t offset =3D match_first - mctx.input.raw_mbs_idx; + if (BE (offset >=3D (__re_size_t) mctx.input.valid_raw_len, 0)) + { + err =3D re_string_reconstruct (&mctx.input, match_first, + eflags); + if (BE (err !=3D REG_NOERROR, 0)) + goto free_return; + + offset =3D 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 =3D (match_first >=3D length + ? 0 : re_string_byte_at (&mctx.input, offset)); + if (fastmap[ch]) + break; + match_first +=3D incr; + if (match_first < left_lim || match_first > right_lim) + { + err =3D 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 =3D re_string_reconstruct (&mctx.input, match_first, eflags); + if (BE (err !=3D 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 =3D mctx.nbkref_ents =3D mctx.max_mb_elem_len =3D= 0; + match_last =3D check_matching (&mctx, fl_longest_match, + start <=3D last_start ? &match_first : NULL); + if (match_last !=3D -1) + { + if (BE (match_last =3D=3D -2, 0)) + { + err =3D REG_ESPACE; + goto free_return; + } + else + { + mctx.match_last =3D match_last; + if ((!preg->no_sub && nmatch > 1) || dfa->nbackref) + { + re_dfastate_t *pstate =3D mctx.state_log[match_last]; + mctx.last_node =3D check_halt_state_context (&mctx, pstate, + match_last); + } + if ((!preg->no_sub && nmatch > 1 && dfa->has_plural_match) + || dfa->nbackref) + { + err =3D prune_impossible_nodes (&mctx); + if (err =3D=3D REG_NOERROR) + break; + if (BE (err !=3D REG_NOMATCH, 0)) + goto free_return; + match_last =3D -1; + } + else + break; /* We found a match. */ + } + } + + match_ctx_clean (&mctx); + } + +#ifdef DEBUG + assert (match_last !=3D -1); + assert (err =3D=3D REG_NOERROR); +#endif + + /* Set pmatch[] if we need. */ + if (nmatch > 0) + { + Idx reg_idx; + + /* Initialize registers. */ + for (reg_idx =3D 1; reg_idx < nmatch; ++reg_idx) + pmatch[reg_idx].rm_so =3D pmatch[reg_idx].rm_eo =3D -1; + + /* Set the points where matching start/end. */ + pmatch[0].rm_so =3D 0; + pmatch[0].rm_eo =3D mctx.match_last; + /* FIXME: This function should fail if mctx.match_last exceeds + the maximum possible regoff_t value. We need a new error + code REG_OVERFLOW. */ + + if (!preg->no_sub && nmatch > 1) + { + err =3D set_regs (preg, &mctx, nmatch, pmatch, + dfa->has_plural_match && dfa->nbackref > 0); + if (BE (err !=3D REG_NOERROR, 0)) + goto free_return; + } + + /* At last, add the offset to each register, since we slid + the buffers so that we could assume that the matching starts + from 0. */ + for (reg_idx =3D 0; reg_idx < nmatch; ++reg_idx) + if (pmatch[reg_idx].rm_so !=3D -1) + { +#ifdef RE_ENABLE_I18N + if (BE (mctx.input.offsets_needed !=3D 0, 0)) + { + pmatch[reg_idx].rm_so =3D + (pmatch[reg_idx].rm_so =3D=3D mctx.input.valid_len + ? mctx.input.valid_raw_len + : mctx.input.offsets[pmatch[reg_idx].rm_so]); + pmatch[reg_idx].rm_eo =3D + (pmatch[reg_idx].rm_eo =3D=3D mctx.input.valid_len + ? mctx.input.valid_raw_len + : mctx.input.offsets[pmatch[reg_idx].rm_eo]); + } +#else + assert (mctx.input.offsets_needed =3D=3D 0); +#endif + pmatch[reg_idx].rm_so +=3D match_first; + pmatch[reg_idx].rm_eo +=3D match_first; + } + for (reg_idx =3D 0; reg_idx < extra_nmatch; ++reg_idx) + { + pmatch[nmatch + reg_idx].rm_so =3D -1; + pmatch[nmatch + reg_idx].rm_eo =3D -1; + } + + if (dfa->subexp_map) + for (reg_idx =3D 0; reg_idx + 1 < nmatch; reg_idx++) + if (dfa->subexp_map[reg_idx] !=3D reg_idx) + { + pmatch[reg_idx + 1].rm_so + =3D pmatch[dfa->subexp_map[reg_idx] + 1].rm_so; + pmatch[reg_idx + 1].rm_eo + =3D 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 +__attribute_warn_unused_result__ +prune_impossible_nodes (re_match_context_t *mctx) +{ + const re_dfa_t *const dfa =3D mctx->dfa; + Idx halt_node, match_last; + reg_errcode_t ret; + re_dfastate_t **sifted_states; + re_dfastate_t **lim_states =3D NULL; + re_sift_context_t sctx; +#ifdef DEBUG + assert (mctx->state_log !=3D NULL); +#endif + match_last =3D mctx->match_last; + halt_node =3D mctx->last_node; + + /* Avoid overflow. */ + if (BE (MIN (IDX_MAX, SIZE_MAX / sizeof (re_dfastate_t *)) <=3D match_= last, 0)) + return REG_ESPACE; + + sifted_states =3D re_malloc (re_dfastate_t *, match_last + 1); + if (BE (sifted_states =3D=3D NULL, 0)) + { + ret =3D REG_ESPACE; + goto free_return; + } + if (dfa->nbackref) + { + lim_states =3D re_malloc (re_dfastate_t *, match_last + 1); + if (BE (lim_states =3D=3D NULL, 0)) + { + ret =3D 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 =3D sift_states_backward (mctx, &sctx); + re_node_set_free (&sctx.limits); + if (BE (ret !=3D REG_NOERROR, 0)) + goto free_return; + if (sifted_states[0] !=3D NULL || lim_states[0] !=3D NULL) + break; + do + { + --match_last; + if (match_last < 0) + { + ret =3D REG_NOMATCH; + goto free_return; + } + } while (mctx->state_log[match_last] =3D=3D NULL + || !mctx->state_log[match_last]->halt); + halt_node =3D check_halt_state_context (mctx, + mctx->state_log[match_last], + match_last); + } + ret =3D merge_state_array (dfa, sifted_states, lim_states, + match_last + 1); + re_free (lim_states); + lim_states =3D NULL; + if (BE (ret !=3D REG_NOERROR, 0)) + goto free_return; + } + else + { + sift_ctx_init (&sctx, sifted_states, lim_states, halt_node, match_= last); + ret =3D sift_states_backward (mctx, &sctx); + re_node_set_free (&sctx.limits); + if (BE (ret !=3D REG_NOERROR, 0)) + goto free_return; + if (sifted_states[0] =3D=3D NULL) + { + ret =3D REG_NOMATCH; + goto free_return; + } + } + re_free (mctx->state_log); + mctx->state_log =3D sifted_states; + sifted_states =3D NULL; + mctx->last_node =3D halt_node; + mctx->match_last =3D match_last; + ret =3D 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)) +acquire_init_state_context (reg_errcode_t *err, const re_match_context_t= *mctx, + Idx idx) +{ + const re_dfa_t *const dfa =3D mctx->dfa; + if (dfa->init_state->has_constraint) + { + unsigned int context; + context =3D re_string_context_at (&mctx->input, idx - 1, mctx->efl= ags); + 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 (contex= t)) + 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 + there is no match, and 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 assumes that the matching starts from the curre= nt + index of the buffer. */ + +static Idx +__attribute_warn_unused_result__ +check_matching (re_match_context_t *mctx, bool fl_longest_match, + Idx *p_match_first) +{ + const re_dfa_t *const dfa =3D mctx->dfa; + reg_errcode_t err; + Idx match =3D 0; + Idx match_last =3D -1; + Idx cur_str_idx =3D re_string_cur_idx (&mctx->input); + re_dfastate_t *cur_state; + bool at_init_state =3D p_match_first !=3D NULL; + Idx next_start_idx =3D cur_str_idx; + + err =3D REG_NOERROR; + cur_state =3D acquire_init_state_context (&err, mctx, cur_str_idx); + /* An initial state must not be NULL (invalid). */ + if (BE (cur_state =3D=3D NULL, 0)) + { + assert (err =3D=3D REG_ESPACE); + return -2; + } + + if (mctx->state_log !=3D NULL) + { + mctx->state_log[cur_str_idx] =3D cur_state; + + /* Check OP_OPEN_SUBEXP in the initial state in case that we use t= hem + later. E.g. Processing back references. */ + if (BE (dfa->nbackref, 0)) + { + at_init_state =3D false; + err =3D check_subexp_matching_top (mctx, &cur_state->nodes, 0); + if (BE (err !=3D REG_NOERROR, 0)) + return err; + + if (cur_state->has_backref) + { + err =3D transit_state_bkref (mctx, &cur_state->nodes); + if (BE (err !=3D 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 =3D cur_str_idx; + match =3D 1; + } + } + } + + while (!re_string_eoi (&mctx->input)) + { + re_dfastate_t *old_state =3D cur_state; + Idx next_char_idx =3D re_string_cur_idx (&mctx->input) + 1; + + if ((BE (next_char_idx >=3D mctx->input.bufs_len, 0) + && mctx->input.bufs_len < mctx->input.len) + || (BE (next_char_idx >=3D mctx->input.valid_len, 0) + && mctx->input.valid_len < mctx->input.len)) + { + err =3D extend_buffers (mctx, next_char_idx + 1); + if (BE (err !=3D REG_NOERROR, 0)) + { + assert (err =3D=3D REG_ESPACE); + return -2; + } + } + + cur_state =3D transit_state (&err, mctx, cur_state); + if (mctx->state_log !=3D NULL) + cur_state =3D merge_state_with_log (&err, mctx, cur_state); + + if (cur_state =3D=3D 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 !=3D REG_NOERROR, 0)) + return -2; + + if (mctx->state_log =3D=3D NULL + || (match && !fl_longest_match) + || (cur_state =3D find_recover_state (&err, mctx)) =3D=3D NULL) + break; + } + + if (BE (at_init_state, 0)) + { + if (old_state =3D=3D cur_state) + next_start_idx =3D next_char_idx; + else + at_init_state =3D false; + } + + 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 =3D re_string_cur_idx (&mctx->input); + match =3D 1; + + /* We found a match, do not modify match_first below. */ + p_match_first =3D NULL; + if (!fl_longest_match) + break; + } + } + } + + if (p_match_first) + *p_match_first +=3D next_start_idx; + + return match_last; +} + +/* Check NODE match the current context. */ + +static bool +check_halt_node_context (const re_dfa_t *dfa, Idx node, unsigned int con= text) +{ + re_token_type_t type =3D dfa->nodes[node].type; + unsigned int constraint =3D dfa->nodes[node].constraint; + if (type !=3D END_OF_RE) + return false; + if (!constraint) + return true; + if (NOT_SATISFY_NEXT_CONSTRAINT (constraint, context)) + return false; + return true; +} + +/* 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 Idx +check_halt_state_context (const re_match_context_t *mctx, + const re_dfastate_t *state, Idx idx) +{ + Idx i; + unsigned int context; +#ifdef DEBUG + assert (state->halt); +#endif + context =3D re_string_context_at (&mctx->input, idx, mctx->eflags); + for (i =3D 0; i < state->nodes.nelem; ++i) + if (check_halt_node_context (mctx->dfa, state->nodes.elems[i], conte= xt)) + 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 Idx +proceed_next_node (const re_match_context_t *mctx, Idx nregs, regmatch_t= *regs, + Idx *pidx, Idx node, re_node_set *eps_via_nodes, + struct re_fail_stack_t *fs) +{ + const re_dfa_t *const dfa =3D mctx->dfa; + Idx i; + bool ok; + if (IS_EPSILON_NODE (dfa->nodes[node].type)) + { + re_node_set *cur_nodes =3D &mctx->state_log[*pidx]->nodes; + re_node_set *edests =3D &dfa->edests[node]; + Idx dest_node; + ok =3D re_node_set_insert (eps_via_nodes, node); + if (BE (! ok, 0)) + return -2; + /* Pick up a valid destination, or return -1 if none + is found. */ + for (dest_node =3D -1, i =3D 0; i < edests->nelem; ++i) + { + Idx candidate =3D edests->elems[i]; + if (!re_node_set_contains (cur_nodes, candidate)) + continue; + if (dest_node =3D=3D -1) + dest_node =3D candidate; + + else + { + /* In order to avoid infinite loop like "(a*)*", return the secon= d + 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 stac= k. */ + else if (fs !=3D 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 + { + Idx naccepted =3D 0; + re_token_type_t type =3D dfa->nodes[node].type; + +#ifdef RE_ENABLE_I18N + if (dfa->nodes[node].accept_mb) + naccepted =3D check_node_accept_bytes (dfa, node, &mctx->input, *pidx); + else +#endif /* RE_ENABLE_I18N */ + if (type =3D=3D OP_BACK_REF) + { + Idx subexp_idx =3D dfa->nodes[node].opr.idx + 1; + naccepted =3D regs[subexp_idx].rm_eo - regs[subexp_idx].rm_so; + if (fs !=3D NULL) + { + if (regs[subexp_idx].rm_so =3D=3D -1 || regs[subexp_idx].rm_eo =3D= =3D -1) + return -1; + else if (naccepted) + { + char *buf =3D (char *) re_string_get_buffer (&mctx->input); + if (memcmp (buf + regs[subexp_idx].rm_so, buf + *pidx, + naccepted) !=3D 0) + return -1; + } + } + + if (naccepted =3D=3D 0) + { + Idx dest_node; + ok =3D re_node_set_insert (eps_via_nodes, node); + if (BE (! ok, 0)) + return -2; + dest_node =3D dfa->edests[node].elems[0]; + if (re_node_set_contains (&mctx->state_log[*pidx]->nodes, + dest_node)) + return dest_node; + } + } + + if (naccepted !=3D 0 + || check_node_accept (mctx, dfa->nodes + node, *pidx)) + { + Idx dest_node =3D dfa->nexts[node]; + *pidx =3D (naccepted =3D=3D 0) ? *pidx + 1 : *pidx + naccepted; + if (fs && (*pidx > mctx->match_last || mctx->state_log[*pidx] =3D=3D = 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 +__attribute_warn_unused_result__ +push_fail_stack (struct re_fail_stack_t *fs, Idx str_idx, Idx dest_node, + Idx nregs, regmatch_t *regs, re_node_set *eps_via_nodes) +{ + reg_errcode_t err; + Idx num =3D fs->num++; + if (fs->num =3D=3D fs->alloc) + { + struct re_fail_stack_ent_t *new_array; + new_array =3D re_realloc (fs->stack, struct re_fail_stack_ent_t, + fs->alloc * 2); + if (new_array =3D=3D NULL) + return REG_ESPACE; + fs->alloc *=3D 2; + fs->stack =3D new_array; + } + fs->stack[num].idx =3D str_idx; + fs->stack[num].node =3D dest_node; + fs->stack[num].regs =3D re_malloc (regmatch_t, nregs); + if (fs->stack[num].regs =3D=3D NULL) + return REG_ESPACE; + memcpy (fs->stack[num].regs, regs, sizeof (regmatch_t) * nregs); + err =3D re_node_set_init_copy (&fs->stack[num].eps_via_nodes, eps_via_= nodes); + return err; +} + +static Idx +pop_fail_stack (struct re_fail_stack_t *fs, Idx *pidx, Idx nregs, + regmatch_t *regs, re_node_set *eps_via_nodes) +{ + Idx num =3D --fs->num; + assert (num >=3D 0); + *pidx =3D 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 =3D fs->stack[num].eps_via_nodes; + return fs->stack[num].node; +} + +/* Set the positions where the subexpressions are starts/ends to registe= rs + PMATCH. + Note: We assume that pmatch[0] is already set, and + pmatch[i].rm_so =3D=3D pmatch[i].rm_eo =3D=3D -1 for 0 < i < nmatch. = */ + +static reg_errcode_t +__attribute_warn_unused_result__ +set_regs (const regex_t *preg, const re_match_context_t *mctx, size_t nm= atch, + regmatch_t *pmatch, bool fl_backtrack) +{ + const re_dfa_t *dfa =3D preg->buffer; + Idx idx, cur_node; + re_node_set eps_via_nodes; + struct re_fail_stack_t *fs; + struct re_fail_stack_t fs_body =3D { 0, 2, NULL }; + regmatch_t *prev_idx_match; + bool prev_idx_match_malloced =3D false; + +#ifdef DEBUG + assert (nmatch > 1); + assert (mctx->state_log !=3D NULL); +#endif + if (fl_backtrack) + { + fs =3D &fs_body; + fs->stack =3D re_malloc (struct re_fail_stack_ent_t, fs->alloc); + if (fs->stack =3D=3D NULL) + return REG_ESPACE; + } + else + fs =3D NULL; + + cur_node =3D dfa->init_node; + re_node_set_init_empty (&eps_via_nodes); + + if (__libc_use_alloca (nmatch * sizeof (regmatch_t))) + prev_idx_match =3D (regmatch_t *) alloca (nmatch * sizeof (regmatch_= t)); + else + { + prev_idx_match =3D re_malloc (regmatch_t, nmatch); + if (prev_idx_match =3D=3D NULL) + { + free_fail_stack_return (fs); + return REG_ESPACE; + } + prev_idx_match_malloced =3D true; + } + memcpy (prev_idx_match, pmatch, sizeof (regmatch_t) * nmatch); + + for (idx =3D pmatch[0].rm_so; idx <=3D pmatch[0].rm_eo ;) + { + update_regs (dfa, pmatch, prev_idx_match, cur_node, idx, nmatch); + + if (idx =3D=3D pmatch[0].rm_eo && cur_node =3D=3D mctx->last_node) + { + Idx reg_idx; + if (fs) + { + for (reg_idx =3D 0; reg_idx < nmatch; ++reg_idx) + if (pmatch[reg_idx].rm_so > -1 && pmatch[reg_idx].rm_eo =3D=3D -1) + break; + if (reg_idx =3D=3D 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 =3D 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 =3D proceed_next_node (mctx, nmatch, pmatch, &idx, cur_no= de, + &eps_via_nodes, fs); + + if (BE (cur_node < 0, 0)) + { + if (BE (cur_node =3D=3D -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 =3D 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 +free_fail_stack_return (struct re_fail_stack_t *fs) +{ + if (fs) + { + Idx fs_idx; + for (fs_idx =3D 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 +update_regs (const re_dfa_t *dfa, regmatch_t *pmatch, + regmatch_t *prev_idx_match, Idx cur_node, Idx cur_idx, Idx nmatch) +{ + int type =3D dfa->nodes[cur_node].type; + if (type =3D=3D OP_OPEN_SUBEXP) + { + Idx reg_num =3D 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 =3D cur_idx; + pmatch[reg_num].rm_eo =3D -1; + } + } + else if (type =3D=3D OP_CLOSE_SUBEXP) + { + Idx reg_num =3D 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 =3D 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 !=3D -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 =3D 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 =3D=3D 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 <=3D 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 <=3D 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) !=3D NULL && re_node_set_contains (&(state)->nodes, node)) + +static reg_errcode_t +sift_states_backward (const re_match_context_t *mctx, re_sift_context_t = *sctx) +{ + reg_errcode_t err; + int null_cnt =3D 0; + Idx str_idx =3D sctx->last_str_idx; + re_node_set cur_dest; + +#ifdef DEBUG + assert (mctx->state_log !=3D NULL && mctx->state_log[str_idx] !=3D NUL= L); +#endif + + /* Build sifted state_log[str_idx]. It has the nodes which can epsilo= n + transit to the last_node and the last_node itself. */ + err =3D re_node_set_init_1 (&cur_dest, sctx->last_node); + if (BE (err !=3D REG_NOERROR, 0)) + return err; + err =3D update_cur_sifted_state (mctx, sctx, str_idx, &cur_dest); + if (BE (err !=3D REG_NOERROR, 0)) + goto free_return; + + /* Then check each states in the state_log. */ + while (str_idx > 0) + { + /* Update counters. */ + null_cnt =3D (sctx->sifted_states[str_idx] =3D=3D 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 =3D build_sifted_states (mctx, sctx, str_idx, &cur_dest); + if (BE (err !=3D 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 =3D update_cur_sifted_state (mctx, sctx, str_idx, &cur_dest); + if (BE (err !=3D REG_NOERROR, 0)) + goto free_return; + } + err =3D REG_NOERROR; + free_return: + re_node_set_free (&cur_dest); + return err; +} + +static reg_errcode_t +__attribute_warn_unused_result__ +build_sifted_states (const re_match_context_t *mctx, re_sift_context_t *= sctx, + Idx str_idx, re_node_set *cur_dest) +{ + const re_dfa_t *const dfa =3D mctx->dfa; + const re_node_set *cur_src =3D &mctx->state_log[str_idx]->non_eps_node= s; + Idx 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 =3D 0; i < cur_src->nelem; i++) + { + Idx prev_node =3D cur_src->elems[i]; + int naccepted =3D 0; + bool ok; + +#ifdef DEBUG + re_token_type_t type =3D 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 =3D 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 =3D 1; + + if (naccepted =3D=3D 0) + continue; + + if (sctx->limits.nelem) + { + Idx to_idx =3D str_idx + naccepted; + if (check_dst_limits (mctx, &sctx->limits, + dfa->nexts[prev_node], to_idx, + prev_node, str_idx)) + continue; + } + ok =3D re_node_set_insert (cur_dest, prev_node); + if (BE (! ok, 0)) + return REG_ESPACE; + } + + return REG_NOERROR; +} + +/* Helper functions. */ + +static reg_errcode_t +clean_state_log_if_needed (re_match_context_t *mctx, Idx next_state_log_= idx) +{ + Idx top =3D mctx->state_log_top; + + if ((next_state_log_idx >=3D mctx->input.bufs_len + && mctx->input.bufs_len < mctx->input.len) + || (next_state_log_idx >=3D mctx->input.valid_len + && mctx->input.valid_len < mctx->input.len)) + { + reg_errcode_t err; + err =3D extend_buffers (mctx, next_state_log_idx + 1); + if (BE (err !=3D 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 =3D next_state_log_idx; + } + return REG_NOERROR; +} + +static reg_errcode_t +merge_state_array (const re_dfa_t *dfa, re_dfastate_t **dst, + re_dfastate_t **src, Idx num) +{ + Idx st_idx; + reg_errcode_t err; + for (st_idx =3D 0; st_idx < num; ++st_idx) + { + if (dst[st_idx] =3D=3D NULL) + dst[st_idx] =3D src[st_idx]; + else if (src[st_idx] !=3D NULL) + { + re_node_set merged_set; + err =3D re_node_set_init_union (&merged_set, &dst[st_idx]->nodes, + &src[st_idx]->nodes); + if (BE (err !=3D REG_NOERROR, 0)) + return err; + dst[st_idx] =3D re_acquire_state (&err, dfa, &merged_set); + re_node_set_free (&merged_set); + if (BE (err !=3D REG_NOERROR, 0)) + return err; + } + } + return REG_NOERROR; +} + +static reg_errcode_t +update_cur_sifted_state (const re_match_context_t *mctx, + re_sift_context_t *sctx, Idx str_idx, + re_node_set *dest_nodes) +{ + const re_dfa_t *const dfa =3D mctx->dfa; + reg_errcode_t err =3D REG_NOERROR; + const re_node_set *candidates; + candidates =3D ((mctx->state_log[str_idx] =3D=3D NULL) ? NULL + : &mctx->state_log[str_idx]->nodes); + + if (dest_nodes->nelem =3D=3D 0) + sctx->sifted_states[str_idx] =3D NULL; + else + { + if (candidates) + { + /* At first, add the nodes which can epsilon transit to a node in + DEST_NODE. */ + err =3D add_epsilon_src_nodes (dfa, dest_nodes, candidates); + if (BE (err !=3D REG_NOERROR, 0)) + return err; + + /* Then, check the limitations in the current sift_context. */ + if (sctx->limits.nelem) + { + err =3D check_subexp_limits (dfa, dest_nodes, candidates, &sctx->= limits, + mctx->bkref_ents, str_idx); + if (BE (err !=3D REG_NOERROR, 0)) + return err; + } + } + + sctx->sifted_states[str_idx] =3D re_acquire_state (&err, dfa, dest= _nodes); + if (BE (err !=3D REG_NOERROR, 0)) + return err; + } + + if (candidates && mctx->state_log[str_idx]->has_backref) + { + err =3D sift_states_bkref (mctx, sctx, str_idx, candidates); + if (BE (err !=3D REG_NOERROR, 0)) + return err; + } + return REG_NOERROR; +} + +static reg_errcode_t +__attribute_warn_unused_result__ +add_epsilon_src_nodes (const re_dfa_t *dfa, re_node_set *dest_nodes, + const re_node_set *candidates) +{ + reg_errcode_t err =3D REG_NOERROR; + Idx i; + + re_dfastate_t *state =3D re_acquire_state (&err, dfa, dest_nodes); + if (BE (err !=3D REG_NOERROR, 0)) + return err; + + if (!state->inveclosure.alloc) + { + err =3D re_node_set_alloc (&state->inveclosure, dest_nodes->nelem)= ; + if (BE (err !=3D REG_NOERROR, 0)) + return REG_ESPACE; + for (i =3D 0; i < dest_nodes->nelem; i++) + { + err =3D re_node_set_merge (&state->inveclosure, + dfa->inveclosures + dest_nodes->elems[i]); + if (BE (err !=3D REG_NOERROR, 0)) + return REG_ESPACE; + } + } + return re_node_set_add_intersect (dest_nodes, candidates, + &state->inveclosure); +} + +static reg_errcode_t +sub_epsilon_src_nodes (const re_dfa_t *dfa, Idx node, re_node_set *dest_= nodes, + const re_node_set *candidates) +{ + Idx ecl_idx; + reg_errcode_t err; + re_node_set *inv_eclosure =3D dfa->inveclosures + node; + re_node_set except_nodes; + re_node_set_init_empty (&except_nodes); + for (ecl_idx =3D 0; ecl_idx < inv_eclosure->nelem; ++ecl_idx) + { + Idx cur_node =3D inv_eclosure->elems[ecl_idx]; + if (cur_node =3D=3D node) + continue; + if (IS_EPSILON_NODE (dfa->nodes[cur_node].type)) + { + Idx edst1 =3D dfa->edests[cur_node].elems[0]; + Idx edst2 =3D ((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 =3D re_node_set_add_intersect (&except_nodes, candidates, + dfa->inveclosures + cur_node); + if (BE (err !=3D REG_NOERROR, 0)) + { + re_node_set_free (&except_nodes); + return err; + } + } + } + } + for (ecl_idx =3D 0; ecl_idx < inv_eclosure->nelem; ++ecl_idx) + { + Idx cur_node =3D inv_eclosure->elems[ecl_idx]; + if (!re_node_set_contains (&except_nodes, cur_node)) + { + Idx idx =3D 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 bool +check_dst_limits (const re_match_context_t *mctx, const re_node_set *lim= its, + Idx dst_node, Idx dst_idx, Idx src_node, Idx src_idx) +{ + const re_dfa_t *const dfa =3D mctx->dfa; + Idx lim_idx, src_pos, dst_pos; + + Idx dst_bkref_idx =3D search_cur_bkref_entry (mctx, dst_idx); + Idx src_bkref_idx =3D search_cur_bkref_entry (mctx, src_idx); + for (lim_idx =3D 0; lim_idx < limits->nelem; ++lim_idx) + { + Idx subexp_idx; + struct re_backref_cache_entry *ent; + ent =3D mctx->bkref_ents + limits->elems[lim_idx]; + subexp_idx =3D dfa->nodes[ent->node].opr.idx; + + dst_pos =3D check_dst_limits_calc_pos (mctx, limits->elems[lim_idx= ], + subexp_idx, dst_node, dst_idx, + dst_bkref_idx); + src_pos =3D check_dst_limits_calc_pos (mctx, limits->elems[lim_idx= ], + subexp_idx, src_node, src_idx, + src_bkref_idx); + + /* In case of: + ( ) + ( ) + ( ) */ + if (src_pos =3D=3D dst_pos) + continue; /* This is unrelated limitation. */ + else + return true; + } + return false; +} + +static int +check_dst_limits_calc_pos_1 (const re_match_context_t *mctx, int boundar= ies, + Idx subexp_idx, Idx from_node, Idx bkref_idx) +{ + const re_dfa_t *const dfa =3D mctx->dfa; + const re_node_set *eclosures =3D dfa->eclosures + from_node; + Idx node_idx; + + /* Else, we are on the boundary: examine the nodes on the epsilon + closure. */ + for (node_idx =3D 0; node_idx < eclosures->nelem; ++node_idx) + { + Idx node =3D eclosures->elems[node_idx]; + switch (dfa->nodes[node].type) + { + case OP_BACK_REF: + if (bkref_idx !=3D -1) + { + struct re_backref_cache_entry *ent =3D mctx->bkref_ents + bkref_i= dx; + do + { + Idx dst; + int cpos; + + if (ent->node !=3D 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 =3D dfa->edests[node].elems[0]; + if (dst =3D=3D from_node) + { + if (boundaries & 1) + return -1; + else /* if (boundaries & 2) */ + return 0; + } + + cpos =3D + check_dst_limits_calc_pos_1 (mctx, boundaries, subexp_idx, + dst, bkref_idx); + if (cpos =3D=3D -1 /* && (boundaries & 1) */) + return -1; + if (cpos =3D=3D 0 && (boundaries & 2)) + return 0; + + if (subexp_idx < BITSET_WORD_BITS) + ent->eps_reachable_subexps_map + &=3D ~((bitset_word_t) 1 << subexp_idx); + } + while (ent++->more); + } + break; + + case OP_OPEN_SUBEXP: + if ((boundaries & 1) && subexp_idx =3D=3D dfa->nodes[node].opr.idx) + return -1; + break; + + case OP_CLOSE_SUBEXP: + if ((boundaries & 2) && subexp_idx =3D=3D dfa->nodes[node].opr.idx) + return 0; + break; + + default: + break; + } + } + + return (boundaries & 2) ? 1 : 0; +} + +static int +check_dst_limits_calc_pos (const re_match_context_t *mctx, Idx limit, + Idx subexp_idx, Idx from_node, Idx str_idx, + Idx bkref_idx) +{ + struct re_backref_cache_entry *lim =3D 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 =3D (str_idx =3D=3D lim->subexp_from); + boundaries |=3D (str_idx =3D=3D lim->subexp_to) << 1; + if (boundaries =3D=3D 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 +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, Idx str_idx) +{ + reg_errcode_t err; + Idx node_idx, lim_idx; + + for (lim_idx =3D 0; lim_idx < limits->nelem; ++lim_idx) + { + Idx subexp_idx; + struct re_backref_cache_entry *ent; + ent =3D bkref_ents + limits->elems[lim_idx]; + + if (str_idx <=3D ent->subexp_from || ent->str_idx < str_idx) + continue; /* This is unrelated limitation. */ + + subexp_idx =3D dfa->nodes[ent->node].opr.idx; + if (ent->subexp_to =3D=3D str_idx) + { + Idx ops_node =3D -1; + Idx cls_node =3D -1; + for (node_idx =3D 0; node_idx < dest_nodes->nelem; ++node_idx) + { + Idx node =3D dest_nodes->elems[node_idx]; + re_token_type_t type =3D dfa->nodes[node].type; + if (type =3D=3D OP_OPEN_SUBEXP + && subexp_idx =3D=3D dfa->nodes[node].opr.idx) + ops_node =3D node; + else if (type =3D=3D OP_CLOSE_SUBEXP + && subexp_idx =3D=3D dfa->nodes[node].opr.idx) + cls_node =3D node; + } + + /* Check the limitation of the open subexpression. */ + /* Note that (ent->subexp_to =3D str_idx !=3D ent->subexp_from). */ + if (ops_node >=3D 0) + { + err =3D sub_epsilon_src_nodes (dfa, ops_node, dest_nodes, + candidates); + if (BE (err !=3D REG_NOERROR, 0)) + return err; + } + + /* Check the limitation of the close subexpression. */ + if (cls_node >=3D 0) + for (node_idx =3D 0; node_idx < dest_nodes->nelem; ++node_idx) + { + Idx node =3D 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 =3D sub_epsilon_src_nodes (dfa, node, dest_nodes, + candidates); + if (BE (err !=3D REG_NOERROR, 0)) + return err; + --node_idx; + } + } + } + else /* (ent->subexp_to !=3D str_idx) */ + { + for (node_idx =3D 0; node_idx < dest_nodes->nelem; ++node_idx) + { + Idx node =3D dest_nodes->elems[node_idx]; + re_token_type_t type =3D dfa->nodes[node].type; + if (type =3D=3D OP_CLOSE_SUBEXP || type =3D=3D OP_OPEN_SUBEXP) + { + if (subexp_idx !=3D dfa->nodes[node].opr.idx) + continue; + /* It is against this limitation. + Remove it form the current sifted state. */ + err =3D sub_epsilon_src_nodes (dfa, node, dest_nodes, + candidates); + if (BE (err !=3D REG_NOERROR, 0)) + return err; + } + } + } + } + return REG_NOERROR; +} + +static reg_errcode_t +__attribute_warn_unused_result__ +sift_states_bkref (const re_match_context_t *mctx, re_sift_context_t *sc= tx, + Idx str_idx, const re_node_set *candidates) +{ + const re_dfa_t *const dfa =3D mctx->dfa; + reg_errcode_t err; + Idx node_idx, node; + re_sift_context_t local_sctx; + Idx first_idx =3D search_cur_bkref_entry (mctx, str_idx); + + if (first_idx =3D=3D -1) + return REG_NOERROR; + + local_sctx.sifted_states =3D NULL; /* Mark that it hasn't been initial= ized. */ + + for (node_idx =3D 0; node_idx < candidates->nelem; ++node_idx) + { + Idx enabled_idx; + re_token_type_t type; + struct re_backref_cache_entry *entry; + node =3D candidates->elems[node_idx]; + type =3D dfa->nodes[node].type; + /* Avoid infinite loop for the REs like "()\1+". */ + if (node =3D=3D sctx->last_node && str_idx =3D=3D sctx->last_str_i= dx) + continue; + if (type !=3D OP_BACK_REF) + continue; + + entry =3D mctx->bkref_ents + first_idx; + enabled_idx =3D first_idx; + do + { + Idx subexp_len; + Idx to_idx; + Idx dst_node; + bool ok; + re_dfastate_t *cur_state; + + if (entry->node !=3D node) + continue; + subexp_len =3D entry->subexp_to - entry->subexp_from; + to_idx =3D str_idx + subexp_len; + dst_node =3D (subexp_len ? dfa->nexts[node] + : dfa->edests[node].elems[0]); + + if (to_idx > sctx->last_str_idx + || sctx->sifted_states[to_idx] =3D=3D 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 =3D=3D NULL) + { + local_sctx =3D *sctx; + err =3D re_node_set_init_copy (&local_sctx.limits, &sctx->limits)= ; + if (BE (err !=3D REG_NOERROR, 0)) + goto free_return; + } + local_sctx.last_node =3D node; + local_sctx.last_str_idx =3D str_idx; + ok =3D re_node_set_insert (&local_sctx.limits, enabled_idx); + if (BE (! ok, 0)) + { + err =3D REG_ESPACE; + goto free_return; + } + cur_state =3D local_sctx.sifted_states[str_idx]; + err =3D sift_states_backward (mctx, &local_sctx); + if (BE (err !=3D REG_NOERROR, 0)) + goto free_return; + if (sctx->limited_states !=3D NULL) + { + err =3D merge_state_array (dfa, sctx->limited_states, + local_sctx.sifted_states, + str_idx + 1); + if (BE (err !=3D REG_NOERROR, 0)) + goto free_return; + } + local_sctx.sifted_states[str_idx] =3D cur_state; + re_node_set_remove (&local_sctx.limits, enabled_idx); + + /* mctx->bkref_ents may have changed, reload the pointer. */ + entry =3D mctx->bkref_ents + enabled_idx; + } + while (enabled_idx++, entry++->more); + } + err =3D REG_NOERROR; + free_return: + if (local_sctx.sifted_states !=3D NULL) + { + re_node_set_free (&local_sctx.limits); + } + + return err; +} + + +#ifdef RE_ENABLE_I18N +static int +sift_states_iter_mb (const re_match_context_t *mctx, re_sift_context_t *= sctx, + Idx node_idx, Idx str_idx, Idx max_str_idx) +{ + const re_dfa_t *const dfa =3D mctx->dfa; + int naccepted; + /* Check the node can accept "multi byte". */ + naccepted =3D check_node_accept_bytes (dfa, node_idx, &mctx->input, st= r_idx); + if (naccepted > 0 && str_idx + naccepted <=3D 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 =3D 0; + /* Otherwise, it is sure that the node could accept + 'naccepted' bytes input. */ + return naccepted; +} +#endif /* RE_ENABLE_I18N */ + +=0C +/* Functions for state transition. */ + +/* Return the next state to which the current state STATE will transit b= y + 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 * +__attribute_warn_unused_result__ +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 =3D transit_state_mb (mctx, state); + if (BE (*err !=3D 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 =3D re_string_fetch_byte (&mctx->input); + for (;;) + { + trtable =3D state->trtable; + if (BE (trtable !=3D NULL, 1)) + return trtable[ch]; + + trtable =3D state->word_trtable; + if (BE (trtable !=3D NULL, 1)) + { + unsigned int context; + context + =3D 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 =3D REG_ESPACE; + return NULL; + } + + /* Retry, we now have a transition table. */ + } +} + +/* Update the state_log if we need */ +static re_dfastate_t * +merge_state_with_log (reg_errcode_t *err, re_match_context_t *mctx, + re_dfastate_t *next_state) +{ + const re_dfa_t *const dfa =3D mctx->dfa; + Idx cur_idx =3D re_string_cur_idx (&mctx->input); + + if (cur_idx > mctx->state_log_top) + { + mctx->state_log[cur_idx] =3D next_state; + mctx->state_log_top =3D cur_idx; + } + else if (mctx->state_log[cur_idx] =3D=3D 0) + { + mctx->state_log[cur_idx] =3D next_state; + } + else + { + re_dfastate_t *pstate; + unsigned int context; + re_node_set next_nodes, *log_nodes, *table_nodes =3D NULL; + /* If (state_log[cur_idx] !=3D 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 =3D mctx->state_log[cur_idx]; + log_nodes =3D pstate->entrance_nodes; + if (next_state !=3D NULL) + { + table_nodes =3D next_state->entrance_nodes; + *err =3D re_node_set_init_union (&next_nodes, table_nodes, + log_nodes); + if (BE (*err !=3D REG_NOERROR, 0)) + return NULL; + } + else + next_nodes =3D *log_nodes; + /* Note: We already add the nodes of the initial state, + then we don't need to add them here. */ + + context =3D re_string_context_at (&mctx->input, + re_string_cur_idx (&mctx->input) - 1, + mctx->eflags); + next_state =3D mctx->state_log[cur_idx] + =3D 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 !=3D NULL) + re_node_set_free (&next_nodes); + } + + if (BE (dfa->nbackref, 0) && next_state !=3D NULL) + { + /* Check OP_OPEN_SUBEXP in the current state in case that we use t= hem + later. We must check them here, since the back references in the + next state might use them. */ + *err =3D check_subexp_matching_top (mctx, &next_state->nodes, + cur_idx); + if (BE (*err !=3D REG_NOERROR, 0)) + return NULL; + + /* If the next state has back references. */ + if (next_state->has_backref) + { + *err =3D transit_state_bkref (mctx, &next_state->nodes); + if (BE (*err !=3D REG_NOERROR, 0)) + return NULL; + next_state =3D 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. */ +static re_dfastate_t * +find_recover_state (reg_errcode_t *err, re_match_context_t *mctx) +{ + re_dfastate_t *cur_state; + do + { + Idx max =3D mctx->state_log_top; + Idx cur_str_idx =3D 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] =3D=3D NULL); + + cur_state =3D merge_state_with_log (err, mctx, NULL); + } + while (*err =3D=3D REG_NOERROR && cur_state =3D=3D 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 re= gular + expression. And register them to use them later for evaluating the + corresponding back references. */ + +static reg_errcode_t +check_subexp_matching_top (re_match_context_t *mctx, re_node_set *cur_no= des, + Idx str_idx) +{ + const re_dfa_t *const dfa =3D mctx->dfa; + Idx 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 =3D 0; node_idx < cur_nodes->nelem; ++node_idx) + { + Idx node =3D cur_nodes->elems[node_idx]; + if (dfa->nodes[node].type =3D=3D 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 =3D match_ctx_add_subtop (mctx, node, str_idx); + if (BE (err !=3D REG_NOERROR, 0)) + return err; + } + } + return REG_NOERROR; +} + +#if 0 +/* Return the next state to which the current state STATE will transit b= y + 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 =3D mctx->dfa; + re_node_set next_nodes; + re_dfastate_t *next_state; + Idx node_cnt, cur_str_idx =3D re_string_cur_idx (&mctx->input); + unsigned int context; + + *err =3D re_node_set_alloc (&next_nodes, state->nodes.nelem + 1); + if (BE (*err !=3D REG_NOERROR, 0)) + return NULL; + for (node_cnt =3D 0; node_cnt < state->nodes.nelem; ++node_cnt) + { + Idx cur_node =3D state->nodes.elems[node_cnt]; + if (check_node_accept (mctx, dfa->nodes + cur_node, cur_str_idx)) + { + *err =3D re_node_set_merge (&next_nodes, + dfa->eclosures + dfa->nexts[cur_node]); + if (BE (*err !=3D REG_NOERROR, 0)) + { + re_node_set_free (&next_nodes); + return NULL; + } + } + } + context =3D re_string_context_at (&mctx->input, cur_str_idx, mctx->efl= ags); + next_state =3D re_acquire_state_context (err, dfa, &next_nodes, contex= t); + /* 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 +transit_state_mb (re_match_context_t *mctx, re_dfastate_t *pstate) +{ + const re_dfa_t *const dfa =3D mctx->dfa; + reg_errcode_t err; + Idx i; + + for (i =3D 0; i < pstate->nodes.nelem; ++i) + { + re_node_set dest_nodes, *new_nodes; + Idx cur_node_idx =3D pstate->nodes.elems[i]; + int naccepted; + Idx 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 =3D 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 =3D check_node_accept_bytes (dfa, cur_node_idx, &mctx->i= nput, + re_string_cur_idx (&mctx->input)); + if (naccepted =3D=3D 0) + continue; + + /* The node can accepts 'naccepted' bytes. */ + dest_idx =3D re_string_cur_idx (&mctx->input) + naccepted; + mctx->max_mb_elem_len =3D ((mctx->max_mb_elem_len < naccepted) ? n= accepted + : mctx->max_mb_elem_len); + err =3D clean_state_log_if_needed (mctx, dest_idx); + if (BE (err !=3D REG_NOERROR, 0)) + return err; +#ifdef DEBUG + assert (dfa->nexts[cur_node_idx] !=3D -1); +#endif + new_nodes =3D dfa->eclosures + dfa->nexts[cur_node_idx]; + + dest_state =3D mctx->state_log[dest_idx]; + if (dest_state =3D=3D NULL) + dest_nodes =3D *new_nodes; + else + { + err =3D re_node_set_init_union (&dest_nodes, + dest_state->entrance_nodes, new_nodes); + if (BE (err !=3D REG_NOERROR, 0)) + return err; + } + context =3D re_string_context_at (&mctx->input, dest_idx - 1, + mctx->eflags); + mctx->state_log[dest_idx] + =3D re_acquire_state_context (&err, dfa, &dest_nodes, context); + if (dest_state !=3D NULL) + re_node_set_free (&dest_nodes); + if (BE (mctx->state_log[dest_idx] =3D=3D NULL && err !=3D REG_NOER= ROR, 0)) + return err; + } + return REG_NOERROR; +} +#endif /* RE_ENABLE_I18N */ + +static reg_errcode_t +transit_state_bkref (re_match_context_t *mctx, const re_node_set *nodes) +{ + const re_dfa_t *const dfa =3D mctx->dfa; + reg_errcode_t err; + Idx i; + Idx cur_str_idx =3D re_string_cur_idx (&mctx->input); + + for (i =3D 0; i < nodes->nelem; ++i) + { + Idx dest_str_idx, prev_nelem, bkc_idx; + Idx node_idx =3D nodes->elems[i]; + unsigned int context; + const re_token_t *node =3D dfa->nodes + node_idx; + re_node_set *new_dest_nodes; + + /* Check whether 'node' is a backreference or not. */ + if (node->type !=3D OP_BACK_REF) + continue; + + if (node->constraint) + { + context =3D 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 =3D mctx->nbkref_ents; + err =3D get_subexp (mctx, node_idx, cur_str_idx); + if (BE (err !=3D 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] !=3D -1); +#endif + for (; bkc_idx < mctx->nbkref_ents; ++bkc_idx) + { + Idx subexp_len; + re_dfastate_t *dest_state; + struct re_backref_cache_entry *bkref_ent; + bkref_ent =3D mctx->bkref_ents + bkc_idx; + if (bkref_ent->node !=3D node_idx || bkref_ent->str_idx !=3D cur_str_= idx) + continue; + subexp_len =3D bkref_ent->subexp_to - bkref_ent->subexp_from; + new_dest_nodes =3D (subexp_len =3D=3D 0 + ? dfa->eclosures + dfa->edests[node_idx].elems[0] + : dfa->eclosures + dfa->nexts[node_idx]); + dest_str_idx =3D (cur_str_idx + bkref_ent->subexp_to + - bkref_ent->subexp_from); + context =3D re_string_context_at (&mctx->input, dest_str_idx - 1, + mctx->eflags); + dest_state =3D mctx->state_log[dest_str_idx]; + prev_nelem =3D ((mctx->state_log[cur_str_idx] =3D=3D NULL) ? 0 + : mctx->state_log[cur_str_idx]->nodes.nelem); + /* Add 'new_dest_node' to state_log. */ + if (dest_state =3D=3D NULL) + { + mctx->state_log[dest_str_idx] + =3D re_acquire_state_context (&err, dfa, new_dest_nodes, + context); + if (BE (mctx->state_log[dest_str_idx] =3D=3D NULL + && err !=3D REG_NOERROR, 0)) + goto free_return; + } + else + { + re_node_set dest_nodes; + err =3D re_node_set_init_union (&dest_nodes, + dest_state->entrance_nodes, + new_dest_nodes); + if (BE (err !=3D REG_NOERROR, 0)) + { + re_node_set_free (&dest_nodes); + goto free_return; + } + mctx->state_log[dest_str_idx] + =3D re_acquire_state_context (&err, dfa, &dest_nodes, context); + re_node_set_free (&dest_nodes); + if (BE (mctx->state_log[dest_str_idx] =3D=3D NULL + && err !=3D REG_NOERROR, 0)) + goto free_return; + } + /* We need to check recursively if the backreference can epsilon + transit. */ + if (subexp_len =3D=3D 0 + && mctx->state_log[cur_str_idx]->nodes.nelem > prev_nelem) + { + err =3D check_subexp_matching_top (mctx, new_dest_nodes, + cur_str_idx); + if (BE (err !=3D REG_NOERROR, 0)) + goto free_return; + err =3D transit_state_bkref (mctx, new_dest_nodes); + if (BE (err !=3D REG_NOERROR, 0)) + goto free_return; + } + } + } + err =3D REG_NOERROR; + free_return: + return err; +} + +/* Enumerate all the candidates which the backreference BKREF_NODE can m= atch + 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 +__attribute_warn_unused_result__ +get_subexp (re_match_context_t *mctx, Idx bkref_node, Idx bkref_str_idx) +{ + const re_dfa_t *const dfa =3D mctx->dfa; + Idx subexp_num, sub_top_idx; + const char *buf =3D (const char *) re_string_get_buffer (&mctx->input)= ; + /* Return if we have already checked BKREF_NODE at BKREF_STR_IDX. */ + Idx cache_idx =3D search_cur_bkref_entry (mctx, bkref_str_idx); + if (cache_idx !=3D -1) + { + const struct re_backref_cache_entry *entry + =3D mctx->bkref_ents + cache_idx; + do + if (entry->node =3D=3D bkref_node) + return REG_NOERROR; /* We already checked it. */ + while (entry++->more); + } + + subexp_num =3D dfa->nodes[bkref_node].opr.idx; + + /* For each sub expression */ + for (sub_top_idx =3D 0; sub_top_idx < mctx->nsub_tops; ++sub_top_idx) + { + reg_errcode_t err; + re_sub_match_top_t *sub_top =3D mctx->sub_tops[sub_top_idx]; + re_sub_match_last_t *sub_last; + Idx sub_last_idx, sl_str, bkref_str_off; + + if (dfa->nodes[sub_top->node].opr.idx !=3D subexp_num) + continue; /* It isn't related. */ + + sl_str =3D sub_top->str_idx; + bkref_str_off =3D bkref_str_idx; + /* At first, check the last node of sub expressions we already + evaluated. */ + for (sub_last_idx =3D 0; sub_last_idx < sub_top->nlasts; ++sub_las= t_idx) + { + regoff_t sl_str_diff; + sub_last =3D sub_top->lasts[sub_last_idx]; + sl_str_diff =3D 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 =3D clean_state_log_if_needed (mctx, + bkref_str_off + + sl_str_diff); + if (BE (err !=3D REG_NOERROR, 0)) + return err; + buf =3D (const char *) re_string_get_buffer (&mctx->input); + } + if (memcmp (buf + bkref_str_off, buf + sl_str, sl_str_diff) !=3D = 0) + /* We don't need to search this sub expression any more. */ + break; + } + bkref_str_off +=3D sl_str_diff; + sl_str +=3D sl_str_diff; + err =3D 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 =3D (const char *) re_string_get_buffer (&mctx->input); + + if (err =3D=3D REG_NOMATCH) + continue; + if (BE (err !=3D 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 <=3D bkref_str_idx; ++sl_str) + { + Idx cls_node; + regoff_t sl_str_off; + const re_node_set *nodes; + sl_str_off =3D 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 >=3D mctx->input.valid_len, 0)) + { + /* If we are at the end of the input, we cannot match. */ + if (bkref_str_off >=3D mctx->input.len) + break; + + err =3D extend_buffers (mctx, bkref_str_off + 1); + if (BE (err !=3D REG_NOERROR, 0)) + return err; + + buf =3D (const char *) re_string_get_buffer (&mctx->input); + } + if (buf [bkref_str_off++] !=3D buf[sl_str - 1]) + break; /* We don't need to search this sub expression + any more. */ + } + if (mctx->state_log[sl_str] =3D=3D NULL) + continue; + /* Does this state have a ')' of the sub expression? */ + nodes =3D &mctx->state_log[sl_str]->nodes; + cls_node =3D find_subexp_node (dfa, nodes, subexp_num, + OP_CLOSE_SUBEXP); + if (cls_node =3D=3D -1) + continue; /* No. */ + if (sub_top->path =3D=3D NULL) + { + sub_top->path =3D calloc (sizeof (state_array_t), + sl_str - sub_top->str_idx + 1); + if (sub_top->path =3D=3D NULL) + return REG_ESPACE; + } + /* Can the OP_OPEN_SUBEXP node arrive the OP_CLOSE_SUBEXP node + in the current context? */ + err =3D check_arrival (mctx, sub_top->path, sub_top->node, + sub_top->str_idx, cls_node, sl_str, + OP_CLOSE_SUBEXP); + if (err =3D=3D REG_NOMATCH) + continue; + if (BE (err !=3D REG_NOERROR, 0)) + return err; + sub_last =3D match_ctx_add_sublast (sub_top, cls_node, sl_str); + if (BE (sub_last =3D=3D NULL, 0)) + return REG_ESPACE; + err =3D get_subexp_sub (mctx, sub_top, sub_last, bkref_node, + bkref_str_idx); + if (err =3D=3D REG_NOMATCH) + continue; + } + } + return REG_NOERROR; +} + +/* Helper functions for get_subexp(). */ + +/* Check SUB_LAST can arrive to the back reference BKREF_NODE at BKREF_S= TR. + If it can arrive, register the sub expression expressed with SUB_TOP + and SUB_LAST. */ + +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, Idx bkref_node, Idx bkref_str) +{ + reg_errcode_t err; + Idx to_idx; + /* Can the subexpression arrive the back reference? */ + err =3D check_arrival (mctx, &sub_last->path, sub_last->node, + sub_last->str_idx, bkref_node, bkref_str, + OP_OPEN_SUBEXP); + if (err !=3D REG_NOERROR) + return err; + err =3D match_ctx_add_entry (mctx, bkref_node, bkref_str, sub_top->str= _idx, + sub_last->str_idx); + if (BE (err !=3D REG_NOERROR, 0)) + return err; + to_idx =3D 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 Idx +find_subexp_node (const re_dfa_t *dfa, const re_node_set *nodes, + Idx subexp_idx, int type) +{ + Idx cls_idx; + for (cls_idx =3D 0; cls_idx < nodes->nelem; ++cls_idx) + { + Idx cls_node =3D nodes->elems[cls_idx]; + const re_token_t *node =3D dfa->nodes + cls_node; + if (node->type =3D=3D type + && node->opr.idx =3D=3D 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 +__attribute_warn_unused_result__ +check_arrival (re_match_context_t *mctx, state_array_t *path, Idx top_no= de, + Idx top_str, Idx last_node, Idx last_str, int type) +{ + const re_dfa_t *const dfa =3D mctx->dfa; + reg_errcode_t err =3D REG_NOERROR; + Idx subexp_num, backup_cur_idx, str_idx, null_cnt; + re_dfastate_t *cur_state =3D NULL; + re_node_set *cur_nodes, next_nodes; + re_dfastate_t **backup_state_log; + unsigned int context; + + subexp_num =3D 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; + Idx old_alloc =3D path->alloc; + Idx incr_alloc =3D last_str + mctx->max_mb_elem_len + 1; + Idx new_alloc; + if (BE (IDX_MAX - old_alloc < incr_alloc, 0)) + return REG_ESPACE; + new_alloc =3D old_alloc + incr_alloc; + if (BE (SIZE_MAX / sizeof (re_dfastate_t *) < new_alloc, 0)) + return REG_ESPACE; + new_array =3D re_realloc (path->array, re_dfastate_t *, new_alloc)= ; + if (BE (new_array =3D=3D NULL, 0)) + return REG_ESPACE; + path->array =3D new_array; + path->alloc =3D new_alloc; + memset (new_array + old_alloc, '\0', + sizeof (re_dfastate_t *) * (path->alloc - old_alloc)); + } + + str_idx =3D path->next_idx ? path->next_idx : top_str; + + /* Temporary modify MCTX. */ + backup_state_log =3D mctx->state_log; + backup_cur_idx =3D mctx->input.cur_idx; + mctx->state_log =3D path->array; + mctx->input.cur_idx =3D str_idx; + + /* Setup initial node set. */ + context =3D re_string_context_at (&mctx->input, str_idx - 1, mctx->efl= ags); + if (str_idx =3D=3D top_str) + { + err =3D re_node_set_init_1 (&next_nodes, top_node); + if (BE (err !=3D REG_NOERROR, 0)) + return err; + err =3D check_arrival_expand_ecl (dfa, &next_nodes, subexp_num, ty= pe); + if (BE (err !=3D REG_NOERROR, 0)) + { + re_node_set_free (&next_nodes); + return err; + } + } + else + { + cur_state =3D mctx->state_log[str_idx]; + if (cur_state && cur_state->has_backref) + { + err =3D re_node_set_init_copy (&next_nodes, &cur_state->nodes); + if (BE (err !=3D REG_NOERROR, 0)) + return err; + } + else + re_node_set_init_empty (&next_nodes); + } + if (str_idx =3D=3D top_str || (cur_state && cur_state->has_backref)) + { + if (next_nodes.nelem) + { + err =3D expand_bkref_cache (mctx, &next_nodes, str_idx, + subexp_num, type); + if (BE (err !=3D REG_NOERROR, 0)) + { + re_node_set_free (&next_nodes); + return err; + } + } + cur_state =3D re_acquire_state_context (&err, dfa, &next_nodes, co= ntext); + if (BE (cur_state =3D=3D NULL && err !=3D REG_NOERROR, 0)) + { + re_node_set_free (&next_nodes); + return err; + } + mctx->state_log[str_idx] =3D cur_state; + } + + for (null_cnt =3D 0; str_idx < last_str && null_cnt <=3D mctx->max_mb_= elem_len;) + { + re_node_set_empty (&next_nodes); + if (mctx->state_log[str_idx + 1]) + { + err =3D re_node_set_merge (&next_nodes, + &mctx->state_log[str_idx + 1]->nodes); + if (BE (err !=3D REG_NOERROR, 0)) + { + re_node_set_free (&next_nodes); + return err; + } + } + if (cur_state) + { + err =3D check_arrival_add_next_nodes (mctx, str_idx, + &cur_state->non_eps_nodes, + &next_nodes); + if (BE (err !=3D REG_NOERROR, 0)) + { + re_node_set_free (&next_nodes); + return err; + } + } + ++str_idx; + if (next_nodes.nelem) + { + err =3D check_arrival_expand_ecl (dfa, &next_nodes, subexp_num, type)= ; + if (BE (err !=3D REG_NOERROR, 0)) + { + re_node_set_free (&next_nodes); + return err; + } + err =3D expand_bkref_cache (mctx, &next_nodes, str_idx, + subexp_num, type); + if (BE (err !=3D REG_NOERROR, 0)) + { + re_node_set_free (&next_nodes); + return err; + } + } + context =3D re_string_context_at (&mctx->input, str_idx - 1, mctx-= >eflags); + cur_state =3D re_acquire_state_context (&err, dfa, &next_nodes, co= ntext); + if (BE (cur_state =3D=3D NULL && err !=3D REG_NOERROR, 0)) + { + re_node_set_free (&next_nodes); + return err; + } + mctx->state_log[str_idx] =3D cur_state; + null_cnt =3D cur_state =3D=3D NULL ? null_cnt + 1 : 0; + } + re_node_set_free (&next_nodes); + cur_nodes =3D (mctx->state_log[last_str] =3D=3D NULL ? NULL + : &mctx->state_log[last_str]->nodes); + path->next_idx =3D str_idx; + + /* Fix MCTX. */ + mctx->state_log =3D backup_state_log; + mctx->input.cur_idx =3D backup_cur_idx; + + /* Then check the current node set has the node LAST_NODE. */ + if (cur_nodes !=3D 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 t= hem + 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 +__attribute_warn_unused_result__ +check_arrival_add_next_nodes (re_match_context_t *mctx, Idx str_idx, + re_node_set *cur_nodes, re_node_set *next_nodes) +{ + const re_dfa_t *const dfa =3D mctx->dfa; + bool ok; + Idx cur_idx; +#ifdef RE_ENABLE_I18N + reg_errcode_t err =3D REG_NOERROR; +#endif + re_node_set union_set; + re_node_set_init_empty (&union_set); + for (cur_idx =3D 0; cur_idx < cur_nodes->nelem; ++cur_idx) + { + int naccepted =3D 0; + Idx cur_node =3D cur_nodes->elems[cur_idx]; +#ifdef DEBUG + re_token_type_t type =3D 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 =3D check_node_accept_bytes (dfa, cur_node, &mctx->input, + str_idx); + if (naccepted > 1) + { + re_dfastate_t *dest_state; + Idx next_node =3D dfa->nexts[cur_node]; + Idx next_idx =3D str_idx + naccepted; + dest_state =3D mctx->state_log[next_idx]; + re_node_set_empty (&union_set); + if (dest_state) + { + err =3D re_node_set_merge (&union_set, &dest_state->nodes); + if (BE (err !=3D REG_NOERROR, 0)) + { + re_node_set_free (&union_set); + return err; + } + } + ok =3D re_node_set_insert (&union_set, next_node); + if (BE (! ok, 0)) + { + re_node_set_free (&union_set); + return REG_ESPACE; + } + mctx->state_log[next_idx] =3D re_acquire_state (&err, dfa, + &union_set); + if (BE (mctx->state_log[next_idx] =3D=3D NULL + && err !=3D 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)) + { + ok =3D re_node_set_insert (next_nodes, dfa->nexts[cur_node]); + if (BE (! ok, 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 +check_arrival_expand_ecl (const re_dfa_t *dfa, re_node_set *cur_nodes, + Idx ex_subexp, int type) +{ + reg_errcode_t err; + Idx idx, outside_node; + re_node_set new_nodes; +#ifdef DEBUG + assert (cur_nodes->nelem); +#endif + err =3D re_node_set_alloc (&new_nodes, cur_nodes->nelem); + if (BE (err !=3D 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 =3D 0; idx < cur_nodes->nelem; ++idx) + { + Idx cur_node =3D cur_nodes->elems[idx]; + const re_node_set *eclosure =3D dfa->eclosures + cur_node; + outside_node =3D find_subexp_node (dfa, eclosure, ex_subexp, type)= ; + if (outside_node =3D=3D -1) + { + /* There are no problematic nodes, just merge them. */ + err =3D re_node_set_merge (&new_nodes, eclosure); + if (BE (err !=3D REG_NOERROR, 0)) + { + re_node_set_free (&new_nodes); + return err; + } + } + else + { + /* There are problematic nodes, re-calculate incrementally. */ + err =3D check_arrival_expand_ecl_sub (dfa, &new_nodes, cur_node, + ex_subexp, type); + if (BE (err !=3D REG_NOERROR, 0)) + { + re_node_set_free (&new_nodes); + return err; + } + } + } + re_node_set_free (cur_nodes); + *cur_nodes =3D 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 +__attribute_warn_unused_result__ +check_arrival_expand_ecl_sub (const re_dfa_t *dfa, re_node_set *dst_node= s, + Idx target, Idx ex_subexp, int type) +{ + Idx cur_node; + for (cur_node =3D target; !re_node_set_contains (dst_nodes, cur_node);= ) + { + bool ok; + + if (dfa->nodes[cur_node].type =3D=3D type + && dfa->nodes[cur_node].opr.idx =3D=3D ex_subexp) + { + if (type =3D=3D OP_CLOSE_SUBEXP) + { + ok =3D re_node_set_insert (dst_nodes, cur_node); + if (BE (! ok, 0)) + return REG_ESPACE; + } + break; + } + ok =3D re_node_set_insert (dst_nodes, cur_node); + if (BE (! ok, 0)) + return REG_ESPACE; + if (dfa->edests[cur_node].nelem =3D=3D 0) + break; + if (dfa->edests[cur_node].nelem =3D=3D 2) + { + reg_errcode_t err; + err =3D check_arrival_expand_ecl_sub (dfa, dst_nodes, + dfa->edests[cur_node].elems[1], + ex_subexp, type); + if (BE (err !=3D REG_NOERROR, 0)) + return err; + } + cur_node =3D 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 +__attribute_warn_unused_result__ +expand_bkref_cache (re_match_context_t *mctx, re_node_set *cur_nodes, + Idx cur_str, Idx subexp_num, int type) +{ + const re_dfa_t *const dfa =3D mctx->dfa; + reg_errcode_t err; + Idx cache_idx_start =3D search_cur_bkref_entry (mctx, cur_str); + struct re_backref_cache_entry *ent; + + if (cache_idx_start =3D=3D -1) + return REG_NOERROR; + + restart: + ent =3D mctx->bkref_ents + cache_idx_start; + do + { + Idx to_idx, next_node; + + /* Is this entry ENT is appropriate? */ + if (!re_node_set_contains (cur_nodes, ent->node)) + continue; /* No. */ + + to_idx =3D 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 =3D=3D 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 =3D dfa->edests[ent->node].elems[0]; + if (re_node_set_contains (cur_nodes, next_node)) + continue; + err =3D re_node_set_init_1 (&new_dests, next_node); + err2 =3D check_arrival_expand_ecl (dfa, &new_dests, subexp_num, type)= ; + err3 =3D re_node_set_merge (cur_nodes, &new_dests); + re_node_set_free (&new_dests); + if (BE (err !=3D REG_NOERROR || err2 !=3D REG_NOERROR + || err3 !=3D REG_NOERROR, 0)) + { + err =3D (err !=3D REG_NOERROR ? err + : (err2 !=3D REG_NOERROR ? err2 : err3)); + return err; + } + /* TODO: It is still inefficient... */ + goto restart; + } + else + { + re_node_set union_set; + next_node =3D dfa->nexts[ent->node]; + if (mctx->state_log[to_idx]) + { + bool ok; + if (re_node_set_contains (&mctx->state_log[to_idx]->nodes, + next_node)) + continue; + err =3D re_node_set_init_copy (&union_set, + &mctx->state_log[to_idx]->nodes); + ok =3D re_node_set_insert (&union_set, next_node); + if (BE (err !=3D REG_NOERROR || ! ok, 0)) + { + re_node_set_free (&union_set); + err =3D err !=3D REG_NOERROR ? err : REG_ESPACE; + return err; + } + } + else + { + err =3D re_node_set_init_1 (&union_set, next_node); + if (BE (err !=3D REG_NOERROR, 0)) + return err; + } + mctx->state_log[to_idx] =3D re_acquire_state (&err, dfa, &union_set); + re_node_set_free (&union_set); + if (BE (mctx->state_log[to_idx] =3D=3D NULL + && err !=3D REG_NOERROR, 0)) + return err; + } + } + while (ent++->more); + return REG_NOERROR; +} + +/* Build transition table for the state. + Return true if successful. */ + +static bool +build_trtable (const re_dfa_t *dfa, re_dfastate_t *state) +{ + reg_errcode_t err; + Idx i, j; + int ch; + bool need_word_trtable =3D false; + bitset_word_t elem, mask; + bool dests_node_malloced =3D false; + bool dest_states_malloced =3D false; + Idx ndests; /* Number of the destination states from 'state'. */ + re_dfastate_t **trtable; + re_dfastate_t **dest_states =3D NULL, **dest_states_word, **dest_state= s_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 =3D (struct dests_alloc *) alloca (sizeof (struct dests_= alloc)); + else + { + dests_alloc =3D re_malloc (struct dests_alloc, 1); + if (BE (dests_alloc =3D=3D NULL, 0)) + return false; + dests_node_malloced =3D true; + } + dests_node =3D dests_alloc->dests_node; + dests_ch =3D dests_alloc->dests_ch; + + /* Initialize transition table. */ + state->word_trtable =3D state->trtable =3D NULL; + + /* At first, group all nodes belonging to 'state' into several + destinations. */ + ndests =3D group_nodes_into_DFAstates (dfa, state, dests_node, dests_c= h); + if (BE (ndests <=3D 0, 0)) + { + if (dests_node_malloced) + re_free (dests_alloc); + /* Return false in case of an error, true otherwise. */ + if (ndests =3D=3D 0) + { + state->trtable =3D (re_dfastate_t **) + calloc (sizeof (re_dfastate_t *), SBC_MAX); + if (BE (state->trtable =3D=3D NULL, 0)) + return false; + return true; + } + return false; + } + + err =3D re_node_set_alloc (&follows, ndests + 1); + if (BE (err !=3D REG_NOERROR, 0)) + goto out_free; + + /* Avoid arithmetic overflow in size calculation. */ + if (BE ((((SIZE_MAX - (sizeof (re_node_set) + sizeof (bitset_t)) * SBC= _MAX) + / (3 * sizeof (re_dfastate_t *))) + < ndests), + 0)) + goto out_free; + + if (__libc_use_alloca ((sizeof (re_node_set) + sizeof (bitset_t)) * SB= C_MAX + + ndests * 3 * sizeof (re_dfastate_t *))) + dest_states =3D (re_dfastate_t **) + alloca (ndests * 3 * sizeof (re_dfastate_t *)); + else + { + dest_states =3D re_malloc (re_dfastate_t *, ndests * 3); + if (BE (dest_states =3D=3D NULL, 0)) + { +out_free: + if (dest_states_malloced) + re_free (dest_states); + re_node_set_free (&follows); + for (i =3D 0; i < ndests; ++i) + re_node_set_free (dests_node + i); + if (dests_node_malloced) + re_free (dests_alloc); + return false; + } + dest_states_malloced =3D true; + } + dest_states_word =3D dest_states + ndests; + dest_states_nl =3D dest_states_word + ndests; + bitset_empty (acceptable); + + /* Then build the states for all destinations. */ + for (i =3D 0; i < ndests; ++i) + { + Idx next_node; + re_node_set_empty (&follows); + /* Merge the follows of this destination states. */ + for (j =3D 0; j < dests_node[i].nelem; ++j) + { + next_node =3D dfa->nexts[dests_node[i].elems[j]]; + if (next_node !=3D -1) + { + err =3D re_node_set_merge (&follows, dfa->eclosures + next_node); + if (BE (err !=3D REG_NOERROR, 0)) + goto out_free; + } + } + dest_states[i] =3D re_acquire_state_context (&err, dfa, &follows, = 0); + if (BE (dest_states[i] =3D=3D NULL && err !=3D 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] =3D re_acquire_state_context (&err, dfa, &follows= , + CONTEXT_WORD); + if (BE (dest_states_word[i] =3D=3D NULL && err !=3D REG_NOERROR, 0)) + goto out_free; + + if (dest_states[i] !=3D dest_states_word[i] && dfa->mb_cur_max > 1) + need_word_trtable =3D true; + + dest_states_nl[i] =3D re_acquire_state_context (&err, dfa, &follows, + CONTEXT_NEWLINE); + if (BE (dest_states_nl[i] =3D=3D NULL && err !=3D REG_NOERROR, 0)) + goto out_free; + } + else + { + dest_states_word[i] =3D dest_states[i]; + dest_states_nl[i] =3D 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 =3D state->trtable =3D + (re_dfastate_t **) calloc (sizeof (re_dfastate_t *), SBC_MAX); + if (BE (trtable =3D=3D NULL, 0)) + goto out_free; + + /* For all characters ch...: */ + for (i =3D 0; i < BITSET_WORDS; ++i) + for (ch =3D i * BITSET_WORD_BITS, elem =3D acceptable[i], mask =3D 1; + elem; + mask <<=3D 1, elem >>=3D 1, ++ch) + if (BE (elem & 1, 0)) + { + /* There must be exactly one destination which accepts + character ch. See group_nodes_into_DFAstates. */ + for (j =3D 0; (dests_ch[j][i] & mask) =3D=3D 0; ++j) + ; + + /* j-th destination accepts the word character ch. */ + if (dfa->word_char[i] & mask) + trtable[ch] =3D dest_states_word[j]; + else + trtable[ch] =3D 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 =3D state->word_trtable =3D + (re_dfastate_t **) calloc (sizeof (re_dfastate_t *), 2 * SBC_MAX); + if (BE (trtable =3D=3D NULL, 0)) + goto out_free; + + /* For all characters ch...: */ + for (i =3D 0; i < BITSET_WORDS; ++i) + for (ch =3D i * BITSET_WORD_BITS, elem =3D acceptable[i], mask =3D 1; + elem; + mask <<=3D 1, elem >>=3D 1, ++ch) + if (BE (elem & 1, 0)) + { + /* There must be exactly one destination which accepts + character ch. See group_nodes_into_DFAstates. */ + for (j =3D 0; (dests_ch[j][i] & mask) =3D=3D 0; ++j) + ; + + /* j-th destination accepts the word character ch. */ + trtable[ch] =3D dest_states[j]; + trtable[ch + SBC_MAX] =3D dest_states_word[j]; + } + } + + /* new line */ + if (bitset_contain (acceptable, NEWLINE_CHAR)) + { + /* The current state accepts newline character. */ + for (j =3D 0; j < ndests; ++j) + if (bitset_contain (dests_ch[j], NEWLINE_CHAR)) + { + /* k-th destination accepts newline character. */ + trtable[NEWLINE_CHAR] =3D dest_states_nl[j]; + if (need_word_trtable) + trtable[NEWLINE_CHAR + SBC_MAX] =3D dest_states_nl[j]; + /* There must be only one destination which accepts + newline. See group_nodes_into_DFAstates. */ + break; + } + } + + if (dest_states_malloced) + re_free (dest_states); + + re_node_set_free (&follows); + for (i =3D 0; i < ndests; ++i) + re_node_set_free (dests_node + i); + + if (dests_node_malloced) + re_free (dests_alloc); + + return true; +} + +/* 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 Idx +group_nodes_into_DFAstates (const re_dfa_t *dfa, const re_dfastate_t *st= ate, + re_node_set *dests_node, bitset_t *dests_ch) +{ + reg_errcode_t err; + bool ok; + Idx i, j, k; + Idx ndests; /* Number of the destinations from 'state'. */ + bitset_t accepts; /* Characters a node can accept. */ + const re_node_set *cur_nodes =3D &state->nodes; + bitset_empty (accepts); + ndests =3D 0; + + /* For all the nodes belonging to 'state', */ + for (i =3D 0; i < cur_nodes->nelem; ++i) + { + re_token_t *node =3D &dfa->nodes[cur_nodes->elems[i]]; + re_token_type_t type =3D node->type; + unsigned int constraint =3D node->constraint; + + /* Enumerate all single byte character this node can accept. */ + if (type =3D=3D CHARACTER) + bitset_set (accepts, node->opr.c); + else if (type =3D=3D SIMPLE_BRACKET) + { + bitset_merge (accepts, node->opr.sbcset); + } + else if (type =3D=3D 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 =3D=3D OP_UTF8_PERIOD) + { + if (ASCII_CHARS % BITSET_WORD_BITS =3D=3D 0) + memset (accepts, -1, ASCII_CHARS / CHAR_BIT); + else + bitset_merge (accepts, utf8_sb_map); + 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 =3D 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 =3D 0; + if (type =3D=3D CHARACTER && !node->word_char) + { + bitset_empty (accepts); + continue; + } +#ifdef RE_ENABLE_I18N + if (dfa->mb_cur_max > 1) + for (j =3D 0; j < BITSET_WORDS; ++j) + any_set |=3D (accepts[j] &=3D (dfa->word_char[j] | ~dfa->sb_char[j])= ); + else +#endif + for (j =3D 0; j < BITSET_WORDS; ++j) + any_set |=3D (accepts[j] &=3D dfa->word_char[j]); + if (!any_set) + continue; + } + if (constraint & NEXT_NOTWORD_CONSTRAINT) + { + bitset_word_t any_set =3D 0; + if (type =3D=3D CHARACTER && node->word_char) + { + bitset_empty (accepts); + continue; + } +#ifdef RE_ENABLE_I18N + if (dfa->mb_cur_max > 1) + for (j =3D 0; j < BITSET_WORDS; ++j) + any_set |=3D (accepts[j] &=3D ~(dfa->word_char[j] & dfa->sb_char[j])= ); + else +#endif + for (j =3D 0; j < BITSET_WORDS; ++j) + any_set |=3D (accepts[j] &=3D ~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 =3D 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 =3D=3D CHARACTER && !bitset_contain (dests_ch[j], node->opr.= c)) + continue; + + /* Enumerate the intersection set of this state and 'accepts'. */ + has_intersec =3D 0; + for (k =3D 0; k < BITSET_WORDS; ++k) + has_intersec |=3D intersec[k] =3D 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 =3D not_consumed =3D 0; + for (k =3D 0; k < BITSET_WORDS; ++k) + { + not_subset |=3D remains[k] =3D ~accepts[k] & dests_ch[j][k]; + not_consumed |=3D accepts[k] =3D 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 =3D re_node_set_init_copy (dests_node + ndests, &dests_node[j= ]); + if (BE (err !=3D REG_NOERROR, 0)) + goto error_return; + ++ndests; + } + + /* Put the position in the current group. */ + ok =3D re_node_set_insert (&dests_node[j], cur_nodes->elems[i]); + if (BE (! ok, 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 =3D=3D ndests) + { + bitset_copy (dests_ch[ndests], accepts); + err =3D re_node_set_init_1 (dests_node + ndests, cur_nodes->elems[i])= ; + if (BE (err !=3D REG_NOERROR, 0)) + goto error_return; + ++ndests; + bitset_empty (accepts); + } + } + return ndests; + error_return: + for (j =3D 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. */ + +# ifdef _LIBC +# include +# endif + +static int +check_node_accept_bytes (const re_dfa_t *dfa, Idx node_idx, + const re_string_t *input, Idx str_idx) +{ + const re_token_t *node =3D dfa->nodes + node_idx; + int char_len, elem_len; + Idx i; + + if (BE (node->type =3D=3D OP_UTF8_PERIOD, 0)) + { + unsigned char c =3D re_string_byte_at (input, str_idx), d; + if (BE (c < 0xc2, 1)) + return 0; + + if (str_idx + 2 > input->len) + return 0; + + d =3D re_string_byte_at (input, str_idx + 1); + if (c < 0xe0) + return (d < 0x80 || d > 0xbf) ? 0 : 2; + else if (c < 0xf0) + { + char_len =3D 3; + if (c =3D=3D 0xe0 && d < 0xa0) + return 0; + } + else if (c < 0xf8) + { + char_len =3D 4; + if (c =3D=3D 0xf0 && d < 0x90) + return 0; + } + else if (c < 0xfc) + { + char_len =3D 5; + if (c =3D=3D 0xf8 && d < 0x88) + return 0; + } + else if (c < 0xfe) + { + char_len =3D 6; + if (c =3D=3D 0xfc && d < 0x84) + return 0; + } + else + return 0; + + if (str_idx + char_len > input->len) + return 0; + + for (i =3D 1; i < char_len; ++i) + { + d =3D re_string_byte_at (input, str_idx + i); + if (d < 0x80 || d > 0xbf) + return 0; + } + return char_len; + } + + char_len =3D re_string_char_size_at (input, str_idx); + if (node->type =3D=3D OP_PERIOD) + { + if (char_len <=3D 1) + return 0; + /* FIXME: I don't think this if is needed, as both '\n' + and '\0' are char_len =3D=3D 1. */ + /* '.' accepts any one character except the following two cases. = */ + if ((!(dfa->syntax & RE_DOT_NEWLINE) && + re_string_byte_at (input, str_idx) =3D=3D '\n') || + ((dfa->syntax & RE_DOT_NOT_NULL) && + re_string_byte_at (input, str_idx) =3D=3D '\0')) + return 0; + return char_len; + } + + elem_len =3D re_string_elem_size_at (input, str_idx); + if ((elem_len <=3D 1 && char_len <=3D 1) || char_len =3D=3D 0) + return 0; + + if (node->type =3D=3D COMPLEX_BRACKET) + { + const re_charset_t *cset =3D node->opr.mbcset; +# ifdef _LIBC + const unsigned char *pin + =3D ((const unsigned char *) re_string_get_buffer (input) + str_idx); + Idx j; + uint32_t nrules; +# endif /* _LIBC */ + int match_len =3D 0; + wchar_t wc =3D ((cset->nranges || cset->nchar_classes || cset->nmb= chars) + ? re_string_wchar_at (input, str_idx) : 0); + + /* match with multibyte character? */ + for (i =3D 0; i < cset->nmbchars; ++i) + if (wc =3D=3D cset->mbchars[i]) + { + match_len =3D char_len; + goto check_node_accept_bytes_match; + } + /* match with character_class? */ + for (i =3D 0; i < cset->nchar_classes; ++i) + { + wctype_t wt =3D cset->char_classes[i]; + if (__iswctype (wc, wt)) + { + match_len =3D char_len; + goto check_node_accept_bytes_match; + } + } + +# ifdef _LIBC + nrules =3D _NL_CURRENT_WORD (LC_COLLATE, _NL_COLLATE_NRULES); + if (nrules !=3D 0) + { + unsigned int in_collseq =3D 0; + const int32_t *table, *indirect; + const unsigned char *weights, *extra; + const char *collseqwc; + + /* match with collating_symbol? */ + if (cset->ncoll_syms) + extra =3D (const unsigned char *) + _NL_CURRENT (LC_COLLATE, _NL_COLLATE_SYMB_EXTRAMB); + for (i =3D 0; i < cset->ncoll_syms; ++i) + { + const unsigned char *coll_sym =3D extra + cset->coll_syms[i]; + /* Compare the length of input collating element and + the length of current collating element. */ + if (*coll_sym !=3D elem_len) + continue; + /* Compare each bytes. */ + for (j =3D 0; j < *coll_sym; j++) + if (pin[j] !=3D coll_sym[1 + j]) + break; + if (j =3D=3D *coll_sym) + { + /* Match if every bytes is equal. */ + match_len =3D j; + goto check_node_accept_bytes_match; + } + } + + if (cset->nranges) + { + if (elem_len <=3D char_len) + { + collseqwc =3D _NL_CURRENT (LC_COLLATE, _NL_COLLATE_COLLSEQWC); + in_collseq =3D __collseq_table_lookup (collseqwc, wc); + } + else + in_collseq =3D find_collation_sequence_value (pin, elem_len); + } + /* match with range expression? */ + /* FIXME: Implement rational ranges here, too. */ + for (i =3D 0; i < cset->nranges; ++i) + if (cset->range_starts[i] <=3D in_collseq + && in_collseq <=3D cset->range_ends[i]) + { + match_len =3D elem_len; + goto check_node_accept_bytes_match; + } + + /* match with equivalence_class? */ + if (cset->nequiv_classes) + { + const unsigned char *cp =3D pin; + table =3D (const int32_t *) + _NL_CURRENT (LC_COLLATE, _NL_COLLATE_TABLEMB); + weights =3D (const unsigned char *) + _NL_CURRENT (LC_COLLATE, _NL_COLLATE_WEIGHTMB); + extra =3D (const unsigned char *) + _NL_CURRENT (LC_COLLATE, _NL_COLLATE_EXTRAMB); + indirect =3D (const int32_t *) + _NL_CURRENT (LC_COLLATE, _NL_COLLATE_INDIRECTMB); + int32_t idx =3D findidx (table, indirect, extra, &cp, elem_len); + int32_t rule =3D idx >> 24; + idx &=3D 0xffffff; + if (idx > 0) + { + size_t weight_len =3D weights[idx]; + for (i =3D 0; i < cset->nequiv_classes; ++i) + { + int32_t equiv_class_idx =3D cset->equiv_classes[i]; + int32_t equiv_class_rule =3D equiv_class_idx >> 24; + equiv_class_idx &=3D 0xffffff; + if (weights[equiv_class_idx] =3D=3D weight_len + && equiv_class_rule =3D=3D rule + && memcmp (weights + idx + 1, + weights + equiv_class_idx + 1, + weight_len) =3D=3D 0) + { + match_len =3D elem_len; + goto check_node_accept_bytes_match; + } + } + } + } + } + else +# endif /* _LIBC */ + { + /* match with range expression? */ + for (i =3D 0; i < cset->nranges; ++i) + { + if (cset->range_starts[i] <=3D wc && wc <=3D cset->range_ends[i]) + { + match_len =3D char_len; + goto check_node_accept_bytes_match; + } + } + } + check_node_accept_bytes_match: + if (!cset->non_match) + return match_len; + else + { + if (match_len > 0) + return 0; + else + return (elem_len > char_len) ? elem_len : char_len; + } + } + return 0; +} + +# ifdef _LIBC +static unsigned int +find_collation_sequence_value (const unsigned char *mbs, size_t mbs_len) +{ + uint32_t nrules =3D _NL_CURRENT_WORD (LC_COLLATE, _NL_COLLATE_NRULES); + if (nrules =3D=3D 0) + { + if (mbs_len =3D=3D 1) + { + /* No valid character. Match it as a single byte character. */ + const unsigned char *collseq =3D (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 =3D (const unsigned char *) + _NL_CURRENT (LC_COLLATE, _NL_COLLATE_SYMB_EXTRAMB); + int32_t extrasize =3D (const unsigned char *) + _NL_CURRENT (LC_COLLATE, _NL_COLLATE_SYMB_EXTRAMB + 1) - extra; + + for (idx =3D 0; idx < extrasize;) + { + int mbs_cnt; + bool found =3D false; + int32_t elem_mbs_len; + /* Skip the name of collating element name. */ + idx =3D idx + extra[idx] + 1; + elem_mbs_len =3D extra[idx++]; + if (mbs_len =3D=3D elem_mbs_len) + { + for (mbs_cnt =3D 0; mbs_cnt < elem_mbs_len; ++mbs_cnt) + if (extra[idx + mbs_cnt] !=3D mbs[mbs_cnt]) + break; + if (mbs_cnt =3D=3D elem_mbs_len) + /* Found the entry. */ + found =3D true; + } + /* Skip the byte sequence of the collating element. */ + idx +=3D elem_mbs_len; + /* Adjust for the alignment. */ + idx =3D (idx + 3) & ~3; + /* Skip the collation sequence value. */ + idx +=3D sizeof (uint32_t); + /* Skip the wide char sequence of the collating element. */ + idx =3D idx + sizeof (uint32_t) * (*(int32_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 +=3D sizeof (uint32_t); + } + return UINT_MAX; + } +} +# endif /* _LIBC */ +#endif /* RE_ENABLE_I18N */ + +/* Check whether the node accepts the byte which is IDX-th + byte of the INPUT. */ + +static bool +check_node_accept (const re_match_context_t *mctx, const re_token_t *nod= e, + Idx idx) +{ + unsigned char ch; + ch =3D re_string_byte_at (&mctx->input, idx); + switch (node->type) + { + case CHARACTER: + if (node->opr.c !=3D ch) + return false; + break; + + case SIMPLE_BRACKET: + if (!bitset_contain (node->opr.sbcset, ch)) + return false; + break; + +#ifdef RE_ENABLE_I18N + case OP_UTF8_PERIOD: + if (ch >=3D ASCII_CHARS) + return false; + FALLTHROUGH; +#endif + case OP_PERIOD: + if ((ch =3D=3D '\n' && !(mctx->dfa->syntax & RE_DOT_NEWLINE)) + || (ch =3D=3D '\0' && (mctx->dfa->syntax & RE_DOT_NOT_NULL))) + return false; + break; + + default: + return false; + } + + if (node->constraint) + { + /* The node has constraints. Check whether the current context + satisfies the constraints. */ + unsigned int context =3D re_string_context_at (&mctx->input, idx, + mctx->eflags); + if (NOT_SATISFY_NEXT_CONSTRAINT (node->constraint, context)) + return false; + } + + return true; +} + +/* Extend the buffers, if the buffers have run out. */ + +static reg_errcode_t +__attribute_warn_unused_result__ +extend_buffers (re_match_context_t *mctx, int min_len) +{ + reg_errcode_t ret; + re_string_t *pstr =3D &mctx->input; + + /* Avoid overflow. */ + if (BE (MIN (IDX_MAX, SIZE_MAX / sizeof (re_dfastate_t *)) / 2 + <=3D pstr->bufs_len, 0)) + return REG_ESPACE; + + /* Double the lengths of the buffers, but allocate at least MIN_LEN. = */ + ret =3D re_string_realloc_buffers (pstr, + MAX (min_len, + MIN (pstr->len, pstr->bufs_len * 2))); + if (BE (ret !=3D REG_NOERROR, 0)) + return ret; + + if (mctx->state_log !=3D 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 =3D re_realloc (mctx->state_log, re_dfas= tate_t *, + pstr->bufs_len + 1); + if (BE (new_array =3D=3D NULL, 0)) + return REG_ESPACE; + mctx->state_log =3D new_array; + } + + /* Then reconstruct the buffers. */ + if (pstr->icase) + { +#ifdef RE_ENABLE_I18N + if (pstr->mb_cur_max > 1) + { + ret =3D build_wcs_upper_buffer (pstr); + if (BE (ret !=3D 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 !=3D NULL) + re_string_translate_buffer (pstr); + } + } + return REG_NOERROR; +} + +=0C +/* Functions for matching context. */ + +/* Initialize MCTX. */ + +static reg_errcode_t +__attribute_warn_unused_result__ +match_ctx_init (re_match_context_t *mctx, int eflags, Idx n) +{ + mctx->eflags =3D eflags; + mctx->match_last =3D -1; + if (n > 0) + { + /* Avoid overflow. */ + size_t max_object_size =3D + MAX (sizeof (struct re_backref_cache_entry), + sizeof (re_sub_match_top_t *)); + if (BE (MIN (IDX_MAX, SIZE_MAX / max_object_size) < n, 0)) + return REG_ESPACE; + + mctx->bkref_ents =3D re_malloc (struct re_backref_cache_entry, n); + mctx->sub_tops =3D re_malloc (re_sub_match_top_t *, n); + if (BE (mctx->bkref_ents =3D=3D NULL || mctx->sub_tops =3D=3D NULL= , 0)) + return REG_ESPACE; + } + /* Already zero-ed by the caller. + else + mctx->bkref_ents =3D NULL; + mctx->nbkref_ents =3D 0; + mctx->nsub_tops =3D 0; */ + mctx->abkref_ents =3D n; + mctx->max_mb_elem_len =3D 1; + mctx->asub_tops =3D 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 inde= x + of the input, or changes the input string. */ + +static void +match_ctx_clean (re_match_context_t *mctx) +{ + Idx st_idx; + for (st_idx =3D 0; st_idx < mctx->nsub_tops; ++st_idx) + { + Idx sl_idx; + re_sub_match_top_t *top =3D mctx->sub_tops[st_idx]; + for (sl_idx =3D 0; sl_idx < top->nlasts; ++sl_idx) + { + re_sub_match_last_t *last =3D 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); + } + re_free (top); + } + + mctx->nsub_tops =3D 0; + mctx->nbkref_ents =3D 0; +} + +/* Free all the memory associated with MCTX. */ + +static void +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 duplica= te + entry, and call with STR_IDX which isn't smaller than any existing en= try. +*/ + +static reg_errcode_t +__attribute_warn_unused_result__ +match_ctx_add_entry (re_match_context_t *mctx, Idx node, Idx str_idx, Id= x from, + Idx to) +{ + if (mctx->nbkref_ents >=3D mctx->abkref_ents) + { + struct re_backref_cache_entry* new_entry; + new_entry =3D re_realloc (mctx->bkref_ents, struct re_backref_cach= e_entry, + mctx->abkref_ents * 2); + if (BE (new_entry =3D=3D NULL, 0)) + { + re_free (mctx->bkref_ents); + return REG_ESPACE; + } + mctx->bkref_ents =3D new_entry; + memset (mctx->bkref_ents + mctx->nbkref_ents, '\0', + sizeof (struct re_backref_cache_entry) * mctx->abkref_ents); + mctx->abkref_ents *=3D 2; + } + if (mctx->nbkref_ents > 0 + && mctx->bkref_ents[mctx->nbkref_ents - 1].str_idx =3D=3D str_idx) + mctx->bkref_ents[mctx->nbkref_ents - 1].more =3D 1; + + mctx->bkref_ents[mctx->nbkref_ents].node =3D node; + mctx->bkref_ents[mctx->nbkref_ents].str_idx =3D str_idx; + mctx->bkref_ents[mctx->nbkref_ents].subexp_from =3D from; + mctx->bkref_ents[mctx->nbkref_ents].subexp_to =3D to; + + /* This is a cache that saves negative results of check_dst_limits_cal= c_pos. + If bit N is clear, means that this entry won't epsilon-transition t= o + 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 !=3D TO. */ + mctx->bkref_ents[mctx->nbkref_ents].eps_reachable_subexps_map + =3D (from =3D=3D to ? -1 : 0); + + mctx->bkref_ents[mctx->nbkref_ents++].more =3D 0; + if (mctx->max_mb_elem_len < to - from) + mctx->max_mb_elem_len =3D to - from; + return REG_NOERROR; +} + +/* Return the first entry with the same str_idx, or -1 if none is + found. Note that MCTX->BKREF_ENTS is already sorted by MCTX->STR_IDX= . */ + +static Idx +search_cur_bkref_entry (const re_match_context_t *mctx, Idx str_idx) +{ + Idx left, right, mid, last; + last =3D right =3D mctx->nbkref_ents; + for (left =3D 0; left < right;) + { + mid =3D (left + right) / 2; + if (mctx->bkref_ents[mid].str_idx < str_idx) + left =3D mid + 1; + else + right =3D mid; + } + if (left < last && mctx->bkref_ents[left].str_idx =3D=3D str_idx) + return left; + else + return -1; +} + +/* Register the node NODE, whose type is OP_OPEN_SUBEXP, and which match= es + at STR_IDX. */ + +static reg_errcode_t +__attribute_warn_unused_result__ +match_ctx_add_subtop (re_match_context_t *mctx, Idx node, Idx str_idx) +{ +#ifdef DEBUG + assert (mctx->sub_tops !=3D NULL); + assert (mctx->asub_tops > 0); +#endif + if (BE (mctx->nsub_tops =3D=3D mctx->asub_tops, 0)) + { + Idx new_asub_tops =3D mctx->asub_tops * 2; + re_sub_match_top_t **new_array =3D re_realloc (mctx->sub_tops, + re_sub_match_top_t *, + new_asub_tops); + if (BE (new_array =3D=3D NULL, 0)) + return REG_ESPACE; + mctx->sub_tops =3D new_array; + mctx->asub_tops =3D new_asub_tops; + } + mctx->sub_tops[mctx->nsub_tops] =3D calloc (1, sizeof (re_sub_match_to= p_t)); + if (BE (mctx->sub_tops[mctx->nsub_tops] =3D=3D NULL, 0)) + return REG_ESPACE; + mctx->sub_tops[mctx->nsub_tops]->node =3D node; + mctx->sub_tops[mctx->nsub_tops++]->str_idx =3D str_idx; + return REG_NOERROR; +} + +/* Register the node NODE, whose type is OP_CLOSE_SUBEXP, and which matc= hes + at STR_IDX, whose corresponding OP_OPEN_SUBEXP is SUB_TOP. */ + +static re_sub_match_last_t * +match_ctx_add_sublast (re_sub_match_top_t *subtop, Idx node, Idx str_idx= ) +{ + re_sub_match_last_t *new_entry; + if (BE (subtop->nlasts =3D=3D subtop->alasts, 0)) + { + Idx new_alasts =3D 2 * subtop->alasts + 1; + re_sub_match_last_t **new_array =3D re_realloc (subtop->lasts, + re_sub_match_last_t *, + new_alasts); + if (BE (new_array =3D=3D NULL, 0)) + return NULL; + subtop->lasts =3D new_array; + subtop->alasts =3D new_alasts; + } + new_entry =3D calloc (1, sizeof (re_sub_match_last_t)); + if (BE (new_entry !=3D NULL, 1)) + { + subtop->lasts[subtop->nlasts] =3D new_entry; + new_entry->node =3D node; + new_entry->str_idx =3D str_idx; + ++subtop->nlasts; + } + return new_entry; +} + +static void +sift_ctx_init (re_sift_context_t *sctx, re_dfastate_t **sifted_sts, + re_dfastate_t **limited_sts, Idx last_node, Idx last_str_idx) +{ + sctx->sifted_states =3D sifted_sts; + sctx->limited_states =3D limited_sts; + sctx->last_node =3D last_node; + sctx->last_str_idx =3D last_str_idx; + re_node_set_init_empty (&sctx->limits); +} diff --git a/lib/streq.h b/lib/streq.h new file mode 100644 index 0000000000..bde1b9562f --- /dev/null +++ b/lib/streq.h @@ -0,0 +1,176 @@ +/* Optimized string comparison. + Copyright (C) 2001-2002, 2007, 2009-2018 Free Software Foundation, In= c. + + This program is free software: you can redistribute it and/or modify = it + under the terms of the GNU General Public License as published + by the Free Software Foundation; either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see = . */ + +/* Written by Bruno Haible . */ + +#ifndef _GL_STREQ_H +#define _GL_STREQ_H + +#include + +/* STREQ_OPT allows to optimize string comparison with a small literal s= tring. + STREQ_OPT (s, "EUC-KR", 'E', 'U', 'C', '-', 'K', 'R', 0, 0, 0) + is semantically equivalent to + strcmp (s, "EUC-KR") =3D=3D 0 + just faster. */ + +/* Help GCC to generate good code for string comparisons with + immediate strings. */ +#if defined (__GNUC__) && defined (__OPTIMIZE__) + +static inline int +streq9 (const char *s1, const char *s2) +{ + return strcmp (s1 + 9, s2 + 9) =3D=3D 0; +} + +static inline int +streq8 (const char *s1, const char *s2, char s28) +{ + if (s1[8] =3D=3D s28) + { + if (s28 =3D=3D 0) + return 1; + else + return streq9 (s1, s2); + } + else + return 0; +} + +static inline int +streq7 (const char *s1, const char *s2, char s27, char s28) +{ + if (s1[7] =3D=3D s27) + { + if (s27 =3D=3D 0) + return 1; + else + return streq8 (s1, s2, s28); + } + else + return 0; +} + +static inline int +streq6 (const char *s1, const char *s2, char s26, char s27, char s28) +{ + if (s1[6] =3D=3D s26) + { + if (s26 =3D=3D 0) + return 1; + else + return streq7 (s1, s2, s27, s28); + } + else + return 0; +} + +static inline int +streq5 (const char *s1, const char *s2, char s25, char s26, char s27, ch= ar s28) +{ + if (s1[5] =3D=3D s25) + { + if (s25 =3D=3D 0) + return 1; + else + return streq6 (s1, s2, s26, s27, s28); + } + else + return 0; +} + +static inline int +streq4 (const char *s1, const char *s2, char s24, char s25, char s26, ch= ar s27, char s28) +{ + if (s1[4] =3D=3D s24) + { + if (s24 =3D=3D 0) + return 1; + else + return streq5 (s1, s2, s25, s26, s27, s28); + } + else + return 0; +} + +static inline int +streq3 (const char *s1, const char *s2, char s23, char s24, char s25, ch= ar s26, char s27, char s28) +{ + if (s1[3] =3D=3D s23) + { + if (s23 =3D=3D 0) + return 1; + else + return streq4 (s1, s2, s24, s25, s26, s27, s28); + } + else + return 0; +} + +static inline int +streq2 (const char *s1, const char *s2, char s22, char s23, char s24, ch= ar s25, char s26, char s27, char s28) +{ + if (s1[2] =3D=3D s22) + { + if (s22 =3D=3D 0) + return 1; + else + return streq3 (s1, s2, s23, s24, s25, s26, s27, s28); + } + else + return 0; +} + +static inline int +streq1 (const char *s1, const char *s2, char s21, char s22, char s23, ch= ar s24, char s25, char s26, char s27, char s28) +{ + if (s1[1] =3D=3D s21) + { + if (s21 =3D=3D 0) + return 1; + else + return streq2 (s1, s2, s22, s23, s24, s25, s26, s27, s28); + } + else + return 0; +} + +static inline int +streq0 (const char *s1, const char *s2, char s20, char s21, char s22, ch= ar s23, char s24, char s25, char s26, char s27, char s28) +{ + if (s1[0] =3D=3D s20) + { + if (s20 =3D=3D 0) + return 1; + else + return streq1 (s1, s2, s21, s22, s23, s24, s25, s26, s27, s28); + } + else + return 0; +} + +#define STREQ_OPT(s1,s2,s20,s21,s22,s23,s24,s25,s26,s27,s28) \ + streq0 (s1, s2, s20, s21, s22, s23, s24, s25, s26, s27, s28) + +#else + +#define STREQ_OPT(s1,s2,s20,s21,s22,s23,s24,s25,s26,s27,s28) \ + (strcmp (s1, s2) =3D=3D 0) + +#endif + +#endif /* _GL_STREQ_H */ diff --git a/lib/wchar.in.h b/lib/wchar.in.h new file mode 100644 index 0000000000..51a5dda17d --- /dev/null +++ b/lib/wchar.in.h @@ -0,0 +1,1072 @@ +/* A substitute for ISO C99 , for platforms that have issues. + + Copyright (C) 2007-2018 Free Software Foundation, Inc. + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 3, or (at your option) + any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, see .= */ + +/* Written by Eric Blake. */ + +/* + * ISO C 99 for platforms that have issues. + * + * + * For now, this just ensures proper prerequisite inclusion order and + * the declaration of wcwidth(). + */ + +#if __GNUC__ >=3D 3 +@PRAGMA_SYSTEM_HEADER@ +#endif +@PRAGMA_COLUMNS@ + +#if (((defined __need_mbstate_t || defined __need_wint_t) = \ + && !defined __MINGW32__) = \ + || (defined __hpux = \ + && ((defined _INTTYPES_INCLUDED && !defined strtoimax) = \ + || defined _GL_JUST_INCLUDE_SYSTEM_WCHAR_H)) = \ + || (defined __MINGW32__ && defined __STRING_H_SOURCED__) = \ + || defined _GL_ALREADY_INCLUDING_WCHAR_H) +/* Special invocation convention: + - Inside glibc and uClibc header files, but not MinGW. + - On HP-UX 11.00 we have a sequence of nested includes + -> -> , and the latter includes , + once indirectly -> -> -> + and once directly. In both situations 'wint_t' is not yet defined, + therefore we cannot provide the function overrides; instead include= only + the system's . + - With MinGW 3.22, when includes , only some part= of + is actually processed, and that doesn't include 'mbstate_= t'. + - On IRIX 6.5, similarly, we have an include -> ,= and + the latter includes . But here, we have no way to detect = whether + is completely included or is still being included. */ + +#@INCLUDE_NEXT@ @NEXT_WCHAR_H@ + +#else +/* Normal invocation convention. */ + +#ifndef _@GUARD_PREFIX@_WCHAR_H + +#define _GL_ALREADY_INCLUDING_WCHAR_H + +#if @HAVE_FEATURES_H@ +# include /* for __GLIBC__ */ +#endif + +/* Tru64 with Desktop Toolkit C has a bug: must be included be= fore + . + BSD/OS 4.0.1 has a bug: , and must be + included before . + In some builds of uClibc, is nonexistent and wchar_t is def= ined + by . + But avoid namespace pollution on glibc systems. */ +#if !(defined __GLIBC__ && !defined __UCLIBC__) +# include +#endif +#ifndef __GLIBC__ +# include +# include +#endif + +/* Include the original if it exists. + Some builds of uClibc lack it. */ +/* The include_next requires a split double-inclusion guard. */ +#if @HAVE_WCHAR_H@ +# @INCLUDE_NEXT@ @NEXT_WCHAR_H@ +#endif + +#undef _GL_ALREADY_INCLUDING_WCHAR_H + +#ifndef _@GUARD_PREFIX@_WCHAR_H +#define _@GUARD_PREFIX@_WCHAR_H + +/* The __attribute__ feature is available in gcc versions 2.5 and later. + The attribute __pure__ was added in gcc 2.96. */ +#if __GNUC__ > 2 || (__GNUC__ =3D=3D 2 && __GNUC_MINOR__ >=3D 96) +# define _GL_ATTRIBUTE_PURE __attribute__ ((__pure__)) +#else +# define _GL_ATTRIBUTE_PURE /* empty */ +#endif + +/* The definitions of _GL_FUNCDECL_RPL etc. are copied here. */ + +/* The definition of _GL_ARG_NONNULL is copied here. */ + +/* The definition of _GL_WARN_ON_USE is copied here. */ + + +/* Define wint_t and WEOF. (Also done in wctype.in.h.) */ +#if !@HAVE_WINT_T@ && !defined wint_t +# define wint_t int +# ifndef WEOF +# define WEOF -1 +# endif +#else +/* mingw and MSVC define wint_t as 'unsigned short' in or + . This is too small: ISO C 99 section 7.24.1.(2) says that + wint_t must be "unchanged by default argument promotions". Override = it. */ +# if @GNULIB_OVERRIDES_WINT_T@ +# if !GNULIB_defined_wint_t +# if @HAVE_CRTDEFS_H@ +# include +# else +# include +# endif +typedef unsigned int rpl_wint_t; +# undef wint_t +# define wint_t rpl_wint_t +# define GNULIB_defined_wint_t 1 +# endif +# endif +# ifndef WEOF +# define WEOF ((wint_t) -1) +# endif +#endif + + +/* Override mbstate_t if it is too small. + On IRIX 6.5, sizeof (mbstate_t) =3D=3D 1, which is not sufficient for + implementing mbrtowc for encodings like UTF-8. */ +#if !(@HAVE_MBSINIT@ && @HAVE_MBRTOWC@) || @REPLACE_MBSTATE_T@ +# if !GNULIB_defined_mbstate_t +typedef int rpl_mbstate_t; +# undef mbstate_t +# define mbstate_t rpl_mbstate_t +# define GNULIB_defined_mbstate_t 1 +# endif +#endif + + +/* Convert a single-byte character to a wide character. */ +#if @GNULIB_BTOWC@ +# if @REPLACE_BTOWC@ +# if !(defined __cplusplus && defined GNULIB_NAMESPACE) +# undef btowc +# define btowc rpl_btowc +# endif +_GL_FUNCDECL_RPL (btowc, wint_t, (int c) _GL_ATTRIBUTE_PURE); +_GL_CXXALIAS_RPL (btowc, wint_t, (int c)); +# else +# if !@HAVE_BTOWC@ +_GL_FUNCDECL_SYS (btowc, wint_t, (int c) _GL_ATTRIBUTE_PURE); +# endif +_GL_CXXALIAS_SYS (btowc, wint_t, (int c)); +# endif +_GL_CXXALIASWARN (btowc); +#elif defined GNULIB_POSIXCHECK +# undef btowc +# if HAVE_RAW_DECL_BTOWC +_GL_WARN_ON_USE (btowc, "btowc is unportable - " + "use gnulib module btowc for portability"); +# endif +#endif + + +/* Convert a wide character to a single-byte character. */ +#if @GNULIB_WCTOB@ +# if @REPLACE_WCTOB@ +# if !(defined __cplusplus && defined GNULIB_NAMESPACE) +# undef wctob +# define wctob rpl_wctob +# endif +_GL_FUNCDECL_RPL (wctob, int, (wint_t wc) _GL_ATTRIBUTE_PURE); +_GL_CXXALIAS_RPL (wctob, int, (wint_t wc)); +# else +# if !defined wctob && !@HAVE_DECL_WCTOB@ +/* wctob is provided by gnulib, or wctob exists but is not declared. */ +_GL_FUNCDECL_SYS (wctob, int, (wint_t wc) _GL_ATTRIBUTE_PURE); +# endif +_GL_CXXALIAS_SYS (wctob, int, (wint_t wc)); +# endif +_GL_CXXALIASWARN (wctob); +#elif defined GNULIB_POSIXCHECK +# undef wctob +# if HAVE_RAW_DECL_WCTOB +_GL_WARN_ON_USE (wctob, "wctob is unportable - " + "use gnulib module wctob for portability"); +# endif +#endif + + +/* Test whether *PS is in the initial state. */ +#if @GNULIB_MBSINIT@ +# if @REPLACE_MBSINIT@ +# if !(defined __cplusplus && defined GNULIB_NAMESPACE) +# undef mbsinit +# define mbsinit rpl_mbsinit +# endif +_GL_FUNCDECL_RPL (mbsinit, int, (const mbstate_t *ps)); +_GL_CXXALIAS_RPL (mbsinit, int, (const mbstate_t *ps)); +# else +# if !@HAVE_MBSINIT@ +_GL_FUNCDECL_SYS (mbsinit, int, (const mbstate_t *ps)); +# endif +_GL_CXXALIAS_SYS (mbsinit, int, (const mbstate_t *ps)); +# endif +_GL_CXXALIASWARN (mbsinit); +#elif defined GNULIB_POSIXCHECK +# undef mbsinit +# if HAVE_RAW_DECL_MBSINIT +_GL_WARN_ON_USE (mbsinit, "mbsinit is unportable - " + "use gnulib module mbsinit for portability"); +# endif +#endif + + +/* Convert a multibyte character to a wide character. */ +#if @GNULIB_MBRTOWC@ +# if @REPLACE_MBRTOWC@ +# if !(defined __cplusplus && defined GNULIB_NAMESPACE) +# undef mbrtowc +# define mbrtowc rpl_mbrtowc +# endif +_GL_FUNCDECL_RPL (mbrtowc, size_t, + (wchar_t *pwc, const char *s, size_t n, mbstate_t *ps)= ); +_GL_CXXALIAS_RPL (mbrtowc, size_t, + (wchar_t *pwc, const char *s, size_t n, mbstate_t *ps)= ); +# else +# if !@HAVE_MBRTOWC@ +_GL_FUNCDECL_SYS (mbrtowc, size_t, + (wchar_t *pwc, const char *s, size_t n, mbstate_t *ps)= ); +# endif +_GL_CXXALIAS_SYS (mbrtowc, size_t, + (wchar_t *pwc, const char *s, size_t n, mbstate_t *ps)= ); +# endif +_GL_CXXALIASWARN (mbrtowc); +#elif defined GNULIB_POSIXCHECK +# undef mbrtowc +# if HAVE_RAW_DECL_MBRTOWC +_GL_WARN_ON_USE (mbrtowc, "mbrtowc is unportable - " + "use gnulib module mbrtowc for portability"); +# endif +#endif + + +/* Recognize a multibyte character. */ +#if @GNULIB_MBRLEN@ +# if @REPLACE_MBRLEN@ +# if !(defined __cplusplus && defined GNULIB_NAMESPACE) +# undef mbrlen +# define mbrlen rpl_mbrlen +# endif +_GL_FUNCDECL_RPL (mbrlen, size_t, (const char *s, size_t n, mbstate_t *p= s)); +_GL_CXXALIAS_RPL (mbrlen, size_t, (const char *s, size_t n, mbstate_t *p= s)); +# else +# if !@HAVE_MBRLEN@ +_GL_FUNCDECL_SYS (mbrlen, size_t, (const char *s, size_t n, mbstate_t *p= s)); +# endif +_GL_CXXALIAS_SYS (mbrlen, size_t, (const char *s, size_t n, mbstate_t *p= s)); +# endif +_GL_CXXALIASWARN (mbrlen); +#elif defined GNULIB_POSIXCHECK +# undef mbrlen +# if HAVE_RAW_DECL_MBRLEN +_GL_WARN_ON_USE (mbrlen, "mbrlen is unportable - " + "use gnulib module mbrlen for portability"); +# endif +#endif + + +/* Convert a string to a wide string. */ +#if @GNULIB_MBSRTOWCS@ +# if @REPLACE_MBSRTOWCS@ +# if !(defined __cplusplus && defined GNULIB_NAMESPACE) +# undef mbsrtowcs +# define mbsrtowcs rpl_mbsrtowcs +# endif +_GL_FUNCDECL_RPL (mbsrtowcs, size_t, + (wchar_t *dest, const char **srcp, size_t len, mbstate= _t *ps) + _GL_ARG_NONNULL ((2))); +_GL_CXXALIAS_RPL (mbsrtowcs, size_t, + (wchar_t *dest, const char **srcp, size_t len, + mbstate_t *ps)); +# else +# if !@HAVE_MBSRTOWCS@ +_GL_FUNCDECL_SYS (mbsrtowcs, size_t, + (wchar_t *dest, const char **srcp, size_t len, mbstate= _t *ps) + _GL_ARG_NONNULL ((2))); +# endif +_GL_CXXALIAS_SYS (mbsrtowcs, size_t, + (wchar_t *dest, const char **srcp, size_t len, + mbstate_t *ps)); +# endif +_GL_CXXALIASWARN (mbsrtowcs); +#elif defined GNULIB_POSIXCHECK +# undef mbsrtowcs +# if HAVE_RAW_DECL_MBSRTOWCS +_GL_WARN_ON_USE (mbsrtowcs, "mbsrtowcs is unportable - " + "use gnulib module mbsrtowcs for portability"); +# endif +#endif + + +/* Convert a string to a wide string. */ +#if @GNULIB_MBSNRTOWCS@ +# if @REPLACE_MBSNRTOWCS@ +# if !(defined __cplusplus && defined GNULIB_NAMESPACE) +# undef mbsnrtowcs +# define mbsnrtowcs rpl_mbsnrtowcs +# endif +_GL_FUNCDECL_RPL (mbsnrtowcs, size_t, + (wchar_t *dest, const char **srcp, size_t srclen, size= _t len, + mbstate_t *ps) + _GL_ARG_NONNULL ((2))); +_GL_CXXALIAS_RPL (mbsnrtowcs, size_t, + (wchar_t *dest, const char **srcp, size_t srclen, size= _t len, + mbstate_t *ps)); +# else +# if !@HAVE_MBSNRTOWCS@ +_GL_FUNCDECL_SYS (mbsnrtowcs, size_t, + (wchar_t *dest, const char **srcp, size_t srclen, size= _t len, + mbstate_t *ps) + _GL_ARG_NONNULL ((2))); +# endif +_GL_CXXALIAS_SYS (mbsnrtowcs, size_t, + (wchar_t *dest, const char **srcp, size_t srclen, size= _t len, + mbstate_t *ps)); +# endif +_GL_CXXALIASWARN (mbsnrtowcs); +#elif defined GNULIB_POSIXCHECK +# undef mbsnrtowcs +# if HAVE_RAW_DECL_MBSNRTOWCS +_GL_WARN_ON_USE (mbsnrtowcs, "mbsnrtowcs is unportable - " + "use gnulib module mbsnrtowcs for portability"); +# endif +#endif + + +/* Convert a wide character to a multibyte character. */ +#if @GNULIB_WCRTOMB@ +# if @REPLACE_WCRTOMB@ +# if !(defined __cplusplus && defined GNULIB_NAMESPACE) +# undef wcrtomb +# define wcrtomb rpl_wcrtomb +# endif +_GL_FUNCDECL_RPL (wcrtomb, size_t, (char *s, wchar_t wc, mbstate_t *ps))= ; +_GL_CXXALIAS_RPL (wcrtomb, size_t, (char *s, wchar_t wc, mbstate_t *ps))= ; +# else +# if !@HAVE_WCRTOMB@ +_GL_FUNCDECL_SYS (wcrtomb, size_t, (char *s, wchar_t wc, mbstate_t *ps))= ; +# endif +_GL_CXXALIAS_SYS (wcrtomb, size_t, (char *s, wchar_t wc, mbstate_t *ps))= ; +# endif +_GL_CXXALIASWARN (wcrtomb); +#elif defined GNULIB_POSIXCHECK +# undef wcrtomb +# if HAVE_RAW_DECL_WCRTOMB +_GL_WARN_ON_USE (wcrtomb, "wcrtomb is unportable - " + "use gnulib module wcrtomb for portability"); +# endif +#endif + + +/* Convert a wide string to a string. */ +#if @GNULIB_WCSRTOMBS@ +# if @REPLACE_WCSRTOMBS@ +# if !(defined __cplusplus && defined GNULIB_NAMESPACE) +# undef wcsrtombs +# define wcsrtombs rpl_wcsrtombs +# endif +_GL_FUNCDECL_RPL (wcsrtombs, size_t, + (char *dest, const wchar_t **srcp, size_t len, mbstate= _t *ps) + _GL_ARG_NONNULL ((2))); +_GL_CXXALIAS_RPL (wcsrtombs, size_t, + (char *dest, const wchar_t **srcp, size_t len, + mbstate_t *ps)); +# else +# if !@HAVE_WCSRTOMBS@ +_GL_FUNCDECL_SYS (wcsrtombs, size_t, + (char *dest, const wchar_t **srcp, size_t len, mbstate= _t *ps) + _GL_ARG_NONNULL ((2))); +# endif +_GL_CXXALIAS_SYS (wcsrtombs, size_t, + (char *dest, const wchar_t **srcp, size_t len, + mbstate_t *ps)); +# endif +_GL_CXXALIASWARN (wcsrtombs); +#elif defined GNULIB_POSIXCHECK +# undef wcsrtombs +# if HAVE_RAW_DECL_WCSRTOMBS +_GL_WARN_ON_USE (wcsrtombs, "wcsrtombs is unportable - " + "use gnulib module wcsrtombs for portability"); +# endif +#endif + + +/* Convert a wide string to a string. */ +#if @GNULIB_WCSNRTOMBS@ +# if @REPLACE_WCSNRTOMBS@ +# if !(defined __cplusplus && defined GNULIB_NAMESPACE) +# undef wcsnrtombs +# define wcsnrtombs rpl_wcsnrtombs +# endif +_GL_FUNCDECL_RPL (wcsnrtombs, size_t, + (char *dest, const wchar_t **srcp, size_t srclen, size= _t len, + mbstate_t *ps) + _GL_ARG_NONNULL ((2))); +_GL_CXXALIAS_RPL (wcsnrtombs, size_t, + (char *dest, const wchar_t **srcp, size_t srclen, size= _t len, + mbstate_t *ps)); +# else +# if !@HAVE_WCSNRTOMBS@ +_GL_FUNCDECL_SYS (wcsnrtombs, size_t, + (char *dest, const wchar_t **srcp, size_t srclen, size= _t len, + mbstate_t *ps) + _GL_ARG_NONNULL ((2))); +# endif +_GL_CXXALIAS_SYS (wcsnrtombs, size_t, + (char *dest, const wchar_t **srcp, size_t srclen, size= _t len, + mbstate_t *ps)); +# endif +_GL_CXXALIASWARN (wcsnrtombs); +#elif defined GNULIB_POSIXCHECK +# undef wcsnrtombs +# if HAVE_RAW_DECL_WCSNRTOMBS +_GL_WARN_ON_USE (wcsnrtombs, "wcsnrtombs is unportable - " + "use gnulib module wcsnrtombs for portability"); +# endif +#endif + + +/* Return the number of screen columns needed for WC. */ +#if @GNULIB_WCWIDTH@ +# if @REPLACE_WCWIDTH@ +# if !(defined __cplusplus && defined GNULIB_NAMESPACE) +# undef wcwidth +# define wcwidth rpl_wcwidth +# endif +_GL_FUNCDECL_RPL (wcwidth, int, (wchar_t) _GL_ATTRIBUTE_PURE); +_GL_CXXALIAS_RPL (wcwidth, int, (wchar_t)); +# else +# if !@HAVE_DECL_WCWIDTH@ +/* wcwidth exists but is not declared. */ +_GL_FUNCDECL_SYS (wcwidth, int, (wchar_t) _GL_ATTRIBUTE_PURE); +# endif +_GL_CXXALIAS_SYS (wcwidth, int, (wchar_t)); +# endif +_GL_CXXALIASWARN (wcwidth); +#elif defined GNULIB_POSIXCHECK +# undef wcwidth +# if HAVE_RAW_DECL_WCWIDTH +_GL_WARN_ON_USE (wcwidth, "wcwidth is unportable - " + "use gnulib module wcwidth for portability"); +# endif +#endif + + +/* Search N wide characters of S for C. */ +#if @GNULIB_WMEMCHR@ +# if !@HAVE_WMEMCHR@ +_GL_FUNCDECL_SYS (wmemchr, wchar_t *, (const wchar_t *s, wchar_t c, size= _t n) + _GL_ATTRIBUTE_PURE); +# endif + /* On some systems, this function is defined as an overloaded function= : + extern "C++" { + const wchar_t * std::wmemchr (const wchar_t *, wchar_t, size_t)= ; + wchar_t * std::wmemchr (wchar_t *, wchar_t, size_t); + } */ +_GL_CXXALIAS_SYS_CAST2 (wmemchr, + wchar_t *, (const wchar_t *, wchar_t, size_t), + const wchar_t *, (const wchar_t *, wchar_t, size= _t)); +# if ((__GLIBC__ =3D=3D 2 && __GLIBC_MINOR__ >=3D 10) && !defined __UCLI= BC__) \ + && (__GNUC__ > 4 || (__GNUC__ =3D=3D 4 && __GNUC_MINOR__ >=3D 4)) +_GL_CXXALIASWARN1 (wmemchr, wchar_t *, (wchar_t *s, wchar_t c, size_t n)= ); +_GL_CXXALIASWARN1 (wmemchr, const wchar_t *, + (const wchar_t *s, wchar_t c, size_t n)); +# else +_GL_CXXALIASWARN (wmemchr); +# endif +#elif defined GNULIB_POSIXCHECK +# undef wmemchr +# if HAVE_RAW_DECL_WMEMCHR +_GL_WARN_ON_USE (wmemchr, "wmemchr is unportable - " + "use gnulib module wmemchr for portability"); +# endif +#endif + + +/* Compare N wide characters of S1 and S2. */ +#if @GNULIB_WMEMCMP@ +# if !@HAVE_WMEMCMP@ +_GL_FUNCDECL_SYS (wmemcmp, int, + (const wchar_t *s1, const wchar_t *s2, size_t n) + _GL_ATTRIBUTE_PURE); +# endif +_GL_CXXALIAS_SYS (wmemcmp, int, + (const wchar_t *s1, const wchar_t *s2, size_t n)); +_GL_CXXALIASWARN (wmemcmp); +#elif defined GNULIB_POSIXCHECK +# undef wmemcmp +# if HAVE_RAW_DECL_WMEMCMP +_GL_WARN_ON_USE (wmemcmp, "wmemcmp is unportable - " + "use gnulib module wmemcmp for portability"); +# endif +#endif + + +/* Copy N wide characters of SRC to DEST. */ +#if @GNULIB_WMEMCPY@ +# if !@HAVE_WMEMCPY@ +_GL_FUNCDECL_SYS (wmemcpy, wchar_t *, + (wchar_t *dest, const wchar_t *src, size_t n)); +# endif +_GL_CXXALIAS_SYS (wmemcpy, wchar_t *, + (wchar_t *dest, const wchar_t *src, size_t n)); +_GL_CXXALIASWARN (wmemcpy); +#elif defined GNULIB_POSIXCHECK +# undef wmemcpy +# if HAVE_RAW_DECL_WMEMCPY +_GL_WARN_ON_USE (wmemcpy, "wmemcpy is unportable - " + "use gnulib module wmemcpy for portability"); +# endif +#endif + + +/* Copy N wide characters of SRC to DEST, guaranteeing correct behavior = for + overlapping memory areas. */ +#if @GNULIB_WMEMMOVE@ +# if !@HAVE_WMEMMOVE@ +_GL_FUNCDECL_SYS (wmemmove, wchar_t *, + (wchar_t *dest, const wchar_t *src, size_t n)); +# endif +_GL_CXXALIAS_SYS (wmemmove, wchar_t *, + (wchar_t *dest, const wchar_t *src, size_t n)); +_GL_CXXALIASWARN (wmemmove); +#elif defined GNULIB_POSIXCHECK +# undef wmemmove +# if HAVE_RAW_DECL_WMEMMOVE +_GL_WARN_ON_USE (wmemmove, "wmemmove is unportable - " + "use gnulib module wmemmove for portability"); +# endif +#endif + + +/* Set N wide characters of S to C. */ +#if @GNULIB_WMEMSET@ +# if !@HAVE_WMEMSET@ +_GL_FUNCDECL_SYS (wmemset, wchar_t *, (wchar_t *s, wchar_t c, size_t n))= ; +# endif +_GL_CXXALIAS_SYS (wmemset, wchar_t *, (wchar_t *s, wchar_t c, size_t n))= ; +_GL_CXXALIASWARN (wmemset); +#elif defined GNULIB_POSIXCHECK +# undef wmemset +# if HAVE_RAW_DECL_WMEMSET +_GL_WARN_ON_USE (wmemset, "wmemset is unportable - " + "use gnulib module wmemset for portability"); +# endif +#endif + + +/* Return the number of wide characters in S. */ +#if @GNULIB_WCSLEN@ +# if !@HAVE_WCSLEN@ +_GL_FUNCDECL_SYS (wcslen, size_t, (const wchar_t *s) _GL_ATTRIBUTE_PURE)= ; +# endif +_GL_CXXALIAS_SYS (wcslen, size_t, (const wchar_t *s)); +_GL_CXXALIASWARN (wcslen); +#elif defined GNULIB_POSIXCHECK +# undef wcslen +# if HAVE_RAW_DECL_WCSLEN +_GL_WARN_ON_USE (wcslen, "wcslen is unportable - " + "use gnulib module wcslen for portability"); +# endif +#endif + + +/* Return the number of wide characters in S, but at most MAXLEN. */ +#if @GNULIB_WCSNLEN@ +# if !@HAVE_WCSNLEN@ +_GL_FUNCDECL_SYS (wcsnlen, size_t, (const wchar_t *s, size_t maxlen) + _GL_ATTRIBUTE_PURE); +# endif +_GL_CXXALIAS_SYS (wcsnlen, size_t, (const wchar_t *s, size_t maxlen)); +_GL_CXXALIASWARN (wcsnlen); +#elif defined GNULIB_POSIXCHECK +# undef wcsnlen +# if HAVE_RAW_DECL_WCSNLEN +_GL_WARN_ON_USE (wcsnlen, "wcsnlen is unportable - " + "use gnulib module wcsnlen for portability"); +# endif +#endif + + +/* Copy SRC to DEST. */ +#if @GNULIB_WCSCPY@ +# if !@HAVE_WCSCPY@ +_GL_FUNCDECL_SYS (wcscpy, wchar_t *, (wchar_t *dest, const wchar_t *src)= ); +# endif +_GL_CXXALIAS_SYS (wcscpy, wchar_t *, (wchar_t *dest, const wchar_t *src)= ); +_GL_CXXALIASWARN (wcscpy); +#elif defined GNULIB_POSIXCHECK +# undef wcscpy +# if HAVE_RAW_DECL_WCSCPY +_GL_WARN_ON_USE (wcscpy, "wcscpy is unportable - " + "use gnulib module wcscpy for portability"); +# endif +#endif + + +/* Copy SRC to DEST, returning the address of the terminating L'\0' in D= EST. */ +#if @GNULIB_WCPCPY@ +# if !@HAVE_WCPCPY@ +_GL_FUNCDECL_SYS (wcpcpy, wchar_t *, (wchar_t *dest, const wchar_t *src)= ); +# endif +_GL_CXXALIAS_SYS (wcpcpy, wchar_t *, (wchar_t *dest, const wchar_t *src)= ); +_GL_CXXALIASWARN (wcpcpy); +#elif defined GNULIB_POSIXCHECK +# undef wcpcpy +# if HAVE_RAW_DECL_WCPCPY +_GL_WARN_ON_USE (wcpcpy, "wcpcpy is unportable - " + "use gnulib module wcpcpy for portability"); +# endif +#endif + + +/* Copy no more than N wide characters of SRC to DEST. */ +#if @GNULIB_WCSNCPY@ +# if !@HAVE_WCSNCPY@ +_GL_FUNCDECL_SYS (wcsncpy, wchar_t *, + (wchar_t *dest, const wchar_t *src, size_t n)); +# endif +_GL_CXXALIAS_SYS (wcsncpy, wchar_t *, + (wchar_t *dest, const wchar_t *src, size_t n)); +_GL_CXXALIASWARN (wcsncpy); +#elif defined GNULIB_POSIXCHECK +# undef wcsncpy +# if HAVE_RAW_DECL_WCSNCPY +_GL_WARN_ON_USE (wcsncpy, "wcsncpy is unportable - " + "use gnulib module wcsncpy for portability"); +# endif +#endif + + +/* Copy no more than N characters of SRC to DEST, returning the address = of + the last character written into DEST. */ +#if @GNULIB_WCPNCPY@ +# if !@HAVE_WCPNCPY@ +_GL_FUNCDECL_SYS (wcpncpy, wchar_t *, + (wchar_t *dest, const wchar_t *src, size_t n)); +# endif +_GL_CXXALIAS_SYS (wcpncpy, wchar_t *, + (wchar_t *dest, const wchar_t *src, size_t n)); +_GL_CXXALIASWARN (wcpncpy); +#elif defined GNULIB_POSIXCHECK +# undef wcpncpy +# if HAVE_RAW_DECL_WCPNCPY +_GL_WARN_ON_USE (wcpncpy, "wcpncpy is unportable - " + "use gnulib module wcpncpy for portability"); +# endif +#endif + + +/* Append SRC onto DEST. */ +#if @GNULIB_WCSCAT@ +# if !@HAVE_WCSCAT@ +_GL_FUNCDECL_SYS (wcscat, wchar_t *, (wchar_t *dest, const wchar_t *src)= ); +# endif +_GL_CXXALIAS_SYS (wcscat, wchar_t *, (wchar_t *dest, const wchar_t *src)= ); +_GL_CXXALIASWARN (wcscat); +#elif defined GNULIB_POSIXCHECK +# undef wcscat +# if HAVE_RAW_DECL_WCSCAT +_GL_WARN_ON_USE (wcscat, "wcscat is unportable - " + "use gnulib module wcscat for portability"); +# endif +#endif + + +/* Append no more than N wide characters of SRC onto DEST. */ +#if @GNULIB_WCSNCAT@ +# if !@HAVE_WCSNCAT@ +_GL_FUNCDECL_SYS (wcsncat, wchar_t *, + (wchar_t *dest, const wchar_t *src, size_t n)); +# endif +_GL_CXXALIAS_SYS (wcsncat, wchar_t *, + (wchar_t *dest, const wchar_t *src, size_t n)); +_GL_CXXALIASWARN (wcsncat); +#elif defined GNULIB_POSIXCHECK +# undef wcsncat +# if HAVE_RAW_DECL_WCSNCAT +_GL_WARN_ON_USE (wcsncat, "wcsncat is unportable - " + "use gnulib module wcsncat for portability"); +# endif +#endif + + +/* Compare S1 and S2. */ +#if @GNULIB_WCSCMP@ +# if !@HAVE_WCSCMP@ +_GL_FUNCDECL_SYS (wcscmp, int, (const wchar_t *s1, const wchar_t *s2) + _GL_ATTRIBUTE_PURE); +# endif +_GL_CXXALIAS_SYS (wcscmp, int, (const wchar_t *s1, const wchar_t *s2)); +_GL_CXXALIASWARN (wcscmp); +#elif defined GNULIB_POSIXCHECK +# undef wcscmp +# if HAVE_RAW_DECL_WCSCMP +_GL_WARN_ON_USE (wcscmp, "wcscmp is unportable - " + "use gnulib module wcscmp for portability"); +# endif +#endif + + +/* Compare no more than N wide characters of S1 and S2. */ +#if @GNULIB_WCSNCMP@ +# if !@HAVE_WCSNCMP@ +_GL_FUNCDECL_SYS (wcsncmp, int, + (const wchar_t *s1, const wchar_t *s2, size_t n) + _GL_ATTRIBUTE_PURE); +# endif +_GL_CXXALIAS_SYS (wcsncmp, int, + (const wchar_t *s1, const wchar_t *s2, size_t n)); +_GL_CXXALIASWARN (wcsncmp); +#elif defined GNULIB_POSIXCHECK +# undef wcsncmp +# if HAVE_RAW_DECL_WCSNCMP +_GL_WARN_ON_USE (wcsncmp, "wcsncmp is unportable - " + "use gnulib module wcsncmp for portability"); +# endif +#endif + + +/* Compare S1 and S2, ignoring case. */ +#if @GNULIB_WCSCASECMP@ +# if !@HAVE_WCSCASECMP@ +_GL_FUNCDECL_SYS (wcscasecmp, int, (const wchar_t *s1, const wchar_t *s2= ) + _GL_ATTRIBUTE_PURE); +# endif +_GL_CXXALIAS_SYS (wcscasecmp, int, (const wchar_t *s1, const wchar_t *s2= )); +_GL_CXXALIASWARN (wcscasecmp); +#elif defined GNULIB_POSIXCHECK +# undef wcscasecmp +# if HAVE_RAW_DECL_WCSCASECMP +_GL_WARN_ON_USE (wcscasecmp, "wcscasecmp is unportable - " + "use gnulib module wcscasecmp for portability"); +# endif +#endif + + +/* Compare no more than N chars of S1 and S2, ignoring case. */ +#if @GNULIB_WCSNCASECMP@ +# if !@HAVE_WCSNCASECMP@ +_GL_FUNCDECL_SYS (wcsncasecmp, int, + (const wchar_t *s1, const wchar_t *s2, size_t n) + _GL_ATTRIBUTE_PURE); +# endif +_GL_CXXALIAS_SYS (wcsncasecmp, int, + (const wchar_t *s1, const wchar_t *s2, size_t n)); +_GL_CXXALIASWARN (wcsncasecmp); +#elif defined GNULIB_POSIXCHECK +# undef wcsncasecmp +# if HAVE_RAW_DECL_WCSNCASECMP +_GL_WARN_ON_USE (wcsncasecmp, "wcsncasecmp is unportable - " + "use gnulib module wcsncasecmp for portability"); +# endif +#endif + + +/* Compare S1 and S2, both interpreted as appropriate to the LC_COLLATE + category of the current locale. */ +#if @GNULIB_WCSCOLL@ +# if !@HAVE_WCSCOLL@ +_GL_FUNCDECL_SYS (wcscoll, int, (const wchar_t *s1, const wchar_t *s2)); +# endif +_GL_CXXALIAS_SYS (wcscoll, int, (const wchar_t *s1, const wchar_t *s2)); +_GL_CXXALIASWARN (wcscoll); +#elif defined GNULIB_POSIXCHECK +# undef wcscoll +# if HAVE_RAW_DECL_WCSCOLL +_GL_WARN_ON_USE (wcscoll, "wcscoll is unportable - " + "use gnulib module wcscoll for portability"); +# endif +#endif + + +/* Transform S2 into array pointed to by S1 such that if wcscmp is appli= ed + to two transformed strings the result is the as applying 'wcscoll' to= the + original strings. */ +#if @GNULIB_WCSXFRM@ +# if !@HAVE_WCSXFRM@ +_GL_FUNCDECL_SYS (wcsxfrm, size_t, (wchar_t *s1, const wchar_t *s2, size= _t n)); +# endif +_GL_CXXALIAS_SYS (wcsxfrm, size_t, (wchar_t *s1, const wchar_t *s2, size= _t n)); +_GL_CXXALIASWARN (wcsxfrm); +#elif defined GNULIB_POSIXCHECK +# undef wcsxfrm +# if HAVE_RAW_DECL_WCSXFRM +_GL_WARN_ON_USE (wcsxfrm, "wcsxfrm is unportable - " + "use gnulib module wcsxfrm for portability"); +# endif +#endif + + +/* Duplicate S, returning an identical malloc'd string. */ +#if @GNULIB_WCSDUP@ +# if !@HAVE_WCSDUP@ +_GL_FUNCDECL_SYS (wcsdup, wchar_t *, (const wchar_t *s)); +# endif +_GL_CXXALIAS_SYS (wcsdup, wchar_t *, (const wchar_t *s)); +_GL_CXXALIASWARN (wcsdup); +#elif defined GNULIB_POSIXCHECK +# undef wcsdup +# if HAVE_RAW_DECL_WCSDUP +_GL_WARN_ON_USE (wcsdup, "wcsdup is unportable - " + "use gnulib module wcsdup for portability"); +# endif +#endif + + +/* Find the first occurrence of WC in WCS. */ +#if @GNULIB_WCSCHR@ +# if !@HAVE_WCSCHR@ +_GL_FUNCDECL_SYS (wcschr, wchar_t *, (const wchar_t *wcs, wchar_t wc) + _GL_ATTRIBUTE_PURE); +# endif + /* On some systems, this function is defined as an overloaded function= : + extern "C++" { + const wchar_t * std::wcschr (const wchar_t *, wchar_t); + wchar_t * std::wcschr (wchar_t *, wchar_t); + } */ +_GL_CXXALIAS_SYS_CAST2 (wcschr, + wchar_t *, (const wchar_t *, wchar_t), + const wchar_t *, (const wchar_t *, wchar_t)); +# if ((__GLIBC__ =3D=3D 2 && __GLIBC_MINOR__ >=3D 10) && !defined __UCLI= BC__) \ + && (__GNUC__ > 4 || (__GNUC__ =3D=3D 4 && __GNUC_MINOR__ >=3D 4)) +_GL_CXXALIASWARN1 (wcschr, wchar_t *, (wchar_t *wcs, wchar_t wc)); +_GL_CXXALIASWARN1 (wcschr, const wchar_t *, (const wchar_t *wcs, wchar_t= wc)); +# else +_GL_CXXALIASWARN (wcschr); +# endif +#elif defined GNULIB_POSIXCHECK +# undef wcschr +# if HAVE_RAW_DECL_WCSCHR +_GL_WARN_ON_USE (wcschr, "wcschr is unportable - " + "use gnulib module wcschr for portability"); +# endif +#endif + + +/* Find the last occurrence of WC in WCS. */ +#if @GNULIB_WCSRCHR@ +# if !@HAVE_WCSRCHR@ +_GL_FUNCDECL_SYS (wcsrchr, wchar_t *, (const wchar_t *wcs, wchar_t wc) + _GL_ATTRIBUTE_PURE); +# endif + /* On some systems, this function is defined as an overloaded function= : + extern "C++" { + const wchar_t * std::wcsrchr (const wchar_t *, wchar_t); + wchar_t * std::wcsrchr (wchar_t *, wchar_t); + } */ +_GL_CXXALIAS_SYS_CAST2 (wcsrchr, + wchar_t *, (const wchar_t *, wchar_t), + const wchar_t *, (const wchar_t *, wchar_t)); +# if ((__GLIBC__ =3D=3D 2 && __GLIBC_MINOR__ >=3D 10) && !defined __UCLI= BC__) \ + && (__GNUC__ > 4 || (__GNUC__ =3D=3D 4 && __GNUC_MINOR__ >=3D 4)) +_GL_CXXALIASWARN1 (wcsrchr, wchar_t *, (wchar_t *wcs, wchar_t wc)); +_GL_CXXALIASWARN1 (wcsrchr, const wchar_t *, (const wchar_t *wcs, wchar_= t wc)); +# else +_GL_CXXALIASWARN (wcsrchr); +# endif +#elif defined GNULIB_POSIXCHECK +# undef wcsrchr +# if HAVE_RAW_DECL_WCSRCHR +_GL_WARN_ON_USE (wcsrchr, "wcsrchr is unportable - " + "use gnulib module wcsrchr for portability"); +# endif +#endif + + +/* Return the length of the initial segmet of WCS which consists entirel= y + of wide characters not in REJECT. */ +#if @GNULIB_WCSCSPN@ +# if !@HAVE_WCSCSPN@ +_GL_FUNCDECL_SYS (wcscspn, size_t, (const wchar_t *wcs, const wchar_t *r= eject) + _GL_ATTRIBUTE_PURE); +# endif +_GL_CXXALIAS_SYS (wcscspn, size_t, (const wchar_t *wcs, const wchar_t *r= eject)); +_GL_CXXALIASWARN (wcscspn); +#elif defined GNULIB_POSIXCHECK +# undef wcscspn +# if HAVE_RAW_DECL_WCSCSPN +_GL_WARN_ON_USE (wcscspn, "wcscspn is unportable - " + "use gnulib module wcscspn for portability"); +# endif +#endif + + +/* Return the length of the initial segmet of WCS which consists entirel= y + of wide characters in ACCEPT. */ +#if @GNULIB_WCSSPN@ +# if !@HAVE_WCSSPN@ +_GL_FUNCDECL_SYS (wcsspn, size_t, (const wchar_t *wcs, const wchar_t *ac= cept) + _GL_ATTRIBUTE_PURE); +# endif +_GL_CXXALIAS_SYS (wcsspn, size_t, (const wchar_t *wcs, const wchar_t *ac= cept)); +_GL_CXXALIASWARN (wcsspn); +#elif defined GNULIB_POSIXCHECK +# undef wcsspn +# if HAVE_RAW_DECL_WCSSPN +_GL_WARN_ON_USE (wcsspn, "wcsspn is unportable - " + "use gnulib module wcsspn for portability"); +# endif +#endif + + +/* Find the first occurrence in WCS of any character in ACCEPT. */ +#if @GNULIB_WCSPBRK@ +# if !@HAVE_WCSPBRK@ +_GL_FUNCDECL_SYS (wcspbrk, wchar_t *, + (const wchar_t *wcs, const wchar_t *accept) + _GL_ATTRIBUTE_PURE); +# endif + /* On some systems, this function is defined as an overloaded function= : + extern "C++" { + const wchar_t * std::wcspbrk (const wchar_t *, const wchar_t *)= ; + wchar_t * std::wcspbrk (wchar_t *, const wchar_t *); + } */ +_GL_CXXALIAS_SYS_CAST2 (wcspbrk, + wchar_t *, (const wchar_t *, const wchar_t *), + const wchar_t *, (const wchar_t *, const wchar_t= *)); +# if ((__GLIBC__ =3D=3D 2 && __GLIBC_MINOR__ >=3D 10) && !defined __UCLI= BC__) \ + && (__GNUC__ > 4 || (__GNUC__ =3D=3D 4 && __GNUC_MINOR__ >=3D 4)) +_GL_CXXALIASWARN1 (wcspbrk, wchar_t *, + (wchar_t *wcs, const wchar_t *accept)); +_GL_CXXALIASWARN1 (wcspbrk, const wchar_t *, + (const wchar_t *wcs, const wchar_t *accept)); +# else +_GL_CXXALIASWARN (wcspbrk); +# endif +#elif defined GNULIB_POSIXCHECK +# undef wcspbrk +# if HAVE_RAW_DECL_WCSPBRK +_GL_WARN_ON_USE (wcspbrk, "wcspbrk is unportable - " + "use gnulib module wcspbrk for portability"); +# endif +#endif + + +/* Find the first occurrence of NEEDLE in HAYSTACK. */ +#if @GNULIB_WCSSTR@ +# if !@HAVE_WCSSTR@ +_GL_FUNCDECL_SYS (wcsstr, wchar_t *, + (const wchar_t *haystack, const wchar_t *needle) + _GL_ATTRIBUTE_PURE); +# endif + /* On some systems, this function is defined as an overloaded function= : + extern "C++" { + const wchar_t * std::wcsstr (const wchar_t *, const wchar_t *); + wchar_t * std::wcsstr (wchar_t *, const wchar_t *); + } */ +_GL_CXXALIAS_SYS_CAST2 (wcsstr, + wchar_t *, (const wchar_t *, const wchar_t *), + const wchar_t *, (const wchar_t *, const wchar_t= *)); +# if ((__GLIBC__ =3D=3D 2 && __GLIBC_MINOR__ >=3D 10) && !defined __UCLI= BC__) \ + && (__GNUC__ > 4 || (__GNUC__ =3D=3D 4 && __GNUC_MINOR__ >=3D 4)) +_GL_CXXALIASWARN1 (wcsstr, wchar_t *, + (wchar_t *haystack, const wchar_t *needle)); +_GL_CXXALIASWARN1 (wcsstr, const wchar_t *, + (const wchar_t *haystack, const wchar_t *needle)); +# else +_GL_CXXALIASWARN (wcsstr); +# endif +#elif defined GNULIB_POSIXCHECK +# undef wcsstr +# if HAVE_RAW_DECL_WCSSTR +_GL_WARN_ON_USE (wcsstr, "wcsstr is unportable - " + "use gnulib module wcsstr for portability"); +# endif +#endif + + +/* Divide WCS into tokens separated by characters in DELIM. */ +#if @GNULIB_WCSTOK@ +# if !@HAVE_WCSTOK@ +_GL_FUNCDECL_SYS (wcstok, wchar_t *, + (wchar_t *wcs, const wchar_t *delim, wchar_t **ptr)); +# endif +_GL_CXXALIAS_SYS (wcstok, wchar_t *, + (wchar_t *wcs, const wchar_t *delim, wchar_t **ptr)); +_GL_CXXALIASWARN (wcstok); +#elif defined GNULIB_POSIXCHECK +# undef wcstok +# if HAVE_RAW_DECL_WCSTOK +_GL_WARN_ON_USE (wcstok, "wcstok is unportable - " + "use gnulib module wcstok for portability"); +# endif +#endif + + +/* Determine number of column positions required for first N wide + characters (or fewer if S ends before this) in S. */ +#if @GNULIB_WCSWIDTH@ +# if @REPLACE_WCSWIDTH@ +# if !(defined __cplusplus && defined GNULIB_NAMESPACE) +# undef wcswidth +# define wcswidth rpl_wcswidth +# endif +_GL_FUNCDECL_RPL (wcswidth, int, (const wchar_t *s, size_t n) + _GL_ATTRIBUTE_PURE); +_GL_CXXALIAS_RPL (wcswidth, int, (const wchar_t *s, size_t n)); +# else +# if !@HAVE_WCSWIDTH@ +_GL_FUNCDECL_SYS (wcswidth, int, (const wchar_t *s, size_t n) + _GL_ATTRIBUTE_PURE); +# endif +_GL_CXXALIAS_SYS (wcswidth, int, (const wchar_t *s, size_t n)); +# endif +_GL_CXXALIASWARN (wcswidth); +#elif defined GNULIB_POSIXCHECK +# undef wcswidth +# if HAVE_RAW_DECL_WCSWIDTH +_GL_WARN_ON_USE (wcswidth, "wcswidth is unportable - " + "use gnulib module wcswidth for portability"); +# endif +#endif + + +/* Convert *TP to a date and time wide string. See + . */ +#if @GNULIB_WCSFTIME@ +# if @REPLACE_WCSFTIME@ +# if !(defined __cplusplus && defined GNULIB_NAMESPACE) +# undef wcsftime +# define wcsftime rpl_wcsftime +# endif +_GL_FUNCDECL_RPL (wcsftime, size_t, (wchar_t *__buf, size_t __bufsize, + const wchar_t *__fmt, const struct = tm *__tp) + _GL_ARG_NONNULL ((1, 3, 4))); +_GL_CXXALIAS_RPL (wcsftime, size_t, (wchar_t *__buf, size_t __bufsize, + const wchar_t *__fmt, const struct = tm *__tp)); +# else +# if !@HAVE_WCSFTIME@ +_GL_FUNCDECL_SYS (wcsftime, size_t, (wchar_t *__buf, size_t __bufsize, + const wchar_t *__fmt, const struct = tm *__tp) + _GL_ARG_NONNULL ((1, 3, 4))); +# endif +_GL_CXXALIAS_SYS (wcsftime, size_t, (wchar_t *__buf, size_t __bufsize, + const wchar_t *__fmt, const struct = tm *__tp)); +# endif +_GL_CXXALIASWARN (wcsftime); +#elif defined GNULIB_POSIXCHECK +# undef wcsftime +# if HAVE_RAW_DECL_WCSFTIME +_GL_WARN_ON_USE (wcsftime, "wcsftime is unportable - " + "use gnulib module wcsftime for portability"); +# endif +#endif + + +#endif /* _@GUARD_PREFIX@_WCHAR_H */ +#endif /* _@GUARD_PREFIX@_WCHAR_H */ +#endif diff --git a/lib/wcrtomb.c b/lib/wcrtomb.c new file mode 100644 index 0000000000..8f01972144 --- /dev/null +++ b/lib/wcrtomb.c @@ -0,0 +1,53 @@ +/* Convert wide character to multibyte character. + Copyright (C) 2008-2018 Free Software Foundation, Inc. + Written by Bruno Haible , 2008. + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see = . */ + +#include + +/* Specification. */ +#include + +#include +#include + + +size_t +wcrtomb (char *s, wchar_t wc, mbstate_t *ps) +{ + /* This implementation of wcrtomb on top of wctomb() supports only + stateless encodings. ps must be in the initial state. */ + if (ps !=3D NULL && !mbsinit (ps)) + { + errno =3D EINVAL; + return (size_t)(-1); + } + + if (s =3D=3D NULL) + /* We know the NUL wide character corresponds to the NUL character. = */ + return 1; + else + { + int ret =3D wctomb (s, wc); + + if (ret >=3D 0) + return ret; + else + { + errno =3D EILSEQ; + return (size_t)(-1); + } + } +} diff --git a/lib/wctype-h.c b/lib/wctype-h.c new file mode 100644 index 0000000000..bb5f847e33 --- /dev/null +++ b/lib/wctype-h.c @@ -0,0 +1,4 @@ +/* Normally this would be wctype.c, but that name's already taken. */ +#include +#define _GL_WCTYPE_INLINE _GL_EXTERN_INLINE +#include "wctype.h" diff --git a/lib/wctype.in.h b/lib/wctype.in.h new file mode 100644 index 0000000000..3c6e5f2903 --- /dev/null +++ b/lib/wctype.in.h @@ -0,0 +1,533 @@ +/* A substitute for ISO C99 , for platforms that lack it. + + Copyright (C) 2006-2018 Free Software Foundation, Inc. + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 3, or (at your option) + any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, see .= */ + +/* Written by Bruno Haible and Paul Eggert. */ + +/* + * ISO C 99 for platforms that lack it. + * + * + * iswctype, towctrans, towlower, towupper, wctrans, wctype, + * wctrans_t, and wctype_t are not yet implemented. + */ + +#if __GNUC__ >=3D 3 +@PRAGMA_SYSTEM_HEADER@ +#endif +@PRAGMA_COLUMNS@ + +#if (defined __MINGW32__ && defined __CTYPE_H_SOURCED__) + +/* Special invocation convention: + - With MinGW 3.22, when includes , only some part= of + is being processed, which doesn't include the idempotenc= y + guard. */ + +#@INCLUDE_NEXT@ @NEXT_WCTYPE_H@ + +#else +/* Normal invocation convention. */ + +#ifndef _@GUARD_PREFIX@_WCTYPE_H + +#if @HAVE_WINT_T@ +/* Solaris 2.5 has a bug: must be included before . + Tru64 with Desktop Toolkit C has a bug: must be included be= fore + . + BSD/OS 4.0.1 has a bug: , and must be + included before . */ +# include +# include +# include +# include +#endif + +/* Native Windows (mingw, MSVC) have declarations of towupper, towlower,= and + isw* functions in , as well as in . Inc= lude + , in advance to avoid rpl_ prefix being added to t= he + declarations. */ +#if defined _WIN32 && ! defined __CYGWIN__ +# include +# include +#endif + +/* Include the original if it exists. + BeOS 5 has the functions but no . */ +/* The include_next requires a split double-inclusion guard. */ +#if @HAVE_WCTYPE_H@ +# @INCLUDE_NEXT@ @NEXT_WCTYPE_H@ +#endif + +#ifndef _@GUARD_PREFIX@_WCTYPE_H +#define _@GUARD_PREFIX@_WCTYPE_H + +#ifndef _GL_INLINE_HEADER_BEGIN + #error "Please include config.h first." +#endif +_GL_INLINE_HEADER_BEGIN +#ifndef _GL_WCTYPE_INLINE +# define _GL_WCTYPE_INLINE _GL_INLINE +#endif + +/* The definitions of _GL_FUNCDECL_RPL etc. are copied here. */ + +/* The definition of _GL_WARN_ON_USE is copied here. */ + +/* Solaris 2.6 includes which includes whic= h + #defines a number of identifiers in the application namespace. Rever= t + these #defines. */ +#ifdef __sun +# undef multibyte +# undef eucw1 +# undef eucw2 +# undef eucw3 +# undef scrw1 +# undef scrw2 +# undef scrw3 +#endif + +/* Define wint_t and WEOF. (Also done in wchar.in.h.) */ +#if !@HAVE_WINT_T@ && !defined wint_t +# define wint_t int +# ifndef WEOF +# define WEOF -1 +# endif +#else +/* mingw and MSVC define wint_t as 'unsigned short' in or + . This is too small: ISO C 99 section 7.24.1.(2) says that + wint_t must be "unchanged by default argument promotions". Override = it. */ +# if @GNULIB_OVERRIDES_WINT_T@ +# if !GNULIB_defined_wint_t +# if @HAVE_CRTDEFS_H@ +# include +# else +# include +# endif +typedef unsigned int rpl_wint_t; +# undef wint_t +# define wint_t rpl_wint_t +# define GNULIB_defined_wint_t 1 +# endif +# endif +# ifndef WEOF +# define WEOF ((wint_t) -1) +# endif +#endif + + +#if !GNULIB_defined_wctype_functions + +/* FreeBSD 4.4 to 4.11 has but lacks the functions. + Linux libc5 has and the functions but they are broken. + Assume all 11 functions (all isw* except iswblank) are implemented th= e + same way, or not at all. */ +# if ! @HAVE_ISWCNTRL@ || @REPLACE_ISWCNTRL@ + +/* IRIX 5.3 has macros but no functions, its isw* macros refer to an + undefined variable _ctmp_ and to macros like _P, and they + refer to system functions like _iswctype that are not in the + standard C library. Rather than try to get ancient buggy + implementations like this to work, just disable them. */ +# undef iswalnum +# undef iswalpha +# undef iswblank +# undef iswcntrl +# undef iswdigit +# undef iswgraph +# undef iswlower +# undef iswprint +# undef iswpunct +# undef iswspace +# undef iswupper +# undef iswxdigit +# undef towlower +# undef towupper + +/* Linux libc5 has and the functions but they are broken. */ +# if @REPLACE_ISWCNTRL@ +# if !(defined __cplusplus && defined GNULIB_NAMESPACE) +# define iswalnum rpl_iswalnum +# define iswalpha rpl_iswalpha +# define iswblank rpl_iswblank +# define iswcntrl rpl_iswcntrl +# define iswdigit rpl_iswdigit +# define iswgraph rpl_iswgraph +# define iswlower rpl_iswlower +# define iswprint rpl_iswprint +# define iswpunct rpl_iswpunct +# define iswspace rpl_iswspace +# define iswupper rpl_iswupper +# define iswxdigit rpl_iswxdigit +# endif +# endif +# if @REPLACE_TOWLOWER@ +# if !(defined __cplusplus && defined GNULIB_NAMESPACE) +# define towlower rpl_towlower +# define towupper rpl_towupper +# endif +# endif + +_GL_WCTYPE_INLINE int +# if @REPLACE_ISWCNTRL@ +rpl_iswalnum +# else +iswalnum +# endif + (wint_t wc) +{ + return ((wc >=3D '0' && wc <=3D '9') + || ((wc & ~0x20) >=3D 'A' && (wc & ~0x20) <=3D 'Z')); +} + +_GL_WCTYPE_INLINE int +# if @REPLACE_ISWCNTRL@ +rpl_iswalpha +# else +iswalpha +# endif + (wint_t wc) +{ + return (wc & ~0x20) >=3D 'A' && (wc & ~0x20) <=3D 'Z'; +} + +_GL_WCTYPE_INLINE int +# if @REPLACE_ISWCNTRL@ +rpl_iswblank +# else +iswblank +# endif + (wint_t wc) +{ + return wc =3D=3D ' ' || wc =3D=3D '\t'; +} + +_GL_WCTYPE_INLINE int +# if @REPLACE_ISWCNTRL@ +rpl_iswcntrl +# else +iswcntrl +# endif + (wint_t wc) +{ + return (wc & ~0x1f) =3D=3D 0 || wc =3D=3D 0x7f; +} + +_GL_WCTYPE_INLINE int +# if @REPLACE_ISWCNTRL@ +rpl_iswdigit +# else +iswdigit +# endif + (wint_t wc) +{ + return wc >=3D '0' && wc <=3D '9'; +} + +_GL_WCTYPE_INLINE int +# if @REPLACE_ISWCNTRL@ +rpl_iswgraph +# else +iswgraph +# endif + (wint_t wc) +{ + return wc >=3D '!' && wc <=3D '~'; +} + +_GL_WCTYPE_INLINE int +# if @REPLACE_ISWCNTRL@ +rpl_iswlower +# else +iswlower +# endif + (wint_t wc) +{ + return wc >=3D 'a' && wc <=3D 'z'; +} + +_GL_WCTYPE_INLINE int +# if @REPLACE_ISWCNTRL@ +rpl_iswprint +# else +iswprint +# endif + (wint_t wc) +{ + return wc >=3D ' ' && wc <=3D '~'; +} + +_GL_WCTYPE_INLINE int +# if @REPLACE_ISWCNTRL@ +rpl_iswpunct +# else +iswpunct +# endif + (wint_t wc) +{ + return (wc >=3D '!' && wc <=3D '~' + && !((wc >=3D '0' && wc <=3D '9') + || ((wc & ~0x20) >=3D 'A' && (wc & ~0x20) <=3D 'Z'))); +} + +_GL_WCTYPE_INLINE int +# if @REPLACE_ISWCNTRL@ +rpl_iswspace +# else +iswspace +# endif + (wint_t wc) +{ + return (wc =3D=3D ' ' || wc =3D=3D '\t' + || wc =3D=3D '\n' || wc =3D=3D '\v' || wc =3D=3D '\f' || wc =3D= =3D '\r'); +} + +_GL_WCTYPE_INLINE int +# if @REPLACE_ISWCNTRL@ +rpl_iswupper +# else +iswupper +# endif + (wint_t wc) +{ + return wc >=3D 'A' && wc <=3D 'Z'; +} + +_GL_WCTYPE_INLINE int +# if @REPLACE_ISWCNTRL@ +rpl_iswxdigit +# else +iswxdigit +# endif + (wint_t wc) +{ + return ((wc >=3D '0' && wc <=3D '9') + || ((wc & ~0x20) >=3D 'A' && (wc & ~0x20) <=3D 'F')); +} + +_GL_WCTYPE_INLINE wint_t +# if @REPLACE_TOWLOWER@ +rpl_towlower +# else +towlower +# endif + (wint_t wc) +{ + return (wc >=3D 'A' && wc <=3D 'Z' ? wc - 'A' + 'a' : wc); +} + +_GL_WCTYPE_INLINE wint_t +# if @REPLACE_TOWLOWER@ +rpl_towupper +# else +towupper +# endif + (wint_t wc) +{ + return (wc >=3D 'a' && wc <=3D 'z' ? wc - 'a' + 'A' : wc); +} + +# elif @GNULIB_ISWBLANK@ && (! @HAVE_ISWBLANK@ || @REPLACE_ISWBLANK@) +/* Only the iswblank function is missing. */ + +# if @REPLACE_ISWBLANK@ +# if !(defined __cplusplus && defined GNULIB_NAMESPACE) +# define iswblank rpl_iswblank +# endif +_GL_FUNCDECL_RPL (iswblank, int, (wint_t wc)); +# else +_GL_FUNCDECL_SYS (iswblank, int, (wint_t wc)); +# endif + +# endif + +# if defined __MINGW32__ + +/* On native Windows, wchar_t is uint16_t, and wint_t is uint32_t. + The functions towlower and towupper are implemented in the MSVCRT lib= rary + to take a wchar_t argument and return a wchar_t result. mingw declar= es + these functions to take a wint_t argument and return a wint_t result. + This means that: + 1. When the user passes an argument outside the range 0x0000..0xFFFF,= the + function will look only at the lower 16 bits. This is allowed acc= ording + to POSIX. + 2. The return value is returned in the lower 16 bits of the result re= gister. + The upper 16 bits are random: whatever happened to be in that part= of the + result register. We need to fix this by adding a zero-extend from + wchar_t to wint_t after the call. */ + +_GL_WCTYPE_INLINE wint_t +rpl_towlower (wint_t wc) +{ + return (wint_t) (wchar_t) towlower (wc); +} +# if !(defined __cplusplus && defined GNULIB_NAMESPACE) +# define towlower rpl_towlower +# endif + +_GL_WCTYPE_INLINE wint_t +rpl_towupper (wint_t wc) +{ + return (wint_t) (wchar_t) towupper (wc); +} +# if !(defined __cplusplus && defined GNULIB_NAMESPACE) +# define towupper rpl_towupper +# endif + +# endif /* __MINGW32__ */ + +# define GNULIB_defined_wctype_functions 1 +#endif + +#if @REPLACE_ISWCNTRL@ +_GL_CXXALIAS_RPL (iswalnum, int, (wint_t wc)); +_GL_CXXALIAS_RPL (iswalpha, int, (wint_t wc)); +_GL_CXXALIAS_RPL (iswcntrl, int, (wint_t wc)); +_GL_CXXALIAS_RPL (iswdigit, int, (wint_t wc)); +_GL_CXXALIAS_RPL (iswgraph, int, (wint_t wc)); +_GL_CXXALIAS_RPL (iswlower, int, (wint_t wc)); +_GL_CXXALIAS_RPL (iswprint, int, (wint_t wc)); +_GL_CXXALIAS_RPL (iswpunct, int, (wint_t wc)); +_GL_CXXALIAS_RPL (iswspace, int, (wint_t wc)); +_GL_CXXALIAS_RPL (iswupper, int, (wint_t wc)); +_GL_CXXALIAS_RPL (iswxdigit, int, (wint_t wc)); +#else +_GL_CXXALIAS_SYS (iswalnum, int, (wint_t wc)); +_GL_CXXALIAS_SYS (iswalpha, int, (wint_t wc)); +_GL_CXXALIAS_SYS (iswcntrl, int, (wint_t wc)); +_GL_CXXALIAS_SYS (iswdigit, int, (wint_t wc)); +_GL_CXXALIAS_SYS (iswgraph, int, (wint_t wc)); +_GL_CXXALIAS_SYS (iswlower, int, (wint_t wc)); +_GL_CXXALIAS_SYS (iswprint, int, (wint_t wc)); +_GL_CXXALIAS_SYS (iswpunct, int, (wint_t wc)); +_GL_CXXALIAS_SYS (iswspace, int, (wint_t wc)); +_GL_CXXALIAS_SYS (iswupper, int, (wint_t wc)); +_GL_CXXALIAS_SYS (iswxdigit, int, (wint_t wc)); +#endif +_GL_CXXALIASWARN (iswalnum); +_GL_CXXALIASWARN (iswalpha); +_GL_CXXALIASWARN (iswcntrl); +_GL_CXXALIASWARN (iswdigit); +_GL_CXXALIASWARN (iswgraph); +_GL_CXXALIASWARN (iswlower); +_GL_CXXALIASWARN (iswprint); +_GL_CXXALIASWARN (iswpunct); +_GL_CXXALIASWARN (iswspace); +_GL_CXXALIASWARN (iswupper); +_GL_CXXALIASWARN (iswxdigit); + +#if @GNULIB_ISWBLANK@ +# if @REPLACE_ISWCNTRL@ || @REPLACE_ISWBLANK@ +_GL_CXXALIAS_RPL (iswblank, int, (wint_t wc)); +# else +_GL_CXXALIAS_SYS (iswblank, int, (wint_t wc)); +# endif +_GL_CXXALIASWARN (iswblank); +#endif + +#if !@HAVE_WCTYPE_T@ +# if !GNULIB_defined_wctype_t +typedef void * wctype_t; +# define GNULIB_defined_wctype_t 1 +# endif +#endif + +/* Get a descriptor for a wide character property. */ +#if @GNULIB_WCTYPE@ +# if !@HAVE_WCTYPE_T@ +_GL_FUNCDECL_SYS (wctype, wctype_t, (const char *name)); +# endif +_GL_CXXALIAS_SYS (wctype, wctype_t, (const char *name)); +_GL_CXXALIASWARN (wctype); +#elif defined GNULIB_POSIXCHECK +# undef wctype +# if HAVE_RAW_DECL_WCTYPE +_GL_WARN_ON_USE (wctype, "wctype is unportable - " + "use gnulib module wctype for portability"); +# endif +#endif + +/* Test whether a wide character has a given property. + The argument WC must be either a wchar_t value or WEOF. + The argument DESC must have been returned by the wctype() function. = */ +#if @GNULIB_ISWCTYPE@ +# if !@HAVE_WCTYPE_T@ +_GL_FUNCDECL_SYS (iswctype, int, (wint_t wc, wctype_t desc)); +# endif +_GL_CXXALIAS_SYS (iswctype, int, (wint_t wc, wctype_t desc)); +_GL_CXXALIASWARN (iswctype); +#elif defined GNULIB_POSIXCHECK +# undef iswctype +# if HAVE_RAW_DECL_ISWCTYPE +_GL_WARN_ON_USE (iswctype, "iswctype is unportable - " + "use gnulib module iswctype for portability"); +# endif +#endif + +#if @REPLACE_TOWLOWER@ || defined __MINGW32__ +_GL_CXXALIAS_RPL (towlower, wint_t, (wint_t wc)); +_GL_CXXALIAS_RPL (towupper, wint_t, (wint_t wc)); +#else +_GL_CXXALIAS_SYS (towlower, wint_t, (wint_t wc)); +_GL_CXXALIAS_SYS (towupper, wint_t, (wint_t wc)); +#endif +_GL_CXXALIASWARN (towlower); +_GL_CXXALIASWARN (towupper); + +#if !@HAVE_WCTRANS_T@ +# if !GNULIB_defined_wctrans_t +typedef void * wctrans_t; +# define GNULIB_defined_wctrans_t 1 +# endif +#endif + +/* Get a descriptor for a wide character case conversion. */ +#if @GNULIB_WCTRANS@ +# if !@HAVE_WCTRANS_T@ +_GL_FUNCDECL_SYS (wctrans, wctrans_t, (const char *name)); +# endif +_GL_CXXALIAS_SYS (wctrans, wctrans_t, (const char *name)); +_GL_CXXALIASWARN (wctrans); +#elif defined GNULIB_POSIXCHECK +# undef wctrans +# if HAVE_RAW_DECL_WCTRANS +_GL_WARN_ON_USE (wctrans, "wctrans is unportable - " + "use gnulib module wctrans for portability"); +# endif +#endif + +/* Perform a given case conversion on a wide character. + The argument WC must be either a wchar_t value or WEOF. + The argument DESC must have been returned by the wctrans() function. = */ +#if @GNULIB_TOWCTRANS@ +# if !@HAVE_WCTRANS_T@ +_GL_FUNCDECL_SYS (towctrans, wint_t, (wint_t wc, wctrans_t desc)); +# endif +_GL_CXXALIAS_SYS (towctrans, wint_t, (wint_t wc, wctrans_t desc)); +_GL_CXXALIASWARN (towctrans); +#elif defined GNULIB_POSIXCHECK +# undef towctrans +# if HAVE_RAW_DECL_TOWCTRANS +_GL_WARN_ON_USE (towctrans, "towctrans is unportable - " + "use gnulib module towctrans for portability"); +# endif +#endif + +_GL_INLINE_HEADER_END + +#endif /* _@GUARD_PREFIX@_WCTYPE_H */ +#endif /* _@GUARD_PREFIX@_WCTYPE_H */ +#endif diff --git a/lisp/char-fold.el b/lisp/char-fold.el index 9c05e364df..311fe885a9 100644 --- a/lisp/char-fold.el +++ b/lisp/char-fold.el @@ -214,7 +214,7 @@ char-fold-to-regexp (when (> spaces 0) (push (char-fold--make-space-string spaces) out)) (let ((regexp (apply #'concat (nreverse out)))) - ;; Limited by `MAX_BUF_SIZE' in `regex.c'. + ;; Limited by MAX_BUF_SIZE in regex-emacs.c. (if (> (length regexp) 5000) (regexp-quote string) regexp)))) diff --git a/m4/btowc.m4 b/m4/btowc.m4 new file mode 100644 index 0000000000..8acdffc514 --- /dev/null +++ b/m4/btowc.m4 @@ -0,0 +1,120 @@ +# btowc.m4 serial 11 +dnl Copyright (C) 2008-2018 Free Software Foundation, Inc. +dnl This file is free software; the Free Software Foundation +dnl gives unlimited permission to copy and/or distribute it, +dnl with or without modifications, as long as this notice is preserved. + +AC_DEFUN([gl_FUNC_BTOWC], +[ + AC_REQUIRE([gl_WCHAR_H_DEFAULTS]) + + dnl Check whether is usable at all, first. Otherwise the tes= t + dnl program below may lead to an endless loop. See + dnl . + AC_REQUIRE([gl_WCHAR_H_INLINE_OK]) + + AC_CHECK_FUNCS_ONCE([btowc]) + if test $ac_cv_func_btowc =3D no; then + HAVE_BTOWC=3D0 + else + + AC_REQUIRE([AC_PROG_CC]) + AC_REQUIRE([gt_LOCALE_FR]) + AC_REQUIRE([AC_CANONICAL_HOST]) dnl for cross-compiles + + dnl Cygwin 1.7.2 btowc('\0') is WEOF, not 0. + AC_CACHE_CHECK([whether btowc(0) is correct], + [gl_cv_func_btowc_nul], + [ + AC_RUN_IFELSE( + [AC_LANG_SOURCE([[ +#include +/* Tru64 with Desktop Toolkit C has a bug: must be included be= fore + . + BSD/OS 4.0.1 has a bug: , and must be + included before . */ +#include +#include +#include +#include +int main () +{ + if (btowc ('\0') !=3D 0) + return 1; + return 0; +}]])], + [gl_cv_func_btowc_nul=3Dyes], + [gl_cv_func_btowc_nul=3Dno], + [ +changequote(,)dnl + case "$host_os" in + # Guess no on Cygwin. + cygwin*) gl_cv_func_btowc_nul=3D"guessing no" ;; + # Guess yes on native Windows. + mingw*) gl_cv_func_btowc_nul=3D"guessing yes" ;; + # Guess yes otherwise. + *) gl_cv_func_btowc_nul=3D"guessing yes" ;; + esac +changequote([,])dnl + ]) + ]) + + dnl IRIX 6.5 btowc(EOF) is 0xFF, not WEOF. + AC_CACHE_CHECK([whether btowc(EOF) is correct], + [gl_cv_func_btowc_eof], + [ + dnl Initial guess, used when cross-compiling or when no suitable= locale + dnl is present. +changequote(,)dnl + case "$host_os" in + # Guess no on IRIX. + irix*) gl_cv_func_btowc_eof=3D"guessing no" ;; + # Guess yes on native Windows. + mingw*) gl_cv_func_btowc_eof=3D"guessing yes" ;; + # Guess yes otherwise. + *) gl_cv_func_btowc_eof=3D"guessing yes" ;; + esac +changequote([,])dnl + if test $LOCALE_FR !=3D none; then + AC_RUN_IFELSE( + [AC_LANG_SOURCE([[ +#include +#include +/* Tru64 with Desktop Toolkit C has a bug: must be included be= fore + . + BSD/OS 4.0.1 has a bug: , and must be + included before . */ +#include +#include +#include +#include +int main () +{ + if (setlocale (LC_ALL, "$LOCALE_FR") !=3D NULL) + { + if (btowc (EOF) !=3D WEOF) + return 1; + } + return 0; +}]])], + [gl_cv_func_btowc_eof=3Dyes], + [gl_cv_func_btowc_eof=3Dno], + [:]) + fi + ]) + + case "$gl_cv_func_btowc_nul" in + *yes) ;; + *) REPLACE_BTOWC=3D1 ;; + esac + case "$gl_cv_func_btowc_eof" in + *yes) ;; + *) REPLACE_BTOWC=3D1 ;; + esac + fi +]) + +# Prerequisites of lib/btowc.c. +AC_DEFUN([gl_PREREQ_BTOWC], [ + : +]) diff --git a/m4/builtin-expect.m4 b/m4/builtin-expect.m4 new file mode 100644 index 0000000000..a1eaf965b4 --- /dev/null +++ b/m4/builtin-expect.m4 @@ -0,0 +1,49 @@ +dnl Check for __builtin_expect. + +dnl Copyright 2016-2018 Free Software Foundation, Inc. +dnl This file is free software; the Free Software Foundation +dnl gives unlimited permission to copy and/or distribute it, +dnl with or without modifications, as long as this notice is preserved. + +dnl Written by Paul Eggert. + +AC_DEFUN([gl___BUILTIN_EXPECT], +[ + AC_CACHE_CHECK([for __builtin_expect], + [gl_cv___builtin_expect], + [AC_LINK_IFELSE( + [AC_LANG_SOURCE([[ + int + main (int argc, char **argv) + { + argc =3D __builtin_expect (argc, 100); + return argv[argc !=3D 100][0]; + }]])], + [gl_cv___builtin_expect=3Dyes], + [AC_LINK_IFELSE( + [AC_LANG_SOURCE([[ + #include + int + main (int argc, char **argv) + { + argc =3D __builtin_expect (argc, 100); + return argv[argc !=3D 100][0]; + }]])], + [gl_cv___builtin_expect=3D"in "], + [gl_cv___builtin_expect=3Dno])])]) + if test "$gl_cv___builtin_expect" =3D yes; then + AC_DEFINE([HAVE___BUILTIN_EXPECT], [1]) + elif test "$gl_cv___builtin_expect" =3D "in "; then + AC_DEFINE([HAVE___BUILTIN_EXPECT], [2]) + fi + AH_VERBATIM([HAVE___BUILTIN_EXPECT], + [/* Define to 1 if the compiler supports __builtin_expect, + and to 2 if does. */ +#undef HAVE___BUILTIN_EXPECT +#ifndef HAVE___BUILTIN_EXPECT +# define __builtin_expect(e, c) (e) +#elif HAVE___BUILTIN_EXPECT =3D=3D 2 +# include +#endif + ]) +]) diff --git a/m4/codeset.m4 b/m4/codeset.m4 new file mode 100644 index 0000000000..bc98201e39 --- /dev/null +++ b/m4/codeset.m4 @@ -0,0 +1,24 @@ +# codeset.m4 serial 5 (gettext-0.18.2) +dnl Copyright (C) 2000-2002, 2006, 2008-2014, 2016 Free Software Foundat= ion, +dnl Inc. +dnl This file is free software; the Free Software Foundation +dnl gives unlimited permission to copy and/or distribute it, +dnl with or without modifications, as long as this notice is preserved. + +dnl From Bruno Haible. + +AC_DEFUN([AM_LANGINFO_CODESET], +[ + AC_CACHE_CHECK([for nl_langinfo and CODESET], [am_cv_langinfo_codeset]= , + [AC_LINK_IFELSE( + [AC_LANG_PROGRAM( + [[#include ]], + [[char* cs =3D nl_langinfo(CODESET); return !cs;]])], + [am_cv_langinfo_codeset=3Dyes], + [am_cv_langinfo_codeset=3Dno]) + ]) + if test $am_cv_langinfo_codeset =3D yes; then + AC_DEFINE([HAVE_LANGINFO_CODESET], [1], + [Define if you have and nl_langinfo(CODESET).]) + fi +]) diff --git a/m4/eealloc.m4 b/m4/eealloc.m4 new file mode 100644 index 0000000000..a5a4e267d8 --- /dev/null +++ b/m4/eealloc.m4 @@ -0,0 +1,31 @@ +# eealloc.m4 serial 3 +dnl Copyright (C) 2003, 2009-2018 Free Software Foundation, Inc. +dnl This file is free software; the Free Software Foundation +dnl gives unlimited permission to copy and/or distribute it, +dnl with or without modifications, as long as this notice is preserved. + +AC_DEFUN([gl_EEALLOC], +[ + AC_REQUIRE([gl_EEMALLOC]) + AC_REQUIRE([gl_EEREALLOC]) +]) + +AC_DEFUN([gl_EEMALLOC], +[ + _AC_FUNC_MALLOC_IF( + [gl_cv_func_malloc_0_nonnull=3D1], + [gl_cv_func_malloc_0_nonnull=3D0]) + AC_DEFINE_UNQUOTED([MALLOC_0_IS_NONNULL], [$gl_cv_func_malloc_0_nonnul= l], + [If malloc(0) is !=3D NULL, define this to 1. Otherwise define this + to 0.]) +]) + +AC_DEFUN([gl_EEREALLOC], +[ + _AC_FUNC_REALLOC_IF( + [gl_cv_func_realloc_0_nonnull=3D1], + [gl_cv_func_realloc_0_nonnull=3D0]) + AC_DEFINE_UNQUOTED([REALLOC_0_IS_NONNULL], [$gl_cv_func_realloc_0_nonn= ull], + [If realloc(NULL,0) is !=3D NULL, define this to 1. Otherwise defin= e this + to 0.]) +]) diff --git a/m4/glibc21.m4 b/m4/glibc21.m4 new file mode 100644 index 0000000000..126aa1a959 --- /dev/null +++ b/m4/glibc21.m4 @@ -0,0 +1,34 @@ +# glibc21.m4 serial 5 +dnl Copyright (C) 2000-2002, 2004, 2008, 2010-2018 Free Software Foundat= ion, +dnl Inc. +dnl This file is free software; the Free Software Foundation +dnl gives unlimited permission to copy and/or distribute it, +dnl with or without modifications, as long as this notice is preserved. + +# Test for the GNU C Library, version 2.1 or newer, or uClibc. +# From Bruno Haible. + +AC_DEFUN([gl_GLIBC21], + [ + AC_CACHE_CHECK([whether we are using the GNU C Library >=3D 2.1 or u= Clibc], + [ac_cv_gnu_library_2_1], + [AC_EGREP_CPP([Lucky], + [ +#include +#ifdef __GNU_LIBRARY__ + #if (__GLIBC__ =3D=3D 2 && __GLIBC_MINOR__ >=3D 1) || (__GLIBC__ > 2) + Lucky GNU user + #endif +#endif +#ifdef __UCLIBC__ + Lucky user +#endif + ], + [ac_cv_gnu_library_2_1=3Dyes], + [ac_cv_gnu_library_2_1=3Dno]) + ] + ) + AC_SUBST([GLIBC21]) + GLIBC21=3D"$ac_cv_gnu_library_2_1" + ] +) diff --git a/m4/gnulib-comp.m4 b/m4/gnulib-comp.m4 index a6e3be3815..3118fea54b 100644 --- a/m4/gnulib-comp.m4 +++ b/m4/gnulib-comp.m4 @@ -48,6 +48,8 @@ AC_DEFUN # Code from module allocator: # Code from module at-internal: # Code from module binary-io: + # Code from module btowc: + # Code from module builtin-expect: # Code from module byteswap: # Code from module c-ctype: # Code from module c-strcase: @@ -101,22 +103,31 @@ AC_DEFUN # Code from module gettimeofday: # Code from module gitlog-to-changelog: # Code from module group-member: + # Code from module hard-locale: # Code from module ignore-value: # Code from module include_next: # Code from module intprops: # Code from module inttypes-incomplete: + # Code from module langinfo: # Code from module largefile: AC_REQUIRE([AC_SYS_LARGEFILE]) # Code from module limits-h: + # Code from module localcharset: + # Code from module locale: + # Code from module localeconv: # Code from module localtime-buffer: # Code from module lstat: # Code from module manywarnings: + # Code from module mbrtowc: + # Code from module mbsinit: + # Code from module mbtowc: # Code from module memrchr: # Code from module minmax: # Code from module mkostemp: # Code from module mktime: # Code from module mktime-internal: # Code from module multiarch: + # Code from module nl_langinfo: # Code from module nocrash: # Code from module nstrftime: # Code from module open: @@ -128,6 +139,7 @@ AC_DEFUN # Code from module qcopy-acl: # Code from module readlink: # Code from module readlinkat: + # Code from module regex: # Code from module root-uid: # Code from module sig2str: # Code from module signal-h: @@ -145,6 +157,7 @@ AC_DEFUN # Code from module stdio: # Code from module stdlib: # Code from module stpcpy: + # Code from module streq: # Code from module string: # Code from module strtoimax: # Code from module strtoll: @@ -171,6 +184,9 @@ AC_DEFUN # Code from module verify: # Code from module vla: # Code from module warnings: + # Code from module wchar: + # Code from module wcrtomb: + # Code from module wctype-h: # Code from module xalloc-oversized: ]) =20 @@ -356,6 +372,11 @@ AC_DEFUN AC_LIBOBJ([readlinkat]) fi gl_UNISTD_MODULE_INDICATOR([readlinkat]) + gl_REGEX + if test $ac_use_included_regex =3D yes; then + AC_LIBOBJ([regex]) + gl_PREREQ_REGEX + fi gl_FUNC_SIG2STR if test $ac_cv_func_sig2str =3D no; then AC_LIBOBJ([sig2str]) @@ -423,6 +444,8 @@ AC_DEFUN gl_UTIMENS AC_C_VARARRAYS gl_gnulib_enabled_260941c0e5dc67ec9e87d1fb321c300b=3Dfalse + gl_gnulib_enabled_btowc=3Dfalse + gl_gnulib_enabled_37f71b604aa9c54446783d80f42fe547=3Dfalse gl_gnulib_enabled_cloexec=3Dfalse gl_gnulib_enabled_dirfd=3Dfalse gl_gnulib_enabled_dosname=3Dfalse @@ -431,12 +454,25 @@ AC_DEFUN gl_gnulib_enabled_getgroups=3Dfalse gl_gnulib_enabled_be453cec5eecf5731a274f2de7f2db36=3Dfalse gl_gnulib_enabled_a9786850e999ae65a836a6041e8e5ed1=3Dfalse + gl_gnulib_enabled_30838f5439487421042f2225bed3af76=3Dfalse + gl_gnulib_enabled_langinfo=3Dfalse + gl_gnulib_enabled_localcharset=3Dfalse + gl_gnulib_enabled_locale=3Dfalse + gl_gnulib_enabled_localeconv=3Dfalse gl_gnulib_enabled_2049e887c7e5308faad27b3f894bb8c9=3Dfalse + gl_gnulib_enabled_mbrtowc=3Dfalse + gl_gnulib_enabled_mbsinit=3Dfalse + gl_gnulib_enabled_mbtowc=3Dfalse gl_gnulib_enabled_5264294aa0a5557541b53c8c741f7f31=3Dfalse + gl_gnulib_enabled_nl_langinfo=3Dfalse gl_gnulib_enabled_open=3Dfalse gl_gnulib_enabled_03e0aaad4cb89ca757653bd367a6ccb7=3Dfalse gl_gnulib_enabled_6099e9737f757db36c47fa9d9f02e88c=3Dfalse + gl_gnulib_enabled_streq=3Dfalse gl_gnulib_enabled_strtoll=3Dfalse + gl_gnulib_enabled_wchar=3Dfalse + gl_gnulib_enabled_wcrtomb=3Dfalse + gl_gnulib_enabled_3dcce957eadc896e63ab5f137947b410=3Dfalse gl_gnulib_enabled_682e609604ccaac6be382e4ee3a4eaec=3Dfalse func_gl_gnulib_m4code_260941c0e5dc67ec9e87d1fb321c300b () { @@ -446,6 +482,29 @@ AC_DEFUN func_gl_gnulib_m4code_open fi } + func_gl_gnulib_m4code_btowc () + { + if ! $gl_gnulib_enabled_btowc; then + gl_FUNC_BTOWC + if test $HAVE_BTOWC =3D 0 || test $REPLACE_BTOWC =3D 1; then + AC_LIBOBJ([btowc]) + gl_PREREQ_BTOWC + fi + gl_WCHAR_MODULE_INDICATOR([btowc]) + gl_gnulib_enabled_btowc=3Dtrue + if test $HAVE_BTOWC =3D 0 || test $REPLACE_BTOWC =3D 1; then + func_gl_gnulib_m4code_mbtowc + fi + func_gl_gnulib_m4code_wchar + fi + } + func_gl_gnulib_m4code_37f71b604aa9c54446783d80f42fe547 () + { + if ! $gl_gnulib_enabled_37f71b604aa9c54446783d80f42fe547; then + gl___BUILTIN_EXPECT + gl_gnulib_enabled_37f71b604aa9c54446783d80f42fe547=3Dtrue + fi + } func_gl_gnulib_m4code_cloexec () { if ! $gl_gnulib_enabled_cloexec; then @@ -537,6 +596,49 @@ AC_DEFUN fi fi } + func_gl_gnulib_m4code_30838f5439487421042f2225bed3af76 () + { + if ! $gl_gnulib_enabled_30838f5439487421042f2225bed3af76; then + gl_gnulib_enabled_30838f5439487421042f2225bed3af76=3Dtrue + fi + } + func_gl_gnulib_m4code_langinfo () + { + if ! $gl_gnulib_enabled_langinfo; then + gl_LANGINFO_H + gl_gnulib_enabled_langinfo=3Dtrue + fi + } + func_gl_gnulib_m4code_localcharset () + { + if ! $gl_gnulib_enabled_localcharset; then + gl_LOCALCHARSET + dnl For backward compatibility. Some packages still use this. + LOCALCHARSET_TESTS_ENVIRONMENT=3D + AC_SUBST([LOCALCHARSET_TESTS_ENVIRONMENT]) + gl_gnulib_enabled_localcharset=3Dtrue + fi + } + func_gl_gnulib_m4code_locale () + { + if ! $gl_gnulib_enabled_locale; then + gl_LOCALE_H + gl_gnulib_enabled_locale=3Dtrue + fi + } + func_gl_gnulib_m4code_localeconv () + { + if ! $gl_gnulib_enabled_localeconv; then + gl_FUNC_LOCALECONV + if test $REPLACE_LOCALECONV =3D 1; then + AC_LIBOBJ([localeconv]) + gl_PREREQ_LOCALECONV + fi + gl_LOCALE_MODULE_INDICATOR([localeconv]) + gl_gnulib_enabled_localeconv=3Dtrue + func_gl_gnulib_m4code_locale + fi + } func_gl_gnulib_m4code_2049e887c7e5308faad27b3f894bb8c9 () { if ! $gl_gnulib_enabled_2049e887c7e5308faad27b3f894bb8c9; then @@ -545,6 +647,65 @@ AC_DEFUN gl_gnulib_enabled_2049e887c7e5308faad27b3f894bb8c9=3Dtrue fi } + func_gl_gnulib_m4code_mbrtowc () + { + if ! $gl_gnulib_enabled_mbrtowc; then + gl_FUNC_MBRTOWC + if test $HAVE_MBRTOWC =3D 0 || test $REPLACE_MBRTOWC =3D 1; then + AC_LIBOBJ([mbrtowc]) + gl_PREREQ_MBRTOWC + fi + gl_WCHAR_MODULE_INDICATOR([mbrtowc]) + gl_gnulib_enabled_mbrtowc=3Dtrue + if test $HAVE_MBRTOWC =3D 0 || test $REPLACE_MBRTOWC =3D 1; then + func_gl_gnulib_m4code_30838f5439487421042f2225bed3af76 + fi + if test $HAVE_MBRTOWC =3D 0 || test $REPLACE_MBRTOWC =3D 1; then + func_gl_gnulib_m4code_localcharset + fi + if test $HAVE_MBRTOWC =3D 0 || test $REPLACE_MBRTOWC =3D 1; then + func_gl_gnulib_m4code_mbsinit + fi + if test $HAVE_MBRTOWC =3D 0 || test $REPLACE_MBRTOWC =3D 1; then + func_gl_gnulib_m4code_streq + fi + func_gl_gnulib_m4code_wchar + fi + } + func_gl_gnulib_m4code_mbsinit () + { + if ! $gl_gnulib_enabled_mbsinit; then + gl_FUNC_MBSINIT + if test $HAVE_MBSINIT =3D 0 || test $REPLACE_MBSINIT =3D 1; then + AC_LIBOBJ([mbsinit]) + gl_PREREQ_MBSINIT + fi + gl_WCHAR_MODULE_INDICATOR([mbsinit]) + gl_gnulib_enabled_mbsinit=3Dtrue + if test $HAVE_MBSINIT =3D 0 || test $REPLACE_MBSINIT =3D 1; then + func_gl_gnulib_m4code_mbrtowc + fi + func_gl_gnulib_m4code_wchar + fi + } + func_gl_gnulib_m4code_mbtowc () + { + if ! $gl_gnulib_enabled_mbtowc; then + gl_FUNC_MBTOWC + if test $REPLACE_MBTOWC =3D 1; then + AC_LIBOBJ([mbtowc]) + gl_PREREQ_MBTOWC + fi + gl_STDLIB_MODULE_INDICATOR([mbtowc]) + gl_gnulib_enabled_mbtowc=3Dtrue + if test $REPLACE_MBTOWC =3D 1; then + func_gl_gnulib_m4code_mbrtowc + fi + if test $REPLACE_MBTOWC =3D 1; then + func_gl_gnulib_m4code_wchar + fi + fi + } func_gl_gnulib_m4code_5264294aa0a5557541b53c8c741f7f31 () { if ! $gl_gnulib_enabled_5264294aa0a5557541b53c8c741f7f31; then @@ -556,6 +717,21 @@ AC_DEFUN gl_gnulib_enabled_5264294aa0a5557541b53c8c741f7f31=3Dtrue fi } + func_gl_gnulib_m4code_nl_langinfo () + { + if ! $gl_gnulib_enabled_nl_langinfo; then + gl_FUNC_NL_LANGINFO + if test $HAVE_NL_LANGINFO =3D 0 || test $REPLACE_NL_LANGINFO =3D 1= ; then + AC_LIBOBJ([nl_langinfo]) + fi + gl_LANGINFO_MODULE_INDICATOR([nl_langinfo]) + gl_gnulib_enabled_nl_langinfo=3Dtrue + func_gl_gnulib_m4code_langinfo + if test $HAVE_NL_LANGINFO =3D 0 || test $REPLACE_NL_LANGINFO =3D 1= ; then + func_gl_gnulib_m4code_localeconv + fi + fi + } func_gl_gnulib_m4code_open () { if ! $gl_gnulib_enabled_open; then @@ -583,6 +759,12 @@ AC_DEFUN gl_gnulib_enabled_6099e9737f757db36c47fa9d9f02e88c=3Dtrue fi } + func_gl_gnulib_m4code_streq () + { + if ! $gl_gnulib_enabled_streq; then + gl_gnulib_enabled_streq=3Dtrue + fi + } func_gl_gnulib_m4code_strtoll () { if ! $gl_gnulib_enabled_strtoll; then @@ -595,6 +777,36 @@ AC_DEFUN gl_gnulib_enabled_strtoll=3Dtrue fi } + func_gl_gnulib_m4code_wchar () + { + if ! $gl_gnulib_enabled_wchar; then + gl_WCHAR_H + gl_gnulib_enabled_wchar=3Dtrue + fi + } + func_gl_gnulib_m4code_wcrtomb () + { + if ! $gl_gnulib_enabled_wcrtomb; then + gl_FUNC_WCRTOMB + if test $HAVE_WCRTOMB =3D 0 || test $REPLACE_WCRTOMB =3D 1; then + AC_LIBOBJ([wcrtomb]) + gl_PREREQ_WCRTOMB + fi + gl_WCHAR_MODULE_INDICATOR([wcrtomb]) + gl_gnulib_enabled_wcrtomb=3Dtrue + if test $HAVE_WCRTOMB =3D 0 || test $REPLACE_WCRTOMB =3D 1; then + func_gl_gnulib_m4code_mbsinit + fi + func_gl_gnulib_m4code_wchar + fi + } + func_gl_gnulib_m4code_3dcce957eadc896e63ab5f137947b410 () + { + if ! $gl_gnulib_enabled_3dcce957eadc896e63ab5f137947b410; then + gl_WCTYPE_H + gl_gnulib_enabled_3dcce957eadc896e63ab5f137947b410=3Dtrue + fi + } func_gl_gnulib_m4code_682e609604ccaac6be382e4ee3a4eaec () { if ! $gl_gnulib_enabled_682e609604ccaac6be382e4ee3a4eaec; then @@ -649,6 +861,33 @@ AC_DEFUN if test $HAVE_READLINKAT =3D 0; then func_gl_gnulib_m4code_03e0aaad4cb89ca757653bd367a6ccb7 fi + if test $ac_use_included_regex =3D yes; then + func_gl_gnulib_m4code_btowc + fi + if test $ac_use_included_regex =3D yes; then + func_gl_gnulib_m4code_37f71b604aa9c54446783d80f42fe547 + fi + if test $ac_use_included_regex =3D yes; then + func_gl_gnulib_m4code_langinfo + fi + if test $ac_use_included_regex =3D yes; then + func_gl_gnulib_m4code_mbrtowc + fi + if test $ac_use_included_regex =3D yes; then + func_gl_gnulib_m4code_mbsinit + fi + if test $ac_use_included_regex =3D yes; then + func_gl_gnulib_m4code_nl_langinfo + fi + if test $ac_use_included_regex =3D yes; then + func_gl_gnulib_m4code_wchar + fi + if test $ac_use_included_regex =3D yes; then + func_gl_gnulib_m4code_wcrtomb + fi + if test $ac_use_included_regex =3D yes; then + func_gl_gnulib_m4code_3dcce957eadc896e63ab5f137947b410 + fi if { test $HAVE_DECL_STRTOIMAX =3D 0 || test $REPLACE_STRTOIMAX =3D 1;= } && test $ac_cv_type_long_long_int =3D yes; then func_gl_gnulib_m4code_strtoll fi @@ -657,6 +896,8 @@ AC_DEFUN fi m4_pattern_allow([^gl_GNULIB_ENABLED_]) AM_CONDITIONAL([gl_GNULIB_ENABLED_260941c0e5dc67ec9e87d1fb321c300b], [= $gl_gnulib_enabled_260941c0e5dc67ec9e87d1fb321c300b]) + AM_CONDITIONAL([gl_GNULIB_ENABLED_btowc], [$gl_gnulib_enabled_btowc]) + AM_CONDITIONAL([gl_GNULIB_ENABLED_37f71b604aa9c54446783d80f42fe547], [= $gl_gnulib_enabled_37f71b604aa9c54446783d80f42fe547]) AM_CONDITIONAL([gl_GNULIB_ENABLED_cloexec], [$gl_gnulib_enabled_cloexe= c]) AM_CONDITIONAL([gl_GNULIB_ENABLED_dirfd], [$gl_gnulib_enabled_dirfd]) AM_CONDITIONAL([gl_GNULIB_ENABLED_dosname], [$gl_gnulib_enabled_dosnam= e]) @@ -665,12 +906,25 @@ AC_DEFUN AM_CONDITIONAL([gl_GNULIB_ENABLED_getgroups], [$gl_gnulib_enabled_getg= roups]) AM_CONDITIONAL([gl_GNULIB_ENABLED_be453cec5eecf5731a274f2de7f2db36], [= $gl_gnulib_enabled_be453cec5eecf5731a274f2de7f2db36]) AM_CONDITIONAL([gl_GNULIB_ENABLED_a9786850e999ae65a836a6041e8e5ed1], [= $gl_gnulib_enabled_a9786850e999ae65a836a6041e8e5ed1]) + AM_CONDITIONAL([gl_GNULIB_ENABLED_30838f5439487421042f2225bed3af76], [= $gl_gnulib_enabled_30838f5439487421042f2225bed3af76]) + AM_CONDITIONAL([gl_GNULIB_ENABLED_langinfo], [$gl_gnulib_enabled_langi= nfo]) + AM_CONDITIONAL([gl_GNULIB_ENABLED_localcharset], [$gl_gnulib_enabled_l= ocalcharset]) + AM_CONDITIONAL([gl_GNULIB_ENABLED_locale], [$gl_gnulib_enabled_locale]= ) + AM_CONDITIONAL([gl_GNULIB_ENABLED_localeconv], [$gl_gnulib_enabled_loc= aleconv]) AM_CONDITIONAL([gl_GNULIB_ENABLED_2049e887c7e5308faad27b3f894bb8c9], [= $gl_gnulib_enabled_2049e887c7e5308faad27b3f894bb8c9]) + AM_CONDITIONAL([gl_GNULIB_ENABLED_mbrtowc], [$gl_gnulib_enabled_mbrtow= c]) + AM_CONDITIONAL([gl_GNULIB_ENABLED_mbsinit], [$gl_gnulib_enabled_mbsini= t]) + AM_CONDITIONAL([gl_GNULIB_ENABLED_mbtowc], [$gl_gnulib_enabled_mbtowc]= ) AM_CONDITIONAL([gl_GNULIB_ENABLED_5264294aa0a5557541b53c8c741f7f31], [= $gl_gnulib_enabled_5264294aa0a5557541b53c8c741f7f31]) + AM_CONDITIONAL([gl_GNULIB_ENABLED_nl_langinfo], [$gl_gnulib_enabled_nl= _langinfo]) AM_CONDITIONAL([gl_GNULIB_ENABLED_open], [$gl_gnulib_enabled_open]) AM_CONDITIONAL([gl_GNULIB_ENABLED_03e0aaad4cb89ca757653bd367a6ccb7], [= $gl_gnulib_enabled_03e0aaad4cb89ca757653bd367a6ccb7]) AM_CONDITIONAL([gl_GNULIB_ENABLED_6099e9737f757db36c47fa9d9f02e88c], [= $gl_gnulib_enabled_6099e9737f757db36c47fa9d9f02e88c]) + AM_CONDITIONAL([gl_GNULIB_ENABLED_streq], [$gl_gnulib_enabled_streq]) AM_CONDITIONAL([gl_GNULIB_ENABLED_strtoll], [$gl_gnulib_enabled_strtol= l]) + AM_CONDITIONAL([gl_GNULIB_ENABLED_wchar], [$gl_gnulib_enabled_wchar]) + AM_CONDITIONAL([gl_GNULIB_ENABLED_wcrtomb], [$gl_gnulib_enabled_wcrtom= b]) + AM_CONDITIONAL([gl_GNULIB_ENABLED_3dcce957eadc896e63ab5f137947b410], [= $gl_gnulib_enabled_3dcce957eadc896e63ab5f137947b410]) AM_CONDITIONAL([gl_GNULIB_ENABLED_682e609604ccaac6be382e4ee3a4eaec], [= $gl_gnulib_enabled_682e609604ccaac6be382e4ee3a4eaec]) # End of code from modules m4_ifval(gl_LIBSOURCES_LIST, [ @@ -828,6 +1082,7 @@ AC_DEFUN lib/at-func.c lib/binary-io.c lib/binary-io.h + lib/btowc.c lib/byteswap.in.h lib/c++defs.h lib/c-ctype.c @@ -895,13 +1150,24 @@ AC_DEFUN lib/gettimeofday.c lib/gl_openssl.h lib/group-member.c + lib/hard-locale.c + lib/hard-locale.h lib/ignore-value.h lib/intprops.h lib/inttypes.in.h + lib/langinfo.in.h lib/limits.in.h + lib/localcharset.c + lib/localcharset.h + lib/locale.in.h + lib/localeconv.c lib/localtime-buffer.c lib/localtime-buffer.h lib/lstat.c + lib/mbrtowc.c + lib/mbsinit.c + lib/mbtowc-impl.h + lib/mbtowc.c lib/md5.c lib/md5.h lib/memrchr.c @@ -909,6 +1175,7 @@ AC_DEFUN lib/mkostemp.c lib/mktime-internal.h lib/mktime.c + lib/nl_langinfo.c lib/nstrftime.c lib/open.c lib/openat-priv.h @@ -921,6 +1188,12 @@ AC_DEFUN lib/qcopy-acl.c lib/readlink.c lib/readlinkat.c + lib/regcomp.c + lib/regex.c + lib/regex.h + lib/regex_internal.c + lib/regex_internal.h + lib/regexec.c lib/root-uid.h lib/set-permissions.c lib/sha1.c @@ -941,6 +1214,7 @@ AC_DEFUN lib/stdio.in.h lib/stdlib.in.h lib/stpcpy.c + lib/streq.h lib/strftime.h lib/string.in.h lib/strtoimax.c @@ -972,15 +1246,22 @@ AC_DEFUN lib/verify.h lib/vla.h lib/warn-on-use.h + lib/wchar.in.h + lib/wcrtomb.c + lib/wctype-h.c + lib/wctype.in.h lib/xalloc-oversized.h m4/00gnulib.m4 m4/absolute-header.m4 m4/acl.m4 m4/alloca.m4 + m4/btowc.m4 + m4/builtin-expect.m4 m4/byteswap.m4 m4/c-strtod.m4 m4/clock_time.m4 m4/close-stream.m4 + m4/codeset.m4 m4/count-leading-zeros.m4 m4/count-one-bits.m4 m4/count-trailing-zeros.m4 @@ -988,6 +1269,7 @@ AC_DEFUN m4/dirent_h.m4 m4/dirfd.m4 m4/dup2.m4 + m4/eealloc.m4 m4/environ.m4 m4/errno_h.m4 m4/euidaccess.m4 @@ -1015,17 +1297,29 @@ AC_DEFUN m4/gettime.m4 m4/gettimeofday.m4 m4/gl-openssl.m4 + m4/glibc21.m4 m4/gnulib-common.m4 m4/group-member.m4 m4/include_next.m4 m4/inttypes.m4 + m4/langinfo_h.m4 m4/largefile.m4 m4/limits-h.m4 + m4/localcharset.m4 + m4/locale-fr.m4 + m4/locale-ja.m4 + m4/locale-zh.m4 + m4/locale_h.m4 + m4/localeconv.m4 m4/localtime-buffer.m4 m4/longlong.m4 m4/lstat.m4 m4/manywarnings-c++.m4 m4/manywarnings.m4 + m4/mbrtowc.m4 + m4/mbsinit.m4 + m4/mbstate_t.m4 + m4/mbtowc.m4 m4/md5.m4 m4/memrchr.m4 m4/minmax.m4 @@ -1033,6 +1327,7 @@ AC_DEFUN m4/mktime.m4 m4/mode_t.m4 m4/multiarch.m4 + m4/nl_langinfo.m4 m4/nocrash.m4 m4/nstrftime.m4 m4/off_t.m4 @@ -1044,6 +1339,7 @@ AC_DEFUN m4/putenv.m4 m4/readlink.m4 m4/readlinkat.m4 + m4/regex.m4 m4/sha1.m4 m4/sha256.m4 m4/sha512.m4 @@ -1084,6 +1380,9 @@ AC_DEFUN m4/vararrays.m4 m4/warn-on-use.m4 m4/warnings.m4 + m4/wchar_h.m4 m4/wchar_t.m4 + m4/wcrtomb.m4 + m4/wctype_h.m4 m4/wint_t.m4 ]) diff --git a/m4/langinfo_h.m4 b/m4/langinfo_h.m4 new file mode 100644 index 0000000000..de077c373d --- /dev/null +++ b/m4/langinfo_h.m4 @@ -0,0 +1,120 @@ +# langinfo_h.m4 serial 8 +dnl Copyright (C) 2009-2018 Free Software Foundation, Inc. +dnl This file is free software; the Free Software Foundation +dnl gives unlimited permission to copy and/or distribute it, +dnl with or without modifications, as long as this notice is preserved. + +AC_DEFUN([gl_LANGINFO_H], +[ + AC_REQUIRE([gl_LANGINFO_H_DEFAULTS]) + + dnl Persuade glibc-2.0.6 to define CODESET. + AC_REQUIRE([AC_USE_SYSTEM_EXTENSIONS]) + + dnl is always overridden, because of GNULIB_POSIXCHECK. + gl_CHECK_NEXT_HEADERS([langinfo.h]) + + dnl Determine whether exists. It is missing on mingw and = BeOS. + HAVE_LANGINFO_CODESET=3D0 + HAVE_LANGINFO_T_FMT_AMPM=3D0 + HAVE_LANGINFO_ALTMON=3D0 + HAVE_LANGINFO_ERA=3D0 + HAVE_LANGINFO_YESEXPR=3D0 + AC_CHECK_HEADERS_ONCE([langinfo.h]) + if test $ac_cv_header_langinfo_h =3D yes; then + HAVE_LANGINFO_H=3D1 + dnl Determine what defines. CODESET and ERA etc. are mi= ssing + dnl on OpenBSD 3.8. T_FMT_AMPM and YESEXPR, NOEXPR are missing on IR= IX 5.3. + dnl ALTMON_* are missing on glibc 2.26 and many other systems. + AC_CACHE_CHECK([whether langinfo.h defines CODESET], + [gl_cv_header_langinfo_codeset], + [AC_COMPILE_IFELSE( + [AC_LANG_PROGRAM([[#include +int a =3D CODESET; +]])], + [gl_cv_header_langinfo_codeset=3Dyes], + [gl_cv_header_langinfo_codeset=3Dno]) + ]) + if test $gl_cv_header_langinfo_codeset =3D yes; then + HAVE_LANGINFO_CODESET=3D1 + fi + AC_CACHE_CHECK([whether langinfo.h defines T_FMT_AMPM], + [gl_cv_header_langinfo_t_fmt_ampm], + [AC_COMPILE_IFELSE( + [AC_LANG_PROGRAM([[#include +int a =3D T_FMT_AMPM; +]])], + [gl_cv_header_langinfo_t_fmt_ampm=3Dyes], + [gl_cv_header_langinfo_t_fmt_ampm=3Dno]) + ]) + if test $gl_cv_header_langinfo_t_fmt_ampm =3D yes; then + HAVE_LANGINFO_T_FMT_AMPM=3D1 + fi + AC_CACHE_CHECK([whether langinfo.h defines ALTMON_1], + [gl_cv_header_langinfo_altmon], + [AC_COMPILE_IFELSE( + [AC_LANG_PROGRAM([[#include +int a =3D ALTMON_1; +]])], + [gl_cv_header_langinfo_altmon=3Dyes], + [gl_cv_header_langinfo_altmon=3Dno]) + ]) + if test $gl_cv_header_langinfo_altmon =3D yes; then + HAVE_LANGINFO_ALTMON=3D1 + fi + AC_CACHE_CHECK([whether langinfo.h defines ERA], + [gl_cv_header_langinfo_era], + [AC_COMPILE_IFELSE( + [AC_LANG_PROGRAM([[#include +int a =3D ERA; +]])], + [gl_cv_header_langinfo_era=3Dyes], + [gl_cv_header_langinfo_era=3Dno]) + ]) + if test $gl_cv_header_langinfo_era =3D yes; then + HAVE_LANGINFO_ERA=3D1 + fi + AC_CACHE_CHECK([whether langinfo.h defines YESEXPR], + [gl_cv_header_langinfo_yesexpr], + [AC_COMPILE_IFELSE( + [AC_LANG_PROGRAM([[#include +int a =3D YESEXPR; +]])], + [gl_cv_header_langinfo_yesexpr=3Dyes], + [gl_cv_header_langinfo_yesexpr=3Dno]) + ]) + if test $gl_cv_header_langinfo_yesexpr =3D yes; then + HAVE_LANGINFO_YESEXPR=3D1 + fi + else + HAVE_LANGINFO_H=3D0 + fi + AC_SUBST([HAVE_LANGINFO_H]) + AC_SUBST([HAVE_LANGINFO_CODESET]) + AC_SUBST([HAVE_LANGINFO_T_FMT_AMPM]) + AC_SUBST([HAVE_LANGINFO_ALTMON]) + AC_SUBST([HAVE_LANGINFO_ERA]) + AC_SUBST([HAVE_LANGINFO_YESEXPR]) + + dnl Check for declarations of anything we want to poison if the + dnl corresponding gnulib module is not in use. + gl_WARN_ON_USE_PREPARE([[#include + ]], [nl_langinfo]) +]) + +AC_DEFUN([gl_LANGINFO_MODULE_INDICATOR], +[ + dnl Use AC_REQUIRE here, so that the default settings are expanded onc= e only. + AC_REQUIRE([gl_LANGINFO_H_DEFAULTS]) + gl_MODULE_INDICATOR_SET_VARIABLE([$1]) + dnl Define it also as a C macro, for the benefit of the unit tests. + gl_MODULE_INDICATOR_FOR_TESTS([$1]) +]) + +AC_DEFUN([gl_LANGINFO_H_DEFAULTS], +[ + GNULIB_NL_LANGINFO=3D0; AC_SUBST([GNULIB_NL_LANGINFO]) + dnl Assume proper GNU behavior unless another module says otherwise. + HAVE_NL_LANGINFO=3D1; AC_SUBST([HAVE_NL_LANGINFO]) + REPLACE_NL_LANGINFO=3D0; AC_SUBST([REPLACE_NL_LANGINFO]) +]) diff --git a/m4/localcharset.m4 b/m4/localcharset.m4 new file mode 100644 index 0000000000..d38a2c9eb3 --- /dev/null +++ b/m4/localcharset.m4 @@ -0,0 +1,11 @@ +# localcharset.m4 serial 8 +dnl Copyright (C) 2002, 2004, 2006, 2009-2018 Free Software Foundation, = Inc. +dnl This file is free software; the Free Software Foundation +dnl gives unlimited permission to copy and/or distribute it, +dnl with or without modifications, as long as this notice is preserved. + +AC_DEFUN([gl_LOCALCHARSET], +[ + dnl Prerequisites of lib/localcharset.c. + AC_REQUIRE([AM_LANGINFO_CODESET]) +]) diff --git a/m4/locale-fr.m4 b/m4/locale-fr.m4 new file mode 100644 index 0000000000..a37a0d2024 --- /dev/null +++ b/m4/locale-fr.m4 @@ -0,0 +1,257 @@ +# locale-fr.m4 serial 19 +dnl Copyright (C) 2003, 2005-2018 Free Software Foundation, Inc. +dnl This file is free software; the Free Software Foundation +dnl gives unlimited permission to copy and/or distribute it, +dnl with or without modifications, as long as this notice is preserved. + +dnl From Bruno Haible. + +dnl Determine the name of a french locale with traditional encoding. +AC_DEFUN([gt_LOCALE_FR], +[ + AC_REQUIRE([AC_CANONICAL_HOST]) + AC_REQUIRE([AM_LANGINFO_CODESET]) + AC_CACHE_CHECK([for a traditional french locale], [gt_cv_locale_fr], [ + AC_LANG_CONFTEST([AC_LANG_SOURCE([ +changequote(,)dnl +#include +#include +#if HAVE_LANGINFO_CODESET +# include +#endif +#include +#include +struct tm t; +char buf[16]; +int main () { + /* On BeOS and Haiku, locales are not implemented in libc. Rather, li= bintl + imitates locale dependent behaviour by looking at the environment + variables, and all locales use the UTF-8 encoding. */ +#if defined __BEOS__ || defined __HAIKU__ + return 1; +#else + /* Check whether the given locale name is recognized by the system. *= / +# if defined _WIN32 && !defined __CYGWIN__ + /* On native Windows, setlocale(category, "") looks at the system sett= ings, + not at the environment variables. Also, when an encoding suffix su= ch + as ".65001" or ".54936" is specified, it succeeds but sets the LC_C= TYPE + category of the locale to "C". */ + if (setlocale (LC_ALL, getenv ("LC_ALL")) =3D=3D NULL + || strcmp (setlocale (LC_CTYPE, NULL), "C") =3D=3D 0) + return 1; +# else + if (setlocale (LC_ALL, "") =3D=3D NULL) return 1; +# endif + /* Check whether nl_langinfo(CODESET) is nonempty and not "ASCII" or "= 646". + On Mac OS X 10.3.5 (Darwin 7.5) in the fr_FR locale, nl_langinfo(CO= DESET) + is empty, and the behaviour of Tcl 8.4 in this locale is not useful= . + On OpenBSD 4.0, when an unsupported locale is specified, setlocale(= ) + succeeds but then nl_langinfo(CODESET) is "646". In this situation, + some unit tests fail. + On MirBSD 10, when an unsupported locale is specified, setlocale() + succeeds but then nl_langinfo(CODESET) is "UTF-8". */ +# if HAVE_LANGINFO_CODESET + { + const char *cs =3D nl_langinfo (CODESET); + if (cs[0] =3D=3D '\0' || strcmp (cs, "ASCII") =3D=3D 0 || strcmp (cs= , "646") =3D=3D 0 + || strcmp (cs, "UTF-8") =3D=3D 0) + return 1; + } +# endif +# ifdef __CYGWIN__ + /* On Cygwin, avoid locale names without encoding suffix, because the + locale_charset() function relies on the encoding suffix. Note that + LC_ALL is set on the command line. */ + if (strchr (getenv ("LC_ALL"), '.') =3D=3D NULL) return 1; +# endif + /* Check whether in the abbreviation of the second month, the second + character (should be U+00E9: LATIN SMALL LETTER E WITH ACUTE) is on= ly + one byte long. This excludes the UTF-8 encoding. */ + t.tm_year =3D 1975 - 1900; t.tm_mon =3D 2 - 1; t.tm_mday =3D 4; + if (strftime (buf, sizeof (buf), "%b", &t) < 3 || buf[2] !=3D 'v') ret= urn 1; +# if !defined __BIONIC__ /* Bionic libc's 'struct lconv' is just a dummy= . */ + /* Check whether the decimal separator is a comma. + On NetBSD 3.0 in the fr_FR.ISO8859-1 locale, localeconv()->decimal_= point + are nl_langinfo(RADIXCHAR) are both ".". */ + if (localeconv () ->decimal_point[0] !=3D ',') return 1; +# endif + return 0; +#endif +} +changequote([,])dnl + ])]) + if AC_TRY_EVAL([ac_link]) && test -s conftest$ac_exeext; then + case "$host_os" in + # Handle native Windows specially, because there setlocale() int= erprets + # "ar" as "Arabic" or "Arabic_Saudi Arabia.1256", + # "fr" or "fra" as "French" or "French_France.1252", + # "ge"(!) or "deu"(!) as "German" or "German_Germany.1252", + # "ja" as "Japanese" or "Japanese_Japan.932", + # and similar. + mingw*) + # Test for the native Windows locale name. + if (LC_ALL=3DFrench_France.1252 LC_TIME=3D LC_CTYPE=3D ./conft= est; exit) 2>/dev/null; then + gt_cv_locale_fr=3DFrench_France.1252 + else + # None found. + gt_cv_locale_fr=3Dnone + fi + ;; + *) + # Setting LC_ALL is not enough. Need to set LC_TIME to empty, = because + # otherwise on Mac OS X 10.3.5 the LC_TIME=3DC from the beginn= ing of the + # configure script would override the LC_ALL setting. Likewise= for + # LC_CTYPE, which is also set at the beginning of the configur= e script. + # Test for the usual locale name. + if (LC_ALL=3Dfr_FR LC_TIME=3D LC_CTYPE=3D ./conftest; exit) 2>= /dev/null; then + gt_cv_locale_fr=3Dfr_FR + else + # Test for the locale name with explicit encoding suffix. + if (LC_ALL=3Dfr_FR.ISO-8859-1 LC_TIME=3D LC_CTYPE=3D ./conft= est; exit) 2>/dev/null; then + gt_cv_locale_fr=3Dfr_FR.ISO-8859-1 + else + # Test for the AIX, OSF/1, FreeBSD, NetBSD, OpenBSD locale= name. + if (LC_ALL=3Dfr_FR.ISO8859-1 LC_TIME=3D LC_CTYPE=3D ./conf= test; exit) 2>/dev/null; then + gt_cv_locale_fr=3Dfr_FR.ISO8859-1 + else + # Test for the HP-UX locale name. + if (LC_ALL=3Dfr_FR.iso88591 LC_TIME=3D LC_CTYPE=3D ./con= ftest; exit) 2>/dev/null; then + gt_cv_locale_fr=3Dfr_FR.iso88591 + else + # Test for the Solaris 7 locale name. + if (LC_ALL=3Dfr LC_TIME=3D LC_CTYPE=3D ./conftest; exi= t) 2>/dev/null; then + gt_cv_locale_fr=3Dfr + else + # None found. + gt_cv_locale_fr=3Dnone + fi + fi + fi + fi + fi + ;; + esac + fi + rm -fr conftest* + ]) + LOCALE_FR=3D$gt_cv_locale_fr + AC_SUBST([LOCALE_FR]) +]) + +dnl Determine the name of a french locale with UTF-8 encoding. +AC_DEFUN([gt_LOCALE_FR_UTF8], +[ + AC_REQUIRE([AM_LANGINFO_CODESET]) + AC_CACHE_CHECK([for a french Unicode locale], [gt_cv_locale_fr_utf8], = [ + AC_LANG_CONFTEST([AC_LANG_SOURCE([ +changequote(,)dnl +#include +#include +#if HAVE_LANGINFO_CODESET +# include +#endif +#include +#include +struct tm t; +char buf[16]; +int main () { + /* On BeOS and Haiku, locales are not implemented in libc. Rather, li= bintl + imitates locale dependent behaviour by looking at the environment + variables, and all locales use the UTF-8 encoding. */ +#if !(defined __BEOS__ || defined __HAIKU__) + /* Check whether the given locale name is recognized by the system. *= / +# if defined _WIN32 && !defined __CYGWIN__ + /* On native Windows, setlocale(category, "") looks at the system sett= ings, + not at the environment variables. Also, when an encoding suffix su= ch + as ".65001" or ".54936" is specified, it succeeds but sets the LC_C= TYPE + category of the locale to "C". */ + if (setlocale (LC_ALL, getenv ("LC_ALL")) =3D=3D NULL + || strcmp (setlocale (LC_CTYPE, NULL), "C") =3D=3D 0) + return 1; +# else + if (setlocale (LC_ALL, "") =3D=3D NULL) return 1; +# endif + /* Check whether nl_langinfo(CODESET) is nonempty and not "ASCII" or "= 646". + On Mac OS X 10.3.5 (Darwin 7.5) in the fr_FR locale, nl_langinfo(CO= DESET) + is empty, and the behaviour of Tcl 8.4 in this locale is not useful= . + On OpenBSD 4.0, when an unsupported locale is specified, setlocale(= ) + succeeds but then nl_langinfo(CODESET) is "646". In this situation, + some unit tests fail. */ +# if HAVE_LANGINFO_CODESET + { + const char *cs =3D nl_langinfo (CODESET); + if (cs[0] =3D=3D '\0' || strcmp (cs, "ASCII") =3D=3D 0 || strcmp (cs= , "646") =3D=3D 0) + return 1; + } +# endif +# ifdef __CYGWIN__ + /* On Cygwin, avoid locale names without encoding suffix, because the + locale_charset() function relies on the encoding suffix. Note that + LC_ALL is set on the command line. */ + if (strchr (getenv ("LC_ALL"), '.') =3D=3D NULL) return 1; +# endif + /* Check whether in the abbreviation of the second month, the second + character (should be U+00E9: LATIN SMALL LETTER E WITH ACUTE) is + two bytes long, with UTF-8 encoding. */ + t.tm_year =3D 1975 - 1900; t.tm_mon =3D 2 - 1; t.tm_mday =3D 4; + if (strftime (buf, sizeof (buf), "%b", &t) < 4 + || buf[1] !=3D (char) 0xc3 || buf[2] !=3D (char) 0xa9 || buf[3] !=3D= 'v') + return 1; +#endif +#if !defined __BIONIC__ /* Bionic libc's 'struct lconv' is just a dummy.= */ + /* Check whether the decimal separator is a comma. + On NetBSD 3.0 in the fr_FR.ISO8859-1 locale, localeconv()->decimal_= point + are nl_langinfo(RADIXCHAR) are both ".". */ + if (localeconv () ->decimal_point[0] !=3D ',') return 1; +#endif + return 0; +} +changequote([,])dnl + ])]) + if AC_TRY_EVAL([ac_link]) && test -s conftest$ac_exeext; then + case "$host_os" in + # Handle native Windows specially, because there setlocale() int= erprets + # "ar" as "Arabic" or "Arabic_Saudi Arabia.1256", + # "fr" or "fra" as "French" or "French_France.1252", + # "ge"(!) or "deu"(!) as "German" or "German_Germany.1252", + # "ja" as "Japanese" or "Japanese_Japan.932", + # and similar. + mingw*) + # Test for the hypothetical native Windows locale name. + if (LC_ALL=3DFrench_France.65001 LC_TIME=3D LC_CTYPE=3D ./conf= test; exit) 2>/dev/null; then + gt_cv_locale_fr_utf8=3DFrench_France.65001 + else + # None found. + gt_cv_locale_fr_utf8=3Dnone + fi + ;; + *) + # Setting LC_ALL is not enough. Need to set LC_TIME to empty, = because + # otherwise on Mac OS X 10.3.5 the LC_TIME=3DC from the beginn= ing of the + # configure script would override the LC_ALL setting. Likewise= for + # LC_CTYPE, which is also set at the beginning of the configur= e script. + # Test for the usual locale name. + if (LC_ALL=3Dfr_FR LC_TIME=3D LC_CTYPE=3D ./conftest; exit) 2>= /dev/null; then + gt_cv_locale_fr_utf8=3Dfr_FR + else + # Test for the locale name with explicit encoding suffix. + if (LC_ALL=3Dfr_FR.UTF-8 LC_TIME=3D LC_CTYPE=3D ./conftest; = exit) 2>/dev/null; then + gt_cv_locale_fr_utf8=3Dfr_FR.UTF-8 + else + # Test for the Solaris 7 locale name. + if (LC_ALL=3Dfr.UTF-8 LC_TIME=3D LC_CTYPE=3D ./conftest; e= xit) 2>/dev/null; then + gt_cv_locale_fr_utf8=3Dfr.UTF-8 + else + # None found. + gt_cv_locale_fr_utf8=3Dnone + fi + fi + fi + ;; + esac + fi + rm -fr conftest* + ]) + LOCALE_FR_UTF8=3D$gt_cv_locale_fr_utf8 + AC_SUBST([LOCALE_FR_UTF8]) +]) diff --git a/m4/locale-ja.m4 b/m4/locale-ja.m4 new file mode 100644 index 0000000000..9f1623191d --- /dev/null +++ b/m4/locale-ja.m4 @@ -0,0 +1,145 @@ +# locale-ja.m4 serial 14 +dnl Copyright (C) 2003, 2005-2018 Free Software Foundation, Inc. +dnl This file is free software; the Free Software Foundation +dnl gives unlimited permission to copy and/or distribute it, +dnl with or without modifications, as long as this notice is preserved. + +dnl From Bruno Haible. + +dnl Determine the name of a japanese locale with EUC-JP encoding. +AC_DEFUN([gt_LOCALE_JA], +[ + AC_REQUIRE([AC_CANONICAL_HOST]) + AC_REQUIRE([AM_LANGINFO_CODESET]) + AC_CACHE_CHECK([for a traditional japanese locale], [gt_cv_locale_ja],= [ + AC_LANG_CONFTEST([AC_LANG_SOURCE([ +changequote(,)dnl +#include +#include +#if HAVE_LANGINFO_CODESET +# include +#endif +#include +#include +struct tm t; +char buf[16]; +int main () +{ + /* On BeOS and Haiku, locales are not implemented in libc. Rather, li= bintl + imitates locale dependent behaviour by looking at the environment + variables, and all locales use the UTF-8 encoding. */ +#if defined __BEOS__ || defined __HAIKU__ + return 1; +#else + /* Check whether the given locale name is recognized by the system. *= / +# if defined _WIN32 && !defined __CYGWIN__ + /* On native Windows, setlocale(category, "") looks at the system sett= ings, + not at the environment variables. Also, when an encoding suffix su= ch + as ".65001" or ".54936" is specified, it succeeds but sets the LC_C= TYPE + category of the locale to "C". */ + if (setlocale (LC_ALL, getenv ("LC_ALL")) =3D=3D NULL + || strcmp (setlocale (LC_CTYPE, NULL), "C") =3D=3D 0) + return 1; +# else + if (setlocale (LC_ALL, "") =3D=3D NULL) return 1; +# endif + /* Check whether nl_langinfo(CODESET) is nonempty and not "ASCII" or "= 646". + On Mac OS X 10.3.5 (Darwin 7.5) in the fr_FR locale, nl_langinfo(CO= DESET) + is empty, and the behaviour of Tcl 8.4 in this locale is not useful= . + On OpenBSD 4.0, when an unsupported locale is specified, setlocale(= ) + succeeds but then nl_langinfo(CODESET) is "646". In this situation, + some unit tests fail. + On MirBSD 10, when an unsupported locale is specified, setlocale() + succeeds but then nl_langinfo(CODESET) is "UTF-8". */ +# if HAVE_LANGINFO_CODESET + { + const char *cs =3D nl_langinfo (CODESET); + if (cs[0] =3D=3D '\0' || strcmp (cs, "ASCII") =3D=3D 0 || strcmp (cs= , "646") =3D=3D 0 + || strcmp (cs, "UTF-8") =3D=3D 0) + return 1; + } +# endif +# ifdef __CYGWIN__ + /* On Cygwin, avoid locale names without encoding suffix, because the + locale_charset() function relies on the encoding suffix. Note that + LC_ALL is set on the command line. */ + if (strchr (getenv ("LC_ALL"), '.') =3D=3D NULL) return 1; +# endif + /* Check whether MB_CUR_MAX is > 1. This excludes the dysfunctional l= ocales + on Cygwin 1.5.x. */ + if (MB_CUR_MAX =3D=3D 1) + return 1; + /* Check whether in a month name, no byte in the range 0x80..0x9F occu= rs. + This excludes the UTF-8 encoding (except on MirBSD). */ + { + const char *p; + t.tm_year =3D 1975 - 1900; t.tm_mon =3D 2 - 1; t.tm_mday =3D 4; + if (strftime (buf, sizeof (buf), "%B", &t) < 2) return 1; + for (p =3D buf; *p !=3D '\0'; p++) + if ((unsigned char) *p >=3D 0x80 && (unsigned char) *p < 0xa0) + return 1; + } + return 0; +#endif +} +changequote([,])dnl + ])]) + if AC_TRY_EVAL([ac_link]) && test -s conftest$ac_exeext; then + case "$host_os" in + # Handle native Windows specially, because there setlocale() int= erprets + # "ar" as "Arabic" or "Arabic_Saudi Arabia.1256", + # "fr" or "fra" as "French" or "French_France.1252", + # "ge"(!) or "deu"(!) as "German" or "German_Germany.1252", + # "ja" as "Japanese" or "Japanese_Japan.932", + # and similar. + mingw*) + # Note that on native Windows, the Japanese locale is + # Japanese_Japan.932, and CP932 is very different from EUC-JP,= so we + # cannot use it here. + gt_cv_locale_ja=3Dnone + ;; + *) + # Setting LC_ALL is not enough. Need to set LC_TIME to empty, = because + # otherwise on Mac OS X 10.3.5 the LC_TIME=3DC from the beginn= ing of the + # configure script would override the LC_ALL setting. Likewise= for + # LC_CTYPE, which is also set at the beginning of the configur= e script. + # Test for the AIX locale name. + if (LC_ALL=3Dja_JP LC_TIME=3D LC_CTYPE=3D ./conftest; exit) 2>= /dev/null; then + gt_cv_locale_ja=3Dja_JP + else + # Test for the locale name with explicit encoding suffix. + if (LC_ALL=3Dja_JP.EUC-JP LC_TIME=3D LC_CTYPE=3D ./conftest;= exit) 2>/dev/null; then + gt_cv_locale_ja=3Dja_JP.EUC-JP + else + # Test for the HP-UX, OSF/1, NetBSD locale name. + if (LC_ALL=3Dja_JP.eucJP LC_TIME=3D LC_CTYPE=3D ./conftest= ; exit) 2>/dev/null; then + gt_cv_locale_ja=3Dja_JP.eucJP + else + # Test for the IRIX, FreeBSD locale name. + if (LC_ALL=3Dja_JP.EUC LC_TIME=3D LC_CTYPE=3D ./conftest= ; exit) 2>/dev/null; then + gt_cv_locale_ja=3Dja_JP.EUC + else + # Test for the Solaris 7 locale name. + if (LC_ALL=3Dja LC_TIME=3D LC_CTYPE=3D ./conftest; exi= t) 2>/dev/null; then + gt_cv_locale_ja=3Dja + else + # Special test for NetBSD 1.6. + if test -f /usr/share/locale/ja_JP.eucJP/LC_CTYPE; t= hen + gt_cv_locale_ja=3Dja_JP.eucJP + else + # None found. + gt_cv_locale_ja=3Dnone + fi + fi + fi + fi + fi + fi + ;; + esac + fi + rm -fr conftest* + ]) + LOCALE_JA=3D$gt_cv_locale_ja + AC_SUBST([LOCALE_JA]) +]) diff --git a/m4/locale-zh.m4 b/m4/locale-zh.m4 new file mode 100644 index 0000000000..cfb447f08d --- /dev/null +++ b/m4/locale-zh.m4 @@ -0,0 +1,139 @@ +# locale-zh.m4 serial 14 +dnl Copyright (C) 2003, 2005-2018 Free Software Foundation, Inc. +dnl This file is free software; the Free Software Foundation +dnl gives unlimited permission to copy and/or distribute it, +dnl with or without modifications, as long as this notice is preserved. + +dnl From Bruno Haible. + +dnl Determine the name of a chinese locale with GB18030 encoding. +AC_DEFUN([gt_LOCALE_ZH_CN], +[ + AC_REQUIRE([AC_CANONICAL_HOST]) + AC_REQUIRE([AM_LANGINFO_CODESET]) + AC_CACHE_CHECK([for a transitional chinese locale], [gt_cv_locale_zh_C= N], [ + AC_LANG_CONFTEST([AC_LANG_SOURCE([ +changequote(,)dnl +#include +#include +#include +#if HAVE_LANGINFO_CODESET +# include +#endif +#include +#include +struct tm t; +char buf[16]; +int main () +{ + /* On BeOS and Haiku, locales are not implemented in libc. Rather, li= bintl + imitates locale dependent behaviour by looking at the environment + variables, and all locales use the UTF-8 encoding. */ +#if defined __BEOS__ || defined __HAIKU__ + return 1; +#else + /* Check whether the given locale name is recognized by the system. *= / +# if defined _WIN32 && !defined __CYGWIN__ + /* On native Windows, setlocale(category, "") looks at the system sett= ings, + not at the environment variables. Also, when an encoding suffix su= ch + as ".65001" or ".54936" is specified, it succeeds but sets the LC_C= TYPE + category of the locale to "C". */ + if (setlocale (LC_ALL, getenv ("LC_ALL")) =3D=3D NULL + || strcmp (setlocale (LC_CTYPE, NULL), "C") =3D=3D 0) + return 1; +# else + if (setlocale (LC_ALL, "") =3D=3D NULL) return 1; +# endif + /* Check whether nl_langinfo(CODESET) is nonempty and not "ASCII" or "= 646". + On Mac OS X 10.3.5 (Darwin 7.5) in the fr_FR locale, nl_langinfo(CO= DESET) + is empty, and the behaviour of Tcl 8.4 in this locale is not useful= . + On OpenBSD 4.0, when an unsupported locale is specified, setlocale(= ) + succeeds but then nl_langinfo(CODESET) is "646". In this situation, + some unit tests fail. + On MirBSD 10, when an unsupported locale is specified, setlocale() + succeeds but then nl_langinfo(CODESET) is "UTF-8". */ +# if HAVE_LANGINFO_CODESET + { + const char *cs =3D nl_langinfo (CODESET); + if (cs[0] =3D=3D '\0' || strcmp (cs, "ASCII") =3D=3D 0 || strcmp (cs= , "646") =3D=3D 0 + || strcmp (cs, "UTF-8") =3D=3D 0) + return 1; + } +# endif +# ifdef __CYGWIN__ + /* On Cygwin, avoid locale names without encoding suffix, because the + locale_charset() function relies on the encoding suffix. Note that + LC_ALL is set on the command line. */ + if (strchr (getenv ("LC_ALL"), '.') =3D=3D NULL) return 1; +# endif + /* Check whether in a month name, no byte in the range 0x80..0x9F occu= rs. + This excludes the UTF-8 encoding (except on MirBSD). */ + { + const char *p; + t.tm_year =3D 1975 - 1900; t.tm_mon =3D 2 - 1; t.tm_mday =3D 4; + if (strftime (buf, sizeof (buf), "%B", &t) < 2) return 1; + for (p =3D buf; *p !=3D '\0'; p++) + if ((unsigned char) *p >=3D 0x80 && (unsigned char) *p < 0xa0) + return 1; + } + /* Check whether a typical GB18030 multibyte sequence is recognized as= a + single wide character. This excludes the GB2312 and GBK encodings.= */ + if (mblen ("\203\062\332\066", 5) !=3D 4) + return 1; + return 0; +#endif +} +changequote([,])dnl + ])]) + if AC_TRY_EVAL([ac_link]) && test -s conftest$ac_exeext; then + case "$host_os" in + # Handle native Windows specially, because there setlocale() int= erprets + # "ar" as "Arabic" or "Arabic_Saudi Arabia.1256", + # "fr" or "fra" as "French" or "French_France.1252", + # "ge"(!) or "deu"(!) as "German" or "German_Germany.1252", + # "ja" as "Japanese" or "Japanese_Japan.932", + # and similar. + mingw*) + # Test for the hypothetical native Windows locale name. + if (LC_ALL=3DChinese_China.54936 LC_TIME=3D LC_CTYPE=3D ./conf= test; exit) 2>/dev/null; then + gt_cv_locale_zh_CN=3DChinese_China.54936 + else + # None found. + gt_cv_locale_zh_CN=3Dnone + fi + ;; + solaris2.8) + # On Solaris 8, the locales zh_CN.GB18030, zh_CN.GBK, zh.GBK a= re + # broken. One witness is the test case in gl_MBRTOWC_SANITYCHE= CK. + # Another witness is that "LC_ALL=3Dzh_CN.GB18030 bash -c true= " dumps core. + gt_cv_locale_zh_CN=3Dnone + ;; + *) + # Setting LC_ALL is not enough. Need to set LC_TIME to empty, = because + # otherwise on Mac OS X 10.3.5 the LC_TIME=3DC from the beginn= ing of the + # configure script would override the LC_ALL setting. Likewise= for + # LC_CTYPE, which is also set at the beginning of the configur= e script. + # Test for the locale name without encoding suffix. + if (LC_ALL=3Dzh_CN LC_TIME=3D LC_CTYPE=3D ./conftest; exit) 2>= /dev/null; then + gt_cv_locale_zh_CN=3Dzh_CN + else + # Test for the locale name with explicit encoding suffix. + if (LC_ALL=3Dzh_CN.GB18030 LC_TIME=3D LC_CTYPE=3D ./conftest= ; exit) 2>/dev/null; then + gt_cv_locale_zh_CN=3Dzh_CN.GB18030 + else + # None found. + gt_cv_locale_zh_CN=3Dnone + fi + fi + ;; + esac + else + # If there was a link error, due to mblen(), the system is so old = that + # it certainly doesn't have a chinese locale. + gt_cv_locale_zh_CN=3Dnone + fi + rm -fr conftest* + ]) + LOCALE_ZH_CN=3D$gt_cv_locale_zh_CN + AC_SUBST([LOCALE_ZH_CN]) +]) diff --git a/m4/locale_h.m4 b/m4/locale_h.m4 new file mode 100644 index 0000000000..4bd9e574eb --- /dev/null +++ b/m4/locale_h.m4 @@ -0,0 +1,122 @@ +# locale_h.m4 serial 20 +dnl Copyright (C) 2007, 2009-2018 Free Software Foundation, Inc. +dnl This file is free software; the Free Software Foundation +dnl gives unlimited permission to copy and/or distribute it, +dnl with or without modifications, as long as this notice is preserved. + +AC_DEFUN([gl_LOCALE_H], +[ + dnl Use AC_REQUIRE here, so that the default behavior below is expande= d + dnl once only, before all statements that occur in other macros. + AC_REQUIRE([gl_LOCALE_H_DEFAULTS]) + + dnl Persuade glibc to define locale_t and the int_p_*, int_= n_* + dnl members of 'struct lconv'. + AC_REQUIRE([gl_USE_SYSTEM_EXTENSIONS]) + + dnl If is replaced, then must also be replaced. + AC_REQUIRE([gl_STDDEF_H]) + + dnl Solaris 11.0 defines the int_p_*, int_n_* members of 'struct lconv= ' + dnl only if _LCONV_C99 is defined. + AC_REQUIRE([AC_CANONICAL_HOST]) + case "$host_os" in + solaris*) + AC_DEFINE([_LCONV_C99], [1], [Define to 1 on Solaris.]) + ;; + esac + + AC_CACHE_CHECK([whether locale.h conforms to POSIX:2001], + [gl_cv_header_locale_h_posix2001], + [AC_COMPILE_IFELSE( + [AC_LANG_PROGRAM( + [[#include + int x =3D LC_MESSAGES; + int y =3D sizeof (((struct lconv *) 0)->decimal_point);]], + [[]])], + [gl_cv_header_locale_h_posix2001=3Dyes], + [gl_cv_header_locale_h_posix2001=3Dno])]) + + dnl Check for . + AC_CHECK_HEADERS_ONCE([xlocale.h]) + if test $ac_cv_header_xlocale_h =3D yes; then + HAVE_XLOCALE_H=3D1 + dnl Check whether use of locale_t requires inclusion of , + dnl e.g. on Mac OS X 10.5. If does not define locale_t by + dnl itself, we assume that will do so. + AC_CACHE_CHECK([whether locale.h defines locale_t], + [gl_cv_header_locale_has_locale_t], + [AC_COMPILE_IFELSE( + [AC_LANG_PROGRAM( + [[#include + locale_t x;]], + [[]])], + [gl_cv_header_locale_has_locale_t=3Dyes], + [gl_cv_header_locale_has_locale_t=3Dno]) + ]) + if test $gl_cv_header_locale_has_locale_t =3D yes; then + gl_cv_header_locale_h_needs_xlocale_h=3Dno + else + gl_cv_header_locale_h_needs_xlocale_h=3Dyes + fi + else + HAVE_XLOCALE_H=3D0 + gl_cv_header_locale_h_needs_xlocale_h=3Dno + fi + AC_SUBST([HAVE_XLOCALE_H]) + + dnl Check whether 'struct lconv' is complete. + dnl Bionic libc's 'struct lconv' is just a dummy. + dnl On OpenBSD 4.9, HP-UX 11, IRIX 6.5, OSF/1 5.1, Solaris 9, Cygwin 1= .5.x, + dnl mingw, MSVC 9, it lacks the int_p_* and int_n_* members. + AC_CACHE_CHECK([whether struct lconv is properly defined], + [gl_cv_sys_struct_lconv_ok], + [AC_COMPILE_IFELSE( + [AC_LANG_PROGRAM( + [[#include + struct lconv l; + int x =3D sizeof (l.decimal_point); + int y =3D sizeof (l.int_p_cs_precedes);]], + [[]])], + [gl_cv_sys_struct_lconv_ok=3Dyes], + [gl_cv_sys_struct_lconv_ok=3Dno]) + ]) + if test $gl_cv_sys_struct_lconv_ok =3D no; then + REPLACE_STRUCT_LCONV=3D1 + fi + + dnl is always overridden, because of GNULIB_POSIXCHECK. + gl_NEXT_HEADERS([locale.h]) + + dnl Check for declarations of anything we want to poison if the + dnl corresponding gnulib module is not in use. + gl_WARN_ON_USE_PREPARE([[#include +/* Some systems provide declarations in a non-standard header. */ +#if HAVE_XLOCALE_H +# include +#endif + ]], + [setlocale duplocale]) +]) + +AC_DEFUN([gl_LOCALE_MODULE_INDICATOR], +[ + dnl Use AC_REQUIRE here, so that the default settings are expanded onc= e only. + AC_REQUIRE([gl_LOCALE_H_DEFAULTS]) + gl_MODULE_INDICATOR_SET_VARIABLE([$1]) + dnl Define it also as a C macro, for the benefit of the unit tests. + gl_MODULE_INDICATOR_FOR_TESTS([$1]) +]) + +AC_DEFUN([gl_LOCALE_H_DEFAULTS], +[ + GNULIB_LOCALECONV=3D0; AC_SUBST([GNULIB_LOCALECONV]) + GNULIB_SETLOCALE=3D0; AC_SUBST([GNULIB_SETLOCALE]) + GNULIB_DUPLOCALE=3D0; AC_SUBST([GNULIB_DUPLOCALE]) + dnl Assume proper GNU behavior unless another module says otherwise. + HAVE_DUPLOCALE=3D1; AC_SUBST([HAVE_DUPLOCALE]) + REPLACE_LOCALECONV=3D0; AC_SUBST([REPLACE_LOCALECONV]) + REPLACE_SETLOCALE=3D0; AC_SUBST([REPLACE_SETLOCALE]) + REPLACE_DUPLOCALE=3D0; AC_SUBST([REPLACE_DUPLOCALE]) + REPLACE_STRUCT_LCONV=3D0; AC_SUBST([REPLACE_STRUCT_LCONV]) +]) diff --git a/m4/localeconv.m4 b/m4/localeconv.m4 new file mode 100644 index 0000000000..517f398e41 --- /dev/null +++ b/m4/localeconv.m4 @@ -0,0 +1,22 @@ +# localeconv.m4 serial 1 +dnl Copyright (C) 2012-2018 Free Software Foundation, Inc. +dnl This file is free software; the Free Software Foundation +dnl gives unlimited permission to copy and/or distribute it, +dnl with or without modifications, as long as this notice is preserved. + +AC_DEFUN([gl_FUNC_LOCALECONV], +[ + AC_REQUIRE([gl_LOCALE_H_DEFAULTS]) + AC_REQUIRE([gl_LOCALE_H]) + + if test $REPLACE_STRUCT_LCONV =3D 1; then + REPLACE_LOCALECONV=3D1 + fi +]) + +# Prerequisites of lib/localeconv.c. +AC_DEFUN([gl_PREREQ_LOCALECONV], +[ + AC_CHECK_MEMBERS([struct lconv.decimal_point], [], [], + [[#include ]]) +]) diff --git a/m4/mbrtowc.m4 b/m4/mbrtowc.m4 new file mode 100644 index 0000000000..c706d04bca --- /dev/null +++ b/m4/mbrtowc.m4 @@ -0,0 +1,672 @@ +# mbrtowc.m4 serial 31 -*- coding: utf-8 -*- +dnl Copyright (C) 2001-2002, 2004-2005, 2008-2018 Free Software Foundati= on, +dnl Inc. +dnl This file is free software; the Free Software Foundation +dnl gives unlimited permission to copy and/or distribute it, +dnl with or without modifications, as long as this notice is preserved. + +AC_DEFUN([gl_FUNC_MBRTOWC], +[ + AC_REQUIRE([gl_WCHAR_H_DEFAULTS]) + + AC_REQUIRE([AC_TYPE_MBSTATE_T]) + gl_MBSTATE_T_BROKEN + + AC_CHECK_FUNCS_ONCE([mbrtowc]) + if test $ac_cv_func_mbrtowc =3D no; then + HAVE_MBRTOWC=3D0 + AC_CHECK_DECLS([mbrtowc],,, [[ +/* Tru64 with Desktop Toolkit C has a bug: must be included be= fore + . + BSD/OS 4.0.1 has a bug: , and must be + included before . */ +#include +#include +#include +#include +]]) + if test $ac_cv_have_decl_mbrtowc =3D yes; then + dnl On Minix 3.1.8, the system's declares mbrtowc() alth= ough + dnl it does not have the function. Avoid a collision with gnulib's + dnl replacement. + REPLACE_MBRTOWC=3D1 + fi + else + if test $REPLACE_MBSTATE_T =3D 1; then + REPLACE_MBRTOWC=3D1 + else + gl_MBRTOWC_NULL_ARG1 + gl_MBRTOWC_NULL_ARG2 + gl_MBRTOWC_RETVAL + gl_MBRTOWC_NUL_RETVAL + gl_MBRTOWC_EMPTY_INPUT + gl_MBRTOWC_C_LOCALE + case "$gl_cv_func_mbrtowc_null_arg1" in + *yes) ;; + *) AC_DEFINE([MBRTOWC_NULL_ARG1_BUG], [1], + [Define if the mbrtowc function has the NULL pwc argument b= ug.]) + REPLACE_MBRTOWC=3D1 + ;; + esac + case "$gl_cv_func_mbrtowc_null_arg2" in + *yes) ;; + *) AC_DEFINE([MBRTOWC_NULL_ARG2_BUG], [1], + [Define if the mbrtowc function has the NULL string argumen= t bug.]) + REPLACE_MBRTOWC=3D1 + ;; + esac + case "$gl_cv_func_mbrtowc_retval" in + *yes) ;; + *) AC_DEFINE([MBRTOWC_RETVAL_BUG], [1], + [Define if the mbrtowc function returns a wrong return valu= e.]) + REPLACE_MBRTOWC=3D1 + ;; + esac + case "$gl_cv_func_mbrtowc_nul_retval" in + *yes) ;; + *) AC_DEFINE([MBRTOWC_NUL_RETVAL_BUG], [1], + [Define if the mbrtowc function does not return 0 for a NUL= character.]) + REPLACE_MBRTOWC=3D1 + ;; + esac + case "$gl_cv_func_mbrtowc_empty_input" in + *yes) ;; + *) AC_DEFINE([MBRTOWC_EMPTY_INPUT_BUG], [1], + [Define if the mbrtowc function does not return (size_t) -2 + for empty input.]) + REPLACE_MBRTOWC=3D1 + ;; + esac + case $gl_cv_C_locale_sans_EILSEQ in + *yes) ;; + *) AC_DEFINE([C_LOCALE_MAYBE_EILSEQ], [1], + [Define to 1 if the C locale may have encoding errors.]) + REPLACE_MBRTOWC=3D1 + ;; + esac + fi + fi +]) + +dnl Test whether mbsinit() and mbrtowc() need to be overridden in a way = that +dnl redefines the semantics of the given mbstate_t type. +dnl Result is REPLACE_MBSTATE_T. +dnl When this is set to 1, we replace both mbsinit() and mbrtowc(), in o= rder to +dnl avoid inconsistencies. + +AC_DEFUN([gl_MBSTATE_T_BROKEN], +[ + AC_REQUIRE([gl_WCHAR_H_DEFAULTS]) + + AC_REQUIRE([AC_TYPE_MBSTATE_T]) + AC_CHECK_FUNCS_ONCE([mbsinit]) + AC_CHECK_FUNCS_ONCE([mbrtowc]) + if test $ac_cv_func_mbsinit =3D yes && test $ac_cv_func_mbrtowc =3D ye= s; then + gl_MBRTOWC_INCOMPLETE_STATE + gl_MBRTOWC_SANITYCHECK + REPLACE_MBSTATE_T=3D0 + case "$gl_cv_func_mbrtowc_incomplete_state" in + *yes) ;; + *) REPLACE_MBSTATE_T=3D1 ;; + esac + case "$gl_cv_func_mbrtowc_sanitycheck" in + *yes) ;; + *) REPLACE_MBSTATE_T=3D1 ;; + esac + else + REPLACE_MBSTATE_T=3D1 + fi +]) + +dnl Test whether mbrtowc puts the state into non-initial state when pars= ing an +dnl incomplete multibyte character. +dnl Result is gl_cv_func_mbrtowc_incomplete_state. + +AC_DEFUN([gl_MBRTOWC_INCOMPLETE_STATE], +[ + AC_REQUIRE([AC_PROG_CC]) + AC_REQUIRE([gt_LOCALE_JA]) + AC_REQUIRE([AC_CANONICAL_HOST]) dnl for cross-compiles + AC_CACHE_CHECK([whether mbrtowc handles incomplete characters], + [gl_cv_func_mbrtowc_incomplete_state], + [ + dnl Initial guess, used when cross-compiling or when no suitable l= ocale + dnl is present. +changequote(,)dnl + case "$host_os" in + # Guess no on AIX and OSF/1. + aix* | osf*) gl_cv_func_mbrtowc_incomplete_state=3D"guessing no"= ;; + # Guess yes otherwise. + *) gl_cv_func_mbrtowc_incomplete_state=3D"guessing yes= " ;; + esac +changequote([,])dnl + if test $LOCALE_JA !=3D none; then + AC_RUN_IFELSE( + [AC_LANG_SOURCE([[ +#include +#include +/* Tru64 with Desktop Toolkit C has a bug: must be included be= fore + . + BSD/OS 4.0.1 has a bug: , and must be + included before . */ +#include +#include +#include +#include +int main () +{ + if (setlocale (LC_ALL, "$LOCALE_JA") !=3D NULL) + { + const char input[] =3D "B\217\253\344\217\251\316er"; /* "B=C3=BC=C3= =9Fer" */ + mbstate_t state; + wchar_t wc; + + memset (&state, '\0', sizeof (mbstate_t)); + if (mbrtowc (&wc, input + 1, 1, &state) =3D=3D (size_t)(-2)) + if (mbsinit (&state)) + return 2; + } + return 0; +}]])], + [gl_cv_func_mbrtowc_incomplete_state=3Dyes], + [gl_cv_func_mbrtowc_incomplete_state=3Dno], + [:]) + fi + ]) +]) + +dnl Test whether mbrtowc works not worse than mbtowc. +dnl Result is gl_cv_func_mbrtowc_sanitycheck. + +AC_DEFUN([gl_MBRTOWC_SANITYCHECK], +[ + AC_REQUIRE([AC_PROG_CC]) + AC_REQUIRE([gt_LOCALE_ZH_CN]) + AC_REQUIRE([AC_CANONICAL_HOST]) dnl for cross-compiles + AC_CACHE_CHECK([whether mbrtowc works as well as mbtowc], + [gl_cv_func_mbrtowc_sanitycheck], + [ + dnl Initial guess, used when cross-compiling or when no suitable l= ocale + dnl is present. +changequote(,)dnl + case "$host_os" in + # Guess no on Solaris 8. + solaris2.8) gl_cv_func_mbrtowc_sanitycheck=3D"guessing no" ;; + # Guess yes otherwise. + *) gl_cv_func_mbrtowc_sanitycheck=3D"guessing yes" ;; + esac +changequote([,])dnl + if test $LOCALE_ZH_CN !=3D none; then + AC_RUN_IFELSE( + [AC_LANG_SOURCE([[ +#include +#include +#include +/* Tru64 with Desktop Toolkit C has a bug: must be included be= fore + . + BSD/OS 4.0.1 has a bug: , and must be + included before . */ +#include +#include +#include +#include +int main () +{ + /* This fails on Solaris 8: + mbrtowc returns 2, and sets wc to 0x00F0. + mbtowc returns 4 (correct) and sets wc to 0x5EDC. */ + if (setlocale (LC_ALL, "$LOCALE_ZH_CN") !=3D NULL) + { + char input[] =3D "B\250\271\201\060\211\070er"; /* "B=C3=BC=C3=9Fe= r" */ + mbstate_t state; + wchar_t wc; + + memset (&state, '\0', sizeof (mbstate_t)); + if (mbrtowc (&wc, input + 3, 6, &state) !=3D 4 + && mbtowc (&wc, input + 3, 6) =3D=3D 4) + return 2; + } + return 0; +}]])], + [gl_cv_func_mbrtowc_sanitycheck=3Dyes], + [gl_cv_func_mbrtowc_sanitycheck=3Dno], + [:]) + fi + ]) +]) + +dnl Test whether mbrtowc supports a NULL pwc argument correctly. +dnl Result is gl_cv_func_mbrtowc_null_arg1. + +AC_DEFUN([gl_MBRTOWC_NULL_ARG1], +[ + AC_REQUIRE([AC_PROG_CC]) + AC_REQUIRE([gt_LOCALE_FR_UTF8]) + AC_REQUIRE([AC_CANONICAL_HOST]) dnl for cross-compiles + AC_CACHE_CHECK([whether mbrtowc handles a NULL pwc argument], + [gl_cv_func_mbrtowc_null_arg1], + [ + dnl Initial guess, used when cross-compiling or when no suitable l= ocale + dnl is present. +changequote(,)dnl + case "$host_os" in + # Guess no on Solaris. + solaris*) gl_cv_func_mbrtowc_null_arg1=3D"guessing no" ;; + # Guess yes otherwise. + *) gl_cv_func_mbrtowc_null_arg1=3D"guessing yes" ;; + esac +changequote([,])dnl + if test $LOCALE_FR_UTF8 !=3D none; then + AC_RUN_IFELSE( + [AC_LANG_SOURCE([[ +#include +#include +#include +/* Tru64 with Desktop Toolkit C has a bug: must be included be= fore + . + BSD/OS 4.0.1 has a bug: , and must be + included before . */ +#include +#include +#include +#include +int main () +{ + int result =3D 0; + + if (setlocale (LC_ALL, "$LOCALE_FR_UTF8") !=3D NULL) + { + char input[] =3D "\303\237er"; + mbstate_t state; + wchar_t wc; + size_t ret; + + memset (&state, '\0', sizeof (mbstate_t)); + wc =3D (wchar_t) 0xBADFACE; + ret =3D mbrtowc (&wc, input, 5, &state); + if (ret !=3D 2) + result |=3D 1; + if (!mbsinit (&state)) + result |=3D 2; + + memset (&state, '\0', sizeof (mbstate_t)); + ret =3D mbrtowc (NULL, input, 5, &state); + if (ret !=3D 2) /* Solaris 7 fails here: ret is -1. */ + result |=3D 4; + if (!mbsinit (&state)) + result |=3D 8; + } + return result; +}]])], + [gl_cv_func_mbrtowc_null_arg1=3Dyes], + [gl_cv_func_mbrtowc_null_arg1=3Dno], + [:]) + fi + ]) +]) + +dnl Test whether mbrtowc supports a NULL string argument correctly. +dnl Result is gl_cv_func_mbrtowc_null_arg2. + +AC_DEFUN([gl_MBRTOWC_NULL_ARG2], +[ + AC_REQUIRE([AC_PROG_CC]) + AC_REQUIRE([gt_LOCALE_FR_UTF8]) + AC_REQUIRE([AC_CANONICAL_HOST]) dnl for cross-compiles + AC_CACHE_CHECK([whether mbrtowc handles a NULL string argument], + [gl_cv_func_mbrtowc_null_arg2], + [ + dnl Initial guess, used when cross-compiling or when no suitable l= ocale + dnl is present. +changequote(,)dnl + case "$host_os" in + # Guess no on OSF/1. + osf*) gl_cv_func_mbrtowc_null_arg2=3D"guessing no" ;; + # Guess yes otherwise. + *) gl_cv_func_mbrtowc_null_arg2=3D"guessing yes" ;; + esac +changequote([,])dnl + if test $LOCALE_FR_UTF8 !=3D none; then + AC_RUN_IFELSE( + [AC_LANG_SOURCE([[ +#include +#include +/* Tru64 with Desktop Toolkit C has a bug: must be included be= fore + . + BSD/OS 4.0.1 has a bug: , and must be + included before . */ +#include +#include +#include +#include +int main () +{ + if (setlocale (LC_ALL, "$LOCALE_FR_UTF8") !=3D NULL) + { + mbstate_t state; + wchar_t wc; + int ret; + + memset (&state, '\0', sizeof (mbstate_t)); + wc =3D (wchar_t) 0xBADFACE; + mbrtowc (&wc, NULL, 5, &state); + /* Check that wc was not modified. */ + if (wc !=3D (wchar_t) 0xBADFACE) + return 2; + } + return 0; +}]])], + [gl_cv_func_mbrtowc_null_arg2=3Dyes], + [gl_cv_func_mbrtowc_null_arg2=3Dno], + [:]) + fi + ]) +]) + +dnl Test whether mbrtowc, when parsing the end of a multibyte character, +dnl correctly returns the number of bytes that were needed to complete t= he +dnl character (not the total number of bytes of the multibyte character)= . +dnl Result is gl_cv_func_mbrtowc_retval. + +AC_DEFUN([gl_MBRTOWC_RETVAL], +[ + AC_REQUIRE([AC_PROG_CC]) + AC_REQUIRE([gt_LOCALE_FR_UTF8]) + AC_REQUIRE([gt_LOCALE_JA]) + AC_REQUIRE([AC_CANONICAL_HOST]) + AC_CACHE_CHECK([whether mbrtowc has a correct return value], + [gl_cv_func_mbrtowc_retval], + [ + dnl Initial guess, used when cross-compiling or when no suitable l= ocale + dnl is present. +changequote(,)dnl + case "$host_os" in + # Guess no on HP-UX, Solaris, native = Windows. + hpux* | solaris* | mingw*) gl_cv_func_mbrtowc_retval=3D"guessing= no" ;; + # Guess yes otherwise. + *) gl_cv_func_mbrtowc_retval=3D"guessing= yes" ;; + esac +changequote([,])dnl + if test $LOCALE_FR_UTF8 !=3D none || test $LOCALE_JA !=3D none \ + || { case "$host_os" in mingw*) true;; *) false;; esac; }; then + AC_RUN_IFELSE( + [AC_LANG_SOURCE([[ +#include +#include +/* Tru64 with Desktop Toolkit C has a bug: must be included be= fore + . + BSD/OS 4.0.1 has a bug: , and must be + included before . */ +#include +#include +#include +#include +int main () +{ + int result =3D 0; + int found_some_locale =3D 0; + /* This fails on Solaris. */ + if (setlocale (LC_ALL, "$LOCALE_FR_UTF8") !=3D NULL) + { + char input[] =3D "B\303\274\303\237er"; /* "B=C3=BC=C3=9Fer" */ + mbstate_t state; + wchar_t wc; + + memset (&state, '\0', sizeof (mbstate_t)); + if (mbrtowc (&wc, input + 1, 1, &state) =3D=3D (size_t)(-2)) + { + input[1] =3D '\0'; + if (mbrtowc (&wc, input + 2, 5, &state) !=3D 1) + result |=3D 1; + } + found_some_locale =3D 1; + } + /* This fails on HP-UX 11.11. */ + if (setlocale (LC_ALL, "$LOCALE_JA") !=3D NULL) + { + char input[] =3D "B\217\253\344\217\251\316er"; /* "B=C3=BC=C3=9Fe= r" */ + mbstate_t state; + wchar_t wc; + + memset (&state, '\0', sizeof (mbstate_t)); + if (mbrtowc (&wc, input + 1, 1, &state) =3D=3D (size_t)(-2)) + { + input[1] =3D '\0'; + if (mbrtowc (&wc, input + 2, 5, &state) !=3D 2) + result |=3D 2; + } + found_some_locale =3D 1; + } + /* This fails on native Windows. */ + if (setlocale (LC_ALL, "Japanese_Japan.932") !=3D NULL) + { + char input[] =3D "<\223\372\226\173\214\352>"; /* "<=E6=97=A5=E6=9C= =AC=E8=AA=9E>" */ + mbstate_t state; + wchar_t wc; + + memset (&state, '\0', sizeof (mbstate_t)); + if (mbrtowc (&wc, input + 3, 1, &state) =3D=3D (size_t)(-2)) + { + input[3] =3D '\0'; + if (mbrtowc (&wc, input + 4, 4, &state) !=3D 1) + result |=3D 4; + } + found_some_locale =3D 1; + } + if (setlocale (LC_ALL, "Chinese_Taiwan.950") !=3D NULL) + { + char input[] =3D "<\244\351\245\273\273\171>"; /* "<=E6=97=A5=E6=9C= =AC=E8=AA=9E>" */ + mbstate_t state; + wchar_t wc; + + memset (&state, '\0', sizeof (mbstate_t)); + if (mbrtowc (&wc, input + 3, 1, &state) =3D=3D (size_t)(-2)) + { + input[3] =3D '\0'; + if (mbrtowc (&wc, input + 4, 4, &state) !=3D 1) + result |=3D 8; + } + found_some_locale =3D 1; + } + if (setlocale (LC_ALL, "Chinese_China.936") !=3D NULL) + { + char input[] =3D "<\310\325\261\276\325\132>"; /* "<=E6=97=A5=E6=9C= =AC=E8=AA=9E>" */ + mbstate_t state; + wchar_t wc; + + memset (&state, '\0', sizeof (mbstate_t)); + if (mbrtowc (&wc, input + 3, 1, &state) =3D=3D (size_t)(-2)) + { + input[3] =3D '\0'; + if (mbrtowc (&wc, input + 4, 4, &state) !=3D 1) + result |=3D 16; + } + found_some_locale =3D 1; + } + return (found_some_locale ? result : 77); +}]])], + [gl_cv_func_mbrtowc_retval=3Dyes], + [if test $? !=3D 77; then + gl_cv_func_mbrtowc_retval=3Dno + fi + ], + [:]) + fi + ]) +]) + +dnl Test whether mbrtowc, when parsing a NUL character, correctly return= s 0. +dnl Result is gl_cv_func_mbrtowc_nul_retval. + +AC_DEFUN([gl_MBRTOWC_NUL_RETVAL], +[ + AC_REQUIRE([AC_PROG_CC]) + AC_REQUIRE([gt_LOCALE_ZH_CN]) + AC_REQUIRE([AC_CANONICAL_HOST]) dnl for cross-compiles + AC_CACHE_CHECK([whether mbrtowc returns 0 when parsing a NUL character= ], + [gl_cv_func_mbrtowc_nul_retval], + [ + dnl Initial guess, used when cross-compiling or when no suitable l= ocale + dnl is present. +changequote(,)dnl + case "$host_os" in + # Guess no on Solaris 8 and 9. + solaris2.[89]) gl_cv_func_mbrtowc_nul_retval=3D"guessing no" ;; + # Guess yes otherwise. + *) gl_cv_func_mbrtowc_nul_retval=3D"guessing yes" ;; + esac +changequote([,])dnl + if test $LOCALE_ZH_CN !=3D none; then + AC_RUN_IFELSE( + [AC_LANG_SOURCE([[ +#include +#include +/* Tru64 with Desktop Toolkit C has a bug: must be included be= fore + . + BSD/OS 4.0.1 has a bug: , and must be + included before . */ +#include +#include +#include +#include +int main () +{ + /* This fails on Solaris 8 and 9. */ + if (setlocale (LC_ALL, "$LOCALE_ZH_CN") !=3D NULL) + { + mbstate_t state; + wchar_t wc; + + memset (&state, '\0', sizeof (mbstate_t)); + if (mbrtowc (&wc, "", 1, &state) !=3D 0) + return 2; + } + return 0; +}]])], + [gl_cv_func_mbrtowc_nul_retval=3Dyes], + [gl_cv_func_mbrtowc_nul_retval=3Dno], + [:]) + fi + ]) +]) + +dnl Test whether mbrtowc returns the correct value on empty input. + +AC_DEFUN([gl_MBRTOWC_EMPTY_INPUT], +[ + AC_REQUIRE([AC_PROG_CC]) + AC_REQUIRE([AC_CANONICAL_HOST]) dnl for cross-compiles + AC_CACHE_CHECK([whether mbrtowc works on empty input], + [gl_cv_func_mbrtowc_empty_input], + [ + dnl Initial guess, used when cross-compiling or when no suitable l= ocale + dnl is present. +changequote(,)dnl + case "$host_os" in + # Guess no on AIX and glibc systems. + aix* | *-gnu* | gnu*) gl_cv_func_mbrtowc_empty_input=3D"guessing= no" ;; + # Guess yes on native Windows. + mingw*) gl_cv_func_mbrtowc_empty_input=3D"guessing= yes" ;; + *) gl_cv_func_mbrtowc_empty_input=3D"guessing= yes" ;; + esac +changequote([,])dnl + AC_RUN_IFELSE( + [AC_LANG_SOURCE([[ + #include + static wchar_t wc; + static mbstate_t mbs; + int + main (void) + { + return mbrtowc (&wc, "", 0, &mbs) !=3D (size_t) -2; + }]])], + [gl_cv_func_mbrtowc_empty_input=3Dyes], + [gl_cv_func_mbrtowc_empty_input=3Dno], + [:]) + ]) +]) + +dnl Test whether mbrtowc reports encoding errors in the C locale. +dnl Although POSIX was never intended to allow this, the GNU C Library +dnl and other implementations do it. See: +dnl https://sourceware.org/bugzilla/show_bug.cgi?id=3D19932 + +AC_DEFUN([gl_MBRTOWC_C_LOCALE], +[ + AC_REQUIRE([AC_CANONICAL_HOST]) dnl for cross-compiles + AC_CACHE_CHECK([whether the C locale is free of encoding errors], + [gl_cv_C_locale_sans_EILSEQ], + [ + dnl Initial guess, used when cross-compiling or when no suitable lo= cale + dnl is present. + gl_cv_C_locale_sans_EILSEQ=3D"guessing no" + + AC_RUN_IFELSE( + [AC_LANG_PROGRAM( + [[#include + #include + #include + ]], [[ + int i; + char *locale =3D setlocale (LC_ALL, "C"); + if (! locale) + return 2; + for (i =3D CHAR_MIN; i <=3D CHAR_MAX; i++) + { + char c =3D i; + wchar_t wc; + mbstate_t mbs =3D { 0, }; + size_t ss =3D mbrtowc (&wc, &c, 1, &mbs); + if (1 < ss) + return 3; + } + return 0; + ]])], + [gl_cv_C_locale_sans_EILSEQ=3Dyes], + [gl_cv_C_locale_sans_EILSEQ=3Dno], + [case "$host_os" in + # Guess yes on native Windows. + mingw*) gl_cv_C_locale_sans_EILSEQ=3D"guessing yes" ;; + esac + ]) + ]) +]) + +# Prerequisites of lib/mbrtowc.c. +AC_DEFUN([gl_PREREQ_MBRTOWC], [ + AC_REQUIRE([AC_C_INLINE]) + : +]) + + +dnl From Paul Eggert + +dnl This is an override of an autoconf macro. + +AC_DEFUN([AC_FUNC_MBRTOWC], +[ + dnl Same as AC_FUNC_MBRTOWC in autoconf-2.60. + AC_CACHE_CHECK([whether mbrtowc and mbstate_t are properly declared], + [gl_cv_func_mbrtowc], + [AC_LINK_IFELSE( + [AC_LANG_PROGRAM( + [[/* Tru64 with Desktop Toolkit C has a bug: must = be + included before . + BSD/OS 4.0.1 has a bug: , and + must be included before . */ + #include + #include + #include + #include ]], + [[wchar_t wc; + char const s[] =3D ""; + size_t n =3D 1; + mbstate_t state; + return ! (sizeof state && (mbrtowc) (&wc, s, n, &state));]= ])], + [gl_cv_func_mbrtowc=3Dyes], + [gl_cv_func_mbrtowc=3Dno])]) + if test $gl_cv_func_mbrtowc =3D yes; then + AC_DEFINE([HAVE_MBRTOWC], [1], + [Define to 1 if mbrtowc and mbstate_t are properly declared.]) + fi +]) diff --git a/m4/mbsinit.m4 b/m4/mbsinit.m4 new file mode 100644 index 0000000000..5cba3df0f0 --- /dev/null +++ b/m4/mbsinit.m4 @@ -0,0 +1,51 @@ +# mbsinit.m4 serial 8 +dnl Copyright (C) 2008, 2010-2018 Free Software Foundation, Inc. +dnl This file is free software; the Free Software Foundation +dnl gives unlimited permission to copy and/or distribute it, +dnl with or without modifications, as long as this notice is preserved. + +AC_DEFUN([gl_FUNC_MBSINIT], +[ + AC_REQUIRE([gl_WCHAR_H_DEFAULTS]) + AC_REQUIRE([AC_CANONICAL_HOST]) + + AC_REQUIRE([AC_TYPE_MBSTATE_T]) + gl_MBSTATE_T_BROKEN + + AC_CHECK_FUNCS_ONCE([mbsinit]) + if test $ac_cv_func_mbsinit =3D no; then + HAVE_MBSINIT=3D0 + AC_CHECK_DECLS([mbsinit],,, [[ +/* Tru64 with Desktop Toolkit C has a bug: must be included be= fore + . + BSD/OS 4.0.1 has a bug: , and must be + included before . */ +#include +#include +#include +#include +]]) + if test $ac_cv_have_decl_mbsinit =3D yes; then + dnl On Minix 3.1.8, the system's declares mbsinit() alth= ough + dnl it does not have the function. Avoid a collision with gnulib's + dnl replacement. + REPLACE_MBSINIT=3D1 + fi + else + if test $REPLACE_MBSTATE_T =3D 1; then + REPLACE_MBSINIT=3D1 + else + dnl On mingw, mbsinit() always returns 1, which is inappropriate f= or + dnl states produced by mbrtowc() for an incomplete multibyte chara= cter + dnl in multibyte locales. + case "$host_os" in + mingw*) REPLACE_MBSINIT=3D1 ;; + esac + fi + fi +]) + +# Prerequisites of lib/mbsinit.c. +AC_DEFUN([gl_PREREQ_MBSINIT], [ + : +]) diff --git a/m4/mbstate_t.m4 b/m4/mbstate_t.m4 new file mode 100644 index 0000000000..004aa0d17c --- /dev/null +++ b/m4/mbstate_t.m4 @@ -0,0 +1,41 @@ +# mbstate_t.m4 serial 13 +dnl Copyright (C) 2000-2002, 2008-2018 Free Software Foundation, Inc. +dnl This file is free software; the Free Software Foundation +dnl gives unlimited permission to copy and/or distribute it, +dnl with or without modifications, as long as this notice is preserved. + +# From Paul Eggert. + +# BeOS 5 has but does not define mbstate_t, +# so you can't declare an object of that type. +# Check for this incompatibility with Standard C. + +# AC_TYPE_MBSTATE_T +# ----------------- +AC_DEFUN([AC_TYPE_MBSTATE_T], +[ + AC_REQUIRE([AC_USE_SYSTEM_EXTENSIONS]) dnl for HP-UX 11.11 + + AC_CACHE_CHECK([for mbstate_t], [ac_cv_type_mbstate_t], + [AC_COMPILE_IFELSE( + [AC_LANG_PROGRAM( + [AC_INCLUDES_DEFAULT[ +/* Tru64 with Desktop Toolkit C has a bug: must be included be= fore + . + BSD/OS 4.0.1 has a bug: , and must be + included before . */ +#include +#include +#include +#include ]], + [[mbstate_t x; return sizeof x;]])], + [ac_cv_type_mbstate_t=3Dyes], + [ac_cv_type_mbstate_t=3Dno])]) + if test $ac_cv_type_mbstate_t =3D yes; then + AC_DEFINE([HAVE_MBSTATE_T], [1], + [Define to 1 if declares mbstate_t.]) + else + AC_DEFINE([mbstate_t], [int], + [Define to a type if does not define.]) + fi +]) diff --git a/m4/mbtowc.m4 b/m4/mbtowc.m4 new file mode 100644 index 0000000000..ecac6a2650 --- /dev/null +++ b/m4/mbtowc.m4 @@ -0,0 +1,19 @@ +# mbtowc.m4 serial 2 +dnl Copyright (C) 2011-2018 Free Software Foundation, Inc. +dnl This file is free software; the Free Software Foundation +dnl gives unlimited permission to copy and/or distribute it, +dnl with or without modifications, as long as this notice is preserved. + +AC_DEFUN([gl_FUNC_MBTOWC], +[ + AC_REQUIRE([gl_STDLIB_H_DEFAULTS]) + + if false; then + REPLACE_MBTOWC=3D1 + fi +]) + +# Prerequisites of lib/mbtowc.c. +AC_DEFUN([gl_PREREQ_MBTOWC], [ + : +]) diff --git a/m4/nl_langinfo.m4 b/m4/nl_langinfo.m4 new file mode 100644 index 0000000000..82d475024a --- /dev/null +++ b/m4/nl_langinfo.m4 @@ -0,0 +1,53 @@ +# nl_langinfo.m4 serial 6 +dnl Copyright (C) 2009-2018 Free Software Foundation, Inc. +dnl This file is free software; the Free Software Foundation +dnl gives unlimited permission to copy and/or distribute it, +dnl with or without modifications, as long as this notice is preserved. + +AC_DEFUN([gl_FUNC_NL_LANGINFO], +[ + AC_REQUIRE([gl_LANGINFO_H_DEFAULTS]) + AC_REQUIRE([gl_LANGINFO_H]) + AC_CHECK_FUNCS_ONCE([nl_langinfo]) + AC_REQUIRE([AC_CANONICAL_HOST]) dnl for cross-compiles + if test $ac_cv_func_nl_langinfo =3D yes; then + # On Irix 6.5, YESEXPR is defined, but nl_langinfo(YESEXPR) is broke= n. + AC_CACHE_CHECK([whether YESEXPR works], + [gl_cv_func_nl_langinfo_yesexpr_works], + [AC_RUN_IFELSE( + [AC_LANG_PROGRAM([[#include +]], [[return !*nl_langinfo(YESEXPR); +]])], + [gl_cv_func_nl_langinfo_yesexpr_works=3Dyes], + [gl_cv_func_nl_langinfo_yesexpr_works=3Dno], + [ + case "$host_os" in + # Guess no on irix systems. + irix*) gl_cv_func_nl_langinfo_yesexpr_works=3D"guessing no";= ; + # Guess yes elsewhere. + *) gl_cv_func_nl_langinfo_yesexpr_works=3D"guessing yes"= ;; + esac + ]) + ]) + case $gl_cv_func_nl_langinfo_yesexpr_works in + *yes) FUNC_NL_LANGINFO_YESEXPR_WORKS=3D1 ;; + *) FUNC_NL_LANGINFO_YESEXPR_WORKS=3D0 ;; + esac + AC_DEFINE_UNQUOTED([FUNC_NL_LANGINFO_YESEXPR_WORKS], + [$FUNC_NL_LANGINFO_YESEXPR_WORKS], + [Define to 1 if nl_langinfo (YESEXPR) returns a non-empty string.]= ) + if test $HAVE_LANGINFO_CODESET =3D 1 \ + && test $HAVE_LANGINFO_T_FMT_AMPM =3D 1 \ + && test $HAVE_LANGINFO_ALTMON =3D 1 \ + && test $HAVE_LANGINFO_ERA =3D 1 \ + && test $FUNC_NL_LANGINFO_YESEXPR_WORKS =3D 1; then + : + else + REPLACE_NL_LANGINFO=3D1 + AC_DEFINE([REPLACE_NL_LANGINFO], [1], + [Define if nl_langinfo exists but is overridden by gnulib.]) + fi + else + HAVE_NL_LANGINFO=3D0 + fi +]) diff --git a/m4/regex.m4 b/m4/regex.m4 new file mode 100644 index 0000000000..055d71b5aa --- /dev/null +++ b/m4/regex.m4 @@ -0,0 +1,300 @@ +# serial 67 + +# Copyright (C) 1996-2001, 2003-2018 Free Software Foundation, Inc. +# +# This file is free software; the Free Software Foundation +# gives unlimited permission to copy and/or distribute it, +# with or without modifications, as long as this notice is preserved. + +dnl Initially derived from code in GNU grep. +dnl Mostly written by Jim Meyering. + +AC_PREREQ([2.50]) + +AC_DEFUN([gl_REGEX], +[ + AC_REQUIRE([AC_CANONICAL_HOST]) dnl for cross-compiles + AC_ARG_WITH([included-regex], + [AS_HELP_STRING([--without-included-regex], + [don't compile regex; this is the default on systems + with recent-enough versions of the GNU C Library + (use with caution on other systems).])]) + + case $with_included_regex in #( + yes|no) ac_use_included_regex=3D$with_included_regex + ;; + '') + # If the system regex support is good enough that it passes the + # following run test, then default to *not* using the included regex= .c. + # If cross compiling, assume the test would fail and use the include= d + # regex.c. + AC_CHECK_DECLS_ONCE([alarm]) + AC_CHECK_HEADERS_ONCE([malloc.h]) + AC_CACHE_CHECK([for working re_compile_pattern], + [gl_cv_func_re_compile_pattern_working], + [AC_RUN_IFELSE( + [AC_LANG_PROGRAM( + [[#include + + #include + #include + #include + + #if defined M_CHECK_ACTION || HAVE_DECL_ALARM + # include + # include + #endif + + #if HAVE_MALLOC_H + # include + #endif + + #ifdef M_CHECK_ACTION + /* Exit with distinguishable exit code. */ + static void sigabrt_no_core (int sig) { raise (SIGTERM); } + #endif + ]], + [[int result =3D 0; + static struct re_pattern_buffer regex; + unsigned char folded_chars[UCHAR_MAX + 1]; + int i; + const char *s; + struct re_registers regs; + + /* Some builds of glibc go into an infinite loop on this + test. Use alarm to force death, and mallopt to avoid + malloc recursion in diagnosing the corrupted heap. */ +#if HAVE_DECL_ALARM + signal (SIGALRM, SIG_DFL); + alarm (2); +#endif +#ifdef M_CHECK_ACTION + signal (SIGABRT, sigabrt_no_core); + mallopt (M_CHECK_ACTION, 2); +#endif + + if (setlocale (LC_ALL, "en_US.UTF-8")) + { + { + /* https://sourceware.org/ml/libc-hacker/2006-09/msg00= 008.html + This test needs valgrind to catch the bug on Debian + GNU/Linux 3.1 x86, but it might catch the bug bette= r + on other platforms and it shouldn't hurt to try the + test here. */ + static char const pat[] =3D "insert into"; + static char const data[] =3D + "\xFF\0\x12\xA2\xAA\xC4\xB1,K\x12\xC4\xB1*\xACK"; + re_set_syntax (RE_SYNTAX_GREP | RE_HAT_LISTS_NOT_NEWLI= NE + | RE_ICASE); + memset (®ex, 0, sizeof regex); + s =3D re_compile_pattern (pat, sizeof pat - 1, ®ex)= ; + if (s) + result |=3D 1; + else if (re_search (®ex, data, sizeof data - 1, + 0, sizeof data - 1, ®s) + !=3D -1) + result |=3D 1; + regfree (®ex); + } + + { + /* This test is from glibc bug 15078. + The test case is from Andreas Schwab in + . + */ + static char const pat[] =3D "[^x]x"; + static char const data[] =3D + /* = */ + "\xe1\x80\x80" + "\xe1\x80\xbb" + "\xe1\x80\xbd" + "\xe1\x80\x94" + "\xe1\x80\xba" + "\xe1\x80\xaf" + "\xe1\x80\x95" + "\xe1\x80\xba" + "x"; + re_set_syntax (0); + memset (®ex, 0, sizeof regex); + s =3D re_compile_pattern (pat, sizeof pat - 1, ®ex)= ; + if (s) + result |=3D 1; + else + { + i =3D re_search (®ex, data, sizeof data - 1, + 0, sizeof data - 1, 0); + if (i !=3D 0 && i !=3D 21) + result |=3D 1; + } + regfree (®ex); + } + + if (! setlocale (LC_ALL, "C")) + return 1; + } + + /* This test is from glibc bug 3957, reported by Andrew Mack= ey. */ + re_set_syntax (RE_SYNTAX_EGREP | RE_HAT_LISTS_NOT_NEWLINE); + memset (®ex, 0, sizeof regex); + s =3D re_compile_pattern ("a[^x]b", 6, ®ex); + if (s) + result |=3D 2; + /* This should fail, but succeeds for glibc-2.5. */ + else if (re_search (®ex, "a\nb", 3, 0, 3, ®s) !=3D -1) + result |=3D 2; + + /* This regular expression is from Spencer ere test number 7= 5 + in grep-2.3. */ + re_set_syntax (RE_SYNTAX_POSIX_EGREP); + memset (®ex, 0, sizeof regex); + for (i =3D 0; i <=3D UCHAR_MAX; i++) + folded_chars[i] =3D i; + regex.translate =3D folded_chars; + s =3D re_compile_pattern ("a[[:@:>@:]]b\n", 11, ®ex); + /* This should fail with _Invalid character class name_ erro= r. */ + if (!s) + result |=3D 4; + + /* Ensure that [b-a] is diagnosed as invalid, when + using RE_NO_EMPTY_RANGES. */ + re_set_syntax (RE_SYNTAX_POSIX_EGREP | RE_NO_EMPTY_RANGES); + memset (®ex, 0, sizeof regex); + s =3D re_compile_pattern ("a[b-a]", 6, ®ex); + if (s =3D=3D 0) + result |=3D 8; + + /* This should succeed, but does not for glibc-2.1.3. */ + memset (®ex, 0, sizeof regex); + s =3D re_compile_pattern ("{1", 2, ®ex); + if (s) + result |=3D 8; + + /* The following example is derived from a problem report + against gawk from Jorge Stolfi . *= / + memset (®ex, 0, sizeof regex); + s =3D re_compile_pattern ("[an\371]*n", 7, ®ex); + if (s) + result |=3D 8; + /* This should match, but does not for glibc-2.2.1. */ + else if (re_match (®ex, "an", 2, 0, ®s) !=3D 2) + result |=3D 8; + + memset (®ex, 0, sizeof regex); + s =3D re_compile_pattern ("x", 1, ®ex); + if (s) + result |=3D 8; + /* glibc-2.2.93 does not work with a negative RANGE argument= . */ + else if (re_search (®ex, "wxy", 3, 2, -2, ®s) !=3D 1) + result |=3D 8; + + /* The version of regex.c in older versions of gnulib + ignored RE_ICASE. Detect that problem too. */ + re_set_syntax (RE_SYNTAX_EMACS | RE_ICASE); + memset (®ex, 0, sizeof regex); + s =3D re_compile_pattern ("x", 1, ®ex); + if (s) + result |=3D 16; + else if (re_search (®ex, "WXY", 3, 0, 3, ®s) < 0) + result |=3D 16; + + /* Catch a bug reported by Vin Shelton in + https://lists.gnu.org/r/bug-coreutils/2007-06/msg00089.ht= ml + */ + re_set_syntax (RE_SYNTAX_POSIX_BASIC + & ~RE_CONTEXT_INVALID_DUP + & ~RE_NO_EMPTY_RANGES); + memset (®ex, 0, sizeof regex); + s =3D re_compile_pattern ("[[:alnum:]_-]\\\\+$", 16, ®ex)= ; + if (s) + result |=3D 32; + + /* REG_STARTEND was added to glibc on 2004-01-15. + Reject older versions. */ + if (! REG_STARTEND) + result |=3D 64; + +#if 0 + /* It would be nice to reject hosts whose regoff_t values ar= e too + narrow (including glibc on hosts with 64-bit ptrdiff_t an= d + 32-bit int), but we should wait until glibc implements th= is + feature. Otherwise, support for equivalence classes and + multibyte collation symbols would always be broken except + when compiling --without-included-regex. */ + if (sizeof (regoff_t) < sizeof (ptrdiff_t) + || sizeof (regoff_t) < sizeof (ssize_t)) + result |=3D 64; +#endif + + return result; + ]])], + [gl_cv_func_re_compile_pattern_working=3Dyes], + [gl_cv_func_re_compile_pattern_working=3Dno], + [case "$host_os" in + # Guess no on native Windows. + mingw*) gl_cv_func_re_compile_pattern_working=3D"guessing no"= ;; + # Otherwise, assume it is not working. + *) gl_cv_func_re_compile_pattern_working=3D"guessing no"= ;; + esac + ]) + ]) + case "$gl_cv_func_re_compile_pattern_working" in #( + *yes) ac_use_included_regex=3Dno;; #( + *no) ac_use_included_regex=3Dyes;; + esac + ;; + *) AC_MSG_ERROR([Invalid value for --with-included-regex: $with_includ= ed_regex]) + ;; + esac + + if test $ac_use_included_regex =3D yes; then + AC_DEFINE([_REGEX_INCLUDE_LIMITS_H], [1], + [Define if you want to include , so that it + consistently overrides 's RE_DUP_MAX.]) + AC_DEFINE([_REGEX_LARGE_OFFSETS], [1], + [Define if you want regoff_t to be at least as wide POSIX requires= .]) + AC_DEFINE([re_syntax_options], [rpl_re_syntax_options], + [Define to rpl_re_syntax_options if the replacement should be used= .]) + AC_DEFINE([re_set_syntax], [rpl_re_set_syntax], + [Define to rpl_re_set_syntax if the replacement should be used.]) + AC_DEFINE([re_compile_pattern], [rpl_re_compile_pattern], + [Define to rpl_re_compile_pattern if the replacement should be use= d.]) + AC_DEFINE([re_compile_fastmap], [rpl_re_compile_fastmap], + [Define to rpl_re_compile_fastmap if the replacement should be use= d.]) + AC_DEFINE([re_search], [rpl_re_search], + [Define to rpl_re_search if the replacement should be used.]) + AC_DEFINE([re_search_2], [rpl_re_search_2], + [Define to rpl_re_search_2 if the replacement should be used.]) + AC_DEFINE([re_match], [rpl_re_match], + [Define to rpl_re_match if the replacement should be used.]) + AC_DEFINE([re_match_2], [rpl_re_match_2], + [Define to rpl_re_match_2 if the replacement should be used.]) + AC_DEFINE([re_set_registers], [rpl_re_set_registers], + [Define to rpl_re_set_registers if the replacement should be used.= ]) + AC_DEFINE([re_comp], [rpl_re_comp], + [Define to rpl_re_comp if the replacement should be used.]) + AC_DEFINE([re_exec], [rpl_re_exec], + [Define to rpl_re_exec if the replacement should be used.]) + AC_DEFINE([regcomp], [rpl_regcomp], + [Define to rpl_regcomp if the replacement should be used.]) + AC_DEFINE([regexec], [rpl_regexec], + [Define to rpl_regexec if the replacement should be used.]) + AC_DEFINE([regerror], [rpl_regerror], + [Define to rpl_regerror if the replacement should be used.]) + AC_DEFINE([regfree], [rpl_regfree], + [Define to rpl_regfree if the replacement should be used.]) + fi +]) + +# Prerequisites of lib/regex.c and lib/regex_internal.c. +AC_DEFUN([gl_PREREQ_REGEX], +[ + AC_REQUIRE([AC_USE_SYSTEM_EXTENSIONS]) + AC_REQUIRE([AC_C_INLINE]) + AC_REQUIRE([AC_C_RESTRICT]) + AC_REQUIRE([AC_TYPE_MBSTATE_T]) + AC_REQUIRE([gl_EEMALLOC]) + AC_REQUIRE([gl_GLIBC21]) + AC_CHECK_HEADERS([libintl.h]) + AC_CHECK_FUNCS_ONCE([isblank iswctype]) + AC_CHECK_DECLS([isblank], [], [], [[#include ]]) +]) diff --git a/m4/wchar_h.m4 b/m4/wchar_h.m4 new file mode 100644 index 0000000000..a062ca981d --- /dev/null +++ b/m4/wchar_h.m4 @@ -0,0 +1,240 @@ +dnl A placeholder for ISO C99 , for platforms that have issues. + +dnl Copyright (C) 2007-2018 Free Software Foundation, Inc. +dnl This file is free software; the Free Software Foundation +dnl gives unlimited permission to copy and/or distribute it, +dnl with or without modifications, as long as this notice is preserved. + +dnl Written by Eric Blake. + +# wchar_h.m4 serial 43 + +AC_DEFUN([gl_WCHAR_H], +[ + AC_REQUIRE([gl_WCHAR_H_DEFAULTS]) + AC_REQUIRE([gl_WCHAR_H_INLINE_OK]) + dnl Prepare for creating substitute . + dnl Check for (missing in Linux uClibc when built without wi= de + dnl character support). + dnl is always overridden, because of GNULIB_POSIXCHECK. + gl_CHECK_NEXT_HEADERS([wchar.h]) + if test $ac_cv_header_wchar_h =3D yes; then + HAVE_WCHAR_H=3D1 + else + HAVE_WCHAR_H=3D0 + fi + AC_SUBST([HAVE_WCHAR_H]) + + AC_REQUIRE([gl_FEATURES_H]) + + AC_REQUIRE([gt_TYPE_WINT_T]) + if test $gt_cv_c_wint_t =3D yes; then + HAVE_WINT_T=3D1 + else + HAVE_WINT_T=3D0 + fi + AC_SUBST([HAVE_WINT_T]) + + AC_REQUIRE([gl_TYPE_WINT_T_PREREQ]) + + dnl Check for declarations of anything we want to poison if the + dnl corresponding gnulib module is not in use. + gl_WARN_ON_USE_PREPARE([[ +/* Tru64 with Desktop Toolkit C has a bug: must be included be= fore + . + BSD/OS 4.0.1 has a bug: , and must be + included before . */ +#if !(defined __GLIBC__ && !defined __UCLIBC__) +# include +# include +# include +#endif +#include + ]], + [btowc wctob mbsinit mbrtowc mbrlen mbsrtowcs mbsnrtowcs wcrtomb + wcsrtombs wcsnrtombs wcwidth wmemchr wmemcmp wmemcpy wmemmove wmems= et + wcslen wcsnlen wcscpy wcpcpy wcsncpy wcpncpy wcscat wcsncat wcscmp + wcsncmp wcscasecmp wcsncasecmp wcscoll wcsxfrm wcsdup wcschr wcsrch= r + wcscspn wcsspn wcspbrk wcsstr wcstok wcswidth wcsftime + ]) +]) + +dnl Check whether is usable at all. +AC_DEFUN([gl_WCHAR_H_INLINE_OK], +[ + dnl Test whether suffers due to the transition from '__inlin= e' to + dnl 'gnu_inline'. See + dnl and . In sum= mary, + dnl glibc version 2.5 or older, together with gcc version 4.3 or newer= and + dnl the option -std=3Dc99 or -std=3Dgnu99, leads to a broken = . + AC_CACHE_CHECK([whether uses 'inline' correctly], + [gl_cv_header_wchar_h_correct_inline], + [gl_cv_header_wchar_h_correct_inline=3Dyes + AC_LANG_CONFTEST([ + AC_LANG_SOURCE([[#define wcstod renamed_wcstod +/* Tru64 with Desktop Toolkit C has a bug: must be included be= fore + . + BSD/OS 4.0.1 has a bug: , and must be + included before . */ +#include +#include +#include +#include +extern int zero (void); +int main () { return zero(); } +]])]) + dnl Do not rename the object file from conftest.$ac_objext to + dnl conftest1.$ac_objext, as this will cause the link to fail on + dnl z/OS when using the XPLINK object format (due to duplicate + dnl CSECT names). Instead, temporarily redefine $ac_compile so + dnl that the object file has the latter name from the start. + save_ac_compile=3D"$ac_compile" + ac_compile=3D`echo "$save_ac_compile" | sed s/conftest/conftest1/` + if echo '#include "conftest.c"' >conftest1.c && + AC_TRY_EVAL([ac_compile]); then + AC_LANG_CONFTEST([ + AC_LANG_SOURCE([[#define wcstod renamed_wcstod +/* Tru64 with Desktop Toolkit C has a bug: must be included be= fore + . + BSD/OS 4.0.1 has a bug: , and must be + included before . */ +#include +#include +#include +#include +int zero (void) { return 0; } +]])]) + dnl See note above about renaming object files. + ac_compile=3D`echo "$save_ac_compile" | sed s/conftest/conftest2/= ` + if echo '#include "conftest.c"' >conftest2.c && + AC_TRY_EVAL([ac_compile]); then + if $CC -o conftest$ac_exeext $CFLAGS $LDFLAGS conftest1.$ac_obj= ext conftest2.$ac_objext $LIBS >&AS_MESSAGE_LOG_FD 2>&1; then + : + else + gl_cv_header_wchar_h_correct_inline=3Dno + fi + fi + fi + ac_compile=3D"$save_ac_compile" + rm -f conftest[12].c conftest[12].$ac_objext conftest$ac_exeext + ]) + if test $gl_cv_header_wchar_h_correct_inline =3D no; then + AC_MSG_ERROR([ cannot be used with this compiler ($CC $CFLA= GS $CPPFLAGS). +This is a known interoperability problem of glibc <=3D 2.5 with gcc >=3D= 4.3 in +C99 mode. You have four options: + - Add the flag -fgnu89-inline to CC and reconfigure, or + - Fix your include files, using parts of + , or + - Use a gcc version older than 4.3, or + - Don't use the flags -std=3Dc99 or -std=3Dgnu99. +Configuration aborted.]) + fi +]) + +AC_DEFUN([gl_WCHAR_MODULE_INDICATOR], +[ + dnl Use AC_REQUIRE here, so that the default settings are expanded onc= e only. + AC_REQUIRE([gl_WCHAR_H_DEFAULTS]) + gl_MODULE_INDICATOR_SET_VARIABLE([$1]) + dnl Define it also as a C macro, for the benefit of the unit tests. + gl_MODULE_INDICATOR_FOR_TESTS([$1]) +]) + +AC_DEFUN([gl_WCHAR_H_DEFAULTS], +[ + GNULIB_BTOWC=3D0; AC_SUBST([GNULIB_BTOWC]) + GNULIB_WCTOB=3D0; AC_SUBST([GNULIB_WCTOB]) + GNULIB_MBSINIT=3D0; AC_SUBST([GNULIB_MBSINIT]) + GNULIB_MBRTOWC=3D0; AC_SUBST([GNULIB_MBRTOWC]) + GNULIB_MBRLEN=3D0; AC_SUBST([GNULIB_MBRLEN]) + GNULIB_MBSRTOWCS=3D0; AC_SUBST([GNULIB_MBSRTOWCS]) + GNULIB_MBSNRTOWCS=3D0; AC_SUBST([GNULIB_MBSNRTOWCS]) + GNULIB_WCRTOMB=3D0; AC_SUBST([GNULIB_WCRTOMB]) + GNULIB_WCSRTOMBS=3D0; AC_SUBST([GNULIB_WCSRTOMBS]) + GNULIB_WCSNRTOMBS=3D0; AC_SUBST([GNULIB_WCSNRTOMBS]) + GNULIB_WCWIDTH=3D0; AC_SUBST([GNULIB_WCWIDTH]) + GNULIB_WMEMCHR=3D0; AC_SUBST([GNULIB_WMEMCHR]) + GNULIB_WMEMCMP=3D0; AC_SUBST([GNULIB_WMEMCMP]) + GNULIB_WMEMCPY=3D0; AC_SUBST([GNULIB_WMEMCPY]) + GNULIB_WMEMMOVE=3D0; AC_SUBST([GNULIB_WMEMMOVE]) + GNULIB_WMEMSET=3D0; AC_SUBST([GNULIB_WMEMSET]) + GNULIB_WCSLEN=3D0; AC_SUBST([GNULIB_WCSLEN]) + GNULIB_WCSNLEN=3D0; AC_SUBST([GNULIB_WCSNLEN]) + GNULIB_WCSCPY=3D0; AC_SUBST([GNULIB_WCSCPY]) + GNULIB_WCPCPY=3D0; AC_SUBST([GNULIB_WCPCPY]) + GNULIB_WCSNCPY=3D0; AC_SUBST([GNULIB_WCSNCPY]) + GNULIB_WCPNCPY=3D0; AC_SUBST([GNULIB_WCPNCPY]) + GNULIB_WCSCAT=3D0; AC_SUBST([GNULIB_WCSCAT]) + GNULIB_WCSNCAT=3D0; AC_SUBST([GNULIB_WCSNCAT]) + GNULIB_WCSCMP=3D0; AC_SUBST([GNULIB_WCSCMP]) + GNULIB_WCSNCMP=3D0; AC_SUBST([GNULIB_WCSNCMP]) + GNULIB_WCSCASECMP=3D0; AC_SUBST([GNULIB_WCSCASECMP]) + GNULIB_WCSNCASECMP=3D0; AC_SUBST([GNULIB_WCSNCASECMP]) + GNULIB_WCSCOLL=3D0; AC_SUBST([GNULIB_WCSCOLL]) + GNULIB_WCSXFRM=3D0; AC_SUBST([GNULIB_WCSXFRM]) + GNULIB_WCSDUP=3D0; AC_SUBST([GNULIB_WCSDUP]) + GNULIB_WCSCHR=3D0; AC_SUBST([GNULIB_WCSCHR]) + GNULIB_WCSRCHR=3D0; AC_SUBST([GNULIB_WCSRCHR]) + GNULIB_WCSCSPN=3D0; AC_SUBST([GNULIB_WCSCSPN]) + GNULIB_WCSSPN=3D0; AC_SUBST([GNULIB_WCSSPN]) + GNULIB_WCSPBRK=3D0; AC_SUBST([GNULIB_WCSPBRK]) + GNULIB_WCSSTR=3D0; AC_SUBST([GNULIB_WCSSTR]) + GNULIB_WCSTOK=3D0; AC_SUBST([GNULIB_WCSTOK]) + GNULIB_WCSWIDTH=3D0; AC_SUBST([GNULIB_WCSWIDTH]) + GNULIB_WCSFTIME=3D0; AC_SUBST([GNULIB_WCSFTIME]) + dnl Assume proper GNU behavior unless another module says otherwise. + HAVE_BTOWC=3D1; AC_SUBST([HAVE_BTOWC]) + HAVE_MBSINIT=3D1; AC_SUBST([HAVE_MBSINIT]) + HAVE_MBRTOWC=3D1; AC_SUBST([HAVE_MBRTOWC]) + HAVE_MBRLEN=3D1; AC_SUBST([HAVE_MBRLEN]) + HAVE_MBSRTOWCS=3D1; AC_SUBST([HAVE_MBSRTOWCS]) + HAVE_MBSNRTOWCS=3D1; AC_SUBST([HAVE_MBSNRTOWCS]) + HAVE_WCRTOMB=3D1; AC_SUBST([HAVE_WCRTOMB]) + HAVE_WCSRTOMBS=3D1; AC_SUBST([HAVE_WCSRTOMBS]) + HAVE_WCSNRTOMBS=3D1; AC_SUBST([HAVE_WCSNRTOMBS]) + HAVE_WMEMCHR=3D1; AC_SUBST([HAVE_WMEMCHR]) + HAVE_WMEMCMP=3D1; AC_SUBST([HAVE_WMEMCMP]) + HAVE_WMEMCPY=3D1; AC_SUBST([HAVE_WMEMCPY]) + HAVE_WMEMMOVE=3D1; AC_SUBST([HAVE_WMEMMOVE]) + HAVE_WMEMSET=3D1; AC_SUBST([HAVE_WMEMSET]) + HAVE_WCSLEN=3D1; AC_SUBST([HAVE_WCSLEN]) + HAVE_WCSNLEN=3D1; AC_SUBST([HAVE_WCSNLEN]) + HAVE_WCSCPY=3D1; AC_SUBST([HAVE_WCSCPY]) + HAVE_WCPCPY=3D1; AC_SUBST([HAVE_WCPCPY]) + HAVE_WCSNCPY=3D1; AC_SUBST([HAVE_WCSNCPY]) + HAVE_WCPNCPY=3D1; AC_SUBST([HAVE_WCPNCPY]) + HAVE_WCSCAT=3D1; AC_SUBST([HAVE_WCSCAT]) + HAVE_WCSNCAT=3D1; AC_SUBST([HAVE_WCSNCAT]) + HAVE_WCSCMP=3D1; AC_SUBST([HAVE_WCSCMP]) + HAVE_WCSNCMP=3D1; AC_SUBST([HAVE_WCSNCMP]) + HAVE_WCSCASECMP=3D1; AC_SUBST([HAVE_WCSCASECMP]) + HAVE_WCSNCASECMP=3D1; AC_SUBST([HAVE_WCSNCASECMP]) + HAVE_WCSCOLL=3D1; AC_SUBST([HAVE_WCSCOLL]) + HAVE_WCSXFRM=3D1; AC_SUBST([HAVE_WCSXFRM]) + HAVE_WCSDUP=3D1; AC_SUBST([HAVE_WCSDUP]) + HAVE_WCSCHR=3D1; AC_SUBST([HAVE_WCSCHR]) + HAVE_WCSRCHR=3D1; AC_SUBST([HAVE_WCSRCHR]) + HAVE_WCSCSPN=3D1; AC_SUBST([HAVE_WCSCSPN]) + HAVE_WCSSPN=3D1; AC_SUBST([HAVE_WCSSPN]) + HAVE_WCSPBRK=3D1; AC_SUBST([HAVE_WCSPBRK]) + HAVE_WCSSTR=3D1; AC_SUBST([HAVE_WCSSTR]) + HAVE_WCSTOK=3D1; AC_SUBST([HAVE_WCSTOK]) + HAVE_WCSWIDTH=3D1; AC_SUBST([HAVE_WCSWIDTH]) + HAVE_WCSFTIME=3D1; AC_SUBST([HAVE_WCSFTIME]) + HAVE_DECL_WCTOB=3D1; AC_SUBST([HAVE_DECL_WCTOB]) + HAVE_DECL_WCWIDTH=3D1; AC_SUBST([HAVE_DECL_WCWIDTH]) + REPLACE_MBSTATE_T=3D0; AC_SUBST([REPLACE_MBSTATE_T]) + REPLACE_BTOWC=3D0; AC_SUBST([REPLACE_BTOWC]) + REPLACE_WCTOB=3D0; AC_SUBST([REPLACE_WCTOB]) + REPLACE_MBSINIT=3D0; AC_SUBST([REPLACE_MBSINIT]) + REPLACE_MBRTOWC=3D0; AC_SUBST([REPLACE_MBRTOWC]) + REPLACE_MBRLEN=3D0; AC_SUBST([REPLACE_MBRLEN]) + REPLACE_MBSRTOWCS=3D0; AC_SUBST([REPLACE_MBSRTOWCS]) + REPLACE_MBSNRTOWCS=3D0; AC_SUBST([REPLACE_MBSNRTOWCS]) + REPLACE_WCRTOMB=3D0; AC_SUBST([REPLACE_WCRTOMB]) + REPLACE_WCSRTOMBS=3D0; AC_SUBST([REPLACE_WCSRTOMBS]) + REPLACE_WCSNRTOMBS=3D0; AC_SUBST([REPLACE_WCSNRTOMBS]) + REPLACE_WCWIDTH=3D0; AC_SUBST([REPLACE_WCWIDTH]) + REPLACE_WCSWIDTH=3D0; AC_SUBST([REPLACE_WCSWIDTH]) + REPLACE_WCSFTIME=3D0; AC_SUBST([REPLACE_WCSFTIME]) +]) diff --git a/m4/wcrtomb.m4 b/m4/wcrtomb.m4 new file mode 100644 index 0000000000..c4e4463097 --- /dev/null +++ b/m4/wcrtomb.m4 @@ -0,0 +1,114 @@ +# wcrtomb.m4 serial 12 +dnl Copyright (C) 2008-2018 Free Software Foundation, Inc. +dnl This file is free software; the Free Software Foundation +dnl gives unlimited permission to copy and/or distribute it, +dnl with or without modifications, as long as this notice is preserved. + +AC_DEFUN([gl_FUNC_WCRTOMB], +[ + AC_REQUIRE([gl_WCHAR_H_DEFAULTS]) + + AC_REQUIRE([AC_TYPE_MBSTATE_T]) + gl_MBSTATE_T_BROKEN + + AC_CHECK_FUNCS_ONCE([wcrtomb]) + if test $ac_cv_func_wcrtomb =3D no; then + HAVE_WCRTOMB=3D0 + AC_CHECK_DECLS([wcrtomb],,, [[ +/* Tru64 with Desktop Toolkit C has a bug: must be included be= fore + . + BSD/OS 4.0.1 has a bug: , and must be + included before . */ +#include +#include +#include +#include +]]) + if test $ac_cv_have_decl_wcrtomb =3D yes; then + dnl On Minix 3.1.8, the system's declares wcrtomb() alth= ough + dnl it does not have the function. Avoid a collision with gnulib's + dnl replacement. + REPLACE_WCRTOMB=3D1 + fi + else + if test $REPLACE_MBSTATE_T =3D 1; then + REPLACE_WCRTOMB=3D1 + else + dnl On AIX 4.3, OSF/1 5.1 and Solaris 10, wcrtomb (NULL, 0, NULL) = sometimes + dnl returns 0 instead of 1. + AC_REQUIRE([AC_PROG_CC]) + AC_REQUIRE([gt_LOCALE_FR]) + AC_REQUIRE([gt_LOCALE_FR_UTF8]) + AC_REQUIRE([gt_LOCALE_JA]) + AC_REQUIRE([gt_LOCALE_ZH_CN]) + AC_REQUIRE([AC_CANONICAL_HOST]) dnl for cross-compiles + AC_CACHE_CHECK([whether wcrtomb return value is correct], + [gl_cv_func_wcrtomb_retval], + [ + dnl Initial guess, used when cross-compiling or when no suitab= le locale + dnl is present. +changequote(,)dnl + case "$host_os" in + # Guess no on AIX 4, OSF/1 and Sola= ris. + aix4* | osf* | solaris*) gl_cv_func_wcrtomb_retval=3D"guessi= ng no" ;; + # Guess yes on native Windows. + mingw*) gl_cv_func_wcrtomb_retval=3D"guessi= ng yes" ;; + # Guess yes otherwise. + *) gl_cv_func_wcrtomb_retval=3D"guessi= ng yes" ;; + esac +changequote([,])dnl + if test $LOCALE_FR !=3D none || test $LOCALE_FR_UTF8 !=3D none= || test $LOCALE_JA !=3D none || test $LOCALE_ZH_CN !=3D none; then + AC_RUN_IFELSE( + [AC_LANG_SOURCE([[ +#include +#include +/* Tru64 with Desktop Toolkit C has a bug: must be included be= fore + . + BSD/OS 4.0.1 has a bug: , and must be + included before . */ +#include +#include +#include +#include +int main () +{ + int result =3D 0; + if (setlocale (LC_ALL, "$LOCALE_FR") !=3D NULL) + { + if (wcrtomb (NULL, 0, NULL) !=3D 1) + result |=3D 1; + } + if (setlocale (LC_ALL, "$LOCALE_FR_UTF8") !=3D NULL) + { + if (wcrtomb (NULL, 0, NULL) !=3D 1) + result |=3D 2; + } + if (setlocale (LC_ALL, "$LOCALE_JA") !=3D NULL) + { + if (wcrtomb (NULL, 0, NULL) !=3D 1) + result |=3D 4; + } + if (setlocale (LC_ALL, "$LOCALE_ZH_CN") !=3D NULL) + { + if (wcrtomb (NULL, 0, NULL) !=3D 1) + result |=3D 8; + } + return result; +}]])], + [gl_cv_func_wcrtomb_retval=3Dyes], + [gl_cv_func_wcrtomb_retval=3Dno], + [:]) + fi + ]) + case "$gl_cv_func_wcrtomb_retval" in + *yes) ;; + *) REPLACE_WCRTOMB=3D1 ;; + esac + fi + fi +]) + +# Prerequisites of lib/wcrtomb.c. +AC_DEFUN([gl_PREREQ_WCRTOMB], [ + : +]) diff --git a/m4/wctype_h.m4 b/m4/wctype_h.m4 new file mode 100644 index 0000000000..15d1ef3253 --- /dev/null +++ b/m4/wctype_h.m4 @@ -0,0 +1,212 @@ +# wctype_h.m4 serial 21 + +dnl A placeholder for ISO C99 , for platforms that lack it. + +dnl Copyright (C) 2006-2018 Free Software Foundation, Inc. +dnl This file is free software; the Free Software Foundation +dnl gives unlimited permission to copy and/or distribute it, +dnl with or without modifications, as long as this notice is preserved. + +dnl Written by Paul Eggert. + +AC_DEFUN([gl_WCTYPE_H], +[ + AC_REQUIRE([gl_WCTYPE_H_DEFAULTS]) + AC_REQUIRE([AC_PROG_CC]) + AC_REQUIRE([AC_CANONICAL_HOST]) + AC_CHECK_FUNCS_ONCE([iswcntrl]) + if test $ac_cv_func_iswcntrl =3D yes; then + HAVE_ISWCNTRL=3D1 + else + HAVE_ISWCNTRL=3D0 + fi + AC_SUBST([HAVE_ISWCNTRL]) + + AC_REQUIRE([gt_TYPE_WINT_T]) + if test $gt_cv_c_wint_t =3D yes; then + HAVE_WINT_T=3D1 + else + HAVE_WINT_T=3D0 + fi + AC_SUBST([HAVE_WINT_T]) + + AC_REQUIRE([gl_TYPE_WINT_T_PREREQ]) + + gl_CHECK_NEXT_HEADERS([wctype.h]) + if test $ac_cv_header_wctype_h =3D yes; then + if test $ac_cv_func_iswcntrl =3D yes; then + dnl Linux libc5 has an iswprint function that returns 0 for all ar= guments. + dnl The other functions are likely broken in the same way. + AC_CACHE_CHECK([whether iswcntrl works], [gl_cv_func_iswcntrl_work= s], + [ + AC_RUN_IFELSE( + [AC_LANG_SOURCE([[ + /* Tru64 with Desktop Toolkit C has a bug: must= be + included before . + BSD/OS 4.0.1 has a bug: , and + must be included before . */ + #include + #include + #include + #include + #include + int main () { return iswprint ('x') =3D=3D 0; } + ]])], + [gl_cv_func_iswcntrl_works=3Dyes], [gl_cv_func_iswcntrl_work= s=3Dno], + [dnl Guess no on Linux libc5, yes otherwise. + AC_COMPILE_IFELSE([AC_LANG_PROGRAM([[#include + #if __GNU_LIBRARY__ =3D=3D 1 + Linux libc5 i18n is broken. + #endif]], [])], + [gl_cv_func_iswcntrl_works=3D"guessing yes"], + [gl_cv_func_iswcntrl_works=3D"guessing no"]) + ]) + ]) + fi + HAVE_WCTYPE_H=3D1 + else + HAVE_WCTYPE_H=3D0 + fi + AC_SUBST([HAVE_WCTYPE_H]) + + case "$gl_cv_func_iswcntrl_works" in + *yes) REPLACE_ISWCNTRL=3D0 ;; + *) REPLACE_ISWCNTRL=3D1 ;; + esac + AC_SUBST([REPLACE_ISWCNTRL]) + + if test $HAVE_ISWCNTRL =3D 0 || test $REPLACE_ISWCNTRL =3D 1; then + dnl Redefine all of iswcntrl, ..., iswxdigit in . + : + fi + + if test $REPLACE_ISWCNTRL =3D 1; then + REPLACE_TOWLOWER=3D1 + else + AC_CHECK_FUNCS([towlower]) + if test $ac_cv_func_towlower =3D yes; then + REPLACE_TOWLOWER=3D0 + else + AC_CHECK_DECLS([towlower],,, + [[/* Tru64 with Desktop Toolkit C has a bug: must be + included before . + BSD/OS 4.0.1 has a bug: , and + must be included before . */ + #include + #include + #include + #include + #if HAVE_WCTYPE_H + # include + #endif + ]]) + if test $ac_cv_have_decl_towlower =3D yes; then + dnl On Minix 3.1.8, the system's declares towlower() = and + dnl towupper() although it does not have the functions. Avoid a + dnl collision with gnulib's replacement. + REPLACE_TOWLOWER=3D1 + else + REPLACE_TOWLOWER=3D0 + fi + fi + fi + AC_SUBST([REPLACE_TOWLOWER]) + + if test $HAVE_ISWCNTRL =3D 0 || test $REPLACE_TOWLOWER =3D 1; then + dnl Redefine towlower, towupper in . + : + fi + + dnl We assume that the wctype() and iswctype() functions exist if and = only + dnl if the type wctype_t is defined in or in if t= hat + dnl exists. + dnl HP-UX 11.00 declares all these in and lacks . + AC_CACHE_CHECK([for wctype_t], [gl_cv_type_wctype_t], + [AC_COMPILE_IFELSE( + [AC_LANG_PROGRAM( + [[/* Tru64 with Desktop Toolkit C has a bug: must be + included before . + BSD/OS 4.0.1 has a bug: , and + must be included before . */ + #include + #include + #include + #include + #if HAVE_WCTYPE_H + # include + #endif + wctype_t a; + ]], + [[]])], + [gl_cv_type_wctype_t=3Dyes], + [gl_cv_type_wctype_t=3Dno]) + ]) + if test $gl_cv_type_wctype_t =3D no; then + HAVE_WCTYPE_T=3D0 + fi + + dnl We assume that the wctrans() and towctrans() functions exist if an= d only + dnl if the type wctrans_t is defined in . + AC_CACHE_CHECK([for wctrans_t], [gl_cv_type_wctrans_t], + [AC_COMPILE_IFELSE( + [AC_LANG_PROGRAM( + [[/* Tru64 with Desktop Toolkit C has a bug: must be + included before . + BSD/OS 4.0.1 has a bug: , and + must be included before . */ + #include + #include + #include + #include + #include + wctrans_t a; + ]], + [[]])], + [gl_cv_type_wctrans_t=3Dyes], + [gl_cv_type_wctrans_t=3Dno]) + ]) + if test $gl_cv_type_wctrans_t =3D no; then + HAVE_WCTRANS_T=3D0 + fi + + dnl Check for declarations of anything we want to poison if the + dnl corresponding gnulib module is not in use. + gl_WARN_ON_USE_PREPARE([[ +/* Tru64 with Desktop Toolkit C has a bug: must be included be= fore + . + BSD/OS 4.0.1 has a bug: , and must be + included before . */ +#if !(defined __GLIBC__ && !defined __UCLIBC__) +# include +# include +# include +# include +#endif +#include + ]], + [wctype iswctype wctrans towctrans + ]) +]) + +AC_DEFUN([gl_WCTYPE_MODULE_INDICATOR], +[ + dnl Use AC_REQUIRE here, so that the default settings are expanded onc= e only. + AC_REQUIRE([gl_WCTYPE_H_DEFAULTS]) + gl_MODULE_INDICATOR_SET_VARIABLE([$1]) + dnl Define it also as a C macro, for the benefit of the unit tests. + gl_MODULE_INDICATOR_FOR_TESTS([$1]) +]) + +AC_DEFUN([gl_WCTYPE_H_DEFAULTS], +[ + GNULIB_ISWBLANK=3D0; AC_SUBST([GNULIB_ISWBLANK]) + GNULIB_WCTYPE=3D0; AC_SUBST([GNULIB_WCTYPE]) + GNULIB_ISWCTYPE=3D0; AC_SUBST([GNULIB_ISWCTYPE]) + GNULIB_WCTRANS=3D0; AC_SUBST([GNULIB_WCTRANS]) + GNULIB_TOWCTRANS=3D0; AC_SUBST([GNULIB_TOWCTRANS]) + dnl Assume proper GNU behavior unless another module says otherwise. + HAVE_ISWBLANK=3D1; AC_SUBST([HAVE_ISWBLANK]) + HAVE_WCTYPE_T=3D1; AC_SUBST([HAVE_WCTYPE_T]) + HAVE_WCTRANS_T=3D1; AC_SUBST([HAVE_WCTRANS_T]) + REPLACE_ISWBLANK=3D0; AC_SUBST([REPLACE_ISWBLANK]) +]) diff --git a/m4/wint_t.m4 b/m4/wint_t.m4 new file mode 100644 index 0000000000..95f6854842 --- /dev/null +++ b/m4/wint_t.m4 @@ -0,0 +1,74 @@ +# wint_t.m4 serial 7 +dnl Copyright (C) 2003, 2007-2018 Free Software Foundation, Inc. +dnl This file is free software; the Free Software Foundation +dnl gives unlimited permission to copy and/or distribute it, +dnl with or without modifications, as long as this notice is preserved. + +dnl From Bruno Haible. +dnl Test whether has the 'wint_t' type and whether gnulib's +dnl or would, if present, override 'wint_t'. +dnl Prerequisite: AC_PROG_CC + +AC_DEFUN([gt_TYPE_WINT_T], +[ + AC_CACHE_CHECK([for wint_t], [gt_cv_c_wint_t], + [AC_COMPILE_IFELSE( + [AC_LANG_PROGRAM( + [[ +/* Tru64 with Desktop Toolkit C has a bug: must be included be= fore + . + BSD/OS 4.0.1 has a bug: , and must be in= cluded + before . */ +#include +#include +#include +#include + wint_t foo =3D (wchar_t)'\0';]], + [[]])], + [gt_cv_c_wint_t=3Dyes], + [gt_cv_c_wint_t=3Dno])]) + if test $gt_cv_c_wint_t =3D yes; then + AC_DEFINE([HAVE_WINT_T], [1], [Define if you have the 'wint_t' type.= ]) + + dnl Determine whether gnulib's or would, if pre= sent, + dnl override 'wint_t'. + AC_CACHE_CHECK([whether wint_t is too small], + [gl_cv_type_wint_t_too_small], + [AC_COMPILE_IFELSE( + [AC_LANG_PROGRAM([[ +/* Tru64 with Desktop Toolkit C has a bug: must be included be= fore + . + BSD/OS 4.0.1 has a bug: , and must be + included before . */ +#if !(defined __GLIBC__ && !defined __UCLIBC__) +# include +# include +# include +#endif +#include + int verify[sizeof (wint_t) < sizeof (int) ? -1 : 1]; + ]])], + [gl_cv_type_wint_t_too_small=3Dno], + [gl_cv_type_wint_t_too_small=3Dyes])]) + if test $gl_cv_type_wint_t_too_small =3D yes; then + GNULIB_OVERRIDES_WINT_T=3D1 + else + GNULIB_OVERRIDES_WINT_T=3D0 + fi + else + GNULIB_OVERRIDES_WINT_T=3D0 + fi + AC_SUBST([GNULIB_OVERRIDES_WINT_T]) +]) + +dnl Prerequisites of the 'wint_t' override. +AC_DEFUN([gl_TYPE_WINT_T_PREREQ], +[ + AC_CHECK_HEADERS_ONCE([crtdefs.h]) + if test $ac_cv_header_crtdefs_h =3D yes; then + HAVE_CRTDEFS_H=3D1 + else + HAVE_CRTDEFS_H=3D0 + fi + AC_SUBST([HAVE_CRTDEFS_H]) +]) diff --git a/src/Makefile.in b/src/Makefile.in index c3bcc50349..1aae27b2f9 100644 --- a/src/Makefile.in +++ b/src/Makefile.in @@ -391,7 +391,7 @@ base_obj =3D emacs.o keyboard.o macros.o keymap.o sysdep.o \ buffer.o filelock.o insdel.o marker.o \ minibuf.o fileio.o dired.o \ - cmds.o casetab.o casefiddle.o indent.o search.o regex.o undo.o \ + cmds.o casetab.o casefiddle.o indent.o search.o regex-emacs.o undo.o \ alloc.o data.o doc.o editfns.o callint.o \ eval.o floatfns.o fns.o font.o print.o lread.o $(MODULES_OBJ) \ syntax.o $(UNEXEC_OBJ) bytecode.o \ diff --git a/src/casetab.c b/src/casetab.c index 8f806a0647..289dc65b85 100644 --- a/src/casetab.c +++ b/src/casetab.c @@ -144,7 +144,7 @@ set_case_table (Lisp_Object table, bool standard) set_char_table_extras (table, 2, eqv); } =20 - /* This is so set_image_of_range_1 in regex.c can find the EQV table. = */ + /* This lets set_image_of_range_1 in regex-emacs.c find the EQV table.= */ set_char_table_extras (canon, 2, eqv); =20 if (standard) diff --git a/src/conf_post.h b/src/conf_post.h index 080d7b7e68..9758298437 100644 --- a/src/conf_post.h +++ b/src/conf_post.h @@ -202,13 +202,6 @@ extern void _DebPrint (const char *fmt, ...); #endif #endif =20 -#ifdef emacs /* Don't do this for lib-src. */ -/* Tell regex.c to use a type compatible with Emacs. */ -#define RE_TRANSLATE_TYPE Lisp_Object -#define RE_TRANSLATE(TBL, C) char_table_translate (TBL, C) -#define RE_TRANSLATE_P(TBL) (!EQ (TBL, make_number (0))) -#endif - /* Tell time_rz.c to use Emacs's getter and setter for TZ. Only Emacs uses time_rz so this is OK. */ #define getenv_TZ emacs_getenv_TZ diff --git a/src/deps.mk b/src/deps.mk index 7b6ae9cd8e..a12321d544 100644 --- a/src/deps.mk +++ b/src/deps.mk @@ -71,7 +71,7 @@ cmds.o: pre-crt0.o: pre-crt0.c dbusbind.o: dbusbind.c termhooks.h frame.h keyboard.h lisp.h $(config_h) dired.o: dired.c commands.h buffer.h lisp.h $(config_h) character.h char= set.h \ - coding.h regex.h systime.h blockinput.h atimer.h composite.h \ + coding.h regex-emacs.h systime.h blockinput.h atimer.h composite.h \ ../lib/filemode.h ../lib/unistd.h globals.h dispnew.o: dispnew.c systime.h commands.h process.h frame.h coding.h \ window.h buffer.h termchar.h termopts.h termhooks.h cm.h \ @@ -169,20 +169,20 @@ process.o: blockinput.h atimer.h coding.h msdos.h nsterm.h composite.h \ keyboard.h lisp.h globals.h $(config_h) character.h xgselect.h syssel= ect.h \ ../lib/unistd.h gnutls.h -regex.o: regex.c syntax.h buffer.h lisp.h globals.h $(config_h) regex.h = \ - category.h character.h +regex-emacs.o: regex-emacs.c syntax.h buffer.h lisp.h globals.h $(config= _h) \ + regex-emacs.h category.h character.h region-cache.o: region-cache.c buffer.h region-cache.h \ lisp.h globals.h $(config_h) scroll.o: scroll.c termchar.h dispextern.h frame.h msdos.h keyboard.h \ termhooks.h lisp.h globals.h $(config_h) systime.h coding.h composite= .h \ window.h -search.o: search.c regex.h commands.h buffer.h region-cache.h syntax.h \ +search.o: search.c regex-emacs.h commands.h buffer.h region-cache.h synt= ax.h \ blockinput.h atimer.h systime.h category.h character.h charset.h \ $(INTERVALS_H) lisp.h globals.h $(config_h) sound.o: sound.c dispextern.h syssignal.h lisp.h globals.h $(config_h) \ atimer.h systime.h ../lib/unistd.h msdos.h syntax.o: syntax.c syntax.h buffer.h commands.h category.h character.h \ - keymap.h regex.h $(INTERVALS_H) lisp.h globals.h $(config_h) + keymap.h regex-emacs.h $(INTERVALS_H) lisp.h globals.h $(config_h) sysdep.o: sysdep.c syssignal.h systty.h systime.h syswait.h blockinput.h= \ process.h dispextern.h termhooks.h termchar.h termopts.h coding.h \ frame.h atimer.h window.h msdos.h dosfns.h keyboard.h cm.h lisp.h \ diff --git a/src/emacs.c b/src/emacs.c index 861d70735c..ee77096918 100644 --- a/src/emacs.c +++ b/src/emacs.c @@ -84,7 +84,7 @@ along with GNU Emacs. If not, see . */ #include "composite.h" #include "dispextern.h" #include "ptr-bounds.h" -#include "regex.h" +#include "regex-emacs.h" #include "sheap.h" #include "syntax.h" #include "sysselect.h" @@ -846,9 +846,9 @@ main (int argc, char **argv) { rlim_t lim =3D rlim.rlim_cur; =20 - /* Approximate the amount regex.c needs per unit of + /* Approximate the amount regex-emacs.c needs per unit of emacs_re_max_failures, then add 33% to cover the size of the - smaller stacks that regex.c successively allocates and + smaller stacks that regex-emacs.c successively allocates and discards on its way to the maximum. */ int min_ratio =3D 20 * sizeof (char *); int ratio =3D min_ratio + min_ratio / 3; @@ -887,7 +887,7 @@ main (int argc, char **argv) lim =3D newlim; } } - /* If the stack is big enough, let regex.c more of it before + /* If the stack is big enough, give regex-emacs.c more of it befor= e falling back to heap allocation. */ emacs_re_safe_alloca =3D max (min (lim - extra, SIZE_MAX) * (min_ratio / ratio), diff --git a/src/regex.c b/src/regex-emacs.c similarity index 99% rename from src/regex.c rename to src/regex-emacs.c index 6ee13c4c99..968a25dc79 100644 --- a/src/regex.c +++ b/src/regex-emacs.c @@ -53,7 +53,7 @@ #include =20 #ifdef emacs -/* We need this for `regex.h', and perhaps for the Emacs include files. = */ +/* We need this for regex-emacs.h, and perhaps for the Emacs include fil= es. */ # include #endif =20 @@ -289,7 +289,7 @@ enum syntaxcode { Swhitespace =3D 0, Sword =3D 1, Ssy= mbol =3D 2 }; #endif =0C /* Get the interface, including the syntax bits. */ -#include "regex.h" +#include "regex-emacs.h" =20 /* isalpha etc. are used for the character classes. */ #include @@ -1157,7 +1157,7 @@ reg_syntax_t re_syntax_options; different, incompatible syntaxes. =20 The argument SYNTAX is a bit mask comprised of the various bits - defined in regex.h. We return the old syntax. */ + defined in regex-emacs.h. We return the old syntax. */ =20 reg_syntax_t re_set_syntax (reg_syntax_t syntax) @@ -1172,7 +1172,7 @@ WEAK_ALIAS (__re_set_syntax, re_set_syntax) #endif =0C /* 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. + in regex-emacs.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? */ =20 @@ -1474,28 +1474,28 @@ do { \ char *destination; \ /* Must be int, so when we don't save any registers, the arithmetic \ of 0 + -1 isn't done as unsigned. */ \ - \ + \ DEBUG_STATEMENT (nfailure_points_pushed++); \ DEBUG_PRINT ("\nPUSH_FAILURE_POINT:\n"); \ DEBUG_PRINT (" Before push, next avail: %zd\n", (fail_stack).avail); = \ DEBUG_PRINT (" size: %zd\n", (fail_stack).size);\ - \ + \ ENSURE_FAIL_STACK (NUM_NONREG_ITEMS); \ - \ + \ DEBUG_PRINT ("\n"); \ - \ + \ DEBUG_PRINT (" Push frame index: %zd\n", fail_stack.frame); \ PUSH_FAILURE_INT (fail_stack.frame); \ - \ + \ DEBUG_PRINT (" Push string %p: \"", string_place); \ DEBUG_PRINT_DOUBLE_STRING (string_place, string1, size1, string2, size= 2);\ DEBUG_PRINT ("\"\n"); \ PUSH_FAILURE_POINTER (string_place); \ - \ + \ DEBUG_PRINT (" Push pattern %p: ", pattern); \ DEBUG_PRINT_COMPILED_PATTERN (bufp, pattern, pend); \ PUSH_FAILURE_POINTER (pattern); \ - \ + \ /* Close the frame by moving the frame pointer past it. */ \ fail_stack.frame =3D fail_stack.avail; \ } while (0) @@ -1822,7 +1822,7 @@ struct range_table_work_area #define SETUP_ASCII_RANGE(work_area, FROM, TO) \ do { \ int C0, C1; \ - \ + \ for (C0 =3D (FROM); C0 <=3D (TO); C0++) \ { \ C1 =3D TRANSLATE (C0); \ @@ -1843,7 +1843,7 @@ struct range_table_work_area do { \ int C0, C1, C2, I; \ int USED =3D RANGE_TABLE_WORK_USED (work_area); \ - \ + \ for (C0 =3D (FROM); C0 <=3D (TO); C0++) \ { \ C1 =3D RE_CHAR_TO_MULTIBYTE (C0); \ @@ -1882,7 +1882,7 @@ struct range_table_work_area #define SETUP_MULTIBYTE_RANGE(work_area, FROM, TO) \ do { \ int C0, C1, C2, I, USED =3D RANGE_TABLE_WORK_USED (work_area); \ - \ + \ SET_RANGE_TABLE_WORK_AREA ((work_area), (FROM), (TO)); \ for (C0 =3D (FROM); C0 <=3D (TO); C0++) \ { \ @@ -1896,7 +1896,7 @@ struct range_table_work_area { \ int from =3D RANGE_TABLE_WORK_ELT (work_area, I); \ int to =3D RANGE_TABLE_WORK_ELT (work_area, I + 1); \ - \ + \ if (C1 >=3D from - 1 && C1 <=3D to + 1) \ { \ if (C1 =3D=3D from - 1) \ @@ -2371,7 +2371,7 @@ static boolean group_in_compile_stack (compile_stac= k_type compile_stack, regnum_t regnum); =20 /* `regex_compile' compiles PATTERN (of length SIZE) according to SYNTAX= . - Returns one of error codes defined in `regex.h', or zero for success. + Returns one of error codes defined in regex-emacs.h, or zero for succ= ess. =20 If WHITESPACE_REGEXP is given (only #ifdef emacs), it is used instead= of a space character in PATTERN. @@ -2714,15 +2714,15 @@ regex_compile (re_char *pattern, size_t size, =20 if (!zero_times_ok && simple) { /* Since simple * loops can be made faster by using - on_failure_keep_string_jump, we turn simple P+ - into PP* if P is simple. */ - unsigned char *p1, *p2; - startoffset =3D b - laststart; - GET_BUFFER_SPACE (startoffset); - p1 =3D b; p2 =3D laststart; - while (p2 < p1) - *b++ =3D *p2++; - zero_times_ok =3D 1; + on_failure_keep_string_jump, we turn simple P+ + into PP* if P is simple. */ + unsigned char *p1, *p2; + startoffset =3D b - laststart; + GET_BUFFER_SPACE (startoffset); + p1 =3D b; p2 =3D laststart; + while (p2 < p1) + *b++ =3D *p2++; + zero_times_ok =3D 1; } =20 GET_BUFFER_SPACE (6); @@ -6217,7 +6217,7 @@ re_match_2_internal (struct re_pattern_buffer *bufp= , re_char *string1, =20 FREE_VARIABLES (); =20 - return -1; /* Failure to match. */ + return -1; /* Failure to match. */ } =0C /* Subroutine definitions for re_match_2. */ @@ -6400,7 +6400,7 @@ re_exec (const char *s) routine will report only success or failure, and nothing about the registers. =20 - It returns 0 if it succeeds, nonzero if it doesn't. (See regex.h for + It returns 0 if it succeeds, nonzero if it doesn't. (See regex-emacs= .h for the return codes and their meanings.) */ =20 reg_errcode_t diff --git a/src/regex.h b/src/regex-emacs.h similarity index 98% rename from src/regex.h rename to src/regex-emacs.h index 3a2d74d86a..8a15e5793f 100644 --- a/src/regex.h +++ b/src/regex-emacs.h @@ -160,9 +160,9 @@ typedef unsigned long reg_syntax_t; =20 /* If this bit is set, turn on internal regex debugging. If not set, and debugging was on, turn it off. - This only works if regex.c is compiled -DDEBUG. + This only works if regex-emacs.c is compiled -DDEBUG. We define this bit always, so that all that's needed to turn on - debugging is to recompile regex.c; the calling code can always have + debugging is to recompile regex-emacs.c; the calling code can always = have this bit set, and it won't affect anything in the normal case. */ #define RE_DEBUG (RE_NO_NEWLINE_ANCHOR << 1) =20 @@ -219,7 +219,7 @@ extern ptrdiff_t emacs_re_safe_alloca; ((RE_SYNTAX_POSIX_EXTENDED | RE_BACKSLASH_ESCAPE_IN_LISTS | RE_DEBUG) = \ & ~(RE_DOT_NOT_NULL | RE_INTERVALS | RE_CONTEXT_INDEP_OPS)) =20 -#define RE_SYNTAX_POSIX_AWK \ +#define RE_SYNTAX_POSIX_AWK \ (RE_SYNTAX_POSIX_EXTENDED | RE_BACKSLASH_ESCAPE_IN_LISTS \ | RE_INTERVALS | RE_NO_GNU_OPS) =20 @@ -317,7 +317,7 @@ extern ptrdiff_t emacs_re_safe_alloca; =20 =20 /* If any error codes are removed, changed, or added, update the - `re_error_msg' table in regex.c. */ + re_error_msg table in regex-emacs.c. */ typedef enum { #ifdef _XOPEN_SOURCE @@ -350,6 +350,11 @@ typedef enum REG_ESIZEBR /* n or m too big in \{n,m\} */ } reg_errcode_t; =0C +/* Use a type compatible with Emacs. */ +#define RE_TRANSLATE_TYPE Lisp_Object +#define RE_TRANSLATE(TBL, C) char_table_translate (TBL, C) +#define RE_TRANSLATE_P(TBL) (!EQ (TBL, make_number (0))) + /* This data structure represents a compiled pattern. Before calling the pattern compiler, the fields `buffer', `allocated', `fastmap', `translate', and `no_sub' can be set. After the pattern has been @@ -650,5 +655,5 @@ typedef int re_wchar_t; =20 #endif /* not WIDE_CHAR_SUPPORT */ =20 -#endif /* regex.h */ +#endif /* regex-emacs.h */ =0C diff --git a/src/search.c b/src/search.c index ccdb659776..4ee70144fc 100644 --- a/src/search.c +++ b/src/search.c @@ -30,7 +30,7 @@ along with GNU Emacs. If not, see . */ #include "blockinput.h" #include "intervals.h" =20 -#include "regex.h" +#include "regex-emacs.h" =20 #define REGEXP_CACHE_SIZE 20 =20 @@ -290,7 +290,7 @@ looking_at_1 (Lisp_Object string, bool posix) if (running_asynch_code) save_search_regs (); =20 - /* This is so set_image_of_range_1 in regex.c can find the EQV table. = */ + /* This lets set_image_of_range_1 in regex-emacs.c find the EQV table.= */ set_char_table_extras (BVAR (current_buffer, case_canon_table), 2, BVAR (current_buffer, case_eqv_table)); =20 @@ -410,7 +410,7 @@ string_match_1 (Lisp_Object regexp, Lisp_Object strin= g, Lisp_Object start, pos_byte =3D string_char_to_byte (string, pos); } =20 - /* This is so set_image_of_range_1 in regex.c can find the EQV table. = */ + /* This lets set_image_of_range_1 in regex-emacs.c find the EQV table.= */ set_char_table_extras (BVAR (current_buffer, case_canon_table), 2, BVAR (current_buffer, case_eqv_table)); =20 @@ -1062,7 +1062,7 @@ search_command (Lisp_Object string, Lisp_Object bou= nd, Lisp_Object noerror, lim_byte =3D CHAR_TO_BYTE (lim); } =20 - /* This is so set_image_of_range_1 in regex.c can find the EQV table. = */ + /* This lets set_image_of_range_1 in regex-emacs.c find the EQV table.= */ set_char_table_extras (BVAR (current_buffer, case_canon_table), 2, BVAR (current_buffer, case_eqv_table)); =20 diff --git a/src/syntax.c b/src/syntax.c index c5a4b03955..5b875ad296 100644 --- a/src/syntax.c +++ b/src/syntax.c @@ -23,7 +23,7 @@ along with GNU Emacs. If not, see . */ #include "lisp.h" #include "character.h" #include "buffer.h" -#include "regex.h" +#include "regex-emacs.h" #include "syntax.h" #include "intervals.h" #include "category.h" @@ -267,7 +267,7 @@ SETUP_SYNTAX_TABLE (ptrdiff_t from, ptrdiff_t count) If it is t (which is only used in fast_c_string_match_ignore_case), ignore properties altogether. =20 - This is meant for regex.c to use. For buffers, regex.c passes argume= nts + This is meant so that for buffers, regex-emacs.c passes arguments to the UPDATE_SYNTAX_TABLE functions which are relative to BEGV. So if it is a buffer, we set the offset field to BEGV. */ =20 @@ -3729,7 +3729,7 @@ syms_of_syntax (void) staticpro (&gl_state.current_syntax_table); staticpro (&gl_state.old_prop); =20 - /* Defined in regex.c. */ + /* Defined in regex-emacs.c. */ staticpro (&re_match_object); =20 DEFSYM (Qscan_error, "scan-error"); diff --git a/src/thread.h b/src/thread.h index c10e5ecb75..dc5d5eca31 100644 --- a/src/thread.h +++ b/src/thread.h @@ -19,7 +19,7 @@ along with GNU Emacs. If not, see . */ #ifndef THREAD_H #define THREAD_H =20 -#include "regex.h" +#include "regex-emacs.h" =20 #ifdef WINDOWSNT #include diff --git a/test/src/regex-tests.el b/test/src/regex-emacs-tests.el similarity index 99% rename from test/src/regex-tests.el rename to test/src/regex-emacs-tests.el index 083ed5c4c8..7a075908a6 100644 --- a/test/src/regex-tests.el +++ b/test/src/regex-emacs-tests.el @@ -1,4 +1,4 @@ -;;; regex-tests.el --- tests for regex.c functions -*- lexical-binding: = t -*- +;;; regex-emacs-tests.el --- tests for regex-emacs.c -*- lexical-binding= : t -*- =20 ;; Copyright (C) 2015-2018 Free Software Foundation, Inc. =20 @@ -24,7 +24,7 @@ (defvar regex-tests--resources-dir (concat (concat (file-name-directory (or load-file-name buffer-file-na= me)) "/regex-resources/")) - "Path to regex-resources directory next to the \"regex-tests.el\" file= .") + "Path to regex-resources directory next to the \"regex-emacs-tests.el\= " file.") =20 (ert-deftest regex-word-cc-fallback-test () "Test that \"[[:cc:]]*x\" matches \"x\" (bug#24020). @@ -683,4 +683,4 @@ regex-tests-TESTS (should-not (string-match "\\`x\\{65535\\}" (make-string 65534 ?x))) (should-error (string-match "\\`x\\{65536\\}" "X") :type 'invalid-rege= xp)) =20 -;;; regex-tests.el ends here +;;; regex-emacs-tests.el ends here --=20 2.17.1