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