diff options
Diffstat (limited to 'libbutl/utility.cxx')
-rw-r--r-- | libbutl/utility.cxx | 157 |
1 files changed, 117 insertions, 40 deletions
diff --git a/libbutl/utility.cxx b/libbutl/utility.cxx index d6a21c6..b03a8f8 100644 --- a/libbutl/utility.cxx +++ b/libbutl/utility.cxx @@ -1,44 +1,23 @@ // file : libbutl/utility.cxx -*- C++ -*- // license : MIT; see accompanying LICENSE file -#ifndef __cpp_modules_ts -#include <libbutl/utility.mxx> -#endif +#include <libbutl/utility.hxx> #ifdef _WIN32 #include <libbutl/win32-utility.hxx> #endif -#include <stdlib.h> // setenv(), unsetenv(), _putenv() - -#ifndef __cpp_lib_modules_ts -#include <string> -#include <cstddef> -#include <utility> +#include <stdlib.h> // getenv(), setenv(), unsetenv(), _putenv() +#include <cstring> // strncmp(), strlen() #include <ostream> #include <type_traits> // enable_if, is_base_of #include <system_error> -#endif #include <libbutl/ft/lang.hxx> #include <libbutl/ft/exception.hxx> -#ifdef __cpp_modules_ts -module butl.utility; - -// Only imports additional to interface. -#ifdef __clang__ -#ifdef __cpp_lib_modules_ts -import std.core; -import std.io; -#endif -#endif - -import butl.utf8; -#else -#include <libbutl/utf8.mxx> -#endif +#include <libbutl/utf8.hxx> namespace butl { @@ -51,11 +30,21 @@ namespace butl #else __thread #endif - bool exception_unwinding_dtor_ = false; +#if defined(__GLIBC__) && \ + defined(__GLIBC_MINOR__) && \ + (__GLIBC__ < 2 || __GLIBC__ == 2 && __GLIBC_MINOR__ < 17) + int +#else + bool +#endif + exception_unwinding_dtor_ = false; #ifdef _WIN32 - bool& + bool exception_unwinding_dtor () {return exception_unwinding_dtor_;} + + void + exception_unwinding_dtor (bool v) {exception_unwinding_dtor_ = v;} #endif #endif @@ -182,13 +171,42 @@ namespace butl for (; i != n && ws (l[i]); ++i) ; for (; n != i && ws (l[n - 1]); --n) ; - if (i != 0) + if (n != l.size ()) l.resize (n); + if (i != 0) l.erase (0, i); + + return l; + } + + string& + trim_left (string& l) + { + auto ws = [] (char c ) { - string s (l, i, n - i); - l.swap (s); - } - else if (n != l.size ()) - l.resize (n); + return c == ' ' || c == '\t' || c == '\n' || c == '\r'; + }; + + size_t i (0), n (l.size ()); + + for (; i != n && ws (l[i]); ++i) ; + + if (i != 0) l.erase (0, i); + + return l; + } + + string& + trim_right (string& l) + { + auto ws = [] (char c ) + { + return c == ' ' || c == '\t' || c == '\n' || c == '\r'; + }; + + size_t i (0), n (l.size ()); + + for (; n != i && ws (l[n - 1]); --n) ; + + if (n != l.size ()) l.resize (n); return l; } @@ -322,6 +340,55 @@ namespace butl s.resize (d - s.begin ()); } +#ifdef __cpp_thread_local + thread_local +#else + __thread +#endif + const char* const* thread_env_ = nullptr; + +#ifdef _WIN32 + const char* const* + thread_env () {return thread_env_;} + + void + thread_env (const char* const* v) {thread_env_ = v;} +#endif + + optional<std::string> + getenv (const char* name) + { + if (const char* const* vs = thread_env_) + { + size_t n (strlen (name)); + + for (; *vs != nullptr; ++vs) + { + const char* v (*vs); + + // Note that on Windows variable names are case-insensitive. + // +#ifdef _WIN32 + if (icasecmp (name, v, n) == 0) +#else + if (strncmp (name, v, n) == 0) +#endif + { + switch (v[n]) + { + case '=': return string (v + n + 1); + case '\0': return nullopt; + } + } + } + } + + if (const char* r = ::getenv (name)) + return std::string (r); + + return nullopt; + } + void setenv (const string& name, const string& value) { @@ -378,7 +445,7 @@ namespace std // Invalid data.\r\n // size_t n (string::traits_type::length (s)); - for (; n > 0; --n) + for (; n != 0; --n) { switch (s[n-1]) { @@ -401,7 +468,7 @@ namespace std // Check if the string ends with the specified suffix and return its // length if that's the case. So can be used as bool. // - auto suffix = [s, n] (const char* v) -> size_t + auto suffix = [s, &n] (const char* v) -> size_t { size_t nv (string::traits_type::length (v)); return (n >= nv && string::traits_type::compare (s + n - nv, v, nv) == 0 @@ -409,17 +476,27 @@ namespace std : 0); }; + // Note that in some cases we need to re-throw exception using a different + // type, for example system_error as ios::failure. In such cases these + // suffixed may accumulate, for example: + // + // Access denied. : Success.: Success. + // + // Thus, we will strip them in a loop. + // size_t ns; - if ((ns = suffix (". : Success")) || - (ns = suffix (". : No error")) || - (ns = suffix (". : The operation completed successfully"))) - n -= ns; + while ((ns = suffix (": Success")) || + (ns = suffix (": No error")) || + (ns = suffix (": The operation completed successfully"))) + { + for (n -= ns; n != 0 && (s[n-1] == '.' || s[n-1] == ' '); --n) ; + } // Lower-case the first letter if the beginning looks like a word (the // second character is the lower-case letter or space). // char c; - bool lc (n > 0 && alpha (c = s[0]) && c == ucase (c) && + bool lc (n != 0 && alpha (c = s[0]) && c == ucase (c) && (n == 1 || (alpha (c = s[1]) && c == lcase (c)) || c == ' ')); // Print the description as is if no adjustment is required. |