USB device can now be unbind
[AROS.git] / compiler / stdc / strtoul.c
blob61c281e11a567e1bc85b739a940c1c48f4b94800
1 /*
2 Copyright © 1995-2012, The AROS Development Team. All rights reserved.
3 $Id$
5 C99 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 #ifndef STDC_STATIC
89 errno = EINVAL;
90 #endif
91 if (endptr)
92 *endptr = (char *)str;
94 return 0;
97 while (isspace (*str))
98 str ++;
101 if (*str)
103 if (*str == '+' || *str == '-')
104 c = *str ++;
106 /* Assume base ? */
107 if (base == 0 || base == 16)
109 if (*str == '0') /* Base 8 or 16 */
111 str++;
112 if (*str == 'x' || *str == 'X')
114 str++;
115 base = 16;
117 else if(base == 0)
118 base = 8;
120 else if(base == 0) /* Any other digit: Base 10 (decimal) */
121 base = 10;
125 Conversion loop, from FreeBSD's src/lib/libc/stdlib/strtoul.c
127 The previous AROS loop was
128 a) inefficient - it did a division each time around.
129 b) buggy - it returned the wrong value in endptr on overflow.
131 cutoff = (unsigned long)ULONG_MAX / (unsigned long)base;
132 cutlim = (unsigned long)ULONG_MAX % (unsigned long)base;
133 val = 0;
134 any = 0;
136 while (*str)
138 digit = *str;
140 if (!isascii(digit))
141 break;
143 if (isdigit(digit))
145 digit -= '0';
147 else if (isalpha(digit))
149 digit -= isupper(digit) ? 'A' - 10 : 'a' - 10;
151 else
152 break;
154 if (digit >= base)
155 break;
158 any < 0 when we have overflowed. We still need to find the
159 end of the subject sequence
161 if (any < 0 || val > cutoff || (val == cutoff && digit > cutlim))
163 any = -1;
165 else
167 any = 1;
168 val = (val * base) + digit;
171 str++;
174 /* Range overflow */
175 if (any < 0)
177 val = ULONG_MAX;
178 #ifndef STDC_STATIC
179 errno = ERANGE;
180 #endif
183 if (c == '-')
184 val = -val;
187 if (endptr)
188 *endptr = (char *)str;
190 return val;
191 } /* strtoul */