From NetBSD:
authorAndrew Moore <alm@FreeBSD.org>
Sun, 17 Apr 1994 09:41:54 +0000 (09:41 +0000)
committerAndrew Moore <alm@FreeBSD.org>
Sun, 17 Apr 1994 09:41:54 +0000 (09:41 +0000)
upgrade sed(1)

usr.bin/sed/Makefile
usr.bin/sed/POSIX
usr.bin/sed/compile.c
usr.bin/sed/defs.h
usr.bin/sed/extern.h
usr.bin/sed/main.c
usr.bin/sed/misc.c
usr.bin/sed/process.c
usr.bin/sed/sed.1

index 52f0fb5..9a6871d 100644 (file)
@@ -1,7 +1,7 @@
-#      @(#)Makefile    5.1 (Berkeley) 8/24/92
+#      from: @(#)Makefile      8.1 (Berkeley) 6/6/93
 
 PROG=  sed
 
 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 <bsd.prog.mk>
 
 .include <bsd.prog.mk>
index 467b31d..fcd557f 100644 (file)
@@ -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.
 
        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
 
 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.
 
        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
 
 22.    Historic implementations of sed ignore the RE delimiter characters
        within character classes.  This is not specified in POSIX.  This
index ef0dbaf..8d3fed3 100644 (file)
@@ -1,7 +1,7 @@
 /*-
  * Copyright (c) 1992 Diomidis Spinellis.
 /*-
  * 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.
  *
  * This code is derived from software contributed to Berkeley by
  * Diomidis Spinellis of Imperial College, University of London.
@@ -36,7 +36,8 @@
  */
 
 #ifndef lint
  */
 
 #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 <sys/types.h>
 #endif /* not lint */
 
 #include <sys/types.h>
@@ -54,6 +55,15 @@ static char sccsid[] = "@(#)compile.c        5.6 (Berkeley) 11/2/92";
 #include "defs.h"
 #include "extern.h"
 
 #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 *));
 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     *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
 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.
 
 /*
  * Command specification.  This is used to drive the command parser.
@@ -121,7 +132,8 @@ void
 compile()
 {
        *compile_stream(NULL, &prog, NULL) = NULL;
 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));
 }
        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 = '}';
                                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;
                        *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");
                        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, 
                        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
                        if (*p == '\0')
                                err(COMPILE, "filename expected");
                        else
-                               cmd->t = duptoeol(p);
+                               cmd->t = duptoeol(p, "read command");
                        break;
                case BRANCH:                    /* b t */
                        p++;
                        break;
                case BRANCH:                    /* b t */
                        p++;
@@ -268,14 +278,15 @@ nonsel:           /* Now parse the command */
                        if (*p == '\0')
                                cmd->t = NULL;
                        else
                        if (*p == '\0')
                                cmd->t = NULL;
                        else
-                               cmd->t = duptoeol(p);
+                               cmd->t = duptoeol(p, "branch");
                        break;
                case LABEL:                     /* : */
                        p++;
                        EATSPACE();
                        break;
                case LABEL:                     /* : */
                        p++;
                        EATSPACE();
-                       cmd->t = duptoeol(p);
+                       cmd->t = duptoeol(p, "label");
                        if (strlen(p) == 0)
                                err(COMPILE, "empty label");
                        if (strlen(p) == 0)
                                err(COMPILE, "empty label");
+                       enterlabel(cmd);
                        break;
                case SUBST:                     /* s */
                        p++;
                        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 *
  */
 static char *
-duptoeol(s)
+duptoeol(s, ctype)
        register char *s;
        register char *s;
+       char *ctype;
 {
        size_t len;
 {
        size_t len;
+       int ws;
        char *start;
 
        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';
        *s = '\0';
+       if (ws)
+               err(WARNING, "whitespace after %s", ctype);
        len = s - start + 1;
        return (memmove(xmalloc(len), start, len));
 }
 
 /*
        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
  * 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) {
 
        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':
                case 'a':
                case 'r':
                        appendnum++;
                        break;
                case 'b':
                case 't':
+                       /* Resolve branch target. */
                        if (cp->t == NULL) {
                                cp->u.c = NULL;
                                break;
                        }
                        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);
                                err(COMPILE2, "undefined label '%s'", cp->t);
                        free(cp->t);
