date and time created 83/02/11 15:45:15 by rrh
[unix-history] / usr / src / usr.bin / ex / ex_put.c
index 033c05b..ceeaf0d 100644 (file)
@@ -1,4 +1,5 @@
-/* Copyright (c) 1979 Regents of the University of California */
+/* Copyright (c) 1981 Regents of the University of California */
+static char *sccsid = "@(#)ex_put.c    7.7     %G%";
 #include "ex.h"
 #include "ex_tty.h"
 #include "ex_vis.h"
 #include "ex.h"
 #include "ex_tty.h"
 #include "ex_vis.h"
@@ -194,12 +195,8 @@ slobber(c)
  * The output buffer is initialized with a useful error
  * message so we don't have to keep it in data space.
  */
  * The output buffer is initialized with a useful error
  * message so we don't have to keep it in data space.
  */
-static char linb[66] = {
-       'E', 'r', 'r', 'o', 'r', ' ', 'm', 'e', 's', 's', 'a', 'g', 'e', ' ',
-       'f', 'i', 'l', 'e', ' ', 'n', 'o', 't', ' ',
-       'a', 'v', 'a', 'i', 'l', 'a', 'b', 'l', 'e', '\n', 0
-};
-static char *linp = linb + 33;
+static char linb[66];
+char *linp = linb;
 
 /*
  * Phadnl records when we have already had a complete line ending with \n.
 
 /*
  * Phadnl records when we have already had a complete line ending with \n.
@@ -303,7 +300,7 @@ flush1()
                                        outcol++;
                                        destcol++;
                                        if (XN && outcol % COLUMNS == 0)
                                        outcol++;
                                        destcol++;
                                        if (XN && outcol % COLUMNS == 0)
-                                               putch('\n');
+                                               putch('\r'), putch('\n');
                                }
                                c = *lp++;
                                if (c <= ' ')
                                }
                                c = *lp++;
                                if (c <= ' ')
@@ -344,8 +341,14 @@ fgoto()
                if (AM == 0) {
                        while (l > 0) {
                                if (pfast)
                if (AM == 0) {
                        while (l > 0) {
                                if (pfast)
-                                       putch('\r');
-                               putch('\n');
+                                       if (xCR)
+                                               tputs(xCR, 0, putch);
+                                       else
+                                               putch('\r');
+                               if (xNL)
+                                       tputs(xNL, 0, putch);
+                               else
+                                       putch('\n');
                                l--;
                        }
                        outcol = 0;
                                l--;
                        }
                        outcol = 0;
@@ -366,7 +369,28 @@ fgoto()
                        destcol = c;
                }
                while (l > LINES - 1) {
                        destcol = c;
                }
                while (l > LINES - 1) {
-                       putch('\n');
+                       /*
+                        * The following linefeed (or simulation thereof)
+                        * is supposed to scroll up the screen, since we
+                        * are on the bottom line.  We make the assumption
+                        * that linefeed will scroll.  If ns is in the
+                        * capability list this won't work.  We should
+                        * probably have an sc capability but sf will
+                        * generally take the place if it works.
+                        *
+                        * Superbee glitch:  in the middle of the screen we
+                        * have to use esc B (down) because linefeed screws up
+                        * in "Efficient Paging" (what a joke) mode (which is
+                        * essential in some SB's because CRLF mode puts garbage
+                        * in at end of memory), but you must use linefeed to
+                        * scroll since down arrow won't go past memory end.
+                        * I turned this off after recieving Paul Eggert's
+                        * Superbee description which wins better.
+                        */
+                       if (xNL /* && !XB */ && pfast)
+                               tputs(xNL, 0, putch);
+                       else
+                               putch('\n');
                        l--;
                        if (pfast == 0)
                                outcol = 0;
                        l--;
                        if (pfast == 0)
                                outcol = 0;
@@ -423,40 +447,74 @@ plod(cnt)
        plodcnt = plodflg = cnt;
        soutcol = outcol;
        soutline = outline;
        plodcnt = plodflg = cnt;
        soutcol = outcol;
        soutline = outline;
