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