Started a glossary implementation (initialized from the socket lib glossary) in Gloss...
g0dil [Thu, 24 Jan 2008 00:32:15 +0000 (00:32 +0000)]
HowTos/NewPacket: Started the packet type section
doclib: Implemented the '\autotoc' command
Packets: Add SENF_PACKET_REGISTRY_REGISTER macro

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

13 files changed:
Glossary.dox [new file with mode: 0644]
HowTos/NewPacket/Mainpage.dox
PPI/Mainpage.dox
Packets/MPEGDVBBundle/GREPacket.cc
Packets/PacketRegistry.hh
Packets/PacketType.ct [new file with mode: 0644]
Packets/PacketType.cti
Packets/PacketType.hh
Socket/Mainpage.dox
doclib/Doxyfile.global
doclib/SConscript
doclib/html-munge.xsl
doclib/senf.css

diff --git a/Glossary.dox b/Glossary.dox
new file mode 100644 (file)
index 0000000..dcbb1b2
--- /dev/null
@@ -0,0 +1,73 @@
+// $Id$
+//
+// Copyright (C) 2008 
+// 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.
+
+/** \page glossary Glossary
+
+    <table class="glossary">
+
+    <tr><td>complete policy</td> <td>libSocket</td> <td>socket policy where each axis is specified
+    completely</td></tr>
+
+    <tr><td>incomplete policy</td> <td>libSocket</td> <td>socket policy, where at least one axis is
+    not fully specified</td></tr>
+
+    <tr><td>policy axis</td> <td>libSocket</td> <td>one aspect defined in the socket policy, typedef
+    and member of the senf::SocketPolicy template</td></tr>
+
+    <tr><td>policy class</td> <td>libSocket</td> <td>implementation of a single policy axis, class
+    derived from the axis base class</td></tr>
+
+    <tr><td>policy interface</td> <td>libSocket</td> <td>interface directly provided by
+    senf::ClientSocketHandle/senf::ServerSocketHandle and defined through the policy</td>
+
+    <tr><td>policy</td> <td>libSocket</td> <td>collection of policy classes, one for each policy
+    axis, instantiation of the SocketPolicy template</td></tr>
+
+    <tr><td>protocol class</td> <td>libSocket</td> <td>definition of a protocol as a class, class
+    inheriting from senf::ConcreteSocketProtocol.</td></tr>
+
+    <tr><td>protocol facet</td> <td>libSocket</td> <td>a class providing some subset of the protocol
+    interface, class derived from senf:;SocketProtocol but not from
+    senf::ConcreteSocketProtocol</td></tr>
+
+    <tr><td>protocol interface</td> <td>libSocket</td> <td>interface provided by the protocol class
+    and accessible via the
+    senf::ProtocolClientSocketHandle::protocol()/senf::ProtocolServerSocketHandle::protocol()
+    member</td></tr>
+
+    <tr><td>socket policy</td> <td>libSocket</td> <td>another name for 'policy'</td></tr>
+
+    </table>
+ */
+
+\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"
+// mode: flyspell
+// mode: auto-fill
+// End:
index 77c649b..8f2a868 100644 (file)
 // Free Software Foundation, Inc.,
 // 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
 