+       /*
+        * Consider homing and moving down/right from there, vs moving
+        * directly with local motions to the right spot.
+        */
        if (HO) {
        if (HO) {
+               /*
+                * i is the cost to home and tab/space to the right to
+                * get to the proper column.  This assumes ND space costs
+                * 1 char.  So i+destcol is cost of motion with home.
+                */
                if (GT)
                if (GT)
-               i = (destcol / value(HARDTABS)) + (destcol % value(HARDTABS));
+                       i = (destcol / value(HARDTABS)) + (destcol % value(HARDTABS));
                else
                        i = destcol;
                else
                        i = destcol;
-       if (destcol >= outcol) {
-               j = destcol / value(HARDTABS) - outcol / value(HARDTABS);
-               if (GT && j)
-                       j += destcol % value(HARDTABS);
+               /*
+                * j is cost to move locally without homing
+                */
+               if (destcol >= outcol) {        /* if motion is to the right */
+                       j = destcol / value(HARDTABS) - outcol / value(HARDTABS);
+                       if (GT && j)
+                               j += destcol % value(HARDTABS);
                        else
                                j = destcol - outcol;
                        else
                                j = destcol - outcol;
-       } else
+               } else
+                       /* leftward motion only works if we can backspace. */
                        if (outcol - destcol <= i && (BS || BC))
                        if (outcol - destcol <= i && (BS || BC))
-                               i = j = outcol - destcol;
+                               i = j = outcol - destcol; /* cheaper to backspace */
                        else
                        else
-                               j = i + 1;
+                               j = i + 1; /* impossibly expensive */
+
+               /* k is the absolute value of vertical distance */
                k = outline - destline;
                if (k < 0)
                        k = -k;
                j += k;
                k = outline - destline;
                if (k < 0)
                        k = -k;
                j += k;
-               if (i + destline < j) {
+
+               /*
+                * Decision.  We may not have a choice if no UP.
+                */
+               if (i + destline < j || (!UP && destline < outline)) {
+                       /*
+                        * Cheaper to home.  Do it now and pretend it's a
+                        * regular local motion.
+                        */
                        tputs(HO, 0, plodput);
                        outcol = outline = 0;
                } else if (LL) {
                        tputs(HO, 0, plodput);
                        outcol = outline = 0;
                } else if (LL) {
+                       /*
+                        * Quickly consider homing down and moving from there.
+                        * Assume cost of LL is 2.
+                        */
                        k = (LINES - 1) - destline;
                        k = (LINES - 1) - destline;
-                       if (i + k + 2 < j) {
+                       if (i + k + 2 < j && (k<=0 || UP)) {
                                tputs(LL, 0, plodput);
                                outcol = 0;
                                outline = LINES - 1;
                        }
                }
                                tputs(LL, 0, plodput);
                                outcol = 0;
                                outline = LINES - 1;
                        }
                }
-       }
+       } else
+       /*
+        * No home and no up means it's impossible, so we return an
+        * incredibly big number to make cursor motion win out.
+        */
+               if (!UP && destline < outline)
+                       return (500);
        if (GT)
        if (GT)
-       i = destcol % value(HARDTABS) + destcol / value(HARDTABS);
+               i = destcol % value(HARDTABS)
+                   + destcol / value(HARDTABS);
        else
                i = destcol;
 /*
        else
                i = destcol;
 /*
@@ -486,64 +544,111 @@ plod(cnt)
         * a return preliminarily.
         */
        if (j > i + 1 || outcol > destcol && !BS && !BC) {
         * a return preliminarily.
         */
        if (j > i + 1 || outcol > destcol && !BS && !BC) {
-               plodput('\r');
+               /*
+                * BUG: this doesn't take the (possibly long) length
+                * of xCR into account.
+                */
+               if (xCR)
+                       tputs(xCR, 0, plodput);
+               else
+                       plodput('\r');
                if (NC) {
                if (NC) {
-                       plodput('\n');
+                       if (xNL)
+                               tputs(xNL, 0, plodput);
+                       else
+                               plodput('\n');
                        outline++;
                }
                outcol = 0;
        }
 dontcr:
                        outline++;
                }
                outcol = 0;
        }
 dontcr:
