BSD 4_4_Lite1 release
[unix-history] / usr / src / usr.bin / sed / process.c
index 9892d18..2ec8aac 100644 (file)
@@ -1,16 +1,42 @@
 /*-
  * 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, 1994
+ *     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.
  *
- * %sccs.include.redist.c%
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ *    must display the following acknowledgement:
+ *     This product includes software developed by the University of
+ *     California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
  */
 
 #ifndef lint
  */
 
 #ifndef lint
-static char sccsid[] = "@(#)process.c  5.5 (Berkeley) %G%";
+static char sccsid[] = "@(#)process.c  8.6 (Berkeley) 4/20/94";
 #endif /* not lint */
 
 #include <sys/types.h>
 #endif /* not lint */
 
 #include <sys/types.h>
@@ -31,13 +57,6 @@ static char sccsid[] = "@(#)process.c        5.5 (Berkeley) %G%";
 #include "defs.h"
 #include "extern.h"
 
 #include "defs.h"
 #include "extern.h"
 
-typedef struct {
-       char *space;            /* Current space pointer. */
-       size_t len;             /* Current length. */
-       int deleted;            /* If deleted. */
-       char *back;             /* Backing memory. */
-       size_t blen;            /* Backing memory length. */
-} SPACE;
 static SPACE HS, PS, SS;
 #define        pd              PS.deleted
 #define        ps              PS.space
 static SPACE HS, PS, SS;
 #define        pd              PS.deleted
 #define        ps              PS.space
@@ -46,12 +65,10 @@ static SPACE HS, PS, SS;
 #define        hsl             HS.len
 
 static inline int       applies __P((struct s_command *));
 #define        hsl             HS.len
 
 static inline int       applies __P((struct s_command *));
-static void             cspace __P((SPACE *, char *, size_t, int));
 static void             flush_appends __P((void));
 static void             lputs __P((char *));
 static void             flush_appends __P((void));
 static void             lputs __P((char *));
-static inline int       regexec_e __P((regex_t *, const char *,
-                           size_t, regmatch_t [], int));
-static void             regsub __P((regmatch_t *, char *, char *, SPACE *));
+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 *));
 
 struct s_appends *appends;     /* Array of pointers to strings to append. */
 static int              substitute __P((struct s_command *));
 
 struct s_appends *appends;     /* Array of pointers to strings to append. */
@@ -61,10 +78,11 @@ 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;
 static regex_t *defpreg;
-static size_t defnmatch;
+size_t maxnsub;
+regmatch_t *match;
+
+#define OUT(s) { fwrite(s, sizeof(u_char), psl, stdout); }
 
 void
 process()
 
 void
 process()
@@ -74,7 +92,7 @@ process()
        size_t len;
        char oldc, *p;
 
        size_t len;
        char oldc, *p;
 
-       for (linenum = 0; ps = mf_fgets(&psl);) {
+       for (linenum = 0; mf_fgets(&PS, REPLACE);) {
                pd = 0;
                cp = prog;
 redirect:
                pd = 0;
                cp = prog;
 redirect:
@@ -94,6 +112,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':
@@ -106,32 +125,29 @@ redirect:
                                        (void)printf("%s", cp->t);
                                break;
                        case 'd':
                                        (void)printf("%s", cp->t);
                                break;
                        case 'd':
-                               if (pd)
-                                       goto new;
                                pd = 1;
                                goto new;
                        case 'D':
                                if (pd)
                                        goto new;
                                pd = 1;
                                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 - ps) + 1;
                                        memmove(ps, p + 1, psl);
                                }
                                goto new;
                        case 'g':
                                        memmove(ps, p + 1, psl);
                                }
                                goto new;
                        case 'g':
-                               ps = hs;
-                               psl = hsl;
+                               cspace(&PS, hs, hsl, REPLACE);
                                break;
                        case 'G':
                                break;
                        case 'G':
-                               cspace(&PS, hs, hsl, 1);
+                               cspace(&PS, hs, hsl, 0);
                                break;
                        case 'h':
                                break;
                        case 'h':
