os.h
Go to the documentation of this file.
1 //
2 // Copyright(c) 2015 Gabi Melman.
3 // Distributed under the MIT License (http://opensource.org/licenses/MIT)
4 //
5 #pragma once
6 
7 #include "../common.h"
8 
9 #include <algorithm>
10 #include <chrono>
11 #include <cstdio>
12 #include <cstdlib>
13 #include <cstring>
14 #include <ctime>
15 #include <functional>
16 #include <string>
17 #include <sys/stat.h>
18 #include <sys/types.h>
19 #include <thread>
20 
21 #ifdef _WIN32
22 
23 #ifndef NOMINMAX
24 #define NOMINMAX // prevent windows redefining min/max
25 #endif
26 
27 #ifndef WIN32_LEAN_AND_MEAN
28 #define WIN32_LEAN_AND_MEAN
29 #endif
30 #include <io.h> // _get_osfhandle and _isatty support
31 #include <process.h> // _get_pid support
32 #include <windows.h>
33 
34 #ifdef __MINGW32__
35 #include <share.h>
36 #endif
37 
38 #else // unix
39 
40 #include <fcntl.h>
41 #include <unistd.h>
42 
43 #ifdef __linux__
44 #include <sys/syscall.h> //Use gettid() syscall under linux to get thread id
45 
46 #elif __FreeBSD__
47 #include <sys/thr.h> //Use thr_self() syscall under FreeBSD to get thread id
48 #endif
49 
50 #endif // unix
51 
52 #ifndef __has_feature // Clang - feature checking macros.
53 #define __has_feature(x) 0 // Compatibility with non-clang compilers.
54 #endif
55 
56 namespace spdlog {
57 namespace details {
58 namespace os {
59 
60 inline spdlog::log_clock::time_point now() SPDLOG_NOEXCEPT
61 {
62 
63 #if defined __linux__ && defined SPDLOG_CLOCK_COARSE
64  timespec ts;
65  ::clock_gettime(CLOCK_REALTIME_COARSE, &ts);
66  return std::chrono::time_point<log_clock, typename log_clock::duration>(
67  std::chrono::duration_cast<typename log_clock::duration>(std::chrono::seconds(ts.tv_sec) + std::chrono::nanoseconds(ts.tv_nsec)));
68 
69 #else
70  return log_clock::now();
71 #endif
72 }
73 inline std::tm localtime(const std::time_t &time_tt) SPDLOG_NOEXCEPT
74 {
75 
76 #ifdef _WIN32
77  std::tm tm;
78  localtime_s(&tm, &time_tt);
79 #else
80  std::tm tm;
81  localtime_r(&time_tt, &tm);
82 #endif
83  return tm;
84 }
85 
86 inline std::tm localtime() SPDLOG_NOEXCEPT
87 {
88  std::time_t now_t = time(nullptr);
89  return localtime(now_t);
90 }
91 
92 inline std::tm gmtime(const std::time_t &time_tt) SPDLOG_NOEXCEPT
93 {
94 
95 #ifdef _WIN32
96  std::tm tm;
97  gmtime_s(&tm, &time_tt);
98 #else
99  std::tm tm;
100  gmtime_r(&time_tt, &tm);
101 #endif
102  return tm;
103 }
104 
105 inline std::tm gmtime() SPDLOG_NOEXCEPT
106 {
107  std::time_t now_t = time(nullptr);
108  return gmtime(now_t);
109 }
110 
111 // eol definition
112 #if !defined(SPDLOG_EOL)
113 #ifdef _WIN32
114 #define SPDLOG_EOL "\r\n"
115 #else
116 #define SPDLOG_EOL "\n"
117 #endif
118 #endif
119 
121 
122 // folder separator
123 #ifdef _WIN32
124 SPDLOG_CONSTEXPR static const char folder_sep = '\\';
125 #else
126 SPDLOG_CONSTEXPR static const char folder_sep = '/';
127 #endif
128 
129 inline void prevent_child_fd(FILE *f)
130 {
131 
132 #ifdef _WIN32
133 #if !defined(__cplusplus_winrt)
134  auto file_handle = (HANDLE)_get_osfhandle(_fileno(f));
135  if (!::SetHandleInformation(file_handle, HANDLE_FLAG_INHERIT, 0))
136  throw spdlog_ex("SetHandleInformation failed", errno);
137 #endif
138 #else
139  auto fd = fileno(f);
140  if (fcntl(fd, F_SETFD, FD_CLOEXEC) == -1)
141  {
142  throw spdlog_ex("fcntl with FD_CLOEXEC failed", errno);
143  }
144 #endif
145 }
146 
147 // fopen_s on non windows for writing
148 inline bool fopen_s(FILE **fp, const filename_t &filename, const filename_t &mode)
149 {
150 #ifdef _WIN32
151 #ifdef SPDLOG_WCHAR_FILENAMES
152  *fp = _wfsopen((filename.c_str()), mode.c_str(), _SH_DENYNO);
153 #else
154  *fp = _fsopen((filename.c_str()), mode.c_str(), _SH_DENYNO);
155 #endif
156 #else // unix
157  *fp = fopen((filename.c_str()), mode.c_str());
158 #endif
159 
160 #ifdef SPDLOG_PREVENT_CHILD_FD
161  if (*fp != nullptr)
162  {
163  prevent_child_fd(*fp);
164  }
165 #endif
166  return *fp == nullptr;
167 }
168 
169 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 inline int rename(const filename_t &filename1, const filename_t &filename2) SPDLOG_NOEXCEPT
179 {
180 #if defined(_WIN32) && defined(SPDLOG_WCHAR_FILENAMES)
181  return _wrename(filename1.c_str(), filename2.c_str());
182 #else
183  return std::rename(filename1.c_str(), filename2.c_str());
184 #endif
185 }
186 
187 // Return if file exists
189 {
190 #ifdef _WIN32
191 #ifdef SPDLOG_WCHAR_FILENAMES
192  auto attribs = GetFileAttributesW(filename.c_str());
193 #else
194  auto attribs = GetFileAttributesA(filename.c_str());
195 #endif
196  return (attribs != INVALID_FILE_ATTRIBUTES && !(attribs & FILE_ATTRIBUTE_DIRECTORY));
197 #else // common linux/unix all have the stat system call
198  struct stat buffer;
199  return (stat(filename.c_str(), &buffer) == 0);
200 #endif
201 }
202 
203 // Return file size according to open FILE* object
204 inline size_t filesize(FILE *f)
205 {
206  if (f == nullptr)
207  {
208  throw spdlog_ex("Failed getting file size. fd is null");
209  }
210 #if defined(_WIN32) && !defined(__CYGWIN__)
211  int fd = _fileno(f);
212 #if _WIN64 // 64 bits
213  __int64 ret = _filelengthi64(fd);
214  if (ret >= 0)
215  {
216  return static_cast<size_t>(ret);
217  }
218 
219 #else // windows 32 bits
220  long ret = _filelength(fd);
221  if (ret >= 0)
222  {
223  return static_cast<size_t>(ret);
224  }
225 #endif
226 
227 #else // unix
228  int fd = fileno(f);
229 // 64 bits(but not in osx or cygwin, where fstat64 is deprecated)
230 #if !defined(__FreeBSD__) && !defined(__APPLE__) && (defined(__x86_64__) || defined(__ppc64__)) && !defined(__CYGWIN__)
231  struct stat64 st;
232  if (fstat64(fd, &st) == 0)
233  {
234  return static_cast<size_t>(st.st_size);
235  }
236 #else // unix 32 bits or cygwin
237  struct stat st;
238 
239  if (fstat(fd, &st) == 0)
240  {
241  return static_cast<size_t>(st.st_size);
242  }
243 #endif
244 #endif
245  throw spdlog_ex("Failed getting file size from fd", errno);
246 }
247 
248 // Return utc offset in minutes or throw spdlog_ex on failure
249 inline int utc_minutes_offset(const std::tm &tm = details::os::localtime())
250 {
251 
252 #ifdef _WIN32
253 #if _WIN32_WINNT < _WIN32_WINNT_WS08
254  TIME_ZONE_INFORMATION tzinfo;
255  auto rv = GetTimeZoneInformation(&tzinfo);
256 #else
257  DYNAMIC_TIME_ZONE_INFORMATION tzinfo;
258  auto rv = GetDynamicTimeZoneInformation(&tzinfo);
259 #endif
260  if (rv == TIME_ZONE_ID_INVALID)
261  throw spdlog::spdlog_ex("Failed getting timezone info. ", errno);
262 
263  int offset = -tzinfo.Bias;
264  if (tm.tm_isdst)
265  {
266  offset -= tzinfo.DaylightBias;
267  }
268  else
269  {
270  offset -= tzinfo.StandardBias;
271  }
272  return offset;
273 #else
274 
275 #if defined(sun) || defined(__sun) || defined(_AIX)
276  // 'tm_gmtoff' field is BSD extension and it's missing on SunOS/Solaris
277  struct helper
278  {
279  static long int calculate_gmt_offset(const std::tm &localtm = details::os::localtime(), const std::tm &gmtm = details::os::gmtime())
280  {
281  int local_year = localtm.tm_year + (1900 - 1);
282  int gmt_year = gmtm.tm_year + (1900 - 1);
283 
284  long int days = (
285  // difference in day of year
286  localtm.tm_yday -
287  gmtm.tm_yday
288 
289  // + intervening leap days
290  + ((local_year >> 2) - (gmt_year >> 2)) - (local_year / 100 - gmt_year / 100) +
291  ((local_year / 100 >> 2) - (gmt_year / 100 >> 2))
292 
293  // + difference in years * 365 */
294  + (long int)(local_year - gmt_year) * 365);
295 
296  long int hours = (24 * days) + (localtm.tm_hour - gmtm.tm_hour);
297  long int mins = (60 * hours) + (localtm.tm_min - gmtm.tm_min);
298  long int secs = (60 * mins) + (localtm.tm_sec - gmtm.tm_sec);
299 
300  return secs;
301  }
302  };
303 
304  auto offset_seconds = helper::calculate_gmt_offset(tm);
305 #else
306  auto offset_seconds = tm.tm_gmtoff;
307 #endif
308 
309  return static_cast<int>(offset_seconds / 60);
310 #endif
311 }
312 
313 // Return current thread id as size_t
314 // It exists because the std::this_thread::get_id() is much slower(especially
315 // under VS 2013)
317 {
318 #ifdef _WIN32
319  return static_cast<size_t>(::GetCurrentThreadId());
320 #elif __linux__
321 #if defined(__ANDROID__) && defined(__ANDROID_API__) && (__ANDROID_API__ < 21)
322 #define SYS_gettid __NR_gettid
323 #endif
324  return static_cast<size_t>(syscall(SYS_gettid));
325 #elif __FreeBSD__
326  long tid;
327  thr_self(&tid);
328  return static_cast<size_t>(tid);
329 #elif __APPLE__
330  uint64_t tid;
331  pthread_threadid_np(nullptr, &tid);
332  return static_cast<size_t>(tid);
333 #else // Default to standard C++11 (other Unix)
334  return static_cast<size_t>(std::hash<std::thread::id>()(std::this_thread::get_id()));
335 #endif
336 }
337 
338 // Return current thread id as size_t (from thread local storage)
339 inline size_t thread_id() SPDLOG_NOEXCEPT
340 {
341 #if defined(SPDLOG_NO_TLS)
342  return _thread_id();
343 #else // cache thread id in tls
344  static thread_local const size_t tid = _thread_id();
345  return tid;
346 #endif
347 }
348 
349 // This is avoid msvc issue in sleep_for that happens if the clock changes.
350 // See https://github.com/gabime/spdlog/issues/609
352 {
353 #if defined(_WIN32)
354  ::Sleep(milliseconds);
355 #else
356  std::this_thread::sleep_for(std::chrono::milliseconds(milliseconds));
357 #endif
358 }
359 
360 // wchar support for windows file names (SPDLOG_WCHAR_FILENAMES must be defined)
361 #if defined(_WIN32) && defined(SPDLOG_WCHAR_FILENAMES)
362 #define SPDLOG_FILENAME_T(s) L##s
364 {
365  std::wstring_convert<std::codecvt_utf8<wchar_t>, wchar_t> c;
366  return c.to_bytes(filename);
367 }
368 #else
369 #define SPDLOG_FILENAME_T(s) s
370 inline std::string filename_to_str(const filename_t &filename)
371 {
372  return filename;
373 }
374 #endif
375 
376 inline int pid()
377 {
378 
379 #ifdef _WIN32
380  return static_cast<int>(::GetCurrentProcessId());
381 #else
382  return static_cast<int>(::getpid());
383 #endif
384 }
385 
386 // Determine if the terminal supports colors
387 // Source: https://github.com/agauniyal/rang/
389 {
390 #ifdef _WIN32
391  return true;
392 #else
393  static constexpr const char *Terms[] = {
394  "ansi", "color", "console", "cygwin", "gnome", "konsole", "kterm", "linux", "msys", "putty", "rxvt", "screen", "vt100", "xterm"};
395 
396  const char *env_p = std::getenv("TERM");
397  if (env_p == nullptr)
398  {
399  return false;
400  }
401 
402  static const bool result =
403  std::any_of(std::begin(Terms), std::end(Terms), [&](const char *term) { return std::strstr(env_p, term) != nullptr; });
404  return result;
405 #endif
406 }
407 
408 // Detrmine if the terminal attached
409 // Source: https://github.com/agauniyal/rang/
410 inline bool in_terminal(FILE *file) SPDLOG_NOEXCEPT
411 {
412 
413 #ifdef _WIN32
414  return _isatty(_fileno(file)) != 0;
415 #else
416  return isatty(fileno(file)) != 0;
417 #endif
418 }
419 } // namespace os
420 } // namespace details
421 } // namespace spdlog
bool file_exists(const filename_t &filename) SPDLOG_NOEXCEPT
Definition: os.h:188
size_t _thread_id() SPDLOG_NOEXCEPT
Definition: os.h:316
Definition: posix.h:188
std::tm gmtime(const std::time_t &time_tt) SPDLOG_NOEXCEPT
Definition: os.h:92
static QCString result
std::string string
Definition: nybbler.cc:12
size_t filesize(FILE *f)
Definition: os.h:204
int errno
Contains the last error code.
Definition: structcmd.h:53
static SPDLOG_CONSTEXPR const char * default_eol
Definition: os.h:120
string filename
Definition: train.py:213
null gmtime_s(...)
Definition: time.h:25
#define SPDLOG_EOL
Definition: os.h:116
null gmtime_r(...)
Definition: time.h:24
null localtime_s(...)
Definition: time.h:23
int utc_minutes_offset(const std::tm &tm=details::os::localtime())
Definition: os.h:249
void prevent_child_fd(FILE *f)
Definition: os.h:129
Definition: async.h:27
decltype(auto) constexpr end(T &&obj)
ADL-aware version of std::end.
Definition: StdUtils.h:72
internal::basic_buffer< FMT_CHAR(S)> buffer
Definition: printf.h:757
int rename(const filename_t &filename1, const filename_t &filename2) SPDLOG_NOEXCEPT
Definition: os.h:178
second seconds
Alias for common language habits.
Definition: spacetime.h:83
static const char * days[]
bool fopen_s(FILE **fp, const filename_t &filename, const filename_t &mode)
Definition: os.h:148
std::string getenv(std::string const &name)
Definition: getenv.cc:15
std::string filename_t
Definition: common.h:202
spdlog::log_clock::time_point now() SPDLOG_NOEXCEPT
Definition: os.h:60
unsigned __int64 uint64_t
Definition: stdint.h:136
int remove(const filename_t &filename) SPDLOG_NOEXCEPT
Definition: os.h:169
bool in_terminal(FILE *file) SPDLOG_NOEXCEPT
Definition: os.h:410
millisecond milliseconds
Alias for common language habits.
Definition: spacetime.h:100
static SPDLOG_CONSTEXPR const char folder_sep
Definition: os.h:126
bool is_color_terminal() SPDLOG_NOEXCEPT
Definition: os.h:388
size_t thread_id() SPDLOG_NOEXCEPT
Definition: os.h:339
#define SPDLOG_NOEXCEPT
Definition: common.h:35
#define SPDLOG_CONSTEXPR
Definition: common.h:36
decltype(auto) constexpr begin(T &&obj)
ADL-aware version of std::begin.
Definition: StdUtils.h:67
std::tm localtime(const std::time_t &time_tt) SPDLOG_NOEXCEPT
Definition: os.h:73
void sleep_for_millis(int milliseconds) SPDLOG_NOEXCEPT
Definition: os.h:351
std::string filename_to_str(const filename_t &filename)
Definition: os.h:370
nanosecond nanoseconds
Alias for common language habits.
Definition: spacetime.h:134