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