summaryrefslogtreecommitdiff
path: root/zen
diff options
context:
space:
mode:
Diffstat (limited to 'zen')
-rw-r--r--zen/file_traverser.cpp1
-rw-r--r--zen/globals.h2
-rw-r--r--zen/http.cpp6
-rw-r--r--zen/legacy_compiler.h1
-rw-r--r--zen/open_ssl.cpp1
-rw-r--r--zen/resolve_path.cpp1
-rw-r--r--zen/shutdown.cpp41
-rw-r--r--zen/shutdown.h6
-rw-r--r--zen/stl_tools.h15
-rw-r--r--zen/string_tools.h122
-rw-r--r--zen/sys_info.cpp18
-rw-r--r--zen/zstring.cpp2
-rw-r--r--zen/zstring.h2
13 files changed, 148 insertions, 70 deletions
diff --git a/zen/file_traverser.cpp b/zen/file_traverser.cpp
index f1b5519b..515580ae 100644
--- a/zen/file_traverser.cpp
+++ b/zen/file_traverser.cpp
@@ -8,7 +8,6 @@
#include "file_error.h"
- //#include <unistd.h> //::pathconf()
#include <sys/stat.h>
#include <dirent.h>
diff --git a/zen/globals.h b/zen/globals.h
index 6a50a497..dd0dfed9 100644
--- a/zen/globals.h
+++ b/zen/globals.h
@@ -219,6 +219,8 @@ bool PodSpinMutex::tryLock()
}
+
+
inline
void PodSpinMutex::lock()
{
diff --git a/zen/http.cpp b/zen/http.cpp
index 24c5aa73..4fe43ede 100644
--- a/zen/http.cpp
+++ b/zen/http.cpp
@@ -144,7 +144,7 @@ public:
statusCode_ = stringTo<int>(statusItems[1]);
- for (const std::string& line : split(headersBuf, "\r\n", SplitOnEmpty::skip))
+ for (const std::string& line : split(headersBuf, '\n', SplitOnEmpty::skip)) //careful: actual line separator is "\r\n"!
responseHeaders_[trimCpy(beforeFirst(line, ':', IfNotFoundReturn::all))] =
/**/ trimCpy(afterFirst (line, ':', IfNotFoundReturn::none));
@@ -344,7 +344,7 @@ bool zen::internetIsAlive() //noexcept
{
try
{
- auto response = std::make_unique<HttpInputStream::Impl>(Zstr("http://www.google.com/"),
+ auto response = std::make_unique<HttpInputStream::Impl>(Zstr("https://www.google.com/"), //https more appropriate than http for testing? (different ports!)
nullptr /*postParams*/,
"" /*contentType*/,
true /*disableGetCache*/,
@@ -353,7 +353,7 @@ bool zen::internetIsAlive() //noexcept
nullptr /*notifyUnbufferedIO*/); //throw SysError
const int statusCode = response->getStatusCode();
- //attention: http://www.google.com/ might redirect to "https" => don't follow, just return "true"!!!
+ //attention: google.com might redirect to https://consent.google.com => don't follow, just return "true"!!!
return statusCode / 100 == 2 || //e.g. 200
statusCode / 100 == 3; //e.g. 301, 302, 303, 307... when in doubt, consider internet alive!
}
diff --git a/zen/legacy_compiler.h b/zen/legacy_compiler.h
index 50d340ca..6c9381ee 100644
--- a/zen/legacy_compiler.h
+++ b/zen/legacy_compiler.h
@@ -22,6 +22,7 @@
Clang https://clang.llvm.org/cxx_status.html#cxx20
libc++ https://libcxx.llvm.org/cxx2a_status.html */
+
namespace std
{
}
diff --git a/zen/open_ssl.cpp b/zen/open_ssl.cpp
index 5e4c370d..99d7582e 100644
--- a/zen/open_ssl.cpp
+++ b/zen/open_ssl.cpp
@@ -5,6 +5,7 @@
// *****************************************************************************
#include "open_ssl.h"
+#include <bit> //std::endian (needed for macOS)
#include "base64.h"
#include "thread.h"
#include <openssl/pem.h>
diff --git a/zen/resolve_path.cpp b/zen/resolve_path.cpp
index 17d3b777..f0a49976 100644
--- a/zen/resolve_path.cpp
+++ b/zen/resolve_path.cpp
@@ -145,7 +145,6 @@ std::optional<Zstring> tryResolveMacro(const Zstring& macro) //macro without %-c
if (std::optional<Zstring> value = getEnvironmentVar(macro))
return *value;
-
return {};
}
diff --git a/zen/shutdown.cpp b/zen/shutdown.cpp
index f46caf6b..a812d6ae 100644
--- a/zen/shutdown.cpp
+++ b/zen/shutdown.cpp
@@ -5,6 +5,7 @@
// *****************************************************************************
#include "shutdown.h"
+#include "thread.h"
#include <zen/process_exec.h>
@@ -15,6 +16,9 @@ using namespace zen;
void zen::shutdownSystem() //throw FileError
{
+ assert(runningOnMainThread());
+ if (runningOnMainThread())
+ onSystemShutdownRunTasks();
try
{
//https://linux.die.net/man/2/reboot => needs admin rights!
@@ -62,3 +66,40 @@ void zen::terminateProcess(int exitCode)
// alternative requiring admin: sudo killall Xorg
// alternative without admin: dbus-send --session --print-reply --dest=org.gnome.SessionManager /org/gnome/SessionManager org.gnome.SessionManager.Logout uint32:1
+
+
+namespace
+{
+using ShutdownTaskList = std::vector<std::weak_ptr<const std::function<void()>>>;
+constinit Global<ShutdownTaskList> globalShutdownTasks;
+GLOBAL_RUN_ONCE(globalShutdownTasks.set(std::make_unique<ShutdownTaskList>()));
+}
+
+
+void zen::onSystemShutdownRegister(const SharedRef<std::function<void()>>& task)
+{
+ assert(runningOnMainThread());
+
+ const auto& tasks = globalShutdownTasks.get();
+ assert(tasks);
+ if (tasks)
+ tasks->push_back(task.ptr());
+}
+
+
+void zen::onSystemShutdownRunTasks()
+{
+ assert(runningOnMainThread()); //no multithreading! else: after taskWeak.lock() task() references may go out of scope! (e.g. "this")
+
+ const auto& tasks = globalShutdownTasks.get();
+ assert(tasks);
+ if (tasks)
+ for (const std::weak_ptr<const std::function<void()>>& taskWeak : *tasks)
+ if (const std::shared_ptr<const std::function<void()>>& task = taskWeak.lock();
+ task)
+ try
+ { (*task)(); }
+ catch (...) { assert(false); }
+
+ globalShutdownTasks.set(nullptr); //trigger assert in onSystemShutdownRegister(), just in case...
+}
diff --git a/zen/shutdown.h b/zen/shutdown.h
index 20354a14..b4d51f69 100644
--- a/zen/shutdown.h
+++ b/zen/shutdown.h
@@ -7,6 +7,7 @@
#ifndef SHUTDOWN_H_3423847870238407783265
#define SHUTDOWN_H_3423847870238407783265
+#include <functional>
#include "file_error.h"
@@ -15,6 +16,11 @@ namespace zen
void shutdownSystem(); //throw FileError
void suspendSystem(); //
[[noreturn]] void terminateProcess(int exitCode);
+
+void onSystemShutdownRegister(const SharedRef<std::function<void()>>& task /*noexcept*/); //save important/user data!
+void onSystemShutdownRegister( SharedRef<std::function<void()>>&& task) = delete; //no temporaries! shared_ptr should manage life time!
+void onSystemShutdownRunTasks(); //call at appropriate time, e.g. when receiving wxEVT_QUERY_END_SESSION/wxEVT_END_SESSION
+//+ also called by shutdownSystem()
}
#endif //SHUTDOWN_H_3423847870238407783265
diff --git a/zen/stl_tools.h b/zen/stl_tools.h
index c2e8eff3..0d359641 100644
--- a/zen/stl_tools.h
+++ b/zen/stl_tools.h
@@ -290,13 +290,26 @@ Num hashArray(ByteIterator first, ByteIterator last)
struct StringHash //support for custom string classes with std::unordered_set/map
{
+ using is_transparent = int; //allow heterogenous lookup!
+
template <class String>
size_t operator()(const String& str) const
{
- const auto* strFirst = strBegin(str);
+ const auto* const strFirst = strBegin(str);
return hashArray<size_t>(strFirst, strFirst + strLength(str));
}
};
+
+struct StringEqual
+{
+ using is_transparent = int; //allow heterogenous lookup!
+
+ template <class String1, class String2>
+ bool operator()(const String1& lhs, const String2& rhs) const
+ {
+ return equalString(lhs, rhs);
+ }
+};
}
#endif //STL_TOOLS_H_84567184321434
diff --git a/zen/string_tools.h b/zen/string_tools.h
index 5f9273c9..ee4e5613 100644
--- a/zen/string_tools.h
+++ b/zen/string_tools.h
@@ -68,12 +68,15 @@ enum class SplitOnEmpty
allow,
skip
};
-template <class S, class T> std::vector<S> split(const S& str, const T& delimiter, SplitOnEmpty soe);
+template <class S, class Char> [[nodiscard]] std::vector<S> split(const S& str, Char delimiter, SplitOnEmpty soe);
+template <class S, class Function1, class Function2> void split2(const S& str, Function1 isDelimiter, Function2 onStringPart);
-template <class S> [[nodiscard]] S trimCpy(S str, bool fromLeft = true, bool fromRight = true);
+template <class S> [[nodiscard]] S trimCpy(S str, bool fromLeft = true, bool fromRight = true);
+template <class Char, class Function> [[nodiscard]] std::pair<Char*, Char*> trimCpy(Char* first, Char* last, bool fromLeft, bool fromRight, Function trimThisChar);
template <class S> void trim (S& str, bool fromLeft = true, bool fromRight = true);
template <class S, class Function> void trim(S& str, bool fromLeft, bool fromRight, Function trimThisChar);
+
template <class S, class T, class U> [[nodiscard]] S replaceCpy(S str, const T& oldTerm, const U& newTerm, bool replaceAll = true);
template <class S, class T, class U> void replace (S& str, const T& oldTerm, const U& newTerm, bool replaceAll = true);
@@ -210,7 +213,7 @@ template <class S, class T> inline
bool startsWith(const S& str, const T& prefix)
{
const size_t pfLen = strLength(prefix);
- return strLength(str) >= pfLen && std::is_eq(impl::strcmpWithNulls(strBegin(str), strBegin(prefix), pfLen));
+ return strLength(str) >= pfLen && impl::strcmpWithNulls(strBegin(str), strBegin(prefix), pfLen) == std::strong_ordering::equal;
}
@@ -218,7 +221,7 @@ template <class S, class T> inline
bool startsWithAsciiNoCase(const S& str, const T& prefix)
{
const size_t pfLen = strLength(prefix);
- return strLength(str) >= pfLen && std::is_eq(impl::strcmpAsciiNoCase(strBegin(str), strBegin(prefix), pfLen));
+ return strLength(str) >= pfLen && impl::strcmpAsciiNoCase(strBegin(str), strBegin(prefix), pfLen) == std::weak_ordering::equivalent;
}
@@ -227,7 +230,7 @@ bool endsWith(const S& str, const T& postfix)
{
const size_t strLen = strLength(str);
const size_t pfLen = strLength(postfix);
- return strLen >= pfLen && std::is_eq(impl::strcmpWithNulls(strBegin(str) + strLen - pfLen, strBegin(postfix), pfLen));
+ return strLen >= pfLen && impl::strcmpWithNulls(strBegin(str) + strLen - pfLen, strBegin(postfix), pfLen) == std::strong_ordering::equal;
}
@@ -236,7 +239,7 @@ bool endsWithAsciiNoCase(const S& str, const T& postfix)
{
const size_t strLen = strLength(str);
const size_t pfLen = strLength(postfix);
- return strLen >= pfLen && std::is_eq(impl::strcmpAsciiNoCase(strBegin(str) + strLen - pfLen, strBegin(postfix), pfLen));
+ return strLen >= pfLen && impl::strcmpAsciiNoCase(strBegin(str) + strLen - pfLen, strBegin(postfix), pfLen) == std::weak_ordering::equivalent;
}
@@ -244,7 +247,7 @@ template <class S, class T> inline
bool equalString(const S& lhs, const T& rhs)
{
const size_t lhsLen = strLength(lhs);
- return lhsLen == strLength(rhs) && std::is_eq(impl::strcmpWithNulls(strBegin(lhs), strBegin(rhs), lhsLen));
+ return lhsLen == strLength(rhs) && impl::strcmpWithNulls(strBegin(lhs), strBegin(rhs), lhsLen) == std::strong_ordering::equal;
}
@@ -252,7 +255,7 @@ template <class S, class T> inline
bool equalAsciiNoCase(const S& lhs, const T& rhs)
{
const size_t lhsLen = strLength(lhs);
- return lhsLen == strLength(rhs) && std::is_eq(impl::strcmpAsciiNoCase(strBegin(lhs), strBegin(rhs), lhsLen));
+ return lhsLen == strLength(rhs) && impl::strcmpAsciiNoCase(strBegin(lhs), strBegin(rhs), lhsLen) == std::weak_ordering::equivalent;
}
@@ -265,7 +268,7 @@ std::strong_ordering compareString(const S& lhs, const T& rhs)
//length check *after* strcmpWithNulls(): we DO care about natural ordering: e.g. for "compareString(getUpperCase(lhs), getUpperCase(rhs))"
if (const std::strong_ordering cmp = impl::strcmpWithNulls(strBegin(lhs), strBegin(rhs), std::min(lhsLen, rhsLen));
- std::is_neq(cmp))
+ cmp != std::strong_ordering::equal)
return cmp;
return lhsLen <=> rhsLen;
}
@@ -279,7 +282,7 @@ std::weak_ordering compareAsciiNoCase(const S& lhs, const T& rhs)
const size_t rhsLen = strLength(rhs);
if (const std::weak_ordering cmp = impl::strcmpAsciiNoCase(strBegin(lhs), strBegin(rhs), std::min(lhsLen, rhsLen));
- std::is_neq(cmp))
+ cmp != std::weak_ordering::equivalent)
return cmp;
return lhsLen <=> rhsLen;
}
@@ -385,37 +388,37 @@ S beforeFirst(const S& str, const T& term, IfNotFoundReturn infr)
}
-template <class S, class T> inline
-std::vector<S> split(const S& str, const T& delimiter, SplitOnEmpty soe)
+template <class S, class Function1, class Function2> inline
+void split2(const S& str, Function1 isDelimiter, Function2 onStringPart)
{
- static_assert(std::is_same_v<GetCharTypeT<S>, GetCharTypeT<T>>);
- const size_t delimLen = strLength(delimiter);
- assert(delimLen > 0);
- if (delimLen == 0)
+ const auto* blockFirst = strBegin(str);
+ const auto* const strEnd = blockFirst + strLength(str);
+
+ for (;;)
{
- if (str.empty() && soe == SplitOnEmpty::skip)
- return {};
- return {str};
- }
+ const auto* const blockLast = std::find_if(blockFirst, strEnd, isDelimiter);
+ onStringPart(blockFirst, blockLast);
+
+ if (blockLast == strEnd)
+ return;
- const auto* const delimFirst = strBegin(delimiter);
- const auto* const delimLast = delimFirst + delimLen;
+ blockFirst = blockLast + 1;
+ }
+}
- const auto* blockStart = strBegin(str);
- const auto* const strLast = blockStart + strLength(str);
+template <class S, class Char> inline
+std::vector<S> split(const S& str, Char delimiter, SplitOnEmpty soe)
+{
+ static_assert(std::is_same_v<GetCharTypeT<S>, Char>);
std::vector<S> output;
- for (;;)
+
+ split2(str, [delimiter](Char c) { return c == delimiter; }, [&](const Char* blockFirst, const Char* blockLast)
{
- const auto* const blockEnd = std::search(blockStart, strLast,
- delimFirst, delimLast);
- if (blockStart != blockEnd || soe == SplitOnEmpty::allow)
- output.emplace_back(blockStart, blockEnd - blockStart);
-
- if (blockEnd == strLast)
- return output;
- blockStart = blockEnd + delimLen;
- }
+ if (blockFirst != blockLast || soe == SplitOnEmpty::allow)
+ output.emplace_back(blockFirst, blockLast);
+ });
+ return output;
}
@@ -484,25 +487,33 @@ void replace(S& str, const T& oldTerm, const U& newTerm, bool replaceAll)
}
-template <class S, class Function> inline
-void trim(S& str, bool fromLeft, bool fromRight, Function trimThisChar)
+template <class Char, class Function> inline
+std::pair<Char*, Char*> trimCpy(Char* first, Char* last, bool fromLeft, bool fromRight, Function trimThisChar)
{
assert(fromLeft || fromRight);
- const auto* const oldBegin = strBegin(str);
- const auto* newBegin = oldBegin;
- const auto* newEnd = oldBegin + strLength(str);
-
if (fromRight)
- while (newBegin != newEnd && trimThisChar(newEnd[-1]))
- --newEnd;
+ while (first != last && trimThisChar(last[-1]))
+ --last;
if (fromLeft)
- while (newBegin != newEnd && trimThisChar(*newBegin))
- ++newBegin;
+ while (first != last && trimThisChar(*first))
+ ++first;
+
+ return {first, last};
+}
+
+
+template <class S, class Function> inline
+void trim(S& str, bool fromLeft, bool fromRight, Function trimThisChar)
+{
+ assert(fromLeft || fromRight);
+
+ const auto* const oldBegin = strBegin(str);
+ const auto& [newBegin, newEnd] = trimCpy(oldBegin, oldBegin + strLength(str), fromLeft, fromRight, trimThisChar);
if (newBegin != oldBegin)
- str = S(newBegin, newEnd - newBegin); //minor inefficiency: in case "str" is not shared, we could save an allocation and do a memory move only
+ str = S(newBegin, newEnd); //minor inefficiency: in case "str" is not shared, we could save an allocation and do a memory move only
else
str.resize(newEnd - newBegin);
}
@@ -613,8 +624,10 @@ S numberTo(const Num& number, std::integral_constant<NumberType, NumberType::flo
const char* strEnd = toChars(std::begin(buffer), std::end(buffer), number);
S output;
- std::for_each(static_cast<const char*>(buffer), strEnd,
- [&](char c) { output += static_cast<GetCharTypeT<S>>(c); });
+
+ for (const char c : makeStringView(static_cast<const char*>(buffer), strEnd))
+ output += static_cast<GetCharTypeT<S>>(c);
+
return output;
}
@@ -716,8 +729,10 @@ double stringToFloat(const char* first, const char* last)
inline
double stringToFloat(const wchar_t* first, const wchar_t* last)
{
- std::string buf(last - first, '\0');
- std::transform(first, last, buf.begin(), [](wchar_t c) { return static_cast<char>(c); });
+ std::string buf; //let's rely on SSO
+
+ for (const wchar_t c : makeStringView(first, last))
+ buf += static_cast<char>(c);
return fromChars(buf.c_str(), buf.c_str() + buf.size());
}
@@ -756,17 +771,16 @@ Num extractInteger(const S& str, bool& hasMinusSign) //very fast conversion to i
}
Num number = 0;
- for (const CharType* it = first; it != last; ++it)
- {
- const CharType c = *it;
+
+ for (const CharType c : makeStringView(first, last))
if (static_cast<CharType>('0') <= c && c <= static_cast<CharType>('9'))
{
number *= 10;
number += c - static_cast<CharType>('0');
}
else //rest of string should contain whitespace only, it's NOT a bug if there is something else!
- break; //assert(std::all_of(iter, last, isWhiteSpace<CharType>)); -> this is NO assert situation
- }
+ break; //assert(std::all_of(it, last, isWhiteSpace<CharType>)); -> this is NO assert situation
+
return number;
}
diff --git a/zen/sys_info.cpp b/zen/sys_info.cpp
index cc852510..d208cc98 100644
--- a/zen/sys_info.cpp
+++ b/zen/sys_info.cpp
@@ -26,6 +26,14 @@ using namespace zen;
Zstring zen::getLoginUser() //throw FileError
{
+ auto tryGetNonRootUser = [](const char* varName) -> const char*
+ {
+ if (const char* buf = ::getenv(varName)) //no extended error reporting
+ if (strLength(buf) > 0 && !equalString(buf, "root"))
+ return buf;
+ return nullptr;
+ };
+
const uid_t userIdNo = ::getuid(); //never fails
if (userIdNo != 0) //nofail; non-root
@@ -54,21 +62,15 @@ Zstring zen::getLoginUser() //throw FileError
return loginUser;
//BUT: getlogin() can fail with ENOENT on Linux Mint: https://freefilesync.org/forum/viewtopic.php?t=8181
- auto tryGetNonRootUser = [](const char* varName) -> const char*
- {
- if (const char* buf = ::getenv(varName)) //no extended error reporting
- if (strLength(buf) > 0 && !equalString(buf, "root"))
- return buf;
- return nullptr;
- };
//getting a little desperate: variables used by installer.sh
if (const char* userName = tryGetNonRootUser("USER")) return userName;
if (const char* userName = tryGetNonRootUser("SUDO_USER")) return userName;
if (const char* userName = tryGetNonRootUser("LOGNAME")) return userName;
+
//apparently the current user really IS root: https://freefilesync.org/forum/viewtopic.php?t=8405
+ assert(getuid() == 0);
return "root";
-
}
diff --git a/zen/zstring.cpp b/zen/zstring.cpp
index 34d52b2c..635fb47d 100644
--- a/zen/zstring.cpp
+++ b/zen/zstring.cpp
@@ -240,7 +240,7 @@ std::weak_ordering compareNatural(const Zstring& lhs, const Zstring& rhs)
while (strR != strEndR && !isWhiteSpace(*strR) && !isDigit(*strR)) ++strR;
if (const std::weak_ordering cmp = compareNoCaseUtf8(textBeginL, strL - textBeginL, textBeginR, strR - textBeginR);
- std::is_neq(cmp))
+ cmp != std::weak_ordering::equivalent)
return cmp;
}
diff --git a/zen/zstring.h b/zen/zstring.h
index b8dfb9a3..15735cb0 100644
--- a/zen/zstring.h
+++ b/zen/zstring.h
@@ -61,7 +61,7 @@ struct ZstringNoCase //use as STL container key: avoid needless upper-case conve
macOS: ignore case + Unicode normalization forms */
std::weak_ordering compareNativePath(const Zstring& lhs, const Zstring& rhs);
-inline bool equalNativePath(const Zstring& lhs, const Zstring& rhs) { return std::is_eq(compareNativePath(lhs, rhs)); }
+inline bool equalNativePath(const Zstring& lhs, const Zstring& rhs) { return compareNativePath(lhs, rhs) == std::weak_ordering::equivalent; }
struct LessNativePath { bool operator()(const Zstring& lhs, const Zstring& rhs) const { return std::is_lt(compareNativePath(lhs, rhs)); } };
bgstack15