Imported from ../bash-2.03.tar.gz.
[platform/upstream/bash.git] / lib / readline / terminal.c
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 */
68 extern FILE *_rl_in_stream, *_rl_out_stream;
69 extern int readline_echoing_p;
70 extern int _rl_bell_preference;
71 extern Keymap _rl_keymap;
72
73 /* Functions imported from bind.c */
74 extern void _rl_bind_if_unbound ();
75
76 /* Functions imported from shell.c */
77 extern void set_lines_and_columns ();
78 extern char *get_env_value ();
79
80 /* **************************************************************** */
81 /*                                                                  */
82 /*                      Terminal and Termcap                        */
83 /*                                                                  */
84 /* **************************************************************** */
85
86 static char *term_buffer = (char *)NULL;
87 static char *term_string_buffer = (char *)NULL;
88
89 static int tcap_initialized;
90
91 /* Non-zero means this terminal can't really do anything. */
92 static int dumb_term;
93
94 #if !defined (__linux__)
95 #  if defined (__EMX__) || defined (NEED_EXTERN_PC)
96 extern 
97 #  endif /* __EMX__ || NEED_EXTERN_PC */
98 char PC, *BC, *UP;
99 #endif /* __linux__ */
100
101 /* Some strings to control terminal actions.  These are output by tputs (). */
102 char *term_goto, *term_clreol, *term_cr, *term_clrpag, *term_backspace;
103 char *term_pc;
104
105 /* Non-zero if we determine that the terminal can do character insertion. */
106 int terminal_can_insert = 0;
107
108 /* How to insert characters. */
109 char *term_im, *term_ei, *term_ic, *term_ip, *term_IC;
110
111 /* How to delete characters. */
112 char *term_dc, *term_DC;
113
114 #if defined (HACK_TERMCAP_MOTION)
115 char *term_forward_char;
116 #endif  /* HACK_TERMCAP_MOTION */
117
118 /* How to go up a line. */
119 char *term_up;
120
121 /* A visible bell, if the terminal can be made to flash the screen. */
122 static char *visible_bell;
123
124 /* Non-zero means the terminal can auto-wrap lines. */
125 int _rl_term_autowrap;
126
127 /* Non-zero means that this terminal has a meta key. */
128 static int term_has_meta;
129
130 /* The sequences to write to turn on and off the meta key, if this
131    terminal    has one. */
132 static char *term_mm, *term_mo;
133
134 /* The key sequences output by the arrow keys, if this terminal has any. */
135 static char *term_ku, *term_kd, *term_kr, *term_kl;
136
137 /* How to initialize and reset the arrow keys, if this terminal has any. */
138 static char *term_ks, *term_ke;
139
140 /* The key sequences sent by the Home and End keys, if any. */
141 static char *term_kh, *term_kH;
142
143 /* Variables that hold the screen dimensions, used by the display code. */
144 int screenwidth, screenheight, screenchars;
145
146 /* Non-zero means the user wants to enable the keypad. */
147 int _rl_enable_keypad;
148
149 /* Non-zero means the user wants to enable a meta key. */
150 int _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. */
156 void
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
222 void
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
235 void
236 rl_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
245 struct _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. */
252 static 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. */
286 static void
287 get_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
297 int
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
420 char *
421 rl_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. */
438 int
439 rl_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
448 void
449 _rl_output_character_function (c)
450      int c;
451 {
452   putc (c, _rl_out_stream);
453 }
454 #else /* !_MINIX */
455 int
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. */
463 void
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. */
472 int
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. */
490 int
491 crlf ()
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. */
502 int
503 ding ()
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
540 void
541 _rl_enable_meta_key ()
542 {
543   if (term_has_meta && term_mm)
544     tputs (term_mm, 1, _rl_output_character_function);
545 }
546
547 void
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 }