terminal.c revision 26497
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 5626497Sache#if defined (GWINSZ_IN_SYS_IOCTL) && !defined (TIOCGWINSZ) 5726497Sache# include <sys/ioctl.h> 5826497Sache#endif /* GWINSZ_IN_SYS_IOCTL && !TIOCGWINSZ */ 5926497Sache 6026497Sache#include "rltty.h" 6121308Sache#include "tcap.h" 6221308Sache 6321308Sache/* Some standard library routines. */ 6421308Sache#include "readline.h" 6521308Sache#include "history.h" 6621308Sache 6721308Sache/* Variables and functions imported from readline.c */ 6821308Sacheextern FILE *_rl_in_stream, *_rl_out_stream; 6921308Sacheextern int readline_echoing_p; 7021308Sacheextern int _rl_bell_preference; 7121308Sacheextern Keymap _rl_keymap; 7221308Sache 7326497Sache/* Functions imported from bind.c */ 7426497Sacheextern void _rl_bind_if_unbound (); 7526497Sache 7626497Sache/* Functions imported from shell.c */ 7726497Sacheextern void set_lines_and_columns (); 7826497Sacheextern char *get_env_value (); 7926497Sache 8021308Sache/* **************************************************************** */ 8121308Sache/* */ 8221308Sache/* Terminal and Termcap */ 8321308Sache/* */ 8421308Sache/* **************************************************************** */ 8521308Sache 8621308Sachestatic char *term_buffer = (char *)NULL; 8721308Sachestatic char *term_string_buffer = (char *)NULL; 8821308Sache 8921308Sachestatic int tcap_initialized; 9021308Sache 9121308Sache/* Non-zero means this terminal can't really do anything. */ 9221308Sachestatic int dumb_term; 9321308Sache 9421308Sache#if !defined (__linux__) 9526497Sache# if defined (__EMX__) || defined (NEED_EXTERN_PC) 9626497Sacheextern 9726497Sache# endif /* __EMX__ || NEED_EXTERN_PC */ 9826497Sachechar PC, *BC, *UP; 9921308Sache#endif /* __linux__ */ 10021308Sache 10121308Sache/* Some strings to control terminal actions. These are output by tputs (). */ 10221308Sachechar *term_goto, *term_clreol, *term_cr, *term_clrpag, *term_backspace; 10321308Sachechar *term_pc; 10421308Sache 10521308Sache/* Non-zero if we determine that the terminal can do character insertion. */ 10621308Sacheint terminal_can_insert = 0; 10721308Sache 10821308Sache/* How to insert characters. */ 10921308Sachechar *term_im, *term_ei, *term_ic, *term_ip, *term_IC; 11021308Sache 11121308Sache/* How to delete characters. */ 11221308Sachechar *term_dc, *term_DC; 11321308Sache 11421308Sache#if defined (HACK_TERMCAP_MOTION) 11521308Sachechar *term_forward_char; 11621308Sache#endif /* HACK_TERMCAP_MOTION */ 11721308Sache 11821308Sache/* How to go up a line. */ 11921308Sachechar *term_up; 12021308Sache 12121308Sache/* A visible bell, if the terminal can be made to flash the screen. */ 12221308Sachestatic char *visible_bell; 12321308Sache 12421308Sache/* Non-zero means the terminal can auto-wrap lines. */ 12521308Sacheint _rl_term_autowrap; 12621308Sache 12721308Sache/* Non-zero means that this terminal has a meta key. */ 12821308Sachestatic int term_has_meta; 12921308Sache 13021308Sache/* The sequences to write to turn on and off the meta key, if this 13121308Sache terminal has one. */ 13221308Sachestatic char *term_mm, *term_mo; 13321308Sache 13421308Sache/* The key sequences output by the arrow keys, if this terminal has any. */ 13521308Sachestatic char *term_ku, *term_kd, *term_kr, *term_kl; 13621308Sache 13721308Sache/* How to initialize and reset the arrow keys, if this terminal has any. */ 13821308Sachestatic char *term_ks, *term_ke; 13921308Sache 14021308Sache/* The key sequences sent by the Home and End keys, if any. */ 14121308Sachestatic char *term_kh, *term_kH; 14221308Sache 14321308Sache/* Variables that hold the screen dimensions, used by the display code. */ 14421308Sacheint screenwidth, screenheight, screenchars; 14521308Sache 14621308Sache/* Non-zero means the user wants to enable the keypad. */ 14721308Sacheint _rl_enable_keypad; 14821308Sache 14921308Sache/* Non-zero means the user wants to enable a meta key. */ 15021308Sacheint _rl_enable_meta = 1; 15121308Sache 15221308Sache/* Get readline's idea of the screen size. TTY is a file descriptor open 15321308Sache to the terminal. If IGNORE_ENV is true, we do not pay attention to the 15421308Sache values of $LINES and $COLUMNS. The tests for TERM_STRING_BUFFER being 15521308Sache non-null serve to check whether or not we have initialized termcap. */ 15621308Sachevoid 15721308Sache_rl_get_screen_size (tty, ignore_env) 15821308Sache int tty, ignore_env; 15921308Sache{ 16021308Sache char *ss; 16121308Sache#if defined (TIOCGWINSZ) 16221308Sache struct winsize window_size; 16321308Sache#endif /* TIOCGWINSZ */ 16426497Sache#if defined (__EMX__) 16526497Sache int sz[2]; 16626497Sache#endif 16721308Sache 16821308Sache#if defined (TIOCGWINSZ) 16921308Sache if (ioctl (tty, TIOCGWINSZ, &window_size) == 0) 17021308Sache { 17121308Sache screenwidth = (int) window_size.ws_col; 17221308Sache screenheight = (int) window_size.ws_row; 17321308Sache } 17421308Sache#endif /* TIOCGWINSZ */ 17521308Sache 17626497Sache#if defined (__EMX__) 17726497Sache _scrsize (sz); 17826497Sache screenwidth = sz[0]; 17926497Sache screenheight = sz[1]; 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 18921308Sache if (screenwidth <= 0 && term_string_buffer) 19021308Sache screenwidth = tgetnum ("co"); 19121308Sache } 19221308Sache 19321308Sache /* Environment variable LINES overrides setting of "li" if IGNORE_ENV 19421308Sache is unset. */ 19521308Sache if (screenheight <= 0) 19621308Sache { 19726497Sache if (ignore_env == 0 && (ss = get_env_value ("LINES"))) 19821308Sache screenheight = atoi (ss); 19921308Sache 20021308Sache if (screenheight <= 0 && term_string_buffer) 20121308Sache screenheight = tgetnum ("li"); 20221308Sache } 20321308Sache 20421308Sache /* If all else fails, default to 80x24 terminal. */ 20521308Sache if (screenwidth <= 1) 20621308Sache screenwidth = 80; 20721308Sache 20821308Sache if (screenheight <= 0) 20921308Sache screenheight = 24; 21021308Sache 21121308Sache /* If we're being compiled as part of bash, set the environment 21221308Sache variables $LINES and $COLUMNS to new values. Otherwise, just 21321308Sache do a pair of putenv () or setenv () calls. */ 21421308Sache set_lines_and_columns (screenheight, screenwidth); 21521308Sache 21621308Sache if (!_rl_term_autowrap) 21721308Sache screenwidth--; 21821308Sache 21921308Sache screenchars = screenwidth * screenheight; 22021308Sache} 22121308Sache 22221308Sachevoid 22321308Sache_rl_set_screen_size (rows, cols) 22421308Sache int rows, cols; 22521308Sache{ 22621308Sache screenheight = rows; 22721308Sache screenwidth = cols; 22821308Sache 22921308Sache if (_rl_term_autowrap == 0) 23021308Sache screenwidth--; 23121308Sache 23221308Sache screenchars = screenwidth * screenheight; 23321308Sache} 23421308Sache 23521308Sachestruct _tc_string { 23621308Sache char *tc_var; 23721308Sache char **tc_value; 23821308Sache}; 23921308Sache 24021308Sache/* This should be kept sorted, just in case we decide to change the 24121308Sache search algorithm to something smarter. */ 24221308Sachestatic struct _tc_string tc_strings[] = 24321308Sache{ 24421308Sache "DC", &term_DC, 24521308Sache "IC", &term_IC, 24621308Sache "ce", &term_clreol, 24721308Sache "cl", &term_clrpag, 24821308Sache "cr", &term_cr, 24921308Sache "dc", &term_dc, 25021308Sache "ei", &term_ei, 25121308Sache "ic", &term_ic, 25221308Sache "im", &term_im, 25321308Sache "kd", &term_kd, 25421308Sache "kh", &term_kh, /* home */ 25521308Sache "kH", &term_kH, /* end */ 25621308Sache "kl", &term_kl, 25721308Sache "kr", &term_kr, 25821308Sache "ku", &term_ku, 25921308Sache "ks", &term_ks, 26021308Sache "ke", &term_ke, 26121308Sache "le", &term_backspace, 26221308Sache "mm", &term_mm, 26321308Sache "mo", &term_mo, 26421308Sache#if defined (HACK_TERMCAP_MOTION) 26521308Sache "nd", &term_forward_char, 26621308Sache#endif 26721308Sache "pc", &term_pc, 26821308Sache "up", &term_up, 26921308Sache "vb", &visible_bell, 27021308Sache}; 27121308Sache 27221308Sache#define NUM_TC_STRINGS (sizeof (tc_strings) / sizeof (struct _tc_string)) 27321308Sache 27421308Sache/* Read the desired terminal capability strings into BP. The capabilities 27521308Sache are described in the TC_STRINGS table. */ 27621308Sachestatic void 27721308Sacheget_term_capabilities (bp) 27821308Sache char **bp; 27921308Sache{ 28021308Sache register int i; 28121308Sache 28221308Sache for (i = 0; i < NUM_TC_STRINGS; i++) 28321308Sache *(tc_strings[i].tc_value) = tgetstr (tc_strings[i].tc_var, bp); 28421308Sache tcap_initialized = 1; 28521308Sache} 28621308Sache 28721308Sacheint 28821308Sache_rl_init_terminal_io (terminal_name) 28921308Sache char *terminal_name; 29021308Sache{ 29121308Sache#if defined (__GO32__) 29221308Sache screenwidth = ScreenCols (); 29321308Sache screenheight = ScreenRows (); 29421308Sache screenchars = screenwidth * screenheight; 29521308Sache term_cr = "\r"; 29621308Sache term_im = term_ei = term_ic = term_IC = (char *)NULL; 29721308Sache term_up = term_dc = term_DC = visible_bell = (char *)NULL; 29821308Sache 29921308Sache /* Does the __GO32__ have a meta key? I don't know. */ 30021308Sache term_has_meta = 0; 30121308Sache term_mm = term_mo = (char *)NULL; 30221308Sache 30321308Sache /* It probably has arrow keys, but I don't know what they are. */ 30421308Sache term_ku = term_kd = term_kr = term_kl = (char *)NULL; 30521308Sache 30621308Sache#if defined (HACK_TERMCAP_MOTION) 30721308Sache term_forward_char = (char *)NULL; 30821308Sache#endif /* HACK_TERMCAP_MOTION */ 30921308Sache terminal_can_insert = _rl_term_autowrap = 0; 31021308Sache return; 31121308Sache#else /* !__GO32__ */ 31221308Sache 31321308Sache char *term, *buffer; 31421308Sache int tty; 31521308Sache Keymap xkeymap; 31621308Sache 31726497Sache term = terminal_name ? terminal_name : get_env_value ("TERM"); 31821308Sache 31921308Sache if (term_string_buffer == 0) 32021308Sache term_string_buffer = xmalloc (2032); 32121308Sache 32221308Sache if (term_buffer == 0) 32321308Sache term_buffer = xmalloc (4080); 32421308Sache 32521308Sache buffer = term_string_buffer; 32621308Sache 32721308Sache term_clrpag = term_cr = term_clreol = (char *)NULL; 32821308Sache 32921308Sache if (term == 0) 33021308Sache term = "dumb"; 33121308Sache 33221308Sache if (tgetent (term_buffer, term) <= 0) 33321308Sache { 33421308Sache dumb_term = 1; 33521308Sache screenwidth = 79; 33621308Sache screenheight = 24; 33721308Sache screenchars = 79 * 24; 33821308Sache term_cr = "\r"; 33921308Sache term_im = term_ei = term_ic = term_IC = (char *)NULL; 34021308Sache term_up = term_dc = term_DC = visible_bell = (char *)NULL; 34121308Sache term_ku = term_kd = term_kl = term_kr = (char *)NULL; 34221308Sache#if defined (HACK_TERMCAP_MOTION) 34321308Sache term_forward_char = (char *)NULL; 34421308Sache#endif 34521308Sache terminal_can_insert = 0; 34621308Sache return 0; 34721308Sache } 34821308Sache 34921308Sache get_term_capabilities (&buffer); 35021308Sache 35121308Sache /* Set up the variables that the termcap library expects the application 35221308Sache to provide. */ 35321308Sache PC = term_pc ? *term_pc : 0; 35421308Sache BC = term_backspace; 35521308Sache UP = term_up; 35621308Sache 35721308Sache if (!term_cr) 35821308Sache term_cr = "\r"; 35921308Sache 36021308Sache tty = rl_instream ? fileno (rl_instream) : 0; 36121308Sache 36221308Sache screenwidth = screenheight = 0; 36321308Sache 36421308Sache _rl_term_autowrap = tgetflag ("am") && tgetflag ("xn"); 36521308Sache 36621308Sache _rl_get_screen_size (tty, 0); 36721308Sache 36821308Sache /* "An application program can assume that the terminal can do 36921308Sache character insertion if *any one of* the capabilities `IC', 37021308Sache `im', `ic' or `ip' is provided." But we can't do anything if 37121308Sache only `ip' is provided, so... */ 37221308Sache terminal_can_insert = (term_IC || term_im || term_ic); 37321308Sache 37421308Sache /* Check to see if this terminal has a meta key and clear the capability 37521308Sache variables if there is none. */ 37621308Sache term_has_meta = (tgetflag ("km") || tgetflag ("MT")); 37721308Sache if (!term_has_meta) 37821308Sache term_mm = term_mo = (char *)NULL; 37921308Sache 38021308Sache /* Attempt to find and bind the arrow keys. Do not override already 38121308Sache bound keys in an overzealous attempt, however. */ 38221308Sache xkeymap = _rl_keymap; 38321308Sache 38421308Sache _rl_keymap = emacs_standard_keymap; 38521308Sache _rl_bind_if_unbound (term_ku, rl_get_previous_history); 38621308Sache _rl_bind_if_unbound (term_kd, rl_get_next_history); 38721308Sache _rl_bind_if_unbound (term_kr, rl_forward); 38821308Sache _rl_bind_if_unbound (term_kl, rl_backward); 38921308Sache 39021308Sache _rl_bind_if_unbound (term_kh, rl_beg_of_line); /* Home */ 39121308Sache _rl_bind_if_unbound (term_kH, rl_end_of_line); /* End */ 39221308Sache 39321308Sache#if defined (VI_MODE) 39421308Sache _rl_keymap = vi_movement_keymap; 39521308Sache _rl_bind_if_unbound (term_ku, rl_get_previous_history); 39621308Sache _rl_bind_if_unbound (term_kd, rl_get_next_history); 39721308Sache _rl_bind_if_unbound (term_kr, rl_forward); 39821308Sache _rl_bind_if_unbound (term_kl, rl_backward); 39921308Sache 40021308Sache _rl_bind_if_unbound (term_kh, rl_beg_of_line); /* Home */ 40121308Sache _rl_bind_if_unbound (term_kH, rl_end_of_line); /* End */ 40221308Sache#endif /* VI_MODE */ 40321308Sache 40421308Sache _rl_keymap = xkeymap; 40521308Sache 40621308Sache#endif /* !__GO32__ */ 40721308Sache return 0; 40821308Sache} 40921308Sache 41021308Sachechar * 41121308Sacherl_get_termcap (cap) 41221308Sache char *cap; 41321308Sache{ 41421308Sache register int i; 41521308Sache 41621308Sache if (tcap_initialized == 0) 41721308Sache return ((char *)NULL); 41821308Sache for (i = 0; i < NUM_TC_STRINGS; i++) 41921308Sache { 42021308Sache if (tc_strings[i].tc_var[0] == cap[0] && strcmp (tc_strings[i].tc_var, cap) == 0) 42121308Sache return *(tc_strings[i].tc_value); 42221308Sache } 42321308Sache return ((char *)NULL); 42421308Sache} 42521308Sache 42626497Sache/* Re-initialize the terminal considering that the TERM/TERMCAP variable 42726497Sache has changed. */ 42826497Sacheint 42926497Sacherl_reset_terminal (terminal_name) 43026497Sache char *terminal_name; 43126497Sache{ 43226497Sache _rl_init_terminal_io (terminal_name); 43326497Sache return 0; 43426497Sache} 43526497Sache 43621308Sache/* A function for the use of tputs () */ 43721308Sacheint 43821308Sache_rl_output_character_function (c) 43921308Sache int c; 44021308Sache{ 44121308Sache return putc (c, _rl_out_stream); 44221308Sache} 44321308Sache 44421308Sache/* Write COUNT characters from STRING to the output stream. */ 44521308Sachevoid 44621308Sache_rl_output_some_chars (string, count) 44721308Sache char *string; 44821308Sache int count; 44921308Sache{ 45021308Sache fwrite (string, 1, count, _rl_out_stream); 45121308Sache} 45221308Sache 45321308Sache/* Move the cursor back. */ 45421308Sacheint 45521308Sache_rl_backspace (count) 45621308Sache int count; 45721308Sache{ 45821308Sache register int i; 45921308Sache 46021308Sache#if !defined (__GO32__) 46121308Sache if (term_backspace) 46221308Sache for (i = 0; i < count; i++) 46321308Sache tputs (term_backspace, 1, _rl_output_character_function); 46421308Sache else 46521308Sache#endif /* !__GO32__ */ 46621308Sache for (i = 0; i < count; i++) 46721308Sache putc ('\b', _rl_out_stream); 46821308Sache return 0; 46921308Sache} 47021308Sache 47121308Sache/* Move to the start of the next line. */ 47221308Sacheint 47321308Sachecrlf () 47421308Sache{ 47521308Sache#if defined (NEW_TTY_DRIVER) 47621308Sache if (term_cr) 47721308Sache tputs (term_cr, 1, _rl_output_character_function); 47821308Sache#endif /* NEW_TTY_DRIVER */ 47921308Sache putc ('\n', _rl_out_stream); 48021308Sache return 0; 48121308Sache} 48221308Sache 48321308Sache/* Ring the terminal bell. */ 48421308Sacheint 48521308Sacheding () 48621308Sache{ 48721308Sache if (readline_echoing_p) 48821308Sache { 48921308Sache#if !defined (__GO32__) 49021308Sache switch (_rl_bell_preference) 49121308Sache { 49221308Sache case NO_BELL: 49321308Sache default: 49421308Sache break; 49521308Sache case VISIBLE_BELL: 49621308Sache if (visible_bell) 49721308Sache { 49821308Sache tputs (visible_bell, 1, _rl_output_character_function); 49921308Sache break; 50021308Sache } 50121308Sache /* FALLTHROUGH */ 50221308Sache case AUDIBLE_BELL: 50321308Sache fprintf (stderr, "\007"); 50421308Sache fflush (stderr); 50521308Sache break; 50621308Sache } 50721308Sache#else /* __GO32__ */ 50821308Sache fprintf (stderr, "\007"); 50921308Sache fflush (stderr); 51021308Sache#endif /* __GO32__ */ 51121308Sache return (0); 51221308Sache } 51321308Sache return (-1); 51421308Sache} 51521308Sache 51621308Sache/* **************************************************************** */ 51721308Sache/* */ 51821308Sache/* Controlling the Meta Key and Keypad */ 51921308Sache/* */ 52021308Sache/* **************************************************************** */ 52121308Sache 52221308Sachestatic int 52321308Sacheoutchar (c) 52421308Sache int c; 52521308Sache{ 52621308Sache return putc (c, rl_outstream); 52721308Sache} 52821308Sache 52926497Sachevoid 53021308Sache_rl_enable_meta_key () 53121308Sache{ 53221308Sache if (term_has_meta && term_mm) 53321308Sache tputs (term_mm, 1, outchar); 53421308Sache} 53521308Sache 53621308Sachevoid 53721308Sache_rl_control_keypad (on) 53821308Sache int on; 53921308Sache{ 54021308Sache if (on && term_ks) 54121308Sache tputs (term_ks, 1, outchar); 54221308Sache else if (!on && term_ke) 54321308Sache tputs (term_ke, 1, outchar); 54421308Sache} 545