-                       cp->u.c = cp2;
                        break;
                case '{':
                        break;
                case '{':
-                       fixuplabel(root, cp->u.c, cp->next);
+                       /* Do interior commands. */
+                       fixuplabel(cp->u.c, cp->next);
                        break;
                }
 }
                        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);
+               }
+       }
+}
index 948ba44..2528a7c 100644 (file)
@@ -1,7 +1,7 @@
 /*-
  * Copyright (c) 1992 Diomidis Spinellis.
 /*-
  * 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.
  *
  * 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.
  *
  * 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.
 
 /*
  * 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 {
  * 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;
 struct s_appends {
        enum {AP_STRING, AP_FILE} type;
        char *s;
+       size_t len;
 };
 
 enum e_spflag {
        APPEND,                                 /* Append to the contents. */
 };
 
 enum e_spflag {
        APPEND,                                 /* Append to the contents. */
-       APPENDNL,                               /* Append, with newline. */
        REPLACE,                                /* Replace the contents. */
 };
 
        REPLACE,                                /* Replace the contents. */
 };
 
index 32b68a1..af03531 100644 (file)
@@ -1,7 +1,7 @@
 /*-
  * Copyright (c) 1992 Diomidis Spinellis.
 /*-
  * 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.
  *
  * 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.
  *
  * 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;
  */
 
 extern struct s_command *prog;
@@ -47,7 +48,9 @@ extern int lastline;
 extern int aflag, eflag, nflag;
 extern char *fname;
 
 extern int aflag, eflag, nflag;
 extern char *fname;
 
+void    cfclose __P((struct s_command *, struct s_command *));
 void    compile __P((void));
 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));
 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));
 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));
index f4fc96f..3070b30 100644 (file)
@@ -1,7 +1,7 @@
 /*-
  * Copyright (c) 1992 Diomidis Spinellis.
 /*-
  * 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.
  *
  * This code is derived from software contributed to Berkeley by
  * Diomidis Spinellis of Imperial College, University of London.
  */
 
 #ifndef lint
  */
 
 #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
 #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 <sys/types.h>
 #endif /* not lint */
 
 #include <sys/types.h>
@@ -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);
        if (ferror(f))
                err(FATAL, "%s: %s", fname, strerror(errno ? errno : EIO));
        cspace(sp, p, len, spflag);
index 8078213..44e2a56 100644 (file)
@@ -1,7 +1,7 @@
 /*-
  * Copyright (c) 1992 Diomidis Spinellis.
 /*-
  * 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.
  *
  * This code is derived from software contributed to Berkeley by
  * Diomidis Spinellis of Imperial College, University of London.
@@ -36,7 +36,8 @@
  */
 
 #ifndef lint
  */
 
 #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 <sys/types.h>
 #endif /* not lint */
 
 #include <sys/types.h>
index f1a4e9e..d21aeba 100644 (file)
@@ -1,7 +1,7 @@
 /*-
  * Copyright (c) 1992 Diomidis Spinellis.
 /*-
  * 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.
  *
  * This code is derived from software contributed to Berkeley by
  * Diomidis Spinellis of Imperial College, University of London.
@@ -36,7 +36,8 @@
  */
 
 #ifndef lint
  */
 
 #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 <sys/types.h>
 #endif /* not lint */
 
 #include <sys/types.h>
@@ -57,7 +58,7 @@ static char sccsid[] = "@(#)process.c 5.10 (Berkeley) 12/2/92";
 #include "defs.h"
 #include "extern.h"
 
 #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
 #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       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 *));
 
 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 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;
 
 static regex_t *defpreg;
 size_t maxnsub;
 regmatch_t *match;
 
+#define OUT(s) { fwrite(s, sizeof(u_char), psl, stdout); }
+
 void
 process()
 {
 void
 process()
 {
@@ -113,6 +114,7 @@ redirect:
                                            (appendnum *= 2));
                                appends[appendx].type = AP_STRING;
                                appends[appendx].s = cp->t;
                                            (appendnum *= 2));
                                appends[appendx].type = AP_STRING;
                                appends[appendx].s = cp->t;
