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