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