terminal.c revision 26497
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
23521308Sachestruct _tc_string {
23621308Sache     char *tc_var;
23721308Sache     char **tc_value;
23821308Sache};
23921308Sache
24021308Sache/* This should be kept sorted, just in case we decide to change the
24121308Sache   search algorithm to something smarter. */
24221308Sachestatic struct _tc_string tc_strings[] =
24321308Sache{
24421308Sache  "DC", &term_DC,
24521308Sache  "IC", &term_IC,
24621308Sache  "ce", &term_clreol,
24721308Sache  "cl", &term_clrpag,
24821308Sache  "cr", &term_cr,
24921308Sache  "dc", &term_dc,
25021308Sache  "ei", &term_ei,
25121308Sache  "ic", &term_ic,
25221308Sache  "im", &term_im,
25321308Sache  "kd", &term_kd,
25421308Sache  "kh", &term_kh,	/* home */
25521308Sache  "kH", &term_kH,	/* end */
25621308Sache  "kl", &term_kl,
25721308Sache  "kr", &term_kr,
25821308Sache  "ku", &term_ku,
25921308Sache  "ks", &term_ks,
26021308Sache  "ke", &term_ke,
26121308Sache  "le", &term_backspace,
26221308Sache  "mm", &term_mm,
26321308Sache  "mo", &term_mo,
26421308Sache#if defined (HACK_TERMCAP_MOTION)
26521308Sache  "nd", &term_forward_char,
26621308Sache#endif
26721308Sache  "pc", &term_pc,
26821308Sache  "up", &term_up,
26921308Sache  "vb", &visible_bell,
27021308Sache};
27121308Sache
27221308Sache#define NUM_TC_STRINGS (sizeof (tc_strings) / sizeof (struct _tc_string))
27321308Sache
27421308Sache/* Read the desired terminal capability strings into BP.  The capabilities
27521308Sache   are described in the TC_STRINGS table. */
27621308Sachestatic void
27721308Sacheget_term_capabilities (bp)
27821308Sache     char **bp;
27921308Sache{
28021308Sache  register int i;
28121308Sache
28221308Sache  for (i = 0; i < NUM_TC_STRINGS; i++)
28321308Sache    *(tc_strings[i].tc_value) = tgetstr (tc_strings[i].tc_var, bp);
28421308Sache  tcap_initialized = 1;
28521308Sache}
28621308Sache
28721308Sacheint
28821308Sache_rl_init_terminal_io (terminal_name)
28921308Sache     char *terminal_name;
29021308Sache{
29121308Sache#if defined (__GO32__)
29221308Sache  screenwidth = ScreenCols ();
29321308Sache  screenheight = ScreenRows ();
29421308Sache  screenchars = screenwidth * screenheight;
29521308Sache  term_cr = "\r";
29621308Sache  term_im = term_ei = term_ic = term_IC = (char *)NULL;
29721308Sache  term_up = term_dc = term_DC = visible_bell = (char *)NULL;
29821308Sache
29921308Sache  /* Does the __GO32__ have a meta key?  I don't know. */
30021308Sache  term_has_meta = 0;
30121308Sache  term_mm = term_mo = (char *)NULL;
30221308Sache
30321308Sache  /* It probably has arrow keys, but I don't know what they are. */
30421308Sache  term_ku = term_kd = term_kr = term_kl = (char *)NULL;
30521308Sache
30621308Sache#if defined (HACK_TERMCAP_MOTION)
30721308Sache  term_forward_char = (char *)NULL;
30821308Sache#endif /* HACK_TERMCAP_MOTION */
30921308Sache  terminal_can_insert = _rl_term_autowrap = 0;
31021308Sache  return;
31121308Sache#else /* !__GO32__ */
31221308Sache
31321308Sache  char *term, *buffer;
31421308Sache  int tty;
31521308Sache  Keymap xkeymap;
31621308Sache
31726497Sache  term = terminal_name ? terminal_name : get_env_value ("TERM");
31821308Sache
31921308Sache  if (term_string_buffer == 0)
32021308Sache    term_string_buffer = xmalloc (2032);
32121308Sache
32221308Sache  if (term_buffer == 0)
32321308Sache    term_buffer = xmalloc (4080);
32421308Sache
32521308Sache  buffer = term_string_buffer;
32621308Sache
32721308Sache  term_clrpag = term_cr = term_clreol = (char *)NULL;
32821308Sache
32921308Sache  if (term == 0)
33021308Sache    term = "dumb";
33121308Sache
33221308Sache  if (tgetent (term_buffer, term) <= 0)
33321308Sache    {
33421308Sache      dumb_term = 1;
33521308Sache      screenwidth = 79;
33621308Sache      screenheight = 24;
33721308Sache      screenchars = 79 * 24;
33821308Sache      term_cr = "\r";
33921308Sache      term_im = term_ei = term_ic = term_IC = (char *)NULL;
34021308Sache      term_up = term_dc = term_DC = visible_bell = (char *)NULL;
34121308Sache      term_ku = term_kd = term_kl = term_kr = (char *)NULL;
34221308Sache#if defined (HACK_TERMCAP_MOTION)
34321308Sache      term_forward_char = (char *)NULL;
34421308Sache#endif
34521308Sache      terminal_can_insert = 0;
34621308Sache      return 0;
34721308Sache    }
34821308Sache
34921308Sache  get_term_capabilities (&buffer);
35021308Sache
35121308Sache  /* Set up the variables that the termcap library expects the application
35221308Sache     to provide. */
35321308Sache  PC = term_pc ? *term_pc : 0;
35421308Sache  BC = term_backspace;
35521308Sache  UP = term_up;
35621308Sache
35721308Sache  if (!term_cr)
35821308Sache    term_cr = "\r";
35921308Sache
36021308Sache  tty = rl_instream ? fileno (rl_instream) : 0;
36121308Sache
36221308Sache  screenwidth = screenheight = 0;
36321308Sache
36421308Sache  _rl_term_autowrap = tgetflag ("am") && tgetflag ("xn");
36521308Sache
36621308Sache  _rl_get_screen_size (tty, 0);
36721308Sache
36821308Sache  /* "An application program can assume that the terminal can do
36921308Sache      character insertion if *any one of* the capabilities `IC',
37021308Sache      `im', `ic' or `ip' is provided."  But we can't do anything if
37121308Sache      only `ip' is provided, so... */
37221308Sache  terminal_can_insert = (term_IC || term_im || term_ic);
37321308Sache
37421308Sache  /* Check to see if this terminal has a meta key and clear the capability
37521308Sache     variables if there is none. */
37621308Sache  term_has_meta = (tgetflag ("km") || tgetflag ("MT"));
37721308Sache  if (!term_has_meta)
37821308Sache    term_mm = term_mo = (char *)NULL;
37921308Sache
38021308Sache  /* Attempt to find and bind the arrow keys.  Do not override already
38121308Sache     bound keys in an overzealous attempt, however. */
38221308Sache  xkeymap = _rl_keymap;
38321308Sache
38421308Sache  _rl_keymap = emacs_standard_keymap;
38521308Sache  _rl_bind_if_unbound (term_ku, rl_get_previous_history);
38621308Sache  _rl_bind_if_unbound (term_kd, rl_get_next_history);
38721308Sache  _rl_bind_if_unbound (term_kr, rl_forward);
38821308Sache  _rl_bind_if_unbound (term_kl, rl_backward);
38921308Sache
39021308Sache  _rl_bind_if_unbound (term_kh, rl_beg_of_line);	/* Home */
39121308Sache  _rl_bind_if_unbound (term_kH, rl_end_of_line);	/* End */
39221308Sache
39321308Sache#if defined (VI_MODE)
39421308Sache  _rl_keymap = vi_movement_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#endif /* VI_MODE */
40321308Sache
40421308Sache  _rl_keymap = xkeymap;
40521308Sache
40621308Sache#endif /* !__GO32__ */
40721308Sache  return 0;
40821308Sache}
40921308Sache
41021308Sachechar *
41121308Sacherl_get_termcap (cap)
41221308Sache     char *cap;
41321308Sache{
41421308Sache  register int i;
41521308Sache
41621308Sache  if (tcap_initialized == 0)
41721308Sache    return ((char *)NULL);
41821308Sache  for (i = 0; i < NUM_TC_STRINGS; i++)
41921308Sache    {
42021308Sache      if (tc_strings[i].tc_var[0] == cap[0] && strcmp (tc_strings[i].tc_var, cap) == 0)
42121308Sache        return *(tc_strings[i].tc_value);
42221308Sache    }
42321308Sache  return ((char *)NULL);
42421308Sache}
42521308Sache
42626497Sache/* Re-initialize the terminal considering that the TERM/TERMCAP variable
42726497Sache   has changed. */
42826497Sacheint
42926497Sacherl_reset_terminal (terminal_name)
43026497Sache     char *terminal_name;
43126497Sache{
43226497Sache  _rl_init_terminal_io (terminal_name);
43326497Sache  return 0;
43426497Sache}
43526497Sache
43621308Sache/* A function for the use of tputs () */
43721308Sacheint
43821308Sache_rl_output_character_function (c)
43921308Sache     int c;
44021308Sache{
44121308Sache  return putc (c, _rl_out_stream);
44221308Sache}
44321308Sache
44421308Sache/* Write COUNT characters from STRING to the output stream. */
44521308Sachevoid
44621308Sache_rl_output_some_chars (string, count)
44721308Sache     char *string;
44821308Sache     int count;
44921308Sache{
45021308Sache  fwrite (string, 1, count, _rl_out_stream);
45121308Sache}
45221308Sache
45321308Sache/* Move the cursor back. */
45421308Sacheint
45521308Sache_rl_backspace (count)
45621308Sache     int count;
45721308Sache{
45821308Sache  register int i;
45921308Sache
46021308Sache#if !defined (__GO32__)
46121308Sache  if (term_backspace)
46221308Sache    for (i = 0; i < count; i++)
46321308Sache      tputs (term_backspace, 1, _rl_output_character_function);
46421308Sache  else
46521308Sache#endif /* !__GO32__ */
46621308Sache    for (i = 0; i < count; i++)
46721308Sache      putc ('\b', _rl_out_stream);
46821308Sache  return 0;
46921308Sache}
47021308Sache
47121308Sache/* Move to the start of the next line. */
47221308Sacheint
47321308Sachecrlf ()
47421308Sache{
47521308Sache#if defined (NEW_TTY_DRIVER)
47621308Sache  if (term_cr)
47721308Sache    tputs (term_cr, 1, _rl_output_character_function);
47821308Sache#endif /* NEW_TTY_DRIVER */
47921308Sache  putc ('\n', _rl_out_stream);
48021308Sache  return 0;
48121308Sache}
48221308Sache
48321308Sache/* Ring the terminal bell. */
48421308Sacheint
48521308Sacheding ()
48621308Sache{
48721308Sache  if (readline_echoing_p)
48821308Sache    {
48921308Sache#if !defined (__GO32__)
49021308Sache      switch (_rl_bell_preference)
49121308Sache        {
49221308Sache	case NO_BELL:
49321308Sache	default:
49421308Sache	  break;
49521308Sache	case VISIBLE_BELL:
49621308Sache	  if (visible_bell)
49721308Sache	    {
49821308Sache	      tputs (visible_bell, 1, _rl_output_character_function);
49921308Sache	      break;
50021308Sache	    }
50121308Sache	  /* FALLTHROUGH */
50221308Sache	case AUDIBLE_BELL:
50321308Sache	  fprintf (stderr, "\007");
50421308Sache	  fflush (stderr);
50521308Sache	  break;
50621308Sache        }
50721308Sache#else /* __GO32__ */
50821308Sache      fprintf (stderr, "\007");
50921308Sache      fflush (stderr);
51021308Sache#endif /* __GO32__ */
51121308Sache      return (0);
51221308Sache    }
51321308Sache  return (-1);
51421308Sache}
51521308Sache
51621308Sache/* **************************************************************** */
51721308Sache/*								    */
51821308Sache/*	 	Controlling the Meta Key and Keypad		    */
51921308Sache/*								    */
52021308Sache/* **************************************************************** */
52121308Sache
52221308Sachestatic int
52321308Sacheoutchar (c)
52421308Sache     int c;
52521308Sache{
52621308Sache  return putc (c, rl_outstream);
52721308Sache}
52821308Sache
52926497Sachevoid
53021308Sache_rl_enable_meta_key ()
53121308Sache{
53221308Sache  if (term_has_meta && term_mm)
53321308Sache    tputs (term_mm, 1, outchar);
53421308Sache}
53521308Sache
53621308Sachevoid
53721308Sache_rl_control_keypad (on)
53821308Sache     int on;
53921308Sache{
54021308Sache  if (on && term_ks)
54121308Sache    tputs (term_ks, 1, outchar);
54221308Sache  else if (!on && term_ke)
54321308Sache    tputs (term_ke, 1, outchar);
54421308Sache}
545