diff options
Diffstat (limited to 'zen')
-rw-r--r-- | zen/dir_watcher.h | 4 | ||||
-rw-r--r-- | zen/file_access.cpp | 15 | ||||
-rw-r--r-- | zen/file_error.h | 2 | ||||
-rw-r--r-- | zen/file_traverser.cpp | 2 | ||||
-rw-r--r-- | zen/globals.h | 17 | ||||
-rw-r--r-- | zen/legacy_compiler.h | 48 | ||||
-rw-r--r-- | zen/open_ssl.cpp | 1 | ||||
-rw-r--r-- | zen/ring_buffer.h | 2 | ||||
-rw-r--r-- | zen/shell_execute.cpp | 2 | ||||
-rw-r--r-- | zen/shutdown.cpp | 4 | ||||
-rw-r--r-- | zen/string_base.h | 49 | ||||
-rw-r--r-- | zen/sys_error.h | 8 | ||||
-rw-r--r-- | zen/system.cpp | 41 | ||||
-rw-r--r-- | zen/thread.cpp | 2 | ||||
-rw-r--r-- | zen/thread.h | 5 |
15 files changed, 62 insertions, 140 deletions
diff --git a/zen/dir_watcher.h b/zen/dir_watcher.h index 3103039d..bf71fda9 100644 --- a/zen/dir_watcher.h +++ b/zen/dir_watcher.h @@ -44,8 +44,8 @@ public: enum class ChangeType { - create, //informal! - update, //use for debugging/logging only! + create, // + update, //informal: use for debugging/logging only! remove, // baseFolderUnavailable, //1. not existing or 2. can't access }; diff --git a/zen/file_access.cpp b/zen/file_access.cpp index cb5a45ed..9a49cd55 100644 --- a/zen/file_access.cpp +++ b/zen/file_access.cpp @@ -127,6 +127,7 @@ std::optional<ItemType> zen::itemStillExists(const Zstring& itemPath) //throw Fi assert(!itemName.empty()); const std::optional<ItemType> parentType = itemStillExists(*parentPath); //throw FileError + if (parentType && *parentType != ItemType::FILE /*obscure, but possible (and not an error)*/) try { @@ -246,14 +247,12 @@ void zen::removeDirectoryPlain(const Zstring& dirPath) //throw FileError } throw FileError(replaceCpy(_("Cannot delete directory %x."), L"%x", fmtPath(dirPath)), formatSystemError(functionName, ec)); } - /* - Windows: may spuriously fail with ERROR_DIR_NOT_EMPTY(145) even though all child items have - successfully been *marked* for deletion, but some application still has a handle open! - e.g. Open "C:\Test\Dir1\Dir2" (filled with lots of files) in Explorer, then delete "C:\Test\Dir1" via ::RemoveDirectory() => Error 145 - Sample code: http://us.generation-nt.com/answer/createfile-directory-handles-removing-parent-help-29126332.html - Alternatives: 1. move file/empty folder to some other location, then DeleteFile()/RemoveDirectory() - 2. use CreateFile/FILE_FLAG_DELETE_ON_CLOSE *without* FILE_SHARE_DELETE instead of DeleteFile() => early failure - */ + /* Windows: may spuriously fail with ERROR_DIR_NOT_EMPTY(145) even though all child items have + successfully been *marked* for deletion, but some application still has a handle open! + e.g. Open "C:\Test\Dir1\Dir2" (filled with lots of files) in Explorer, then delete "C:\Test\Dir1" via ::RemoveDirectory() => Error 145 + Sample code: http://us.generation-nt.com/answer/createfile-directory-handles-removing-parent-help-29126332.html + Alternatives: 1. move file/empty folder to some other location, then DeleteFile()/RemoveDirectory() + 2. use CreateFile/FILE_FLAG_DELETE_ON_CLOSE *without* FILE_SHARE_DELETE instead of DeleteFile() => early failure */ } diff --git a/zen/file_error.h b/zen/file_error.h index 55935eba..b9ce9419 100644 --- a/zen/file_error.h +++ b/zen/file_error.h @@ -7,9 +7,7 @@ #ifndef FILE_ERROR_H_839567308565656789 #define FILE_ERROR_H_839567308565656789 -#include <string> #include "zstring.h" -#include "utf.h" #include "sys_error.h" //we'll need this later anyway! diff --git a/zen/file_traverser.cpp b/zen/file_traverser.cpp index 48185516..28e62236 100644 --- a/zen/file_traverser.cpp +++ b/zen/file_traverser.cpp @@ -51,7 +51,7 @@ void zen::traverseFolder(const Zstring& dirPath, const Zstring& itemName = itemNameRaw; if (itemName.empty()) //checks result of normalizeUtfForPosix, too! - throw FileError(replaceCpy(_("Cannot read directory %x."), L"%x", fmtPath(dirPath)), formatSystemError("readdir", L"", L"Data corruption; item with empty name.")); + throw FileError(replaceCpy(_("Cannot read directory %x."), L"%x", fmtPath(dirPath)), formatSystemError("readdir", L"", L"Folder contains child item without a name.")); const Zstring& itemPath = appendSeparator(dirPath) + itemName; diff --git a/zen/globals.h b/zen/globals.h index 4c1453a2..876d2598 100644 --- a/zen/globals.h +++ b/zen/globals.h @@ -21,8 +21,7 @@ Solve static destruction order fiasco by providing shared ownership and serializ => use trivially-destructible POD only!!! ATTENTION: function-static globals have the compiler generate "magic statics" == compiler-genenerated locking code which will crash or leak memory when accessed after global is "dead" - => "solved" by FunStatGlobal, but we can't have "too many" of these... -*/ + => "solved" by FunStatGlobal, but we can't have "too many" of these... */ class PodSpinMutex { @@ -33,7 +32,11 @@ public: bool isLocked(); private: - std::atomic_flag flag_; //= ATOMIC_FLAG_INIT; rely entirely on static zero-initialization! => avoid potential contention with worker thread during Global<> construction! + std::atomic_flag flag_; /* => avoid potential contention with worker thread during Global<> construction! + - "For an atomic_flag with static storage duration, this guarantees static initialization:" => just what the doctor ordered! + - "[default initialization] initializes std::atomic_flag to clear state" - since C++20 => + - "std::atomic_flag is [...] guaranteed to be lock-free" + - interestingly, is_trivially_constructible_v<> is false, thanks to constexpr! https://developercommunity.visualstudio.com/content/problem/416343/stdatomic-no-longer-is-trivially-constructible.html */ }; @@ -43,7 +46,7 @@ class Global //don't use for function-scope statics! public: Global() { - static_assert(std::is_trivially_constructible_v<Pod>&& std::is_trivially_destructible_v<Pod>, "this memory needs to live forever"); + static_assert(std::is_trivially_destructible_v<Pod>, "this memory needs to live forever"); assert(!pod_.spinLock.isLocked()); //we depend on static zero-initialization! assert(!pod_.inst); // } @@ -106,8 +109,7 @@ public: std::shared_ptr<T> get() { - static_assert(std::is_trivially_constructible_v<FunStatGlobal>&& - std::is_trivially_destructible_v<FunStatGlobal>, "this class must not generate code for magic statics!"); + static_assert(std::is_trivially_destructible_v<FunStatGlobal>, "this class must not generate code for magic statics!"); pod_.spinLock.lock(); ZEN_ON_SCOPE_EXIT(pod_.spinLock.unlock()); @@ -184,8 +186,7 @@ void registerGlobalForDestruction(CleanUpEntry& entry) CleanUpEntry* head; } cleanUpList; - static_assert(std::is_trivially_constructible_v<decltype(cleanUpList)>&& - std::is_trivially_destructible_v<decltype(cleanUpList)>, "we must not generate code for magic statics!"); + static_assert(std::is_trivially_destructible_v<decltype(cleanUpList)>, "we must not generate code for magic statics!"); cleanUpList.spinLock.lock(); ZEN_ON_SCOPE_EXIT(cleanUpList.spinLock.unlock()); diff --git a/zen/legacy_compiler.h b/zen/legacy_compiler.h index 8d44f3f7..b480aa6d 100644 --- a/zen/legacy_compiler.h +++ b/zen/legacy_compiler.h @@ -7,6 +7,9 @@ #ifndef LEGACY_COMPILER_H_839567308565656789 #define LEGACY_COMPILER_H_839567308565656789 + #include <numbers> //C++20 + + #include <span> //requires C++20 @@ -18,53 +21,8 @@ namespace std //--------------------------------------------------------------------------------- -#if __cpp_lib_span - #error get rid of workaround: -#endif - -template <class T> -class span -{ -public: - template <class Iterator> - span(Iterator first, Iterator last) : size_(last - first), data_(first != last ? &*first : nullptr) {} - - template <class Container> - span(Container& cont) : span(cont.begin(), cont.end()) {} - - using iterator = T*; - using const_iterator = const T*; - - iterator begin() { return data_; } - iterator end () { return data_ + size_; } - - const_iterator begin() const { return data_; } - const_iterator end () const { return data_ + size_; } - const_iterator cbegin() const { return begin(); } - const_iterator cend () const { return end (); } - T* data() const { return data_; } - size_t size() const { return size_; } - bool empty() const { return size_ == 0; } - -private: - const size_t size_; - T* const data_; -}; - - -#if __cpp_lib_math_constants - #error get rid of workaround: -#endif - -namespace numbers -{ -const double pi = 3.14159265358979323846; -const double e = 2.71828182845904523536; -const double sqrt2 = 1.41421356237309504880; -const double ln2 = 0.693147180559945309417; -} } diff --git a/zen/open_ssl.cpp b/zen/open_ssl.cpp index 1feeb1a9..64b20bb3 100644 --- a/zen/open_ssl.cpp +++ b/zen/open_ssl.cpp @@ -569,7 +569,6 @@ public: if (sslError == SSL_ERROR_ZERO_RETURN) return 0; //EOF + close_notify alert - warn_static("find a better solution for SSL_read_ex + EOF") #if OPENSSL_VERSION_NUMBER == 0x1010105fL //OpenSSL 1.1.1e const auto ec = ::ERR_peek_last_error(); if (sslError == SSL_ERROR_SSL && ERR_GET_REASON(ec) == SSL_R_UNEXPECTED_EOF_WHILE_READING) //EOF: only expected for HTTP/1.0 diff --git a/zen/ring_buffer.h b/zen/ring_buffer.h index 8cce8e80..a8d629c6 100644 --- a/zen/ring_buffer.h +++ b/zen/ring_buffer.h @@ -210,7 +210,7 @@ private: RingBuffer (const RingBuffer&) = delete; //wait until there is a reason to copy a RingBuffer RingBuffer& operator=(const RingBuffer&) = delete; // - RingBuffer(size_t capacity) : + explicit RingBuffer(size_t capacity) : rawMem_(static_cast<std::byte*>(::operator new (capacity * sizeof(T)))), //throw std::bad_alloc capacity_(capacity) {} diff --git a/zen/shell_execute.cpp b/zen/shell_execute.cpp index 63696568..c8779bb8 100644 --- a/zen/shell_execute.cpp +++ b/zen/shell_execute.cpp @@ -240,7 +240,7 @@ void zen::openWithDefaultApp(const Zstring& itemPath) //throw FileError const Zstring cmdTemplate = R"(xdg-open "%x")"; //doesn't block => no need for time out! const Zstring cmdLine = replaceCpy(cmdTemplate, Zstr("%x"), itemPath); - if (const auto [exitCode, output] = consoleExecute(cmdLine, std::nullopt /*timeoutMs*/); //throw SysError, (SysErrorTimeOut) + if (const auto& [exitCode, output] = consoleExecute(cmdLine, std::nullopt /*timeoutMs*/); //throw SysError, (SysErrorTimeOut) exitCode != 0) throw SysError(formatSystemError(utfTo<std::string>(cmdTemplate), replaceCpy(_("Exit code %x"), L"%x", numberTo<std::wstring>(exitCode)), output)); } diff --git a/zen/shutdown.cpp b/zen/shutdown.cpp index 21e24527..8e8456df 100644 --- a/zen/shutdown.cpp +++ b/zen/shutdown.cpp @@ -19,7 +19,7 @@ void zen::shutdownSystem() //throw FileError { //https://linux.die.net/man/2/reboot => needs admin rights! //"systemctl" should work without admin rights: - const auto [exitCode, output] = consoleExecute("systemctl poweroff", std::nullopt /*timeoutMs*/); //throw SysError, (SysErrorTimeOut) + const auto& [exitCode, output] = consoleExecute("systemctl poweroff", std::nullopt /*timeoutMs*/); //throw SysError, (SysErrorTimeOut) if (!trimCpy(output).empty()) //see comment in suspendSystem() throw SysError(output); @@ -33,7 +33,7 @@ void zen::suspendSystem() //throw FileError try { //"systemctl" should work without admin rights: - const auto [exitCode, output] = consoleExecute("systemctl suspend", std::nullopt /*timeoutMs*/); //throw SysError, (SysErrorTimeOut) + const auto& [exitCode, output] = consoleExecute("systemctl suspend", std::nullopt /*timeoutMs*/); //throw SysError, (SysErrorTimeOut) //why does "systemctl suspend" return exit code 1 despite apparent success!?? if (!trimCpy(output).empty()) //at least we can assume "no output" on success throw SysError(output); diff --git a/zen/string_base.h b/zen/string_base.h index 5922c3ff..58e5d43a 100644 --- a/zen/string_base.h +++ b/zen/string_base.h @@ -12,9 +12,7 @@ #include <cstdint> #include <atomic> #include "string_tools.h" -#if __cpp_impl_three_way_comparison && __cpp_lib_three_way_comparison #include <compare> -#endif //Zbase - a policy based string class optimizing performance and flexibility @@ -295,29 +293,15 @@ private: }; -#if __cpp_impl_three_way_comparison && __cpp_lib_three_way_comparison - #error implement! -#endif - template <class Char, template <class> class SP> bool operator==(const Zbase<Char, SP>& lhs, const Zbase<Char, SP>& rhs); template <class Char, template <class> class SP> bool operator==(const Zbase<Char, SP>& lhs, const Char* rhs); template <class Char, template <class> class SP> inline bool operator==(const Char* lhs, const Zbase<Char, SP>& rhs) { return operator==(rhs, lhs); } -#if __cpp_impl_three_way_comparison && __cpp_lib_three_way_comparison template <class Char, template <class> class SP> std::strong_ordering operator<=>(const Zbase<Char, SP>& lhs, const Zbase<Char, SP>& rhs); template <class Char, template <class> class SP> std::strong_ordering operator<=>(const Zbase<Char, SP>& lhs, const Char* rhs); template <class Char, template <class> class SP> std::strong_ordering operator<=>(const Char* lhs, const Zbase<Char, SP>& rhs); -#else -template <class Char, template <class> class SP> inline bool operator!=(const Zbase<Char, SP>& lhs, const Zbase<Char, SP>& rhs) { return !operator==(lhs, rhs); } -template <class Char, template <class> class SP> inline bool operator!=(const Zbase<Char, SP>& lhs, const Char* rhs) { return !operator==(lhs, rhs); } -template <class Char, template <class> class SP> inline bool operator!=(const Char* lhs, const Zbase<Char, SP>& rhs) { return !operator==(lhs, rhs); } - -template <class Char, template <class> class SP> bool operator<(const Zbase<Char, SP>& lhs, const Zbase<Char, SP>& rhs); -template <class Char, template <class> class SP> bool operator<(const Zbase<Char, SP>& lhs, const Char* rhs); -template <class Char, template <class> class SP> bool operator<(const Char* lhs, const Zbase<Char, SP>& rhs); -#endif template <class Char, template <class> class SP> inline Zbase<Char, SP> operator+(const Zbase<Char, SP>& lhs, const Zbase<Char, SP>& rhs) { return Zbase<Char, SP>(lhs) += rhs; } template <class Char, template <class> class SP> inline Zbase<Char, SP> operator+(const Zbase<Char, SP>& lhs, const Char* rhs) { return Zbase<Char, SP>(lhs) += rhs; } @@ -498,12 +482,11 @@ bool operator==(const Zbase<Char, SP>& lhs, const Char* rhs) } -#if __cpp_impl_three_way_comparison && __cpp_lib_three_way_comparison template <class Char, template <class> class SP> inline std::strong_ordering operator<=>(const Zbase<Char, SP>& lhs, const Zbase<Char, SP>& rhs) { - return std::lexicographical_compare_three_way(lhs.begin(), lhs.end(), //respect embedded 0 - rhs.begin(), rhs.end()); + return std::lexicographical_compare_three_way(lhs.begin(), lhs.end(), //respect embedded 0 + rhs.begin(), rhs.end()); // } @@ -518,35 +501,11 @@ std::strong_ordering operator<=>(const Zbase<Char, SP>& lhs, const Char* rhs) template <class Char, template <class> class SP> inline std::strong_ordering operator<=>(const Char* lhs, const Zbase<Char, SP>& rhs) { - return std::lexicographical_compare_three_way(lhs, lhs + strLength(lhs), //respect embedded 0 - rhs.begin(), rhs.end()); -} - -#else -template <class Char, template <class> class SP> inline -bool operator<(const Zbase<Char, SP>& lhs, const Zbase<Char, SP>& rhs) -{ - return std::lexicographical_compare(lhs.begin(), lhs.end(), //respect embedded 0 - rhs.begin(), rhs.end()); -} - - -template <class Char, template <class> class SP> inline -bool operator<(const Zbase<Char, SP>& lhs, const Char* rhs) -{ - return std::lexicographical_compare(lhs.begin(), lhs.end(), //respect embedded 0 - rhs, rhs + strLength(rhs)); + return std::lexicographical_compare_three_way(lhs, lhs + strLength(lhs), + rhs.begin(), rhs.end()); //respect embedded 0 } -template <class Char, template <class> class SP> inline -bool operator<(const Char* lhs, const Zbase<Char, SP>& rhs) -{ - return std::lexicographical_compare(lhs, lhs + strLength(lhs), //respect embedded 0 - rhs.begin(), rhs.end()); -} -#endif - template <class Char, template <class> class SP> inline size_t Zbase<Char, SP>::length() const diff --git a/zen/sys_error.h b/zen/sys_error.h index 2dd3c188..01df17ab 100644 --- a/zen/sys_error.h +++ b/zen/sys_error.h @@ -7,10 +7,10 @@ #ifndef SYS_ERROR_H_3284791347018951324534 #define SYS_ERROR_H_3284791347018951324534 -#include <string> -#include "scope_guard.h" -#include "i18n.h" -#include "utf.h" +//#include <string> +#include "scope_guard.h" // +#include "utf.h" //not used by this header, but the "rest of the world" needs it! +#include "i18n.h" // #include <cerrno> diff --git a/zen/system.cpp b/zen/system.cpp index d9a169c7..aa967f71 100644 --- a/zen/system.cpp +++ b/zen/system.cpp @@ -96,22 +96,31 @@ std::wstring zen::getOsDescription() //throw FileError { try { - std::wstring osName; - std::wstring osVersion; - - if (const auto [exitCode, output] = consoleExecute("lsb_release --id -s", std::nullopt); //throw SysError - exitCode != 0) - throw SysError(formatSystemError("lsb_release --id", replaceCpy(_("Exit code %x"), L"%x", numberTo<std::wstring>(exitCode)), output)); - else - osName = trimCpy(output); - - if (const auto [exitCode, output] = consoleExecute("lsb_release --release -s", std::nullopt); //throw SysError - exitCode != 0) - throw SysError(formatSystemError("lsb_release --release", replaceCpy(_("Exit code %x"), L"%x", numberTo<std::wstring>(exitCode)), output)); - else - osVersion = trimCpy(output); - - return osName + L' ' + osVersion; //e.g. "CentOS 7.7.1908" + //"lsb_release" not available on some systems: https://freefilesync.org/forum/viewtopic.php?t=7191 + // => use /etc/os-release: https://www.freedesktop.org/software/systemd/man/os-release.html + std::string releaseInfo; + try + { + releaseInfo = loadBinContainer<std::string>("/etc/os-release", nullptr /*notifyUnbufferedIO*/); //throw FileError + } + catch (const FileError& e) { throw SysError(e.toString()); } //further enrich with context info => SysError + + std::string osName; + std::string osVersion; + for (const std::string& line : split(releaseInfo, '\n', SplitType::SKIP_EMPTY)) //throw FileError + if (startsWith(line, "NAME=")) + osName = afterFirst(line, '=', IF_MISSING_RETURN_NONE); + else if (startsWith(line, "VERSION_ID=")) + osVersion = afterFirst(line, '=', IF_MISSING_RETURN_NONE); + + trim(osName, true, true, [](char c) { return c == '"' || c == '\''; }); + trim(osVersion, true, true, [](char c) { return c == '"' || c == '\''; }); + + if (osName .empty()) throw SysError(formatSystemError("/etc/os-release", L"", L"NAME missing.")); + if (osVersion.empty()) throw SysError(formatSystemError("/etc/os-release", L"", L"VERSION_ID missing.")); + + //PRETTY_NAME? too wordy! e.g. "Fedora 17 (Beefy Miracle)" + return utfTo<std::wstring>(osName + ' ' + osVersion); //e.g. "CentOS Linux 7" } catch (const SysError& e) { throw FileError(_("Cannot get process information."), e.toString()); } diff --git a/zen/thread.cpp b/zen/thread.cpp index 6e8b8219..6b763f39 100644 --- a/zen/thread.cpp +++ b/zen/thread.cpp @@ -53,3 +53,5 @@ uint64_t zen::getMainThreadId() return globalMainThreadId; } + + diff --git a/zen/thread.h b/zen/thread.h index a1d5197c..99e61e1f 100644 --- a/zen/thread.h +++ b/zen/thread.h @@ -18,9 +18,6 @@ namespace zen { class InterruptionStatus; -#if __cpp_lib_jthread - #error refactor! -#endif class InterruptibleThread { public: @@ -92,7 +89,7 @@ template<typename T> inline bool isReady(const std::future<T>& f) { return f.wait_for(std::chrono::seconds(0)) == std::future_status::ready; } //------------------------------------------------------------------------------------------ -//wait until first job is successful or all failed: substitute until std::when_any is available +//wait until first job is successful or all failed //TODO: use std::when_any when available template <class T> class AsyncFirstResult |