diff options
Diffstat (limited to 'usr.bin/sed/process.c')
-rw-r--r-- | usr.bin/sed/process.c | 92 |
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 |