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