fixed undo within a global command (would corrupt the buffer)
authorAndrew Moore <alm@FreeBSD.org>
Sat, 26 Jun 1993 06:47:21 +0000 (06:47 +0000)
committerAndrew Moore <alm@FreeBSD.org>
Sat, 26 Jun 1993 06:47:21 +0000 (06:47 +0000)
changed move within a global to behave as in SunOS
added a couple error messages

12 files changed:
bin/ed/POSIX
bin/ed/buf.c
bin/ed/ed.1
bin/ed/ed.c
bin/ed/ed.h
bin/ed/re.c
bin/ed/test/g3.d [new file with mode: 0644]
bin/ed/test/g3.r [new file with mode: 0644]
bin/ed/test/g3.t [new file with mode: 0644]
bin/ed/test/g4.d [new file with mode: 0644]
bin/ed/test/g4.r [new file with mode: 0644]
bin/ed/test/g4.t [new file with mode: 0644]

index dd506fb..47a80b9 100644 (file)
@@ -48,3 +48,15 @@ Though ed is not a binary editor, it can be used (if painfully) to edit
 binary files.  To assist in binary editing, when a file containing at
 least one ASCII NUL character is written, a newline is not appended
 if it did not already contain one upon reading.
 binary files.  To assist in binary editing, when a file containing at
 least one ASCII NUL character is written, a newline is not appended
 if it did not already contain one upon reading.
+
+Since the behavior of `u' (undo) within a `g' (global) command list is
+not specified by POSIX D11/2, it follows the behavior of the SunOS ed
+(this is the best way, I think, in that the alternatives are either too
+complicated to implement or too confusing to use):  undo forces a global
+command list to be executed only once, rather than for each line matching
+a global pattern.  In addtion, each instance of `u' within a global command
+undoes all previous commands (including undo's) in the command list.
+
+The `m' (move) command within a `g' command list also follows the SunOS
+ed implementation: any moved lines are removed from the global command's
+`active' list.
index 57c3361..1d74cb8 100644 (file)
@@ -165,7 +165,11 @@ getaddr(lp)
 
        while (cp != lp && (cp = cp->next) != &line0)
                n++;
 
        while (cp != lp && (cp = cp->next) != &line0)
                n++;
-       return (cp != &line0) ? n : 0;
+       if (n && cp == &line0) {
+               sprintf(errmsg, "invalid address");
+               return ERR;
+        }
+        return n;
 }
 
 
 }
 
 
index ff6a849..e9a3180 100644 (file)
@@ -92,9 +92,9 @@ commands have the structure:
 .I [address [,address]]command[parameters]
 .RE
 .sp
 .I [address [,address]]command[parameters]
 .RE
 .sp
-The address(es) indicate the line(s) to be affected by the command.
-If fewer addresses are given than the command accepts, then default
-addresses are supplied.
+The address(es) indicate the line or range of lines to be affected by the
+command.  If fewer addresses are given than the command accepts, then
+default addresses are supplied.
 
 .SS OPTIONS
 .TP 8
 
 .SS OPTIONS
 .TP 8
@@ -311,7 +311,7 @@ not listed below, including `{', '}', `(', `)', `<' and `>',
 matches itself.
 
 .TP 8
 matches itself.
 
 .TP 8
