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