source: trunk/third/readline/terminal.c @ 17010

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