summaryrefslogtreecommitdiff
path: root/src/strutil.cc
diff options
context:
space:
mode:
Diffstat (limited to 'src/strutil.cc')
-rw-r--r--src/strutil.cc211
1 files changed, 211 insertions, 0 deletions
diff --git a/src/strutil.cc b/src/strutil.cc
new file mode 100644
index 0000000..adee769
--- /dev/null
+++ b/src/strutil.cc
@@ -0,0 +1,211 @@
+#include "common.hh"
+
+#include "strutil.hh"
+
+#include <errno.h>
+#include <limits>
+#include <stdlib.h>
+
+namespace str {
+
+namespace {
+
+// Sadly strtoul(l) doesn't treat negative values an error but instead returns
+// ULONG_MAX - value which is indistinguable from ULONG_MAX - value the positive
+// way.
+bool is_negative(std::string const& str) {
+ for (auto i = str.begin(); i != str.end(); ++i) {
+ if (!isspace(*i)) {
+ return *i == '-';
+ }
+ }
+ return false;
+}
+
+} // namespace
+
+std::optional<uint16_t> parse_uint16(std::string const& str) {
+ static_assert(sizeof(unsigned long) >= sizeof(uint16_t),
+ "Need unsigned long to be >= uint16_t");
+ if (str.empty() || is_negative(str))
+ return std::nullopt;
+ char* end = nullptr;
+ errno = 0;
+ auto tmp = strtoul(str.c_str(), &end, 10);
+ if (errno || end != str.c_str() + str.size() ||
+ tmp > std::numeric_limits<uint16_t>::max())
+ return std::nullopt;
+ return static_cast<uint16_t>(tmp);
+}
+
+std::optional<uint32_t> parse_uint32(std::string const& str) {
+ static_assert(sizeof(unsigned long long) >= sizeof(uint32_t),
+ "Need unsigned long long to be >= uint32_t");
+ if (str.empty() || is_negative(str))
+ return std::nullopt;
+ char* end = nullptr;
+ errno = 0;
+ auto tmp = strtoull(str.c_str(), &end, 10);
+ if (errno || end != str.c_str() + str.size() ||
+ tmp > std::numeric_limits<uint32_t>::max())
+ return std::nullopt;
+ return static_cast<uint32_t>(tmp);
+}
+
+std::optional<uint64_t> parse_uint64(std::string const& str) {
+ static_assert(sizeof(unsigned long long) >= sizeof(uint64_t),
+ "Need unsigned long long to be >= uint64_t");
+ if (str.empty() || is_negative(str))
+ return std::nullopt;
+ char* end = nullptr;
+ errno = 0;
+ auto tmp = strtoull(str.c_str(), &end, 10);
+ if (errno || end != str.c_str() + str.size() ||
+ tmp > std::numeric_limits<uint64_t>::max())
+ return std::nullopt;
+ return static_cast<uint64_t>(tmp);
+}
+
+std::vector<std::string_view> split(std::string_view str, char delim) {
+ std::vector<std::string_view> ret;
+ size_t last = 0;
+ while (true) {
+ size_t next = str.find(delim, last);
+ if (next == std::string::npos)
+ break;
+ if (next > last)
+ ret.push_back(str.substr(last, next - last));
+ last = next + 1;
+ }
+ if (last < str.size() || ret.empty())
+ ret.push_back(str.substr(last));
+ return ret;
+}
+
+std::vector<std::string> split(std::string const& str, char delim) {
+ std::vector<std::string> ret;
+ size_t last = 0;
+ while (true) {
+ size_t next = str.find(delim, last);
+ if (next == std::string::npos)
+ break;
+ if (next > last)
+ ret.push_back(str.substr(last, next - last));
+ last = next + 1;
+ }
+ if (last < str.size() || ret.empty())
+ ret.push_back(str.substr(last));
+ return ret;
+}
+
+std::string join(std::vector<std::string> const& in, char delim) {
+ std::string ret;
+ join(in, delim, ret);
+ return ret;
+}
+
+std::string join(std::vector<std::string> const& in, std::string_view delim) {
+ std::string ret;
+ join(in, delim, ret);
+ return ret;
+}
+
+void join(std::vector<std::string> const& in, char delim, std::string& out) {
+ join(in, std::string_view(&delim, 1), out);
+}
+
+void join(std::vector<std::string> const& in, std::string_view delim,
+ std::string& out) {
+ auto it = in.begin();
+ if (it == in.end())
+ return;
+ out.append(*it);
+ for (++it; it != in.end(); ++it) {
+ out.append(delim);
+ out.append(*it);
+ }
+}
+
+std::string join(std::vector<std::string_view> const& in, char delim) {
+ std::string ret;
+ join(in, delim, ret);
+ return ret;
+}
+
+std::string join(std::vector<std::string_view> const& in,
+ std::string_view delim) {
+ std::string ret;
+ join(in, delim, ret);
+ return ret;
+}
+
+void join(std::vector<std::string_view> const& in, char delim,
+ std::string& out) {
+ join(in, std::string_view(&delim, 1), out);
+}
+
+void join(std::vector<std::string_view> const& in, std::string_view delim,
+ std::string& out) {
+ auto it = in.begin();
+ if (it == in.end())
+ return;
+ out.append(*it);
+ for (++it; it != in.end(); ++it) {
+ out.append(delim);
+ out.append(*it);
+ }
+}
+
+bool starts_with(std::string_view str, std::string_view prefix) {
+ return str.size() >= prefix.size() &&
+ str.compare(0, prefix.size(), prefix) == 0;
+}
+
+bool ends_with(std::string_view str, std::string_view suffix) {
+ return str.size() >= suffix.size() &&
+ str.compare(str.size() - suffix.size(), suffix.size(), suffix) == 0;
+}
+
+std::string_view trim(std::string_view str) {
+ return ltrim(rtrim(str));
+}
+
+std::string_view ltrim(std::string_view str) {
+ size_t start = 0;
+ while (start < str.size() && str[start] == ' ')
+ ++start;
+ return str.substr(start);
+}
+
+std::string_view rtrim(std::string_view str) {
+ size_t end = str.size();
+ while (end > 0 && str[end - 1] == ' ')
+ --end;
+ return str.substr(0, end);
+}
+
+std::string trim(std::string const& str) {
+ size_t start = 0;
+ while (start < str.size() && str[start] == ' ')
+ ++start;
+ size_t end = str.size();
+ while (end > start && str[end - 1] == ' ')
+ --end;
+ return str.substr(start, end - start);
+}
+
+std::string ltrim(std::string const& str) {
+ size_t start = 0;
+ while (start < str.size() && str[start] == ' ')
+ ++start;
+ return str.substr(start);
+}
+
+std::string rtrim(std::string const& str) {
+ size_t end = str.size();
+ while (end > 0 && str[end - 1] == ' ')
+ --end;
+ return str.substr(0, end);
+}
+
+} // namespace str