diff --git a/backward.cpp b/backward.cpp index 4c68284..33a9a32 100644 --- a/backward.cpp +++ b/backward.cpp @@ -27,6 +27,6 @@ namespace backward { -backward::SignalHandling sh; +backward::SignalHandling sh; } // namespace backward diff --git a/backward.hpp b/backward.hpp index f9f2f33..fffdde1 100644 --- a/backward.hpp +++ b/backward.hpp @@ -1861,6 +1861,15 @@ class SnippetFactory { /*************** PRINTER ***************/ +template +class Colorize; + +template +class BlankPadding; + +template +class NewLine; + namespace ColorMode { enum type { automatic, @@ -1909,7 +1918,8 @@ namespace Color { }; } // namespace Color -class Colorize { +template<> +class Colorize { public: Colorize(std::ostream& os): _os(os), _reset(false), _enabled(false) {} @@ -1918,10 +1928,6 @@ class Colorize { _enabled = mode == ColorMode::always; } - void activate(ColorMode::type mode, FILE* fp) { - activate(mode, fileno(fp)); - } - void set_color(Color::type ccode) { if (!_enabled) return; @@ -1938,15 +1944,42 @@ class Colorize { } private: - void activate(ColorMode::type mode, int fd) { - activate(mode == ColorMode::automatic && isatty(fd) ? ColorMode::always : mode); - } - std::ostream& _os; bool _reset; bool _enabled; }; +template<> +class Colorize { +public: + Colorize(FILE *fp): + _fp(fp), _reset(false), _enabled(false) {} + + void activate(ColorMode::type mode) { + _enabled = (mode == ColorMode::automatic && isatty(fileno(_fp))) ? ColorMode::always : mode; + } + + void set_color(Color::type ccode) { + if (!_enabled) return; + + // I assume that the terminal can handle basic colors. Seriously I + // don't want to deal with all the termcap shit. + fprintf(_fp, "\033[%dm", static_cast(ccode)); + _reset = (ccode != Color::reset); + } + + ~Colorize() { + if (_reset) { + set_color(Color::reset); + } + } + +private: + FILE* _fp; + bool _reset; + bool _enabled; +}; + #else // ndef BACKWARD_SYSTEM_LINUX namespace Color { @@ -1957,19 +1990,95 @@ namespace Color { }; } // namespace Color -class Colorize { +template<> +class Colorize { public: Colorize(std::ostream&) {} void activate(ColorMode::type) {} - void activate(ColorMode::type, FILE*) {} + void set_color(Color::type) {} +}; + +template<> +class Colorize { +public: + Colorize(FILE *) {} + void activate(ColorMode::type) {} void set_color(Color::type) {} }; #endif // BACKWARD_SYSTEM_LINUX -class Printer { +template<> +class BlankPadding { public: + BlankPadding(int width) : _width(width) {} + int width() const { return _width; } + +private: + int _width; +}; + +inline std::ostream& operator<<(std::ostream& os, const BlankPadding& bp) { + os << std::setw(bp.width()); + return os; +} + +template<> +class NewLine { +}; + +inline std::ostream& operator<<(std::ostream& os, const NewLine&) { + os << std::endl; + return os; +} + +class FileStreamWrapper { +public: + FileStreamWrapper(FILE *fp) : _fp(fp) {} + + FileStreamWrapper& operator<<(int v) { + fprintf(_fp, "%d", v); + return *this; + } + + FileStreamWrapper& operator<<(const std::string& s) { + fprintf(_fp, "%s", s.c_str()); + return *this; + } + +private: + FILE *_fp; +}; + +template<> +class BlankPadding { +public: + BlankPadding(int width) : _width(width) {} + + int width() const { return _width; } + +private: + int _width; +}; + +inline FileStreamWrapper& operator<<(FileStreamWrapper& os, const BlankPadding& bp) { + os << std::string(' ', bp.width()); + return os; +} + +template<> +class NewLine { +}; + +inline FileStreamWrapper& operator<<(FileStreamWrapper& os, const NewLine&) { + os << std::string("\n"); + return os; +} + +template +class Printer { +public: bool snippet; ColorMode::type color_mode; bool address; @@ -1986,48 +2095,12 @@ class Printer { trace_context_size(7) {} - template - FILE* print(ST& st, FILE* fp = stderr) { - cfile_streambuf obuf(fp); - std::ostream os(&obuf); - Colorize colorize(os); - colorize.activate(color_mode, fp); - print_stacktrace(st, os, colorize); - return fp; - } - - template - std::ostream& print(ST& st, std::ostream& os) { - Colorize colorize(os); - colorize.activate(color_mode); - print_stacktrace(st, os, colorize); - return os; - } - - template - FILE* print(IT begin, IT end, FILE* fp = stderr, size_t thread_id = 0) { - cfile_streambuf obuf(fp); - std::ostream os(&obuf); - Colorize colorize(os); - colorize.activate(color_mode, fp); - print_stacktrace(begin, end, os, thread_id, colorize); - return fp; - } - - template - std::ostream& print(IT begin, IT end, std::ostream& os, size_t thread_id = 0) { - Colorize colorize(os); - colorize.activate(color_mode); - print_stacktrace(begin, end, os, thread_id, colorize); - return os; - } - -private: +protected: TraceResolver _resolver; SnippetFactory _snippets; template - void print_stacktrace(ST& st, std::ostream& os, Colorize& colorize) { + void print_stacktrace(ST& st, Stream& os, Colorize& colorize) { print_header(os, st.thread_id()); _resolver.load_stacktrace(st); for (size_t trace_idx = st.size(); trace_idx > 0; --trace_idx) { @@ -2036,26 +2109,24 @@ class Printer { } template - void print_stacktrace(IT begin, IT end, std::ostream& os, size_t thread_id, Colorize& colorize) { + void print_stacktrace(IT begin, IT end, Stream& os, size_t thread_id, Colorize& colorize) { print_header(os, thread_id); for (; begin != end; ++begin) { print_trace(os, *begin, colorize); } } - void print_header(std::ostream& os, size_t thread_id) { + void print_header(Stream& os, size_t thread_id) { os << "Stack trace (most recent call last)"; if (thread_id) { os << " in thread " << thread_id; } - os << ":\n"; + os << NewLine< Stream >(); } - void print_trace(std::ostream& os, const ResolvedTrace& trace, - Colorize& colorize) { - os << "#" - << std::left << std::setw(2) << trace.idx - << std::right; + void print_trace(Stream& os, const ResolvedTrace& trace, + Colorize& colorize) { + os << "#" << BlankPadding(2) << trace.idx; bool already_indented = true; if (!trace.source.filename.size() || object) { @@ -2065,7 +2136,7 @@ class Printer { << trace.addr << ", in " << trace.object_function - << "\n"; + << NewLine(); already_indented = false; } @@ -2096,12 +2167,10 @@ class Printer { } } - void print_snippet(std::ostream& os, const char* indent, + void print_snippet(Stream& os, const char* indent, const ResolvedTrace::SourceLoc& source_loc, - Colorize& colorize, Color::type color_code, - int context_size) - { - using namespace std; + Colorize& colorize, Color::type color_code, + int context_size) { typedef SnippetFactory::lines_t lines_t; lines_t lines = _snippets.get_snippet(source_loc.filename, @@ -2115,17 +2184,17 @@ class Printer { } else { os << indent << " "; } - os << std::setw(4) << it->first + os << BlankPadding(4) << it->first << ": " << it->second - << "\n"; + << NewLine(); if (it-> first == source_loc.line) { colorize.set_color(Color::reset); } } } - void print_source_loc(std::ostream& os, const char* indent, + void print_source_loc(Stream& os, const char* indent, const ResolvedTrace::SourceLoc& source_loc, void* addr=0) { os << indent @@ -2139,7 +2208,69 @@ class Printer { if (address && addr != 0) { os << " [" << addr << "]"; } - os << "\n"; + os << NewLine(); + } +}; + +class StreamPrinter : public Printer { +public: + StreamPrinter(std::ostream& os) : _os(os) {} + + template + void print(ST& st) { + Colorize colorize(_os); + colorize.activate(color_mode); + print_stacktrace(st, _os, colorize); + } + + template + void print(IT begin, IT end, size_t thread_id = 0) { + Colorize colorize(_os); + colorize.activate(color_mode); + print_stacktrace(begin, end, thread_id, colorize); + } + +private: + std::ostream& _os; +}; + +class CErrPrinter { +public: + typedef StreamPrinter PrinterImpl; + static PrinterImpl& get_instance() { + static PrinterImpl sp(std::cerr); + return sp; + } +}; + +class StdioPrinter : public Printer { +public: + StdioPrinter(FILE* fp) : _fp(fp) {} + + template + void print(ST& st) { + cfile_streambuf obuf(_fp); + std::ostream os(&obuf); + StreamPrinter(os).print(st); + } + + template + void print(IT begin, IT end, size_t thread_id = 0) { + cfile_streambuf obuf(_fp); + std::ostream os(&obuf); + StreamPrinter(os).print(begin, end, thread_id); + } + +private: + FILE* _fp; +}; + +class StderrPrinter { +public: + typedef StdioPrinter PrinterImpl; + static PrinterImpl& get_instance() { + static PrinterImpl sp(stderr); + return sp; } }; @@ -2148,6 +2279,7 @@ class Printer { #if defined(BACKWARD_SYSTEM_LINUX) || defined(BACKWARD_SYSTEM_DARWIN) +template class SignalHandling { public: static std::vector make_default_signals() { @@ -2235,9 +2367,9 @@ class SignalHandling { st.load_here(32); } - Printer printer; + typename Printer::PrinterImpl& printer = Printer::get_instance(); printer.address = true; - printer.print(st, stderr); + printer.print(st); #if _XOPEN_SOURCE >= 700 || _POSIX_C_SOURCE >= 200809L psiginfo(info, 0); @@ -2267,6 +2399,7 @@ class SignalHandling { #ifdef BACKWARD_SYSTEM_UNKNOWN +template< typename Printer > class SignalHandling { public: SignalHandling(const std::vector& = std::vector()) {} diff --git a/test/rectrace.cpp b/test/rectrace.cpp index bde82ba..c8a04d9 100644 --- a/test/rectrace.cpp +++ b/test/rectrace.cpp @@ -27,6 +27,14 @@ using namespace backward; +class StdoutPrinter { +public: + static StdioPrinter& get_instance() { + static StdioPrinter sp(stdout); + return sp; + } +}; + typedef StackTrace stacktrace_t; void end_of_our_journey(stacktrace_t& st) { @@ -69,10 +77,10 @@ TEST (recursion) { std::cout << "rec(" << input << ") == " << r << std::endl; - Printer printer; + StdioPrinter& printer = StdoutPrinter::get_instance(); // printer.address = true; printer.object = true; - printer.print(st, stdout); + printer.print(st); } } @@ -94,6 +102,5 @@ TEST (fibrecursive) { std::cout << "fib(" << input << ") == " << r << std::endl; - Printer printer; - printer.print(st, stdout); + StdoutPrinter::get_instance().print(st); } diff --git a/test/select_signals.cpp b/test/select_signals.cpp index ef3499b..a091d81 100644 --- a/test/select_signals.cpp +++ b/test/select_signals.cpp @@ -23,12 +23,32 @@ #include "backward.hpp" +#include + #include #include #include "test/test.hpp" using namespace backward; +class VoidPrinter { +public: + typedef VoidPrinter PrinterImpl; + bool address; + + VoidPrinter() {} + + template + void print(ST&) { + } + + static PrinterImpl& get_instance() { + static PrinterImpl sp; + return sp; + } +}; + + void badass_function() { char* ptr = (char*)42; *ptr = 42; @@ -37,7 +57,7 @@ void badass_function() { TEST_SEGFAULT (pprint_sigsev) { std::vector signals; signals.push_back(SIGSEGV); - SignalHandling sh(signals); + SignalHandling sh(signals); std::cout << std::boolalpha << "sh.loaded() == " << sh.loaded() << std::endl; badass_function(); } @@ -45,7 +65,7 @@ TEST_SEGFAULT (pprint_sigsev) { TEST_SEGFAULT (wont_pprint) { std::vector signals; signals.push_back(SIGABRT); - SignalHandling sh(signals); + SignalHandling sh(signals); std::cout << std::boolalpha << "sh.loaded() == " << sh.loaded() << std::endl; badass_function(); } diff --git a/test/stacktrace.cpp b/test/stacktrace.cpp index 76cbc60..bfc5f58 100644 --- a/test/stacktrace.cpp +++ b/test/stacktrace.cpp @@ -27,6 +27,14 @@ using namespace backward; +class StdoutPrinter { +public: + static StdioPrinter& get_instance() { + static StdioPrinter sp(stdout); + return sp; + } +}; + void collect_trace(StackTrace& st) { st.load_here(); } @@ -35,8 +43,7 @@ TEST (minitrace) { StackTrace st; collect_trace(st); - Printer printer; - printer.print(st, stdout); + StdoutPrinter::get_instance().print(st); } void d(StackTrace& st) { @@ -60,6 +67,5 @@ TEST (smalltrace) { StackTrace st; a(st); - Printer printer; - printer.print(st, stdout); + StdoutPrinter::get_instance().print(st); }