Console: Add console logging documentation
g0dil [Tue, 29 Apr 2008 23:54:00 +0000 (23:54 +0000)]
Console: Implement (and document) Server::stop()
Console: Implement working readline C-d and minnimal C-c support
Utils/Logger: Make Stream optional in routing commands

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

14 files changed:
Console/Example.dox
Console/Mainpage.dox
Console/Readline.cc
Console/Readline.cci
Console/Readline.hh
Console/Server.hh
Console/testServer.cc
Doxyfile
Mainpage.dox
Utils/Logger/Target.cti
Utils/Logger/Target.hh
Utils/Logger/Target.ih
senfscons/Mainpage.dox
senfscons/senfutil.py

index 9481834..bb39190 100644 (file)
     main-loop after shutdownServer returns (which is ultimately called via the console server from
     the scheduler). Throwing a senf::console::Executor::ExitException is like entering the \c exit
     built-in command at the console.
+
+    The next callback accesses the client instance directly to manipulate the logging:
     
-    \until Example
+    \until }
+
+    The senf::console::Client instance can be accessed using the senf::console::Client::get() helper
+    via the output stream. Since every Client is a senf::log::Target, we can route arbitrary log
+    messages to the console instance.
+
+    We now define \c main() which initializes the node tree and starts the console server
+    
+    \until route
+    
+    Here we just setup more verbose logging and set \c SIGPIPE signals to be ignored. \c SIGPIPE's
+    are a pain and really should be disabled.
+    
+    \until settings
 
-    The \c main routine enables more verbose console logging and adds some directories and callbacks
-    to the tree so we have some stuff to play around with.
+    This shows, how to set the top-level documentation and create a new subdirectory directly
 
-    The following few lines of code instantiate a \c TestObject instance and add this object's
-    directory node to the tree
+    \until mkdir
 
+    Here we create another new directory but save a reference so we can later access the node
+    directly. All the add commands return such a node reference of the correct type (this is a lie,
+    but it works like this anyways and it's an implementation detail that must not concern you
+    here).
+    
+    This way of stroing a refernce is not bad, but even better is to use a \c
+    senf::console::ScopedDirectory<> for this
+
+    \until functions
+    
+    This will automatically remove the node from the tree when the senf::console::ScopedDiretory
+    instance is destroyed and keeps the node alive even when unlinked from the tree (a plain
+    reference becomes invalid when anyone later unlinks the node from the tree). This is much safer
+    and is the preferred way to keep a hold on a directory.
+
+    The next statements add commands to the various directories declared so far
+    
     \until Example
+
+    We now continue by creating an instance of our test class \c TestObject
     
-    Now we are ready to start the server and enter the Scheduler main-loop
+    \until Example
+
+    We add that objects directory to the \c test dir. We now have created a directory structure like
+    tis:
+    <pre>
+    /
+      console/
+        showlog
+      server/
+        shutdown
+      test/
+        echo
+        testob/
+          vat
+    </pre>
+
+    We now start the server (giving it a nice descriptive name) and run the scheduler.
 
     \until }
  */
index 1b7da14..e6cf404 100644 (file)
     \endcode
 
     \see \ref console_parser