+       /* Move down, if necessary, until we are at the desired line */
        while (outline < destline) {
        while (outline < destline) {
-               outline++;
-               plodput('\n');
+               j = destline - outline;
+               if (j > costDP && DOWN_PARM) {
+                       /* Win big on Tek 4025 */
+                       tputs(tgoto(DOWN_PARM, 0, j), j, plodput);
+                       outline += j;
+               }
+               else {
+                       outline++;
+                       if (xNL && pfast)
+                               tputs(xNL, 0, plodput);
+                       else
+                               plodput('\n');
+               }
                if (plodcnt < 0)
                        goto out;
                if (NONL || pfast == 0)
                        outcol = 0;
        }
        if (BT)
                if (plodcnt < 0)
                        goto out;
                if (NONL || pfast == 0)
                        outcol = 0;
        }
        if (BT)
-               k = strlen(BT);
+               k = strlen(BT); /* should probably be cost(BT) and moved out */
+       /* Move left, if necessary, to desired column */
        while (outcol > destcol) {
                if (plodcnt < 0)
                        goto out;
        while (outcol > destcol) {
                if (plodcnt < 0)
                        goto out;
-/*
                if (BT && !insmode && outcol - destcol > 4+k) {
                        tputs(BT, 0, plodput);
                        outcol--;
                if (BT && !insmode && outcol - destcol > 4+k) {
                        tputs(BT, 0, plodput);
                        outcol--;
-                       outcol &= ~7;
+                       outcol -= outcol % value(HARDTABS); /* outcol &= ~7; */
                        continue;
                }
                        continue;
                }
-*/
-               outcol--;
-               if (BC)
-                       tputs(BC, 0, plodput);
-               else
-                       plodput('\b');
+               j = outcol - destcol;
+               if (j > costLP && LEFT_PARM) {
+                       tputs(tgoto(LEFT_PARM, 0, j), j, plodput);
+                       outcol -= j;
+               }
+               else {
+                       outcol--;
+                       if (BC)
+                               tputs(BC, 0, plodput);
+                       else
+                               plodput('\b');
+               }
        }
        }
+       /* Move up, if necessary, to desired row */
        while (outline > destline) {
        while (outline > destline) {
-               outline--;
-               tputs(UP, 0, plodput);
+               j = outline - destline;
+               if (UP_PARM && j > 1) {
+                       /* Win big on Tek 4025 */
+                       tputs(tgoto(UP_PARM, 0, j), j, plodput);
+                       outline -= j;
+               }
+               else {
+                       outline--;
+                       tputs(UP, 0, plodput);
+               }
                if (plodcnt < 0)
                        goto out;
        }
                if (plodcnt < 0)
                        goto out;
        }
+       /*
+        * Now move to the right, if necessary.  We first tab to
+        * as close as we can get.
+        */
        if (GT && !insmode && destcol - outcol > 1) {
        if (GT && !insmode && destcol - outcol > 1) {
-       for (;;) {
-               i = (outcol / value(HARDTABS) + 1) * value(HARDTABS);
-               if (i > destcol)
-                       break;
+               /* tab to right as far as possible without passing col */
+               for (;;) {
+                       i = tabcol(outcol, value(HARDTABS));
+                       if (i > destcol)
+                               break;
                        if (TA)
                                tputs(TA, 0, plodput);
                        else
                                plodput('\t');
                        outcol = i;
                }
                        if (TA)
                                tputs(TA, 0, plodput);
                        else
                                plodput('\t');
                        outcol = i;
                }
+               /* consider another tab and then some backspaces */
                if (destcol - outcol > 4 && i < COLUMNS && (BC || BS)) {
                        if (TA)
                                tputs(TA, 0, plodput);
                        else
                                plodput('\t');
                        outcol = i;
                if (destcol - outcol > 4 && i < COLUMNS && (BC || BS)) {
                        if (TA)
                                tputs(TA, 0, plodput);
                        else
                                plodput('\t');
                        outcol = i;
+                       /*
+                        * Back up.  Don't worry about LEFT_PARM because
+                        * it's never more than 4 spaces anyway.
+                        */
                        while (outcol > destcol) {
                                outcol--;
                                if (BC)
                        while (outcol > destcol) {
                                outcol--;
                                if (BC)
@@ -553,27 +658,43 @@ dontcr:
                        }
                }
        }
                        }
                }
        }
