2 * Copyright (c) 1980 Regents of the University of California.
3 * All rights reserved. The Berkeley software License Agreement
4 * specifies the terms and conditions for redistribution.
7 #pragma ident "%Z%%M% %I% %E% SMI"
10 #define MAXHOP 32 /* max number of tc= indirections */
16 * grindcap - routines for dealing with the language definitions data base
17 * (code stolen almost totally from termcap)
19 * BUG: Should use a "last" pointer in tbuf, so that searching
20 * for capabilities alphabetically would not be a n**2/2
21 * process when large numbers of capabilities are given.
22 * Note: If we add a last pointer now we will screw up the
23 * tc capability. We really should compile termcap.
25 * Essentially all the work here is scanning and decoding escapes
26 * in string capabilities. We don't use stdio because the editor
27 * doesn't, and because living w/o it is not hard.
31 static char *filename
;
32 static int hopcount
; /* detect infinite loops in termcap, init 0 */
36 static char *tdecode(char *str
, char **area
);
37 static char *tskip(char *bp
);
38 static int tnchktc(void);
39 static int tnamatch(char *np
);
41 static char *vgrind_msg
;
44 * Get an entry for terminal name in buffer bp,
45 * from the termcap file. Parse is very rudimentary;
46 * we just notice escaped newlines.
49 tgetent(char *bp
, char *name
, char *file
)
61 tf
= open(filename
, 0);
68 cnt
= read(tf
, ibuf
, BUFSIZ
);
77 if (cp
> bp
&& cp
[-1] == '\\'){
83 if (cp
>= bp
+BUFSIZ
) {
84 vgrind_msg
= gettext("Vgrind entry too long\n");
85 write(2, vgrind_msg
, strlen(vgrind_msg
));
93 * The real work for the match.
103 * tnchktc: check the last entry, see if it's tc=xxx. If so,
104 * recursively find xxx and append that entry (minus the names)
105 * to take the place of the tc=xxx entry. This allows termcap
106 * entries to say "like an HP2621 but doesn't turn on the labels".
107 * Note that this works because of the left to right scan.
113 char tcname
[16]; /* name of similar terminal */
115 char *holdtbuf
= tbuf
;
118 p
= tbuf
+ strlen(tbuf
) - 2; /* before the last colon */
121 vgrind_msg
= gettext("Bad vgrind entry\n");
122 write(2, vgrind_msg
, strlen(vgrind_msg
));
126 /* p now points to beginning of last field */
127 if (p
[0] != 't' || p
[1] != 'c')
131 while (q
&& *q
!= ':')
134 if (++hopcount
> MAXHOP
) {
135 vgrind_msg
= gettext("Infinite tc= loop\n");
136 write(2, vgrind_msg
, strlen(vgrind_msg
));
139 if (tgetent(tcbuf
, tcname
, filename
) != 1)
141 for (q
=tcbuf
; *q
!= ':'; q
++)
143 l
= p
- holdtbuf
+ strlen(q
);
145 vgrind_msg
= gettext("Vgrind entry too long\n");
146 write(2, vgrind_msg
, strlen(vgrind_msg
));
147 q
[BUFSIZ
- (p
-tbuf
)] = 0;
155 * Tnamatch deals with name matching. The first field of the termcap
156 * entry is a sequence of names separated by |'s, so we compare
157 * against each such name. The normal : terminator after the last
158 * name (before the first field) stops us.
169 for (Np
= np
; *Np
&& *Bp
== *Np
; Bp
++, Np
++)
171 if (*Np
== 0 && (*Bp
== '|' || *Bp
== ':' || *Bp
== 0))
173 while (*Bp
&& *Bp
!= ':' && *Bp
!= '|')
175 if (*Bp
== 0 || *Bp
== ':')
182 * Skip to the next field. Notice that this is very dumb, not
183 * knowing about \: escapes or any such. If necessary, :'s can be put
184 * into the termcap file in octal.
190 while (*bp
&& *bp
!= ':')
198 * Return the (numeric) option id.
199 * Numeric options look like
201 * i.e. the option string is separated from the numeric value by
202 * a # character. If the option is not found we return -1.
203 * Note that we handle octal numbers beginning with 0.
215 if (*bp
++ != id
[0] || *bp
== 0 || *bp
++ != id
[1])
227 i
*= base
, i
+= *bp
++ - '0';
233 * Handle a flag option.
234 * Flag options are given "naked", i.e. followed by a : or the end
235 * of the buffer. Return 1 if we find the option, or 0 if it is
247 if (*bp
++ == id
[0] && *bp
!= 0 && *bp
++ == id
[1]) {
248 if (!*bp
|| *bp
== ':')
257 * Get a string valued option.
260 * Much decoding is done on the strings, and the strings are
261 * placed in area, which is a ref parameter which is updated.
262 * No checking on area overflow.
265 tgetstr(char *id
, char **area
)
273 if (*bp
++ != id
[0] || *bp
== 0 || *bp
++ != id
[1])
280 return (tdecode(bp
, area
));
285 * Tdecode does the grung work to decode the
286 * string capability escapes.
289 tdecode(char *str
, char **area
)
297 if (c
== ':' && *(cp
-1) != '\\')