erste version, test vor configure
This commit is contained in:
50
configure.in
Normal file
50
configure.in
Normal file
@@ -0,0 +1,50 @@
|
|||||||
|
AC_INIT([mrw/mrw.hpp])
|
||||||
|
PACKAGENAME=mrw-c++
|
||||||
|
MAJOR=0
|
||||||
|
MINOR=01
|
||||||
|
SUPPORT=alfa
|
||||||
|
AM_INIT_AUTOMAKE(@PACKAGENAME@, @MAJOR@.@MINOR@)
|
||||||
|
|
||||||
|
# languages
|
||||||
|
AC_LANG(C++)
|
||||||
|
|
||||||
|
# programs
|
||||||
|
AC_PROG_CXX
|
||||||
|
AC_PROG_CPP
|
||||||
|
AC_PROG_INSTALL
|
||||||
|
AC_PROG_LN_S
|
||||||
|
AC_PROG_MAKE_SET
|
||||||
|
AC_PROG_LIBTOOL
|
||||||
|
AC_CHECK_PROG(have_doxygen, doxygen, yes, no)
|
||||||
|
AC_CHECK_PROG(have_dot, dot, yes, no)
|
||||||
|
|
||||||
|
# libraries
|
||||||
|
#AC_SEARCH_LIBS(demangle, iberty)
|
||||||
|
#AC_SEARCH_LIBS(, bfd)
|
||||||
|
|
||||||
|
# Arguments
|
||||||
|
AM_MAINTAINER_MODE
|
||||||
|
AC_ARG_ENABLE(dot,
|
||||||
|
[ --disable-dot disable dot graphic tools for documentation],
|
||||||
|
[have_dot="$enableval"])
|
||||||
|
test "$enableval" = "yes" && HAVE_DOT="YES" || HAVE_DOT="NO";
|
||||||
|
|
||||||
|
# export macros
|
||||||
|
AC_SUBST(HAVE_DOT)
|
||||||
|
AC_SUBST(MAJOR)
|
||||||
|
AC_SUBST(MINOR)
|
||||||
|
AC_SUBST(SUPPORT)
|
||||||
|
AC_SUBST(PACKAGENAME)
|
||||||
|
|
||||||
|
# create output
|
||||||
|
AC_CONFIG_FILES([makefile mrw/makefile mrw/doxyfile])
|
||||||
|
|
||||||
|
# infos and warnings
|
||||||
|
if test "$have_doxygen" = "no"; then
|
||||||
|
AC_MSG_WARN([Missing program doxygen!
|
||||||
|
- you cannot rebuild the documentation with make doc
|
||||||
|
- there are precompiled derieved files in the distribution]); fi
|
||||||
|
if test "$have_dot" = "no"; then
|
||||||
|
AC_MSG_WARN([Missing program dot!
|
||||||
|
- when you rebild documentation with make doc, there are no generated images
|
||||||
|
- there are precompiled derieved files in the distribution]); fi
|
1
makefile.am
Normal file
1
makefile.am
Normal file
@@ -0,0 +1 @@
|
|||||||
|
SUBDIRS = mrw
|
31
mrw/auto.cpp
Normal file
31
mrw/auto.cpp
Normal file
@@ -0,0 +1,31 @@
|
|||||||
|
#include <mrw/auto.hpp>
|
||||||
|
#include <unistd.h> // close
|
||||||
|
#include <sys/stat.h> // fstat
|
||||||
|
#include <sys/mman.h> // mmap
|
||||||
|
|
||||||
|
namespace mrw {
|
||||||
|
|
||||||
|
//----------------------------------------------------------------------------
|
||||||
|
|
||||||
|
AutoFile& AutoFile::reset(int fd) throw() {
|
||||||
|
if (_fd!=-1) close(_fd);
|
||||||
|
_fd = fd;
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
|
//----------------------------------------------------------------------------
|
||||||
|
AutoMapper::AutoMapper(int fd, size_t sz, void* addr,
|
||||||
|
int prot, int flags, off_t off) throw() {
|
||||||
|
if (!(_sz=sz)) {
|
||||||
|
struct stat st;
|
||||||
|
if (fd==-1 || fstat(fd, &st)==-1) {release(); return;}
|
||||||
|
_sz = st.st_size;
|
||||||
|
}
|
||||||
|
if ((_cont=mmap(addr, _sz, prot, flags, fd, off))==MAP_FAILED) release();
|
||||||
|
}
|
||||||
|
|
||||||
|
//----------------------------------------------------------------------------
|
||||||
|
AutoMapper::~AutoMapper() throw() {
|
||||||
|
if (_cont && _sz) munmap(_cont, _sz);
|
||||||
|
}
|
||||||
|
}
|
139
mrw/auto.hpp
Normal file
139
mrw/auto.hpp
Normal file
@@ -0,0 +1,139 @@
|
|||||||
|
#ifndef __MRW_AUTO_HPP__
|
||||||
|
#define __MRW_AUTO_HPP__
|
||||||
|
|
||||||
|
#include <sys/types.h> // size_t
|
||||||
|
#include <sys/mman.h> // PROT_READ, MAP_SHARED
|
||||||
|
#include <bfd.h> // bfd*
|
||||||
|
|
||||||
|
namespace mrw {
|
||||||
|
|
||||||
|
/** @defgroup AutoTools Classes for Automated Resource Handling
|
||||||
|
|
||||||
|
For pointers that have been allocated with @c new, you can use
|
||||||
|
std::auto_ptr to automatically free them when you leave the
|
||||||
|
context. Unfortunately there is no such thing for @c malloc
|
||||||
|
(except @c malloca that only works for a subset of problems: if
|
||||||
|
you and not a system call allocates memory), @c open and so on.
|
||||||
|
These classes can take over the resource ownership.
|
||||||
|
*/
|
||||||
|
//@{
|
||||||
|
|
||||||
|
/** @brief Automatically closes a file when destructed.
|
||||||
|
|
||||||
|
AutoFile works exactly like std::auto_ptr, but not for files
|
||||||
|
instead of pointers. Whenever the context of AutoFile is left,
|
||||||
|
the opened file is close. This way, resources are freed even in
|
||||||
|
case of exceptions.
|
||||||
|
*/
|
||||||
|
class AutoFile {
|
||||||
|
public:
|
||||||
|
/// @brief Construct from an opened file.
|
||||||
|
/// @note Don't close @c fd
|
||||||
|
explicit AutoFile(int fd = -1) throw(): _fd(fd) {}
|
||||||
|
/// @brief Takeover ownership from another AutoFile.
|
||||||
|
AutoFile(AutoFile& o) throw(): _fd(o.release()) {}
|
||||||
|
/// @brief Closes file if open.
|
||||||
|
~AutoFile() throw() {reset();}
|
||||||
|
/// @brief Assign new file descriptor.
|
||||||
|
/// The old file of @c this is closed if open.
|
||||||
|
AutoFile& operator=(int fd) throw() {return reset(fd);}
|
||||||
|
/// @brief Takeover ownership from another AutoFile.
|
||||||
|
/// The old file of @c this is closed if open.
|
||||||
|
AutoFile& operator=(AutoFile& other) throw() {
|
||||||
|
return reset(other.release());
|
||||||
|
}
|
||||||
|
/// @brief get the file descriptor @return file descriptor
|
||||||
|
operator const int() const throw() {
|
||||||
|
return _fd;
|
||||||
|
}
|
||||||
|
/// @brief Give away ownership of the file. @return old file descriptor
|
||||||
|
int release() throw() {
|
||||||
|
int ret(_fd); _fd=-1;
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
/// @brief assign a new file descriptor
|
||||||
|
/** The old file of @c this is closed if open. */
|
||||||
|
AutoFile& reset(int = -1) throw();
|
||||||
|
private:
|
||||||
|
int _fd; ///< the file descriptor
|
||||||
|
};
|
||||||
|
|
||||||
|
/** @brief Automatically call @c munmap for mmaped files on destruction.
|
||||||
|
|
||||||
|
It's the same as std::auto_ptr, but for @c mmap instead of @c
|
||||||
|
new. When the context of @c AutoMapper is left, @c munmap is
|
||||||
|
called.
|
||||||
|
*/
|
||||||
|
class AutoMapper {
|
||||||
|
public:
|
||||||
|
AutoMapper(void* cont = 0, size_t sz = 0) throw():
|
||||||
|
_cont(cont), _sz(sz) {}
|
||||||
|
AutoMapper(int, size_t=0, void* = 0,
|
||||||
|
int = PROT_READ, int = MAP_SHARED, off_t = 0) throw();
|
||||||
|
~AutoMapper() throw();
|
||||||
|
operator const void*() const throw() {return _cont;}
|
||||||
|
AutoMapper& set(void* cont, size_t sz) throw() {
|
||||||
|
_cont=cont; _sz=sz;
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
void* release() throw() {
|
||||||
|
void* ret(_cont); _cont=0; _sz=0;
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
const void* last() const throw() {
|
||||||
|
return _cont && _sz ? (void*)((size_t)_cont+_sz-1) : 0;
|
||||||
|
}
|
||||||
|
private:
|
||||||
|
void* _cont;
|
||||||
|
size_t _sz;
|
||||||
|
};
|
||||||
|
|
||||||
|
/** @brief Automatically call @c bfd_close for @c bfd*.
|
||||||
|
|
||||||
|
It acts like a @c std::auto_ptr, but for @c bfd*, that means it
|
||||||
|
calls @c bfd_close whenever the context is left.
|
||||||
|
*/
|
||||||
|
class AutoBfd {
|
||||||
|
public:
|
||||||
|
AutoBfd(bfd* p=0) throw(): _bfd(p) {}
|
||||||
|
~AutoBfd() throw() {if (_bfd) bfd_close(_bfd);}
|
||||||
|
AutoBfd& operator=(bfd* p) throw() {
|
||||||
|
release(); _bfd=p; return *this;
|
||||||
|
}
|
||||||
|
AutoBfd& operator=(AutoBfd& o) throw() {
|
||||||
|
release(); _bfd=o.release(); return *this;
|
||||||
|
}
|
||||||
|
operator bfd*() throw() {return _bfd;}
|
||||||
|
bfd* operator->() throw() {return _bfd;}
|
||||||
|
bfd* release() throw() {bfd* res(_bfd); _bfd = 0; return res;}
|
||||||
|
private:
|
||||||
|
bfd* _bfd;
|
||||||
|
};
|
||||||
|
|
||||||
|
/** @brief Automatically calls @c free for @c malloc allocated memory.
|
||||||
|
|
||||||
|
It works like a @c std::auto_ptr, but for memory that was
|
||||||
|
allocated with @c malloc, not @c new. Memory is freed, whenever
|
||||||
|
the context od @c AutoFree is left.
|
||||||
|
*/
|
||||||
|
template <class T> class AutoFree {
|
||||||
|
public:
|
||||||
|
AutoFree(T* p=0) throw(): _p(p) {}
|
||||||
|
AutoFree(AutoFree& o) throw(): _p(o.release()) {}
|
||||||
|
~AutoFree() throw() {if (_p) free(_p);}
|
||||||
|
AutoFree& operator=(T* p) throw() {
|
||||||
|
release(); _p=p; return *this;
|
||||||
|
}
|
||||||
|
AutoFree& operator=(AutoFree& o) throw() {
|
||||||
|
release(); _p=o.release(); return *this;
|
||||||
|
}
|
||||||
|
operator T*() {return _p;}
|
||||||
|
operator T**() {return &_p;}
|
||||||
|
operator bool() {return _p;}
|
||||||
|
T* release() throw() {T* r(_p); _p=0; return r;}
|
||||||
|
private:
|
||||||
|
T* _p;
|
||||||
|
};
|
||||||
|
//@}
|
||||||
|
}
|
||||||
|
#endif
|
46
mrw/auto_test.cpp
Normal file
46
mrw/auto_test.cpp
Normal file
@@ -0,0 +1,46 @@
|
|||||||
|
#include <mrw/auto.hpp>
|
||||||
|
#include <cppunit/TestFixture.h>
|
||||||
|
#include <cppunit/ui/text/TestRunner.h>
|
||||||
|
#include <cppunit/extensions/HelperMacros.h>
|
||||||
|
#include <cppunit/extensions/TestFactoryRegistry.h>
|
||||||
|
#include <fcntl.h> // open
|
||||||
|
|
||||||
|
class AutoTest: public CppUnit::TestFixture {
|
||||||
|
public:
|
||||||
|
void AutoFile() {
|
||||||
|
char c(0);
|
||||||
|
int i(-1);
|
||||||
|
{
|
||||||
|
mrw::AutoFile a;
|
||||||
|
CPPUNIT_ASSERT(a==-1); // init as -1
|
||||||
|
i = a = open("test.dat", O_RDONLY);
|
||||||
|
CPPUNIT_ASSERT(i==a && a>0); // file is now open
|
||||||
|
mrw::AutoFile b(a);
|
||||||
|
CPPUNIT_ASSERT(a==-1 && i==b); // b has taken ownership
|
||||||
|
CPPUNIT_ASSERT(read(b, &c, 1)==1 && c=='H'); // file is good
|
||||||
|
mrw::AutoFile c(i);
|
||||||
|
CPPUNIT_ASSERT(i==b && b==c); // ooops, two owner!
|
||||||
|
c.release();
|
||||||
|
CPPUNIT_ASSERT(i==b && c==-1); // it's ok now
|
||||||
|
b = open("test.dat", O_RDONLY);
|
||||||
|
//close(i);
|
||||||
|
CPPUNIT_ASSERT(read(i, &c, 1)==-1); // old file is closed
|
||||||
|
i = b.reset();
|
||||||
|
CPPUNIT_ASSERT(read(i, &c, 1)==-1); // new file is closed
|
||||||
|
i = a = open("test.dat", O_RDONLY);
|
||||||
|
}
|
||||||
|
CPPUNIT_ASSERT(read(i, &c, 1)==-1); // file is closed now
|
||||||
|
}
|
||||||
|
CPPUNIT_TEST_SUITE(AutoTest);
|
||||||
|
CPPUNIT_TEST(AutoFile);
|
||||||
|
CPPUNIT_TEST_SUITE_END();
|
||||||
|
};
|
||||||
|
CPPUNIT_TEST_SUITE_REGISTRATION(AutoTest);
|
||||||
|
|
||||||
|
int main() {
|
||||||
|
CppUnit::TextUi::TestRunner runner;
|
||||||
|
runner.addTest(CppUnit::TestFactoryRegistry::getRegistry().makeTest());
|
||||||
|
return runner.run() ? 0 : 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
static char* c = new char[100];
|
41
mrw/autostacktracestderr.cpp
Normal file
41
mrw/autostacktracestderr.cpp
Normal file
@@ -0,0 +1,41 @@
|
|||||||
|
#include <mrw/stacktrace.hpp>
|
||||||
|
#include <mrw/exception.hpp>
|
||||||
|
#include <exception>
|
||||||
|
#include <iostream>
|
||||||
|
|
||||||
|
namespace mrw {
|
||||||
|
|
||||||
|
/// @todo integrate it into the distribution and document it
|
||||||
|
void unexpected() {
|
||||||
|
std::cerr<<"UNEXPECTED EXCEPTION: ----------------------------"<<std::endl;
|
||||||
|
try {
|
||||||
|
throw;
|
||||||
|
} catch (const mrw::exception& x) {
|
||||||
|
StackTrace::createSymtable();
|
||||||
|
std::cerr<<"---------- Reason:"<<std::endl
|
||||||
|
<<x.what()<<std::endl
|
||||||
|
<<"---------- Stack:"<<std::endl
|
||||||
|
<<x.stacktrace()<<std::endl;
|
||||||
|
} catch (const std::exception& x) {
|
||||||
|
std::cerr<<"---------- Reason:"<<std::endl
|
||||||
|
<<x.what()<<std::endl
|
||||||
|
<<"---------- Stack: **** not available ****"<<std::endl;
|
||||||
|
} catch (...) {
|
||||||
|
std::cerr<<"---------- Reason: **** not available ****"<<std::endl
|
||||||
|
<<"---------- Stack: **** not available ****"<<std::endl;
|
||||||
|
}
|
||||||
|
std::cerr<<"-------------------------------------------------"<<std::endl;
|
||||||
|
throw std::bad_exception();
|
||||||
|
}
|
||||||
|
|
||||||
|
class AutoStackTrace {
|
||||||
|
public:
|
||||||
|
AutoStackTrace() {
|
||||||
|
std::set_unexpected(&mrw::unexpected);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
// initialize stack traces (load symbols)
|
||||||
|
static AutoStackTrace _autoStackTrace;
|
||||||
|
|
||||||
|
}
|
1101
mrw/doxyfile.in
Normal file
1101
mrw/doxyfile.in
Normal file
@@ -0,0 +1,1101 @@
|
|||||||
|
# Doxyfile 1.3.2
|
||||||
|
|
||||||
|
# This file describes the settings to be used by the documentation system
|
||||||
|
# doxygen (www.doxygen.org) for a project
|
||||||
|
#
|
||||||
|
# All text after a hash (#) is considered a comment and will be ignored
|
||||||
|
# The format is:
|
||||||
|
# TAG = value [value, ...]
|
||||||
|
# For lists items can also be appended using:
|
||||||
|
# TAG += value [value, ...]
|
||||||
|
# Values that contain spaces should be placed between quotes (" ")
|
||||||
|
|
||||||
|
#---------------------------------------------------------------------------
|
||||||
|
# General configuration options
|
||||||
|
#---------------------------------------------------------------------------
|
||||||
|
|
||||||
|
# The PROJECT_NAME tag is a single word (or a sequence of words surrounded
|
||||||
|
# by quotes) that should identify the project.
|
||||||
|
|
||||||
|
PROJECT_NAME = "MRW C++ Library"
|
||||||
|
|
||||||
|
# The PROJECT_NUMBER tag can be used to enter a project or revision number.
|
||||||
|
# This could be handy for archiving the generated documentation or
|
||||||
|
# if some version control system is used.
|
||||||
|
|
||||||
|
PROJECT_NUMBER = experimental
|
||||||
|
|
||||||
|
# The OUTPUT_DIRECTORY tag is used to specify the (relative or absolute)
|
||||||
|
# base path where the generated documentation will be put.
|
||||||
|
# If a relative path is entered, it will be relative to the location
|
||||||
|
# where doxygen was started. If left blank the current directory will be used.
|
||||||
|
|
||||||
|
OUTPUT_DIRECTORY = doc
|
||||||
|
|
||||||
|
# The OUTPUT_LANGUAGE tag is used to specify the language in which all
|
||||||
|
# documentation generated by doxygen is written. Doxygen will use this
|
||||||
|
# information to generate all constant output in the proper language.
|
||||||
|
# The default language is English, other supported languages are:
|
||||||
|
# Brazilian, Catalan, Chinese, Chinese-Traditional, Croatian, Czech, Danish, Dutch,
|
||||||
|
# Finnish, French, German, Greek, Hungarian, Italian, Japanese, Japanese-en
|
||||||
|
# (Japanese with English messages), Korean, Norwegian, Polish, Portuguese,
|
||||||
|
# Romanian, Russian, Serbian, Slovak, Slovene, Spanish, Swedish, and Ukrainian.
|
||||||
|
|
||||||
|
OUTPUT_LANGUAGE = English
|
||||||
|
|
||||||
|
# This tag can be used to specify the encoding used in the generated output.
|
||||||
|
# The encoding is not always determined by the language that is chosen,
|
||||||
|
# but also whether or not the output is meant for Windows or non-Windows users.
|
||||||
|
# In case there is a difference, setting the USE_WINDOWS_ENCODING tag to YES
|
||||||
|
# forces the Windows encoding (this is the default for the Windows binary),
|
||||||
|
# whereas setting the tag to NO uses a Unix-style encoding (the default for
|
||||||
|
# all platforms other than Windows).
|
||||||
|
|
||||||
|
USE_WINDOWS_ENCODING = NO
|
||||||
|
|
||||||
|
# If the EXTRACT_ALL tag is set to YES doxygen will assume all entities in
|
||||||
|
# documentation are documented, even if no documentation was available.
|
||||||
|
# Private class members and static file members will be hidden unless
|
||||||
|
# the EXTRACT_PRIVATE and EXTRACT_STATIC tags are set to YES
|
||||||
|
|
||||||
|
EXTRACT_ALL = NO
|
||||||
|
|
||||||
|
# If the EXTRACT_PRIVATE tag is set to YES all private members of a class
|
||||||
|
# will be included in the documentation.
|
||||||
|
|
||||||
|
EXTRACT_PRIVATE = NO
|
||||||
|
|
||||||
|
# If the EXTRACT_STATIC tag is set to YES all static members of a file
|
||||||
|
# will be included in the documentation.
|
||||||
|
|
||||||
|
EXTRACT_STATIC = NO
|
||||||
|
|
||||||
|
# If the EXTRACT_LOCAL_CLASSES tag is set to YES classes (and structs)
|
||||||
|
# defined locally in source files will be included in the documentation.
|
||||||
|
# If set to NO only classes defined in header files are included.
|
||||||
|
|
||||||
|
EXTRACT_LOCAL_CLASSES = NO
|
||||||
|
|
||||||
|
# If the HIDE_UNDOC_MEMBERS tag is set to YES, Doxygen will hide all
|
||||||
|
# undocumented members of documented classes, files or namespaces.
|
||||||
|
# If set to NO (the default) these members will be included in the
|
||||||
|
# various overviews, but no documentation section is generated.
|
||||||
|
# This option has no effect if EXTRACT_ALL is enabled.
|
||||||
|
|
||||||
|
HIDE_UNDOC_MEMBERS = NO
|
||||||
|
|
||||||
|
# If the HIDE_UNDOC_CLASSES tag is set to YES, Doxygen will hide all
|
||||||
|
# undocumented classes that are normally visible in the class hierarchy.
|
||||||
|
# If set to NO (the default) these classes will be included in the various
|
||||||
|
# overviews. This option has no effect if EXTRACT_ALL is enabled.
|
||||||
|
|
||||||
|
HIDE_UNDOC_CLASSES = NO
|
||||||
|
|
||||||
|
# If the HIDE_FRIEND_COMPOUNDS tag is set to YES, Doxygen will hide all
|
||||||
|
# friend (class|struct|union) declarations.
|
||||||
|
# If set to NO (the default) these declarations will be included in the
|
||||||
|
# documentation.
|
||||||
|
|
||||||
|
HIDE_FRIEND_COMPOUNDS = NO
|
||||||
|
|
||||||
|
# If the HIDE_IN_BODY_DOCS tag is set to YES, Doxygen will hide any
|
||||||
|
# documentation blocks found inside the body of a function.
|
||||||
|
# If set to NO (the default) these blocks will be appended to the
|
||||||
|
# function's detailed documentation block.
|
||||||
|
|
||||||
|
HIDE_IN_BODY_DOCS = NO
|
||||||
|
|
||||||
|
# If the BRIEF_MEMBER_DESC tag is set to YES (the default) Doxygen will
|
||||||
|
# include brief member descriptions after the members that are listed in
|
||||||
|
# the file and class documentation (similar to JavaDoc).
|
||||||
|
# Set to NO to disable this.
|
||||||
|
|
||||||
|
BRIEF_MEMBER_DESC = YES
|
||||||
|
|
||||||
|
# If the REPEAT_BRIEF tag is set to YES (the default) Doxygen will prepend
|
||||||
|
# the brief description of a member or function before the detailed description.
|
||||||
|
# Note: if both HIDE_UNDOC_MEMBERS and BRIEF_MEMBER_DESC are set to NO, the
|
||||||
|
# brief descriptions will be completely suppressed.
|
||||||
|
|
||||||
|
REPEAT_BRIEF = YES
|
||||||
|
|
||||||
|
# If the ALWAYS_DETAILED_SEC and REPEAT_BRIEF tags are both set to YES then
|
||||||
|
# Doxygen will generate a detailed section even if there is only a brief
|
||||||
|
# description.
|
||||||
|
|
||||||
|
ALWAYS_DETAILED_SEC = NO
|
||||||
|
|
||||||
|
# If the INLINE_INHERITED_MEMB tag is set to YES, doxygen will show all inherited
|
||||||
|
# members of a class in the documentation of that class as if those members were
|
||||||
|
# ordinary class members. Constructors, destructors and assignment operators of
|
||||||
|
# the base classes will not be shown.
|
||||||
|
|
||||||
|
INLINE_INHERITED_MEMB = NO
|
||||||
|
|
||||||
|
# If the FULL_PATH_NAMES tag is set to YES then Doxygen will prepend the full
|
||||||
|
# path before files name in the file list and in the header files. If set
|
||||||
|
# to NO the shortest path that makes the file name unique will be used.
|
||||||
|
|
||||||
|
FULL_PATH_NAMES = YES
|
||||||
|
|
||||||
|
# If the FULL_PATH_NAMES tag is set to YES then the STRIP_FROM_PATH tag
|
||||||
|
# can be used to strip a user-defined part of the path. Stripping is
|
||||||
|
# only done if one of the specified strings matches the left-hand part of
|
||||||
|
# the path. It is allowed to use relative paths in the argument list.
|
||||||
|
|
||||||
|
STRIP_FROM_PATH = ../
|
||||||
|
|
||||||
|
# The INTERNAL_DOCS tag determines if documentation
|
||||||
|
# that is typed after a \internal command is included. If the tag is set
|
||||||
|
# to NO (the default) then the documentation will be excluded.
|
||||||
|
# Set it to YES to include the internal documentation.
|
||||||
|
|
||||||
|
INTERNAL_DOCS = NO
|
||||||
|
|
||||||
|
# If the CASE_SENSE_NAMES tag is set to NO then Doxygen will only generate
|
||||||
|
# file names in lower-case letters. If set to YES upper-case letters are also
|
||||||
|
# allowed. This is useful if you have classes or files whose names only differ
|
||||||
|
# in case and if your file system supports case sensitive file names. Windows
|
||||||
|
# users are advised to set this option to NO.
|
||||||
|
|
||||||
|
CASE_SENSE_NAMES = YES
|
||||||
|
|
||||||
|
# If the SHORT_NAMES tag is set to YES, doxygen will generate much shorter
|
||||||
|
# (but less readable) file names. This can be useful is your file systems
|
||||||
|
# doesn't support long names like on DOS, Mac, or CD-ROM.
|
||||||
|
|
||||||
|
SHORT_NAMES = NO
|
||||||
|
|
||||||
|
# If the HIDE_SCOPE_NAMES tag is set to NO (the default) then Doxygen
|
||||||
|
# will show members with their full class and namespace scopes in the
|
||||||
|
# documentation. If set to YES the scope will be hidden.
|
||||||
|
|
||||||
|
HIDE_SCOPE_NAMES = NO
|
||||||
|
|
||||||
|
# If the SHOW_INCLUDE_FILES tag is set to YES (the default) then Doxygen
|
||||||
|
# will put a list of the files that are included by a file in the documentation
|
||||||
|
# of that file.
|
||||||
|
|
||||||
|
SHOW_INCLUDE_FILES = YES
|
||||||
|
|
||||||
|
# If the JAVADOC_AUTOBRIEF tag is set to YES then Doxygen
|
||||||
|
# will interpret the first line (until the first dot) of a JavaDoc-style
|
||||||
|
# comment as the brief description. If set to NO, the JavaDoc
|
||||||
|
# comments will behave just like the Qt-style comments (thus requiring an
|
||||||
|
# explict @brief command for a brief description.
|
||||||
|
|
||||||
|
JAVADOC_AUTOBRIEF = NO
|
||||||
|
|
||||||
|
# The MULTILINE_CPP_IS_BRIEF tag can be set to YES to make Doxygen
|
||||||
|
# treat a multi-line C++ special comment block (i.e. a block of //! or ///
|
||||||
|
# comments) as a brief description. This used to be the default behaviour.
|
||||||
|
# The new default is to treat a multi-line C++ comment block as a detailed
|
||||||
|
# description. Set this tag to YES if you prefer the old behaviour instead.
|
||||||
|
|
||||||
|
MULTILINE_CPP_IS_BRIEF = NO
|
||||||
|
|
||||||
|
# If the DETAILS_AT_TOP tag is set to YES then Doxygen
|
||||||
|
# will output the detailed description near the top, like JavaDoc.
|
||||||
|
# If set to NO, the detailed description appears after the member
|
||||||
|
# documentation.
|
||||||
|
|
||||||
|
DETAILS_AT_TOP = YES
|
||||||
|
|
||||||
|
# If the INHERIT_DOCS tag is set to YES (the default) then an undocumented
|
||||||
|
# member inherits the documentation from any documented member that it
|
||||||
|
# reimplements.
|
||||||
|
|
||||||
|
INHERIT_DOCS = YES
|
||||||
|
|
||||||
|
# If the INLINE_INFO tag is set to YES (the default) then a tag [inline]
|
||||||
|
# is inserted in the documentation for inline members.
|
||||||
|
|
||||||
|
INLINE_INFO = YES
|
||||||
|
|
||||||
|
# If the SORT_MEMBER_DOCS tag is set to YES (the default) then doxygen
|
||||||
|
# will sort the (detailed) documentation of file and class members
|
||||||
|
# alphabetically by member name. If set to NO the members will appear in
|
||||||
|
# declaration order.
|
||||||
|
|
||||||
|
SORT_MEMBER_DOCS = YES
|
||||||
|
|
||||||
|
# If member grouping is used in the documentation and the DISTRIBUTE_GROUP_DOC
|
||||||
|
# tag is set to YES, then doxygen will reuse the documentation of the first
|
||||||
|
# member in the group (if any) for the other members of the group. By default
|
||||||
|
# all members of a group must be documented explicitly.
|
||||||
|
|
||||||
|
DISTRIBUTE_GROUP_DOC = NO
|
||||||
|
|
||||||
|
# The TAB_SIZE tag can be used to set the number of spaces in a tab.
|
||||||
|
# Doxygen uses this value to replace tabs by spaces in code fragments.
|
||||||
|
|
||||||
|
TAB_SIZE = 8
|
||||||
|
|
||||||
|
# The GENERATE_TODOLIST tag can be used to enable (YES) or
|
||||||
|
# disable (NO) the todo list. This list is created by putting \todo
|
||||||
|
# commands in the documentation.
|
||||||
|
|
||||||
|
GENERATE_TODOLIST = YES
|
||||||
|
|
||||||
|
# The GENERATE_TESTLIST tag can be used to enable (YES) or
|
||||||
|
# disable (NO) the test list. This list is created by putting \test
|
||||||
|
# commands in the documentation.
|
||||||
|
|
||||||
|
GENERATE_TESTLIST = YES
|
||||||
|
|
||||||
|
# The GENERATE_BUGLIST tag can be used to enable (YES) or
|
||||||
|
# disable (NO) the bug list. This list is created by putting \bug
|
||||||
|
# commands in the documentation.
|
||||||
|
|
||||||
|
GENERATE_BUGLIST = YES
|
||||||
|
|
||||||
|
# The GENERATE_DEPRECATEDLIST tag can be used to enable (YES) or
|
||||||
|
# disable (NO) the deprecated list. This list is created by putting
|
||||||
|
# \deprecated commands in the documentation.
|
||||||
|
|
||||||
|
GENERATE_DEPRECATEDLIST= YES
|
||||||
|
|
||||||
|
# This tag can be used to specify a number of aliases that acts
|
||||||
|
# as commands in the documentation. An alias has the form "name=value".
|
||||||
|
# For example adding "sideeffect=\par Side Effects:\n" will allow you to
|
||||||
|
# put the command \sideeffect (or @sideeffect) in the documentation, which
|
||||||
|
# will result in a user-defined paragraph with heading "Side Effects:".
|
||||||
|
# You can put \n's in the value part of an alias to insert newlines.
|
||||||
|
|
||||||
|
ALIASES =
|
||||||
|
|
||||||
|
# The ENABLED_SECTIONS tag can be used to enable conditional
|
||||||
|
# documentation sections, marked by \if sectionname ... \endif.
|
||||||
|
|
||||||
|
ENABLED_SECTIONS =
|
||||||
|
|
||||||
|
# The MAX_INITIALIZER_LINES tag determines the maximum number of lines
|
||||||
|
# the initial value of a variable or define consists of for it to appear in
|
||||||
|
# the documentation. If the initializer consists of more lines than specified
|
||||||
|
# here it will be hidden. Use a value of 0 to hide initializers completely.
|
||||||
|
# The appearance of the initializer of individual variables and defines in the
|
||||||
|
# documentation can be controlled using \showinitializer or \hideinitializer
|
||||||
|
# command in the documentation regardless of this setting.
|
||||||
|
|
||||||
|
MAX_INITIALIZER_LINES = 30
|
||||||
|
|
||||||
|
# Set the OPTIMIZE_OUTPUT_FOR_C tag to YES if your project consists of C sources
|
||||||
|
# only. Doxygen will then generate output that is more tailored for C.
|
||||||
|
# For instance, some of the names that are used will be different. The list
|
||||||
|
# of all members will be omitted, etc.
|
||||||
|
|
||||||
|
OPTIMIZE_OUTPUT_FOR_C = NO
|
||||||
|
|
||||||
|
# Set the OPTIMIZE_OUTPUT_JAVA tag to YES if your project consists of Java sources
|
||||||
|
# only. Doxygen will then generate output that is more tailored for Java.
|
||||||
|
# For instance, namespaces will be presented as packages, qualified scopes
|
||||||
|
# will look different, etc.
|
||||||
|
|
||||||
|
OPTIMIZE_OUTPUT_JAVA = NO
|
||||||
|
|
||||||
|
# Set the SHOW_USED_FILES tag to NO to disable the list of files generated
|
||||||
|
# at the bottom of the documentation of classes and structs. If set to YES the
|
||||||
|
# list will mention the files that were used to generate the documentation.
|
||||||
|
|
||||||
|
SHOW_USED_FILES = YES
|
||||||
|
|
||||||
|
#---------------------------------------------------------------------------
|
||||||
|
# configuration options related to warning and progress messages
|
||||||
|
#---------------------------------------------------------------------------
|
||||||
|
|
||||||
|
# The QUIET tag can be used to turn on/off the messages that are generated
|
||||||
|
# by doxygen. Possible values are YES and NO. If left blank NO is used.
|
||||||
|
|
||||||
|
QUIET = NO
|
||||||
|
|
||||||
|
# The WARNINGS tag can be used to turn on/off the warning messages that are
|
||||||
|
# generated by doxygen. Possible values are YES and NO. If left blank
|
||||||
|
# NO is used.
|
||||||
|
|
||||||
|
WARNINGS = YES
|
||||||
|
|
||||||
|
# If WARN_IF_UNDOCUMENTED is set to YES, then doxygen will generate warnings
|
||||||
|
# for undocumented members. If EXTRACT_ALL is set to YES then this flag will
|
||||||
|
# automatically be disabled.
|
||||||
|
|
||||||
|
WARN_IF_UNDOCUMENTED = NO
|
||||||
|
|
||||||
|
# If WARN_IF_DOC_ERROR is set to YES, doxygen will generate warnings for
|
||||||
|
# potential errors in the documentation, such as not documenting some
|
||||||
|
# parameters in a documented function, or documenting parameters that
|
||||||
|
# don't exist or using markup commands wrongly.
|
||||||
|
|
||||||
|
WARN_IF_DOC_ERROR = YES
|
||||||
|
|
||||||
|
# The WARN_FORMAT tag determines the format of the warning messages that
|
||||||
|
# doxygen can produce. The string should contain the $file, $line, and $text
|
||||||
|
# tags, which will be replaced by the file and line number from which the
|
||||||
|
# warning originated and the warning text.
|
||||||
|
|
||||||
|
WARN_FORMAT = "$file:$line: $text"
|
||||||
|
|
||||||
|
# The WARN_LOGFILE tag can be used to specify a file to which warning
|
||||||
|
# and error messages should be written. If left blank the output is written
|
||||||
|
# to stderr.
|
||||||
|
|
||||||
|
WARN_LOGFILE = doxygen.errors
|
||||||
|
|
||||||
|
#---------------------------------------------------------------------------
|
||||||
|
# configuration options related to the input files
|
||||||
|
#---------------------------------------------------------------------------
|
||||||
|
|
||||||
|
# The INPUT tag can be used to specify the files and/or directories that contain
|
||||||
|
# documented source files. You may enter file names like "myfile.cpp" or
|
||||||
|
# directories like "/usr/src/myproject". Separate the files or directories
|
||||||
|
# with spaces.
|
||||||
|
|
||||||
|
INPUT = ../mrw
|
||||||
|
|
||||||
|
# If the value of the INPUT tag contains directories, you can use the
|
||||||
|
# FILE_PATTERNS tag to specify one or more wildcard pattern (like *.cpp
|
||||||
|
# and *.h) to filter out the source-files in the directories. If left
|
||||||
|
# blank the following patterns are tested:
|
||||||
|
# *.c *.cc *.cxx *.cpp *.c++ *.java *.ii *.ixx *.ipp *.i++ *.inl *.h *.hh *.hxx *.hpp
|
||||||
|
# *.h++ *.idl *.odl *.cs
|
||||||
|
|
||||||
|
FILE_PATTERNS =
|
||||||
|
|
||||||
|
# The RECURSIVE tag can be used to turn specify whether or not subdirectories
|
||||||
|
# should be searched for input files as well. Possible values are YES and NO.
|
||||||
|
# If left blank NO is used.
|
||||||
|
|
||||||
|
RECURSIVE = NO
|
||||||
|
|
||||||
|
# The EXCLUDE tag can be used to specify files and/or directories that should
|
||||||
|
# excluded from the INPUT source files. This way you can easily exclude a
|
||||||
|
# subdirectory from a directory tree whose root is specified with the INPUT tag.
|
||||||
|
|
||||||
|
EXCLUDE =
|
||||||
|
|
||||||
|
# The EXCLUDE_SYMLINKS tag can be used select whether or not files or directories
|
||||||
|
# that are symbolic links (a Unix filesystem feature) are excluded from the input.
|
||||||
|
|
||||||
|
EXCLUDE_SYMLINKS = NO
|
||||||
|
|
||||||
|
# If the value of the INPUT tag contains directories, you can use the
|
||||||
|
# EXCLUDE_PATTERNS tag to specify one or more wildcard patterns to exclude
|
||||||
|
# certain files from those directories.
|
||||||
|
|
||||||
|
EXCLUDE_PATTERNS =
|
||||||
|
|
||||||
|
# The EXAMPLE_PATH tag can be used to specify one or more files or
|
||||||
|
# directories that contain example code fragments that are included (see
|
||||||
|
# the \include command).
|
||||||
|
|
||||||
|
EXAMPLE_PATH = examples
|
||||||
|
|
||||||
|
# If the value of the EXAMPLE_PATH tag contains directories, you can use the
|
||||||
|
# EXAMPLE_PATTERNS tag to specify one or more wildcard pattern (like *.cpp
|
||||||
|
# and *.h) to filter out the source-files in the directories. If left
|
||||||
|
# blank all files are included.
|
||||||
|
|
||||||
|
EXAMPLE_PATTERNS =
|
||||||
|
|
||||||
|
# If the EXAMPLE_RECURSIVE tag is set to YES then subdirectories will be
|
||||||
|
# searched for input files to be used with the \include or \dontinclude
|
||||||
|
# commands irrespective of the value of the RECURSIVE tag.
|
||||||
|
# Possible values are YES and NO. If left blank NO is used.
|
||||||
|
|
||||||
|
EXAMPLE_RECURSIVE = NO
|
||||||
|
|
||||||
|
# The IMAGE_PATH tag can be used to specify one or more files or
|
||||||
|
# directories that contain image that are included in the documentation (see
|
||||||
|
# the \image command).
|
||||||
|
|
||||||
|
IMAGE_PATH =
|
||||||
|
|
||||||
|
# The INPUT_FILTER tag can be used to specify a program that doxygen should
|
||||||
|
# invoke to filter for each input file. Doxygen will invoke the filter program
|
||||||
|
# by executing (via popen()) the command <filter> <input-file>, where <filter>
|
||||||
|
# is the value of the INPUT_FILTER tag, and <input-file> is the name of an
|
||||||
|
# input file. Doxygen will then use the output that the filter program writes
|
||||||
|
# to standard output.
|
||||||
|
|
||||||
|
INPUT_FILTER =
|
||||||
|
|
||||||
|
# If the FILTER_SOURCE_FILES tag is set to YES, the input filter (if set using
|
||||||
|
# INPUT_FILTER) will be used to filter the input files when producing source
|
||||||
|
# files to browse (i.e. when SOURCE_BROWSER is set to YES).
|
||||||
|
|
||||||
|
FILTER_SOURCE_FILES = NO
|
||||||
|
|
||||||
|
#---------------------------------------------------------------------------
|
||||||
|
# configuration options related to source browsing
|
||||||
|
#---------------------------------------------------------------------------
|
||||||
|
|
||||||
|
# If the SOURCE_BROWSER tag is set to YES then a list of source files will
|
||||||
|
# be generated. Documented entities will be cross-referenced with these sources.
|
||||||
|
|
||||||
|
SOURCE_BROWSER = NO
|
||||||
|
|
||||||
|
# Setting the INLINE_SOURCES tag to YES will include the body
|
||||||
|
# of functions and classes directly in the documentation.
|
||||||
|
|
||||||
|
INLINE_SOURCES = NO
|
||||||
|
|
||||||
|
# Setting the STRIP_CODE_COMMENTS tag to YES (the default) will instruct
|
||||||
|
# doxygen to hide any special comment blocks from generated source code
|
||||||
|
# fragments. Normal C and C++ comments will always remain visible.
|
||||||
|
|
||||||
|
STRIP_CODE_COMMENTS = YES
|
||||||
|
|
||||||
|
# If the REFERENCED_BY_RELATION tag is set to YES (the default)
|
||||||
|
# then for each documented function all documented
|
||||||
|
# functions referencing it will be listed.
|
||||||
|
|
||||||
|
REFERENCED_BY_RELATION = YES
|
||||||
|
|
||||||
|
# If the REFERENCES_RELATION tag is set to YES (the default)
|
||||||
|
# then for each documented function all documented entities
|
||||||
|
# called/used by that function will be listed.
|
||||||
|
|
||||||
|
REFERENCES_RELATION = YES
|
||||||
|
|
||||||
|
# If the VERBATIM_HEADERS tag is set to YES (the default) then Doxygen
|
||||||
|
# will generate a verbatim copy of the header file for each class for
|
||||||
|
# which an include is specified. Set to NO to disable this.
|
||||||
|
|
||||||
|
VERBATIM_HEADERS = YES
|
||||||
|
|
||||||
|
#---------------------------------------------------------------------------
|
||||||
|
# configuration options related to the alphabetical class index
|
||||||
|
#---------------------------------------------------------------------------
|
||||||
|
|
||||||
|
# If the ALPHABETICAL_INDEX tag is set to YES, an alphabetical index
|
||||||
|
# of all compounds will be generated. Enable this if the project
|
||||||
|
# contains a lot of classes, structs, unions or interfaces.
|
||||||
|
|
||||||
|
ALPHABETICAL_INDEX = YES
|
||||||
|
|
||||||
|
# If the alphabetical index is enabled (see ALPHABETICAL_INDEX) then
|
||||||
|
# the COLS_IN_ALPHA_INDEX tag can be used to specify the number of columns
|
||||||
|
# in which this list will be split (can be a number in the range [1..20])
|
||||||
|
|
||||||
|
COLS_IN_ALPHA_INDEX = 5
|
||||||
|
|
||||||
|
# In case all classes in a project start with a common prefix, all
|
||||||
|
# classes will be put under the same header in the alphabetical index.
|
||||||
|
# The IGNORE_PREFIX tag can be used to specify one or more prefixes that
|
||||||
|
# should be ignored while generating the index headers.
|
||||||
|
|
||||||
|
IGNORE_PREFIX =
|
||||||
|
|
||||||
|
#---------------------------------------------------------------------------
|
||||||
|
# configuration options related to the HTML output
|
||||||
|
#---------------------------------------------------------------------------
|
||||||
|
|
||||||
|
# If the GENERATE_HTML tag is set to YES (the default) Doxygen will
|
||||||
|
# generate HTML output.
|
||||||
|
|
||||||
|
GENERATE_HTML = YES
|
||||||
|
|
||||||
|
# The HTML_OUTPUT tag is used to specify where the HTML docs will be put.
|
||||||
|
# If a relative path is entered the value of OUTPUT_DIRECTORY will be
|
||||||
|
# put in front of it. If left blank `html' will be used as the default path.
|
||||||
|
|
||||||
|
HTML_OUTPUT = html
|
||||||
|
|
||||||
|
# The HTML_FILE_EXTENSION tag can be used to specify the file extension for
|
||||||
|
# each generated HTML page (for example: .htm,.php,.asp). If it is left blank
|
||||||
|
# doxygen will generate files with .html extension.
|
||||||
|
|
||||||
|
HTML_FILE_EXTENSION = .html
|
||||||
|
|
||||||
|
# The HTML_HEADER tag can be used to specify a personal HTML header for
|
||||||
|
# each generated HTML page. If it is left blank doxygen will generate a
|
||||||
|
# standard header.
|
||||||
|
|
||||||
|
HTML_HEADER =
|
||||||
|
|
||||||
|
# The HTML_FOOTER tag can be used to specify a personal HTML footer for
|
||||||
|
# each generated HTML page. If it is left blank doxygen will generate a
|
||||||
|
# standard footer.
|
||||||
|
|
||||||
|
HTML_FOOTER =
|
||||||
|
|
||||||
|
# The HTML_STYLESHEET tag can be used to specify a user-defined cascading
|
||||||
|
# style sheet that is used by each HTML page. It can be used to
|
||||||
|
# fine-tune the look of the HTML output. If the tag is left blank doxygen
|
||||||
|
# will generate a default style sheet
|
||||||
|
|
||||||
|
HTML_STYLESHEET =
|
||||||
|
|
||||||
|
# If the HTML_ALIGN_MEMBERS tag is set to YES, the members of classes,
|
||||||
|
# files or namespaces will be aligned in HTML using tables. If set to
|
||||||
|
# NO a bullet list will be used.
|
||||||
|
|
||||||
|
HTML_ALIGN_MEMBERS = YES
|
||||||
|
|
||||||
|
# If the GENERATE_HTMLHELP tag is set to YES, additional index files
|
||||||
|
# will be generated that can be used as input for tools like the
|
||||||
|
# Microsoft HTML help workshop to generate a compressed HTML help file (.chm)
|
||||||
|
# of the generated HTML documentation.
|
||||||
|
|
||||||
|
GENERATE_HTMLHELP = NO
|
||||||
|
|
||||||
|
# If the GENERATE_HTMLHELP tag is set to YES, the CHM_FILE tag can
|
||||||
|
# be used to specify the file name of the resulting .chm file. You
|
||||||
|
# can add a path in front of the file if the result should not be
|
||||||
|
# written to the html output dir.
|
||||||
|
|
||||||
|
CHM_FILE =
|
||||||
|
|
||||||
|
# If the GENERATE_HTMLHELP tag is set to YES, the HHC_LOCATION tag can
|
||||||
|
# be used to specify the location (absolute path including file name) of
|
||||||
|
# the HTML help compiler (hhc.exe). If non-empty doxygen will try to run
|
||||||
|
# the HTML help compiler on the generated index.hhp.
|
||||||
|
|
||||||
|
HHC_LOCATION =
|
||||||
|
|
||||||
|
# If the GENERATE_HTMLHELP tag is set to YES, the GENERATE_CHI flag
|
||||||
|
# controls if a separate .chi index file is generated (YES) or that
|
||||||
|
# it should be included in the master .chm file (NO).
|
||||||
|
|
||||||
|
GENERATE_CHI = NO
|
||||||
|
|
||||||
|
# If the GENERATE_HTMLHELP tag is set to YES, the BINARY_TOC flag
|
||||||
|
# controls whether a binary table of contents is generated (YES) or a
|
||||||
|
# normal table of contents (NO) in the .chm file.
|
||||||
|
|
||||||
|
BINARY_TOC = NO
|
||||||
|
|
||||||
|
# The TOC_EXPAND flag can be set to YES to add extra items for group members
|
||||||
|
# to the contents of the HTML help documentation and to the tree view.
|
||||||
|
|
||||||
|
TOC_EXPAND = NO
|
||||||
|
|
||||||
|
# The DISABLE_INDEX tag can be used to turn on/off the condensed index at
|
||||||
|
# top of each HTML page. The value NO (the default) enables the index and
|
||||||
|
# the value YES disables it.
|
||||||
|
|
||||||
|
DISABLE_INDEX = NO
|
||||||
|
|
||||||
|
# This tag can be used to set the number of enum values (range [1..20])
|
||||||
|
# that doxygen will group on one line in the generated HTML documentation.
|
||||||
|
|
||||||
|
ENUM_VALUES_PER_LINE = 4
|
||||||
|
|
||||||
|
# If the GENERATE_TREEVIEW tag is set to YES, a side panel will be
|
||||||
|
# generated containing a tree-like index structure (just like the one that
|
||||||
|
# is generated for HTML Help). For this to work a browser that supports
|
||||||
|
# JavaScript, DHTML, CSS and frames is required (for instance Mozilla 1.0+,
|
||||||
|
# Netscape 6.0+, Internet explorer 5.0+, or Konqueror). Windows users are
|
||||||
|
# probably better off using the HTML help feature.
|
||||||
|
|
||||||
|
GENERATE_TREEVIEW = NO
|
||||||
|
|
||||||
|
# If the treeview is enabled (see GENERATE_TREEVIEW) then this tag can be
|
||||||
|
# used to set the initial width (in pixels) of the frame in which the tree
|
||||||
|
# is shown.
|
||||||
|
|
||||||
|
TREEVIEW_WIDTH = 250
|
||||||
|
|
||||||
|
#---------------------------------------------------------------------------
|
||||||
|
# configuration options related to the LaTeX output
|
||||||
|
#---------------------------------------------------------------------------
|
||||||
|
|
||||||
|
# If the GENERATE_LATEX tag is set to YES (the default) Doxygen will
|
||||||
|
# generate Latex output.
|
||||||
|
|
||||||
|
GENERATE_LATEX = NO
|
||||||
|
|
||||||
|
# The LATEX_OUTPUT tag is used to specify where the LaTeX docs will be put.
|
||||||
|
# If a relative path is entered the value of OUTPUT_DIRECTORY will be
|
||||||
|
# put in front of it. If left blank `latex' will be used as the default path.
|
||||||
|
|
||||||
|
LATEX_OUTPUT = latex
|
||||||
|
|
||||||
|
# The LATEX_CMD_NAME tag can be used to specify the LaTeX command name to be
|
||||||
|
# invoked. If left blank `latex' will be used as the default command name.
|
||||||
|
|
||||||
|
LATEX_CMD_NAME = latex
|
||||||
|
|
||||||
|
# The MAKEINDEX_CMD_NAME tag can be used to specify the command name to
|
||||||
|
# generate index for LaTeX. If left blank `makeindex' will be used as the
|
||||||
|
# default command name.
|
||||||
|
|
||||||
|
MAKEINDEX_CMD_NAME = makeindex
|
||||||
|
|
||||||
|
# If the COMPACT_LATEX tag is set to YES Doxygen generates more compact
|
||||||
|
# LaTeX documents. This may be useful for small projects and may help to
|
||||||
|
# save some trees in general.
|
||||||
|
|
||||||
|
COMPACT_LATEX = NO
|
||||||
|
|
||||||
|
# The PAPER_TYPE tag can be used to set the paper type that is used
|
||||||
|
# by the printer. Possible values are: a4, a4wide, letter, legal and
|
||||||
|
# executive. If left blank a4wide will be used.
|
||||||
|
|
||||||
|
PAPER_TYPE = a4wide
|
||||||
|
|
||||||
|
# The EXTRA_PACKAGES tag can be to specify one or more names of LaTeX
|
||||||
|
# packages that should be included in the LaTeX output.
|
||||||
|
|
||||||
|
EXTRA_PACKAGES =
|
||||||
|
|
||||||
|
# The LATEX_HEADER tag can be used to specify a personal LaTeX header for
|
||||||
|
# the generated latex document. The header should contain everything until
|
||||||
|
# the first chapter. If it is left blank doxygen will generate a
|
||||||
|
# standard header. Notice: only use this tag if you know what you are doing!
|
||||||
|
|
||||||
|
LATEX_HEADER =
|
||||||
|
|
||||||
|
# If the PDF_HYPERLINKS tag is set to YES, the LaTeX that is generated
|
||||||
|
# is prepared for conversion to pdf (using ps2pdf). The pdf file will
|
||||||
|
# contain links (just like the HTML output) instead of page references
|
||||||
|
# This makes the output suitable for online browsing using a pdf viewer.
|
||||||
|
|
||||||
|
PDF_HYPERLINKS = NO
|
||||||
|
|
||||||
|
# If the USE_PDFLATEX tag is set to YES, pdflatex will be used instead of
|
||||||
|
# plain latex in the generated Makefile. Set this option to YES to get a
|
||||||
|
# higher quality PDF documentation.
|
||||||
|
|
||||||
|
USE_PDFLATEX = NO
|
||||||
|
|
||||||
|
# If the LATEX_BATCHMODE tag is set to YES, doxygen will add the \\batchmode.
|
||||||
|
# command to the generated LaTeX files. This will instruct LaTeX to keep
|
||||||
|
# running if errors occur, instead of asking the user for help.
|
||||||
|
# This option is also used when generating formulas in HTML.
|
||||||
|
|
||||||
|
LATEX_BATCHMODE = NO
|
||||||
|
|
||||||
|
# If LATEX_HIDE_INDICES is set to YES then doxygen will not
|
||||||
|
# include the index chapters (such as File Index, Compound Index, etc.)
|
||||||
|
# in the output.
|
||||||
|
|
||||||
|
LATEX_HIDE_INDICES = NO
|
||||||
|
|
||||||
|
#---------------------------------------------------------------------------
|
||||||
|
# configuration options related to the RTF output
|
||||||
|
#---------------------------------------------------------------------------
|
||||||
|
|
||||||
|
# If the GENERATE_RTF tag is set to YES Doxygen will generate RTF output
|
||||||
|
# The RTF output is optimised for Word 97 and may not look very pretty with
|
||||||
|
# other RTF readers or editors.
|
||||||
|
|
||||||
|
GENERATE_RTF = NO
|
||||||
|
|
||||||
|
# The RTF_OUTPUT tag is used to specify where the RTF docs will be put.
|
||||||
|
# If a relative path is entered the value of OUTPUT_DIRECTORY will be
|
||||||
|
# put in front of it. If left blank `rtf' will be used as the default path.
|
||||||
|
|
||||||
|
RTF_OUTPUT = rtf
|
||||||
|
|
||||||
|
# If the COMPACT_RTF tag is set to YES Doxygen generates more compact
|
||||||
|
# RTF documents. This may be useful for small projects and may help to
|
||||||
|
# save some trees in general.
|
||||||
|
|
||||||
|
COMPACT_RTF = NO
|
||||||
|
|
||||||
|
# If the RTF_HYPERLINKS tag is set to YES, the RTF that is generated
|
||||||
|
# will contain hyperlink fields. The RTF file will
|
||||||
|
# contain links (just like the HTML output) instead of page references.
|
||||||
|
# This makes the output suitable for online browsing using WORD or other
|
||||||
|
# programs which support those fields.
|
||||||
|
# Note: wordpad (write) and others do not support links.
|
||||||
|
|
||||||
|
RTF_HYPERLINKS = NO
|
||||||
|
|
||||||
|
# Load stylesheet definitions from file. Syntax is similar to doxygen's
|
||||||
|
# config file, i.e. a series of assigments. You only have to provide
|
||||||
|
# replacements, missing definitions are set to their default value.
|
||||||
|
|
||||||
|
RTF_STYLESHEET_FILE =
|
||||||
|
|
||||||
|
# Set optional variables used in the generation of an rtf document.
|
||||||
|
# Syntax is similar to doxygen's config file.
|
||||||
|
|
||||||
|
RTF_EXTENSIONS_FILE =
|
||||||
|
|
||||||
|
#---------------------------------------------------------------------------
|
||||||
|
# configuration options related to the man page output
|
||||||
|
#---------------------------------------------------------------------------
|
||||||
|
|
||||||
|
# If the GENERATE_MAN tag is set to YES (the default) Doxygen will
|
||||||
|
# generate man pages
|
||||||
|
|
||||||
|
GENERATE_MAN = NO
|
||||||
|
|
||||||
|
# The MAN_OUTPUT tag is used to specify where the man pages will be put.
|
||||||
|
# If a relative path is entered the value of OUTPUT_DIRECTORY will be
|
||||||
|
# put in front of it. If left blank `man' will be used as the default path.
|
||||||
|
|
||||||
|
MAN_OUTPUT = man
|
||||||
|
|
||||||
|
# The MAN_EXTENSION tag determines the extension that is added to
|
||||||
|
# the generated man pages (default is the subroutine's section .3)
|
||||||
|
|
||||||
|
MAN_EXTENSION = .3
|
||||||
|
|
||||||
|
# If the MAN_LINKS tag is set to YES and Doxygen generates man output,
|
||||||
|
# then it will generate one additional man file for each entity
|
||||||
|
# documented in the real man page(s). These additional files
|
||||||
|
# only source the real man page, but without them the man command
|
||||||
|
# would be unable to find the correct page. The default is NO.
|
||||||
|
|
||||||
|
MAN_LINKS = NO
|
||||||
|
|
||||||
|
#---------------------------------------------------------------------------
|
||||||
|
# configuration options related to the XML output
|
||||||
|
#---------------------------------------------------------------------------
|
||||||
|
|
||||||
|
# If the GENERATE_XML tag is set to YES Doxygen will
|
||||||
|
# generate an XML file that captures the structure of
|
||||||
|
# the code including all documentation. Note that this
|
||||||
|
# feature is still experimental and incomplete at the
|
||||||
|
# moment.
|
||||||
|
|
||||||
|
GENERATE_XML = NO
|
||||||
|
|
||||||
|
# The XML_OUTPUT tag is used to specify where the XML pages will be put.
|
||||||
|
# If a relative path is entered the value of OUTPUT_DIRECTORY will be
|
||||||
|
# put in front of it. If left blank `xml' will be used as the default path.
|
||||||
|
|
||||||
|
XML_OUTPUT = xml
|
||||||
|
|
||||||
|
# The XML_SCHEMA tag can be used to specify an XML schema,
|
||||||
|
# which can be used by a validating XML parser to check the
|
||||||
|
# syntax of the XML files.
|
||||||
|
|
||||||
|
XML_SCHEMA =
|
||||||
|
|
||||||
|
# The XML_DTD tag can be used to specify an XML DTD,
|
||||||
|
# which can be used by a validating XML parser to check the
|
||||||
|
# syntax of the XML files.
|
||||||
|
|
||||||
|
XML_DTD =
|
||||||
|
|
||||||
|
#---------------------------------------------------------------------------
|
||||||
|
# configuration options for the AutoGen Definitions output
|
||||||
|
#---------------------------------------------------------------------------
|
||||||
|
|
||||||
|
# If the GENERATE_AUTOGEN_DEF tag is set to YES Doxygen will
|
||||||
|
# generate an AutoGen Definitions (see autogen.sf.net) file
|
||||||
|
# that captures the structure of the code including all
|
||||||
|
# documentation. Note that this feature is still experimental
|
||||||
|
# and incomplete at the moment.
|
||||||
|
|
||||||
|
GENERATE_AUTOGEN_DEF = NO
|
||||||
|
|
||||||
|
#---------------------------------------------------------------------------
|
||||||
|
# configuration options related to the Perl module output
|
||||||
|
#---------------------------------------------------------------------------
|
||||||
|
|
||||||
|
# If the GENERATE_PERLMOD tag is set to YES Doxygen will
|
||||||
|
# generate a Perl module file that captures the structure of
|
||||||
|
# the code including all documentation. Note that this
|
||||||
|
# feature is still experimental and incomplete at the
|
||||||
|
# moment.
|
||||||
|
|
||||||
|
GENERATE_PERLMOD = NO
|
||||||
|
|
||||||
|
# If the PERLMOD_LATEX tag is set to YES Doxygen will generate
|
||||||
|
# the necessary Makefile rules, Perl scripts and LaTeX code to be able
|
||||||
|
# to generate PDF and DVI output from the Perl module output.
|
||||||
|
|
||||||
|
PERLMOD_LATEX = NO
|
||||||
|
|
||||||
|
# If the PERLMOD_PRETTY tag is set to YES the Perl module output will be
|
||||||
|
# nicely formatted so it can be parsed by a human reader. This is useful
|
||||||
|
# if you want to understand what is going on. On the other hand, if this
|
||||||
|
# tag is set to NO the size of the Perl module output will be much smaller
|
||||||
|
# and Perl will parse it just the same.
|
||||||
|
|
||||||
|
PERLMOD_PRETTY = YES
|
||||||
|
|
||||||
|
# The names of the make variables in the generated doxyrules.make file
|
||||||
|
# are prefixed with the string contained in PERLMOD_MAKEVAR_PREFIX.
|
||||||
|
# This is useful so different doxyrules.make files included by the same
|
||||||
|
# Makefile don't overwrite each other's variables.
|
||||||
|
|
||||||
|
PERLMOD_MAKEVAR_PREFIX =
|
||||||
|
|
||||||
|
#---------------------------------------------------------------------------
|
||||||
|
# Configuration options related to the preprocessor
|
||||||
|
#---------------------------------------------------------------------------
|
||||||
|
|
||||||
|
# If the ENABLE_PREPROCESSING tag is set to YES (the default) Doxygen will
|
||||||
|
# evaluate all C-preprocessor directives found in the sources and include
|
||||||
|
# files.
|
||||||
|
|
||||||
|
ENABLE_PREPROCESSING = YES
|
||||||
|
|
||||||
|
# If the MACRO_EXPANSION tag is set to YES Doxygen will expand all macro
|
||||||
|
# names in the source code. If set to NO (the default) only conditional
|
||||||
|
# compilation will be performed. Macro expansion can be done in a controlled
|
||||||
|
# way by setting EXPAND_ONLY_PREDEF to YES.
|
||||||
|
|
||||||
|
MACRO_EXPANSION = NO
|
||||||
|
|
||||||
|
# If the EXPAND_ONLY_PREDEF and MACRO_EXPANSION tags are both set to YES
|
||||||
|
# then the macro expansion is limited to the macros specified with the
|
||||||
|
# PREDEFINED and EXPAND_AS_PREDEFINED tags.
|
||||||
|
|
||||||
|
EXPAND_ONLY_PREDEF = NO
|
||||||
|
|
||||||
|
# If the SEARCH_INCLUDES tag is set to YES (the default) the includes files
|
||||||
|
# in the INCLUDE_PATH (see below) will be search if a #include is found.
|
||||||
|
|
||||||
|
SEARCH_INCLUDES = YES
|
||||||
|
|
||||||
|
# The INCLUDE_PATH tag can be used to specify one or more directories that
|
||||||
|
# contain include files that are not input files but should be processed by
|
||||||
|
# the preprocessor.
|
||||||
|
|
||||||
|
INCLUDE_PATH =
|
||||||
|
|
||||||
|
# You can use the INCLUDE_FILE_PATTERNS tag to specify one or more wildcard
|
||||||
|
# patterns (like *.h and *.hpp) to filter out the header-files in the
|
||||||
|
# directories. If left blank, the patterns specified with FILE_PATTERNS will
|
||||||
|
# be used.
|
||||||
|
|
||||||
|
INCLUDE_FILE_PATTERNS =
|
||||||
|
|
||||||
|
# The PREDEFINED tag can be used to specify one or more macro names that
|
||||||
|
# are defined before the preprocessor is started (similar to the -D option of
|
||||||
|
# gcc). The argument of the tag is a list of macros of the form: name
|
||||||
|
# or name=definition (no spaces). If the definition and the = are
|
||||||
|
# omitted =1 is assumed.
|
||||||
|
|
||||||
|
PREDEFINED =
|
||||||
|
|
||||||
|
# If the MACRO_EXPANSION and EXPAND_ONLY_PREDEF tags are set to YES then
|
||||||
|
# this tag can be used to specify a list of macro names that should be expanded.
|
||||||
|
# The macro definition that is found in the sources will be used.
|
||||||
|
# Use the PREDEFINED tag if you want to use a different macro definition.
|
||||||
|
|
||||||
|
EXPAND_AS_DEFINED =
|
||||||
|
|
||||||
|
# If the SKIP_FUNCTION_MACROS tag is set to YES (the default) then
|
||||||
|
# doxygen's preprocessor will remove all function-like macros that are alone
|
||||||
|
# on a line, have an all uppercase name, and do not end with a semicolon. Such
|
||||||
|
# function macros are typically used for boiler-plate code, and will confuse the
|
||||||
|
# parser if not removed.
|
||||||
|
|
||||||
|
SKIP_FUNCTION_MACROS = YES
|
||||||
|
|
||||||
|
#---------------------------------------------------------------------------
|
||||||
|
# Configuration::addtions related to external references
|
||||||
|
#---------------------------------------------------------------------------
|
||||||
|
|
||||||
|
# The TAGFILES option can be used to specify one or more tagfiles.
|
||||||
|
# Optionally an initial location of the external documentation
|
||||||
|
# can be added for each tagfile. The format of a tag file without
|
||||||
|
# this location is as follows:
|
||||||
|
# TAGFILES = file1 file2 ...
|
||||||
|
# Adding location for the tag files is done as follows:
|
||||||
|
# TAGFILES = file1=loc1 "file2 = loc2" ...
|
||||||
|
# where "loc1" and "loc2" can be relative or absolute paths or
|
||||||
|
# URLs. If a location is present for each tag, the installdox tool
|
||||||
|
# does not have to be run to correct the links.
|
||||||
|
# Note that each tag file must have a unique name
|
||||||
|
# (where the name does NOT include the path)
|
||||||
|
# If a tag file is not located in the directory in which doxygen
|
||||||
|
# is run, you must also specify the path to the tagfile here.
|
||||||
|
|
||||||
|
TAGFILES =
|
||||||
|
|
||||||
|
# When a file name is specified after GENERATE_TAGFILE, doxygen will create
|
||||||
|
# a tag file that is based on the input files it reads.
|
||||||
|
|
||||||
|
GENERATE_TAGFILE =
|
||||||
|
|
||||||
|
# If the ALLEXTERNALS tag is set to YES all external classes will be listed
|
||||||
|
# in the class index. If set to NO only the inherited external classes
|
||||||
|
# will be listed.
|
||||||
|
|
||||||
|
ALLEXTERNALS = NO
|
||||||
|
|
||||||
|
# If the EXTERNAL_GROUPS tag is set to YES all external groups will be listed
|
||||||
|
# in the modules index. If set to NO, only the current project's groups will
|
||||||
|
# be listed.
|
||||||
|
|
||||||
|
EXTERNAL_GROUPS = YES
|
||||||
|
|
||||||
|
# The PERL_PATH should be the absolute path and name of the perl script
|
||||||
|
# interpreter (i.e. the result of `which perl').
|
||||||
|
|
||||||
|
PERL_PATH = /usr/bin/perl
|
||||||
|
|
||||||
|
#---------------------------------------------------------------------------
|
||||||
|
# Configuration options related to the dot tool
|
||||||
|
#---------------------------------------------------------------------------
|
||||||
|
|
||||||
|
# If the CLASS_DIAGRAMS tag is set to YES (the default) Doxygen will
|
||||||
|
# generate a inheritance diagram (in HTML, RTF and LaTeX) for classes with base or
|
||||||
|
# super classes. Setting the tag to NO turns the diagrams off. Note that this
|
||||||
|
# option is superceded by the HAVE_DOT option below. This is only a fallback. It is
|
||||||
|
# recommended to install and use dot, since it yields more powerful graphs.
|
||||||
|
|
||||||
|
CLASS_DIAGRAMS = YES
|
||||||
|
|
||||||
|
# If set to YES, the inheritance and collaboration graphs will hide
|
||||||
|
# inheritance and usage relations if the target is undocumented
|
||||||
|
# or is not a class.
|
||||||
|
|
||||||
|
HIDE_UNDOC_RELATIONS = NO
|
||||||
|
|
||||||
|
# If you set the HAVE_DOT tag to YES then doxygen will assume the dot tool is
|
||||||
|
# available from the path. This tool is part of Graphviz, a graph visualization
|
||||||
|
# toolkit from AT&T and Lucent Bell Labs. The other options in this section
|
||||||
|
# have no effect if this option is set to NO (the default)
|
||||||
|
|
||||||
|
HAVE_DOT = @HAVE_DOT@
|
||||||
|
|
||||||
|
# If the CLASS_GRAPH and HAVE_DOT tags are set to YES then doxygen
|
||||||
|
# will generate a graph for each documented class showing the direct and
|
||||||
|
# indirect inheritance relations. Setting this tag to YES will force the
|
||||||
|
# the CLASS_DIAGRAMS tag to NO.
|
||||||
|
|
||||||
|
CLASS_GRAPH = YES
|
||||||
|
|
||||||
|
# If the COLLABORATION_GRAPH and HAVE_DOT tags are set to YES then doxygen
|
||||||
|
# will generate a graph for each documented class showing the direct and
|
||||||
|
# indirect implementation dependencies (inheritance, containment, and
|
||||||
|
# class references variables) of the class with other documented classes.
|
||||||
|
|
||||||
|
COLLABORATION_GRAPH = NO
|
||||||
|
|
||||||
|
# If the UML_LOOK tag is set to YES doxygen will generate inheritance and
|
||||||
|
# colloborations diagrams in a style similiar to the OMG's Unified Modeling
|
||||||
|
# Language.
|
||||||
|
|
||||||
|
UML_LOOK = NO
|
||||||
|
|
||||||
|
# If set to YES, the inheritance and collaboration graphs will show the
|
||||||
|
# relations between templates and their instances.
|
||||||
|
|
||||||
|
TEMPLATE_RELATIONS = YES
|
||||||
|
|
||||||
|
# If the ENABLE_PREPROCESSING, SEARCH_INCLUDES, INCLUDE_GRAPH, and HAVE_DOT
|
||||||
|
# tags are set to YES then doxygen will generate a graph for each documented
|
||||||
|
# file showing the direct and indirect include dependencies of the file with
|
||||||
|
# other documented files.
|
||||||
|
|
||||||
|
INCLUDE_GRAPH = NO
|
||||||
|
|
||||||
|
# If the ENABLE_PREPROCESSING, SEARCH_INCLUDES, INCLUDED_BY_GRAPH, and
|
||||||
|
# HAVE_DOT tags are set to YES then doxygen will generate a graph for each
|
||||||
|
# documented header file showing the documented files that directly or
|
||||||
|
# indirectly include this file.
|
||||||
|
|
||||||
|
INCLUDED_BY_GRAPH = NO
|
||||||
|
|
||||||
|
# If the CALL_GRAPH and HAVE_DOT tags are set to YES then doxygen will
|
||||||
|
# generate a call dependency graph for every global function or class method.
|
||||||
|
# Note that enabling this option will significantly increase the time of a run.
|
||||||
|
# So in most cases it will be better to enable call graphs for selected
|
||||||
|
# functions only using the \callgraph command.
|
||||||
|
|
||||||
|
CALL_GRAPH = NO
|
||||||
|
|
||||||
|
# If the GRAPHICAL_HIERARCHY and HAVE_DOT tags are set to YES then doxygen
|
||||||
|
# will graphical hierarchy of all classes instead of a textual one.
|
||||||
|
|
||||||
|
GRAPHICAL_HIERARCHY = YES
|
||||||
|
|
||||||
|
# The DOT_IMAGE_FORMAT tag can be used to set the image format of the images
|
||||||
|
# generated by dot. Possible values are png, jpg, or gif
|
||||||
|
# If left blank png will be used.
|
||||||
|
|
||||||
|
DOT_IMAGE_FORMAT = png
|
||||||
|
|
||||||
|
# The tag DOT_PATH can be used to specify the path where the dot tool can be
|
||||||
|
# found. If left blank, it is assumed the dot tool can be found on the path.
|
||||||
|
|
||||||
|
DOT_PATH =
|
||||||
|
|
||||||
|
# The DOTFILE_DIRS tag can be used to specify one or more directories that
|
||||||
|
# contain dot files that are included in the documentation (see the
|
||||||
|
# \dotfile command).
|
||||||
|
|
||||||
|
DOTFILE_DIRS =
|
||||||
|
|
||||||
|
# The MAX_DOT_GRAPH_WIDTH tag can be used to set the maximum allowed width
|
||||||
|
# (in pixels) of the graphs generated by dot. If a graph becomes larger than
|
||||||
|
# this value, doxygen will try to truncate the graph, so that it fits within
|
||||||
|
# the specified constraint. Beware that most browsers cannot cope with very
|
||||||
|
# large images.
|
||||||
|
|
||||||
|
MAX_DOT_GRAPH_WIDTH = 800
|
||||||
|
|
||||||
|
# The MAX_DOT_GRAPH_HEIGHT tag can be used to set the maximum allows height
|
||||||
|
# (in pixels) of the graphs generated by dot. If a graph becomes larger than
|
||||||
|
# this value, doxygen will try to truncate the graph, so that it fits within
|
||||||
|
# the specified constraint. Beware that most browsers cannot cope with very
|
||||||
|
# large images.
|
||||||
|
|
||||||
|
MAX_DOT_GRAPH_HEIGHT = 800
|
||||||
|
|
||||||
|
# The MAX_DOT_GRAPH_DEPTH tag can be used to set the maximum depth of the
|
||||||
|
# graphs generated by dot. A depth value of 3 means that only nodes reachable
|
||||||
|
# from the root by following a path via at most 3 edges will be shown. Nodes that
|
||||||
|
# lay further from the root node will be omitted. Note that setting this option to
|
||||||
|
# 1 or 2 may greatly reduce the computation time needed for large code bases. Also
|
||||||
|
# note that a graph may be further truncated if the graph's image dimensions are
|
||||||
|
# not sufficient to fit the graph (see MAX_DOT_GRAPH_WIDTH and MAX_DOT_GRAPH_HEIGHT).
|
||||||
|
# If 0 is used for the depth value (the default), the graph is not depth-constrained.
|
||||||
|
|
||||||
|
MAX_DOT_GRAPH_DEPTH = 0
|
||||||
|
|
||||||
|
# If the GENERATE_LEGEND tag is set to YES (the default) Doxygen will
|
||||||
|
# generate a legend page explaining the meaning of the various boxes and
|
||||||
|
# arrows in the dot generated graphs.
|
||||||
|
|
||||||
|
GENERATE_LEGEND = YES
|
||||||
|
|
||||||
|
# If the DOT_CLEANUP tag is set to YES (the default) Doxygen will
|
||||||
|
# remove the intermediate dot files that are used to generate
|
||||||
|
# the various graphs.
|
||||||
|
|
||||||
|
DOT_CLEANUP = YES
|
||||||
|
|
||||||
|
#---------------------------------------------------------------------------
|
||||||
|
# Configuration::addtions related to the search engine
|
||||||
|
#---------------------------------------------------------------------------
|
||||||
|
|
||||||
|
# The SEARCHENGINE tag specifies whether or not a search engine should be
|
||||||
|
# used. If set to NO the values of all tags below this one will be ignored.
|
||||||
|
|
||||||
|
SEARCHENGINE = NO
|
||||||
|
|
||||||
|
# The CGI_NAME tag should be the name of the CGI script that
|
||||||
|
# starts the search engine (doxysearch) with the correct parameters.
|
||||||
|
# A script with this name will be generated by doxygen.
|
||||||
|
|
||||||
|
CGI_NAME = search.cgi
|
||||||
|
|
||||||
|
# The CGI_URL tag should be the absolute URL to the directory where the
|
||||||
|
# cgi binaries are located. See the documentation of your http daemon for
|
||||||
|
# details.
|
||||||
|
|
||||||
|
CGI_URL =
|
||||||
|
|
||||||
|
# The DOC_URL tag should be the absolute URL to the directory where the
|
||||||
|
# documentation is located. If left blank the absolute path to the
|
||||||
|
# documentation, with file:// prepended to it, will be used.
|
||||||
|
|
||||||
|
DOC_URL =
|
||||||
|
|
||||||
|
# The DOC_ABSPATH tag should be the absolute path to the directory where the
|
||||||
|
# documentation is located. If left blank the directory on the local machine
|
||||||
|
# will be used.
|
||||||
|
|
||||||
|
DOC_ABSPATH =
|
||||||
|
|
||||||
|
# The BIN_ABSPATH tag must point to the directory where the doxysearch binary
|
||||||
|
# is installed.
|
||||||
|
|
||||||
|
BIN_ABSPATH = /usr/local/bin/
|
||||||
|
|
||||||
|
# The EXT_DOC_PATHS tag can be used to specify one or more paths to
|
||||||
|
# documentation generated for other projects. This allows doxysearch to search
|
||||||
|
# the documentation for these projects as well.
|
||||||
|
|
||||||
|
EXT_DOC_PATHS =
|
15
mrw/exception.cpp
Normal file
15
mrw/exception.cpp
Normal file
@@ -0,0 +1,15 @@
|
|||||||
|
#include <mrw/exception.hpp>
|
||||||
|
#include <mrw/stacktrace.hpp>
|
||||||
|
|
||||||
|
namespace mrw {
|
||||||
|
exception::exception() throw(std::bad_exception):
|
||||||
|
_stacktrace(new StackTrace) {
|
||||||
|
}
|
||||||
|
exception::~exception() throw() {
|
||||||
|
delete _stacktrace;
|
||||||
|
}
|
||||||
|
const std::string& exception::stacktrace() const throw(std::bad_exception) {
|
||||||
|
static const std::string st(*_stacktrace);
|
||||||
|
return st;
|
||||||
|
}
|
||||||
|
}
|
170
mrw/exception.hpp
Normal file
170
mrw/exception.hpp
Normal file
@@ -0,0 +1,170 @@
|
|||||||
|
#ifndef __MRW_EXCEPTION_HPP__
|
||||||
|
#define __MRW_EXCEPTION_HPP__
|
||||||
|
|
||||||
|
#include <exception>
|
||||||
|
#include <string>
|
||||||
|
|
||||||
|
namespace mrw {
|
||||||
|
|
||||||
|
class StackTrace;
|
||||||
|
|
||||||
|
/** @addtogroup StackTrace
|
||||||
|
|
||||||
|
@section exc Exception Handling with Stack Trace
|
||||||
|
|
||||||
|
One of the main reasons for the mrw::StackTrace class is, to be
|
||||||
|
able to store a trace where an exception is thrown. This trace
|
||||||
|
is then stored as exception information, but not yet evaluated,
|
||||||
|
symbols are calculated only if necessary, upon request. So the
|
||||||
|
exception is still relatively cheap.
|
||||||
|
|
||||||
|
There is a class named mrw::exception that derieves from and
|
||||||
|
behaves as @c std::exception, but it stores a mrw::StackTrace on
|
||||||
|
construction and offers a method @c mrw::exception::stacktrace()
|
||||||
|
that returns a well formatted stack trace of the point, where
|
||||||
|
the exception was created.
|
||||||
|
|
||||||
|
@subsection excprob Common Problems with Exception Handling
|
||||||
|
|
||||||
|
Exceptions are very handy: When you have a problem, you throw an
|
||||||
|
exception and when you call a method and reach the next line,
|
||||||
|
everything was fine. You don't have to care about error handling
|
||||||
|
unless you are able to handle it. Otherwise you simply let pass
|
||||||
|
any exception up in the stack.
|
||||||
|
|
||||||
|
The big disadvantage is, when you catch an exception, you don't
|
||||||
|
know where it was thrown. That's the stack trace for. Another
|
||||||
|
problem is, the exception specification problem: When you don't
|
||||||
|
write exception specifications, you don't know what a specific
|
||||||
|
method throws. If you do write exception specifications, they
|
||||||
|
are not checked at compile time, but enforced at run time. If a
|
||||||
|
wrong exception is thrown, the program stops, calls an
|
||||||
|
unexpected handler that by default aborts the program. Since the
|
||||||
|
unexpected handler must not return, the problem cannot be
|
||||||
|
recovered from. But the unexpected handler can rethrow and catch
|
||||||
|
the bad exception and it is allowed to throw a new
|
||||||
|
exception. This is what my suggested exception handling concept
|
||||||
|
makes use of.
|
||||||
|
|
||||||
|
@subsection excsug Suggested Exception Handling Rules
|
||||||
|
|
||||||
|
-# derieve all your exceptions from mrw::exception
|
||||||
|
-# write exception specifications as follows:
|
||||||
|
- if any exception is thrown, specify @c throw(mrw::exception)
|
||||||
|
- if no exception is thrown, specify @c throw(std::bad_exception)
|
||||||
|
-# document the exact exception thrown with Doxygen's \@throw tag
|
||||||
|
-# write an unexpected handler as follows:
|
||||||
|
|
||||||
|
@code
|
||||||
|
void unexpectedHandler() {
|
||||||
|
try {
|
||||||
|
throw;
|
||||||
|
} catch (mrw::exception& x) {
|
||||||
|
// trace x.stacktrace() and x.what()
|
||||||
|
} catch (std::exception& x) {
|
||||||
|
// trace x.what()
|
||||||
|
} catch (...) {
|
||||||
|
// trace unknown unexpected
|
||||||
|
}
|
||||||
|
throw std::bad_exception(); // try to recover
|
||||||
|
}
|
||||||
|
@endcode
|
||||||
|
|
||||||
|
What happens:
|
||||||
|
- If you throw an exception in a method that declares not to
|
||||||
|
throw an exception, the unexpected handler is called.
|
||||||
|
- It writes a stack trace for you to be able to find your bug.
|
||||||
|
- Then it throws a @c std::bad_exception, which is allowed to pass.
|
||||||
|
- Your program does not abort, but continues running.
|
||||||
|
- If higher in the stack you catch the exception, you may be
|
||||||
|
able to recover.
|
||||||
|
- If you throw an exception where you are allowed to, you only need to
|
||||||
|
catch mrw::exception and you can access @c what() and @c stacktrace().
|
||||||
|
|
||||||
|
For a proof of concept refer to
|
||||||
|
@ref exceptionhandling.cpp "the example exceptionhandling.cpp".
|
||||||
|
*/
|
||||||
|
//@{
|
||||||
|
|
||||||
|
/** @example exceptionhandling.cpp
|
||||||
|
|
||||||
|
It is possible to recover from an unexpected exception! A stack
|
||||||
|
trace helps you to find the source of a problem, here function
|
||||||
|
@c fn2() in file @c /privat/home/marc/pro/mrw-c++/mrw/test.cpp
|
||||||
|
on line @c 25. This example produces the following output:
|
||||||
|
|
||||||
|
@verbatim
|
||||||
|
call fn0
|
||||||
|
enter fn0
|
||||||
|
enter fn1
|
||||||
|
enter fn2
|
||||||
|
UNEXPECTED:N3mrw9exceptionE
|
||||||
|
---------------------------Stack:
|
||||||
|
[0x8049e51] ../sysdeps/i386/elf/start.S:105 _start
|
||||||
|
[0x401cfd3e] ????:0 ????
|
||||||
|
[0x804a3d0] examples/exceptionhandling.cpp:50 main
|
||||||
|
[0x804a2a3] examples/exceptionhandling.cpp:38 fn0()
|
||||||
|
[0x804a227] examples/exceptionhandling.cpp:32 fn1()
|
||||||
|
[0x804a1c1] examples/exceptionhandling.cpp:25 fn2()
|
||||||
|
[0x804fdda] ../mrw/exception.cpp:6 mrw::exception::exception()
|
||||||
|
[0x804a8f5] ../mrw/stacktrace.cpp:54 mrw::StackTrace::StackTrace()
|
||||||
|
---------------------------------
|
||||||
|
EXCEPTION caught in fn0:St13bad_exception
|
||||||
|
leave fn0
|
||||||
|
call of fn0 successful
|
||||||
|
@endverbatim
|
||||||
|
|
||||||
|
Please note, that without the exception concept and without the
|
||||||
|
unexpected handler, the program would abort in function fn2 on
|
||||||
|
line 25. The output was produced by the following code:
|
||||||
|
*/
|
||||||
|
|
||||||
|
/** @brief replacement for @c std::exception, that collects a stack trace
|
||||||
|
|
||||||
|
This exception class behaves exactely like @c std::exception,
|
||||||
|
but it collects a stack trace in the constructor and offers a
|
||||||
|
method to return the formatted stack trace for logging.
|
||||||
|
|
||||||
|
It is recommended, to inherit all the exceptions you ever throw
|
||||||
|
from this class. This way you can always access the stack trace
|
||||||
|
if you run into troubles. It is fursther recommended, to write a
|
||||||
|
unexpected handler, that rethrows, catches this exception, then
|
||||||
|
throws a @c std::bad_exception to try to continue. This is the
|
||||||
|
reason, why all the exception specifications in the MRW C++
|
||||||
|
Library declar @c throw(std::bad_exception) instead of @c
|
||||||
|
throw(), when they throw nothing.
|
||||||
|
|
||||||
|
@code
|
||||||
|
namespace myProject {
|
||||||
|
void unexpectedHandler() {
|
||||||
|
try {
|
||||||
|
throw;
|
||||||
|
} catch (mrw::exception& x) {
|
||||||
|
// trace x.stacktrace() and x.what()
|
||||||
|
} catch (std::exception& x) {
|
||||||
|
// trace x.what()
|
||||||
|
} catch (...) {
|
||||||
|
// trace unknown unexpected
|
||||||
|
}
|
||||||
|
throw std::bad_exception(); // try to recover
|
||||||
|
}
|
||||||
|
}
|
||||||
|
int main() {
|
||||||
|
std::set_unexpected(&myProject::unexpectedHandler);
|
||||||
|
...
|
||||||
|
}
|
||||||
|
@endcode
|
||||||
|
*/
|
||||||
|
class exception: public std::exception {
|
||||||
|
public:
|
||||||
|
exception() throw(std::bad_exception);
|
||||||
|
virtual ~exception() throw();
|
||||||
|
const std::string& stacktrace() const throw(std::bad_exception);
|
||||||
|
private:
|
||||||
|
StackTrace* _stacktrace;
|
||||||
|
};
|
||||||
|
|
||||||
|
//@}
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif
|
163
mrw/exec.cpp
Normal file
163
mrw/exec.cpp
Normal file
@@ -0,0 +1,163 @@
|
|||||||
|
#include <mrw/exec.hpp>
|
||||||
|
#include <mrw/unistd.hpp>
|
||||||
|
#include <sys/wait.h> // waitpid
|
||||||
|
#include <unistd.h> // fork, exec
|
||||||
|
#include <string.h> // memcpy
|
||||||
|
|
||||||
|
#include <iostream>
|
||||||
|
|
||||||
|
mrw::ExecutionFailedExc::ExecutionFailedExc(const std::string& w,
|
||||||
|
const std::string& c)
|
||||||
|
throw(std::bad_exception):
|
||||||
|
_what(std::string("mrw::Exec: command execution failed\n")+
|
||||||
|
std::string(" failed command was: \""+c+"\"\n")+
|
||||||
|
std::string(" error was: \"")+w+'"') {
|
||||||
|
/**
|
||||||
|
@c what looks like:
|
||||||
|
@verbatim
|
||||||
|
mrw::Exec: command execution failed
|
||||||
|
failed command was: "/bin/OOOOPS -v -q --crash"
|
||||||
|
error was: "execution failed"
|
||||||
|
@endverbatim
|
||||||
|
*/
|
||||||
|
}
|
||||||
|
|
||||||
|
mrw::Cmd::Cmd(const std::string& c) throw(std::bad_exception) {
|
||||||
|
_cmd.push_back(c);
|
||||||
|
}
|
||||||
|
|
||||||
|
mrw::Cmd& mrw::Cmd::operator,(const std::string& arg)
|
||||||
|
throw(std::bad_exception) {
|
||||||
|
_cmd.push_back(arg);
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
|
mrw::Cmd& mrw::Cmd::operator<<(const std::string& arg)
|
||||||
|
throw(std::bad_exception) {
|
||||||
|
_cmd.push_back(arg);
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
|
mrw::Cmd::operator std::string() const throw(std::bad_exception) {
|
||||||
|
ArgList::const_iterator it(_cmd.begin());
|
||||||
|
std::string c(*it);
|
||||||
|
while (++it!=_cmd.end()) c+=' '+*it;
|
||||||
|
return c;
|
||||||
|
}
|
||||||
|
|
||||||
|
mrw::Cmd::operator mrw::Exec() const throw(std::bad_exception) {
|
||||||
|
return mrw::Exec(*this);
|
||||||
|
}
|
||||||
|
|
||||||
|
mrw::Exec mrw::Cmd::execute(bool throwExc) const throw(mrw::exception) {
|
||||||
|
return mrw::Exec(*this).execute(throwExc);
|
||||||
|
}
|
||||||
|
|
||||||
|
const char* mrw::Cmd::path() const throw(std::bad_exception) {
|
||||||
|
return _cmd.front().c_str();
|
||||||
|
}
|
||||||
|
char** mrw::Cmd::args() const throw(std::bad_exception) {
|
||||||
|
if (_cmd.size()==0) return 0;
|
||||||
|
char** array = new char*[_cmd.size()+1];
|
||||||
|
int i(0);
|
||||||
|
for (ArgList::const_iterator it(_cmd.begin()); it!=_cmd.end(); ++it)
|
||||||
|
memcpy(array[i++]=new char[it->size()+1], it->c_str(), it->size()+1);
|
||||||
|
array[i] = 0;
|
||||||
|
return array;
|
||||||
|
}
|
||||||
|
|
||||||
|
mrw::Exec::Exec(const mrw::Cmd& c) throw(std::bad_exception):
|
||||||
|
_cmd(new mrw::Cmd(c)), _success(false) {
|
||||||
|
}
|
||||||
|
|
||||||
|
mrw::Exec::Exec(const mrw::Exec& e) throw(std::bad_exception):
|
||||||
|
_cmd(new mrw::Cmd(*e._cmd)),
|
||||||
|
_res(e._res), _err(e._err), _success(e._success) {
|
||||||
|
}
|
||||||
|
|
||||||
|
mrw::Exec::~Exec() throw() {
|
||||||
|
delete _cmd;
|
||||||
|
}
|
||||||
|
|
||||||
|
mrw::Exec& mrw::Exec::operator=(const mrw::Exec& e) throw(std::bad_exception) {
|
||||||
|
if (this==&e) return *this;
|
||||||
|
*_cmd=*e._cmd; _res=e._res; _err=e._err; _success=e._success;
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
|
mrw::Exec& mrw::Exec::execute(bool throwExc) throw(mrw::exception) {
|
||||||
|
/** This method calls @c fork, sets up a pipe connection to pass @c
|
||||||
|
stdot and @c stderr from the child process to the parent process
|
||||||
|
using mrw::pipe and calls @c execvp to execute the program. */
|
||||||
|
_success = false;
|
||||||
|
_res = _err = "";
|
||||||
|
mrw::pipe stdout, stderr;
|
||||||
|
if (!stdout || !stderr)
|
||||||
|
throw mrw::ExecutionFailedExc("cannot create pipe", *_cmd);
|
||||||
|
pid_t pid(fork());
|
||||||
|
if (pid<0)
|
||||||
|
throw ExecutionFailedExc("cannot fork", *_cmd);
|
||||||
|
if (pid) { // parent
|
||||||
|
stdout.close_out();
|
||||||
|
stderr.close_out();
|
||||||
|
if (!stdout || !stderr)
|
||||||
|
throw ExecutionFailedExc("cannot close pipe", *_cmd);
|
||||||
|
int num1(0), num2(0);
|
||||||
|
for (char buf1[4096], buf2[4096];
|
||||||
|
(num1=read(stdout.istream(), buf1, sizeof(buf1)))>0 ||
|
||||||
|
num1==-1 && errno==EINTR ||
|
||||||
|
(num2=read(stderr.istream(), buf2, sizeof(buf2)))>0 ||
|
||||||
|
num2==-1 && errno==EINTR;
|
||||||
|
_res += std::string(buf1, num1), _err += std::string(buf2, num2));
|
||||||
|
if (num1==-1 || num2==-1)
|
||||||
|
throw ExecutionFailedExc("cannot_ read pipe", *_cmd);
|
||||||
|
// wait for child to get return code
|
||||||
|
int s(0);
|
||||||
|
if (waitpid(pid, &s, 0)!=pid || WIFEXITED(s)!=0 && WEXITSTATUS(s)!=0) {
|
||||||
|
if (throwExc) {
|
||||||
|
throw ExecutionFailedExc("execution failed", *_cmd);
|
||||||
|
} else {
|
||||||
|
_success = false;
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else { // child
|
||||||
|
stdout.close_in();
|
||||||
|
stderr.close_in();
|
||||||
|
stdout.connect_cout();
|
||||||
|
stderr.connect_cerr();
|
||||||
|
execvp(_cmd->path(), _cmd->args());
|
||||||
|
exit(1); // execute failed
|
||||||
|
}
|
||||||
|
_success = true;
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
|
mrw::Exec& mrw::Exec::operator>>(std::string& res) throw(mrw::exception) {
|
||||||
|
execute();
|
||||||
|
res += _res;
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
|
mrw::Exec::operator std::string&() throw(mrw::exception) {
|
||||||
|
if (!_success) execute();
|
||||||
|
return _res;
|
||||||
|
}
|
||||||
|
|
||||||
|
mrw::Exec::operator bool() throw(std::bad_exception) {
|
||||||
|
return _success;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string& mrw::Exec::result() throw(mrw::exception) {
|
||||||
|
if (!_success) execute();
|
||||||
|
return _res;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string& mrw::Exec::error() throw(mrw::exception) {
|
||||||
|
if (!_success) execute();
|
||||||
|
return _err;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool mrw::Exec::success() throw(std::bad_exception) {
|
||||||
|
return _success;
|
||||||
|
}
|
266
mrw/exec.hpp
Normal file
266
mrw/exec.hpp
Normal file
@@ -0,0 +1,266 @@
|
|||||||
|
#ifndef __MRW_EXEC_HPP__
|
||||||
|
#define __MRW_EXEC_HPP__
|
||||||
|
|
||||||
|
#include <string>
|
||||||
|
#include <list>
|
||||||
|
#include <mrw/exception.hpp>
|
||||||
|
|
||||||
|
namespace mrw {
|
||||||
|
|
||||||
|
/** @defgroup CmdExec Execute UNIX Commands
|
||||||
|
|
||||||
|
There is no easy way to safely execute UNIX commands and to
|
||||||
|
return the output of the callee to the caller. @c system ist
|
||||||
|
first of all known to be unsafe, because it opens a shell, and
|
||||||
|
second there is no way to transfer the output back to the
|
||||||
|
caller. On the other hand, starting a new process with @c fork
|
||||||
|
and @c exec and passing the output of the callee to the caller
|
||||||
|
using pipes is quite complex and needs much more than one simple
|
||||||
|
line of code. This is the gap that is filled with this command
|
||||||
|
execution classes. There's a class for the command to be
|
||||||
|
executed and a class for the execution of the command.
|
||||||
|
|
||||||
|
Forking a subprocess and evaluating the result becomes so easy:
|
||||||
|
|
||||||
|
@code
|
||||||
|
try {
|
||||||
|
// execute the command: /bin/ls -l /tmp
|
||||||
|
mrw::Exec ls =
|
||||||
|
(mrw::Cmd("/bin/ls"), "-l", "/tmp").execute(false);
|
||||||
|
// evaluate the result
|
||||||
|
if (ls.success())
|
||||||
|
std::cout<<"Execution successful, result was:"<<std::endl;
|
||||||
|
else
|
||||||
|
std::cerr<<"Error in execution, error was:"<<std::endl;
|
||||||
|
std::cout<<ls.result()<<std::endl;
|
||||||
|
std::cerr<<ls.error()<<std::endl;
|
||||||
|
} catch (ExecutionFailedExc& x) {
|
||||||
|
// a fatal execution error occurred
|
||||||
|
// you can trace x.what() and x.stacktrace()
|
||||||
|
}
|
||||||
|
@endcode
|
||||||
|
*/
|
||||||
|
//@{
|
||||||
|
|
||||||
|
class Cmd;
|
||||||
|
|
||||||
|
/** @brief Exception: Execution of command failed.
|
||||||
|
|
||||||
|
This exception is thrown, if the exection of a command in
|
||||||
|
mrw::Exec is failed. That means, it was not possible to fork or
|
||||||
|
to create the necessary pipes, or the command executing process
|
||||||
|
terminated with an error. In the last case, you can access the
|
||||||
|
error stream from @c stderr respectively @c cerr with method
|
||||||
|
mrw::Exec::error().
|
||||||
|
*/
|
||||||
|
class ExecutionFailedExc: public mrw::exception {
|
||||||
|
public:
|
||||||
|
ExecutionFailedExc(const std::string&, const std::string&)
|
||||||
|
throw(std::bad_exception);
|
||||||
|
virtual ~ExecutionFailedExc() throw() {}
|
||||||
|
virtual const char* what() const throw() {return _what.c_str();}
|
||||||
|
private:
|
||||||
|
std::string _what;
|
||||||
|
};
|
||||||
|
|
||||||
|
/** @brief Execute a command in a new process.
|
||||||
|
|
||||||
|
This class handles the execution of a command in a new process
|
||||||
|
and returns the two streams @c cout and @cerr, also known as @c
|
||||||
|
stderr and @stdout.
|
||||||
|
|
||||||
|
There are different ways of usage for this class. A simple way,
|
||||||
|
one line of code, to get only the resulting stream (no error)
|
||||||
|
is:
|
||||||
|
|
||||||
|
@code
|
||||||
|
string stdout =
|
||||||
|
(mrw::Cmd("/bin/ls"), "-l", "/tmp").execute(false).result();
|
||||||
|
@endcode
|
||||||
|
|
||||||
|
If you need not only the resulting @c stdout stream, but also
|
||||||
|
the error stream @c stderr, then you need to store the result:
|
||||||
|
|
||||||
|
@code
|
||||||
|
mrw::Exec ls =
|
||||||
|
(mrw::Cmd("/bin/ls"), "-l", "/tmp").execute(false);
|
||||||
|
if (!ls) ...; // command termianted with error
|
||||||
|
// ls.result() contains stdout
|
||||||
|
// ls.error() contains stderr
|
||||||
|
@endcode
|
||||||
|
|
||||||
|
@note Please note that the command execution may throw an exception.
|
||||||
|
*/
|
||||||
|
class Exec {
|
||||||
|
public:
|
||||||
|
|
||||||
|
/** @brief Create an executor given a command.
|
||||||
|
Construction without passing a command is not possible. */
|
||||||
|
Exec(const mrw::Cmd&) throw(std::bad_exception);
|
||||||
|
|
||||||
|
Exec(const mrw::Exec&) throw(std::bad_exception);
|
||||||
|
~Exec() throw();
|
||||||
|
Exec& operator=(const mrw::Exec&) throw(std::bad_exception);
|
||||||
|
|
||||||
|
/** @brief Execute the command.
|
||||||
|
|
||||||
|
@param bool
|
||||||
|
- @c true throw an exception if return status is not zero
|
||||||
|
- @c false throw only an exception in case of a fatal error
|
||||||
|
|
||||||
|
@throw ExecutionFailedExc is thrown if
|
||||||
|
- fork fails
|
||||||
|
- creation or setup of pipes failed
|
||||||
|
- if given parameter is @c true (the default) also if the
|
||||||
|
executed program terminates with an error
|
||||||
|
*/
|
||||||
|
Exec& execute(bool=true) throw(mrw::exception);
|
||||||
|
|
||||||
|
/** @brief Executes the command if not done, streams @c stdout into a string
|
||||||
|
|
||||||
|
If the command has not yet been executed successfully, it is
|
||||||
|
first executed, then the @c stdout output of the called
|
||||||
|
program is appended to the string.
|
||||||
|
|
||||||
|
@throw ExecutionFailedExc in case of any failure or if the
|
||||||
|
executed program does not return a zero exit status.
|
||||||
|
*/
|
||||||
|
Exec& operator>>(std::string&) throw(mrw::exception);
|
||||||
|
|
||||||
|
/** @brief Executes the command if not done, returns @c stdout as string
|
||||||
|
|
||||||
|
If the command has not yet been executed successfully, it is
|
||||||
|
first executed, then the @c stdout output of the called
|
||||||
|
program is returned.
|
||||||
|
|
||||||
|
@return @c stdout of the called program
|
||||||
|
|
||||||
|
@throw ExecutionFailedExc in case of any failure or if the
|
||||||
|
executed program does not return a zero exit status.
|
||||||
|
*/
|
||||||
|
operator std::string&() throw(mrw::exception);
|
||||||
|
|
||||||
|
/** @return
|
||||||
|
- @c true if the last execution was successful
|
||||||
|
- @c false if the last execution failed or the command was
|
||||||
|
never executed
|
||||||
|
*/
|
||||||
|
operator bool() throw(std::bad_exception);
|
||||||
|
|
||||||
|
/** @brief Executes the command if not done, returns @c stdout as string
|
||||||
|
|
||||||
|
If the command has not yet been executed successfully, it is
|
||||||
|
first executed, then the @c stdout output of the called
|
||||||
|
program is returned.
|
||||||
|
|
||||||
|
@return @c stdout of the called program
|
||||||
|
|
||||||
|
@throw ExecutionFailedExc in case of any failure or if the
|
||||||
|
executed program does not return a zero exit status.
|
||||||
|
*/
|
||||||
|
std::string& result() throw(mrw::exception);
|
||||||
|
|
||||||
|
/** @brief Executes the command if not done, returns @c stderr as string
|
||||||
|
|
||||||
|
If the command has not yet been executed successfully, it is
|
||||||
|
first executed, then the @c stderr error output of the called
|
||||||
|
program is returned.
|
||||||
|
|
||||||
|
@return @c stderr of the called program
|
||||||
|
|
||||||
|
@throw ExecutionFailedExc in case of any failure or if the
|
||||||
|
executed program does not return a zero exit status.
|
||||||
|
*/
|
||||||
|
std::string& error() throw(mrw::exception);
|
||||||
|
|
||||||
|
/** @return
|
||||||
|
- @c true if the last execution was successful
|
||||||
|
- @c false if the last execution failed or the command was
|
||||||
|
never executed
|
||||||
|
*/
|
||||||
|
bool success() throw(std::bad_exception);
|
||||||
|
|
||||||
|
private:
|
||||||
|
Exec(); // no default constructor
|
||||||
|
mrw::Cmd* _cmd;
|
||||||
|
std::string _res, _err;
|
||||||
|
bool _success;
|
||||||
|
};
|
||||||
|
|
||||||
|
/** @brief A system command to be executed
|
||||||
|
|
||||||
|
This class is used in conjunction with mrw::Exec. It mus be
|
||||||
|
initialized with the command name, then the command parameters
|
||||||
|
are appended either with commas, or by streaming them into the
|
||||||
|
command, whatever you like.
|
||||||
|
|
||||||
|
You can stream the data into the class:
|
||||||
|
|
||||||
|
@code
|
||||||
|
mrw::Cmd ls("/bin/ls"); // the command to execute is: /bin/ls
|
||||||
|
ls<<"-l"<<"/tmp"; // the command is now: /bin/ls -l /tmp
|
||||||
|
@endcode
|
||||||
|
|
||||||
|
Or you can setup your command with commas:
|
||||||
|
|
||||||
|
@code
|
||||||
|
mrw::Cmd ls = (mrw::Cmd(/bin/ls), "-l", "/tmp");
|
||||||
|
@endcode
|
||||||
|
*/
|
||||||
|
class Cmd {
|
||||||
|
public:
|
||||||
|
/** @brief Create a command given the name of the executable
|
||||||
|
@param std::string the name of the program to execute (no parameter)
|
||||||
|
@note There is no default constructor. */
|
||||||
|
Cmd(const std::string&) throw(std::bad_exception);
|
||||||
|
|
||||||
|
/** @brief Append a parameter to a command
|
||||||
|
@param std::string a parameter / commandline argument
|
||||||
|
to append to the command */
|
||||||
|
Cmd& operator,(const std::string&) throw(std::bad_exception);
|
||||||
|
|
||||||
|
/** @brief Append a parameter to a command
|
||||||
|
@param std::string a parameter / commandline argument
|
||||||
|
to append to the command */
|
||||||
|
Cmd& operator<<(const std::string&) throw(std::bad_exception);
|
||||||
|
|
||||||
|
/** @return the command including parameter */
|
||||||
|
operator std::string() const throw(std::bad_exception);
|
||||||
|
|
||||||
|
/** @return a mrw::Exec that's constructed with this class */
|
||||||
|
operator Exec() const throw(std::bad_exception);
|
||||||
|
|
||||||
|
/** @brief Create a mrw::Exec and execute the command
|
||||||
|
|
||||||
|
Creates a mrw::Exec, executes the command, passes the flag to
|
||||||
|
mrw::Exec::execute() and returns the created mrw::Exec. The
|
||||||
|
result of the execution can be retrieved through the returned
|
||||||
|
mrw::Exec object: The methods mrw::Exec::success(),
|
||||||
|
mrw::Exec::result() and mrw::Exec::error() provide the
|
||||||
|
necessary information.
|
||||||
|
|
||||||
|
@param bool
|
||||||
|
- @c true throw an exception if return status is not zero
|
||||||
|
- @c false throw only an exception in case of a fatal error
|
||||||
|
|
||||||
|
@return the mrw::Exec that has executed the command
|
||||||
|
|
||||||
|
@throw ExecutionFailedExc is thrown if
|
||||||
|
- fork fails
|
||||||
|
- creation or setup of pipes failed
|
||||||
|
- if given parameter is @c true (the default) also if the
|
||||||
|
executed program terminates with an error
|
||||||
|
*/
|
||||||
|
Exec execute(bool=true) const throw(mrw::exception);
|
||||||
|
|
||||||
|
private:
|
||||||
|
friend class Exec; // is allowed to call path() and args()
|
||||||
|
Cmd(); // no default constructor
|
||||||
|
const char* path() const throw(std::bad_exception);
|
||||||
|
char** args() const throw(std::bad_exception);
|
||||||
|
typedef std::list<std::string> ArgList;
|
||||||
|
ArgList _cmd;
|
||||||
|
};
|
||||||
|
//@}
|
||||||
|
}
|
||||||
|
#endif
|
22
mrw/exec_test.cpp
Normal file
22
mrw/exec_test.cpp
Normal file
@@ -0,0 +1,22 @@
|
|||||||
|
#include <mrw/exec.hpp>
|
||||||
|
#include <mrw/stacktrace.hpp>
|
||||||
|
#include <iostream>
|
||||||
|
|
||||||
|
int main() {
|
||||||
|
// std::cout<<"RESULT: "
|
||||||
|
// <<(mrw::Cmd("/bin/ls"), "-l", "/tmp").execute().result()
|
||||||
|
// <<std::endl;
|
||||||
|
try {
|
||||||
|
std::cout<<"RESULT: "
|
||||||
|
<<(mrw::Cmd("/bin/false")).execute().result()
|
||||||
|
<<std::endl;
|
||||||
|
} catch (const mrw::exception &x) {
|
||||||
|
mrw::StackTrace::createSymtable();
|
||||||
|
std::cout<<"EXCEPTION: ----------------------------------------"<<std::endl
|
||||||
|
<<"---------- Reason:"<<std::endl
|
||||||
|
<<x.what()<<std::endl
|
||||||
|
<<"---------- Stack:"<<std::endl
|
||||||
|
<<x.stacktrace()<<std::endl
|
||||||
|
<<"---------------------------------------------------"<<std::endl;
|
||||||
|
}
|
||||||
|
}
|
18
mrw/makefile.am
Normal file
18
mrw/makefile.am
Normal file
@@ -0,0 +1,18 @@
|
|||||||
|
EXTRA_DIST = doc examples
|
||||||
|
CLEANFILES = doxygen.err
|
||||||
|
|
||||||
|
lib_LTLIBRARIES = libmrw.la libautostacktracestderr.la
|
||||||
|
|
||||||
|
libmrw_la_SOURCES = mrw.hpp \
|
||||||
|
auto.hpp auto.cpp unistd.hpp \
|
||||||
|
stacktrace.hpp stacktrace.cpp exception.hpp \
|
||||||
|
exec.hpp exec.cpp
|
||||||
|
libmrw_la_LDFLAGS = -version-info @MAJOR@:@MINOR@:@SUPPORT@
|
||||||
|
|
||||||
|
libautostacktracestderr_la_SOURCES = autostacktracestderr.cpp
|
||||||
|
libautostacktracestderr_la_LDFLAGS = -version-info @MAJOR@:@MINOR@:@SUPPORT@
|
||||||
|
|
||||||
|
|
||||||
|
doc: doc/html/index.html
|
||||||
|
doc/html/index.html: doxyfile *.[ch]pp
|
||||||
|
doxygen doxyfile
|
41
mrw/mrw.hpp
Normal file
41
mrw/mrw.hpp
Normal file
@@ -0,0 +1,41 @@
|
|||||||
|
/** @mainpage
|
||||||
|
|
||||||
|
@section license License and Copyright
|
||||||
|
|
||||||
|
- All files are under GNU LGPL license.
|
||||||
|
- All files are copyrighted by Marc Wäckerlin.
|
||||||
|
- There is no warranty.
|
||||||
|
- For details, read the file LICENSE in your distribution.
|
||||||
|
|
||||||
|
@section intro Introduction
|
||||||
|
|
||||||
|
This library cares a about:
|
||||||
|
- resource management
|
||||||
|
- execution of UNIX sub processes
|
||||||
|
- stack trace
|
||||||
|
- exception handling
|
||||||
|
|
||||||
|
For details, see the modules page.
|
||||||
|
|
||||||
|
@section link Compile and Link Options
|
||||||
|
|
||||||
|
To be able to get the source file name / line number
|
||||||
|
information in stack trace, you need the debug information compile
|
||||||
|
option @c -g. For compilation on Solaris, you may need the option
|
||||||
|
@c -D__solaris__. You must link to the MRW C++ Library. For this
|
||||||
|
you need the link option @c -lmrw.
|
||||||
|
|
||||||
|
@section download Download and Installation
|
||||||
|
|
||||||
|
Download the latest version from:
|
||||||
|
- http://marc.waeckerlin.org/c++/libmrw
|
||||||
|
|
||||||
|
Install it with:
|
||||||
|
|
||||||
|
@verbatim
|
||||||
|
tar xzvf mrw-c++-<VERSION>.tar.gz
|
||||||
|
cd mrw-c++-<VERSION>
|
||||||
|
./configure
|
||||||
|
make all check install
|
||||||
|
@endverbatim
|
||||||
|
*/
|
189
mrw/stacktrace.cpp
Normal file
189
mrw/stacktrace.cpp
Normal file
@@ -0,0 +1,189 @@
|
|||||||
|
#include <mrw/stacktrace.hpp>
|
||||||
|
#include <sstream>
|
||||||
|
#include <unistd.h>
|
||||||
|
#include <sys/types.h>
|
||||||
|
#include <sys/stat.h>
|
||||||
|
#include <sys/mman.h>
|
||||||
|
#include <fcntl.h>
|
||||||
|
#include <assert.h>
|
||||||
|
#include <math.h>
|
||||||
|
#include <algorithm>
|
||||||
|
#include <list>
|
||||||
|
#if defined(__solaris__)
|
||||||
|
#include <sys/old_procfs.h>
|
||||||
|
#endif
|
||||||
|
#if defined (__GLIBC__)
|
||||||
|
#include <execinfo.h>
|
||||||
|
#endif
|
||||||
|
#include <bfd.h>
|
||||||
|
extern "C" {
|
||||||
|
#include <demangle.h>
|
||||||
|
}
|
||||||
|
#include <iomanip>
|
||||||
|
|
||||||
|
namespace mrw {
|
||||||
|
|
||||||
|
//----------------------------------------------------------------------------
|
||||||
|
std::string demangle(bfd* abfd, const char* name) {
|
||||||
|
if (bfd_get_symbol_leading_char(abfd) == name[0]) ++name;
|
||||||
|
|
||||||
|
/* This is a hack for better error reporting on XCOFF, PowerPC64-ELF
|
||||||
|
or the MS PE format. These formats have a number of leading '.'s
|
||||||
|
on at least some symbols, so we remove all dots to avoid
|
||||||
|
confusing the demangler. */
|
||||||
|
const char* p (name);
|
||||||
|
while (p && *p == '.') ++p;
|
||||||
|
|
||||||
|
mrw::AutoFree<char> res(cplus_demangle(p, DMGL_ANSI | DMGL_PARAMS));
|
||||||
|
if (res) {
|
||||||
|
/* Now put back any stripped dots. */
|
||||||
|
if (p==name) return (char*)res;
|
||||||
|
std::string add_dots('.', p-name);
|
||||||
|
return add_dots+=(char*)res;
|
||||||
|
}
|
||||||
|
return name;
|
||||||
|
}
|
||||||
|
|
||||||
|
//----------------------------------------------------------------------------
|
||||||
|
StackTrace::StackTrace() throw(std::bad_exception) {
|
||||||
|
// maximum trace level is limited here to 50, see below why
|
||||||
|
# if defined(__GLIBC__)
|
||||||
|
{
|
||||||
|
const int TRACE_LEVEL(50);
|
||||||
|
void* ba[TRACE_LEVEL];
|
||||||
|
for (int n(backtrace(ba, TRACE_LEVEL)), i(0); i<n; ++i)
|
||||||
|
_trace.push_back(ba[i]);
|
||||||
|
}
|
||||||
|
# elif defined(__GNUG__)
|
||||||
|
{
|
||||||
|
# define push(i) \
|
||||||
|
(__builtin_return_address(i) ? \
|
||||||
|
(_trace.push_back(__builtin_return_address(i)), true) : false)
|
||||||
|
push(0) && push(1) && push(2) && push(3) && push(4) && push(5) &&
|
||||||
|
push(6) && push(7) && push(8) && push(9) && push(10) && push(11) &&
|
||||||
|
push(12) && push(13) && push(14) && push(15) && push(16) && push(17)
|
||||||
|
&& push(18) && push(19) && push(20) && push(21) && push(22) &&
|
||||||
|
push(23) && push(24) && push(25) && push(26) && push(27) && push(28)
|
||||||
|
&& push(29) && push(30) && push(31) && push(32) && push(33) &&
|
||||||
|
push(34) && push(35) && push(36) && push(37) && push(38) && push(39)
|
||||||
|
&& push(40) && push(41) && push(42) && push(43) && push(44) &&
|
||||||
|
push(45) && push(46) && push(47) && push(48) && push(49);
|
||||||
|
# undef push
|
||||||
|
}
|
||||||
|
# else
|
||||||
|
# warning "You need GNU gcc or GNU glibc to be able to use mrw::StackTrace"
|
||||||
|
# endif
|
||||||
|
}
|
||||||
|
|
||||||
|
//----------------------------------------------------------------------------
|
||||||
|
StackTrace::operator std::string() const throw(std::bad_exception) {
|
||||||
|
static const double LN10(log(10));
|
||||||
|
std::stringstream s;
|
||||||
|
bool first(true);
|
||||||
|
unsigned int lisz(0), fisz(0);
|
||||||
|
std::list<CodePos> l;
|
||||||
|
for (AddressTrace::const_reverse_iterator it(_trace.rbegin());
|
||||||
|
it!=_trace.rend(); ++it, first=false) {
|
||||||
|
CodePos c(translate(*it));
|
||||||
|
if (log(c.line+1)/LN10 > lisz) lisz = (unsigned int)(log(c.line+1)/LN10);
|
||||||
|
if (c.file.size() > fisz) fisz = c.file.size();
|
||||||
|
l.push_back(c);
|
||||||
|
}
|
||||||
|
for (std::list<CodePos>::iterator it(l.begin()); it!=l.end(); ++it)
|
||||||
|
s<<"["<<it->address<<"] "
|
||||||
|
<<it->file<<':'<<it->line
|
||||||
|
<<std::setw(fisz+lisz-it->file.size()-
|
||||||
|
(unsigned int)(log(it->line+1)/LN10)-1)
|
||||||
|
<<" "<<it->function<<std::endl;
|
||||||
|
return s.str();
|
||||||
|
}
|
||||||
|
|
||||||
|
//----------------------------------------------------------------------------
|
||||||
|
const StackTrace& StackTrace::print(std::ostream& os) const
|
||||||
|
throw(std::bad_exception) {
|
||||||
|
os<<(std::string)*this;
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
|
//----------------------------------------------------------------------------
|
||||||
|
StackTrace::CodePos StackTrace::translate(void* addr)
|
||||||
|
throw(std::bad_exception) {
|
||||||
|
assert(sizeof(bfd_vma)>=sizeof(void*));
|
||||||
|
bfd_vma vma_addr(reinterpret_cast<bfd_vma>(addr));
|
||||||
|
if (!_dic.get()) return CodePos(addr, "????", "????", 0);
|
||||||
|
std::vector<Translator::key_type>::iterator
|
||||||
|
it(std::lower_bound(_addrs.begin(), _addrs.end(), vma_addr));
|
||||||
|
if (it--==_addrs.begin() || *it > vma_addr ||
|
||||||
|
(*_dic)[*it].first <= vma_addr) return CodePos(addr, "????", "????", 0);
|
||||||
|
static const char* file(0);
|
||||||
|
static const char* function(0);
|
||||||
|
unsigned int line;
|
||||||
|
if (!bfd_find_nearest_line(_bfd, (*_dic)[*it].second, _syms.get(),
|
||||||
|
vma_addr-*it, &file, &function, &line))
|
||||||
|
return CodePos(addr, "????", "????", 0);
|
||||||
|
return CodePos(addr, mrw::demangle(_bfd, function), file?file:"????", line);
|
||||||
|
}
|
||||||
|
|
||||||
|
//----------------------------------------------------------------------------
|
||||||
|
bool StackTrace::createSymtable(std::string fname) throw(std::bad_exception) {
|
||||||
|
if (_dic.get()) return true;
|
||||||
|
AutoBfd abfd(bfd_openr((fname!="" ? fname : filename()).c_str(), 0));
|
||||||
|
long memsz(-1);
|
||||||
|
AutoFree<char*> m(0);
|
||||||
|
if (!abfd || bfd_check_format(abfd, bfd_archive) ||
|
||||||
|
!bfd_check_format_matches(abfd, bfd_object, m) ||
|
||||||
|
!(bfd_get_file_flags(abfd)&HAS_SYMS) ||
|
||||||
|
(memsz=bfd_get_symtab_upper_bound(abfd))<0) return false;
|
||||||
|
std::auto_ptr<asymbol*> syms(new asymbol*[memsz]);
|
||||||
|
if (bfd_canonicalize_symtab(abfd, syms.get())<0) return false;
|
||||||
|
_bfd = abfd;
|
||||||
|
_syms = syms;
|
||||||
|
_dic = std::auto_ptr<Translator>(new Translator());
|
||||||
|
bfd_map_over_sections(_bfd, buildSectionMap, 0);
|
||||||
|
std::sort(_addrs.begin(), _addrs.end());
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
//----------------------------------------------------------------------------
|
||||||
|
std::string StackTrace::filename() throw(std::bad_exception) {
|
||||||
|
std::stringstream s;
|
||||||
|
s<<"/proc/"<<getpid();
|
||||||
|
# if defined(__solaris__)
|
||||||
|
{
|
||||||
|
std::string res;
|
||||||
|
AutoFile fd(open(s.str().c_str(), O_RDONLY));
|
||||||
|
prpsinfo_t status;
|
||||||
|
if (fd==-1 || ioctl(fd, PIOCPSINFO, &status)==-1) return res;
|
||||||
|
res = status.pr_psargs;
|
||||||
|
res = res.substr(0, res.find(' '));
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
# elif defined(__linux__)
|
||||||
|
{
|
||||||
|
s<<"/exe";
|
||||||
|
return s.str();
|
||||||
|
}
|
||||||
|
# else
|
||||||
|
# warning "Don't know how to get executable file name in your system!"
|
||||||
|
# warning "Impossible to get function names in stack trace!"
|
||||||
|
# warning "Give the path to the executable to StackTrace::createSymtable!"
|
||||||
|
# endif
|
||||||
|
}
|
||||||
|
|
||||||
|
//----------------------------------------------------------------------------
|
||||||
|
void StackTrace::buildSectionMap(bfd* abfd, asection* section, void*)
|
||||||
|
throw(std::bad_exception) {
|
||||||
|
if (!(bfd_get_section_flags(abfd, section)&SEC_ALLOC)) return;
|
||||||
|
bfd_vma vma(bfd_get_section_vma(abfd, section));
|
||||||
|
bfd_size_type sz(bfd_get_section_size_before_reloc(section));
|
||||||
|
(*_dic)[vma] = Translator::mapped_type(vma+sz, section);
|
||||||
|
_addrs.push_back(vma);
|
||||||
|
}
|
||||||
|
|
||||||
|
//----------------------------------------------------------------------------
|
||||||
|
std::auto_ptr<StackTrace::Translator> StackTrace::_dic;
|
||||||
|
std::vector<StackTrace::Translator::key_type> StackTrace::_addrs;
|
||||||
|
AutoBfd StackTrace::_bfd;
|
||||||
|
std::auto_ptr<asymbol*> StackTrace::_syms;
|
||||||
|
|
||||||
|
}
|
158
mrw/stacktrace.hpp
Normal file
158
mrw/stacktrace.hpp
Normal file
@@ -0,0 +1,158 @@
|
|||||||
|
// g++ -Wall -D__SOLARIS__ -g -I /home/public/freeware/include -L /home/public/freeware/lib -I . stacktrace.cxx -lbfd -liberty
|
||||||
|
#ifndef __MRW_STACKTRACE_HPP__
|
||||||
|
#define __MRW_STACKTRACE_HPP__
|
||||||
|
#include <mrw/auto.hpp>
|
||||||
|
#include <vector>
|
||||||
|
#include <map>
|
||||||
|
#include <string>
|
||||||
|
#include <memory>
|
||||||
|
#include <sys/mman.h>
|
||||||
|
#include <bfd.h>
|
||||||
|
|
||||||
|
#ifdef __REENTRANT
|
||||||
|
#warning "mrw::StackTrace is not thread safe yet!"
|
||||||
|
#warning "It should work, but is at least untested..."
|
||||||
|
#endif
|
||||||
|
|
||||||
|
namespace mrw {
|
||||||
|
|
||||||
|
/** @defgroup StackTrace Collect and Format a Stack Trace
|
||||||
|
|
||||||
|
Somewhere in a program, there is a fatal error, e.g. an
|
||||||
|
unexpected exception is thrown. How is it possible to debug the
|
||||||
|
problem in such a case? Sometimes you can start a debugger and
|
||||||
|
trace the execution of your program. But what if it occurs only
|
||||||
|
once a week, or if you cannot set a breakpoint, because you
|
||||||
|
don't know where the problem is located, or because only the
|
||||||
|
1000th run of a method causes a problem, or what if the problem
|
||||||
|
occurs only at your customers installation?
|
||||||
|
|
||||||
|
One way to solve these problems is to do logging, or even
|
||||||
|
function tracing, so you can narrow down the lines of code,
|
||||||
|
where the problem occurs. But sometimes this is not enough,
|
||||||
|
especially with exceptions. One of the worst things with
|
||||||
|
exceptions is, you can catch an exception somewhere, but you
|
||||||
|
don't know where it was thrown. Here it is very handy, to be
|
||||||
|
able to write a stacktrace to a logging device.
|
||||||
|
|
||||||
|
For logging, I recommend log4cxx on page:
|
||||||
|
- http://logging.apache.org/log4cxx
|
||||||
|
|
||||||
|
These classes are for collecting a stack trace and later for
|
||||||
|
formatting with source code file name, line number and the
|
||||||
|
method name.
|
||||||
|
|
||||||
|
For collecting the stack trace (the addresses):
|
||||||
|
- either the GNU gcc compiler is required
|
||||||
|
- or the GNU glibc library function @c backtrace
|
||||||
|
|
||||||
|
For extracting information from an address, the ELF library is required.
|
||||||
|
|
||||||
|
@note For all features and full operation, this class requires:
|
||||||
|
- either a GNU glibc bases system (LINUX), or the GNU gcc compiler
|
||||||
|
- a system with ELF binaries (LINUX, Solaris, ...)
|
||||||
|
- debug information, compile option @c -g
|
||||||
|
- it must be linked with @c -libery and @c -lbfd
|
||||||
|
*/
|
||||||
|
//@{
|
||||||
|
|
||||||
|
/** @brief store and print a stack trace of the actual position in code
|
||||||
|
|
||||||
|
In the constructor, a stack trace is stored, but not yet
|
||||||
|
evaluated. Therefore storing a stack trace is relatively
|
||||||
|
fast. The evaluation is done when the stack trace is printed on
|
||||||
|
a stream or converted to a string. "Evaluation" means, that the
|
||||||
|
addresses are mapped to the correspoding symbols, the method
|
||||||
|
names, sorce file names and line numbers are evaluated.
|
||||||
|
|
||||||
|
@note Method StackTrace::createSymtable must be called exactely
|
||||||
|
once, before evaluating the first stack trace.Best place is the
|
||||||
|
first line of the @c main function.
|
||||||
|
|
||||||
|
@note This class requires libbfd an libiberty. Debug information
|
||||||
|
is required for compiling. You nee the compile option @c -g, or
|
||||||
|
even better @c -ggdb3. To link, you need @c -lmrw, @c -lbfd and
|
||||||
|
@c -liberty.
|
||||||
|
|
||||||
|
@note The stack trace is known to work perfectly on Linux and
|
||||||
|
Solaris both with GNU gcc compiler. But it should work with the
|
||||||
|
GNU compiler on all systems, or wherever there is a glibc
|
||||||
|
library.
|
||||||
|
|
||||||
|
@note Symbol evaluation requires the ELF library and an ELF system.
|
||||||
|
*/
|
||||||
|
class StackTrace {
|
||||||
|
public:
|
||||||
|
//............................................................... typedefs
|
||||||
|
typedef std::vector<void*> AddressTrace; ///< container for the adresses
|
||||||
|
/// structure to store all evaluated information
|
||||||
|
struct CodePos {
|
||||||
|
CodePos(void* a, std::string fn, std::string fi, unsigned int l)
|
||||||
|
throw(std::bad_exception):
|
||||||
|
address(a), function(fn), file(fi), line(l) {
|
||||||
|
}
|
||||||
|
void* address; ///< the address pointer
|
||||||
|
std::string function; ///< function/method name
|
||||||
|
std::string file; ///< code file name
|
||||||
|
unsigned int line; ///< code line number
|
||||||
|
};
|
||||||
|
//................................................................ methods
|
||||||
|
/// the constructor stores the actual stack trace
|
||||||
|
StackTrace() throw(std::bad_exception);
|
||||||
|
/// evaluates the symbol table and returns the formatted stack trace
|
||||||
|
operator std::string() const throw(std::bad_exception);
|
||||||
|
/// @return list of raw stack addresses
|
||||||
|
operator const AddressTrace&() const throw(std::bad_exception) {
|
||||||
|
return _trace;
|
||||||
|
}
|
||||||
|
/// evaluate the stack trace and print it to a stream
|
||||||
|
const StackTrace& print(std::ostream& os) const throw(std::bad_exception);
|
||||||
|
/// evaluates and returns all information from a raw address
|
||||||
|
static CodePos translate(void* addr) throw(std::bad_exception);
|
||||||
|
|
||||||
|
/** @brief read the symbol table from the executable file
|
||||||
|
|
||||||
|
@param std::string The file name of the executable. On Linux
|
||||||
|
and Solaris, this can be evaluated automatically, so the
|
||||||
|
parameter is optional.
|
||||||
|
|
||||||
|
@return @c true in case of success. If @c false is returned,
|
||||||
|
the symbol table was not read and the evaluation cannot be
|
||||||
|
done. Printing then only prints the raw addresses, without
|
||||||
|
file, line nmber information and method names.
|
||||||
|
|
||||||
|
@note This method must be executed once before a stack trace
|
||||||
|
is printed the very first time. For storing a stack trace
|
||||||
|
(that means for the creation of a mrw::StackTrace object) a
|
||||||
|
call to this method is not yet needed.
|
||||||
|
|
||||||
|
@note If this method is called more than once, the symbols
|
||||||
|
are created only the first time, so you don't loose too much
|
||||||
|
time.
|
||||||
|
*/
|
||||||
|
static bool createSymtable(std::string = "") throw(std::bad_exception);
|
||||||
|
private:
|
||||||
|
//............................................................... typedefs
|
||||||
|
typedef std::map<bfd_vma, std::pair<bfd_vma, asection*> >
|
||||||
|
Translator;
|
||||||
|
//.............................................................. variables
|
||||||
|
AddressTrace _trace;
|
||||||
|
static std::auto_ptr<Translator> _dic;
|
||||||
|
static std::vector<Translator::key_type> _addrs;
|
||||||
|
static AutoBfd _bfd;
|
||||||
|
static std::auto_ptr<asymbol*> _syms;
|
||||||
|
//................................................................ methods
|
||||||
|
static std::string filename() throw(std::bad_exception);
|
||||||
|
static void buildSectionMap(bfd*, asection*, void*)
|
||||||
|
throw(std::bad_exception);
|
||||||
|
};
|
||||||
|
|
||||||
|
/// evaluate a stack trace and shift it on a stream
|
||||||
|
inline std::ostream& operator<<(std::ostream& os, const StackTrace& st)
|
||||||
|
throw(std::bad_exception) {
|
||||||
|
return os<<(std::string)st;
|
||||||
|
}
|
||||||
|
|
||||||
|
//@}
|
||||||
|
}
|
||||||
|
#endif
|
32
mrw/stacktrace_test.cpp
Normal file
32
mrw/stacktrace_test.cpp
Normal file
@@ -0,0 +1,32 @@
|
|||||||
|
#include <mrw/stacktrace.hpp>
|
||||||
|
#include <cppunit/TestFixture.h>
|
||||||
|
#include <cppunit/ui/text/TestRunner.h>
|
||||||
|
#include <cppunit/extensions/HelperMacros.h>
|
||||||
|
#include <cppunit/extensions/TestFactoryRegistry.h>
|
||||||
|
#include <iostream>
|
||||||
|
|
||||||
|
class StackTraceTest: public CppUnit::TestFixture {
|
||||||
|
public:
|
||||||
|
/// test if symbols are correctely evaluated
|
||||||
|
void StackTrace() {
|
||||||
|
mrw::StackTrace::createSymtable();
|
||||||
|
mrw::StackTrace s; int l(__LINE__); std::string f(__FILE__);
|
||||||
|
std::stringstream ss;
|
||||||
|
ss<<f<<':'<<l;
|
||||||
|
std::string st(s);
|
||||||
|
int pos(st.find(ss.str()));
|
||||||
|
std::cout<<st<<std::endl;
|
||||||
|
CPPUNIT_ASSERT(pos<st.size());
|
||||||
|
CPPUNIT_ASSERT(st.find("mrw::StackTrace::StackTrace()", pos)<st.size());
|
||||||
|
}
|
||||||
|
CPPUNIT_TEST_SUITE(StackTraceTest);
|
||||||
|
CPPUNIT_TEST(StackTrace);
|
||||||
|
CPPUNIT_TEST_SUITE_END();
|
||||||
|
};
|
||||||
|
CPPUNIT_TEST_SUITE_REGISTRATION(StackTraceTest);
|
||||||
|
|
||||||
|
int main() {
|
||||||
|
CppUnit::TextUi::TestRunner runner;
|
||||||
|
runner.addTest(CppUnit::TestFactoryRegistry::getRegistry().makeTest());
|
||||||
|
return runner.run() ? 0 : 1;
|
||||||
|
}
|
1
mrw/test.dat
Normal file
1
mrw/test.dat
Normal file
@@ -0,0 +1 @@
|
|||||||
|
Hallo Welt
|
93
mrw/unistd.hpp
Normal file
93
mrw/unistd.hpp
Normal file
@@ -0,0 +1,93 @@
|
|||||||
|
#ifndef __MRW_UNISTD_HPP__
|
||||||
|
#define __MRW_UNISTD_HPP__
|
||||||
|
|
||||||
|
#include <unistd.h> // pipe, close
|
||||||
|
#include <errno.h> // errno
|
||||||
|
|
||||||
|
namespace mrw {
|
||||||
|
/** @addtogroup AutoTools */
|
||||||
|
//@{
|
||||||
|
|
||||||
|
/// class that implements an unnamed UNIX pipe
|
||||||
|
/** Implements a UNIX pipe that is automatically closed in
|
||||||
|
destructor and offers some facilities. */
|
||||||
|
class pipe {
|
||||||
|
private:
|
||||||
|
/// the filedescriptor, [0] to read and [1] to write
|
||||||
|
int _fd[2];
|
||||||
|
int _lastError;
|
||||||
|
public:
|
||||||
|
/// creates a unix pipe
|
||||||
|
pipe(): _lastError(-1) {
|
||||||
|
_fd[0] = -1;
|
||||||
|
_fd[1] = -1;
|
||||||
|
if (::pipe(_fd)==-1)
|
||||||
|
{
|
||||||
|
_lastError=errno;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
/// destructor closes pipe if still open
|
||||||
|
~pipe() {
|
||||||
|
close();
|
||||||
|
}
|
||||||
|
/// closes pipe if open
|
||||||
|
void close() {
|
||||||
|
close_in();
|
||||||
|
close_out();
|
||||||
|
}
|
||||||
|
/// closes input pipe if open
|
||||||
|
void close_in() {
|
||||||
|
if (_fd[0]!=-1) while (::close(_fd[0])==-1) if (errno!=EINTR) {
|
||||||
|
_lastError = errno;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
_fd[0] = -1;
|
||||||
|
}
|
||||||
|
/// closes output pipe if open
|
||||||
|
void close_out() {
|
||||||
|
if (_fd[1]!=-1) while (::close(_fd[1])==-1) if (errno!=EINTR) {
|
||||||
|
_lastError = errno;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
_fd[1] = -1;
|
||||||
|
}
|
||||||
|
/// @return true if no error occured
|
||||||
|
operator bool() {
|
||||||
|
return _lastError == -1;
|
||||||
|
}
|
||||||
|
/// @return last error code, -1 if no error
|
||||||
|
int error() {
|
||||||
|
return _lastError;
|
||||||
|
}
|
||||||
|
/// connect output stream to @c stdout
|
||||||
|
void connect_cout() {
|
||||||
|
while (::dup2(_fd[1], 1)==-1) if (errno!=EINTR) {
|
||||||
|
_lastError = errno;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
/// connect output stream to @c stderr
|
||||||
|
void connect_cerr() {
|
||||||
|
while (::dup2(_fd[1], 2)==-1) if (errno!=EINTR) {
|
||||||
|
_lastError = errno;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
/// get an input stream
|
||||||
|
/** @return stream to read from
|
||||||
|
@note invalid after destruction or @c close or @c close_in */
|
||||||
|
int istream() {
|
||||||
|
return _fd[0];
|
||||||
|
}
|
||||||
|
/// get an output stream
|
||||||
|
/** @return stream to write to
|
||||||
|
@note invalid after destruction or @c close or @c close_out */
|
||||||
|
int ostream() {
|
||||||
|
return _fd[1];
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
//@}
|
||||||
|
|
||||||
|
}
|
||||||
|
#endif
|
Reference in New Issue
Block a user