-\fR\\\fIc\fR
+\fR\e\fIc\fR
 Any backslash-escaped character
 .IR c ,
 except for `{', '}', `(', `)', `<' and `>',
 Any backslash-escaped character
 .IR c ,
 except for `{', '}', `(', `)', `<' and `>',
@@ -389,28 +389,28 @@ anchors the regular expression to the end of a line.
 Otherwise, it matches itself.
 
 .TP 8
 Otherwise, it matches itself.
 
 .TP 8
-\fR\\<\fR
+\fR\e<\fR
 Anchors the single character regular expression or subexpression
 immediately following it to the beginning of a word.
 (This may not be available)
 
 .TP 8
 Anchors the single character regular expression or subexpression
 immediately following it to the beginning of a word.
 (This may not be available)
 
 .TP 8
-\fR\\>\fR
+\fR\e>\fR
 Anchors the single character regular expression or subexpression
 immediately following it to the end of a word.
 (This may not be available)
 
 .TP 8
 Anchors the single character regular expression or subexpression
 immediately following it to the end of a word.
 (This may not be available)
 
 .TP 8
-\fR\\(\fIre\fR\\)\fR
+\fR\e(\fIre\fR\e)\fR
 Defines a subexpression
 .IR re .
 Subexpressions may be nested.
 Defines a subexpression
 .IR re .
 Subexpressions may be nested.
-A subsequent backreference of the form \fI`\\n'\fR, where
+A subsequent backreference of the form \fI`\en'\fR, where
 .I n
 is a number in the range [1,9], expands to the text matched by the
 .IR n th
 subexpression.
 .I n
 is a number in the range [1,9], expands to the text matched by the
 .IR n th
 subexpression.
-For example, the regular expression `\\(.*\\)\\1' matches any string
+For example, the regular expression `\e(.*\e)\e1' matches any string
 consisting of identical adjacent substrings.
 Subexpressions are ordered relative to
 their left delimiter.
 consisting of identical adjacent substrings.
 Subexpressions are ordered relative to
 their left delimiter.
@@ -426,7 +426,7 @@ the string `abbb' (as opposed to the substring `bbb'), since a null match
 is the only left-most match.
 
 .TP 8
 is the only left-most match.
 
 .TP 8
-\fR\\{\fIn,m\fR\\}\fR or \fR\\{\fIn,\fR\\}\fR or \fR\\{\fIn\fR\\}\fR
+\fR\e{\fIn,m\fR\e}\fR or \fR\e{\fIn,\fR\e}\fR or \fR\e{\fIn\fR\e}\fR
 Matches the single character regular expression or subexpression
 immediately preceding it at least
 .I n
 Matches the single character regular expression or subexpression
 immediately preceding it at least
 .I n
@@ -735,7 +735,7 @@ An unescaped `&' in
 .I replacement
 is replaced by the currently matched text.
 The character sequence
 .I replacement
 is replaced by the currently matched text.
 The character sequence
-\fI`\\m'\fR,
+\fI`\em'\fR,
 where
 .I m
 is a number in the range [1,9], is replaced by the
 where
 .I m
 is a number in the range [1,9], is replaced by the
@@ -912,8 +912,8 @@ that line.
 Buffer file
 .PD 0
 .TP 20
 Buffer file
 .PD 0
 .TP 20
-\fR./ed.hup\fR, $HOME/ed.hup
-First and second files to which
+ed.hup
+The file to which
 .B ed
 attempts to write the  buffer if the terminal hangs up.
 
 .B ed
 attempts to write the  buffer if the terminal hangs up.
 
@@ -971,6 +971,10 @@ replaces any occurrences of
 .I old
 with
 .IR new .
 .I old
 with
 .IR new .
+If the
+.I `u'
+(undo) command occurs in a global command list, then
+the command list is executed only once.
 
 If diagnostics are not disabled, attempting to quit
 .B ed
 
 If diagnostics are not disabled, attempting to quit
 .B ed
index de226ff..d43282e 100644 (file)
@@ -583,7 +583,6 @@ doglob(gflag)
 
 long ucurln = -1;      /* if >= 0, undo enabled */
 long ulastln = -1;     /* if >= 0, undo enabled */
 
 long ucurln = -1;      /* if >= 0, undo enabled */
 long ulastln = -1;     /* if >= 0, undo enabled */
-int usw = 0;           /* if set, undo last undo */
 int patlock = 0;       /* if set, pattern not released by optpat() */
 
 long rows = 22;                /* scroll length: ws_row - 2 */
 int patlock = 0;       /* if set, pattern not released by optpat() */
 
 long rows = 22;                /* scroll length: ws_row - 2 */
@@ -646,7 +645,8 @@ docmd(glob)
                        return ERR;
                VRFYCMD();
                memset(mark, 0, sizeof mark);
                        return ERR;
                VRFYCMD();
                memset(mark, 0, sizeof mark);
-               lndelete(1, lastln);
+               if (lndelete(1, lastln) < 0)
+                       return ERR;
                ureset();
                if (sbclose() < 0)
                        return ERR;
                ureset();
                if (sbclose() < 0)
                        return ERR;
@@ -752,9 +752,7 @@ docmd(glob)
                }
                VRFYCMD();
                if (!glob) ureset();
                }
                VRFYCMD();
                if (!glob) ureset();
-               if (num == line1 - 1 || num == line2)
-                       curln = line2;
-               else if (move(num) < 0)
+               if (move(num, glob) < 0)
                        return ERR;
                else
                        modified = 1;
                        return ERR;
                else
                        modified = 1;
@@ -912,7 +910,7 @@ docmd(glob)
                        return ERR;
                }
                VRFYCMD();
                        return ERR;
                }
                VRFYCMD();
-               if (undo() < 0)
+               if (undo(glob) < 0)
                        return ERR;
                break;
        case 'v':
                        return ERR;
                break;
        case 'v':
@@ -1300,74 +1298,6 @@ append(n, glob)
 }
 
 
 }
 
 
