terminal.c revision 136758
1/* $FreeBSD: head/contrib/libreadline/terminal.c 136758 2004-10-21 20:02:02Z peter $ */ 2 3/* terminal.c -- controlling the terminal with termcap. */ 4 5/* Copyright (C) 1996 Free Software Foundation, Inc. 6 7 This file is part of the GNU Readline Library, a library for 8 reading lines of text with interactive input and history editing. 9 10 The GNU Readline Library is free software; you can redistribute it 11 and/or modify it under the terms of the GNU General Public License 12 as published by the Free Software Foundation; either version 2, or 13 (at your option) any later version. 14 15 The GNU Readline Library is distributed in the hope that it will be 16 useful, but WITHOUT ANY WARRANTY; without even the implied warranty 17 of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 18 GNU General Public License for more details. 19 20 The GNU General Public License is often shipped with GNU software, and 21 is generally kept in a file called COPYING or LICENSE. If you do not 22 have a copy of the license, write to the Free Software Foundation, 23 59 Temple Place, Suite 330, Boston, MA 02111 USA. */ 24#define READLINE_LIBRARY 25 26#if defined (HAVE_CONFIG_H) 27# include <config.h> 28#endif 29 30#include <sys/types.h> 31#include "posixstat.h" 32#include <fcntl.h> 33#if defined (HAVE_SYS_FILE_H) 34# include <sys/file.h> 35#endif /* HAVE_SYS_FILE_H */ 36 37#if defined (HAVE_UNISTD_H) 38# include <unistd.h> 39#endif /* HAVE_UNISTD_H */ 40 41#if defined (HAVE_STDLIB_H) 42# include <stdlib.h> 43#else 44# include "ansi_stdlib.h" 45#endif /* HAVE_STDLIB_H */ 46 47#if defined (HAVE_LOCALE_H) 48# include <locale.h> 49#endif 50 51#include <stdio.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#include "rlprivate.h" 68#include "rlshell.h" 69#include "xmalloc.h" 70 71#define CUSTOM_REDISPLAY_FUNC() (rl_redisplay_function != rl_redisplay) 72#define CUSTOM_INPUT_FUNC() (rl_getc_function != rl_getc) 73 74/* **************************************************************** */ 75/* */ 76/* Terminal and Termcap */ 77/* */ 78/* **************************************************************** */ 79 80static char *term_buffer = (char *)NULL; 81static char *term_string_buffer = (char *)NULL; 82 83static int tcap_initialized; 84 85#if !defined (__linux__) 86# if defined (__EMX__) || defined (NEED_EXTERN_PC) 87extern 88# endif /* __EMX__ || NEED_EXTERN_PC */ 89char PC, *BC, *UP; 90#endif /* __linux__ */ 91 92/* Some strings to control terminal actions. These are output by tputs (). */ 93char *_rl_term_clreol; 94char *_rl_term_clrpag; 95char *_rl_term_cr; 96char *_rl_term_backspace; 97char *_rl_term_goto; 98char *_rl_term_pc; 99 100/* Non-zero if we determine that the terminal can do character insertion. */ 101int _rl_terminal_can_insert = 0; 102 103/* How to insert characters. */ 104char *_rl_term_im; 105char *_rl_term_ei; 106char *_rl_term_ic; 107char *_rl_term_ip; 108char *_rl_term_IC; 109 110/* How to delete characters. */ 111char *_rl_term_dc; 112char *_rl_term_DC; 113 114#if defined (HACK_TERMCAP_MOTION) 115char *_rl_term_forward_char; 116#endif /* HACK_TERMCAP_MOTION */ 117 118/* How to go up a line. */ 119char *_rl_term_up; 120 121/* A visible bell; char if the terminal can be made to flash the screen. */ 122static char *_rl_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 *_rl_term_mm; 133static char *_rl_term_mo; 134 135/* The key sequences output by the arrow keys, if this terminal has any. */ 136static char *_rl_term_ku; 137static char *_rl_term_kd; 138static char *_rl_term_kr; 139static char *_rl_term_kl; 140 141/* How to initialize and reset the arrow keys, if this terminal has any. */ 142static char *_rl_term_ks; 143static char *_rl_term_ke; 144 145/* The key sequences sent by the Home and End keys, if any. */ 146static char *_rl_term_kh; 147static char *_rl_term_kH; 148static char *_rl_term_at7; /* @7 */ 149 150/* Insert key */ 151static char *_rl_term_kI; 152 153/* Cursor control */ 154static char *_rl_term_vs; /* very visible */ 155static char *_rl_term_ve; /* normal */ 156 157static void bind_termcap_arrow_keys PARAMS((Keymap)); 158 159/* Variables that hold the screen dimensions, used by the display code. */ 160int _rl_screenwidth, _rl_screenheight, _rl_screenchars; 161 162/* Non-zero means the user wants to enable the keypad. */ 163int _rl_enable_keypad; 164 165/* Non-zero means the user wants to enable a meta key. */ 166int _rl_enable_meta = 1; 167 168#if defined (__EMX__) 169static void 170_emx_get_screensize (swp, shp) 171 int *swp, *shp; 172{ 173 int sz[2]; 174 175 _scrsize (sz); 176 177 if (swp) 178 *swp = sz[0]; 179 if (shp) 180 *shp = sz[1]; 181} 182#endif 183 184/* Get readline's idea of the screen size. TTY is a file descriptor open 185 to the terminal. If IGNORE_ENV is true, we do not pay attention to the 186 values of $LINES and $COLUMNS. The tests for TERM_STRING_BUFFER being 187 non-null serve to check whether or not we have initialized termcap. */ 188void 189_rl_get_screen_size (tty, ignore_env) 190 int tty, ignore_env; 191{ 192 char *ss; 193#if defined (TIOCGWINSZ) 194 struct winsize window_size; 195#endif /* TIOCGWINSZ */ 196 197#if defined (TIOCGWINSZ) 198 if (ioctl (tty, TIOCGWINSZ, &window_size) == 0) 199 { 200 _rl_screenwidth = (int) window_size.ws_col; 201 _rl_screenheight = (int) window_size.ws_row; 202 } 203#endif /* TIOCGWINSZ */ 204 205#if defined (__EMX__) 206 _emx_get_screensize (&_rl_screenwidth, &_rl_screenheight); 207#endif 208 209 /* Environment variable COLUMNS overrides setting of "co" if IGNORE_ENV 210 is unset. */ 211 if (_rl_screenwidth <= 0) 212 { 213 if (ignore_env == 0 && (ss = sh_get_env_value ("COLUMNS"))) 214 _rl_screenwidth = atoi (ss); 215 216#if !defined (__DJGPP__) 217 if (_rl_screenwidth <= 0 && term_string_buffer) 218 _rl_screenwidth = tgetnum ("co"); 219#endif 220 } 221 222 /* Environment variable LINES overrides setting of "li" if IGNORE_ENV 223 is unset. */ 224 if (_rl_screenheight <= 0) 225 { 226 if (ignore_env == 0 && (ss = sh_get_env_value ("LINES"))) 227 _rl_screenheight = atoi (ss); 228 229#if !defined (__DJGPP__) 230 if (_rl_screenheight <= 0 && term_string_buffer) 231 _rl_screenheight = tgetnum ("li"); 232#endif 233 } 234 235 /* If all else fails, default to 80x24 terminal. */ 236 if (_rl_screenwidth <= 1) 237 _rl_screenwidth = 80; 238 239 if (_rl_screenheight <= 0) 240 _rl_screenheight = 24; 241 242 /* If we're being compiled as part of bash, set the environment 243 variables $LINES and $COLUMNS to new values. Otherwise, just 244 do a pair of putenv () or setenv () calls. */ 245 sh_set_lines_and_columns (_rl_screenheight, _rl_screenwidth); 246 247 if (_rl_term_autowrap == 0) 248 _rl_screenwidth--; 249 250 _rl_screenchars = _rl_screenwidth * _rl_screenheight; 251} 252 253void 254_rl_set_screen_size (rows, cols) 255 int rows, cols; 256{ 257 if (rows == 0 || cols == 0) 258 return; 259 260 _rl_screenheight = rows; 261 _rl_screenwidth = cols; 262 263 if (_rl_term_autowrap == 0) 264 _rl_screenwidth--; 265 266 _rl_screenchars = _rl_screenwidth * _rl_screenheight; 267} 268 269void 270rl_set_screen_size (rows, cols) 271 int rows, cols; 272{ 273 _rl_set_screen_size (rows, cols); 274} 275 276void 277rl_get_screen_size (rows, cols) 278 int *rows, *cols; 279{ 280 if (rows) 281 *rows = _rl_screenheight; 282 if (cols) 283 *cols = _rl_screenwidth; 284} 285 286void 287rl_resize_terminal () 288{ 289 if (readline_echoing_p) 290 { 291 _rl_get_screen_size (fileno (rl_instream), 1); 292 if (CUSTOM_REDISPLAY_FUNC ()) 293 rl_forced_update_display (); 294 else 295 _rl_redisplay_after_sigwinch (); 296 } 297} 298 299struct _tc_string { 300 const char *tc_var; 301 char **tc_value; 302}; 303 304/* This should be kept sorted, just in case we decide to change the 305 search algorithm to something smarter. */ 306static struct _tc_string tc_strings[] = 307{ 308 { "@7", &_rl_term_at7 }, 309 { "DC", &_rl_term_DC }, 310 { "IC", &_rl_term_IC }, 311 { "ce", &_rl_term_clreol }, 312 { "cl", &_rl_term_clrpag }, 313 { "cr", &_rl_term_cr }, 314 { "dc", &_rl_term_dc }, 315 { "ei", &_rl_term_ei }, 316 { "ic", &_rl_term_ic }, 317 { "im", &_rl_term_im }, 318 { "kH", &_rl_term_kH }, /* home down ?? */ 319 { "kI", &_rl_term_kI }, /* insert */ 320 { "kd", &_rl_term_kd }, 321 { "ke", &_rl_term_ke }, /* end keypad mode */ 322 { "kh", &_rl_term_kh }, /* home */ 323 { "kl", &_rl_term_kl }, 324 { "kr", &_rl_term_kr }, 325 { "ks", &_rl_term_ks }, /* start keypad mode */ 326 { "ku", &_rl_term_ku }, 327 { "le", &_rl_term_backspace }, 328 { "mm", &_rl_term_mm }, 329 { "mo", &_rl_term_mo }, 330#if defined (HACK_TERMCAP_MOTION) 331 { "nd", &_rl_term_forward_char }, 332#endif 333 { "pc", &_rl_term_pc }, 334 { "up", &_rl_term_up }, 335 { "vb", &_rl_visible_bell }, 336 { "vs", &_rl_term_vs }, 337 { "ve", &_rl_term_ve }, 338}; 339 340#define NUM_TC_STRINGS (sizeof (tc_strings) / sizeof (struct _tc_string)) 341 342/* Read the desired terminal capability strings into BP. The capabilities 343 are described in the TC_STRINGS table. */ 344static void 345get_term_capabilities (bp) 346 char **bp; 347{ 348#if !defined (__DJGPP__) /* XXX - doesn't DJGPP have a termcap library? */ 349 register int i; 350 351 for (i = 0; i < NUM_TC_STRINGS; i++) 352 *(tc_strings[i].tc_value) = tgetstr ((char *)tc_strings[i].tc_var, bp); 353#endif 354 tcap_initialized = 1; 355} 356 357int 358_rl_init_terminal_io (terminal_name) 359 const char *terminal_name; 360{ 361 const char *term; 362 char *buffer; 363 int tty, tgetent_ret; 364 365 term = terminal_name ? terminal_name : sh_get_env_value ("TERM"); 366 _rl_term_clrpag = _rl_term_cr = _rl_term_clreol = (char *)NULL; 367 tty = rl_instream ? fileno (rl_instream) : 0; 368 _rl_screenwidth = _rl_screenheight = 0; 369 370 if (term == 0) 371 term = "dumb"; 372 373 /* I've separated this out for later work on not calling tgetent at all 374 if the calling application has supplied a custom redisplay function, 375 (and possibly if the application has supplied a custom input function). */ 376 if (CUSTOM_REDISPLAY_FUNC()) 377 { 378 tgetent_ret = -1; 379 } 380 else 381 { 382 if (term_string_buffer == 0) 383 term_string_buffer = (char *)xmalloc(2032); 384 385 if (term_buffer == 0) 386 term_buffer = (char *)xmalloc(4080); 387 388 buffer = term_string_buffer; 389 390 tgetent_ret = tgetent (term_buffer, term); 391 } 392 393 if (tgetent_ret <= 0) 394 { 395 FREE (term_string_buffer); 396 FREE (term_buffer); 397 buffer = term_buffer = term_string_buffer = (char *)NULL; 398 399 _rl_term_autowrap = 0; /* used by _rl_get_screen_size */ 400 401#if defined (__EMX__) 402 _emx_get_screensize (&_rl_screenwidth, &_rl_screenheight); 403 _rl_screenwidth--; 404#else /* !__EMX__ */ 405 _rl_get_screen_size (tty, 0); 406#endif /* !__EMX__ */ 407 408 /* Defaults. */ 409 if (_rl_screenwidth <= 0 || _rl_screenheight <= 0) 410 { 411 _rl_screenwidth = 79; 412 _rl_screenheight = 24; 413 } 414 415 /* Everything below here is used by the redisplay code (tputs). */ 416 _rl_screenchars = _rl_screenwidth * _rl_screenheight; 417 _rl_term_cr = "\r"; 418 _rl_term_im = _rl_term_ei = _rl_term_ic = _rl_term_IC = (char *)NULL; 419 _rl_term_up = _rl_term_dc = _rl_term_DC = _rl_visible_bell = (char *)NULL; 420 _rl_term_ku = _rl_term_kd = _rl_term_kl = _rl_term_kr = (char *)NULL; 421 _rl_term_kh = _rl_term_kH = _rl_term_kI = (char *)NULL; 422 _rl_term_ks = _rl_term_ke = _rl_term_at7 = (char *)NULL; 423 _rl_term_mm = _rl_term_mo = (char *)NULL; 424 _rl_term_ve = _rl_term_vs = (char *)NULL; 425#if defined (HACK_TERMCAP_MOTION) 426 term_forward_char = (char *)NULL; 427#endif 428 _rl_terminal_can_insert = term_has_meta = 0; 429 430 /* Reasonable defaults for tgoto(). Readline currently only uses 431 tgoto if _rl_term_IC or _rl_term_DC is defined, but just in case we 432 change that later... */ 433 PC = '\0'; 434 BC = _rl_term_backspace = "\b"; 435 UP = _rl_term_up; 436 437 return 0; 438 } 439 440 get_term_capabilities (&buffer); 441 442 /* Set up the variables that the termcap library expects the application 443 to provide. */ 444 PC = _rl_term_pc ? *_rl_term_pc : 0; 445 BC = _rl_term_backspace; 446 UP = _rl_term_up; 447 448 if (!_rl_term_cr) 449 _rl_term_cr = "\r"; 450 451 _rl_term_autowrap = tgetflag ("am") && tgetflag ("xn"); 452 453 _rl_get_screen_size (tty, 0); 454 455 /* "An application program can assume that the terminal can do 456 character insertion if *any one of* the capabilities `IC', 457 `im', `ic' or `ip' is provided." But we can't do anything if 458 only `ip' is provided, so... */ 459 _rl_terminal_can_insert = (_rl_term_IC || _rl_term_im || _rl_term_ic); 460 461 /* Check to see if this terminal has a meta key and clear the capability 462 variables if there is none. */ 463 term_has_meta = (tgetflag ("km") || tgetflag ("MT")); 464 if (!term_has_meta) 465 _rl_term_mm = _rl_term_mo = (char *)NULL; 466 467 /* Attempt to find and bind the arrow keys. Do not override already 468 bound keys in an overzealous attempt, however. */ 469 470 bind_termcap_arrow_keys (emacs_standard_keymap); 471 472#if defined (VI_MODE) 473 bind_termcap_arrow_keys (vi_movement_keymap); 474 bind_termcap_arrow_keys (vi_insertion_keymap); 475#endif /* VI_MODE */ 476 477 return 0; 478} 479 480/* Bind the arrow key sequences from the termcap description in MAP. */ 481static void 482bind_termcap_arrow_keys (map) 483 Keymap map; 484{ 485 Keymap xkeymap; 486 487 xkeymap = _rl_keymap; 488 _rl_keymap = map; 489 490 rl_bind_keyseq_if_unbound (_rl_term_ku, rl_get_previous_history); 491 rl_bind_keyseq_if_unbound (_rl_term_kd, rl_get_next_history); 492 rl_bind_keyseq_if_unbound (_rl_term_kr, rl_forward_char); 493 rl_bind_keyseq_if_unbound (_rl_term_kl, rl_backward_char); 494 495 rl_bind_keyseq_if_unbound (_rl_term_kh, rl_beg_of_line); /* Home */ 496 rl_bind_keyseq_if_unbound (_rl_term_at7, rl_end_of_line); /* End */ 497 498 _rl_keymap = xkeymap; 499} 500 501char * 502rl_get_termcap (cap) 503 const char *cap; 504{ 505 register int i; 506 507 if (tcap_initialized == 0) 508 return ((char *)NULL); 509 for (i = 0; i < NUM_TC_STRINGS; i++) 510 { 511 if (tc_strings[i].tc_var[0] == cap[0] && strcmp (tc_strings[i].tc_var, cap) == 0) 512 return *(tc_strings[i].tc_value); 513 } 514 return ((char *)NULL); 515} 516 517/* Re-initialize the terminal considering that the TERM/TERMCAP variable 518 has changed. */ 519int 520rl_reset_terminal (terminal_name) 521 const char *terminal_name; 522{ 523 _rl_init_terminal_io (terminal_name); 524 return 0; 525} 526 527/* A function for the use of tputs () */ 528#ifdef _MINIX 529void 530_rl_output_character_function (c) 531 int c; 532{ 533 putc (c, _rl_out_stream); 534} 535#else /* !_MINIX */ 536int 537_rl_output_character_function (c) 538 int c; 539{ 540 return putc (c, _rl_out_stream); 541} 542#endif /* !_MINIX */ 543 544/* Write COUNT characters from STRING to the output stream. */ 545void 546_rl_output_some_chars (string, count) 547 const char *string; 548 int count; 549{ 550 fwrite (string, 1, count, _rl_out_stream); 551} 552 553/* Move the cursor back. */ 554int 555_rl_backspace (count) 556 int count; 557{ 558 register int i; 559 560 if (_rl_term_backspace) 561 for (i = 0; i < count; i++) 562 tputs (_rl_term_backspace, 1, _rl_output_character_function); 563 else 564 for (i = 0; i < count; i++) 565 putc ('\b', _rl_out_stream); 566 return 0; 567} 568 569/* Move to the start of the next line. */ 570int 571rl_crlf () 572{ 573#if defined (NEW_TTY_DRIVER) 574 if (_rl_term_cr) 575 tputs (_rl_term_cr, 1, _rl_output_character_function); 576#endif /* NEW_TTY_DRIVER */ 577 putc ('\n', _rl_out_stream); 578 return 0; 579} 580 581/* Ring the terminal bell. */ 582int 583rl_ding () 584{ 585 if (readline_echoing_p) 586 { 587 switch (_rl_bell_preference) 588 { 589 case NO_BELL: 590 default: 591 break; 592 case VISIBLE_BELL: 593 if (_rl_visible_bell) 594 { 595 tputs (_rl_visible_bell, 1, _rl_output_character_function); 596 break; 597 } 598 /* FALLTHROUGH */ 599 case AUDIBLE_BELL: 600 fprintf (stderr, "\007"); 601 fflush (stderr); 602 break; 603 } 604 return (0); 605 } 606 return (-1); 607} 608 609/* **************************************************************** */ 610/* */ 611/* Controlling the Meta Key and Keypad */ 612/* */ 613/* **************************************************************** */ 614 615void 616_rl_enable_meta_key () 617{ 618#if !defined (__DJGPP__) 619 if (term_has_meta && _rl_term_mm) 620 tputs (_rl_term_mm, 1, _rl_output_character_function); 621#endif 622} 623 624void 625_rl_control_keypad (on) 626 int on; 627{ 628#if !defined (__DJGPP__) 629 if (on && _rl_term_ks) 630 tputs (_rl_term_ks, 1, _rl_output_character_function); 631 else if (!on && _rl_term_ke) 632 tputs (_rl_term_ke, 1, _rl_output_character_function); 633#endif 634} 635 636/* **************************************************************** */ 637/* */ 638/* Controlling the Cursor */ 639/* */ 640/* **************************************************************** */ 641 642/* Set the cursor appropriately depending on IM, which is one of the 643 insert modes (insert or overwrite). Insert mode gets the normal 644 cursor. Overwrite mode gets a very visible cursor. Only does 645 anything if we have both capabilities. */ 646void 647_rl_set_cursor (im, force) 648 int im, force; 649{ 650 if (_rl_term_ve && _rl_term_vs) 651 { 652 if (force || im != rl_insert_mode) 653 { 654 if (im == RL_IM_OVERWRITE) 655 tputs (_rl_term_vs, 1, _rl_output_character_function); 656 else 657 tputs (_rl_term_ve, 1, _rl_output_character_function); 658 } 659 } 660} 661