BSD 4 release
[unix-history] / usr / src / cmd / ex / ex_put.c
index c184d88..4ca6902 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_put.c    6.3 11/3/80";
 #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];
+static 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.
@@ -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,9 +544,19 @@ 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;
                        outline++;
                }
                outcol = 0;
@@ -496,7 +564,10 @@ plod(cnt)
 dontcr:
        while (outline < destline) {
                outline++;
 dontcr:
        while (outline < destline) {
                outline++;
-               plodput('\n');
+               if (xNL && pfast)
+                       tputs(xNL, 0, plodput);
+               else
+                       plodput('\n');
                if (plodcnt < 0)
                        goto out;
                if (NONL || pfast == 0)
                if (plodcnt < 0)
                        goto out;
                if (NONL || pfast == 0)
@@ -529,7 +600,7 @@ dontcr:
        }
        if (GT && !insmode && destcol - outcol > 1) {
        for (;;) {
        }
        if (GT && !insmode && destcol - outcol > 1) {
        for (;;) {
-               i = (outcol / value(HARDTABS) + 1) * value(HARDTABS);
+               i = tabcol(outcol, value(HARDTABS));
                if (i > destcol)
                        break;
                        if (TA)
                if (i > destcol)
                        break;
                        if (TA)
@@ -554,10 +625,21 @@ dontcr:
                }
        }
        while (outcol < destcol) {
                }
        }
        while (outcol < destcol) {
-               if (inopen && ND)
+               /*
+                * 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 (insmode && ND)
                        tputs(ND, 0, plodput);
                else
                        tputs(ND, 0, plodput);
                else
-                       plodput(' ');
+                       plodput(i);
                outcol++;
                if (plodcnt < 0)
                        goto out;
                outcol++;
                if (plodcnt < 0)
                        goto out;
@@ -653,7 +735,7 @@ putch(c)
        int c;
 {
 
        int c;
 {
 
-       *obp++ = c;
+       *obp++ = c & 0177;
        if (obp >= &obuf[sizeof obuf])
                flusho();
 }
        if (obp >= &obuf[sizeof obuf])
                flusho();
 }
@@ -662,16 +744,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
  */
@@ -732,7 +804,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);
 }
 
@@ -754,42 +832,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 TIOCGETC
-       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;
+       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 & OCRNL) == 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))
+               chmod(ttynbuf, ttymesg);
 }
 
 #ifndef CBREAK
 }
 
 #ifndef CBREAK
@@ -818,7 +995,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) {
@@ -830,18 +1007,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 TIOCGETC
-       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);
 }
@@ -850,31 +1040,55 @@ gTTY(i)
        int i;
 {
 
        int i;
 {
 
+#ifndef USG3TTY
        ignore(gtty(i, &tty));
        ignore(gtty(i, &tty));
-#ifdef TIOCGETC
+# 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 TIOCSETC
+# 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
 }
 
@@ -886,3 +1100,39 @@ noonl()
 
        putchar(Outchar != termchar ? ' ' : '\n');
 }
 
        putchar(Outchar != termchar ? ' ' : '\n');
 }
+
+#ifdef SIGTSTP
+/*
+ * We have just gotten a susp.  Suspend and prepare to resume.
+ */
+onsusp()
+{
+       ttymode f;
+
+       f = setty(normf);
+       vnfl();
+       putpad(TE);
+       flush();
+
+       signal(SIGTSTP, SIG_DFL);
+       kill(0, SIGTSTP);
+
+       /* the pc stops here */
+
+       signal(SIGTSTP, onsusp);
+       vcontin(0);
+       setty(f);
+       if (!inopen)
+               error(0);
+       else {
+               if (vcnt < 0) {
+                       vcnt = -vcnt;
+                       if (state == VISUAL)
+                               vclear();
+                       else if (state == CRTOPEN)
+                               vcnt = 0;
+               }
+               vdirty(0, LINES);
+               vrepaint(cursor);
+       }
+}