诸暨麻将添加redis
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 
 

537 lines
14 KiB

  1. // Copyright(c) 2015-present, Gabi Melman & spdlog contributors.
  2. // Distributed under the MIT License (http://opensource.org/licenses/MIT)
  3. #pragma once
  4. #ifndef SPDLOG_HEADER_ONLY
  5. #include <spdlog/details/os.h>
  6. #endif
  7. #include <spdlog/common.h>
  8. #include <algorithm>
  9. #include <chrono>
  10. #include <cstdio>
  11. #include <cstdlib>
  12. #include <cstring>
  13. #include <ctime>
  14. #include <string>
  15. #include <thread>
  16. #include <array>
  17. #include <sys/stat.h>
  18. #include <sys/types.h>
  19. #ifdef _WIN32
  20. #ifndef NOMINMAX
  21. #define NOMINMAX // prevent windows redefining min/max
  22. #endif
  23. #ifndef WIN32_LEAN_AND_MEAN
  24. #define WIN32_LEAN_AND_MEAN
  25. #endif
  26. #include <io.h> // _get_osfhandle and _isatty support
  27. #include <process.h> // _get_pid support
  28. #include <windows.h>
  29. #ifdef __MINGW32__
  30. #include <share.h>
  31. #endif
  32. #if defined(SPDLOG_WCHAR_TO_UTF8_SUPPORT) || defined(SPDLOG_WCHAR_FILENAMES)
  33. #include <limits>
  34. #endif
  35. #include <direct.h> // for _mkdir/_wmkdir
  36. #else // unix
  37. #include <fcntl.h>
  38. #include <unistd.h>
  39. #ifdef __linux__
  40. #include <sys/syscall.h> //Use gettid() syscall under linux to get thread id
  41. #elif defined(_AIX)
  42. #include <pthread.h> // for pthread_getthreadid_np
  43. #elif defined(__DragonFly__) || defined(__FreeBSD__)
  44. #include <pthread_np.h> // for pthread_getthreadid_np
  45. #elif defined(__NetBSD__)
  46. #include <lwp.h> // for _lwp_self
  47. #elif defined(__sun)
  48. #include <thread.h> // for thr_self
  49. #endif
  50. #endif // unix
  51. #ifndef __has_feature // Clang - feature checking macros.
  52. #define __has_feature(x) 0 // Compatibility with non-clang compilers.
  53. #endif
  54. namespace spdlog {
  55. namespace details {
  56. namespace os {
  57. SPDLOG_INLINE spdlog::log_clock::time_point now() SPDLOG_NOEXCEPT
  58. {
  59. #if defined __linux__ && defined SPDLOG_CLOCK_COARSE
  60. timespec ts;
  61. ::clock_gettime(CLOCK_REALTIME_COARSE, &ts);
  62. return std::chrono::time_point<log_clock, typename log_clock::duration>(
  63. std::chrono::duration_cast<typename log_clock::duration>(std::chrono::seconds(ts.tv_sec) + std::chrono::nanoseconds(ts.tv_nsec)));
  64. #else
  65. return log_clock::now();
  66. #endif
  67. }
  68. SPDLOG_INLINE std::tm localtime(const std::time_t &time_tt) SPDLOG_NOEXCEPT
  69. {
  70. #ifdef _WIN32
  71. std::tm tm;
  72. ::localtime_s(&tm, &time_tt);
  73. #else
  74. std::tm tm;
  75. ::localtime_r(&time_tt, &tm);
  76. #endif
  77. return tm;
  78. }
  79. SPDLOG_INLINE std::tm localtime() SPDLOG_NOEXCEPT
  80. {
  81. std::time_t now_t = ::time(nullptr);
  82. return localtime(now_t);
  83. }
  84. SPDLOG_INLINE std::tm gmtime(const std::time_t &time_tt) SPDLOG_NOEXCEPT
  85. {
  86. #ifdef _WIN32
  87. std::tm tm;
  88. ::gmtime_s(&tm, &time_tt);
  89. #else
  90. std::tm tm;
  91. ::gmtime_r(&time_tt, &tm);
  92. #endif
  93. return tm;
  94. }
  95. SPDLOG_INLINE std::tm gmtime() SPDLOG_NOEXCEPT
  96. {
  97. std::time_t now_t = ::time(nullptr);
  98. return gmtime(now_t);
  99. }
  100. #ifdef SPDLOG_PREVENT_CHILD_FD
  101. SPDLOG_INLINE void prevent_child_fd(FILE *f)
  102. {
  103. #ifdef _WIN32
  104. auto file_handle = reinterpret_cast<HANDLE>(_get_osfhandle(::_fileno(f)));
  105. if (!::SetHandleInformation(file_handle, HANDLE_FLAG_INHERIT, 0))
  106. SPDLOG_THROW(spdlog_ex("SetHandleInformation failed", errno));
  107. #else
  108. auto fd = ::fileno(f);
  109. if (::fcntl(fd, F_SETFD, FD_CLOEXEC) == -1)
  110. {
  111. SPDLOG_THROW(spdlog_ex("fcntl with FD_CLOEXEC failed", errno));
  112. }
  113. #endif
  114. }
  115. #endif // SPDLOG_PREVENT_CHILD_FD
  116. // fopen_s on non windows for writing
  117. SPDLOG_INLINE bool fopen_s(FILE **fp, const filename_t &filename, const filename_t &mode)
  118. {
  119. #ifdef _WIN32
  120. #ifdef SPDLOG_WCHAR_FILENAMES
  121. *fp = ::_wfsopen((filename.c_str()), mode.c_str(), _SH_DENYNO);
  122. #else
  123. *fp = ::_fsopen((filename.c_str()), mode.c_str(), _SH_DENYNO);
  124. #endif
  125. #else // unix
  126. *fp = ::fopen((filename.c_str()), mode.c_str());
  127. #endif
  128. #ifdef SPDLOG_PREVENT_CHILD_FD
  129. // prevent child processes from inheriting log file descriptors
  130. if (*fp != nullptr)
  131. {
  132. prevent_child_fd(*fp);
  133. }
  134. #endif
  135. return *fp == nullptr;
  136. }
  137. SPDLOG_INLINE int remove(const filename_t &filename) SPDLOG_NOEXCEPT
  138. {
  139. #if defined(_WIN32) && defined(SPDLOG_WCHAR_FILENAMES)
  140. return ::_wremove(filename.c_str());
  141. #else
  142. return std::remove(filename.c_str());
  143. #endif
  144. }
  145. SPDLOG_INLINE int remove_if_exists(const filename_t &filename) SPDLOG_NOEXCEPT
  146. {
  147. return path_exists(filename) ? remove(filename) : 0;
  148. }
  149. SPDLOG_INLINE int rename(const filename_t &filename1, const filename_t &filename2) SPDLOG_NOEXCEPT
  150. {
  151. #if defined(_WIN32) && defined(SPDLOG_WCHAR_FILENAMES)
  152. return ::_wrename(filename1.c_str(), filename2.c_str());
  153. #else
  154. return std::rename(filename1.c_str(), filename2.c_str());
  155. #endif
  156. }
  157. // Return true if path exists (file or directory)
  158. SPDLOG_INLINE bool path_exists(const filename_t &filename) SPDLOG_NOEXCEPT
  159. {
  160. #ifdef _WIN32
  161. #ifdef SPDLOG_WCHAR_FILENAMES
  162. auto attribs = ::GetFileAttributesW(filename.c_str());
  163. #else
  164. auto attribs = ::GetFileAttributesA(filename.c_str());
  165. #endif
  166. return attribs != INVALID_FILE_ATTRIBUTES;
  167. #else // common linux/unix all have the stat system call
  168. struct stat buffer;
  169. return (::stat(filename.c_str(), &buffer) == 0);
  170. #endif
  171. }
  172. // Return file size according to open FILE* object
  173. SPDLOG_INLINE size_t filesize(FILE *f)
  174. {
  175. if (f == nullptr)
  176. {
  177. SPDLOG_THROW(spdlog_ex("Failed getting file size. fd is null"));
  178. }
  179. #if defined(_WIN32) && !defined(__CYGWIN__)
  180. int fd = ::_fileno(f);
  181. #if _WIN64 // 64 bits
  182. __int64 ret = ::_filelengthi64(fd);
  183. if (ret >= 0)
  184. {
  185. return static_cast<size_t>(ret);
  186. }
  187. #else // windows 32 bits
  188. long ret = ::_filelength(fd);
  189. if (ret >= 0)
  190. {
  191. return static_cast<size_t>(ret);
  192. }
  193. #endif
  194. #else // unix
  195. int fd = ::fileno(f);
  196. // 64 bits(but not in osx or cygwin, where fstat64 is deprecated)
  197. #if (defined(__linux__) || defined(__sun) || defined(_AIX)) && (defined(__LP64__) || defined(_LP64))
  198. struct stat64 st;
  199. if (::fstat64(fd, &st) == 0)
  200. {
  201. return static_cast<size_t>(st.st_size);
  202. }
  203. #else // other unix or linux 32 bits or cygwin
  204. struct stat st;
  205. if (::fstat(fd, &st) == 0)
  206. {
  207. return static_cast<size_t>(st.st_size);
  208. }
  209. #endif
  210. #endif
  211. SPDLOG_THROW(spdlog_ex("Failed getting file size from fd", errno));
  212. }
  213. // Return utc offset in minutes or throw spdlog_ex on failure
  214. SPDLOG_INLINE int utc_minutes_offset(const std::tm &tm)
  215. {
  216. #ifdef _WIN32
  217. #if _WIN32_WINNT < _WIN32_WINNT_WS08
  218. TIME_ZONE_INFORMATION tzinfo;
  219. auto rv = ::GetTimeZoneInformation(&tzinfo);
  220. #else
  221. DYNAMIC_TIME_ZONE_INFORMATION tzinfo;
  222. auto rv = ::GetDynamicTimeZoneInformation(&tzinfo);
  223. #endif
  224. if (rv == TIME_ZONE_ID_INVALID)
  225. SPDLOG_THROW(spdlog::spdlog_ex("Failed getting timezone info. ", errno));
  226. int offset = -tzinfo.Bias;
  227. if (tm.tm_isdst)
  228. {
  229. offset -= tzinfo.DaylightBias;
  230. }
  231. else
  232. {
  233. offset -= tzinfo.StandardBias;
  234. }
  235. return offset;
  236. #else
  237. #if defined(sun) || defined(__sun) || defined(_AIX) || (!defined(_BSD_SOURCE) && !defined(_GNU_SOURCE))
  238. // 'tm_gmtoff' field is BSD extension and it's missing on SunOS/Solaris
  239. struct helper
  240. {
  241. static long int calculate_gmt_offset(const std::tm &localtm = details::os::localtime(), const std::tm &gmtm = details::os::gmtime())
  242. {
  243. int local_year = localtm.tm_year + (1900 - 1);
  244. int gmt_year = gmtm.tm_year + (1900 - 1);
  245. long int days = (
  246. // difference in day of year
  247. localtm.tm_yday -
  248. gmtm.tm_yday
  249. // + intervening leap days
  250. + ((local_year >> 2) - (gmt_year >> 2)) - (local_year / 100 - gmt_year / 100) +
  251. ((local_year / 100 >> 2) - (gmt_year / 100 >> 2))
  252. // + difference in years * 365 */
  253. + (long int)(local_year - gmt_year) * 365);
  254. long int hours = (24 * days) + (localtm.tm_hour - gmtm.tm_hour);
  255. long int mins = (60 * hours) + (localtm.tm_min - gmtm.tm_min);
  256. long int secs = (60 * mins) + (localtm.tm_sec - gmtm.tm_sec);
  257. return secs;
  258. }
  259. };
  260. auto offset_seconds = helper::calculate_gmt_offset(tm);
  261. #else
  262. auto offset_seconds = tm.tm_gmtoff;
  263. #endif
  264. return static_cast<int>(offset_seconds / 60);
  265. #endif
  266. }
  267. // Return current thread id as size_t
  268. // It exists because the std::this_thread::get_id() is much slower(especially
  269. // under VS 2013)
  270. SPDLOG_INLINE size_t _thread_id() SPDLOG_NOEXCEPT
  271. {
  272. #ifdef _WIN32
  273. return static_cast<size_t>(::GetCurrentThreadId());
  274. #elif defined(__linux__)
  275. #if defined(__ANDROID__) && defined(__ANDROID_API__) && (__ANDROID_API__ < 21)
  276. #define SYS_gettid __NR_gettid
  277. #endif
  278. return static_cast<size_t>(::syscall(SYS_gettid));
  279. #elif defined(_AIX) || defined(__DragonFly__) || defined(__FreeBSD__)
  280. return static_cast<size_t>(::pthread_getthreadid_np());
  281. #elif defined(__NetBSD__)
  282. return static_cast<size_t>(::_lwp_self());
  283. #elif defined(__OpenBSD__)
  284. return static_cast<size_t>(::getthrid());
  285. #elif defined(__sun)
  286. return static_cast<size_t>(::thr_self());
  287. #elif __APPLE__
  288. uint64_t tid;
  289. pthread_threadid_np(nullptr, &tid);
  290. return static_cast<size_t>(tid);
  291. #else // Default to standard C++11 (other Unix)
  292. return static_cast<size_t>(std::hash<std::thread::id>()(std::this_thread::get_id()));
  293. #endif
  294. }
  295. // Return current thread id as size_t (from thread local storage)
  296. SPDLOG_INLINE size_t thread_id() SPDLOG_NOEXCEPT
  297. {
  298. #if defined(SPDLOG_NO_TLS)
  299. return _thread_id();
  300. #else // cache thread id in tls
  301. static thread_local const size_t tid = _thread_id();
  302. return tid;
  303. #endif
  304. }
  305. // This is avoid msvc issue in sleep_for that happens if the clock changes.
  306. // See https://github.com/gabime/spdlog/issues/609
  307. SPDLOG_INLINE void sleep_for_millis(int milliseconds) SPDLOG_NOEXCEPT
  308. {
  309. #if defined(_WIN32)
  310. ::Sleep(milliseconds);
  311. #else
  312. std::this_thread::sleep_for(std::chrono::milliseconds(milliseconds));
  313. #endif
  314. }
  315. // wchar support for windows file names (SPDLOG_WCHAR_FILENAMES must be defined)
  316. #if defined(_WIN32) && defined(SPDLOG_WCHAR_FILENAMES)
  317. SPDLOG_INLINE std::string filename_to_str(const filename_t &filename)
  318. {
  319. memory_buf_t buf;
  320. wstr_to_utf8buf(filename, buf);
  321. return fmt::to_string(buf);
  322. }
  323. #else
  324. SPDLOG_INLINE std::string filename_to_str(const filename_t &filename)
  325. {
  326. return filename;
  327. }
  328. #endif
  329. SPDLOG_INLINE int pid() SPDLOG_NOEXCEPT
  330. {
  331. #ifdef _WIN32
  332. return static_cast<int>(::GetCurrentProcessId());
  333. #else
  334. return static_cast<int>(::getpid());
  335. #endif
  336. }
  337. // Determine if the terminal supports colors
  338. // Source: https://github.com/agauniyal/rang/
  339. SPDLOG_INLINE bool is_color_terminal() SPDLOG_NOEXCEPT
  340. {
  341. #ifdef _WIN32
  342. return true;
  343. #else
  344. static constexpr std::array<const char *, 14> Terms = {
  345. {"ansi", "color", "console", "cygwin", "gnome", "konsole", "kterm", "linux", "msys", "putty", "rxvt", "screen", "vt100", "xterm"}};
  346. const char *env_p = std::getenv("TERM");
  347. if (env_p == nullptr)
  348. {
  349. return false;
  350. }
  351. static const bool result =
  352. std::any_of(std::begin(Terms), std::end(Terms), [&](const char *term) { return std::strstr(env_p, term) != nullptr; });
  353. return result;
  354. #endif
  355. }
  356. // Detrmine if the terminal attached
  357. // Source: https://github.com/agauniyal/rang/
  358. SPDLOG_INLINE bool in_terminal(FILE *file) SPDLOG_NOEXCEPT
  359. {
  360. #ifdef _WIN32
  361. return ::_isatty(_fileno(file)) != 0;
  362. #else
  363. return ::isatty(fileno(file)) != 0;
  364. #endif
  365. }
  366. #if (defined(SPDLOG_WCHAR_TO_UTF8_SUPPORT) || defined(SPDLOG_WCHAR_FILENAMES)) && defined(_WIN32)
  367. SPDLOG_INLINE void wstr_to_utf8buf(wstring_view_t wstr, memory_buf_t &target)
  368. {
  369. if (wstr.size() > static_cast<size_t>((std::numeric_limits<int>::max)()))
  370. {
  371. SPDLOG_THROW(spdlog::spdlog_ex("UTF-16 string is too big to be converted to UTF-8"));
  372. }
  373. int wstr_size = static_cast<int>(wstr.size());
  374. if (wstr_size == 0)
  375. {
  376. target.resize(0);
  377. return;
  378. }
  379. int result_size = static_cast<int>(target.capacity());
  380. if ((wstr_size + 1) * 2 > result_size)
  381. {
  382. result_size = ::WideCharToMultiByte(CP_UTF8, 0, wstr.data(), wstr_size, NULL, 0, NULL, NULL);
  383. }
  384. if (result_size > 0)
  385. {
  386. target.resize(result_size);
  387. result_size = ::WideCharToMultiByte(CP_UTF8, 0, wstr.data(), wstr_size, target.data(), result_size, NULL, NULL);
  388. if (result_size > 0)
  389. {
  390. target.resize(result_size);
  391. return;
  392. }
  393. }
  394. SPDLOG_THROW(spdlog::spdlog_ex(fmt::format("WideCharToMultiByte failed. Last error: {}", ::GetLastError())));
  395. }
  396. #endif // (defined(SPDLOG_WCHAR_TO_UTF8_SUPPORT) || defined(SPDLOG_WCHAR_FILENAMES)) && defined(_WIN32)
  397. // return true on success
  398. SPDLOG_INLINE bool mkdir_(const filename_t &path)
  399. {
  400. #ifdef _WIN32
  401. #ifdef SPDLOG_WCHAR_FILENAMES
  402. return ::_wmkdir(path.c_str()) == 0;
  403. #else
  404. return ::_mkdir(path.c_str()) == 0;
  405. #endif
  406. #else
  407. return ::mkdir(path.c_str(), mode_t(0755)) == 0;
  408. #endif
  409. }
  410. // create the given directory - and all directories leading to it
  411. // return true on success or if the directory already exists
  412. SPDLOG_INLINE bool create_dir(filename_t path)
  413. {
  414. if (path_exists(path))
  415. {
  416. return true;
  417. }
  418. if (path.empty())
  419. {
  420. return false;
  421. }
  422. #ifdef _WIN32
  423. // support forward slash in windows
  424. std::replace(path.begin(), path.end(), '/', folder_sep);
  425. #endif
  426. size_t search_offset = 0;
  427. do
  428. {
  429. auto token_pos = path.find(folder_sep, search_offset);
  430. // treat the entire path as a folder if no folder separator not found
  431. if (token_pos == filename_t::npos)
  432. {
  433. token_pos = path.size();
  434. }
  435. auto subdir = path.substr(0, token_pos);
  436. if (!subdir.empty() && !path_exists(subdir) && !mkdir_(subdir))
  437. {
  438. return false; // return error if failed creating dir
  439. }
  440. search_offset = token_pos + 1;
  441. } while (search_offset < path.size());
  442. return true;
  443. }
  444. // Return directory name from given path or empty string
  445. // "abc/file" => "abc"
  446. // "abc/" => "abc"
  447. // "abc" => ""
  448. // "abc///" => "abc//"
  449. SPDLOG_INLINE filename_t dir_name(filename_t path)
  450. {
  451. #ifdef _WIN32
  452. // support forward slash in windows
  453. std::replace(path.begin(), path.end(), '/', folder_sep);
  454. #endif
  455. auto pos = path.find_last_of(folder_sep);
  456. return pos != filename_t::npos ? path.substr(0, pos) : filename_t{};
  457. }
  458. } // namespace os
  459. } // namespace details
  460. } // namespace spdlog