summaryrefslogtreecommitdiff
path: root/usr.bin
diff options
context:
space:
mode:
authorIngo Schwarze <schwarze@cvs.openbsd.org>2011-07-24 13:59:16 +0000
committerIngo Schwarze <schwarze@cvs.openbsd.org>2011-07-24 13:59:16 +0000
commit7b515bfb1eb01953979594346ed1757636d2ae5a (patch)
treefa6383cf9ac352a821231e273e6da682701aa1b2 /usr.bin
parentc914600c0963c19dd4cd341f05c6a7d13cb05db9 (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.c92
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