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