File:  [MW Coherent from dump] / coherent / b / lib / libc / gen / strtol.c
Revision 1.1.1.1 (vendor branch): download - view: text, annotated - select for diffs
Wed May 29 04:56:35 2019 UTC (7 years ago) by root
Branches: MarkWilliams, MAIN
CVS tags: relic, HEAD
coherent

/*
 * C general utilities library.
 * strtol(), strtoul()
 * ANSI 4.10.1.5, 4.10.1.6.
 * Convert ASCII to long or unsigned long (the System V way).
 * atol() was so simple before System V/ANSI got hold of it...
 */

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

extern unsigned long _strtoul();

long
strtol(nptr, endptr, base) char *nptr; char **endptr; int base;
{
	return (long)_strtoul(nptr, endptr, base, 0);
}

unsigned long
strtoul(nptr, endptr, base) char *nptr; char **endptr; int base;
{
	return _strtoul(nptr, endptr, base, 1);
}

static
unsigned long
_strtoul(nptr, endptr, base, uflag) char *nptr; char **endptr; int base, uflag;
{
	register char *cp;
	register unsigned long val;
	register int c, sign, overflow, pflag, dlimit, ulimit, llimit;
	unsigned long quot, rem;

	cp = nptr;
	val = pflag = overflow = sign = 0;

	/* Leading white space. */
	while (isspace(c = *cp++))
		;

	/* Optional sign. */
	switch(c) {
	case '-':
		sign = 1;
		/* fall through... */
	case '+':
		c = *cp++;
	}

	/* Determine implicit base. */
	if (base == 0) {
		if (c == '0')
			base = (*cp == 'x' || *cp == 'X') ? 16 : 8;
		else if (isdigit(c))
			base = 10;
		else {			/* expected form not found */
			cp = nptr;
			goto done;
		}
	}

	/* Skip optional hex base "0x" or "0X". */
	if (base == 16 && c == '0' && (*cp == 'x' || *cp == 'X')) {
		++pflag;
		++cp;
		c = *cp++;
	}

	/* Initialize legal character limits. */
	dlimit = '0' + base;
	ulimit = 'A' + base - 10;
	llimit = 'a' + base - 10;

	/* The next character must be a legitimate digit; e.g. " +@" fails. */
	/* Watch out for e.g. "0xy", which is "0" followed by "xy". */
	if (!(   (isdigit(c) && c < dlimit)
	      || (isupper(c) && c < ulimit)
	      || (islower(c) && c < llimit))) {
		cp = (pflag) ? cp - 2 : nptr;
		goto done;
	}

	/* Determine limits for overflow computation. */
	/* This would use ldiv() if it worked for unsigned long. */
	if (uflag) {
		quot = ULONG_MAX / base;
		rem = ULONG_MAX % base;
	} else {
		quot = LONG_MAX / base;
		rem = LONG_MAX % base;
	}

	/* Process digit string. */
	for ( ; ; c = *cp++) {
		if (isdigit(c) && c < dlimit)
			c -= '0';
		else if (isupper(c) && c < ulimit)
			c -= 'A'-10;
		else if (islower(c) && c < llimit)
			c -= 'a'-10;
		else {
			--cp;
			break;
		}
		if (val < quot || (val == quot && c <= rem))
			val = val * base + c;
		else
			++overflow;
	}

done:
	/* Store end pointer and return approriate result. */
	if (endptr != (char **)NULL)
		*endptr = cp;
	if (overflow) {
		errno = ERANGE;
		if (uflag)
			return ULONG_MAX;
		return (unsigned long)(sign ? LONG_MIN : LONG_MAX);
	}
	return (sign) ? (unsigned long)(-(long)val) : val;
}

/* end of strtol.c */

unix.superglobalmegacorp.com

This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.