// file : bbot/diagnostics -*- C++ -*- // copyright : Copyright (c) 2014-2017 Code Synthesis Ltd // license : MIT; see accompanying LICENSE file #ifndef BBOT_DIAGNOSTICS #define BBOT_DIAGNOSTICS #include #include #include namespace bbot { using butl::diag_record; // Throw this exception to terminate the process. The handler should // assume that the diagnostics has already been issued. // class failed: public std::exception {}; // Verbosity level. Update documentation for --verbose if changing. // // 0 - disabled // 1 - high-level information messages // 2 - essential underlying commands that are being executed // 3 - all underlying commands that are being executed // 4 - information that could be helpful to the user // 5 - information that could be helpful to the developer // 6 - even more detailed information // // While uint8 is more than enough, use uint16 for the ease of printing. // extern uint16_t verb; template inline void l1 (const F& f) {if (verb >= 1) f ();} template inline void l2 (const F& f) {if (verb >= 2) f ();} template inline void l3 (const F& f) {if (verb >= 3) f ();} template inline void l4 (const F& f) {if (verb >= 4) f ();} template inline void l5 (const F& f) {if (verb >= 5) f ();} template inline void l6 (const F& f) {if (verb >= 6) f ();} // Diagnostic facility, base infrastructure. // using butl::diag_stream; using butl::diag_epilogue; // Diagnostic facility, project specifics. // struct simple_prologue_base { explicit simple_prologue_base (const char* type, const char* name) : type_ (type), name_ (name) {} void operator() (const diag_record& r) const; private: const char* type_; const char* name_; }; class location { public: location () {} location (string f, uint64_t l, uint64_t c) : file (move (f)), line (l), column (c) {} string file; uint64_t line; uint64_t column; }; struct location_prologue_base { location_prologue_base (const char* type, const char* name, const location& l) : type_ (type), name_ (name), loc_ (l) {} void operator() (const diag_record& r) const; private: const char* type_; const char* name_; const location loc_; }; struct basic_mark_base { using simple_prologue = butl::diag_prologue; using location_prologue = butl::diag_prologue; explicit basic_mark_base (const char* type, const char* name = nullptr, const void* data = nullptr, diag_epilogue* epilogue = nullptr) : type_ (type), name_ (name), data_ (data), epilogue_ (epilogue) {} simple_prologue operator() () const { return simple_prologue (epilogue_, type_, name_); } location_prologue operator() (const location& l) const { return location_prologue (epilogue_, type_, name_, l); } template location_prologue operator() (const L& l) const { return location_prologue ( epilogue_, type_, name_, get_location (l, data_)); } template location_prologue operator() (F&& f, L&& l, C&& c) const { return location_prologue ( epilogue_, type_, name_, location (forward (f), forward (l), forward (c))); } protected: const char* type_; const char* name_; const void* data_; diag_epilogue* const epilogue_; }; using basic_mark = butl::diag_mark; extern const basic_mark error; extern const basic_mark warn; extern const basic_mark info; extern const basic_mark text; // trace // struct trace_mark_base: basic_mark_base { explicit trace_mark_base (const char* name, const void* data = nullptr) : basic_mark_base ("trace", name, data) {} }; using trace_mark = butl::diag_mark; using tracer = trace_mark; // fail // struct fail_mark_base: basic_mark_base { explicit fail_mark_base (const char* type, const void* data = nullptr) : basic_mark_base (type, nullptr, data, [](const diag_record& r) { r.flush (); throw failed (); }) {} }; using fail_mark = butl::diag_mark; struct fail_end_base { [[noreturn]] void operator() (const diag_record& r) const { // If we just throw then the record's destructor will see an active // exception and will not flush the record. // r.flush (); throw failed (); } }; using fail_end = butl::diag_noreturn_end; extern const fail_mark fail; extern const fail_end endf; } #endif // BBOT_DIAGNOSTICS