version 1.3, 1994/01/13 22:24:06 |
version 1.54.18.1, 2009/08/04 20:04:39 |
|
|
|
/* $NetBSD$ */ |
|
|
/* |
/* |
* Copyright (c) 1980 The Regents of the University of California. |
* Copyright (c) 1980, 1993 |
* All rights reserved. |
* The Regents of the University of California. All rights reserved. |
* |
* |
* Redistribution and use in source and binary forms, with or without |
* Redistribution and use in source and binary forms, with or without |
* modification, are permitted provided that the following conditions |
* modification, are permitted provided that the following conditions |
|
|
* 2. Redistributions in binary form must reproduce the above copyright |
* 2. Redistributions in binary form must reproduce the above copyright |
* notice, this list of conditions and the following disclaimer in the |
* notice, this list of conditions and the following disclaimer in the |
* documentation and/or other materials provided with the distribution. |
* documentation and/or other materials provided with the distribution. |
* 3. All advertising materials mentioning features or use of this software |
* 3. Neither the name of the University nor the names of its contributors |
* must display the following acknowledgement: |
|
* This product includes software developed by the University of |
|
* California, Berkeley and its contributors. |
|
* 4. Neither the name of the University nor the names of its contributors |
|
* may be used to endorse or promote products derived from this software |
* may be used to endorse or promote products derived from this software |
* without specific prior written permission. |
* without specific prior written permission. |
* |
* |
|
|
* SUCH DAMAGE. |
* SUCH DAMAGE. |
*/ |
*/ |
|
|
|
#include <sys/cdefs.h> |
#ifndef lint |
#ifndef lint |
/*static char sccsid[] = "from: @(#)termcap.c 5.5 (Berkeley) 6/1/90";*/ |
#if 0 |
static char rcsid[] = "$Id$"; |
static char sccsid[] = "@(#)termcap.c 8.1 (Berkeley) 6/4/93"; |
|
#else |
|
__RCSID("$NetBSD$"); |
|
#endif |
#endif /* not lint */ |
#endif /* not lint */ |
|
|
#define BUFSIZ 1024 |
#include <sys/types.h> |
#define MAXHOP 32 /* max number of tc= indirections */ |
#include <sys/param.h> |
#define PBUFSIZ 512 /* max length of filename path */ |
#include <assert.h> |
#define PVECSIZ 32 /* max number of names in path */ |
|
|
|
#include <ctype.h> |
#include <ctype.h> |
|
#include <stdio.h> |
|
#include <stdlib.h> |
|
#include <string.h> |
|
#include <termcap.h> |
|
#include <errno.h> |
#include "pathnames.h" |
#include "pathnames.h" |
|
#include "termcap_private.h" |
|
|
|
#define PBUFSIZ MAXPATHLEN /* max length of filename path */ |
|
#define PVECSIZ 32 /* max number of names in path */ |
|
#define CAPSIZ 256 /* max capability size */ |
|
|
/* |
/* |
* termcap - routines for dealing with the terminal capability data base |
* termcap - routines for dealing with the terminal capability data base |
Line 58 static char rcsid[] = "$Id$"; |
|
Line 68 static char rcsid[] = "$Id$"; |
|
* doesn't, and because living w/o it is not hard. |
* doesn't, and because living w/o it is not hard. |
*/ |
*/ |
|
|
static char *tbuf; |
static char *tbuf = NULL; /* termcap buffer */ |
static int hopcount; /* detect infinite loops in termcap, init 0 */ |
static struct tinfo *fbuf = NULL; /* untruncated termcap buffer */ |
static char pathbuf[PBUFSIZ]; /* holds raw path of filenames */ |
|
static char *pathvec[PVECSIZ]; /* to point to names in pathbuf */ |
|
static char **pvec; /* holds usable tail of path vector */ |
|
static char *tskip(); |
|
static char *tdecode(); |
|
char *tgetstr(); |
|
char *getenv(); |
|
|
|
/* |
/* |
* Get an entry for terminal name in buffer bp from the termcap file. |
* Set the termcap entry to the arbitrary string passed in, this can |
|
* be used to provide a "dummy" termcap entry if a real one does not |
|
* exist. This function will malloc the buffer and space for the |
|
* string. If an error occurs return -1 otherwise return 0. |
*/ |
*/ |
tgetent(bp, name) |
int |
char *bp, *name; |
t_setinfo(struct tinfo **bp, const char *entry) |
{ |
{ |
register char *p; |
char capability[CAPSIZ], *cap_ptr; |
register char *cp; |
size_t limit; |
register int c; |
|
char *term, *home, *termpath; |
_DIAGASSERT(bp != NULL); |
char **fname = pathvec; |
_DIAGASSERT(entry != NULL); |
|
|
|
if ((*bp = malloc(sizeof(struct tinfo))) == NULL) |
|
return -1; |
|
|
|
if (((*bp)->info = (char *) malloc(strlen(entry) + 1)) == NULL) |
|
return -1; |
|
|
|
strcpy((*bp)->info, entry); |
|
|
|
cap_ptr = capability; |
|
limit = sizeof(capability) - 1; |
|
(*bp)->up = t_getstr(*bp, "up", &cap_ptr, &limit); |
|
if ((*bp)->up) |
|
(*bp)->up = strdup((*bp)->up); |
|
cap_ptr = capability; |
|
limit = sizeof(capability) - 1; |
|
(*bp)->bc = t_getstr(*bp, "bc", &cap_ptr, &limit); |
|
if ((*bp)->bc) |
|
(*bp)->bc = strdup((*bp)->bc); |
|
(*bp)->tbuf = NULL; |
|
|
|
return 0; |
|
} |
|
|
|
/* |
|
* Get an extended entry for the terminal name. This differs from |
|
* tgetent only in a) the buffer is malloc'ed for the caller and |
|
* b) the termcap entry is not truncated to 1023 characters. |
|
*/ |
|
|
|
int |
|
t_getent(struct tinfo **bp, const char *name) |
|
{ |
|
char *p; |
|
char *cp; |
|
char **fname; |
|
char *home; |
|
int i, did_getset; |
|
size_t limit; |
|
char pathbuf[PBUFSIZ]; /* holds raw path of filenames */ |
|
char *pathvec[PVECSIZ]; /* to point to names in pathbuf */ |
|
char *termpath; |
|
char capability[CAPSIZ], *cap_ptr; |
|
int error; |
|
|
|
|
pvec = pathvec; |
_DIAGASSERT(bp != NULL); |
tbuf = bp; |
_DIAGASSERT(name != NULL); |
|
|
|
if ((*bp = malloc(sizeof(struct tinfo))) == NULL) |
|
return 0; |
|
|
|
fname = pathvec; |
p = pathbuf; |
p = pathbuf; |
cp = getenv("TERMCAP"); |
cp = getenv("TERMCAP"); |
/* |
/* |
* TERMCAP can have one of two things in it. It can be the |
* 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 |
* name of a file to use instead of |
* case it better start with a "/". Or it can be an entry to |
* /usr/share/misc/termcap. In this case it better start with |
* use so we don't have to read the file. In this case it |
* a "/". Or it can be an entry to use so we don't have to |
* has to already have the newlines crunched out. If TERMCAP |
* read the file. In this case cgetset() withh crunch out the |
* does not hold a file name then a path of names is searched |
* newlines. If TERMCAP does not hold a file name then a path |
* instead. The path is found in the TERMPATH variable, or |
* of names is searched instead. The path is found in the |
* becomes "$HOME/.termcap /etc/termcap" if no TERMPATH exists. |
* TERMPATH variable, or becomes _PATH_DEF ("$HOME/.termcap |
|
* /usr/share/misc/termcap") if no TERMPATH exists. |
*/ |
*/ |
if (!cp || *cp != '/') { /* no TERMCAP or it holds an entry */ |
if (!cp || *cp != '/') { /* no TERMCAP or it holds an entry */ |
if (termpath = getenv("TERMPATH")) |
if ((termpath = getenv("TERMPATH")) != NULL) |
strncpy(pathbuf, termpath, PBUFSIZ); |
(void)strlcpy(pathbuf, termpath, sizeof(pathbuf)); |
else { |
else { |
if (home = getenv("HOME")) { /* set up default */ |
if ((home = getenv("HOME")) != NULL) { |
|
/* set up default */ |
p += strlen(home); /* path, looking in */ |
p += strlen(home); /* path, looking in */ |
strcpy(pathbuf, home); /* $HOME first */ |
(void)strlcpy(pathbuf, home, |
*p++ = '/'; |
sizeof(pathbuf)); /* $HOME first */ |
|
if ((size_t)(p - pathbuf) < sizeof(pathbuf) - 1) |
|
*p++ = '/'; |
} /* if no $HOME look in current directory */ |
} /* if no $HOME look in current directory */ |
strncpy(p, _PATH_DEF, PBUFSIZ - (p - pathbuf)); |
if ((size_t)(p - pathbuf) < sizeof(pathbuf) - 1) { |
|
(void)strlcpy(p, _PATH_DEF, |
|
sizeof(pathbuf) - (p - pathbuf)); |
|
} |
} |
} |
} |
} |
else /* user-defined name in TERMCAP */ |
else { |
strncpy(pathbuf, cp, PBUFSIZ); /* still can be tokenized */ |
/* user-defined name in TERMCAP; still can be tokenized */ |
|
(void)strlcpy(pathbuf, cp, sizeof(pathbuf)); |
|
} |
|
|
*fname++ = pathbuf; /* tokenize path into vector of names */ |
*fname++ = pathbuf; /* tokenize path into vector of names */ |
while (*++p) |
while (*++p) |
Line 124 tgetent(bp, name) |
|
Line 189 tgetent(bp, name) |
|
break; |
break; |
} |
} |
} |
} |
*fname = (char *) 0; /* mark end of vector */ |
*fname = NULL; /* mark end of vector */ |
if (cp && *cp && *cp != '/') { |
|
tbuf = cp; |
/* |
c = tnamatch(name); |
* try ignoring TERMCAP if it has a ZZ in it, we do this |
tbuf = bp; |
* because a TERMCAP with ZZ in it indicates the entry has been |
if (c) { |
* exported by another program using the "old" interface, the |
strcpy(bp,cp); |
* termcap entry has been truncated and ZZ points to an address |
return (tnchktc()); |
* in the exporting programs memory space which is of no use |
|
* here - anyone who is exporting the termcap entry and then |
|
* reading it back again in the same program deserves to be |
|
* taken out, beaten up, dragged about, shot and then hurt some |
|
* more. |
|
*/ |
|
did_getset = 0; |
|
if (cp && *cp && *cp != '/' && strstr(cp, ":ZZ") == NULL) { |
|
did_getset = 1; |
|
if (cgetset(cp) < 0) { |
|
error = -2; |
|
goto out; |
} |
} |
} |
} |
return (tfindent(bp, name)); /* find terminal entry in path */ |
|
|
/* |
|
* XXX potential security hole here in a set-id program if the |
|
* user had setup name to be built from a path they can not |
|
* normally read. |
|
*/ |
|
(*bp)->info = NULL; |
|
i = cgetent(&((*bp)->info), (const char *const *)pathvec, name); |
|
|
|
/* |
|
* if we get an error and we skipped doing the cgetset before |
|
* we try with TERMCAP in place - we may be using a truncated |
|
* termcap entry but what else can one do? |
|
*/ |
|
if ((i < 0) && (did_getset == 0)) { |
|
if (cp && *cp && *cp != '/') |
|
if (cgetset(cp) < 0) { |
|
error = -2; |
|
goto out; |
|
} |
|
i = cgetent(&((*bp)->info), (const char *const *)pathvec, name); |
|
} |
|
|
|
/* no tc reference loop return code in libterm XXX */ |
|
if (i == -3) { |
|
error = -1; |
|
goto out; |
|
} |
|
|
|
/* |
|
* fill in t_goto capabilities - this prevents memory leaks |
|
* and is more efficient than fetching these capabilities |
|
* every time t_goto is called. |
|
*/ |
|
if (i >= 0) { |
|
cap_ptr = capability; |
|
limit = sizeof(capability) - 1; |
|
(*bp)->up = t_getstr(*bp, "up", &cap_ptr, &limit); |
|
if ((*bp)->up) |
|
(*bp)->up = strdup((*bp)->up); |
|
cap_ptr = capability; |
|
limit = sizeof(capability) - 1; |
|
(*bp)->bc = t_getstr(*bp, "bc", &cap_ptr, &limit); |
|
if ((*bp)->bc) |
|
(*bp)->bc = strdup((*bp)->bc); |
|
(*bp)->tbuf = NULL; |
|
} else { |
|
error = i + 1; |
|
goto out; |
|
} |
|
|
|
return (i + 1); |
|
out: |
|
free(*bp); |
|
*bp = NULL; |
|
return error; |
} |
} |
|
|
/* |
/* |
* tfindent - reads through the list of files in pathvec as if they were one |
* Get an entry for terminal name in buffer bp from the termcap file. |
* continuous file searching for terminal entries along the way. It will |
*/ |
* participate in indirect recursion if the call to tnchktc() finds a tc= |
int |
* field, which is only searched for in the current file and files ocurring |
tgetent(char *bp, const char *name) |
* after it in pathvec. The usable part of this vector is kept in the global |
{ |
* variable pvec. Terminal entries may not be broken across files. Parse is |
int i, plen, elen, c; |
* very rudimentary; we just notice escaped newlines. |
char *ptrbuf = NULL; |
*/ |
|
tfindent(bp, name) |
|
char *bp, *name; |
|
{ |
|
register char *cp; |
|
register int c; |
|
register int i, cnt; |
|
char ibuf[BUFSIZ]; |
|
int opencnt = 0; |
|
int tf; |
|
|
|
tbuf = bp; |
|
nextfile: |
|
i = cnt = 0; |
|
while (*pvec && (tf = open(*pvec, 0)) < 0) |
|
pvec++; |
|
if (!*pvec) |
|
return (opencnt ? 0 : -1); |
|
opencnt++; |
|
for (;;) { |
|
cp = bp; |
|
for (;;) { |
|
if (i == cnt) { |
|
cnt = read(tf, ibuf, BUFSIZ); |
|
if (cnt <= 0) { |
|
close(tf); |
|
pvec++; |
|
goto nextfile; |
|
} |
|
i = 0; |
|
} |
|
c = ibuf[i++]; |
|
if (c == '\n') { |
|
if (cp > bp && cp[-1] == '\\'){ |
|
cp--; |
|
continue; |
|
} |
|
break; |
|
} |
|
if (cp >= bp+BUFSIZ) { |
|
write(2,"Termcap entry too long\n", 23); |
|
break; |
|
} else |
|
*cp++ = c; |
|
} |
|
*cp = 0; |
|
|
|
|
i = t_getent(&fbuf, name); |
|
|
|
if (i == 1) { |
/* |
/* |
* The real work for the match. |
* if the termcap entry is larger than 1023 bytes, |
|
* stash the full buffer pointer as the ZZ capability |
|
* in the termcap buffer passed. |
*/ |
*/ |
if (tnamatch(name)) { |
if (strlcpy(bp, fbuf->info, 1024) >= 1024) { |
close(tf); |
plen = asprintf(&ptrbuf, ":ZZ=%p", fbuf->info); |
return(tnchktc()); |
(void)strlcpy(bp, fbuf->info, 1024); |
|
elen = strlen(bp); |
|
/* |
|
* backup over the entry if the addition of the full |
|
* buffer pointer will overflow the buffer passed. We |
|
* want to truncate the termcap entry on a capability |
|
* boundary. |
|
*/ |
|
if ((elen + plen) > 1023) { |
|
bp[1023 - plen] = '\0'; |
|
for (c = (elen - plen); c > 0; c--) { |
|
if (bp[c] == ':') { |
|
bp[c] = '\0'; |
|
break; |
|
} |
|
} |
|
|
|
} |
|
strcat(bp, ptrbuf); |
} |
} |
|
tbuf = bp; |
} |
} |
} |
|
|
|
/* |
return i; |
* tnchktc: check the last entry, see if it's tc=xxx. If so, |
|
* recursively find xxx and append that entry (minus the names) |
|
* to take the place of the tc=xxx entry. This allows termcap |
|
* entries to say "like an HP2621 but doesn't turn on the labels". |
|
* Note that this works because of the left to right scan. |
|
*/ |
|
tnchktc() |
|
{ |
|
register char *p, *q; |
|
char tcname[16]; /* name of similar terminal */ |
|
char tcbuf[BUFSIZ]; |
|
char *holdtbuf = tbuf; |
|
int l; |
|
|
|
p = tbuf + strlen(tbuf) - 2; /* before the last colon */ |
|
while (*--p != ':') |
|
if (p<tbuf) { |
|
write(2, "Bad termcap entry\n", 18); |
|
return (0); |
|
} |
|
p++; |
|
/* p now points to beginning of last field */ |
|
if (p[0] != 't' || p[1] != 'c') |
|
return(1); |
|
strcpy(tcname,p+3); |
|
q = tcname; |
|
while (*q && *q != ':') |
|
q++; |
|
*q = 0; |
|
if (++hopcount > MAXHOP) { |
|
write(2, "Infinite tc= loop\n", 18); |
|
return (0); |
|
} |
|
if (tfindent(tcbuf, tcname) != 1) { |
|
hopcount = 0; /* unwind recursion */ |
|
return(0); |
|
} |
|
for (q=tcbuf; *q != ':'; q++) |
|
; |
|
l = p - holdtbuf + strlen(q); |
|
if (l > BUFSIZ) { |
|
write(2, "Termcap entry too long\n", 23); |
|
q[BUFSIZ - (p-tbuf)] = 0; |
|
} |
|
strcpy(p, q+1); |
|
tbuf = holdtbuf; |
|
hopcount = 0; /* unwind recursion */ |
|
return(1); |
|
} |
|
|
|
/* |
|
* Tnamatch deals with name matching. The first field of the termcap |
|
* entry is a sequence of names separated by |'s, so we compare |
|
* against each such name. The normal : terminator after the last |
|
* name (before the first field) stops us. |
|
*/ |
|
tnamatch(np) |
|
char *np; |
|
{ |
|
register char *Np, *Bp; |
|
|
|
Bp = tbuf; |
|
if (*Bp == '#') |
|
return(0); |
|
for (;;) { |
|
for (Np = np; *Np && *Bp == *Np; Bp++, Np++) |
|
continue; |
|
if (*Np == 0 && (*Bp == '|' || *Bp == ':' || *Bp == 0)) |
|
return (1); |
|
while (*Bp && *Bp != ':' && *Bp != '|') |
|
Bp++; |
|
if (*Bp == 0 || *Bp == ':') |
|
return (0); |
|
Bp++; |
|
} |
|
} |
|
|
|
/* |
|
* Skip to the next field. Notice that this is very dumb, not |
|
* knowing about \: escapes or any such. If necessary, :'s can be put |
|
* into the termcap file in octal. |
|
*/ |
|
static char * |
|
tskip(bp) |
|
register char *bp; |
|
{ |
|
|
|
while (*bp && *bp != ':') |
|
bp++; |
|
if (*bp == ':') |
|
bp++; |
|
return (bp); |
|
} |
} |
|
|
/* |
/* |
|
|
* a # character. If the option is not found we return -1. |
* a # character. If the option is not found we return -1. |
* Note that we handle octal numbers beginning with 0. |
* Note that we handle octal numbers beginning with 0. |
*/ |
*/ |
tgetnum(id) |
int |
char *id; |
t_getnum(struct tinfo *info, const char *id) |
{ |
{ |
register int i, base; |
long num; |
register char *bp = tbuf; |
|
|
|
for (;;) { |
_DIAGASSERT(info != NULL); |
bp = tskip(bp); |
_DIAGASSERT(id != NULL); |
if (*bp == 0) |
|
return (-1); |
if (cgetnum(info->info, id, &num) == 0) |
if (*bp++ != id[0] || *bp == 0 || *bp++ != id[1]) |
return (int)(num); |
continue; |
else |
if (*bp == '@') |
return (-1); |
return(-1); |
} |
if (*bp != '#') |
|
continue; |
int |
bp++; |
tgetnum(const char *id) |
base = 10; |
{ |
if (*bp == '0') |
return fbuf ? t_getnum(fbuf, id) : -1; |
base = 8; |
|
i = 0; |
|
while (isdigit(*bp)) |
|
i *= base, i += *bp++ - '0'; |
|
return (i); |
|
} |
|
} |
} |
|
|
/* |
/* |
|
|
* of the buffer. Return 1 if we find the option, or 0 if it is |
* of the buffer. Return 1 if we find the option, or 0 if it is |
* not given. |
* not given. |
*/ |
*/ |
tgetflag(id) |
int t_getflag(struct tinfo *info, const char *id) |
char *id; |
|
{ |
{ |
register char *bp = tbuf; |
_DIAGASSERT(info != NULL); |
|
_DIAGASSERT(id != NULL); |
|
|
|
return (cgetcap(info->info, id, ':') != NULL); |
|
} |
|
|
for (;;) { |
int |
bp = tskip(bp); |
tgetflag(const char *id) |
if (!*bp) |
{ |
return (0); |
return fbuf ? t_getflag(fbuf, id) : 0; |
if (*bp++ == id[0] && *bp != 0 && *bp++ == id[1]) { |
} |
if (!*bp || *bp == ':') |
|
return (1); |
/* |
else if (*bp == '@') |
* Get a string valued option. |
return(0); |
* These are given as |
|
* cl=^Z |
|
* Much decoding is done on the strings, and the strings are |
|
* placed in area, which is a ref parameter which is updated. |
|
* limit is the number of characters allowed to be put into |
|
* area, this is updated. |
|
*/ |
|
char * |
|
t_getstr(struct tinfo *info, const char *id, char **area, size_t *limit) |
|
{ |
|
char *s; |
|
int i; |
|
|
|
_DIAGASSERT(info != NULL); |
|
_DIAGASSERT(id != NULL); |
|
/* area may be NULL */ |
|
|
|
|
|
if ((i = cgetstr(info->info, id, &s)) < 0) { |
|
errno = ENOENT; |
|
if ((area == NULL) && (limit != NULL)) |
|
*limit = 0; |
|
return NULL; |
|
} |
|
|
|
if (area != NULL) { |
|
/* |
|
* check if there is room for the new entry to be put into |
|
* area |
|
*/ |
|
if (limit != NULL && (*limit < (size_t) i)) { |
|
errno = E2BIG; |
|
free(s); |
|
return NULL; |
} |
} |
|
|
|
(void)strcpy(*area, s); |
|
free(s); |
|
s = *area; |
|
*area += i + 1; |
|
if (limit != NULL) |
|
*limit -= i; |
|
return (s); |
|
} else { |
|
_DIAGASSERT(limit != NULL); |
|
*limit = i; |
|
free(s); |
|
return NULL; |
} |
} |
} |
} |
|
|
|
|
* No checking on area overflow. |
* No checking on area overflow. |
*/ |
*/ |
char * |
char * |
tgetstr(id, area) |
tgetstr(const char *id, char **area) |
char *id, **area; |
{ |
|
struct tinfo dummy, *ti; |
|
char ids[3]; |
|
|
|
_DIAGASSERT(id != NULL); |
|
|
|
if (fbuf == NULL) |
|
return NULL; |
|
|
|
/* |
|
* XXX |
|
* This is for all the boneheaded programs that relied on tgetstr |
|
* to look only at the first 2 characters of the string passed... |
|
*/ |
|
ids[0] = id[0]; |
|
ids[1] = id[1]; |
|
ids[2] = '\0'; |
|
|
|
if ((id[0] == 'Z') && (id[1] == 'Z')) { |
|
ti = &dummy; |
|
dummy.info = tbuf; |
|
} else |
|
ti = fbuf; |
|
|
|
if (area == NULL || *area == NULL) { |
|
static char capability[CAPSIZ]; |
|
size_t limit = sizeof(capability) - 1; |
|
char *ptr; |
|
|
|
ptr = capability; |
|
return t_getstr(ti, ids, &ptr, &limit); |
|
} else |
|
return t_getstr(ti, ids, area, NULL); |
|
} |
|
|
|
/* |
|
* Return a string valued option specified by id, allocating memory to |
|
* an internal buffer as necessary. The memory allocated can be |
|
* free'd by a call to t_freent(). |
|
* |
|
* If the string is not found or memory allocation fails then NULL |
|
* is returned. |
|
*/ |
|
char * |
|
t_agetstr(struct tinfo *info, const char *id) |
{ |
{ |
register char *bp = tbuf; |
size_t new_size; |
|
struct tbuf *tb; |
|
|
|
_DIAGASSERT(info != NULL); |
|
_DIAGASSERT(id != NULL); |
|
|
|
t_getstr(info, id, NULL, &new_size); |
|
|
|
/* either the string is empty or the capability does not exist. */ |
|
if (new_size == 0) |
|
return NULL; |
|
|
|
if ((tb = info->tbuf) == NULL || |
|
(size_t) (tb->eptr - tb->ptr) < (new_size + 1)) { |
|
if (new_size < CAPSIZ) |
|
new_size = CAPSIZ; |
|
else |
|
new_size++; |
|
|
|
if ((tb = malloc(sizeof(*info->tbuf))) == NULL) |
|
return NULL; |
|
|
|
if ((tb->data = tb->ptr = tb->eptr = malloc(new_size)) |
|
== NULL) { |
|
free(tb); |
|
return NULL; |
|
} |
|
|
for (;;) { |
tb->eptr += new_size; |
bp = tskip(bp); |
|
if (!*bp) |
if (info->tbuf != NULL) |
return (0); |
tb->next = info->tbuf; |
if (*bp++ != id[0] || *bp == 0 || *bp++ != id[1]) |
else |
continue; |
tb->next = NULL; |
if (*bp == '@') |
|
return(0); |
info->tbuf = tb; |
if (*bp != '=') |
|
continue; |
|
bp++; |
|
return (tdecode(bp, area)); |
|
} |
} |
|
return t_getstr(info, id, &tb->ptr, NULL); |
} |
} |
|
|
/* |
/* |
* Tdecode does the grung work to decode the |
* Free the buffer allocated by t_getent |
* string capability escapes. |
* |
*/ |
*/ |
static char * |
void |
tdecode(str, area) |
t_freent(struct tinfo *info) |
register char *str; |
{ |
char **area; |
struct tbuf *tb, *wb; |
{ |
_DIAGASSERT(info != NULL); |
register char *cp; |
free(info->info); |
register int c; |
if (info->up != NULL) |
register char *dp; |
free(info->up); |
int i; |
if (info->bc != NULL) |
|
free(info->bc); |
|
for (tb = info->tbuf; tb;) { |
|
wb = tb; |
|
tb = tb->next; |
|
free(wb->data); |
|
free(wb); |
|
} |
|
free(info); |
|
} |
|
|
cp = *area; |
/* |
while ((c = *str++) && c != ':') { |
* Get the terminal name string from the termcap entry. |
switch (c) { |
* |
|
*/ |
case '^': |
int |
c = *str++ & 037; |
t_getterm(struct tinfo *info, char **area, size_t *limit) |
break; |
{ |
|
char *endp; |
case '\\': |
size_t count; |
dp = "E\033^^\\\\::n\nr\rt\tb\bf\f"; |
|
c = *str++; |
_DIAGASSERT(info != NULL); |
nextc: |
if ((endp = strchr(info->info, ':')) == NULL) { |
if (*dp++ == c) { |
errno = EINVAL; |
c = *dp++; |
return -1; |
break; |
} |
} |
|
dp++; |
|
if (*dp) |
count = endp - info->info + 1; |
goto nextc; |
if (area == NULL) { |
if (isdigit(c)) { |
_DIAGASSERT(limit != NULL); |
c -= '0', i = 2; |
*limit = count; |
do |
return 0; |
c <<= 3, c |= *str++ - '0'; |
} else { |
while (--i && isdigit(*str)); |
if ((limit != NULL) && (count > *limit)) { |
} |
errno = E2BIG; |
break; |
return -1; |
} |
} |
*cp++ = c; |
|
|
(void)strlcpy(*area, info->info, count); |
|
if (limit != NULL) |
|
*limit -= count; |
} |
} |
*cp++ = 0; |
|
str = *area; |
return 0; |
*area = cp; |
|
return (str); |
|
} |
} |