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