diff options
Diffstat (limited to 'usr.bin/more/screen.c')
-rw-r--r-- | usr.bin/more/screen.c | 610 |
1 files changed, 610 insertions, 0 deletions
diff --git a/usr.bin/more/screen.c b/usr.bin/more/screen.c new file mode 100644 index 0000000..bf12ad6 --- /dev/null +++ b/usr.bin/more/screen.c @@ -0,0 +1,610 @@ +/* + * Copyright (c) 1988 Mark Nudleman + * Copyright (c) 1988, 1993 + * The Regents of the University of California. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the University of + * California, Berkeley and its contributors. + * 4. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#ifndef lint +static char sccsid[] = "@(#)screen.c 8.2 (Berkeley) 4/20/94"; +#endif /* not lint */ + +/* + * Routines which deal with the characteristics of the terminal. + * Uses termcap to be as terminal-independent as possible. + * + * {{ Someday this should be rewritten to use curses. }} + */ + +#include <stdio.h> +#include <less.h> + +#define TERMIOS 1 + +#if TERMIO +#include <termio.h> +#else +#if TERMIOS +#include <termios.h> +#define TAB3 0 +#include <sys/ioctl.h> +#else +#include <sgtty.h> +#endif +#endif + +#ifdef TIOCGWINSZ +#include <sys/ioctl.h> +#else +/* + * For the Unix PC (ATT 7300 & 3B1): + * Since WIOCGETD is defined in sys/window.h, we can't use that to decide + * whether to include sys/window.h. Use SIGPHONE from sys/signal.h instead. + */ +#include <sys/signal.h> +#ifdef SIGPHONE +#include <sys/window.h> +#endif +#endif + +/* + * Strings passed to tputs() to do various terminal functions. + */ +static char + *sc_pad, /* Pad string */ + *sc_home, /* Cursor home */ + *sc_addline, /* Add line, scroll down following lines */ + *sc_lower_left, /* Cursor to last line, first column */ + *sc_move, /* General cursor positioning */ + *sc_clear, /* Clear screen */ + *sc_eol_clear, /* Clear to end of line */ + *sc_s_in, /* Enter standout (highlighted) mode */ + *sc_s_out, /* Exit standout mode */ + *sc_u_in, /* Enter underline mode */ + *sc_u_out, /* Exit underline mode */ + *sc_b_in, /* Enter bold mode */ + *sc_b_out, /* Exit bold mode */ + *sc_backspace, /* Backspace cursor */ + *sc_init, /* Startup terminal initialization */ + *sc_deinit; /* Exit terminal de-intialization */ + +int auto_wrap; /* Terminal does \r\n when write past margin */ +int ignaw; /* Terminal ignores \n immediately after wrap */ + /* The user's erase and line-kill chars */ +int retain_below; /* Terminal retains text below the screen */ +int erase_char, kill_char, werase_char; +int sc_width, sc_height = -1; /* Height & width of screen */ +int sc_window = -1; /* window size for forward and backward */ +int bo_width, be_width; /* Printing width of boldface sequences */ +int ul_width, ue_width; /* Printing width of underline sequences */ +int so_width, se_width; /* Printing width of standout sequences */ + +int mode_flags = 0; +#define M_SO 1 +#define M_UL 2 +#define M_BO 4 + +/* + * These two variables are sometimes defined in, + * and needed by, the termcap library. + * It may be necessary on some systems to declare them extern here. + */ +/*extern*/ short ospeed; /* Terminal output baud rate */ +/*extern*/ char PC; /* Pad character */ + +extern int back_scroll; +char *tgetstr(); +char *tgoto(); + +/* + * Change terminal to "raw mode", or restore to "normal" mode. + * "Raw mode" means + * 1. An outstanding read will complete on receipt of a single keystroke. + * 2. Input is not echoed. + * 3. On output, \n is mapped to \r\n. + * 4. \t is NOT expanded into spaces. + * 5. Signal-causing characters such as ctrl-C (interrupt), + * etc. are NOT disabled. + * It doesn't matter whether an input \n is mapped to \r, or vice versa. + */ +raw_mode(on) + int on; +{ +#if TERMIO || TERMIOS + +#if TERMIO + struct termio s; + static struct termio save_term; +#else + struct termios s; + static struct termios save_term; +#endif + + if (on) + { + /* + * Get terminal modes. + */ +#if TERMIO + (void)ioctl(2, TCGETA, &s); +#else + tcgetattr(2, &s); +#endif + + /* + * Save modes and set certain variables dependent on modes. + */ + save_term = s; +#if TERMIO + ospeed = s.c_cflag & CBAUD; +#else + /* more work needed here */ +#endif + erase_char = s.c_cc[VERASE]; + kill_char = s.c_cc[VKILL]; + werase_char = s.c_cc[VWERASE]; + + /* + * Set the modes to the way we want them. + */ + s.c_lflag &= ~(ICANON|ECHO|ECHOE|ECHOK|ECHONL); + s.c_oflag |= (OPOST|ONLCR|TAB3); +#if TERMIO + s.c_oflag &= ~(OCRNL|ONOCR|ONLRET); +#endif + s.c_cc[VMIN] = 1; + s.c_cc[VTIME] = 0; + } else + { + /* + * Restore saved modes. + */ + s = save_term; + } +#if TERMIO + (void)ioctl(2, TCSETAW, &s); +#else + tcsetattr(2, TCSADRAIN, &s); +#endif +#else + struct sgttyb s; + struct ltchars l; + static struct sgttyb save_term; + + if (on) + { + /* + * Get terminal modes. + */ + (void)ioctl(2, TIOCGETP, &s); + (void)ioctl(2, TIOCGLTC, &l); + + /* + * Save modes and set certain variables dependent on modes. + */ + save_term = s; + ospeed = s.sg_ospeed; + erase_char = s.sg_erase; + kill_char = s.sg_kill; + werase_char = l.t_werasc; + + /* + * Set the modes to the way we want them. + */ + s.sg_flags |= CBREAK; + s.sg_flags &= ~(ECHO|XTABS); + } else + { + /* + * Restore saved modes. + */ + s = save_term; + } + (void)ioctl(2, TIOCSETN, &s); +#endif +} + +/* + * Get terminal capabilities via termcap. + */ +get_term() +{ + char termbuf[2048]; + char *sp; + char *term; + int hard; +#ifdef TIOCGWINSZ + struct winsize w; +#else +#ifdef WIOCGETD + struct uwdata w; +#endif +#endif + static char sbuf[1024]; + + char *getenv(), *strcpy(); + + /* + * Find out what kind of terminal this is. + */ + if ((term = getenv("TERM")) == NULL) + term = "unknown"; + if (tgetent(termbuf, term) <= 0) + (void)strcpy(termbuf, "dumb:co#80:hc:"); + + /* + * Get size of the screen. + */ +#ifdef TIOCGWINSZ + if (ioctl(2, TIOCGWINSZ, &w) == 0 && w.ws_row > 0) + sc_height = w.ws_row; +#else +#ifdef WIOCGETD + if (ioctl(2, WIOCGETD, &w) == 0 && w.uw_height > 0) + sc_height = w.uw_height/w.uw_vs; +#endif +#endif + else + sc_height = tgetnum("li"); + hard = (sc_height < 0 || tgetflag("hc")); + if (hard) { + /* Oh no, this is a hardcopy terminal. */ + sc_height = 24; + } + +#ifdef TIOCGWINSZ + if (ioctl(2, TIOCGWINSZ, &w) == 0 && w.ws_col > 0) + sc_width = w.ws_col; + else +#ifdef WIOCGETD + if (ioctl(2, WIOCGETD, &w) == 0 && w.uw_width > 0) + sc_width = w.uw_width/w.uw_hs; + else +#endif +#endif + sc_width = tgetnum("co"); + if (sc_width < 0) + sc_width = 80; + + auto_wrap = tgetflag("am"); + ignaw = tgetflag("xn"); + retain_below = tgetflag("db"); + + /* + * Assumes termcap variable "sg" is the printing width of + * the standout sequence, the end standout sequence, + * the underline sequence, the end underline sequence, + * the boldface sequence, and the end boldface sequence. + */ + if ((so_width = tgetnum("sg")) < 0) + so_width = 0; + be_width = bo_width = ue_width = ul_width = se_width = so_width; + + /* + * Get various string-valued capabilities. + */ + sp = sbuf; + + sc_pad = tgetstr("pc", &sp); + if (sc_pad != NULL) + PC = *sc_pad; + + sc_init = tgetstr("ti", &sp); + if (sc_init == NULL) + sc_init = ""; + + sc_deinit= tgetstr("te", &sp); + if (sc_deinit == NULL) + sc_deinit = ""; + + sc_eol_clear = tgetstr("ce", &sp); + if (hard || sc_eol_clear == NULL || *sc_eol_clear == '\0') + { + sc_eol_clear = ""; + } + + sc_clear = tgetstr("cl", &sp); + if (hard || sc_clear == NULL || *sc_clear == '\0') + { + sc_clear = "\n\n"; + } + + sc_move = tgetstr("cm", &sp); + if (hard || sc_move == NULL || *sc_move == '\0') + { + /* + * This is not an error here, because we don't + * always need sc_move. + * We need it only if we don't have home or lower-left. + */ + sc_move = ""; + } + + sc_s_in = tgetstr("so", &sp); + if (hard || sc_s_in == NULL) + sc_s_in = ""; + + sc_s_out = tgetstr("se", &sp); + if (hard || sc_s_out == NULL) + sc_s_out = ""; + + sc_u_in = tgetstr("us", &sp); + if (hard || sc_u_in == NULL) + sc_u_in = sc_s_in; + + sc_u_out = tgetstr("ue", &sp); + if (hard || sc_u_out == NULL) + sc_u_out = sc_s_out; + + sc_b_in = tgetstr("md", &sp); + if (hard || sc_b_in == NULL) + { + sc_b_in = sc_s_in; + sc_b_out = sc_s_out; + } else + { + sc_b_out = tgetstr("me", &sp); + if (hard || sc_b_out == NULL) + sc_b_out = ""; + } + + sc_home = tgetstr("ho", &sp); + if (hard || sc_home == NULL || *sc_home == '\0') + { + if (*sc_move == '\0') + { + /* + * This last resort for sc_home is supposed to + * be an up-arrow suggesting moving to the + * top of the "virtual screen". (The one in + * your imagination as you try to use this on + * a hard copy terminal.) + */ + sc_home = "|\b^"; + } else + { + /* + * No "home" string, + * but we can use "move(0,0)". + */ + (void)strcpy(sp, tgoto(sc_move, 0, 0)); + sc_home = sp; + sp += strlen(sp) + 1; + } + } + + sc_lower_left = tgetstr("ll", &sp); + if (hard || sc_lower_left == NULL || *sc_lower_left == '\0') + { + if (*sc_move == '\0') + { + sc_lower_left = "\r"; + } else + { + /* + * No "lower-left" string, + * but we can use "move(0,last-line)". + */ + (void)strcpy(sp, tgoto(sc_move, 0, sc_height-1)); + sc_lower_left = sp; + sp += strlen(sp) + 1; + } + } + + /* + * To add a line at top of screen and scroll the display down, + * we use "al" (add line) or "sr" (scroll reverse). + */ + if ((sc_addline = tgetstr("al", &sp)) == NULL || + *sc_addline == '\0') + sc_addline = tgetstr("sr", &sp); + + if (hard || sc_addline == NULL || *sc_addline == '\0') + { + sc_addline = ""; + /* Force repaint on any backward movement */ + back_scroll = 0; + } + + if (tgetflag("bs")) + sc_backspace = "\b"; + else + { + sc_backspace = tgetstr("bc", &sp); + if (sc_backspace == NULL || *sc_backspace == '\0') + sc_backspace = "\b"; + } +} + + +/* + * Below are the functions which perform all the + * terminal-specific screen manipulation. + */ + +int putchr(); + +/* + * Initialize terminal + */ +init() +{ + tputs(sc_init, sc_height, putchr); +} + +/* + * Deinitialize terminal + */ +deinit() +{ + tputs(sc_deinit, sc_height, putchr); +} + +/* + * Home cursor (move to upper left corner of screen). + */ +home() +{ + tputs(sc_home, 1, putchr); +} + +/* + * Add a blank line (called with cursor at home). + * Should scroll the display down. + */ +add_line() +{ + tputs(sc_addline, sc_height, putchr); +} + +int short_file; /* if file less than a screen */ +lower_left() +{ + if (short_file) { + putchr('\r'); + flush(); + } + else + tputs(sc_lower_left, 1, putchr); +} + +/* + * Ring the terminal bell. + */ +bell() +{ + putchr('\7'); +} + +/* + * Clear the screen. + */ +clear() +{ + if (mode_flags & M_SO) + so_exit(); + if (mode_flags & M_UL) + ul_exit(); + if (mode_flags & M_BO) + bo_exit(); + tputs(sc_clear, sc_height, putchr); +} + +/* + * Clear from the cursor to the end of the cursor's line. + * {{ This must not move the cursor. }} + */ +clear_eol() +{ + if (mode_flags & M_SO) + so_exit(); + if (mode_flags & M_UL) + ul_exit(); + if (mode_flags & M_BO) + bo_exit(); + tputs(sc_eol_clear, 1, putchr); +} + +/* + * Begin "standout" (bold, underline, or whatever). + */ +so_enter() +{ + tputs(sc_s_in, 1, putchr); + mode_flags |= M_SO; +} + +/* + * End "standout". + */ +so_exit() +{ + tputs(sc_s_out, 1, putchr); + mode_flags &= ~M_SO; +} + +/* + * Begin "underline" (hopefully real underlining, + * otherwise whatever the terminal provides). + */ +ul_enter() +{ + tputs(sc_u_in, 1, putchr); + mode_flags |= M_UL; +} + +/* + * End "underline". + */ +ul_exit() +{ + tputs(sc_u_out, 1, putchr); + mode_flags &= ~M_UL; +} + +/* + * Begin "bold" + */ +bo_enter() +{ + tputs(sc_b_in, 1, putchr); + mode_flags |= M_BO; +} + +/* + * End "bold". + */ +bo_exit() +{ + tputs(sc_b_out, 1, putchr); + mode_flags &= ~M_BO; +} + +/* + * Erase the character to the left of the cursor + * and move the cursor left. + */ +backspace() +{ + /* + * Try to erase the previous character by overstriking with a space. + */ + tputs(sc_backspace, 1, putchr); + putchr(' '); + tputs(sc_backspace, 1, putchr); +} + +/* + * Output a plain backspace, without erasing the previous char. + */ +putbs() +{ + tputs(sc_backspace, 1, putchr); +} |