Packets: Additional example documentation on the mainpage
g0dil [Tue, 17 Jul 2007 21:17:53 +0000 (21:17 +0000)]
Packets: Documentation for PacketData and updates to PacketParsera and Packdocumentation
doclib: Add additional formating to member documentation via html-munge.xsl and senf.css (enhance brief descriptions and make auto-generated docs less obstrusive)
Add flyspell-prog-mode to project.el

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

Packets/DefaultBundle/DefaultBundle.dox
Packets/Mainpage.dox
Packets/Packet.hh
Packets/PacketData.hh
Packets/PacketParser.cti
Packets/PacketParser.hh
Packets/PacketParser.mpp
doclib/html-munge.xsl
doclib/senf.css
project.el

index 5891ca8..ad6977c 100644 (file)
@@ -26,7 +26,8 @@
 
 /** \defgroup protocolbundle_default The Default Bundle
 
-    The default bundle combines a set of basic low level protocols like Ethernet or IP.
+    The default bundle combines a set of basic low level protocols like Ethernet or IP. Find the
+    list of packet types implemented below under 'Typedefs'.
 
     \ingroup protocolbundles
  */
 // c-file-style: "senf"
 // indent-tabs-mode: nil
 // ispell-local-dictionary: "american"
-// compile-command: "scons -u test"
-// mode: flyspell
+// compile-command: "scons -u doc"
 // mode: auto-fill
-// ispell-local-dictionary: "american"
 // End:
+
+//  LocalWords:  Fraunhofer Institut fuer offene Kommunikationssysteme FOKUS de
+//  LocalWords:  Kompetenzzentrum Satelitenkommunikation SatCom Bund berlios IP
+//  LocalWords:  defgroup protocolbundles protocolbundle ingroup dil
index bb4aa52..d1437a7 100644 (file)
         parsing the packet information into meaningful values.
     \li The \ref protocolbundles provide concrete implementations for interpreting packets of
         some protocol. The Protocol Bundles are built on top of the basic packet library.
- */
 
-/*    
+    All these components work together to provide a hopefully simple and intuitive interface to
+    packet parsing and creation.
+
+    \section intro Introduction
+    
+    Most every use of the packet library starts with some concrete packet typedef. Some fundamental
+    packet typedefs are provided by \ref protocolbundle_default. The first example will build a
+    complex packet: This will be an Ethernet packet containing an IPv4 UDP packet. We begin by
+    building the raw packet skeleton:
+
+    \code
+      senf::EthernetPacket eth      (senf::EthernetPacket::create());
+      senf::IpV4Packet     ip       (senf::IpV4Packet::createAfter(ethernet));
+      senf::UDPPacket      udp      (senf::UDPPacket::createAfter(ip));
+      senf::DataPacket     payload  (senf::DataPacket::createAfter(udp, 
+                                                                   std::string("Hello, world!")));
+    \endcode
+
+    These commands create what is called an interpreter chain. This chain consists of four
+    interpreters. All interpreters reference the same data storage. This data storage is a random
+    access sequence which contains the data bytes of the packet.
+
+    \note The data structures allocated are automatically managed using reference counting. In this
+        example we have four packet references each referencing the same underlying data
+        structure. This data structure will be freed when the last reference to it goes out of
+        scope.
+
+    The packet created above already has the correct payload however all protocol fields are
+    empty. We need to set those protocol fields:
+
+    \code
+      udp->source()      = 2000u;
+      udp->destination() = 2001u;
+      ip->ttl()          = 255u;
+      ip->source()       = senf::INet4Address("192.168.0.1"); // (*)
+      ip->destination()  = senf::INet4Address("192.168.0.2"); // (*)
+      eth->source()      = senf::MACAddress("00:11:22:33:44:55");
+      eth->destination() = senf::MACAddress("00:11:22:33:44:66");
+    
+      eth.finalize(); // (*)
+    \endcode
+
+    As seen above, packet fields are accessed using the <tt>-></tt> operator whereas other packet
+    facilities (like \c finalize()) are directly accessed using the member operator. The field
+    values are simple set using appropriately named accessors. As a last step, the \c finalize()
+    call will update all calculated fields (fields like next-protocol, header or payload length,
+    checksums etc). Now the packet is ready. We may now send it out using a packet socket
+
+    \code
+      senf::PacketSocketHandle sock ("eth0");
+      sock.write(eth.data());
+    \endcode
+
+    The packet library also provides lot's of facilities to navigate the packet chain:
 
-     - ParseInt.hh: Lots of parsers for integer numbers like senf::Parse_UInt8, for integer
-       bitfields like senf::Parse_UIntField and senf::Parse_Flag to parse boolean flags.
+    \code
+      eth.next() == ip;                   // true
+      eth.next().is<IpV4Packet>();        // true
+      eth.next().next() == udp;           // true
+      eth.next().is<UDPPacket>();         // false
+      eth.next<UDPPacket>() == udp;       // true
 
-     - ParseArray.hh: The senf::Parse_Array parser to parse arbitrary fixed-size arrays of
-       fixed-size elements (that is sub-parsers).
+      udp.next<UDPPacket>();              // throws InvalidPacketChainException
+      udp.next<UDPPacket>(senf::nothrow); // a senf::Packet testing as false
+      udp.findNext<UDPPacket()> == udp;   // true
+      udp.first<IpV4Packet>() == ip;      // true
 
-     - ParseVec.hh: The senf::Parse_Vector parser to parse dynamically sized arrays of fixed-size
-       elements (that is sub-parsers).
+      udp.prev() == ip;                   // true
+      udp.prev<EthernetPacket>() == eth   // true
+    \endcode
 
-    See senf::ParserBase for further information.
+    ... and so on. It is therefore not necessary to stash away a reference for every interpreter (as
+    each of the sub-packets are called) as long as at least one reference is available.
 
-    \section stuff Other Utilities
+    These chain navigation functions are also used to parse a packet. Let's read an Ethernet packet
+    from a packet socket handle:
+    
+    \code
+      senf::PacketSocketHandle sock ("eth0");
+      senf::EthernetPacket packet (senf::EthernetPacket::create(senf::Packet::noinit));
+      sock.read(packet.data(),0u);
+    \endcode
+
+    This first creates an uninitialized Ethernet packet and then reads into this packet. We can now
+    parse this packet. Let's find out, whether this is a UDP packet destined to port 2001:
 
-    The pkf also comprises some additional utilities to support the development of packet classes.
+    \code
+      try {
+          senf::UDPPacket udp (packet.findNext<UDPPacket>(senf::nothrow));
+          if (udp && udp->destination() == 2001u) {
+              // Voila ...
+          }
+      } catch (senf::TruncatedPacketException const &) {
+          std::cerr << "Ooops !! Broken packet received ...\n"
+      }
+    \endcode
 
-    The senf::PacketRegistry implements a registry of packets keyed by an arbitrary type. The
-    registry is used to find a packet type given some kind of id (like the ethertype value from the
-    ethernet header). Together with it's support classes (especially senf::PacketRegistryMixin) this
-    class greatly simplifies implementing the needed table lookups.
+    TruncatedPacketException is thrown by <tt>udp->destination()</tt> if that field cannot be
+    accessed. More generally, whenever a field cannot be accessed because it would be out of bounds
+    of the data read, this exception is generated.
+
+    This is only a very short introduction to the library to give a feel for the implementation. For
+    a detailed discussion see the respective reference documentation.
  */
 
 \f
 // c-file-style: "senf"
 // indent-tabs-mode: nil
 // ispell-local-dictionary: "american"
