diff options
author | Ingo Schwarze <schwarze@cvs.openbsd.org> | 2011-07-24 13:59:16 +0000 |
---|---|---|
committer | Ingo Schwarze <schwarze@cvs.openbsd.org> | 2011-07-24 13:59:16 +0000 |
commit | 7b515bfb1eb01953979594346ed1757636d2ae5a (patch) | |
tree | fa6383cf9ac352a821231e273e6da682701aa1b2 /usr.bin | |
parent | c914600c0963c19dd4cd341f05c6a7d13cb05db9 (diff) |
Rewrite the main loop of the "sed s/..." command, shortening it by ten
lines and simplifying it by removing the switch statement implementing
/g, /1, and /2 separately and repetitively.
The idea to make the loop control variable slen, i.e. the length of the
string remaining to be processed, signed, and stay in the loop even when
slen == 0 (i.e. at the end of the string), lifted from FreeBSD by otto@.
On i386, process.o shrinks by 440 bytes, and the sed binary by 23 bytes.
This fixes multiple aspects of the replacement of multiple (/g) or
specific (e.g. /2) instances of zero-length matches, both with BREs and
EREs, both with and without a trailing newline character on the input.
Feedback and OK otto@.
Diffstat (limited to 'usr.bin')
-rw-r--r-- | usr.bin/sed/process.c | 92 |
1 files changed, 43 insertions, 49 deletions
diff --git a/usr.bin/sed/process.c b/usr.bin/sed/process.c index e1e63090027..11073dbec7c 100644 --- a/usr.bin/sed/process.c +++ b/usr.bin/sed/process.c @@ -1,4 +1,4 @@ -/* $OpenBSD: process.c,v 1.15 2009/10/27 23:59:43 deraadt Exp $ */ +/* $OpenBSD: process.c,v 1.16 2011/07/24 13:59:15 schwarze Exp $ */ /*- * Copyright (c) 1992 Diomidis Spinellis. @@ -312,7 +312,7 @@ substitute(struct s_command *cp) { SPACE tspace; regex_t *re; - size_t re_off, slen; + regoff_t slen; int n, lastempty; char *s; @@ -333,60 +333,54 @@ substitute(struct s_command *cp) n = cp->u.s->n; lastempty = 1; - 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); - } + do { + /* Copy the leading retained string. */ + if (n <= 1 && match[0].rm_so) + cspace(&SS, s, match[0].rm_so, APPEND); - /* 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; + /* 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. */ + regsub(&SS, s, cp->u.s->new); + if (n == 1) + n = -1; } else { - 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; + /* Want a later match: append original. */ + if (match[0].rm_eo) + cspace(&SS, s, match[0].rm_eo, APPEND); + n--; } - } 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); } - /* 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. */ + + /* Move past this match. */ 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 |