Refactor missing prototypes 2 (#14170)
[betaflight.git] / src / main / common / strtol.c
blobf94f3fc38df6768434e26756015780ccd7f301fa
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
22 #include <ctype.h>
23 #include <limits.h>
25 #include "platform.h"
27 #include "common/utils.h"
29 #include "strtol.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;
36 #if _STRTO_ENDPTR
37 const char *fail_char;
38 #define SET_FAIL(X) fail_char = (X)
39 #else
40 #define SET_FAIL(X) ((void)(X)) /* Keep side effects. */
41 #endif
42 unsigned char negative, digit, cutoff_digit;
44 SET_FAIL(str);
46 while (isspace(*str)) { /* Skip leading whitespace. */
47 ++str;
50 /* Handle optional sign. */
51 negative = 0;
52 switch (*str) {
53 case '-':
54 negative = 1; /* Fall through to increment str. */
55 FALLTHROUGH;
56 case '+':
57 ++str;
60 if (!base || base == 16 || base == 2) { /* Either dynamic (base = 0) or base with 0[xb] prefix. */
61 if (*str == '0') {
62 SET_FAIL(++str);
63 if ((!base || base == 16) && tolower(*str) == 'x') {
64 ++str;
65 base = 16;
66 } else if ((!base || base == 2) && tolower(*str) == 'b') {
67 ++str;
68 base = 2;
69 } else if(!base) {
70 base = 8;
75 number = 0;
77 if (((unsigned)(base - 2)) < 35) { /* Legal base. */
78 cutoff_digit = ULONG_MAX % base;
79 cutoff = ULONG_MAX / base;
80 do {
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 */);
87 if (digit >= base) {
88 break;
91 SET_FAIL(++str);
93 if ((number > cutoff)
94 || ((number == cutoff) && (digit > cutoff_digit))) {
95 number = ULONG_MAX;
96 negative &= sflag;
97 } else {
98 number = number * base + digit;
100 } while (1);
103 #if _STRTO_ENDPTR
104 if (endptr) {
105 *endptr = (char *) fail_char;
107 #endif
110 unsigned long tmp = (negative
111 ? ((unsigned long)(-(1+LONG_MIN)))+1
112 : LONG_MAX);
113 if (sflag && (number > tmp)) {
114 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);