+       /*
+        * We've tabbed as much as possible.  If we still need to go
+        * further (not exact or can't tab) space over.  This is a
+        * very common case when moving to the right with space.
+        */
        while (outcol < destcol) {
        while (outcol < destcol) {
-               /*
-                * move one char to the right.  We don't use ND space
-                * because it's better to just print the char we are
-                * moving over.  There are various exceptions, however.
-                * If !inopen, vtube contains garbage.  If the char is
-                * a null or a tab we want to print a space.  Other random
-                * chars we use space for instead, too.
-                */
-#ifdef TRACE
-               if (trace)
-                       fprintf(trace, "ND: inopen=%d, i=%d, outline=%d, outcol=%d\n", inopen, i, outline, outcol);
-#endif
-               if (!inopen || vtube[outline]==NULL ||
-                       (i=vtube[outline][outcol]) < ' ')
-                       i = ' ';
-               if (insmode && ND)
-                       tputs(ND, 0, plodput);
-               else
-                       plodput(i);
-               outcol++;
+               j = destcol - outcol;
+               if (j > costRP && RIGHT_PARM) {
+                       /*
+                        * This probably happens rarely, if at all.
+                        * It seems mainly useful for ANSI terminals
+                        * with no hardware tabs, and I don't know
+                        * of any such terminal at the moment.
+                        */
+                       tputs(tgoto(RIGHT_PARM, 0, j), j, plodput);
+                       outcol += j;
+               }
+               else {
+                       /*
+                        * move one char to the right.  We don't use ND space
+                        * because it's better to just print the char we are
+                        * moving over.  There are various exceptions, however.
+                        * If !inopen, vtube contains garbage.  If the char is
+                        * a null or a tab we want to print a space.  Other
+                        * random chars we use space for instead, too.
+                        */
+                       if (!inopen || vtube[outline]==NULL ||
+                               (i=vtube[outline][outcol]) < ' ')
+                               i = ' ';
+                       if(i & QUOTE)   /* mjm: no sign extension on 3B */
+                               i = ' ';
+                       if (insmode && ND)
+                               tputs(ND, 0, plodput);
+                       else
+                               plodput(i);
+                       outcol++;
+               }
                if (plodcnt < 0)
                        goto out;
        }
                if (plodcnt < 0)
                        goto out;
        }
@@ -668,7 +789,11 @@ putch(c)
        int c;
 {
 
        int c;
 {
 
-       *obp++ = c;
+#ifdef OLD3BTTY                /* mjm */
+       if(c == '\n')   /* mjm: Fake "\n\r" for '\n' til fix in 3B firmware */
+               putch('\r');    /* mjm: vi does "stty -icanon" => -onlcr !! */
+#endif
+       *obp++ = c & 0177;
        if (obp >= &obuf[sizeof obuf])
                flusho();
 }
        if (obp >= &obuf[sizeof obuf])
                flusho();
 }
@@ -677,16 +802,6 @@ putch(c)
  * Miscellaneous routines related to output.
  */
 
  * Miscellaneous routines related to output.
  */
 
-/*
- * Cursor motion.
- */
-char *
-cgoto()
-{
-
-       return (tgoto(CM, destcol, destline));
-}
-
 /*
  * Put with padding
  */
 /*
  * Put with padding
  */
@@ -747,7 +862,13 @@ pstart()
        flusho();
        pfast = 1;
        normtty++;
        flusho();
        pfast = 1;
        normtty++;
+#ifndef USG3TTY
        tty.sg_flags = normf & ~(ECHO|XTABS|CRMOD);
        tty.sg_flags = normf & ~(ECHO|XTABS|CRMOD);
+#else
+       tty = normf;
+       tty.c_oflag &= ~(ONLCR|TAB3);
+       tty.c_lflag &= ~ECHO;
+#endif
        sTTY(1);
 }
 
        sTTY(1);
 }
 
@@ -769,42 +890,141 @@ pstop()
 /*
  * Prep tty for open mode.
  */
 /*
  * Prep tty for open mode.
  */
