| /* |
| * 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; |
| } |
| } |