MQLplus/lib_debug/lib_debug_printf.mqh
super.admin 466f9ca5c5 convert
2025-05-30 16:09:52 +02:00

488 lines
20 KiB
MQL5

#ifndef LIB_DBG_DEBUG_PRINTF_MQH_INCLUDED
#define LIB_DBG_DEBUG_PRINTF_MQH_INCLUDED
#property version "5.10"
/**********************************************************************************
* Copyright (C) 2020 Dominik Egert <info@freie-netze.de>
*
* This file is the debugger printf replacement 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 support functions
//
// Overloaded functions
#ifndef LIB_DEBUG_NAMESPACE
#ifdef __MQL5__
namespace dbg_lib
{
#endif
//#define _DBG_CODE_LOCATION_STRING file, function, line
// Debug printf composer
void LIB_DBG_NAMESPACE_DEF(dbg_lib, dbg_trace_begin)(const string file, const string function, const int line, ulong& call_counter)
{
// Update lib_debug state
LIB_DBG_NAMESPACE(dbg_lib, trace_api_calls) = LIB_DBG_API_CALL_TRACE_DEFAULT;
LIB_DBG_NAMESPACE(dbg_lib, trace_call_depth)++;
call_counter++;
// Construct trace details
string trace_details = StringFormat(DBG_OUTPUT_TRACE_BEGIN_FORMAT, LIB_DBG_NAMESPACE(dbg_lib, dbg_ChartID)(), LIB_DBG_NAMESPACE(dbg_lib, trace_call_depth), function, call_counter);
// Print details
LIB_DBG_NAMESPACE(dbg_lib, dbg_printf)("\r\n%"+ IntegerToString(LIB_DBG_NAMESPACE(dbg_lib, trace_call_depth) * 2) +"s%s", "", StringFormat("%s" + DBG_OUTPUT_STRING, DBG_OUTPUT_PREFIX, DBG_TRACE_BEGIN_MSG_TXT, DBG_CODE_LOCATION_STRING, trace_details));
};
void LIB_DBG_NAMESPACE_DEF(dbg_lib, dbg_trace_end)(const string file, const string function, const int line, const string value_msg = NULL)
{
// Return value
string msg = NULL;
if(value_msg != NULL)
{
int split_1 = StringFind(value_msg, "(");
msg = StringSubstr(value_msg, 0, split_1) + ">>> return" + StringSubstr(value_msg, split_1);
}
else
{ msg = ">>> return(void)"; }
LIB_DBG_NAMESPACE(dbg_lib, dbg_printf)("%s", LIB_DBG_NAMESPACE_DEF(dbg_lib, dbg_context_msg)(DBG_OUTPUT_PREFIX, file, function, line, msg, "=", DBG_MSG_FORMAT_RIGHT_COLUMN_SPACER - 10));
// Close trace
string trace_details = StringFormat(DBG_OUTPUT_TRACE_END_FORMAT, LIB_DBG_NAMESPACE(dbg_lib, trace_call_depth), function);
LIB_DBG_NAMESPACE(dbg_lib, dbg_printf)("%s\r\n", LIB_DBG_NAMESPACE_DEF(dbg_lib, dbg_context_msg)(DBG_TRACE_END_MSG_TXT, file, function, line, trace_details));
// Check uninit state
if(_StopFlag)
{ LIB_DBG_NAMESPACE(dbg_lib, dbg_printf)("%s", LIB_DBG_NAMESPACE_DEF(dbg_lib, dbg_context_msg)(DBG_OUTPUT_PREFIX, file, function, line, LIB_DBG_NAMESPACE(dbg_lib, var_out)(__DBG_STRINGIFY_MACRO((_StopFlag)), _StopFlag), "=", DBG_MSG_FORMAT_RIGHT_COLUMN_SPACER)); }
msg = LIB_DBG_NAMESPACE(dbg_lib, uninit_text)(function, -1);
if(msg != NULL)
{ LIB_DBG_NAMESPACE(dbg_lib, dbg_printf)("%s", LIB_DBG_NAMESPACE_DEF(dbg_lib, dbg_context_msg)(DBG_OUTPUT_PREFIX, file, function, line, msg)); }
// Update lib_debug state
LIB_DBG_NAMESPACE(dbg_lib, trace_api_calls) = false;
LIB_DBG_NAMESPACE(dbg_lib, trace_call_depth)--;
DBG_TRACE_EXEC_DELAY;
};
const string LIB_DBG_NAMESPACE_DEF(dbg_lib, dbg_context_msg)(const string prefix, const string file, const string function, const int line, const string _msg, const string msg2_token = NULL, const int msg2_column = NULL)
{
// Prevalidate input
if(_msg == NULL)
{ return(NULL); }
// Check for multiline output
string result = NULL;
string ml_out[];
string msg = NULL;
int lines = StringSplit(_msg, 0x0A, ml_out);
// Rejoin string containing linebreaks
for(int out_msgs = 0; (out_msgs < lines); out_msgs++)
{
int is_str = StringFind(ml_out[out_msgs], "[str]");
if( (is_str > 0)
&& (StringFind(ml_out[0], "'") > is_str)
&& (StringFind(ml_out[0], "(length: ") < 0) )
{
for(int cnt = 1; (cnt < lines) && (StringFind(ml_out[out_msgs], "(length: ") < 0); cnt++)
{
ml_out[out_msgs] += "\n" + ml_out[cnt];
ml_out[cnt] = NULL;
}
int ptr = NULL;
for(int cnt = NULL; (cnt < lines); cnt++)
{
ml_out[ptr] = ml_out[cnt];
ptr += (ml_out[cnt] != NULL);
}
lines = ptr + (ml_out[ptr] != NULL);
}
}
// First line
string insert = (msg2_token == NULL) ? ml_out[0] : "%s";
string pre_out = StringFormat("%"+ IntegerToString(LIB_DBG_NAMESPACE(dbg_lib, trace_call_depth) * 2) +"s%s" + DBG_OUTPUT_STRING, "", DBG_OUTPUT_PREFIX, prefix, DBG_CODE_LOCATION_STRING, insert);
string out = "";
if( (msg2_token != NULL)
&& (msg2_column != NULL) )
{
string substr = StringSubstr(ml_out[0], 0, StringFind(ml_out[0], msg2_token));
#ifdef __MQL5__
StringTrimRight(substr);
StringTrimLeft(substr);
#else
substr = StringTrimRight(substr);
substr = StringTrimLeft(substr);
#endif
out = StringFormat(pre_out, substr + "%s ");
int len = StringLen(out);
out = StringFormat(out, "%" + IntegerToString(msg2_column - len) + "s%s");
substr = StringSubstr(ml_out[0], StringFind(ml_out[0], msg2_token));
#ifdef __MQL5__
StringTrimRight(substr);
StringTrimLeft(substr);
#else
substr = StringTrimRight(substr);
substr = StringTrimLeft(substr);
#endif
result += StringFormat(out + "\n", "", substr);
}
else
{ result += pre_out + "\n"; }
// Consecutive lines
bool mtx_hdr = false;
bool mtx_out = (lines > 2) && (StringFind(result, "[mtx]") > -1);
bool new_set = (lines < 2) || (StringLen(ml_out[2]) < 2);
int pos = -1;
string substr = NULL;
string _shift = StringFormat("%"+ IntegerToString(MathMax(0, StringFind(result, StringSubstr(ml_out[0], 0, MathMin(5, StringLen(ml_out[0])))))) +"s", " ");
// Clearings for matrix output
if(mtx_out)
{
StringReplace(result, "=", "");
StringReplace(result, "}", "");
}
// Process each line
for(int cnt = 1; (cnt < lines); cnt++)
{
msg = ml_out[cnt];
if(StringLen(msg) < 2)
{
new_set = true;
continue;
}
// Add new set marker
pre_out = StringFormat("%"+ IntegerToString(LIB_DBG_NAMESPACE(dbg_lib, trace_call_depth) * 2) +"s%s", "", insert);
out = "";
if( (msg2_token != NULL)
&& (msg2_column != NULL) )
{
substr = StringSubstr(msg, 0, StringFind(msg, msg2_token));
mtx_hdr = ((StringFind(msg, "][") > -1) && (StringFind(msg, "{") == -1));
if(mtx_hdr)
{ substr = StringSubstr(substr, 1); }
else
#ifdef __MQL5__
{ StringTrimLeft(substr); }
StringTrimRight(substr);
#else
{ substr = StringTrimLeft(substr); }
substr = StringTrimRight(substr);
#endif
out = StringFormat(pre_out, substr + "%s ");
pos = StringLen(out);
out = StringFormat(out, "%" + IntegerToString(msg2_column - pos - StringLen(_shift) - ((new_set) ? 2 : 0)) + "s%s");
substr = StringSubstr(msg, StringFind(msg, msg2_token));
#ifdef __MQL5__
StringTrimRight(substr);
StringTrimLeft(substr);
#else
substr = StringTrimRight(substr);
substr = StringTrimLeft(substr);
#endif
out = StringFormat("%s" + out, _shift, "", (StringLen(substr) < 2) ? "" : substr);
#ifdef __MQL5__
StringTrimRight(out);
#else
out = StringTrimRight(out);
#endif
result += out + "\n";
}
else
{ result += pre_out + "\n"; }
// Trace new set state
new_set = (new_set) ? false : new_set;
}
return(StringSubstr(result, 0, StringLen(result) - 1));
};
// Self destructing file handle
#ifdef LIB_DBG_LOG_TO_FILE
struct __dbg_file_handle
{
int obj;
__dbg_file_handle() : obj(INVALID_HANDLE) { obj = FileOpen(DBG_LOG_FILENAME, FILE_COMMON | FILE_TXT | FILE_ANSI | FILE_WRITE | FILE_SHARE_READ, CP_ACP); };
~__dbg_file_handle() { if(obj != INVALID_HANDLE) { FileClose(obj); } }
} __dbg_f_h;
void LIB_DBG_NAMESPACE_DEF(dbg_lib, dbg_print_to_file)(const string out)
{ FileWriteString(__dbg_f_h.obj, out + "\r\n", StringLen(out)); FileFlush(__dbg_f_h.obj); }
#endif
// Debug get true system time
const datetime LIB_DBG_NAMESPACE_DEF(dbg_lib, dbg_true_system_time)()
{
if(FileIsExist("time.tmp", FILE_COMMON))
{ FileDelete("time.tmp", FILE_COMMON); }
const int f_h = FileOpen("time.tmp", FILE_COMMON | FILE_WRITE, CP_ACP);
const datetime tm = (f_h != INVALID_HANDLE) ? (datetime)FileGetInteger(f_h, FILE_CREATE_DATE) : LIB_DBG_NAMESPACE(dbg_lib, dbg_TimeCurrent)();
FileClose(f_h);
FileDelete("time.tmp", FILE_COMMON);
return(tm);
}
// Debug printf functions
void LIB_DBG_NAMESPACE_DEF(dbg_lib, dbg_mq4_ml_printf)(string p1)
{
string ml_out[];
const int lines = StringSplit(p1, 0x0A, ml_out);
for(int cnt = NULL; (cnt < lines); cnt++)
{ printf("%s", ml_out[cnt]); }
}
void LIB_DBG_NAMESPACE_DEF(dbg_lib, dbg_printf)(const string p1)
{
#ifdef LIB_DBG_LOG_TO_FILE
LIB_DBG_NAMESPACE(dbg_lib, dbg_print_to_file)(p1);
#endif
#ifndef LIB_DBG_NO_JOURNAL
if((p1 != NULL) && (p1 != ""))
#ifdef __MQL5__
{ printf("%s", p1); }
#else
{ LIB_DBG_NAMESPACE_DEF(dbg_lib, dbg_mq4_ml_printf)(p1); }
#endif
#endif
}
template <typename T>
void LIB_DBG_NAMESPACE_DEF(dbg_lib, dbg_printf)(const string p1, const T p2)
{
#ifdef LIB_DBG_LOG_TO_FILE
LIB_DBG_NAMESPACE(dbg_lib, dbg_print_to_file)(StringFormat(p1, p2));
#endif
#ifndef LIB_DBG_NO_JOURNAL
if((p1 != NULL) && (p1 != ""))
#ifdef __MQL5__
{ printf(p1, p2); }
#else
{ LIB_DBG_NAMESPACE_DEF(dbg_lib, dbg_mq4_ml_printf)(StringFormat(p1, p2)); }
#endif
#endif
}
template <typename T, typename U>
void LIB_DBG_NAMESPACE_DEF(dbg_lib, dbg_printf)(const string p1, const T p2, const U p3)
{
#ifdef LIB_DBG_LOG_TO_FILE
LIB_DBG_NAMESPACE(dbg_lib, dbg_print_to_file)(StringFormat(p1, p2, p3));
#endif
#ifndef LIB_DBG_NO_JOURNAL
if((p1 != NULL) && (p1 != ""))
#ifdef __MQL5__
{ printf(p1, p2, p3); }
#else
{ LIB_DBG_NAMESPACE_DEF(dbg_lib, dbg_mq4_ml_printf)(StringFormat(p1, p2, p3)); }
#endif
#endif
}
template <typename T, typename U, typename V>
void LIB_DBG_NAMESPACE_DEF(dbg_lib, dbg_printf)(const string p1, const T p2, const U p3, const V p4)
{
#ifdef LIB_DBG_LOG_TO_FILE
LIB_DBG_NAMESPACE(dbg_lib, dbg_print_to_file)(StringFormat(p1, p2, p3, p4));
#endif
#ifndef DBG_NO_JOURNAL_OUTPUT
if((p1 != NULL) && (p1 != ""))
#ifdef __MQL5__
{ printf(p1, p2, p3, p4); }
#else
{ LIB_DBG_NAMESPACE_DEF(dbg_lib, dbg_mq4_ml_printf)(StringFormat(p1, p2, p3, p4)); }
#endif
#endif
}
template <typename T, typename U, typename V, typename W>
void LIB_DBG_NAMESPACE_DEF(dbg_lib, dbg_printf)(const string p1, const T p2, const U p3, const V p4, const W p5)
{
#ifdef LIB_DBG_LOG_TO_FILE
LIB_DBG_NAMESPACE(dbg_lib, dbg_print_to_file)(StringFormat(p1, p2, p3, p4, p5));
#endif
#ifndef DBG_NO_JOURNAL_OUTPUT
if((p1 != NULL) && (p1 != ""))
#ifdef __MQL5__
{ printf(p1, p2, p3, p4, p5); }
#else
{ LIB_DBG_NAMESPACE_DEF(dbg_lib, dbg_mq4_ml_printf)(StringFormat(p1, p2, p3, p4, p5)); }
#endif
#endif
}
template <typename T, typename U, typename V, typename W, typename X>
void LIB_DBG_NAMESPACE_DEF(dbg_lib, dbg_printf)(const string p1, const T p2, const U p3, const V p4, const W p5, const X p6)
{
#ifdef LIB_DBG_LOG_TO_FILE
LIB_DBG_NAMESPACE(dbg_lib, dbg_print_to_file)(StringFormat(p1, p2, p3, p4, p5, p6));
#endif
#ifndef DBG_NO_JOURNAL_OUTPUT
if((p1 != NULL) && (p1 != ""))
#ifdef __MQL5__
{ printf(p1, p2, p3, p4, p5, p6); }
#else
{ LIB_DBG_NAMESPACE_DEF(dbg_lib, dbg_mq4_ml_printf)(StringFormat(p1, p2, p3, p4, p5, p6)); }
#endif
#endif
}
template <typename T, typename U, typename V, typename W, typename X, typename Y>
void LIB_DBG_NAMESPACE_DEF(dbg_lib, dbg_printf)(const string p1, const T p2, const U p3, const V p4, const W p5, const X p6, const Y p7)
{
#ifdef LIB_DBG_LOG_TO_FILE
LIB_DBG_NAMESPACE(dbg_lib, dbg_print_to_file)(StringFormat(p1, p2, p3, p4, p5, p6, p7));
#endif
#ifndef DBG_NO_JOURNAL_OUTPUT
if((p1 != NULL) && (p1 != ""))
#ifdef __MQL5__
{ printf(p1, p2, p3, p4, p5, p6, p7); }
#else
{ LIB_DBG_NAMESPACE_DEF(dbg_lib, dbg_mq4_ml_printf)(StringFormat(p1, p2, p3, p4, p5, p6, p7)); }
#endif
#endif
}
template <typename T, typename U, typename V, typename W, typename X, typename Y, typename Z>
void LIB_DBG_NAMESPACE_DEF(dbg_lib, dbg_printf)(const string p1, const T p2, const U p3, const V p4, const W p5, const X p6, const Y p7, const Z p8)
{
#ifdef LIB_DBG_LOG_TO_FILE
LIB_DBG_NAMESPACE(dbg_lib, dbg_print_to_file)(StringFormat(p1, p2, p3, p4, p5, p6, p7, p8));
#endif
#ifndef DBG_NO_JOURNAL_OUTPUT
if((p1 != NULL) && (p1 != ""))
#ifdef __MQL5__
{ printf(p1, p2, p3, p4, p5, p6, p7, p8); }
#else
{ LIB_DBG_NAMESPACE_DEF(dbg_lib, dbg_mq4_ml_printf)(StringFormat(p1, p2, p3, p4, p5, p6, p7, p8)); }
#endif
#endif
}
template <typename T, typename U, typename V, typename W, typename X, typename Y, typename Z, typename Z2>
void LIB_DBG_NAMESPACE_DEF(dbg_lib, dbg_printf)(const string p1, const T p2, const U p3, const V p4, const W p5, const X p6, const Y p7, const Z p8, const Z2 p9)
{
#ifdef LIB_DBG_LOG_TO_FILE
LIB_DBG_NAMESPACE(dbg_lib, dbg_print_to_file)(StringFormat(p1, p2, p3, p4, p5, p6, p7, p8, p9));
#endif
#ifndef DBG_NO_JOURNAL_OUTPUT
if((p1 != NULL) && (p1 != ""))
#ifdef __MQL5__
{ printf(p1, p2, p3, p4, p5, p6, p7, p8, p9); }
#else
{ LIB_DBG_NAMESPACE_DEF(dbg_lib, dbg_mq4_ml_printf)(StringFormat(p1, p2, p3, p4, p5, p6, p7, p8, p9)); }
#endif
#endif
}
template <typename T, typename U, typename V, typename W, typename X, typename Y, typename Z, typename Z2, typename Z3>
void LIB_DBG_NAMESPACE_DEF(dbg_lib, dbg_printf)(const string p1, const T p2, const U p3, const V p4, const W p5, const X p6, const Y p7, const Z p8, const Z2 p9, const Z3 p10)
{
#ifdef LIB_DBG_LOG_TO_FILE
LIB_DBG_NAMESPACE(dbg_lib, dbg_print_to_file)(StringFormat(p1, p2, p3, p4, p5, p6, p7, p8, p9, p10));
#endif
#ifndef DBG_NO_JOURNAL_OUTPUT
if((p1 != NULL) && (p1 != ""))
#ifdef __MQL5__
{ printf(p1, p2, p3, p4, p5, p6, p7, p8, p9, p10); }
#else
{ LIB_DBG_NAMESPACE_DEF(dbg_lib, dbg_mq4_ml_printf)(StringFormat(p1, p2, p3, p4, p5, p6, p7, p8, p9, p10)); }
#endif
#endif
}
#ifdef __MQL5__
};
#endif
#endif
//
// END Debugging support
//*********************************************************************************************************************************************************/
#endif // LIB_DBG_DEBUG_PRINTF_MQH_INCLUDED