1 |
#pragma once |
2 |
#include <cassert> |
3 |
#include <cstring> |
4 |
#include <cstdio> |
5 |
#include <sstream> |
6 |
#include <fcntl.h> |
7 |
#include <sys/stat.h> |
8 |
|
9 |
#ifndef PLOG_ENABLE_WCHAR_INPUT |
10 |
# ifdef _WIN32 |
11 |
# define PLOG_ENABLE_WCHAR_INPUT 1 |
12 |
# else |
13 |
# define PLOG_ENABLE_WCHAR_INPUT 0 |
14 |
# endif |
15 |
#endif |
16 |
|
17 |
#ifdef _WIN32 |
18 |
# include <plog/WinApi.h> |
19 |
# include <time.h> |
20 |
# include <sys/timeb.h> |
21 |
# include <io.h> |
22 |
# include <share.h> |
23 |
#else |
24 |
# include <unistd.h> |
25 |
# include <sys/syscall.h> |
26 |
# include <sys/time.h> |
27 |
# include <pthread.h> |
28 |
# if PLOG_ENABLE_WCHAR_INPUT |
29 |
# include <iconv.h> |
30 |
# endif |
31 |
#endif |
32 |
|
33 |
#ifdef _WIN32 |
34 |
# define _PLOG_NSTR(x) L##x |
35 |
# define PLOG_NSTR(x) _PLOG_NSTR(x) |
36 |
#else |
37 |
# define PLOG_NSTR(x) x |
38 |
#endif |
39 |
|
40 |
namespace plog |
41 |
{ |
42 |
namespace util |
43 |
{ |
44 |
#ifdef _WIN32 |
45 |
typedef std::wstring nstring; |
46 |
typedef std::wstringstream nstringstream; |
47 |
typedef wchar_t nchar; |
48 |
#else |
49 |
typedef std::string nstring; |
50 |
typedef std::stringstream nstringstream; |
51 |
typedef char nchar; |
52 |
#endif |
53 |
|
54 |
inline void localtime_s(struct tm* t, const time_t* time) |
55 |
{ |
56 |
#if defined(_WIN32) && defined(__BORLANDC__) |
57 |
::localtime_s(time, t); |
58 |
#elif defined(_WIN32) && defined(__MINGW32__) && !defined(__MINGW64_VERSION_MAJOR) |
59 |
*t = *::localtime(time); |
60 |
#elif defined(_WIN32) |
61 |
::localtime_s(t, time); |
62 |
#else |
63 |
::localtime_r(time, t); |
64 |
#endif |
65 |
} |
66 |
|
67 |
#ifdef _WIN32 |
68 |
typedef timeb Time; |
69 |
|
70 |
inline void ftime(Time* t) |
71 |
{ |
72 |
::ftime(t); |
73 |
} |
74 |
#else |
75 |
struct Time |
76 |
{ |
77 |
time_t time; |
78 |
unsigned short millitm; |
79 |
}; |
80 |
|
81 |
inline void ftime(Time* t) |
82 |
{ |
83 |
timeval tv; |
84 |
::gettimeofday(&tv, NULL); |
85 |
|
86 |
t->time = tv.tv_sec; |
87 |
t->millitm = static_cast<unsigned short>(tv.tv_usec / 1000); |
88 |
} |
89 |
#endif |
90 |
|
91 |
inline unsigned int gettid() |
92 |
{ |
93 |
#ifdef _WIN32 |
94 |
return GetCurrentThreadId(); |
95 |
#elif defined(__unix__) |
96 |
return static_cast<unsigned int>(::syscall(__NR_gettid)); |
97 |
#elif defined(__APPLE__) |
98 |
uint64_t tid64; |
99 |
pthread_threadid_np(NULL, &tid64); |
100 |
return static_cast<unsigned int>(tid64); |
101 |
#endif |
102 |
} |
103 |
|
104 |
#if PLOG_ENABLE_WCHAR_INPUT && !defined(_WIN32) |
105 |
inline std::string toNarrow(const wchar_t* wstr) |
106 |
{ |
107 |
size_t wlen = ::wcslen(wstr); |
108 |
std::string str(wlen * sizeof(wchar_t), 0); |
109 |
|
110 |
if (!str.empty()) |
111 |
{ |
112 |
const char* in = reinterpret_cast<const char*>(&wstr[0]); |
113 |
char* out = &str[0]; |
114 |
size_t inBytes = wlen * sizeof(wchar_t); |
115 |
size_t outBytes = str.size(); |
116 |
|
117 |
iconv_t cd = ::iconv_open("UTF-8", "WCHAR_T"); |
118 |
::iconv(cd, const_cast<char**>(&in), &inBytes, &out, &outBytes); |
119 |
::iconv_close(cd); |
120 |
|
121 |
str.resize(str.size() - outBytes); |
122 |
} |
123 |
|
124 |
return str; |
125 |
} |
126 |
#endif |
127 |
|
128 |
#ifdef _WIN32 |
129 |
inline std::wstring toWide(const char* str) |
130 |
{ |
131 |
size_t len = ::strlen(str); |
132 |
std::wstring wstr(len, 0); |
133 |
|
134 |
if (!wstr.empty()) |
135 |
{ |
136 |
int wlen = MultiByteToWideChar(codePage::kActive, 0, str, static_cast<int>(len), &wstr[0], static_cast<int>(wstr.size())); |
137 |
wstr.resize(wlen); |
138 |
} |
139 |
|
140 |
return wstr; |
141 |
} |
142 |
|
143 |
inline std::string toUTF8(const std::wstring& wstr) |
144 |
{ |
145 |
std::string str(wstr.size() * sizeof(wchar_t), 0); |
146 |
|
147 |
if (!str.empty()) |
148 |
{ |
149 |
int len = WideCharToMultiByte(codePage::kUTF8, 0, wstr.c_str(), static_cast<int>(wstr.size()), &str[0], static_cast<int>(str.size()), 0, 0); |
150 |
str.resize(len); |
151 |
} |
152 |
|
153 |
return str; |
154 |
} |
155 |
#endif |
156 |
|
157 |
inline std::string processFuncName(const char* func) |
158 |
{ |
159 |
#if (defined(_WIN32) && !defined(__MINGW32__)) || defined(__OBJC__) |
160 |
return std::string(func); |
161 |
#else |
162 |
const char* funcBegin = func; |
163 |
const char* funcEnd = ::strchr(funcBegin, '('); |
164 |
|
165 |
if (!funcEnd) |
166 |
{ |
167 |
return std::string(func); |
168 |
} |
169 |
|
170 |
for (const char* i = funcEnd - 1; i >= funcBegin; --i) // search backwards for the first space char |
171 |
{ |
172 |
if (*i == ' ') |
173 |
{ |
174 |
funcBegin = i + 1; |
175 |
break; |
176 |
} |
177 |
} |
178 |
|
179 |
return std::string(funcBegin, funcEnd); |
180 |
#endif |
181 |
} |
182 |
|
183 |
inline const nchar* findExtensionDot(const nchar* fileName) |
184 |
{ |
185 |
#ifdef _WIN32 |
186 |
return std::wcsrchr(fileName, L'.'); |
187 |
#else |
188 |
return std::strrchr(fileName, '.'); |
189 |
#endif |
190 |
} |
191 |
|
192 |
inline void splitFileName(const nchar* fileName, nstring& fileNameNoExt, nstring& fileExt) |
193 |
{ |
194 |
const nchar* dot = findExtensionDot(fileName); |
195 |
|
196 |
if (dot) |
197 |
{ |
198 |
fileNameNoExt.assign(fileName, dot); |
199 |
fileExt.assign(dot + 1); |
200 |
} |
201 |
else |
202 |
{ |
203 |
fileNameNoExt.assign(fileName); |
204 |
fileExt.clear(); |
205 |
} |
206 |
} |
207 |
|
208 |
class NonCopyable |
209 |
{ |
210 |
protected: |
211 |
NonCopyable() |
212 |
{ |
213 |
} |
214 |
|
215 |
private: |
216 |
NonCopyable(const NonCopyable&); |
217 |
NonCopyable& operator=(const NonCopyable&); |
218 |
}; |
219 |
|
220 |
class File : NonCopyable |
221 |
{ |
222 |
public: |
223 |
File() : m_file(-1) |
224 |
{ |
225 |
} |
226 |
|
227 |
File(const nchar* fileName) : m_file(-1) |
228 |
{ |
229 |
open(fileName); |
230 |
} |
231 |
|
232 |
~File() |
233 |
{ |
234 |
close(); |
235 |
} |
236 |
|
237 |
off_t open(const nchar* fileName) |
238 |
{ |
239 |
#if defined(_WIN32) && (defined(__BORLANDC__) || defined(__MINGW32__)) |
240 |
m_file = ::_wsopen(fileName, _O_CREAT | _O_WRONLY | _O_BINARY, SH_DENYWR, _S_IREAD | _S_IWRITE); |
241 |
#elif defined(_WIN32) |
242 |
::_wsopen_s(&m_file, fileName, _O_CREAT | _O_WRONLY | _O_BINARY, _SH_DENYWR, _S_IREAD | _S_IWRITE); |
243 |
#else |
244 |
m_file = ::open(fileName, O_CREAT | O_WRONLY, S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH); |
245 |
#endif |
246 |
return seek(0, SEEK_END); |
247 |
} |
248 |
|
249 |
int write(const void* buf, size_t count) |
250 |
{ |
251 |
#ifdef _WIN32 |
252 |
return m_file != -1 ? ::_write(m_file, buf, static_cast<unsigned int>(count)) : -1; |
253 |
#else |
254 |
return m_file != -1 ? static_cast<int>(::write(m_file, buf, count)) : -1; |
255 |
#endif |
256 |
} |
257 |
|
258 |
template<class CharType> |
259 |
int write(const std::basic_string<CharType>& str) |
260 |
{ |
261 |
return write(str.data(), str.size() * sizeof(CharType)); |
262 |
} |
263 |
|
264 |
off_t seek(off_t offset, int whence) |
265 |
{ |
266 |
#ifdef _WIN32 |
267 |
return m_file != -1 ? ::_lseek(m_file, offset, whence) : -1; |
268 |
#else |
269 |
return m_file != -1 ? ::lseek(m_file, offset, whence) : -1; |
270 |
#endif |
271 |
} |
272 |
|
273 |
void close() |
274 |
{ |
275 |
if (m_file != -1) |
276 |
{ |
277 |
#ifdef _WIN32 |
278 |
::_close(m_file); |
279 |
#else |
280 |
::close(m_file); |
281 |
#endif |
282 |
m_file = -1; |
283 |
} |
284 |
} |
285 |
|
286 |
static int unlink(const nchar* fileName) |
287 |
{ |
288 |
#ifdef _WIN32 |
289 |
return ::_wunlink(fileName); |
290 |
#else |
291 |
return ::unlink(fileName); |
292 |
#endif |
293 |
} |
294 |
|
295 |
static int rename(const nchar* oldFilename, const nchar* newFilename) |
296 |
{ |
297 |
#ifdef _WIN32 |
298 |
return MoveFileW(oldFilename, newFilename); |
299 |
#else |
300 |
return ::rename(oldFilename, newFilename); |
301 |
#endif |
302 |
} |
303 |
|
304 |
private: |
305 |
int m_file; |
306 |
}; |
307 |
|
308 |
class Mutex : NonCopyable |
309 |
{ |
310 |
public: |
311 |
Mutex() |
312 |
{ |
313 |
#ifdef _WIN32 |
314 |
InitializeCriticalSection(&m_sync); |
315 |
#else |
316 |
::pthread_mutex_init(&m_sync, 0); |
317 |
#endif |
318 |
} |
319 |
|
320 |
~Mutex() |
321 |
{ |
322 |
#ifdef _WIN32 |
323 |
DeleteCriticalSection(&m_sync); |
324 |
#else |
325 |
::pthread_mutex_destroy(&m_sync); |
326 |
#endif |
327 |
} |
328 |
|
329 |
friend class MutexLock; |
330 |
|
331 |
private: |
332 |
void lock() |
333 |
{ |
334 |
#ifdef _WIN32 |
335 |
EnterCriticalSection(&m_sync); |
336 |
#else |
337 |
::pthread_mutex_lock(&m_sync); |
338 |
#endif |
339 |
} |
340 |
|
341 |
void unlock() |
342 |
{ |
343 |
#ifdef _WIN32 |
344 |
LeaveCriticalSection(&m_sync); |
345 |
#else |
346 |
::pthread_mutex_unlock(&m_sync); |
347 |
#endif |
348 |
} |
349 |
|
350 |
private: |
351 |
#ifdef _WIN32 |
352 |
CRITICAL_SECTION m_sync; |
353 |
#else |
354 |
pthread_mutex_t m_sync; |
355 |
#endif |
356 |
}; |
357 |
|
358 |
class MutexLock : NonCopyable |
359 |
{ |
360 |
public: |
361 |
MutexLock(Mutex& mutex) : m_mutex(mutex) |
362 |
{ |
363 |
m_mutex.lock(); |
364 |
} |
365 |
|
366 |
~MutexLock() |
367 |
{ |
368 |
m_mutex.unlock(); |
369 |
} |
370 |
|
371 |
private: |
372 |
Mutex& m_mutex; |
373 |
}; |
374 |
|
375 |
template<class T> |
376 |
class Singleton : NonCopyable |
377 |
{ |
378 |
public: |
379 |
Singleton() |
380 |
{ |
381 |
assert(!m_instance); |
382 |
m_instance = static_cast<T*>(this); |
383 |
} |
384 |
|
385 |
~Singleton() |
386 |
{ |
387 |
assert(m_instance); |
388 |
m_instance = 0; |
389 |
} |
390 |
|
391 |
static T* getInstance() |
392 |
{ |
393 |
return m_instance; |
394 |
} |
395 |
|
396 |
private: |
397 |
static T* m_instance; |
398 |
}; |
399 |
|
400 |
template<class T> |
401 |
T* Singleton<T>::m_instance = NULL; |
402 |
} |
403 |
} |