-#ifdef sun
-/* subst: change all text matching a pattern in a range of lines according to
-   a substitution template; return status  */
-subst(pat, gflag)
-       pattern_t *pat;
-       int gflag;
-{
-       undo_t *up = NULL;
-       char *txt;
-       char *eot;
-       line_t *bp, *ep, *np;
-       long ocl;
-       long nsubs = 0;
-       int len;
-
-       ep = getlp(curln = line2);
-       for (bp = getlp(line1); bp != ep->next; bp = bp->next)
-               if ((len = regsub(pat, bp, gflag)) < 0)
-                       return ERR;
-               else if (!len) {
-                       /* add copy of bp after current line - this avoids
-                          overloading the undo structure, since only two
-                          undo nodes are needed for the whole substitution;
-                          the cost is high, but the less than if undo is
-                          overloaded on a Sun evidently. XXX */
-                       if ((np = lpdup(bp)) == NULL)
-                               return ERR;
-                       spl1();
-                       lpqueue(np);
-                       if (up)
-                               up->t = getlp(curln);
-                       else if ((up = upush(UADD, curln, curln)) == NULL) {
-                               spl0();
-                               return ERR;
-                       }
-                       spl0();
-               } else {
-                       txt = rbuf;
-                       eot = rbuf + len;
-                       spl1();
-                       do {
-                               if ((txt = puttxt(txt)) == NULL) {
-                                       spl0();
-                                       return ERR;
-                               } else if (up)
-                                       up->t = getlp(curln);
-                               else if ((up = upush(UADD, curln, curln)) == NULL) {
-                                       spl0();
-                                       return ERR;
-                               }
-                       } while (txt != eot);
-                       spl0();
-                       nsubs++;
-               }
-       ocl = curln;
-       lndelete(line1, line2);
-       curln = ocl - (line2 - line1 + 1);
-       if  (nsubs == 0 && !(gflag & GLB)) {
-               sprintf(errmsg, "no match");
-               return ERR;
-       } else if ((gflag & (GPR | GLS | GNP))
-        && doprint(curln, curln, gflag) < 0)
-               return ERR;
-       return 1;
-}
-#else  /* sun */
-
-
 /* subst: change all text matching a pattern in a range of lines according to
    a substitution template; return status  */
 subst(pat, gflag)
 /* subst: change all text matching a pattern in a range of lines according to
    a substitution template; return status  */
 subst(pat, gflag)
@@ -1389,7 +1319,8 @@ subst(pat, gflag)
                        return ERR;
                else if (len) {
                        up = NULL;
                        return ERR;
                else if (len) {
                        up = NULL;
-                       lndelete(curln, curln);
+                       if (lndelete(curln, curln) < 0)
+                               return ERR;
                        txt = rbuf;
                        eot = rbuf + len;
                        spl1();
                        txt = rbuf;
                        eot = rbuf + len;
                        spl1();
@@ -1416,7 +1347,6 @@ subst(pat, gflag)
                return ERR;
        return 1;
 }
                return ERR;
        return 1;
 }
-#endif /* sun */
 
 
 /* regsub: replace text matched by a pattern according to a substitution
 
 
 /* regsub: replace text matched by a pattern according to a substitution
@@ -1498,7 +1428,8 @@ join(from, to)
        }
        CKBUF(buf, n, size + 2, ERR);
        memcpy(buf + size, "\n", 2);
        }
        CKBUF(buf, n, size + 2, ERR);
        memcpy(buf + size, "\n", 2);
-       lndelete(from, to);
+       if (lndelete(from, to) < 0)
+               return ERR;
        curln = from - 1;
        spl1();
        if (puttxt(buf) == NULL
        curln = from - 1;
        spl1();
        if (puttxt(buf) == NULL
@@ -1513,28 +1444,37 @@ join(from, to)
 
 
 /* move: move a range of lines */
 
 
 /* move: move a range of lines */
