1/*
2 * CDDL HEADER START
3 *
4 * The contents of this file are subject to the terms of the
5 * Common Development and Distribution License, Version 1.0 only
6 * (the "License").  You may not use this file except in compliance
7 * with the License.
8 *
9 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
10 * or http://www.opensolaris.org/os/licensing.
11 * See the License for the specific language governing permissions
12 * and limitations under the License.
13 *
14 * When distributing Covered Code, include this CDDL HEADER in each
15 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
16 * If applicable, add the following below this CDDL HEADER, with the
17 * fields enclosed by brackets "[]" replaced with your own identifying
18 * information: Portions Copyright [yyyy] [name of copyright owner]
19 *
20 * CDDL HEADER END
21 */
22
23/*
24 * Copyright 2006 Sun Microsystems, Inc.  All rights reserved.
25 * Use is subject to license terms.
26 */
27
28/*	Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T	*/
29/*	  All Rights Reserved  	*/
30
31#pragma ident	"%Z%%M%	%I%	%E% SMI"
32
33#include "mt.h"
34#include "uucp.h"
35
36#ifdef TLI
37
38#include <stdio.h>
39#include <string.h>
40#include <memory.h>
41#include <malloc.h>
42#include <sys/tiuser.h>
43#include <ctype.h>
44#define	OCT	0
45#define	HEX	1
46/*
47 * #include <nsaddr.h>
48 */
49#define	toupper(c)	(islower(c) ? _toupper(c) : (c))
50#define	todigit(c)	((int)((c) - '0'))	/* char to digit */
51#define	toxdigit(c)	((isdigit(c))?todigit(c):(toupper(c)-(int)'A'+10))
52#define	isodigit(c)	(isdigit(c) && ((c) != '9') && ((c) != '8'))
53#define	itoac(i)	(((i) > 9) ? ((char)((i)-10) + 'A'):((char)(i) + '0'))
54#define	MASK(n)		((1 << (n)) - 1)
55
56#define	SBUFSIZE	128
57
58/*
59 * #define	TRUE	1
60 * #define	FALSE	0
61 */
62
63/*	local static functions	*/
64static int dobase(char *, char *, int);
65static void memcp(char *, char *, int);
66static char *xfer(char *, char *, unsigned, unsigned);
67
68/*
69 *	stoa - convert string to address
70 *
71 *	If a string begins in \o or \O, the following address is octal
72 *	"  "   "       "    " \x or \X, the following address is hex
73 *
74 *	If ok, return pointer to netbuf structure.
75 *	A  NULL is returned on any error(s).
76 */
77
78/* Return netbuf ptr if success */
79static struct netbuf *
80stoa(char *str, struct netbuf *addr)
81{
82	int	myadr;		/* was netbuf struct allocated here ? */
83	static	char *sbuf;
84
85	myadr = FALSE;
86
87	if (!str)
88		return (NULL);
89	while (*str && isspace(*str))	/* leading whites are OK */
90		++str;
91
92	if (!str || !*str)	/* Nothing to convert */
93		return (NULL);
94
95	if (!addr) {
96		if ((addr = malloc(sizeof (struct netbuf))) == NULL)
97			return (NULL);
98
99		myadr = TRUE;
100		addr->buf = NULL;
101		addr->maxlen = 0;
102		addr->len = 0;
103	}
104
105	if (sbuf == NULL) {
106		sbuf = malloc(SBUFSIZE);
107		if (sbuf == NULL)
108			return (NULL);
109	}
110
111	/* Now process the address */
112	if (*str == '\\') {
113		++str;
114		switch (*str) {
115
116		case 'X':	/* hex */
117		case 'x':
118			addr->len = dobase(++str, sbuf, HEX);
119			break;
120
121		case 'o':	/* octal */
122		case 'O':
123			addr->len = dobase(++str, sbuf, OCT);
124			break;
125
126		default:	/* error */
127			addr->len = 0;
128			break;
129		}
130	}
131
132	if (addr->len == 0) {	/* Error in conversion */
133		if (myadr)
134			free(addr);
135		return (NULL);
136	}
137	if ((addr->buf = xfer(addr->buf, sbuf, addr->len, addr->maxlen)) ==
138									NULL)
139		return (NULL);
140	return (addr);
141}
142
143/*
144 *	dobase :	converts a hex or octal ASCII string
145 *		to a binary address. Only HEX or OCT may be used
146 *		for type.
147 *	return length of binary string (in bytes), 0 if error.
148 *	The binary result is placed at buf.
149 */
150
151static int
152dobase(char *s, char *buf, int type)
153{
154	int	bp = SBUFSIZE - 1;
155	int	shift = 0;
156	char	*end;
157
158	for (end = s; *end && ((type == OCT) ? isodigit(*end) :
159							isxdigit(*end)); ++end)
160		;
161
162	/*
163	 * any non-white, non-digits cause address to be rejected,
164	 * other fields are ignored
165	 */
166	if ((*s == 0) || (end == s) || (!isspace(*end) && *end)) {
167		(void) fprintf(stderr,
168				"dobase: Illegal trailer on address string\n");
169		buf[0] = '\0';
170		return (0);
171	}
172	--end;
173
174	buf[bp] = '\0';
175
176	while (bp > 0 && end >= s) {
177		buf[bp] |= toxdigit(*end) << shift;
178		if (type == OCT) {
179			if (shift > 5) {
180				buf[--bp] = (todigit(*end) >> (8 - shift))
181					& MASK(shift-5);
182			}
183			if ((shift = (shift + 3) % 8) == 0)
184				buf[--bp] = 0;
185		} else	/* hex */
186			if ((shift = (shift) ? 0 : 4) == 0)
187				buf[--bp] = 0;
188		--end;
189	}
190	if (bp == 0) {
191		(void) fprintf(stderr, "stoa: dobase: number to long\n");
192		return (0);
193	}
194
195	/* need to catch end case to avoid extra 0's in front	*/
196	if (!shift)
197		bp++;
198	memcp(buf, &buf[bp], (SBUFSIZE - bp));
199	return (SBUFSIZE - bp);
200}
201
202static void
203memcp(char *d, char *s, int n)
204{
205	while (n--)
206		*d++ = *s++;
207}
208
209/*
210 * transfer block to a given destination or allocate one of the
211 *	right size
212 *	if max = 0 : ignore max
213 */
214
215static char *
216xfer(char *dest, char *src, unsigned len, unsigned max)
217{
218	if (max && dest && max < len) {		/* No room */
219		(void) fprintf(stderr, "xfer: destination not long enough\n");
220		return (NULL);
221	}
222	if (!dest)
223		if ((dest = malloc(len)) == NULL) {
224			(void) fprintf(stderr, "xfer: malloc failed\n");
225			return (NULL);
226		}
227
228	(void) memcpy(dest, src, (size_t)len);
229	return (dest);
230}
231#endif /* TLI */
232