Prototyped.
[unix-history] / usr / src / usr.bin / vgrind / vgrindefs.c
CommitLineData
76797561 1/*
616af90a
KB
2 * Copyright (c) 1980 The Regents of the University of California.
3 * All rights reserved.
4 *
6ecf3d85 5 * %sccs.include.redist.c%
76797561 6 */
fb89c9af 7
76797561 8#ifndef lint
6ecf3d85 9static char sccsid[] = "@(#)vgrindefs.c 5.3 (Berkeley) %G%";
616af90a 10#endif /* not lint */
fb89c9af
KM
11
12#define BUFSIZ 1024
13#define MAXHOP 32 /* max number of tc= indirections */
14
15#include <ctype.h>
fb89c9af
KM
16/*
17 * grindcap - routines for dealing with the language definitions data base
18 * (code stolen almost totally from termcap)
19 *
20 * BUG: Should use a "last" pointer in tbuf, so that searching
21 * for capabilities alphabetically would not be a n**2/2
22 * process when large numbers of capabilities are given.
23 * Note: If we add a last pointer now we will screw up the
24 * tc capability. We really should compile termcap.
25 *
26 * Essentially all the work here is scanning and decoding escapes
27 * in string capabilities. We don't use stdio because the editor
28 * doesn't, and because living w/o it is not hard.
29 */
30
31static char *tbuf;
1a8c1b81 32static char *filename;
fb89c9af
KM
33static int hopcount; /* detect infinite loops in termcap, init 0 */
34char *tskip();
35char *tgetstr();
36char *tdecode();
37char *getenv();
38
39/*
40 * Get an entry for terminal name in buffer bp,
41 * from the termcap file. Parse is very rudimentary;
42 * we just notice escaped newlines.
43 */
1a8c1b81
RC
44tgetent(bp, name, file)
45 char *bp, *name, *file;
fb89c9af
KM
46{
47 register char *cp;
48 register int c;
49 register int i = 0, cnt = 0;
50 char ibuf[BUFSIZ];
51 char *cp2;
52 int tf;
53
54 tbuf = bp;
55 tf = 0;
1a8c1b81 56 filename = file;
fb89c9af
KM
57 tf = open(filename, 0);
58 if (tf < 0)
59 return (-1);
60 for (;;) {
61 cp = bp;
62 for (;;) {
63 if (i == cnt) {
64 cnt = read(tf, ibuf, BUFSIZ);
65 if (cnt <= 0) {
66 close(tf);
67 return (0);
68 }
69 i = 0;
70 }
71 c = ibuf[i++];
72 if (c == '\n') {
73 if (cp > bp && cp[-1] == '\\'){
74 cp--;
75 continue;
76 }
77 break;
78 }
79 if (cp >= bp+BUFSIZ) {
80 write(2,"Vgrind entry too long\n", 23);
81 break;
82 } else
83 *cp++ = c;
84 }
85 *cp = 0;
86
87 /*
88 * The real work for the match.
89 */
90 if (tnamatch(name)) {
91 close(tf);
92 return(tnchktc());
93 }
94 }
95}
96
97/*
98 * tnchktc: check the last entry, see if it's tc=xxx. If so,
99 * recursively find xxx and append that entry (minus the names)
100 * to take the place of the tc=xxx entry. This allows termcap
101 * entries to say "like an HP2621 but doesn't turn on the labels".
102 * Note that this works because of the left to right scan.
103 */
104tnchktc()
105{
106 register char *p, *q;
107 char tcname[16]; /* name of similar terminal */
108 char tcbuf[BUFSIZ];
109 char *holdtbuf = tbuf;
110 int l;
111
112 p = tbuf + strlen(tbuf) - 2; /* before the last colon */
113 while (*--p != ':')
114 if (p<tbuf) {
115 write(2, "Bad vgrind entry\n", 18);
116 return (0);
117 }
118 p++;
119 /* p now points to beginning of last field */
120 if (p[0] != 't' || p[1] != 'c')
121 return(1);
122 strcpy(tcname,p+3);
123 q = tcname;
124 while (q && *q != ':')
125 q++;
126 *q = 0;
127 if (++hopcount > MAXHOP) {
128 write(2, "Infinite tc= loop\n", 18);
129 return (0);
130 }
1a8c1b81 131 if (tgetent(tcbuf, tcname, filename) != 1)
fb89c9af
KM
132 return(0);
133 for (q=tcbuf; *q != ':'; q++)
134 ;
135 l = p - holdtbuf + strlen(q);
136 if (l > BUFSIZ) {
137 write(2, "Vgrind entry too long\n", 23);
138 q[BUFSIZ - (p-tbuf)] = 0;
139 }
140 strcpy(p, q+1);
141 tbuf = holdtbuf;
142 return(1);
143}
144
145/*
146 * Tnamatch deals with name matching. The first field of the termcap
147 * entry is a sequence of names separated by |'s, so we compare
148 * against each such name. The normal : terminator after the last
149 * name (before the first field) stops us.
150 */
151tnamatch(np)
152 char *np;
153{
154 register char *Np, *Bp;
155
156 Bp = tbuf;
157 if (*Bp == '#')
158 return(0);
159 for (;;) {
160 for (Np = np; *Np && *Bp == *Np; Bp++, Np++)
161 continue;
162 if (*Np == 0 && (*Bp == '|' || *Bp == ':' || *Bp == 0))
163 return (1);
164 while (*Bp && *Bp != ':' && *Bp != '|')
165 Bp++;
166 if (*Bp == 0 || *Bp == ':')
167 return (0);
168 Bp++;
169 }
170}
171
172/*
173 * Skip to the next field. Notice that this is very dumb, not
174 * knowing about \: escapes or any such. If necessary, :'s can be put
175 * into the termcap file in octal.
176 */
177static char *
178tskip(bp)
179 register char *bp;
180{
181
182 while (*bp && *bp != ':')
183 bp++;
184 if (*bp == ':')
185 bp++;
186 return (bp);
187}
188
189/*
190 * Return the (numeric) option id.
191 * Numeric options look like
192 * li#80
193 * i.e. the option string is separated from the numeric value by
194 * a # character. If the option is not found we return -1.
195 * Note that we handle octal numbers beginning with 0.
196 */
197tgetnum(id)
198 char *id;
199{
200 register int i, base;
201 register char *bp = tbuf;
202
203 for (;;) {
204 bp = tskip(bp);
205 if (*bp == 0)
206 return (-1);
207 if (*bp++ != id[0] || *bp == 0 || *bp++ != id[1])
208 continue;
209 if (*bp == '@')
210 return(-1);
211 if (*bp != '#')
212 continue;
213 bp++;
214 base = 10;
215 if (*bp == '0')
216 base = 8;
217 i = 0;
218 while (isdigit(*bp))
219 i *= base, i += *bp++ - '0';
220 return (i);
221 }
222}
223
224/*
225 * Handle a flag option.
226 * Flag options are given "naked", i.e. followed by a : or the end
227 * of the buffer. Return 1 if we find the option, or 0 if it is
228 * not given.
229 */
230tgetflag(id)
231 char *id;
232{
233 register char *bp = tbuf;
234
235 for (;;) {
236 bp = tskip(bp);
237 if (!*bp)
238 return (0);
239 if (*bp++ == id[0] && *bp != 0 && *bp++ == id[1]) {
240 if (!*bp || *bp == ':')
241 return (1);
242 else if (*bp == '@')
243 return(0);
244 }
245 }
246}
247
248/*
249 * Get a string valued option.
250 * These are given as
251 * cl=^Z
252 * Much decoding is done on the strings, and the strings are
253 * placed in area, which is a ref parameter which is updated.
254 * No checking on area overflow.
255 */
256char *
257tgetstr(id, area)
258 char *id, **area;
259{
260 register char *bp = tbuf;
261
262 for (;;) {
263 bp = tskip(bp);
264 if (!*bp)
265 return (0);
266 if (*bp++ != id[0] || *bp == 0 || *bp++ != id[1])
267 continue;
268 if (*bp == '@')
269 return(0);
270 if (*bp != '=')
271 continue;
272 bp++;
273 return (tdecode(bp, area));
274 }
275}
276
277/*
278 * Tdecode does the grung work to decode the
279 * string capability escapes.
280 */
281static char *
282tdecode(str, area)
283 register char *str;
284 char **area;
285{
286 register char *cp;
287 register int c;
288 int i;
289
290 cp = *area;
291 while (c = *str++) {
292 if (c == ':' && *(cp-1) != '\\')
293 break;
294 *cp++ = c;
295 }
296 *cp++ = 0;
297 str = *area;
298 *area = cp;
299 return (str);
300}