USB device can now be unbind
[AROS.git] / compiler / stdc / strtoull.c
blobe9484f4d9991475260e1230296d76e31f2ed2750
1 /*
2 Copyright © 1995-2012, The AROS Development Team. All rights reserved.
3 $Id$
5 C99 function strtoull().
6 */
8 /* This function requires the use of the long long type. */
9 #include <aros/system.h>
10 #if defined(AROS_HAVE_LONG_LONG)
12 #include <ctype.h>
13 #include <errno.h>
14 #include <stdlib.h>
15 #ifndef AROS_NO_LIMITS_H
16 # include <limits.h>
17 #else
18 # define ULLONG_MAX 0xffffffffffffffffULL
19 #endif
21 /*****************************************************************************
23 NAME */
24 #include <stdlib.h>
26 unsigned long long strtoull (
28 /* SYNOPSIS */
29 const char * restrict str,
30 char ** restrict endptr,
31 int base)
33 /* FUNCTION
34 Convert a string of digits into an integer according to the
35 given base.
37 INPUTS
38 str - The string which should be converted. Leading
39 whitespace are ignored. The number may be prefixed
40 by a '+' or '-'. If base is above 10, then the
41 alphabetic characters from 'A' are used to specify
42 digits above 9 (ie. 'A' or 'a' is 10, 'B' or 'b' is
43 11 and so on until 'Z' or 'z' is 35).
44 endptr - If this is non-NULL, then the address of the first
45 character after the number in the string is stored
46 here.
47 base - The base for the number. May be 0 or between 2 and 36,
48 including both. 0 means to autodetect the base. strtoull()
49 selects the base by inspecting the first characters
50 of the string. If they are "0x", then base 16 is
51 assumed. If they are "0", then base 8 is assumed. Any
52 other digit will assume base 10. This is like in C.
54 If you give base 16, then an optional "0x" may
55 precede the number in the string.
57 RESULT
58 The value of the string. The first character after the number
59 is returned in *endptr, if endptr is non-NULL. If no digits can
60 be converted, *endptr contains str (if non-NULL) and 0 is
61 returned.
63 NOTES
65 EXAMPLE
66 // Returns 1, ptr points to the 0-Byte
67 strtoull (" \t +0x1", &ptr, 0);
69 // Returns 15. ptr points to the a
70 strtoull ("017a", &ptr, 0);
72 // Returns 215 (5*36 + 35)
73 strtoull ("5z", &ptr, 36);
75 BUGS
77 SEE ALSO
78 strtoll(), strtoull()
80 INTERNALS
82 ******************************************************************************/
84 unsigned long long val = 0;
85 int digit;
86 char c = 0;
87 unsigned long long cutoff;
88 int cutlim;
89 int any;
91 if (base < 0 || base == 1 || base > 36)
93 #ifndef STDC_STATIC
94 errno = EINVAL;
95 #endif
96 if (endptr)
97 *endptr = (char *)str;
99 return 0;
102 while (isspace (*str))
103 str ++;
105 if (*str)
107 if (*str == '+' || *str == '-')
108 c = *str ++;
110 /* Assume base ? */
111 if (base == 0 || base == 16)
113 if (*str == '0') /* Base 8 or 16 */
115 str++;
116 if (*str == 'x' || *str == 'X')
118 base = 16;
119 str++;
121 else if(base == 0)
122 base = 8;
124 else if(base == 0) /* Any other digit: Base 10 (decimal) */
125 base = 10;
129 Conversion loop, from FreeBSD's src/lib/libc/stdlib/strtoull.c
131 The previous AROS loop was
132 a) inefficient - it did a division each time around.
133 b) buggy - it returned the wrong value in endptr on overflow.
135 cutoff = (unsigned long long)ULLONG_MAX / (unsigned long long)base;
136 cutlim = (unsigned long long)ULLONG_MAX % (unsigned long long)base;
137 val = 0;
138 any = 0;
140 while (*str)
142 digit = *str;
144 if (!isascii(digit))
145 break;
147 if (isdigit(digit))
148 digit -= '0';
149 else if (isalpha(digit))
150 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 = ULLONG_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 } /* strtoull */
193 #endif /* AROS_HAVE_LONG_LONG */