/*
 *  This code is loosely based on src/lib/libc/net/inet_addr.c from FreeBSD 4.8
 */

#include "sm/generic.h"
SM_RCSID("@(#)$Id: sm_inet_arpa2ipv4.c,v 1.2 2005/01/18 00:06:21 ca Exp $")

#include "sm/assert.h"
#include "sm/error.h"
#include "sm/ctype.h"
#include "sm/net.h"

sm_ret_T
sm_inet_arpa2ipv4(const char *cp, ipv4_T *ipv4)
{
	ulong parts[4], ul;
	ipv4_T val;
	char *c, *endptr;
	int n;
	bool gotend;

	c = (char *)cp;
	n = 0;
	gotend = false;
	ul = 0;
	while (!gotend)
	{
		errno = 0;
		ul = strtoul(c, &endptr, 0);
		if (errno == ERANGE)	/* Fail completely if it overflowed. */
			return sm_error_perm(SM_EM_IP, errno);

		/*
		**  If the whole string is invalid, endptr will equal c. this
		**  way we can make sure someone hasn't gone '.12' or something
		**  which would get past the next check.
		*/

		if (endptr == c)
			return sm_error_perm(SM_EM_IP, EINVAL);
		parts[n] = ul;
		c = endptr;

		/* Check the next character past the previous number's end */
		switch (*c)
		{
		  case '.':
			if (n >= 3)
			{
				if (strcasecmp(c, ".in-addr.arpa") != 0)
					return sm_error_perm(SM_EM_IP, EINVAL);
				else
				{
					gotend = true;
					break;
				}
			}
			n++;
			c++;
			break;

		default:
			return sm_error_perm(SM_EM_IP, EINVAL);
		}

	}

	if (n != 3)
		return sm_error_perm(SM_EM_IP, EINVAL);
	if (parts[3] > 0xff || parts[2] > 0xff || parts[1] > 0xff
	    || parts[0] > 0xff)
		return sm_error_perm(SM_EM_IP, EINVAL);
	val = (parts[3] << 24) | (parts[2] << 16) | (parts[1] << 8) | parts[0];
	if (ipv4 != NULL)
		*ipv4 = htonl(val);
	return SM_SUCCESS;
}


syntax highlighted by Code2HTML, v. 0.9.1