LCOV - code coverage report
Current view: top level - app/libs/spdlog/include/spdlog/details - os-inl.h (source / functions) Hit Total Coverage
Test: coverage.info Lines: 0 26 0.0 %
Date: 2023-08-17 16:45:52 Functions: 0 2 0.0 %

          Line data    Source code
       1             : // Copyright(c) 2015-present, Gabi Melman & spdlog contributors.
       2             : // Distributed under the MIT License (http://opensource.org/licenses/MIT)
       3             : 
       4             : #pragma once
       5             : 
       6             : #ifndef SPDLOG_HEADER_ONLY
       7             : #    include <spdlog/details/os.h>
       8             : #endif
       9             : 
      10             : #include <spdlog/common.h>
      11             : 
      12             : #include <algorithm>
      13             : #include <chrono>
      14             : #include <cstdio>
      15             : #include <cstdlib>
      16             : #include <cstring>
      17             : #include <ctime>
      18             : #include <string>
      19             : #include <thread>
      20             : #include <array>
      21             : #include <sys/stat.h>
      22             : #include <sys/types.h>
      23             : 
      24             : #ifdef _WIN32
      25             : 
      26             : #    include <io.h>      // for _get_osfhandle, _isatty, _fileno
      27             : #    include <process.h> // for _get_pid
      28             : #    include <spdlog/details/windows_include.h>
      29             : #    include <fileapi.h> // for FlushFileBuffers
      30             : 
      31             : #    ifdef __MINGW32__
      32             : #        include <share.h>
      33             : #    endif
      34             : 
      35             : #    if defined(SPDLOG_WCHAR_TO_UTF8_SUPPORT) || defined(SPDLOG_WCHAR_FILENAMES)
      36             : #        include <limits>
      37             : #        include <cassert>
      38             : #    endif
      39             : 
      40             : #    include <direct.h> // for _mkdir/_wmkdir
      41             : 
      42             : #else // unix
      43             : 
      44             : #    include <fcntl.h>
      45             : #    include <unistd.h>
      46             : 
      47             : #    ifdef __linux__
      48             : #        include <sys/syscall.h> //Use gettid() syscall under linux to get thread id
      49             : 
      50             : #    elif defined(_AIX)
      51             : #        include <pthread.h> // for pthread_getthrds_np
      52             : 
      53             : #    elif defined(__DragonFly__) || defined(__FreeBSD__)
      54             : #        include <pthread_np.h> // for pthread_getthreadid_np
      55             : 
      56             : #    elif defined(__NetBSD__)
      57             : #        include <lwp.h> // for _lwp_self
      58             : 
      59             : #    elif defined(__sun)
      60             : #        include <thread.h> // for thr_self
      61             : #    endif
      62             : 
      63             : #endif // unix
      64             : 
      65             : #if defined __APPLE__
      66             : #    include <AvailabilityMacros.h>
      67             : #endif
      68             : 
      69             : #ifndef __has_feature          // Clang - feature checking macros.
      70             : #    define __has_feature(x) 0 // Compatibility with non-clang compilers.
      71             : #endif
      72             : 
      73             : namespace spdlog {
      74             : namespace details {
      75             : namespace os {
      76             : 
      77           0 : SPDLOG_INLINE spdlog::log_clock::time_point now() SPDLOG_NOEXCEPT
      78             : {
      79             : 
      80             : #if defined __linux__ && defined SPDLOG_CLOCK_COARSE
      81             :     timespec ts;
      82             :     ::clock_gettime(CLOCK_REALTIME_COARSE, &ts);
      83             :     return std::chrono::time_point<log_clock, typename log_clock::duration>(
      84             :         std::chrono::duration_cast<typename log_clock::duration>(std::chrono::seconds(ts.tv_sec) + std::chrono::nanoseconds(ts.tv_nsec)));
      85             : 
      86             : #else
      87           0 :     return log_clock::now();
      88             : #endif
      89             : }
      90           0 : SPDLOG_INLINE std::tm localtime(const std::time_t &time_tt) SPDLOG_NOEXCEPT
      91             : {
      92             : 
      93             : #ifdef _WIN32
      94             :     std::tm tm;
      95             :     ::localtime_s(&tm, &time_tt);
      96             : #else
      97           0 :     std::tm tm;
      98           0 :     ::localtime_r(&time_tt, &tm);
      99             : #endif
     100           0 :     return tm;
     101             : }
     102             : 
     103             : SPDLOG_INLINE std::tm localtime() SPDLOG_NOEXCEPT
     104             : {
     105             :     std::time_t now_t = ::time(nullptr);
     106             :     return localtime(now_t);
     107             : }
     108             : 
     109             : SPDLOG_INLINE std::tm gmtime(const std::time_t &time_tt) SPDLOG_NOEXCEPT
     110             : {
     111             : 
     112             : #ifdef _WIN32
     113             :     std::tm tm;
     114             :     ::gmtime_s(&tm, &time_tt);
     115             : #else
     116             :     std::tm tm;
     117             :     ::gmtime_r(&time_tt, &tm);
     118             : #endif
     119             :     return tm;
     120             : }
     121             : 
     122             : SPDLOG_INLINE std::tm gmtime() SPDLOG_NOEXCEPT
     123             : {
     124             :     std::time_t now_t = ::time(nullptr);
     125             :     return gmtime(now_t);
     126             : }
     127             : 
     128             : // fopen_s on non windows for writing
     129             : SPDLOG_INLINE bool fopen_s(FILE **fp, const filename_t &filename, const filename_t &mode)
     130             : {
     131             : #ifdef _WIN32
     132             : #    ifdef SPDLOG_WCHAR_FILENAMES
     133             :     *fp = ::_wfsopen((filename.c_str()), mode.c_str(), _SH_DENYNO);
     134             : #    else
     135             :     *fp = ::_fsopen((filename.c_str()), mode.c_str(), _SH_DENYNO);
     136             : #    endif
     137             : #    if defined(SPDLOG_PREVENT_CHILD_FD)
     138             :     if (*fp != nullptr)
     139             :     {
     140             :         auto file_handle = reinterpret_cast<HANDLE>(_get_osfhandle(::_fileno(*fp)));
     141             :         if (!::SetHandleInformation(file_handle, HANDLE_FLAG_INHERIT, 0))
     142             :         {
     143             :             ::fclose(*fp);
     144             :             *fp = nullptr;
     145             :         }
     146             :     }
     147             : #    endif
     148             : #else // unix
     149             : #    if defined(SPDLOG_PREVENT_CHILD_FD)
     150             :     const int mode_flag = mode == SPDLOG_FILENAME_T("ab") ? O_APPEND : O_TRUNC;
     151             :     const int fd = ::open((filename.c_str()), O_CREAT | O_WRONLY | O_CLOEXEC | mode_flag, mode_t(0644));
     152             :     if (fd == -1)
     153             :     {
     154             :         return true;
     155             :     }
     156             :     *fp = ::fdopen(fd, mode.c_str());
     157             :     if (*fp == nullptr)
     158             :     {
     159             :         ::close(fd);
     160             :     }
     161             : #    else
     162             :     *fp = ::fopen((filename.c_str()), mode.c_str());
     163             : #    endif
     164             : #endif
     165             : 
     166             :     return *fp == nullptr;
     167             : }
     168             : 
     169             : SPDLOG_INLINE int remove(const filename_t &filename) SPDLOG_NOEXCEPT
     170             : {
     171             : #if defined(_WIN32) && defined(SPDLOG_WCHAR_FILENAMES)
     172             :     return ::_wremove(filename.c_str());
     173             : #else
     174             :     return std::remove(filename.c_str());
     175             : #endif
     176             : }
     177             : 
     178             : SPDLOG_INLINE int remove_if_exists(const filename_t &filename) SPDLOG_NOEXCEPT
     179             : {
     180             :     return path_exists(filename) ? remove(filename) : 0;
     181             : }
     182             : 
     183             : SPDLOG_INLINE int rename(const filename_t &filename1, const filename_t &filename2) SPDLOG_NOEXCEPT
     184             : {
     185             : #if defined(_WIN32) && defined(SPDLOG_WCHAR_FILENAMES)
     186             :     return ::_wrename(filename1.c_str(), filename2.c_str());
     187             : #else
     188             :     return std::rename(filename1.c_str(), filename2.c_str());
     189             : #endif
     190             : }
     191             : 
     192             : // Return true if path exists (file or directory)
     193             : SPDLOG_INLINE bool path_exists(const filename_t &filename) SPDLOG_NOEXCEPT
     194             : {
     195             : #ifdef _WIN32
     196             : #    ifdef SPDLOG_WCHAR_FILENAMES
     197             :     auto attribs = ::GetFileAttributesW(filename.c_str());
     198             : #    else
     199             :     auto attribs = ::GetFileAttributesA(filename.c_str());
     200             : #    endif
     201             :     return attribs != INVALID_FILE_ATTRIBUTES;
     202             : #else // common linux/unix all have the stat system call
     203             :     struct stat buffer;
     204             :     return (::stat(filename.c_str(), &buffer) == 0);
     205             : #endif
     206             : }
     207             : 
     208             : #ifdef _MSC_VER
     209             : // avoid warning about unreachable statement at the end of filesize()
     210             : #    pragma warning(push)
     211             : #    pragma warning(disable : 4702)
     212             : #endif
     213             : 
     214             : // Return file size according to open FILE* object
     215             : SPDLOG_INLINE size_t filesize(FILE *f)
     216             : {
     217             :     if (f == nullptr)
     218             :     {
     219             :         throw_spdlog_ex("Failed getting file size. fd is null");
     220             :     }
     221             : #if defined(_WIN32) && !defined(__CYGWIN__)
     222             :     int fd = ::_fileno(f);
     223             : #    if defined(_WIN64) // 64 bits
     224             :     __int64 ret = ::_filelengthi64(fd);
     225             :     if (ret >= 0)
     226             :     {
     227             :         return static_cast<size_t>(ret);
     228             :     }
     229             : 
     230             : #    else // windows 32 bits
     231             :     long ret = ::_filelength(fd);
     232             :     if (ret >= 0)
     233             :     {
     234             :         return static_cast<size_t>(ret);
     235             :     }
     236             : #    endif
     237             : 
     238             : #else // unix
     239             : // OpenBSD and AIX doesn't compile with :: before the fileno(..)
     240             : #    if defined(__OpenBSD__) || defined(_AIX)
     241             :     int fd = fileno(f);
     242             : #    else
     243             :     int fd = ::fileno(f);
     244             : #    endif
     245             : // 64 bits(but not in osx, linux/musl or cygwin, where fstat64 is deprecated)
     246             : #    if ((defined(__linux__) && defined(__GLIBC__)) || defined(__sun) || defined(_AIX)) && (defined(__LP64__) || defined(_LP64))
     247             :     struct stat64 st;
     248             :     if (::fstat64(fd, &st) == 0)
     249             :     {
     250             :         return static_cast<size_t>(st.st_size);
     251             :     }
     252             : #    else // other unix or linux 32 bits or cygwin
     253             :     struct stat st;
     254             :     if (::fstat(fd, &st) == 0)
     255             :     {
     256             :         return static_cast<size_t>(st.st_size);
     257             :     }
     258             : #    endif
     259             : #endif
     260             :     throw_spdlog_ex("Failed getting file size from fd", errno);
     261             :     return 0; // will not be reached.
     262             : }
     263             : 
     264             : #ifdef _MSC_VER
     265             : #    pragma warning(pop)
     266             : #endif
     267             : 
     268             : // Return utc offset in minutes or throw spdlog_ex on failure
     269           0 : SPDLOG_INLINE int utc_minutes_offset(const std::tm &tm)
     270             : {
     271             : 
     272             : #ifdef _WIN32
     273             : #    if _WIN32_WINNT < _WIN32_WINNT_WS08
     274             :     TIME_ZONE_INFORMATION tzinfo;
     275             :     auto rv = ::GetTimeZoneInformation(&tzinfo);
     276             : #    else
     277             :     DYNAMIC_TIME_ZONE_INFORMATION tzinfo;
     278             :     auto rv = ::GetDynamicTimeZoneInformation(&tzinfo);
     279             : #    endif
     280             :     if (rv == TIME_ZONE_ID_INVALID)
     281             :         throw_spdlog_ex("Failed getting timezone info. ", errno);
     282             : 
     283             :     int offset = -tzinfo.Bias;
     284             :     if (tm.tm_isdst)
     285             :     {
     286             :         offset -= tzinfo.DaylightBias;
     287             :     }
     288             :     else
     289             :     {
     290             :         offset -= tzinfo.StandardBias;
     291             :     }
     292             :     return offset;
     293             : #else
     294             : 
     295             : #    if defined(sun) || defined(__sun) || defined(_AIX) || (defined(__NEWLIB__) && !defined(__TM_GMTOFF)) ||                               \
     296             :         (!defined(_BSD_SOURCE) && !defined(_GNU_SOURCE))
     297             :     // 'tm_gmtoff' field is BSD extension and it's missing on SunOS/Solaris
     298             :     struct helper
     299             :     {
     300             :         static long int calculate_gmt_offset(const std::tm &localtm = details::os::localtime(), const std::tm &gmtm = details::os::gmtime())
     301             :         {
     302             :             int local_year = localtm.tm_year + (1900 - 1);
     303             :             int gmt_year = gmtm.tm_year + (1900 - 1);
     304             : 
     305             :             long int days = (
     306             :                 // difference in day of year
     307             :                 localtm.tm_yday -
     308             :                 gmtm.tm_yday
     309             : 
     310             :                 // + intervening leap days
     311             :                 + ((local_year >> 2) - (gmt_year >> 2)) - (local_year / 100 - gmt_year / 100) +
     312             :                 ((local_year / 100 >> 2) - (gmt_year / 100 >> 2))
     313             : 
     314             :                 // + difference in years * 365 */
     315             :                 + static_cast<long int>(local_year - gmt_year) * 365);
     316             : 
     317             :             long int hours = (24 * days) + (localtm.tm_hour - gmtm.tm_hour);
     318             :             long int mins = (60 * hours) + (localtm.tm_min - gmtm.tm_min);
     319             :             long int secs = (60 * mins) + (localtm.tm_sec - gmtm.tm_sec);
     320             : 
     321             :             return secs;
     322             :         }
     323             :     };
     324             : 
     325             :     auto offset_seconds = helper::calculate_gmt_offset(tm);
     326             : #    else
     327           0 :     auto offset_seconds = tm.tm_gmtoff;
     328             : #    endif
     329             : 
     330           0 :     return static_cast<int>(offset_seconds / 60);
     331             : #endif
     332             : }
     333             : 
     334             : // Return current thread id as size_t
     335             : // It exists because the std::this_thread::get_id() is much slower(especially
     336             : // under VS 2013)
     337           0 : SPDLOG_INLINE size_t _thread_id() SPDLOG_NOEXCEPT
     338             : {
     339             : #ifdef _WIN32
     340             :     return static_cast<size_t>(::GetCurrentThreadId());
     341             : #elif defined(__linux__)
     342             : #    if defined(__ANDROID__) && defined(__ANDROID_API__) && (__ANDROID_API__ < 21)
     343             : #        define SYS_gettid __NR_gettid
     344             : #    endif
     345           0 :     return static_cast<size_t>(::syscall(SYS_gettid));
     346             : #elif defined(_AIX)
     347             :     struct __pthrdsinfo buf;
     348             :     int reg_size = 0;
     349             :     pthread_t pt = pthread_self();
     350             :     int retval = pthread_getthrds_np(&pt, PTHRDSINFO_QUERY_TID, &buf, sizeof(buf), NULL, &reg_size);
     351             :     int tid = (!retval) ? buf.__pi_tid : 0;
     352             :     return static_cast<size_t>(tid);
     353             : #elif defined(__DragonFly__) || defined(__FreeBSD__)
     354             :     return static_cast<size_t>(::pthread_getthreadid_np());
     355             : #elif defined(__NetBSD__)
     356             :     return static_cast<size_t>(::_lwp_self());
     357             : #elif defined(__OpenBSD__)
     358             :     return static_cast<size_t>(::getthrid());
     359             : #elif defined(__sun)
     360             :     return static_cast<size_t>(::thr_self());
     361             : #elif __APPLE__
     362             :     uint64_t tid;
     363             :     // There is no pthread_threadid_np prior to 10.6, and it is not supported on any PPC,
     364             :     // including 10.6.8 Rosetta. __POWERPC__ is Apple-specific define encompassing ppc and ppc64.
     365             : #    if (MAC_OS_X_VERSION_MAX_ALLOWED < 1060) || defined(__POWERPC__)
     366             :     tid = pthread_mach_thread_np(pthread_self());
     367             : #    elif MAC_OS_X_VERSION_MIN_REQUIRED < 1060
     368             :     if (&pthread_threadid_np)
     369             :     {
     370             :         pthread_threadid_np(nullptr, &tid);
     371             :     }
     372             :     else
     373             :     {
     374             :         tid = pthread_mach_thread_np(pthread_self());
     375             :     }
     376             : #    else
     377             :     pthread_threadid_np(nullptr, &tid);
     378             : #    endif
     379             :     return static_cast<size_t>(tid);
     380             : #else // Default to standard C++11 (other Unix)
     381             :     return static_cast<size_t>(std::hash<std::thread::id>()(std::this_thread::get_id()));
     382             : #endif
     383             : }
     384             : 
     385             : // Return current thread id as size_t (from thread local storage)
     386           0 : SPDLOG_INLINE size_t thread_id() SPDLOG_NOEXCEPT
     387             : {
     388             : #if defined(SPDLOG_NO_TLS)
     389             :     return _thread_id();
     390             : #else // cache thread id in tls
     391           0 :     static thread_local const size_t tid = _thread_id();
     392           0 :     return tid;
     393             : #endif
     394             : }
     395             : 
     396             : // This is avoid msvc issue in sleep_for that happens if the clock changes.
     397             : // See https://github.com/gabime/spdlog/issues/609
     398             : SPDLOG_INLINE void sleep_for_millis(unsigned int milliseconds) SPDLOG_NOEXCEPT
     399             : {
     400             : #if defined(_WIN32)
     401             :     ::Sleep(milliseconds);
     402             : #else
     403             :     std::this_thread::sleep_for(std::chrono::milliseconds(milliseconds));
     404             : #endif
     405             : }
     406             : 
     407             : // wchar support for windows file names (SPDLOG_WCHAR_FILENAMES must be defined)
     408             : #if defined(_WIN32) && defined(SPDLOG_WCHAR_FILENAMES)
     409             : SPDLOG_INLINE std::string filename_to_str(const filename_t &filename)
     410             : {
     411             :     memory_buf_t buf;
     412             :     wstr_to_utf8buf(filename, buf);
     413             :     return SPDLOG_BUF_TO_STRING(buf);
     414             : }
     415             : #else
     416             : SPDLOG_INLINE std::string filename_to_str(const filename_t &filename)
     417             : {
     418             :     return filename;
     419             : }
     420             : #endif
     421             : 
     422           0 : SPDLOG_INLINE int pid() SPDLOG_NOEXCEPT
     423             : {
     424             : 
     425             : #ifdef _WIN32
     426             :     return conditional_static_cast<int>(::GetCurrentProcessId());
     427             : #else
     428           0 :     return conditional_static_cast<int>(::getpid());
     429             : #endif
     430             : }
     431             : 
     432             : // Determine if the terminal supports colors
     433             : // Based on: https://github.com/agauniyal/rang/
     434           0 : SPDLOG_INLINE bool is_color_terminal() SPDLOG_NOEXCEPT
     435             : {
     436             : #ifdef _WIN32
     437             :     return true;
     438             : #else
     439             : 
     440           0 :     static const bool result = []() {
     441           0 :         const char *env_colorterm_p = std::getenv("COLORTERM");
     442           0 :         if (env_colorterm_p != nullptr)
     443             :         {
     444             :             return true;
     445             :         }
     446             : 
     447           0 :         static constexpr std::array<const char *, 16> terms = {{"ansi", "color", "console", "cygwin", "gnome", "konsole", "kterm", "linux",
     448             :             "msys", "putty", "rxvt", "screen", "vt100", "xterm", "alacritty", "vt102"}};
     449             : 
     450           0 :         const char *env_term_p = std::getenv("TERM");
     451           0 :         if (env_term_p == nullptr)
     452             :         {
     453             :             return false;
     454             :         }
     455             : 
     456           0 :         return std::any_of(terms.begin(), terms.end(), [&](const char *term) { return std::strstr(env_term_p, term) != nullptr; });
     457           0 :     }();
     458             : 
     459           0 :     return result;
     460             : #endif
     461             : }
     462             : 
     463             : // Determine if the terminal attached
     464             : // Source: https://github.com/agauniyal/rang/
     465             : SPDLOG_INLINE bool in_terminal(FILE *file) SPDLOG_NOEXCEPT
     466             : {
     467             : 
     468             : #ifdef _WIN32
     469             :     return ::_isatty(_fileno(file)) != 0;
     470             : #else
     471             :     return ::isatty(fileno(file)) != 0;
     472             : #endif
     473             : }
     474             : 
     475             : #if (defined(SPDLOG_WCHAR_TO_UTF8_SUPPORT) || defined(SPDLOG_WCHAR_FILENAMES)) && defined(_WIN32)
     476             : SPDLOG_INLINE void wstr_to_utf8buf(wstring_view_t wstr, memory_buf_t &target)
     477             : {
     478             :     if (wstr.size() > static_cast<size_t>((std::numeric_limits<int>::max)()) / 2 - 1)
     479             :     {
     480             :         throw_spdlog_ex("UTF-16 string is too big to be converted to UTF-8");
     481             :     }
     482             : 
     483             :     int wstr_size = static_cast<int>(wstr.size());
     484             :     if (wstr_size == 0)
     485             :     {
     486             :         target.resize(0);
     487             :         return;
     488             :     }
     489             : 
     490             :     int result_size = static_cast<int>(target.capacity());
     491             :     if ((wstr_size + 1) * 2 > result_size)
     492             :     {
     493             :         result_size = ::WideCharToMultiByte(CP_UTF8, 0, wstr.data(), wstr_size, NULL, 0, NULL, NULL);
     494             :     }
     495             : 
     496             :     if (result_size > 0)
     497             :     {
     498             :         target.resize(result_size);
     499             :         result_size = ::WideCharToMultiByte(CP_UTF8, 0, wstr.data(), wstr_size, target.data(), result_size, NULL, NULL);
     500             : 
     501             :         if (result_size > 0)
     502             :         {
     503             :             target.resize(result_size);
     504             :             return;
     505             :         }
     506             :     }
     507             : 
     508             :     throw_spdlog_ex(fmt_lib::format("WideCharToMultiByte failed. Last error: {}", ::GetLastError()));
     509             : }
     510             : 
     511             : SPDLOG_INLINE void utf8_to_wstrbuf(string_view_t str, wmemory_buf_t &target)
     512             : {
     513             :     if (str.size() > static_cast<size_t>((std::numeric_limits<int>::max)()) - 1)
     514             :     {
     515             :         throw_spdlog_ex("UTF-8 string is too big to be converted to UTF-16");
     516             :     }
     517             : 
     518             :     int str_size = static_cast<int>(str.size());
     519             :     if (str_size == 0)
     520             :     {
     521             :         target.resize(0);
     522             :         return;
     523             :     }
     524             : 
     525             :     // find the size to allocate for the result buffer
     526             :     int result_size = ::MultiByteToWideChar(CP_UTF8, MB_ERR_INVALID_CHARS, str.data(), str_size, NULL, 0);
     527             : 
     528             :     if (result_size > 0)
     529             :     {
     530             :         target.resize(result_size);
     531             :         result_size = ::MultiByteToWideChar(CP_UTF8, MB_ERR_INVALID_CHARS, str.data(), str_size, target.data(), result_size);
     532             :         if (result_size > 0)
     533             :         {
     534             :             assert(result_size == target.size());
     535             :             return;
     536             :         }
     537             :     }
     538             : 
     539             :     throw_spdlog_ex(fmt_lib::format("MultiByteToWideChar failed. Last error: {}", ::GetLastError()));
     540             : }
     541             : #endif // (defined(SPDLOG_WCHAR_TO_UTF8_SUPPORT) || defined(SPDLOG_WCHAR_FILENAMES)) && defined(_WIN32)
     542             : 
     543             : // return true on success
     544             : static SPDLOG_INLINE bool mkdir_(const filename_t &path)
     545             : {
     546             : #ifdef _WIN32
     547             : #    ifdef SPDLOG_WCHAR_FILENAMES
     548             :     return ::_wmkdir(path.c_str()) == 0;
     549             : #    else
     550             :     return ::_mkdir(path.c_str()) == 0;
     551             : #    endif
     552             : #else
     553             :     return ::mkdir(path.c_str(), mode_t(0755)) == 0;
     554             : #endif
     555             : }
     556             : 
     557             : // create the given directory - and all directories leading to it
     558             : // return true on success or if the directory already exists
     559             : SPDLOG_INLINE bool create_dir(const filename_t &path)
     560             : {
     561             :     if (path_exists(path))
     562             :     {
     563             :         return true;
     564             :     }
     565             : 
     566             :     if (path.empty())
     567             :     {
     568             :         return false;
     569             :     }
     570             : 
     571             :     size_t search_offset = 0;
     572             :     do
     573             :     {
     574             :         auto token_pos = path.find_first_of(folder_seps_filename, search_offset);
     575             :         // treat the entire path as a folder if no folder separator not found
     576             :         if (token_pos == filename_t::npos)
     577             :         {
     578             :             token_pos = path.size();
     579             :         }
     580             : 
     581             :         auto subdir = path.substr(0, token_pos);
     582             : 
     583             :         if (!subdir.empty() && !path_exists(subdir) && !mkdir_(subdir))
     584             :         {
     585             :             return false; // return error if failed creating dir
     586             :         }
     587             :         search_offset = token_pos + 1;
     588             :     } while (search_offset < path.size());
     589             : 
     590             :     return true;
     591             : }
     592             : 
     593             : // Return directory name from given path or empty string
     594             : // "abc/file" => "abc"
     595             : // "abc/" => "abc"
     596             : // "abc" => ""
     597             : // "abc///" => "abc//"
     598             : SPDLOG_INLINE filename_t dir_name(const filename_t &path)
     599             : {
     600             :     auto pos = path.find_last_of(folder_seps_filename);
     601             :     return pos != filename_t::npos ? path.substr(0, pos) : filename_t{};
     602             : }
     603             : 
     604             : std::string SPDLOG_INLINE getenv(const char *field)
     605             : {
     606             : 
     607             : #if defined(_MSC_VER)
     608             : #    if defined(__cplusplus_winrt)
     609             :     return std::string{}; // not supported under uwp
     610             : #    else
     611             :     size_t len = 0;
     612             :     char buf[128];
     613             :     bool ok = ::getenv_s(&len, buf, sizeof(buf), field) == 0;
     614             :     return ok ? buf : std::string{};
     615             : #    endif
     616             : #else // revert to getenv
     617             :     char *buf = ::getenv(field);
     618             :     return buf ? buf : std::string{};
     619             : #endif
     620             : }
     621             : 
     622             : // Do fsync by FILE handlerpointer
     623             : // Return true on success
     624             : SPDLOG_INLINE bool fsync(FILE *fp)
     625             : {
     626             : #ifdef _WIN32
     627             :     return FlushFileBuffers(reinterpret_cast<HANDLE>(_get_osfhandle(_fileno(fp)))) != 0;
     628             : #else
     629             :     return ::fsync(fileno(fp)) == 0;
     630             : #endif
     631             : }
     632             : 
     633             : } // namespace os
     634             : } // namespace details
     635             : } // namespace spdlog

Generated by: LCOV version 1.14