terminal.c revision 47558
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
5626497Sache#if defined (GWINSZ_IN_SYS_IOCTL) && !defined (TIOCGWINSZ)
5726497Sache#  include <sys/ioctl.h>
5826497Sache#endif /* GWINSZ_IN_SYS_IOCTL && !TIOCGWINSZ */
5926497Sache
6026497Sache#include "rltty.h"
6121308Sache#include "tcap.h"
6221308Sache
6321308Sache/* Some standard library routines. */
6421308Sache#include "readline.h"
6521308Sache#include "history.h"
6621308Sache
6721308Sache/* Variables and functions imported from readline.c */
6821308Sacheextern FILE *_rl_in_stream, *_rl_out_stream;
6921308Sacheextern int readline_echoing_p;
7021308Sacheextern int _rl_bell_preference;
7121308Sacheextern Keymap _rl_keymap;
7221308Sache
7326497Sache/* Functions imported from bind.c */
7426497Sacheextern void _rl_bind_if_unbound ();
7526497Sache
7626497Sache/* Functions imported from shell.c */
7726497Sacheextern void set_lines_and_columns ();
7826497Sacheextern char *get_env_value ();
7926497Sache
8021308Sache/* **************************************************************** */
8121308Sache/*								    */
8221308Sache/*			Terminal and Termcap			    */
8321308Sache/*								    */
8421308Sache/* **************************************************************** */
8521308Sache
8621308Sachestatic char *term_buffer = (char *)NULL;
8721308Sachestatic char *term_string_buffer = (char *)NULL;
8821308Sache
8921308Sachestatic int tcap_initialized;
9021308Sache
9121308Sache/* Non-zero means this terminal can't really do anything. */
9221308Sachestatic int dumb_term;
9321308Sache
9421308Sache#if !defined (__linux__)
9526497Sache#  if defined (__EMX__) || defined (NEED_EXTERN_PC)
9626497Sacheextern
9726497Sache#  endif /* __EMX__ || NEED_EXTERN_PC */
9826497Sachechar PC, *BC, *UP;
9921308Sache#endif /* __linux__ */
10021308Sache
10121308Sache/* Some strings to control terminal actions.  These are output by tputs (). */
10221308Sachechar *term_goto, *term_clreol, *term_cr, *term_clrpag, *term_backspace;
10321308Sachechar *term_pc;
10421308Sache
10521308Sache/* Non-zero if we determine that the terminal can do character insertion. */
10621308Sacheint terminal_can_insert = 0;
10721308Sache
10821308Sache/* How to insert characters. */
10921308Sachechar *term_im, *term_ei, *term_ic, *term_ip, *term_IC;
11021308Sache
11121308Sache/* How to delete characters. */
11221308Sachechar *term_dc, *term_DC;
11321308Sache
11421308Sache#if defined (HACK_TERMCAP_MOTION)
11521308Sachechar *term_forward_char;
11621308Sache#endif  /* HACK_TERMCAP_MOTION */
11721308Sache
11821308Sache/* How to go up a line. */
11921308Sachechar *term_up;
12021308Sache
12121308Sache/* A visible bell, if the terminal can be made to flash the screen. */
12221308Sachestatic char *visible_bell;
12321308Sache
12421308Sache/* Non-zero means the terminal can auto-wrap lines. */
12521308Sacheint _rl_term_autowrap;
12621308Sache
12721308Sache/* Non-zero means that this terminal has a meta key. */
12821308Sachestatic int term_has_meta;
12921308Sache
13021308Sache/* The sequences to write to turn on and off the meta key, if this
13121308Sache   terminal    has one. */
13221308Sachestatic char *term_mm, *term_mo;
13321308Sache
13421308Sache/* The key sequences output by the arrow keys, if this terminal has any. */
13521308Sachestatic char *term_ku, *term_kd, *term_kr, *term_kl;
13621308Sache
13721308Sache/* How to initialize and reset the arrow keys, if this terminal has any. */
13821308Sachestatic char *term_ks, *term_ke;
13921308Sache
14021308Sache/* The key sequences sent by the Home and End keys, if any. */
14121308Sachestatic char *term_kh, *term_kH;
14221308Sache
14321308Sache/* Variables that hold the screen dimensions, used by the display code. */
14421308Sacheint screenwidth, screenheight, screenchars;
14521308Sache
14621308Sache/* Non-zero means the user wants to enable the keypad. */
14721308Sacheint _rl_enable_keypad;
14821308Sache
14921308Sache/* Non-zero means the user wants to enable a meta key. */
15021308Sacheint _rl_enable_meta = 1;
15121308Sache
15221308Sache/* Get readline's idea of the screen size.  TTY is a file descriptor open
15321308Sache   to the terminal.  If IGNORE_ENV is true, we do not pay attention to the
15421308Sache   values of $LINES and $COLUMNS.  The tests for TERM_STRING_BUFFER being
15521308Sache   non-null serve to check whether or not we have initialized termcap. */
15621308Sachevoid
15721308Sache_rl_get_screen_size (tty, ignore_env)
15821308Sache     int tty, ignore_env;
15921308Sache{
16021308Sache  char *ss;
16121308Sache#if defined (TIOCGWINSZ)
16221308Sache  struct winsize window_size;
16321308Sache#endif /* TIOCGWINSZ */
16426497Sache#if defined (__EMX__)
16526497Sache  int sz[2];
16626497Sache#endif
16721308Sache
16821308Sache#if defined (TIOCGWINSZ)
16921308Sache  if (ioctl (tty, TIOCGWINSZ, &window_size) == 0)
17021308Sache    {
17121308Sache      screenwidth = (int) window_size.ws_col;
17221308Sache      screenheight = (int) window_size.ws_row;
17321308Sache    }
17421308Sache#endif /* TIOCGWINSZ */
17521308Sache
17626497Sache#if defined (__EMX__)
17726497Sache  _scrsize (sz);
17826497Sache  screenwidth = sz[0];
17926497Sache  screenheight = sz[1];
18026497Sache#endif
18126497Sache
18221308Sache  /* Environment variable COLUMNS overrides setting of "co" if IGNORE_ENV
18321308Sache     is unset. */
18421308Sache  if (screenwidth <= 0)
18521308Sache    {
18626497Sache      if (ignore_env == 0 && (ss = get_env_value ("COLUMNS")))
18721308Sache	screenwidth = atoi (ss);
18821308Sache
18921308Sache      if (screenwidth <= 0 && term_string_buffer)
19021308Sache	screenwidth = tgetnum ("co");
19121308Sache    }
19221308Sache
19321308Sache  /* Environment variable LINES overrides setting of "li" if IGNORE_ENV
19421308Sache     is unset. */
19521308Sache  if (screenheight <= 0)
19621308Sache    {
19726497Sache      if (ignore_env == 0 && (ss = get_env_value ("LINES")))
19821308Sache	screenheight = atoi (ss);
19921308Sache
20021308Sache      if (screenheight <= 0 && term_string_buffer)
20121308Sache	screenheight = tgetnum ("li");
20221308Sache    }
20321308Sache
20421308Sache  /* If all else fails, default to 80x24 terminal. */
20521308Sache  if (screenwidth <= 1)
20621308Sache    screenwidth = 80;
20721308Sache
20821308Sache  if (screenheight <= 0)
20921308Sache    screenheight = 24;
21021308Sache
21121308Sache  /* If we're being compiled as part of bash, set the environment
21221308Sache     variables $LINES and $COLUMNS to new values.  Otherwise, just
21321308Sache     do a pair of putenv () or setenv () calls. */
21421308Sache  set_lines_and_columns (screenheight, screenwidth);
21521308Sache
21621308Sache  if (!_rl_term_autowrap)
21721308Sache    screenwidth--;
21821308Sache
21921308Sache  screenchars = screenwidth * screenheight;
22021308Sache}
22121308Sache
22221308Sachevoid
22321308Sache_rl_set_screen_size (rows, cols)
22421308Sache     int rows, cols;
22521308Sache{
22621308Sache  screenheight = rows;
22721308Sache  screenwidth = cols;
22821308Sache
22921308Sache  if (_rl_term_autowrap == 0)
23021308Sache    screenwidth--;
23121308Sache
23221308Sache  screenchars = screenwidth * screenheight;
23321308Sache}
23421308Sache
23547558Sachevoid
23647558Sacherl_resize_terminal ()
23747558Sache{
23847558Sache  if (readline_echoing_p)
23947558Sache    {
24047558Sache      _rl_get_screen_size (fileno (rl_instream), 1);
24147558Sache      _rl_redisplay_after_sigwinch ();
24247558Sache    }
24347558Sache}
24447558Sache
24521308Sachestruct _tc_string {
24621308Sache     char *tc_var;
24721308Sache     char **tc_value;
24821308Sache};
24921308Sache
25021308Sache/* This should be kept sorted, just in case we decide to change the
25121308Sache   search algorithm to something smarter. */
25221308Sachestatic struct _tc_string tc_strings[] =
25321308Sache{
25421308Sache  "DC", &term_DC,
25521308Sache  "IC", &term_IC,
25621308Sache  "ce", &term_clreol,
25721308Sache  "cl", &term_clrpag,
25821308Sache  "cr", &term_cr,
25921308Sache  "dc", &term_dc,
26021308Sache  "ei", &term_ei,
26121308Sache  "ic", &term_ic,
26221308Sache  "im", &term_im,
26321308Sache  "kd", &term_kd,
26421308Sache  "kh", &term_kh,	/* home */
26521308Sache  "kH", &term_kH,	/* end */
26621308Sache  "kl", &term_kl,
26721308Sache  "kr", &term_kr,
26821308Sache  "ku", &term_ku,
26921308Sache  "ks", &term_ks,
27021308Sache  "ke", &term_ke,
27121308Sache  "le", &term_backspace,
27221308Sache  "mm", &term_mm,
27321308Sache  "mo", &term_mo,
27421308Sache#if defined (HACK_TERMCAP_MOTION)
27521308Sache  "nd", &term_forward_char,
27621308Sache#endif
27721308Sache  "pc", &term_pc,
27821308Sache  "up", &term_up,
27921308Sache  "vb", &visible_bell,
28021308Sache};
28121308Sache
28221308Sache#define NUM_TC_STRINGS (sizeof (tc_strings) / sizeof (struct _tc_string))
28321308Sache
28421308Sache/* Read the desired terminal capability strings into BP.  The capabilities
28521308Sache   are described in the TC_STRINGS table. */
28621308Sachestatic void
28721308Sacheget_term_capabilities (bp)
28821308Sache     char **bp;
28921308Sache{
29021308Sache  register int i;
29121308Sache
29221308Sache  for (i = 0; i < NUM_TC_STRINGS; i++)
29321308Sache    *(tc_strings[i].tc_value) = tgetstr (tc_strings[i].tc_var, bp);
29421308Sache  tcap_initialized = 1;
29521308Sache}
29621308Sache
29721308Sacheint
29821308Sache_rl_init_terminal_io (terminal_name)
29921308Sache     char *terminal_name;
30021308Sache{
30121308Sache#if defined (__GO32__)
30221308Sache  screenwidth = ScreenCols ();
30321308Sache  screenheight = ScreenRows ();
30421308Sache  screenchars = screenwidth * screenheight;
30521308Sache  term_cr = "\r";
30621308Sache  term_im = term_ei = term_ic = term_IC = (char *)NULL;
30721308Sache  term_up = term_dc = term_DC = visible_bell = (char *)NULL;
30821308Sache
30921308Sache  /* Does the __GO32__ have a meta key?  I don't know. */
31021308Sache  term_has_meta = 0;
31121308Sache  term_mm = term_mo = (char *)NULL;
31221308Sache
31321308Sache  /* It probably has arrow keys, but I don't know what they are. */
31421308Sache  term_ku = term_kd = term_kr = term_kl = (char *)NULL;
31521308Sache
31621308Sache#if defined (HACK_TERMCAP_MOTION)
31721308Sache  term_forward_char = (char *)NULL;
31821308Sache#endif /* HACK_TERMCAP_MOTION */
31921308Sache  terminal_can_insert = _rl_term_autowrap = 0;
32021308Sache  return;
32121308Sache#else /* !__GO32__ */
32221308Sache
32321308Sache  char *term, *buffer;
32421308Sache  int tty;
32521308Sache  Keymap xkeymap;
32621308Sache
32726497Sache  term = terminal_name ? terminal_name : get_env_value ("TERM");
32821308Sache
32921308Sache  if (term_string_buffer == 0)
33021308Sache    term_string_buffer = xmalloc (2032);
33121308Sache
33221308Sache  if (term_buffer == 0)
33321308Sache    term_buffer = xmalloc (4080);
33421308Sache
33521308Sache  buffer = term_string_buffer;
33621308Sache
33721308Sache  term_clrpag = term_cr = term_clreol = (char *)NULL;
33821308Sache
33921308Sache  if (term == 0)
34021308Sache    term = "dumb";
34121308Sache
34221308Sache  if (tgetent (term_buffer, term) <= 0)
34321308Sache    {
34421308Sache      dumb_term = 1;
34521308Sache      screenwidth = 79;
34621308Sache      screenheight = 24;
34721308Sache      screenchars = 79 * 24;
34821308Sache      term_cr = "\r";
34921308Sache      term_im = term_ei = term_ic = term_IC = (char *)NULL;
35021308Sache      term_up = term_dc = term_DC = visible_bell = (char *)NULL;
35121308Sache      term_ku = term_kd = term_kl = term_kr = (char *)NULL;
35221308Sache#if defined (HACK_TERMCAP_MOTION)
35321308Sache      term_forward_char = (char *)NULL;
35421308Sache#endif
35521308Sache      terminal_can_insert = 0;
35621308Sache      return 0;
35721308Sache    }
35821308Sache
35921308Sache  get_term_capabilities (&buffer);
36021308Sache
36121308Sache  /* Set up the variables that the termcap library expects the application
36221308Sache     to provide. */
36321308Sache  PC = term_pc ? *term_pc : 0;
36421308Sache  BC = term_backspace;
36521308Sache  UP = term_up;
36621308Sache
36721308Sache  if (!term_cr)
36821308Sache    term_cr = "\r";
36921308Sache
37021308Sache  tty = rl_instream ? fileno (rl_instream) : 0;
37121308Sache
37221308Sache  screenwidth = screenheight = 0;
37321308Sache
37421308Sache  _rl_term_autowrap = tgetflag ("am") && tgetflag ("xn");
37521308Sache
37621308Sache  _rl_get_screen_size (tty, 0);
37721308Sache
37821308Sache  /* "An application program can assume that the terminal can do
37921308Sache      character insertion if *any one of* the capabilities `IC',
38021308Sache      `im', `ic' or `ip' is provided."  But we can't do anything if
38121308Sache      only `ip' is provided, so... */
38221308Sache  terminal_can_insert = (term_IC || term_im || term_ic);
38321308Sache
38421308Sache  /* Check to see if this terminal has a meta key and clear the capability
38521308Sache     variables if there is none. */
38621308Sache  term_has_meta = (tgetflag ("km") || tgetflag ("MT"));
38721308Sache  if (!term_has_meta)
38821308Sache    term_mm = term_mo = (char *)NULL;
38921308Sache
39021308Sache  /* Attempt to find and bind the arrow keys.  Do not override already
39121308Sache     bound keys in an overzealous attempt, however. */
39221308Sache  xkeymap = _rl_keymap;
39321308Sache
39421308Sache  _rl_keymap = emacs_standard_keymap;
39521308Sache  _rl_bind_if_unbound (term_ku, rl_get_previous_history);
39621308Sache  _rl_bind_if_unbound (term_kd, rl_get_next_history);
39721308Sache  _rl_bind_if_unbound (term_kr, rl_forward);
39821308Sache  _rl_bind_if_unbound (term_kl, rl_backward);
39921308Sache
40021308Sache  _rl_bind_if_unbound (term_kh, rl_beg_of_line);	/* Home */
40121308Sache  _rl_bind_if_unbound (term_kH, rl_end_of_line);	/* End */
40221308Sache
40321308Sache#if defined (VI_MODE)
40421308Sache  _rl_keymap = vi_movement_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#endif /* VI_MODE */
41321308Sache
41421308Sache  _rl_keymap = xkeymap;
41521308Sache
41621308Sache#endif /* !__GO32__ */
41721308Sache  return 0;
41821308Sache}
41921308Sache
42021308Sachechar *
42121308Sacherl_get_termcap (cap)
42221308Sache     char *cap;
42321308Sache{
42421308Sache  register int i;
42521308Sache
42621308Sache  if (tcap_initialized == 0)
42721308Sache    return ((char *)NULL);
42821308Sache  for (i = 0; i < NUM_TC_STRINGS; i++)
42921308Sache    {
43021308Sache      if (tc_strings[i].tc_var[0] == cap[0] && strcmp (tc_strings[i].tc_var, cap) == 0)
43121308Sache        return *(tc_strings[i].tc_value);
43221308Sache    }
43321308Sache  return ((char *)NULL);
43421308Sache}
43521308Sache
43626497Sache/* Re-initialize the terminal considering that the TERM/TERMCAP variable
43726497Sache   has changed. */
43826497Sacheint
43926497Sacherl_reset_terminal (terminal_name)
44026497Sache     char *terminal_name;
44126497Sache{
44226497Sache  _rl_init_terminal_io (terminal_name);
44326497Sache  return 0;
44426497Sache}
44526497Sache
44621308Sache/* A function for the use of tputs () */
44735486Sache#ifdef _MINIX
44835486Sachevoid
44935486Sache_rl_output_character_function (c)
45035486Sache     int c;
45135486Sache{
45235486Sache  putc (c, _rl_out_stream);
45335486Sache}
45435486Sache#else /* !_MINIX */
45521308Sacheint
45621308Sache_rl_output_character_function (c)
45721308Sache     int c;
45821308Sache{
45921308Sache  return putc (c, _rl_out_stream);
46021308Sache}
46135486Sache#endif /* !_MINIX */
46221308Sache/* Write COUNT characters from STRING to the output stream. */
46321308Sachevoid
46421308Sache_rl_output_some_chars (string, count)
46521308Sache     char *string;
46621308Sache     int count;
46721308Sache{
46821308Sache  fwrite (string, 1, count, _rl_out_stream);
46921308Sache}
47021308Sache
47121308Sache/* Move the cursor back. */
47221308Sacheint
47321308Sache_rl_backspace (count)
47421308Sache     int count;
47521308Sache{
47621308Sache  register int i;
47721308Sache
47821308Sache#if !defined (__GO32__)
47921308Sache  if (term_backspace)
48021308Sache    for (i = 0; i < count; i++)
48121308Sache      tputs (term_backspace, 1, _rl_output_character_function);
48221308Sache  else
48321308Sache#endif /* !__GO32__ */
48421308Sache    for (i = 0; i < count; i++)
48521308Sache      putc ('\b', _rl_out_stream);
48621308Sache  return 0;
48721308Sache}
48821308Sache
48921308Sache/* Move to the start of the next line. */
49021308Sacheint
49121308Sachecrlf ()
49221308Sache{
49321308Sache#if defined (NEW_TTY_DRIVER)
49421308Sache  if (term_cr)
49521308Sache    tputs (term_cr, 1, _rl_output_character_function);
49621308Sache#endif /* NEW_TTY_DRIVER */
49721308Sache  putc ('\n', _rl_out_stream);
49821308Sache  return 0;
49921308Sache}
50021308Sache
50121308Sache/* Ring the terminal bell. */
50221308Sacheint
50321308Sacheding ()
50421308Sache{
50521308Sache  if (readline_echoing_p)
50621308Sache    {
50721308Sache#if !defined (__GO32__)
50821308Sache      switch (_rl_bell_preference)
50921308Sache        {
51021308Sache	case NO_BELL:
51121308Sache	default:
51221308Sache	  break;
51321308Sache	case VISIBLE_BELL:
51421308Sache	  if (visible_bell)
51521308Sache	    {
51621308Sache	      tputs (visible_bell, 1, _rl_output_character_function);
51721308Sache	      break;
51821308Sache	    }
51921308Sache	  /* FALLTHROUGH */
52021308Sache	case AUDIBLE_BELL:
52121308Sache	  fprintf (stderr, "\007");
52221308Sache	  fflush (stderr);
52321308Sache	  break;
52421308Sache        }
52521308Sache#else /* __GO32__ */
52621308Sache      fprintf (stderr, "\007");
52721308Sache      fflush (stderr);
52821308Sache#endif /* __GO32__ */
52921308Sache      return (0);
53021308Sache    }
53121308Sache  return (-1);
53221308Sache}
53321308Sache
53421308Sache/* **************************************************************** */
53521308Sache/*								    */
53621308Sache/*	 	Controlling the Meta Key and Keypad		    */
53721308Sache/*								    */
53821308Sache/* **************************************************************** */
53921308Sache
54026497Sachevoid
54121308Sache_rl_enable_meta_key ()
54221308Sache{
54321308Sache  if (term_has_meta && term_mm)
54435486Sache    tputs (term_mm, 1, _rl_output_character_function);
54521308Sache}
54621308Sache
54721308Sachevoid
54821308Sache_rl_control_keypad (on)
54921308Sache     int on;
55021308Sache{
55121308Sache  if (on && term_ks)
55235486Sache    tputs (term_ks, 1, _rl_output_character_function);
55321308Sache  else if (!on && term_ke)
55435486Sache    tputs (term_ke, 1, _rl_output_character_function);
55521308Sache}
556