Minix1.5/lib/ansi/strtoul.c

Compare this file to the similar file:
Show the results in this format:

/* strtoul.c						ANSI 4.10.1.6
 *	unsigned long int strtoul(const char *nptr, char **endptr, int base);
 *
 *	Converts a numeric string, in various bases, to an unsigned long.
 */

#include <lib.h>
#include <ctype.h>
#include <errno.h>
#include <limits.h>
#include <stdlib.h>

#ifdef strtoul
#undef strtoul
#endif

PUBLIC unsigned long int strtoul(nptr, endptr, base)
_CONST char *nptr;
char **endptr;
int base;
{
  register int c;
  unsigned long int result = 0L;
  unsigned long int limit;
  int negative = 0;
  int overflow = 0;
  int saw_a_digit = 0;			/* it's not a number without a digit */

  if (endptr != (char **) NULL)		/* set up default final pointer */
	*endptr = nptr;

  while ((c = *nptr) && isspace(c))	/* skip leading white space */
	++nptr;

  if (c == '+' || c == '-') {		/* handle signs */
	negative = (c == '-');
	++nptr;
  }

  if (base == 0) {			/* determine base if unknown */
	base = 10;
	if (*nptr == '0') {
		base = 8;
		++nptr;
		if ((c = *nptr) == 'x' || c == 'X') {
			base = 16;
			++nptr;
		}
	}
  }
  else
  if (base == 16 && *nptr == '0') {	/* discard 0x/0X prefix if hex */
	++nptr;
	if ((c = *nptr == 'x') || c == 'X')
		++nptr;
  }

  limit = ULONG_MAX / base;		/* ensure no overflow */

  --nptr;				/* convert the number */
  while ((c = *++nptr) != 0) {
	if (isdigit(c))
		c -= '0';
	else
		c -= isupper(c) ? ('A' - 10) : ('a' - 10);
	if (c < 0 || c >= base)
		break;
	saw_a_digit = 1;
	if (result > limit)
		overflow = 1;
	if (!overflow) {
		result = base * result;
		if (c > ULONG_MAX - result)
			overflow = 1;
		else	
			result += c;
	}
  }
  if (!saw_a_digit)
	return 0;

  if (negative && !overflow)	/* BIZARRE, but ANSI says we should do this! */
	result = 0L - result;
  if (overflow) {
	errno = ERANGE;
	result = ULONG_MAX;
  }

  if (endptr != (char **) NULL)		/* record good final pointer */
	*endptr = nptr;
  return result;
}