Below is the file 'sanity.cc' from this revision. You can also download the file.
// copyright (C) 2002, 2003 graydon hoare <graydon@pobox.com> // all rights reserved. // licensed to the public under the terms of the GNU GPL (>= 2) // see the file COPYING for details #include <stdio.h> #include <stdarg.h> #include <algorithm> #include <iterator> #include <iostream> #include <fstream> #include <string> #include <vector> #include <sstream> #include <boost/lexical_cast.hpp> #include "constants.hh" #include "platform.hh" #include "sanity.hh" #include "transforms.hh" #include "ui.hh" using namespace std; using boost::format; // debugging / logging system sanity global_sanity; sanity::sanity() : debug(false), quiet(false), relaxed(false), logbuf(0xffff), already_dumping(false) { std::string flavour; get_system_flavour(flavour); L(F("started up on %s\n") % flavour); } sanity::~sanity() {} void sanity::dump_buffer() { if (!filename.empty()) { ofstream out(filename.as_external().c_str()); if (out) { copy(logbuf.begin(), logbuf.end(), ostream_iterator<char>(out)); copy(gasp_dump.begin(), gasp_dump.end(), ostream_iterator<char>(out)); ui.inform((F("wrote debugging log to %s") % filename).str()); } else ui.inform((F("failed to write debugging log to %s") % filename).str()); } else ui.inform("discarding debug log (maybe you want --debug or --dump?)"); } void sanity::set_debug() { quiet = false; debug = true; // it is possible that some pre-setting-of-debug data // accumulated in the log buffer (during earlier option processing) // so we will dump it now ostringstream oss; vector<string> lines; copy(logbuf.begin(), logbuf.end(), ostream_iterator<char>(oss)); split_into_lines(oss.str(), lines); for (vector<string>::const_iterator i = lines.begin(); i != lines.end(); ++i) ui.inform((*i) + "\n"); } void sanity::set_brief() { brief = true; } void sanity::set_quiet() { debug = false; quiet = true; } void sanity::set_relaxed(bool rel) { relaxed = rel; } string sanity::do_format(format const & fmt, char const * file, int line) { try { return fmt.str(); } catch (std::exception & e) { ui.inform(F("fatal: formatter failed on %s:%d: %s") % file % line % e.what()); throw; } } void sanity::log(format const & fmt, char const * file, int line) { string str = do_format(fmt, file, line); if (str.size() > constants::log_line_sz) { str.resize(constants::log_line_sz); if (str.at(str.size() - 1) != '\n') str.at(str.size() - 1) = '\n'; } copy(str.begin(), str.end(), back_inserter(logbuf)); if (str[str.size() - 1] != '\n') logbuf.push_back('\n'); if (debug) ui.inform(str); } void sanity::progress(format const & fmt, char const * file, int line) { string str = do_format(fmt, file, line); if (str.size() > constants::log_line_sz) { str.resize(constants::log_line_sz); if (str.at(str.size() - 1) != '\n') str.at(str.size() - 1) = '\n'; } copy(str.begin(), str.end(), back_inserter(logbuf)); if (str[str.size() - 1] != '\n') logbuf.push_back('\n'); if (! quiet) ui.inform(str); } void sanity::warning(format const & fmt, char const * file, int line) { string str = do_format(fmt, file, line); if (str.size() > constants::log_line_sz) { str.resize(constants::log_line_sz); if (str.at(str.size() - 1) != '\n') str.at(str.size() - 1) = '\n'; } string str2 = "warning: " + str; copy(str2.begin(), str2.end(), back_inserter(logbuf)); if (str[str.size() - 1] != '\n') logbuf.push_back('\n'); if (! quiet) ui.warn(str); } void sanity::naughty_failure(string const & expr, format const & explain, string const & file, int line) { string message; log(format("%s:%d: usage constraint '%s' violated\n") % file % line % expr, file.c_str(), line); prefix_lines_with(_("misuse: "), explain.str(), message); throw informative_failure(message); } void sanity::error_failure(string const & expr, format const & explain, string const & file, int line) { string message; log(format("%s:%d: detected error '%s' violated\n") % file % line % expr, file.c_str(), line); prefix_lines_with(_("error: "), explain.str(), message); throw informative_failure(message); } void sanity::invariant_failure(string const & expr, string const & file, int line) { format fmt = format("%s:%d: invariant '%s' violated\n") % file % line % expr; log(fmt, file.c_str(), line); gasp(); throw logic_error(fmt.str()); } void sanity::index_failure(string const & vec_expr, string const & idx_expr, unsigned long sz, unsigned long idx, string const & file, int line) { format fmt = format("%s:%d: index '%s' = %d overflowed vector '%s' with size %d\n") % file % line % idx_expr % idx % vec_expr % sz; log(fmt, file.c_str(), line); gasp(); throw logic_error(fmt.str()); } // Last gasp dumps void sanity::gasp() { if (already_dumping) { L(F("ignoring request to give last gasp; already in process of dumping\n")); return; } already_dumping = true; L(F("saving current work set: %i items") % musings.size()); std::ostringstream out; out << F("Current work set: %i items\n") % musings.size(); for (std::vector<MusingI const *>::const_iterator i = musings.begin(); i != musings.end(); ++i) { std::string tmp; try { (*i)->gasp(tmp); out << tmp; } catch (logic_error) { out << tmp; out << "<caught logic_error>\n"; L(F("ignoring error trigged by saving work set to debug log")); } catch (informative_failure) { out << tmp; out << "<caught informative_failure>\n"; L(F("ignoring error trigged by saving work set to debug log")); } } gasp_dump = out.str(); L(F("finished saving work set")); if (debug) { ui.inform("contents of work set:"); ui.inform(gasp_dump); } already_dumping = false; } MusingI::MusingI() { if (!global_sanity.already_dumping) global_sanity.musings.push_back(this); } MusingI::~MusingI() { if (!global_sanity.already_dumping) { I(global_sanity.musings.back() == this); global_sanity.musings.pop_back(); } } void dump(std::string const & obj, std::string & out) { out = obj; } void MusingBase::gasp(const std::string & objstr, std::string & out) const { out = (boost::format("----- begin '%s' (in %s, at %s:%d)\n" "%s" "----- end '%s' (in %s, at %s:%d)\n") % name % func % file % line % objstr % name % func % file % line ).str(); } boost::format F(const char * str) { return boost::format(gettext(str), get_user_locale()); } boost::format FP(const char * str1, const char * strn, unsigned long count) { return boost::format(ngettext(str1, strn, count), get_user_locale()); }