diff --git a/test/unit_tests/wiring/string.cpp b/test/unit_tests/wiring/string.cpp index 64fa786dac..ada301d806 100644 --- a/test/unit_tests/wiring/string.cpp +++ b/test/unit_tests/wiring/string.cpp @@ -30,6 +30,19 @@ TEST_CASE("Can print UINT_MAX in decimal") { REQUIRE(String(UINT_MAX, DEC)=="4294967295"); } +TEST_CASE("Can print INT64_MAX/MIN value in decimal") { + // Must make an explicit `long long` cast for x86_64 architectures that + // use `long` for 64-bit numbers. + REQUIRE(String((long long)INT64_MAX, DEC)=="9223372036854775807"); + REQUIRE(String((long long)INT64_MIN, DEC)=="-9223372036854775808"); +} + +TEST_CASE("Can print UINT64_MAX in decimal") { + // Must make an explicit `unsigned long long` cast for x86_64 architectures that + // use `unsigned long` for 64-bit numbers. + REQUIRE(String((unsigned long long)UINT64_MAX, DEC)=="18446744073709551615"); +} + TEST_CASE("Can print INT_MAX value in binary") { REQUIRE(String(INT_MAX, BIN)=="1111111111111111111111111111111"); } @@ -42,6 +55,19 @@ TEST_CASE("Can print UINT_MAX in binary") { REQUIRE(String(UINT_MAX, BIN)=="11111111111111111111111111111111"); } +TEST_CASE("Can print INT64_MAX/MIN value in binary") { + // Must make an explicit `long long` cast for x86_64 architectures that + // use `long` for 64-bit numbers. + REQUIRE(String((long long)INT64_MAX, BIN)=="111111111111111111111111111111111111111111111111111111111111111"); + REQUIRE(String((long long)INT64_MIN, BIN)=="-1000000000000000000000000000000000000000000000000000000000000000"); +} + +TEST_CASE("Can print UINT64_MAX in binary") { + // Must make an explicit `unsigned long long` cast for x86_64 architectures that + // use `unsigned long` for 64-bit numbers. + REQUIRE(String((unsigned long long)UINT64_MAX, BIN)=="1111111111111111111111111111111111111111111111111111111111111111"); +} + TEST_CASE("Can convert float to string with default precision of 6") { REQUIRE(String(1.0)=="1.000000"); } @@ -101,3 +127,85 @@ TEST_CASE("Substring with left and right after the end returns until the end of TEST_CASE("Substring with flipped left and right returns the correct substring") { REQUIRE(String("test123").substring(5, 3)==String("t1")); } + +TEST_CASE("String operator +=", "[Particle::String]") { + + SECTION("Appending char array") { + String str1; + str1 += "World!"; + REQUIRE(str1 == "World!"); + } + + SECTION("Appending another String object") { + String str1("Hello"); + String str2(", World!"); + str1 += str2; + REQUIRE(str1 == "Hello, World!"); + } + + SECTION("Appending long long") { + String str1("n="); + str1 += (long long)9223372036854775807; + REQUIRE(str1 == "n=9223372036854775807"); + } + + SECTION("Appending unsigned long long") { + String str1("n="); + str1 += (unsigned long long)18446744073709551615ULL; + REQUIRE(str1 == "n=18446744073709551615"); + } +} + +TEST_CASE("String concat", "[ParticleString]") { + + SECTION("Concatenating char array") { + String str1("Hello"); + str1.concat(", World!"); + REQUIRE(str1 == "Hello, World!"); + } + + SECTION("Concatenating another String object") { + String str1("Hello"); + String str2(", World!"); + str1.concat(str2); + REQUIRE(str1 == "Hello, World!"); + } + + // TODO: Use of int type causes problems on x86_64, fine on ARM + // SECTION("Concatenating int") { + // String str1("Hello "); + // str1.concat((int)-2147483647); + // REQUIRE(str1 == "Hello -2147483647"); + // } + + // TODO: Use of unsigned int type causes problems on x86_64, fine on ARM + // SECTION("Concatenating unsigned int") { + // String str1("Hello "); + // str1.concat((unsigned int)4294967295); + // REQUIRE(str1 == "Hello 4294967295"); + // } + + SECTION("Concatenating long") { + String str1("Hello "); + str1.concat((long)-2147483647L); + REQUIRE(str1 == "Hello -2147483647"); + } + + SECTION("Concatenating unsigned long") { + String str1("Hello "); + str1.concat((unsigned long)4294967295UL); + REQUIRE(str1 == "Hello 4294967295"); + } + + SECTION("Concatenating long long") { + String str1("Hello "); + str1.concat((long long)-9223372036854775807); + REQUIRE(str1 == "Hello -9223372036854775807"); + } + + SECTION("Concatenating unsigned long long") { + String str1("Hello "); + str1.concat((unsigned long long)18446744073709551615ULL); + REQUIRE(str1 == "Hello 18446744073709551615"); + } +} diff --git a/wiring/inc/spark_wiring_string.h b/wiring/inc/spark_wiring_string.h index a912d3d828..d614d43084 100644 --- a/wiring/inc/spark_wiring_string.h +++ b/wiring/inc/spark_wiring_string.h @@ -54,169 +54,179 @@ class StringSumHelper; // The string class class String { - // use a function pointer to allow for "if (s)" without the - // complications of an operator bool(). for more information, see: - // http://www.artima.com/cppsource/safebool.html - typedef void (String::*StringIfHelperType)() const; - void StringIfHelper() const {} + // use a function pointer to allow for "if (s)" without the + // complications of an operator bool(). for more information, see: + // http://www.artima.com/cppsource/safebool.html + typedef void (String::*StringIfHelperType)() const; + void StringIfHelper() const {} public: - // constructors - // creates a copy of the initial value. - // if the initial value is null or invalid, or if memory allocation - // fails, the string will be marked as invalid (i.e. "if (s)" will - // be false). - String(const char *cstr = ""); - String(const char *cstr, unsigned int length); - String(const String &str); - String(const __FlashStringHelper *pstr); + // constructors + // creates a copy of the initial value. + // if the initial value is null or invalid, or if memory allocation + // fails, the string will be marked as invalid (i.e. "if (s)" will + // be false). + String(const char *cstr = ""); + String(const char *cstr, unsigned int length); + String(const String &str); + String(const __FlashStringHelper *pstr); String(const Printable& printable); - #ifdef __GXX_EXPERIMENTAL_CXX0X__ - String(String &&rval); - String(StringSumHelper &&rval); - #endif - explicit String(char c); - explicit String(unsigned char, unsigned char base=10); - explicit String(int, unsigned char base=10); - explicit String(unsigned int, unsigned char base=10); - explicit String(long, unsigned char base=10); - explicit String(unsigned long, unsigned char base=10); + #ifdef __GXX_EXPERIMENTAL_CXX0X__ + String(String &&rval); + String(StringSumHelper &&rval); + #endif + explicit String(char c); + explicit String(unsigned char, unsigned char base=10); + explicit String(int, unsigned char base=10); + explicit String(unsigned int, unsigned char base=10); + explicit String(long, unsigned char base=10); + explicit String(unsigned long, unsigned char base=10); + explicit String(long long, unsigned char base=10); + explicit String(unsigned long long, unsigned char base=10); explicit String(float, int decimalPlaces=6); explicit String(double, int decimalPlaces=6); - ~String(void); - - // memory management - // return true on success, false on failure (in which case, the string - // is left unchanged). reserve(0), if successful, will validate an - // invalid string (i.e., "if (s)" will be true afterwards) - unsigned char reserve(unsigned int size); - inline unsigned int length(void) const {return len;} - - // creates a copy of the assigned value. if the value is null or - // invalid, or if the memory allocation fails, the string will be - // marked as invalid ("if (s)" will be false). - String & operator = (const String &rhs); - String & operator = (const char *cstr); - String & operator = (const __FlashStringHelper *pstr); - #ifdef __GXX_EXPERIMENTAL_CXX0X__ - String & operator = (String &&rval); - String & operator = (StringSumHelper &&rval); - #endif + ~String(void); + + // memory management + // return true on success, false on failure (in which case, the string + // is left unchanged). reserve(0), if successful, will validate an + // invalid string (i.e., "if (s)" will be true afterwards) + unsigned char reserve(unsigned int size); + inline unsigned int length(void) const {return len;} + + // creates a copy of the assigned value. if the value is null or + // invalid, or if the memory allocation fails, the string will be + // marked as invalid ("if (s)" will be false). + String & operator = (const String &rhs); + String & operator = (const char *cstr); + String & operator = (const __FlashStringHelper *pstr); + #ifdef __GXX_EXPERIMENTAL_CXX0X__ + String & operator = (String &&rval); + String & operator = (StringSumHelper &&rval); + #endif operator const char*() const { return c_str(); } - // concatenate (works w/ built-in types) - - // returns true on success, false on failure (in which case, the string - // is left unchanged). if the argument is null or invalid, the - // concatenation is considered unsucessful. - unsigned char concat(const String &str); - unsigned char concat(const char *cstr); - unsigned char concat(const __FlashStringHelper * str); - unsigned char concat(char c); - unsigned char concat(unsigned char c); - unsigned char concat(int num); - unsigned char concat(unsigned int num); - unsigned char concat(long num); - unsigned char concat(unsigned long num); - unsigned char concat(float num); - unsigned char concat(double num); - - // if there's not enough memory for the concatenated value, the string - // will be left unchanged (but this isn't signalled in any way) - String & operator += (const String &rhs) {concat(rhs); return (*this);} - String & operator += (const char *cstr) {concat(cstr); return (*this);} - String & operator += (char c) {concat(c); return (*this);} - String & operator += (unsigned char num) {concat(num); return (*this);} - String & operator += (int num) {concat(num); return (*this);} - String & operator += (unsigned int num) {concat(num); return (*this);} - String & operator += (long num) {concat(num); return (*this);} - String & operator += (unsigned long num) {concat(num); return (*this);} - - friend StringSumHelper & operator + (const StringSumHelper &lhs, const String &rhs); - friend StringSumHelper & operator + (const StringSumHelper &lhs, const char *cstr); - friend StringSumHelper & operator + (const StringSumHelper &lhs, char c); - friend StringSumHelper & operator + (const StringSumHelper &lhs, unsigned char num); - friend StringSumHelper & operator + (const StringSumHelper &lhs, int num); - friend StringSumHelper & operator + (const StringSumHelper &lhs, unsigned int num); - friend StringSumHelper & operator + (const StringSumHelper &lhs, long num); - friend StringSumHelper & operator + (const StringSumHelper &lhs, unsigned long num); - friend StringSumHelper & operator + (const StringSumHelper &lhs, float num); - friend StringSumHelper & operator + (const StringSumHelper &lhs, double num); - - // comparison (only works w/ Strings and "strings") - operator StringIfHelperType() const { return buffer ? &String::StringIfHelper : 0; } - int compareTo(const String &s) const; - unsigned char equals(const String &s) const; - unsigned char equals(const char *cstr) const; - unsigned char operator == (const String &rhs) const {return equals(rhs);} - unsigned char operator == (const char *cstr) const {return equals(cstr);} - unsigned char operator != (const String &rhs) const {return !equals(rhs);} - unsigned char operator != (const char *cstr) const {return !equals(cstr);} - unsigned char operator < (const String &rhs) const; - unsigned char operator > (const String &rhs) const; - unsigned char operator <= (const String &rhs) const; - unsigned char operator >= (const String &rhs) const; - unsigned char equalsIgnoreCase(const String &s) const; - unsigned char startsWith( const String &prefix) const; - unsigned char startsWith(const String &prefix, unsigned int offset) const; - unsigned char endsWith(const String &suffix) const; - - // character acccess - char charAt(unsigned int index) const; - void setCharAt(unsigned int index, char c); - char operator [] (unsigned int index) const; - char& operator [] (unsigned int index); - void getBytes(unsigned char *buf, unsigned int bufsize, unsigned int index=0) const; - void toCharArray(char *buf, unsigned int bufsize, unsigned int index=0) const - {getBytes((unsigned char *)buf, bufsize, index);} - const char * c_str() const { return buffer; } - - // search - int indexOf( char ch ) const; - int indexOf( char ch, unsigned int fromIndex ) const; - int indexOf( const String &str ) const; - int indexOf( const String &str, unsigned int fromIndex ) const; - int lastIndexOf( char ch ) const; - int lastIndexOf( char ch, unsigned int fromIndex ) const; - int lastIndexOf( const String &str ) const; - int lastIndexOf( const String &str, unsigned int fromIndex ) const; - String substring( unsigned int beginIndex ) const; - String substring( unsigned int beginIndex, unsigned int endIndex ) const; - - // modification - String& replace(char find, char replace); - String& replace(const String& find, const String& replace); - String& remove(unsigned int index); - String& remove(unsigned int index, unsigned int count); - String& toLowerCase(void); - String& toUpperCase(void); - String& trim(void); - - // parsing/conversion - long toInt(void) const; - float toFloat(void) const; + // concatenate (works w/ built-in types) + + // returns true on success, false on failure (in which case, the string + // is left unchanged). if the argument is null or invalid, the + // concatenation is considered unsucessful. + unsigned char concat(const String &str); + unsigned char concat(const char *cstr); + unsigned char concat(const __FlashStringHelper * str); + unsigned char concat(char c); + unsigned char concat(unsigned char c); + unsigned char concat(int num); + unsigned char concat(unsigned int num); + unsigned char concat(long num); + unsigned char concat(unsigned long num); + unsigned char concat(long long num); + unsigned char concat(unsigned long long num); + unsigned char concat(float num); + unsigned char concat(double num); + + // if there's not enough memory for the concatenated value, the string + // will be left unchanged (but this isn't signalled in any way) + String & operator += (const String &rhs) {concat(rhs); return (*this);} + String & operator += (const char *cstr) {concat(cstr); return (*this);} + String & operator += (char c) {concat(c); return (*this);} + String & operator += (unsigned char num) {concat(num); return (*this);} + String & operator += (int num) {concat(num); return (*this);} + String & operator += (unsigned int num) {concat(num); return (*this);} + String & operator += (long num) {concat(num); return (*this);} + String & operator += (unsigned long num) {concat(num); return (*this);} + String & operator += (long long num) {concat(num); return (*this);} + String & operator += (unsigned long long num) {concat(num); return (*this);} + + friend StringSumHelper & operator + (const StringSumHelper &lhs, const String &rhs); + friend StringSumHelper & operator + (const StringSumHelper &lhs, const char *cstr); + friend StringSumHelper & operator + (const StringSumHelper &lhs, char c); + friend StringSumHelper & operator + (const StringSumHelper &lhs, unsigned char num); + friend StringSumHelper & operator + (const StringSumHelper &lhs, int num); + friend StringSumHelper & operator + (const StringSumHelper &lhs, unsigned int num); + friend StringSumHelper & operator + (const StringSumHelper &lhs, long num); + friend StringSumHelper & operator + (const StringSumHelper &lhs, unsigned long num); + friend StringSumHelper & operator + (const StringSumHelper &lhs, long long num); + friend StringSumHelper & operator + (const StringSumHelper &lhs, unsigned long long num); + friend StringSumHelper & operator + (const StringSumHelper &lhs, float num); + friend StringSumHelper & operator + (const StringSumHelper &lhs, double num); + + // comparison (only works w/ Strings and "strings") + operator StringIfHelperType() const { return buffer ? &String::StringIfHelper : 0; } + int compareTo(const String &s) const; + unsigned char equals(const String &s) const; + unsigned char equals(const char *cstr) const; + unsigned char operator == (const String &rhs) const {return equals(rhs);} + unsigned char operator == (const char *cstr) const {return equals(cstr);} + unsigned char operator != (const String &rhs) const {return !equals(rhs);} + unsigned char operator != (const char *cstr) const {return !equals(cstr);} + unsigned char operator < (const String &rhs) const; + unsigned char operator > (const String &rhs) const; + unsigned char operator <= (const String &rhs) const; + unsigned char operator >= (const String &rhs) const; + unsigned char equalsIgnoreCase(const String &s) const; + unsigned char startsWith( const String &prefix) const; + unsigned char startsWith(const String &prefix, unsigned int offset) const; + unsigned char endsWith(const String &suffix) const; + + // character acccess + char charAt(unsigned int index) const; + void setCharAt(unsigned int index, char c); + char operator [] (unsigned int index) const; + char& operator [] (unsigned int index); + void getBytes(unsigned char *buf, unsigned int bufsize, unsigned int index=0) const; + void toCharArray(char *buf, unsigned int bufsize, unsigned int index=0) const + {getBytes((unsigned char *)buf, bufsize, index);} + const char * c_str() const { return buffer; } + + // search + int indexOf( char ch ) const; + int indexOf( char ch, unsigned int fromIndex ) const; + int indexOf( const String &str ) const; + int indexOf( const String &str, unsigned int fromIndex ) const; + int lastIndexOf( char ch ) const; + int lastIndexOf( char ch, unsigned int fromIndex ) const; + int lastIndexOf( const String &str ) const; + int lastIndexOf( const String &str, unsigned int fromIndex ) const; + String substring( unsigned int beginIndex ) const; + String substring( unsigned int beginIndex, unsigned int endIndex ) const; + + // modification + String& replace(char find, char replace); + String& replace(const String& find, const String& replace); + String& remove(unsigned int index); + String& remove(unsigned int index, unsigned int count); + String& toLowerCase(void); + String& toUpperCase(void); + String& trim(void); + + // parsing/conversion + long toInt(void) const; + long long toLongLongInt(unsigned char base=10) const; + unsigned long long toULongLongInt(unsigned char base=10) const; + float toFloat(void) const; static String format(const char* format, ...); protected: - char *buffer; // the actual char array - unsigned int capacity; // the array length minus one (for the '\0') - unsigned int len; // the String length (not counting the '\0') - unsigned char flags; // unused, for future features + char *buffer; // the actual char array + unsigned int capacity; // the array length minus one (for the '\0') + unsigned int len; // the String length (not counting the '\0') + unsigned char flags; // unused, for future features protected: - void init(void); - void invalidate(void); - unsigned char changeBuffer(unsigned int maxStrLen); - unsigned char concat(const char *cstr, unsigned int length); + void init(void); + void invalidate(void); + unsigned char changeBuffer(unsigned int maxStrLen); + unsigned char concat(const char *cstr, unsigned int length); - // copy and move - String & copy(const char *cstr, unsigned int length); - String & copy(const __FlashStringHelper *pstr, unsigned int length); + // copy and move + String & copy(const char *cstr, unsigned int length); + String & copy(const __FlashStringHelper *pstr, unsigned int length); - #ifdef __GXX_EXPERIMENTAL_CXX0X__ - void move(String &rhs); - #endif + #ifdef __GXX_EXPERIMENTAL_CXX0X__ + void move(String &rhs); + #endif friend class StringPrintableHelper; @@ -225,14 +235,16 @@ class String class StringSumHelper : public String { public: - StringSumHelper(const String &s) : String(s) {} - StringSumHelper(const char *p) : String(p) {} - StringSumHelper(char c) : String(c) {} - StringSumHelper(unsigned char num) : String(num) {} - StringSumHelper(int num) : String(num) {} - StringSumHelper(unsigned int num) : String(num) {} - StringSumHelper(long num) : String(num) {} - StringSumHelper(unsigned long num) : String(num) {} + StringSumHelper(const String &s) : String(s) {} + StringSumHelper(const char *p) : String(p) {} + StringSumHelper(char c) : String(c) {} + StringSumHelper(unsigned char num) : String(num) {} + StringSumHelper(int num) : String(num) {} + StringSumHelper(unsigned int num) : String(num) {} + StringSumHelper(long num) : String(num) {} + StringSumHelper(unsigned long num) : String(num) {} + StringSumHelper(long long num) : String(num) {} + StringSumHelper(unsigned long long num) : String(num) {} }; #endif // __cplusplus diff --git a/wiring/src/spark_wiring_string.cpp b/wiring/src/spark_wiring_string.cpp index f75a8112b2..48bfe957cd 100644 --- a/wiring/src/spark_wiring_string.cpp +++ b/wiring/src/spark_wiring_string.cpp @@ -31,6 +31,7 @@ #include #include #include +#include #include "string_convert.h" //These are very crude implementations - will refine later @@ -68,109 +69,131 @@ void dtoa (double val, unsigned char prec, char *sout) { String::String(const char *cstr) { - init(); - if (cstr) copy(cstr, strlen(cstr)); + init(); + if (cstr) { + copy(cstr, strlen(cstr)); + } } String::String(const char *cstr, unsigned int length) { - init(); - if (cstr) copy(cstr, length); + init(); + if (cstr) { + copy(cstr, length); + } } String::String(const String &value) { - init(); - *this = value; + init(); + *this = value; } String::String(const __FlashStringHelper *pstr) { - init(); - const char* cstr = reinterpret_cast(pstr); - if (cstr) copy(cstr, strlen(cstr)); + init(); + const char* cstr = reinterpret_cast(pstr); + if (cstr) { + copy(cstr, strlen(cstr)); + } } #ifdef __GXX_EXPERIMENTAL_CXX0X__ String::String(String &&rval) { - init(); - move(rval); + init(); + move(rval); } String::String(StringSumHelper &&rval) { - init(); - move(rval); + init(); + move(rval); } #endif String::String(char c) { - init(); - char buf[2]; - buf[0] = c; - buf[1] = 0; - *this = buf; + init(); + char buf[2] = {}; + buf[0] = c; + buf[1] = 0; + *this = buf; } String::String(unsigned char value, unsigned char base) { - init(); - char buf[9]; - utoa(value, buf, base); - *this = buf; + init(); + char buf[9] = {}; + utoa(value, buf, base); + *this = buf; } String::String(int value, unsigned char base) { - init(); - char buf[34]; - itoa(value, buf, base); - *this = buf; + init(); + char buf[34] = {}; + itoa(value, buf, base); + *this = buf; } String::String(unsigned int value, unsigned char base) { - init(); - char buf[33]; - utoa(value, buf, base); - *this = buf; + init(); + char buf[33] = {}; + utoa(value, buf, base); + *this = buf; } String::String(long value, unsigned char base) { - init(); - char buf[34]; - ltoa(value, buf, base); - *this = buf; + init(); + char buf[34] = {}; + ltoa(value, buf, base); + *this = buf; } String::String(unsigned long value, unsigned char base) { - init(); - char buf[33]; - ultoa(value, buf, base); - *this = buf; + init(); + char buf[33] = {}; + ultoa(value, buf, base); + *this = buf; +} + +String::String(long long value, unsigned char base) +{ + init(); + char buf[66] = {}; // Assuming a maximum of 64-bit binary representation + '-' + null terminator. + std::to_chars(buf, buf + sizeof(buf) - 1, value, (int)base); + *this = buf; +} + +String::String(unsigned long long value, unsigned char base) +{ + init(); + char buf[65] = {}; // Assuming a maximum of 64-bit binary representation + null terminator. + std::to_chars(buf, buf + sizeof(buf) - 1, value, (int)base); + *this = buf; } String::String(float value, int decimalPlaces) { - init(); - char buf[33]; - dtoa(value, decimalPlaces, buf); - *this = buf; + init(); + char buf[33] = {}; + dtoa(value, decimalPlaces, buf); + *this = buf; } String::String(double value, int decimalPlaces) { - init(); - char buf[33]; - dtoa(value, decimalPlaces, buf); - *this = buf; + init(); + char buf[33] = {}; + dtoa(value, decimalPlaces, buf); + *this = buf; } String::~String() { - free(buffer); + free(buffer); } /*********************************************/ @@ -179,38 +202,44 @@ String::~String() inline void String::init(void) { - buffer = NULL; - capacity = 0; - len = 0; - flags = 0; + buffer = nullptr; + capacity = 0; + len = 0; + flags = 0; } void String::invalidate(void) { - if (buffer) free(buffer); - buffer = NULL; - capacity = len = 0; + if (buffer) { + free(buffer); + } + buffer = nullptr; + capacity = len = 0; } unsigned char String::reserve(unsigned int size) { - if (buffer && capacity >= size) return 1; - if (changeBuffer(size)) { - if (len == 0) buffer[0] = 0; - return 1; - } - return 0; + if (buffer && capacity >= size) { + return 1; + } + if (changeBuffer(size)) { + if (len == 0) { + buffer[0] = 0; + } + return 1; + } + return 0; } unsigned char String::changeBuffer(unsigned int maxStrLen) { - char *newbuffer = (char *)realloc(buffer, maxStrLen + 1); - if (newbuffer) { - buffer = newbuffer; - capacity = maxStrLen; - return 1; - } - return 0; + char *newbuffer = (char *)realloc(buffer, maxStrLen + 1); + if (newbuffer) { + buffer = newbuffer; + capacity = maxStrLen; + return 1; + } + return 0; } /*********************************************/ @@ -219,14 +248,14 @@ unsigned char String::changeBuffer(unsigned int maxStrLen) String & String::copy(const char *cstr, unsigned int length) { - if (!reserve(length)) { - invalidate(); - return *this; - } - len = length; - memcpy(buffer, cstr, length); - buffer[len] = 0; - return *this; + if (!reserve(length)) { + invalidate(); + return *this; + } + len = length; + memcpy(buffer, cstr, length); + buffer[len] = 0; + return *this; } String & String::copy(const __FlashStringHelper *pstr, unsigned int length) { @@ -236,63 +265,81 @@ String & String::copy(const __FlashStringHelper *pstr, unsigned int length) { #ifdef __GXX_EXPERIMENTAL_CXX0X__ void String::move(String &rhs) { - if (buffer) { - if (capacity >= rhs.len && rhs.buffer) { - strcpy(buffer, rhs.buffer); - len = rhs.len; - rhs.len = 0; - return; - } else { - free(buffer); - } - } - buffer = rhs.buffer; - capacity = rhs.capacity; - len = rhs.len; - rhs.buffer = NULL; - rhs.capacity = 0; - rhs.len = 0; + if (buffer) { + if (capacity >= rhs.len && rhs.buffer) { + strcpy(buffer, rhs.buffer); + len = rhs.len; + rhs.len = 0; + return; + } else { + free(buffer); + } + } + buffer = rhs.buffer; + capacity = rhs.capacity; + len = rhs.len; + rhs.buffer = nullptr; + rhs.capacity = 0; + rhs.len = 0; } #endif String & String::operator = (const String &rhs) { - if (this == &rhs) return *this; + if (this == &rhs) { + return *this; + } - if (rhs.buffer) copy(rhs.buffer, rhs.len); - else invalidate(); + if (rhs.buffer) { + copy(rhs.buffer, rhs.len); + } + else { + invalidate(); + } - return *this; + return *this; } String & String::operator = (const __FlashStringHelper *pstr) { - const char* cstr = reinterpret_cast(pstr); - if (cstr) copy(cstr, strlen(cstr)); - else invalidate(); + const char* cstr = reinterpret_cast(pstr); + if (cstr) { + copy(cstr, strlen(cstr)); + } + else { + invalidate(); + } return *this; } #ifdef __GXX_EXPERIMENTAL_CXX0X__ String & String::operator = (String &&rval) { - if (this != &rval) move(rval); - return *this; + if (this != &rval) { + move(rval); + } + return *this; } String & String::operator = (StringSumHelper &&rval) { - if (this != &rval) move(rval); - return *this; + if (this != &rval) { + move(rval); + } + return *this; } #endif String & String::operator = (const char *cstr) { - if (cstr) copy(cstr, strlen(cstr)); - else invalidate(); + if (cstr) { + copy(cstr, strlen(cstr)); + } + else { + invalidate(); + } - return *this; + return *this; } /*********************************************/ @@ -301,85 +348,107 @@ String & String::operator = (const char *cstr) unsigned char String::concat(const String &s) { - return concat(s.buffer, s.len); + return concat(s.buffer, s.len); } unsigned char String::concat(const char *cstr, unsigned int length) { - unsigned int newlen = len + length; - if (!cstr) return 0; - if (length == 0) return 1; - if (!reserve(newlen)) return 0; - strcpy(buffer + len, cstr); - len = newlen; - return 1; + unsigned int newlen = len + length; + if (!cstr) { + return 0; + } + if (length == 0) { + return 1; + } + if (!reserve(newlen)) { + return 0; + } + strcpy(buffer + len, cstr); + len = newlen; + return 1; } unsigned char String::concat(const char *cstr) { - if (!cstr) return 0; - return concat(cstr, strlen(cstr)); + if (!cstr) { + return 0; + } + return concat(cstr, strlen(cstr)); } unsigned char String::concat(const __FlashStringHelper * str) { - return concat(reinterpret_cast(str)); + return concat(reinterpret_cast(str)); } unsigned char String::concat(char c) { - char buf[2]; - buf[0] = c; - buf[1] = 0; - return concat(buf, 1); + char buf[2] = {}; + buf[0] = c; + buf[1] = 0; + return concat(buf, 1); } unsigned char String::concat(unsigned char num) { - char buf[4]; - itoa(num, buf, 10); - return concat(buf, strlen(buf)); + char buf[4] = {}; + itoa(num, buf, 10); + return concat(buf, strlen(buf)); } unsigned char String::concat(int num) { - char buf[7]; - itoa(num, buf, 10); - return concat(buf, strlen(buf)); + char buf[7] = {}; + itoa(num, buf, 10); + return concat(buf, strlen(buf)); } unsigned char String::concat(unsigned int num) { - char buf[6]; - utoa(num, buf, 10); - return concat(buf, strlen(buf)); + char buf[6] = {}; + utoa(num, buf, 10); + return concat(buf, strlen(buf)); } unsigned char String::concat(long num) { - char buf[12]; - ltoa(num, buf, 10); - return concat(buf, strlen(buf)); + char buf[12] = {}; + ltoa(num, buf, 10); + return concat(buf, strlen(buf)); } unsigned char String::concat(unsigned long num) { - char buf[11]; - ultoa(num, buf, DEC); - return concat(buf, strlen(buf)); + char buf[11] = {}; + ultoa(num, buf, DEC); + return concat(buf, strlen(buf)); +} + +unsigned char String::concat(long long num) +{ + char buf[66] = {}; // Assuming a maximum of 64-bit binary representation + '-' + null terminator. + std::to_chars(buf, buf + sizeof(buf) - 1, num, (int)DEC); + return concat(buf, strlen(buf)); +} + +unsigned char String::concat(unsigned long long num) +{ + char buf[65] = {}; // Assuming a maximum of 64-bit binary representation + null terminator. + std::to_chars(buf, buf + sizeof(buf) - 1, num, (int)DEC); + return concat(buf, strlen(buf)); } unsigned char String::concat(float num) { - char buf[20]; - dtoa(num, 6, buf); - return concat(buf, strlen(buf)); + char buf[20] = {}; + dtoa(num, 6, buf); + return concat(buf, strlen(buf)); } unsigned char String::concat(double num) { - char buf[20]; - dtoa(num, 6, buf); - return concat(buf, strlen(buf)); + char buf[20] = {}; + dtoa(num, 6, buf); + return concat(buf, strlen(buf)); } /*********************************************/ @@ -388,72 +457,110 @@ unsigned char String::concat(double num) StringSumHelper & operator + (const StringSumHelper &lhs, const String &rhs) { - StringSumHelper &a = const_cast(lhs); - if (!a.concat(rhs.buffer, rhs.len)) a.invalidate(); - return a; + StringSumHelper &a = const_cast(lhs); + if (!a.concat(rhs.buffer, rhs.len)) { + a.invalidate(); + } + return a; } StringSumHelper & operator + (const StringSumHelper &lhs, const char *cstr) { - StringSumHelper &a = const_cast(lhs); - if (!cstr || !a.concat(cstr, strlen(cstr))) a.invalidate(); - return a; + StringSumHelper &a = const_cast(lhs); + if (!cstr || !a.concat(cstr, strlen(cstr))) { + a.invalidate(); + } + return a; } StringSumHelper & operator + (const StringSumHelper &lhs, char c) { - StringSumHelper &a = const_cast(lhs); - if (!a.concat(c)) a.invalidate(); - return a; + StringSumHelper &a = const_cast(lhs); + if (!a.concat(c)) { + a.invalidate(); + } + return a; } StringSumHelper & operator + (const StringSumHelper &lhs, unsigned char num) { - StringSumHelper &a = const_cast(lhs); - if (!a.concat(num)) a.invalidate(); - return a; + StringSumHelper &a = const_cast(lhs); + if (!a.concat(num)) { + a.invalidate(); + } + return a; } StringSumHelper & operator + (const StringSumHelper &lhs, int num) { - StringSumHelper &a = const_cast(lhs); - if (!a.concat(num)) a.invalidate(); - return a; + StringSumHelper &a = const_cast(lhs); + if (!a.concat(num)) { + a.invalidate(); + } + return a; } StringSumHelper & operator + (const StringSumHelper &lhs, unsigned int num) { - StringSumHelper &a = const_cast(lhs); - if (!a.concat(num)) a.invalidate(); - return a; + StringSumHelper &a = const_cast(lhs); + if (!a.concat(num)) { + a.invalidate(); + } + return a; } StringSumHelper & operator + (const StringSumHelper &lhs, long num) { - StringSumHelper &a = const_cast(lhs); - if (!a.concat(num)) a.invalidate(); - return a; + StringSumHelper &a = const_cast(lhs); + if (!a.concat(num)) { + a.invalidate(); + } + return a; } StringSumHelper & operator + (const StringSumHelper &lhs, unsigned long num) { - StringSumHelper &a = const_cast(lhs); - if (!a.concat(num)) a.invalidate(); - return a; + StringSumHelper &a = const_cast(lhs); + if (!a.concat(num)) { + a.invalidate(); + } + return a; +} + +StringSumHelper & operator + (const StringSumHelper &lhs, long long num) +{ + StringSumHelper &a = const_cast(lhs); + if (!a.concat(num)) { + a.invalidate(); + } + return a; +} + +StringSumHelper & operator + (const StringSumHelper &lhs, unsigned long long num) +{ + StringSumHelper &a = const_cast(lhs); + if (!a.concat(num)) { + a.invalidate(); + } + return a; } StringSumHelper & operator + (const StringSumHelper &lhs, float num) { - StringSumHelper &a = const_cast(lhs); - if (!a.concat(num)) a.invalidate(); - return a; + StringSumHelper &a = const_cast(lhs); + if (!a.concat(num)) { + a.invalidate(); + } + return a; } StringSumHelper & operator + (const StringSumHelper &lhs, double num) { - StringSumHelper &a = const_cast(lhs); - if (!a.concat(num)) a.invalidate(); - return a; + StringSumHelper &a = const_cast(lhs); + if (!a.concat(num)) { + a.invalidate(); + } + return a; } /*********************************************/ /* Comparison */ @@ -461,75 +568,97 @@ StringSumHelper & operator + (const StringSumHelper &lhs, double num) int String::compareTo(const String &s) const { - if (!buffer || !s.buffer) { - if (s.buffer && s.len > 0) return 0 - *(unsigned char *)s.buffer; - if (buffer && len > 0) return *(unsigned char *)buffer; - return 0; - } - return strcmp(buffer, s.buffer); + if (!buffer || !s.buffer) { + if (s.buffer && s.len > 0) { + return 0 - *(unsigned char *)s.buffer; + } + if (buffer && len > 0) { + return *(unsigned char *)buffer; + } + return 0; + } + return strcmp(buffer, s.buffer); } unsigned char String::equals(const String &s2) const { - return (len == s2.len && compareTo(s2) == 0); + return (len == s2.len && compareTo(s2) == 0); } unsigned char String::equals(const char *cstr) const { - if (len == 0) return (cstr == NULL || *cstr == 0); - if (cstr == NULL) return buffer[0] == 0; - return strcmp(buffer, cstr) == 0; + if (len == 0) { + return (cstr == nullptr || *cstr == 0); + } + if (cstr == nullptr) { + return buffer[0] == 0; + } + return strcmp(buffer, cstr) == 0; } unsigned char String::operator<(const String &rhs) const { - return compareTo(rhs) < 0; + return compareTo(rhs) < 0; } unsigned char String::operator>(const String &rhs) const { - return compareTo(rhs) > 0; + return compareTo(rhs) > 0; } unsigned char String::operator<=(const String &rhs) const { - return compareTo(rhs) <= 0; + return compareTo(rhs) <= 0; } unsigned char String::operator>=(const String &rhs) const { - return compareTo(rhs) >= 0; + return compareTo(rhs) >= 0; } unsigned char String::equalsIgnoreCase( const String &s2 ) const { - if (this == &s2) return 1; - if (len != s2.len) return 0; - if (len == 0) return 1; - const char *p1 = buffer; - const char *p2 = s2.buffer; - while (*p1) { - if (tolower(*p1++) != tolower(*p2++)) return 0; - } - return 1; + if (this == &s2) { + return 1; + } + if (len != s2.len) { + return 0; + } + if (len == 0) { + return 1; + } + const char *p1 = buffer; + const char *p2 = s2.buffer; + while (*p1) { + if (tolower(*p1++) != tolower(*p2++)) { + return 0; + } + } + return 1; } unsigned char String::startsWith( const String &s2 ) const { - if (len < s2.len) return 0; - return startsWith(s2, 0); + if (len < s2.len) { + return 0; + } + return startsWith(s2, 0); } unsigned char String::startsWith( const String &s2, unsigned int offset ) const { - if (offset > len - s2.len || !buffer || !s2.buffer) return 0; - return strncmp( &buffer[offset], s2.buffer, s2.len ) == 0; + if (offset > len - s2.len || !buffer || !s2.buffer) { + return 0; + } + return strncmp( &buffer[offset], s2.buffer, s2.len ) == 0; } unsigned char String::endsWith( const String &s2 ) const { - if ( len < s2.len || !buffer || !s2.buffer) return 0; - return strcmp(&buffer[len - s2.len], s2.buffer) == 0; + if ( len < s2.len || !buffer || !s2.buffer) { + return 0; + } + return strcmp(&buffer[len - s2.len], s2.buffer) == 0; } /*********************************************/ @@ -538,41 +667,49 @@ unsigned char String::endsWith( const String &s2 ) const char String::charAt(unsigned int loc) const { - return operator[](loc); + return operator[](loc); } void String::setCharAt(unsigned int loc, char c) { - if (loc < len) buffer[loc] = c; + if (loc < len) { + buffer[loc] = c; + } } char & String::operator[](unsigned int index) { - static char dummy_writable_char; - if (index >= len || !buffer) { - dummy_writable_char = 0; - return dummy_writable_char; - } - return buffer[index]; + static char dummy_writable_char; + if (index >= len || !buffer) { + dummy_writable_char = 0; + return dummy_writable_char; + } + return buffer[index]; } char String::operator[]( unsigned int index ) const { - if (index >= len || !buffer) return 0; - return buffer[index]; + if (index >= len || !buffer) { + return 0; + } + return buffer[index]; } void String::getBytes(unsigned char *buf, unsigned int bufsize, unsigned int index) const { - if (!bufsize || !buf) return; - if (index >= len) { - buf[0] = 0; - return; - } - unsigned int n = bufsize - 1; - if (n > len - index) n = len - index; - strncpy((char *)buf, buffer + index, n); - buf[n] = 0; + if (!bufsize || !buf) { + return; + } + if (index >= len) { + buf[0] = 0; + return; + } + unsigned int n = bufsize - 1; + if (n > len - index) { + n = len - index; + } + strncpy((char *)buf, buffer + index, n); + buf[n] = 0; } /*********************************************/ @@ -581,81 +718,103 @@ void String::getBytes(unsigned char *buf, unsigned int bufsize, unsigned int ind int String::indexOf(char c) const { - return indexOf(c, 0); + return indexOf(c, 0); } int String::indexOf( char ch, unsigned int fromIndex ) const { - if (fromIndex >= len) return -1; - const char* temp = strchr(buffer + fromIndex, ch); - if (temp == NULL) return -1; - return temp - buffer; + if (fromIndex >= len) { + return -1; + } + const char* temp = strchr(buffer + fromIndex, ch); + if (temp == nullptr) { + return -1; + } + return temp - buffer; } int String::indexOf(const String &s2) const { - return indexOf(s2, 0); + return indexOf(s2, 0); } int String::indexOf(const String &s2, unsigned int fromIndex) const { - if (fromIndex >= len) return -1; - const char *found = strstr(buffer + fromIndex, s2.buffer); - if (found == NULL) return -1; - return found - buffer; + if (fromIndex >= len) { + return -1; + } + const char *found = strstr(buffer + fromIndex, s2.buffer); + if (found == nullptr) { + return -1; + } + return found - buffer; } int String::lastIndexOf( char theChar ) const { - return lastIndexOf(theChar, len - 1); + return lastIndexOf(theChar, len - 1); } int String::lastIndexOf(char ch, unsigned int fromIndex) const { - if (fromIndex >= len) return -1; - char tempchar = buffer[fromIndex + 1]; - buffer[fromIndex + 1] = '\0'; - char* temp = strrchr( buffer, ch ); - buffer[fromIndex + 1] = tempchar; - if (temp == NULL) return -1; - return temp - buffer; + if (fromIndex >= len) { + return -1; + } + char tempchar = buffer[fromIndex + 1]; + buffer[fromIndex + 1] = '\0'; + char* temp = strrchr( buffer, ch ); + buffer[fromIndex + 1] = tempchar; + if (temp == nullptr) { + return -1; + } + return temp - buffer; } int String::lastIndexOf(const String &s2) const { - return lastIndexOf(s2, len - s2.len); + return lastIndexOf(s2, len - s2.len); } int String::lastIndexOf(const String &s2, unsigned int fromIndex) const { - if (s2.len == 0 || len == 0 || s2.len > len) return -1; - if (fromIndex >= len) fromIndex = len - 1; - int found = -1; - for (char *p = buffer; p <= buffer + fromIndex; p++) { - p = strstr(p, s2.buffer); - if (!p) break; - if ((unsigned int)(p - buffer) <= fromIndex) found = p - buffer; - } - return found; + if (s2.len == 0 || len == 0 || s2.len > len) { + return -1; + } + if (fromIndex >= len) fromIndex = len - 1; + int found = -1; + for (char *p = buffer; p <= buffer + fromIndex; p++) { + p = strstr(p, s2.buffer); + if (!p) { + break; + } + if ((unsigned int)(p - buffer) <= fromIndex) { + found = p - buffer; + } + } + return found; } String String::substring( unsigned int left ) const { - return substring(left, len); + return substring(left, len); } String String::substring(unsigned int left, unsigned int right) const { - if (left > right) { - unsigned int temp = right; - right = left; - left = temp; - } - String out; - if (left > len) return out; - if (right > len) right = len; - out.copy(&buffer[left], right - left); - return out; + if (left > right) { + unsigned int temp = right; + right = left; + left = temp; + } + String out; + if (left > len) { + return out; + } + if (right > len) { + right = len; + } + out.copy(&buffer[left], right - left); + return out; } /*********************************************/ @@ -664,104 +823,125 @@ String String::substring(unsigned int left, unsigned int right) const String& String::replace(char find, char replace) { - if (buffer) - for (char *p = buffer; *p; p++) { - if (*p == find) *p = replace; - } - return *this; + if (buffer) { + for (char *p = buffer; *p; p++) { + if (*p == find) *p = replace; + } + } + return *this; } String& String::replace(const String& find, const String& replace) { - if (len == 0 || find.len == 0) return *this; - int diff = replace.len - find.len; - char *readFrom = buffer; - char *foundAt; - if (diff == 0) { - while ((foundAt = strstr(readFrom, find.buffer)) != NULL) { - memcpy(foundAt, replace.buffer, replace.len); - readFrom = foundAt + replace.len; - } - } else if (diff < 0) { - char *writeTo = buffer; - while ((foundAt = strstr(readFrom, find.buffer)) != NULL) { - unsigned int n = foundAt - readFrom; - memcpy(writeTo, readFrom, n); - writeTo += n; - memcpy(writeTo, replace.buffer, replace.len); - writeTo += replace.len; - readFrom = foundAt + find.len; - len += diff; - } - strcpy(writeTo, readFrom); - } else { - unsigned int size = len; // compute size needed for result - while ((foundAt = strstr(readFrom, find.buffer)) != NULL) { - readFrom = foundAt + find.len; - size += diff; - } - if (size == len) return *this;; - if (size > capacity && !changeBuffer(size)) return *this; // XXX: tell user! - int index = len - 1; - while (index >= 0 && (index = lastIndexOf(find, index)) >= 0) { - readFrom = buffer + index + find.len; - memmove(readFrom + diff, readFrom, len - (readFrom - buffer)); - len += diff; - buffer[len] = 0; - memcpy(buffer + index, replace.buffer, replace.len); - index--; - } - } + if (len == 0 || find.len == 0) { return *this; + } + int diff = replace.len - find.len; + char *readFrom = buffer; + char *foundAt; + if (diff == 0) { + while ((foundAt = strstr(readFrom, find.buffer)) != nullptr) { + memcpy(foundAt, replace.buffer, replace.len); + readFrom = foundAt + replace.len; + } + } else if (diff < 0) { + char *writeTo = buffer; + while ((foundAt = strstr(readFrom, find.buffer)) != nullptr) { + unsigned int n = foundAt - readFrom; + memcpy(writeTo, readFrom, n); + writeTo += n; + memcpy(writeTo, replace.buffer, replace.len); + writeTo += replace.len; + readFrom = foundAt + find.len; + len += diff; + } + strcpy(writeTo, readFrom); + } else { + unsigned int size = len; // compute size needed for result + while ((foundAt = strstr(readFrom, find.buffer)) != nullptr) { + readFrom = foundAt + find.len; + size += diff; + } + if (size == len) { + return *this; + } + if (size > capacity && !changeBuffer(size)) { + return *this; // XXX: tell user! + } + int index = len - 1; + while (index >= 0 && (index = lastIndexOf(find, index)) >= 0) { + readFrom = buffer + index + find.len; + memmove(readFrom + diff, readFrom, len - (readFrom - buffer)); + len += diff; + buffer[len] = 0; + memcpy(buffer + index, replace.buffer, replace.len); + index--; + } + } + return *this; } String& String::remove(unsigned int index){ - int count = len - index; - return remove(index, count); + int count = len - index; + return remove(index, count); } String& String::remove(unsigned int index, unsigned int count){ - if (index >= len) { return *this; } - if (count <= 0) { return *this; } - if (index + count > len) { count = len - index; } - char *writeTo = buffer + index; - len = len - count; - memmove(writeTo, buffer + index + count,len - index); - buffer[len] = 0; - return *this; + if (index >= len) { + return *this; + } + if (count <= 0) { + return *this; + } + if (index + count > len) { + count = len - index; + } + char *writeTo = buffer + index; + len = len - count; + memmove(writeTo, buffer + index + count,len - index); + buffer[len] = 0; + return *this; } String& String::toLowerCase(void) { - if (buffer) { - for (char *p = buffer; *p; p++) { - *p = tolower(*p); - } + if (buffer) { + for (char *p = buffer; *p; p++) { + *p = tolower(*p); } - return *this; + } + return *this; } String& String::toUpperCase(void) { - if (buffer) { - for (char *p = buffer; *p; p++) { - *p = toupper(*p); - } + if (buffer) { + for (char *p = buffer; *p; p++) { + *p = toupper(*p); } - return *this; + } + return *this; } String& String::trim(void) { - if (!buffer || len == 0) return *this; - char *begin = buffer; - while (isspace(*begin)) begin++; - char *end = buffer + len - 1; - while (isspace(*end) && end >= begin) end--; - len = end + 1 - begin; - if (begin > buffer) memcpy(buffer, begin, len); - buffer[len] = 0; + if (!buffer || len == 0) { return *this; + } + char *begin = buffer; + while (isspace(*begin)) { + begin++; + } + char *end = buffer + len - 1; + while (isspace(*end) && end >= begin) { + end--; + } + len = end + 1 - begin; + if (begin > buffer) { + memcpy(buffer, begin, len); + } + buffer[len] = 0; + return *this; } /*********************************************/ @@ -770,15 +950,34 @@ String& String::trim(void) long String::toInt(void) const { - if (buffer) return atol(buffer); - return 0; + if (buffer) { + return atol(buffer); + } + return 0; } +long long String::toLongLongInt(unsigned char base) const +{ + if (buffer) { + return strtoll(buffer, nullptr, base); + } + return 0; +} + +unsigned long long String::toULongLongInt(unsigned char base) const +{ + if (buffer) { + return strtoull(buffer, nullptr, base); + } + return 0; +} float String::toFloat(void) const { - if (buffer) return float(atof(buffer)); - return 0; + if (buffer) { + return float(atof(buffer)); + } + return 0; } class StringPrintableHelper : public Print