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