terminal.c revision 58314
158314Sache/* $FreeBSD: head/contrib/libreadline/terminal.c 58314 2000-03-19 22:00:57Z ache $ */ 221308Sache/* terminal.c -- controlling the terminal with termcap. */ 321308Sache 421308Sache/* Copyright (C) 1996 Free Software Foundation, Inc. 521308Sache 621308Sache This file is part of the GNU Readline Library, a library for 721308Sache reading lines of text with interactive input and history editing. 821308Sache 921308Sache The GNU Readline Library is free software; you can redistribute it 1021308Sache and/or modify it under the terms of the GNU General Public License 1158314Sache as published by the Free Software Foundation; either version 2, or 1221308Sache (at your option) any later version. 1321308Sache 1421308Sache The GNU Readline Library is distributed in the hope that it will be 1521308Sache useful, but WITHOUT ANY WARRANTY; without even the implied warranty 1621308Sache of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 1721308Sache GNU General Public License for more details. 1821308Sache 1921308Sache The GNU General Public License is often shipped with GNU software, and 2021308Sache is generally kept in a file called COPYING or LICENSE. If you do not 2121308Sache have a copy of the license, write to the Free Software Foundation, 2258314Sache 59 Temple Place, Suite 330, Boston, MA 02111 USA. */ 2321308Sache#define READLINE_LIBRARY 2421308Sache 2521308Sache#if defined (HAVE_CONFIG_H) 2621308Sache# include <config.h> 2721308Sache#endif 2821308Sache 2921308Sache#include <sys/types.h> 3021308Sache#include "posixstat.h" 3121308Sache#include <fcntl.h> 3221308Sache#if defined (HAVE_SYS_FILE_H) 3321308Sache# include <sys/file.h> 3421308Sache#endif /* HAVE_SYS_FILE_H */ 3521308Sache 3621308Sache#if defined (HAVE_UNISTD_H) 3721308Sache# include <unistd.h> 3821308Sache#endif /* HAVE_UNISTD_H */ 3921308Sache 4021308Sache#if defined (HAVE_STDLIB_H) 4121308Sache# include <stdlib.h> 4221308Sache#else 4321308Sache# include "ansi_stdlib.h" 4421308Sache#endif /* HAVE_STDLIB_H */ 4521308Sache 4621308Sache#if defined (HAVE_LOCALE_H) 4721308Sache# include <locale.h> 4821308Sache#endif 4921308Sache 5021308Sache#include <stdio.h> 5121308Sache 5221308Sache/* System-specific feature definitions and include files. */ 5321308Sache#include "rldefs.h" 5421308Sache 5526497Sache#if defined (GWINSZ_IN_SYS_IOCTL) && !defined (TIOCGWINSZ) 5626497Sache# include <sys/ioctl.h> 5726497Sache#endif /* GWINSZ_IN_SYS_IOCTL && !TIOCGWINSZ */ 5826497Sache 5926497Sache#include "rltty.h" 6021308Sache#include "tcap.h" 6121308Sache 6221308Sache/* Some standard library routines. */ 6321308Sache#include "readline.h" 6421308Sache#include "history.h" 6521308Sache 6658314Sache#include "rlprivate.h" 6758314Sache#include "rlshell.h" 6821308Sache 6921308Sache/* **************************************************************** */ 7021308Sache/* */ 7121308Sache/* Terminal and Termcap */ 7221308Sache/* */ 7321308Sache/* **************************************************************** */ 7421308Sache 7521308Sachestatic char *term_buffer = (char *)NULL; 7621308Sachestatic char *term_string_buffer = (char *)NULL; 7721308Sache 7821308Sachestatic int tcap_initialized; 7921308Sache 8021308Sache/* Non-zero means this terminal can't really do anything. */ 8121308Sachestatic int dumb_term; 8221308Sache 8321308Sache#if !defined (__linux__) 8426497Sache# if defined (__EMX__) || defined (NEED_EXTERN_PC) 8526497Sacheextern 8626497Sache# endif /* __EMX__ || NEED_EXTERN_PC */ 8726497Sachechar PC, *BC, *UP; 8821308Sache#endif /* __linux__ */ 8921308Sache 9021308Sache/* Some strings to control terminal actions. These are output by tputs (). */ 9121308Sachechar *term_goto, *term_clreol, *term_cr, *term_clrpag, *term_backspace; 9221308Sachechar *term_pc; 9321308Sache 9421308Sache/* Non-zero if we determine that the terminal can do character insertion. */ 9521308Sacheint terminal_can_insert = 0; 9621308Sache 9721308Sache/* How to insert characters. */ 9821308Sachechar *term_im, *term_ei, *term_ic, *term_ip, *term_IC; 9921308Sache 10021308Sache/* How to delete characters. */ 10121308Sachechar *term_dc, *term_DC; 10221308Sache 10321308Sache#if defined (HACK_TERMCAP_MOTION) 10421308Sachechar *term_forward_char; 10521308Sache#endif /* HACK_TERMCAP_MOTION */ 10621308Sache 10721308Sache/* How to go up a line. */ 10821308Sachechar *term_up; 10921308Sache 11021308Sache/* A visible bell, if the terminal can be made to flash the screen. */ 11121308Sachestatic char *visible_bell; 11221308Sache 11321308Sache/* Non-zero means the terminal can auto-wrap lines. */ 11421308Sacheint _rl_term_autowrap; 11521308Sache 11621308Sache/* Non-zero means that this terminal has a meta key. */ 11721308Sachestatic int term_has_meta; 11821308Sache 11921308Sache/* The sequences to write to turn on and off the meta key, if this 12021308Sache terminal has one. */ 12121308Sachestatic char *term_mm, *term_mo; 12221308Sache 12321308Sache/* The key sequences output by the arrow keys, if this terminal has any. */ 12421308Sachestatic char *term_ku, *term_kd, *term_kr, *term_kl; 12521308Sache 12621308Sache/* How to initialize and reset the arrow keys, if this terminal has any. */ 12721308Sachestatic char *term_ks, *term_ke; 12821308Sache 12921308Sache/* The key sequences sent by the Home and End keys, if any. */ 13021308Sachestatic char *term_kh, *term_kH; 13121308Sache 13221308Sache/* Variables that hold the screen dimensions, used by the display code. */ 13321308Sacheint screenwidth, screenheight, screenchars; 13421308Sache 13521308Sache/* Non-zero means the user wants to enable the keypad. */ 13621308Sacheint _rl_enable_keypad; 13721308Sache 13821308Sache/* Non-zero means the user wants to enable a meta key. */ 13921308Sacheint _rl_enable_meta = 1; 14021308Sache 14158314Sache#if defined (__EMX__) 14258314Sachestatic void 14358314Sache_emx_get_screensize (swp, shp) 14458314Sache int *swp, *shp; 14558314Sache{ 14658314Sache int sz[2]; 14758314Sache 14858314Sache _scrsize (sz); 14958314Sache 15058314Sache if (swp) 15158314Sache *swp = sz[0]; 15258314Sache if (shp) 15358314Sache *shp = sz[1]; 15458314Sache} 15558314Sache#endif 15658314Sache 15721308Sache/* Get readline's idea of the screen size. TTY is a file descriptor open 15821308Sache to the terminal. If IGNORE_ENV is true, we do not pay attention to the 15921308Sache values of $LINES and $COLUMNS. The tests for TERM_STRING_BUFFER being 16021308Sache non-null serve to check whether or not we have initialized termcap. */ 16121308Sachevoid 16221308Sache_rl_get_screen_size (tty, ignore_env) 16321308Sache int tty, ignore_env; 16421308Sache{ 16521308Sache char *ss; 16621308Sache#if defined (TIOCGWINSZ) 16721308Sache struct winsize window_size; 16821308Sache#endif /* TIOCGWINSZ */ 16921308Sache 17021308Sache#if defined (TIOCGWINSZ) 17121308Sache if (ioctl (tty, TIOCGWINSZ, &window_size) == 0) 17221308Sache { 17321308Sache screenwidth = (int) window_size.ws_col; 17421308Sache screenheight = (int) window_size.ws_row; 17521308Sache } 17621308Sache#endif /* TIOCGWINSZ */ 17721308Sache 17826497Sache#if defined (__EMX__) 17958314Sache _emx_get_screensize (&screenwidth, &screenheight); 18026497Sache#endif 18126497Sache 18221308Sache /* Environment variable COLUMNS overrides setting of "co" if IGNORE_ENV 18321308Sache is unset. */ 18421308Sache if (screenwidth <= 0) 18521308Sache { 18626497Sache if (ignore_env == 0 && (ss = get_env_value ("COLUMNS"))) 18721308Sache screenwidth = atoi (ss); 18821308Sache 18958314Sache#if !defined (__DJGPP__) 19021308Sache if (screenwidth <= 0 && term_string_buffer) 19121308Sache screenwidth = tgetnum ("co"); 19258314Sache#endif 19321308Sache } 19421308Sache 19521308Sache /* Environment variable LINES overrides setting of "li" if IGNORE_ENV 19621308Sache is unset. */ 19721308Sache if (screenheight <= 0) 19821308Sache { 19926497Sache if (ignore_env == 0 && (ss = get_env_value ("LINES"))) 20021308Sache screenheight = atoi (ss); 20121308Sache 20258314Sache#if !defined (__DJGPP__) 20321308Sache if (screenheight <= 0 && term_string_buffer) 20421308Sache screenheight = tgetnum ("li"); 20558314Sache#endif 20621308Sache } 20721308Sache 20821308Sache /* If all else fails, default to 80x24 terminal. */ 20921308Sache if (screenwidth <= 1) 21021308Sache screenwidth = 80; 21121308Sache 21221308Sache if (screenheight <= 0) 21321308Sache screenheight = 24; 21421308Sache 21521308Sache /* If we're being compiled as part of bash, set the environment 21621308Sache variables $LINES and $COLUMNS to new values. Otherwise, just 21721308Sache do a pair of putenv () or setenv () calls. */ 21821308Sache set_lines_and_columns (screenheight, screenwidth); 21921308Sache 22058314Sache if (_rl_term_autowrap == 0) 22121308Sache screenwidth--; 22221308Sache 22321308Sache screenchars = screenwidth * screenheight; 22421308Sache} 22521308Sache 22621308Sachevoid 22721308Sache_rl_set_screen_size (rows, cols) 22821308Sache int rows, cols; 22921308Sache{ 23021308Sache screenheight = rows; 23121308Sache screenwidth = cols; 23221308Sache 23321308Sache if (_rl_term_autowrap == 0) 23421308Sache screenwidth--; 23521308Sache 23621308Sache screenchars = screenwidth * screenheight; 23721308Sache} 23821308Sache 23947558Sachevoid 24047558Sacherl_resize_terminal () 24147558Sache{ 24247558Sache if (readline_echoing_p) 24347558Sache { 24447558Sache _rl_get_screen_size (fileno (rl_instream), 1); 24547558Sache _rl_redisplay_after_sigwinch (); 24647558Sache } 24747558Sache} 24847558Sache 24921308Sachestruct _tc_string { 25021308Sache char *tc_var; 25121308Sache char **tc_value; 25221308Sache}; 25321308Sache 25421308Sache/* This should be kept sorted, just in case we decide to change the 25521308Sache search algorithm to something smarter. */ 25621308Sachestatic struct _tc_string tc_strings[] = 25721308Sache{ 25858314Sache { "DC", &term_DC }, 25958314Sache { "IC", &term_IC }, 26058314Sache { "ce", &term_clreol }, 26158314Sache { "cl", &term_clrpag }, 26258314Sache { "cr", &term_cr }, 26358314Sache { "dc", &term_dc }, 26458314Sache { "ei", &term_ei }, 26558314Sache { "ic", &term_ic }, 26658314Sache { "im", &term_im }, 26758314Sache { "kd", &term_kd }, 26858314Sache { "kh", &term_kh }, /* home */ 26958314Sache { "@7", &term_kH }, /* end */ 27058314Sache { "kl", &term_kl }, 27158314Sache { "kr", &term_kr }, 27258314Sache { "ku", &term_ku }, 27358314Sache { "ks", &term_ks }, 27458314Sache { "ke", &term_ke }, 27558314Sache { "le", &term_backspace }, 27658314Sache { "mm", &term_mm }, 27758314Sache { "mo", &term_mo }, 27821308Sache#if defined (HACK_TERMCAP_MOTION) 27958314Sache { "nd", &term_forward_char }, 28021308Sache#endif 28158314Sache { "pc", &term_pc }, 28258314Sache { "up", &term_up }, 28358314Sache { "vb", &visible_bell }, 28421308Sache}; 28521308Sache 28621308Sache#define NUM_TC_STRINGS (sizeof (tc_strings) / sizeof (struct _tc_string)) 28721308Sache 28821308Sache/* Read the desired terminal capability strings into BP. The capabilities 28921308Sache are described in the TC_STRINGS table. */ 29021308Sachestatic void 29121308Sacheget_term_capabilities (bp) 29221308Sache char **bp; 29321308Sache{ 29458314Sache#if !defined (__DJGPP__) /* XXX - doesn't DJGPP have a termcap library? */ 29521308Sache register int i; 29621308Sache 29721308Sache for (i = 0; i < NUM_TC_STRINGS; i++) 29821308Sache *(tc_strings[i].tc_value) = tgetstr (tc_strings[i].tc_var, bp); 29958314Sache#endif 30021308Sache tcap_initialized = 1; 30121308Sache} 30221308Sache 30358314Sache#define CUSTOM_REDISPLAY_FUNC() (rl_redisplay_function != rl_redisplay) 30458314Sache#define CUSTOM_INPUT_FUNC() (rl_getc_function != rl_getc) 30558314Sache 30621308Sacheint 30721308Sache_rl_init_terminal_io (terminal_name) 30821308Sache char *terminal_name; 30921308Sache{ 31021308Sache char *term, *buffer; 31158314Sache int tty, tgetent_ret; 31221308Sache Keymap xkeymap; 31321308Sache 31426497Sache term = terminal_name ? terminal_name : get_env_value ("TERM"); 31558314Sache term_clrpag = term_cr = term_clreol = (char *)NULL; 31658314Sache tty = rl_instream ? fileno (rl_instream) : 0; 31758314Sache screenwidth = screenheight = 0; 31821308Sache 31958314Sache if (term == 0) 32058314Sache term = "dumb"; 32121308Sache 32258314Sache /* I've separated this out for later work on not calling tgetent at all 32358314Sache if the calling application has supplied a custom redisplay function, 32458314Sache (and possibly if the application has supplied a custom input function). */ 32558314Sache if (CUSTOM_REDISPLAY_FUNC()) 32658314Sache { 32758314Sache tgetent_ret = -1; 32858314Sache } 32958314Sache else 33058314Sache { 33158314Sache if (term_string_buffer == 0) 33258314Sache term_string_buffer = xmalloc(2032); 33321308Sache 33458314Sache if (term_buffer == 0) 33558314Sache term_buffer = xmalloc(4080); 33621308Sache 33758314Sache buffer = term_string_buffer; 33821308Sache 33958314Sache tgetent_ret = tgetent (term_buffer, term); 34058314Sache } 34121308Sache 34258314Sache if (tgetent_ret <= 0) 34321308Sache { 34458314Sache FREE (term_string_buffer); 34558314Sache FREE (term_buffer); 34658314Sache buffer = term_buffer = term_string_buffer = (char *)NULL; 34758314Sache 34821308Sache dumb_term = 1; 34958314Sache _rl_term_autowrap = 0; /* used by _rl_get_screen_size */ 35058314Sache 35158314Sache#if defined (__EMX__) 35258314Sache _emx_get_screensize (&screenwidth, &screenheight); 35358314Sache screenwidth--; 35458314Sache#else /* !__EMX__ */ 35558314Sache _rl_get_screen_size (tty, 0); 35658314Sache#endif /* !__EMX__ */ 35758314Sache 35858314Sache /* Defaults. */ 35958314Sache if (screenwidth <= 0 || screenheight <= 0) 36058314Sache { 36158314Sache screenwidth = 79; 36258314Sache screenheight = 24; 36358314Sache } 36458314Sache 36558314Sache /* Everything below here is used by the redisplay code (tputs). */ 36658314Sache screenchars = screenwidth * screenheight; 36721308Sache term_cr = "\r"; 36821308Sache term_im = term_ei = term_ic = term_IC = (char *)NULL; 36921308Sache term_up = term_dc = term_DC = visible_bell = (char *)NULL; 37021308Sache term_ku = term_kd = term_kl = term_kr = (char *)NULL; 37158314Sache term_mm = term_mo = (char *)NULL; 37221308Sache#if defined (HACK_TERMCAP_MOTION) 37321308Sache term_forward_char = (char *)NULL; 37421308Sache#endif 37558314Sache terminal_can_insert = term_has_meta = 0; 37658314Sache 37758314Sache /* Reasonable defaults for tgoto(). Readline currently only uses 37858314Sache tgoto if term_IC or term_DC is defined, but just in case we 37958314Sache change that later... */ 38058314Sache PC = '\0'; 38158314Sache BC = term_backspace = "\b"; 38258314Sache UP = term_up; 38358314Sache 38421308Sache return 0; 38521308Sache } 38621308Sache 38721308Sache get_term_capabilities (&buffer); 38821308Sache 38921308Sache /* Set up the variables that the termcap library expects the application 39021308Sache to provide. */ 39121308Sache PC = term_pc ? *term_pc : 0; 39221308Sache BC = term_backspace; 39321308Sache UP = term_up; 39421308Sache 39521308Sache if (!term_cr) 39621308Sache term_cr = "\r"; 39721308Sache 39821308Sache _rl_term_autowrap = tgetflag ("am") && tgetflag ("xn"); 39921308Sache 40021308Sache _rl_get_screen_size (tty, 0); 40121308Sache 40221308Sache /* "An application program can assume that the terminal can do 40321308Sache character insertion if *any one of* the capabilities `IC', 40421308Sache `im', `ic' or `ip' is provided." But we can't do anything if 40521308Sache only `ip' is provided, so... */ 40621308Sache terminal_can_insert = (term_IC || term_im || term_ic); 40721308Sache 40821308Sache /* Check to see if this terminal has a meta key and clear the capability 40921308Sache variables if there is none. */ 41021308Sache term_has_meta = (tgetflag ("km") || tgetflag ("MT")); 41121308Sache if (!term_has_meta) 41221308Sache term_mm = term_mo = (char *)NULL; 41321308Sache 41421308Sache /* Attempt to find and bind the arrow keys. Do not override already 41521308Sache bound keys in an overzealous attempt, however. */ 41621308Sache xkeymap = _rl_keymap; 41721308Sache 41821308Sache _rl_keymap = emacs_standard_keymap; 41921308Sache _rl_bind_if_unbound (term_ku, rl_get_previous_history); 42021308Sache _rl_bind_if_unbound (term_kd, rl_get_next_history); 42121308Sache _rl_bind_if_unbound (term_kr, rl_forward); 42221308Sache _rl_bind_if_unbound (term_kl, rl_backward); 42321308Sache 42421308Sache _rl_bind_if_unbound (term_kh, rl_beg_of_line); /* Home */ 42521308Sache _rl_bind_if_unbound (term_kH, rl_end_of_line); /* End */ 42621308Sache 42721308Sache#if defined (VI_MODE) 42821308Sache _rl_keymap = vi_movement_keymap; 42921308Sache _rl_bind_if_unbound (term_ku, rl_get_previous_history); 43021308Sache _rl_bind_if_unbound (term_kd, rl_get_next_history); 43121308Sache _rl_bind_if_unbound (term_kr, rl_forward); 43221308Sache _rl_bind_if_unbound (term_kl, rl_backward); 43321308Sache 43421308Sache _rl_bind_if_unbound (term_kh, rl_beg_of_line); /* Home */ 43521308Sache _rl_bind_if_unbound (term_kH, rl_end_of_line); /* End */ 43621308Sache#endif /* VI_MODE */ 43721308Sache 43821308Sache _rl_keymap = xkeymap; 43921308Sache 44021308Sache return 0; 44121308Sache} 44221308Sache 44321308Sachechar * 44421308Sacherl_get_termcap (cap) 44521308Sache char *cap; 44621308Sache{ 44721308Sache register int i; 44821308Sache 44921308Sache if (tcap_initialized == 0) 45021308Sache return ((char *)NULL); 45121308Sache for (i = 0; i < NUM_TC_STRINGS; i++) 45221308Sache { 45321308Sache if (tc_strings[i].tc_var[0] == cap[0] && strcmp (tc_strings[i].tc_var, cap) == 0) 45421308Sache return *(tc_strings[i].tc_value); 45521308Sache } 45621308Sache return ((char *)NULL); 45721308Sache} 45821308Sache 45926497Sache/* Re-initialize the terminal considering that the TERM/TERMCAP variable 46026497Sache has changed. */ 46126497Sacheint 46226497Sacherl_reset_terminal (terminal_name) 46326497Sache char *terminal_name; 46426497Sache{ 46526497Sache _rl_init_terminal_io (terminal_name); 46626497Sache return 0; 46726497Sache} 46826497Sache 46921308Sache/* A function for the use of tputs () */ 47035486Sache#ifdef _MINIX 47135486Sachevoid 47235486Sache_rl_output_character_function (c) 47335486Sache int c; 47435486Sache{ 47535486Sache putc (c, _rl_out_stream); 47635486Sache} 47735486Sache#else /* !_MINIX */ 47821308Sacheint 47921308Sache_rl_output_character_function (c) 48021308Sache int c; 48121308Sache{ 48221308Sache return putc (c, _rl_out_stream); 48321308Sache} 48435486Sache#endif /* !_MINIX */ 48558314Sache 48621308Sache/* Write COUNT characters from STRING to the output stream. */ 48721308Sachevoid 48821308Sache_rl_output_some_chars (string, count) 48921308Sache char *string; 49021308Sache int count; 49121308Sache{ 49221308Sache fwrite (string, 1, count, _rl_out_stream); 49321308Sache} 49421308Sache 49521308Sache/* Move the cursor back. */ 49621308Sacheint 49721308Sache_rl_backspace (count) 49821308Sache int count; 49921308Sache{ 50021308Sache register int i; 50121308Sache 50221308Sache if (term_backspace) 50321308Sache for (i = 0; i < count; i++) 50421308Sache tputs (term_backspace, 1, _rl_output_character_function); 50521308Sache else 50621308Sache for (i = 0; i < count; i++) 50721308Sache putc ('\b', _rl_out_stream); 50821308Sache return 0; 50921308Sache} 51021308Sache 51121308Sache/* Move to the start of the next line. */ 51221308Sacheint 51321308Sachecrlf () 51421308Sache{ 51521308Sache#if defined (NEW_TTY_DRIVER) 51621308Sache if (term_cr) 51721308Sache tputs (term_cr, 1, _rl_output_character_function); 51821308Sache#endif /* NEW_TTY_DRIVER */ 51921308Sache putc ('\n', _rl_out_stream); 52021308Sache return 0; 52121308Sache} 52221308Sache 52321308Sache/* Ring the terminal bell. */ 52421308Sacheint 52521308Sacheding () 52621308Sache{ 52721308Sache if (readline_echoing_p) 52821308Sache { 52921308Sache switch (_rl_bell_preference) 53021308Sache { 53121308Sache case NO_BELL: 53221308Sache default: 53321308Sache break; 53421308Sache case VISIBLE_BELL: 53521308Sache if (visible_bell) 53621308Sache { 53721308Sache tputs (visible_bell, 1, _rl_output_character_function); 53821308Sache break; 53921308Sache } 54021308Sache /* FALLTHROUGH */ 54121308Sache case AUDIBLE_BELL: 54221308Sache fprintf (stderr, "\007"); 54321308Sache fflush (stderr); 54421308Sache break; 54521308Sache } 54621308Sache return (0); 54721308Sache } 54821308Sache return (-1); 54921308Sache} 55021308Sache 55121308Sache/* **************************************************************** */ 55221308Sache/* */ 55321308Sache/* Controlling the Meta Key and Keypad */ 55421308Sache/* */ 55521308Sache/* **************************************************************** */ 55621308Sache 55726497Sachevoid 55821308Sache_rl_enable_meta_key () 55921308Sache{ 56058314Sache#if !defined (__DJGPP__) 56121308Sache if (term_has_meta && term_mm) 56235486Sache tputs (term_mm, 1, _rl_output_character_function); 56358314Sache#endif 56421308Sache} 56521308Sache 56621308Sachevoid 56721308Sache_rl_control_keypad (on) 56821308Sache int on; 56921308Sache{ 57058314Sache#if !defined (__DJGPP__) 57121308Sache if (on && term_ks) 57235486Sache tputs (term_ks, 1, _rl_output_character_function); 57321308Sache else if (!on && term_ke) 57435486Sache tputs (term_ke, 1, _rl_output_character_function); 57558314Sache#endif 57621308Sache} 577