Packets: Add introductory parse helper documentation
g0dil [Thu, 18 Oct 2007 09:38:18 +0000 (09:38 +0000)]
Utils: Implement ErrnoException

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

Packets/MPEGDVBBundle/DSMCCSection.hh
Packets/ParseHelpers.hh
Packets/ParseInt.hh
Scheduler/ReadHelper.ct
Scheduler/WriteHelper.ct
Utils/Exception.cc
Utils/Exception.cci
Utils/Exception.cti [new file with mode: 0644]
Utils/Exception.hh
Utils/Exception.test.cc [new file with mode: 0644]
senf.dict

index 922c871..e6c2cef 100644 (file)
@@ -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 ); }
index b4eb6c4..e050ea4 100644 (file)
     \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
 
     \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
     \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
index 7612398..f73c437 100644 (file)
@@ -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))); }
index e39eb4f..6e388f3 100644 (file)
@@ -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;
     }
index 485c1e7..898a549 100644 (file)
@@ -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;
     }
index 80b6c98..de36e86 100644 (file)
@@ -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////////////////////////////////////////
index 9c3a383..9903bec 100644 (file)
     \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 (file)
index 0000000..bd89b67
--- /dev/null
@@ -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_
+
+\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 a3c66a9..c6e9ba3 100644 (file)
@@ -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
 
 \f
diff --git a/Utils/Exception.test.cc b/Utils/Exception.test.cc
new file mode 100644 (file)
index 0000000..7421921
--- /dev/null
@@ -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_
+
+\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 080ca89..40b7ccc 100644 (file)
--- 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