1114477Sru/* terminal.c -- how to handle the physical terminal for Info.
2146520Sru   $Id: terminal.c,v 1.3 2004/04/11 17:56:46 karl Exp $
321495Sjmacd
4114477Sru   Copyright (C) 1988, 1989, 1990, 1991, 1992, 1993, 1996, 1997, 1998,
5146520Sru   1999, 2001, 2002, 2004 Free Software Foundation, Inc.
621495Sjmacd
721495Sjmacd   This program is free software; you can redistribute it and/or modify
821495Sjmacd   it under the terms of the GNU General Public License as published by
921495Sjmacd   the Free Software Foundation; either version 2, or (at your option)
1021495Sjmacd   any later version.
1121495Sjmacd
1221495Sjmacd   This program is distributed in the hope that it will be useful,
1321495Sjmacd   but WITHOUT ANY WARRANTY; without even the implied warranty of
1421495Sjmacd   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
1521495Sjmacd   GNU General Public License for more details.
1621495Sjmacd
1721495Sjmacd   You should have received a copy of the GNU General Public License
1821495Sjmacd   along with this program; if not, write to the Free Software
1921495Sjmacd   Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
2021495Sjmacd
21146520Sru   Originally written by Brian Fox (bfox@ai.mit.edu). */
2221495Sjmacd
2342664Smarkm#include "info.h"
2421495Sjmacd#include "terminal.h"
2521495Sjmacd#include "termdep.h"
2621495Sjmacd
2742664Smarkm#include <sys/types.h>
2842664Smarkm#include <signal.h>
2921495Sjmacd
3021495Sjmacd/* The Unix termcap interface code. */
3142664Smarkm#ifdef HAVE_NCURSES_TERMCAP_H
3242664Smarkm#include <ncurses/termcap.h>
3342664Smarkm#else
3442664Smarkm#ifdef HAVE_TERMCAP_H
3542664Smarkm#include <termcap.h>
3642664Smarkm#else
3742664Smarkm/* On Solaris2, sys/types.h #includes sys/reg.h, which #defines PC.
3842664Smarkm   Unfortunately, PC is a global variable used by the termcap library. */
3942664Smarkm#undef PC
4021495Sjmacd
4142664Smarkm/* Termcap requires these variables, whether we access them or not. */
4242664Smarkmchar *BC, *UP;
4342664Smarkmchar PC;      /* Pad character */
4442664Smarkmshort ospeed; /* Terminal output baud rate */
4521495Sjmacdextern int tgetnum (), tgetflag (), tgetent ();
4621495Sjmacdextern char *tgetstr (), *tgoto ();
4721495Sjmacdextern void tputs ();
4842664Smarkm#endif /* not HAVE_TERMCAP_H */
4942664Smarkm#endif /* not HAVE_NCURSES_TERMCAP_H */
5021495Sjmacd
5121495Sjmacd/* Function "hooks".  If you make one of these point to a function, that
5221495Sjmacd   function is called when appropriate instead of its namesake.  Your
5321495Sjmacd   function is called with exactly the same arguments that were passed
5421495Sjmacd   to the namesake function. */
5521495SjmacdVFunction *terminal_begin_inverse_hook = (VFunction *)NULL;
5621495SjmacdVFunction *terminal_end_inverse_hook = (VFunction *)NULL;
5721495SjmacdVFunction *terminal_prep_terminal_hook = (VFunction *)NULL;
5821495SjmacdVFunction *terminal_unprep_terminal_hook = (VFunction *)NULL;
5921495SjmacdVFunction *terminal_up_line_hook = (VFunction *)NULL;
6021495SjmacdVFunction *terminal_down_line_hook = (VFunction *)NULL;
6121495SjmacdVFunction *terminal_clear_screen_hook = (VFunction *)NULL;
6221495SjmacdVFunction *terminal_clear_to_eol_hook = (VFunction *)NULL;
6321495SjmacdVFunction *terminal_get_screen_size_hook = (VFunction *)NULL;
6421495SjmacdVFunction *terminal_goto_xy_hook = (VFunction *)NULL;
6521495SjmacdVFunction *terminal_initialize_terminal_hook = (VFunction *)NULL;
6621495SjmacdVFunction *terminal_new_terminal_hook = (VFunction *)NULL;
6721495SjmacdVFunction *terminal_put_text_hook = (VFunction *)NULL;
6821495SjmacdVFunction *terminal_ring_bell_hook = (VFunction *)NULL;
6921495SjmacdVFunction *terminal_write_chars_hook = (VFunction *)NULL;
7021495SjmacdVFunction *terminal_scroll_terminal_hook = (VFunction *)NULL;
7121495Sjmacd
7221495Sjmacd/* **************************************************************** */
7342664Smarkm/*                                                                  */
7442664Smarkm/*                      Terminal and Termcap                        */
7542664Smarkm/*                                                                  */
7621495Sjmacd/* **************************************************************** */
7721495Sjmacd
7821495Sjmacd/* A buffer which holds onto the current terminal description, and a pointer
7956164Sru   used to float within it.  And the name of the terminal.  */
8056164Srustatic char *term_buffer = NULL;
8156164Srustatic char *term_string_buffer = NULL;
8256164Srustatic char *term_name;
8321495Sjmacd
8421495Sjmacd/* Some strings to control terminal actions.  These are output by tputs (). */
8521495Sjmacdstatic char *term_goto, *term_clreol, *term_cr, *term_clrpag;
8621495Sjmacdstatic char *term_begin_use, *term_end_use;
8721495Sjmacdstatic char *term_AL, *term_DL, *term_al, *term_dl;
8821495Sjmacd
8942664Smarkmstatic char *term_keypad_on, *term_keypad_off;
9042664Smarkm
9121495Sjmacd/* How to go up a line. */
9221495Sjmacdstatic char *term_up;
9321495Sjmacd
9421495Sjmacd/* How to go down a line. */
9521495Sjmacdstatic char *term_dn;
9621495Sjmacd
9721495Sjmacd/* An audible bell, if the terminal can be made to make noise. */
9821495Sjmacdstatic char *audible_bell;
9921495Sjmacd
10021495Sjmacd/* A visible bell, if the terminal can be made to flash the screen. */
10121495Sjmacdstatic char *visible_bell;
10221495Sjmacd
10321495Sjmacd/* The string to write to turn on the meta key, if this term has one. */
10421495Sjmacdstatic char *term_mm;
10521495Sjmacd
10621495Sjmacd/* The string to turn on inverse mode, if this term has one. */
10721495Sjmacdstatic char *term_invbeg;
10821495Sjmacd
10921495Sjmacd/* The string to turn off inverse mode, if this term has one. */
11021495Sjmacdstatic char *term_invend;
11121495Sjmacd
11242664Smarkm/* Although I can't find any documentation that says this is supposed to
11342664Smarkm   return its argument, all the code I've looked at (termutils, less)
11442664Smarkm   does so, so fine.  */
11542664Smarkmstatic int
116146520Sruoutput_character_function (int c)
11721495Sjmacd{
11821495Sjmacd  putc (c, stdout);
11942664Smarkm  return c;
12021495Sjmacd}
12121495Sjmacd
12221495Sjmacd/* Macro to send STRING to the terminal. */
12321495Sjmacd#define send_to_terminal(string) \
12421495Sjmacd  do { \
12521495Sjmacd    if (string) \
12621495Sjmacd      tputs (string, 1, output_character_function); \
12721495Sjmacd     } while (0)
12821495Sjmacd
12942664Smarkm/* Tell the terminal that we will be doing cursor addressable motion.  */
13021495Sjmacdstatic void
131146520Sruterminal_begin_using_terminal (void)
13221495Sjmacd{
133146520Sru  RETSIGTYPE (*sigsave) (int signum);
13442664Smarkm
13542664Smarkm  if (term_keypad_on)
13642664Smarkm      send_to_terminal (term_keypad_on);
13742664Smarkm
13842664Smarkm  if (!term_begin_use || !*term_begin_use)
13942664Smarkm    return;
14042664Smarkm
14142664Smarkm#ifdef SIGWINCH
14242664Smarkm  sigsave = signal (SIGWINCH, SIG_IGN);
14342664Smarkm#endif
14442664Smarkm
14521495Sjmacd  send_to_terminal (term_begin_use);
14642664Smarkm  fflush (stdout);
14756164Sru  if (STREQ (term_name, "sun-cmd"))
14856164Sru    /* Without this fflush and sleep, running info in a shelltool or
14956164Sru       cmdtool (TERM=sun-cmd) with scrollbars loses -- the scrollbars are
15056164Sru       not restored properly.
15156164Sru       From: strube@physik3.gwdg.de (Hans Werner Strube).  */
15256164Sru    sleep (1);
15342664Smarkm
15442664Smarkm#ifdef SIGWINCH
15542664Smarkm  signal (SIGWINCH, sigsave);
15642664Smarkm#endif
15721495Sjmacd}
15821495Sjmacd
15942664Smarkm/* Tell the terminal that we will not be doing any more cursor
16042664Smarkm   addressable motion. */
16121495Sjmacdstatic void
162146520Sruterminal_end_using_terminal (void)
16321495Sjmacd{
164146520Sru  RETSIGTYPE (*sigsave) (int signum);
16542664Smarkm
16642664Smarkm  if (term_keypad_off)
16742664Smarkm      send_to_terminal (term_keypad_off);
16842664Smarkm
16942664Smarkm  if (!term_end_use || !*term_end_use)
17042664Smarkm    return;
17142664Smarkm
17242664Smarkm#ifdef SIGWINCH
17342664Smarkm  sigsave = signal (SIGWINCH, SIG_IGN);
17442664Smarkm#endif
17542664Smarkm
17621495Sjmacd  send_to_terminal (term_end_use);
17742664Smarkm  fflush (stdout);
17856164Sru  if (STREQ (term_name, "sun-cmd"))
17956164Sru    /* See comments at other sleep.  */
18056164Sru    sleep (1);
18142664Smarkm
18242664Smarkm#ifdef SIGWINCH
18342664Smarkm  signal (SIGWINCH, sigsave);
18442664Smarkm#endif
18521495Sjmacd}
18621495Sjmacd
18721495Sjmacd/* **************************************************************** */
18842664Smarkm/*                                                                  */
18942664Smarkm/*                   Necessary Terminal Functions                   */
19042664Smarkm/*                                                                  */
19121495Sjmacd/* **************************************************************** */
19221495Sjmacd
19321495Sjmacd/* The functions and variables on this page implement the user visible
19421495Sjmacd   portion of the terminal interface. */
19521495Sjmacd
19621495Sjmacd/* The width and height of the terminal. */
19721495Sjmacdint screenwidth, screenheight;
19821495Sjmacd
19921495Sjmacd/* Non-zero means this terminal can't really do anything. */
20021495Sjmacdint terminal_is_dumb_p = 0;
20121495Sjmacd
20221495Sjmacd/* Non-zero means that this terminal has a meta key. */
20321495Sjmacdint terminal_has_meta_p = 0;
20421495Sjmacd
20521495Sjmacd/* Non-zero means that this terminal can produce a visible bell. */
20621495Sjmacdint terminal_has_visible_bell_p = 0;
20721495Sjmacd
20821495Sjmacd/* Non-zero means to use that visible bell if at all possible. */
20921495Sjmacdint terminal_use_visible_bell_p = 0;
21021495Sjmacd
21121495Sjmacd/* Non-zero means that the terminal can do scrolling. */
21221495Sjmacdint terminal_can_scroll = 0;
21321495Sjmacd
21421495Sjmacd/* The key sequences output by the arrow keys, if this terminal has any. */
21593142Sruchar *term_ku = NULL;
21693142Sruchar *term_kd = NULL;
21793142Sruchar *term_kr = NULL;
21893142Sruchar *term_kl = NULL;
21993142Sruchar *term_kP = NULL;   /* page-up */
22093142Sruchar *term_kN = NULL;   /* page-down */
22193142Sruchar *term_kh = NULL;	/* home */
22293142Sruchar *term_ke = NULL;	/* end */
22393142Sruchar *term_kD = NULL;	/* delete */
22493142Sruchar *term_ki = NULL;	/* ins */
22593142Sruchar *term_kx = NULL;	/* del */
22621495Sjmacd
22721495Sjmacd/* Move the cursor to the terminal location of X and Y. */
22821495Sjmacdvoid
229146520Sruterminal_goto_xy (int x, int y)
23021495Sjmacd{
23121495Sjmacd  if (terminal_goto_xy_hook)
23221495Sjmacd    (*terminal_goto_xy_hook) (x, y);
23321495Sjmacd  else
23421495Sjmacd    {
23521495Sjmacd      if (term_goto)
23642664Smarkm        tputs (tgoto (term_goto, x, y), 1, output_character_function);
23721495Sjmacd    }
23821495Sjmacd}
23921495Sjmacd
24021495Sjmacd/* Print STRING to the terminal at the current position. */
24121495Sjmacdvoid
242146520Sruterminal_put_text (char *string)
24321495Sjmacd{
24421495Sjmacd  if (terminal_put_text_hook)
24521495Sjmacd    (*terminal_put_text_hook) (string);
24621495Sjmacd  else
24721495Sjmacd    {
24821495Sjmacd      printf ("%s", string);
24921495Sjmacd    }
25021495Sjmacd}
25121495Sjmacd
25221495Sjmacd/* Print NCHARS from STRING to the terminal at the current position. */
25321495Sjmacdvoid
254146520Sruterminal_write_chars (char *string, int nchars)
25521495Sjmacd{
25621495Sjmacd  if (terminal_write_chars_hook)
25721495Sjmacd    (*terminal_write_chars_hook) (string, nchars);
25821495Sjmacd  else
25921495Sjmacd    {
26021495Sjmacd      if (nchars)
26142664Smarkm        fwrite (string, 1, nchars, stdout);
26221495Sjmacd    }
26321495Sjmacd}
26421495Sjmacd
26521495Sjmacd/* Clear from the current position of the cursor to the end of the line. */
26621495Sjmacdvoid
267146520Sruterminal_clear_to_eol (void)
26821495Sjmacd{
26921495Sjmacd  if (terminal_clear_to_eol_hook)
27021495Sjmacd    (*terminal_clear_to_eol_hook) ();
27121495Sjmacd  else
27221495Sjmacd    {
27321495Sjmacd      send_to_terminal (term_clreol);
27421495Sjmacd    }
27521495Sjmacd}
27621495Sjmacd
27721495Sjmacd/* Clear the entire terminal screen. */
27821495Sjmacdvoid
279146520Sruterminal_clear_screen (void)
28021495Sjmacd{
28121495Sjmacd  if (terminal_clear_screen_hook)
28221495Sjmacd    (*terminal_clear_screen_hook) ();
28321495Sjmacd  else
28421495Sjmacd    {
28521495Sjmacd      send_to_terminal (term_clrpag);
28621495Sjmacd    }
28721495Sjmacd}
28821495Sjmacd
28921495Sjmacd/* Move the cursor up one line. */
29021495Sjmacdvoid
291146520Sruterminal_up_line (void)
29221495Sjmacd{
29321495Sjmacd  if (terminal_up_line_hook)
29421495Sjmacd    (*terminal_up_line_hook) ();
29521495Sjmacd  else
29621495Sjmacd    {
29721495Sjmacd      send_to_terminal (term_up);
29821495Sjmacd    }
29921495Sjmacd}
30021495Sjmacd
30121495Sjmacd/* Move the cursor down one line. */
30221495Sjmacdvoid
303146520Sruterminal_down_line (void)
30421495Sjmacd{
30521495Sjmacd  if (terminal_down_line_hook)
30621495Sjmacd    (*terminal_down_line_hook) ();
30721495Sjmacd  else
30821495Sjmacd    {
30921495Sjmacd      send_to_terminal (term_dn);
31021495Sjmacd    }
31121495Sjmacd}
31221495Sjmacd
31321495Sjmacd/* Turn on reverse video if possible. */
31421495Sjmacdvoid
315146520Sruterminal_begin_inverse (void)
31621495Sjmacd{
31721495Sjmacd  if (terminal_begin_inverse_hook)
31821495Sjmacd    (*terminal_begin_inverse_hook) ();
31921495Sjmacd  else
32021495Sjmacd    {
32121495Sjmacd      send_to_terminal (term_invbeg);
32221495Sjmacd    }
32321495Sjmacd}
32421495Sjmacd
32521495Sjmacd/* Turn off reverse video if possible. */
32621495Sjmacdvoid
327146520Sruterminal_end_inverse (void)
32821495Sjmacd{
32921495Sjmacd  if (terminal_end_inverse_hook)
33021495Sjmacd    (*terminal_end_inverse_hook) ();
33121495Sjmacd  else
33221495Sjmacd    {
33321495Sjmacd      send_to_terminal (term_invend);
33421495Sjmacd    }
33521495Sjmacd}
33621495Sjmacd
33721495Sjmacd/* Ring the terminal bell.  The bell is run visibly if it both has one and
33821495Sjmacd   terminal_use_visible_bell_p is non-zero. */
33921495Sjmacdvoid
340146520Sruterminal_ring_bell (void)
34121495Sjmacd{
34221495Sjmacd  if (terminal_ring_bell_hook)
34321495Sjmacd    (*terminal_ring_bell_hook) ();
34421495Sjmacd  else
34521495Sjmacd    {
34621495Sjmacd      if (terminal_has_visible_bell_p && terminal_use_visible_bell_p)
34742664Smarkm        send_to_terminal (visible_bell);
34821495Sjmacd      else
34942664Smarkm        send_to_terminal (audible_bell);
35021495Sjmacd    }
35121495Sjmacd}
35221495Sjmacd
35321495Sjmacd/* At the line START, delete COUNT lines from the terminal display. */
35421495Sjmacdstatic void
355146520Sruterminal_delete_lines (int start, int count)
35621495Sjmacd{
35721495Sjmacd  int lines;
35821495Sjmacd
35921495Sjmacd  /* Normalize arguments. */
36021495Sjmacd  if (start < 0)
36121495Sjmacd    start = 0;
36221495Sjmacd
36321495Sjmacd  lines = screenheight - start;
36421495Sjmacd  terminal_goto_xy (0, start);
36521495Sjmacd  if (term_DL)
36621495Sjmacd    tputs (tgoto (term_DL, 0, count), lines, output_character_function);
36721495Sjmacd  else
36821495Sjmacd    {
36921495Sjmacd      while (count--)
37042664Smarkm        tputs (term_dl, lines, output_character_function);
37121495Sjmacd    }
37221495Sjmacd
37321495Sjmacd  fflush (stdout);
37421495Sjmacd}
37521495Sjmacd
37621495Sjmacd/* At the line START, insert COUNT lines in the terminal display. */
37721495Sjmacdstatic void
378146520Sruterminal_insert_lines (int start, int count)
37921495Sjmacd{
38021495Sjmacd  int lines;
38121495Sjmacd
38221495Sjmacd  /* Normalize arguments. */
38321495Sjmacd  if (start < 0)
38421495Sjmacd    start = 0;
38521495Sjmacd
38621495Sjmacd  lines = screenheight - start;
38721495Sjmacd  terminal_goto_xy (0, start);
38821495Sjmacd
38921495Sjmacd  if (term_AL)
39021495Sjmacd    tputs (tgoto (term_AL, 0, count), lines, output_character_function);
39121495Sjmacd  else
39221495Sjmacd    {
39321495Sjmacd      while (count--)
39442664Smarkm        tputs (term_al, lines, output_character_function);
39521495Sjmacd    }
39621495Sjmacd
39721495Sjmacd  fflush (stdout);
39821495Sjmacd}
39921495Sjmacd
40021495Sjmacd/* Scroll an area of the terminal, starting with the region from START
40121495Sjmacd   to END, AMOUNT lines.  If AMOUNT is negative, the lines are scrolled
40221495Sjmacd   towards the top of the screen, else they are scrolled towards the
40321495Sjmacd   bottom of the screen. */
40421495Sjmacdvoid
405146520Sruterminal_scroll_terminal (int start, int end, int amount)
40621495Sjmacd{
40721495Sjmacd  if (!terminal_can_scroll)
40821495Sjmacd    return;
40921495Sjmacd
41021495Sjmacd  /* Any scrolling at all? */
41121495Sjmacd  if (amount == 0)
41221495Sjmacd    return;
41321495Sjmacd
41421495Sjmacd  if (terminal_scroll_terminal_hook)
41521495Sjmacd    (*terminal_scroll_terminal_hook) (start, end, amount);
41621495Sjmacd  else
41721495Sjmacd    {
41821495Sjmacd      /* If we are scrolling down, delete AMOUNT lines at END.  Then insert
41942664Smarkm         AMOUNT lines at START. */
42021495Sjmacd      if (amount > 0)
42142664Smarkm        {
42242664Smarkm          terminal_delete_lines (end, amount);
42342664Smarkm          terminal_insert_lines (start, amount);
42442664Smarkm        }
42521495Sjmacd
42621495Sjmacd      /* If we are scrolling up, delete AMOUNT lines before START.  This
42742664Smarkm         actually does the upwards scroll.  Then, insert AMOUNT lines
42842664Smarkm         after the already scrolled region (i.e., END - AMOUNT). */
42921495Sjmacd      if (amount < 0)
43042664Smarkm        {
43142664Smarkm          int abs_amount = -amount;
43242664Smarkm          terminal_delete_lines (start - abs_amount, abs_amount);
43342664Smarkm          terminal_insert_lines (end - abs_amount, abs_amount);
43442664Smarkm        }
43521495Sjmacd    }
43621495Sjmacd}
43721495Sjmacd
43821495Sjmacd/* Re-initialize the terminal considering that the TERM/TERMCAP variable
43921495Sjmacd   has changed. */
44021495Sjmacdvoid
441146520Sruterminal_new_terminal (char *terminal_name)
44221495Sjmacd{
44321495Sjmacd  if (terminal_new_terminal_hook)
44421495Sjmacd    (*terminal_new_terminal_hook) (terminal_name);
44521495Sjmacd  else
44621495Sjmacd    {
44721495Sjmacd      terminal_initialize_terminal (terminal_name);
44821495Sjmacd    }
44921495Sjmacd}
45021495Sjmacd
45121495Sjmacd/* Set the global variables SCREENWIDTH and SCREENHEIGHT. */
45221495Sjmacdvoid
453146520Sruterminal_get_screen_size (void)
45421495Sjmacd{
45521495Sjmacd  if (terminal_get_screen_size_hook)
45621495Sjmacd    (*terminal_get_screen_size_hook) ();
45721495Sjmacd  else
45821495Sjmacd    {
45921495Sjmacd      screenwidth = screenheight = 0;
46021495Sjmacd
46121495Sjmacd#if defined (TIOCGWINSZ)
46221495Sjmacd      {
46342664Smarkm        struct winsize window_size;
46421495Sjmacd
46542664Smarkm        if (ioctl (fileno (stdout), TIOCGWINSZ, &window_size) == 0)
46642664Smarkm          {
46742664Smarkm            screenwidth = (int) window_size.ws_col;
46842664Smarkm            screenheight = (int) window_size.ws_row;
46942664Smarkm          }
47021495Sjmacd      }
47142664Smarkm#endif                          /* TIOCGWINSZ */
47221495Sjmacd
47321495Sjmacd      /* Environment variable COLUMNS overrides setting of "co". */
47421495Sjmacd      if (screenwidth <= 0)
47542664Smarkm        {
47642664Smarkm          char *sw = getenv ("COLUMNS");
47721495Sjmacd
47842664Smarkm          if (sw)
47942664Smarkm            screenwidth = atoi (sw);
48021495Sjmacd
48142664Smarkm          if (screenwidth <= 0)
48242664Smarkm            screenwidth = tgetnum ("co");
48342664Smarkm        }
48421495Sjmacd
48521495Sjmacd      /* Environment variable LINES overrides setting of "li". */
48621495Sjmacd      if (screenheight <= 0)
48742664Smarkm        {
48842664Smarkm          char *sh = getenv ("LINES");
48921495Sjmacd
49042664Smarkm          if (sh)
49142664Smarkm            screenheight = atoi (sh);
49221495Sjmacd
49342664Smarkm          if (screenheight <= 0)
49442664Smarkm            screenheight = tgetnum ("li");
49542664Smarkm        }
49621495Sjmacd
49721495Sjmacd      /* If all else fails, default to 80x24 terminal. */
49821495Sjmacd      if (screenwidth <= 0)
49942664Smarkm        screenwidth = 80;
50021495Sjmacd
50121495Sjmacd      if (screenheight <= 0)
50242664Smarkm        screenheight = 24;
50321495Sjmacd    }
50421495Sjmacd}
50521495Sjmacd
50642664Smarkm/* Initialize the terminal which is known as TERMINAL_NAME.  If this
50742664Smarkm   terminal doesn't have cursor addressability, `terminal_is_dumb_p'
50842664Smarkm   becomes nonzero.  The variables SCREENHEIGHT and SCREENWIDTH are set
50942664Smarkm   to the dimensions that this terminal actually has.  The variable
51042664Smarkm   TERMINAL_HAS_META_P becomes nonzero if this terminal supports a Meta
51142664Smarkm   key.  Finally, the terminal screen is cleared. */
51221495Sjmacdvoid
513146520Sruterminal_initialize_terminal (char *terminal_name)
51421495Sjmacd{
51556164Sru  char *buffer;
51621495Sjmacd
51721495Sjmacd  terminal_is_dumb_p = 0;
51821495Sjmacd
51921495Sjmacd  if (terminal_initialize_terminal_hook)
52021495Sjmacd    {
52121495Sjmacd      (*terminal_initialize_terminal_hook) (terminal_name);
52221495Sjmacd      return;
52321495Sjmacd    }
52421495Sjmacd
52556164Sru  term_name = terminal_name ? terminal_name : getenv ("TERM");
52656164Sru  if (!term_name)
52756164Sru    term_name = "dumb";
52821495Sjmacd
52921495Sjmacd  if (!term_string_buffer)
53056164Sru    term_string_buffer = xmalloc (2048);
53121495Sjmacd
53221495Sjmacd  if (!term_buffer)
53356164Sru    term_buffer = xmalloc (2048);
53421495Sjmacd
53521495Sjmacd  buffer = term_string_buffer;
53621495Sjmacd
53756164Sru  term_clrpag = term_cr = term_clreol = NULL;
53821495Sjmacd
53956164Sru  /* HP-UX 11.x returns 0 for OK --jeff.hull@state.co.us.  */
54056164Sru  if (tgetent (term_buffer, term_name) < 0)
54121495Sjmacd    {
54221495Sjmacd      terminal_is_dumb_p = 1;
54321495Sjmacd      screenwidth = 80;
54421495Sjmacd      screenheight = 24;
54521495Sjmacd      term_cr = "\r";
54656164Sru      term_up = term_dn = audible_bell = visible_bell = NULL;
54756164Sru      term_ku = term_kd = term_kl = term_kr = NULL;
54856164Sru      term_kP = term_kN = NULL;
54993142Sru      term_kh = term_ke = NULL;
55093142Sru      term_kD = NULL;
55121495Sjmacd      return;
55221495Sjmacd    }
55321495Sjmacd
55421495Sjmacd  BC = tgetstr ("pc", &buffer);
55521495Sjmacd  PC = BC ? *BC : 0;
55621495Sjmacd
55756164Sru#if defined (HAVE_TERMIOS_H)
55821495Sjmacd  {
55956164Sru    struct termios ti;
56056164Sru    if (tcgetattr (fileno(stdout), &ti) != -1)
56156164Sru      ospeed = cfgetospeed (&ti);
56256164Sru    else
56356164Sru      ospeed = B9600;
56456164Sru  }
56556164Sru#else
56656164Sru# if defined (TIOCGETP)
56756164Sru  {
56821495Sjmacd    struct sgttyb sg;
56921495Sjmacd
57021495Sjmacd    if (ioctl (fileno (stdout), TIOCGETP, &sg) != -1)
57121495Sjmacd      ospeed = sg.sg_ospeed;
57221495Sjmacd    else
57321495Sjmacd      ospeed = B9600;
57421495Sjmacd  }
57556164Sru# else
57621495Sjmacd  ospeed = B9600;
57756164Sru# endif /* !TIOCGETP */
57856164Sru#endif
57921495Sjmacd
58021495Sjmacd  term_cr = tgetstr ("cr", &buffer);
58121495Sjmacd  term_clreol = tgetstr ("ce", &buffer);
58221495Sjmacd  term_clrpag = tgetstr ("cl", &buffer);
58321495Sjmacd  term_goto = tgetstr ("cm", &buffer);
58421495Sjmacd
58556164Sru  /* Find out about this terminal's scrolling capability. */
58621495Sjmacd  term_AL = tgetstr ("AL", &buffer);
58721495Sjmacd  term_DL = tgetstr ("DL", &buffer);
58821495Sjmacd  term_al = tgetstr ("al", &buffer);
58921495Sjmacd  term_dl = tgetstr ("dl", &buffer);
59021495Sjmacd
59121495Sjmacd  terminal_can_scroll = ((term_AL || term_al) && (term_DL || term_dl));
59221495Sjmacd
59321495Sjmacd  term_invbeg = tgetstr ("mr", &buffer);
59421495Sjmacd  if (term_invbeg)
59521495Sjmacd    term_invend = tgetstr ("me", &buffer);
59621495Sjmacd  else
59793142Sru    term_invend = NULL;
59821495Sjmacd
59921495Sjmacd  if (!term_cr)
60021495Sjmacd    term_cr =  "\r";
60121495Sjmacd
60221495Sjmacd  terminal_get_screen_size ();
60321495Sjmacd
60421495Sjmacd  term_up = tgetstr ("up", &buffer);
60521495Sjmacd  term_dn = tgetstr ("dn", &buffer);
60621495Sjmacd  visible_bell = tgetstr ("vb", &buffer);
60793142Sru  terminal_has_visible_bell_p = (visible_bell != NULL);
60821495Sjmacd  audible_bell = tgetstr ("bl", &buffer);
60921495Sjmacd  if (!audible_bell)
61021495Sjmacd    audible_bell = "\007";
61121495Sjmacd  term_begin_use = tgetstr ("ti", &buffer);
61221495Sjmacd  term_end_use = tgetstr ("te", &buffer);
61321495Sjmacd
61442664Smarkm  term_keypad_on = tgetstr ("ks", &buffer);
61542664Smarkm  term_keypad_off = tgetstr ("ke", &buffer);
61642664Smarkm
61721495Sjmacd  /* Check to see if this terminal has a meta key. */
61821495Sjmacd  terminal_has_meta_p = (tgetflag ("km") || tgetflag ("MT"));
61921495Sjmacd  if (terminal_has_meta_p)
62021495Sjmacd    {
62121495Sjmacd      term_mm = tgetstr ("mm", &buffer);
62221495Sjmacd    }
62321495Sjmacd  else
62421495Sjmacd    {
62593142Sru      term_mm = NULL;
62621495Sjmacd    }
62721495Sjmacd
62842699Smarkm  /* Attempt to find the arrow keys.  */
62921495Sjmacd  term_ku = tgetstr ("ku", &buffer);
63021495Sjmacd  term_kd = tgetstr ("kd", &buffer);
63121495Sjmacd  term_kr = tgetstr ("kr", &buffer);
63221495Sjmacd  term_kl = tgetstr ("kl", &buffer);
63342664Smarkm
63421787Sjmacd  term_kP = tgetstr ("kP", &buffer);
63521787Sjmacd  term_kN = tgetstr ("kN", &buffer);
63621495Sjmacd
63793142Sru#if defined(INFOKEY)
63893142Sru  term_kh = tgetstr ("kh", &buffer);
63993142Sru  term_ke = tgetstr ("@7", &buffer);
64093142Sru  term_ki = tgetstr ("kI", &buffer);
64193142Sru  term_kx = tgetstr ("kD", &buffer);
64293142Sru#endif /* defined(INFOKEY) */
64393142Sru
64493142Sru  /* Home and end keys. */
64593142Sru  term_kh = tgetstr ("kh", &buffer);
64693142Sru  term_ke = tgetstr ("@7", &buffer);
64793142Sru
64893142Sru  term_kD = tgetstr ("kD", &buffer);
64993142Sru
65021495Sjmacd  /* If this terminal is not cursor addressable, then it is really dumb. */
65121495Sjmacd  if (!term_goto)
65221495Sjmacd    terminal_is_dumb_p = 1;
65321495Sjmacd}
65421495Sjmacd
65556164Sru/* How to read characters from the terminal.  */
65621495Sjmacd
65721495Sjmacd#if defined (HAVE_TERMIOS_H)
65821495Sjmacdstruct termios original_termios, ttybuff;
65921495Sjmacd#else
66021495Sjmacd#  if defined (HAVE_TERMIO_H)
66121495Sjmacd/* A buffer containing the terminal mode flags upon entry to info. */
66221495Sjmacdstruct termio original_termio, ttybuff;
66321495Sjmacd#  else /* !HAVE_TERMIO_H */
66421495Sjmacd/* Buffers containing the terminal mode flags upon entry to info. */
66521495Sjmacdint original_tty_flags = 0;
66621495Sjmacdint original_lmode;
66721495Sjmacdstruct sgttyb ttybuff;
66856164Sru
66956164Sru#    if defined(TIOCGETC) && defined(M_XENIX)
67056164Sru/* SCO 3.2v5.0.2 defines but does not support TIOCGETC.  Gak.  Maybe
67156164Sru   better fix would be to use Posix termios in preference.  --gildea,
67256164Sru   1jul99.  */
67356164Sru#      undef TIOCGETC
67456164Sru#    endif
67556164Sru
67656164Sru#    if defined (TIOCGETC)
67756164Sru/* A buffer containing the terminal interrupt characters upon entry
67856164Sru   to Info. */
67956164Srustruct tchars original_tchars;
68056164Sru#    endif
68156164Sru
68256164Sru#    if defined (TIOCGLTC)
68356164Sru/* A buffer containing the local terminal mode characters upon entry
68456164Sru   to Info. */
68556164Srustruct ltchars original_ltchars;
68656164Sru#    endif
68721495Sjmacd#  endif /* !HAVE_TERMIO_H */
68821495Sjmacd#endif /* !HAVE_TERMIOS_H */
68921495Sjmacd
69021495Sjmacd/* Prepare to start using the terminal to read characters singly. */
69121495Sjmacdvoid
692146520Sruterminal_prep_terminal (void)
69321495Sjmacd{
69421495Sjmacd  int tty;
69521495Sjmacd
69621495Sjmacd  if (terminal_prep_terminal_hook)
69721495Sjmacd    {
69821495Sjmacd      (*terminal_prep_terminal_hook) ();
69921495Sjmacd      return;
70021495Sjmacd    }
70121495Sjmacd
70242664Smarkm  terminal_begin_using_terminal ();
70342664Smarkm
70421495Sjmacd  tty = fileno (stdin);
70521495Sjmacd
70621495Sjmacd#if defined (HAVE_TERMIOS_H)
70721495Sjmacd  tcgetattr (tty, &original_termios);
70821495Sjmacd  tcgetattr (tty, &ttybuff);
70921495Sjmacd#else
71021495Sjmacd#  if defined (HAVE_TERMIO_H)
71121495Sjmacd  ioctl (tty, TCGETA, &original_termio);
71221495Sjmacd  ioctl (tty, TCGETA, &ttybuff);
71321495Sjmacd#  endif
71421495Sjmacd#endif
71521495Sjmacd
71621495Sjmacd#if defined (HAVE_TERMIOS_H) || defined (HAVE_TERMIO_H)
71721495Sjmacd  ttybuff.c_iflag &= (~ISTRIP & ~INLCR & ~IGNCR & ~ICRNL & ~IXON);
71842664Smarkm/* These output flags are not part of POSIX, so only use them if they
71942664Smarkm   are defined.  */
72042664Smarkm#ifdef ONLCR
72142664Smarkm  ttybuff.c_oflag &= ~ONLCR ;
72242664Smarkm#endif
72342664Smarkm#ifdef OCRNL
72442664Smarkm  ttybuff.c_oflag &= ~OCRNL;
72542664Smarkm#endif
72621495Sjmacd  ttybuff.c_lflag &= (~ICANON & ~ECHO);
72721495Sjmacd
72821495Sjmacd  ttybuff.c_cc[VMIN] = 1;
72921495Sjmacd  ttybuff.c_cc[VTIME] = 0;
73021495Sjmacd
73121495Sjmacd  if (ttybuff.c_cc[VINTR] == '\177')
73221495Sjmacd    ttybuff.c_cc[VINTR] = -1;
73321495Sjmacd
73421495Sjmacd  if (ttybuff.c_cc[VQUIT] == '\177')
73521495Sjmacd    ttybuff.c_cc[VQUIT] = -1;
73621495Sjmacd
73742664Smarkm#ifdef VLNEXT
73842664Smarkm  if (ttybuff.c_cc[VLNEXT] == '\026')
73942664Smarkm    ttybuff.c_cc[VLNEXT] = -1;
74042664Smarkm#endif /* VLNEXT */
74142664Smarkm#endif /* TERMIOS or TERMIO */
74242664Smarkm
74393142Sru/* cf. emacs/src/sysdep.c for being sure output is on. */
74421495Sjmacd#if defined (HAVE_TERMIOS_H)
74593142Sru  /* linux kernel 2.2.x needs a TCOFF followed by a TCOON to turn output
74693142Sru     back on if the user presses ^S at the very beginning; just a TCOON
74793142Sru     doesn't work.  --Kevin Ryde <user42@zip.com.au>, 16jun2000.  */
74821495Sjmacd  tcsetattr (tty, TCSANOW, &ttybuff);
74993142Sru#  ifdef TCOON
75093142Sru  tcflow (tty, TCOOFF);
75193142Sru  tcflow (tty, TCOON);
75293142Sru#  endif
75321495Sjmacd#else
75421495Sjmacd#  if defined (HAVE_TERMIO_H)
75521495Sjmacd  ioctl (tty, TCSETA, &ttybuff);
75693142Sru#    ifdef TCXONC
75793142Sru  ioctl (tty, TCXONC, 1);
75893142Sru#    endif
75921495Sjmacd#  endif
76021495Sjmacd#endif
76121495Sjmacd
76221495Sjmacd#if !defined (HAVE_TERMIOS_H) && !defined (HAVE_TERMIO_H)
76321495Sjmacd  ioctl (tty, TIOCGETP, &ttybuff);
76421495Sjmacd
76521495Sjmacd  if (!original_tty_flags)
76621495Sjmacd    original_tty_flags = ttybuff.sg_flags;
76721495Sjmacd
76821495Sjmacd  /* Make this terminal pass 8 bits around while we are using it. */
76921495Sjmacd#  if defined (PASS8)
77021495Sjmacd  ttybuff.sg_flags |= PASS8;
77121495Sjmacd#  endif /* PASS8 */
77221495Sjmacd
77321495Sjmacd#  if defined (TIOCLGET) && defined (LPASS8)
77421495Sjmacd  {
77521495Sjmacd    int flags;
77621495Sjmacd    ioctl (tty, TIOCLGET, &flags);
77721495Sjmacd    original_lmode = flags;
77821495Sjmacd    flags |= LPASS8;
77921495Sjmacd    ioctl (tty, TIOCLSET, &flags);
78021495Sjmacd  }
78121495Sjmacd#  endif /* TIOCLGET && LPASS8 */
78221495Sjmacd
78321495Sjmacd#  if defined (TIOCGETC)
78421495Sjmacd  {
78521495Sjmacd    struct tchars temp;
78621495Sjmacd
78721495Sjmacd    ioctl (tty, TIOCGETC, &original_tchars);
78821495Sjmacd    temp = original_tchars;
78921495Sjmacd
79021495Sjmacd    /* C-s and C-q. */
79121495Sjmacd    temp.t_startc = temp.t_stopc = -1;
79221495Sjmacd
79321495Sjmacd    /* Often set to C-d. */
79421495Sjmacd    temp.t_eofc = -1;
79521495Sjmacd
79621495Sjmacd    /* If the a quit or interrupt character conflicts with one of our
79721495Sjmacd       commands, then make it go away. */
79821495Sjmacd    if (temp.t_intrc == '\177')
79921495Sjmacd      temp.t_intrc = -1;
80021495Sjmacd
80121495Sjmacd    if (temp.t_quitc == '\177')
80221495Sjmacd      temp.t_quitc = -1;
80321495Sjmacd
80421495Sjmacd    ioctl (tty, TIOCSETC, &temp);
80521495Sjmacd  }
80621495Sjmacd#  endif /* TIOCGETC */
80721495Sjmacd
80821495Sjmacd#  if defined (TIOCGLTC)
80921495Sjmacd  {
81021495Sjmacd    struct ltchars temp;
81121495Sjmacd
81221495Sjmacd    ioctl (tty, TIOCGLTC, &original_ltchars);
81321495Sjmacd    temp = original_ltchars;
81421495Sjmacd
81521495Sjmacd    /* Make the interrupt keys go away.  Just enough to make people happy. */
81642664Smarkm    temp.t_lnextc = -1;         /* C-v. */
81742664Smarkm    temp.t_dsuspc = -1;         /* C-y. */
81842664Smarkm    temp.t_flushc = -1;         /* C-o. */
81921495Sjmacd    ioctl (tty, TIOCSLTC, &temp);
82021495Sjmacd  }
82121495Sjmacd#  endif /* TIOCGLTC */
82221495Sjmacd
82321495Sjmacd  ttybuff.sg_flags &= ~ECHO;
82421495Sjmacd  ttybuff.sg_flags |= CBREAK;
82521495Sjmacd  ioctl (tty, TIOCSETN, &ttybuff);
82621495Sjmacd#endif /* !HAVE_TERMIOS_H && !HAVE_TERMIO_H */
82721495Sjmacd}
82821495Sjmacd
82921495Sjmacd/* Restore the tty settings back to what they were before we started using
83021495Sjmacd   this terminal. */
83121495Sjmacdvoid
832146520Sruterminal_unprep_terminal (void)
83321495Sjmacd{
83421495Sjmacd  int tty;
83521495Sjmacd
83621495Sjmacd  if (terminal_unprep_terminal_hook)
83721495Sjmacd    {
83821495Sjmacd      (*terminal_unprep_terminal_hook) ();
83921495Sjmacd      return;
84021495Sjmacd    }
84121495Sjmacd
84221495Sjmacd  tty = fileno (stdin);
84321495Sjmacd
84421495Sjmacd#if defined (HAVE_TERMIOS_H)
84521495Sjmacd  tcsetattr (tty, TCSANOW, &original_termios);
84621495Sjmacd#else
84721495Sjmacd#  if defined (HAVE_TERMIO_H)
84821495Sjmacd  ioctl (tty, TCSETA, &original_termio);
84921495Sjmacd#  else /* !HAVE_TERMIO_H */
85021495Sjmacd  ioctl (tty, TIOCGETP, &ttybuff);
85121495Sjmacd  ttybuff.sg_flags = original_tty_flags;
85221495Sjmacd  ioctl (tty, TIOCSETN, &ttybuff);
85321495Sjmacd
85421495Sjmacd#  if defined (TIOCGETC)
85521495Sjmacd  ioctl (tty, TIOCSETC, &original_tchars);
85621495Sjmacd#  endif /* TIOCGETC */
85721495Sjmacd
85821495Sjmacd#  if defined (TIOCGLTC)
85921495Sjmacd  ioctl (tty, TIOCSLTC, &original_ltchars);
86021495Sjmacd#  endif /* TIOCGLTC */
86121495Sjmacd
86221495Sjmacd#  if defined (TIOCLGET) && defined (LPASS8)
86321495Sjmacd  ioctl (tty, TIOCLSET, &original_lmode);
86421495Sjmacd#  endif /* TIOCLGET && LPASS8 */
86521495Sjmacd
86621495Sjmacd#  endif /* !HAVE_TERMIO_H */
86721495Sjmacd#endif /* !HAVE_TERMIOS_H */
86821495Sjmacd  terminal_end_using_terminal ();
86921495Sjmacd}
87042699Smarkm
87156164Sru#ifdef __MSDOS__
87256164Sru# include "pcterm.c"
87356164Sru#endif
874