From 9de2792751aecddfb6e1afa3d1f70e0adcb446c4 Mon Sep 17 00:00:00 2001
From: g0dil <g0dil@wiback.org>
Date: Thu, 18 Oct 2007 09:38:18 +0000
Subject: [PATCH] Packets: Add introductory parse helper documentation Utils:
 Implement ErrnoException

---
 Packets/MPEGDVBBundle/DSMCCSection.hh |   2 +-
 Packets/ParseHelpers.hh               | 344 +++++++++++++++++++-------
 Packets/ParseInt.hh                   |   5 +
 Scheduler/ReadHelper.ct               |   2 +-
 Scheduler/WriteHelper.ct              |   2 +-
 Utils/Exception.cc                    |  36 ++-
 Utils/Exception.cci                   |  77 +++++-
 Utils/Exception.cti                   |  55 ++++
 Utils/Exception.hh                    |  64 +++--
 Utils/Exception.test.cc               |  53 ++++
 senf.dict                             |   5 +
 11 files changed, 524 insertions(+), 121 deletions(-)
 create mode 100644 Utils/Exception.cti
 create mode 100644 Utils/Exception.test.cc

diff --git a/Packets/MPEGDVBBundle/DSMCCSection.hh b/Packets/MPEGDVBBundle/DSMCCSection.hh
index 922c8711e..e6c2cef9f 100644
--- a/Packets/MPEGDVBBundle/DSMCCSection.hh
+++ b/Packets/MPEGDVBBundle/DSMCCSection.hh
@@ -60,7 +60,7 @@ namespace senf {
 
         SENF_PARSER_FIELD    ( sec_num             , Parse_UInt8   );
         SENF_PARSER_FIELD    ( last_sec_num        , Parse_UInt8   );
-        
+
         SENF_PARSER_FINALIZE( Parse_DSMCCSection );
 
         Parse_UInt32 crc() const { return parse<Parse_UInt32>( data().size()-4 ); }
diff --git a/Packets/ParseHelpers.hh b/Packets/ParseHelpers.hh
index b4eb6c44d..e050ea4c3 100644
--- a/Packets/ParseHelpers.hh
+++ b/Packets/ParseHelpers.hh
@@ -49,18 +49,15 @@
     \code
     struct Parse_EthVLan : public PacketParserBase
     {
-        typedef Parse_UIntField < 0,  3 > Parse_Priority;
-        typedef Parse_Flag          < 3 > Parse_CFI;
-        typedef Parse_UIntField < 4, 16 > Parse_VLanId;
-        typedef Parse_UInt16              Parse_Type;
-
-        SENF_PACKET_PARSER_INIT(Parse_EthVLan);
-
-        SENF_PACKET_PARSER_DEFINE_FIXED_FIELDS(
-            ((OverlayField)( priority, Parse_Priority ))
-            ((OverlayField)( cfi,      Parse_CFI      ))
-            ((Field       )( vlanId,   Parse_VLanId   ))
-            ((Field       )( type,     Parse_Type     )) );
+    #   include SENF_FIXED_PARSER()
+
+        SENF_PARSER_BITFIELD( priority,  3, unsigned );
+        SENF_PARSER_BITFIELD( cfi,       1, bool     );
+        SENF_PARSER_BITFIELD( vlanId,   12, unsigned );
+
+        SENF_PARSER_FIELD( type, Parse_UInt16 );
+
+        SENF_PARSER_FINALIZE(Parse_EthVLan);
     };
     \endcode
 
@@ -70,10 +67,9 @@
     \li The macros provide a definition for \c init() 
     \li The macros define the \c bytes(), \c fixed_bytes and \c init_bytes members as needed.
 
-    You may define either a fixed or a dynamically sized parser. Fixed size parsers are defined
-    using \ref SENF_PACKET_PARSER_DEFINE_FIXED_FIELDS, dynamically sized parsers are defined
-    using \ref SENF_PACKET_PARSER_DEFINE_FIELDS. The different members are implemented such
-    that:
+    You may define either a fixed or a dynamically sized parser. Fixed size parsers are defined by
+    starting the packet with <tt>\#include SENF_FIXED_PARSER()</tt>, dynamically sized parsers start
+    with <tt>\#include SENF_PARSER()</tt>. The different members are implemented such that:
 
     \li The needed parser constructor is defined
     \li \c init() calls \c defaultInit(). \c defaultInit() is defined to call \c init() on each
@@ -81,96 +77,260 @@
     \li \c bytes() (on dynamically sized parser) respectively \c fixed_bytes (on fixed size
         parsers) is defined to return the sum of the sizes of all fields.
     \li On dynamically sized parsers, \c init_bytes is defined to return the sum of the
-        \c init_size's of all fields
+        \c init_byte's of all fields
 
-    The central definition macros are \ref SENF_PACKET_PARSER_DEFINE_FIXED_FIELDS and \ref
-    SENF_PACKET_PARSER_DEFINE_FIELDS. The argument to both has the same structure. It is a
-    (boost preprocessor style) sequence of field definitions where each field definition
-    provides the builder macro to use and the name and type of the field to define:
-    \code
-      SENF_PACKET_PARSER_DEFINE[_FIXED]_FIELDS(
-          (( <builder> )( <name>, <type> ))
-          ...
-      )
-    \endcode
+    \section parserlanguage The Parser Macro micro-language
+
+    The macros provided to help implement collection parsers implement a very small declarative
+    language. This way of to think of the macros simplifies understanding, how the macros work.
 
-    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
-    \li <tt>OverlayField</tt> defines a field like <tt>Field</tt> but does \e not increment the
-        position. In the above example, this is used to overlay the different bitfield parsers:
-        All overlaying bitfield parser except the last one (the one with the highest bit
-        numbers) is marked as OverlayField.
-
-    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 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 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
-    set up the field values as needed:
+    Central to this language is the concept of <em>current offset</em>. The current offset is the
+    place (in bytes) from the beginning of the parser at which the next field will be added. Adding
+    fields to the parser will advance this offset by the size of the field added. Additional
+    commands allow to arbitrarily manipulate the current offset manually.
+
+    For fixed size parsers, the current offset is a single constant integral value, the number of
+    bytes from the parsers start. For dynamically sized parsers, the current offset really consists
+    of two values: One is the number of bytes from the parsers start, which however needs not be a
+    constant expression, the other value is the \c init_bytes value at this point, which is an
+    integral constant.
+
+    To demonstrate this functionality, here a more complex example (taken from MPEGDVBBundle and
+    then simplified by removing some fields)
     \code
-      struct SomePacket : public senf::PacketParserBase
-      {
-          SENF_PACKET_PARSER_NO_INIT(SomePacket);
-
-          typedef senf::Parse_UInt8 Parse_Type;
-          typedef senf::Parse_Vector< senf::Parse_UInt32,
-                                      senf::SimpleVectorSizer<senf::Parse_UInt16>
-                                    > Parse_Elements;
-
-          SENF_PACKET_PARSER_DEFINE_FIELDS(
-              ((Field)( type,     Parse_Type     ))
-              ((Field)( elements, Parse_Elements ))
-          );
-
-          void init() const {
-              defaultInit();
-              type() = 0x01;
-              elements().push_back(0x01020304u);
-          }
-      }
+    struct Parse_DSMCCSection : public PacketParserBase
+    {
+    #   include SENF_FIXED_PARSER()
+
+        SENF_PARSER_FIELD    ( table_id            , Parse_UInt8   );
+        
+        SENF_PARSER_BITFIELD ( ssi                 ,  1 , bool     );
+        SENF_PARSER_BITFIELD ( private_indicator   ,  1 , bool     );
+        SENF_PARSER_SKIP_BITS( 2 );
+        SENF_PARSER_BITFIELD ( sec_length          , 12 , unsigned );
+        
+        SENF_PARSER_FIELD    ( table_id_extension  , Parse_UInt16  );
+        
+        SENF_PARSER_FINALIZE( Parse_DSMCCSection );
+    };
+
+    struct Parse_DatagramSection : public Parse_DSMCCSection
+    {
+    #   include SENF_FIXED_PARSER()
+
+        SENF_PARSER_INHERIT( Parse_DSMCCSection );
+
+        SENF_PARSER_FIELD    ( mac_addr_4          , Parse_UInt8   );
+        SENF_PARSER_FIELD    ( mac_addr_3          , Parse_UInt8   );
+
+        SENF_PARSER_FINALIZE( Parse_DatagramSection );
+
+        // Parse table_id_extension as two bytes
+        SENF_PARSER_GOTO( table_id_extension );
+        SENF_PARSER_FIELD    ( mac_addr_6          , Parse_UInt8   );
+        SENF_PARSER_FIELD    ( mac_addr_5          , Parse_UInt8   );
+    };
     \endcode
 
+    This code defines two parsers, the second of which is based on the first. Both are fixed size
+    parsers. The definition of \c Parse_DSMCCSection is straight forward (more on bit fields
+    below). 
+
+    The derived parser is a little bit more complex. It starts out the same defining itself as a
+    fixed size parser. Then the base class is imported. Among other things, this call sets the
+    current offset to the first byte after the base parser (the base parser need not be implemented
+    using the packet parser macros, it just needs to be a valid parser). The additional fields \c
+    mac_addr_4 and \c mac_addr_3 are defined. Then we finalize the parser declaration.
+
+    <em>After</em> \ref SENF_PARSER_FINALIZE we add two more fields but not at the end of the
+    parser. \ref SENF_PARSER_GOTO jumps back to a previously defined label or field. Since the base
+    parser \c Parse_DSMCCSection is defined using the packet parser macros, we can even jump to
+    labels or fields defined in the base parser. Here, we jump to the beginning of the \c
+    table_id_extension field. \c mac_addr_6 and \c mac_addr_5 are therefore defined starting at that
+    offset and therefore overlay the \c table_id_extension field.
+
+    \section parsermacroinit Parser initialization
+
+    \par ""
+        \ref SENF_FIXED_PARSER(), \ref SENF_PARSER(), \ref SENF_PARSER_INHERIT(), \ref
+        SENF_PARSER_INIT(), \ref SENF_PARSER_FINALIZE()
+
+    Every parser using the parser macros starts either with <tt>\#include SENF_PARSER()</tt> or with
+    <tt>\#include SENF_FIXED_PARSER()</tt>. This command sets the current offset to zero and defines
+    the type of parser to define.
+
+    A following optional \ref SENF_PARSER_INHERIT(\e base_class) is necessary if the parser does not
+    derive from senf::PacketParserBase. This call sets the base class and advances the current
+    offset to the end of the base parser.
+
+    \ref SENF_PARSER_INIT() is used to define the parser initialization code (the \c init()
+    member).
+
+    \ref SENF_PARSER_FINALIZE(\e class_name) is called to define the parsers constructor, the \c
+    init() member and to set the parsers size (\c fixed_bytes for fixed size parsers or \c bytes()
+    and \c init_bytes for dynamically sized parsers). It is valid to define further fields \e after
+    \ref SENF_PARSER_FINALIZE() has been called, however
+    \li Fields defined after \ref SENF_PARSER_FINALIZE() will \e not be initialized by \c
+        defaultInit() (and therefore not by the default provided \c init() member). This can be very
+        helpful when defining overlaying fields to avoid initializing some bytes multiple times.
+    \li The size of the parser is given by the current offset at the time of the \ref
+        SENF_PARSER_FINALIZE() call.
+
+    \section parsermacrofields Defining fields
+
+    \par ""
+        \ref SENF_PARSER_FIELD(), \ref SENF_PARSER_FIELD_RO(), \ref SENF_PARSER_PRIVATE_FIELD(),
+        \ref SENF_PARSER_PRIVATE_FIELD_RO(), SENF_PARSER_CUSTOM_FIELD()
+
+    There are quite a few commands available to define fields. All these macros do the same thing:
+    they define a field accessor plus some auxiliary symbols for the field:
+    \par ""
+        <em>type</em> <em>name</em><tt>()</tt> <tt>const</tt><br>
+        <tt>typedef</tt> <em>type</em> <em>name</em><tt>_t</tt><br>
+        <tt>size_type</tt> <tt>const</tt> <em>name</em><tt>_offset</tt><br>
+        &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<em>or</em><br>
+        &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<tt>size_type</tt> <em>name</em><tt>_offset()</tt> <tt>const</tt>
+    
+    Here \e type is the type of the field defined (the return value of the \e name() accessor) and
+    \e name is the field name. <em>name</em><tt>_offset</tt> gives the offset of the first byte of
+    the field from the start of the parser. This member is a constant for fixed size parser and a
+    member function for dynamically sized parsers. <em>name</em><tt>_t</tt> is just an alias for the
+    fields type (more precisely the return type of the <em>name</em>() accessor).
+
+    There are some properties the field defining macros might have. These properties are parts
+    of the macro name:
+
+    \par RO: Read only fields
+        Macros with \c RO in their name define read only fields. This is only possible, if the
+        field's parser is a value parser (that is, it must have a \c value_type typedef member and
+        must provide the \c value() accessor member function). In this case, the value returned from
+        the \e name() accessor member is not the parser but the parsers value and therefore it does
+        not allow assignment to the field.
+
+    \par PRIVATE: Fields private to the parser class 
+        A private field will not be accessible from the outside (it is made \c private to the parser
+        class). This is very handy when providing other accessor members to access a field in a
+        manner more suitable for the specific field, when combining several fields into a single
+        return value etc.
+
+    The field defining macros come in groups which members only differ in their properties:
+
+    \par Define standard fields:
+        \ref SENF_PARSER_FIELD(), \ref SENF_PARSER_FIELD_RO(), \ref SENF_PARSER_PRIVATE_FIELD(),
+        \ref SENF_PARSER_PRIVATE_FIELD_RO() define standard fields.
+
+    \par Define arbitrary custom field:
+        \ref SENF_PARSER_CUSTOM_FIELD()
+
+    See the documentation of each of these macros for a detailed description of the macro arguments
+    and usage. Bit-fields are handled in the following section.
+
+    \subsection parsermacrobitfields Bit-fields
+
+    \par "" 
+        \ref SENF_PARSER_BITFIELD(), \ref SENF_PARSER_BITFIELD_RO(), \ref
+        SENF_PARSER_PRIVATE_BITFIELD(), \ref SENF_PARSER_PRIVATE_BITFIELD_RO() \n
+
+    Bit-fields play a special role. They are quite frequent in packet definitions but don't fit into
+    the byte offset based parsing infrastructure defined so far. Since defining the correctly
+    parameterized Parse_IntField, Parse_UIntField and Parse_Flag typedefs is quite tedious, these
+    helper macros are provided.
+
+    It is important to recognize, that the current offset does \e not include the current bit
+    position. The current offset after defining a bit-field will be the first complete byte after
+    that bit-field. Only the bit-field macros additionally take care of the current bit position
+    which is reset automatically by any intervening non-bitfield command.
+
+    So bit-field commands will come in groups. Any group of consecutive bitfield commands defines a
+    set of consecutive bits. The group as a whole will always be considered to cover a fixed number
+    of complete bytes. If the group does not cover those bytes completely (there are some bit's left
+    at the end), those bit's will be skipped.
+
+    Since consecutive bit-field commands are aggregated into a single bit-field group, the offset of
+    all these bit-fields will be the offset of the \e beginning of the bit-field irrespective of the
+    number of bits parsed so far. Changing the offset to some bitfield using \ref SENF_PARSER_GOTO()
+    will therefore always go to the position at the beginning of this bitfield group. And since the
+    current offset does not include the bit position, the bit position will be 0, the first bit. You
+    may however break a bit-field group into two groups (at a byte boundary) by placing a \ref
+    SENF_PARSER_LABEL() command between the two groups.
+
+    The additional command \ref SENF_PARSER_SKIP_BITS() can be used to skip bit's between two
+    bit-fields.
+
+    \section parsermacrooffset Manipulating the current offset
+
+    \par ""
+        \ref SENF_PARSER_SKIP(), \ref SENF_PARSER_SKIP_BITS(), \ref SENF_PARSER_GOTO(), \ref
+        SENF_PARSER_GOTO_OFFSET(), \ref SENF_PARSER_LABEL()
+
+    To define more complex parsers, there are some macro commands which change the current offset. 
+
+    \ref SENF_PARSER_SKIP(\e bytes) will skip the given number of bytes. \ref
+    SENF_PARSER_SKIP_BITS(\e bits) will work within bitfield definition to skip that number of bits.
+
+    \ref SENF_PARSER_GOTO(\e label_or_field) will change the offset to the given field or label. The
+    following fields will therefore start at that offset and overlay any fields already defined.
+
+    \ref SENF_PARSER_GOTO_OFFSET(\e offset) will jump to the given byte offset from the start of the
+    parser.
+
+    \ref SENF_PARSER_LABEL(\e name) will define \e name as a label for the current offset which can
+    then later be referenced using \ref SENF_PARSER_GOTO(). This also defines
+    <em>name</em><tt>_offset</tt> as a constant or member (for fixed respectively dynamically sized
+    parsers).
+    
+    It is very important to recognize, that the size of the parser is defined by the current offset
+    <em>at the time \ref SENF_PARSER_FINALIZE() is called</em>. This allows to arbitrarily
+    manipulate the size of the parser by changing the current offset accordingly. For dynamically
+    sized parsers, the offset can even be any expression involving member function calls. See the
+    documentation of the respective macros for more details.
+
     \ingroup packetparser
  */