+                               appends[appendx].len = strlen(cp->t);
                                appendx++;
                                break;
                        case 'b':
                                appendx++;
                                break;
                        case 'b':
@@ -130,10 +132,10 @@ redirect:
                        case 'D':
                                if (pd)
                                        goto new;
                        case 'D':
                                if (pd)
                                        goto new;
-                               if ((p = strchr(ps, '\n')) == NULL)
+                               if ((p = memchr(ps, '\n', psl)) == NULL)
                                        pd = 1;
                                else {
                                        pd = 1;
                                else {
-                                       psl -= (p - ps) - 1;
+                                       psl -= (p + 1) - ps;
                                        memmove(ps, p + 1, psl);
                                }
                                goto new;
                                        memmove(ps, p + 1, psl);
                                }
                                goto new;
@@ -141,13 +143,13 @@ redirect:
                                cspace(&PS, hs, hsl, REPLACE);
                                break;
                        case 'G':
                                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':
                                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);
                                break;
                        case 'i':
                                (void)printf("%s", cp->t);
@@ -157,10 +159,10 @@ redirect:
                                break;
                        case 'n':
                                if (!nflag && !pd)
                                break;
                        case 'n':
                                if (!nflag && !pd)
-                                       (void)printf("%s\n", ps);
+                                       OUT(ps)
                                flush_appends();
                                r = mf_fgets(&PS, REPLACE);
                                flush_appends();
                                r = mf_fgets(&PS, REPLACE);
-#ifdef HISTORIC_PRACTICE
+#ifndef NONHISTORIC_PRACTICE
                                if (!r)
                                        exit(0);
 #endif
                                if (!r)
                                        exit(0);
 #endif
@@ -168,31 +170,31 @@ redirect:
                                break;
                        case 'N':
                                flush_appends();
                                break;
                        case 'N':
                                flush_appends();
-                               if (!mf_fgets(&PS, APPENDNL)) {
+                               if (!mf_fgets(&PS, 0)) {
                                        if (!nflag && !pd)
                                        if (!nflag && !pd)
-                                               (void)printf("%s\n", ps);
+                                               OUT(ps)
                                        exit(0);
                                }
                                break;
                        case 'p':
                                if (pd)
                                        break;
                                        exit(0);
                                }
                                break;
                        case 'p':
                                if (pd)
                                        break;
-                               (void)printf("%s\n", ps);
+                               OUT(ps)
                                break;
                        case 'P':
                                if (pd)
                                        break;
                                break;
                        case 'P':
                                if (pd)
                                        break;
-                               if ((p = strchr(ps, '\n')) != NULL) {
+                               if ((p = memchr(ps, '\n', psl)) != NULL) {
                                        oldc = *p;
                                        *p = '\0';
                                }
                                        oldc = *p;
                                        *p = '\0';
                                }
-                               (void)printf("%s\n", ps);
+                               OUT(ps)
                                if (p != NULL)
                                        *p = oldc;
                                break;
                        case 'q':
                                if (!nflag && !pd)
                                if (p != NULL)
                                        *p = oldc;
                                break;
                        case 'q':
                                if (!nflag && !pd)
-                                       (void)printf("%s\n", ps);
+                                       OUT(ps)
                                flush_appends();
                                exit(0);
                        case 'r':
                                flush_appends();
                                exit(0);
                        case 'r':
@@ -202,6 +204,7 @@ redirect:
                                            (appendnum *= 2));
                                appends[appendx].type = AP_FILE;
                                appends[appendx].s = cp->t;
                                            (appendnum *= 2));
                                appends[appendx].type = AP_FILE;
                                appends[appendx].s = cp->t;
+                               appends[appendx].len = strlen(cp->t);
                                appendx++;
                                break;
                        case 's':
                                appendx++;
                                break;
                        case 's':
@@ -222,13 +225,13 @@ redirect:
                                    DEFFILEMODE)) == -1)
                                        err(FATAL, "%s: %s\n",
                                            cp->t, strerror(errno));
                                    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':
                                        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;
                                tspace = PS;
                                PS = HS;
                                HS = tspace;
