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