17c478bdstevel@tonic-gate/*
28d489c7muffin * Copyright 2001 Sun Microsystems, Inc.  All rights reserved.
38d489c7muffin * Use is subject to license terms.
47c478bdstevel@tonic-gate */
57c478bdstevel@tonic-gate
67c478bdstevel@tonic-gate/*
77c478bdstevel@tonic-gate * Copyright (c) 1983 Regents of the University of California.
87c478bdstevel@tonic-gate * All rights reserved. The Berkeley software License Agreement
97c478bdstevel@tonic-gate * specifies the terms and conditions for redistribution.
107c478bdstevel@tonic-gate */
118d489c7muffin
127c478bdstevel@tonic-gate#pragma ident	"%Z%%M%	%I%	%E% SMI"
137c478bdstevel@tonic-gate
147c478bdstevel@tonic-gate/*
157c478bdstevel@tonic-gate * remcap - routines for dealing with the remote host data base
167c478bdstevel@tonic-gate *
177c478bdstevel@tonic-gate * derived from termcap
187c478bdstevel@tonic-gate */
197c478bdstevel@tonic-gate#ifdef USG
207c478bdstevel@tonic-gate#include <sys/types.h>
217c478bdstevel@tonic-gate#include <fcntl.h>	/* for O_RDONLY */
227c478bdstevel@tonic-gate#else
237c478bdstevel@tonic-gate#include <sys/file.h>	/* for O_RDONLY */
247c478bdstevel@tonic-gate#include <ctype.h>
257c478bdstevel@tonic-gate#endif
267c478bdstevel@tonic-gate
278d489c7muffin#include <stdlib.h>
288d489c7muffin#include <string.h>
298d489c7muffin#include <unistd.h>
308d489c7muffin#include <ctype.h>
318d489c7muffin
327c478bdstevel@tonic-gate#ifndef BUFSIZ
337c478bdstevel@tonic-gate#define	BUFSIZ		1024
347c478bdstevel@tonic-gate#endif
357c478bdstevel@tonic-gate#define	MAXHOP		32		/* max number of tc= indirections */
367c478bdstevel@tonic-gate#define	SYSREMOTE	"/etc/remote"	/* system remote file */
377c478bdstevel@tonic-gate
387c478bdstevel@tonic-gate#define	tgetent		rgetent
397c478bdstevel@tonic-gate#define	tnchktc		rnchktc
407c478bdstevel@tonic-gate#define	tnamatch	rnamatch
417c478bdstevel@tonic-gate#define	tgetnum		rgetnum
427c478bdstevel@tonic-gate#define	tgetflag	rgetflag
437c478bdstevel@tonic-gate#define	tgetstr		rgetstr
447c478bdstevel@tonic-gate#define	E_TERMCAP	RM = SYSREMOTE
457c478bdstevel@tonic-gate#define	V_TERMCAP	"REMOTE"
467c478bdstevel@tonic-gate#define	V_TERM		"HOST"
477c478bdstevel@tonic-gate
487c478bdstevel@tonic-gatechar	*RM;
497c478bdstevel@tonic-gate
507c478bdstevel@tonic-gate/*
517c478bdstevel@tonic-gate * termcap - routines for dealing with the terminal capability data base
527c478bdstevel@tonic-gate *
537c478bdstevel@tonic-gate * BUG:		Should use a "last" pointer in tbuf, so that searching
547c478bdstevel@tonic-gate *		for capabilities alphabetically would not be a n**2/2
557c478bdstevel@tonic-gate *		process when large numbers of capabilities are given.
567c478bdstevel@tonic-gate * Note:	If we add a last pointer now we will screw up the
577c478bdstevel@tonic-gate *		tc capability. We really should compile termcap.
587c478bdstevel@tonic-gate *
597c478bdstevel@tonic-gate * Essentially all the work here is scanning and decoding escapes
607c478bdstevel@tonic-gate * in string capabilities.  We don't use stdio because the editor
617c478bdstevel@tonic-gate * doesn't, and because living w/o it is not hard.
627c478bdstevel@tonic-gate */
637c478bdstevel@tonic-gate
648d489c7muffinstatic char *tbuf;
658d489c7muffinstatic int hopcount;	/* detect infinite loops in termcap, init 0 */
668d489c7muffinstatic char *remotefile;
678d489c7muffin
688d489c7muffinstatic char	*tskip(char *);
698d489c7muffinstatic char	*tdecode(char *, char **);
708d489c7muffin
718d489c7muffinchar	*tgetstr(char *, char **);
728d489c7muffinint	getent(char *, char *, char *, int);
738d489c7muffinint	tnchktc(void);
748d489c7muffinint	tnamatch(char *);
758d489c7muffin
768d489c7muffinextern void	myperm(void);
778d489c7muffinextern void	userperm(void);
787c478bdstevel@tonic-gate
797c478bdstevel@tonic-gate/*
807c478bdstevel@tonic-gate * If we use a user specified entry to get the device name,
817c478bdstevel@tonic-gate * we need to open the device as the user.
827c478bdstevel@tonic-gate */
837c478bdstevel@tonic-gateint trusted_device = 0;
847c478bdstevel@tonic-gate
857c478bdstevel@tonic-gate/*
867c478bdstevel@tonic-gate * Get an entry for terminal name in buffer bp,
877c478bdstevel@tonic-gate * from the termcap file.  Parse is very rudimentary;
887c478bdstevel@tonic-gate * we just notice escaped newlines.
897c478bdstevel@tonic-gate */
908d489c7muffinint
918d489c7muffintgetent(char *bp, char *name, int len)
927c478bdstevel@tonic-gate{
937c478bdstevel@tonic-gate	char lbuf[BUFSIZ], *cp, *p;
947c478bdstevel@tonic-gate	int rc1, rc2;
957c478bdstevel@tonic-gate
967c478bdstevel@tonic-gate	trusted_device = 1;
977c478bdstevel@tonic-gate
987c478bdstevel@tonic-gate	remotefile = cp = getenv(V_TERMCAP);
997c478bdstevel@tonic-gate	if (cp == (char *)0 || strcmp(cp, SYSREMOTE) == 0) {
1007c478bdstevel@tonic-gate		remotefile = cp = SYSREMOTE;
1017c478bdstevel@tonic-gate		return (getent(bp, name, cp, len));
1027c478bdstevel@tonic-gate	} else {
1037c478bdstevel@tonic-gate		if ((rc1 = getent(bp, name, cp, len)) != 1)
1047c478bdstevel@tonic-gate			*bp = '\0';
1057c478bdstevel@tonic-gate		remotefile = cp = SYSREMOTE;
1067c478bdstevel@tonic-gate		rc2 = getent(lbuf, name, cp, sizeof (lbuf));
1077c478bdstevel@tonic-gate		if (rc1 != 1 && rc2 != 1)
1087c478bdstevel@tonic-gate			return (rc2);
1097c478bdstevel@tonic-gate		if (rc2 == 1) {
1107c478bdstevel@tonic-gate			p = lbuf;
1117c478bdstevel@tonic-gate			if (rc1 == 1)
1127c478bdstevel@tonic-gate				while (*p++ != ':')
1137c478bdstevel@tonic-gate					;
1147c478bdstevel@tonic-gate			if (strlen(bp) + strlen(p) >= len) {
1158d489c7muffin				(void) write(2, "Remcap entry too long\n", 23);
1167c478bdstevel@tonic-gate				return (-1);
1177c478bdstevel@tonic-gate			}
1188d489c7muffin			(void) strcat(bp, p);
1197c478bdstevel@tonic-gate		}
1207c478bdstevel@tonic-gate		tbuf = bp;
1217c478bdstevel@tonic-gate		return (1);
1227c478bdstevel@tonic-gate	}
1237c478bdstevel@tonic-gate}
1247c478bdstevel@tonic-gate
1258d489c7muffinint
1268d489c7muffingetent(char *bp, char *name, char *cp, int len)
1277c478bdstevel@tonic-gate{
1288d489c7muffin	int c;
1298d489c7muffin	int i = 0, cnt = 0;
1307c478bdstevel@tonic-gate	char ibuf[BUFSIZ], *cp2;
1317c478bdstevel@tonic-gate	int tf;
1327c478bdstevel@tonic-gate	int safe = 1; /* reset only when we open the user's $REMOTE */
1337c478bdstevel@tonic-gate
1347c478bdstevel@tonic-gate	tbuf = bp;
1357c478bdstevel@tonic-gate	tf = 0;
1367c478bdstevel@tonic-gate	/*
1377c478bdstevel@tonic-gate	 * TERMCAP can have one of two things in it. It can be the
1387c478bdstevel@tonic-gate	 * name of a file to use instead of /etc/termcap. In this
1397c478bdstevel@tonic-gate	 * case it better start with a "/". Or it can be an entry to
1407c478bdstevel@tonic-gate	 * use so we don't have to read the file. In this case it
1417c478bdstevel@tonic-gate	 * has to already have the newlines crunched out.
1427c478bdstevel@tonic-gate	 */
1437c478bdstevel@tonic-gate	if (cp && *cp) {
1447c478bdstevel@tonic-gate		if (*cp != '/') {
1457c478bdstevel@tonic-gate			cp2 = getenv(V_TERM);
1467c478bdstevel@tonic-gate			if (cp2 == (char *)0 || strcmp(name, cp2) == 0) {
1477c478bdstevel@tonic-gate				if (strstr(cp, "dv=") != 0)
1487c478bdstevel@tonic-gate					trusted_device = 0;
1498d489c7muffin				(void) strncpy(bp, cp, len-1);
1507c478bdstevel@tonic-gate				bp[len-1] = '\0';
1517c478bdstevel@tonic-gate				return (tnchktc());
1527c478bdstevel@tonic-gate			} else
1537c478bdstevel@tonic-gate				tf = open(E_TERMCAP, O_RDONLY);
1547c478bdstevel@tonic-gate		} else {
1557c478bdstevel@tonic-gate			/* open SYSREMOTE as uucp, other files as user */
1567c478bdstevel@tonic-gate			safe = strcmp(cp, SYSREMOTE) == 0;
1577c478bdstevel@tonic-gate			if (!safe)
1587c478bdstevel@tonic-gate				userperm();
1597c478bdstevel@tonic-gate			tf = open(RM = cp, O_RDONLY);
1607c478bdstevel@tonic-gate			if (!safe)
1617c478bdstevel@tonic-gate				myperm();
1627c478bdstevel@tonic-gate		}
1637c478bdstevel@tonic-gate	}
1647c478bdstevel@tonic-gate	if (tf == 0)
1657c478bdstevel@tonic-gate		tf = open(E_TERMCAP, O_RDONLY);
1667c478bdstevel@tonic-gate	if (tf < 0)
1677c478bdstevel@tonic-gate		return (-1);
1687c478bdstevel@tonic-gate	for (;;) {
1697c478bdstevel@tonic-gate		cp = bp;
1707c478bdstevel@tonic-gate		for (;;) {
1717c478bdstevel@tonic-gate			if (i == cnt) {
1727c478bdstevel@tonic-gate				cnt = read(tf, ibuf, BUFSIZ);
1737c478bdstevel@tonic-gate				if (cnt <= 0) {
1748d489c7muffin					(void) close(tf);
1757c478bdstevel@tonic-gate					return (0);
1767c478bdstevel@tonic-gate				}
1777c478bdstevel@tonic-gate				i = 0;
1787c478bdstevel@tonic-gate			}
1797c478bdstevel@tonic-gate			c = ibuf[i++];
1807c478bdstevel@tonic-gate			if (c == '\n') {
1817c478bdstevel@tonic-gate				if (cp > bp && cp[-1] == '\\') {
1827c478bdstevel@tonic-gate					cp--;
1837c478bdstevel@tonic-gate					continue;
1847c478bdstevel@tonic-gate				}
1857c478bdstevel@tonic-gate				break;
1867c478bdstevel@tonic-gate			}
1877c478bdstevel@tonic-gate			if (cp >= bp+len) {
1888d489c7muffin				(void) write(2, "Remcap entry too long\n", 23);
1897c478bdstevel@tonic-gate				break;
1907c478bdstevel@tonic-gate			} else
1917c478bdstevel@tonic-gate				*cp++ = c;
1927c478bdstevel@tonic-gate		}
1937c478bdstevel@tonic-gate		*cp = 0;
1947c478bdstevel@tonic-gate
1957c478bdstevel@tonic-gate		/*
1967c478bdstevel@tonic-gate		 * The real work for the match.
1977c478bdstevel@tonic-gate		 */
1987c478bdstevel@tonic-gate		if (tnamatch(name)) {
1997c478bdstevel@tonic-gate			/*
2007c478bdstevel@tonic-gate			 * if a dv= entry is obtained from $REMOTE,
2017c478bdstevel@tonic-gate			 * switch off trusted_device status
2027c478bdstevel@tonic-gate			 */
2037c478bdstevel@tonic-gate			if (!safe && strstr(bp, "dv=") != 0)
2047c478bdstevel@tonic-gate				trusted_device = 0;
2058d489c7muffin			(void) close(tf);
2067c478bdstevel@tonic-gate			return (tnchktc());
2077c478bdstevel@tonic-gate		}
2087c478bdstevel@tonic-gate	}
2097c478bdstevel@tonic-gate}
2107c478bdstevel@tonic-gate
2117c478bdstevel@tonic-gate/*
2127c478bdstevel@tonic-gate * tnchktc: check the last entry, see if it's tc=xxx. If so,
2137c478bdstevel@tonic-gate * recursively find xxx and append that entry (minus the names)
2147c478bdstevel@tonic-gate * to take the place of the tc=xxx entry. This allows termcap
2157c478bdstevel@tonic-gate * entries to say "like an HP2621 but doesn't turn on the labels".
2167c478bdstevel@tonic-gate * Note that this works because of the left to right scan.
2177c478bdstevel@tonic-gate */
2188d489c7muffinint
2198d489c7muffintnchktc(void)
2207c478bdstevel@tonic-gate{
2218d489c7muffin	char *p, *q;
2227c478bdstevel@tonic-gate	char tcname[64];	/* name of similar terminal */
2237c478bdstevel@tonic-gate	char tcbuf[BUFSIZ];
2247c478bdstevel@tonic-gate	char *holdtbuf = tbuf;
2257c478bdstevel@tonic-gate	int l;
2267c478bdstevel@tonic-gate
2277c478bdstevel@tonic-gate	p = tbuf + strlen(tbuf) - 2;	/* before the last colon */
2287c478bdstevel@tonic-gate	while (*--p != ':')
2297c478bdstevel@tonic-gate		if (p < tbuf) {
2308d489c7muffin			(void) write(2, "Bad remcap entry\n", 18);
2317c478bdstevel@tonic-gate			return (0);
2327c478bdstevel@tonic-gate		}
2337c478bdstevel@tonic-gate	p++;
2347c478bdstevel@tonic-gate	/* p now points to beginning of last field */
2357c478bdstevel@tonic-gate	if (p[0] != 't' || p[1] != 'c')
2367c478bdstevel@tonic-gate		return (1);
2378d489c7muffin	(void) strlcpy(tcname, p+3, sizeof (tcname));
2387c478bdstevel@tonic-gate	q = tcname;
2397c478bdstevel@tonic-gate	while (*q && *q != ':')
2407c478bdstevel@tonic-gate		q++;
2417c478bdstevel@tonic-gate	*q = 0;
2427c478bdstevel@tonic-gate	if (++hopcount > MAXHOP) {
2438d489c7muffin		(void) write(2, "Infinite tc= loop\n", 18);
2447c478bdstevel@tonic-gate		return (0);
2457c478bdstevel@tonic-gate	}
2467c478bdstevel@tonic-gate	if (getent(tcbuf, tcname, remotefile, sizeof (tcbuf)) != 1) {
2477c478bdstevel@tonic-gate		if (strcmp(remotefile, SYSREMOTE) == 0)
2487c478bdstevel@tonic-gate			return (0);
2497c478bdstevel@tonic-gate		else if (getent(tcbuf, tcname, SYSREMOTE, sizeof (tcbuf)) != 1)
2507c478bdstevel@tonic-gate			return (0);
2517c478bdstevel@tonic-gate	}
2527c478bdstevel@tonic-gate	for (q = tcbuf; *q++ != ':'; )
2537c478bdstevel@tonic-gate		;
2547c478bdstevel@tonic-gate	l = p - holdtbuf + strlen(q);
2557c478bdstevel@tonic-gate	if (l > BUFSIZ) {
2568d489c7muffin		(void) write(2, "Remcap entry too long\n", 23);
2577c478bdstevel@tonic-gate		q[BUFSIZ - (p-holdtbuf)] = 0;
2587c478bdstevel@tonic-gate	}
2598d489c7muffin	(void) strcpy(p, q);
2607c478bdstevel@tonic-gate	tbuf = holdtbuf;
2617c478bdstevel@tonic-gate	return (1);
2627c478bdstevel@tonic-gate}
2637c478bdstevel@tonic-gate
2647c478bdstevel@tonic-gate/*
2657c478bdstevel@tonic-gate * Tnamatch deals with name matching.  The first field of the termcap
2667c478bdstevel@tonic-gate * entry is a sequence of names separated by |'s, so we compare
2677c478bdstevel@tonic-gate * against each such name.  The normal : terminator after the last
2687c478bdstevel@tonic-gate * name (before the first field) stops us.
2697c478bdstevel@tonic-gate */
2708d489c7muffinint
2718d489c7muffintnamatch(char *np)
2727c478bdstevel@tonic-gate{
2738d489c7muffin	char *Np, *Bp;
2747c478bdstevel@tonic-gate
2757c478bdstevel@tonic-gate	Bp = tbuf;
2767c478bdstevel@tonic-gate	if (*Bp == '#')
2777c478bdstevel@tonic-gate		return (0);
2787c478bdstevel@tonic-gate	for (;;) {
2797c478bdstevel@tonic-gate		for (Np = np; *Np && *Bp == *Np; Bp++, Np++)
2807c478bdstevel@tonic-gate			continue;
2817c478bdstevel@tonic-gate		if (*Np == 0 && (*Bp == '|' || *Bp == ':' || *Bp == 0))
2827c478bdstevel@tonic-gate			return (1);
2837c478bdstevel@tonic-gate		while (*Bp && *Bp != ':' && *Bp != '|')
2847c478bdstevel@tonic-gate			Bp++;
2857c478bdstevel@tonic-gate		if (*Bp == 0 || *Bp == ':')
2867c478bdstevel@tonic-gate			return (0);
2877c478bdstevel@tonic-gate		Bp++;
2887c478bdstevel@tonic-gate	}
2897c478bdstevel@tonic-gate}
2907c478bdstevel@tonic-gate
2917c478bdstevel@tonic-gate/*
2927c478bdstevel@tonic-gate * Skip to the next field.  Notice that this is very dumb, not
2937c478bdstevel@tonic-gate * knowing about \: escapes or any such.  If necessary, :'s can be put
2947c478bdstevel@tonic-gate * into the termcap file in octal.
2957c478bdstevel@tonic-gate */
2967c478bdstevel@tonic-gatestatic char *
2978d489c7muffintskip(char *bp)
2987c478bdstevel@tonic-gate{
2997c478bdstevel@tonic-gate
3007c478bdstevel@tonic-gate	while (*bp && *bp != ':')
3017c478bdstevel@tonic-gate		bp++;
3027c478bdstevel@tonic-gate	if (*bp == ':') {
3037c478bdstevel@tonic-gate		do {
3047c478bdstevel@tonic-gate			bp++;
3057c478bdstevel@tonic-gate			while (isspace(*bp))
3067c478bdstevel@tonic-gate				bp++;
3077c478bdstevel@tonic-gate		} while (*bp == ':');
3087c478bdstevel@tonic-gate	}
3097c478bdstevel@tonic-gate	return (bp);
3107c478bdstevel@tonic-gate}
3117c478bdstevel@tonic-gate
3127c478bdstevel@tonic-gate/*
3137c478bdstevel@tonic-gate * Return the (numeric) option id.
3147c478bdstevel@tonic-gate * Numeric options look like
3157c478bdstevel@tonic-gate *	li#80
3167c478bdstevel@tonic-gate * i.e. the option string is separated from the numeric value by
3177c478bdstevel@tonic-gate * a # character.  If the option is not found we return -1.
3187c478bdstevel@tonic-gate * Note that we handle octal numbers beginning with 0.
3197c478bdstevel@tonic-gate */
3208d489c7muffinint
3218d489c7muffintgetnum(char *id)
3227c478bdstevel@tonic-gate{
3238d489c7muffin	int i, base;
3248d489c7muffin	char *bp = tbuf;
3257c478bdstevel@tonic-gate
3267c478bdstevel@tonic-gate	for (;;) {
3277c478bdstevel@tonic-gate		bp = tskip(bp);
3287c478bdstevel@tonic-gate		if (*bp == 0)
3297c478bdstevel@tonic-gate			return (-1);
3307c478bdstevel@tonic-gate		if (*bp++ != id[0] || *bp == 0 || *bp++ != id[1])
3317c478bdstevel@tonic-gate			continue;
3327c478bdstevel@tonic-gate		if (*bp == '@')
3337c478bdstevel@tonic-gate			return (-1);
3347c478bdstevel@tonic-gate		if (*bp != '#')
3357c478bdstevel@tonic-gate			continue;
3367c478bdstevel@tonic-gate		bp++;
3377c478bdstevel@tonic-gate		base = 10;
3387c478bdstevel@tonic-gate		if (*bp == '0')
3397c478bdstevel@tonic-gate			base = 8;
3407c478bdstevel@tonic-gate		i = 0;
3417c478bdstevel@tonic-gate		while (isdigit(*bp))
3427c478bdstevel@tonic-gate			i *= base, i += *bp++ - '0';
3437c478bdstevel@tonic-gate		return (i);
3447c478bdstevel@tonic-gate	}
3457c478bdstevel@tonic-gate}
3467c478bdstevel@tonic-gate
3477c478bdstevel@tonic-gate/*
3487c478bdstevel@tonic-gate * Handle a flag option.
3497c478bdstevel@tonic-gate * Flag options are given "naked", i.e. followed by a : or the end
3507c478bdstevel@tonic-gate * of the buffer.  Return 1 if we find the option, or 0 if it is
3517c478bdstevel@tonic-gate * not given.
3527c478bdstevel@tonic-gate */
3538d489c7muffinint
3548d489c7muffintgetflag(char *id)
3557c478bdstevel@tonic-gate{
3568d489c7muffin	char *bp = tbuf;
3577c478bdstevel@tonic-gate
3587c478bdstevel@tonic-gate	for (;;) {
3597c478bdstevel@tonic-gate		bp = tskip(bp);
3607c478bdstevel@tonic-gate		if (!*bp)
3617c478bdstevel@tonic-gate			return (0);
3627c478bdstevel@tonic-gate		if (*bp++ == id[0] && *bp != 0 && *bp++ == id[1]) {
3637c478bdstevel@tonic-gate			if (!*bp || *bp == ':')
3647c478bdstevel@tonic-gate				return (1);
3657c478bdstevel@tonic-gate			else if (*bp == '@')
3667c478bdstevel@tonic-gate				return (0);
3677c478bdstevel@tonic-gate		}
3687c478bdstevel@tonic-gate	}
3697c478bdstevel@tonic-gate}
3707c478bdstevel@tonic-gate
3717c478bdstevel@tonic-gate/*
3727c478bdstevel@tonic-gate * Get a string valued option.
3737c478bdstevel@tonic-gate * These are given as
3747c478bdstevel@tonic-gate *	cl=^Z
3757c478bdstevel@tonic-gate * Much decoding is done on the strings, and the strings are
3767c478bdstevel@tonic-gate * placed in area, which is a ref parameter which is updated.
3777c478bdstevel@tonic-gate * No checking on area overflow.
3787c478bdstevel@tonic-gate */
3797c478bdstevel@tonic-gatechar *
3808d489c7muffintgetstr(char *id, char **area)
3817c478bdstevel@tonic-gate{
3828d489c7muffin	char *bp = tbuf;
3837c478bdstevel@tonic-gate
3847c478bdstevel@tonic-gate	for (;;) {
3857c478bdstevel@tonic-gate		bp = tskip(bp);
3867c478bdstevel@tonic-gate		if (!*bp)
3877c478bdstevel@tonic-gate			return (0);
3887c478bdstevel@tonic-gate		if (*bp++ != id[0] || *bp == 0 || *bp++ != id[1])
3897c478bdstevel@tonic-gate			continue;
3907c478bdstevel@tonic-gate		if (*bp == '@')
3917c478bdstevel@tonic-gate			return (0);
3927c478bdstevel@tonic-gate		if (*bp != '=')
3937c478bdstevel@tonic-gate			continue;
3947c478bdstevel@tonic-gate		bp++;
3957c478bdstevel@tonic-gate		return (tdecode(bp, area));
3967c478bdstevel@tonic-gate	}
3977c478bdstevel@tonic-gate}
3987c478bdstevel@tonic-gate
3997c478bdstevel@tonic-gate/*
4007c478bdstevel@tonic-gate * Tdecode does the grung work to decode the
4017c478bdstevel@tonic-gate * string capability escapes.
4027c478bdstevel@tonic-gate */
4037c478bdstevel@tonic-gatestatic char *
4048d489c7muffintdecode(char *str, char **area)
4057c478bdstevel@tonic-gate{
4068d489c7muffin	char *cp;
4078d489c7muffin	int c;
4088d489c7muffin	char *dp;
4097c478bdstevel@tonic-gate	int i;
4107c478bdstevel@tonic-gate
4117c478bdstevel@tonic-gate	cp = *area;
4128d489c7muffin	while ((c = *str++) != 0 && c != ':') {
4137c478bdstevel@tonic-gate		switch (c) {
4147c478bdstevel@tonic-gate
4157c478bdstevel@tonic-gate		case '^':
4167c478bdstevel@tonic-gate			c = *str++ & 037;
4177c478bdstevel@tonic-gate			break;
4187c478bdstevel@tonic-gate
4197c478bdstevel@tonic-gate		case '\\':
4207c478bdstevel@tonic-gate			dp = "E\033^^\\\\::n\nr\rt\tb\bf\f";
4217c478bdstevel@tonic-gate			c = *str++;
4227c478bdstevel@tonic-gatenextc:
4237c478bdstevel@tonic-gate			if (*dp++ == c) {
4247c478bdstevel@tonic-gate				c = *dp++;
4257c478bdstevel@tonic-gate				break;
4267c478bdstevel@tonic-gate			}
4277c478bdstevel@tonic-gate			dp++;
4287c478bdstevel@tonic-gate			if (*dp)
4297c478bdstevel@tonic-gate				goto nextc;
4307c478bdstevel@tonic-gate			if (isdigit(c)) {
4317c478bdstevel@tonic-gate				c -= '0', i = 2;
4327c478bdstevel@tonic-gate				do
4337c478bdstevel@tonic-gate					c <<= 3, c |= *str++ - '0';
4348d489c7muffin				while (--i && isdigit(*str))
4358d489c7muffin					;
4367c478bdstevel@tonic-gate			}
4377c478bdstevel@tonic-gate			break;
4387c478bdstevel@tonic-gate		}
4397c478bdstevel@tonic-gate		*cp++ = c;
4407c478bdstevel@tonic-gate	}
4417c478bdstevel@tonic-gate	*cp++ = 0;
4427c478bdstevel@tonic-gate	str = *area;
4437c478bdstevel@tonic-gate	*area = cp;
4447c478bdstevel@tonic-gate	return (str);
4457c478bdstevel@tonic-gate}
446