150276Speter/**************************************************************************** 2166124Srafan * Copyright (c) 1998-2005,2006 Free Software Foundation, Inc. * 350276Speter * * 450276Speter * Permission is hereby granted, free of charge, to any person obtaining a * 550276Speter * copy of this software and associated documentation files (the * 650276Speter * "Software"), to deal in the Software without restriction, including * 750276Speter * without limitation the rights to use, copy, modify, merge, publish, * 850276Speter * distribute, distribute with modifications, sublicense, and/or sell * 950276Speter * copies of the Software, and to permit persons to whom the Software is * 1050276Speter * furnished to do so, subject to the following conditions: * 1150276Speter * * 1250276Speter * The above copyright notice and this permission notice shall be included * 1350276Speter * in all copies or substantial portions of the Software. * 1450276Speter * * 1550276Speter * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS * 1650276Speter * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF * 1750276Speter * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. * 1850276Speter * IN NO EVENT SHALL THE ABOVE COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, * 1950276Speter * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR * 2050276Speter * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR * 2150276Speter * THE USE OR OTHER DEALINGS IN THE SOFTWARE. * 2250276Speter * * 2350276Speter * Except as contained in this notice, the name(s) of the above copyright * 2450276Speter * holders shall not be used in advertising or otherwise to promote the * 2550276Speter * sale, use or other dealings in this Software without prior written * 2650276Speter * authorization. * 2750276Speter ****************************************************************************/ 2850276Speter 2950276Speter/**************************************************************************** 3050276Speter * Author: Zeyd M. Ben-Halim <zmbenhal@netcom.com> 1992,1995 * 3150276Speter * and: Eric S. Raymond <esr@snark.thyrsus.com> * 32166124Srafan * and: Thomas E. Dickey 1996-on * 3350276Speter ****************************************************************************/ 3450276Speter 3550276Speter/* 3650276Speter * Termcap compatibility support 3750276Speter * 3850276Speter * If your OS integrator didn't install a terminfo database, you can call 3950276Speter * _nc_read_termcap_entry() to support reading and translating capabilities 4050276Speter * from the system termcap file. This is a kludge; it will bulk up and slow 4150276Speter * down every program that uses ncurses, and translated termcap entries cannot 4250276Speter * use full terminfo capabilities. Don't use it unless you absolutely have to; 4350276Speter * instead, get your system people to run tic(1) from root on the terminfo 4450276Speter * master included with ncurses to translate it into a terminfo database. 4550276Speter * 4650276Speter * If USE_GETCAP is enabled, we use what is effectively a copy of the 4.4BSD 4750276Speter * getcap code to fetch entries. There are disadvantages to this; mainly that 4850276Speter * getcap(3) does its own resolution, meaning that entries read in in this way 4950276Speter * can't reference the terminfo tree. The only thing it buys is faster startup 5050276Speter * time, getcap(3) is much faster than our tic parser. 5150276Speter */ 5250276Speter 5350276Speter#include <curses.priv.h> 5450276Speter 5550276Speter#include <ctype.h> 5697049Speter#include <sys/types.h> 5797049Speter#include <sys/stat.h> 5850276Speter#include <tic.h> 5950276Speter#include <term_entry.h> 6050276Speter 61166124SrafanMODULE_ID("$Id: read_termcap.c,v 1.71 2006/07/29 12:06:51 tom Exp $") 6250276Speter 6366963Speter#if !PURE_TERMINFO 6450276Speter 6550276Speter#define TC_SUCCESS 0 66166124Srafan#define TC_NOT_FOUND -1 67166124Srafan#define TC_SYS_ERR -2 68166124Srafan#define TC_REF_LOOP -3 69166124Srafan#define TC_UNRESOLVED -4 /* this is not returned by BSD cgetent */ 7050276Speter 71166124Srafanstatic NCURSES_CONST char * 7297049Speterget_termpath(void) 7397049Speter{ 74166124Srafan NCURSES_CONST char *result; 7597049Speter 7697049Speter if (!use_terminfo_vars() || (result = getenv("TERMPATH")) == 0) 7797049Speter result = TERMPATH; 7897049Speter T(("TERMPATH is %s", result)); 7997049Speter return result; 8097049Speter} 8197049Speter 8250276Speter#if USE_GETCAP 8350276Speter 8450276Speter#if HAVE_BSD_CGETENT 8550276Speter#define _nc_cgetcap cgetcap 8650276Speter#define _nc_cgetent(buf, oline, db_array, name) cgetent(buf, db_array, name) 8750276Speter#define _nc_cgetmatch cgetmatch 8850276Speter#define _nc_cgetset cgetset 8950276Speter#else 9050276Speterstatic int _nc_cgetmatch(char *, const char *); 9166963Speterstatic int _nc_getent(char **, unsigned *, int *, int, char **, int, const char 9266963Speter *, int, char *); 9350276Speterstatic int _nc_nfcmp(const char *, char *); 9450276Speter 9550276Speter/*- 9650276Speter * Copyright (c) 1992, 1993 9750276Speter * The Regents of the University of California. All rights reserved. 9850276Speter * 9950276Speter * This code is derived from software contributed to Berkeley by 10050276Speter * Casey Leedom of Lawrence Livermore National Laboratory. 10150276Speter * 10250276Speter * Redistribution and use in source and binary forms, with or without 10350276Speter * modification, are permitted provided that the following conditions 10450276Speter * are met: 10550276Speter * 1. Redistributions of source code must retain the above copyright 10650276Speter * notice, this list of conditions and the following disclaimer. 10750276Speter * 2. Redistributions in binary form must reproduce the above copyright 10850276Speter * notice, this list of conditions and the following disclaimer in the 10950276Speter * documentation and/or other materials provided with the distribution. 11050276Speter * 3. All advertising materials mentioning features or use of this software 11150276Speter * must display the following acknowledgment: 11250276Speter * This product includes software developed by the University of 11350276Speter * California, Berkeley and its contributors. 11450276Speter * 4. Neither the name of the University nor the names of its contributors 11550276Speter * may be used to endorse or promote products derived from this software 11650276Speter * without specific prior written permission. 11750276Speter * 11850276Speter * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 11950276Speter * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 12050276Speter * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 12150276Speter * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 12250276Speter * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 12350276Speter * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 12450276Speter * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 12550276Speter * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 12650276Speter * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 12750276Speter * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 12850276Speter * SUCH DAMAGE. 12950276Speter */ 13050276Speter 13150276Speter/* static char sccsid[] = "@(#)getcap.c 8.3 (Berkeley) 3/25/94"; */ 13250276Speter 13350276Speter#define BFRAG 1024 13450276Speter#define BSIZE 1024 13562449Speter#define MAX_RECURSION 32 /* maximum getent recursion */ 13650276Speter 13762449Speterstatic size_t topreclen; /* toprec length */ 13862449Speterstatic char *toprec; /* Additional record specified by cgetset() */ 13962449Speterstatic int gottoprec; /* Flag indicating retrieval of toprecord */ 14050276Speter 14150276Speter/* 14250276Speter * Cgetset() allows the addition of a user specified buffer to be added to the 14350276Speter * database array, in effect "pushing" the buffer on top of the virtual 14450276Speter * database. 0 is returned on success, -1 on failure. 14550276Speter */ 14650276Speterstatic int 14750276Speter_nc_cgetset(const char *ent) 14850276Speter{ 14962449Speter if (ent == 0) { 15062449Speter FreeIfNeeded(toprec); 15162449Speter toprec = 0; 15262449Speter topreclen = 0; 15350276Speter return (0); 15462449Speter } 15562449Speter topreclen = strlen(ent); 15662449Speter if ((toprec = typeMalloc(char, topreclen + 1)) == 0) { 15762449Speter errno = ENOMEM; 15862449Speter return (-1); 15962449Speter } 16062449Speter gottoprec = 0; 16162449Speter (void) strcpy(toprec, ent); 16262449Speter return (0); 16350276Speter} 16450276Speter 16550276Speter/* 16650276Speter * Cgetcap searches the capability record buf for the capability cap with type 16750276Speter * `type'. A pointer to the value of cap is returned on success, 0 if the 16850276Speter * requested capability couldn't be found. 16950276Speter * 17050276Speter * Specifying a type of ':' means that nothing should follow cap (:cap:). In 17150276Speter * this case a pointer to the terminating ':' or NUL will be returned if cap is 17250276Speter * found. 17350276Speter * 17450276Speter * If (cap, '@') or (cap, terminator, '@') is found before (cap, terminator) 17550276Speter * return 0. 17650276Speter */ 17750276Speterstatic char * 17850276Speter_nc_cgetcap(char *buf, const char *cap, int type) 17950276Speter{ 18062449Speter register const char *cp; 18162449Speter register char *bp; 18250276Speter 18362449Speter bp = buf; 18462449Speter for (;;) { 18562449Speter /* 18662449Speter * Skip past the current capability field - it's either the 18762449Speter * name field if this is the first time through the loop, or 18862449Speter * the remainder of a field whose name failed to match cap. 18962449Speter */ 19050276Speter for (;;) { 19162449Speter if (*bp == '\0') 19262449Speter return (0); 19362449Speter else if (*bp++ == ':') 19462449Speter break; 19562449Speter } 19650276Speter 19762449Speter /* 19862449Speter * Try to match (cap, type) in buf. 19962449Speter */ 20062449Speter for (cp = cap; *cp == *bp && *bp != '\0'; cp++, bp++) 20162449Speter continue; 20262449Speter if (*cp != '\0') 20362449Speter continue; 20462449Speter if (*bp == '@') 20562449Speter return (0); 20662449Speter if (type == ':') { 20762449Speter if (*bp != '\0' && *bp != ':') 20862449Speter continue; 20962449Speter return (bp); 21050276Speter } 21162449Speter if (*bp != type) 21262449Speter continue; 21362449Speter bp++; 21462449Speter return (*bp == '@' ? 0 : bp); 21562449Speter } 21662449Speter /* NOTREACHED */ 21750276Speter} 21850276Speter 21950276Speter/* 22050276Speter * Cgetent extracts the capability record name from the NULL terminated file 22150276Speter * array db_array and returns a pointer to a malloc'd copy of it in buf. Buf 22250276Speter * must be retained through all subsequent calls to cgetcap, cgetnum, cgetflag, 22350276Speter * and cgetstr, but may then be freed. 22450276Speter * 22550276Speter * Returns: 22650276Speter * 22750276Speter * positive # on success (i.e., the index in db_array) 22850276Speter * TC_NOT_FOUND if the requested record couldn't be found 22950276Speter * TC_SYS_ERR if a system error was encountered (e.g.,couldn't open a file) 23050276Speter * TC_REF_LOOP if a potential reference loop is detected 231166124Srafan * TC_UNRESOLVED if we had too many recurrences to resolve 23250276Speter */ 23350276Speterstatic int 23450276Speter_nc_cgetent(char **buf, int *oline, char **db_array, const char *name) 23550276Speter{ 23662449Speter unsigned dummy; 23750276Speter 23862449Speter return (_nc_getent(buf, &dummy, oline, 0, db_array, -1, name, 0, 0)); 23950276Speter} 24050276Speter 24150276Speter/* 24250276Speter * Getent implements the functions of cgetent. If fd is non-negative, 24350276Speter * *db_array has already been opened and fd is the open file descriptor. We 24450276Speter * do this to save time and avoid using up file descriptors for tc= 24550276Speter * recursions. 24650276Speter * 24750276Speter * Getent returns the same success/failure codes as cgetent. On success, a 24850276Speter * pointer to a malloc'd capability record with all tc= capabilities fully 24950276Speter * expanded and its length (not including trailing ASCII NUL) are left in 25050276Speter * *cap and *len. 25150276Speter * 25250276Speter * Basic algorithm: 25350276Speter * + Allocate memory incrementally as needed in chunks of size BFRAG 25450276Speter * for capability buffer. 25550276Speter * + Recurse for each tc=name and interpolate result. Stop when all 25650276Speter * names interpolated, a name can't be found, or depth exceeds 25750276Speter * MAX_RECURSION. 25850276Speter */ 25950276Speter#define DOALLOC(size) typeRealloc(char, size, record) 26050276Speterstatic int 26150276Speter_nc_getent( 26266963Speter char **cap, /* termcap-content */ 26366963Speter unsigned *len, /* length, needed for recursion */ 26466963Speter int *beginning, /* line-number at match */ 26566963Speter int in_array, /* index in 'db_array[] */ 26666963Speter char **db_array, /* list of files to search */ 26766963Speter int fd, 26866963Speter const char *name, 26966963Speter int depth, 27066963Speter char *nfield) 27150276Speter{ 27262449Speter register char *r_end, *rp; 27362449Speter int myfd = FALSE; 27462449Speter char *record = 0; 27562449Speter int tc_not_resolved; 27662449Speter int current; 27762449Speter int lineno; 27850276Speter 27962449Speter /* 28062449Speter * Return with ``loop detected'' error if we've recurred more than 28162449Speter * MAX_RECURSION times. 28262449Speter */ 28362449Speter if (depth > MAX_RECURSION) 28462449Speter return (TC_REF_LOOP); 28562449Speter 28662449Speter /* 28762449Speter * Check if we have a top record from cgetset(). 28862449Speter */ 28962449Speter if (depth == 0 && toprec != 0 && _nc_cgetmatch(toprec, name) == 0) { 29062449Speter if ((record = DOALLOC(topreclen + BFRAG)) == 0) { 29162449Speter errno = ENOMEM; 29262449Speter return (TC_SYS_ERR); 29362449Speter } 29462449Speter (void) strcpy(record, toprec); 29562449Speter rp = record + topreclen + 1; 29662449Speter r_end = rp + BFRAG; 29762449Speter current = in_array; 29862449Speter } else { 29962449Speter int foundit; 30062449Speter 30150276Speter /* 30262449Speter * Allocate first chunk of memory. 30350276Speter */ 30462449Speter if ((record = DOALLOC(BFRAG)) == 0) { 30562449Speter errno = ENOMEM; 30662449Speter return (TC_SYS_ERR); 30762449Speter } 30862449Speter rp = r_end = record + BFRAG; 30962449Speter foundit = FALSE; 31050276Speter 31150276Speter /* 31262449Speter * Loop through database array until finding the record. 31350276Speter */ 31462449Speter for (current = in_array; db_array[current] != 0; current++) { 31562449Speter int eof = FALSE; 31650276Speter 31762449Speter /* 31862449Speter * Open database if not already open. 31962449Speter */ 32062449Speter if (fd >= 0) { 32162449Speter (void) lseek(fd, (off_t) 0, SEEK_SET); 32262449Speter } else if ((_nc_access(db_array[current], R_OK) < 0) 32366963Speter || (fd = open(db_array[current], O_RDONLY, 0)) < 0) { 32462449Speter /* No error on unfound file. */ 32562449Speter if (errno == ENOENT) 32662449Speter continue; 32762449Speter free(record); 32862449Speter return (TC_SYS_ERR); 32962449Speter } else { 33062449Speter myfd = TRUE; 33162449Speter } 33262449Speter lineno = 0; 33350276Speter 33462449Speter /* 33562449Speter * Find the requested capability record ... 33662449Speter */ 33762449Speter { 33862449Speter char buf[2048]; 33962449Speter register char *b_end = buf; 34062449Speter register char *bp = buf; 34162449Speter register int c; 34262449Speter 34350276Speter /* 34462449Speter * Loop invariants: 34562449Speter * There is always room for one more character in record. 34662449Speter * R_end always points just past end of record. 34762449Speter * Rp always points just past last character in record. 34862449Speter * B_end always points just past last character in buf. 34962449Speter * Bp always points at next character in buf. 35050276Speter */ 35150276Speter 35262449Speter for (;;) { 35362449Speter int first = lineno + 1; 35462449Speter 35562449Speter /* 35662449Speter * Read in a line implementing (\, newline) 35762449Speter * line continuation. 35862449Speter */ 35962449Speter rp = record; 36062449Speter for (;;) { 36162449Speter if (bp >= b_end) { 36262449Speter int n; 36362449Speter 36462449Speter n = read(fd, buf, sizeof(buf)); 36562449Speter if (n <= 0) { 36662449Speter if (myfd) 36762449Speter (void) close(fd); 36862449Speter if (n < 0) { 36962449Speter free(record); 37062449Speter return (TC_SYS_ERR); 37162449Speter } 37262449Speter fd = -1; 37362449Speter eof = TRUE; 37462449Speter break; 37562449Speter } 37662449Speter b_end = buf + n; 37762449Speter bp = buf; 37850276Speter } 37950276Speter 38062449Speter c = *bp++; 38162449Speter if (c == '\n') { 38262449Speter lineno++; 38362449Speter if (rp == record || *(rp - 1) != '\\') 38462449Speter break; 38562449Speter } 38662449Speter *rp++ = c; 38762449Speter 38850276Speter /* 38962449Speter * Enforce loop invariant: if no room 39062449Speter * left in record buffer, try to get 39162449Speter * some more. 39250276Speter */ 39362449Speter if (rp >= r_end) { 39462449Speter unsigned pos; 39562449Speter size_t newsize; 39650276Speter 39762449Speter pos = rp - record; 39862449Speter newsize = r_end - record + BFRAG; 39962449Speter record = DOALLOC(newsize); 40062449Speter if (record == 0) { 40162449Speter if (myfd) 40262449Speter (void) close(fd); 40362449Speter errno = ENOMEM; 40462449Speter return (TC_SYS_ERR); 40562449Speter } 40662449Speter r_end = record + newsize; 40762449Speter rp = record + pos; 40862449Speter } 40962449Speter } 41062449Speter /* loop invariant lets us do this */ 41162449Speter *rp++ = '\0'; 41250276Speter 41362449Speter /* 41462449Speter * If encountered eof check next file. 41562449Speter */ 41662449Speter if (eof) 41762449Speter break; 41850276Speter 41962449Speter /* 42062449Speter * Toss blank lines and comments. 42162449Speter */ 42262449Speter if (*record == '\0' || *record == '#') 42362449Speter continue; 42450276Speter 42562449Speter /* 42662449Speter * See if this is the record we want ... 42762449Speter */ 42862449Speter if (_nc_cgetmatch(record, name) == 0 42962449Speter && (nfield == 0 43062449Speter || !_nc_nfcmp(nfield, record))) { 43162449Speter foundit = TRUE; 43262449Speter *beginning = first; 43362449Speter break; /* found it! */ 43462449Speter } 43562449Speter } 43662449Speter } 43762449Speter if (foundit) 43862449Speter break; 43962449Speter } 44050276Speter 44162449Speter if (!foundit) 44262449Speter return (TC_NOT_FOUND); 44362449Speter } 44450276Speter 44562449Speter /* 44662449Speter * Got the capability record, but now we have to expand all tc=name 44762449Speter * references in it ... 44862449Speter */ 44962449Speter { 45062449Speter register char *newicap, *s; 45162449Speter register int newilen; 45262449Speter unsigned ilen; 45362449Speter int diff, iret, tclen, oline; 45462449Speter char *icap, *scan, *tc, *tcstart, *tcend; 45550276Speter 45650276Speter /* 45762449Speter * Loop invariants: 45862449Speter * There is room for one more character in record. 45962449Speter * R_end points just past end of record. 46062449Speter * Rp points just past last character in record. 46162449Speter * Scan points at remainder of record that needs to be 46262449Speter * scanned for tc=name constructs. 46350276Speter */ 46462449Speter scan = record; 46562449Speter tc_not_resolved = FALSE; 46662449Speter for (;;) { 46762449Speter if ((tc = _nc_cgetcap(scan, "tc", '=')) == 0) 46862449Speter break; 46950276Speter 47062449Speter /* 47162449Speter * Find end of tc=name and stomp on the trailing `:' 47262449Speter * (if present) so we can use it to call ourselves. 47362449Speter */ 47462449Speter s = tc; 47562449Speter while (*s != '\0') { 47662449Speter if (*s++ == ':') { 47762449Speter *(s - 1) = '\0'; 47862449Speter break; 47962449Speter } 48062449Speter } 48162449Speter tcstart = tc - 3; 48262449Speter tclen = s - tcstart; 48362449Speter tcend = s; 48450276Speter 48562449Speter iret = _nc_getent(&icap, &ilen, &oline, current, db_array, fd, 48666963Speter tc, depth + 1, 0); 48762449Speter newicap = icap; /* Put into a register. */ 48862449Speter newilen = ilen; 48962449Speter if (iret != TC_SUCCESS) { 49062449Speter /* an error */ 49162449Speter if (iret < TC_NOT_FOUND) { 49262449Speter if (myfd) 49362449Speter (void) close(fd); 49462449Speter free(record); 49562449Speter return (iret); 49662449Speter } 49762449Speter if (iret == TC_UNRESOLVED) 49862449Speter tc_not_resolved = TRUE; 49962449Speter /* couldn't resolve tc */ 50062449Speter if (iret == TC_NOT_FOUND) { 50162449Speter *(s - 1) = ':'; 50262449Speter scan = s - 1; 50362449Speter tc_not_resolved = TRUE; 50462449Speter continue; 50562449Speter } 50662449Speter } 50750276Speter 50862449Speter /* not interested in name field of tc'ed record */ 50962449Speter s = newicap; 51062449Speter while (*s != '\0' && *s++ != ':') ; 51162449Speter newilen -= s - newicap; 51262449Speter newicap = s; 51350276Speter 51462449Speter /* make sure interpolated record is `:'-terminated */ 51562449Speter s += newilen; 51662449Speter if (*(s - 1) != ':') { 51762449Speter *s = ':'; /* overwrite NUL with : */ 51862449Speter newilen++; 51962449Speter } 52050276Speter 52162449Speter /* 52262449Speter * Make sure there's enough room to insert the 52362449Speter * new record. 52462449Speter */ 52562449Speter diff = newilen - tclen; 52662449Speter if (diff >= r_end - rp) { 52762449Speter unsigned pos, tcpos, tcposend; 52862449Speter size_t newsize; 52950276Speter 53062449Speter pos = rp - record; 53162449Speter newsize = r_end - record + diff + BFRAG; 53262449Speter tcpos = tcstart - record; 53362449Speter tcposend = tcend - record; 53462449Speter record = DOALLOC(newsize); 53562449Speter if (record == 0) { 53662449Speter if (myfd) 53762449Speter (void) close(fd); 53862449Speter free(icap); 53962449Speter errno = ENOMEM; 54062449Speter return (TC_SYS_ERR); 54162449Speter } 54262449Speter r_end = record + newsize; 54362449Speter rp = record + pos; 54462449Speter tcstart = record + tcpos; 54562449Speter tcend = record + tcposend; 54662449Speter } 54750276Speter 54862449Speter /* 54962449Speter * Insert tc'ed record into our record. 55062449Speter */ 55162449Speter s = tcstart + newilen; 55262449Speter memmove(s, tcend, (size_t) (rp - tcend)); 55362449Speter memmove(tcstart, newicap, (size_t) newilen); 55462449Speter rp += diff; 55562449Speter free(icap); 55650276Speter 55762449Speter /* 55862449Speter * Start scan on `:' so next cgetcap works properly 55962449Speter * (cgetcap always skips first field). 56062449Speter */ 56162449Speter scan = s - 1; 56250276Speter } 56362449Speter } 56450276Speter 56562449Speter /* 56662449Speter * Close file (if we opened it), give back any extra memory, and 56762449Speter * return capability, length and success. 56862449Speter */ 56962449Speter if (myfd) 57062449Speter (void) close(fd); 57162449Speter *len = rp - record - 1; /* don't count NUL */ 57262449Speter if (r_end > rp) { 57362449Speter if ((record = DOALLOC((size_t) (rp - record))) == 0) { 57462449Speter errno = ENOMEM; 57562449Speter return (TC_SYS_ERR); 57650276Speter } 57762449Speter } 57850276Speter 57962449Speter *cap = record; 58062449Speter if (tc_not_resolved) 58162449Speter return (TC_UNRESOLVED); 58262449Speter return (current); 58350276Speter} 58450276Speter 58550276Speter/* 58650276Speter * Cgetmatch will return 0 if name is one of the names of the capability 58750276Speter * record buf, -1 if not. 58850276Speter */ 58950276Speterstatic int 59050276Speter_nc_cgetmatch(char *buf, const char *name) 59150276Speter{ 59262449Speter register const char *np; 59362449Speter register char *bp; 59450276Speter 59562449Speter /* 59662449Speter * Start search at beginning of record. 59762449Speter */ 59862449Speter bp = buf; 59962449Speter for (;;) { 60050276Speter /* 60162449Speter * Try to match a record name. 60250276Speter */ 60362449Speter np = name; 60450276Speter for (;;) { 60562449Speter if (*np == '\0') { 60662449Speter if (*bp == '|' || *bp == ':' || *bp == '\0') 60762449Speter return (0); 60862449Speter else 60962449Speter break; 61062449Speter } else if (*bp++ != *np++) { 61162449Speter break; 61262449Speter } 61362449Speter } 61450276Speter 61562449Speter /* 61662449Speter * Match failed, skip to next name in record. 61762449Speter */ 61862449Speter bp--; /* a '|' or ':' may have stopped the match */ 61962449Speter for (;;) { 62062449Speter if (*bp == '\0' || *bp == ':') 62162449Speter return (-1); /* match failed totally */ 62262449Speter else if (*bp++ == '|') 62362449Speter break; /* found next name */ 62450276Speter } 62562449Speter } 62650276Speter} 62750276Speter 62850276Speter/* 62950276Speter * Compare name field of record. 63050276Speter */ 63150276Speterstatic int 63250276Speter_nc_nfcmp(const char *nf, char *rec) 63350276Speter{ 63462449Speter char *cp, tmp; 63562449Speter int ret; 63650276Speter 63762449Speter for (cp = rec; *cp != ':'; cp++) ; 63850276Speter 63962449Speter tmp = *(cp + 1); 64062449Speter *(cp + 1) = '\0'; 64162449Speter ret = strcmp(nf, rec); 64262449Speter *(cp + 1) = tmp; 64350276Speter 64462449Speter return (ret); 64550276Speter} 64650276Speter#endif /* HAVE_BSD_CGETENT */ 64750276Speter 64850276Speter/* 64950276Speter * Since ncurses provides its own 'tgetent()', we cannot use the native one. 65050276Speter * So we reproduce the logic to get down to cgetent() -- or our cut-down 65150276Speter * version of that -- to circumvent the problem of configuring against the 65250276Speter * termcap library. 65350276Speter */ 65450276Speter#define USE_BSD_TGETENT 1 65550276Speter 65650276Speter#if USE_BSD_TGETENT 65750276Speter/* 65850276Speter * Copyright (c) 1980, 1993 65950276Speter * The Regents of the University of California. All rights reserved. 66050276Speter * 66150276Speter * Redistribution and use in source and binary forms, with or without 66250276Speter * modification, are permitted provided that the following conditions 66350276Speter * are met: 66450276Speter * 1. Redistributions of source code must retain the above copyright 66550276Speter * notice, this list of conditions and the following disclaimer. 66650276Speter * 2. Redistributions in binary form must reproduce the above copyright 66750276Speter * notice, this list of conditions and the following disclaimer in the 66850276Speter * documentation and/or other materials provided with the distribution. 66950276Speter * 3. All advertising materials mentioning features or use of this software 67050276Speter * must display the following acknowledgment: 67150276Speter * This product includes software developed by the University of 67250276Speter * California, Berkeley and its contributors. 67350276Speter * 4. Neither the name of the University nor the names of its contributors 67450276Speter * may be used to endorse or promote products derived from this software 67550276Speter * without specific prior written permission. 67650276Speter * 67750276Speter * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 67850276Speter * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 67950276Speter * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 68050276Speter * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 68150276Speter * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 68250276Speter * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 68350276Speter * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 68450276Speter * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 68550276Speter * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 68650276Speter * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 68750276Speter * SUCH DAMAGE. 68850276Speter */ 68950276Speter 69050276Speter/* static char sccsid[] = "@(#)termcap.c 8.1 (Berkeley) 6/4/93" */ 69150276Speter 69250276Speter#define PBUFSIZ 512 /* max length of filename path */ 69350276Speter#define PVECSIZ 32 /* max number of names in path */ 69450276Speter#define TBUFSIZ (2048*2) 69550276Speter 69650276Speterstatic char *tbuf; 69750276Speter 69850276Speter/* 69950276Speter * On entry, srcp points to a non ':' character which is the beginning of the 70050276Speter * token, if any. We'll try to return a string that doesn't end with a ':'. 70150276Speter */ 70250276Speterstatic char * 70350276Speterget_tc_token(char **srcp, int *endp) 70450276Speter{ 70562449Speter int ch; 70662449Speter bool found = FALSE; 70762449Speter char *s, *base; 70862449Speter char *tok = 0; 70950276Speter 71062449Speter *endp = TRUE; 71162449Speter for (s = base = *srcp; *s != '\0';) { 71262449Speter ch = *s++; 71362449Speter if (ch == '\\') { 71462449Speter if (*s == '\0') { 71562449Speter break; 71662449Speter } else if (*s++ == '\n') { 717166124Srafan while (isspace(UChar(*s))) 71862449Speter s++; 71962449Speter } else { 72062449Speter found = TRUE; 72162449Speter } 72262449Speter } else if (ch == ':') { 72362449Speter if (found) { 72450276Speter tok = base; 72562449Speter s[-1] = '\0'; 72662449Speter *srcp = s; 72762449Speter *endp = FALSE; 72862449Speter break; 72962449Speter } 73062449Speter base = s; 731166124Srafan } else if (isgraph(UChar(ch))) { 73262449Speter found = TRUE; 73350276Speter } 73462449Speter } 73550276Speter 73662449Speter /* malformed entry may end without a ':' */ 73762449Speter if (tok == 0 && found) { 73862449Speter tok = base; 73962449Speter } 74062449Speter 74162449Speter return tok; 74250276Speter} 74350276Speter 74450276Speterstatic char * 74550276Spetercopy_tc_token(char *dst, const char *src, size_t len) 74650276Speter{ 74762449Speter int ch; 74850276Speter 74962449Speter while ((ch = *src++) != '\0') { 75062449Speter if (ch == '\\' && *src == '\n') { 751166124Srafan while (isspace(UChar(*src))) 75262449Speter src++; 75362449Speter continue; 75450276Speter } 75562449Speter if (--len == 0) { 75662449Speter dst = 0; 75762449Speter break; 75862449Speter } 75962449Speter *dst++ = ch; 76062449Speter } 76162449Speter return dst; 76250276Speter} 76350276Speter 76450276Speter/* 76550276Speter * Get an entry for terminal name in buffer bp from the termcap file. 76650276Speter */ 76750276Speterstatic int 76850276Speter_nc_tgetent(char *bp, char **sourcename, int *lineno, const char *name) 76950276Speter{ 77062449Speter static char *the_source; 77150276Speter 77262449Speter register char *p; 77362449Speter register char *cp; 77476726Speter char *dummy = NULL; 77562449Speter char **fname; 77662449Speter char *home; 77762449Speter int i; 77862449Speter char pathbuf[PBUFSIZ]; /* holds raw path of filenames */ 77962449Speter char *pathvec[PVECSIZ]; /* to point to names in pathbuf */ 78062449Speter char **pvec; /* holds usable tail of path vector */ 781166124Srafan NCURSES_CONST char *termpath; 78266963Speter string_desc desc; 78350276Speter 78462449Speter fname = pathvec; 78562449Speter pvec = pathvec; 78662449Speter tbuf = bp; 78762449Speter p = pathbuf; 78876726Speter cp = use_terminfo_vars()? getenv("TERMCAP") : NULL; 78950276Speter 79062449Speter /* 79162449Speter * TERMCAP can have one of two things in it. It can be the name of a file 79262449Speter * to use instead of /etc/termcap. In this case it better start with a 79362449Speter * "/". Or it can be an entry to use so we don't have to read the file. 79462449Speter * In this case it has to already have the newlines crunched out. If 79562449Speter * TERMCAP does not hold a file name then a path of names is searched 79662449Speter * instead. The path is found in the TERMPATH variable, or becomes 79762449Speter * "$HOME/.termcap /etc/termcap" if no TERMPATH exists. 79862449Speter */ 79966963Speter _nc_str_init(&desc, pathbuf, sizeof(pathbuf)); 80066963Speter if (cp == NULL) { 80197049Speter _nc_safe_strcpy(&desc, get_termpath()); 802166124Srafan } else if (!_nc_is_abs_path(cp)) { /* TERMCAP holds an entry */ 80397049Speter if ((termpath = get_termpath()) != 0) { 80466963Speter _nc_safe_strcat(&desc, termpath); 80562449Speter } else { 80666963Speter char temp[PBUFSIZ]; 80766963Speter temp[0] = 0; 80866963Speter if ((home = getenv("HOME")) != 0 && *home != '\0' 80966963Speter && strchr(home, ' ') == 0 81066963Speter && strlen(home) < sizeof(temp) - 10) { /* setup path */ 81166963Speter sprintf(temp, "%s/", home); /* $HOME first */ 81266963Speter } 81366963Speter /* if no $HOME look in current directory */ 81466963Speter strcat(temp, ".termcap"); 81566963Speter _nc_safe_strcat(&desc, temp); 81697049Speter _nc_safe_strcat(&desc, " "); 81797049Speter _nc_safe_strcat(&desc, get_termpath()); 81850276Speter } 81966963Speter } else { /* user-defined name in TERMCAP */ 82066963Speter _nc_safe_strcat(&desc, cp); /* still can be tokenized */ 82166963Speter } 82250276Speter 82362449Speter *fname++ = pathbuf; /* tokenize path into vector of names */ 82462449Speter while (*++p) { 82576726Speter if (*p == ' ' || *p == NCURSES_PATHSEP) { 82662449Speter *p = '\0'; 82762449Speter while (*++p) 82876726Speter if (*p != ' ' && *p != NCURSES_PATHSEP) 82962449Speter break; 83062449Speter if (*p == '\0') 83162449Speter break; 83262449Speter *fname++ = p; 83362449Speter if (fname >= pathvec + PVECSIZ) { 83462449Speter fname--; 83562449Speter break; 83662449Speter } 83750276Speter } 83862449Speter } 83962449Speter *fname = 0; /* mark end of vector */ 840166124Srafan if (_nc_is_abs_path(cp)) { 84162449Speter if (_nc_cgetset(cp) < 0) { 84262449Speter return (TC_SYS_ERR); 84350276Speter } 84462449Speter } 84550276Speter 84662449Speter i = _nc_cgetent(&dummy, lineno, pathvec, name); 84750276Speter 84862449Speter /* ncurses' termcap-parsing routines cannot handle multiple adjacent 84962449Speter * empty fields, and mistakenly use the last valid cap entry instead of 85062449Speter * the first (breaks tc= includes) 85162449Speter */ 85262449Speter if (i >= 0) { 85362449Speter char *pd, *ps, *tok; 85462449Speter int endflag = FALSE; 85562449Speter char *list[1023]; 85662449Speter size_t n, count = 0; 85750276Speter 85862449Speter pd = bp; 85962449Speter ps = dummy; 86062449Speter while (!endflag && (tok = get_tc_token(&ps, &endflag)) != 0) { 86162449Speter bool ignore = FALSE; 86250276Speter 86362449Speter for (n = 1; n < count; n++) { 86462449Speter char *s = list[n]; 86562449Speter if (s[0] == tok[0] 86662449Speter && s[1] == tok[1]) { 86762449Speter ignore = TRUE; 86862449Speter break; 86950276Speter } 87062449Speter } 87162449Speter if (ignore != TRUE) { 87262449Speter list[count++] = tok; 87362449Speter pd = copy_tc_token(pd, tok, TBUFSIZ - (2 + pd - bp)); 87462449Speter if (pd == 0) { 87562449Speter i = -1; 87662449Speter break; 87762449Speter } 87862449Speter *pd++ = ':'; 87962449Speter *pd = '\0'; 88062449Speter } 88150276Speter } 88262449Speter } 88350276Speter 88462449Speter FreeIfNeeded(dummy); 88562449Speter FreeIfNeeded(the_source); 88662449Speter the_source = 0; 88750276Speter 88862449Speter /* This is not related to the BSD cgetent(), but to fake up a suitable 88962449Speter * filename for ncurses' error reporting. (If we are not using BSD 89062449Speter * cgetent, then it is the actual filename). 89162449Speter */ 89262449Speter if (i >= 0) { 893166124Srafan#if HAVE_BSD_CGETENT 894166124Srafan char temp[PATH_MAX]; 895166124Srafan 896166124Srafan _nc_str_init(&desc, temp, sizeof(temp)); 897166124Srafan _nc_safe_strcpy(&desc, pathvec[i]); 898166124Srafan _nc_safe_strcat(&desc, ".db"); 899166124Srafan if (_nc_access(temp, R_OK) == 0) { 900166124Srafan _nc_safe_strcpy(&desc, pathvec[i]); 901166124Srafan } 902166124Srafan if ((the_source = strdup(temp)) != 0) 903166124Srafan *sourcename = the_source; 904166124Srafan#else 90562449Speter if ((the_source = strdup(pathvec[i])) != 0) 90662449Speter *sourcename = the_source; 907166124Srafan#endif 90862449Speter } 90950276Speter 91062449Speter return (i); 91150276Speter} 91250276Speter#endif /* USE_BSD_TGETENT */ 91350276Speter#endif /* USE_GETCAP */ 91450276Speter 91550276Speter#define MAXPATHS 32 91650276Speter 91750276Speter/* 91850276Speter * Add a filename to the list in 'termpaths[]', checking that we really have 91950276Speter * a right to open the file. 92050276Speter */ 92150276Speter#if !USE_GETCAP 92262449Speterstatic int 92362449Speteradd_tc(char *termpaths[], char *path, int count) 92450276Speter{ 92597049Speter char *save = strchr(path, NCURSES_PATHSEP); 92697049Speter if (save != 0) 92797049Speter *save = '\0'; 92862449Speter if (count < MAXPATHS 92997049Speter && _nc_access(path, R_OK) == 0) { 93062449Speter termpaths[count++] = path; 93197049Speter T(("Adding termpath %s", path)); 93297049Speter } 93362449Speter termpaths[count] = 0; 93497049Speter if (save != 0) 93597049Speter *save = NCURSES_PATHSEP; 93662449Speter return count; 93750276Speter} 93850276Speter#define ADD_TC(path, count) filecount = add_tc(termpaths, path, count) 93950276Speter#endif /* !USE_GETCAP */ 94050276Speter 94176726SpeterNCURSES_EXPORT(int) 942166124Srafan_nc_read_termcap_entry(const char *const tn, TERMTYPE *const tp) 94350276Speter{ 944166124Srafan int found = TGETENT_NO; 94562449Speter ENTRY *ep; 94650276Speter#if USE_GETCAP_CACHE 94762449Speter char cwd_buf[PATH_MAX]; 94850276Speter#endif 94950276Speter#if USE_GETCAP 95062449Speter char *p, tc[TBUFSIZ]; 951166124Srafan int status; 95262449Speter static char *source; 95362449Speter static int lineno; 95450276Speter 95597049Speter T(("read termcap entry for %s", tn)); 956166124Srafan 957166124Srafan if (strlen(tn) == 0 958166124Srafan || strcmp(tn, ".") == 0 959166124Srafan || strcmp(tn, "..") == 0 960166124Srafan || _nc_pathlast(tn) != 0) { 961166124Srafan T(("illegal or missing entry name '%s'", tn)); 962166124Srafan return TGETENT_NO; 963166124Srafan } 964166124Srafan 96566963Speter if (use_terminfo_vars() && (p = getenv("TERMCAP")) != 0 966166124Srafan && !_nc_is_abs_path(p) && _nc_name_match(p, tn, "|:")) { 96762449Speter /* TERMCAP holds a termcap entry */ 96862449Speter strncpy(tc, p, sizeof(tc) - 1); 96962449Speter tc[sizeof(tc) - 1] = '\0'; 97062449Speter _nc_set_source("TERMCAP"); 97162449Speter } else { 97250276Speter /* we're using getcap(3) */ 973166124Srafan if ((status = _nc_tgetent(tc, &source, &lineno, tn)) < 0) 974166124Srafan return (status == TC_NOT_FOUND ? TGETENT_NO : TGETENT_ERR); 97550276Speter 97650276Speter _nc_curr_line = lineno; 97750276Speter _nc_set_source(source); 97862449Speter } 97962449Speter _nc_read_entry_source((FILE *) 0, tc, FALSE, FALSE, NULLHOOK); 98050276Speter#else 98162449Speter /* 98262449Speter * Here is what the 4.4BSD termcap(3) page prescribes: 98362449Speter * 98462449Speter * It will look in the environment for a TERMCAP variable. If found, and 98562449Speter * the value does not begin with a slash, and the terminal type name is the 98662449Speter * same as the environment string TERM, the TERMCAP string is used instead 98762449Speter * of reading a termcap file. If it does begin with a slash, the string is 98862449Speter * used as a path name of the termcap file to search. If TERMCAP does not 98962449Speter * begin with a slash and name is different from TERM, tgetent() searches 99062449Speter * the files $HOME/.termcap and /usr/share/misc/termcap, in that order, 99162449Speter * unless the environment variable TERMPATH exists, in which case it 99262449Speter * specifies a list of file pathnames (separated by spaces or colons) to be 99362449Speter * searched instead. 99462449Speter * 99562449Speter * It goes on to state: 99662449Speter * 99762449Speter * Whenever multiple files are searched and a tc field occurs in the 99862449Speter * requested entry, the entry it names must be found in the same file or 99962449Speter * one of the succeeding files. 100062449Speter * 100162449Speter * However, this restriction is relaxed in ncurses; tc references to 100262449Speter * previous files are permitted. 100362449Speter * 100462449Speter * This routine returns 1 if an entry is found, 0 if not found, and -1 if 100562449Speter * the database is not accessible. 100662449Speter */ 100762449Speter FILE *fp; 100862449Speter char *tc, *termpaths[MAXPATHS]; 100962449Speter int filecount = 0; 101097049Speter int j, k; 101162449Speter bool use_buffer = FALSE; 101297049Speter bool normal = TRUE; 101362449Speter char tc_buf[1024]; 101462449Speter char pathbuf[PATH_MAX]; 101597049Speter char *copied = 0; 101697049Speter char *cp; 101797049Speter struct stat test_stat[MAXPATHS]; 101850276Speter 101962449Speter termpaths[filecount] = 0; 102066963Speter if (use_terminfo_vars() && (tc = getenv("TERMCAP")) != 0) { 1021166124Srafan if (_nc_is_abs_path(tc)) { /* interpret as a filename */ 102262449Speter ADD_TC(tc, 0); 102397049Speter normal = FALSE; 102462449Speter } else if (_nc_name_match(tc, tn, "|:")) { /* treat as a capability file */ 102562449Speter use_buffer = TRUE; 102662449Speter (void) sprintf(tc_buf, "%.*s\n", (int) sizeof(tc_buf) - 2, tc); 102797049Speter normal = FALSE; 102897049Speter } 102997049Speter } 103050276Speter 103197049Speter if (normal) { /* normal case */ 103297049Speter char envhome[PATH_MAX], *h; 103397049Speter 103497049Speter copied = strdup(get_termpath()); 103597049Speter for (cp = copied; *cp; cp++) { 103697049Speter if (*cp == NCURSES_PATHSEP) 103797049Speter *cp = '\0'; 103897049Speter else if (cp == copied || cp[-1] == '\0') { 103997049Speter ADD_TC(cp, filecount); 104062449Speter } 104150276Speter } 104250276Speter 104350276Speter#define PRIVATE_CAP "%s/.termcap" 104450276Speter 104576726Speter if (use_terminfo_vars() && (h = getenv("HOME")) != NULL && *h != '\0' 104662449Speter && (strlen(h) + sizeof(PRIVATE_CAP)) < PATH_MAX) { 104762449Speter /* user's .termcap, if any, should override it */ 104862449Speter (void) strcpy(envhome, h); 104962449Speter (void) sprintf(pathbuf, PRIVATE_CAP, envhome); 105062449Speter ADD_TC(pathbuf, filecount); 105150276Speter } 105262449Speter } 105350276Speter 105497049Speter /* 105597049Speter * Probably /etc/termcap is a symlink to /usr/share/misc/termcap. 105697049Speter * Avoid reading the same file twice. 105797049Speter */ 1058166124Srafan#if HAVE_LINK 105997049Speter for (j = 0; j < filecount; j++) { 106097049Speter bool omit = FALSE; 106197049Speter if (stat(termpaths[j], &test_stat[j]) != 0 106297049Speter || (test_stat[j].st_mode & S_IFMT) != S_IFREG) { 106397049Speter omit = TRUE; 106497049Speter } else { 106597049Speter for (k = 0; k < j; k++) { 106697049Speter if (test_stat[k].st_dev == test_stat[j].st_dev 106797049Speter && test_stat[k].st_ino == test_stat[j].st_ino) { 106897049Speter omit = TRUE; 106997049Speter break; 107097049Speter } 107197049Speter } 107297049Speter } 107397049Speter if (omit) { 107497049Speter T(("Path %s is a duplicate", termpaths[j])); 107597049Speter for (k = j + 1; k < filecount; k++) { 107697049Speter termpaths[k - 1] = termpaths[k]; 107797049Speter test_stat[k - 1] = test_stat[k]; 107897049Speter } 107997049Speter --filecount; 108097049Speter --j; 108197049Speter } 108297049Speter } 108397049Speter#endif 108497049Speter 108562449Speter /* parse the sources */ 108662449Speter if (use_buffer) { 108762449Speter _nc_set_source("TERMCAP"); 108850276Speter 108962449Speter /* 109062449Speter * We don't suppress warning messages here. The presumption is 109162449Speter * that since it's just a single entry, they won't be a pain. 109262449Speter */ 109362449Speter _nc_read_entry_source((FILE *) 0, tc_buf, FALSE, FALSE, NULLHOOK); 109462449Speter } else { 109562449Speter int i; 109650276Speter 109762449Speter for (i = 0; i < filecount; i++) { 109850276Speter 109962449Speter T(("Looking for %s in %s", tn, termpaths[i])); 110097049Speter if (_nc_access(termpaths[i], R_OK) == 0 110197049Speter && (fp = fopen(termpaths[i], "r")) != (FILE *) 0) { 110262449Speter _nc_set_source(termpaths[i]); 110350276Speter 110462449Speter /* 110562449Speter * Suppress warning messages. Otherwise you get 400 lines of 110662449Speter * crap from archaic termcap files as ncurses complains about 110762449Speter * all the obsolete capabilities. 110862449Speter */ 110962449Speter _nc_read_entry_source(fp, (char *) 0, FALSE, TRUE, NULLHOOK); 111050276Speter 111162449Speter (void) fclose(fp); 111262449Speter } 111350276Speter } 111462449Speter } 111597049Speter if (copied != 0) 111697049Speter free(copied); 111750276Speter#endif /* USE_GETCAP */ 111850276Speter 111962449Speter if (_nc_head == 0) 1120166124Srafan return (TGETENT_ERR); 112150276Speter 112262449Speter /* resolve all use references */ 1123166124Srafan _nc_resolve_uses2(TRUE, FALSE); 112450276Speter 112562449Speter /* find a terminal matching tn, if we can */ 112650276Speter#if USE_GETCAP_CACHE 112762449Speter if (getcwd(cwd_buf, sizeof(cwd_buf)) != 0) { 112862449Speter _nc_set_writedir((char *) 0); /* note: this does a chdir */ 112950276Speter#endif 113062449Speter for_entry_list(ep) { 113162449Speter if (_nc_name_match(ep->tterm.term_names, tn, "|:")) { 113262449Speter /* 1133166124Srafan * Make a local copy of the terminal capabilities, delinked 1134166124Srafan * from the list. 113562449Speter */ 113662449Speter *tp = ep->tterm; 1137166124Srafan _nc_delink_entry(_nc_head, &(ep->tterm)); 1138166124Srafan free(ep); 113950276Speter 114062449Speter /* 114162449Speter * OK, now try to write the type to user's terminfo directory. 114262449Speter * Next time he loads this, it will come through terminfo. 114362449Speter * 114462449Speter * Advantage: Second and subsequent fetches of this entry will 114562449Speter * be very fast. 114662449Speter * 114762449Speter * Disadvantage: After the first time a termcap type is loaded 114862449Speter * by its user, editing it in the /etc/termcap file, or in 114962449Speter * TERMCAP, or in a local ~/.termcap, will be ineffective 115062449Speter * unless the terminfo entry is explicitly removed. 115162449Speter */ 115250276Speter#if USE_GETCAP_CACHE 115362449Speter (void) _nc_write_entry(tp); 115450276Speter#endif 1155166124Srafan found = TGETENT_YES; 115662449Speter break; 115762449Speter } 115862449Speter } 115950276Speter#if USE_GETCAP_CACHE 116062449Speter chdir(cwd_buf); 116162449Speter } 116250276Speter#endif 116350276Speter 116462449Speter return (found); 116550276Speter} 116650276Speter#else 116776726Speterextern 116876726SpeterNCURSES_EXPORT(void) 116976726Speter_nc_read_termcap(void); 117076726SpeterNCURSES_EXPORT(void) 117162449Speter_nc_read_termcap(void) 117262449Speter{ 117362449Speter} 117462449Speter#endif /* PURE_TERMINFO */ 1175