/*
 *      dnsutl - utilities to make DNS easier to configure
 *      Copyright (C) 1999, 2006, 2007 Peter Miller
 *
 *      This program is free software; you can redistribute it and/or modify
 *      it under the terms of the GNU General Public License as published by
 *      the Free Software Foundation; either version 3 of the License, or
 *      (at your option) any later version.
 *
 *      This program 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 General Public License for more details.
 *
 *      You should have received a copy of the GNU General Public License
 *      along with this program. If not, see
 *      <http://www.gnu.org/licenses/>.
 */

#include <ac/ctype.h>

#include <error.h>
#include <srrf/address.h>
#include <str.h>


static int
srrf_address_value(const char *s, unsigned long *np)
{
    const char      *cp;
    unsigned long   result;
    int             n;

    /*
     * collect the first octet
     */
    cp = s;
    if (!isdigit(*cp))
        return 0;
    n = 0;
    for (;;)
    {
        n = n * 10 + *cp++ - '0';
        if (n >= 256)
            return 0;
        if (!isdigit(*cp))
            break;
    }
    result = (unsigned long)n << 24;
    if (!*cp)
    {
        *np = result;
        return 1;
    }

    /*
     * collect the second octet
     */
    if (*cp++ != '.')
        return 0;
    if (!isdigit(*cp))
        return 0;
    n = 0;
    for (;;)
    {
        n = n * 10 + *cp++ - '0';
        if (n >= 256)
            return 0;
        if (!isdigit(*cp))
            break;
    }
    result |= (unsigned long)n << 16;
    if (!*cp)
    {
        *np = result;
        return 2;
    }

    /*
     * collect the third octet
     */
    if (*cp++ != '.')
        return 0;
    if (!isdigit(*cp))
        return 0;
    n = 0;
    for (;;)
    {
        n = n * 10 + *cp++ - '0';
        if (n >= 256)
            return 0;
        if (!isdigit(*cp))
            break;
    }
    result |= (unsigned long)n << 8;
    if (!*cp)
    {
        *np = result;
        return 3;
    }

    /*
     * collect the fourth octet
     */
    if (*cp++ != '.')
        return 0;
    if (!isdigit(*cp))
        return 0;
    n = 0;
    for (;;)
    {
        n = n * 10 + *cp++ - '0';
        if (n >= 256)
            return 0;
        if (!isdigit(*cp))
            break;
    }
    result |= (unsigned long)n;
    if (*cp)
        return 0;
    *np = result;
    return 4;
}


unsigned long
srrf_address(const char *s)
{
    unsigned long   result;

    if (!srrf_address_value(s, &result))
        fatal("the string \"%s\" is not a valid address", s);
    return result;
}


string_ty *
srrf_address_cannonicalize(string_ty * s)
{
    unsigned long   addr;

    if (!srrf_address_value(s->str_text, &addr))
        return 0;
    return
        str_format
        (
            "%d.%d.%d.%d",
            (unsigned char)(addr >> 24),
            (unsigned char)(addr >> 16),
            (unsigned char)(addr >> 8),
            (unsigned char)addr
        );
}


syntax highlighted by Code2HTML, v. 0.9.1