diff options
Diffstat (limited to 'libmailutils/cidr/tostr.c')
-rw-r--r-- | libmailutils/cidr/tostr.c | 159 |
1 files changed, 159 insertions, 0 deletions
diff --git a/libmailutils/cidr/tostr.c b/libmailutils/cidr/tostr.c new file mode 100644 index 000000000..3d1ee5f49 --- /dev/null +++ b/libmailutils/cidr/tostr.c @@ -0,0 +1,159 @@ +/* GNU Mailutils -- a suite of utilities for electronic mail + Copyright (C) 2011 Free Software Foundation, Inc. + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 3 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General + Public License along with this library. If not, see + <http://www.gnu.org/licenses/>. */ + +#ifdef HAVE_CONFIG_H +# include <config.h> +#endif +#include <string.h> +#include <stdlib.h> +#include <mailutils/cidr.h> +#include <mailutils/errno.h> + +static int +to_xdig (unsigned char b) +{ + if (b >= 0xa) + return 'A' + b - 0xa; + else + return '0' + b; +} + +static size_t +format_ipv6_bytes (const unsigned char *bytes, int len, + char *buf, size_t size) +{ + size_t total = 0; + int i; + + for (i = 0; i < len; i += 2) + { + if (i) + { + if (total++ < size) + *buf++ = ':'; + } + if (total++ < size) + *buf++ = to_xdig (*bytes >> 4); + if (total++ < size) + *buf++ = to_xdig (*bytes & 0xf); + bytes++; + if (total++ < size) + *buf++ = to_xdig (*bytes >> 4); + if (total++ < size) + *buf++ = to_xdig (*bytes & 0xf); + bytes++; + } + return total; +} + +static size_t +format_ipv4_bytes (const unsigned char *bytes, int len, + char *buf, size_t size) +{ + int i; + size_t total = 0; + + for (i = 0; i < len; i++) + { + unsigned char b = *bytes++; + char nbuf[3]; + int j; + + if (i) + { + if (total++ < size) + *buf++ = '.'; + } + + j = 0; + do + { + nbuf[j++] = b % 10 + '0'; + b /= 10; + } + while (b); + + for (; j; j--) + { + if (total++ < size) + *buf++ = nbuf[j - 1]; + } + } + return total; +} + +int +mu_cidr_to_string (struct mu_cidr *cidr, int flags, + char *buf, size_t size, size_t *pret) +{ + size_t (*fmt) (const unsigned char *bytes, int len, char *buf, size_t size); + size_t n, total = 0; + + if (size == 0) + return MU_ERR_BUFSPACE; + size--; + switch (cidr->family) + { + case AF_INET: + fmt = format_ipv4_bytes; + break; + +#ifdef MAILUTILS_IPV6 + case AF_INET6: + fmt = format_ipv6_bytes; + break; +#endif + + default: + return MU_ERR_FAMILY; + } + + n = fmt (cidr->address, cidr->len, buf, size); + if (buf) + buf += n; + total += n; + + if (!(flags & MU_CIDR_FMT_ADDRONLY)) + { + if (total++ < size) + *buf++ = '/'; + n = fmt (cidr->netmask, cidr->len, buf, size - total); + if (buf) + buf += n; + total += n; + } + + if (buf) + *buf++ = 0; + if (pret) + *pret = total; + return 0; +} + +int +mu_cidr_format (struct mu_cidr *cidr, int flags, char **pbuf) +{ + char buf[MU_CIDR_MAXBUFSIZE]; + int rc = mu_cidr_to_string (cidr, flags, buf, sizeof (buf), NULL); + if (rc) + return rc; + *pbuf = strdup (buf); + if (!*buf) + return ENOMEM; + return 0; +} + |