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