Skip to content

Commit

Permalink
Debug guards: add a way to enable / disable per category
Browse files Browse the repository at this point in the history
- New way to enable / disable function guards per category. Such a category can
  be either a file name or of a different scope altogether.

- In non-shipping, the disabled guards still leave a skeleton in place, but the
  amount of executed code is minimal and should not be noticeable.

- In shipping, the guards are still removed altogether.

[#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 affc825 commit fc77c06
Show file tree
Hide file tree
Showing 4 changed files with 161 additions and 58 deletions.
67 changes: 46 additions & 21 deletions PowerEditor/src/MISC/Debug/npp_debug.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,7 @@ outputFunction setOutputFunction(outputFunction newOutputFunction)
return currentOutputFunc;
}

// Joce: We could (should?) make OutputF a functor
void outputF(TCHAR* format, ...)
{
va_list args;
Expand All @@ -50,54 +51,78 @@ void outputF(TCHAR* format, ...)
int FuncGuard::_depth = 0;
TCHAR FuncGuard::_indent[MAX_DEBUG_INDENT];

FuncGuard::FuncGuard(const TCHAR* funcsig, const TCHAR* funcname, const TCHAR* file, int line):
_funcname(funcname)
FuncGuard::FuncGuard( const TCHAR* funcsig, const TCHAR* funcname, const TCHAR* file, int line, State state, const TCHAR* category):
_state(state)
{
outputF(TEXT("%s%s(%d):\n"), getIndent(), file, line);
outputF(TEXT("%sEntering[ %s ]\n"), getIndent(), funcsig);
indent();
if (_state == Enabled)
{
_funcname = funcname;
// JOCE: we currently don't do anything with the category variable. Should it be here at all?
_category = category;

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

FuncGuard::~FuncGuard()
{
unindent();
outputF(TEXT("%sLeaving[ %s ]\n"), getIndent(), _funcname.c_str());
if (_state == Enabled)
{
unindent();
outputF(TEXT("%sLeaving[ %s ]\n"), getIndent(), _funcname.c_str());
}
}

void FuncGuard::outputIndent()
{
outputF(getIndent());
if (_state == Enabled)
{
outputF(getIndent());
}
}

void FuncGuard::indent()
{
_depth++;
if (_depth >= MAX_DEBUG_INDENT)
if (_state == Enabled)
{
DebugBreak();
_depth = MAX_DEBUG_INDENT-1;
_depth++;
if (_depth >= MAX_DEBUG_INDENT)
{
DebugBreak();
_depth = MAX_DEBUG_INDENT-1;
}
}
}

void FuncGuard::unindent()
{
_depth--;
if (_depth < 0)
if (_state == Enabled)
{
DebugBreak();
_depth = 0;
_depth--;
if (_depth < 0)
{
DebugBreak();
_depth = 0;
}
}
}

TCHAR* FuncGuard::getIndent()
{
int i = 0;;
for (; i < _depth; i++)
if (_state == Enabled)
{
_indent[i] = TEXT('\t');
int i = 0;;
for (; i < _depth; i++)
{
_indent[i] = TEXT('\t');
}
_indent[i] = TEXT('\0');
return _indent;
}
_indent[i] = TEXT('\0');
return _indent;
return TEXT("");
}

} // namespace Debug
Expand Down
82 changes: 52 additions & 30 deletions PowerEditor/src/MISC/Debug/npp_debug.h
Original file line number Diff line number Diff line change
Expand Up @@ -20,47 +20,69 @@

#ifndef SHIPPING

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

outputFunction setOutputFunction(outputFunction newOutputFunction);
outputFunction setOutputFunction(outputFunction newOutputFunction);

void outputF(TCHAR* format, ...);
void outputF(TCHAR* format, ...);

// JOCE: Nice to have: configurable indent character (' ', '\t', '_', '+', etc...)
class FuncGuard
{
public:
FuncGuard(const TCHAR* funcsig, const TCHAR* funcname, const TCHAR* file, int line);
~FuncGuard();
// JOCE: Nice to have: configurable indent character (' ', '\t', '_', '+', etc...)
class FuncGuard
{
public:
enum State
{
Disabled,
Enabled
};

void outputIndent();
FuncGuard(const TCHAR* funcsig, const TCHAR* funcname, const TCHAR* file, int line, State state, const TCHAR* category);
~FuncGuard();

private:
void indent();
void unindent();
TCHAR* getIndent();
generic_string _funcname;
void outputIndent();

static int _depth;
static TCHAR _indent[MAX_DEBUG_INDENT];
};
private:
void indent();
void unindent();
TCHAR* getIndent();
generic_string _funcname;
generic_string _category;
State _state;

} // namespace NppDebug
static int _depth;
static TCHAR _indent[MAX_DEBUG_INDENT];
};

#define debugf(format, ...) NppDebug::outputF(format, __VA_ARGS__)
// JOCE: modify to make that a single call to OutputF
#define line_debugf(format, ...) NppDebug::outputF(TEXT("%s(%d): "), TEXT(__FILE__), __LINE__); NppDebug::outputF(format, __VA_ARGS__)
// JOCE: modify to make that a single call to OutputF
#define guard_debugf(format, ...) __npp_func_guard__.outputIndent(); NppDebug::outputF(format, __VA_ARGS__)
#define func_guard() NppDebug::FuncGuard __npp_func_guard__(TEXT(__FUNCSIG__), TEXT(__FUNCTION__), TEXT(__FILE__), __LINE__)
} // namespace NppDebug

