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