From eba3042910f063ae638a7e0134b79175978e2fca Mon Sep 17 00:00:00 2001 From: Boris Kolpackov Date: Sat, 28 Apr 2018 16:34:57 +0200 Subject: Move trim(), next_word() basic string utilities from build2 --- libbutl/path.mxx | 3 +++ libbutl/utility.cxx | 38 ++++++++++++++++++++++++++++++- libbutl/utility.ixx | 56 ++++++++++++++++++++++++++++++++++++---------- libbutl/utility.mxx | 64 ++++++++++++++++++++++++++++++++++++++++------------- 4 files changed, 133 insertions(+), 28 deletions(-) diff --git a/libbutl/path.mxx b/libbutl/path.mxx index ab85a0f..5b9bec1 100644 --- a/libbutl/path.mxx +++ b/libbutl/path.mxx @@ -343,6 +343,9 @@ LIBBUTL_MODEXPORT namespace butl static int compare (const C* l, size_type ln, const C* r, size_type rn) { + //@@ TODO: would be nice to ignore difference in trailing slashes + // (except for POSIX root). + for (size_type i (0), n (ln < rn ? ln : rn); i != n; ++i) { #ifdef _WIN32 diff --git a/libbutl/utility.cxx b/libbutl/utility.cxx index c8e4e85..4645b68 100644 --- a/libbutl/utility.cxx +++ b/libbutl/utility.cxx @@ -35,7 +35,6 @@ import std.io; #endif - namespace butl { using namespace std; @@ -88,6 +87,43 @@ namespace butl win32::error_msg (system_code)); #endif } + + string& + trim (string& l) + { + /* + assert (trim (r = "") == ""); + assert (trim (r = " ") == ""); + assert (trim (r = " \t\r") == ""); + assert (trim (r = "a") == "a"); + assert (trim (r = " a") == "a"); + assert (trim (r = "a ") == "a"); + assert (trim (r = " \ta") == "a"); + assert (trim (r = "a \r") == "a"); + assert (trim (r = " a ") == "a"); + assert (trim (r = " \ta \r") == "a"); + */ + + size_t i (0), n (l.size ()); + + for (char c; + i != n && ((c = l[i]) == ' ' || c == '\t' || c == '\r'); + ++i) ; + + for (char c; + n != i && ((c = l[n - 1]) == ' ' || c == '\t' || c == '\r'); + --n) ; + + if (i != 0) + { + string s (l, i, n - i); + l.swap (s); + } + else if (n != l.size ()) + l.resize (n); + + return l; + } } namespace std diff --git a/libbutl/utility.ixx b/libbutl/utility.ixx index fcb8789..24271e4 100644 --- a/libbutl/utility.ixx +++ b/libbutl/utility.ixx @@ -4,18 +4,6 @@ namespace butl { - inline bool - eof (std::istream& is) - { - if (!is.fail ()) - return false; - - if (is.eof ()) - return true; - - throw std::istream::failure (""); - } - inline char ucase (char c) { @@ -167,4 +155,48 @@ namespace butl { return std::iswxdigit (c); } + + inline std::size_t + next_word (const std::string& s, std::size_t& b, std::size_t& e, + char d1, char d2) + { + return next_word (s, s.size (), b, e, d1, d2); + } + + inline size_t + next_word (const std::string& s, + std::size_t n, std::size_t& b, std::size_t& e, + char d1, char d2) + { + if (b != e) + b = e; + + // Skip leading delimiters. + // + for (; b != n && (s[b] == d1 || s[b] == d2); ++b) ; + + if (b == n) + { + e = n; + return 0; + } + + // Find first trailing delimiter. + // + for (e = b + 1; e != n && s[e] != d1 && s[e] != d2; ++e) ; + + return e - b; + } + + inline bool + eof (std::istream& is) + { + if (!is.fail ()) + return false; + + if (is.eof ()) + return true; + + throw std::istream::failure (""); + } } diff --git a/libbutl/utility.mxx b/libbutl/utility.mxx index 4c83827..b957282 100644 --- a/libbutl/utility.mxx +++ b/libbutl/utility.mxx @@ -57,21 +57,6 @@ LIBBUTL_MODEXPORT namespace butl [[noreturn]] LIBBUTL_SYMEXPORT void throw_system_error (int system_code, int fallback_errno_code = 0); - // If an input stream is in a failed state, then return true if this is - // because of the eof and throw istream::failure otherwise. If the stream - // is not in a failed state, return false. This helper function is normally - // used like this: - // - // is.exceptions (istream::badbit); - // - // for (string l; !eof (getline (is, l)); ) - // { - // ... - // } - // - bool - eof (std::istream&); - // Convert ASCII character/string case. If there is no upper/lower case // counterpart, leave the character unchanged. The POSIX locale (also known // as C locale) must be the current application locale. Otherwise the @@ -149,6 +134,55 @@ LIBBUTL_MODEXPORT namespace butl bool alnum (wchar_t); bool xdigit (wchar_t); + // Basic string utilities. + // + + // Trim leading/trailing whitespacec, including '\r'. + // + std::string& + trim (std::string&); + + // Find the beginning and end poistions of the next word. Return the size + // of the word or 0 and set b = e = n if there are no more words. For + // example: + // + // for (size_t b (0), e (0); next_word (s, b, e); ) + // { + // string w (s, b, e - b); + // } + // + // Or: + // + // for (size_t b (0), e (0), n; n = next_word (s, b, e, ' ', ','); ) + // { + // string w (s, b, n); + // } + // + // The second version examines up to the n'th character in the string. + // + std::size_t + next_word (const std::string&, std::size_t& b, std::size_t& e, + char d1 = ' ', char d2 = '\0'); + + std::size_t + next_word (const std::string&, std::size_t n, std::size_t& b, std::size_t& e, + char d1 = ' ', char d2 = '\0'); + + // If an input stream is in a failed state, then return true if this is + // because of the eof and throw istream::failure otherwise. If the stream + // is not in a failed state, return false. This helper function is normally + // used like this: + // + // is.exceptions (istream::badbit); + // + // for (string l; !eof (getline (is, l)); ) + // { + // ... + // } + // + bool + eof (std::istream&); + // Key comparators (i.e., to be used in sets, maps, etc). // struct compare_c_string -- cgit v1.1