You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
938 lines
25 KiB
938 lines
25 KiB
/*==LICENSE==* |
|
|
|
CyanWorlds.com Engine - MMOG client, server and tools |
|
Copyright (C) 2011 Cyan Worlds, Inc. |
|
|
|
This program is free software: you can redistribute it and/or modify |
|
it under the terms of the GNU General Public License as published by |
|
the Free Software Foundation, either version 3 of the License, or |
|
(at your option) any later version. |
|
|
|
This program is distributed in the hope that it will be useful, |
|
but WITHOUT ANY WARRANTY; without even the implied warranty of |
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
|
GNU General Public License for more details. |
|
|
|
You should have received a copy of the GNU General Public License |
|
along with this program. If not, see <http://www.gnu.org/licenses/>. |
|
|
|
Additional permissions under GNU GPL version 3 section 7 |
|
|
|
If you modify this Program, or any covered work, by linking or |
|
combining it with any of RAD Game Tools Bink SDK, Autodesk 3ds Max SDK, |
|
NVIDIA PhysX SDK, Microsoft DirectX SDK, OpenSSL library, Independent |
|
JPEG Group JPEG library, Microsoft Windows Media SDK, or Apple QuickTime SDK |
|
(or a modified version of those libraries), |
|
containing parts covered by the terms of the Bink SDK EULA, 3ds Max EULA, |
|
PhysX SDK EULA, DirectX SDK EULA, OpenSSL and SSLeay licenses, IJG |
|
JPEG Library README, Windows Media SDK EULA, or QuickTime SDK EULA, the |
|
licensors of this Program grant you additional |
|
permission to convey the resulting work. Corresponding Source for a |
|
non-source form of such a combination shall include the source code for |
|
the parts of OpenSSL and IJG JPEG Library used as well as that of the covered |
|
work. |
|
|
|
You can contact Cyan Worlds, Inc. by email legal@cyan.com |
|
or by snail mail at: |
|
Cyan Worlds, Inc. |
|
14617 N Newport Hwy |
|
Mead, WA 99021 |
|
|
|
*==LICENSE==*/ |
|
////////////////////////////////////////////////////////////////////////////// |
|
// // |
|
// plStatusLog Functions // |
|
// // |
|
//// History ///////////////////////////////////////////////////////////////// |
|
// // |
|
// 10.02.2001 mcn - Created // |
|
// 10.16.2001 mcn - Added static versions of AddLine() so you don't need // |
|
// to explicitly create a log // |
|
// 10.17.2001 mcn - Added support for carriage returns in printed lines // |
|
// 10.24.2002 eap - Added kDebugOutput flag for writing to debug window // |
|
// 10.25.2002 eap - Updated to work under unix // |
|
// 12.13.2002 eap - Added kStdout flag // |
|
// // |
|
////////////////////////////////////////////////////////////////////////////// |
|
|
|
#include <stdarg.h> |
|
#include <stdlib.h> |
|
#include "hsThread.h" |
|
#include "hsTemplates.h" |
|
#include "hsTimer.h" |
|
#include "hsStlUtils.h" |
|
#include "plFile/plFileUtils.h" |
|
#include "plStatusLog.h" |
|
#include "hsStlUtils.h" |
|
#include "plFile/hsFiles.h" |
|
#include "plUnifiedTime/plUnifiedTime.h" |
|
#include "pnProduct/pnProduct.h" |
|
|
|
#include "plEncryptLogLine.h" |
|
|
|
#if HS_BUILD_FOR_WIN32 |
|
#include <Shlobj.h> |
|
#endif |
|
|
|
////////////////////////////////////////////////////////////////////////////// |
|
//// plStatusLogMgr Stuff //////////////////////////////////////////////////// |
|
////////////////////////////////////////////////////////////////////////////// |
|
|
|
wchar_t plStatusLogMgr::fBasePath[ MAX_PATH ] = L""; |
|
|
|
//// Constructor & Destructor //////////////////////////////////////////////// |
|
|
|
plStatusLogMgr::plStatusLogMgr() |
|
{ |
|
fDisplays = nil; |
|
fCurrDisplay = nil; |
|
fDrawer = nil; |
|
fLastLogChangeTime = 0; |
|
|
|
#if HS_BUILD_FOR_WIN32 |
|
SHGetSpecialFolderPathW(NULL, fBasePath, CSIDL_LOCAL_APPDATA, TRUE); |
|
//#elif HS_BUILD_FOR_DARWIN |
|
// Do some Mac specific thing here eventually |
|
#else |
|
const char* home = getenv("HOME"); |
|
if (!home) home = ""; |
|
wchar_t* temp = hsStringToWString(home); |
|
swprintf(fBasePath, MAX_PATH, L"%S/.cache", temp); |
|
delete[] temp; |
|
#endif |
|
|
|
plFileUtils::ConcatFileName(fBasePath, ProductLongName()); |
|
plFileUtils::ConcatFileName(fBasePath, L"Log"); |
|
plFileUtils::EnsureFilePathExists(fBasePath); |
|
} |
|
|
|
plStatusLogMgr::~plStatusLogMgr() |
|
{ |
|
// Unlink all the displays, but don't delete them; leave that to whomever owns them |
|
while( fDisplays != nil ) |
|
{ |
|
plStatusLog *log = fDisplays; |
|
|
|
fDisplays->IUnlink(); |
|
|
|
if( log->fFlags & plStatusLog::kDeleteForMe ) |
|
delete log; |
|
} |
|
} |
|
|
|
plStatusLogMgr &plStatusLogMgr::GetInstance( void ) |
|
{ |
|
static plStatusLogMgr theManager; |
|
return theManager; |
|
} |
|
|
|
//// IEnsurePathExists /////////////////////////////////////////////////////// |
|
|
|
void plStatusLogMgr::IEnsurePathExists( const wchar_t *dirName ) |
|
{ |
|
// Note: this creates the directory if it doesn't exist, or if it does, |
|
// returns false |
|
plFileUtils::CreateDir( dirName ); |
|
} |
|
|
|
//// IPathAppend ///////////////////////////////////////////////////////////// |
|
|
|
void plStatusLogMgr::IPathAppend( wchar_t *base, const wchar_t *extra, unsigned maxLen ) |
|
{ |
|
if (!base || !extra) |
|
return; |
|
|
|
unsigned baseLen = wcslen(base); |
|
unsigned extraLen = wcslen(extra); |
|
|
|
bool needsSeparator = false; |
|
if (baseLen >= 1) |
|
needsSeparator = (base[baseLen - 1] != WPATH_SEPARATOR); |
|
|
|
if (needsSeparator) |
|
{ |
|
if ((baseLen + 1 + 1) >= maxLen) |
|
return; // abort, buffer isn't big enough |
|
base[baseLen] = WPATH_SEPARATOR; |
|
++baseLen; |
|
base[baseLen] = '\0'; |
|
} |
|
|
|
// concat the strings, making sure not to overrun the buffer |
|
unsigned curExtraPos = 0; |
|
for (unsigned curBasePos = baseLen; curBasePos < maxLen; ++curBasePos) |
|
{ |
|
base[curBasePos] = extra[curExtraPos]; |
|
if (extra[curExtraPos] == '\0') |
|
break; // done |
|
++curExtraPos; |
|
} |
|
|
|
// ensure we are null-terminated |
|
base[maxLen - 1] = '\0'; |
|
} |
|
|
|
//// Draw //////////////////////////////////////////////////////////////////// |
|
|
|
void plStatusLogMgr::Draw( void ) |
|
{ |
|
/// Just draw current plStatusLog |
|
if( fCurrDisplay != nil && fDrawer != nil ) |
|
{ |
|
plStatusLog* firstLog = nil; |
|
if (hsTimer::GetSysSeconds() - fLastLogChangeTime < 1) |
|
firstLog = fDisplays; |
|
|
|
fDrawer->Draw(fCurrDisplay, firstLog); |
|
} |
|
} |
|
|
|
//// CreateStatusLog ///////////////////////////////////////////////////////// |
|
|
|
plStatusLog *plStatusLogMgr::CreateStatusLog( uint8_t numDisplayLines, const char *filename, uint32_t flags ) |
|
{ |
|
wchar_t* wFilename = hsStringToWString(filename); |
|
plStatusLog* ret = CreateStatusLog(numDisplayLines, wFilename, flags); |
|
delete [] wFilename; |
|
return ret; |
|
} |
|
|
|
plStatusLog *plStatusLogMgr::CreateStatusLog( uint8_t numDisplayLines, const wchar_t *filename, uint32_t flags ) |
|
{ |
|
IEnsurePathExists( fBasePath ); |
|
plStatusLog *log = new plStatusLog( numDisplayLines, filename, flags ); |
|
|
|
// Put the new log in its alphabetical position |
|
plStatusLog** nextLog = &fDisplays; |
|
while (*nextLog) |
|
{ |
|
if (wcsicmp(filename, (*nextLog)->GetFileNameW()) <= 0) |
|
break; |
|
nextLog = &(*nextLog)->fNext; |
|
} |
|
log->ILink(nextLog); |
|
|
|
log->fDisplayPointer = &fCurrDisplay; |
|
|
|
return log; |
|
} |
|
|
|
//// ToggleStatusLog ///////////////////////////////////////////////////////// |
|
|
|
void plStatusLogMgr::ToggleStatusLog( plStatusLog *logToDisplay ) |
|
{ |
|
if( fCurrDisplay == logToDisplay ) |
|
fCurrDisplay = nil; |
|
else |
|
fCurrDisplay = logToDisplay; |
|
|
|
fLastLogChangeTime = hsTimer::GetSysSeconds(); |
|
} |
|
|
|
//// SetCurrStatusLog //////////////////////////////////////////////////////// |
|
|
|
void plStatusLogMgr::SetCurrStatusLog(const char* logName) |
|
{ |
|
wchar_t* wLogName = hsStringToWString(logName); |
|
SetCurrStatusLog(wLogName); |
|
delete [] wLogName; |
|
} |
|
|
|
void plStatusLogMgr::SetCurrStatusLog(const wchar_t* logName) |
|
{ |
|
plStatusLog* log = FindLog(logName, false); |
|
if (log != nil) |
|
fCurrDisplay = log; |
|
} |
|
|
|
//// NextStatusLog /////////////////////////////////////////////////////////// |
|
|
|
void plStatusLogMgr::NextStatusLog( void ) |
|
{ |
|
if( fCurrDisplay == nil ) |
|
fCurrDisplay = fDisplays; |
|
else |
|
fCurrDisplay = fCurrDisplay->fNext; |
|
|
|
fLastLogChangeTime = hsTimer::GetSysSeconds(); |
|
} |
|
|
|
void plStatusLogMgr::PrevStatusLog( void ) |
|
{ |
|
if( fCurrDisplay == nil ) |
|
{ |
|
fCurrDisplay = fDisplays; |
|
while (fCurrDisplay && fCurrDisplay->fNext) |
|
fCurrDisplay = fCurrDisplay->fNext; |
|
} |
|
else |
|
{ |
|
plStatusLog* lastLog = fDisplays; |
|
while (lastLog && lastLog->fNext != fCurrDisplay) |
|
lastLog = lastLog->fNext; |
|
|
|
fCurrDisplay = lastLog; |
|
} |
|
|
|
fLastLogChangeTime = hsTimer::GetSysSeconds(); |
|
} |
|
|
|
//// FindLog //////////////////////////////////////////////////////////////// |
|
|
|
plStatusLog *plStatusLogMgr::FindLog( const char *filename, bool createIfNotFound ) |
|
{ |
|
wchar_t* wFilename = hsStringToWString(filename); |
|
plStatusLog* ret = FindLog(wFilename, createIfNotFound); |
|
delete [] wFilename; |
|
return ret; |
|
} |
|
|
|
plStatusLog *plStatusLogMgr::FindLog( const wchar_t *filename, bool createIfNotFound ) |
|
{ |
|
plStatusLog *log = fDisplays; |
|
|
|
while( log != nil ) |
|
{ |
|
if( wcsicmp( log->GetFileNameW(), filename ) == 0 ) |
|
return log; |
|
|
|
log = log->fNext; |
|
} |
|
|
|
if( !createIfNotFound ) |
|
return nil; |
|
|
|
// Didn't find one, so create one! (make it a nice default one :) |
|
log = CreateStatusLog( kDefaultNumLines, filename, plStatusLog::kFilledBackground | |
|
plStatusLog::kDeleteForMe ); |
|
|
|
return log; |
|
} |
|
|
|
//// SetBasePath //////////////////////////////////////////////////////////////// |
|
|
|
void plStatusLogMgr::SetBasePath( const char * path ) |
|
{ |
|
wchar_t* wPath = hsStringToWString(path); |
|
SetBasePath(wPath); |
|
delete [] wPath; |
|
} |
|
|
|
void plStatusLogMgr::SetBasePath( const wchar_t * path ) |
|
{ |
|
wcscpy( fBasePath, path ); |
|
} |
|
|
|
|
|
//// BounceLogs /////////////////////////////////////////////////////////////// |
|
|
|
void plStatusLogMgr::BounceLogs() |
|
{ |
|
plStatusLog *log = fDisplays; |
|
|
|
while( log != nil ) |
|
{ |
|
plStatusLog * tmp = log; |
|
log = log->fNext; |
|
tmp->Bounce(); |
|
} |
|
} |
|
|
|
//// DumpLogs //////////////////////////////////////////////////////////////// |
|
|
|
bool plStatusLogMgr::DumpLogs( const char *newFolderName ) |
|
{ |
|
wchar_t* wFolderName = hsStringToWString(newFolderName); |
|
bool ret = DumpLogs(wFolderName); |
|
delete [] wFolderName; |
|
return ret; |
|
} |
|
|
|
bool plStatusLogMgr::DumpLogs( const wchar_t *newFolderName ) |
|
{ |
|
bool retVal = true; // assume success |
|
// create root path and make sure it exists |
|
wchar_t temp[MAX_PATH]; |
|
std::wstring newPath = L""; |
|
if (fBasePath) |
|
{ |
|
wcsncpy(temp, fBasePath, MAX_PATH); |
|
IPathAppend(temp, newFolderName, MAX_PATH); |
|
newPath = temp; |
|
} |
|
else |
|
newPath = newFolderName; |
|
IEnsurePathExists(newPath.c_str()); |
|
|
|
#if HS_BUILD_FOR_WIN32 |
|
hsWFolderIterator folderIterator; |
|
if (fBasePath) |
|
folderIterator.SetPath(fBasePath); |
|
else |
|
folderIterator.SetPath(L"."); |
|
|
|
while (folderIterator.NextFile()) |
|
{ |
|
if (folderIterator.IsDirectory()) |
|
continue; |
|
|
|
std::wstring baseFilename = folderIterator.GetFileName(); |
|
std::wstring source; |
|
if (fBasePath) |
|
{ |
|
wcsncpy(temp, fBasePath, MAX_PATH); |
|
IPathAppend(temp, baseFilename.c_str(), MAX_PATH); |
|
source = temp; |
|
} |
|
else |
|
source = baseFilename; |
|
|
|
std::wstring destination; |
|
wcsncpy(temp, newPath.c_str(), MAX_PATH); |
|
IPathAppend(temp, baseFilename.c_str(), MAX_PATH); |
|
destination = temp; |
|
|
|
bool succeeded = (CopyFileW(source.c_str(), destination.c_str(), FALSE) != 0); |
|
retVal = retVal && succeeded; |
|
} |
|
#endif |
|
return retVal; |
|
} |
|
|
|
////////////////////////////////////////////////////////////////////////////// |
|
//// plStatusLog //////////////////////////////////////////////////////////// |
|
////////////////////////////////////////////////////////////////////////////// |
|
|
|
uint32_t plStatusLog::fLoggingOff = false; |
|
|
|
plStatusLog::plStatusLog( uint8_t numDisplayLines, const wchar_t *filename, uint32_t flags ) |
|
{ |
|
fFileHandle = nil; |
|
fSema = nil; |
|
fSize = 0; |
|
fForceLog = false; |
|
|
|
fMaxNumLines = numDisplayLines; |
|
if( filename != nil ) |
|
{ |
|
fFilename = filename; |
|
char* temp = hsWStringToString(filename); |
|
fCFilename = temp; |
|
delete [] temp; |
|
|
|
fSema = new hsSemaphore(1, fCFilename.c_str()); |
|
} |
|
else |
|
{ |
|
fFilename = L""; |
|
fCFilename = ""; |
|
flags |= kDontWriteFile; |
|
|
|
fSema = new hsSemaphore(1); |
|
} |
|
|
|
fOrigFlags = fFlags = flags; |
|
|
|
IInit(); |
|
} |
|
|
|
plStatusLog::~plStatusLog() |
|
{ |
|
IFini(); |
|
} |
|
|
|
void plStatusLog::IInit() |
|
{ |
|
int i; |
|
|
|
fFlags = fOrigFlags; |
|
|
|
fLines = new char *[ fMaxNumLines ]; |
|
fColors = new uint32_t[ fMaxNumLines ]; |
|
for( i = 0; i < fMaxNumLines; i++ ) |
|
{ |
|
fLines[ i ] = nil; |
|
fColors[ i ] = kWhite; |
|
} |
|
|
|
fNext = nil; |
|
fBack = nil; |
|
|
|
} |
|
|
|
bool plStatusLog::IReOpen( void ) |
|
{ |
|
if( fFileHandle != nil ) |
|
{ |
|
fclose( fFileHandle ); |
|
fFileHandle = nil; |
|
} |
|
|
|
// Open the file, clearing it, if necessary |
|
if(!(fFlags & kDontWriteFile)) |
|
{ |
|
wchar_t file[ MAX_PATH ]; |
|
wchar_t fileNoExt[MAX_PATH]; |
|
wchar_t* ext=nil; |
|
IParseFileName(file, MAX_PATH, fileNoExt, &ext); |
|
fEncryptMe = false; |
|
#ifdef PLASMA_EXTERNAL_RELEASE |
|
fEncryptMe = ( wcsicmp( fFilename.c_str(), L"chat.log" ) != 0 ) ? true : false; |
|
if( fEncryptMe ) |
|
ext = L".elf"; |
|
#endif |
|
wchar_t fileToOpen[MAX_PATH]; |
|
hsSnwprintf(fileToOpen, MAX_PATH, L"%s.0%s", fileNoExt, ext); |
|
if (!(fFlags & kDontRotateLogs)) |
|
{ |
|
wchar_t work[MAX_PATH], work2[MAX_PATH]; |
|
hsSnwprintf(work, MAX_PATH, L"%s.3%s",fileNoExt,ext); |
|
plFileUtils::RemoveFile(work); |
|
hsSnwprintf(work2, MAX_PATH, L"%s.2%s",fileNoExt,ext); |
|
plFileUtils::FileMove(work2, work); |
|
hsSnwprintf(work, MAX_PATH, L"%s.1%s",fileNoExt,ext); |
|
plFileUtils::FileMove(work, work2); |
|
plFileUtils::FileMove(fileToOpen, work); |
|
} |
|
|
|
if (fFlags & kAppendToLast) |
|
{ |
|
fFileHandle = hsWFopen( fileToOpen, fEncryptMe ? L"ab" : L"at" ); |
|
} |
|
else |
|
{ |
|
fFileHandle = hsWFopen( fileToOpen, fEncryptMe ? L"wb" : L"wt" ); |
|
// if we need to reopen lets just append |
|
fFlags |= kAppendToLast; |
|
} |
|
} |
|
|
|
if (fFileHandle) |
|
fSize = ftell( fFileHandle ); |
|
else |
|
fSize = 0; |
|
|
|
return fFileHandle != nil; |
|
} |
|
|
|
void plStatusLog::IFini( void ) |
|
{ |
|
int i; |
|
|
|
if( fFileHandle != nil ) |
|
{ |
|
fclose( fFileHandle ); |
|
fFileHandle = nil; |
|
} |
|
|
|
if( *fDisplayPointer == this ) |
|
*fDisplayPointer = nil; |
|
|
|
if( fBack != nil || fNext != nil ) |
|
IUnlink(); |
|
|
|
for( i = 0; i < fMaxNumLines; i++ ) |
|
delete [] fLines[ i ]; |
|
|
|
if (fSema) |
|
delete fSema; |
|
|
|
delete [] fLines; |
|
delete [] fColors; |
|
} |
|
|
|
|
|
void plStatusLog::IParseFileName(wchar_t* file, size_t fnsize, wchar_t* fileNoExt, wchar_t** ext) const |
|
{ |
|
const wchar_t *base = plStatusLogMgr::IGetBasePath(); |
|
if( wcslen( base ) != nil ) |
|
hsSnwprintf( file, fnsize, L"%s%s%s", base, WPATH_SEPARATOR_STR, fFilename.c_str() ); |
|
else |
|
wcscpy( file, fFilename.c_str() ); |
|
|
|
plFileUtils::EnsureFilePathExists( file ); |
|
|
|
// apache-style file backup |
|
|
|
*ext = wcsrchr(file, L'.'); |
|
if (*ext) |
|
{ |
|
int fileLen = *ext - file; |
|
wcsncpy(fileNoExt, file, fileLen); |
|
fileNoExt[fileLen] = L'\0'; |
|
} |
|
else |
|
{ |
|
wcscpy(fileNoExt, file); |
|
*ext = L'\0'; |
|
} |
|
|
|
} |
|
|
|
//// IUnlink ///////////////////////////////////////////////////////////////// |
|
|
|
void plStatusLog::IUnlink( void ) |
|
{ |
|
hsAssert( fBack, "plStatusLog not in list" ); |
|
if( fNext ) |
|
fNext->fBack = fBack; |
|
*fBack = fNext; |
|
|
|
fBack = nil; |
|
fNext = nil; |
|
} |
|
|
|
//// ILink /////////////////////////////////////////////////////////////////// |
|
|
|
void plStatusLog::ILink( plStatusLog **back ) |
|
{ |
|
hsAssert( fNext == nil && fBack == nil, "Trying to link a plStatusLog that's already linked" ); |
|
|
|
fNext = *back; |
|
if( *back ) |
|
(*back)->fBack = &fNext; |
|
fBack = back; |
|
*back = this; |
|
} |
|
|
|
//// IAddLine //////////////////////////////////////////////////////////////// |
|
// Actually add a stinking line. |
|
|
|
bool plStatusLog::IAddLine( const char *line, int32_t count, uint32_t color ) |
|
{ |
|
int i; |
|
|
|
if(fLoggingOff && !fForceLog) |
|
return true; |
|
|
|
/// Scroll pointers up |
|
fSema->Wait(); |
|
|
|
bool ret = true; |
|
|
|
if (fMaxNumLines > 0) |
|
{ |
|
delete [] fLines[ 0 ]; |
|
for( i = 0; i < fMaxNumLines - 1; i++ ) |
|
{ |
|
fLines[ i ] = fLines[ i + 1 ]; |
|
fColors[ i ] = fColors[ i + 1 ]; |
|
} |
|
} |
|
|
|
/// Add new |
|
if( line == nil || strlen( line ) == 0 ) |
|
{ |
|
if (fMaxNumLines > 0) |
|
{ |
|
fColors[ i ] = 0; |
|
fLines[ i ] = nil; |
|
} |
|
ret = IPrintLineToFile( "", 0 ); |
|
} |
|
else |
|
{ |
|
if( count < 0 ) |
|
count = strlen( line ); |
|
|
|
if (fMaxNumLines > 0) |
|
{ |
|
fLines[ i ] = new char[ count + 1 ]; |
|
hsStrncpy( fLines[ i ], line, count + 1 ); |
|
fLines[ i ][ count ] = 0; |
|
|
|
char *c = strchr( fLines[ i ], '\n' ); |
|
if( c != nil ) |
|
{ |
|
*c = 0; |
|
count--; |
|
} |
|
|
|
fColors[ i ] = color; |
|
} |
|
|
|
ret = IPrintLineToFile( line, count ); |
|
} |
|
|
|
fSema->Signal(); |
|
|
|
return ret; |
|
} |
|
|
|
//// AddLine ///////////////////////////////////////////////////////////////// |
|
|
|
bool plStatusLog::AddLine( const char *line, uint32_t color ) |
|
{ |
|
char *c, *str; |
|
if(fLoggingOff && !fForceLog) |
|
return true; |
|
|
|
bool ret = true; |
|
|
|
/// Scan for carriage returns and feed each section into IAddLine() |
|
for( str = (char *)line; ( c = strchr( str, '\n' ) ) != nil; str = c + 1 ) |
|
{ |
|
// So if we got here, c points to a carriage return... |
|
ret = IAddLine( str, (uintptr_t)c - (uintptr_t)str, color ); |
|
} |
|
|
|
/// We might have some left over |
|
if( strlen( str ) > 0 ) |
|
{ |
|
ret &= IAddLine( str, -1, color ); |
|
} |
|
|
|
return ret; |
|
} |
|
|
|
//// AddLine printf-style Variations ///////////////////////////////////////// |
|
|
|
bool plStatusLog::AddLineV( const char *format, va_list arguments ) |
|
{ |
|
if(fLoggingOff && !fForceLog) |
|
return true; |
|
return AddLineV( kWhite, format, arguments ); |
|
} |
|
|
|
bool plStatusLog::AddLineV( uint32_t color, const char *format, va_list arguments ) |
|
{ |
|
if(fLoggingOff && !fForceLog) |
|
return true; |
|
char buffer[2000]; |
|
vsprintf(buffer, format, arguments); |
|
return AddLine( buffer, color ); |
|
} |
|
|
|
bool plStatusLog::AddLineF( const char *format, ... ) |
|
{ |
|
if(fLoggingOff && !fForceLog) |
|
return true; |
|
va_list arguments; |
|
va_start( arguments, format ); |
|
|
|
return AddLineV( kWhite, format, arguments ); |
|
} |
|
|
|
bool plStatusLog::AddLineF( uint32_t color, const char *format, ... ) |
|
{ |
|
if(fLoggingOff && !fForceLog) |
|
return true; |
|
va_list arguments; |
|
va_start( arguments, format ); |
|
|
|
return AddLineV( color, format, arguments ); |
|
} |
|
|
|
//// AddLine Static Variations /////////////////////////////////////////////// |
|
|
|
bool plStatusLog::AddLineS( const char *filename, const char *format, ... ) |
|
{ |
|
plStatusLog *log = plStatusLogMgr::GetInstance().FindLog( filename ); |
|
|
|
if(fLoggingOff && !log->fForceLog) |
|
return true; |
|
|
|
va_list arguments; |
|
va_start( arguments, format ); |
|
|
|
return log->AddLineV( format, arguments ); |
|
} |
|
|
|
bool plStatusLog::AddLineS( const char *filename, uint32_t color, const char *format, ... ) |
|
{ |
|
plStatusLog *log = plStatusLogMgr::GetInstance().FindLog( filename ); |
|
|
|
if(fLoggingOff && !log->fForceLog) |
|
return true; |
|
|
|
va_list arguments; |
|
va_start( arguments, format ); |
|
|
|
return log->AddLineV( color, format, arguments ); |
|
} |
|
|
|
//// Clear /////////////////////////////////////////////////////////////////// |
|
|
|
void plStatusLog::Clear( void ) |
|
{ |
|
int i; |
|
|
|
|
|
for( i = 0; i < fMaxNumLines; i++ ) |
|
{ |
|
delete [] fLines[ i ]; |
|
fLines[ i ] = nil; |
|
} |
|
} |
|
|
|
|
|
//// Bounce ////////////////////////////////////////////////////////////////// |
|
|
|
void plStatusLog::Bounce( uint32_t flags) |
|
{ |
|
if (flags) |
|
fOrigFlags=flags; |
|
Clear(); |
|
if( fFileHandle != nil ) |
|
{ |
|
fclose( fFileHandle ); |
|
fFileHandle = nil; |
|
} |
|
AddLine( "--------- Bounced Log ---------" ); |
|
} |
|
|
|
//// IPrintLineToFile //////////////////////////////////////////////////////// |
|
|
|
bool plStatusLog::IPrintLineToFile( const char *line, uint32_t count ) |
|
{ |
|
if( fFlags & kDontWriteFile ) |
|
return true; |
|
|
|
#ifdef PLASMA_EXTERNAL_RELEASE |
|
uint8_t hint = 0; |
|
if( fFlags & kAppendToLast ) |
|
{ |
|
hint = (uint8_t)fSize; |
|
} |
|
#endif |
|
|
|
if (!fFileHandle) |
|
IReOpen(); |
|
|
|
bool ret = ( fFileHandle!=nil ); |
|
|
|
if( fFileHandle != nil ) |
|
{ |
|
char work[256]; |
|
char buf[2000]; |
|
buf[0] = 0; |
|
|
|
//build line to encrypt |
|
|
|
if( count != 0 ) |
|
{ |
|
if ( fFlags & kTimestamp ) |
|
{ |
|
snprintf(work, arrsize(work), "(%s) ", plUnifiedTime(kNow).Format("%m/%d %H:%M:%S").c_str()); |
|
strncat(buf, work, arrsize(work)); |
|
} |
|
if ( fFlags & kTimestampGMT ) |
|
{ |
|
snprintf(work, arrsize(work), "(%s) ", plUnifiedTime::GetCurrentTime().Format("%m/%d %H:%M:%S UTC").c_str()); |
|
strncat(buf, work, arrsize(work)); |
|
} |
|
if ( fFlags & kTimeInSeconds ) |
|
{ |
|
snprintf(work, arrsize(work), "(%lu) ", (unsigned long)plUnifiedTime(kNow).GetSecs()); |
|
strncat(buf, work, arrsize(work)); |
|
} |
|
if ( fFlags & kTimeAsDouble ) |
|
{ |
|
snprintf(work, arrsize(work), "(%f) ", plUnifiedTime(kNow).GetSecsDouble()); |
|
strncat(buf, work, arrsize(work)); |
|
} |
|
if (fFlags & kRawTimeStamp) |
|
{ |
|
snprintf(work, arrsize(work), "[t=%10f] ", hsTimer::GetSeconds()); |
|
strncat(buf, work, arrsize(work)); |
|
} |
|
if (fFlags & kThreadID) |
|
{ |
|
snprintf(work, arrsize(work), "[t=%lu] ", hsThread::GetMyThreadId()); |
|
strncat(buf, work, arrsize(work)); |
|
} |
|
|
|
size_t remaining = arrsize(buf) - strlen(buf) - 1; |
|
if (!fEncryptMe) remaining -= 1; |
|
if (count <= remaining) { |
|
strncat(buf, line, count); |
|
} else { |
|
strncat(buf, line, remaining); |
|
} |
|
|
|
if(!fEncryptMe ) |
|
{ |
|
strncat(buf, "\n", 1); |
|
} |
|
} |
|
|
|
unsigned length = strlen(buf); |
|
|
|
#ifdef PLASMA_EXTERNAL_RELEASE |
|
// Print to a separate line, since we have to encrypt it |
|
if( fEncryptMe ) |
|
{ |
|
// Encrypt! |
|
plStatusEncrypt::Encrypt( (uint8_t *)buf, hint ); |
|
|
|
// xor the line length, then write it out, then the line, no terminating character |
|
uint16_t encrySize = length ^ ((uint16_t)fSize); |
|
|
|
// try the first write, if it fails reopen and try again |
|
int err; |
|
err = fputc( encrySize & 0xff, fFileHandle ); |
|
if (err == EOF && IReOpen()) |
|
{ |
|
err = fputc( encrySize & 0xff, fFileHandle ); |
|
} |
|
|
|
if (err != EOF) |
|
{ |
|
fSize++; // inc for the last putc |
|
err = fputc( encrySize >> 8, fFileHandle ); |
|
if (err != EOF) |
|
fSize++; // inc for the last putc |
|
err = fwrite( buf, 1, length, fFileHandle ); |
|
fSize += err; |
|
|
|
if (!(fFlags & kNonFlushedLog)) |
|
fflush(fFileHandle); |
|
} |
|
else |
|
{ |
|
ret = false; |
|
} |
|
} |
|
else |
|
#endif |
|
{ |
|
int err; |
|
err = fwrite(buf,1,length,fFileHandle); |
|
ret = ( ferror( fFileHandle )==0 ); |
|
|
|
if ( ret ) |
|
{ |
|
fSize += err; |
|
if (!(fFlags & kNonFlushedLog)) |
|
fflush(fFileHandle); |
|
} |
|
} |
|
|
|
if ( fSize>=kMaxFileSize ) |
|
{ |
|
plStatusLogMgr::GetInstance().BounceLogs(); |
|
} |
|
|
|
} |
|
|
|
if ( fFlags & kDebugOutput ) |
|
{ |
|
#if HS_BUILD_FOR_WIN32 |
|
#ifndef PLASMA_EXTERNAL_RELEASE |
|
std::string str; |
|
xtl::format( str, "%.*s\n", count, line ); |
|
OutputDebugString( str.c_str() ); |
|
#endif |
|
#else |
|
fprintf( stderr, "%.*s\n", count, line ); |
|
#endif |
|
} |
|
|
|
if ( fFlags & kStdout ) |
|
{ |
|
fprintf( stdout, "%.*s\n", count, line ); |
|
} |
|
|
|
return ret; |
|
} |
|
|
|
|