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