From: Andrew Moore Date: Sun, 17 Apr 1994 09:41:54 +0000 (+0000) Subject: From NetBSD: X-Git-Tag: FreeBSD-release/1.1.5~898 X-Git-Url: https://git.subgeniuskitty.com/unix-history/.git/commitdiff_plain/a53c32b3bc584c03ef83ce54280b59c4fbde51be From NetBSD: upgrade sed(1) --- diff --git a/usr.bin/sed/Makefile b/usr.bin/sed/Makefile index 52f0fb5f3e..9a6871df40 100644 --- a/usr.bin/sed/Makefile +++ b/usr.bin/sed/Makefile @@ -1,7 +1,7 @@ -# @(#)Makefile 5.1 (Berkeley) 8/24/92 +# from: @(#)Makefile 8.1 (Berkeley) 6/6/93 PROG= sed -SRCS= compile.c main.c misc.c process.c -CFLAGS+=-I${.CURDIR} -DHISTORIC_PRACTICE +SRCS= compile.c main.c misc.c process.c +CFLAGS+=-I${.CURDIR} .include diff --git a/usr.bin/sed/POSIX b/usr.bin/sed/POSIX index 467b31db3e..fcd557f728 100644 --- a/usr.bin/sed/POSIX +++ b/usr.bin/sed/POSIX @@ -97,10 +97,7 @@ All uses of "POSIX" refer to section 4.55, Draft 12 of POSIX 1003.2. did not produce any output. POSIX does not specify this behavior. This implementation follows historic practice. -10. POSIX does not specify that the q command causes all lines that - have been appended to be output and that the pattern space is - printed before exiting. This implementation follows historic - practice. +10. Deleted. 11. Historical implementations do not output the change text of a c command in the case of an address range whose first line number @@ -175,11 +172,7 @@ All uses of "POSIX" refer to section 4.55, Draft 12 of POSIX 1003.2. string1 or string2 of the y command. This is not specified by POSIX. This implementation follows historic practice. -21. POSIX does not specify if the "Nth occurrence" of an RE in a - substitute command is an overlapping or a non-overlapping one, - i.e. what is the result of s/a*/A/2 on the pattern "aaaaa aaaaa". - Historical practice is to drop core or only do non-overlapping - RE's. This implementation only does non-overlapping RE's. +21. Deleted. 22. Historic implementations of sed ignore the RE delimiter characters within character classes. This is not specified in POSIX. This diff --git a/usr.bin/sed/compile.c b/usr.bin/sed/compile.c index ef0dbaf046..8d3fed30e9 100644 --- a/usr.bin/sed/compile.c +++ b/usr.bin/sed/compile.c @@ -1,7 +1,7 @@ /*- * Copyright (c) 1992 Diomidis Spinellis. - * Copyright (c) 1992 The Regents of the University of California. - * All rights reserved. + * Copyright (c) 1992, 1993 + * The Regents of the University of California. All rights reserved. * * This code is derived from software contributed to Berkeley by * Diomidis Spinellis of Imperial College, University of London. @@ -36,7 +36,8 @@ */ #ifndef lint -static char sccsid[] = "@(#)compile.c 5.6 (Berkeley) 11/2/92"; +/* from: static char sccsid[] = "@(#)compile.c 8.1 (Berkeley) 6/6/93"; */ +static char *rcsid = "$Id: compile.c,v 1.10 1994/02/03 23:44:46 cgd Exp $"; #endif /* not lint */ #include @@ -54,6 +55,15 @@ static char sccsid[] = "@(#)compile.c 5.6 (Berkeley) 11/2/92"; #include "defs.h" #include "extern.h" +#define LHSZ 128 +#define LHMASK (LHSZ - 1) +static struct labhash { + struct labhash *lh_next; + u_int lh_hash; + struct s_command *lh_cmd; + int lh_ref; +} *labels[LHSZ]; + static char *compile_addr __P((char *, struct s_addr *)); static char *compile_ccl __P((char **, char *)); static char *compile_delimited __P((char *, char *)); @@ -64,11 +74,12 @@ static char *compile_text __P((void)); static char *compile_tr __P((char *, char **)); static struct s_command **compile_stream __P((char *, struct s_command **, char *)); -static char *duptoeol __P((char *)); +static char *duptoeol __P((char *, char *)); +static void enterlabel __P((struct s_command *)); static struct s_command - *findlabel __P((struct s_command *, struct s_command *)); -static void fixuplabel __P((struct s_command *, struct s_command *, - struct s_command *)); + *findlabel __P((char *)); +static void fixuplabel __P((struct s_command *, struct s_command *)); +static void uselabel __P((void)); /* * Command specification. This is used to drive the command parser. @@ -121,7 +132,8 @@ void compile() { *compile_stream(NULL, &prog, NULL) = NULL; - fixuplabel(prog, prog, NULL); + fixuplabel(prog, NULL); + uselabel(); appends = xmalloc(sizeof(struct s_appends) * appendnum); match = xmalloc((maxnsub + 1) * sizeof(regmatch_t)); } @@ -208,8 +220,6 @@ nonsel: /* Now parse the command */ p = NULL; cmd2 = xmalloc(sizeof(struct s_command)); cmd2->code = '}'; - cmd2->a1 = cmd2->a2 = NULL; - cmd2->nonsel = 0; *compile_stream("}", &cmd->u.c, p) = cmd2; cmd->next = cmd2; link = &cmd2->next; @@ -246,7 +256,7 @@ nonsel: /* Now parse the command */ EATSPACE(); if (*p == '\0') err(COMPILE, "filename expected"); - cmd->t = duptoeol(p); + cmd->t = duptoeol(p, "w command"); if (aflag) cmd->u.fd = -1; else if ((cmd->u.fd = open(p, @@ -260,7 +270,7 @@ nonsel: /* Now parse the command */ if (*p == '\0') err(COMPILE, "filename expected"); else - cmd->t = duptoeol(p); + cmd->t = duptoeol(p, "read command"); break; case BRANCH: /* b t */ p++; @@ -268,14 +278,15 @@ nonsel: /* Now parse the command */ if (*p == '\0') cmd->t = NULL; else - cmd->t = duptoeol(p); + cmd->t = duptoeol(p, "branch"); break; case LABEL: /* : */ p++; EATSPACE(); - cmd->t = duptoeol(p); + cmd->t = duptoeol(p, "label"); if (strlen(p) == 0) err(COMPILE, "empty label"); + enterlabel(cmd); break; case SUBST: /* s */ p++; @@ -666,77 +677,129 @@ compile_addr(p, a) } /* - * Return a copy of all the characters up to \n or \0 + * duptoeol -- + * Return a copy of all the characters up to \n or \0. */ static char * -duptoeol(s) +duptoeol(s, ctype) register char *s; + char *ctype; { size_t len; + int ws; char *start; - for (start = s; *s != '\0' && *s != '\n'; ++s); + ws = 0; + for (start = s; *s != '\0' && *s != '\n'; ++s) + ws = isspace(*s); *s = '\0'; + if (ws) + err(WARNING, "whitespace after %s", ctype); len = s - start + 1; return (memmove(xmalloc(len), start, len)); } /* - * Find the label contained in the command l in the command linked list cp. - * L is excluded from the search. Return NULL if not found. - */ -static struct s_command * -findlabel(l, cp) - struct s_command *l, *cp; -{ - struct s_command *r; - - for (; cp; cp = cp->next) - if (cp->code == ':' && cp != l && strcmp(l->t, cp->t) == 0) - return (cp); - else if (cp->code == '{' && (r = findlabel(l, cp->u.c))) - return (r); - return (NULL); -} - -/* - * Convert goto label names to addresses. - * Detect duplicate labels. - * Set appendnum to the number of a and r commands in the script. - * Free the memory used by labels in b and t commands (but not by :) - * Root is a pointer to the script linked list; cp points to the - * search start. + * Convert goto label names to addresses, and count a and r commands, in + * the given subset of the script. Free the memory used by labels in b + * and t commands (but not by :). + * * TODO: Remove } nodes */ static void -fixuplabel(root, cp, end) - struct s_command *root, *cp, *end; +fixuplabel(cp, end) + struct s_command *cp, *end; { - struct s_command *cp2; for (; cp != end; cp = cp->next) switch (cp->code) { - case ':': - if (findlabel(cp, root)) - err(COMPILE2, "duplicate label %s", cp->t); - break; case 'a': case 'r': appendnum++; break; case 'b': case 't': + /* Resolve branch target. */ if (cp->t == NULL) { cp->u.c = NULL; break; } - if ((cp2 = findlabel(cp, root)) == NULL) + if ((cp->u.c = findlabel(cp->t)) == NULL) err(COMPILE2, "undefined label '%s'", cp->t); free(cp->t); - cp->u.c = cp2; break; case '{': - fixuplabel(root, cp->u.c, cp->next); + /* Do interior commands. */ + fixuplabel(cp->u.c, cp->next); break; } } + +/* + * Associate the given command label for later lookup. + */ +static void +enterlabel(cp) + struct s_command *cp; +{ + register struct labhash **lhp, *lh; + register u_char *p; + register u_int h, c; + + for (h = 0, p = (u_char *)cp->t; (c = *p) != 0; p++) + h = (h << 5) + h + c; + lhp = &labels[h & LHMASK]; + for (lh = *lhp; lh != NULL; lh = lh->lh_next) + if (lh->lh_hash == h && strcmp(cp->t, lh->lh_cmd->t) == 0) + err(COMPILE2, "duplicate label '%s'", cp->t); + lh = xmalloc(sizeof *lh); + lh->lh_next = *lhp; + lh->lh_hash = h; + lh->lh_cmd = cp; + lh->lh_ref = 0; + *lhp = lh; +} + +/* + * Find the label contained in the command l in the command linked + * list cp. L is excluded from the search. Return NULL if not found. + */ +static struct s_command * +findlabel(name) + char *name; +{ + register struct labhash *lh; + register u_char *p; + register u_int h, c; + + for (h = 0, p = (u_char *)name; (c = *p) != 0; p++) + h = (h << 5) + h + c; + for (lh = labels[h & LHMASK]; lh != NULL; lh = lh->lh_next) { + if (lh->lh_hash == h && strcmp(name, lh->lh_cmd->t) == 0) { + lh->lh_ref = 1; + return (lh->lh_cmd); + } + } + return (NULL); +} + +/* + * Warn about any unused labels. As a side effect, release the label hash + * table space. + */ +static void +uselabel() +{ + register struct labhash *lh, *next; + register int i; + + for (i = 0; i < LHSZ; i++) { + for (lh = labels[i]; lh != NULL; lh = next) { + next = lh->lh_next; + if (!lh->lh_ref) + err(WARNING, "unused label '%s'", + lh->lh_cmd->t); + free(lh); + } + } +} diff --git a/usr.bin/sed/defs.h b/usr.bin/sed/defs.h index 948ba44548..2528a7cc5d 100644 --- a/usr.bin/sed/defs.h +++ b/usr.bin/sed/defs.h @@ -1,7 +1,7 @@ /*- * Copyright (c) 1992 Diomidis Spinellis. - * Copyright (c) 1992 The Regents of the University of California. - * All rights reserved. + * Copyright (c) 1992, 1993 + * The Regents of the University of California. All rights reserved. * * This code is derived from software contributed to Berkeley by * Diomidis Spinellis of Imperial College, University of London. @@ -34,7 +34,8 @@ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * - * @(#)defs.h 5.3 (Berkeley) 8/28/92 + * from: @(#)defs.h 8.1 (Berkeley) 6/6/93 + * $Id: defs.h,v 1.5 1994/02/03 23:44:51 cgd Exp $ */ /* @@ -74,7 +75,7 @@ struct s_subst { /* * An internally compiled command. - * Initialy, label references are stored in u.t, on a second pass they + * Initialy, label references are stored in t, on a second pass they * are updated to pointers. */ struct s_command { @@ -115,11 +116,11 @@ enum e_args { struct s_appends { enum {AP_STRING, AP_FILE} type; char *s; + size_t len; }; enum e_spflag { APPEND, /* Append to the contents. */ - APPENDNL, /* Append, with newline. */ REPLACE, /* Replace the contents. */ }; diff --git a/usr.bin/sed/extern.h b/usr.bin/sed/extern.h index 32b68a1ee9..af03531644 100644 --- a/usr.bin/sed/extern.h +++ b/usr.bin/sed/extern.h @@ -1,7 +1,7 @@ /*- * Copyright (c) 1992 Diomidis Spinellis. - * Copyright (c) 1992 The Regents of the University of California. - * All rights reserved. + * Copyright (c) 1992, 1993 + * The Regents of the University of California. All rights reserved. * * This code is derived from software contributed to Berkeley by * Diomidis Spinellis of Imperial College, University of London. @@ -34,7 +34,8 @@ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * - * @(#)extern.h 5.5 (Berkeley) 8/30/92 + * from: @(#)extern.h 8.1 (Berkeley) 6/6/93 + * $Id: extern.h,v 1.4 1994/02/03 23:44:52 cgd Exp $ */ extern struct s_command *prog; @@ -47,7 +48,9 @@ extern int lastline; extern int aflag, eflag, nflag; extern char *fname; +void cfclose __P((struct s_command *, struct s_command *)); void compile __P((void)); +void cspace __P((SPACE *, char *, size_t, enum e_spflag)); char *cu_fgets __P((char *, int)); void err __P((int, const char *, ...)); int mf_fgets __P((SPACE *, enum e_spflag)); @@ -55,5 +58,3 @@ void process __P((void)); char *strregerror __P((int, regex_t *)); void *xmalloc __P((u_int)); void *xrealloc __P((void *, u_int)); -void cfclose __P((struct s_command *, struct s_command *)); -void cspace __P((SPACE *, char *, size_t, enum e_spflag)); diff --git a/usr.bin/sed/main.c b/usr.bin/sed/main.c index f4fc96f702..3070b30c6b 100644 --- a/usr.bin/sed/main.c +++ b/usr.bin/sed/main.c @@ -1,7 +1,7 @@ /*- * Copyright (c) 1992 Diomidis Spinellis. - * Copyright (c) 1992 The Regents of the University of California. - * All rights reserved. + * Copyright (c) 1992, 1993 + * The Regents of the University of California. All rights reserved. * * This code is derived from software contributed to Berkeley by * Diomidis Spinellis of Imperial College, University of London. @@ -36,13 +36,14 @@ */ #ifndef lint -char copyright[] = -"@(#) Copyright (c) 1992 The Regents of the University of California.\n\ - All rights reserved.\n"; +static char copyright[] = +"@(#) Copyright (c) 1992, 1993\n\ + The Regents of the University of California. All rights reserved.\n"; #endif /* not lint */ #ifndef lint -static char sccsid[] = "@(#)main.c 5.6 (Berkeley) 8/30/92"; +/* from: static char sccsid[] = "@(#)main.c 8.2 (Berkeley) 1/3/94"; */ +static char *rcsid = "$Id: main.c,v 1.6 1994/02/03 23:44:53 cgd Exp $"; #endif /* not lint */ #include @@ -286,11 +287,11 @@ mf_fgets(sp, spflag) } /* - * Use fgetline so that we can handle essentially infinite input - * data. Can't use the pointer into the stdio buffer as the process - * space because the ungetc() can cause it to move. + * Use fgetln so that we can handle essentially infinite input data. + * Can't use the pointer into the stdio buffer as the process space + * because the ungetc() can cause it to move. */ - p = fgetline(f, &len); + p = fgetln(f, &len); if (ferror(f)) err(FATAL, "%s: %s", fname, strerror(errno ? errno : EIO)); cspace(sp, p, len, spflag); diff --git a/usr.bin/sed/misc.c b/usr.bin/sed/misc.c index 807821334c..44e2a56f9e 100644 --- a/usr.bin/sed/misc.c +++ b/usr.bin/sed/misc.c @@ -1,7 +1,7 @@ /*- * Copyright (c) 1992 Diomidis Spinellis. - * Copyright (c) 1992 The Regents of the University of California. - * All rights reserved. + * Copyright (c) 1992, 1993 + * The Regents of the University of California. All rights reserved. * * This code is derived from software contributed to Berkeley by * Diomidis Spinellis of Imperial College, University of London. @@ -36,7 +36,8 @@ */ #ifndef lint -static char sccsid[] = "@(#)misc.c 5.3 (Berkeley) 8/26/92"; +/* from: static char sccsid[] = "@(#)misc.c 8.1 (Berkeley) 6/6/93"; */ +static char *rcsid = "$Id: misc.c,v 1.4 1994/02/03 23:44:54 cgd Exp $"; #endif /* not lint */ #include diff --git a/usr.bin/sed/process.c b/usr.bin/sed/process.c index f1a4e9e9f2..d21aebac90 100644 --- a/usr.bin/sed/process.c +++ b/usr.bin/sed/process.c @@ -1,7 +1,7 @@ /*- * Copyright (c) 1992 Diomidis Spinellis. - * Copyright (c) 1992 The Regents of the University of California. - * All rights reserved. + * Copyright (c) 1992, 1993 + * The Regents of the University of California. All rights reserved. * * This code is derived from software contributed to Berkeley by * Diomidis Spinellis of Imperial College, University of London. @@ -36,7 +36,8 @@ */ #ifndef lint -static char sccsid[] = "@(#)process.c 5.10 (Berkeley) 12/2/92"; +/* from: static char sccsid[] = "@(#)process.c 8.1 (Berkeley) 6/6/93"; */ +static char *rcsid = "$Id: process.c,v 1.13 1994/03/24 15:55:01 mycroft Exp $"; #endif /* not lint */ #include @@ -57,7 +58,7 @@ static char sccsid[] = "@(#)process.c 5.10 (Berkeley) 12/2/92"; #include "defs.h" #include "extern.h" -static SPACE HS = {""}, PS, SS; +static SPACE HS, PS, SS; #define pd PS.deleted #define ps PS.space #define psl PS.len @@ -67,7 +68,7 @@ static SPACE HS = {""}, PS, SS; static inline int applies __P((struct s_command *)); static void flush_appends __P((void)); static void lputs __P((char *)); -static inline int regexec_e __P((regex_t *, const char *, int, int)); +static inline int regexec_e __P((regex_t *, const char *, int, int, size_t)); static void regsub __P((SPACE *, char *, char *)); static int substitute __P((struct s_command *)); @@ -78,12 +79,12 @@ int appendnum; /* Size of appends array. */ static int lastaddr; /* Set by applies if last address of a range. */ static int sdone; /* If any substitutes since last line input. */ /* Iov structure for 'w' commands. */ -static struct iovec iov[2] = { NULL, 0, "\n", 1 }; - static regex_t *defpreg; size_t maxnsub; regmatch_t *match; +#define OUT(s) { fwrite(s, sizeof(u_char), psl, stdout); } + void process() { @@ -113,6 +114,7 @@ redirect: (appendnum *= 2)); appends[appendx].type = AP_STRING; appends[appendx].s = cp->t; + appends[appendx].len = strlen(cp->t); appendx++; break; case 'b': @@ -130,10 +132,10 @@ redirect: case 'D': if (pd) goto new; - if ((p = strchr(ps, '\n')) == NULL) + if ((p = memchr(ps, '\n', psl)) == NULL) pd = 1; else { - psl -= (p - ps) - 1; + psl -= (p + 1) - ps; memmove(ps, p + 1, psl); } goto new; @@ -141,13 +143,13 @@ redirect: cspace(&PS, hs, hsl, REPLACE); break; case 'G': - cspace(&PS, hs, hsl, APPENDNL); + cspace(&PS, hs, hsl, 0); break; case 'h': cspace(&HS, ps, psl, REPLACE); break; case 'H': - cspace(&HS, ps, psl, APPENDNL); + cspace(&HS, ps, psl, 0); break; case 'i': (void)printf("%s", cp->t); @@ -157,10 +159,10 @@ redirect: break; case 'n': if (!nflag && !pd) - (void)printf("%s\n", ps); + OUT(ps) flush_appends(); r = mf_fgets(&PS, REPLACE); -#ifdef HISTORIC_PRACTICE +#ifndef NONHISTORIC_PRACTICE if (!r) exit(0); #endif @@ -168,31 +170,31 @@ redirect: break; case 'N': flush_appends(); - if (!mf_fgets(&PS, APPENDNL)) { + if (!mf_fgets(&PS, 0)) { if (!nflag && !pd) - (void)printf("%s\n", ps); + OUT(ps) exit(0); } break; case 'p': if (pd) break; - (void)printf("%s\n", ps); + OUT(ps) break; case 'P': if (pd) break; - if ((p = strchr(ps, '\n')) != NULL) { + if ((p = memchr(ps, '\n', psl)) != NULL) { oldc = *p; *p = '\0'; } - (void)printf("%s\n", ps); + OUT(ps) if (p != NULL) *p = oldc; break; case 'q': if (!nflag && !pd) - (void)printf("%s\n", ps); + OUT(ps) flush_appends(); exit(0); case 'r': @@ -202,6 +204,7 @@ redirect: (appendnum *= 2)); appends[appendx].type = AP_FILE; appends[appendx].s = cp->t; + appends[appendx].len = strlen(cp->t); appendx++; break; case 's': @@ -222,13 +225,13 @@ redirect: DEFFILEMODE)) == -1) err(FATAL, "%s: %s\n", cp->t, strerror(errno)); - iov[0].iov_base = ps; - iov[0].iov_len = psl; - if (writev(cp->u.fd, iov, 2) != psl + 1) + if (write(cp->u.fd, ps, psl) != psl) err(FATAL, "%s: %s\n", cp->t, strerror(errno)); break; case 'x': + if (hs == NULL) + cspace(&HS, "", 0, REPLACE); tspace = PS; PS = HS; HS = tspace; @@ -236,7 +239,7 @@ redirect: case 'y': if (pd) break; - for (p = ps, len = psl; len--; ++p) + for (p = ps, len = psl; --len; ++p) *p = cp->u.y[*p]; break; case ':': @@ -249,7 +252,7 @@ redirect: } /* for all cp */ new: if (!nflag && !pd) - (void)printf("%s\n", ps); + OUT(ps) flush_appends(); } /* for all lines */ } @@ -258,8 +261,8 @@ new: if (!nflag && !pd) * TRUE if the address passed matches the current program state * (lastline, linenumber, ps). */ -#define MATCH(a) \ - (a)->type == AT_RE ? regexec_e((a)->u.r, ps, 0, 1) : \ +#define MATCH(a) \ + (a)->type == AT_RE ? regexec_e((a)->u.r, ps, 0, 1, psl) : \ (a)->type == AT_LINE ? linenum == (a)->u.l : lastline /* @@ -314,14 +317,11 @@ substitute(cp) { SPACE tspace; regex_t *re; - size_t re_off; - size_t re_eoff; - int n; + size_t re_off, slen; + int n, lastempty; char *s; - char *eos; s = ps; - eos = s + strlen(s); re = cp->u.s->re; if (re == NULL) { if (defpreg != NULL && cp->u.s->maxbref > defpreg->re_nsub) { @@ -330,33 +330,52 @@ substitute(cp) cp->u.s->maxbref); } } - if (!regexec_e(re, s, 0, 0)) + if (!regexec_e(re, s, 0, 0, psl)) return (0); SS.len = 0; /* Clean substitute space. */ + slen = psl; n = cp->u.s->n; + lastempty = 1; + switch (n) { case 0: /* Global */ do { - /* Locate start of replaced string. */ - re_off = match[0].rm_so; - re_eoff = match[0].rm_eo; - /* Copy leading retained string. */ - cspace(&SS, s, re_off, APPEND); - /* Add in regular expression. */ - regsub(&SS, s, cp->u.s->new); + 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); + } + /* Move past this match. */ - s += match[0].rm_eo; - } while(*s && re_eoff && regexec_e(re, s, REG_NOTBOL, 0)); - if (eos - s > 0 && !re_eoff) - err(FATAL, "infinite substitution loop"); + if (match[0].rm_so != match[0].rm_eo) { + s += match[0].rm_eo; + slen -= match[0].rm_eo; + lastempty = 0; + } 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; + } + } while (slen > 0 && regexec_e(re, s, REG_NOTBOL, 0, slen)); /* Copy trailing retained string. */ - cspace(&SS, s, strlen(s), APPEND); + if (slen > 0) + cspace(&SS, s, slen, APPEND); break; default: /* Nth occurrence */ while (--n) { s += match[0].rm_eo; - if (!regexec_e(re, s, REG_NOTBOL, 0)) + slen -= match[0].rm_eo; + if (!regexec_e(re, s, REG_NOTBOL, 0, slen)) return (0); } /* FALLTHROUGH */ @@ -369,7 +388,8 @@ substitute(cp) regsub(&SS, s, cp->u.s->new); /* Copy trailing retained string. */ s += match[0].rm_eo; - cspace(&SS, s, strlen(s), APPEND); + slen -= match[0].rm_eo; + cspace(&SS, s, slen, APPEND); break; } @@ -384,16 +404,14 @@ substitute(cp) /* Handle the 'p' flag. */ if (cp->u.s->p) - (void)printf("%s\n", ps); + OUT(ps) /* Handle the 'w' flag. */ if (cp->u.s->wfile && !pd) { if (cp->u.s->wfd == -1 && (cp->u.s->wfd = open(cp->u.s->wfile, O_WRONLY|O_APPEND|O_CREAT|O_TRUNC, DEFFILEMODE)) == -1) err(FATAL, "%s: %s\n", cp->u.s->wfile, strerror(errno)); - iov[0].iov_base = ps; - iov[0].iov_len = psl; - if (writev(cp->u.s->wfd, iov, 2) != psl + 1) + if (write(cp->u.s->wfd, ps, psl) != psl) err(FATAL, "%s: %s\n", cp->u.s->wfile, strerror(errno)); } return (1); @@ -413,7 +431,8 @@ flush_appends() for (i = 0; i < appendx; i++) switch (appends[i].type) { case AP_STRING: - (void)printf("%s", appends[i].s); + fwrite(appends[i].s, sizeof(char), appends[i].len, + stdout); break; case AP_FILE: /* @@ -426,8 +445,8 @@ flush_appends() */ if ((f = fopen(appends[i].s, "r")) == NULL) break; - while (count = fread(buf, 1, sizeof(buf), f)) - (void)fwrite(buf, 1, count, stdout); + while (count = fread(buf, sizeof(char), sizeof(buf), f)) + (void)fwrite(buf, sizeof(char), count, stdout); (void)fclose(f); break; } @@ -469,7 +488,7 @@ lputs(s) (void)putchar("\\abfnrtv"[p - escapes]); count += 2; } else { - (void)printf("%03o", (u_char)*s); + (void)printf("%03o", *(u_char *)s); count += 4; } } @@ -481,21 +500,28 @@ lputs(s) } static inline int -regexec_e(preg, string, eflags, nomatch) +regexec_e(preg, string, eflags, nomatch, slen) regex_t *preg; const char *string; int eflags, nomatch; + size_t slen; { int eval; - + if (preg == NULL) { if (defpreg == NULL) err(FATAL, "first RE may not be empty"); } else defpreg = preg; + /* Set anchors, discounting trailing newline (if any). */ + if (slen > 0 && string[slen - 1] == '\n') + slen--; + match[0].rm_so = 0; + match[0].rm_eo = slen; + eval = regexec(defpreg, string, - nomatch ? 0 : maxnsub + 1, match, eflags); + nomatch ? 0 : maxnsub + 1, match, eflags | REG_STARTEND); switch(eval) { case 0: return (1); @@ -565,24 +591,18 @@ cspace(sp, p, len, spflag) { size_t tlen; - /* - * Make sure SPACE has enough memory and ramp up quickly. Appends - * need two extra bytes, one for the newline, one for a terminating - * NULL. - */ -/* tlen = sp->len + len + spflag == APPENDNL ? 2 : 1; */ - tlen = sp->len + len + (spflag == APPENDNL ? 2 : 1); /* XXX */ + /* Make sure SPACE has enough memory and ramp up quickly. */ + tlen = sp->len + len + 1; if (tlen > sp->blen) { sp->blen = tlen + 1024; sp->space = sp->back = xrealloc(sp->back, sp->blen); } - if (spflag == APPENDNL) - sp->space[sp->len++] = '\n'; - else if (spflag == REPLACE) + if (spflag == REPLACE) sp->len = 0; memmove(sp->space + sp->len, p, len); + sp->space[sp->len += len] = '\0'; } diff --git a/usr.bin/sed/sed.1 b/usr.bin/sed/sed.1 index 8fb1d52844..63bcd329c4 100644 --- a/usr.bin/sed/sed.1 +++ b/usr.bin/sed/sed.1 @@ -1,5 +1,5 @@ -.\" Copyright (c) 1992 The Regents of the University of California. -.\" All rights reserved. +.\" Copyright (c) 1992, 1993 +.\" The Regents of the University of California. All rights reserved. .\" .\" This code is derived from software contributed to Berkeley by .\" the Institute of Electrical and Electronics Engineers, Inc. @@ -32,9 +32,9 @@ .\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF .\" SUCH DAMAGE. .\" -.\" @(#)sed.1 5.2 (Berkeley) 8/24/92 +.\" @(#)sed.1 8.2 (Berkeley) 12/30/93 .\" -.Dd "August 24, 1992" +.Dd "December 30, 1993" .Dt SED 1 .Os .Sh NAME @@ -257,7 +257,7 @@ can be preceded by white space and can be followed by white space. The function can be preceded by white space. The terminating .Dq } -must be preceded by a newline an optional white space. +must be preceded by a newline or optional white space. .sp .Bl -tag -width "XXXXXX" -compact .It [2addr] function-list @@ -394,7 +394,7 @@ An ampersand appearing in the replacement is replaced by the string matching the RE. The special meaning of .Dq & -in this context can be suppressed by preceding it by backslash. +in this context can be suppressed by preceding it by a backslash. The string .Dq \e# , where @@ -456,8 +456,9 @@ Within .Em string1 and .Em string2 , -the delimiter itself can be used as a literal character if it is preceded -by a backslash. +a backslash followed by any character other than a newline is that literal +character, and a backslash followed by an ``n'' is replaced by a newline +character. .sp .It [2addr]!function .It [2addr]!function-list