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