terminal.c revision 21308
121308Sache/* terminal.c -- controlling the terminal with termcap. */ 221308Sache 321308Sache/* Copyright (C) 1996 Free Software Foundation, Inc. 421308Sache 521308Sache This file is part of the GNU Readline Library, a library for 621308Sache reading lines of text with interactive input and history editing. 721308Sache 821308Sache The GNU Readline Library is free software; you can redistribute it 921308Sache and/or modify it under the terms of the GNU General Public License 1021308Sache as published by the Free Software Foundation; either version 1, or 1121308Sache (at your option) any later version. 1221308Sache 1321308Sache The GNU Readline Library is distributed in the hope that it will be 1421308Sache useful, but WITHOUT ANY WARRANTY; without even the implied warranty 1521308Sache of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 1621308Sache GNU General Public License for more details. 1721308Sache 1821308Sache The GNU General Public License is often shipped with GNU software, and 1921308Sache is generally kept in a file called COPYING or LICENSE. If you do not 2021308Sache have a copy of the license, write to the Free Software Foundation, 2121308Sache 675 Mass Ave, Cambridge, MA 02139, USA. */ 2221308Sache#define READLINE_LIBRARY 2321308Sache 2421308Sache#if defined (HAVE_CONFIG_H) 2521308Sache# include <config.h> 2621308Sache#endif 2721308Sache 2821308Sache#include <sys/types.h> 2921308Sache#include "posixstat.h" 3021308Sache#include <fcntl.h> 3121308Sache#if defined (HAVE_SYS_FILE_H) 3221308Sache# include <sys/file.h> 3321308Sache#endif /* HAVE_SYS_FILE_H */ 3421308Sache 3521308Sache#if defined (HAVE_UNISTD_H) 3621308Sache# include <unistd.h> 3721308Sache#endif /* HAVE_UNISTD_H */ 3821308Sache 3921308Sache#if defined (HAVE_STDLIB_H) 4021308Sache# include <stdlib.h> 4121308Sache#else 4221308Sache# include "ansi_stdlib.h" 4321308Sache#endif /* HAVE_STDLIB_H */ 4421308Sache 4521308Sache#if defined (HAVE_LOCALE_H) 4621308Sache# include <locale.h> 4721308Sache#endif 4821308Sache 4921308Sache#include <signal.h> 5021308Sache#include <stdio.h> 5121308Sache#include <setjmp.h> 5221308Sache 5321308Sache/* System-specific feature definitions and include files. */ 5421308Sache#include "rldefs.h" 5521308Sache 5621308Sache#include "tcap.h" 5721308Sache 5821308Sache#if defined (GWINSZ_IN_SYS_IOCTL) 5921308Sache# include <sys/ioctl.h> 6021308Sache#endif /* GWINSZ_IN_SYS_IOCTL */ 6121308Sache 6221308Sache/* Some standard library routines. */ 6321308Sache#include "readline.h" 6421308Sache#include "history.h" 6521308Sache 6621308Sache/* Variables and functions imported from readline.c */ 6721308Sacheextern FILE *_rl_in_stream, *_rl_out_stream; 6821308Sacheextern int readline_echoing_p; 6921308Sacheextern int _rl_bell_preference; 7021308Sacheextern Keymap _rl_keymap; 7121308Sache 7221308Sache/* **************************************************************** */ 7321308Sache/* */ 7421308Sache/* Terminal and Termcap */ 7521308Sache/* */ 7621308Sache/* **************************************************************** */ 7721308Sache 7821308Sachestatic char *term_buffer = (char *)NULL; 7921308Sachestatic char *term_string_buffer = (char *)NULL; 8021308Sache 8121308Sachestatic int tcap_initialized; 8221308Sache 8321308Sache/* Non-zero means this terminal can't really do anything. */ 8421308Sachestatic int dumb_term; 8521308Sache 8621308Sache#if !defined (__linux__) 8721308Sache/* If this causes problems, add back the `extern'. */ 8821308Sache/*extern*/ char PC, *BC, *UP; 8921308Sache#endif /* __linux__ */ 9021308Sache 9121308Sache/* Some strings to control terminal actions. These are output by tputs (). */ 9221308Sachechar *term_goto, *term_clreol, *term_cr, *term_clrpag, *term_backspace; 9321308Sachechar *term_pc; 9421308Sache 9521308Sache/* Non-zero if we determine that the terminal can do character insertion. */ 9621308Sacheint terminal_can_insert = 0; 9721308Sache 9821308Sache/* How to insert characters. */ 9921308Sachechar *term_im, *term_ei, *term_ic, *term_ip, *term_IC; 10021308Sache 10121308Sache/* How to delete characters. */ 10221308Sachechar *term_dc, *term_DC; 10321308Sache 10421308Sache#if defined (HACK_TERMCAP_MOTION) 10521308Sachechar *term_forward_char; 10621308Sache#endif /* HACK_TERMCAP_MOTION */ 10721308Sache 10821308Sache/* How to go up a line. */ 10921308Sachechar *term_up; 11021308Sache 11121308Sache/* A visible bell, if the terminal can be made to flash the screen. */ 11221308Sachestatic char *visible_bell; 11321308Sache 11421308Sache/* Non-zero means the terminal can auto-wrap lines. */ 11521308Sacheint _rl_term_autowrap; 11621308Sache 11721308Sache/* Non-zero means that this terminal has a meta key. */ 11821308Sachestatic int term_has_meta; 11921308Sache 12021308Sache/* The sequences to write to turn on and off the meta key, if this 12121308Sache terminal has one. */ 12221308Sachestatic char *term_mm, *term_mo; 12321308Sache 12421308Sache/* The key sequences output by the arrow keys, if this terminal has any. */ 12521308Sachestatic char *term_ku, *term_kd, *term_kr, *term_kl; 12621308Sache 12721308Sache/* How to initialize and reset the arrow keys, if this terminal has any. */ 12821308Sachestatic char *term_ks, *term_ke; 12921308Sache 13021308Sache/* The key sequences sent by the Home and End keys, if any. */ 13121308Sachestatic char *term_kh, *term_kH; 13221308Sache 13321308Sache/* Variables that hold the screen dimensions, used by the display code. */ 13421308Sacheint screenwidth, screenheight, screenchars; 13521308Sache 13621308Sache/* Non-zero means the user wants to enable the keypad. */ 13721308Sacheint _rl_enable_keypad; 13821308Sache 13921308Sache/* Non-zero means the user wants to enable a meta key. */ 14021308Sacheint _rl_enable_meta = 1; 14121308Sache 14221308Sache/* Re-initialize the terminal considering that the TERM/TERMCAP variable 14321308Sache has changed. */ 14421308Sacheint 14521308Sacherl_reset_terminal (terminal_name) 14621308Sache char *terminal_name; 14721308Sache{ 14821308Sache _rl_init_terminal_io (terminal_name); 14921308Sache return 0; 15021308Sache} 15121308Sache 15221308Sache#if !defined (SHELL) 15321308Sachestatic void 15421308Sacheset_lines_and_columns (lines, cols) 15521308Sache int lines, cols; 15621308Sache{ 15721308Sache char *b; 15821308Sache 15921308Sache#if defined (HAVE_PUTENV) 16021308Sache b = xmalloc (24); 16121308Sache sprintf (b, "LINES=%d", lines); 16221308Sache putenv (b); 16321308Sache b = xmalloc (24); 16421308Sache sprintf (b, "COLUMNS=%d", cols); 16521308Sache putenv (b); 16621308Sache#else /* !HAVE_PUTENV */ 16721308Sache# if defined (HAVE_SETENV) 16821308Sache b = xmalloc (8); 16921308Sache sprintf (b, "%d", lines); 17021308Sache setenv ("LINES", b, 1); 17121308Sache b = xmalloc (8); 17221308Sache sprintf (b, "%d", cols); 17321308Sache setenv ("COLUMNS", b, 1); 17421308Sache# endif /* HAVE_SETENV */ 17521308Sache#endif /* !HAVE_PUTENV */ 17621308Sache} 17721308Sache#else /* SHELL */ 17821308Sacheextern void set_lines_and_columns (); 17921308Sache#endif /* SHELL */ 18021308Sache 18121308Sache/* Get readline's idea of the screen size. TTY is a file descriptor open 18221308Sache to the terminal. If IGNORE_ENV is true, we do not pay attention to the 18321308Sache values of $LINES and $COLUMNS. The tests for TERM_STRING_BUFFER being 18421308Sache non-null serve to check whether or not we have initialized termcap. */ 18521308Sachevoid 18621308Sache_rl_get_screen_size (tty, ignore_env) 18721308Sache int tty, ignore_env; 18821308Sache{ 18921308Sache char *ss; 19021308Sache#if defined (TIOCGWINSZ) 19121308Sache struct winsize window_size; 19221308Sache#endif /* TIOCGWINSZ */ 19321308Sache 19421308Sache#if defined (TIOCGWINSZ) 19521308Sache if (ioctl (tty, TIOCGWINSZ, &window_size) == 0) 19621308Sache { 19721308Sache screenwidth = (int) window_size.ws_col; 19821308Sache screenheight = (int) window_size.ws_row; 19921308Sache } 20021308Sache#endif /* TIOCGWINSZ */ 20121308Sache 20221308Sache /* Environment variable COLUMNS overrides setting of "co" if IGNORE_ENV 20321308Sache is unset. */ 20421308Sache if (screenwidth <= 0) 20521308Sache { 20621308Sache if (ignore_env == 0 && (ss = getenv ("COLUMNS"))) 20721308Sache screenwidth = atoi (ss); 20821308Sache 20921308Sache if (screenwidth <= 0 && term_string_buffer) 21021308Sache screenwidth = tgetnum ("co"); 21121308Sache } 21221308Sache 21321308Sache /* Environment variable LINES overrides setting of "li" if IGNORE_ENV 21421308Sache is unset. */ 21521308Sache if (screenheight <= 0) 21621308Sache { 21721308Sache if (ignore_env == 0 && (ss = getenv ("LINES"))) 21821308Sache screenheight = atoi (ss); 21921308Sache 22021308Sache if (screenheight <= 0 && term_string_buffer) 22121308Sache screenheight = tgetnum ("li"); 22221308Sache } 22321308Sache 22421308Sache /* If all else fails, default to 80x24 terminal. */ 22521308Sache if (screenwidth <= 1) 22621308Sache screenwidth = 80; 22721308Sache 22821308Sache if (screenheight <= 0) 22921308Sache screenheight = 24; 23021308Sache 23121308Sache /* If we're being compiled as part of bash, set the environment 23221308Sache variables $LINES and $COLUMNS to new values. Otherwise, just 23321308Sache do a pair of putenv () or setenv () calls. */ 23421308Sache set_lines_and_columns (screenheight, screenwidth); 23521308Sache 23621308Sache if (!_rl_term_autowrap) 23721308Sache screenwidth--; 23821308Sache 23921308Sache screenchars = screenwidth * screenheight; 24021308Sache} 24121308Sache 24221308Sachevoid 24321308Sache_rl_set_screen_size (rows, cols) 24421308Sache int rows, cols; 24521308Sache{ 24621308Sache screenheight = rows; 24721308Sache screenwidth = cols; 24821308Sache 24921308Sache if (_rl_term_autowrap == 0) 25021308Sache screenwidth--; 25121308Sache 25221308Sache screenchars = screenwidth * screenheight; 25321308Sache} 25421308Sache 25521308Sachestruct _tc_string { 25621308Sache char *tc_var; 25721308Sache char **tc_value; 25821308Sache}; 25921308Sache 26021308Sache/* This should be kept sorted, just in case we decide to change the 26121308Sache search algorithm to something smarter. */ 26221308Sachestatic struct _tc_string tc_strings[] = 26321308Sache{ 26421308Sache "DC", &term_DC, 26521308Sache "IC", &term_IC, 26621308Sache "ce", &term_clreol, 26721308Sache "cl", &term_clrpag, 26821308Sache "cr", &term_cr, 26921308Sache "dc", &term_dc, 27021308Sache "ei", &term_ei, 27121308Sache "ic", &term_ic, 27221308Sache "im", &term_im, 27321308Sache "kd", &term_kd, 27421308Sache "kh", &term_kh, /* home */ 27521308Sache "kH", &term_kH, /* end */ 27621308Sache "kl", &term_kl, 27721308Sache "kr", &term_kr, 27821308Sache "ku", &term_ku, 27921308Sache "ks", &term_ks, 28021308Sache "ke", &term_ke, 28121308Sache "le", &term_backspace, 28221308Sache "mm", &term_mm, 28321308Sache "mo", &term_mo, 28421308Sache#if defined (HACK_TERMCAP_MOTION) 28521308Sache "nd", &term_forward_char, 28621308Sache#endif 28721308Sache "pc", &term_pc, 28821308Sache "up", &term_up, 28921308Sache "vb", &visible_bell, 29021308Sache}; 29121308Sache 29221308Sache#define NUM_TC_STRINGS (sizeof (tc_strings) / sizeof (struct _tc_string)) 29321308Sache 29421308Sache/* Read the desired terminal capability strings into BP. The capabilities 29521308Sache are described in the TC_STRINGS table. */ 29621308Sachestatic void 29721308Sacheget_term_capabilities (bp) 29821308Sache char **bp; 29921308Sache{ 30021308Sache register int i; 30121308Sache 30221308Sache for (i = 0; i < NUM_TC_STRINGS; i++) 30321308Sache *(tc_strings[i].tc_value) = tgetstr (tc_strings[i].tc_var, bp); 30421308Sache tcap_initialized = 1; 30521308Sache} 30621308Sache 30721308Sacheint 30821308Sache_rl_init_terminal_io (terminal_name) 30921308Sache char *terminal_name; 31021308Sache{ 31121308Sache#if defined (__GO32__) 31221308Sache screenwidth = ScreenCols (); 31321308Sache screenheight = ScreenRows (); 31421308Sache screenchars = screenwidth * screenheight; 31521308Sache term_cr = "\r"; 31621308Sache term_im = term_ei = term_ic = term_IC = (char *)NULL; 31721308Sache term_up = term_dc = term_DC = visible_bell = (char *)NULL; 31821308Sache 31921308Sache /* Does the __GO32__ have a meta key? I don't know. */ 32021308Sache term_has_meta = 0; 32121308Sache term_mm = term_mo = (char *)NULL; 32221308Sache 32321308Sache /* It probably has arrow keys, but I don't know what they are. */ 32421308Sache term_ku = term_kd = term_kr = term_kl = (char *)NULL; 32521308Sache 32621308Sache#if defined (HACK_TERMCAP_MOTION) 32721308Sache term_forward_char = (char *)NULL; 32821308Sache#endif /* HACK_TERMCAP_MOTION */ 32921308Sache terminal_can_insert = _rl_term_autowrap = 0; 33021308Sache return; 33121308Sache#else /* !__GO32__ */ 33221308Sache 33321308Sache char *term, *buffer; 33421308Sache int tty; 33521308Sache Keymap xkeymap; 33621308Sache 33721308Sache term = terminal_name ? terminal_name : getenv ("TERM"); 33821308Sache 33921308Sache if (term_string_buffer == 0) 34021308Sache term_string_buffer = xmalloc (2032); 34121308Sache 34221308Sache if (term_buffer == 0) 34321308Sache term_buffer = xmalloc (4080); 34421308Sache 34521308Sache buffer = term_string_buffer; 34621308Sache 34721308Sache term_clrpag = term_cr = term_clreol = (char *)NULL; 34821308Sache 34921308Sache if (term == 0) 35021308Sache term = "dumb"; 35121308Sache 35221308Sache if (tgetent (term_buffer, term) <= 0) 35321308Sache { 35421308Sache dumb_term = 1; 35521308Sache screenwidth = 79; 35621308Sache screenheight = 24; 35721308Sache screenchars = 79 * 24; 35821308Sache term_cr = "\r"; 35921308Sache term_im = term_ei = term_ic = term_IC = (char *)NULL; 36021308Sache term_up = term_dc = term_DC = visible_bell = (char *)NULL; 36121308Sache term_ku = term_kd = term_kl = term_kr = (char *)NULL; 36221308Sache#if defined (HACK_TERMCAP_MOTION) 36321308Sache term_forward_char = (char *)NULL; 36421308Sache#endif 36521308Sache terminal_can_insert = 0; 36621308Sache return 0; 36721308Sache } 36821308Sache 36921308Sache get_term_capabilities (&buffer); 37021308Sache 37121308Sache /* Set up the variables that the termcap library expects the application 37221308Sache to provide. */ 37321308Sache PC = term_pc ? *term_pc : 0; 37421308Sache BC = term_backspace; 37521308Sache UP = term_up; 37621308Sache 37721308Sache if (!term_cr) 37821308Sache term_cr = "\r"; 37921308Sache 38021308Sache tty = rl_instream ? fileno (rl_instream) : 0; 38121308Sache 38221308Sache screenwidth = screenheight = 0; 38321308Sache 38421308Sache _rl_term_autowrap = tgetflag ("am") && tgetflag ("xn"); 38521308Sache 38621308Sache _rl_get_screen_size (tty, 0); 38721308Sache 38821308Sache /* "An application program can assume that the terminal can do 38921308Sache character insertion if *any one of* the capabilities `IC', 39021308Sache `im', `ic' or `ip' is provided." But we can't do anything if 39121308Sache only `ip' is provided, so... */ 39221308Sache terminal_can_insert = (term_IC || term_im || term_ic); 39321308Sache 39421308Sache /* Check to see if this terminal has a meta key and clear the capability 39521308Sache variables if there is none. */ 39621308Sache term_has_meta = (tgetflag ("km") || tgetflag ("MT")); 39721308Sache if (!term_has_meta) 39821308Sache term_mm = term_mo = (char *)NULL; 39921308Sache 40021308Sache /* Attempt to find and bind the arrow keys. Do not override already 40121308Sache bound keys in an overzealous attempt, however. */ 40221308Sache xkeymap = _rl_keymap; 40321308Sache 40421308Sache _rl_keymap = emacs_standard_keymap; 40521308Sache _rl_bind_if_unbound (term_ku, rl_get_previous_history); 40621308Sache _rl_bind_if_unbound (term_kd, rl_get_next_history); 40721308Sache _rl_bind_if_unbound (term_kr, rl_forward); 40821308Sache _rl_bind_if_unbound (term_kl, rl_backward); 40921308Sache 41021308Sache _rl_bind_if_unbound (term_kh, rl_beg_of_line); /* Home */ 41121308Sache _rl_bind_if_unbound (term_kH, rl_end_of_line); /* End */ 41221308Sache 41321308Sache#if defined (VI_MODE) 41421308Sache _rl_keymap = vi_movement_keymap; 41521308Sache _rl_bind_if_unbound (term_ku, rl_get_previous_history); 41621308Sache _rl_bind_if_unbound (term_kd, rl_get_next_history); 41721308Sache _rl_bind_if_unbound (term_kr, rl_forward); 41821308Sache _rl_bind_if_unbound (term_kl, rl_backward); 41921308Sache 42021308Sache _rl_bind_if_unbound (term_kh, rl_beg_of_line); /* Home */ 42121308Sache _rl_bind_if_unbound (term_kH, rl_end_of_line); /* End */ 42221308Sache#endif /* VI_MODE */ 42321308Sache 42421308Sache _rl_keymap = xkeymap; 42521308Sache 42621308Sache#endif /* !__GO32__ */ 42721308Sache return 0; 42821308Sache} 42921308Sache 43021308Sachechar * 43121308Sacherl_get_termcap (cap) 43221308Sache char *cap; 43321308Sache{ 43421308Sache register int i; 43521308Sache 43621308Sache if (tcap_initialized == 0) 43721308Sache return ((char *)NULL); 43821308Sache for (i = 0; i < NUM_TC_STRINGS; i++) 43921308Sache { 44021308Sache if (tc_strings[i].tc_var[0] == cap[0] && strcmp (tc_strings[i].tc_var, cap) == 0) 44121308Sache return *(tc_strings[i].tc_value); 44221308Sache } 44321308Sache return ((char *)NULL); 44421308Sache} 44521308Sache 44621308Sache/* A function for the use of tputs () */ 44721308Sacheint 44821308Sache_rl_output_character_function (c) 44921308Sache int c; 45021308Sache{ 45121308Sache return putc (c, _rl_out_stream); 45221308Sache} 45321308Sache 45421308Sache/* Write COUNT characters from STRING to the output stream. */ 45521308Sachevoid 45621308Sache_rl_output_some_chars (string, count) 45721308Sache char *string; 45821308Sache int count; 45921308Sache{ 46021308Sache fwrite (string, 1, count, _rl_out_stream); 46121308Sache} 46221308Sache 46321308Sache/* Move the cursor back. */ 46421308Sacheint 46521308Sache_rl_backspace (count) 46621308Sache int count; 46721308Sache{ 46821308Sache register int i; 46921308Sache 47021308Sache#if !defined (__GO32__) 47121308Sache if (term_backspace) 47221308Sache for (i = 0; i < count; i++) 47321308Sache tputs (term_backspace, 1, _rl_output_character_function); 47421308Sache else 47521308Sache#endif /* !__GO32__ */ 47621308Sache for (i = 0; i < count; i++) 47721308Sache putc ('\b', _rl_out_stream); 47821308Sache return 0; 47921308Sache} 48021308Sache 48121308Sache/* Move to the start of the next line. */ 48221308Sacheint 48321308Sachecrlf () 48421308Sache{ 48521308Sache#if defined (NEW_TTY_DRIVER) 48621308Sache if (term_cr) 48721308Sache tputs (term_cr, 1, _rl_output_character_function); 48821308Sache#endif /* NEW_TTY_DRIVER */ 48921308Sache putc ('\n', _rl_out_stream); 49021308Sache return 0; 49121308Sache} 49221308Sache 49321308Sache/* Ring the terminal bell. */ 49421308Sacheint 49521308Sacheding () 49621308Sache{ 49721308Sache if (readline_echoing_p) 49821308Sache { 49921308Sache#if !defined (__GO32__) 50021308Sache switch (_rl_bell_preference) 50121308Sache { 50221308Sache case NO_BELL: 50321308Sache default: 50421308Sache break; 50521308Sache case VISIBLE_BELL: 50621308Sache if (visible_bell) 50721308Sache { 50821308Sache tputs (visible_bell, 1, _rl_output_character_function); 50921308Sache break; 51021308Sache } 51121308Sache /* FALLTHROUGH */ 51221308Sache case AUDIBLE_BELL: 51321308Sache fprintf (stderr, "\007"); 51421308Sache fflush (stderr); 51521308Sache break; 51621308Sache } 51721308Sache#else /* __GO32__ */ 51821308Sache fprintf (stderr, "\007"); 51921308Sache fflush (stderr); 52021308Sache#endif /* __GO32__ */ 52121308Sache return (0); 52221308Sache } 52321308Sache return (-1); 52421308Sache} 52521308Sache 52621308Sache/* **************************************************************** */ 52721308Sache/* */ 52821308Sache/* Controlling the Meta Key and Keypad */ 52921308Sache/* */ 53021308Sache/* **************************************************************** */ 53121308Sache 53221308Sachestatic int 53321308Sacheoutchar (c) 53421308Sache int c; 53521308Sache{ 53621308Sache return putc (c, rl_outstream); 53721308Sache} 53821308Sache 53921308Sacheint 54021308Sache_rl_enable_meta_key () 54121308Sache{ 54221308Sache if (term_has_meta && term_mm) 54321308Sache tputs (term_mm, 1, outchar); 54421308Sache} 54521308Sache 54621308Sachevoid 54721308Sache_rl_control_keypad (on) 54821308Sache int on; 54921308Sache{ 55021308Sache if (on && term_ks) 55121308Sache tputs (term_ks, 1, outchar); 55221308Sache else if (!on && term_ke) 55321308Sache tputs (term_ke, 1, outchar); 55421308Sache} 555