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