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

lfn serial ticket/834-toolchain-update topic/msim-upgrade topic/simplify-dev-export
Last change on this file since d6c98451 was d6c98451, checked in by Jiri Svoboda <jiri@…>, 10 years ago

Move (u)intmax_t to libc. Some stdint.h work.

  • Property mode set to 100644
File size: 10.4 KB
RevLine 
[2b83add]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 */
[087c8798]32/** @file Backend for integer conversions.
[2b83add]33 */
34
35#define LIBPOSIX_INTERNAL
[fdf97f6]36#define __POSIX_DEF__(x) posix_##x
[2b83add]37
38#include "../internal/common.h"
[a3da2b2]39#include "posix/stdlib.h"
[a6d908c1]40
[a3da2b2]41#include "posix/ctype.h"
42#include "posix/errno.h"
43#include "posix/inttypes.h"
44#include "posix/limits.h"
[aa5acd47]45
[087c8798]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 */
[2b83add]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
[087c8798]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 */
[aa5acd47]69static inline int digit_value(int c)
[2b83add]70{
71 if (c <= '9') {
72 return c - '0';
73 } else {
74 return 10 + tolower(c) - 'a';
75 }
76}
77
[087c8798]78/**
[aa5acd47]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.
[087c8798]83 *
84 * @param nptr Input string.
85 * @param endptr If non-NULL, *endptr is set to the position of the first
[aa5acd47]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.
[087c8798]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.
[aa5acd47]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.
[087c8798]100 */
[aa5acd47]101static inline uintmax_t internal_strtol(
[2b83add]102 const char *restrict nptr, char **restrict endptr, int base,
[aa5acd47]103 const intmax_t min_value, const uintmax_t max_value,
[2b83add]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
[aa5acd47]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;
[2b83add]120
121 /* Current index in the input string. */
[aa5acd47]122 size_t i = 0;
[2b83add]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;
[aa5acd47]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
[2b83add]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') {
[aa5acd47]154 /* 0x... is hex. */
[2b83add]155 base = 16;
156 i += 2;
157 } else {
[aa5acd47]158 /* 0... is octal. */
[2b83add]159 base = 8;
160 }
161 } else {
[aa5acd47]162 /* Anything else is decimal by default. */
[2b83add]163 base = 10;
164 }
165 break;
166 case 16:
[aa5acd47]167 /* Allow hex number to be prefixed with "0x". */
[2b83add]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 */
[aa5acd47]187 uintmax_t max_safe_value = (real_max_value - base + 1) / base;
[2b83add]188
[aa5acd47]189 uintmax_t result = 0;
[2b83add]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;
[aa5acd47]199 result = 0;
[2b83add]200 }
201 i++;
202 }
203 }
204
205 while (is_digit_in_base(nptr[i], base)) {
[aa5acd47]206 int digit = digit_value(nptr[i]);
[2b83add]207
208 if (result > max_safe_value) {
209 /* corner case, check for overflow */
210
[aa5acd47]211 uintmax_t boundary = (real_max_value - digit) / base;
[2b83add]212
213 if (result > boundary) {
214 /* overflow */
215 errno = ERANGE;
[102a729]216 result = real_max_value;
[2b83add]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
[087c8798]241/**
242 * Convert a string to an integer.
243 *
244 * @param nptr Input string.
245 * @return Result of the conversion.
246 */
[2b83add]247int posix_atoi(const char *nptr)
248{
249 bool neg = false;
[aa5acd47]250 uintmax_t result =
[2b83add]251 internal_strtol(nptr, NULL, 10, INT_MIN, INT_MAX, &neg);
252
[aa5acd47]253 return (neg ? ((int) -result) : (int) result);
[2b83add]254}
255
[087c8798]256/**
257 * Convert a string to a long integer.
258 *
259 * @param nptr Input string.
260 * @return Result of the conversion.
261 */
[2b83add]262long posix_atol(const char *nptr)
263{
264 bool neg = false;
[aa5acd47]265 uintmax_t result =
[2b83add]266 internal_strtol(nptr, NULL, 10, LONG_MIN, LONG_MAX, &neg);
267
[aa5acd47]268 return (neg ? ((long) -result) : (long) result);
[2b83add]269}
270
[087c8798]271/**
272 * Convert a string to a long long integer.
273 *
274 * @param nptr Input string.
275 * @return Result of the conversion.
276 */
[2b83add]277long long posix_atoll(const char *nptr)
278{
279 bool neg = false;
[aa5acd47]280 uintmax_t result =
[2b83add]281 internal_strtol(nptr, NULL, 10, LLONG_MIN, LLONG_MAX, &neg);
282
[aa5acd47]283 return (neg ? ((long long) -result) : (long long) result);
[2b83add]284}
285
[087c8798]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 */
[2b83add]295long posix_strtol(const char *restrict nptr, char **restrict endptr, int base)
296{
297 bool neg = false;
[aa5acd47]298 uintmax_t result =
[2b83add]299 internal_strtol(nptr, endptr, base, LONG_MIN, LONG_MAX, &neg);
300
[aa5acd47]301 return (neg ? ((long) -result) : ((long) result));
[2b83add]302}
303
[087c8798]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 */
[2b83add]313long long posix_strtoll(
314 const char *restrict nptr, char **restrict endptr, int base)
315{
316 bool neg = false;
[aa5acd47]317 uintmax_t result =
[2b83add]318 internal_strtol(nptr, endptr, base, LLONG_MIN, LLONG_MAX, &neg);
319
[aa5acd47]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);
[2b83add]340}
341
[087c8798]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 */
[2b83add]351unsigned long posix_strtoul(
352 const char *restrict nptr, char **restrict endptr, int base)
353{
[aa5acd47]354 uintmax_t result =
[2b83add]355 internal_strtol(nptr, endptr, base, 0, ULONG_MAX, NULL);
356
357 return (unsigned long) result;
358}
359
[087c8798]360/**
[aa5acd47]361 * Convert a string to an unsigned long long integer.
[087c8798]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 */
[2b83add]369unsigned long long posix_strtoull(
370 const char *restrict nptr, char **restrict endptr, int base)
371{
[aa5acd47]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;
[2b83add]394}
395
396/** @}
397 */
Note: See TracBrowser for help on using the repository browser.