-                               cspace(&HS, ps, psl, 0);
+                               cspace(&HS, ps, psl, REPLACE);
                                break;
                        case 'H':
                                break;
                        case 'H':
-                               cspace(&HS, ps, psl, 1);
+                               cspace(&HS, ps, psl, 0);
                                break;
                        case 'i':
                                (void)printf("%s", cp->t);
                                break;
                        case 'i':
                                (void)printf("%s", cp->t);
@@ -141,45 +157,39 @@ redirect:
                                break;
                        case 'n':
                                if (!nflag && !pd)
                                break;
                        case 'n':
                                if (!nflag && !pd)
-                                       (void)printf("%s\n", ps);
+                                       OUT(ps)
                                flush_appends();
                                flush_appends();
-                               ps = mf_fgets(&psl);
-#ifdef HISTORIC_PRACTICE
-                               if (ps == NULL)
+                               if (!mf_fgets(&PS, REPLACE))
                                        exit(0);
                                        exit(0);
-#endif
                                pd = 0;
                                break;
                        case 'N':
                                flush_appends();
                                pd = 0;
                                break;
                        case 'N':
                                flush_appends();
-                               if (ps != PS.back)
-                                       cspace(&PS, NULL, 0, 0);
-                               if ((p = mf_fgets(&len)) == NULL) {
+                               if (!mf_fgets(&PS, 0)) {
                                        if (!nflag && !pd)
                                        if (!nflag && !pd)
-                                               (void)printf("%s\n", ps);
+                                               OUT(ps)
                                        exit(0);
                                }
                                        exit(0);
                                }
-                               cspace(&PS, p, len, 1);
                                break;
                        case 'p':
                                if (pd)
                                        break;
                                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':
@@ -189,10 +199,11 @@ 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':
-                               sdone = substitute(cp);
+                               sdone |= substitute(cp);
                                break;
                        case 't':
                                if (sdone) {
                                break;
                        case 't':
                                if (sdone) {
@@ -209,13 +220,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;
@@ -223,7 +234,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 ':':
@@ -236,7 +247,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 */
 }
@@ -245,9 +256,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, NULL, 0) :                       \
+#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
 
 /*
@@ -302,61 +312,79 @@ substitute(cp)
 {
        SPACE tspace;
        regex_t *re;
 {
        SPACE tspace;
        regex_t *re;
-       size_t nsub;
-       int n, re_off;
-       char *endp, *s;
+       size_t re_off, slen;
+       int lastempty, n;
+       char *s;
 
        s = ps;
        re = cp->u.s->re;
        if (re == NULL) {
 
        s = ps;
        re = cp->u.s->re;
        if (re == NULL) {
-               nsub = 1;
-               if (defpreg != NULL && cp->u.s->maxbref > defnmatch) {
+               if (defpreg != NULL && cp->u.s->maxbref > defpreg->re_nsub) {
                        linenum = cp->u.s->linenum;
                        err(COMPILE, "\\%d not defined in the RE",
                            cp->u.s->maxbref);
                }
                        linenum = cp->u.s->linenum;
                        err(COMPILE, "\\%d not defined in the RE",
                            cp->u.s->maxbref);
                }
-       } else
-               nsub = re->re_nsub + 1;
-       if (!regexec_e(re, s, nsub, cp->u.s->pmatch, 0))
+       }
+       if (!regexec_e(re, s, 0, 0, psl))
                return (0);
 
                return (0);
 
-       SS.len = 0;                             /* Clean substitute space. */
-       n = cp->u.s->n;
-       switch (n) {
-       case 0:                                 /* Global */
-               do {
-                       /* Locate start of replaced string. */
-                       re_off = cp->u.s->pmatch[0].rm_so;
-                       /* Locate end of replaced string + 1. */
-                       endp = s + cp->u.s->pmatch[0].rm_eo;
-                       /* Copy leading retained string. */
-                       cspace(&SS, s, re_off, 0);
-                       /* Add in regular expression. */
-                       regsub(cp->u.s->pmatch, s, cp->u.s->new, &SS);
-                       /* Move past this match. */
-                       s += cp->u.s->pmatch[0].rm_eo;
-               } while(regexec_e(re, s, nsub, cp->u.s->pmatch, REG_NOTBOL));
+       SS.len = 0;                             /* Clean substitute space. */
+       slen = psl;
+       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);
+                       }
+
+                       /* 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 {
+                               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), 0);
-               break;
+               if (slen > 0)
+                       cspace(&SS, s, slen, APPEND);
+               break;
        default:                                /* Nth occurrence */
                while (--n) {
        default:                                /* Nth occurrence */
                while (--n) {
-                       s += cp->u.s->pmatch[0].rm_eo;
-                       if (!regexec_e(re,
-                           s, nsub, cp->u.s->pmatch, REG_NOTBOL))
+                       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. */
                                return (0);
                }
                /* FALLTHROUGH */
        case 1:                                 /* 1st occurrence */
                /* Locate start of replaced string. */
-               re_off = cp->u.s->pmatch[0].rm_so + s - ps;
+               re_off = match[0].rm_so + (s - ps);
                /* Copy leading retained string. */
                /* Copy leading retained string. */
-               cspace(&SS, ps, re_off, 0);
+               cspace(&SS, ps, re_off, APPEND);
                /* Add in regular expression. */
                /* Add in regular expression. */
-               regsub(cp->u.s->pmatch, s, cp->u.s->new, &SS);
+               regsub(&SS, s, cp->u.s->new);
                /* Copy trailing retained string. */
                /* Copy trailing retained string. */
-               s += cp->u.s->pmatch[0].rm_eo;
-               cspace(&SS, s, strlen(s), 0);
+               s += match[0].rm_eo;
+               slen -= match[0].rm_eo;
+               cspace(&SS, s, slen, APPEND);
                break;
        }
 
                break;
        }
 
