Utils: Add DiscardStream
g0dil [Mon, 23 Feb 2009 19:37:18 +0000 (19:37 +0000)]
Utils/Console: Allow adding additional config sources to a config bundle while parsing
Utils/Console: Redirect non error console output during configuration to a DiscardStream
Utils/Console: Add more information to path/directory console errors
Utils/Logger: Fix reference to destroyed areas in global destructors

git-svn-id: https://svn.berlios.de/svnroot/repos/senf/trunk@1133 270642c3-0616-0410-b53a-bc976706d245

18 files changed:
Utils/Console/Config.cc
Utils/Console/Config.cci
Utils/Console/Config.hh
Utils/Console/Config.ih
Utils/Console/ConfigFile.cc
Utils/Console/Executor.cc
Utils/Console/Executor.hh
Utils/Console/Parse.test.cc
Utils/Console/ProgramOptions.cc
Utils/Console/Server.ih
Utils/DiscardStream.cci [new file with mode: 0644]
Utils/DiscardStream.hh [new file with mode: 0644]
Utils/DiscardStream.test.cc [new file with mode: 0644]
Utils/Logger/AreaRegistry.cc
Utils/Logger/AreaRegistry.cci
Utils/Logger/AreaRegistry.ih
Utils/Logger/Target.cc
Utils/auto_unit_test.hh

index 77d712a..e6723aa 100644 (file)
@@ -120,9 +120,8 @@ prefix_ void senf::console::ConfigBundle::parse(DirectoryNode & restrict)
 
 prefix_ void senf::console::ConfigBundle::parseInternal()
 {
-    Sources::const_iterator i (sources_.begin());
-    Sources::const_iterator const i_end (sources_.end());
-    for (; i != i_end; ++i)
+    // It is valid to add additional sources at the end while parsing ...
+    for (Sources::const_iterator i (sources_.begin()); i != sources_.end(); ++i)
         (*i)->parse(executor_);
 }
 
index 46cb12f..99bccc8 100644 (file)
@@ -53,6 +53,11 @@ prefix_ senf::console::DirectoryNode & senf::console::detail::RestrictedExecutor
     return executor_.chroot();
 }
 
+prefix_ std::ostream & senf::console::detail::RestrictedExecutor::stream()
+{
+    return stream_;
+}
+
 ///////////////////////////////////////////////////////////////////////////
 // senf::console::ConfigBundle
 
index 4ef6fb0..64d9802 100644 (file)
@@ -28,6 +28,7 @@
 
 // Custom includes
 #include <boost/utility.hpp>
+#include <list>
 #include "Parse.hh"
 #include "Executor.hh"
 
