1 /* terminal.c -- controlling the terminal with termcap. */
3 /* Copyright (C) 1996 Free Software Foundation, Inc.
5 This file is part of the GNU Readline Library, a library for
6 reading lines of text with interactive input and history editing.
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.
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.
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
24 #if defined (HAVE_CONFIG_H)
28 #include <sys/types.h>
29 #include "posixstat.h"
31 #if defined (HAVE_SYS_FILE_H)
32 # include <sys/file.h>
33 #endif /* HAVE_SYS_FILE_H */
35 #if defined (HAVE_UNISTD_H)
37 #endif /* HAVE_UNISTD_H */
39 #if defined (HAVE_STDLIB_H)
42 # include "ansi_stdlib.h"
43 #endif /* HAVE_STDLIB_H */
45 #if defined (HAVE_LOCALE_H)
51 /* System-specific feature definitions and include files. */
54 #if defined (GWINSZ_IN_SYS_IOCTL) && !defined (TIOCGWINSZ)
55 # include <sys/ioctl.h>
56 #endif /* GWINSZ_IN_SYS_IOCTL && !TIOCGWINSZ */
65 /* Some standard library routines. */
69 #include "rlprivate.h"
73 #define CUSTOM_REDISPLAY_FUNC() (rl_redisplay_function != rl_redisplay)
74 #define CUSTOM_INPUT_FUNC() (rl_getc_function != rl_getc)
76 /* **************************************************************** */
78 /* Terminal and Termcap */
80 /* **************************************************************** */
83 static char *term_buffer
= (char *)NULL
;
84 static char *term_string_buffer
= (char *)NULL
;
86 /* Non-zero means this terminal can't really do anything. */
88 #endif /* !__MSDOS__ */
90 static int tcap_initialized
;
92 #if !defined (__linux__)
93 # if defined (__EMX__) || defined (NEED_EXTERN_PC)
95 # endif /* __EMX__ || NEED_EXTERN_PC */
97 #endif /* __linux__ */
99 /* Some strings to control terminal actions. These are output by tputs (). */
100 char *_rl_term_clreol
;
101 char *_rl_term_clrpag
;
103 char *_rl_term_backspace
;
107 /* Non-zero if we determine that the terminal can do character insertion. */
108 int _rl_terminal_can_insert
= 0;
110 /* How to insert characters. */
117 /* How to delete characters. */
121 #if defined (HACK_TERMCAP_MOTION)
122 char *_rl_term_forward_char
;
123 #endif /* HACK_TERMCAP_MOTION */
125 /* How to go up a line. */
128 /* A visible bell; char if the terminal can be made to flash the screen. */
129 static char *_rl_visible_bell
;
131 /* Non-zero means the terminal can auto-wrap lines. */
132 int _rl_term_autowrap
;
134 /* Non-zero means that this terminal has a meta key. */
135 static int term_has_meta
;
137 /* The sequences to write to turn on and off the meta key, if this
139 static char *_rl_term_mm
;
140 static char *_rl_term_mo
;
142 /* The key sequences output by the arrow keys, if this terminal has any. */
143 static char *_rl_term_ku
;
144 static char *_rl_term_kd
;
145 static char *_rl_term_kr
;
146 static char *_rl_term_kl
;
148 /* How to initialize and reset the arrow keys, if this terminal has any. */
149 static char *_rl_term_ks
;
150 static char *_rl_term_ke
;
152 /* The key sequences sent by the Home and End keys, if any. */
153 static char *_rl_term_kh
;
154 static char *_rl_term_kH
;
155 static char *_rl_term_at7
; /* @7 */
158 static char *_rl_term_kI
;
161 static char *_rl_term_vs
; /* very visible */
162 static char *_rl_term_ve
; /* normal */
164 static void bind_termcap_arrow_keys
PARAMS((Keymap
));
166 /* Variables that hold the screen dimensions, used by the display code. */
167 int _rl_screenwidth
, _rl_screenheight
, _rl_screenchars
;
169 /* Non-zero means the user wants to enable the keypad. */
170 int _rl_enable_keypad
;
172 /* Non-zero means the user wants to enable a meta key. */
173 int _rl_enable_meta
= 1;
175 #if defined (__EMX__)
177 _emx_get_screensize (swp
, shp
)
191 /* Get readline's idea of the screen size. TTY is a file descriptor open
192 to the terminal. If IGNORE_ENV is true, we do not pay attention to the
193 values of $LINES and $COLUMNS. The tests for TERM_STRING_BUFFER being
194 non-null serve to check whether or not we have initialized termcap. */
196 _rl_get_screen_size (tty
, ignore_env
)
200 #if defined (TIOCGWINSZ)
201 struct winsize window_size
;
202 #endif /* TIOCGWINSZ */
204 #if defined (TIOCGWINSZ)
205 if (ioctl (tty
, TIOCGWINSZ
, &window_size
) == 0)
207 _rl_screenwidth
= (int) window_size
.ws_col
;
208 _rl_screenheight
= (int) window_size
.ws_row
;
210 #endif /* TIOCGWINSZ */
212 #if defined (__EMX__)
213 _emx_get_screensize (&_rl_screenwidth
, &_rl_screenheight
);
216 /* Environment variable COLUMNS overrides setting of "co" if IGNORE_ENV
218 if (_rl_screenwidth
<= 0)
220 if (ignore_env
== 0 && (ss
= sh_get_env_value ("COLUMNS")))
221 _rl_screenwidth
= atoi (ss
);
223 #if defined (__DJGPP__)
224 if (_rl_screenwidth
<= 0)
225 _rl_screenwidth
= ScreenCols ();
227 if (_rl_screenwidth
<= 0 && term_string_buffer
)
228 _rl_screenwidth
= tgetnum ("co");
232 /* Environment variable LINES overrides setting of "li" if IGNORE_ENV
234 if (_rl_screenheight
<= 0)
236 if (ignore_env
== 0 && (ss
= sh_get_env_value ("LINES")))
237 _rl_screenheight
= atoi (ss
);
239 #if defined (__DJGPP__)
240 if (_rl_screenheight
<= 0)
241 _rl_screenheight
= ScreenRows ();
243 if (_rl_screenheight
<= 0 && term_string_buffer
)
244 _rl_screenheight
= tgetnum ("li");
248 /* If all else fails, default to 80x24 terminal. */
249 if (_rl_screenwidth
<= 1)
250 _rl_screenwidth
= 80;
252 if (_rl_screenheight
<= 0)
253 _rl_screenheight
= 24;
255 /* If we're being compiled as part of bash, set the environment
256 variables $LINES and $COLUMNS to new values. Otherwise, just
257 do a pair of putenv () or setenv () calls. */
258 sh_set_lines_and_columns (_rl_screenheight
, _rl_screenwidth
);
260 if (_rl_term_autowrap
== 0)
263 _rl_screenchars
= _rl_screenwidth
* _rl_screenheight
;
267 _rl_set_screen_size (rows
, cols
)
270 if (rows
== 0 || cols
== 0)
273 _rl_screenheight
= rows
;
274 _rl_screenwidth
= cols
;
276 if (_rl_term_autowrap
== 0)
279 _rl_screenchars
= _rl_screenwidth
* _rl_screenheight
;
283 rl_set_screen_size (rows
, cols
)
286 _rl_set_screen_size (rows
, cols
);
290 rl_get_screen_size (rows
, cols
)
294 *rows
= _rl_screenheight
;
296 *cols
= _rl_screenwidth
;
300 rl_resize_terminal ()
302 if (readline_echoing_p
)
304 _rl_get_screen_size (fileno (rl_instream
), 1);
305 if (CUSTOM_REDISPLAY_FUNC ())
306 rl_forced_update_display ();
308 _rl_redisplay_after_sigwinch ();
317 /* This should be kept sorted, just in case we decide to change the
318 search algorithm to something smarter. */
319 static struct _tc_string tc_strings
[] =
321 { "@7", &_rl_term_at7
},
322 { "DC", &_rl_term_DC
},
323 { "IC", &_rl_term_IC
},
324 { "ce", &_rl_term_clreol
},
325 { "cl", &_rl_term_clrpag
},
326 { "cr", &_rl_term_cr
},
327 { "dc", &_rl_term_dc
},
328 { "ei", &_rl_term_ei
},
329 { "ic", &_rl_term_ic
},
330 { "im", &_rl_term_im
},
331 { "kH", &_rl_term_kH
}, /* home down ?? */
332 { "kI", &_rl_term_kI
}, /* insert */
333 { "kd", &_rl_term_kd
},
334 { "ke", &_rl_term_ke
}, /* end keypad mode */
335 { "kh", &_rl_term_kh
}, /* home */
336 { "kl", &_rl_term_kl
},
337 { "kr", &_rl_term_kr
},
338 { "ks", &_rl_term_ks
}, /* start keypad mode */
339 { "ku", &_rl_term_ku
},
340 { "le", &_rl_term_backspace
},
341 { "mm", &_rl_term_mm
},
342 { "mo", &_rl_term_mo
},
343 #if defined (HACK_TERMCAP_MOTION)
344 { "nd", &_rl_term_forward_char
},
346 { "pc", &_rl_term_pc
},
347 { "up", &_rl_term_up
},
348 { "vb", &_rl_visible_bell
},
349 { "vs", &_rl_term_vs
},
350 { "ve", &_rl_term_ve
},
353 #define NUM_TC_STRINGS (sizeof (tc_strings) / sizeof (struct _tc_string))
355 /* Read the desired terminal capability strings into BP. The capabilities
356 are described in the TC_STRINGS table. */
358 get_term_capabilities (bp
)
361 #if !defined (__DJGPP__) /* XXX - doesn't DJGPP have a termcap library? */
364 for (i
= 0; i
< NUM_TC_STRINGS
; i
++)
366 *(tc_strings
[i
].tc_value
) = tgetstr ((char *)tc_strings
[i
].tc_var
, bp
);
368 *(tc_strings
[i
].tc_value
) = tgetstr (tc_strings
[i
].tc_var
, bp
);
371 tcap_initialized
= 1;
375 _rl_init_terminal_io (terminal_name
)
376 const char *terminal_name
;
380 int tty
, tgetent_ret
;
382 term
= terminal_name
? terminal_name
: sh_get_env_value ("TERM");
383 _rl_term_clrpag
= _rl_term_cr
= _rl_term_clreol
= (char *)NULL
;
384 tty
= rl_instream
? fileno (rl_instream
) : 0;
385 _rl_screenwidth
= _rl_screenheight
= 0;
391 _rl_term_im
= _rl_term_ei
= _rl_term_ic
= _rl_term_IC
= (char *)NULL
;
392 _rl_term_up
= _rl_term_dc
= _rl_term_DC
= _rl_visible_bell
= (char *)NULL
;
393 _rl_term_ku
= _rl_term_kd
= _rl_term_kl
= _rl_term_kr
= (char *)NULL
;
394 _rl_term_mm
= _rl_term_mo
= (char *)NULL
;
395 _rl_terminal_can_insert
= term_has_meta
= _rl_term_autowrap
= 0;
397 _rl_term_clreol
= _rl_term_clrpag
= _rl_term_backspace
= (char *)NULL
;
398 _rl_term_goto
= _rl_term_pc
= _rl_term_ip
= (char *)NULL
;
399 _rl_term_ks
= _rl_term_ke
=_rl_term_vs
= _rl_term_ve
= (char *)NULL
;
400 _rl_term_kh
= _rl_term_kH
= _rl_term_at7
= _rl_term_kI
= (char *)NULL
;
401 #if defined(HACK_TERMCAP_MOTION)
402 _rl_term_forward_char
= (char *)NULL
;
405 _rl_get_screen_size (tty
, 0);
406 #else /* !__MSDOS__ */
407 /* I've separated this out for later work on not calling tgetent at all
408 if the calling application has supplied a custom redisplay function,
409 (and possibly if the application has supplied a custom input function). */
410 if (CUSTOM_REDISPLAY_FUNC())
416 if (term_string_buffer
== 0)
417 term_string_buffer
= (char *)xmalloc(2032);
419 if (term_buffer
== 0)
420 term_buffer
= (char *)xmalloc(4080);
422 buffer
= term_string_buffer
;
424 tgetent_ret
= tgetent (term_buffer
, term
);
427 if (tgetent_ret
<= 0)
429 FREE (term_string_buffer
);
431 buffer
= term_buffer
= term_string_buffer
= (char *)NULL
;
433 _rl_term_autowrap
= 0; /* used by _rl_get_screen_size */
435 #if defined (__EMX__)
436 _emx_get_screensize (&_rl_screenwidth
, &_rl_screenheight
);
439 _rl_get_screen_size (tty
, 0);
440 #endif /* !__EMX__ */
443 if (_rl_screenwidth
<= 0 || _rl_screenheight
<= 0)
445 _rl_screenwidth
= 79;
446 _rl_screenheight
= 24;
449 /* Everything below here is used by the redisplay code (tputs). */
450 _rl_screenchars
= _rl_screenwidth
* _rl_screenheight
;
452 _rl_term_im
= _rl_term_ei
= _rl_term_ic
= _rl_term_IC
= (char *)NULL
;
453 _rl_term_up
= _rl_term_dc
= _rl_term_DC
= _rl_visible_bell
= (char *)NULL
;
454 _rl_term_ku
= _rl_term_kd
= _rl_term_kl
= _rl_term_kr
= (char *)NULL
;
455 _rl_term_kh
= _rl_term_kH
= _rl_term_kI
= (char *)NULL
;
456 _rl_term_ks
= _rl_term_ke
= _rl_term_at7
= (char *)NULL
;
457 _rl_term_mm
= _rl_term_mo
= (char *)NULL
;
458 _rl_term_ve
= _rl_term_vs
= (char *)NULL
;
459 #if defined (HACK_TERMCAP_MOTION)
460 term_forward_char
= (char *)NULL
;
462 _rl_terminal_can_insert
= term_has_meta
= 0;
464 /* Reasonable defaults for tgoto(). Readline currently only uses
465 tgoto if _rl_term_IC or _rl_term_DC is defined, but just in case we
466 change that later... */
468 BC
= _rl_term_backspace
= "\b";
474 get_term_capabilities (&buffer
);
476 /* Set up the variables that the termcap library expects the application
478 PC
= _rl_term_pc
? *_rl_term_pc
: 0;
479 BC
= _rl_term_backspace
;
485 _rl_term_autowrap
= tgetflag ("am") && tgetflag ("xn");
487 _rl_get_screen_size (tty
, 0);
489 /* "An application program can assume that the terminal can do
490 character insertion if *any one of* the capabilities `IC',
491 `im', `ic' or `ip' is provided." But we can't do anything if
492 only `ip' is provided, so... */
493 _rl_terminal_can_insert
= (_rl_term_IC
|| _rl_term_im
|| _rl_term_ic
);
495 /* Check to see if this terminal has a meta key and clear the capability
496 variables if there is none. */
497 term_has_meta
= (tgetflag ("km") || tgetflag ("MT"));
499 _rl_term_mm
= _rl_term_mo
= (char *)NULL
;
501 #endif /* !__MSDOS__ */
503 /* Attempt to find and bind the arrow keys. Do not override already
504 bound keys in an overzealous attempt, however. */
506 bind_termcap_arrow_keys (emacs_standard_keymap
);
508 #if defined (VI_MODE)
509 bind_termcap_arrow_keys (vi_movement_keymap
);
510 bind_termcap_arrow_keys (vi_insertion_keymap
);
516 /* Bind the arrow key sequences from the termcap description in MAP. */
518 bind_termcap_arrow_keys (map
)
523 xkeymap
= _rl_keymap
;
526 _rl_bind_if_unbound (_rl_term_ku
, rl_get_previous_history
);
527 _rl_bind_if_unbound (_rl_term_kd
, rl_get_next_history
);
528 _rl_bind_if_unbound (_rl_term_kr
, rl_forward
);
529 _rl_bind_if_unbound (_rl_term_kl
, rl_backward
);
531 _rl_bind_if_unbound (_rl_term_kh
, rl_beg_of_line
); /* Home */
532 _rl_bind_if_unbound (_rl_term_at7
, rl_end_of_line
); /* End */
534 _rl_keymap
= xkeymap
;
543 if (tcap_initialized
== 0)
544 return ((char *)NULL
);
545 for (i
= 0; i
< NUM_TC_STRINGS
; i
++)
547 if (tc_strings
[i
].tc_var
[0] == cap
[0] && strcmp (tc_strings
[i
].tc_var
, cap
) == 0)
548 return *(tc_strings
[i
].tc_value
);
550 return ((char *)NULL
);
553 /* Re-initialize the terminal considering that the TERM/TERMCAP variable
556 rl_reset_terminal (terminal_name
)
557 const char *terminal_name
;
559 _rl_init_terminal_io (terminal_name
);
563 /* A function for the use of tputs () */
566 _rl_output_character_function (c
)
569 putc (c
, _rl_out_stream
);
573 _rl_output_character_function (c
)
576 return putc (c
, _rl_out_stream
);
580 /* Write COUNT characters from STRING to the output stream. */
582 _rl_output_some_chars (string
, count
)
586 fwrite (string
, 1, count
, _rl_out_stream
);
589 /* Move the cursor back. */
591 _rl_backspace (count
)
597 if (_rl_term_backspace
)
598 for (i
= 0; i
< count
; i
++)
599 tputs (_rl_term_backspace
, 1, _rl_output_character_function
);
602 for (i
= 0; i
< count
; i
++)
603 putc ('\b', _rl_out_stream
);
607 /* Move to the start of the next line. */
611 #if defined (NEW_TTY_DRIVER)
613 tputs (_rl_term_cr
, 1, _rl_output_character_function
);
614 #endif /* NEW_TTY_DRIVER */
615 putc ('\n', _rl_out_stream
);
619 /* Ring the terminal bell. */
623 if (readline_echoing_p
)
625 switch (_rl_bell_preference
)
635 if (_rl_visible_bell
)
637 tputs (_rl_visible_bell
, 1, _rl_output_character_function
);
643 fprintf (stderr
, "\007");
652 /* **************************************************************** */
654 /* Controlling the Meta Key and Keypad */
656 /* **************************************************************** */
659 _rl_enable_meta_key ()
661 #if !defined (__DJGPP__)
662 if (term_has_meta
&& _rl_term_mm
)
663 tputs (_rl_term_mm
, 1, _rl_output_character_function
);
668 _rl_control_keypad (on
)
671 #if !defined (__DJGPP__)
672 if (on
&& _rl_term_ks
)
673 tputs (_rl_term_ks
, 1, _rl_output_character_function
);
674 else if (!on
&& _rl_term_ke
)
675 tputs (_rl_term_ke
, 1, _rl_output_character_function
);
679 /* **************************************************************** */
681 /* Controlling the Cursor */
683 /* **************************************************************** */
685 /* Set the cursor appropriately depending on IM, which is one of the
686 insert modes (insert or overwrite). Insert mode gets the normal
687 cursor. Overwrite mode gets a very visible cursor. Only does
688 anything if we have both capabilities. */
690 _rl_set_cursor (im
, force
)
694 if (_rl_term_ve
&& _rl_term_vs
)
696 if (force
|| im
!= rl_insert_mode
)
698 if (im
== RL_IM_OVERWRITE
)
699 tputs (_rl_term_vs
, 1, _rl_output_character_function
);
701 tputs (_rl_term_ve
, 1, _rl_output_character_function
);