+///\ingroup packetparsermacros
+///\{
 
-#define SENF_FIXED_PARSER()     SENF_ABSOLUTE_INCLUDE_PATH(Packets/parse_fixed_setup.hh)
-#define SENF_PARSER()           SENF_ABSOLUTE_INCLUDE_PATH(Packets/parse_setup.hh)
+#define SENF_FIXED_PARSER()      SENF_ABSOLUTE_INCLUDE_PATH(Packets/parse_fixed_setup.hh)
+#define SENF_PARSER()            SENF_ABSOLUTE_INCLUDE_PATH(Packets/parse_setup.hh)
 
-#define SENF_PARSER_INHERIT     BOOST_PP_CAT( SENF_PARSER_INHERIT_     , SENF_PARSER_TYPE )
+#define SENF_PARSER_INHERIT      BOOST_PP_CAT(SENF_PARSER_INHERIT_,      SENF_PARSER_TYPE)
 
-#define SENF_PARSER_FIELD        BOOST_PP_CAT( SENF_PARSER_FIELD_        , SENF_PARSER_TYPE )
-#define SENF_PARSER_FIELD_RO     BOOST_PP_CAT( SENF_PARSER_FIELD_RO_     , SENF_PARSER_TYPE )
-#define SENF_PARSER_BITFIELD     BOOST_PP_CAT( SENF_PARSER_BITFIELD_     , SENF_PARSER_TYPE )
-#define SENF_PARSER_BITFIELD_RO  BOOST_PP_CAT( SENF_PARSER_BITFIELD_RO_  , SENF_PARSER_TYPE )
-#define SENF_PARSER_CUSTOM_FIELD BOOST_PP_CAT( SENF_PARSER_CUSTOM_FIELD_ , SENF_PARSER_TYPE )
+#define SENF_PARSER_FIELD        BOOST_PP_CAT(SENF_PARSER_FIELD_,        SENF_PARSER_TYPE)
+#define SENF_PARSER_FIELD_RO     BOOST_PP_CAT(SENF_PARSER_FIELD_RO_,     SENF_PARSER_TYPE)
+#define SENF_PARSER_BITFIELD     BOOST_PP_CAT(SENF_PARSER_BITFIELD_,     SENF_PARSER_TYPE)
+#define SENF_PARSER_BITFIELD_RO  BOOST_PP_CAT(SENF_PARSER_BITFIELD_RO_,  SENF_PARSER_TYPE)
+#define SENF_PARSER_CUSTOM_FIELD BOOST_PP_CAT(SENF_PARSER_CUSTOM_FIELD_, SENF_PARSER_TYPE)
 
