diff options
author | Niklas Hallqvist <niklas@cvs.openbsd.org> | 1995-12-22 16:47:20 +0000 |
---|---|---|
committer | Niklas Hallqvist <niklas@cvs.openbsd.org> | 1995-12-22 16:47:20 +0000 |
commit | ec18f98a8dd00dbc9bdc71858b395712564182bf (patch) | |
tree | f31db27a0d475ab3bb7d62153ec5f12c4d691b2e /gnu/usr.bin/texinfo/info/terminal.c | |
parent | 0ea8ce66e7dba7c3b169b0e15553a973df9e3570 (diff) |
Import of texinfo-3.6 from FSF
Diffstat (limited to 'gnu/usr.bin/texinfo/info/terminal.c')
-rw-r--r-- | gnu/usr.bin/texinfo/info/terminal.c | 745 |
1 files changed, 745 insertions, 0 deletions
diff --git a/gnu/usr.bin/texinfo/info/terminal.c b/gnu/usr.bin/texinfo/info/terminal.c new file mode 100644 index 00000000000..e51c8765141 --- /dev/null +++ b/gnu/usr.bin/texinfo/info/terminal.c @@ -0,0 +1,745 @@ +/* terminal.c -- How to handle the physical terminal for Info. */ + +/* This file is part of GNU Info, a program for reading online documentation + stored in Info format. + + This file has appeared in prior works by the Free Software Foundation; + thus it carries copyright dates from 1988 through 1993. + + Copyright (C) 1988, 1989, 1990, 1991, 1992, 1993 Free Software + Foundation, Inc. + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2, or (at your option) + any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + + Written by Brian Fox (bfox@ai.mit.edu). */ + +#include <stdio.h> +#include <sys/types.h> +#include "terminal.h" +#include "termdep.h" + +extern void *xmalloc (), *xrealloc (); + +/* The Unix termcap interface code. */ + +extern int tgetnum (), tgetflag (), tgetent (); +extern char *tgetstr (), *tgoto (); +extern char *getenv (); +extern void tputs (); + +/* Function "hooks". If you make one of these point to a function, that + function is called when appropriate instead of its namesake. Your + function is called with exactly the same arguments that were passed + to the namesake function. */ +VFunction *terminal_begin_inverse_hook = (VFunction *)NULL; +VFunction *terminal_end_inverse_hook = (VFunction *)NULL; +VFunction *terminal_prep_terminal_hook = (VFunction *)NULL; +VFunction *terminal_unprep_terminal_hook = (VFunction *)NULL; +VFunction *terminal_up_line_hook = (VFunction *)NULL; +VFunction *terminal_down_line_hook = (VFunction *)NULL; +VFunction *terminal_clear_screen_hook = (VFunction *)NULL; +VFunction *terminal_clear_to_eol_hook = (VFunction *)NULL; +VFunction *terminal_get_screen_size_hook = (VFunction *)NULL; +VFunction *terminal_goto_xy_hook = (VFunction *)NULL; +VFunction *terminal_initialize_terminal_hook = (VFunction *)NULL; +VFunction *terminal_new_terminal_hook = (VFunction *)NULL; +VFunction *terminal_put_text_hook = (VFunction *)NULL; +VFunction *terminal_ring_bell_hook = (VFunction *)NULL; +VFunction *terminal_write_chars_hook = (VFunction *)NULL; +VFunction *terminal_scroll_terminal_hook = (VFunction *)NULL; + +/* **************************************************************** */ +/* */ +/* Terminal and Termcap */ +/* */ +/* **************************************************************** */ + +/* On Solaris2, sys/types.h #includes sys/reg.h, which #defines PC. + Unfortunately, PC is a global variable used by the termcap library. */ +#undef PC + +/* TERMCAP requires these variables, whether we access them or not. */ +char PC; +char *BC, *UP; +short ospeed; + +/* A buffer which holds onto the current terminal description, and a pointer + used to float within it. */ +static char *term_buffer = (char *)NULL; +static char *term_string_buffer = (char *)NULL; + +/* Some strings to control terminal actions. These are output by tputs (). */ +static char *term_goto, *term_clreol, *term_cr, *term_clrpag; +static char *term_begin_use, *term_end_use; +static char *term_AL, *term_DL, *term_al, *term_dl; + +/* How to go up a line. */ +static char *term_up; + +/* How to go down a line. */ +static char *term_dn; + +/* An audible bell, if the terminal can be made to make noise. */ +static char *audible_bell; + +/* A visible bell, if the terminal can be made to flash the screen. */ +static char *visible_bell; + +/* The string to write to turn on the meta key, if this term has one. */ +static char *term_mm; + +/* The string to write to turn off the meta key, if this term has one. */ +static char *term_mo; + +/* The string to turn on inverse mode, if this term has one. */ +static char *term_invbeg; + +/* The string to turn off inverse mode, if this term has one. */ +static char *term_invend; + +static void +output_character_function (c) + int c; +{ + putc (c, stdout); +} + +/* Macro to send STRING to the terminal. */ +#define send_to_terminal(string) \ + do { \ + if (string) \ + tputs (string, 1, output_character_function); \ + } while (0) + +/* Tell the terminal that we will be doing cursor addressable motion. */ +static void +terminal_begin_using_terminal () +{ + send_to_terminal (term_begin_use); +} + +/* Tell the terminal that we will not be doing any more cursor addressable + motion. */ +static void +terminal_end_using_terminal () +{ + send_to_terminal (term_end_use); +} + +/* **************************************************************** */ +/* */ +/* Necessary Terminal Functions */ +/* */ +/* **************************************************************** */ + +/* The functions and variables on this page implement the user visible + portion of the terminal interface. */ + +/* The width and height of the terminal. */ +int screenwidth, screenheight; + +/* Non-zero means this terminal can't really do anything. */ +int terminal_is_dumb_p = 0; + +/* Non-zero means that this terminal has a meta key. */ +int terminal_has_meta_p = 0; + +/* Non-zero means that this terminal can produce a visible bell. */ +int terminal_has_visible_bell_p = 0; + +/* Non-zero means to use that visible bell if at all possible. */ +int terminal_use_visible_bell_p = 0; + +/* Non-zero means that the terminal can do scrolling. */ +int terminal_can_scroll = 0; + +/* The key sequences output by the arrow keys, if this terminal has any. */ +char *term_ku, *term_kd, *term_kr, *term_kl; + +/* Move the cursor to the terminal location of X and Y. */ +void +terminal_goto_xy (x, y) + int x, y; +{ + if (terminal_goto_xy_hook) + (*terminal_goto_xy_hook) (x, y); + else + { + if (term_goto) + tputs (tgoto (term_goto, x, y), 1, output_character_function); + } +} + +/* Print STRING to the terminal at the current position. */ +void +terminal_put_text (string) + char *string; +{ + if (terminal_put_text_hook) + (*terminal_put_text_hook) (string); + else + { + printf ("%s", string); + } +} + +/* Print NCHARS from STRING to the terminal at the current position. */ +void +terminal_write_chars (string, nchars) + char *string; + int nchars; +{ + if (terminal_write_chars_hook) + (*terminal_write_chars_hook) (string, nchars); + else + { + if (nchars) + fwrite (string, 1, nchars, stdout); + } +} + +/* Clear from the current position of the cursor to the end of the line. */ +void +terminal_clear_to_eol () +{ + if (terminal_clear_to_eol_hook) + (*terminal_clear_to_eol_hook) (); + else + { + send_to_terminal (term_clreol); + } +} + +/* Clear the entire terminal screen. */ +void +terminal_clear_screen () +{ + if (terminal_clear_screen_hook) + (*terminal_clear_screen_hook) (); + else + { + send_to_terminal (term_clrpag); + } +} + +/* Move the cursor up one line. */ +void +terminal_up_line () +{ + if (terminal_up_line_hook) + (*terminal_up_line_hook) (); + else + { + send_to_terminal (term_up); + } +} + +/* Move the cursor down one line. */ +void +terminal_down_line () +{ + if (terminal_down_line_hook) + (*terminal_down_line_hook) (); + else + { + send_to_terminal (term_dn); + } +} + +/* Turn on reverse video if possible. */ +void +terminal_begin_inverse () +{ + if (terminal_begin_inverse_hook) + (*terminal_begin_inverse_hook) (); + else + { + send_to_terminal (term_invbeg); + } +} + +/* Turn off reverse video if possible. */ +void +terminal_end_inverse () +{ + if (terminal_end_inverse_hook) + (*terminal_end_inverse_hook) (); + else + { + send_to_terminal (term_invend); + } +} + +/* Ring the terminal bell. The bell is run visibly if it both has one and + terminal_use_visible_bell_p is non-zero. */ +void +terminal_ring_bell () +{ + if (terminal_ring_bell_hook) + (*terminal_ring_bell_hook) (); + else + { + if (terminal_has_visible_bell_p && terminal_use_visible_bell_p) + send_to_terminal (visible_bell); + else + send_to_terminal (audible_bell); + } +} + +/* At the line START, delete COUNT lines from the terminal display. */ +static void +terminal_delete_lines (start, count) + int start, count; +{ + int lines; + + /* Normalize arguments. */ + if (start < 0) + start = 0; + + lines = screenheight - start; + terminal_goto_xy (0, start); + if (term_DL) + tputs (tgoto (term_DL, 0, count), lines, output_character_function); + else + { + while (count--) + tputs (term_dl, lines, output_character_function); + } + + fflush (stdout); +} + +/* At the line START, insert COUNT lines in the terminal display. */ +static void +terminal_insert_lines (start, count) + int start, count; +{ + int lines; + + /* Normalize arguments. */ + if (start < 0) + start = 0; + + lines = screenheight - start; + terminal_goto_xy (0, start); + + if (term_AL) + tputs (tgoto (term_AL, 0, count), lines, output_character_function); + else + { + while (count--) + tputs (term_al, lines, output_character_function); + } + + fflush (stdout); +} + +/* Scroll an area of the terminal, starting with the region from START + to END, AMOUNT lines. If AMOUNT is negative, the lines are scrolled + towards the top of the screen, else they are scrolled towards the + bottom of the screen. */ +void +terminal_scroll_terminal (start, end, amount) + int start, end, amount; +{ + if (!terminal_can_scroll) + return; + + /* Any scrolling at all? */ + if (amount == 0) + return; + + if (terminal_scroll_terminal_hook) + (*terminal_scroll_terminal_hook) (start, end, amount); + else + { + /* If we are scrolling down, delete AMOUNT lines at END. Then insert + AMOUNT lines at START. */ + if (amount > 0) + { + terminal_delete_lines (end, amount); + terminal_insert_lines (start, amount); + } + + /* If we are scrolling up, delete AMOUNT lines before START. This + actually does the upwards scroll. Then, insert AMOUNT lines + after the already scrolled region (i.e., END - AMOUNT). */ + if (amount < 0) + { + int abs_amount = -amount; + terminal_delete_lines (start - abs_amount, abs_amount); + terminal_insert_lines (end - abs_amount, abs_amount); + } + } +} + +/* Re-initialize the terminal considering that the TERM/TERMCAP variable + has changed. */ +void +terminal_new_terminal (terminal_name) + char *terminal_name; +{ + if (terminal_new_terminal_hook) + (*terminal_new_terminal_hook) (terminal_name); + else + { + terminal_initialize_terminal (terminal_name); + } +} + +/* Set the global variables SCREENWIDTH and SCREENHEIGHT. */ +void +terminal_get_screen_size () +{ + if (terminal_get_screen_size_hook) + (*terminal_get_screen_size_hook) (); + else + { + screenwidth = screenheight = 0; + +#if defined (TIOCGWINSZ) + { + struct winsize window_size; + + if (ioctl (fileno (stdout), TIOCGWINSZ, &window_size) == 0) + { + screenwidth = (int) window_size.ws_col; + screenheight = (int) window_size.ws_row; + } + } +#endif /* TIOCGWINSZ */ + + /* Environment variable COLUMNS overrides setting of "co". */ + if (screenwidth <= 0) + { + char *sw = getenv ("COLUMNS"); + + if (sw) + screenwidth = atoi (sw); + + if (screenwidth <= 0) + screenwidth = tgetnum ("co"); + } + + /* Environment variable LINES overrides setting of "li". */ + if (screenheight <= 0) + { + char *sh = getenv ("LINES"); + + if (sh) + screenheight = atoi (sh); + + if (screenheight <= 0) + screenheight = tgetnum ("li"); + } + + /* If all else fails, default to 80x24 terminal. */ + if (screenwidth <= 0) + screenwidth = 80; + + if (screenheight <= 0) + screenheight = 24; + } +} + +/* Initialize the terminal which is known as TERMINAL_NAME. If this terminal + doesn't have cursor addressability, TERMINAL_IS_DUMB_P becomes non-zero. + The variables SCREENHEIGHT and SCREENWIDTH are set to the dimensions that + this terminal actually has. The variable TERMINAL_HAS_META_P becomes non- + zero if this terminal supports a Meta key. Finally, the terminal screen is + cleared. */ +void +terminal_initialize_terminal (terminal_name) + char *terminal_name; +{ + char *term, *buffer; + + terminal_is_dumb_p = 0; + + if (terminal_initialize_terminal_hook) + { + (*terminal_initialize_terminal_hook) (terminal_name); + return; + } + + term = terminal_name ? terminal_name : getenv ("TERM"); + + if (!term_string_buffer) + term_string_buffer = (char *)xmalloc (2048); + + if (!term_buffer) + term_buffer = (char *)xmalloc (2048); + + buffer = term_string_buffer; + + term_clrpag = term_cr = term_clreol = (char *)NULL; + + if (!term) + term = "dumb"; + + if (tgetent (term_buffer, term) <= 0) + { + terminal_is_dumb_p = 1; + screenwidth = 80; + screenheight = 24; + term_cr = "\r"; + term_up = term_dn = audible_bell = visible_bell = (char *)NULL; + term_ku = term_kd = term_kl = term_kr = (char *)NULL; + return; + } + + BC = tgetstr ("pc", &buffer); + PC = BC ? *BC : 0; + +#if defined (TIOCGETP) + { + struct sgttyb sg; + + if (ioctl (fileno (stdout), TIOCGETP, &sg) != -1) + ospeed = sg.sg_ospeed; + else + ospeed = B9600; + } +#else + ospeed = B9600; +#endif /* !TIOCGETP */ + + term_cr = tgetstr ("cr", &buffer); + term_clreol = tgetstr ("ce", &buffer); + term_clrpag = tgetstr ("cl", &buffer); + term_goto = tgetstr ("cm", &buffer); + + /* Find out about this terminals scrolling capability. */ + term_AL = tgetstr ("AL", &buffer); + term_DL = tgetstr ("DL", &buffer); + term_al = tgetstr ("al", &buffer); + term_dl = tgetstr ("dl", &buffer); + + terminal_can_scroll = ((term_AL || term_al) && (term_DL || term_dl)); + + term_invbeg = tgetstr ("mr", &buffer); + if (term_invbeg) + term_invend = tgetstr ("me", &buffer); + else + term_invend = (char *)NULL; + + if (!term_cr) + term_cr = "\r"; + + terminal_get_screen_size (); + + term_up = tgetstr ("up", &buffer); + term_dn = tgetstr ("dn", &buffer); + visible_bell = tgetstr ("vb", &buffer); + terminal_has_visible_bell_p = (visible_bell != (char *)NULL); + audible_bell = tgetstr ("bl", &buffer); + if (!audible_bell) + audible_bell = "\007"; + term_begin_use = tgetstr ("ti", &buffer); + term_end_use = tgetstr ("te", &buffer); + + /* Check to see if this terminal has a meta key. */ + terminal_has_meta_p = (tgetflag ("km") || tgetflag ("MT")); + if (terminal_has_meta_p) + { + term_mm = tgetstr ("mm", &buffer); + term_mo = tgetstr ("mo", &buffer); + } + else + { + term_mm = (char *)NULL; + term_mo = (char *)NULL; + } + + /* Attempt to find the arrow keys. */ + term_ku = tgetstr ("ku", &buffer); + term_kd = tgetstr ("kd", &buffer); + term_kr = tgetstr ("kr", &buffer); + term_kl = tgetstr ("kl", &buffer); + + /* If this terminal is not cursor addressable, then it is really dumb. */ + if (!term_goto) + terminal_is_dumb_p = 1; + + terminal_begin_using_terminal (); +} + +/* **************************************************************** */ +/* */ +/* How to Read Characters From the Terminal */ +/* */ +/* **************************************************************** */ + +#if defined (TIOCGETC) +/* A buffer containing the terminal interrupt characters upon entry + to Info. */ +struct tchars original_tchars; +#endif + +#if defined (TIOCGLTC) +/* A buffer containing the local terminal mode characters upon entry + to Info. */ +struct ltchars original_ltchars; +#endif + +#if defined (HAVE_TERMIO_H) +/* A buffer containing the terminal mode flags upon entry to info. */ +struct termio original_termio, ttybuff; +#else /* !HAVE_TERMIO_H */ +/* Buffers containing the terminal mode flags upon entry to info. */ +int original_tty_flags = 0; +int original_lmode; +struct sgttyb ttybuff; +#endif /* !HAVE_TERMIO_H */ + +/* Prepare to start using the terminal to read characters singly. */ +void +terminal_prep_terminal () +{ + int tty; + + if (terminal_prep_terminal_hook) + { + (*terminal_prep_terminal_hook) (); + return; + } + + tty = fileno (stdin); + +#if defined (HAVE_TERMIO_H) + ioctl (tty, TCGETA, &original_termio); + ioctl (tty, TCGETA, &ttybuff); + ttybuff.c_iflag &= (~ISTRIP & ~INLCR & ~IGNCR & ~ICRNL & ~IXON); + ttybuff.c_oflag &= (~ONLCR & ~OCRNL); + ttybuff.c_lflag &= (~ICANON & ~ECHO); + + ttybuff.c_cc[VMIN] = 1; + ttybuff.c_cc[VTIME] = 0; + + if (ttybuff.c_cc[VINTR] == '\177') + ttybuff.c_cc[VINTR] = -1; + + if (ttybuff.c_cc[VQUIT] == '\177') + ttybuff.c_cc[VQUIT] = -1; + + ioctl (tty, TCSETA, &ttybuff); + +#else /* !HAVE_TERMIO_H */ + + ioctl (tty, TIOCGETP, &ttybuff); + + if (!original_tty_flags) + original_tty_flags = ttybuff.sg_flags; + + /* Make this terminal pass 8 bits around while we are using it. */ +#if defined (PASS8) + ttybuff.sg_flags |= PASS8; +#endif /* PASS8 */ + +#if defined (TIOCLGET) && defined (LPASS8) + { + int flags; + ioctl (tty, TIOCLGET, &flags); + original_lmode = flags; + flags |= LPASS8; + ioctl (tty, TIOCLSET, &flags); + } +#endif /* TIOCLGET && LPASS8 */ + +#if defined (TIOCGETC) + { + struct tchars temp; + + ioctl (tty, TIOCGETC, &original_tchars); + temp = original_tchars; + + /* C-s and C-q. */ + temp.t_startc = temp.t_stopc = -1; + + /* Often set to C-d. */ + temp.t_eofc = -1; + + /* If the a quit or interrupt character conflicts with one of our + commands, then make it go away. */ + if (temp.t_intrc == '\177') + temp.t_intrc = -1; + + if (temp.t_quitc == '\177') + temp.t_quitc = -1; + + ioctl (tty, TIOCSETC, &temp); + } +#endif /* TIOCGETC */ + +#if defined (TIOCGLTC) + { + struct ltchars temp; + + ioctl (tty, TIOCGLTC, &original_ltchars); + temp = original_ltchars; + + /* Make the interrupt keys go away. Just enough to make people happy. */ + temp.t_lnextc = -1; /* C-v. */ + temp.t_dsuspc = -1; /* C-y. */ + temp.t_flushc = -1; /* C-o. */ + ioctl (tty, TIOCSLTC, &temp); + } +#endif /* TIOCGLTC */ + + ttybuff.sg_flags &= ~ECHO; + ttybuff.sg_flags |= CBREAK; + ioctl (tty, TIOCSETN, &ttybuff); +#endif /* !HAVE_TERMIO_H */ +} + +/* Restore the tty settings back to what they were before we started using + this terminal. */ +void +terminal_unprep_terminal () +{ + int tty; + + if (terminal_unprep_terminal_hook) + { + (*terminal_unprep_terminal_hook) (); + return; + } + + tty = fileno (stdin); + +#if defined (HAVE_TERMIO_H) + ioctl (tty, TCSETA, &original_termio); +#else /* !HAVE_TERMIO_H */ + ioctl (tty, TIOCGETP, &ttybuff); + ttybuff.sg_flags = original_tty_flags; + ioctl (tty, TIOCSETN, &ttybuff); + +#if defined (TIOCGETC) + ioctl (tty, TIOCSETC, &original_tchars); +#endif /* TIOCGETC */ + +#if defined (TIOCGLTC) + ioctl (tty, TIOCSLTC, &original_ltchars); +#endif /* TIOCGLTC */ + +#if defined (TIOCLGET) && defined (LPASS8) + ioctl (tty, TIOCLSET, &original_lmode); +#endif /* TIOCLGET && LPASS8 */ + +#endif /* !HAVE_TERMIO_H */ + terminal_end_using_terminal (); +} + |