193 lines
No EOL
19 KiB
MQL5
193 lines
No EOL
19 KiB
MQL5
//+------------------------------------------------------------------+
|
|
//| Trace |
|
|
//| Copyright 2006-2011, www.FXmaster.de |
|
|
//| www.FXmaster.de |
|
|
//+------------------------------------------------------------------+
|
|
#property copyright "Copyright 2006-2011, www.FXmaster.de"
|
|
#property link "www.FXmaster.de"
|
|
|
|
#include "Tree.mqh"
|
|
|
|
class CTraceView; // предварительное объявление
|
|
//------------------------------------------------------------------ class CTraceCtrl
|
|
class CTraceCtrl
|
|
{
|
|
public:
|
|
CTreeCtrl *m_stack; // объект графа
|
|
CTreeCtrl *m_prop; // объект списка свойств
|
|
CTreeCtrl *m_file; // группировка по файлам
|
|
CTreeCtrl *m_class; // группировка по классам
|
|
CTraceView* m_traceview; // указатель на отображение класса
|
|
CNode* m_cur; // указатель на текущий узел
|
|
|
|
public:
|
|
CTraceCtrl() { Create(); Reset(); } // создали трейсер
|
|
~CTraceCtrl() { delete m_stack; delete m_prop; delete m_file; delete m_class; } // удалили трейсер
|
|
void Create(); // создали трейсер
|
|
void In(string apath, string afile, int aline, string atext, string adesc, int aid); // вход в указанный узел
|
|
void Out(int aid); // выход до указанного узла
|
|
bool StepBack(); // выход из узла на один шаг вверх (переход на родителя)
|
|
void Reset() { m_cur=m_stack.m_root; m_stack.Reset(); m_file.Reset(); m_class.Reset(); } // сброс всех узлов
|
|
void Clear() { m_cur=m_stack.m_root; m_stack.Clear(); m_file.Clear(); m_class.Clear(); } // сброс всех узлов
|
|
|
|
public:
|
|
void AddWatch(string name, string val); // проверка дебаг режима для узла
|
|
void Break(); // пауза для узла
|
|
};
|
|
//------------------------------------------------------------------ CTraceCtrl
|
|
void CTraceCtrl::Create()
|
|
{
|
|
m_stack=new CTreeCtrl; m_stack.m_root.m_text="TRACE"; m_stack.m_mode=1; // создали объект графа
|
|
m_prop=new CTreeCtrl; m_prop.m_root.m_text="INFO"; // создали объект графа
|
|
m_file=new CTreeCtrl; m_file.m_root.m_text="FILE"; // создали объект графа
|
|
m_class=new CTreeCtrl; m_class.m_root.m_text="CLASS"; // создали объект графа
|
|
m_cur=m_stack.m_root; // установили указатель на корень
|
|
m_stack.m_bBreak=true;
|
|
}
|
|
//------------------------------------------------------------------ In
|
|
void CTraceCtrl::In(string apath, string afile, int aline, string atext, string adesc, int aid)
|
|
{
|
|
if (NIL(m_stack) || NIL(m_cur)) return; // правильность указателя
|
|
if (aid>=0) Out(aid); // если задан требуемый узел, то переходим на него
|
|
// проверяем имена уже имеющихся узлов
|
|
int i, size=ArraySize(m_cur.m_next); // взяли список веток нода
|
|
bool b=false, ident;
|
|
for (i=0; i<size; i++) // ищем в ветках текущего нода требуемое имя
|
|
{
|
|
if (NIL(m_cur.m_next[i])) continue; // правильность указателя
|
|
if (m_cur.m_next[i].m_text==atext) { b=true; break; } // если нашли, то поиск останавливаем
|
|
}
|
|
ident=(m_cur.m_file==afile && m_cur.m_line==aline && m_cur.m_path==apath);
|
|
|
|
if (b)
|
|
{
|
|
m_cur=m_cur.m_next[i]; // передвинулись к следующему узлу
|
|
m_cur.m_desc=adesc; // задали атрибут
|
|
}
|
|
else if (!ident)// если узел не найден и это не текущий, то создаем новый узел
|
|
{
|
|
ArrayResize(m_cur.m_next, size+1); // расширили массив
|
|
m_cur.m_next[size]=new CNode; // создали узел
|
|
if (NIL(m_cur.m_next[size])) return; // проверили
|
|
m_stack.m_maxid++; // увеличили глобальный счетчик
|
|
m_cur.m_next[size].m_prev=m_cur; // поставили указатель на родителя
|
|
m_cur=m_cur.m_next[size]; // переместили текущий указатель на новый узел
|
|
m_cur.m_id=m_stack.m_maxid; m_cur.m_text=atext;
|
|
|
|
// задали атрибуты
|
|
string afunc=atext, aclass="__base__"; int k=StringFind(atext, "::");
|
|
if (k>0) { aclass=StringSubstr(atext, 0, k); afunc=StringSubstr(atext, k+2); }
|
|
m_cur.m_path=apath; m_cur.m_file=afile; m_cur.m_line=aline;
|
|
m_cur.m_func=afunc; m_cur.m_class=aclass; m_cur.m_desc=adesc;
|
|
|
|
// группируем в деревья
|
|
m_stack.SortBy(TG_TEXT, true);
|
|
m_file.Clear(); m_stack.GroupBy(TG_FILE, m_file); m_file.SortBy(TG_TEXT, true);
|
|
m_class.Clear(); m_stack.GroupBy(TG_CLASS, m_class); m_class.SortBy(TG_TEXT, true);
|
|
}
|
|
m_cur.m_uses++;
|
|
m_cur.m_tick0=GetTickCount(); m_cur.m_last=TimeLocal(); // задали число обращений и время входа
|
|
}
|
|
//------------------------------------------------------------------ Out
|
|
void CTraceCtrl::Out(int aid)
|
|
{
|
|
if (aid<0) { StepBack(); return; }
|
|
CNode *node=m_stack.FindNode(aid); if (NIL(node)) return; // нашли узел требуемого id
|
|
while (m_cur!=node) if (!StepBack()) break; // выходим из узлов, пока не достигнем требуемого
|
|
if (m_cur!=node) m_cur=node; // если в соседней ветке, то перепрыгиваем
|
|
if (NIL(m_cur)) m_cur=node; // если текущий не указан, то задаем
|
|
}
|
|
//------------------------------------------------------------------ StepBack
|
|
bool CTraceCtrl::StepBack()
|
|
{
|
|
if (NIL(m_stack.m_root)) { Print("-err Out root"); return(false); } // правильность указателя
|
|
if (NIL(m_cur)) { m_cur=m_stack.m_root; return(false); } // правильность указателя
|
|
if (m_cur.m_tick0>0) m_cur.m_tick+=GetTickCount()-m_cur.m_tick0; m_cur.m_tick0=0; // подсчитали время
|
|
if (m_cur==m_stack.m_root) return(false); // если уже на верхушке
|
|
if (NIL(m_cur.m_prev)) { Print("-err Out "+m_cur.m_text+"("+(string)m_cur.m_id+")"); return(false); } // правильность указателя
|
|
m_cur=m_cur.m_prev; // перешли к родительскому узлу
|
|
return(true);
|
|
}
|
|
//------------------------------------------------------------------ AddWatch
|
|
void CTraceCtrl::AddWatch(string name, string val) // добавиление Watch-переменной в текущий узел
|
|
{
|
|
if (!NIL(m_trace) && !NIL(m_trace.m_cur)) m_trace.m_cur.AddWatch(name, val);
|
|
}
|
|
//------------------------------------------------------------------ Break
|
|
void CTraceCtrl::Break() // проверка дебаг режима для узла
|
|
{
|
|
if (NIL(m_traceview) || NIL(m_stack)) return; // проверка валидности
|
|
if (!m_stack.m_bBreak) return; // проверка разрешенности дебага
|
|
|
|
m_stack.BreakBy(TG_ALL, NULL, false); // убрали флаги m_break со всех ущлов
|
|
m_cur.m_break=true; // активировали только на текущем
|
|
m_traceview.m_viewstack.m_sid=m_cur.m_id; // перенесли выделение на него
|
|
m_stack.ExpandBy(TG_UP, m_cur, true, m_cur); // раскрыли родительские узлы, если закрыты
|
|
m_traceview.Draw(); // отрисовали все
|
|
string namedbg=m_traceview.m_viewstack.m_name+string(m_cur.m_id)+".dbg"; // получили имя кнопки BREAK
|
|
string name=m_traceview.m_viewstack.m_name+".break"; // получили имя кнопки BREAK
|
|
bool state=ObjectGetInteger(m_traceview.m_chart, namedbg, OBJPROP_STATE);
|
|
while(!state) // пока кнопка не нажата, выполняем цикл
|
|
{
|
|
Sleep(500); // сделали паузу
|
|
state=ObjectGetInteger(m_traceview.m_chart, namedbg, OBJPROP_STATE); // проверяем её состояние
|
|
if (!m_traceview.IsOpenView()) break; // если окно закрыто, то выходим
|
|
m_stack.m_bBreak=ObjectGetInteger(m_traceview.m_chart, name, OBJPROP_STATE); // проверяем её состояние
|
|
state=state || !m_stack.m_bBreak; // учитываем состояние кнопки активности дебага системы
|
|
m_traceview.Draw(); // отрисовали возможные изменения
|
|
}
|
|
m_cur.m_break=false; // убрали флаг
|
|
m_traceview.Draw(); // отрисовали обновление
|
|
}
|
|
|
|
//------------------------------------------------------------------ CIn
|
|
class CIn
|
|
{
|
|
public:
|
|
void In(string apath, string afile, int aline, string afunc, string adesc)
|
|
{
|
|
if (NIL(m_trace)) return; // если нет графа, то выходим
|
|
if (NIL(m_trace.m_stack)) return;
|
|
if (NIL(m_trace.m_stack.m_root)) return;
|
|
if (NIL(m_trace.m_cur)) m_trace.m_cur=m_trace.m_stack.m_root;
|
|
m_trace.In(apath, afile, aline, afunc, adesc, -1); // вошли в следующий
|
|
|
|
if (m_trace.m_cur.m_brkuse>0 && m_trace.m_cur.m_uses>=m_trace.m_cur.m_brkuse) // если достигли числа вызовов
|
|
m_trace.Break(); //то входим в дебаг
|
|
}
|
|
void ~CIn() { if (!NIL(m_trace)) m_trace.Out(-1); } // вышли выше
|
|
};
|
|
// определение макросов
|
|
#ifdef TRACE
|
|
#define _IN(desc) CIn _in; _in.In(__PATH__, __FILE__, __LINE__, __FUNCTION__, string(desc))
|
|
#define _IN1(desc) CIn _in1; _in1.In(__PATH__, __FILE__, __LINE__, __FUNCTION__, string(desc))
|
|
#define _IN2(desc) CIn _in2; _in2.In(__PATH__, __FILE__, __LINE__, __FUNCTION__, string(desc))
|
|
#define _IN3(desc) CIn _in3; _in3.In(__PATH__, __FILE__, __LINE__, __FUNCTION__, string(desc))
|
|
#define _IN4(desc) CIn _in4; _in4.In(__PATH__, __FILE__, __LINE__, __FUNCTION__, string(desc))
|
|
#define _IN5(desc) CIn _in5; _in5.In(__PATH__, __FILE__, __LINE__, __FUNCTION__, string(desc))
|
|
|
|
#define _WATCH(w, v) if (!NIL(m_trace)) if (!NIL(m_trace.m_cur)) m_trace.m_cur.AddWatch(w, string(v));
|
|
|
|
#define _BRKUSES(u) if (!NIL(m_trace)) if (!NIL(m_trace.m_cur)) if (m_trace.m_cur.m_brkuse==-2) m_trace.m_cur.m_brkuse=long(u);
|
|
|
|
#include "View\TraceView.mqh" // подключаем описание класса
|
|
|
|
#ifndef __MQL4__
|
|
extern CTraceCtrl* m_trace; // единственный экземпляр трассировщика
|
|
#else
|
|
CTraceCtrl* m_trace; // единственный экземпляр трассировщика
|
|
#endif
|
|
#else //TRACE
|
|
|
|
#define _IN(desc) ;// CIn _in; _in.In(__PATH__, __FILE__, __LINE__, __FUNCTION__, string(desc))
|
|
#define _IN1(desc) ;// CIn _in1; _in1.In(__PATH__, __FILE__, __LINE__, __FUNCTION__, string(desc))
|
|
#define _IN2(desc) ;// CIn _in2; _in2.In(__PATH__, __FILE__, __LINE__, __FUNCTION__, string(desc))
|
|
#define _IN3(desc) ;// CIn _in3; _in3.In(__PATH__, __FILE__, __LINE__, __FUNCTION__, string(desc))
|
|
#define _IN4(desc) ;// CIn _in4; _in4.In(__PATH__, __FILE__, __LINE__, __FUNCTION__, string(desc))
|
|
#define _IN5(desc) ;// CIn _in5; _in5.In(__PATH__, __FILE__, __LINE__, __FUNCTION__, string(desc))
|
|
|
|
#define _WATCH(w, v) ;// if (!NIL(m_trace)) if (!NIL(m_trace.m_cur)) m_trace.m_cur.AddWatch(w, string(v));
|
|
|
|
#define _BRKUSES(u) ;//if (!NIL(m_trace)) if (!NIL(m_trace.m_cur)) if (m_trace.m_cur.m_brkuse==-2) m_trace.m_cur.m_brkuse=long(u);
|
|
|
|
#endif //TRACE |