cleanups, add manual page
[unix-history] / usr / src / usr.bin / ex / ex_re.c
index c2b21d3..c12d077 100644 (file)
@@ -1,4 +1,13 @@
-/* Copyright (c) 1979 Regents of the University of California */
+/*
+ * Copyright (c) 1980 Regents of the University of California.
+ * All rights reserved.  The Berkeley software License Agreement
+ * specifies the terms and conditions for redistribution.
+ */
+
+#ifndef lint
+static char *sccsid = "@(#)ex_re.c     7.6 (Berkeley) %G%";
+#endif not lint
+
 #include "ex.h"
 #include "ex_re.h"
 
 #include "ex.h"
 #include "ex_re.h"
 
@@ -35,11 +44,11 @@ global(k)
        nonzero();
        if (skipend())
                error("Global needs re|Missing regular expression for global");
        nonzero();
        if (skipend())
                error("Global needs re|Missing regular expression for global");
-       c = getchar();
+       c = ex_getchar();
        ignore(compile(c, 1));
        savere(scanre);
        gp = globuf;
        ignore(compile(c, 1));
        savere(scanre);
        gp = globuf;
-       while ((c = getchar()) != '\n') {
+       while ((c = ex_getchar()) != '\n') {
                switch (c) {
 
                case EOF:
                switch (c) {
 
                case EOF:
@@ -47,7 +56,7 @@ global(k)
                        goto brkwh;
 
                case '\\':
                        goto brkwh;
 
                case '\\':
-                       c = getchar();
+                       c = ex_getchar();
                        switch (c) {
 
                        case '\\':
                        switch (c) {
 
                        case '\\':
@@ -69,7 +78,6 @@ global(k)
        }
 brkwh:
        ungetchar(c);
        }
 brkwh:
        ungetchar(c);
-out:
        newline();
        *gp++ = c;
        *gp++ = 0;
        newline();
        *gp++ = c;
        *gp++ = 0;
@@ -80,9 +88,31 @@ out:
                if (a1 >= addr1 && a1 <= addr2 && execute(0, a1) == k)
                        *a1 |= 01;
        }
                if (a1 >= addr1 && a1 <= addr2 && execute(0, a1) == k)
                        *a1 |= 01;
        }
-       /* should use gdelete from ed to avoid n**2 here on g/.../d */
+#ifdef notdef
+/*
+ * This code is commented out for now.  The problem is that we don't
+ * fix up the undo area the way we should.  Basically, I think what has
+ * to be done is to copy the undo area down (since we shrunk everything)
+ * and move the various pointers into it down too.  I will do this later
+ * when I have time. (Mark, 10-20-80)
+ */
+       /*
+        * Special case: g/.../d (avoid n^2 algorithm)
+        */
+       if (globuf[0]=='d' && globuf[1]=='\n' && globuf[2]=='\0') {
+               gdelete();
+               return;
+       }
+#endif
        if (inopen)
                inopen = -1;
        if (inopen)
                inopen = -1;
+       /*
+        * Now for each marked line, set dot there and do the commands.
+        * Note the n^2 behavior here for lots of lines matching.
+        * This is really needed: in some cases you could delete lines,
+        * causing a marked line to be moved before a1 and missed if
+        * we didn't restart at zero each time.
+        */
        for (a1 = one; a1 <= dol; a1++) {
                if (*a1 & 01) {
                        *a1 &= ~01;
        for (a1 = one; a1 <= dol; a1++) {
                if (*a1 & 01) {
                        *a1 &= ~01;
@@ -104,6 +134,37 @@ out:
        }
 }
 
        }
 }
 
+/*
+ * gdelete: delete inside a global command. Handles the
+ * special case g/r.e./d. All lines to be deleted have
+ * already been marked. Squeeze the remaining lines together.
+ * Note that other cases such as g/r.e./p, g/r.e./s/r.e.2/rhs/,
+ * and g/r.e./.,/r.e.2/d are not treated specially.  There is no
+ * good reason for this except the question: where to you draw the line?
+ */
+gdelete()
+{
+       register line *a1, *a2, *a3;
+
+       a3 = dol;
+       /* find first marked line. can skip all before it */
+       for (a1=zero; (*a1&01)==0; a1++)
+               if (a1>=a3)
+                       return;
+       /* copy down unmarked lines, compacting as we go. */
+       for (a2=a1+1; a2<=a3;) {
+               if (*a2&01) {
+                       a2++;           /* line is marked, skip it */
+                       dot = a1;       /* dot left after line deletion */
+               } else
+                       *a1++ = *a2++;  /* unmarked, copy it */
+       }
+       dol = a1-1;
+       if (dot>dol)
+               dot = dol;
+       change();
+}
+
 bool   cflag;
 int    scount, slines, stotal;
 
 bool   cflag;
 int    scount, slines, stotal;
 
@@ -112,7 +173,7 @@ substitute(c)
 {
        register line *addr;
        register int n;
 {
        register line *addr;
        register int n;
-       int gsubf;
+       int gsubf, hopcount;
 
        gsubf = compsub(c);
        if(FIXUNDO)
 
        gsubf = compsub(c);
        if(FIXUNDO)
@@ -120,21 +181,20 @@ substitute(c)
        stotal = 0;
        slines = 0;
        for (addr = addr1; addr <= addr2; addr++) {
        stotal = 0;
        slines = 0;
        for (addr = addr1; addr <= addr2; addr++) {
-               scount = 0;
+               scount = hopcount = 0;
                if (dosubcon(0, addr) == 0)
                        continue;
                if (gsubf) {
                if (dosubcon(0, addr) == 0)
                        continue;
                if (gsubf) {
-#ifdef notdef
                        /*
                        /*
-                        * should check but loc2 is already munged.
-                        * This needs a fancier check later.
+                        * The loop can happen from s/\</&/g
+                        * but we don't want to break other, reasonable cases.
                         */
                         */
-                       if (loc1 == loc2)
-                               error("substitution loop");
-#endif
-                       while (*loc2)
+                       while (*loc2) {
+                               if (++hopcount > sizeof linebuf)
+                                       error("substitution loop");
                                if (dosubcon(1, addr) == 0)
                                        break;
                                if (dosubcon(1, addr) == 0)
                                        break;
+                       }
                }
                if (scount) {
                        stotal += scount;
                }
                if (scount) {
                        stotal += scount;
@@ -163,7 +223,7 @@ compsub(ch)
 
        case 's':
                ignore(skipwh());
 
        case 's':
                ignore(skipwh());
-               seof = getchar();
+               seof = ex_getchar();
                if (endcmd(seof) || any(seof, "gcr")) {
                        ungetchar(seof);
                        goto redo;
                if (endcmd(seof) || any(seof, "gcr")) {
                        ungetchar(seof);
                        goto redo;
@@ -189,7 +249,7 @@ compsub(ch)
                break;
        }
        for (;;) {
                break;
        }
        for (;;) {
-               c = getchar();
+               c = ex_getchar();
                switch (c) {
 
                case 'g':
                switch (c) {
 
                case 'g':
@@ -222,18 +282,18 @@ comprhs(seof)
 {
        register char *rp, *orp;
        register int c;
 {
        register char *rp, *orp;
        register int c;
-       char orhsbuf[LBSIZE / 2];
+       char orhsbuf[RHSSIZE];
 
        rp = rhsbuf;
        CP(orhsbuf, rp);
        for (;;) {
 
        rp = rhsbuf;
        CP(orhsbuf, rp);
        for (;;) {
-               c = getchar();
+               c = ex_getchar();
                if (c == seof)
                        break;
                switch (c) {
 
                case '\\':
                if (c == seof)
                        break;
                switch (c) {
 
                case '\\':
-                       c = getchar();
+                       c = ex_getchar();
                        if (c == EOF) {
                                ungetchar(c);
                                break;
                        if (c == EOF) {
                                ungetchar(c);
                                break;
@@ -250,7 +310,7 @@ comprhs(seof)
 magic:
                        if (c == '~') {
                                for (orp = orhsbuf; *orp; *rp++ = *orp++)
 magic:
                        if (c == '~') {
                                for (orp = orhsbuf; *orp; *rp++ = *orp++)
-                                       if (rp >= &rhsbuf[LBSIZE / 2 + 1])
+                                       if (rp >= &rhsbuf[RHSSIZE - 1])
                                                goto toobig;
                                continue;
                        }
                                                goto toobig;
                                continue;
                        }
@@ -270,9 +330,11 @@ magic:
                                goto magic;
                        break;
                }
                                goto magic;
                        break;
                }
-               if (rp >= &rhsbuf[LBSIZE / 2 - 1])
+               if (rp >= &rhsbuf[RHSSIZE - 1]) {
 toobig:
 toobig:
+                       *rp = 0;
                        error("Replacement pattern too long@- limit 256 characters");
                        error("Replacement pattern too long@- limit 256 characters");
+               }
                *rp++ = c;
        }
 endrhs:
                *rp++ = c;
        }
 endrhs:
@@ -314,7 +376,7 @@ confirmed(a)
        pofix();
        pline(lineno(a));
        if (inopen)
        pofix();
        pline(lineno(a));
        if (inopen)
-               putchar('\n' | QUOTE);
+               ex_putchar('\n' | QUOTE);
        c = column(loc1 - 1);
        ugo(c - 1 + (inopen ? 1 : 0), ' ');
        ugo(column(loc2 - 1) - c, '^');
        c = column(loc1 - 1);
        ugo(c - 1 + (inopen ? 1 : 0), ' ');
        ugo(column(loc2 - 1) - c, '^');
@@ -324,7 +386,7 @@ again:
        if (c == '\r')
                c = '\n';
        if (inopen)
        if (c == '\r')
                c = '\n';
        if (inopen)
-               putchar(c), flush();
+               ex_putchar(c), flush();
        if (c != '\n' && c != EOF) {
                c = getkey();
                goto again;
        if (c != '\n' && c != EOF) {
                c = getkey();
                goto again;
@@ -349,7 +411,7 @@ ugo(cnt, with)
 
        if (cnt > 0)
                do
 
        if (cnt > 0)
                do
-                       putchar(with);
+                       ex_putchar(with);
                while (--cnt > 0);
 }
 
                while (--cnt > 0);
 }
 
@@ -368,6 +430,10 @@ dosub()
                *sp++ = *lp++;
        casecnt = 0;
        while (c = *rp++) {
                *sp++ = *lp++;
        casecnt = 0;
        while (c = *rp++) {
+               /* ^V <return> from vi to split lines */
+               if (c == '\r')
+                       c = '\n';
+
                if (c & QUOTE)
                        switch (c & TRIM) {
 
                if (c & QUOTE)
                        switch (c & TRIM) {
 
@@ -459,9 +525,9 @@ snote(total, lines)
 
        if (!notable(total))
                return;
 
        if (!notable(total))
                return;
-       printf(mesg("%d subs|%d substitutions"), total);
+       ex_printf(mesg("%d subs|%d substitutions"), total);
        if (lines != 1 && lines != total)
        if (lines != 1 && lines != total)
-               printf(" on %d lines", lines);
+               ex_printf(" on %d lines", lines);
        noonl();
        flush();
 }
        noonl();
        flush();
 }
@@ -479,7 +545,7 @@ compile(eof, oknl)
        if (isalpha(eof) || isdigit(eof))
                error("Regular expressions cannot be delimited by letters or digits");
        ep = expbuf;
        if (isalpha(eof) || isdigit(eof))
                error("Regular expressions cannot be delimited by letters or digits");
        ep = expbuf;
-       c = getchar();
+       c = ex_getchar();
        if (eof == '\\')
                switch (c) {
 
        if (eof == '\\')
                switch (c) {
 
@@ -512,7 +578,7 @@ error("No previous substitute re|No previous substitute regular expression");
        nbra = 0;
        circfl = 0;
        if (c == '^') {
        nbra = 0;
        circfl = 0;
        if (c == '^') {
-               c = getchar();
+               c = ex_getchar();
                circfl++;
        }
        ungetchar(c);
                circfl++;
        }
        ungetchar(c);
@@ -520,7 +586,7 @@ error("No previous substitute re|No previous substitute regular expression");
                if (ep >= &expbuf[ESIZE - 2])
 complex:
                        cerror("Re too complex|Regular expression too complicated");
                if (ep >= &expbuf[ESIZE - 2])
 complex:
                        cerror("Re too complex|Regular expression too complicated");
-               c = getchar();
+               c = ex_getchar();
                if (c == eof || c == EOF) {
                        if (bracketp != bracket)
 cerror("Unmatched \\(|More \\('s than \\)'s in regular expression");
                if (c == eof || c == EOF) {
                        if (bracketp != bracket)
 cerror("Unmatched \\(|More \\('s than \\)'s in regular expression");
@@ -538,7 +604,7 @@ cerror("Unmatched \\(|More \\('s than \\)'s in regular expression");
                switch (c) {
 
                case '\\':
                switch (c) {
 
                case '\\':
-                       c = getchar();
+                       c = ex_getchar();
                        switch (c) {
 
                        case '(':
                        switch (c) {
 
                        case '(':
@@ -603,23 +669,23 @@ cerror("Illegal *|Can't * a \\n in regular expression");
                                *ep++ = CCL;
                                *ep++ = 0;
                                cclcnt = 1;
                                *ep++ = CCL;
                                *ep++ = 0;
                                cclcnt = 1;
-                               c = getchar();
+                               c = ex_getchar();
                                if (c == '^') {
                                if (c == '^') {
-                                       c = getchar();
+                                       c = ex_getchar();
                                        ep[-2] = NCCL;
                                }
                                if (c == ']')
 cerror("Bad character class|Empty character class '[]' or '[^]' cannot match");
                                while (c != ']') {
                                        if (c == '\\' && any(peekchar(), "]-^\\"))
                                        ep[-2] = NCCL;
                                }
                                if (c == ']')
 cerror("Bad character class|Empty character class '[]' or '[^]' cannot match");
                                while (c != ']') {
                                        if (c == '\\' && any(peekchar(), "]-^\\"))
-                                               c = getchar() | QUOTE;
+                                               c = ex_getchar() | QUOTE;
                                        if (c == '\n' || c == EOF)
                                                cerror("Missing ]");
                                        *ep++ = c;
                                        cclcnt++;
                                        if (ep >= &expbuf[ESIZE])
                                                goto complex;
                                        if (c == '\n' || c == EOF)
                                                cerror("Missing ]");
                                        *ep++ = c;
                                        cclcnt++;
                                        if (ep >= &expbuf[ESIZE])
                                                goto complex;
-                                       c = getchar();
+                                       c = ex_getchar();
                                }
                                lastep[1] = cclcnt;
                                continue;
                                }
                                lastep[1] = cclcnt;
                                continue;
@@ -694,6 +760,7 @@ same(a, b)
 
 char   *locs;
 
 
 char   *locs;
 
+/* VARARGS1 */
 execute(gf, addr)
        line *addr;
 {
 execute(gf, addr)
        line *addr;
 {
@@ -747,8 +814,6 @@ advance(lp, ep)
        register char *lp, *ep;
 {
        register char *curlp;
        register char *lp, *ep;
 {
        register char *curlp;
-       char *sp, *sp1;
-       int c;
 
        for (;;) switch (*ep++) {
 
 
        for (;;) switch (*ep++) {
 
@@ -839,7 +904,7 @@ star:
                return (0);
 
        case CBRC:
                return (0);
 
        case CBRC:
-               if (lp == expbuf)
+               if (lp == linebuf)
                        continue;
                if ((isdigit(*lp) || uletter(*lp)) && !uletter(lp[-1]) && !isdigit(lp[-1]))
                        continue;
                        continue;
                if ((isdigit(*lp) || uletter(*lp)) && !uletter(lp[-1]) && !isdigit(lp[-1]))
                        continue;