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