00001
00002
00003
00004
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
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
00070
00072
00074
00075
00076
00077
00078 TagParser::TagParser()
00079 {}
00080
00082
00083
00084
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
00104
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;
00148 const char * esep = 0;
00149 for ( const char * ch = begin_r; *ch; ++ch )
00150 {
00151 switch ( *ch )
00152 {
00153 case '.':
00154 esep = ch;
00155 break;
00156 case ':':
00157 tsep = ch;
00158 ch = 0;
00159 break;
00160 case ' ':
00161 case '\t':
00162 case '\n':
00163 case '\r':
00164 ch = 0;
00165 break;
00166 }
00167 if ( ! ch )
00168 break;
00169 }
00170
00171 if ( ! tsep )
00172 return false;
00173
00174
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;
00187 return true;
00188 }
00189
00191 }
00193
00195
00196
00197
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 '=':
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 )
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 '+':
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:
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 }
00350 }