terminal.c revision 21308
1130561Sobrien/* terminal.c -- controlling the terminal with termcap. */
2130561Sobrien
3130561Sobrien/* Copyright (C) 1996 Free Software Foundation, Inc.
4130561Sobrien
5130561Sobrien   This file is part of the GNU Readline Library, a library for
6130561Sobrien   reading lines of text with interactive input and history editing.
7130561Sobrien
8130561Sobrien   The GNU Readline Library is free software; you can redistribute it
9130561Sobrien   and/or modify it under the terms of the GNU General Public License
10130561Sobrien   as published by the Free Software Foundation; either version 1, or
11130561Sobrien   (at your option) any later version.
12130561Sobrien
13130561Sobrien   The GNU Readline Library is distributed in the hope that it will be
14130561Sobrien   useful, but WITHOUT ANY WARRANTY; without even the implied warranty
15130561Sobrien   of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16130561Sobrien   GNU General Public License for more details.
17130561Sobrien
18218822Sdim   The GNU General Public License is often shipped with GNU software, and
19130561Sobrien   is generally kept in a file called COPYING or LICENSE.  If you do not
20130561Sobrien   have a copy of the license, write to the Free Software Foundation,
21130561Sobrien   675 Mass Ave, Cambridge, MA 02139, USA. */
22130561Sobrien#define READLINE_LIBRARY
23130561Sobrien
24130561Sobrien#if defined (HAVE_CONFIG_H)
25130561Sobrien#  include <config.h>
26130561Sobrien#endif
27130561Sobrien
28130561Sobrien#include <sys/types.h>
29130561Sobrien#include "posixstat.h"
30130561Sobrien#include <fcntl.h>
31130561Sobrien#if defined (HAVE_SYS_FILE_H)
32130561Sobrien#  include <sys/file.h>
33130561Sobrien#endif /* HAVE_SYS_FILE_H */
34130561Sobrien
35130561Sobrien#if defined (HAVE_UNISTD_H)
36130561Sobrien#  include <unistd.h>
37130561Sobrien#endif /* HAVE_UNISTD_H */
38130561Sobrien
39130561Sobrien#if defined (HAVE_STDLIB_H)
40130561Sobrien#  include <stdlib.h>
41130561Sobrien#else
42130561Sobrien#  include "ansi_stdlib.h"
43130561Sobrien#endif /* HAVE_STDLIB_H */
44130561Sobrien
45130561Sobrien#if defined (HAVE_LOCALE_H)
46130561Sobrien#  include <locale.h>
47130561Sobrien#endif
48130561Sobrien
49130561Sobrien#include <signal.h>
50130561Sobrien#include <stdio.h>
51130561Sobrien#include <setjmp.h>
52130561Sobrien
53130561Sobrien/* System-specific feature definitions and include files. */
54130561Sobrien#include "rldefs.h"
55130561Sobrien
56130561Sobrien#include "tcap.h"
57130561Sobrien
58130561Sobrien#if defined (GWINSZ_IN_SYS_IOCTL)
59130561Sobrien#  include <sys/ioctl.h>
60130561Sobrien#endif /* GWINSZ_IN_SYS_IOCTL */
61130561Sobrien
62130561Sobrien/* Some standard library routines. */
63130561Sobrien#include "readline.h"
64130561Sobrien#include "history.h"
65130561Sobrien
66130561Sobrien/* Variables and functions imported from readline.c */
67130561Sobrienextern FILE *_rl_in_stream, *_rl_out_stream;
68130561Sobrienextern int readline_echoing_p;
69130561Sobrienextern int _rl_bell_preference;
70130561Sobrienextern Keymap _rl_keymap;
71130561Sobrien
72130561Sobrien/* **************************************************************** */
73130561Sobrien/*								    */
74130561Sobrien/*			Terminal and Termcap			    */
75130561Sobrien/*								    */
76130561Sobrien/* **************************************************************** */
77130561Sobrien
78130561Sobrienstatic char *term_buffer = (char *)NULL;
79130561Sobrienstatic char *term_string_buffer = (char *)NULL;
80130561Sobrien
81130561Sobrienstatic int tcap_initialized;
82130561Sobrien
83130561Sobrien/* Non-zero means this terminal can't really do anything. */
84130561Sobrienstatic int dumb_term;
85130561Sobrien
86130561Sobrien#if !defined (__linux__)
87130561Sobrien/* If this causes problems, add back the `extern'. */
88130561Sobrien/*extern*/ char PC, *BC, *UP;
89130561Sobrien#endif /* __linux__ */
90130561Sobrien
91130561Sobrien/* Some strings to control terminal actions.  These are output by tputs (). */
92130561Sobrienchar *term_goto, *term_clreol, *term_cr, *term_clrpag, *term_backspace;
93130561Sobrienchar *term_pc;
94130561Sobrien
95130561Sobrien/* Non-zero if we determine that the terminal can do character insertion. */
96130561Sobrienint terminal_can_insert = 0;
97130561Sobrien
98130561Sobrien/* How to insert characters. */
99130561Sobrienchar *term_im, *term_ei, *term_ic, *term_ip, *term_IC;
100130561Sobrien
101130561Sobrien/* How to delete characters. */
102130561Sobrienchar *term_dc, *term_DC;
103130561Sobrien
104130561Sobrien#if defined (HACK_TERMCAP_MOTION)
105130561Sobrienchar *term_forward_char;
106130561Sobrien#endif  /* HACK_TERMCAP_MOTION */
107130561Sobrien
108130561Sobrien/* How to go up a line. */
109130561Sobrienchar *term_up;
110130561Sobrien
111130561Sobrien/* A visible bell, if the terminal can be made to flash the screen. */
112130561Sobrienstatic char *visible_bell;
113130561Sobrien
114130561Sobrien/* Non-zero means the terminal can auto-wrap lines. */
115130561Sobrienint _rl_term_autowrap;
116130561Sobrien
117130561Sobrien/* Non-zero means that this terminal has a meta key. */
118130561Sobrienstatic int term_has_meta;
119130561Sobrien
120130561Sobrien/* The sequences to write to turn on and off the meta key, if this
121130561Sobrien   terminal    has one. */
122130561Sobrienstatic char *term_mm, *term_mo;
123130561Sobrien
124130561Sobrien/* The key sequences output by the arrow keys, if this terminal has any. */
125130561Sobrienstatic char *term_ku, *term_kd, *term_kr, *term_kl;
126130561Sobrien
127130561Sobrien/* How to initialize and reset the arrow keys, if this terminal has any. */
128130561Sobrienstatic char *term_ks, *term_ke;
129130561Sobrien
130130561Sobrien/* The key sequences sent by the Home and End keys, if any. */
131130561Sobrienstatic char *term_kh, *term_kH;
132130561Sobrien
133130561Sobrien/* Variables that hold the screen dimensions, used by the display code. */
134130561Sobrienint screenwidth, screenheight, screenchars;
135130561Sobrien
136130561Sobrien/* Non-zero means the user wants to enable the keypad. */
137130561Sobrienint _rl_enable_keypad;
138130561Sobrien
139130561Sobrien/* Non-zero means the user wants to enable a meta key. */
140130561Sobrienint _rl_enable_meta = 1;
141130561Sobrien
142130561Sobrien/* Re-initialize the terminal considering that the TERM/TERMCAP variable
143130561Sobrien   has changed. */
144130561Sobrienint
145130561Sobrienrl_reset_terminal (terminal_name)
146130561Sobrien     char *terminal_name;
147130561Sobrien{
148130561Sobrien  _rl_init_terminal_io (terminal_name);
149130561Sobrien  return 0;
150130561Sobrien}
151130561Sobrien
152130561Sobrien#if !defined (SHELL)
153130561Sobrienstatic void
154130561Sobrienset_lines_and_columns (lines, cols)
155130561Sobrien     int lines, cols;
156130561Sobrien{
157130561Sobrien  char *b;
158130561Sobrien
159130561Sobrien#if defined (HAVE_PUTENV)
160130561Sobrien  b = xmalloc (24);
161130561Sobrien  sprintf (b, "LINES=%d", lines);
162130561Sobrien  putenv (b);
163130561Sobrien  b = xmalloc (24);
164130561Sobrien  sprintf (b, "COLUMNS=%d", cols);
165130561Sobrien  putenv (b);
166130561Sobrien#else /* !HAVE_PUTENV */
167130561Sobrien#  if defined (HAVE_SETENV)
168130561Sobrien  b = xmalloc (8);
169130561Sobrien  sprintf (b, "%d", lines);
170130561Sobrien  setenv ("LINES", b, 1);
171130561Sobrien  b = xmalloc (8);
172130561Sobrien  sprintf (b, "%d", cols);
173130561Sobrien  setenv ("COLUMNS", b, 1);
174130561Sobrien#  endif /* HAVE_SETENV */
175130561Sobrien#endif /* !HAVE_PUTENV */
176130561Sobrien}
177130561Sobrien#else /* SHELL */
178130561Sobrienextern void set_lines_and_columns ();
179130561Sobrien#endif /* SHELL */
180130561Sobrien
181130561Sobrien/* Get readline's idea of the screen size.  TTY is a file descriptor open
182130561Sobrien   to the terminal.  If IGNORE_ENV is true, we do not pay attention to the
183130561Sobrien   values of $LINES and $COLUMNS.  The tests for TERM_STRING_BUFFER being
184130561Sobrien   non-null serve to check whether or not we have initialized termcap. */
185130561Sobrienvoid
186130561Sobrien_rl_get_screen_size (tty, ignore_env)
187130561Sobrien     int tty, ignore_env;
188130561Sobrien{
189130561Sobrien  char *ss;
190130561Sobrien#if defined (TIOCGWINSZ)
191130561Sobrien  struct winsize window_size;
192130561Sobrien#endif /* TIOCGWINSZ */
193130561Sobrien
194130561Sobrien#if defined (TIOCGWINSZ)
195130561Sobrien  if (ioctl (tty, TIOCGWINSZ, &window_size) == 0)
196130561Sobrien    {
197130561Sobrien      screenwidth = (int) window_size.ws_col;
198130561Sobrien      screenheight = (int) window_size.ws_row;
199130561Sobrien    }
200130561Sobrien#endif /* TIOCGWINSZ */
201130561Sobrien
202130561Sobrien  /* Environment variable COLUMNS overrides setting of "co" if IGNORE_ENV
203130561Sobrien     is unset. */
204130561Sobrien  if (screenwidth <= 0)
205130561Sobrien    {
206130561Sobrien      if (ignore_env == 0 && (ss = getenv ("COLUMNS")))
207130561Sobrien	screenwidth = atoi (ss);
208130561Sobrien
209130561Sobrien      if (screenwidth <= 0 && term_string_buffer)
210130561Sobrien	screenwidth = tgetnum ("co");
211130561Sobrien    }
212130561Sobrien
213130561Sobrien  /* Environment variable LINES overrides setting of "li" if IGNORE_ENV
214130561Sobrien     is unset. */
215130561Sobrien  if (screenheight <= 0)
216130561Sobrien    {
217130561Sobrien      if (ignore_env == 0 && (ss = getenv ("LINES")))
218130561Sobrien	screenheight = atoi (ss);
219130561Sobrien
220130561Sobrien      if (screenheight <= 0 && term_string_buffer)
221130561Sobrien	screenheight = tgetnum ("li");
222130561Sobrien    }
223130561Sobrien
224130561Sobrien  /* If all else fails, default to 80x24 terminal. */
225130561Sobrien  if (screenwidth <= 1)
226130561Sobrien    screenwidth = 80;
227130561Sobrien
228130561Sobrien  if (screenheight <= 0)
229130561Sobrien    screenheight = 24;
230130561Sobrien
231130561Sobrien  /* If we're being compiled as part of bash, set the environment
232130561Sobrien     variables $LINES and $COLUMNS to new values.  Otherwise, just
233130561Sobrien     do a pair of putenv () or setenv () calls. */
234130561Sobrien  set_lines_and_columns (screenheight, screenwidth);
235130561Sobrien
236130561Sobrien  if (!_rl_term_autowrap)
237130561Sobrien    screenwidth--;
238130561Sobrien
239130561Sobrien  screenchars = screenwidth * screenheight;
240130561Sobrien}
241130561Sobrien
242130561Sobrienvoid
243130561Sobrien_rl_set_screen_size (rows, cols)
244130561Sobrien     int rows, cols;
245130561Sobrien{
246130561Sobrien  screenheight = rows;
247130561Sobrien  screenwidth = cols;
248130561Sobrien
249130561Sobrien  if (_rl_term_autowrap == 0)
250130561Sobrien    screenwidth--;
251130561Sobrien
252130561Sobrien  screenchars = screenwidth * screenheight;
253130561Sobrien}
254130561Sobrien
255130561Sobrienstruct _tc_string {
256130561Sobrien     char *tc_var;
257130561Sobrien     char **tc_value;
258130561Sobrien};
259130561Sobrien
260130561Sobrien/* This should be kept sorted, just in case we decide to change the
261130561Sobrien   search algorithm to something smarter. */
262130561Sobrienstatic struct _tc_string tc_strings[] =
263130561Sobrien{
264130561Sobrien  "DC", &term_DC,
265130561Sobrien  "IC", &term_IC,
266130561Sobrien  "ce", &term_clreol,
267130561Sobrien  "cl", &term_clrpag,
268130561Sobrien  "cr", &term_cr,
269130561Sobrien  "dc", &term_dc,
270130561Sobrien  "ei", &term_ei,
271130561Sobrien  "ic", &term_ic,
272130561Sobrien  "im", &term_im,
273130561Sobrien  "kd", &term_kd,
274130561Sobrien  "kh", &term_kh,	/* home */
275130561Sobrien  "kH", &term_kH,	/* end */
276130561Sobrien  "kl", &term_kl,
277130561Sobrien  "kr", &term_kr,
278130561Sobrien  "ku", &term_ku,
279130561Sobrien  "ks", &term_ks,
280130561Sobrien  "ke", &term_ke,
281130561Sobrien  "le", &term_backspace,
282130561Sobrien  "mm", &term_mm,
283  "mo", &term_mo,
284#if defined (HACK_TERMCAP_MOTION)
285  "nd", &term_forward_char,
286#endif
287  "pc", &term_pc,
288  "up", &term_up,
289  "vb", &visible_bell,
290};
291
292#define NUM_TC_STRINGS (sizeof (tc_strings) / sizeof (struct _tc_string))
293
294/* Read the desired terminal capability strings into BP.  The capabilities
295   are described in the TC_STRINGS table. */
296static void
297get_term_capabilities (bp)
298     char **bp;
299{
300  register int i;
301
302  for (i = 0; i < NUM_TC_STRINGS; i++)
303    *(tc_strings[i].tc_value) = tgetstr (tc_strings[i].tc_var, bp);
304  tcap_initialized = 1;
305}
306
307int
308_rl_init_terminal_io (terminal_name)
309     char *terminal_name;
310{
311#if defined (__GO32__)
312  screenwidth = ScreenCols ();
313  screenheight = ScreenRows ();
314  screenchars = screenwidth * screenheight;
315  term_cr = "\r";
316  term_im = term_ei = term_ic = term_IC = (char *)NULL;
317  term_up = term_dc = term_DC = visible_bell = (char *)NULL;
318
319  /* Does the __GO32__ have a meta key?  I don't know. */
320  term_has_meta = 0;
321  term_mm = term_mo = (char *)NULL;
322
323  /* It probably has arrow keys, but I don't know what they are. */
324  term_ku = term_kd = term_kr = term_kl = (char *)NULL;
325
326#if defined (HACK_TERMCAP_MOTION)
327  term_forward_char = (char *)NULL;
328#endif /* HACK_TERMCAP_MOTION */
329  terminal_can_insert = _rl_term_autowrap = 0;
330  return;
331#else /* !__GO32__ */
332
333  char *term, *buffer;
334  int tty;
335  Keymap xkeymap;
336
337  term = terminal_name ? terminal_name : getenv ("TERM");
338
339  if (term_string_buffer == 0)
340    term_string_buffer = xmalloc (2032);
341
342  if (term_buffer == 0)
343    term_buffer = xmalloc (4080);
344
345  buffer = term_string_buffer;
346
347  term_clrpag = term_cr = term_clreol = (char *)NULL;
348
349  if (term == 0)
350    term = "dumb";
351
352  if (tgetent (term_buffer, term) <= 0)
353    {
354      dumb_term = 1;
355      screenwidth = 79;
356      screenheight = 24;
357      screenchars = 79 * 24;
358      term_cr = "\r";
359      term_im = term_ei = term_ic = term_IC = (char *)NULL;
360      term_up = term_dc = term_DC = visible_bell = (char *)NULL;
361      term_ku = term_kd = term_kl = term_kr = (char *)NULL;
362#if defined (HACK_TERMCAP_MOTION)
363      term_forward_char = (char *)NULL;
364#endif
365      terminal_can_insert = 0;
366      return 0;
367    }
368
369  get_term_capabilities (&buffer);
370
371  /* Set up the variables that the termcap library expects the application
372     to provide. */
373  PC = term_pc ? *term_pc : 0;
374  BC = term_backspace;
375  UP = term_up;
376
377  if (!term_cr)
378    term_cr = "\r";
379
380  tty = rl_instream ? fileno (rl_instream) : 0;
381
382  screenwidth = screenheight = 0;
383
384  _rl_term_autowrap = tgetflag ("am") && tgetflag ("xn");
385
386  _rl_get_screen_size (tty, 0);
387
388  /* "An application program can assume that the terminal can do
389      character insertion if *any one of* the capabilities `IC',
390      `im', `ic' or `ip' is provided."  But we can't do anything if
391      only `ip' is provided, so... */
392  terminal_can_insert = (term_IC || term_im || term_ic);
393
394  /* Check to see if this terminal has a meta key and clear the capability
395     variables if there is none. */
396  term_has_meta = (tgetflag ("km") || tgetflag ("MT"));
397  if (!term_has_meta)
398    term_mm = term_mo = (char *)NULL;
399
400  /* Attempt to find and bind the arrow keys.  Do not override already
401     bound keys in an overzealous attempt, however. */
402  xkeymap = _rl_keymap;
403
404  _rl_keymap = emacs_standard_keymap;
405  _rl_bind_if_unbound (term_ku, rl_get_previous_history);
406  _rl_bind_if_unbound (term_kd, rl_get_next_history);
407  _rl_bind_if_unbound (term_kr, rl_forward);
408  _rl_bind_if_unbound (term_kl, rl_backward);
409
410  _rl_bind_if_unbound (term_kh, rl_beg_of_line);	/* Home */
411  _rl_bind_if_unbound (term_kH, rl_end_of_line);	/* End */
412
413#if defined (VI_MODE)
414  _rl_keymap = vi_movement_keymap;
415  _rl_bind_if_unbound (term_ku, rl_get_previous_history);
416  _rl_bind_if_unbound (term_kd, rl_get_next_history);
417  _rl_bind_if_unbound (term_kr, rl_forward);
418  _rl_bind_if_unbound (term_kl, rl_backward);
419
420  _rl_bind_if_unbound (term_kh, rl_beg_of_line);	/* Home */
421  _rl_bind_if_unbound (term_kH, rl_end_of_line);	/* End */
422#endif /* VI_MODE */
423
424  _rl_keymap = xkeymap;
425
426#endif /* !__GO32__ */
427  return 0;
428}
429
430char *
431rl_get_termcap (cap)
432     char *cap;
433{
434  register int i;
435
436  if (tcap_initialized == 0)
437    return ((char *)NULL);
438  for (i = 0; i < NUM_TC_STRINGS; i++)
439    {
440      if (tc_strings[i].tc_var[0] == cap[0] && strcmp (tc_strings[i].tc_var, cap) == 0)
441        return *(tc_strings[i].tc_value);
442    }
443  return ((char *)NULL);
444}
445
446/* A function for the use of tputs () */
447int
448_rl_output_character_function (c)
449     int c;
450{
451  return putc (c, _rl_out_stream);
452}
453
454/* Write COUNT characters from STRING to the output stream. */
455void
456_rl_output_some_chars (string, count)
457     char *string;
458     int count;
459{
460  fwrite (string, 1, count, _rl_out_stream);
461}
462
463/* Move the cursor back. */
464int
465_rl_backspace (count)
466     int count;
467{
468  register int i;
469
470#if !defined (__GO32__)
471  if (term_backspace)
472    for (i = 0; i < count; i++)
473      tputs (term_backspace, 1, _rl_output_character_function);
474  else
475#endif /* !__GO32__ */
476    for (i = 0; i < count; i++)
477      putc ('\b', _rl_out_stream);
478  return 0;
479}
480
481/* Move to the start of the next line. */
482int
483crlf ()
484{
485#if defined (NEW_TTY_DRIVER)
486  if (term_cr)
487    tputs (term_cr, 1, _rl_output_character_function);
488#endif /* NEW_TTY_DRIVER */
489  putc ('\n', _rl_out_stream);
490  return 0;
491}
492
493/* Ring the terminal bell. */
494int
495ding ()
496{
497  if (readline_echoing_p)
498    {
499#if !defined (__GO32__)
500      switch (_rl_bell_preference)
501        {
502	case NO_BELL:
503	default:
504	  break;
505	case VISIBLE_BELL:
506	  if (visible_bell)
507	    {
508	      tputs (visible_bell, 1, _rl_output_character_function);
509	      break;
510	    }
511	  /* FALLTHROUGH */
512	case AUDIBLE_BELL:
513	  fprintf (stderr, "\007");
514	  fflush (stderr);
515	  break;
516        }
517#else /* __GO32__ */
518      fprintf (stderr, "\007");
519      fflush (stderr);
520#endif /* __GO32__ */
521      return (0);
522    }
523  return (-1);
524}
525
526/* **************************************************************** */
527/*								    */
528/*	 	Controlling the Meta Key and Keypad		    */
529/*								    */
530/* **************************************************************** */
531
532static int
533outchar (c)
534     int c;
535{
536  return putc (c, rl_outstream);
537}
538
539int
540_rl_enable_meta_key ()
541{
542  if (term_has_meta && term_mm)
543    tputs (term_mm, 1, outchar);
544}
545
546void
547_rl_control_keypad (on)
548     int on;
549{
550  if (on && term_ks)
551    tputs (term_ks, 1, outchar);
552  else if (!on && term_ke)
553    tputs (term_ke, 1, outchar);
554}
555