diff options
Diffstat (limited to 'libbutl/utility.ixx')
-rw-r--r-- | libbutl/utility.ixx | 160 |
1 files changed, 140 insertions, 20 deletions
diff --git a/libbutl/utility.ixx b/libbutl/utility.ixx index 72fbc5b..fda1ce5 100644 --- a/libbutl/utility.ixx +++ b/libbutl/utility.ixx @@ -1,13 +1,10 @@ // file : libbutl/utility.ixx -*- C++ -*- // license : MIT; see accompanying LICENSE file -#ifndef __cpp_lib_modules_ts #include <cctype> // toupper(), tolower(), is*() #include <cwctype> // isw*() -#include <cstdlib> // getenv() #include <algorithm> // for_each() #include <stdexcept> // invalid_argument -#endif namespace butl { @@ -25,12 +22,15 @@ namespace butl } inline std::string& - ucase (std::string& s) + ucase (std::string& s, std::size_t p, std::size_t n) { - if (size_t n = s.size ()) + if (n == std::string::npos) + n = s.size () - p; + + if (n != 0) { s.front () = s.front (); // Force copy in CoW. - ucase (const_cast<char*> (s.data ()), n); + ucase (const_cast<char*> (s.data ()) + p, n); } return s; } @@ -43,9 +43,9 @@ namespace butl } inline std::string - ucase (const std::string& s) + ucase (const std::string& s, std::size_t p, std::size_t n) { - return ucase (s.c_str (), s.size ()); + return ucase (s.c_str () + p, n != std::string::npos ? n : s.size () - p); } inline char @@ -62,12 +62,15 @@ namespace butl } inline std::string& - lcase (std::string& s) + lcase (std::string& s, std::size_t p, std::size_t n) { - if (size_t n = s.size ()) + if (n == std::string::npos) + n = s.size () - p; + + if (n != 0) { s.front () = s.front (); // Force copy in CoW. - lcase (const_cast<char*> (s.data ()), n); + lcase (const_cast<char*> (s.data ()) + p, n); } return s; } @@ -80,9 +83,9 @@ namespace butl } inline std::string - lcase (const std::string& s) + lcase (const std::string& s, std::size_t p, std::size_t n) { - return lcase (s.c_str (), s.size ()); + return lcase (s.c_str () + p, n != std::string::npos ? n : s.size () - p); } inline int @@ -140,6 +143,12 @@ namespace butl } inline bool + wspace (char c) + { + return std::isspace (c); + } + + inline bool alpha (wchar_t c) { return std::iswalpha (c); @@ -163,6 +172,12 @@ namespace butl return std::iswxdigit (c); } + inline bool + wspace (wchar_t c) + { + return std::iswspace (c); + } + inline std::size_t next_word (const std::string& s, std::size_t& b, std::size_t& e, char d1, char d2) @@ -170,7 +185,7 @@ namespace butl return next_word (s, s.size (), b, e, d1, d2); } - inline size_t + inline std::size_t next_word (const std::string& s, std::size_t n, std::size_t& b, std::size_t& e, char d1, char d2) @@ -195,6 +210,66 @@ namespace butl return e - b; } + inline std::size_t + next_word (const std::string& s, + std::size_t n, std::size_t& b, std::size_t& e, std::size_t& m, + char d1, char d2) + { + // An empty word will necessarily be represented as b and e being the + // position of a delimiter. Consider these corner cases (in all three we + // should produce two words): + // + // \n + // a\n + // \na + // + // It feels sensible to represent an empty word as the position of the + // trailing delimiter except if it is the last character (the first two + // cases). Thus the additional m state, which, if 0 or 1 indicates the + // number of delimiters to skip before parsing the next word and 2 if + // this is a trailing delimiter for which we need to fake an empty word + // with the leading delimiter. + + if (b != e) + b = e; + + if (m > 1) + { + --m; + return 0; + } + + // Skip the leading delimiter, if any. + // + b += m; + + if (b == n) + { + e = n; + return 0; + } + + // Find first trailing delimiter. + // + m = 0; + for (e = b; e != n; ++e) + { + if (s[e] == d1 || s[e] == d2) + { + m = 1; + + // Handle the special delimiter as the last character case. + // + if (e + 1 == n) + ++m; + + break; + } + } + + return e - b; + } + inline std::string& sanitize_identifier (std::string& s) { @@ -222,7 +297,7 @@ namespace butl inline void sanitize_strlit (const std::string& s, std::string& o) { - for (size_t i (0), j;; i = j + 1) + for (std::size_t i (0), j;; i = j + 1) { j = s.find_first_of ("\\\"\n", i); o.append (s.c_str () + i, (j == std::string::npos ? s.size () : j) - i); @@ -327,13 +402,58 @@ namespace butl return utf8_length_impl (s, nullptr, ts, wl).has_value (); } - inline optional<std::string> - getenv (const std::string& name) +#ifndef _WIN32 + inline const char* const* + thread_env () { - if (const char* r = std::getenv (name.c_str ())) - return std::string (r); + return thread_env_; + } - return nullopt; + inline void + thread_env (const char* const* v) + { + thread_env_ = v; + } +#endif + + // auto_thread_env + // + inline auto_thread_env:: + auto_thread_env (const char* const* new_env) + { + const char* const* cur_env (thread_env ()); + + if (cur_env != new_env) + { + prev_env = cur_env; + thread_env (new_env); + } + } + + inline auto_thread_env:: + auto_thread_env (auto_thread_env&& x) noexcept + : prev_env (std::move (x.prev_env)) + { + x.prev_env = nullopt; + } + + inline auto_thread_env& auto_thread_env:: + operator= (auto_thread_env&& x) noexcept + { + if (this != &x) + { + prev_env = std::move (x.prev_env); + x.prev_env = nullopt; + } + + return *this; + } + + inline auto_thread_env:: + ~auto_thread_env () + { + if (prev_env) + thread_env (*prev_env); } template <typename F, typename P> |