2 * Copyright (c) 2005 Martin Decky
3 * Copyright (c) 2008 Jiri Svoboda
4 * Copyright (c) 2011 Martin Sucha
5 * Copyright (c) 2011 Oleg Romanenko
6 * Copyright (c) 2011 Jiri Zarevucky
9 * Redistribution and use in source and binary forms, with or without
10 * modification, are permitted provided that the following conditions
13 * - Redistributions of source code must retain the above copyright
14 * notice, this list of conditions and the following disclaimer.
15 * - Redistributions in binary form must reproduce the above copyright
16 * notice, this list of conditions and the following disclaimer in the
17 * documentation and/or other materials provided with the distribution.
18 * - The name of the author may not be used to endorse or promote products
19 * derived from this software without specific prior written permission.
21 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
22 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
23 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
24 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
25 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
26 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
27 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
28 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
29 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
30 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
48 // FIXME: The original HelenOS functions return EOVERFLOW instead
49 // of ERANGE. It's a pointless distinction from standard functions,
50 // so we should change that. Beware the callers though.
52 // TODO: more unit tests
54 static inline int _digit_value(int c
)
58 } else if (islower(c
)) {
60 } else if (isupper(c
)) {
67 * FIXME: workaround for GCC "optimizing" the overflow check
68 * into soft-emulated 128b multiplication using `__multi3`,
69 * which we don't currently implement.
71 __attribute__((noinline
)) static uintmax_t _max_value(int base
)
73 return UINTMAX_MAX
/ base
;
76 static inline int _prefixbase(const char *restrict
*nptrptr
, bool nonstd
)
78 const char *nptr
= *nptrptr
;
83 if (nptr
[1] == 'x' || nptr
[1] == 'X') {
84 if (_digit_value(nptr
[2]) < 16) {
94 if (_digit_value(nptr
[2]) < 2) {
101 if (_digit_value(nptr
[2]) < 8) {
110 if (_digit_value(nptr
[2]) < 10) {
121 static inline uintmax_t _strtoumax(
122 const char *restrict nptr
, char **restrict endptr
, int base
,
123 bool *restrict sgn
, errno_t
*err
, bool nonstd
)
125 assert(nptr
!= NULL
);
128 const char *first
= nptr
;
130 /* Skip leading whitespace. */
132 while (isspace(*nptr
)) {
136 /* Parse sign, if any. */
148 /* Figure out the base. */
151 base
= _prefixbase(&nptr
, nonstd
);
153 if (base
== 16 && !nonstd
) {
155 * Standard strto* functions allow hexadecimal prefix to be
156 * present when base is explicitly set to 16.
157 * Our nonstandard str_* functions don't allow it.
158 * I don't know if that is intended, just matching the original
159 * functionality here.
162 if (nptr
[0] == '0' && (nptr
[1] == 'x' || nptr
[1] == 'X') &&
163 _digit_value(nptr
[2]) < base
)
167 if (base
< 2 || base
> 36) {
172 /* Must be at least one digit. */
174 if (_digit_value(*nptr
) >= base
) {
175 /* No digits on input. */
177 *endptr
= (char *) first
;
181 /* Read the value. */
183 uintmax_t result
= 0;
184 uintmax_t max
= _max_value(base
);
187 while (digit
= _digit_value(*nptr
), digit
< base
) {
189 __builtin_add_overflow(result
* base
, digit
, &result
)) {
191 *err
= nonstd
? EOVERFLOW
: ERANGE
;
192 result
= UINTMAX_MAX
;
201 if (endptr
!= NULL
) {
203 * Move the pointer to the end of the number,
204 * in case it isn't there already.
205 * This can happen when the number has legal formatting,
206 * but is out of range of the target type.
208 while (_digit_value(*nptr
) < base
) {
212 *endptr
= (char *) nptr
;
218 static inline intmax_t _strtosigned(const char *nptr
, char **endptr
, int base
,
219 intmax_t min
, intmax_t max
, errno_t
*err
, bool nonstd
)
222 uintmax_t number
= _strtoumax(nptr
, endptr
, base
, &sgn
, err
, nonstd
);
224 if (number
> (uintmax_t) max
) {
225 if (sgn
&& (number
- 1 == (uintmax_t) max
)) {
229 *err
= nonstd
? EOVERFLOW
: ERANGE
;
230 return (sgn
? min
: max
);
233 return (sgn
? -number
: number
);
236 static inline uintmax_t _strtounsigned(const char *nptr
, char **endptr
, int base
,
237 uintmax_t max
, errno_t
*err
, bool nonstd
)
240 uintmax_t number
= _strtoumax(nptr
, endptr
, base
, &sgn
, err
, nonstd
);
243 /* Do not allow negative values */
249 *err
= nonstd
? EOVERFLOW
: ERANGE
;
253 return (sgn
? -number
: number
);
256 /** Convert initial part of string to long int according to given base.
257 * The number may begin with an arbitrary number of whitespaces followed by
258 * optional sign (`+' or `-'). If the base is 0 or 16, the prefix `0x' may be
259 * inserted and the number will be taken as hexadecimal one. If the base is 0
260 * and the number begin with a zero, number will be taken as octal one (as with
261 * base 8). Otherwise the base 0 is taken as decimal.
263 * @param nptr Pointer to string.
264 * @param[out] endptr If not NULL, function stores here pointer to the first
266 * @param base Zero or number between 2 and 36 inclusive.
267 * @return Result of conversion.
269 long strtol(const char *nptr
, char **endptr
, int base
)
275 return _strtosigned(nptr
, endptr
, base
, LONG_MIN
, LONG_MAX
, &errno
, false);
278 /** Convert initial part of string to unsigned long according to given base.
279 * The number may begin with an arbitrary number of whitespaces followed by
280 * optional sign (`+' or `-'). If the base is 0 or 16, the prefix `0x' may be
281 * inserted and the number will be taken as hexadecimal one. If the base is 0
282 * and the number begin with a zero, number will be taken as octal one (as with
283 * base 8). Otherwise the base 0 is taken as decimal.
285 * @param nptr Pointer to string.
286 * @param[out] endptr If not NULL, function stores here pointer to the first
288 * @param base Zero or number between 2 and 36 inclusive.
289 * @return Result of conversion.
291 unsigned long strtoul(const char *nptr
, char **endptr
, int base
)
297 return _strtounsigned(nptr
, endptr
, base
, ULONG_MAX
, &errno
, false);
300 long long strtoll(const char *nptr
, char **endptr
, int base
)
306 return _strtosigned(nptr
, endptr
, base
, LLONG_MIN
, LLONG_MAX
, &errno
, false);
309 unsigned long long strtoull(const char *nptr
, char **endptr
, int base
)
315 return _strtounsigned(nptr
, endptr
, base
, ULLONG_MAX
, &errno
, false);
318 intmax_t strtoimax(const char *nptr
, char **endptr
, int base
)
324 return _strtosigned(nptr
, endptr
, base
, INTMAX_MIN
, INTMAX_MAX
, &errno
, false);
327 uintmax_t strtoumax(const char *nptr
, char **endptr
, int base
)
333 return _strtounsigned(nptr
, endptr
, base
, UINTMAX_MAX
, &errno
, false);
336 int atoi(const char *nptr
)
338 return (int)strtol(nptr
, NULL
, 10);
341 long atol(const char *nptr
)
343 return strtol(nptr
, NULL
, 10);
346 long long atoll(const char *nptr
)
348 return strtoll(nptr
, NULL
, 10);
351 /** Convert string to uint8_t.
353 * @param nptr Pointer to string.
354 * @param endptr If not NULL, pointer to the first invalid character
356 * @param base Zero or number between 2 and 36 inclusive.
357 * @param strict Do not allow any trailing characters.
358 * @param result Result of the conversion.
360 * @return EOK if conversion was successful.
363 errno_t
str_uint8_t(const char *nptr
, const char **endptr
, unsigned int base
,
364 bool strict
, uint8_t *result
)
366 assert(result
!= NULL
);
369 char *lendptr
= (char *) nptr
;
371 uintmax_t r
= _strtounsigned(nptr
, &lendptr
, base
, UINT8_MAX
, &rc
, true);
379 if (strict
&& *lendptr
!= '\0')
386 /** Convert string to uint16_t.
388 * @param nptr Pointer to string.
389 * @param endptr If not NULL, pointer to the first invalid character
391 * @param base Zero or number between 2 and 36 inclusive.
392 * @param strict Do not allow any trailing characters.
393 * @param result Result of the conversion.
395 * @return EOK if conversion was successful.
398 errno_t
str_uint16_t(const char *nptr
, const char **endptr
, unsigned int base
,
399 bool strict
, uint16_t *result
)
401 assert(result
!= NULL
);
404 char *lendptr
= (char *) nptr
;
406 uintmax_t r
= _strtounsigned(nptr
, &lendptr
, base
, UINT16_MAX
, &rc
, true);
414 if (strict
&& *lendptr
!= '\0')
421 /** Convert string to uint32_t.
423 * @param nptr Pointer to string.
424 * @param endptr If not NULL, pointer to the first invalid character
426 * @param base Zero or number between 2 and 36 inclusive.
427 * @param strict Do not allow any trailing characters.
428 * @param result Result of the conversion.
430 * @return EOK if conversion was successful.
433 errno_t
str_uint32_t(const char *nptr
, const char **endptr
, unsigned int base
,
434 bool strict
, uint32_t *result
)
436 assert(result
!= NULL
);
439 char *lendptr
= (char *) nptr
;
441 uintmax_t r
= _strtounsigned(nptr
, &lendptr
, base
, UINT32_MAX
, &rc
, true);
449 if (strict
&& *lendptr
!= '\0')
456 /** Convert string to uint64_t.
458 * @param nptr Pointer to string.
459 * @param endptr If not NULL, pointer to the first invalid character
461 * @param base Zero or number between 2 and 36 inclusive.
462 * @param strict Do not allow any trailing characters.
463 * @param result Result of the conversion.
465 * @return EOK if conversion was successful.
468 errno_t
str_uint64_t(const char *nptr
, const char **endptr
, unsigned int base
,
469 bool strict
, uint64_t *result
)
471 assert(result
!= NULL
);
474 char *lendptr
= (char *) nptr
;
476 uintmax_t r
= _strtounsigned(nptr
, &lendptr
, base
, UINT64_MAX
, &rc
, true);
484 if (strict
&& *lendptr
!= '\0')
491 /** Convert string to int64_t.
493 * @param nptr Pointer to string.
494 * @param endptr If not NULL, pointer to the first invalid character
496 * @param base Zero or number between 2 and 36 inclusive.
497 * @param strict Do not allow any trailing characters.
498 * @param result Result of the conversion.
500 * @return EOK if conversion was successful.
503 errno_t
str_int64_t(const char *nptr
, const char **endptr
, unsigned int base
,
504 bool strict
, int64_t *result
)
506 assert(result
!= NULL
);
509 char *lendptr
= (char *) nptr
;
511 intmax_t r
= _strtosigned(nptr
, &lendptr
, base
, INT64_MIN
, INT64_MAX
, &rc
, true);
519 if (strict
&& *lendptr
!= '\0')
526 /** Convert string to size_t.
528 * @param nptr Pointer to string.
529 * @param endptr If not NULL, pointer to the first invalid character
531 * @param base Zero or number between 2 and 36 inclusive.
532 * @param strict Do not allow any trailing characters.
533 * @param result Result of the conversion.
535 * @return EOK if conversion was successful.
538 errno_t
str_size_t(const char *nptr
, const char **endptr
, unsigned int base
,
539 bool strict
, size_t *result
)
541 assert(result
!= NULL
);
544 char *lendptr
= (char *) nptr
;
546 uintmax_t r
= _strtounsigned(nptr
, &lendptr
, base
, SIZE_MAX
, &rc
, true);
554 if (strict
&& *lendptr
!= '\0')