1#include <arpa/inet.h>
2#include <ctype.h>
3#include <errno.h>
4#include <string.h>
5#include <sys/socket.h>
6
7static int hexval(unsigned c) {
8    if (c - '0' < 10)
9        return c - '0';
10    c |= 32;
11    if (c - 'a' < 6)
12        return c - 'a' + 10;
13    return -1;
14}
15
16int inet_pton(int af, const char* restrict s, void* restrict a0) {
17    uint16_t ip[8];
18    unsigned char* a = a0;
19    int i, j, v, d, brk = -1, need_v4 = 0;
20
21    if (af == AF_INET) {
22        for (i = 0; i < 4; i++) {
23            for (v = j = 0; j < 3 && isdigit(s[j]); j++)
24                v = 10 * v + s[j] - '0';
25            if (j == 0 || (j > 1 && s[0] == '0') || v > 255)
26                return 0;
27            a[i] = v;
28            if (s[j] == 0 && i == 3)
29                return 1;
30            if (s[j] != '.')
31                return 0;
32            s += j + 1;
33        }
34        return 0;
35    } else if (af != AF_INET6) {
36        errno = EAFNOSUPPORT;
37        return -1;
38    }
39
40    if (*s == ':' && *++s != ':')
41        return 0;
42
43    for (i = 0;; i++) {
44        if (s[0] == ':' && brk < 0) {
45            brk = i;
46            ip[i & 7] = 0;
47            if (!*++s)
48                break;
49            if (i == 7)
50                return 0;
51            continue;
52        }
53        for (v = j = 0; j < 4 && (d = hexval(s[j])) >= 0; j++)
54            v = 16 * v + d;
55        if (j == 0)
56            return 0;
57        ip[i & 7] = v;
58        if (!s[j] && (brk >= 0 || i == 7))
59            break;
60        if (i == 7)
61            return 0;
62        if (s[j] != ':') {
63            if (s[j] != '.' || (i < 6 && brk < 0))
64                return 0;
65            need_v4 = 1;
66            i++;
67            break;
68        }
69        s += j + 1;
70    }
71    if (brk >= 0) {
72        memmove(ip + brk + 7 - i, ip + brk, 2 * (i + 1 - brk));
73        for (j = 0; j < 7 - i; j++)
74            ip[brk + j] = 0;
75    }
76    for (j = 0; j < 8; j++) {
77        *a++ = ip[j] >> 8;
78        *a++ = ip[j];
79    }
80    if (need_v4 && inet_pton(AF_INET, (void*)s, a - 4) <= 0)
81        return 0;
82    return 1;
83}
84