home *** CD-ROM | disk | FTP | other *** search
/ InfoMagic Source Code 1993 July / THE_SOURCE_CODE_CD_ROM.iso / bsd_srcs / usr.bin / more / screen.c < prev    next >
Encoding:
C/C++ Source or Header  |  1992-08-03  |  11.9 KB  |  558 lines

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