From: g0dil Date: Thu, 18 Oct 2007 09:38:18 +0000 (+0000) Subject: Packets: Add introductory parse helper documentation X-Git-Url: http://g0dil.de/git?a=commitdiff_plain;h=96d3a2a43b4e6d7693a136a3adeb099440f19068;p=senf.git Packets: Add introductory parse helper documentation Utils: Implement ErrnoException git-svn-id: https://svn.berlios.de/svnroot/repos/senf/trunk@467 270642c3-0616-0410-b53a-bc976706d245 --- diff --git a/Packets/MPEGDVBBundle/DSMCCSection.hh b/Packets/MPEGDVBBundle/DSMCCSection.hh index 922c871..e6c2cef 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( data().size()-4 ); } diff --git a/Packets/ParseHelpers.hh b/Packets/ParseHelpers.hh index b4eb6c4..e050ea4 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 \#include SENF_FIXED_PARSER(), dynamically sized parsers start + with \#include SENF_PARSER(). 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( - (( )( , )) - ... - ) - \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_t as a typedef for \a type, the fields value - \li \a name_offset 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 Field defines a field and increments the current position by the size of the - field - \li OverlayField defines a field like Field 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, This argument cannot be a multi-parameter template. 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 current offset. 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 - > 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. + + After \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 \#include SENF_PARSER() or with + \#include SENF_FIXED_PARSER(). 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 "" + type name() const
+ typedef type name_t
+ size_type const name_offset
+           or
+      size_type name_offset() const + + 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. name_offset 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. name_t is just an alias for the + fields type (more precisely the return type of the name() 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 + name_offset 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 + at the time \ref SENF_PARSER_FINALIZE() is called. 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 7612398..f73c437 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::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 e39eb4f..6e388f3 100644 --- a/Scheduler/ReadHelper.ct +++ b/Scheduler/ReadHelper.ct @@ -85,7 +85,7 @@ prefix_ void senf::ReadHelper::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 485c1e7..898a549 100644 --- a/Scheduler/WriteHelper.ct +++ b/Scheduler/WriteHelper.ct @@ -87,7 +87,7 @@ prefix_ void senf::WriteHelper::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 80b6c98..de36e86 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(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 9c3a383..9903bec 100644 --- a/Utils/Exception.cci +++ b/Utils/Exception.cci @@ -21,26 +21,95 @@ \brief Exception inline non-template implementation */ // Custom includes +#include +#include #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 0000000..bd89b67 --- /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 +// +// 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 +prefix_ senf::ErrnoException::ErrnoException() + : SystemException(fixed_code) +{} + +template +prefix_ senf::ErrnoException::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 a3c66a9..c6e9ba3 100644 --- a/Utils/Exception.hh +++ b/Utils/Exception.hh @@ -29,6 +29,8 @@ // Custom includes #include #include +#include +#include //#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 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 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 + 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 0000000..7421921 --- /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 +// +// 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 +#include + +#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 080ca89..40b7ccc 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