Zsh Mailing List Archive
Messages sorted by: Reverse Date, Date, Thread, Author

[PATCH] Add zsh/re2 module with conditions



Folks,

I tend to get automatically kicked off the -workers list by ezmlm
because I reject mails which are self-declared as spam, so please CC
replies to me.  Also: my commit-bit is currently
surrended-for-safekeeping because I've not been doing much with Zsh, so
someone else will need to merge this, if it's accepted.

RE2 is a regular expression library, written in C++, from Google.  It
offers most of the features of PCRE, excluding those which can't be
handled without backtracking.  It's BSD-licensed.  This patch adds the
zsh/re2 module.  It used the `cre` library to have C-language bindings.

At this point, I haven't done anything about rebinding =~ to handle
this.  It's purely new infix-operators based on words.  I'm thinking
perhaps something along the lines of $zsh_reop_modules=(regex), with
`setopt rematch_pcre` becoming a compatibility interface that acts as
though `pcre` were prepended to that list and

  zsh_reop_modules=(pcre regex)

having the same effect.  Then I could use `zsh_reop_modules=(re2 regex)`.
Does this seem sane?  Anyone have better suggestions?  I do want to have
=~ able to use this module, but the current work stands alone and should
be merge-able as-is.

Is there particular interest in having command-forms too?  There's no
"study" concept, but I suppose compiling a hairy regexp only once might
be good in some situations (but why use shell for those?)

This has been tested on MacOS 10.10.5.

My ulterior motive is that I want "better than zsh/regex" available by
default on MacOS, where Apple build without GPL modules for the system
Zsh.  I hope that by offering this option, Apple's engineers might
incorporate this one day and I can be happier. :)

I've also pushed this code to a GitHub repo, philpennock/zsh-code on the
re2 branch: https://github.com/philpennock/zsh-code/tree/re2

Tested with re2 20160901 installed via Brew, cre2 installed via:

    git clone https://github.com/marcomaggi/cre2
    cd cre2
      LIBTOOLIZE=glibtoolize sh ./autogen.sh
      CXX=g++-6 CC=gcc-6 ./configure --prefix=/opt/regexps
      make doc/stamp-vti
      make
      make install

and Zsh configured with:

    CPPFLAGS=-I/opt/regexps/include LDFLAGS=-L/opt/regexps/lib \
      ./configure --prefix=/opt/zsh-devel --enable-pcre --enable-re2 \
         --enable-cap --enable-multibyte --enable-zsh-secure-free \
         --with-tcsetpgrp --enable-etcdir=/etc

