]> git.ipfire.org Git - thirdparty/bash.git/blob - lib/readline/terminal.c
Imported from ../bash-2.0.tar.gz.
[thirdparty/bash.git] / lib / readline / 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 1, 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 675 Mass Ave, Cambridge, MA 02139, 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 <signal.h>
50 #include <stdio.h>
51 #include <setjmp.h>
52
53 /* System-specific feature definitions and include files. */
54 #include "rldefs.h"
55
56 #include "tcap.h"
57
58 #if defined (GWINSZ_IN_SYS_IOCTL)
59 # include <sys/ioctl.h>
60 #endif /* GWINSZ_IN_SYS_IOCTL */
61
62 /* Some standard library routines. */
63 #include "readline.h"
64 #include "history.h"
65
66 /* Variables and functions imported from readline.c */
67 extern FILE *_rl_in_stream, *_rl_out_stream;
68 extern int readline_echoing_p;
69 extern int _rl_bell_preference;
70 extern Keymap _rl_keymap;
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 /* Non-zero means this terminal can't really do anything. */
84 static int dumb_term;
85
86 #if !defined (__linux__)
87 /* If this causes problems, add back the `extern'. */
88 /*extern*/ 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 /* Re-initialize the terminal considering that the TERM/TERMCAP variable
143 has changed. */
144 int
145 rl_reset_terminal (terminal_name)
146 char *terminal_name;
147 {
148 _rl_init_terminal_io (terminal_name);
149 return 0;
150 }
151
152 #if !defined (SHELL)
153 static void
154 set_lines_and_columns (lines, cols)
155 int lines, cols;
156 {
157 char *b;
158
159 #if defined (HAVE_PUTENV)
160 b = xmalloc (24);
161 sprintf (b, "LINES=%d", lines);
162 putenv (b);
163 b = xmalloc (24);
164 sprintf (b, "COLUMNS=%d", cols);
165 putenv (b);
166 #else /* !HAVE_PUTENV */
167 # if defined (HAVE_SETENV)
168 b = xmalloc (8);
169 sprintf (b, "%d", lines);
170 setenv ("LINES", b, 1);
171 b = xmalloc (8);
172 sprintf (b, "%d", cols);
173 setenv ("COLUMNS", b, 1);
174 # endif /* HAVE_SETENV */
175 #endif /* !HAVE_PUTENV */
176 }
177 #else /* SHELL */
178 extern void set_lines_and_columns ();
179 #endif /* SHELL */
180
181 /* Get readline's idea of the screen size. TTY is a file descriptor open
182 to the terminal. If IGNORE_ENV is true, we do not pay attention to the
183 values of $LINES and $COLUMNS. The tests for TERM_STRING_BUFFER being
184 non-null serve to check whether or not we have initialized termcap. */
185 void
186 _rl_get_screen_size (tty, ignore_env)
187 int tty, ignore_env;
188 {
189 char *ss;
190 #if defined (TIOCGWINSZ)
191 struct winsize window_size;
192 #endif /* TIOCGWINSZ */
193
194 #if defined (TIOCGWINSZ)
195 if (ioctl (tty, TIOCGWINSZ, &window_size) == 0)
196 {
197 screenwidth = (int) window_size.ws_col;
198 screenheight = (int) window_size.ws_row;
199 }
200 #endif /* TIOCGWINSZ */
201
202 /* Environment variable COLUMNS overrides setting of "co" if IGNORE_ENV
203 is unset. */
204 if (screenwidth <= 0)
205 {
206 if (ignore_env == 0 && (ss = getenv ("COLUMNS")))
207 screenwidth = atoi (ss);
208
209 if (screenwidth <= 0 && term_string_buffer)
210 screenwidth = tgetnum ("co");
211 }
212
213 /* Environment variable LINES overrides setting of "li" if IGNORE_ENV
214 is unset. */
215 if (screenheight <= 0)
216 {
217 if (ignore_env == 0 && (ss = getenv ("LINES")))
218 screenheight = atoi (ss);
219
220 if (screenheight <= 0 && term_string_buffer)
221 screenheight = tgetnum ("li");
222 }
223
224 /* If all else fails, default to 80x24 terminal. */
225 if (screenwidth <= 1)
226 screenwidth = 80;
227
228 if (screenheight <= 0)
229 screenheight = 24;
230
231 /* If we're being compiled as part of bash, set the environment
232 variables $LINES and $COLUMNS to new values. Otherwise, just
233 do a pair of putenv () or setenv () calls. */
234 set_lines_and_columns (screenheight, screenwidth);
235
236 if (!_rl_term_autowrap)
237 screenwidth--;
238
239 screenchars = screenwidth * screenheight;
240 }
241
242 void
243 _rl_set_screen_size (rows, cols)
244 int rows, cols;
245 {
246 screenheight = rows;
247 screenwidth = cols;
248
249 if (_rl_term_autowrap == 0)
250 screenwidth--;
251
252 screenchars = screenwidth * screenheight;
253 }
254
255 struct _tc_string {
256 char *tc_var;
257 char **tc_value;
258 };
259
260 /* This should be kept sorted, just in case we decide to change the
261 search algorithm to something smarter. */
262 static struct _tc_string tc_strings[] =
263 {
264 "DC", &term_DC,
265 "IC", &term_IC,
266 "ce", &term_clreol,
267 "cl", &term_clrpag,
268 "cr", &term_cr,
269 "dc", &term_dc,
270 "ei", &term_ei,
271 "ic", &term_ic,
272 "im", &term_im,
273 "kd", &term_kd,
274 "kh", &term_kh, /* home */
275 "kH", &term_kH, /* end */
276 "kl", &term_kl,
277 "kr", &term_kr,
278 "ku", &term_ku,
279 "ks", &term_ks,
280 "ke", &term_ke,
281 "le", &term_backspace,
282 "mm", &term_mm,
283 "mo", &term_mo,
284 #if defined (HACK_TERMCAP_MOTION)
285 "nd", &term_forward_char,
286 #endif
287 "pc", &term_pc,
288 "up", &term_up,
289 "vb", &visible_bell,
290 };
291
292 #define NUM_TC_STRINGS (sizeof (tc_strings) / sizeof (struct _tc_string))
293
294 /* Read the desired terminal capability strings into BP. The capabilities
295 are described in the TC_STRINGS table. */
296 static void
297 get_term_capabilities (bp)
298 char **bp;
299 {
300 register int i;
301
302 for (i = 0; i < NUM_TC_STRINGS; i++)
303 *(tc_strings[i].tc_value) = tgetstr (tc_strings[i].tc_var, bp);
304 tcap_initialized = 1;
305 }
306
307 int
308 _rl_init_terminal_io (terminal_name)
309 char *terminal_name;
310 {
311 #if defined (__GO32__)
312 screenwidth = ScreenCols ();
313 screenheight = ScreenRows ();
314 screenchars = screenwidth * screenheight;
315 term_cr = "\r";
316 term_im = term_ei = term_ic = term_IC = (char *)NULL;
317 term_up = term_dc = term_DC = visible_bell = (char *)NULL;
318
319 /* Does the __GO32__ have a meta key? I don't know. */
320 term_has_meta = 0;
321 term_mm = term_mo = (char *)NULL;
322
323 /* It probably has arrow keys, but I don't know what they are. */
324 term_ku = term_kd = term_kr = term_kl = (char *)NULL;
325
326 #if defined (HACK_TERMCAP_MOTION)
327 term_forward_char = (char *)NULL;
328 #endif /* HACK_TERMCAP_MOTION */
329 terminal_can_insert = _rl_term_autowrap = 0;
330 return;
331 #else /* !__GO32__ */
332
333 char *term, *buffer;
334 int tty;
335 Keymap xkeymap;
336
337 term = terminal_name ? terminal_name : getenv ("TERM");
338
339 if (term_string_buffer == 0)
340 term_string_buffer = xmalloc (2032);
341
342 if (term_buffer == 0)
343 term_buffer = xmalloc (4080);
344
345 buffer = term_string_buffer;
346
347 term_clrpag = term_cr = term_clreol = (char *)NULL;
348
349 if (term == 0)
350 term = "dumb";
351
352 if (tgetent (term_buffer, term) <= 0)
353 {
354 dumb_term = 1;
355 screenwidth = 79;
356 screenheight = 24;
357 screenchars = 79 * 24;
358 term_cr = "\r";
359 term_im = term_ei = term_ic = term_IC = (char *)NULL;
360 term_up = term_dc = term_DC = visible_bell = (char *)NULL;
361 term_ku = term_kd = term_kl = term_kr = (char *)NULL;
362 #if defined (HACK_TERMCAP_MOTION)
363 term_forward_char = (char *)NULL;
364 #endif
365 terminal_can_insert = 0;
366 return 0;
367 }
368
369 get_term_capabilities (&buffer);
370
371 /* Set up the variables that the termcap library expects the application
372 to provide. */
373 PC = term_pc ? *term_pc : 0;
374 BC = term_backspace;
375 UP = term_up;
376
377 if (!term_cr)
378 term_cr = "\r";
379
380 tty = rl_instream ? fileno (rl_instream) : 0;
381
382 screenwidth = screenheight = 0;
383
384 _rl_term_autowrap = tgetflag ("am") && tgetflag ("xn");
385
386 _rl_get_screen_size (tty, 0);
387
388 /* "An application program can assume that the terminal can do
389 character insertion if *any one of* the capabilities `IC',
390 `im', `ic' or `ip' is provided." But we can't do anything if
391 only `ip' is provided, so... */
392 terminal_can_insert = (term_IC || term_im || term_ic);
393
394 /* Check to see if this terminal has a meta key and clear the capability
395 variables if there is none. */
396 term_has_meta = (tgetflag ("km") || tgetflag ("MT"));
397 if (!term_has_meta)
398 term_mm = term_mo = (char *)NULL;
399
400 /* Attempt to find and bind the arrow keys. Do not override already
401 bound keys in an overzealous attempt, however. */
402 xkeymap = _rl_keymap;
403
404 _rl_keymap = emacs_standard_keymap;
405 _rl_bind_if_unbound (term_ku, rl_get_previous_history);
406 _rl_bind_if_unbound (term_kd, rl_get_next_history);
407 _rl_bind_if_unbound (term_kr, rl_forward);
408 _rl_bind_if_unbound (term_kl, rl_backward);
409
410 _rl_bind_if_unbound (term_kh, rl_beg_of_line); /* Home */
411 _rl_bind_if_unbound (term_kH, rl_end_of_line); /* End */
412
413 #if defined (VI_MODE)
414 _rl_keymap = vi_movement_keymap;
415 _rl_bind_if_unbound (term_ku, rl_get_previous_history);
416 _rl_bind_if_unbound (term_kd, rl_get_next_history);
417 _rl_bind_if_unbound (term_kr, rl_forward);
418 _rl_bind_if_unbound (term_kl, rl_backward);
419
420 _rl_bind_if_unbound (term_kh, rl_beg_of_line); /* Home */
421 _rl_bind_if_unbound (term_kH, rl_end_of_line); /* End */
422 #endif /* VI_MODE */
423
424 _rl_keymap = xkeymap;
425
426 #endif /* !__GO32__ */
427 return 0;
428 }
429
430 char *
431 rl_get_termcap (cap)
432 char *cap;
433 {
434 register int i;
435
436 if (tcap_initialized == 0)
437 return ((char *)NULL);
438 for (i = 0; i < NUM_TC_STRINGS; i++)
439 {
440 if (tc_strings[i].tc_var[0] == cap[0] && strcmp (tc_strings[i].tc_var, cap) == 0)
441 return *(tc_strings[i].tc_value);
442 }
443 return ((char *)NULL);
444 }
445
446 /* A function for the use of tputs () */
447 int
448 _rl_output_character_function (c)
449 int c;
450 {
451 return putc (c, _rl_out_stream);
452 }
453
454 /* Write COUNT characters from STRING to the output stream. */
455 void
456 _rl_output_some_chars (string, count)
457 char *string;
458 int count;
459 {
460 fwrite (string, 1, count, _rl_out_stream);
461 }
462
463 /* Move the cursor back. */
464 int
465 _rl_backspace (count)
466 int count;
467 {
468 register int i;
469
470 #if !defined (__GO32__)
471 if (term_backspace)
472 for (i = 0; i < count; i++)
473 tputs (term_backspace, 1, _rl_output_character_function);
474 else
475 #endif /* !__GO32__ */
476 for (i = 0; i < count; i++)
477 putc ('\b', _rl_out_stream);
478 return 0;
479 }
480
481 /* Move to the start of the next line. */
482 int
483 crlf ()
484 {
485 #if defined (NEW_TTY_DRIVER)
486 if (term_cr)
487 tputs (term_cr, 1, _rl_output_character_function);
488 #endif /* NEW_TTY_DRIVER */
489 putc ('\n', _rl_out_stream);
490 return 0;
491 }
492
493 /* Ring the terminal bell. */
494 int
495 ding ()
496 {
497 if (readline_echoing_p)
498 {
499 #if !defined (__GO32__)
500 switch (_rl_bell_preference)
501 {
502 case NO_BELL:
503 default:
504 break;
505 case VISIBLE_BELL:
506 if (visible_bell)
507 {
508 tputs (visible_bell, 1, _rl_output_character_function);
509 break;
510 }
511 /* FALLTHROUGH */
512 case AUDIBLE_BELL:
513 fprintf (stderr, "\007");
514 fflush (stderr);
515 break;
516 }
517 #else /* __GO32__ */
518 fprintf (stderr, "\007");
519 fflush (stderr);
520 #endif /* __GO32__ */
521 return (0);
522 }
523 return (-1);
524 }
525
526 /* **************************************************************** */
527 /* */
528 /* Controlling the Meta Key and Keypad */
529 /* */
530 /* **************************************************************** */
531
532 static int
533 outchar (c)
534 int c;
535 {
536 return putc (c, rl_outstream);
537 }
538
539 int
540 _rl_enable_meta_key ()
541 {
542 if (term_has_meta && term_mm)
543 tputs (term_mm, 1, outchar);
544 }
545
546 void
547 _rl_control_keypad (on)
548 int on;
549 {
550 if (on && term_ks)
551 tputs (term_ks, 1, outchar);
552 else if (!on && term_ke)
553 tputs (term_ke, 1, outchar);
554 }