Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
29 changes: 27 additions & 2 deletions api/String.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@
#include "deprecated-avr-comp/avr/dtostrf.h"

#include <float.h>
#include <limits.h>

namespace arduino {

Expand Down Expand Up @@ -732,8 +733,32 @@ void String::trim(void)

long String::toInt(void) const
{
if (buffer) return atol(buffer);
return 0;
if (!buffer) return 0;

char const *p = buffer;
while (isspace(static_cast<unsigned char>(*p))) p++;

bool const negative = *p == '-';
if (negative || *p == '+') p++;

unsigned long value = 0;
unsigned long const negative_limit = static_cast<unsigned long>(-(LONG_MIN + 1L)) + 1UL;
unsigned long const limit = negative
? negative_limit
: static_cast<unsigned long>(LONG_MAX);
unsigned long const cutoff = limit / 10UL;
unsigned long const cutlim = limit % 10UL;

while (isdigit(static_cast<unsigned char>(*p))) {
unsigned long const digit = static_cast<unsigned long>(*p - '0');
if (value > cutoff || (value == cutoff && digit > cutlim)) return 0;
value = value * 10UL + digit;
p++;
}

if (!negative) return static_cast<long>(value);
if (value == negative_limit) return LONG_MIN;
return -static_cast<long>(value);
}

float String::toFloat(void) const
Expand Down
37 changes: 37 additions & 0 deletions test/src/String/test_toInt.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,9 @@

#include <catch2/catch_test_macros.hpp>

#include <climits>
#include <string>

#include <api/String.h>

#include "StringPrinter.h"
Expand Down Expand Up @@ -45,3 +48,37 @@ TEST_CASE ("Testing String::toInt when string does not have a buffer", "[String-
arduino::String str(buffer);
REQUIRE(str.toInt() == 0);
}

TEST_CASE ("Testing String::toInt when string exceeds the long range", "[String-toInt-05]")
{
unsigned long const minimum_magnitude = static_cast<unsigned long>(-(LONG_MIN + 1L)) + 1UL;
std::string const one_past_maximum = std::to_string(static_cast<unsigned long>(LONG_MAX) + 1UL);
std::string const one_past_minimum = "-" + std::to_string(minimum_magnitude + 1UL);
arduino::String positive_boundary(one_past_maximum.c_str());
arduino::String negative_boundary(one_past_minimum.c_str());
arduino::String positive("999999999999999999999999999999999999");
arduino::String negative("-999999999999999999999999999999999999");

REQUIRE(positive_boundary.toInt() == 0);
REQUIRE(negative_boundary.toInt() == 0);
REQUIRE(positive.toInt() == 0);
REQUIRE(negative.toInt() == 0);
}

TEST_CASE ("Testing String::toInt at the long range limits", "[String-toInt-06]")
{
arduino::String maximum(std::to_string(LONG_MAX).c_str());
arduino::String minimum(std::to_string(LONG_MIN).c_str());

REQUIRE(maximum.toInt() == LONG_MAX);
REQUIRE(minimum.toInt() == LONG_MIN);
}

TEST_CASE ("Testing String::toInt keeps atol parsing behavior", "[String-toInt-07]")
{
arduino::String negative(" \t-123abc");
arduino::String positive("+456xyz");

REQUIRE(negative.toInt() == -123);
REQUIRE(positive.toInt() == 456);
}
Loading