[BACK]Return to getterm.c CVS log [TXT][DIR] Up to [local] / src / lib / libtermlib

File: [local] / src / lib / libtermlib / Attic / getterm.c (download)

Revision 1.16, Sat Jan 17 16:35:06 1998 UTC (26 years, 4 months ago) by millert
Branch: MAIN
CVS Tags: OPENBSD_2_8_BASE, OPENBSD_2_8, OPENBSD_2_7_BASE, OPENBSD_2_7, OPENBSD_2_6_BASE, OPENBSD_2_6, OPENBSD_2_5_BASE, OPENBSD_2_5, OPENBSD_2_4_BASE, OPENBSD_2_4, OPENBSD_2_3_BASE, OPENBSD_2_3
Changes since 1.15: +3 -2 lines

-Wall

/*	$OpenBSD: getterm.c,v 1.16 1998/01/17 16:35:06 millert Exp $	*/

/*
 * Copyright (c) 1996 SigmaSoft, Th. Lockert <tholo@sigmasoft.com>
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 * 1. Redistributions of source code must retain the above copyright
 *    notice, this list of conditions and the following disclaimer.
 * 2. Redistributions in binary form must reproduce the above copyright
 *    notice, this list of conditions and the following disclaimer in the
 *    documentation and/or other materials provided with the distribution.
 * 3. All advertising materials mentioning features or use of this software
 *    must display the following acknowledgement:
 *	This product includes software developed by SigmaSoft, Th.  Lockert.
 * 4. The name of the author may not be used to endorse or promote products
 *    derived from this software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES,
 * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
 * AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL
 * THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
 * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
 * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
 * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
 * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 */

#ifndef lint
static char rcsid[] = "$OpenBSD: getterm.c,v 1.16 1998/01/17 16:35:06 millert Exp $";
#endif

#include <err.h>
#include <stdlib.h>
#include <string.h>
#include <sys/param.h>
#include <sys/ioctl.h>
#include "term.h"
#include "term.private.h"
#include "pathnames.h"

#define	PVECSIZ	32
#define	MAXSIZE	256	/* Maximum allowed size of a terminal name field */

TERMINAL *cur_term;
char *_ti_buf;
char *UP;
char *BC;
char PC;
int LINES, COLS, TABSIZE;
char ttytype[MAXSIZE];

static int _ti_use_env = TRUE;

/*
 * Internal routine to read in a terminal description.
 * Currently supports reading from termcap files and databases
 * only; should be extended to also support reading from binary
 * terminfo files
 *
 * Will also set up global variables for compatibility with old
 * termcap routines, as well as populate cur_term's capability
 * variables.  If called from the termcap tgetent() compatibility
 * routine, it will copy the termcap entry into the buffer
 * provided to that routine.  Note that no other code in this
 * library depends on the termcap entry being kept
 */
