PoolQuery.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/Gettext.h"
00016 #include "zypp/base/LogTools.h"
00017 #include "zypp/base/Algorithm.h"
00018 #include "zypp/base/String.h"
00019 #include "zypp/repo/RepoException.h"
00020 #include "zypp/RelCompare.h"
00021 
00022 #include "zypp/sat/Pool.h"
00023 #include "zypp/sat/Solvable.h"
00024 #include "zypp/sat/AttrMatcher.h"
00025 
00026 #include "zypp/PoolQuery.h"
00027 
00028 #undef ZYPP_BASE_LOGGER_LOGGROUP
00029 #define ZYPP_BASE_LOGGER_LOGGROUP "PoolQuery"
00030 
00031 using namespace std;
00032 using namespace zypp::sat;
00033 
00035 namespace zypp
00036 { 
00037 
00039   namespace
00040   { 
00041 
00043     // some Helpers and Predicates
00045 
00046     bool isDependencyAttribute( sat::SolvAttr attr_r )
00047     {
00048       static sat::SolvAttr deps[] = {
00049         SolvAttr::provides,
00050         SolvAttr::requires,
00051         SolvAttr::recommends,
00052         SolvAttr::obsoletes,
00053         SolvAttr::conflicts,
00054         SolvAttr::suggests,
00055         SolvAttr::supplements,
00056         SolvAttr::enhances,
00057       };
00058       for_( it, arrayBegin(deps), arrayEnd(deps) )
00059         if ( *it == attr_r )
00060           return true;
00061       return false;
00062     }
00063 
00068     struct EditionRangePredicate
00069     {
00070       EditionRangePredicate( const Rel & op, const Edition & edition )
00071         : _range( op, edition )
00072       {}
00073 
00074       bool operator()( sat::LookupAttr::iterator iter_r )
00075       {
00076         CapDetail cap( iter_r.id() );
00077         if ( ! cap.isSimple() )
00078           return false;
00079         if ( cap.isNamed() ) // no range to match
00080           return true;
00081         return overlaps( Edition::MatchRange( cap.op(), cap.ed() ), _range );
00082       }
00083 
00084       std::string serialize() const
00085       {
00086         std::string ret( "EditionRange" );
00087         str::appendEscaped( ret, _range.op.asString() );
00088         str::appendEscaped( ret, _range.value.asString() );
00089         return ret;
00090       }
00091 
00092       Edition::MatchRange _range;
00093     };
00094 
00096     struct SolvableRangePredicate
00097     {
00098       SolvableRangePredicate( const Rel & op, const Edition & edition )
00099         : _range( op, edition )
00100       {}
00101 
00102       bool operator()( sat::LookupAttr::iterator iter_r )
00103       {
00104         return overlaps( Edition::MatchRange( Rel::EQ, iter_r.inSolvable().edition() ), _range );
00105       }
00106 
00107       std::string serialize() const
00108       {
00109         std::string ret( "SolvableRange" );
00110         str::appendEscaped( ret, _range.op.asString() );
00111         str::appendEscaped( ret, _range.value.asString() );
00112         return ret;
00113       }
00114 
00115       Edition::MatchRange _range;
00116     };
00117 
00122     struct CapabilityMatchPredicate
00123     {
00124       CapabilityMatchPredicate( Capability cap_r )
00125         : _cap( cap_r )
00126       {}
00127 
00128       bool operator()( sat::LookupAttr::iterator iter_r ) const
00129       {
00130         return _cap.matches( iter_r.asType<Capability>() ) == CapMatch::yes;
00131       }
00132 
00133       std::string serialize() const
00134       {
00135         std::string ret( "CapabilityMatch" );
00136         str::appendEscaped( ret, _cap.asString() );
00137         return ret;
00138       }
00139 
00140       Capability _cap;
00141     };
00142 
00144     //
00146 
00164     struct AttrMatchData
00165     {
00166       typedef function<bool(sat::LookupAttr::iterator)> Predicate;
00167 
00168       static bool always( sat::LookupAttr::iterator ) { return true; }
00169       static bool never( sat::LookupAttr::iterator ) { return false; }
00170 
00171       AttrMatchData()
00172       {}
00173 
00174       AttrMatchData( sat::SolvAttr attr_r, const sat::AttrMatcher & attrMatcher_r )
00175         : attr( attr_r )
00176         , attrMatcher( attrMatcher_r )
00177       {}
00178 
00179       AttrMatchData( sat::SolvAttr attr_r, const sat::AttrMatcher & attrMatcher_r,
00180                      const Predicate & predicate_r, const std::string & predicateStr_r )
00181         : attr( attr_r )
00182         , attrMatcher( attrMatcher_r )
00183         , predicate( predicate_r )
00184         , predicateStr( predicateStr_r )
00185       {}
00186 
00192       template<class _Predicate>
00193       void addPredicate( const _Predicate & predicate_r )
00194       {
00195         predicate    = predicate_r;
00196         predicateStr = predicate_r.serialize();
00197       }
00198 
00204       std::string serialize() const
00205       {
00206         std::string ret( "AttrMatchData" );
00207         str::appendEscaped( ret, attr.asString() );
00208         str::appendEscaped( ret, attrMatcher.searchstring() );
00209         // TODO: Actually the flag should be serialized too, but for PoolQuery
00210         // it's by now sufficient to differ between mode OTHER and others,
00211         // i.e. whether to compile or not compile.
00212         str::appendEscaped( ret, attrMatcher.flags().mode() == Match::OTHER ? "C" : "X" );
00213         str::appendEscaped( ret, predicateStr );
00214         return ret;
00215       }
00216 
00220       static AttrMatchData deserialize( const std::string & str_r )
00221       {
00222         std::vector<std::string> words;
00223         str::splitEscaped( str_r, std::back_inserter(words) );
00224         if ( words.empty() || words[0] != "AttrMatchData" )
00225           ZYPP_THROW( Exception( str::Str() << "Expecting AttrMatchData: " << str_r ) );
00226         if ( words.size() != 5 )
00227           ZYPP_THROW( Exception( str::Str() << "Wrong number of words: " << str_r ) );
00228 
00229         AttrMatchData ret;
00230         ret.attr = sat::SolvAttr( words[1] );
00231         ret.attrMatcher = sat::AttrMatcher( words[2] );
00232         if ( words[3] == "C" )
00233           ret.attrMatcher.setFlags( Match::OTHER );
00234         ret.predicateStr = words[4];
00235 
00236         // now the predicate
00237         words.clear();
00238         str::splitEscaped( ret.predicateStr, std::back_inserter(words) );
00239         if ( ! words.empty() )
00240         {
00241           if ( words[0] == "EditionRange" )
00242           {
00243             if ( words.size() != 3 )
00244               ZYPP_THROW( Exception( str::Str() << "Wrong number of words: " << str_r ) );
00245             ret.predicate = EditionRangePredicate( Rel(words[1]), Edition(words[2]) );
00246           }
00247           else if ( words[0] == "SolvableRange" )
00248           {
00249             if ( words.size() != 3 )
00250               ZYPP_THROW( Exception( str::Str() << "Wrong number of words: " << str_r ) );
00251             ret.predicate = SolvableRangePredicate( Rel(words[1]), Edition(words[2]) );
00252           }
00253           else if ( words[0] == "CapabilityMatch" )
00254           {
00255             if ( words.size() != 2 )
00256               ZYPP_THROW( Exception( str::Str() << "Wrong number of words: " << str_r ) );
00257             ret.predicate = CapabilityMatchPredicate( Capability(words[1]) );
00258           }
00259           else
00260             ZYPP_THROW( Exception( str::Str() << "Unknown predicate: " << str_r ) );
00261         }
00262         return ret;
00263      }
00264 
00265       sat::SolvAttr    attr;
00266       sat::AttrMatcher attrMatcher;
00267       Predicate        predicate;
00268       std::string      predicateStr;
00269     };
00270 
00272     inline std::ostream & operator<<( std::ostream & str, const AttrMatchData & obj )
00273     {
00274       str << obj.attr << ": " << obj.attrMatcher;
00275       if ( obj.predicate )
00276         str << " +(" << obj.predicateStr << ")";
00277       return str;
00278     }
00279 
00281     inline bool operator==( const AttrMatchData & lhs, const AttrMatchData & rhs )
00282     {
00283       return ( lhs.attr == rhs.attr
00284                && lhs.attrMatcher == rhs.attrMatcher
00285                && lhs.predicateStr == rhs.predicateStr );
00286     }
00287 
00289     inline bool operator!=( const AttrMatchData & lhs, const AttrMatchData & rhs )
00290     { return !( lhs == rhs ); }
00291 
00293     inline bool operator<( const AttrMatchData & lhs, const AttrMatchData & rhs )
00294     {
00295       if ( lhs.attr != rhs.attr )
00296         return (  lhs.attr < rhs.attr );
00297       if ( lhs.attrMatcher != rhs.attrMatcher )
00298         return (  lhs.attrMatcher < rhs.attrMatcher );
00299       if ( lhs.predicateStr != rhs.predicateStr )
00300         return (  lhs.predicateStr < rhs.predicateStr );
00301       return false;
00302     }
00303 
00304     typedef std::list<AttrMatchData> AttrMatchList;
00305 
00306 
00307   } 
00308   // namespace
00310 
00312   //
00313   //  CLASS NAME : PoolQuery::Impl
00314   //
00316   class PoolQuery::Impl
00317   {
00318   public:
00319     Impl()
00320       : _flags( Match::SUBSTRING | Match::NOCASE | Match::SKIP_KIND )
00321       , _match_word(false)
00322       , _require_all(false)
00323       , _status_flags(ALL)
00324     {}
00325 
00326     ~Impl()
00327     {}
00328 
00329   public:
00331     string asString() const;
00332 
00336     StrContainer _strings;
00338     AttrRawStrMap _attrs;
00340     std::set<AttrMatchData> _uncompiledPredicated;
00341 
00343     Match _flags;
00344     bool _match_word;
00345     bool _require_all;
00346 
00348     StatusFilter _status_flags;
00349 
00351     Edition _edition;
00353     Rel _op;
00354 
00356     StrContainer _repos;
00357 
00359     Kinds _kinds;
00361 
00362   public:
00363 
00364     bool operator==( const PoolQuery::Impl & rhs ) const
00365     {
00366       return ( _strings == rhs._strings
00367                && _attrs == rhs._attrs
00368                && _uncompiledPredicated == rhs._uncompiledPredicated
00369                && _flags == rhs._flags
00370                && _match_word == rhs._match_word
00371                && _require_all == rhs._require_all
00372                && _status_flags == rhs._status_flags
00373                && _edition == rhs._edition
00374                && _op == rhs._op
00375                && _repos == rhs._repos
00376                && _kinds == rhs._kinds );
00377     }
00378 
00379     bool operator!=( const PoolQuery::Impl & rhs ) const
00380     { return ! operator==( rhs ); }
00381 
00382   public:
00387     void compile() const;
00388 
00390     mutable AttrMatchList _attrMatchList;
00391 
00392   private:
00394     string createRegex( const StrContainer & container, const Match & flags ) const;
00395 
00396   private:
00397     friend Impl * rwcowClone<Impl>( const Impl * rhs );
00399     Impl * clone() const
00400     { return new Impl( *this ); }
00401   };
00402 
00404 
00405   struct MyInserter
00406   {
00407     MyInserter(PoolQuery::StrContainer & cont) : _cont(cont) {}
00408 
00409     bool operator()(const string & str)
00410     {
00411       _cont.insert(str);
00412       return true;
00413     }
00414 
00415     PoolQuery::StrContainer & _cont;
00416   };
00417 
00418 
00419   struct EmptyFilter
00420   {
00421     bool operator()(const string & str)
00422     {
00423       return !str.empty();
00424     }
00425   };
00426 
00427   void PoolQuery::Impl::compile() const
00428   {
00429     _attrMatchList.clear();
00430 
00431     Match cflags( _flags );
00432     if ( cflags.mode() == Match::OTHER ) // this will never succeed...
00433       ZYPP_THROW( MatchUnknownModeException( cflags ) );
00434 
00436     string rcstrings;
00437 
00438 
00439     // 'different'         - will have to iterate through all and match by ourselves (slow)
00440     // 'same'              - will pass the compiled string to dataiterator_init
00441     // 'one-attr'          - will pass it to dataiterator_init
00442     // 'one-non-regex-str' - will pass to dataiterator_init, set flag to SEARCH_STRING or SEARCH_SUBSTRING
00443 
00444     // // NO ATTRIBUTE
00445     // else
00446     //   for all _strings
00447     //     create regex; store in rcstrings; if more strings flag regex;
00448     if (_attrs.empty())
00449     {
00450       ; // A default 'query-all' will be added after all sources are processed.
00451     }
00452 
00453     // // ONE ATTRIBUTE
00454     // else if _attrs is not empty but it contains just one attr
00455     //   for all _strings and _attr[key] strings
00456     //     create regex; flag 'one-attr'; if more strings flag regex;
00457     else if (_attrs.size() == 1)
00458     {
00459       StrContainer joined;
00460       invokeOnEach(_strings.begin(), _strings.end(), EmptyFilter(), MyInserter(joined));
00461       invokeOnEach(_attrs.begin()->second.begin(), _attrs.begin()->second.end(), EmptyFilter(), MyInserter(joined));
00462       rcstrings = createRegex(joined, cflags);
00463       if (joined.size() > 1) // switch to regex for multiple strings
00464         cflags.setModeRegex();
00465       _attrMatchList.push_back( AttrMatchData( _attrs.begin()->first,
00466                                 sat::AttrMatcher( rcstrings, cflags ) ) );
00467     }
00468 
00469     // // MULTIPLE ATTRIBUTES
00470     else
00471     {
00472       // check whether there are any per-attribute strings
00473       bool attrvals_empty = true;
00474       for (AttrRawStrMap::const_iterator ai = _attrs.begin(); ai != _attrs.end(); ++ai)
00475         if (!ai->second.empty())
00476           for(StrContainer::const_iterator it = ai->second.begin();
00477               it != ai->second.end(); it++)
00478             if (!it->empty())
00479             {
00480               attrvals_empty = false;
00481               goto attremptycheckend;
00482             }
00483 attremptycheckend:
00484 
00485       // chceck whether the per-attribute strings are all the same
00486       bool attrvals_thesame = true;
00487       AttrRawStrMap::const_iterator ai = _attrs.begin();
00488       const StrContainer & set1 = ai->second;
00489       ++ai;
00490       for (; ai != _attrs.end(); ++ai)
00491       {
00492         StrContainer result;
00493         set_difference(
00494           set1.begin(), set1.end(),
00495           ai->second.begin(), ai->second.end(),
00496           inserter(result, result.begin())/*, ltstr()*/);
00497         if (!result.empty())
00498         {
00499           attrvals_thesame = false;
00500           break;
00501         }
00502       }
00503 
00504       // // THE SAME STRINGS FOR DIFFERENT ATTRS
00505       // else if _attrs is not empty but it does not contain strings
00506       //   for each key in _attrs take all _strings
00507       //     create regex; store in rcstrings; flag 'same'; if more strings flag regex;
00508       if (attrvals_empty || attrvals_thesame)
00509       {
00510         StrContainer joined;
00511         if (attrvals_empty)
00512         {
00513           invokeOnEach(_strings.begin(), _strings.end(), EmptyFilter(), MyInserter(joined));
00514           rcstrings = createRegex(joined, cflags);
00515         }
00516         else
00517         {
00518           invokeOnEach(_strings.begin(), _strings.end(), EmptyFilter(), MyInserter(joined));
00519           invokeOnEach(_attrs.begin()->second.begin(), _attrs.begin()->second.end(), EmptyFilter(), MyInserter(joined));
00520           rcstrings = createRegex(joined, cflags);
00521         }
00522         if (joined.size() > 1) // switch to regex for multiple strings
00523           cflags.setModeRegex();
00524         // May use the same AttrMatcher for all
00525         sat::AttrMatcher matcher( rcstrings, cflags );
00526         for_( ai, _attrs.begin(), _attrs.end() )
00527         {
00528           _attrMatchList.push_back( AttrMatchData( ai->first, matcher ) );
00529         }
00530       }
00531 
00532       // // DIFFERENT STRINGS FOR DIFFERENT ATTRS
00533       // if _attrs is not empty and it contains non-empty vectors with non-empty strings
00534       //   for each key in _attrs take all _strings + all _attrs[key] strings
00535       //     create regex; flag 'different'; if more strings flag regex;
00536       else
00537       {
00538         for_(ai, _attrs.begin(), _attrs.end())
00539         {
00540           StrContainer joined;
00541           invokeOnEach(_strings.begin(), _strings.end(), EmptyFilter(), MyInserter(joined));
00542           invokeOnEach(ai->second.begin(), ai->second.end(), EmptyFilter(), MyInserter(joined));
00543           string s = createRegex(joined, cflags);
00544           if (joined.size() > 1) // switch to regex for multiple strings
00545             cflags.setModeRegex();
00546           _attrMatchList.push_back( AttrMatchData( ai->first,
00547                                     sat::AttrMatcher( s, cflags ) ) );
00548         }
00549       }
00550     }
00551 
00552     // Now handle any predicated queries
00553     if ( ! _uncompiledPredicated.empty() )
00554     {
00555       StrContainer global;
00556       invokeOnEach( _strings.begin(), _strings.end(), EmptyFilter(), MyInserter(global) );
00557       for_( it, _uncompiledPredicated.begin(), _uncompiledPredicated.end() )
00558       {
00559         if ( it->attrMatcher.flags().mode() == Match::OTHER )
00560         {
00561           // need to compile:
00562           StrContainer joined( global );
00563           const std::string & mstr( it->attrMatcher.searchstring() );
00564           if ( ! mstr.empty() )
00565             joined.insert( mstr );
00566 
00567           cflags = _flags;
00568           rcstrings = createRegex( joined, cflags );
00569           if ( joined.size() > 1 ) // switch to regex for multiple strings
00570             cflags.setModeRegex();
00571 
00572           _attrMatchList.push_back( AttrMatchData( it->attr,
00573                                     sat::AttrMatcher( rcstrings, cflags ),
00574                                                       it->predicate, it->predicateStr ) );
00575         }
00576         else
00577         {
00578           // copy matcher
00579          _attrMatchList.push_back( *it );
00580         }
00581       }
00582     }
00583 
00584     // If no attributes defined at all, then add 'query all'
00585     if ( _attrMatchList.empty() )
00586     {
00587       cflags = _flags;
00588       rcstrings = createRegex( _strings, cflags );
00589       if ( _strings.size() > 1 ) // switch to regex for multiple strings
00590         cflags.setModeRegex();
00591       _attrMatchList.push_back( AttrMatchData( sat::SolvAttr::allAttr,
00592                                 sat::AttrMatcher( rcstrings, cflags ) ) );
00593     }
00594 
00595     // Finally check here, whether all involved regex compile.
00596     for_( it, _attrMatchList.begin(), _attrMatchList.end() )
00597     {
00598       it->attrMatcher.compile(); // throws on error
00599     }
00600     //DBG << asString() << endl;
00601   }
00602 
00603 
00607   static string wildcards2regex(const string & str)
00608   {
00609     string regexed = str;
00610 
00611     string r_all(".*"); // regex equivalent of '*'
00612     string r_one(".");  // regex equivalent of '?'
00613     string::size_type pos;
00614 
00615     // replace all "*" in input with ".*"
00616     for (pos = 0; (pos = regexed.find("*", pos)) != std::string::npos; pos+=2)
00617       regexed = regexed.replace(pos, 1, r_all);
00618 
00619     // replace all "?" in input with "."
00620     for (pos = 0; (pos = regexed.find('?', pos)) != std::string::npos; ++pos)
00621       regexed = regexed.replace(pos, 1, r_one);
00622 
00623     return regexed;
00624   }
00625 
00626   string PoolQuery::Impl::createRegex( const StrContainer & container, const Match & flags ) const
00627   {
00629 #define WB (_match_word ? string("\\b") : string())
00630     string rstr;
00631 
00632     if (container.empty())
00633       return rstr;
00634 
00635     if (container.size() == 1)
00636     {
00637       return WB + *container.begin() + WB;
00638     }
00639 
00640     // multiple strings
00641 
00642     bool use_wildcards = flags.isModeGlob();
00643     StrContainer::const_iterator it = container.begin();
00644     string tmp;
00645 
00646     if (use_wildcards)
00647       tmp = wildcards2regex(*it);
00648     else
00649       tmp = *it;
00650 
00651     if (_require_all)
00652     {
00653       if ( ! flags.isModeString() ) // not match exact
00654         tmp += ".*" + WB + tmp;
00655       rstr = "(?=" + tmp + ")";
00656     }
00657     else
00658     {
00659       if ( flags.isModeString() || flags.isModeGlob() )
00660         rstr = "^";
00661       rstr += WB + "(" + tmp;
00662     }
00663 
00664     ++it;
00665 
00666     for (; it != container.end(); ++it)
00667     {
00668       if (use_wildcards)
00669         tmp = wildcards2regex(*it);
00670       else
00671         tmp = *it;
00672 
00673       if (_require_all)
00674       {
00675         if ( ! flags.isModeString() ) // not match exact
00676           tmp += ".*" + WB + tmp;
00677         rstr += "(?=" + tmp + ")";
00678       }
00679       else
00680       {
00681         rstr += "|" + tmp;
00682       }
00683     }
00684 
00685     if (_require_all)
00686     {
00687       if ( ! flags.isModeString() ) // not match exact
00688         rstr += WB + ".*";
00689     }
00690     else
00691     {
00692       rstr += ")" + WB;
00693       if ( flags.isModeString() || flags.isModeGlob() )
00694         rstr += "$";
00695     }
00696 
00697     return rstr;
00698 #undef WB
00699   }
00700 
00701   string PoolQuery::Impl::asString() const
00702   {
00703     ostringstream o;
00704 
00705     o << "kinds: ";
00706     if ( _kinds.empty() )
00707       o << "ALL";
00708     else
00709     {
00710       for(Kinds::const_iterator it = _kinds.begin();
00711           it != _kinds.end(); ++it)
00712         o << *it << " ";
00713     }
00714     o << endl;
00715 
00716     o << "repos: ";
00717     if ( _repos.empty() )
00718       o << "ALL";
00719     else
00720     {
00721       for(StrContainer::const_iterator it = _repos.begin();
00722           it != _repos.end(); ++it)
00723         o << *it << " ";
00724     }
00725     o << endl;
00726 
00727     o << "version: "<< _op << " " << _edition.asString() << endl;
00728     o << "status: " << ( _status_flags ? ( _status_flags == INSTALLED_ONLY ? "INSTALLED_ONLY" : "UNINSTALLED_ONLY" )
00729                                        : "ALL" ) << endl;
00730 
00731     o << "string match flags: " << Match(_flags) << endl;
00732 
00733     // raw
00734     o << "strings: ";
00735     for(StrContainer::const_iterator it = _strings.begin();
00736         it != _strings.end(); ++it)
00737       o << *it << " ";
00738     o << endl;
00739 
00740     o << "attributes: " << endl;
00741     for(AttrRawStrMap::const_iterator ai = _attrs.begin(); ai != _attrs.end(); ++ai)
00742     {
00743       o << "* " << ai->first << ": ";
00744       for(StrContainer::const_iterator vi = ai->second.begin();
00745           vi != ai->second.end(); ++vi)
00746         o << *vi << " ";
00747       o << endl;
00748     }
00749 
00750     o << "predicated: " << endl;
00751     for_( it, _uncompiledPredicated.begin(), _uncompiledPredicated.end() )
00752     {
00753       o << "* " << *it << endl;
00754     }
00755 
00756     // compiled
00757     o << "last attribute matcher compiled: " << endl;
00758     if ( _attrMatchList.empty() )
00759     {
00760       o << "not yet compiled" << endl;
00761     }
00762     else
00763     {
00764       for_( it, _attrMatchList.begin(), _attrMatchList.end() )
00765       {
00766         o << "* " << *it << endl;
00767       }
00768     }
00769     return o.str();
00770   }
00771 
00773 
00775   //
00776   //    CLASS NAME : PoolQuery
00777   //
00779 
00780   PoolQuery::PoolQuery()
00781     : _pimpl(new Impl())
00782   {}
00783 
00784   PoolQuery::~PoolQuery()
00785   {}
00786 
00787   void PoolQuery::addRepo(const std::string &repoalias)
00788   {
00789     if (repoalias.empty())
00790     {
00791       WAR << "ignoring an empty repository alias" << endl;
00792       return;
00793     }
00794     _pimpl->_repos.insert(repoalias);
00795   }
00796 
00797   void PoolQuery::addKind(const ResKind & kind)
00798   { _pimpl->_kinds.insert(kind); }
00799 
00800   void PoolQuery::addString(const string & value)
00801   { _pimpl->_strings.insert(value); }
00802 
00803   void PoolQuery::addAttribute(const sat::SolvAttr & attr, const std::string & value)
00804   { _pimpl->_attrs[attr].insert(value); }
00805 
00806   void PoolQuery::addDependency( const sat::SolvAttr & attr, const std::string & name, const Rel & op, const Edition & edition )
00807   {
00808     switch ( op.inSwitch() )
00809     {
00810       case Rel::ANY_e:  // no additional constraint on edition.
00811         addAttribute( attr, name );
00812         return;
00813 
00814       case Rel::NONE_e: // will never match.
00815         return;
00816 
00817       default: // go and add the predicated query (uncompiled)
00818         break;
00819     }
00820 
00821     // Match::OTHER indicates need to compile
00822     // (merge global search strings into name).
00823     AttrMatchData attrMatchData( attr, sat::AttrMatcher( name, Match::OTHER ) );
00824 
00825     if ( isDependencyAttribute( attr ) )
00826       attrMatchData.addPredicate( EditionRangePredicate( op, edition ) );
00827     else
00828       attrMatchData.addPredicate( SolvableRangePredicate( op, edition ) );
00829 
00830     _pimpl->_uncompiledPredicated.insert( attrMatchData );
00831   }
00832 
00833   void PoolQuery::addDependency( const sat::SolvAttr & attr, Capability cap_r )
00834   {
00835     CapDetail cap( cap_r );
00836     if ( ! cap.isSimple() ) // will never match.
00837       return;
00838 
00839     // Matches STRING per default. (won't get compiled!)
00840     AttrMatchData attrMatchData( attr, sat::AttrMatcher( cap.name().asString() ) );
00841 
00842     if ( isDependencyAttribute( attr ) )
00843       attrMatchData.addPredicate( CapabilityMatchPredicate( cap_r ) );
00844     else
00845       attrMatchData.addPredicate( SolvableRangePredicate( cap.op(), cap.ed() ) );
00846 
00847     _pimpl->_uncompiledPredicated.insert( attrMatchData );
00848   }
00849 
00850   void PoolQuery::setEdition(const Edition & edition, const Rel & op)
00851   {
00852     _pimpl->_edition = edition;
00853     _pimpl->_op = op;
00854   }
00855 
00856   void PoolQuery::setMatchSubstring()   { _pimpl->_flags.setModeSubstring(); }
00857   void PoolQuery::setMatchExact()       { _pimpl->_flags.setModeString(); }
00858   void PoolQuery::setMatchRegex()       { _pimpl->_flags.setModeRegex(); }
00859   void PoolQuery::setMatchGlob()        { _pimpl->_flags.setModeGlob(); }
00860   void PoolQuery::setMatchWord()
00861   {
00862     _pimpl->_match_word = true;
00863     _pimpl->_flags.setModeRegex();
00864   }
00865 
00866   Match PoolQuery::flags() const
00867   { return _pimpl->_flags; }
00868   void PoolQuery::setFlags( const Match & flags )
00869   { _pimpl->_flags = flags; }
00870 
00871 
00872   void PoolQuery::setInstalledOnly()
00873   { _pimpl->_status_flags = INSTALLED_ONLY; }
00874   void PoolQuery::setUninstalledOnly()
00875   { _pimpl->_status_flags = UNINSTALLED_ONLY; }
00876   void PoolQuery::setStatusFilterFlags( PoolQuery::StatusFilter flags )
00877   { _pimpl->_status_flags = flags; }
00878 
00879 
00880   void PoolQuery::setRequireAll(bool require_all)
00881   { _pimpl->_require_all = require_all; }
00882 
00883 
00884   const PoolQuery::StrContainer &
00885   PoolQuery::strings() const
00886   { return _pimpl->_strings; }
00887 
00888   const PoolQuery::AttrRawStrMap &
00889   PoolQuery::attributes() const
00890   { return _pimpl->_attrs; }
00891 
00892   const PoolQuery::StrContainer &
00893   PoolQuery::attribute(const sat::SolvAttr & attr) const
00894   {
00895     static const PoolQuery::StrContainer nocontainer;
00896     AttrRawStrMap::const_iterator it = _pimpl->_attrs.find(attr);
00897     return it != _pimpl->_attrs.end() ? it->second : nocontainer;
00898   }
00899 
00900   const Edition PoolQuery::edition() const
00901   { return _pimpl->_edition; }
00902   const Rel PoolQuery::editionRel() const
00903   { return _pimpl->_op; }
00904 
00905 
00906   const PoolQuery::Kinds &
00907   PoolQuery::kinds() const
00908   { return _pimpl->_kinds; }
00909 
00910   const PoolQuery::StrContainer &
00911   PoolQuery::repos() const
00912   { return _pimpl->_repos; }
00913 
00914 
00915   bool PoolQuery::caseSensitive() const
00916   { return !_pimpl->_flags.test( Match::NOCASE ); }
00917   void PoolQuery::setCaseSensitive( bool value )
00918   { _pimpl->_flags.turn( Match::NOCASE, !value ); }
00919 
00920   bool PoolQuery::filesMatchFullPath() const
00921   { return _pimpl->_flags.test( Match::FILES ); }
00922   void PoolQuery::setFilesMatchFullPath( bool value )
00923   { _pimpl->_flags.turn( Match::FILES, value ); }
00924 
00925   bool PoolQuery::matchExact() const            { return _pimpl->_flags.isModeString(); }
00926   bool PoolQuery::matchSubstring() const        { return _pimpl->_flags.isModeSubstring(); }
00927   bool PoolQuery::matchGlob() const             { return _pimpl->_flags.isModeGlob(); }
00928   bool PoolQuery::matchRegex() const            { return _pimpl->_flags.isModeRegex(); }
00929 
00930   bool PoolQuery::matchWord() const
00931   { return _pimpl->_match_word; }
00932 
00933   bool PoolQuery::requireAll() const
00934   { return _pimpl->_require_all; }
00935 
00936   PoolQuery::StatusFilter PoolQuery::statusFilterFlags() const
00937   { return _pimpl->_status_flags; }
00938 
00939   bool PoolQuery::empty() const
00940   {
00941     try { return begin() == end(); }
00942     catch (const Exception & ex) {}
00943     return true;
00944   }
00945 
00946   PoolQuery::size_type PoolQuery::size() const
00947   {
00948     try
00949     {
00950       size_type count = 0;
00951       for_( it, begin(), end() )
00952         ++count;
00953       return count;
00954     }
00955     catch (const Exception & ex) {}
00956     return 0;
00957   }
00958 
00959   void PoolQuery::execute(ProcessResolvable fnc)
00960   { invokeOnEach( begin(), end(), fnc); }
00961 
00962 
00964   //
00965   //  CLASS NAME : PoolQuery::Attr
00966   //
00971   struct PoolQueryAttr : public IdStringType<PoolQueryAttr>
00972   {
00973   private:
00974     friend class IdStringType<PoolQueryAttr>;
00975     IdString _str;
00976   public:
00977 
00978     //noAttr
00979     PoolQueryAttr(){}
00980 
00981     explicit PoolQueryAttr( const char* cstr_r )
00982         : _str( cstr_r )
00983       {}
00984 
00985     explicit PoolQueryAttr( const std::string & str_r )
00986         : _str( str_r )
00987       {}
00988 
00989     // unknown atributes
00990     static const PoolQueryAttr noAttr;
00991 
00992     // PoolQuery's own attributes
00993     static const PoolQueryAttr repoAttr;
00994     static const PoolQueryAttr kindAttr;
00995     static const PoolQueryAttr stringAttr;
00996     static const PoolQueryAttr stringTypeAttr;
00997     static const PoolQueryAttr requireAllAttr;
00998     static const PoolQueryAttr caseSensitiveAttr;
00999     static const PoolQueryAttr installStatusAttr;
01000     static const PoolQueryAttr editionAttr;
01001     static const PoolQueryAttr complexAttr;
01002   };
01003 
01004   const PoolQueryAttr PoolQueryAttr::noAttr;
01005 
01006   const PoolQueryAttr PoolQueryAttr::repoAttr( "repo" );
01007   const PoolQueryAttr PoolQueryAttr::kindAttr( "type" );
01008   const PoolQueryAttr PoolQueryAttr::stringAttr( "query_string" );
01009   const PoolQueryAttr PoolQueryAttr::stringTypeAttr("match_type");
01010   const PoolQueryAttr PoolQueryAttr::requireAllAttr("require_all");
01011   const PoolQueryAttr PoolQueryAttr::caseSensitiveAttr("case_sensitive");
01012   const PoolQueryAttr PoolQueryAttr::installStatusAttr("install_status");
01013   const PoolQueryAttr PoolQueryAttr::editionAttr("version");
01014   const PoolQueryAttr PoolQueryAttr::complexAttr("complex");
01015 
01016   class StringTypeAttr : public IdStringType<PoolQueryAttr>
01017   {
01018     friend class IdStringType<StringTypeAttr>;
01019     IdString _str;
01020 
01021   public:
01022     StringTypeAttr(){}
01023     explicit StringTypeAttr( const char* cstr_r )
01024             : _str( cstr_r ){}
01025     explicit StringTypeAttr( const std::string & str_r )
01026              : _str( str_r ){}
01027 
01028     static const StringTypeAttr noAttr;
01029 
01030     static const StringTypeAttr exactAttr;
01031     static const StringTypeAttr substringAttr;
01032     static const StringTypeAttr regexAttr;
01033     static const StringTypeAttr globAttr;
01034     static const StringTypeAttr wordAttr;
01035   };
01036 
01037   const StringTypeAttr StringTypeAttr::noAttr;
01038 
01039   const StringTypeAttr StringTypeAttr::exactAttr("exact");
01040   const StringTypeAttr StringTypeAttr::substringAttr("substring");
01041   const StringTypeAttr StringTypeAttr::regexAttr("regex");
01042   const StringTypeAttr StringTypeAttr::globAttr("glob");
01043   const StringTypeAttr StringTypeAttr::wordAttr("word");
01044 
01046 
01047 
01048   //\TODO maybe ctor with stream can be usefull
01049   //\TODO let it throw, let it throw, let it throw.
01050   bool PoolQuery::recover( istream &str, char delim )
01051   {
01052     bool finded_something = false; //indicates some atributes is finded
01053     string s;
01054     do {
01055       if ( str.eof() )
01056         break;
01057 
01058       getline( str, s, delim );
01059 
01060       if ((!s.empty()) && s[0]=='#') //comment
01061       {
01062         continue;
01063       }
01064 
01065       string::size_type pos = s.find(':');
01066       if (s.empty() || pos == s.npos) // some garbage on line... act like blank line
01067       {
01068         if (finded_something) //is first blank line after record?
01069         {
01070           break;
01071         }
01072         else
01073         {
01074           continue;
01075         }
01076       }
01077 
01078       finded_something = true;
01079 
01080       string attrName(str::trim(string(s,0,pos))); // trimmed name of atribute
01081       string attrValue(str::trim(string(s,pos+1,s.npos))); //trimmed value
01082 
01083       PoolQueryAttr attribute( attrName );
01084 
01085       MIL << "attribute name: " << attrName << endl;
01086 
01087       if ( attribute==PoolQueryAttr::repoAttr )
01088       {
01089         addRepo( attrValue );
01090       }
01091       /* some backwards compatibility */
01092       else if ( attribute==PoolQueryAttr::kindAttr || attribute=="kind" )
01093       {
01094         addKind( ResKind(attrValue) );
01095       }
01096       else if ( attribute==PoolQueryAttr::stringAttr
01097         || attribute=="global_string")
01098       {
01099         addString( attrValue );
01100       }
01101       else if ( attribute==PoolQueryAttr::stringTypeAttr
01102         || attribute=="string_type" )
01103       {
01104         StringTypeAttr s(attrValue);
01105         if( s == StringTypeAttr::regexAttr )
01106         {
01107           setMatchRegex();
01108         }
01109         else if ( s == StringTypeAttr::globAttr )
01110         {
01111           setMatchGlob();
01112         }
01113         else if ( s == StringTypeAttr::exactAttr )
01114         {
01115           setMatchExact();
01116         }
01117         else if ( s == StringTypeAttr::substringAttr )
01118         {
01119           setMatchSubstring();
01120         }
01121         else if ( s == StringTypeAttr::wordAttr )
01122         {
01123           setMatchWord();
01124         }
01125         else if ( s == StringTypeAttr::noAttr )
01126         {
01127           WAR << "unknown string type " << attrValue << endl;
01128         }
01129         else
01130         {
01131           WAR << "forget recover some attribute defined as String type attribute: " << attrValue << endl;
01132         }
01133       }
01134       else if ( attribute==PoolQueryAttr::requireAllAttr )
01135       {
01136         if ( str::strToTrue(attrValue) )
01137         {
01138           setRequireAll(true);
01139         }
01140         else if ( !str::strToFalse(attrValue) )
01141         {
01142           setRequireAll(false);
01143         }
01144         else
01145         {
01146           WAR << "unknown boolean value " << attrValue << endl;
01147         }
01148       }
01149       else if ( attribute==PoolQueryAttr::caseSensitiveAttr )
01150       {
01151         if ( str::strToTrue(attrValue) )
01152         {
01153           setCaseSensitive(true);
01154         }
01155         else if ( !str::strToFalse(attrValue) )
01156         {
01157           setCaseSensitive(false);
01158         }
01159         else
01160         {
01161           WAR << "unknown boolean value " << attrValue << endl;
01162         }
01163       }
01164       else if ( attribute==PoolQueryAttr::installStatusAttr )
01165       {
01166         if( attrValue == "all" )
01167         {
01168           setStatusFilterFlags( ALL );
01169         }
01170         else if( attrValue == "installed" )
01171         {
01172           setInstalledOnly();
01173         }
01174         else if( attrValue == "not-installed" )
01175         {
01176           setUninstalledOnly();
01177         }
01178         else
01179         {
01180           WAR << "Unknown value for install status " << attrValue << endl;
01181         }
01182       }
01183       else if ( attribute == PoolQueryAttr::editionAttr)
01184       {
01185         string::size_type pos;
01186         Rel rel("==");
01187         if (attrValue.find_first_of("=<>!") == 0)
01188         {
01189           pos = attrValue.find_last_of("=<>");
01190           rel = Rel(attrValue.substr(0, pos+1));
01191           attrValue = str::trim(attrValue.substr(pos+1, attrValue.npos));
01192         }
01193 
01194         setEdition(Edition(attrValue), rel);
01195       }
01196       else if ( attribute == PoolQueryAttr::complexAttr )
01197       {
01198         try
01199         {
01200           _pimpl->_uncompiledPredicated.insert( AttrMatchData::deserialize( attrValue ) );
01201         }
01202         catch ( const Exception & err )
01203         {
01204           WAR << "Unparsable value for complex: " << err.asUserHistory() << endl;
01205 
01206         }
01207       }
01208       else if ( attribute==PoolQueryAttr::noAttr )
01209       {
01210         WAR << "empty attribute name" << endl;
01211       }
01212       else
01213       {
01214         string s = attrName;
01215         str::replaceAll( s,"_",":" );
01216         SolvAttr a(s);
01217         addAttribute(a,attrValue);
01218       }
01219 
01220     } while ( true );
01221 
01222     return finded_something;
01223   }
01224 
01225   void PoolQuery::serialize( ostream &str, char delim ) const
01226   {
01227     //separating delim
01228     str << delim;
01229     //iterate thrue all settings and write it
01230     static const zypp::PoolQuery q; //not save default options, so create default query example
01231 
01232     for_( it, repos().begin(), repos().end() )
01233     {
01234       str << "repo: " << *it << delim ;
01235     }
01236 
01237     for_( it, kinds().begin(), kinds().end() )
01238     {
01239       str << PoolQueryAttr::kindAttr.asString() << ": "
01240           << it->idStr() << delim ;
01241     }
01242 
01243     if (editionRel() != Rel::ANY && edition() != Edition::noedition)
01244       str << PoolQueryAttr::editionAttr.asString() << ": " << editionRel() << " " << edition() << delim;
01245 
01246     if (matchMode()!=q.matchMode())
01247     {
01248       switch( matchMode() )
01249       {
01250       case Match::STRING:
01251         str << PoolQueryAttr::stringTypeAttr.asString() << ": exact" << delim;
01252         break;
01253       case Match::SUBSTRING:
01254         str << PoolQueryAttr::stringTypeAttr.asString()
01255             << ": substring" << delim;
01256         break;
01257       case Match::GLOB:
01258         str << PoolQueryAttr::stringTypeAttr.asString() << ": glob" << delim;
01259         break;
01260       case Match::REGEX:
01261         str << PoolQueryAttr::stringTypeAttr.asString() << ": regex" << delim;
01262         break;
01263       default:
01264         WAR << "unknown match type "  << matchMode() << endl;
01265       }
01266     }
01267 
01268     if( caseSensitive() != q.caseSensitive() )
01269     {
01270       str << "case_sensitive: ";
01271       if (caseSensitive())
01272       {
01273         str << "on" << delim;
01274       }
01275       else
01276       {
01277         str << "off" << delim;
01278       }
01279     }
01280 
01281     if( requireAll() != q.requireAll() )
01282     {
01283       str << "require_all: ";
01284       if (requireAll())
01285       {
01286         str << "on" << delim;
01287       }
01288       else
01289       {
01290         str << "off" << delim;
01291       }
01292     }
01293 
01294     if( statusFilterFlags() != q.statusFilterFlags() )
01295     {
01296       switch( statusFilterFlags() )
01297       {
01298       case ALL:
01299         str << "install_status: all" << delim;
01300         break;
01301       case INSTALLED_ONLY:
01302         str << "install_status: installed" << delim;
01303         break;
01304       case UNINSTALLED_ONLY:
01305         str << "install_status: not-installed" << delim;
01306         break;
01307       }
01308     }
01309 
01310     for_( it, strings().begin(), strings().end() )
01311     {
01312       str << PoolQueryAttr::stringAttr.asString()<< ": " << *it << delim;
01313     }
01314 
01315     for_( it, attributes().begin(), attributes().end() )
01316     {
01317       string s = it->first.asString();
01318       str::replaceAll(s,":","_");
01319       for_( it2,it->second.begin(),it->second.end() )
01320       {
01321         str << s <<": "<< *it2 << delim;
01322       }
01323     }
01324 
01325     for_( it, _pimpl->_uncompiledPredicated.begin(), _pimpl->_uncompiledPredicated.end() )
01326     {
01327       str << "complex: "<< it->serialize() << delim;
01328     }
01329 
01330     //separating delim - protection
01331     str << delim;
01332   }
01333 
01334   string PoolQuery::asString() const
01335   { return _pimpl->asString(); }
01336 
01337   ostream & operator<<( ostream & str, const PoolQuery & obj )
01338   { return str << obj.asString(); }
01339 
01340   std::ostream & dumpOn( std::ostream & str, const PoolQuery & obj )
01341   { return dumpRange( str << obj, obj.begin(), obj.end() ); }
01342 
01343   bool PoolQuery::operator==( const PoolQuery & rhs ) const
01344   { return *_pimpl == *rhs._pimpl; }
01345 
01347   namespace detail
01348   { 
01349 
01351     //
01352     //  CLASS NAME : PoolQueryMatcher
01353     //
01370     class PoolQueryMatcher
01371     {
01372       public:
01373         typedef sat::LookupAttr::iterator base_iterator;
01374 
01375       public:
01376         const base_iterator & end() const
01377         {
01378           static base_iterator _end;
01379           return _end;
01380         }
01381 
01382         bool advance( base_iterator & base_r ) const
01383         {
01384           if ( base_r == end() )
01385             base_r = startNewQyery(); // first candidate
01386           else
01387           {
01388             base_r.nextSkipSolvable(); // assert we don't visit this Solvable again
01389             ++base_r; // advance to next candidate
01390           }
01391 
01392           while ( base_r != end() )
01393           {
01394             if ( isAMatch( base_r ) )
01395               return true;
01396             // No match: try next
01397             ++base_r;
01398           }
01399           return false;
01400         }
01401 
01405         void matchDetail( const base_iterator & base_r, std::vector<base_iterator> & return_r ) const
01406         {
01407           if ( base_r == end() )
01408             return;
01409 
01410           sat::Solvable inSolvable( base_r.inSolvable() );
01411 
01412           if ( _attrMatchList.size() == 1 )
01413           {
01414             // base_r is already on the 1st matching attribute!
01415             // String matching is done by the base iterator. We must check the predicate here.
01416             // Let's see if there are more matches for this solvable:
01417             base_iterator base( base_r );
01418             base.stayInThisSolvable(); // avoid discarding matches we found far away from here.
01419             return_r.push_back( base );
01420 
01421             const AttrMatchData::Predicate & predicate( _attrMatchList.front().predicate );
01422             for ( ++base; base.inSolvable() == inSolvable; ++base ) // safe even if base == end()
01423             {
01424               if ( ! predicate || predicate( base ) )
01425                 return_r.push_back( base );
01426             }
01427           }
01428           else
01429           {
01430             // Here: search all attributes ;(
01431             for_( mi, _attrMatchList.begin(), _attrMatchList.end() )
01432             {
01433               const AttrMatchData & matchData( *mi );
01434               sat::LookupAttr q( matchData.attr, inSolvable );
01435               if ( matchData.attrMatcher ) // an empty searchstring matches always
01436                 q.setAttrMatcher( matchData.attrMatcher );
01437 
01438               if ( ! q.empty() ) // there are matches.
01439               {
01440                 // now check any predicate:
01441                 const AttrMatchData::Predicate & predicate( matchData.predicate );
01442                 for_( it, q.begin(), q.end() )
01443                 {
01444                   if ( ! predicate || predicate( it ) )
01445                     return_r.push_back( it );
01446                 }
01447               }
01448             }
01449           }
01450         }
01451 
01452       public:
01456         PoolQueryMatcher( const shared_ptr<const PoolQuery::Impl> & query_r )
01457         {
01458           query_r->compile();
01459 
01460           // Repo restriction:
01461           sat::Pool satpool( sat::Pool::instance() );
01462           for_( it, query_r->_repos.begin(), query_r->_repos.end() )
01463           {
01464             Repository r( satpool.reposFind( *it ) );
01465             if ( r )
01466               _repos.insert( r );
01467           }
01468           // Kind restriction:
01469           _kinds = query_r->_kinds;
01470           // Edition restriction:
01471           _op      = query_r->_op;
01472           _edition = query_r->_edition;
01473           // Status restriction:
01474           _status_flags = query_r->_status_flags;
01475           // AttrMatcher
01476           _attrMatchList = query_r->_attrMatchList;
01477         }
01478 
01479         ~PoolQueryMatcher()
01480         {}
01481 
01482       private:
01484         base_iterator startNewQyery() const
01485         {
01486           sat::LookupAttr q;
01487 
01488           // Repo restriction:
01489           if ( _repos.size() == 1 )
01490             q.setRepo( *_repos.begin() );
01491           // else: handled in isAMatch.
01492 
01493           // Attribute restriction:
01494           if ( _attrMatchList.size() == 1 ) // all (SolvAttr::allAttr) or 1 attr
01495           {
01496             const AttrMatchData & matchData( _attrMatchList.front() );
01497             q.setAttr( matchData.attr );
01498             if ( matchData.attrMatcher ) // empty searchstring matches always
01499               q.setAttrMatcher( matchData.attrMatcher );
01500           }
01501           else // more than 1 attr (but not all)
01502           {
01503             // no restriction, it's all handled in isAMatch.
01504             q.setAttr( sat::SolvAttr::allAttr );
01505           }
01506 
01507           return q.begin();
01508         }
01509 
01510 
01521         bool isAMatch( base_iterator & base_r ) const
01522         {
01524           Repository inRepo( base_r.inRepo() );
01525           // Status restriction:
01526           if ( _status_flags
01527              && ( (_status_flags == PoolQuery::INSTALLED_ONLY) != inRepo.isSystemRepo() ) )
01528           {
01529             base_r.nextSkipRepo();
01530             return false;
01531           }
01532           // Repo restriction:
01533           if ( _repos.size() > 1 && _repos.find( inRepo ) == _repos.end() )
01534           {
01535             base_r.nextSkipRepo();
01536             return false;
01537           }
01539           sat::Solvable inSolvable( base_r.inSolvable() );
01540           // Kind restriction:
01541           if ( ! _kinds.empty() && ! inSolvable.isKind( _kinds.begin(), _kinds.end() ) )
01542           {
01543             base_r.nextSkipSolvable();
01544             return false;
01545           }
01546 
01547           // Edition restriction:
01548           if ( _op != Rel::ANY && !compareByRel( _op, inSolvable.edition(), _edition, Edition::Match() ) )
01549           {
01550             base_r.nextSkipSolvable();
01551             return false;
01552           }
01554           // string and predicate matching:
01555 
01556           if ( _attrMatchList.size() == 1 )
01557           {
01558             // String matching was done by the base iterator.
01559             // Now check any predicate:
01560             const AttrMatchData::Predicate & predicate( _attrMatchList.front().predicate );
01561             if ( ! predicate || predicate( base_r ) )
01562               return true;
01563 
01564             return false; // no skip as there may be more occurrences od this attr.
01565           }
01566 
01567           // Here: search all attributes ;(
01568           for_( mi, _attrMatchList.begin(), _attrMatchList.end() )
01569           {
01570             const AttrMatchData & matchData( *mi );
01571             sat::LookupAttr q( matchData.attr, inSolvable );
01572             if ( matchData.attrMatcher ) // an empty searchstring matches always
01573               q.setAttrMatcher( matchData.attrMatcher );
01574 
01575             if ( ! q.empty() ) // there are matches.
01576             {
01577               // now check any predicate:
01578               const AttrMatchData::Predicate & predicate( matchData.predicate );
01579               if ( predicate )
01580               {
01581                 for_( it, q.begin(), q.end() )
01582                 {
01583                   if ( predicate( it ) )
01584                     return true;
01585                 }
01586               }
01587               else
01588                 return true;
01589             }
01590           }
01591           base_r.nextSkipSolvable();
01592           return false;
01593         }
01594 
01595       private:
01597         std::set<Repository> _repos;
01599         std::set<ResKind> _kinds;
01601         Rel _op;
01602         Edition _edition;
01604         int _status_flags;
01606         AttrMatchList _attrMatchList;
01607     };
01609 
01610     void PoolQueryIterator::increment()
01611     {
01612       // matcher restarts if at end! It is called from the ctor
01613       // to get the 1st match. But if the end is reached, it should
01614       // be deleted, otherwise we'd start over again.
01615       if ( !_matcher )
01616         return; // at end
01617       if ( _matches )
01618         _matches.reset(); // invalidate old matches
01619       if ( ! _matcher->advance( base_reference() ) )
01620         _matcher.reset();
01621     }
01622 
01623     const PoolQueryIterator::Matches & PoolQueryIterator::matches() const
01624     {
01625       if ( _matches )
01626         return *_matches;
01627 
01628       if ( !_matcher )
01629       {
01630         // at end of query:
01631         static const Matches _none;
01632         return _none;
01633       }
01634 
01635       _matches.reset( new Matches );
01636       _matcher->matchDetail( base_reference(), *_matches );
01637       return *_matches;
01638     }
01639 
01640     std::ostream & dumpOn( std::ostream & str, const PoolQueryIterator & obj )
01641     {
01642       str << *obj;
01643       if ( ! obj.matchesEmpty() )
01644       {
01645         for_( it, obj.matchesBegin(), obj.matchesEnd() )
01646         {
01647           str << endl << "    " << it->inSolvAttr() << "\t" << it->asString();
01648         }
01649       }
01650       return str;
01651     }
01652 
01654   } //namespace detail
01656 
01657   detail::PoolQueryIterator PoolQuery::begin() const
01658   {
01659     return shared_ptr<detail::PoolQueryMatcher>( new detail::PoolQueryMatcher( _pimpl.getPtr() ) );
01660   }
01661 
01663 } // namespace zypp
01665 

doxygen