#ifdef _MSC_VER
#pragma warning (disable:4995)
#endif
#if defined(STORMLIB_WINDOWS) || defined(CASCLIB_PLATFORM_WINDOWS)
#define TEST_PLATFORM_WINDOWS
#endif
#ifdef _MSC_VER
#define fmt_I64u_t _T("%I64u")
#define fmt_I64u_a "%I64u"
#define fmt_I64X_t _T("%I64X")
#define fmt_I64X_a "%I64X"
#else
#define fmt_I64u_t L"%llu"
#define fmt_I64u_a "%llu"
#define fmt_I64X_t L"%llX"
#define fmt_I64X_a "%llX"
#endif
#ifdef __CASCLIB_SELF__
#define TEST_MIN CASCLIB_MIN
#define TEST_PRINT_PREFIX false
#else
#define TEST_MIN STORMLIB_MIN
#define TEST_PRINT_PREFIX true
#endif
inline DWORD TestInterlockedIncrement(DWORD * PtrValue)
{
#ifdef TEST_PLATFORM_WINDOWS
return (DWORD)InterlockedIncrement((LONG *)(PtrValue));
#elif defined(__GNUC__)
return __sync_add_and_fetch(PtrValue, 1);
#else
return ++(*PtrValue);
#endif
}
inline DWORD Test_GetLastError()
{
return GetCascError();
}
void TestStrCopy(char * szTarget, size_t cchTarget, const char * szSource, size_t cchSource = -1)
{
size_t cchToCopy;
if(cchTarget > 0)
{
if(cchSource == -1)
cchSource = strlen(szSource);
cchToCopy = TEST_MIN((cchTarget - 1), cchSource);
memcpy(szTarget, szSource, cchToCopy);
szTarget[cchToCopy] = 0;
}
}
void TestStrCopy(char * szTarget, size_t cchTarget, const wchar_t * szSource, size_t cchSource = -1)
{
size_t cchToCopy;
if(cchTarget > 0)
{
if(cchSource == -1)
cchSource = wcslen(szSource);
cchToCopy = TEST_MIN((cchTarget - 1), cchSource);
wcstombs(szTarget, szSource, cchToCopy);
szTarget[cchToCopy] = 0;
}
}
void TestStrCopy(wchar_t * szTarget, size_t cchTarget, const char * szSource, size_t cchSource = -1)
{
size_t cchToCopy;
if(cchTarget > 0)
{
if(cchSource == -1)
cchSource = strlen(szSource);
cchToCopy = TEST_MIN((cchTarget - 1), cchSource);
mbstowcs(szTarget, szSource, cchToCopy);
szTarget[cchToCopy] = 0;
}
}
wchar_t * CopyFormatCharacter(wchar_t * szBuffer, const wchar_t *& szFormat)
{
static const wchar_t * szStringFormat = L"%s";
static const wchar_t * szUint64Format = fmt_I64u_t;
if(szFormat[0] == '%')
{
if(szFormat[1] == 's')
{
wcscpy(szBuffer, szStringFormat);
szFormat += 2;
return szBuffer + wcslen(szStringFormat);
}
if(szFormat[1] == 'I' && szFormat[2] == '6' && szFormat[3] == '4' && szFormat[4] == 'u')
{
wcscpy(szBuffer, szUint64Format);
szFormat += 5;
return szBuffer + wcslen(szUint64Format);
}
}
*szBuffer++ = *szFormat++;
return szBuffer;
}
char * CopyFormatCharacter(char * szBuffer, const char *& szFormat)
{
static const char * szStringFormat = "\"%s\"";
static const char * szUint64Format = fmt_I64u_a;
if(szFormat[0] == '%')
{
if(szFormat[1] == 's')
{
TestStrCopy(szBuffer, 32, szStringFormat);
szFormat += 2;
return szBuffer + strlen(szStringFormat);
}
if(szFormat[1] == 'I' && szFormat[2] == '6' && szFormat[3] == '4' && szFormat[4] == 'u')
{
TestStrCopy(szBuffer, 32, szUint64Format);
szFormat += 5;
return szBuffer + strlen(szUint64Format);
}
}
*szBuffer++ = *szFormat++;
return szBuffer;
}
size_t TestStrPrintfV(char * buffer, size_t nCount, const char * format, va_list argList)
{
return vsnprintf(buffer, nCount, format, argList);
}
size_t TestStrPrintf(char * buffer, size_t nCount, const char * format, ...)
{
va_list argList;
size_t length;
va_start(argList, format);
length = TestStrPrintfV(buffer, nCount, format, argList);
va_end(argList);
return length;
}
size_t TestStrPrintfV(wchar_t * buffer, size_t nCount, const wchar_t * format, va_list argList)
{
#ifdef TEST_PLATFORM_WINDOWS
return _vsnwprintf(buffer, nCount, format, argList);
#else
return vswprintf(buffer, nCount, format, argList);
#endif
}
size_t TestStrPrintf(wchar_t * buffer, size_t nCount, const wchar_t * format, ...)
{
va_list argList;
size_t length;
va_start(argList, format);
length = TestStrPrintfV(buffer, nCount, format, argList);
va_end(argList);
return length;
}
class TLogHelper
{
public:
TLogHelper(const char * szNewMainTitle = NULL, const TCHAR * szNewSubTitle1 = NULL, const TCHAR * szNewSubTitle2 = NULL)
{
memset(this, 0, sizeof(TLogHelper));
UserString = "";
TotalFiles = 1;
UserCount = 1;
UserTotal = 1;
#ifdef TEST_PLATFORM_WINDOWS
InitializeCriticalSection(&Locker);
TickCount = GetTickCount();
#endif
SetStartTime();
szMainTitle = szNewMainTitle;
szSubTitle1 = szNewSubTitle1;
szSubTitle2 = szNewSubTitle2;
if(szNewMainTitle != NULL)
{
#ifdef __CASCLIB_SELF__
char szMainTitleT[0x100] = {0};
size_t nLength;
nLength = TestStrPrintf(szMainTitleT, _countof(szMainTitleT), "-- \"%s\" --", szNewMainTitle);
while(nLength < 90)
szMainTitleT[nLength++] = '-';
if(nLength < sizeof(szMainTitleT))
szMainTitleT[nLength++] = 0;
printf("%s\n", szMainTitleT);
#endif
#ifdef __STORMLIB_SELF__
TCHAR szMainTitleT[0x100] = {0};
TestStrCopy(szMainTitleT, _countof(szMainTitleT), szMainTitle);
if(szSubTitle1 != NULL && szSubTitle2 != NULL)
nPrevPrinted = _tprintf(_T("\rRunning %s (%s+%s) ..."), szMainTitleT, szSubTitle1, szSubTitle2);
else if(szSubTitle1 != NULL)
nPrevPrinted = _tprintf(_T("\rRunning %s (%s) ..."), szMainTitleT, szSubTitle1);
else
nPrevPrinted = _tprintf(_T("\rRunning %s ..."), szMainTitleT);
#endif
}
}
~TLogHelper()
{
if(bMessagePrinted == false)
{
PrintVerdict(ERROR_SUCCESS);
}
#ifdef TEST_PLATFORM_WINDOWS
DeleteCriticalSection(&Locker);
#endif
#ifdef __CASCLIB_SELF__
printf("\n");
#endif
}
bool TimeElapsed(DWORD Milliseconds)
{
bool bTimeElapsed = false;
#ifdef TEST_PLATFORM_WINDOWS
if(GetTickCount() > (TickCount + Milliseconds))
{
TickCount = GetTickCount();
if(TestInterlockedIncrement(&TimeTrigger) == 1)
{
bTimeElapsed = true;
}
}
#endif
return bTimeElapsed;
}
template <typename XCHAR>
DWORD PrintWithClreol(const XCHAR * szFormat, va_list argList, bool bPrintLastError, bool bPrintEndOfLine)
{
char * szBufferPtr;
char * szBufferEnd;
size_t nNewPrinted;
size_t nLength = 0;
DWORD dwErrCode = Test_GetLastError();
XCHAR szMessage[0x200];
char szBuffer[0x200];
bool bPrintPrefix = TEST_PRINT_PREFIX;
szBufferEnd = szBuffer + _countof(szBuffer);
szBufferPtr = szBuffer;
*szBufferPtr++ = '\r';
if(szMainTitle != NULL && bPrintPrefix)
{
while(szMainTitle[nLength] != 0)
*szBufferPtr++ = szMainTitle[nLength++];
*szBufferPtr++ = ':';
*szBufferPtr++ = ' ';
}
nLength = TestStrPrintfV(szMessage, _countof(szMessage), szFormat, argList);
TestStrCopy(szBufferPtr, (szBufferEnd - szBufferPtr), szMessage);
szBufferPtr += nLength;
if(bPrintLastError)
{
nLength = TestStrPrintf(szBufferPtr, (szBufferEnd - szBufferPtr), " (error code: %u)", dwErrCode);
szBufferPtr += nLength;
}
nNewPrinted = (szBufferPtr - szBuffer);
if((nLength = (szBufferPtr - szBuffer - 1)) < nPrevPrinted)
{
size_t nPadding = nPrevPrinted - nLength;
if((size_t)(nLength + nPadding) > (size_t)(szBufferEnd - szBufferPtr))
nPadding = (szBufferEnd - szBufferPtr);
memset(szBufferPtr, ' ', nPadding);
szBufferPtr += nPadding;
}
if((bPrintEndOfLine != false) && (szBufferPtr < szBufferEnd))
*szBufferPtr++ = '\n';
*szBufferPtr = 0;
if(bPrintEndOfLine != false)
{
bMessagePrinted = true;
nPrevPrinted = 0;
}
else
{
nPrevPrinted = nNewPrinted;
}
printf("%s", szBuffer);
nMessageCounter++;
return dwErrCode;
}
template <typename XCHAR>
void PrintProgress(const XCHAR * szFormat, ...)
{
va_list argList;
TimeTrigger = 0;
if(ProgressReady())
{
va_start(argList, szFormat);
PrintWithClreol(szFormat, argList, false, false);
va_end(argList);
}
}
template <typename XCHAR>
void PrintMessage(const XCHAR * szFormat, ...)
{
va_list argList;
va_start(argList, szFormat);
PrintWithClreol(szFormat, argList, false, true);
va_end(argList);
}
void PrintTotalTime()
{
DWORD TotalTime = SetEndTime();
if(TotalTime != 0)
PrintMessage("TotalTime: %u.%u second(s)", (TotalTime / 1000), (TotalTime % 1000));
PrintMessage("Work complete.");
}
template <typename XCHAR>
int PrintErrorVa(const XCHAR * szFormat, ...)
{
va_list argList;
int nResult;
va_start(argList, szFormat);
nResult = PrintWithClreol(szFormat, argList, true, true);
va_end(argList);
return nResult;
}
template <typename XCHAR>
int PrintError(const XCHAR * szFormat, const XCHAR * szFileName = NULL)
{
return PrintErrorVa(szFormat, szFileName);
}
DWORD PrintVerdict(DWORD dwErrCode = ERROR_SUCCESS)
{
LPCTSTR szSaveSubTitle1 = szSubTitle1;
LPCTSTR szSaveSubTitle2 = szSubTitle2;
TCHAR szSaveMainTitle[0x80];
TestStrCopy(szSaveMainTitle, _countof(szSaveMainTitle), szMainTitle);
szMainTitle = NULL;
szSubTitle1 = NULL;
szSubTitle2 = NULL;
if(szSaveMainTitle[0] != 0)
{
if(DontPrintResult == false)
{
const TCHAR * szVerdict = (dwErrCode == ERROR_SUCCESS) ? _T("succeeded") : _T("failed");
if(szSaveSubTitle1 != NULL && szSaveSubTitle2 != NULL)
PrintMessage(_T("%s (%s+%s) %s."), szSaveMainTitle, szSaveSubTitle1, szSaveSubTitle2, szVerdict);
else if(szSaveSubTitle1 != NULL)
PrintMessage(_T("%s (%s) %s."), szSaveMainTitle, szSaveSubTitle1, szVerdict);
else
PrintMessage(_T("%s %s."), szSaveMainTitle, szVerdict);
}
else
{
PrintProgress(" ");
printf("\r");
}
}
return dwErrCode;
}
void Lock()
{
#ifdef TEST_PLATFORM_WINDOWS
EnterCriticalSection(&Locker);
#endif
}
void Unlock()
{
#ifdef TEST_PLATFORM_WINDOWS
LeaveCriticalSection(&Locker);
#endif
}
ULONGLONG GetCurrentThreadTime()
{
#ifdef _WIN32
ULONGLONG TempTime = 0;
GetSystemTimeAsFileTime((LPFILETIME)(&TempTime));
return ((TempTime) / 10 / 1000);
#else
return time(NULL) * 1000;
#endif
}
bool ProgressReady()
{
time_t dwTickCount = time(NULL);
bool bResult = false;
if(dwTickCount > dwPrevTickCount)
{
dwPrevTickCount = dwTickCount;
bResult = true;
}
return bResult;
}
ULONGLONG SetStartTime()
{
StartTime = GetCurrentThreadTime();
return StartTime;
}
DWORD SetEndTime()
{
EndTime = GetCurrentThreadTime();
return (DWORD)(EndTime - StartTime);
}
void IncrementTotalBytes(ULONGLONG IncrementValue)
{
Lock();
TotalBytes = TotalBytes + IncrementValue;
Unlock();
}
void FormatTotalBytes(char * szBuffer, size_t ccBuffer)
{
ULONGLONG Bytes = TotalBytes;
ULONGLONG Divider = 1000000000;
char * szBufferEnd = szBuffer + ccBuffer;
bool bDividingOn = false;
while((szBuffer + 4) < szBufferEnd && Divider > 0)
{
if(bDividingOn)
{
szBuffer += TestStrPrintf(szBuffer, ccBuffer, " %03u", (DWORD)(Bytes / Divider));
Bytes = Bytes % Divider;
}
else if(Bytes > Divider)
{
szBuffer += TestStrPrintf(szBuffer, ccBuffer, "%u", (DWORD)(Bytes / Divider));
Bytes = Bytes % Divider;
bDividingOn = true;
}
Divider /= 1000;
}
}
#ifdef TEST_PLATFORM_WINDOWS
CRITICAL_SECTION Locker;
#endif
ULONGLONG TotalBytes; ULONGLONG ByteCount; ULONGLONG StartTime; ULONGLONG EndTime; const char * UserString;
DWORD UserCount;
DWORD UserTotal;
DWORD TickCount;
DWORD TimeTrigger; DWORD TotalFiles; DWORD FileCount; DWORD DontPrintResult:1;
protected:
const char * szMainTitle; const TCHAR * szSubTitle1; const TCHAR * szSubTitle2; size_t nMessageCounter;
size_t nPrevPrinted; time_t dwPrevTickCount;
bool bMessagePrinted;
};