@@ -94,7 +95,7 @@ namespace console {
     private:
         void parseInternal();
 
-        typedef std::vector<detail::ConfigSource::ptr> Sources;
+        typedef std::list<detail::ConfigSource::ptr> Sources;
 
         Sources sources_;
         detail::RestrictedExecutor executor_;
index bb0e55e..3c9ec54 100644 (file)
@@ -31,6 +31,7 @@
 #include <boost/intrusive_ptr.hpp>
 #include "Executor.hh"
 #include "../../Utils/intrusive_refcount.hh"
+#include "../../Utils/DiscardStream.hh"
 
 ///////////////////////////////ih.p////////////////////////////////////////
 
@@ -77,6 +78,8 @@ namespace detail {
 
         DirectoryNode & root() const;
 
+        std::ostream & stream();
+
         class RestrictGuard;
 
     protected:
@@ -90,6 +93,7 @@ namespace detail {
         Executor executor_;
         ParsedNodes parsedNodes_;
         DirectoryNode::ptr restrict_;
+        DiscardStream stream_;
 
         friend class RestrictGuard;
     };
index bbe3b3f..6674c4c 100644 (file)
@@ -39,7 +39,7 @@ prefix_ void senf::console::detail::ConfigFileSource::v_parse(RestrictedExecutor
 {
     try {
         parser_.parseFile(filename_, boost::bind( boost::ref(executor),
-                                                  boost::ref(std::cerr),
+                                                  boost::ref(executor.stream()),
                                                   _1 ));
     }
     catch (SystemException & ex) {
index 7733e07..e464906 100644 (file)
@@ -41,7 +41,7 @@
 
 namespace {
 
-    struct TraverseTokens {
+    struct TraversTokens {
         typedef std::string const & result_type;
         result_type operator()(senf::console::Token const & token) const {
             return token.value();
@@ -140,11 +140,11 @@ prefix_ void senf::console::Executor::execute(std::ostream & output,
 
         }
     }
-    catch (InvalidPathException &) {
-        throw SyntaxErrorException("invalid path");
+    catch (InvalidPathException & ex) {
+        throw SyntaxErrorException("invalid path") << " '" << ex.path << "'";
     }
-    catch (InvalidDirectoryException &) {
-        throw SyntaxErrorException("invalid directory");
+    catch (InvalidDirectoryException & ex) {
+        throw SyntaxErrorException("invalid directory") << " '" << ex.path << "'";
     }
     catch (InvalidCommandException &) {
         throw SyntaxErrorException("invalid command");
@@ -297,7 +297,12 @@ senf::console::Executor::traverseNode(ParseCommandInfo::TokensRange const & path
         return dir.back().lock()->get(name);
     }
     catch (UnknownNodeNameException &) {
-        throw InvalidPathException();
+        throw InvalidPathException(
+            senf::stringJoin(
+                senf::make_transform_range(
+                    boost::make_iterator_range(path.begin(), path.end()),
+                    boost::bind(&Token::value, _1)),
+                "/"));
     }
 }
 
@@ -305,10 +310,14 @@ prefix_ void
 senf::console::Executor::traverseDirectory(ParseCommandInfo::TokensRange const & path,
                                            Path & dir)
 {
+    std::string errorPath;
     try {
         ParseCommandInfo::TokensRange::const_iterator i (path.begin());
         ParseCommandInfo::TokensRange::const_iterator const i_end (path.end());
         for (; i != i_end; ++i) {
+            if (i != path.begin())
+                errorPath += "/";
+            errorPath += i->value();
             if (*i == NoneToken()) {
                 if (i == path.begin()) {
                     dir.clear();
index 6a950f0..9341ded 100644 (file)
@@ -148,8 +148,17 @@ namespace console {
                                Path & dir);
         std::string complete(DirectoryNode & dir, std::string const & name);
 
-        struct InvalidPathException {};
-        struct InvalidDirectoryException {};
+        struct InvalidPathException {
+            std::string path;
+            InvalidPathException() : path() {}
+            InvalidPathException(std::string path_) : path(path_) {}
+            
+        };
+        struct InvalidDirectoryException {
+            std::string path;
+            InvalidDirectoryException() : path() {}
+            InvalidDirectoryException(std::string path_) : path(path_) {}
+        };
         struct InvalidCommandException {};
         
         DirectoryNode::ptr root_;
index 7f85ac7..57fb988 100644 (file)
@@ -85,7 +85,7 @@ BOOST_AUTO_UNIT_TEST(commandGrammar)
     {
         static char text[] = 
             "# Comment\n"
-            "doo / bii / doo arg"
+            "doo/bii/doo arg/two/three"
             "                flab::blub"
             "                123.434>a"
             "                (a,b;c (huhu/{haha}))"
@@ -99,7 +99,7 @@ BOOST_AUTO_UNIT_TEST(commandGrammar)
                          grammar.use_parser<Grammar::SkipParser>() ) . full );
         BOOST_CHECK_EQUAL( ss.str(), 
                            "beginCommand( Word('doo')/Word('bii')/Word('doo') )\n"
-                           "pushToken( Word('arg') )\n"
+                           "pushToken( Word('arg/two/three') )\n"
                            "pushToken( Word('flab::blub') )\n"
                            "pushToken( Word('123.434>a') )\n"
                            "pushToken( ArgumentGroupOpen('(') )\n"
index 0efbd7e..245cce3 100644 (file)
@@ -152,7 +152,7 @@ senf::console::detail::ProgramOptionsSource::parseLongOption(std::string const &
 
     cmd.command(path);
     parser_.parseArguments(value, cmd);
-    executor(std::cerr, cmd);
+    executor(executor.stream(), cmd);
 }
 
 prefix_ void
index 5e110fa..d97c1c9 100644 (file)
@@ -70,11 +70,6 @@ namespace detail {
         : public boost::iostreams::sink
     {
     public:
-        typedef ClientSocketHandle< 
-            senf::MakeSocketPolicy<StreamFramingPolicy,
-                                   WriteablePolicy,
-                                   ConnectedCommunicationPolicy>::policy > Handle;
-
         NonblockingSocketSink(Client & client);
         std::streamsize write(const char * s, std::streamsize n);
 
diff --git a/Utils/DiscardStream.cci b/Utils/DiscardStream.cci
new file mode 100644 (file)
index 0000000..dcdd535
--- /dev/null
@@ -0,0 +1,55 @@
+// $Id$
+//
+// Copyright (C) 2009 
+// Fraunhofer Institute for Open Communication Systems (FOKUS)
+// Competence Center NETwork research (NET), St. Augustin, GERMANY
+//     Stefan Bund <g0dil@berlios.de>
+//
+// This program is free software; you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation; either version 2 of the License, or
+// (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with this program; if not, write to the
+// Free Software Foundation, Inc.,
+// 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
+
+/** \file
+    \brief DiscardStream inline non-template implementation */
+
+//#include "DiscardStream.ih"
+
+// Custom includes
+
+#define prefix_ inline
+///////////////////////////////cci.p///////////////////////////////////////
+
+prefix_ std::streamsize senf::DiscardSink::write(char const * s, std::streamsize n)
+{
+    return n;
+}
+
+prefix_ senf::DiscardStream::DiscardStream()
+{
+    open(DiscardSink());
+}
+
+///////////////////////////////cci.e///////////////////////////////////////
+#undef prefix_
+
+\f
+// Local Variables:
+// mode: c++
+// fill-column: 100
+// comment-column: 40
+// c-file-style: "senf"
+// indent-tabs-mode: nil
+// ispell-local-dictionary: "american"
+// compile-command: "scons -u test"
+// End:
diff --git a/Utils/DiscardStream.hh b/Utils/DiscardStream.hh
new file mode 100644 (file)
index 0000000..de4823b
--- /dev/null
@@ -0,0 +1,69 @@
+// $Id$
+//
+// Copyright (C) 2009 
+// Fraunhofer Institute for Open Communication Systems (FOKUS)
+// Competence Center NETwork research (NET), St. Augustin, GERMANY
+//     Stefan Bund <g0dil@berlios.de>
+//
+// This program is free software; you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation; either version 2 of the License, or
+// (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with this program; if not, write to the
+// Free Software Foundation, Inc.,
+// 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
+
+/** \file
+    \brief DiscardStream public header */
+
+#ifndef HH_SENF_Utils_DiscardStream_
+#define HH_SENF_Utils_DiscardStream_ 1
+
+// Custom includes
+#include <boost/iostreams/concepts.hpp>
+#include <boost/iostreams/stream.hpp>
+
+//#include "DiscardStream.mpp"
+///////////////////////////////hh.p////////////////////////////////////////
+
+namespace senf {
+
+    class DiscardSink
+        : public boost::iostreams::sink
+    {
+    public:
+        std::streamsize write(char const * s, std::streamsize n);
+    };
+
+    class DiscardStream
+        : public boost::iostreams::stream<DiscardSink>
+    {
+    public:
+        DiscardStream();
+    };
+
+}
+
+///////////////////////////////hh.e////////////////////////////////////////
+#include "DiscardStream.cci"
+//#include "DiscardStream.ct"
+//#include "DiscardStream.cti"
+#endif
+
+\f
+// Local Variables:
+// mode: c++
+// fill-column: 100
+// comment-column: 40
+// c-file-style: "senf"
+// indent-tabs-mode: nil
+// ispell-local-dictionary: "american"
+// compile-command: "scons -u test"
+// End:
diff --git a/Utils/DiscardStream.test.cc b/Utils/DiscardStream.test.cc
new file mode 100644 (file)
index 0000000..8214457
--- /dev/null
@@ -0,0 +1,56 @@
+// $Id$
+//
+// Copyright (C) 2009 
+// Fraunhofer Institute for Open Communication Systems (FOKUS)
+// Competence Center NETwork research (NET), St. Augustin, GERMANY
+//     Stefan Bund <g0dil@berlios.de>
+//
+// This program is free software; you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation; either version 2 of the License, or
+// (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with this program; if not, write to the
+// Free Software Foundation, Inc.,
+// 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
+
+/** \file
+    \brief DiscardStream.test unit tests */
+
+//#include "DiscardStream.test.hh"
+//#include "DiscardStream.test.ih"
+
+// Custom includes
+#include "DiscardStream.hh"
+
+#include "../Utils/auto_unit_test.hh"
+#include <boost/test/test_tools.hpp>
+
+#define prefix_
+///////////////////////////////cc.p////////////////////////////////////////
+
+BOOST_AUTO_UNIT_TEST(discardStream)
+{
+    senf::DiscardStream stream;
+    SENF_CHECK_NO_THROW( stream << "discard me" );
+}
+
+///////////////////////////////cc.e////////////////////////////////////////
+#undef prefix_
+
+\f
+// Local Variables:
+// mode: c++
+// fill-column: 100
+// comment-column: 40
+// c-file-style: "senf"
+// indent-tabs-mode: nil
+// ispell-local-dictionary: "american"
+// compile-command: "scons -u test"
+// End:
index 7a6a988..11bec47 100644 (file)
 ///////////////////////////////////////////////////////////////////////////
 // senf::log::detail::AreaBase
 
-prefix_ senf::log::detail::AreaBase::~AreaBase()
+prefix_ senf::log::detail::AreaBase::AreaBase()
+    : alive_ (true)
 {}
 
+prefix_ senf::log::detail::AreaBase::~AreaBase()
+{
+    alive_ = false;
+}
+
 prefix_ void senf::log::detail::AreaBase::updateRoutingCache(Target & target,
                                                              StreamBase const & stream,
                                                              unsigned limit)
index 76e6e51..158c007 100644 (file)
@@ -88,6 +88,12 @@ prefix_ void senf::log::detail::AreaBase::init()
     senf::log::AreaRegistry::instance().registerArea(*this);
 }
 
+prefix_ bool senf::log::detail::AreaBase::alive()
+    const
+{
+    return alive_;
+}
+
 prefix_ unsigned senf::log::detail::AreaBase::limit(StreamBase const & stream)
     const
 {
index 53b3d10..d5cd809 100644 (file)
@@ -47,12 +47,14 @@ namespace detail {
     /** \brief Internal: Area base class */
     struct AreaBase
     {
+        AreaBase();
         virtual ~AreaBase();
         
         std::string fullName() const;
         virtual std::string v_name() const;
 
         void init();
+        bool alive() const;
 
         unsigned limit(StreamBase const & stream) const;
         void updateRoutingCache(Target & target, StreamBase const & stream, unsigned limit) const; 
@@ -74,6 +76,7 @@ namespace detail {
         };
         typedef std::vector<CacheEntry> RoutingCache;
         mutable RoutingCache routingCache_;
+        bool alive_;
     };
 
 }}}
index 16b00ff..7896bf0 100644 (file)
@@ -272,6 +272,9 @@ prefix_ void senf::log::Target::updateRoutingCache(detail::StreamBase const * st
             updateRoutingCache(stream, i->second);
         return;
     }
+    if (! area->alive())
+        // We are globally destructing and the area is gone already ...
+        return;
     unsigned limit (DISABLED::value);
     RIB::iterator i (rib_.begin());
     RIB::iterator const i_end (rib_.end());
@@ -415,7 +418,7 @@ prefix_ senf::log::detail::TargetRegistry::TargetRegistry()
              "    <Directory '/sys/log/client-xxx.xxx.xxx.xxx:xxx'>\n"
              "\n"
              "Route all messages to the currently connected client\n"
-             "    $ /sys/log/self { route (); }");
+ "    $ /sys/log/self { route (); }");
 }
 
 prefix_ senf::log::detail::TargetRegistry::~TargetRegistry()
index 8b0e1bb..c12bb7d 100644 (file)
@@ -37,6 +37,7 @@
 #define HH_SENF_Utils_auto_unit_test_ 1
 
 // Custom includes
+#include <iostream>
 #include <boost/version.hpp>
 
 //#include "auto_unit_test.mpp"