Пример #1
0
_nc_is_abs_path(const char *path)
{
#if defined(__EMX__) || defined(__DJGPP__)
#define is_pathname(s) ((((s) != 0) && ((s)[0] == '/')) \
		  || (((s)[0] != 0) && ((s)[1] == ':')))
#else
#define is_pathname(s) ((s) != 0 && (s)[0] == '/')
#endif
    return is_pathname(path);
}
Пример #2
0
int _nc_read_termcap_entry(const char *const tn, TERMTYPE *const tp)
{
	int found = FALSE;
	ENTRY	*ep;
#if USE_GETCAP_CACHE
	char	cwd_buf[PATH_MAX];
#endif
#if USE_GETCAP
	char	tc[TBUFSIZ];
	static char	*source;
	static int lineno;

	/* we're using getcap(3) */
	if (_nc_tgetent(tc, &source, &lineno, tn) < 0)
		return (ERR);

	_nc_curr_line = lineno;
	_nc_set_source(source);
	_nc_read_entry_source((FILE *)0, tc, FALSE, FALSE, NULLHOOK);
#else
	/*
	 * Here is what the 4.4BSD termcap(3) page prescribes:
	 *
	 * It will look in the environment for a TERMCAP variable.  If found,
	 * and the value does not begin with a slash, and the terminal type
	 * name is the same as the environment string TERM, the TERMCAP string
	 * is used instead of reading a termcap file.  If it does begin with a
	 * slash, the string is used as a path name of the termcap file to
	 * search.  If TERMCAP does not begin with a slash and name is
	 * different from TERM, tgetent() searches the files $HOME/.termcap and
	 * /usr/share/misc/termcap, in that order, unless the environment
	 * variable TERMPATH exists, in which case it specifies a list of file
	 * pathnames (separated by spaces or colons) to be searched instead.
	 *
	 * It goes on to state:
	 *
	 * Whenever multiple files are searched and a tc field occurs in the
	 * requested entry, the entry it names must be found in the same file
	 * or one of the succeeding files.
	 *
	 * However, this restriction is relaxed in ncurses; tc references to
	 * previous files are permitted.
	 *
	 * This routine returns 1 if an entry is found, 0 if not found, and -1
	 * if the database is not accessible.
	 */
	FILE	*fp;
	char	*tc, *termpaths[MAXPATHS];
	int	filecount = 0;
	bool	use_buffer = FALSE;
	char	tc_buf[1024];
	char	pathbuf[PATH_MAX];

	termpaths[filecount] = 0;
	if ((tc = getenv("TERMCAP")) != 0)
	{
		if (is_pathname(tc))	/* interpret as a filename */
		{
			ADD_TC(tc, 0);
		}
		else if (_nc_name_match(tc, tn, "|:")) /* treat as a capability file */
		{
			use_buffer = TRUE;
			(void) sprintf(tc_buf, "%.*s\n", (int)sizeof(tc_buf)-2, tc);
		}
		else if ((tc = getenv("TERMPATH")) != 0)
		{
			char    *cp;

			for (cp = tc; *cp; cp++)
			{
				if (*cp == ':')
					*cp = '\0';
				else if (cp == tc || cp[-1] == '\0')
				{
					ADD_TC(cp, filecount);
				}
			}
		}
	}
	else	/* normal case */
	{
		char	envhome[PATH_MAX], *h;

		filecount = 0;

		/*
		 * Probably /etc/termcap is a symlink to /usr/share/misc/termcap.
		 * Avoid reading the same file twice.
		 */
		if (_nc_access("/etc/termcap", F_OK) == 0)
			ADD_TC("/etc/termcap", filecount);
		else
			ADD_TC("/usr/share/misc/termcap", filecount);

		if ((h = getenv("HOME")) != NULL && strlen(h) + 9 < PATH_MAX)
		{
		    /* user's .termcap, if any, should override it */
		    (void) strcpy(envhome, h);
		    (void) sprintf(pathbuf, "%s/.termcap", envhome);
		    ADD_TC(pathbuf, filecount);
		}
	}

	/* parse the sources */
	if (use_buffer)
	{
		_nc_set_source("TERMCAP");

		/*
		 * We don't suppress warning messages here.  The presumption is
		 * that since it's just a single entry, they won't be a pain.
		 */
		_nc_read_entry_source((FILE *)0, tc_buf, FALSE, FALSE, NULLHOOK);
	} else {
		int	i;

		for (i = 0; i < filecount; i++) {

			T(("Looking for %s in %s", tn, termpaths[i]));
			if ((fp = fopen(termpaths[i], "r")) != (FILE *)0)
			{
				_nc_set_source(termpaths[i]);

				/*
				 * Suppress warning messages.  Otherwise you
				 * get 400 lines of crap from archaic termcap
				 * files as ncurses complains about all the
				 * obsolete capabilities.
				 */
				_nc_read_entry_source(fp, (char*)0, FALSE, TRUE, NULLHOOK);

				(void) fclose(fp);
			}
		}
	}
#endif /* USE_GETCAP */

	if (_nc_head == 0)
		return(ERR);

	/* resolve all use references */
	_nc_resolve_uses();

	/* find a terminal matching tn, if we can */
#if USE_GETCAP_CACHE
	if (getcwd(cwd_buf, sizeof(cwd_buf)) != 0)
	{
		_nc_set_writedir((char *)0); /* note: this does a chdir */
#endif
		for_entry_list(ep) {
			if (_nc_name_match(ep->tterm.term_names, tn, "|:"))
			{
				/*
				 * Make a local copy of the terminal
				 * capabilities.  Free all entry storage except
				 * the string table for the loaded type (which
				 * we disconnected from the list by NULLing out
				 * ep->tterm.str_table above).
				 */
				memcpy(tp, &ep->tterm, sizeof(TERMTYPE));
				ep->tterm.str_table = (char *)0;

				/*
				 * OK, now try to write the type to user's
				 * terminfo directory.  Next time he loads
				 * this, it will come through terminfo.
				 *
				 * Advantage:  Second and subsequent fetches of
				 * this entry will be very fast.
				 *
				 * Disadvantage:  After the first time a
				 * termcap type is loaded by its user, editing
				 * it in the /etc/termcap file, or in TERMCAP,
				 * or in a local ~/.termcap, will be
				 * ineffective unless the terminfo entry is
				 * explicitly removed.
				 */
#if USE_GETCAP_CACHE
				(void) _nc_write_entry(tp);
#endif
				found = TRUE;
				break;
			}
		}
#if USE_GETCAP_CACHE
		chdir(cwd_buf);
	}
Пример #3
0
/*
 * Get an entry for terminal name in buffer bp from the termcap file.
 */
static int
_nc_tgetent(char *bp, char **sourcename, int *lineno, const char *name)
{
	static char *the_source;

	register char *p;
	register char *cp;
	char  *dummy;
	char **fname;
	char  *home;
	int    i;
	char   pathbuf[PBUFSIZ];	/* holds raw path of filenames */
	char  *pathvec[PVECSIZ];	/* to point to names in pathbuf */
	char **pvec;			/* holds usable tail of path vector */
	char  *termpath;

	fname = pathvec;
	pvec = pathvec;
	tbuf = bp;
	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 (!is_pathname(cp)) {	/* no TERMCAP or it holds an entry */
		if ((termpath = getenv("TERMPATH")) != 0) {
			strlcpy(pathbuf, termpath, PBUFSIZ);
		} else {
			if ((home = getenv("HOME")) != 0 &&
			    strlen(home) < PBUFSIZ) { /* setup path */
				p += strlen(home);	/* path, looking in */
				strcpy(pathbuf, home);	/* $HOME first */
				*p++ = '/';
			}	/* if no $HOME look in current directory */
#define	MY_PATH_DEF	".termcap /etc/termcap /usr/share/misc/termcap"
			strlcpy(p, MY_PATH_DEF, (size_t)(PBUFSIZ - (p - pathbuf)));
		}
	}
	else				/* user-defined name in TERMCAP */
		strlcpy(pathbuf, cp, PBUFSIZ); /* still can be tokenized */

	*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 = 0;			/* mark end of vector */
	if (is_pathname(cp)) {
		if (_nc_cgetset(cp) < 0) {
			return(TC_SYS_ERR);
		}
	}

	i = _nc_cgetent(&dummy, lineno, pathvec, name);

	/* ncurses' termcap-parsing routines cannot handle multiple adjacent
	 * empty fields, and mistakenly use the last valid cap entry instead of
	 * the first (breaks tc= includes)
	 */
	if (i >= 0) {
		char *pd, *ps, *tok;
		int endflag = FALSE;
		char *list[1023];
		size_t n, count = 0;

		pd = bp;
		ps = dummy;
		while (!endflag && (tok = get_tc_token(&ps, &endflag)) != 0) {
			bool ignore = FALSE;

			for (n = 1; n < count; n++) {
				char *s = list[n];
				if (s[0] == tok[0]
				 && s[1] == tok[1]) {
					ignore = TRUE;
					break;
				}
			}
			if (ignore != TRUE) {
				list[count++] = tok;
				pd = copy_tc_token(pd, tok, TBUFSIZ - (2+pd-bp));
				if (pd == 0) {
					i = -1;
					break;
				}
				*pd++ = ':';
				*pd = '\0';
			}
		}
	}

	FreeIfNeeded(dummy);
	FreeIfNeeded(the_source);
	the_source = 0;

	/* This is not related to the BSD cgetent(), but to fake up a suitable
	 * filename for ncurses' error reporting.  (If we are not using BSD
	 * cgetent, then it is the actual filename).
	 */
	if (i >= 0) {
		the_source = malloc(strlen(pathvec[i]) + 1);
		if (the_source != 0)
			*sourcename = strcpy(the_source, pathvec[i]);
	}

	return(i);
}