-#define SENF_PARSER_PRIVATE_FIELD        BOOST_PP_CAT( SENF_PARSER_P_FIELD_        , SENF_PARSER_TYPE )
-#define SENF_PARSER_PRIVATE_FIELD_RO     BOOST_PP_CAT( SENF_PARSER_P_FIELD_RO_     , SENF_PARSER_TYPE )
-#define SENF_PARSER_PRIVATE_BITFIELD     BOOST_PP_CAT( SENF_PARSER_P_BITFIELD_     , SENF_PARSER_TYPE )
-#define SENF_PARSER_PRIVATE_BITFIELD_RO  BOOST_PP_CAT( SENF_PARSER_P_BITFIELD_RO_  , SENF_PARSER_TYPE )
+#define SENF_PARSER_PRIVATE_FIELD       BOOST_PP_CAT(SENF_PARSER_P_FIELD_,       SENF_PARSER_TYPE)
+#define SENF_PARSER_PRIVATE_FIELD_RO    BOOST_PP_CAT(SENF_PARSER_P_FIELD_RO_,    SENF_PARSER_TYPE)
+#define SENF_PARSER_PRIVATE_BITFIELD    BOOST_PP_CAT(SENF_PARSER_P_BITFIELD_,    SENF_PARSER_TYPE)
+#define SENF_PARSER_PRIVATE_BITFIELD_RO BOOST_PP_CAT(SENF_PARSER_P_BITFIELD_RO_, SENF_PARSER_TYPE)
 
