rationalized handling of child processes, cleaned up mail1 some more
[unix-history] / usr / src / usr.bin / tip / remcap.c
CommitLineData
051b1e55
DF
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
05862919 7#ifndef lint
051b1e55
DF
8static char sccsid[] = "@(#)remcap.c 5.1 (Berkeley) %G%";
9#endif not lint
ff9b62f7 10
ff9b62f7 11/*
3095e901
SL
12 * remcap - routines for dealing with the remote host data base
13 *
05862919 14 * derived from termcap
3095e901 15 */
05862919
SL
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 */
3095e901 24
3095e901
SL
25#define tgetent rgetent
26#define tnchktc rnchktc
27#define tnamatch rnamatch
28#define tgetnum rgetnum
29#define tgetflag rgetflag
30#define tgetstr rgetstr
6b46907f 31#define E_TERMCAP RM = SYSREMOTE
fa7b15dc
SL
32#define V_TERMCAP "REMOTE"
33#define V_TERM "HOST"
34
3095e901 35char *RM;
3095e901
SL
36
37/*
38 * termcap - routines for dealing with the terminal capability data base
ff9b62f7
BJ
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.
3095e901
SL
43 * Note: If we add a last pointer now we will screw up the
44 * tc capability. We really should compile termcap.
ff9b62f7
BJ
45 *
46 * Essentially all the work here is scanning and decoding escapes
3095e901
SL
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 */
ff9b62f7 50
3095e901
SL
51static char *tbuf;
52static int hopcount; /* detect infinite loops in termcap, init 0 */
53char *tskip();
54char *tgetstr();
55char *tdecode();
ff9b62f7 56char *getenv();
05862919 57static char *remotefile;
ff9b62f7
BJ
58
59/*
3095e901
SL
60 * Get an entry for terminal name in buffer bp,
61 * from the termcap file. Parse is very rudimentary;
ff9b62f7
BJ
62 * we just notice escaped newlines.
63 */
3095e901 64tgetent(bp, name)
ff9b62f7
BJ
65 char *bp, *name;
66{
05862919
SL
67 char lbuf[BUFSIZ], *cp, *p;
68 int rc1, rc2;
6b46907f
RC
69
70 remotefile = cp = getenv(V_TERMCAP);
71 if (cp == (char *)0 || strcmp(cp, SYSREMOTE) == 0) {
72 remotefile = cp = SYSREMOTE;
05862919 73 return (getent(bp, name, cp));
6b46907f
RC
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)
05862919 80 return (rc2);
6b46907f
RC
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);
05862919 88 return (-1);
6b46907f
RC
89 }
90 strcat(bp, p);
91 }
92 tbuf = bp;
05862919 93 return (1);
6b46907f
RC
94 }
95}
96
97getent(bp, name, cp)
98 char *bp, *name, *cp;
99{
ff9b62f7
BJ
100 register int c;
101 register int i = 0, cnt = 0;
05862919 102 char ibuf[BUFSIZ], *cp2;
ff9b62f7
BJ
103 int tf;
104
3095e901
SL
105 tbuf = bp;
106 tf = 0;
3095e901
SL
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!='/') {
fa7b15dc 116 cp2 = getenv(V_TERM);
05862919 117 if (cp2 == (char *)0 || strcmp(name,cp2) == 0) {
3095e901 118 strcpy(bp,cp);
05862919
SL
119 return (tnchktc());
120 } else
121 tf = open(E_TERMCAP, O_RDONLY);
3095e901 122 } else
05862919 123 tf = open(RM = cp, O_RDONLY);
3095e901 124 }
05862919
SL
125 if (tf == 0)
126 tf = open(E_TERMCAP, O_RDONLY);
3095e901 127 if (tf < 0)
ff9b62f7
BJ
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') {
6b46907f 142 if (cp > bp && cp[-1] == '\\') {
ff9b62f7
BJ
143 cp--;
144 continue;
145 }
146 break;
147 }
3095e901 148 if (cp >= bp+BUFSIZ) {
6b46907f 149 write(2,"Remcap entry too long\n", 23);
3095e901
SL
150 break;
151 } else
152 *cp++ = c;
ff9b62f7
BJ
153 }
154 *cp = 0;
155
156 /*
157 * The real work for the match.
158 */
3095e901 159 if (tnamatch(name)) {
ff9b62f7 160 close(tf);
05862919 161 return (tnchktc());
3095e901
SL
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 */
173tnchktc()
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;
6b46907f 180 char *cp;
3095e901
SL
181
182 p = tbuf + strlen(tbuf) - 2; /* before the last colon */
183 while (*--p != ':')
184 if (p<tbuf) {
6b46907f 185 write(2, "Bad remcap entry\n", 18);
3095e901 186 return (0);
ff9b62f7 187 }
3095e901
SL
188 p++;
189 /* p now points to beginning of last field */
190 if (p[0] != 't' || p[1] != 'c')
05862919 191 return (1);
6b46907f 192 strcpy(tcname, p+3);
3095e901 193 q = tcname;
6b46907f 194 while (*q && *q != ':')
3095e901
SL
195 q++;
196 *q = 0;
197 if (++hopcount > MAXHOP) {
198 write(2, "Infinite tc= loop\n", 18);
199 return (0);
200 }
6b46907f
RC
201 if (getent(tcbuf, tcname, remotefile) != 1) {
202 if (strcmp(remotefile, SYSREMOTE) == 0)
05862919 203 return (0);
6b46907f 204 else if (getent(tcbuf, tcname, SYSREMOTE) != 1)
05862919 205 return (0);
6b46907f
RC
206 }
207 for (q = tcbuf; *q++ != ':'; )
3095e901
SL
208 ;
209 l = p - holdtbuf + strlen(q);
210 if (l > BUFSIZ) {
6b46907f
RC
211 write(2, "Remcap entry too long\n", 23);
212 q[BUFSIZ - (p-holdtbuf)] = 0;
ff9b62f7 213 }
6b46907f 214 strcpy(p, q);
3095e901 215 tbuf = holdtbuf;
05862919 216 return (1);
ff9b62f7
BJ
217}
218
219/*
3095e901 220 * Tnamatch deals with name matching. The first field of the termcap
ff9b62f7
BJ
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 */
3095e901 225tnamatch(np)
ff9b62f7
BJ
226 char *np;
227{
228 register char *Np, *Bp;
229
3095e901
SL
230 Bp = tbuf;
231 if (*Bp == '#')
05862919 232 return (0);
ff9b62f7
BJ
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
3095e901 249 * into the termcap file in octal.
ff9b62f7
BJ
250 */
251static char *
3095e901 252tskip(bp)
ff9b62f7
BJ
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 */
3095e901 271tgetnum(id)
ff9b62f7
BJ
272 char *id;
273{
274 register int i, base;
3095e901 275 register char *bp = tbuf;
ff9b62f7
BJ
276
277 for (;;) {
3095e901 278 bp = tskip(bp);
ff9b62f7
BJ
279 if (*bp == 0)
280 return (-1);
281 if (*bp++ != id[0] || *bp == 0 || *bp++ != id[1])
282 continue;
3095e901 283 if (*bp == '@')
05862919 284 return (-1);
ff9b62f7
BJ
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 */
3095e901 304tgetflag(id)
ff9b62f7
BJ
305 char *id;
306{
3095e901 307 register char *bp = tbuf;
ff9b62f7
BJ
308
309 for (;;) {
3095e901 310 bp = tskip(bp);
ff9b62f7
BJ
311 if (!*bp)
312 return (0);
3095e901
SL
313 if (*bp++ == id[0] && *bp != 0 && *bp++ == id[1]) {
314 if (!*bp || *bp == ':')
315 return (1);
316 else if (*bp == '@')
05862919 317 return (0);
3095e901 318 }
ff9b62f7
BJ
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 */
330char *
3095e901 331tgetstr(id, area)
ff9b62f7
BJ
332 char *id, **area;
333{
3095e901 334 register char *bp = tbuf;
ff9b62f7
BJ
335
336 for (;;) {
3095e901 337 bp = tskip(bp);
ff9b62f7
BJ
338 if (!*bp)
339 return (0);
340 if (*bp++ != id[0] || *bp == 0 || *bp++ != id[1])
341 continue;
3095e901 342 if (*bp == '@')
05862919 343 return (0);
ff9b62f7
BJ
344 if (*bp != '=')
345 continue;
346 bp++;
3095e901 347 return (tdecode(bp, area));
ff9b62f7
BJ
348 }
349}
350
351/*
352 * Tdecode does the grung work to decode the
353 * string capability escapes.
354 */
3095e901
SL
355static char *
356tdecode(str, area)
ff9b62f7
BJ
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++;
376nextc:
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}