terminal.c revision 35486
1/* terminal.c -- controlling the terminal with termcap. */
2
3/* Copyright (C) 1996 Free Software Foundation, Inc.
4
5   This file is part of the GNU Readline Library, a library for
6   reading lines of text with interactive input and history editing.
7
8   The GNU Readline Library is free software; you can redistribute it
9   and/or modify it under the terms of the GNU General Public License
10   as published by the Free Software Foundation; either version 1, or
11   (at your option) any later version.
12
13   The GNU Readline Library is distributed in the hope that it will be
14   useful, but WITHOUT ANY WARRANTY; without even the implied warranty
15   of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16   GNU General Public License for more details.
17
18   The GNU General Public License is often shipped with GNU software, and
19   is generally kept in a file called COPYING or LICENSE.  If you do not
20   have a copy of the license, write to the Free Software Foundation,
21   675 Mass Ave, Cambridge, MA 02139, USA. */
22#define READLINE_LIBRARY
23
24#if defined (HAVE_CONFIG_H)
25#  include <config.h>
26#endif
27
28#include <sys/types.h>
29#include "posixstat.h"
30#include <fcntl.h>
31#if defined (HAVE_SYS_FILE_H)
32#  include <sys/file.h>
33#endif /* HAVE_SYS_FILE_H */
34
35#if defined (HAVE_UNISTD_H)
36#  include <unistd.h>
37#endif /* HAVE_UNISTD_H */
38
39#if defined (HAVE_STDLIB_H)
40#  include <stdlib.h>
41#else
42#  include "ansi_stdlib.h"
43#endif /* HAVE_STDLIB_H */
44
45#if defined (HAVE_LOCALE_H)
46#  include <locale.h>
47#endif
48
49#include <signal.h>
50#include <stdio.h>
51#include <setjmp.h>
52
53/* System-specific feature definitions and include files. */
54#include "rldefs.h"
55
56#if defined (GWINSZ_IN_SYS_IOCTL) && !defined (TIOCGWINSZ)
57#  include <sys/ioctl.h>
58#endif /* GWINSZ_IN_SYS_IOCTL && !TIOCGWINSZ */
59
60#include "rltty.h"
61#include "tcap.h"
62
63/* Some standard library routines. */
64#include "readline.h"
65#include "history.h"
66
67/* Variables and functions imported from readline.c */
68extern FILE *_rl_in_stream, *_rl_out_stream;
69extern int readline_echoing_p;
70extern int _rl_bell_preference;
71extern Keymap _rl_keymap;
72
73/* Functions imported from bind.c */
74extern void _rl_bind_if_unbound ();
75
76/* Functions imported from shell.c */
77extern void set_lines_and_columns ();
78extern char *get_env_value ();
79
80/* **************************************************************** */
81/*								    */
82/*			Terminal and Termcap			    */
83/*								    */
84/* **************************************************************** */
85
86static char *term_buffer = (char *)NULL;
87static char *term_string_buffer = (char *)NULL;
88
89static int tcap_initialized;
90
91/* Non-zero means this terminal can't really do anything. */
92static int dumb_term;
93
94#if !defined (__linux__)
95#  if defined (__EMX__) || defined (NEED_EXTERN_PC)
96extern
97#  endif /* __EMX__ || NEED_EXTERN_PC */
98char PC, *BC, *UP;
99#endif /* __linux__ */
100
101/* Some strings to control terminal actions.  These are output by tputs (). */
102char *term_goto, *term_clreol, *term_cr, *term_clrpag, *term_backspace;
103char *term_pc;
104
105/* Non-zero if we determine that the terminal can do character insertion. */
106int terminal_can_insert = 0;
107
108/* How to insert characters. */
109char *term_im, *term_ei, *term_ic, *term_ip, *term_IC;
110
111/* How to delete characters. */
112char *term_dc, *term_DC;
113
114#if defined (HACK_TERMCAP_MOTION)
115char *term_forward_char;
116#endif  /* HACK_TERMCAP_MOTION */
117
118/* How to go up a line. */
119char *term_up;
120
121/* A visible bell, if the terminal can be made to flash the screen. */
122static char *visible_bell;
123
124/* Non-zero means the terminal can auto-wrap lines. */
125int _rl_term_autowrap;
126
127/* Non-zero means that this terminal has a meta key. */
128static int term_has_meta;
129
130/* The sequences to write to turn on and off the meta key, if this
131   terminal    has one. */
132static char *term_mm, *term_mo;
133
134/* The key sequences output by the arrow keys, if this terminal has any. */
135static char *term_ku, *term_kd, *term_kr, *term_kl;
136
137/* How to initialize and reset the arrow keys, if this terminal has any. */
138static char *term_ks, *term_ke;
139
140/* The key sequences sent by the Home and End keys, if any. */
141static char *term_kh, *term_kH;
142
143/* Variables that hold the screen dimensions, used by the display code. */
144int screenwidth, screenheight, screenchars;
145
146/* Non-zero means the user wants to enable the keypad. */
147int _rl_enable_keypad;
148
149/* Non-zero means the user wants to enable a meta key. */
150int _rl_enable_meta = 1;
151
152/* Get readline's idea of the screen size.  TTY is a file descriptor open
153   to the terminal.  If IGNORE_ENV is true, we do not pay attention to the
154   values of $LINES and $COLUMNS.  The tests for TERM_STRING_BUFFER being
155   non-null serve to check whether or not we have initialized termcap. */
156void
157_rl_get_screen_size (tty, ignore_env)
158     int tty, ignore_env;
159{
160  char *ss;
161#if defined (TIOCGWINSZ)
162  struct winsize window_size;
163#endif /* TIOCGWINSZ */
164#if defined (__EMX__)
165  int sz[2];
166#endif
167
168#if defined (TIOCGWINSZ)
169  if (ioctl (tty, TIOCGWINSZ, &window_size) == 0)
170    {
171      screenwidth = (int) window_size.ws_col;
172      screenheight = (int) window_size.ws_row;
173    }
174#endif /* TIOCGWINSZ */
175
176#if defined (__EMX__)
177  _scrsize (sz);
178  screenwidth = sz[0];
179  screenheight = sz[1];
180#endif
181
182  /* Environment variable COLUMNS overrides setting of "co" if IGNORE_ENV
183     is unset. */
184  if (screenwidth <= 0)
185    {
186      if (ignore_env == 0 && (ss = get_env_value ("COLUMNS")))
187	screenwidth = atoi (ss);
188
189      if (screenwidth <= 0 && term_string_buffer)
190	screenwidth = tgetnum ("co");
191    }
192
193  /* Environment variable LINES overrides setting of "li" if IGNORE_ENV
194     is unset. */
195  if (screenheight <= 0)
196    {
197      if (ignore_env == 0 && (ss = get_env_value ("LINES")))
198	screenheight = atoi (ss);
199
200      if (screenheight <= 0 && term_string_buffer)
201	screenheight = tgetnum ("li");
202    }
203
204  /* If all else fails, default to 80x24 terminal. */
205  if (screenwidth <= 1)
206    screenwidth = 80;
207
208  if (screenheight <= 0)
209    screenheight = 24;
210
211  /* If we're being compiled as part of bash, set the environment
212     variables $LINES and $COLUMNS to new values.  Otherwise, just
213     do a pair of putenv () or setenv () calls. */
214  set_lines_and_columns (screenheight, screenwidth);
215
216  if (!_rl_term_autowrap)
217    screenwidth--;
218
219  screenchars = screenwidth * screenheight;
220}
221
222void
223_rl_set_screen_size (rows, cols)
224     int rows, cols;
225{
226  screenheight = rows;
227  screenwidth = cols;
228
229  if (_rl_term_autowrap == 0)
230    screenwidth--;
231
232  screenchars = screenwidth * screenheight;
233}
234
235struct _tc_string {
236     char *tc_var;
237     char **tc_value;
238};
239
240/* This should be kept sorted, just in case we decide to change the
241   search algorithm to something smarter. */
242static struct _tc_string tc_strings[] =
243{
244  "DC", &term_DC,
245  "IC", &term_IC,
246  "ce", &term_clreol,
247  "cl", &term_clrpag,
248  "cr", &term_cr,
249  "dc", &term_dc,
250  "ei", &term_ei,
251  "ic", &term_ic,
252  "im", &term_im,
253  "kd", &term_kd,
254  "kh", &term_kh,	/* home */
255  "kH", &term_kH,	/* end */
256  "kl", &term_kl,
257  "kr", &term_kr,
258  "ku", &term_ku,
259  "ks", &term_ks,
260  "ke", &term_ke,
261  "le", &term_backspace,
262  "mm", &term_mm,
263  "mo", &term_mo,
264#if defined (HACK_TERMCAP_MOTION)
265  "nd", &term_forward_char,
266#endif
267  "pc", &term_pc,
268  "up", &term_up,
269  "vb", &visible_bell,
270};
271
272#define NUM_TC_STRINGS (sizeof (tc_strings) / sizeof (struct _tc_string))
273
274/* Read the desired terminal capability strings into BP.  The capabilities
275   are described in the TC_STRINGS table. */
276static void
277get_term_capabilities (bp)
278     char **bp;
279{
280  register int i;
281
282  for (i = 0; i < NUM_TC_STRINGS; i++)
283    *(tc_strings[i].tc_value) = tgetstr (tc_strings[i].tc_var, bp);
284  tcap_initialized = 1;
285}
286
287int
288_rl_init_terminal_io (terminal_name)
289     char *terminal_name;
290{
291#if defined (__GO32__)
292  screenwidth = ScreenCols ();
293  screenheight = ScreenRows ();
294  screenchars = screenwidth * screenheight;
295  term_cr = "\r";
296  term_im = term_ei = term_ic = term_IC = (char *)NULL;
297  term_up = term_dc = term_DC = visible_bell = (char *)NULL;
298
299  /* Does the __GO32__ have a meta key?  I don't know. */
300  term_has_meta = 0;
301  term_mm = term_mo = (char *)NULL;
302
303  /* It probably has arrow keys, but I don't know what they are. */
304  term_ku = term_kd = term_kr = term_kl = (char *)NULL;
305
306#if defined (HACK_TERMCAP_MOTION)
307  term_forward_char = (char *)NULL;
308#endif /* HACK_TERMCAP_MOTION */
309  terminal_can_insert = _rl_term_autowrap = 0;
310  return;
311#else /* !__GO32__ */
312
313  char *term, *buffer;
314  int tty;
315  Keymap xkeymap;
316
317  term = terminal_name ? terminal_name : get_env_value ("TERM");
318
319  if (term_string_buffer == 0)
320    term_string_buffer = xmalloc (2032);
321
322  if (term_buffer == 0)
323    term_buffer = xmalloc (4080);
324
325  buffer = term_string_buffer;
326
327  term_clrpag = term_cr = term_clreol = (char *)NULL;
328
329  if (term == 0)
330    term = "dumb";
331
332  if (tgetent (term_buffer, term) <= 0)
333    {
334      dumb_term = 1;
335      screenwidth = 79;
336      screenheight = 24;
337      screenchars = 79 * 24;
338      term_cr = "\r";
339      term_im = term_ei = term_ic = term_IC = (char *)NULL;
340      term_up = term_dc = term_DC = visible_bell = (char *)NULL;
341      term_ku = term_kd = term_kl = term_kr = (char *)NULL;
342#if defined (HACK_TERMCAP_MOTION)
343      term_forward_char = (char *)NULL;
344#endif
345      terminal_can_insert = 0;
346      return 0;
347    }
348
349  get_term_capabilities (&buffer);
350
351  /* Set up the variables that the termcap library expects the application
352     to provide. */
353  PC = term_pc ? *term_pc : 0;
354  BC = term_backspace;
355  UP = term_up;
356
357  if (!term_cr)
358    term_cr = "\r";
359
360  tty = rl_instream ? fileno (rl_instream) : 0;
361
362  screenwidth = screenheight = 0;
363
364  _rl_term_autowrap = tgetflag ("am") && tgetflag ("xn");
365
366  _rl_get_screen_size (tty, 0);
367
368  /* "An application program can assume that the terminal can do
369      character insertion if *any one of* the capabilities `IC',
370      `im', `ic' or `ip' is provided."  But we can't do anything if
371      only `ip' is provided, so... */
372  terminal_can_insert = (term_IC || term_im || term_ic);
373
374  /* Check to see if this terminal has a meta key and clear the capability
375     variables if there is none. */
376  term_has_meta = (tgetflag ("km") || tgetflag ("MT"));
377  if (!term_has_meta)
378    term_mm = term_mo = (char *)NULL;
379
380  /* Attempt to find and bind the arrow keys.  Do not override already
381     bound keys in an overzealous attempt, however. */
382  xkeymap = _rl_keymap;
383
384  _rl_keymap = emacs_standard_keymap;
385  _rl_bind_if_unbound (term_ku, rl_get_previous_history);
386  _rl_bind_if_unbound (term_kd, rl_get_next_history);
387  _rl_bind_if_unbound (term_kr, rl_forward);
388  _rl_bind_if_unbound (term_kl, rl_backward);
389
390  _rl_bind_if_unbound (term_kh, rl_beg_of_line);	/* Home */
391  _rl_bind_if_unbound (term_kH, rl_end_of_line);	/* End */
392
393#if defined (VI_MODE)
394  _rl_keymap = vi_movement_keymap;
395  _rl_bind_if_unbound (term_ku, rl_get_previous_history);
396  _rl_bind_if_unbound (term_kd, rl_get_next_history);
397  _rl_bind_if_unbound (term_kr, rl_forward);
398  _rl_bind_if_unbound (term_kl, rl_backward);
399
400  _rl_bind_if_unbound (term_kh, rl_beg_of_line);	/* Home */
401  _rl_bind_if_unbound (term_kH, rl_end_of_line);	/* End */
402#endif /* VI_MODE */
403
404  _rl_keymap = xkeymap;
405
406#endif /* !__GO32__ */
407  return 0;
408}
409
410char *
411rl_get_termcap (cap)
412     char *cap;
413{
414  register int i;
415
416  if (tcap_initialized == 0)
417    return ((char *)NULL);
418  for (i = 0; i < NUM_TC_STRINGS; i++)
419    {
420      if (tc_strings[i].tc_var[0] == cap[0] && strcmp (tc_strings[i].tc_var, cap) == 0)
421        return *(tc_strings[i].tc_value);
422    }
423  return ((char *)NULL);
424}
425
426/* Re-initialize the terminal considering that the TERM/TERMCAP variable
427   has changed. */
428int
429rl_reset_terminal (terminal_name)
430     char *terminal_name;
431{
432  _rl_init_terminal_io (terminal_name);
433  return 0;
434}
435
436/* A function for the use of tputs () */
437#ifdef _MINIX
438void
439_rl_output_character_function (c)
440     int c;
441{
442  putc (c, _rl_out_stream);
443}
444#else /* !_MINIX */
445int
446_rl_output_character_function (c)
447     int c;
448{
449  return putc (c, _rl_out_stream);
450}
451#endif /* !_MINIX */
452/* Write COUNT characters from STRING to the output stream. */
453void
454_rl_output_some_chars (string, count)
455     char *string;
456     int count;
457{
458  fwrite (string, 1, count, _rl_out_stream);
459}
460
461/* Move the cursor back. */
462int
463_rl_backspace (count)
464     int count;
465{
466  register int i;
467
468#if !defined (__GO32__)
469  if (term_backspace)
470    for (i = 0; i < count; i++)
471      tputs (term_backspace, 1, _rl_output_character_function);
472  else
473#endif /* !__GO32__ */
474    for (i = 0; i < count; i++)
475      putc ('\b', _rl_out_stream);
476  return 0;
477}
478
479/* Move to the start of the next line. */
480int
481crlf ()
482{
483#if defined (NEW_TTY_DRIVER)
484  if (term_cr)
485    tputs (term_cr, 1, _rl_output_character_function);
486#endif /* NEW_TTY_DRIVER */
487  putc ('\n', _rl_out_stream);
488  return 0;
489}
490
491/* Ring the terminal bell. */
492int
493ding ()
494{
495  if (readline_echoing_p)
496    {
497#if !defined (__GO32__)
498      switch (_rl_bell_preference)
499        {
500	case NO_BELL:
501	default:
502	  break;
503	case VISIBLE_BELL:
504	  if (visible_bell)
505	    {
506	      tputs (visible_bell, 1, _rl_output_character_function);
507	      break;
508	    }
509	  /* FALLTHROUGH */
510	case AUDIBLE_BELL:
511	  fprintf (stderr, "\007");
512	  fflush (stderr);
513	  break;
514        }
515#else /* __GO32__ */
516      fprintf (stderr, "\007");
517      fflush (stderr);
518#endif /* __GO32__ */
519      return (0);
520    }
521  return (-1);
522}
523
524/* **************************************************************** */
525/*								    */
526/*	 	Controlling the Meta Key and Keypad		    */
527/*								    */
528/* **************************************************************** */
529
530void
531_rl_enable_meta_key ()
532{
533  if (term_has_meta && term_mm)
534    tputs (term_mm, 1, _rl_output_character_function);
535}
536
537void
538_rl_control_keypad (on)
539     int on;
540{
541  if (on && term_ks)
542    tputs (term_ks, 1, _rl_output_character_function);
543  else if (!on && term_ke)
544    tputs (term_ke, 1, _rl_output_character_function);
545}
546