Feedback welcome.
(Oh, I can't spell "tough", it seems; deferring fix for now).

Regards,
-Phil

----------------------------8< git patch >8-----------------------------
Add support for Google's BSD-licensed RE2 library, via the cre
C-language bindings (also BSD-licensed).

Guard with --enable-re2 for now.

Adds 4 infix conditions.  Currently no commands, no support for changing
how =~ binds.

Includes tests & docs
---
 Doc/Makefile.in     |   2 +-
 Doc/Zsh/mod_re2.yo  |  65 +++++++++++
 INSTALL             |   8 ++
 Src/Modules/re2.c   | 324 ++++++++++++++++++++++++++++++++++++++++++++++++++++
 Src/Modules/re2.mdd |   5 +
 Test/V11re2.ztst    | 170 +++++++++++++++++++++++++++
 configure.ac        |  14 +++
 7 files changed, 587 insertions(+), 1 deletion(-)
 create mode 100644 Doc/Zsh/mod_re2.yo
 create mode 100644 Src/Modules/re2.c
 create mode 100644 Src/Modules/re2.mdd
 create mode 100644 Test/V11re2.ztst

diff --git a/Doc/Makefile.in b/Doc/Makefile.in
index 2752096..8c00876 100644
--- a/Doc/Makefile.in
+++ b/Doc/Makefile.in
@@ -65,7 +65,7 @@ Zsh/mod_datetime.yo Zsh/mod_db_gdbm.yo Zsh/mod_deltochar.yo \
 Zsh/mod_example.yo Zsh/mod_files.yo Zsh/mod_langinfo.yo \
 Zsh/mod_mapfile.yo Zsh/mod_mathfunc.yo Zsh/mod_newuser.yo \
 Zsh/mod_parameter.yo Zsh/mod_pcre.yo Zsh/mod_private.yo \
-Zsh/mod_regex.yo Zsh/mod_sched.yo Zsh/mod_socket.yo \
+Zsh/mod_re2.yo Zsh/mod_regex.yo Zsh/mod_sched.yo Zsh/mod_socket.yo \
 Zsh/mod_stat.yo  Zsh/mod_system.yo Zsh/mod_tcp.yo \
 Zsh/mod_termcap.yo Zsh/mod_terminfo.yo \
 Zsh/mod_zftp.yo Zsh/mod_zle.yo Zsh/mod_zleparameter.yo \
diff --git a/Doc/Zsh/mod_re2.yo b/Doc/Zsh/mod_re2.yo
new file mode 100644
index 0000000..5527440
--- /dev/null
+++ b/Doc/Zsh/mod_re2.yo
@@ -0,0 +1,65 @@
+COMMENT(!MOD!zsh/re2
+Interface to the RE2 regular expression library.
+!MOD!)
+cindex(regular expressions)
+cindex(re2)
+The tt(zsh/re2) module makes available the following test conditions:
+
+startitem()
+findex(re2-match)
+item(var(expr) tt(-re2-match) var(regex))(
+Matches a string against an RE2 regular expression.
+On successful match,
+matched portion of the string will normally be placed in the tt(MATCH)
+variable.  If there are any capturing parentheses within the regex, then
+the tt(match) array variable will contain those.
+If the match is not successful, then the variables will not be altered.
+
+In addition, the tt(MBEGIN) and tt(MEND) variables are updated to point
+to the offsets within var(expr) for the beginning and end of the matched
+text, with the tt(mbegin) and tt(mend) arrays holding the beginning and
+end of each substring matched.
+
+If tt(BASH_REMATCH) is set, then the array tt(BASH_REMATCH) will be set
+instead of all of the other variables.
+
+Canonical documentation for this syntax accepted by this regular expression
+engine can be found at:
+uref(https://github.com/google/re2/wiki/Syntax)
+)
+enditem()
+
+startitem()
+findex(re2-match-posix)
+item(var(expr) tt(-re2-match-posix) var(regex))(
+Matches as per tt(-re2-match) but configuring the RE2 engine to use
+POSIX syntax.
+)
+enditem()
+
+startitem()
+findex(re2-match-posixperl)
+item(var(expr) tt(-re2-match-posixperl) var(regex))(
+Matches as per tt(-re2-match) but configuring the RE2 engine to use
+POSIX syntax, with the Perl classes and word-boundary extensions re-enabled
+too.
+
+This thus adds support for:
+tt(\d), tt(\s), tt(\w), tt(\D), tt(\S), tt(\W), tt(\b), and tt(\B).
+)
+enditem()
+
+startitem()
+findex(re2-match-longest)
+item(var(expr) tt(-re2-match-longest) var(regex))(
+Matches as per tt(-re2-match) but configuring the RE2 engine to find
+the longest match, instead of the left-most.
+
+For example, given
+
+example([[ abb -re2-match-longest ^a+LPAR()b|bb+RPAR() ]])
+
+This will match the right-branch, thus tt(abb), where tt(-re2-match) would
+instead match only tt(ab).
+)
+enditem()
diff --git a/INSTALL b/INSTALL
index 99895bd..887dd8e 100644
--- a/INSTALL
+++ b/INSTALL
@@ -558,6 +558,14 @@ only be searched for if the option --enable-pcre is passed to configure.
 
 (Future versions of the shell may have a better fix for this problem.)
 
+--enable-re2:
+
+The RE2 library is written in C++, so a C-library shim layer is needed for
+use by Zsh.  We use https://github.com/marcomaggi/cre2 for this, which is
+currently at version 0.3.1.  Both re2 and cre2 need to be installed for
+this option to successfully enable the zsh/re2 module.  The Zsh
+functionality is currently experimental.
+
 --enable-cap:
 
 This searches for POSIX capabilities; if found, the `cap' library
diff --git a/Src/Modules/re2.c b/Src/Modules/re2.c
new file mode 100644
index 0000000..e542723
--- /dev/null
+++ b/Src/Modules/re2.c
@@ -0,0 +1,324 @@
+/*
+ * re2.c
+ *
+ * This file is part of zsh, the Z shell.
+ *
+ * Copyright (c) 2016 Phil Pennock
+ * All Rights Reserved.
+ *
+ * Permission is hereby granted, without written agreement and without
+ * license or royalty fees, to use, copy, modify, and distribute this
+ * software and to distribute modified versions of this software for any
+ * purpose, provided that the above copyright notice and the following
+ * two paragraphs appear in all copies of this software.
+ *
+ * In no event shall Phil Pennock or the Zsh Development Group be liable
+ * to any party for direct, indirect, special, incidental, or consequential
+ * damages arising out of the use of this software and its documentation,
+ * even if Phil Pennock and the Zsh Development Group have been advised of
+ * the possibility of such damage.
+ *
+ * Phil Pennock and the Zsh Development Group specifically disclaim any
+ * warranties, including, but not limited to, the implied warranties of
+ * merchantability and fitness for a particular purpose.  The software
+ * provided hereunder is on an "as is" basis, and Phil Pennock and the
+ * Zsh Development Group have no obligation to provide maintenance,
+ * support, updates, enhancements, or modifications.
+ *
+ */
+
+/* This is heavily based upon my earlier regex module, with Peter's fixes
+ * for the tought stuff I had skipped / gotten wrong. */
+
+#include "re2.mdh"
+#include "re2.pro"
+
+/*
+ * re2 itself is a C++ library; zsh needs C language bindings.
+ * These come from <https://github.com/marcomaggi/cre2>.
+ */
+#include <cre2.h>
+
+/* the conditions we support */
+#define ZRE2_COND_RE2		0
+#define ZRE2_COND_POSIX		1
+#define ZRE2_COND_POSIXPERL	2
+#define ZRE2_COND_LONGEST	3
+
+/**/
+static int
+zcond_re2_match(char **a, int id)
+{
+    cre2_regexp_t *rex;
+    cre2_options_t *opt;
+    cre2_string_t *m, *matches = NULL;
+    char *lhstr, *lhstr_zshmeta, *rhre, *rhre_zshmeta;
+    char **result_array, **x;
+    char *s;
+    char **mbegin, **mend, **bptr, **eptr;
+    size_t matchessz = 0;
+    int return_value, ncaptures, matched, nelem, start, n, indexing_base;
+    int remaining_len, charlen;
+    zlong offs;
+
+    return_value = 0; /* 1 => matched successfully */
+
+    lhstr_zshmeta = cond_str(a,0,0);
+    rhre_zshmeta = cond_str(a,1,0);
+    lhstr = ztrdup(lhstr_zshmeta);
+    unmetafy(lhstr, NULL);
+    rhre = ztrdup(rhre_zshmeta);
+    unmetafy(rhre, NULL);
+
+    opt = cre2_opt_new();
+    if (!opt) {
+	zwarn("re2 opt memory allocation failure");
+	goto CLEANUP_UNMETAONLY;
+    }
+    /* nb: we can set encoding here; re2 assumes UTF-8 by default */
+    cre2_opt_set_log_errors(opt, 0); /* don't hit stderr by default */
+    if (!isset(CASEMATCH)) {
+	cre2_opt_set_case_sensitive(opt, 0);
+    }
+
+    /* "The following options are only consulted when POSIX syntax is enabled;
+     * when POSIX syntax is disabled: these features are always enabled and
+     * cannot be turned off."
+     * Seems hard to mis-parse, but I did.  Okay, Perl classes \d,\w and friends
+     * always on normally, can _also_ be enabled in POSIX mode. */
+
+    switch (id) {
+    case ZRE2_COND_RE2:
+	/* nothing to do, this is default */
+	break;
+    case ZRE2_COND_POSIX:
+	cre2_opt_set_posix_syntax(opt, 1);
+	break;
+    case ZRE2_COND_POSIXPERL:
+	cre2_opt_set_posix_syntax(opt, 1);
+	/* we enable Perl classes (\d, \s, \w, \D, \S, \W)
+	 * and boundaries/not (\b \B) */
+	cre2_opt_set_perl_classes(opt, 1);
+	cre2_opt_set_word_boundary(opt, 1);
+	break;
+    case ZRE2_COND_LONGEST:
+	cre2_opt_set_longest_match(opt, 1);
+	break;
+    default:
+	DPUTS(1, "bad re2 option");
+	goto CLEANUP_UNMETAONLY;
+    }
+
+    rex = cre2_new(rhre, strlen(rhre), opt);
+    if (!rex) {
+	zwarn("re2 regular expression memory allocation failure");
+	goto CLEANUP_OPT;
+    }
+    if (cre2_error_code(rex)) {
+	zwarn("re2 rexexp compilation failed: %s", cre2_error_string(rex));
+	goto CLEANUP;
+    }
+
+    ncaptures = cre2_num_capturing_groups(rex);
+    /* the nmatch for cre2_match follows the usual pattern of index 0 holding
+     * the entire matched substring, index 1 holding the first capturing
+     * sub-expression, etc.  So we need ncaptures+1 elements. */
+    matchessz = (ncaptures + 1) * sizeof(cre2_string_t);
+    matches = zalloc(matchessz);
+
+    matched = cre2_match(rex,
+			 lhstr, strlen(lhstr), /* text to match against */
+			 0, strlen(lhstr), /* substring of text to consider */
+			 CRE2_UNANCHORED, /* user should explicitly anchor */
+			 matches, (ncaptures+1));
+    if (!matched)
+	goto CLEANUP;
+    return_value = 1;
+
+    /* We have a match, we will return success, we have array of cre2_string_t
+     * items, each with .data and .length fields pointing into the matched text,
+     * all in unmetafied format.
+     *
+     * We need to collect the results, put together various arrays and offset
+     * variables, while respecting options to change the array set, the indexing
+     * of that array and everything else that 26 years of history has endowed
+     * upon us. */
+    /* option BASHREMATCH set:
+     *    set $BASH_REMATCH instead of $MATCH/$match
+     *    entire matched portion in index 0 (useful with option KSH_ARRAYS)
+     * option _not_ set:
+     *    $MATCH scalar gets entire string
+     *    $match array gets substrings
+     *    $MBEGIN $MEND scalars get offsets of entire match
+     *    $mbegin $mend arrays get offsets of substrings
+     *    all of the offsets depend upon KSHARRAYS to determine indexing!
+     */
+
+    if (isset(BASHREMATCH)) {
+	start = 0;
+	nelem = ncaptures + 1;
+    } else {
+	start = 1;
+	nelem = ncaptures;
+    }
+    result_array = NULL;
+    if (nelem) {
+	result_array = x = (char **) zalloc(sizeof(char *) * (nelem + 1));
+	for (m = matches + start, n = start; n <= ncaptures; ++n, ++m, ++x) {
+	    /* .data is (const char *), metafy can modify in-place so takes
+	     * (char *) but doesn't modify given META_DUP, so safe to drop
+	     * the const. */
+	    *x = metafy((char *)m->data, m->length, META_DUP);
+	}
+	*x = NULL;
+    }
+
+    if (isset(BASHREMATCH)) {
+	setaparam("BASH_REMATCH", result_array);
+	goto CLEANUP;
+    }
+
+    indexing_base = isset(KSHARRAYS) ? 0 : 1;
+
+    setsparam("MATCH", metafy((char *)matches[0].data, matches[0].length, META_DUP));
+    /* count characters before the match */
+    s = lhstr;
+    remaining_len = matches[0].data - lhstr;
+    offs = 0;
+    MB_CHARINIT();
+    while (remaining_len) {
+	offs++;
+	charlen = MB_CHARLEN(s, remaining_len);
+	s += charlen;
+	remaining_len -= charlen;
+    }
+    setiparam("MBEGIN", offs + indexing_base);
+    /* then the characters within the match */
+    remaining_len = matches[0].length;
+    while (remaining_len) {
+	offs++;
+	charlen = MB_CHARLEN(s, remaining_len);
+	s += charlen;
+	remaining_len -= charlen;
+    }
+    /* zsh ${foo[a,b]} is inclusive of end-points, [a,b] not [a,b) */
+    setiparam("MEND", offs + indexing_base - 1);
+    if (!nelem) {
+	goto CLEANUP;
+    }
+
+    bptr = mbegin = (char **)zalloc(sizeof(char *)*(nelem+1));
+    eptr = mend = (char **)zalloc(sizeof(char *)*(nelem+1));
+    for (m = matches + start, n = 0;
+	 n < nelem;
+	 ++n, ++m, ++bptr, ++eptr)
+    {
+	char buf[DIGBUFSIZE];
+	if (m->data == NULL) {
+	    /* FIXME: have assumed this is the API for non-matching substrings; confirm! */
+	    *bptr = ztrdup("-1");
+	    *eptr = ztrdup("-1");
+	    continue;
+	}
+	s = lhstr;
+	remaining_len = m->data - lhstr;
+	offs = 0;
+	/* Find the start offset */
+	MB_CHARINIT();
+	while (remaining_len) {
+	    offs++;
+	    charlen = MB_CHARLEN(s, remaining_len);
+	    s += charlen;
+	    remaining_len -= charlen;
+	}
+	convbase(buf, offs + indexing_base, 10);
+	*bptr = ztrdup(buf);
+	/* Continue to the end offset */
+	remaining_len = m->length;
+	while (remaining_len) {
+	    offs++;
+	    charlen = MB_CHARLEN(s, remaining_len);
+	    s += charlen;
+	    remaining_len -= charlen;
+	}
+	convbase(buf, offs + indexing_base - 1, 10);
+	*eptr = ztrdup(buf);
+    }
+    *bptr = *eptr = NULL;
+
+    setaparam("match", result_array);
+    setaparam("mbegin", mbegin);
+    setaparam("mend", mend);
+
+CLEANUP:
+    if (matches)
+	zfree(matches, matchessz);
+    cre2_delete(rex);
+CLEANUP_OPT:
+    cre2_opt_delete(opt);
+CLEANUP_UNMETAONLY:
+    free(lhstr);
+    free(rhre);
+    return return_value;
+}
+
+
+static struct conddef cotab[] = {
+    CONDDEF("re2-match", CONDF_INFIX, zcond_re2_match, 0, 0, ZRE2_COND_RE2),
+    CONDDEF("re2-match-posix", CONDF_INFIX, zcond_re2_match, 0, 0, ZRE2_COND_POSIX),
+    CONDDEF("re2-match-posixperl", CONDF_INFIX, zcond_re2_match, 0, 0, ZRE2_COND_POSIXPERL),
+    CONDDEF("re2-match-longest", CONDF_INFIX, zcond_re2_match, 0, 0, ZRE2_COND_LONGEST),
+};
+
+
+static struct features module_features = {
+    NULL, 0,
+    cotab, sizeof(cotab)/sizeof(*cotab),
+    NULL, 0,
+    NULL, 0,
+    0
+};
+
+
+/**/
+int
+setup_(UNUSED(Module m))
+{
+    return 0;
+}
+
+/**/
+int
+features_(Module m, char ***features)
+{
+    *features = featuresarray(m, &module_features);
+    return 0;
+}
+
+/**/
+int
+enables_(Module m, int **enables)
+{
+    return handlefeatures(m, &module_features, enables);
+}
+
+/**/
+int
+boot_(UNUSED(Module m))
+{
+    return 0;
+}
+
+/**/
+int
+cleanup_(Module m)
+{
+    return setfeatureenables(m, &module_features, NULL);
+}
+
+/**/
+int
+finish_(UNUSED(Module m))
+{
+    return 0;
+}
diff --git a/Src/Modules/re2.mdd b/Src/Modules/re2.mdd
new file mode 100644
index 0000000..b20838c
--- /dev/null
+++ b/Src/Modules/re2.mdd
@@ -0,0 +1,5 @@
+name=zsh/re2
+link='if test "x$enable_re2" = xyes && test "x$ac_cv_lib_cre2_cre2_version_string" = xyes; then echo dynamic; else echo no; fi'
+load=no
+
+objects="re2.o"
diff --git a/Test/V11re2.ztst b/Test/V11re2.ztst
new file mode 100644
index 0000000..d6e327c
--- /dev/null
+++ b/Test/V11re2.ztst
@@ -0,0 +1,170 @@
+%prep
+
+  if ! zmodload -F zsh/re2 C:re2-match 2>/dev/null
+  then
+    ZTST_unimplemented="the zsh/re2 module is not available"
+    return 0
+  fi
+# Load the rest of the builtins
+  zmodload zsh/re2
+  ##FIXME#setopt rematch_pcre
+# Find a UTF-8 locale.
+  setopt multibyte
+# Don't let LC_* override our choice of locale.
+  unset -m LC_\*
+  mb_ok=
+  langs=(en_{US,GB}.{UTF-,utf}8 en.UTF-8
+	 $(locale -a 2>/dev/null | egrep 'utf8|UTF-8'))
+  for LANG in $langs; do
+    if [[ é = ? ]]; then
+      mb_ok=1
+      break;
+    fi
+  done
+  if [[ -z $mb_ok ]]; then
+    ZTST_unimplemented="no UTF-8 locale or multibyte mode is not implemented"
+  else
+    print -u $ZTST_fd Testing RE2 multibyte with locale $LANG
+    mkdir multibyte.tmp && cd multibyte.tmp
+  fi
+
+%test
+
+  [[ 'foo→bar' -re2-match .([^[:ascii:]]). ]]
+  print $MATCH
+  print $match[1]
+0:Basic non-ASCII regexp matching
+>o→b
+>→
+
+  [[ alphabeta -re2-match a([^a]+)a ]]
+  echo "$? basic"
+  print $MATCH
+  print $match[1]
+  [[ ! alphabeta -re2-match a(.+)a ]]
+  echo "$? negated op"
+  [[ alphabeta -re2-match ^b ]]
+  echo "$? failed match"
+# default matches on first, then takes longest substring
+# -longest keeps looking
+  [[ abb -re2-match a(b|bb) ]]
+  echo "$? first .${MATCH}.${match[1]}."
+  [[ abb -re2-match-longest a(b|bb) ]]
+  echo "$? longest .${MATCH}.${match[1]}."
+  [[ alphabeta -re2-match ab ]]; echo "$? unanchored"
+  [[ alphabeta -re2-match ^ab ]]; echo "$? anchored"
+  [[ alphabeta -re2-match '^a(\w+)a$' ]]
+  echo "$? perl class used"
+  echo ".${MATCH}. .${match[1]}."
+  [[ alphabeta -re2-match-posix '^a(\w+)a$' ]]
+  echo "$? POSIX-mode, should inhibit Perl class"
+  [[ alphabeta -re2-match-posixperl '^a(\w+)a$' ]]
+  echo "$? POSIX-mode with Perl classes enabled .${match[1]}."
+  unset MATCH match
+  [[ alphabeta -re2-match ^a([^a]+)a([^a]+)a$ ]]
+  echo "$? matched, set vars"
+  echo ".$MATCH. ${#MATCH}"
+  echo ".${(j:|:)match[*]}."
+  unset MATCH match
+  [[ alphabeta -re2-match fr(.+)d ]]
+  echo "$? unmatched, not setting MATCH/match"
+  echo ".$MATCH. ${#MATCH}"
+  echo ".${(j:|:)match[*]}."
+0:Basic matching & result codes
+>0 basic
+>alpha
+>lph
+>1 negated op
+>1 failed match
+>0 first .ab.b.
+>0 longest .abb.bb.
+>0 unanchored
+>1 anchored
+>0 perl class used
+>.alphabeta. .lphabet.
+>1 POSIX-mode, should inhibit Perl class
+>0 POSIX-mode with Perl classes enabled .lphabet.
+>0 matched, set vars
+>.alphabeta. 9
+>.lph|bet.
+>1 unmatched, not setting MATCH/match
+>.. 0
+>..
+
+  m() {
+    unset MATCH MBEGIN MEND match mbegin mend
+    [[ $2 -re2-match $3 ]]
+    print $? $1: m:${MATCH}: ma:${(j:|:)match}: MBEGIN=$MBEGIN MEND=$MEND mbegin="(${mbegin[*]})" mend="(${mend[*]})"
+  }
+  data='alpha beta gamma delta'
+  m uncapturing $data '\b\w+\b'
+  m capturing $data '\b(\w+)\b'
+  m 'capture 2' $data '\b(\w+)\s+(\w+)\b'
+  m 'capture repeat' $data '\b(?:(\w+)\s+)+(\w+)\b'
+0:Beginning and end testing
+>0 uncapturing: m:alpha: ma:: MBEGIN=1 MEND=5 mbegin=() mend=()
+>0 capturing: m:alpha: ma:alpha: MBEGIN=1 MEND=5 mbegin=(1) mend=(5)
+>0 capture 2: m:alpha beta: ma:alpha|beta: MBEGIN=1 MEND=10 mbegin=(1 7) mend=(5 10)
+>0 capture repeat: m:alpha beta gamma delta: ma:gamma|delta: MBEGIN=1 MEND=22 mbegin=(12 18) mend=(16 22)
+
+
+  unset match mend
+  s=$'\u00a0'
+  [[ $s -re2-match '^.$' ]] && print OK
+  [[ A${s}B -re2-match .(.). && $match[1] == $s ]] && print OK
+  [[ A${s}${s}B -re2-match A([^[:ascii:]]*)B && $mend[1] == 3 ]] && print OK
+  unset s
+0:Raw IMETA characters in input string
+>OK
+>OK
+>OK
+
+  [[ foo -re2-match f.+ ]] ; print $?
+  [[ foo -re2-match x.+ ]] ; print $?
+  [[ ! foo -re2-match f.+ ]] ; print $?
+  [[ ! foo -re2-match x.+ ]] ; print $?
+  [[ foo -re2-match f.+ && bar -re2-match b.+ ]] ; print $?
+  [[ foo -re2-match x.+ && bar -re2-match b.+ ]] ; print $?
+  [[ foo -re2-match f.+ && bar -re2-match x.+ ]] ; print $?
+  [[ ! foo -re2-match f.+ && bar -re2-match b.+ ]] ; print $?
+  [[ foo -re2-match f.+ && ! bar -re2-match b.+ ]] ; print $?
+  [[ ! ( foo -re2-match f.+ && bar -re2-match b.+ ) ]] ; print $?
+  [[ ! foo -re2-match x.+ && bar -re2-match b.+ ]] ; print $?
+  [[ foo -re2-match x.+ && ! bar -re2-match b.+ ]] ; print $?
+  [[ ! ( foo -re2-match x.+ && bar -re2-match b.+ ) ]] ; print $?
+0:Regex result inversion detection
+>0
+>1
+>1
+>0
+>0
+>1
+>1
+>1
+>1
+>1
+>0
+>1
+>0
+
+# Subshell because crash on failure
+  ( [[ test.txt -re2-match '^(.*_)?(test)' ]]
+    echo $match[2] )
+0:regression for segmentation fault (pcre, dup for re2), workers/38307
+>test
+
+  setopt BASH_REMATCH KSH_ARRAYS
+  unset MATCH MBEGIN MEND match mbegin mend BASH_REMATCH
+  [[ alphabeta -re2-match '^a([^a]+)(a)([^a]+)a$' ]]
+  echo "$? bash_rematch"
+  echo "m:${MATCH}: ma:${(j:|:)match}:"
+  echo MBEGIN=$MBEGIN MEND=$MEND mbegin="(${mbegin[*]})" mend="(${mend[*]})"
+  echo "BASH_REMATCH=[${(j:, :)BASH_REMATCH[@]}]"
+  echo "[0]=${BASH_REMATCH[0]} [1]=${BASH_REMATCH[1]}"
+0:bash_rematch works
+>0 bash_rematch
+>m:: ma::
+>MBEGIN= MEND= mbegin=() mend=()
+>BASH_REMATCH=[alphabeta, lph, a, bet]
+>[0]=alphabeta [1]=lph
+
diff --git a/configure.ac b/configure.ac
index 0e0bd53..9c23691 100644
--- a/configure.ac
+++ b/configure.ac
@@ -442,6 +442,11 @@ AC_ARG_ENABLE(pcre,
 AC_HELP_STRING([--enable-pcre],
 [enable the search for the pcre library (may create run-time library dependencies)]))
 
+dnl Do you want to look for re2 support?
+AC_ARG_ENABLE(re2,
+AC_HELP_STRING([--enable-re2],
+[enable the search for cre2 C-language bindings and re2 library]))
+
 dnl Do you want to look for capability support?
 AC_ARG_ENABLE(cap,
 AC_HELP_STRING([--enable-cap],
@@ -683,6 +688,15 @@ if test "x$ac_cv_prog_PCRECONF" = xpcre-config; then
 fi
 fi
 
+if test x$enable_re2 = xyes; then
+AC_CHECK_LIB([re2],[main],,
+  [AC_MSG_FAILURE([test for RE2 library failed])])
+AC_CHECK_LIB([cre2],[cre2_version_string],,
+  [AC_MSG_FAILURE([test for CRE2 library failed])])
+AC_CHECK_HEADERS([cre2.h],,
+  [AC_MSG_ERROR([test for RE2 header failed])])
+fi
+
 AC_CHECK_HEADERS(sys/time.h sys/times.h sys/select.h termcap.h termio.h \
 		 termios.h sys/param.h sys/filio.h string.h memory.h \
 		 limits.h fcntl.h libc.h sys/utsname.h sys/resource.h \
-- 
2.10.0

Attachment: signature.asc
Description: Digital signature



Messages sorted by: Reverse Date, Date, Thread, Author