date and time created 90/05/16 11:30:33 by bostic
[unix-history] / usr / src / lib / libc / stdlib / strtoul.c
CommitLineData
8c50609b
KB
1/*
2 * Copyright (c) 1990 Regents of the University of California.
3 * All rights reserved.
4 *
5 * %sccs.include.redist.c%
6 */
7
8#if defined(LIBC_SCCS) && !defined(lint)
9static char sccsid[] = "@(#)strtoul.c 5.1 (Berkeley) %G%";
10#endif /* LIBC_SCCS and not lint */
11
12#include <limits.h>
13#include <ctype.h>
14#include <errno.h>
15
16/*
17 * Convert a string to an unsigned long integer.
18 *
19 * Ignores `locale' stuff. Assumes that the upper and lower case
20 * alphabets and digits are each contiguous.
21 */
22unsigned long
23strtoul(nptr, endptr, base)
24 char *nptr, **endptr;
25 register int base;
26{
27 register char *s = nptr;
28 register unsigned long acc;
29 register int c;
30 register unsigned long cutoff;
31 register int neg = 0, any, cutlim;
32
33 /*
34 * See strtol for comments as to the logic used.
35 */
36 do {
37 c = *s++;
38 } while (isspace(c));
39 if (c == '-') {
40 neg = 1;
41 c = *s++;
42 } else if (c == '+')
43 c = *s++;
44 if ((base == 0 || base == 16) &&
45 c == '0' && (*s == 'x' || *s == 'X')) {
46 c = s[1];
47 s += 2;
48 base = 16;
49 }
50 if (base == 0)
51 base = c == '0' ? 8 : 10;
52 cutoff = (unsigned long)ULONG_MAX / (unsigned long)base;
53 cutlim = (unsigned long)ULONG_MAX % (unsigned long)base;
54 for (acc = 0, any = 0;; c = *s++) {
55 if (isdigit(c))
56 c -= '0';
57 else if (isalpha(c))
58 c -= isupper(c) ? 'A' - 10 : 'a' - 10;
59 else
60 break;
61 if (c >= base)
62 break;
63 if (any < 0 || acc > cutoff || acc == cutoff && c > cutlim)
64 any = -1;
65 else {
66 any = 1;
67 acc *= base;
68 acc += c;
69 }
70 }
71 if (any < 0) {
72 acc = ULONG_MAX;
73 errno = ERANGE;
74 } else if (neg)
75 acc = -acc;
76 if (endptr != 0)
77 *endptr = any ? s - 1 : nptr;
78 return (acc);
79}