source: trunk/essentials/app-shells/bash/lib/readline/terminal.c

Last change on this file was 3241, checked in by bird, 18 years ago

Applied bash31-006

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