#define debugf(format, ...) NppDebug::outputF(format, __VA_ARGS__)
// JOCE: modify to make that a single call to OutputF
#define line_debugf(format, ...) NppDebug::outputF(TEXT("%s(%d): "), TEXT(__FILE__), __LINE__); NppDebug::outputF(format, __VA_ARGS__)

#define func_guard_declare_cat(cat) extern NppDebug::FuncGuard::State __func_guard_category_##cat
#define func_guard_enable_cat(cat) NppDebug::FuncGuard::State __func_guard_category_##cat = NppDebug::FuncGuard::Enabled
#define func_guard_disable_cat(cat) NppDebug::FuncGuard::State __func_guard_category_##cat = NppDebug::FuncGuard::Disabled

#define func_guard(cat) NppDebug::FuncGuard __npp_func_guard__( TEXT(__FUNCSIG__), TEXT(__FUNCTION__), TEXT(__FILE__), __LINE__, __func_guard_category_##cat, TEXT( #cat ))

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

#else // if !SHIPPING

#define debugf(format, ...) void(0)
#define _debugf(format, ...) void(0)
#define guard_func() void(0)
#define line_debugf(format, ...) void(0)

#define func_guard_declare_cat(cat) void(0)
#define func_guard_enable_cat(cat) void(0)
#define func_guard_disable_cat(cat) void(0)

#define func_guard(cat) void(0)

#define guard_debugf(format, ...) void(0)
#endif // SHIPPING

#endif // NPP_DEBUG_H
1 change: 1 addition & 0 deletions PowerEditor/src/precompiled_headers.h
Original file line number Diff line number Diff line change
Expand Up @@ -86,6 +86,7 @@
// Power Editor
#include "Common.h"


#include "Debug/npp_debug.h"

