#if defined(LIBC_SCCS) && !defined(lint)
static char rcsid[] = "$Id: inet_pton.c,v 1.3 2003/04/10 18:53:29 majka Exp $";
#endif
#ifdef HAVE_CONFIG_H
#include <config.h>
#endif
#include <sys/param.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <net/if.h>
#include <arpa/nameser.h>
#include <string.h>
#include <stdlib.h>
#include <errno.h>
#define INET6 1
#define IN6ADDRSZ 16
#if 0
#ifndef HAVE_PORTABLE_PROTOTYPE
#include "cdecl_ext.h"
#endif
#ifndef HAVE_U_INT16_T
#include "bittypes.h"
#endif
#if !(defined(HAVE_INADDRSZ) && defined(HAVE_IN6ADDRSZ))
#include "addrsize.h"
#endif
#endif
#ifndef NS_INADDRSZ
#define NS_INADDRSZ INADDRSZ
#endif
#ifndef NS_IN6ADDRSZ
#define NS_IN6ADDRSZ IN6ADDRSZ
#endif
#ifndef NS_INT16SZ
#define NS_INT16SZ sizeof(u_int16_t)
#endif
static int inet_pton4 __P((const char *src, u_char *dst));
#ifdef INET6
static int inet_pton6 __P((const char *src, u_char *dst));
#endif
int
inet_pton(int af, const char *src, void *dst)
{
int status;
unsigned short ifnum;
char *p, *s;
switch (af)
{
case AF_INET:
{
return (inet_pton4(src, dst));
}
#ifdef INET6
case AF_INET6:
{
ifnum = 0;
p = NULL;
s = (char *)src;
if (src != NULL) p = strrchr(src, '%');
if (p != NULL)
{
s = strdup(src);
if (s == NULL)
{
errno = ENOMEM;
return -1;
}
s[p - src] = '\0';
}
status = inet_pton6(s, dst);
if (p != NULL) free(s);
if (status != 1) return status;
if ((p != NULL) && IN6_IS_ADDR_LINKLOCAL((struct in6_addr *)dst))
{
ifnum = if_nametoindex(++p);
ifnum = htons(ifnum);
((struct in6_addr *)dst)->__u6_addr.__u6_addr16[1] = ifnum;
}
return 1;
}
#endif
default:
{
errno = EAFNOSUPPORT;
return -1;
}
}
return -1;
}
static int
inet_pton4(const char *src, u_char *dst)
{
static const char digits[] = "0123456789";
int saw_digit, octets, ch;
u_char tmp[NS_INADDRSZ], *tp;
saw_digit = 0;
octets = 0;
*(tp = tmp) = 0;
while ((ch = *src++) != '\0') {
const char *pch;
if ((pch = strchr(digits, ch)) != NULL) {
u_int new = *tp * 10 + (pch - digits);
if (new > 255)
return (0);
*tp = new;
if (! saw_digit) {
if (++octets > 4)
return (0);
saw_digit = 1;
}
} else if (ch == '.' && saw_digit) {
if (octets == 4)
return (0);
*++tp = 0;
saw_digit = 0;
} else
return (0);
}
if (octets < 4)
return (0);
memcpy(dst, tmp, NS_INADDRSZ);
return (1);
}
#ifdef INET6
static int
inet_pton6(const char *src, u_char *dst)
{
static const char xdigits_l[] = "0123456789abcdef",
xdigits_u[] = "0123456789ABCDEF";
u_char tmp[NS_IN6ADDRSZ], *tp, *endp, *colonp;
const char *xdigits, *curtok;
int ch, saw_xdigit;
u_int val;
memset((tp = tmp), '\0', NS_IN6ADDRSZ);
endp = tp + NS_IN6ADDRSZ;
colonp = NULL;
if (*src == ':')
if (*++src != ':')
return (0);
curtok = src;
saw_xdigit = 0;
val = 0;
while ((ch = *src++) != '\0') {
const char *pch;
if ((pch = strchr((xdigits = xdigits_l), ch)) == NULL)
pch = strchr((xdigits = xdigits_u), ch);
if (pch != NULL) {
val <<= 4;
val |= (pch - xdigits);
if (val > 0xffff)
return (0);
saw_xdigit = 1;
continue;
}
if (ch == ':') {
curtok = src;
if (!saw_xdigit) {
if (colonp)
return (0);
colonp = tp;
continue;
} else if (*src == '\0') {
return (0);
}
if (tp + NS_INT16SZ > endp)
return (0);
*tp++ = (u_char) (val >> 8) & 0xff;
*tp++ = (u_char) val & 0xff;
saw_xdigit = 0;
val = 0;
continue;
}
if (ch == '.' && ((tp + NS_INADDRSZ) <= endp) &&
inet_pton4(curtok, tp) > 0) {
tp += NS_INADDRSZ;
saw_xdigit = 0;
break;
}
return (0);
}
if (saw_xdigit) {
if (tp + NS_INT16SZ > endp)
return (0);
*tp++ = (u_char) (val >> 8) & 0xff;
*tp++ = (u_char) val & 0xff;
}
if (colonp != NULL) {
const int n = tp - colonp;
int i;
if (tp == endp)
return (0);
for (i = 1; i <= n; i++) {
endp[- i] = colonp[n - i];
colonp[n - i] = 0;
}
tp = endp;
}
if (tp != endp)
return (0);
memcpy(dst, tmp, NS_IN6ADDRSZ);
return (1);
}
#endif