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

Revision 12992, 13.7 KB checked in by kcr, 26 years ago (diff)
This commit was generated by cvs2svn to compensate for changes in r12991, 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 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
235void
236rl_resize_terminal ()
237{
238  if (readline_echoing_p)
239    {
240      _rl_get_screen_size (fileno (rl_instream), 1);
241      _rl_redisplay_after_sigwinch ();
242    }
243}
244
245struct _tc_string {
246     char *tc_var;
247     char **tc_value;
248};
249
250/* This should be kept sorted, just in case we decide to change the
251   search algorithm to something smarter. */
252static struct _tc_string tc_strings[] =
253{
254  "DC", &term_DC,
255  "IC", &term_IC,
256  "ce", &term_clreol,
257  "cl", &term_clrpag,
258  "cr", &term_cr,
259  "dc", &term_dc,
260  "ei", &term_ei,
261  "ic", &term_ic,
262  "im", &term_im,
263  "kd", &term_kd,
264  "kh", &term_kh,       /* home */
265  "kH", &term_kH,       /* end */
266  "kl", &term_kl,
267  "kr", &term_kr,
268  "ku", &term_ku,
269  "ks", &term_ks,
270  "ke", &term_ke,
271  "le", &term_backspace,
272  "mm", &term_mm,
273  "mo", &term_mo,
274#if defined (HACK_TERMCAP_MOTION)
275  "nd", &term_forward_char,
276#endif
277  "pc", &term_pc,
278  "up", &term_up,
279  "vb", &visible_bell,
280};
281
282#define NUM_TC_STRINGS (sizeof (tc_strings) / sizeof (struct _tc_string))
283
284/* Read the desired terminal capability strings into BP.  The capabilities
285   are described in the TC_STRINGS table. */
286static void
287get_term_capabilities (bp)
288     char **bp;
289{
290  register int i;
291
292  for (i = 0; i < NUM_TC_STRINGS; i++)
293    *(tc_strings[i].tc_value) = tgetstr (tc_strings[i].tc_var, bp);
294  tcap_initialized = 1;
295}
296
297int
298_rl_init_terminal_io (terminal_name)
299     char *terminal_name;
300{
301#if defined (__GO32__)
302  screenwidth = ScreenCols ();
303  screenheight = ScreenRows ();
304  screenchars = screenwidth * screenheight;
305  term_cr = "\r";
306  term_im = term_ei = term_ic = term_IC = (char *)NULL;
307  term_up = term_dc = term_DC = visible_bell = (char *)NULL;
308
309  /* Does the __GO32__ have a meta key?  I don't know. */
310  term_has_meta = 0;
311  term_mm = term_mo = (char *)NULL;
312
313  /* It probably has arrow keys, but I don't know what they are. */
314  term_ku = term_kd = term_kr = term_kl = (char *)NULL;
315
316#if defined (HACK_TERMCAP_MOTION)
317  term_forward_char = (char *)NULL;
318#endif /* HACK_TERMCAP_MOTION */
319  terminal_can_insert = _rl_term_autowrap = 0;
320  return;
321#else /* !__GO32__ */
322
323  char *term, *buffer;
324  int tty;
325  Keymap xkeymap;
326
327  term = terminal_name ? terminal_name : get_env_value ("TERM");
328
329  if (term_string_buffer == 0)
330    term_string_buffer = xmalloc (2032);
331
332  if (term_buffer == 0)
333    term_buffer = xmalloc (4080);
334
335  buffer = term_string_buffer;
336
337  term_clrpag = term_cr = term_clreol = (char *)NULL;
338
339  if (term == 0)
340    term = "dumb";
341
342  if (tgetent (term_buffer, term) <= 0)
343    {
344      dumb_term = 1;
345      screenwidth = 79;
346      screenheight = 24;
347      screenchars = 79 * 24;
348      term_cr = "\r";
349      term_im = term_ei = term_ic = term_IC = (char *)NULL;
350      term_up = term_dc = term_DC = visible_bell = (char *)NULL;
351      term_ku = term_kd = term_kl = term_kr = (char *)NULL;
352#if defined (HACK_TERMCAP_MOTION)
353      term_forward_char = (char *)NULL;
354#endif
355      terminal_can_insert = 0;
356      return 0;
357    }
358
359  get_term_capabilities (&buffer);
360
361  /* Set up the variables that the termcap library expects the application
362     to provide. */
363  PC = term_pc ? *term_pc : 0;
364  BC = term_backspace;
365  UP = term_up;
366
367  if (!term_cr)
368    term_cr = "\r";
369
370  tty = rl_instream ? fileno (rl_instream) : 0;
371
372  screenwidth = screenheight = 0;
373
374  _rl_term_autowrap = tgetflag ("am") && tgetflag ("xn");
375
376  _rl_get_screen_size (tty, 0);
377
378  /* "An application program can assume that the terminal can do
379      character insertion if *any one of* the capabilities `IC',
380      `im', `ic' or `ip' is provided."  But we can't do anything if
381      only `ip' is provided, so... */
382  terminal_can_insert = (term_IC || term_im || term_ic);
383
384  /* Check to see if this terminal has a meta key and clear the capability
385     variables if there is none. */
386  term_has_meta = (tgetflag ("km") || tgetflag ("MT"));
387  if (!term_has_meta)
388    term_mm = term_mo = (char *)NULL;
389
390  /* Attempt to find and bind the arrow keys.  Do not override already
391     bound keys in an overzealous attempt, however. */
392  xkeymap = _rl_keymap;
393
394  _rl_keymap = emacs_standard_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
403#if defined (VI_MODE)
404  _rl_keymap = vi_movement_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#endif /* VI_MODE */
413
414  _rl_keymap = xkeymap;
415
416#endif /* !__GO32__ */
417  return 0;
418}
419
420char *
421rl_get_termcap (cap)
422     char *cap;
423{
424  register int i;
425
426  if (tcap_initialized == 0)
427    return ((char *)NULL);
428  for (i = 0; i < NUM_TC_STRINGS; i++)
429    {
430      if (tc_strings[i].tc_var[0] == cap[0] && strcmp (tc_strings[i].tc_var, cap) == 0)
431        return *(tc_strings[i].tc_value);
432    }
433  return ((char *)NULL);
434}
435
436/* Re-initialize the terminal considering that the TERM/TERMCAP variable
437   has changed. */
438int
439rl_reset_terminal (terminal_name)
440     char *terminal_name;
441{
442  _rl_init_terminal_io (terminal_name);
443  return 0;
444}
445
446/* A function for the use of tputs () */
447#ifdef _MINIX
448void
449_rl_output_character_function (c)
450     int c;
451{
452  putc (c, _rl_out_stream);
453}
454#else /* !_MINIX */
455int
456_rl_output_character_function (c)
457     int c;
458{
459  return putc (c, _rl_out_stream);
460}
461#endif /* !_MINIX */
462/* Write COUNT characters from STRING to the output stream. */
463void
464_rl_output_some_chars (string, count)
465     char *string;
466     int count;
467{
468  fwrite (string, 1, count, _rl_out_stream);
469}
470
471/* Move the cursor back. */
472int
473_rl_backspace (count)
474     int count;
475{
476  register int i;
477
478#if !defined (__GO32__)
479  if (term_backspace)
480    for (i = 0; i < count; i++)
481      tputs (term_backspace, 1, _rl_output_character_function);
482  else
483#endif /* !__GO32__ */
484    for (i = 0; i < count; i++)
485      putc ('\b', _rl_out_stream);
486  return 0;
487}
488
489/* Move to the start of the next line. */
490int
491crlf ()
492{
493#if defined (NEW_TTY_DRIVER)
494  if (term_cr)
495    tputs (term_cr, 1, _rl_output_character_function);
496#endif /* NEW_TTY_DRIVER */
497  putc ('\n', _rl_out_stream);
498  return 0;
499}
500
501/* Ring the terminal bell. */
502int
503ding ()
504{
505  if (readline_echoing_p)
506    {
507#if !defined (__GO32__)
508      switch (_rl_bell_preference)
509        {
510        case NO_BELL:
511        default:
512          break;
513        case VISIBLE_BELL:
514          if (visible_bell)
515            {
516              tputs (visible_bell, 1, _rl_output_character_function);
517              break;
518            }
519          /* FALLTHROUGH */
520        case AUDIBLE_BELL:
521          fprintf (stderr, "\007");
522          fflush (stderr);
523          break;
524        }
525#else /* __GO32__ */
526      fprintf (stderr, "\007");
527      fflush (stderr);
528#endif /* __GO32__ */
529      return (0);
530    }
531  return (-1);
532}
533
534/* **************************************************************** */
535/*                                                                  */
536/*              Controlling the Meta Key and Keypad                 */
537/*                                                                  */
538/* **************************************************************** */
539
540void
541_rl_enable_meta_key ()
542{
543  if (term_has_meta && term_mm)
544    tputs (term_mm, 1, _rl_output_character_function);
545}
546
547void
548_rl_control_keypad (on)
549     int on;
550{
551  if (on && term_ks)
552    tputs (term_ks, 1, _rl_output_character_function);
553  else if (!on && term_ke)
554    tputs (term_ke, 1, _rl_output_character_function);
555}
Note: See TracBrowser for help on using the repository browser.