_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); }
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); }
/* * 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); }