|
|
1.1 root 1: /*
2: * Copyright (c) 1983 Regents of the University of California.
3: * All rights reserved.
4: *
5: * Redistribution and use in source and binary forms are permitted
6: * provided that the above copyright notice and this paragraph are
7: * duplicated in all such forms and that any documentation,
8: * advertising materials, and other materials related to such
9: * distribution and use acknowledge that the software was developed
10: * by the University of California, Berkeley. The name of the
11: * University may not be used to endorse or promote products derived
12: * from this software without specific prior written permission.
13: * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
14: * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
15: * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
16: */
17:
18: #ifndef lint
19: static char sccsid[] = "@(#)printcap.c 5.3 (Berkeley) 6/30/88";
20: #endif /* not lint */
21:
22: #define BUFSIZ 1024
23: #define MAXHOP 32 /* max number of tc= indirections */
24:
25: #include <ctype.h>
26: #include <stdio.h>
27: /*
28: * termcap - routines for dealing with the terminal capability data base
29: *
30: * BUG: Should use a "last" pointer in tbuf, so that searching
31: * for capabilities alphabetically would not be a n**2/2
32: * process when large numbers of capabilities are given.
33: * Note: If we add a last pointer now we will screw up the
34: * tc capability. We really should compile termcap.
35: *
36: * Essentially all the work here is scanning and decoding escapes
37: * in string capabilities. We don't use stdio because the editor
38: * doesn't, and because living w/o it is not hard.
39: */
40:
41: #define PRINTCAP
42:
43: #ifdef PRINTCAP
44: #define tgetent pgetent
45: #define tskip pskip
46: #define tgetstr pgetstr
47: #define tdecode pdecode
48: #define tgetnum pgetnum
49: #define tgetflag pgetflag
50: #define tdecode pdecode
51: #define tnchktc pnchktc
52: #define tnamatch pnamatch
53: #undef E_TERMCAP
54: #define E_TERMCAP "/etc/printcap"
55: #define V6
56: #endif
57:
58: static FILE *pfp = NULL; /* printcap data base file pointer */
59: static char *tbuf;
60: static int hopcount; /* detect infinite loops in termcap, init 0 */
61: char *tskip();
62: char *tgetstr();
63: char *tdecode();
64: char *getenv();
65:
66: /*
67: * Similar to tgetent except it returns the next enrty instead of
68: * doing a lookup.
69: */
70: getprent(bp)
71: register char *bp;
72: {
73: register int c, skip = 0;
74:
75: if (pfp == NULL && (pfp = fopen(E_TERMCAP, "r")) == NULL)
76: return(-1);
77: tbuf = bp;
78: for (;;) {
79: switch (c = getc(pfp)) {
80: case EOF:
81: fclose(pfp);
82: pfp = NULL;
83: return(0);
84: case '\n':
85: if (bp == tbuf) {
86: skip = 0;
87: continue;
88: }
89: if (bp[-1] == '\\') {
90: bp--;
91: continue;
92: }
93: *bp = '\0';
94: return(1);
95: case '#':
96: if (bp == tbuf)
97: skip++;
98: default:
99: if (skip)
100: continue;
101: if (bp >= tbuf+BUFSIZ) {
102: write(2, "Termcap entry too long\n", 23);
103: *bp = '\0';
104: return(1);
105: }
106: *bp++ = c;
107: }
108: }
109: }
110:
111: endprent()
112: {
113: if (pfp != NULL)
114: fclose(pfp);
115: }
116:
117: /*
118: * Get an entry for terminal name in buffer bp,
119: * from the termcap file. Parse is very rudimentary;
120: * we just notice escaped newlines.
121: */
122: tgetent(bp, name)
123: char *bp, *name;
124: {
125: register char *cp;
126: register int c;
127: register int i = 0, cnt = 0;
128: char ibuf[BUFSIZ];
129: char *cp2;
130: int tf;
131:
132: tbuf = bp;
133: tf = 0;
134: #ifndef V6
135: cp = getenv("TERMCAP");
136: /*
137: * TERMCAP can have one of two things in it. It can be the
138: * name of a file to use instead of /etc/termcap. In this
139: * case it better start with a "/". Or it can be an entry to
140: * use so we don't have to read the file. In this case it
141: * has to already have the newlines crunched out.
142: */
143: if (cp && *cp) {
144: if (*cp!='/') {
145: cp2 = getenv("TERM");
146: if (cp2==(char *) 0 || strcmp(name,cp2)==0) {
147: strcpy(bp,cp);
148: return(tnchktc());
149: } else {
150: tf = open(E_TERMCAP, 0);
151: }
152: } else
153: tf = open(cp, 0);
154: }
155: if (tf==0)
156: tf = open(E_TERMCAP, 0);
157: #else
158: tf = open(E_TERMCAP, 0);
159: #endif
160: if (tf < 0)
161: return (-1);
162: for (;;) {
163: cp = bp;
164: for (;;) {
165: if (i == cnt) {
166: cnt = read(tf, ibuf, BUFSIZ);
167: if (cnt <= 0) {
168: close(tf);
169: return (0);
170: }
171: i = 0;
172: }
173: c = ibuf[i++];
174: if (c == '\n') {
175: if (cp > bp && cp[-1] == '\\'){
176: cp--;
177: continue;
178: }
179: break;
180: }
181: if (cp >= bp+BUFSIZ) {
182: write(2,"Termcap entry too long\n", 23);
183: break;
184: } else
185: *cp++ = c;
186: }
187: *cp = 0;
188:
189: /*
190: * The real work for the match.
191: */
192: if (tnamatch(name)) {
193: close(tf);
194: return(tnchktc());
195: }
196: }
197: }
198:
199: /*
200: * tnchktc: check the last entry, see if it's tc=xxx. If so,
201: * recursively find xxx and append that entry (minus the names)
202: * to take the place of the tc=xxx entry. This allows termcap
203: * entries to say "like an HP2621 but doesn't turn on the labels".
204: * Note that this works because of the left to right scan.
205: */
206: tnchktc()
207: {
208: register char *p, *q;
209: char tcname[16]; /* name of similar terminal */
210: char tcbuf[BUFSIZ];
211: char *holdtbuf = tbuf;
212: int l;
213:
214: p = tbuf + strlen(tbuf) - 2; /* before the last colon */
215: while (*--p != ':')
216: if (p<tbuf) {
217: write(2, "Bad termcap entry\n", 18);
218: return (0);
219: }
220: p++;
221: /* p now points to beginning of last field */
222: if (p[0] != 't' || p[1] != 'c')
223: return(1);
224: strcpy(tcname,p+3);
225: q = tcname;
226: while (q && *q != ':')
227: q++;
228: *q = 0;
229: if (++hopcount > MAXHOP) {
230: write(2, "Infinite tc= loop\n", 18);
231: return (0);
232: }
233: if (tgetent(tcbuf, tcname) != 1)
234: return(0);
235: for (q=tcbuf; *q != ':'; q++)
236: ;
237: l = p - holdtbuf + strlen(q);
238: if (l > BUFSIZ) {
239: write(2, "Termcap entry too long\n", 23);
240: q[BUFSIZ - (p-tbuf)] = 0;
241: }
242: strcpy(p, q+1);
243: tbuf = holdtbuf;
244: return(1);
245: }
246:
247: /*
248: * Tnamatch deals with name matching. The first field of the termcap
249: * entry is a sequence of names separated by |'s, so we compare
250: * against each such name. The normal : terminator after the last
251: * name (before the first field) stops us.
252: */
253: tnamatch(np)
254: char *np;
255: {
256: register char *Np, *Bp;
257:
258: Bp = tbuf;
259: if (*Bp == '#')
260: return(0);
261: for (;;) {
262: for (Np = np; *Np && *Bp == *Np; Bp++, Np++)
263: continue;
264: if (*Np == 0 && (*Bp == '|' || *Bp == ':' || *Bp == 0))
265: return (1);
266: while (*Bp && *Bp != ':' && *Bp != '|')
267: Bp++;
268: if (*Bp == 0 || *Bp == ':')
269: return (0);
270: Bp++;
271: }
272: }
273:
274: /*
275: * Skip to the next field. Notice that this is very dumb, not
276: * knowing about \: escapes or any such. If necessary, :'s can be put
277: * into the termcap file in octal.
278: */
279: static char *
280: tskip(bp)
281: register char *bp;
282: {
283:
284: while (*bp && *bp != ':')
285: bp++;
286: if (*bp == ':')
287: bp++;
288: return (bp);
289: }
290:
291: /*
292: * Return the (numeric) option id.
293: * Numeric options look like
294: * li#80
295: * i.e. the option string is separated from the numeric value by
296: * a # character. If the option is not found we return -1.
297: * Note that we handle octal numbers beginning with 0.
298: */
299: tgetnum(id)
300: char *id;
301: {
302: register int i, base;
303: register char *bp = tbuf;
304:
305: for (;;) {
306: bp = tskip(bp);
307: if (*bp == 0)
308: return (-1);
309: if (*bp++ != id[0] || *bp == 0 || *bp++ != id[1])
310: continue;
311: if (*bp == '@')
312: return(-1);
313: if (*bp != '#')
314: continue;
315: bp++;
316: base = 10;
317: if (*bp == '0')
318: base = 8;
319: i = 0;
320: while (isdigit(*bp))
321: i *= base, i += *bp++ - '0';
322: return (i);
323: }
324: }
325:
326: /*
327: * Handle a flag option.
328: * Flag options are given "naked", i.e. followed by a : or the end
329: * of the buffer. Return 1 if we find the option, or 0 if it is
330: * not given.
331: */
332: tgetflag(id)
333: char *id;
334: {
335: register char *bp = tbuf;
336:
337: for (;;) {
338: bp = tskip(bp);
339: if (!*bp)
340: return (0);
341: if (*bp++ == id[0] && *bp != 0 && *bp++ == id[1]) {
342: if (!*bp || *bp == ':')
343: return (1);
344: else if (*bp == '@')
345: return(0);
346: }
347: }
348: }
349:
350: /*
351: * Get a string valued option.
352: * These are given as
353: * cl=^Z
354: * Much decoding is done on the strings, and the strings are
355: * placed in area, which is a ref parameter which is updated.
356: * No checking on area overflow.
357: */
358: char *
359: tgetstr(id, area)
360: char *id, **area;
361: {
362: register char *bp = tbuf;
363:
364: for (;;) {
365: bp = tskip(bp);
366: if (!*bp)
367: return (0);
368: if (*bp++ != id[0] || *bp == 0 || *bp++ != id[1])
369: continue;
370: if (*bp == '@')
371: return(0);
372: if (*bp != '=')
373: continue;
374: bp++;
375: return (tdecode(bp, area));
376: }
377: }
378:
379: /*
380: * Tdecode does the grung work to decode the
381: * string capability escapes.
382: */
383: static char *
384: tdecode(str, area)
385: register char *str;
386: char **area;
387: {
388: register char *cp;
389: register int c;
390: register char *dp;
391: int i;
392:
393: cp = *area;
394: while ((c = *str++) && c != ':') {
395: switch (c) {
396:
397: case '^':
398: c = *str++ & 037;
399: break;
400:
401: case '\\':
402: dp = "E\033^^\\\\::n\nr\rt\tb\bf\f";
403: c = *str++;
404: nextc:
405: if (*dp++ == c) {
406: c = *dp++;
407: break;
408: }
409: dp++;
410: if (*dp)
411: goto nextc;
412: if (isdigit(c)) {
413: c -= '0', i = 2;
414: do
415: c <<= 3, c |= *str++ - '0';
416: while (--i && isdigit(*str));
417: }
418: break;
419: }
420: *cp++ = c;
421: }
422: *cp++ = 0;
423: str = *area;
424: *area = cp;
425: return (str);
426: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.