#include <string.h> // for memset() and strcpy()
# include <NSSystemDirectories.h> // for NSSearchPath*()
# include <sys/types.h> // for mode_t
# include <sys/stat.h> // for mkdir() and stat()
#include "DSCThread.h" // for CThread identification
#include "CLog.h"
#include "COSUtils.h"
#include "DSMutexSemaphore.h"
const char *kgStringMessageEndOfLine = "\r\n";
OptionBits CLog::fSrvrLogFlags = kLogMeta;
OptionBits CLog::fErrLogFlags = kLogMeta;
OptionBits CLog::fDbgLogFlags = kLogMeta;
OptionBits CLog::fInfoLogFlags = kLogMeta;
CLog *CLog::fServerLog = nil;
CLog *CLog::fDebugLog = nil;
CLog *CLog::fErrorLog = nil;
CLog *CLog::fInfoLog = nil;
CString *CLog::fServerLogName = nil;
CString *CLog::fErrorLogName = nil;
CString *CLog::fDebugLogName = nil;
CString *CLog::fInfoLogName = nil;
sInt32 CLog::Initialize ( OptionBits srvrFlags, OptionBits errFlags,
OptionBits debugFlags, OptionBits infoFlags,
bool inOpenDbgLog, bool inOpenInfoLog )
{
sInt32 result;
NSSearchPathEnumerationState eState;
struct stat ssFolder;
char localPath[ PATH_MAX ];
CString csBasePath( 128 );
try
{
eState = NSStartSearchPathEnumeration( NSLibraryDirectory, NSLocalDomainMask );
eState = NSGetNextSearchPathEnumeration( eState, localPath );
fSrvrLogFlags = srvrFlags;
fErrLogFlags = errFlags;
fDbgLogFlags = debugFlags;
fInfoLogFlags = infoFlags;
fServerLogName = new CString( 128 );
if ( fServerLogName == nil )
{
throw( (sInt32)eMemoryAllocError );
}
fErrorLogName = new CString( 128 );
if ( fErrorLogName == nil )
{
throw( (sInt32)eMemoryAllocError );
}
fDebugLogName = new CString( 128 );
if ( fDebugLogName == nil )
{
throw( (sInt32)eMemoryAllocError );
}
fInfoLogName = new CString( 128 );
if ( fInfoLogName == nil )
{
throw( (sInt32)eMemoryAllocError );
}
csBasePath.Set( localPath );
csBasePath.Append( "/" );
csBasePath.Append( COSUtils::GetStringFromList( kAppStringsListID, kStrLogFolder ) );
result = ::stat( csBasePath.GetData(), &ssFolder );
if ( result != eDSNoErr )
{
result = ::mkdir( csBasePath.GetData(), 0775 );
::chmod( csBasePath.GetData(), 0775 ); }
csBasePath.Append( "/" );
csBasePath.Append( COSUtils::GetStringFromList( kAppStringsListID, kStrProductFolder ) );
result = ::stat( csBasePath.GetData(), &ssFolder );
if ( result != eDSNoErr )
{
result = ::mkdir( csBasePath.GetData(), 0775 );
::chmod( csBasePath.GetData(), 0775 ); }
csBasePath. Append( "/" );
fServerLogName->Set( csBasePath.GetData() );
fServerLogName->Append( COSUtils::GetStringFromList( kAppStringsListID, kStrProductFolder ) );
fServerLogName->Append( "." );
fServerLogName->Append( COSUtils::GetStringFromList( kAppStringsListID, kStrServerLogFileName ) );
fErrorLogName->Set( csBasePath.GetData() );
fErrorLogName->Append( COSUtils::GetStringFromList( kAppStringsListID, kStrProductFolder ) );
fErrorLogName->Append( "." );
fErrorLogName->Append( COSUtils::GetStringFromList( kAppStringsListID, kStrErrorLogFileName ) );
fDebugLogName->Set( csBasePath.GetData() );
fDebugLogName->Append( COSUtils::GetStringFromList( kAppStringsListID, kStrProductFolder ) );
fDebugLogName->Append( "." );
fDebugLogName->Append( COSUtils::GetStringFromList( kAppStringsListID, kStrDebugLogFileName ) );
fInfoLogName->Set( csBasePath.GetData() );
fInfoLogName->Append( COSUtils::GetStringFromList( kAppStringsListID, kStrProductFolder ) );
fInfoLogName->Append( "." );
fInfoLogName->Append( COSUtils::GetStringFromList( kAppStringsListID, kStrInfoLogFileName ) );
if ( result == eDSNoErr )
{
fServerLog = new CLog( fServerLogName->GetData(), kLengthUnlimited, kThreadInfo | kRollLog );
if ( inOpenDbgLog == true )
{
fDebugLog = new CLog( fDebugLogName->GetData(), kLengthUnlimited, kThreadInfo | kRollLog );
}
if ( inOpenInfoLog == true )
{
fInfoLog = new CLog( fInfoLogName->GetData(), kLengthUnlimited, kThreadInfo | kRollLog );
}
}
}
catch( sInt32 err )
{
result = err;
}
return( result );
}
void CLog::Deinitialize ( void )
{
if ( fServerLog != nil )
{
delete( fServerLog );
fServerLog = nil;
}
if ( fErrorLog != nil )
{
delete( fErrorLog );
fErrorLog = nil;
}
if ( fDebugLog != nil )
{
delete( fDebugLog );
fDebugLog = nil;
}
if ( fInfoLog != nil )
{
delete( fInfoLog );
fInfoLog = nil;
}
}
void CLog::StartLogging ( eLogType inWhichLog, uInt32 inFlag )
{
switch ( inWhichLog )
{
case keServerLog:
fSrvrLogFlags |= inFlag;
break;
case keErrorLog:
fErrLogFlags |= inFlag;
break;
case keDebugLog:
fDbgLogFlags |= inFlag;
break;
case keInfoLog:
fInfoLogFlags |= inFlag;
break;
}
}
void CLog::StopLogging ( eLogType inWhichLog, uInt32 inFlag )
{
switch ( inWhichLog )
{
case keServerLog:
fSrvrLogFlags &= ~inFlag;
break;
case keErrorLog:
fErrLogFlags &= ~inFlag;
break;
case keDebugLog:
fDbgLogFlags &= ~inFlag;
break;
case keInfoLog:
fInfoLogFlags &= ~inFlag;
break;
}
}
void CLog::ToggleLogging ( eLogType inWhichLog, uInt32 inFlag )
{
switch ( inWhichLog )
{
case keServerLog:
if ( fSrvrLogFlags & inFlag )
{
fSrvrLogFlags &= ~inFlag;
}
else
{
fSrvrLogFlags |= inFlag;
}
break;
case keErrorLog:
if ( fErrLogFlags & inFlag )
{
fErrLogFlags &= ~inFlag;
}
else
{
fErrLogFlags |= inFlag;
}
break;
case keDebugLog:
if ( fDbgLogFlags & inFlag )
{
fDbgLogFlags &= ~inFlag;
}
else
{
fDbgLogFlags |= inFlag;
}
break;
case keInfoLog:
if ( fInfoLogFlags & inFlag )
{
fInfoLogFlags &= ~inFlag;
}
else
{
fInfoLogFlags |= inFlag;
}
break;
}
}
bool CLog::IsLogging ( eLogType inWhichLog, uInt32 inFlag )
{
switch ( inWhichLog )
{
case keServerLog:
return( fSrvrLogFlags & inFlag );
case keErrorLog:
return( fErrLogFlags & inFlag );
case keDebugLog:
return( fDbgLogFlags & inFlag );
case keInfoLog:
return( fInfoLogFlags & inFlag );
}
return( false );
}
void CLog::StartDebugLog ( void )
{
try
{
if ( fDebugLog == nil )
{
fDbgLogFlags = kLogEverything;
fDebugLog = new CLog( fDebugLogName->GetData(), kLengthUnlimited, kThreadInfo | kRollLog );
}
}
catch ( ... )
{
}
}
void CLog::StopDebugLog ( void )
{
if ( fDebugLog != nil )
{
fDebugLog->Lock();
fDbgLogFlags = kLogMeta;
delete( fDebugLog );
fDebugLog = nil;
}
}
void CLog::StartErrorLog ( void )
{
try
{
if ( fErrorLog == nil )
{
fErrLogFlags = kLogEverything;
fErrorLog = new CLog( fErrorLogName->GetData(), kLengthUnlimited, kThreadInfo | kRollLog );
}
}
catch ( ... )
{
}
}
void CLog::StopErrorLog ( void )
{
if ( fErrorLog != nil )
{
fErrorLog->Lock();
fErrLogFlags = kLogMeta;
delete( fErrorLog );
fErrorLog = nil;
}
}
void CLog::StartInfoLog ( void )
{
try
{
if ( fInfoLog == nil )
{
fInfoLogFlags = kLogEverything;
fInfoLog = new CLog( fInfoLogName->GetData(), kLengthUnlimited, kThreadInfo | kRollLog );
}
}
catch( ... )
{
}
}
void CLog::StopInfoLog ( void )
{
if ( fInfoLog != nil )
{
fInfoLog->Lock();
fInfoLogFlags = kLogMeta;
delete( fInfoLog );
fInfoLog = nil;
}
}
CLog* CLog::GetServerLog ( void )
{
return( fServerLog );
}
CLog* CLog::GetErrorLog ( void )
{
return( fErrorLog );
}
CLog* CLog::GetDebugLog ( void )
{
return( fDebugLog );
}
CLog* CLog::GetInfoLog ( void )
{
return( fInfoLog );
}
long CLog::Lock ( void )
{
return( fLock->Wait() );
}
void CLog::UnLock ( void )
{
fLock->Signal();
}
#pragma mark **** CLog Public Instance Methods ****
CLog::CLog ( const char *inFile,
uInt32 inMaxLen,
OptionBits inFlags,
OSType type,
OSType creator )
{
fFlags = inFlags;
fMaxLength = inMaxLen;
fOffset = 0;
fLength = 0;
::memset( fHooks, 0, sizeof( fHooks ) );
try {
fFile = new CFile( inFile, true, (inFlags & CLog::kRollLog) );
if ( !fFile->is_open() )
throw(-1);
if (fFile != nil)
{
fFile->seekp( 0, ios::end );
fLength = fFile->tellp();
}
} catch ( ... ) {
fFile = nil;
fLength = 0;
}
fLock = new DSMutexSemaphore( true );
if (fLock != nil)
{
fLock->Signal();
}
}
CLog::~CLog ( void )
{
if ( fFile != nil )
{
delete( fFile );
fFile = nil;
}
if ( fLock != nil )
{
delete( fLock );
fLock = nil;
}
}
void CLog::SetMaxLength ( uInt32 inMaxLen )
{
fMaxLength = inMaxLen;
}
void CLog::GetInfo ( CFileSpec &fileSpec,
uInt32 &startOffset,
uInt32 &dataLength,
bool &hasWrapped )
{
::strcpy( fileSpec, fFileSpec );
startOffset = fOffset;
dataLength = fLength;
hasWrapped = false;
}
OSErr CLog::ClearLog ( void )
{
try {
if( fFile == nil ) throw ((OSErr) ds_fnfErr);
fFile->seteof( 0 );
fOffset = 0;
fLength = 0;
}
catch ( OSErr nErr )
{
return( nErr );
}
return( eDSNoErr );
}
void CLog::AddHook ( AppendHook fpNewHook )
{
AppendHook *pHooks = fHooks;
for ( ; *pHooks; pHooks++ )
{
}
*pHooks = fpNewHook;
}
OSErr CLog::Append ( const CString &line )
{
CString csTemp( 60 + line.GetLength() );
fLock->Wait();
if (fFlags & kThreadInfo)
{
DSCThread *cur = (DSCThread *)DSLThread::GetCurrentThread();
if ( cur )
{
csTemp.Sprintf( "%D %T - %S", &line );
}
else
{
csTemp.Sprintf( "%D %T - %S", &line );
}
}
else
{
csTemp.Sprintf("%D %T\t%S", &line);
}
if (csTemp[csTemp.GetLength () - 1] != '\n')
{
csTemp.Append ('\n');
}
try {
if( fFile == nil ) throw ((OSErr) ds_fnfErr);
fFile->write( csTemp.GetData(), csTemp.GetLength() );
AppendHook *pHooks = fHooks ;
for ( ; *pHooks ; pHooks++)
(*pHooks) (csTemp);
}
catch ( OSErr nErr )
{
fLock->Signal();
return( nErr );
}
fLock->Signal();
return( eDSNoErr );
}