BSD 4 release
[unix-history] / usr / src / cmd / ex / ex_re.c
index 93abfaa..5f0665b 100644 (file)
@@ -1,4 +1,5 @@
-/* Copyright (c) 1979 Regents of the University of California */
+/* Copyright (c) 1980 Regents of the University of California */
+static char *sccsid = "@(#)ex_re.c     6.2 10/23/80";
 #include "ex.h"
 #include "ex_re.h"
 
 #include "ex.h"
 #include "ex_re.h"
 
@@ -73,16 +74,38 @@ out:
        newline();
        *gp++ = c;
        *gp++ = 0;
        newline();
        *gp++ = c;
        *gp++ = 0;
+       saveall();
        inglobal = 2;
        for (a1 = one; a1 <= dol; a1++) {
                *a1 &= ~01;
                if (a1 >= addr1 && a1 <= addr2 && execute(0, a1) == k)
                        *a1 |= 01;
        }
        inglobal = 2;
        for (a1 = one; a1 <= dol; a1++) {
                *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 */
-       saveall();
+#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,7 +127,38 @@ out:
        }
 }
 
        }
 }
 
-bool   xflag;
+/*
+ * 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;
 
 substitute(c)
 int    scount, slines, stotal;
 
 substitute(c)
@@ -112,10 +166,10 @@ substitute(c)
 {
        register line *addr;
        register int n;
 {
        register line *addr;
        register int n;
-       int gsubf;
+       int gsubf, hopcount = 0;
 
        gsubf = compsub(c);
 
        gsubf = compsub(c);
-       if (!inglobal)
+       if(FIXUNDO)
                save12(), undkind = UNDCHANGE;
        stotal = 0;
        slines = 0;
                save12(), undkind = UNDCHANGE;
        stotal = 0;
        slines = 0;
@@ -124,17 +178,16 @@ substitute(c)
                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;
@@ -145,7 +198,7 @@ substitute(c)
                        addr2 += n;
                }
        }
                        addr2 += n;
                }
        }
-       if (stotal == 0 && !inglobal && !xflag)
+       if (stotal == 0 && !inglobal && !cflag)
                error("Fail|Substitute pattern match failed");
        snote(stotal, slines);
        return (stotal);
                error("Fail|Substitute pattern match failed");
        snote(stotal, slines);
        return (stotal);
@@ -157,7 +210,7 @@ compsub(ch)
        static int gsubf;
 
        if (!value(EDCOMPATIBLE))
        static int gsubf;
 
        if (!value(EDCOMPATIBLE))
-               gsubf = xflag = 0;
+               gsubf = cflag = 0;
        uselastre = 0;
        switch (ch) {
 
        uselastre = 0;
        switch (ch) {
 
@@ -174,7 +227,7 @@ compsub(ch)
                uselastre = 1;
                comprhs(seof);
                gsubf = 0;
                uselastre = 1;
                comprhs(seof);
                gsubf = 0;
-               xflag = 0;
+               cflag = 0;
                break;
 
        case '~':
                break;
 
        case '~':
@@ -184,6 +237,8 @@ compsub(ch)
        redo:
                if (re.Expbuf[0] == 0)
                        error("No previous re|No previous regular expression");
        redo:
                if (re.Expbuf[0] == 0)
                        error("No previous re|No previous regular expression");
+               if (subre.Expbuf[0] == 0)
+                       error("No previous substitute re|No previous substitute to repeat");
                break;
        }
        for (;;) {
                break;
        }
        for (;;) {
@@ -195,7 +250,7 @@ compsub(ch)
                        continue;
 
                case 'c':
                        continue;
 
                case 'c':
-                       xflag = !xflag;
+                       cflag = !cflag;
                        continue;
 
                case 'r':
                        continue;
 
                case 'r':
@@ -220,7 +275,7 @@ 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);
 
        rp = rhsbuf;
        CP(orhsbuf, rp);
@@ -248,7 +303,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;
                        }
@@ -257,8 +312,10 @@ magic:
 
                case '\n':
                case EOF:
 
                case '\n':
                case EOF:
-                       ungetchar(c);
-                       goto endrhs;
+                       if (!(globp && globp[0])) {
+                               ungetchar(c);
+                               goto endrhs;
+                       }
 
                case '~':
                case '&':
 
                case '~':
                case '&':
@@ -266,9 +323,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:
@@ -305,7 +364,7 @@ confirmed(a)
 {
        register int c, ch;
 
 {
        register int c, ch;
 
-       if (xflag == 0)
+       if (cflag == 0)
                return (1);
        pofix();
        pline(lineno(a));
                return (1);
        pofix();
        pline(lineno(a));
@@ -520,7 +579,7 @@ complex:
                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");
-                       *ep++ = CEOF;
+                       *ep++ = CEOFC;
                        if (c == EOF)
                                ungetchar(c);
                        return (eof);
                        if (c == EOF)
                                ungetchar(c);
                        return (eof);
@@ -645,7 +704,7 @@ cerror("Bad \\n|\\n in regular expression with n greater than the number of \\('
                case '\n':
                        if (oknl) {
                                ungetchar(c);
                case '\n':
                        if (oknl) {
                                ungetchar(c);
-                               *ep++ = CEOF;
+                               *ep++ = CEOFC;
                                return (eof);
                        }
 cerror("Badly formed re|Missing closing delimiter for regular expression");
                                return (eof);
                        }
 cerror("Badly formed re|Missing closing delimiter for regular expression");
@@ -699,10 +758,6 @@ execute(gf, addr)
        if (gf) {
                if (circfl)
                        return (0);
        if (gf) {
                if (circfl)
                        return (0);
-#ifdef notdef
-               if (loc1 == loc2)
-                       loc2++;
-#endif
                locs = p1 = loc2;
        } else {
                if (addr == zero)
                locs = p1 = loc2;
        } else {
                if (addr == zero)
@@ -781,7 +836,7 @@ advance(lp, ep)
                        continue;
                return (0);
 
                        continue;
                return (0);
 
-       case CEOF:
+       case CEOFC:
                loc2 = lp;
                return (1);
 
                loc2 = lp;
                return (1);