00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014 #include <fs/sys/fsLog.h>
00015
00016
00017 #if defined(FS_HAS_FSASSERT)
00018 # include <fs/sys/fsAssert.h>
00019 #else
00020 # include <cassert>
00021 # if !defined(FS_ASSERT)
00022 # define FS_ASSERT(exp) assert(exp)
00023 # endif
00024 # if !defined(FS_ASSERT_MSG)
00025 # define FS_ASSERT_MSG(exp, msg) assert(exp && msg)
00026 # endif
00027 # if !defined(FS_VERIFY)
00028 # define FS_VERIFY(exp) \
00029 { bool bExp = !!(exp); assert(bExp && #exp); bExp; }
00030 # endif
00031 # if !defined(FS_VERIFY_MSG)
00032 # define FS_VERIFY_MSG(exp, msg) \
00033 { bool bExp = !!(exp); assert(bExp && #exp && msg); bExp; }
00034 # endif
00035 # if !defined(FS_STATIC_ASSERT)
00036 # define FS_STATIC_ASSERT(exp) { char error[(exp) ? 1 : 0]; error; }
00037 # endif
00038 #endif
00039 #if !defined(FS_VERIFY_RETURN)
00040 # define FS_VERIFY_RETURN(exp) \
00041 if(!(exp)) { FS_ASSERT_MSG(0, #exp "<return>"); return; }
00042 #endif
00043 #if !defined(FS_VERIFY_RETURN_VAL)
00044 # define FS_VERIFY_RETURN_VAL(exp, ret) \
00045 if(!(exp)) { FS_ASSERT_MSG(0, #exp "<returns:>" #ret); return (ret); }
00046 #endif
00047
00048
00049 #include <queue>
00050 #include <string>
00051 #include <stdarg.h>
00052
00053 #if defined(_WIN32)
00054 # include <windows.h>
00055 #else
00056 # include <time.h>
00057 #endif
00058
00059
00060 #if defined(FS_HAS_FSMEMMGR)
00061 # include <fs/sys/fsMemMgr.h>
00062 #endif
00063
00064 #if (_MSC_VER >= 1400) // MSVC8
00065 # pragma warning(disable : 4996) // function was marked as deprecated
00066 #endif
00067
00068 using namespace fs::sys;
00069
00070 namespace fs { namespace sys {
00071
00072
00073
00075
00077 class LogImpl_t : public Log_t
00078 {
00079 public:
00080
00081 LogImpl_t(unsigned int fMode, size_t uHist, const char *pszFile);
00082 virtual ~LogImpl_t();
00083
00084 virtual void SetTgt(Log_t *pTgt);
00085
00086 protected:
00087
00088 virtual void RegSrc(Log_t *pSrc, bool bReg = true);
00089 virtual void PushLn(const char *pszText, bool bMsgBrk = false);
00090
00091 private:
00092
00093 LogImpl_t();
00094 LogImpl_t(const LogImpl_t &);
00095 LogImpl_t & operator = (const LogImpl_t &);
00096
00097 unsigned int m_fMode;
00098
00099 Log_t *m_pTgt;
00100 typedef std::vector<Log_t *> TSrcs;
00101 TSrcs m_Srcs;
00102
00103 void *m_hFile;
00104
00105 typedef std::deque<std::string> Hist_t;
00106 Hist_t m_Hist;
00107 size_t m_uHist;
00108
00109 size_t m_uWrns;
00110 size_t m_uErrs;
00111 };
00112
00113 }}
00114
00115 LogImpl_t::LogImpl_t(unsigned int fMode, size_t uHist, const char
00116 *pszFile):
00117 m_fMode(fMode),
00118 m_pTgt(0),
00119 m_hFile(0),
00120 m_uHist(uHist),
00121 m_uWrns(0),
00122 m_uErrs(0)
00123 {
00124 if((fMode & LOG_FILE) && pszFile)
00125 m_hFile = static_cast<FILE *>(::fopen(pszFile, "w"));
00126 }
00127
00128 LogImpl_t::~LogImpl_t()
00129 {
00130
00131 SetTgt(0);
00132
00133
00134 while(!m_Srcs.empty())
00135 m_Srcs[0]->SetTgt(0);
00136
00137
00138 char szBuf[96];
00139
00140 ::sprintf(szBuf, "o.LOG %u warning(s), %u error(s) found.",
00141 m_uWrns, m_uErrs);
00142
00143 PushLn(szBuf);
00144
00145
00146 if(m_hFile)
00147 ::fclose(static_cast<FILE *>(m_hFile));
00148 }
00149
00150 void LogImpl_t::SetTgt(Log_t *pTgt)
00151 {
00152 if(pTgt == this || m_pTgt == pTgt)
00153 return;
00154
00155 if(m_pTgt)
00156 m_pTgt->RegSrc(this, false);
00157
00158 m_pTgt = pTgt;
00159 if(!m_pTgt)
00160 return;
00161
00162 if(m_pTgt)
00163 m_pTgt->RegSrc(this);
00164
00165
00166 for(Hist_t::const_iterator it = m_Hist.begin(); it != m_Hist.end(); ++it)
00167 m_pTgt->PushLn((*it).c_str());
00168
00169
00170 Hist_t().swap(m_Hist);
00171 }
00172
00173 void LogImpl_t::RegSrc(Log_t *pSrc, bool bReg)
00174 {
00175 FS_ASSERT(pSrc);
00176
00177 if(bReg)
00178 m_Srcs.push_back(pSrc);
00179 else
00180 {
00181 m_Srcs.erase(
00182 std::remove(m_Srcs.begin(), m_Srcs.end(), pSrc), m_Srcs.end()
00183 );
00184 }
00185 }
00186
00187 void LogImpl_t::PushLn(const char *pszText, bool bMsgBrk)
00188 {
00189 if(bMsgBrk)
00190 {
00191
00192
00193 FS_ASSERT_MSG(0, pszText);
00194 }
00195
00196
00197 bool bWrn = pszText && ::strstr(pszText,"] !.");
00198 bool bErr = pszText && ::strstr(pszText,"] x.");
00199
00200 if((m_fMode & LOG_RTMBRK) && (bWrn || bErr))
00201 {
00202
00203
00204 FS_ASSERT_MSG(0, pszText);
00205 }
00206
00207 if(m_pTgt)
00208 {
00209 m_pTgt->PushLn(pszText);
00210 return;
00211 }
00212
00213
00214 if(m_fMode & LOG_HIST)
00215 {
00216 if(m_Hist.size() > m_uHist)
00217 m_Hist.pop_front();
00218
00219 m_Hist.push_back(pszText);
00220 }
00221 if(m_hFile)
00222 {
00223 ::fputs(pszText, static_cast<FILE *>(m_hFile));
00224 ::fputs("\n", static_cast<FILE *>(m_hFile));
00225 ::fflush(static_cast<FILE *>(m_hFile));
00226 }
00227 if(m_fMode & LOG_STDOUT)
00228 {
00229 ::puts(pszText);
00230 }
00231 #if defined(_WIN32)
00232 if(m_fMode & LOG_DBGOUT)
00233 {
00234 ::OutputDebugStringA(pszText);
00235 ::OutputDebugStringA("\n");
00236 }
00237 #endif
00238
00239
00240 if(bWrn) ++m_uWrns;
00241 if(bErr) ++m_uErrs;
00242 }
00243
00244
00245
00250 Log_t::Log_t(unsigned int fMode, size_t uHist, const char *pszFile):
00251 m_pImpl(new LogImpl_t(fMode, uHist, pszFile))
00252 {
00253 FS_ASSERT_MSG(m_pImpl, "Invalid implementation pointer!");
00254 }
00255
00256 Log_t::Log_t():
00257 m_pImpl(0)
00258 {
00259 }
00260
00261 Log_t::~Log_t()
00262 {
00263
00264
00265 delete m_pImpl;
00266 }
00267
00273 void Log_t::Push(const char *pszFmt, ...)
00274 {
00275 FS_ASSERT_MSG(m_pImpl, "Invalid implementation pointer!");
00276
00277
00278 unsigned int uTimeMs = 0;
00279
00280
00281
00282 #if defined(UNDER_CE)
00283
00285 uTimeMs = ::GetTickCount();
00286
00287 #elif defined(_WIN32)
00288
00289 ::FILETIME tmCreation;
00290 ::FILETIME tmExit;
00291 ::FILETIME tmKernel;
00292 ::FILETIME tmUser;
00293 ::GetProcessTimes(::GetCurrentProcess(), &tmCreation, &tmExit,
00294 &tmKernel, &tmUser);
00295
00296 ::FILETIME tmCurrent;
00297 ::GetSystemTimeAsFileTime(&tmCurrent);
00298
00299 const __int64 nDur100NS =
00300 (static_cast<__int64>
00301 (tmCurrent.dwHighDateTime - tmCreation.dwHighDateTime) << 32) +
00302 (tmCurrent.dwLowDateTime - tmCreation.dwLowDateTime);
00303
00304 uTimeMs = static_cast<unsigned int>(nDur100NS / 10000);
00305
00306 #else
00307
00309 uTimeMs = static_cast<unsigned int>
00310 (1000.0 * ::clock() / CLOCKS_PER_SEC);
00311
00312 #endif
00313
00314 char szBuf[1024];
00315 ::sprintf(szBuf, "[%06u:%03u] ", uTimeMs / 1000, uTimeMs % 1000);
00316
00317
00318 va_list Args;
00319 va_start(Args, pszFmt);
00320 const size_t uSize = sizeof(szBuf);
00321 const size_t uCount = ::strlen(szBuf);
00323 ::_vsnprintf(szBuf + uCount, sizeof(szBuf) - uCount, pszFmt, Args);
00324 va_end(Args);
00325
00326
00327 szBuf[uSize - 2] = szBuf[uSize - 3] = szBuf[uSize - 4] = '.';
00328 szBuf[uSize - 1] = '\0';
00329
00330
00331 for(size_t n = ::strlen(szBuf) - 1; n > 0; --n)
00332 {
00333 if(szBuf[n] == 0x0D || szBuf[n] == 0x0A)
00334 szBuf[n] = '\0';
00335 else
00336 break;
00337 }
00338
00339
00340 bool bMsgBrk = false;
00341 size_t uLen = strlen(szBuf);
00342 if(uLen > 0 && szBuf[uLen - 1] == '@')
00343 {
00344 szBuf[uLen - 1] = '\0';
00345 bMsgBrk = true;
00346 }
00347
00348
00349 m_pImpl->PushLn(szBuf, bMsgBrk);
00350 }
00351
00352 void Log_t::PushLn(const char *pszText, bool bMsgBrk)
00353 {
00354 FS_ASSERT_MSG(m_pImpl, "Invalid implementation pointer!");
00355 m_pImpl->PushLn(pszText, bMsgBrk);
00356 }
00357
00360 void Log_t::SetTgt(Log_t *pTgt)
00361 {
00362 FS_ASSERT_MSG(m_pImpl, "Invalid implementation pointer!");
00363 m_pImpl->SetTgt(pTgt ? pTgt->m_pImpl : 0);
00364 }
00365
00366 void Log_t::RegSrc(Log_t *pSrc, bool bReg)
00367 {
00368 FS_ASSERT_MSG(m_pImpl, "Invalid implementation pointer!");
00369 m_pImpl->RegSrc(pSrc, bReg);
00370 }
00371
00372 #if defined (FS_LOG_ENABLE_MODLOG)
00373 Log_t & fs::sys::ModLog()
00374 {
00375 static Log_t Inst(
00376 FS_LOG_MODLOG_MODE,
00377 FS_LOG_MODLOG_HIST,
00378 FS_LOG_MODLOG_FILE
00379 );
00380
00381 return Inst;
00382 }
00383 #endif
00384