Files
mars-flaim/flaim/src/ftrace.cpp
dsandersoremutah c55dab446f Renamed version4 to flaim and version5 to xflaim
git-svn-id: https://svn.code.sf.net/p/flaim/code/trunk@7 0109f412-320b-0410-ab79-c3e0c5ffbbe6
2006-01-27 21:06:39 +00:00

767 lines
18 KiB
C++

//-------------------------------------------------------------------------
// Desc: Trace class.
// Tabs: 3
//
// Copyright (c) 1999-2000,2003-2006 Novell, Inc. All Rights Reserved.
//
// This program is free software; you can redistribute it and/or
// modify it under the terms of version 2 of the GNU General Public
// License as published by the Free Software Foundation.
//
// 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, contact Novell, Inc.
//
// To contact Novell about this file by physical or electronic mail,
// you may find current contact information at www.novell.com
//
// $Id: ftrace.cpp 12329 2006-01-20 17:49:30 -0700 (Fri, 20 Jan 2006) ahodgkinson $
//-------------------------------------------------------------------------
#include "flaimsys.h"
FSTATIC FLMUINT traceFormatNumber(
FLMUINT64 ui64Number,
FLMINT uiBase,
char * pszDest);
/****************************************************************************
Public: Constructors
****************************************************************************/
FlmTrace::FlmTrace()
{
m_hMutex = F_MUTEX_NULL;
m_uiLockCnt = 0;
#ifdef FLM_DEBUG
m_uiLockThreadId = 0;
#endif
m_uiEnabledCategories = 0;
m_pTracePipe = NULL;
}
/****************************************************************************
Public: Destructor
****************************************************************************/
FlmTrace::~FlmTrace()
{
flmAssert( m_uiLockCnt == 0);
if (m_hMutex != F_MUTEX_NULL)
{
f_mutexDestroy( &m_hMutex);
}
if (m_pTracePipe)
{
m_pTracePipe->Release();
}
}
/****************************************************************************
Public: addRef
Desc: Add a reference to this object.
****************************************************************************/
FLMUINT FlmTrace::AddRef( void)
{
FLMUINT uiReturnCnt;
lock();
uiReturnCnt = ++m_ui32RefCnt;
unlock();
return uiReturnCnt;
}
/****************************************************************************
Public: release
Desc: Removes a reference to this object.
****************************************************************************/
FLMUINT FlmTrace::Release( void)
{
FLMUINT uiReturnCnt;
lock();
uiReturnCnt = --m_ui32RefCnt;
unlock();
if( !uiReturnCnt)
{
delete this;
}
return uiReturnCnt;
}
/****************************************************************************
Public: FlmTrace::trace
Desc: Outputs the formatted message to the appropriate places.
****************************************************************************/
void FlmTrace::trace(
FLMUINT uiCategory,
const char * pszFormat,
...
)
{
f_va_list args;
f_va_start( args, pszFormat);
// First see if the stuff is enabled.
if (uiCategory & m_uiEnabledCategories)
{
lock();
// Leave room for terminator.
m_uiMaxLen = sizeof( m_szDestStr) - 1;
m_pszDestStr = &m_szDestStr [0];
m_uiCurrentForeColor = FLM_CURRENT_COLOR;
m_uiCurrentBackColor = FLM_CURRENT_COLOR;
m_uiForeColorDepth = 0;
m_uiBackColorDepth = 0;
m_uiCategory = uiCategory;
traceOutputArgs( pszFormat, (f_va_list *)&args);
outputCurrentText( m_uiCurrentForeColor, m_uiCurrentBackColor);
unlock();
}
f_va_end( args);
}
/****************************************************************************
Public: FlmTrace::setMultiThreaded
Desc: Enables this as a multi-threaded trace object.
****************************************************************************/
FLMBOOL FlmTrace::setMultiThreaded( void)
{
FLMBOOL bOk = TRUE;
if (m_hMutex == F_MUTEX_NULL)
{
if (RC_BAD( f_mutexCreate( &m_hMutex)))
{
bOk = FALSE;
}
}
return( bOk);
}
/****************************************************************************
Public: FlmTrace::setPipe
Desc: Sets a FlmTrace object to pipe output to.
****************************************************************************/
void FlmTrace::setPipe(
FlmTrace * pTracePipe
)
{
lock();
if (m_pTracePipe && m_pTracePipe != pTracePipe)
{
m_pTracePipe->Release();
}
if ((m_pTracePipe = pTracePipe) != NULL)
{
m_pTracePipe->AddRef();
}
unlock();
}
/****************************************************************************
Public: FlmTrace::lock
Desc: Locks the object for multi-threaded use.
****************************************************************************/
void FlmTrace::lock( void)
{
if (m_uiLockCnt)
{
#ifdef FLM_DEBUG
flmAssert( m_uiLockThreadId == f_threadId());
#endif
m_uiLockCnt++;
}
else if (m_hMutex != F_MUTEX_NULL)
{
f_mutexLock( m_hMutex);
m_uiLockCnt++;
#ifdef FLM_DEBUG
m_uiLockThreadId = f_threadId();
#endif
}
}
/****************************************************************************
Public: FlmTrace::unlock
Desc: Unlocks the object for multi-threaded use.
****************************************************************************/
void FlmTrace::unlock( void)
{
if (m_uiLockCnt)
{
#ifdef FLM_DEBUG
flmAssert( m_uiLockThreadId == f_threadId());
#endif
m_uiLockCnt--;
if (!m_uiLockCnt && m_hMutex != F_MUTEX_NULL)
{
f_mutexUnlock( m_hMutex);
#ifdef FLM_DEBUG
m_uiLockThreadId = 0;
#endif
}
}
}
/****************************************************************************
Public: FlmTrace::outputText
Desc: Calls outputString and then forwards to pipe for output.
****************************************************************************/
void FlmTrace::outputText(
FLMUINT uiCategory,
FLMUINT uiForeColor,
FLMUINT uiBackColor,
const char * pszString)
{
lock();
outputString( uiCategory, uiForeColor, uiBackColor, pszString);
unlock();
if (m_pTracePipe)
{
if (uiCategory & m_pTracePipe->getEnabledCategories())
{
m_pTracePipe->outputText( uiCategory, uiForeColor, uiBackColor,
pszString);
}
}
}
/****************************************************************************
Desc: Parameter 'ppszFormat' points to text following a '%' sign. Process
legal field information. Leave 'ppszFormat' pointing at the format
specifier character.
****************************************************************************/
void FlmTrace::processFieldInfo(
const char ** ppszFormat,
FLMUINT * puiWidth,
FLMUINT * puiPrecision,
FLMUINT * puiFlags,
f_va_list * args)
{
const char * pszTmp = *ppszFormat;
/* process flags */
*puiFlags = 0;
for (;;)
{
switch (*pszTmp)
{
case '-': *puiFlags |= FORMAT_MINUS_FLAG; break;
case '+': *puiFlags |= FORMAT_PLUS_FLAG; break;
case ' ': *puiFlags |= FORMAT_SPACE_FLAG; break;
case '#': *puiFlags |= FORMAT_POUND_FLAG; break;
case '0': *puiFlags |= FORMAT_ZERO_FLAG; break;
default:
goto Out1;
}
pszTmp++;
}
Out1:
// process width
*puiWidth = 0;
if (*pszTmp == '*')
{
*puiWidth = f_va_arg( *args, unsigned int);
++pszTmp;
}
else while (*pszTmp >= '0' && *pszTmp <= '9')
{
*puiWidth = (*puiWidth * 10) + (*pszTmp - '0');
++pszTmp;
}
// process precision
*puiPrecision = 0;
if (*pszTmp == '.')
{
++pszTmp;
if (*pszTmp == '*')
{
*puiPrecision = f_va_arg( *args, unsigned int);
++pszTmp;
}
else while (*pszTmp >= '0' && *pszTmp <= '9')
{
*puiPrecision = (*puiPrecision * 10) + (*pszTmp - '0');
++pszTmp;
}
}
// size modifiers
switch( *pszTmp)
{
case 'L': *puiFlags |= FORMAT_DOUBLE_FLAG; ++pszTmp; break;
case 'l': *puiFlags |= FORMAT_LONG_FLAG; ++pszTmp; break;
case 'h': *puiFlags |= FORMAT_SHORT_FLAG; ++pszTmp; break;
case 'I':
{
if( pszTmp[1] == '6' && pszTmp[2] == '4')
{
*puiFlags |= FORMAT_INT64_FLAG;
pszTmp += 3;
}
break;
}
}
*ppszFormat = pszTmp;
}
/****************************************************************************
Desc: Handle text portions of the text string.
****************************************************************************/
void FlmTrace::processStringText(
FLMUINT uiLen,
...)
{
f_va_list args;
f_va_start(args, uiLen);
if (uiLen)
{
formatString( 0, uiLen, uiLen, 0, (f_va_list *)&args);
}
f_va_end(args);
}
/****************************************************************************
Desc: Parse arguments in pszFormat, calling approopriate handlers.
****************************************************************************/
void FlmTrace::traceOutputArgs(
const char * pszFormat,
f_va_list * args)
{
FLMUINT uiChar;
FLMUINT uiWidth;
FLMUINT uiPrecision;
FLMUINT uiFlags;
const char * pszTextStart = pszFormat;
while ((uiChar = (FLMUINT)*pszFormat++) != 0)
{
if (uiChar != '%')
{
continue;
}
uiWidth = pszFormat - pszTextStart - 1;
processStringText( uiWidth, pszTextStart);
processFieldInfo( &pszFormat, &uiWidth, &uiPrecision, &uiFlags, args);
uiChar = (FLMUINT)*pszFormat++;
switch (uiChar)
{
case 'c':
case '%':
formatChar( uiChar, args);
break;
case 'B':
case 'F':
formatColor( uiChar, uiWidth, uiFlags);
break;
case 'd':
case 'o':
case 'u':
case 'x':
case 'X':
formatNumber( uiChar, uiWidth, uiPrecision, uiFlags, args);
break;
case 's':
case 'S':
case 'U':
formatString( uiChar, uiWidth, uiPrecision, uiFlags, args);
break;
default:
formatNotHandled();
break;
}
pszTextStart = pszFormat;
}
processStringText( (FLMUINT)(pszFormat - pszTextStart) - 1, pszTextStart);
}
/****************************************************************************
Desc: Change colors - may only push or pop a color on to the color stack.
****************************************************************************/
void FlmTrace::formatColor(
FLMUINT uiChar,
FLMUINT uiColor,
FLMUINT uiFlags)
{
FLMUINT uiPrevForeColor = m_uiCurrentForeColor;
FLMUINT uiPrevBackColor = m_uiCurrentBackColor;
if (uiChar == 'F') // Foreground color
{
if ((uiFlags & FORMAT_PLUS_FLAG) && m_uiForeColorDepth < 8)
{
m_uiForeColorStack [m_uiForeColorDepth++] = m_uiCurrentForeColor;
}
else if ((uiFlags & FORMAT_MINUS_FLAG) && m_uiForeColorDepth > 0)
{
m_uiCurrentForeColor = m_uiForeColorStack [--m_uiForeColorDepth];
}
else
{
m_uiCurrentForeColor = uiColor;
}
}
else // uiChar == 'B' - background color
{
if ((uiFlags & FORMAT_PLUS_FLAG) && m_uiBackColorDepth < 8)
{
m_uiBackColorStack [m_uiBackColorDepth++] = m_uiCurrentBackColor;
}
else if ((uiFlags & FORMAT_MINUS_FLAG) && m_uiBackColorDepth > 0)
{
m_uiCurrentBackColor = m_uiBackColorStack [--m_uiBackColorDepth];
}
else
{
m_uiCurrentBackColor = uiColor;
}
}
// If the color changed, output the current text with the last
// colors we had.
if ((m_uiCurrentForeColor != uiPrevForeColor) ||
(m_uiCurrentBackColor != uiPrevBackColor))
{
outputCurrentText( uiPrevForeColor, uiPrevBackColor);
}
}
/****************************************************************************
Desc: String formatter.
Outputs the asciiz string specified by ADDRESS in 's'.
Outputs length preceeded string specified by ADDRESS in 'S'.
Outputs unicode string specified by ADDRESS in 'U'.
Format: %[flags][width][.prec]'s'|'S'|'U'
flags = '-' left justifies if string length < width
width = minimum number of characters to print
prec = maximum number of characters to print
****************************************************************************/
void FlmTrace::formatString(
FLMUINT uiFormatChar,
FLMUINT uiWidth,
FLMUINT uiPrecision,
FLMUINT uiFlags,
f_va_list * args)
{
F_SPRINTF_INFO info;
info.pszDestStr = m_pszDestStr;
flmSprintfStringFormatter( (FLMBYTE)uiFormatChar, uiWidth,
uiPrecision, uiFlags, &info, args);
m_pszDestStr = info.pszDestStr;
}
/****************************************************************************
Desc: This is used by printf and sprintf to output numbers. It uses
recursion to separate the numbers down to individual digits and
output them in the proper order.
****************************************************************************/
FSTATIC FLMUINT traceFormatNumber(
FLMUINT64 ui64Number,
FLMINT uiBase,
char * pszDest)
{
char c = (char)(ui64Number % uiBase);
FLMUINT64 ui64Index = ui64Number / uiBase;
ui64Index = ui64Index
? traceFormatNumber( ui64Index, uiBase, pszDest)
: 0;
pszDest [ui64Index] = (char)((c > 9)
? c + 'a' - 10
: c + '0');
return (FLMUINT)(ui64Index + 1);
}
// Percent formating prefixes
#define P_NONE 0
#define P_MINUS 1
#define P_PLUS 2
#define P_POUND 3
/****************************************************************************
Desc: Number formatter.
Formats the number specified by VALUE in 'd', 'o', 'u', 'x', or 'X'
Format: %[flags][width][.prec]'E'
flags = 'h' value is uint16
'l' value is uint32
'-' left align result
'+' print plus sign if positive
'#' print '0x' in front of hex numbers
'0' zero-fill
width = minimum number of characters to output
prec = maximum number of characters to output (truncates or rounds)
****************************************************************************/
void FlmTrace::formatNumber(
FLMUINT uiFormatChar,
FLMUINT uiWidth,
FLMUINT uiPrecision,
FLMUINT uiFlags,
f_va_list * args)
{
FLMUINT uiCount;
FLMUINT uiPrefix = P_NONE;
FLMUINT uiLength;
FLMUINT uiBase = 10;
char szNumberBuffer [64];
char * pszStr;
FLMUINT64 ui64Arg;
if (uiFlags & FORMAT_SHORT_FLAG)
{
ui64Arg = f_va_arg( *args, int);
}
else if (uiFlags & FORMAT_LONG_FLAG)
{
ui64Arg = f_va_arg( *args, long int);
}
else if ( uiFlags & FORMAT_INT64_FLAG)
{
ui64Arg = f_va_arg( *args, FLMUINT64);
}
else
{
ui64Arg = f_va_arg( *args, int);
}
switch (uiFormatChar)
{
case 'd':
if ((long)ui64Arg < 0)
{
// handle negatives
uiPrefix = P_MINUS;
if (uiWidth > 0)
{
uiWidth--;
}
ui64Arg = -(long)ui64Arg;
}
else if (uiFlags & FORMAT_PLUS_FLAG)
{
uiPrefix = P_PLUS;
if (uiWidth > 0)
uiWidth--;
}
break;
case 'o':
uiBase = 8;
break;
case 'x':
case 'X':
if (uiFlags & FORMAT_POUND_FLAG && ui64Arg)
{
uiPrefix = P_POUND;
if (uiWidth > 1)
{
uiWidth -= 2;
}
}
uiBase = 16;
break;
}
uiLength = traceFormatNumber( ui64Arg, uiBase, szNumberBuffer);
szNumberBuffer [uiLength] = 0;
if (uiFormatChar == 'X')
{
char * p = &szNumberBuffer [0];
while (*p)
{
if ((*p >= 'a') && (*p <= 'z'))
{
*p = (char)(*p - 'a' + 'A');
}
p++;
}
}
if (uiWidth < uiLength)
{
uiWidth = uiLength;
}
if (uiFlags & FORMAT_ZERO_FLAG)
{
uiPrecision = uiWidth; // zero fill
}
else if (!(uiFlags & FORMAT_MINUS_FLAG))
{
// Right justify.
while ((uiWidth > uiLength) &&
(uiWidth > uiPrecision))
{
if (!m_uiMaxLen)
{
outputCurrentText( m_uiCurrentForeColor, m_uiCurrentBackColor);
}
*m_pszDestStr++ = ' ';
m_uiMaxLen--;
--uiWidth;
}
}
// handle the prefix if any
if (!m_uiMaxLen)
{
outputCurrentText( m_uiCurrentForeColor, m_uiCurrentBackColor);
}
switch (uiPrefix)
{
case P_MINUS:
*m_pszDestStr++ = '-';
m_uiMaxLen--;
break;
case P_PLUS:
*m_pszDestStr++ = '+';
m_uiMaxLen--;
break;
case P_POUND:
*m_pszDestStr++ = '0';
m_uiMaxLen--;
if (!m_uiMaxLen)
{
outputCurrentText( m_uiCurrentForeColor, m_uiCurrentBackColor);
}
*m_pszDestStr++ = (char)uiFormatChar;
m_uiMaxLen--;
break;
}
// handle the precision
while (uiLength < uiPrecision)
{
if (!m_uiMaxLen)
{
outputCurrentText( m_uiCurrentForeColor, m_uiCurrentBackColor);
}
*m_pszDestStr++ = '0';
m_uiMaxLen--;
--uiPrecision;
--uiWidth;
}
// print out the number
for (uiCount = uiLength, pszStr = szNumberBuffer;
uiCount > 0;
uiCount--, m_uiMaxLen--)
{
if (!m_uiMaxLen)
{
outputCurrentText( m_uiCurrentForeColor, m_uiCurrentBackColor);
}
*m_pszDestStr++ = *pszStr++;
}
if (uiFlags & FORMAT_MINUS_FLAG)
{
while (uiLength < uiWidth) // left justify
{
if (!m_uiMaxLen)
{
outputCurrentText( m_uiCurrentForeColor, m_uiCurrentBackColor);
}
*m_pszDestStr++ = ' ';
m_uiMaxLen--;
--uiWidth;
}
}
}
/****************************************************************************
Desc: Character formatter.
FOrmats the character specified by VALUE in 'c', or the '%' character.
Format: %[flags][width][.prec]'c'
flags = <not used>
width = <not used>
prec = <not used>
****************************************************************************/
void FlmTrace::formatChar(
FLMUINT uiFormatChar,
f_va_list * args)
{
char c = (uiFormatChar == '%')
? '%'
: f_va_arg( *args, int);
if (!m_uiMaxLen)
{
outputCurrentText( m_uiCurrentForeColor, m_uiCurrentBackColor);
}
*m_pszDestStr++ = c;
m_uiMaxLen--;
}
/****************************************************************************
Desc: Handles all formatting stuff that is invalid.
****************************************************************************/
void FlmTrace::formatNotHandled( void)
{
const char * pszNoFormatter = "<no formatter>";
FLMUINT uiLen = f_strlen( pszNoFormatter);
FLMUINT uiTmpLen;
while (uiLen)
{
if (!m_uiMaxLen)
{
outputCurrentText( m_uiCurrentForeColor, m_uiCurrentBackColor);
}
if ((uiTmpLen = uiLen) > m_uiMaxLen)
{
uiTmpLen = m_uiMaxLen;
}
f_memcpy( m_pszDestStr, (void *)pszNoFormatter, uiTmpLen);
m_pszDestStr += uiTmpLen;
m_uiMaxLen -= uiTmpLen;
uiLen -= uiTmpLen;
pszNoFormatter += uiTmpLen;
}
}
/****************************************************************************
Desc: Outputs the current text that we have buffered.
****************************************************************************/
void FlmTrace::outputCurrentText(
FLMUINT uiForeColor,
FLMUINT uiBackColor
)
{
FLMUINT uiLen = (FLMUINT)(m_pszDestStr - &m_szDestStr [0]);
if (uiLen)
{
m_szDestStr [uiLen] = 0;
outputText( m_uiCategory, uiForeColor, uiBackColor, m_szDestStr);
m_uiMaxLen = sizeof( m_szDestStr) - 1;
m_pszDestStr = &m_szDestStr [0];
}
}