+
+
+    \section console_misc Further features
+
+    \subsection console_serverclient Server and Client objects
+
+    The senf::console::Server and senf::console::Client objects offer further API calls. To access
+    the server instance you need to store away the senf::console::Server reference returned when
+    starting the server so you can later refer to it:
+    \code
+    int main(int, char**)
+    {
+        senf::console::Server & server ( senf::console::start( ... ) );
+    
+        // Do something ...
+
+        server.stop()
+    }
+    \endcode
+
+    The client instance can be accessed via the \c std::ostream arg of any command callback
+    \code
+    void someCallback(std::ostream & os, ... )
+    {
+        senf::console::Client & client (senf::console::Client::get(os));
+    
+        // Use the client's log target
+        client.route<senf::log::Debug, senf::Log::IMPORTANT>();
+    }
+    \endcode
+
+    \see 
+        senf::console::Server for the Server API \n
+        <a href="classsenf_1_1console_1_1Client-members.html">senf::console::Client / List of all
+        members</a> for the Client API
+
+
+    \subsection console_shell Features of the interactive console shell
+
+    The interactive shell will use the GNU readline library for the first connected
+    instance. Further users will not have access to this functionality since GNU readline is
+    completely non-reentrant.
+
+    The shell supports auto-cd and auto-completion: If you enter the name of a directory at the
+    prompt, the console will change to that directory. With auto-completion, any unique beginning of
+    a path component will be completed automatically and transparently to th corresponding full
+    name.
  */
 
 /** \defgroup console_commands Supported command types
index 8d796e6..16bcfa0 100644 (file)
@@ -72,16 +72,20 @@ namespace {
     int readline_getc_function(FILE *)
     {
         if (senf::console::detail::ReadlineClientReader::active())
-            return senf::console::detail::ReadlineClientReader::instance().getc();
+            return senf::console::detail::ReadlineClientReader::instance().getc()
         else
             return -1;
     }
 
     void readline_callback(char * input)
     {
-        if (senf::console::detail::ReadlineClientReader::active() && input)
-            return senf::console::detail::ReadlineClientReader::instance().callback(
-                std::string(input) );
+        if (senf::console::detail::ReadlineClientReader::active()) {
+            if (input)
+                return senf::console::detail::ReadlineClientReader::instance().callback(
+                    std::string(input) );
+            else // input == 0 -> EOF (or Ctrl-D)
+                senf::console::detail::ReadlineClientReader::instance().eof();
+        }
     }
 
     ssize_t readline_cookie_write_function(void * cookie, char const * buffer, size_t size)
@@ -100,6 +104,14 @@ namespace {
     void readline_deprep_term()
     {}
 
+    int restart_line(int count, int key)
+    {
+        rl_kill_full_line(count, key);
+        rl_crlf();
+        rl_forced_update_display();
+        return 0;
+    }
+
 }
 
 prefix_ senf::console::detail::ReadlineClientReader::ReadlineClientReader(Client & client)
@@ -129,6 +141,7 @@ prefix_ senf::console::detail::ReadlineClientReader::ReadlineClientReader(Client
     rl_deprep_term_function = &readline_deprep_term;
     rl_getc_function = &readline_getc_function;
     rl_bind_key('\t', &rl_insert);
+    rl_bind_key('\x03', &restart_line);
     using_history();
     
     // Don't ask me, where I found this ...
@@ -191,11 +204,11 @@ prefix_ void senf::console::detail::ReadlineClientReader::charEvent(Scheduler::E
         stopClient();
         return;
     }
-    ch_ = ch;
+    ch_ = static_cast<unsigned char>(ch);
 
     if (skipChars_ > 0)
         --skipChars_;
-    else if (ch_ == static_cast<char>(0xff))
+    else if (ch_ == 0xff)
         skipChars_ = 2;
     else if (ch_ != 0)
         rl_callback_read_char();
index 8d12264..da2842c 100644 (file)
@@ -62,6 +62,12 @@ prefix_ void senf::console::detail::ReadlineClientReader::terminate()
     terminate_ = true;
 }
 
+prefix_ void senf::console::detail::ReadlineClientReader::eof()
+{
+    stream() << '\n' << std::flush;
+    stopClient();
+}
+
 ///////////////////////////////////////////////////////////////////////////
 // senf::console::detail::SafeReadlineClientReader
 
index 7a348ef..48cfb71 100644 (file)
@@ -63,6 +63,7 @@ namespace detail {
         void callback(std::string line);
         void write(std::string text);
         void terminate();
+        void eof();
         
     private:
         virtual void v_disablePrompt();
index e33be2c..dc7630d 100644 (file)
@@ -54,7 +54,6 @@ namespace console {
 
         This class provides an interactive console TCP server.
 
-        \todo Add readline support
         \todo Add interactivity detection using timeout
         \idea To support blocking commands, we could give the Client 'suspend()' and 'resume()'
             members. suspend() would probably throw some kind of exception to transfer control back
index bf41384..429d959 100644 (file)
@@ -71,37 +71,45 @@ void shutdownServer()
 
 void enableLogging(std::ostream & os)
 {
-    senf::console::Client::get(os).route<senf::SenfLog,senf::log::NOTICE>();
+    senf::console::Client::get(os).route<senf::log::NOTICE>();
 }
 
 int main(int, char **)
 {
     ::signal(SIGPIPE, SIG_IGN);
-    senf::log::ConsoleTarget::instance().route< senf::SenfLog, senf::log::NOTICE >();
+    senf::log::ConsoleTarget::instance().route< senf::log::VERBOSE >();
 
     senf::console::root()
         .doc("This is the console test application");
+
     senf::console::root()
         .mkdir("console")
         .doc("Console settings");
+
+    senf::console::DirectoryNode & serverDir (
+        senf::console::root()
+            .mkdir("server")
+            .doc("server commands") );
+
+    senf::console::ScopedDirectory<> testDir;
     senf::console::root()
-        .mkdir("test")
+        .add("test", testDir)
         .doc("Test functions");
-    senf::console::root()
-        .mkdir("server");
 
     senf::console::root()["console"]
         .add("showlog", &enableLogging)
         .doc("Enable display of log messages on the current console");
-    senf::console::root()["server"]
+
+    serverDir
         .add("shutdown", &shutdownServer)
         .doc("Terminate server application");
-    senf::console::root()["test"]
+
+    testDir
         .add("echo", &echo)
         .doc("Example of a function utilizing manual argument parsing");
 
     TestObject test;
-    senf::console::root()["test"]
+    testDir
         .add("testob", test.dir)
         .doc("Example of an instance directory");
 
index c671589..b556d23 100644 (file)
--- a/Doxyfile
+++ b/Doxyfile
@@ -13,4 +13,5 @@ TAGFILES = \
     "$(TOPDIR)/Packets/doc/Packets.tag" \
     "$(TOPDIR)/Packets/DefaultBundle/doc/DefaultBundle.tag" \
     "$(TOPDIR)/Socket/doc/Socket.tag" \
-    "$(TOPDIR)/Utils/doc/Utils.tag"
+    "$(TOPDIR)/Utils/doc/Utils.tag" \
+    "$(TOPDIR)/senfscons/doc/senfscons.tag"
index 036a1e6..f7ff985 100644 (file)
 
     The most simple way to build using SENF is to use a very simple SCons helper which automatically
     supports debug and final builds, uses SENF either centrally installed or locally built and has
-    some other nice features. See \ref senfutil for more info and an example for this utility.
+    some other nice features. See <a
+    href="../../senfscons/doc/html/index.html#senfutil_overview">Building Projects using SENF</a>
+    for more info and an example for this utility.
 
     \see \ref senf_components \n
          \ref senf_overview
index 8718906..1608c9f 100644 (file)
 
 #ifndef DOXYGEN
 
-template <class Stream>
+template <class A1>
 prefix_ void senf::log::Target::route(action_t action, int index)
 {
-    route(&Stream::instance(), 0, NONE::value, action, index);
+    route<A1,mpl::nil,mpl::nil>(action, index);
 }
 
-template <class Stream, class Level>
-prefix_ void senf::log::Target::
-route(action_t action, int index,
-      typename boost::enable_if< boost::is_convertible<Level*, detail::LevelBase *> >::type *)
-{
-    route(&Stream::instance(), 0, Level::value, action, index);
-}
-
-template <class Stream, class Area>
-prefix_ void senf::log::Target::
-route(action_t action, int index,
-      typename boost::enable_if< boost::is_convertible<Area*, detail::AreaBase *> >::type *)
-{
-    route(&Stream::instance(), &Area::instance(), NONE::value, action, index);
-}
-
-template <class Stream, class AreaClass>
-prefix_ void senf::log::Target::
-route(action_t action, int index,
-      typename boost::enable_if< boost::is_convertible<typename AreaClass::SENFLogArea *, detail::AreaBase *> >::type *)
-{
-    route(&Stream::instance(), &AreaClass::SENFLogArea::instance(), NONE::value, action, index);
-}
-
-template <class Stream, class Area, class Level>
-prefix_ void senf::log::Target::
-route(action_t action, int index,
-      typename boost::enable_if< boost::is_convertible<Area *, detail::AreaBase *> >::type *)
+template <class A1, class A2>
+prefix_ void senf::log::Target::route(action_t action, int index)
 {
-    route(&Stream::instance(), &Area::instance(), Level::value, action, index);
+    route<A1,A2,mpl::nil>(action, index);
 }
 
-template <class Stream, class AreaClass, class Level>
-prefix_ void senf::log::Target::
-route(action_t action, int index,
-      typename boost::enable_if< boost::is_convertible<typename AreaClass::SENFLogArea *, detail::AreaBase *> >::type *)
+template <class A1, class A2, class A3>
+prefix_ void senf::log::Target::route(action_t action, int index)
 {
-    route(&Stream::instance(), &AreaClass::SENFLogArea::instance(), Level::value, action, index);
+    typedef detail::RouteParameters<A1,A2,A3> Params;
+    route( detail::InstanceP<typename Params::Stream, detail::StreamBase>::value(), 
+           detail::InstanceP<typename Params::Area, detail::AreaBase>::value(), 
+           Params::Level::value, 
+           action, index);
 }
 
-// senf::log::target::ununroute
-
-template <class Stream>
+template <class A1>
 prefix_ void senf::log::Target::unroute(action_t action)
 {
-    unroute(&Stream::instance(), 0, NONE::value, action);
+    unroute<A1,mpl::nil,mpl::nil>(action);
 }
 
-template <class Stream, class Level>
-prefix_ void senf::log::Target::
-unroute(action_t action,
-      typename boost::enable_if< boost::is_convertible<Level*, detail::LevelBase *> >::type *)
-{
-    unroute(&Stream::instance(), 0, Level::value, action);
-}
-
-template <class Stream, class Area>
-prefix_ void senf::log::Target::
-unroute(action_t action,
-      typename boost::enable_if< boost::is_convertible<Area*, detail::AreaBase *> >::type *)
-{
-    unroute(&Stream::instance(), &Area::instance(), NONE::value, action);
-}
-
-template <class Stream, class AreaClass>
-prefix_ void senf::log::Target::
-unroute(action_t action,
-      typename boost::enable_if< boost::is_convertible<typename AreaClass::SENFLogArea *, detail::AreaBase *> >::type *)
-{
-    unroute(&Stream::instance(), &AreaClass::SENFLogArea::instance(), NONE::value, action);
-}
-
-template <class Stream, class Area, class Level>
-prefix_ void senf::log::Target::
-unroute(action_t action,
-      typename boost::enable_if< boost::is_convertible<Area *, detail::AreaBase *> >::type *)
+template <class A1, class A2>
+prefix_ void senf::log::Target::unroute(action_t action)
 {
-    unroute(&Stream::instance(), &Area::instance(), Level::value, action);
+    unroute<A1,A2,mpl::nil>(action);
 }
 
-template <class Stream, class AreaClass, class Level>
-prefix_ void senf::log::Target::
-unroute(action_t action,
-      typename boost::enable_if< boost::is_convertible<typename AreaClass::SENFLogArea *, detail::AreaBase *> >::type *)
+template <class A1, class A2, class A3>
+prefix_ void senf::log::Target::unroute(action_t action)
 {
-    unroute(&Stream::instance(), &AreaClass::SENFLogArea::instance(), Level::value, action);
+    typedef detail::RouteParameters<A1,A2,A3> Params;
+    unroute( detail::InstanceP<typename Params::Stream, detail::StreamBase>::value(), 
+             detail::InstanceP<typename Params::Area, detail::AreaBase>::value(), 
+             Params::Level::value, 
+             action);
 }
 
 #endif 
index 7c999b8..664f5b2 100644 (file)
@@ -71,7 +71,7 @@ namespace log {
         implementation is more efficient and utilizes a routing cache).
 
         Each routing entry consists of the following parameters
-        \li (mandatory) \e stream. The entry will match only messages directed at that stream
+        \li (optional) \e stream. The entry will match only messages directed at that stream
         \li (optional) \e area. If the area is specified, only messages directed at that area are
             matched, otherwise any area will be allowed
         \li (optional) \e level. If the log level is specified, messages will be accepted if their
@@ -193,10 +193,11 @@ namespace log {
         template <class Stream, class Area, class Level> void route(
             action_t action = ACCEPT, int index = -1); ///< Add route (static)
                                         /**< Add a route for the given combination of \a Stream, \a
-                                             Area and \a Level. The \a Stream parameter is mandatory
-                                             while either \a Area or \a Level are optional (the
-                                             template signature is shown simplified here):
+                                             Area and \a Level. All parameters (\a Stream, \a Area
+                                             and \a Level) are optional (the template signature is
+                                             shown simplified here). Examples:
                                              \code
+                                             target.route<SomeLevel>();
                                              target.route<SomeStream>();
                                              target.route<SomeStream, SomeLevel>();
                                              target.route<SomeStream, SomeArea>();
@@ -206,9 +207,9 @@ namespace log {
                                              See the class description for information on the \a
                                              action and \a index parameters 
 
-                                             \tparam Stream mandatory stream to match
-                                             \tparam Area optional area to match
-                                             \tparam Level optional level, matches messages with
+                                             \tparam Stream stream to match
+                                             \tparam Area area to match
+                                             \tparam Level level, matches messages with
                                                  at least the given level. 
                                              \param[in] action routing action to take
                                              \param[in] index position of new route in the routing
@@ -220,9 +221,9 @@ namespace log {
                    unsigned level = NONE::value, action_t action = ACCEPT, int index = -1);
                                         ///< Add route (dynamic)
                                         /**< Add a route for the given combination of \a stream, \a
-                                             area and \a level. The \a stream parameter is mandatory
-                                             while either \a area or \a level may be left
-                                             unspecified by setting them to the empty string or
+                                             area and \a level. All parameters (\a Stream, \a Area
+                                             and \a Level) are optional and may be omitted by
+                                             setting them to the empty string or the
                                              senf::log::NONE::value respectively.
 
                                              See the class description for information on the \a
@@ -233,10 +234,10 @@ namespace log {
                                              \throws InvalidAreaException if the given \a area is
                                                  not found in the AreaRegistry
 
-                                             \param[in] stream mandatory stream to match
-                                             \param[in] area optional area to match
-                                             \param[in] level optional level, matches messages with
-                                                 at least the given level.
+                                             \param[in] stream stream to match
+                                             \param[in] area area to match
+                                             \param[in] level level, matches messages with at least
+                                                 the given level.
                                              \param[in] action routing action to take
                                              \param[in] index position of new route in the routing
                                                  table */
