|
|
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[] = "@(#)termcap.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: #define E_TERMCAP "/etc/termcap"
14:
15: #include <ctype.h>
16: /*
17: * termcap - routines for dealing with the terminal capability data base
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 int hopcount; /* detect infinite loops in termcap, init 0 */
32: char *tskip();
33: char *tgetstr();
34: char *tdecode();
35: char *getenv();
36:
37: /*
38: * Get an entry for terminal name in buffer bp,
39: * from the termcap file. Parse is very rudimentary;
40: * we just notice escaped newlines.
41: */
42: tgetent(bp, name)
43: char *bp, *name;
44: {
45: register char *cp;
46: register int c;
47: register int i = 0, cnt = 0;
48: char ibuf[BUFSIZ];
49: int tf;
50:
51: tbuf = bp;
52: tf = -1;
53: #ifndef V6
54: cp = getenv("TERMCAP");
55: /*
56: * TERMCAP can have one of two things in it. It can be the
57: * name of a file to use instead of /etc/termcap. In this
58: * case it better start with a "/". Or it can be an entry to
59: * use so we don't have to read the file. In this case it
60: * has to already have the newlines crunched out.
61: */
62: if (cp && *cp) {
63: if (*cp == '/') {
64: tf = open(cp, 0);
65: } else {
66: tbuf = cp;
67: c = tnamatch(name);
68: tbuf = bp;
69: if (c) {
70: strcpy(bp,cp);
71: return(tnchktc());
72: }
73: }
74: }
75: if (tf < 0)
76: tf = open(E_TERMCAP, 0);
77: #else
78: tf = open(E_TERMCAP, 0);
79: #endif
80: if (tf < 0)
81: return (-1);
82: for (;;) {
83: cp = bp;
84: for (;;) {
85: if (i == cnt) {
86: cnt = read(tf, ibuf, BUFSIZ);
87: if (cnt <= 0) {
88: close(tf);
89: return (0);
90: }
91: i = 0;
92: }
93: c = ibuf[i++];
94: if (c == '\n') {
95: if (cp > bp && cp[-1] == '\\'){
96: cp--;
97: continue;
98: }
99: break;
100: }
101: if (cp >= bp+BUFSIZ) {
102: write(2,"Termcap entry too long\n", 23);
103: break;
104: } else
105: *cp++ = c;
106: }
107: *cp = 0;
108:
109: /*
110: * The real work for the match.
111: */
112: if (tnamatch(name)) {
113: close(tf);
114: return(tnchktc());
115: }
116: }
117: }
118:
119: /*
120: * tnchktc: check the last entry, see if it's tc=xxx. If so,
121: * recursively find xxx and append that entry (minus the names)
122: * to take the place of the tc=xxx entry. This allows termcap
123: * entries to say "like an HP2621 but doesn't turn on the labels".
124: * Note that this works because of the left to right scan.
125: */
126: tnchktc()
127: {
128: register char *p, *q;
129: char tcname[16]; /* name of similar terminal */
130: char tcbuf[BUFSIZ];
131: char *holdtbuf = tbuf;
132: int l;
133:
134: p = tbuf + strlen(tbuf) - 2; /* before the last colon */
135: while (*--p != ':')
136: if (p<tbuf) {
137: write(2, "Bad termcap entry\n", 18);
138: return (0);
139: }
140: p++;
141: /* p now points to beginning of last field */
142: if (p[0] != 't' || p[1] != 'c')
143: return(1);
144: strcpy(tcname,p+3);
145: q = tcname;
146: while (*q && *q != ':')
147: q++;
148: *q = 0;
149: if (++hopcount > MAXHOP) {
150: write(2, "Infinite tc= loop\n", 18);
151: return (0);
152: }
153: if (tgetent(tcbuf, tcname) != 1) {
154: hopcount = 0; /* unwind recursion */
155: return(0);
156: }
157: for (q=tcbuf; *q != ':'; q++)
158: ;
159: l = p - holdtbuf + strlen(q);
160: if (l > BUFSIZ) {
161: write(2, "Termcap entry too long\n", 23);
162: q[BUFSIZ - (p-tbuf)] = 0;
163: }
164: strcpy(p, q+1);
165: tbuf = holdtbuf;
166: hopcount = 0; /* unwind recursion */
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: */
176: tnamatch(np)
177: char *np;
178: {
179: register char *Np, *Bp;
180:
181: Bp = tbuf;
182: if (*Bp == '#')
183: return(0);
184: for (;;) {
185: for (Np = np; *Np && *Bp == *Np; Bp++, Np++)
186: continue;
187: if (*Np == 0 && (*Bp == '|' || *Bp == ':' || *Bp == 0))
188: return (1);
189: while (*Bp && *Bp != ':' && *Bp != '|')
190: Bp++;
191: if (*Bp == 0 || *Bp == ':')
192: return (0);
193: Bp++;
194: }
195: }
196:
197: /*
198: * Skip to the next field. Notice that this is very dumb, not
199: * knowing about \: escapes or any such. If necessary, :'s can be put
200: * into the termcap file in octal.
201: */
202: static char *
203: tskip(bp)
204: register char *bp;
205: {
206:
207: while (*bp && *bp != ':')
208: bp++;
209: if (*bp == ':')
210: bp++;
211: return (bp);
212: }
213:
214: /*
215: * Return the (numeric) option id.
216: * Numeric options look like
217: * li#80
218: * i.e. the option string is separated from the numeric value by
219: * a # character. If the option is not found we return -1.
220: * Note that we handle octal numbers beginning with 0.
221: */
222: tgetnum(id)
223: char *id;
224: {
225: register int i, base;
226: register char *bp = tbuf;
227:
228: for (;;) {
229: bp = tskip(bp);
230: if (*bp == 0)
231: return (-1);
232: if (*bp++ != id[0] || *bp == 0 || *bp++ != id[1])
233: continue;
234: if (*bp == '@')
235: return(-1);
236: if (*bp != '#')
237: continue;
238: bp++;
239: base = 10;
240: if (*bp == '0')
241: base = 8;
242: i = 0;
243: while (isdigit(*bp))
244: i *= base, i += *bp++ - '0';
245: return (i);
246: }
247: }
248:
249: /*
250: * Handle a flag option.
251: * Flag options are given "naked", i.e. followed by a : or the end
252: * of the buffer. Return 1 if we find the option, or 0 if it is
253: * not given.
254: */
255: tgetflag(id)
256: char *id;
257: {
258: register char *bp = tbuf;
259:
260: for (;;) {
261: bp = tskip(bp);
262: if (!*bp)
263: return (0);
264: if (*bp++ == id[0] && *bp != 0 && *bp++ == id[1]) {
265: if (!*bp || *bp == ':')
266: return (1);
267: else if (*bp == '@')
268: return(0);
269: }
270: }
271: }
272:
273: /*
274: * Get a string valued option.
275: * These are given as
276: * cl=^Z
277: * Much decoding is done on the strings, and the strings are
278: * placed in area, which is a ref parameter which is updated.
279: * No checking on area overflow.
280: */
281: char *
282: tgetstr(id, area)
283: char *id, **area;
284: {
285: register char *bp = tbuf;
286:
287: for (;;) {
288: bp = tskip(bp);
289: if (!*bp)
290: return (0);
291: if (*bp++ != id[0] || *bp == 0 || *bp++ != id[1])
292: continue;
293: if (*bp == '@')
294: return(0);
295: if (*bp != '=')
296: continue;
297: bp++;
298: return (tdecode(bp, area));
299: }
300: }
301:
302: /*
303: * Tdecode does the grung work to decode the
304: * string capability escapes.
305: */
306: static char *
307: tdecode(str, area)
308: register char *str;
309: char **area;
310: {
311: register char *cp;
312: register int c;
313: register char *dp;
314: int i;
315:
316: cp = *area;
317: while ((c = *str++) && c != ':') {
318: switch (c) {
319:
320: case '^':
321: c = *str++ & 037;
322: break;
323:
324: case '\\':
325: dp = "E\033^^\\\\::n\nr\rt\tb\bf\f";
326: c = *str++;
327: nextc:
328: if (*dp++ == c) {
329: c = *dp++;
330: break;
331: }
332: dp++;
333: if (*dp)
334: goto nextc;
335: if (isdigit(c)) {
336: c -= '0', i = 2;
337: do
338: c <<= 3, c |= *str++ - '0';
339: while (--i && isdigit(*str));
340: }
341: break;
342: }
343: *cp++ = c;
344: }
345: *cp++ = 0;
346: str = *area;
347: *area = cp;
348: return (str);
349: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.