xref: /illumos-gate/usr/src/cmd/listen/nstoa.c (revision 7c478bd9)
1*7c478bd9Sstevel@tonic-gate /*
2*7c478bd9Sstevel@tonic-gate  * CDDL HEADER START
3*7c478bd9Sstevel@tonic-gate  *
4*7c478bd9Sstevel@tonic-gate  * The contents of this file are subject to the terms of the
5*7c478bd9Sstevel@tonic-gate  * Common Development and Distribution License, Version 1.0 only
6*7c478bd9Sstevel@tonic-gate  * (the "License").  You may not use this file except in compliance
7*7c478bd9Sstevel@tonic-gate  * with the License.
8*7c478bd9Sstevel@tonic-gate  *
9*7c478bd9Sstevel@tonic-gate  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
10*7c478bd9Sstevel@tonic-gate  * or http://www.opensolaris.org/os/licensing.
11*7c478bd9Sstevel@tonic-gate  * See the License for the specific language governing permissions
12*7c478bd9Sstevel@tonic-gate  * and limitations under the License.
13*7c478bd9Sstevel@tonic-gate  *
14*7c478bd9Sstevel@tonic-gate  * When distributing Covered Code, include this CDDL HEADER in each
15*7c478bd9Sstevel@tonic-gate  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
16*7c478bd9Sstevel@tonic-gate  * If applicable, add the following below this CDDL HEADER, with the
17*7c478bd9Sstevel@tonic-gate  * fields enclosed by brackets "[]" replaced with your own identifying
18*7c478bd9Sstevel@tonic-gate  * information: Portions Copyright [yyyy] [name of copyright owner]
19*7c478bd9Sstevel@tonic-gate  *
20*7c478bd9Sstevel@tonic-gate  * CDDL HEADER END
21*7c478bd9Sstevel@tonic-gate  */
22*7c478bd9Sstevel@tonic-gate /*	Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T	*/
23*7c478bd9Sstevel@tonic-gate /*	  All Rights Reserved  	*/
24*7c478bd9Sstevel@tonic-gate 
25*7c478bd9Sstevel@tonic-gate 
26*7c478bd9Sstevel@tonic-gate #ident	"%Z%%M%	%I%	%E% SMI"	/* SVr4.0 1.2	*/
27*7c478bd9Sstevel@tonic-gate 
28*7c478bd9Sstevel@tonic-gate /*
29*7c478bd9Sstevel@tonic-gate 	stoa - convert string to address
30*7c478bd9Sstevel@tonic-gate 
31*7c478bd9Sstevel@tonic-gate 	If a string begins in \o or \O, the following address is octal
32*7c478bd9Sstevel@tonic-gate 	"  "   "       "    " \x or \X, the following address is hex
33*7c478bd9Sstevel@tonic-gate 	Otherwise, a string is considered text. Text may be quoted
34*7c478bd9Sstevel@tonic-gate 	with double quotes and the C-like escapes \n, \b, \t, \v, \r, and \nnn
35*7c478bd9Sstevel@tonic-gate 	(nnn = octal char) are recognized.
36*7c478bd9Sstevel@tonic-gate 	A \ followed by a newline causes the newline
37*7c478bd9Sstevel@tonic-gate 	to vanish. A \ followed by any other char causes any "magic" of
38*7c478bd9Sstevel@tonic-gate 	any other char to disappear.
39*7c478bd9Sstevel@tonic-gate 
40*7c478bd9Sstevel@tonic-gate 	Other escape sequences recognized are:
41*7c478bd9Sstevel@tonic-gate 		\!cmd args [ \! || EOL ]
42*7c478bd9Sstevel@tonic-gate 	which is replaced by the raw output of the execution of cmd.
43*7c478bd9Sstevel@tonic-gate 	This may only be used in a string.
44*7c478bd9Sstevel@tonic-gate 
45*7c478bd9Sstevel@tonic-gate 		\$cmd args [ \$ || EOL ]
46*7c478bd9Sstevel@tonic-gate 	which is replaced by the output of the execution of cmd and
47*7c478bd9Sstevel@tonic-gate 	is then reprocessed.
48*7c478bd9Sstevel@tonic-gate 
49*7c478bd9Sstevel@tonic-gate 	A  NULL is returned on any error(s).
50*7c478bd9Sstevel@tonic-gate */
51*7c478bd9Sstevel@tonic-gate 
52*7c478bd9Sstevel@tonic-gate #include <stdio.h>
53*7c478bd9Sstevel@tonic-gate #include <memory.h>
54*7c478bd9Sstevel@tonic-gate #include <ctype.h>
55*7c478bd9Sstevel@tonic-gate #include "nsaddr.h"
56*7c478bd9Sstevel@tonic-gate 
57*7c478bd9Sstevel@tonic-gate 
58*7c478bd9Sstevel@tonic-gate #define	toupper(c)	(islower(c) ? _toupper(c) : (c))
59*7c478bd9Sstevel@tonic-gate #define	todigit(c)	((int)((c) - '0'))	/* char to digit */
60*7c478bd9Sstevel@tonic-gate #define	toxdigit(c)	((isdigit(c))?todigit(c):(toupper(c)-(int)'A'+10))
61*7c478bd9Sstevel@tonic-gate #define	isodigit(c)	(isdigit(c) && ((c) != '9') && ((c) != '8'))
62*7c478bd9Sstevel@tonic-gate #define	itoac(i)	(((i) > 9) ? ((char)((i)-10) + 'A'):((char)(i) + '0'))
63*7c478bd9Sstevel@tonic-gate #define	MASK(n)		((1 << (n)) - 1)
64*7c478bd9Sstevel@tonic-gate 
65*7c478bd9Sstevel@tonic-gate #define	MAXRLEVEL	10	/* maximum recursion level */
66*7c478bd9Sstevel@tonic-gate 
67*7c478bd9Sstevel@tonic-gate #define	TRUE	1;
68*7c478bd9Sstevel@tonic-gate #define	FALSE	0;
69*7c478bd9Sstevel@tonic-gate 
70*7c478bd9Sstevel@tonic-gate char	scanbuf[SBUFSIZE];
71*7c478bd9Sstevel@tonic-gate int	sbp = 0;
72*7c478bd9Sstevel@tonic-gate int	rec = 0;	/* Recursion level */
73*7c478bd9Sstevel@tonic-gate 
74*7c478bd9Sstevel@tonic-gate char	sbuf[SBUFSIZE];
75*7c478bd9Sstevel@tonic-gate 
76*7c478bd9Sstevel@tonic-gate extern void free();
77*7c478bd9Sstevel@tonic-gate 
78*7c478bd9Sstevel@tonic-gate struct netbuf *
79*7c478bd9Sstevel@tonic-gate stoa(str, addr)			/* Return 0 for success, -1 for error */
80*7c478bd9Sstevel@tonic-gate char	*str;
81*7c478bd9Sstevel@tonic-gate struct netbuf	*addr;
82*7c478bd9Sstevel@tonic-gate {
83*7c478bd9Sstevel@tonic-gate 	char	*xfer(), *prescan();
84*7c478bd9Sstevel@tonic-gate 
85*7c478bd9Sstevel@tonic-gate 	int	myadr;		/* was netbuf struct allocated here ? */
86*7c478bd9Sstevel@tonic-gate 	int	quote;		/* quoted string ? */
87*7c478bd9Sstevel@tonic-gate 
88*7c478bd9Sstevel@tonic-gate 	myadr = FALSE;
89*7c478bd9Sstevel@tonic-gate 
90*7c478bd9Sstevel@tonic-gate 	if (!str)
91*7c478bd9Sstevel@tonic-gate 		return NULL;
92*7c478bd9Sstevel@tonic-gate 	while (*str && isspace(*str))	/* leading whites are OK */
93*7c478bd9Sstevel@tonic-gate 		++str;
94*7c478bd9Sstevel@tonic-gate 
95*7c478bd9Sstevel@tonic-gate 	str = prescan(str);		/* Do all \$ ... \$ */
96*7c478bd9Sstevel@tonic-gate 
97*7c478bd9Sstevel@tonic-gate 	if (!str || !*str) return NULL;		/* Nothing to convert */
98*7c478bd9Sstevel@tonic-gate 
99*7c478bd9Sstevel@tonic-gate 	if (!addr) {
100*7c478bd9Sstevel@tonic-gate 		if ((addr = (struct netbuf *)malloc(sizeof(struct netbuf))) == NULL)
101*7c478bd9Sstevel@tonic-gate 			return NULL;
102*7c478bd9Sstevel@tonic-gate 		myadr = TRUE;
103*7c478bd9Sstevel@tonic-gate 		addr->buf = NULL;
104*7c478bd9Sstevel@tonic-gate 		addr->maxlen = 0;
105*7c478bd9Sstevel@tonic-gate 		addr->len = 0;
106*7c478bd9Sstevel@tonic-gate 	}
107*7c478bd9Sstevel@tonic-gate 
108*7c478bd9Sstevel@tonic-gate 	/* Now process the address */
109*7c478bd9Sstevel@tonic-gate 	quote = 0;
110*7c478bd9Sstevel@tonic-gate 
111*7c478bd9Sstevel@tonic-gate 	if (*str == '\\') {
112*7c478bd9Sstevel@tonic-gate 		++str;
113*7c478bd9Sstevel@tonic-gate 		switch (*str) {
114*7c478bd9Sstevel@tonic-gate 
115*7c478bd9Sstevel@tonic-gate 		case 'X':	/* hex */
116*7c478bd9Sstevel@tonic-gate 		case 'x':
117*7c478bd9Sstevel@tonic-gate 			addr->len = dobase(++str, sbuf, HEX);
118*7c478bd9Sstevel@tonic-gate 			break;
119*7c478bd9Sstevel@tonic-gate 
120*7c478bd9Sstevel@tonic-gate 		case 'o':	/* octal */
121*7c478bd9Sstevel@tonic-gate 		case 'O':
122*7c478bd9Sstevel@tonic-gate 			addr->len = dobase(++str, sbuf, OCT);
123*7c478bd9Sstevel@tonic-gate 			break;
124*7c478bd9Sstevel@tonic-gate 
125*7c478bd9Sstevel@tonic-gate 		case '\0':	/* No address given!, length is 0 */
126*7c478bd9Sstevel@tonic-gate 			addr->len = dostring(str, sbuf, 0);
127*7c478bd9Sstevel@tonic-gate 			break;
128*7c478bd9Sstevel@tonic-gate 
129*7c478bd9Sstevel@tonic-gate 		default:	/* \ is handled by dostring */
130*7c478bd9Sstevel@tonic-gate 			addr->len = dostring(--str, sbuf, quote);
131*7c478bd9Sstevel@tonic-gate 			break;
132*7c478bd9Sstevel@tonic-gate 		}
133*7c478bd9Sstevel@tonic-gate 	}
134*7c478bd9Sstevel@tonic-gate 	else {
135*7c478bd9Sstevel@tonic-gate 		if (*str == '"') {	/* quoted string */
136*7c478bd9Sstevel@tonic-gate 			quote = 1;
137*7c478bd9Sstevel@tonic-gate 			++str;
138*7c478bd9Sstevel@tonic-gate 		}
139*7c478bd9Sstevel@tonic-gate 		addr->len = dostring(str, sbuf, quote);
140*7c478bd9Sstevel@tonic-gate 	}
141*7c478bd9Sstevel@tonic-gate 
142*7c478bd9Sstevel@tonic-gate 	if (addr->len == 0) {	/* Error in conversion */
143*7c478bd9Sstevel@tonic-gate 		if (myadr)
144*7c478bd9Sstevel@tonic-gate 			free(addr);
145*7c478bd9Sstevel@tonic-gate 		return NULL;
146*7c478bd9Sstevel@tonic-gate 	}
147*7c478bd9Sstevel@tonic-gate 	if ((addr->buf = xfer(addr->buf, sbuf, addr->len, addr->maxlen)) == NULL)
148*7c478bd9Sstevel@tonic-gate 		return NULL;
149*7c478bd9Sstevel@tonic-gate 	else
150*7c478bd9Sstevel@tonic-gate 		return addr;
151*7c478bd9Sstevel@tonic-gate }
152*7c478bd9Sstevel@tonic-gate 
153*7c478bd9Sstevel@tonic-gate 
154*7c478bd9Sstevel@tonic-gate /*
155*7c478bd9Sstevel@tonic-gate 	dostring:	Copy string at s to buf translating
156*7c478bd9Sstevel@tonic-gate 		escaped characters and shell escapes.
157*7c478bd9Sstevel@tonic-gate 	return length of string.
158*7c478bd9Sstevel@tonic-gate */
159*7c478bd9Sstevel@tonic-gate 
160*7c478bd9Sstevel@tonic-gate int
161*7c478bd9Sstevel@tonic-gate dostring(s, buf, quote)		/* read in a raw address */
162*7c478bd9Sstevel@tonic-gate char	*s, *buf;
163*7c478bd9Sstevel@tonic-gate int	quote;
164*7c478bd9Sstevel@tonic-gate {
165*7c478bd9Sstevel@tonic-gate 	char	*xcmd();
166*7c478bd9Sstevel@tonic-gate 
167*7c478bd9Sstevel@tonic-gate 	int	oc, ch, len = 0;
168*7c478bd9Sstevel@tonic-gate 	int	l = 0;
169*7c478bd9Sstevel@tonic-gate 	char	*rout;
170*7c478bd9Sstevel@tonic-gate 
171*7c478bd9Sstevel@tonic-gate 	while (*s) {
172*7c478bd9Sstevel@tonic-gate 		if (len >= SBUFSIZE) {
173*7c478bd9Sstevel@tonic-gate 			fprintf(stderr, "dostring: string too long\n");
174*7c478bd9Sstevel@tonic-gate 			break;
175*7c478bd9Sstevel@tonic-gate 		}
176*7c478bd9Sstevel@tonic-gate 		else if (*s == '\\')
177*7c478bd9Sstevel@tonic-gate 			switch(*++s) {
178*7c478bd9Sstevel@tonic-gate 
179*7c478bd9Sstevel@tonic-gate 			case '!':	/* raw shell escape */
180*7c478bd9Sstevel@tonic-gate 				if (rout = xcmd(s+1, '!', &s, &l)) {
181*7c478bd9Sstevel@tonic-gate 					if (len + l < SBUFSIZE)
182*7c478bd9Sstevel@tonic-gate 						memcpy(buf+len, rout, l);
183*7c478bd9Sstevel@tonic-gate 					len += l;
184*7c478bd9Sstevel@tonic-gate 					free(rout);
185*7c478bd9Sstevel@tonic-gate 				}
186*7c478bd9Sstevel@tonic-gate 				break;
187*7c478bd9Sstevel@tonic-gate 
188*7c478bd9Sstevel@tonic-gate 			case '\n':	/* ignore newline */
189*7c478bd9Sstevel@tonic-gate 				++s;
190*7c478bd9Sstevel@tonic-gate 				break;
191*7c478bd9Sstevel@tonic-gate 
192*7c478bd9Sstevel@tonic-gate 			case 'b':	/* backspace */
193*7c478bd9Sstevel@tonic-gate 				buf[len++] = '\b'; s++;
194*7c478bd9Sstevel@tonic-gate 				break;
195*7c478bd9Sstevel@tonic-gate 
196*7c478bd9Sstevel@tonic-gate 			case 'n':	/* newline */
197*7c478bd9Sstevel@tonic-gate 				buf[len++] = '\n'; s++;
198*7c478bd9Sstevel@tonic-gate 				break;
199*7c478bd9Sstevel@tonic-gate 
200*7c478bd9Sstevel@tonic-gate 			case 'r':	/* return */
201*7c478bd9Sstevel@tonic-gate 				buf[len++] = '\r'; s++;
202*7c478bd9Sstevel@tonic-gate 				break;
203*7c478bd9Sstevel@tonic-gate 
204*7c478bd9Sstevel@tonic-gate 			case 't':	/* horiz. tab */
205*7c478bd9Sstevel@tonic-gate 				buf[len++] = '\t'; s++;
206*7c478bd9Sstevel@tonic-gate 				break;
207*7c478bd9Sstevel@tonic-gate 
208*7c478bd9Sstevel@tonic-gate 			case 'v':	/* vert. tab */
209*7c478bd9Sstevel@tonic-gate 				buf[len++] = '\v'; s++;
210*7c478bd9Sstevel@tonic-gate 
211*7c478bd9Sstevel@tonic-gate 			case '0':
212*7c478bd9Sstevel@tonic-gate 			case '1':
213*7c478bd9Sstevel@tonic-gate 			case '2':
214*7c478bd9Sstevel@tonic-gate 			case '3':
215*7c478bd9Sstevel@tonic-gate 				for(oc=ch=0; (*s >= '0' && *s <= '7') && oc++ < 3; ++s)
216*7c478bd9Sstevel@tonic-gate 					ch = (ch << 3) | (*s - '0');
217*7c478bd9Sstevel@tonic-gate 				buf[len++] = ch;
218*7c478bd9Sstevel@tonic-gate 				break;
219*7c478bd9Sstevel@tonic-gate 
220*7c478bd9Sstevel@tonic-gate 			case 0:		/* end of string -- terminate */
221*7c478bd9Sstevel@tonic-gate 				break;
222*7c478bd9Sstevel@tonic-gate 
223*7c478bd9Sstevel@tonic-gate 			default:	/* take the character blindly */
224*7c478bd9Sstevel@tonic-gate 				buf[len++] = *s++;
225*7c478bd9Sstevel@tonic-gate 				break;
226*7c478bd9Sstevel@tonic-gate 			}
227*7c478bd9Sstevel@tonic-gate 		else if ((quote && (*s == '"')) || (!quote && isspace(*s)))
228*7c478bd9Sstevel@tonic-gate 			break;
229*7c478bd9Sstevel@tonic-gate 
230*7c478bd9Sstevel@tonic-gate 		else
231*7c478bd9Sstevel@tonic-gate 			buf[len++] = *s++;
232*7c478bd9Sstevel@tonic-gate 	}
233*7c478bd9Sstevel@tonic-gate 	return (len >= SBUFSIZE) ? 0 : len;
234*7c478bd9Sstevel@tonic-gate }
235*7c478bd9Sstevel@tonic-gate 
236*7c478bd9Sstevel@tonic-gate 
237*7c478bd9Sstevel@tonic-gate /*
238*7c478bd9Sstevel@tonic-gate 	dobase :	converts a hex or octal ASCII string
239*7c478bd9Sstevel@tonic-gate 		to a binary address. Only HEX or OCT may be used
240*7c478bd9Sstevel@tonic-gate 		for type.
241*7c478bd9Sstevel@tonic-gate 	return length of binary string (in bytes), 0 if error.
242*7c478bd9Sstevel@tonic-gate 	The binary result is placed at buf.
243*7c478bd9Sstevel@tonic-gate */
244*7c478bd9Sstevel@tonic-gate 
245*7c478bd9Sstevel@tonic-gate int
246*7c478bd9Sstevel@tonic-gate dobase(s, buf, type)	/* read in an address */
247*7c478bd9Sstevel@tonic-gate char	*s, *buf;	/* source ASCII, result binary string */
248*7c478bd9Sstevel@tonic-gate int	type;
249*7c478bd9Sstevel@tonic-gate {
250*7c478bd9Sstevel@tonic-gate 	void	memcp();
251*7c478bd9Sstevel@tonic-gate 	int	bp = SBUFSIZE - 1;
252*7c478bd9Sstevel@tonic-gate 	int	shift = 0;
253*7c478bd9Sstevel@tonic-gate 	char	*end;
254*7c478bd9Sstevel@tonic-gate 
255*7c478bd9Sstevel@tonic-gate 	for (end = s; *end && ((type == OCT) ? isodigit(*end) :
256*7c478bd9Sstevel@tonic-gate 		isxdigit(*end)); ++end) ;
257*7c478bd9Sstevel@tonic-gate 
258*7c478bd9Sstevel@tonic-gate 	/* any non-white, non-digits cause address to be rejected,
259*7c478bd9Sstevel@tonic-gate 	   other fields are ignored */
260*7c478bd9Sstevel@tonic-gate 
261*7c478bd9Sstevel@tonic-gate 	if ((*s == 0) || (end == s) || (!isspace(*end) && *end)) {
262*7c478bd9Sstevel@tonic-gate 		fprintf(stderr, "dobase: Illegal trailer on address string\n");
263*7c478bd9Sstevel@tonic-gate 		buf[0] = '\0';
264*7c478bd9Sstevel@tonic-gate 		return 0;
265*7c478bd9Sstevel@tonic-gate 	}
266*7c478bd9Sstevel@tonic-gate 	--end;
267*7c478bd9Sstevel@tonic-gate 
268*7c478bd9Sstevel@tonic-gate 	buf[bp] = '\0';
269*7c478bd9Sstevel@tonic-gate 
270*7c478bd9Sstevel@tonic-gate 	while (bp > 0 && end >= s) {
271*7c478bd9Sstevel@tonic-gate 		buf[bp] |= toxdigit(*end) << shift;
272*7c478bd9Sstevel@tonic-gate 		if (type == OCT) {
273*7c478bd9Sstevel@tonic-gate 			if (shift > 5) {
274*7c478bd9Sstevel@tonic-gate 				buf[--bp] = (todigit(*end) >> (8 - shift))
275*7c478bd9Sstevel@tonic-gate 					& MASK(shift-5);
276*7c478bd9Sstevel@tonic-gate 			}
277*7c478bd9Sstevel@tonic-gate 			if ((shift = (shift + 3) % 8) == 0)
278*7c478bd9Sstevel@tonic-gate 				buf[--bp] = 0;
279*7c478bd9Sstevel@tonic-gate 		}
280*7c478bd9Sstevel@tonic-gate 		else	/* hex */
281*7c478bd9Sstevel@tonic-gate 			if ((shift = (shift) ? 0 : 4) == 0)
282*7c478bd9Sstevel@tonic-gate 				buf[--bp] = 0;;
283*7c478bd9Sstevel@tonic-gate 		--end;
284*7c478bd9Sstevel@tonic-gate 	}
285*7c478bd9Sstevel@tonic-gate 	if (bp == 0) {
286*7c478bd9Sstevel@tonic-gate 		fprintf(stderr, "stoa: dobase: number to long\n");
287*7c478bd9Sstevel@tonic-gate 		return 0;
288*7c478bd9Sstevel@tonic-gate 	}
289*7c478bd9Sstevel@tonic-gate 
290*7c478bd9Sstevel@tonic-gate 	/* need to catch end case to avoid extra 0's in front	*/
291*7c478bd9Sstevel@tonic-gate 	if (!shift)
292*7c478bd9Sstevel@tonic-gate 		bp++;
293*7c478bd9Sstevel@tonic-gate 	memcp(buf, &buf[bp], (SBUFSIZE - bp));
294*7c478bd9Sstevel@tonic-gate 	return (SBUFSIZE - bp);
295*7c478bd9Sstevel@tonic-gate }
296*7c478bd9Sstevel@tonic-gate 
297*7c478bd9Sstevel@tonic-gate #ifdef NOTUSED
298*7c478bd9Sstevel@tonic-gate 
299*7c478bd9Sstevel@tonic-gate 
300*7c478bd9Sstevel@tonic-gate /*
301*7c478bd9Sstevel@tonic-gate 
302*7c478bd9Sstevel@tonic-gate 	atos(str, addr, type)
303*7c478bd9Sstevel@tonic-gate 
304*7c478bd9Sstevel@tonic-gate 	convert address to ASCII form with address in hex, octal,
305*7c478bd9Sstevel@tonic-gate 	or character form.
306*7c478bd9Sstevel@tonic-gate 	return pointer to buffer (NULL on failure).
307*7c478bd9Sstevel@tonic-gate */
308*7c478bd9Sstevel@tonic-gate 
309*7c478bd9Sstevel@tonic-gate 
310*7c478bd9Sstevel@tonic-gate char *
311*7c478bd9Sstevel@tonic-gate atos(str, addr, type)
312*7c478bd9Sstevel@tonic-gate char	*str;
313*7c478bd9Sstevel@tonic-gate struct netbuf	*addr;
314*7c478bd9Sstevel@tonic-gate int	type;
315*7c478bd9Sstevel@tonic-gate {
316*7c478bd9Sstevel@tonic-gate 	char	*xfer();
317*7c478bd9Sstevel@tonic-gate 	int	mystr = 0;	/* was str allocated here ? */
318*7c478bd9Sstevel@tonic-gate 	unsigned	x_atos(), o_atos();
319*7c478bd9Sstevel@tonic-gate 	void	memcp();
320*7c478bd9Sstevel@tonic-gate 
321*7c478bd9Sstevel@tonic-gate 	char	*base;
322*7c478bd9Sstevel@tonic-gate 
323*7c478bd9Sstevel@tonic-gate 	if (addr == NULL)
324*7c478bd9Sstevel@tonic-gate 		return NULL;
325*7c478bd9Sstevel@tonic-gate 
326*7c478bd9Sstevel@tonic-gate 	if (str == NULL)
327*7c478bd9Sstevel@tonic-gate 		if ((str = malloc(SBUFSIZE)) == NULL)
328*7c478bd9Sstevel@tonic-gate 			return NULL;
329*7c478bd9Sstevel@tonic-gate 		else
330*7c478bd9Sstevel@tonic-gate 			mystr = 1;
331*7c478bd9Sstevel@tonic-gate 
332*7c478bd9Sstevel@tonic-gate 	switch (type) {
333*7c478bd9Sstevel@tonic-gate 
334*7c478bd9Sstevel@tonic-gate 	case OCT:
335*7c478bd9Sstevel@tonic-gate 		/* first add \o */
336*7c478bd9Sstevel@tonic-gate 		sbuf[0] = '\\';
337*7c478bd9Sstevel@tonic-gate 		sbuf[1] = 'o';
338*7c478bd9Sstevel@tonic-gate 
339*7c478bd9Sstevel@tonic-gate 		return xfer(str, sbuf, o_atos(sbuf+2, addr->buf, addr->len) + 2,
340*7c478bd9Sstevel@tonic-gate 			mystr ? SBUFSIZE : 0);
341*7c478bd9Sstevel@tonic-gate 
342*7c478bd9Sstevel@tonic-gate 	case HEX:
343*7c478bd9Sstevel@tonic-gate 		/* first add \x */
344*7c478bd9Sstevel@tonic-gate 		sbuf[0] = '\\';
345*7c478bd9Sstevel@tonic-gate 		sbuf[1] = 'x';
346*7c478bd9Sstevel@tonic-gate 
347*7c478bd9Sstevel@tonic-gate 		return xfer(str, sbuf, x_atos(sbuf+2, addr->buf, addr->len) + 2,
348*7c478bd9Sstevel@tonic-gate 			mystr ? SBUFSIZE : 0);
349*7c478bd9Sstevel@tonic-gate 
350*7c478bd9Sstevel@tonic-gate 	case RAW:
351*7c478bd9Sstevel@tonic-gate 		base = xfer(str, addr->buf,
352*7c478bd9Sstevel@tonic-gate 			 addr->len + 1, mystr ? SBUFSIZE : 0);
353*7c478bd9Sstevel@tonic-gate 		if (base)
354*7c478bd9Sstevel@tonic-gate 			base[addr->len] = '\0';	/* terminate*/
355*7c478bd9Sstevel@tonic-gate 		return base;
356*7c478bd9Sstevel@tonic-gate 
357*7c478bd9Sstevel@tonic-gate 	default:
358*7c478bd9Sstevel@tonic-gate 		return NULL;
359*7c478bd9Sstevel@tonic-gate 	}
360*7c478bd9Sstevel@tonic-gate }
361*7c478bd9Sstevel@tonic-gate 
362*7c478bd9Sstevel@tonic-gate 
363*7c478bd9Sstevel@tonic-gate /*
364*7c478bd9Sstevel@tonic-gate 	x_atos, o_atos
365*7c478bd9Sstevel@tonic-gate 	return the number of bytes occupied by string + NULL*/
366*7c478bd9Sstevel@tonic-gate 
367*7c478bd9Sstevel@tonic-gate /*
368*7c478bd9Sstevel@tonic-gate 	x_atos :	convert an address string a, length s
369*7c478bd9Sstevel@tonic-gate 		to hex ASCII in s */
370*7c478bd9Sstevel@tonic-gate 
371*7c478bd9Sstevel@tonic-gate 
372*7c478bd9Sstevel@tonic-gate unsigned
373*7c478bd9Sstevel@tonic-gate x_atos(s, a, l)
374*7c478bd9Sstevel@tonic-gate char	*s, *a;
375*7c478bd9Sstevel@tonic-gate unsigned	l;
376*7c478bd9Sstevel@tonic-gate {
377*7c478bd9Sstevel@tonic-gate 	char	*b;
378*7c478bd9Sstevel@tonic-gate 
379*7c478bd9Sstevel@tonic-gate 	b = s;
380*7c478bd9Sstevel@tonic-gate 	while (l--) {
381*7c478bd9Sstevel@tonic-gate 		*s++ = itoac(((*a >> 4) & MASK (4)));
382*7c478bd9Sstevel@tonic-gate 		*s++ = itoac((*a & MASK(4)));
383*7c478bd9Sstevel@tonic-gate 		++a;
384*7c478bd9Sstevel@tonic-gate 	}
385*7c478bd9Sstevel@tonic-gate 	*s = '\0';
386*7c478bd9Sstevel@tonic-gate 	return (s - b + 1);
387*7c478bd9Sstevel@tonic-gate }
388*7c478bd9Sstevel@tonic-gate 
389*7c478bd9Sstevel@tonic-gate 
390*7c478bd9Sstevel@tonic-gate /*
391*7c478bd9Sstevel@tonic-gate 	o_atos :	convert an address a, length l
392*7c478bd9Sstevel@tonic-gate 		to octal ASCII in s   */
393*7c478bd9Sstevel@tonic-gate 
394*7c478bd9Sstevel@tonic-gate 
395*7c478bd9Sstevel@tonic-gate unsigned
396*7c478bd9Sstevel@tonic-gate o_atos(s, a, l)
397*7c478bd9Sstevel@tonic-gate char	*s, *a;
398*7c478bd9Sstevel@tonic-gate unsigned	l;
399*7c478bd9Sstevel@tonic-gate {
400*7c478bd9Sstevel@tonic-gate 	int	i, shift;
401*7c478bd9Sstevel@tonic-gate 	char	*b;
402*7c478bd9Sstevel@tonic-gate 
403*7c478bd9Sstevel@tonic-gate 	b = s;
404*7c478bd9Sstevel@tonic-gate 	if (l == 0) {
405*7c478bd9Sstevel@tonic-gate 		*s = '\0';
406*7c478bd9Sstevel@tonic-gate 		return 0;
407*7c478bd9Sstevel@tonic-gate 	}
408*7c478bd9Sstevel@tonic-gate 
409*7c478bd9Sstevel@tonic-gate 	/* take care of partial bits and set shift factor for next 3  */
410*7c478bd9Sstevel@tonic-gate 
411*7c478bd9Sstevel@tonic-gate 	i = l % 3;
412*7c478bd9Sstevel@tonic-gate 	*s++ = itoac((*a>>(i+5)) & MASK(3-i));
413*7c478bd9Sstevel@tonic-gate 	shift = 2 + i;
414*7c478bd9Sstevel@tonic-gate 
415*7c478bd9Sstevel@tonic-gate 	while (l)
416*7c478bd9Sstevel@tonic-gate 		if (shift <= 5) {
417*7c478bd9Sstevel@tonic-gate 			*s++ = itoac((*a >> shift) & MASK(3));
418*7c478bd9Sstevel@tonic-gate 			if (shift == 0) {
419*7c478bd9Sstevel@tonic-gate 				++a;
420*7c478bd9Sstevel@tonic-gate 				--l;
421*7c478bd9Sstevel@tonic-gate 			}
422*7c478bd9Sstevel@tonic-gate 			shift += (shift < 3) ? 5 : -3;
423*7c478bd9Sstevel@tonic-gate 		}
424*7c478bd9Sstevel@tonic-gate 		else {
425*7c478bd9Sstevel@tonic-gate 			i = (*a & MASK(shift-5)) << (8-shift);
426*7c478bd9Sstevel@tonic-gate 			i |= (*++a >> shift) & MASK(8-shift);
427*7c478bd9Sstevel@tonic-gate 			*s++ = itoac(i);
428*7c478bd9Sstevel@tonic-gate 			shift -= 3;
429*7c478bd9Sstevel@tonic-gate 			--l;
430*7c478bd9Sstevel@tonic-gate 		}
431*7c478bd9Sstevel@tonic-gate 	*s++ = '\0';
432*7c478bd9Sstevel@tonic-gate 	return (s - b + 1);
433*7c478bd9Sstevel@tonic-gate }
434*7c478bd9Sstevel@tonic-gate 
435*7c478bd9Sstevel@tonic-gate #endif /* NOTUSED */
436*7c478bd9Sstevel@tonic-gate 
437*7c478bd9Sstevel@tonic-gate void
438*7c478bd9Sstevel@tonic-gate memcp(d, s, n)	/* safe memcpy for overlapping regions */
439*7c478bd9Sstevel@tonic-gate char	*d, *s;
440*7c478bd9Sstevel@tonic-gate int	n;
441*7c478bd9Sstevel@tonic-gate {
442*7c478bd9Sstevel@tonic-gate 	while (n--)
443*7c478bd9Sstevel@tonic-gate 		*d++ = *s++;
444*7c478bd9Sstevel@tonic-gate }
445*7c478bd9Sstevel@tonic-gate 
446*7c478bd9Sstevel@tonic-gate 
447*7c478bd9Sstevel@tonic-gate /* transfer block to a given destination or allocate one of the
448*7c478bd9Sstevel@tonic-gate     right size
449*7c478bd9Sstevel@tonic-gate     if max = 0 : ignore max
450*7c478bd9Sstevel@tonic-gate */
451*7c478bd9Sstevel@tonic-gate 
452*7c478bd9Sstevel@tonic-gate char *
453*7c478bd9Sstevel@tonic-gate xfer(dest, src, len, max)
454*7c478bd9Sstevel@tonic-gate char	*dest, *src;
455*7c478bd9Sstevel@tonic-gate unsigned	len, max;
456*7c478bd9Sstevel@tonic-gate {
457*7c478bd9Sstevel@tonic-gate 	if (max && dest && max < len) {		/* No room */
458*7c478bd9Sstevel@tonic-gate 		fprintf(stderr, "xfer: destination not long enough\n");
459*7c478bd9Sstevel@tonic-gate 		return NULL;
460*7c478bd9Sstevel@tonic-gate 	}
461*7c478bd9Sstevel@tonic-gate 	if (!dest)
462*7c478bd9Sstevel@tonic-gate 		if ((dest = (char *)malloc(len)) == NULL) {
463*7c478bd9Sstevel@tonic-gate 			fprintf(stderr, "xfer: malloc failed\n");
464*7c478bd9Sstevel@tonic-gate 			return NULL;
465*7c478bd9Sstevel@tonic-gate 		}
466*7c478bd9Sstevel@tonic-gate 
467*7c478bd9Sstevel@tonic-gate 	memcpy(dest, src, (int)len);
468*7c478bd9Sstevel@tonic-gate 	return dest;
469*7c478bd9Sstevel@tonic-gate }
470*7c478bd9Sstevel@tonic-gate 
471*7c478bd9Sstevel@tonic-gate /*
472*7c478bd9Sstevel@tonic-gate 	prescan:	scan through string s, expanding all \$...\$
473*7c478bd9Sstevel@tonic-gate 		as shell escapes.
474*7c478bd9Sstevel@tonic-gate 	Return pointer to string of expanded text.
475*7c478bd9Sstevel@tonic-gate */
476*7c478bd9Sstevel@tonic-gate 
477*7c478bd9Sstevel@tonic-gate char *
478*7c478bd9Sstevel@tonic-gate prescan(s)
479*7c478bd9Sstevel@tonic-gate char	*s;
480*7c478bd9Sstevel@tonic-gate {
481*7c478bd9Sstevel@tonic-gate 	int	scan();
482*7c478bd9Sstevel@tonic-gate 
483*7c478bd9Sstevel@tonic-gate 	rec = sbp = 0;
484*7c478bd9Sstevel@tonic-gate 	if (!s || !*s || !scan(s))
485*7c478bd9Sstevel@tonic-gate 		return NULL;
486*7c478bd9Sstevel@tonic-gate 	scanbuf[sbp] = '\0';
487*7c478bd9Sstevel@tonic-gate 	return scanbuf;
488*7c478bd9Sstevel@tonic-gate }
489*7c478bd9Sstevel@tonic-gate 
490*7c478bd9Sstevel@tonic-gate 
491*7c478bd9Sstevel@tonic-gate /*
492*7c478bd9Sstevel@tonic-gate 	scan:	scan through string s, expanding all \$...\$.
493*7c478bd9Sstevel@tonic-gate 	(Part II of prescan)
494*7c478bd9Sstevel@tonic-gate 	Return 0 if anything failed, else 1.
495*7c478bd9Sstevel@tonic-gate */
496*7c478bd9Sstevel@tonic-gate 
497*7c478bd9Sstevel@tonic-gate scan(s)
498*7c478bd9Sstevel@tonic-gate char	*s;
499*7c478bd9Sstevel@tonic-gate {
500*7c478bd9Sstevel@tonic-gate 	char	*xcmd();
501*7c478bd9Sstevel@tonic-gate 	char	*cmd;
502*7c478bd9Sstevel@tonic-gate 	int	len;
503*7c478bd9Sstevel@tonic-gate 	int	esc = 0;		/* Keep lookout for \\$ */
504*7c478bd9Sstevel@tonic-gate 
505*7c478bd9Sstevel@tonic-gate 	while (*s) {
506*7c478bd9Sstevel@tonic-gate 		if (!esc && (*s == '\\' && *(s+1) == '$')) {
507*7c478bd9Sstevel@tonic-gate 			if (rec++ == MAXRLEVEL) {
508*7c478bd9Sstevel@tonic-gate 				fprintf(stderr, "scan: Recursion \
509*7c478bd9Sstevel@tonic-gate level past %d on shell escape\n", rec);
510*7c478bd9Sstevel@tonic-gate 				return 0;
511*7c478bd9Sstevel@tonic-gate 			}
512*7c478bd9Sstevel@tonic-gate 			if ((cmd = xcmd(s+2, '$', &s, &len)) != NULL) {
513*7c478bd9Sstevel@tonic-gate 				cmd[len] = '\0';
514*7c478bd9Sstevel@tonic-gate  				if (*cmd != '\0')
515*7c478bd9Sstevel@tonic-gate 					scan(cmd);
516*7c478bd9Sstevel@tonic-gate 				free(cmd);
517*7c478bd9Sstevel@tonic-gate 			}
518*7c478bd9Sstevel@tonic-gate 			else
519*7c478bd9Sstevel@tonic-gate 				return 0;
520*7c478bd9Sstevel@tonic-gate 		}
521*7c478bd9Sstevel@tonic-gate 
522*7c478bd9Sstevel@tonic-gate 		else if (sbp == SBUFSIZE) {
523*7c478bd9Sstevel@tonic-gate 			fprintf(stderr, "Overflow on shell esc expansion\n");
524*7c478bd9Sstevel@tonic-gate 			return 0;
525*7c478bd9Sstevel@tonic-gate 		}
526*7c478bd9Sstevel@tonic-gate 		else if (sbp < SBUFSIZE)
527*7c478bd9Sstevel@tonic-gate 			esc = ((scanbuf[sbp++] = *s++) == '\\');
528*7c478bd9Sstevel@tonic-gate 	}
529*7c478bd9Sstevel@tonic-gate 	return 1;
530*7c478bd9Sstevel@tonic-gate }
531*7c478bd9Sstevel@tonic-gate 
532*7c478bd9Sstevel@tonic-gate 
533*7c478bd9Sstevel@tonic-gate /*
534*7c478bd9Sstevel@tonic-gate 	xcmd :	extract command line for shell escape and execute it
535*7c478bd9Sstevel@tonic-gate 		return pointer to output of command
536*7c478bd9Sstevel@tonic-gate */
537*7c478bd9Sstevel@tonic-gate 
538*7c478bd9Sstevel@tonic-gate char *
539*7c478bd9Sstevel@tonic-gate xcmd(s, ec, ps, len)
540*7c478bd9Sstevel@tonic-gate char	*s;		/* input string */
541*7c478bd9Sstevel@tonic-gate char	ec;		/* escape char ( $ or ! ) */
542*7c478bd9Sstevel@tonic-gate char	**ps;		/* address of input string pointer */
543*7c478bd9Sstevel@tonic-gate int	*len;		/* Number of bytes of output from command */
544*7c478bd9Sstevel@tonic-gate {
545*7c478bd9Sstevel@tonic-gate 	FILE	*popen();
546*7c478bd9Sstevel@tonic-gate 	int	pclose();
547*7c478bd9Sstevel@tonic-gate 
548*7c478bd9Sstevel@tonic-gate 	FILE	*pfp;		/* pipe for process */
549*7c478bd9Sstevel@tonic-gate 	char	*cmd;		/* command buffer */
550*7c478bd9Sstevel@tonic-gate 	char	*cmdp;		/* pointer along cmd */
551*7c478bd9Sstevel@tonic-gate 	char	*ocmd;		/* output of command buffer */
552*7c478bd9Sstevel@tonic-gate 	int	esc = 0;	/* escaped escape shell */
553*7c478bd9Sstevel@tonic-gate 
554*7c478bd9Sstevel@tonic-gate 	*len = 0;
555*7c478bd9Sstevel@tonic-gate 
556*7c478bd9Sstevel@tonic-gate 	if ((cmd = cmdp = (char *)malloc(SBUFSIZE)) == NULL) {
557*7c478bd9Sstevel@tonic-gate 		fprintf(stderr, "xcmd: malloc failed\n");
558*7c478bd9Sstevel@tonic-gate 		return NULL;
559*7c478bd9Sstevel@tonic-gate 	}
560*7c478bd9Sstevel@tonic-gate 
561*7c478bd9Sstevel@tonic-gate 	if ((ocmd = (char *)malloc(SBUFSIZE)) == NULL) {
562*7c478bd9Sstevel@tonic-gate 		fprintf(stderr, "xcmd: malloc failed\n");
563*7c478bd9Sstevel@tonic-gate 		free(cmd);
564*7c478bd9Sstevel@tonic-gate 		return NULL;
565*7c478bd9Sstevel@tonic-gate 	}
566*7c478bd9Sstevel@tonic-gate 	while (*s) {
567*7c478bd9Sstevel@tonic-gate 		if (!esc && *s == '\\' && *(s+1) == ec) {
568*7c478bd9Sstevel@tonic-gate 			s += 2;
569*7c478bd9Sstevel@tonic-gate 			break;
570*7c478bd9Sstevel@tonic-gate 		}
571*7c478bd9Sstevel@tonic-gate 		else
572*7c478bd9Sstevel@tonic-gate 			esc = (*cmdp++ = *s++) == '\\';
573*7c478bd9Sstevel@tonic-gate 	}
574*7c478bd9Sstevel@tonic-gate 	*cmdp = '\0';
575*7c478bd9Sstevel@tonic-gate 	*ps = s;
576*7c478bd9Sstevel@tonic-gate 
577*7c478bd9Sstevel@tonic-gate 	if ((pfp = popen(cmd, "r")) == NULL)
578*7c478bd9Sstevel@tonic-gate 		fprintf(stderr, "xcmd: popen failed\n");
579*7c478bd9Sstevel@tonic-gate 	while (fread(&ocmd[*len], 1, 1, pfp))
580*7c478bd9Sstevel@tonic-gate 		if ((*len += 1) >= SBUFSIZE) {
581*7c478bd9Sstevel@tonic-gate 			fprintf(stderr, "xcmd: command output too long\n");
582*7c478bd9Sstevel@tonic-gate 			break;
583*7c478bd9Sstevel@tonic-gate 		}
584*7c478bd9Sstevel@tonic-gate 	pclose(pfp);
585*7c478bd9Sstevel@tonic-gate 	free(cmd);
586*7c478bd9Sstevel@tonic-gate 
587*7c478bd9Sstevel@tonic-gate 	return ocmd;
588*7c478bd9Sstevel@tonic-gate }
589