terminal.c revision 21308
121308Sache/* terminal.c -- controlling the terminal with termcap. */
221308Sache
321308Sache/* Copyright (C) 1996 Free Software Foundation, Inc.
421308Sache
521308Sache   This file is part of the GNU Readline Library, a library for
621308Sache   reading lines of text with interactive input and history editing.
721308Sache
821308Sache   The GNU Readline Library is free software; you can redistribute it
921308Sache   and/or modify it under the terms of the GNU General Public License
1021308Sache   as published by the Free Software Foundation; either version 1, or
1121308Sache   (at your option) any later version.
1221308Sache
1321308Sache   The GNU Readline Library is distributed in the hope that it will be
1421308Sache   useful, but WITHOUT ANY WARRANTY; without even the implied warranty
1521308Sache   of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
1621308Sache   GNU General Public License for more details.
1721308Sache
1821308Sache   The GNU General Public License is often shipped with GNU software, and
1921308Sache   is generally kept in a file called COPYING or LICENSE.  If you do not
2021308Sache   have a copy of the license, write to the Free Software Foundation,
2121308Sache   675 Mass Ave, Cambridge, MA 02139, USA. */
2221308Sache#define READLINE_LIBRARY
2321308Sache
2421308Sache#if defined (HAVE_CONFIG_H)
2521308Sache#  include <config.h>
2621308Sache#endif
2721308Sache
2821308Sache#include <sys/types.h>
2921308Sache#include "posixstat.h"
3021308Sache#include <fcntl.h>
3121308Sache#if defined (HAVE_SYS_FILE_H)
3221308Sache#  include <sys/file.h>
3321308Sache#endif /* HAVE_SYS_FILE_H */
3421308Sache
3521308Sache#if defined (HAVE_UNISTD_H)
3621308Sache#  include <unistd.h>
3721308Sache#endif /* HAVE_UNISTD_H */
3821308Sache
3921308Sache#if defined (HAVE_STDLIB_H)
4021308Sache#  include <stdlib.h>
4121308Sache#else
4221308Sache#  include "ansi_stdlib.h"
4321308Sache#endif /* HAVE_STDLIB_H */
4421308Sache
4521308Sache#if defined (HAVE_LOCALE_H)
4621308Sache#  include <locale.h>
4721308Sache#endif
4821308Sache
4921308Sache#include <signal.h>
5021308Sache#include <stdio.h>
5121308Sache#include <setjmp.h>
5221308Sache
5321308Sache/* System-specific feature definitions and include files. */
5421308Sache#include "rldefs.h"
5521308Sache
5621308Sache#include "tcap.h"
5721308Sache
5821308Sache#if defined (GWINSZ_IN_SYS_IOCTL)
5921308Sache#  include <sys/ioctl.h>
6021308Sache#endif /* GWINSZ_IN_SYS_IOCTL */
6121308Sache
6221308Sache/* Some standard library routines. */
6321308Sache#include "readline.h"
6421308Sache#include "history.h"
6521308Sache
6621308Sache/* Variables and functions imported from readline.c */
6721308Sacheextern FILE *_rl_in_stream, *_rl_out_stream;
6821308Sacheextern int readline_echoing_p;
6921308Sacheextern int _rl_bell_preference;
7021308Sacheextern Keymap _rl_keymap;
7121308Sache
7221308Sache/* **************************************************************** */
7321308Sache/*								    */
7421308Sache/*			Terminal and Termcap			    */
7521308Sache/*								    */
7621308Sache/* **************************************************************** */
7721308Sache
7821308Sachestatic char *term_buffer = (char *)NULL;
7921308Sachestatic char *term_string_buffer = (char *)NULL;
8021308Sache
8121308Sachestatic int tcap_initialized;
8221308Sache
8321308Sache/* Non-zero means this terminal can't really do anything. */
8421308Sachestatic int dumb_term;
8521308Sache
8621308Sache#if !defined (__linux__)
8721308Sache/* If this causes problems, add back the `extern'. */
8821308Sache/*extern*/ char PC, *BC, *UP;
8921308Sache#endif /* __linux__ */
9021308Sache
9121308Sache/* Some strings to control terminal actions.  These are output by tputs (). */
9221308Sachechar *term_goto, *term_clreol, *term_cr, *term_clrpag, *term_backspace;
9321308Sachechar *term_pc;
9421308Sache
9521308Sache/* Non-zero if we determine that the terminal can do character insertion. */
9621308Sacheint terminal_can_insert = 0;
9721308Sache
9821308Sache/* How to insert characters. */
9921308Sachechar *term_im, *term_ei, *term_ic, *term_ip, *term_IC;
10021308Sache
10121308Sache/* How to delete characters. */
10221308Sachechar *term_dc, *term_DC;
10321308Sache
10421308Sache#if defined (HACK_TERMCAP_MOTION)
10521308Sachechar *term_forward_char;
10621308Sache#endif  /* HACK_TERMCAP_MOTION */
10721308Sache
10821308Sache/* How to go up a line. */
10921308Sachechar *term_up;
11021308Sache
11121308Sache/* A visible bell, if the terminal can be made to flash the screen. */
11221308Sachestatic char *visible_bell;
11321308Sache
11421308Sache/* Non-zero means the terminal can auto-wrap lines. */
11521308Sacheint _rl_term_autowrap;
11621308Sache
11721308Sache/* Non-zero means that this terminal has a meta key. */
11821308Sachestatic int term_has_meta;
11921308Sache
12021308Sache/* The sequences to write to turn on and off the meta key, if this
12121308Sache   terminal    has one. */
12221308Sachestatic char *term_mm, *term_mo;
12321308Sache
12421308Sache/* The key sequences output by the arrow keys, if this terminal has any. */
12521308Sachestatic char *term_ku, *term_kd, *term_kr, *term_kl;
12621308Sache
12721308Sache/* How to initialize and reset the arrow keys, if this terminal has any. */
12821308Sachestatic char *term_ks, *term_ke;
12921308Sache
13021308Sache/* The key sequences sent by the Home and End keys, if any. */
13121308Sachestatic char *term_kh, *term_kH;
13221308Sache
13321308Sache/* Variables that hold the screen dimensions, used by the display code. */
13421308Sacheint screenwidth, screenheight, screenchars;
13521308Sache
13621308Sache/* Non-zero means the user wants to enable the keypad. */
13721308Sacheint _rl_enable_keypad;
13821308Sache
13921308Sache/* Non-zero means the user wants to enable a meta key. */
14021308Sacheint _rl_enable_meta = 1;
14121308Sache
14221308Sache/* Re-initialize the terminal considering that the TERM/TERMCAP variable
14321308Sache   has changed. */
14421308Sacheint
14521308Sacherl_reset_terminal (terminal_name)
14621308Sache     char *terminal_name;
14721308Sache{
14821308Sache  _rl_init_terminal_io (terminal_name);
14921308Sache  return 0;
15021308Sache}
15121308Sache
15221308Sache#if !defined (SHELL)
15321308Sachestatic void
15421308Sacheset_lines_and_columns (lines, cols)
15521308Sache     int lines, cols;
15621308Sache{
15721308Sache  char *b;
15821308Sache
15921308Sache#if defined (HAVE_PUTENV)
16021308Sache  b = xmalloc (24);
16121308Sache  sprintf (b, "LINES=%d", lines);
16221308Sache  putenv (b);
16321308Sache  b = xmalloc (24);
16421308Sache  sprintf (b, "COLUMNS=%d", cols);
16521308Sache  putenv (b);
16621308Sache#else /* !HAVE_PUTENV */
16721308Sache#  if defined (HAVE_SETENV)
16821308Sache  b = xmalloc (8);
16921308Sache  sprintf (b, "%d", lines);
17021308Sache  setenv ("LINES", b, 1);
17121308Sache  b = xmalloc (8);
17221308Sache  sprintf (b, "%d", cols);
17321308Sache  setenv ("COLUMNS", b, 1);
17421308Sache#  endif /* HAVE_SETENV */
17521308Sache#endif /* !HAVE_PUTENV */
17621308Sache}
17721308Sache#else /* SHELL */
17821308Sacheextern void set_lines_and_columns ();
17921308Sache#endif /* SHELL */
18021308Sache
18121308Sache/* Get readline's idea of the screen size.  TTY is a file descriptor open
18221308Sache   to the terminal.  If IGNORE_ENV is true, we do not pay attention to the
18321308Sache   values of $LINES and $COLUMNS.  The tests for TERM_STRING_BUFFER being
18421308Sache   non-null serve to check whether or not we have initialized termcap. */
18521308Sachevoid
18621308Sache_rl_get_screen_size (tty, ignore_env)
18721308Sache     int tty, ignore_env;
18821308Sache{
18921308Sache  char *ss;
19021308Sache#if defined (TIOCGWINSZ)
19121308Sache  struct winsize window_size;
19221308Sache#endif /* TIOCGWINSZ */
19321308Sache
19421308Sache#if defined (TIOCGWINSZ)
19521308Sache  if (ioctl (tty, TIOCGWINSZ, &window_size) == 0)
19621308Sache    {
19721308Sache      screenwidth = (int) window_size.ws_col;
19821308Sache      screenheight = (int) window_size.ws_row;
19921308Sache    }
20021308Sache#endif /* TIOCGWINSZ */
20121308Sache
20221308Sache  /* Environment variable COLUMNS overrides setting of "co" if IGNORE_ENV
20321308Sache     is unset. */
20421308Sache  if (screenwidth <= 0)
20521308Sache    {
20621308Sache      if (ignore_env == 0 && (ss = getenv ("COLUMNS")))
20721308Sache	screenwidth = atoi (ss);
20821308Sache
20921308Sache      if (screenwidth <= 0 && term_string_buffer)
21021308Sache	screenwidth = tgetnum ("co");
21121308Sache    }
21221308Sache
21321308Sache  /* Environment variable LINES overrides setting of "li" if IGNORE_ENV
21421308Sache     is unset. */
21521308Sache  if (screenheight <= 0)
21621308Sache    {
21721308Sache      if (ignore_env == 0 && (ss = getenv ("LINES")))
21821308Sache	screenheight = atoi (ss);
21921308Sache
22021308Sache      if (screenheight <= 0 && term_string_buffer)
22121308Sache	screenheight = tgetnum ("li");
22221308Sache    }
22321308Sache
22421308Sache  /* If all else fails, default to 80x24 terminal. */
22521308Sache  if (screenwidth <= 1)
22621308Sache    screenwidth = 80;
22721308Sache
22821308Sache  if (screenheight <= 0)
22921308Sache    screenheight = 24;
23021308Sache
23121308Sache  /* If we're being compiled as part of bash, set the environment
23221308Sache     variables $LINES and $COLUMNS to new values.  Otherwise, just
23321308Sache     do a pair of putenv () or setenv () calls. */
23421308Sache  set_lines_and_columns (screenheight, screenwidth);
23521308Sache
23621308Sache  if (!_rl_term_autowrap)
23721308Sache    screenwidth--;
23821308Sache
23921308Sache  screenchars = screenwidth * screenheight;
24021308Sache}
24121308Sache
24221308Sachevoid
24321308Sache_rl_set_screen_size (rows, cols)
24421308Sache     int rows, cols;
24521308Sache{
24621308Sache  screenheight = rows;
24721308Sache  screenwidth = cols;
24821308Sache
24921308Sache  if (_rl_term_autowrap == 0)
25021308Sache    screenwidth--;
25121308Sache
25221308Sache  screenchars = screenwidth * screenheight;
25321308Sache}
25421308Sache
25521308Sachestruct _tc_string {
25621308Sache     char *tc_var;
25721308Sache     char **tc_value;
25821308Sache};
25921308Sache
26021308Sache/* This should be kept sorted, just in case we decide to change the
26121308Sache   search algorithm to something smarter. */
26221308Sachestatic struct _tc_string tc_strings[] =
26321308Sache{
26421308Sache  "DC", &term_DC,
26521308Sache  "IC", &term_IC,
26621308Sache  "ce", &term_clreol,
26721308Sache  "cl", &term_clrpag,
26821308Sache  "cr", &term_cr,
26921308Sache  "dc", &term_dc,
27021308Sache  "ei", &term_ei,
27121308Sache  "ic", &term_ic,
27221308Sache  "im", &term_im,
27321308Sache  "kd", &term_kd,
27421308Sache  "kh", &term_kh,	/* home */
27521308Sache  "kH", &term_kH,	/* end */
27621308Sache  "kl", &term_kl,
27721308Sache  "kr", &term_kr,
27821308Sache  "ku", &term_ku,
27921308Sache  "ks", &term_ks,
28021308Sache  "ke", &term_ke,
28121308Sache  "le", &term_backspace,
28221308Sache  "mm", &term_mm,
28321308Sache  "mo", &term_mo,
28421308Sache#if defined (HACK_TERMCAP_MOTION)
28521308Sache  "nd", &term_forward_char,
28621308Sache#endif
28721308Sache  "pc", &term_pc,
28821308Sache  "up", &term_up,
28921308Sache  "vb", &visible_bell,
29021308Sache};
29121308Sache
29221308Sache#define NUM_TC_STRINGS (sizeof (tc_strings) / sizeof (struct _tc_string))
29321308Sache
29421308Sache/* Read the desired terminal capability strings into BP.  The capabilities
29521308Sache   are described in the TC_STRINGS table. */
29621308Sachestatic void
29721308Sacheget_term_capabilities (bp)
29821308Sache     char **bp;
29921308Sache{
30021308Sache  register int i;
30121308Sache
30221308Sache  for (i = 0; i < NUM_TC_STRINGS; i++)
30321308Sache    *(tc_strings[i].tc_value) = tgetstr (tc_strings[i].tc_var, bp);
30421308Sache  tcap_initialized = 1;
30521308Sache}
30621308Sache
30721308Sacheint
30821308Sache_rl_init_terminal_io (terminal_name)
30921308Sache     char *terminal_name;
31021308Sache{
31121308Sache#if defined (__GO32__)
31221308Sache  screenwidth = ScreenCols ();
31321308Sache  screenheight = ScreenRows ();
31421308Sache  screenchars = screenwidth * screenheight;
31521308Sache  term_cr = "\r";
31621308Sache  term_im = term_ei = term_ic = term_IC = (char *)NULL;
31721308Sache  term_up = term_dc = term_DC = visible_bell = (char *)NULL;
31821308Sache
31921308Sache  /* Does the __GO32__ have a meta key?  I don't know. */
32021308Sache  term_has_meta = 0;
32121308Sache  term_mm = term_mo = (char *)NULL;
32221308Sache
32321308Sache  /* It probably has arrow keys, but I don't know what they are. */
32421308Sache  term_ku = term_kd = term_kr = term_kl = (char *)NULL;
32521308Sache
32621308Sache#if defined (HACK_TERMCAP_MOTION)
32721308Sache  term_forward_char = (char *)NULL;
32821308Sache#endif /* HACK_TERMCAP_MOTION */
32921308Sache  terminal_can_insert = _rl_term_autowrap = 0;
33021308Sache  return;
33121308Sache#else /* !__GO32__ */
33221308Sache
33321308Sache  char *term, *buffer;
33421308Sache  int tty;
33521308Sache  Keymap xkeymap;
33621308Sache
33721308Sache  term = terminal_name ? terminal_name : getenv ("TERM");
33821308Sache
33921308Sache  if (term_string_buffer == 0)
34021308Sache    term_string_buffer = xmalloc (2032);
34121308Sache
34221308Sache  if (term_buffer == 0)
34321308Sache    term_buffer = xmalloc (4080);
34421308Sache
34521308Sache  buffer = term_string_buffer;
34621308Sache
34721308Sache  term_clrpag = term_cr = term_clreol = (char *)NULL;
34821308Sache
34921308Sache  if (term == 0)
35021308Sache    term = "dumb";
35121308Sache
35221308Sache  if (tgetent (term_buffer, term) <= 0)
35321308Sache    {
35421308Sache      dumb_term = 1;
35521308Sache      screenwidth = 79;
35621308Sache      screenheight = 24;
35721308Sache      screenchars = 79 * 24;
35821308Sache      term_cr = "\r";
35921308Sache      term_im = term_ei = term_ic = term_IC = (char *)NULL;
36021308Sache      term_up = term_dc = term_DC = visible_bell = (char *)NULL;
36121308Sache      term_ku = term_kd = term_kl = term_kr = (char *)NULL;
36221308Sache#if defined (HACK_TERMCAP_MOTION)
36321308Sache      term_forward_char = (char *)NULL;
36421308Sache#endif
36521308Sache      terminal_can_insert = 0;
36621308Sache      return 0;
36721308Sache    }
36821308Sache
36921308Sache  get_term_capabilities (&buffer);
37021308Sache
37121308Sache  /* Set up the variables that the termcap library expects the application
37221308Sache     to provide. */
37321308Sache  PC = term_pc ? *term_pc : 0;
37421308Sache  BC = term_backspace;
37521308Sache  UP = term_up;
37621308Sache
37721308Sache  if (!term_cr)
37821308Sache    term_cr = "\r";
37921308Sache
38021308Sache  tty = rl_instream ? fileno (rl_instream) : 0;
38121308Sache
38221308Sache  screenwidth = screenheight = 0;
38321308Sache
38421308Sache  _rl_term_autowrap = tgetflag ("am") && tgetflag ("xn");
38521308Sache
38621308Sache  _rl_get_screen_size (tty, 0);
38721308Sache
38821308Sache  /* "An application program can assume that the terminal can do
38921308Sache      character insertion if *any one of* the capabilities `IC',
39021308Sache      `im', `ic' or `ip' is provided."  But we can't do anything if
39121308Sache      only `ip' is provided, so... */
39221308Sache  terminal_can_insert = (term_IC || term_im || term_ic);
39321308Sache
39421308Sache  /* Check to see if this terminal has a meta key and clear the capability
39521308Sache     variables if there is none. */
39621308Sache  term_has_meta = (tgetflag ("km") || tgetflag ("MT"));
39721308Sache  if (!term_has_meta)
39821308Sache    term_mm = term_mo = (char *)NULL;
39921308Sache
40021308Sache  /* Attempt to find and bind the arrow keys.  Do not override already
40121308Sache     bound keys in an overzealous attempt, however. */
40221308Sache  xkeymap = _rl_keymap;
40321308Sache
40421308Sache  _rl_keymap = emacs_standard_keymap;
40521308Sache  _rl_bind_if_unbound (term_ku, rl_get_previous_history);
40621308Sache  _rl_bind_if_unbound (term_kd, rl_get_next_history);
40721308Sache  _rl_bind_if_unbound (term_kr, rl_forward);
40821308Sache  _rl_bind_if_unbound (term_kl, rl_backward);
40921308Sache
41021308Sache  _rl_bind_if_unbound (term_kh, rl_beg_of_line);	/* Home */
41121308Sache  _rl_bind_if_unbound (term_kH, rl_end_of_line);	/* End */
41221308Sache
41321308Sache#if defined (VI_MODE)
41421308Sache  _rl_keymap = vi_movement_keymap;
41521308Sache  _rl_bind_if_unbound (term_ku, rl_get_previous_history);
41621308Sache  _rl_bind_if_unbound (term_kd, rl_get_next_history);
41721308Sache  _rl_bind_if_unbound (term_kr, rl_forward);
41821308Sache  _rl_bind_if_unbound (term_kl, rl_backward);
41921308Sache
42021308Sache  _rl_bind_if_unbound (term_kh, rl_beg_of_line);	/* Home */
42121308Sache  _rl_bind_if_unbound (term_kH, rl_end_of_line);	/* End */
42221308Sache#endif /* VI_MODE */
42321308Sache
42421308Sache  _rl_keymap = xkeymap;
42521308Sache
42621308Sache#endif /* !__GO32__ */
42721308Sache  return 0;
42821308Sache}
42921308Sache
43021308Sachechar *
43121308Sacherl_get_termcap (cap)
43221308Sache     char *cap;
43321308Sache{
43421308Sache  register int i;
43521308Sache
43621308Sache  if (tcap_initialized == 0)
43721308Sache    return ((char *)NULL);
43821308Sache  for (i = 0; i < NUM_TC_STRINGS; i++)
43921308Sache    {
44021308Sache      if (tc_strings[i].tc_var[0] == cap[0] && strcmp (tc_strings[i].tc_var, cap) == 0)
44121308Sache        return *(tc_strings[i].tc_value);
44221308Sache    }
44321308Sache  return ((char *)NULL);
44421308Sache}
44521308Sache
44621308Sache/* A function for the use of tputs () */
44721308Sacheint
44821308Sache_rl_output_character_function (c)
44921308Sache     int c;
45021308Sache{
45121308Sache  return putc (c, _rl_out_stream);
45221308Sache}
45321308Sache
45421308Sache/* Write COUNT characters from STRING to the output stream. */
45521308Sachevoid
45621308Sache_rl_output_some_chars (string, count)
45721308Sache     char *string;
45821308Sache     int count;
45921308Sache{
46021308Sache  fwrite (string, 1, count, _rl_out_stream);
46121308Sache}
46221308Sache
46321308Sache/* Move the cursor back. */
46421308Sacheint
46521308Sache_rl_backspace (count)
46621308Sache     int count;
46721308Sache{
46821308Sache  register int i;
46921308Sache
47021308Sache#if !defined (__GO32__)
47121308Sache  if (term_backspace)
47221308Sache    for (i = 0; i < count; i++)
47321308Sache      tputs (term_backspace, 1, _rl_output_character_function);
47421308Sache  else
47521308Sache#endif /* !__GO32__ */
47621308Sache    for (i = 0; i < count; i++)
47721308Sache      putc ('\b', _rl_out_stream);
47821308Sache  return 0;
47921308Sache}
48021308Sache
48121308Sache/* Move to the start of the next line. */
48221308Sacheint
48321308Sachecrlf ()
48421308Sache{
48521308Sache#if defined (NEW_TTY_DRIVER)
48621308Sache  if (term_cr)
48721308Sache    tputs (term_cr, 1, _rl_output_character_function);
48821308Sache#endif /* NEW_TTY_DRIVER */
48921308Sache  putc ('\n', _rl_out_stream);
49021308Sache  return 0;
49121308Sache}
49221308Sache
49321308Sache/* Ring the terminal bell. */
49421308Sacheint
49521308Sacheding ()
49621308Sache{
49721308Sache  if (readline_echoing_p)
49821308Sache    {
49921308Sache#if !defined (__GO32__)
50021308Sache      switch (_rl_bell_preference)
50121308Sache        {
50221308Sache	case NO_BELL:
50321308Sache	default:
50421308Sache	  break;
50521308Sache	case VISIBLE_BELL:
50621308Sache	  if (visible_bell)
50721308Sache	    {
50821308Sache	      tputs (visible_bell, 1, _rl_output_character_function);
50921308Sache	      break;
51021308Sache	    }
51121308Sache	  /* FALLTHROUGH */
51221308Sache	case AUDIBLE_BELL:
51321308Sache	  fprintf (stderr, "\007");
51421308Sache	  fflush (stderr);
51521308Sache	  break;
51621308Sache        }
51721308Sache#else /* __GO32__ */
51821308Sache      fprintf (stderr, "\007");
51921308Sache      fflush (stderr);
52021308Sache#endif /* __GO32__ */
52121308Sache      return (0);
52221308Sache    }
52321308Sache  return (-1);
52421308Sache}
52521308Sache
52621308Sache/* **************************************************************** */
52721308Sache/*								    */
52821308Sache/*	 	Controlling the Meta Key and Keypad		    */
52921308Sache/*								    */
53021308Sache/* **************************************************************** */
53121308Sache
53221308Sachestatic int
53321308Sacheoutchar (c)
53421308Sache     int c;
53521308Sache{
53621308Sache  return putc (c, rl_outstream);
53721308Sache}
53821308Sache
53921308Sacheint
54021308Sache_rl_enable_meta_key ()
54121308Sache{
54221308Sache  if (term_has_meta && term_mm)
54321308Sache    tputs (term_mm, 1, outchar);
54421308Sache}
54521308Sache
54621308Sachevoid
54721308Sache_rl_control_keypad (on)
54821308Sache     int on;
54921308Sache{
55021308Sache  if (on && term_ks)
55121308Sache    tputs (term_ks, 1, outchar);
55221308Sache  else if (!on && term_ke)
55321308Sache    tputs (term_ke, 1, outchar);
55421308Sache}
555