MQLplus/lib_debug/lib_debug_macros.mqh

214 lines
14 KiB
MQL5
Raw Permalink Normal View History

2025-05-30 16:09:52 +02:00
#ifndef LIB_DBG_DEBUG_MACROS_MQH_INCLUDED
#define LIB_DBG_DEBUG_MACROS_MQH_INCLUDED
#property version "5.10"
/**********************************************************************************
* Copyright (C) 2020 Dominik Egert <info@freie-netze.de>
*
* This file is the debugger main user macros include file.
*
* Lisence applied: GPLv2
* https://www.gnu.org/licenses/old-licenses/gpl-2.0.html
*
* Author Dominik Egert / Freie Netze UG.
**********************************************************************************
*
* Version: 5.10
* State: public
*
* File information
* ================
*
*/
//*********************************************************************************************************************************************************/
// BEGIN Debugging macros
//
/////////////////////////////////////////////////////////////////////////////////////////////////////
//
// Debugger helpers
//
#ifndef LIB_DEBUG_INCLUDE_STUB
// Stringify macro helper
#define DBG_TO_STRING(x) LIB_DBG_NAMESPACE(dbg_lib, dbg_printf)("%s", __DBG_STRINGIFY_MACRO(x));
// Custom register enum resolver macro
#ifdef __MQL5__
#define DBG_ENUM_RESOLVER(x) namespace dbg_lib { const string LIB_DBG_NAMESPACE_DEF(dbg_lib, var_out)(const string name, x val, const int shift = 0, const string prefix = "", const int offset = 0, const bool hex = DBG_HEX_OUTPUT) { return(LIB_DBG_NAMESPACE_DEF(dbg_lib, enum_to_string)(name, val, shift, prefix, offset, hex)); }; }
#else
#define DBG_ENUM_RESOLVER(x) const string LIB_DBG_NAMESPACE_DEF(dbg_lib, var_out)(const string name, x val, const int shift = 0, const string prefix = "", const int offset = 0, const bool hex = DBG_HEX_OUTPUT) { return(LIB_DBG_NAMESPACE_DEF(dbg_lib, enum_to_string)(name, val, shift, prefix, offset, hex)); }
#endif
// Debug to string functions
#define DBG_STR(x) LIB_DBG_NAMESPACE(dbg_lib, dbg_context_msg)(DBG_OUTPUT_PREFIX, __FILE__, __FUNCTION__, __LINE__, x)
#define DBG_STR_IF(c, x) ((c) ? LIB_DBG_NAMESPACE(dbg_lib, dbg_context_msg)(DBG_OUTPUT_PREFIX, __FILE__, __FUNCTION__, __LINE__, LIB_DBG_NAMESPACE(dbg_lib, dbg_StringFormat)("$$DBG_IF(%s)$$ :--> %s", #c, x)) : NULL)
#define DBG_STR_VAR(x) LIB_DBG_NAMESPACE(dbg_lib, dbg_context_msg)(DBG_OUTPUT_PREFIX, __FILE__, __FUNCTION__, __LINE__, LIB_DBG_NAMESPACE(dbg_lib, var_out)(__DBG_STRINGIFY_MACRO((x)), (x)), "=", DBG_MSG_FORMAT_RIGHT_COLUMN_SPACER)
#define DBG_STR_VAR_IF(c, x) ((c) ? LIB_DBG_NAMESPACE(dbg_lib, dbg_context_msg)(DBG_OUTPUT_PREFIX, __FILE__, __FUNCTION__, __LINE__, LIB_DBG_NAMESPACE(dbg_lib, dbg_StringFormat)("$$DBG_IF(%s)$$ :--> %s", #c, LIB_DBG_NAMESPACE(dbg_lib, var_out)(__DBG_STRINGIFY_MACRO((x)), (x))), "=", DBG_MSG_FORMAT_RIGHT_COLUMN_SPACER) : NULL)
#define DBG_STR_PERSIST(x) DBG_STR(x)
#define DBG_STR_BITS(x) LIB_DBG_NAMESPACE(dbg_lib, dbg_context_msg)(DBG_OUTPUT_PREFIX, __FILE__, __FUNCTION__, __LINE__, LIB_DBG_NAMESPACE(dbg_lib, var_out)(__DBG_STRINGIFY_MACRO((x)), (x), 0, "", 0, false), "=", DBG_MSG_FORMAT_RIGHT_COLUMN_SPACER)
#define DBG_STR_ERRCODE(x) LIB_DBG_NAMESPACE(dbg_lib, dbg_context_msg)(DBG_OUTPUT_PREFIX, __FILE__, __FUNCTION__, __LINE__, LIB_DBG_NAMESPACE(dbg_lib, var_out)(__DBG_STRINGIFY_MACRO((x)), LIB_DBG_NAMESPACE(dbg_lib, dbg_errcode_to_name)(x)), "=", DBG_MSG_FORMAT_RIGHT_COLUMN_SPACER)
// Debug std out
#define DBG_MSG(x) LIB_DBG_NAMESPACE(dbg_lib, dbg_printf)(DBG_STR(x));
#define DBG_MSG_IF(c, x) { if(c) { LIB_DBG_NAMESPACE(dbg_lib, dbg_printf)(DBG_STR_IF(c, x)); } }
#define DBG_MSG_VAR(x) LIB_DBG_NAMESPACE(dbg_lib, dbg_printf)(DBG_STR_VAR(x));
#define DBG_MSG_VAR_IF(c, x) { if(c) { LIB_DBG_NAMESPACE(dbg_lib, dbg_printf)(DBG_STR_VAR_IF(c, x)); } }
#define DBG_MSG_PERSIST(x) DBG_MSG(x)
#define DBG_MSG_BITS(x) LIB_DBG_NAMESPACE(dbg_lib, dbg_printf)(DBG_STR_BITS(x))
#define DBG_MSG_ERRCODE(x) LIB_DBG_NAMESPACE(dbg_lib, dbg_printf)(DBG_STR_ERRCODE(x), true)
// Var dump macro
#define DBG_MSG_LISTDUMP(x, y) LIB_DBG_NAMESPACE(dbg_lib, list_dump_arrays)(x, #x, y, #y, __FILE__, __FUNCTION__, __LINE__, DBG_MSG_VAR_ARRAY_LIMIT(x))
// Tracing inside ()-condition statements
#define DBG_MSG_EVAL(x) (LIB_DBG_NAMESPACE(dbg_lib, dbg_eval_return)(__FILE__, __FUNCTION__, __LINE__, __DBG_STRINGIFY_MACRO(x), x))
#define DBG_MSG_EVAL_IF(c, x) (LIB_DBG_NAMESPACE(dbg_lib, dbg_eval_return)(__FILE__, __FUNCTION__, __LINE__, __DBG_STRINGIFY_MACRO(x), x, c))
#define DBG_MSG_EVAL_CMNT(m, x) (LIB_DBG_NAMESPACE(dbg_lib, dbg_eval_return)(__FILE__, __FUNCTION__, __LINE__, __DBG_STRINGIFY_MACRO(x), x, true, m))
#define DBG_MSG_EVAL_IF_CMNT(c, m, x) (LIB_DBG_NAMESPACE(dbg_lib, dbg_eval_return)(__FILE__, __FUNCTION__, __LINE__, __DBG_STRINGIFY_MACRO(x), x, c, m))
// Array check macro
#define DBG_MSG_ARRAY_OUT_OF_RANGE(x, y) { if((y < NULL) || (y >= LIB_DBG_NAMESPACE(dbg_lib, dbg_ArraySize)(x))) { DBG_MSG(LIB_DBG_NAMESPACE(dbg_lib, dbg_StringFormat)("%s{%i] :--> ARRAY OUT OF RANGE", __DBG_STRINGIFY_MACRO(x), y)); DBG_MSG_VAR(x); } }
// Program uninit reason tracing
#define DBG_SET_UNINIT_REASON(x) LIB_DBG_NAMESPACE(dbg_lib, dbg_uninit_reason) = x;
#define DBG_MSG_UNINIT_RESOLVER if(_StopFlag) { DBG_MSG_VAR(_StopFlag); } LIB_DBG_NAMESPACE(dbg_lib, uninit_text)(__FUNCTION__, -1);
// Include-File loader tracing
#ifdef __MQL5__
#define DBG_FILE_VARNAME(x) dbg_file_loader_##x
#define DBG_MSG_TRACE_FILE_LOADER static bool DBG_FILE_VARNAME(__COUNTER__) = LIB_DBG_NAMESPACE(dbg_lib, dbg_print_file_trace)(__FILE__);
#else
#define DBG_MSG_TRACE_FILE_LOADER
#endif
#endif
// MQL-API function tracer macro
#ifndef DBG_MSG_MQLFUNC
#define DBG_MSG_MQLFUNC(x, id) dbg_mql_api_call_tracer.trace_call_details(__LINE__, id, __FILE__, __FUNCTION__, #x, DBG_MQLAPI_VERSION).x
#endif
//
/////////////////////////////////////////////////////////////////////////////////////////////////////
/////////////////////////////////////////////////////////////////////////////////////////////////////
//
// Assert support
//
// Generic assert definition
#define DBG_GENERIC_ASSERT(condition, message) { if(!(condition)) { string msg = LIB_DBG_NAMESPACE(dbg_lib, dbg_StringFormat)(DBG_OUTPUT_STRING, ((#condition == "") ? "" : #condition + " "), DBG_CODE_LOCATION_STRING, message);
// Call modal dialog and div/zero!
#define DBG_ASSERT(condition, message) DBG_GENERIC_ASSERT(condition, message) LIB_DBG_NAMESPACE(dbg_lib, dbg_Alert)(DBG_ASSERT_MSG_TXT + " " + msg); DBG_CRASH_CODE; } }
// Print out information
#define DBG_ASSERT_LOG(condition, message) DBG_GENERIC_ASSERT(condition, message) LIB_DBG_NAMESPACE(dbg_lib, dbg_printf)("%s%s %s", DBG_OUTPUT_PREFIX + DBG_OUTPUT_PREFIX, DBG_ASSERT_MSG_TXT, msg); } }
// Print info and abort execution by return;
#define DBG_ASSERT_RETURN(condition, message) DBG_GENERIC_ASSERT(condition, message) LIB_DBG_NAMESPACE(dbg_lib, dbg_printf)("%s%s %s", DBG_OUTPUT_PREFIX + DBG_OUTPUT_PREFIX, DBG_ASSERT_MSG_TXT, msg); return; } }
// Print info and abort execution by return;
#define DBG_ASSERT_RETURN_VAR(condition, message, return_value) DBG_GENERIC_ASSERT(condition, message) LIB_DBG_NAMESPACE(dbg_lib, dbg_printf)("%s%s %s", DBG_OUTPUT_PREFIX + DBG_OUTPUT_PREFIX, DBG_ASSERT_MSG_TXT, msg); return(return_value); } }
//
/////////////////////////////////////////////////////////////////////////////////////////////////////
/////////////////////////////////////////////////////////////////////////////////////////////////////
//
// Software inherited brakepoints
//
// Debugging macros
#define DBG_SOFT_BREAKPOINT { LIB_DBG_NAMESPACE(dbg_lib, BreakPoint)(__LINE__, __FILE__); if(IS_DEBUG_MODE) { DebugBreak(); } else { DBG_SLEEP_SECONDS(DBG_SOFT_BKP_TIMEOUT); } }
#define DBG_SOFT_BREAKPOINT_TS(timestamp) { LIB_DBG_NAMESPACE(dbg_lib, BreakPoint)(__LINE__, __FILE__, LIB_DBG_NAMESPACE(dbg_lib, dbg_StringToTime)(timestamp)); DBG_SOFT_BREAKPOINT }
#define DBG_SOFT_BREAKPOINT_CONDITION(x) { if((x) && (LIB_DBG_NAMESPACE(dbg_lib, BreakPoint)(__LINE__, __FILE__, LIB_DBG_NAMESPACE(dbg_lib, dbg_TimeCurrent)() + DBG_SOFT_BKP_TIMEOUT))) { DBG_SOFT_BREAKPOINT; } }
#define DBG_SOFT_BREAKPOINT_EXEC_TIME(x) { DBG_SOFT_BREAKPOINT_CONDITION(LIB_DBG_NAMESPACE(dbg_lib, ExecTime)(x)); LIB_DBG_NAMESPACE(dbg_lib, ExecTime)(NULL); }
// Conditional break debugging macros
#define DBG_BREAK_CALL_COUNTER(x) if(dbg_lib_func_call_count == x) { DebugBreak(); }
#define DBG_BREAK_IF(x) if(x) { DebugBreak(); }
#ifdef __MQL5__
#define DBG_BREAK_CONDITION_CREATE(x, y) namespace dbg_lib { static bool dbg_cond_ID_state_##x = false; static bool dbg_cond_ID_enabled_##x = y; }
#define DBG_BREAK_CONDITION_ACTIVATE(x, y) do { dbg_lib::dbg_cond_ID_state_##x |= (y); } while(false)
#define DBG_BREAK_CONDITION_DEACTIVATE(x, y) do { dbg_lib::dbg_cond_ID_state_##x = !(y); } while(false)
#define DBG_BREAK_CONDITION_ON_ID(x) do { if(dbg_lib::dbg_cond_ID_state_##x && dbg_lib::dbg_cond_ID_enabled_##x) { DebugBreak(); } } while(false)
#define DBG_BREAK_CONDITION_ON_ID_RESET(x) do { if(dbg_lib::dbg_cond_ID_state_##x && dbg_lib::dbg_cond_ID_enabled_##x) { dbg_lib::dbg_cond_ID_state_##x = false; DebugBreak(); } } while(false)
#else
#define DBG_BREAK_CONDITION_CREATE(x, y) static bool dbg_cond_ID_state_##x = false; static bool dbg_cond_ID_enabled_##x = y;
#define DBG_BREAK_CONDITION_ACTIVATE(x, y) dbg_cond_ID_state_##x |= (y);
#define DBG_BREAK_CONDITION_DEACTIVATE(x, y) dbg_cond_ID_state_##x = !(y);
#define DBG_BREAK_CONDITION_ON_ID(x) { if(dbg_cond_ID_state_##x && dbg_cond_ID_enabled_##x) { DebugBreak(); } }
#define DBG_BREAK_CONDITION_ON_ID_RESET(x) { if(dbg_cond_ID_state_##x && dbg_cond_ID_enabled_##x) { dbg_cond_ID_state_##x = false; DebugBreak(); } }
#endif
// Array out of range stop macro
#define DBG_BREAK_ARRAY_OUT_OF_RANGE(x, y) { if((LIB_DBG_NAMESPACE(dbg_lib, dbg_ArraySize)(x) <= (y)) || ((y) < NULL)) { DBG_MSG_VARDUMP(x); DBG_MSG_VAR(typename_raw(x)); DBG_MSG_VAR(LIB_DBG_NAMESPACE(dbg_lib, dbg_ArraySize)(x)); DBG_MSG_VAR((y)); DebugBreak(); } }
/*
#ifdef __MQL5__
#define DBG_BREAK_ARRAY_OUT_OF_RANGE(x, y) { const int arr_size = LIB_DBG_NAMESPACE(dbg_lib, dbg_ArraySize)(x); if((arr_size <= y) || (y < NULL)) { LIB_DBG_NAMESPACE(dbg_lib, dbg_ArrayPrint)(x, _Digits, (arr_size < 5) ? NULL : (arr_size - 5), NULL); DBG_MSG_VAR(typename_raw(x)); DBG_MSG_VAR(LIB_DBG_NAMESPACE(dbg_lib, dbg_ArraySize)(x)); DBG_MSG_VAR(y); DebugBreak(); } }
#else
#define DBG_BREAK_ARRAY_OUT_OF_RANGE(x, y) { if((LIB_DBG_NAMESPACE(dbg_lib, dbg_ArraySize)(x) <= y) || (y < NULL)) { DBG_MSG_VARDUMP(x); DBG_MSG_VAR(typename_raw(x)); DBG_MSG_VAR(LIB_DBG_NAMESPACE(dbg_lib, dbg_ArraySize)(x)); DBG_MSG_VAR(y); DebugBreak(); } }
#endif
*/
//
/////////////////////////////////////////////////////////////////////////////////////////////////////
/////////////////////////////////////////////////////////////////////////////////////////////////////
//
// Loop tracing
//
// Init loop trace
#define DBG_TRACE_LOOP_BEGIN_ID(x) int _dbg_loop_start##x = 0x00; int _dbg_loop_finish##x = 0x00; ulong _dbg_loop_runtime##x = LIB_DBG_NAMESPACE(dbg_lib, dbg_GetMicrosecondCount)();
#define DBG_TRACE_LOOP_BEGIN DBG_TRACE_LOOP_BEGIN_ID(__FUNCTION__)
// Count loop heads
#define DBG_TRACE_LOOP_START_ID(x) _dbg_loop_start##x++;
#define DBG_TRACE_LOOP_START DBG_TRACE_LOOP_START_ID(__FUNCTION__)
// Count loop footers
#define DBG_TRACE_LOOP_FINISH_ID(x) _dbg_loop_finish##x++;
#define DBG_TRACE_LOOP_FINISH DBG_TRACE_LOOP_FINISH_ID(__FUNCTION__)
// Print loop stats
#define DBG_TRACE_LOOP_END_ID(x) DBG_MSG(LIB_DBG_NAMESPACE(dbg_lib, dbg_StringFormat)("Iterations begin: %i; Iterations end: %i; Runtime: %i microseconds.", _dbg_loop_start##x, _dbg_loop_finish##x, (LIB_DBG_NAMESPACE(dbg_lib, dbg_GetMicrosecondCount)() - _dbg_loop_runtime##x)));
#define DBG_TRACE_LOOP_END DBG_TRACE_LOOP_END_ID(__FUNCTION__)
//
/////////////////////////////////////////////////////////////////////////////////////////////////////
//
// END Debugging support
//*********************************************************************************************************************************************************/
#endif // LIB_DBG_DEBUG_MACROS_MQH_INCLUDED