terminal.c revision 21308
1130561Sobrien/* terminal.c -- controlling the terminal with termcap. */ 2130561Sobrien 3130561Sobrien/* Copyright (C) 1996 Free Software Foundation, Inc. 4130561Sobrien 5130561Sobrien This file is part of the GNU Readline Library, a library for 6130561Sobrien reading lines of text with interactive input and history editing. 7130561Sobrien 8130561Sobrien The GNU Readline Library is free software; you can redistribute it 9130561Sobrien and/or modify it under the terms of the GNU General Public License 10130561Sobrien as published by the Free Software Foundation; either version 1, or 11130561Sobrien (at your option) any later version. 12130561Sobrien 13130561Sobrien The GNU Readline Library is distributed in the hope that it will be 14130561Sobrien useful, but WITHOUT ANY WARRANTY; without even the implied warranty 15130561Sobrien of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 16130561Sobrien GNU General Public License for more details. 17130561Sobrien 18218822Sdim The GNU General Public License is often shipped with GNU software, and 19130561Sobrien is generally kept in a file called COPYING or LICENSE. If you do not 20130561Sobrien have a copy of the license, write to the Free Software Foundation, 21130561Sobrien 675 Mass Ave, Cambridge, MA 02139, USA. */ 22130561Sobrien#define READLINE_LIBRARY 23130561Sobrien 24130561Sobrien#if defined (HAVE_CONFIG_H) 25130561Sobrien# include <config.h> 26130561Sobrien#endif 27130561Sobrien 28130561Sobrien#include <sys/types.h> 29130561Sobrien#include "posixstat.h" 30130561Sobrien#include <fcntl.h> 31130561Sobrien#if defined (HAVE_SYS_FILE_H) 32130561Sobrien# include <sys/file.h> 33130561Sobrien#endif /* HAVE_SYS_FILE_H */ 34130561Sobrien 35130561Sobrien#if defined (HAVE_UNISTD_H) 36130561Sobrien# include <unistd.h> 37130561Sobrien#endif /* HAVE_UNISTD_H */ 38130561Sobrien 39130561Sobrien#if defined (HAVE_STDLIB_H) 40130561Sobrien# include <stdlib.h> 41130561Sobrien#else 42130561Sobrien# include "ansi_stdlib.h" 43130561Sobrien#endif /* HAVE_STDLIB_H */ 44130561Sobrien 45130561Sobrien#if defined (HAVE_LOCALE_H) 46130561Sobrien# include <locale.h> 47130561Sobrien#endif 48130561Sobrien 49130561Sobrien#include <signal.h> 50130561Sobrien#include <stdio.h> 51130561Sobrien#include <setjmp.h> 52130561Sobrien 53130561Sobrien/* System-specific feature definitions and include files. */ 54130561Sobrien#include "rldefs.h" 55130561Sobrien 56130561Sobrien#include "tcap.h" 57130561Sobrien 58130561Sobrien#if defined (GWINSZ_IN_SYS_IOCTL) 59130561Sobrien# include <sys/ioctl.h> 60130561Sobrien#endif /* GWINSZ_IN_SYS_IOCTL */ 61130561Sobrien 62130561Sobrien/* Some standard library routines. */ 63130561Sobrien#include "readline.h" 64130561Sobrien#include "history.h" 65130561Sobrien 66130561Sobrien/* Variables and functions imported from readline.c */ 67130561Sobrienextern FILE *_rl_in_stream, *_rl_out_stream; 68130561Sobrienextern int readline_echoing_p; 69130561Sobrienextern int _rl_bell_preference; 70130561Sobrienextern Keymap _rl_keymap; 71130561Sobrien 72130561Sobrien/* **************************************************************** */ 73130561Sobrien/* */ 74130561Sobrien/* Terminal and Termcap */ 75130561Sobrien/* */ 76130561Sobrien/* **************************************************************** */ 77130561Sobrien 78130561Sobrienstatic char *term_buffer = (char *)NULL; 79130561Sobrienstatic char *term_string_buffer = (char *)NULL; 80130561Sobrien 81130561Sobrienstatic int tcap_initialized; 82130561Sobrien 83130561Sobrien/* Non-zero means this terminal can't really do anything. */ 84130561Sobrienstatic int dumb_term; 85130561Sobrien 86130561Sobrien#if !defined (__linux__) 87130561Sobrien/* If this causes problems, add back the `extern'. */ 88130561Sobrien/*extern*/ char PC, *BC, *UP; 89130561Sobrien#endif /* __linux__ */ 90130561Sobrien 91130561Sobrien/* Some strings to control terminal actions. These are output by tputs (). */ 92130561Sobrienchar *term_goto, *term_clreol, *term_cr, *term_clrpag, *term_backspace; 93130561Sobrienchar *term_pc; 94130561Sobrien 95130561Sobrien/* Non-zero if we determine that the terminal can do character insertion. */ 96130561Sobrienint terminal_can_insert = 0; 97130561Sobrien 98130561Sobrien/* How to insert characters. */ 99130561Sobrienchar *term_im, *term_ei, *term_ic, *term_ip, *term_IC; 100130561Sobrien 101130561Sobrien/* How to delete characters. */ 102130561Sobrienchar *term_dc, *term_DC; 103130561Sobrien 104130561Sobrien#if defined (HACK_TERMCAP_MOTION) 105130561Sobrienchar *term_forward_char; 106130561Sobrien#endif /* HACK_TERMCAP_MOTION */ 107130561Sobrien 108130561Sobrien/* How to go up a line. */ 109130561Sobrienchar *term_up; 110130561Sobrien 111130561Sobrien/* A visible bell, if the terminal can be made to flash the screen. */ 112130561Sobrienstatic char *visible_bell; 113130561Sobrien 114130561Sobrien/* Non-zero means the terminal can auto-wrap lines. */ 115130561Sobrienint _rl_term_autowrap; 116130561Sobrien 117130561Sobrien/* Non-zero means that this terminal has a meta key. */ 118130561Sobrienstatic int term_has_meta; 119130561Sobrien 120130561Sobrien/* The sequences to write to turn on and off the meta key, if this 121130561Sobrien terminal has one. */ 122130561Sobrienstatic char *term_mm, *term_mo; 123130561Sobrien 124130561Sobrien/* The key sequences output by the arrow keys, if this terminal has any. */ 125130561Sobrienstatic char *term_ku, *term_kd, *term_kr, *term_kl; 126130561Sobrien 127130561Sobrien/* How to initialize and reset the arrow keys, if this terminal has any. */ 128130561Sobrienstatic char *term_ks, *term_ke; 129130561Sobrien 130130561Sobrien/* The key sequences sent by the Home and End keys, if any. */ 131130561Sobrienstatic char *term_kh, *term_kH; 132130561Sobrien 133130561Sobrien/* Variables that hold the screen dimensions, used by the display code. */ 134130561Sobrienint screenwidth, screenheight, screenchars; 135130561Sobrien 136130561Sobrien/* Non-zero means the user wants to enable the keypad. */ 137130561Sobrienint _rl_enable_keypad; 138130561Sobrien 139130561Sobrien/* Non-zero means the user wants to enable a meta key. */ 140130561Sobrienint _rl_enable_meta = 1; 141130561Sobrien 142130561Sobrien/* Re-initialize the terminal considering that the TERM/TERMCAP variable 143130561Sobrien has changed. */ 144130561Sobrienint 145130561Sobrienrl_reset_terminal (terminal_name) 146130561Sobrien char *terminal_name; 147130561Sobrien{ 148130561Sobrien _rl_init_terminal_io (terminal_name); 149130561Sobrien return 0; 150130561Sobrien} 151130561Sobrien 152130561Sobrien#if !defined (SHELL) 153130561Sobrienstatic void 154130561Sobrienset_lines_and_columns (lines, cols) 155130561Sobrien int lines, cols; 156130561Sobrien{ 157130561Sobrien char *b; 158130561Sobrien 159130561Sobrien#if defined (HAVE_PUTENV) 160130561Sobrien b = xmalloc (24); 161130561Sobrien sprintf (b, "LINES=%d", lines); 162130561Sobrien putenv (b); 163130561Sobrien b = xmalloc (24); 164130561Sobrien sprintf (b, "COLUMNS=%d", cols); 165130561Sobrien putenv (b); 166130561Sobrien#else /* !HAVE_PUTENV */ 167130561Sobrien# if defined (HAVE_SETENV) 168130561Sobrien b = xmalloc (8); 169130561Sobrien sprintf (b, "%d", lines); 170130561Sobrien setenv ("LINES", b, 1); 171130561Sobrien b = xmalloc (8); 172130561Sobrien sprintf (b, "%d", cols); 173130561Sobrien setenv ("COLUMNS", b, 1); 174130561Sobrien# endif /* HAVE_SETENV */ 175130561Sobrien#endif /* !HAVE_PUTENV */ 176130561Sobrien} 177130561Sobrien#else /* SHELL */ 178130561Sobrienextern void set_lines_and_columns (); 179130561Sobrien#endif /* SHELL */ 180130561Sobrien 181130561Sobrien/* Get readline's idea of the screen size. TTY is a file descriptor open 182130561Sobrien to the terminal. If IGNORE_ENV is true, we do not pay attention to the 183130561Sobrien values of $LINES and $COLUMNS. The tests for TERM_STRING_BUFFER being 184130561Sobrien non-null serve to check whether or not we have initialized termcap. */ 185130561Sobrienvoid 186130561Sobrien_rl_get_screen_size (tty, ignore_env) 187130561Sobrien int tty, ignore_env; 188130561Sobrien{ 189130561Sobrien char *ss; 190130561Sobrien#if defined (TIOCGWINSZ) 191130561Sobrien struct winsize window_size; 192130561Sobrien#endif /* TIOCGWINSZ */ 193130561Sobrien 194130561Sobrien#if defined (TIOCGWINSZ) 195130561Sobrien if (ioctl (tty, TIOCGWINSZ, &window_size) == 0) 196130561Sobrien { 197130561Sobrien screenwidth = (int) window_size.ws_col; 198130561Sobrien screenheight = (int) window_size.ws_row; 199130561Sobrien } 200130561Sobrien#endif /* TIOCGWINSZ */ 201130561Sobrien 202130561Sobrien /* Environment variable COLUMNS overrides setting of "co" if IGNORE_ENV 203130561Sobrien is unset. */ 204130561Sobrien if (screenwidth <= 0) 205130561Sobrien { 206130561Sobrien if (ignore_env == 0 && (ss = getenv ("COLUMNS"))) 207130561Sobrien screenwidth = atoi (ss); 208130561Sobrien 209130561Sobrien if (screenwidth <= 0 && term_string_buffer) 210130561Sobrien screenwidth = tgetnum ("co"); 211130561Sobrien } 212130561Sobrien 213130561Sobrien /* Environment variable LINES overrides setting of "li" if IGNORE_ENV 214130561Sobrien is unset. */ 215130561Sobrien if (screenheight <= 0) 216130561Sobrien { 217130561Sobrien if (ignore_env == 0 && (ss = getenv ("LINES"))) 218130561Sobrien screenheight = atoi (ss); 219130561Sobrien 220130561Sobrien if (screenheight <= 0 && term_string_buffer) 221130561Sobrien screenheight = tgetnum ("li"); 222130561Sobrien } 223130561Sobrien 224130561Sobrien /* If all else fails, default to 80x24 terminal. */ 225130561Sobrien if (screenwidth <= 1) 226130561Sobrien screenwidth = 80; 227130561Sobrien 228130561Sobrien if (screenheight <= 0) 229130561Sobrien screenheight = 24; 230130561Sobrien 231130561Sobrien /* If we're being compiled as part of bash, set the environment 232130561Sobrien variables $LINES and $COLUMNS to new values. Otherwise, just 233130561Sobrien do a pair of putenv () or setenv () calls. */ 234130561Sobrien set_lines_and_columns (screenheight, screenwidth); 235130561Sobrien 236130561Sobrien if (!_rl_term_autowrap) 237130561Sobrien screenwidth--; 238130561Sobrien 239130561Sobrien screenchars = screenwidth * screenheight; 240130561Sobrien} 241130561Sobrien 242130561Sobrienvoid 243130561Sobrien_rl_set_screen_size (rows, cols) 244130561Sobrien int rows, cols; 245130561Sobrien{ 246130561Sobrien screenheight = rows; 247130561Sobrien screenwidth = cols; 248130561Sobrien 249130561Sobrien if (_rl_term_autowrap == 0) 250130561Sobrien screenwidth--; 251130561Sobrien 252130561Sobrien screenchars = screenwidth * screenheight; 253130561Sobrien} 254130561Sobrien 255130561Sobrienstruct _tc_string { 256130561Sobrien char *tc_var; 257130561Sobrien char **tc_value; 258130561Sobrien}; 259130561Sobrien 260130561Sobrien/* This should be kept sorted, just in case we decide to change the 261130561Sobrien search algorithm to something smarter. */ 262130561Sobrienstatic struct _tc_string tc_strings[] = 263130561Sobrien{ 264130561Sobrien "DC", &term_DC, 265130561Sobrien "IC", &term_IC, 266130561Sobrien "ce", &term_clreol, 267130561Sobrien "cl", &term_clrpag, 268130561Sobrien "cr", &term_cr, 269130561Sobrien "dc", &term_dc, 270130561Sobrien "ei", &term_ei, 271130561Sobrien "ic", &term_ic, 272130561Sobrien "im", &term_im, 273130561Sobrien "kd", &term_kd, 274130561Sobrien "kh", &term_kh, /* home */ 275130561Sobrien "kH", &term_kH, /* end */ 276130561Sobrien "kl", &term_kl, 277130561Sobrien "kr", &term_kr, 278130561Sobrien "ku", &term_ku, 279130561Sobrien "ks", &term_ks, 280130561Sobrien "ke", &term_ke, 281130561Sobrien "le", &term_backspace, 282130561Sobrien "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. */ 296static void 297get_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 307int 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 430char * 431rl_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 () */ 447int 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. */ 455void 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. */ 464int 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. */ 482int 483crlf () 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. */ 494int 495ding () 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 532static int 533outchar (c) 534 int c; 535{ 536 return putc (c, rl_outstream); 537} 538 539int 540_rl_enable_meta_key () 541{ 542 if (term_has_meta && term_mm) 543 tputs (term_mm, 1, outchar); 544} 545 546void 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} 555