Skip to content

Commit

Permalink
Debug output: improve output performance and design
Browse files Browse the repository at this point in the history
- Replace the `outputF` function with the `DebugOutput` object that allows
  to bundle up the outputs and flush them to the debug console only when ready.
- It also improves the testability of debug tools that need to output as you
  now only have to overload the output part of the class.
- `DebugOutput` comes with its set of tests.
- The existing function guards tests have been updated to reflect the new
  output method.

- Future improvements:
  - Instead of an extern variable to the global `DebugOutput` (yuk) we could
    implement a DebugOutput stack where we could push and pop `DebugOutput`
    objects. This stack would live in the application object.

[#8 state:needs_ack responsible:npp-community]

Signed-off-by: Jocelyn Legault <jocelynlegault@gmail.com>
  • Loading branch information
joce authored and Thell Fowler committed Dec 6, 2009
1 parent 9b0cc77 commit bcb2c98
Show file tree
Hide file tree
Showing 3 changed files with 229 additions and 59 deletions.
72 changes: 51 additions & 21 deletions PowerEditor/src/MISC/Debug/npp_debug.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -23,29 +23,57 @@

namespace NppDebug
{
DebugOutput defaultDebugOutput;
DebugOutput* g_debugOutput = &defaultDebugOutput;

static outputFunction debugOutput = OutputDebugString;
DebugOutput::DebugOutput()
{
resetValues();
}

void DebugOutput::printf(const TCHAR* format, ...)
{
if (format)
{
va_list args;

va_start( args, format );
int nbWrittenChar = _vsntprintf_s( m_currentPtr, MAX_DEBUG_STR - m_currentLen, _TRUNCATE, format, args );
if (nbWrittenChar >= 0)
{
m_currentLen += nbWrittenChar;
}
else // _vsntprintf_s returned -1, this means we were truncated.
{
m_currentLen = MAX_DEBUG_STR-1;
}
m_currentPtr = &m_outputStr[0] + m_currentLen;
}
else
{
*m_currentPtr = TEXT('\0');
}
}

void DebugOutput::flush()
{
if (m_outputStr[0] != TEXT('\0'))
{
output(&m_outputStr[0]);
resetValues();
}
}

outputFunction setOutputFunction(outputFunction newOutputFunction)
void DebugOutput::output(const TCHAR* str)
{
outputFunction currentOutputFunc = debugOutput;
debugOutput = newOutputFunction;
return currentOutputFunc;
OutputDebugString(str);
}

// Joce: We could (should?) make OutputF a functor
void outputF(TCHAR* format, ...)
void DebugOutput::resetValues()
{
va_list args;
int len;
TCHAR* buffer;

va_start( args, format );
len = _vsctprintf( format, args ) + 1; // _vscprintf doesn't count terminating '\0'
buffer = new TCHAR[len];
_vstprintf_s( buffer, len, format, args );
debugOutput(buffer);
delete [] buffer;
m_outputStr[0] = TEXT('\0');
m_currentPtr = &m_outputStr[0];
m_currentLen = 0;
}

int FuncGuard::_depth = 0;
Expand All @@ -61,9 +89,10 @@ FuncGuard::FuncGuard( const TCHAR* funcsig, const TCHAR* funcname, const TCHAR*
_category = category;

// JOCE Only one call to OutputF.
outputF(TEXT("%s%s(%d):\n"), getIndent(), file, line);
outputF(TEXT("%sEntering[ %s ]\n"), getIndent(), funcsig);
g_debugOutput->printf(TEXT("%s%s(%d):\n"), getIndent(), file, line);
g_debugOutput->printf(TEXT("%sEntering[ %s ]\n"), getIndent(), funcsig);
indent();
g_debugOutput->flush();
}
}

Expand All @@ -72,15 +101,16 @@ FuncGuard::~FuncGuard()
if (_state == Enabled)
{
unindent();
outputF(TEXT("%sLeaving[ %s ]\n"), getIndent(), _funcname.c_str());
g_debugOutput->printf(TEXT("%sLeaving[ %s ]\n"), getIndent(), _funcname.c_str());
g_debugOutput->flush();
}
}

void FuncGuard::outputIndent()
{
if (_state == Enabled)
{
outputF(getIndent());
g_debugOutput->printf(getIndent());
}
}

Expand Down
33 changes: 22 additions & 11 deletions PowerEditor/src/MISC/Debug/npp_debug.h
Original file line number Diff line number Diff line change
Expand Up @@ -20,14 +20,25 @@

#ifndef SHIPPING

#define MAX_DEBUG_INDENT 1024
#define MAX_DEBUG_INDENT 32
#define MAX_DEBUG_STR 1024
namespace NppDebug
{
typedef void (__stdcall *outputFunction)(const TCHAR*);

outputFunction setOutputFunction(outputFunction newOutputFunction);
class DebugOutput
{
public:
DebugOutput();
void printf(const TCHAR* format, ...);
void flush();
protected:
virtual void output(const TCHAR* str);
void resetValues();
TCHAR m_outputStr[MAX_DEBUG_STR];
TCHAR* m_currentPtr;
int m_currentLen;
};

void outputF(TCHAR* format, ...);
extern DebugOutput* g_debugOutput;

// JOCE: Nice to have: configurable indent character (' ', '\t', '_', '+', etc...)
class FuncGuard
Expand Down Expand Up @@ -59,7 +70,7 @@ namespace NppDebug
} // namespace NppDebug

// debugf() works just at printf(), except that it outputs to the debug console in MSVC
#define debugf(format, ...) NppDebug::outputF(format, __VA_ARGS__)
#define debugf(format, ...) NppDebug::g_debugOutput->printf(format, __VA_ARGS__); NppDebug::g_debugOutput->flush()

// line_debugf() works just as debugf, but it prefixes the text message with the file name
// and line number of the call in a way that MSVC recognizes so you can double click on the
Expand All @@ -69,9 +80,9 @@ namespace NppDebug
// source\folder\file.cpp(42): Hello World!!!

#define line_debugf(format, ...) \
/* JOCE: modify to make that a single call to OutputF */ \
NppDebug::outputF(TEXT("%s(%d): "), TEXT(__FILE__), __LINE__); \
NppDebug::outputF(format, __VA_ARGS__)
NppDebug::g_debugOutput->printf(TEXT("%s(%d): "), TEXT(__FILE__), __LINE__); \
NppDebug::g_debugOutput->printf(format, __VA_ARGS__); \
NppDebug::g_debugOutput->flush()

//
// Debug Guards
Expand Down Expand Up @@ -183,9 +194,9 @@ namespace NppDebug
// Leaving[ FooTwo ]

#define guard_debugf(format, ...) \
/* JOCE: modify to make that a single call to OutputF (should make guard_debugf part of the function guard */ \
__npp_func_guard__.outputIndent(); \
NppDebug::outputF(format, __VA_ARGS__)
NppDebug::g_debugOutput->printf(format, __VA_ARGS__); \
NppDebug::g_debugOutput->flush()

#else // if !SHIPPING

Expand Down

0 comments on commit bcb2c98

Please sign in to comment.