BSD 4_4_Lite1 release
[unix-history] / usr / src / usr.bin / sed / process.c
index cd302ac..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.9 (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>
@@ -41,7 +67,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 *));
 
@@ -52,19 +78,18 @@ 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()
 {
        struct s_command *cp;
        SPACE tspace;
        size_t len;
 void
 process()
 {
        struct s_command *cp;
        SPACE tspace;
        size_t len;
-       int r;
        char oldc, *p;
 
        for (linenum = 0; mf_fgets(&PS, REPLACE);) {
        char oldc, *p;
 
        for (linenum = 0; mf_fgets(&PS, REPLACE);) {
@@ -87,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':
@@ -104,10 +130,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 - ps) + 1;
                                        memmove(ps, p + 1, psl);
                                }
                                goto new;
                                        memmove(ps, p + 1, psl);
                                }
                                goto new;
@@ -115,13 +141,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);
@@ -131,42 +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();
-                               r = mf_fgets(&PS, REPLACE);
-#ifdef HISTORIC_PRACTICE
-                               if (!r)
+                               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 (!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':
@@ -176,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) {
@@ -196,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;
@@ -210,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 ':':
@@ -223,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 */
 }
@@ -232,8 +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, 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
 
 /*
@@ -288,8 +312,8 @@ substitute(cp)
 {
        SPACE tspace;
        regex_t *re;
 {
        SPACE tspace;
        regex_t *re;
-       size_t re_off;
-       int n;
+       size_t re_off, slen;
+       int lastempty, n;
        char *s;
 
        s = ps;
        char *s;
 
        s = ps;
@@ -301,30 +325,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);
 
                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 = 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(regexec_e(re, s, REG_NOTBOL, 0));
+       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), APPEND);
-               break;
+               if (slen > 0)
+                       cspace(&SS, s, slen, APPEND);
+               break;
        default:                                /* Nth occurrence */
                while (--n) {
                        s += match[0].rm_eo;
        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 */
@@ -337,7 +383,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;
        }
 
@@ -352,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);
@@ -381,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:
                        /*
@@ -394,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
@@ -438,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;
                        }
                }
@@ -450,21 +495,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);
@@ -534,23 +586,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;
+       /* 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';
 }