1 /* Copyright (C) 2002 Manuel Novoa III
2 * From my (incomplete) stdlib library for linux and (soon) elks.
4 * This library is free software; you can redistribute it and/or
5 * modify it under the terms of the GNU Library General Public
6 * License as published by the Free Software Foundation; either
7 * version 2 of the License, or (at your option) any later version.
9 * This library is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12 * Library General Public License for more details.
14 * You should have received a copy of the GNU Library General Public
15 * License along with this library; if not, see
16 * <http://www.gnu.org/licenses/>.
18 * Adapted for Betaflight by Petr Ledvina, 2018
27 #include "common/utils.h"
31 #define _STRTO_ENDPTR 1
33 static unsigned long _strto_l(const char * str
, char ** endptr
, int base
, int sflag
)
35 unsigned long number
, cutoff
;
37 const char *fail_char
;
38 #define SET_FAIL(X) fail_char = (X)
40 #define SET_FAIL(X) ((void)(X)) /* Keep side effects. */
42 unsigned char negative
, digit
, cutoff_digit
;
46 while (isspace(*str
)) { /* Skip leading whitespace. */
50 /* Handle optional sign. */
54 negative
= 1; /* Fall through to increment str. */
60 if (!base
|| base
== 16 || base
== 2) { /* Either dynamic (base = 0) or base with 0[xb] prefix. */
63 if ((!base
|| base
== 16) && tolower(*str
) == 'x') {
66 } else if ((!base
|| base
== 2) && tolower(*str
) == 'b') {
77 if (((unsigned)(base
- 2)) < 35) { /* Legal base. */
78 cutoff_digit
= ULONG_MAX
% base
;
79 cutoff
= ULONG_MAX
/ base
;
81 digit
= ( (*str
- '0') <= 9)
82 ? /* 0..9 */ (*str
- '0')
83 : /* else */ (((0x20 | *str
) >= 'a') /* WARNING: assumes ascii. */
84 ? /* >= A/a */ ((0x20 | *str
) - ('a' - 10))
85 : /* else */ 40 /* bad value */);
94 || ((number
== cutoff
) && (digit
> cutoff_digit
))) {
98 number
= number
* base
+ digit
;
105 *endptr
= (char *) fail_char
;
110 unsigned long tmp
= (negative
111 ? ((unsigned long)(-(1+LONG_MIN
)))+1
113 if (sflag
&& (number
> tmp
)) {
118 return negative
? (unsigned long)(-((long)number
)) : number
;
121 long strtol(const char * str
, char ** endptr
, int base
)
123 return _strto_l(str
, endptr
, base
, 1);
126 unsigned long strtoul(const char * str
, char ** endptr
, int base
)
128 return _strto_l(str
, endptr
, base
, 0);
131 int atoi(const char *str
)
133 return strtol(str
, NULL
, 10);