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

lfn serial ticket/834-toolchain-update topic/msim-upgrade topic/simplify-dev-export
Last change on this file since c280d7e was dc12262, checked in by Martin Decky <martin@…>, 8 years ago

add standardized case fallthrough comment annotations, add actual missing breaks

GCC 7.1's attribute((fallthrough)) would be more elegant, but unfortunatelly this annotation is incompatible with previous versions of GCC (it generates an empty declaration error)

  • Property mode set to 100644
File size: 10.4 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 Backend for integer conversions.
33 */
34
35#define LIBPOSIX_INTERNAL
36#define __POSIX_DEF__(x) posix_##x
37
38#include "../internal/common.h"
39#include "posix/stdlib.h"
40
41#include "posix/ctype.h"
42#include "posix/errno.h"
43#include "posix/inttypes.h"
44#include "posix/limits.h"
45
46/**
47 * Decides whether a digit belongs to a particular base.
48 *
49 * @param c Character representation of the digit.
50 * @param base Base against which the digit shall be tested.
51 * @return True if the digit belongs to the base, false otherwise.
52 */
53static inline bool is_digit_in_base(int c, int base)
54{
55 if (base <= 10) {
56 return c >= '0' && c < '0' + base;
57 } else {
58 return isdigit(c) ||
59 (tolower(c) >= 'a' && tolower(c) < ('a' + base - 10));
60 }
61}
62
63/**
64 * Derive a digit from its character representation.
65 *
66 * @param c Character representation of the digit.
67 * @return Digit value represented by an integer.
68 */
69static inline int digit_value(int c)
70{
71 if (c <= '9') {
72 return c - '0';
73 } else {
74 return 10 + tolower(c) - 'a';
75 }
76}
77
78/**
79 * Generic function for parsing an integer from it's string representation.
80 * Different variants differ in lower and upper bounds.
81 * The parsed string returned by this function is always positive, sign
82 * information is provided via a dedicated parameter.
83 *
84 * @param nptr Input string.
85 * @param endptr If non-NULL, *endptr is set to the position of the first
86 * unrecognized character. If no digit has been parsed, value of
87 * nptr is stored there (regardless of any skipped characters at the
88 * beginning).
89 * @param base Expected base of the string representation. If 0, base is
90 * determined to be decimal, octal or hexadecimal using the same rules
91 * as C syntax. Otherwise, value must be between 2 and 36, inclusive.
92 * @param min_value Lower bound for the resulting conversion.
93 * @param max_value Upper bound for the resulting conversion.
94 * @param out_negative Either NULL for unsigned conversion or a pointer to the
95 * bool variable into which shall be placed the negativity of the resulting
96 * converted value.
97 * @return The absolute value of the parsed value, or the closest in-range value
98 * if the parsed value is out of range. If the input is invalid, zero is
99 * returned and errno is set to EINVAL.
100 */
101static inline uintmax_t internal_strtol(
102 const char *restrict nptr, char **restrict endptr, int base,
103 const intmax_t min_value, const uintmax_t max_value,
104 bool *restrict out_negative)
105{
106 if (nptr == NULL) {
107 errno = EINVAL;
108 return 0;
109 }
110
111 if (base < 0 || base == 1 || base > 36) {
112 errno = EINVAL;
113 return 0;
114 }
115
116 /* The maximal absolute value that can be returned in this run.
117 * Depends on sign.
118 */
119 uintmax_t real_max_value = max_value;
120
121 /* Current index in the input string. */
122 size_t i = 0;
123 bool negative = false;
124
125 /* Skip whitespace. */
126 while (isspace(nptr[i])) {
127 i++;
128 }
129
130 /* Parse sign. */
131 switch (nptr[i]) {
132 case '-':
133 negative = true;
134
135 /* The strange computation is are there to avoid a corner case
136 * where -min_value can't be represented in intmax_t.
137 * (I'm not exactly sure what the semantics are in such a
138 * case, but this should be safe for any case.)
139 */
140 real_max_value = (min_value == 0)
141 ? 0
142 :(((uintmax_t) -(min_value + 1)) + 1);
143
144 /* Fallthrough */
145 case '+':
146 i++;
147 }
148
149 /* Figure out the base. */
150 switch (base) {
151 case 0:
152 if (nptr[i] == '0') {
153 if (tolower(nptr[i + 1]) == 'x') {
154 /* 0x... is hex. */
155 base = 16;
156 i += 2;
157 } else {
158 /* 0... is octal. */
159 base = 8;
160 }
161 } else {
162 /* Anything else is decimal by default. */
163 base = 10;
164 }
165 break;
166 case 16:
167 /* Allow hex number to be prefixed with "0x". */
168 if (nptr[i] == '0' && tolower(nptr[i + 1]) == 'x') {
169 i += 2;
170 }
171 break;
172 }
173
174 if (!is_digit_in_base(nptr[i], base)) {
175 /* No digits to parse, invalid input. */
176
177 errno = EINVAL;
178 if (endptr != NULL) {
179 *endptr = (char *) nptr;
180 }
181 return 0;
182 }
183
184 /* Maximal value to which a digit can be added without a risk
185 * of overflow.
186 */
187 uintmax_t max_safe_value = (real_max_value - base + 1) / base;
188
189 uintmax_t result = 0;
190
191 if (real_max_value == 0) {
192 /* Special case when a negative number is parsed as
193 * unsigned integer. Only -0 is accepted.
194 */
195
196 while (is_digit_in_base(nptr[i], base)) {
197 if (nptr[i] != '0') {
198 errno = ERANGE;
199 result = 0;
200 }
201 i++;
202 }
203 }
204
205 while (is_digit_in_base(nptr[i], base)) {
206 int digit = digit_value(nptr[i]);
207
208 if (result > max_safe_value) {
209 /* corner case, check for overflow */
210
211 uintmax_t boundary = (real_max_value - digit) / base;
212
213 if (result > boundary) {
214 /* overflow */
215 errno = ERANGE;
216 result = real_max_value;
217 break;
218 }
219 }
220
221 result = result * base + digit;
222 i++;
223 }
224
225 if (endptr != NULL) {
226 /* Move the pointer to the end of the number,
227 * in case it isn't there already.
228 */
229 while (is_digit_in_base(nptr[i], base)) {
230 i++;
231 }
232
233 *endptr = (char *) &nptr[i];
234 }
235 if (out_negative != NULL) {
236 *out_negative = negative;
237 }
238 return result;
239}
240
241/**
242 * Convert a string to an integer.
243 *
244 * @param nptr Input string.
245 * @return Result of the conversion.
246 */
247int posix_atoi(const char *nptr)
248{
249 bool neg = false;
250 uintmax_t result =
251 internal_strtol(nptr, NULL, 10, INT_MIN, INT_MAX, &neg);
252
253 return (neg ? ((int) -result) : (int) result);
254}
255
256/**
257 * Convert a string to a long integer.
258 *
259 * @param nptr Input string.
260 * @return Result of the conversion.
261 */
262long posix_atol(const char *nptr)
263{
264 bool neg = false;
265 uintmax_t result =
266 internal_strtol(nptr, NULL, 10, LONG_MIN, LONG_MAX, &neg);
267
268 return (neg ? ((long) -result) : (long) result);
269}
270
271/**
272 * Convert a string to a long long integer.
273 *
274 * @param nptr Input string.
275 * @return Result of the conversion.
276 */
277long long posix_atoll(const char *nptr)
278{
279 bool neg = false;
280 uintmax_t result =
281 internal_strtol(nptr, NULL, 10, LLONG_MIN, LLONG_MAX, &neg);
282
283 return (neg ? ((long long) -result) : (long long) result);
284}
285
286/**
287 * Convert a string to a long integer.
288 *
289 * @param nptr Input string.
290 * @param endptr Pointer to the final part of the string which
291 * was not used for conversion.
292 * @param base Expected base of the string representation.
293 * @return Result of the conversion.
294 */
295long posix_strtol(const char *restrict nptr, char **restrict endptr, int base)
296{
297 bool neg = false;
298 uintmax_t result =
299 internal_strtol(nptr, endptr, base, LONG_MIN, LONG_MAX, &neg);
300
301 return (neg ? ((long) -result) : ((long) result));
302}
303
304/**
305 * Convert a string to a long long integer.
306 *
307 * @param nptr Input string.
308 * @param endptr Pointer to the final part of the string which
309 * was not used for conversion.
310 * @param base Expected base of the string representation.
311 * @return Result of the conversion.
312 */
313long long posix_strtoll(
314 const char *restrict nptr, char **restrict endptr, int base)
315{
316 bool neg = false;
317 uintmax_t result =
318 internal_strtol(nptr, endptr, base, LLONG_MIN, LLONG_MAX, &neg);
319
320 return (neg ? ((long long) -result) : (long long) result);
321}
322
323/**
324 * Convert a string to a largest signed integer type.
325 *
326 * @param nptr Input string.
327 * @param endptr Pointer to the final part of the string which
328 * was not used for conversion.
329 * @param base Expected base of the string representation.
330 * @return Result of the conversion.
331 */
332intmax_t posix_strtoimax(
333 const char *restrict nptr, char **restrict endptr, int base)
334{
335 bool neg = false;
336 uintmax_t result =
337 internal_strtol(nptr, endptr, base, INTMAX_MIN, INTMAX_MAX, &neg);
338
339 return (neg ? ((intmax_t) -result) : (intmax_t) result);
340}
341
342/**
343 * Convert a string to an unsigned long integer.
344 *
345 * @param nptr Input string.
346 * @param endptr Pointer to the final part of the string which
347 * was not used for conversion.
348 * @param base Expected base of the string representation.
349 * @return Result of the conversion.
350 */
351unsigned long posix_strtoul(
352 const char *restrict nptr, char **restrict endptr, int base)
353{
354 uintmax_t result =
355 internal_strtol(nptr, endptr, base, 0, ULONG_MAX, NULL);
356
357 return (unsigned long) result;
358}
359
360/**
361 * Convert a string to an unsigned long long integer.
362 *
363 * @param nptr Input string.
364 * @param endptr Pointer to the final part of the string which
365 * was not used for conversion.
366 * @param base Expected base of the string representation.
367 * @return Result of the conversion.
368 */
369unsigned long long posix_strtoull(
370 const char *restrict nptr, char **restrict endptr, int base)
371{
372 uintmax_t result =
373 internal_strtol(nptr, endptr, base, 0, ULLONG_MAX, NULL);
374
375 return (unsigned long long) result;
376}
377
378/**
379 * Convert a string to a largest unsigned integer type.
380 *
381 * @param nptr Input string.
382 * @param endptr Pointer to the final part of the string which
383 * was not used for conversion.
384 * @param base Expected base of the string representation.
385 * @return Result of the conversion.
386 */
387uintmax_t posix_strtoumax(
388 const char *restrict nptr, char **restrict endptr, int base)
389{
390 uintmax_t result =
391 internal_strtol(nptr, endptr, base, 0, UINTMAX_MAX, NULL);
392
393 return result;
394}
395
396/** @}
397 */
Note: See TracBrowser for help on using the repository browser.