terminal.c revision 1.5
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 2, 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   59 Temple Place, Suite 330, Boston, MA 02111 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 <stdio.h>
50
51/* System-specific feature definitions and include files. */
52#include "rldefs.h"
53
54#  include <sys/ioctl.h>
55
56#include "rltty.h"
57#include "tcap.h"
58
59/* Some standard library routines. */
60#include "readline.h"
61#include "history.h"
62
63#include "rlprivate.h"
64#include "rlshell.h"
65#include "xmalloc.h"
66
67#define CUSTOM_REDISPLAY_FUNC() (rl_redisplay_function != rl_redisplay)
68#define CUSTOM_INPUT_FUNC() (rl_getc_function != rl_getc)
69
70/* **************************************************************** */
71/*								    */
72/*			Terminal and Termcap			    */
73/*								    */
74/* **************************************************************** */
75
76static char *term_buffer = (char *)NULL;
77static char *term_string_buffer = (char *)NULL;
78
79static int tcap_initialized;
80
81#if !defined (__linux__)
82#  if defined (__EMX__) || defined (NEED_EXTERN_PC)
83extern
84#  endif /* __EMX__ || NEED_EXTERN_PC */
85char PC, *BC, *UP;
86#endif /* __linux__ */
87
88/* Some strings to control terminal actions.  These are output by tputs (). */
89char *_rl_term_clreol;
90char *_rl_term_clrpag;
91char *_rl_term_cr;
92char *_rl_term_backspace;
93char *_rl_term_goto;
94char *_rl_term_pc;
95
96/* Non-zero if we determine that the terminal can do character insertion. */
97int _rl_terminal_can_insert = 0;
98
99/* How to insert characters. */
100char *_rl_term_im;
101char *_rl_term_ei;
102char *_rl_term_ic;
103char *_rl_term_ip;
104char *_rl_term_IC;
105
106/* How to delete characters. */
107char *_rl_term_dc;
108char *_rl_term_DC;
109
110#if defined (HACK_TERMCAP_MOTION)
111char *_rl_term_forward_char;
112#endif  /* HACK_TERMCAP_MOTION */
113
114/* How to go up a line. */
115char *_rl_term_up;
116
117/* A visible bell; char if the terminal can be made to flash the screen. */
118static char *_rl_visible_bell;
119
120/* Non-zero means the terminal can auto-wrap lines. */
121int _rl_term_autowrap;
122
123/* Non-zero means that this terminal has a meta key. */
124static int term_has_meta;
125
126/* The sequences to write to turn on and off the meta key, if this
127   terminal has one. */
128static char *_rl_term_mm;
129static char *_rl_term_mo;
130
131/* The key sequences output by the arrow keys, if this terminal has any. */
132static char *_rl_term_ku;
133static char *_rl_term_kd;
134static char *_rl_term_kr;
135static char *_rl_term_kl;
136
137/* How to initialize and reset the arrow keys, if this terminal has any. */
138static char *_rl_term_ks;
139static char *_rl_term_ke;
140
141/* The key sequences sent by the Home and End keys, if any. */
142static char *_rl_term_kh;
143static char *_rl_term_kH;
144static char *_rl_term_at7;	/* @7 */
145
146/* Insert key */
147static char *_rl_term_kI;
148
149/* Cursor control */
150static char *_rl_term_vs;	/* very visible */
151static char *_rl_term_ve;	/* normal */
152
153static void bind_termcap_arrow_keys PARAMS((Keymap));
154
155/* Variables that hold the screen dimensions, used by the display code. */
156int _rl_screenwidth, _rl_screenheight, _rl_screenchars;
157
158/* Non-zero means the user wants to enable the keypad. */
159int _rl_enable_keypad;
160
161/* Non-zero means the user wants to enable a meta key. */
162int _rl_enable_meta = 1;
163
164#if defined (__EMX__)
165static void
166_emx_get_screensize (swp, shp)
167     int *swp, *shp;
168{
169  int sz[2];
170
171  _scrsize (sz);
172
173  if (swp)
174    *swp = sz[0];
175  if (shp)
176    *shp = sz[1];
177}
178#endif
179
180/* Get readline's idea of the screen size.  TTY is a file descriptor open
181   to the terminal.  If IGNORE_ENV is true, we do not pay attention to the
182   values of $LINES and $COLUMNS.  The tests for TERM_STRING_BUFFER being
183   non-null serve to check whether or not we have initialized termcap. */
184void
185_rl_get_screen_size (tty, ignore_env)
186     int tty, ignore_env;
187{
188  char *ss;
189#if defined (TIOCGWINSZ)
190  struct winsize window_size;
191#endif /* TIOCGWINSZ */
192
193#if defined (TIOCGWINSZ)
194  if (ioctl (tty, TIOCGWINSZ, &window_size) == 0)
195    {
196      _rl_screenwidth = (int) window_size.ws_col;
197      _rl_screenheight = (int) window_size.ws_row;
198    }
199#endif /* TIOCGWINSZ */
200
201#if defined (__EMX__)
202  _emx_get_screensize (&_rl_screenwidth, &_rl_screenheight);
203#endif
204
205  /* Environment variable COLUMNS overrides setting of "co" if IGNORE_ENV
206     is unset. */
207  if (_rl_screenwidth <= 0)
208    {
209      if (ignore_env == 0 && (ss = sh_get_env_value ("COLUMNS")) && *ss != '\0')
210	_rl_screenwidth = atoi (ss);
211
212#if !defined (__DJGPP__)
213      if (_rl_screenwidth <= 0 && term_string_buffer)
214	_rl_screenwidth = tgetnum ("co");
215#endif
216    }
217
218  /* Environment variable LINES overrides setting of "li" if IGNORE_ENV
219     is unset. */
220  if (_rl_screenheight <= 0)
221    {
222      if (ignore_env == 0 && (ss = sh_get_env_value ("LINES")) && *ss != '\0')
223	_rl_screenheight = atoi (ss);
224
225#if !defined (__DJGPP__)
226      if (_rl_screenheight <= 0 && term_string_buffer)
227	_rl_screenheight = tgetnum ("li");
228#endif
229    }
230
231  /* If all else fails, default to 80x24 terminal. */
232  if (_rl_screenwidth <= 1)
233    _rl_screenwidth = 80;
234
235  if (_rl_screenheight <= 0)
236    _rl_screenheight = 24;
237
238  /* If we're being compiled as part of bash, set the environment
239     variables $LINES and $COLUMNS to new values.  Otherwise, just
240     do a pair of putenv () or setenv () calls. */
241  sh_set_lines_and_columns (_rl_screenheight, _rl_screenwidth);
242
243  if (_rl_term_autowrap == 0)
244    _rl_screenwidth--;
245
246  _rl_screenchars = _rl_screenwidth * _rl_screenheight;
247}
248
249void
250_rl_set_screen_size (rows, cols)
251     int rows, cols;
252{
253  if (rows == 0 || cols == 0)
254    return;
255
256  _rl_screenheight = rows;
257  _rl_screenwidth = cols;
258
259  if (_rl_term_autowrap == 0)
260    _rl_screenwidth--;
261
262  _rl_screenchars = _rl_screenwidth * _rl_screenheight;
263}
264
265void
266rl_set_screen_size (rows, cols)
267     int rows, cols;
268{
269  _rl_set_screen_size (rows, cols);
270}
271
272void
273rl_get_screen_size (rows, cols)
274     int *rows, *cols;
275{
276  if (rows)
277    *rows = _rl_screenheight;
278  if (cols)
279    *cols = _rl_screenwidth;
280}
281
282void
283rl_resize_terminal ()
284{
285  if (readline_echoing_p)
286    {
287      _rl_get_screen_size (fileno (rl_instream), 1);
288      if (CUSTOM_REDISPLAY_FUNC ())
289	rl_forced_update_display ();
290      else
291	_rl_redisplay_after_sigwinch ();
292    }
293}
294
295struct _tc_string {
296     const char *tc_var;
297     char **tc_value;
298};
299
300/* This should be kept sorted, just in case we decide to change the
301   search algorithm to something smarter. */
302static struct _tc_string tc_strings[] =
303{
304  { "@7", &_rl_term_at7 },
305  { "DC", &_rl_term_DC },
306  { "IC", &_rl_term_IC },
307  { "ce", &_rl_term_clreol },
308  { "cl", &_rl_term_clrpag },
309  { "cr", &_rl_term_cr },
310  { "dc", &_rl_term_dc },
311  { "ei", &_rl_term_ei },
312  { "ic", &_rl_term_ic },
313  { "im", &_rl_term_im },
314  { "kH", &_rl_term_kH },	/* home down ?? */
315  { "kI", &_rl_term_kI },	/* insert */
316  { "kd", &_rl_term_kd },
317  { "ke", &_rl_term_ke },	/* end keypad mode */
318  { "kh", &_rl_term_kh },	/* home */
319  { "kl", &_rl_term_kl },
320  { "kr", &_rl_term_kr },
321  { "ks", &_rl_term_ks },	/* start keypad mode */
322  { "ku", &_rl_term_ku },
323  { "le", &_rl_term_backspace },
324  { "mm", &_rl_term_mm },
325  { "mo", &_rl_term_mo },
326#if defined (HACK_TERMCAP_MOTION)
327  { "nd", &_rl_term_forward_char },
328#endif
329  { "pc", &_rl_term_pc },
330  { "up", &_rl_term_up },
331  { "vb", &_rl_visible_bell },
332  { "vs", &_rl_term_vs },
333  { "ve", &_rl_term_ve },
334};
335
336#define NUM_TC_STRINGS (sizeof (tc_strings) / sizeof (struct _tc_string))
337
338/* Read the desired terminal capability strings into BP.  The capabilities
339   are described in the TC_STRINGS table. */
340static void
341get_term_capabilities (bp)
342     char **bp;
343{
344#if !defined (__DJGPP__)	/* XXX - doesn't DJGPP have a termcap library? */
345  register int i;
346
347  for (i = 0; i < NUM_TC_STRINGS; i++)
348#  ifdef __LCC__
349    *(tc_strings[i].tc_value) = tgetstr ((char *)tc_strings[i].tc_var, bp);
350#  else
351    *(tc_strings[i].tc_value) = tgetstr (tc_strings[i].tc_var, bp);
352#  endif
353#endif
354  tcap_initialized = 1;
355}
356
357int
358_rl_init_terminal_io (terminal_name)
359     const char *terminal_name;
360{
361  const char *term;
362  char *buffer;
363  int tty, tgetent_ret;
364
365  term = terminal_name ? terminal_name : sh_get_env_value ("TERM");
366  _rl_term_clrpag = _rl_term_cr = _rl_term_clreol = (char *)NULL;
367  tty = rl_instream ? fileno (rl_instream) : 0;
368  _rl_screenwidth = _rl_screenheight = 0;
369
370  if (term == 0 || *term == '\0')
371    term = "dumb";
372
373  /* I've separated this out for later work on not calling tgetent at all
374     if the calling application has supplied a custom redisplay function,
375     (and possibly if the application has supplied a custom input function). */
376  if (CUSTOM_REDISPLAY_FUNC())
377    {
378      tgetent_ret = -1;
379    }
380  else
381    {
382      if (term_string_buffer == 0)
383	term_string_buffer = (char *)xmalloc(2032);
384
385      if (term_buffer == 0)
386	term_buffer = (char *)xmalloc(4080);
387
388      buffer = term_string_buffer;
389
390      tgetent_ret = tgetent (term_buffer, term);
391    }
392
393  if (tgetent_ret <= 0)
394    {
395      FREE (term_string_buffer);
396      FREE (term_buffer);
397      buffer = term_buffer = term_string_buffer = (char *)NULL;
398
399      _rl_term_autowrap = 0;	/* used by _rl_get_screen_size */
400
401#if defined (__EMX__)
402      _emx_get_screensize (&_rl_screenwidth, &_rl_screenheight);
403      _rl_screenwidth--;
404#else /* !__EMX__ */
405      _rl_get_screen_size (tty, 0);
406#endif /* !__EMX__ */
407
408      /* Defaults. */
409      if (_rl_screenwidth <= 0 || _rl_screenheight <= 0)
410        {
411	  _rl_screenwidth = 79;
412	  _rl_screenheight = 24;
413        }
414
415      /* Everything below here is used by the redisplay code (tputs). */
416      _rl_screenchars = _rl_screenwidth * _rl_screenheight;
417      _rl_term_cr = "\r";
418      _rl_term_im = _rl_term_ei = _rl_term_ic = _rl_term_IC = (char *)NULL;
419      _rl_term_up = _rl_term_dc = _rl_term_DC = _rl_visible_bell = (char *)NULL;
420      _rl_term_ku = _rl_term_kd = _rl_term_kl = _rl_term_kr = (char *)NULL;
421      _rl_term_kh = _rl_term_kH = _rl_term_kI = (char *)NULL;
422      _rl_term_ks = _rl_term_ke = _rl_term_at7 = (char *)NULL;
423      _rl_term_mm = _rl_term_mo = (char *)NULL;
424      _rl_term_ve = _rl_term_vs = (char *)NULL;
425#if defined (HACK_TERMCAP_MOTION)
426      term_forward_char = (char *)NULL;
427#endif
428      _rl_terminal_can_insert = term_has_meta = 0;
429
430      /* Reasonable defaults for tgoto().  Readline currently only uses
431         tgoto if _rl_term_IC or _rl_term_DC is defined, but just in case we
432         change that later... */
433      PC = '\0';
434      BC = _rl_term_backspace = "\b";
435      UP = _rl_term_up;
436
437      return 0;
438    }
439
440  get_term_capabilities (&buffer);
441
442  /* Set up the variables that the termcap library expects the application
443     to provide. */
444  PC = _rl_term_pc ? *_rl_term_pc : 0;
445  BC = _rl_term_backspace;
446  UP = _rl_term_up;
447
448  if (!_rl_term_cr)
449    _rl_term_cr = "\r";
450
451  _rl_term_autowrap = tgetflag ("am") && tgetflag ("xn");
452
453  _rl_get_screen_size (tty, 0);
454
455  /* "An application program can assume that the terminal can do
456      character insertion if *any one of* the capabilities `IC',
457      `im', `ic' or `ip' is provided."  But we can't do anything if
458      only `ip' is provided, so... */
459  _rl_terminal_can_insert = (_rl_term_IC || _rl_term_im || _rl_term_ic);
460
461  /* Check to see if this terminal has a meta key and clear the capability
462     variables if there is none. */
463  term_has_meta = (tgetflag ("km") || tgetflag ("MT"));
464  if (!term_has_meta)
465    _rl_term_mm = _rl_term_mo = (char *)NULL;
466
467  /* Attempt to find and bind the arrow keys.  Do not override already
468     bound keys in an overzealous attempt, however. */
469
470  bind_termcap_arrow_keys (emacs_standard_keymap);
471
472#if defined (VI_MODE)
473  bind_termcap_arrow_keys (vi_movement_keymap);
474  bind_termcap_arrow_keys (vi_insertion_keymap);
475#endif /* VI_MODE */
476
477  return 0;
478}
479
480/* Bind the arrow key sequences from the termcap description in MAP. */
481static void
482bind_termcap_arrow_keys (map)
483     Keymap map;
484{
485  Keymap xkeymap;
486
487  xkeymap = _rl_keymap;
488  _rl_keymap = map;
489
490  _rl_bind_if_unbound (_rl_term_ku, rl_get_previous_history);
491  _rl_bind_if_unbound (_rl_term_kd, rl_get_next_history);
492  _rl_bind_if_unbound (_rl_term_kr, rl_forward);
493  _rl_bind_if_unbound (_rl_term_kl, rl_backward);
494
495  _rl_bind_if_unbound (_rl_term_kh, rl_beg_of_line);	/* Home */
496  _rl_bind_if_unbound (_rl_term_at7, rl_end_of_line);	/* End */
497
498  _rl_keymap = xkeymap;
499}
500
501char *
502rl_get_termcap (cap)
503     const char *cap;
504{
505  register int i;
506
507  if (tcap_initialized == 0)
508    return ((char *)NULL);
509  for (i = 0; i < NUM_TC_STRINGS; i++)
510    {
511      if (tc_strings[i].tc_var[0] == cap[0] && strcmp (tc_strings[i].tc_var, cap) == 0)
512        return *(tc_strings[i].tc_value);
513    }
514  return ((char *)NULL);
515}
516
517/* Re-initialize the terminal considering that the TERM/TERMCAP variable
518   has changed. */
519int
520rl_reset_terminal (terminal_name)
521     const char *terminal_name;
522{
523  _rl_init_terminal_io (terminal_name);
524  return 0;
525}
526
527/* A function for the use of tputs () */
528#ifdef _MINIX
529void
530_rl_output_character_function (c)
531     int c;
532{
533  putc (c, _rl_out_stream);
534}
535#else /* !_MINIX */
536int
537_rl_output_character_function (c)
538     int c;
539{
540  return putc (c, _rl_out_stream);
541}
542#endif /* !_MINIX */
543
544/* Write COUNT characters from STRING to the output stream. */
545void
546_rl_output_some_chars (string, count)
547     const char *string;
548     int count;
549{
550  fwrite (string, 1, count, _rl_out_stream);
551}
552
553/* Move the cursor back. */
554int
555_rl_backspace (count)
556     int count;
557{
558  register int i;
559
560  if (_rl_term_backspace)
561    for (i = 0; i < count; i++)
562      tputs (_rl_term_backspace, 1, _rl_output_character_function);
563  else
564    for (i = 0; i < count; i++)
565      putc ('\b', _rl_out_stream);
566  return 0;
567}
568
569/* Move to the start of the next line. */
570int
571rl_crlf ()
572{
573#if defined (NEW_TTY_DRIVER)
574  if (_rl_term_cr)
575    tputs (_rl_term_cr, 1, _rl_output_character_function);
576#endif /* NEW_TTY_DRIVER */
577  putc ('\n', _rl_out_stream);
578  return 0;
579}
580
581/* Ring the terminal bell. */
582int
583rl_ding ()
584{
585  if (readline_echoing_p)
586    {
587      switch (_rl_bell_preference)
588        {
589	case NO_BELL:
590	default:
591	  break;
592	case VISIBLE_BELL:
593	  if (_rl_visible_bell)
594	    {
595	      tputs (_rl_visible_bell, 1, _rl_output_character_function);
596	      break;
597	    }
598	  /* FALLTHROUGH */
599	case AUDIBLE_BELL:
600	  fprintf (stderr, "\007");
601	  fflush (stderr);
602	  break;
603        }
604      return (0);
605    }
606  return (-1);
607}
608
609/* **************************************************************** */
610/*								    */
611/*		Controlling the Meta Key and Keypad		    */
612/*								    */
613/* **************************************************************** */
614
615void
616_rl_enable_meta_key ()
617{
618#if !defined (__DJGPP__)
619  if (term_has_meta && _rl_term_mm)
620    tputs (_rl_term_mm, 1, _rl_output_character_function);
621#endif
622}
623
624void
625_rl_control_keypad (on)
626     int on;
627{
628#if !defined (__DJGPP__)
629  if (on && _rl_term_ks)
630    tputs (_rl_term_ks, 1, _rl_output_character_function);
631  else if (!on && _rl_term_ke)
632    tputs (_rl_term_ke, 1, _rl_output_character_function);
633#endif
634}
635
636/* **************************************************************** */
637/*								    */
638/*			Controlling the Cursor			    */
639/*								    */
640/* **************************************************************** */
641
642/* Set the cursor appropriately depending on IM, which is one of the
643   insert modes (insert or overwrite).  Insert mode gets the normal
644   cursor.  Overwrite mode gets a very visible cursor.  Only does
645   anything if we have both capabilities. */
646void
647_rl_set_cursor (im, force)
648     int im, force;
649{
650  if (_rl_term_ve && _rl_term_vs)
651    {
652      if (force || im != rl_insert_mode)
653	{
654	  if (im == RL_IM_OVERWRITE)
655	    tputs (_rl_term_vs, 1, _rl_output_character_function);
656	  else
657	    tputs (_rl_term_ve, 1, _rl_output_character_function);
658	}
659    }
660}
661