-/** \mainpage libPackets: How to define and use a new Packet Type
+/** \mainpage HowTo: Defining and using a new 'libPacket' Packet Type 
 
     This howto will introduce the facilities needed to define a new packet type. As example, the
     \c GREPacket type is defined. 
 
+    \autotoc
+
+
     \section howto_newpacket_start Getting started
 
     Before starting with the implementation, we look at the specification of the GRE packet. This is
@@ -57,6 +60,7 @@
     \li The GRE packet header is a dynamically sized header.
     \li The GRE packet header utilizes the senf::EtherTypes registry for next-header selection
 
+
     \section howto_newpacket_parser Implementing the GRE Parser
 
     The next step in creating a new packet type is to implement the parser. The parser is
     these members manually but the SENF library provides a large set of helper macros which simplify
     this task considerably.
 
+
+    \subsection howto_newpacket_parser_skeleton The PacketParser skeleton
+
     \code
-    struct GREParser : public senf::PacketParser
+    struct GREPacketParser : public senf::PacketParser
     {
     #   include SENF_PARSER()
 
         // Define fields
 
-        SENF_PARSER_FINALIZE(GREParser);
+        SENF_PARSER_FINALIZE(GREPacketParser);
     };
     \endcode
 
     This is the standard skeleton of any parser class: We need to inherit senf::PacketParser and
     start out by including either \ref SENF_PARSER() or \ref SENF_FIXED_PARSER(). Which, depends on
-    whether we define a fixed size or a dynamically sized parser. As \c GREParser is dynamically
+    whether we define a fixed size or a dynamically sized parser. As \c GREPacketParser is dynamically
     sized, we include \ref SENF_PARSER().
 
     After the fields are defined, we need to call the \ref SENF_PARSER_FINALIZE() macro to close of
@@ -90,6 +97,9 @@
     go back to define the parser fields and begin with the simple part: Those fields which are
     always present.
 
+
+    \subsection howto_newpacket_parser_simple Simple field definitions
+
     \code
     SENF_PARSER_BITFIELD  ( checksumPresent, 1, bool     );
     SENF_PARSER_SKIP_BITS (                 12           );
     is defined as a dynamically sized parser, this offset is not a constant, it is an expression
     which calculates the offset of a field depending on the preceding data).
 
+
+    \subsection howto_newpacket_parser_variant Defining optional fields: The 'variant' parser
+
     We now come to the optional fields. Since there are two fields which need to be disabled/enabled
     together, we first need to define an additional sub-parser which combines those two
     fields. After this parser is defined, we can use \ref SENF_PARSER_VARIANT() to add this parser
     as an optional parser to the GRE header.
     
     \code
-    struct GREParser_OptFields : public senf::PacketParser
+    struct GREPacketParser_OptFields : public senf::PacketParser
     {
     #   include SENF_FIXED_PARSER()
 
         SENF_PARSER_FIELD ( checksum, senf::UInt16Parser );
         SENF_PARSER_SKIP  (           2                  );
 
-        SENF_PARSER_FINALIZE(GREParser_OptFields);
+        SENF_PARSER_FINALIZE(GREPacketParser_OptFields);
     };
     \endcode
 
     This parser only parses the two optional fields of which the reserved field is just skipped. The
-    parser this time is a fixed size parser. We can now use this parser to continue the \c GREParser
+    parser this time is a fixed size parser. We can now use this parser to continue the \c GREPacketParser
     implementation:
 
     \code
 
     SENF_PARSER_VARIANT   ( optionalFields,  checksumPresent,
                                              (senf::VoidPacketParser)
-                                             (GREParser_OptFields) );
+                                             (GREPacketParser_OptFields) );
     \endcode
 
     For a variant parser, two things need to be specified: A selector and a list of variant
     parser which returns a value which is implicitly convertible to \c unsigned). This value is used
     as index into the list of variant types. So in our case, 0 is associated with
     senf::VoidPacketParser whereas 1 is associated with \c
-    GREParser_OptFields. (senf::VoidPacketParser is a special empty parser which is used in a
+    GREPacketParser_OptFields. (senf::VoidPacketParser is a special empty parser which is used in a
     Variant to denote cases in which the variant parser should not parse anything)
 
-    This parser will work, it is however not very safe and not very usable. If \a p is a GREParser
+    This parser will work, it is however not very safe and not very usable. If \a p is a GREPacketParser
     instance, than we access the fields via:
     \code
     p.checksumPresent()                    = true;
     enabled, the variant parser needs to insert additional 4 bytes of data and remove those bytes,
     when the checksumPresent field is disabled. 
 
-    To fix this, we make the checksumPresent field read-only:
+
+    \subsection howto_newpacket_parser_fixvariant Fixing access by providing custom accessor members
+
+    Since we don't want to allow che \a checksumPresent() field to be changed directly, we mark this
+    field as read-only:
 
     \code
     SENF_PARSER_BITFIELD_RO ( checksumPresent,  1, bool     );
     \endcode
 
-    To change the checksumPresent value, we now need to use the variant parsers \a init member:
+    To change the \a checksumPresent() value, the variant parser provides special members to change
+    the currently selected variant:
 
     \code
     p.optionalFields().init<0>();
     p.optionalFields().init<1>();
     \endcode
     
-    The first statements switches to the first variant and therefore in this case disables the
-    checksum field. The second statement will switch to the second variant and enable the checksum
-    field. 
+    These statements also change the selector field (in this case \a checksumPresent()) to the
+    correct value: The first statements switches to the first variant and therefore in this case
+    disables the checksum field. The second statement will switch to the second variant and enable
+    the checksum field.
 
-    This again is not very usable. So we complete the parser by providing simple additional members
-    which wrap these complicated calls. While doing this, we also mark the variant as a private
-    field so it is not directly accessible any more (since we now have the additional helpers which
-    are used to access the variant, we don't want anyone to mess around with it directly). Here the
-    final \c GREParser
+    Again, these statements are relatively complex. So we complete the parser by providing simple
+    additional members which wrap these complicated calls. While doing this, we also mark the
+    variant as a private field so it is not directly accessible any more (since we now have the
+    additional helpers which are used to access the variant, we don't want anyone to mess around
+    with it directly). Here the final \c GREPacketParser
 
     \code
-    struct GREParser_OptFields : public senf::PacketParser
+    struct GREPacketParser_OptFields : public senf::PacketParser
     {
     #   include SENF_FIXED_PARSER()
 
         SENF_PARSER_FIELD           ( checksum,        senf::UInt16Parser         );
         SENF_PARSER_SKIP            (                   2                         );
 
-        SENF_PARSER_FINALIZE(GREParser_OptFields);
+        SENF_PARSER_FINALIZE(GREPacketParser_OptFields);
     };
 
-    struct GREParser : public senf::PacketParser
+    struct GREPacketParser : public senf::PacketParser
     {
     #   include SENF_PARSER()
 
 
         SENF_PARSER_PRIVATE_VARIANT ( optionalFields_, checksumPresent,
                                                          (senf::VoidPacketParser)
-                                                         (GREParser_OptFields)    );
+                                                         (GREPacketParser_OptFields)    );
 
-        typedef GREParser_OptFields::checksum_t checksum_t;
+        typedef GREPacketParser_OptFields::checksum_t checksum_t;
         checksum_t checksum() const
             { return optionalFields_().get<1>().checksum(); }
 
         void enableChecksum()  const { optionalFields_().init<1>(); }
         void disableChecksum() const { optionalFields_().init<0>(); }
     
-        SENF_PARSER_FINALIZE(GREParser);
+        SENF_PARSER_FINALIZE(GREPacketParser);
     };
     \endcode
 
     define some additional symbols providing further information about the field. Of these
     additional symbols, the most important is <em>field</em><code>_t</code>, which is the (parser)
     type returned by the field. This helps to work with a parser in more complex situations
-    (e.g. when using collection parsers) since it allows to access the parser type without exact
+    (e.g. when using \ref parsecollection) since it allows to access the parser type without exact
     knowledge of this type (which may become quite complex if templates are involved) as long as the
     field name is known. Since we provide an accessor for the \a checksum field, we also provide the
     \a checksum_t typedef for this accessor.
 
-    The \c GREParser is now simple and safe to use. The only responsibility of the user now is to
+    The \c GREPacketParser is now simple and safe to use. The only responsibility of the user now is to
     only access \a checksum() if the \a checksumPresent() field is set. Otherwise, the behavior is
     undefined (in debug builds, the parser will terminate the application with an assert).
+
+
+    \section howto_newpacket_type Defining the packet type
+
+    After we have implemented the \c GREPacketParser we need now to build the packet type. This is
+    done by providing a special policy class called the 'packet type'. This class encapsulates all
+    the information the packet library needs to know about a packet:
+
+    \subsection howto_newpacket_type_skeleton The packet type skeleton
+
+    For every type of packet, the 'packet type' class will look roughly the same. If the packet
+    utilizes a registry and is not hopelessly complex, the packet type will almost always look like
+    this:
+    \code
+    struct GREPacketType
+        : public senf::PacketTypeBase,
+          public senf::PacketTypeMixin<GREPacketType, EtherTypes>
+    {
+        typedef senf::PacketTypeMixin<GREPacketType, EtherTypes> mixin;
+        typedef senf::ConcretePacket<GREPacketType> packet;
+        typedef senf::GREPacketParser parser;
+    
+        using mixin::nextPacketRange;
+        using mixin::nextPacketType;
+        using mixin::init;
+        using mixin::initSize;
+
+        // Define members here
+    };
+    \endcode
+    We note, that \c GREPacketType derives from two classes: senf::PacketTypeBase and
+    senf::PacketTypeMixin. senf::PacketTypeBase must be inherited by every packet type class. the
+    senf::PacketTypeMixin provides default implementations for some members which are useful for
+    most kinds of packets. If a packet type is very complex and these defaults don't work, the mixin
+    class can and should be left out.
+
+    Of the typedefs, only \a parser is mandatory. It defines the packet parser to use to interpret
+    this type of packet. \a mixin and \a packet are defined to simplify the following
+    definitions (More on \a packet and senf::ConcretePacket later).
+
+    The next block of statements imports all the default implementations provided by the mixin
+    class:
+    
+    \li \a nextPacketRange provides information about where the next packet lives within the GRE
+        packet.
+    \li \a nextPacketType provides the type of the next packet from information in the GRE packet.
+    \li \a init is called to initialize a new GRE packet. This call is forwarded to \c
+        GREPacketparser::init.
+    \li \a initSize is called to find the size of an empty (newly create) GRE packet. This is also
+        provided by GREPacketParser.
+    
+    With these default implementations provided by the mixin, only a few additional members are
+    needed to complete the \c GREPacketType: \a nextPacketKey, \a finalize, and \a dump
+
+
+    \subsection howto_newpacket_type_registry Utilizing the packet registry
+
+    We want the GRE packet to utilize the senf::EtherTypes registry to find the type of packet
+    contained in the GRE payload. A registry maps an arbitrary key value to a packet type
+    represented by a packet factory instance. The details have already been taken care of by the
+    senf::PacketTypeMixin (it provides the \a nextPacketType member). However, to lookup the packet
+    in the registry, the mixin needs to know the key value. To this end, we implement \a
+    nextPacketKey(), which is very simple:
+
+    \code
+    static key_t nextPacketKey(packet p) { return p->protocolType(); }
+    \endcode
+
+    All \c GREPacketType members are static. They are passed the packet in question as an
+    argument. \a nextPacketKey() just needs to return the value of the correct packet field. And
+    since the \c parser type (as defined as a typedef) allows direct access to the packet parser
+    using the <tt>-></tt> operator, we can simply access that value.
+
+    The \c key_t return type is a typedef provided by the mixin class it is taken from the type of
+    registry, in this case it is senf::EtherTypes::key_t (which is defined as a 16 bit unsigned
+    integer value).
+
+    With this information, the packet library can now find out the type of packet needed to parse
+    the GRE payload -- as long as the protocolType() is registered with the senf::EtherTypes
+    registry. If this is not the case, the packet library will not try to interpret the payload, it
+    will return a senf::DataPacket.
+
+    One special case of GRE encapsulation occurs when layer 2 frames and especially ethernet frames
+    are carried in the GRE payload. The ETHERTYPE registry normally only contains layer 3 protocols
+    (like IP or IPX) however for this special case, the value 0x6558 has been added to the ETHERTYPE
+    registry. So we need to add this value to inform the packet library to parse the payload as an
+    ethernet packet if the \a protocolType() is 0x6558. This happens in the implementation file (the
+    \c .cc file):
+
+    \code
+    SENF_PACKET_REGISTRY_REGISTER( senf::EtherTypes, 0x6558, senf::EthernetPacket );
+    \endcode
+
+    This macro registers the value 0x6558 in the senf::EtherTypes registry and associates it with
+    the packet type senf::EthernetPacket. This macro declares an anonymous static variable, it
+    therefore must always be placed in the implementation file and \e never in an include file.
+
+    Additionally, we want the GRE packet to be parsed when present as an IP payload. Therefore we
+    additionally need to register GRE in the senf::IpTypes registry. Looking at the <a
+    href="http://www.iana.org/assignments/protocol-numbers">IP protocol numbers</a>, we find that
+    GRE has been assigned the value 47:
+
+    \code
+    SENF_PACKET_REGISTRY_REGISTER( senf::IpTypes, 47, GREPacket );
+    \endcode
+
+    But wait -- what is \c GREPacket ? This question is answered a few section farther on.
+    
+    \fixme Document the needed \c \#include files
+    \fixme Provide an advanced section with additional info: How to ensure, that the first 5 bits in
+        reserver0 are not set. How to enforce version == 0 (that is, make version() read-only and
+        return no_factory for the next packet type if any of the conditions is violated)
  */
 
 \f
