New debugstream.

git-svn-id: svn://svn.lyx.org/lyx/lyx-devel/trunk@7832 a592a061-630c-0410-9148-cb99ea01b6c8
This commit is contained in:
Lars Gullik Bjønnes 2003-09-26 14:27:20 +00:00
parent fbdee86f79
commit 8d098dcb56
14 changed files with 222 additions and 476 deletions

View File

@ -1,3 +1,7 @@
2003-09-26 Lars Gullik Bjønnes <larsbj@gullik.net>
* boost/test/detail/nullstream.hpp: new file
2003-08-28 Lars Gullik Bjønnes <larsbj@gullik.net>
* boost/config/compiler/gcc.hpp: allow for gcc 3.4

View File

@ -0,0 +1,85 @@
// (C) Copyright Gennadiy Rozental 2002.
// (C) Copyright Daryle Walker 2000-2001.
// Permission to copy, use, modify, sell and distribute this software
// is granted provided this copyright notice appears in all copies.
// This software is provided "as is" without express or implied warranty,
// and with no claim as to its suitability for any purpose.
// See http://www.boost.org for most recent version including documentation.
//
// File : $RCSfile: nullstream.hpp,v $
//
// Version : $Id: nullstream.hpp,v 1.3 2003/02/15 21:57:25 rogeeff Exp $
//
// Description : simulate /dev/null stream
// ***************************************************************************
#ifndef BOOST_NULLSTREAM_HPP
#define BOOST_NULLSTREAM_HPP
#include <ostream> // for std::basic_ostream
#include <streambuf> // for std::basic_streambuf
#include <string> // for std::char_traits
#include <boost/utility/base_from_member.hpp>
namespace boost {
// ************************************************************************** //
// ************** basic_nullbuf ************** //
// ************************************************************************** //
// Class for a buffer that reads nothing and writes to nothing.
// Idea from an Usenet post by Tom <the_wid@my-deja.com> at
// 27 Oct 2000 14:06:21 GMT on comp.lang.c++.
template<typename CharType, class CharTraits = ::std::char_traits<CharType> >
class basic_nullbuf : public ::std::basic_streambuf<CharType, CharTraits> {
typedef ::std::basic_streambuf<CharType, CharTraits> base_type;
public:
// Types
typedef typename base_type::char_type char_type;
typedef typename base_type::traits_type traits_type;
typedef typename base_type::int_type int_type;
typedef typename base_type::pos_type pos_type;
typedef typename base_type::off_type off_type;
// Use automatic default constructor and destructor
protected:
// The default implementations of the miscellaneous virtual
// member functions are sufficient.
// The default implementations of the input & putback virtual
// member functions, being nowhere but EOF, are sufficient.
// The output virtual member functions need to be changed to
// accept anything without any problems, instead of being at EOF.
virtual ::std::streamsize xsputn( char_type const* /*s*/, ::std::streamsize n ) { return n; } // "s" is unused
virtual int_type overflow( int_type c = traits_type::eof() ) { return traits_type::not_eof( c ); }
};
typedef basic_nullbuf<char> nullbuf;
typedef basic_nullbuf<wchar_t> wnullbuf;
// ************************************************************************** //
// ************** basic_onullstream ************** //
// ************************************************************************** //
// Output streams based on basic_nullbuf.
template< typename CharType, class CharTraits = ::std::char_traits<CharType> >
class basic_onullstream : private boost::base_from_member<basic_nullbuf<CharType, CharTraits> >
, public ::std::basic_ostream<CharType, CharTraits> {
typedef boost::base_from_member<basic_nullbuf<CharType, CharTraits> > pbase_type;
typedef ::std::basic_ostream<CharType, CharTraits> base_type;
public:
// Constructor
basic_onullstream() : pbase_type(), base_type( &this->pbase_type::member ) {}
};
typedef basic_onullstream<char> onullstream;
typedef basic_onullstream<wchar_t> wonullstream;
} // namespace boost
#endif // BOOST_NULLSTREAM_HPP

View File

@ -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

View File

@ -1,3 +1,12 @@
2003-09-26 Lars Gullik Bjønnes <larsbj@gullik.net>
* lyx_main.C: remove the glboal debug object
* debug.h: adjust for new debugstream
* debug.C: adjust for new debugstream and keep the global debug
object here.
2003-09-22 Angus Leeming <leeming@lyx.org>
* paragraph_pimpl.h: add #include "lyxfont.h". Needed by earlier versions
@ -20,13 +29,13 @@
* kbsequence.C (addkey): return a FuncRequest
* kbmap.h (kb_key): struct var FuncRequest instead of int action.
* kbmap.h (kb_key): struct var FuncRequest instead of int action.
* kbmap.C (bind): take a FuncRequest as arg, adjust
(read): adjust
(lookup): adjust
(defkey): change to take a FuncRequest as arg, adjust
(findbinding): take a FuncRequest as arg, adjust.
(findbinding): take a FuncRequest as arg, adjust.
* funcrequest.h (operator=): added

View File

@ -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(errorTags)/sizeof(error_item);
} // 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 & val)
}
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, Debug::type level)
}
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());

View File

@ -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);
typedef basic_debugstream<lyx_debug_trait> LyXErr;
typedef LyXErr::debug Debug;
std::ostream & operator<<(std::ostream & o, Debug::type t);
extern DebugStream lyxerr;
extern LyXErr lyxerr;
#endif

View File

@ -87,8 +87,6 @@ extern void QuitLyX();
extern LyXServer * lyxserver;
DebugStream lyxerr;
boost::scoped_ptr<LastFiles> lastfiles;
// This is the global bufferlist object

View File

@ -1,3 +1,9 @@
2003-09-26 Lars Gullik Bjønnes <larsbj@gullik.net>
* debugstream.h: add file, updated version of the DebugStream
* DebugStream.C,DebugStream.h: delete files
2003-09-25 Angus Leeming <leeming@lyx.org>
* filetools.C (ReplaceEnvironmentPath): rewrite to use boost::regex.

View File

@ -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

View File

@ -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

View File

@ -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 \

87
src/support/debugstream.h Normal file
View File

@ -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

View File

@ -1,3 +1,7 @@
2003-09-26 Lars Gullik Bjønnes <larsbj@gullik.net>
* tex2lyx.C: adjust for new debugstream.
2003-09-08 Angus Leeming <leeming@lyx.org>
* math.C:

View File

@ -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() {}