home *** CD-ROM | disk | FTP | other *** search
/ Power-Programmierung / CD2.mdf / c / library / os2 / less / screen.c < prev    next >
Encoding:
C/C++ Source or Header  |  1991-06-27  |  14.4 KB  |  753 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 <stdio.h>
  9. #include <stdlib.h>
  10.  
  11. #include "less.h"
  12. #if XENIX
  13. #include <sys/types.h>
  14. #include <sys/ioctl.h>
  15. #endif
  16.  
  17. #ifdef OS2
  18. #undef VOID
  19. #undef CONTROL
  20. #define INCL_SUB
  21. #define INCL_NOPM
  22. #include <os2.h>
  23. #else
  24. #if TERMIO
  25. #include <termio.h>
  26. #else
  27. #include <sgtty.h>
  28. #endif
  29. #endif
  30.  
  31. #if !TERMIO && defined(TIOCGWINSZ)
  32. #include <sys/ioctl.h>
  33. #else
  34. /*
  35.  * For the Unix PC (ATT 7300 & 3B1):
  36.  * Since WIOCGETD is defined in sys/window.h, we can't use that to decide
  37.  * whether to include sys/window.h.  Use SIGPHONE from signal.h instead.
  38.  */
  39. #include <signal.h>
  40. #ifdef SIGPHONE
  41. #include <sys/window.h>
  42. #endif
  43. #endif
  44.  
  45. #if NEED_PTEM_H && defined(TIOCGWINSZ)
  46. /*
  47.  * All this just to get struct winsize.  Sigh.
  48.  */
  49. #include <sys/types.h>
  50. #include <sys/stream.h>
  51. #include <sys/ptem.h>
  52. #endif
  53.  
  54. /*
  55.  * Strings passed to tputs() to do various terminal functions.
  56.  */
  57. static char
  58.     *sc_pad,        /* Pad string */
  59.     *sc_home,        /* Cursor home */
  60.     *sc_addline,        /* Add line, scroll down following lines */
  61.     *sc_lower_left,        /* Cursor to last line, first column */
  62.     *sc_move,        /* General cursor positioning */
  63.     *sc_clear,        /* Clear screen */
  64.     *sc_eol_clear,        /* Clear to end of line */
  65.     *sc_s_in,        /* Enter standout (highlighted) mode */
  66.     *sc_s_out,        /* Exit standout mode */
  67.     *sc_u_in,        /* Enter underline mode */
  68.     *sc_u_out,        /* Exit underline mode */
  69.     *sc_b_in,        /* Enter bold mode */
  70.     *sc_b_out,        /* Exit bold mode */
  71.     *sc_bl_in,        /* Enter blink mode */
  72.     *sc_bl_out,        /* Exit blink mode */
  73.     *sc_visual_bell,    /* Visual bell (flash screen) sequence */
  74.     *sc_backspace,        /* Backspace cursor */
  75.     *sc_init,        /* Startup terminal initialization */
  76.     *sc_deinit;        /* Exit terminal de-initialization */
  77.  
  78. static int init_done = 0;
  79.  
  80. public int auto_wrap;        /* Terminal does \r\n when write past margin */
  81. public int ignaw;        /* Terminal ignores \n immediately after wrap */
  82. public int erase_char, kill_char; /* The user's erase and line-kill chars */
  83. public int sc_width, sc_height;    /* Height & width of screen */
  84. public int bo_s_width, bo_e_width;    /* Printing width of boldface seq */
  85. public int ul_s_width, ul_e_width;    /* Printing width of underline seq */
  86. public int so_s_width, so_e_width;    /* Printing width of standout seq */
  87. public int bl_s_width, bl_e_width;    /* Printing width of blink seq */
  88.  
  89. static char *cheaper();
  90. static int cost();
  91.  
  92. /*
  93.  * These two variables are sometimes defined in,
  94.  * and needed by, the termcap library.
  95.  * It may be necessary on some systems to declare them extern here.
  96.  */
  97. /*extern*/ short ospeed;    /* Terminal output baud rate */
  98. /*extern*/ char PC;        /* Pad character */
  99.  
  100. extern int quiet;        /* If VERY_QUIET, use visual bell for bell */
  101. extern int know_dumb;        /* Don't complain about a dumb terminal */
  102. extern int back_scroll;
  103. extern int swindow;
  104. extern char *tgetstr();
  105. extern char *tgoto();
  106. extern char *getenv();
  107.  
  108.  
  109. /*
  110.  * Change terminal to "raw mode", or restore to "normal" mode.
  111.  * "Raw mode" means
  112.  *    1. An outstanding read will complete on receipt of a single keystroke.
  113.  *    2. Input is not echoed.
  114.  *    3. On output, \n is mapped to \r\n.
  115.  *    4. \t is NOT expanded into spaces.
  116.  *    5. Signal-causing characters such as ctrl-C (interrupt),
  117.  *       etc. are NOT disabled.
  118.  * It doesn't matter whether an input \n is mapped to \r, or vice versa.
  119.  */
  120.     public void
  121. raw_mode(on)
  122.     int on;
  123. {
  124.     static int curr_on = 0;
  125.  
  126.     if (on == curr_on)
  127.         return;
  128. #ifdef OS2
  129.         signal(SIGINT, SIG_IGN);
  130.     erase_char = '\b';
  131.     kill_char = '\033';
  132. #else
  133. #if TERMIO
  134.     {
  135.     struct termio s;
  136.     static struct termio save_term;
  137.  
  138.     if (on)
  139.     {
  140.         /*
  141.          * Get terminal modes.
  142.          */
  143.         ioctl(2, TCGETA, &s);
  144.  
  145.         /*
  146.          * Save modes and set certain variables dependent on modes.
  147.          */
  148.         save_term = s;
  149.         ospeed = s.c_cflag & CBAUD;
  150.         erase_char = s.c_cc[VERASE];
  151.         kill_char = s.c_cc[VKILL];
  152.  
  153.         /*
  154.          * Set the modes to the way we want them.
  155.          */
  156.         s.c_lflag &= ~(ICANON|ECHO|ECHOE|ECHOK|ECHONL);
  157.         s.c_oflag |=  (OPOST|ONLCR|TAB3);
  158.         s.c_oflag &= ~(OCRNL|ONOCR|ONLRET);
  159.         s.c_cc[VMIN] = 1;
  160.         s.c_cc[VTIME] = 0;
  161.     } else
  162.     {
  163.         /*
  164.          * Restore saved modes.
  165.          */
  166.         s = save_term;
  167.     }
  168.     ioctl(2, TCSETAW, &s);
  169.     }
  170. #else
  171.     {
  172.     struct sgttyb s;
  173.     static struct sgttyb save_term;
  174.  
  175.     if (on)
  176.     {
  177.         /*
  178.          * Get terminal modes.
  179.          */
  180.         ioctl(2, TIOCGETP, &s);
  181.  
  182.         /*
  183.          * Save modes and set certain variables dependent on modes.
  184.          */
  185.         save_term = s;
  186.         ospeed = s.sg_ospeed;
  187.         erase_char = s.sg_erase;
  188.         kill_char = s.sg_kill;
  189.  
  190.         /*
  191.          * Set the modes to the way we want them.
  192.          */
  193.         s.sg_flags |= CBREAK;
  194.         s.sg_flags &= ~(ECHO|XTABS);
  195.     } else
  196.     {
  197.         /*
  198.          * Restore saved modes.
  199.          */
  200.         s = save_term;
  201.     }
  202.     ioctl(2, TIOCSETN, &s);
  203.     }
  204. #endif
  205. #endif
  206.     curr_on = on;
  207. }
  208.  
  209.     static void
  210. cannot(s)
  211.     char *s;
  212. {
  213.     PARG parg;
  214.  
  215.     if (know_dumb)
  216.         /*
  217.          * User knows this is a dumb terminal, so don't tell him.
  218.          */
  219.         return;
  220.  
  221.     parg.p_string = s;
  222.     error("WARNING: terminal cannot %s", &parg);
  223. }
  224.  
  225. /*
  226.  * Get size of the output screen.
  227.  */
  228.     public void
  229. scrsize(p_height, p_width)
  230.     int *p_height;
  231.     int *p_width;
  232. {
  233. #ifdef OS2
  234.         if ( _osmode == DOS_MODE )
  235.         {
  236.           *p_width  = (* (char far *) 0x0040004A);
  237.           *p_height = (* (char far *) 0x00400084) + 1;
  238.  
  239.       if ( (*p_height < 25) || (*p_height > 75) )
  240.         *p_height = 25;
  241.         }
  242.         else
  243.         {
  244.           VIOMODEINFO mi;
  245.  
  246.           mi.cb = sizeof(mi);
  247.           VioGetMode(&mi, 0);
  248.           *p_width = mi.col;
  249.           *p_height = mi.row;
  250.         }
  251. #else
  252.     register char *s;
  253. #ifdef TIOCGWINSZ
  254.     struct winsize w;
  255. #else
  256. #ifdef WIOCGETD
  257.     struct uwdata w;
  258. #endif
  259. #endif
  260.  
  261. #ifdef TIOCGWINSZ
  262.     if (ioctl(2, TIOCGWINSZ, &w) == 0 && w.ws_row > 0)
  263.         *p_height = w.ws_row;
  264.     else
  265. #else
  266. #ifdef WIOCGETD
  267.     if (ioctl(2, WIOCGETD, &w) == 0 && w.uw_height > 0)
  268.         *p_height = w.uw_height/w.uw_vs;
  269.     else
  270. #endif
  271. #endif
  272.     if ((s = getenv("LINES")) != NULL)
  273.         *p_height = atoi(s);
  274.     else
  275.          *p_height = tgetnum("li");
  276.  
  277.     if (*p_height <= 0)
  278.         *p_height = 24;
  279.  
  280. #ifdef TIOCGWINSZ
  281.      if (ioctl(2, TIOCGWINSZ, &w) == 0 && w.ws_col > 0)
  282.         *p_width = w.ws_col;
  283.     else
  284. #ifdef WIOCGETD
  285.     if (ioctl(2, WIOCGETD, &w) == 0 && w.uw_width > 0)
  286.         *p_width = w.uw_width/w.uw_hs;
  287.     else
  288. #endif
  289. #endif
  290.     if ((s = getenv("COLUMNS")) != NULL)
  291.         *p_width = atoi(s);
  292.     else
  293.          *p_width = tgetnum("co");
  294. #endif /* OS2 */
  295.  
  296.      if (*p_width <= 0)
  297.           *p_width = 80;
  298. }
  299.  
  300. /*
  301.  * Get terminal capabilities via termcap.
  302.  */
  303.     public void
  304. get_term()
  305. {
  306.     char *sp;
  307.     register char *t1, *t2;
  308.     register int hard;
  309.     char *term;
  310.     char termbuf[2048];
  311.  
  312.     static char sbuf[1024];
  313.  
  314.     /*
  315.      * Find out what kind of terminal this is.
  316.      */
  317.      if ((term = getenv("TERM")) == NULL)
  318. #ifdef OS2
  319.                 term = "ansi";
  320. #else
  321.          term = "unknown";
  322. #endif
  323.      if (tgetent(termbuf, term) <= 0)
  324.          strcpy(termbuf, "dumb:hc:");
  325.  
  326.      hard = tgetflag("hc");
  327.  
  328.     /*
  329.      * Get size of the screen.
  330.      */
  331.     scrsize(&sc_height, &sc_width);
  332.     pos_init();
  333.     if (swindow < 0)
  334.         swindow = sc_height - 1;
  335.  
  336.     auto_wrap = tgetflag("am");
  337.     ignaw = tgetflag("xn");
  338.  
  339.     /*
  340.      * Assumes termcap variable "sg" is the printing width of:
  341.      * the standout sequence, the end standout sequence,
  342.      * the underline sequence, the end underline sequence,
  343.      * the boldface sequence, and the end boldface sequence.
  344.      */
  345.     if ((so_s_width = tgetnum("sg")) < 0)
  346.         so_s_width = 0;
  347.     so_e_width = so_s_width;
  348.  
  349.     bo_s_width = bo_e_width = so_s_width;
  350.     ul_s_width = ul_e_width = so_s_width;
  351.     bl_s_width = bl_e_width = so_s_width;
  352.  
  353.     /*
  354.      * Get various string-valued capabilities.
  355.      */
  356.     sp = sbuf;
  357.  
  358.     sc_pad = tgetstr("pc", &sp);
  359.     if (sc_pad != NULL)
  360.         PC = *sc_pad;
  361.  
  362.     sc_init = tgetstr("ti", &sp);
  363.     if (sc_init == NULL)
  364.         sc_init = "";
  365.  
  366.     sc_deinit= tgetstr("te", &sp);
  367.     if (sc_deinit == NULL)
  368.         sc_deinit = "";
  369.  
  370.     sc_eol_clear = tgetstr("ce", &sp);
  371.     if (hard || sc_eol_clear == NULL || *sc_eol_clear == '\0')
  372.     {
  373.         cannot("clear to end of line");
  374.         sc_eol_clear = "";
  375.     }
  376.  
  377.     sc_clear = tgetstr("cl", &sp);
  378.     if (hard || sc_clear == NULL || *sc_clear == '\0')
  379.     {
  380.         cannot("clear screen");
  381.         sc_clear = "\n\n";
  382.     }
  383.  
  384.     sc_move = tgetstr("cm", &sp);
  385.     if (hard || sc_move == NULL || *sc_move == '\0')
  386.     {
  387.         /*
  388.          * This is not an error here, because we don't
  389.          * always need sc_move.
  390.          * We need it only if we don't have home or lower-left.
  391.          */
  392.         sc_move = "";
  393.     }
  394.  
  395.     sc_s_in = tgetstr("so", &sp);
  396.     if (hard || sc_s_in == NULL)
  397.         sc_s_in = "";
  398.  
  399.     sc_s_out = tgetstr("se", &sp);
  400.     if (hard || sc_s_out == NULL)
  401.         sc_s_out = "";
  402.  
  403.     sc_u_in = tgetstr("us", &sp);
  404.     if (hard || sc_u_in == NULL)
  405.         sc_u_in = sc_s_in;
  406.  
  407.     sc_u_out = tgetstr("ue", &sp);
  408.     if (hard || sc_u_out == NULL)
  409.         sc_u_out = sc_s_out;
  410.  
  411.     sc_b_in = tgetstr("md", &sp);
  412.     if (hard || sc_b_in == NULL)
  413.     {
  414.         sc_b_in = sc_s_in;
  415.         sc_b_out = sc_s_out;
  416.     } else
  417.     {
  418.         sc_b_out = tgetstr("me", &sp);
  419.         if (hard || sc_b_out == NULL)
  420.             sc_b_out = "";
  421.     }
  422.  
  423.     sc_bl_in = tgetstr("mb", &sp);
  424.     if (hard || sc_bl_in == NULL)
  425.     {
  426.         sc_bl_in = sc_s_in;
  427.         sc_bl_out = sc_s_out;
  428.     } else
  429.     {
  430.         sc_bl_out = sc_b_out;
  431.     }
  432.  
  433.     sc_visual_bell = tgetstr("vb", &sp);
  434.     if (hard || sc_visual_bell == NULL)
  435.         sc_visual_bell = "";
  436.  
  437.     if (tgetflag("bs"))
  438.         sc_backspace = "\b";
  439.     else
  440.     {
  441.         sc_backspace = tgetstr("bc", &sp);
  442.         if (sc_backspace == NULL || *sc_backspace == '\0')
  443.             sc_backspace = "\b";
  444.     }
  445.  
  446.     /*
  447.      * Choose between using "ho" and "cm" ("home" and "cursor move")
  448.      * to move the cursor to the upper left corner of the screen.
  449.      */
  450.     t1 = tgetstr("ho", &sp);
  451.     if (hard || t1 == NULL)
  452.         t1 = "";
  453.     if (*sc_move == '\0')
  454.         t2 = "";
  455.     else
  456.     {
  457.         strcpy(sp, tgoto(sc_move, 0, 0));
  458.         t2 = sp;
  459.         sp += strlen(sp) + 1;
  460.     }
  461.     sc_home = cheaper(t1, t2, "home cursor", "|\b^");
  462.  
  463.     /*
  464.      * Choose between using "ll" and "cm"  ("lower left" and "cursor move")
  465.      * to move the cursor to the lower left corner of the screen.
  466.      */
  467.     t1 = tgetstr("ll", &sp);
  468.     if (hard || t1 == NULL)
  469.         t1 = "";
  470.     if (*sc_move == '\0')
  471.         t2 = "";
  472.     else
  473.     {
  474.         strcpy(sp, tgoto(sc_move, 0, sc_height-1));
  475.         t2 = sp;
  476.         sp += strlen(sp) + 1;
  477.     }
  478.     sc_lower_left = cheaper(t1, t2,
  479.         "move cursor to lower left of screen", "\r");
  480.  
  481.     /*
  482.      * Choose between using "al" or "sr" ("add line" or "scroll reverse")
  483.      * to add a line at the top of the screen.
  484.      */
  485.     t1 = tgetstr("al", &sp);
  486.     if (hard || t1 == NULL)
  487.         t1 = "";
  488.     t2 = tgetstr("sr", &sp);
  489.     if (hard || t2 == NULL)
  490.         t2 = "";
  491. #ifdef OS2
  492.         if (*t1 == '\0' && *t2 == '\0')
  493.            sc_addline = "";
  494.         else
  495. #endif
  496.     sc_addline = cheaper(t1, t2, "scroll backwards", "");
  497.  
  498.     if (*sc_addline == '\0')
  499.     {
  500.         /*
  501.          * Force repaint on any backward movement.
  502.          */
  503.         back_scroll = 0;
  504.     }
  505. }
  506.  
  507. /*
  508.  * Return the cost of displaying a termcap string.
  509.  * We use the trick of calling tputs, but as a char printing function
  510.  * we give it inc_costcount, which just increments "costcount".
  511.  * This tells us how many chars would be printed by using this string.
  512.  * {{ Couldn't we just use strlen? }}
  513.  */
  514. static int costcount;
  515.  
  516. /*ARGSUSED*/
  517.     static void
  518. inc_costcount(c)
  519.     int c;
  520. {
  521.     costcount++;
  522. }
  523.  
  524.     static int
  525. cost(t)
  526.     char *t;
  527. {
  528.     costcount = 0;
  529.     tputs(t, sc_height, inc_costcount);
  530.     return (costcount);
  531. }
  532.  
  533. /*
  534.  * Return the "best" of the two given termcap strings.
  535.  * The best, if both exist, is the one with the lower
  536.  * cost (see cost() function).
  537.  */
  538.     static char *
  539. cheaper(t1, t2, doit, def)
  540.     char *t1, *t2;
  541.     char *doit;
  542.     char *def;
  543. {
  544.     if (*t1 == '\0' && *t2 == '\0')
  545.     {
  546.         cannot(doit);
  547.         return (def);
  548.     }
  549.     if (*t1 == '\0')
  550.         return (t2);
  551.     if (*t2 == '\0')
  552.         return (t1);
  553.     if (cost(t1) < cost(t2))
  554.         return (t1);
  555.     return (t2);
  556. }
  557.  
  558.  
  559. /*
  560.  * Below are the functions which perform all the
  561.  * terminal-specific screen manipulation.
  562.  */
  563.  
  564.  
  565. /*
  566.  * Initialize terminal
  567.  */
  568.     public void
  569. init()
  570. {
  571.     tputs(sc_init, sc_height, putchr);
  572.     init_done = 1;
  573. }
  574.  
  575. /*
  576.  * Deinitialize terminal
  577.  */
  578.     public void
  579. deinit()
  580. {
  581.     if (!init_done)
  582.         return;
  583.     tputs(sc_deinit, sc_height, putchr);
  584.     init_done = 0;
  585. }
  586.  
  587. /*
  588.  * Home cursor (move to upper left corner of screen).
  589.  */
  590.     public void
  591. home()
  592. {
  593.     tputs(sc_home, 1, putchr);
  594. }
  595.  
  596. /*
  597.  * Add a blank line (called with cursor at home).
  598.  * Should scroll the display down.
  599.  */
  600.     public void
  601. add_line()
  602. {
  603.     tputs(sc_addline, sc_height, putchr);
  604. }
  605.  
  606. /*
  607.  * Move cursor to lower left corner of screen.
  608.  */
  609.     public void
  610. lower_left()
  611. {
  612.     tputs(sc_lower_left, 1, putchr);
  613. }
  614.  
  615. /*
  616.  * Ring the terminal bell.
  617.  */
  618.     public void
  619. bell()
  620. {
  621.     if (quiet == VERY_QUIET)
  622.         vbell();
  623.     else
  624.         putchr('\7');
  625. }
  626.  
  627. /*
  628.  * Output the "visual bell", if there is one.
  629.  */
  630.     public void
  631. vbell()
  632. {
  633.     if (*sc_visual_bell == '\0')
  634.         return;
  635.     tputs(sc_visual_bell, sc_height, putchr);
  636. }
  637.  
  638. /*
  639.  * Clear the screen.
  640.  */
  641.     public void
  642. clear()
  643. {
  644.     tputs(sc_clear, sc_height, putchr);
  645. }
  646.  
  647. /*
  648.  * Clear from the cursor to the end of the cursor's line.
  649.  * {{ This must not move the cursor. }}
  650.  */
  651.     public void
  652. clear_eol()
  653. {
  654.     tputs(sc_eol_clear, 1, putchr);
  655. }
  656.  
  657. /*
  658.  * Begin "standout" (bold, underline, or whatever).
  659.  */
  660.     public void
  661. so_enter()
  662. {
  663.     tputs(sc_s_in, 1, putchr);
  664. }
  665.  
  666. /*
  667.  * End "standout".
  668.  */
  669.     public void
  670. so_exit()
  671. {
  672.     tputs(sc_s_out, 1, putchr);
  673. }
  674.  
  675. /*
  676.  * Begin "underline" (hopefully real underlining,
  677.  * otherwise whatever the terminal provides).
  678.  */
  679.     public void
  680. ul_enter()
  681. {
  682.     tputs(sc_u_in, 1, putchr);
  683. }
  684.  
  685. /*
  686.  * End "underline".
  687.  */
  688.     public void
  689. ul_exit()
  690. {
  691.     tputs(sc_u_out, 1, putchr);
  692. }
  693.  
  694. /*
  695.  * Begin "bold"
  696.  */
  697.     public void
  698. bo_enter()
  699. {
  700.     tputs(sc_b_in, 1, putchr);
  701. }
  702.  
  703. /*
  704.  * End "bold".
  705.  */
  706.     public void
  707. bo_exit()
  708. {
  709.     tputs(sc_b_out, 1, putchr);
  710. }
  711.  
  712. /*
  713.  * Begin "blink"
  714.  */
  715.     public void
  716. bl_enter()
  717. {
  718.     tputs(sc_bl_in, 1, putchr);
  719. }
  720.  
  721. /*
  722.  * End "blink".
  723.  */
  724.     public void
  725. bl_exit()
  726. {
  727.     tputs(sc_bl_out, 1, putchr);
  728. }
  729.  
  730. /*
  731.  * Erase the character to the left of the cursor
  732.  * and move the cursor left.
  733.  */
  734.     public void
  735. backspace()
  736. {
  737.     /*
  738.      * Try to erase the previous character by overstriking with a space.
  739.      */
  740.     tputs(sc_backspace, 1, putchr);
  741.     putchr(' ');
  742.     tputs(sc_backspace, 1, putchr);
  743. }
  744.  
  745. /*
  746.  * Output a plain backspace, without erasing the previous char.
  747.  */
  748.     public void
  749. putbs()
  750. {
  751.     tputs(sc_backspace, 1, putchr);
  752. }
  753.