From 2c4db439d235b68478d90c450289d2d0ba418547 Mon Sep 17 00:00:00 2001 From: B Stack Date: Wed, 18 Mar 2020 08:59:09 -0400 Subject: add upstream 10.21 --- zen/basic_math.h | 16 +---- zen/crc.h | 58 +++++++--------- zen/dir_watcher.cpp | 3 +- zen/error_log.h | 85 +++++++++++++++-------- zen/file_access.cpp | 4 +- zen/file_io.cpp | 6 +- zen/file_io.h | 2 +- zen/format_unit.cpp | 5 +- zen/guid.h | 12 ++-- zen/http.cpp | 42 ++++++------ zen/http.h | 8 +-- zen/legacy_compiler.h | 17 +++-- zen/open_ssl.cpp | 31 +++++---- zen/perf.h | 2 +- zen/recycler.cpp | 4 +- zen/serialize.h | 38 ++--------- zen/shell_execute.h | 4 +- zen/socket.h | 4 +- zen/string_base.h | 32 +++++++-- zen/string_tools.h | 12 ++-- zen/string_traits.h | 3 +- zen/sys_error.cpp | 184 ++++++++++++++++++++++++++++++++++++++++++++++++++ zen/sys_error.h | 62 ++--------------- zen/system.cpp | 31 ++++++++- zen/thread.cpp | 2 +- zen/thread.h | 2 +- zen/time.h | 184 +++++++++----------------------------------------- zen/zlib_wrap.cpp | 14 ++-- zen/zlib_wrap.h | 6 +- zen/zstring.cpp | 3 +- zen/zstring.h | 7 +- 31 files changed, 472 insertions(+), 411 deletions(-) (limited to 'zen') diff --git a/zen/basic_math.h b/zen/basic_math.h index 8a32ee69..26dda9a6 100644 --- a/zen/basic_math.h +++ b/zen/basic_math.h @@ -14,6 +14,7 @@ #include #include #include "type_traits.h" +#include "legacy_compiler.h" namespace numeric @@ -53,17 +54,6 @@ double mad(RandomAccessIterator first, RandomAccessIterator last); //note: inval template double norm2(InputIterator first, InputIterator last); -//constants -const double pi = 3.14159265358979323846; -const double e = 2.71828182845904523536; -const double sqrt2 = 1.41421356237309504880; -const double ln2 = 0.693147180559945309417; - -#if __cpp_lib_math_constants //C++20 - #error implement math constants from header -#endif -//static_assert(pi + e + sqrt2 + ln2 == 7.9672352249818781, "whoopsie"); - //---------------------------------------------------------------------------------- @@ -213,14 +203,14 @@ T power(T value) inline double radToDeg(double rad) { - return rad * 180.0 / numeric::pi; + return rad * (180.0 / std::numbers::pi); } inline double degToRad(double degree) { - return degree * numeric::pi / 180.0; + return degree / (180.0 / std::numbers::pi); } diff --git a/zen/crc.h b/zen/crc.h index df460a03..0570cced 100644 --- a/zen/crc.h +++ b/zen/crc.h @@ -64,38 +64,32 @@ uint32_t getCrc32(ByteIterator first, ByteIterator last) //https://en.wikipedia. { constexpr uint32_t crcTable[] = { - 0x00000000, 0x77073096, 0xee0e612c, 0x990951ba, 0x076dc419, 0x706af48f, 0xe963a535, 0x9e6495a3, - 0x0edb8832, 0x79dcb8a4, 0xe0d5e91e, 0x97d2d988, 0x09b64c2b, 0x7eb17cbd, 0xe7b82d07, 0x90bf1d91, - 0x1db71064, 0x6ab020f2, 0xf3b97148, 0x84be41de, 0x1adad47d, 0x6ddde4eb, 0xf4d4b551, 0x83d385c7, - 0x136c9856, 0x646ba8c0, 0xfd62f97a, 0x8a65c9ec, 0x14015c4f, 0x63066cd9, 0xfa0f3d63, 0x8d080df5, - 0x3b6e20c8, 0x4c69105e, 0xd56041e4, 0xa2677172, 0x3c03e4d1, 0x4b04d447, 0xd20d85fd, 0xa50ab56b, - 0x35b5a8fa, 0x42b2986c, 0xdbbbc9d6, 0xacbcf940, 0x32d86ce3, 0x45df5c75, 0xdcd60dcf, 0xabd13d59, - 0x26d930ac, 0x51de003a, 0xc8d75180, 0xbfd06116, 0x21b4f4b5, 0x56b3c423, 0xcfba9599, 0xb8bda50f, - 0x2802b89e, 0x5f058808, 0xc60cd9b2, 0xb10be924, 0x2f6f7c87, 0x58684c11, 0xc1611dab, 0xb6662d3d, - 0x76dc4190, 0x01db7106, 0x98d220bc, 0xefd5102a, 0x71b18589, 0x06b6b51f, 0x9fbfe4a5, 0xe8b8d433, - 0x7807c9a2, 0x0f00f934, 0x9609a88e, 0xe10e9818, 0x7f6a0dbb, 0x086d3d2d, 0x91646c97, 0xe6635c01, - 0x6b6b51f4, 0x1c6c6162, 0x856530d8, 0xf262004e, 0x6c0695ed, 0x1b01a57b, 0x8208f4c1, 0xf50fc457, - 0x65b0d9c6, 0x12b7e950, 0x8bbeb8ea, 0xfcb9887c, 0x62dd1ddf, 0x15da2d49, 0x8cd37cf3, 0xfbd44c65, - 0x4db26158, 0x3ab551ce, 0xa3bc0074, 0xd4bb30e2, 0x4adfa541, 0x3dd895d7, 0xa4d1c46d, 0xd3d6f4fb, - 0x4369e96a, 0x346ed9fc, 0xad678846, 0xda60b8d0, 0x44042d73, 0x33031de5, 0xaa0a4c5f, 0xdd0d7cc9, - 0x5005713c, 0x270241aa, 0xbe0b1010, 0xc90c2086, 0x5768b525, 0x206f85b3, 0xb966d409, 0xce61e49f, - 0x5edef90e, 0x29d9c998, 0xb0d09822, 0xc7d7a8b4, 0x59b33d17, 0x2eb40d81, 0xb7bd5c3b, 0xc0ba6cad, - 0xedb88320, 0x9abfb3b6, 0x03b6e20c, 0x74b1d29a, 0xead54739, 0x9dd277af, 0x04db2615, 0x73dc1683, - 0xe3630b12, 0x94643b84, 0x0d6d6a3e, 0x7a6a5aa8, 0xe40ecf0b, 0x9309ff9d, 0x0a00ae27, 0x7d079eb1, - 0xf00f9344, 0x8708a3d2, 0x1e01f268, 0x6906c2fe, 0xf762575d, 0x806567cb, 0x196c3671, 0x6e6b06e7, - 0xfed41b76, 0x89d32be0, 0x10da7a5a, 0x67dd4acc, 0xf9b9df6f, 0x8ebeeff9, 0x17b7be43, 0x60b08ed5, - 0xd6d6a3e8, 0xa1d1937e, 0x38d8c2c4, 0x4fdff252, 0xd1bb67f1, 0xa6bc5767, 0x3fb506dd, 0x48b2364b, - 0xd80d2bda, 0xaf0a1b4c, 0x36034af6, 0x41047a60, 0xdf60efc3, 0xa867df55, 0x316e8eef, 0x4669be79, - 0xcb61b38c, 0xbc66831a, 0x256fd2a0, 0x5268e236, 0xcc0c7795, 0xbb0b4703, 0x220216b9, 0x5505262f, - 0xc5ba3bbe, 0xb2bd0b28, 0x2bb45a92, 0x5cb36a04, 0xc2d7ffa7, 0xb5d0cf31, 0x2cd99e8b, 0x5bdeae1d, - 0x9b64c2b0, 0xec63f226, 0x756aa39c, 0x026d930a, 0x9c0906a9, 0xeb0e363f, 0x72076785, 0x05005713, - 0x95bf4a82, 0xe2b87a14, 0x7bb12bae, 0x0cb61b38, 0x92d28e9b, 0xe5d5be0d, 0x7cdcefb7, 0x0bdbdf21, - 0x86d3d2d4, 0xf1d4e242, 0x68ddb3f8, 0x1fda836e, 0x81be16cd, 0xf6b9265b, 0x6fb077e1, 0x18b74777, - 0x88085ae6, 0xff0f6a70, 0x66063bca, 0x11010b5c, 0x8f659eff, 0xf862ae69, 0x616bffd3, 0x166ccf45, - 0xa00ae278, 0xd70dd2ee, 0x4e048354, 0x3903b3c2, 0xa7672661, 0xd06016f7, 0x4969474d, 0x3e6e77db, - 0xaed16a4a, 0xd9d65adc, 0x40df0b66, 0x37d83bf0, 0xa9bcae53, 0xdebb9ec5, 0x47b2cf7f, 0x30b5ffe9, - 0xbdbdf21c, 0xcabac28a, 0x53b39330, 0x24b4a3a6, 0xbad03605, 0xcdd70693, 0x54de5729, 0x23d967bf, - 0xb3667a2e, 0xc4614ab8, 0x5d681b02, 0x2a6f2b94, 0xb40bbe37, 0xc30c8ea1, 0x5a05df1b, 0x2d02ef8d + 0x00000000, 0x77073096, 0xee0e612c, 0x990951ba, 0x076dc419, 0x706af48f, 0xe963a535, 0x9e6495a3, 0x0edb8832, 0x79dcb8a4, + 0xe0d5e91e, 0x97d2d988, 0x09b64c2b, 0x7eb17cbd, 0xe7b82d07, 0x90bf1d91, 0x1db71064, 0x6ab020f2, 0xf3b97148, 0x84be41de, + 0x1adad47d, 0x6ddde4eb, 0xf4d4b551, 0x83d385c7, 0x136c9856, 0x646ba8c0, 0xfd62f97a, 0x8a65c9ec, 0x14015c4f, 0x63066cd9, + 0xfa0f3d63, 0x8d080df5, 0x3b6e20c8, 0x4c69105e, 0xd56041e4, 0xa2677172, 0x3c03e4d1, 0x4b04d447, 0xd20d85fd, 0xa50ab56b, + 0x35b5a8fa, 0x42b2986c, 0xdbbbc9d6, 0xacbcf940, 0x32d86ce3, 0x45df5c75, 0xdcd60dcf, 0xabd13d59, 0x26d930ac, 0x51de003a, + 0xc8d75180, 0xbfd06116, 0x21b4f4b5, 0x56b3c423, 0xcfba9599, 0xb8bda50f, 0x2802b89e, 0x5f058808, 0xc60cd9b2, 0xb10be924, + 0x2f6f7c87, 0x58684c11, 0xc1611dab, 0xb6662d3d, 0x76dc4190, 0x01db7106, 0x98d220bc, 0xefd5102a, 0x71b18589, 0x06b6b51f, + 0x9fbfe4a5, 0xe8b8d433, 0x7807c9a2, 0x0f00f934, 0x9609a88e, 0xe10e9818, 0x7f6a0dbb, 0x086d3d2d, 0x91646c97, 0xe6635c01, + 0x6b6b51f4, 0x1c6c6162, 0x856530d8, 0xf262004e, 0x6c0695ed, 0x1b01a57b, 0x8208f4c1, 0xf50fc457, 0x65b0d9c6, 0x12b7e950, + 0x8bbeb8ea, 0xfcb9887c, 0x62dd1ddf, 0x15da2d49, 0x8cd37cf3, 0xfbd44c65, 0x4db26158, 0x3ab551ce, 0xa3bc0074, 0xd4bb30e2, + 0x4adfa541, 0x3dd895d7, 0xa4d1c46d, 0xd3d6f4fb, 0x4369e96a, 0x346ed9fc, 0xad678846, 0xda60b8d0, 0x44042d73, 0x33031de5, + 0xaa0a4c5f, 0xdd0d7cc9, 0x5005713c, 0x270241aa, 0xbe0b1010, 0xc90c2086, 0x5768b525, 0x206f85b3, 0xb966d409, 0xce61e49f, + 0x5edef90e, 0x29d9c998, 0xb0d09822, 0xc7d7a8b4, 0x59b33d17, 0x2eb40d81, 0xb7bd5c3b, 0xc0ba6cad, 0xedb88320, 0x9abfb3b6, + 0x03b6e20c, 0x74b1d29a, 0xead54739, 0x9dd277af, 0x04db2615, 0x73dc1683, 0xe3630b12, 0x94643b84, 0x0d6d6a3e, 0x7a6a5aa8, + 0xe40ecf0b, 0x9309ff9d, 0x0a00ae27, 0x7d079eb1, 0xf00f9344, 0x8708a3d2, 0x1e01f268, 0x6906c2fe, 0xf762575d, 0x806567cb, + 0x196c3671, 0x6e6b06e7, 0xfed41b76, 0x89d32be0, 0x10da7a5a, 0x67dd4acc, 0xf9b9df6f, 0x8ebeeff9, 0x17b7be43, 0x60b08ed5, + 0xd6d6a3e8, 0xa1d1937e, 0x38d8c2c4, 0x4fdff252, 0xd1bb67f1, 0xa6bc5767, 0x3fb506dd, 0x48b2364b, 0xd80d2bda, 0xaf0a1b4c, + 0x36034af6, 0x41047a60, 0xdf60efc3, 0xa867df55, 0x316e8eef, 0x4669be79, 0xcb61b38c, 0xbc66831a, 0x256fd2a0, 0x5268e236, + 0xcc0c7795, 0xbb0b4703, 0x220216b9, 0x5505262f, 0xc5ba3bbe, 0xb2bd0b28, 0x2bb45a92, 0x5cb36a04, 0xc2d7ffa7, 0xb5d0cf31, + 0x2cd99e8b, 0x5bdeae1d, 0x9b64c2b0, 0xec63f226, 0x756aa39c, 0x026d930a, 0x9c0906a9, 0xeb0e363f, 0x72076785, 0x05005713, + 0x95bf4a82, 0xe2b87a14, 0x7bb12bae, 0x0cb61b38, 0x92d28e9b, 0xe5d5be0d, 0x7cdcefb7, 0x0bdbdf21, 0x86d3d2d4, 0xf1d4e242, + 0x68ddb3f8, 0x1fda836e, 0x81be16cd, 0xf6b9265b, 0x6fb077e1, 0x18b74777, 0x88085ae6, 0xff0f6a70, 0x66063bca, 0x11010b5c, + 0x8f659eff, 0xf862ae69, 0x616bffd3, 0x166ccf45, 0xa00ae278, 0xd70dd2ee, 0x4e048354, 0x3903b3c2, 0xa7672661, 0xd06016f7, + 0x4969474d, 0x3e6e77db, 0xaed16a4a, 0xd9d65adc, 0x40df0b66, 0x37d83bf0, 0xa9bcae53, 0xdebb9ec5, 0x47b2cf7f, 0x30b5ffe9, + 0xbdbdf21c, 0xcabac28a, 0x53b39330, 0x24b4a3a6, 0xbad03605, 0xcdd70693, 0x54de5729, 0x23d967bf, 0xb3667a2e, 0xc4614ab8, + 0x5d681b02, 0x2a6f2b94, 0xb40bbe37, 0xc30c8ea1, 0x5a05df1b, 0x2d02ef8d }; static_assert(arraySize(crcTable) == 256 && arrayAccumulate(crcTable) == 549755813760); static_assert(sizeof(typename std::iterator_traits::value_type) == 1); diff --git a/zen/dir_watcher.cpp b/zen/dir_watcher.cpp index 94632ea4..307b48e5 100644 --- a/zen/dir_watcher.cpp +++ b/zen/dir_watcher.cpp @@ -85,7 +85,8 @@ DirWatcher::DirWatcher(const Zstring& dirPath) : //throw FileError const ErrorCode ec = getLastError(); //copy before directly/indirectly making other system calls! if (ec == ENOSPC) //fix misleading system message "No space left on device" throw FileError(replaceCpy(_("Cannot monitor directory %x."), L"%x", fmtPath(subDirPath)), - formatSystemError(L"inotify_add_watch", numberTo(ec), L"The user limit on the total number of inotify watches was reached or the kernel failed to allocate a needed resource.")); + formatSystemError(L"inotify_add_watch", L"ENOSPC", + L"The user limit on the total number of inotify watches was reached or the kernel failed to allocate a needed resource.")); throw FileError(replaceCpy(_("Cannot monitor directory %x."), L"%x", fmtPath(subDirPath)), formatSystemError(L"inotify_add_watch", ec)); } diff --git a/zen/error_log.h b/zen/error_log.h index cc52fc6e..ab23e33a 100644 --- a/zen/error_log.h +++ b/zen/error_log.h @@ -8,9 +8,7 @@ #define ERROR_LOG_H_8917590832147915 #include -#include #include -//#include #include "time.h" #include "i18n.h" #include "utf.h" @@ -31,10 +29,10 @@ struct LogEntry { time_t time = 0; MessageType type = MSG_TYPE_FATAL_ERROR; - Zstringw message; //std::wstring may employ small string optimization: we cannot accept bloating the "ErrorLog::entries_" memory block below (think 1 million items) + Zstringc message; //conserve memory (=> avoid std::string SSO overhead!) }; -std::wstring formatMessage(const LogEntry& entry); +std::string formatMessage(const LogEntry& entry); class ErrorLog @@ -42,7 +40,14 @@ class ErrorLog public: void logMsg(const std::wstring& msg, MessageType type); - int getItemCount(int typeFilter = MSG_TYPE_INFO | MSG_TYPE_WARNING | MSG_TYPE_ERROR | MSG_TYPE_FATAL_ERROR) const; + struct Stats + { + int info = 0; + int warning = 0; + int error = 0; + int fatal = 0; + }; + Stats getStats() const; //subset of std::vector<> interface: using const_iterator = std::vector::const_iterator; @@ -65,59 +70,79 @@ private: inline void ErrorLog::logMsg(const std::wstring& msg, MessageType type) { - entries_.push_back({ std::time(nullptr), type, copyStringTo(msg) }); + entries_.push_back({ std::time(nullptr), type, utfTo(msg) }); } -inline -int ErrorLog::getItemCount(int typeFilter) const -{ - return static_cast(std::count_if(entries_.begin(), entries_.end(), [typeFilter](const LogEntry& e) { return e.type & typeFilter; })); -} - -inline -std::wstring getMessageTypeLabel(MessageType type) +inline +ErrorLog::Stats ErrorLog::getStats() const { - switch (type) + Stats count; + for (const LogEntry& entry : entries_) + switch (entry.type) { case MSG_TYPE_INFO: - return _("Info"); + ++count.info; + break; case MSG_TYPE_WARNING: - return _("Warning"); + ++count.warning; + break; case MSG_TYPE_ERROR: - return _("Error"); + ++count.error; + break; case MSG_TYPE_FATAL_ERROR: - return _("Serious Error"); + ++count.fatal; + break; } - assert(false); - return std::wstring(); + assert(static_cast(entries_.size()) == count.info + count.warning + count.error + count.fatal); + return count; +} + + +inline +std::wstring getMessageTypeLabel(MessageType type) +{ + switch (type) + { + case MSG_TYPE_INFO: + return _("Info"); + case MSG_TYPE_WARNING: + return _("Warning"); + case MSG_TYPE_ERROR: + return _("Error"); + case MSG_TYPE_FATAL_ERROR: + return _("Serious Error"); + } + assert(false); + return std::wstring(); } inline -std::wstring formatMessage(const LogEntry& entry) +std::string formatMessage(const LogEntry& entry) { - std::wstring msgFmt = L"[" + formatTime(FORMAT_TIME, getLocalTime(entry.time)) + L"] " + getMessageTypeLabel(entry.type) + L": "; + std::string msgFmt = '[' + utfTo(formatTime(formatTimeTag, getLocalTime(entry.time))) + "] " + utfTo(getMessageTypeLabel(entry.type)) + ": "; const size_t prefixLen = unicodeLength(msgFmt); //consider Unicode! - const Zstringw msg = trimCpy(entry.message); - static_assert(std::is_same_v, "don't worry about copying as long as we're using a ref-counted string!"); + const Zstringc msg = trimCpy(entry.message); + static_assert(std::is_same_v, "don't worry about copying as long as we're using a ref-counted string!"); for (auto it = msg.begin(); it != msg.end(); ) - if (*it == L'\n') + if (*it == '\n') { - msgFmt += L'\n'; - msgFmt.append(prefixLen, L' '); + msgFmt += '\n'; + msgFmt.append(prefixLen, ' '); ++it; //skip duplicate newlines - for (;it != msg.end() && *it == L'\n'; ++it) + for (; it != msg.end() && *it == '\n'; ++it) ; } else msgFmt += *it++; - return msgFmt += L'\n'; + msgFmt += '\n'; + return msgFmt; } } diff --git a/zen/file_access.cpp b/zen/file_access.cpp index e23d48be..4f6704d2 100644 --- a/zen/file_access.cpp +++ b/zen/file_access.cpp @@ -311,7 +311,7 @@ void moveAndRenameFileSub(const Zstring& pathFrom, const Zstring& pathTo, bool r { auto throwException = [&](int ec) { - const std::wstring errorMsg = replaceCpy(replaceCpy(_("Cannot move file %x to %y."), L"%x", L"\n" + fmtPath(pathFrom)), L"%y", L"\n" + fmtPath(pathTo)); + const std::wstring errorMsg = replaceCpy(replaceCpy(_("Cannot move file %x to %y."), L"%x", L'\n' + fmtPath(pathFrom)), L"%y", L'\n' + fmtPath(pathTo)); const std::wstring errorDescr = formatSystemError(L"rename", ec); if (ec == EXDEV) @@ -575,7 +575,7 @@ void zen::copySymlink(const Zstring& sourcePath, const Zstring& targetPath, bool const Zstring linkPath = getSymlinkTargetRaw(sourcePath); //throw FileError; accept broken symlinks if (::symlink(linkPath.c_str(), targetPath.c_str()) != 0) - THROW_LAST_FILE_ERROR(replaceCpy(replaceCpy(_("Cannot copy symbolic link %x to %y."), L"%x", L"\n" + fmtPath(sourcePath)), L"%y", L"\n" + fmtPath(targetPath)), L"symlink"); + THROW_LAST_FILE_ERROR(replaceCpy(replaceCpy(_("Cannot copy symbolic link %x to %y."), L"%x", L'\n' + fmtPath(sourcePath)), L"%y", L'\n' + fmtPath(targetPath)), L"symlink"); //allow only consistent objects to be created -> don't place before ::symlink(); targetPath may already exist! ZEN_ON_SCOPE_FAIL(try { removeSymlinkPlain(targetPath); /*throw FileError*/ } diff --git a/zen/file_io.cpp b/zen/file_io.cpp index e788bcfe..b78259e0 100644 --- a/zen/file_io.cpp +++ b/zen/file_io.cpp @@ -68,7 +68,7 @@ FileBase::FileHandle openHandleForRead(const Zstring& filePath) //throw FileErro return name + printNumber(L"0%06o", m & S_IFMT); }(); throw FileError(replaceCpy(_("Cannot open file %x."), L"%x", fmtPath(filePath)), - _("Unsupported item type.") + L" [" + typeName + L"]"); + _("Unsupported item type.") + L" [" + typeName + L']'); } } //else: let ::open() fail for errors like "not existing" @@ -100,7 +100,7 @@ FileInput::FileInput(const Zstring& filePath, const IOCallback& notifyUnbuffered size_t FileInput::tryRead(void* buffer, size_t bytesToRead) //throw FileError, ErrorFileLocked; may return short, only 0 means EOF! { if (bytesToRead == 0) //"read() with a count of 0 returns zero" => indistinguishable from end of file! => check! - throw std::logic_error("Contract violation! " + std::string(__FILE__) + ":" + numberTo(__LINE__)); + throw std::logic_error("Contract violation! " + std::string(__FILE__) + ':' + numberTo(__LINE__)); assert(bytesToRead == getBlockSize()); ssize_t bytesRead = 0; @@ -215,7 +215,7 @@ FileOutput::~FileOutput() size_t FileOutput::tryWrite(const void* buffer, size_t bytesToWrite) //throw FileError; may return short! CONTRACT: bytesToWrite > 0 { if (bytesToWrite == 0) - throw std::logic_error("Contract violation! " + std::string(__FILE__) + ":" + numberTo(__LINE__)); + throw std::logic_error("Contract violation! " + std::string(__FILE__) + ':' + numberTo(__LINE__)); assert(bytesToWrite <= getBlockSize()); ssize_t bytesWritten = 0; diff --git a/zen/file_io.h b/zen/file_io.h index 54bde5aa..b47c6077 100644 --- a/zen/file_io.h +++ b/zen/file_io.h @@ -119,7 +119,7 @@ void saveBinContainer(const Zstring& filePath, const BinContainer& buffer, const if (!buffer.empty()) { /*snake oil?*/ fileOut.preAllocateSpaceBestEffort(buffer.size()); //throw FileError - fileOut.write(&*buffer.begin(), buffer.size()); //throw FileError, X + fileOut.write(&buffer[0], buffer.size()); //throw FileError, X } fileOut.finalize(); //throw FileError, X } diff --git a/zen/format_unit.cpp b/zen/format_unit.cpp index f2df4153..91a881dc 100644 --- a/zen/format_unit.cpp +++ b/zen/format_unit.cpp @@ -11,6 +11,7 @@ #include "i18n.h" #include "time.h" #include "globals.h" +#include "utf.h" #include //thousands separator #include "utf.h" // @@ -115,7 +116,7 @@ std::wstring roundToBlock(double timeInHigh, std::wstring output = formatUnitTime(roundedtimeInLow / unitLowPerHigh, unitHigh); if (unitLowPerHigh > blockSizeLow) - output += L" " + formatUnitTime(roundedtimeInLow % unitLowPerHigh, unitLow); + output += L' ' + formatUnitTime(roundedtimeInLow % unitLowPerHigh, unitLow); return output; } } @@ -194,7 +195,7 @@ std::wstring zen::formatUtcToLocalTime(time_t utcTime) TimeComp loc = getLocalTime(utcTime); - std::wstring dateString = formatTime(L"%x %X", loc); + std::wstring dateString = utfTo(formatTime(Zstr("%x %X"), loc)); return !dateString.empty() ? dateString : errorMsg(); } diff --git a/zen/guid.h b/zen/guid.h index 657ed07a..88059be8 100644 --- a/zen/guid.h +++ b/zen/guid.h @@ -26,8 +26,8 @@ std::string generateGUID() //creates a 16-byte GUID #if __GLIBC__ > 2 || (__GLIBC__ == 2 && __GLIBC_MINOR__ >= 25) //getentropy() requires glibc 2.25 (ldd --version) PS: CentOS 7 is on 2.17 if (::getentropy(&guid[0], guid.size()) != 0) //"The maximum permitted value for the length argument is 256" - throw std::runtime_error(std::string(__FILE__) + "[" + numberTo(__LINE__) + "] Failed to generate GUID." + - "\n" + utfTo(formatSystemError(L"getentropy", errno))); + throw std::runtime_error(std::string(__FILE__) + '[' + numberTo(__LINE__) + "] Failed to generate GUID." + "\n\n" + + utfTo(formatSystemError(L"getentropy", errno))); #else class RandomGeneratorPosix { @@ -35,8 +35,8 @@ std::string generateGUID() //creates a 16-byte GUID RandomGeneratorPosix() { if (fd_ == -1) - throw std::runtime_error(std::string(__FILE__) + "[" + numberTo(__LINE__) + "] Failed to generate GUID." + - "\n" + utfTo(formatSystemError(L"open", errno))); + throw std::runtime_error(std::string(__FILE__) + '[' + numberTo(__LINE__) + "] Failed to generate GUID." + "\n\n" + + utfTo(formatSystemError(L"open", errno))); } ~RandomGeneratorPosix() { ::close(fd_); } @@ -47,8 +47,8 @@ std::string generateGUID() //creates a 16-byte GUID { const ssize_t bytesRead = ::read(fd_, static_cast(buf) + offset, size - offset); if (bytesRead < 1) //0 means EOF => error in this context (should check for buffer overflow, too?) - throw std::runtime_error(std::string(__FILE__) + "[" + numberTo(__LINE__) + "] Failed to generate GUID." + - "\n" + utfTo(formatSystemError(L"read", bytesRead < 0 ? errno : EIO))); + throw std::runtime_error(std::string(__FILE__) + '[' + numberTo(__LINE__) + "] Failed to generate GUID." + "\n\n" + + utfTo(formatSystemError(L"read", bytesRead < 0 ? errno : EIO))); offset += bytesRead; assert(offset <= size); } diff --git a/zen/http.cpp b/zen/http.cpp index 8cd99d7a..c6a390de 100644 --- a/zen/http.cpp +++ b/zen/http.cpp @@ -19,7 +19,7 @@ class HttpInputStream::Impl public: Impl(const Zstring& url, const std::string* postBuf /*issue POST if bound, GET otherwise*/, - const Zstring& contentType, //required for POST + const std::string& contentType, //required for POST bool disableGetCache /*not relevant for POST (= never cached)*/, const Zstring& userAgent, const Zstring* caCertFilePath /*optional: enable certificate validation*/, @@ -37,9 +37,9 @@ public: const bool useTls = [&] { - if (startsWithAsciiNoCase(url, Zstr("http://"))) + if (startsWithAsciiNoCase(url, "http://")) return false; - if (startsWithAsciiNoCase(url, Zstr("https://"))) + if (startsWithAsciiNoCase(url, "https://")) return true; throw SysError(L"URL uses unexpected protocol."); }(); @@ -49,7 +49,7 @@ public: std::map headers; if (postBuf && !contentType.empty()) - headers["Content-Type"] = utfTo(contentType); + headers["Content-Type"] = contentType; if (useTls) //HTTP default port: 443, see %WINDIR%\system32\drivers\etc\services { @@ -96,7 +96,7 @@ public: const size_t blockSize = std::min(static_cast(1024), memBuf_.size()); //smaller block size: try to only read header part buf.resize(buf.size() + blockSize); const size_t bytesReceived = tryRead(&*(buf.end() - blockSize), blockSize); //throw SysError - buf.resize(buf.size() - blockSize + bytesReceived); //caveat: unsigned arithmetics + buf.resize(buf.size() - (blockSize - bytesReceived)); //caveat: unsigned arithmetics if (contains(buf, headerDelim)) { @@ -122,8 +122,8 @@ public: statusCode_ = stringTo(statusItems[1]); for (const std::string& line : split(headersBuf, "\r\n", SplitType::SKIP_EMPTY)) - responseHeaders_[trimCpy(beforeFirst(line, ":", IF_MISSING_RETURN_ALL))] = - /**/ trimCpy(afterFirst (line, ":", IF_MISSING_RETURN_NONE)); + responseHeaders_[trimCpy(beforeFirst(line, ':', IF_MISSING_RETURN_ALL))] = + /**/ trimCpy(afterFirst (line, ':', IF_MISSING_RETURN_NONE)); //try to get "Content-Length" header if available if (const std::string* value = getHeader("Content-Length")) @@ -236,7 +236,7 @@ namespace { std::unique_ptr sendHttpRequestImpl(const Zstring& url, const std::string* postBuf /*issue POST if bound, GET otherwise*/, - const Zstring& contentType, //required for POST + const std::string& contentType, //required for POST const Zstring& userAgent, const Zstring* caCertFilePath /*optional: enable certificate validation*/, const IOCallback& notifyUnbufferedIO) //throw SysError, X @@ -248,8 +248,8 @@ std::unique_ptr sendHttpRequestImpl(const Zstring& url, auto response = std::make_unique(urlRed, postBuf, contentType, false /*disableGetCache*/, userAgent, caCertFilePath, notifyUnbufferedIO); //throw SysError, X //https://en.wikipedia.org/wiki/List_of_HTTP_status_codes#3xx_Redirection - const int httpStatusCode = response->getStatusCode(); - if (httpStatusCode / 100 == 3) //e.g. 301, 302, 303, 307... we're not too greedy since we check location, too! + const int httpStatus = response->getStatusCode(); + if (httpStatus / 100 == 3) //e.g. 301, 302, 303, 307... we're not too greedy since we check location, too! { const std::string* value = response->getHeader("Location"); if (!value || value->empty()) @@ -259,8 +259,8 @@ std::unique_ptr sendHttpRequestImpl(const Zstring& url, } else { - if (httpStatusCode != 200) //HTTP_STATUS_OK(200) - throw SysError(formatHttpStatusCode(httpStatusCode)); //e.g. HTTP_STATUS_NOT_FOUND(404) + if (httpStatus != 200) //HTTP_STATUS_OK(200) + throw SysError(formatHttpStatus(httpStatus)); //e.g. HTTP_STATUS_NOT_FOUND(404) return response; } @@ -340,19 +340,19 @@ std::vector> zen::xWwwFormUrlDecode(const st HttpInputStream zen::sendHttpGet(const Zstring& url, const Zstring& userAgent, const Zstring* caCertFilePath, const IOCallback& notifyUnbufferedIO) //throw SysError, X { - return sendHttpRequestImpl(url, nullptr /*postBuf*/, Zstr("") /*contentType*/, userAgent, caCertFilePath, notifyUnbufferedIO); //throw SysError, X, X + return sendHttpRequestImpl(url, nullptr /*postBuf*/, "" /*contentType*/, userAgent, caCertFilePath, notifyUnbufferedIO); //throw SysError, X, X } HttpInputStream zen::sendHttpPost(const Zstring& url, const std::vector>& postParams, const Zstring& userAgent, const Zstring* caCertFilePath, const IOCallback& notifyUnbufferedIO) //throw SysError, X { - return sendHttpPost(url, xWwwFormUrlEncode(postParams), Zstr("application/x-www-form-urlencoded"), userAgent, caCertFilePath, notifyUnbufferedIO); //throw SysError, X + return sendHttpPost(url, xWwwFormUrlEncode(postParams), "application/x-www-form-urlencoded", userAgent, caCertFilePath, notifyUnbufferedIO); //throw SysError, X } -HttpInputStream zen::sendHttpPost(const Zstring& url, const std::string& postBuf, const Zstring& contentType, +HttpInputStream zen::sendHttpPost(const Zstring& url, const std::string& postBuf, const std::string& contentType, const Zstring& userAgent, const Zstring* caCertFilePath, const IOCallback& notifyUnbufferedIO) //throw SysError, X { return sendHttpRequestImpl(url, &postBuf, contentType, userAgent, caCertFilePath, notifyUnbufferedIO); //throw SysError, X @@ -365,7 +365,7 @@ bool zen::internetIsAlive() //noexcept { auto response = std::make_unique(Zstr("http://www.google.com/"), nullptr /*postParams*/, - Zstr("") /*contentType*/, + "" /*contentType*/, true /*disableGetCache*/, Zstr("FreeFileSync"), nullptr /*caCertFilePath*/, @@ -380,7 +380,7 @@ bool zen::internetIsAlive() //noexcept } -std::wstring zen::formatHttpStatusCode(int sc) +std::wstring zen::formatHttpStatus(int sc) { const wchar_t* statusText = [&] //https://en.wikipedia.org/wiki/List_of_HTTP_status_codes { @@ -462,13 +462,13 @@ std::wstring zen::formatHttpStatusCode(int sc) } -bool zen::isValidEmail(const Zstring& email) +bool zen::isValidEmail(const std::string& email) { //https://en.wikipedia.org/wiki/Email_address#Syntax //https://tools.ietf.org/html/rfc3696 => note errata! https://www.rfc-editor.org/errata_search.php?rfc=3696 //https://tools.ietf.org/html/rfc5321 - std::string local = utfTo(beforeLast(email, Zstr('@'), IF_MISSING_RETURN_NONE)); - std::string domain = utfTo( afterLast(email, Zstr('@'), IF_MISSING_RETURN_NONE)); + std::string local = beforeLast(email, '@', IF_MISSING_RETURN_NONE); + std::string domain = afterLast(email, '@', IF_MISSING_RETURN_NONE); //consider: "t@st"@email.com t\@st@email.com" auto stripComments = [](std::string& part) @@ -517,7 +517,7 @@ bool zen::isValidEmail(const Zstring& email) } -std::string zen::htmlSpecialChars(const std::string& str) +std::string zen::htmlSpecialChars(const std::string_view& str) { //mirror PHP: https://github.com/php/php-src/blob/e99d5d39239c611e1e7304e79e88545c4e71a073/ext/standard/html_tables.h#L6189 std::string output; diff --git a/zen/http.h b/zen/http.h index fbaa09de..09395f8f 100644 --- a/zen/http.h +++ b/zen/http.h @@ -48,15 +48,15 @@ HttpInputStream sendHttpPost(const Zstring& url, const IOCallback& notifyUnbufferedIO /*throw X*/); //throw SysError, X HttpInputStream sendHttpPost(const Zstring& url, - const std::string& postBuf, const Zstring& contentType, + const std::string& postBuf, const std::string& contentType, const Zstring& userAgent, const Zstring* caCertFilePath /*optional: enable certificate validation*/, const IOCallback& notifyUnbufferedIO /*throw X*/); //throw SysError, X bool internetIsAlive(); //noexcept -std::wstring formatHttpStatusCode(int httpStatusCode); -bool isValidEmail(const Zstring& email); -std::string htmlSpecialChars(const std::string& str); +std::wstring formatHttpStatus(int httpStatus); +bool isValidEmail(const std::string& email); +std::string htmlSpecialChars(const std::string_view& str); std::string xWwwFormUrlEncode(const std::vector>& paramPairs); std::vector> xWwwFormUrlDecode(const std::string& str); diff --git a/zen/legacy_compiler.h b/zen/legacy_compiler.h index 54dd7f59..8d44f3f7 100644 --- a/zen/legacy_compiler.h +++ b/zen/legacy_compiler.h @@ -8,11 +8,6 @@ #define LEGACY_COMPILER_H_839567308565656789 -#if !__cpp_lib_erase_if - #include - #include - #include -#endif //https://isocpp.org/std/standing-documents/sd-6-sg10-feature-test-recommendations @@ -58,8 +53,18 @@ private: 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 dc9c8a19..b823f8ca 100644 --- a/zen/open_ssl.cpp +++ b/zen/open_ssl.cpp @@ -322,8 +322,8 @@ std::string createSignature(const std::string& message, EVP_PKEY* privateKey) // reinterpret_cast(&signature[0]), //unsigned char* sigret, &sigLen) != 1) //size_t* siglen throw SysError(formatLastOpenSSLError(L"EVP_DigestSignFinal")); - signature.resize(sigLen); + signature.resize(sigLen); return signature; } @@ -373,7 +373,7 @@ void zen::verifySignature(const std::string& message, const std::string& signatu namespace { -std::wstring formatSslErrorRaw(int ec) +std::wstring formatSslErrorCode(int ec) { switch (ec) { @@ -388,12 +388,15 @@ std::wstring formatSslErrorRaw(int ec) ZEN_CHECK_CASE_FOR_CONSTANT(SSL_ERROR_WANT_ACCEPT); ZEN_CHECK_CASE_FOR_CONSTANT(SSL_ERROR_WANT_ASYNC); ZEN_CHECK_CASE_FOR_CONSTANT(SSL_ERROR_WANT_ASYNC_JOB); + ZEN_CHECK_CASE_FOR_CONSTANT(SSL_ERROR_WANT_CLIENT_HELLO_CB); + + default: + return replaceCpy(L"SSL error %x", L"%x", numberTo(ec)); } - return L"Unknown SSL error: " + numberTo(ec); } -std::wstring formatX509ErrorRaw(long ec) +std::wstring formatX509ErrorCode(long ec) { switch (ec) { @@ -473,8 +476,10 @@ std::wstring formatX509ErrorRaw(long ec) ZEN_CHECK_CASE_FOR_CONSTANT(X509_V_ERR_OCSP_VERIFY_NEEDED); ZEN_CHECK_CASE_FOR_CONSTANT(X509_V_ERR_OCSP_VERIFY_FAILED); ZEN_CHECK_CASE_FOR_CONSTANT(X509_V_ERR_OCSP_CERT_UNKNOWN); + + default: + return replaceCpy(L"X509 error %x", L"%x", numberTo(ec)); } - return L"Unknown X509 error: " + numberTo(ec); } } @@ -487,7 +492,7 @@ public: { ZEN_ON_SCOPE_FAIL(cleanup(); /*destructor call would lead to member double clean-up!!!*/); - ctx_ = ::SSL_CTX_new(TLS_client_method()); + ctx_ = ::SSL_CTX_new(::TLS_client_method()); if (!ctx_) throw SysError(formatLastOpenSSLError(L"SSL_CTX_new")); @@ -526,13 +531,13 @@ public: const int rv = ::SSL_connect(ssl_); //implicitly calls SSL_set_connect_state() if (rv != 1) - throw SysError(formatLastOpenSSLError(L"SSL_connect") + L" " + formatSslErrorRaw(::SSL_get_error(ssl_, rv))); + throw SysError(formatLastOpenSSLError(L"SSL_connect") + L' ' + formatSslErrorCode(::SSL_get_error(ssl_, rv))); if (caCertFilePath) { const long verifyResult = ::SSL_get_verify_result(ssl_); if (verifyResult != X509_V_OK) - throw SysError(formatSystemError(L"SSL_get_verify_result", formatX509ErrorRaw(verifyResult), L"")); + throw SysError(formatSystemError(L"SSL_get_verify_result", formatX509ErrorCode(verifyResult), L"")); } } @@ -554,7 +559,7 @@ public: size_t tryRead(void* buffer, size_t bytesToRead) //throw SysError; may return short, only 0 means EOF! { if (bytesToRead == 0) //"read() with a count of 0 returns zero" => indistinguishable from end of file! => check! - throw std::logic_error("Contract violation! " + std::string(__FILE__) + ":" + numberTo(__LINE__)); + throw std::logic_error("Contract violation! " + std::string(__FILE__) + ':' + numberTo(__LINE__)); size_t bytesReceived = 0; const int rv = ::SSL_read_ex(ssl_, buffer, bytesToRead, &bytesReceived); @@ -564,7 +569,7 @@ public: if (sslError == SSL_ERROR_ZERO_RETURN || //EOF + close_notify alert (sslError == SSL_ERROR_SYSCALL && ::ERR_peek_last_error() == 0)) //EOF: only expected for HTTP/1.0 return 0; - throw SysError(formatLastOpenSSLError(L"SSL_read_ex") + L" " + formatSslErrorRaw(sslError)); + throw SysError(formatLastOpenSSLError(L"SSL_read_ex") + L' ' + formatSslErrorCode(sslError)); } assert(bytesReceived > 0); //SSL_read_ex() considers EOF an error! if (bytesReceived > bytesToRead) //better safe than sorry @@ -576,12 +581,12 @@ public: size_t tryWrite(const void* buffer, size_t bytesToWrite) //throw SysError; may return short! CONTRACT: bytesToWrite > 0 { if (bytesToWrite == 0) - throw std::logic_error("Contract violation! " + std::string(__FILE__) + ":" + numberTo(__LINE__)); + throw std::logic_error("Contract violation! " + std::string(__FILE__) + ':' + numberTo(__LINE__)); size_t bytesWritten = 0; const int rv = ::SSL_write_ex(ssl_, buffer, bytesToWrite, &bytesWritten); if (rv != 1) - throw SysError(formatLastOpenSSLError(L"SSL_write_ex") + L" " + formatSslErrorRaw(::SSL_get_error(ssl_, rv))); + throw SysError(formatLastOpenSSLError(L"SSL_write_ex") + L' ' + formatSslErrorCode(::SSL_get_error(ssl_, rv))); if (bytesWritten > bytesToWrite) throw SysError(L"SSL_write_ex: buffer overflow."); @@ -759,7 +764,7 @@ std::string zen::convertPuttyKeyToPkix(const std::string& keyStream, const std:: auto numToBeString = [](size_t n) -> std::string { - static_assert(usingLittleEndian()&& sizeof(n) >= 4); + static_assert(usingLittleEndian() && sizeof(n) >= 4); const char* numStr = reinterpret_cast(&n); return { numStr[3], numStr[2], numStr[1], numStr[0] }; //big endian! }; diff --git a/zen/perf.h b/zen/perf.h index b6cb5bb0..9f368016 100644 --- a/zen/perf.h +++ b/zen/perf.h @@ -98,7 +98,7 @@ public: const int64_t timeMs = std::chrono::duration_cast(watch_.elapsed()).count(); const std::string msg = numberTo(timeMs) + " ms"; - std::clog << "Perf: duration: " << msg << "\n"; + std::clog << "Perf: duration: " << msg << '\n'; resultShown_ = true; } diff --git a/zen/recycler.cpp b/zen/recycler.cpp index dc156a6f..f4fd870b 100644 --- a/zen/recycler.cpp +++ b/zen/recycler.cpp @@ -45,7 +45,9 @@ bool zen::recycleOrDeleteIfExists(const Zstring& itemPath) //throw FileError return true; } - throw FileError(errorMsg, formatSystemError(L"g_file_trash", replaceCpy(_("Error Code %x"), L"%x", numberTo(error->code)), utfTo(error->message))); + throw FileError(errorMsg, formatSystemError(L"g_file_trash", + replaceCpy(_("Error Code %x"), L"%x", numberTo(error->code)), + utfTo(error->message))); //g_quark_to_string(error->domain) } return true; diff --git a/zen/serialize.h b/zen/serialize.h index dd884e3b..1eabcdec 100644 --- a/zen/serialize.h +++ b/zen/serialize.h @@ -25,35 +25,6 @@ namespace zen binary container for data storage: must support "basic" std::vector interface (e.g. std::vector, std::string, Zbase) */ -//binary container reference implementations -using Utf8String = Zbase; //ref-counted + COW text stream + guaranteed performance: exponential growth -class ByteArray; //ref-counted byte stream + guaranteed performance: exponential growth -> no COW, but 12% faster than Utf8String (due to no null-termination?) - - -class ByteArray //essentially a std::vector with ref-counted semantics, but no COW! => *almost* value type semantics, but not quite -{ -public: - using value_type = std::vector::value_type; - using iterator = std::vector::iterator; - using const_iterator = std::vector::const_iterator; - - iterator begin() { return buffer_.ref().begin(); } - iterator end () { return buffer_.ref().end (); } - - const_iterator begin() const { return buffer_.ref().begin(); } - const_iterator end () const { return buffer_.ref().end (); } - - void resize(size_t len) { buffer_.ref().resize(len); } - size_t size() const { return buffer_.ref().size(); } - bool empty() const { return buffer_.ref().empty(); } - - inline friend bool operator==(const ByteArray& lhs, const ByteArray& rhs) { return lhs.buffer_.ref() == rhs.buffer_.ref(); } - -private: - SharedRef> buffer_ = makeSharedRef>(); - //perf: shared_ptr indirection irrelevant: less than 1% slower! -}; - /* ------------------------------- |Buffered Input Stream Concept| @@ -158,6 +129,7 @@ struct MemoryStreamOut } const BinContainer& ref() const { return buffer_; } + /**/ BinContainer& ref() { return buffer_; } private: MemoryStreamOut (const MemoryStreamOut&) = delete; @@ -180,7 +152,7 @@ void bufferedStreamCopy(BufferedInputStream& streamIn, //throw X { const size_t blockSize = streamIn.getBlockSize(); if (blockSize == 0) - throw std::logic_error("Contract violation! " + std::string(__FILE__) + ":" + numberTo(__LINE__)); + throw std::logic_error("Contract violation! " + std::string(__FILE__) + ':' + numberTo(__LINE__)); std::vector buffer(blockSize); for (;;) @@ -201,7 +173,7 @@ BinContainer bufferedLoad(BufferedInputStream& streamIn) //throw X const size_t blockSize = streamIn.getBlockSize(); if (blockSize == 0) - throw std::logic_error("Contract violation! " + std::string(__FILE__) + ":" + numberTo(__LINE__)); + throw std::logic_error("Contract violation! " + std::string(__FILE__) + ':' + numberTo(__LINE__)); BinContainer buffer; for (;;) @@ -238,7 +210,7 @@ void writeContainer(BufferedOutputStream& stream, const C& cont) //don't even co const auto len = cont.size(); writeNumber(stream, static_cast(len)); if (len > 0) - writeArray(stream, &*cont.begin(), sizeof(typename C::value_type) * len); //don't use c_str(), but access uniformly via STL interface + writeArray(stream, &cont[0], sizeof(typename C::value_type) * len); //don't use c_str(), but access uniformly via STL interface } @@ -276,7 +248,7 @@ C readContainer(BufferedInputStream& stream) //throw UnexpectedEndOfStreamError catch (std::length_error&) { throw UnexpectedEndOfStreamError(); } //most likely this is due to data corruption! catch ( std::bad_alloc&) { throw UnexpectedEndOfStreamError(); } // - readArray(stream, &*cont.begin(), sizeof(typename C::value_type) * strLength); //throw UnexpectedEndOfStreamError + readArray(stream, &cont[0], sizeof(typename C::value_type) * strLength); //throw UnexpectedEndOfStreamError } return cont; } diff --git a/zen/shell_execute.h b/zen/shell_execute.h index 580c4558..faea4bd9 100644 --- a/zen/shell_execute.h +++ b/zen/shell_execute.h @@ -74,7 +74,7 @@ int shellExecute(const Zstring& command, ExecutionType type, bool hideConsole) / std::string getCommandOutput(const Zstring& command) //throw SysError { //https://developer.apple.com/library/archive/documentation/System/Conceptual/ManPages_iPhoneOS/man3/popen.3.html - FILE* pipe = ::popen(command.c_str(), "r"); + FILE* pipe = ::popen(command.c_str(), "r"); if (!pipe) THROW_LAST_SYS_ERROR(L"popen"); ZEN_ON_SCOPE_EXIT(::pclose(pipe)); @@ -97,7 +97,7 @@ std::string getCommandOutput(const Zstring& command) //throw SysError output.resize(output.size() - (blockSize - bytesRead)); //caveat: unsigned arithmetics } while (!::feof(pipe)); - + return output; } } diff --git a/zen/socket.h b/zen/socket.h index 827d446b..3bd0a2a0 100644 --- a/zen/socket.h +++ b/zen/socket.h @@ -89,7 +89,7 @@ namespace size_t tryReadSocket(SocketType socket, void* buffer, size_t bytesToRead) //throw SysError; may return short, only 0 means EOF! { if (bytesToRead == 0) //"read() with a count of 0 returns zero" => indistinguishable from end of file! => check! - throw std::logic_error("Contract violation! " + std::string(__FILE__) + ":" + numberTo(__LINE__)); + throw std::logic_error("Contract violation! " + std::string(__FILE__) + ':' + numberTo(__LINE__)); int bytesReceived = 0; for (;;) @@ -114,7 +114,7 @@ size_t tryReadSocket(SocketType socket, void* buffer, size_t bytesToRead) //thro size_t tryWriteSocket(SocketType socket, const void* buffer, size_t bytesToWrite) //throw SysError; may return short! CONTRACT: bytesToWrite > 0 { if (bytesToWrite == 0) - throw std::logic_error("Contract violation! " + std::string(__FILE__) + ":" + numberTo(__LINE__)); + throw std::logic_error("Contract violation! " + std::string(__FILE__) + ':' + numberTo(__LINE__)); int bytesWritten = 0; for (;;) diff --git a/zen/string_base.h b/zen/string_base.h index 6c835c72..d2e00baf 100644 --- a/zen/string_base.h +++ b/zen/string_base.h @@ -221,6 +221,7 @@ public: Zbase(); Zbase(const Char* str) : Zbase(str, str + strLength(str)) {} //implicit conversion from a C-string! Zbase(const Char* str, size_t len) : Zbase(str, str + len) {} + Zbase(size_t count, Char fillChar); Zbase(const Zbase& str); Zbase(Zbase&& tmp) noexcept; template @@ -251,7 +252,8 @@ public: size_t length() const; size_t size () const { return length(); } const Char* c_str() const { return rawStr_; } //C-string format with 0-termination - const Char operator[](size_t pos) const; + const Char& operator[](size_t pos) const; + /**/ Char& operator[](size_t pos); bool empty() const { return length() == 0; } void clear(); size_t find (const Zbase& str, size_t pos = 0) const; // @@ -283,10 +285,11 @@ public: static const size_t npos = static_cast(-1); private: - Zbase (int) = delete; // - Zbase& operator= (int) = delete; //detect usage errors by creating an intentional ambiguity with "Char" - Zbase& operator+=(int) = delete; // - void push_back (int) = delete; // + Zbase (int) = delete; // + Zbase(size_t count, int) = delete; // + Zbase& operator= (int) = delete; //detect usage errors by creating an intentional ambiguity with "Char" + Zbase& operator+= (int) = delete; // + void push_back (int) = delete; // Char* rawStr_; }; @@ -359,6 +362,15 @@ Zbase::Zbase(InputIterator first, InputIterator last) } +template class SP> inline +Zbase::Zbase(size_t count, Char fillChar) +{ + rawStr_ = this->create(count); + std::fill(rawStr_, rawStr_ + count, fillChar); + rawStr_[count] = 0; +} + + template class SP> inline Zbase::Zbase(const Zbase& str) { @@ -544,7 +556,15 @@ size_t Zbase::length() const template class SP> inline -const Char Zbase::operator[](size_t pos) const +const Char& Zbase::operator[](size_t pos) const +{ + assert(pos < length()); //design by contract! no runtime check! + return rawStr_[pos]; +} + + +template class SP> inline +Char& Zbase::operator[](size_t pos) { assert(pos < length()); //design by contract! no runtime check! return rawStr_[pos]; diff --git a/zen/string_tools.h b/zen/string_tools.h index 5c444830..40a4ea52 100644 --- a/zen/string_tools.h +++ b/zen/string_tools.h @@ -167,8 +167,8 @@ Char asciiToLower(Char c) } -template inline -Char asciiToUpper(Char c) + template inline + Char asciiToUpper(Char c) { if (static_cast('a') <= c && c <= static_cast('z')) return static_cast(c - static_cast('a') + static_cast('A')); @@ -182,13 +182,13 @@ inline int strcmpWithNulls(const char* ptr1, const char* ptr2, size_t num) inline int strcmpWithNulls(const wchar_t* ptr1, const wchar_t* ptr2, size_t num) { return std::wmemcmp(ptr1, ptr2, num); } // -template inline -int strcmpAsciiNoCase(const Char* lhs, const Char* rhs, size_t len) +template inline +int strcmpAsciiNoCase(const Char1* lhs, const Char2* rhs, size_t len) { while (len-- > 0) { - const Char charL = asciiToLower(*lhs++); //ordering: lower-case chars have higher code points than uppper-case - const Char charR = asciiToLower(*rhs++); // + const Char1 charL = asciiToLower(*lhs++); //ordering: lower-case chars have higher code points than uppper-case + const Char2 charR = asciiToLower(*rhs++); // if (charL != charR) return static_cast(charL) - static_cast(charR); //unsigned char-comparison is the convention! //unsigned underflow is well-defined! diff --git a/zen/string_traits.h b/zen/string_traits.h index f1269130..69d76b44 100644 --- a/zen/string_traits.h +++ b/zen/string_traits.h @@ -220,7 +220,8 @@ auto makeStringView(Iterator first, Iterator last) last - first); } -template inline auto makeStringView(Iterator first, size_t len) { return makeStringView(first, first + len); } +template inline +auto makeStringView(Iterator first, size_t len) { return makeStringView(first, first + len); } } #endif //STRING_TRAITS_H_813274321443234 diff --git a/zen/sys_error.cpp b/zen/sys_error.cpp index 2acaca1d..b802780b 100644 --- a/zen/sys_error.cpp +++ b/zen/sys_error.cpp @@ -4,3 +4,187 @@ // * Copyright (C) Zenju (zenju AT freefilesync DOT org) - All Rights Reserved * // ***************************************************************************** +#include "sys_error.h" + #include + +using namespace zen; + + + + +std::wstring zen::getSystemErrorDescription(ErrorCode ec) //return empty string on error +{ + const ErrorCode currentError = getLastError(); //not necessarily == ec + ZEN_ON_SCOPE_EXIT(errno = currentError); + + std::wstring errorMsg; + errorMsg = utfTo(::strerror(ec)); + return trimCpy(errorMsg); //Windows messages seem to end with a space... +} + + +namespace +{ +std::wstring formatSystemErrorCode(ErrorCode ec) +{ + switch (ec) //pretty much all codes currently used on CentOS 7 and macOS 10.15 + { + ZEN_CHECK_CASE_FOR_CONSTANT(EPERM); + ZEN_CHECK_CASE_FOR_CONSTANT(ENOENT); + ZEN_CHECK_CASE_FOR_CONSTANT(ESRCH); + ZEN_CHECK_CASE_FOR_CONSTANT(EINTR); + ZEN_CHECK_CASE_FOR_CONSTANT(EIO); + ZEN_CHECK_CASE_FOR_CONSTANT(ENXIO); + ZEN_CHECK_CASE_FOR_CONSTANT(E2BIG); + ZEN_CHECK_CASE_FOR_CONSTANT(ENOEXEC); + ZEN_CHECK_CASE_FOR_CONSTANT(EBADF); + ZEN_CHECK_CASE_FOR_CONSTANT(ECHILD); + ZEN_CHECK_CASE_FOR_CONSTANT(EAGAIN); + ZEN_CHECK_CASE_FOR_CONSTANT(ENOMEM); + ZEN_CHECK_CASE_FOR_CONSTANT(EACCES); + ZEN_CHECK_CASE_FOR_CONSTANT(EFAULT); + ZEN_CHECK_CASE_FOR_CONSTANT(ENOTBLK); + ZEN_CHECK_CASE_FOR_CONSTANT(EBUSY); + ZEN_CHECK_CASE_FOR_CONSTANT(EEXIST); + ZEN_CHECK_CASE_FOR_CONSTANT(EXDEV); + ZEN_CHECK_CASE_FOR_CONSTANT(ENODEV); + ZEN_CHECK_CASE_FOR_CONSTANT(ENOTDIR); + ZEN_CHECK_CASE_FOR_CONSTANT(EISDIR); + ZEN_CHECK_CASE_FOR_CONSTANT(EINVAL); + ZEN_CHECK_CASE_FOR_CONSTANT(ENFILE); + ZEN_CHECK_CASE_FOR_CONSTANT(EMFILE); + ZEN_CHECK_CASE_FOR_CONSTANT(ENOTTY); + ZEN_CHECK_CASE_FOR_CONSTANT(ETXTBSY); + ZEN_CHECK_CASE_FOR_CONSTANT(EFBIG); + ZEN_CHECK_CASE_FOR_CONSTANT(ENOSPC); + ZEN_CHECK_CASE_FOR_CONSTANT(ESPIPE); + ZEN_CHECK_CASE_FOR_CONSTANT(EROFS); + ZEN_CHECK_CASE_FOR_CONSTANT(EMLINK); + ZEN_CHECK_CASE_FOR_CONSTANT(EPIPE); + ZEN_CHECK_CASE_FOR_CONSTANT(EDOM); + ZEN_CHECK_CASE_FOR_CONSTANT(ERANGE); + ZEN_CHECK_CASE_FOR_CONSTANT(EDEADLK); + ZEN_CHECK_CASE_FOR_CONSTANT(ENAMETOOLONG); + ZEN_CHECK_CASE_FOR_CONSTANT(ENOLCK); + ZEN_CHECK_CASE_FOR_CONSTANT(ENOSYS); + ZEN_CHECK_CASE_FOR_CONSTANT(ENOTEMPTY); + ZEN_CHECK_CASE_FOR_CONSTANT(ELOOP); + ZEN_CHECK_CASE_FOR_CONSTANT(ENOMSG); + ZEN_CHECK_CASE_FOR_CONSTANT(EIDRM); + ZEN_CHECK_CASE_FOR_CONSTANT(ENOSTR); + ZEN_CHECK_CASE_FOR_CONSTANT(ENODATA); + ZEN_CHECK_CASE_FOR_CONSTANT(ETIME); + ZEN_CHECK_CASE_FOR_CONSTANT(ENOSR); + ZEN_CHECK_CASE_FOR_CONSTANT(EREMOTE); + ZEN_CHECK_CASE_FOR_CONSTANT(ENOLINK); + ZEN_CHECK_CASE_FOR_CONSTANT(EPROTO); + ZEN_CHECK_CASE_FOR_CONSTANT(EMULTIHOP); + ZEN_CHECK_CASE_FOR_CONSTANT(EBADMSG); + ZEN_CHECK_CASE_FOR_CONSTANT(EOVERFLOW); + ZEN_CHECK_CASE_FOR_CONSTANT(EILSEQ); + ZEN_CHECK_CASE_FOR_CONSTANT(EUSERS); + ZEN_CHECK_CASE_FOR_CONSTANT(ENOTSOCK); + ZEN_CHECK_CASE_FOR_CONSTANT(EDESTADDRREQ); + ZEN_CHECK_CASE_FOR_CONSTANT(EMSGSIZE); + ZEN_CHECK_CASE_FOR_CONSTANT(EPROTOTYPE); + ZEN_CHECK_CASE_FOR_CONSTANT(ENOPROTOOPT); + ZEN_CHECK_CASE_FOR_CONSTANT(EPROTONOSUPPORT); + ZEN_CHECK_CASE_FOR_CONSTANT(ESOCKTNOSUPPORT); + ZEN_CHECK_CASE_FOR_CONSTANT(ENOTSUP); + ZEN_CHECK_CASE_FOR_CONSTANT(EPFNOSUPPORT); + ZEN_CHECK_CASE_FOR_CONSTANT(EAFNOSUPPORT); + ZEN_CHECK_CASE_FOR_CONSTANT(EADDRINUSE); + ZEN_CHECK_CASE_FOR_CONSTANT(EADDRNOTAVAIL); + ZEN_CHECK_CASE_FOR_CONSTANT(ENETDOWN); + ZEN_CHECK_CASE_FOR_CONSTANT(ENETUNREACH); + ZEN_CHECK_CASE_FOR_CONSTANT(ENETRESET); + ZEN_CHECK_CASE_FOR_CONSTANT(ECONNABORTED); + ZEN_CHECK_CASE_FOR_CONSTANT(ECONNRESET); + ZEN_CHECK_CASE_FOR_CONSTANT(ENOBUFS); + ZEN_CHECK_CASE_FOR_CONSTANT(EISCONN); + ZEN_CHECK_CASE_FOR_CONSTANT(ENOTCONN); + ZEN_CHECK_CASE_FOR_CONSTANT(ESHUTDOWN); + ZEN_CHECK_CASE_FOR_CONSTANT(ETOOMANYREFS); + ZEN_CHECK_CASE_FOR_CONSTANT(ETIMEDOUT); + ZEN_CHECK_CASE_FOR_CONSTANT(ECONNREFUSED); + ZEN_CHECK_CASE_FOR_CONSTANT(EHOSTDOWN); + ZEN_CHECK_CASE_FOR_CONSTANT(EHOSTUNREACH); + ZEN_CHECK_CASE_FOR_CONSTANT(EALREADY); + ZEN_CHECK_CASE_FOR_CONSTANT(EINPROGRESS); + ZEN_CHECK_CASE_FOR_CONSTANT(ESTALE); + ZEN_CHECK_CASE_FOR_CONSTANT(EDQUOT); + ZEN_CHECK_CASE_FOR_CONSTANT(ECANCELED); + ZEN_CHECK_CASE_FOR_CONSTANT(EOWNERDEAD); + ZEN_CHECK_CASE_FOR_CONSTANT(ENOTRECOVERABLE); + + ZEN_CHECK_CASE_FOR_CONSTANT(ECHRNG); + ZEN_CHECK_CASE_FOR_CONSTANT(EL2NSYNC); + ZEN_CHECK_CASE_FOR_CONSTANT(EL3HLT); + ZEN_CHECK_CASE_FOR_CONSTANT(EL3RST); + ZEN_CHECK_CASE_FOR_CONSTANT(ELNRNG); + ZEN_CHECK_CASE_FOR_CONSTANT(EUNATCH); + ZEN_CHECK_CASE_FOR_CONSTANT(ENOCSI); + ZEN_CHECK_CASE_FOR_CONSTANT(EL2HLT); + ZEN_CHECK_CASE_FOR_CONSTANT(EBADE); + ZEN_CHECK_CASE_FOR_CONSTANT(EBADR); + ZEN_CHECK_CASE_FOR_CONSTANT(EXFULL); + ZEN_CHECK_CASE_FOR_CONSTANT(ENOANO); + ZEN_CHECK_CASE_FOR_CONSTANT(EBADRQC); + ZEN_CHECK_CASE_FOR_CONSTANT(EBADSLT); + ZEN_CHECK_CASE_FOR_CONSTANT(EBFONT); + ZEN_CHECK_CASE_FOR_CONSTANT(ENONET); + ZEN_CHECK_CASE_FOR_CONSTANT(ENOPKG); + ZEN_CHECK_CASE_FOR_CONSTANT(EADV); + ZEN_CHECK_CASE_FOR_CONSTANT(ESRMNT); + ZEN_CHECK_CASE_FOR_CONSTANT(ECOMM); + ZEN_CHECK_CASE_FOR_CONSTANT(EDOTDOT); + ZEN_CHECK_CASE_FOR_CONSTANT(ENOTUNIQ); + ZEN_CHECK_CASE_FOR_CONSTANT(EBADFD); + ZEN_CHECK_CASE_FOR_CONSTANT(EREMCHG); + ZEN_CHECK_CASE_FOR_CONSTANT(ELIBACC); + ZEN_CHECK_CASE_FOR_CONSTANT(ELIBBAD); + ZEN_CHECK_CASE_FOR_CONSTANT(ELIBSCN); + ZEN_CHECK_CASE_FOR_CONSTANT(ELIBMAX); + ZEN_CHECK_CASE_FOR_CONSTANT(ELIBEXEC); + ZEN_CHECK_CASE_FOR_CONSTANT(ERESTART); + ZEN_CHECK_CASE_FOR_CONSTANT(ESTRPIPE); + ZEN_CHECK_CASE_FOR_CONSTANT(EUCLEAN); + ZEN_CHECK_CASE_FOR_CONSTANT(ENOTNAM); + ZEN_CHECK_CASE_FOR_CONSTANT(ENAVAIL); + ZEN_CHECK_CASE_FOR_CONSTANT(EISNAM); + ZEN_CHECK_CASE_FOR_CONSTANT(EREMOTEIO); + ZEN_CHECK_CASE_FOR_CONSTANT(ENOMEDIUM); + ZEN_CHECK_CASE_FOR_CONSTANT(EMEDIUMTYPE); + ZEN_CHECK_CASE_FOR_CONSTANT(ENOKEY); + ZEN_CHECK_CASE_FOR_CONSTANT(EKEYEXPIRED); + ZEN_CHECK_CASE_FOR_CONSTANT(EKEYREVOKED); + ZEN_CHECK_CASE_FOR_CONSTANT(EKEYREJECTED); + ZEN_CHECK_CASE_FOR_CONSTANT(ERFKILL); + ZEN_CHECK_CASE_FOR_CONSTANT(EHWPOISON); + default: + return replaceCpy(_("Error Code %x"), L"%x", numberTo(ec)); + } +} +} + + +std::wstring zen::formatSystemError(const std::wstring& functionName, ErrorCode ec) +{ + return formatSystemError(functionName, formatSystemErrorCode(ec), getSystemErrorDescription(ec)); +} + + +std::wstring zen::formatSystemError(const std::wstring& functionName, const std::wstring& errorCode, const std::wstring& errorMsg) +{ + std::wstring output = errorCode + L':'; + + const std::wstring errorMsgFmt = trimCpy(errorMsg); + if (!errorMsgFmt.empty()) + { + output += L' '; + output += errorMsgFmt; + } + + output += L" [" + functionName + L']'; + return output; +} diff --git a/zen/sys_error.h b/zen/sys_error.h index a9347bdd..6bef45ea 100644 --- a/zen/sys_error.h +++ b/zen/sys_error.h @@ -8,11 +8,10 @@ #define SYS_ERROR_H_3284791347018951324534 #include -#include "utf.h" -#include "i18n.h" #include "scope_guard.h" +#include "i18n.h" +#include "utf.h" - #include #include @@ -23,9 +22,8 @@ namespace zen ErrorCode getLastError(); -std::wstring formatSystemError(const std::wstring& functionName, ErrorCode ec); std::wstring formatSystemError(const std::wstring& functionName, const std::wstring& errorCode, const std::wstring& errorMsg); - +std::wstring formatSystemError(const std::wstring& functionName, ErrorCode ec); //A low-level exception class giving (non-translated) detail information only - same conceptional level like "GetLastError()"! @@ -47,11 +45,6 @@ private: do { const ErrorCode ecInternal = getLastError(); throw SysError(formatSystemError(functionName, ecInternal)); } while (false) -//helper for error checking macros: -inline bool validatBool(bool b) { return b; } -inline bool validatBool(void* b) { return b != nullptr; } -bool validatBool(int) = delete; //catch unintended bool conversions, e.g. HRESULT - @@ -59,56 +52,15 @@ bool validatBool(int) = delete; //catch unintended bool conversions, e.g. HRESUL inline ErrorCode getLastError() { - return errno; //don't use "::", errno is a macro! + return errno; //don't use "::" prefix, errno is a macro! } -std::wstring formatSystemErrorRaw(long long) = delete; //intentional overload ambiguity to catch usage errors - -inline -std::wstring formatSystemErrorRaw(ErrorCode ec) //return empty string on error -{ - const ErrorCode currentError = getLastError(); //not necessarily == lastError - - std::wstring errorMsg; - ZEN_ON_SCOPE_EXIT(errno = currentError); - - errorMsg = utfTo(::strerror(ec)); - trim(errorMsg); //Windows messages seem to end with a blank... - - return errorMsg; -} +std::wstring getSystemErrorDescription(ErrorCode ec); //return empty string on error +//intentional overload ambiguity to catch usage errors with HRESULT: +std::wstring getSystemErrorDescription(long long) = delete; -std::wstring formatSystemError(const std::wstring& functionName, long long lastError) = delete; //intentional overload ambiguity to catch usage errors with HRESULT! - -inline -std::wstring formatSystemError(const std::wstring& functionName, ErrorCode ec) -{ - const std::wstring errorCode = numberTo(ec); - const std::wstring errorDescr = formatSystemErrorRaw(ec); - - return formatSystemError(functionName, replaceCpy(_("Error Code %x"), L"%x", errorCode), errorDescr); -} - - -inline -std::wstring formatSystemError(const std::wstring& functionName, const std::wstring& errorCode, const std::wstring& errorMsg) -{ - std::wstring output = errorCode + L":"; - - const std::wstring errorMsgFmt = trimCpy(errorMsg); - if (!errorMsgFmt.empty()) - { - output += L" "; - output += errorMsgFmt; - } - - output += L" [" + functionName + L"]"; - - return output; -} - } #endif //SYS_ERROR_H_3284791347018951324534 diff --git a/zen/system.cpp b/zen/system.cpp index 5945484f..9401b94f 100644 --- a/zen/system.cpp +++ b/zen/system.cpp @@ -44,6 +44,7 @@ namespace ComputerModel zen::getComputerModel() //throw FileError { + ComputerModel cm; try { auto tryGetInfo = [](const Zstring& filePath) @@ -57,9 +58,33 @@ ComputerModel zen::getComputerModel() //throw FileError } catch (const FileError& e) { throw SysError(e.toString()); } //errors should be further enriched by context info => SysError }; - return { tryGetInfo("/sys/devices/virtual/dmi/id/product_name"), //throw SysError - tryGetInfo("/sys/devices/virtual/dmi/id/sys_vendor") }; // + cm.model = tryGetInfo("/sys/devices/virtual/dmi/id/product_name"); //throw SysError + cm.vendor = tryGetInfo("/sys/devices/virtual/dmi/id/sys_vendor"); // + + //clean up: + for (const char* dummyModel : + { + "To Be Filled By O.E.M.", "Default string", "empty", "O.E.M", "OEM", "NA", + "System Product Name", "Please change product name", "INVALID", + }) + if (equalAsciiNoCase(cm.model, dummyModel)) + { + cm.model.clear(); + break; + } + + for (const char* dummyVendor : + { + "To Be Filled By O.E.M.", "Default string", "empty", "O.E.M", "OEM", "NA", + "System manufacturer", "OEM Manufacturer", + }) + if (equalAsciiNoCase(cm.vendor, dummyVendor)) + { + cm.vendor.clear(); + break; + } + return cm; } catch (const SysError& e) { throw FileError(_("Cannot get process information."), e.toString()); } } @@ -73,7 +98,7 @@ std::wstring zen::getOsDescription() //throw FileError { const std::string osName = trimCpy(getCommandOutput("lsb_release --id -s" )); //throw SysError const std::string osVersion = trimCpy(getCommandOutput("lsb_release --release -s")); // - return utfTo(osName + " " + osVersion); //e.g. "CentOS 7.7.1908" + return utfTo(osName + ' ' + osVersion); //e.g. "CentOS 7.7.1908" } catch (const SysError& e) { throw FileError(_("Cannot get process information."), e.toString()); } diff --git a/zen/thread.cpp b/zen/thread.cpp index 49c6d9b3..6e8b8219 100644 --- a/zen/thread.cpp +++ b/zen/thread.cpp @@ -28,7 +28,7 @@ uint64_t getThreadIdNative() const pid_t tid = ::syscall(SYS_gettid); //no-fail //"Invalid thread and process IDs": https://devblogs.microsoft.com/oldnewthing/20040223-00/?p=40503 //if (tid == 0) -> not sure this holds on Linux, too! - // throw std::runtime_error(std::string(__FILE__) + "[" + numberTo(__LINE__) + "] Failed to get thread ID."); + // throw std::runtime_error(std::string(__FILE__) + '[' + numberTo(__LINE__) + "] Failed to get thread ID."); static_assert(sizeof(uint64_t) >= sizeof(tid)); return tid; } diff --git a/zen/thread.h b/zen/thread.h index d6cafab7..a1d5197c 100644 --- a/zen/thread.h +++ b/zen/thread.h @@ -149,7 +149,7 @@ class ThreadGroup { public: ThreadGroup(size_t threadCountMax, const std::string& groupName) : threadCountMax_(threadCountMax), groupName_(groupName) - { if (threadCountMax == 0) throw std::logic_error("Contract violation! " + std::string(__FILE__) + ":" + numberTo(__LINE__)); } + { if (threadCountMax == 0) throw std::logic_error("Contract violation! " + std::string(__FILE__) + ':' + numberTo(__LINE__)); } ~ThreadGroup() { diff --git a/zen/time.h b/zen/time.h index 27ce518f..9718e5f6 100644 --- a/zen/time.h +++ b/zen/time.h @@ -8,7 +8,7 @@ #define TIME_H_8457092814324342453627 #include -#include "string_tools.h" +#include "zstring.h" namespace zen @@ -24,7 +24,7 @@ struct TimeComp //replaces std::tm and SYSTEMTIME }; inline bool operator==(const TimeComp& lhs, const TimeComp& rhs) { - return lhs.year == rhs.year && lhs.month == rhs.month && lhs.day == rhs.day && lhs.hour == rhs.hour && lhs.minute == rhs.minute && lhs.second == rhs.second; + return lhs.second == rhs.second && lhs.minute == rhs.minute && lhs.hour == rhs.hour && lhs.day == rhs.day && lhs.month == rhs.month && lhs.year == rhs.year; } inline bool operator!=(const TimeComp& lhs, const TimeComp& rhs) { return !(lhs == rhs); } @@ -37,34 +37,26 @@ time_t utcToTimeT(const TimeComp& tc); //convert UTC time compone TimeComp getCompileTime(); //returns TimeComp() on error //---------------------------------------------------------------------------------------------------------------------------------- - -/* -format (current) date and time; example: - formatTime(L"%Y|%m|%d"); -> "2011|10|29" - formatTime(FORMAT_DATE); -> "2011-10-29" - formatTime(FORMAT_TIME); -> "17:55:34" -*/ -template -String formatTime(const String2& format, const TimeComp& tc = getLocalTime()); //format as specified by "std::strftime", returns empty string on failure +/* format (current) date and time; example: + formatTime(Zstr("%Y|%m|%d")); -> "2011|10|29" + formatTime(formatDateTag); -> "2011-10-29" + formatTime(formatTimeTag); -> "17:55:34" */ +Zstring formatTime(const Zchar* format, const TimeComp& tc = getLocalTime()); //format as specified by "std::strftime", returns empty string on failure //the "format" parameter of formatTime() is partially specialized with the following type tags: -const struct FormatDateTag {} FORMAT_DATE = {}; //%x - locale dependent date representation: e.g. 8/23/2001 -const struct FormatTimeTag {} FORMAT_TIME = {}; //%X - locale dependent time representation: e.g. 2:55:02 PM -const struct FormatDateTimeTag {} FORMAT_DATE_TIME = {}; //%c - locale dependent date and time: e.g. 8/23/2001 2:55:02 PM +const Zchar* const formatDateTag = Zstr("%x"); //locale-dependent date representation: e.g. 8/23/2001 +const Zchar* const formatTimeTag = Zstr("%X"); //locale-dependent time representation: e.g. 2:55:02 PM +const Zchar* const formatDateTimeTag = Zstr("%c"); //locale-dependent date and time: e.g. 8/23/2001 2:55:02 PM -const struct FormatIsoDateTag {} FORMAT_ISO_DATE = {}; //%Y-%m-%d - e.g. 2001-08-23 -const struct FormatIsoTimeTag {} FORMAT_ISO_TIME = {}; //%H:%M:%S - e.g. 14:55:02 -const struct FormatIsoDateTimeTag {} FORMAT_ISO_DATE_TIME = {}; //%Y-%m-%d %H:%M:%S - e.g. 2001-08-23 14:55:02 +const Zchar* const formatIsoDateTag = Zstr("%Y-%m-%d"); //e.g. 2001-08-23 +const Zchar* const formatIsoTimeTag = Zstr("%H:%M:%S"); //e.g. 14:55:02 +const Zchar* const formatIsoDateTimeTag = Zstr("%Y-%m-%d %H:%M:%S"); //e.g. 2001-08-23 14:55:02 //---------------------------------------------------------------------------------------------------------------------------------- - -/* -example: parseTime("%Y-%m-%d %H:%M:%S", "2001-08-23 14:55:02"); - parseTime(FORMAT_ISO_DATE_TIME, "2001-08-23 14:55:02"); -*/ +//example: parseTime("%Y-%m-%d %H:%M:%S", "2001-08-23 14:55:02"); +// parseTime(formatIsoDateTimeTag, "2001-08-23 14:55:02"); template TimeComp parseTime(const String& format, const String2& str); //similar to ::strptime() - //---------------------------------------------------------------------------------------------------------------------------------- @@ -118,68 +110,6 @@ TimeComp toZenTimeComponents(const std::tm& ctc) } -template -struct GetFormat; //get default time formats as char* or wchar_t* - -template <> -struct GetFormat //%x - locale dependent date representation: e.g. 08/23/01 -{ - const char* format(char) const { return "%x"; } - const wchar_t* format(wchar_t) const { return L"%x"; } -}; - -template <> -struct GetFormat //%X - locale dependent time representation: e.g. 14:55:02 -{ - const char* format(char) const { return "%X"; } - const wchar_t* format(wchar_t) const { return L"%X"; } -}; - -template <> -struct GetFormat //%c - locale dependent date and time: e.g. Thu Aug 23 14:55:02 2001 -{ - const char* format(char) const { return "%c"; } - const wchar_t* format(wchar_t) const { return L"%c"; } -}; - -template <> -struct GetFormat //%Y-%m-%d - e.g. 2001-08-23 -{ - const char* format(char) const { return "%Y-%m-%d"; } - const wchar_t* format(wchar_t) const { return L"%Y-%m-%d"; } -}; - -template <> -struct GetFormat //%H:%M:%S - e.g. 14:55:02 -{ - const char* format(char) const { return "%H:%M:%S"; } - const wchar_t* format(wchar_t) const { return L"%H:%M:%S"; } -}; - -template <> -struct GetFormat //%Y-%m-%d %H:%M:%S - e.g. 2001-08-23 14:55:02 -{ - const char* format(char) const { return "%Y-%m-%d %H:%M:%S"; } - const wchar_t* format(wchar_t) const { return L"%Y-%m-%d %H:%M:%S"; } -}; - - -//strftime() craziness on invalid input: -// VS 2010: CRASH unless "_invalid_parameter_handler" is set: https://msdn.microsoft.com/en-us/library/ksazx244.aspx -// GCC: returns 0, apparently no crash. Still, considering some clib maintainer's comments, we should expect the worst! -inline -size_t strftimeWrap_impl(char* buffer, size_t bufferSize, const char* format, const std::tm* timeptr) -{ - return std::strftime(buffer, bufferSize, format, timeptr); -} - - -inline -size_t strftimeWrap_impl(wchar_t* buffer, size_t bufferSize, const wchar_t* format, const std::tm* timeptr) -{ - return std::wcsftime(buffer, bufferSize, format, timeptr); -} - /* inline bool isValid(const std::tm& t) @@ -203,35 +133,6 @@ bool isValid(const std::tm& t) //tm_isdst }; */ - -template inline -size_t strftimeWrap(CharType* buffer, size_t bufferSize, const CharType* format, const std::tm* timeptr) -{ - return strftimeWrap_impl(buffer, bufferSize, format, timeptr); -} - - -struct UserDefinedFormatTag {}; -struct PredefinedFormatTag {}; - -template inline -String formatTime(const String2& format, const TimeComp& tc, UserDefinedFormatTag) //format as specified by "std::strftime", returns empty string on failure -{ - std::tm ctc = toClibTimeComponents(tc); - std::mktime(&ctc); // unfortunately std::strftime() needs all elements of "struct tm" filled, e.g. tm_wday, tm_yday - //note: although std::mktime() explicitly expects "local time", calculating weekday and day of year *should* be time-zone and DST independent - - GetCharTypeT buffer[256] = {}; - const size_t charsWritten = strftimeWrap(buffer, 256, strBegin(format), &ctc); - return String(buffer, charsWritten); -} - - -template inline -String formatTime(FormatType, const TimeComp& tc, PredefinedFormatTag) -{ - return formatTime(GetFormat().format(GetCharTypeT()), tc, UserDefinedFormatTag()); -} } @@ -298,28 +199,29 @@ TimeComp getCompileTime() } -template inline -String formatTime(const String2& format, const TimeComp& tc) +inline +Zstring formatTime(const Zchar* format, const TimeComp& tc) { if (tc == TimeComp()) //failure code from getLocalTime() - return String(); + return Zstring(); - using FormatTag = std::conditional_t< - std::is_same_v || - std::is_same_v || - std::is_same_v || - std::is_same_v || - std::is_same_v || - std::is_same_v, impl::PredefinedFormatTag, impl::UserDefinedFormatTag>; + std::tm ctc = impl::toClibTimeComponents(tc); + std::mktime(&ctc); //unfortunately std::strftime() needs all elements of "struct tm" filled, e.g. tm_wday, tm_yday + //note: although std::mktime() explicitly expects "local time", calculating weekday and day of year *should* be time-zone and DST independent - return impl::formatTime(format, tc, FormatTag()); + Zstring buffer(256, Zstr('\0')); + //strftime() craziness on invalid input: + // VS 2010: CRASH unless "_invalid_parameter_handler" is set: https://docs.microsoft.com/en-us/cpp/c-runtime-library/parameter-validation + // GCC: returns 0, apparently no crash. Still, considering some clib maintainer's comments, we should expect the worst! + // Windows: avoid char-based strftime() which uses ANSI encoding! (e.g. Greek letters for AM/PM) + const size_t charsWritten = std::strftime(&buffer[0], buffer.size(), format, &ctc); + buffer.resize(charsWritten); + return buffer; } -namespace impl -{ template -TimeComp parseTime(const String& format, const String2& str, UserDefinedFormatTag) +TimeComp parseTime(const String& format, const String2& str) { using CharType = GetCharTypeT; static_assert(std::is_same_v>); @@ -371,11 +273,9 @@ TimeComp parseTime(const String& format, const String2& str, UserDefinedFormatTa return TimeComp(); const char* months[] = { "jan", "feb", "mar", "apr", "may", "jun", "jul", "aug", "sep", "oct", "nov", "dec" }; - auto itMonth = std::find_if(std::begin(months), std::end(months), [&](const char* name) + auto itMonth = std::find_if(std::begin(months), std::end(months), [&](const char* month) { - return asciiToLower(itStr[0]) == name[0] && - asciiToLower(itStr[1]) == name[1] && - asciiToLower(itStr[2]) == name[2]; + return equalAsciiNoCase(makeStringView(itStr, 3), month); }); if (itMonth == std::end(months)) return TimeComp(); @@ -422,26 +322,6 @@ TimeComp parseTime(const String& format, const String2& str, UserDefinedFormatTa return output; } - - -template inline -TimeComp parseTime(FormatType, const String& str, PredefinedFormatTag) -{ - return parseTime(GetFormat().format(GetCharTypeT()), str, UserDefinedFormatTag()); -} -} - - -template inline -TimeComp parseTime(const String& format, const String2& str) -{ - using FormatTag = std::conditional_t< - std::is_same_v || - std::is_same_v || - std::is_same_v, impl::PredefinedFormatTag, impl::UserDefinedFormatTag>; - - return impl::parseTime(format, str, FormatTag()); -} } #endif //TIME_H_8457092814324342453627 diff --git a/zen/zlib_wrap.cpp b/zen/zlib_wrap.cpp index 57a0f33c..685843c3 100644 --- a/zen/zlib_wrap.cpp +++ b/zen/zlib_wrap.cpp @@ -29,8 +29,10 @@ std::wstring formatZlibStatusCode(int sc) ZEN_CHECK_CASE_FOR_CONSTANT(Z_MEM_ERROR); ZEN_CHECK_CASE_FOR_CONSTANT(Z_BUF_ERROR); ZEN_CHECK_CASE_FOR_CONSTANT(Z_VERSION_ERROR); + + default: + return replaceCpy(L"zlib status %x", L"%x", numberTo(sc)); } - return replaceCpy(L"zlib status %x.", L"%x", numberTo(sc)); } } @@ -53,7 +55,7 @@ size_t zen::impl::zlib_compress(const void* src, size_t srcLen, void* trg, size_ // Z_MEM_ERROR: not enough memory // Z_BUF_ERROR: not enough room in the output buffer if (rv != Z_OK || bufferSize > trgLen) - throw SysError(formatSystemError(L"compress2", formatZlibStatusCode(rv), L"zlib error")); + throw SysError(formatSystemError(L"zlib compress2", formatZlibStatusCode(rv), L"")); return bufferSize; } @@ -71,7 +73,7 @@ size_t zen::impl::zlib_decompress(const void* src, size_t srcLen, void* trg, siz // Z_BUF_ERROR: not enough room in the output buffer // Z_DATA_ERROR: input data was corrupted or incomplete if (rv != Z_OK || bufferSize > trgLen) - throw SysError(formatSystemError(L"uncompress", formatZlibStatusCode(rv), L"zlib error")); + throw SysError(formatSystemError(L"zlib uncompress", formatZlibStatusCode(rv), L"")); return bufferSize; } @@ -96,7 +98,7 @@ public: memLevel, //int memLevel Z_DEFAULT_STRATEGY); //int strategy if (rv != Z_OK) - throw SysError(formatSystemError(L"deflateInit2", formatZlibStatusCode(rv), L"zlib error")); + throw SysError(formatSystemError(L"zlib deflateInit2", formatZlibStatusCode(rv), L"")); } ~Impl() @@ -108,7 +110,7 @@ public: size_t read(void* buffer, size_t bytesToRead) //throw SysError, X; return "bytesToRead" bytes unless end of stream! { if (bytesToRead == 0) //"read() with a count of 0 returns zero" => indistinguishable from end of file! => check! - throw std::logic_error("Contract violation! " + std::string(__FILE__) + ":" + numberTo(__LINE__)); + throw std::logic_error("Contract violation! " + std::string(__FILE__) + ':' + numberTo(__LINE__)); gzipStream_.next_out = static_cast(buffer); gzipStream_.avail_out = static_cast(bytesToRead); @@ -131,7 +133,7 @@ public: if (rv == Z_STREAM_END) return bytesToRead - gzipStream_.avail_out; if (rv != Z_OK) - throw SysError(formatSystemError(L"deflate", formatZlibStatusCode(rv), L"zlib error")); + throw SysError(formatSystemError(L"zlib deflate", formatZlibStatusCode(rv), L"")); if (gzipStream_.avail_out == 0) return bytesToRead; diff --git a/zen/zlib_wrap.h b/zen/zlib_wrap.h index b820a4f8..3db609da 100644 --- a/zen/zlib_wrap.h +++ b/zen/zlib_wrap.h @@ -63,7 +63,7 @@ BinContainer compress(const BinContainer& stream, int level) //throw SysError //save uncompressed stream size for decompression const uint64_t uncompressedSize = stream.size(); //use portable number type! contOut.resize(sizeof(uncompressedSize)); - std::memcpy(&*contOut.begin(), &uncompressedSize, sizeof(uncompressedSize)); + std::memcpy(&contOut[0], &uncompressedSize, sizeof(uncompressedSize)); const size_t bufferEstimate = impl::zlib_compressBound(stream.size()); //upper limit for buffer size, larger than input size!!! @@ -105,8 +105,8 @@ BinContainer decompress(const BinContainer& stream) //throw SysError contOut.resize(static_cast(uncompressedSize)); //throw std::bad_alloc } //most likely this is due to data corruption: - catch (const std::length_error& e) { throw SysError(L"zlib error: " + _("Out of memory.") + L" " + utfTo(e.what())); } - catch (const std::bad_alloc& e) { throw SysError(L"zlib error: " + _("Out of memory.") + L" " + utfTo(e.what())); } + catch (const std::length_error& e) { throw SysError(L"zlib error: " + _("Out of memory.") + L' ' + utfTo(e.what())); } + catch (const std::bad_alloc& e) { throw SysError(L"zlib error: " + _("Out of memory.") + L' ' + utfTo(e.what())); } const size_t bytesWritten = impl::zlib_decompress(&*stream.begin() + sizeof(uncompressedSize), stream.size() - sizeof(uncompressedSize), diff --git a/zen/zstring.cpp b/zen/zstring.cpp index ff20b8cf..046a3bd4 100644 --- a/zen/zstring.cpp +++ b/zen/zstring.cpp @@ -50,7 +50,8 @@ Zstring getUnicodeNormalForm(const Zstring& str) { //fast pre-check: if (isAsciiString(str)) //perf: in the range of 3.5ns - return str; //god bless our ref-counting! => save output string memory consumption! + return str; + static_assert(std::is_same_v&>, "god bless our ref-counting! => save output string memory consumption!"); //Example: const char* decomposed = "\x6f\xcc\x81"; // const char* precomposed = "\xc3\xb3"; diff --git a/zen/zstring.h b/zen/zstring.h index f24e4299..d5d8c588 100644 --- a/zen/zstring.h +++ b/zen/zstring.h @@ -19,8 +19,9 @@ //a high-performance string for interfacing with native OS APIs in multithreaded contexts using Zstring = zen::Zbase; -//for special UI-contexts: guaranteed exponential growth + ref-counting -using Zstringw = zen::Zbase; +//for special UI-contexts: guaranteed exponential growth + ref-counting + COW + no SSO overhead +using Zstringc = zen::Zbase; +//using Zstringw = zen::Zbase; //Caveat: don't expect input/output string sizes to match: @@ -34,7 +35,7 @@ Zstring makeUpperCopy(const Zstring& str); Zstring getUnicodeNormalForm(const Zstring& str); // "In fact, Unicode declares that there is an equivalence relationship between decomposed and composed sequences, // and conformant software should not treat canonically equivalent sequences, whether composed or decomposed or something in between, as different." -// http://www.win.tue.nl/~aeb/linux/uc/nfc_vs_nfd.html +// http://www.win.tue.nl/~aeb/linux/uc/nfc_vs_nfd.html struct LessUnicodeNormal { bool operator()(const Zstring& lhs, const Zstring& rhs) const { return getUnicodeNormalForm(lhs) < getUnicodeNormalForm(rhs);} }; -- cgit