blob: 19fe16e03f98d441d76d85cfb910aded8b47c443 [file] [log] [blame]
/*
* inet/inet_pton.c
*/
#include <stdio.h>
#include <stdint.h>
#include <errno.h>
#include <ctype.h>
#include <string.h>
#include <arpa/inet.h>
#include <netinet/in6.h>
static inline int hexval(int ch)
{
if (ch >= '0' && ch <= '9') {
return ch - '0';
} else if (ch >= 'A' && ch <= 'F') {
return ch - 'A' + 10;
} else if (ch >= 'a' && ch <= 'f') {
return ch - 'a' + 10;
} else {
return -1;
}
}
int inet_pton(int af, const char *src, void *dst)
{
switch (af) {
case AF_INET:
return inet_aton(src, (struct in_addr *)dst);
case AF_INET6:
{
struct in6_addr *d = (struct in6_addr *)dst;
int colons = 0, dcolons = 0;
int i;
const char *p;
/* A double colon will increment colons by 2,
dcolons by 1 */
for (p = dst; *p; p++) {
if (p[0] == ':') {
colons++;
if (p[1] == ':')
dcolons++;
} else if (!isxdigit(*p))
return 0; /* Invalid address */
}
if (colons > 7 || dcolons > 1
|| (!dcolons && colons != 7))
return 0; /* Invalid address */
memset(d, 0, sizeof(struct in6_addr));
i = 0;
for (p = dst; *p; p++) {
if (*p == ':') {
if (p[1] == ':') {
i += (8 - colons);
} else {
i++;
}
} else {
d->s6_addr16[i] =
htons((ntohs(d->s6_addr16[i]) << 4)
+ hexval(*p));
}
}
return 1;
}
default:
errno = EAFNOSUPPORT;
return -1;
}
}