int
_ti_gettermcap(name)
     const char *name;
{
    register char *p;
    register char *cp;
    char  *dummy;
    char **fname;
    char  *home;
    int    i;
    char   pathbuf[MAXPATHLEN+1];	/* holds raw path of filenames */
    char  *pathvec[PVECSIZ];		/* to point to names in pathbuf */
    char  *termpath;
    long   num;

    fname = pathvec;
    p = pathbuf;
    cp = getenv("TERMCAP");
    /*
     * TERMCAP can have one of two things in it. It can be the
     * name of a file to use instead of /etc/termcap. In this
     * case it better start with a "/". Or it can be an entry to
     * use so we don't have to read the file. In this case it
     * has to already have the newlines crunched out.  If TERMCAP
     * does not hold a file name then a path of names is searched
     * instead.  The path is found in the TERMPATH variable, or
     * becomes "$HOME/.termcap /etc/termcap" if no TERMPATH exists.
     */
    if (!cp || *cp != '/') {	/* no TERMCAP or it holds an entry */
	if ((termpath = getenv("TERMPATH")) != NULL)
	    strncpy(pathbuf, termpath, sizeof(pathbuf)-1);
	else {
	    if ((home = getenv("HOME")) != NULL) {
		/* set up default */
		/* $HOME first */
		strncpy(pathbuf, home, sizeof(pathbuf) - 1 -
		    strlen(_PATH_CAPDEF) - 1);
		pathbuf[sizeof(pathbuf) - 1 - strlen(_PATH_CAPDEF) - 1] = '\0';
		p += strlen(pathbuf);	/* path, looking in */
		*p++ = '/';
	    }	/* if no $HOME look in current directory */
	    strncpy(p, _PATH_CAPDEF, sizeof(pathbuf) - 1 - (p - pathbuf));
	}
    }
    else					/* user-defined name in TERMCAP */
	strncpy(pathbuf, cp, sizeof(pathbuf)-1);	/* still can be tokenized */
    pathbuf[sizeof(pathbuf)-1] = '\0';

    *fname++ = pathbuf;	/* tokenize path into vector of names */
    while (*++p)
	if (*p == ' ' || *p == ':') {
	    *p = '\0';
	    while (*++p)
		if (*p != ' ' && *p != ':')
		    break;
	    if (*p == '\0')
		break;
	    *fname++ = p;
	    if (fname >= pathvec + PVECSIZ) {
		fname--;
		break;
	    }
	}
    *fname = (char *) 0;			/* mark end of vector */
    if (cp && *cp && *cp != '/')
	if (cgetset(cp) < 0)
	    return (-2);

    dummy = NULL;
    i = cgetent(&dummy, pathvec, (char *)name);      
	
    if (i == 0) {
	char *s;

	if ((s = home = strchr(dummy, ':')) == NULL) {
	    cur_term->name = cur_term->names = strdup(name);
	    strncpy(ttytype, name, MAXSIZE - 1);
	    ttytype[MAXSIZE - 1] = '\0';
	}
	else {
	    size_t n;

	    n = s - dummy - (dummy[2] == '|' ? 3 : 0);
	    cur_term->names = malloc(n + 1);
	    strncpy(cur_term->names, dummy + (dummy[2] == '|' ? 3 : 0), n);
	    cur_term->names[n] = '\0';
	    strncpy(ttytype, dummy + (dummy[2] == '|' ? 3 : 0),
		    (size_t)MIN(MAXSIZE - 1, s - dummy));
	    ttytype[MAXSIZE - 1] = '\0';
	    *home = '\0';
	    while (s > dummy && *s != '|')
		s--;
	    if (s > dummy)
		s++;
	    cur_term->name = strdup(s);
	    *home = ':';
	}
	for (i = 0; i < _ti_numcaps; i++) {
	    switch (_ti_captoidx[i].type) {
		case TYPE_BOOL:
		    if (cgetcap(dummy, (char *)_ti_captoidx[i].name, ':') == NULL)
			cur_term->bools[_ti_captoidx[i].idx] = 0;
		    else
			cur_term->bools[_ti_captoidx[i].idx] = 1;
		    break;
		case TYPE_NUM:
		    if (cgetnum(dummy, (char *)_ti_captoidx[i].name, &num) < 0)
			cur_term->nums[_ti_captoidx[i].idx] = 0;
		    else
			cur_term->nums[_ti_captoidx[i].idx] = (int)num;
		    break;
		case TYPE_STR:
		    if (cgetstr(dummy, (char *)_ti_captoidx[i].name, &s) < 0)
			cur_term->strs[_ti_captoidx[i].idx] = NULL;
		    else {
			cur_term->strs[_ti_captoidx[i].idx] = _ti_captoinfo(s);
			free(s);
		    }
		    break;
	    }
	}
	if (_ti_buf) {
	    strncpy(_ti_buf, dummy, 1023);
	    _ti_buf[1023] = '\0';
	    if ((cp = strrchr(_ti_buf, ':')) != NULL)
		if (cp[1] != '\0')
		    cp[1] = '\0';
	}
	i = 0;
    }

    /* We are done with the returned termcap buffer now; free it */
    if (dummy)
	free(dummy);

    /* we found a "tc" reference loop, return error */
    if (i == -3)
	return (-1);

    return (i + 1);
}

