aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorRobin Haberkorn <rhaberkorn@fmsbw.de>2026-06-27 17:07:31 +0200
committerRobin Haberkorn <rhaberkorn@fmsbw.de>2026-06-27 17:11:39 +0200
commit413bad8c8848bc2e31ac0034c58130ac67f3b1f8 (patch)
treeabf99972f5c8023e43377dcf07d72f330828afcf
parentfaa449f2c2353aad5ebd61f27181fdc576a6ab78 (diff)
downloadterex-413bad8c8848bc2e31ac0034c58130ac67f3b1f8.tar.gz
implemented REG_ANCHORED execution flag
* So you can anchor executions of already compiled patterns. In principle REG_BOSONLY could also be handled by the same code. * Required by SciTECO. * Test suite has been fixed and extended. The test program now takes getopt() style short arguments to specify flags.
-rw-r--r--README.md1
-rw-r--r--regc_lex.c1
-rw-r--r--regex.h3
-rw-r--r--regexec.c6
-rwxr-xr-xregtest_terex.sh117
5 files changed, 80 insertions, 48 deletions
diff --git a/README.md b/README.md
index d63d030..6958290 100644
--- a/README.md
+++ b/README.md
@@ -20,6 +20,7 @@ Compared to hsrex, this library has the following changes:
You no longer need to compile a special version of the library.
It expects Unicode strings by default unless specifying the `REG_RAW`
`tere_comp()` compilation flag.
+* Support the `REG_ANCHORED` flag for `tere_exec()`.
## TODO
diff --git a/regc_lex.c b/regc_lex.c
index f7b4c95..6186e10 100644
--- a/regc_lex.c
+++ b/regc_lex.c
@@ -322,6 +322,7 @@ next(
/*
* REG_BOSONLY
+ * FIXME: Let this be handled by REG_ANCHORED during execution as well?
*/
if (v->nexttype == EMPTY && (v->cflags&REG_BOSONLY)) {
diff --git a/regex.h b/regex.h
index 65455f9..167b414 100644
--- a/regex.h
+++ b/regex.h
@@ -230,7 +230,7 @@ typedef struct {
#define REG_DUMP 004000 /* none of your business :-) */
#define REG_FAKE 010000 /* none of your business :-) */
#define REG_PROGRESS 020000 /* none of your business :-) */
-#define REG_RAW 040000 /* pattern and subject are raw ASCII */
+#define REG_RAW 040000 /* pattern and subject are raw bytes */
/*
* execution
@@ -252,6 +252,7 @@ typedef struct {
#define REG_FTRACE 0010 /* none of your business */
#define REG_MTRACE 0020 /* none of your business */
#define REG_SMALL 0040 /* none of your business */
+#define REG_ANCHORED 0100 /* match anchored (see also REG_BOSONLY) */
/*
* misc generics (may be more functions here eventually)
diff --git a/regexec.c b/regexec.c
index d047929..848d911 100644
--- a/regexec.c
+++ b/regexec.c
@@ -415,6 +415,9 @@ find(
if (end != NULL) {
break; /* NOTE BREAK OUT */
}
+ if (v->eflags & REG_ANCHORED) {
+ break; /* NOTE BREAK OUT */
+ }
}
assert(end != NULL); /* search RE succeeded so loop should */
freedfa(d);
@@ -578,6 +581,9 @@ cfindloop(
estop = prevchr(v, end);
}
}
+ if (v->eflags & REG_ANCHORED) {
+ break; /* NOTE BREAK OUT */
+ }
}
} while (close < v->stop);
diff --git a/regtest_terex.sh b/regtest_terex.sh
index 75e051b..930867d 100755
--- a/regtest_terex.sh
+++ b/regtest_terex.sh
@@ -72,6 +72,7 @@ cat<<-EOF>$rgsrc
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
+ #include <unistd.h>
#include "regalone.h"
#include "regex.h"
size_t hexescapes2bin(unsigned char *t, char *src, size_t mxlen)
@@ -100,16 +101,27 @@ cat<<-EOF>$rgsrc
size_t relen, datlen;
regex_t cre;
regmatch_t pmatch[100];
- int cflags, nmatch, rc;
+ int nmatch, rc, ch;
+ int cflags = REG_ADVANCED, eflags = 0;
char buf[1024*2];
//memset(&cre, '\0', sizeof(cre));
- nmatch = atoi(argv[2]);
- relen = hexescapes2bin(re, argv[3], sizeof(re)/sizeof(char));
- datlen = hexescapes2bin(dat, argv[4], sizeof(dat)/sizeof(char));
- cflags = REG_ADVANCED | (nmatch ? 0 : REG_NOSUB);
- if ( atoi(argv[1]) != 0 ) cflags |= REG_RAW;
- rc = re_comp(&cre, re, relen, cflags);
+
+ while ((ch = getopt(argc, argv, "raA")) != -1) {
+ switch (ch) {
+ case 'r': cflags |= REG_RAW; break;
+ case 'a': cflags |= REG_BOSONLY; break;
+ case 'A': eflags |= REG_ANCHORED; break;
+ }
+ }
+ argc -= optind;
+ argv += optind;
+
+ nmatch = atoi(argv[0]);
+ if (!nmatch) cflags |= REG_NOSUB;
+ relen = hexescapes2bin(re, argv[1], sizeof(re)/sizeof(char));
+ datlen = hexescapes2bin(dat, argv[2], sizeof(dat)/sizeof(char));
+ rc = tere_comp(&cre, re, relen, cflags);
if ( rc != REG_OKAY )
{
regerror(rc, &cre, buf, sizeof(buf));
@@ -124,7 +136,7 @@ cat<<-EOF>$rgsrc
nmatch, cre.re_nsub);
return 1;
}
- rc = re_exec(&cre, dat, datlen, NULL, 100, pmatch, 0);
+ rc = tere_exec(&cre, dat, datlen, NULL, 100, pmatch, eflags);
if ( rc != REG_OKAY )
{
regerror(rc, &cre, buf, sizeof(buf));
@@ -140,7 +152,7 @@ cat<<-EOF>$rgsrc
sprintf(&buf[strlen(buf)], "%s%.*s",
i>1 ? ":" : "",
(int)(pmatch[i].rm_eo-pmatch[i].rm_so),
- argv[4]+pmatch[i].rm_so);
+ argv[2]+pmatch[i].rm_so);
printf("%s\n", buf);
}
regfree(&cre);
@@ -153,69 +165,73 @@ export PATH LD_LIBRARY_PATH
$CC -Wall -g -O0 -I. -I$H/inc -L. -lterex -o $rgbin $rgsrc
#-----------------------------------
msg="Simple match"
-resp=`$rgbin 0 0 "clavo" "Pablito clavo un clavito" 2>&1`
+resp=`$rgbin 0 "clavo" "Pablito clavo un clavito" 2>&1`
test -z "$resp" && f_ok "$msg" || f_no "$msg" "$resp"
-resp=`$rgbin 1 0 "clavo" "Pablito clavo un clavito" 2>&1`
+resp=`$rgbin -r 0 "clavo" "Pablito clavo un clavito" 2>&1`
test -z "$resp" && f_ok "$msg (raw)" || f_no "$msg (raw)" "$resp"
#-----------------------------------
msg="yyyy-mm-dd between 1900-01-01 and 2099-12-31"
-resp=`$rgbin 0 0 \
+resp=`$rgbin 0 \
"(19|20)\d\d[- /.](0[1-9]|1[012])[- /.](0[1-9]|[12][0-9]|3[01])" \
"1960-10-12" 2>&1`
test -z "$resp" && f_ok "$msg" || f_no "$msg" "$resp"
-resp=`$rgbin 1 0 \
+resp=`$rgbin -r 0 \
"(19|20)\d\d[- /.](0[1-9]|1[012])[- /.](0[1-9]|[12][0-9]|3[01])" \
"1960-10-12" 2>&1`
test -z "$resp" && f_ok "$msg (raw)" || f_no "$msg (raw)" "$resp"
#-----------------------------------
msg="yyyy-mm-dd out of 1900-01-01 and 2099-12-31"
-resp=`$rgbin 0 0 \
+resp=`$rgbin 0 \
"(19|20)\d\d[- /.](0[1-9]|1[012])[- /.](0[1-9]|[12][0-9]|3[01])" \
"El arzobispo 1960-14-12 de Constantinopla" 2>&1`
if echo "$resp"|grep "failed to match">/dev/null;
then f_ok "$msg"; else f_no "$msg" "$resp"; fi
-resp=`$rgbin 1 0 \
+resp=`$rgbin -r 0 \
"(19|20)\d\d[- /.](0[1-9]|1[012])[- /.](0[1-9]|[12][0-9]|3[01])" \
"El arzobispo 1960-14-12 de Constantinopla" 2>&1`
if echo "$resp"|grep "failed to match">/dev/null;
then f_ok "$msg (raw)"; else f_no "$msg (raw)" "$resp"; fi
#-----------------------------------
msg="1..999"
-resp=`$rgbin 0 0 "^([1-9]|[1-9][0-9]|[1-9][0-9][0-9])$" "432" 2>&1`
+resp=`$rgbin 0 "^([1-9]|[1-9][0-9]|[1-9][0-9][0-9])$" "432" 2>&1`
test -z "$resp" && f_ok "$msg" || f_no "$msg" "$resp"
-resp=`$rgbin 1 0 "^([1-9]|[1-9][0-9]|[1-9][0-9][0-9])$" "432" 2>&1`
+resp=`$rgbin -r 0 "^([1-9]|[1-9][0-9]|[1-9][0-9][0-9])$" "432" 2>&1`
test -z "$resp" && f_ok "$msg (raw)" || f_no "$msg (raw)" "$resp"
#-----------------------------------
msg="Bad 1..999"
-resp=`$rgbin 0 0 "^([1-9]|[1-9][0-9]|[1-9][0-9][0-9])$" " 4321" 2>&1`
+resp=`$rgbin 0 "^([1-9]|[1-9][0-9]|[1-9][0-9][0-9])$" " 4321" 2>&1`
if echo "$resp"|grep "failed to match">/dev/null;
then f_ok "$msg"; else f_no "$msg" "$resp"; fi
-resp=`$rgbin 1 0 "^([1-9]|[1-9][0-9]|[1-9][0-9][0-9])$" " 4321" 2>&1`
+resp=`$rgbin -r 0 "^([1-9]|[1-9][0-9]|[1-9][0-9][0-9])$" " 4321" 2>&1`
if echo "$resp"|grep "failed to match">/dev/null;
then f_ok "$msg (raw)"; else f_no "$msg (raw)" "$resp"; fi
#-----------------------------------
msg="Quantifier: One to three words between 'word1' and 'word2'"
-resp=`$rgbin 0 0 "word1\W+(?:\w+\W+){1,3}?word2" \
- "word1 clavo un clavito word2" 2>&1`
+resp=`$rgbin 0 \
+ "word1\W+(?:\w+\W+){1,3}?word2" \
+ "word1 clavo un clavito word2" 2>&1`
test -z "$resp" && f_ok "$msg" || f_no "$msg" "$resp"
-resp=`$rgbin 1 0 "word1\W+(?:\w+\W+){1,3}?word2" \
- "word1 clavo un clavito word2" 2>&1`
+resp=`$rgbin -r 0 \
+ "word1\W+(?:\w+\W+){1,3}?word2" \
+ "word1 clavo un clavito word2" 2>&1`
test -z "$resp" && f_ok "$msg (raw)" || f_no "$msg (raw)" "$resp"
#-----------------------------------
msg="Pathological: a?^6a^15 against aaaaaaaaaaaaaaaaaa..."
-resp=`$rgbin 0 0 "a?a?a?a?a?aaaaaaaaaaaaaaa" \
- "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa" 2>&1`
+resp=`$rgbin 0 \
+ "a?a?a?a?a?aaaaaaaaaaaaaaa" \
+ "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa" 2>&1`
test -z "$resp" && f_ok "$msg" || f_no "$msg" "$resp"
-resp=`$rgbin 1 0 "a?a?a?a?a?aaaaaaaaaaaaaaa" \
- "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa" 2>&1`
+resp=`$rgbin -r 0 \
+ "a?a?a?a?a?aaaaaaaaaaaaaaa" \
+ "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa" 2>&1`
test -z "$resp" && f_ok "$msg (raw)" || f_no "$msg (raw)" "$resp"
#-----------------------------------
msg="Pathological: (a|aa)*b against aaaaaaaaaaaaaaaaaa...b"
-resp=`$rgbin 0 0 "(a|aa)*b" \
- "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaab" 2>&1`
+resp=`$rgbin 0 \
+ "(a|aa)*b" "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaab" 2>&1`
test -z "$resp" && f_ok "$msg" || f_no "$msg" "$resp"
-resp=`$rgbin 1 0 "(a|aa)*b" \
- "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaab" 2>&1`
+resp=`$rgbin -r 0 \
+ "(a|aa)*b" "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaab" 2>&1`
test -z "$resp" && f_ok "$msg (raw)" || f_no "$msg (raw)" "$resp"
#-----------------------------------
cat<<-EOF>$datsrc
@@ -263,9 +279,9 @@ while test $i -lt 5; do
i=`expr $i + 1`
done
msg="5 group patterns taken with bracket ranges"
-resp=`$rgbin 0 5 "$totre" "$totdat" 2>&1`
+resp=`$rgbin 5 "$totre" "$totdat" 2>&1`
test "$resp" = "$expectedresp" && f_ok "$msg" || f_no "$msg" "$resp"
-resp=`$rgbin 1 5 "$totre" "$totdat" 2>&1`
+resp=`$rgbin -r 5 "$totre" "$totdat" 2>&1`
test "$resp" = "$expectedresp" && f_ok "$msg (raw)" || f_no "$msg (raw)" "$resp"
#-----------------------------------
i=0
@@ -280,9 +296,9 @@ while test $i -lt 10; do
i=`expr $i + 1`
done
msg="10 group patterns taken with bracket ranges"
-resp=`$rgbin 0 10 "$totre" "$totdat" 2>&1`
+resp=`$rgbin 10 "$totre" "$totdat" 2>&1`
test "$resp" = "$expectedresp" && f_ok "$msg" || f_no "$msg" "$resp"
-resp=`$rgbin 1 10 "$totre" "$totdat" 2>&1`
+resp=`$rgbin -r 10 "$totre" "$totdat" 2>&1`
test "$resp" = "$expectedresp" && f_ok "$msg (raw)" || f_no "$msg (raw)" "$resp"
#-----------------------------------
i=0
@@ -297,9 +313,9 @@ while test $i -lt 99; do
i=`expr $i + 1`
done
msg="99 group patterns taken with bracket ranges"
-resp=`$rgbin 0 99 "$totre" "$totdat" 2>&1`
+resp=`$rgbin 99 "$totre" "$totdat" 2>&1`
test "$resp" = "$expectedresp" && f_ok "$msg" || f_no "$msg" "$resp"
-resp=`$rgbin 1 99 "$totre" "$totdat" 2>&1`
+resp=`$rgbin -r 99 "$totre" "$totdat" 2>&1`
test "$resp" = "$expectedresp" && f_ok "$msg (raw)" || f_no "$msg (raw)" "$resp"
#-----------------------------------
i=0
@@ -314,34 +330,41 @@ while test $i -lt 99; do
i=`expr $i + 1`
done
msg="99 group patterns taken with character classes"
-resp=`$rgbin 0 99 "$totre" "$totdat" 2>&1`
+resp=`$rgbin 99 "$totre" "$totdat" 2>&1`
test "$resp" = "$expectedresp" && f_ok "$msg" || f_no "$msg" "$resp"
-resp=`$rgbin 1 99 "$totre" "$totdat" 2>&1`
+resp=`$rgbin -r 99 "$totre" "$totdat" 2>&1`
test "$resp" = "$expectedresp" && f_ok "$msg (raw)" || f_no "$msg (raw)" "$resp"
#-----------------------------------
msg="Binary data"
-resp=`$rgbin 0 0 "clavo" $'Pablito\01clavo un clavito' 2>&1`
+resp=`$rgbin 0 "clavo" $'Pablito\01clavo un clavito' 2>&1`
test -z "$resp" && f_ok "$msg" || f_no "$msg" "$resp"
-resp=`$rgbin 1 0 "clavo" $'Pablito\01clavo un clavito' 2>&1`
+resp=`$rgbin -r 0 "clavo" $'Pablito\01clavo un clavito' 2>&1`
test -z "$resp" && f_ok "$msg (raw)" || f_no "$msg (raw)" "$resp"
#-----------------------------------
msg="Binary RE and data"
-resp=`$rgbin 0 0 $'cl\xFFavo' $'Pablito\x01cl\xFFavo un clavito' 2>&1`
+resp=`$rgbin 0 $'cl\xFFavo' $'Pablito\x01cl\xFFavo un clavito' 2>&1`
test -z "$resp" && f_ok "$msg" || f_no "$msg" "$resp"
-resp=`$rgbin 1 0 $'cl\xFFavo' $'Pablito\x01cl\xFFavo un clavito' 2>&1`
+resp=`$rgbin -r 0 $'cl\xFFavo' $'Pablito\x01cl\xFFavo un clavito' 2>&1`
test -z "$resp" && f_ok "$msg (raw)" || f_no "$msg (raw)" "$resp"
#-----------------------------------
msg="One group pattern with case-insensitive matching"
-resp=`$rgbin 0 1 "(?i)(clavo)" "Pablito ClAvO un clavito" 2>&1`
+resp=`$rgbin 1 "(?i)(clavo)" "Pablito ClAvO un clavito" 2>&1`
test "$resp" = "ClAvO" && f_ok "$msg" || f_no "$msg" "$resp"
-resp=`$rgbin 1 1 "(?i)(clavo)" "Pablito ClAvO un clavito" 2>&1`
+resp=`$rgbin -r 1 "(?i)(clavo)" "Pablito ClAvO un clavito" 2>&1`
test "$resp" = "ClAvO" && f_ok "$msg (raw)" || f_no "$msg" "$resp (raw)"
#-----------------------------------
-resp=`$rgbin 1 1 $'([\x01\x5F\xFF]+)' $'ABC\x5F' 2>&1`
+resp=`$rgbin -r 1 $'([\x01\x5F\xFF]+)' $'ABC\x5F' 2>&1`
msg="Raw character class"
test "$resp" = $'\x5F' && f_ok "$msg" || f_no "$msg" "$resp"
#-----------------------------------
-resp=`$rgbin 0 1 '([[:alpha:]]+)' 'абвгд' 2>&1`
+resp=`$rgbin 1 '([[:alpha:]]+)' 'абвгд' 2>&1`
msg="Unicode character class"
test "$resp" = "абвгд" && f_ok "$msg" || f_no "$msg" "$resp"
#-----------------------------------
+resp=`$rgbin -A 0 'ABC' 'blablaABC' 2>&1`
+msg="Anchored search (failure)"
+test -z "$resp" && f_ok "$msg" || f_no "$msg" "$resp"
+resp=`$rgbin -A 1 '(ABC)' 'ABCblablaABC' 2>&1`
+msg="Anchored search (success)"
+test "$resp" = "ABC" && f_ok "$msg" || f_no "$msg" "$resp"
+#-----------------------------------