chiark / gitweb /
volume_id: provide libvolume_id.a file
[elogind.git] / klibc / klibc / inet / inet_pton.c
1 /*
2  * inet/inet_pton.c
3  */
4
5 #include <stdio.h>
6 #include <stdint.h>
7 #include <errno.h>
8 #include <ctype.h>
9 #include <string.h>
10 #include <arpa/inet.h>
11 #include <netinet/in6.h>
12
13 static inline int hexval(int ch)
14 {
15   if ( ch >= '0' && ch <= '9' ) {
16     return ch-'0';
17   } else if ( ch >= 'A' && ch <= 'F' ) {
18     return ch-'A'+10;
19   } else if ( ch >= 'a' && ch <= 'f' ) {
20     return ch-'a'+10;
21   } else {
22     return -1;
23   }
24 }
25
26 int inet_pton(int af, const char *src, void *dst)
27 {
28   switch ( af ) {
29   case AF_INET:
30     return inet_aton(src, (struct in_addr *)dst);
31     
32   case AF_INET6:
33     {
34       struct in6_addr *d = (struct in6_addr *)dst;
35       int colons = 0, dcolons = 0;
36       int i;
37       const char *p;
38
39       /* A double colon will increment colons by 2, dcolons by 1 */
40       for ( p = dst ; *p ; p++ ) {
41         if ( p[0] == ':' ) {
42           colons++;
43           if ( p[1] == ':' )
44             dcolons++;
45         } else if ( !isxdigit(*p) )
46           return 0;             /* Not a valid address */
47       }
48
49       if ( colons > 7 || dcolons > 1 || (!dcolons && colons != 7) )
50         return 0;               /* Not a valid address */
51
52       memset(d, 0, sizeof(struct in6_addr));
53
54       i = 0;
55       for ( p = dst ; *p ; p++ ) {
56         if ( *p == ':' ) {
57           if ( p[1] == ':' ) {
58             i += (8-colons);
59           } else {
60             i++;
61           }
62         } else {
63           d->s6_addr16[i] = htons((ntohs(d->s6_addr16[i]) << 4) + hexval(*p));
64         }
65       }
66
67       return 1;
68     }
69
70   default:
71     errno = EAFNOSUPPORT;
72     return -1;
73   }
74 }