cleanups, add manual page
[unix-history] / usr / src / usr.bin / ex / ex_vget.c
index c1d1828..4789454 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_vget.c  6.10 (Berkeley) %G%";
+#endif not lint
+
 #include "ex.h"
 #include "ex_tty.h"
 #include "ex_vis.h"
 #include "ex.h"
 #include "ex_tty.h"
 #include "ex_vis.h"
  * Return the key.
  */
 ungetkey(c)
  * Return the key.
  */
 ungetkey(c)
-       char c;
+       int c;          /* mjm: char --> int */
 {
 
 {
 
-       if (Peekkey != ATTN)
-               Peekkey = c;
+       if (Peek_key != ATTN)
+               Peek_key = c;
 }
 
 /*
 }
 
 /*
@@ -26,7 +35,7 @@ ungetkey(c)
  */
 getkey()
 {
  */
 getkey()
 {
-       register char c;
+       register int c;         /* mjm: char --> int */
 
        do {
                c = getbr();
 
        do {
                c = getbr();
@@ -42,11 +51,13 @@ getkey()
 peekbr()
 {
 
 peekbr()
 {
 
-       Peekkey = getbr();
-       return (Peekkey == 0);
+       Peek_key = getbr();
+       return (Peek_key == 0);
 }
 
 short  precbksl;
 }
 
 short  precbksl;
+jmp_buf        readbuf;
+int    doingread = 0;
 
 /*
  * Get a keystroke, including a ^@.
 
 /*
  * Get a keystroke, including a ^@.
@@ -63,13 +74,25 @@ getbr()
        char ch;
        register int c, d;
        register char *colp;
        char ch;
        register int c, d;
        register char *colp;
+#define BEEHIVE
+#ifdef BEEHIVE
+       static char Peek2key;
+#endif
+       extern short slevel, ttyindes;
 
 getATTN:
 
 getATTN:
-       if (Peekkey) {
-               c = Peekkey;
-               Peekkey = 0;
+       if (Peek_key) {
+               c = Peek_key;
+               Peek_key = 0;
+               return (c);
+       }
+#ifdef BEEHIVE
+       if (Peek2key) {
+               c = Peek2key;
+               Peek2key = 0;
                return (c);
        }
                return (c);
        }
+#endif
        if (vglobp) {
                if (*vglobp)
                        return (lastvgk = *vglobp++);
        if (vglobp) {
                if (*vglobp)
                        return (lastvgk = *vglobp++);
@@ -81,21 +104,48 @@ getATTN:
                        return(*vmacp++);
                /* End of a macro or set of nested macros */
                vmacp = 0;
                        return(*vmacp++);
                /* End of a macro or set of nested macros */
                vmacp = 0;
+               if (inopen == -1)       /* don't screw up undo for esc esc */
+                       vundkind = VMANY;
                inopen = 1;     /* restore old setting now that macro done */
                inopen = 1;     /* restore old setting now that macro done */
-               vundkind = VMANY;
+               vch_mac = VC_NOTINMAC;
        }
        }
-#ifdef TRACE
-       if (trace)
-               fflush(trace);
-#endif
        flusho();
 again:
        flusho();
 again:
-       if (read(0, &ch, 1) != 1) {
+       if (setjmp(readbuf))
+               goto getATTN;
+       doingread = 1;
+#ifndef        vms
+       c = read(slevel == 0 ? 0 : ttyindes, &ch, 1);
+#else
+       c = vms_read(slevel == 0 ? 0 : ttyindes, &ch, 1);
+#endif
+       doingread = 0;
+       if (c != 1) {
                if (errno == EINTR)
                        goto getATTN;
                error("Input read error");
        }
        c = ch & TRIM;
                if (errno == EINTR)
                        goto getATTN;
                error("Input read error");
        }
        c = ch & TRIM;
+#ifdef BEEHIVE
+       if (XB && slevel==0 && c == ESCAPE) {
+               if (read(0, &Peek2key, 1) != 1)
+                       goto getATTN;
+               Peek2key &= TRIM;
+               switch (Peek2key) {
+               case 'C':       /* SPOW mode sometimes sends \EC for space */
+                       c = ' ';
+                       Peek2key = 0;
+                       break;
+               case 'q':       /* f2 -> ^C */
+                       c = CTRL('c');
+                       Peek2key = 0;
+                       break;
+               case 'p':       /* f1 -> esc */
+                       Peek2key = 0;
+                       break;
+               }
+       }
+#endif
 
 #ifdef UCVISUAL
        /*
 
 #ifdef UCVISUAL
        /*
@@ -125,14 +175,14 @@ again:
                        }
                        if (precbksl == 2) {
                                if (!d) {
                        }
                        if (precbksl == 2) {
                                if (!d) {
-                                       Peekkey = c;
+                                       Peek_key = c;
                                        precbksl = 0;
                                        c = '\\';
                                }
                        } else if (d)
                                c = d;
                        else {
                                        precbksl = 0;
                                        c = '\\';
                                }
                        } else if (d)
                                c = d;
                        else {
-                               Peekkey = c;
+                               Peek_key = c;
                                precbksl = 0;
                                c = '\\';
                        }
                                precbksl = 0;
                                c = '\\';
                        }
@@ -166,6 +216,11 @@ getesc()
        c = getkey();
        switch (c) {
 
        c = getkey();
        switch (c) {
 
+       case CTRL('v'):
+       case CTRL('q'):
+               c = getkey();
+               return (c);
+
        case ATTN:
        case QUIT:
                ungetkey(c);
        case ATTN:
        case QUIT:
                ungetkey(c);
@@ -183,8 +238,8 @@ getesc()
 peekkey()
 {
 
 peekkey()
 {
 
-       Peekkey = getkey();
-       return (Peekkey);
+       Peek_key = getkey();
+       return (Peek_key);
 }
 
 /*
 }
 
 /*
@@ -205,7 +260,7 @@ readecho(c)
                vclrech(0);
        splitw++;
        vgoto(WECHO, 0);
                vclrech(0);
        splitw++;
        vgoto(WECHO, 0);
-       putchar(c);
+       ex_putchar(c);
        vclreol();
        vgoto(WECHO, 1);
        cursor = linebuf; linebuf[0] = 0; genbuf[0] = c;
        vclreol();
        vgoto(WECHO, 1);
        cursor = linebuf; linebuf[0] = 0; genbuf[0] = c;
@@ -215,21 +270,23 @@ readecho(c)
                vglobp = INS;
        }
        OP = Pline; Pline = normline;
                vglobp = INS;
        }
        OP = Pline; Pline = normline;
-       ignore(vgetline(0, genbuf + 1, &waste));
+       ignore(vgetline(0, genbuf + 1, &waste, c));
+       if (Outchar == termchar)
+               ex_putchar('\n');
        vscrap();
        Pline = OP;
        vscrap();
        Pline = OP;
-       if (Peekkey != ATTN && Peekkey != QUIT && Peekkey != CTRL(h)) {
+       if (Peek_key != ATTN && Peek_key != QUIT && Peek_key != CTRL('h')) {
                cursor = sc;
                vclreol();
                return (0);
        }
 blewit:
                cursor = sc;
                vclreol();
                return (0);
        }
 blewit:
-       OPeek = Peekkey==CTRL(h) ? 0 : Peekkey; Peekkey = 0;
+       OPeek = Peek_key==CTRL('h') ? 0 : Peek_key; Peek_key = 0;
        splitw = 0;
        vclean();
        vshow(dot, NOLINE);
        vnline(sc);
        splitw = 0;
        vclean();
        vshow(dot, NOLINE);
        vnline(sc);
-       Peekkey = OPeek;
+       Peek_key = OPeek;
        return (1);
 }
 
        return (1);
 }
 
@@ -241,7 +298,7 @@ blewit:
 setLAST()
 {
 
 setLAST()
 {
 
-       if (vglobp)
+       if (vglobp || vmacp)
                return;
        lastreg = vreg;
        lasthad = Xhadcnt;
                return;
        lastreg = vreg;
        lasthad = Xhadcnt;
@@ -269,13 +326,13 @@ addtext(cp)
 setDEL()
 {
 
 setDEL()
 {
 
-       setBUF(DEL);
+       ex_setBUF(DEL);
 }
 
 /*
  * Put text from cursor upto wcursor in BUF.
  */
 }
 
 /*
  * Put text from cursor upto wcursor in BUF.
  */
-setBUF(BUF)
+ex_setBUF(BUF)
        register char *BUF;
 {
        register int c;
        register char *BUF;
 {
        register int c;
@@ -318,14 +375,14 @@ noteit(must)
        if (WBOT == WECHO)
                vmoveitup(1, 1);
        vigoto(WECHO, 0);
        if (WBOT == WECHO)
                vmoveitup(1, 1);
        vigoto(WECHO, 0);
-       printf("%d %sline", notecnt, notesgn);
+       ex_printf("%d %sline", notecnt, notesgn);
        if (notecnt > 1)
        if (notecnt > 1)
-               putchar('s');
+               ex_putchar('s');
        if (*notenam) {
        if (*notenam) {
-               printf(" %s", notenam);
+               ex_printf(" %s", notenam);
                if (*(strend(notenam) - 1) != 'e')
                if (*(strend(notenam) - 1) != 'e')
-                       putchar('e');
-               putchar('d');
+                       ex_putchar('e');
+               ex_putchar('d');
        }
        vclreol();
        notecnt = 0;
        }
        vclreol();
        notecnt = 0;
@@ -348,7 +405,7 @@ beep()
        if (VB)
                vputp(VB, 0);
        else
        if (VB)
                vputp(VB, 0);
        else
-               vputc(CTRL(g));
+               vputc(CTRL('g'));
 }
 
 /*
 }
 
 /*
@@ -385,12 +442,19 @@ map(c,maps)
        if (trace)
                fprintf(trace,"map(%c): ",c);
 #endif
        if (trace)
                fprintf(trace,"map(%c): ",c);
 #endif
+       /*
+        * If c==0, the char came from getesc typing escape.  Pass it through
+        * unchanged.  0 messes up the following code anyway.
+        */
+       if (c==0)
+               return(0);
+
        b[0] = c;
        b[1] = 0;
        for (d=0; maps[d].mapto; d++) {
 #ifdef MDEBUG
                if (trace)
        b[0] = c;
        b[1] = 0;
        for (d=0; maps[d].mapto; d++) {
 #ifdef MDEBUG
                if (trace)
-                       fprintf(trace,"d=%d, ",d);
+                       fprintf(trace,"\ntry '%s', ",maps[d].cap);
 #endif
                if (p = maps[d].cap) {
                        for (q=b; *p; p++, q++) {
 #endif
                if (p = maps[d].cap) {
                        for (q=b; *p; p++, q++) {
@@ -400,6 +464,8 @@ map(c,maps)
 #endif
                                if (*q==0) {
                                        /*
 #endif
                                if (*q==0) {
                                        /*
+                                        * Is there another char waiting?
+                                        *
                                         * This test is oversimplified, but
                                         * should work mostly. It handles the
                                         * case where we get an ESCAPE that
                                         * This test is oversimplified, but
                                         * should work mostly. It handles the
                                         * case where we get an ESCAPE that
@@ -407,10 +473,28 @@ map(c,maps)
                                         */
                                        if ((c=='#' ? peekkey() : fastpeekkey()) == 0) {
 #ifdef MDEBUG
                                         */
                                        if ((c=='#' ? peekkey() : fastpeekkey()) == 0) {
 #ifdef MDEBUG
-                                       if (trace)
-                                               fprintf(trace,"fpk=0: return %c",c);
+                                               if (trace)
+                                                       fprintf(trace,"fpk=0: will return '%c'",c);
+#endif
+                                               /*
+                                                * Nothing waiting.  Push back
+                                                * what we peeked at & return
+                                                * failure (c).
+                                                *
+                                                * We want to be able to undo
+                                                * commands, but it's nonsense
+                                                * to undo part of an insertion
+                                                * so if in input mode don't.
+                                                */
+#ifdef MDEBUG
+                                               if (trace)
+                                                       fprintf(trace, "Call macpush, b %d %d %d\n", b[0], b[1], b[2]);
+#endif
+                                               macpush(&b[1],maps == arrows);
+#ifdef MDEBUG
+                                               if (trace)
+                                                       fprintf(trace, "return %d\n", c);       
 #endif
 #endif
-                                               macpush(&b[1]);
                                                return(c);
                                        }
                                        *q = getkey();
                                                return(c);
                                        }
                                        *q = getkey();
@@ -419,11 +503,11 @@ map(c,maps)
                                if (*p != *q)
                                        goto contin;
                        }
                                if (*p != *q)
                                        goto contin;
                        }
-                       macpush(maps[d].mapto);
+                       macpush(maps[d].mapto,maps == arrows);
                        c = getkey();
 #ifdef MDEBUG
                        c = getkey();
 #ifdef MDEBUG
-       if (trace)
-               fprintf(trace,"Success: return %c",c);
+                       if (trace)
+                               fprintf(trace,"Success: push(%s), return %c",maps[d].mapto, c);
 #endif
                        return(c);      /* first char of map string */
                        contin:;
 #endif
                        return(c);      /* first char of map string */
                        contin:;
@@ -431,9 +515,9 @@ map(c,maps)
        }
 #ifdef MDEBUG
        if (trace)
        }
 #ifdef MDEBUG
        if (trace)
-               fprintf(trace,"Fail: return %c",c); /* DEBUG */
+               fprintf(trace,"Fail: push(%s), return %c", &b[1], c);
 #endif
 #endif
-       macpush(&b[1]);
+       macpush(&b[1],0);
        return(c);
 }
 
        return(c);
 }
 
@@ -442,36 +526,88 @@ map(c,maps)
  * worry about where vmacp was previously pointing. We also have to
  * check for overflow (which is typically from a recursive macro)
  * Finally we have to set a flag so the whole thing can be undone.
  * worry about where vmacp was previously pointing. We also have to
  * check for overflow (which is typically from a recursive macro)
  * Finally we have to set a flag so the whole thing can be undone.
+ * canundo is 1 iff we want to be able to undo the macro.  This
+ * is false for, for example, pushing back lookahead from fastpeekkey(),
+ * since otherwise two fast escapes can clobber our undo.
  */
  */
-macpush(st)
+macpush(st, canundo)
 char *st;
 char *st;
+int canundo;
 {
        char tmpbuf[BUFSIZ];
 
        if (st==0 || *st==0)
                return;
 {
        char tmpbuf[BUFSIZ];
 
        if (st==0 || *st==0)
                return;
-#ifdef TRACE
+#ifdef MDEBUG
        if (trace)
        if (trace)
-               fprintf(trace, "macpush(%s)",st);
+               fprintf(trace, "macpush(%s), canundo=%d\n",st,canundo);
 #endif
 #endif
-       if (strlen(vmacp) + strlen(st) > BUFSIZ)
+       if ((vmacp ? strlen(vmacp) : 0) + strlen(st) > BUFSIZ)
                error("Macro too long@ - maybe recursive?");
                error("Macro too long@ - maybe recursive?");
-       if (vmacp)
+       if (vmacp) {
                strcpy(tmpbuf, vmacp);
                strcpy(tmpbuf, vmacp);
+               if (!FIXUNDO)
+                       canundo = 0;    /* can't undo inside a macro anyway */
+       }
        strcpy(vmacbuf, st);
        if (vmacp)
                strcat(vmacbuf, tmpbuf);
        vmacp = vmacbuf;
        /* arrange to be able to undo the whole macro */
        strcpy(vmacbuf, st);
        if (vmacp)
                strcat(vmacbuf, tmpbuf);
        vmacp = vmacbuf;
        /* arrange to be able to undo the whole macro */
-       inopen = -1;    /* no need to save since it had to be 1 or -1 before */
-       otchng = tchng;
-       saveall();
-       vundkind = VMANY;
-#ifdef TRACE
-       if (trace)
-               fprintf(trace, "saveall for macro: undkind=%d, unddel=%d, undap1=%d, undap2=%d, dol=%d, unddol=%d, truedol=%d\n", undkind, lineno(unddel), lineno(undap1), lineno(undap2), lineno(dol), lineno(unddol), lineno(truedol));
+       if (canundo) {
+#ifdef notdef
+               otchng = tchng;
+               vsave();
+               saveall();
+               inopen = -1;    /* no need to save since it had to be 1 or -1 before */
+               vundkind = VMANY;
 #endif
 #endif
+               vch_mac = VC_NOCHANGE;
+       }
+}
+
+#ifdef TRACE
+visdump(s)
+char *s;
+{
+       register int i;
+
+       if (!trace) return;
+
+       fprintf(trace, "\n%s: basWTOP=%d, basWLINES=%d, WTOP=%d, WBOT=%d, WLINES=%d, WCOLS=%d, WECHO=%d\n",
+               s, basWTOP, basWLINES, WTOP, WBOT, WLINES, WCOLS, WECHO);
+       fprintf(trace, "   vcnt=%d, vcline=%d, cursor=%d, wcursor=%d, wdot=%d\n",
+               vcnt, vcline, cursor-linebuf, wcursor-linebuf, wdot-zero);
+       for (i=0; i<TUBELINES; i++)
+               if (vtube[i] && *vtube[i])
+                       fprintf(trace, "%d: '%s'\n", i, vtube[i]);
+       tvliny();
+}
+
+vudump(s)
+char *s;
+{
+       register line *p;
+       char savelb[1024];
+
+       if (!trace) return;
+
+       fprintf(trace, "\n%s: undkind=%d, vundkind=%d, unddel=%d, undap1=%d, undap2=%d,\n",
+               s, undkind, vundkind, lineno(unddel), lineno(undap1), lineno(undap2));
+       fprintf(trace, "  undadot=%d, dot=%d, dol=%d, unddol=%d, truedol=%d\n",
+               lineno(undadot), lineno(dot), lineno(dol), lineno(unddol), lineno(truedol));
+       fprintf(trace, "  [\n");
+       CP(savelb, linebuf);
+       fprintf(trace, "linebuf = '%s'\n", linebuf);
+       for (p=zero+1; p<=truedol; p++) {
+               fprintf(trace, "%o ", *p);
+               getline(*p);
+               fprintf(trace, "'%s'\n", linebuf);
+       }
+       fprintf(trace, "]\n");
+       CP(linebuf, savelb);
 }
 }
+#endif
 
 /*
  * Get a count from the keyed input stream.
 
 /*
  * Get a count from the keyed input stream.
@@ -503,10 +639,35 @@ vgetcnt()
 fastpeekkey()
 {
        int trapalarm();
 fastpeekkey()
 {
        int trapalarm();
+       int (*Oint)();
        register int c;
 
        register int c;
 
-       signal(SIGALRM, trapalarm);
-       alarm(1);
+       /*
+        * If the user has set notimeout, we wait forever for a key.
+        * If we are in a macro we do too, but since it's already
+        * buffered internally it will return immediately.
+        * In other cases we force this to die in 1 second.
+        * This is pretty reliable (VMUNIX rounds it to .5 - 1.5 secs,
+        * but UNIX truncates it to 0 - 1 secs) but due to system delays
+        * there are times when arrow keys or very fast typing get counted
+        * as separate.  notimeout is provided for people who dislike such
+        * nondeterminism.
+        */
+#ifdef MDEBUG
+       if (trace)
+               fprintf(trace,"\nfastpeekkey: ",c);
+#endif
+       Oint = signal(SIGINT, trapalarm);
+       if (value(TIMEOUT) && inopen >= 0) {
+               signal(SIGALRM, trapalarm);
+#ifdef MDEBUG
+               alarm(10);
+               if (trace)
+                       fprintf(trace, "set alarm ");
+#else
+               alarm(1);
+#endif
+       }
        CATCH
                c = peekkey();
 #ifdef MDEBUG
        CATCH
                c = peekkey();
 #ifdef MDEBUG
@@ -518,17 +679,19 @@ fastpeekkey()
                c = 0;
 #ifdef MDEBUG
        if (trace)
                c = 0;
 #ifdef MDEBUG
        if (trace)
-               fprintf(trace,"[TOUT]",c);
+               fprintf(trace,"[TIMEOUT]",c);
 #endif
        ENDCATCH
 #ifdef MDEBUG
        if (trace)
                fprintf(trace,"[fpk:%o]",c);
 #endif
 #endif
        ENDCATCH
 #ifdef MDEBUG
        if (trace)
                fprintf(trace,"[fpk:%o]",c);
 #endif
+       signal(SIGINT,Oint);
        return(c);
 }
 
 trapalarm() {
        alarm(0);
        return(c);
 }
 
 trapalarm() {
        alarm(0);
-       longjmp(vreslab,1);
+       if (vcatch)
+               longjmp(vreslab,1);
 }
 }