-#define SENF_PARSER_SKIP        BOOST_PP_CAT( SENF_PARSER_SKIP_        , SENF_PARSER_TYPE )
-#define SENF_PARSER_SKIP_BITS   BOOST_PP_CAT( SENF_PARSER_SKIP_BITS_   , SENF_PARSER_TYPE )
-#define SENF_PARSER_GOTO        BOOST_PP_CAT( SENF_PARSER_GOTO_        , SENF_PARSER_TYPE )
-#define SENF_PARSER_GOTO_OFFSET BOOST_PP_CAT( SENF_PARSER_GOTO_OFFSET_ , SENF_PARSER_TYPE )
-#define SENF_PARSER_LABEL       BOOST_PP_CAT( SENF_PARSER_LABEL_       , SENF_PARSER_TYPE )
+#define SENF_PARSER_SKIP         BOOST_PP_CAT(SENF_PARSER_SKIP_,        SENF_PARSER_TYPE)
+#define SENF_PARSER_SKIP_BITS    BOOST_PP_CAT(SENF_PARSER_SKIP_BITS_,   SENF_PARSER_TYPE)
+#define SENF_PARSER_GOTO         BOOST_PP_CAT(SENF_PARSER_GOTO_,        SENF_PARSER_TYPE)
+#define SENF_PARSER_GOTO_OFFSET  BOOST_PP_CAT(SENF_PARSER_GOTO_OFFSET_, SENF_PARSER_TYPE)
+#define SENF_PARSER_LABEL        BOOST_PP_CAT(SENF_PARSER_LABEL_,       SENF_PARSER_TYPE)
+
+/** \brief Define parser initialization routine
+
+    \code
+    SENF_PARSER_INIT() {
+        defaultInit();
+        foo() = 2;
+    }
+    \endcode
+    Defining the initialization code manually skips the automatic call of defaultInit(), which may
+    be performed manually. Should the initialization code be more complex, it should be placed into
+    a non-inline private member which is called from \ref SENF_PARSER_INIT()
+    
+    \hideinitializer
+ */
+#define SENF_PARSER_INIT()       void init(int)
 
