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