Message_AMOS.cc

Go to the documentation of this file.
00001 
00002 
00003 
00004 
00005 
00006 
00007 
00008 
00009 
00010 #include "Message_AMOS.hh"
00011 #include <cstdio>
00012 using namespace AMOS;
00013 using namespace std;
00014 using namespace HASHMAP;
00015 
00016 #define FIELD_SEPARATOR  ':'
00017 #define FIELD_TERMINATOR '.'
00018 
00019 
00020 
00021 
00022 //================================================ Message_t ===================
00023 //----------------------------------------------------- skipto -----------------
00024 inline bool skipto (istream & in, char ch)
00025 {
00026   static const int chunk = 1024;
00027 
00028   while ( true )
00029     {
00030       in . ignore (chunk, ch);
00031 
00032       if ( !in . good( ) )
00033         return false;
00034       if ( in . gcount( ) != chunk )
00035         return true;
00036 
00037       in . unget( );
00038     }
00039 }
00040 
00041 
00042 //----------------------------------------------------- read -------------------
00043 bool Message_t::read (istream & in)
00044 {
00045   int i;
00046   char ch;
00047   string data;
00048   string chunk;
00049   string name (NCODE_SIZE, NULL_CHAR);
00050 
00051   //-- Search for the beginning of the message
00052   if ( !skipto (in, '{') )
00053     return NULL_NCODE;
00054 
00055   //-- Empty the object
00056   clear( );
00057 
00058   try {
00059 
00060     //-- Get the type name
00061     for ( i = 0; i < NCODE_SIZE; i ++ )
00062       name [i] = in . get( );
00063     if ( in . get( ) != NL_CHAR )
00064       AMOS_THROW_IO ("Could not parse message NCode: " + name);
00065     setMessageCode (name);
00066 
00067     //-- Until end of message
00068     while ( true )
00069       {
00070         //-- Check next char
00071         ch = in . peek( );
00072 
00073         //-- If unexpected EOF
00074         if ( ch == EOF )
00075           AMOS_THROW_IO ("Unbalanced message nesting");
00076         //-- If a nested message, read it in
00077         else if ( ch == '{' )
00078           {
00079             subs_m . push_back (Message_t ( ));
00080             subs_m . back( ) . read (in);
00081             continue;
00082           }
00083         //-- If end of message
00084         else if ( ch == '}' )
00085           {
00086             skipto (in, NL_CHAR);
00087             break;
00088           }
00089         //-- If spacing
00090         else if ( ch == NL_CHAR )
00091           {
00092             in . get( );
00093             continue;
00094           }
00095 
00096         //-- Get the field name
00097         for ( i = 0; i < NCODE_SIZE; i ++ )
00098           name [i] = in . get( );
00099         if ( in . get( ) != FIELD_SEPARATOR )
00100           AMOS_THROW_IO ("Could not parse field code in '" +
00101                          Decode (mcode_m) + "' message");
00102 
00103         //-- Read in first line of field
00104         getline (in, data);
00105         if ( !in . good( ) )
00106           AMOS_THROW_IO ("Could not parse single-line field data in '" +
00107                          Decode (mcode_m) + "' message");
00108 
00109         //-- If multi-line field
00110         if ( data . empty( ) )
00111           {
00112             getline (in, data, FIELD_TERMINATOR);
00113 
00114             //-- Slurp up '.'s while not the '\n.\n' pattern
00115             while ( in . peek( ) != NL_CHAR ||
00116                     (!data . empty( ) && *(data . rbegin( )) != NL_CHAR) )
00117               {
00118                 if ( !in . good( ) )
00119                   AMOS_THROW_IO ("Unterminated multi-line field in '" +
00120                                  Decode (mcode_m) + "' message");
00121                 
00122                 data . push_back (FIELD_TERMINATOR);
00123                 getline (in, chunk, FIELD_TERMINATOR);
00124                 data . append (chunk);
00125               }
00126             in . get( );
00127 
00128             if ( !in . good( ) )
00129               AMOS_THROW_IO ("Could not parse multi-line field data in '" +
00130                              Decode (mcode_m) + "' message");
00131           }
00132 
00133         //-- Set field data
00134         setField (name, data);
00135       }
00136   }
00137   catch (Exception_t) {
00138 
00139     //-- Clean up and rethrow
00140     clear( );
00141     throw;
00142   }
00143 
00144   return true;
00145 }
00146 
00147 
00148 //----------------------------------------------------- setField ---------------
00149 void Message_t::setField (NCode_t fcode, const string & data)
00150 {
00151   if ( data . empty( ) )
00152     return;
00153 
00154   //-- Check pre-conditions
00155   string::size_type nlpos = data . rfind (NL_CHAR);
00156   if ( nlpos != string::npos  &&  nlpos != data . size( ) - 1 )
00157     AMOS_THROW_ARGUMENT ("Invalid multi-line message field format");
00158 
00159   //-- Insert new field, overwrite if already exists
00160   fields_m [fcode] = data;
00161 }
00162 
00163 
00164 //----------------------------------------------------- skip -------------------
00165 NCode_t Message_t::skip (istream & in) // static const
00166 {
00167   int i;
00168   char ch;
00169   string name (NCODE_SIZE, NULL_CHAR);
00170 
00171   //-- Search for the beginning of the message
00172   if ( !skipto (in, '{') )
00173     return NULL_NCODE;
00174 
00175   //-- Get the type name
00176   for ( i = 0; i < NCODE_SIZE; i ++ )
00177     name [i] = in . get( );
00178   if ( in . get( ) != NL_CHAR )
00179     AMOS_THROW_IO ("Could not parse message header: " + name);
00180 
00181   //-- Until end of message
00182   i = 1;
00183   while ( i != 0 )
00184     {
00185       //-- Get next char
00186       ch = in . get( );
00187       if ( !in . good( ) )
00188         AMOS_THROW_IO ("Unbalanced message nesting");
00189 
00190       //-- Increment/decrement level counter
00191       if ( ch == '{' )
00192         i ++;
00193       else if ( ch == '}' )
00194         i --;
00195 
00196       //-- Suck in rest of line
00197       if ( ch != NL_CHAR )
00198         skipto (in, NL_CHAR);
00199     }
00200 
00201   return Encode (name);
00202 }
00203 
00204 
00205 //----------------------------------------------------- write ------------------
00206 void Message_t::write (ostream & out) const
00207 {
00208   bool mline = false;
00209 
00210   //-- Write opening of message
00211   out << '{' << Decode (mcode_m) << endl;
00212 
00213   //-- Write all fields
00214   hash_map<NCode_t,string>::const_iterator mi;
00215   for ( mi = fields_m . begin( ); mi != fields_m . end( ); mi ++ )
00216     {
00217       //-- Set multi-line message flag
00218       mline = *(mi -> second . rbegin( )) == NL_CHAR ? true : false;
00219 
00220       out << Decode (mi -> first) << FIELD_SEPARATOR;
00221       if ( mline )
00222         out . put (NL_CHAR);
00223       out << mi -> second;
00224       if ( mline )
00225         out . put (FIELD_TERMINATOR);
00226       out . put (NL_CHAR);
00227     }
00228 
00229   //-- Write all sub-messages
00230  vector<Message_t>::const_iterator vi;
00231   for ( vi = subs_m . begin( ); vi != subs_m . end( ); vi ++ )
00232     vi -> write (out);
00233 
00234   //-- Close out message
00235   out << '}' << endl;
00236 
00237   //-- Check stream 'goodness'
00238   if ( !out . good( ) )
00239     AMOS_THROW_IO ("Message write failure");
00240 }

Generated on Mon Feb 22 17:36:27 2010 for libAMOS by  doxygen 1.4.7