/*
 * Internal routine to read in a terminal description.
 * Currently supports reading from termcap files and databases
 * only; should be extended to also support reading from binary
 * terminfo files
 *
 * Will also set up global variables for compatibility with old
 * termcap routines, as well as populate cur_term's capability
 * variables.  If called from the termcap tgetent() compatibility
 * routine, it will copy the termcap entry into the buffer
 * provided to that routine.  Note that no other code in this
 * library depends on the termcap entry being kept
 */
int
_ti_getterminfo(name)
     const char *name;
{
    register char *p;
    register char *cp;
    char  *dummy;
    char **fname;
    char  *home;
    int    i;
    char   pathbuf[MAXPATHLEN+1];	/* holds raw path of filenames */
    char  *pathvec[PVECSIZ];		/* to point to names in pathbuf */
    char  *termpath;
    long   num;

    fname = pathvec;
    p = pathbuf;
    /*
     * TERMCAP can have one of two things in it. It can be the
     * name of a file to use instead of /etc/termcap. In this
     * case it better start with a "/". Or it can be an entry to
     * use so we don't have to read the file. In this case it
     * has to already have the newlines crunched out.  If TERMCAP
     * does not hold a file name then a path of names is searched
     * instead.  The path is found in the TERMINFO variable, or
     * becomes "$HOME/.terminfo /usr/share/misc/terminfo" if no
     * TERMINFO exists.
     */
    if ((termpath = getenv("TERMINFO")) != NULL)
	strncpy(pathbuf, termpath, sizeof(pathbuf) - 1);
    else {
	if ((home = getenv("HOME")) != NULL) {
	    /* set up default */
	    /* $HOME first */
	    strncpy(pathbuf, home, sizeof(pathbuf) - 1 -
		strlen(_PATH_INFODEF) - 1);
	    pathbuf[sizeof(pathbuf) - 1 - strlen(_PATH_INFODEF) - 1] = '\0';
	    p += strlen(home);	/* path, looking in */
	    *p++ = '/';
	}	/* if no $HOME look in current directory */
	strncpy(p, _PATH_INFODEF, sizeof(pathbuf) - 1 - (p - pathbuf));
    }
    pathbuf[sizeof(pathbuf) - 1] = '\0';

    *fname++ = pathbuf;	/* tokenize path into vector of names */
    while (*++p)
	if (*p == ' ' || *p == ':') {
	    *p = '\0';
	    while (*++p)
		if (*p != ' ' && *p != ':')
		    break;
	    if (*p == '\0')
		break;
	    *fname++ = p;
	    if (fname >= pathvec + PVECSIZ) {
		fname--;
		break;
	    }
	}
    *fname = (char *) 0;			/* mark end of vector */
    (void) cgetset(NULL);

    dummy = NULL;
    i = cgetent(&dummy, pathvec, (char *)name);      
	
    if (i == 0) {
	char *s;

	if ((s = home = strchr(dummy, ':')) == NULL) {
	    cur_term->name = cur_term->names = strdup(name);
	    strncpy(ttytype, name, MAXSIZE - 1);
	    ttytype[MAXSIZE - 1] = '\0';
	}
	else {
	    size_t n;

	    n = s - dummy - (dummy[2] == '|' ? 3 : 0);
	    cur_term->names = malloc(n + 1);
	    strncpy(cur_term->names, dummy + (dummy[2] == '|' ? 3 : 0), n);
	    cur_term->names[n] = '\0';
	    strncpy(ttytype, dummy + (dummy[2] == '|' ? 3 : 0),
		    (size_t)MIN(MAXSIZE - 1, s - dummy));
	    ttytype[MAXSIZE - 1] = '\0';
	    *home = '\0';
	    while (s > dummy && *s != '|')
		s--;
	    if (s > dummy)
		s++;
	    cur_term->name = strdup(s);
	    *home = ':';
	}
	for (i = 0 ; i < _tBoolCnt ; i++) {
	    if (cgetcap(dummy, (char *)boolcodes[i], ':') == NULL)
		cur_term->bools[i] = 0;
	    else
		cur_term->bools[i] = 1;
	}
	for (i = 0 ; i < _tNumCnt ; i++) {
	    if (cgetnum(dummy, (char *)numcodes[i], &num) < 0)
		cur_term->nums[i] = 0;
	    else
		cur_term->nums[i] = (int)num;
	}
	for (i = 0 ; i < _tStrCnt ; i++) {
	    if (cgetstr(dummy, (char *)strcodes[i], &s) < 0)
		cur_term->strs[i] = NULL;
	    else
		cur_term->strs[i] = s;
	}
	if (_ti_buf) {
	    strncpy(_ti_buf, dummy, 1023);
	    _ti_buf[1023] = '\0';
	    if ((cp = strrchr(_ti_buf, ':')) != NULL)
		if (cp[1] != '\0')
		    cp[1] = '\0';
	}
	i = 0;
    }

    /* We are done with the returned termcap buffer now; free it */
    if (dummy)
	free(dummy);

    /* we found a "tc" reference loop, return error */
    if (i == -3)
	return (-1);

    return (i + 1);
}

