Back to home page

EIC code displayed by LXR

 
 

    


File indexing completed on 2025-01-18 10:12:41

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 <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 // unix
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 // unix
0062 
0063 #ifndef __has_feature          // Clang - feature checking macros.
0064 #    define __has_feature(x) 0 // Compatibility with non-clang compilers.
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 // fopen_s on non windows for writing
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 // unix
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 // Return true if path exists (file or directory)
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 // common linux/unix all have the stat system call
0197     struct stat buffer;
0198     return (::stat(filename.c_str(), &buffer) == 0);
0199 #endif
0200 }
0201 
0202 #ifdef _MSC_VER
0203 // avoid warning about unreachable statement at the end of filesize()
0204 #    pragma warning(push)
0205 #    pragma warning(disable : 4702)
0206 #endif
0207 
0208 // Return file size according to open FILE* object
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) // 64 bits
0218     __int64 ret = ::_filelengthi64(fd);
0219     if (ret >= 0)
0220     {
0221         return static_cast<size_t>(ret);
0222     }
0223 
0224 #    else // windows 32 bits
0225     long ret = ::_filelength(fd);
0226     if (ret >= 0)
0227     {
0228         return static_cast<size_t>(ret);
0229     }
0230 #    endif
0231 
0232 #else // unix
0233 // OpenBSD and AIX doesn't compile with :: before the fileno(..)
0234 #    if defined(__OpenBSD__) || defined(_AIX)
0235     int fd = fileno(f);
0236 #    else
0237     int fd = ::fileno(f);
0238 #    endif
0239 // 64 bits(but not in osx or cygwin, where fstat64 is deprecated)
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 // other unix or linux 32 bits or cygwin
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; // will not be reached.
0256 }
0257 
0258 #ifdef _MSC_VER
0259 #    pragma warning(pop)
0260 #endif
0261 
0262 // Return utc offset in minutes or throw spdlog_ex on failure
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     // 'tm_gmtoff' field is BSD extension and it's missing on SunOS/Solaris
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                 // difference in day of year
0300                 localtm.tm_yday -
0301                 gmtm.tm_yday
0302 
0303                 // + intervening leap days
0304                 + ((local_year >> 2) - (gmt_year >> 2)) - (local_year / 100 - gmt_year / 100) +
0305                 ((local_year / 100 >> 2) - (gmt_year / 100 >> 2))
0306 
0307                 // + difference in years * 365 */
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 // Return current thread id as size_t
0328 // It exists because the std::this_thread::get_id() is much slower(especially
0329 // under VS 2013)
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, &reg_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 // Default to standard C++11 (other Unix)
0359     return static_cast<size_t>(std::hash<std::thread::id>()(std::this_thread::get_id()));
0360 #endif
0361 }
0362 
0363 // Return current thread id as size_t (from thread local storage)
0364 SPDLOG_INLINE size_t thread_id() SPDLOG_NOEXCEPT
0365 {
0366 #if defined(SPDLOG_NO_TLS)
0367     return _thread_id();
0368 #else // cache thread id in tls
0369     static thread_local const size_t tid = _thread_id();
0370     return tid;
0371 #endif
0372 }
0373 
0374 // This is avoid msvc issue in sleep_for that happens if the clock changes.
0375 // See https://github.com/gabime/spdlog/issues/609
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 // wchar support for windows file names (SPDLOG_WCHAR_FILENAMES must be defined)
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 // Determine if the terminal supports colors
0411 // Based on: https://github.com/agauniyal/rang/
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 // Determine if the terminal attached
0442 // Source: https://github.com/agauniyal/rang/
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 // (defined(SPDLOG_WCHAR_TO_UTF8_SUPPORT) || defined(SPDLOG_WCHAR_FILENAMES)) && defined(_WIN32)
0524 
0525 // return true on success
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 // create the given directory - and all directories leading to it
0540 // return true on success or if the directory already exists
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         // treat the entire path as a folder if no folder separator not found
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; // return error if failed creating dir
0568         }
0569         search_offset = token_pos + 1;
0570     } while (search_offset < path.size());
0571 
0572     return true;
0573 }
0574 
0575 // Return directory name from given path or empty string
0576 // "abc/file" => "abc"
0577 // "abc/" => "abc"
0578 // "abc" => ""
0579 // "abc///" => "abc//"
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{}; // not supported under uwp
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 // revert to getenv
0599     char *buf = ::getenv(field);
0600     return buf ? buf : std::string{};
0601 #endif
0602 }
0603 
0604 } // namespace os
0605 } // namespace details
0606 } // namespace spdlog