diff --git a/configure.in b/configure.in new file mode 100644 index 0000000..5da78df --- /dev/null +++ b/configure.in @@ -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 diff --git a/makefile.am b/makefile.am new file mode 100644 index 0000000..86da0ee --- /dev/null +++ b/makefile.am @@ -0,0 +1 @@ +SUBDIRS = mrw diff --git a/mrw/auto.cpp b/mrw/auto.cpp new file mode 100644 index 0000000..7de5c43 --- /dev/null +++ b/mrw/auto.cpp @@ -0,0 +1,31 @@ +#include +#include // close +#include // fstat +#include // 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); + } +} diff --git a/mrw/auto.hpp b/mrw/auto.hpp new file mode 100644 index 0000000..cab6f79 --- /dev/null +++ b/mrw/auto.hpp @@ -0,0 +1,139 @@ +#ifndef __MRW_AUTO_HPP__ +#define __MRW_AUTO_HPP__ + +#include // size_t +#include // PROT_READ, MAP_SHARED +#include // 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 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 diff --git a/mrw/auto_test.cpp b/mrw/auto_test.cpp new file mode 100644 index 0000000..0822b46 --- /dev/null +++ b/mrw/auto_test.cpp @@ -0,0 +1,46 @@ +#include +#include +#include +#include +#include +#include // 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]; diff --git a/mrw/autostacktracestderr.cpp b/mrw/autostacktracestderr.cpp new file mode 100644 index 0000000..4cdd145 --- /dev/null +++ b/mrw/autostacktracestderr.cpp @@ -0,0 +1,41 @@ +#include +#include +#include +#include + +namespace mrw { + + /// @todo integrate it into the distribution and document it + void unexpected() { + std::cerr<<"UNEXPECTED EXCEPTION: ----------------------------"<