index 8f4a8a8..72b5f4b 100644 (file)
 
 /** \page ppi_overview PPI Overview and Concepts
 
-    <div class="toc">
-    <div>Contents</div>
-    <ol>
-    <li>\ref ppi_design</li>
-    <li>\ref ppi_packets</li>
-    <li>\ref ppi_modules</li>
-    <li>\ref ppi_connectors</li>
-    <li>\ref ppi_connections</li>
-    <li>\ref ppi_throttling</li>
-    <li>\ref ppi_events</li>
-    <li>\ref ppi_run</li>
-    <li>\ref ppi_flows</li>
-    </ol>
-    </div>
+    \autotoc
 
     \section ppi_design Design considerations
 
index a9cdda7..90bdc5b 100644 (file)
 #define prefix_
 ///////////////////////////////cc.p////////////////////////////////////////
 
-namespace {
-    senf::PacketRegistry<senf::EtherTypes>::RegistrationProxy<senf::EthernetPacket>
-        registerTransparentEthernetBridging (0x6558);
-}
+SENF_PACKET_REGISTRY_REGISTER( senf::EtherTypes, 0x6558, senf::EthernetPacket );
 
 prefix_ void senf::GREPacketType::dump(packet p, std::ostream & os)
 {
index 6c76021..04e3177 100644 (file)
@@ -193,6 +193,19 @@ packet of which the key is requested
         static Registry & registry();
     };
 
+    /** \brief Statically add an entry to a packet registry
+
+        This macro will declare an anonymous global variable in such a way, that constructing this
+        variable will add a registration to the given packet registry.
+
+        \hideinitializer
+     */
+#   define SENF_PACKET_REGISTRY_REGISTER( registry, value, type )                                       \
+        namespace {                                                                                     \
+            senf::PacketRegistry< registry >::RegistrationProxy< type >                                 \
+                packetRegistration_ ## __LINE__ ( value );                                              \
+        }
+
     /** \brief Entry not found in registry
 
         This exception is signaled whenever a throwing lookup operation fails.
diff --git a/Packets/PacketType.ct b/Packets/PacketType.ct
new file mode 100644 (file)
index 0000000..d3cc085
--- /dev/null
@@ -0,0 +1,65 @@
+// $Id$
+//
+// Copyright (C) 2008 
+// 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 PacketType non-inline template implementation  */
+
+//#include "PacketType.ih"
+
+// Custom includes
+
+#define prefix_
+///////////////////////////////ct.p////////////////////////////////////////
+
+///////////////////////////////////////////////////////////////////////////
+// senf::PacketTypeMixin<Self,void>
+
+template <class Self>
+prefix_ senf::PacketInterpreterBase::optional_range
+senf::PacketTypeMixin<Self,void>::nextPacketRange(Packet p)
+{
+    if (p.data().size() < Self::initSize())
+        return PacketTypeBase::no_range();
+    typename Self::size_type sz (Self::initHeadSize());
+    ///\idea This if condition could be replaced with a compile time switch by checking, wether
+    /// (the function address) Self::initHeadSize is different from PacketTypeBase::initHeadSize
+    if (sz == PacketTypeBase::size_type(-1))
+        return PacketTypeBase::range(boost::next(p.data().begin(),Self::initSize()),
+                                     p.data().end());
+    else
+        return PacketTypeBase::range(boost::next(p.data().begin(),sz),
+                                     boost::prior(p.data().end(),Self::initSize()-sz));
+}
+
+///////////////////////////////ct.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 5d1ec9d..843e83a 100644 (file)
@@ -86,23 +86,6 @@ senf::PacketTypeMixin<Self,Registry>::key(Packet p)
 // senf::PacketTypeMixin<Self,void>
 
 template <class Self>
