From 2abcaebd8129a360c44be32d50c23e1aa49ff06e Mon Sep 17 00:00:00 2001 From: Petr Ledvina Date: Mon, 12 Mar 2018 21:24:15 +0100 Subject: [PATCH] Reimplement strtol/strtoul/atoi (#5400) newlibc version is pulling in (part of) locale support Adapted from uClibc source code Addded support for 0b.... prefix for binary numbers --- make/source.mk | 1 + src/main/common/strtol.c | 131 +++++++++++++++++++++++++++++++++++++++ 2 files changed, 132 insertions(+) create mode 100644 src/main/common/strtol.c diff --git a/make/source.mk b/make/source.mk index ed430360b1..4a28c95c0b 100644 --- a/make/source.mk +++ b/make/source.mk @@ -15,6 +15,7 @@ COMMON_SRC = \ common/printf.c \ common/streambuf.c \ common/string_light.c \ + common/strtol.c \ common/time.c \ common/typeconversion.c \ config/config_eeprom.c \ diff --git a/src/main/common/strtol.c b/src/main/common/strtol.c new file mode 100644 index 0000000000..18300d5623 --- /dev/null +++ b/src/main/common/strtol.c @@ -0,0 +1,131 @@ +/* Copyright (C) 2002 Manuel Novoa III + * From my (incomplete) stdlib library for linux and (soon) elks. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public + * License along with this library; if not, see + * . + + * Adapted for Betaflight by Petr Ledvina, 2018 + + */ + + +#include +#include + +#include "common/utils.h" + +#define _STRTO_ENDPTR 1 + +unsigned long _strto_l(const char * str, char ** endptr, int base, int sflag) +{ + unsigned long number, cutoff; +#if _STRTO_ENDPTR + const char *fail_char; +#define SET_FAIL(X) fail_char = (X) +#else +#define SET_FAIL(X) ((void)(X)) /* Keep side effects. */ +#endif + unsigned char negative, digit, cutoff_digit; + + SET_FAIL(str); + + while (isspace(*str)) { /* Skip leading whitespace. */ + ++str; + } + + /* Handle optional sign. */ + negative = 0; + switch (*str) { + case '-': + negative = 1; /* Fall through to increment str. */ + FALLTHROUGH; + case '+': + ++str; + } + + if (!base || base == 16 || base == 2) { /* Either dynamic (base = 0) or base with 0[xb] prefix. */ + if (*str == '0') { + SET_FAIL(++str); + if ((!base || base == 16) && tolower(*str) == 'x') { + ++str; + base = 16; + } else if ((!base || base == 2) && tolower(*str) == 'b') { + ++str; + base = 2; + } else if(!base) { + base = 8; + } + } + } + + number = 0; + + if (((unsigned)(base - 2)) < 35) { /* Legal base. */ + cutoff_digit = ULONG_MAX % base; + cutoff = ULONG_MAX / base; + do { + digit = ( (*str - '0') <= 9) + ? /* 0..9 */ (*str - '0') + : /* else */ (((0x20 | *str) >= 'a') /* WARNING: assumes ascii. */ + ? /* >= A/a */ ((0x20 | *str) - ('a' - 10)) + : /* else */ 40 /* bad value */); + + if (digit >= base) { + break; + } + + SET_FAIL(++str); + + if ((number > cutoff) + || ((number == cutoff) && (digit > cutoff_digit))) { + number = ULONG_MAX; + negative &= sflag; + } else { + number = number * base + digit; + } + } while (1); + } + +#if _STRTO_ENDPTR + if (endptr) { + *endptr = (char *) fail_char; + } +#endif + + { + unsigned long tmp = (negative + ? ((unsigned long)(-(1+LONG_MIN)))+1 + : LONG_MAX); + if (sflag && (number > tmp)) { + number = tmp; + } + } + + return negative ? (unsigned long)(-((long)number)) : number; +} + +long strtol(const char * str, char ** endptr, int base) +{ + return _strto_l(str, endptr, base, 1); +} + +unsigned long strtoul(const char * str, char ** endptr, int base) +{ + return _strto_l(str, endptr, base, 0); +} + +int atoi(const char *str) +{ + return strtol(str, NULL, 10); +}