Files
gsmartcontrol/src/hz/debug.h
T
2012-08-11 16:18:34 +00:00

367 lines
9.4 KiB
C++

/**************************************************************************
Copyright:
(C) 2008 - 2012 Alexander Shaduri <ashaduri 'at' gmail.com>
License: See LICENSE_zlib.txt file
***************************************************************************/
/// \file
/// \author Alexander Shaduri
/// \ingroup hz
/// \weakgroup hz
/// @{
#ifndef HZ_DEBUG_H
#define HZ_DEBUG_H
#include "hz_config.h" // feature macros
#include <cstdio> // std::fprintf(), std::vfprintf()
#ifndef __GNUC__
#include <cstdarg> // std::va_start, va_list macro and friends
#endif
/*
#include <cassert>
#ifndef ASSERT // assert() is undefined if NDEBUG is defined.
# define ASSERT(a) assert(a)
#endif
*/
/**
\file
This file is a link between libhz (and its users) and libdebug.
It provides a way to write in libdebug-like API without actually
using libdebug.
Note that it provides only output functions. The setup functions
cannot be emulated (but you probably won't need them in libraries
anyway).
*/
// Use libdebug as is
#if defined(HZ_USE_LIBDEBUG) && (HZ_USE_LIBDEBUG)
// only output functions
#include "libdebug/libdebug_mini.h"
#else
// undef them in case libdebug was included
#ifdef debug_out_dump
#undef debug_out_dump
#endif
#ifdef debug_out_info
#undef debug_out_info
#endif
#ifdef debug_out_warn
#undef debug_out_warn
#endif
#ifdef debug_out_error
#undef debug_out_error
#endif
#ifdef debug_out_fatal
#undef debug_out_fatal
#endif
#ifdef debug_print_dump
#undef debug_print_dump
#endif
#ifdef debug_print_info
#undef debug_print_info
#endif
#ifdef debug_print_warn
#undef debug_print_warn
#endif
#ifdef debug_print_error
#undef debug_print_error
#endif
#ifdef debug_print_fatal
#undef debug_print_fatal
#endif
#ifdef DBG_FILE
#undef DBG_FILE
#endif
#ifdef DBG_LINE
#undef DBG_LINE
#endif
#ifdef DBG_FUNC_NAME
#undef DBG_FUNC_NAME
#endif
#ifdef DBG_FUNC_PRNAME
#undef DBG_FUNC_PRNAME
#endif
#ifdef DBG_FUNC
#undef DBG_FUNC
#endif
#ifdef DBG_FUNC_MSG
#undef DBG_FUNC_MSG
#endif
#ifdef DBG_POS
#undef DBG_POS
#endif
#ifdef DBG_TRACE_POINT_MSG
#undef DBG_TRACE_POINT_MSG
#endif
#ifdef DBG_TRACE_POINT_AUTO
#undef DBG_TRACE_POINT_AUTO
#endif
#ifdef DBG_FUNCTION_ENTER_MSG
#undef DBG_FUNCTION_ENTER_MSG
#endif
#ifdef DBG_FUNCTION_EXIT_MSG
#undef DBG_FUNCTION_EXIT_MSG
#endif
#ifdef DBG_ASSERT_MSG
#undef DBG_ASSERT_MSG
#endif
#ifdef DBG_ASSERT
#undef DBG_ASSERT
#endif
// emulate libdebug API through std::cerr
#if defined(HZ_EMULATE_LIBDEBUG) && HZ_EMULATE_LIBDEBUG
#include <iostream>
#include <cstdio>
#include <string>
// cerr / stderr have no buffering, so no need to sync them with each other.
#define debug_out_dump(domain, output) \
std::cerr << "<dump> [" << (domain) << "] " << output
#define debug_out_info(domain, output) \
std::cerr << "<info> [" << (domain) << "] " << output
#define debug_out_warn(domain, output) \
std::cerr << "<warn> [" << (domain) << "] " << output
#define debug_out_error(domain, output) \
std::cerr << "<error> [" << (domain) << "] " << output
#define debug_out_fatal(domain, output) \
std::cerr << "<fatal> [" << (domain) << "] " << output
#ifdef __GNUC__
// The "trim trailing comma" and "##" extensions are GNU features (works with intel too).
// The ## part is needed to avoid requirement of at least one argument after "format".
#define debug_print_dump(domain, format, ...) \
std::fprintf(stderr, (std::string("<dump> [") + (domain) + "] " + format).c_str(), ## __VA_ARGS__)
#define debug_print_info(domain, format, ...) \
std::fprintf(stderr, (std::string("<info> [") + (domain) + "] " + format).c_str(), ## __VA_ARGS__)
#define debug_print_warn(domain, format, ...) \
std::fprintf(stderr, (std::string("<warn> [") + (domain) + "] " + format).c_str(), ## __VA_ARGS__)
#define debug_print_error(domain, format, ...) \
std::fprintf(stderr, (std::string("<error> [") + (domain) + "] " + format).c_str(), ## __VA_ARGS__)
#define debug_print_fatal(domain, format, ...) \
std::fprintf(stderr, (std::string("<fatal> [") + (domain) + "] " + format).c_str(), ## __VA_ARGS__)
#else // non-gcc compilers:
namespace hz {
namespace internal {
inline void debug_print_impl(const std::string& header, const char* format, ...)
{
std::va_list ap;
va_start(ap, format);
std::vfprintf(stderr, (header + format).c_str(), ap);
va_end(ap);
}
}
}
#define debug_print_dump(domain, ...) \
hz::internal::debug_print_impl(std::string("<dump> [") + (domain) + "] ", __VA_ARGS__)
#define debug_print_info(domain, ...) \
hz::internal::debug_print_impl(std::string("<info> [") + (domain) + "] ", __VA_ARGS__)
#define debug_print_warn(domain, ...) \
hz::internal::debug_print_impl(std::string("<warn> [") + (domain) + "] ", __VA_ARGS__)
#define debug_print_error(domain, ...) \
hz::internal::debug_print_impl(std::string("<error> [") + (domain) + "] ", __VA_ARGS__)
#define debug_print_fatal(domain, ...) \
hz::internal::debug_print_impl(std::string("<fatal> [") + (domain) + "] ", __VA_ARGS__)
#endif
#define DBG_FILE __FILE__
#define DBG_LINE __LINE__
#if defined HAVE_CXX___func__ && HAVE_CXX___func__
#define DBG_FUNC_NAME __func__
#elif defined HAVE_CXX___FUNCTION__ && HAVE_CXX___FUNCTION__
#define DBG_FUNC_NAME __FUNCTION__
#else
#define DBG_FUNC_NAME "unknown"
#endif
#ifdef __GNUC__
#define DBG_FUNC_PRNAME __PRETTY_FUNCTION__
#else
#define DBG_FUNC_PRNAME DBG_FUNC_NAME
#endif
#include <string>
namespace hz {
namespace internal {
inline std::string format_function_msg(const std::string& func, bool add_suffix)
{
// if it's "bool<unnamed>::A::func(int)" or "bool test::A::func(int)",
// remove the return type and parameters.
std::string::size_type endpos = func.find('(');
if (endpos == std::string::npos)
endpos = func.size();
// search for first space (after the parameter), or "<unnamed>".
std::string::size_type pos = func.find_first_of(" >");
if (pos != std::string::npos) {
if (func[pos] == '>')
pos += 2; // skip ::
++pos; // skip whatever character we're over
// debug_out_info("default", "pos: " << pos << ", endpos: " << endpos << "\n");
return func.substr(pos >= endpos ? 0 : pos, endpos - pos) + (add_suffix ? "(): " : "()");
}
return func.substr(0, endpos) + (add_suffix ? "(): " : "()");
}
}
}
#define DBG_FUNC (hz::internal::format_function_msg(DBG_FUNC_PRNAME, false).c_str())
#define DBG_FUNC_MSG (hz::internal::format_function_msg(DBG_FUNC_PRNAME, true).c_str())
// Note: DBG_POS is not an object if emulated or disabled! Only valid for outputting to streams.
#define DBG_POS "(function: " << DBG_FUNC_NAME << "(), file: " << DBG_FILE \
<< ", line: " << DBG_LINE << ")"
#define DBG_TRACE_POINT_MSG(a) debug_out_dump("default", "Trace point \"" << #a << "\" reached at " << DBG_POS << ".\n")
#define DBG_TRACE_POINT_AUTO debug_out_dump("default", "Trace point reached at " << DBG_POS << ".\n")
#define DBG_FUNCTION_ENTER_MSG debug_out_dump("default", "ENTER: \"" << DBG_FUNC << "\"\n")
#define DBG_FUNCTION_EXIT_MSG debug_out_dump("default", "EXIT: \"" << DBG_FUNC << "\"\n")
#define DBG_ASSERT_MSG(cond, msg) \
if (true) { \
if (!(cond)) \
debug_out_error("default", (msg) << "\n"); \
} else (void)0
#define DBG_ASSERT(cond) \
if (true) { \
if (!(cond)) \
debug_out_error("default", "ASSERTION FAILED: " << #cond << " at " << DBG_POS << "\n"); \
} else (void)0
// No output at all
#else
// do/while block is needed to:
// 1. make " if(a) debug_out_info(); f(); " work correctly.
// 2. require terminating semicolon.
#define debug_out_dump(domain, output) if(true){}else(void)0
#define debug_out_info(domain, output) if(true){}else(void)0
#define debug_out_warn(domain, output) if(true){}else(void)0
#define debug_out_error(domain, output) if(true){}else(void)0
#define debug_out_fatal(domain, output) if(true){}else(void)0
#define debug_print_dump(domain, format, ...) if(true){}else(void)0
#define debug_print_info(domain, format, ...) if(true){}else(void)0
#define debug_print_warn(domain, format, ...) if(true){}else(void)0
#define debug_print_error(domain, format, ...) if(true){}else(void)0
#define debug_print_fatal(domain, format, ...) if(true){}else(void)0
#define DBG_FILE ""
#define DBG_LINE 0
#define DBG_FUNC_NAME ""
#define DBG_FUNC_PRNAME ""
#define DBG_FUNC ""
#define DBG_FUNC_MSG ""
// Note: DBG_POS is not an object if emulated or disabled!
#define DBG_POS ""
#define DBG_TRACE_POINT_MSG(a) if(true){}else(void)0
#define DBG_TRACE_POINT_AUTO if(true){}else(void)0
#define DBG_FUNCTION_ENTER_MSG if(true){}else(void)0
#define DBG_FUNCTION_EXIT_MSG if(true){}else(void)0
#define DBG_ASSERT_MSG(cond, msg) if(true){}else(void)0
#define DBG_ASSERT(cond) if(true){}else(void)0
#endif
// other stuff, emulated or not
// #ifdef debug_begin
// #undef debug_begin
// #endif
#define debug_begin() if(true){}else(void)0
// #ifdef debug_end
// #undef debug_end
// #endif
#define debug_end() if(true){}else(void)0
#define debug_indent_inc(...) if(true){}else(void)0
#define debug_indent_dec(...) if(true){}else(void)0
#define debug_indent_reset() if(true){}else(void)0
#define debug_indent ""
#define debug_unindent ""
#define debug_resindent ""
#endif
#endif
/// @}