Refactored os.cpp to os_unix.cpp and os_windows.cpp

This commit is contained in:
gabime 2024-01-14 12:09:22 +02:00
parent 3954caccc1
commit 885b796447
9 changed files with 391 additions and 291 deletions

View File

@ -191,11 +191,11 @@ set(SPDLOG_HEADERS
"include/spdlog/details/periodic_worker.h" "include/spdlog/details/periodic_worker.h"
"include/spdlog/details/registry.h" "include/spdlog/details/registry.h"
"include/spdlog/details/synchronous_factory.h" "include/spdlog/details/synchronous_factory.h"
"include/spdlog/details/tcp_client-windows.h"
"include/spdlog/details/tcp_client.h" "include/spdlog/details/tcp_client_unix.h"
"include/spdlog/details/thread_pool.h" "include/spdlog/details/thread_pool.h"
"include/spdlog/details/udp_client-windows.h" "include/spdlog/details/udp_client_windows.h"
"include/spdlog/details/udp_client.h" "include/spdlog/details/udp_client_unix.h"
"include/spdlog/details/windows_include.h" "include/spdlog/details/windows_include.h"
"include/spdlog/fmt/bin_to_hex.h" "include/spdlog/fmt/bin_to_hex.h"
"include/spdlog/fmt/fmt.h" "include/spdlog/fmt/fmt.h"
@ -236,7 +236,6 @@ set(SPDLOG_SRCS
"src/details/file_helper.cpp" "src/details/file_helper.cpp"
"src/details/log_msg.cpp" "src/details/log_msg.cpp"
"src/details/log_msg_buffer.cpp" "src/details/log_msg_buffer.cpp"
"src/details/os.cpp"
"src/details/periodic_worker.cpp" "src/details/periodic_worker.cpp"
"src/details/registry.cpp" "src/details/registry.cpp"
"src/details/thread_pool.cpp" "src/details/thread_pool.cpp"
@ -249,6 +248,15 @@ set(SPDLOG_SRCS
"src/sinks/stdout_sinks.cpp" "src/sinks/stdout_sinks.cpp"
"src/sinks/wincolor_sink.cpp") "src/sinks/wincolor_sink.cpp")
if(WIN32)
list(APPEND SPDLOG_SRCS "src/details/os_windows.cpp")
list(APPEND SPDLOG_HEADERS "include/spdlog/details/tcp_client_windows.h")
list(APPEND SPDLOG_HEADERS "include/spdlog/details/udp_client_windows.h")
else()
list(APPEND SPDLOG_SRCS "src/details/os_unix.cpp")
list(APPEND SPDLOG_HEADERS "include/spdlog/details/tcp_client_unix.h")
list(APPEND SPDLOG_HEADERS "include/spdlog/details/udp_client_unix.h")
endif()
# Generate spdlog_config.h based on the current configuration # Generate spdlog_config.h based on the current configuration
set(OUT_CONFIG_FILE "${CMAKE_CURRENT_SOURCE_DIR}/include/spdlog/spdlog_config.h") set(OUT_CONFIG_FILE "${CMAKE_CURRENT_SOURCE_DIR}/include/spdlog/spdlog_config.h")
message(STATUS "Generating ${OUT_CONFIG_FILE}") message(STATUS "Generating ${OUT_CONFIG_FILE}")
@ -256,7 +264,8 @@ configure_file("${CMAKE_CURRENT_SOURCE_DIR}/cmake/spdlog_config.h.in" ${OUT_CONF
list(APPEND SPDLOG_HEADERS ${OUT_CONFIG_FILE}) list(APPEND SPDLOG_HEADERS ${OUT_CONFIG_FILE})
if(BUILD_SHARED_LIBS) if(BUILD_SHARED_LIBS)
if(WIN32) if(WIN32)
set(VERSION_RC ${CMAKE_CURRENT_BINARY_DIR}/version.rc ) set(VERSION_RC ${CMAKE_CURRENT_BINARY_DIR}/version.rc
src/details/os_unix.cpp)
configure_file(${CMAKE_CURRENT_SOURCE_DIR}/cmake/version.rc.in ${CMAKE_CURRENT_BINARY_DIR}/version.rc @ONLY) configure_file(${CMAKE_CURRENT_SOURCE_DIR}/cmake/version.rc.in ${CMAKE_CURRENT_BINARY_DIR}/version.rc @ONLY)
endif() endif()
add_library(spdlog SHARED ${SPDLOG_SRCS} ${SPDLOG_HEADERS} ${VERSION_RC}) add_library(spdlog SHARED ${SPDLOG_SRCS} ${SPDLOG_HEADERS} ${VERSION_RC})

View File

@ -4,7 +4,7 @@
#pragma once #pragma once
#ifdef _WIN32 #ifdef _WIN32
#error include tcp_client-windows.h instead #error include tcp_client_windows.h instead
#endif #endif
// tcp client helper // tcp client helper
@ -23,7 +23,7 @@
namespace spdlog { namespace spdlog {
namespace details { namespace details {
class tcp_client { class tcp_client_unix {
int socket_ = -1; int socket_ = -1;
public: public:
@ -38,7 +38,7 @@ public:
int fd() const { return socket_; } int fd() const { return socket_; }
~tcp_client() { close(); } ~tcp_client_unix() { close(); }
// try to connect or throw on failure // try to connect or throw on failure
void connect(const std::string &host, int port) { void connect(const std::string &host, int port) {

View File

@ -22,7 +22,7 @@
namespace spdlog { namespace spdlog {
namespace details { namespace details {
class tcp_client { class tcp_client_unix {
SOCKET socket_ = INVALID_SOCKET; SOCKET socket_ = INVALID_SOCKET;
static void init_winsock_() { static void init_winsock_() {
@ -42,9 +42,9 @@ class tcp_client {
} }
public: public:
tcp_client() { init_winsock_(); } tcp_client_unix() { init_winsock_(); }
~tcp_client() { ~tcp_client_unix() {
close(); close();
::WSACleanup(); ::WSACleanup();
} }

View File

@ -10,7 +10,7 @@
#include "./os.h" #include "./os.h"
#ifdef _WIN32 #ifdef _WIN32
#error "include udp_client-windows.h instead" #error "include udp_client_windows.h instead"
#endif #endif
#include <arpa/inet.h> #include <arpa/inet.h>
@ -26,7 +26,7 @@
namespace spdlog { namespace spdlog {
namespace details { namespace details {
class udp_client { class udp_client_unix {
static constexpr int TX_BUFFER_SIZE = 1024 * 10; static constexpr int TX_BUFFER_SIZE = 1024 * 10;
int socket_ = -1; int socket_ = -1;
struct sockaddr_in sockAddr_; struct sockaddr_in sockAddr_;
@ -39,7 +39,7 @@ class udp_client {
} }
public: public:
udp_client(const std::string &host, uint16_t port) { udp_client_unix(const std::string &host, uint16_t port) {
socket_ = ::socket(PF_INET, SOCK_DGRAM, 0); socket_ = ::socket(PF_INET, SOCK_DGRAM, 0);
if (socket_ < 0) { if (socket_ < 0) {
throw_spdlog_ex("error: Create Socket Failed!"); throw_spdlog_ex("error: Create Socket Failed!");
@ -63,7 +63,7 @@ public:
::memset(sockAddr_.sin_zero, 0x00, sizeof(sockAddr_.sin_zero)); ::memset(sockAddr_.sin_zero, 0x00, sizeof(sockAddr_.sin_zero));
} }
~udp_client() { cleanup_(); } ~udp_client_unix() { cleanup_(); }
int fd() const { return socket_; } int fd() const { return socket_; }

View File

@ -25,7 +25,7 @@
namespace spdlog { namespace spdlog {
namespace details { namespace details {
class udp_client { class udp_client_unix {
static constexpr int TX_BUFFER_SIZE = 1024 * 10; static constexpr int TX_BUFFER_SIZE = 1024 * 10;
SOCKET socket_ = INVALID_SOCKET; SOCKET socket_ = INVALID_SOCKET;
sockaddr_in addr_ = {}; sockaddr_in addr_ = {};
@ -55,7 +55,7 @@ class udp_client {
} }
public: public:
udp_client(const std::string &host, uint16_t port) { udp_client_unix(const std::string &host, uint16_t port) {
init_winsock_(); init_winsock_();
addr_.sin_family = PF_INET; addr_.sin_family = PF_INET;
@ -83,7 +83,7 @@ public:
} }
} }
~udp_client() { cleanup_(); } ~udp_client_unix() { cleanup_(); }
SOCKET fd() const { return socket_; } SOCKET fd() const { return socket_; }

View File

@ -9,7 +9,7 @@
#ifdef _WIN32 #ifdef _WIN32
#include "../details/tcp_client-windows.h" #include "../details/tcp_client-windows.h"
#else #else
#include "../details/tcp_client.h" #include "../details/tcp_client_unix.h"
#endif #endif
#include <chrono> #include <chrono>
@ -65,7 +65,7 @@ protected:
void flush_() override {} void flush_() override {}
tcp_sink_config config_; tcp_sink_config config_;
details::tcp_client client_; details::tcp_client_unix client_;
}; };
using tcp_sink_mt = tcp_sink<std::mutex>; using tcp_sink_mt = tcp_sink<std::mutex>;

View File

@ -9,7 +9,7 @@
#ifdef _WIN32 #ifdef _WIN32
#include "../details/udp_client-windows.h" #include "../details/udp_client-windows.h"
#else #else
#include "../details/udp_client.h" #include "../details/udp_client_unix.h"
#endif #endif
#include <chrono> #include <chrono>
@ -49,7 +49,7 @@ protected:
} }
void flush_() override {} void flush_() override {}
details::udp_client client_; details::udp_client_unix client_;
}; };
using udp_sink_mt = udp_sink<std::mutex>; using udp_sink_mt = udp_sink<std::mutex>;

View File

@ -1,9 +1,9 @@
// Copyright(c) 2015-present, Gabi Melman & spdlog contributors. // Copyright(c) 2015-present, Gabi Melman & spdlog contributors.
// Distributed under the MIT License (http://opensource.org/licenses/MIT) // Distributed under the MIT License (http://opensource.org/licenses/MIT)
#include "spdlog/details/os.h" #include <fcntl.h>
#include <sys/stat.h> #include <sys/stat.h>
#include <unistd.h>
#include <algorithm> #include <algorithm>
#include <array> #include <array>
@ -16,29 +16,7 @@
#include <thread> #include <thread>
#include "spdlog/common.h" #include "spdlog/common.h"
#include "spdlog/details/os.h"
// clang-format off
#ifdef _WIN32
#include "spdlog/details/windows_include.h"
#include <fileapi.h> // for FlushFileBuffers
#include <io.h> // for _get_osfhandle, _isatty, _fileno
#include <process.h> // for _get_pid
#ifdef __MINGW32__
#include <share.h>
#endif
#if defined(SPDLOG_WCHAR_FILENAMES)
#include <cassert>
#include <limits>
#endif
#include <direct.h> // for _mkdir/_wmkdir
#else // unix
#include <fcntl.h>
#include <unistd.h>
#ifdef __linux__ #ifdef __linux__
#include <sys/syscall.h> //Use gettid() syscall under linux to get thread id #include <sys/syscall.h> //Use gettid() syscall under linux to get thread id
@ -56,8 +34,6 @@
#include <thread.h> // for thr_self #include <thread.h> // for thr_self
#endif #endif
#endif // _WIN32
#if defined __APPLE__ #if defined __APPLE__
#include <AvailabilityMacros.h> #include <AvailabilityMacros.h>
#endif #endif
@ -84,15 +60,9 @@ spdlog::log_clock::time_point now() noexcept {
#endif #endif
} }
std::tm localtime(const std::time_t &time_tt) noexcept { std::tm localtime(const std::time_t &time_tt) noexcept {
#ifdef _WIN32
std::tm tm;
const auto rv = ::localtime_s(&tm, &time_tt);
return rv == 0 ? tm : std::tm{};
#else
std::tm tm; std::tm tm;
const auto *rv = ::localtime_r(&time_tt, &tm); const auto *rv = ::localtime_r(&time_tt, &tm);
return rv != nullptr ? tm : std::tm{}; return rv != nullptr ? tm : std::tm{};
#endif
} }
std::tm localtime() noexcept { std::tm localtime() noexcept {
@ -101,13 +71,8 @@ std::tm localtime() noexcept {
} }
std::tm gmtime(const std::time_t &time_tt) noexcept { std::tm gmtime(const std::time_t &time_tt) noexcept {
#ifdef _WIN32
std::tm tm;
::gmtime_s(&tm, &time_tt);
#else
std::tm tm; std::tm tm;
::gmtime_r(&time_tt, &tm); ::gmtime_r(&time_tt, &tm);
#endif
return tm; return tm;
} }
@ -118,22 +83,6 @@ std::tm gmtime() noexcept {
// fopen_s on non windows for writing // fopen_s on non windows for writing
bool fopen_s(FILE **fp, const filename_t &filename, const filename_t &mode) { bool fopen_s(FILE **fp, const filename_t &filename, const filename_t &mode) {
#ifdef _WIN32
#ifdef SPDLOG_WCHAR_FILENAMES
*fp = ::_wfsopen((filename.c_str()), mode.c_str(), _SH_DENYNO);
#else
*fp = ::_fsopen((filename.c_str()), mode.c_str(), _SH_DENYNO);
#endif
#if defined(SPDLOG_PREVENT_CHILD_FD)
if (*fp != nullptr) {
auto file_handle = reinterpret_cast<HANDLE>(_get_osfhandle(::_fileno(*fp)));
if (!::SetHandleInformation(file_handle, HANDLE_FLAG_INHERIT, 0)) {
::fclose(*fp);
*fp = nullptr;
}
}
#endif
#else // unix
#if defined(SPDLOG_PREVENT_CHILD_FD) #if defined(SPDLOG_PREVENT_CHILD_FD)
const int mode_flag = mode == SPDLOG_FILENAME_T("ab") ? O_APPEND : O_TRUNC; const int mode_flag = mode == SPDLOG_FILENAME_T("ab") ? O_APPEND : O_TRUNC;
const int fd = ::open((filename.c_str()), O_CREAT | O_WRONLY | O_CLOEXEC | mode_flag, mode_t(0644)); const int fd = ::open((filename.c_str()), O_CREAT | O_WRONLY | O_CLOEXEC | mode_flag, mode_t(0644));
@ -147,71 +96,29 @@ bool fopen_s(FILE **fp, const filename_t &filename, const filename_t &mode) {
#else #else
*fp = ::fopen((filename.c_str()), mode.c_str()); *fp = ::fopen((filename.c_str()), mode.c_str());
#endif #endif
#endif
return *fp == nullptr; return *fp == nullptr;
} }
int remove(const filename_t &filename) noexcept { int remove(const filename_t &filename) noexcept { return std::remove(filename.c_str()); }
#if defined(_WIN32) && defined(SPDLOG_WCHAR_FILENAMES)
return ::_wremove(filename.c_str());
#else
return std::remove(filename.c_str());
#endif
}
int remove_if_exists(const filename_t &filename) noexcept { return path_exists(filename) ? remove(filename) : 0; } int remove_if_exists(const filename_t &filename) noexcept { return path_exists(filename) ? remove(filename) : 0; }
int rename(const filename_t &filename1, const filename_t &filename2) noexcept { int rename(const filename_t &filename1, const filename_t &filename2) noexcept {
#if defined(_WIN32) && defined(SPDLOG_WCHAR_FILENAMES)
return ::_wrename(filename1.c_str(), filename2.c_str());
#else
return std::rename(filename1.c_str(), filename2.c_str()); return std::rename(filename1.c_str(), filename2.c_str());
#endif
} }
// Return true if path exists (file or directory) // Return true if path exists (file or directory)
bool path_exists(const filename_t &filename) noexcept { bool path_exists(const filename_t &filename) noexcept {
#ifdef _WIN32
#ifdef SPDLOG_WCHAR_FILENAMES
auto attribs = ::GetFileAttributesW(filename.c_str());
#else
auto attribs = ::GetFileAttributesA(filename.c_str());
#endif
return attribs != INVALID_FILE_ATTRIBUTES;
#else // common linux/unix all have the stat system call
struct stat buffer; struct stat buffer;
return (::stat(filename.c_str(), &buffer) == 0); return (::stat(filename.c_str(), &buffer) == 0);
#endif
} }
#ifdef _MSC_VER
// avoid warning about unreachable statement at the end of filesize()
#pragma warning(push)
#pragma warning(disable : 4702)
#endif
// Return file size according to open FILE* object // Return file size according to open FILE* object
size_t filesize(FILE *f) { size_t filesize(FILE *f) {
if (f == nullptr) { if (f == nullptr) {
throw_spdlog_ex("Failed getting file size. fd is null"); throw_spdlog_ex("Failed getting file size. fd is null");
} }
#if defined(_WIN32) && !defined(__CYGWIN__)
int fd = ::_fileno(f);
#if defined(_WIN64) // 64 bits
__int64 ret = ::_filelengthi64(fd);
if (ret >= 0) {
return static_cast<size_t>(ret);
}
#else // windows 32 bits
long ret = ::_filelength(fd);
if (ret >= 0) {
return static_cast<size_t>(ret);
}
#endif
#else // unix
// OpenBSD and AIX doesn't compile with :: before the fileno(..) // OpenBSD and AIX doesn't compile with :: before the fileno(..)
#if defined(__OpenBSD__) || defined(_AIX) #if defined(__OpenBSD__) || defined(_AIX)
int fd = fileno(f); int fd = fileno(f);
@ -230,36 +137,12 @@ size_t filesize(FILE *f) {
return static_cast<size_t>(st.st_size); return static_cast<size_t>(st.st_size);
} }
#endif #endif
#endif
throw_spdlog_ex("Failed getting file size from fd", errno); throw_spdlog_ex("Failed getting file size from fd", errno);
return 0; // will not be reached. return 0; // will not be reached.
} }
#ifdef _MSC_VER
#pragma warning(pop)
#endif
// Return utc offset in minutes or throw spdlog_ex on failure // Return utc offset in minutes or throw spdlog_ex on failure
int utc_minutes_offset(const std::tm &tm) { int utc_minutes_offset(const std::tm &tm) {
#ifdef _WIN32
#if _WIN32_WINNT < _WIN32_WINNT_WS08
TIME_ZONE_INFORMATION tzinfo;
auto rv = ::GetTimeZoneInformation(&tzinfo);
#else
DYNAMIC_TIME_ZONE_INFORMATION tzinfo;
auto rv = ::GetDynamicTimeZoneInformation(&tzinfo);
#endif
if (rv == TIME_ZONE_ID_INVALID) throw_spdlog_ex("Failed getting timezone info. ", errno);
int offset = -tzinfo.Bias;
if (tm.tm_isdst) {
offset -= tzinfo.DaylightBias;
} else {
offset -= tzinfo.StandardBias;
}
return offset;
#else
#if defined(sun) || defined(__sun) || defined(_AIX) || (defined(__NEWLIB__) && !defined(__TM_GMTOFF)) || \ #if defined(sun) || defined(__sun) || defined(_AIX) || (defined(__NEWLIB__) && !defined(__TM_GMTOFF)) || \
(!defined(_BSD_SOURCE) && !defined(_GNU_SOURCE)) (!defined(_BSD_SOURCE) && !defined(_GNU_SOURCE))
// 'tm_gmtoff' field is BSD extension and it's missing on SunOS/Solaris // 'tm_gmtoff' field is BSD extension and it's missing on SunOS/Solaris
@ -293,18 +176,14 @@ int utc_minutes_offset(const std::tm &tm) {
#else #else
auto offset_seconds = tm.tm_gmtoff; auto offset_seconds = tm.tm_gmtoff;
#endif #endif
return static_cast<int>(offset_seconds / 60); return static_cast<int>(offset_seconds / 60);
#endif
} }
// Return current thread id as size_t // Return current thread id as size_t
// It exists because the std::this_thread::get_id() is much slower(especially // It exists because the std::this_thread::get_id() is much slower(especially
// under VS 2013) // under VS 2013)
size_t _thread_id() noexcept { size_t _thread_id() noexcept {
#ifdef _WIN32 #if defined(__linux__)
return static_cast<size_t>(::GetCurrentThreadId());
#elif defined(__linux__)
#if defined(__ANDROID__) && defined(__ANDROID_API__) && (__ANDROID_API__ < 21) #if defined(__ANDROID__) && defined(__ANDROID_API__) && (__ANDROID_API__ < 21)
#define SYS_gettid __NR_gettid #define SYS_gettid __NR_gettid
#endif #endif
@ -358,42 +237,17 @@ size_t thread_id() noexcept {
return tid; return tid;
} }
// This is avoid msvc issue in sleep_for that happens if the clock changes.
// See https://github.com/gabime/spdlog/issues/609
void sleep_for_millis(unsigned int milliseconds) noexcept { void sleep_for_millis(unsigned int milliseconds) noexcept {
#if defined(_WIN32)
::Sleep(milliseconds);
#else
std::this_thread::sleep_for(std::chrono::milliseconds(milliseconds)); std::this_thread::sleep_for(std::chrono::milliseconds(milliseconds));
#endif
} }
// wchar support for windows file names (SPDLOG_WCHAR_FILENAMES must be defined)
#if defined(_WIN32) && defined(SPDLOG_WCHAR_FILENAMES)
std::string filename_to_str(const filename_t &filename) {
memory_buf_t buf;
wstr_to_utf8buf(filename, buf);
return SPDLOG_BUF_TO_STRING(buf);
}
#else
std::string filename_to_str(const filename_t &filename) { return filename; } std::string filename_to_str(const filename_t &filename) { return filename; }
#endif
int pid() noexcept { int pid() noexcept { return static_cast<int>(::getpid()); }
#ifdef _WIN32
return static_cast<int>(::GetCurrentProcessId());
#else
return static_cast<int>(::getpid());
#endif
}
// Determine if the terminal supports colors // Determine if the terminal supports colors
// Based on: https://github.com/agauniyal/rang/ // Based on: https://github.com/agauniyal/rang/
bool is_color_terminal() noexcept { bool is_color_terminal() noexcept {
#ifdef _WIN32
return true;
#else
static const bool result = []() { static const bool result = []() {
const char *env_colorterm_p = std::getenv("COLORTERM"); const char *env_colorterm_p = std::getenv("COLORTERM");
if (env_colorterm_p != nullptr) { if (env_colorterm_p != nullptr) {
@ -414,88 +268,14 @@ bool is_color_terminal() noexcept {
}(); }();
return result; return result;
#endif
} }
// Determine if the terminal attached // Determine if the terminal attached
// Source: https://github.com/agauniyal/rang/ // Source: https://github.com/agauniyal/rang/
bool in_terminal(FILE *file) noexcept { bool in_terminal(FILE *file) noexcept { return ::isatty(fileno(file)) != 0; }
#ifdef _WIN32
return ::_isatty(_fileno(file)) != 0;
#else
return ::isatty(fileno(file)) != 0;
#endif
}
#if defined(SPDLOG_WCHAR_FILENAMES) && defined(_WIN32)
void wstr_to_utf8buf(wstring_view_t wstr, memory_buf_t &target) {
if (wstr.size() > static_cast<size_t>((std::numeric_limits<int>::max)()) / 2 - 1) {
throw_spdlog_ex("UTF-16 string is too big to be converted to UTF-8");
}
int wstr_size = static_cast<int>(wstr.size());
if (wstr_size == 0) {
target.resize(0);
return;
}
int result_size = static_cast<int>(target.capacity());
if ((wstr_size + 1) * 2 > result_size) {
result_size = ::WideCharToMultiByte(CP_UTF8, 0, wstr.data(), wstr_size, NULL, 0, NULL, NULL);
}
if (result_size > 0) {
target.resize(result_size);
result_size = ::WideCharToMultiByte(CP_UTF8, 0, wstr.data(), wstr_size, target.data(), result_size, NULL, NULL);
if (result_size > 0) {
target.resize(result_size);
return;
}
}
throw_spdlog_ex(fmt_lib::format("WideCharToMultiByte failed. Last error: {}", ::GetLastError()));
}
void utf8_to_wstrbuf(string_view_t str, wmemory_buf_t &target) {
if (str.size() > static_cast<size_t>((std::numeric_limits<int>::max)()) - 1) {
throw_spdlog_ex("UTF-8 string is too big to be converted to UTF-16");
}
int str_size = static_cast<int>(str.size());
if (str_size == 0) {
target.resize(0);
return;
}
// find the size to allocate for the result buffer
int result_size = ::MultiByteToWideChar(CP_UTF8, MB_ERR_INVALID_CHARS, str.data(), str_size, NULL, 0);
if (result_size > 0) {
target.resize(result_size);
result_size = ::MultiByteToWideChar(CP_UTF8, MB_ERR_INVALID_CHARS, str.data(), str_size, target.data(), result_size);
if (result_size > 0) {
assert(result_size == target.size());
return;
}
}
throw_spdlog_ex(fmt_lib::format("MultiByteToWideChar failed. Last error: {}", ::GetLastError()));
}
#endif // defined(SPDLOG_WCHAR_FILENAMES) && defined(_WIN32)
// return true on success // return true on success
static bool mkdir_(const filename_t &path) { static bool mkdir_(const filename_t &path) { return ::mkdir(path.c_str(), mode_t(0755)) == 0; }
#ifdef _WIN32
#ifdef SPDLOG_WCHAR_FILENAMES
return ::_wmkdir(path.c_str()) == 0;
#else
return ::_mkdir(path.c_str()) == 0;
#endif
#else
return ::mkdir(path.c_str(), mode_t(0755)) == 0;
#endif
}
// create the given directory - and all directories leading to it // create the given directory - and all directories leading to it
// return true on success or if the directory already exists // return true on success or if the directory already exists
@ -538,30 +318,13 @@ filename_t dir_name(const filename_t &path) {
} }
std::string getenv(const char *field) { std::string getenv(const char *field) {
#if defined(_MSC_VER)
#if defined(__cplusplus_winrt)
return std::string{}; // not supported under uwp
#else
size_t len = 0;
char buf[128];
bool ok = ::getenv_s(&len, buf, sizeof(buf), field) == 0;
return ok ? buf : std::string{};
#endif
#else // revert to getenv
char *buf = ::getenv(field); char *buf = ::getenv(field);
return buf != nullptr ? buf : std::string{}; return buf != nullptr ? buf : std::string{};
#endif
} }
// Do fsync by FILE handlerpointer // Do fsync by FILE handlerpointer
// Return true on success // Return true on success
bool fsync(FILE *fp) { bool fsync(FILE *fp) { return ::fsync(fileno(fp)) == 0; }
#ifdef _WIN32
return FlushFileBuffers(reinterpret_cast<HANDLE>(_get_osfhandle(_fileno(fp)))) != 0;
#else
return ::fsync(fileno(fp)) == 0;
#endif
}
} // namespace os } // namespace os
} // namespace details } // namespace details

328
src/details/os_windows.cpp Normal file
View File

@ -0,0 +1,328 @@
// Copyright(c) 2015-present, Gabi Melman & spdlog contributors.
// Distributed under the MIT License (http://opensource.org/licenses/MIT)
#ifndef _WIN32
#error "_WIN32 only source file"
#endif
#include <fileapi.h> // for FlushFileBuffers
#include <io.h> // for _get_osfhandle, _isatty, _fileno
#include <process.h> // for _get_pid
#include <sys/stat.h>
#include <algorithm>
#include <array>
#include <chrono>
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <ctime>
#include <string>
#include <thread>
#include "spdlog/common.h"
#include "spdlog/details/os.h"
#include "spdlog/details/windows_include.h"
#ifdef __MINGW32__
#include <share.h>
#endif
#if defined(SPDLOG_WCHAR_FILENAMES)
#include <cassert>
#include <limits>
#endif
#include <direct.h> // for _mkdir/_wmkdir
// clang-format on
namespace spdlog {
namespace details {
namespace os {
spdlog::log_clock::time_point now() noexcept { return log_clock::now(); }
std::tm localtime(const std::time_t &time_tt) noexcept {
std::tm tm;
const auto rv = ::localtime_s(&tm, &time_tt);
return rv == 0 ? tm : std::tm{};
}
std::tm localtime() noexcept {
std::time_t now_t = ::time(nullptr);
return localtime(now_t);
}
std::tm gmtime(const std::time_t &time_tt) noexcept {
std::tm tm;
::gmtime_s(&tm, &time_tt);
return tm;
}
std::tm gmtime() noexcept {
std::time_t now_t = ::time(nullptr);
return gmtime(now_t);
}
bool fopen_s(FILE **fp, const filename_t &filename, const filename_t &mode) {
#ifdef SPDLOG_WCHAR_FILENAMES
*fp = ::_wfsopen((filename.c_str()), mode.c_str(), _SH_DENYNO);
#else
*fp = ::_fsopen((filename.c_str()), mode.c_str(), _SH_DENYNO);
#endif
#if defined(SPDLOG_PREVENT_CHILD_FD)
if (*fp != nullptr) {
auto file_handle = reinterpret_cast<HANDLE>(_get_osfhandle(::_fileno(*fp)));
if (!::SetHandleInformation(file_handle, HANDLE_FLAG_INHERIT, 0)) {
::fclose(*fp);
*fp = nullptr;
}
}
#endif
return *fp == nullptr;
}
int remove(const filename_t &filename) noexcept {
#if defined(SPDLOG_WCHAR_FILENAMES)
return ::_wremove(filename.c_str());
#else
return std::remove(filename.c_str());
#endif
}
int remove_if_exists(const filename_t &filename) noexcept { return path_exists(filename) ? remove(filename) : 0; }
int rename(const filename_t &filename1, const filename_t &filename2) noexcept {
#if defined(SPDLOG_WCHAR_FILENAMES)
return ::_wrename(filename1.c_str(), filename2.c_str());
#else
return std::rename(filename1.c_str(), filename2.c_str());
#endif
}
// Return true if path exists (file or directory)
bool path_exists(const filename_t &filename) noexcept {
#ifdef SPDLOG_WCHAR_FILENAMES
auto attribs = ::GetFileAttributesW(filename.c_str());
#else
auto attribs = ::GetFileAttributesA(filename.c_str());
#endif
return attribs != INVALID_FILE_ATTRIBUTES;
}
#ifdef _MSC_VER
// avoid warning about unreachable statement at the end of filesize()
#pragma warning(push)
#pragma warning(disable : 4702)
#endif
// Return file size according to open FILE* object
size_t filesize(FILE *f) {
if (f == nullptr) {
throw_spdlog_ex("Failed getting file size. fd is null");
}
int fd = ::_fileno(f);
#if defined(_WIN64) // 64 bits
__int64 ret = ::_filelengthi64(fd);
if (ret >= 0) {
return static_cast<size_t>(ret);
}
#else // windows 32 bits
long ret = ::_filelength(fd);
if (ret >= 0) {
return static_cast<size_t>(ret);
}
#endif
throw_spdlog_ex("Failed getting file size from fd", errno);
return 0; // will not be reached.
}
#ifdef _MSC_VER
#pragma warning(pop)
#endif
// Return utc offset in minutes or throw spdlog_ex on failure
int utc_minutes_offset(const std::tm &tm) {
#if _WIN32_WINNT < _WIN32_WINNT_WS08
TIME_ZONE_INFORMATION tzinfo;
auto rv = ::GetTimeZoneInformation(&tzinfo);
#else
DYNAMIC_TIME_ZONE_INFORMATION tzinfo;
auto rv = ::GetDynamicTimeZoneInformation(&tzinfo);
#endif
if (rv == TIME_ZONE_ID_INVALID) throw_spdlog_ex("Failed getting timezone info. ", errno);
int offset = -tzinfo.Bias;
if (tm.tm_isdst) {
offset -= tzinfo.DaylightBias;
} else {
offset -= tzinfo.StandardBias;
}
return offset;
}
// Return current thread id as size_t
// It exists because the std::this_thread::get_id() is much slower(especially
// under VS 2013)
size_t _thread_id() noexcept { return static_cast<size_t>(::GetCurrentThreadId()); }
// Return current thread id as size_t (from thread local storage)
size_t thread_id() noexcept {
// cache thread id in tls
static thread_local const size_t tid = _thread_id();
return tid;
}
// This is avoid msvc issue in sleep_for that happens if the clock changes.
// See https://github.com/gabime/spdlog/issues/609
void sleep_for_millis(unsigned int milliseconds) noexcept { ::Sleep(milliseconds); }
// wchar support for windows file names (SPDLOG_WCHAR_FILENAMES must be defined)
#if defined(SPDLOG_WCHAR_FILENAMES)
std::string filename_to_str(const filename_t &filename) {
memory_buf_t buf;
wstr_to_utf8buf(filename, buf);
return SPDLOG_BUF_TO_STRING(buf);
}
#else
std::string filename_to_str(const filename_t &filename) { return filename; }
#endif
int pid() noexcept { return static_cast<int>(::GetCurrentProcessId()); }
bool is_color_terminal() noexcept { return true; }
// Determine if the terminal attached
bool in_terminal(FILE *file) noexcept { return ::_isatty(_fileno(file)) != 0; }
#if defined(SPDLOG_WCHAR_FILENAMES)
void wstr_to_utf8buf(wstring_view_t wstr, memory_buf_t &target) {
if (wstr.size() > static_cast<size_t>((std::numeric_limits<int>::max)()) / 2 - 1) {
throw_spdlog_ex("UTF-16 string is too big to be converted to UTF-8");
}
int wstr_size = static_cast<int>(wstr.size());
if (wstr_size == 0) {
target.resize(0);
return;
}
int result_size = static_cast<int>(target.capacity());
if ((wstr_size + 1) * 2 > result_size) {
result_size = ::WideCharToMultiByte(CP_UTF8, 0, wstr.data(), wstr_size, NULL, 0, NULL, NULL);
}
if (result_size > 0) {
target.resize(result_size);
result_size = ::WideCharToMultiByte(CP_UTF8, 0, wstr.data(), wstr_size, target.data(), result_size, NULL, NULL);
if (result_size > 0) {
target.resize(result_size);
return;
}
}
throw_spdlog_ex(fmt_lib::format("WideCharToMultiByte failed. Last error: {}", ::GetLastError()));
}
void utf8_to_wstrbuf(string_view_t str, wmemory_buf_t &target) {
if (str.size() > static_cast<size_t>((std::numeric_limits<int>::max)()) - 1) {
throw_spdlog_ex("UTF-8 string is too big to be converted to UTF-16");
}
int str_size = static_cast<int>(str.size());
if (str_size == 0) {
target.resize(0);
return;
}
// find the size to allocate for the result buffer
int result_size = ::MultiByteToWideChar(CP_UTF8, MB_ERR_INVALID_CHARS, str.data(), str_size, NULL, 0);
if (result_size > 0) {
target.resize(result_size);
result_size = ::MultiByteToWideChar(CP_UTF8, MB_ERR_INVALID_CHARS, str.data(), str_size, target.data(), result_size);
if (result_size > 0) {
assert(result_size == target.size());
return;
}
}
throw_spdlog_ex(fmt_lib::format("MultiByteToWideChar failed. Last error: {}", ::GetLastError()));
}
#endif // defined(SPDLOG_WCHAR_FILENAMES)
// return true on success
static bool mkdir_(const filename_t &path) {
#
#ifdef SPDLOG_WCHAR_FILENAMES
return ::_wmkdir(path.c_str()) == 0;
#else
return ::_mkdir(path.c_str()) == 0;
#endif
}
// create the given directory - and all directories leading to it
// return true on success or if the directory already exists
bool create_dir(const filename_t &path) {
if (path_exists(path)) {
return true;
}
if (path.empty()) {
return false;
}
size_t search_offset = 0;
do {
auto token_pos = path.find_first_of(folder_seps_filename, search_offset);
// treat the entire path as a folder if no folder separator not found
if (token_pos == filename_t::npos) {
token_pos = path.size();
}
auto subdir = path.substr(0, token_pos);
if (!subdir.empty() && !path_exists(subdir) && !mkdir_(subdir)) {
return false; // return error if failed creating dir
}
search_offset = token_pos + 1;
} while (search_offset < path.size());
return true;
}
// Return directory name from given path or empty string
// "abc/file" => "abc"
// "abc/" => "abc"
// "abc" => ""
// "abc///" => "abc//"
filename_t dir_name(const filename_t &path) {
auto pos = path.find_last_of(folder_seps_filename);
return pos != filename_t::npos ? path.substr(0, pos) : filename_t{};
}
std::string getenv(const char *field) {
#if defined(_MSC_VER)
#if defined(__cplusplus_winrt)
return std::string{}; // not supported under uwp
#else
size_t len = 0;
char buf[128];
bool ok = ::getenv_s(&len, buf, sizeof(buf), field) == 0;
return ok ? buf : std::string{};
#endif
#else // revert to getenv
char *buf = ::getenv(field);
return buf != nullptr ? buf : std::string{};
#endif
}
// Do fsync by FILE handlerpointer
// Return true on success
bool fsync(FILE *fp) { return FlushFileBuffers(reinterpret_cast<HANDLE>(_get_osfhandle(_fileno(fp)))) != 0; }
} // namespace os
} // namespace details
} // namespace spdlog