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