home *** CD-ROM | disk | FTP | other *** search
/ Usenet 1994 October / usenetsourcesnewsgroupsinfomagicoctober1994disk2.iso / unix / volume6 / less.patch / screen.c < prev   
C/C++ Source or Header  |  1986-11-30  |  10KB  |  509 lines

  1. /*
  2.  * Routines which deal with the characteristics of the terminal.
  3.  * Uses termcap to be as terminal-independent as possible.
  4.  *
  5.  * {{ Someday this should be rewritten to use curses. }}
  6.  */
  7.  
  8. #include "less.h"
  9. #if XENIX
  10. #include <sys/types.h>
  11. #include <sys/ioctl.h>
  12. #endif
  13.  
  14. #if TERMIO
  15. #include <termio.h>
  16. #else
  17. #include <sgtty.h>
  18. #endif
  19.  
  20. /*
  21.  * Strings passed to tputs() to do various terminal functions.
  22.  */
  23. static char
  24.     *sc_pad,        /* Pad string */
  25.     *sc_home,        /* Cursor home */
  26.     *sc_addline,        /* Add line, scroll down following lines */
  27.     *sc_lower_left,        /* Cursor to last line, first column */
  28.     *sc_move,        /* General cursor positioning */
  29.     *sc_clear,        /* Clear screen */
  30.     *sc_eol_clear,        /* Clear to end of line */
  31.     *sc_s_in,        /* Enter standout (highlighted) mode */
  32.     *sc_s_out,        /* Exit standout mode */
  33.     *sc_u_in,        /* Enter underline mode */
  34.     *sc_u_out,        /* Exit underline mode */
  35.     *sc_visual_bell,    /* Visual bell (flash screen) sequence */
  36.     *sc_backspace,        /* Backspace cursor */
  37.     *sc_init,        /* Startup terminal initialization */
  38.     *sc_deinit;        /* Exit terminal de-intialization */
  39. static int dumb;
  40. static int hard;
  41.  
  42. public int auto_wrap;        /* Terminal does \r\n when write past margin */
  43. public int ignaw;        /* Terminal ignores \n immediately after wrap */
  44. public int erase_char, kill_char; /* The user's erase and line-kill chars */
  45. public int sc_width, sc_height;    /* Height & width of screen */
  46. public int sc_window = -1;    /* window size for forward and backward */
  47. public int ul_width, ue_width;    /* Printing width of underline sequences */
  48. public int so_width, se_width;    /* Printing width of standout sequences */
  49.  
  50. /*
  51.  * These two variables are sometimes defined in,
  52.  * and needed by, the termcap library.
  53.  * It may be necessary on some systems to declare them extern here.
  54.  */
  55. /*extern*/ short ospeed;    /* Terminal output baud rate */
  56. /*extern*/ char PC;        /* Pad character */
  57.  
  58. extern int quiet;        /* If VERY_QUIET, use visual bell for bell */
  59. extern int know_dumb;        /* Don't complain about a dumb terminal */
  60. extern int back_scroll;
  61. char *tgetstr();
  62. char *tgoto();
  63.  
  64. /*
  65.  * Change terminal to "raw mode", or restore to "normal" mode.
  66.  * "Raw mode" means 
  67.  *    1. An outstanding read will complete on receipt of a single keystroke.
  68.  *    2. Input is not echoed.  
  69.  *    3. On output, \n is mapped to \r\n.
  70.  *    4. \t is NOT be expanded into spaces.
  71.  *    5. Signal-causing characters such as ctrl-C (interrupt),
  72.  *       etc. are NOT disabled.
  73.  * It doesn't matter whether an input \n is mapped to \r, or vice versa.
  74.  */
  75.     public void
  76. raw_mode(on)
  77.     int on;
  78. {
  79. #if TERMIO
  80.     struct termio s;
  81.     static struct termio save_term;
  82.  
  83.     if (on)
  84.     {
  85.         /*
  86.          * Get terminal modes.
  87.          */
  88.         ioctl(2, TCGETA, &s);
  89.  
  90.         /*
  91.          * Save modes and set certain variables dependent on modes.
  92.          */
  93.         save_term = s;
  94.         ospeed = s.c_cflag & CBAUD;
  95.         erase_char = s.c_cc[VERASE];
  96.         kill_char = s.c_cc[VKILL];
  97.  
  98.         /*
  99.          * Set the modes to the way we want them.
  100.          */
  101.         s.c_lflag &= ~(ICANON|ECHO|ECHOE|ECHOK|ECHONL);
  102.         s.c_oflag |=  (OPOST|ONLCR|TAB3);
  103.         s.c_oflag &= ~(OCRNL|ONOCR|ONLRET);
  104.         s.c_cc[VMIN] = 1;
  105.         s.c_cc[VTIME] = 0;
  106.     } else
  107.     {
  108.         /*
  109.          * Restore saved modes.
  110.          */
  111.         s = save_term;
  112.     }
  113.     ioctl(2, TCSETAW, &s);
  114. #else
  115.     struct sgttyb s;
  116.     static struct sgttyb save_term;
  117.  
  118.     if (on)
  119.     {
  120.         /*
  121.          * Get terminal modes.
  122.          */
  123.         ioctl(2, TIOCGETP, &s);
  124.  
  125.         /*
  126.          * Save modes and set certain variables dependent on modes.
  127.          */
  128.         save_term = s;
  129.         ospeed = s.sg_ospeed;
  130.         erase_char = s.sg_erase;
  131.         kill_char = s.sg_kill;
  132.  
  133.         /*
  134.          * Set the modes to the way we want them.
  135.          */
  136.         s.sg_flags |= CBREAK;
  137.         s.sg_flags &= ~(ECHO|XTABS);
  138.     } else
  139.     {
  140.         /*
  141.          * Restore saved modes.
  142.          */
  143.         s = save_term;
  144.     }
  145.     ioctl(2, TIOCSETN, &s);
  146. #endif
  147. }
  148.  
  149. static int couldnt = 0;
  150.  
  151.     static void
  152. cannot(s)
  153.     char *s;
  154. {
  155.     if (know_dumb)
  156.         /* 
  157.          * He knows he has a dumb terminal, so don't tell him. 
  158.          */
  159.         return;
  160.  
  161.     printf("WARNING: terminal cannot \"%s\"\n", s);
  162.     couldnt = 1;
  163. }
  164.  
  165. /*
  166.  * Get terminal capabilities via termcap.
  167.  */
  168.     public void
  169. get_term()
  170. {
  171.     char termbuf[1024];
  172.     char *sp;
  173.     static char sbuf[150];
  174.  
  175.     char *getenv();
  176.  
  177.     /*
  178.      * Find out what kind of terminal this is.
  179.      */
  180.     if (tgetent(termbuf, getenv("TERM")) <= 0)
  181.         dumb = 1;
  182.  
  183.     /*
  184.      * Get size of the screen.
  185.      */
  186.     if (dumb || (sc_height = tgetnum("li")) < 0 || tgetflag("hc"))
  187.     {
  188.         /* Oh no, this is a hardcopy terminal. */
  189.         hard = 1;
  190.         sc_height = 24;
  191.     }
  192.     /*
  193.      * This is terrible - the following if "knows" that it is being
  194.      * executed *after* command line and environment options have
  195.      * already been parsed.  Should it be executed in the main program
  196.      * instead?
  197.      */
  198.     if ((sc_window <= 0) || (sc_window >= sc_height))
  199.         sc_window = sc_height-1;
  200.     if (dumb || (sc_width = tgetnum("co")) < 0)
  201.         sc_width = 80;
  202.  
  203.     auto_wrap = tgetflag("am");
  204.     ignaw = tgetflag("xn");
  205.  
  206.     /*
  207.      * Assumes termcap variable "sg" is the printing width of
  208.      * the standout sequence, the end standout sequence,
  209.      * the underline sequence, and the end underline sequence.
  210.      */
  211.     if ((ul_width = tgetnum("sg")) < 0)
  212.         ul_width = 0;
  213.     so_width = se_width = ue_width = ul_width;
  214.  
  215.     /*
  216.      * Get various string-valued capabilities.
  217.      */
  218.     sp = sbuf;
  219.  
  220.     sc_pad = (dumb) ? NULL : tgetstr("pc", &sp);
  221.     if (sc_pad != NULL)
  222.         PC = *sc_pad;
  223.  
  224.     sc_init = (dumb) ? NULL : tgetstr("ti", &sp);
  225.     if (sc_init == NULL)
  226.         sc_init = "";
  227.  
  228.     sc_deinit= (dumb) ? NULL : tgetstr("te", &sp);
  229.     if (sc_deinit == NULL)
  230.         sc_deinit = "";
  231.  
  232.     sc_eol_clear = (dumb) ? NULL : tgetstr("ce", &sp);
  233.     if (hard || sc_eol_clear == NULL || *sc_eol_clear == '\0')
  234.     {
  235.         cannot("clear to end of line");
  236.         sc_eol_clear = "";
  237.     }
  238.  
  239.     sc_clear = (dumb) ? NULL : tgetstr("cl", &sp);
  240.     if (hard || sc_clear == NULL || *sc_clear == '\0')
  241.     {
  242.         cannot("clear screen");
  243.         sc_clear = "\n\n";
  244.     }
  245.  
  246.     sc_move = (dumb) ? NULL : tgetstr("cm", &sp);
  247.     if (hard || sc_move == NULL || *sc_move == '\0')
  248.     {
  249.         /*
  250.          * This is not an error here, because we don't 
  251.          * always need sc_move.
  252.          * We need it only if we don't have home or lower-left.
  253.          */
  254.         sc_move = "";
  255.     }
  256.  
  257.     sc_s_in = (dumb) ? NULL : tgetstr("so", &sp);
  258.     if (hard || sc_s_in == NULL)
  259.         sc_s_in = "";
  260.  
  261.     sc_s_out = (dumb) ? NULL : tgetstr("se", &sp);
  262.     if (hard || sc_s_out == NULL)
  263.         sc_s_out = "";
  264.  
  265.     sc_u_in = (dumb) ? NULL : tgetstr("us", &sp);
  266.     if (hard || sc_u_in == NULL)
  267.         sc_u_in = sc_s_in;
  268.  
  269.     sc_u_out = (dumb) ? NULL : tgetstr("ue", &sp);
  270.     if (hard || sc_u_out == NULL)
  271.         sc_u_out = sc_s_out;
  272.  
  273.     sc_visual_bell = (dumb) ? NULL : tgetstr("vb", &sp);
  274.     if (hard || sc_visual_bell == NULL)
  275.         sc_visual_bell = "";
  276.  
  277.     sc_home = (dumb) ? NULL : tgetstr("ho", &sp);
  278.     if (hard || sc_home == NULL || *sc_home == '\0')
  279.     {
  280.         if (*sc_move == '\0')
  281.         {
  282.             cannot("home cursor");
  283.             /*
  284.              * This last resort for sc_home is supposed to
  285.              * be an up-arrow suggesting moving to the 
  286.              * top of the "virtual screen". (The one in
  287.              * your imagination as you try to use this on
  288.              * a hard copy terminal.)
  289.              */
  290.             sc_home = "|\b^";        
  291.         } else
  292.         {
  293.             /* 
  294.              * No "home" string,
  295.              * but we can use "move(0,0)".
  296.              */
  297.             strcpy(sp, tgoto(sc_move, 0, 0));
  298.             sc_home = sp;
  299.             sp += strlen(sp) + 1;
  300.         }
  301.     }
  302.  
  303.     sc_lower_left = (dumb) ? NULL : tgetstr("ll", &sp);
  304.     if (hard || sc_lower_left == NULL || *sc_lower_left == '\0')
  305.     {
  306.         if (*sc_move == '\0')
  307.         {
  308.             cannot("move cursor to lower left of screen");
  309.             sc_lower_left = "\r";
  310.         } else
  311.         {
  312.             /*
  313.              * No "lower-left" string, 
  314.              * but we can use "move(0,last-line)".
  315.              */
  316.             strcpy(sp, tgoto(sc_move, 0, sc_height-1));
  317.             sc_lower_left = sp;
  318.             sp += strlen(sp) + 1;
  319.         }
  320.     }
  321.  
  322.     /*
  323.      * To add a line at top of screen and scroll the display down,
  324.      * we use "al" (add line) or "sr" (scroll reverse).
  325.      */
  326.     if (dumb)
  327.         sc_addline = NULL;
  328.     else if ((sc_addline = tgetstr("al", &sp)) == NULL || 
  329.          *sc_addline == '\0')
  330.         sc_addline = tgetstr("sr", &sp);
  331.  
  332.     if (hard || sc_addline == NULL || *sc_addline == '\0')
  333.     {
  334.         cannot("scroll backwards");
  335.         sc_addline = "";
  336.         /* Force repaint on any backward movement */
  337.         back_scroll = 0;
  338.     }
  339.  
  340.     if (dumb || tgetflag("bs"))
  341.         sc_backspace = "\b";
  342.     else
  343.     {
  344.         sc_backspace = tgetstr("bc", &sp);
  345.         if (sc_backspace == NULL || *sc_backspace == '\0')
  346.             sc_backspace = "\b";
  347.     }
  348.  
  349.     if (couldnt)
  350.         /* Give him time to read all the "cannot" messages. */
  351.         error("");
  352. }
  353.  
  354.  
  355. /*
  356.  * Below are the functions which perform all the 
  357.  * terminal-specific screen manipulation.
  358.  */
  359.  
  360.  
  361. /*
  362.  * Initialize terminal
  363.  */
  364.     public void
  365. init()
  366. {
  367.     tputs(sc_init, sc_height, putc);
  368. }
  369.  
  370. /*
  371.  * Deinitialize terminal
  372.  */
  373.     public void
  374. deinit()
  375. {
  376.     tputs(sc_deinit, sc_height, putc);
  377. }
  378.  
  379. /*
  380.  * Home cursor (move to upper left corner of screen).
  381.  */
  382.     public void
  383. home()
  384. {
  385.     tputs(sc_home, 1, putc);
  386. }
  387.  
  388. /*
  389.  * Add a blank line (called with cursor at home).
  390.  * Should scroll the display down.
  391.  */
  392.     public void
  393. add_line()
  394. {
  395.     tputs(sc_addline, sc_height, putc);
  396. }
  397.  
  398. /*
  399.  * Move cursor to lower left corner of screen.
  400.  */
  401.     public void
  402. lower_left()
  403. {
  404.     tputs(sc_lower_left, 1, putc);
  405. }
  406.  
  407. /*
  408.  * Ring the terminal bell.
  409.  */
  410.     public void
  411. bell()
  412. {
  413.     if (quiet == VERY_QUIET)
  414.         vbell();
  415.     else
  416.         putc('\7');
  417. }
  418.  
  419. /*
  420.  * Output the "visual bell", if there is one.
  421.  */
  422.     public void
  423. vbell()
  424. {
  425.     if (*sc_visual_bell == '\0')
  426.         return;
  427.     tputs(sc_visual_bell, sc_height, putc);
  428. }
  429.  
  430. /*
  431.  * Clear the screen.
  432.  */
  433.     public void
  434. clear()
  435. {
  436.     tputs(sc_clear, sc_height, putc);
  437. }
  438.  
  439. /*
  440.  * Clear from the cursor to the end of the cursor's line.
  441.  * {{ This must not move the cursor. }}
  442.  */
  443.     public void
  444. clear_eol()
  445. {
  446.     tputs(sc_eol_clear, 1, putc);
  447. }
  448.  
  449. /*
  450.  * Begin "standout" (bold, underline, or whatever).
  451.  */
  452.     public void
  453. so_enter()
  454. {
  455.     tputs(sc_s_in, 1, putc);
  456. }
  457.  
  458. /*
  459.  * End "standout".
  460.  */
  461.     public void
  462. so_exit()
  463. {
  464.     tputs(sc_s_out, 1, putc);
  465. }
  466.  
  467. /*
  468.  * Begin "underline" (hopefully real underlining, 
  469.  * otherwise whatever the terminal provides).
  470.  */
  471.     public void
  472. ul_enter()
  473. {
  474.     tputs(sc_u_in, 1, putc);
  475. }
  476.  
  477. /*
  478.  * End "underline".
  479.  */
  480.     public void
  481. ul_exit()
  482. {
  483.     tputs(sc_u_out, 1, putc);
  484. }
  485.  
  486. /*
  487.  * Erase the character to the left of the cursor 
  488.  * and move the cursor left.
  489.  */
  490.     public void
  491. backspace()
  492. {
  493.     /* 
  494.      * Try to erase the previous character by overstriking with a space.
  495.      */
  496.     tputs(sc_backspace, 1, putc);
  497.     putc(' ');
  498.     tputs(sc_backspace, 1, putc);
  499. }
  500.  
  501. /*
  502.  * Output a plain backspace, without erasing the previous char.
  503.  */
  504.     public void
  505. putbs()
  506. {
  507.     tputs(sc_backspace, 1, putc);
  508. }
  509.