Fix somewhat broken beginning and end of line handling using REG_NOEOL
flag of regexec().
Also force progress with zero-width matches by re-running regexec at
next position if a zero-width match is found at the current position.
---
ed.c | 49 +++++++++++++++++++++++++++++++++++-------------
tests/0047-ed.sh | 24 ++++++++++++++++++++++++
2 files changed, 60 insertions(+), 13 deletions(-)
create mode 100755 tests/0047-ed.sh
diff --git a/ed.c b/ed.c
index 59101d3..081acaf 100644
--- a/ed.c
+++ b/ed.c
@@ -69,7 +69,6 @@ static char *rhs;
static char *lastmatch;
static struct undo udata;
static int newcmd;
-static int eol, bol;
static sig_atomic_t intr, hup;
@@ -403,15 +402,11 @@ compile(int delim)
if (!isgraph(delim))
error("invalid pattern delimiter");
- eol = bol = bracket = lastre.siz = 0;
+ bracket = lastre.siz = 0;
for (n = 0;; ++n) {
c = input();
if (c == delim && !bracket || c == '\0') {
break;
- } else if (c == '^') {
- bol = 1;
- } else if (c == '$') {
- eol = 1;
} else if (c == '\\') {
addchar(c, &lastre);
c = input();
@@ -433,7 +428,7 @@ compile(int delim)
regfree(pattern);
if (!pattern && (!(pattern = malloc(sizeof(*pattern)))))
error("out of memory");
- if ((ret = regcomp(pattern, lastre.str, REG_NEWLINE))) {
+ if ((ret = regcomp(pattern, lastre.str, 0))) {
regerror(ret, pattern, buf, sizeof(buf));
error(buf);
}
@@ -446,7 +441,7 @@ match(int num)
lastmatch = gettxt(num);
text.str[text.siz - 2] = '\0';
- r =!regexec(pattern, lastmatch, 10, matchs, 0);
+ r = !regexec(pattern, lastmatch, 10, matchs, 0);
text.str[text.siz - 2] = '\n';
return r;
@@ -456,13 +451,43 @@ static int
rematch(int num)
{
regoff_t off = matchs[0].rm_eo;
+ regmatch_t *m;
+ int r;
+
+ text.str[text.siz - 2] = '\0';
+ r = !regexec(pattern, lastmatch + off, 10, matchs, REG_NOTBOL);
+ text.str[text.siz - 2] = '\n';
+
+ if (!r)
+ return 0;
- if (!regexec(pattern, lastmatch + off, 10, matchs, 0)) {
+ if (matchs[0].rm_eo > 0) {
lastmatch += off;
return 1;
}
- return 0;
+ /* Zero width match was found at the end of the input, done */
+ if (lastmatch[off] == '\n') {
+ lastmatch += off;
+ return 0;
+ }
+
+ /* Zero width match at the current posiion, find the next one */
+ text.str[text.siz - 2] = '\0';
+ r = !regexec(pattern, lastmatch + off + 1, 10, matchs, REG_NOTBOL);
+ text.str[text.siz - 2] = '\n';
+
+ if (!r)
+ return 0;
+
+ /* Re-adjust matches to account for +1 in regexec */
+ for (m = matchs; m < &matchs[10]; m++) {
+ m->rm_so += 1;
+ m->rm_eo += 1;
+ }
+ lastmatch += off;
+
+ return 1;
}
static int
@@ -1238,12 +1263,10 @@ subline(int num, int nth)
string(&s);
i = changed = 0;
- for (m = match(num); m; m = rematch(num)) {
+ for (m = match(num); m; m = (nth < 0 || i < nth) && rematch(num)) {
chksignals();
addpre(&s);
changed |= addsub(&s, nth, ++i);
- if (eol || bol)
- break;
}
if (!changed)
return;
diff --git a/tests/0047-ed.sh b/tests/0047-ed.sh
new file mode 100755
index 0000000..47f77ff
--- /dev/null
+++ b/tests/0047-ed.sh
@@ -0,0 +1,24 @@
+#!/bin/sh
+
+tmp=tmp.$$
+
+trap 'rm -f $tmp' EXIT
+trap 'exit $?' HUP INT TERM
+
+cat <<EOF > $tmp
+LLLx
+yLyLyLyxy
+zzzzxy
+EOF
+
+$EXEC ../ed -s /dev/null <<EOF | diff -u $tmp -
+i
+LLL
+.
+s! *!x!4
+p
+s# *#y#g
+p
+s/\(^\|L\)y/z/g
+p
+EOF
--
2.42.0