define __KERNEL_STRICT_NAMES to avoid inclusion of kernel types on systems that carry...
[cake.git] / compiler / clib / strtoul.c
blob67436471354ab2fb8e89526802ca21dda1f038a9
1 /*
2 Copyright © 1995-2001, The AROS Development Team. All rights reserved.
3 $Id$
5 ANSI C function strtoul().
6 */
8 #include <ctype.h>
9 #include <errno.h>
10 #ifndef AROS_NO_LIMITS_H
11 # include <limits.h>
12 #else
13 # define ULONG_MAX 4294967295UL
14 #endif
16 /*****************************************************************************
18 NAME */
19 #include <stdlib.h>
21 unsigned long strtoul (
23 /* SYNOPSIS */
24 const char * str,
25 char ** endptr,
26 int base)
28 /* FUNCTION
29 Convert a string of digits into an integer according to the
30 given base.
32 INPUTS
33 str - The string which should be converted. Leading
34 whitespace are ignored. The number may be prefixed
35 by a '+' or '-'. If base is above 10, then the
36 alphabetic characters from 'A' are used to specify
37 digits above 9 (ie. 'A' or 'a' is 10, 'B' or 'b' is
38 11 and so on until 'Z' or 'z' is 35).
39 endptr - If this is non-NULL, then the address of the first
40 character after the number in the string is stored
41 here.
42 base - The base for the number. May be 0 or between 2 and 36,
43 including both. 0 means to autodetect the base. strtoul()
44 selects the base by inspecting the first characters
45 of the string. If they are "0x", then base 16 is
46 assumed. If they are "0", then base 8 is assumed. Any
47 other digit will assume base 10. This is like in C.
49 If you give base 16, then an optional "0x" may
50 precede the number in the string.
52 RESULT
53 The value of the string. The first character after the number
54 is returned in *endptr, if endptr is non-NULL. If no digits can
55 be converted, *endptr contains str (if non-NULL) and 0 is
56 returned.
58 NOTES
60 EXAMPLE
61 // Returns 1, ptr points to the 0-Byte
62 strtoul (" \t +0x1", &ptr, 0);
64 // Returns 15. ptr points to the a
65 strtoul ("017a", &ptr, 0);
67 // Returns 215 (5*36 + 35)
68 strtoul ("5z", &ptr, 36);
70 BUGS
72 SEE ALSO
73 atoi(), atol(), strtod(), strtol(), strtoul()
75 INTERNALS
77 ******************************************************************************/
79 unsigned long val = 0;
80 int digit;
81 char c = 0;
82 unsigned long cutoff;
83 int cutlim;
84 int any;
86 if (base < 0 || base == 1 || base > 36)
88 errno = EINVAL;
90 if (endptr)
91 *endptr = (char *)str;
93 return 0;
96 while (isspace (*str))
97 str ++;
100 if (*str)
102 if (*str == '+' || *str == '-')
103 c = *str ++;
105 /* Assume base ? */
106 if (base == 0 || base == 16)
108 if (*str == '0') /* Base 8 or 16 */
110 str++;
111 if (*str == 'x' || *str == 'X')
113 str++;
114 base = 16;
116 else if(base == 0)
117 base = 8;
119 else if(base == 0) /* Any other digit: Base 10 (decimal) */
120 base = 10;
124 Conversion loop, from FreeBSD's src/lib/libc/stdlib/strtoul.c
126 The previous AROS loop was
127 a) inefficient - it did a division each time around.
128 b) buggy - it returned the wrong value in endptr on overflow.
130 cutoff = (unsigned long)ULONG_MAX / (unsigned long)base;
131 cutlim = (unsigned long)ULONG_MAX % (unsigned long)base;
132 val = 0;
133 any = 0;
135 while (*str)
137 digit = *str;
139 if (!isascii(digit))
140 break;
142 if (isdigit(digit))
144 digit -= '0';
146 else if (isalpha(digit))
148 digit -= isupper(digit) ? 'A' - 10 : 'a' - 10;
150 else
151 break;
153 if (digit >= base)
154 break;
157 any < 0 when we have overflowed. We still need to find the
158 end of the subject sequence
160 if (any < 0 || val > cutoff || (val == cutoff && digit > cutlim))
162 any = -1;
164 else
166 any = 1;
167 val = (val * base) + digit;
170 str++;
173 /* Range overflow */
174 if (any < 0)
176 val = ULONG_MAX;
177 errno = ERANGE;
180 if (c == '-')
181 val = -val;
184 if (endptr)
185 *endptr = (char *)str;
187 return val;
188 } /* strtoul */