+ttymode
 ostart()
 {
 ostart()
 {
-       int f;
+       ttymode f;
 
        if (!intty)
                error("Open and visual must be used interactively");
        gTTY(1);
        normtty++;
 
        if (!intty)
                error("Open and visual must be used interactively");
        gTTY(1);
        normtty++;
+#ifndef USG3TTY
        f = tty.sg_flags;
        f = tty.sg_flags;
-#ifdef CBREAK
-       tty.sg_flags = (normf &~ (ECHO|XTABS|CRMOD)) | CBREAK;
+       tty.sg_flags = (normf &~ (ECHO|XTABS|CRMOD)) |
+# ifdef CBREAK
+                                                       CBREAK;
+# else
+                                                       RAW;
+# endif
+# ifdef TIOCGETC
+       ttcharoff();
+# endif
 #else
 #else
-       tty.sg_flags = (normf &~ (ECHO|XTABS|CRMOD)) | RAW;
-#endif
-#ifdef EATQS
-       nttyc.t_quitc = nttyc.t_startc = nttyc.t_stopc = '\377';
+       f = tty;
+       tty = normf;
+       tty.c_iflag &= ~ICRNL;
+       tty.c_lflag &= ~(ECHO|ICANON);
+       tty.c_oflag &= ~(TAB3|ONLCR);
+       tty.c_cc[VMIN] = 1;
+       tty.c_cc[VTIME] = 1;
+       ttcharoff();
 #endif
        sTTY(1);
 #endif
        sTTY(1);
-       putpad(VS);
-       putpad(KS);
+       tostart();
        pfast |= 2;
        return (f);
 }
 
        pfast |= 2;
        return (f);
 }
 
+/* actions associated with putting the terminal in open mode */
+tostart()
+{
+       putpad(VS);
+       putpad(KS);
+       if (!value(MESG)) {
+               if (ttynbuf[0] == 0) {
+                       register char *tn;
+                       if ((tn=ttyname(2)) == NULL &&
+                           (tn=ttyname(1)) == NULL &&
+                           (tn=ttyname(0)) == NULL)
+                               ttynbuf[0] = 1;
+                       else
+                               strcpy(ttynbuf, tn);
+               }
+               if (ttynbuf[0] != 1) {
+                       struct stat sbuf;
+                       stat(ttynbuf, &sbuf);
+                       ttymesg = sbuf.st_mode & 0777;
+                       chmod(ttynbuf,
+#ifdef UCBV7
+       /*
+        * This applies to the UCB V7 Pdp-11 system with the
+        * -u write option only.
+        */
+                                       0611    /* 11 = urgent only allowed */
+#else
+                                       0600
+#endif
+                                               );
+               }
+       }
+}
+
+/*
+ * Turn off start/stop chars if they aren't the default ^S/^Q.
+ * This is so idiots who make esc their start/stop don't lose.
+ * We always turn off quit since datamedias send ^\ for their
+ * right arrow key.
+ */
+#ifdef TIOCGETC
+ttcharoff()
+{
+       nttyc.t_quitc = '\377';
+       if (nttyc.t_startc != CTRL(q))
+               nttyc.t_startc = '\377';
+       if (nttyc.t_stopc != CTRL(s))
+               nttyc.t_stopc = '\377';
+# ifdef TIOCLGET
+       nlttyc.t_suspc = '\377';        /* ^Z */
+       nlttyc.t_dsuspc = '\377';       /* ^Y */
+       nlttyc.t_flushc = '\377';       /* ^O */
+       nlttyc.t_lnextc = '\377';       /* ^V */
+# endif
+}
+#endif
+
+#ifdef USG3TTY
+ttcharoff()
+{
+       tty.c_cc[VQUIT] = '\377';
+# ifdef VSTART
+       /*
+        * The following is sample code if USG ever lets people change
+        * their start/stop chars.  As long as they can't we can't get
+        * into trouble so we just leave them alone.
+        */
+       if (tty.c_cc[VSTART] != CTRL(q))
+               tty.c_cc[VSTART] = '\377';
+       if (tty.c_cc[VSTOP] != CTRL(s))
+               tty.c_cc[VSTOP] = '\377';
+# endif
+}
+#endif
+
 /*
  * Stop open, restoring tty modes.
  */
 ostop(f)
 /*
  * Stop open, restoring tty modes.
  */
 ostop(f)
