xref: /illumos-gate/usr/src/cmd/listen/nstoa.c (revision 25b601ca)
17c478bd9Sstevel@tonic-gate /*
27c478bd9Sstevel@tonic-gate  * CDDL HEADER START
37c478bd9Sstevel@tonic-gate  *
47c478bd9Sstevel@tonic-gate  * The contents of this file are subject to the terms of the
57c478bd9Sstevel@tonic-gate  * Common Development and Distribution License, Version 1.0 only
67c478bd9Sstevel@tonic-gate  * (the "License").  You may not use this file except in compliance
77c478bd9Sstevel@tonic-gate  * with the License.
87c478bd9Sstevel@tonic-gate  *
97c478bd9Sstevel@tonic-gate  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
107c478bd9Sstevel@tonic-gate  * or http://www.opensolaris.org/os/licensing.
117c478bd9Sstevel@tonic-gate  * See the License for the specific language governing permissions
127c478bd9Sstevel@tonic-gate  * and limitations under the License.
137c478bd9Sstevel@tonic-gate  *
147c478bd9Sstevel@tonic-gate  * When distributing Covered Code, include this CDDL HEADER in each
157c478bd9Sstevel@tonic-gate  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
167c478bd9Sstevel@tonic-gate  * If applicable, add the following below this CDDL HEADER, with the
177c478bd9Sstevel@tonic-gate  * fields enclosed by brackets "[]" replaced with your own identifying
187c478bd9Sstevel@tonic-gate  * information: Portions Copyright [yyyy] [name of copyright owner]
197c478bd9Sstevel@tonic-gate  *
207c478bd9Sstevel@tonic-gate  * CDDL HEADER END
217c478bd9Sstevel@tonic-gate  */
22113f4232Sakaplan 
23113f4232Sakaplan /*
24113f4232Sakaplan  * Copyright 2005 Sun Microsystems, Inc.  All rights reserved.
25113f4232Sakaplan  * Use is subject to license terms.
26113f4232Sakaplan  */
27113f4232Sakaplan 
287c478bd9Sstevel@tonic-gate /*	Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T	*/
297c478bd9Sstevel@tonic-gate /*	  All Rights Reserved  	*/
307c478bd9Sstevel@tonic-gate 
317c478bd9Sstevel@tonic-gate /*
327c478bd9Sstevel@tonic-gate 	stoa - convert string to address
337c478bd9Sstevel@tonic-gate 
347c478bd9Sstevel@tonic-gate 	If a string begins in \o or \O, the following address is octal
357c478bd9Sstevel@tonic-gate 	"  "   "       "    " \x or \X, the following address is hex
367c478bd9Sstevel@tonic-gate 	Otherwise, a string is considered text. Text may be quoted
377c478bd9Sstevel@tonic-gate 	with double quotes and the C-like escapes \n, \b, \t, \v, \r, and \nnn
387c478bd9Sstevel@tonic-gate 	(nnn = octal char) are recognized.
397c478bd9Sstevel@tonic-gate 	A \ followed by a newline causes the newline
407c478bd9Sstevel@tonic-gate 	to vanish. A \ followed by any other char causes any "magic" of
417c478bd9Sstevel@tonic-gate 	any other char to disappear.
427c478bd9Sstevel@tonic-gate 
437c478bd9Sstevel@tonic-gate 	Other escape sequences recognized are:
447c478bd9Sstevel@tonic-gate 		\!cmd args [ \! || EOL ]
457c478bd9Sstevel@tonic-gate 	which is replaced by the raw output of the execution of cmd.
467c478bd9Sstevel@tonic-gate 	This may only be used in a string.
477c478bd9Sstevel@tonic-gate 
487c478bd9Sstevel@tonic-gate 		\$cmd args [ \$ || EOL ]
497c478bd9Sstevel@tonic-gate 	which is replaced by the output of the execution of cmd and
507c478bd9Sstevel@tonic-gate 	is then reprocessed.
517c478bd9Sstevel@tonic-gate 
527c478bd9Sstevel@tonic-gate 	A  NULL is returned on any error(s).
537c478bd9Sstevel@tonic-gate */
547c478bd9Sstevel@tonic-gate 
557c478bd9Sstevel@tonic-gate #include <stdio.h>
567c478bd9Sstevel@tonic-gate #include <memory.h>
577c478bd9Sstevel@tonic-gate #include <ctype.h>
587c478bd9Sstevel@tonic-gate #include "nsaddr.h"
597c478bd9Sstevel@tonic-gate 
607c478bd9Sstevel@tonic-gate 
617c478bd9Sstevel@tonic-gate #define	toupper(c)	(islower(c) ? _toupper(c) : (c))
627c478bd9Sstevel@tonic-gate #define	todigit(c)	((int)((c) - '0'))	/* char to digit */
637c478bd9Sstevel@tonic-gate #define	toxdigit(c)	((isdigit(c))?todigit(c):(toupper(c)-(int)'A'+10))
647c478bd9Sstevel@tonic-gate #define	isodigit(c)	(isdigit(c) && ((c) != '9') && ((c) != '8'))
657c478bd9Sstevel@tonic-gate #define	itoac(i)	(((i) > 9) ? ((char)((i)-10) + 'A'):((char)(i) + '0'))
667c478bd9Sstevel@tonic-gate #define	MASK(n)		((1 << (n)) - 1)
677c478bd9Sstevel@tonic-gate 
687c478bd9Sstevel@tonic-gate #define	MAXRLEVEL	10	/* maximum recursion level */
697c478bd9Sstevel@tonic-gate 
707c478bd9Sstevel@tonic-gate #define	TRUE	1;
717c478bd9Sstevel@tonic-gate #define	FALSE	0;
727c478bd9Sstevel@tonic-gate 
737c478bd9Sstevel@tonic-gate char	scanbuf[SBUFSIZE];
747c478bd9Sstevel@tonic-gate int	sbp = 0;
757c478bd9Sstevel@tonic-gate int	rec = 0;	/* Recursion level */
767c478bd9Sstevel@tonic-gate 
777c478bd9Sstevel@tonic-gate char	sbuf[SBUFSIZE];
787c478bd9Sstevel@tonic-gate 
797c478bd9Sstevel@tonic-gate extern void free();
807c478bd9Sstevel@tonic-gate 
817c478bd9Sstevel@tonic-gate struct netbuf *
stoa(str,addr)827c478bd9Sstevel@tonic-gate stoa(str, addr)			/* Return 0 for success, -1 for error */
837c478bd9Sstevel@tonic-gate char	*str;
847c478bd9Sstevel@tonic-gate struct netbuf	*addr;
857c478bd9Sstevel@tonic-gate {
867c478bd9Sstevel@tonic-gate 	char	*xfer(), *prescan();
877c478bd9Sstevel@tonic-gate 
887c478bd9Sstevel@tonic-gate 	int	myadr;		/* was netbuf struct allocated here ? */
897c478bd9Sstevel@tonic-gate 	int	quote;		/* quoted string ? */
907c478bd9Sstevel@tonic-gate 
917c478bd9Sstevel@tonic-gate 	myadr = FALSE;
927c478bd9Sstevel@tonic-gate 
937c478bd9Sstevel@tonic-gate 	if (!str)
947c478bd9Sstevel@tonic-gate 		return NULL;
957c478bd9Sstevel@tonic-gate 	while (*str && isspace(*str))	/* leading whites are OK */
967c478bd9Sstevel@tonic-gate 		++str;
977c478bd9Sstevel@tonic-gate 
987c478bd9Sstevel@tonic-gate 	str = prescan(str);		/* Do all \$ ... \$ */
997c478bd9Sstevel@tonic-gate 
1007c478bd9Sstevel@tonic-gate 	if (!str || !*str) return NULL;		/* Nothing to convert */
1017c478bd9Sstevel@tonic-gate 
1027c478bd9Sstevel@tonic-gate 	if (!addr) {
1037c478bd9Sstevel@tonic-gate 		if ((addr = (struct netbuf *)malloc(sizeof(struct netbuf))) == NULL)
1047c478bd9Sstevel@tonic-gate 			return NULL;
1057c478bd9Sstevel@tonic-gate 		myadr = TRUE;
1067c478bd9Sstevel@tonic-gate 		addr->buf = NULL;
1077c478bd9Sstevel@tonic-gate 		addr->maxlen = 0;
1087c478bd9Sstevel@tonic-gate 		addr->len = 0;
1097c478bd9Sstevel@tonic-gate 	}
1107c478bd9Sstevel@tonic-gate 
1117c478bd9Sstevel@tonic-gate 	/* Now process the address */
1127c478bd9Sstevel@tonic-gate 	quote = 0;
1137c478bd9Sstevel@tonic-gate 
1147c478bd9Sstevel@tonic-gate 	if (*str == '\\') {
1157c478bd9Sstevel@tonic-gate 		++str;
1167c478bd9Sstevel@tonic-gate 		switch (*str) {
1177c478bd9Sstevel@tonic-gate 
1187c478bd9Sstevel@tonic-gate 		case 'X':	/* hex */
1197c478bd9Sstevel@tonic-gate 		case 'x':
1207c478bd9Sstevel@tonic-gate 			addr->len = dobase(++str, sbuf, HEX);
1217c478bd9Sstevel@tonic-gate 			break;
1227c478bd9Sstevel@tonic-gate 
1237c478bd9Sstevel@tonic-gate 		case 'o':	/* octal */
1247c478bd9Sstevel@tonic-gate 		case 'O':
1257c478bd9Sstevel@tonic-gate 			addr->len = dobase(++str, sbuf, OCT);
1267c478bd9Sstevel@tonic-gate 			break;
1277c478bd9Sstevel@tonic-gate 
1287c478bd9Sstevel@tonic-gate 		case '\0':	/* No address given!, length is 0 */
1297c478bd9Sstevel@tonic-gate 			addr->len = dostring(str, sbuf, 0);
1307c478bd9Sstevel@tonic-gate 			break;
1317c478bd9Sstevel@tonic-gate 
1327c478bd9Sstevel@tonic-gate 		default:	/* \ is handled by dostring */
1337c478bd9Sstevel@tonic-gate 			addr->len = dostring(--str, sbuf, quote);
1347c478bd9Sstevel@tonic-gate 			break;
1357c478bd9Sstevel@tonic-gate 		}
1367c478bd9Sstevel@tonic-gate 	}
1377c478bd9Sstevel@tonic-gate 	else {
1387c478bd9Sstevel@tonic-gate 		if (*str == '"') {	/* quoted string */
1397c478bd9Sstevel@tonic-gate 			quote = 1;
1407c478bd9Sstevel@tonic-gate 			++str;
1417c478bd9Sstevel@tonic-gate 		}
1427c478bd9Sstevel@tonic-gate 		addr->len = dostring(str, sbuf, quote);
1437c478bd9Sstevel@tonic-gate 	}
1447c478bd9Sstevel@tonic-gate 
1457c478bd9Sstevel@tonic-gate 	if (addr->len == 0) {	/* Error in conversion */
1467c478bd9Sstevel@tonic-gate 		if (myadr)
1477c478bd9Sstevel@tonic-gate 			free(addr);
1487c478bd9Sstevel@tonic-gate 		return NULL;
1497c478bd9Sstevel@tonic-gate 	}
1507c478bd9Sstevel@tonic-gate 	if ((addr->buf = xfer(addr->buf, sbuf, addr->len, addr->maxlen)) == NULL)
1517c478bd9Sstevel@tonic-gate 		return NULL;
1527c478bd9Sstevel@tonic-gate 	else
1537c478bd9Sstevel@tonic-gate 		return addr;
1547c478bd9Sstevel@tonic-gate }
1557c478bd9Sstevel@tonic-gate 
1567c478bd9Sstevel@tonic-gate 
1577c478bd9Sstevel@tonic-gate /*
1587c478bd9Sstevel@tonic-gate 	dostring:	Copy string at s to buf translating
1597c478bd9Sstevel@tonic-gate 		escaped characters and shell escapes.
1607c478bd9Sstevel@tonic-gate 	return length of string.
1617c478bd9Sstevel@tonic-gate */
1627c478bd9Sstevel@tonic-gate 
1637c478bd9Sstevel@tonic-gate int
dostring(s,buf,quote)1647c478bd9Sstevel@tonic-gate dostring(s, buf, quote)		/* read in a raw address */
1657c478bd9Sstevel@tonic-gate char	*s, *buf;
1667c478bd9Sstevel@tonic-gate int	quote;
1677c478bd9Sstevel@tonic-gate {
1687c478bd9Sstevel@tonic-gate 	char	*xcmd();
1697c478bd9Sstevel@tonic-gate 
1707c478bd9Sstevel@tonic-gate 	int	oc, ch, len = 0;
1717c478bd9Sstevel@tonic-gate 	int	l = 0;
1727c478bd9Sstevel@tonic-gate 	char	*rout;
1737c478bd9Sstevel@tonic-gate 
1747c478bd9Sstevel@tonic-gate 	while (*s) {
1757c478bd9Sstevel@tonic-gate 		if (len >= SBUFSIZE) {
1767c478bd9Sstevel@tonic-gate 			fprintf(stderr, "dostring: string too long\n");
1777c478bd9Sstevel@tonic-gate 			break;
1787c478bd9Sstevel@tonic-gate 		}
1797c478bd9Sstevel@tonic-gate 		else if (*s == '\\')
1807c478bd9Sstevel@tonic-gate 			switch(*++s) {
1817c478bd9Sstevel@tonic-gate 
1827c478bd9Sstevel@tonic-gate 			case '!':	/* raw shell escape */
1837c478bd9Sstevel@tonic-gate 				if (rout = xcmd(s+1, '!', &s, &l)) {
1847c478bd9Sstevel@tonic-gate 					if (len + l < SBUFSIZE)
1857c478bd9Sstevel@tonic-gate 						memcpy(buf+len, rout, l);
1867c478bd9Sstevel@tonic-gate 					len += l;
1877c478bd9Sstevel@tonic-gate 					free(rout);
1887c478bd9Sstevel@tonic-gate 				}
1897c478bd9Sstevel@tonic-gate 				break;
1907c478bd9Sstevel@tonic-gate 
1917c478bd9Sstevel@tonic-gate 			case '\n':	/* ignore newline */
1927c478bd9Sstevel@tonic-gate 				++s;
1937c478bd9Sstevel@tonic-gate 				break;
1947c478bd9Sstevel@tonic-gate 
1957c478bd9Sstevel@tonic-gate 			case 'b':	/* backspace */
1967c478bd9Sstevel@tonic-gate 				buf[len++] = '\b'; s++;
1977c478bd9Sstevel@tonic-gate 				break;
1987c478bd9Sstevel@tonic-gate 
1997c478bd9Sstevel@tonic-gate 			case 'n':	/* newline */
2007c478bd9Sstevel@tonic-gate 				buf[len++] = '\n'; s++;
2017c478bd9Sstevel@tonic-gate 				break;
2027c478bd9Sstevel@tonic-gate 
2037c478bd9Sstevel@tonic-gate 			case 'r':	/* return */
2047c478bd9Sstevel@tonic-gate 				buf[len++] = '\r'; s++;
2057c478bd9Sstevel@tonic-gate 				break;
2067c478bd9Sstevel@tonic-gate 
2077c478bd9Sstevel@tonic-gate 			case 't':	/* horiz. tab */
2087c478bd9Sstevel@tonic-gate 				buf[len++] = '\t'; s++;
2097c478bd9Sstevel@tonic-gate 				break;
2107c478bd9Sstevel@tonic-gate 
2117c478bd9Sstevel@tonic-gate 			case 'v':	/* vert. tab */
2127c478bd9Sstevel@tonic-gate 				buf[len++] = '\v'; s++;
213*25b601caSToomas Soome 				/* FALLTHROUGH */
2147c478bd9Sstevel@tonic-gate 
2157c478bd9Sstevel@tonic-gate 			case '0':
2167c478bd9Sstevel@tonic-gate 			case '1':
2177c478bd9Sstevel@tonic-gate 			case '2':
2187c478bd9Sstevel@tonic-gate 			case '3':
2197c478bd9Sstevel@tonic-gate 				for(oc=ch=0; (*s >= '0' && *s <= '7') && oc++ < 3; ++s)
2207c478bd9Sstevel@tonic-gate 					ch = (ch << 3) | (*s - '0');
2217c478bd9Sstevel@tonic-gate 				buf[len++] = ch;
2227c478bd9Sstevel@tonic-gate 				break;
2237c478bd9Sstevel@tonic-gate 
2247c478bd9Sstevel@tonic-gate 			case 0:		/* end of string -- terminate */
2257c478bd9Sstevel@tonic-gate 				break;
2267c478bd9Sstevel@tonic-gate 
2277c478bd9Sstevel@tonic-gate 			default:	/* take the character blindly */
2287c478bd9Sstevel@tonic-gate 				buf[len++] = *s++;
2297c478bd9Sstevel@tonic-gate 				break;
2307c478bd9Sstevel@tonic-gate 			}
2317c478bd9Sstevel@tonic-gate 		else if ((quote && (*s == '"')) || (!quote && isspace(*s)))
2327c478bd9Sstevel@tonic-gate 			break;
2337c478bd9Sstevel@tonic-gate 
2347c478bd9Sstevel@tonic-gate 		else
2357c478bd9Sstevel@tonic-gate 			buf[len++] = *s++;
2367c478bd9Sstevel@tonic-gate 	}
2377c478bd9Sstevel@tonic-gate 	return (len >= SBUFSIZE) ? 0 : len;
2387c478bd9Sstevel@tonic-gate }
2397c478bd9Sstevel@tonic-gate 
2407c478bd9Sstevel@tonic-gate 
2417c478bd9Sstevel@tonic-gate /*
2427c478bd9Sstevel@tonic-gate 	dobase :	converts a hex or octal ASCII string
2437c478bd9Sstevel@tonic-gate 		to a binary address. Only HEX or OCT may be used
2447c478bd9Sstevel@tonic-gate 		for type.
2457c478bd9Sstevel@tonic-gate 	return length of binary string (in bytes), 0 if error.
2467c478bd9Sstevel@tonic-gate 	The binary result is placed at buf.
2477c478bd9Sstevel@tonic-gate */
2487c478bd9Sstevel@tonic-gate 
2497c478bd9Sstevel@tonic-gate int
dobase(s,buf,type)2507c478bd9Sstevel@tonic-gate dobase(s, buf, type)	/* read in an address */
2517c478bd9Sstevel@tonic-gate char	*s, *buf;	/* source ASCII, result binary string */
2527c478bd9Sstevel@tonic-gate int	type;
2537c478bd9Sstevel@tonic-gate {
2547c478bd9Sstevel@tonic-gate 	void	memcp();
2557c478bd9Sstevel@tonic-gate 	int	bp = SBUFSIZE - 1;
2567c478bd9Sstevel@tonic-gate 	int	shift = 0;
2577c478bd9Sstevel@tonic-gate 	char	*end;
2587c478bd9Sstevel@tonic-gate 
2597c478bd9Sstevel@tonic-gate 	for (end = s; *end && ((type == OCT) ? isodigit(*end) :
2607c478bd9Sstevel@tonic-gate 		isxdigit(*end)); ++end) ;
2617c478bd9Sstevel@tonic-gate 
2627c478bd9Sstevel@tonic-gate 	/* any non-white, non-digits cause address to be rejected,
2637c478bd9Sstevel@tonic-gate 	   other fields are ignored */
2647c478bd9Sstevel@tonic-gate 
2657c478bd9Sstevel@tonic-gate 	if ((*s == 0) || (end == s) || (!isspace(*end) && *end)) {
2667c478bd9Sstevel@tonic-gate 		fprintf(stderr, "dobase: Illegal trailer on address string\n");
2677c478bd9Sstevel@tonic-gate 		buf[0] = '\0';
2687c478bd9Sstevel@tonic-gate 		return 0;
2697c478bd9Sstevel@tonic-gate 	}
2707c478bd9Sstevel@tonic-gate 	--end;
2717c478bd9Sstevel@tonic-gate 
2727c478bd9Sstevel@tonic-gate 	buf[bp] = '\0';
2737c478bd9Sstevel@tonic-gate 
2747c478bd9Sstevel@tonic-gate 	while (bp > 0 && end >= s) {
2757c478bd9Sstevel@tonic-gate 		buf[bp] |= toxdigit(*end) << shift;
2767c478bd9Sstevel@tonic-gate 		if (type == OCT) {
2777c478bd9Sstevel@tonic-gate 			if (shift > 5) {
2787c478bd9Sstevel@tonic-gate 				buf[--bp] = (todigit(*end) >> (8 - shift))
2797c478bd9Sstevel@tonic-gate 					& MASK(shift-5);
2807c478bd9Sstevel@tonic-gate 			}
2817c478bd9Sstevel@tonic-gate 			if ((shift = (shift + 3) % 8) == 0)
2827c478bd9Sstevel@tonic-gate 				buf[--bp] = 0;
2837c478bd9Sstevel@tonic-gate 		}
2847c478bd9Sstevel@tonic-gate 		else	/* hex */
2857c478bd9Sstevel@tonic-gate 			if ((shift = (shift) ? 0 : 4) == 0)
2867c478bd9Sstevel@tonic-gate 				buf[--bp] = 0;;
2877c478bd9Sstevel@tonic-gate 		--end;
2887c478bd9Sstevel@tonic-gate 	}
2897c478bd9Sstevel@tonic-gate 	if (bp == 0) {
2907c478bd9Sstevel@tonic-gate 		fprintf(stderr, "stoa: dobase: number to long\n");
2917c478bd9Sstevel@tonic-gate 		return 0;
2927c478bd9Sstevel@tonic-gate 	}
2937c478bd9Sstevel@tonic-gate 
2947c478bd9Sstevel@tonic-gate 	/* need to catch end case to avoid extra 0's in front	*/
2957c478bd9Sstevel@tonic-gate 	if (!shift)
2967c478bd9Sstevel@tonic-gate 		bp++;
2977c478bd9Sstevel@tonic-gate 	memcp(buf, &buf[bp], (SBUFSIZE - bp));
2987c478bd9Sstevel@tonic-gate 	return (SBUFSIZE - bp);
2997c478bd9Sstevel@tonic-gate }
3007c478bd9Sstevel@tonic-gate 
3017c478bd9Sstevel@tonic-gate #ifdef NOTUSED
3027c478bd9Sstevel@tonic-gate 
3037c478bd9Sstevel@tonic-gate 
3047c478bd9Sstevel@tonic-gate /*
3057c478bd9Sstevel@tonic-gate 
3067c478bd9Sstevel@tonic-gate 	atos(str, addr, type)
3077c478bd9Sstevel@tonic-gate 
3087c478bd9Sstevel@tonic-gate 	convert address to ASCII form with address in hex, octal,
3097c478bd9Sstevel@tonic-gate 	or character form.
3107c478bd9Sstevel@tonic-gate 	return pointer to buffer (NULL on failure).
3117c478bd9Sstevel@tonic-gate */
3127c478bd9Sstevel@tonic-gate 
3137c478bd9Sstevel@tonic-gate 
3147c478bd9Sstevel@tonic-gate char *
atos(str,addr,type)3157c478bd9Sstevel@tonic-gate atos(str, addr, type)
3167c478bd9Sstevel@tonic-gate char	*str;
3177c478bd9Sstevel@tonic-gate struct netbuf	*addr;
3187c478bd9Sstevel@tonic-gate int	type;
3197c478bd9Sstevel@tonic-gate {
3207c478bd9Sstevel@tonic-gate 	char	*xfer();
3217c478bd9Sstevel@tonic-gate 	int	mystr = 0;	/* was str allocated here ? */
3227c478bd9Sstevel@tonic-gate 	unsigned	x_atos(), o_atos();
3237c478bd9Sstevel@tonic-gate 	void	memcp();
3247c478bd9Sstevel@tonic-gate 
3257c478bd9Sstevel@tonic-gate 	char	*base;
3267c478bd9Sstevel@tonic-gate 
3277c478bd9Sstevel@tonic-gate 	if (addr == NULL)
3287c478bd9Sstevel@tonic-gate 		return NULL;
3297c478bd9Sstevel@tonic-gate 
3307c478bd9Sstevel@tonic-gate 	if (str == NULL)
3317c478bd9Sstevel@tonic-gate 		if ((str = malloc(SBUFSIZE)) == NULL)
3327c478bd9Sstevel@tonic-gate 			return NULL;
3337c478bd9Sstevel@tonic-gate 		else
3347c478bd9Sstevel@tonic-gate 			mystr = 1;
3357c478bd9Sstevel@tonic-gate 
3367c478bd9Sstevel@tonic-gate 	switch (type) {
3377c478bd9Sstevel@tonic-gate 
3387c478bd9Sstevel@tonic-gate 	case OCT:
3397c478bd9Sstevel@tonic-gate 		/* first add \o */
3407c478bd9Sstevel@tonic-gate 		sbuf[0] = '\\';
3417c478bd9Sstevel@tonic-gate 		sbuf[1] = 'o';
3427c478bd9Sstevel@tonic-gate 
3437c478bd9Sstevel@tonic-gate 		return xfer(str, sbuf, o_atos(sbuf+2, addr->buf, addr->len) + 2,
3447c478bd9Sstevel@tonic-gate 			mystr ? SBUFSIZE : 0);
3457c478bd9Sstevel@tonic-gate 
3467c478bd9Sstevel@tonic-gate 	case HEX:
3477c478bd9Sstevel@tonic-gate 		/* first add \x */
3487c478bd9Sstevel@tonic-gate 		sbuf[0] = '\\';
3497c478bd9Sstevel@tonic-gate 		sbuf[1] = 'x';
3507c478bd9Sstevel@tonic-gate 
3517c478bd9Sstevel@tonic-gate 		return xfer(str, sbuf, x_atos(sbuf+2, addr->buf, addr->len) + 2,
3527c478bd9Sstevel@tonic-gate 			mystr ? SBUFSIZE : 0);
3537c478bd9Sstevel@tonic-gate 
3547c478bd9Sstevel@tonic-gate 	case RAW:
3557c478bd9Sstevel@tonic-gate 		base = xfer(str, addr->buf,
3567c478bd9Sstevel@tonic-gate 			 addr->len + 1, mystr ? SBUFSIZE : 0);
3577c478bd9Sstevel@tonic-gate 		if (base)
3587c478bd9Sstevel@tonic-gate 			base[addr->len] = '\0';	/* terminate*/
3597c478bd9Sstevel@tonic-gate 		return base;
3607c478bd9Sstevel@tonic-gate 
3617c478bd9Sstevel@tonic-gate 	default:
3627c478bd9Sstevel@tonic-gate 		return NULL;
3637c478bd9Sstevel@tonic-gate 	}
3647c478bd9Sstevel@tonic-gate }
3657c478bd9Sstevel@tonic-gate 
3667c478bd9Sstevel@tonic-gate 
3677c478bd9Sstevel@tonic-gate /*
3687c478bd9Sstevel@tonic-gate 	x_atos, o_atos
3697c478bd9Sstevel@tonic-gate 	return the number of bytes occupied by string + NULL*/
3707c478bd9Sstevel@tonic-gate 
3717c478bd9Sstevel@tonic-gate /*
3727c478bd9Sstevel@tonic-gate 	x_atos :	convert an address string a, length s
3737c478bd9Sstevel@tonic-gate 		to hex ASCII in s */
3747c478bd9Sstevel@tonic-gate 
3757c478bd9Sstevel@tonic-gate 
3767c478bd9Sstevel@tonic-gate unsigned
x_atos(s,a,l)3777c478bd9Sstevel@tonic-gate x_atos(s, a, l)
3787c478bd9Sstevel@tonic-gate char	*s, *a;
3797c478bd9Sstevel@tonic-gate unsigned	l;
3807c478bd9Sstevel@tonic-gate {
3817c478bd9Sstevel@tonic-gate 	char	*b;
3827c478bd9Sstevel@tonic-gate 
3837c478bd9Sstevel@tonic-gate 	b = s;
3847c478bd9Sstevel@tonic-gate 	while (l--) {
3857c478bd9Sstevel@tonic-gate 		*s++ = itoac(((*a >> 4) & MASK (4)));
3867c478bd9Sstevel@tonic-gate 		*s++ = itoac((*a & MASK(4)));
3877c478bd9Sstevel@tonic-gate 		++a;
3887c478bd9Sstevel@tonic-gate 	}
3897c478bd9Sstevel@tonic-gate 	*s = '\0';
3907c478bd9Sstevel@tonic-gate 	return (s - b + 1);
3917c478bd9Sstevel@tonic-gate }
3927c478bd9Sstevel@tonic-gate 
3937c478bd9Sstevel@tonic-gate 
3947c478bd9Sstevel@tonic-gate /*
3957c478bd9Sstevel@tonic-gate 	o_atos :	convert an address a, length l
3967c478bd9Sstevel@tonic-gate 		to octal ASCII in s   */
3977c478bd9Sstevel@tonic-gate 
3987c478bd9Sstevel@tonic-gate 
3997c478bd9Sstevel@tonic-gate unsigned
o_atos(s,a,l)4007c478bd9Sstevel@tonic-gate o_atos(s, a, l)
4017c478bd9Sstevel@tonic-gate char	*s, *a;
4027c478bd9Sstevel@tonic-gate unsigned	l;
4037c478bd9Sstevel@tonic-gate {
4047c478bd9Sstevel@tonic-gate 	int	i, shift;
4057c478bd9Sstevel@tonic-gate 	char	*b;
4067c478bd9Sstevel@tonic-gate 
4077c478bd9Sstevel@tonic-gate 	b = s;
4087c478bd9Sstevel@tonic-gate 	if (l == 0) {
4097c478bd9Sstevel@tonic-gate 		*s = '\0';
4107c478bd9Sstevel@tonic-gate 		return 0;
4117c478bd9Sstevel@tonic-gate 	}
4127c478bd9Sstevel@tonic-gate 
4137c478bd9Sstevel@tonic-gate 	/* take care of partial bits and set shift factor for next 3  */
4147c478bd9Sstevel@tonic-gate 
4157c478bd9Sstevel@tonic-gate 	i = l % 3;
4167c478bd9Sstevel@tonic-gate 	*s++ = itoac((*a>>(i+5)) & MASK(3-i));
4177c478bd9Sstevel@tonic-gate 	shift = 2 + i;
4187c478bd9Sstevel@tonic-gate 
4197c478bd9Sstevel@tonic-gate 	while (l)
4207c478bd9Sstevel@tonic-gate 		if (shift <= 5) {
4217c478bd9Sstevel@tonic-gate 			*s++ = itoac((*a >> shift) & MASK(3));
4227c478bd9Sstevel@tonic-gate 			if (shift == 0) {
4237c478bd9Sstevel@tonic-gate 				++a;
4247c478bd9Sstevel@tonic-gate 				--l;
4257c478bd9Sstevel@tonic-gate 			}
4267c478bd9Sstevel@tonic-gate 			shift += (shift < 3) ? 5 : -3;
4277c478bd9Sstevel@tonic-gate 		}
4287c478bd9Sstevel@tonic-gate 		else {
4297c478bd9Sstevel@tonic-gate 			i = (*a & MASK(shift-5)) << (8-shift);
4307c478bd9Sstevel@tonic-gate 			i |= (*++a >> shift) & MASK(8-shift);
4317c478bd9Sstevel@tonic-gate 			*s++ = itoac(i);
4327c478bd9Sstevel@tonic-gate 			shift -= 3;
4337c478bd9Sstevel@tonic-gate 			--l;
4347c478bd9Sstevel@tonic-gate 		}
4357c478bd9Sstevel@tonic-gate 	*s++ = '\0';
4367c478bd9Sstevel@tonic-gate 	return (s - b + 1);
4377c478bd9Sstevel@tonic-gate }
4387c478bd9Sstevel@tonic-gate 
4397c478bd9Sstevel@tonic-gate #endif /* NOTUSED */
4407c478bd9Sstevel@tonic-gate 
4417c478bd9Sstevel@tonic-gate void
memcp(d,s,n)4427c478bd9Sstevel@tonic-gate memcp(d, s, n)	/* safe memcpy for overlapping regions */
4437c478bd9Sstevel@tonic-gate char	*d, *s;
4447c478bd9Sstevel@tonic-gate int	n;
4457c478bd9Sstevel@tonic-gate {
4467c478bd9Sstevel@tonic-gate 	while (n--)
4477c478bd9Sstevel@tonic-gate 		*d++ = *s++;
4487c478bd9Sstevel@tonic-gate }
4497c478bd9Sstevel@tonic-gate 
4507c478bd9Sstevel@tonic-gate 
4517c478bd9Sstevel@tonic-gate /* transfer block to a given destination or allocate one of the
4527c478bd9Sstevel@tonic-gate     right size
4537c478bd9Sstevel@tonic-gate     if max = 0 : ignore max
4547c478bd9Sstevel@tonic-gate */
4557c478bd9Sstevel@tonic-gate 
4567c478bd9Sstevel@tonic-gate char *
xfer(dest,src,len,max)4577c478bd9Sstevel@tonic-gate xfer(dest, src, len, max)
4587c478bd9Sstevel@tonic-gate char	*dest, *src;
4597c478bd9Sstevel@tonic-gate unsigned	len, max;
4607c478bd9Sstevel@tonic-gate {
4617c478bd9Sstevel@tonic-gate 	if (max && dest && max < len) {		/* No room */
4627c478bd9Sstevel@tonic-gate 		fprintf(stderr, "xfer: destination not long enough\n");
4637c478bd9Sstevel@tonic-gate 		return NULL;
4647c478bd9Sstevel@tonic-gate 	}
4657c478bd9Sstevel@tonic-gate 	if (!dest)
4667c478bd9Sstevel@tonic-gate 		if ((dest = (char *)malloc(len)) == NULL) {
4677c478bd9Sstevel@tonic-gate 			fprintf(stderr, "xfer: malloc failed\n");
4687c478bd9Sstevel@tonic-gate 			return NULL;
4697c478bd9Sstevel@tonic-gate 		}
4707c478bd9Sstevel@tonic-gate 
4717c478bd9Sstevel@tonic-gate 	memcpy(dest, src, (int)len);
4727c478bd9Sstevel@tonic-gate 	return dest;
4737c478bd9Sstevel@tonic-gate }
4747c478bd9Sstevel@tonic-gate 
4757c478bd9Sstevel@tonic-gate /*
4767c478bd9Sstevel@tonic-gate 	prescan:	scan through string s, expanding all \$...\$
4777c478bd9Sstevel@tonic-gate 		as shell escapes.
4787c478bd9Sstevel@tonic-gate 	Return pointer to string of expanded text.
4797c478bd9Sstevel@tonic-gate */
4807c478bd9Sstevel@tonic-gate 
4817c478bd9Sstevel@tonic-gate char *
prescan(s)4827c478bd9Sstevel@tonic-gate prescan(s)
4837c478bd9Sstevel@tonic-gate char	*s;
4847c478bd9Sstevel@tonic-gate {
4857c478bd9Sstevel@tonic-gate 	int	scan();
4867c478bd9Sstevel@tonic-gate 
4877c478bd9Sstevel@tonic-gate 	rec = sbp = 0;
4887c478bd9Sstevel@tonic-gate 	if (!s || !*s || !scan(s))
4897c478bd9Sstevel@tonic-gate 		return NULL;
4907c478bd9Sstevel@tonic-gate 	scanbuf[sbp] = '\0';
4917c478bd9Sstevel@tonic-gate 	return scanbuf;
4927c478bd9Sstevel@tonic-gate }
4937c478bd9Sstevel@tonic-gate 
4947c478bd9Sstevel@tonic-gate 
4957c478bd9Sstevel@tonic-gate /*
4967c478bd9Sstevel@tonic-gate 	scan:	scan through string s, expanding all \$...\$.
4977c478bd9Sstevel@tonic-gate 	(Part II of prescan)
4987c478bd9Sstevel@tonic-gate 	Return 0 if anything failed, else 1.
4997c478bd9Sstevel@tonic-gate */
5007c478bd9Sstevel@tonic-gate 
501113f4232Sakaplan int
scan(s)5027c478bd9Sstevel@tonic-gate scan(s)
5037c478bd9Sstevel@tonic-gate char	*s;
5047c478bd9Sstevel@tonic-gate {
5057c478bd9Sstevel@tonic-gate 	char	*xcmd();
5067c478bd9Sstevel@tonic-gate 	char	*cmd;
5077c478bd9Sstevel@tonic-gate 	int	len;
5087c478bd9Sstevel@tonic-gate 	int	esc = 0;		/* Keep lookout for \\$ */
5097c478bd9Sstevel@tonic-gate 
5107c478bd9Sstevel@tonic-gate 	while (*s) {
5117c478bd9Sstevel@tonic-gate 		if (!esc && (*s == '\\' && *(s+1) == '$')) {
5127c478bd9Sstevel@tonic-gate 			if (rec++ == MAXRLEVEL) {
5137c478bd9Sstevel@tonic-gate 				fprintf(stderr, "scan: Recursion \
5147c478bd9Sstevel@tonic-gate level past %d on shell escape\n", rec);
5157c478bd9Sstevel@tonic-gate 				return 0;
5167c478bd9Sstevel@tonic-gate 			}
5177c478bd9Sstevel@tonic-gate 			if ((cmd = xcmd(s+2, '$', &s, &len)) != NULL) {
5187c478bd9Sstevel@tonic-gate 				cmd[len] = '\0';
5197c478bd9Sstevel@tonic-gate  				if (*cmd != '\0')
5207c478bd9Sstevel@tonic-gate 					scan(cmd);
5217c478bd9Sstevel@tonic-gate 				free(cmd);
5227c478bd9Sstevel@tonic-gate 			}
5237c478bd9Sstevel@tonic-gate 			else
5247c478bd9Sstevel@tonic-gate 				return 0;
5257c478bd9Sstevel@tonic-gate 		}
5267c478bd9Sstevel@tonic-gate 
5277c478bd9Sstevel@tonic-gate 		else if (sbp == SBUFSIZE) {
5287c478bd9Sstevel@tonic-gate 			fprintf(stderr, "Overflow on shell esc expansion\n");
5297c478bd9Sstevel@tonic-gate 			return 0;
5307c478bd9Sstevel@tonic-gate 		}
5317c478bd9Sstevel@tonic-gate 		else if (sbp < SBUFSIZE)
5327c478bd9Sstevel@tonic-gate 			esc = ((scanbuf[sbp++] = *s++) == '\\');
5337c478bd9Sstevel@tonic-gate 	}
5347c478bd9Sstevel@tonic-gate 	return 1;
5357c478bd9Sstevel@tonic-gate }
5367c478bd9Sstevel@tonic-gate 
5377c478bd9Sstevel@tonic-gate 
5387c478bd9Sstevel@tonic-gate /*
5397c478bd9Sstevel@tonic-gate 	xcmd :	extract command line for shell escape and execute it
5407c478bd9Sstevel@tonic-gate 		return pointer to output of command
5417c478bd9Sstevel@tonic-gate */
5427c478bd9Sstevel@tonic-gate 
5437c478bd9Sstevel@tonic-gate char *
xcmd(s,ec,ps,len)5447c478bd9Sstevel@tonic-gate xcmd(s, ec, ps, len)
5457c478bd9Sstevel@tonic-gate char	*s;		/* input string */
5467c478bd9Sstevel@tonic-gate char	ec;		/* escape char ( $ or ! ) */
5477c478bd9Sstevel@tonic-gate char	**ps;		/* address of input string pointer */
5487c478bd9Sstevel@tonic-gate int	*len;		/* Number of bytes of output from command */
5497c478bd9Sstevel@tonic-gate {
5507c478bd9Sstevel@tonic-gate 	FILE	*popen();
5517c478bd9Sstevel@tonic-gate 	int	pclose();
5527c478bd9Sstevel@tonic-gate 
5537c478bd9Sstevel@tonic-gate 	FILE	*pfp;		/* pipe for process */
5547c478bd9Sstevel@tonic-gate 	char	*cmd;		/* command buffer */
5557c478bd9Sstevel@tonic-gate 	char	*cmdp;		/* pointer along cmd */
5567c478bd9Sstevel@tonic-gate 	char	*ocmd;		/* output of command buffer */
5577c478bd9Sstevel@tonic-gate 	int	esc = 0;	/* escaped escape shell */
5587c478bd9Sstevel@tonic-gate 
5597c478bd9Sstevel@tonic-gate 	*len = 0;
5607c478bd9Sstevel@tonic-gate 
5617c478bd9Sstevel@tonic-gate 	if ((cmd = cmdp = (char *)malloc(SBUFSIZE)) == NULL) {
5627c478bd9Sstevel@tonic-gate 		fprintf(stderr, "xcmd: malloc failed\n");
5637c478bd9Sstevel@tonic-gate 		return NULL;
5647c478bd9Sstevel@tonic-gate 	}
5657c478bd9Sstevel@tonic-gate 
5667c478bd9Sstevel@tonic-gate 	if ((ocmd = (char *)malloc(SBUFSIZE)) == NULL) {
5677c478bd9Sstevel@tonic-gate 		fprintf(stderr, "xcmd: malloc failed\n");
5687c478bd9Sstevel@tonic-gate 		free(cmd);
5697c478bd9Sstevel@tonic-gate 		return NULL;
5707c478bd9Sstevel@tonic-gate 	}
5717c478bd9Sstevel@tonic-gate 	while (*s) {
5727c478bd9Sstevel@tonic-gate 		if (!esc && *s == '\\' && *(s+1) == ec) {
5737c478bd9Sstevel@tonic-gate 			s += 2;
5747c478bd9Sstevel@tonic-gate 			break;
5757c478bd9Sstevel@tonic-gate 		}
5767c478bd9Sstevel@tonic-gate 		else
5777c478bd9Sstevel@tonic-gate 			esc = (*cmdp++ = *s++) == '\\';
5787c478bd9Sstevel@tonic-gate 	}
5797c478bd9Sstevel@tonic-gate 	*cmdp = '\0';
5807c478bd9Sstevel@tonic-gate 	*ps = s;
5817c478bd9Sstevel@tonic-gate 
5827c478bd9Sstevel@tonic-gate 	if ((pfp = popen(cmd, "r")) == NULL)
5837c478bd9Sstevel@tonic-gate 		fprintf(stderr, "xcmd: popen failed\n");
5847c478bd9Sstevel@tonic-gate 	while (fread(&ocmd[*len], 1, 1, pfp))
5857c478bd9Sstevel@tonic-gate 		if ((*len += 1) >= SBUFSIZE) {
5867c478bd9Sstevel@tonic-gate 			fprintf(stderr, "xcmd: command output too long\n");
5877c478bd9Sstevel@tonic-gate 			break;
5887c478bd9Sstevel@tonic-gate 		}
5897c478bd9Sstevel@tonic-gate 	pclose(pfp);
5907c478bd9Sstevel@tonic-gate 	free(cmd);
5917c478bd9Sstevel@tonic-gate 
5927c478bd9Sstevel@tonic-gate 	return ocmd;
5937c478bd9Sstevel@tonic-gate }
594