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#ifdef __MSDOS__ 59# include <pc.h> 60#endif 61 62#include "rltty.h" 63#include "tcap.h" 64 65/* Some standard library routines. */ 66#include "readline.h" 67#include "history.h" 68 69#include "rlprivate.h" 70#include "rlshell.h" 71#include "xmalloc.h" 72 73#define CUSTOM_REDISPLAY_FUNC() (rl_redisplay_function != rl_redisplay) 74#define CUSTOM_INPUT_FUNC() (rl_getc_function != rl_getc) 75 76/* **************************************************************** */ 77/* */ 78/* Terminal and Termcap */ 79/* */ 80/* **************************************************************** */ 81 82#ifndef __MSDOS__ 83static char *term_buffer = (char *)NULL; 84static char *term_string_buffer = (char *)NULL; 85 86/* Non-zero means this terminal can't really do anything. */ 87static int dumb_term; 88#endif /* !__MSDOS__ */ 89 90static int tcap_initialized; 91 92#if !defined (__linux__) 93# if defined (__EMX__) || defined (NEED_EXTERN_PC) 94extern 95# endif /* __EMX__ || NEED_EXTERN_PC */ 96char PC, *BC, *UP; 97#endif /* __linux__ */ 98 99/* Some strings to control terminal actions. These are output by tputs (). */ 100char *_rl_term_clreol; 101char *_rl_term_clrpag; 102char *_rl_term_cr; 103char *_rl_term_backspace; 104char *_rl_term_goto; 105char *_rl_term_pc; 106 107/* Non-zero if we determine that the terminal can do character insertion. */ 108int _rl_terminal_can_insert = 0; 109 110/* How to insert characters. */ 111char *_rl_term_im; 112char *_rl_term_ei; 113char *_rl_term_ic; 114char *_rl_term_ip; 115char *_rl_term_IC; 116 117/* How to delete characters. */ 118char *_rl_term_dc; 119char *_rl_term_DC; 120 121#if defined (HACK_TERMCAP_MOTION) 122char *_rl_term_forward_char; 123#endif /* HACK_TERMCAP_MOTION */ 124 125/* How to go up a line. */ 126char *_rl_term_up; 127 128/* A visible bell; char if the terminal can be made to flash the screen. */ 129static char *_rl_visible_bell; 130 131/* Non-zero means the terminal can auto-wrap lines. */ 132int _rl_term_autowrap; 133 134/* Non-zero means that this terminal has a meta key. */ 135static int term_has_meta; 136 137/* The sequences to write to turn on and off the meta key, if this 138 terminal has one. */ 139static char *_rl_term_mm; 140static char *_rl_term_mo; 141 142/* The key sequences output by the arrow keys, if this terminal has any. */ 143static char *_rl_term_ku; 144static char *_rl_term_kd; 145static char *_rl_term_kr; 146static char *_rl_term_kl; 147 148/* How to initialize and reset the arrow keys, if this terminal has any. */ 149static char *_rl_term_ks; 150static char *_rl_term_ke; 151 152/* The key sequences sent by the Home and End keys, if any. */ 153static char *_rl_term_kh; 154static char *_rl_term_kH; 155static char *_rl_term_at7; /* @7 */ 156 157/* Insert key */ 158static char *_rl_term_kI; 159 160/* Cursor control */ 161static char *_rl_term_vs; /* very visible */ 162static char *_rl_term_ve; /* normal */ 163 164static void bind_termcap_arrow_keys PARAMS((Keymap)); 165 166/* Variables that hold the screen dimensions, used by the display code. */ 167int _rl_screenwidth, _rl_screenheight, _rl_screenchars; 168 169/* Non-zero means the user wants to enable the keypad. */ 170int _rl_enable_keypad; 171 172/* Non-zero means the user wants to enable a meta key. */ 173int _rl_enable_meta = 1; 174 175#if defined (__EMX__) 176static void 177_emx_get_screensize (swp, shp) 178 int *swp, *shp; 179{ 180 int sz[2]; 181 182 _scrsize (sz); 183 184 if (swp) 185 *swp = sz[0]; 186 if (shp) 187 *shp = sz[1]; 188} 189#endif 190 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. */ 195void 196_rl_get_screen_size (tty, ignore_env) 197 int tty, ignore_env; 198{ 199 char *ss; 200#if defined (TIOCGWINSZ) 201 struct winsize window_size; 202#endif /* TIOCGWINSZ */ 203 204#if defined (TIOCGWINSZ) 205 if (ioctl (tty, TIOCGWINSZ, &window_size) == 0) 206 { 207 _rl_screenwidth = (int) window_size.ws_col; 208 _rl_screenheight = (int) window_size.ws_row; 209 } 210#endif /* TIOCGWINSZ */ 211 212#if defined (__EMX__) 213 _emx_get_screensize (&_rl_screenwidth, &_rl_screenheight); 214#endif 215 216 /* Environment variable COLUMNS overrides setting of "co" if IGNORE_ENV 217 is unset. */ 218 if (_rl_screenwidth <= 0) 219 { 220 if (ignore_env == 0 && (ss = sh_get_env_value ("COLUMNS"))) 221 _rl_screenwidth = atoi (ss); 222 223#if defined (__DJGPP__) 224 if (_rl_screenwidth <= 0) 225 _rl_screenwidth = ScreenCols (); 226#else 227 if (_rl_screenwidth <= 0 && term_string_buffer) 228 _rl_screenwidth = tgetnum ("co"); 229#endif 230 } 231 232 /* Environment variable LINES overrides setting of "li" if IGNORE_ENV 233 is unset. */ 234 if (_rl_screenheight <= 0) 235 { 236 if (ignore_env == 0 && (ss = sh_get_env_value ("LINES"))) 237 _rl_screenheight = atoi (ss); 238 239#if defined (__DJGPP__) 240 if (_rl_screenheight <= 0) 241 _rl_screenheight = ScreenRows (); 242#else 243 if (_rl_screenheight <= 0 && term_string_buffer) 244 _rl_screenheight = tgetnum ("li"); 245#endif 246 } 247 248 /* If all else fails, default to 80x24 terminal. */ 249 if (_rl_screenwidth <= 1) 250 _rl_screenwidth = 80; 251 252 if (_rl_screenheight <= 0) 253 _rl_screenheight = 24; 254 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); 259 260 if (_rl_term_autowrap == 0) 261 _rl_screenwidth--; 262 263 _rl_screenchars = _rl_screenwidth * _rl_screenheight; 264} 265 266void 267_rl_set_screen_size (rows, cols) 268 int rows, cols; 269{ 270 if (rows == 0 || cols == 0) 271 return; 272 273 _rl_screenheight = rows; 274 _rl_screenwidth = cols; 275 276 if (_rl_term_autowrap == 0) 277 _rl_screenwidth--; 278 279 _rl_screenchars = _rl_screenwidth * _rl_screenheight; 280} 281 282void 283rl_set_screen_size (rows, cols) 284 int rows, cols; 285{ 286 _rl_set_screen_size (rows, cols); 287} 288 289void 290rl_get_screen_size (rows, cols) 291 int *rows, *cols; 292{ 293 if (rows) 294 *rows = _rl_screenheight; 295 if (cols) 296 *cols = _rl_screenwidth; 297} 298 299void 300rl_resize_terminal () 301{ 302 if (readline_echoing_p) 303 { 304 _rl_get_screen_size (fileno (rl_instream), 1); 305 if (CUSTOM_REDISPLAY_FUNC ()) 306 rl_forced_update_display (); 307 else 308 _rl_redisplay_after_sigwinch (); 309 } 310} 311 312struct _tc_string { 313 const char *tc_var; 314 char **tc_value; 315}; 316 317/* This should be kept sorted, just in case we decide to change the 318 search algorithm to something smarter. */ 319static struct _tc_string tc_strings[] = 320{ 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 }, 345#endif 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 }, 351}; 352 353#define NUM_TC_STRINGS (sizeof (tc_strings) / sizeof (struct _tc_string)) 354 355/* Read the desired terminal capability strings into BP. The capabilities 356 are described in the TC_STRINGS table. */ 357static void 358get_term_capabilities (bp) 359 char **bp; 360{ 361#if !defined (__DJGPP__) /* XXX - doesn't DJGPP have a termcap library? */ 362 register int i; 363 364 for (i = 0; i < NUM_TC_STRINGS; i++) 365# ifdef __LCC__ 366 *(tc_strings[i].tc_value) = tgetstr ((char *)tc_strings[i].tc_var, bp); 367# else 368 *(tc_strings[i].tc_value) = tgetstr (tc_strings[i].tc_var, bp); 369# endif 370#endif 371 tcap_initialized = 1; 372} 373 374int 375_rl_init_terminal_io (terminal_name) 376 const char *terminal_name; 377{ 378 const char *term; 379 char *buffer; 380 int tty, tgetent_ret; 381 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; 386 387 if (term == 0) 388 term = "dumb"; 389 390#ifdef __MSDOS__ 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; 396 _rl_term_cr = "\r"; 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; 403#endif 404 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()) 411 { 412 tgetent_ret = -1; 413 } 414 else 415 { 416 if (term_string_buffer == 0) 417 term_string_buffer = (char *)xmalloc(2032); 418 419 if (term_buffer == 0) 420 term_buffer = (char *)xmalloc(4080); 421 422 buffer = term_string_buffer; 423 424 tgetent_ret = tgetent (term_buffer, term); 425 } 426 427 if (tgetent_ret <= 0) 428 { 429 FREE (term_string_buffer); 430 FREE (term_buffer); 431 buffer = term_buffer = term_string_buffer = (char *)NULL; 432 433 _rl_term_autowrap = 0; /* used by _rl_get_screen_size */ 434 435#if defined (__EMX__) 436 _emx_get_screensize (&_rl_screenwidth, &_rl_screenheight); 437 _rl_screenwidth--; 438#else /* !__EMX__ */ 439 _rl_get_screen_size (tty, 0); 440#endif /* !__EMX__ */ 441 442 /* Defaults. */ 443 if (_rl_screenwidth <= 0 || _rl_screenheight <= 0) 444 { 445 _rl_screenwidth = 79; 446 _rl_screenheight = 24; 447 } 448 449 /* Everything below here is used by the redisplay code (tputs). */ 450 _rl_screenchars = _rl_screenwidth * _rl_screenheight; 451 _rl_term_cr = "\r"; 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; 461#endif 462 _rl_terminal_can_insert = term_has_meta = 0; 463 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... */ 467 PC = '\0'; 468 BC = _rl_term_backspace = "\b"; 469 UP = _rl_term_up; 470 471 return 0; 472 } 473 474 get_term_capabilities (&buffer); 475 476 /* Set up the variables that the termcap library expects the application 477 to provide. */ 478 PC = _rl_term_pc ? *_rl_term_pc : 0; 479 BC = _rl_term_backspace; 480 UP = _rl_term_up; 481 482 if (!_rl_term_cr) 483 _rl_term_cr = "\r"; 484 485 _rl_term_autowrap = tgetflag ("am") && tgetflag ("xn"); 486 487 _rl_get_screen_size (tty, 0); 488 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); 494 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")); 498 if (!term_has_meta) 499 _rl_term_mm = _rl_term_mo = (char *)NULL; 500 501#endif /* !__MSDOS__ */ 502 503 /* Attempt to find and bind the arrow keys. Do not override already 504 bound keys in an overzealous attempt, however. */ 505 506 bind_termcap_arrow_keys (emacs_standard_keymap); 507 508#if defined (VI_MODE) 509 bind_termcap_arrow_keys (vi_movement_keymap); 510 bind_termcap_arrow_keys (vi_insertion_keymap); 511#endif /* VI_MODE */ 512 513 return 0; 514} 515 516/* Bind the arrow key sequences from the termcap description in MAP. */ 517static void 518bind_termcap_arrow_keys (map) 519 Keymap map; 520{ 521 Keymap xkeymap; 522 523 xkeymap = _rl_keymap; 524 _rl_keymap = map; 525 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); 530 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 */ 533 534 _rl_keymap = xkeymap; 535} 536 537char * 538rl_get_termcap (cap) 539 const char *cap; 540{ 541 register int i; 542 543 if (tcap_initialized == 0) 544 return ((char *)NULL); 545 for (i = 0; i < NUM_TC_STRINGS; i++) 546 { 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); 549 } 550 return ((char *)NULL); 551} 552 553/* Re-initialize the terminal considering that the TERM/TERMCAP variable 554 has changed. */ 555int 556rl_reset_terminal (terminal_name) 557 const char *terminal_name; 558{ 559 _rl_init_terminal_io (terminal_name); 560 return 0; 561} 562 563/* A function for the use of tputs () */ 564#ifdef _MINIX 565void 566_rl_output_character_function (c) 567 int c; 568{ 569 putc (c, _rl_out_stream); 570} 571#else /* !_MINIX */ 572int 573_rl_output_character_function (c) 574 int c; 575{ 576 return putc (c, _rl_out_stream); 577} 578#endif /* !_MINIX */ 579 580/* Write COUNT characters from STRING to the output stream. */ 581void 582_rl_output_some_chars (string, count) 583 const char *string; 584 int count; 585{ 586 fwrite (string, 1, count, _rl_out_stream); 587} 588 589/* Move the cursor back. */ 590int 591_rl_backspace (count) 592 int count; 593{ 594 register int i; 595 596#ifndef __MSDOS__ 597 if (_rl_term_backspace) 598 for (i = 0; i < count; i++) 599 tputs (_rl_term_backspace, 1, _rl_output_character_function); 600 else 601#endif 602 for (i = 0; i < count; i++) 603 putc ('\b', _rl_out_stream); 604 return 0; 605} 606 607/* Move to the start of the next line. */ 608int 609rl_crlf () 610{ 611#if defined (NEW_TTY_DRIVER) 612 if (_rl_term_cr) 613 tputs (_rl_term_cr, 1, _rl_output_character_function); 614#endif /* NEW_TTY_DRIVER */ 615 putc ('\n', _rl_out_stream); 616 return 0; 617} 618 619/* Ring the terminal bell. */ 620int 621rl_ding () 622{ 623 if (readline_echoing_p) 624 { 625 switch (_rl_bell_preference) 626 { 627 case NO_BELL: 628 default: 629 break; 630 case VISIBLE_BELL: 631#ifdef __MSDOS__ 632 ScreenVisualBell (); 633 break; 634#else 635 if (_rl_visible_bell) 636 { 637 tputs (_rl_visible_bell, 1, _rl_output_character_function); 638 break; 639 } 640#endif 641 /* FALLTHROUGH */ 642 case AUDIBLE_BELL: 643 fprintf (stderr, "\007"); 644 fflush (stderr); 645 break; 646 } 647 return (0); 648 } 649 return (-1); 650} 651 652/* **************************************************************** */ 653/* */ 654/* Controlling the Meta Key and Keypad */ 655/* */ 656/* **************************************************************** */ 657 658void 659_rl_enable_meta_key () 660{ 661#if !defined (__DJGPP__) 662 if (term_has_meta && _rl_term_mm) 663 tputs (_rl_term_mm, 1, _rl_output_character_function); 664#endif 665} 666 667void 668_rl_control_keypad (on) 669 int on; 670{ 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); 676#endif 677} 678 679/* **************************************************************** */ 680/* */ 681/* Controlling the Cursor */ 682/* */ 683/* **************************************************************** */ 684 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. */ 689void 690_rl_set_cursor (im, force) 691 int im, force; 692{ 693#ifndef __MSDOS__ 694 if (_rl_term_ve && _rl_term_vs) 695 { 696 if (force || im != rl_insert_mode) 697 { 698 if (im == RL_IM_OVERWRITE) 699 tputs (_rl_term_vs, 1, _rl_output_character_function); 700 else 701 tputs (_rl_term_ve, 1, _rl_output_character_function); 702 } 703 } 704#endif 705} 706