/* Lightly hacked and C++-ified from the Berkeley C l;ibrary. */

/*
 * strtoul : convert a string to long.
 *
 * Andy Wilson, 2-Oct-89.
 */

#include <errno.h>
#include <ctype.h>
#include <stdio.h>
/*#include "ansidecl.h"*/

#define	ULONG_MAX	((unsigned long)(~0L))		/* 0xFFFFFFFF */

extern int errno;

extern "C" unsigned long
strtoul(const char *s, char **ptr, int base)
{
  unsigned long total = 0, tmp = 0;
  int digit;
  const char *start=s;
  int did_conversion=0;
  int negate = 0;

  if (s==NULL)
    {
      errno = ERANGE;
      if (!ptr)
	*ptr = (char *)start;
      return 0L;
    }

  while (isspace(*s))
    s++;
  if (*s == '+')
    s++;
  else if (*s == '-')
    s++, negate = 1;
  if (base==0)
    {
      /*
       * try to infer base from the string
       * (assume decimal).
       */
      base = 10;
      if (*s=='0')
	{
	  base = 8;	/* guess it's octal */
	  s++;		/* (but check for hex) */
	  if (*s=='X' || *s=='x')
	    {
	      s++;
	      base = 16;
	    }
	}
    }

  while ( digit = *s )
    {
      if (digit >= '0' && digit < ('0'+base))
	digit -= '0';
      else
	if (base > 10)
	  {
	    if (digit >= 'a' && digit < ('a'+base))
	      digit = digit - 'a' + 10;
	    else if (digit >= 'A' && digit < ('A'+base))
	      digit = digit - 'A' + 10;
	    else
	      break;
	  }
	else
	  break;
      did_conversion = 1;
      tmp = (total * base) + digit;
      if (tmp < total)	/* check overflow */
	{
	  errno = ERANGE;
	  if (ptr != NULL)
	    *ptr = (char *)s;
	  return (ULONG_MAX);
	}
      total = tmp;
      s++;
    }
  if (ptr != NULL)
    *ptr = (char *) ((did_conversion) ? (char *)s : start);
  return negate ? -total : total;
}