@@ -255,9 +256,9 @@ namespace log {
                                              found, it will be removed, otherwise the call will be
                                              ignored
 
-                                             \tparam Stream mandatory stream to match
-                                             \tparam Area optional area to match
-                                             \tparam Level optional level, matches messages with
+                                             \tparam Stream stream to match
+                                             \tparam Area area to match
+                                             \tparam Level level, matches messages with
                                                  at least the given level. 
                                              \param[in] action routing action to take */
 
@@ -276,10 +277,10 @@ namespace log {
                                              found, it will be removed, otherwise the call will be
                                              ignored
 
-                                             \param[in] stream mandatory stream to match
-                                             \param[in] area optional area to match
-                                             \param[in] level optional level, matches messages with
-                                                 at least the given level.
+                                             \param[in] stream stream to match
+                                             \param[in] area area to match
+                                             \param[in] level level, matches messages with at least
+                                                 the given level.
                                              \param[in] action routing action to take */
         void unroute(int index=-1);     ///< Remove route (indexed)
                                         /**< This call will remove the route with the given index.
@@ -291,51 +292,19 @@ namespace log {
 
 #       ifndef DOXYGEN
 
-        template <class Stream> void route(
-            action_t action = ACCEPT, int index = -1);
-        template <class Stream, class Level> void route(
-            action_t action = ACCEPT, int index = -1,
-            typename boost::enable_if< boost::is_convertible<Level*,
-                                                             detail::LevelBase *> >::type * = 0);
-        template <class Stream, class Area> void route(
-            action_t action = ACCEPT, int index = -1,
-            typename boost::enable_if< boost::is_convertible<Area*,
-                                                             detail::AreaBase *> >::type * = 0);
-        template <class Stream, class AreaClass> void route(
-            action_t action = ACCEPT, int index = -1,
-            typename boost::enable_if< boost::is_convertible<typename AreaClass::SENFLogArea *,
-                                                             detail::AreaBase *> >::type * = 0);
-        template <class Stream, class Area, class Level> void route(
-            action_t action = ACCEPT, int index = -1,
-            typename boost::enable_if< boost::is_convertible<Area *,
-                                                             detail::AreaBase *> >::type * = 0);
-        template <class Stream, class AreaClass, class Level> void route(
-            action_t action = ACCEPT, int index = -1,
-            typename boost::enable_if< boost::is_convertible<typename AreaClass::SENFLogArea *,
-                                                             detail::AreaBase *> >::type * = 0);
-
-        template <class Stream> void unroute(
-            action_t action = ACCEPT);
-        template <class Stream, class Level> void unroute(
-            action_t action = ACCEPT,
-            typename boost::enable_if< boost::is_convertible<Level*,
-                                                             detail::LevelBase *> >::type * = 0);
-        template <class Stream, class Area> void unroute(
-            action_t action = ACCEPT,
-            typename boost::enable_if< boost::is_convertible<Area*,
-                                                             detail::AreaBase *> >::type * = 0);
-        template <class Stream, class AreaClass> void unroute(
-            action_t action = ACCEPT,
-            typename boost::enable_if< boost::is_convertible<typename AreaClass::SENFLogArea *,
-                                                             detail::AreaBase *> >::type * = 0);
-        template <class Stream, class Area, class Level> void unroute(
-            action_t action = ACCEPT,
-            typename boost::enable_if< boost::is_convertible<Area*,
-                                                             detail::AreaBase *> >::type * = 0);
-        template <class Stream, class AreaClass, class Level> void unroute(
-            action_t action = ACCEPT,
-            typename boost::enable_if< boost::is_convertible<typename AreaClass::SENFLogArea *,
-                                                             detail::AreaBase *> >::type * = 0);
+        template <class A1>
+        void route(action_t action = ACCEPT, int index = -1);
+        template <class A1, class A2>
+        void route(action_t action = ACCEPT, int index = -1);
+        template <class A1, class A2, class A3>
+        void route(action_t action = ACCEPT, int index = -1);
+
+        template <class A1>
+        void unroute(action_t action = ACCEPT);
+        template <class A1, class A2>
+        void unroute(action_t action = ACCEPT);
+        template <class A1, class A2, class A3>
+        void unroute(action_t action = ACCEPT);
 
 #       endif
 
index b0b61d9..d11daf0 100644 (file)
@@ -71,6 +71,74 @@ namespace detail {
     template <class Stream, class Area, class Level>
     void write(std::string msg);
 
+    senf::mpl::rv<0u> RouteParameterCheck_(...);
+    senf::mpl::rv<1u> RouteParameterCheck_(StreamBase *);
+    senf::mpl::rv<2u> RouteParameterCheck_(AreaBase *);
+    template <class T> senf::mpl::rv<3u> RouteParameterCheck_(T*, typename T::SENFLogArea * = 0);
+    senf::mpl::rv<4u> RouteParameterCheck_(LevelBase *);
+
+    template < class T, class A2, class A1,
+               unsigned type = SENF_MPL_RV( RouteParameterCheck_(static_cast<T*>(0)) ) >
+    struct RouteParameters
+    {};
+
+    template <class A2, class A1>
+    struct RouteParameters<mpl::nil,A2,A1,0u>
+        : public RouteParameters<A2,A1,mpl::nil>
+    {};
+
+    struct NilLevel {
+        static unsigned const value = NONE::value;
+    };
+
+    template <>
+    struct RouteParameters<mpl::nil,mpl::nil,mpl::nil,0u>
+    {
+        typedef mpl::nil Stream;
+        typedef mpl::nil Area;
+        typedef NilLevel Level;
+    };
+
+    template <class T, class A2, class A1>
+    struct RouteParameters<T,A2,A1,1u>
+        : public RouteParameters<A2,A1,mpl::nil>
+    {
+        typedef T Stream;
+    };
+
+    template <class T, class A2, class A1>
+    struct RouteParameters<T,A2,A1,2u>
+        : public RouteParameters<A2,A1,mpl::nil>
+    {
+        typedef T Area;
+    };
+
+    template <class T, class A2, class A1>
+    struct RouteParameters<T,A2,A1,3u>
+        : public RouteParameters<A2,A1,mpl::nil>
+    {
+        typedef typename T::SENFLogArea Area;
+    };
+
+    template <class T, class A2, class A1>
+    struct RouteParameters<T,A2,A1,4u>
+        : public RouteParameters<A2,A1,mpl::nil>
+    {
+        typedef T Level;
+    };
+
+    template <class T, class RV>
+    struct InstanceP
+    {
+        static RV * value() { return & T::instance(); }
+    };
+
+    template <class RV>
+    struct InstanceP<mpl::nil, RV>
+    {
+        static RV * value() { return 0; }
+    };
+
 }}}
 
 ///////////////////////////////ih.e////////////////////////////////////////
index 5c81984..85ea790 100644 (file)
@@ -33,8 +33,10 @@ namespace senfscons {
     href="http://www.stack.nl/~dimitri/doxygen/">Doxygen</a>. This infrastructure uses quite a bit
     of pre- and postprocessing (which is integrated with the provided Doxygen builder) to fix some
     doxygen problems and generate a (IMHO) more readable layout.
+    
+    \autotoc
 
-    \section senfutil Building Projects using SENF
+    \section senfutil_overview Building Projects using SENF
 
     When building projects using senf, SENFSCons has a very simple helper module \ref senfutil to
     make the building of libraries utilizing senf simpler:
@@ -89,11 +91,16 @@ namespace senfscons {
           LOGLEVELS='senf::log::Debug||IMPORTANT myapp::Transactions|mytrans::Area|VERBOSE'
     </pre>
 
-    \section layout The Project Layout
+    \section senfscons_intro Introduction to the SENFSCons build system
 
-    A Project using the SENFSCons infrastructure will always use a consistent directory layout. The
-    top-level directory will contain one subdirectory for every module. The main target will often
-    be considered to be just another module using the facilities provided by library modules.
+    Here we give an overview on how SENF itself is built. The SENFSCons system aims to be quite
+    flexible at separates SENF specific tasks from generic tasks to facilitate reuse.
+
+    \subsection senfscons_layout The Project Layout
+
+    The SENFSCons infrastructure will always use a consistent directory layout. The top-level
+    directory will contain one subdirectory for every module. The main target will often be
+    considered to be just another module using the facilities provided by library modules.
 
     The top-level project directory must contain the SENFSCons module in 'senfscons'.
 
@@ -105,7 +112,7 @@ namespace senfscons {
     cross-link the different module documentations. The unit-tests as well are run on a per-module
     basis.
 
-    \section Standard Build Configuration
+    \subsection senfscons_buildconf Standard Build Configuration
 
     When the \c SConsctruct and \c SConscript files are build using the default SENFSCons helpers,
     by default all libraries and binaries are built. Some additional targets are
index a0954a8..2e537d8 100644 (file)
@@ -35,8 +35,6 @@ def SetupForSENF(env):
     opts.Add( BoolOption('final', 'Build final (optimized) build', False) )
     opts.Update(env)
 
-    print env.subst('$LOGLEVELS')
-
     if env.subst('$LOGLEVELS'):
         env.Append( expandLogOption=expandLogOption )
         env.Append( CPPDEFINES = { 'SENF_LOG_CONF': '$expandLogOption' } )