home *** CD-ROM | disk | FTP | other *** search
- /* original from norbert schelenkar's stdio */
- /* eff hacks ++jrb */
- /* conversion to ansi spec -- mj */
- /*
- * Base can be anything between 2 and 36 or 0.
- * If not NULL then resulting *endptr points to the first
- * non-accepted character.
- */
-
- #include <ctype.h>
- #include <errno.h>
- #include <limits.h>
- #include <stdlib.h>
- #include <stddef.h>
-
- /* macro to avoid most frequent long muls on a lowly 68k */
- #define _BASEMUL(B, SH, X) \
- ((0 != SH) ? \
- ((10 == (B)) ? ((((X) << (SH)) + (X)) << 1) : ((X) << (SH))) : \
- ((X) * (B)))
-
- unsigned long int strtoul(nptr, endptr, base)
- register const char *nptr;
- char **endptr;
- int base;
- {
- register short c;
- unsigned long result = 0L;
- unsigned long limit;
- short negative = 0;
- short overflow = -2; /* if this stays negative then no
- conversion was performed */
- short digit;
- int shift;
-
- if (endptr != NULL)
- *endptr = (char *)nptr;
-
- while ((c = *nptr) && isspace(c)) /* skip leading white space */
- nptr++;
- if ((c = *nptr) == '+' || c == '-') { /* handle signs */
- negative = (c == '-');
- nptr++;
- }
- if (base == 0) { /* determine base if unknown */
- if (*nptr == '0') {
- base = 8;
- nptr++;
- if ((c = *nptr) == 'x' || c == 'X') {
- base += base;
- nptr++;
- }
- }
- else
- base = 10;
- }
- else
- if (base == 16 && *nptr == '0') { /* discard 0x/0X prefix if hex */
- nptr++;
- if ((c = *nptr == 'x') || c == 'X')
- nptr++;
- }
- if (base < 2 || base > 36)
- return result;
-
- limit = ULONG_MAX/(unsigned long)base; /* ensure no overflow */
- shift = 0;
- switch (base) {
- case 32: shift++;
- case 16: shift++;
- case 8: shift++;
- case 4: case 10: shift++;
- case 2: shift++;
- default:;
- }
-
- nptr--; /* convert the number */
- while (c = *++nptr) {
- if (isdigit(c))
- digit = c - '0';
- else
- digit = c - (isupper(c) ? 'A' : 'a') + 10;
- if (digit < 0 || digit >= base)
- break;
- overflow &= 1; /* valid digit - some conversion performed */
- if (0 == (overflow &= 1)) { /* valid digit
- - some conversion performed */
- if ((result > limit) ||
- (digit >
- (ULONG_MAX - (result = _BASEMUL(base, shift, result))))) {
- result = ULONG_MAX;
- errno = ERANGE;
- overflow = 1;
- negative = 0;
- }
- else
- result += digit;
- }
- }
- if (negative) /* ANSI says we should do this! */
- result = 0L - result;
-
- if ((endptr != NULL) && (overflow >= 0)) /* move *endptr if some */
- *endptr = (char *) nptr; /* digits were accepted */
- return result;
- }
-