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