Commit 0cb6072c authored by Ian Bell's avatar Ian Bell
Browse files

DEB_out. General tidy of DEB_out code replacing DebStream::Impl with new...

DEB_out. General tidy of DEB_out code replacing DebStream::Impl with new DebFile class. Added DEB_ON enabling macro definition to Cmakelists.txt (currently defined in both Release and Debug builds). Added DEB_module() and some four-letter module declarations. Added call stack based hyperlinks and pop-up texts for HTML deb out. Added new DebUtils.hh header

The only change to IGM and CoMISo code in this CL is addition of DEB_module() statements.

[git-p4: depot-paths = "//ReForm/ReForm/main/Base/": change = 10466]
parent 2b28e03b
set(my_headers
${CMAKE_CURRENT_SOURCE_DIR}/DebOut.hh
${CMAKE_CURRENT_SOURCE_DIR}/DebUtils.hh
PARENT_SCOPE
)
......
......@@ -11,10 +11,11 @@
#ifndef REFORM_DEBUG_OUT_HH_INCLUDED
#define REFORM_DEBUG_OUT_HH_INCLUDED
#define DEB_out_INCLUDED 1 // TODO: Define as a Cmake defined DEB_ON
// DEB_ON is defined, or not, in Cmakelists.txt for primary project
#ifndef DEB_out_INCLUDED
#ifndef DEB_ON
#define DEB_module(SS)
#define DEB_enter_func
#define DEB_only( CC )
#define DEB_out(LL, AA )
......@@ -26,36 +27,41 @@
#define DEB_error(AA)
#define DEB_error_if(CC, AA)
#else // DEB_out_INCLUDED
#else // DEB_ON
#include <string>
namespace ReForm {}
#define DEB_module(SS) static const char * l_g_module = SS;
/* TODO: This should use an atomic thread safe static int
*/
#define DEB_enter_func static int deb_enter_count =0; \
ReForm::DebEnter deb(__FUNCTION__, deb_enter_count++);
ReForm::DebEnter deb(__FUNCTION__, deb_enter_count++, l_g_module);
#define DEB_only( CC ) CC
#define DEB_out(LL, AA ) { if (deb.permission(LL)) { deb.stream() << AA ; } }
#define DEB_out(LL, AA ) { if (deb.permission(LL)) \
{ deb.stream() << AA << deb.end(); } }
#define DEB_out_if( CC, LL, AA ) { if (deb.permission(LL) && (CC)) { deb.stream() << AA ; } }
#define DEB_out_if( CC, LL, AA ) { if (deb.permission(LL) && (CC)) \
{ deb.stream() << AA << deb.end(); } }
#define DEB_warning(LL, AA ) { if (deb.permission(LL, 1)) { deb.stream(1) << AA << "\n"; } }
#define DEB_warning(LL, AA ) { if (deb.permission(LL, 1)) \
{ deb.stream(1) << AA << deb.end_lf(); } }
#define DEB_warning_if( CC, LL, AA ) { if (deb.permission(LL, 1) && (CC)) \
{ deb.stream(1) << AA << "\n"; } }
{ deb.stream(1) << AA << deb.end_lf(); } }
#define DEB_mesh_out_if( CC, LL, FF, MM ) { if (deb.permission(LL, 2) && (CC)) \
#define DEB_mesh_out_if( CC, LL, FF, MM ){ if (deb.permission(LL, 2) && (CC)) \
{ deb.stream(2) << deb.mesh(FF, MM) ; } }
// TODO: implement Deb.mesh() filename and mesh holding class and assocated
// DebStream streamer
#define DEB_error(AA) { if (deb.permission(0, 1) )\
{ deb.stream(1) << "Error:" << AA << deb.end_lf(); } }
#define DEB_error(AA) DEB_out(0, "Error:" << AA << "\n")
#define DEB_error_if(CC, AA) if (CC) DEB_error(AA)
......@@ -70,25 +76,45 @@ namespace ReForm
class DebStream;
class DebCommand
{
public:
enum CommandType
{
end = 0x01,
end_lf = 0x03
};
CommandType com_;
CommandType com() const { return com_; }
DebCommand(CommandType _com) : com_(_com) {}
~DebCommand() {};
};
// Class used to maintain DebStream's CallStack
// This does not currently contain a pointer to the file streamer used
// but might do in future. It currently just contains an integer counter
// determining whether a given DEB_out should include or omit a call stack
// or a Deb destructor output some kind of closing function exit trace.
// but might do in future.
class DebEnter
{
public:
int deb_outs_; //!< Number of DEB_outs encountered within this function
int id_;
int deb_outs_; /*!< Number of DEB_outs encountered within this function
determining whether a given DEB_out should include or omit
a call stack or exit trace. */
const char * module_; /*!< Module name for this DEB_enter. */
DebEnter(const char * _funcname, int _count);
DebEnter(const char * const _funcname, const int _count,const char * const _module);
~DebEnter();
DebStream& stream(int _warn = 0, bool _print = true);
bool permission(int _lev, int _warn=0);
DebStream& stream(const int _warn = 0, const bool _print = true);
int permission(const int _lev, const int _warn=0);
DebCommand end() { return DebCommand(DebCommand::CommandType::end); }
DebCommand end_lf() { return DebCommand(DebCommand::CommandType::end_lf); }
};
// C++ needs sight of this class definition to compile the below declared
// << streamers for some reason. Otherwise could move into DebStream.cc
#if 1
class DebFile;
class DebStream
{
public:
......@@ -101,10 +127,9 @@ class DebStream;
};
private:
class Impl;
Impl * impl_;
Impl * impl() { return impl_;}
DebFile * dfile_;
public:
DebFile * dfile() const { return dfile_;}
//! Constructor.
DebStream(
const char * _file_name = nullptr, //!< [in] File name if file based.
......@@ -116,40 +141,12 @@ class DebStream;
DebStream& print(const double);
DebStream& print(const char * const, bool fork = true);
DebStream& print(const char);
//! Output to file, if any.
int flush();
//! Add footer, flush, and close file.
void close();
//! Wipe all buffers, rendering future flush() inactive.
void clear();
//! Set debug level.
void set_level(int, int _warn=0);
//! Are we at the start of a text line?
bool at_line_start();
DebStream& print(const DebCommand &);
//! Get the currently active DebStream
static DebStream& get_global(int _warn=0);
static void set_global_name(const char * name, int _warn = 0);
void set_file_name(const char * _name);
bool permission(int _lev, int _warn=0);
void indent(int _depth);
//void add_to_call_stack(const char * _funcname, const int _count);
class CallStack;
class FunctionCallSequence;
CallStack& call_stack();
};
#endif
DebStream& operator<<(DebStream& ds, const int i );
DebStream& operator<<(DebStream& ds, const double d );
......@@ -161,6 +158,9 @@ DebStream& operator<<(DebStream& ds, const float d );
DebStream& operator<<(DebStream& ds, const char c);
DebStream& operator<<(DebStream& ds, const char* const s );
DebStream& operator<<(DebStream& ds, const std::string& s );
DebStream& operator<<(DebStream& ds, const DebCommand& co );
// A std::stream streamer might be useful here. Add when needed.
}//namespace
......
......@@ -14,8 +14,9 @@
#include <time.h>
#include <vector>
#include <iostream>
#include <map>
#ifdef DEB_out_INCLUDED
#ifdef DEB_ON
#define LOCAL_PROC static
......@@ -29,82 +30,13 @@ LOCAL_PROC bool is_html_filename(const char * const str)
namespace ReForm
{
// This is currently in DebOut.hh instead
#if 0
class DebStream
{
public:
enum StreamType
{
append = 0x01,
html = 0x02,
retain = 0x04,
keep_open = 0x08
};
private:
class Impl;
Impl * impl_;
public:
//! Constructor.
DebStream(
const char * _file_name = nullptr, //!< [in] File name if file based.
const StreamType _type = append //!< [in] bitsfield enum type identifier
) ;
~DebStream();
DebStream& print(const int);
DebStream& print(const double);
DebStream& print(const char * const);
DebStream& print(const char);
//! Output to file, if any.
int flush();
//! Add footer, flush, and close file.
void close();
//! Wipe all buffers, rendering future flush() inactive.
void clear();
//! Set debug level.
void set_level(int, int _warn=0);
//! Are we at the start of a text line?
bool at_line_start();
//! Get the currently active DebStream
static DebStream& get_global(int _warn=0);
static void set_global_name(const char * name, int _warn = 0);
void set_file_name(const char * _name);
bool permission(int _lev, int _warn=0);
void indent(int _depth);
//void add_to_call_stack(const char * _funcname, const int _count);
class CallStack;
class FunctionCallSequence;
CallStack& call_stack();
private:
Impl * impl() { return impl_;}
};
#endif
// Can't easily put these in impl anymore
class DebStream::FunctionCallSequence
class FunctionCallSequence
{
std::string func_name_;
std::vector<int> counts_; // These may not be sequential when multithreaded.
public:
DebStream::FunctionCallSequence(const char * _func_name, const int _count)
FunctionCallSequence(const char * _func_name, const int _count)
: func_name_(_func_name)
{
counts_.push_back(_count);
......@@ -211,7 +143,7 @@ namespace ReForm
}; // endclass FunctionCallSequence
class DebStream::CallStack
class CallStack
{
std::vector<FunctionCallSequence> calls_;
int depth_;
......@@ -274,12 +206,26 @@ namespace ReForm
class DebStream::Impl
class DebFile
{
private:
StreamType type_;
class module_stats
{
public:
int lev_; // Level set for this module
int col_; // Colour (24 bit RGB, MSB=Red) for this module's DEB_out
module_stats(int _lev=0) : lev_(_lev), col_(0x808080) {}
~module_stats() {}
};
std::map<std::string, module_stats> module_map_;
typedef std::map<std::string, module_stats>::iterator module_map_itr;
typedef std::map<std::string, module_stats>::const_iterator const_module_map_itr;
DebStream::StreamType type_;
int lev_;
int num_flush_;
int priority_; // Last permission granted
std::string current_;
std::string output_;
std::string file_name_;
......@@ -292,14 +238,15 @@ public:
CallStack& call_stack() { return call_stack_;}
bool is_kept_open() const { return 0 != (type_ & StreamType::keep_open); }
bool is_html() const { return 0 != (type_ & StreamType::html); }
bool is_retained() const { return 0 != (type_ & StreamType::retain); }
bool is_appended() const { return 0 != (type_ & StreamType::append); }
bool is_kept_open() const { return 0 != (type_ & DebStream::StreamType::keep_open); }
bool is_html() const { return 0 != (type_ & DebStream::StreamType::html); }
bool is_retained() const { return 0 != (type_ & DebStream::StreamType::retain); }
bool is_appended() const { return 0 != (type_ & DebStream::StreamType::append); }
// Only applies to HTML DEB_out
bool is_white_on_black() { return true; }
bool is_white_on_black() const { return true; }
bool file_is_open() const { return file_stream_.is_open(); }
int priority() const { return priority_; }
bool fork_to_cout() { return false; }
bool fork_to_cerr() { return true; }
......@@ -317,19 +264,7 @@ public:
output_.clear();
file_name_.clear();
}
Impl(
DebStream* _deb_stream,
StreamType _type = (StreamType) (append | retain),
const char * _file_name = nullptr) :
type_(_type), lev_(5), deb_stream_(_deb_stream), num_flush_(0)
{
set_file_name(_file_name);
indent_string_ = ".";
}
~Impl() {}
char prev_char() const
{
if (!current_.empty()) return current_.back();
......@@ -337,24 +272,36 @@ public:
return '\0';
}
void line_break(bool _with_indent=false)
void indent(int _depth)
{
for (int i=0; i < _depth; ++i)
{
if (is_html()) current_.append("-");
//else current_.append(" ");
}
}
void line_break(bool _with_indent = true)
{
_with_indent;
if ( is_html() ) current_.append("<br>"); // Don't bother with matching </br>
current_.append("\n", 1);
// Don't add indent yet because we might not want it.
}
void indent(int _depth)
{
if (!indent_string_.empty())
if (_with_indent)
{
for (int i=0; i < _depth; ++i) current_.append(indent_string_);
indent(call_stack().depth() );
}
}
void set_level(int _lev) { lev_ = _lev; }
void print_direct(const std::string & _s)
{
current_.append(_s);
}
void print(const char _c)
{
if (_c == '\n') line_break();
......@@ -368,13 +315,15 @@ public:
for (int i=0; ;++i)
{
const char c = _s[i];
if(c=='\0') break;
if (c=='\0') break;
print(c);
}
if (_fork)
{
if (fork_to_cout()) std::cout << _s;
if (fork_to_cerr()) std::cerr << _s;
if (fork_to_cout())
std::cout << _s;
if (fork_to_cerr())
std::cerr << _s;
}
}
......@@ -394,6 +343,20 @@ public:
print(buffer);
}
void print(const DebCommand& _co)
{
switch(_co.com()) {
case DebCommand::end :
if (is_html()) print("</FONT>", false);
break;
case DebCommand::end_lf :
if (is_html()) print("</FONT>", false);
line_break();
break;
}
}
DebStream & stream() { return *deb_stream_; }
// Append current asctime to given string
......@@ -416,6 +379,59 @@ public:
return false;
}
#if 0
bool hover(std::string & _str, const std::string & _hover, const bool _open)
{
if (is_html())
{
char buffer[1024];
if (_open) sprintf_s(buffer, sizeof(buffer),
"<span title=\"%s\">", _hover.c_str());
else sprintf_s(buffer, sizeof(buffer), "</span>");
_str.append(buffer);
return true;
}
return false;
}
#endif
bool anchor(std::string & _str, const int _id, const char * _tag, const bool _open)
{
if (is_html())
{
char buffer[1024];
if (_open) sprintf_s(buffer, sizeof(buffer), "<A name=\"%08X_%s\">", _id, _tag);
else sprintf_s(buffer, sizeof(buffer), "</A>");
_str.append(buffer);
return true;
}
return false;
}
bool link_to(std::string & _str, const int _id, const char * _tag, const std::string & _hover, const bool _open)
{
if (is_html())
{
char buffer[2048];
if (_open)
{
// HTML title hover text is cropped to 64 char in Firefox but displays
// OK in Chrome. We could use javascript to avoid this limit but HTML
// is simpler.
if (_hover.empty()) sprintf_s(buffer, sizeof(buffer),
"<A href=\"#%08X_%s\">", _id, _tag);
else sprintf_s(buffer, sizeof(buffer),
"<A href=\"#%08X_%s\" title=\"%s\">", _id, _tag, _hover.c_str());
}
else sprintf_s(buffer, sizeof(buffer), "</A>");
_str.append(buffer);
return true;
}
return false;
}
void header(std::string & str)
{
if ( is_html() )
......@@ -428,7 +444,7 @@ public:
// stylesheet loads go here
// within HEAD javascript goes here
str.append("\n</HEAD>");
if( is_white_on_black() )
if ( is_white_on_black() )
{
str.append( "\n<BODY BGCOLOR=\"#000000\" TEXT=\"#FFFFFF\" LINK=\"#%00FFFF\" VLINK=\"#FFFF00\" >");
}
......@@ -442,7 +458,9 @@ public:
if (date_header)
{
add_time(str);
str.append( "[ Build: " __TIME__ " " __DATE__ "] \n");
str.append( "[ Build: " __TIME__ " " __DATE__ "] ");
if (is_html()) str.append("<BR>");
str.append("\n");
}
}
......@@ -458,7 +476,7 @@ public:
if (is_html())
{
stream() << "\n</BODY></HTML>";
stream().print("\n</BODY></HTML>", false);
}
}
......@@ -473,7 +491,7 @@ public:
if ( !current_.empty() )
{
const char * fname = file_name();
if((fname != nullptr) || file_is_open() )
if ((fname != nullptr) || file_is_open() )
{
if ( !file_is_open() )
{
......@@ -526,55 +544,170 @@ public:
flush();
}
bool permission(int _lev)
{
return _lev <= lev_;
}
void set_file_name(const char * _name)
{
file_name_ = _name;
if ( is_html_filename(_name) )
type_ = (StreamType)(type_ | StreamType::html);
{
type_ = (DebStream::StreamType)(type_ | DebStream::StreamType::html);
}
}
}; // endclass DebStream::Impl
void set_module_level(const char * const _module, const int _lev)
{
std::pair<module_map_itr, bool> ins = module_map_.insert(
std::pair<std::string, module_stats>(_module, module_stats(_lev)) );
if (!ins.second) ins.first->second.lev_ = _lev;
}
int get_module_level(const char * const _module) const
{
const_module_map_itr it = module_map_.find(std::string(_module));
if (it == module_map_.end()) return lev_;
return it->second.lev_;
}
void set_module_color(const char * const _module, const int _col)
{
std::pair<module_map_itr, bool> ins = module_map_.insert(
std::pair<std::string, module_stats>(_module, module_stats(lev_)) );
ins.first->second.col_ = _col;
}
int get_module_color(const char * const _module) const
{
const_module_map_itr it = module_map_.find(std::string(_module));
if (it == module_map_.end())
{
if (is_white_on_black() ) return 0xFFFFFF;
else return 0x000000;
}
return it->second.col_;
}
int permission(const int _lev, const int _warn, const char * const _module)
{
_warn;
int lev = get_module_level(_module);
lev -= _lev;
if (lev <0) lev = 0;
if (lev > 0) priority_ = lev;
return lev;
}
bool at_line_start()
{
char prev = prev_char();
return (prev=='\n') || (prev=='\0');
}
DebFile(
DebStream* _deb_stream,
DebStream::StreamType _type = (DebStream::StreamType) (DebStream::append | DebStream::retain),
const char * _file_name = nullptr) :
type_(_type), lev_(5), deb_stream_(_deb_stream), num_flush_(0)
{
set_file_name(_file_name);
indent_string_ = ".";
set_module_color("PARA", 0xFF0000);
set_module_color("SOLV", 0x00FF00);
set_module_color("NSLV", 0xFFFF00);
set_module_color("CFLD", 0x0000FF);
set_module_color("CURV", 0x00FFFF);
}
~DebFile() {}
}; // endclass DebFile