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