|
|
#include "precomp.h"
#include "logitem.h"
// utility APIs declarations
// these two are identical to _strdate and _strtime respectively
LPCTSTR StrGetDate(LPTSTR pszDate); LPCTSTR StrGetTime(LPTSTR pszTime);
// string constants
const TCHAR c_szCRLF[] = TEXT("\r\n"); const TCHAR c_szSpace[] = TEXT(" "); const TCHAR c_szCommaSpace[] = TEXT(", "); const TCHAR c_szColonColon[] = TEXT("::"); const TCHAR c_szColonSpace[] = TEXT(": "); const TCHAR c_szLine[] = TEXT("line %i");
/////////////////////////////////////////////////////////////////////////////
// CLogItem
TCHAR CLogItem::m_szModule[MAX_PATH]; BYTE CLogItem::m_bStep = 4;
CLogItem::CLogItem(DWORD dwFlags /*= LIF_DEFAULT*/, LPBOOL pfLogLevels /*= NULL*/, UINT cLogLevels /*= 0*/) { if (m_szModule[0] == TEXT('\0')) { GetModuleFileName(GetModuleHandle(g_szModule), m_szModule, countof(m_szModule)); CharLower(m_szModule); }
m_nAbsOffset = 0; m_iRelOffset = 0; m_nLine = 0;
m_rgfLogLevels = NULL; m_cLogLevels = cLogLevels; if (pfLogLevels != NULL) { ASSERT(cLogLevels > 0);
m_rgfLogLevels = new BOOL[m_cLogLevels]; memcpy(m_rgfLogLevels, pfLogLevels, m_cLogLevels * sizeof(BOOL)); } else ASSERT(cLogLevels == 0);
m_nLevel = 0;
SetFlags(dwFlags); }
CLogItem::~CLogItem() { delete[] m_rgfLogLevels; }
/////////////////////////////////////////////////////////////////////////////
// CLogItem operations
LPCTSTR WINAPIV CLogItem::Log(int iLine, LPCTSTR pszFormat ...) { TCHAR szFormat[3 * MAX_PATH], szBuffer[MAX_PATH]; LPCTSTR pszAux; UINT nLen, nAuxLen, cchCRLF; BOOL fPreviousToken;
szFormat[0] = TEXT('\0'); nLen = 0;
if (hasFlag(LIF_NONE)) return NULL;
if (m_rgfLogLevels != NULL && m_nLevel < m_cLogLevels) { ASSERT((int)m_nLevel >= 0);
if (!m_rgfLogLevels[m_nLevel]) return NULL; }
// prepend any CRLF at the beginning
cchCRLF = StrSpn(pszFormat, c_szCRLF); if (cchCRLF > 0) { // special case
if (cchCRLF >= (UINT)StrLen(pszFormat)) { StrCpy(m_szMessage, pszFormat);
if (hasFlag(LIF_DUPLICATEINODS)) OutputDebugString(m_szMessage);
return m_szMessage; }
StrCpyN(&szFormat[nLen], pszFormat, cchCRLF + 1); nLen += cchCRLF;
pszFormat += cchCRLF; }
fPreviousToken = FALSE; if (hasFlag(LIF_DATE)) { StrGetDate(szBuffer); StrCpy(&szFormat[nLen], szBuffer); nLen += StrLen(szBuffer);
fPreviousToken = TRUE; }
if (hasFlag(LIF_TIME)) { if (fPreviousToken) { StrCpy(&szFormat[nLen], c_szSpace); nLen += countof(c_szSpace)-1; }
StrGetTime(szBuffer); StrCpy(&szFormat[nLen], szBuffer); nLen += StrLen(szBuffer);
fPreviousToken = TRUE; }
if (fPreviousToken) { StrCpy(&szFormat[nLen], c_szSpace); nLen += countof(c_szSpace)-1; } if ((m_nAbsOffset-1 + m_iRelOffset) > 0) { ASSERT((m_nAbsOffset-1 + m_iRelOffset) * m_bStep < countof(szBuffer)); for (UINT i = 0; i < (m_nAbsOffset-1 + m_iRelOffset) * m_bStep; i++) szBuffer[i] = TEXT(' ');
StrCpy(&szFormat[nLen], szBuffer); nLen += i-1; }
fPreviousToken = FALSE; if (hasFlag(LIF_MODULE_ALL)) { pszAux = szBuffer; if (!hasFlag(LIF_MODULEPATH)) makeRawFileName(m_szModule, szBuffer, countof(szBuffer)); else pszAux = m_szModule; // should be lowercase already
StrCpy(&szFormat[nLen], pszAux); nLen += StrLen(pszAux);
fPreviousToken = TRUE; }
if (hasFlag(LIF_FILE_ALL)) { if (fPreviousToken) { StrCpy(&szFormat[nLen], c_szCommaSpace); nLen += countof(c_szCommaSpace)-1; }
if (!hasFlag(LIF_FILEPATH)) makeRawFileName(m_szFile, szBuffer, countof(szBuffer)); else { StrCpy(szBuffer, m_szFile); CharLower(szBuffer); }
StrCpy(&szFormat[nLen], szBuffer); nLen += StrLen(szBuffer);
fPreviousToken = TRUE; }
if (hasFlag(LIF_CLASS) && hasFlag(LIF_CLASS2)) { if (fPreviousToken) { StrCpy(&szFormat[nLen], c_szCommaSpace); nLen += countof(c_szCommaSpace)-1; }
StrCpy(&szFormat[nLen], m_szClass); nLen += StrLen(m_szClass);
fPreviousToken = TRUE; }
if (hasFlag(LIF_FUNCTION)) { if (fPreviousToken) { pszAux = (hasFlag(LIF_CLASS) && hasFlag(LIF_CLASS2)) ? c_szColonColon : c_szCommaSpace;
StrCpy(&szFormat[nLen], pszAux); nLen += StrLen(pszAux); }
StrCpy(&szFormat[nLen], m_szFunction); nLen += StrLen(m_szFunction);
fPreviousToken = TRUE; }
if (hasFlag(LIF_LINE) && iLine > 0) { if (fPreviousToken) { StrCpy(&szFormat[nLen], c_szCommaSpace); nLen += countof(c_szCommaSpace)-1; }
nAuxLen = wnsprintf(szBuffer, countof(szBuffer), c_szLine, iLine); StrCpy(&szFormat[nLen], szBuffer); nLen += nAuxLen;
fPreviousToken = TRUE; }
if (pszFormat == NULL) StrCpy(m_szMessage, szFormat); // nLen stays the same
else { if (fPreviousToken) { StrCpy(&szFormat[nLen], c_szColonSpace); nLen += countof(c_szColonSpace)-1; }
StrCpy(&szFormat[nLen], pszFormat);
va_list arglist; va_start(arglist, pszFormat); nAuxLen = wvnsprintf(m_szMessage, countof(m_szMessage), szFormat, arglist); va_end(arglist);
nLen = nAuxLen; }
if (hasFlag(LIF_APPENDCRLF)) StrCpy(&m_szMessage[nLen], c_szCRLF);
if (hasFlag(LIF_DUPLICATEINODS)) OutputDebugString(m_szMessage);
return m_szMessage; }
CLogItem::operator LPCTSTR() const { return m_szMessage; }
/////////////////////////////////////////////////////////////////////////////
// CLogItem implementation helper routines
LPCTSTR CLogItem::makeRawFileName(LPCTSTR pszPath, LPTSTR pszFile, UINT cchFile) { TCHAR szBuffer[MAX_PATH]; LPCTSTR pszRawName;
if (pszFile == NULL || cchFile == 0) return NULL; *pszFile = TEXT('\0');
if (pszPath == NULL || StrLen(pszPath) == 0) return NULL;
pszRawName = PathFindFileName(pszPath); ASSERT(StrLen(pszRawName) > 0); StrCpy(szBuffer, pszRawName); CharLower(szBuffer);
if (cchFile <= (UINT)StrLen(szBuffer)) return NULL;
StrCpy(pszFile, szBuffer); return pszFile; }
BOOL CLogItem::setFlag(DWORD dwMask, BOOL fSet /*= TRUE*/) { BOOL fIsFlag = ((m_dwFlags & dwMask) != 0L);
if (fIsFlag == fSet) return FALSE;
if (!fIsFlag && fSet) m_dwFlags |= dwMask;
else { ASSERT(fIsFlag && !fSet); m_dwFlags &= ~dwMask; }
return TRUE; }
/////////////////////////////////////////////////////////////////////////////
// Utility functions
// Note. pszDate must point to the buffer of at least 11 characters.
LPCTSTR StrGetDate(LPTSTR pszDate) { SYSTEMTIME dt; UINT nMonth, nDay, nYear;
GetLocalTime(&dt); nMonth = dt.wMonth; nDay = dt.wDay; nYear = dt.wYear;
*(pszDate + 2) = *(pszDate + 5) = TEXT('/'); *(pszDate + 10) = TEXT('\0');
*(pszDate + 0) = (TCHAR)(nMonth / 10 + TEXT('0')); *(pszDate + 1) = (TCHAR)(nMonth % 10 + TEXT('0'));
*(pszDate + 3) = (TCHAR)(nDay / 10 + TEXT('0')); *(pszDate + 4) = (TCHAR)(nDay % 10 + TEXT('0'));
*(pszDate + 6) = (TCHAR)(((nYear / 1000) % 10) + TEXT('0')); *(pszDate + 7) = (TCHAR)(((nYear / 100) % 10) + TEXT('0')); *(pszDate + 8) = (TCHAR)(((nYear / 10) % 10) + TEXT('0')); *(pszDate + 9) = (TCHAR)(((nYear / 1) % 10) + TEXT('0'));
return pszDate; }
// Note. pszTime must point to the buffer of at least 9 characters.
LPCTSTR StrGetTime(LPTSTR pszTime) { SYSTEMTIME dt; int nHours, nMinutes, nSeconds;
GetLocalTime(&dt); nHours = dt.wHour; nMinutes = dt.wMinute; nSeconds = dt.wSecond;
*(pszTime + 2) = *(pszTime + 5) = TEXT(':'); *(pszTime + 8) = TEXT('\0');
*(pszTime + 0) = (TCHAR)(nHours / 10 + TEXT('0')); *(pszTime + 1) = (TCHAR)(nHours % 10 + TEXT('0'));
*(pszTime + 3) = (TCHAR)(nMinutes / 10 + TEXT('0')); *(pszTime + 4) = (TCHAR)(nMinutes % 10 + TEXT('0'));
*(pszTime + 6) = (TCHAR)(nSeconds / 10 + TEXT('0')); *(pszTime + 7) = (TCHAR)(nSeconds % 10 + TEXT('0'));
return pszTime; }
//----- Testing the stuff -----
/*
struct Test { Test(); void foo(); void bar(); };
static Test t;
Test::Test() { MACRO_LI_Prolog(Test, Test) MACRO_LI_SetFlags(MACRO_LI_GetFlags() | LIF_DUPLICATEINODS);
LI0("Calling foo and then bar"); foo(); LI0("foo returned"); bar(); LI0("bar returned"); }
void Test::foo() { MACRO_LI_Prolog(Test, foo);
LI0("Calling bar"); bar(); LI0("bar returned"); }
void Test::bar() { MACRO_LI_Prolog(Test, bar);
LI0("No arguments"); LI1("One argument: %d", 2*2); LI2("Two arguments: %i, %s", 15, TEXT("nyah")); LI3("Three arguments: %d, %s, %x", 5, TEXT("the bar it is"), 0x80FF); } */
|