From 93696ef645b69da00be01e6db341c28991fd55c8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marc=20W=C3=A4ckerlin?= Date: Fri, 23 Apr 2004 16:03:29 +0000 Subject: [PATCH] Version 0.90 --- COPYING | 18 +++--- ChangeLog | 7 +++ NEWS | 5 ++ README | 15 ++--- bootstrap.sh | 4 ++ configure.in | 31 +++++++--- makefile.am | 23 ++++++-- mrw-c++-devel.spec.in | 42 ++++++++++++++ mrw-c++.spec.in | 46 +++++++++++++++ mrw/auto.hpp | 4 ++ mrw/autostacktracelog4cxx.cpp | 91 ++++++++++++++++++++++++++++++ mrw/autostacktracestderr.cpp | 70 ++++++++++++++++++++++- mrw/doxyfile.in | 30 +++++----- mrw/examples/exceptionhandling.cpp | 55 ++++++++++++++++++ mrw/exception.hpp | 12 +++- mrw/exec.cpp | 24 ++++---- mrw/exec.hpp | 7 ++- mrw/makefile.am | 29 +++++++--- mrw/mrw.hpp.in | 73 +++++++++++++----------- mrw/mrwexclog4cxx_test.cpp | 68 ++++++++++++++++++++++ mrw/mrwexcstderr_test.cpp | 66 ++++++++++++++++++++++ mrw/stacktrace.hpp | 38 +++++++++++++ mrw/unistd.hpp | 6 +- 23 files changed, 657 insertions(+), 107 deletions(-) create mode 100755 bootstrap.sh create mode 100644 mrw-c++-devel.spec.in create mode 100644 mrw-c++.spec.in create mode 100644 mrw/autostacktracelog4cxx.cpp create mode 100644 mrw/examples/exceptionhandling.cpp create mode 100644 mrw/mrwexclog4cxx_test.cpp create mode 100644 mrw/mrwexcstderr_test.cpp diff --git a/COPYING b/COPYING index cf9b6b9..2c24624 100644 --- a/COPYING +++ b/COPYING @@ -57,7 +57,7 @@ modified by someone else and passed on, the recipients should know that what they have is not the original version, so that the original author's reputation will not be affected by problems that might be introduced by others. -^L + Finally, software patents pose a constant threat to the existence of any free program. We wish to make sure that a company cannot effectively restrict the users of a free program by obtaining a @@ -113,7 +113,7 @@ modification follow. Pay close attention to the difference between a "work based on the library" and a "work that uses the library". The former contains code derived from the library, whereas the latter must be combined with the library in order to run. -^L + GNU LESSER GENERAL PUBLIC LICENSE TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION @@ -160,7 +160,7 @@ Library. You may charge a fee for the physical act of transferring a copy, and you may at your option offer warranty protection in exchange for a fee. - + 2. You may modify your copy or copies of the Library or any portion of it, thus forming a work based on the Library, and copy and distribute such modifications or work under the terms of Section 1 @@ -218,7 +218,7 @@ instead of to this License. (If a newer version than version 2 of the ordinary GNU General Public License has appeared, then you can specify that version instead if you wish.) Do not make any other change in these notices. -^L + Once this change is made in a given copy, it is irreversible for that copy, so the ordinary GNU General Public License applies to all subsequent copies and derivative works made from that copy. @@ -269,7 +269,7 @@ Library will still fall under Section 6.) distribute the object code for the work under the terms of Section 6. Any executables containing that work also fall under Section 6, whether or not they are linked directly with the Library itself. -^L + 6. As an exception to the Sections above, you may also combine or link a "work that uses the Library" with the Library to produce a work containing portions of the Library, and distribute that work @@ -331,7 +331,7 @@ restrictions of other proprietary libraries that do not normally accompany the operating system. Such a contradiction means you cannot use both them and the Library together in an executable that you distribute. -^L + 7. You may place library facilities that are a work based on the Library side-by-side in a single library together with other library facilities not covered by this License, and distribute such a combined @@ -372,7 +372,7 @@ subject to these terms and conditions. You may not impose any further restrictions on the recipients' exercise of the rights granted herein. You are not responsible for enforcing compliance by third parties with this License. -^L + 11. If, as a consequence of a court judgment or allegation of patent infringement or for any other reason (not limited to patent issues), conditions are imposed on you (whether by court order, agreement or @@ -425,7 +425,7 @@ conditions either of that version or of any later version published by the Free Software Foundation. If the Library does not specify a license version number, you may choose any version ever published by the Free Software Foundation. -^L + 14. If you wish to incorporate parts of the Library into other free programs whose distribution conditions are incompatible with these, write to the author to ask for permission. For software which is @@ -459,7 +459,7 @@ SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES. END OF TERMS AND CONDITIONS -^L + How to Apply These Terms to Your New Libraries If you develop a new library, and you want it to be of the greatest diff --git a/ChangeLog b/ChangeLog index e69de29..b5bc499 100644 --- a/ChangeLog +++ b/ChangeLog @@ -0,0 +1,7 @@ +* Fri Apr 24 2004 Marc Wäckerlin - mrw-c++-0.90 (mrw) + - initial rpm with two spec files + - test cases for libmrwexcstderr and libmrwexclog4cxx +* Thu Apr 23 2004 Marc Wäckerlin - mrw-c++-0.11 (mrw) + - better support for solaris, but not yet tested + - more and better documentation and a pdf file + - new submodule "Automated Unexpected Handler with Stack Trace" diff --git a/NEWS b/NEWS index e69de29..3112486 100644 --- a/NEWS +++ b/NEWS @@ -0,0 +1,5 @@ +This is a preliminary release. Especially tests, configure +environment, packages and documentation are not yet finished. It +should already work, even though it may be not yet perfect. + +It is know not to link on Solaris. \ No newline at end of file diff --git a/README b/README index 79ed0c1..a252eca 100644 --- a/README +++ b/README @@ -1,9 +1,6 @@ -Please read: - - from the .tar.gz package: - mrw/doc/html/index.html - - from the .tar.gz installation: - /usr/local/share/mrw-c++/doc/html/index.html - - from the rpm installation: - /usr/share/doc/packages/mrw-c++/doc/html/index.html - - the webpage at: - http://marc.waeckerlin.org/mrw-c++/index.html +C++ Library for automated C-Library resource management, UNIX +Pipes, simple and secure UNIX system command execution, runtime +stack trace and automated unexpected exception handling. + +HTML and PDF documentation is include in the installation (built with +Doxygen). diff --git a/bootstrap.sh b/bootstrap.sh new file mode 100755 index 0000000..805ee7d --- /dev/null +++ b/bootstrap.sh @@ -0,0 +1,4 @@ +#! /bin/sh + +make distclean +aclocal && libtoolize --force && automake && autoconf diff --git a/configure.in b/configure.in index 5e52115..5b25db9 100644 --- a/configure.in +++ b/configure.in @@ -1,9 +1,16 @@ -AC_INIT([mrw/stacktrace.hpp]) +# init +AC_INIT([mrw/mrw.hpp.in]) PACKAGENAME=mrw-c++ MAJOR=0 -MINOR=10 -SUPPORT=alfa -AM_INIT_AUTOMAKE(@PACKAGENAME@, @MAJOR@.@MINOR@) +MINOR=90 +SUPPORT=beta +AM_INIT_AUTOMAKE(@PACKAGENAME@, @MAJOR@.@MINOR@, [marc@waeckerlin.org]) + +# macros +README=README +AC_SUBST_FILE(README) +CHANGE_LOG=ChangeLog +AC_SUBST_FILE(CHANGE_LOG) # languages AC_LANG(C++) @@ -18,9 +25,18 @@ AC_PROG_LIBTOOL AC_CHECK_PROG(have_doxygen, doxygen, yes, no) AC_CHECK_PROG(have_dot, dot, yes, no) +# solaris? +AC_CHECK_HEADER(sys/old_procfs.h, [AM_CPPFLAGS=-D__solaris__]) + # libraries -AC_SEARCH_LIBS(cplus_demangle, iberty) -AC_SEARCH_LIBS(bfd_get_symbol_leading_char, bfd) +AC_SEARCH_LIBS(cplus_demangle, iberty, [AC_MSG_RESULT([OK])], + [AC_MSG_ERROR([Library iberty is required!])]) +AC_SEARCH_LIBS(bfd_arch_list, bfd, [AC_MSG_RESULT([OK])], + [ + AC_SEARCH_LIBS(bfd_arch_list, bfd, [AC_MSG_RESULT([OK])], + [AC_MSG_ERROR([BFD library libbfd is required])], + [-lintl]) + ]) # Arguments AM_MAINTAINER_MODE @@ -37,7 +53,8 @@ AC_SUBST(SUPPORT) AC_SUBST(PACKAGENAME) # create output -AC_CONFIG_FILES([makefile mrw/makefile mrw/doxyfile mrw/mrw.hpp]) +AC_CONFIG_FILES([makefile mrw-c++.spec mrw-c++-devel.spec + mrw/makefile mrw/doxyfile mrw/mrw.hpp]) AC_OUTPUT # infos and warnings diff --git a/makefile.am b/makefile.am index 648a0f9..007170a 100644 --- a/makefile.am +++ b/makefile.am @@ -1,11 +1,24 @@ SUBDIRS = mrw -include_HEADERS = mrw/auto.hpp mrw/unistd.hpp \ +nobase_include_HEADERS = mrw/auto.hpp mrw/unistd.hpp \ mrw/stacktrace.hpp mrw/exception.hpp \ mrw/exec.hpp -data_DATA = AUTHORS NEWS README COPYING INSTALL ChangeLog +infosdir = ${pkgdatadir} +infos_DATA = AUTHORS NEWS README COPYING INSTALL ChangeLog \ + @PACKAGENAME@.spec @PACKAGENAME@-devel.spec -webserver: all check doc dist +RPMS = /usr/src/packages/RPMS/i586/@PACKAGENAME@-@MAJOR@.@MINOR@-1.i586.rpm \ + /usr/src/packages/RPMS/i586/@PACKAGENAME@-devel-@MAJOR@.@MINOR@-1.i586.rpm + +rpm: dist + cp @PACKAGENAME@-@MAJOR@.@MINOR@.tar.gz /usr/src/packages/SOURCES/ + rpmbuild -bb --clean @PACKAGENAME@.spec + rpmbuild -bb --clean @PACKAGENAME@-devel.spec + +webserver: all check dist ${RPMS} ssh root@waeckerlin.org mkdir -p /home/marc/mrw-c++ - scp mrw/doc/html/* root@waeckerlin.org:/home/marc/mrw-c++/ - scp @PACKAGENAME@-@MAJOR@.@MINOR@.tar.gz root@waeckerlin.org:/home/marc/mrw-c++/ \ No newline at end of file + scp mrw/doc/html/* \ + mrw/doc/latex/@PACKAGENAME@-@MAJOR@.@MINOR@.pdf \ + @PACKAGENAME@-@MAJOR@.@MINOR@.tar.gz \ + ${RPMS} \ + root@waeckerlin.org:/home/marc/mrw-c++/ diff --git a/mrw-c++-devel.spec.in b/mrw-c++-devel.spec.in new file mode 100644 index 0000000..9f73928 --- /dev/null +++ b/mrw-c++-devel.spec.in @@ -0,0 +1,42 @@ +# rpmbuild -bb --clean @PACKAGENAME@.spec +Summary: MRW's C++ Class Library, facilities for ease and quality +Name: @PACKAGENAME@-devel +Version: @MAJOR@.@MINOR@ +Release: 1 +License: LGPL +Group: Development/Libraries/C++ +URL: http://marc.waeckerlin.org/mrw-c++/index.html +Source0: @PACKAGENAME@-@MAJOR@.@MINOR@.tar.gz +BuildRoot: %{_tmppath}/%{name}-%{version}-%{release}-buildroot + +Prefix: /usr + +Requires: gcc-c++ >= 3.0 +Requires: binutils +Requires: @PACKAGENAME@ = @MAJOR@.@MINOR@ + +%description +@README@ + +This Package contains all files required for developement. + +%prep +%setup -q -n @PACKAGENAME@-@MAJOR@.@MINOR@ +./configure --prefix=$RPM_BUILD_ROOT/usr + +%build +make check + +%install +make install +rm -rf $RPM_BUILD_ROOT/usr/lib/libmrw*.so* + +%clean +rm -rf $RPM_BUILD_ROOT + +%files +%defattr(-,root,root,-) +/usr + +%changelog +@CHANGE_LOG@ diff --git a/mrw-c++.spec.in b/mrw-c++.spec.in new file mode 100644 index 0000000..69d9927 --- /dev/null +++ b/mrw-c++.spec.in @@ -0,0 +1,46 @@ +# rpmbuild -bb --clean @PACKAGENAME@.spec +Summary: MRW's C++ Class Library, facilities for ease and quality +Name: @PACKAGENAME@ +Version: @MAJOR@.@MINOR@ +Release: 1 +License: LGPL +Group: Development/Libraries/C++ +URL: http://marc.waeckerlin.org/mrw-c++/index.html +Source0: %{name}-%{version}.tar.gz +BuildRoot: %{_tmppath}/%{name}-%{version}-%{release}-buildroot + +Prefix: /usr + +Requires: gcc-c++ >= 3.0 +Requires: binutils + +%description +@README@ + +This package contains only the shared libraries required at runtime. + +%prep +%setup -q +./configure --prefix=$RPM_BUILD_ROOT/usr + +%build +make check + +%install +make install +rm -rf $RPM_BUILD_ROOT/usr/share/mrw-c++ +rm -rf $RPM_BUILD_ROOT/usr/include/mrw +rm -rf $RPM_BUILD_ROOT/usr/lib/libmrw*.la +rm -rf $RPM_BUILD_ROOT/usr/lib/libmrw*.a +rmdir $RPM_BUILD_ROOT/usr/include +rmdir $RPM_BUILD_ROOT/usr/share + +%clean +rm -rf $RPM_BUILD_ROOT + +%files +%defattr(-,root,root,-) +/usr + +%changelog +@CHANGE_LOG@ diff --git a/mrw/auto.hpp b/mrw/auto.hpp index cab6f79..eba4375 100644 --- a/mrw/auto.hpp +++ b/mrw/auto.hpp @@ -19,6 +19,7 @@ namespace mrw { //@{ /** @brief Automatically closes a file when destructed. + @pre #include AutoFile works exactly like std::auto_ptr, but not for files instead of pointers. Whenever the context of AutoFile is left, @@ -59,6 +60,7 @@ namespace mrw { }; /** @brief Automatically call @c munmap for mmaped files on destruction. + @pre #include 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 @@ -89,6 +91,7 @@ namespace mrw { }; /** @brief Automatically call @c bfd_close for @c bfd*. + @pre #include It acts like a @c std::auto_ptr, but for @c bfd*, that means it calls @c bfd_close whenever the context is left. @@ -111,6 +114,7 @@ namespace mrw { }; /** @brief Automatically calls @c free for @c malloc allocated memory. + @pre #include It works like a @c std::auto_ptr, but for memory that was allocated with @c malloc, not @c new. Memory is freed, whenever diff --git a/mrw/autostacktracelog4cxx.cpp b/mrw/autostacktracelog4cxx.cpp new file mode 100644 index 0000000..4adb105 --- /dev/null +++ b/mrw/autostacktracelog4cxx.cpp @@ -0,0 +1,91 @@ +#include +#include +#include +#include + +namespace mrw { + + /** @addtogroup StackTrace */ + //@{ + + /** @addtogroup AutoTrace + + @section trclog4cxx Trace using the log4cxx Library + + If you link to the library @c libmrwexclog4cxx using a linker + option such as: @c -lmrwexclog4cxx, then an unexpected handler + is registered, that traces a fatal error using the log4cxx + library. You don't need to change a single line in your code! + + The log4cxx library is located at: + - http://logging.apache.org/log4cxx + + @note The configurator is not installed automatically. If you + want to trace e.g. on the console, you have to call @c + log4cxx::BasicConfigurator::configure(); as first statement in + your @c main(). + */ + //@{ + + /// The log4cxx logger where the trace is written to. + static log4cxx::LoggerPtr logger = log4cxx::Logger::getLogger(_T("libmrw")); + + /** @brief unexpected handler, that traces using log4cxx + + The unexpected handler is installed automatically when you link + to @c -lmrwexclog4cxx. The implementation of this unexpected + handler is as follows: + + @code + void unexpected_log4cxx() { + logger->fatal("Unexpected Exception", __FILE__, __LINE__); + try { + throw; + } catch (const mrw::exception& x) { + StackTrace::createSymtable(); + logger->fatal(std::string("Reason:\n")+x.what() + +"\nStack:+\n"+x.stacktrace()); + } catch (const std::exception& x) { + logger->fatal(std::string("Reason:\n")+x.what() + +"\nStack: **** not available ****"); + } catch (...) { + logger->fatal(std::string("Reason: **** not available ****\n") + +"\nStack: **** not available ****"); + } + throw std::bad_exception(); + } + @endcode + + */ + void unexpected_log4cxx() { + logger->fatal("Unexpected Exception", __FILE__, __LINE__); + try { + throw; + } catch (const mrw::exception& x) { + StackTrace::createSymtable(); + logger->fatal(std::string("Reason:\n")+x.what() + +"\nStack:+\n"+x.stacktrace()); + } catch (const std::exception& x) { + logger->fatal(std::string("Reason:\n")+x.what() + +"\nStack: **** not available ****"); + } catch (...) { + logger->fatal(std::string("Reason: **** not available ****\n") + +"\nStack: **** not available ****"); + } + throw std::bad_exception(); + } + + //@} + //@} + + class AutoStackTrace { + public: + AutoStackTrace() { + std::set_unexpected(&mrw::unexpected_log4cxx); + } + }; + + // initialize stack traces (load symbols) + static AutoStackTrace _autoStackTrace; + +} diff --git a/mrw/autostacktracestderr.cpp b/mrw/autostacktracestderr.cpp index 4cdd145..f956361 100644 --- a/mrw/autostacktracestderr.cpp +++ b/mrw/autostacktracestderr.cpp @@ -5,8 +5,69 @@ namespace mrw { - /// @todo integrate it into the distribution and document it - void unexpected() { + /** @addtogroup StackTrace */ + //@{ + + /** @defgroup AutoTrace Automated Unexpected Handler with Stack Trace + + @brief Don't care about the unexpected handler, let the library + do all the repetitive work for you. + + For all your programs it is recommended to implement an identical + unexpected handler, that rethrows, catches the @c + mrw::exception, @c std::exception and all unknown exceptions, + traces them and finally quits with a throw of a @c + atd::bad_exception. The only thing that may be different from + project to project is, how tracing is done. The MRW C++ Class + Library provides you with additional libraries you can link + to. By linking to the library, you get an unexpected handler for + free: You don't need to add a single line of code, just link to + one more library! The libraries differ in how tracing is done. + + The Implementation is done with a static instance of a class that + sets the unexpected handler in the constructor. + + @section trcstderr Trace using std::cerr + + If you link to the library @c libmrwexcstderr using a linker + option such as: @c -lmrwexcstderr, then an unexpected handler is + registered, that traces to the standard error stream @c + std::cerr. You don't need to change a single line in your code! + */ + //@{ + + /** @brief unexpected handler, that traces to @c std::cerr + + The unexpected handler is installed automatically when you link + to @c -lmrwexcstderr. The implementation of this unexpected + handler is as follows: + + @code + void unexpected_stderr() { + std::cerr<<"UNEXPECTED EXCEPTION: ----------------------------"< +#include +#include +#include + +void unexpectedHandler() { + try { + throw; + } catch (mrw::exception& x) { + mrw::StackTrace::createSymtable(); + std::cerr<<"UNEXPECTED:"< This exception class behaves exactely like @c std::exception, but it collects a stack trace in the constructor and offers a diff --git a/mrw/exec.cpp b/mrw/exec.cpp index ddc479a..b547543 100644 --- a/mrw/exec.cpp +++ b/mrw/exec.cpp @@ -85,26 +85,26 @@ mrw::Exec& mrw::Exec::operator=(const mrw::Exec& e) throw(std::bad_exception) { 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 + stdout 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) + 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) + 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=read(stdOut.istream(), buf1, sizeof(buf1)))>0 || num1==-1 && errno==EINTR || - (num2=read(stderr.istream(), buf2, sizeof(buf2)))>0 || + (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) @@ -120,10 +120,10 @@ mrw::Exec& mrw::Exec::execute(bool throwExc) throw(mrw::exception) { } } } else { // child - stdout.close_in(); - stderr.close_in(); - stdout.connect_cout(); - stderr.connect_cerr(); + stdOut.close_in(); + stdErr.close_in(); + stdOut.connect_cout(); + stdErr.connect_cerr(); execvp(_cmd->path(), _cmd->args()); exit(1); // execute failed } diff --git a/mrw/exec.hpp b/mrw/exec.hpp index ce81a90..80a5c2a 100644 --- a/mrw/exec.hpp +++ b/mrw/exec.hpp @@ -45,6 +45,7 @@ namespace mrw { class Cmd; /** @brief Exception: Execution of command failed. + @pre #include This exception is thrown, if the exection of a command in mrw::Exec is failed. That means, it was not possible to fork or @@ -64,10 +65,11 @@ namespace mrw { }; /** @brief Execute a command in a new process. + @pre #include 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. + and returns the two streams @c cout and @c cerr, also known as @c + stderr and @c 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) @@ -188,6 +190,7 @@ namespace mrw { }; /** @brief A system command to be executed + @pre #include This class is used in conjunction with mrw::Exec. It mus be initialized with the command name, then the command parameters diff --git a/mrw/makefile.am b/mrw/makefile.am index 80c0c25..b77b7d9 100644 --- a/mrw/makefile.am +++ b/mrw/makefile.am @@ -1,26 +1,31 @@ -CLEANFILES = doxygen.error AM_CPPFLAGS = -I.. +CLEANFILES = doxygen.error examplesdir = ${pkgdatadir}/examples examples_DATA = examples/* htmldir = ${pkgdatadir}/doc/html html_DATA = doc/html/* -EXTRA_DIST = test.dat ${examples_DATA} ${html_DATA} +pdfdir = ${pkgdatadir}/doc/pdf +pdf_DATA = doc/latex/@PACKAGENAME@-@MAJOR@.@MINOR@.pdf +EXTRA_DIST = test.dat ${examples_DATA} ${html_DATA} ${pdf_DATA} -lib_LTLIBRARIES = libmrw.la libmrwexcstderr.la +lib_LTLIBRARIES = libmrw.la libmrwexcstderr.la libmrwexclog4cxx.la libmrw_la_SOURCES = mrw.hpp \ auto.hpp auto.cpp unistd.hpp \ stacktrace.hpp stacktrace.cpp exception.hpp exception.cpp \ exec.hpp exec.cpp libmrw_la_LDFLAGS = -version-info @MAJOR@:@MINOR@ -libmrw_la_LIBADD = -liberty -lbfd libmrwexcstderr_la_SOURCES = autostacktracestderr.cpp libmrwexcstderr_la_LDFLAGS = -version-info @MAJOR@:@MINOR@ libmrwexcstderr_la_LIBADD = -lmrw -check_PROGRAMS = auto_test exec_test stacktrace_test +libmrwexclog4cxx_la_SOURCES = autostacktracelog4cxx.cpp +libmrwexclog4cxx_la_LDFLAGS = -version-info @MAJOR@:@MINOR@ +libmrwexclog4cxx_la_LIBADD = -lmrw + +check_PROGRAMS = auto_test exec_test stacktrace_test mrwexcstderr_test mrwexclog4cxx_test auto_test_SOURCES = auto_test.cpp auto_test_CPPFLAGS = -I.. -g3 auto_test_LDADD = -lmrw -lcppunit @@ -30,8 +35,18 @@ exec_test_LDADD = -lmrw -lcppunit stacktrace_test_SOURCES = stacktrace_test.cpp stacktrace_test_CPPFLAGS = -I.. -g3 stacktrace_test_LDADD = -lmrw -lcppunit +mrwexcstderr_test_SOURCES = mrwexcstderr_test.cpp +mrwexcstderr_test_CPPFLAGS = -I.. -g3 +mrwexcstderr_test_LDADD = -lmrwexcstderr -lcppunit +mrwexclog4cxx_test_SOURCES = mrwexclog4cxx_test.cpp +mrwexclog4cxx_test_CPPFLAGS = -I.. -g3 +mrwexclog4cxx_test_LDADD = -lmrwexclog4cxx -lcppunit -llog4cxx TESTS = ${check_PROGRAMS} -doc: doc/html/index.html -doc/html/index.html: doxyfile *.[ch]pp +deps = ../COPYING ../README ../INSTALL ../NEWS ../ChangeLog +doc: doc/html/index.html doc/latex/@PACKAGENAME@-@MAJOR@.@MINOR@.pdf +doc/html/index.html: doxyfile *.[ch]pp ${deps} doxygen doxyfile +doc/latex/@PACKAGENAME@-@MAJOR@.@MINOR@.pdf: doxyfile *.[ch]pp ${deps} + cd doc/latex && make && \ + mv refman.pdf @PACKAGENAME@-@MAJOR@.@MINOR@.pdf diff --git a/mrw/mrw.hpp.in b/mrw/mrw.hpp.in index 0230de2..34f02e0 100644 --- a/mrw/mrw.hpp.in +++ b/mrw/mrw.hpp.in @@ -1,50 +1,52 @@ /** @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. + @verbinclude README + + For details, see the "Modules" page. - @section download Download and Installation + @section download Download Download this version from here: - - http://marc.waeckerlin.org/mrw-c++/mrw-c++-@MAJOR@.@MINOR@.tar.gz - - Not yet available: - - http://marc.waeckerlin.org/mrw-c++/mrw-c++-@MAJOR@.@MINOR@.rpm - - http://marc.waeckerlin.org/mrw-c++/mrw-c++-devel-@MAJOR@.@MINOR@.rpm + - Source TAR-Ball (./configure && make all install): + - http://marc.waeckerlin.org/mrw-c++/mrw-c++-@MAJOR@.@MINOR@.tar.gz + - RPM Packages (built on i586/SuSE): + - http://marc.waeckerlin.org/mrw-c++/mrw-c++-@MAJOR@.@MINOR@-1.i586.rpm + - http://marc.waeckerlin.org/mrw-c++/mrw-c++-devel-@MAJOR@.@MINOR@-1.i586.rpm + Download this documentation in PDF: + - http://marc.waeckerlin.org/mrw-c++/mrw-c++-@MAJOR@.@MINOR@.pdf + The homepage is on: - http://marc.waeckerlin.org/mrw-c++/index.html - Install it with: - + @section usage Usage of the Library + + Include the headers you need with prefix @c mrw, e.g.: + + @verbatim + #include + @endverbatim + + Compile with debug information enabled, thats option @c -g and + link to the library with option @c -lmrw, e.g.; + @verbatim - tar xzvf mrw-c++-@MAJOR@.@MINOR@.tar.gz - cd mrw-c++-@MAJOR@.@MINOR@ - ./configure - make all check install + g++ -g -o myprogram myprogram.cpp -lmrw @endverbatim + + For the @ref AutoTools "unexpected handler" you need to link with + @c -lmrwexcstderr or @c -lmrwexclog4cxx. + + @section moreinfo Additional Information + + See the "Related Pages". + + - @ref license "License Information (LGPL)" + - @ref install "Compilation and Installation Information" + - @ref news "Breaking News" + - @ref changes "Change Log" */ /** @page license License @@ -53,6 +55,9 @@ /** @page readme Readme @verbinclude README */ +/** @page install Installation + @verbinclude INSTALL */ + /** @page news News @verbinclude NEWS */ diff --git a/mrw/mrwexclog4cxx_test.cpp b/mrw/mrwexclog4cxx_test.cpp new file mode 100644 index 0000000..b02d27a --- /dev/null +++ b/mrw/mrwexclog4cxx_test.cpp @@ -0,0 +1,68 @@ +#include +#include +#include +#include +#include +#include + +namespace mrw { + class AutoExcLog4CxxTest: public CppUnit::TestFixture { + private: + bool enter_unexpectedThrow; + bool exit_unexpectedThrow; + bool enter_passUnexpected; + bool exit_passUnexpected; + bool enter_catchUnexpected; + bool exit_catchUnexpected; + public: + void setUp() { + enter_unexpectedThrow = false; + exit_unexpectedThrow = false; + enter_passUnexpected = false; + exit_passUnexpected = false; + enter_catchUnexpected = false; + exit_catchUnexpected = false; + } + void unexpectedThrow() throw(std::bad_exception) { + enter_unexpectedThrow = true; + throw mrw::exception(); + exit_unexpectedThrow = true; + } + void passUnexpected() throw(std::bad_exception) { + enter_passUnexpected = true; + unexpectedThrow(); + exit_passUnexpected = true; + } + void catchUnexpected() throw() { + enter_catchUnexpected = true; + bool caught(false); + try { + passUnexpected(); + } catch (std::bad_exception&) { + caught = true; + } + CPPUNIT_ASSERT(caught); + exit_catchUnexpected = true; + } + void testcase() { + catchUnexpected(); + CPPUNIT_ASSERT(enter_catchUnexpected && + enter_passUnexpected && + enter_unexpectedThrow && + exit_catchUnexpected && + !exit_passUnexpected && + !exit_unexpectedThrow); + } + CPPUNIT_TEST_SUITE(AutoExcLog4CxxTest); + CPPUNIT_TEST(testcase); + CPPUNIT_TEST_SUITE_END(); + }; + CPPUNIT_TEST_SUITE_REGISTRATION(AutoExcLog4CxxTest); +} + +int main() { + log4cxx::BasicConfigurator::configure(); + CppUnit::TextUi::TestRunner runner; + runner.addTest(CppUnit::TestFactoryRegistry::getRegistry().makeTest()); + return runner.run() ? 0 : 1; +} diff --git a/mrw/mrwexcstderr_test.cpp b/mrw/mrwexcstderr_test.cpp new file mode 100644 index 0000000..c0bc5d1 --- /dev/null +++ b/mrw/mrwexcstderr_test.cpp @@ -0,0 +1,66 @@ +#include +#include +#include +#include +#include + +namespace mrw { + class AutoExcStderrTest: public CppUnit::TestFixture { + private: + bool enter_unexpectedThrow; + bool exit_unexpectedThrow; + bool enter_passUnexpected; + bool exit_passUnexpected; + bool enter_catchUnexpected; + bool exit_catchUnexpected; + public: + void setUp() { + enter_unexpectedThrow = false; + exit_unexpectedThrow = false; + enter_passUnexpected = false; + exit_passUnexpected = false; + enter_catchUnexpected = false; + exit_catchUnexpected = false; + } + void unexpectedThrow() throw(std::bad_exception) { + enter_unexpectedThrow = true; + throw mrw::exception(); + exit_unexpectedThrow = true; + } + void passUnexpected() throw(std::bad_exception) { + enter_passUnexpected = true; + unexpectedThrow(); + exit_passUnexpected = true; + } + void catchUnexpected() throw() { + enter_catchUnexpected = true; + bool caught(false); + try { + passUnexpected(); + } catch (std::bad_exception&) { + caught = true; + } + CPPUNIT_ASSERT(caught); + exit_catchUnexpected = true; + } + void testcase() { + catchUnexpected(); + CPPUNIT_ASSERT(enter_catchUnexpected && + enter_passUnexpected && + enter_unexpectedThrow && + exit_catchUnexpected && + !exit_passUnexpected && + !exit_unexpectedThrow); + } + CPPUNIT_TEST_SUITE(AutoExcStderrTest); + CPPUNIT_TEST(testcase); + CPPUNIT_TEST_SUITE_END(); + }; + CPPUNIT_TEST_SUITE_REGISTRATION(AutoExcStderrTest); +} + +int main() { + CppUnit::TextUi::TestRunner runner; + runner.addTest(CppUnit::TestFactoryRegistry::getRegistry().makeTest()); + return runner.run() ? 0 : 1; +} diff --git a/mrw/stacktrace.hpp b/mrw/stacktrace.hpp index bb25aff..1b22457 100644 --- a/mrw/stacktrace.hpp +++ b/mrw/stacktrace.hpp @@ -53,10 +53,48 @@ namespace mrw { - a system with ELF binaries (LINUX, Solaris, ...) - debug information, compile option @c -g - it must be linked with @c -libery and @c -lbfd + + @subsection sttech Technology + + On GNU glibc based systems (Linux), the stack trace is collected + with GNU glibc's function @c backtrace(). On other systems + (Solaris) it is collected using the GNU gcc's internal function @c + __builtin_return_address(). With both functions, at most 50 steps + back are collected. + + The evaluation is not done with the glibc library function @c + backtrace_symbols(), because this function is unable to print + the source file name and line number information. Instead of + this, the executable binary is loaded into the memory and + evaluated using the bdf library functions. For this the stack + tracer needs to know how to find out which executable is + running. It is possible to get this information automatically on + Linux and Solaris. On other systems, I don't have this + information, but you can either tell me, and I integrate support + for your system (when I have time to do it), or provide the + executable file name as an argument to @c + mrw::StackTrace::createSymtable(). + + @subsection stdrawbacks Draw Backs + + Unfortunately it is not possible to extract the source file name + and line number information if the executable was not compiled + with debug option @c -g. But what's worse, it is not possible to + ger symbolic information from libraries linked to the + executable. Perhaps it could be possible, if I'd add a + possibility to read and evaluate these libraries, but that's for + a future release. + + @todo Add support to read debugging information from libraries + that are linked to the executable. + + @todo Add support for alternative symbol evaluation using @c + backtrace_symbols. */ //@{ /** @brief store and print a stack trace of the actual position in code + @pre #include In the constructor, a stack trace is stored, but not yet evaluated. Therefore storing a stack trace is relatively diff --git a/mrw/unistd.hpp b/mrw/unistd.hpp index 3d5f8fb..df13834 100644 --- a/mrw/unistd.hpp +++ b/mrw/unistd.hpp @@ -8,8 +8,10 @@ namespace mrw { /** @addtogroup AutoTools */ //@{ - /// class that implements an unnamed UNIX pipe - /** Implements a UNIX pipe that is automatically closed in + /** @brief class that implements an unnamed UNIX pipe + @pre #include + + Implements a UNIX pipe that is automatically closed in destructor and offers some facilities. */ class pipe { private: