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