@@ -371,16 +399,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);
@@ -400,7 +426,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:
                        /*
@@ -413,15 +440,14 @@ 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;
                }
        if (ferror(stdout))
                err(FATAL, "stdout: %s", strerror(errno ? errno : EIO));
                        (void)fclose(f);
                        break;
                }
        if (ferror(stdout))
                err(FATAL, "stdout: %s", strerror(errno ? errno : EIO));
-       appendx = 0;
-       sdone = 0;
+       appendx = sdone = 0;
 }
 
 static void
 }
 
 static void
@@ -457,7 +483,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;
                        }
                }
@@ -469,25 +495,28 @@ lputs(s)
 }
 
 static inline int
 }
 
 static inline int
-regexec_e(preg, string, nmatch, pmatch, eflags)
+regexec_e(preg, string, eflags, nomatch, slen)
        regex_t *preg;
        const char *string;
        regex_t *preg;
        const char *string;
-       size_t nmatch;
-       regmatch_t pmatch[];
-       int eflags;
+       int eflags, nomatch;
+       size_t slen;
 {
        int eval;
 {
        int eval;
-
+       
        if (preg == NULL) {
                if (defpreg == NULL)
                        err(FATAL, "first RE may not be empty");
        if (preg == NULL) {
                if (defpreg == NULL)
                        err(FATAL, "first RE may not be empty");
-       } else {
+       } else
                defpreg = preg;
                defpreg = preg;
-               defnmatch = nmatch;
-       }
 
 
-       eval = regexec(defpreg,
-           string, pmatch == NULL ? 0 : defnmatch, pmatch, eflags);
+       /* 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 | REG_STARTEND);
        switch(eval) {
        case 0:
                return (1);
        switch(eval) {
        case 0:
                return (1);
@@ -503,10 +532,9 @@ regexec_e(preg, string, nmatch, pmatch, eflags)
  * Based on a routine by Henry Spencer
  */
 static void
  * Based on a routine by Henry Spencer
  */
 static void
-regsub(pmatch, string, src, sp)
-       regmatch_t *pmatch;
-       char *string, *src;
+regsub(sp, string, src)
        SPACE *sp;
        SPACE *sp;
