TagParser.cc

Go to the documentation of this file.
00001 /*---------------------------------------------------------------------\
00002 |                          ____ _   __ __ ___                          |
00003 |                         |__  / \ / / . \ . \                         |
00004 |                           / / \ V /|  _/  _/                         |
00005 |                          / /__ | | | | | |                           |
00006 |                         /_____||_| |_| |_|                           |
00007 |                                                                      |
00008 \---------------------------------------------------------------------*/
00012 #include <iostream>
00013 #include <sstream>
00014 
00015 #include "zypp/base/Logger.h"
00016 #include "zypp/base/String.h"
00017 #include "zypp/base/IOStream.h"
00018 #include "zypp/base/UserRequestException.h"
00019 #include "zypp/parser/ParseException.h"
00020 
00021 #include "zypp/parser/TagParser.h"
00022 #include "zypp/ProgressData.h"
00023 
00024 using std::endl;
00025 
00027 namespace zypp
00028 { 
00029 
00030   namespace parser
00031   { 
00032 
00034     //
00035     //  CLASS NAME : TagParser::Tag
00036     //
00038 
00039     std::string TagParser::Tag::asString() const
00040     {
00041       std::string ret( name );
00042       if ( ! modifier.empty() )
00043         ret += modifier;
00044       return ret += ":";
00045     }
00046 
00047     std::ostream & operator<<( std::ostream & str, const TagParser::Tag & obj )
00048     {
00049       str << "@" << obj.lineNo << "{" << obj.name;
00050       if ( ! obj.modifier.empty() )
00051         str << '.' << obj.modifier;
00052       return str << ":}(" << obj.dataStart << "|" << obj.dataLength << ")";
00053     }
00054 
00055     std::ostream & operator<<( std::ostream & str, const TagParser::SingleTag & obj )
00056     {
00057       str << "=" << static_cast<const TagParser::Tag &>( obj );
00058       return str << "\"" << obj.value << "\"";
00059     }
00060 
00061     std::ostream & operator<<( std::ostream & str, const TagParser::MultiTag & obj )
00062     {
00063       str << "+" << static_cast<const TagParser::Tag &>( obj );
00064       return str << "[" << obj.value.size() << "]";
00065     }
00066 
00068     //
00069     //  CLASS NAME : TagParser
00070     //
00072 
00074     //
00075     //  METHOD NAME : TagParser::TagParser
00076     //  METHOD TYPE : Ctor
00077     //
00078     TagParser::TagParser()
00079     {}
00080 
00082     //
00083     //  METHOD NAME : TagParser::~TagParser
00084     //  METHOD TYPE : Dtor
00085     //
00086     TagParser::~TagParser()
00087     {}
00088 
00089     void TagParser::beginParse()
00090     {}
00091     void TagParser::consume( const SingleTagPtr & tag_r )
00092     {}
00093     void TagParser::consume( const MultiTagPtr & tag_r )
00094     {}
00095     void TagParser::endParse()
00096     {}
00097 
00098     void TagParser::userRequestedAbort( unsigned lineNo_r )
00099     { ZYPP_THROW( AbortRequestException( errPrefix( lineNo_r ) ) ); }
00100 
00102     //
00103     //  METHOD NAME : TagParser::errPrefix
00104     //  METHOD TYPE : std::string
00105     //
00106     std::string TagParser::errPrefix( unsigned lineNo_r,
00107                                       const std::string & msg_r ) const
00108     {
00109       return str::form( "%s:%u:- | %s",
00110                         _inputname.c_str(),
00111                         lineNo_r,
00112                         msg_r.c_str() );
00113     }
00114 
00115     std::string TagParser::errPrefix( const SingleTagPtr & tag_r,
00116                                       const std::string & msg_r ) const
00117     {
00118       return str::form( "%s:%u:=%s %s | %s",
00119                         _inputname.c_str(),
00120                         tag_r->lineNo,
00121                         tag_r->asString().c_str(),
00122                         tag_r->value.c_str(),
00123                         msg_r.c_str() );
00124     }
00125 
00126     std::string TagParser::errPrefix( const MultiTagPtr & tag_r,
00127                                       const std::string & msg_r ) const
00128     {
00129       return str::form( "%s:%u:+%s (@%u) | %s",
00130                         _inputname.c_str(),
00131                         tag_r->lineNo,
00132                         tag_r->asString().c_str(),
00133                         tag_r->value.size(),
00134                         msg_r.c_str() );
00135     }
00136 
00138     namespace
00139     { 
00140 
00145       inline bool helperParseStartTag( TagParser::Tag & tag_r, const char *& begin_r )
00146       {
00147         const char * tsep = 0;  // find ':'
00148         const char * esep = 0;  // remember last '.'
00149         for ( const char * ch = begin_r; *ch; ++ch )
00150         {
00151           switch ( *ch )
00152           {
00153             case '.':
00154               esep = ch; // remember
00155               break;
00156             case ':':
00157               tsep = ch;
00158               ch = 0;    // done: found ':'
00159               break;
00160             case ' ':
00161             case '\t':
00162             case '\n':
00163             case '\r':
00164               ch = 0; // fail: no whitespace allowed in tag
00165               break;
00166           }
00167           if ( ! ch )
00168             break;
00169         }
00170 
00171         if ( ! tsep )
00172           return false; // no tag found
00173 
00174         // Update name and modifier
00175         if ( esep )
00176         {
00177           std::string( begin_r, esep-begin_r ).swap( tag_r.name );
00178           ++esep;
00179           std::string( esep, tsep-esep ).swap( tag_r.modifier );
00180         }
00181         else
00182         {
00183           std::string( begin_r, tsep-begin_r ).swap( tag_r.name );
00184         }
00185 
00186         begin_r = tsep+1; // behind ':'
00187         return true;
00188       }
00189 
00191     } // namespace
00193 
00195     //
00196     //  METHOD NAME : TagParser::parse
00197     //  METHOD TYPE : void
00198     //
00199     void TagParser::parse( const InputStream & input_r, const ProgressData::ReceiverFnc & fnc_r )
00200     {
00201       MIL << "Start parsing " << input_r << endl;
00202       if ( ! input_r.stream() )
00203       {
00204         std::ostringstream s;
00205         s << "Can't read bad stream: " << input_r;
00206         ZYPP_THROW( ParseException( s.str() ) );
00207       }
00208       _inputname = input_r.name();
00209       beginParse();
00210 
00211       ProgressData ticks( makeProgressData( input_r ) );
00212       ticks.sendTo( fnc_r );
00213       if ( ! ticks.toMin() )
00214         userRequestedAbort( 0 );
00215 
00216       iostr::EachLine line( input_r );
00217       for( ; line; line.next() )
00218       {
00219         const char * cp = (*line).c_str();
00220         switch ( *cp )
00221         {
00223           case '=': // get single line data
00224           {
00225             SingleTagPtr tagP( new SingleTag( line.lineNo(), line.lineStart() ) );
00226             SingleTag & tag( *tagP.get() );
00227 
00228             const char * cp = (*line).c_str() + 1;
00229             if ( helperParseStartTag( tag, cp ) )
00230             {
00231               while ( *cp == ' ' || *cp == '\t' )
00232                 ++cp;
00233 
00234               tag.dataStart = tag.tagStart + cp - (*line).c_str();
00235 
00236               if ( *cp ) // not at string end
00237               {
00238                 const char * ep = (*line).c_str() + (*line).size();
00239                 do {
00240                   --ep;
00241                 } while ( *ep == ' ' || *ep == '\t' );
00242                 tag.dataLength = ep+1-cp;
00243                 std::string( cp, tag.dataLength ).swap( tag.value );
00244               }
00245 
00246               consume( tagP );
00247             }
00248             else
00249             {
00250               ZYPP_THROW( ParseException( errPrefix( line.lineNo(), "Orphan data: " + (*line) ) ) );
00251             }
00252           }
00253           break;
00254 
00256           case '+': // get mulit line data
00257           {
00258             MultiTagPtr tagP( new MultiTag(line.lineNo(), line.lineStart() ) );
00259             MultiTag & tag( *tagP.get() );
00260 
00261             const char * cp = (*line).c_str() + 1;
00262             if ( helperParseStartTag( tag, cp ) )
00263             {
00264               std::string endTag( "-" );
00265               endTag += tag.name;
00266               if ( ! tag.modifier.empty() )
00267               {
00268                 endTag += ".";
00269                 endTag += tag.modifier;
00270               }
00271               endTag += ":";
00272 
00273               line.next();
00274               tag.dataStart = line.lineStart();
00275 
00276               for( ; line; line.next() )
00277               {
00278                 if ( str::hasPrefix( *line, endTag ) )
00279                 {
00280                   tag.dataLength = line.lineStart() - tag.dataStart;
00281                   break;
00282                 }
00283                 else
00284                 {
00285                   tag.value.push_back( *line );
00286                 }
00287               }
00288 
00289               if ( ! line )
00290               {
00291                 ZYPP_THROW( ParseException( errPrefix( tagP, "Reached EOF while looking for end tag") ) );
00292               }
00293 
00294               consume( tagP );
00295             }
00296             else
00297             {
00298               ZYPP_THROW( ParseException( errPrefix( line.lineNo(), "Orphan data: " + (*line) ) ) );
00299             }
00300           }
00301           break;
00302 
00304           default: // empty or comment
00305           {
00306             for ( const char * cp = (*line).c_str(); *cp; ++cp )
00307             {
00308               switch( *cp )
00309               {
00310                 case ' ':
00311                 case '\t':
00312                 case '\r':
00313                 case '\n':
00314                   break;
00315 
00316                 default:
00317                   if ( *cp != '#' )
00318                   {
00319                     ZYPP_THROW( ParseException( errPrefix( line.lineNo(), "Orphan data: " + (*line) ) ) );
00320                   }
00321                   cp = 0;
00322                   break;
00323               }
00324 
00325               if ( ! cp )
00326               {
00327                 break;
00328               }
00329             }
00330           }
00331           break;
00332         }
00333 
00334         if ( ! ticks.set( input_r.stream().tellg() ) )
00335           userRequestedAbort( line.lineNo() );
00336       }
00337 
00338       if ( ! ticks.toMax() )
00339         userRequestedAbort( line.lineNo() );
00340 
00341       endParse();
00342       _inputname.clear();
00343       MIL << "Done parsing " << input_r << endl;
00344     }
00345 
00347   } // namespace parser
00350 } // namespace zypp

Generated on Tue Sep 25 19:23:03 2007 for libzypp by  doxygen 1.5.3