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