+       char *string, *src;
 {
        register int len, no;
        register char c, *dst;
 {
        register int len, no;
        register char c, *dst;
@@ -532,10 +560,10 @@ regsub(pmatch, string, src, sp)
                        NEEDSP(1);
                        *dst++ = c;
                        ++sp->len;
                        NEEDSP(1);
                        *dst++ = c;
                        ++sp->len;
-               } else if (pmatch[no].rm_so != -1 && pmatch[no].rm_eo != -1) {
-                       len = pmatch[no].rm_eo - pmatch[no].rm_so;
+               } else if (match[no].rm_so != -1 && match[no].rm_eo != -1) {
+                       len = match[no].rm_eo - match[no].rm_so;
                        NEEDSP(len);
                        NEEDSP(len);
-                       memmove(dst, string + pmatch[no].rm_so, len);
+                       memmove(dst, string + match[no].rm_so, len);
                        dst += len;
                        sp->len += len;
                }
                        dst += len;
                        sp->len += len;
                }
@@ -549,56 +577,39 @@ regsub(pmatch, string, src, sp)
  *     Append the source space to the destination space, allocating new
  *     space as necessary.
  */
  *     Append the source space to the destination space, allocating new
  *     space as necessary.
  */
-static void
-cspace(sp, p, len, append)
+void
+cspace(sp, p, len, spflag)
        SPACE *sp;
        char *p;
        size_t len;
        SPACE *sp;
        char *p;
        size_t len;
-       int append;
+       enum e_spflag spflag;
 {
        size_t tlen;
 {
        size_t tlen;
-       int needcopy;
-
-       /* Current pointer may point to something else at the moment. */
-       needcopy = sp->space != sp->back;
 
 
-       /*
-        * Make sure SPACE has enough memory and ramp up quickly.
-        * Add in two extra bytes, one for the newline, one for a
-        * terminating NULL.
-        */
-       tlen = sp->len + len + 2;
+       /* Make sure SPACE has enough memory and ramp up quickly. */
+       tlen = sp->len + len + 1;
        if (tlen > sp->blen) {
                sp->blen = tlen + 1024;
        if (tlen > sp->blen) {
                sp->blen = tlen + 1024;
-               sp->back = xrealloc(sp->back, sp->blen);
+               sp->space = sp->back = xrealloc(sp->back, sp->blen);
        }
 
        }
 
-       if (needcopy)
-               memmove(sp->back, sp->space, sp->len + 1);
-       sp->space = sp->back;
-
-       /* May just be copying out of a stdio buffer. */
-       if (len == NULL)
-               return;
+       if (spflag == REPLACE)
+               sp->len = 0;
 
 
-       /* Append a separating newline. */
-       if (append)
-               sp->space[sp->len++] = '\n';
+       memmove(sp->space + sp->len, p, len);
 
 
-       /* Append the new stuff, plus its terminating NULL. */
-       memmove(sp->space + sp->len, p, len + 1);
-       sp->len += len;
+       sp->space[sp->len += len] = '\0';
 }
 
 /*
  * Close all cached opened files and report any errors
  */
 void
 }
 
 /*
  * Close all cached opened files and report any errors
  */
 void
-cfclose(cp)
-       register struct s_command *cp;
+cfclose(cp, end)
+       register struct s_command *cp, *end;
 {
 
 {
 
-       for (; cp != NULL; cp = cp->next)
+       for (; cp != end; cp = cp->next)
                switch(cp->code) {
                case 's':
                        if (cp->u.s->wfd != -1 && close(cp->u.s->wfd))
                switch(cp->code) {
                case 's':
                        if (cp->u.s->wfd != -1 && close(cp->u.s->wfd))
@@ -612,7 +623,7 @@ cfclose(cp)
                        cp->u.fd = -1;
                        break;
                case '{':
                        cp->u.fd = -1;
                        break;
                case '{':
-                       cfclose(cp->u.c);
+                       cfclose(cp->u.c, cp->next);
                        break;
                }
 }
                        break;
                }
 }