@@ -236,7 +239,7 @@ redirect:
                        case 'y':
                                if (pd)
                                        break;
                        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 ':':
                                        *p = cp->u.y[*p];
                                break;
                        case ':':
@@ -249,7 +252,7 @@ redirect:
                } /* for all cp */
 
 new:           if (!nflag && !pd)
                } /* for all cp */
 
 new:           if (!nflag && !pd)
-                       (void)printf("%s\n", ps);
+                       OUT(ps)
                flush_appends();
        } /* for all lines */
 }
                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).
  */
  * 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
 
 /*
            (a)->type == AT_LINE ? linenum == (a)->u.l : lastline
 
 /*
@@ -314,14 +317,11 @@ substitute(cp)
 {
        SPACE tspace;
        regex_t *re;
 {
        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 *s;
-       char *eos;
 
        s = ps;
 
        s = ps;
-       eos = s + strlen(s);
        re = cp->u.s->re;
        if (re == NULL) {
                if (defpreg != NULL && cp->u.s->maxbref > defpreg->re_nsub) {
        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);
                }
        }
                            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. */
                return (0);
 
        SS.len = 0;                             /* Clean substitute space. */
+       slen = psl;
        n = cp->u.s->n;
        n = cp->u.s->n;
+       lastempty = 1;
+
        switch (n) {
        case 0:                                 /* Global */
                do {
        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. */
                        /* 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. */
                /* 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;
                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 */
                                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;
                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;
        }
 
                break;
        }
 
@@ -384,16 +404,14 @@ substitute(cp)
 
        /* Handle the 'p' flag. */
        if (cp->u.s->p)
 
        /* 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));
 
        /* 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);
                        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:
        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:
                        /*
                        break;
                case AP_FILE:
                        /*
@@ -426,8 +445,8 @@ flush_appends()
                         */
                        if ((f = fopen(appends[i].s, "r")) == NULL)
                                break;
                         */
                        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;
                }
                        (void)fclose(f);
                        break;
                }
@@ -469,7 +488,7 @@ lputs(s)
                                (void)putchar("\\abfnrtv"[p - escapes]);
                                count += 2;
                        } else {
                                (void)putchar("\\abfnrtv"[p - escapes]);
                                count += 2;
                        } else {
-                               (void)printf("%03o", (u_char)*s);
+                               (void)printf("%03o", *(u_char *)s);
                                count += 4;
                        }
                }
                                count += 4;
                        }
                }
@@ -481,21 +500,28 @@ lputs(s)
 }
 
 static inline int
 }
 
 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;
        regex_t *preg;
        const char *string;
        int eflags, nomatch;
+       size_t slen;
 {
        int eval;
 {
        int eval;
-
+       
        if (preg == NULL) {
                if (defpreg == NULL)
                        err(FATAL, "first RE may not be empty");
        } else
                defpreg = preg;
 
        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,
        eval = regexec(defpreg, string,
-           nomatch ? 0 : maxnsub + 1, match, eflags);
+           nomatch ? 0 : maxnsub + 1, match, eflags | REG_STARTEND);
        switch(eval) {
        case 0:
                return (1);
        switch(eval) {
        case 0:
                return (1);
@@ -565,24 +591,18 @@ cspace(sp, p, len, spflag)
 {
        size_t tlen;
 
 {
        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 (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->len = 0;
 
        memmove(sp->space + sp->len, p, len);
+
        sp->space[sp->len += len] = '\0';
 }
 
        sp->space[sp->len += len] = '\0';
 }
 
index 8fb1d52..63bcd32 100644 (file)
@@ -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.
 .\"
 .\" 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.
 .\"
 .\" 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
 .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 }
 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
 .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 &
 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 backslash.
 The string
 .Dq \e# ,
 where
 The string
 .Dq \e# ,
 where
@@ -456,8 +456,9 @@ Within
 .Em string1
 and
 .Em string2 ,
 .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
 .sp
 .It [2addr]!function
 .It [2addr]!function-list