00001
00002
00003
00004
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
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() )
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
00230
00231
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
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
00348
00350
00351
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 if ( _flags == rhs._flags
00405
00406
00407
00408
00409
00410 || ( _flags.isModeString() && rhs._flags.isModeGlob()
00411 || _flags.isModeGlob() && rhs._flags.isModeString() )
00412 && _strings.empty()
00413 && _attrs.size() == 1
00414 && _attrs.begin()->first == sat::SolvAttr::name )
00415 {
00416 return ( _strings == rhs._strings
00417 && _attrs == rhs._attrs
00418 && _uncompiledPredicated == rhs._uncompiledPredicated
00419 && _match_word == rhs._match_word
00420 && _require_all == rhs._require_all
00421 && _status_flags == rhs._status_flags
00422 && _edition == rhs._edition
00423 && _op == rhs._op
00424 && _repos == rhs._repos
00425 && _kinds == rhs._kinds );
00426 }
00427 return false;
00428 }
00429
00430 bool operator!=( const PoolQuery::Impl & rhs ) const
00431 { return ! operator==( rhs ); }
00432
00433 public:
00438 void compile() const;
00439
00441 mutable AttrMatchList _attrMatchList;
00442
00443 private:
00445 string createRegex( const StrContainer & container, const Match & flags ) const;
00446
00447 private:
00448 friend Impl * rwcowClone<Impl>( const Impl * rhs );
00450 Impl * clone() const
00451 { return new Impl( *this ); }
00452 };
00453
00455
00456 struct MyInserter
00457 {
00458 MyInserter(PoolQuery::StrContainer & cont) : _cont(cont) {}
00459
00460 bool operator()(const string & str)
00461 {
00462 _cont.insert(str);
00463 return true;
00464 }
00465
00466 PoolQuery::StrContainer & _cont;
00467 };
00468
00469
00470 struct EmptyFilter
00471 {
00472 bool operator()(const string & str)
00473 {
00474 return !str.empty();
00475 }
00476 };
00477
00478 void PoolQuery::Impl::compile() const
00479 {
00480 _attrMatchList.clear();
00481
00482 Match cflags( _flags );
00483 if ( cflags.mode() == Match::OTHER )
00484 ZYPP_THROW( MatchUnknownModeException( cflags ) );
00485
00487 string rcstrings;
00488
00489
00490
00491
00492
00493
00494
00495
00496
00497
00498
00499 if (_attrs.empty())
00500 {
00501 ;
00502 }
00503
00504
00505
00506
00507
00508 else if (_attrs.size() == 1)
00509 {
00510 StrContainer joined;
00511 invokeOnEach(_strings.begin(), _strings.end(), EmptyFilter(), MyInserter(joined));
00512 invokeOnEach(_attrs.begin()->second.begin(), _attrs.begin()->second.end(), EmptyFilter(), MyInserter(joined));
00513 rcstrings = createRegex(joined, cflags);
00514 if (joined.size() > 1)
00515 cflags.setModeRegex();
00516 _attrMatchList.push_back( AttrMatchData( _attrs.begin()->first,
00517 sat::AttrMatcher( rcstrings, cflags ) ) );
00518 }
00519
00520
00521 else
00522 {
00523
00524 bool attrvals_empty = true;
00525 for (AttrRawStrMap::const_iterator ai = _attrs.begin(); ai != _attrs.end(); ++ai)
00526 if (!ai->second.empty())
00527 for(StrContainer::const_iterator it = ai->second.begin();
00528 it != ai->second.end(); it++)
00529 if (!it->empty())
00530 {
00531 attrvals_empty = false;
00532 goto attremptycheckend;
00533 }
00534 attremptycheckend:
00535
00536
00537 bool attrvals_thesame = true;
00538 AttrRawStrMap::const_iterator ai = _attrs.begin();
00539 const StrContainer & set1 = ai->second;
00540 ++ai;
00541 for (; ai != _attrs.end(); ++ai)
00542 {
00543 StrContainer result;
00544 set_difference(
00545 set1.begin(), set1.end(),
00546 ai->second.begin(), ai->second.end(),
00547 inserter(result, result.begin()));
00548 if (!result.empty())
00549 {
00550 attrvals_thesame = false;
00551 break;
00552 }
00553 }
00554
00555
00556
00557
00558
00559 if (attrvals_empty || attrvals_thesame)
00560 {
00561 StrContainer joined;
00562 if (attrvals_empty)
00563 {
00564 invokeOnEach(_strings.begin(), _strings.end(), EmptyFilter(), MyInserter(joined));
00565 rcstrings = createRegex(joined, cflags);
00566 }
00567 else
00568 {
00569 invokeOnEach(_strings.begin(), _strings.end(), EmptyFilter(), MyInserter(joined));
00570 invokeOnEach(_attrs.begin()->second.begin(), _attrs.begin()->second.end(), EmptyFilter(), MyInserter(joined));
00571 rcstrings = createRegex(joined, cflags);
00572 }
00573 if (joined.size() > 1)
00574 cflags.setModeRegex();
00575
00576 sat::AttrMatcher matcher( rcstrings, cflags );
00577 for_( ai, _attrs.begin(), _attrs.end() )
00578 {
00579 _attrMatchList.push_back( AttrMatchData( ai->first, matcher ) );
00580 }
00581 }
00582
00583
00584
00585
00586
00587 else
00588 {
00589 for_(ai, _attrs.begin(), _attrs.end())
00590 {
00591 StrContainer joined;
00592 invokeOnEach(_strings.begin(), _strings.end(), EmptyFilter(), MyInserter(joined));
00593 invokeOnEach(ai->second.begin(), ai->second.end(), EmptyFilter(), MyInserter(joined));
00594 string s = createRegex(joined, cflags);
00595 if (joined.size() > 1)
00596 cflags.setModeRegex();
00597 _attrMatchList.push_back( AttrMatchData( ai->first,
00598 sat::AttrMatcher( s, cflags ) ) );
00599 }
00600 }
00601 }
00602
00603
00604 if ( ! _uncompiledPredicated.empty() )
00605 {
00606 StrContainer global;
00607 invokeOnEach( _strings.begin(), _strings.end(), EmptyFilter(), MyInserter(global) );
00608 for_( it, _uncompiledPredicated.begin(), _uncompiledPredicated.end() )
00609 {
00610 if ( it->attrMatcher.flags().mode() == Match::OTHER )
00611 {
00612
00613 StrContainer joined( global );
00614 const std::string & mstr( it->attrMatcher.searchstring() );
00615 if ( ! mstr.empty() )
00616 joined.insert( mstr );
00617
00618 cflags = _flags;
00619 rcstrings = createRegex( joined, cflags );
00620 if ( joined.size() > 1 )
00621 cflags.setModeRegex();
00622
00623 _attrMatchList.push_back( AttrMatchData( it->attr,
00624 sat::AttrMatcher( rcstrings, cflags ),
00625 it->predicate, it->predicateStr ) );
00626 }
00627 else
00628 {
00629
00630 _attrMatchList.push_back( *it );
00631 }
00632 }
00633 }
00634
00635
00636 if ( _attrMatchList.empty() )
00637 {
00638 cflags = _flags;
00639 rcstrings = createRegex( _strings, cflags );
00640 if ( _strings.size() > 1 )
00641 cflags.setModeRegex();
00642 _attrMatchList.push_back( AttrMatchData( sat::SolvAttr::allAttr,
00643 sat::AttrMatcher( rcstrings, cflags ) ) );
00644 }
00645
00646
00647 for_( it, _attrMatchList.begin(), _attrMatchList.end() )
00648 {
00649 it->attrMatcher.compile();
00650 }
00651
00652 }
00653
00654
00658 static string wildcards2regex(const string & str)
00659 {
00660 string regexed = str;
00661
00662 string r_all(".*");
00663 string r_one(".");
00664 string::size_type pos;
00665
00666
00667 for (pos = 0; (pos = regexed.find("*", pos)) != std::string::npos; pos+=2)
00668 regexed = regexed.replace(pos, 1, r_all);
00669
00670
00671 for (pos = 0; (pos = regexed.find('?', pos)) != std::string::npos; ++pos)
00672 regexed = regexed.replace(pos, 1, r_one);
00673
00674 return regexed;
00675 }
00676
00677 string PoolQuery::Impl::createRegex( const StrContainer & container, const Match & flags ) const
00678 {
00680 #define WB (_match_word ? string("\\b") : string())
00681 string rstr;
00682
00683 if (container.empty())
00684 return rstr;
00685
00686 if (container.size() == 1)
00687 {
00688 return WB + *container.begin() + WB;
00689 }
00690
00691
00692
00693 bool use_wildcards = flags.isModeGlob();
00694 StrContainer::const_iterator it = container.begin();
00695 string tmp;
00696
00697 if (use_wildcards)
00698 tmp = wildcards2regex(*it);
00699 else
00700 tmp = *it;
00701
00702 if (_require_all)
00703 {
00704 if ( ! flags.isModeString() )
00705 tmp += ".*" + WB + tmp;
00706 rstr = "(?=" + tmp + ")";
00707 }
00708 else
00709 {
00710 if ( flags.isModeString() || flags.isModeGlob() )
00711 rstr = "^";
00712 rstr += WB + "(" + tmp;
00713 }
00714
00715 ++it;
00716
00717 for (; it != container.end(); ++it)
00718 {
00719 if (use_wildcards)
00720 tmp = wildcards2regex(*it);
00721 else
00722 tmp = *it;
00723
00724 if (_require_all)
00725 {
00726 if ( ! flags.isModeString() )
00727 tmp += ".*" + WB + tmp;
00728 rstr += "(?=" + tmp + ")";
00729 }
00730 else
00731 {
00732 rstr += "|" + tmp;
00733 }
00734 }
00735
00736 if (_require_all)
00737 {
00738 if ( ! flags.isModeString() )
00739 rstr += WB + ".*";
00740 }
00741 else
00742 {
00743 rstr += ")" + WB;
00744 if ( flags.isModeString() || flags.isModeGlob() )
00745 rstr += "$";
00746 }
00747
00748 return rstr;
00749 #undef WB
00750 }
00751
00752 string PoolQuery::Impl::asString() const
00753 {
00754 ostringstream o;
00755
00756 o << "kinds: ";
00757 if ( _kinds.empty() )
00758 o << "ALL";
00759 else
00760 {
00761 for(Kinds::const_iterator it = _kinds.begin();
00762 it != _kinds.end(); ++it)
00763 o << *it << " ";
00764 }
00765 o << endl;
00766
00767 o << "repos: ";
00768 if ( _repos.empty() )
00769 o << "ALL";
00770 else
00771 {
00772 for(StrContainer::const_iterator it = _repos.begin();
00773 it != _repos.end(); ++it)
00774 o << *it << " ";
00775 }
00776 o << endl;
00777
00778 o << "version: "<< _op << " " << _edition.asString() << endl;
00779 o << "status: " << ( _status_flags ? ( _status_flags == INSTALLED_ONLY ? "INSTALLED_ONLY" : "UNINSTALLED_ONLY" )
00780 : "ALL" ) << endl;
00781
00782 o << "string match flags: " << Match(_flags) << endl;
00783
00784
00785 o << "strings: ";
00786 for(StrContainer::const_iterator it = _strings.begin();
00787 it != _strings.end(); ++it)
00788 o << *it << " ";
00789 o << endl;
00790
00791 o << "attributes: " << endl;
00792 for(AttrRawStrMap::const_iterator ai = _attrs.begin(); ai != _attrs.end(); ++ai)
00793 {
00794 o << "* " << ai->first << ": ";
00795 for(StrContainer::const_iterator vi = ai->second.begin();
00796 vi != ai->second.end(); ++vi)
00797 o << *vi << " ";
00798 o << endl;
00799 }
00800
00801 o << "predicated: " << endl;
00802 for_( it, _uncompiledPredicated.begin(), _uncompiledPredicated.end() )
00803 {
00804 o << "* " << *it << endl;
00805 }
00806
00807
00808 o << "last attribute matcher compiled: " << endl;
00809 if ( _attrMatchList.empty() )
00810 {
00811 o << "not yet compiled" << endl;
00812 }
00813 else
00814 {
00815 for_( it, _attrMatchList.begin(), _attrMatchList.end() )
00816 {
00817 o << "* " << *it << endl;
00818 }
00819 }
00820 return o.str();
00821 }
00822
00824
00826
00827
00828
00830
00831 PoolQuery::PoolQuery()
00832 : _pimpl(new Impl())
00833 {}
00834
00835 PoolQuery::~PoolQuery()
00836 {}
00837
00838 void PoolQuery::addRepo(const std::string &repoalias)
00839 {
00840 if (repoalias.empty())
00841 {
00842 WAR << "ignoring an empty repository alias" << endl;
00843 return;
00844 }
00845 _pimpl->_repos.insert(repoalias);
00846 }
00847
00848 void PoolQuery::addKind(const ResKind & kind)
00849 { _pimpl->_kinds.insert(kind); }
00850
00851 void PoolQuery::addString(const string & value)
00852 { _pimpl->_strings.insert(value); }
00853
00854 void PoolQuery::addAttribute(const sat::SolvAttr & attr, const std::string & value)
00855 { _pimpl->_attrs[attr].insert(value); }
00856
00857 void PoolQuery::addDependency( const sat::SolvAttr & attr, const std::string & name, const Rel & op, const Edition & edition )
00858 { return addDependency( attr, name, op, edition, Arch_empty ); }
00859
00860 void PoolQuery::addDependency( const sat::SolvAttr & attr, const std::string & name, const Rel & op, const Edition & edition, const Arch & arch )
00861 {
00862 switch ( op.inSwitch() )
00863 {
00864 case Rel::ANY_e:
00865 if ( arch.empty() )
00866 {
00867 addAttribute( attr, name );
00868 return;
00869 }
00870 break;
00871
00872 case Rel::NONE_e:
00873 return;
00874
00875 default:
00876 break;
00877 }
00878
00879
00880
00881 AttrMatchData attrMatchData( attr, sat::AttrMatcher( name, Match::OTHER ) );
00882
00883 if ( isDependencyAttribute( attr ) )
00884 attrMatchData.addPredicate( EditionRangePredicate( op, edition, arch ) );
00885 else
00886 attrMatchData.addPredicate( SolvableRangePredicate( op, edition, arch ) );
00887
00888 _pimpl->_uncompiledPredicated.insert( attrMatchData );
00889 }
00890
00891 void PoolQuery::addDependency( const sat::SolvAttr & attr, Capability cap_r )
00892 {
00893 CapDetail cap( cap_r );
00894 if ( ! cap.isSimple() )
00895 return;
00896
00897
00898 AttrMatchData attrMatchData( attr, sat::AttrMatcher( cap.name().asString() ) );
00899
00900 if ( isDependencyAttribute( attr ) )
00901 attrMatchData.addPredicate( CapabilityMatchPredicate( cap_r ) );
00902 else
00903 attrMatchData.addPredicate( SolvableRangePredicate( cap.op(), cap.ed() ) );
00904
00905 _pimpl->_uncompiledPredicated.insert( attrMatchData );
00906 }
00907
00908 void PoolQuery::setEdition(const Edition & edition, const Rel & op)
00909 {
00910 _pimpl->_edition = edition;
00911 _pimpl->_op = op;
00912 }
00913
00914 void PoolQuery::setMatchSubstring() { _pimpl->_flags.setModeSubstring(); }
00915 void PoolQuery::setMatchExact() { _pimpl->_flags.setModeString(); }
00916 void PoolQuery::setMatchRegex() { _pimpl->_flags.setModeRegex(); }
00917 void PoolQuery::setMatchGlob() { _pimpl->_flags.setModeGlob(); }
00918 void PoolQuery::setMatchWord()
00919 {
00920 _pimpl->_match_word = true;
00921 _pimpl->_flags.setModeRegex();
00922 }
00923
00924 Match PoolQuery::flags() const
00925 { return _pimpl->_flags; }
00926 void PoolQuery::setFlags( const Match & flags )
00927 { _pimpl->_flags = flags; }
00928
00929
00930 void PoolQuery::setInstalledOnly()
00931 { _pimpl->_status_flags = INSTALLED_ONLY; }
00932 void PoolQuery::setUninstalledOnly()
00933 { _pimpl->_status_flags = UNINSTALLED_ONLY; }
00934 void PoolQuery::setStatusFilterFlags( PoolQuery::StatusFilter flags )
00935 { _pimpl->_status_flags = flags; }
00936
00937
00938 void PoolQuery::setRequireAll(bool require_all)
00939 { _pimpl->_require_all = require_all; }
00940
00941
00942 const PoolQuery::StrContainer &
00943 PoolQuery::strings() const
00944 { return _pimpl->_strings; }
00945
00946 const PoolQuery::AttrRawStrMap &
00947 PoolQuery::attributes() const
00948 { return _pimpl->_attrs; }
00949
00950 const PoolQuery::StrContainer &
00951 PoolQuery::attribute(const sat::SolvAttr & attr) const
00952 {
00953 static const PoolQuery::StrContainer nocontainer;
00954 AttrRawStrMap::const_iterator it = _pimpl->_attrs.find(attr);
00955 return it != _pimpl->_attrs.end() ? it->second : nocontainer;
00956 }
00957
00958 const Edition PoolQuery::edition() const
00959 { return _pimpl->_edition; }
00960 const Rel PoolQuery::editionRel() const
00961 { return _pimpl->_op; }
00962
00963
00964 const PoolQuery::Kinds &
00965 PoolQuery::kinds() const
00966 { return _pimpl->_kinds; }
00967
00968 const PoolQuery::StrContainer &
00969 PoolQuery::repos() const
00970 { return _pimpl->_repos; }
00971
00972
00973 bool PoolQuery::caseSensitive() const
00974 { return !_pimpl->_flags.test( Match::NOCASE ); }
00975 void PoolQuery::setCaseSensitive( bool value )
00976 { _pimpl->_flags.turn( Match::NOCASE, !value ); }
00977
00978 bool PoolQuery::filesMatchFullPath() const
00979 { return _pimpl->_flags.test( Match::FILES ); }
00980 void PoolQuery::setFilesMatchFullPath( bool value )
00981 { _pimpl->_flags.turn( Match::FILES, value ); }
00982
00983 bool PoolQuery::matchExact() const { return _pimpl->_flags.isModeString(); }
00984 bool PoolQuery::matchSubstring() const { return _pimpl->_flags.isModeSubstring(); }
00985 bool PoolQuery::matchGlob() const { return _pimpl->_flags.isModeGlob(); }
00986 bool PoolQuery::matchRegex() const { return _pimpl->_flags.isModeRegex(); }
00987
00988 bool PoolQuery::matchWord() const
00989 { return _pimpl->_match_word; }
00990
00991 bool PoolQuery::requireAll() const
00992 { return _pimpl->_require_all; }
00993
00994 PoolQuery::StatusFilter PoolQuery::statusFilterFlags() const
00995 { return _pimpl->_status_flags; }
00996
00997 bool PoolQuery::empty() const
00998 {
00999 try { return begin() == end(); }
01000 catch (const Exception & ex) {}
01001 return true;
01002 }
01003
01004 PoolQuery::size_type PoolQuery::size() const
01005 {
01006 try
01007 {
01008 size_type count = 0;
01009 for_( it, begin(), end() )
01010 ++count;
01011 return count;
01012 }
01013 catch (const Exception & ex) {}
01014 return 0;
01015 }
01016
01017 void PoolQuery::execute(ProcessResolvable fnc)
01018 { invokeOnEach( begin(), end(), fnc); }
01019
01020
01022
01023
01024
01029 struct PoolQueryAttr : public IdStringType<PoolQueryAttr>
01030 {
01031 private:
01032 friend class IdStringType<PoolQueryAttr>;
01033 IdString _str;
01034 public:
01035
01036
01037 PoolQueryAttr(){}
01038
01039 explicit PoolQueryAttr( const char* cstr_r )
01040 : _str( cstr_r )
01041 {}
01042
01043 explicit PoolQueryAttr( const std::string & str_r )
01044 : _str( str_r )
01045 {}
01046
01047
01048 static const PoolQueryAttr noAttr;
01049
01050
01051 static const PoolQueryAttr repoAttr;
01052 static const PoolQueryAttr kindAttr;
01053 static const PoolQueryAttr stringAttr;
01054 static const PoolQueryAttr stringTypeAttr;
01055 static const PoolQueryAttr requireAllAttr;
01056 static const PoolQueryAttr caseSensitiveAttr;
01057 static const PoolQueryAttr installStatusAttr;
01058 static const PoolQueryAttr editionAttr;
01059 static const PoolQueryAttr complexAttr;
01060 };
01061
01062 const PoolQueryAttr PoolQueryAttr::noAttr;
01063
01064 const PoolQueryAttr PoolQueryAttr::repoAttr( "repo" );
01065 const PoolQueryAttr PoolQueryAttr::kindAttr( "type" );
01066 const PoolQueryAttr PoolQueryAttr::stringAttr( "query_string" );
01067 const PoolQueryAttr PoolQueryAttr::stringTypeAttr("match_type");
01068 const PoolQueryAttr PoolQueryAttr::requireAllAttr("require_all");
01069 const PoolQueryAttr PoolQueryAttr::caseSensitiveAttr("case_sensitive");
01070 const PoolQueryAttr PoolQueryAttr::installStatusAttr("install_status");
01071 const PoolQueryAttr PoolQueryAttr::editionAttr("version");
01072 const PoolQueryAttr PoolQueryAttr::complexAttr("complex");
01073
01074 class StringTypeAttr : public IdStringType<PoolQueryAttr>
01075 {
01076 friend class IdStringType<StringTypeAttr>;
01077 IdString _str;
01078
01079 public:
01080 StringTypeAttr(){}
01081 explicit StringTypeAttr( const char* cstr_r )
01082 : _str( cstr_r ){}
01083 explicit StringTypeAttr( const std::string & str_r )
01084 : _str( str_r ){}
01085
01086 static const StringTypeAttr noAttr;
01087
01088 static const StringTypeAttr exactAttr;
01089 static const StringTypeAttr substringAttr;
01090 static const StringTypeAttr regexAttr;
01091 static const StringTypeAttr globAttr;
01092 static const StringTypeAttr wordAttr;
01093 };
01094
01095 const StringTypeAttr StringTypeAttr::noAttr;
01096
01097 const StringTypeAttr StringTypeAttr::exactAttr("exact");
01098 const StringTypeAttr StringTypeAttr::substringAttr("substring");
01099 const StringTypeAttr StringTypeAttr::regexAttr("regex");
01100 const StringTypeAttr StringTypeAttr::globAttr("glob");
01101 const StringTypeAttr StringTypeAttr::wordAttr("word");
01102
01104
01105
01106
01107
01108 bool PoolQuery::recover( istream &str, char delim )
01109 {
01110 bool finded_something = false;
01111 string s;
01112 do {
01113 if ( str.eof() )
01114 break;
01115
01116 getline( str, s, delim );
01117
01118 if ((!s.empty()) && s[0]=='#')
01119 {
01120 continue;
01121 }
01122
01123 string::size_type pos = s.find(':');
01124 if (s.empty() || pos == s.npos)
01125 {
01126 if (finded_something)
01127 {
01128 break;
01129 }
01130 else
01131 {
01132 continue;
01133 }
01134 }
01135
01136 finded_something = true;
01137
01138 string attrName(str::trim(string(s,0,pos)));
01139 string attrValue(str::trim(string(s,pos+1,s.npos)));
01140
01141 PoolQueryAttr attribute( attrName );
01142
01143 MIL << "attribute name: " << attrName << endl;
01144
01145 if ( attribute==PoolQueryAttr::repoAttr )
01146 {
01147 addRepo( attrValue );
01148 }
01149
01150 else if ( attribute==PoolQueryAttr::kindAttr || attribute=="kind" )
01151 {
01152 addKind( ResKind(attrValue) );
01153 }
01154 else if ( attribute==PoolQueryAttr::stringAttr
01155 || attribute=="global_string")
01156 {
01157 addString( attrValue );
01158 }
01159 else if ( attribute==PoolQueryAttr::stringTypeAttr
01160 || attribute=="string_type" )
01161 {
01162 StringTypeAttr s(attrValue);
01163 if( s == StringTypeAttr::regexAttr )
01164 {
01165 setMatchRegex();
01166 }
01167 else if ( s == StringTypeAttr::globAttr )
01168 {
01169 setMatchGlob();
01170 }
01171 else if ( s == StringTypeAttr::exactAttr )
01172 {
01173 setMatchExact();
01174 }
01175 else if ( s == StringTypeAttr::substringAttr )
01176 {
01177 setMatchSubstring();
01178 }
01179 else if ( s == StringTypeAttr::wordAttr )
01180 {
01181 setMatchWord();
01182 }
01183 else if ( s == StringTypeAttr::noAttr )
01184 {
01185 WAR << "unknown string type " << attrValue << endl;
01186 }
01187 else
01188 {
01189 WAR << "forget recover some attribute defined as String type attribute: " << attrValue << endl;
01190 }
01191 }
01192 else if ( attribute==PoolQueryAttr::requireAllAttr )
01193 {
01194 if ( str::strToTrue(attrValue) )
01195 {
01196 setRequireAll(true);
01197 }
01198 else if ( !str::strToFalse(attrValue) )
01199 {
01200 setRequireAll(false);
01201 }
01202 else
01203 {
01204 WAR << "unknown boolean value " << attrValue << endl;
01205 }
01206 }
01207 else if ( attribute==PoolQueryAttr::caseSensitiveAttr )
01208 {
01209 if ( str::strToTrue(attrValue) )
01210 {
01211 setCaseSensitive(true);
01212 }
01213 else if ( !str::strToFalse(attrValue) )
01214 {
01215 setCaseSensitive(false);
01216 }
01217 else
01218 {
01219 WAR << "unknown boolean value " << attrValue << endl;
01220 }
01221 }
01222 else if ( attribute==PoolQueryAttr::installStatusAttr )
01223 {
01224 if( attrValue == "all" )
01225 {
01226 setStatusFilterFlags( ALL );
01227 }
01228 else if( attrValue == "installed" )
01229 {
01230 setInstalledOnly();
01231 }
01232 else if( attrValue == "not-installed" )
01233 {
01234 setUninstalledOnly();
01235 }
01236 else
01237 {
01238 WAR << "Unknown value for install status " << attrValue << endl;
01239 }
01240 }
01241 else if ( attribute == PoolQueryAttr::editionAttr)
01242 {
01243 string::size_type pos;
01244 Rel rel("==");
01245 if (attrValue.find_first_of("=<>!") == 0)
01246 {
01247 pos = attrValue.find_last_of("=<>");
01248 rel = Rel(attrValue.substr(0, pos+1));
01249 attrValue = str::trim(attrValue.substr(pos+1, attrValue.npos));
01250 }
01251
01252 setEdition(Edition(attrValue), rel);
01253 }
01254 else if ( attribute == PoolQueryAttr::complexAttr )
01255 {
01256 try
01257 {
01258 _pimpl->_uncompiledPredicated.insert( AttrMatchData::deserialize( attrValue ) );
01259 }
01260 catch ( const Exception & err )
01261 {
01262 WAR << "Unparsable value for complex: " << err.asUserHistory() << endl;
01263
01264 }
01265 }
01266 else if ( attribute==PoolQueryAttr::noAttr )
01267 {
01268 WAR << "empty attribute name" << endl;
01269 }
01270 else
01271 {
01272 string s = attrName;
01273 str::replaceAll( s,"_",":" );
01274 SolvAttr a(s);
01275 if ( a == SolvAttr::name || isDependencyAttribute( a ) )
01276 {
01277 Capability c( attrValue );
01278 CapDetail d( c );
01279 if ( d.isVersioned() )
01280 addDependency( a, d.name().asString(), d.op(), d.ed() );
01281 else
01282 addDependency( a, attrValue );
01283 }
01284 else
01285 addAttribute( a, attrValue );
01286 }
01287
01288 } while ( true );
01289
01290 return finded_something;
01291 }
01292
01293 void PoolQuery::serialize( ostream &str, char delim ) const
01294 {
01295
01296 str << delim;
01297
01298 static const zypp::PoolQuery q;
01299
01300 for_( it, repos().begin(), repos().end() )
01301 {
01302 str << "repo: " << *it << delim ;
01303 }
01304
01305 for_( it, kinds().begin(), kinds().end() )
01306 {
01307 str << PoolQueryAttr::kindAttr.asString() << ": "
01308 << it->idStr() << delim ;
01309 }
01310
01311 if (editionRel() != Rel::ANY && edition() != Edition::noedition)
01312 str << PoolQueryAttr::editionAttr.asString() << ": " << editionRel() << " " << edition() << delim;
01313
01314 if (matchMode()!=q.matchMode())
01315 {
01316 switch( matchMode() )
01317 {
01318 case Match::STRING:
01319 str << PoolQueryAttr::stringTypeAttr.asString() << ": exact" << delim;
01320 break;
01321 case Match::SUBSTRING:
01322 str << PoolQueryAttr::stringTypeAttr.asString()
01323 << ": substring" << delim;
01324 break;
01325 case Match::GLOB:
01326 str << PoolQueryAttr::stringTypeAttr.asString() << ": glob" << delim;
01327 break;
01328 case Match::REGEX:
01329 str << PoolQueryAttr::stringTypeAttr.asString() << ": regex" << delim;
01330 break;
01331 default:
01332 WAR << "unknown match type " << matchMode() << endl;
01333 }
01334 }
01335
01336 if( caseSensitive() != q.caseSensitive() )
01337 {
01338 str << "case_sensitive: ";
01339 if (caseSensitive())
01340 {
01341 str << "on" << delim;
01342 }
01343 else
01344 {
01345 str << "off" << delim;
01346 }
01347 }
01348
01349 if( requireAll() != q.requireAll() )
01350 {
01351 str << "require_all: ";
01352 if (requireAll())
01353 {
01354 str << "on" << delim;
01355 }
01356 else
01357 {
01358 str << "off" << delim;
01359 }
01360 }
01361
01362 if( statusFilterFlags() != q.statusFilterFlags() )
01363 {
01364 switch( statusFilterFlags() )
01365 {
01366 case ALL:
01367 str << "install_status: all" << delim;
01368 break;
01369 case INSTALLED_ONLY:
01370 str << "install_status: installed" << delim;
01371 break;
01372 case UNINSTALLED_ONLY:
01373 str << "install_status: not-installed" << delim;
01374 break;
01375 }
01376 }
01377
01378 for_( it, strings().begin(), strings().end() )
01379 {
01380 str << PoolQueryAttr::stringAttr.asString()<< ": " << *it << delim;
01381 }
01382
01383 for_( it, attributes().begin(), attributes().end() )
01384 {
01385 string s = it->first.asString();
01386 str::replaceAll(s,":","_");
01387 for_( it2,it->second.begin(),it->second.end() )
01388 {
01389 str << s <<": "<< *it2 << delim;
01390 }
01391 }
01392
01393 for_( it, _pimpl->_uncompiledPredicated.begin(), _pimpl->_uncompiledPredicated.end() )
01394 {
01395 str << "complex: "<< it->serialize() << delim;
01396 }
01397
01398
01399 str << delim;
01400 }
01401
01402 string PoolQuery::asString() const
01403 { return _pimpl->asString(); }
01404
01405 ostream & operator<<( ostream & str, const PoolQuery & obj )
01406 { return str << obj.asString(); }
01407
01408 std::ostream & dumpOn( std::ostream & str, const PoolQuery & obj )
01409 { return dumpRange( str << obj, obj.begin(), obj.end() ); }
01410
01411 bool PoolQuery::operator==( const PoolQuery & rhs ) const
01412 { return *_pimpl == *rhs._pimpl; }
01413
01415 namespace detail
01416 {
01417
01419
01420
01421
01438 class PoolQueryMatcher
01439 {
01440 public:
01441 typedef sat::LookupAttr::iterator base_iterator;
01442
01443 public:
01444 const base_iterator & end() const
01445 {
01446 static base_iterator _end;
01447 return _end;
01448 }
01449
01450 bool advance( base_iterator & base_r ) const
01451 {
01452 if ( base_r == end() )
01453 base_r = startNewQyery();
01454 else
01455 {
01456 base_r.nextSkipSolvable();
01457 ++base_r;
01458 }
01459
01460 while ( base_r != end() )
01461 {
01462 if ( isAMatch( base_r ) )
01463 return true;
01464
01465 ++base_r;
01466 }
01467 return false;
01468 }
01469
01473 void matchDetail( const base_iterator & base_r, std::vector<base_iterator> & return_r ) const
01474 {
01475 if ( base_r == end() )
01476 return;
01477
01478 sat::Solvable inSolvable( base_r.inSolvable() );
01479
01480 if ( _attrMatchList.size() == 1 )
01481 {
01482
01483
01484
01485 base_iterator base( base_r );
01486 base.stayInThisSolvable();
01487 return_r.push_back( base );
01488
01489 const AttrMatchData::Predicate & predicate( _attrMatchList.front().predicate );
01490 for ( ++base; base.inSolvable() == inSolvable; ++base )
01491 {
01492 if ( ! predicate || predicate( base ) )
01493 return_r.push_back( base );
01494 }
01495 }
01496 else
01497 {
01498
01499 for_( mi, _attrMatchList.begin(), _attrMatchList.end() )
01500 {
01501 const AttrMatchData & matchData( *mi );
01502 sat::LookupAttr q( matchData.attr, inSolvable );
01503 if ( matchData.attrMatcher )
01504 q.setAttrMatcher( matchData.attrMatcher );
01505
01506 if ( ! q.empty() )
01507 {
01508
01509 const AttrMatchData::Predicate & predicate( matchData.predicate );
01510 for_( it, q.begin(), q.end() )
01511 {
01512 if ( ! predicate || predicate( it ) )
01513 return_r.push_back( it );
01514 }
01515 }
01516 }
01517 }
01518 }
01519
01520 public:
01524 PoolQueryMatcher( const shared_ptr<const PoolQuery::Impl> & query_r )
01525 {
01526 query_r->compile();
01527
01528
01529 sat::Pool satpool( sat::Pool::instance() );
01530
01531 for_( it, query_r->_repos.begin(), query_r->_repos.end() )
01532 {
01533 Repository r( satpool.reposFind( *it ) );
01534 if ( r )
01535 _repos.insert( r );
01536 else
01537 _neverMatchRepo = true;
01538 }
01539
01540
01541 if ( _neverMatchRepo && ! _repos.empty() )
01542 _neverMatchRepo = false;
01543
01544
01545 _kinds = query_r->_kinds;
01546
01547 _op = query_r->_op;
01548 _edition = query_r->_edition;
01549
01550 _status_flags = query_r->_status_flags;
01551
01552 _attrMatchList = query_r->_attrMatchList;
01553 }
01554
01555 ~PoolQueryMatcher()
01556 {}
01557
01558 private:
01560 base_iterator startNewQyery() const
01561 {
01562 sat::LookupAttr q;
01563
01564 if ( _neverMatchRepo )
01565 return q.end();
01566
01567
01568 if ( _repos.size() == 1 )
01569 q.setRepo( *_repos.begin() );
01570
01571
01572
01573 if ( _attrMatchList.size() == 1 )
01574 {
01575 const AttrMatchData & matchData( _attrMatchList.front() );
01576 q.setAttr( matchData.attr );
01577 if ( matchData.attrMatcher )
01578 q.setAttrMatcher( matchData.attrMatcher );
01579 }
01580 else
01581 {
01582
01583 q.setAttr( sat::SolvAttr::allAttr );
01584 }
01585
01586 return q.begin();
01587 }
01588
01589
01600 bool isAMatch( base_iterator & base_r ) const
01601 {
01603 Repository inRepo( base_r.inRepo() );
01604
01605 if ( _status_flags
01606 && ( (_status_flags == PoolQuery::INSTALLED_ONLY) != inRepo.isSystemRepo() ) )
01607 {
01608 base_r.nextSkipRepo();
01609 return false;
01610 }
01611
01612 if ( _repos.size() > 1 && _repos.find( inRepo ) == _repos.end() )
01613 {
01614 base_r.nextSkipRepo();
01615 return false;
01616 }
01618 sat::Solvable inSolvable( base_r.inSolvable() );
01619
01620 if ( ! _kinds.empty() && ! inSolvable.isKind( _kinds.begin(), _kinds.end() ) )
01621 {
01622 base_r.nextSkipSolvable();
01623 return false;
01624 }
01625
01626
01627 if ( _op != Rel::ANY && !compareByRel( _op, inSolvable.edition(), _edition, Edition::Match() ) )
01628 {
01629 base_r.nextSkipSolvable();
01630 return false;
01631 }
01633
01634
01635 if ( _attrMatchList.size() == 1 )
01636 {
01637
01638
01639 const AttrMatchData::Predicate & predicate( _attrMatchList.front().predicate );
01640 if ( ! predicate || predicate( base_r ) )
01641 return true;
01642
01643 return false;
01644 }
01645
01646
01647 for_( mi, _attrMatchList.begin(), _attrMatchList.end() )
01648 {
01649 const AttrMatchData & matchData( *mi );
01650 sat::LookupAttr q( matchData.attr, inSolvable );
01651 if ( matchData.attrMatcher )
01652 q.setAttrMatcher( matchData.attrMatcher );
01653
01654 if ( ! q.empty() )
01655 {
01656
01657 const AttrMatchData::Predicate & predicate( matchData.predicate );
01658 if ( predicate )
01659 {
01660 for_( it, q.begin(), q.end() )
01661 {
01662 if ( predicate( it ) )
01663 return true;
01664 }
01665 }
01666 else
01667 return true;
01668 }
01669 }
01670 base_r.nextSkipSolvable();
01671 return false;
01672 }
01673
01674 private:
01676 std::set<Repository> _repos;
01677 DefaultIntegral<bool,false> _neverMatchRepo;
01679 std::set<ResKind> _kinds;
01681 Rel _op;
01682 Edition _edition;
01684 int _status_flags;
01686 AttrMatchList _attrMatchList;
01687 };
01689
01690 void PoolQueryIterator::increment()
01691 {
01692
01693
01694
01695 if ( !_matcher )
01696 return;
01697 if ( _matches )
01698 _matches.reset();
01699 if ( ! _matcher->advance( base_reference() ) )
01700 _matcher.reset();
01701 }
01702
01703 const PoolQueryIterator::Matches & PoolQueryIterator::matches() const
01704 {
01705 if ( _matches )
01706 return *_matches;
01707
01708 if ( !_matcher )
01709 {
01710
01711 static const Matches _none;
01712 return _none;
01713 }
01714
01715 _matches.reset( new Matches );
01716 _matcher->matchDetail( base_reference(), *_matches );
01717 return *_matches;
01718 }
01719
01720 std::ostream & dumpOn( std::ostream & str, const PoolQueryIterator & obj )
01721 {
01722 str << *obj;
01723 if ( ! obj.matchesEmpty() )
01724 {
01725 for_( it, obj.matchesBegin(), obj.matchesEnd() )
01726 {
01727 str << endl << " " << it->inSolvAttr() << "\t" << it->asString();
01728 }
01729 }
01730 return str;
01731 }
01732
01734 }
01736
01737 detail::PoolQueryIterator PoolQuery::begin() const
01738 {
01739 return shared_ptr<detail::PoolQueryMatcher>( new detail::PoolQueryMatcher( _pimpl.getPtr() ) );
01740 }
01741
01743 }
01745