* readline.c (rl_save_state, rl_restore_state): Support systems
[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 2, 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    59 Temple Place, Suite 330, Boston, MA 02111 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 <stdio.h>
50
51 /* System-specific feature definitions and include files. */
52 #include "rldefs.h"
53
54 #if defined (GWINSZ_IN_SYS_IOCTL) && !defined (TIOCGWINSZ)
55 #  include <sys/ioctl.h>
56 #endif /* GWINSZ_IN_SYS_IOCTL && !TIOCGWINSZ */
57
58 #ifdef __MSDOS__
59 # include <pc.h>
60 #endif
61
62 #include "rltty.h"
63 #include "tcap.h"
64
65 /* Some standard library routines. */
66 #include "readline.h"
67 #include "history.h"
68
69 #include "rlprivate.h"
70 #include "rlshell.h"
71 #include "xmalloc.h"
72
73 #define CUSTOM_REDISPLAY_FUNC() (rl_redisplay_function != rl_redisplay)
74 #define CUSTOM_INPUT_FUNC() (rl_getc_function != rl_getc)
75
76 /* **************************************************************** */
77 /*                                                                  */
78 /*                      Terminal and Termcap                        */
79 /*                                                                  */
80 /* **************************************************************** */
81
82 #ifndef __MSDOS__
83 static char *term_buffer = (char *)NULL;
84 static char *term_string_buffer = (char *)NULL;
85
86 /* Non-zero means this terminal can't really do anything. */
87 static int dumb_term;
88 #endif /* !__MSDOS__ */
89
90 static int tcap_initialized;
91
92 #if !defined (__linux__)
93 #  if defined (__EMX__) || defined (NEED_EXTERN_PC)
94 extern 
95 #  endif /* __EMX__ || NEED_EXTERN_PC */
96 char PC, *BC, *UP;
97 #endif /* __linux__ */
98
99 /* Some strings to control terminal actions.  These are output by tputs (). */
100 char *_rl_term_clreol;
101 char *_rl_term_clrpag;
102 char *_rl_term_cr;
103 char *_rl_term_backspace;
104 char *_rl_term_goto;
105 char *_rl_term_pc;
106
107 /* Non-zero if we determine that the terminal can do character insertion. */
108 int _rl_terminal_can_insert = 0;
109
110 /* How to insert characters. */
111 char *_rl_term_im;
112 char *_rl_term_ei;
113 char *_rl_term_ic;
114 char *_rl_term_ip;
115 char *_rl_term_IC;
116
117 /* How to delete characters. */
118 char *_rl_term_dc;
119 char *_rl_term_DC;
120
121 #if defined (HACK_TERMCAP_MOTION)
122 char *_rl_term_forward_char;
123 #endif  /* HACK_TERMCAP_MOTION */
124
125 /* How to go up a line. */
126 char *_rl_term_up;
127
128 /* A visible bell; char if the terminal can be made to flash the screen. */
129 static char *_rl_visible_bell;
130
131 /* Non-zero means the terminal can auto-wrap lines. */
132 int _rl_term_autowrap;
133
134 /* Non-zero means that this terminal has a meta key. */
135 static int term_has_meta;
136
137 /* The sequences to write to turn on and off the meta key, if this
138    terminal has one. */
139 static char *_rl_term_mm;
140 static char *_rl_term_mo;
141
142 /* The key sequences output by the arrow keys, if this terminal has any. */
143 static char *_rl_term_ku;
144 static char *_rl_term_kd;
145 static char *_rl_term_kr;
146 static char *_rl_term_kl;
147
148 /* How to initialize and reset the arrow keys, if this terminal has any. */
149 static char *_rl_term_ks;
150 static char *_rl_term_ke;
151
152 /* The key sequences sent by the Home and End keys, if any. */
153 static char *_rl_term_kh;
154 static char *_rl_term_kH;
155 static char *_rl_term_at7;      /* @7 */
156
157 /* Insert key */
158 static char *_rl_term_kI;
159
160 /* Cursor control */
161 static char *_rl_term_vs;       /* very visible */
162 static char *_rl_term_ve;       /* normal */
163
164 static void bind_termcap_arrow_keys PARAMS((Keymap));
165
166 /* Variables that hold the screen dimensions, used by the display code. */
167 int _rl_screenwidth, _rl_screenheight, _rl_screenchars;
168
169 /* Non-zero means the user wants to enable the keypad. */
170 int _rl_enable_keypad;
171
172 /* Non-zero means the user wants to enable a meta key. */
173 int _rl_enable_meta = 1;
174
175 #if defined (__EMX__)
176 static void
177 _emx_get_screensize (swp, shp)
178      int *swp, *shp;
179 {
180   int sz[2];
181
182   _scrsize (sz);
183
184   if (swp)
185     *swp = sz[0];
186   if (shp)
187     *shp = sz[1];
188 }
189 #endif
190
191 /* Get readline's idea of the screen size.  TTY is a file descriptor open
192    to the terminal.  If IGNORE_ENV is true, we do not pay attention to the
193    values of $LINES and $COLUMNS.  The tests for TERM_STRING_BUFFER being
194    non-null serve to check whether or not we have initialized termcap. */
195 void
196 _rl_get_screen_size (tty, ignore_env)
197      int tty, ignore_env;
198 {
199   char *ss;
200 #if defined (TIOCGWINSZ)
201   struct winsize window_size;
202 #endif /* TIOCGWINSZ */
203
204 #if defined (TIOCGWINSZ)
205   if (ioctl (tty, TIOCGWINSZ, &window_size) == 0)
206     {
207       _rl_screenwidth = (int) window_size.ws_col;
208       _rl_screenheight = (int) window_size.ws_row;
209     }
210 #endif /* TIOCGWINSZ */
211
212 #if defined (__EMX__)
213   _emx_get_screensize (&_rl_screenwidth, &_rl_screenheight);
214 #endif
215
216   /* Environment variable COLUMNS overrides setting of "co" if IGNORE_ENV
217      is unset. */
218   if (_rl_screenwidth <= 0)
219     {
220       if (ignore_env == 0 && (ss = sh_get_env_value ("COLUMNS")))
221         _rl_screenwidth = atoi (ss);
222
223 #if defined (__DJGPP__)
224       if (_rl_screenwidth <= 0)
225         _rl_screenwidth = ScreenCols ();
226 #else
227       if (_rl_screenwidth <= 0 && term_string_buffer)
228         _rl_screenwidth = tgetnum ("co");
229 #endif
230     }
231
232   /* Environment variable LINES overrides setting of "li" if IGNORE_ENV
233      is unset. */
234   if (_rl_screenheight <= 0)
235     {
236       if (ignore_env == 0 && (ss = sh_get_env_value ("LINES")))
237         _rl_screenheight = atoi (ss);
238
239 #if defined (__DJGPP__)
240       if (_rl_screenheight <= 0)
241         _rl_screenheight = ScreenRows ();
242 #else
243       if (_rl_screenheight <= 0 && term_string_buffer)
244         _rl_screenheight = tgetnum ("li");
245 #endif
246     }
247
248   /* If all else fails, default to 80x24 terminal. */
249   if (_rl_screenwidth <= 1)
250     _rl_screenwidth = 80;
251
252   if (_rl_screenheight <= 0)
253     _rl_screenheight = 24;
254
255   /* If we're being compiled as part of bash, set the environment
256      variables $LINES and $COLUMNS to new values.  Otherwise, just
257      do a pair of putenv () or setenv () calls. */
258   sh_set_lines_and_columns (_rl_screenheight, _rl_screenwidth);
259
260   if (_rl_term_autowrap == 0)
261     _rl_screenwidth--;
262
263   _rl_screenchars = _rl_screenwidth * _rl_screenheight;
264 }
265
266 void
267 _rl_set_screen_size (rows, cols)
268      int rows, cols;
269 {
270   if (rows == 0 || cols == 0)
271     return;
272
273   _rl_screenheight = rows;
274   _rl_screenwidth = cols;
275
276   if (_rl_term_autowrap == 0)
277     _rl_screenwidth--;
278
279   _rl_screenchars = _rl_screenwidth * _rl_screenheight;
280 }
281
282 void
283 rl_set_screen_size (rows, cols)
284      int rows, cols;
285 {
286   _rl_set_screen_size (rows, cols);
287 }
288
289 void
290 rl_get_screen_size (rows, cols)
291      int *rows, *cols;
292 {
293   if (rows)
294     *rows = _rl_screenheight;
295   if (cols)
296     *cols = _rl_screenwidth;
297 }
298      
299 void
300 rl_resize_terminal ()
301 {
302   if (readline_echoing_p)
303     {
304       _rl_get_screen_size (fileno (rl_instream), 1);
305       if (CUSTOM_REDISPLAY_FUNC ())
306         rl_forced_update_display ();
307       else
308         _rl_redisplay_after_sigwinch ();
309     }
310 }
311
312 struct _tc_string {
313      const char *tc_var;
314      char **tc_value;
315 };
316
317 /* This should be kept sorted, just in case we decide to change the
318    search algorithm to something smarter. */
319 static struct _tc_string tc_strings[] =
320 {
321   { "@7", &_rl_term_at7 },
322   { "DC", &_rl_term_DC },
323   { "IC", &_rl_term_IC },
324   { "ce", &_rl_term_clreol },
325   { "cl", &_rl_term_clrpag },
326   { "cr", &_rl_term_cr },
327   { "dc", &_rl_term_dc },
328   { "ei", &_rl_term_ei },
329   { "ic", &_rl_term_ic },
330   { "im", &_rl_term_im },
331   { "kH", &_rl_term_kH },       /* home down ?? */
332   { "kI", &_rl_term_kI },       /* insert */
333   { "kd", &_rl_term_kd },
334   { "ke", &_rl_term_ke },       /* end keypad mode */
335   { "kh", &_rl_term_kh },       /* home */
336   { "kl", &_rl_term_kl },
337   { "kr", &_rl_term_kr },
338   { "ks", &_rl_term_ks },       /* start keypad mode */
339   { "ku", &_rl_term_ku },
340   { "le", &_rl_term_backspace },
341   { "mm", &_rl_term_mm },
342   { "mo", &_rl_term_mo },
343 #if defined (HACK_TERMCAP_MOTION)
344   { "nd", &_rl_term_forward_char },
345 #endif
346   { "pc", &_rl_term_pc },
347   { "up", &_rl_term_up },
348   { "vb", &_rl_visible_bell },
349   { "vs", &_rl_term_vs },
350   { "ve", &_rl_term_ve },
351 };
352
353 #define NUM_TC_STRINGS (sizeof (tc_strings) / sizeof (struct _tc_string))
354
355 /* Read the desired terminal capability strings into BP.  The capabilities
356    are described in the TC_STRINGS table. */
357 static void
358 get_term_capabilities (bp)
359      char **bp;
360 {
361 #if !defined (__DJGPP__)        /* XXX - doesn't DJGPP have a termcap library? */
362   register int i;
363
364   for (i = 0; i < NUM_TC_STRINGS; i++)
365 #  ifdef __LCC__
366     *(tc_strings[i].tc_value) = tgetstr ((char *)tc_strings[i].tc_var, bp);
367 #  else
368     *(tc_strings[i].tc_value) = tgetstr (tc_strings[i].tc_var, bp);
369 #  endif
370 #endif
371   tcap_initialized = 1;
372 }
373
374 int
375 _rl_init_terminal_io (terminal_name)
376      const char *terminal_name;
377 {
378   const char *term;
379   char *buffer;
380   int tty, tgetent_ret;
381
382   term = terminal_name ? terminal_name : sh_get_env_value ("TERM");
383   _rl_term_clrpag = _rl_term_cr = _rl_term_clreol = (char *)NULL;
384   tty = rl_instream ? fileno (rl_instream) : 0;
385   _rl_screenwidth = _rl_screenheight = 0;
386
387   if (term == 0)
388     term = "dumb";
389
390 #ifdef __MSDOS__
391   _rl_term_im = _rl_term_ei = _rl_term_ic = _rl_term_IC = (char *)NULL;
392   _rl_term_up = _rl_term_dc = _rl_term_DC = _rl_visible_bell = (char *)NULL;
393   _rl_term_ku = _rl_term_kd = _rl_term_kl = _rl_term_kr = (char *)NULL;
394   _rl_term_mm = _rl_term_mo = (char *)NULL;
395   _rl_terminal_can_insert = term_has_meta = _rl_term_autowrap = 0;
396   _rl_term_cr = "\r";
397   _rl_term_clreol = _rl_term_clrpag = _rl_term_backspace = (char *)NULL;
398   _rl_term_goto = _rl_term_pc = _rl_term_ip = (char *)NULL;
399   _rl_term_ks = _rl_term_ke =_rl_term_vs = _rl_term_ve = (char *)NULL;
400   _rl_term_kh = _rl_term_kH = _rl_term_at7 = _rl_term_kI = (char *)NULL;
401 #if defined(HACK_TERMCAP_MOTION)
402   _rl_term_forward_char = (char *)NULL;
403 #endif
404
405   _rl_get_screen_size (tty, 0);
406 #else  /* !__MSDOS__ */
407   /* I've separated this out for later work on not calling tgetent at all
408      if the calling application has supplied a custom redisplay function,
409      (and possibly if the application has supplied a custom input function). */
410   if (CUSTOM_REDISPLAY_FUNC())
411     {
412       tgetent_ret = -1;
413     }
414   else
415     {
416       if (term_string_buffer == 0)
417         term_string_buffer = (char *)xmalloc(2032);
418
419       if (term_buffer == 0)
420         term_buffer = (char *)xmalloc(4080);
421
422       buffer = term_string_buffer;
423
424       tgetent_ret = tgetent (term_buffer, term);
425     }
426
427   if (tgetent_ret <= 0)
428     {
429       FREE (term_string_buffer);
430       FREE (term_buffer);
431       buffer = term_buffer = term_string_buffer = (char *)NULL;
432
433       _rl_term_autowrap = 0;    /* used by _rl_get_screen_size */
434
435 #if defined (__EMX__)
436       _emx_get_screensize (&_rl_screenwidth, &_rl_screenheight);
437       _rl_screenwidth--;
438 #else /* !__EMX__ */
439       _rl_get_screen_size (tty, 0);
440 #endif /* !__EMX__ */
441
442       /* Defaults. */
443       if (_rl_screenwidth <= 0 || _rl_screenheight <= 0)
444         {
445           _rl_screenwidth = 79;
446           _rl_screenheight = 24;
447         }
448
449       /* Everything below here is used by the redisplay code (tputs). */
450       _rl_screenchars = _rl_screenwidth * _rl_screenheight;
451       _rl_term_cr = "\r";
452       _rl_term_im = _rl_term_ei = _rl_term_ic = _rl_term_IC = (char *)NULL;
453       _rl_term_up = _rl_term_dc = _rl_term_DC = _rl_visible_bell = (char *)NULL;
454       _rl_term_ku = _rl_term_kd = _rl_term_kl = _rl_term_kr = (char *)NULL;
455       _rl_term_kh = _rl_term_kH = _rl_term_kI = (char *)NULL;
456       _rl_term_ks = _rl_term_ke = _rl_term_at7 = (char *)NULL;
457       _rl_term_mm = _rl_term_mo = (char *)NULL;
458       _rl_term_ve = _rl_term_vs = (char *)NULL;
459 #if defined (HACK_TERMCAP_MOTION)
460       term_forward_char = (char *)NULL;
461 #endif
462       _rl_terminal_can_insert = term_has_meta = 0;
463
464       /* Reasonable defaults for tgoto().  Readline currently only uses
465          tgoto if _rl_term_IC or _rl_term_DC is defined, but just in case we
466          change that later... */
467       PC = '\0';
468       BC = _rl_term_backspace = "\b";
469       UP = _rl_term_up;
470
471       return 0;
472     }
473
474   get_term_capabilities (&buffer);
475
476   /* Set up the variables that the termcap library expects the application
477      to provide. */
478   PC = _rl_term_pc ? *_rl_term_pc : 0;
479   BC = _rl_term_backspace;
480   UP = _rl_term_up;
481
482   if (!_rl_term_cr)
483     _rl_term_cr = "\r";
484
485   _rl_term_autowrap = tgetflag ("am") && tgetflag ("xn");
486
487   _rl_get_screen_size (tty, 0);
488
489   /* "An application program can assume that the terminal can do
490       character insertion if *any one of* the capabilities `IC',
491       `im', `ic' or `ip' is provided."  But we can't do anything if
492       only `ip' is provided, so... */
493   _rl_terminal_can_insert = (_rl_term_IC || _rl_term_im || _rl_term_ic);
494
495   /* Check to see if this terminal has a meta key and clear the capability
496      variables if there is none. */
497   term_has_meta = (tgetflag ("km") || tgetflag ("MT"));
498   if (!term_has_meta)
499     _rl_term_mm = _rl_term_mo = (char *)NULL;
500
501 #endif /* !__MSDOS__ */
502
503   /* Attempt to find and bind the arrow keys.  Do not override already
504      bound keys in an overzealous attempt, however. */
505
506   bind_termcap_arrow_keys (emacs_standard_keymap);
507
508 #if defined (VI_MODE)
509   bind_termcap_arrow_keys (vi_movement_keymap);
510   bind_termcap_arrow_keys (vi_insertion_keymap);
511 #endif /* VI_MODE */
512
513   return 0;
514 }
515
516 /* Bind the arrow key sequences from the termcap description in MAP. */
517 static void
518 bind_termcap_arrow_keys (map)
519      Keymap map;
520 {
521   Keymap xkeymap;
522
523   xkeymap = _rl_keymap;
524   _rl_keymap = map;
525
526   _rl_bind_if_unbound (_rl_term_ku, rl_get_previous_history);
527   _rl_bind_if_unbound (_rl_term_kd, rl_get_next_history);
528   _rl_bind_if_unbound (_rl_term_kr, rl_forward);
529   _rl_bind_if_unbound (_rl_term_kl, rl_backward);
530
531   _rl_bind_if_unbound (_rl_term_kh, rl_beg_of_line);    /* Home */
532   _rl_bind_if_unbound (_rl_term_at7, rl_end_of_line);   /* End */
533
534   _rl_keymap = xkeymap;
535 }
536
537 char *
538 rl_get_termcap (cap)
539      const char *cap;
540 {
541   register int i;
542
543   if (tcap_initialized == 0)
544     return ((char *)NULL);
545   for (i = 0; i < NUM_TC_STRINGS; i++)
546     {
547       if (tc_strings[i].tc_var[0] == cap[0] && strcmp (tc_strings[i].tc_var, cap) == 0)
548         return *(tc_strings[i].tc_value);
549     }
550   return ((char *)NULL);
551 }
552
553 /* Re-initialize the terminal considering that the TERM/TERMCAP variable
554    has changed. */
555 int
556 rl_reset_terminal (terminal_name)
557      const char *terminal_name;
558 {
559   _rl_init_terminal_io (terminal_name);
560   return 0;
561 }
562
563 /* A function for the use of tputs () */
564 #ifdef _MINIX
565 void
566 _rl_output_character_function (c)
567      int c;
568 {
569   putc (c, _rl_out_stream);
570 }
571 #else /* !_MINIX */
572 int
573 _rl_output_character_function (c)
574      int c;
575 {
576   return putc (c, _rl_out_stream);
577 }
578 #endif /* !_MINIX */
579
580 /* Write COUNT characters from STRING to the output stream. */
581 void
582 _rl_output_some_chars (string, count)
583      const char *string;
584      int count;
585 {
586   fwrite (string, 1, count, _rl_out_stream);
587 }
588
589 /* Move the cursor back. */
590 int
591 _rl_backspace (count)
592      int count;
593 {
594   register int i;
595
596 #ifndef __MSDOS__
597   if (_rl_term_backspace)
598     for (i = 0; i < count; i++)
599       tputs (_rl_term_backspace, 1, _rl_output_character_function);
600   else
601 #endif
602     for (i = 0; i < count; i++)
603       putc ('\b', _rl_out_stream);
604   return 0;
605 }
606
607 /* Move to the start of the next line. */
608 int
609 rl_crlf ()
610 {
611 #if defined (NEW_TTY_DRIVER)
612   if (_rl_term_cr)
613     tputs (_rl_term_cr, 1, _rl_output_character_function);
614 #endif /* NEW_TTY_DRIVER */
615   putc ('\n', _rl_out_stream);
616   return 0;
617 }
618
619 /* Ring the terminal bell. */
620 int
621 rl_ding ()
622 {
623   if (readline_echoing_p)
624     {
625       switch (_rl_bell_preference)
626         {
627         case NO_BELL:
628         default:
629           break;
630         case VISIBLE_BELL:
631 #ifdef __MSDOS__
632           ScreenVisualBell ();
633           break;
634 #else
635           if (_rl_visible_bell)
636             {
637               tputs (_rl_visible_bell, 1, _rl_output_character_function);
638               break;
639             }
640 #endif
641           /* FALLTHROUGH */
642         case AUDIBLE_BELL:
643           fprintf (stderr, "\007");
644           fflush (stderr);
645           break;
646         }
647       return (0);
648     }
649   return (-1);
650 }
651
652 /* **************************************************************** */
653 /*                                                                  */
654 /*              Controlling the Meta Key and Keypad                 */
655 /*                                                                  */
656 /* **************************************************************** */
657
658 void
659 _rl_enable_meta_key ()
660 {
661 #if !defined (__DJGPP__)
662   if (term_has_meta && _rl_term_mm)
663     tputs (_rl_term_mm, 1, _rl_output_character_function);
664 #endif
665 }
666
667 void
668 _rl_control_keypad (on)
669      int on;
670 {
671 #if !defined (__DJGPP__)
672   if (on && _rl_term_ks)
673     tputs (_rl_term_ks, 1, _rl_output_character_function);
674   else if (!on && _rl_term_ke)
675     tputs (_rl_term_ke, 1, _rl_output_character_function);
676 #endif
677 }
678
679 /* **************************************************************** */
680 /*                                                                  */
681 /*                      Controlling the Cursor                      */
682 /*                                                                  */
683 /* **************************************************************** */
684
685 /* Set the cursor appropriately depending on IM, which is one of the
686    insert modes (insert or overwrite).  Insert mode gets the normal
687    cursor.  Overwrite mode gets a very visible cursor.  Only does
688    anything if we have both capabilities. */
689 void
690 _rl_set_cursor (im, force)
691      int im, force;
692 {
693 #ifndef __MSDOS__
694   if (_rl_term_ve && _rl_term_vs)
695     {
696       if (force || im != rl_insert_mode)
697         {
698           if (im == RL_IM_OVERWRITE)
699             tputs (_rl_term_vs, 1, _rl_output_character_function);
700           else
701             tputs (_rl_term_ve, 1, _rl_output_character_function);
702         }
703     }
704 #endif
705 }