#endif // PRECOMPILED_HEADERS_H
69 changes: 62 additions & 7 deletions PowerEditor/tests/testNppDebug.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -65,7 +65,7 @@ class FuncGuardTest : public ::testing::Test
TEST_F(FuncGuardTest, guardSimple)
{
{
NppDebug::FuncGuard guard(TEXT("sig"), TEXT("name"), TEXT("file"), 1);
NppDebug::FuncGuard guard(TEXT("sig"), TEXT("name"), TEXT("file"), 1, NppDebug::FuncGuard::Enabled, TEXT("test"));
ASSERT_EQ(TEXT("file(1):\nEntering[ sig ]\n"), s_outputResult);
}
ASSERT_EQ(TEXT("file(1):\nEntering[ sig ]\nLeaving[ name ]\n"), s_outputResult);
Expand All @@ -74,28 +74,55 @@ TEST_F(FuncGuardTest, guardSimple)
TEST_F(FuncGuardTest, guardSimpleIndent)
{
{
NppDebug::FuncGuard guard1(TEXT("sig"), TEXT("name"), TEXT("file"), 1);
NppDebug::FuncGuard guard1(TEXT("sig"), TEXT("name"), TEXT("file"), 1, NppDebug::FuncGuard::Enabled, TEXT("test"));
ASSERT_EQ(TEXT("file(1):\nEntering[ sig ]\n"), s_outputResult);
{
NppDebug::FuncGuard guard2(TEXT("sig2"), TEXT("name2"), TEXT("file2"), 2);
NppDebug::FuncGuard guard2(TEXT("sig2"), TEXT("name2"), TEXT("file2"), 2, NppDebug::FuncGuard::Enabled, TEXT("test"));
ASSERT_EQ(TEXT("file(1):\nEntering[ sig ]\n\tfile2(2):\n\tEntering[ sig2 ]\n"), s_outputResult);
}
ASSERT_EQ(TEXT("file(1):\nEntering[ sig ]\n\tfile2(2):\n\tEntering[ sig2 ]\n\tLeaving[ name2 ]\n"), s_outputResult);
}
ASSERT_EQ(TEXT("file(1):\nEntering[ sig ]\n\tfile2(2):\n\tEntering[ sig2 ]\n\tLeaving[ name2 ]\nLeaving[ name ]\n"), s_outputResult);
}

TEST_F(FuncGuardTest, guardSimpleDisabled)
{
{
NppDebug::FuncGuard guard(TEXT("sig"), TEXT("name"), TEXT("file"), 1, NppDebug::FuncGuard::Disabled, TEXT("test"));
ASSERT_EQ(TEXT(""), s_outputResult);
}
ASSERT_EQ(TEXT(""), s_outputResult);
}

TEST_F(FuncGuardTest, guardSimpleIndentDisabled)
{
{
NppDebug::FuncGuard guard1(TEXT("sig"), TEXT("name"), TEXT("file"), 1, NppDebug::FuncGuard::Disabled, TEXT("test"));
ASSERT_EQ(TEXT(""), s_outputResult);
{
NppDebug::FuncGuard guard2(TEXT("sig2"), TEXT("name2"), TEXT("file2"), 2, NppDebug::FuncGuard::Disabled, TEXT("test"));
ASSERT_EQ(TEXT(""), s_outputResult);
}
ASSERT_EQ(TEXT(""), s_outputResult);
}
ASSERT_EQ(TEXT(""), s_outputResult);
}

// Enable the 'test' function guard category
func_guard_enable_cat(test);


static TCHAR TestGuardFuncOneGuardLine[8];
void TestGuardFuncOne()
{
func_guard(); int line = __LINE__; // This declaration needs to be on the same line as func_guard to get the right line number.
func_guard(test); int line = __LINE__; // This declaration needs to be on the same line as func_guard to get the right line number.
_itot_s(line, TestGuardFuncOneGuardLine, 10);
}

static TCHAR TestGuardFuncTwoGuardLine[8];
void TestGuardFuncTwo()
{
func_guard(); int line = __LINE__; // This declaration needs to be on the same line as func_guard to get the right line number.
func_guard(test); int line = __LINE__; // This declaration needs to be on the same line as func_guard to get the right line number.
_itot_s(line, TestGuardFuncTwoGuardLine, 10);
TestGuardFuncOne();
}
Expand Down Expand Up @@ -133,14 +160,14 @@ TEST_F(FuncGuardTest, guardFuncIndent)

void TestGuardFuncWithCommentOne()
{
func_guard(); int line = __LINE__; // This declaration needs to be on the same line as func_guard to get the right line number.
func_guard(test); int line = __LINE__; // This declaration needs to be on the same line as func_guard to get the right line number.
_itot_s(line, TestGuardFuncOneGuardLine, 10);
guard_debugf(TEXT("We print a number: %d\n"), 42);
}

void TestGuardFuncWithCommentTwo()
{
func_guard(); int line = __LINE__; // This declaration needs to be on the same line as func_guard to get the right line number.
func_guard(test); int line = __LINE__; // This declaration needs to be on the same line as func_guard to get the right line number.
_itot_s(line, TestGuardFuncTwoGuardLine, 10);
TestGuardFuncWithCommentOne();
}
Expand All @@ -165,5 +192,33 @@ TEST_F(FuncGuardTest, guardFuncIndentWithDebugComment)
ASSERT_EQ(expected, s_outputResult);
}

// Disable the 'test_disable' function guard category
func_guard_disable_cat(test_disable);

void TestGuardFuncDisabledOne()
{
func_guard(test_disable);
}

void TestGuardFuncDisabledTwo()
{
func_guard(test_disable);
TestGuardFuncDisabledOne();
}

TEST_F(FuncGuardTest, guardFuncDisabled)
{
TestGuardFuncDisabledOne();
generic_string expected = TEXT("");
ASSERT_EQ(expected, s_outputResult);
}

TEST_F(FuncGuardTest, guardFuncIndentDisabled)
{
TestGuardFuncDisabledTwo();
generic_string expected = TEXT("");
ASSERT_EQ(expected, s_outputResult);
}


#endif // SHIPPING

0 comments on commit fc77c06

Please sign in to comment.