File indexing completed on 2025-01-18 10:12:41
0001
0002
0003
0004 #pragma once
0005
0006 #ifndef SPDLOG_HEADER_ONLY
0007 # include <spdlog/details/os.h>
0008 #endif
0009
0010 #include <spdlog/common.h>
0011
0012 #include <algorithm>
0013 #include <chrono>
0014 #include <cstdio>
0015 #include <cstdlib>
0016 #include <cstring>
0017 #include <ctime>
0018 #include <string>
0019 #include <thread>
0020 #include <array>
0021 #include <sys/stat.h>
0022 #include <sys/types.h>
0023
0024 #ifdef _WIN32
0025
0026 # include <io.h> // _get_osfhandle and _isatty support
0027 # include <process.h> // _get_pid support
0028 # include <spdlog/details/windows_include.h>
0029
0030 # ifdef __MINGW32__
0031 # include <share.h>
0032 # endif
0033
0034 # if defined(SPDLOG_WCHAR_TO_UTF8_SUPPORT) || defined(SPDLOG_WCHAR_FILENAMES)
0035 # include <limits>
0036 # endif
0037
0038 # include <direct.h> // for _mkdir/_wmkdir
0039
0040 #else
0041
0042 # include <fcntl.h>
0043 # include <unistd.h>
0044
0045 # ifdef __linux__
0046 # include <sys/syscall.h> //Use gettid() syscall under linux to get thread id
0047
0048 # elif defined(_AIX)
0049 # include <pthread.h> // for pthread_getthrds_np
0050
0051 # elif defined(__DragonFly__) || defined(__FreeBSD__)
0052 # include <pthread_np.h> // for pthread_getthreadid_np
0053
0054 # elif defined(__NetBSD__)
0055 # include <lwp.h> // for _lwp_self
0056
0057 # elif defined(__sun)
0058 # include <thread.h> // for thr_self
0059 # endif
0060
0061 #endif
0062
0063 #ifndef __has_feature
0064 # define __has_feature(x) 0
0065 #endif
0066
0067 namespace spdlog {
0068 namespace details {
0069 namespace os {
0070
0071 SPDLOG_INLINE spdlog::log_clock::time_point now() SPDLOG_NOEXCEPT
0072 {
0073
0074 #if defined __linux__ && defined SPDLOG_CLOCK_COARSE
0075 timespec ts;
0076 ::clock_gettime(CLOCK_REALTIME_COARSE, &ts);
0077 return std::chrono::time_point<log_clock, typename log_clock::duration>(
0078 std::chrono::duration_cast<typename log_clock::duration>(std::chrono::seconds(ts.tv_sec) + std::chrono::nanoseconds(ts.tv_nsec)));
0079
0080 #else
0081 return log_clock::now();
0082 #endif
0083 }
0084 SPDLOG_INLINE std::tm localtime(const std::time_t &time_tt) SPDLOG_NOEXCEPT
0085 {
0086
0087 #ifdef _WIN32
0088 std::tm tm;
0089 ::localtime_s(&tm, &time_tt);
0090 #else
0091 std::tm tm;
0092 ::localtime_r(&time_tt, &tm);
0093 #endif
0094 return tm;
0095 }
0096
0097 SPDLOG_INLINE std::tm localtime() SPDLOG_NOEXCEPT
0098 {
0099 std::time_t now_t = ::time(nullptr);
0100 return localtime(now_t);
0101 }
0102
0103 SPDLOG_INLINE std::tm gmtime(const std::time_t &time_tt) SPDLOG_NOEXCEPT
0104 {
0105
0106 #ifdef _WIN32
0107 std::tm tm;
0108 ::gmtime_s(&tm, &time_tt);
0109 #else
0110 std::tm tm;
0111 ::gmtime_r(&time_tt, &tm);
0112 #endif
0113 return tm;
0114 }
0115
0116 SPDLOG_INLINE std::tm gmtime() SPDLOG_NOEXCEPT
0117 {
0118 std::time_t now_t = ::time(nullptr);
0119 return gmtime(now_t);
0120 }
0121
0122
0123 SPDLOG_INLINE bool fopen_s(FILE **fp, const filename_t &filename, const filename_t &mode)
0124 {
0125 #ifdef _WIN32
0126 # ifdef SPDLOG_WCHAR_FILENAMES
0127 *fp = ::_wfsopen((filename.c_str()), mode.c_str(), _SH_DENYNO);
0128 # else
0129 *fp = ::_fsopen((filename.c_str()), mode.c_str(), _SH_DENYNO);
0130 # endif
0131 # if defined(SPDLOG_PREVENT_CHILD_FD)
0132 if (*fp != nullptr)
0133 {
0134 auto file_handle = reinterpret_cast<HANDLE>(_get_osfhandle(::_fileno(*fp)));
0135 if (!::SetHandleInformation(file_handle, HANDLE_FLAG_INHERIT, 0))
0136 {
0137 ::fclose(*fp);
0138 *fp = nullptr;
0139 }
0140 }
0141 # endif
0142 #else
0143 # if defined(SPDLOG_PREVENT_CHILD_FD)
0144 const int mode_flag = mode == SPDLOG_FILENAME_T("ab") ? O_APPEND : O_TRUNC;
0145 const int fd = ::open((filename.c_str()), O_CREAT | O_WRONLY | O_CLOEXEC | mode_flag, mode_t(0644));
0146 if (fd == -1)
0147 {
0148 return true;
0149 }
0150 *fp = ::fdopen(fd, mode.c_str());
0151 if (*fp == nullptr)
0152 {
0153 ::close(fd);
0154 }
0155 # else
0156 *fp = ::fopen((filename.c_str()), mode.c_str());
0157 # endif
0158 #endif
0159
0160 return *fp == nullptr;
0161 }
0162
0163 SPDLOG_INLINE int remove(const filename_t &filename) SPDLOG_NOEXCEPT
0164 {
0165 #if defined(_WIN32) && defined(SPDLOG_WCHAR_FILENAMES)
0166 return ::_wremove(filename.c_str());
0167 #else
0168 return std::remove(filename.c_str());
0169 #endif
0170 }
0171
0172 SPDLOG_INLINE int remove_if_exists(const filename_t &filename) SPDLOG_NOEXCEPT
0173 {
0174 return path_exists(filename) ? remove(filename) : 0;
0175 }
0176
0177 SPDLOG_INLINE int rename(const filename_t &filename1, const filename_t &filename2) SPDLOG_NOEXCEPT
0178 {
0179 #if defined(_WIN32) && defined(SPDLOG_WCHAR_FILENAMES)
0180 return ::_wrename(filename1.c_str(), filename2.c_str());
0181 #else
0182 return std::rename(filename1.c_str(), filename2.c_str());
0183 #endif
0184 }
0185
0186
0187 SPDLOG_INLINE bool path_exists(const filename_t &filename) SPDLOG_NOEXCEPT
0188 {
0189 #ifdef _WIN32
0190 # ifdef SPDLOG_WCHAR_FILENAMES
0191 auto attribs = ::GetFileAttributesW(filename.c_str());
0192 # else
0193 auto attribs = ::GetFileAttributesA(filename.c_str());
0194 # endif
0195 return attribs != INVALID_FILE_ATTRIBUTES;
0196 #else
0197 struct stat buffer;
0198 return (::stat(filename.c_str(), &buffer) == 0);
0199 #endif
0200 }
0201
0202 #ifdef _MSC_VER
0203
0204 # pragma warning(push)
0205 # pragma warning(disable : 4702)
0206 #endif
0207
0208
0209 SPDLOG_INLINE size_t filesize(FILE *f)
0210 {
0211 if (f == nullptr)
0212 {
0213 throw_spdlog_ex("Failed getting file size. fd is null");
0214 }
0215 #if defined(_WIN32) && !defined(__CYGWIN__)
0216 int fd = ::_fileno(f);
0217 # if defined(_WIN64)
0218 __int64 ret = ::_filelengthi64(fd);
0219 if (ret >= 0)
0220 {
0221 return static_cast<size_t>(ret);
0222 }
0223
0224 # else
0225 long ret = ::_filelength(fd);
0226 if (ret >= 0)
0227 {
0228 return static_cast<size_t>(ret);
0229 }
0230 # endif
0231
0232 #else
0233
0234 # if defined(__OpenBSD__) || defined(_AIX)
0235 int fd = fileno(f);
0236 # else
0237 int fd = ::fileno(f);
0238 # endif
0239
0240 # if (defined(__linux__) || defined(__sun) || defined(_AIX)) && (defined(__LP64__) || defined(_LP64))
0241 struct stat64 st;
0242 if (::fstat64(fd, &st) == 0)
0243 {
0244 return static_cast<size_t>(st.st_size);
0245 }
0246 # else
0247 struct stat st;
0248 if (::fstat(fd, &st) == 0)
0249 {
0250 return static_cast<size_t>(st.st_size);
0251 }
0252 # endif
0253 #endif
0254 throw_spdlog_ex("Failed getting file size from fd", errno);
0255 return 0;
0256 }
0257
0258 #ifdef _MSC_VER
0259 # pragma warning(pop)
0260 #endif
0261
0262
0263 SPDLOG_INLINE int utc_minutes_offset(const std::tm &tm)
0264 {
0265
0266 #ifdef _WIN32
0267 # if _WIN32_WINNT < _WIN32_WINNT_WS08
0268 TIME_ZONE_INFORMATION tzinfo;
0269 auto rv = ::GetTimeZoneInformation(&tzinfo);
0270 # else
0271 DYNAMIC_TIME_ZONE_INFORMATION tzinfo;
0272 auto rv = ::GetDynamicTimeZoneInformation(&tzinfo);
0273 # endif
0274 if (rv == TIME_ZONE_ID_INVALID)
0275 throw_spdlog_ex("Failed getting timezone info. ", errno);
0276
0277 int offset = -tzinfo.Bias;
0278 if (tm.tm_isdst)
0279 {
0280 offset -= tzinfo.DaylightBias;
0281 }
0282 else
0283 {
0284 offset -= tzinfo.StandardBias;
0285 }
0286 return offset;
0287 #else
0288
0289 # if defined(sun) || defined(__sun) || defined(_AIX) || (!defined(_BSD_SOURCE) && !defined(_GNU_SOURCE))
0290
0291 struct helper
0292 {
0293 static long int calculate_gmt_offset(const std::tm &localtm = details::os::localtime(), const std::tm &gmtm = details::os::gmtime())
0294 {
0295 int local_year = localtm.tm_year + (1900 - 1);
0296 int gmt_year = gmtm.tm_year + (1900 - 1);
0297
0298 long int days = (
0299
0300 localtm.tm_yday -
0301 gmtm.tm_yday
0302
0303
0304 + ((local_year >> 2) - (gmt_year >> 2)) - (local_year / 100 - gmt_year / 100) +
0305 ((local_year / 100 >> 2) - (gmt_year / 100 >> 2))
0306
0307
0308 + static_cast<long int>(local_year - gmt_year) * 365);
0309
0310 long int hours = (24 * days) + (localtm.tm_hour - gmtm.tm_hour);
0311 long int mins = (60 * hours) + (localtm.tm_min - gmtm.tm_min);
0312 long int secs = (60 * mins) + (localtm.tm_sec - gmtm.tm_sec);
0313
0314 return secs;
0315 }
0316 };
0317
0318 auto offset_seconds = helper::calculate_gmt_offset(tm);
0319 # else
0320 auto offset_seconds = tm.tm_gmtoff;
0321 # endif
0322
0323 return static_cast<int>(offset_seconds / 60);
0324 #endif
0325 }
0326
0327
0328
0329
0330 SPDLOG_INLINE size_t _thread_id() SPDLOG_NOEXCEPT
0331 {
0332 #ifdef _WIN32
0333 return static_cast<size_t>(::GetCurrentThreadId());
0334 #elif defined(__linux__)
0335 # if defined(__ANDROID__) && defined(__ANDROID_API__) && (__ANDROID_API__ < 21)
0336 # define SYS_gettid __NR_gettid
0337 # endif
0338 return static_cast<size_t>(::syscall(SYS_gettid));
0339 #elif defined(_AIX)
0340 struct __pthrdsinfo buf;
0341 int reg_size = 0;
0342 pthread_t pt = pthread_self();
0343 int retval = pthread_getthrds_np(&pt, PTHRDSINFO_QUERY_TID, &buf, sizeof(buf), NULL, ®_size);
0344 int tid = (!retval) ? buf.__pi_tid : 0;
0345 return static_cast<size_t>(tid);
0346 #elif defined(__DragonFly__) || defined(__FreeBSD__)
0347 return static_cast<size_t>(::pthread_getthreadid_np());
0348 #elif defined(__NetBSD__)
0349 return static_cast<size_t>(::_lwp_self());
0350 #elif defined(__OpenBSD__)
0351 return static_cast<size_t>(::getthrid());
0352 #elif defined(__sun)
0353 return static_cast<size_t>(::thr_self());
0354 #elif __APPLE__
0355 uint64_t tid;
0356 pthread_threadid_np(nullptr, &tid);
0357 return static_cast<size_t>(tid);
0358 #else
0359 return static_cast<size_t>(std::hash<std::thread::id>()(std::this_thread::get_id()));
0360 #endif
0361 }
0362
0363
0364 SPDLOG_INLINE size_t thread_id() SPDLOG_NOEXCEPT
0365 {
0366 #if defined(SPDLOG_NO_TLS)
0367 return _thread_id();
0368 #else
0369 static thread_local const size_t tid = _thread_id();
0370 return tid;
0371 #endif
0372 }
0373
0374
0375
0376 SPDLOG_INLINE void sleep_for_millis(unsigned int milliseconds) SPDLOG_NOEXCEPT
0377 {
0378 #if defined(_WIN32)
0379 ::Sleep(milliseconds);
0380 #else
0381 std::this_thread::sleep_for(std::chrono::milliseconds(milliseconds));
0382 #endif
0383 }
0384
0385
0386 #if defined(_WIN32) && defined(SPDLOG_WCHAR_FILENAMES)
0387 SPDLOG_INLINE std::string filename_to_str(const filename_t &filename)
0388 {
0389 memory_buf_t buf;
0390 wstr_to_utf8buf(filename, buf);
0391 return SPDLOG_BUF_TO_STRING(buf);
0392 }
0393 #else
0394 SPDLOG_INLINE std::string filename_to_str(const filename_t &filename)
0395 {
0396 return filename;
0397 }
0398 #endif
0399
0400 SPDLOG_INLINE int pid() SPDLOG_NOEXCEPT
0401 {
0402
0403 #ifdef _WIN32
0404 return conditional_static_cast<int>(::GetCurrentProcessId());
0405 #else
0406 return conditional_static_cast<int>(::getpid());
0407 #endif
0408 }
0409
0410
0411
0412 SPDLOG_INLINE bool is_color_terminal() SPDLOG_NOEXCEPT
0413 {
0414 #ifdef _WIN32
0415 return true;
0416 #else
0417
0418 static const bool result = []() {
0419 const char *env_colorterm_p = std::getenv("COLORTERM");
0420 if (env_colorterm_p != nullptr)
0421 {
0422 return true;
0423 }
0424
0425 static constexpr std::array<const char *, 16> terms = {{"ansi", "color", "console", "cygwin", "gnome", "konsole", "kterm", "linux",
0426 "msys", "putty", "rxvt", "screen", "vt100", "xterm", "alacritty", "vt102"}};
0427
0428 const char *env_term_p = std::getenv("TERM");
0429 if (env_term_p == nullptr)
0430 {
0431 return false;
0432 }
0433
0434 return std::any_of(terms.begin(), terms.end(), [&](const char *term) { return std::strstr(env_term_p, term) != nullptr; });
0435 }();
0436
0437 return result;
0438 #endif
0439 }
0440
0441
0442
0443 SPDLOG_INLINE bool in_terminal(FILE *file) SPDLOG_NOEXCEPT
0444 {
0445
0446 #ifdef _WIN32
0447 return ::_isatty(_fileno(file)) != 0;
0448 #else
0449 return ::isatty(fileno(file)) != 0;
0450 #endif
0451 }
0452
0453 #if (defined(SPDLOG_WCHAR_TO_UTF8_SUPPORT) || defined(SPDLOG_WCHAR_FILENAMES)) && defined(_WIN32)
0454 SPDLOG_INLINE void wstr_to_utf8buf(wstring_view_t wstr, memory_buf_t &target)
0455 {
0456 if (wstr.size() > static_cast<size_t>((std::numeric_limits<int>::max)()) / 2 - 1)
0457 {
0458 throw_spdlog_ex("UTF-16 string is too big to be converted to UTF-8");
0459 }
0460
0461 int wstr_size = static_cast<int>(wstr.size());
0462 if (wstr_size == 0)
0463 {
0464 target.resize(0);
0465 return;
0466 }
0467
0468 int result_size = static_cast<int>(target.capacity());
0469 if ((wstr_size + 1) * 2 > result_size)
0470 {
0471 result_size = ::WideCharToMultiByte(CP_UTF8, 0, wstr.data(), wstr_size, NULL, 0, NULL, NULL);
0472 }
0473
0474 if (result_size > 0)
0475 {
0476 target.resize(result_size);
0477 result_size = ::WideCharToMultiByte(CP_UTF8, 0, wstr.data(), wstr_size, target.data(), result_size, NULL, NULL);
0478
0479 if (result_size > 0)
0480 {
0481 target.resize(result_size);
0482 return;
0483 }
0484 }
0485
0486 throw_spdlog_ex(fmt_lib::format("WideCharToMultiByte failed. Last error: {}", ::GetLastError()));
0487 }
0488
0489 SPDLOG_INLINE void utf8_to_wstrbuf(string_view_t str, wmemory_buf_t &target)
0490 {
0491 if (str.size() > static_cast<size_t>((std::numeric_limits<int>::max)()) - 1)
0492 {
0493 throw_spdlog_ex("UTF-8 string is too big to be converted to UTF-16");
0494 }
0495
0496 int str_size = static_cast<int>(str.size());
0497 if (str_size == 0)
0498 {
0499 target.resize(0);
0500 return;
0501 }
0502
0503 int result_size = static_cast<int>(target.capacity());
0504 if (str_size + 1 > result_size)
0505 {
0506 result_size = ::MultiByteToWideChar(CP_UTF8, MB_ERR_INVALID_CHARS, str.data(), str_size, NULL, 0);
0507 }
0508
0509 if (result_size > 0)
0510 {
0511 target.resize(result_size);
0512 result_size = ::MultiByteToWideChar(CP_UTF8, MB_ERR_INVALID_CHARS, str.data(), str_size, target.data(), result_size);
0513
0514 if (result_size > 0)
0515 {
0516 target.resize(result_size);
0517 return;
0518 }
0519 }
0520
0521 throw_spdlog_ex(fmt_lib::format("MultiByteToWideChar failed. Last error: {}", ::GetLastError()));
0522 }
0523 #endif
0524
0525
0526 static SPDLOG_INLINE bool mkdir_(const filename_t &path)
0527 {
0528 #ifdef _WIN32
0529 # ifdef SPDLOG_WCHAR_FILENAMES
0530 return ::_wmkdir(path.c_str()) == 0;
0531 # else
0532 return ::_mkdir(path.c_str()) == 0;
0533 # endif
0534 #else
0535 return ::mkdir(path.c_str(), mode_t(0755)) == 0;
0536 #endif
0537 }
0538
0539
0540
0541 SPDLOG_INLINE bool create_dir(const filename_t &path)
0542 {
0543 if (path_exists(path))
0544 {
0545 return true;
0546 }
0547
0548 if (path.empty())
0549 {
0550 return false;
0551 }
0552
0553 size_t search_offset = 0;
0554 do
0555 {
0556 auto token_pos = path.find_first_of(folder_seps_filename, search_offset);
0557
0558 if (token_pos == filename_t::npos)
0559 {
0560 token_pos = path.size();
0561 }
0562
0563 auto subdir = path.substr(0, token_pos);
0564
0565 if (!subdir.empty() && !path_exists(subdir) && !mkdir_(subdir))
0566 {
0567 return false;
0568 }
0569 search_offset = token_pos + 1;
0570 } while (search_offset < path.size());
0571
0572 return true;
0573 }
0574
0575
0576
0577
0578
0579
0580 SPDLOG_INLINE filename_t dir_name(const filename_t &path)
0581 {
0582 auto pos = path.find_last_of(folder_seps_filename);
0583 return pos != filename_t::npos ? path.substr(0, pos) : filename_t{};
0584 }
0585
0586 std::string SPDLOG_INLINE getenv(const char *field)
0587 {
0588
0589 #if defined(_MSC_VER)
0590 # if defined(__cplusplus_winrt)
0591 return std::string{};
0592 # else
0593 size_t len = 0;
0594 char buf[128];
0595 bool ok = ::getenv_s(&len, buf, sizeof(buf), field) == 0;
0596 return ok ? buf : std::string{};
0597 # endif
0598 #else
0599 char *buf = ::getenv(field);
0600 return buf ? buf : std::string{};
0601 #endif
0602 }
0603
0604 }
0605 }
0606 }