-// mode: flyspell
 // mode: auto-fill
+// compile-command: "scons -u doc"
 // End:
+
+//  LocalWords:  mainpage SENF packetparser protocolbundles protocolbundle IPv4
+//  LocalWords:  udp endcode li senf EthernetPacket eth IpV createAfter ip std
+//  LocalWords:  ethernet UDPPacket DataPacket ttl INet MACAddress nothrow prev
+//  LocalWords:  PacketSocketHandle InvalidPacketChainException findNext noinit
+//  LocalWords:  tt TruncatedPacketException const cerr Ooops
index 0ef0cfd..c2c8b92 100644 (file)
@@ -104,7 +104,7 @@ namespace senf {
 
         Packet is protocol agnostic. This class only provides non-protocol dependent members. To
         access the protocol specific features of a packet (like header fields) the ConcretePacket
-        class extending Packet is povided.
+        class extending Packet is provided.
 
         \section packet_semantics Semantics
         
@@ -128,6 +128,11 @@ namespace senf {
         (protocol). For each implemented protocol, typedefs should be provided for these
         instantiations (Example: \ref EthernetPacket is a typedef for
         \ref ConcretePacket < \ref EthernetPacketType >).
+
+        \see 
+            \ref ConcretePacket for the type specific interface\n
+            \ref PacketData for the sequence interface\n
+            \ref packetparser for a specification of the parser interface
       */
     class Packet
         : public SafeBool<Packet>,
@@ -317,7 +322,7 @@ namespace senf {
                                         /**< \see valid() */
         bool valid() const;             ///< Check, whether the packet is valid()
                                         /**< An in-valid() packet does not allow any operation
-                                             except checking vor validity and assignment. in-valid()
+                                             except checking for validity and assignment. in-valid()
                                              packets serve the same role as 0-pointers. */
         
 
@@ -337,7 +342,7 @@ namespace senf {
                                         /**< This method is provided mostly to help debugging packet
                                              problems. Each concrete packet should implement a dump
                                              method writing out all fields of the packet in a
-                                             readable reresentation. dump() will call this member
+                                             readable representation. dump() will call this member
                                              for each packet/header/interpreter in the chain from \c
                                              this packet up to the end of the chain. */
 
@@ -483,7 +488,7 @@ namespace senf {
                                              \param[in] noinit This parameter must always have the
                                                  value \c senf::noinit. */
         static ConcretePacket createAfter(Packet packet, size_type size);
-                                        ///< Create default initializzed packet after \a packet
+                                        ///< Create default initialized packet after \a packet
                                         /**< This member will create a default initialized packet
                                              with the given size. If the size parameter is smaller
                                              than the minimum allowed packet size an exception will
@@ -590,3 +595,13 @@ namespace senf {
 // compile-command: "scons -u test"
 // comment-column: 40
 // End:
+
+//  LocalWords:  defgroup li html png STL ConcretePacket PacketInterpreterBase
+//  LocalWords:  PacketInterpreter PacketImpl OtherPacket EthernetPacket param
+//  LocalWords:  EthernetPacketType PacketData packetparser nothrow senf prev
+//  LocalWords:  InvalidPacketChainException findNext findPrev parseNextAs tt
+//  LocalWords:  PacketType SomePacketType createAfter createBefore noinit href
+//  LocalWords:  PacketTypeBase TruncatedPacketException http www org Institut
+//  LocalWords:  Fraunhofer fuer offene Kommunikationssysteme FOKUS SatCom Bund
+//  LocalWords:  Kompetenzzentrum Satelitenkommunikation berlios de hh
+//  LocalWords:  addtogroup Structors PacketType dil
index e7dae96..fee2c00 100644 (file)
 
 namespace senf {
 
-    /** \brief
+    /** \brief Packet data STL-sequence view
 
-        PacketData only exists to separate out the container interface from PacketInterpreter.
+        The PacketData class provides an STL-sequence compatible view of the raw packet data. Each
+        packet/header/interpreter in the chain references the same storage area, presenting a
+        different (but nested/overlapping) section of the data.
+
+        Whenever the data is manipulated through PacketData, the change is assumed to be within the
+        data range of that packet: All insertions take place \e inside \c this packet and \e outside
+        any following packets in the packet chain. 
+
+        \warning It is not permissible to change data belonging to a following
+            packet/header/interpreter even though this data is part of \c this sequence. Doing so
+            will corrupt the packet data.
+        
+        \par
+
+        \warning When accessing packet data via the PacketData interface you are on your own: The
+            packet is not validated in any way, you bypass all parsers.
+
+        All public members are those of an STL random-access sequence.
+
+        \implementation This class is very tightly integrated with PacketInterpreterBase /
+            PacketInterpreter. It is separated out of those classes primarily to provide a clean
+            sequence interface to the library user and not for implementation reasons (it would have
+            been simpler to implement all these members in PacketInterpreterBase).
+
+        \ingroup packet_module
       */
     class PacketData
         : boost::noncopyable
@@ -47,8 +71,6 @@ namespace senf {
         ///////////////////////////////////////////////////////////////////////////
         // Types
 
-        typedef senf::detail::packet::smart_pointer<PacketData>::ptr_t ptr;
-        
         typedef senf::detail::packet::iterator iterator;
         typedef senf::detail::packet::const_iterator const_iterator;
         typedef senf::detail::packet::size_type size_type;
@@ -99,15 +121,16 @@ namespace senf {
 
         ///@}
 
-        bool valid();
-
     protected:
         PacketData(size_type b, size_type e);
 
+        /// Need to make this protected so we can change it in the derived class
         detail::PacketImpl * impl_;
 
         detail::PacketImpl & impl() const;
 
+        bool valid();
+
     private:
         size_type begin_;
         size_type end_;
@@ -180,3 +203,8 @@ namespace senf {
 // compile-command: "scons -u test"
 // comment-column: 40
 // End:
+
+//  LocalWords:  Fraunhofer Institut fuer offene Kommunikationssysteme FOKUS de
+//  LocalWords:  Kompetenzzentrum Satelitenkommunikation SatCom Bund berlios dil
+//  LocalWords:  PacketData hh STL PacketInterpreterBase PacketInterpreter
+//  LocalWords:  ingroup Structors
index 826f066..4945e3d 100644 (file)
@@ -87,7 +87,7 @@ prefix_ senf::PacketParserBase::size_type senf::detail::packetParserSize(Parser
 
 template <class Parser>
 prefix_ senf::SafePacketParser<Parser>::SafePacketParser()
-    : i_()
+    : parser_(), i_()
 {}
 
 template <class Parser>
index e5eee77..a52c888 100644 (file)
@@ -1,7 +1,7 @@
 // Copyright (C) 2007 
 // Fraunhofer Institut fuer offene Kommunikationssysteme (FOKUS)
 // Kompetenzzentrum fuer Satelitenkommunikation (SatCom)
-//     Stefan Bund <g0dil@berlios.de>
+//     Stefan Bund <g0dil@berlios.be>
 //
 // 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
 /** \defgroup packetparser The PacketParser facility
     
     The PacketParser facility provides a framework to implement very lightweight classes which parse
-    the raw content of a packet into meaningful values. PacketParsers are always passed around by
-    value, they can be understood as pointers into the data structure with added type information
-    providing parsing functions.
+    the raw content of a packet into meaningful values. PacketParsers are always passed around
+    <em>by value</em>, they can be understood as pointers into the packet data with added type
+    information providing parsing functions.
 
-    Parsers are built hirarchically. A high-level parser will return other parsers when returning
-    some element (Example: Asking an EthernetParser for the ethertype field by calling the parsers
-    \c type() member will return an UInt16 parser). The lowest level building blocks then return the
+    Parsers are built hierarchically. A high-level parser will return other parsers when accessing
+    an element (Example: Asking an EthernetParser for the ethertype field by calling the parsers \c
+    type() member will return an \c UInt16 parser). The lowest level building blocks then return the
     values. This hierarchical structure greatly simplifies building complex parsers.
 
-    Every parser is derived from senf::PacketParserBase. This parser provides the necessary
-    housekeeping information and provides the parsers with access to the data.
+    Since parsers are very lightweight and are passed by value, packet fields are accessed using the
+    corresponding accessor method:
+    \code
+      SomePacket p (...)
+      SomePacket q (...)
+
+      // Assign new value to an integer parser
+      p->someField() = 10;
+
+      // Write out above value
+      std::cerr << p->someField() << "\n";
+
+      // Use the generic parser-assignment operator '<<' to copy field values
+      p->someVector()[1].someOtherField() << q->someField();
+      p->someVector() << q->someVector()
+    \endcode
 
-    The PacketParser facility predefines several parsers to be used as building blocks in defining
-    more complex parsers (integer parsers, several parsers for repetitive constructs)
+    Here \c someField(), \c someOtherField() and \c someVector() are accessor methods named after
+    the field name. Each returns a parser object. Simple parsers can be used like their
+    corresponding basic type (e.g. a Parse_UInt16 field can be used like an unsigned integer), more
+    complex parsers provide type specific access members. Assigning a value to a parser will change
+    the underlying representation (the packet data). 
+
+    More complex parsers (especially those representing a collection of values) provide an
+    additional wrapper class for mutating access (e.g. Parse_Vector provides a container wrapper
+    with am STL compatible random-access sequence interface). See the documentation of the specific
+    parser for the wrapper specification.
+
+    Every parser is derived from senf::PacketParserBase. This class provides the necessary
+    housekeeping information and provides the parsers with access to the data.
  */
 
 #ifndef HH_PacketParser_
 
 namespace senf {
     
-    /** \brief Parser Baseclass
+    /** \brief Parser Base class
+
+        Parsers come in two favors: fixed and dynamically sized parsers. A <em>fixed size
+        parser</em> has a constant size, it will always parse a fixed number of bytes. The low-level
+        'final'  parsers (like the integer parsers) are fixed size parsers as are composite parsers
+        built up only of fixed-size fields.
 
-        To implement a packet parser, you need to derive from PacketParserBase and implement several
-        required members. There are two ways how to do this.
-        \li If the parser just consists of a simple sequence of consecutive fields, the
-            SENF_PACKET_PARESR_DEFINE_FIELDS and SENF_PACKET_PARSER_DEFINE_FIXED_FIELDS macros
-            provide a simple an convenient way to define the packet
+        A <em>dynamically sized</em> parser on the other hand infers it's size from the contents of
+        the data parsed. Any parser containing at least one dynamically sized sub-parser will itself
+        be dynamically sized.
+        
+        Both kinds of parser need to derive from PacketParserBase and implement several required
+        members. Which members to implement depends on the parsers flavor. There are two ways how to
+        do this.
+        \li If the parser just consists of a simple sequence of consecutive fields (sub-parsers),
+            the \ref SENF_PACKET_PARSER_DEFINE_FIELDS and \ref
+            SENF_PACKET_PARSER_DEFINE_FIXED_FIELDS macros provide a simple and convenient way to
+            define the packet
         \li In more complex cases, you need to implement the necessary members manually.
 
-        The following example documents the interface (which must be) provided by a parser.
+        This documentation is about the manual implementation. You should nevertheless read through
+        this to understand, what above macros are doing.
+
+        The following example documents the interface (which must be) provided by a parser:
         \code
           struct FooParser : public PacketParserBase
           {
@@ -85,7 +124,7 @@ namespace senf {
               // of bytes to allocate when creating a new object
               static const size_type init_bytes = some_constant_size;
 
-              // You also mey define an init() member. This will be called to initialize a newly
+              // You also may define an init() member. This will be called to initialize a newly
               // created data object. The default implementation just does nothing.
               void init() const;
 
@@ -101,13 +140,13 @@ namespace senf {
         \endcode
         
         You should never call the \c bytes() member of a parser directly. Instead you should use the
-        freestanding senf::bytes() functon. This function will return the correct size even for
-        fixed-size parsers. You may access \c fixed_bytes directly, however be aware that this will
-        restrict your code to fixed size parsers (which depending on the circumstances may be
+        freestanding senf::bytes() function. This function will return the correct size irrespective
+        of the parsers flavor. You may access \c fixed_bytes directly, however be aware that this
+        will restrict your code to fixed size parsers (which depending on the circumstances may be
         exactly what you want).
 
-        In the same way, dont access \c init_bytes directly, always use the senf::init_bytes
-        metafunction class which will correctly support fixed size parsers.
+        In the same way, don't access \c init_bytes directly, always use the senf::init_bytes
+        meta-function class which correctly supports fixed size parsers.
 
         \ingroup packetparser
       */
@@ -117,11 +156,11 @@ namespace senf {
         ///////////////////////////////////////////////////////////////////////////
         // Types
 
-        typedef detail::packet::iterator data_iterator;
-        typedef detail::packet::size_type size_type;
-        typedef detail::packet::difference_type difference_type;
-        typedef detail::packet::byte byte;
-        typedef PacketData * state_type;
+        typedef detail::packet::iterator data_iterator; ///< Raw data iterator type
+        typedef detail::packet::size_type size_type; ///< Unsigned integral type
+        typedef detail::packet::difference_type difference_type; ///< Signed integral type
+        typedef detail::packet::byte byte; ///< Unsigned 8bit value, the raw value type
+        typedef PacketData * state_type; ///< Type of the 'state' parameter
 
         ///////////////////////////////////////////////////////////////////////////
         ///\name Structors and default members
@@ -135,23 +174,68 @@ namespace senf {
         ///@}
         ///////////////////////////////////////////////////////////////////////////
 
-        data_iterator i() const;
-        state_type state() const;
-        PacketData & data() const;
-
-        void init() const;
+        data_iterator i() const;        ///< Return beginning of data to parse
+                                        /**< The parser is expected to interpret the data beginning
+                                             here. The size of the interpreted is given by
+                                             <tt>senf::bytes(</tt><em>parser
+                                             instance</em><tt>)</tt>. */
+        state_type state() const;       ///< Return state of this parser
+                                        /**< The value returned should be interpreted as an opaque
+                                             value provided just to be forwarded to other
+                                             parsers. */
+        PacketData & data() const;      ///< Access the packets raw data container
+                                        /**< This member will return the raw data container holding
+                                             the data which is parsed by \c this parser. */
+
+        void init() const;              ///< Default implementation
+                                        /**< This is just an empty default
+                                             implementation. Re-implement this member in your own
+                                             parsers if needed. */
 
     protected:
-        PacketParserBase(data_iterator i, state_type s);
-        PacketParserBase(data_iterator i, state_type s, size_type size);
-
-        bool check(size_type size);
-        void validate(size_type size);
-
-        template <class Parser> Parser parse(data_iterator i) const;
-        template <class Parser> Parser parse(size_type n) const;
-
-        void defaultInit() const;
+        PacketParserBase(data_iterator i, state_type s); ///< Standard constructor
+                                        /**< This is the constructor used by most parsers. The
+                                             parameters are just forwarded from the derived classes
+                                             constructor parameters. */
+        PacketParserBase(data_iterator i, state_type s, size_type size); 
+                                        ///< Size checking constructor
+                                        /**< In addition to the standard constructor, this
+                                             constructor will validate, that there is enough data in
+                                             the raw data container to parse \a size bytes after \a
+                                             i.
+
+                                             This constructor is called by all 'final' parsers
+                                             (e.g. the integer parsers) and \e only by those
+                                             parsers. Most parsers do \e not check the validity of
+                                             the iterator, this is delayed until the very last
+                                             parser. This allows to partial parse truncated
+                                             packets.
+
+                                             \throw TruncatedPacketException if the raw data
+                                                 container does not hold at least \a size bytes
+                                                 beginning at \a i. */
+
+        bool check(size_type size);     ///< Check size of data container
+                                        /**< \returns \c true, if the data container holds at least
+                                             \a size beginning at i(), \c false otherwise. */
+        void validate(size_type size);  ///< Validate size of data container
+                                        /**< \throws TruncatedPacketException if the raw data
+                                             container does not hold at least \a size bytes
+                                             beginning at i(). */
+
+        template <class Parser> Parser parse(data_iterator i) const; ///< Create sub-parser
+                                        /**< Creates a new instance of \a Parser to parse data
+                                             beginning at \a i. Automatically passes \a state() to
+                                             the new parser. */
+        template <class Parser> Parser parse(size_type n) const; ///< Create sub-parser
+                                        /**< Creates a new instance of \a Parser to parse data
+                                         * beginning at i()<tt> + </tt>\a n. Automatically passes \a
+                                             state() to the new parser. */
+
+        void defaultInit() const;       ///< Default implementation
+                                        /**< This is just an empty default
+                                             implementation. Re-implement this member in your own
+                                             parsers if needed. */
 
     private:
         data_iterator end();
@@ -183,16 +267,16 @@ namespace senf {
 
     /** \brief Return number of bytes to allocate to new object of given type
 
-        This metafcuntion is called like
+        This meta-function is called like
         \code
             senf::init_bytes<SomeParser>::value
         \endcode
 
-        This expression evaluates to a compile-time constant itegral expression of type
-        senf::PacketParserBase::size_type. This metafunction will return \c Parser::fixed_bytes or
+        This expression evaluates to a compile-time constant integral expression of type
+        senf::PacketParserBase::size_type. This meta-function will return \c Parser::fixed_bytes or
         \c Parser::init_bytes depending on the type of parser.
 
-        \param[in] Parser Parser to return init_bytes for
+        \param[in] Parser The Parser to return init_bytes for
         \returns Number of bytes to allocate to the new object
         \ingroup packetparser
      */
@@ -200,12 +284,32 @@ namespace senf {
     struct init_bytes : public detail::ParserInitBytes<Parser>
     {};
 
+    /** \brief Generic parser copying
+
+        This operator allows to copy the values of identical parsers. This operation does \e not
+        depend on the parsers detailed implementation, it will just replace the data bytes of the
+        target parser with those from the source parser. This allows to easily copy around complex
+        packet substructures.
+
+        This operation is different from the ordinary assignment operator: It does not change the \a
+        target parser, it changes the data referenced by the \a target parser.
+
+        \ingroup packetparser
+     */
     template <class Parser>
     typename boost::enable_if< 
         boost::is_base_of<PacketParserBase, Parser>,
         Parser >::type
     operator<<(Parser target, Parser source);
 
+    /** \brief Generic parser value assignment
+
+        This operator allows to assign a value to parsers which implement a <tt>value(</tt>\a
+        value<tt>)</tt> member. This operator allows to use a common syntax for assigning values or
+        parsers to a parser. 
+
+        \ingroup packetparser
+     */
     template <class Parser, class Value>
     typename boost::enable_if_c < 
         boost::is_base_of<PacketParserBase, Parser>::value 
@@ -216,7 +320,7 @@ namespace senf {
     /** \defgroup packetparsermacros Helper macros for defining new packet parsers
         
         To simplify the definition of simple packet parsers, several macros are provided. Before
-        using these macros you should familarize yourself with the packet parser interface as
+        using these macros you should familiarize yourself with the packet parser interface as
         described in senf::PacketParserBase.
 
         These macros simplify providing the above defined interface. A typical packet declaration
@@ -273,6 +377,13 @@ namespace senf {
           )
         \endcode
         
+        For each field, this command will define
+        \li A method \a name() returning an instance of the \a type parser
+        \li \a name<tt>_t</tt> as a typedef for \a type, the fields value
+        \li \a name<tt>_offset</tt> to give the offset of the field from the beginning of the
+            parser. If the parser is a fixed size parser, this will be a static constant, otherwise
+            it will be a method.
+
         The \a builder argument selects, how the field is defined
         \li <tt>Field</tt> defines a field and increments the current position by the size of the
             field
@@ -284,10 +395,10 @@ namespace senf {
         The \a name argument defines the name of the accessor method.
 
         The \a type argument is the parser to return for that field. Since none of the arguments may
-        contain a komma, <em>This argument cannot be a template</em>. Always use typedefs to access
-        tempalte parsers as shown above.
+        contain a comma, <em>This argument cannot be a multi-parameter template</em>. Always use
+        typedefs to access templated parsers as shown above.
 
-        The \ref SENF_PACKET_PARSER_INIT makro defines the constructor and the \c init() member. If
+        The \ref SENF_PACKET_PARSER_INIT macro defines the constructor and the \c init() member. If
         you want to provide your own \c init() implementation, use \ref
         SENF_PACKET_PARSER_NO_INIT. The first statement in your init method should probably to call
         \c defaultInit(). This will call the \c init() member of all the fields. Afterwards you can
@@ -331,7 +442,7 @@ namespace senf {
     name(data_iterator i, state_type s) : senf::PacketParserBase(i,s) {}                          \
     void init() const { defaultInit(); }
 
-    /** \brief Define initialization mebers of a parser except init()
+    /** \brief Define initialization members of a parser except init()
         
         This macro is like SENF_PACKET_PARSER_INIT but does \e not define \c init(). This allows you
         to provide your own implementation. You should call \c defaultInit() first before
@@ -371,7 +482,20 @@ namespace senf {
         SENF_PACKET_PARSER_INIT(VoidPacketParser);
     };
 
-    /** \brief
+    /** \brief Iterator re-validating Parser wrapper
+
+        An ordinary parser will be invalidated whenever the raw data container's size is
+        changed. This can complicate some algorithms considerably.
+
+        This wrapper will update the parsers iterator (the value returned by the i() member) on
+        every access. This ensures that the iterator will stay valid.
+
+        \attention Beware however, if you insert or remove data before the safe wrapper, the
+            location will \e not be updated accordingly and therefore the parser will be
+            invalid.
+
+        Additionally a SafePacketparser has an uninitialized state. The only allowed operations in
+        this state are the boolean test for validity and assigning another parser.
       */
     template <class Parser>
     class SafePacketParser
@@ -385,23 +509,26 @@ namespace senf {
         ///\name Structors and default members
         ///@{
 
-        // default default constructor
         // default copy constructor
         // default copy assignment
         // default destructor
-        SafePacketParser();
+        SafePacketParser();             ///< Create an empty uninitialized SafePacketParser
 
         // conversion constructors
-        SafePacketParser(Parser parser);
+        SafePacketParser(Parser parser); ///< Initialize SafePacketParser from \a parser
 
-        SafePacketParser & operator=(Parser parser);
+        SafePacketParser & operator=(Parser parser); ///< Assign \a parser to \c this
 
         ///@}
         ///////////////////////////////////////////////////////////////////////////
 
-        Parser operator*() const;
-        Parser const * operator->() const;
-        bool boolean_test() const;
+        Parser operator*() const;       ///< Access the stored parser
+                                        /**< On every access, the stored parsers iterator will be
+                                             updated / re-validated. */
+        Parser const * operator->() const; ///< Access the stored parser
+                                        /**< On every access, the stored parsers iterator will be
+                                             updated / re-validated. */
+        bool boolean_test() const;      ///< Check validity
 
     protected:
 
@@ -428,3 +555,14 @@ namespace senf {
 // compile-command: "scons -u test"
 // comment-column: 40
 // End:
+
+//  LocalWords:  templated PacketParser defgroup packetparser PacketParsers li
+//  LocalWords:  EthernetParser ethertype UInt senf PacketParserBase tt
+//  LocalWords:  struct FooParser const init endcode ingroup param SomeParser
+//  LocalWords:  ethernet DefaultBundle EthernetPacket hh EthVLan UIntField CFI
+//  LocalWords:  VLanId OverlayField cfi vlanId accessor defaultInit bitfield
+//  LocalWords:  SomePacket SimpleVectorSizer packetparsermacros Fraunhofer std
+//  LocalWords:  hideinitializer Institut fuer offene Kommunikationssysteme STL
+//  LocalWords:  FOKUS Kompetenzzentrum Satelitenkommunikation SatCom Bund cerr
+//  LocalWords:  berlios dil Structors someField someVector someOtherField
+//  LocalWords:  TruncatedPacketException
index 7c72a96..581ef30 100644 (file)
 # define SENF_PACKET_PARSER_I_GET_TYPE_1(x) SENF_PACKET_PARSER_I_GET_TYPE_2
 # define SENF_PACKET_PARSER_I_GET_TYPE_2(name,type) type
 # 
-# define SENF_PACKET_PARSER_I_DEFINE_INIT_C(_0,_1,elt)                                             \
+# define SENF_PACKET_PARSER_I_DEFINE_INIT_C(_0,_1,elt)                                            \
      SENF_PACKET_PARSER_I_GET_NAME(elt) ().init();
 # 
-# define SENF_PACKET_PARSER_I_DEFINE_INIT(fields)                                                  \
-     void defaultInit() const {                                                                    \
-         BOOST_PP_SEQ_FOR_EACH( SENF_PACKET_PARSER_I_DEFINE_INIT_C, _, fields)                     \
+# define SENF_PACKET_PARSER_I_DEFINE_INIT(fields)                                                 \
+     void defaultInit() const {                                                                   \
+         BOOST_PP_SEQ_FOR_EACH( SENF_PACKET_PARSER_I_DEFINE_INIT_C, _, fields)                    \
      }
 # 
-# define SENF_PACKET_PARSER_I_FIELD_DISPATCH(n,t,name,type)                                        \
+# define SENF_PACKET_PARSER_I_FIELD_DISPATCH(n,t,name,type)                                       \
      SENF_PACKET_PARSER_I_ ## t(n,name,type)
 # 
-# define SENF_PACKET_PARSER_I_FIELD_C(_0,_1,n,elt)                                                 \
-     BOOST_PP_EXPAND(                                                                              \
+# define SENF_PACKET_PARSER_I_FIELD_C(_0,_1,n,elt)                                                \
+     BOOST_PP_EXPAND(                                                                             \
          SENF_PACKET_PARSER_I_FIELD_DISPATCH SENF_PACKET_PARSER_I_UNWRAP(n,elt))
 # 
-# define SENF_PACKET_PARSER_I_INITSIZE_C(_0,_1,n,elt)                                              \
+# define SENF_PACKET_PARSER_I_INITSIZE_C(_0,_1,n,elt)                                             \
      BOOST_PP_IF(n,+,) senf::init_bytes< SENF_PACKET_PARSER_I_GET_TYPE(elt) >::value
 #     
-# define SENF_PACKET_PARSER_I_DEFINE_FIELDS(fields)                                                \
-     size_type offset_0_() const { return 0; }                                                     \
-     BOOST_PP_SEQ_FOR_EACH_I(SENF_PACKET_PARSER_I_FIELD_C, _, fields)                              \
-     size_type bytes() const {                                                                     \
-         return BOOST_PP_CAT(offset_,BOOST_PP_CAT(BOOST_PP_SEQ_SIZE(fields),_)) ();                \
-     }                                                                                             \
-     SENF_PACKET_PARSER_I_DEFINE_INIT(fields)                                                      \
-     static const size_type init_bytes =                                                           \
+# define SENF_PACKET_PARSER_I_DEFINE_FIELDS(fields)                                               \
+     size_type offset_0_() const { return 0; }                                                    \
+     BOOST_PP_SEQ_FOR_EACH_I(SENF_PACKET_PARSER_I_FIELD_C, _, fields)                             \
+     size_type bytes() const {                                                                    \
+         return BOOST_PP_CAT(offset_,BOOST_PP_CAT(BOOST_PP_SEQ_SIZE(fields),_)) ();               \
+     }                                                                                            \
+     SENF_PACKET_PARSER_I_DEFINE_INIT(fields)                                                     \
+     static const size_type init_bytes =                                                          \
          BOOST_PP_SEQ_FOR_EACH_I(SENF_PACKET_PARSER_I_INITSIZE_C, _, fields) ;
 # 
-# define SENF_PACKET_PARSER_I_FIXED_FIELD_DISPATCH(n,t,name,type)                                  \
+# define SENF_PACKET_PARSER_I_FIXED_FIELD_DISPATCH(n,t,name,type)                                 \
      SENF_PACKET_PARSER_I_FIXED_ ## t(n,name,type)
 # 
-# define SENF_PACKET_PARSER_I_FIXED_FIELD_C(_0,_1,n,elt)                                           \
-     BOOST_PP_EXPAND(                                                                              \
+# define SENF_PACKET_PARSER_I_FIXED_FIELD_C(_0,_1,n,elt)                                          \
+     BOOST_PP_EXPAND(                                                                             \
          SENF_PACKET_PARSER_I_FIXED_FIELD_DISPATCH SENF_PACKET_PARSER_I_UNWRAP(n,elt))
 # 
-# define SENF_PACKET_PARSER_I_DEFINE_FIXED_FIELDS(fields)                                          \
-     static const size_type offset_0_ = 0;                                                         \
-     BOOST_PP_SEQ_FOR_EACH_I(SENF_PACKET_PARSER_I_FIXED_FIELD_C, _, fields)                        \
-     static const size_type fixed_bytes =                                                          \
-         BOOST_PP_CAT(offset_,BOOST_PP_CAT(BOOST_PP_SEQ_SIZE(fields),_));                          \
+# define SENF_PACKET_PARSER_I_DEFINE_FIXED_FIELDS(fields)                                         \
+     static const size_type offset_0_ = 0;                                                        \
+     BOOST_PP_SEQ_FOR_EACH_I(SENF_PACKET_PARSER_I_FIXED_FIELD_C, _, fields)                       \
+     static const size_type fixed_bytes =                                                         \
+         BOOST_PP_CAT(offset_,BOOST_PP_CAT(BOOST_PP_SEQ_SIZE(fields),_));                         \
      SENF_PACKET_PARSER_I_DEFINE_INIT(fields)
 # 
 # ///////////////////////////////////////////////////////////////////////////
 # // Definition of the field types
 # 
-# define SENF_PACKET_PARSER_I_Field(n,name,type)                                                   \
-     type name () const {                                                                          \
-         return parse< type >( BOOST_PP_CAT(offset_,BOOST_PP_CAT(n,_)) () );                       \
-     }                                                                                             \
-     size_type BOOST_PP_CAT(offset_,BOOST_PP_CAT(BOOST_PP_INC(n),_)) () const {                    \
-         return BOOST_PP_CAT(offset_,BOOST_PP_CAT(n,_)) () + senf::bytes( name () );               \
+# define SENF_PACKET_PARSER_I_Field(n,name,type)                                                  \
+     typedef type BOOST_PP_CAT(name,_t) ;                                                         \
+     type name () const {                                                                         \
+         return parse< type >( BOOST_PP_CAT(offset_,BOOST_PP_CAT(n,_)) () );                      \
+     }                                                                                            \
+     size_type BOOST_PP_CAT(offset_,BOOST_PP_CAT(BOOST_PP_INC(n),_)) () const {                   \
+         return BOOST_PP_CAT(offset_,BOOST_PP_CAT(n,_)) () + senf::bytes( name () );              \
+     }                                                                                            \
+     size_type BOOST_PP_CAT(name, _offset) () const {                                             \
+         return BOOST_PP_CAT(offset_,BOOST_PP_CAT(BOOST_PP_INC(n),_)) () ;                        \
      }
 # 
-# define SENF_PACKET_PARSER_I_FIXED_Field(n,name,type)                                             \
-     type name () const {                                                                          \
-         return parse< type >( BOOST_PP_CAT(offset_,BOOST_PP_CAT(n,_)) );                          \
-     }                                                                                             \
-     static const size_type BOOST_PP_CAT(offset_,BOOST_PP_CAT(BOOST_PP_INC(n),_)) =                \
-         BOOST_PP_CAT(offset_,BOOST_PP_CAT(n,_)) + type::fixed_bytes;
-# 
-# define SENF_PACKET_PARSER_I_OverlayField(n,name,type)                                            \
-     type name () const {                                                                          \
-         return parse< type >( BOOST_PP_CAT(offset_,BOOST_PP_CAT(n,_)) () );                       \
-     }                                                                                             \
-     size_type BOOST_PP_CAT(offset_,BOOST_PP_CAT(BOOST_PP_INC(n),_)) () const {                    \
-         return BOOST_PP_CAT(offset_,BOOST_PP_CAT(n,_)) ();                                        \
+# define SENF_PACKET_PARSER_I_FIXED_Field(n,name,type)                                            \
+     typedef type BOOST_PP_CAT(name,_t) ;                                                         \
+     type name () const {                                                                         \
+         return parse< type >( BOOST_PP_CAT(offset_,BOOST_PP_CAT(n,_)) );                         \
+     }                                                                                            \
+     static const size_type BOOST_PP_CAT(offset_,BOOST_PP_CAT(BOOST_PP_INC(n),_)) =               \
+         BOOST_PP_CAT(offset_,BOOST_PP_CAT(n,_)) + type::fixed_bytes;                             \
+     static const size_type BOOST_PP_CAT(name,_offset) =                                          \
+         BOOST_PP_CAT(offset_,BOOST_PP_CAT(BOOST_PP_INC(n),_));
+# 
+# define SENF_PACKET_PARSER_I_OverlayField(n,name,type)                                           \
+     typedef type BOOST_PP_CAT(name,_t) ;                                                         \
+     type name () const {                                                                         \
+         return parse< type >( BOOST_PP_CAT(offset_,BOOST_PP_CAT(n,_)) () );                      \
+     }                                                                                            \
+     size_type BOOST_PP_CAT(offset_,BOOST_PP_CAT(BOOST_PP_INC(n),_)) () const {                   \
+         return BOOST_PP_CAT(offset_,BOOST_PP_CAT(n,_)) ();                                       \
+     }                                                                                            \
+     size_type BOOST_PP_CAT(name, _offset) () const {                                             \
+         return BOOST_PP_CAT(offset_,BOOST_PP_CAT(BOOST_PP_INC(n),_)) () ;                        \
      }
 # 
-# define SENF_PACKET_PARSER_I_FIXED_OverlayField(n,name,type)                                      \
-     type name () const {                                                                          \
-         return parse< type >( BOOST_PP_CAT(offset_,BOOST_PP_CAT(n,_)) );                          \
-     }                                                                                             \
-     static const size_type BOOST_PP_CAT(offset_,BOOST_PP_CAT(BOOST_PP_INC(n),_)) =                \
-         BOOST_PP_CAT(offset_,BOOST_PP_CAT(n,_));
+# define SENF_PACKET_PARSER_I_FIXED_OverlayField(n,name,type)                                     \
+     typedef type BOOST_PP_CAT(name,_t) ;                                                         \
+     type name () const {                                                                         \
+         return parse< type >( BOOST_PP_CAT(offset_,BOOST_PP_CAT(n,_)) );                         \
+     }                                                                                            \
+     static const size_type BOOST_PP_CAT(offset_,BOOST_PP_CAT(BOOST_PP_INC(n),_)) =               \
+         BOOST_PP_CAT(offset_,BOOST_PP_CAT(n,_));                                                 \
+     static const size_type BOOST_PP_CAT(name,_offset) =                                          \
+         BOOST_PP_CAT(offset_,BOOST_PP_CAT(BOOST_PP_INC(n),_));
 # 
 # ///////////////////////////////mpp.e///////////////////////////////////////
 # endif
index 671373c..69136e0 100644 (file)
       <xsl:with-param name="class">anchor</xsl:with-param>\r
     </xsl:call-template>\r
   </xsl:template>\r
+\r
+  <xsl:template match="div[@class='memdoc']/p[1]">\r
+    <xsl:call-template name="add-class">\r
+      <xsl:with-param name="class">memtitle</xsl:with-param>\r
+    </xsl:call-template>\r
+  </xsl:template>\r
+\r
+  <xsl:template match="div[@class='memdoc']/p[starts-with(text(),'Definition at line ')]">\r
+    <xsl:call-template name="add-class">\r
+      <xsl:with-param name="class">sourceline</xsl:with-param>\r
+    </xsl:call-template>\r
+  </xsl:template>\r
+\r
+  <xsl:template match="div[@class='memdoc']/p[starts-with(text(),'References ')]">\r
+    <xsl:call-template name="add-class">\r
+      <xsl:with-param name="class">references</xsl:with-param>\r
+    </xsl:call-template>\r
+  </xsl:template>\r
+\r
+  <xsl:template match="div[@class='memdoc']/p[starts-with(text(),'Referenced by ')]">\r
+    <xsl:call-template name="add-class">\r
+      <xsl:with-param name="class">referencedby</xsl:with-param>\r
+    </xsl:call-template>\r
+  </xsl:template>\r
+\r
+  <xsl:template match="div[@class='memdoc']/p[starts-with(text(),'Reimplemented from ')]">\r
+    <xsl:call-template name="add-class">\r
+      <xsl:with-param name="class">reimplementedfrom</xsl:with-param>\r
+    </xsl:call-template>\r
+  </xsl:template>\r
+\r
+  <xsl:template match="div[@class='memdoc']/p[starts-with(text(),'Reimplemented in ')]">\r
+    <xsl:call-template name="add-class">\r
+      <xsl:with-param name="class">reimplementedin</xsl:with-param>\r
+    </xsl:call-template>\r
+  </xsl:template>\r
   \r
   <!-- Remove [external] references from the modules page -->\r
   <xsl:template match="div[@id='content2']/ul/li[a/@class='elRef'][a/@doxygen][code/text()='[external]'][not(ul)]">\r
index 250dadc..4263f8f 100644 (file)
@@ -258,7 +258,7 @@ dl.xref-bug, dl.xref-fix, dl.xref-todo, dl.xref-idea {
         margin: 4px 8px 4px 2px;
         background-color: #FFEEEE;
         color: #666666;
-        font-size: 9px;
+        font-size: 75%;
         overflow: hidden;
 }
 
@@ -310,7 +310,27 @@ div.idea {
 
 dl.implementation {
         color: #666666;
-        font-size: 9px;
+        font-size: 75%;
+}
+
+p.memtitle {
+        color: #1a41a8;
+        font-weight: bold;
+        margin-right: 14px;
+        border-bottom: 1px solid #84b0c7;
+}
+
+p.sourceline, p.references, p.referencedby, p.reimplementedfrom, p.reimplementedin {
+        color: #666666;
+        font-size: 75%;
+        margin-left: 10em;
+        margin-bottom: .2em;
+        margin-top: .2em;
+        text-indent: -4em;
+}
+
+div.memproto {
+        margin-bottom: .5em;
 }
 
 table {
index 7f83abe..95d7cb4 100644 (file)
 (let ((local-conf (ccide-project-search-upwards "project-local.el")))
   (if local-conf
       (load-file local-conf)))
+
+(defun flyspell-cc-progmode-verify ()
+  "Replacement for standard flyspell-generic-progmode-verify which
+checks for C/C++ preproc directives. Additionally, anything after ^L
+is ignored (Those are the file local variables and local words)."
+  (let ((f (get-text-property (point) 'face)))
+    (and (memq f flyspell-prog-text-faces)
+        (not (save-excursion 
+               (beginning-of-line) 
+               (looking-at "\\(//\\)?#")))
+        (not (let ((l (max (point-min) (- (point-max) 4096))))
+               (and (< l (point))
+                    (save-excursion (search-backward "\f" l t))))))))
+
+(defun flyspell-cc-mode ()
+  "Torn on `flyspell-mode` for comments and strings in C/C++ mode."
+  (interactive)
+  (setq flyspell-generic-check-word-p 'flyspell-cc-progmode-verify)
+  (flyspell-mode 1))
+
+;; Better set this here than in the file variables since the setting
+;; is only valid if project.el is loaded ...
+(flyspell-cc-mode)