-       int f;
+       ttymode f;
 {
 
 {
 
+#ifndef USG3TTY
        pfast = (f & CRMOD) == 0;
        pfast = (f & CRMOD) == 0;
+#else
+       pfast = (f.c_oflag & ONLCR) == 0;
+#endif
        termreset(), fgoto(), flusho();
        normal(f);
        termreset(), fgoto(), flusho();
        normal(f);
+       tostop();
+}
+
+/* Actions associated with putting the terminal in the right mode. */
+tostop()
+{
        putpad(VE);
        putpad(KE);
        putpad(VE);
        putpad(KE);
+       if (!value(MESG) && ttynbuf[0]>1)
+               chmod(ttynbuf, ttymesg);
 }
 
 #ifndef CBREAK
 }
 
 #ifndef CBREAK
@@ -833,7 +1053,7 @@ vraw()
  * Restore flags to normal state f.
  */
 normal(f)
  * Restore flags to normal state f.
  */
 normal(f)
-       int f;
+       ttymode f;
 {
 
        if (normtty > 0) {
 {
 
        if (normtty > 0) {
@@ -845,18 +1065,31 @@ normal(f)
 /*
  * Straight set of flags to state f.
  */
 /*
  * Straight set of flags to state f.
  */
+ttymode
 setty(f)
 setty(f)
-       int f;
+       ttymode f;
 {
 {
+#ifndef USG3TTY
        register int ot = tty.sg_flags;
        register int ot = tty.sg_flags;
+#else
+       ttymode ot;
+       ot = tty;
+#endif
 
 
-#ifdef EATQS
-       if (f == normf)
+#ifndef USG3TTY
+       if (f == normf) {
                nttyc = ottyc;
                nttyc = ottyc;
-       else
-               nttyc.t_quitc = nttyc.t_startc = nttyc.t_stopc = '\377';
-#endif
+# ifdef TIOCLGET
+               nlttyc = olttyc;
+# endif
+       } else
+               ttcharoff();
        tty.sg_flags = f;
        tty.sg_flags = f;
+#else
+       if (tty.c_lflag & ICANON)
+               ttcharoff();
+       tty = f;
+#endif
        sTTY(1);
        return (ot);
 }
        sTTY(1);
        return (ot);
 }
@@ -865,31 +1098,55 @@ gTTY(i)
        int i;
 {
 
        int i;
 {
 
+#ifndef USG3TTY
        ignore(gtty(i, &tty));
        ignore(gtty(i, &tty));
-#ifdef EATQS
+# ifdef TIOCGETC
        ioctl(i, TIOCGETC, &ottyc);
        nttyc = ottyc;
        ioctl(i, TIOCGETC, &ottyc);
        nttyc = ottyc;
+# endif
+# ifdef TIOCGLTC
+       ioctl(i, TIOCGLTC, &olttyc);
+       nlttyc = olttyc;
+# endif
+#else
+       ioctl(i, TCGETA, &tty);
 #endif
 }
 
 #endif
 }
 
+/*
+ * sTTY: set the tty modes on file descriptor i to be what's
+ * currently in global "tty".  (Also use nttyc if needed.)
+ */
 sTTY(i)
        int i;
 {
 
 sTTY(i)
        int i;
 {
 
-/*
- * Bug in USG tty driver, put out a null char as a patch.
- */
-#ifdef USG
-       if (tty.sg_ospeed == B1200)
-               write(1, "", 1);
-#endif
-#ifdef TIOCSETN
+#ifndef USG3TTY
+# ifdef USG
+       /* Bug in USG tty driver, put out a DEL as a patch. */
+       if (tty.sg_ospeed >= B1200)
+               write(1, "\377", 1);
+# endif
+
+# ifdef TIOCSETN
+       /* Don't flush typeahead if we don't have to */
        ioctl(i, TIOCSETN, &tty);
        ioctl(i, TIOCSETN, &tty);
-#else
+# else
+       /* We have to.  Too bad. */
        stty(i, &tty);
        stty(i, &tty);
-#endif
-#ifdef EATQS
+# endif
+
+# ifdef TIOCGETC
+       /* Update the other random chars while we're at it. */
        ioctl(i, TIOCSETC, &nttyc);
        ioctl(i, TIOCSETC, &nttyc);
+# endif
+# ifdef TIOCSLTC
+       ioctl(i, TIOCSLTC, &nlttyc);
+# endif
+
+#else
+       /* USG 3 very simple: just set everything */
+       ioctl(i, TCSETAW, &tty);
 #endif
 }
 
 #endif
 }