source: mainline/uspace/lib/posix/stdlib/strtol.c@ 3f466c33

lfn serial ticket/834-toolchain-update topic/msim-upgrade topic/simplify-dev-export
Last change on this file since 3f466c33 was a6d908c1, checked in by Jiří Zárevúcky <zarevucky.jiri@…>, 14 years ago

Small changes in includes.

  • Property mode set to 100644
File size: 5.8 KB
Line 
1/*
2 * Copyright (c) 2011 Jiri Zarevucky
3 * All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
8 *
9 * - Redistributions of source code must retain the above copyright
10 * notice, this list of conditions and the following disclaimer.
11 * - Redistributions in binary form must reproduce the above copyright
12 * notice, this list of conditions and the following disclaimer in the
13 * documentation and/or other materials provided with the distribution.
14 * - The name of the author may not be used to endorse or promote products
15 * derived from this software without specific prior written permission.
16 *
17 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
18 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
19 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
20 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
21 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
22 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
23 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
24 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
25 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
26 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27 */
28
29/** @addtogroup libposix
30 * @{
31 */
32/** @file
33 */
34
35#define LIBPOSIX_INTERNAL
36
37#include "../internal/common.h"
38#include "../stdlib.h"
39
40#include "../limits.h"
41#include "../ctype.h"
42#include <errno.h> // FIXME: use POSIX errno
43
44// TODO: documentation
45
46static inline bool is_digit_in_base(int c, int base)
47{
48 if (base <= 10) {
49 return c >= '0' && c < '0' + base;
50 } else {
51 return isdigit(c) ||
52 (tolower(c) >= 'a' && tolower(c) < ('a' + base - 10));
53 }
54}
55
56static inline int get_digit_in_base(int c, int base)
57{
58 if (c <= '9') {
59 return c - '0';
60 } else {
61 return 10 + tolower(c) - 'a';
62 }
63}
64
65static inline unsigned long long internal_strtol(
66 const char *restrict nptr, char **restrict endptr, int base,
67 const long long min_value, const unsigned long long max_value,
68 bool *restrict out_negative)
69{
70 if (nptr == NULL) {
71 errno = EINVAL;
72 return 0;
73 }
74
75 if (base < 0 || base == 1 || base > 36) {
76 errno = EINVAL;
77 return 0;
78 }
79
80 unsigned long long real_max_value = max_value;
81
82 /* Current index in the input string. */
83 int i = 0;
84 bool negative = false;
85
86 /* Skip whitespace. */
87 while (isspace(nptr[i])) {
88 i++;
89 }
90
91 /* Parse sign. */
92 switch (nptr[i]) {
93 case '-':
94 negative = true;
95 real_max_value = -min_value;
96 /* fallthrough */
97 case '+':
98 i++;
99 }
100
101 /* Figure out the base. */
102 switch (base) {
103 case 0:
104 if (nptr[i] == '0') {
105 if (tolower(nptr[i + 1]) == 'x') {
106 base = 16;
107 i += 2;
108 } else {
109 base = 8;
110 }
111 } else {
112 base = 10;
113 }
114 break;
115 case 16:
116 if (nptr[i] == '0' && tolower(nptr[i + 1]) == 'x') {
117 i += 2;
118 }
119 break;
120 }
121
122 if (!is_digit_in_base(nptr[i], base)) {
123 /* No digits to parse, invalid input. */
124
125 errno = EINVAL;
126 if (endptr != NULL) {
127 *endptr = (char *) nptr;
128 }
129 return 0;
130 }
131
132 /* Maximal value to which a digit can be added without a risk
133 * of overflow.
134 */
135 unsigned long long max_safe_value = (real_max_value - base + 1) / base;
136
137 unsigned long long result = 0;
138
139 if (real_max_value == 0) {
140 /* Special case when a negative number is parsed as
141 * unsigned integer. Only -0 is accepted.
142 */
143
144 while (is_digit_in_base(nptr[i], base)) {
145 if (nptr[i] != '0') {
146 errno = ERANGE;
147 result = max_value;
148 }
149 i++;
150 }
151 }
152
153 while (is_digit_in_base(nptr[i], base)) {
154 int digit = get_digit_in_base(nptr[i], base);
155
156 if (result > max_safe_value) {
157 /* corner case, check for overflow */
158
159 unsigned long long
160 boundary = (real_max_value - digit) / base;
161
162 if (result > boundary) {
163 /* overflow */
164 errno = ERANGE;
165 result = max_value;
166 break;
167 }
168 }
169
170 result = result * base + digit;
171 i++;
172 }
173
174 if (endptr != NULL) {
175 /* Move the pointer to the end of the number,
176 * in case it isn't there already.
177 */
178 while (is_digit_in_base(nptr[i], base)) {
179 i++;
180 }
181
182 *endptr = (char *) &nptr[i];
183 }
184 if (out_negative != NULL) {
185 *out_negative = negative;
186 }
187 return result;
188}
189
190int posix_atoi(const char *nptr)
191{
192 bool neg = false;
193 unsigned long long result =
194 internal_strtol(nptr, NULL, 10, INT_MIN, INT_MAX, &neg);
195
196 return (int) (neg ? -result : result);
197}
198
199long posix_atol(const char *nptr)
200{
201 bool neg = false;
202 unsigned long long result =
203 internal_strtol(nptr, NULL, 10, LONG_MIN, LONG_MAX, &neg);
204
205 return (long) (neg ? -result : result);
206}
207
208long long posix_atoll(const char *nptr)
209{
210 bool neg = false;
211 unsigned long long result =
212 internal_strtol(nptr, NULL, 10, LLONG_MIN, LLONG_MAX, &neg);
213
214 return (long long) (neg ? -result : result);
215}
216
217long posix_strtol(const char *restrict nptr, char **restrict endptr, int base)
218{
219 bool neg = false;
220 unsigned long long result =
221 internal_strtol(nptr, endptr, base, LONG_MIN, LONG_MAX, &neg);
222
223 return (long) (neg ? -result : result);
224}
225
226long long posix_strtoll(
227 const char *restrict nptr, char **restrict endptr, int base)
228{
229 bool neg = false;
230 unsigned long long result =
231 internal_strtol(nptr, endptr, base, LLONG_MIN, LLONG_MAX, &neg);
232
233 return (long long) (neg ? -result : result);
234}
235
236unsigned long posix_strtoul(
237 const char *restrict nptr, char **restrict endptr, int base)
238{
239 unsigned long long result =
240 internal_strtol(nptr, endptr, base, 0, ULONG_MAX, NULL);
241
242 return (unsigned long) result;
243}
244
245unsigned long long posix_strtoull(
246 const char *restrict nptr, char **restrict endptr, int base)
247{
248 return internal_strtol(nptr, endptr, base, 0, ULLONG_MAX, NULL);
249}
250
251
252/** @}
253 */
254
Note: See TracBrowser for help on using the repository browser.