-prefix_ senf::PacketInterpreterBase::optional_range
-senf::PacketTypeMixin<Self,void>::nextPacketRange(Packet p)
-{
-    if (p.data().size() < Self::initSize())
-        return PacketTypeBase::no_range();
-    typename Self::size_type sz (Self::initHeadSize());
-    ///\idea This if condition could be replaced with a compile time switch by checking, wether
-    /// (the function address) Self::initHeadSize is different from PacketTypeBase::initHeadSize
-    if (sz == PacketTypeBase::size_type(-1))
-        return PacketTypeBase::range(boost::next(p.data().begin(),Self::initSize()),
-                                     p.data().end());
-    else
-        return PacketTypeBase::range(boost::next(p.data().begin(),sz),
-                                     boost::prior(p.data().end(),Self::initSize()-sz));
-}
-
-template <class Self>
 prefix_ senf::PacketInterpreterBase::size_type senf::PacketTypeMixin<Self,void>::initSize()
 {
     return senf::init_bytes< typename Self::parser >::value;
index 6f07b6b..e23ef09 100644 (file)
@@ -367,7 +367,7 @@ namespace senf {
 #if !defined(HH_Packets__decls_) && !defined(HH_PacketType_i_)
 #define HH_PacketType_i_
 #include "PacketType.cci"
-//#include "PacketType.ct"
+#include "PacketType.ct"
 #include "PacketType.cti"
 #endif
 
index 8e6383b..62feb85 100644 (file)
@@ -243,40 +243,6 @@ namespace senf {
     \see policy_group
  */
 
-/** \page glossary Glossary
-
-    <table class="glossary">
-
-    <tr><td>policy</td> <td>collection of policy classes, one for each policy axis, instantiation of
-    the SocketPolicy template</td></tr>
-
-    <tr><td>policy axis</td> <td>one aspect defined in the socket policy, typedef and member of the
-    SocketPolicy template</td></tr>
-
-    <tr><td>policy class</td> <td>implementation of a single policy axis, class derived from the
-    axis base class</td></tr>
-
-    <tr><td>complete policy</td> <td>socket policy where each axis is specified completely</td></tr>
-
-    <tr><td>incomplete policy</td> <td>socket policy, where at least one axis is not fully
-    specified</td></tr>
-
-    <tr><td>protocol class</td> <td>definition of a protocol as a class, class inheriting from
-    ConcreteSocketProtocol.</td></tr>
-
-    <tr><td>protocol facet</td> <td>a class providing some subset of the protocol interface, class
-    derived from SocketProtocol but not from ConcreteSocketProtocol</td></tr>
-
-    <tr><td>policy interface</td> <td>interface directly provided by
-    ClientSocketHandle/ServerSocketHandle and defined through the policy</td>
-
-    <tr><td>protocol interface</td> <td>interface provided by the protocol class and accessible via
-    the ProtocolClientSocketHandle::protocol()/ProtocolServerSocketHandle::protocol()
-    member</td></tr>
-
-    </table>
- */
-
 /** \page implementation Implementation notes
 
     \section class_diagram Class Diagram
index 2674a00..0ffed1c 100644 (file)
@@ -8,7 +8,8 @@ INPUT_FILTER           = "$(TOPDIR)/doclib/filter.pl"
 ALIASES                = "fixme=\xrefitem fixme \"Fix\" \"Fixmes\"" \
                          "idea=\xrefitem idea \"Idea\" \"Ideas\"" \
                          "implementation=\par \"Implementation note:\"" \
-                         "doc=\xrefitem doc \"Documentation request\" \"Documentation Requests\""
+                         "doc=\xrefitem doc \"Documentation request\" \"Documentation Requests\"" \
+                         "autotoc=\htmlonly <div id="autotoc"></div> \endhtmlonly"
 REPEAT_BRIEF           = YES
 ALWAYS_DETAILED_SEC    = YES
 MULTILINE_CPP_IS_BRIEF = YES
index 926b576..a9d17ec 100644 (file)
@@ -88,7 +88,7 @@ HEADER = """<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http
 <link href="@TOPDIR@/doclib/senf.css" rel="stylesheet" type="text/css">
 <link rel="shortcut icon" href="@TOPDIR@/doclib/favicon.ico">
 <style type="text/css">
-div.tabs ul li.$projectname a { background-color: #EDE497; }
+div.tabs li.$projectname a { background-color: #EDE497; }
 </style>
 </head>
 <body>
@@ -125,6 +125,7 @@ div.tabs ul li.$projectname a { background-color: #EDE497; }
 {{      for name, path, level in modules():
           <li class="${name} level${level}"><a href="@TOPDIR@/${path}/index.html">${name}</a></li>
 }}
+        <li class="glossary level0"><a href="@TOPDIR@/doc/html/glossary.html">Glossary</a></li>
       </ul>
     </div>"""
 
index 3229bf7..8efc0f8 100644 (file)
 \r
   <!-- ====================================================================== -->\r
 \r
+  <!-- Hack Glossary menu highlight -->\r
+\r
+  <xsl:template match="div[@class='tabs menu']/ul[1]">\r
+    <xsl:choose>\r
+      <xsl:when test="//h1[.//text()='Glossary']">\r
+        <xsl:call-template name="add-class">\r
+          <xsl:with-param name="class">glossary</xsl:with-param>\r
+        </xsl:call-template>\r
+      </xsl:when>\r
+      <xsl:otherwise>\r
+        <xsl:copy>\r
+          <xsl:call-template name="copy-attributes"/>\r
+          <xsl:apply-templates/>\r
+        </xsl:copy>\r
+      </xsl:otherwise>\r
+    </xsl:choose>\r
+  </xsl:template>\r
+\r
+  <!-- Autogenerate table-of-contents for a page -->\r
+\r
+  <xsl:template match="div[@id='autotoc']">\r
+    <xsl:copy>\r
+      <xsl:call-template name="copy-attributes"/>\r
+      <h1>Contents</h1>\r
+      <ul>\r
+        <xsl:for-each select="following::h2|following::h3|following::h4">\r
+          <xsl:element name="li">\r
+            <xsl:attribute name="class"><xsl:value-of select="concat('level_',local-name())"/></xsl:attribute>\r
+            <b><xsl:call-template name="section-number"/></b>\r
+            <xsl:element name="a">\r
+              <xsl:attribute name="href"><xsl:value-of select="concat('#',a/@name)"/></xsl:attribute>\r
+              <xsl:value-of select="string(current())"/>\r
+            </xsl:element>\r
+          </xsl:element>\r
+        </xsl:for-each>\r
+      </ul>\r
+    </xsl:copy>\r
+  </xsl:template>\r
+\r
+  <xsl:template name="section-number">\r
+    <xsl:number level="any" from="h1" count="h2"/>\r
+    <xsl:text>.</xsl:text>\r
+    <xsl:if test="self::h3|self::h4">\r
+      <xsl:number level="any" from="h2" count="h3"/>\r
+      <xsl:text>.</xsl:text>\r
+    </xsl:if>\r
+    <xsl:if test="self::h4">\r
+      <xsl:number level="any" from="h3" count="h4"/>\r
+      <xsl:text>.</xsl:text>\r
+    </xsl:if>\r
+    <xsl:text> </xsl:text>\r
+  </xsl:template>\r
+  \r
+  <xsl:template match="h2|h3|h4">\r
+    <xsl:copy>\r
+      <xsl:call-template name="copy-attributes"/>\r
+      <xsl:if test="preceding::div[@id='autotoc']">\r
+        <xsl:call-template name="section-number"/>\r
+      </xsl:if>\r
+      <xsl:apply-templates/>\r
+    </xsl:copy>\r
+  </xsl:template>\r
+\r
   <!-- Remove the automatically inserted search form (we build our own) -->\r
   <xsl:template match="li[form]"> \r
   </xsl:template>\r
index 368d233..be87f66 100644 (file)
@@ -184,7 +184,7 @@ div.tabs li.current span {
         padding-bottom: 6px;
 }
 
-div.tabs ul li a:hover, div.tabs ul li.current a {
+div.tabs ul li a:hover, div.tabs ul li.current a, div.tabs ul.glossary li a:hover {
         color: #726921;
         text-decoration: none;
         background-color: #EDE497;
@@ -195,6 +195,14 @@ div.tabs ul li.level1 a {
         font-size: 90%;
 }
 
+div.tabs ul.glossary li a {
+        background-color: #FDF7C3;
+}
+
+div.tabs ul.glossary li.glossary a {
+        background-color: #EDE497;
+}
+
 #footer {
         clear: both;
         padding: 4px 10px 4px 142px;
@@ -489,6 +497,29 @@ p.commalist {
         text-indent: -4em;
 }
 
+#autotoc h1 {
+        font-size: 120%;
+        text-align: left;
+}
+
+#autotoc ul {
+        list-style-type: none;
+        padding: 0;
+        margin: 1em 0 1em 2em;
+}
+
+#autotoc ul li.level_h2 {
+        margin: .5em 0 .2em 0;
+}
+
+#autotoc ul li.level_h3 {
+        margin-left: 1.5em;
+}
+
+#autotoc ul li.level_h4 {
+        margin-left: 3em;
+}
+
 /* \f
  * Local Variables:
  * indent-tabs-mode: nil