summaryrefslogtreecommitdiff
path: root/zen
diff options
context:
space:
mode:
Diffstat (limited to 'zen')
-rw-r--r--zen/argon2.cpp2
-rw-r--r--zen/basic_math.h8
-rw-r--r--zen/dir_watcher.cpp2
-rw-r--r--zen/file_access.cpp46
-rw-r--r--zen/file_access.h3
-rw-r--r--zen/file_io.cpp16
-rw-r--r--zen/file_path.h8
-rw-r--r--zen/file_traverser.h1
-rw-r--r--zen/format_unit.cpp2
-rw-r--r--zen/open_ssl.cpp2
-rw-r--r--zen/perf.h1
-rw-r--r--zen/process_exec.cpp1
-rw-r--r--zen/process_priority.cpp152
-rw-r--r--zen/process_priority.h21
-rw-r--r--zen/scope_guard.h1
-rw-r--r--zen/socket.h2
-rw-r--r--zen/stl_tools.h59
-rw-r--r--zen/stream_buffer.h2
-rw-r--r--zen/string_tools.h2
-rw-r--r--zen/sys_info.cpp1
-rw-r--r--zen/time.h6
-rw-r--r--zen/zstring.h4
22 files changed, 242 insertions, 100 deletions
diff --git a/zen/argon2.cpp b/zen/argon2.cpp
index 5918b4b3..333128ce 100644
--- a/zen/argon2.cpp
+++ b/zen/argon2.cpp
@@ -37,9 +37,7 @@
#include "argon2.h"
#include <cassert>
-//#include <cstring>
#include <cstdint>
-//#include <cstdlib>
#if defined __GNUC__ //including clang
#pragma GCC diagnostic ignored "-Wimplicit-fallthrough" //"this statement may fall through"
diff --git a/zen/basic_math.h b/zen/basic_math.h
index 77ce7b7e..9080d07d 100644
--- a/zen/basic_math.h
+++ b/zen/basic_math.h
@@ -27,7 +27,7 @@ template <class N, class D> auto intDivCeil (N numerator, D denominator);
template <class N, class D> auto intDivFloor(N numerator, D denominator);
template <size_t N, class T>
-T power(T value);
+constexpr T power(T value);
double radToDeg(double rad); //convert unit [rad] into [°]
double degToRad(double degree); //convert unit [°] into [rad]
@@ -207,12 +207,12 @@ namespace
{
template <size_t N, class T> struct PowerImpl;
//let's use non-recursive specializations to help the compiler
-template <class T> struct PowerImpl<2, T> { static T result(T value) { return value * value; } };
-template <class T> struct PowerImpl<3, T> { static T result(T value) { return value * value * value; } };
+template <class T> struct PowerImpl<2, T> { static constexpr T result(T value) { return value * value; } };
+template <class T> struct PowerImpl<3, T> { static constexpr T result(T value) { return value * value * value; } };
}
template <size_t N, class T> inline
-T power(T value)
+constexpr T power(T value)
{
return PowerImpl<N, T>::result(value);
}
diff --git a/zen/dir_watcher.cpp b/zen/dir_watcher.cpp
index 1b7b0ec4..b5533500 100644
--- a/zen/dir_watcher.cpp
+++ b/zen/dir_watcher.cpp
@@ -5,8 +5,6 @@
// *****************************************************************************
#include "dir_watcher.h"
-//#include <algorithm>
-//#include <set>
#include "thread.h"
#include "scope_guard.h"
#include "file_access.h"
diff --git a/zen/file_access.cpp b/zen/file_access.cpp
index e1b2860e..80a14ce7 100644
--- a/zen/file_access.cpp
+++ b/zen/file_access.cpp
@@ -5,9 +5,7 @@
// *****************************************************************************
#include "file_access.h"
-//#include <map>
#include <algorithm>
-//#include <chrono>
#include <variant>
#include "file_traverser.h"
#include "scope_guard.h"
@@ -325,10 +323,21 @@ void moveAndRenameFileSub(const Zstring& pathFrom, const Zstring& pathTo, bool r
if (::rename(pathFrom.c_str(), pathTo.c_str()) != 0)
{
- if (errno == EXDEV)
- throw ErrorMoveUnsupported(getErrorMsg(), formatSystemError("rename", errno));
+ const int ec = errno; //copy before making other system calls!
+ std::wstring errorDescr = formatSystemError("rename", ec);
+
+ if (ec == EXDEV)
+ throw ErrorMoveUnsupported(getErrorMsg(), errorDescr);
+
+ if (ec == EINVAL)
+ for (const Zchar c : getItemName(pathTo))
+ if (contains(fileNameForbiddenChars, c))
+ {
+ errorDescr += L' ' + replaceCpy(_("Unsupported character %x"), L"%x", L"'" + utfTo<std::wstring>(c) + L"'");
+ break;
+ }
- throw FileError(getErrorMsg(), formatSystemError("rename", errno));
+ throw FileError(getErrorMsg(), errorDescr);
}
}
@@ -530,10 +539,21 @@ void zen::createDirectory(const Zstring& dirPath) //throw FileError, ErrorTarget
if (::mkdir(dirPath.c_str(), mode) != 0)
{
- const int ec = errno; //copy before directly or indirectly making other system calls!
+ const int ec = errno; //copy before making other system calls!
+ std::wstring errorDescr = formatSystemError("mkdir", ec);
+
if (ec == EEXIST)
- throw ErrorTargetExisting(replaceCpy(_("Cannot create directory %x."), L"%x", fmtPath(dirPath)), formatSystemError("mkdir", ec));
- THROW_LAST_SYS_ERROR("mkdir");
+ throw ErrorTargetExisting(replaceCpy(_("Cannot create directory %x."), L"%x", fmtPath(dirPath)), errorDescr);
+
+ if (ec == EINVAL)
+ for (const Zchar c : getItemName(dirPath))
+ if (contains(fileNameForbiddenChars, c))
+ {
+ errorDescr += L' ' + replaceCpy(_("Unsupported character %x"), L"%x", L"'" + utfTo<std::wstring>(c) + L"'");
+ break;
+ }
+
+ throw SysError(errorDescr);
}
}
catch (const SysError& e) { throw FileError(replaceCpy(_("Cannot create directory %x."), L"%x", fmtPath(dirPath)), e.toString()); }
@@ -666,11 +686,19 @@ FileCopyResult zen::copyNewFile(const Zstring& sourceFile, const Zstring& target
{
const int ec = errno; //copy before making other system calls!
const std::wstring errorMsg = replaceCpy(_("Cannot write file %x."), L"%x", fmtPath(targetFile));
- const std::wstring errorDescr = formatSystemError("open", ec);
+ std::wstring errorDescr = formatSystemError("open", ec);
if (ec == EEXIST)
throw ErrorTargetExisting(errorMsg, errorDescr);
+ if (ec == EINVAL)
+ for (const Zchar c : getItemName(targetFile))
+ if (contains(fileNameForbiddenChars, c))
+ {
+ errorDescr += L' ' + replaceCpy(_("Unsupported character %x"), L"%x", L"'" + utfTo<std::wstring>(c) + L"'");
+ break;
+ }
+
throw FileError(errorMsg, errorDescr);
}
FileOutputPlain fileOut(fdTarget, targetFile); //pass ownership
diff --git a/zen/file_access.h b/zen/file_access.h
index a3fdcd70..42ee06c0 100644
--- a/zen/file_access.h
+++ b/zen/file_access.h
@@ -7,8 +7,7 @@
#ifndef FILE_ACCESS_H_8017341345614857
#define FILE_ACCESS_H_8017341345614857
-//#include <functional>
-#include "file_path.h"
+#include "file_path.h" //we'll need this later anyway!
#include "file_error.h"
#include "serialize.h" //IoCallback
#include <sys/stat.h>
diff --git a/zen/file_io.cpp b/zen/file_io.cpp
index af80a69a..0a119b4a 100644
--- a/zen/file_io.cpp
+++ b/zen/file_io.cpp
@@ -183,7 +183,7 @@ FileBase::FileHandle openHandleForWrite(const Zstring& filePath) //throw FileErr
{
try
{
- //checkForUnsupportedType(filePath); -> not needed, open() + O_WRONLY should fail fast
+ //check for named pipe, etc.? not needed, open() + O_WRONLY should fail fast
const mode_t lockFileMode = S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP | S_IROTH | S_IWOTH; //0666 => umask will be applied implicitly!
@@ -195,10 +195,20 @@ FileBase::FileHandle openHandleForWrite(const Zstring& filePath) //throw FileErr
if (fdFile == -1)
{
const int ec = errno; //copy before making other system calls!
+ std::wstring errorDescr = formatSystemError("open", ec);
+
if (ec == EEXIST)
- throw ErrorTargetExisting(replaceCpy(_("Cannot write file %x."), L"%x", fmtPath(filePath)), formatSystemError("open", ec));
+ throw ErrorTargetExisting(replaceCpy(_("Cannot write file %x."), L"%x", fmtPath(filePath)), errorDescr);
- THROW_LAST_SYS_ERROR("open");
+ if (ec == EINVAL)
+ for (const Zchar c : getItemName(filePath))
+ if (contains(fileNameForbiddenChars, c))
+ {
+ errorDescr += L' ' + replaceCpy(_("Unsupported character %x"), L"%x", L"'" + utfTo<std::wstring>(c) + L"'");
+ break;
+ }
+
+ throw SysError(errorDescr);
}
return fdFile; //pass ownership
}
diff --git a/zen/file_path.h b/zen/file_path.h
index 960ec52f..9446ad75 100644
--- a/zen/file_path.h
+++ b/zen/file_path.h
@@ -14,6 +14,14 @@ namespace zen
{
const Zchar FILE_NAME_SEPARATOR = '/';
+/* forbidden characters in file names:
+ Windows: <>:"/\|?* https://docs.microsoft.com/de-de/windows/win32/fileio/naming-a-file#naming-conventions
+ Linux: /
+ macOS: :
+*/
+const Zchar fileNameForbiddenChars[] = Zstr(R"(<>:"/\|?*)");
+
+
struct PathComponents
{
Zstring rootPath; //itemPath = rootPath + (FILE_NAME_SEPARATOR?) + relPath
diff --git a/zen/file_traverser.h b/zen/file_traverser.h
index 8c2755d6..8f7d8368 100644
--- a/zen/file_traverser.h
+++ b/zen/file_traverser.h
@@ -9,7 +9,6 @@
#include <functional>
#include "file_error.h"
-//#include "file_path.h"
namespace zen
{
diff --git a/zen/format_unit.cpp b/zen/format_unit.cpp
index fe44ac7b..e9f7571f 100644
--- a/zen/format_unit.cpp
+++ b/zen/format_unit.cpp
@@ -5,8 +5,6 @@
// *****************************************************************************
#include "format_unit.h"
-//#include <ctime>
-//#include <cstdio>
#include "basic_math.h"
#include "sys_error.h"
#include "i18n.h"
diff --git a/zen/open_ssl.cpp b/zen/open_ssl.cpp
index 0d4a89ca..e3fc4260 100644
--- a/zen/open_ssl.cpp
+++ b/zen/open_ssl.cpp
@@ -292,7 +292,7 @@ std::string createHash(const std::string_view str, const EVP_MD* type) //throw S
if (::EVP_DigestUpdate(mdctx, //EVP_MD_CTX* ctx
str.data(), //const void*
- str.size()) != 1) //size_t cnt);
+ str.size()) != 1) //size_t cnt
throw SysError(formatLastOpenSSLError("EVP_DigestUpdate"));
if (::EVP_DigestFinal_ex(mdctx, //EVP_MD_CTX* ctx
diff --git a/zen/perf.h b/zen/perf.h
index fe3c5f67..4dc79563 100644
--- a/zen/perf.h
+++ b/zen/perf.h
@@ -8,7 +8,6 @@
#define PERF_H_83947184145342652456
#include <chrono>
-//#include "scope_guard.h"
#include "string_tools.h"
#include <iostream>
diff --git a/zen/process_exec.cpp b/zen/process_exec.cpp
index 76a2e436..24bb8ad2 100644
--- a/zen/process_exec.cpp
+++ b/zen/process_exec.cpp
@@ -5,7 +5,6 @@
// *****************************************************************************
#include "process_exec.h"
-//#include <chrono>
#include "guid.h"
#include "file_access.h"
#include "file_io.h"
diff --git a/zen/process_priority.cpp b/zen/process_priority.cpp
index b7b4e029..6bd2e3f4 100644
--- a/zen/process_priority.cpp
+++ b/zen/process_priority.cpp
@@ -5,50 +5,120 @@
// *****************************************************************************
#include "process_priority.h"
-#include "i18n.h"
+ #include <sys/resource.h> //setpriority
using namespace zen;
-struct PreventStandby::Impl {};
-PreventStandby::PreventStandby() {}
-PreventStandby::~PreventStandby() {}
-
-//solution for GNOME?: https://people.gnome.org/~mccann/gnome-session/docs/gnome-session.html#org.gnome.SessionManager.Inhibit
-
-struct ScheduleForBackgroundProcessing::Impl {};
-ScheduleForBackgroundProcessing::ScheduleForBackgroundProcessing() {}
-ScheduleForBackgroundProcessing::~ScheduleForBackgroundProcessing() {}
-
-/*
-struct ScheduleForBackgroundProcessing
-{
- - required functions ioprio_get/ioprio_set are not part of glibc: https://linux.die.net/man/2/ioprio_set
- - and probably never will: https://sourceware.org/bugzilla/show_bug.cgi?id=4464
- - /usr/include/linux/ioprio.h not available on Ubuntu, so we can't use it instead
-
- ScheduleForBackgroundProcessing() : oldIoPrio(getIoPriority(IOPRIO_WHO_PROCESS, ::getpid()))
- {
- if (oldIoPrio != -1)
- setIoPriority(::getpid(), IOPRIO_PRIO_VALUE(IOPRIO_CLASS_IDLE, 0));
- }
- ~ScheduleForBackgroundProcessing()
- {
- if (oldIoPrio != -1)
- setIoPriority(::getpid(), oldIoPrio);
- }
-
-private:
- static int getIoPriority(pid_t pid)
- {
- return ::syscall(SYS_ioprio_get, IOPRIO_WHO_PROCESS, pid);
- }
- static int setIoPriority(pid_t pid, int ioprio)
- {
- return ::syscall(SYS_ioprio_set, IOPRIO_WHO_PROCESS, pid, ioprio);
- }
-
- const int oldIoPrio;
+namespace
+{
+#if 0
+//https://linux.die.net/man/2/getpriority
+//CPU priority from highest to lowest range: [-NZERO, NZERO -1] usually: [-20, 19]
+enum //with values from CentOS 7
+{
+ CPU_PRIO_VERYHIGH = -NZERO,
+ CPU_PRIO_HIGH = -5,
+ CPU_PRIO_NORMAL = 0,
+ CPU_PRIO_LOW = 5,
+ CPU_PRIO_VERYLOW = NZERO - 1,
+};
+
+int getCpuPriority() //throw SysError
+{
+ errno = 0;
+ const int prio = getpriority(PRIO_PROCESS, 0 /* = the calling process */);
+ if (prio == -1 && errno != 0) //"can legitimately return the value -1"
+ THROW_LAST_SYS_ERROR("getpriority");
+ return prio;
+}
+
+
+//lowering is allowed, but increasing CPU prio requires admin rights >:(
+void setCpuPriority(int prio) //throw SysError
+{
+ if (setpriority(PRIO_PROCESS, 0 /* = the calling process */, prio) != 0)
+ THROW_LAST_SYS_ERROR("setpriority(" + numberTo<std::string>(prio) + ')');
+}
+#endif
+//---------------------------------------------------------------------------------------------------
+
+//- required functions ioprio_get/ioprio_set are not part of glibc: https://linux.die.net/man/2/ioprio_set
+//- and probably never will: https://sourceware.org/bugzilla/show_bug.cgi?id=4464
+//https://github.com/torvalds/linux/blob/master/include/uapi/linux/ioprio.h
+#define IOPRIO_CLASS_SHIFT 13
+
+#define IOPRIO_PRIO_VALUE(prioclass, priolevel) \
+ (((prioclass) << IOPRIO_CLASS_SHIFT) | (priolevel))
+
+#define IOPRIO_NORM 4
+
+enum
+{
+ IOPRIO_WHO_PROCESS = 1,
+ IOPRIO_WHO_PGRP,
+ IOPRIO_WHO_USER,
};
-*/
+
+enum
+{
+ IOPRIO_CLASS_NONE = 0,
+ IOPRIO_CLASS_RT = 1,
+ IOPRIO_CLASS_BE = 2,
+ IOPRIO_CLASS_IDLE = 3,
+};
+
+
+int getIoPriority() //throw SysError
+{
+ const int rv = ::syscall(SYS_ioprio_get, IOPRIO_WHO_PROCESS, ::getpid());
+ if (rv == -1)
+ THROW_LAST_SYS_ERROR("ioprio_get");
+
+ //fix Linux kernel fuck up: bogus system default value
+ if (rv == IOPRIO_PRIO_VALUE(IOPRIO_CLASS_NONE, IOPRIO_NORM))
+ return IOPRIO_PRIO_VALUE(IOPRIO_CLASS_BE, IOPRIO_NORM);
+
+ return rv;
+}
+
+
+void setIoPriority(int ioPrio) //throw SysError
+{
+ if (::syscall(SYS_ioprio_set, IOPRIO_WHO_PROCESS, ::getpid(), ioPrio) != 0)
+ THROW_LAST_SYS_ERROR("ioprio_set(0x" + printNumber<std::string>("%x", static_cast<unsigned int>(ioPrio)) + ')');
+}
+}
+
+
+struct SetProcessPriority::Impl
+{
+ std::optional<int> oldIoPrio;
+};
+
+
+SetProcessPriority::SetProcessPriority(ProcessPriority prio) : //throw FileError
+ pimpl_(new Impl)
+{
+ if (prio == ProcessPriority::background)
+ try
+ {
+ pimpl_->oldIoPrio = getIoPriority(); //throw SysError
+
+ setIoPriority(IOPRIO_PRIO_VALUE(IOPRIO_CLASS_BE, 6 /*0 (highest) to 7 (lowest)*/)); //throw SysError
+ //maybe even IOPRIO_PRIO_VALUE(IOPRIO_CLASS_IDLE, 0) ? nope: "only served when no one else is using the disk"
+ }
+ catch (const SysError& e) { throw FileError(_("Cannot change process I/O priorities."), e.toString()); }
+}
+
+
+SetProcessPriority::~SetProcessPriority()
+{
+ if (pimpl_->oldIoPrio)
+ try
+ {
+ setIoPriority(*pimpl_->oldIoPrio); //throw SysError
+ }
+ catch (const SysError& e) { logExtraError(_("Cannot change process I/O priorities.") + L"\n\n" + e.toString()); }
+}
diff --git a/zen/process_priority.h b/zen/process_priority.h
index cfadfff1..216c1153 100644
--- a/zen/process_priority.h
+++ b/zen/process_priority.h
@@ -13,23 +13,20 @@
namespace zen
{
-//signal a "busy" state to the operating system
-class PreventStandby
+enum class ProcessPriority
{
-public:
- PreventStandby(); //throw FileError
- ~PreventStandby();
-private:
- struct Impl;
- const std::unique_ptr<Impl> pimpl_;
+ normal,
+ background, //lower CPU and file I/O priorities
};
-//lower CPU and file I/O priorities
-class ScheduleForBackgroundProcessing
+//- prevent operating system going into sleep state
+//- set process I/O priorities
+class SetProcessPriority
{
public:
- ScheduleForBackgroundProcessing(); //throw FileError
- ~ScheduleForBackgroundProcessing();
+ explicit SetProcessPriority(ProcessPriority prio); //throw FileError
+ ~SetProcessPriority();
+
private:
struct Impl;
const std::unique_ptr<Impl> pimpl_;
diff --git a/zen/scope_guard.h b/zen/scope_guard.h
index 866044a8..7dd2bbde 100644
--- a/zen/scope_guard.h
+++ b/zen/scope_guard.h
@@ -8,7 +8,6 @@
#define SCOPE_GUARD_H_8971632487321434
#include <cassert>
-//#include "type_traits.h"
#include "legacy_compiler.h" //std::uncaught_exceptions
//best of Zen, Loki and C++17
diff --git a/zen/socket.h b/zen/socket.h
index 461226d0..9663a422 100644
--- a/zen/socket.h
+++ b/zen/socket.h
@@ -165,7 +165,7 @@ public:
//-----------------------------------------------------------
//configure *after* selecting appropriate socket: cfg-failure should not discard otherwise fine connection!
- int noDelay = 1; //disable Nagle algorithm: https://brooker.co.za/blog/2024/05/09/nagle.html
+ int noDelay = 1; //disable Nagle algorithm: https://brooker.co.za/blog/2024/05/09/nagle.html
//e.g. test case "website sync": 23% shorter comparison time!
if (::setsockopt(socket_, //_In_ SOCKET s
IPPROTO_TCP, //_In_ int level
diff --git a/zen/stl_tools.h b/zen/stl_tools.h
index f167a814..9fc34e8c 100644
--- a/zen/stl_tools.h
+++ b/zen/stl_tools.h
@@ -14,7 +14,6 @@
#include <unordered_map>
#include <memory>
#include <cassert>
-//#include <algorithm>
#include <optional>
#include "type_traits.h"
@@ -93,21 +92,22 @@ class SharedRef //why is there no std::shared_ref???
public:
SharedRef() = delete; //no surprise memory allocations!
- explicit SharedRef(std::shared_ptr<T> ptr) : ref_(std::move(ptr)) { assert(ref_); }
+ explicit SharedRef(const std::shared_ptr<T>& ptr) : ptr_ (ptr) { assert(ptr_); }
+ explicit SharedRef( std::shared_ptr<T>&& ptr) : ptr_(std::move(ptr)) { assert(ptr_); }
- template <class U>
- SharedRef(const SharedRef<U>& other) : ref_(other.ref_) {}
+ template <class U> SharedRef(const SharedRef<U>& other) : ptr_ (other.ptr_) {}
+ template <class U> SharedRef( SharedRef<U>&& other) : ptr_(std::move(other.ptr_)) {}
- /**/ T& ref() { return *ref_; };
- const T& ref() const { return *ref_; };
+ /**/ T& ref() { return *ptr_; };
+ const T& ref() const { return *ptr_; };
- std::shared_ptr< T> ptr() { return ref_; };
- std::shared_ptr<const T> ptr() const { return ref_; };
+ const std::shared_ptr< T>& ptr() { return ptr_; };
+ /**/ std::shared_ptr<const T> ptr() const { return ptr_; }; //careful: return value has different type => creates temporary!
private:
template <class U> friend class SharedRef;
- std::shared_ptr<T> ref_; //always bound
+ std::shared_ptr<T> ptr_; //always bound
};
template <class T, class... Args> inline
@@ -115,8 +115,49 @@ SharedRef<T> makeSharedRef(Args&& ... args) { return SharedRef<T>(std::make_shar
+//hide SharedRef as an implementation detail
+template <class IterImpl, //underlying iterator type
+ class T> //target value type
+class DerefIter
+{
+public:
+ using iterator_category = std::bidirectional_iterator_tag;
+ using value_type = T;
+ using difference_type = ptrdiff_t;
+ using pointer = T*;
+ using reference = T&;
+
+ DerefIter() {}
+ DerefIter(IterImpl it) : it_(std::move(it)) {}
+ //DerefIter(const DerefIter& other) : it_(other.it_) {}
+ DerefIter& operator++() { ++it_; return *this; }
+ DerefIter& operator--() { --it_; return *this; }
+ inline friend DerefIter operator++(DerefIter& it, int) { return it++; }
+ inline friend DerefIter operator--(DerefIter& it, int) { return it--; }
+ inline friend ptrdiff_t operator-(const DerefIter& lhs, const DerefIter& rhs) { return lhs.it_ - rhs.it_; }
+ bool operator==(const DerefIter&) const = default;
+ T& operator* () const { return it_->ref(); }
+ T* operator->() const { return &it_->ref(); }
+private:
+ IterImpl it_{};
+};
+
+template <class Iterator>
+class Range
+{
+public:
+ Range(Iterator first, Iterator last) : first_(std::move(first)), last_(std::move(last)) {}
+ Iterator begin() const { return first_; }
+ Iterator end () const { return last_; }
+
+ bool empty() const { return first_ == last_; }
+ size_t size() const { return last_ - first_; }
+private:
+ Iterator first_;
+ Iterator last_;
+};
//######################## implementation ########################
diff --git a/zen/stream_buffer.h b/zen/stream_buffer.h
index 5d2ec024..1a7acb13 100644
--- a/zen/stream_buffer.h
+++ b/zen/stream_buffer.h
@@ -8,10 +8,8 @@
#define STREAM_BUFFER_H_08492572089560298
#include <thread>
-//#include <condition_variable>
#include "ring_buffer.h"
#include "string_tools.h"
-//#include "thread.h"
namespace zen
diff --git a/zen/string_tools.h b/zen/string_tools.h
index d7d0804f..6fc58f9c 100644
--- a/zen/string_tools.h
+++ b/zen/string_tools.h
@@ -7,8 +7,6 @@
#ifndef STRING_TOOLS_H_213458973046
#define STRING_TOOLS_H_213458973046
-//#include <cctype> //isspace
-//#include <cwctype> //iswspace
#include <cstdio> //sprintf
#include <cwchar> //swprintf
#include "stl_tools.h"
diff --git a/zen/sys_info.cpp b/zen/sys_info.cpp
index 530b3d85..4687bfcb 100644
--- a/zen/sys_info.cpp
+++ b/zen/sys_info.cpp
@@ -8,7 +8,6 @@
#include "crc.h"
#include "file_access.h"
#include "sys_version.h"
-//#include "time.h"
#include "symlink_target.h"
#include "file_io.h"
diff --git a/zen/time.h b/zen/time.h
index aa7df21b..11bfeb1a 100644
--- a/zen/time.h
+++ b/zen/time.h
@@ -60,7 +60,7 @@ TimeComp parseTime(const String& format, const String2& str); //similar to ::str
//----------------------------------------------------------------------------------------------------------------------------------
//format: [-][[d.]HH:]MM:SS e.g. -1.23:45:67
-Zstring formatTimeSpan(int64_t timeInSec, bool hourOptional = false);
+Zstring formatTimeSpan(int64_t timeInSec, bool hourRequired = true);
@@ -389,7 +389,7 @@ TimeComp parseTime(const String& format, const String2& str)
inline
-Zstring formatTimeSpan(int64_t timeInSec, bool hourOptional)
+Zstring formatTimeSpan(int64_t timeInSec, bool hourRequired)
{
Zstring timespanStr;
@@ -400,7 +400,7 @@ Zstring formatTimeSpan(int64_t timeInSec, bool hourOptional)
}
//check *before* subtracting days!
- const Zchar* timeSpanFmt = hourOptional && timeInSec < 3600 ? Zstr("%M:%S") : formatIsoTimeTag;
+ const Zchar* timeSpanFmt = timeInSec < 3600 && !hourRequired ? Zstr("%M:%S") : formatIsoTimeTag;
const int secsPerDay = 24 * 3600;
const int64_t days = numeric::intDivFloor(timeInSec, secsPerDay);
diff --git a/zen/zstring.h b/zen/zstring.h
index 00b1c86e..0d493314 100644
--- a/zen/zstring.h
+++ b/zen/zstring.h
@@ -103,4 +103,8 @@ const wchar_t LEFT_ARROW_ANTICLOCK = L'\u2B8F'; //Anticlockwise Triangle-Headed
const wchar_t* const TAB_SPACE = L" "; //4: the only sensible space count for tabs
+const wchar_t LINE_SEPARATOR = L'\u2028'; //WTF: visually indistinguishable from new line!
+const wchar_t PARAGRAPH_SEPARATOR = L'\u2029';
+
+
#endif //ZSTRING_H_73425873425789
bgstack15