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