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 <spdlog/common.h>
8
9 #include <cstdio>
10 #include <ctime>
11 #include <functional>
12 #include <string>
13 #include <stdio.h>
14 #include <string.h>
15 #include <sys/stat.h>
16
17
18 #ifdef _WIN32
19
20 #ifndef NOMINMAX
21 #define NOMINMAX //prevent windows redefining min/max
22 #endif
23
24 #ifndef WIN32_LEAN_AND_MEAN
25 #define WIN32_LEAN_AND_MEAN
26 #endif
27 #include <windows.h>
28
29 #ifdef __MINGW32__
30 #include <share.h>
31 #endif
32
33 #include <sys/types.h>
34 #include <io.h>
35
36 #elif __linux__
37
38 #include <sys/syscall.h> //Use gettid() syscall under linux to get thread id
39 #include <unistd.h>
40 #include <chrono>
41
42 #elif defined(_AIX)
43 #include <pthread.h> // for pthread_getthreadid_np
44
45 #elif defined(__DragonFly__) || defined(__FreeBSD__)
46 #include <pthread_np.h> // for pthread_getthreadid_np
47
48 #elif defined(__NetBSD__)
49 #include <lwp.h> // for _lwp_self
50
51 #elif defined(__OpenBSD__)
52 #include <unistd.h> // for getthrid
53
54 #elif defined(__sun)
55 #include <thread.h> // for thr_self
56
57 #else
58 #include <thread>
59
60 #endif
61
62 namespace spdlog
63 {
64 namespace details
65 {
66 namespace os
67 {
68
now()69 inline spdlog::log_clock::time_point now()
70 {
71
72 #if defined __linux__ && defined SPDLOG_CLOCK_COARSE
73 timespec ts;
74 ::clock_gettime(CLOCK_REALTIME_COARSE, &ts);
75 return std::chrono::time_point<log_clock, typename log_clock::duration>(
76 std::chrono::duration_cast<typename log_clock::duration>(
77 std::chrono::seconds(ts.tv_sec) + std::chrono::nanoseconds(ts.tv_nsec)));
78
79
80 #else
81 return log_clock::now();
82 #endif
83
84 }
localtime(const std::time_t & time_tt)85 inline std::tm localtime(const std::time_t &time_tt)
86 {
87
88 #ifdef _WIN32
89 std::tm tm;
90 localtime_s(&tm, &time_tt);
91 #else
92 std::tm tm;
93 localtime_r(&time_tt, &tm);
94 #endif
95 return tm;
96 }
97
localtime()98 inline std::tm localtime()
99 {
100 std::time_t now_t = time(nullptr);
101 return localtime(now_t);
102 }
103
104
gmtime(const std::time_t & time_tt)105 inline std::tm gmtime(const std::time_t &time_tt)
106 {
107
108 #ifdef _WIN32
109 std::tm tm;
110 gmtime_s(&tm, &time_tt);
111 #else
112 std::tm tm;
113 gmtime_r(&time_tt, &tm);
114 #endif
115 return tm;
116 }
117
gmtime()118 inline std::tm gmtime()
119 {
120 std::time_t now_t = time(nullptr);
121 return gmtime(now_t);
122 }
123 inline bool operator==(const std::tm& tm1, const std::tm& tm2)
124 {
125 return (tm1.tm_sec == tm2.tm_sec &&
126 tm1.tm_min == tm2.tm_min &&
127 tm1.tm_hour == tm2.tm_hour &&
128 tm1.tm_mday == tm2.tm_mday &&
129 tm1.tm_mon == tm2.tm_mon &&
130 tm1.tm_year == tm2.tm_year &&
131 tm1.tm_isdst == tm2.tm_isdst);
132 }
133
134 inline bool operator!=(const std::tm& tm1, const std::tm& tm2)
135 {
136 return !(tm1 == tm2);
137 }
138
139 // eol definition
140 #if !defined (SPDLOG_EOL)
141 #ifdef _WIN32
142 #define SPDLOG_EOL "\r\n"
143 #else
144 #define SPDLOG_EOL "\n"
145 #endif
146 #endif
147
148 SPDLOG_CONSTEXPR static const char* eol = SPDLOG_EOL;
149 SPDLOG_CONSTEXPR static int eol_size = sizeof(SPDLOG_EOL) - 1;
150
151
152
153 //fopen_s on non windows for writing
fopen_s(FILE ** fp,const filename_t & filename,const filename_t & mode)154 inline int fopen_s(FILE** fp, const filename_t& filename, const filename_t& mode)
155 {
156 #ifdef _WIN32
157 #ifdef SPDLOG_WCHAR_FILENAMES
158 *fp = _wfsopen((filename.c_str()), mode.c_str(), _SH_DENYWR);
159 #else
160 *fp = _fsopen((filename.c_str()), mode.c_str(), _SH_DENYWR);
161 #endif
162 return *fp == nullptr;
163 #else
164 *fp = fopen((filename.c_str()), mode.c_str());
165 return *fp == nullptr;
166 #endif
167 }
168
remove(const filename_t & filename)169 inline int remove(const filename_t &filename)
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
rename(const filename_t & filename1,const filename_t & filename2)178 inline int rename(const filename_t& filename1, const filename_t& filename2)
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
188 //Return if file exists
file_exists(const filename_t & filename)189 inline bool file_exists(const filename_t& filename)
190 {
191 #ifdef _WIN32
192 #ifdef SPDLOG_WCHAR_FILENAMES
193 auto attribs = GetFileAttributesW(filename.c_str());
194 #else
195 auto attribs = GetFileAttributesA(filename.c_str());
196 #endif
197 return (attribs != INVALID_FILE_ATTRIBUTES && !(attribs & FILE_ATTRIBUTE_DIRECTORY));
198 #else //common linux/unix all have the stat system call
199 struct stat buffer;
200 return (stat (filename.c_str(), &buffer) == 0);
201 #endif
202 }
203
204
205
206
207 //Return file size according to open FILE* object
filesize(FILE * f)208 inline size_t filesize(FILE *f)
209 {
210 if (f == nullptr)
211 throw spdlog_ex("Failed getting file size. fd is null");
212 #ifdef _WIN32
213 int fd = _fileno(f);
214 #if _WIN64 //64 bits
215 struct _stat64 st;
216 if (_fstat64(fd, &st) == 0)
217 return st.st_size;
218
219 #else //windows 32 bits
220 long ret = _filelength(fd);
221 if (ret >= 0)
222 return static_cast<size_t>(ret);
223 #endif
224
225 #else // unix
226 int fd = fileno(f);
227 //64 bits(but not in osx, where fstat64 is deprecated)
228 #if (defined(__linux__) || defined(__sun) || defined(_AIX)) && (defined(__LP64__) || defined(_LP64))
229 struct stat64 st;
230 if (fstat64(fd, &st) == 0)
231 return static_cast<size_t>(st.st_size);
232 #else // unix 32 bits or osx
233 struct stat st;
234 if (fstat(fd, &st) == 0)
235 return static_cast<size_t>(st.st_size);
236 #endif
237 #endif
238 throw spdlog_ex("Failed getting file size from fd", errno);
239 }
240
241
242
243
244 //Return utc offset in minutes or throw spdlog_ex on failure
245 inline int utc_minutes_offset(const std::tm& tm = details::os::localtime())
246 {
247
248 #ifdef _WIN32
249 #if _WIN32_WINNT < _WIN32_WINNT_WS08
250 TIME_ZONE_INFORMATION tzinfo;
251 auto rv = GetTimeZoneInformation(&tzinfo);
252 #else
253 DYNAMIC_TIME_ZONE_INFORMATION tzinfo;
254 auto rv = GetDynamicTimeZoneInformation(&tzinfo);
255 #endif
256 if (rv == TIME_ZONE_ID_INVALID)
257 throw spdlog::spdlog_ex("Failed getting timezone info. ", errno);
258
259 int offset = -tzinfo.Bias;
260 if (tm.tm_isdst)
261 offset -= tzinfo.DaylightBias;
262 else
263 offset -= tzinfo.StandardBias;
264 return offset;
265 #else
266
267 #if defined(sun) || defined(__sun)
268 // 'tm_gmtoff' field is BSD extension and it's missing on SunOS/Solaris
269 struct helper
270 {
271 static long int calculate_gmt_offset(const std::tm & localtm = details::os::localtime(), const std::tm & gmtm = details::os::gmtime())
272 {
273 int local_year = localtm.tm_year + (1900 - 1);
274 int gmt_year = gmtm.tm_year + (1900 - 1);
275
276 long int days = (
277 // difference in day of year
278 localtm.tm_yday - gmtm.tm_yday
279
280 // + intervening leap days
281 + ((local_year >> 2) - (gmt_year >> 2))
282 - (local_year / 100 - gmt_year / 100)
283 + ((local_year / 100 >> 2) - (gmt_year / 100 >> 2))
284
285 // + difference in years * 365 */
286 + (long int)(local_year - gmt_year) * 365
287 );
288
289 long int hours = (24 * days) + (localtm.tm_hour - gmtm.tm_hour);
290 long int mins = (60 * hours) + (localtm.tm_min - gmtm.tm_min);
291 long int secs = (60 * mins) + (localtm.tm_sec - gmtm.tm_sec);
292
293 return secs;
294 }
295 };
296
297 long int offset_seconds = helper::calculate_gmt_offset(tm);
298 #else
299 long int offset_seconds = tm.tm_gmtoff;
300 #endif
301
302 return static_cast<int>(offset_seconds / 60);
303 #endif
304 }
305
306 //Return current thread id as size_t
307 //It exists because the std::this_thread::get_id() is much slower(espcially under VS 2013)
thread_id()308 inline size_t thread_id()
309 {
310 #ifdef _WIN32
311 return static_cast<size_t>(::GetCurrentThreadId());
312 #elif __linux__
313 # if defined(__ANDROID__) && defined(__ANDROID_API__) && (__ANDROID_API__ < 21)
314 # define SYS_gettid __NR_gettid
315 # endif
316 return static_cast<size_t>(syscall(SYS_gettid));
317 #elif defined(_AIX) || defined(__DragonFly__) || defined(__FreeBSD__)
318 return static_cast<size_t>(pthread_getthreadid_np());
319 #elif defined(__NetBSD__)
320 return static_cast<size_t>(_lwp_self());
321 #elif defined(__OpenBSD__)
322 return static_cast<size_t>(getthrid());
323 #elif defined(__sun)
324 return static_cast<size_t>(thr_self());
325 #else //Default to standard C++11 (OSX and other Unix)
326 return static_cast<size_t>(std::hash<std::thread::id>()(std::this_thread::get_id()));
327 #endif
328
329
330 }
331
332
333 // wchar support for windows file names (SPDLOG_WCHAR_FILENAMES must be defined)
334 #if defined(_WIN32) && defined(SPDLOG_WCHAR_FILENAMES)
335 #define SPDLOG_FILENAME_T(s) L ## s
filename_to_str(const filename_t & filename)336 inline std::string filename_to_str(const filename_t& filename)
337 {
338 std::wstring_convert<std::codecvt_utf8<wchar_t>, wchar_t> c;
339 return c.to_bytes(filename);
340 }
341 #else
342 #define SPDLOG_FILENAME_T(s) s
filename_to_str(const filename_t & filename)343 inline std::string filename_to_str(const filename_t& filename)
344 {
345 return filename;
346 }
347 #endif
348
349
350 // Return errno string (thread safe)
errno_str(int err_num)351 inline std::string errno_str(int err_num)
352 {
353 char buf[256];
354 SPDLOG_CONSTEXPR auto buf_size = sizeof(buf);
355
356 #ifdef _WIN32
357 if(strerror_s(buf, buf_size, err_num) == 0)
358 return std::string(buf);
359 else
360 return "Unkown error";
361
362 #elif defined(__FreeBSD__) || defined(__APPLE__) || defined(ANDROID) || defined(__QNX__) || \
363 ((_POSIX_C_SOURCE >= 200112L) && ! _GNU_SOURCE) // posix version
364
365 if (strerror_r(err_num, buf, buf_size) == 0)
366 return std::string(buf);
367 else
368 return "Unkown error";
369
370 #else // gnu version (might not use the given buf, so its retval pointer must be used)
371 return std::string(strerror_r(err_num, buf, buf_size));
372 #endif
373 }
374
375 } //os
376 } //details
377 } //spdlog
378