summaryrefslogtreecommitdiff
path: root/usr.bin
diff options
context:
space:
mode:
authorIngo Schwarze <schwarze@cvs.openbsd.org>2011-07-26 08:47:08 +0000
committerIngo Schwarze <schwarze@cvs.openbsd.org>2011-07-26 08:47:08 +0000
commit238f0eccdd536ff7a9ce2364afec9f037c1dd7d2 (patch)
tree3700ba6d4aab393effcbfc705b32f467c66a1fc3 /usr.bin
parent4eb7bc1b08f121e2c4e620f90d4d73cb986174f8 (diff)
Backout previous, naddy@ found the following regression:
When the input does not end in a trailing newline character and there is an empty match at the end, the new code adds a spurious '\0' character. I have a fix, but otto@ prefers backout and full re-evaluation after release.
Diffstat (limited to 'usr.bin')
-rw-r--r--usr.bin/sed/process.c92
1 files changed, 49 insertions, 43 deletions
diff --git a/usr.bin/sed/process.c b/usr.bin/sed/process.c
index 11073dbec7c..148ccaf9493 100644
--- a/usr.bin/sed/process.c
+++ b/usr.bin/sed/process.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: process.c,v 1.16 2011/07/24 13:59:15 schwarze Exp $ */
+/* $OpenBSD: process.c,v 1.17 2011/07/26 08:47:07 schwarze Exp $ */
/*-
* Copyright (c) 1992 Diomidis Spinellis.
@@ -312,7 +312,7 @@ substitute(struct s_command *cp)
{
SPACE tspace;
regex_t *re;
- regoff_t slen;
+ size_t re_off, slen;
int n, lastempty;
char *s;
@@ -333,54 +333,60 @@ substitute(struct s_command *cp)
n = cp->u.s->n;
lastempty = 1;
- do {
- /* Copy the leading retained string. */
- if (n <= 1 && match[0].rm_so)
- cspace(&SS, s, match[0].rm_so, APPEND);
-
- /* Skip zero-length matches right after other matches. */
- if (lastempty || match[0].rm_so ||
- match[0].rm_so != match[0].rm_eo) {
- if (n <= 1) {
- /* Want this match: append replacement. */
+ switch (n) {
+ case 0: /* Global */
+ do {
+ if (lastempty || match[0].rm_so != match[0].rm_eo) {
+ /* Locate start of replaced string. */
+ re_off = match[0].rm_so;
+ /* Copy leading retained string. */
+ cspace(&SS, s, re_off, APPEND);
+ /* Add in regular expression. */
regsub(&SS, s, cp->u.s->new);
- if (n == 1)
- n = -1;
+ }
+
+ /* Move past this match. */
+ if (match[0].rm_so != match[0].rm_eo) {
+ s += match[0].rm_eo;
+ slen -= match[0].rm_eo;
+ lastempty = 0;
} else {
- /* Want a later match: append original. */
- if (match[0].rm_eo)
- cspace(&SS, s, match[0].rm_eo, APPEND);
- n--;
+ if (match[0].rm_so == 0)
+ cspace(&SS, s, match[0].rm_so + 1,
+ APPEND);
+ else
+ cspace(&SS, s + match[0].rm_so, 1,
+ APPEND);
+ s += match[0].rm_so + 1;
+ slen -= match[0].rm_so + 1;
+ lastempty = 1;
}
+ } while (slen > 0 && regexec_e(re, s, REG_NOTBOL, 0, slen));
+ /* Copy trailing retained string. */
+ if (slen > 0)
+ cspace(&SS, s, slen, APPEND);
+ break;
+ default: /* Nth occurrence */
+ while (--n) {
+ s += match[0].rm_eo;
+ slen -= match[0].rm_eo;
+ if (!regexec_e(re, s, REG_NOTBOL, 0, slen))
+ return (0);
}
-
- /* Move past this match. */
+ /* FALLTHROUGH */
+ case 1: /* 1st occurrence */
+ /* Locate start of replaced string. */
+ re_off = match[0].rm_so + (s - ps);
+ /* Copy leading retained string. */
+ cspace(&SS, ps, re_off, APPEND);
+ /* Add in regular expression. */
+ regsub(&SS, s, cp->u.s->new);
+ /* Copy trailing retained string. */
s += match[0].rm_eo;
slen -= match[0].rm_eo;
-
- /*
- * After a zero-length match, advance one byte,
- * and at the end of the line, terminate.
- */
- if (match[0].rm_so == match[0].rm_eo) {
- if (*s == '\n')
- slen = -1;
- else
- slen--;
- cspace(&SS, s++, 1, APPEND);
- lastempty = 1;
- } else
- lastempty = 0;
-
- } while (n >= 0 && slen >= 0 && regexec_e(re, s, REG_NOTBOL, 0, slen));
-
- /* Did not find the requested number of matches. */
- if (n > 1)
- return (0);
-
- /* Copy the trailing retained string. */
- if (slen > 0)
cspace(&SS, s, slen, APPEND);
+ break;
+ }
/*
* Swap the substitute space and the pattern space, and make sure