The new functions StrToInt64 and StrToUint64 parse a string as a signed and
unsigned 64-bit integer, respectively. Prefixes 0 for octal and 0x for
hexadecimal are supported, as well as suffixes k, M and G for kilobytes,
megabytes and gigabytes, respectively.
---
src/base/Makefile.am | 3 +
src/base/string_parse.cc | 79 ++++++++++++++++++++++
src/base/string_parse.h | 47 +++++++++++++
src/base/tests/string_parse_test.cc | 129 ++++++++++++++++++++++++++++++++++++
4 files changed, 258 insertions(+)
create mode 100644 src/base/string_parse.cc
create mode 100644 src/base/string_parse.h
create mode 100644 src/base/tests/string_parse_test.cc
diff --git a/src/base/Makefile.am b/src/base/Makefile.am
index 540c6dfe7..bb13d6c43 100644
--- a/src/base/Makefile.am
+++ b/src/base/Makefile.am
@@ -65,6 +65,7 @@ lib_libopensaf_core_la_SOURCES += \
src/base/process.cc \
src/base/saf_edu.c \
src/base/saf_error.c \
+ src/base/string_parse.cc \
src/base/sysf_def.c \
src/base/sysf_exc_scr.c \
src/base/sysf_ipc.c \
@@ -140,6 +141,7 @@ noinst_HEADERS += \
src/base/saf_error.h \
src/base/saf_mem.h \
src/base/sprr_dl_api.h \
+ src/base/string_parse.h \
src/base/sysf_exc_scr.h \
src/base/sysf_ipc.h \
src/base/tests/mock_clock_gettime.h \
@@ -206,6 +208,7 @@ bin_libbase_test_SOURCES = \
src/base/tests/mock_logtrace.cc \
src/base/tests/mock_osaf_abort.cc \
src/base/tests/mock_osafassert.cc \
+ src/base/tests/string_parse_test.cc \
src/base/tests/time_add_test.cc \
src/base/tests/time_compare_test.cc \
src/base/tests/time_convert_test.cc \
diff --git a/src/base/string_parse.cc b/src/base/string_parse.cc
new file mode 100644
index 000000000..915f0e95a
--- /dev/null
+++ b/src/base/string_parse.cc
@@ -0,0 +1,79 @@
+/* -*- OpenSAF -*-
+ *
+ * Copyright Ericsson AB 2018 - All Rights Reserved.
+ *
+ * This program 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. This file and program are licensed
+ * under the GNU Lesser General Public License Version 2.1, February 1999.
+ * The complete license can be accessed from the following location:
+ * http://opensource.org/licenses/lgpl-license.php
+ * See the Copying file included with the OpenSAF distribution for full
+ * licensing terms.
+ *
+ */
+
+#include "base/string_parse.h"
+
+#include <cerrno>
+#include <cinttypes>
+#include <cstdlib>
+
+namespace {
+
+int64_t ParseSuffix(char** endptr) {
+ switch (**endptr) {
+ case 'k':
+ ++(*endptr);
+ return 1024;
+ case 'M':
+ ++(*endptr);
+ return 1024 * 1024;
+ case 'G':
+ ++(*endptr);
+ return 1024 * 1024 * 1024;
+ default:
+ return 1;
+ }
+}
+
+} // namespace
+
+namespace base {
+
+int64_t StrToInt64(const char* str, bool* success) {
+ str = RemoveLeadingWhitespace(str);
+ errno = 0;
+ char* endptr;
+ int64_t val = strtoll(str, &endptr, 0);
+ int64_t multiplier = ParseSuffix(&endptr);
+ endptr = RemoveLeadingWhitespace(endptr);
+ *success = *str != '\0' && errno == 0 && *endptr == '\0' &&
+ (val >= 0 ? val <= (INT64_MAX / multiplier)
+ : val >= (INT64_MIN / multiplier));
+ return val * multiplier;
+}
+
+uint64_t StrToUint64(const char* str, bool* success) {
+ str = RemoveLeadingWhitespace(str);
+ errno = 0;
+ char* endptr;
+ uint64_t val = strtoull(str, &endptr, 0);
+ uint64_t multiplier = ParseSuffix(&endptr);
+ endptr = RemoveLeadingWhitespace(endptr);
+ *success = *str != '\0' && *str != '-' && errno == 0 && *endptr == '\0' &&
+ val <= (~static_cast<uint64_t>(0) / multiplier);
+ return val * multiplier;
+}
+
+const char* RemoveLeadingWhitespace(const char* str) {
+ while (*str == ' ' || *str == '\t' || *str == '\r' || *str == '\n') ++str;
+ return str;
+}
+
+char* RemoveLeadingWhitespace(char* str) {
+ while (*str == ' ' || *str == '\t' || *str == '\r' || *str == '\n') ++str;
+ return str;
+}
+
+} // namespace base
diff --git a/src/base/string_parse.h b/src/base/string_parse.h
new file mode 100644
index 000000000..17569241c
--- /dev/null
+++ b/src/base/string_parse.h
@@ -0,0 +1,47 @@
+/* -*- OpenSAF -*-
+ *
+ * Copyright Ericsson AB 2018 - All Rights Reserved.
+ *
+ * This program 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. This file and program are licensed
+ * under the GNU Lesser General Public License Version 2.1, February 1999.
+ * The complete license can be accessed from the following location:
+ * http://opensource.org/licenses/lgpl-license.php
+ * See the Copying file included with the OpenSAF distribution for full
+ * licensing terms.
+ *
+ */
+
+#ifndef BASE_STRING_PARSE_H_
+#define BASE_STRING_PARSE_H_
+
+#include <cstdint>
+#include <string>
+
+namespace base {
+
+// Parse the string @a str as a signed (StrToInt64) or unsigned (StrToUint6t4)
+// integer. Leading and trailing whitespace is ignored. Returns the parsed
value
+// and sets the output parameter @a success to true if the whole string was
+// successfully parsed. Parsing will fail if no valid integer was found, if an
+// underflow or overflow occurred, or if not the whole string was consumed.
+// Standard C/C++ base prefixes (0 for octal and 0x or 0X for hexadecimal) can
+// be used, as well as the suffixes k (1024), M (1024 ** 2) and G (1024 ** 3).
+int64_t StrToInt64(const char* str, bool* success);
+uint64_t StrToUint64(const char* str, bool* success);
+static inline int64_t StrToInt64(const std::string& str, bool* success) {
+ return StrToInt64(str.c_str(), success);
+}
+static inline uint64_t StrToUint64(const std::string& str, bool* success) {
+ return StrToUint64(str.c_str(), success);
+}
+
+// Returns the substring of @a str starting at the first non-whitespace
+// character.
+const char* RemoveLeadingWhitespace(const char* str);
+char* RemoveLeadingWhitespace(char* str);
+
+} // namespace base
+
+#endif // BASE_STRING_PARSE_H_
diff --git a/src/base/tests/string_parse_test.cc
b/src/base/tests/string_parse_test.cc
new file mode 100644
index 000000000..14fc2a38d
--- /dev/null
+++ b/src/base/tests/string_parse_test.cc
@@ -0,0 +1,129 @@
+/* -*- OpenSAF -*-
+ *
+ * Copyright Ericsson AB 2018 - All Rights Reserved.
+ *
+ * This program 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. This file and program are licensed
+ * under the GNU Lesser General Public License Version 2.1, February 1999.
+ * The complete license can be accessed from the following location:
+ * http://opensource.org/licenses/lgpl-license.php
+ * See the Copying file included with the OpenSAF distribution for full
+ * licensing terms.
+ *
+ */
+
+#include <cinttypes>
+#include <cstdint>
+#include <string>
+
+#include "base/string_parse.h"
+#include "gtest/gtest.h"
+
+struct TestVector {
+ const char* str;
+ bool unsigned_success;
+ uint64_t unsigned_value;
+ bool signed_success;
+ int64_t signed_value;
+};
+
+static constexpr int64_t kKilo = 1024;
+static constexpr int64_t kMega = 1024 * 1024;
+static constexpr int64_t kGiga = 1024 * 1024 * 1024;
+static constexpr uint64_t kKiloU = kKilo;
+static constexpr uint64_t kMegaU = kMega;
+static constexpr uint64_t kGigaU = kGiga;
+
+static const TestVector test_vectors[] = {
+ {"0", true, 0, true, 0},
+ {"1", true, 1, true, 1},
+ {"-1", false, 0, true, -1},
+ {"-0xf", false, 0, true, -15},
+ {"-010", false, 0, true, -8},
+ {"18446744073709551614", true, UINT64_MAX - 1, false, 0},
+ {"18446744073709551615", true, UINT64_MAX, false, 0},
+ {"18446744073709551616", false, 0, false, 0},
+ {"9223372036854775806", true, INT64_MAX - 1, true, INT64_MAX - 1},
+ {"9223372036854775807", true, INT64_MAX, true, INT64_MAX},
+ {"9223372036854775808", true, 9223372036854775808ull, false, 0},
+ {"-9223372036854775807", false, 0, true, INT64_MIN + 1},
+ {"-9223372036854775808", false, 0, true, INT64_MIN},
+ {"-9223372036854775809", false, 0, false, 0},
+ {"0x7fffffffffffffff", true, 0x7fffffffffffffff, true, 0x7fffffffffffffff},
+ {"0x8000000000000000", true, 0x8000000000000000, false, 0},
+ {"0666", true, 0666, true, 0666},
+ {"0xbeef", true, 0xbeef, true, 0xbeef},
+ {"0XBEEF", true, 0xbeef, true, 0xbeef},
+ {"0x3fffffffffffffk", true, 0xfffffffffffffc00ull, false, 0},
+ {"0x40000000000000k", false, 0, false, 0},
+ {"0x1fffffffffffffk", true, 0x7ffffffffffffc00ull, true,
+ 0x7ffffffffffffc00ull},
+ {"0x20000000000000k", true, 0x8000000000000000ull, false, 0},
+ {"-0x20000000000000k", false, 0, true, INT64_MIN},
+ {"10k", true, 10 * kKiloU, true, 10 * kKilo},
+ {"10K", false, 0, false, 0},
+ {"-10k", false, 0, true, -10 * 1024},
+ {"15M", true, 15 * kMegaU, true, 15 * kMega},
+ {"-15M", false, 0, true, -15 * kMega},
+ {" -15M ", false, 0, true, -15 * kMega},
+ {" -15 M ", false, 0, false, 0},
+ {"0x42G", true, 0x42 * kGigaU, true, 0x42 * kGiga},
+ {"0x42H", false, 0, false, 0},
+ {"0xffffffffffG", false, 0, false, 0},
+ {"-1099511627775G", false, 0, false, 0},
+ {"0xffffffffffM", true, 0xffffffffff * kMegaU, true, 0xffffffffff * kMega},
+ {"", false, 0, false, 0},
+ {" ", false, 0, false, 0},
+ {".", false, 0, false, 0},
+ {"0x", false, 0, false, 0},
+ {"x", false, 0, false, 0},
+ {" ", false, 0, false, 0},
+ {" abc ", false, 0, false, 0}};
+
+TEST(BaseString, TestVectors) {
+ for (size_t i = 0; i < sizeof(test_vectors) / sizeof(test_vectors[0]); ++i) {
+ bool unsigned_success = false;
+ uint64_t unsigned_value =
+ base::StrToUint64(test_vectors[i].str, &unsigned_success);
+ bool signed_success = false;
+ int64_t signed_value =
+ base::StrToInt64(test_vectors[i].str, &signed_success);
+ EXPECT_EQ(unsigned_success, test_vectors[i].unsigned_success);
+ EXPECT_EQ(signed_success, test_vectors[i].signed_success);
+ if (unsigned_success) {
+ EXPECT_EQ(unsigned_value, test_vectors[i].unsigned_value);
+ }
+ if (signed_success) {
+ EXPECT_EQ(signed_value, test_vectors[i].signed_value);
+ }
+ }
+}
+
+TEST(BaseString, StdString) {
+ std::string str{" 4711k "};
+ bool unsigned_success = false;
+ uint64_t unsigned_value = base::StrToUint64(str, &unsigned_success);
+ bool signed_success = false;
+ int64_t signed_value = base::StrToInt64(str, &signed_success);
+ EXPECT_TRUE(unsigned_success);
+ EXPECT_TRUE(signed_success);
+ EXPECT_EQ(unsigned_value, 4711 * kKiloU);
+ EXPECT_EQ(signed_value, 4711 * kKilo);
+}
+
+TEST(BaseString, RemoveWhitespace) {
+ const char* str1 = "hej";
+ const char* str2 = " abc ";
+ const char* str3 = "";
+ char str4[] = "\t\r\n";
+ char str5[] = "1234";
+ char str6[] = " .";
+
+ EXPECT_EQ(base::RemoveLeadingWhitespace(str1), str1);
+ EXPECT_EQ(base::RemoveLeadingWhitespace(str2), str2 + 2);
+ EXPECT_EQ(base::RemoveLeadingWhitespace(str3), str3);
+ EXPECT_EQ(base::RemoveLeadingWhitespace(str4), str4 + 3);
+ EXPECT_EQ(base::RemoveLeadingWhitespace(str5), str5);
+ EXPECT_EQ(base::RemoveLeadingWhitespace(str6), str6 + 4);
+}
--
2.13.3
------------------------------------------------------------------------------
Check out the vibrant tech community on one of the world's most
engaging tech sites, Slashdot.org! http://sdm.link/slashdot
_______________________________________________
Opensaf-devel mailing list
[email protected]
https://lists.sourceforge.net/lists/listinfo/opensaf-devel