Import GNU readline 5.0.
[dragonfly.git] / contrib / readline-5.0 / 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     *(tc_strings[i].tc_value) = tgetstr ((char *)tc_strings[i].tc_var, bp);
351 #endif
352   tcap_initialized = 1;
353 }
354
355 int
356 _rl_init_terminal_io (terminal_name)
357      const char *terminal_name;
358 {
359   const char *term;
360   char *buffer;
361   int tty, tgetent_ret;
362
363   term = terminal_name ? terminal_name : sh_get_env_value ("TERM");
364   _rl_term_clrpag = _rl_term_cr = _rl_term_clreol = (char *)NULL;
365   tty = rl_instream ? fileno (rl_instream) : 0;
366   _rl_screenwidth = _rl_screenheight = 0;
367
368   if (term == 0)
369     term = "dumb";
370
371   /* I've separated this out for later work on not calling tgetent at all
372      if the calling application has supplied a custom redisplay function,
373      (and possibly if the application has supplied a custom input function). */
374   if (CUSTOM_REDISPLAY_FUNC())
375     {
376       tgetent_ret = -1;
377     }
378   else
379     {
380       if (term_string_buffer == 0)
381         term_string_buffer = (char *)xmalloc(2032);
382
383       if (term_buffer == 0)
384         term_buffer = (char *)xmalloc(4080);
385
386       buffer = term_string_buffer;
387
388       tgetent_ret = tgetent (term_buffer, term);
389     }
390
391   if (tgetent_ret <= 0)
392     {
393       FREE (term_string_buffer);
394       FREE (term_buffer);
395       buffer = term_buffer = term_string_buffer = (char *)NULL;
396
397       _rl_term_autowrap = 0;    /* used by _rl_get_screen_size */
398
399 #if defined (__EMX__)
400       _emx_get_screensize (&_rl_screenwidth, &_rl_screenheight);
401       _rl_screenwidth--;
402 #else /* !__EMX__ */
403       _rl_get_screen_size (tty, 0);
404 #endif /* !__EMX__ */
405
406       /* Defaults. */
407       if (_rl_screenwidth <= 0 || _rl_screenheight <= 0)
408         {
409           _rl_screenwidth = 79;
410           _rl_screenheight = 24;
411         }
412
413       /* Everything below here is used by the redisplay code (tputs). */
414       _rl_screenchars = _rl_screenwidth * _rl_screenheight;
415       _rl_term_cr = "\r";
416       _rl_term_im = _rl_term_ei = _rl_term_ic = _rl_term_IC = (char *)NULL;
417       _rl_term_up = _rl_term_dc = _rl_term_DC = _rl_visible_bell = (char *)NULL;
418       _rl_term_ku = _rl_term_kd = _rl_term_kl = _rl_term_kr = (char *)NULL;
419       _rl_term_kh = _rl_term_kH = _rl_term_kI = (char *)NULL;
420       _rl_term_ks = _rl_term_ke = _rl_term_at7 = (char *)NULL;
421       _rl_term_mm = _rl_term_mo = (char *)NULL;
422       _rl_term_ve = _rl_term_vs = (char *)NULL;
423 #if defined (HACK_TERMCAP_MOTION)
424       term_forward_char = (char *)NULL;
425 #endif
426       _rl_terminal_can_insert = term_has_meta = 0;
427
428       /* Reasonable defaults for tgoto().  Readline currently only uses
429          tgoto if _rl_term_IC or _rl_term_DC is defined, but just in case we
430          change that later... */
431       PC = '\0';
432       BC = _rl_term_backspace = "\b";
433       UP = _rl_term_up;
434
435       return 0;
436     }
437
438   get_term_capabilities (&buffer);
439
440   /* Set up the variables that the termcap library expects the application
441      to provide. */
442   PC = _rl_term_pc ? *_rl_term_pc : 0;
443   BC = _rl_term_backspace;
444   UP = _rl_term_up;
445
446   if (!_rl_term_cr)
447     _rl_term_cr = "\r";
448
449   _rl_term_autowrap = tgetflag ("am") && tgetflag ("xn");
450
451   _rl_get_screen_size (tty, 0);
452
453   /* "An application program can assume that the terminal can do
454       character insertion if *any one of* the capabilities `IC',
455       `im', `ic' or `ip' is provided."  But we can't do anything if
456       only `ip' is provided, so... */
457   _rl_terminal_can_insert = (_rl_term_IC || _rl_term_im || _rl_term_ic);
458
459   /* Check to see if this terminal has a meta key and clear the capability
460      variables if there is none. */
461   term_has_meta = (tgetflag ("km") || tgetflag ("MT"));
462   if (!term_has_meta)
463     _rl_term_mm = _rl_term_mo = (char *)NULL;
464
465   /* Attempt to find and bind the arrow keys.  Do not override already
466      bound keys in an overzealous attempt, however. */
467
468   bind_termcap_arrow_keys (emacs_standard_keymap);
469
470 #if defined (VI_MODE)
471   bind_termcap_arrow_keys (vi_movement_keymap);
472   bind_termcap_arrow_keys (vi_insertion_keymap);
473 #endif /* VI_MODE */
474
475   return 0;
476 }
477
478 /* Bind the arrow key sequences from the termcap description in MAP. */
479 static void
480 bind_termcap_arrow_keys (map)
481      Keymap map;
482 {
483   Keymap xkeymap;
484
485   xkeymap = _rl_keymap;
486   _rl_keymap = map;
487
488   rl_bind_keyseq_if_unbound (_rl_term_ku, rl_get_previous_history);
489   rl_bind_keyseq_if_unbound (_rl_term_kd, rl_get_next_history);
490   rl_bind_keyseq_if_unbound (_rl_term_kr, rl_forward_char);
491   rl_bind_keyseq_if_unbound (_rl_term_kl, rl_backward_char);
492
493   rl_bind_keyseq_if_unbound (_rl_term_kh, rl_beg_of_line);      /* Home */
494   rl_bind_keyseq_if_unbound (_rl_term_at7, rl_end_of_line);     /* End */
495
496   _rl_keymap = xkeymap;
497 }
498
499 char *
500 rl_get_termcap (cap)
501      const char *cap;
502 {
503   register int i;
504
505   if (tcap_initialized == 0)
506     return ((char *)NULL);
507   for (i = 0; i < NUM_TC_STRINGS; i++)
508     {
509       if (tc_strings[i].tc_var[0] == cap[0] && strcmp (tc_strings[i].tc_var, cap) == 0)
510         return *(tc_strings[i].tc_value);
511     }
512   return ((char *)NULL);
513 }
514
515 /* Re-initialize the terminal considering that the TERM/TERMCAP variable
516    has changed. */
517 int
518 rl_reset_terminal (terminal_name)
519      const char *terminal_name;
520 {
521   _rl_init_terminal_io (terminal_name);
522   return 0;
523 }
524
525 /* A function for the use of tputs () */
526 #ifdef _MINIX
527 void
528 _rl_output_character_function (c)
529      int c;
530 {
531   putc (c, _rl_out_stream);
532 }
533 #else /* !_MINIX */
534 int
535 _rl_output_character_function (c)
536      int c;
537 {
538   return putc (c, _rl_out_stream);
539 }
540 #endif /* !_MINIX */
541
542 /* Write COUNT characters from STRING to the output stream. */
543 void
544 _rl_output_some_chars (string, count)
545      const char *string;
546      int count;
547 {
548   fwrite (string, 1, count, _rl_out_stream);
549 }
550
551 /* Move the cursor back. */
552 int
553 _rl_backspace (count)
554      int count;
555 {
556   register int i;
557
558   if (_rl_term_backspace)
559     for (i = 0; i < count; i++)
560       tputs (_rl_term_backspace, 1, _rl_output_character_function);
561   else
562     for (i = 0; i < count; i++)
563       putc ('\b', _rl_out_stream);
564   return 0;
565 }
566
567 /* Move to the start of the next line. */
568 int
569 rl_crlf ()
570 {
571 #if defined (NEW_TTY_DRIVER)
572   if (_rl_term_cr)
573     tputs (_rl_term_cr, 1, _rl_output_character_function);
574 #endif /* NEW_TTY_DRIVER */
575   putc ('\n', _rl_out_stream);
576   return 0;
577 }
578
579 /* Ring the terminal bell. */
580 int
581 rl_ding ()
582 {
583   if (readline_echoing_p)
584     {
585       switch (_rl_bell_preference)
586         {
587         case NO_BELL:
588         default:
589           break;
590         case VISIBLE_BELL:
591           if (_rl_visible_bell)
592             {
593               tputs (_rl_visible_bell, 1, _rl_output_character_function);
594               break;
595             }
596           /* FALLTHROUGH */
597         case AUDIBLE_BELL:
598           fprintf (stderr, "\007");
599           fflush (stderr);
600           break;
601         }
602       return (0);
603     }
604   return (-1);
605 }
606
607 /* **************************************************************** */
608 /*                                                                  */
609 /*              Controlling the Meta Key and Keypad                 */
610 /*                                                                  */
611 /* **************************************************************** */
612
613 void
614 _rl_enable_meta_key ()
615 {
616 #if !defined (__DJGPP__)
617   if (term_has_meta && _rl_term_mm)
618     tputs (_rl_term_mm, 1, _rl_output_character_function);
619 #endif
620 }
621
622 void
623 _rl_control_keypad (on)
624      int on;
625 {
626 #if !defined (__DJGPP__)
627   if (on && _rl_term_ks)
628     tputs (_rl_term_ks, 1, _rl_output_character_function);
629   else if (!on && _rl_term_ke)
630     tputs (_rl_term_ke, 1, _rl_output_character_function);
631 #endif
632 }
633
634 /* **************************************************************** */
635 /*                                                                  */
636 /*                      Controlling the Cursor                      */
637 /*                                                                  */
638 /* **************************************************************** */
639
640 /* Set the cursor appropriately depending on IM, which is one of the
641    insert modes (insert or overwrite).  Insert mode gets the normal
642    cursor.  Overwrite mode gets a very visible cursor.  Only does
643    anything if we have both capabilities. */
644 void
645 _rl_set_cursor (im, force)
646      int im, force;
647 {
648   if (_rl_term_ve && _rl_term_vs)
649     {
650       if (force || im != rl_insert_mode)
651         {
652           if (im == RL_IM_OVERWRITE)
653             tputs (_rl_term_vs, 1, _rl_output_character_function);
654           else
655             tputs (_rl_term_ve, 1, _rl_output_character_function);
656         }
657     }
658 }