lib_setup.c revision 97049
143967Sache/**************************************************************************** 26527Sache * Copyright (c) 1998,1999,2000,2001 Free Software Foundation, Inc. * 36527Sache * * 46527Sache * Permission is hereby granted, free of charge, to any person obtaining a * 56527Sache * copy of this software and associated documentation files (the * 66527Sache * "Software"), to deal in the Software without restriction, including * 76527Sache * without limitation the rights to use, copy, modify, merge, publish, * 86527Sache * distribute, distribute with modifications, sublicense, and/or sell * 96527Sache * copies of the Software, and to permit persons to whom the Software is * 106527Sache * furnished to do so, subject to the following conditions: * 116527Sache * * 126527Sache * The above copyright notice and this permission notice shall be included * 136527Sache * in all copies or substantial portions of the Software. * 146527Sache * * 156527Sache * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS * 166527Sache * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF * 176527Sache * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. * 186527Sache * IN NO EVENT SHALL THE ABOVE COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, * 196527Sache * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR * 206527Sache * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR * 216527Sache * THE USE OR OTHER DEALINGS IN THE SOFTWARE. * 226527Sache * * 236527Sache * Except as contained in this notice, the name(s) of the above copyright * 246527Sache * holders shall not be used in advertising or otherwise to promote the * 256527Sache * sale, use or other dealings in this Software without prior written * 266527Sache * authorization. * 276527Sache ****************************************************************************/ 286527Sache 296527Sache/**************************************************************************** 3087243Smarkm * Author: Zeyd M. Ben-Halim <zmbenhal@netcom.com> 1992,1995 * 3187243Smarkm * and: Eric S. Raymond <esr@snark.thyrsus.com> * 3287243Smarkm ****************************************************************************/ 33175038Simp 3418950Sache/* 356527Sache * Terminal setup routines common to termcap and terminfo: 36101867Sache * 376527Sache * use_env(bool) 386527Sache * setupterm(char *, int, int *) 396527Sache */ 4087012Sache 4116073Sphk#include <curses.priv.h> 426527Sache#include <tic.h> /* for MAX_NAME_SIZE */ 4343967Sache#include <term_entry.h> 4487052Sache 456527Sache#if SVR4_TERMIO && !defined(_POSIX_SOURCE) 466527Sache#define _POSIX_SOURCE 476527Sache#endif 486527Sache 496527Sache#include <term.h> /* lines, columns, cur_term */ 5087243Smarkm 516527SacheMODULE_ID("$Id: lib_setup.c,v 1.68 2001/12/08 22:14:18 tom Exp $") 526527Sache 5343967Sache/**************************************************************************** 5443967Sache * 5543967Sache * Terminal size computation 5643967Sache * 576527Sache ****************************************************************************/ 586527Sache 5918950Sache#if HAVE_SIZECHANGE 6043967Sache# if !defined(sun) || !TERMIOS 6143967Sache# if HAVE_SYS_IOCTL_H 6243967Sache# include <sys/ioctl.h> 6343967Sache# endif 6443967Sache# endif 6543967Sache#endif 6643967Sache 6743967Sache#if NEED_PTEM_H 6818950Sache /* On SCO, they neglected to define struct winsize in termios.h -- it's only 6918950Sache * in termio.h and ptem.h (the former conflicts with other definitions). 7018950Sache */ 7118950Sache# include <sys/stream.h> 7218950Sache# include <sys/ptem.h> 7318950Sache#endif 7418950Sache 7518950Sache/* 7618950Sache * SCO defines TIOCGSIZE and the corresponding struct. Other systems (SunOS, 7718950Sache * Solaris, IRIX) define TIOCGWINSZ and struct winsize. 7818950Sache */ 7918950Sache#ifdef TIOCGSIZE 8018950Sache# define IOCTL_WINSIZE TIOCGSIZE 8118950Sache# define STRUCT_WINSIZE struct ttysize 8243967Sache# define WINSIZE_ROWS(n) (int)n.ts_lines 8318950Sache# define WINSIZE_COLS(n) (int)n.ts_cols 8418950Sache#else 8518950Sache# ifdef TIOCGWINSZ 8643967Sache# define IOCTL_WINSIZE TIOCGWINSZ 876527Sache# define STRUCT_WINSIZE struct winsize 886527Sache# define WINSIZE_ROWS(n) (int)n.ws_row 896527Sache# define WINSIZE_COLS(n) (int)n.ws_col 906527Sache# endif 916527Sache#endif 926527Sache 93102299Sachestatic int _use_env = TRUE; 946527Sache 956527Sachestatic void do_prototype(void); 966527Sache 976527SacheNCURSES_EXPORT(void) 986527Sacheuse_env(bool f) 996527Sache{ 100102299Sache T((T_CALLED("use_env()"))); 101102299Sache _use_env = f; 10251890Sache returnVoid; 10318950Sache} 10418950Sache 10518950SacheNCURSES_EXPORT_VAR(int) LINES = 0; 10618950SacheNCURSES_EXPORT_VAR(int) COLS = 0; 10718950SacheNCURSES_EXPORT_VAR(int) TABSIZE = 0; 10818950Sache 10918950Sachestatic void 11018950Sache_nc_get_screensize(int *linep, int *colp) 11118950Sache/* Obtain lines/columns values from the environment and/or terminfo entry */ 11218950Sache{ 1136527Sache /* figure out the size of the screen */ 11443940Sache T(("screen size: terminfo lines = %d columns = %d", lines, columns)); 1156527Sache 11618950Sache if (!_use_env) { 11718950Sache *linep = (int) lines; 11818950Sache *colp = (int) columns; 11918950Sache } else { /* usually want to query LINES and COLUMNS from environment */ 12043940Sache int value; 12118950Sache 1226527Sache *linep = *colp = 0; 1236527Sache 1246527Sache /* first, look for environment variables */ 1256527Sache if ((value = _nc_getenv_num("LINES")) > 0) { 12643940Sache *linep = value; 1276527Sache } 1286527Sache if ((value = _nc_getenv_num("COLUMNS")) > 0) { 1296527Sache *colp = value; 1306527Sache } 13118955Sache T(("screen size: environment LINES = %d COLUMNS = %d", *linep, *colp)); 13218955Sache 13318950Sache#ifdef __EMX__ 13418955Sache if (*linep <= 0 || *colp <= 0) { 13518950Sache int screendata[2]; 1366527Sache _scrsize(screendata); 13787052Sache *colp = screendata[0]; 13818955Sache *linep = screendata[1]; 13918955Sache T(("EMX screen size: environment LINES = %d COLUMNS = %d", 14087052Sache *linep, *colp)); 14118955Sache } 14218955Sache#endif 14387052Sache#if HAVE_SIZECHANGE 14418955Sache /* if that didn't work, maybe we can try asking the OS */ 14543967Sache if (*linep <= 0 || *colp <= 0) { 14643967Sache if (isatty(cur_term->Filedes)) { 14743967Sache STRUCT_WINSIZE size; 14843967Sache 14918955Sache errno = 0; 1506527Sache do { 1516527Sache if (ioctl(cur_term->Filedes, IOCTL_WINSIZE, &size) < 0 1526527Sache && errno != EINTR) 1536527Sache goto failure; 15443967Sache } while 1556527Sache (errno == EINTR); 1566527Sache 15718950Sache /* 15887243Smarkm * Solaris lets users override either dimension with an 15918950Sache * environment variable. 16018950Sache */ 16118950Sache if (*linep <= 0) 16218950Sache *linep = WINSIZE_ROWS(size); 1636527Sache if (*colp <= 0) 16443940Sache *colp = WINSIZE_COLS(size); 16518950Sache } 1666527Sache /* FALLTHRU */ 1676527Sache failure:; 16818950Sache } 1696527Sache#endif /* HAVE_SIZECHANGE */ 17043940Sache 1716527Sache /* if we can't get dynamic info about the size, use static */ 1726527Sache if (*linep <= 0) { 1736527Sache *linep = (int) lines; 17418950Sache } 1756527Sache if (*colp <= 0) { 17643940Sache *colp = (int) columns; 1776527Sache } 1786527Sache 1796527Sache /* the ultimate fallback, assume fixed 24x80 size */ 18018950Sache if (*linep <= 0) { 1816527Sache *linep = 24; 18243940Sache } 1836527Sache if (*colp <= 0) { 1846527Sache *colp = 80; 1856527Sache } 18618950Sache 1876527Sache /* 18843940Sache * Put the derived values back in the screen-size caps, so 1896527Sache * tigetnum() and tgetnum() will do the right thing. 1906527Sache */ 1916527Sache lines = (short) (*linep); 19218950Sache columns = (short) (*colp); 1936527Sache } 19443940Sache 1956527Sache T(("screen size is %dx%d", *linep, *colp)); 1966527Sache 1976527Sache if (VALID_NUMERIC(init_tabs)) 19818950Sache TABSIZE = (int) init_tabs; 1996527Sache else 20043940Sache TABSIZE = 8; 2016527Sache T(("TABSIZE = %d", TABSIZE)); 2026527Sache 2036527Sache} 20418950Sache 2056527Sache#if USE_SIZECHANGE 20643940SacheNCURSES_EXPORT(void) 2076527Sache_nc_update_screensize(void) 2086527Sache{ 2096527Sache int my_lines, my_cols; 21018950Sache 21187243Smarkm _nc_get_screensize(&my_lines, &my_cols); 21218950Sache if (SP != 0 && SP->_resize != 0) 21318950Sache SP->_resize(my_lines, my_cols); 2146527Sache} 21518950Sache#endif 21687243Smarkm 21718950Sache/**************************************************************************** 21818950Sache * 21918950Sache * Terminal setup 22018950Sache * 2216527Sache ****************************************************************************/ 2226527Sache 2236527Sache#define ret_error(code, fmt, arg) if (errret) {\ 2246527Sache *errret = code;\ 2256527Sache returnCode(ERR);\ 22618950Sache } else {\ 2276527Sache fprintf(stderr, fmt, arg);\ 2286527Sache exit(EXIT_FAILURE);\ 2296527Sache } 2306527Sache 2316527Sache#define ret_error0(code, msg) if (errret) {\ 23218950Sache *errret = code;\ 23318950Sache returnCode(ERR);\ 23443940Sache } else {\ 23518950Sache fprintf(stderr, msg);\ 23618950Sache exit(EXIT_FAILURE);\ 23718950Sache } 23818950Sache 23918950Sache#if USE_DATABASE || USE_TERMCAP 24043940Sachestatic int 24118950Sachegrab_entry(const char *const tn, TERMTYPE * const tp) 24218950Sache/* return 1 if entry found, 0 if not found, -1 if database not accessible */ 24318950Sache{ 2446527Sache char filename[PATH_MAX]; 24518950Sache int status; 24618950Sache 24718950Sache /* 24818950Sache * $TERM shouldn't contain pathname delimiters. 24918950Sache */ 25018950Sache if (strchr(tn, '/')) 25118950Sache return 0; 2526527Sache 2536527Sache#if USE_DATABASE 2546527Sache if ((status = _nc_read_entry(tn, filename, tp)) != 1) { 25518950Sache 25618950Sache#if !PURE_TERMINFO 2576527Sache /* 25818950Sache * Try falling back on the termcap file. 25918950Sache * Note: allowing this call links the entire terminfo/termcap 2606527Sache * compiler into the startup code. It's preferable to build a 2616527Sache * real terminfo database and use that. 26218950Sache */ 26318950Sache status = _nc_read_termcap_entry(tn, tp); 26418950Sache#endif /* PURE_TERMINFO */ 26518950Sache 26618950Sache } 26718950Sache#else 26818950Sache status = _nc_read_termcap_entry(tn, tp); 26918950Sache#endif 2706527Sache 2716527Sache /* 2726527Sache * If we have an entry, force all of the cancelled strings to null 27318950Sache * pointers so we don't have to test them in the rest of the library. 27418950Sache * (The terminfo compiler bypasses this logic, since it must know if 27518950Sache * a string is cancelled, for merging entries). 27618950Sache */ 2776527Sache if (status == 1) { 2786527Sache int n; 2796527Sache for_each_boolean(n, tp) { 2806527Sache if (!VALID_BOOLEAN(tp->Booleans[n])) 2816527Sache tp->Booleans[n] = FALSE; 2826527Sache } 2836527Sache for_each_string(n, tp) { 2846527Sache if (tp->Strings[n] == CANCELLED_STRING) 2856527Sache tp->Strings[n] = ABSENT_STRING; 2866527Sache } 2876527Sache } 288 return (status); 289} 290#endif 291 292NCURSES_EXPORT_VAR(char) ttytype[NAMESIZE] = ""; 293 294/* 295 * setupterm(termname, Filedes, errret) 296 * 297 * Find and read the appropriate object file for the terminal 298 * Make cur_term point to the structure. 299 * 300 */ 301 302NCURSES_EXPORT(int) 303setupterm(NCURSES_CONST char *tname, int Filedes, int *errret) 304{ 305 struct term *term_ptr; 306 int status; 307 308 T((T_CALLED("setupterm(%s,%d,%p)"), _nc_visbuf(tname), Filedes, errret)); 309 310 if (tname == 0) { 311 tname = getenv("TERM"); 312 if (tname == 0 || *tname == '\0') { 313 ret_error0(-1, "TERM environment variable not set.\n"); 314 } 315 } 316 if (strlen(tname) > MAX_NAME_SIZE) { 317 ret_error(-1, "TERM environment must be <= %d characters.\n", 318 MAX_NAME_SIZE); 319 } 320 321 T(("your terminal name is %s", tname)); 322 323 term_ptr = typeCalloc(TERMINAL, 1); 324 325 if (term_ptr == 0) { 326 ret_error0(-1, "Not enough memory to create terminal structure.\n"); 327 } 328#if USE_DATABASE || USE_TERMCAP 329 status = grab_entry(tname, &term_ptr->type); 330#else 331 status = 0; 332#endif 333 334 /* try fallback list if entry on disk */ 335 if (status != 1) { 336 const TERMTYPE *fallback = _nc_fallback(tname); 337 338 if (fallback) { 339 term_ptr->type = *fallback; 340 status = 1; 341 } 342 } 343 344 if (status == -1) { 345 ret_error0(-1, "terminals database is inaccessible\n"); 346 } else if (status == 0) { 347 ret_error(0, "'%s': unknown terminal type.\n", tname); 348 } 349 350 /* 351 * Improve on SVr4 curses. If an application mixes curses and termcap 352 * calls, it may call both initscr and tgetent. This is not really a 353 * good thing to do, but can happen if someone tries using ncurses with 354 * the readline library. The problem we are fixing is that when 355 * tgetent calls setupterm, the resulting Ottyb struct in cur_term is 356 * zeroed. A subsequent call to endwin uses the zeroed terminal 357 * settings rather than the ones saved in initscr. So we check if 358 * cur_term appears to contain terminal settings for the same output 359 * file as our current call - and copy those terminal settings. (SVr4 360 * curses does not do this, however applications that are working 361 * around the problem will still work properly with this feature). 362 */ 363 if (cur_term != 0) { 364 if (cur_term->Filedes == Filedes) 365 term_ptr->Ottyb = cur_term->Ottyb; 366 } 367 368 set_curterm(term_ptr); 369 370 if (command_character && getenv("CC")) 371 do_prototype(); 372 373 strncpy(ttytype, cur_term->type.term_names, NAMESIZE - 1); 374 ttytype[NAMESIZE - 1] = '\0'; 375 376 /* 377 * Allow output redirection. This is what SVr3 does. 378 * If stdout is directed to a file, screen updates go 379 * to standard error. 380 */ 381 if (Filedes == STDOUT_FILENO && !isatty(Filedes)) 382 Filedes = STDERR_FILENO; 383 cur_term->Filedes = Filedes; 384 385 _nc_get_screensize(&LINES, &COLS); 386 387 if (errret) 388 *errret = 1; 389 390 T((T_CREATE("screen %s %dx%d"), tname, LINES, COLS)); 391 392 if (generic_type) { 393 ret_error(0, "'%s': I need something more specific.\n", tname); 394 } 395 if (hard_copy) { 396 ret_error(1, "'%s': I can't handle hardcopy terminals.\n", tname); 397 } 398 returnCode(OK); 399} 400 401/* 402** do_prototype() 403** 404** Take the real command character out of the CC environment variable 405** and substitute it in for the prototype given in 'command_character'. 406** 407*/ 408 409static void 410do_prototype(void) 411{ 412 int i; 413 char CC; 414 char proto; 415 char *tmp; 416 417 tmp = getenv("CC"); 418 CC = *tmp; 419 proto = *command_character; 420 421 for_each_string(i, &(cur_term->type)) { 422 for (tmp = cur_term->type.Strings[i]; *tmp; tmp++) { 423 if (*tmp == proto) 424 *tmp = CC; 425 } 426 } 427} 428