void
_ti_get_screensize(linep, colp, tabp)
    int *linep;
    int *colp;
    int *tabp;
{
    char *s;
#ifdef TIOCGWINSZ
    struct winsize winsz;
#endif

    *linep = lines;
    *colp = columns;
    if (tabp != NULL) {
	if (init_tabs == 0)
	    init_tabs = *tabp = 8;
	else
	    *tabp = init_tabs;
    }
    if (_ti_use_env) {
#ifdef TIOCGWINSZ
	/*
	 * get the current window size, overrides entries in termcap
	 */
	if (ioctl(cur_term->fd, TIOCGWINSZ, &winsz) >= 0) {
	    if (winsz.ws_row > 0)
		*linep = winsz.ws_row;
	    if (winsz.ws_col > 0)
		*colp = winsz.ws_col;
	}
#endif
	/*
	 * LINES and COLS environment variables overrides any other
	 * method of getting the terminal window size
	 */
	if ((s = getenv("LINES")) != NULL)
	    *linep = atoi(s);
	if ((s = getenv("COLUMNS")) != NULL)
	    *colp = atoi(s);
    }
    lines = *linep;
    columns = *colp;
}

int
_ti_getterm(name)
     const char *name;
{
    int ret = 1;
    char *s;

    s = getenv("TERMCAP");
    if (s && *s == '/')
	s = NULL;
    if (_ti_buf || s) {
	if (_ti_gettermcap(name) != 1) {
	    del_curterm(cur_term);
	    if ((cur_term = calloc(sizeof(TERMINAL), 1)) == NULL)
		errx(1, "No memory for terminal description");
	    ret = _ti_getterminfo(name);
	}
    }
    else {
	if (_ti_getterminfo(name) != 1) {
	    del_curterm(cur_term);
	    if ((cur_term = calloc(sizeof(TERMINAL), 1)) == NULL)
		errx(1, "No memory for terminal description");
	    ret = _ti_gettermcap(name);
	}
    }

    if (ret == 1) {
	_ti_fillcap(cur_term);
	UP = cursor_up;
	BC = backspace_if_not_bs;
	PC = pad_char ? pad_char[0] : '\0';
	_ti_get_screensize(&LINES, &COLS, &TABSIZE);
    }
    return ret;
}

/*
 * Allows the calling program to not have the window size or
 * environment variables LINES and COLS override the termcap
 * or terminfo lines/columns specifications
 */
void
use_env(flag)
    int flag;
{
    _ti_use_env = flag;
}