-#define SENF_PARSER_INIT()      void init(int)
+#define SENF_PARSER_FINALIZE     BOOST_PP_CAT(SENF_PARSER_FINALIZE_,    SENF_PARSER_TYPE)
 
-#define SENF_PARSER_FINALIZE    BOOST_PP_CAT( SENF_PARSER_FINALIZE_    , SENF_PARSER_TYPE )
+///\}
 
 ///////////////////////////////hh.e////////////////////////////////////////
 #endif
diff --git a/Packets/ParseInt.hh b/Packets/ParseInt.hh
index 761239807..f73c4374e 100644
--- a/Packets/ParseInt.hh
+++ b/Packets/ParseInt.hh
@@ -299,6 +299,8 @@ namespace senf {
         ///////////////////////////////////////////////////////////////////////////
 
         typedef boost::int32_t value_type;
+        static size_type const start_bit = Start;
+        static size_type const end_bit = End;
         static size_type const fixed_bytes = (End-1)/8+1;
 
         value_type value() const {
@@ -352,6 +354,8 @@ namespace senf {
         ///////////////////////////////////////////////////////////////////////////
 
         typedef boost::uint32_t value_type;
+        static size_type const start_bit = Start;
+        static size_type const end_bit = End;
         static size_type const fixed_bytes = (End-1)/8+1;
 
         value_type value() const { return detail::packet::parse_bitfield<Start,End>::parse(i()); }
@@ -393,6 +397,7 @@ namespace senf {
         ///////////////////////////////////////////////////////////////////////////
 
         typedef bool value_type;
+        static size_type const bit = Bit;
         static size_type const fixed_bytes = Bit/8+1;
 
         value_type value() const { return i()[Bit/8] & (1<<(7-(Bit%8))); }
diff --git a/Scheduler/ReadHelper.ct b/Scheduler/ReadHelper.ct
index e39eb4f35..6e388f3c4 100644
--- a/Scheduler/ReadHelper.ct
+++ b/Scheduler/ReadHelper.ct
@@ -85,7 +85,7 @@ prefix_ void senf::ReadHelper<Handle>::process(Handle handle,
         }
     }
     catch (senf::SystemException const & ex) {
-        errno_ = ex.err;
+        errno_ = ex.code();
         done();
         return;
     }
diff --git a/Scheduler/WriteHelper.ct b/Scheduler/WriteHelper.ct
index 485c1e75a..898a5497f 100644
--- a/Scheduler/WriteHelper.ct
+++ b/Scheduler/WriteHelper.ct
@@ -87,7 +87,7 @@ prefix_ void senf::WriteHelper<Handle>::process(Handle handle,
         }
     }
     catch (senf::SystemException const & ex) {
-        errno_ = ex.err;
+        errno_ = ex.code();
         done();
         return;
     }
diff --git a/Utils/Exception.cc b/Utils/Exception.cc
index 80b6c98bd..de36e8620 100644
--- a/Utils/Exception.cc
+++ b/Utils/Exception.cc
@@ -39,16 +39,40 @@ prefix_ void senf::SystemException::init()
     // however all other solutions to format the message are terribly
     // ugly (since thay must use a static and shared buffer ...)
     std::stringstream s;
-    if (where)
-        s << where << ": ";
-    s << "(" << err << ") " << std::strerror(err);
+    if (where_)
+        s << where_ << ": ";
+    s << "(" << code_ << ") " << description();
     buffer_ = s.str();
 }
 
-prefix_ char const * senf::SystemException::what()
-    const throw()
+prefix_ void senf::throwErrno(char const * where, int code)
 {
-    return buffer_.c_str();
+    switch (code) {
+
+    // BOOST_PP_REPEAT is limited to 256 repetitions. The max errno value I found in any header file
+    // was somewhere around 530 or so. I assume going to 1024 will be good enough. This explicit
+    // code will be optimized into a jump table by g++ (which is more efficient than trying to do
+    // the table oneself)
+
+#   define ExceptionCase(z, n, data) case n: throw ErrnoException<n>(where);
+    BOOST_PP_REPEAT(256, ExceptionCase, _) ;
+#   undef ExceptionCase
+
+#   define ExceptionCase(z, n, data) case 256+n: throw ErrnoException<256+n>(where);
+    BOOST_PP_REPEAT(256, ExceptionCase, _) ;
+#   undef ExceptionCase
+
+#   define ExceptionCase(z, n, data) case 512+n: throw ErrnoException<512+n>(where);
+    BOOST_PP_REPEAT(256, ExceptionCase, _) ;
+#   undef ExceptionCase
+
+#   define ExceptionCase(z, n, data) case 768+n: throw ErrnoException<768+n>(where);
+    BOOST_PP_REPEAT(256, ExceptionCase, _) ;
+#   undef ExceptionCase
+
+    default:
+        throw SystemException(where, code);
+    }
 }
 
 ///////////////////////////////cc.e////////////////////////////////////////
diff --git a/Utils/Exception.cci b/Utils/Exception.cci
index 9c3a383a4..9903becd7 100644
--- a/Utils/Exception.cci
+++ b/Utils/Exception.cci
@@ -21,26 +21,95 @@
     \brief Exception inline non-template implementation */
 
 // Custom includes
+#include <errno.h>
+#include <cstring>
 
 #define prefix_ inline
 ///////////////////////////////cci.p///////////////////////////////////////
 
-prefix_  senf::SystemException::SystemException(int err_)
-    : where(0), err(err_)
+prefix_ senf::SystemException::SystemException()
+    : where_(0), code_(errno)
 {
     init();
 }
 
-prefix_ senf::SystemException::SystemException(char const * where_, int err_)
-    : where(where_), err(err_)
+prefix_  senf::SystemException::SystemException(int code)
+    : where_(0), code_(code)
 {
     init();
 }
 
+prefix_ senf::SystemException::SystemException(char const * where)
+    : where_(where), code_(errno)
+{
+    init();
+}
+
+prefix_ senf::SystemException::SystemException(char const * where, int code)
+    : where_(where), code_(code)
+{
+    init();
+}
+
+prefix_ char const * senf::SystemException::what()
+    const throw()
+{
+    return buffer_.c_str();
+}
+
+prefix_ char const * senf::SystemException::where()
+    const
+{
+    return where_;
+}
+
+prefix_ int senf::SystemException::code()
+    const
+{
+    return code_;
+}
+
+prefix_ char const * senf::SystemException::description()
+    const
+{
+    return std::strerror(code_);
+}
+
+prefix_ bool senf::SystemException::anyOf(int c0, int c1, int c2, int c3, int c4, int c5,
+                                          int c6, int c7, int c8, int c9)
+{
+    return 
+        (c0 && code_ == c0) ||
+        (c1 && code_ == c1) ||
+        (c2 && code_ == c2) ||
+        (c3 && code_ == c3) ||
+        (c4 && code_ == c4) ||
+        (c5 && code_ == c5) ||
+        (c6 && code_ == c6) ||
+        (c7 && code_ == c7) ||
+        (c8 && code_ == c8) ||
+        (c9 && code_ == c9);
+}
+
 prefix_  senf::SystemException::~SystemException()
     throw()
 {}
 
+prefix_ void senf::throwErrno()
+{
+    throwErrno(0, errno);
+}
+
+prefix_ void senf::throwErrno(char const * where)
+{
+    throwErrno(where, errno);
+}
+
+prefix_ void senf::throwErrno(int code)
+{
+    throwErrno(0, code);
+}
+
 ///////////////////////////////cci.e///////////////////////////////////////
 #undef prefix_
 
diff --git a/Utils/Exception.cti b/Utils/Exception.cti
new file mode 100644
index 000000000..bd89b67b5
--- /dev/null
+++ b/Utils/Exception.cti
@@ -0,0 +1,55 @@
+// $Id$
+//
+// Copyright (C) 2007 
+// Fraunhofer Institut fuer offene Kommunikationssysteme (FOKUS)
+// Kompetenzzentrum fuer Satelitenkommunikation (SatCom)
+//     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 Exception inline template implementation */
+
+//#include "Exception.ih"
+
+// Custom includes
+
+#define prefix_ inline
+///////////////////////////////cti.p///////////////////////////////////////
+
+template <int Code>
+prefix_ senf::ErrnoException<Code>::ErrnoException()
+    : SystemException(fixed_code)
+{}
+
+template <int Code>
+prefix_ senf::ErrnoException<Code>::ErrnoException(char const * where)
+    : SystemException(where,fixed_code)
+{}
+
+/////////////////////////////cti.e///////////////////////////////////////
+#undef prefix_
+
+
+// Local Variables:
+// mode: c++
+// fill-column: 100
+// comment-column: 40
+// c-file-style: "senf"
+// indent-tabs-mode: nil
+// ispell-local-dictionary: "american"
+// compile-command: "scons -u test"
+// End:
diff --git a/Utils/Exception.hh b/Utils/Exception.hh
index a3c66a9b9..c6e9ba357 100644
--- a/Utils/Exception.hh
+++ b/Utils/Exception.hh
@@ -29,6 +29,8 @@
 // Custom includes
 #include <exception>
 #include <string>
+#include <boost/preprocessor/repeat.hpp>
+#include <boost/preprocessor/cat.hpp>
 
 //#include "Exception.mpp"
 ///////////////////////////////hh.p////////////////////////////////////////
@@ -39,39 +41,69 @@ namespace senf {
 
         This exception is thrown to signal generic errno failures.
 
-        \todo make where and err accessors and make the member vars private
+        \todo make where and err accessors and make the member variables private
 
-        \idea Add a template class derived from SystemException which
-        takes the error number as a numeric argument. This allows
-        catching specific errno conditions: ErrnoException<EPIPE> etc.
+        \idea Add a template class derived from SystemException which takes the error number as a
+        numeric argument. This allows catching specific errno conditions: ErrnoException<EPIPE> etc.
 
-        \idea Add a generic error thrower which takes the origin
-        string and errno value as an argument and will throw a
-        corresponding template class instance. This would just be a
-        big switch statement containing all possible errno values,
-        probably created using some macro metaprogramming.
+        \idea Add a generic error thrower which takes the origin string and errno value as an
+        argument and will throw a corresponding template class instance. This would just be a big
+        switch statement containing all possible errno values, probably created using some macro
+        meta-programming.
      */
     class SystemException : public std::exception
     {
     public:
-        explicit SystemException(int err); ///< SystemException without error lokus info
-                                        /**< \param[in] err error number (the errno value) */
-        SystemException(char const * where, int err); ///< SystemException with error location info
+        SystemException();              ///< SystemException without error location infor
+                                        /**< The error code is taken from the current value of the
+                                             global 'errno' variable  */
+
+        explicit SystemException(int code); ///< SystemException without error location info
+                                        /**< \param[in] code error number (the errno value) */
+
+        explicit SystemException(char const * where); ///< SystemException with error location info
+                                        /**< The error code is taken from the current value of the
+                                             global 'errno' variable 
+                                             \param[in] where description of error origin */
+
+        SystemException(char const * where, int code); ///< SystemException with error location info 
                                         /**< \param[in] where description of error origin
-                                             \param[in] err error number (the errno value) */
+                                             \param[in] code error number (the errno value) */
 
         virtual char const * what() const throw(); ///< Return verbose error description
 
-        char const * where; ///< Error origin
-        int err; ///< Error number
+        char const * where() const;     ///< Error origin
+        int code() const;               ///< Error code (errno number)
+        char const * description() const; ///< Error description (strerror() value)
+
+        bool anyOf(int c0, int c1=0, int c2=0, int c3=0, int c4=0, int c5=0, 
+                   int c6=0, int c7=0, int c8=0, int c9=0);
 
         virtual ~SystemException() throw();
 
     private:
         void init();
+
+        char const * const where_;
+        int const code_;
         std::string buffer_;
     };
 
+    template <int Code>
+    class ErrnoException : public SystemException
+    {
+    public:
+        static int const fixed_code = Code;
+
+        ErrnoException();
+        explicit ErrnoException(char const * where);
+    };
+
+    void throwErrno();
+    void throwErrno(char const * where);
+    void throwErrno(int code);
+    void throwErrno(char const * where, int code);
+
     enum NoThrow_t { nothrow };
 
 }
@@ -79,7 +111,7 @@ namespace senf {
 ///////////////////////////////hh.e////////////////////////////////////////
 #include "Exception.cci"
 //#include "Exception.ct"
-//#include "Exception.cti"
+#include "Exception.cti"
 #endif
 
 
diff --git a/Utils/Exception.test.cc b/Utils/Exception.test.cc
new file mode 100644
index 000000000..7421921aa
--- /dev/null
+++ b/Utils/Exception.test.cc
@@ -0,0 +1,53 @@
+// $Id$
+//
+// Copyright (C) 2007 
+// Fraunhofer Institut fuer offene Kommunikationssysteme (FOKUS)
+// Kompetenzzentrum fuer Satelitenkommunikation (SatCom)
+//     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 Exception.test unit tests */
+
+//#include "Exception.test.hh"
+//#include "Exception.test.ih"
+
+// Custom includes
+#include "Exception.hh"
+
+#include <boost/test/auto_unit_test.hpp>
+#include <boost/test/test_tools.hpp>
+
+#define prefix_
+///////////////////////////////cc.p////////////////////////////////////////
+
+BOOST_AUTO_UNIT_TEST(errnoException)
+{}
+
+///////////////////////////////cc.e////////////////////////////////////////
+#undef prefix_
+
+
+// Local Variables:
+// mode: c++
+// fill-column: 100
+// comment-column: 40
+// c-file-style: "senf"
+// indent-tabs-mode: nil
+// ispell-local-dictionary: "american"
+// compile-command: "scons -u test"
+// End:
diff --git a/senf.dict b/senf.dict
index 080ca896d..40b7cccb4 100644
--- a/senf.dict
+++ b/senf.dict
@@ -59,6 +59,9 @@ ElementParser
 endcode
 enum
 eof
+EPIPE
+errno
+ErrnoException
 ErrorException
 eth
 ethernet
@@ -195,6 +198,7 @@ ParseList
 ParseListB
 ParseListN
 parseNextAs
+parserlanguage
 ParseVec
 PassiveConnector
 PassiveInput
@@ -260,6 +264,7 @@ someVector
 std
 stefan
 STL
+strerror
 struct
 structors
 SyntaxException
-- 
GitLab