/*====================================================================*
 *
 *   uint64_t basespec (char const * string, unsigned base, unsigned size);
 *
 *   number.h
 *
 *   convert a character string to an equivalent unsigned integer and
 *   return the result; terminate the program on failure;
 *
 *   the base argument is the number base to be used for conversion;
 *   base 0 permits the number base to be determined by the string
 *   string prefix; 0b, 0d or 0x for binary, decimal or hex;
 *
 *   this implementation accepts a minus sign in order to negate any
 *   number in any base;
 *
 *   the size argument is the maximum number of bytes permitted in the
 *   result;
 *
 *   Motley Tools by Charles Maier <cmaier@cmassoc.net>;
 *   Copyright (c) 2001-2006 by Charles Maier Associates;
 *   Licensed under the Internet Software Consortium License;
 *
 *--------------------------------------------------------------------*/

#ifndef BASESPEC_SOURCE
#define BASESPEC_SOURCE

#include <stdlib.h>
#include <ctype.h>

#include "../tools/number.h"
#include "../tools/error.h"

uint64_t basespec (char const * string, unsigned base, unsigned size)

{
	char const * number = string;
	unsigned radix = RADIX_DEC;
	signed scale = 1;
	uint64_t limit = 0;
	uint64_t value = 0;
	unsigned digit = 0;
	limit = ~limit;
	if (size < sizeof (limit))
	{
		limit <<= size << 3;
		limit = ~limit;
	}
	if (base)
	{
		radix = base;
	}
	if (* number == '=')
	{
		number++;
	}
	else if (* number == '+')
	{
		number++;
	}
	else if (* number == '-')
	{
		number++;
		scale = -1;
	}
	if (*number == '0')
	{
		number++;
		if ((*number == 'b') || (*number == 'B'))
		{
			radix = RADIX_BIN;
			number++;
		}
		else if ((*number == 'd') || (*number == 'D'))
		{
			radix = RADIX_DEC;
			number++;
		}
		else if ((*number == 'x') || (*number == 'X'))
		{
			radix = RADIX_HEX;
			number++;
		}
	}
	if ((base) && (base != radix))
	{
		error (1, EINVAL, "%s is not base %d notation", string, base);
	}
	while ((digit = todigit (*number)) < radix)
	{
		value *= radix;
		value += digit;
		if (value > limit)
		{
			error (1, ERANGE, "%s exceeds %d bits", string, (size << 3));
		}
		number++;
	}

#ifdef WIN32

	while (isspace (*number))
	{
		number++;
	}

#endif

	if (*number)
	{
		error (1, EINVAL, "%s is not base %d notation", string, radix);
	}
	return (scale * value);
}

#endif