
/***************************************************************************
*                            COPYRIGHT NOTICE                              *
****************************************************************************
*                ncurses is copyright (C) 1992-1995                        *
*                          Zeyd M. Ben-Halim                               *
*                          zmbenhal@netcom.com                             *
*                          Eric S. Raymond                                 *
*                          esr@snark.thyrsus.com                           *
*                                                                          *
*        Permission is hereby granted to reproduce and distribute ncurses  *
*        by any means and for any fee, whether alone or as part of a       *
*        larger distribution, in source or in binary form, PROVIDED        *
*        this notice is included with any such distribution, and is not    *
*        removed from any of its header files. Mention of ncurses in any   *
*        applications linked with it is highly appreciated.                *
*                                                                          *
*        ncurses comes AS IS with no warranty, implied or expressed.       *
*                                                                          *
***************************************************************************/


/*
 * Terminal setup routines common to termcap and terminfo:
 *
 *		use_env(bool)
 *		setupterm(char *, int, int *)
 */

#include <curses.priv.h>

#include <string.h>

#ifdef SVR4_TERMIO
#define _POSIX_SOURCE
#endif

#include <term.h>	/* lines, columns, cur_term */

MODULE_ID("$Id: lib_setup.c,v 1.18 1996/09/01 01:35:05 tom Exp $")

/****************************************************************************
 *
 * Terminal size computation
 *
 ****************************************************************************/

#if !defined(sun) || !HAVE_TERMIOS_H
#include <sys/ioctl.h>
#endif

static int _use_env = TRUE;

static void do_prototype(void);

void use_env(bool f)
{
	_use_env = f;
}

int LINES, COLS, TABSIZE;

void _nc_get_screensize(void)
/* set LINES and COLS from the environment and/or terminfo entry */
{
char		*rows, *cols;

	/* figure out the size of the screen */
	T(("screen size: terminfo lines = %d columns = %d", lines, columns));

	if (!_use_env)
	{
	    LINES = (int)lines;
	    COLS  = (int)columns;
	}
	else	/* usually want to query LINES and COLUMNS from environment */
	{
	    LINES = COLS = 0;

	    /* first, look for environment variables */
	    rows = getenv("LINES");
	    if (rows != (char *)NULL)
		LINES = atoi(rows);
	    cols = getenv("COLUMNS");
	    if (cols != (char *)NULL)
		COLS = atoi(cols);
	    T(("screen size: environment LINES = %d COLUMNS = %d",LINES,COLS));

#if defined(TIOCGWINSZ) && !defined(BROKEN_TIOCGWINSZ)
	    /* if that didn't work, maybe we can try asking the OS */
	    if (LINES <= 0 || COLS <= 0)
	    {
		if (isatty(cur_term->Filedes))
		{
		    struct winsize size;

		    errno = 0;
		    do {
			if (ioctl(cur_term->Filedes, TIOCGWINSZ, &size) < 0
				&& errno != EINTR)
			    goto failure;
		    } while
			(errno == EINTR);

		    LINES = (int)size.ws_row;
		    COLS  = (int)size.ws_col;
		}
		/* FALLTHRU */
	    failure:;
	    }
#endif /* defined(TIOCGWINSZ) && !defined(BROKEN_TIOCGWINSZ) */

	    /* if we can't get dynamic info about the size, use static */
	    if (LINES <= 0 || COLS <= 0)
		if (lines > 0 && columns > 0)
		{
		    LINES = (int)lines;
		    COLS  = (int)columns;
		}

	    /* the ultimate fallback, assume fixed 24x80 size */
	    if (LINES <= 0 || COLS <= 0)
	    {
		LINES = 24;
		COLS  = 80;
	    }

	    /*
	     * Put the derived values back in the screen-size caps, so
	     * tigetnum() and tgetnum() will do the right thing.
	     */
	    lines   = (short)LINES;
	    columns = (short)COLS;
	}

	T(("screen size is %dx%d", LINES, COLS));

#ifdef init_tabs
	if (init_tabs != -1)
		TABSIZE = (int)init_tabs;
	else
#endif /* init_tabs */
		TABSIZE = 8;
	T(("TABSIZE = %d", TABSIZE));

}

