/****************************************************************************
- * Copyright (c) 1998,1999,2000 Free Software Foundation, Inc. *
+ * Copyright (c) 1998-2005,2006 Free Software Foundation, Inc. *
* *
* Permission is hereby granted, free of charge, to any person obtaining a *
* copy of this software and associated documentation files (the *
/****************************************************************************
* Author: Zeyd M. Ben-Halim <zmbenhal@netcom.com> 1992,1995 *
* and: Eric S. Raymond <esr@snark.thyrsus.com> *
+ * and: Thomas E. Dickey 1996-on *
****************************************************************************/
/*
#include <curses.priv.h>
#include <ctype.h>
+#include <sys/types.h>
+#include <sys/stat.h>
#include <tic.h>
#include <term_entry.h>
-MODULE_ID("$Id: read_termcap.c,v 1.47 2000/04/15 16:53:19 Todd.C.Miller Exp $")
+MODULE_ID("$Id: read_termcap.c,v 1.71 2006/07/29 12:06:51 tom Exp $")
-#ifndef PURE_TERMINFO
-
-#ifdef __EMX__
-#define is_pathname(s) ((((s) != 0) && ((s)[0] == '/')) \
- || (((s)[0] != 0) && ((s)[1] == ':')))
-#else
-#define is_pathname(s) ((s) != 0 && (s)[0] == '/')
-#endif
+#if !PURE_TERMINFO
#define TC_SUCCESS 0
-#define TC_UNRESOLVED -1
-#define TC_NOT_FOUND -2
-#define TC_SYS_ERR -3
-#define TC_REF_LOOP -4
+#define TC_NOT_FOUND -1
+#define TC_SYS_ERR -2
+#define TC_REF_LOOP -3
+#define TC_UNRESOLVED -4 /* this is not returned by BSD cgetent */
+
+static NCURSES_CONST char *
+get_termpath(void)
+{
+ NCURSES_CONST char *result;
+
+ if (!use_terminfo_vars() || (result = getenv("TERMPATH")) == 0)
+ result = TERMPATH;
+ T(("TERMPATH is %s", result));
+ return result;
+}
#if USE_GETCAP
#define _nc_cgetset cgetset
#else
static int _nc_cgetmatch(char *, const char *);
-static int _nc_getent(char **, unsigned *, int *, int, char **, int, const char *, int, char *);
+static int _nc_getent(char **, unsigned *, int *, int, char **, int, const char
+ *, int, char *);
static int _nc_nfcmp(const char *, char *);
/*-
#define BFRAG 1024
#define BSIZE 1024
-#define ESC ('[' & 037) /* ASCII ESC */
#define MAX_RECURSION 32 /* maximum getent recursion */
-#define SFRAG 100 /* cgetstr mallocs in SFRAG chunks */
-
-#define RECOK (char)0
-#define TCERR (char)1
-#define SHADOW (char)2
static size_t topreclen; /* toprec length */
static char *toprec; /* Additional record specified by cgetset() */
* Returns:
*
* positive # on success (i.e., the index in db_array)
- * TC_UNRESOLVED if we had too many recurrences to resolve
* TC_NOT_FOUND if the requested record couldn't be found
* TC_SYS_ERR if a system error was encountered (e.g.,couldn't open a file)
* TC_REF_LOOP if a potential reference loop is detected
+ * TC_UNRESOLVED if we had too many recurrences to resolve
*/
static int
_nc_cgetent(char **buf, int *oline, char **db_array, const char *name)
#define DOALLOC(size) typeRealloc(char, size, record)
static int
_nc_getent(
- char **cap, /* termcap-content */
- unsigned *len, /* length, needed for recursion */
- int *beginning, /* line-number at match */
- int in_array, /* index in 'db_array[] */
- char **db_array, /* list of files to search */
- int fd,
- const char *name,
- int depth,
- char *nfield)
+ char **cap, /* termcap-content */
+ unsigned *len, /* length, needed for recursion */
+ int *beginning, /* line-number at match */
+ int in_array, /* index in 'db_array[] */
+ char **db_array, /* list of files to search */
+ int fd,
+ const char *name,
+ int depth,
+ char *nfield)
{
register char *r_end, *rp;
int myfd = FALSE;
if (fd >= 0) {
(void) lseek(fd, (off_t) 0, SEEK_SET);
} else if ((_nc_access(db_array[current], R_OK) < 0)
- || (fd = open(db_array[current], O_RDONLY, 0)) < 0) {
+ || (fd = open(db_array[current], O_RDONLY, 0)) < 0) {
/* No error on unfound file. */
if (errno == ENOENT)
continue;
tcend = s;
iret = _nc_getent(&icap, &ilen, &oline, current, db_array, fd,
- tc, depth + 1, 0);
+ tc, depth + 1, 0);
newicap = icap; /* Put into a register. */
newilen = ilen;
if (iret != TC_SUCCESS) {
if (*s == '\0') {
break;
} else if (*s++ == '\n') {
- while (isspace(*s))
+ while (isspace(UChar(*s)))
s++;
} else {
found = TRUE;
break;
}
base = s;
- } else if (isgraph(ch)) {
+ } else if (isgraph(UChar(ch))) {
found = TRUE;
}
}
while ((ch = *src++) != '\0') {
if (ch == '\\' && *src == '\n') {
- while (isspace(*src))
+ while (isspace(UChar(*src)))
src++;
continue;
}
register char *p;
register char *cp;
- char *dummy;
+ char *dummy = NULL;
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;
+ NCURSES_CONST char *termpath;
+ string_desc desc;
fname = pathvec;
pvec = pathvec;
tbuf = bp;
p = pathbuf;
- cp = getenv("TERMCAP");
+ cp = use_terminfo_vars()? getenv("TERMCAP") : NULL;
/*
* TERMCAP can have one of two things in it. It can be the name of a file
* 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) {
- strncpy(pathbuf, termpath, PBUFSIZ - 1);
+ _nc_str_init(&desc, pathbuf, sizeof(pathbuf));
+ if (cp == NULL) {
+ _nc_safe_strcpy(&desc, get_termpath());
+ } else if (!_nc_is_abs_path(cp)) { /* TERMCAP holds an entry */
+ if ((termpath = get_termpath()) != 0) {
+ _nc_safe_strcat(&desc, termpath);
} 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"
- strncpy(p, MY_PATH_DEF, (size_t) (PBUFSIZ - (p - pathbuf) - 1));
+ char temp[PBUFSIZ];
+ temp[0] = 0;
+ if ((home = getenv("HOME")) != 0 && *home != '\0'
+ && strchr(home, ' ') == 0
+ && strlen(home) < sizeof(temp) - 10) { /* setup path */
+ sprintf(temp, "%s/", home); /* $HOME first */
+ }
+ /* if no $HOME look in current directory */
+ strcat(temp, ".termcap");
+ _nc_safe_strcat(&desc, temp);
+ _nc_safe_strcat(&desc, " ");
+ _nc_safe_strcat(&desc, get_termpath());
}
- } else /* user-defined name in TERMCAP */
- strncpy(pathbuf, cp, PBUFSIZ - 1); /* still can be tokenized */
- pathbuf[PBUFSIZ - 1] = '\0';
+ } else { /* user-defined name in TERMCAP */
+ _nc_safe_strcat(&desc, cp); /* still can be tokenized */
+ }
*fname++ = pathbuf; /* tokenize path into vector of names */
while (*++p) {
- if (*p == ' ' || *p == ':') {
+ if (*p == ' ' || *p == NCURSES_PATHSEP) {
*p = '\0';
while (*++p)
- if (*p != ' ' && *p != ':')
+ if (*p != ' ' && *p != NCURSES_PATHSEP)
break;
if (*p == '\0')
break;
}
}
*fname = 0; /* mark end of vector */
- if (is_pathname(cp)) {
+ if (_nc_is_abs_path(cp)) {
if (_nc_cgetset(cp) < 0) {
return (TC_SYS_ERR);
}
* cgetent, then it is the actual filename).
*/
if (i >= 0) {
+#if HAVE_BSD_CGETENT
+ char temp[PATH_MAX];
+
+ _nc_str_init(&desc, temp, sizeof(temp));
+ _nc_safe_strcpy(&desc, pathvec[i]);
+ _nc_safe_strcat(&desc, ".db");
+ if (_nc_access(temp, R_OK) == 0) {
+ _nc_safe_strcpy(&desc, pathvec[i]);
+ }
+ if ((the_source = strdup(temp)) != 0)
+ *sourcename = the_source;
+#else
if ((the_source = strdup(pathvec[i])) != 0)
*sourcename = the_source;
+#endif
}
return (i);
static int
add_tc(char *termpaths[], char *path, int count)
{
+ char *save = strchr(path, NCURSES_PATHSEP);
+ if (save != 0)
+ *save = '\0';
if (count < MAXPATHS
- && _nc_access(path, R_OK) == 0)
+ && _nc_access(path, R_OK) == 0) {
termpaths[count++] = path;
+ T(("Adding termpath %s", path));
+ }
termpaths[count] = 0;
+ if (save != 0)
+ *save = NCURSES_PATHSEP;
return count;
}
#define ADD_TC(path, count) filecount = add_tc(termpaths, path, count)
#endif /* !USE_GETCAP */
-int
-_nc_read_termcap_entry(const char *const tn, TERMTYPE * const tp)
+NCURSES_EXPORT(int)
+_nc_read_termcap_entry(const char *const tn, TERMTYPE *const tp)
{
- int found = FALSE;
+ int found = TGETENT_NO;
ENTRY *ep;
#if USE_GETCAP_CACHE
char cwd_buf[PATH_MAX];
#endif
#if USE_GETCAP
char *p, tc[TBUFSIZ];
+ int status;
static char *source;
static int lineno;
- if ((p = getenv("TERMCAP")) != 0
- && !is_pathname(p) && _nc_name_match(p, tn, "|:")) {
+ T(("read termcap entry for %s", tn));
+
+ if (strlen(tn) == 0
+ || strcmp(tn, ".") == 0
+ || strcmp(tn, "..") == 0
+ || _nc_pathlast(tn) != 0) {
+ T(("illegal or missing entry name '%s'", tn));
+ return TGETENT_NO;
+ }
+
+ if (use_terminfo_vars() && (p = getenv("TERMCAP")) != 0
+ && !_nc_is_abs_path(p) && _nc_name_match(p, tn, "|:")) {
/* TERMCAP holds a termcap entry */
strncpy(tc, p, sizeof(tc) - 1);
tc[sizeof(tc) - 1] = '\0';
_nc_set_source("TERMCAP");
} else {
/* we're using getcap(3) */
- if (_nc_tgetent(tc, &source, &lineno, tn) < 0)
- return (ERR);
+ if ((status = _nc_tgetent(tc, &source, &lineno, tn)) < 0)
+ return (status == TC_NOT_FOUND ? TGETENT_NO : TGETENT_ERR);
_nc_curr_line = lineno;
_nc_set_source(source);
FILE *fp;
char *tc, *termpaths[MAXPATHS];
int filecount = 0;
+ int j, k;
bool use_buffer = FALSE;
+ bool normal = TRUE;
char tc_buf[1024];
char pathbuf[PATH_MAX];
+ char *copied = 0;
+ char *cp;
+ struct stat test_stat[MAXPATHS];
termpaths[filecount] = 0;
- if ((tc = getenv("TERMCAP")) != 0) {
- if (is_pathname(tc)) { /* interpret as a filename */
+ if (use_terminfo_vars() && (tc = getenv("TERMCAP")) != 0) {
+ if (_nc_is_abs_path(tc)) { /* interpret as a filename */
ADD_TC(tc, 0);
+ normal = FALSE;
} 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);
- }
- }
+ normal = FALSE;
}
- } else { /* normal case */
- char envhome[PATH_MAX], *h;
+ }
- filecount = 0;
+ if (normal) { /* normal case */
+ char envhome[PATH_MAX], *h;
- /*
- * 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);
+ copied = strdup(get_termpath());
+ for (cp = copied; *cp; cp++) {
+ if (*cp == NCURSES_PATHSEP)
+ *cp = '\0';
+ else if (cp == copied || cp[-1] == '\0') {
+ ADD_TC(cp, filecount);
+ }
+ }
#define PRIVATE_CAP "%s/.termcap"
- if ((h = getenv("HOME")) != NULL
+ if (use_terminfo_vars() && (h = getenv("HOME")) != NULL && *h != '\0'
&& (strlen(h) + sizeof(PRIVATE_CAP)) < PATH_MAX) {
/* user's .termcap, if any, should override it */
(void) strcpy(envhome, h);
}
}
+ /*
+ * Probably /etc/termcap is a symlink to /usr/share/misc/termcap.
+ * Avoid reading the same file twice.
+ */
+#if HAVE_LINK
+ for (j = 0; j < filecount; j++) {
+ bool omit = FALSE;
+ if (stat(termpaths[j], &test_stat[j]) != 0
+ || (test_stat[j].st_mode & S_IFMT) != S_IFREG) {
+ omit = TRUE;
+ } else {
+ for (k = 0; k < j; k++) {
+ if (test_stat[k].st_dev == test_stat[j].st_dev
+ && test_stat[k].st_ino == test_stat[j].st_ino) {
+ omit = TRUE;
+ break;
+ }
+ }
+ }
+ if (omit) {
+ T(("Path %s is a duplicate", termpaths[j]));
+ for (k = j + 1; k < filecount; k++) {
+ termpaths[k - 1] = termpaths[k];
+ test_stat[k - 1] = test_stat[k];
+ }
+ --filecount;
+ --j;
+ }
+ }
+#endif
+
/* parse the sources */
if (use_buffer) {
_nc_set_source("TERMCAP");
for (i = 0; i < filecount; i++) {
T(("Looking for %s in %s", tn, termpaths[i]));
- if ((fp = fopen(termpaths[i], "r")) != (FILE *) 0) {
+ if (_nc_access(termpaths[i], R_OK) == 0
+ && (fp = fopen(termpaths[i], "r")) != (FILE *) 0) {
_nc_set_source(termpaths[i]);
/*
}
}
}
+ if (copied != 0)
+ free(copied);
#endif /* USE_GETCAP */
if (_nc_head == 0)
- return (ERR);
+ return (TGETENT_ERR);
/* resolve all use references */
- _nc_resolve_uses(TRUE);
+ _nc_resolve_uses2(TRUE, FALSE);
/* find a terminal matching tn, if we can */
#if USE_GETCAP_CACHE
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).
+ * Make a local copy of the terminal capabilities, delinked
+ * from the list.
*/
*tp = ep->tterm;
- ep->tterm.str_table = (char *) 0;
+ _nc_delink_entry(_nc_head, &(ep->tterm));
+ free(ep);
/*
* OK, now try to write the type to user's terminfo directory.
#if USE_GETCAP_CACHE
(void) _nc_write_entry(tp);
#endif
- found = TRUE;
+ found = TGETENT_YES;
break;
}
}
}
#endif
- _nc_free_entries(_nc_head);
return (found);
}
#else
-extern void _nc_read_termcap(void);
-void
+extern
+NCURSES_EXPORT(void)
+_nc_read_termcap(void);
+NCURSES_EXPORT(void)
_nc_read_termcap(void)
{
}