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