lib_setup.c revision 66963
150276Speter/**************************************************************************** 262449Speter * Copyright (c) 1998,1999,2000 Free Software Foundation, Inc. * 350276Speter * * 450276Speter * Permission is hereby granted, free of charge, to any person obtaining a * 550276Speter * copy of this software and associated documentation files (the * 650276Speter * "Software"), to deal in the Software without restriction, including * 750276Speter * without limitation the rights to use, copy, modify, merge, publish, * 850276Speter * distribute, distribute with modifications, sublicense, and/or sell * 950276Speter * copies of the Software, and to permit persons to whom the Software is * 1050276Speter * furnished to do so, subject to the following conditions: * 1150276Speter * * 1250276Speter * The above copyright notice and this permission notice shall be included * 1350276Speter * in all copies or substantial portions of the Software. * 1450276Speter * * 1550276Speter * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS * 1650276Speter * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF * 1750276Speter * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. * 1850276Speter * IN NO EVENT SHALL THE ABOVE COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, * 1950276Speter * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR * 2050276Speter * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR * 2150276Speter * THE USE OR OTHER DEALINGS IN THE SOFTWARE. * 2250276Speter * * 2350276Speter * Except as contained in this notice, the name(s) of the above copyright * 2450276Speter * holders shall not be used in advertising or otherwise to promote the * 2550276Speter * sale, use or other dealings in this Software without prior written * 2650276Speter * authorization. * 2750276Speter ****************************************************************************/ 2850276Speter 2950276Speter/**************************************************************************** 3050276Speter * Author: Zeyd M. Ben-Halim <zmbenhal@netcom.com> 1992,1995 * 3150276Speter * and: Eric S. Raymond <esr@snark.thyrsus.com> * 3250276Speter ****************************************************************************/ 3350276Speter 3450276Speter/* 3550276Speter * Terminal setup routines common to termcap and terminfo: 3650276Speter * 3750276Speter * use_env(bool) 3850276Speter * setupterm(char *, int, int *) 3950276Speter */ 4050276Speter 4150276Speter#include <curses.priv.h> 4262449Speter#include <tic.h> /* for MAX_NAME_SIZE */ 4350276Speter#include <term_entry.h> 4450276Speter 4566963Speter#if SVR4_TERMIO && !defined(_POSIX_SOURCE) 4650276Speter#define _POSIX_SOURCE 4750276Speter#endif 4850276Speter 4962449Speter#include <term.h> /* lines, columns, cur_term */ 5050276Speter 5166963SpeterMODULE_ID("$Id: lib_setup.c,v 1.60 2000/09/02 18:13:12 tom Exp $") 5250276Speter 5350276Speter/**************************************************************************** 5450276Speter * 5550276Speter * Terminal size computation 5650276Speter * 5750276Speter ****************************************************************************/ 5850276Speter 5950276Speter#if HAVE_SIZECHANGE 6050276Speter# if !defined(sun) || !TERMIOS 6150276Speter# if HAVE_SYS_IOCTL_H 6250276Speter# include <sys/ioctl.h> 6350276Speter# endif 6450276Speter# endif 6550276Speter#endif 6650276Speter 6750276Speter#if NEED_PTEM_H 6850276Speter /* On SCO, they neglected to define struct winsize in termios.h -- it's only 6950276Speter * in termio.h and ptem.h (the former conflicts with other definitions). 7050276Speter */ 7150276Speter# include <sys/stream.h> 7250276Speter# include <sys/ptem.h> 7350276Speter#endif 7450276Speter 7550276Speter/* 7650276Speter * SCO defines TIOCGSIZE and the corresponding struct. Other systems (SunOS, 7750276Speter * Solaris, IRIX) define TIOCGWINSZ and struct winsize. 7850276Speter */ 7950276Speter#ifdef TIOCGSIZE 8050276Speter# define IOCTL_WINSIZE TIOCGSIZE 8150276Speter# define STRUCT_WINSIZE struct ttysize 8250276Speter# define WINSIZE_ROWS(n) (int)n.ts_lines 8350276Speter# define WINSIZE_COLS(n) (int)n.ts_cols 8450276Speter#else 8550276Speter# ifdef TIOCGWINSZ 8650276Speter# define IOCTL_WINSIZE TIOCGWINSZ 8750276Speter# define STRUCT_WINSIZE struct winsize 8850276Speter# define WINSIZE_ROWS(n) (int)n.ws_row 8950276Speter# define WINSIZE_COLS(n) (int)n.ws_col 9050276Speter# endif 9150276Speter#endif 9250276Speter 9350276Speterstatic int _use_env = TRUE; 9450276Speter 9550276Speterstatic void do_prototype(void); 9650276Speter 9762449Spetervoid 9862449Speteruse_env(bool f) 9950276Speter{ 10062449Speter _use_env = f; 10150276Speter} 10250276Speter 10362449Speterint LINES = 0, COLS = 0, TABSIZE = 0; 10450276Speter 10562449Speterstatic void 10662449Speter_nc_get_screensize(int *linep, int *colp) 10750276Speter/* Obtain lines/columns values from the environment and/or terminfo entry */ 10850276Speter{ 10962449Speter /* figure out the size of the screen */ 11062449Speter T(("screen size: terminfo lines = %d columns = %d", lines, columns)); 11150276Speter 11262449Speter if (!_use_env) { 11362449Speter *linep = (int) lines; 11462449Speter *colp = (int) columns; 11562449Speter } else { /* usually want to query LINES and COLUMNS from environment */ 11662449Speter int value; 11750276Speter 11862449Speter *linep = *colp = 0; 11950276Speter 12062449Speter /* first, look for environment variables */ 12162449Speter if ((value = _nc_getenv_num("LINES")) > 0) { 12262449Speter *linep = value; 12362449Speter } 12462449Speter if ((value = _nc_getenv_num("COLUMNS")) > 0) { 12562449Speter *colp = value; 12662449Speter } 12762449Speter T(("screen size: environment LINES = %d COLUMNS = %d", *linep, *colp)); 12850276Speter 12950276Speter#ifdef __EMX__ 13062449Speter if (*linep <= 0 || *colp <= 0) { 13162449Speter int screendata[2]; 13262449Speter _scrsize(screendata); 13362449Speter *colp = screendata[0]; 13462449Speter *linep = screendata[1]; 13562449Speter T(("EMX screen size: environment LINES = %d COLUMNS = %d", 13662449Speter *linep, *colp)); 13762449Speter } 13850276Speter#endif 13950276Speter#if HAVE_SIZECHANGE 14062449Speter /* if that didn't work, maybe we can try asking the OS */ 14162449Speter if (*linep <= 0 || *colp <= 0) { 14262449Speter if (isatty(cur_term->Filedes)) { 14362449Speter STRUCT_WINSIZE size; 14450276Speter 14562449Speter errno = 0; 14662449Speter do { 14762449Speter if (ioctl(cur_term->Filedes, IOCTL_WINSIZE, &size) < 0 14862449Speter && errno != EINTR) 14962449Speter goto failure; 15062449Speter } while 15162449Speter (errno == EINTR); 15250276Speter 15362449Speter /* 15462449Speter * Solaris lets users override either dimension with an 15562449Speter * environment variable. 15662449Speter */ 15762449Speter if (*linep <= 0) 15862449Speter *linep = WINSIZE_ROWS(size); 15962449Speter if (*colp <= 0) 16062449Speter *colp = WINSIZE_COLS(size); 16150276Speter } 16262449Speter /* FALLTHRU */ 16362449Speter failure:; 16462449Speter } 16550276Speter#endif /* HAVE_SIZECHANGE */ 16650276Speter 16762449Speter /* if we can't get dynamic info about the size, use static */ 16862449Speter if (*linep <= 0 || *colp <= 0) 16962449Speter if (lines > 0 && columns > 0) { 17062449Speter *linep = (int) lines; 17162449Speter *colp = (int) columns; 17250276Speter } 17350276Speter 17462449Speter /* the ultimate fallback, assume fixed 24x80 size */ 17562449Speter if (*linep <= 0 || *colp <= 0) { 17662449Speter *linep = 24; 17762449Speter *colp = 80; 17850276Speter } 17950276Speter 18062449Speter /* 18162449Speter * Put the derived values back in the screen-size caps, so 18262449Speter * tigetnum() and tgetnum() will do the right thing. 18362449Speter */ 18462449Speter lines = (short) (*linep); 18562449Speter columns = (short) (*colp); 18662449Speter } 18750276Speter 18862449Speter T(("screen size is %dx%d", *linep, *colp)); 18950276Speter 19062449Speter if (VALID_NUMERIC(init_tabs)) 19162449Speter TABSIZE = (int) init_tabs; 19262449Speter else 19362449Speter TABSIZE = 8; 19462449Speter T(("TABSIZE = %d", TABSIZE)); 19562449Speter 19650276Speter} 19750276Speter 19850276Speter#if USE_SIZECHANGE 19962449Spetervoid 20062449Speter_nc_update_screensize(void) 20150276Speter{ 20262449Speter int my_lines, my_cols; 20350276Speter 20462449Speter _nc_get_screensize(&my_lines, &my_cols); 20562449Speter if (SP != 0 && SP->_resize != 0) 20662449Speter SP->_resize(my_lines, my_cols); 20750276Speter} 20850276Speter#endif 20950276Speter 21050276Speter/**************************************************************************** 21150276Speter * 21250276Speter * Terminal setup 21350276Speter * 21450276Speter ****************************************************************************/ 21550276Speter 21650276Speter#define ret_error(code, fmt, arg) if (errret) {\ 21750276Speter *errret = code;\ 21850276Speter returnCode(ERR);\ 21950276Speter } else {\ 22050276Speter fprintf(stderr, fmt, arg);\ 22150276Speter exit(EXIT_FAILURE);\ 22250276Speter } 22350276Speter 22450276Speter#define ret_error0(code, msg) if (errret) {\ 22550276Speter *errret = code;\ 22650276Speter returnCode(ERR);\ 22750276Speter } else {\ 22850276Speter fprintf(stderr, msg);\ 22950276Speter exit(EXIT_FAILURE);\ 23050276Speter } 23150276Speter 23250276Speter#if USE_DATABASE 23362449Speterstatic int 23462449Spetergrab_entry(const char *const tn, TERMTYPE * const tp) 23550276Speter/* return 1 if entry found, 0 if not found, -1 if database not accessible */ 23650276Speter{ 23762449Speter char filename[PATH_MAX]; 23862449Speter int status; 23950276Speter 24062449Speter /* 24162449Speter * $TERM shouldn't contain pathname delimiters. 24262449Speter */ 24362449Speter if (strchr(tn, '/')) 24462449Speter return 0; 24550276Speter 24662449Speter if ((status = _nc_read_entry(tn, filename, tp)) != 1) { 24750276Speter 24866963Speter#if !PURE_TERMINFO 24962449Speter /* 25062449Speter * Try falling back on the termcap file. 25162449Speter * Note: allowing this call links the entire terminfo/termcap 25262449Speter * compiler into the startup code. It's preferable to build a 25362449Speter * real terminfo database and use that. 25462449Speter */ 25562449Speter status = _nc_read_termcap_entry(tn, tp); 25650276Speter#endif /* PURE_TERMINFO */ 25750276Speter 25862449Speter } 25950276Speter 26062449Speter /* 26162449Speter * If we have an entry, force all of the cancelled strings to null 26262449Speter * pointers so we don't have to test them in the rest of the library. 26362449Speter * (The terminfo compiler bypasses this logic, since it must know if 26462449Speter * a string is cancelled, for merging entries). 26562449Speter */ 26662449Speter if (status == 1) { 26762449Speter int n; 26862449Speter for_each_boolean(n, tp) 26962449Speter if (!VALID_BOOLEAN(tp->Booleans[n])) 27062449Speter tp->Booleans[n] = FALSE; 27162449Speter for_each_string(n, tp) 27262449Speter if (tp->Strings[n] == CANCELLED_STRING) 27362449Speter tp->Strings[n] = ABSENT_STRING; 27462449Speter } 27562449Speter return (status); 27650276Speter} 27750276Speter#endif 27850276Speter 27962449Speterchar ttytype[NAMESIZE] = ""; 28050276Speter 28150276Speter/* 28250276Speter * setupterm(termname, Filedes, errret) 28350276Speter * 28450276Speter * Find and read the appropriate object file for the terminal 28550276Speter * Make cur_term point to the structure. 28650276Speter * 28750276Speter */ 28850276Speter 28962449Speterint 29062449Spetersetupterm(NCURSES_CONST char *tname, int Filedes, int *errret) 29150276Speter{ 29262449Speter struct term *term_ptr; 29362449Speter int status; 29450276Speter 29562449Speter T((T_CALLED("setupterm(%s,%d,%p)"), _nc_visbuf(tname), Filedes, errret)); 29650276Speter 29762449Speter if (tname == 0) { 29862449Speter tname = getenv("TERM"); 29962449Speter if (tname == 0 || *tname == '\0') { 30062449Speter ret_error0(-1, "TERM environment variable not set.\n"); 30150276Speter } 30262449Speter } 30362449Speter if (strlen(tname) > MAX_NAME_SIZE) { 30462449Speter ret_error(-1, "TERM environment must be <= %d characters.\n", 30562449Speter MAX_NAME_SIZE); 30662449Speter } 30750276Speter 30862449Speter T(("your terminal name is %s", tname)); 30950276Speter 31062449Speter term_ptr = typeCalloc(TERMINAL, 1); 31150276Speter 31262449Speter if (term_ptr == 0) { 31362449Speter ret_error0(-1, "Not enough memory to create terminal structure.\n"); 31462449Speter } 31550276Speter#if USE_DATABASE 31662449Speter status = grab_entry(tname, &term_ptr->type); 31750276Speter#else 31862449Speter status = 0; 31950276Speter#endif 32050276Speter 32162449Speter /* try fallback list if entry on disk */ 32262449Speter if (status != 1) { 32362449Speter const TERMTYPE *fallback = _nc_fallback(tname); 32450276Speter 32562449Speter if (fallback) { 32662449Speter term_ptr->type = *fallback; 32762449Speter status = 1; 32850276Speter } 32962449Speter } 33050276Speter 33162449Speter if (status == -1) { 33262449Speter ret_error0(-1, "terminals database is inaccessible\n"); 33362449Speter } else if (status == 0) { 33462449Speter ret_error(0, "'%s': unknown terminal type.\n", tname); 33562449Speter } 33650276Speter 33762449Speter /* 33862449Speter * Improve on SVr4 curses. If an application mixes curses and termcap 33962449Speter * calls, it may call both initscr and tgetent. This is not really a 34062449Speter * good thing to do, but can happen if someone tries using ncurses with 34162449Speter * the readline library. The problem we are fixing is that when 34262449Speter * tgetent calls setupterm, the resulting Ottyb struct in cur_term is 34362449Speter * zeroed. A subsequent call to endwin uses the zeroed terminal 34462449Speter * settings rather than the ones saved in initscr. So we check if 34562449Speter * cur_term appears to contain terminal settings for the same output 34662449Speter * file as our current call - and copy those terminal settings. (SVr4 34762449Speter * curses does not do this, however applications that are working 34862449Speter * around the problem will still work properly with this feature). 34962449Speter */ 35062449Speter if (cur_term != 0) { 35162449Speter if (cur_term->Filedes == Filedes) 35262449Speter term_ptr->Ottyb = cur_term->Ottyb; 35362449Speter } 35450276Speter 35562449Speter set_curterm(term_ptr); 35650276Speter 35762449Speter if (command_character && getenv("CC")) 35862449Speter do_prototype(); 35950276Speter 36062449Speter strncpy(ttytype, cur_term->type.term_names, NAMESIZE - 1); 36162449Speter ttytype[NAMESIZE - 1] = '\0'; 36250276Speter 36362449Speter /* 36462449Speter * Allow output redirection. This is what SVr3 does. 36562449Speter * If stdout is directed to a file, screen updates go 36662449Speter * to standard error. 36762449Speter */ 36862449Speter if (Filedes == STDOUT_FILENO && !isatty(Filedes)) 36962449Speter Filedes = STDERR_FILENO; 37062449Speter cur_term->Filedes = Filedes; 37150276Speter 37262449Speter _nc_get_screensize(&LINES, &COLS); 37350276Speter 37462449Speter if (errret) 37562449Speter *errret = 1; 37650276Speter 37762449Speter T((T_CREATE("screen %s %dx%d"), tname, LINES, COLS)); 37850276Speter 37962449Speter if (generic_type) { 38062449Speter ret_error(0, "'%s': I need something more specific.\n", tname); 38162449Speter } 38262449Speter if (hard_copy) { 38362449Speter ret_error(1, "'%s': I can't handle hardcopy terminals.\n", tname); 38462449Speter } 38562449Speter returnCode(OK); 38650276Speter} 38750276Speter 38850276Speter/* 38950276Speter** do_prototype() 39050276Speter** 39150276Speter** Take the real command character out of the CC environment variable 39250276Speter** and substitute it in for the prototype given in 'command_character'. 39350276Speter** 39450276Speter*/ 39550276Speter 39650276Speterstatic void 39750276Speterdo_prototype(void) 39850276Speter{ 39962449Speter int i; 40062449Speter char CC; 40162449Speter char proto; 40262449Speter char *tmp; 40350276Speter 40462449Speter tmp = getenv("CC"); 40562449Speter CC = *tmp; 40662449Speter proto = *command_character; 40750276Speter 40862449Speter for_each_string(i, &(cur_term->type)) { 40962449Speter for (tmp = cur_term->type.Strings[i]; *tmp; tmp++) { 41062449Speter if (*tmp == proto) 41162449Speter *tmp = CC; 41250276Speter } 41362449Speter } 41450276Speter} 415