/* strtoul.c (emx+gcc) -- Copyright (c) 1990-1993 by Eberhard Mattes */

#include <stdlib.h>
#include <limits.h>
#include <ctype.h>
#include <errno.h>

unsigned long strtoul (const char *string, char **end_ptr, int radix)
{
  const unsigned char *s;
  char neg;
  unsigned long result;

  s = string;
  while (isspace (*s))
    ++s;

  neg = 0;
  if (*s == '-')
    {
      neg = 1; ++s;
    }
  else if (*s == '+')
    ++s;

  if ((radix == 0 || radix == 16) && s[0] == '0'
      && (s[1] == 'x' || s[1] == 'X'))
    {
      radix = 16; s += 2;
    }
  if (radix == 0)
    radix = (s[0] == '0' ? 8 : 10);

  result = 0;                   /* Keep the compiler happy */
  if (radix >= 2 && radix <= 36)
    {
      unsigned long n, max1, max2;
      enum {no_number, ok, overflow} state;
      unsigned char c;

      max1 = ULONG_MAX / radix;
      max2 = ULONG_MAX - max1 * radix;
      n = 0; state = no_number;
      for (;;)
        {
          c = *s;
          if (c >= '0' && c <= '9')
            c = c - '0';
          else if (c >= 'A' && c <= 'Z')
            c = c - 'A' + 10;
          else if (c >= 'a' && c <= 'z')
            c = c - 'a' + 10;
          else
            break;
          if (c >= radix)
            break;
          if (n >= max1 && (n > max1 || (unsigned long)c > max2))
            state = overflow;
          if (state != overflow)
            {
              n = n * radix + (unsigned long)c;
              state = ok;
            }
          ++s;
        }
      switch (state)
        {
        case no_number:
          result = 0;
          s = string;
          /* Don't set errno!? */
          break;
        case ok:
          result = (neg ? -n : n);
          break;
        case overflow:
          result = ULONG_MAX;
          errno = ERANGE;
          break;
        }
    }
  else
    {
      result = 0;
      errno = EDOM;
    }
  if (end_ptr != NULL)
    *end_ptr = (char *)s;
  return (result);
}
