Merge pull request #11297 from SteveCEvans/baro_state
[betaflight.git] / src / main / common / strtol.c
blobb14ce8d369c5299a1b4ee17f7c318175ebd0d85c
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
23 #include <ctype.h>
24 #include <limits.h>
26 #include "platform.h"
28 #include "common/utils.h"
30 #define _STRTO_ENDPTR 1
32 unsigned long _strto_l(const char * str, char ** endptr, int base, int sflag)
34 unsigned long number, cutoff;
35 #if _STRTO_ENDPTR
36 const char *fail_char;
37 #define SET_FAIL(X) fail_char = (X)
38 #else
39 #define SET_FAIL(X) ((void)(X)) /* Keep side effects. */
40 #endif
41 unsigned char negative, digit, cutoff_digit;
43 SET_FAIL(str);
45 while (isspace(*str)) { /* Skip leading whitespace. */
46 ++str;
49 /* Handle optional sign. */
50 negative = 0;
51 switch (*str) {
52 case '-':
53 negative = 1; /* Fall through to increment str. */
54 FALLTHROUGH;
55 case '+':
56 ++str;
59 if (!base || base == 16 || base == 2) { /* Either dynamic (base = 0) or base with 0[xb] prefix. */
60 if (*str == '0') {
61 SET_FAIL(++str);
62 if ((!base || base == 16) && tolower(*str) == 'x') {
63 ++str;
64 base = 16;
65 } else if ((!base || base == 2) && tolower(*str) == 'b') {
66 ++str;
67 base = 2;
68 } else if(!base) {
69 base = 8;
74 number = 0;
76 if (((unsigned)(base - 2)) < 35) { /* Legal base. */
77 cutoff_digit = ULONG_MAX % base;
78 cutoff = ULONG_MAX / base;
79 do {
80 digit = ( (*str - '0') <= 9)
81 ? /* 0..9 */ (*str - '0')
82 : /* else */ (((0x20 | *str) >= 'a') /* WARNING: assumes ascii. */
83 ? /* >= A/a */ ((0x20 | *str) - ('a' - 10))
84 : /* else */ 40 /* bad value */);
86 if (digit >= base) {
87 break;
90 SET_FAIL(++str);
92 if ((number > cutoff)
93 || ((number == cutoff) && (digit > cutoff_digit))) {
94 number = ULONG_MAX;
95 negative &= sflag;
96 } else {
97 number = number * base + digit;
99 } while (1);
102 #if _STRTO_ENDPTR
103 if (endptr) {
104 *endptr = (char *) fail_char;
106 #endif
109 unsigned long tmp = (negative
110 ? ((unsigned long)(-(1+LONG_MIN)))+1
111 : LONG_MAX);
112 if (sflag && (number > tmp)) {
113 number = tmp;
117 return negative ? (unsigned long)(-((long)number)) : number;
120 long strtol(const char * str, char ** endptr, int base)
122 return _strto_l(str, endptr, base, 1);
125 unsigned long strtoul(const char * str, char ** endptr, int base)
127 return _strto_l(str, endptr, base, 0);
130 int atoi(const char *str)
132 return strtol(str, NULL, 10);