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