home *** CD-ROM | disk | FTP | other *** search
/ minnie.tuhs.org / unixen.tar / unixen / PDP-11 / Distributions / ucb / spencer_2bsd.tar.gz / 2bsd.tar / src / ex / ex_put.c < prev    next >
C/C++ Source or Header  |  1980-02-17  |  13KB  |  831 lines

  1. /* Copyright (c) 1979 Regents of the University of California */
  2. #include "ex.h"
  3. #include "ex_tty.h"
  4.  
  5. /*
  6.  * Terminal driving and line formatting routines.
  7.  * Basic motion optimizations are done here as well
  8.  * as formatting of lines (printing of control characters,
  9.  * line numbering and the like).
  10.  */
  11.  
  12. /*
  13.  * The routines outchar, putchar and pline are actually
  14.  * variables, and these variables point at the current definitions
  15.  * of the routines.  See the routine setflav.
  16.  * We sometimes make outchar be routines which catch the characters
  17.  * to be printed, e.g. if we want to see how long a line is.
  18.  * During open/visual, outchar and putchar will be set to
  19.  * routines in the file ex_vput.c (vputchar, vinschar, etc.).
  20.  */
  21. int    (*Outchar)() = termchar;
  22. int    (*Putchar)() = normchar;
  23. int    (*Pline)() = normline;
  24.  
  25. int (*
  26. setlist(t))()
  27.     bool t;
  28. {
  29.     register int (*P)();
  30.  
  31.     listf = t;
  32.     P = Putchar;
  33.     Putchar = t ? listchar : normchar;
  34.     return (P);
  35. }
  36.  
  37. int (*
  38. setnumb(t))()
  39.     bool t;
  40. {
  41.     register int (*P)();
  42.  
  43.     numberf = t;
  44.     P = Pline;
  45.     Pline = t ? numbline : normline;
  46.     return (P);
  47. }
  48.  
  49. /*
  50.  * Format c for list mode; leave things in common
  51.  * with normal print mode to be done by normchar.
  52.  */
  53. listchar(c)
  54.     register short c;
  55. {
  56.  
  57.     c &= (TRIM|QUOTE);
  58.     switch (c) {
  59.  
  60.     case '\t':
  61.     case '\b':
  62.         outchar('^');
  63.         c = ctlof(c);
  64.         break;
  65.  
  66.     case '\n':
  67.         break;
  68.  
  69.     case '\n' | QUOTE:
  70.         outchar('$');
  71.         break;
  72.  
  73.     default:
  74.         if (c & QUOTE)
  75.             break;
  76.         if (c < ' ' && c != '\n' || c == DELETE)
  77.             outchar('^'), c = ctlof(c);
  78.         break;
  79.     }
  80.     normchar(c);
  81. }
  82.  
  83. /*
  84.  * Format c for printing.  Handle funnies of upper case terminals
  85.  * and crocky hazeltines which don't have ~.
  86.  */
  87. normchar(c)
  88.     register short c;
  89. {
  90.     register char *colp;
  91.  
  92.     c &= (TRIM|QUOTE);
  93.     if (c == '~' && HZ) {
  94.         normchar('\\');
  95.         c = '^';
  96.     }
  97.     if (c & QUOTE)
  98.         switch (c) {
  99.  
  100.         case ' ' | QUOTE:
  101.         case '\b' | QUOTE:
  102.             break;
  103.  
  104.         case QUOTE:
  105.             return;
  106.  
  107.         default:
  108.             c &= TRIM;
  109.         }
  110.     else if (c < ' ' && (c != '\b' || !OS) && c != '\n' && c != '\t' || c == DELETE)
  111.         putchar('^'), c = ctlof(c);
  112.     else if (UPPERCASE)
  113.         if (isupper(c)) {
  114.             outchar('\\');
  115.             c = tolower(c);
  116.         } else {
  117.             colp = "({)}!|^~'`";
  118.             while (*colp++)
  119.                 if (c == *colp++) {
  120.                     outchar('\\');
  121.                     c = colp[-2];
  122.                     break;
  123.                 }
  124.         }
  125.     outchar(c);
  126. }
  127.  
  128. /*
  129.  * Print a line with a number.
  130.  */
  131. numbline(i)
  132.     int i;
  133. {
  134.  
  135.     if (shudclob)
  136.         slobber(' ');
  137.     printf("%6d  ", i);
  138.     normline();
  139. }
  140.  
  141. /*
  142.  * Normal line output, no numbering.
  143.  */
  144. normline()
  145. {
  146.     register char *cp;
  147.  
  148.     if (shudclob)
  149.         slobber(linebuf[0]);
  150.     /* pdp-11 doprnt is not reentrant so can't use "printf" here
  151.        in case we are tracing */
  152.     for (cp = linebuf; *cp;)
  153.         putchar(*cp++);
  154.     if (!inopen)
  155.         putchar('\n' | QUOTE);
  156. }
  157.  
  158. /*
  159.  * Given c at the beginning of a line, determine whether
  160.  * the printing of the line will erase or otherwise obliterate
  161.  * the prompt which was printed before.  If it won't, do it now.
  162.  */
  163. slobber(c)
  164.     int c;
  165. {
  166.  
  167.     shudclob = 0;
  168.     switch (c) {
  169.  
  170.     case '\t':
  171.         if (Putchar == listchar)
  172.             return;
  173.         break;
  174.  
  175.     default:
  176.         return;
  177.  
  178.     case ' ':
  179.     case 0:
  180.         break;
  181.     }
  182.     if (OS)
  183.         return;
  184.     flush();
  185.     putch(' ');
  186.     if (BC)
  187.         tputs(BC, 0, putch);
  188.     else
  189.         putch('\b');
  190. }
  191.  
  192. /*
  193.  * The output buffer is initialized with a useful error
  194.  * message so we don't have to keep it in data space.
  195.  */
  196. static    char linb[66] = {
  197.     'E', 'r', 'r', 'o', 'r', ' ', 'm', 'e', 's', 's', 'a', 'g', 'e', ' ',
  198.     'f', 'i', 'l', 'e', ' ', 'n', 'o', 't', ' ',
  199.     'a', 'v', 'a', 'i', 'l', 'a', 'b', 'l', 'e', '\n', 0
  200. };
  201. static    char *linp = linb + 33;
  202.  
  203. /*
  204.  * Phadnl records when we have already had a complete line ending with \n.
  205.  * If another line starts without a flush, and the terminal suggests it,
  206.  * we switch into -nl mode so that we can send lineffeeds to avoid
  207.  * a lot of spacing.
  208.  */
  209. static    bool phadnl;
  210.  
  211. /*
  212.  * Indirect to current definition of putchar.
  213.  */
  214. putchar(c)
  215.     int c;
  216. {
  217.  
  218.     (*Putchar)(c);
  219. }
  220.  
  221. /*
  222.  * Termchar routine for command mode.
  223.  * Watch for possible switching to -nl mode.
  224.  * Otherwise flush into next level of buffering when
  225.  * small buffer fills or at a newline.
  226.  */
  227. termchar(c)
  228.     int c;
  229. {
  230.  
  231.     if (pfast == 0 && phadnl)
  232.         pstart();
  233.     if (c == '\n')
  234.         phadnl = 1;
  235.     else if (linp >= &linb[63])
  236.         flush1();
  237.     *linp++ = c;
  238.     if (linp >= &linb[63]) {
  239.         fgoto();
  240.         flush1();
  241.     }
  242. }
  243.  
  244. flush()
  245. {
  246.  
  247.     flush1();
  248.     flush2();
  249. }
  250.  
  251. /*
  252.  * Flush from small line buffer into output buffer.
  253.  * Work here is destroying motion into positions, and then
  254.  * letting fgoto do the optimized motion.
  255.  */
  256. flush1()
  257. {
  258.     register char *lp;
  259.     register short c;
  260.  
  261.     *linp = 0;
  262.     lp = linb;
  263.     while (*lp)
  264.         switch (c = *lp++) {
  265.  
  266.         case '\r':
  267.             destline += destcol / COLUMNS;
  268.             destcol = 0;
  269.             continue;
  270.  
  271.         case '\b':
  272.             if (destcol)
  273.                 destcol--;
  274.             continue;
  275.  
  276.         case ' ':
  277.             destcol++;
  278.             continue;
  279.  
  280.         case '\t':
  281.             destcol += value(TABSTOP) - destcol % value(TABSTOP);
  282.             continue;
  283.  
  284.         case '\n':
  285.             destline += destcol / COLUMNS + 1;
  286.             if (destcol != 0 && destcol % COLUMNS == 0)
  287.                 destline--;
  288.             destcol = 0;
  289.             continue;
  290.  
  291.         default:
  292.             fgoto();
  293.             for (;;) {
  294.                 if (AM == 0 && outcol == COLUMNS)
  295.                     fgoto();
  296.                 c &= TRIM;
  297.                 putch(c);
  298.                 if (c == '\b') {
  299.                     outcol--;
  300.                     destcol--;
  301.                 } else if (c >= ' ' && c != DELETE) {
  302.                     outcol++;
  303.                     destcol++;
  304.                     if (XN && outcol % COLUMNS == 0)
  305.                         putch('\n');
  306.                 }
  307.                 c = *lp++;
  308.                 if (c <= ' ')
  309.                     break;
  310.             }
  311.             --lp;
  312.             continue;
  313.         }
  314.     linp = linb;
  315. }
  316.  
  317. flush2()
  318. {
  319.  
  320.     fgoto();
  321.     flusho();
  322.     pstop();
  323. }
  324.  
  325. /*
  326.  * Sync the position of the output cursor.
  327.  * Most work here is rounding for terminal boundaries getting the
  328.  * column position implied by wraparound or the lack thereof and
  329.  * rolling up the screen to get destline on the screen.
  330.  */
  331. fgoto()
  332. {
  333.     register int l, c;
  334.  
  335.     if (destcol > COLUMNS - 1) {
  336.         destline += destcol / COLUMNS;
  337.         destcol %= COLUMNS;
  338.     }
  339.     if (outcol > COLUMNS - 1) {
  340.         l = (outcol + 1) / COLUMNS;
  341.         outline += l;
  342.         outcol %= COLUMNS;
  343.         if (AM == 0) {
  344.             while (l > 0) {
  345.                 if (pfast)
  346.                     putch('\r');
  347.                 putch('\n');
  348.                 l--;
  349.             }
  350.             outcol = 0;
  351.         }
  352.         if (outline > LINES - 1) {
  353.             destline -= outline - (LINES - 1);
  354.             outline = LINES - 1;
  355.         }
  356.     }
  357.     if (destline > LINES - 1) {
  358.         l = destline;
  359.         destline = LINES - 1;
  360.         if (outline < LINES - 1) {
  361.             c = destcol;
  362.             if (pfast == 0 && (!CA || holdcm))
  363.                 destcol = 0;
  364.             fgoto();
  365.             destcol = c;
  366.         }
  367.         while (l > LINES - 1) {
  368.             putch('\n');
  369.             l--;
  370.             if (pfast == 0)
  371.                 outcol = 0;
  372.         }
  373.     }
  374.     if (destline < outline && !(CA && !holdcm || UP != NOSTR))
  375.         destline = outline;
  376.     if (motion())
  377.         return;
  378.     if (CA && !holdcm) {
  379.         tputs(cgoto(), 0, putch);
  380.         outline = destline;
  381.         outcol = destcol;
  382.     } else
  383.         plod();
  384. }
  385.  
  386. /*
  387.  * Tab to column col by flushing and then setting destcol.
  388.  * Used by "set all".
  389.  */
  390. tab(col)
  391.     int col;
  392. {
  393.  
  394.     flush1();
  395.     destcol = col;
  396. }
  397.  
  398. /*
  399.  * Routine to decide how to do a basic motion,
  400.  * choosing between local motions and cursor addressing.
  401.  */ 
  402. motion()
  403. {
  404.     register int v, h;
  405.     /*
  406.      * V is vertical distance, then cost with cr.
  407.      * H is horizontal distance, then direct move cost.
  408.      */
  409.  
  410.     if (!BS)
  411.         return (0);
  412.     v = destline - outline;
  413.     if (v < 0)
  414.         if (CA && !holdcm || UP) {
  415.             if (!UP)
  416.                 return (0);
  417.             v = -v;
  418.         } else
  419.             destline = outline;
  420.     h = destcol;
  421.     if (!v || pfast) {
  422.         h -= outcol;
  423.         if (h < 0)
  424.             h = -h;
  425.     }
  426.     h += v;
  427.     if (pfast || !NONL) {
  428.         if (outcol)
  429.             v++;
  430.         v += destcol;
  431.     } else
  432.         v = 5;
  433.     if (v >= 4 && h >= 4)
  434.         return (0);
  435.     plod();
  436.     return (1);
  437. }
  438.  
  439. /*
  440.  * Move (slowly) to destination.
  441.  * Hard thing here is using home cursor on really deficient terminals.
  442.  * Otherwise just use cursor motions, hacking use of tabs and overtabbing
  443.  * and backspace.
  444.  */
  445. plod()
  446. {
  447.     register int i, j, k;
  448.  
  449.     if (HO && (!CA || holdcm)) {
  450.         if (GT)
  451.             i = (destcol >> 3) + (destcol & 07);
  452.         else
  453.             i = destcol;
  454.         if (destcol >= outcol)
  455.             if (GT && (j = ((destcol - (outcol &~ 07)) >> 3)))
  456.                 j += destcol & 07;
  457.             else
  458.                 j = destcol - outcol;
  459.         else
  460.             if (outcol - destcol <= i && (BS || BC))
  461.                 i = j = outcol - destcol;
  462.             else
  463.                 j = i + 1;
  464.         k = outline - destline;
  465.         if (k < 0)
  466.             k = -k;
  467.         j += k;
  468.         if (i + destline < j) {
  469.             tputs(HO, 0, putch);
  470.             outcol = outline = 0;
  471.         } else if (LL) {
  472.             k = (LINES - 1) - destline;
  473.             if (i + k + 2 < j) {
  474.                 tputs(LL, 0, putch);
  475.                 outcol = 0;
  476.                 outline = LINES - 1;
  477.             }
  478.         }
  479.     }
  480.     if (GT && (!CA || holdcm))
  481.         i = (destcol >> 3) + (destcol & 07);
  482.     else
  483.         i = destcol;
  484.     if ((!NONL || outline >= destline) && (!NC || outline < destline) &&
  485.         (outcol - destcol > i + 1 || outcol > destcol && !BS && !BC)) {
  486.         putch('\r');
  487.         if (NC) {
  488.             putch('\n');
  489.             outline++;
  490.         }
  491.         outcol = 0;
  492.     }
  493.     while (outline < destline) {
  494.         outline++;
  495.         putch('\n');
  496.         if (NONL || pfast == 0)
  497.             outcol = 0;
  498.     }
  499.     while (outcol > destcol) {
  500.         outcol--;
  501.         if (BC)
  502.             tputs(BC, 0, putch);
  503.         else
  504.             putch('\b');
  505.     }
  506.     while (outline > destline) {
  507.         outline--;
  508.         putS(UP);
  509.     }
  510.     if (GT && destcol - outcol > 1) {
  511.         while ((i = ((outcol + 8) &~ 7)) <= destcol) {
  512.             if (TA)
  513.                 tputs(TA, 0, putch);
  514.             else
  515.                 putch('\t');
  516.             outcol = i;
  517.         }
  518.         if (destcol - outcol > 4 && (BC || BS)) {
  519.             if (TA)
  520.                 tputs(TA, 0, putch);
  521.             else
  522.                 putch('\t');
  523.             outcol = i;
  524.             while (outcol > destcol) {
  525.                 outcol--;
  526.                 if (BC)
  527.                     tputs(BC, 0, putch);
  528.                 else
  529.                     putch('\b');
  530.             }
  531.         }
  532.     }
  533.     while (outcol < destcol) {
  534.         if (inopen && ND)
  535.             putS(ND);
  536.         else
  537.             putch(' ');
  538.         outcol++;
  539.     }
  540. }
  541.  
  542. /*
  543.  * An input line arrived.
  544.  * Calculate new (approximate) screen line position.
  545.  * Approximate because kill character echoes newline with
  546.  * no feedback and also because of long input lines.
  547.  */
  548. noteinp()
  549. {
  550.  
  551.     outline++;
  552.     if (outline > LINES - 1)
  553.         outline = LINES - 1;
  554.     destline = outline;
  555.     destcol = outcol = 0;
  556. }
  557.  
  558. /*
  559.  * Something weird just happened and we
  560.  * lost track of whats happening out there.
  561.  * Since we cant, in general, read where we are
  562.  * we just reset to some known state.
  563.  * On cursor addressible terminals setting to unknown
  564.  * will force a cursor address soon.
  565.  */
  566. termreset()
  567. {
  568.  
  569.     endim();
  570.     destcol = 0;
  571.     destline = LINES - 1;
  572.     if (CA) {
  573.         outcol = UKCOL;
  574.         outline = UKCOL;
  575.     } else {
  576.         outcol = destcol;
  577.         outline = destline;
  578.     }
  579. }
  580.  
  581. /*
  582.  * Low level buffering, with the ability to drain
  583.  * buffered output without printing it.
  584.  */
  585. char    *obp = obuf;
  586.  
  587. draino()
  588. {
  589.  
  590.     obp = obuf;
  591. }
  592.  
  593. flusho()
  594. {
  595.  
  596.     if (obp != obuf) {
  597.         write(1, obuf, obp - obuf);
  598.         obp = obuf;
  599.     }
  600. }
  601.  
  602. putnl()
  603. {
  604.  
  605.     putchar('\n');
  606. }
  607.  
  608. putS(cp)
  609.     char *cp;
  610. {
  611.  
  612.     if (cp == NULL)
  613.         return;
  614.     while (*cp)
  615.         putch(*cp++);
  616. }
  617.  
  618.  
  619. putch(c)
  620.     int c;
  621. {
  622.  
  623.     *obp++ = c;
  624.     if (obp >= &obuf[sizeof obuf])
  625.         flusho();
  626. }
  627.  
  628. /*
  629.  * Miscellaneous routines related to output.
  630.  */
  631.  
  632. /*
  633.  * Cursor motion.
  634.  */
  635. char *
  636. cgoto()
  637. {
  638.  
  639.     return (tgoto(CM, destcol, destline));
  640. }
  641.  
  642. /*
  643.  * Put with padding
  644.  */
  645. putpad(cp)
  646.     char *cp;
  647. {
  648.  
  649.     flush();
  650.     tputs(cp, 0, putch);
  651. }
  652.  
  653. /*
  654.  * Set output through normal command mode routine.
  655.  */
  656. setoutt()
  657. {
  658.  
  659.     Outchar = termchar;
  660. }
  661.  
  662. /*
  663.  * Printf (temporarily) in list mode.
  664.  */
  665. /*VARARGS2*/
  666. lprintf(cp, dp)
  667.     char *cp, *dp;
  668. {
  669.     register int (*P)();
  670.  
  671.     P = setlist(1);
  672.     printf(cp, dp);
  673.     Putchar = P;
  674. }
  675.  
  676. /*
  677.  * Newline + flush.
  678.  */
  679. putNFL()
  680. {
  681.  
  682.     putnl();
  683.     flush();
  684. }
  685.  
  686. /*
  687.  * Try to start -nl mode.
  688.  */
  689. pstart()
  690. {
  691.  
  692.     if (NONL)
  693.         return;
  694.      if (!value(OPTIMIZE))
  695.         return;
  696.     if (ruptible == 0 || pfast)
  697.         return;
  698.     fgoto();
  699.     flusho();
  700.     pfast = 1;
  701.     normtty++;
  702.     tty.sg_flags = normf & ~(ECHO|CRMOD);
  703.     sTTY(1);
  704. }
  705.  
  706. /*
  707.  * Stop -nl mode.
  708.  */
  709. pstop()
  710. {
  711.  
  712.     if (inopen)
  713.         return;
  714.     phadnl = 0;
  715.     linp = linb;
  716.     draino();
  717.     normal(normf);
  718.     pfast &= ~1;
  719. }
  720.  
  721. /*
  722.  * Prep tty for open mode.
  723.  */
  724. ostart()
  725. {
  726.     int f;
  727.  
  728.     if (!intty)
  729.         error("Open and visual must be used interactively");
  730.     gTTY(1);
  731.     normtty++;
  732.     f = tty.sg_flags;
  733. #ifdef V6
  734.     tty.sg_flags = (normf &~ (ECHO|CRMOD)) | RAW;
  735. #else
  736.     tty.sg_flags = (normf &~ (ECHO|CRMOD)) | CBREAK;
  737. #endif
  738.     sTTY(1);
  739.     putpad(VS);
  740.     pfast |= 2;
  741.     return (f);
  742. }
  743.  
  744. /*
  745.  * Stop open, restoring tty modes.
  746.  */
  747. ostop(f)
  748.     int f;
  749. {
  750.  
  751.     pfast = (f & CRMOD) == 0;
  752.     termreset(), fgoto(), flusho();
  753.     normal(f);
  754.     putpad(VE);
  755. }
  756.  
  757. #ifdef V6
  758. /*
  759.  * Into cooked mode for interruptibility.
  760.  */
  761. vcook()
  762. {
  763.  
  764.     tty.sg_flags &= ~RAW;
  765.     sTTY(1);
  766. }
  767.  
  768. /*
  769.  * Back into raw mode.
  770.  */
  771. vraw()
  772. {
  773.  
  774.     tty.sg_flags |= RAW;
  775.     sTTY(1);
  776. }
  777. #endif
  778.  
  779. /*
  780.  * Restore flags to normal state f.
  781.  */
  782. normal(f)
  783.     int f;
  784. {
  785.  
  786.     if (normtty > 0) {
  787.         setty(f);
  788.         normtty--;
  789.     }
  790. }
  791.  
  792. /*
  793.  * Straight set of flags to state f.
  794.  */
  795. setty(f)
  796.     int f;
  797. {
  798.     register int ot = tty.sg_flags;
  799.  
  800.     tty.sg_flags = f;
  801.     sTTY(1);
  802.     return (ot);
  803. }
  804.  
  805. gTTY(i)
  806.     int i;
  807. {
  808.  
  809.     ignore(gtty(i, &tty));
  810. }
  811.  
  812. sTTY(i)
  813.     int i;
  814. {
  815.  
  816. #ifdef V6
  817.     stty(i, &tty);
  818. #else
  819.     ioctl(i, TIOCSETN, &tty);
  820. #endif
  821. }
  822.  
  823. /*
  824.  * Print newline, or blank if in open/visual
  825.  */
  826. noonl()
  827. {
  828.  
  829.     putchar(Outchar != termchar ? ' ' : '\n');
  830. }
  831.