/****************************************************************************
 *
 * Terminal setup
 *
 ****************************************************************************/

#define ret_error(code, fmt, arg)	if (errret) {\
					    *errret = code;\
					    return(ERR);\
					} else {\
					    fprintf(stderr, fmt, arg);\
					    exit(EXIT_FAILURE);\
					}

#define ret_error0(code, msg)		if (errret) {\
					    *errret = code;\
					    return(ERR);\
					} else {\
					    fprintf(stderr, msg);\
					    exit(EXIT_FAILURE);\
					}

static int grab_entry(const char *const tn, TERMTYPE *const tp)
/* return 1 if entry found, 0 if not found, -1 if database not accessible */
{
	char	filename[PATH_MAX];
	int	status;

	if ((status = _nc_read_entry(tn, filename, tp)) == 1)
	    return(1);

#ifndef PURE_TERMINFO
	/*
	 * Try falling back on the termcap file.  Note: allowing this call
	 * links the entire terminfo/termcap compiler into the startup code.
	 * It's preferable to build a real terminfo database and use that.
	 */
	status = _nc_read_termcap_entry(tn, tp);
#endif /* PURE_TERMINFO */

	return(status);
}

char ttytype[NAMESIZE];

/*
 *	setupterm(termname, Filedes, errret)
 *
 *	Find and read the appropriate object file for the terminal
 *	Make cur_term point to the structure.
 *
 */

int setupterm(const char *tname, int Filedes, int *errret)
{
struct term	*term_ptr;

	T(("setupterm(%s,%d,%p) called", tname, Filedes, errret));

	if (tname == NULL) {
		tname = getenv("TERM");
		if (tname == NULL)
			ret_error0(-1, "TERM environment variable not set.\n");
	}

	T(("your terminal name is %s", tname));

	if (_nc_name_match(ttytype, tname, "|") == FALSE || isendwin()) {
		int status;

		if (isendwin()) {
			T(("deleting cur_term"));
			T(("must be resizing"));
			del_curterm(cur_term);
		}

		term_ptr = (TERMINAL *) calloc(1, sizeof(TERMINAL));

		if (term_ptr == NULL)
			ret_error0(-1, "Not enough memory to create terminal structure.\n") ;
		status = grab_entry(tname, &term_ptr->type);

		/* try fallback list if entry on disk */
		if (status != 1)
		{
		    const TERMTYPE	*fallback = _nc_fallback(tname);

		    if (fallback)
		    {
			memcpy(&term_ptr->type, fallback, sizeof(TERMTYPE));
			status = 1;
		    }
		}

		if (status == -1)
		{
			ret_error0(-1, "terminals database is inaccessible\n");
		}
		else if (status == 0)
		{
			ret_error(0, "'%s': unknown terminal type.\n", tname);
		}

		cur_term = term_ptr;
		if (generic_type)
			ret_error(0, "'%s': I need something more specific.\n", tname);
		if (hard_copy)
			ret_error(1, "'%s': I can't handle hardcopy terminals.\n", tname);

		if (command_character  &&  getenv("CC"))
			do_prototype();

		strncpy(ttytype, cur_term->type.term_names, NAMESIZE - 1);
		ttytype[NAMESIZE - 1] = '\0';

		/*
		 * Allow output redirection.  This is what SVr3 does.
		 * If stdout is directed to a file, screen updates go
		 * to standard error.
		 */
		if (Filedes == STDOUT_FILENO && !isatty(Filedes))
		    Filedes = STDERR_FILENO;
		cur_term->Filedes = Filedes;

		_nc_get_screensize();
	}

	if (errret)
		*errret = 1;
	return(OK);

}

/*
**	do_prototype()
**
**	Take the real command character out of the CC environment variable
**	and substitute it in for the prototype given in 'command_character'.
**
*/

static void
do_prototype(void)
{
int	i, j;
char	CC;
char	proto;
char    *tmp;

	tmp = getenv("CC");
	CC = *tmp;
	proto = *command_character;

	for (i=0; i < STRCOUNT; i++) {
		j = 0;
		while (cur_term->type.Strings[i][j]) {
			if (cur_term->type.Strings[i][j] == proto)
				cur_term->type.Strings[i][j] = CC;
			j++;
		}
	}
}
