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