This is the reworked debug stream. Unless I get objections, this will go into CVS rather soon.
? debug-1.diff Index: po/POTFILES.in =================================================================== RCS file: /usr/local/lyx/cvsroot/lyx-devel/po/POTFILES.in,v retrieving revision 1.354 diff -u -p -r1.354 POTFILES.in --- po/POTFILES.in 21 Sep 2003 16:02:52 -0000 1.354 +++ po/POTFILES.in 26 Sep 2003 12:37:01 -0000 @@ -185,6 +185,7 @@ src/mathed/ref_inset.C src/paragraph.C src/paragraph_funcs.C src/rowpainter.C +src/support/path_defines.C src/text.C src/text2.C src/text3.C Index: src/debug.C =================================================================== RCS file: /usr/local/lyx/cvsroot/lyx-devel/src/debug.C,v retrieving revision 1.37 diff -u -p -r1.37 debug.C --- src/debug.C 9 Sep 2003 22:13:23 -0000 1.37 +++ src/debug.C 26 Sep 2003 12:37:01 -0000 @@ -16,6 +16,7 @@ #include "support/lstrings.h" +#include <iostream> #include <iomanip> using lyx::support::ascii_lowercase; @@ -71,16 +72,7 @@ int const numErrorTags = sizeof(errorTag } // namespace anon -Debug::type const Debug::ANY = Debug::type( - Debug::INFO | Debug::INIT | Debug::KEY | Debug::GUI | - Debug::PARSER | Debug::LYXRC | Debug::KBMAP | Debug::LATEX | - Debug::MATHED | Debug::FONT | Debug::TCLASS | Debug::LYXVC | - Debug::LYXSERVER | Debug::ROFF | Debug::ACTION | Debug::LYXLEX | - Debug::DEPEND | Debug::INSETS | Debug::FILES | Debug::WORKAREA | - Debug::INSETTEXT | Debug::GRAPHICS | Debug::CHANGES | Debug::EXTERNAL); - - -Debug::type Debug::value(string const & val) +lyx_debug_trait::type lyx_debug_trait::value(string const & val) { type l = Debug::NONE; string v(val); @@ -106,7 +98,7 @@ Debug::type Debug::value(string const & } -void Debug::showLevel(ostream & os, Debug::type level) +void lyx_debug_trait::showLevel(ostream & os, lyx_debug_trait::type level) { // Show what features are traced for (int i = 0; i < numErrorTags ; ++i) { @@ -122,7 +114,7 @@ void Debug::showLevel(ostream & os, Debu } -void Debug::showTags(ostream & os) +void lyx_debug_trait::showTags(ostream & os) { for (int i = 0; i < numErrorTags ; ++i) os << setw(7) << errorTags[i].level @@ -130,3 +122,5 @@ void Debug::showTags(ostream & os) << " " << _(errorTags[i].desc) << '\n'; os.flush(); } + +LyXErr lyxerr(std::cerr.rdbuf()); Index: src/debug.h =================================================================== RCS file: /usr/local/lyx/cvsroot/lyx-devel/src/debug.h,v retrieving revision 1.33 diff -u -p -r1.33 debug.h --- src/debug.h 7 Sep 2003 21:25:33 -0000 1.33 +++ src/debug.h 26 Sep 2003 12:37:01 -0000 @@ -15,12 +15,13 @@ #include "support/std_string.h" +#include "support/debugstream.h" /** Ideally this should have been a namespace, but since we try to be compilable on older C++ compilators too, we use a struct instead. This is all the different debug levels that we have. */ -struct Debug { +struct lyx_debug_trait { /// enum type { /// @@ -72,15 +73,19 @@ struct Debug { /// change tracking CHANGES = (1 << 22), /// - EXTERNAL = (1 << 23) + EXTERNAL = (1 << 23), + /// + ANY = 0xffffff }; - /// - static type const ANY; + + static bool match(type a, type b) { + return (a & b); + } /** A function to convert symbolic string names on debug levels to their numerical value. */ - static Debug::type value(string const & val); + static type value(string const & val); /** Display the tags and descriptions of the current debug level of ds @@ -95,18 +100,17 @@ struct Debug { inline -void operator|=(Debug::type & d1, Debug::type d2) +void operator|=(lyx_debug_trait::type & d1, lyx_debug_trait::type d2) { - d1 = static_cast<Debug::type>(d1 | d2); + d1 = static_cast<lyx_debug_trait::type>(d1 | d2); } -#include "support/DebugStream.h" - - +// std::ostream & operator<<(std::ostream & o, Debug::type t); -std::ostream & operator<<(std::ostream & o, Debug::type t); +typedef basic_debugstream<lyx_debug_trait> LyXErr; +typedef LyXErr::debug Debug; -extern DebugStream lyxerr; +extern LyXErr lyxerr; #endif Index: src/lyx_main.C =================================================================== RCS file: /usr/local/lyx/cvsroot/lyx-devel/src/lyx_main.C,v retrieving revision 1.176 diff -u -p -r1.176 lyx_main.C --- src/lyx_main.C 21 Sep 2003 23:00:44 -0000 1.176 +++ src/lyx_main.C 26 Sep 2003 12:37:01 -0000 @@ -87,8 +87,6 @@ extern void QuitLyX(); extern LyXServer * lyxserver; -DebugStream lyxerr; - boost::scoped_ptr<LastFiles> lastfiles; // This is the global bufferlist object Index: src/support/DebugStream.C =================================================================== RCS file: src/support/DebugStream.C diff -N src/support/DebugStream.C --- src/support/DebugStream.C 23 Aug 2003 00:16:56 -0000 1.17 +++ /dev/null 1 Jan 1970 00:00:00 -0000 @@ -1,299 +0,0 @@ -/** - * \file DebugStream.C - * This file is part of LyX, the document processor. - * Licence details can be found in the file COPYING. - * - * \author Lars Gullik Bjønnes - * - * Full author contact details are available in file CREDITS. - */ - -//#define TEST_DEBUGSTREAM - -#include <config.h> - -//#include "DebugStream.h" -#include "debug.h" - -// Since the current C++ lib in egcs does not have a standard implementation -// of basic_streambuf and basic_filebuf we don't have to include this -// header. -//#define MODERN_STL_STREAMS -#ifdef MODERN_STL_STREAMS -#include <fstream> -#endif -#include <iostream> - -using std::ostream; -using std::streambuf; -using std::streamsize; -using std::filebuf; -using std::cerr; -using std::ios; - -ostream & operator<<(ostream & o, Debug::type t) -{ - return o << int(t); -} - -/** This is a streambuffer that never prints out anything, at least - that is the intention. You can call it a no-op streambuffer, and - the ostream that uses it will be a no-op stream. -*/ -class nullbuf : public streambuf { -protected: -#ifndef MODERN_STL_STREAMS - typedef char char_type; - typedef int int_type; - /// - virtual int sync() { return 0; } -#endif - /// - virtual streamsize xsputn(char_type const *, streamsize n) { - // fakes a purge of the buffer by returning n - return n; - } -#ifdef MODERN_STL_STREAMS - /// - virtual int_type overflow(int_type c = traits_type::eof()) { - // fakes success by returning c - return c == traits_type::eof() ? ' ' : c; - } -#else - /// - virtual int_type overflow(int_type c = EOF) { - // fakes success by returning c - return c == EOF ? ' ' : c; - } -#endif -}; - -/** A streambuf that sends the output to two different streambufs. These - can be any kind of streambufs. -*/ -class teebuf : public streambuf { -public: - /// - teebuf(streambuf * b1, streambuf * b2) - : streambuf(), sb1(b1), sb2(b2) {} -protected: -#ifdef MODERN_STL_STREAMS - /// - virtual int sync() { - sb2->pubsync(); - return sb1->pubsync(); - } - /// - virtual streamsize xsputn(char_type const * p, streamsize n) { - sb2->sputn(p, n); - return sb1->sputn(p, n); - } - /// - virtual int_type overflow(int_type c = traits_type::eof()) { - sb2->sputc(c); - return sb1->sputc(c); - } -#else - typedef char char_type; - typedef int int_type; - /// - virtual int sync() { - sb2->sync(); - return sb1->sync(); - } - /// - virtual streamsize xsputn(char_type const * p, streamsize n) { - sb2->xsputn(p, n); - return sb1->xsputn(p, n); - } - /// - virtual int_type overflow(int_type c = EOF) { - sb2->overflow(c); - return sb1->overflow(c); - } -#endif -private: - /// - streambuf * sb1; - /// - streambuf * sb2; -}; - -/// -class debugbuf : public streambuf { -public: - /// - debugbuf(streambuf * b) - : streambuf(), sb(b) {} -protected: -#ifdef MODERN_STL_STREAMS - /// - virtual int sync() { - return sb->pubsync(); - } - /// - virtual streamsize xsputn(char_type const * p, streamsize n) { - return sb->sputn(p, n); - } - /// - virtual int_type overflow(int_type c = traits_type::eof()) { - return sb->sputc(c); - } -#else - typedef char char_type; - typedef int int_type; - /// - virtual int sync() { - return sb->sync(); - } - /// - virtual streamsize xsputn(char_type const * p, streamsize n) { - return sb->xsputn(p, n); - } - /// - virtual int_type overflow(int_type c = EOF) { - return sb->overflow(c); - } -#endif -private: - /// - streambuf * sb; -}; - - -/// So that public parts of DebugStream does not need to know about filebuf -struct DebugStream::debugstream_internal { - /// Used when logging to file. - filebuf fbuf; -}; - - -/// Constructor, sets the debug level to t. -DebugStream::DebugStream(Debug::type t) - : ostream(new debugbuf(cerr.rdbuf())), - dt(t), nullstream(new nullbuf), internal(0) {} - - -/// Constructor, sets the log file to f, and the debug level to t. -DebugStream::DebugStream(char const * f, Debug::type t) - : ostream(new debugbuf(cerr.rdbuf())), - dt(t), nullstream(new nullbuf), - internal(new debugstream_internal) -{ - internal->fbuf.open(f, ios::out|ios::app); - delete rdbuf(new teebuf(cerr.rdbuf(), - &internal->fbuf)); -} - - -DebugStream::~DebugStream() -{ - delete nullstream.rdbuf(0); // Without this we leak - delete rdbuf(0); // Without this we leak - delete internal; -} - - -/// Sets the debugstreams' logfile to f. -void DebugStream::logFile(char const * f) -{ - if (internal) { - internal->fbuf.close(); - } else { - internal = new debugstream_internal; - } - internal->fbuf.open(f, ios::out|ios::app); - delete rdbuf(new teebuf(cerr.rdbuf(), - &internal->fbuf)); -} - - -#ifdef TEST_DEBUGSTREAM - -// Example debug stream -DebugStream debugstream; - -int main(int, char **) -{ - /** - I have been running some tests on this to see how much overhead - this kind of permanent debug code has. My conclusion is: not - much. In all, but the most time critical code, this will have - close to no impact at all. - - In the tests that I have run the use of - if (debugstream.debugging(DebugStream::INFO)) - debugstream << "some debug\n"; - has close to no overhead when the debug level is not - DebugStream::INFO. - - The overhead for - debugstream.debug(DebugStream::INFO) << "some debug\n"; - is also very small when the debug level is not - DebugStream::INFO. However the overhead for this will increase - if complex debugging information is output. - - The overhead when the debug level is DebugStream::INFO can be - significant, but since we then are running in debug mode it is - of no concern. - - Why should we use this instead of the class Error that we already - have? First of all it uses C++ iostream and constructs, secondly - it will be a lot easier to output the debug info that we need - without a lot of manual conversions, thirdly we can now use - iomanipulators and the complete iostream formatting functions. - pluss it will work for all types that have a operator<< - defined, and can be used in functors that take a ostream & as - parameter. And there should be less need for temporary objects. - And one nice bonus is that we get a log file almost for - free. - - Some of the names are of course open to modifications. I will try - to use the names we already use in LyX. - */ - // Just a few simple debugs to show how it can work. - debugstream << "Debug level set to Debug::NONE\n"; - if (debugstream.debugging()) { - debugstream << "Something must be debugged\n"; - } - debugstream.debug(Debug::WARN) << "more debug(WARN)\n"; - debugstream.debug(Debug::INFO) << "even more debug(INFO)\n"; - debugstream.debug(Debug::CRIT) << "even more debug(CRIT)\n"; - debugstream.level(Debug::value("INFO")); - debugstream << "Setting debug level to Debug::INFO\n"; - if (debugstream.debugging()) { - debugstream << "Something must be debugged\n"; - } - debugstream.debug(Debug::WARN) << "more debug(WARN)\n"; - debugstream.debug(Debug::INFO) << "even more debug(INFO)\n"; - debugstream.debug(Debug::CRIT) << "even more debug(CRIT)\n"; - debugstream.addLevel(Debug::type(Debug::CRIT | - Debug::WARN)); - debugstream << "Adding Debug::CRIT and Debug::WARN\n"; - debugstream[Debug::WARN] << "more debug(WARN)\n"; - debugstream[Debug::INFO] << "even more debug(INFO)\n"; - debugstream[Debug::CRIT] << "even more debug(CRIT)\n"; - debugstream.delLevel(Debug::INFO); - debugstream << "Removing Debug::INFO\n"; - debugstream[Debug::WARN] << "more debug(WARN)\n"; - debugstream[Debug::INFO] << "even more debug(INFO)\n"; - debugstream[Debug::CRIT] << "even more debug(CRIT)\n"; - debugstream.logFile("logfile"); - debugstream << "Setting logfile to \"logfile\"\n"; - debugstream << "Value: " << 123 << " " << "12\n"; - int i = 0; - int * p = new int; - // note: the (void*) is needed on g++ 2.7.x since it does not - // support partial specialization. In egcs this should not be - // needed. - debugstream << "automatic " << &i - << ", free store " << p << endl; - delete p; - /* - for (int j = 0; j < 200000; ++j) { - DebugStream tmp; - tmp << "Test" << endl; - } - */ -} -#endif Index: src/support/DebugStream.h =================================================================== RCS file: src/support/DebugStream.h diff -N src/support/DebugStream.h --- src/support/DebugStream.h 5 Sep 2003 17:23:10 -0000 1.22 +++ /dev/null 1 Jan 1970 00:00:00 -0000 @@ -1,145 +0,0 @@ -// -*- C++ -*- -/** - * \file DebugStream.h - * This file is part of LyX, the document processor. - * Licence details can be found in the file COPYING. - * - * \author Lars Gullik Bjønnes - * - * Full author contact details are available in file CREDITS. - */ - -#ifndef DEBUGSTREAM_H -#define DEBUGSTREAM_H - -#include "std_ostream.h" - -#ifdef TEST_DEBUGSTREAM -#include <string> -struct Debug { - enum type { - NONE = 0, - INFO = (1 << 0), // 1 - WARN = (1 << 1), // 2 - CRIT = (1 << 2) // 4 - }; - static const type ANY = type(INFO | WARN | CRIT); - static Debug::type value(string const & val) { - if (val == "NONE") return Debug::NONE; - if (val == "INFO") return Debug::INFO; - if (val == "WARN") return Debug::WARN; - if (val == "CRIT") return Debug::CRIT; - return Debug::NONE; - } -}; -#endif - -/** DebugStream is a ostream intended for debug output. - It has also support for a logfile. Debug output is output to cerr - and if the logfile is set, to the logfile. - - Example of Usage: - DebugStream debug; - debug.level(Debug::INFO); - debug.debug(Debug::WARN) << "WARN\n"; - debug[Debug::INFO] << "INFO\n"; - debug << "Always\n"; - - Will output: - INFO - Always - - If you want to have debug output from time critical code you should - use this construct: - if (debug.debugging(Debug::INFO)) { - debug << "...debug output...\n"; - } - - To give debug info even if no debug (NONE) is requested: - debug << "... always output ...\n"; - - To give debug output regardless of what debug level is set (!NONE): - debug.debug() << "...on debug output...\n"; - debug[Debug::ANY] << "...on debug output...\n"; - - To give debug output when a specific debug level is set (INFO): - debug.debug(Debug::INFO) << "...info...\n"; - debug[Debug::INFO] << "...info...\n"; - - To give debug output when either on of debug levels is set (INFO or CRIT): - debug.debug(Debug::type(Debug::INFO | Debug::CRIT)) << "...info/crit...\n"; - debug[Debug::type(Debug::INFO | Debug::CRIT)] << "...info/crit...\n"; - -*/ -class DebugStream : public std::ostream -{ -public: - /// Constructor, sets the debug level to t. - explicit DebugStream(Debug::type t = Debug::NONE); - - /// Constructor, sets the log file to f, and the debug level to t. - explicit - DebugStream(char const * f, Debug::type t = Debug::NONE); - - /// - ~DebugStream(); - - /// Sets the debug level to t. - void level(Debug::type t) { - dt = Debug::type(t & Debug::ANY); - } - - /// Returns the current debug level. - Debug::type level() const { - return dt; - } - - /// Adds t to the current debug level. - void addLevel(Debug::type t) { - dt = Debug::type(dt | t); - } - - /// Deletes t from the current debug level. - void delLevel(Debug::type t) { - dt = Debug::type(dt & ~t); - } - - /// Sets the debugstreams' logfile to f. - void logFile(char const * f); - - /// Returns true if t is part of the current debug level. - bool debugging(Debug::type t = Debug::ANY) const - { - if (dt & t) return true; - return false; - } - - - /** Returns the no-op stream if t is not part of the - current debug level otherwise the real debug stream - is used. - */ - std::ostream & debug(Debug::type t = Debug::ANY) { - if (dt & t) return *this; - return nullstream; - } - - - /** This is an operator to give a more convenient use: - dbgstream[Debug::INFO] << "Info!\n"; - */ - std::ostream & operator[](Debug::type t) { - return debug(t); - } -private: - /// The current debug level - Debug::type dt; - /// The no-op stream. - std::ostream nullstream; - /// - struct debugstream_internal; - /// - debugstream_internal * internal; -}; - -#endif Index: src/support/Makefile.am =================================================================== RCS file: /usr/local/lyx/cvsroot/lyx-devel/src/support/Makefile.am,v retrieving revision 1.67 diff -u -p -r1.67 Makefile.am --- src/support/Makefile.am 15 Sep 2003 10:59:59 -0000 1.67 +++ src/support/Makefile.am 26 Sep 2003 12:37:01 -0000 @@ -16,8 +16,6 @@ BUILT_SOURCES = path_defines.C libsupport_la_SOURCES = \ BoostFormat.h \ - DebugStream.C \ - DebugStream.h \ FileInfo.C \ FileInfo.h \ FileMonitor.h \ @@ -29,6 +27,7 @@ libsupport_la_SOURCES = \ copy.C \ copied_ptr.h \ cow_ptr.h \ + debugstream,h \ filename.C \ filename.h \ filetools.C \ Index: src/support/debugstream.h =================================================================== RCS file: src/support/debugstream.h diff -N src/support/debugstream.h --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ src/support/debugstream.h 26 Sep 2003 12:37:02 -0000 @@ -0,0 +1,87 @@ +// -*- C++ -*- +/** + * \file debugStream.h + * This file is part of LyX, the document processor. + * Licence details can be found in the file COPYING. + * + * \author Lars Gullik Bjønnes + * + * Full author contact details are available in file CREDITS. + */ + +#ifndef DEBUG_STREAM_HPP +#define DEBUG_STREAM_HPP + +#include <boost/test/detail/nullstream.hpp> + + +struct debug_trait { + enum type { + NONE = 0, + EMERG = 1, + ALERT = 2, + CRIT = 3, + ERR = 4, + WARN = 5, + NOTICE = 6, + INFO = 7, + DEBUG = 8, + ANY = 0xffffff + }; + + static bool match(type a, type b) { + return (b <= a || (b == ANY && a > NONE)); + } +}; + + +template <class dtrait, + class charT = char, + class traits = std::char_traits<charT> > +class basic_debugstream : public std::basic_ostream<charT, traits> { +public: + typedef dtrait debug; + typedef typename debug::type Type; + + /// Constructor, sets the debug level to t. + explicit basic_debugstream(std::basic_streambuf<charT, traits> * buf) + : std::basic_ostream<charT, traits>(buf), dt(debug::NONE) + {} + + /// Sets the debug level to t. + void level(Type t) { + dt = t; + } + + /// Returns the current debug level. + Type level() const { + return dt; + } + + /// Returns true if t is part of the current debug level. + bool debugging(Type t = debug::ANY) const + { + if (debug::match(dt, t)) return true; + return false; + } + + /** Returns the no-op stream if t is not part of the + current debug level otherwise the real debug stream + is used. + Use: dbgstream[Debug::INFO] << "Info!\n"; + */ + std::basic_ostream<charT, traits> & operator[](Type t) { + if (debug::match(dt, t)) + return *this; + return nullstream; + } +private: + /// The current debug level + Type dt; + /// The no-op stream. + boost::basic_onullstream<charT, traits> nullstream; +}; + +typedef basic_debugstream<debug_trait> debugstream; + +#endif Index: src/tex2lyx/tex2lyx.C =================================================================== RCS file: /usr/local/lyx/cvsroot/lyx-devel/src/tex2lyx/tex2lyx.C,v retrieving revision 1.49 diff -u -p -r1.49 tex2lyx.C --- src/tex2lyx/tex2lyx.C 9 Sep 2003 17:25:35 -0000 1.49 +++ src/tex2lyx/tex2lyx.C 26 Sep 2003 12:37:02 -0000 @@ -41,8 +41,7 @@ using std::string; using std::vector; // Hacks to allow the thing to link in the lyxlayout stuff -Debug::type const Debug::ANY = Debug::type(0); -DebugStream lyxerr; +LyXErr lyxerr(std::cerr.rdbuf()); void LyX::emergencyCleanup() {}
-- Lgb