/* printcap.c 1.4 83/01/05 */
/* Copyright (c) 1979 Regents of the University of California */
#define MAXHOP 32 /* max number of tc= indirections */
* termcap - routines for dealing with the terminal capability data base
* BUG: Should use a "last" pointer in tbuf, so that searching
* for capabilities alphabetically would not be a n**2/2
* process when large numbers of capabilities are given.
* Note: If we add a last pointer now we will screw up the
* tc capability. We really should compile termcap.
* Essentially all the work here is scanning and decoding escapes
* in string capabilities. We don't use stdio because the editor
* doesn't, and because living w/o it is not hard.
#define tgetflag pgetflag
#define tnamatch pnamatch
#define E_TERMCAP "/etc/printcap"
static int hopcount
; /* detect infinite loops in termcap, init 0 */
* Get an entry for terminal name in buffer bp,
* from the termcap file. Parse is very rudimentary;
* we just notice escaped newlines.
register int i
= 0, cnt
= 0;
* 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 (cp2
==(char *) 0 || strcmp(name
,cp2
)==0) {
cnt
= read(tf
, ibuf
, BUFSIZ
);
if (cp
> bp
&& cp
[-1] == '\\'){
write(2,"Termcap entry too long\n", 23);
* The real work for the match.
* 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.
char tcname
[16]; /* name of similar terminal */
p
= tbuf
+ strlen(tbuf
) - 2; /* before the last colon */
write(2, "Bad termcap entry\n", 18);
/* p now points to beginning of last field */
if (p
[0] != 't' || p
[1] != 'c')
if (++hopcount
> MAXHOP
) {
write(2, "Infinite tc= loop\n", 18);
if (tgetent(tcbuf
, tcname
) != 1)
for (q
=tcbuf
; *q
!= ':'; q
++)
l
= p
- holdtbuf
+ strlen(q
);
write(2, "Termcap entry too long\n", 23);
q
[BUFSIZ
- (p
-tbuf
)] = 0;
* 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.
for (Np
= np
; *Np
&& *Bp
== *Np
; Bp
++, Np
++)
if (*Np
== 0 && (*Bp
== '|' || *Bp
== ':' || *Bp
== 0))
while (*Bp
&& *Bp
!= ':' && *Bp
!= '|')
if (*Bp
== 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.
while (*bp
&& *bp
!= ':')
* Return the (numeric) option id.
* Numeric options look like
* i.e. the option string is separated from the numeric value by
* a # character. If the option is not found we return -1.
* Note that we handle octal numbers beginning with 0.
register char *bp
= tbuf
;
if (*bp
++ != id
[0] || *bp
== 0 || *bp
++ != id
[1])
i
*= base
, i
+= *bp
++ - '0';
* Flag options are given "naked", i.e. followed by a : or the end
* of the buffer. Return 1 if we find the option, or 0 if it is
register char *bp
= tbuf
;
if (*bp
++ == id
[0] && *bp
!= 0 && *bp
++ == id
[1]) {
* Get a string valued option.
* Much decoding is done on the strings, and the strings are
* placed in area, which is a ref parameter which is updated.
* No checking on area overflow.
register char *bp
= tbuf
;
if (*bp
++ != id
[0] || *bp
== 0 || *bp
++ != id
[1])
return (tdecode(bp
, area
));
* Tdecode does the grung work to decode the
* string capability escapes.
while ((c
= *str
++) && c
!= ':') {
dp
= "E\033^^\\\\::n\nr\rt\tb\bf\f";
c
<<= 3, c
|= *str
++ - '0';
while (--i
&& isdigit(*str
));