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