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