]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - contrib/libreadline/terminal.c
This commit was generated by cvs2svn to compensate for changes in r95154,
[FreeBSD/FreeBSD.git] / contrib / libreadline / terminal.c
1 /* $FreeBSD$ */
2 /* terminal.c -- controlling the terminal with termcap. */
3
4 /* Copyright (C) 1996 Free Software Foundation, Inc.
5
6    This file is part of the GNU Readline Library, a library for
7    reading lines of text with interactive input and history editing.
8
9    The GNU Readline Library is free software; you can redistribute it
10    and/or modify it under the terms of the GNU General Public License
11    as published by the Free Software Foundation; either version 2, or
12    (at your option) any later version.
13
14    The GNU Readline Library is distributed in the hope that it will be
15    useful, but WITHOUT ANY WARRANTY; without even the implied warranty
16    of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
17    GNU General Public License for more details.
18
19    The GNU General Public License is often shipped with GNU software, and
20    is generally kept in a file called COPYING or LICENSE.  If you do not
21    have a copy of the license, write to the Free Software Foundation,
22    59 Temple Place, Suite 330, Boston, MA 02111 USA. */
23 #define READLINE_LIBRARY
24
25 #if defined (HAVE_CONFIG_H)
26 #  include <config.h>
27 #endif
28
29 #include <sys/types.h>
30 #include "posixstat.h"
31 #include <fcntl.h>
32 #if defined (HAVE_SYS_FILE_H)
33 #  include <sys/file.h>
34 #endif /* HAVE_SYS_FILE_H */
35
36 #if defined (HAVE_UNISTD_H)
37 #  include <unistd.h>
38 #endif /* HAVE_UNISTD_H */
39
40 #if defined (HAVE_STDLIB_H)
41 #  include <stdlib.h>
42 #else
43 #  include "ansi_stdlib.h"
44 #endif /* HAVE_STDLIB_H */
45
46 #if defined (HAVE_LOCALE_H)
47 #  include <locale.h>
48 #endif
49
50 #include <stdio.h>
51
52 /* System-specific feature definitions and include files. */
53 #include "rldefs.h"
54
55 #if defined (GWINSZ_IN_SYS_IOCTL) && !defined (TIOCGWINSZ)
56 #  include <sys/ioctl.h>
57 #endif /* GWINSZ_IN_SYS_IOCTL && !TIOCGWINSZ */
58
59 #include "rltty.h"
60 #include "tcap.h"
61
62 /* Some standard library routines. */
63 #include "readline.h"
64 #include "history.h"
65
66 #include "rlprivate.h"
67 #include "rlshell.h"
68
69 /* **************************************************************** */
70 /*                                                                  */
71 /*                      Terminal and Termcap                        */
72 /*                                                                  */
73 /* **************************************************************** */
74
75 static char *term_buffer = (char *)NULL;
76 static char *term_string_buffer = (char *)NULL;
77
78 static int tcap_initialized;
79
80 #if !defined (__linux__)
81 #  if defined (__EMX__) || defined (NEED_EXTERN_PC)
82 extern 
83 #  endif /* __EMX__ || NEED_EXTERN_PC */
84 char PC, *BC, *UP;
85 #endif /* __linux__ */
86
87 /* Some strings to control terminal actions.  These are output by tputs (). */
88 char *_rl_term_clreol;
89 char *_rl_term_clrpag;
90 char *_rl_term_cr;
91 char *_rl_term_backspace;
92 char *_rl_term_goto;
93 char *_rl_term_pc;
94
95 /* Non-zero if we determine that the terminal can do character insertion. */
96 int _rl_terminal_can_insert = 0;
97
98 /* How to insert characters. */
99 char *_rl_term_im;
100 char *_rl_term_ei;
101 char *_rl_term_ic;
102 char *_rl_term_ip;
103 char *_rl_term_IC;
104
105 /* How to delete characters. */
106 char *_rl_term_dc;
107 char *_rl_term_DC;
108
109 #if defined (HACK_TERMCAP_MOTION)
110 char *_rl_term_forward_char;
111 #endif  /* HACK_TERMCAP_MOTION */
112
113 /* How to go up a line. */
114 char *_rl_term_up;
115
116 /* A visible bell; char if the terminal can be made to flash the screen. */
117 static char *_rl_visible_bell;
118
119 /* Non-zero means the terminal can auto-wrap lines. */
120 int _rl_term_autowrap;
121
122 /* Non-zero means that this terminal has a meta key. */
123 static int term_has_meta;
124
125 /* The sequences to write to turn on and off the meta key, if this
126    terminal has one. */
127 static char *_rl_term_mm;
128 static char *_rl_term_mo;
129
130 /* The key sequences output by the arrow keys, if this terminal has any. */
131 static char *_rl_term_ku;
132 static char *_rl_term_kd;
133 static char *_rl_term_kr;
134 static char *_rl_term_kl;
135
136 /* How to initialize and reset the arrow keys, if this terminal has any. */
137 static char *_rl_term_ks;
138 static char *_rl_term_ke;
139
140 /* The key sequences sent by the Home and End keys, if any. */
141 static char *_rl_term_kh;
142 static char *_rl_term_kH;
143
144 /* Variables that hold the screen dimensions, used by the display code. */
145 int _rl_screenwidth, _rl_screenheight, _rl_screenchars;
146
147 /* Non-zero means the user wants to enable the keypad. */
148 int _rl_enable_keypad;
149
150 /* Non-zero means the user wants to enable a meta key. */
151 int _rl_enable_meta = 1;
152
153 #if defined (__EMX__)
154 static void
155 _emx_get_screensize (swp, shp)
156      int *swp, *shp;
157 {
158   int sz[2];
159
160   _scrsize (sz);
161
162   if (swp)
163     *swp = sz[0];
164   if (shp)
165     *shp = sz[1];
166 }
167 #endif
168
169 /* Get readline's idea of the screen size.  TTY is a file descriptor open
170    to the terminal.  If IGNORE_ENV is true, we do not pay attention to the
171    values of $LINES and $COLUMNS.  The tests for TERM_STRING_BUFFER being
172    non-null serve to check whether or not we have initialized termcap. */
173 void
174 _rl_get_screen_size (tty, ignore_env)
175      int tty, ignore_env;
176 {
177   char *ss;
178 #if defined (TIOCGWINSZ)
179   struct winsize window_size;
180 #endif /* TIOCGWINSZ */
181
182 #if defined (TIOCGWINSZ)
183   if (ioctl (tty, TIOCGWINSZ, &window_size) == 0)
184     {
185       _rl_screenwidth = (int) window_size.ws_col;
186       _rl_screenheight = (int) window_size.ws_row;
187     }
188 #endif /* TIOCGWINSZ */
189
190 #if defined (__EMX__)
191   _emx_get_screensize (&_rl_screenwidth, &_rl_screenheight);
192 #endif
193
194   /* Environment variable COLUMNS overrides setting of "co" if IGNORE_ENV
195      is unset. */
196   if (_rl_screenwidth <= 0)
197     {
198       if (ignore_env == 0 && (ss = sh_get_env_value ("COLUMNS")))
199         _rl_screenwidth = atoi (ss);
200
201 #if !defined (__DJGPP__)
202       if (_rl_screenwidth <= 0 && term_string_buffer)
203         _rl_screenwidth = tgetnum ("co");
204 #endif
205     }
206
207   /* Environment variable LINES overrides setting of "li" if IGNORE_ENV
208      is unset. */
209   if (_rl_screenheight <= 0)
210     {
211       if (ignore_env == 0 && (ss = sh_get_env_value ("LINES")))
212         _rl_screenheight = atoi (ss);
213
214 #if !defined (__DJGPP__)
215       if (_rl_screenheight <= 0 && term_string_buffer)
216         _rl_screenheight = tgetnum ("li");
217 #endif
218     }
219
220   /* If all else fails, default to 80x24 terminal. */
221   if (_rl_screenwidth <= 1)
222     _rl_screenwidth = 80;
223
224   if (_rl_screenheight <= 0)
225     _rl_screenheight = 24;
226
227   /* If we're being compiled as part of bash, set the environment
228      variables $LINES and $COLUMNS to new values.  Otherwise, just
229      do a pair of putenv () or setenv () calls. */
230   sh_set_lines_and_columns (_rl_screenheight, _rl_screenwidth);
231
232   if (_rl_term_autowrap == 0)
233     _rl_screenwidth--;
234
235   _rl_screenchars = _rl_screenwidth * _rl_screenheight;
236 }
237
238 void
239 _rl_set_screen_size (rows, cols)
240      int rows, cols;
241 {
242   if (rows == 0 || cols == 0)
243     return;
244
245   _rl_screenheight = rows;
246   _rl_screenwidth = cols;
247
248   if (_rl_term_autowrap == 0)
249     _rl_screenwidth--;
250
251   _rl_screenchars = _rl_screenwidth * _rl_screenheight;
252 }
253
254 void
255 rl_set_screen_size (rows, cols)
256      int rows, cols;
257 {
258   _rl_set_screen_size (rows, cols);
259 }
260
261 void
262 rl_get_screen_size (rows, cols)
263      int *rows, *cols;
264 {
265   if (rows)
266     *rows = _rl_screenheight;
267   if (cols)
268     *cols = _rl_screenwidth;
269 }
270      
271 void
272 rl_resize_terminal ()
273 {
274   if (readline_echoing_p)
275     {
276       _rl_get_screen_size (fileno (rl_instream), 1);
277       _rl_redisplay_after_sigwinch ();
278     }
279 }
280
281 struct _tc_string {
282      const char *tc_var;
283      char **tc_value;
284 };
285
286 /* This should be kept sorted, just in case we decide to change the
287    search algorithm to something smarter. */
288 static struct _tc_string tc_strings[] =
289 {
290   { "DC", &_rl_term_DC },
291   { "IC", &_rl_term_IC },
292   { "ce", &_rl_term_clreol },
293   { "cl", &_rl_term_clrpag },
294   { "cr", &_rl_term_cr },
295   { "dc", &_rl_term_dc },
296   { "ei", &_rl_term_ei },
297   { "ic", &_rl_term_ic },
298   { "im", &_rl_term_im },
299   { "kd", &_rl_term_kd },
300   { "kh", &_rl_term_kh },       /* home */
301   { "@7", &_rl_term_kH },       /* end */
302   { "kl", &_rl_term_kl },
303   { "kr", &_rl_term_kr },
304   { "ku", &_rl_term_ku },
305   { "ks", &_rl_term_ks },
306   { "ke", &_rl_term_ke },
307   { "le", &_rl_term_backspace },
308   { "mm", &_rl_term_mm },
309   { "mo", &_rl_term_mo },
310 #if defined (HACK_TERMCAP_MOTION)
311   { "nd", &_rl_term_forward_char },
312 #endif
313   { "pc", &_rl_term_pc },
314   { "up", &_rl_term_up },
315   { "vb", &_rl_visible_bell },
316 };
317
318 #define NUM_TC_STRINGS (sizeof (tc_strings) / sizeof (struct _tc_string))
319
320 /* Read the desired terminal capability strings into BP.  The capabilities
321    are described in the TC_STRINGS table. */
322 static void
323 get_term_capabilities (bp)
324      char **bp;
325 {
326 #if !defined (__DJGPP__)        /* XXX - doesn't DJGPP have a termcap library? */
327   register int i;
328
329   for (i = 0; i < NUM_TC_STRINGS; i++)
330     *(tc_strings[i].tc_value) = tgetstr (tc_strings[i].tc_var, bp);
331 #endif
332   tcap_initialized = 1;
333 }
334
335 #define CUSTOM_REDISPLAY_FUNC() (rl_redisplay_function != rl_redisplay)
336 #define CUSTOM_INPUT_FUNC() (rl_getc_function != rl_getc)
337
338 int
339 _rl_init_terminal_io (terminal_name)
340      const char *terminal_name;
341 {
342   const char *term;
343   char *buffer;
344   int tty, tgetent_ret;
345   Keymap xkeymap;
346
347   term = terminal_name ? terminal_name : sh_get_env_value ("TERM");
348   _rl_term_clrpag = _rl_term_cr = _rl_term_clreol = (char *)NULL;
349   tty = rl_instream ? fileno (rl_instream) : 0;
350   _rl_screenwidth = _rl_screenheight = 0;
351
352   if (term == 0)
353     term = "dumb";
354
355   /* I've separated this out for later work on not calling tgetent at all
356      if the calling application has supplied a custom redisplay function,
357      (and possibly if the application has supplied a custom input function). */
358   if (CUSTOM_REDISPLAY_FUNC())
359     {
360       tgetent_ret = -1;
361     }
362   else
363     {
364       if (term_string_buffer == 0)
365         term_string_buffer = xmalloc(2032);
366
367       if (term_buffer == 0)
368         term_buffer = xmalloc(4080);
369
370       buffer = term_string_buffer;
371
372       tgetent_ret = tgetent (term_buffer, term);
373     }
374
375   if (tgetent_ret <= 0)
376     {
377       FREE (term_string_buffer);
378       FREE (term_buffer);
379       buffer = term_buffer = term_string_buffer = (char *)NULL;
380
381       _rl_term_autowrap = 0;    /* used by _rl_get_screen_size */
382
383 #if defined (__EMX__)
384       _emx_get_screensize (&_rl_screenwidth, &_rl_screenheight);
385       _rl_screenwidth--;
386 #else /* !__EMX__ */
387       _rl_get_screen_size (tty, 0);
388 #endif /* !__EMX__ */
389
390       /* Defaults. */
391       if (_rl_screenwidth <= 0 || _rl_screenheight <= 0)
392         {
393           _rl_screenwidth = 79;
394           _rl_screenheight = 24;
395         }
396
397       /* Everything below here is used by the redisplay code (tputs). */
398       _rl_screenchars = _rl_screenwidth * _rl_screenheight;
399       _rl_term_cr = "\r";
400       _rl_term_im = _rl_term_ei = _rl_term_ic = _rl_term_IC = (char *)NULL;
401       _rl_term_up = _rl_term_dc = _rl_term_DC = _rl_visible_bell = (char *)NULL;
402       _rl_term_ku = _rl_term_kd = _rl_term_kl = _rl_term_kr = (char *)NULL;
403       _rl_term_mm = _rl_term_mo = (char *)NULL;
404 #if defined (HACK_TERMCAP_MOTION)
405       term_forward_char = (char *)NULL;
406 #endif
407       _rl_terminal_can_insert = term_has_meta = 0;
408
409       /* Reasonable defaults for tgoto().  Readline currently only uses
410          tgoto if _rl_term_IC or _rl_term_DC is defined, but just in case we
411          change that later... */
412       PC = '\0';
413       BC = _rl_term_backspace = "\b";
414       UP = _rl_term_up;
415
416       return 0;
417     }
418
419   get_term_capabilities (&buffer);
420
421   /* Set up the variables that the termcap library expects the application
422      to provide. */
423   PC = _rl_term_pc ? *_rl_term_pc : 0;
424   BC = _rl_term_backspace;
425   UP = _rl_term_up;
426
427   if (!_rl_term_cr)
428     _rl_term_cr = "\r";
429
430   _rl_term_autowrap = tgetflag ("am") && tgetflag ("xn");
431
432   _rl_get_screen_size (tty, 0);
433
434   /* "An application program can assume that the terminal can do
435       character insertion if *any one of* the capabilities `IC',
436       `im', `ic' or `ip' is provided."  But we can't do anything if
437       only `ip' is provided, so... */
438   _rl_terminal_can_insert = (_rl_term_IC || _rl_term_im || _rl_term_ic);
439
440   /* Check to see if this terminal has a meta key and clear the capability
441      variables if there is none. */
442   term_has_meta = (tgetflag ("km") || tgetflag ("MT"));
443   if (!term_has_meta)
444     _rl_term_mm = _rl_term_mo = (char *)NULL;
445
446   /* Attempt to find and bind the arrow keys.  Do not override already
447      bound keys in an overzealous attempt, however. */
448   xkeymap = _rl_keymap;
449
450   _rl_keymap = emacs_standard_keymap;
451   _rl_bind_if_unbound (_rl_term_ku, rl_get_previous_history);
452   _rl_bind_if_unbound (_rl_term_kd, rl_get_next_history);
453   _rl_bind_if_unbound (_rl_term_kr, rl_forward);
454   _rl_bind_if_unbound (_rl_term_kl, rl_backward);
455
456   _rl_bind_if_unbound (_rl_term_kh, rl_beg_of_line);    /* Home */
457   _rl_bind_if_unbound (_rl_term_kH, rl_end_of_line);    /* End */
458
459 #if defined (VI_MODE)
460   _rl_keymap = vi_movement_keymap;
461   _rl_bind_if_unbound (_rl_term_ku, rl_get_previous_history);
462   _rl_bind_if_unbound (_rl_term_kd, rl_get_next_history);
463   _rl_bind_if_unbound (_rl_term_kr, rl_forward);
464   _rl_bind_if_unbound (_rl_term_kl, rl_backward);
465
466   _rl_bind_if_unbound (_rl_term_kh, rl_beg_of_line);    /* Home */
467   _rl_bind_if_unbound (_rl_term_kH, rl_end_of_line);    /* End */
468 #endif /* VI_MODE */
469
470   _rl_keymap = xkeymap;
471
472   return 0;
473 }
474
475 char *
476 rl_get_termcap (cap)
477      const char *cap;
478 {
479   register int i;
480
481   if (tcap_initialized == 0)
482     return ((char *)NULL);
483   for (i = 0; i < NUM_TC_STRINGS; i++)
484     {
485       if (tc_strings[i].tc_var[0] == cap[0] && strcmp (tc_strings[i].tc_var, cap) == 0)
486         return *(tc_strings[i].tc_value);
487     }
488   return ((char *)NULL);
489 }
490
491 /* Re-initialize the terminal considering that the TERM/TERMCAP variable
492    has changed. */
493 int
494 rl_reset_terminal (terminal_name)
495      const char *terminal_name;
496 {
497   _rl_init_terminal_io (terminal_name);
498   return 0;
499 }
500
501 /* A function for the use of tputs () */
502 #ifdef _MINIX
503 void
504 _rl_output_character_function (c)
505      int c;
506 {
507   putc (c, _rl_out_stream);
508 }
509 #else /* !_MINIX */
510 int
511 _rl_output_character_function (c)
512      int c;
513 {
514   return putc (c, _rl_out_stream);
515 }
516 #endif /* !_MINIX */
517
518 /* Write COUNT characters from STRING to the output stream. */
519 void
520 _rl_output_some_chars (string, count)
521      const char *string;
522      int count;
523 {
524   fwrite (string, 1, count, _rl_out_stream);
525 }
526
527 /* Move the cursor back. */
528 int
529 _rl_backspace (count)
530      int count;
531 {
532   register int i;
533
534   if (_rl_term_backspace)
535     for (i = 0; i < count; i++)
536       tputs (_rl_term_backspace, 1, _rl_output_character_function);
537   else
538     for (i = 0; i < count; i++)
539       putc ('\b', _rl_out_stream);
540   return 0;
541 }
542
543 /* Move to the start of the next line. */
544 int
545 rl_crlf ()
546 {
547 #if defined (NEW_TTY_DRIVER)
548   if (_rl_term_cr)
549     tputs (_rl_term_cr, 1, _rl_output_character_function);
550 #endif /* NEW_TTY_DRIVER */
551   putc ('\n', _rl_out_stream);
552   return 0;
553 }
554
555 /* Ring the terminal bell. */
556 int
557 rl_ding ()
558 {
559   if (readline_echoing_p)
560     {
561       switch (_rl_bell_preference)
562         {
563         case NO_BELL:
564         default:
565           break;
566         case VISIBLE_BELL:
567           if (_rl_visible_bell)
568             {
569               tputs (_rl_visible_bell, 1, _rl_output_character_function);
570               break;
571             }
572           /* FALLTHROUGH */
573         case AUDIBLE_BELL:
574           fprintf (stderr, "\007");
575           fflush (stderr);
576           break;
577         }
578       return (0);
579     }
580   return (-1);
581 }
582
583 /* **************************************************************** */
584 /*                                                                  */
585 /*              Controlling the Meta Key and Keypad                 */
586 /*                                                                  */
587 /* **************************************************************** */
588
589 void
590 _rl_enable_meta_key ()
591 {
592 #if !defined (__DJGPP__)
593   if (term_has_meta && _rl_term_mm)
594     tputs (_rl_term_mm, 1, _rl_output_character_function);
595 #endif
596 }
597
598 void
599 _rl_control_keypad (on)
600      int on;
601 {
602 #if !defined (__DJGPP__)
603   if (on && _rl_term_ks)
604     tputs (_rl_term_ks, 1, _rl_output_character_function);
605   else if (!on && _rl_term_ke)
606     tputs (_rl_term_ke, 1, _rl_output_character_function);
607 #endif
608 }