-move(num)
+move(num, glob)
        long num;
 {
        long num;
 {
-       line_t *b1, *a1, *b2, *a2;
+       line_t *b1, *a1, *b2, *a2, *lp;
        long n = nextln(line2, lastln);
        long p = prevln(line1, lastln);
        long n = nextln(line2, lastln);
        long p = prevln(line1, lastln);
+       int done = (num == line1 - 1 || num == line2);
 
        spl1();
 
        spl1();
-       if (upush(UMOV, p, n) == NULL
+       if (done) {
+               a2 = getlp(n);
+               b2 = getlp(p);
+               curln = line2;
+       } else if (upush(UMOV, p, n) == NULL
         || upush(UMOV, num, nextln(num, lastln)) == NULL) {
         || upush(UMOV, num, nextln(num, lastln)) == NULL) {
-               spl0();
-               return ERR;
+               spl0();
+               return ERR;
+       } else {
+               a1 = getlp(n);
+               if (num < line1)
+                       b1 = getlp(p), b2 = getlp(num); /* this getlp last! */
+               else    b2 = getlp(num), b1 = getlp(p); /* this getlp last! */
+               a2 = b2->next;
+               requeue(b2, b1->next);
+               requeue(a1->prev, a2);
+               requeue(b1, a1);
+               curln = num + ((num < line1) ? line2 - line1 + 1 : 0);
        }
        }
-       a1 = getlp(n);
-       if (num < line1)
-               b1 = getlp(p), b2 = getlp(num); /* this getlp last! */
-       else    b2 = getlp(num), b1 = getlp(p); /* this getlp last! */
-       a2 = b2->next;
-       requeue(b2, b1->next);
-       requeue(a1->prev, a2);
-       requeue(b1, a1);
-       curln = num + ((num < line1) ? line2 - line1 + 1 : 0);
+       if (glob)
+               for (lp = b2->next; lp != a2; lp = lp->next)
+                       lp->len &= ~ACTV;               /* zero ACTV  bit */
        spl0();
        return 0;
 }
        spl0();
        return 0;
 }
@@ -1857,7 +1797,6 @@ undo_t *ustack = NULL;                            /* undo stack */
 long usize = 0;                                        /* stack size variable */
 long u_p = 0;                                  /* undo stack pointer */
 
 long usize = 0;                                        /* stack size variable */
 long u_p = 0;                                  /* undo stack pointer */
 
-
 /* upush: return pointer to intialized undo node */
 undo_t *
 upush(type, from, to)
 /* upush: return pointer to intialized undo node */
 undo_t *
 upush(type, from, to)
@@ -1894,14 +1833,22 @@ upush(type, from, to)
        return NULL;
 }
 
        return NULL;
 }
 
+
+/* USWAP: swap undo nodes */
+#define USWAP(x,y) { \
+       undo_t utmp; \
+       utmp = x, x = y, y = utmp; \
+}
+
+
 /* undo: undo last change to the editor buffer */
 /* undo: undo last change to the editor buffer */
