Back to home page

EIC code displayed by LXR

 
 

    


File indexing completed on 2025-07-09 08:47:30

0001 // Copyright(c) 2015-present, Gabi Melman & spdlog contributors.
0002 // Distributed under the MIT License (http://opensource.org/licenses/MIT)
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 <array>
0014 #include <chrono>
0015 #include <cstdio>
0016 #include <cstdlib>
0017 #include <cstring>
0018 #include <ctime>
0019 #include <string>
0020 #include <sys/stat.h>
0021 #include <sys/types.h>
0022 #include <thread>
0023 
0024 #ifdef _WIN32
0025     #include <spdlog/details/windows_include.h>
0026     #include <fileapi.h>  // for FlushFileBuffers
0027     #include <io.h>       // for _get_osfhandle, _isatty, _fileno
0028     #include <process.h>  // for _get_pid
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 <cassert>
0036         #include <limits>
0037     #endif
0038 
0039     #include <direct.h>  // for _mkdir/_wmkdir
0040 
0041 #else  // unix
0042 
0043     #include <fcntl.h>
0044     #include <unistd.h>
0045 
0046     #ifdef __linux__
0047         #include <sys/syscall.h>  //Use gettid() syscall under linux to get thread id
0048 
0049     #elif defined(_AIX)
0050         #include <pthread.h>  // for pthread_getthrds_np
0051 
0052     #elif defined(__DragonFly__) || defined(__FreeBSD__)
0053         #include <pthread_np.h>  // for pthread_getthreadid_np
0054 
0055     #elif defined(__NetBSD__)
0056         #include <lwp.h>  // for _lwp_self
0057 
0058     #elif defined(__sun)
0059         #include <thread.h>  // for thr_self
0060     #endif
0061 
0062 #endif  // unix
0063 
0064 #if defined __APPLE__
0065     #include <AvailabilityMacros.h>
0066 #endif
0067 
0068 #ifndef __has_feature           // Clang - feature checking macros.
0069     #define __has_feature(x) 0  // Compatibility with non-clang compilers.
0070 #endif
0071 
0072 namespace spdlog {
0073 namespace details {
0074 namespace os {
0075 
0076 SPDLOG_INLINE spdlog::log_clock::time_point now() SPDLOG_NOEXCEPT {
0077 #if defined __linux__ && defined SPDLOG_CLOCK_COARSE
0078     timespec ts;
0079     ::clock_gettime(CLOCK_REALTIME_COARSE, &ts);
0080     return std::chrono::time_point<log_clock, typename log_clock::duration>(
0081         std::chrono::duration_cast<typename log_clock::duration>(
0082             std::chrono::seconds(ts.tv_sec) + std::chrono::nanoseconds(ts.tv_nsec)));
0083 
0084 #else
0085     return log_clock::now();
0086 #endif
0087 }
0088 SPDLOG_INLINE std::tm localtime(const std::time_t &time_tt) SPDLOG_NOEXCEPT {
0089 #ifdef _WIN32
0090     std::tm tm;
0091     ::localtime_s(&tm, &time_tt);
0092 #else
0093     std::tm tm;
0094     ::localtime_r(&time_tt, &tm);
0095 #endif
0096     return tm;
0097 }
0098 
0099 SPDLOG_INLINE std::tm localtime() SPDLOG_NOEXCEPT {
0100     std::time_t now_t = ::time(nullptr);
0101     return localtime(now_t);
0102 }
0103 
0104 SPDLOG_INLINE std::tm gmtime(const std::time_t &time_tt) SPDLOG_NOEXCEPT {
0105 #ifdef _WIN32
0106     std::tm tm;
0107     ::gmtime_s(&tm, &time_tt);
0108 #else
0109     std::tm tm;
0110     ::gmtime_r(&time_tt, &tm);
0111 #endif
0112     return tm;
0113 }
0114 
0115 SPDLOG_INLINE std::tm gmtime() SPDLOG_NOEXCEPT {
0116     std::time_t now_t = ::time(nullptr);
0117     return gmtime(now_t);
0118 }
0119 
0120 // fopen_s on non windows for writing
0121 SPDLOG_INLINE bool fopen_s(FILE **fp, const filename_t &filename, const filename_t &mode) {
0122 #ifdef _WIN32
0123     #ifdef SPDLOG_WCHAR_FILENAMES
0124     *fp = ::_wfsopen((filename.c_str()), mode.c_str(), _SH_DENYNO);
0125     #else
0126     *fp = ::_fsopen((filename.c_str()), mode.c_str(), _SH_DENYNO);
0127     #endif
0128     #if defined(SPDLOG_PREVENT_CHILD_FD)
0129     if (*fp != nullptr) {
0130         auto file_handle = reinterpret_cast<HANDLE>(_get_osfhandle(::_fileno(*fp)));
0131         if (!::SetHandleInformation(file_handle, HANDLE_FLAG_INHERIT, 0)) {
0132             ::fclose(*fp);
0133             *fp = nullptr;
0134         }
0135     }
0136     #endif
0137 #else  // unix
0138     #if defined(SPDLOG_PREVENT_CHILD_FD)
0139     const int mode_flag = mode == SPDLOG_FILENAME_T("ab") ? O_APPEND : O_TRUNC;
0140     const int fd =
0141         ::open((filename.c_str()), O_CREAT | O_WRONLY | O_CLOEXEC | mode_flag, mode_t(0644));
0142     if (fd == -1) {
0143         return true;
0144     }
0145     *fp = ::fdopen(fd, mode.c_str());
0146     if (*fp == nullptr) {
0147         ::close(fd);
0148     }
0149     #else
0150     *fp = ::fopen((filename.c_str()), mode.c_str());
0151     #endif
0152 #endif
0153 
0154     return *fp == nullptr;
0155 }
0156 
0157 SPDLOG_INLINE int remove(const filename_t &filename) SPDLOG_NOEXCEPT {
0158 #if defined(_WIN32) && defined(SPDLOG_WCHAR_FILENAMES)
0159     return ::_wremove(filename.c_str());
0160 #else
0161     return std::remove(filename.c_str());
0162 #endif
0163 }
0164 
0165 SPDLOG_INLINE int remove_if_exists(const filename_t &filename) SPDLOG_NOEXCEPT {
0166     return path_exists(filename) ? remove(filename) : 0;
0167 }
0168 
0169 SPDLOG_INLINE int rename(const filename_t &filename1, const filename_t &filename2) SPDLOG_NOEXCEPT {
0170 #if defined(_WIN32) && defined(SPDLOG_WCHAR_FILENAMES)
0171     return ::_wrename(filename1.c_str(), filename2.c_str());
0172 #else
0173     return std::rename(filename1.c_str(), filename2.c_str());
0174 #endif
0175 }
0176 
0177 // Return true if path exists (file or directory)
0178 SPDLOG_INLINE bool path_exists(const filename_t &filename) SPDLOG_NOEXCEPT {
0179 #ifdef _WIN32
0180     struct _stat buffer;
0181     #ifdef SPDLOG_WCHAR_FILENAMES
0182     return (::_wstat(filename.c_str(), &buffer) == 0);
0183     #else
0184     return (::_stat(filename.c_str(), &buffer) == 0);
0185     #endif
0186 #else  // common linux/unix all have the stat system call
0187     struct stat buffer;
0188     return (::stat(filename.c_str(), &buffer) == 0);
0189 #endif
0190 }
0191 
0192 #ifdef _MSC_VER
0193     // avoid warning about unreachable statement at the end of filesize()
0194     #pragma warning(push)
0195     #pragma warning(disable : 4702)
0196 #endif
0197 
0198 // Return file size according to open FILE* object
0199 SPDLOG_INLINE size_t filesize(FILE *f) {
0200     if (f == nullptr) {
0201         throw_spdlog_ex("Failed getting file size. fd is null");
0202     }
0203 #if defined(_WIN32) && !defined(__CYGWIN__)
0204     int fd = ::_fileno(f);
0205     #if defined(_WIN64)  // 64 bits
0206     __int64 ret = ::_filelengthi64(fd);
0207     if (ret >= 0) {
0208         return static_cast<size_t>(ret);
0209     }
0210 
0211     #else  // windows 32 bits
0212     long ret = ::_filelength(fd);
0213     if (ret >= 0) {
0214         return static_cast<size_t>(ret);
0215     }
0216     #endif
0217 
0218 #else  // unix
0219     // OpenBSD and AIX doesn't compile with :: before the fileno(..)
0220     #if defined(__OpenBSD__) || defined(_AIX)
0221     int fd = fileno(f);
0222     #else
0223     int fd = ::fileno(f);
0224     #endif
0225     // 64 bits(but not in osx, linux/musl or cygwin, where fstat64 is deprecated)
0226     #if ((defined(__linux__) && defined(__GLIBC__)) || defined(__sun) || defined(_AIX)) && \
0227         (defined(__LP64__) || defined(_LP64))
0228     struct stat64 st;
0229     if (::fstat64(fd, &st) == 0) {
0230         return static_cast<size_t>(st.st_size);
0231     }
0232     #else  // other unix or linux 32 bits or cygwin
0233     struct stat st;
0234     if (::fstat(fd, &st) == 0) {
0235         return static_cast<size_t>(st.st_size);
0236     }
0237     #endif
0238 #endif
0239     throw_spdlog_ex("Failed getting file size from fd", errno);
0240     return 0;  // will not be reached.
0241 }
0242 
0243 #ifdef _MSC_VER
0244     #pragma warning(pop)
0245 #endif
0246 
0247 // Return utc offset in minutes or throw spdlog_ex on failure
0248 SPDLOG_INLINE int utc_minutes_offset(const std::tm &tm) {
0249 #ifdef _WIN32
0250     #if _WIN32_WINNT < _WIN32_WINNT_WS08
0251     TIME_ZONE_INFORMATION tzinfo;
0252     auto rv = ::GetTimeZoneInformation(&tzinfo);
0253     #else
0254     DYNAMIC_TIME_ZONE_INFORMATION tzinfo;
0255     auto rv = ::GetDynamicTimeZoneInformation(&tzinfo);
0256     #endif
0257     if (rv == TIME_ZONE_ID_INVALID) throw_spdlog_ex("Failed getting timezone info. ", errno);
0258 
0259     int offset = -tzinfo.Bias;
0260     if (tm.tm_isdst) {
0261         offset -= tzinfo.DaylightBias;
0262     } else {
0263         offset -= tzinfo.StandardBias;
0264     }
0265     return offset;
0266 #else
0267 
0268     #if defined(sun) || defined(__sun) || defined(_AIX) || \
0269         (defined(__NEWLIB__) && !defined(__TM_GMTOFF)) ||  \
0270         (!defined(_BSD_SOURCE) && !defined(_GNU_SOURCE))
0271     // 'tm_gmtoff' field is BSD extension and it's missing on SunOS/Solaris
0272     struct helper {
0273         static long int calculate_gmt_offset(const std::tm &localtm = details::os::localtime(),
0274                                              const std::tm &gmtm = details::os::gmtime()) {
0275             int local_year = localtm.tm_year + (1900 - 1);
0276             int gmt_year = gmtm.tm_year + (1900 - 1);
0277 
0278             long int days = (
0279                 // difference in day of year
0280                 localtm.tm_yday -
0281                 gmtm.tm_yday
0282 
0283                 // + intervening leap days
0284                 + ((local_year >> 2) - (gmt_year >> 2)) - (local_year / 100 - gmt_year / 100) +
0285                 ((local_year / 100 >> 2) - (gmt_year / 100 >> 2))
0286 
0287                 // + difference in years * 365 */
0288                 + static_cast<long int>(local_year - gmt_year) * 365);
0289 
0290             long int hours = (24 * days) + (localtm.tm_hour - gmtm.tm_hour);
0291             long int mins = (60 * hours) + (localtm.tm_min - gmtm.tm_min);
0292             long int secs = (60 * mins) + (localtm.tm_sec - gmtm.tm_sec);
0293 
0294             return secs;
0295         }
0296     };
0297 
0298     auto offset_seconds = helper::calculate_gmt_offset(tm);
0299     #else
0300     auto offset_seconds = tm.tm_gmtoff;
0301     #endif
0302 
0303     return static_cast<int>(offset_seconds / 60);
0304 #endif
0305 }
0306 
0307 // Return current thread id as size_t
0308 // It exists because the std::this_thread::get_id() is much slower(especially
0309 // under VS 2013)
0310 SPDLOG_INLINE size_t _thread_id() SPDLOG_NOEXCEPT {
0311 #ifdef _WIN32
0312     return static_cast<size_t>(::GetCurrentThreadId());
0313 #elif defined(__linux__)
0314     #if defined(__ANDROID__) && defined(__ANDROID_API__) && (__ANDROID_API__ < 21)
0315         #define SYS_gettid __NR_gettid
0316     #endif
0317     return static_cast<size_t>(::syscall(SYS_gettid));
0318 #elif defined(_AIX)
0319     struct __pthrdsinfo buf;
0320     int reg_size = 0;
0321     pthread_t pt = pthread_self();
0322     int retval = pthread_getthrds_np(&pt, PTHRDSINFO_QUERY_TID, &buf, sizeof(buf), NULL, &reg_size);
0323     int tid = (!retval) ? buf.__pi_tid : 0;
0324     return static_cast<size_t>(tid);
0325 #elif defined(__DragonFly__) || defined(__FreeBSD__)
0326     return static_cast<size_t>(::pthread_getthreadid_np());
0327 #elif defined(__NetBSD__)
0328     return static_cast<size_t>(::_lwp_self());
0329 #elif defined(__OpenBSD__)
0330     return static_cast<size_t>(::getthrid());
0331 #elif defined(__sun)
0332     return static_cast<size_t>(::thr_self());
0333 #elif __APPLE__
0334     uint64_t tid;
0335     // There is no pthread_threadid_np prior to Mac OS X 10.6, and it is not supported on any PPC,
0336     // including 10.6.8 Rosetta. __POWERPC__ is Apple-specific define encompassing ppc and ppc64.
0337     #ifdef MAC_OS_X_VERSION_MAX_ALLOWED
0338     {
0339         #if (MAC_OS_X_VERSION_MAX_ALLOWED < 1060) || defined(__POWERPC__)
0340         tid = pthread_mach_thread_np(pthread_self());
0341         #elif MAC_OS_X_VERSION_MIN_REQUIRED < 1060
0342         if (&pthread_threadid_np) {
0343             pthread_threadid_np(nullptr, &tid);
0344         } else {
0345             tid = pthread_mach_thread_np(pthread_self());
0346         }
0347         #else
0348         pthread_threadid_np(nullptr, &tid);
0349         #endif
0350     }
0351     #else
0352     pthread_threadid_np(nullptr, &tid);
0353     #endif
0354     return static_cast<size_t>(tid);
0355 #else  // Default to standard C++11 (other Unix)
0356     return static_cast<size_t>(std::hash<std::thread::id>()(std::this_thread::get_id()));
0357 #endif
0358 }
0359 
0360 // Return current thread id as size_t (from thread local storage)
0361 SPDLOG_INLINE size_t thread_id() SPDLOG_NOEXCEPT {
0362 #if defined(SPDLOG_NO_TLS)
0363     return _thread_id();
0364 #else  // cache thread id in tls
0365     static thread_local const size_t tid = _thread_id();
0366     return tid;
0367 #endif
0368 }
0369 
0370 // This is avoid msvc issue in sleep_for that happens if the clock changes.
0371 // See https://github.com/gabime/spdlog/issues/609
0372 SPDLOG_INLINE void sleep_for_millis(unsigned int milliseconds) SPDLOG_NOEXCEPT {
0373 #if defined(_WIN32)
0374     ::Sleep(milliseconds);
0375 #else
0376     std::this_thread::sleep_for(std::chrono::milliseconds(milliseconds));
0377 #endif
0378 }
0379 
0380 // wchar support for windows file names (SPDLOG_WCHAR_FILENAMES must be defined)
0381 #if defined(_WIN32) && defined(SPDLOG_WCHAR_FILENAMES)
0382 SPDLOG_INLINE std::string filename_to_str(const filename_t &filename) {
0383     memory_buf_t buf;
0384     wstr_to_utf8buf(filename, buf);
0385     return SPDLOG_BUF_TO_STRING(buf);
0386 }
0387 #else
0388 SPDLOG_INLINE std::string filename_to_str(const filename_t &filename) { return filename; }
0389 #endif
0390 
0391 SPDLOG_INLINE int pid() SPDLOG_NOEXCEPT {
0392 #ifdef _WIN32
0393     return conditional_static_cast<int>(::GetCurrentProcessId());
0394 #else
0395     return conditional_static_cast<int>(::getpid());
0396 #endif
0397 }
0398 
0399 // Determine if the terminal supports colors
0400 // Based on: https://github.com/agauniyal/rang/
0401 SPDLOG_INLINE bool is_color_terminal() SPDLOG_NOEXCEPT {
0402 #ifdef _WIN32
0403     return true;
0404 #else
0405 
0406     static const bool result = []() {
0407         const char *env_colorterm_p = std::getenv("COLORTERM");
0408         if (env_colorterm_p != nullptr) {
0409             return true;
0410         }
0411 
0412         static constexpr std::array<const char *, 16> terms = {
0413             {"ansi", "color", "console", "cygwin", "gnome", "konsole", "kterm", "linux", "msys",
0414              "putty", "rxvt", "screen", "vt100", "xterm", "alacritty", "vt102"}};
0415 
0416         const char *env_term_p = std::getenv("TERM");
0417         if (env_term_p == nullptr) {
0418             return false;
0419         }
0420 
0421         return std::any_of(terms.begin(), terms.end(), [&](const char *term) {
0422             return std::strstr(env_term_p, term) != nullptr;
0423         });
0424     }();
0425 
0426     return result;
0427 #endif
0428 }
0429 
0430 // Determine if the terminal attached
0431 // Source: https://github.com/agauniyal/rang/
0432 SPDLOG_INLINE bool in_terminal(FILE *file) SPDLOG_NOEXCEPT {
0433 #ifdef _WIN32
0434     return ::_isatty(_fileno(file)) != 0;
0435 #else
0436     return ::isatty(fileno(file)) != 0;
0437 #endif
0438 }
0439 
0440 #if (defined(SPDLOG_WCHAR_TO_UTF8_SUPPORT) || defined(SPDLOG_WCHAR_FILENAMES)) && defined(_WIN32)
0441 SPDLOG_INLINE void wstr_to_utf8buf(wstring_view_t wstr, memory_buf_t &target) {
0442     if (wstr.size() > static_cast<size_t>((std::numeric_limits<int>::max)()) / 4 - 1) {
0443         throw_spdlog_ex("UTF-16 string is too big to be converted to UTF-8");
0444     }
0445 
0446     int wstr_size = static_cast<int>(wstr.size());
0447     if (wstr_size == 0) {
0448         target.resize(0);
0449         return;
0450     }
0451 
0452     int result_size = static_cast<int>(target.capacity());
0453     if ((wstr_size + 1) * 4 > result_size) {
0454         result_size =
0455             ::WideCharToMultiByte(CP_UTF8, 0, wstr.data(), wstr_size, NULL, 0, NULL, NULL);
0456     }
0457 
0458     if (result_size > 0) {
0459         target.resize(result_size);
0460         result_size = ::WideCharToMultiByte(CP_UTF8, 0, wstr.data(), wstr_size, target.data(),
0461                                             result_size, NULL, NULL);
0462 
0463         if (result_size > 0) {
0464             target.resize(result_size);
0465             return;
0466         }
0467     }
0468 
0469     throw_spdlog_ex(
0470         fmt_lib::format("WideCharToMultiByte failed. Last error: {}", ::GetLastError()));
0471 }
0472 
0473 SPDLOG_INLINE void utf8_to_wstrbuf(string_view_t str, wmemory_buf_t &target) {
0474     if (str.size() > static_cast<size_t>((std::numeric_limits<int>::max)()) - 1) {
0475         throw_spdlog_ex("UTF-8 string is too big to be converted to UTF-16");
0476     }
0477 
0478     int str_size = static_cast<int>(str.size());
0479     if (str_size == 0) {
0480         target.resize(0);
0481         return;
0482     }
0483 
0484     // find the size to allocate for the result buffer
0485     int result_size =
0486         ::MultiByteToWideChar(CP_UTF8, MB_ERR_INVALID_CHARS, str.data(), str_size, NULL, 0);
0487 
0488     if (result_size > 0) {
0489         target.resize(result_size);
0490         result_size = ::MultiByteToWideChar(CP_UTF8, MB_ERR_INVALID_CHARS, str.data(), str_size,
0491                                             target.data(), result_size);
0492         if (result_size > 0) {
0493             assert(result_size == target.size());
0494             return;
0495         }
0496     }
0497 
0498     throw_spdlog_ex(
0499         fmt_lib::format("MultiByteToWideChar failed. Last error: {}", ::GetLastError()));
0500 }
0501 #endif  // (defined(SPDLOG_WCHAR_TO_UTF8_SUPPORT) || defined(SPDLOG_WCHAR_FILENAMES)) &&
0502         // defined(_WIN32)
0503 
0504 // return true on success
0505 static SPDLOG_INLINE bool mkdir_(const filename_t &path) {
0506 #ifdef _WIN32
0507     #ifdef SPDLOG_WCHAR_FILENAMES
0508     return ::_wmkdir(path.c_str()) == 0;
0509     #else
0510     return ::_mkdir(path.c_str()) == 0;
0511     #endif
0512 #else
0513     return ::mkdir(path.c_str(), mode_t(0755)) == 0;
0514 #endif
0515 }
0516 
0517 // create the given directory - and all directories leading to it
0518 // return true on success or if the directory already exists
0519 SPDLOG_INLINE bool create_dir(const filename_t &path) {
0520     if (path_exists(path)) {
0521         return true;
0522     }
0523 
0524     if (path.empty()) {
0525         return false;
0526     }
0527 
0528     size_t search_offset = 0;
0529     do {
0530         auto token_pos = path.find_first_of(folder_seps_filename, search_offset);
0531         // treat the entire path as a folder if no folder separator not found
0532         if (token_pos == filename_t::npos) {
0533             token_pos = path.size();
0534         }
0535 
0536         auto subdir = path.substr(0, token_pos);
0537 #ifdef _WIN32
0538         // if subdir is just a drive letter, add a slash e.g. "c:"=>"c:\",
0539         // otherwise path_exists(subdir) returns false (issue #3079)
0540         const bool is_drive = subdir.length() == 2 && subdir[1] == ':';
0541         if (is_drive) {
0542             subdir += '\\';
0543             token_pos++;
0544         }
0545 #endif
0546 
0547         if (!subdir.empty() && !path_exists(subdir) && !mkdir_(subdir)) {
0548             return false;  // return error if failed creating dir
0549         }
0550         search_offset = token_pos + 1;
0551     } while (search_offset < path.size());
0552 
0553     return true;
0554 }
0555 
0556 // Return directory name from given path or empty string
0557 // "abc/file" => "abc"
0558 // "abc/" => "abc"
0559 // "abc" => ""
0560 // "abc///" => "abc//"
0561 SPDLOG_INLINE filename_t dir_name(const filename_t &path) {
0562     auto pos = path.find_last_of(folder_seps_filename);
0563     return pos != filename_t::npos ? path.substr(0, pos) : filename_t{};
0564 }
0565 
0566 std::string SPDLOG_INLINE getenv(const char *field) {
0567 #if defined(_MSC_VER)
0568     #if defined(__cplusplus_winrt)
0569     return std::string{};  // not supported under uwp
0570     #else
0571     size_t len = 0;
0572     char buf[128];
0573     bool ok = ::getenv_s(&len, buf, sizeof(buf), field) == 0;
0574     return ok ? buf : std::string{};
0575     #endif
0576 #else  // revert to getenv
0577     char *buf = ::getenv(field);
0578     return buf ? buf : std::string{};
0579 #endif
0580 }
0581 
0582 // Do fsync by FILE handlerpointer
0583 // Return true on success
0584 SPDLOG_INLINE bool fsync(FILE *fp) {
0585 #ifdef _WIN32
0586     return FlushFileBuffers(reinterpret_cast<HANDLE>(_get_osfhandle(_fileno(fp)))) != 0;
0587 #else
0588     return ::fsync(fileno(fp)) == 0;
0589 #endif
0590 }
0591 
0592 }  // namespace os
0593 }  // namespace details
0594 }  // namespace spdlog