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