-undo()
+undo(glob)
+       int glob;
 {
 {
-       long n = usw ? 0 : u_p - 1;
-       int i = usw ? 1 : -1;
-       long j = u_p;
+       long n;
        long ocurln = curln;
        long olastln = lastln;
        long ocurln = curln;
        long olastln = lastln;
+       line_t *lp, *np;
 
        if (ucurln == -1 || ulastln == -1) {
                sprintf(errmsg, "nothing to undo");
 
        if (ucurln == -1 || ulastln == -1) {
                sprintf(errmsg, "nothing to undo");
@@ -1910,8 +1857,8 @@ undo()
                modified = 1;
        getlp(0);                               /* this getlp last! */
        spl1();
                modified = 1;
        getlp(0);                               /* this getlp last! */
        spl1();
-       for (; j-- > 0; n += i)
-               switch(ustack[n].type ^ usw) {
+       for (n = u_p; n-- > 0;) {
+               switch(ustack[n].type) {
                case UADD:
                        requeue(ustack[n].h->prev, ustack[n].t->next);
                        break;
                case UADD:
                        requeue(ustack[n].h->prev, ustack[n].t->next);
                        break;
@@ -1921,16 +1868,23 @@ undo()
                        break;
                case UMOV:
                case VMOV:
                        break;
                case UMOV:
                case VMOV:
-                       requeue(ustack[n + i].h, ustack[n].h->next);
-                       requeue(ustack[n].t->prev, ustack[n + i].t);
+                       requeue(ustack[n - 1].h, ustack[n].h->next);
+                       requeue(ustack[n].t->prev, ustack[n - 1].t);
                        requeue(ustack[n].h, ustack[n].t);
                        requeue(ustack[n].h, ustack[n].t);
-                       n += i, j--;
+                       n--;
                        break;
                default:
                        /*NOTREACHED*/
                        ;
                }
                        break;
                default:
                        /*NOTREACHED*/
                        ;
                }
-       usw = 1 - usw;
+               ustack[n].type ^= 1;
+       }
+       /* reverse undo order */
+       for (n = u_p; n-- > (u_p + 1)/ 2;)
+               USWAP(ustack[n], ustack[u_p - 1 - n]);
+       if (glob)
+               for (lp = np = getlp(0); (lp = lp->next) != np;)
+                       lp->len &= ~ACTV;               /* zero ACTV bit */
        curln = ucurln, ucurln = ocurln;
        lastln = ulastln, ulastln = olastln;
        spl0();
        curln = ucurln, ucurln = ocurln;
        lastln = ulastln, ulastln = olastln;
        spl0();
@@ -1946,7 +1900,7 @@ ureset()
        int i;
 
        while (u_p--)
        int i;
 
        while (u_p--)
-               if ((ustack[u_p].type ^ usw) == UDEL) {
+               if ((ustack[u_p].type) == UDEL) {
                        ep = ustack[u_p].t->next;
                        for (lp = ustack[u_p].h; lp != ep; lp = tl) {
                                if (markno)
                        ep = ustack[u_p].t->next;
                        for (lp = ustack[u_p].h; lp != ep; lp = tl) {
                                if (markno)
@@ -1959,7 +1913,7 @@ ureset()
                                free(lp);
                        }
                }
                                free(lp);
                        }
                }
-       u_p = usw = 0;
+       u_p = 0;
        ucurln = curln;
        ulastln = lastln;
 }
        ucurln = curln;
        ulastln = lastln;
 }
index 1b277fe..c854364 100644 (file)
@@ -237,7 +237,7 @@ void lpqueue __P((line_t *));
 void makekey __P((char *));
 char *makesub __P((int));
 char *translit __P((char *, int, int, int));
 void makekey __P((char *));
 char *makesub __P((int));
 char *translit __P((char *, int, int, int));
-int move __P((long));
+int move __P((long, int));
 int oddesc __P((char *, char *));
 void onhup __P((int));
 void onintr __P((int));
 int oddesc __P((char *, char *));
 void onhup __P((int));
 void onintr __P((int));
@@ -253,7 +253,7 @@ int catsub __P((char *, regmatch_t *, int));
 int subst __P((pattern_t *, int));
 int tobinhex __P((int, int));
 int transfer __P((long));
 int subst __P((pattern_t *, int));
 int tobinhex __P((int, int));
 int transfer __P((long));
-int undo __P((void));
+int undo __P((int));
 undo_t *upush __P((int, long, long));
 void ureset __P((void));
 
 undo_t *upush __P((int, long, long));
 void ureset __P((void));
 
index 462c816..e944750 100644 (file)
@@ -71,7 +71,7 @@ optpat()
                sprintf(errmsg, "invalid pattern delimiter");
                return NULL;
        } else if (*ibufp == delim) {
                sprintf(errmsg, "invalid pattern delimiter");
                return NULL;
        } else if (*ibufp == delim) {
-               sprintf(errmsg, "no previous pattern");
+               if (!exp) sprintf(errmsg, "no previous pattern");
                return exp;
        } else if ((exps = getlhs(delim)) == NULL)
                return NULL;
                return exp;
        } else if ((exps = getlhs(delim)) == NULL)
                return NULL;
diff --git a/bin/ed/test/g3.d b/bin/ed/test/g3.d
new file mode 100644 (file)
index 0000000..92f337e
--- /dev/null
@@ -0,0 +1,5 @@
+line 1
+line 2
+line 3
+line 4
+line5
diff --git a/bin/ed/test/g3.r b/bin/ed/test/g3.r
new file mode 100644 (file)
index 0000000..cc6fbdd
--- /dev/null
@@ -0,0 +1,5 @@
+linc 3
+xine 1
+xine 2
+xinc 4
+xinc5
diff --git a/bin/ed/test/g3.t b/bin/ed/test/g3.t
new file mode 100644 (file)
index 0000000..2d052a6
--- /dev/null
@@ -0,0 +1,4 @@
+g/./s//x/\
+3m0
+g/./s/e/c/\
+2,3m1
diff --git a/bin/ed/test/g4.d b/bin/ed/test/g4.d
new file mode 100644 (file)
index 0000000..92f337e
--- /dev/null
@@ -0,0 +1,5 @@
+line 1
+line 2
+line 3
+line 4
+line5
diff --git a/bin/ed/test/g4.r b/bin/ed/test/g4.r
new file mode 100644 (file)
index 0000000..350882d
--- /dev/null
@@ -0,0 +1,7 @@
+hello
+zine 1
+line 2
+line 3
+line 4
+line5
+world
diff --git a/bin/ed/test/g4.t b/bin/ed/test/g4.t
new file mode 100644 (file)
index 0000000..ec61816
--- /dev/null
@@ -0,0 +1,13 @@
+g/./s/./x/\
+u\
+s/./y/\
+u\
+s/./z/\
+u
+u
+0a
+hello
+.
+$a
+world
+.